Index: Makefile.in
===================================================================
--- Makefile.in	(revisión: 626)
+++ Makefile.in	(copia de trabajo)
@@ -27,7 +27,7 @@
 
 prefix = @prefix@
 
-SUBDIRS = @mod_irc@ @mod_pubsub@ @mod_muc@ @eldap@ @web@ stringprep @tls@ @odbc@ @ejabberd_zlib@
+SUBDIRS = @mod_irc@ @mod_pubsub@ @mod_muc@ @eldap@ @web@ stringprep @tls@ @odbc@ @ejabberd_zlib@ @pam@
 ERLSHLIBS = expat_erl.so
 SOURCES = $(wildcard *.erl)
 BEAMS = $(SOURCES:.erl=.beam)
Index: configure.ac
===================================================================
--- configure.ac	(revisión: 626)
+++ configure.ac	(copia de trabajo)
@@ -16,6 +16,8 @@
 AM_WITH_EXPAT
 #locating zlib
 AM_WITH_ZLIB
+#locating zlib
+AM_WITH_ZLIB
 
 # Checks for typedefs, structures, and compiler characteristics.
 AC_C_CONST
@@ -27,6 +29,7 @@
 AC_FUNC_MALLOC
 AC_HEADER_STDC
 
+AC_MOD_ENABLE(pam, yes)
 AC_MOD_ENABLE(mod_pubsub, yes)
 AC_MOD_ENABLE(mod_irc, yes)
 AC_MOD_ENABLE(mod_muc, yes)
