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