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