~ubuntu-branches/ubuntu/precise/nss-pam-ldapd/precise-security

« back to all changes in this revision

Viewing changes to nslcd/pam.c

  • Committer: Package Import Robot
  • Author(s): Arthur de Jong
  • Date: 2011-09-04 21:00:00 UTC
  • mfrom: (14.1.4 experimental)
  • Revision ID: package-import@ubuntu.com-20110904210000-pe3u91iga88vtr16
Tags: 0.8.4
* Upload to unstable
* switch to using the member attribute by default instead of
  uniqueMember (backwards incompatible change)
* only return "x" as a password hash when the object has the shadowAccount
  objectClass and nsswitch.conf is configured to do shadow lookups using
  LDAP (this avoids some problems with pam_unix)
* fix problem with partial attribute name matches in DN (thanks Timothy
  White)
* fix a problem with objectSid mappings with recent versions of OpenLDAP
  (patch by Wesley Mason)
* set the socket timeout in a connection callback to avoid timeout
  issues during the SSL handshake (patch by Stefan Völkel)
* check for unknown variables in pam_authz_search
* only check password expiration when authenticating, only check account
  expiration when doing authorisation
* make buffer sizes consistent and grow all buffers holding string
  representations of numbers to be able to hold 64-bit numbers
* update AX_PTHREAD from autoconf-archive
* support querying DNS SRV records from a different domain than the current
  one (based on a patch by James M. Leddy)
