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