+++ /dev/null
-Source: http://ejabberd.jabber.ru/files/contributions/ejabberd_auth_pam.diff
-
-Index: Makefile.in
-===================================================================
---- Makefile.in (revisión: 705)
-+++ 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: ejabberd.cfg.example
-===================================================================
---- ejabberd.cfg.example (revisión: 705)
-+++ ejabberd.cfg.example (copia de trabajo)
-@@ -95,7 +95,14 @@
- %{auth_method, odbc}.
- %{odbc_server, "DSN=ejabberd;UID=ejabberd;PWD=ejabberd"}.
-
-+% If you want to allow both internal and PAM authentication:
-+{auth_method, [internal, pam]}.
-+% Default PAM service "login" can be changed with:
-+%{pam_service, "login"}.
-+% Default PAM prompt "Password:" can be changed with:
-+%{pam_prompt_pwd, "Password:"}.
-
-+
- % Host name:
- {hosts, ["localhost"]}.
-
-Index: configure.ac
-===================================================================
---- configure.ac (revisión: 705)
-+++ configure.ac (copia de trabajo)
-@@ -16,6 +16,10 @@
- AM_WITH_EXPAT
- #locating zlib
- AM_WITH_ZLIB
-+#locating zlib
-+AM_WITH_ZLIB
-+#locating Linux-PAM
-+AM_WITH_PAM
-
- # Checks for typedefs, structures, and compiler characteristics.
- AC_C_CONST
-@@ -27,6 +31,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 +60,7 @@
- AC_SUBST(db_type)
-
- AC_CONFIG_FILES([Makefile
-+ $make_pam
- $make_mod_irc
- $make_mod_muc
- $make_mod_pubsub
-Index: pam/Makefile.in
-===================================================================
---- pam/Makefile.in (revisión: 0)
-+++ pam/Makefile.in (revisión: 0)
-@@ -0,0 +1,35 @@
-+# $Id$
-+
-+CC = @CC@
-+CFLAGS = @CFLAGS@ @PAM_CFLAGS@ @ERLANG_CFLAGS@
-+CPPFLAGS = @CPPFLAGS@
-+LDFLAGS = @LDFLAGS@
-+LIBS = @LIBS@ @PAM_LIBS@ @ERLANG_LIBS@
-+
-+SUBDIRS =
-+
-+ERLSHLIBS = ../ejabberd_auth_pam.so
-+
-+OUTDIR = ..
-+EFLAGS = -I .. -pz ..
-+OBJS = \
-+ $(OUTDIR)/ejabberd_auth_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/ejabberd_auth_pam.c
-===================================================================
---- pam/ejabberd_auth_pam.c (revisión: 0)
-+++ pam/ejabberd_auth_pam.c (revisión: 0)
-@@ -0,0 +1,255 @@
-+#include <stdio.h>
-+#include <string.h>
-+#include <ei.h>
-+#include <erl_driver.h>
-+#include <security/pam_appl.h>
-+
-+#ifdef LINUX_PAM /* XXX: and OpenPAM? */
-+# define PAM_MSG_MEMBER(msg, n, member) ((msg)[(n)]->member)
-+#else
-+# define PAM_MSG_MEMBER(msg, n, member) ((*(msg))[(n)].member)
-+#endif
-+
-+//
-+#ifndef LINKEDLIBPAM
-+#include <dlfcn.h>
-+
-+#ifndef LIBPAMPATH
-+#define LIBPAMPATH "/usr/lib/libpam.so"
-+#endif
-+
-+static void *libpam_h = NULL;
-+
-+void init_libpam() {
-+ if ( libpam_h == NULL ) {
-+ libpam_h = dlopen( LIBPAMPATH, RTLD_GLOBAL | RTLD_NOW );
-+ printf( "Open: %s\r\n", LIBPAMPATH );
-+ };
-+};
-+
-+void fin_libpam() {
-+ if ( libpam_h != NULL ) {
-+ dlclose( libpam_h );
-+ libpam_h = NULL;
-+ printf( "Close: %s\r\n", LIBPAMPATH );
-+ };
-+};
-+#endif
-+//
-+
-+typedef struct _PromptMatch {
-+ struct _PromptMatch* next;
-+ char* prompt;
-+ char* response;
-+} *PromptMatch;
-+
-+typedef struct {
-+ ErlDrvPort port;
-+} ejabberd_pam_data;
-+
-+static PromptMatch _newMatch( PromptMatch list, char* prompt, char* response ) {
-+ PromptMatch result = ( PromptMatch)malloc( sizeof( struct _PromptMatch ));
-+ bzero( result, sizeof( struct _PromptMatch ));
-+ result->prompt = prompt;
-+ result->response = response;
-+ result->next = list;
-+ 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 ) {
-+ next = cur->next;
-+ free( cur->prompt );
-+ free( cur->response );
-+ free( cur );
-+ cur = next;
-+ };
-+};
-+
-+static int pam_conversation( int msgcnt, const struct pam_message** msgs, struct pam_response** res, void* arg ) {
-+ int iResult = PAM_CONV_ERR;
-+ if (( msgcnt > 0 ) || ( msgcnt <= PAM_MAX_NUM_MSG )) {
-+ // Allocate a response for each message
-+ int iSizeResponse = sizeof( struct pam_response ) * msgcnt;
-+ struct pam_response *reply = (struct pam_response *)malloc( iSizeResponse );
-+ if ( reply != NULL ) {
-+ bzero( reply, iSizeResponse );
-+ // Walk each message from PAM and lookup the response corresponding to each prompt
-+ int ii;
-+ char* response;
-+ for ( ii = 0; ii < msgcnt; ii++ ) {
-+ printf( "prompt(index %d)(style %d): %s\r\n", ii, PAM_MSG_MEMBER( msgs, ii, msg_style ), PAM_MSG_MEMBER( msgs, ii, msg ));
-+ switch ( PAM_MSG_MEMBER( msgs, ii, msg_style )) {
-+ case PAM_PROMPT_ECHO_ON :
-+ case PAM_PROMPT_ECHO_OFF :
-+ // Find the response for the current prompt; if none is found, warn
-+ response = _findMatch( (PromptMatch)arg, PAM_MSG_MEMBER( msgs, ii, msg ));
-+ if ( response != NULL ) {
-+ // Copy password into response
-+ reply[ ii ].resp = strdup( response );
-+ reply[ ii ].resp_retcode = PAM_SUCCESS;
-+ } else {
-+ printf("Warning: No prompt found for: %s\r\n", PAM_MSG_MEMBER( msgs, ii, msg ));
-+ reply[ ii ].resp = strdup( "Unexpected prompt" );
-+ reply[ ii ].resp_retcode = PAM_SUCCESS;
-+ };
-+ break;
-+ default :
-+ reply[ ii ].resp = strdup("");
-+ reply[ ii ].resp_retcode = PAM_SUCCESS;
-+ };
-+ };
-+ *res = reply;
-+ iResult = PAM_SUCCESS;
-+ };
-+ };
-+ return iResult;
-+};
-+
-+#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 ErlDrvData start( ErlDrvPort port, char* command ) {
-+ printf( "PAM-AUTH driver start\r\n" );
-+ #ifndef LINKEDLIBPAM
-+ init_libpam();
-+ #endif
-+ ejabberd_pam_data *d = (ejabberd_pam_data *)driver_alloc( sizeof( ejabberd_pam_data ));
-+ d->port = port;
-+ set_port_control_flags( port, PORT_CONTROL_FLAG_BINARY );
-+ return (ErlDrvData)d;
-+};
-+
-+static void stop( ErlDrvData handle ) {
-+ driver_free( (char *)handle );
-+ #ifndef LINKEDLIBPAM
-+ fin_libpam();
-+ #endif
-+ printf( "PAM-AUTH driver stop\r\n" );
-+};
-+
-+static int auth_params( char* buf, PromptMatch* head ) {
-+ int iSize = 0;
-+ int iIndex = 0;
-+ int iResult = 0;
-+ char* prompt = NULL;
-+ char* response = NULL;
-+ // Parse the version and tuple header
-+ ei_decode_version( buf, &iIndex, &iSize );
-+ ei_decode_tuple_header( buf, &iIndex, &iSize );
-+ if ( iSize == 2 ) {
-+ // The first item in the tuple should be the username
-+ DECODE_STRING( buf, &iIndex, response );
-+ *head = _newMatch( *head, strdup( "login" ), response );
-+
-+ // 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, &iIndex, &iSize );
-+
-+ // 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
-+ int ii = 0;
-+ for ( ii = 0; ii < iSize; ii++ ) {
-+ int iTupleSize = 0;
-+ ei_decode_tuple_header( buf, &iIndex, &iTupleSize );
-+ if ( iTupleSize != 2 ) {
-+ printf( "Incorrect number of arguments in prompt/response tuple(index %d): %d\r\n", ii, iTupleSize );
-+ } else {
-+ // Decode the prompt from the tuple
-+ DECODE_STRING( buf, &iIndex, prompt );
-+ DECODE_STRING( buf, &iIndex, response );
-+ // Add a new prompt item to track this prompt/response pair
-+ *head = _newMatch( *head, prompt, response );
-+ };
-+ };
-+ iResult = 1;
-+ };
-+ return iResult;
-+};
-+
-+static int auth( PromptMatch head ) {
-+ // Setup PAM conversation structure; pass in the prompt match list
-+ // so we can process the prompts from PAM
-+ int flags = 0; //PAM_SILENT
-+ int iResult = 0;
-+ pam_handle_t* pam = NULL;
-+
-+ char* service = _findMatch( head, "service" );
-+ char* username = _findMatch( head, "login" );
-+
-+ struct pam_conv conv = { pam_conversation, head };
-+
-+ // Spin up PAM
-+ int rc = pam_start( service, username, &conv, &pam );
-+ if ( rc == PAM_SUCCESS ) {
-+ // Attempt to authenticate the user
-+ rc = pam_authenticate( pam, flags );
-+ if ( rc != PAM_SUCCESS )
-+ printf("Authentication failed for: %s. Error: %s\r\n", username, pam_strerror( NULL, rc ));
-+ else
-+ iResult = 1;
-+ pam_end( pam, rc );
-+ } else
-+ printf("Unable to spin up PAM: %s\r\n", pam_strerror( NULL, rc ));
-+ return iResult;
-+};
-+
-+static int control( ErlDrvData drv_data, unsigned int command, char *buf,
-+ int len, char** rbuf, int rlen ) {
-+ int iResult;
-+ PromptMatch head = NULL;
-+ if (( iResult = auth_params( buf, &head )) != 0 ) {
-+ iResult = auth( head );
-+ _cleanupMatch( head );
-+ };
-+ RETURN_INT( iResult );
-+};
-+
-+ErlDrvEntry entry = {
-+ NULL, /* F_PTR init, N/A */
-+ start, /* L_PTR start, called when port is opened */
-+ stop, /* 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 */
-+ "ejabberd_auth_pam", /* char *driver_name, the argument to open_port */
-+ NULL, /* F_PTR finish, called when unloaded */
-+ NULL, /* handle */
-+ control, /* F_PTR control, port_command callback */
-+ NULL, /* F_PTR timeout, reserved */
-+ NULL /* F_PTR outputv, reserved */
-+};
-+
-+DRIVER_INIT(ejabberd_auth_pam) /* must match name in driver_entry */
-+{
-+ return &entry;
-+};
-Index: pam/ejabberd_auth_pam.erl
-===================================================================
---- pam/ejabberd_auth_pam.erl (revisión: 0)
-+++ pam/ejabberd_auth_pam.erl (revisión: 0)
-@@ -0,0 +1,90 @@
-+-module(ejabberd_auth_pam).
-+-author('').
-+
-+-export([
-+ start/1,
-+ plain_password_required/0,
-+ set_password/3,
-+ try_register/3,
-+ remove_user/2,
-+ remove_user/3,
-+ get_password/2,
-+ get_password_s/2,
-+ is_user_exists/2,
-+ get_vh_registered_users/1,
-+ check_password/3,
-+ check_password/5
-+ ]).
-+
-+start( _Host ) ->
-+ case erl_ddll:load_driver( ejabberd:get_so_path(), ejabberd_auth_pam) of
-+ ok -> ok;
-+ {error, already_loaded} -> ok;
-+ Error -> exit({error, could_not_load_driver, Error})
-+ end.
-+
-+plain_password_required() ->
-+ true.
-+
-+check_password( User, Server, Password ) ->
-+ PAMService =
-+ case ejabberd_config:get_local_option( { pam_service, Server } ) of
-+ undefined ->
-+ "login";
-+ Service ->
-+ Service
-+ end,
-+ PAMPrompt =
-+ case ejabberd_config:get_local_option( { pam_prompt_pwd, Server } ) of
-+ undefined ->
-+ "Password:";
-+ Prompt ->
-+ Prompt
-+ end,
-+ Port = open_port( { spawn, ejabberd_auth_pam }, [ binary ] ),
-+ Bin = term_to_binary( { User, [ { PAMPrompt, Password }, { "service", PAMService } ] }),
-+ Res = port_control( Port, 1, Bin ),
-+ case Res of
-+ <<0>> -> false;
-+ <<1>> -> true;
-+ _ -> undefined
-+ end.
-+
-+check_password( User, Server, Password, _StreamID, _Digest ) ->
-+ check_password( User, Server, Password ).
-+
-+set_password( _User, _Server, _Password ) ->
-+ { error, not_allowed }.
-+
-+try_register( _User, _Server, _Password ) ->
-+ { error, not_allowed }.
-+
-+remove_user( _User, _Server ) ->
-+ { error, not_allowed }.
-+
-+remove_user( _User, _Server, _Password ) ->
-+ { error, not_allowed }.
-+
-+get_vh_registered_users( _Server ) ->
-+ [].
-+
-+is_user_exists( _User, _Server ) ->
-+ {ok,FileBin}=file:read_file("/etc/passwd"),
-+ Tmp=binary_to_list(FileBin),
-+ FileStr=string:concat("\n", Tmp),
-+
-+ Tmp2=string:concat("\n", _User),
-+ RegExp=string:concat(Tmp2, ":"),
-+
-+ case regexp:match(FileStr, RegExp) of
-+ {match, _, _} ->
-+ true;
-+ _ ->
-+ false
-+ end.
-+
-+get_password( _User, _Server ) ->
-+ false.
-+
-+get_password_s( _User, _Server ) ->
-+ "".
-Index: aclocal.m4
-===================================================================
---- aclocal.m4 (revisión: 705)
-+++ 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
-+])