* fix a problem with uninitialised memory while parsing the tls_ciphers
  option (closes: #638872) (but doesn't work yet due to #640384)
* implement bounds checking of numeric values read from LDAP (patch by
  Jakub Hrozek)
* correctly support large uid and gid values from LDAP (patch by Jakub
  Hrozek)
* improvements to the configure script (patch by Jakub Hrozek)
* switch to dh for debian/rules and bump debhelper compatibility to 8
* build Debian packages with multiarch support
* ship shlibs (but still no symbol files) for libnss-ldapd since that was
  the easiest way to support multiarch
* fix output in init script when restarting nslcd (closes: #637132)
* correctly handle leading and trailing spaces in preseeded debconf uri
  option (patch by Andreas B. Mundt) (closes: #637863)
* support spaces around database names in /etc/nsswitch.conf while
  configuring package (closes: #640185)
* updated Russian debconf translation by Yuri Kozlov (closes: #637751)
* updated French debconf translation by Christian Perrier (closes: #637756)
* added Slovak debconf translation by Slavko (closes: #637759)
* updated Danish debconf translation by Joe Hansen (closes :#637763)
* updated Brazilian Portuguese debconf translation by Denis Doria
* updated Portuguese debconf translation by Américo Monteiro
* updated Japanese debconf translation by Kenshi Muto (closes: #638195)
* updated Czech debconf translation by Miroslav Kure (closes: #639026)
* updated German debconf translation by Chris Leick (closes: #639107)
* updated Spanish debconf translation by Francisco Javier Cuadrado
  (closes: #639236)
* updated Dutch debconf translation by Arthur de Jong with help from Paul
  Gevers and Jeroen Schot

Show diffs side-by-side

added added

removed removed

Lines of Context:
2
2
   pam.c - pam processing routines
3
3
 
4
4
   Copyright (C) 2009 Howard Chu
5
 
   Copyright (C) 2009, 2010 Arthur de Jong
 
5
   Copyright (C) 2009, 2010, 2011 Arthur de Jong
6
6
 
7
7
   This library is free software; you can redistribute it and/or
8
8
   modify it under the terms of the GNU Lesser General Public
29
29
#include <stdint.h>
30
30
#endif /* HAVE_STDINT_H */
31
31
#include <unistd.h>
 
32
#include <time.h>
32
33
 
33
34
#include "common.h"
34
35
#include "log.h"
38
39
#include "common/dict.h"
39
40
#include "common/expr.h"
40
41
 
41
 
#ifndef HOST_NAME_MAX
42
 
#define HOST_NAME_MAX 255
43
 
#endif /* not HOST_NAME_MAX */
44
 
 
45
 
/* set up a connection and try to bind with the specified DN and password
46
 
   returns a NSLCD_PAM_* error code */
 
42
/* set up a connection and try to bind with the specified DN and password,
 
43
   returns an LDAP result code */
47
44
static int try_bind(const char *userdn,const char *password)
48
45
{
49
46
  MYLDAP_SESSION *session;
50
 
  char *username;
 
47
  MYLDAP_SEARCH *search;
 
48
  MYLDAP_ENTRY *entry;
 
49
  static const char *attrs[2];
51
50
  int rc;
52
51
  /* set up a new connection */
53
52
  session=myldap_create_session();
54
53
  if (session==NULL)
55
 
    return NSLCD_PAM_AUTH_ERR;
 
54
    return LDAP_UNAVAILABLE;
56
55
  /* set up credentials for the session */
57
56
  myldap_set_credentials(session,userdn,password);
58
57
  /* perform search for own object (just to do any kind of search) */
59
 
  username=lookup_dn2uid(session,userdn,&rc);
60
 
  if (username!=NULL)
61
 
    free(username);
 
58
  attrs[0]="dn";
 
59
  attrs[1]=NULL;
 
60
  search=myldap_search(session,userdn,LDAP_SCOPE_BASE,"(objectClass=*)",attrs,&rc);
 
61
  if ((search==NULL)||(rc!=LDAP_SUCCESS))
 
62
  {
 
63
    if (rc==LDAP_SUCCESS)
 
64
      rc=LDAP_LOCAL_ERROR;
 
65
    log_log(LOG_WARNING,"lookup of %s failed: %s",userdn,ldap_err2string(rc));
 
66
  }
 
67
  else
 
68
  {
 
69
    entry=myldap_get_entry(search,&rc);
 
70
    if ((entry==NULL)||(rc!=LDAP_SUCCESS))
 
71
    {
 
72
      if (rc==LDAP_SUCCESS)
 
73
        rc=LDAP_NO_RESULTS_RETURNED;
 
74
      log_log(LOG_WARNING,"lookup of %s failed: %s",userdn,ldap_err2string(rc));
 
75
    }
 
76
  }
62
77
  /* close the session */
63
78
  myldap_session_close(session);
64
 
  /* handle the results */
65
 
  switch(rc)
66
 
  {
67
 
    case LDAP_SUCCESS:             return NSLCD_PAM_SUCCESS;
68
 
    case LDAP_INVALID_CREDENTIALS: return NSLCD_PAM_AUTH_ERR;
69
 
    default:                       return NSLCD_PAM_AUTH_ERR;
70
 
  }
 
79
  /* return results */
 
80
  return rc;
71
81
}
72
82
 
73
 
/* ensure that both userdn and username are filled in from the entry */
74
 
static int validate_user(MYLDAP_SESSION *session,char *userdn,size_t userdnsz,
75
 
                         char *username,size_t usernamesz)
 
83
/* ensure that both userdn and username are filled in from the entry,
 
84
   returns an LDAP result code */
 
85
static MYLDAP_ENTRY *validate_user(MYLDAP_SESSION *session,
 
86
                         char *username,int *rcp)
76
87
{
 
88
  int rc;
77
89
  MYLDAP_ENTRY *entry=NULL;
78
 
  const char *value;
79
 
  const char **values;
80
90
  /* check username for validity */
81
91
  if (!isvalidname(username))
82
92
  {
83
 
    log_log(LOG_WARNING,"\"%s\": invalid user name",username);
84
 
    return -1;
85
 
  }
86
 
  /* look up user DN if not known */
87
 
  if (userdn[0]=='\0')
88
 
  {
89
 
    /* get the user entry based on the username */
90
 
    entry=uid2entry(session,username);
91
 
    if (entry==NULL)
92
 
    {
93
 
      log_log(LOG_WARNING,"\"%s\": user not found",username);
94
 
      return -1;
95
 
    }
96
 
    /* get the DN */
97
 
    myldap_cpy_dn(entry,userdn,userdnsz);
98
 
    if (strcasecmp(userdn,"unknown")==0)
99
 
    {
100
 
      log_log(LOG_WARNING,"\"%s\": user has no DN",username);
101
 
      return -1;
102
 
    }
103
 
    /* get the "real" username */
104
 
    value=myldap_get_rdn_value(entry,attmap_passwd_uid);
105
 
    if (value==NULL)
106
 
    {
107
 
      /* get the username from the uid attribute */
108
 
      values=myldap_get_values(entry,attmap_passwd_uid);
109
 
      if ((values==NULL)||(values[0]==NULL))
110
 
        log_log(LOG_WARNING,"\"%s\": DN %s is missing a %s attribute",
111
 
                            username,userdn,attmap_passwd_uid);
112
 
      value=values[0];
113
 
    }
114
 
    /* check the username */
115
 
    if ((value==NULL)||!isvalidname(value)||strlen(value)>=usernamesz)
116
 
    {
117
 
      log_log(LOG_WARNING,"\"%s\": DN %s has invalid username",username,userdn);
118
 
      return -1;
119
 
    }
120
 
    /* check if the username is different and update it if needed */
121
 
    if (strcmp(username,value)!=0)
122
 
    {
123
 
      log_log(LOG_INFO,"username changed from \"%s\" to \"%s\"",username,value);
124
 
      strcpy(username,value);
125
 
    }
126
 
  }
127
 
  /* all check passed */
128
 
  return 0;
 
93
    log_log(LOG_WARNING,"\"%s\": name denied by validnames option",username);
 
94
    *rcp=LDAP_NO_SUCH_OBJECT;
 
95
    return NULL;
 
96
  }
 
97
  /* get the user entry based on the username */
 
98
  entry=uid2entry(session,username,&rc);
 
99
  if (entry==NULL)
 
100
  {
 
101
    if (rc==LDAP_SUCCESS)
 
102
      rc=LDAP_NO_SUCH_OBJECT;
 
103
    log_log(LOG_WARNING,"\"%s\": user not found: %s",username,ldap_err2string(rc));
 
104
    *rcp=rc;
 
105
  }
 
106
  return entry;
 
107
}
 
108
 
 
109
/* update the username value from the entry if needed */
 
110
static void update_username(MYLDAP_ENTRY *entry,char *username,size_t username_len)
 
111
{
 
112
  const char **values;
 
113
  const char *value;
 
114
  /* get the "real" username */
 
115
  value=myldap_get_rdn_value(entry,attmap_passwd_uid);
 
116
  if (value==NULL)
 
117
  {
 
118
    /* get the username from the uid attribute */
 
119
    values=myldap_get_values(entry,attmap_passwd_uid);
 
120
    if ((values==NULL)||(values[0]==NULL))
 
121
      log_log(LOG_WARNING,"\"%s\": DN %s is missing a %s attribute",
 
122
                          username,myldap_get_dn(entry),attmap_passwd_uid);
 
123
    value=values[0];
 
124
  }
 
125
  /* check the username */
 
126
  if ((value==NULL)||!isvalidname(value)||strlen(value)>=username_len)
 
127
  {
 
128
    log_log(LOG_WARNING,"passwd entry %s name denied by validnames option: \"%s\"",
 
129
                        myldap_get_dn(entry),username);
 
130
    return;
 
131
  }
 
132
  /* check if the username is different and update it if needed */
 
133
  if (strcmp(username,value)!=0)
 
134
  {
 
135
    log_log(LOG_INFO,"username changed from \"%s\" to \"%s\"",username,value);
 
136
    strcpy(username,value);
 
137
  }
 
138
}
 
139
 
 
140
static int check_shadow(MYLDAP_SESSION *session,const char *username,
 
141
                        char *authzmsg,size_t authzmsgsz,
 
142
                        int check_maxdays,int check_mindays)
 
143
{
 
144
  MYLDAP_ENTRY *entry=NULL;
 
145
  long today,lastchangedate,mindays,maxdays,warndays,inactdays,expiredate;
 
146
  unsigned long flag;
 
147
  long daysleft,inactleft;
 
148
  /* get the shadow entry */
 
149
  entry=shadow_uid2entry(session,username,NULL);
 
150
  if (entry==NULL)
 
151
    return NSLCD_PAM_SUCCESS; /* no shadow entry found, nothing to check */
 
152
  /* get today's date */
 
153
  today=(long)(time(NULL)/(60*60*24));
 
154
  /* get shadown information */
 
155
  get_shadow_properties(entry,&lastchangedate,&mindays,&maxdays,&warndays,
 
156
                        &inactdays,&expiredate,&flag);
 
157
  /* check account expiry date */
 
158
  if ((expiredate!=-1)&&(today>=expiredate))
 
159
  {
 
160
    daysleft=today-expiredate;
 
161
    mysnprintf(authzmsg,authzmsgsz-1,"account expired %ld days ago",daysleft);
 
162
    log_log(LOG_WARNING,"%s: %s",myldap_get_dn(entry),authzmsg);
 
163
    return NSLCD_PAM_ACCT_EXPIRED;
 
164
  }
 
165
  /* password expiration isn't interesting at this point because the user
 
166
     may not have authenticated with a password and if he did that would be
 
167
     checked in the authc phase */
 
168
  if (check_maxdays)
 
169
  {
 
170
    /* check lastchanged */
 
171
    if (lastchangedate==0)
 
172
    {
 
173
      mysnprintf(authzmsg,authzmsgsz-1,"need a new password");
 
174
      log_log(LOG_WARNING,"%s: %s",myldap_get_dn(entry),authzmsg);
 
175
      return NSLCD_PAM_NEW_AUTHTOK_REQD;
 
176
    }
 
177
    else if (today<lastchangedate)
 
178
      log_log(LOG_WARNING,"%s: password changed in the future",myldap_get_dn(entry));
 
179
    else if (maxdays!=-1)
 
180
    {
 
181
      /* check maxdays */
 
182
      daysleft=lastchangedate+maxdays-today;
 
183
      if (daysleft==0)
 
184
        mysnprintf(authzmsg,authzmsgsz-1,"password will expire today");
 
185
      else if (daysleft<0)
 
186
        mysnprintf(authzmsg,authzmsgsz-1,"password expired %ld days ago",-daysleft);
 
187
      /* check inactdays */
 
188
      if ((daysleft<=0)&&(inactdays!=-1))
 
189
      {
 
190
        inactleft=lastchangedate+maxdays+inactdays-today;
 
191
        if (inactleft==0)
 
192
          mysnprintf(authzmsg+strlen(authzmsg),authzmsgsz-strlen(authzmsg)-1,
 
193
                     ", account will be locked today");
 
194
        else if (inactleft>0)
 
195
          mysnprintf(authzmsg+strlen(authzmsg),authzmsgsz-strlen(authzmsg)-1,
 
196
                     ", account will be locked in %ld days",inactleft);
 
197
        else
 
198
        {
 
199
          mysnprintf(authzmsg+strlen(authzmsg),authzmsgsz-strlen(authzmsg)-1,
 
200
                     ", account locked %ld days ago",-inactleft);
 
201
          log_log(LOG_WARNING,"%s: %s",myldap_get_dn(entry),authzmsg);
 
202
          return NSLCD_PAM_AUTHTOK_EXPIRED;
 
203
        }
 
204
      }
 
205
      if (daysleft<=0)
 
206
      {
 
207
        /* log previously built message */
 
208
        log_log(LOG_WARNING,"%s: %s",myldap_get_dn(entry),authzmsg);
 
209
        return NSLCD_PAM_NEW_AUTHTOK_REQD;
 
210
      }
 
211
      /* check warndays */
 
212
      if ((warndays>0)&&(daysleft<=warndays))
 
213
      {
 
214
        mysnprintf(authzmsg,authzmsgsz-1,"password will expire in %ld days",daysleft);
 
215
        log_log(LOG_WARNING,"%s: %s",myldap_get_dn(entry),authzmsg);
 
216
      }
 
217
    }
 
218
  }
 
219
  if (check_mindays)
 
220
  {
 
221
    daysleft=lastchangedate+mindays-today;
 
222
    if ((mindays!=-1)&&(daysleft>0))
 
223
    {
 
224
      mysnprintf(authzmsg,authzmsgsz-1,"password cannot be changed for another %ld days",daysleft);
 
225
      log_log(LOG_WARNING,"%s: %s",myldap_get_dn(entry),authzmsg);
 
226
      return NSLCD_PAM_AUTHTOK_ERR;
 
227
    }
 
228
  }
 
229
  return NSLCD_PAM_SUCCESS;
129
230
}
130
231
 
131
232
/* check authentication credentials of the user */
132
 
int nslcd_pam_authc(TFILE *fp,MYLDAP_SESSION *session)
 
233
int nslcd_pam_authc(TFILE *fp,MYLDAP_SESSION *session,uid_t calleruid)
133
234
{
134
235
  int32_t tmpint32;
135
236
  int rc;
136
237
  char username[256];
137
 
  char userdn[256];
138
238
  char servicename[64];
139
239
  char password[64];
 
240
  const char *userdn;
 
241
  MYLDAP_ENTRY *entry;
 
242
  int authzrc=NSLCD_PAM_SUCCESS;
 
243
  char authzmsg[1024];
 
244
  authzmsg[0]='\0';
140
245
  /* read request parameters */
141
246
  READ_STRING(fp,username);
142
 
  READ_STRING(fp,userdn);
 
247
  SKIP_STRING(fp); /* DN */
143
248
  READ_STRING(fp,servicename);
144
249
  READ_STRING(fp,password);
145
250
  /* log call */
146
 
  log_log(LOG_DEBUG,"nslcd_pam_authc(\"%s\",\"%s\",\"%s\",\"%s\")",
147
 
                    username,userdn,servicename,*password?"***":"");
 
251
  log_setrequest("authc=\"%s\"",username);
 
252
  log_log(LOG_DEBUG,"nslcd_pam_authc(\"%s\",\"%s\",\"%s\")",
 
253
                    username,servicename,*password?"***":"");
148
254
  /* write the response header */
149
255
  WRITE_INT32(fp,NSLCD_VERSION);
150
256
  WRITE_INT32(fp,NSLCD_ACTION_PAM_AUTHC);
152
258
     authenticate as administrator, otherwise validate request as usual */
153
259
  if ((*username=='\0')&&(nslcd_cfg->ldc_rootpwmoddn!=NULL))
154
260
  {
155
 
    if (strlen(nslcd_cfg->ldc_rootpwmoddn)>=sizeof(userdn))
156
 
    {
157
 
      log_log(LOG_ERR,"nslcd_pam_authc(): rootpwmoddn will not fit in userdn");
 
261
    userdn=nslcd_cfg->ldc_rootpwmoddn;
 
262
    /* if the caller is root we will allow the use of the rootpwmodpw option */
 
263
    if ((*password=='\0')&&(calleruid==0)&&(nslcd_cfg->ldc_rootpwmodpw!=NULL))
 
264
    {
 
265
      if (strlen(nslcd_cfg->ldc_rootpwmodpw)>=sizeof(password))
 
266
      {
 
267
        log_log(LOG_ERR,"nslcd_pam_authc(): rootpwmodpw will not fit in password");
 
268
        return -1;
 
269
      }
 
270
      strcpy(password,nslcd_cfg->ldc_rootpwmodpw);
 
271
    }
 
272
  }
 
273
  else
 
274
  {
 
275
    /* try normal authentication, lookup the user entry */
 
276
    entry=validate_user(session,username,&rc);
 
277
    if (entry==NULL)
 
278
    {
 
279
      /* for user not found we just say no result */
 
280
      if (rc==LDAP_NO_SUCH_OBJECT)
 
281
      {
 
282
        WRITE_INT32(fp,NSLCD_RESULT_END);
 
283
      }
158
284
      return -1;
159
285
    }
160
 
    strcpy(userdn,nslcd_cfg->ldc_rootpwmoddn);
161
 
  }
162
 
  else if (validate_user(session,userdn,sizeof(userdn),username,sizeof(username)))
163
 
  {
164
 
    WRITE_INT32(fp,NSLCD_RESULT_END);
165
 
    return -1;
 
286
    userdn=myldap_get_dn(entry);
 
287
    update_username(entry,username,sizeof(username));
166
288
  }
167
289
  /* try authentication */
168
290
  rc=try_bind(userdn,password);
169
 
  if (rc==NSLCD_PAM_SUCCESS)
 
291
  if (rc==LDAP_SUCCESS)
170
292
    log_log(LOG_DEBUG,"bind successful");
 
293
  /* map result code */
 
294
  switch (rc)
 
295
  {
 
296
    case LDAP_SUCCESS:             rc=NSLCD_PAM_SUCCESS;  break;
 
297
    case LDAP_INVALID_CREDENTIALS: rc=NSLCD_PAM_AUTH_ERR; break;
 
298
    default:                       rc=NSLCD_PAM_AUTH_ERR;
 
299
  }
 
300
  /* perform shadow attribute checks */
 
301
  if (*username!='\0')
 
302
    authzrc=check_shadow(session,username,authzmsg,sizeof(authzmsg),1,0);
171
303
  /* write response */
172
304
  WRITE_INT32(fp,NSLCD_RESULT_BEGIN);
173
305
  WRITE_STRING(fp,username);
174
306
  WRITE_STRING(fp,userdn);
175
 
  WRITE_INT32(fp,rc);  /* authc */
176
 
  WRITE_INT32(fp,rc);  /* authz */
177
 
  WRITE_STRING(fp,""); /* authzmsg */
 
307
  WRITE_INT32(fp,rc);
 
308
  WRITE_INT32(fp,authzrc);
 
309
  WRITE_STRING(fp,authzmsg);
178
310
  WRITE_INT32(fp,NSLCD_RESULT_END);
179
311
  return 0;
180
312
}
228
360
           element in the dict) */
229
361
}
230
362
 
231
 
static int try_autzsearch(MYLDAP_SESSION *session,DICT *dict,const char *searchfilter)
 
363
/* perform an authorisation search, returns an LDAP status code */
 
364
static int try_autzsearch(MYLDAP_SESSION *session,const char *dn,
 
365
                          const char *username,const char *servicename,
 
366
                          const char *ruser,const char *rhost,const char *tty)
232
367
{
 
368
  char hostname[HOST_NAME_MAX+1];
 
369
  const char *fqdn;
 
370
  DICT *dict;
233
371
  char filter_buffer[1024];
234
372
  MYLDAP_SEARCH *search;
235
373
  MYLDAP_ENTRY *entry;
236
374
  static const char *attrs[2];
237
375
  int rc;
 
376
  const char *res;
 
377
  /* check whether the search filter is configured at all */
 
378
  if (!nslcd_cfg->ldc_pam_authz_search)
 
379
    return LDAP_SUCCESS;
 
380
  /* build the dictionary with variables
 
381
     NOTE: any variables added here also need to be added to
 
382
           cfg.c:parse_pam_authz_search_statement() */
 
383
  dict=dict_new();
 
384
  autzsearch_var_add(dict,"username",username);
 
385
  autzsearch_var_add(dict,"service",servicename);
 
386
  autzsearch_var_add(dict,"ruser",ruser);
 
387
  autzsearch_var_add(dict,"rhost",rhost);
 
388
  autzsearch_var_add(dict,"tty",tty);
 
389
  if (gethostname(hostname,sizeof(hostname))==0)
 
390
    autzsearch_var_add(dict,"hostname",hostname);
 
391
  if ((fqdn=getfqdn())!=NULL)
 
392
    autzsearch_var_add(dict,"fqdn",fqdn);
 
393
  autzsearch_var_add(dict,"dn",dn);
 
394
  autzsearch_var_add(dict,"uid",username);
238
395
  /* build the search filter */
239
 
  if (expr_parse(searchfilter,filter_buffer,sizeof(filter_buffer),
240
 
                 autzsearch_var_get,(void *)dict)==NULL)
 
396
  res=expr_parse(nslcd_cfg->ldc_pam_authz_search,
 
397
                 filter_buffer,sizeof(filter_buffer),
 
398
                 autzsearch_var_get,(void *)dict);
 
399
  autzsearch_vars_free(dict);
 
400
  dict_free(dict);
 
401
  if (res==NULL)
241
402
  {
242
 
    log_log(LOG_ERR,"pam_authz_search \"%s\" is invalid",searchfilter);
243
 
    return -1;
 
403
    log_log(LOG_ERR,"pam_authz_search \"%s\" is invalid",nslcd_cfg->ldc_pam_authz_search);
 
404
    return LDAP_LOCAL_ERROR;
244
405
  }
245
406
  log_log(LOG_DEBUG,"trying pam_authz_search \"%s\"",filter_buffer);
246
407
  /* perform the search */
253
414
  {
254
415
    log_log(LOG_ERR,"pam_authz_search \"%s\" failed: %s",
255
416
            filter_buffer,ldap_err2string(rc));
256
 
    return -1;
 
417
    return rc;
257
418
  }
258
419
  /* try to get an entry */
259
 
  entry=myldap_get_entry(search,NULL);
 
420
  entry=myldap_get_entry(search,&rc);
260
421
  if (entry==NULL)
261
422
  {
262
423
    log_log(LOG_ERR,"pam_authz_search \"%s\" found no matches",filter_buffer);
263
 
    return -1;
 
424
    if (rc==LDAP_SUCCESS)
 
425
      rc=LDAP_NO_SUCH_OBJECT;
 
426
    return rc;
264
427
  }
265
428
  log_log(LOG_DEBUG,"pam_authz_search found \"%s\"",myldap_get_dn(entry));
266
429
  /* we've found an entry so it's OK */
267
 
  return 0;
 
430
  return LDAP_SUCCESS;
268
431
}
269
432
 
270
433
/* check authorisation of the user */
271
434
int nslcd_pam_authz(TFILE *fp,MYLDAP_SESSION *session)
272
435
{
273
436
  int32_t tmpint32;
 
437
  int rc;
274
438
  char username[256];
275
 
  char userdn[256];
276
439
  char servicename[64];
277
 
  char ruser[256];
278
 
  char rhost[256];
279
 
  char tty[256];
280
 
  char hostname[HOST_NAME_MAX+1];
281
 
  DICT *dict;
 
440
  char ruser[256],rhost[HOST_NAME_MAX+1],tty[64];
 
441
  MYLDAP_ENTRY *entry;
 
442
  char authzmsg[1024];
 
443
  authzmsg[0]='\0';
282
444
  /* read request parameters */
283
445
  READ_STRING(fp,username);
284
 
  READ_STRING(fp,userdn);
 
446
  SKIP_STRING(fp); /* DN */
285
447
  READ_STRING(fp,servicename);
286
448
  READ_STRING(fp,ruser);
287
449
  READ_STRING(fp,rhost);
288
450
  READ_STRING(fp,tty);
289
451
  /* log call */
290
 
  log_log(LOG_DEBUG,"nslcd_pam_authz(\"%s\",\"%s\",\"%s\",\"%s\",\"%s\",\"%s\")",
291
 
            username,userdn,servicename,ruser,rhost,tty);
 
452
  log_setrequest("authz=\"%s\"",username);
 
453
  log_log(LOG_DEBUG,"nslcd_pam_authz(\"%s\",\"%s\",\"%s\",\"%s\",\"%s\")",
 
454
            username,servicename,ruser,rhost,tty);
292
455
  /* write the response header */
293
456
  WRITE_INT32(fp,NSLCD_VERSION);
294
457
  WRITE_INT32(fp,NSLCD_ACTION_PAM_AUTHZ);
295
 
  /* validate request and fill in the blanks */
296
 
  if (validate_user(session,userdn,sizeof(userdn),username,sizeof(username)))
297
 
  {
298
 
    WRITE_INT32(fp,NSLCD_RESULT_END);
299
 
    return -1;
300
 
  }
301
 
  if (nslcd_cfg->ldc_pam_authz_search)
302
 
  {
303
 
    /* TODO: perform any authorisation checks */
304
 
    dict=dict_new();
305
 
    autzsearch_var_add(dict,"username",username);
306
 
    autzsearch_var_add(dict,"service",servicename);
307
 
    autzsearch_var_add(dict,"ruser",ruser);
308
 
    autzsearch_var_add(dict,"rhost",rhost);
309
 
    autzsearch_var_add(dict,"tty",tty);
310
 
    if (gethostname(hostname,sizeof(hostname))==0)
311
 
      autzsearch_var_add(dict,"hostname",hostname);
312
 
    /* TODO: fqdn */
313
 
    autzsearch_var_add(dict,"dn",userdn);
314
 
    autzsearch_var_add(dict,"uid",username);
315
 
    if (try_autzsearch(session,dict,nslcd_cfg->ldc_pam_authz_search))
 
458
  /* validate request */
 
459
  entry=validate_user(session,username,&rc);
 
460
  if (entry==NULL)
 
461
  {
 
462
    /* for user not found we just say no result */
 
463
    if (rc==LDAP_NO_SUCH_OBJECT)
316
464
    {
317
 
      WRITE_INT32(fp,NSLCD_RESULT_BEGIN);
318
 
      WRITE_STRING(fp,username);
319
 
      WRITE_STRING(fp,userdn);
320
 
      WRITE_INT32(fp,NSLCD_PAM_PERM_DENIED);  /* authz */
321
 
      WRITE_STRING(fp,"LDAP authorisation check failed"); /* authzmsg */
322
465
      WRITE_INT32(fp,NSLCD_RESULT_END);
323
466
    }
324
 
    autzsearch_vars_free(dict);
325
 
    dict_free(dict);
326
 
  }
 
467
    return -1;
 
468
  }
 
469
  /* check authorisation search */
 
470
  rc=try_autzsearch(session,myldap_get_dn(entry),username,servicename,ruser,rhost,tty);
 
471
  if (rc!=LDAP_SUCCESS)
 
472
  {
 
473
    WRITE_INT32(fp,NSLCD_RESULT_BEGIN);
 
474
    WRITE_STRING(fp,username);
 
475
    WRITE_STRING(fp,"");
 
476
    WRITE_INT32(fp,NSLCD_PAM_PERM_DENIED);
 
477
    WRITE_STRING(fp,"LDAP authorisation check failed");
 
478
    WRITE_INT32(fp,NSLCD_RESULT_END);
 
479
    return 0;
 
480
  }
 
481
  /* perform shadow attribute checks */
 
482
  rc=check_shadow(session,username,authzmsg,sizeof(authzmsg),0,0);
327
483
  /* write response */
328
484
  WRITE_INT32(fp,NSLCD_RESULT_BEGIN);
329
485
  WRITE_STRING(fp,username);
330
 
  WRITE_STRING(fp,userdn);
331
 
  WRITE_INT32(fp,NSLCD_PAM_SUCCESS);  /* authz */
332
 
  WRITE_STRING(fp,""); /* authzmsg */
 
486
  WRITE_STRING(fp,myldap_get_dn(entry));
 
487
  WRITE_INT32(fp,rc);
 
488
  WRITE_STRING(fp,authzmsg);
333
489
  WRITE_INT32(fp,NSLCD_RESULT_END);
334
490
  return 0;
335
491
}
338
494
{
339
495
  int32_t tmpint32;
340
496
  char username[256];
341
 
  char userdn[256];
342
497
  char servicename[64];
343
 
  char tty[64],rhost[64],ruser[256];
 
498
  char tty[64],rhost[HOST_NAME_MAX+1],ruser[256];
344
499
  int32_t sessionid;
345
500
  /* read request parameters */
346
501
  READ_STRING(fp,username);
347
 
  READ_STRING(fp,userdn);
 
502
  SKIP_STRING(fp); /* DN */
348
503
  READ_STRING(fp,servicename);
349
504
  READ_STRING(fp,tty);
350
505
  READ_STRING(fp,rhost);
351
506
  READ_STRING(fp,ruser);
352
507
  READ_INT32(fp,sessionid);
353
508
  /* log call */
354
 
  log_log(LOG_DEBUG,"nslcd_pam_sess_o(\"%s\",\"%s\",\"%s\",\"%s\",\"%s\",\"%s\")",
355
 
                    username,userdn,servicename,tty,rhost,ruser);
 
509
  log_setrequest("sess_o=\"%s\"",username);
 
510
  log_log(LOG_DEBUG,"nslcd_pam_sess_o(\"%s\",\"%s\",\"%s\",\"%s\",\"%s\")",
 
511
                    username,servicename,tty,rhost,ruser);
356
512
  /* write the response header */
357
513
  WRITE_INT32(fp,NSLCD_VERSION);
358
514
  WRITE_INT32(fp,NSLCD_ACTION_PAM_SESS_O);
367
523
{
368
524
  int32_t tmpint32;
369
525
  char username[256];
370
 
  char userdn[256];
371
526
  char servicename[64];
372
 
  char tty[64],rhost[64],ruser[256];
 
527
  char tty[64],rhost[HOST_NAME_MAX+1],ruser[256];
373
528
  int32_t sessionid;
374
529
  /* read request parameters */
375
530
  READ_STRING(fp,username);
376
 
  READ_STRING(fp,userdn);
 
531
  SKIP_STRING(fp); /* DN */
377
532
  READ_STRING(fp,servicename);
378
533
  READ_STRING(fp,tty);
379
534
  READ_STRING(fp,rhost);
380
535
  READ_STRING(fp,ruser);
381
536
  READ_INT32(fp,sessionid);
382
537
  /* log call */
383
 
  log_log(LOG_DEBUG,"nslcd_pam_sess_c(\"%s\",\"%s\",\"%s\",%d)",
384
 
                    username,userdn,servicename,(int)sessionid);
 
538
  log_setrequest("sess_c=\"%s\"",username);
 
539
  log_log(LOG_DEBUG,"nslcd_pam_sess_c(\"%s\",\"%s\",%d)",
 
540
                    username,servicename,(int)sessionid);
385
541
  /* write the response header */
386
542
  WRITE_INT32(fp,NSLCD_VERSION);
387
543
  WRITE_INT32(fp,NSLCD_ACTION_PAM_SESS_C);
397
553
                     const char *oldpassword,const char *newpassword)
398
554
{
399
555
  MYLDAP_SESSION *session;
400
 
  char *username;
 
556
  char buffer[256];
401
557
  int rc;
402
558
  /* set up a new connection */
403
559
  session=myldap_create_session();
406
562
  /* set up credentials for the session */
407
563
  myldap_set_credentials(session,binddn,oldpassword);
408
564
  /* perform search for own object (just to do any kind of search) */
409
 
  username=lookup_dn2uid(session,userdn,&rc);
410
 
  if (username!=NULL)
411
 
    free(username);
412
 
  /* perform actual password modification */
413
 
  if (rc==LDAP_SUCCESS)
 
565
  if ((lookup_dn2uid(session,userdn,&rc,buffer,sizeof(buffer))!=NULL)&&(rc==LDAP_SUCCESS))
414
566
  {
415
567
    /* if doing password modification as admin, don't pass old password along */
416
568
    if ((nslcd_cfg->ldc_rootpwmoddn!=NULL)&&(strcmp(binddn,nslcd_cfg->ldc_rootpwmoddn)==0))
417
569
      oldpassword=NULL;
418
570
    /* perform password modification */
419
571
    rc=myldap_passwd(session,userdn,oldpassword,newpassword);
 
572
    if (rc==LDAP_SUCCESS)
 
573
    {
 
574
      /* try to update the shadowLastChange attribute */
 
575
      (void)update_lastchange(session,userdn);
 
576
    }
420
577
  }
421
578
  /* close the session */
422
579
  myldap_session_close(session);
424
581
  return rc;
425
582
}
426
583
 
427
 
int nslcd_pam_pwmod(TFILE *fp,MYLDAP_SESSION *session)
 
584
int nslcd_pam_pwmod(TFILE *fp,MYLDAP_SESSION *session,uid_t calleruid)
428
585
{
429
586
  int32_t tmpint32;
 
587
  int rc;
430
588
  char username[256];
431
589
  char userdn[256];
 
590
  int asroot;
432
591
  char servicename[64];
433
592
  char oldpassword[64];
434
593
  char newpassword[64];
435
 
  char *binddn=userdn; /* the user performing the modification */
436
 
  int rc;
 
594
  const char *binddn=NULL; /* the user performing the modification */
 
595
  MYLDAP_ENTRY *entry;
 
596
  char authzmsg[1024];
 
597
  authzmsg[0]='\0';
437
598
  /* read request parameters */
438
599
  READ_STRING(fp,username);
439
 
  READ_STRING(fp,userdn);
 
600
  READ_STRING(fp,userdn); /* we can't ignore userdn for now here because we
 
601
                             need it to determine the modify-as-root case */
 
602
  asroot=(nslcd_cfg->ldc_rootpwmoddn!=NULL)&&(strcmp(userdn,nslcd_cfg->ldc_rootpwmoddn)==0);
440
603
  READ_STRING(fp,servicename);
441
604
  READ_STRING(fp,oldpassword);
442
605
  READ_STRING(fp,newpassword);
443
606
  /* log call */
444
 
  log_log(LOG_DEBUG,"nslcd_pam_pwmod(\"%s\",\"%s\",\"%s\",\"%s\",\"%s\")",
445
 
                    username,userdn,servicename,*oldpassword?"***":"",
 
607
  log_setrequest("pwmod=\"%s\"",username);
 
608
  log_log(LOG_DEBUG,"nslcd_pam_pwmod(\"%s\",%s,\"%s\",\"%s\",\"%s\")",
 
609
                    username,asroot?"asroot":"asuser",servicename,*oldpassword?"***":"",
446
610
                    *newpassword?"***":"");
447
611
  /* write the response header */
448
612
  WRITE_INT32(fp,NSLCD_VERSION);
449
613
  WRITE_INT32(fp,NSLCD_ACTION_PAM_PWMOD);
 
614
  /* validate request */
 
615
  entry=validate_user(session,username,&rc);
 
616
  if (entry==NULL)
 
617
  {
 
618
    /* for user not found we just say no result */
 
619
    if (rc==LDAP_NO_SUCH_OBJECT)
 
620
    {
 
621
      WRITE_INT32(fp,NSLCD_RESULT_END);
 
622
    }
 
623
    return -1;
 
624
  }
450
625
  /* check if the the user passed the rootpwmoddn */
451
 
  if ((nslcd_cfg->ldc_rootpwmoddn!=NULL)&&(strcmp(userdn,nslcd_cfg->ldc_rootpwmoddn)==0))
 
626
  if (asroot)
452
627
  {
453
628
    binddn=nslcd_cfg->ldc_rootpwmoddn;
454
 
    userdn[0]='\0'; /* cause validate_user() to get the user DN */
 
629
    /* check if rootpwmodpw should be used */
 
630
    if ((*oldpassword=='\0')&&(calleruid==0)&&(nslcd_cfg->ldc_rootpwmodpw!=NULL))
 
631
    {
 
632
      if (strlen(nslcd_cfg->ldc_rootpwmodpw)>=sizeof(oldpassword))
 
633
      {
 
634
        log_log(LOG_ERR,"nslcd_pam_pwmod(): rootpwmodpw will not fit in oldpassword");
 
635
        return -1;
 
636
      }
 
637
      strcpy(oldpassword,nslcd_cfg->ldc_rootpwmodpw);
 
638
    }
455
639
  }
456
 
  /* validate request and fill in the blanks */
457
 
  if (validate_user(session,userdn,sizeof(userdn),username,sizeof(username)))
 
640
  else
458
641
  {
459
 
    WRITE_INT32(fp,NSLCD_RESULT_END);
460
 
    return -1;
 
642
    binddn=myldap_get_dn(entry);
 
643
    /* check whether shadow properties allow password change */
 
644
    rc=check_shadow(session,username,authzmsg,sizeof(authzmsg),0,1);
 
645
    if (rc!=NSLCD_PAM_SUCCESS)
 
646
    {
 
647
      WRITE_INT32(fp,NSLCD_RESULT_BEGIN);
 
648
      WRITE_STRING(fp,username);
 
649
      WRITE_STRING(fp,"");
 
650
      WRITE_INT32(fp,rc);
 
651
      WRITE_STRING(fp,authzmsg);
 
652
      WRITE_INT32(fp,NSLCD_RESULT_END);
 
653
      return 0;
 
654
    }
461
655
  }
462
656
  /* perform password modification */
463
 
  rc=try_pwmod(binddn,userdn,oldpassword,newpassword);
 
657
  rc=try_pwmod(binddn,myldap_get_dn(entry),oldpassword,newpassword);
 
658
  if (rc!=LDAP_SUCCESS)
 
659
  {
 
660
    mysnprintf(authzmsg,sizeof(authzmsg)-1,"password change failed: %s",ldap_err2string(rc));
 
661
    WRITE_INT32(fp,NSLCD_RESULT_BEGIN);
 
662
    WRITE_STRING(fp,username);
 
663
    WRITE_STRING(fp,"");
 
664
    WRITE_INT32(fp,NSLCD_PAM_PERM_DENIED);
 
665
    WRITE_STRING(fp,authzmsg);
 
666
    WRITE_INT32(fp,NSLCD_RESULT_END);
 
667
  }
464
668
  /* write response */
465
669
  WRITE_INT32(fp,NSLCD_RESULT_BEGIN);
466
670
  WRITE_STRING(fp,username);
467
 
  WRITE_STRING(fp,userdn);
468
 
  if (rc==LDAP_SUCCESS)
469
 
  {
470
 
    WRITE_INT32(fp,NSLCD_PAM_SUCCESS);
471
 
    WRITE_STRING(fp,"");
472
 
  }
473
 
  else
474
 
  {
475
 
    WRITE_INT32(fp,NSLCD_PAM_PERM_DENIED);
476
 
    WRITE_STRING(fp,ldap_err2string(rc));
477
 
  }
 
671
  WRITE_STRING(fp,myldap_get_dn(entry));
 
672
  WRITE_INT32(fp,NSLCD_PAM_SUCCESS);
 
673
  WRITE_STRING(fp,"");
478
674
  WRITE_INT32(fp,NSLCD_RESULT_END);
479
675
  return 0;
480
676
}