@@ -55,6 +58,7 @@
 AC_SUBST(db_type)
 
 AC_CONFIG_FILES([Makefile
+                 $make_pam
                  $make_mod_irc
                  $make_mod_muc
                  $make_mod_pubsub
Index: pam/stress_pam.erl
===================================================================
--- pam/stress_pam.erl	(revisión: 0)
+++ pam/stress_pam.erl	(revisión: 0)
@@ -0,0 +1,11 @@
+-module(stress_pam).
+-export([start/0]).
+
+start() ->
+    Port = pam:start(),
+    stress(Port).
+
+stress(Port) ->
+    true = pam:check_password(Port, "user", "password"),
+    timer:sleep(200),
+    stress(Port).
Index: pam/Makefile.in
===================================================================
--- pam/Makefile.in	(revisión: 0)
+++ pam/Makefile.in	(revisión: 0)
@@ -0,0 +1,35 @@
+# $Id: Makefile.in 285 2004-11-05 21:14:31Z aleksey $
+
+CC = @CC@
+CFLAGS = @CFLAGS@ @PAM_CFLAGS@ @ERLANG_CFLAGS@
+CPPFLAGS = @CPPFLAGS@
+LDFLAGS = @LDFLAGS@
+LIBS = @LIBS@ @PAM_LIBS@ @ERLANG_LIBS@
+
+SUBDIRS = 
+
+ERLSHLIBS = ../pam_drv.so
+
+OUTDIR = ..
+EFLAGS = -I .. -pz ..
+OBJS   = \
+	$(OUTDIR)/pam.beam
+
+all:    $(OBJS) $(ERLSHLIBS)
+
+$(OUTDIR)/%.beam:       %.erl
+	@ERLC@ -W $(EFLAGS) -o $(OUTDIR) $<
+
+$(ERLSHLIBS):	../%.so:	%.c
+	$(CC) -Wall $(CFLAGS) $(LDFLAGS) \
+	$(subst ../,,$(subst .so,.c,$@)) $(LIBS) \
+	-o $@ -fpic -shared
+
+clean:
+	rm -f $(OBJS) $(ERLSHLIBS)
+
+distclean: clean
+	rm -f Makefile
+
+TAGS:
+	etags *.erl
Index: pam/pam_drv.c
===================================================================
--- pam/pam_drv.c	(revisión: 0)
+++ pam/pam_drv.c	(revisión: 0)
@@ -0,0 +1,235 @@
+#include <stdio.h>
+#include <string.h>
+#include <erl_driver.h>
+#include <ei.h>
+#include <security/pam_appl.h>
+
+typedef struct _PromptMatch
+{
+    struct _PromptMatch* next;
+    char* prompt;
+    char* response;
+} *PromptMatch;
+
+static PromptMatch _newMatch(PromptMatch list, char* prompt, char* response)
+{
+    PromptMatch result = (PromptMatch)malloc(sizeof(struct _PromptMatch));
+    memset(result, '\0', sizeof(struct _PromptMatch));
+    result->prompt = prompt;
+    result->response = response;
+    if (list != NULL)
+    {
+        list->next = result;
+        return list;
+    }
+    else
+    {
+        return result;
+    }
+}
+
+static char* _findMatch(PromptMatch list, const char* prompt)
+{
+    PromptMatch cur = list;
+    while (cur != NULL)
+    {
+        if (strstr(prompt, cur->prompt) != 0)
+        {
+            return cur->response;
+        }
+        cur = cur->next;
+    }
+    return NULL;
+}
+
+static void _cleanupMatch(PromptMatch list)
+{
+    PromptMatch cur = list;
+    PromptMatch next;
+    while (cur != NULL)
+    {
+        free(cur->prompt);
+        free(cur->response);
+        next = cur->next;
+        free(cur);
+        cur = next;
+    }
+}
+
+static int _handle_pam_conversation(int msgcnt, const struct pam_message** msgs, struct pam_response** res,
+                                    void* arg)
+{
+    int i;
+    PromptMatch prompts = (PromptMatch)arg;
+    struct pam_response *reply;
+
+    if(msgcnt <= 0)
+    {
+        return PAM_CONV_ERR;
+    }
+
+    // Allocate a response for each message
+    reply = (struct pam_response *) malloc(sizeof(struct pam_response) * msgcnt);
+    memset(reply, 0, sizeof(struct pam_response) * msgcnt);
+
+    // Walk each message from PAM and lookup the response corresponding to each prompt
+    for(i = 0; i < msgcnt; i++) 
+    {
+        if(msgs[i]->msg_style == PAM_PROMPT_ECHO_OFF || msgs[i]->msg_style == PAM_PROMPT_ECHO_ON) 
+        {
+            // Find the response for the current prompt; if none is found, warn
+            char* response = _findMatch(prompts, msgs[i]->msg);
+            if (response != NULL)
+            {
+                // Copy password into response
+                reply[i].resp = strdup(response);
+                reply[i].resp_retcode = 0;
+            }
+            else
+            {
+                printf("Warning: No prompt found for: %s\n", msgs[i]->msg);
+                reply[i].resp = strdup("Unexpected prompt");
+                reply[i].resp_retcode = 0;
+            }
+        }
+    }
+
+    *res = reply;
+
+    return PAM_SUCCESS;
+}
+
+#define DECODE_STRING(buffer, index, result) \
+    {                                             \
+        int tmp = 0; int size = 0;                \
+        ei_get_type(buffer, index, &tmp, &size); \
+        result = malloc(size + 1);                \
+        ei_decode_string(buffer, index, result); \
+    }
+
+#define RETURN_INT(value) \
+    {                                             \
+        ErlDrvBinary* b = driver_alloc_binary(1); \
+        rlen = 1;                                 \
+        b->orig_bytes[0] = value;                 \
+        *rbuf = (char*)b;                         \
+        return rlen;                              \
+    }
+
+static int pam_erl_start(ErlDrvPort port, char* command)
+{
+  set_port_control_flags(port, PORT_CONTROL_FLAG_BINARY);
+  return 0;
+}
+
+static int pam_erl_control(ErlDrvData drv_data, unsigned int command,
+                           char *buf, int len,
+                           char **rbuf, int rlen)
+{
+    int tmp = 0;
+    int index = 0;
+    int size = 0;
+    char* username = 0;
+    char* password = 0;
+
+    int i = 0;
+    int rc = 0;
+    struct pam_conv conv;
+    pam_handle_t* pam;
+
+    // Parse the version and tuple header
+    ei_decode_version(buf, &index, &tmp);
+    ei_decode_tuple_header(buf, &index, &tmp);
+    if (tmp != 2)
+    {
+        printf("Incorrect number of arguments!\n");
+        RETURN_INT(-1);
+    }
+
+    // The first item in the tuple should be the username
+    DECODE_STRING(buf, &index, username);
+
+    // The second item in the tuple should be a list of tuples
+    // Each tuple in the list consists of the expected prompt string
+    // and the value to return at that prompt
+    ei_decode_list_header(buf, &index, &size);
+
+    // Loop over the list and pull out each prompt/response tuple and
+    // store it into a PromptItem list that will get processed in
+    // the PAM conversation
+    PromptMatch head = NULL;
+    for (i = 0; i < size; i++)
+    {
+        int tuplecnt = 0;
+        char* prompt = 0;
+        char* response = 0;
+
+        ei_decode_tuple_header(buf, &index, &tuplecnt);
+        if (tuplecnt != 2)
+        {
+            printf("Incorrect number of arguments in prompt/response tuple: %d\n", tuplecnt);
+            _cleanupMatch(head);
+            free(username);
+            RETURN_INT(-2);
+        }
+
+        // Decode the prompt from the tuple
+        DECODE_STRING(buf, &index, prompt);
+        DECODE_STRING(buf, &index, response);
+
+        // Add a new prompt item to track this prompt/response pair
+        head = _newMatch(head, prompt, response);
+    }
+
+    // Setup PAM conversation structure; pass in the prompt match list
+    // so we can process the prompts from PAM
+    conv.conv = _handle_pam_conversation;
+    conv.appdata_ptr = head;
+
+    // Spin up PAM
+    rc = pam_start("login", username, &conv, &pam);
+    if (rc != PAM_SUCCESS)
+    {
+        printf("Unable to spin up PAM: %s\n", pam_strerror(NULL, rc));
+        RETURN_INT(-3);
+    }
+
+    // Attempt to authenticate the user
+    rc = pam_authenticate(pam, 0);
+    if (rc != PAM_SUCCESS)
+    {
+        pam_end(pam, rc);
+        printf("Authentication failed for: %s. Error: %s\n", username, pam_strerror(NULL, rc));
+        free(password);
+        free(username);
+        RETURN_INT(1);
+    }
+
+    pam_end(pam, rc);
+
+    _cleanupMatch(head);
+    free(username);
+
+    RETURN_INT(0);
+}
+
+ErlDrvEntry pam_driver_entry = {
+  NULL,			/* F_PTR init, N/A */
+  pam_erl_start,		/* L_PTR start, called when port is opened */
+  NULL,		/* F_PTR stop, called when port is closed */
+  NULL,			/* F_PTR output, called when erlang has sent */
+  NULL,			/* F_PTR ready_input, called when input descriptor ready */
+  NULL,			/* F_PTR ready_output, called when
+                           output descriptor ready */
+  "pam_drv",			/* char *driver_name, the argument to open_port */
+  NULL,			/* F_PTR finish, called when unloaded */
+  NULL,			/* handle */
+  pam_erl_control,		/* F_PTR control, port_command callback */
+  NULL,			/* F_PTR timeout, reserved */
+  NULL				/* F_PTR outputv, reserved */
+};
+
+DRIVER_INIT(pam_drv) /* must match name in driver_entry */
+{
+    return &pam_driver_entry;
+}
Index: pam/pam_test.c
===================================================================
--- pam/pam_test.c	(revisión: 0)
+++ pam/pam_test.c	(revisión: 0)
@@ -0,0 +1,68 @@
+#include <stdio.h>
+#include <string.h>
+#include <security/pam_appl.h>
+
+static int _handle_pam_conversation(int msgcnt, const struct pam_message** msgs, struct pam_response** res,
+                                    void* arg)
+{
+    int i;
+    struct pam_response *reply;
+
+    if(msgcnt <= 0)
+    {
+        return PAM_CONV_ERR;
+    }
+
+    // Allocate a response for each message
+    reply = (struct pam_response *) malloc(sizeof(struct pam_response) * msgcnt);
+    memset(reply, 0, sizeof(struct pam_response) * msgcnt);
+
+    // Walk each message from PAM and lookup the response corresponding to each prompt
+    for(i = 0; i < msgcnt; i++) 
+    {
+      printf("PAM Message(%d): %s\n", msgs[i]->msg_style, msgs[i]->msg);
+      reply[i].resp = strdup("Unexpected prompt");
+      reply[i].resp_retcode = 0;
+    }
+
+    *res = reply;
+
+    return PAM_SUCCESS;
+}
+
+
+int main(int args, char** argv)
+{
+    struct pam_conv conv;
+    pam_handle_t* pam;
+    int rc;
+
+    if (args < 3)
+    {
+      printf("Please provide a username and service as the first and second arguments!\n");
+      return -1;
+    }
+
+    char* username = argv[1];
+    char* service = argv[2];
+
+    // Setup PAM conversation structure; pass in the prompt match list
+    // so we can process the prompts from PAM
+    conv.conv = _handle_pam_conversation;
+    conv.appdata_ptr = 0;
+
+    // Spin up PAM
+    rc = pam_start(service, username, &conv, &pam);
+    if (rc != PAM_SUCCESS)
+    {
+        printf("Unable to spin up PAM: %s\n", pam_strerror(NULL, rc));
+        return -3;
+    }
+
+    // Attempt to authenticate the user
+    rc = pam_authenticate(pam, 0);
+
+    pam_end(pam, rc);
+
+    return 0;
+}
Index: pam/pam.erl
===================================================================
--- pam/pam.erl	(revisión: 0)
+++ pam/pam.erl	(revisión: 0)
@@ -0,0 +1,19 @@
+-module(pam).
+-author('dizzyd@dizzyd.com').
+
+-export([start/0, 
+         check_password/3]).
+
+start() ->
+    ok = erl_ddll:load_driver(ejabberd:get_so_path(), pam_drv),
+    open_port({spawn, pam_drv}, [binary]).
+
+check_password(Port, Username, Password) ->
+    Bin = term_to_binary({Username, [{"Password:", Password}]}),
+    Res = port_control(Port, 0, Bin),
+    case Res of
+        <<0>> ->
+            true;
+        _ ->
+            false
+    end.
Index: aclocal.m4
===================================================================
--- aclocal.m4	(revisión: 626)
+++ aclocal.m4	(copia de trabajo)
@@ -292,3 +292,32 @@
 fi
 ])
 dnl <openssl/>
+
+AC_DEFUN(AM_WITH_PAM,
+[ AC_ARG_WITH(pam, [ --with-pam=PREFIX  prefix where PAM is installed ])
+unset PAM_LIBS;
+unset PAM_CFLAGS;
+
+if test x"$with_pam" != x; then
+	PAM_CFLAGS="-I$with_pam/include"
+   PAM_LIBS="-L$with_pam/lib"
+fi
+
+AC_CHECK_LIB(pam, pam_start, 
+	[ PAM_LIBS="$PAM_LIBS -lpam" pam_found=yes ],
+	[ pam_found=no ],
+	"$PAM_LIBS")
+
+if test $pam_found = yes; then
+   pam_save_CFLAGS="$CFLAGS"
+   CFLAGS="$PAM_CFLAGS $CFLAGS"
+   AC_CHECK_HEADERS(security/pam_appl.h, ,$pam_found=no)
+   if test $pam_found = no; then
+      AC_MSG_ERROR([Could not find security/pam_appl.h])
+   fi
+   CFLAGS=$pam_save_CFLAGS
+
+   AC_SUBST(PAM_CFLAGS)
+   AC_SUBST(PAM_LIBS)
+fi
+])
