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