]> git.pld-linux.org Git - packages/ejabberd.git/blob - ejabberd-auth_pam.patch
- use _alt_name if build with logdb
[packages/ejabberd.git] / ejabberd-auth_pam.patch
1 Source: http://ejabberd.jabber.ru/files/contributions/ejabberd_auth_pam.diff
2
3 Index: Makefile.in
4 ===================================================================
5 --- Makefile.in (revisión: 705)
6 +++ Makefile.in (copia de trabajo)
7 @@ -27,7 +27,7 @@
8  
9  prefix = @prefix@
10  
11 -SUBDIRS = @mod_irc@ @mod_pubsub@ @mod_muc@ @eldap@ @web@ stringprep @tls@ @odbc@ @ejabberd_zlib@
12 +SUBDIRS = @mod_irc@ @mod_pubsub@ @mod_muc@ @eldap@ @web@ stringprep @tls@ @odbc@ @ejabberd_zlib@ @pam@
13  ERLSHLIBS = expat_erl.so
14  SOURCES = $(wildcard *.erl)
15  BEAMS = $(SOURCES:.erl=.beam)
16 Index: ejabberd.cfg.example
17 ===================================================================
18 --- ejabberd.cfg.example        (revisión: 705)
19 +++ ejabberd.cfg.example        (copia de trabajo)
20 @@ -95,7 +95,14 @@
21  %{auth_method, odbc}.
22  %{odbc_server, "DSN=ejabberd;UID=ejabberd;PWD=ejabberd"}.
23  
24 +% If you want to allow both internal and PAM authentication:
25 +{auth_method, [internal, pam]}.
26 +% Default PAM service "login" can be changed with:
27 +%{pam_service, "login"}.
28 +% Default PAM prompt "Password:" can be changed with:
29 +%{pam_prompt_pwd, "Password:"}.
30  
31 +
32  % Host name:
33  {hosts, ["localhost"]}.
34  
35 Index: configure.ac
36 ===================================================================
37 --- configure.ac        (revisión: 705)
38 +++ configure.ac        (copia de trabajo)
39 @@ -16,6 +16,10 @@
40  AM_WITH_EXPAT
41  #locating zlib
42  AM_WITH_ZLIB
43 +#locating zlib
44 +AM_WITH_ZLIB
45 +#locating Linux-PAM
46 +AM_WITH_PAM
47  
48  # Checks for typedefs, structures, and compiler characteristics.
49  AC_C_CONST
50 @@ -27,6 +31,7 @@
51  AC_FUNC_MALLOC
52  AC_HEADER_STDC
53  
54 +AC_MOD_ENABLE(pam, yes)
55  AC_MOD_ENABLE(mod_pubsub, yes)
56  AC_MOD_ENABLE(mod_irc, yes)
57  AC_MOD_ENABLE(mod_muc, yes)
58 @@ -55,6 +60,7 @@
59  AC_SUBST(db_type)
60  
61  AC_CONFIG_FILES([Makefile
62 +                 $make_pam
63                   $make_mod_irc
64                   $make_mod_muc
65                   $make_mod_pubsub
66 Index: pam/Makefile.in
67 ===================================================================
68 --- pam/Makefile.in     (revisión: 0)
69 +++ pam/Makefile.in     (revisión: 0)
70 @@ -0,0 +1,35 @@
71 +# $Id$
72 +
73 +CC = @CC@
74 +CFLAGS = @CFLAGS@ @PAM_CFLAGS@ @ERLANG_CFLAGS@
75 +CPPFLAGS = @CPPFLAGS@
76 +LDFLAGS = @LDFLAGS@
77 +LIBS = @LIBS@ @PAM_LIBS@ @ERLANG_LIBS@
78 +
79 +SUBDIRS = 
80 +
81 +ERLSHLIBS = ../ejabberd_auth_pam.so
82 +
83 +OUTDIR = ..
84 +EFLAGS = -I .. -pz ..
85 +OBJS   = \
86 +       $(OUTDIR)/ejabberd_auth_pam.beam
87 +
88 +all:    $(OBJS) $(ERLSHLIBS)
89 +
90 +$(OUTDIR)/%.beam:       %.erl
91 +       @ERLC@ -W $(EFLAGS) -o $(OUTDIR) $<
92 +
93 +$(ERLSHLIBS):  ../%.so:        %.c
94 +       $(CC) -Wall $(CFLAGS) $(LDFLAGS) \
95 +       $(subst ../,,$(subst .so,.c,$@)) $(LIBS) \
96 +       -o $@ -fpic -shared
97 +
98 +clean:
99 +       rm -f $(OBJS) $(ERLSHLIBS)
100 +
101 +distclean: clean
102 +       rm -f Makefile
103 +
104 +TAGS:
105 +       etags *.erl
106 Index: pam/ejabberd_auth_pam.c
107 ===================================================================
108 --- pam/ejabberd_auth_pam.c     (revisión: 0)
109 +++ pam/ejabberd_auth_pam.c     (revisión: 0)
110 @@ -0,0 +1,255 @@
111 +#include <stdio.h>
112 +#include <string.h>
113 +#include <ei.h>
114 +#include <erl_driver.h>
115 +#include <security/pam_appl.h>
116 +
117 +#ifdef LINUX_PAM        /* XXX: and OpenPAM? */
118 +# define PAM_MSG_MEMBER(msg, n, member) ((msg)[(n)]->member)
119 +#else
120 +# define PAM_MSG_MEMBER(msg, n, member) ((*(msg))[(n)].member)
121 +#endif
122 +
123 +//
124 +#ifndef LINKEDLIBPAM
125 +#include <dlfcn.h>
126 +
127 +#ifndef LIBPAMPATH
128 +#define LIBPAMPATH "/usr/lib/libpam.so"
129 +#endif
130 +
131 +static void *libpam_h = NULL;
132 +
133 +void init_libpam() {
134 +  if ( libpam_h == NULL ) {
135 +    libpam_h = dlopen( LIBPAMPATH, RTLD_GLOBAL | RTLD_NOW );
136 +    printf( "Open: %s\r\n", LIBPAMPATH );
137 +  };
138 +};
139 +
140 +void fin_libpam() {
141 +  if ( libpam_h != NULL ) {
142 +    dlclose( libpam_h );
143 +    libpam_h = NULL;
144 +    printf( "Close: %s\r\n", LIBPAMPATH );
145 +  };
146 +};
147 +#endif
148 +//
149 +
150 +typedef struct _PromptMatch {
151 +  struct _PromptMatch* next;
152 +  char* prompt;
153 +  char* response;
154 +} *PromptMatch;
155 +
156 +typedef struct {
157 +  ErlDrvPort port;
158 +} ejabberd_pam_data;
159 +
160 +static PromptMatch _newMatch( PromptMatch list, char* prompt, char* response ) {
161 +  PromptMatch result = ( PromptMatch)malloc( sizeof( struct _PromptMatch ));
162 +  bzero( result, sizeof( struct _PromptMatch ));
163 +  result->prompt = prompt;
164 +  result->response = response;
165 +  result->next = list;
166 +  return result;
167 +};
168 +
169 +static char* _findMatch( PromptMatch list, const char* prompt ) {
170 +  PromptMatch cur = list;
171 +  while ( cur != NULL ) {
172 +   if ( strstr( prompt, cur->prompt ) != 0 )
173 +     return cur->response;
174 +   cur = cur->next;
175 +  };
176 +  return NULL;
177 +};
178 +
179 +static void _cleanupMatch( PromptMatch list ) {
180 +  PromptMatch cur = list;
181 +  PromptMatch next;
182 +  while ( cur != NULL ) {
183 +    next = cur->next;
184 +    free( cur->prompt );
185 +    free( cur->response );
186 +    free( cur );
187 +    cur = next;
188 +  };
189 +};
190 +
191 +static int pam_conversation( int msgcnt, const struct pam_message** msgs, struct pam_response** res, void* arg ) {
192 +  int iResult = PAM_CONV_ERR;
193 +  if (( msgcnt > 0 ) || ( msgcnt <= PAM_MAX_NUM_MSG )) {
194 +    // Allocate a response for each message
195 +    int iSizeResponse = sizeof( struct pam_response ) * msgcnt;
196 +    struct pam_response *reply = (struct pam_response *)malloc( iSizeResponse );
197 +    if ( reply != NULL ) {    
198 +      bzero( reply, iSizeResponse );      
199 +      // Walk each message from PAM and lookup the response corresponding to each prompt
200 +      int ii;
201 +      char* response;
202 +      for ( ii = 0; ii < msgcnt; ii++ ) {
203 +        printf( "prompt(index %d)(style %d): %s\r\n", ii, PAM_MSG_MEMBER( msgs, ii, msg_style ), PAM_MSG_MEMBER( msgs, ii, msg ));
204 +        switch ( PAM_MSG_MEMBER( msgs, ii, msg_style )) {
205 +          case PAM_PROMPT_ECHO_ON :
206 +          case PAM_PROMPT_ECHO_OFF :
207 +            // Find the response for the current prompt; if none is found, warn
208 +            response = _findMatch( (PromptMatch)arg, PAM_MSG_MEMBER( msgs, ii, msg ));
209 +            if ( response != NULL ) {
210 +              // Copy password into response
211 +              reply[ ii ].resp = strdup( response );
212 +              reply[ ii ].resp_retcode = PAM_SUCCESS;
213 +            } else {
214 +              printf("Warning: No prompt found for: %s\r\n", PAM_MSG_MEMBER( msgs, ii, msg ));
215 +              reply[ ii ].resp = strdup( "Unexpected prompt" );
216 +              reply[ ii ].resp_retcode = PAM_SUCCESS;
217 +            };
218 +            break;
219 +          default :
220 +            reply[ ii ].resp = strdup("");
221 +            reply[ ii ].resp_retcode = PAM_SUCCESS;
222 +        };
223 +      };
224 +      *res = reply;
225 +      iResult = PAM_SUCCESS;
226 +    };
227 +  };
228 +  return iResult;
229 +};
230 +
231 +#define DECODE_STRING(buffer, index, result)      \
232 +    {                                             \
233 +        int tmp = 0; int size = 0;                \
234 +        ei_get_type(buffer, index, &tmp, &size);  \
235 +        result = malloc(size + 1);                \
236 +        ei_decode_string(buffer, index, result);  \
237 +    }
238 +
239 +#define RETURN_INT(value) \
240 +    {                                             \
241 +        ErlDrvBinary* b = driver_alloc_binary(1); \
242 +        rlen = 1;                                 \
243 +        b->orig_bytes[0] = value;                 \
244 +        *rbuf = (char*)b;                         \
245 +        return rlen;                              \
246 +    }
247 +
248 +
249 +static ErlDrvData start( ErlDrvPort port, char* command ) {
250 +  printf( "PAM-AUTH driver start\r\n" );
251 +  #ifndef LINKEDLIBPAM
252 +    init_libpam();
253 +  #endif
254 +  ejabberd_pam_data *d = (ejabberd_pam_data *)driver_alloc( sizeof( ejabberd_pam_data ));
255 +  d->port = port;
256 +  set_port_control_flags( port, PORT_CONTROL_FLAG_BINARY );
257 +  return (ErlDrvData)d;
258 +};
259 +
260 +static void stop( ErlDrvData handle ) {
261 +  driver_free( (char *)handle );
262 +  #ifndef LINKEDLIBPAM
263 +    fin_libpam();
264 +  #endif
265 +  printf( "PAM-AUTH driver stop\r\n" );
266 +};
267 +
268 +static int auth_params( char* buf, PromptMatch* head ) {
269 +  int iSize = 0;
270 +  int iIndex = 0;
271 +  int iResult = 0;
272 +  char* prompt = NULL;
273 +  char* response = NULL;
274 +  // Parse the version and tuple header
275 +  ei_decode_version( buf, &iIndex, &iSize );
276 +  ei_decode_tuple_header( buf, &iIndex, &iSize );
277 +  if ( iSize == 2 ) {
278 +    // The first item in the tuple should be the username
279 +    DECODE_STRING( buf, &iIndex, response );
280 +    *head = _newMatch( *head, strdup( "login" ), response );
281 +
282 +    // The second item in the tuple should be a list of tuples
283 +    // Each tuple in the list consists of the expected prompt string
284 +    // and the value to return at that prompt
285 +    ei_decode_list_header( buf, &iIndex, &iSize );
286 +
287 +    // Loop over the list and pull out each prompt/response tuple and
288 +    // store it into a PromptItem list that will get processed in
289 +    // the PAM conversation
290 +    int ii = 0;
291 +    for ( ii = 0; ii < iSize; ii++ ) {
292 +      int iTupleSize = 0;
293 +      ei_decode_tuple_header( buf, &iIndex, &iTupleSize );
294 +      if ( iTupleSize != 2 ) {
295 +        printf( "Incorrect number of arguments in prompt/response tuple(index %d): %d\r\n", ii, iTupleSize );
296 +      } else {
297 +        // Decode the prompt from the tuple
298 +        DECODE_STRING( buf, &iIndex, prompt );
299 +        DECODE_STRING( buf, &iIndex, response );
300 +        // Add a new prompt item to track this prompt/response pair
301 +        *head = _newMatch( *head, prompt, response );
302 +      };
303 +    };
304 +    iResult = 1;
305 +  };
306 +  return iResult;
307 +};
308 +
309 +static int auth( PromptMatch head ) {
310 +  // Setup PAM conversation structure; pass in the prompt match list
311 +  // so we can process the prompts from PAM
312 +  int flags = 0; //PAM_SILENT
313 +  int iResult = 0;
314 +  pam_handle_t* pam = NULL;
315 +  
316 +  char* service = _findMatch( head, "service" );
317 +  char* username = _findMatch( head, "login" );
318 +
319 +  struct pam_conv conv = { pam_conversation, head };
320 +
321 +  // Spin up PAM
322 +  int rc = pam_start( service, username, &conv, &pam );
323 +  if ( rc == PAM_SUCCESS ) {      
324 +    // Attempt to authenticate the user
325 +    rc = pam_authenticate( pam, flags );
326 +    if ( rc != PAM_SUCCESS )
327 +      printf("Authentication failed for: %s. Error: %s\r\n", username, pam_strerror( NULL, rc ));
328 +    else   
329 +      iResult = 1;
330 +    pam_end( pam, rc );
331 +  } else
332 +    printf("Unable to spin up PAM: %s\r\n", pam_strerror( NULL, rc ));
333 +  return iResult;
334 +};
335 +
336 +static int control( ErlDrvData drv_data, unsigned int command, char *buf, 
337 +                    int len, char** rbuf, int rlen ) {
338 +  int iResult;
339 +  PromptMatch head = NULL;
340 +  if (( iResult = auth_params( buf, &head )) != 0 ) {
341 +    iResult = auth( head );
342 +    _cleanupMatch( head );
343 +  };
344 +  RETURN_INT( iResult );
345 +};
346 +
347 +ErlDrvEntry entry = {
348 +  NULL,                        /* F_PTR init, N/A */
349 +  start,               /* L_PTR start, called when port is opened */
350 +  stop,                        /* F_PTR stop, called when port is closed */
351 +  NULL,                        /* F_PTR output, called when erlang has sent */
352 +  NULL,                        /* F_PTR ready_input, called when input descriptor ready */
353 +  NULL,                        /* F_PTR ready_output, called when output descriptor ready */
354 +  "ejabberd_auth_pam",  /* char *driver_name, the argument to open_port */
355 +  NULL,                        /* F_PTR finish, called when unloaded */
356 +  NULL,                        /* handle */
357 +  control,             /* F_PTR control, port_command callback */
358 +  NULL,                        /* F_PTR timeout, reserved */
359 +  NULL                 /* F_PTR outputv, reserved */
360 +};
361 +
362 +DRIVER_INIT(ejabberd_auth_pam) /* must match name in driver_entry */
363 +{
364 +  return &entry;
365 +};
366 Index: pam/ejabberd_auth_pam.erl
367 ===================================================================
368 --- pam/ejabberd_auth_pam.erl   (revisión: 0)
369 +++ pam/ejabberd_auth_pam.erl   (revisión: 0)
370 @@ -0,0 +1,90 @@
371 +-module(ejabberd_auth_pam).
372 +-author('').
373 +
374 +-export([
375 +         start/1,
376 +         plain_password_required/0, 
377 +         set_password/3, 
378 +        try_register/3,
379 +         remove_user/2,
380 +         remove_user/3, 
381 +         get_password/2,
382 +         get_password_s/2,
383 +         is_user_exists/2,
384 +         get_vh_registered_users/1,
385 +         check_password/3,
386 +        check_password/5
387 +        ]).
388 +
389 +start( _Host ) ->
390 +  case erl_ddll:load_driver( ejabberd:get_so_path(), ejabberd_auth_pam) of
391 +    ok -> ok;
392 +    {error, already_loaded} -> ok;
393 +    Error -> exit({error, could_not_load_driver, Error})
394 +  end.
395 +
396 +plain_password_required() ->
397 +  true.
398 +
399 +check_password( User, Server, Password ) ->
400 +  PAMService = 
401 +        case ejabberd_config:get_local_option( { pam_service, Server } ) of
402 +                undefined -> 
403 +                    "login";
404 +                Service -> 
405 +                    Service
406 +              end,
407 +  PAMPrompt = 
408 +        case ejabberd_config:get_local_option( { pam_prompt_pwd, Server } ) of
409 +                undefined -> 
410 +                    "Password:";
411 +                Prompt -> 
412 +                    Prompt
413 +              end,
414 +  Port = open_port( { spawn, ejabberd_auth_pam }, [ binary ] ),
415 +  Bin = term_to_binary( { User, [ { PAMPrompt, Password }, { "service", PAMService } ] }),
416 +  Res = port_control( Port, 1, Bin ),
417 +  case Res of
418 +    <<0>> -> false;
419 +    <<1>> -> true;
420 +    _ -> undefined
421 +  end.
422 +
423 +check_password( User, Server, Password,  _StreamID, _Digest ) ->
424 +  check_password( User, Server,  Password ).
425 +
426 +set_password( _User, _Server, _Password ) ->
427 +  { error, not_allowed }.
428 +
429 +try_register( _User, _Server, _Password ) ->
430 +  { error, not_allowed }.
431 +
432 +remove_user( _User, _Server ) ->
433 +  { error, not_allowed }.
434 +
435 +remove_user( _User, _Server, _Password ) ->
436 +  { error, not_allowed }.
437 +    
438 +get_vh_registered_users( _Server ) ->
439 +  [].
440 +    
441 +is_user_exists( _User, _Server ) ->
442 +  {ok,FileBin}=file:read_file("/etc/passwd"),
443 +  Tmp=binary_to_list(FileBin),
444 +  FileStr=string:concat("\n", Tmp),
445 +
446 +  Tmp2=string:concat("\n", _User),
447 +  RegExp=string:concat(Tmp2, ":"),
448 +
449 +  case regexp:match(FileStr, RegExp) of
450 +    {match, _, _}  ->
451 +        true;
452 +    _ ->
453 +        false
454 +  end.
455 +
456 +get_password( _User, _Server ) ->
457 +  false.
458 +
459 +get_password_s( _User, _Server ) ->
460 +  "".
461 Index: aclocal.m4
462 ===================================================================
463 --- aclocal.m4  (revisión: 705)
464 +++ aclocal.m4  (copia de trabajo)
465 @@ -292,3 +292,32 @@
466  fi
467  ])
468  dnl <openssl/>
469 +
470 +AC_DEFUN(AM_WITH_PAM,
471 +[ AC_ARG_WITH(pam, [ --with-pam=PREFIX  prefix where PAM is installed ])
472 +unset PAM_LIBS;
473 +unset PAM_CFLAGS;
474 +
475 +if test x"$with_pam" != x; then
476 +       PAM_CFLAGS="-I$with_pam/include"
477 +   PAM_LIBS="-L$with_pam/lib"
478 +fi
479 +
480 +AC_CHECK_LIB(pam, pam_start, 
481 +       [ PAM_LIBS="$PAM_LIBS -lpam" pam_found=yes ],
482 +       [ pam_found=no ],
483 +       "$PAM_LIBS")
484 +
485 +if test $pam_found = yes; then
486 +   pam_save_CFLAGS="$CFLAGS"
487 +   CFLAGS="$PAM_CFLAGS $CFLAGS"
488 +   AC_CHECK_HEADERS(security/pam_appl.h, ,$pam_found=no)
489 +   if test $pam_found = no; then
490 +      AC_MSG_ERROR([Could not find security/pam_appl.h])
491 +   fi
492 +   CFLAGS=$pam_save_CFLAGS
493 +
494 +   AC_SUBST(PAM_CFLAGS)
495 +   AC_SUBST(PAM_LIBS)
496 +fi
497 +])
This page took 0.077336 seconds and 3 git commands to generate.