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
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
57
59
/* the attributes used in searches */
58
60
const char *attmap_passwd_uid = "uid";
59
const char *attmap_passwd_userPassword = "userPassword";
61
const char *attmap_passwd_userPassword = "\"*\"";
60
62
const char *attmap_passwd_uidNumber = "uidNumber";
61
63
const char *attmap_passwd_gidNumber = "gidNumber";
62
64
const char *attmap_passwd_gecos = "\"${gecos:-$cn}\"";
63
65
const char *attmap_passwd_homeDirectory = "homeDirectory";
64
66
const char *attmap_passwd_loginShell = "loginShell";
68
/* special properties for objectSid-based searches
69
(these are already LDAP-escaped strings) */
70
static char *uidSid=NULL;
71
static char *gidSid=NULL;
66
73
/* default values for attributes */
67
74
static const char *default_passwd_userPassword = "*"; /* unmatchable */
97
104
static int mkfilter_passwd_byuid(uid_t uid,
98
105
char *buffer,size_t buflen)
100
return mysnprintf(buffer,buflen,
103
attmap_passwd_uidNumber,(int)uid);
109
return mysnprintf(buffer,buflen,
110
"(&%s(%s=%s\\%02x\\%02x\\%02x\\%02x))",
112
attmap_passwd_uidNumber,uidSid,
113
(int)(uid&0xff),(int)((uid>>8)&0xff),
114
(int)((uid>>16)&0xff),(int)((uid>>24)&0xff));
118
return mysnprintf(buffer,buflen,
121
attmap_passwd_uidNumber,(int)uid);
106
125
void passwd_init(void)
114
133
/* set up scope */
115
134
if (passwd_scope==LDAP_SCOPE_DEFAULT)
116
135
passwd_scope=nslcd_cfg->ldc_scope;
136
/* special case when uidNumber or gidNumber reference objectSid */
137
if (strncasecmp(attmap_passwd_uidNumber,"objectSid:",10)==0)
139
uidSid=sid2search(attmap_passwd_uidNumber+10);
140
attmap_passwd_uidNumber=strndup(attmap_passwd_uidNumber,9);
142
if (strncasecmp(attmap_passwd_gidNumber,"objectSid:",10)==0)
144
gidSid=sid2search(attmap_passwd_gidNumber+10);
145
attmap_passwd_gidNumber=strndup(attmap_passwd_gidNumber,9);
117
147
/* set up attribute list */
119
149
attmap_add_attributes(set,"objectClass"); /* for testing shadowAccount */
139
169
#define DN2UID_CACHE_TIMEOUT (15*60)
171
/* checks whether the entry has a valid uidNumber attribute
173
static int entry_has_valid_uid(MYLDAP_ENTRY *entry)
179
/* if min_uid is not set any entry should do */
180
if (nslcd_cfg->ldc_nss_min_uid==0)
182
/* get all uidNumber attributes */
183
values=myldap_get_values_len(entry,attmap_passwd_uidNumber);
184
if ((values==NULL)||(values[0]==NULL))
186
log_log(LOG_WARNING,"passwd entry %s does not contain %s value",
187
myldap_get_dn(entry),attmap_passwd_uidNumber);
190
/* check if there is a uidNumber attributes >= min_uid */
191
for (i=0;values[i]!=NULL;i++)
194
uid=(uid_t)binsid2id(values[i]);
198
uid=strtouid(values[i],&tmp,0);
199
if ((*(values[i])=='\0')||(*tmp!='\0'))
201
log_log(LOG_WARNING,"passwd entry %s contains non-numeric %s value",
202
myldap_get_dn(entry),attmap_passwd_uidNumber);
207
log_log(LOG_WARNING,"passwd entry %s contains too large %s value",
208
myldap_get_dn(entry),attmap_passwd_uidNumber);
212
if (uid>=nslcd_cfg->ldc_nss_min_uid)
141
219
/* Perform an LDAP lookup to translate the DN into a uid.
142
220
This function either returns NULL or a strdup()ed string. */
143
char *lookup_dn2uid(MYLDAP_SESSION *session,const char *dn,int *rcp)
221
char *lookup_dn2uid(MYLDAP_SESSION *session,const char *dn,int *rcp,char *buf,size_t buflen)
145
223
MYLDAP_SEARCH *search;
146
224
MYLDAP_ENTRY *entry;
147
static const char *attrs[2];
225
static const char *attrs[3];
148
226
int rc=LDAP_SUCCESS;
149
227
const char **values;
153
231
/* we have to look up the entry */
154
232
attrs[0]=attmap_passwd_uid;
233
attrs[1]=attmap_passwd_uidNumber;
156
235
search=myldap_search(session,dn,LDAP_SCOPE_BASE,passwd_filter,attrs,rcp);
157
236
if (search==NULL)
166
245
log_log(LOG_WARNING,"lookup of user %s failed: %s",dn,ldap_err2string(*rcp));
169
/* get uid (just use first one) */
170
values=myldap_get_values(entry,attmap_passwd_uid);
171
/* check the result for presence and validity */
172
if ((values!=NULL)&&(values[0]!=NULL)&&isvalidname(values[0]))
173
uid=strdup(values[0]);
248
/* check the uidNumber attribute if min_uid is set */
249
if (entry_has_valid_uid(entry))
251
/* get uid (just use first one) */
252
values=myldap_get_values(entry,attmap_passwd_uid);
253
/* check the result for presence and validity */
254
if ((values!=NULL)&&(values[0]!=NULL)&&isvalidname(values[0])&&(strlen(values[0])<buflen))
256
strcpy(buf,values[0]);
260
/* clean up and return */
176
261
myldap_search_close(search);
217
302
pthread_mutex_unlock(&dn2uid_cache_mutex);
218
303
/* look up the uid using an LDAP query */
219
uid=lookup_dn2uid(session,dn,NULL);
304
uid=lookup_dn2uid(session,dn,NULL,buf,buflen);
220
305
/* store the result in the cache */
221
306
pthread_mutex_lock(&dn2uid_cache_mutex);
307
/* try to get the entry from the cache here again because it could have
308
changed in the meantime */
309
cacheentry=dict_get(dn2uid_cache,dn);
222
310
if (cacheentry==NULL)
224
312
/* allocate a new entry in the cache */
225
313
cacheentry=(struct dn2uid_cache_entry *)malloc(sizeof(struct dn2uid_cache_entry));
226
314
if (cacheentry!=NULL)
316
cacheentry->uid=NULL;
227
317
dict_put(dn2uid_cache,dn,cacheentry);
229
else if (cacheentry->uid!=NULL)
230
free(cacheentry->uid);
231
320
/* update the cache entry */
232
321
if (cacheentry!=NULL)
234
323
cacheentry->timestamp=time(NULL);
324
/* copy the uid if needed */
325
if (cacheentry->uid==NULL)
326
cacheentry->uid=uid!=NULL?strdup(uid):NULL;
327
else if (strcmp(cacheentry->uid,uid)!=0)
329
free(cacheentry->uid);
330
cacheentry->uid=uid!=NULL?strdup(uid):NULL;
237
333
pthread_mutex_unlock(&dn2uid_cache_mutex);
238
334
/* copy the result into the buffer */
239
if ((uid!=NULL)&&(strlen(uid)<buflen))
246
MYLDAP_ENTRY *uid2entry(MYLDAP_SESSION *session,const char *uid)
338
MYLDAP_ENTRY *uid2entry(MYLDAP_SESSION *session,const char *uid,int *rcp)
248
340
MYLDAP_SEARCH *search=NULL;
249
341
MYLDAP_ENTRY *entry=NULL;
250
342
const char *base;
252
static const char *attrs[2];
344
static const char *attrs[3];
253
345
char filter[1024];
254
346
/* if it isn't a valid username, just bail out now */
255
347
if (!isvalidname(uid))
350
*rcp=LDAP_INVALID_SYNTAX;
257
353
/* set up attributes (we don't need much) */
258
354
attrs[0]=attmap_passwd_uid;
355
attrs[1]=attmap_passwd_uidNumber;
260
357
/* we have to look up the entry */
261
358
mkfilter_passwd_byname(uid,filter,sizeof(filter));
262
359
for (i=0;(i<NSS_LDAP_CONFIG_MAX_BASES)&&((base=passwd_bases[i])!=NULL);i++)
264
search=myldap_search(session,base,passwd_scope,filter,attrs,NULL);
361
search=myldap_search(session,base,passwd_scope,filter,attrs,rcp);
265
362
if (search==NULL)
364
if ((rcp!=NULL)&&(*rcp==LDAP_SUCCESS))
365
*rcp=LDAP_NO_SUCH_OBJECT;
267
entry=myldap_get_entry(search,NULL);
368
entry=myldap_get_entry(search,rcp);
369
if ((entry!=NULL)&&(entry_has_valid_uid(entry)))
372
if ((rcp!=NULL)&&(*rcp==LDAP_SUCCESS))
373
*rcp=LDAP_NO_SUCH_OBJECT;
276
379
MYLDAP_ENTRY *entry;
277
380
/* look up the entry */
278
entry=uid2entry(session,uid);
381
entry=uid2entry(session,uid,NULL);
282
385
return myldap_cpy_dn(entry,buf,buflen);
388
/* the cached value of whether shadow lookups use LDAP in nsswitch.conf */
389
#define NSSWITCH_FILE "/etc/nsswitch.conf"
390
#define CACHED_UNKNOWN 22
391
static int cached_shadow_uses_ldap=CACHED_UNKNOWN;
392
static time_t cached_shadow_lastcheck=0;
393
#define CACHED_SHADOW_TIMEOUT (60)
394
static time_t nsswitch_mtime=0;
396
/* check whether /etc/nsswitch.conf should be related to update
397
cached_shadow_uses_ldap */
398
static inline void check_nsswitch_reload(void)
402
if ((cached_shadow_uses_ldap!=CACHED_UNKNOWN)&&
403
((t=time(NULL)) > (cached_shadow_lastcheck+CACHED_SHADOW_TIMEOUT)))
405
cached_shadow_lastcheck=t;
406
if (stat(NSSWITCH_FILE,&buf))
408
log_log(LOG_ERR,"stat(%s) failed: %s",NSSWITCH_FILE,strerror(errno));
409
/* trigger a recheck anyway */
410
cached_shadow_uses_ldap=CACHED_UNKNOWN;
413
/* trigger a recheck if file changed */
414
if (buf.st_mtime!=nsswitch_mtime)
416
nsswitch_mtime=buf.st_mtime;
417
cached_shadow_uses_ldap=CACHED_UNKNOWN;
422
/* check whether shadow lookups are configured to use ldap */
423
static inline int shadow_uses_ldap(void)
425
if (cached_shadow_uses_ldap==CACHED_UNKNOWN)
426
cached_shadow_uses_ldap=nsswitch_db_uses_ldap(NSSWITCH_FILE,"shadow");
427
return cached_shadow_uses_ldap;
285
430
/* the maximum number of uidNumber attributes per entry */
286
431
#define MAXUIDS_PER_ENTRY 5
309
455
myldap_get_dn(entry),attmap_passwd_uid);
312
/* get the password for this entry */
313
if (myldap_has_objectclass(entry,"shadowAccount"))
458
/* if we are using shadow maps and this entry looks like it would return
459
shadow information, make the passwd entry indicate it */
460
if (myldap_has_objectclass(entry,"shadowAccount")&&shadow_uses_ldap())
315
/* if the entry has a shadowAccount entry, point to that instead */
320
passwd=get_userpassword(entry,attmap_passwd_userPassword);
466
passwd=get_userpassword(entry,attmap_passwd_userPassword,passbuffer,sizeof(passbuffer));
321
467
if ((passwd==NULL)||(calleruid!=0))
322
468
passwd=default_passwd_userPassword;
339
485
for (numuids=0;(numuids<MAXUIDS_PER_ENTRY)&&(tmpvalues[numuids]!=NULL);numuids++)
341
uids[numuids]=(uid_t)strtol(tmpvalues[numuids],&tmp,0);
342
if ((*(tmpvalues[numuids])=='\0')||(*tmp!='\0'))
488
uids[numuids]=(uid_t)binsid2id(tmpvalues[numuids]);
344
log_log(LOG_WARNING,"passwd entry %s contains non-numeric %s value",
345
myldap_get_dn(entry),attmap_passwd_uidNumber);
492
uids[numuids]=strtouid(tmpvalues[numuids],&tmp,0);
493
if ((*(tmpvalues[numuids])=='\0')||(*tmp!='\0'))
495
log_log(LOG_WARNING,"passwd entry %s contains non-numeric %s value",
496
myldap_get_dn(entry),attmap_passwd_uidNumber);
501
log_log(LOG_WARNING,"passwd entry %s contains too large %s value",
502
myldap_get_dn(entry),attmap_passwd_uidNumber);
350
508
/* get the gid for this entry */
351
attmap_get_value(entry,attmap_passwd_gidNumber,gidbuf,sizeof(gidbuf));
354
log_log(LOG_WARNING,"passwd entry %s does not contain %s value",
355
myldap_get_dn(entry),attmap_passwd_gidNumber);
511
tmpvalues=myldap_get_values_len(entry,attmap_passwd_gidNumber);
512
if ((tmpvalues==NULL)||(tmpvalues[0]==NULL))
514
log_log(LOG_WARNING,"passwd entry %s does not contain %s value",
515
myldap_get_dn(entry),attmap_passwd_gidNumber);
518
gid=(gid_t)binsid2id(tmpvalues[0]);
358
gid=(gid_t)strtol(gidbuf,&tmp,0);
359
if ((gidbuf[0]=='\0')||(*tmp!='\0'))
361
log_log(LOG_WARNING,"passwd entry %s contains non-numeric %s value",
362
myldap_get_dn(entry),attmap_passwd_gidNumber);
522
attmap_get_value(entry,attmap_passwd_gidNumber,gidbuf,sizeof(gidbuf));
525
log_log(LOG_WARNING,"passwd entry %s does not contain %s value",
526
myldap_get_dn(entry),attmap_passwd_gidNumber);
530
gid=strtogid(gidbuf,&tmp,0);
531
if ((gidbuf[0]=='\0')||(*tmp!='\0'))
533
log_log(LOG_WARNING,"passwd entry %s contains non-numeric %s value",
534
myldap_get_dn(entry),attmap_passwd_gidNumber);
539
log_log(LOG_WARNING,"passwd entry %s contains too large %s value",
540
myldap_get_dn(entry),attmap_passwd_gidNumber);
365
544
/* get the gecos for this entry */
366
545
attmap_get_value(entry,attmap_passwd_gecos,gecos,sizeof(gecos));
378
557
if (!isvalidname(usernames[i]))
380
log_log(LOG_WARNING,"passwd entry %s contains invalid user name: \"%s\"",
559
log_log(LOG_WARNING,"passwd entry %s denied by validnames option: \"%s\"",
381
560
myldap_get_dn(entry),usernames[i]);
385
564
for (j=0;j<numuids;j++)
387
WRITE_INT32(fp,NSLCD_RESULT_BEGIN);
388
WRITE_STRING(fp,usernames[i]);
389
WRITE_STRING(fp,passwd);
390
WRITE_TYPE(fp,uids[j],uid_t);
391
WRITE_TYPE(fp,gid,gid_t);
392
WRITE_STRING(fp,gecos);
393
WRITE_STRING(fp,homedir);
394
WRITE_STRING(fp,shell);
566
if (uids[j]>=nslcd_cfg->ldc_nss_min_uid)
568
WRITE_INT32(fp,NSLCD_RESULT_BEGIN);
569
WRITE_STRING(fp,usernames[i]);
570
WRITE_STRING(fp,passwd);
571
WRITE_TYPE(fp,uids[j],uid_t);
572
WRITE_TYPE(fp,gid,gid_t);
573
WRITE_STRING(fp,gecos);
574
WRITE_STRING(fp,homedir);
575
WRITE_STRING(fp,shell);
404
586
char filter[1024];
405
587
READ_STRING(fp,name);
588
log_setrequest("passwd=\"%s\"",name);
406
589
if (!isvalidname(name)) {
407
log_log(LOG_WARNING,"nslcd_passwd_byname(%s): invalid user name",name);
590
log_log(LOG_WARNING,"\"%s\": name denied by validnames option",name);
410
log_log(LOG_DEBUG,"nslcd_passwd_byname(%s)",name);,
593
check_nsswitch_reload();,
411
594
NSLCD_ACTION_PASSWD_BYNAME,
412
595
mkfilter_passwd_byname(name,filter,sizeof(filter)),
413
596
write_passwd(fp,entry,name,NULL,calleruid)
419
602
char filter[1024];
420
READ_TYPE(fp,uid,uid_t);,
421
log_log(LOG_DEBUG,"nslcd_passwd_byuid(%d)",(int)uid);,
603
READ_TYPE(fp,uid,uid_t);
604
log_setrequest("passwd=%d",(int)uid);
605
if (uid<nslcd_cfg->ldc_nss_min_uid)
607
/* return an empty result */
608
WRITE_INT32(fp,NSLCD_VERSION);
609
WRITE_INT32(fp,NSLCD_ACTION_PASSWD_BYUID);
610
WRITE_INT32(fp,NSLCD_RESULT_END);
612
check_nsswitch_reload();,
422
613
NSLCD_ACTION_PASSWD_BYUID,
423
614
mkfilter_passwd_byuid(uid,filter,sizeof(filter)),
424
615
write_passwd(fp,entry,NULL,&uid,calleruid)
427
618
NSLCD_HANDLE_UID(
429
620
const char *filter;
430
/* no parameters to read */,
431
log_log(LOG_DEBUG,"nslcd_passwd_all()");,
621
log_setrequest("passwd(all)");
622
check_nsswitch_reload();,
432
623
NSLCD_ACTION_PASSWD_ALL,
433
624
(filter=passwd_filter,0),
434
625
write_passwd(fp,entry,NULL,NULL,calleruid)