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