getpwent.c revision 1.21.2.3 1 /* $NetBSD: getpwent.c,v 1.21.2.3 1997/06/02 05:01:12 lukem Exp $ */
2
3 /*
4 * Copyright (c) 1988, 1993
5 * The Regents of the University of California. All rights reserved.
6 * Portions Copyright (c) 1994, 1995, Jason Downs. All rights reserved.
7 * Portions Copyright (c) 1997 Luke Mewburn. All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. All advertising materials mentioning features or use of this software
18 * must display the following acknowledgement:
19 * This product includes software developed by the University of
20 * California, Berkeley and its contributors.
21 * 4. Neither the name of the University nor the names of its contributors
22 * may be used to endorse or promote products derived from this software
23 * without specific prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 * SUCH DAMAGE.
36 */
37
38 #if defined(LIBC_SCCS) && !defined(lint)
39 #if 0
40 static char sccsid[] = "@(#)getpwent.c 8.1 (Berkeley) 6/4/93";
41 #else
42 static char rcsid[] = "$NetBSD: getpwent.c,v 1.21.2.3 1997/06/02 05:01:12 lukem Exp $";
43 #endif
44 #endif /* LIBC_SCCS and not lint */
45
46 #include <sys/param.h>
47 #include <fcntl.h>
48 #include <db.h>
49 #include <syslog.h>
50 #include <pwd.h>
51 #include <utmp.h>
52 #include <errno.h>
53 #include <unistd.h>
54 #include <stdlib.h>
55 #include <string.h>
56 #include <limits.h>
57 #include <netgroup.h>
58 #include <nsswitch.h>
59 #ifdef HESIOD
60 #include <hesiod.h>
61 #endif
62 #ifdef YP
63 #include <machine/param.h>
64 #include <stdio.h>
65 #include <rpc/rpc.h>
66 #include <rpcsvc/yp_prot.h>
67 #include <rpcsvc/ypclnt.h>
68 #endif
69
70 static struct passwd _pw_passwd; /* password structure */
71 static DB *_pw_db; /* password database */
72 static int _pw_keynum; /* key counter */
73 static int _pw_stayopen; /* keep fd's open */
74 static int _pw_flags; /* password flags */
75 static int _pw_none; /* true if getpwent got EOF */
76
77 static int __hashpw __P((DBT *));
78 static int __initdb __P((void));
79
80 const char __yp_token[] = "__YP!"; /* Let pwd_mkdb pull this in. */
81
82 #ifdef YP
83 static char *__ypcurrent, *__ypdomain;
84 static int __ypcurrentlen;
85 #endif
86
87 #ifdef HESIOD
88 static int _pw_hesnum;
89 #endif
90
91 #if defined(YP) || defined(HESIOD)
92 enum _pwmode { PWMODE_NONE, PWMODE_FULL, PWMODE_USER, PWMODE_NETGRP };
93 static enum _pwmode __pwmode;
94
95 static struct passwd *__pwproto = (struct passwd *)NULL;
96 static int __pwproto_flags;
97 static char line[1024];
98 static long prbuf[1024 / sizeof(long)];
99 static DB *__pwexclude = (DB *)NULL;
100
101 /*
102 * add a name to the compat mode exclude list
103 */
104 static int
105 __pwexclude_add(name)
106 const char *name;
107 {
108 DBT key, data;
109
110 /* initialize the exclusion table if needed. */
111 if(__pwexclude == (DB *)NULL) {
112 __pwexclude = dbopen(NULL, O_RDWR, 600, DB_HASH, NULL);
113 if(__pwexclude == (DB *)NULL)
114 return 1;
115 }
116
117 /* set up the key */
118 key.data = (char *)name;
119 key.size = strlen(name);
120
121 /* data is nothing. */
122 data.data = NULL;
123 data.size = 0;
124
125 /* store it */
126 if((__pwexclude->put)(__pwexclude, &key, &data, 0) == -1)
127 return 1;
128
129 return 0;
130 }
131
132 /*
133 * test if a name is on the compat mode exclude list
134 */
135 static int
136 __pwexclude_is(name)
137 const char *name;
138 {
139 DBT key, data;
140
141 if(__pwexclude == (DB *)NULL)
142 return 0; /* nothing excluded */
143
144 /* set up the key */
145 key.data = (char *)name;
146 key.size = strlen(name);
147
148 if((__pwexclude->get)(__pwexclude, &key, &data, 0) == 0)
149 return 1; /* excluded */
150
151 return 0;
152 }
153
154 /*
155 * setup the compat mode prototype template
156 */
157 static void
158 __pwproto_set()
159 {
160 char *ptr;
161 struct passwd *pw = &_pw_passwd;
162
163 /* make this the new prototype */
164 ptr = (char *)prbuf;
165
166 /* first allocate the struct. */
167 __pwproto = (struct passwd *)ptr;
168 ptr += sizeof(struct passwd);
169
170 /* name */
171 if(pw->pw_name && (pw->pw_name)[0]) {
172 ptr = (char *)ALIGN(ptr);
173 memmove(ptr, pw->pw_name, strlen(pw->pw_name) + 1);
174 __pwproto->pw_name = ptr;
175 ptr += (strlen(pw->pw_name) + 1);
176 } else
177 __pwproto->pw_name = (char *)NULL;
178
179 /* password */
180 if(pw->pw_passwd && (pw->pw_passwd)[0]) {
181 ptr = (char *)ALIGN(ptr);
182 memmove(ptr, pw->pw_passwd, strlen(pw->pw_passwd) + 1);
183 __pwproto->pw_passwd = ptr;
184 ptr += (strlen(pw->pw_passwd) + 1);
185 } else
186 __pwproto->pw_passwd = (char *)NULL;
187
188 /* uid */
189 __pwproto->pw_uid = pw->pw_uid;
190
191 /* gid */
192 __pwproto->pw_gid = pw->pw_gid;
193
194 /* change (ignored anyway) */
195 __pwproto->pw_change = pw->pw_change;
196
197 /* class (ignored anyway) */
198 __pwproto->pw_class = "";
199
200 /* gecos */
201 if(pw->pw_gecos && (pw->pw_gecos)[0]) {
202 ptr = (char *)ALIGN(ptr);
203 memmove(ptr, pw->pw_gecos, strlen(pw->pw_gecos) + 1);
204 __pwproto->pw_gecos = ptr;
205 ptr += (strlen(pw->pw_gecos) + 1);
206 } else
207 __pwproto->pw_gecos = (char *)NULL;
208
209 /* dir */
210 if(pw->pw_dir && (pw->pw_dir)[0]) {
211 ptr = (char *)ALIGN(ptr);
212 memmove(ptr, pw->pw_dir, strlen(pw->pw_dir) + 1);
213 __pwproto->pw_dir = ptr;
214 ptr += (strlen(pw->pw_dir) + 1);
215 } else
216 __pwproto->pw_dir = (char *)NULL;
217
218 /* shell */
219 if(pw->pw_shell && (pw->pw_shell)[0]) {
220 ptr = (char *)ALIGN(ptr);
221 memmove(ptr, pw->pw_shell, strlen(pw->pw_shell) + 1);
222 __pwproto->pw_shell = ptr;
223 ptr += (strlen(pw->pw_shell) + 1);
224 } else
225 __pwproto->pw_shell = (char *)NULL;
226
227 /* expire (ignored anyway) */
228 __pwproto->pw_expire = pw->pw_expire;
229
230 /* flags */
231 __pwproto_flags = _pw_flags;
232 }
233
234 /*
235 * parse an old-style passwd file line (from NIS or HESIOD)
236 */
237 static int
238 __pwparse(pw, s)
239 struct passwd *pw;
240 char *s;
241 {
242 char *bp, *cp, *ep;
243 unsigned long id;
244
245 /* since this is currently using strsep(), parse it first */
246 bp = s;
247 pw->pw_name = strsep(&bp, ":\n");
248 pw->pw_passwd = strsep(&bp, ":\n");
249 if (!(cp = strsep(&bp, ":\n")))
250 return 1;
251 id = strtoul(cp, &ep, 10);
252 if (id > UID_MAX || *ep != '\0')
253 return 1;
254 pw->pw_uid = (uid_t)id;
255 if (!(cp = strsep(&bp, ":\n")))
256 return 1;
257 id = strtoul(cp, &ep, 10);
258 if (id > GID_MAX || *ep != '\0')
259 return 1;
260 pw->pw_gid = (gid_t)id;
261 pw->pw_change = 0;
262 pw->pw_class = "";
263 pw->pw_gecos = strsep(&bp, ":\n");
264 pw->pw_dir = strsep(&bp, ":\n");
265 pw->pw_shell = strsep(&bp, ":\n");
266 pw->pw_expire = 0;
267
268 /* now let the prototype override, if set. */
269 if(__pwproto != (struct passwd *)NULL) {
270 #ifdef PW_OVERRIDE_PASSWD
271 if(__pwproto->pw_passwd != (char *)NULL)
272 pw->pw_passwd = __pwproto->pw_passwd;
273 #endif
274 if(!(__pwproto_flags & _PASSWORD_NOUID))
275 pw->pw_uid = __pwproto->pw_uid;
276 if(!(__pwproto_flags & _PASSWORD_NOGID))
277 pw->pw_gid = __pwproto->pw_gid;
278 if(__pwproto->pw_gecos != (char *)NULL)
279 pw->pw_gecos = __pwproto->pw_gecos;
280 if(__pwproto->pw_dir != (char *)NULL)
281 pw->pw_dir = __pwproto->pw_dir;
282 if(__pwproto->pw_shell != (char *)NULL)
283 pw->pw_shell = __pwproto->pw_shell;
284 }
285 return 0;
286 }
287 #endif /* YP || HESIOD */
288
289 /*
290 * local files implementation of getpw*()
291 * varargs: type, [ uid (type == _PW_KEYBYUID) | name (type == _PW_KEYBYNAME) ]
292 */
293 static int
294 _local_getpw(rv, cb_data, ap)
295 void *rv;
296 void *cb_data;
297 va_list ap;
298 {
299 DBT key;
300 char bf[MAX(UT_NAMESIZE, sizeof(_pw_keynum)) + 1];
301 uid_t uid;
302 int search, len, rval;
303 const char *name;
304
305 if (!_pw_db && !__initdb())
306 return NS_UNAVAIL;
307
308 search = va_arg(ap, int);
309 bf[0] = search;
310 switch (search) {
311 case _PW_KEYBYNUM:
312 ++_pw_keynum;
313 memmove(bf + 1, (char *)&_pw_keynum, sizeof(_pw_keynum));
314 key.size = sizeof(_pw_keynum) + 1;
315 break;
316 case _PW_KEYBYNAME:
317 name = va_arg(ap, const char *);
318 len = strlen(name);
319 memmove(bf + 1, name, MIN(len, UT_NAMESIZE));
320 key.size = len + 1;
321 break;
322 case _PW_KEYBYUID:
323 uid = va_arg(ap, uid_t);
324 memmove(bf + 1, (char *)&uid, sizeof(len));
325 key.size = sizeof(uid) + 1;
326 break;
327 default:
328 abort();
329 }
330
331 key.data = (u_char *)bf;
332 rval = __hashpw(&key);
333 if (rval == NS_NOTFOUND && search == _PW_KEYBYNUM) {
334 _pw_none = 1;
335 rval = NS_SUCCESS;
336 }
337
338 if (!_pw_stayopen && (search != _PW_KEYBYNUM)) {
339 (void)(_pw_db->close)(_pw_db);
340 _pw_db = (DB *)NULL;
341 }
342 return (rval);
343 }
344
345 #ifdef HESIOD
346 /*
347 * hesiod implementation of getpw*()
348 * varargs: type, [ uid (type == _PW_KEYBYUID) | name (type == _PW_KEYBYNAME) ]
349 */
350 static int
351 _dns_getpw(rv, cb_data, ap)
352 void *rv;
353 void *cb_data;
354 va_list ap;
355 {
356 const char *name;
357 uid_t uid;
358 int search;
359 char **hp;
360
361
362 search = va_arg(ap, int);
363 switch (search) {
364 case _PW_KEYBYNUM:
365 snprintf(line, sizeof(line) - 1, "passwd-%u", _pw_hesnum);
366 _pw_hesnum++;
367 break;
368 case _PW_KEYBYNAME:
369 name = va_arg(ap, const char *);
370 strncpy(line, name, sizeof(line));
371 break;
372 case _PW_KEYBYUID:
373 uid = va_arg(ap, uid_t);
374 snprintf(line, sizeof(line), "%u", uid);
375 break;
376 default:
377 abort();
378 }
379 line[sizeof(line) - 1] = '\0';
380
381 hp = hes_resolve(line, "passwd");
382 if (hp == NULL) {
383 switch (hes_error()) {
384 case HES_ER_NOTFOUND:
385 if (search == _PW_KEYBYNUM) {
386 _pw_hesnum = 0;
387 _pw_none = 1;
388 return NS_SUCCESS;
389 }
390 return NS_NOTFOUND;
391 case HES_ER_OK:
392 abort();
393 default:
394 return NS_UNAVAIL;
395 }
396 }
397
398 strncpy(line, hp[0], sizeof(line)); /* only check first elem */
399 line[sizeof(line) - 1] = '\0';
400 hes_free(hp);
401 if (__pwparse(&_pw_passwd, line))
402 return NS_UNAVAIL;
403 return NS_SUCCESS;
404 }
405 #endif
406
407 #ifdef YP
408 /*
409 * nis implementation of getpw*()
410 * varargs: type, [ uid (type == _PW_KEYBYUID) | name (type == _PW_KEYBYNAME) ]
411 */
412 static int
413 _nis_getpw(rv, cb_data, ap)
414 void *rv;
415 void *cb_data;
416 va_list ap;
417 {
418 const char *name;
419 uid_t uid;
420 int search;
421 char *key, *data;
422 char *map = "passwd.byname";
423 int keylen, datalen, r;
424
425 if(__ypdomain == NULL) {
426 if(_yp_check(&__ypdomain) == 0)
427 return NS_UNAVAIL;
428 }
429
430 search = va_arg(ap, int);
431 switch (search) {
432 case _PW_KEYBYNUM:
433 break;
434 case _PW_KEYBYNAME:
435 name = va_arg(ap, const char *);
436 strncpy(line, name, sizeof(line));
437 break;
438 case _PW_KEYBYUID:
439 uid = va_arg(ap, uid_t);
440 snprintf(line, sizeof(line), "%u", uid);
441 map = "passwd.byuid";
442 break;
443 default:
444 abort();
445 }
446 line[sizeof(line) - 1] = '\0';
447 if (search != _PW_KEYBYNUM) {
448 data = NULL;
449 r = yp_match(__ypdomain, map, line, strlen(line),
450 &data, &datalen);
451 switch (r) {
452 case 0:
453 break;
454 case YPERR_KEY:
455 r = NS_NOTFOUND;
456 break;
457 default:
458 r = NS_UNAVAIL;
459 break;
460 }
461 if (r != 0) {
462 if (data)
463 free(data);
464 return r;
465 }
466 data[datalen] = '\0'; /* clear trailing \n */
467 strncpy(line, data, sizeof(line));
468 line[sizeof(line) - 1] = '\0';
469 free(data);
470 if (__pwparse(&_pw_passwd, line))
471 return NS_UNAVAIL;
472 return NS_SUCCESS;
473 }
474
475 for (;;) {
476 data = key = NULL;
477 if (__ypcurrent) {
478 r = yp_next(__ypdomain, map,
479 __ypcurrent, __ypcurrentlen,
480 &key, &keylen, &data, &datalen);
481 free(__ypcurrent);
482 switch (r) {
483 case 0:
484 __ypcurrent = key;
485 __ypcurrentlen = keylen;
486 break;
487 case YPERR_NOMORE:
488 __ypcurrent = NULL;
489 _pw_none = 1;
490 if (key)
491 free(key);
492 return NS_SUCCESS;
493 default:
494 r = NS_UNAVAIL;
495 break;
496 }
497 } else {
498 r = 0;
499 if (yp_first(__ypdomain, map, &__ypcurrent,
500 &__ypcurrentlen, &data, &datalen))
501 r = NS_UNAVAIL;
502 }
503 if (r != 0) {
504 if (key)
505 free(key);
506 if (data)
507 free(data);
508 return r;
509 }
510 data[datalen] = '\0'; /* clear trailing \n */
511 strncpy(line, data, sizeof(line));
512 line[sizeof(line) - 1] = '\0';
513 free(data);
514 if (! __pwparse(&_pw_passwd, line))
515 return NS_SUCCESS;
516 }
517 /* NOTREACHED */
518 } /* _nis_getpw */
519 #endif
520
521 #if defined(YP) || defined(HESIOD)
522 /*
523 * See if the compat token is in the database. Only works if pwd_mkdb knows
524 * about the token.
525 */
526 static int
527 __has_compatpw()
528 {
529 DBT key, data;
530 DBT pkey, pdata;
531 int len;
532 char bf[UT_NAMESIZE];
533
534 key.data = (u_char *)__yp_token;
535 key.size = strlen(__yp_token);
536
537 /* Pre-token database support. */
538 bf[0] = _PW_KEYBYNAME;
539 len = strlen("+");
540 memmove(bf + 1, "+", MIN(len, UT_NAMESIZE));
541 pkey.data = (u_char *)bf;
542 pkey.size = len + 1;
543
544 if ((_pw_db->get)(_pw_db, &key, &data, 0)
545 && (_pw_db->get)(_pw_db, &pkey, &pdata, 0))
546 return 0; /* No compat token */
547 return 1;
548 }
549
550 /*
551 * log an error if "files" or "compat" is specified in passwd_compat database
552 */
553 static int
554 _bad_getpw(rv, cb_data, ap)
555 void *rv;
556 void *cb_data;
557 va_list ap;
558 {
559 static int warned;
560 if (!warned) {
561 syslog(LOG_ERR,
562 "nsswitch.conf passwd_compat database can't use '%s'",
563 (char *)cb_data);
564 }
565 warned = 1;
566 return NS_UNAVAIL;
567 }
568
569 /*
570 * when a name lookup in compat mode is required (e.g., '+name', or a name in
571 * '+@netgroup'), look it up in the 'passwd_compat' nsswitch database.
572 * only Hesiod and NIS is supported - it doesn't make sense to lookup
573 * compat names from 'files' or 'compat'.
574 */
575 static int
576 __getpwcompat(type, uid, name)
577 int type;
578 uid_t uid;
579 const char *name;
580 {
581 static ns_dtab dtab;
582
583 if (dtab[NS_FILES].cb == NULL) {
584 NS_FILES_CB(dtab, _bad_getpw, "files");
585 NS_DNS_CB(dtab, _dns_getpw, NULL);
586 NS_NIS_CB(dtab, _nis_getpw, NULL);
587 NS_COMPAT_CB(dtab, _bad_getpw, "compat");
588 }
589
590 switch (type) {
591 case _PW_KEYBYNUM:
592 return nsdispatch(NULL, dtab, NSDB_PASSWD_COMPAT, type);
593 case _PW_KEYBYNAME:
594 return nsdispatch(NULL, dtab, NSDB_PASSWD_COMPAT, type, name);
595 case _PW_KEYBYUID:
596 return nsdispatch(NULL, dtab, NSDB_PASSWD_COMPAT, type, uid);
597 default:
598 abort();
599 }
600 }
601
602 /*
603 * compat implementation of getpwent()
604 * varargs (ignored):
605 * type, [ uid (type == _PW_KEYBYUID) | name (type == _PW_KEYBYNAME) ]
606 */
607 static int
608 _compat_getpwent(rv, cb_data, ap)
609 void *rv;
610 void *cb_data;
611 va_list ap;
612 {
613 DBT key;
614 char bf[sizeof(_pw_keynum) + 1];
615 static char *name = NULL;
616 const char *user, *host, *dom;
617 int has_compatpw;
618
619 if (!_pw_db && !__initdb())
620 return NS_UNAVAIL;
621
622 has_compatpw = __has_compatpw();
623
624 again:
625 if (has_compatpw && (__pwmode != PWMODE_NONE)) {
626 int r;
627
628 switch (__pwmode) {
629 case PWMODE_FULL:
630 r = __getpwcompat(_PW_KEYBYNUM, 0, NULL);
631 if (r == NS_SUCCESS)
632 return r;
633 __pwmode = PWMODE_NONE;
634 break;
635
636 case PWMODE_NETGRP:
637 r = getnetgrent(&host, &user, &dom);
638 if (r == 0) { /* end of group */
639 endnetgrent();
640 __pwmode = PWMODE_NONE;
641 break;
642 }
643 if (!user || !*user)
644 break;
645 r = __getpwcompat(_PW_KEYBYNAME, 0, user);
646 if (r == NS_SUCCESS)
647 return r;
648 break;
649
650 case PWMODE_USER:
651 if (name == NULL) {
652 __pwmode = PWMODE_NONE;
653 break;
654 }
655 r = __getpwcompat(_PW_KEYBYNAME, 0, name);
656 free(name);
657 name = NULL;
658 if (r == NS_SUCCESS)
659 return r;
660 break;
661
662 case PWMODE_NONE:
663 abort();
664 }
665 goto again;
666 }
667
668 ++_pw_keynum;
669 bf[0] = _PW_KEYBYNUM;
670 memmove(bf + 1, (char *)&_pw_keynum, sizeof(_pw_keynum));
671 key.data = (u_char *)bf;
672 key.size = sizeof(_pw_keynum) + 1;
673 if(__hashpw(&key) == NS_SUCCESS) {
674 /* if we don't have YP at all, don't bother. */
675 if (has_compatpw) {
676 if(_pw_passwd.pw_name[0] == '+') {
677 /* set the mode */
678 switch(_pw_passwd.pw_name[1]) {
679 case '\0':
680 __pwmode = PWMODE_FULL;
681 break;
682 case '@':
683 __pwmode = PWMODE_NETGRP;
684 setnetgrent(_pw_passwd.pw_name + 2);
685 break;
686 default:
687 __pwmode = PWMODE_USER;
688 name = strdup(_pw_passwd.pw_name + 1);
689 break;
690 }
691
692 /* save the prototype */
693 __pwproto_set();
694 goto again;
695 } else if(_pw_passwd.pw_name[0] == '-') {
696 /* an attempted exclusion */
697 switch(_pw_passwd.pw_name[1]) {
698 case '\0':
699 break;
700 case '@':
701 setnetgrent(_pw_passwd.pw_name + 2);
702 while(getnetgrent(&host, &user, &dom)) {
703 if(user && *user)
704 __pwexclude_add(user);
705 }
706 endnetgrent();
707 break;
708 default:
709 __pwexclude_add(_pw_passwd.pw_name + 1);
710 break;
711 }
712 goto again;
713 }
714 }
715 return NS_SUCCESS;
716 }
717 return NS_NOTFOUND;
718 }
719
720 /*
721 * compat implementation of getpwnam() and getpwuid()
722 * varargs: type, [ uid (type == _PW_KEYBYUID) | name (type == _PW_KEYBYNAME) ]
723 */
724
725 static int
726 _compat_getpw(rv, cb_data, ap)
727 void *rv;
728 void *cb_data;
729 va_list ap;
730 {
731 DBT key;
732 int len, search, rval;
733 uid_t uid;
734 char bf[MAXLOGNAME + 1];
735 const char *name;
736
737 search = va_arg(ap, int);
738 uid = 0;
739 name = NULL;
740 rval = NS_NOTFOUND;
741
742 if (!_pw_db && !__initdb())
743 return NS_UNAVAIL;
744
745 switch (search) {
746 case _PW_KEYBYNAME:
747 name = va_arg(ap, const char *);
748 break;
749 case _PW_KEYBYUID:
750 uid = va_arg(ap, uid_t);
751 break;
752 default:
753 abort();
754 }
755
756 /*
757 * If YP is active, we must sequence through the passwd file
758 * in sequence.
759 */
760 if (__has_compatpw()) {
761 int r;
762 int s = -1;
763 const char *host, *user, *dom;
764
765 for(_pw_keynum=1; _pw_keynum; _pw_keynum++) {
766 bf[0] = _PW_KEYBYNUM;
767 memmove(bf + 1, (char *)&_pw_keynum,
768 sizeof(_pw_keynum));
769 key.data = (u_char *)bf;
770 key.size = sizeof(_pw_keynum) + 1;
771 if(__hashpw(&key) != NS_SUCCESS)
772 break;
773 switch(_pw_passwd.pw_name[0]) {
774 case '+':
775 /* save the prototype */
776 __pwproto_set();
777
778 switch(_pw_passwd.pw_name[1]) {
779 case '\0':
780 r = __getpwcompat(search, uid, name);
781 if (r != NS_SUCCESS)
782 continue;
783 break;
784 case '@':
785 pwnam_netgrp:
786 if(__ypcurrent) {
787 free(__ypcurrent);
788 __ypcurrent = NULL;
789 }
790 if(s == -1) /* first time */
791 setnetgrent(_pw_passwd.pw_name + 2);
792 s = getnetgrent(&host, &user, &dom);
793 if(s == 0) { /* end of group */
794 endnetgrent();
795 s = -1;
796 continue;
797 }
798 if (!user || !*user)
799 goto pwnam_netgrp;
800
801 r = __getpwcompat(_PW_KEYBYNAME,
802 0, user);
803
804 if (r == NS_UNAVAIL)
805 return r;
806 if (r == NS_NOTFOUND) {
807 /*
808 * just because this user is bad
809 * it doesn't mean they all are.
810 */
811 goto pwnam_netgrp;
812 }
813 break;
814 default:
815 user = _pw_passwd.pw_name + 1;
816 r = __getpwcompat(_PW_KEYBYNAME,
817 0, user);
818
819 if (r == NS_UNAVAIL)
820 return r;
821 if (r == NS_NOTFOUND)
822 continue;
823 break;
824 }
825 if(__pwexclude_is(_pw_passwd.pw_name)) {
826 if(s == 1) /* inside netgrp */
827 goto pwnam_netgrp;
828 continue;
829 }
830 break;
831 case '-':
832 /* attempted exclusion */
833 switch(_pw_passwd.pw_name[1]) {
834 case '\0':
835 break;
836 case '@':
837 setnetgrent(_pw_passwd.pw_name + 2);
838 while(getnetgrent(&host, &user, &dom)) {
839 if(user && *user)
840 __pwexclude_add(user);
841 }
842 endnetgrent();
843 break;
844 default:
845 __pwexclude_add(_pw_passwd.pw_name + 1);
846 break;
847 }
848 break;
849
850 continue;
851 }
852 if ((search == _PW_KEYBYNAME &&
853 strcmp(_pw_passwd.pw_name, name) == 0)
854 || (search == _PW_KEYBYUID &&
855 _pw_passwd.pw_uid == uid)) {
856 rval = NS_SUCCESS;
857 break;
858 }
859 if(s == 1) /* inside netgrp */
860 goto pwnam_netgrp;
861 continue;
862 }
863 __pwproto = (struct passwd *)NULL;
864 } else {
865 bf[0] = _PW_KEYBYNAME;
866 len = strlen(name);
867 memmove(bf + 1, name, MIN(len, UT_NAMESIZE));
868 key.data = (u_char *)bf;
869 key.size = len + 1;
870 rval = __hashpw(&key);
871 }
872
873 if (!_pw_stayopen) {
874 (void)(_pw_db->close)(_pw_db);
875 _pw_db = (DB *)NULL;
876 }
877 if(__pwexclude != (DB *)NULL) {
878 (void)(__pwexclude->close)(__pwexclude);
879 __pwexclude = (DB *)NULL;
880 }
881 return rval;
882 }
883 #endif /* YP || HESIOD */
884
885 struct passwd *
886 getpwent()
887 {
888 int r;
889 static ns_dtab dtab;
890
891 if (dtab[NS_FILES].cb == NULL) {
892 NS_FILES_CB(dtab, _local_getpw, NULL);
893 NS_DNS_CB(dtab, _dns_getpw, NULL);
894 NS_NIS_CB(dtab, _nis_getpw, NULL);
895 NS_COMPAT_CB(dtab, _compat_getpwent, NULL);
896 }
897
898 _pw_none = 0;
899 r = nsdispatch(NULL, dtab, NSDB_PASSWD, _PW_KEYBYNUM);
900 if (_pw_none || r != NS_SUCCESS)
901 return (struct passwd *)NULL;
902 return &_pw_passwd;
903 }
904
905 struct passwd *
906 getpwnam(name)
907 const char *name;
908 {
909 int r;
910 static ns_dtab dtab;
911
912 if (name == NULL || name[0] == '\0')
913 return (struct passwd *)NULL;
914
915 if (dtab[NS_FILES].cb == NULL) {
916 NS_FILES_CB(dtab, _local_getpw, NULL);
917 NS_DNS_CB(dtab, _dns_getpw, NULL);
918 NS_NIS_CB(dtab, _nis_getpw, NULL);
919 NS_COMPAT_CB(dtab, _compat_getpw, NULL);
920 }
921
922 r = nsdispatch(NULL, dtab, NSDB_PASSWD, _PW_KEYBYNAME, name);
923 return (r == NS_SUCCESS ? &_pw_passwd : (struct passwd *)NULL);
924 }
925
926 struct passwd *
927 getpwuid(uid)
928 uid_t uid;
929 {
930 int r;
931 static ns_dtab dtab;
932
933 if (dtab[NS_FILES].cb == NULL) {
934 NS_FILES_CB(dtab, _local_getpw, NULL);
935 NS_DNS_CB(dtab, _dns_getpw, NULL);
936 NS_NIS_CB(dtab, _nis_getpw, NULL);
937 NS_COMPAT_CB(dtab, _compat_getpw, NULL);
938 }
939
940 r = nsdispatch(NULL, dtab, NSDB_PASSWD, _PW_KEYBYUID, (int)uid);
941 return (r == NS_SUCCESS ? &_pw_passwd : (struct passwd *)NULL);
942 }
943
944 int
945 setpassent(stayopen)
946 int stayopen;
947 {
948 _pw_keynum = 0;
949 _pw_stayopen = stayopen;
950 #ifdef YP
951 __pwmode = PWMODE_NONE;
952 if(__ypcurrent)
953 free(__ypcurrent);
954 __ypcurrent = NULL;
955 #endif
956 #ifdef HESIOD
957 _pw_hesnum = 0;
958 #endif
959 #if defined(YP) || defined(HESIOD)
960 if(__pwexclude != (DB *)NULL) {
961 (void)(__pwexclude->close)(__pwexclude);
962 __pwexclude = (DB *)NULL;
963 }
964 __pwproto = (struct passwd *)NULL;
965 #endif
966 return 1;
967 }
968
969 void
970 setpwent()
971 {
972 (void) setpassent(0);
973 }
974
975 void
976 endpwent()
977 {
978 _pw_keynum = 0;
979 if (_pw_db) {
980 (void)(_pw_db->close)(_pw_db);
981 _pw_db = (DB *)NULL;
982 }
983 __pwmode = PWMODE_NONE;
984 #ifdef YP
985 if(__ypcurrent)
986 free(__ypcurrent);
987 __ypcurrent = NULL;
988 #endif
989 #ifdef HESIOD
990 _pw_hesnum = 0;
991 #endif
992 #if defined(YP) || defined(HESIOD)
993 if(__pwexclude != (DB *)NULL) {
994 (void)(__pwexclude->close)(__pwexclude);
995 __pwexclude = (DB *)NULL;
996 }
997 __pwproto = (struct passwd *)NULL;
998 #endif
999 }
1000
1001 static int
1002 __initdb()
1003 {
1004 static int warned;
1005 char *p;
1006
1007 #if defined(YP) || defined(HESIOD)
1008 __pwmode = PWMODE_NONE;
1009 #endif
1010 p = (geteuid()) ? _PATH_MP_DB : _PATH_SMP_DB;
1011 _pw_db = dbopen(p, O_RDONLY, 0, DB_HASH, NULL);
1012 if (_pw_db)
1013 return 1;
1014 if (!warned)
1015 syslog(LOG_ERR, "%s: %m", p);
1016 warned = 1;
1017 return 0;
1018 }
1019
1020 static int
1021 __hashpw(key)
1022 DBT *key;
1023 {
1024 char *p, *t;
1025 static u_int max;
1026 static char *line;
1027 DBT data;
1028
1029 switch ((_pw_db->get)(_pw_db, key, &data, 0)) {
1030 case 0:
1031 break; /* found */
1032 case 1:
1033 return NS_NOTFOUND;
1034 case -1:
1035 return NS_UNAVAIL; /* error in db routines */
1036 default:
1037 abort();
1038 }
1039
1040 p = (char *)data.data;
1041 if (data.size > max && !(line = realloc(line, (max += 1024))))
1042 return NS_UNAVAIL;
1043
1044 t = line;
1045 #define EXPAND(e) e = t; while ((*t++ = *p++));
1046 EXPAND(_pw_passwd.pw_name);
1047 EXPAND(_pw_passwd.pw_passwd);
1048 memmove((char *)&_pw_passwd.pw_uid, p, sizeof(int));
1049 p += sizeof(int);
1050 memmove((char *)&_pw_passwd.pw_gid, p, sizeof(int));
1051 p += sizeof(int);
1052 memmove((char *)&_pw_passwd.pw_change, p, sizeof(time_t));
1053 p += sizeof(time_t);
1054 EXPAND(_pw_passwd.pw_class);
1055 EXPAND(_pw_passwd.pw_gecos);
1056 EXPAND(_pw_passwd.pw_dir);
1057 EXPAND(_pw_passwd.pw_shell);
1058 memmove((char *)&_pw_passwd.pw_expire, p, sizeof(time_t));
1059 p += sizeof(time_t);
1060
1061 /* See if there's any data left. If so, read in flags. */
1062 if (data.size > (p - (char *)data.data)) {
1063 memmove((char *)&_pw_flags, p, sizeof(int));
1064 p += sizeof(int);
1065 } else
1066 _pw_flags = _PASSWORD_NOUID|_PASSWORD_NOGID; /* default */
1067
1068 return NS_SUCCESS;
1069 }
1070