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

« back to all changes in this revision

Viewing changes to nslcd/shadow.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:
1
1
/*
2
 
   shadow.c - service entry lookup routines
 
2
   shadow.c - shadow entry lookup routines
3
3
   Parts of this file were part of the nss_ldap library (as ldap-spwd.c)
4
4
   which has been forked into the nss-pam-ldapd library.
5
5
 
6
6
   Copyright (C) 1997-2005 Luke Howard
7
7
   Copyright (C) 2006 West Consulting
8
 
   Copyright (C) 2006, 2007, 2008, 2009, 2010 Arthur de Jong
 
8
   Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011 Arthur de Jong
9
9
 
10
10
   This library is free software; you can redistribute it and/or
11
11
   modify it under the terms of the GNU Lesser General Public
28
28
#include <stdio.h>
29
29
#include <stdlib.h>
30
30
#include <string.h>
 
31
#include <time.h>
31
32
 
32
33
#include "common.h"
33
34
#include "log.h"
54
55
 
55
56
/* the attributes to request with searches */
56
57
const char *attmap_shadow_uid              = "uid";
57
 
const char *attmap_shadow_userPassword     = "userPassword";
 
58
const char *attmap_shadow_userPassword     = "\"*\"";
58
59
const char *attmap_shadow_shadowLastChange = "\"${shadowLastChange:--1}\"";
59
60
const char *attmap_shadow_shadowMin        = "\"${shadowMin:--1}\"";
60
61
const char *attmap_shadow_shadowMax        = "\"${shadowMax:--1}\"";
111
112
 
112
113
static long to_date(const char *date,const char *attr)
113
114
{
114
 
  char buffer[8];
 
115
  char buffer[32];
115
116
  long value;
116
117
  char *tmp;
117
118
  size_t l;
125
126
       last 9 digits from the string and going from there */
126
127
    l=strlen(date)-9;
127
128
    if (l>(sizeof(buffer)-1))
128
 
      return 0; /* error */
 
129
      return -1; /* error */
129
130
    strncpy(buffer,date,l);
130
131
    buffer[l]='\0';
 
132
    errno=0;
131
133
    value=strtol(date,&tmp,0);
132
134
    if ((*date=='\0')||(*tmp!='\0'))
133
135
    {
134
136
      log_log(LOG_WARNING,"shadow entry contains non-numeric %s value",attr);
135
 
      return 0;
 
137
      return -1;
 
138
    }
 
139
    else if (errno!=0)
 
140
    {
 
141
      log_log(LOG_WARNING,"shadow entry contains too large %s value",attr);
 
142
      return -1;
136
143
    }
137
144
    return value/864-134774;
138
145
    /* note that AD does not have expiry dates but a lastchangeddate
139
146
       and some value that needs to be added */
140
147
  }
 
148
  errno=0;
141
149
  value=strtol(date,&tmp,0);
142
150
  if ((*date=='\0')||(*tmp!='\0'))
143
151
  {
144
152
    log_log(LOG_WARNING,"shadow entry contains non-numeric %s value",attr);
145
 
    return 0;
 
153
    return -1;
 
154
  }
 
155
  else if (errno!=0)
 
156
  {
 
157
    log_log(LOG_WARNING,"shadow entry contains too large %s value",attr);
 
158
    return -1;
146
159
  }
147
160
  return value;
148
161
}
151
164
#define UF_DONT_EXPIRE_PASSWD 0x10000
152
165
#endif
153
166
 
154
 
#define GET_OPTIONAL_LONG(var,att) \
 
