1 /*
2    passwd.c - password entry lookup routines
3    Parts of this file were part of the nss_ldap library (as ldap-pwd.c)
4    which has been forked into the nss-pam-ldapd library.
5 
6    Copyright (C) 1997-2005 Luke Howard
7    Copyright (C) 2006 West Consulting
8    Copyright (C) 2006-2017 Arthur de Jong
9 
10    This library is free software; you can redistribute it and/or
11    modify it under the terms of the GNU Lesser General Public
12    License as published by the Free Software Foundation; either
13    version 2.1 of the License, or (at your option) any later version.
14 
15    This library is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18    Lesser General Public License for more details.
19 
20    You should have received a copy of the GNU Lesser General Public
21    License along with this library; if not, write to the Free Software
22    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
23    02110-1301 USA
24 */
25 
26 #include "config.h"
27 
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <sys/types.h>
31 #include <unistd.h>
32 #include <string.h>
33 #include <pthread.h>
34 
35 #include "common.h"
36 #include "log.h"
37 #include "myldap.h"
38 #include "cfg.h"
39 #include "attmap.h"
40 #include "common/dict.h"
41 #include "compat/strndup.h"
42 
43 /* ( nisSchema.2.0 NAME 'posixAccount' SUP top AUXILIARY
44  *   DESC 'Abstraction of an account with POSIX attributes'
45  *   MUST ( cn $ uid $ uidNumber $ gidNumber $ homeDirectory )
46  *   MAY ( userPassword $ loginShell $ gecos $ description ) )
47  */
48 
49 /* the search base for searches */
50 const char *passwd_bases[NSS_LDAP_CONFIG_MAX_BASES] = { NULL };
51 
52 /* the search scope for searches */
53 int passwd_scope = LDAP_SCOPE_DEFAULT;
54 
55 /* the basic search filter for searches */
56 const char *passwd_filter = "(objectClass=posixAccount)";
57 
58 /* the attributes used in searches */
59 const char *attmap_passwd_uid           = "uid";
60 const char *attmap_passwd_userPassword  = "\"*\"";
61 const char *attmap_passwd_uidNumber     = "uidNumber";
62 const char *attmap_passwd_gidNumber     = "gidNumber";
63 const char *attmap_passwd_gecos         = "\"${gecos:-$cn}\"";
64 const char *attmap_passwd_homeDirectory = "homeDirectory";
65 const char *attmap_passwd_loginShell    = "loginShell";
66 
67 /* special properties for objectSid-based searches
68    (these are already LDAP-escaped strings) */
69 static char *uidSid = NULL;
70 static char *gidSid = NULL;
71 
72 /* default values for attributes */
73 static const char *default_passwd_userPassword = "*"; /* unmatchable */
74 
75 /* Note that the resulting password value should be one of:
76    <empty> - no password set, allow login without password
77    *       - often used to prevent logins
78    x       - "valid" encrypted password that does not match any valid password
79              often used to indicate that the password is defined elsewhere
80    other   - encrypted password, usually in crypt(3) format */
81 
82 /* the attribute list to request with searches */
83 static const char **passwd_attrs = NULL;
84 
85 /* create a search filter for searching a passwd entry
86    by name, return -1 on errors */
mkfilter_passwd_byname(const char * name,char * buffer,size_t buflen)87 static int mkfilter_passwd_byname(const char *name,
88                                   char *buffer, size_t buflen)
89 {
90   char safename[BUFLEN_SAFENAME];
91   /* escape attribute */
92   if (myldap_escape(name, safename, sizeof(safename)))
93   {
94     log_log(LOG_ERR, "mkfilter_passwd_byname(): safename buffer too small");
95     return -1;
96   }
97   /* build filter */
98   return mysnprintf(buffer, buflen, "(&%s(%s=%s))",
99                     passwd_filter, attmap_passwd_uid, safename);
100 }
101 
102 /* create a search filter for searching a passwd entry
103    by uid, return -1 on errors */
mkfilter_passwd_byuid(uid_t uid,char * buffer,size_t buflen)104 static int mkfilter_passwd_byuid(uid_t uid, char *buffer, size_t buflen)
105 {
106   uid -= nslcd_cfg->nss_uid_offset;
107   if (uidSid != NULL)
108   {
109     return mysnprintf(buffer, buflen, "(&%s(%s=%s\\%02x\\%02x\\%02x\\%02x))",
110                       passwd_filter, attmap_passwd_uidNumber, uidSid,
111                       (int)(uid & 0xff), (int)((uid >> 8) & 0xff),
112                       (int)((uid >> 16) & 0xff), (int)((uid >> 24) & 0xff));
113   }
114   else
115   {
116     return mysnprintf(buffer, buflen, "(&%s(%s=%lu))",
117                       passwd_filter, attmap_passwd_uidNumber, (unsigned long int)uid);
118   }
119 }
120 
passwd_init(void)121 void passwd_init(void)
122 {
123   int i;
124   SET *set;
125   /* set up search bases */
126   if (passwd_bases[0] == NULL)
127     for (i = 0; i < NSS_LDAP_CONFIG_MAX_BASES; i++)
128       passwd_bases[i] = nslcd_cfg->bases[i];
129   /* set up scope */
130   if (passwd_scope == LDAP_SCOPE_DEFAULT)
131     passwd_scope = nslcd_cfg->scope;
132   /* special case when uidNumber or gidNumber reference objectSid */
133   if (strncasecmp(attmap_passwd_uidNumber, "objectSid:", 10) == 0)
134   {
135     uidSid = sid2search(attmap_passwd_uidNumber + 10);
136     attmap_passwd_uidNumber = strndup(attmap_passwd_uidNumber, 9);
137   }
138   if (strncasecmp(attmap_passwd_gidNumber, "objectSid:", 10) == 0)
139   {
140     gidSid = sid2search(attmap_passwd_gidNumber + 10);
141     attmap_passwd_gidNumber = strndup(attmap_passwd_gidNumber, 9);
142   }
143   /* set up attribute list */
144   set = set_new();
145   attmap_add_attributes(set, "objectClass"); /* for testing shadowAccount */
146   attmap_add_attributes(set, attmap_passwd_uid);
147   attmap_add_attributes(set, attmap_passwd_userPassword);
148   attmap_add_attributes(set, attmap_passwd_uidNumber);
149   attmap_add_attributes(set, attmap_passwd_gidNumber);
150   attmap_add_attributes(set, attmap_passwd_gecos);
151   attmap_add_attributes(set, attmap_passwd_homeDirectory);
152   attmap_add_attributes(set, attmap_passwd_loginShell);
153   passwd_attrs = set_tolist(set);
154   if (passwd_attrs == NULL)
155   {
156     log_log(LOG_CRIT, "malloc() failed to allocate memory");
157     exit(EXIT_FAILURE);
158   }
159   set_free(set);
160 }
161 
162 /* the cache that is used in dn2uid() */
163 static pthread_mutex_t dn2uid_cache_mutex = PTHREAD_MUTEX_INITIALIZER;
164 static DICT *dn2uid_cache = NULL;
165 struct dn2uid_cache_entry {
166   time_t timestamp;
167   char *uid;
168 };
169 
170 /* checks whether the entry has a valid uidNumber attribute
171    (>= nss_min_uid) */
entry_has_valid_uid(MYLDAP_ENTRY * entry)172 static int entry_has_valid_uid(MYLDAP_ENTRY *entry)
173 {
174   int i;
175   const char **values;
176   char *tmp;
177   uid_t uid;
178   /* if min_uid is not set any entry should do */
179   if (nslcd_cfg->nss_min_uid == 0)
180     return 1;
181   /* get all uidNumber attributes */
182   values = myldap_get_values_len(entry, attmap_passwd_uidNumber);
183   if ((values == NULL) || (values[0] == NULL))
184   {
185     log_log(LOG_WARNING, "%s: %s: missing",
186             myldap_get_dn(entry), attmap_passwd_uidNumber);
187     return 0;
188   }
189   /* check if there is a uidNumber attributes >= min_uid */
190   for (i = 0; values[i] != NULL; i++)
191   {
192     if (uidSid != NULL)
193       uid = (uid_t)binsid2id(values[i]);
194     else
195     {
196       errno = 0;
197       uid = strtouid(values[i], &tmp, 10);
198       if ((*(values[i]) == '\0') || (*tmp != '\0'))
199       {
200         log_log(LOG_WARNING, "%s: %s: non-numeric",
201                 myldap_get_dn(entry), attmap_passwd_uidNumber);
202         continue;
203       }
204       else if ((errno != 0) || (strchr(values[i], '-') != NULL))
205       {
206         log_log(LOG_WARNING, "%s: %s: out of range",
207                 myldap_get_dn(entry), attmap_passwd_uidNumber);
208         continue;
209       }
210     }
211     if (uid < nslcd_cfg->nss_min_uid)
212     {
213       log_log(LOG_DEBUG, "%s: %s: less than nss_min_uid",
214               myldap_get_dn(entry), attmap_passwd_uidNumber);
215     }
216     else
217       return 1;
218   }
219   /* nothing found */
220   return 0;
221 }
222 
223 /* Perform an LDAP lookup to translate the DN into a uid.
224    This function either returns NULL or a strdup()ed string. */
lookup_dn2uid(MYLDAP_SESSION * session,const char * dn,int * rcp,char * buf,size_t buflen)225 char *lookup_dn2uid(MYLDAP_SESSION *session, const char *dn, int *rcp,
226                     char *buf, size_t buflen)
227 {
228   MYLDAP_SEARCH *search;
229   MYLDAP_ENTRY *entry;
230   static const char *attrs[3];
231   int rc = LDAP_SUCCESS;
232   const char **values;
233   char *uid = NULL;
234   if (rcp == NULL)
235     rcp = &rc;
236   /* we have to look up the entry */
237   attrs[0] = attmap_passwd_uid;
238   attrs[1] = attmap_passwd_uidNumber;
239   attrs[2] = NULL;
240   search = myldap_search(session, dn, LDAP_SCOPE_BASE, passwd_filter, attrs, rcp);
241   if (search == NULL)
242   {
243     log_log(LOG_WARNING, "%s: lookup error: %s", dn, ldap_err2string(*rcp));
244     return NULL;
245   }
246   entry = myldap_get_entry(search, rcp);
247   if (entry == NULL)
248   {
249     if (*rcp != LDAP_SUCCESS)
250       log_log(LOG_WARNING, "%s: lookup error: %s", dn, ldap_err2string(*rcp));
251     return NULL;
252   }
253   /* check the uidNumber attribute if min_uid is set */
254   if (entry_has_valid_uid(entry))
255   {
256     /* get uid (just use first one) */
257     values = myldap_get_values(entry, attmap_passwd_uid);
258     /* check the result for presence and validity */
259     if ((values != NULL) && (values[0] != NULL) &&
260         isvalidname(values[0]) && (strlen(values[0]) < buflen))
261     {
262       strcpy(buf, values[0]);
263       uid = buf;
264     }
265   }
266   /* clean up and return */
267   myldap_search_close(search);
268   return uid;
269 }
270 
271 /* Translate the DN into a user name. This function tries several approaches
272    at getting the user name, including looking in the DN for a uid attribute,
273    looking in the cache and falling back to looking up a uid attribute in a
274    LDAP query. */
dn2uid(MYLDAP_SESSION * session,const char * dn,char * buf,size_t buflen)275 char *dn2uid(MYLDAP_SESSION *session, const char *dn, char *buf, size_t buflen)
276 {
277   struct dn2uid_cache_entry *cacheentry = NULL;
278   char *uid;
279   /* check for empty string */
280   if ((dn == NULL) || (*dn == '\0'))
281     return NULL;
282   /* try to look up uid within DN string */
283   if (myldap_cpy_rdn_value(dn, attmap_passwd_uid, buf, buflen) != NULL)
284   {
285     /* check if it is valid */
286     if (!isvalidname(buf))
287       return NULL;
288     return buf;
289   }
290   /* if we don't use the cache, just lookup and return */
291   if ((nslcd_cfg->cache_dn2uid_positive == 0) && (nslcd_cfg->cache_dn2uid_negative == 0))
292     return lookup_dn2uid(session, dn, NULL, buf, buflen);
293   /* see if we have a cached entry */
294   pthread_mutex_lock(&dn2uid_cache_mutex);
295   if (dn2uid_cache == NULL)
296     dn2uid_cache = dict_new();
297   if ((dn2uid_cache != NULL) && ((cacheentry = dict_get(dn2uid_cache, dn)) != NULL))
298   {
299     if ((cacheentry->uid != NULL) && (strlen(cacheentry->uid) < buflen))
300     {
301       /* positive hit: if the cached entry is still valid, return that */
302       if ((nslcd_cfg->cache_dn2uid_positive > 0) &&
303           (time(NULL) < (cacheentry->timestamp + nslcd_cfg->cache_dn2uid_positive)))
304       {
305         strcpy(buf, cacheentry->uid);
306         pthread_mutex_unlock(&dn2uid_cache_mutex);
307         return buf;
308       }
309     }
310     else
311     {
312       /* negative hit: if the cached entry is still valid, return that */
313       if ((nslcd_cfg->cache_dn2uid_negative > 0) &&
314            (time(NULL) < (cacheentry->timestamp + nslcd_cfg->cache_dn2uid_negative)))
315       {
316         pthread_mutex_unlock(&dn2uid_cache_mutex);
317         return NULL;
318       }
319     }
320   }
321   pthread_mutex_unlock(&dn2uid_cache_mutex);
322   /* look up the uid using an LDAP query */
323   uid = lookup_dn2uid(session, dn, NULL, buf, buflen);
324   /* store the result in the cache */
325   pthread_mutex_lock(&dn2uid_cache_mutex);
326   /* try to get the entry from the cache here again because it could have
327      changed in the meantime */
328   cacheentry = dict_get(dn2uid_cache, dn);
329   if (cacheentry == NULL)
330   {
331     /* allocate a new entry in the cache */
332     cacheentry = (struct dn2uid_cache_entry *)malloc(sizeof(struct dn2uid_cache_entry));
333     if (cacheentry != NULL)
334     {
335       cacheentry->uid = NULL;
336       dict_put(dn2uid_cache, dn, cacheentry);
337     }
338   }
339   /* update the cache entry */
340   if (cacheentry != NULL)
341   {
342     cacheentry->timestamp = time(NULL);
343     /* copy the uid if needed */
344     if (cacheentry->uid == NULL)
345       cacheentry->uid = uid != NULL ? strdup(uid) : NULL;
346     else if ((uid == NULL) || (strcmp(cacheentry->uid, uid) != 0))
347     {
348       free(cacheentry->uid);
349       cacheentry->uid = uid != NULL ? strdup(uid) : NULL;
350     }
351   }
352   pthread_mutex_unlock(&dn2uid_cache_mutex);
353   /* copy the result into the buffer */
354   return uid;
355 }
356 
uid2entry(MYLDAP_SESSION * session,const char * uid,int * rcp)357 MYLDAP_ENTRY *uid2entry(MYLDAP_SESSION *session, const char *uid, int *rcp)
358 {
359   MYLDAP_SEARCH *search = NULL;
360   MYLDAP_ENTRY *entry = NULL;
361   const char *base;
362   int i;
363   static const char *attrs[3];
364   char filter[BUFLEN_FILTER];
365   /* if it isn't a valid username, just bail out now */
366   if (!isvalidname(uid))
367   {
368     if (rcp != NULL)
369       *rcp = LDAP_INVALID_SYNTAX;
370     return NULL;
371   }
372   /* set up attributes (we don't need much) */
373   attrs[0] = attmap_passwd_uid;
374   attrs[1] = attmap_passwd_uidNumber;
375   attrs[2] = NULL;
376   /* we have to look up the entry */
377   mkfilter_passwd_byname(uid, filter, sizeof(filter));
378   for (i = 0; (i < NSS_LDAP_CONFIG_MAX_BASES) && ((base = passwd_bases[i]) != NULL); i++)
379   {
380     search = myldap_search(session, base, passwd_scope, filter, attrs, rcp);
381     if (search == NULL)
382     {
383       if ((rcp != NULL) && (*rcp == LDAP_SUCCESS))
384         *rcp = LDAP_NO_SUCH_OBJECT;
385       return NULL;
386     }
387     entry = myldap_get_entry(search, rcp);
388     if ((entry != NULL) && (entry_has_valid_uid(entry)))
389       return entry;
390   }
391   if ((rcp != NULL) && (*rcp == LDAP_SUCCESS))
392     *rcp = LDAP_NO_SUCH_OBJECT;
393   return NULL;
394 }
395 
uid2dn(MYLDAP_SESSION * session,const char * uid,char * buf,size_t buflen)396 char *uid2dn(MYLDAP_SESSION *session, const char *uid, char *buf, size_t buflen)
397 {
398   MYLDAP_ENTRY *entry;
399   /* look up the entry */
400   entry = uid2entry(session, uid, NULL);
401   if (entry == NULL)
402     return NULL;
403   /* get DN */
404   return myldap_cpy_dn(entry, buf, buflen);
405 }
406 
407 #ifndef NSS_FLAVOUR_GLIBC
408 /* only check nsswitch.conf for glibc */
409 #define check_nsswitch_reload()
410 #define shadow_uses_ldap() (1)
411 #endif /* NSS_FLAVOUR_GLIBC */
412 
413 /* the maximum number of uidNumber attributes per entry */
414 #define MAXUIDS_PER_ENTRY 5
415 
write_passwd(TFILE * fp,MYLDAP_ENTRY * entry,const char * requser,const uid_t * requid,uid_t calleruid)416 static int write_passwd(TFILE *fp, MYLDAP_ENTRY *entry, const char *requser,
417                         const uid_t *requid, uid_t calleruid)
418 {
419   int32_t tmpint32;
420   const char **tmpvalues;
421   char *tmp;
422   const char **usernames;
423   const char *passwd;
424   uid_t uids[MAXUIDS_PER_ENTRY];
425   int numuids;
426   char gidbuf[32];
427   gid_t gid;
428   char gecos[1024];
429   char homedir[256];
430   char shell[64];
431   char passbuffer[BUFLEN_PASSWORDHASH];
432   int i, j;
433   /* get the usernames for this entry */
434   usernames = myldap_get_values(entry, attmap_passwd_uid);
435   if ((usernames == NULL) || (usernames[0] == NULL))
436   {
437     log_log(LOG_WARNING, "%s: %s: missing",
438             myldap_get_dn(entry), attmap_passwd_uid);
439     return 0;
440   }
441   /* if we are using shadow maps and this entry looks like it would return
442      shadow information, make the passwd entry indicate it */
443   if (myldap_has_objectclass(entry, "shadowAccount") && nsswitch_shadow_uses_ldap())
444   {
445     passwd = "x";
446   }
447   else
448   {
449     passwd = get_userpassword(entry, attmap_passwd_userPassword,
450                               passbuffer, sizeof(passbuffer));
451     if ((passwd == NULL) || (calleruid != 0))
452       passwd = default_passwd_userPassword;
453   }
454   /* get the uids for this entry */
455   if (requid != NULL)
456   {
457     uids[0] = *requid;
458     numuids = 1;
459   }
460   else
461   {
462     tmpvalues = myldap_get_values_len(entry, attmap_passwd_uidNumber);
463     if ((tmpvalues == NULL) || (tmpvalues[0] == NULL))
464     {
465       log_log(LOG_WARNING, "%s: %s: missing",
466               myldap_get_dn(entry), attmap_passwd_uidNumber);
467       return 0;
468     }
469     for (numuids = 0; (numuids < MAXUIDS_PER_ENTRY) && (tmpvalues[numuids] != NULL); numuids++)
470     {
471       if (uidSid != NULL)
472         uids[numuids] = (uid_t)binsid2id(tmpvalues[numuids]);
473       else
474       {
475         errno = 0;
476         uids[numuids] = strtouid(tmpvalues[numuids], &tmp, 10);
477         if ((*(tmpvalues[numuids]) == '\0') || (*tmp != '\0'))
478         {
479           log_log(LOG_WARNING, "%s: %s: non-numeric",
480                   myldap_get_dn(entry), attmap_passwd_uidNumber);
481           return 0;
482         }
483         else if ((errno != 0) || (strchr(tmpvalues[numuids], '-') != NULL))
484         {
485           log_log(LOG_WARNING, "%s: %s: out of range",
486                   myldap_get_dn(entry), attmap_passwd_uidNumber);
487           return 0;
488         }
489       }
490       uids[numuids] += nslcd_cfg->nss_uid_offset;
491       if (uids[numuids] < nslcd_cfg->nss_min_uid)
492       {
493           log_log(LOG_DEBUG, "%s: %s: less than nss_min_uid",
494                   myldap_get_dn(entry), attmap_passwd_uidNumber);
495       }
496     }
497   }
498   /* get the gid for this entry */
499   if (gidSid != NULL)
500   {
501     tmpvalues = myldap_get_values_len(entry, attmap_passwd_gidNumber);
502     if ((tmpvalues == NULL) || (tmpvalues[0] == NULL))
503     {
504       log_log(LOG_WARNING, "%s: %s: missing",
505               myldap_get_dn(entry), attmap_passwd_gidNumber);
506       return 0;
507     }
508     gid = (gid_t)binsid2id(tmpvalues[0]);
509   }
510   else
511   {
512     attmap_get_value(entry, attmap_passwd_gidNumber, gidbuf, sizeof(gidbuf));
513     if (gidbuf[0] == '\0')
514     {
515       log_log(LOG_WARNING, "%s: %s: missing",
516               myldap_get_dn(entry), attmap_passwd_gidNumber);
517       return 0;
518     }
519     errno = 0;
520     gid = strtogid(gidbuf, &tmp, 10);
521     if ((gidbuf[0] == '\0') || (*tmp != '\0'))
522     {
523       log_log(LOG_WARNING, "%s: %s: non-numeric",
524               myldap_get_dn(entry), attmap_passwd_gidNumber);
525       return 0;
526     }
527     else if ((errno != 0) || (strchr(gidbuf, '-') != NULL))
528     {
529       log_log(LOG_WARNING, "%s: %s: out of range",
530               myldap_get_dn(entry), attmap_passwd_gidNumber);
531       return 0;
532     }
533   }
534   gid += nslcd_cfg->nss_gid_offset;
535   /* get the gecos for this entry */
536   attmap_get_value(entry, attmap_passwd_gecos, gecos, sizeof(gecos));
537   /* get the home directory for this entry */
538   attmap_get_value(entry, attmap_passwd_homeDirectory, homedir, sizeof(homedir));
539   if (homedir[0] == '\0')
540     log_log(LOG_WARNING, "%s: %s: missing",
541             myldap_get_dn(entry), attmap_passwd_homeDirectory);
542   /* get the shell for this entry */
543   attmap_get_value(entry, attmap_passwd_loginShell, shell, sizeof(shell));
544   /* write the entries */
545   for (i = 0; usernames[i] != NULL; i++)
546   {
547     if ((requser == NULL) || (STR_CMP(requser, usernames[i]) == 0))
548     {
549       if (!isvalidname(usernames[i]))
550       {
551         log_log(LOG_WARNING, "%s: %s: denied by validnames option",
552                 myldap_get_dn(entry), attmap_passwd_uid);
553       }
554       else
555       {
556         for (j = 0; j < numuids; j++)
557         {
558           if (uids[j] >= nslcd_cfg->nss_min_uid)
559           {
560             WRITE_INT32(fp, NSLCD_RESULT_BEGIN);
561             WRITE_STRING(fp, usernames[i]);
562             WRITE_STRING(fp, passwd);
563             WRITE_INT32(fp, uids[j]);
564             WRITE_INT32(fp, gid);
565             WRITE_STRING(fp, gecos);
566             WRITE_STRING(fp, homedir);
567             WRITE_STRING(fp, shell);
568           }
569         }
570       }
571     }
572   }
573   return 0;
574 }
575 
576 NSLCD_HANDLE_UID(
577   passwd, byname, NSLCD_ACTION_PASSWD_BYNAME,
578   char name[BUFLEN_NAME];
579   char filter[BUFLEN_FILTER];
580   READ_STRING(fp, name);
581   log_setrequest("passwd=\"%s\"", name);
582   if (!isvalidname(name))
583   {
584     log_log(LOG_WARNING, "request denied by validnames option");
585     return -1;
586   }
587   nsswitch_check_reload();,
588   mkfilter_passwd_byname(name, filter, sizeof(filter)),
589   write_passwd(fp, entry, name, NULL, calleruid)
590 )
591 
592 NSLCD_HANDLE_UID(
593   passwd, byuid, NSLCD_ACTION_PASSWD_BYUID,
594   uid_t uid;
595   char filter[BUFLEN_FILTER];
596   READ_INT32(fp, uid);
597   log_setrequest("passwd=%lu", (unsigned long int)uid);
598   if (uid < nslcd_cfg->nss_min_uid)
599   {
600     log_log(LOG_DEBUG, "request ignored by nss_min_uid option");
601     /* return an empty result */
602     WRITE_INT32(fp, NSLCD_VERSION);
603     WRITE_INT32(fp, NSLCD_ACTION_PASSWD_BYUID);
604     WRITE_INT32(fp, NSLCD_RESULT_END);
605     return 0;
606   }
607   nsswitch_check_reload();,
608   mkfilter_passwd_byuid(uid, filter, sizeof(filter)),
609   write_passwd(fp, entry, NULL, &uid, calleruid)
610 )
611 
612 NSLCD_HANDLE_UID(
613   passwd, all, NSLCD_ACTION_PASSWD_ALL,
614   const char *filter;
615   log_setrequest("passwd(all)");
616   nsswitch_check_reload();,
617   (filter = passwd_filter, 0),
618   write_passwd(fp, entry, NULL, NULL, calleruid)
619 )
620