SOURCES: ejabberd-auth_pam.patch (NEW) - New file: PAM authenticat...

japhy japhy at pld-linux.org
Tue Feb 13 08:56:48 CET 2007


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
++])
================================================================


More information about the pld-cvs-commit mailing list