167
#define GET_OPTIONAL_LONG(var,att,fallback) \
155
168
  tmpvalue=attmap_get_value(entry,attmap_shadow_##att,buffer,sizeof(buffer)); \
156
169
  if (tmpvalue==NULL) \
157
170
    tmpvalue=""; \
 
171
  errno=0; \
158
172
  var=strtol(tmpvalue,&tmp,0); \
159
173
  if ((*(tmpvalue)=='\0')||(*tmp!='\0')) \
160
174
  { \
161
175
    log_log(LOG_WARNING,"shadow entry %s contains non-numeric %s value", \
162
176
                        myldap_get_dn(entry),attmap_shadow_##att); \
163
 
    return 0; \
164
 
  }
165
 
 
166
 
#define GET_OPTIONAL_DATE(var,att) \
167
 
  tmpvalue=attmap_get_value(entry,attmap_shadow_##att,buffer,sizeof(buffer)); \
168
 
  if (tmpvalue==NULL) \
169
 
    tmpvalue=""; \
170
 
  var=to_date(tmpvalue,attmap_shadow_##att);
 
177
    var=fallback; \
 
178
  } \
 
179
  else if (errno!=0) \
 
180
  { \
 
181
    log_log(LOG_WARNING,"shadow entry %s contains too large %s value", \
 
182
                        myldap_get_dn(entry),attmap_shadow_##att); \
 
183
    var=fallback; \
 
184
  }
 
185
 
 
186
void get_shadow_properties(MYLDAP_ENTRY *entry,long *lastchangedate,
 
187
                           long *mindays,long *maxdays,long *warndays,
 
188
                           long *inactdays,long *expiredate,unsigned long *flag)
 
189
{
 
190
  char buffer[64];
 
191
  const char *tmpvalue;
 
192
  char *tmp;
 
193
  /* get lastchange date */
 
194
  tmpvalue=attmap_get_value(entry,attmap_shadow_shadowLastChange,buffer,sizeof(buffer));
 
195
  if (tmpvalue==NULL)
 
196
    tmpvalue="";
 
197
  *lastchangedate=to_date(tmpvalue,attmap_shadow_shadowLastChange);
 
198
  /* get other shadow properties */
 
199
  GET_OPTIONAL_LONG(*mindays,shadowMin,-1);
 
200
  GET_OPTIONAL_LONG(*maxdays,shadowMax,-1);
 
201
  GET_OPTIONAL_LONG(*warndays,shadowWarning,-1);
 
202
  GET_OPTIONAL_LONG(*inactdays,shadowInactive,-1);
 
203
  GET_OPTIONAL_LONG(*expiredate,shadowExpire,-1);
 
204
  GET_OPTIONAL_LONG(*flag,shadowFlag,0);
 
205
  /* if we're using AD handle the flag specially */
 
206
  if (strcasecmp(attmap_shadow_shadowLastChange,"pwdLastSet")==0)
 
207
  {
 
208
    if (*flag&UF_DONT_EXPIRE_PASSWD)
 
209
      *maxdays=-1;
 
210
    *flag=0;
 
211
  }
 
212
}
 
213
 
 
214
/* try to update the shadowLastChange attribute of the entry if possible */
 
215
int update_lastchange(MYLDAP_SESSION *session,const char *userdn)
 
216
{
 
217
  MYLDAP_SEARCH *search;
 
218
  MYLDAP_ENTRY *entry;
 
219
  static const char *attrs[3];
 
220
  const char *attr;
 
221
  int rc;
 
222
  const char **values;
 
223
  LDAPMod mod,*mods[2];
 
224
  char buffer[64],*strvals[2];
 
225
  /* find the name of the attribute to use */
 
226
  if ( (attmap_shadow_shadowLastChange==NULL) || (attmap_shadow_shadowLastChange[0]=='\0') )
 
227
    return LDAP_LOCAL_ERROR; /* attribute not mapped at all */
 
228
  else if (strcmp(attmap_shadow_shadowLastChange,"\"${shadowLastChange:--1}\"")==0)
 
229
    attr="shadowLastChange";
 
230
  else if (attmap_shadow_shadowLastChange[0]=='\"')
 
231
    return LDAP_LOCAL_ERROR; /* other expressions not supported for now */
 
232
  else
 
233
    attr=attmap_shadow_shadowLastChange;
 
234
  /* set up the attributes we need */
 
235
  attrs[0]=attmap_shadow_uid;
 
236
  attrs[1]=attr;
 
237
  attrs[2]=NULL;
 
238
  /* find the entry to see if the attribute is present */
 
239
  search=myldap_search(session,userdn,LDAP_SCOPE_BASE,shadow_filter,attrs,&rc);
 
240
  if (search==NULL)
 
241
    return rc;
 
242
  entry=myldap_get_entry(search,&rc);
 
243
  if (entry==NULL)
 
244
    return rc;
 
245
  values=myldap_get_values(entry,attr);
 
246
  if ((values==NULL)||(values[0]==NULL)||(values[0][0]=='\0'))
 
247
    return LDAP_NO_SUCH_ATTRIBUTE;
 
248
  /* build the value for the new attribute */
 
249
  if (strcasecmp(attr,"pwdLastSet")==0)
 
250
  {
 
251
    /* for AD we use another timestamp */
 
252
    if(mysnprintf(buffer,sizeof(buffer),"%ld000000000",((long int)time(NULL)/100L+(134774L*864L))))
 
253
      return LDAP_LOCAL_ERROR;
 
254
  }
 
255
  else
 
256
  {
 
257
    /* time in days since Jan 1, 1970 */
 
258
    if(mysnprintf(buffer,sizeof(buffer),"%ld",((long int)(time(NULL)/(long int)(60*60*24)))))
 
259
      return LDAP_LOCAL_ERROR;
 
260
  }
 
261
  /* update the shadowLastChange attribute */
 
262
  strvals[0]=buffer;
 
263
  strvals[1]=NULL;
 
264
  mod.mod_op=LDAP_MOD_REPLACE;
 
265
  mod.mod_type=(char *)attr;
 
266
  mod.mod_values=strvals;
 
267
  mods[0]=&mod;
 
268
  mods[1]=NULL;
 
269
  rc=myldap_modify(session,userdn,mods);
 
270
  if (rc!=LDAP_SUCCESS)
 
271
    log_log(LOG_WARNING,"modification of %s attribute of %s failed: %s",
 
272
                        attr,userdn,ldap_err2string(rc));
 
273
  else
 
274
    log_log(LOG_DEBUG,"modification of %s attribute of %s succeeded",
 
275
                     attr,userdn);
 
276
  return rc;
 
277
}
171
278
 
172
279
static int write_shadow(TFILE *fp,MYLDAP_ENTRY *entry,const char *requser)
173
280
{
174
281
  int32_t tmpint32;
175
 
  const char *tmpvalue;
176
 
  char *tmp;
177
282
  const char **usernames;
178
283
  const char *passwd;
179
284
  long lastchangedate;
184
289
  long expiredate;
185
290
  unsigned long flag;
186
291
  int i;
187
 
  char buffer[80];
 
292
  char passbuffer[64];
188
293
  /* get username */
189
294
  usernames=myldap_get_values(entry,attmap_shadow_uid);
190
295
  if ((usernames==NULL)||(usernames[0]==NULL))
194
299
    return 0;
195
300
  }
196
301
  /* get password */
197
 
  passwd=get_userpassword(entry,attmap_shadow_userPassword);
 
302
  passwd=get_userpassword(entry,attmap_shadow_userPassword,passbuffer,sizeof(passbuffer));
198
303
  if (passwd==NULL)
199
304
    passwd=default_shadow_userPassword;
200
 
  /* get lastchange date */
201
 
  GET_OPTIONAL_DATE(lastchangedate,shadowLastChange);
202
 
  /* get mindays */
203
 
  GET_OPTIONAL_LONG(mindays,shadowMin);
204
 
  /* get maxdays */
205
 
  GET_OPTIONAL_LONG(maxdays,shadowMax);
206
 
  /* get warndays */
207
 
  GET_OPTIONAL_LONG(warndays,shadowWarning);
208
 
  /* get inactdays */
209
 
  GET_OPTIONAL_LONG(inactdays,shadowInactive);
210
 
  /* get expire date */
211
 
  GET_OPTIONAL_LONG(expiredate,shadowExpire);
212
 
  /* get flag */
213
 
  GET_OPTIONAL_LONG(flag,shadowFlag);
214
 
  /* if we're using AD handle the flag specially */
215
 
  if (strcasecmp(attmap_shadow_shadowLastChange,"pwdLastSet")==0)
216
 
  {
217
 
    if (flag&UF_DONT_EXPIRE_PASSWD)
218
 
      maxdays=99999;
219
 
    flag=0;
220
 
  }
 
305
  /* get expiry properties */
 
306
  get_shadow_properties(entry,&lastchangedate,&mindays,&maxdays,&warndays,
 
307
                        &inactdays,&expiredate,&flag);
221
308
  /* write the entries */
222
309
  for (i=0;usernames[i]!=NULL;i++)
223
310
    if ((requser==NULL)||(strcmp(requser,usernames[i])==0))
236
323
  return 0;
237
324
}
238
325
 
 
326
MYLDAP_ENTRY *shadow_uid2entry(MYLDAP_SESSION *session,const char *username,int *rcp)
 
327
{
 
328
  MYLDAP_SEARCH *search=NULL;
 
329
  MYLDAP_ENTRY *entry=NULL;
 
330
  const char *base;
 
331
  char filter[1024];
 
332
  int i;
 
333
  /* if it isn't a valid username, just bail out now */
 
334
  if (!isvalidname(username))
 
335
  {
 
336
    if (rcp!=NULL)
 
337
      *rcp=LDAP_INVALID_SYNTAX;
 
338
    return NULL;
 
339
  }
 
340
  /* we have to look up the entry */
 
341
  mkfilter_shadow_byname(username,filter,sizeof(filter));
 
342
  for (i=0;(i<NSS_LDAP_CONFIG_MAX_BASES)&&((base=shadow_bases[i])!=NULL);i++)
 
343
  {
 
344
    search=myldap_search(session,base,shadow_scope,filter,shadow_attrs,rcp);
 
345
    if (search==NULL)
 
346
    {
 
347
      if ((rcp!=NULL)&&(*rcp==LDAP_SUCCESS))
 
348
        *rcp=LDAP_NO_SUCH_OBJECT;
 
349
      return NULL;
 
350
    }
 
351
    entry=myldap_get_entry(search,rcp);
 
352
    if (entry!=NULL)
 
353
      return entry;
 
354
  }
 
355
  if ((rcp!=NULL)&&(*rcp==LDAP_SUCCESS))
 
356
    *rcp=LDAP_NO_SUCH_OBJECT;
 
357
  return NULL;
 
358
}
 
359
 
239
360
NSLCD_HANDLE(
240
361
  shadow,byname,
241
362
  char name[256];
242
363
  char filter[1024];
243
 
  READ_STRING(fp,name);,
244
 
  log_log(LOG_DEBUG,"nslcd_shadow_byname(%s)",name);,
 
364
  READ_STRING(fp,name);
 
365
  log_setrequest("shadow=\"%s\"",name);,
245
366
  NSLCD_ACTION_SHADOW_BYNAME,
246
367
  mkfilter_shadow_byname(name,filter,sizeof(filter)),
247
368
  write_shadow(fp,entry,name)
250
371
NSLCD_HANDLE(
251
372
  shadow,all,
252
373
  const char *filter;
253
 
  /* no parameters to read */,
254
 
  log_log(LOG_DEBUG,"nslcd_shadow_all()");,
 
374
  log_setrequest("shadow(all)");,
255
375
  NSLCD_ACTION_SHADOW_ALL,
256
376
  (filter=shadow_filter,0),
257
377
  write_shadow(fp,entry,NULL)