~ubuntu-branches/debian/squeeze/nss-pam-ldapd/squeeze

« back to all changes in this revision

Viewing changes to pam/pam.c

  • Committer: Bazaar Package Importer
  • Author(s): Arthur de Jong
  • Date: 2009-10-20 12:00:00 UTC
  • Revision ID: james.westby@ubuntu.com-20091020120000-di0099d0pliwbsz1
Tags: 0.7.1
* implement password changing by performing an LDAP password modify EXOP
  request (closes: #550836)
* fix return of authorisation check in PAM module (patch by Howard Chu)
* fix "Use StartTLS?" debconf question when no ssl option is defined in the
  config
* fix for problem when authenticating to LDAP entries without a uid
  attribute in the DN
* general code clean-up and portability improvements and include all
  needed header files (closes: #547206)
* provide more information with communication error messages
* updated German debconf translation by Erik Schanze (closes: #546244)
* updated Vietnamese debconf translation by Clytie Siddall (closes: #548037)

Show diffs side-by-side

added added

removed removed

Lines of Context:
20
20
   02110-1301 USA
21
21
*/
22
22
 
23
 
/*
24
 
   WARNING: this code is under development and the details of the protocol
25
 
            may change between releases.
26
 
*/
27
 
 
28
23
#include "config.h"
29
24
 
30
25
#include <stdlib.h>
31
26
#include <string.h>
32
27
#include <errno.h>
33
28
#include <syslog.h>
 
29
#include <unistd.h>
 
30
#include <sys/types.h>
34
31
 
35
32
#include "common.h"
36
33
#include "compat/attrs.h"
 
34
#include "compat/pam_compat.h"
37
35
 
38
36
/* these are defined (before including pam_modules.h) for staticly linking */
39
37
#define PAM_SM_AUTH
41
39
#define PAM_SM_SESSION
42
40
#define PAM_SM_PASSWORD
43
41
 
 
42
#ifdef HAVE_SECURITY_PAM_APPL_H
 
43
#include <security/pam_appl.h>
 
44
#endif /* HAVE_SECURITY_PAM_APPL_H */
44
45
#ifndef HAVE_PAM_PAM_MODULES_H
45
46
#include <security/pam_modules.h>
46
 
#else
 
47
#ifdef HAVE_SECURITY_PAM_EXT_H
 
48
#include <security/pam_ext.h>
 
49
#endif /* HAVE_SECURITY_PAM_EXT_H */
 
50
#else /* not HAVE_PAM_PAM_MODULES_H */
47
51
#include <pam/pam_modules.h>
48
 
#endif
 
52
#endif /* not HAVE_PAM_PAM_MODULES_H */
49
53
 
50
54
#define IGNORE_UNKNOWN  1
51
55
#define IGNORE_UNAVAIL  2
56
60
 
57
61
#define PLD_CTX "PAM_LDAPD_CTX"
58
62
 
 
63
/* some systems don't have LOG_AUTHPRIV */
 
64
#ifndef LOG_AUTHPRIV
 
65
#define LOG_AUTHPRIV LOG_AUTH
 
66
#endif /* not LOG_AUTHPRIV */
 
67
 
59
68
/* this struct represents that context that the PAM module keeps
60
69
   between calls */
61
70
typedef struct pld_ctx {
63
72
  char *dn;
64
73
  char *tmpluser;
65
74
  char *authzmsg;
66
 
  char *oldpw;
 
75
  char *oldpassword;
67
76
  int authok;
68
77
  int authz;
69
78
  int sessid;
100
109
    free(ctx->user);
101
110
    ctx->user=NULL;
102
111
  }
103
 
  if (ctx->oldpw)
 
112
  if (ctx->oldpassword)
104
113
  {
105
 
    memset(ctx->oldpw,0,strlen(ctx->oldpw));
106
 
    free(ctx->oldpw);
107
 
    ctx->oldpw=NULL;
 
114
    memset(ctx->oldpassword,0,strlen(ctx->oldpassword));
 
115
    free(ctx->oldpassword);
 
116
    ctx->oldpassword=NULL;
108
117
  }
109
118
  ctx->dn=NULL;
110
119
  ctx->tmpluser=NULL;
152
161
}
153
162
 
154
163
/* ask the user for an authentication token (password) */
155
 
static int pam_get_authtok(pam_handle_t *pamh,int flags,char *prompt1,char *prompt2,char **pwd)
 
164
static int my_pam_get_authtok(pam_handle_t *pamh,int flags,char *prompt1,char *prompt2,const char **pwd)
156
165
{
157
166
  int rc;
158
167
  char *p;
219
228
}
220
229
 
221
230
/* perform an authentication call over nslcd */
222
 
static int nslcd_request_authc(pld_ctx *ctx,const char *username,const char *svc,const char *passwd)
 
231
static int nslcd_request_authc(pld_ctx *ctx,const char *username,
 
232
                               const char *service,const char *passwd)
223
233
{
224
234
  PAM_REQUEST(NSLCD_ACTION_PAM_AUTHC,
225
235
    /* write the request parameters */
226
236
    WRITE_STRING(fp,username);
227
237
    WRITE_STRING(fp,ctx->dn);
228
 
    WRITE_STRING(fp,svc);
 
238
    WRITE_STRING(fp,service);
229
239
    WRITE_STRING(fp,passwd),
230
240
    /* read the result entry */
231
241
    READ_BUF_STRING(fp,ctx->tmpluser);
278
288
  {
279
289
    if (!first_pass)
280
290
    {
281
 
      rc=pam_get_authtok(pamh,flags,i==0?"Password: ":"LDAP Password: ",NULL,&passwd);
 
291
      rc=my_pam_get_authtok(pamh,flags,i==0?"Password: ":"LDAP Password: ",NULL,(const char **)&passwd);
282
292
      if (rc!=PAM_SUCCESS)
283
293
        return rc;
284
294
      /* exit loop after trying this password */
309
319
    ctx->user=strdup(username);
310
320
    /* if password change is required, save old password in context */
311
321
    if (ctx->authz==PAM_NEW_AUTHTOK_REQD)
312
 
      ctx->oldpw=strdup(passwd);
 
322
      ctx->oldpassword=strdup(passwd);
313
323
  }
314
324
  /* update caller's idea of the user name */
315
325
  if ( (rc==PAM_SUCCESS) && ctx->tmpluser && ctx->tmpluser[0] &&
320
330
}
321
331
 
322
332
/* called to update the authentication credentials */
323
 
int pam_sm_setcred(pam_handle_t *pamh,int flags,int argc,const char **argv)
 
333
int pam_sm_setcred(pam_handle_t UNUSED(*pamh),int UNUSED(flags),
 
334
                   int UNUSED(argc),const char UNUSED(**argv))
324
335
{
325
336
  /* we don't need to do anything here */
326
337
  return PAM_SUCCESS;
327
338
}
328
339
 
329
 
static int pam_warn(
 
340
static int my_pam_warn(
330
341
  struct pam_conv *aconv, const char *message, int style, int no_warn)
331
342
{
332
343
  struct pam_message msg, *pmsg;
338
349
  pmsg=&msg;
339
350
 
340
351
  msg.msg_style=style;
341
 
  msg.msg=(char *) message;
 
352
  msg.msg=(char *)message;
342
353
  resp=NULL;
343
354
 
344
355
  return aconv->conv(1,
348
359
 
349
360
/* perform an authorisation call over nslcd */
350
361
static int nslcd_request_authz(pld_ctx *ctx,const char *username,
351
 
        const char *svc,const char *ruser,const char *rhost,const char *tty)
 
362
                               const char *service,const char *ruser,
 
363
                               const char *rhost,const char *tty)
352
364
{
353
365
  PAM_REQUEST(NSLCD_ACTION_PAM_AUTHZ,
354
366
    /* write the request parameters */
355
367
    WRITE_STRING(fp,username);
356
368
    WRITE_STRING(fp,ctx->dn);
357
 
    WRITE_STRING(fp,svc);
 
369
    WRITE_STRING(fp,service);
358
370
    WRITE_STRING(fp,ruser);
359
371
    WRITE_STRING(fp,rhost);
360
372
    WRITE_STRING(fp,tty),
436
448
  if (rc!=PAM_SUCCESS)
437
449
  {
438
450
    if (rc!=PAM_IGNORE)
439
 
      pam_warn(appconv,"LDAP authorization failed",PAM_ERROR_MSG,no_warn);
 
451
      my_pam_warn(appconv,"LDAP authorization failed",PAM_ERROR_MSG,no_warn);
440
452
  }
441
453
  else
442
454
  {
 
455
    rc=ctx2.authz;
443
456
    if (ctx2.authzmsg && ctx2.authzmsg[0])
444
 
      pam_warn(appconv,ctx2.authzmsg,PAM_TEXT_INFO,no_warn);
 
457
      my_pam_warn(appconv,ctx2.authzmsg,PAM_TEXT_INFO,no_warn);
445
458
    if (ctx2.authz==PAM_SUCCESS)
446
459
    {
447
460
      rc=ctx->authz;
448
461
      if (ctx->authzmsg && ctx->authzmsg[0])
449
 
        pam_warn(appconv,ctx->authzmsg,PAM_TEXT_INFO,no_warn);
 
462
        my_pam_warn(appconv,ctx->authzmsg,PAM_TEXT_INFO,no_warn);
450
463
    }
451
464
  }
452
465
 
459
472
}
460
473
 
461
474
/* do a session nslcd request (open or close) */
462
 
static int nslcd_request_sess(pam_handle_t *pamh,pld_ctx *ctx,int action)
 
475
static int nslcd_request_sess(pld_ctx *ctx,int action,const char *service,
 
476
                              const char *tty, const char *rhost,
 
477
                              const char *ruser)
463
478
{
464
 
  const char *svc=NULL,*tty=NULL,*rhost=NULL,*ruser=NULL;
465
479
  PAM_REQUEST(action,
466
 
    /* get information for request (ignore errors) */
467
 
    pam_get_item(pamh,PAM_SERVICE,(const void **)&svc);
468
 
    pam_get_item(pamh,PAM_TTY,(const void **)&tty);
469
 
    pam_get_item(pamh,PAM_RHOST,(const void **)&rhost);
470
 
    pam_get_item(pamh,PAM_RUSER,(const void **)&ruser);
471
480
    /* write the request parameters */
472
481
    WRITE_STRING(fp,ctx->user);
473
482
    WRITE_STRING(fp,ctx->dn);
474
 
    WRITE_STRING(fp,svc);
 
483
    WRITE_STRING(fp,service);
475
484
    WRITE_STRING(fp,tty);
476
485
    WRITE_STRING(fp,rhost);
477
486
    WRITE_STRING(fp,ruser);
484
493
  pam_handle_t *pamh, int flags, int argc, const char **argv,
485
494
  int action, int *no_warn)
486
495
{
487
 
  int rc, err;
 
496
  int rc;
488
497
  const char *username;
489
498
  int ignore_flags=0;
490
 
  int i, success=PAM_SUCCESS;
 
499
  int i;
491
500
  pld_ctx *ctx=NULL;
 
501
  const char *service=NULL,*tty=NULL,*rhost=NULL,*ruser=NULL;
492
502
 
493
503
  for (i=0;i<argc;i++)
494
504
  {
521
531
  rc=ctx_get(pamh,username,&ctx);
522
532
  if (rc!=PAM_SUCCESS)
523
533
    return rc;
524
 
 
525
 
  rc=nslcd_request_sess(pamh,ctx,action);
 
534
  /* read PAM information */
 
535
  pam_get_item(pamh,PAM_SERVICE,(const void **)&service);
 
536
  pam_get_item(pamh,PAM_TTY,(const void **)&tty);
 
537
  pam_get_item(pamh,PAM_RHOST,(const void **)&rhost);
 
538
  pam_get_item(pamh,PAM_RUSER,(const void **)&ruser);
 
539
  /* do the nslcd request */
 
540
  rc=nslcd_request_sess(ctx,action,service,tty,rhost,ruser);
526
541
  if ((rc==PAM_AUTHINFO_UNAVAIL)&&(ignore_flags&IGNORE_UNAVAIL))
527
542
    rc=PAM_IGNORE;
528
543
  else if ((rc==PAM_USER_UNKNOWN)&&(ignore_flags&IGNORE_UNKNOWN))
542
557
 
543
558
  rc=pam_sm_session(pamh,flags,argc,argv,NSLCD_ACTION_PAM_SESS_O,&no_warn);
544
559
  if ((rc!=PAM_SUCCESS)&&(rc!=PAM_IGNORE))
545
 
    pam_warn(appconv,"LDAP open_session failed",PAM_ERROR_MSG,no_warn);
 
560
    my_pam_warn(appconv,"LDAP open_session failed",PAM_ERROR_MSG,no_warn);
546
561
  return rc;
547
562
}
548
563
 
549
564
int pam_sm_close_session(
550
565
  pam_handle_t *pamh, int flags, int argc, const char **argv)
551
566
{
552
 
  int rc, no_warn=0;;
 
567
  int rc, no_warn=0;
553
568
  struct pam_conv *appconv;
554
569
 
555
570
  rc=pam_get_item(pamh,PAM_CONV,(const void **)&appconv);
558
573
 
559
574
  rc=pam_sm_session(pamh,flags,argc,argv,NSLCD_ACTION_PAM_SESS_C,&no_warn);
560
575
  if ((rc!=PAM_SUCCESS)&&(rc!=PAM_IGNORE))
561
 
    pam_warn(appconv,"LDAP close_session failed",PAM_ERROR_MSG,no_warn);
 
576
    my_pam_warn(appconv,"LDAP close_session failed",PAM_ERROR_MSG,no_warn);
562
577
  return rc;
563
578
}
564
579
 
565
580
/* do a password modification nslcd call */
566
 
static int nslcd_request_pwmod(pld_ctx *ctx,const char *username,const char *svc,
567
 
                    const char *oldpw,const char *newpw)
 
581
static int nslcd_request_pwmod(pld_ctx *ctx,const char *username,
 
582
                               const char *service,const char *oldpasswd,
 
583
                               const char *newpasswd)
568
584
{
569
 
  PAM_REQUEST(NSLCD_ACTION_PAM_AUTHZ,
 
585
  PAM_REQUEST(NSLCD_ACTION_PAM_PWMOD,
570
586
    /* write the request parameters */
571
587
    WRITE_STRING(fp,username);
572
588
    WRITE_STRING(fp,ctx->dn);
573
 
    WRITE_STRING(fp,svc);
574
 
    WRITE_STRING(fp,oldpw);
575
 
    WRITE_STRING(fp,newpw),
 
589
    WRITE_STRING(fp,service);
 
590
    WRITE_STRING(fp,oldpasswd);
 
591
    WRITE_STRING(fp,newpasswd),
576
592
    /* read the result entry */
577
593
    READ_BUF_STRING(fp,ctx->tmpluser);
578
594
    READ_BUF_STRING(fp,ctx->dn);
580
596
    READ_BUF_STRING(fp,ctx->authzmsg);)
581
597
}
582
598
 
583
 
int pam_sm_chauthtok(
584
 
  pam_handle_t *pamh, int flags, int argc, const char **argv)
585
 
{
586
 
  int rc;
587
 
  const char *username, *p=NULL, *q=NULL, *svc;
 
599
/* ensure that the context includes and oldpassword field */
 
600
static const char *get_old_password(pam_handle_t *pamh, int flags,pld_ctx *ctx)
 
601
{
 
602
  int rc;
 
603
  const char *oldpassword;
 
604
  /* if we already have an old password we are done */
 
605
  if ((ctx->oldpassword!=NULL)&&(*ctx->oldpassword!='\0'))
 
606
    return ctx->oldpassword;
 
607
  /* try to get the old password from the PAM stack */
 
608
  rc=pam_get_item(pamh,PAM_OLDAUTHTOK,(const void **)&oldpassword);
 
609
  if ((rc==PAM_SUCCESS)&&(oldpassword!=NULL)&&(*oldpassword!='\0'))
 
610
    return oldpassword;
 
611
  /* otherwise prompt for it */
 
612
  rc=my_pam_get_authtok(pamh,flags,"(current) LDAP Password: ",NULL,
 
613
                     (const char **)&oldpassword);
 
614
  if ((rc==PAM_SUCCESS)&&(oldpassword!=NULL)&&(*oldpassword!='\0'))
 
615
  {
 
616
    /* save the password */
 
617
    pam_set_item(pamh,PAM_OLDAUTHTOK,oldpassword);
 
618
    return oldpassword;
 
619
  }
 
620
  return NULL;
 
621
}
 
622
 
 
623
/* Change the password of the user. This function is first called with
 
624
   PAM_PRELIM_CHECK set in the flags and then without the flag. In the first
 
625
   pass it is determined whether we can contact the LDAP server and the
 
626
   provided old password is valid. In the second pass we get the new
 
627
   password and actually modify the password. */
 
628
int pam_sm_chauthtok(pam_handle_t *pamh,int flags,int argc,const char **argv)
 
629
{
 
630
  int rc;
 
631
  const char *username,*service;
 
632
  const char *oldpassword=NULL;
 
633
  const char *newpassword=NULL;
588
634
  int first_pass=0, no_warn=0, ignore_flags=0;
589
 
  int i, success=PAM_SUCCESS;
 
635
  int i;
590
636
  struct pam_conv *appconv;
591
637
  pld_ctx *ctx=NULL;
592
638
 
628
674
  if (rc!=PAM_SUCCESS)
629
675
    return rc;
630
676
 
631
 
  rc=pam_get_item(pamh,PAM_SERVICE,(const void **)&svc);
 
677
  rc=pam_get_item(pamh,PAM_SERVICE,(const void **)&service);
632
678
  if (rc!=PAM_SUCCESS)
633
679
    return rc;
634
 
 
635
 
  if (flags & PAM_PRELIM_CHECK) {
636
 
    if (getuid()) {
637
 
      if (!first_pass) {
638
 
        rc=pam_get_authtok(pamh,flags,"(current) LDAP Password: ",NULL,&p);
639
 
        if (rc==PAM_SUCCESS) {
640
 
          pam_set_item(pamh,PAM_OLDAUTHTOK,p);
641
 
          memset(p,0,strlen(p));
642
 
          free(p);
643
 
        }
644
 
      }
645
 
      rc=pam_get_item(pamh,PAM_OLDAUTHTOK,&p);
646
 
      if (rc)
647
 
        return rc;
648
 
    }
649
 
    else
650
 
      rc=PAM_SUCCESS;
651
 
    if (!ctx->dn)
652
 
    {
653
 
      rc=nslcd_request_pwmod(ctx,username,svc,p,NULL);
654
 
      if ((rc==PAM_AUTHINFO_UNAVAIL)&&(ignore_flags&IGNORE_UNAVAIL))
655
 
        rc=PAM_IGNORE;
656
 
      else if ((rc==PAM_USER_UNKNOWN)&&(ignore_flags&IGNORE_UNKNOWN))
657
 
        rc=PAM_IGNORE;
658
 
    }
659
 
    return rc;
660
 
  }
661
 
 
662
 
  rc=pam_get_item(pamh,PAM_OLDAUTHTOK,&p);
663
 
  if (rc)
664
 
    return rc;
665
 
 
666
 
  if (!p)
667
 
    p=ctx->oldpw;
668
 
 
669
 
  if (first_pass)
670
 
  {
671
 
    rc=pam_get_item(pamh,PAM_AUTHTOK,&q);
672
 
    if ((rc!=PAM_SUCCESS || !q) && (first_pass & (USE_FIRST|USE_TOKEN))) {
673
 
      if (rc==PAM_SUCCESS)
674
 
        rc=PAM_AUTHTOK_RECOVERY_ERR;
675
 
      return rc;
676
 
    }
677
 
  }
678
 
  if (!q)
679
 
  {
680
 
    rc=pam_get_authtok(pamh, flags, "Enter new LDAP Password: ",
681
 
      "Retype new LDAP Password: ", &q);
 
680
  /* TODO: if we are root we may want to authenticate with the LDAP
 
681
           administrator password (this shouldn't be a problem because
 
682
           root is unlikely to be in LDAP anyway but perhaps we can check
 
683
           the requested username and only use the administrator if that
 
684
           isn't root) */
 
685
  /* prelimenary check, just see if we can connect to the LDAP server
 
686
     and authenticate with the current password */
 
687
  if (flags&PAM_PRELIM_CHECK)
 
688
  {
 
689
    /* get old (current) password */
 
690
    oldpassword=get_old_password(pamh,flags,ctx);
 
691
    /* check the old password */
 
692
    rc=nslcd_request_authc(ctx,username,service,oldpassword);
682
693
    if (rc==PAM_SUCCESS)
683
 
    {
684
 
      pam_set_item(pamh,PAM_AUTHTOK,q);
685
 
      memset(q,0,strlen(q));
686
 
      free(q);
687
 
      rc=pam_get_item(pamh,PAM_AUTHTOK,&q);
688
 
    }
689
 
    if (rc!=PAM_SUCCESS)
690
 
      return rc;
 
694
      rc=ctx->authok;
 
695
    if ((rc==PAM_AUTHINFO_UNAVAIL)&&(ignore_flags&IGNORE_UNAVAIL))
 
696
      rc=PAM_IGNORE;
 
697
    else if ((rc==PAM_USER_UNKNOWN)&&(ignore_flags&IGNORE_UNKNOWN))
 
698
      rc=PAM_IGNORE;
 
699
    /* TODO: figure out when to return PAM_TRY_AGAIN */
 
700
    /* TODO: if password is incorrect (NSLCD_PAM_AUTH_ERR) log that */
 
701
    return rc;
691
702
  }
692
 
  rc=nslcd_request_pwmod(ctx,username,svc,p,q);
693
 
  if ((rc==PAM_AUTHINFO_UNAVAIL)&&(ignore_flags&IGNORE_UNAVAIL))
694
 
    rc=PAM_IGNORE;
695
 
  else if ((rc==PAM_USER_UNKNOWN)&&(ignore_flags&IGNORE_UNKNOWN))
696
 
    rc=PAM_IGNORE;
697
 
  p=NULL; q=NULL;
 
703
  /* get the old password (from the previous call) */
 
704
  rc=pam_get_item(pamh,PAM_OLDAUTHTOK,(const void **)&oldpassword);
 
705
  if (rc!=PAM_SUCCESS)
 
706
    return rc;
 
707
  /* get the new password */
 
708
  rc=pam_get_authtok(pamh,PAM_AUTHTOK,&newpassword,NULL);
 
709
  if (rc!=PAM_SUCCESS)
 
710
    return rc;
 
711
  /* perform the password modification */
 
712
  rc=nslcd_request_pwmod(ctx,username,service,oldpassword,newpassword);
698
713
  if (rc==PAM_SUCCESS)
699
 
  {
700
714
    rc=ctx->authz;
701
 
    if (rc!=PAM_SUCCESS)
702
 
      pam_warn(appconv, ctx->authzmsg, PAM_ERROR_MSG, no_warn);
703
 
  }
704
 
  else if (rc!=PAM_IGNORE)
705
 
    pam_warn(appconv, "LDAP pwmod failed", PAM_ERROR_MSG, no_warn);
 
715
  else
 
716
    ctx->authzmsg=(char *)pam_strerror(pamh,rc);
 
717
  if ((rc==PAM_AUTHINFO_UNAVAIL)&&(ignore_flags&IGNORE_UNAVAIL))
 
718
    rc=PAM_IGNORE;
 
719
  else if ((rc==PAM_USER_UNKNOWN)&&(ignore_flags&IGNORE_UNKNOWN))
 
720
    rc=PAM_IGNORE;
 
721
  else
 
722
    my_pam_warn(appconv,ctx->authzmsg,PAM_ERROR_MSG,no_warn);
706
723
  return rc;
707
724
}
708
725