getpwent.c revision 1.30 1 /* $NetBSD: getpwent.c,v 1.30 1998/11/12 16:38:49 christos 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.30 1998/11/12 16:38:49 christos 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 #ifdef YP
60 #include <machine/param.h>
61 #include <stdio.h>
62 #include <rpc/rpc.h>
63 #include <rpcsvc/yp_prot.h>
64 #include <rpcsvc/ypclnt.h>
65 #endif
66
67 #include "pw_private.h"
68
69 #ifdef __weak_alias
70 __weak_alias(endpwent,_endpwent);
71 __weak_alias(getpwent,_getpwent);
72 __weak_alias(getpwnam,_getpwnam);
73 __weak_alias(getpwuid,_getpwuid);
74 __weak_alias(setpassent,_setpassent);
75 __weak_alias(setpwent,_setpwent);
76 #endif
77
78
79 /*
80 * The lookup techniques and data extraction code here must be kept
81 * in sync with that in `pwd_mkdb'.
82 */
83
84 static struct passwd _pw_passwd; /* password structure */
85 static DB *_pw_db; /* password database */
86 static int _pw_keynum; /* key counter */
87 static int _pw_stayopen; /* keep fd's open */
88 static int _pw_flags; /* password flags */
89 static int __hashpw __P((DBT *));
90 static int __initdb __P((void));
91
92 const char __yp_token[] = "__YP!"; /* Let pwd_mkdb pull this in. */
93
94 #ifdef YP
95 enum _ypmode { YPMODE_NONE, YPMODE_FULL, YPMODE_USER, YPMODE_NETGRP };
96 static enum _ypmode __ypmode;
97
98 enum _ypmap { YPMAP_NONE, YPMAP_ADJUNCT, YPMAP_MASTER };
99
100 static char *__ypcurrent, *__ypdomain;
101 static int __ypcurrentlen;
102 static struct passwd *__ypproto = (struct passwd *)NULL;
103 static int __ypflags;
104 static char line[1024];
105 static long prbuf[1024 / sizeof(long)];
106 static DB *__ypexclude = (DB *)NULL;
107
108 static int __has_yppw __P((void));
109 static int __ypexclude_add __P((const char *));
110 static int __ypexclude_is __P((const char *));
111 static int __ypmaptype __P((void));
112 static void __ypproto_set __P((void));
113 static int __ypparse __P((struct passwd *, char *));
114
115 /* macros for deciding which YP maps to use. */
116 #define PASSWD_BYNAME (__ypmaptype() == YPMAP_MASTER \
117 ? "master.passwd.byname" : "passwd.byname")
118 #define PASSWD_BYUID (__ypmaptype() == YPMAP_MASTER \
119 ? "master.passwd.byuid" : "passwd.byuid")
120
121 static int
122 __ypexclude_add(name)
123 const char *name;
124 {
125 DBT key;
126 DBT data;
127
128 /* initialize the exclusion table if needed. */
129 if(__ypexclude == (DB *)NULL) {
130 __ypexclude = dbopen(NULL, O_RDWR, 600, DB_HASH, NULL);
131 if(__ypexclude == (DB *)NULL)
132 return(1);
133 }
134
135 /* set up the key */
136 key.size = strlen(name);
137 /* LINTED key does not get modified */
138 key.data = (char *)name;
139
140 /* data is nothing. */
141 data.data = NULL;
142 data.size = 0;
143
144 /* store it */
145 if((__ypexclude->put)(__ypexclude, &key, &data, 0) == -1)
146 return(1);
147
148 return(0);
149 }
150
151 static int
152 __ypexclude_is(name)
153 const char *name;
154 {
155 const DBT key;
156 DBT data;
157
158 if(__ypexclude == (DB *)NULL)
159 return(0); /* nothing excluded */
160
161 /* set up the key */
162 key.size = strlen(name);
163 /* LINTED key does not get modified */
164 key.data = (char *)name;
165
166 if((__ypexclude->get)(__ypexclude, &key, &data, 0) == 0)
167 return(1); /* excluded */
168
169 return(0);
170 }
171
172 static void
173 __ypproto_set()
174 {
175 char *ptr;
176 struct passwd *pw = &_pw_passwd;
177
178 /* make this the new prototype */
179 ptr = (char *)(void *)prbuf;
180
181 /* first allocate the struct. */
182 __ypproto = (struct passwd *)(void *)ptr;
183 ptr += sizeof(struct passwd);
184
185 /* name */
186 if(pw->pw_name && (pw->pw_name)[0]) {
187 ptr = (char *)ALIGN((u_long)ptr);
188 memmove(ptr, pw->pw_name, strlen(pw->pw_name) + 1);
189 __ypproto->pw_name = ptr;
190 ptr += (strlen(pw->pw_name) + 1);
191 } else
192 __ypproto->pw_name = (char *)NULL;
193
194 /* password */
195 if(pw->pw_passwd && (pw->pw_passwd)[0]) {
196 ptr = (char *)ALIGN((u_long)ptr);
197 memmove(ptr, pw->pw_passwd, strlen(pw->pw_passwd) + 1);
198 __ypproto->pw_passwd = ptr;
199 ptr += (strlen(pw->pw_passwd) + 1);
200 } else
201 __ypproto->pw_passwd = (char *)NULL;
202
203 /* uid */
204 __ypproto->pw_uid = pw->pw_uid;
205
206 /* gid */
207 __ypproto->pw_gid = pw->pw_gid;
208
209 /* change (ignored anyway) */
210 __ypproto->pw_change = pw->pw_change;
211
212 /* class (ignored anyway) */
213 __ypproto->pw_class = "";
214
215 /* gecos */
216 if(pw->pw_gecos && (pw->pw_gecos)[0]) {
217 ptr = (char *)ALIGN((u_long)ptr);
218 memmove(ptr, pw->pw_gecos, strlen(pw->pw_gecos) + 1);
219 __ypproto->pw_gecos = ptr;
220 ptr += (strlen(pw->pw_gecos) + 1);
221 } else
222 __ypproto->pw_gecos = (char *)NULL;
223
224 /* dir */
225 if(pw->pw_dir && (pw->pw_dir)[0]) {
226 ptr = (char *)ALIGN((u_long)ptr);
227 memmove(ptr, pw->pw_dir, strlen(pw->pw_dir) + 1);
228 __ypproto->pw_dir = ptr;
229 ptr += (strlen(pw->pw_dir) + 1);
230 } else
231 __ypproto->pw_dir = (char *)NULL;
232
233 /* shell */
234 if(pw->pw_shell && (pw->pw_shell)[0]) {
235 ptr = (char *)ALIGN((u_long)ptr);
236 memmove(ptr, pw->pw_shell, strlen(pw->pw_shell) + 1);
237 __ypproto->pw_shell = ptr;
238 ptr += (strlen(pw->pw_shell) + 1);
239 } else
240 __ypproto->pw_shell = (char *)NULL;
241
242 /* expire (ignored anyway) */
243 __ypproto->pw_expire = pw->pw_expire;
244
245 /* flags */
246 __ypflags = _pw_flags;
247 }
248
249 static int
250 __ypmaptype()
251 {
252 static int maptype = -1;
253 int order, r;
254
255 if (maptype != -1)
256 return (maptype);
257
258 maptype = YPMAP_NONE;
259 if (geteuid() != 0)
260 return (maptype);
261
262 if (!__ypdomain) {
263 if( _yp_check(&__ypdomain) == 0)
264 return (maptype);
265 }
266
267 r = yp_order(__ypdomain, "master.passwd.byname", &order);
268 if (r == 0) {
269 maptype = YPMAP_MASTER;
270 return (maptype);
271 }
272
273 /*
274 * NIS+ in YP compat mode doesn't support
275 * YPPROC_ORDER -- no point in continuing.
276 */
277 if (r == YPERR_YPERR)
278 return (maptype);
279
280 /* master.passwd doesn't exist -- try passwd.adjunct */
281 if (r == YPERR_MAP) {
282 r = yp_order(__ypdomain, "passwd.adjunct.byname", &order);
283 if (r == 0)
284 maptype = YPMAP_ADJUNCT;
285 return (maptype);
286 }
287
288 return (maptype);
289 }
290
291 static int
292 __ypparse(pw, s)
293 struct passwd *pw;
294 char *s;
295 {
296 static char adjunctpw[YPMAXRECORD + 2];
297 int flags, maptype;
298
299 maptype = __ypmaptype();
300 flags = _PASSWORD_NOWARN;
301 if (maptype != YPMAP_MASTER)
302 flags |= _PASSWORD_OLDFMT;
303 if (! __pw_scan(s, pw, &flags))
304 return 1;
305
306 /* now let the prototype override, if set. */
307 if(__ypproto != (struct passwd *)NULL) {
308 #ifdef YP_OVERRIDE_PASSWD
309 if(__ypproto->pw_passwd != (char *)NULL)
310 pw->pw_passwd = __ypproto->pw_passwd;
311 #endif
312 if(!(__ypflags & _PASSWORD_NOUID))
313 pw->pw_uid = __ypproto->pw_uid;
314 if(!(__ypflags & _PASSWORD_NOGID))
315 pw->pw_gid = __ypproto->pw_gid;
316 if(__ypproto->pw_gecos != (char *)NULL)
317 pw->pw_gecos = __ypproto->pw_gecos;
318 if(__ypproto->pw_dir != (char *)NULL)
319 pw->pw_dir = __ypproto->pw_dir;
320 if(__ypproto->pw_shell != (char *)NULL)
321 pw->pw_shell = __ypproto->pw_shell;
322 }
323 if ((maptype == YPMAP_ADJUNCT) &&
324 (strstr(pw->pw_passwd, "##") != NULL)) {
325 char *data, *bp;
326 int datalen;
327
328 if (yp_match(__ypdomain, "passwd.adjunct.byname", pw->pw_name,
329 (int)strlen(pw->pw_name), &data, &datalen) == 0) {
330 if (datalen > sizeof(adjunctpw) - 1)
331 datalen = sizeof(adjunctpw) - 1;
332 strncpy(adjunctpw, data, (size_t)datalen);
333
334 /* skip name to get password */
335 if ((bp = strsep(&data, ":")) != NULL &&
336 (bp = strsep(&data, ":")) != NULL)
337 pw->pw_passwd = bp;
338 }
339 }
340 return 0;
341 }
342 #endif
343
344 struct passwd *
345 getpwent()
346 {
347 DBT dbt;
348 char bf[sizeof(_pw_keynum) + 1];
349 #ifdef YP
350 static char *name = (char *)NULL;
351 const char *user, *host, *dom;
352 int has_yppw;
353 #endif
354
355 if (!_pw_db && !__initdb())
356 return((struct passwd *)NULL);
357
358 #ifdef YP
359 has_yppw = __has_yppw();
360
361 again:
362 if(has_yppw && (__ypmode != YPMODE_NONE)) {
363 char *key, *data;
364 int keylen, datalen;
365 int r, s;
366
367 if(!__ypdomain) {
368 if( _yp_check(&__ypdomain) == 0) {
369 __ypmode = YPMODE_NONE;
370 goto again;
371 }
372 }
373 switch(__ypmode) {
374 case YPMODE_FULL:
375 data = NULL;
376 if(__ypcurrent) {
377 key = NULL;
378 r = yp_next(__ypdomain, PASSWD_BYNAME,
379 __ypcurrent, __ypcurrentlen,
380 &key, &keylen, &data, &datalen);
381 free(__ypcurrent);
382 if(r != 0) {
383 __ypcurrent = NULL;
384 if (key)
385 free(key);
386 }
387 else {
388 __ypcurrent = key;
389 __ypcurrentlen = keylen;
390 }
391 } else {
392 r = yp_first(__ypdomain, PASSWD_BYNAME,
393 &__ypcurrent, &__ypcurrentlen,
394 &data, &datalen);
395 }
396 if(r != 0) {
397 __ypmode = YPMODE_NONE;
398 if(data)
399 free(data);
400 data = NULL;
401 goto again;
402 }
403 memmove(line, data, (size_t)datalen);
404 free(data);
405 data = NULL;
406 break;
407 case YPMODE_NETGRP:
408 s = getnetgrent(&host, &user, &dom);
409 if(s == 0) { /* end of group */
410 endnetgrent();
411 __ypmode = YPMODE_NONE;
412 goto again;
413 }
414 if(user && *user) {
415 data = NULL;
416 r = yp_match(__ypdomain, PASSWD_BYNAME,
417 user, (int)strlen(user),
418 &data, &datalen);
419 } else
420 goto again;
421 if(r != 0) {
422 /*
423 * if the netgroup is invalid, keep looking
424 * as there may be valid users later on.
425 */
426 if(data)
427 free(data);
428 goto again;
429 }
430 memmove(line, data, (size_t)datalen);
431 free(data);
432 data = NULL;
433 break;
434 case YPMODE_USER:
435 if(name != (char *)NULL) {
436 data = NULL;
437 r = yp_match(__ypdomain, PASSWD_BYNAME,
438 name, (int)strlen(name),
439 &data, &datalen);
440 __ypmode = YPMODE_NONE;
441 free(name);
442 name = NULL;
443 if(r != 0) {
444 if(data)
445 free(data);
446 goto again;
447 }
448 memmove(line, data, (size_t)datalen);
449 free(data);
450 data = (char *)NULL;
451 } else { /* XXX */
452 __ypmode = YPMODE_NONE;
453 goto again;
454 }
455 break;
456 case YPMODE_NONE:
457 abort(); /* cannot happen */
458 break;
459 }
460
461 line[datalen] = '\0';
462 if (__ypparse(&_pw_passwd, line))
463 goto again;
464 return &_pw_passwd;
465 }
466 #endif
467
468 ++_pw_keynum;
469 bf[0] = _PW_KEYBYNUM;
470 memmove(bf + 1, &_pw_keynum, sizeof(_pw_keynum));
471 dbt.data = (u_char *)bf;
472 dbt.size = sizeof(_pw_keynum) + 1;
473 if(__hashpw(&dbt)) {
474 #ifdef YP
475 /* if we don't have YP at all, don't bother. */
476 if(has_yppw) {
477 if(_pw_passwd.pw_name[0] == '+') {
478 /* set the mode */
479 switch(_pw_passwd.pw_name[1]) {
480 case '\0':
481 __ypmode = YPMODE_FULL;
482 break;
483 case '@':
484 __ypmode = YPMODE_NETGRP;
485 setnetgrent(_pw_passwd.pw_name + 2);
486 break;
487 default:
488 __ypmode = YPMODE_USER;
489 name = strdup(_pw_passwd.pw_name + 1);
490 break;
491 }
492
493 /* save the prototype */
494 __ypproto_set();
495 goto again;
496 } else if(_pw_passwd.pw_name[0] == '-') {
497 /* an attempted exclusion */
498 switch(_pw_passwd.pw_name[1]) {
499 case '\0':
500 break;
501 case '@':
502 setnetgrent(_pw_passwd.pw_name + 2);
503 while(getnetgrent(&host, &user, &dom)) {
504 if(user && *user)
505 __ypexclude_add(user);
506 }
507 endnetgrent();
508 break;
509 default:
510 __ypexclude_add(_pw_passwd.pw_name + 1);
511 break;
512 }
513 goto again;
514 }
515 }
516 #endif
517 return &_pw_passwd;
518 }
519 return (struct passwd *)NULL;
520 }
521
522 #ifdef YP
523
524 /*
525 * See if the YP token is in the database. Only works if pwd_mkdb knows
526 * about the token.
527 */
528 static int
529 __has_yppw()
530 {
531 DBT key, data;
532 DBT pkey, pdata;
533 char bf[MAXLOGNAME];
534
535 key.size = strlen(__yp_token);
536 /* LINTED key does not get modified */
537 key.data = (u_char *)__yp_token;
538
539 /* Pre-token database support. */
540 bf[0] = _PW_KEYBYNAME;
541 bf[1] = '+';
542 pkey.data = (u_char *)bf;
543 pkey.size = 2;
544
545 if ((_pw_db->get)(_pw_db, &key, &data, 0)
546 && (_pw_db->get)(_pw_db, &pkey, &pdata, 0))
547 return(0); /* No YP. */
548 return(1);
549 }
550 #endif
551
552 struct passwd *
553 getpwnam(name)
554 const char *name;
555 {
556 DBT key;
557 int len, rval;
558 char bf[MAXLOGNAME + 1];
559
560 if (!_pw_db && !__initdb())
561 return((struct passwd *)NULL);
562
563 #ifdef YP
564 /*
565 * If YP is active, we must sequence through the passwd file
566 * in sequence.
567 */
568 if (__has_yppw()) {
569 int r;
570 int s = -1;
571 const char *host, *user, *dom;
572
573 for(_pw_keynum=1; _pw_keynum; _pw_keynum++) {
574 bf[0] = _PW_KEYBYNUM;
575 memmove(bf + 1, &_pw_keynum, sizeof(_pw_keynum));
576 key.data = (u_char *)bf;
577 key.size = sizeof(_pw_keynum) + 1;
578 if(__hashpw(&key) == 0)
579 break;
580 switch(_pw_passwd.pw_name[0]) {
581 case '+':
582 if(!__ypdomain) {
583 if(_yp_check(&__ypdomain) == 0) {
584 continue;
585 }
586 }
587 /* save the prototype */
588 __ypproto_set();
589
590 switch(_pw_passwd.pw_name[1]) {
591 case '\0':
592 if(__ypcurrent) {
593 free(__ypcurrent);
594 __ypcurrent = NULL;
595 }
596 r = yp_match(__ypdomain,
597 PASSWD_BYNAME,
598 name, (int)strlen(name),
599 &__ypcurrent, &__ypcurrentlen);
600 if(r != 0) {
601 if(__ypcurrent)
602 free(__ypcurrent);
603 __ypcurrent = NULL;
604 continue;
605 }
606 break;
607 case '@':
608 pwnam_netgrp:
609 if(__ypcurrent) {
610 free(__ypcurrent);
611 __ypcurrent = NULL;
612 }
613 if(s == -1) /* first time */
614 setnetgrent(_pw_passwd.pw_name + 2);
615 s = getnetgrent(&host, &user, &dom);
616 if(s == 0) { /* end of group */
617 endnetgrent();
618 s = -1;
619 continue;
620 } else {
621 if(user && *user) {
622 r = yp_match(__ypdomain,
623 PASSWD_BYNAME,
624 user,
625 (int)strlen(user),
626 &__ypcurrent,
627 &__ypcurrentlen);
628 } else
629 goto pwnam_netgrp;
630 if(r != 0) {
631 if(__ypcurrent)
632 free(__ypcurrent);
633 __ypcurrent = NULL;
634 /*
635 * just because this
636 * user is bad, doesn't
637 * mean they all are.
638 */
639 goto pwnam_netgrp;
640 }
641 }
642 break;
643 default:
644 if(__ypcurrent) {
645 free(__ypcurrent);
646 __ypcurrent = NULL;
647 }
648 user = _pw_passwd.pw_name + 1;
649 r = yp_match(__ypdomain,
650 PASSWD_BYNAME,
651 user, (int)strlen(user),
652 &__ypcurrent,
653 &__ypcurrentlen);
654 if(r != 0) {
655 if(__ypcurrent)
656 free(__ypcurrent);
657 __ypcurrent = NULL;
658 continue;
659 }
660 break;
661 }
662 memmove(line, __ypcurrent,
663 (size_t)__ypcurrentlen);
664 line[__ypcurrentlen] = '\0';
665 if(__ypparse(&_pw_passwd, line)
666 || __ypexclude_is(_pw_passwd.pw_name)) {
667 if(s == 1) /* inside netgrp */
668 goto pwnam_netgrp;
669 continue;
670 }
671 break;
672 case '-':
673 /* attempted exclusion */
674 switch(_pw_passwd.pw_name[1]) {
675 case '\0':
676 break;
677 case '@':
678 setnetgrent(_pw_passwd.pw_name + 2);
679 while(getnetgrent(&host, &user, &dom)) {
680 if(user && *user)
681 __ypexclude_add(user);
682 }
683 endnetgrent();
684 break;
685 default:
686 __ypexclude_add(_pw_passwd.pw_name + 1);
687 break;
688 }
689 break;
690 }
691 if(strcmp(_pw_passwd.pw_name, name) == 0) {
692 if (!_pw_stayopen) {
693 (void)(_pw_db->close)(_pw_db);
694 _pw_db = (DB *)NULL;
695 }
696 if(__ypexclude != (DB *)NULL) {
697 (void)(__ypexclude->close)(__ypexclude);
698 __ypexclude = (DB *)NULL;
699 }
700 __ypproto = (struct passwd *)NULL;
701 return &_pw_passwd;
702 }
703 if(s == 1) /* inside netgrp */
704 goto pwnam_netgrp;
705 continue;
706 }
707 if (!_pw_stayopen) {
708 (void)(_pw_db->close)(_pw_db);
709 _pw_db = (DB *)NULL;
710 }
711 if(__ypexclude != (DB *)NULL) {
712 (void)(__ypexclude->close)(__ypexclude);
713 __ypexclude = (DB *)NULL;
714 }
715 __ypproto = (struct passwd *)NULL;
716 return (struct passwd *)NULL;
717 }
718 #endif /* YP */
719
720 bf[0] = _PW_KEYBYNAME;
721 len = strlen(name);
722 len = MIN(len, MAXLOGNAME);
723 memmove(bf + 1, name, (size_t)len);
724 key.data = (u_char *)bf;
725 key.size = len + 1;
726 rval = __hashpw(&key);
727
728 if (!_pw_stayopen) {
729 (void)(_pw_db->close)(_pw_db);
730 _pw_db = (DB *)NULL;
731 }
732 return(rval ? &_pw_passwd : (struct passwd *)NULL);
733 }
734
735 struct passwd *
736 getpwuid(uid)
737 uid_t uid;
738 {
739 DBT key;
740 char bf[sizeof(_pw_keynum) + 1];
741 uid_t keyuid;
742 int rval;
743
744 if (!_pw_db && !__initdb())
745 return((struct passwd *)NULL);
746
747 #ifdef YP
748 /*
749 * If YP is active, we must sequence through the passwd file
750 * in sequence.
751 */
752 if (__has_yppw()) {
753 char uidbuf[20];
754 int r;
755 int s = -1;
756 const char *host, *user, *dom;
757
758 snprintf(uidbuf, sizeof(uidbuf), "%u", uid);
759 for(_pw_keynum=1; _pw_keynum; _pw_keynum++) {
760 bf[0] = _PW_KEYBYNUM;
761 memmove(bf + 1, &_pw_keynum, sizeof(_pw_keynum));
762 key.data = (u_char *)bf;
763 key.size = sizeof(_pw_keynum) + 1;
764 if(__hashpw(&key) == 0)
765 break;
766 switch(_pw_passwd.pw_name[0]) {
767 case '+':
768 if(!__ypdomain) {
769 if(_yp_check(&__ypdomain) == 0) {
770 continue;
771 }
772 }
773 /* save the prototype */
774 __ypproto_set();
775
776 switch(_pw_passwd.pw_name[1]) {
777 case '\0':
778 if(__ypcurrent) {
779 free(__ypcurrent);
780 __ypcurrent = NULL;
781 }
782 r = yp_match(__ypdomain, PASSWD_BYUID,
783 uidbuf, (int)strlen(uidbuf),
784 &__ypcurrent, &__ypcurrentlen);
785 if(r != 0) {
786 if(__ypcurrent)
787 free(__ypcurrent);
788 __ypcurrent = NULL;
789 continue;
790 }
791 break;
792 case '@':
793 pwuid_netgrp:
794 if(__ypcurrent) {
795 free(__ypcurrent);
796 __ypcurrent = NULL;
797 }
798 if(s == -1) /* first time */
799 setnetgrent(_pw_passwd.pw_name + 2);
800 s = getnetgrent(&host, &user, &dom);
801 if(s == 0) { /* end of group */
802 endnetgrent();
803 s = -1;
804 continue;
805 } else {
806 if(user && *user) {
807 r = yp_match(__ypdomain,
808 PASSWD_BYNAME,
809 user,
810 (int)strlen(user),
811 &__ypcurrent,
812 &__ypcurrentlen);
813 } else
814 goto pwuid_netgrp;
815 if(r != 0) {
816 if(__ypcurrent)
817 free(__ypcurrent);
818 __ypcurrent = NULL;
819 /*
820 * just because this
821 * user is bad, doesn't
822 * mean they all are.
823 */
824 goto pwuid_netgrp;
825 }
826 }
827 break;
828 default:
829 if(__ypcurrent) {
830 free(__ypcurrent);
831 __ypcurrent = NULL;
832 }
833 user = _pw_passwd.pw_name + 1;
834 r = yp_match(__ypdomain,
835 PASSWD_BYNAME,
836 user, (int)strlen(user),
837 &__ypcurrent,
838 &__ypcurrentlen);
839 if(r != 0) {
840 if(__ypcurrent)
841 free(__ypcurrent);
842 __ypcurrent = NULL;
843 continue;
844 }
845 break;
846 }
847 memmove(line, __ypcurrent,
848 (size_t)__ypcurrentlen);
849 line[__ypcurrentlen] = '\0';
850 if(__ypparse(&_pw_passwd, line)
851 || __ypexclude_is(_pw_passwd.pw_name)) {
852 if(s == 1) /* inside netgroup */
853 goto pwuid_netgrp;
854 continue;
855 }
856 break;
857 case '-':
858 /* attempted exclusion */
859 switch(_pw_passwd.pw_name[1]) {
860 case '\0':
861 break;
862 case '@':
863 setnetgrent(_pw_passwd.pw_name + 2);
864 while(getnetgrent(&host, &user, &dom)) {
865 if(user && *user)
866 __ypexclude_add(user);
867 }
868 endnetgrent();
869 break;
870 default:
871 __ypexclude_add(_pw_passwd.pw_name + 1);
872 break;
873 }
874 break;
875 }
876 if( _pw_passwd.pw_uid == uid) {
877 if (!_pw_stayopen) {
878 (void)(_pw_db->close)(_pw_db);
879 _pw_db = (DB *)NULL;
880 }
881 if (__ypexclude != (DB *)NULL) {
882 (void)(__ypexclude->close)(__ypexclude);
883 __ypexclude = (DB *)NULL;
884 }
885 __ypproto = NULL;
886 return &_pw_passwd;
887 }
888 if(s == 1) /* inside netgroup */
889 goto pwuid_netgrp;
890 continue;
891 }
892 if (!_pw_stayopen) {
893 (void)(_pw_db->close)(_pw_db);
894 _pw_db = (DB *)NULL;
895 }
896 if(__ypexclude != (DB *)NULL) {
897 (void)(__ypexclude->close)(__ypexclude);
898 __ypexclude = (DB *)NULL;
899 }
900 __ypproto = (struct passwd *)NULL;
901 return (struct passwd *)NULL;
902 }
903 #endif /* YP */
904
905 bf[0] = _PW_KEYBYUID;
906 keyuid = uid;
907 memmove(bf + 1, &keyuid, sizeof(keyuid));
908 key.data = (u_char *)bf;
909 key.size = sizeof(keyuid) + 1;
910 rval = __hashpw(&key);
911
912 if (!_pw_stayopen) {
913 (void)(_pw_db->close)(_pw_db);
914 _pw_db = (DB *)NULL;
915 }
916 return(rval ? &_pw_passwd : (struct passwd *)NULL);
917 }
918
919 int
920 setpassent(stayopen)
921 int stayopen;
922 {
923 _pw_keynum = 0;
924 _pw_stayopen = stayopen;
925 #ifdef YP
926 __ypmode = YPMODE_NONE;
927 if(__ypcurrent)
928 free(__ypcurrent);
929 __ypcurrent = NULL;
930 if(__ypexclude != (DB *)NULL) {
931 (void)(__ypexclude->close)(__ypexclude);
932 __ypexclude = (DB *)NULL;
933 }
934 __ypproto = (struct passwd *)NULL;
935 #endif
936 return(1);
937 }
938
939 void
940 setpwent()
941 {
942 (void) setpassent(0);
943 }
944
945 void
946 endpwent()
947 {
948 _pw_keynum = 0;
949 if (_pw_db) {
950 (void)(_pw_db->close)(_pw_db);
951 _pw_db = (DB *)NULL;
952 }
953 #ifdef YP
954 __ypmode = YPMODE_NONE;
955 if(__ypcurrent)
956 free(__ypcurrent);
957 __ypcurrent = NULL;
958 if(__ypexclude != (DB *)NULL) {
959 (void)(__ypexclude->close)(__ypexclude);
960 __ypexclude = (DB *)NULL;
961 }
962 __ypproto = (struct passwd *)NULL;
963 #endif
964 }
965
966 static int
967 __initdb()
968 {
969 static int warned;
970 char *p;
971
972 #ifdef YP
973 __ypmode = YPMODE_NONE;
974 #endif
975 if (geteuid() == 0) {
976 _pw_db = dbopen((p = _PATH_SMP_DB), O_RDONLY, 0, DB_HASH, NULL);
977 if (_pw_db)
978 return(1);
979 }
980 _pw_db = dbopen((p = _PATH_MP_DB), O_RDONLY, 0, DB_HASH, NULL);
981 if (_pw_db)
982 return(1);
983 if (!warned)
984 syslog(LOG_ERR, "%s: %m", p);
985 warned = 1;
986 return(0);
987 }
988
989 static int
990 __hashpw(key)
991 DBT *key;
992 {
993 char *p, *t;
994 static u_int max;
995 static char *buf;
996 DBT data;
997
998 if ((_pw_db->get)(_pw_db, key, &data, 0))
999 return(0);
1000 p = (char *)data.data;
1001 if (data.size > max && !(buf = realloc(buf, (max += 1024))))
1002 return(0);
1003
1004 /* THIS CODE MUST MATCH THAT IN pwd_mkdb. */
1005 t = buf;
1006 #define EXPAND(e) e = t; while ((*t++ = *p++));
1007 #define SCALAR(v) memmove(&(v), p, sizeof v); p += sizeof v
1008 EXPAND(_pw_passwd.pw_name);
1009 EXPAND(_pw_passwd.pw_passwd);
1010 SCALAR(_pw_passwd.pw_uid);
1011 SCALAR(_pw_passwd.pw_gid);
1012 SCALAR(_pw_passwd.pw_change);
1013 EXPAND(_pw_passwd.pw_class);
1014 EXPAND(_pw_passwd.pw_gecos);
1015 EXPAND(_pw_passwd.pw_dir);
1016 EXPAND(_pw_passwd.pw_shell);
1017 SCALAR(_pw_passwd.pw_expire);
1018
1019 /* See if there's any data left. If so, read in flags. */
1020 if (data.size > (p - (char *)data.data)) {
1021 SCALAR(_pw_flags);
1022 } else
1023 _pw_flags = _PASSWORD_NOUID|_PASSWORD_NOGID; /* default */
1024
1025 return(1);
1026 }
1027