Author: japhy Date: Tue Feb 13 07:56:48 2007 GMT Module: SOURCES Tag: HEAD ---- Log message: - New file: PAM authentication support for ejabberd.
---- Files affected: SOURCES: ejabberd-auth_pam.patch (NONE -> 1.1) (NEW) ---- Diffs: ================================================================ Index: SOURCES/ejabberd-auth_pam.patch diff -u /dev/null SOURCES/ejabberd-auth_pam.patch:1.1 --- /dev/null Tue Feb 13 08:56:48 2007 +++ SOURCES/ejabberd-auth_pam.patch Tue Feb 13 08:56:43 2007 @@ -0,0 +1,497 @@ +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 ++]) ================================================================
_______________________________________________ pld-cvs-commit mailing list [email protected] http://lists.pld-linux.org/mailman/listinfo/pld-cvs-commit
