Remove _THREAD_SAFE depenendancies. Create weakly associated stubs for
[dragonfly.git] / lib / libc / gen / getpwent.c
1 /*
2  * Copyright (c) 1988, 1993
3  *      The Regents of the University of California.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *      This product includes software developed by the University of
16  *      California, Berkeley and its contributors.
17  * 4. Neither the name of the University nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  *
33  * @(#)getpwent.c       8.2 (Berkeley) 4/27/95
34  * $FreeBSD: src/lib/libc/gen/getpwent.c,v 1.53.2.2 2001/03/05 09:52:13 obrien Exp $
35  * $DragonFly: src/lib/libc/gen/getpwent.c,v 1.5 2005/01/31 22:29:15 dillon Exp $
36  */
37
38 #include "namespace.h"
39 #include <stdio.h>
40 #include <sys/param.h>
41 #include <fcntl.h>
42 #include <syslog.h>
43 #include <pwd.h>
44 #include <utmp.h>
45 #include <errno.h>
46 #include <unistd.h>
47 #include <stdlib.h>
48 #include <string.h>
49 #include <limits.h>
50 #include <grp.h>
51 #include "un-namespace.h"
52
53 #include <db.h>
54
55 extern void setnetgrent ( char * );
56 extern int getnetgrent ( char **, char **, char ** );
57 extern int innetgr ( const char *, const char *, const char *, const char * );
58
59 /*
60  * The lookup techniques and data extraction code here must be kept
61  * in sync with that in `pwd_mkdb'.
62  */
63
64 static struct passwd _pw_passwd;        /* password structure */
65 static DB *_pw_db;                      /* password database */
66 static int _pw_keynum;                  /* key counter */
67 static int _pw_stayopen;                /* keep fd's open */
68 #ifdef YP
69 #include <rpc/rpc.h>
70 #include <rpcsvc/yp_prot.h>
71 #include <rpcsvc/ypclnt.h>
72
73 static struct passwd _pw_copy;
74 static DBT empty = { NULL, 0 };
75 static DB *_ypcache = (DB *)NULL;
76 static int _yp_exclusions = 0;
77 static int _yp_enabled = -1;
78 static int _pw_stepping_yp;             /* set true when stepping thru map */
79 static char _ypnam[YPMAXRECORD];
80 #define YP_HAVE_MASTER 2
81 #define YP_HAVE_ADJUNCT 1
82 #define YP_HAVE_NONE 0
83 static int _gotmaster;
84 static char *_pw_yp_domain;
85 static inline int unwind ( char * );
86 static void _ypinitdb ( void );
87 static int _havemaster (char *);
88 static int _getyppass (struct passwd *, const char *, const char * );
89 static int _nextyppass (struct passwd *);
90 static inline int lookup (const char *);
91 static inline void store (const char *);
92 static inline int ingr (const char *, const char*);
93 static inline int verf (const char *);
94 static char * _get_adjunct_pw (const char *);
95 #endif
96 static int __hashpw(DBT *);
97 static int __initdb(void);
98
99 struct passwd *
100 getpwent()
101 {
102         DBT key;
103         char bf[sizeof(_pw_keynum) + 1];
104         int rv;
105
106         if (!_pw_db && !__initdb())
107                 return((struct passwd *)NULL);
108
109 #ifdef YP
110         if(_pw_stepping_yp) {
111                 _pw_passwd = _pw_copy;
112                 if (unwind((char *)&_ypnam))
113                         return(&_pw_passwd);
114         }
115 #endif
116 tryagain:
117
118         ++_pw_keynum;
119         bf[0] = _PW_KEYBYNUM;
120         bcopy((char *)&_pw_keynum, bf + 1, sizeof(_pw_keynum));
121         key.data = (u_char *)bf;
122         key.size = sizeof(_pw_keynum) + 1;
123         rv = __hashpw(&key);
124         if(!rv) return (struct passwd *)NULL;
125 #ifdef YP
126         if(_pw_passwd.pw_name[0] == '+' || _pw_passwd.pw_name[0] == '-') {
127                 if (_yp_enabled == -1)
128                         _ypinitdb();
129                 bzero((char *)&_ypnam, sizeof(_ypnam));
130                 bcopy(_pw_passwd.pw_name, _ypnam,
131                         strlen(_pw_passwd.pw_name));
132                 _pw_copy = _pw_passwd;
133                 if (unwind((char *)&_ypnam) == 0)
134                         goto tryagain;
135                 else
136                         return(&_pw_passwd);
137         }
138 #else
139         /* Ignore YP password file entries when YP is disabled. */
140         if(_pw_passwd.pw_name[0] == '+' || _pw_passwd.pw_name[0] == '-') {
141                 goto tryagain;
142         }
143 #endif
144         return(&_pw_passwd);
145 }
146
147 struct passwd *
148 getpwnam(name)
149         const char *name;
150 {
151         DBT key;
152         int len, rval;
153         char bf[UT_NAMESIZE + 2];
154
155         if (!_pw_db && !__initdb())
156                 return((struct passwd *)NULL);
157
158         bf[0] = _PW_KEYBYNAME;
159         len = strlen(name);
160         if (len > UT_NAMESIZE)
161                 return(NULL);
162         bcopy(name, bf + 1, len);
163         key.data = (u_char *)bf;
164         key.size = len + 1;
165         rval = __hashpw(&key);
166
167 #ifdef YP
168         if (!rval) {
169                 if (_yp_enabled == -1)
170                         _ypinitdb();
171                 if (_yp_enabled)
172                         rval = _getyppass(&_pw_passwd, name, "passwd.byname");
173         }
174 #endif
175         /*
176          * Prevent login attempts when YP is not enabled but YP entries
177          * are in /etc/master.passwd.
178          */
179         if (rval && (_pw_passwd.pw_name[0] == '+'||
180                         _pw_passwd.pw_name[0] == '-')) rval = 0;
181
182         if (!_pw_stayopen)
183                 endpwent();
184         return(rval ? &_pw_passwd : (struct passwd *)NULL);
185 }
186
187 struct passwd *
188 getpwuid(uid)
189         uid_t uid;
190 {
191         DBT key;
192         int keyuid, rval;
193         char bf[sizeof(keyuid) + 1];
194
195         if (!_pw_db && !__initdb())
196                 return((struct passwd *)NULL);
197
198         bf[0] = _PW_KEYBYUID;
199         keyuid = uid;
200         bcopy(&keyuid, bf + 1, sizeof(keyuid));
201         key.data = (u_char *)bf;
202         key.size = sizeof(keyuid) + 1;
203         rval = __hashpw(&key);
204
205 #ifdef YP
206         if (!rval) {
207                 if (_yp_enabled == -1)
208                         _ypinitdb();
209                 if (_yp_enabled) {
210                         char ypbuf[16]; /* big enough for 32-bit uids */
211                         snprintf(ypbuf, sizeof ypbuf, "%u", (unsigned)uid);
212                         rval = _getyppass(&_pw_passwd, ypbuf, "passwd.byuid");
213                 }
214         }
215 #endif
216         /*
217          * Prevent login attempts when YP is not enabled but YP entries
218          * are in /etc/master.passwd.
219          */
220         if (rval && (_pw_passwd.pw_name[0] == '+'||
221                         _pw_passwd.pw_name[0] == '-')) rval = 0;
222
223         if (!_pw_stayopen)
224                 endpwent();
225         return(rval ? &_pw_passwd : (struct passwd *)NULL);
226 }
227
228 int
229 setpassent(stayopen)
230         int stayopen;
231 {
232         _pw_keynum = 0;
233 #ifdef YP
234         _pw_stepping_yp = 0;
235         if (stayopen)
236                 setgroupent(1);
237 #endif
238         _pw_stayopen = stayopen;
239         return(1);
240 }
241
242 void
243 setpwent()
244 {
245         (void)setpassent(0);
246 }
247
248 void
249 endpwent()
250 {
251         _pw_keynum = 0;
252 #ifdef YP
253         _pw_stepping_yp = 0;
254 #endif
255         if (_pw_db) {
256                 (void)(_pw_db->close)(_pw_db);
257                 _pw_db = (DB *)NULL;
258         }
259 #ifdef YP
260         if (_ypcache) {
261                 (void)(_ypcache->close)(_ypcache);
262                 _ypcache = (DB *)NULL;
263                 _yp_exclusions = 0;
264         }
265         /* Fix for PR #12008 */
266         _yp_enabled = -1;
267 #endif
268 }
269
270 static int
271 __initdb()
272 {
273         static int warned;
274         char *p;
275
276         p = (geteuid()) ? _PATH_MP_DB : _PATH_SMP_DB;
277         _pw_db = dbopen(p, O_RDONLY, 0, DB_HASH, NULL);
278         if (_pw_db)
279                 return(1);
280         if (!warned++)
281                 syslog(LOG_ERR, "%s: %m", p);
282         return(0);
283 }
284
285 static int
286 __hashpw(key)
287         DBT *key;
288 {
289         char *p, *t;
290         static u_int max;
291         static char *line;
292         DBT data;
293
294         if ((_pw_db->get)(_pw_db, key, &data, 0))
295                 return(0);
296         p = (char *)data.data;
297
298         /* Increase buffer size for long lines if necessary. */
299         if (data.size > max) {
300                 max = data.size + 1024;
301                 if (!(line = reallocf(line, max)))
302                         return(0);
303         }
304
305         /* THIS CODE MUST MATCH THAT IN pwd_mkdb. */
306         t = line;
307 #define EXPAND(e)       e = t; while ( (*t++ = *p++) );
308 #define SCALAR(v)       memmove(&(v), p, sizeof v); p += sizeof v
309         EXPAND(_pw_passwd.pw_name);
310         EXPAND(_pw_passwd.pw_passwd);
311         SCALAR(_pw_passwd.pw_uid);
312         SCALAR(_pw_passwd.pw_gid);
313         SCALAR(_pw_passwd.pw_change);
314         EXPAND(_pw_passwd.pw_class);
315         EXPAND(_pw_passwd.pw_gecos);
316         EXPAND(_pw_passwd.pw_dir);
317         EXPAND(_pw_passwd.pw_shell);
318         SCALAR(_pw_passwd.pw_expire);
319         bcopy(p, (char *)&_pw_passwd.pw_fields, sizeof _pw_passwd.pw_fields);
320         p += sizeof _pw_passwd.pw_fields;
321         return(1);
322 }
323
324 #ifdef YP
325
326 static void
327 _ypinitdb()
328 {
329         DBT key, data;
330         char buf[] = { _PW_KEYYPENABLED };
331         key.data = buf;
332         key.size = 1;
333         _yp_enabled = 0;
334         if ((_pw_db->get)(_pw_db, &key, &data, 0) == 0) {
335                 _yp_enabled = (int)*((char *)data.data) - 2;
336                 /* Don't even bother with this if we aren't root. */
337                 if (!geteuid()) {
338                         if (!_pw_yp_domain)
339                                 if (yp_get_default_domain(&_pw_yp_domain))
340                                         return;
341                         _gotmaster = _havemaster(_pw_yp_domain);
342                 } else _gotmaster = YP_HAVE_NONE;
343                 /*
344                  * Create a DB hash database in memory. Bet you didn't know you
345                  * could do a dbopen() with a NULL filename, did you.
346                  */
347                 if (_ypcache == (DB *)NULL)
348                         _ypcache = dbopen(NULL, O_RDWR, 600, DB_HASH, NULL);
349         }
350 }
351
352 /*
353  * See if a user is in the blackballed list.
354  */
355 static inline int
356 lookup(name)
357         const char *name;
358 {
359         DBT key;
360
361         if (!_yp_exclusions)
362                 return(0);
363
364         key.data = (char *)name;
365         key.size = strlen(name);
366
367         if ((_ypcache->get)(_ypcache, &key, &empty, 0)) {
368                 return(0);
369         }
370
371         return(1);
372 }
373
374 /*
375  * Store a blackballed user in an in-core hash database.
376  */
377 static inline void
378 store(key)
379         const char *key;
380 {
381         DBT lkey;
382 /*
383         if (lookup(key))
384                 return;
385 */
386
387         _yp_exclusions = 1;
388
389         lkey.data = (char *)key;
390         lkey.size = strlen(key);
391
392         (void)(_ypcache->put)(_ypcache, &lkey, &empty, R_NOOVERWRITE);
393 }
394
395 /*
396  * Parse the + entries in the password database and do appropriate
397  * NIS lookups. While ugly to look at, this is optimized to do only
398  * as many lookups as are absolutely necessary in any given case.
399  * Basically, the getpwent() function will feed us + and - lines
400  * as they appear in the database. For + lines, we do netgroup/group
401  * and user lookups to find all usernames that match the rule and
402  * extract them from the NIS passwd maps. For - lines, we save the
403  * matching names in a database and a) exlude them, and b) make sure
404  * we don't consider them when processing other + lines that appear
405  * later.
406  */
407 static inline int
408 unwind(grp)
409         char *grp;
410 {
411         char *user, *host, *domain;
412         static int latch = 0;
413         static struct group *gr = NULL;
414         int rv = 0;
415
416         if (grp[0] == '+') {
417                 if (strlen(grp) == 1) {
418                         return(_nextyppass(&_pw_passwd));
419                 }
420                 if (grp[1] == '@') {
421                         _pw_stepping_yp = 1;
422 grpagain:
423                         if (gr != NULL) {
424                                 if (*gr->gr_mem != NULL) {
425                                         if (lookup(*gr->gr_mem)) {
426                                                 gr->gr_mem++;
427                                                 goto grpagain;
428                                         }
429                                         rv = _getyppass(&_pw_passwd,
430                                                         *gr->gr_mem,
431                                                         "passwd.byname");
432                                         gr->gr_mem++;
433                                         return(rv);
434                                 } else {
435                                         latch = 0;
436                                         _pw_stepping_yp = 0;
437                                         gr = NULL;
438                                         return(0);
439                                 }
440                         }
441                         if (!latch) {
442                                 setnetgrent(grp+2);
443                                 latch++;
444                         }
445 again:
446                         if (getnetgrent(&host, &user, &domain) == 0) {
447                                 if ((gr = getgrnam(grp+2)) != NULL)
448                                         goto grpagain;
449                                 latch = 0;
450                                 _pw_stepping_yp = 0;
451                                 return(0);
452                         } else {
453                                 if (lookup(user))
454                                         goto again;
455                                 if (_getyppass(&_pw_passwd, user,
456                                                         "passwd.byname"))
457                                         return(1);
458                                 else
459                                         goto again;
460                         }
461                 } else {
462                         if (lookup(grp+1))
463                                 return(0);
464                         return(_getyppass(&_pw_passwd, grp+1, "passwd.byname"));
465                 }
466         } else {
467                 if (grp[1] == '@') {
468                         setnetgrent(grp+2);
469                         rv = 0;
470                         while(getnetgrent(&host, &user, &domain) != 0) {
471                                 store(user);
472                                 rv++;
473                         }
474                         if (!rv && (gr = getgrnam(grp+2)) != NULL) {
475                                 while(*gr->gr_mem) {
476                                         store(*gr->gr_mem);
477                                         gr->gr_mem++;
478                                 }
479                         }
480                 } else {
481                         store(grp+1);
482                 }
483         }
484         return(0);
485 }
486
487 /*
488  * See if a user is a member of a particular group.
489  */
490 static inline int
491 ingr(grp, name)
492         const char *grp;
493         const char *name;
494 {
495         struct group *gr;
496
497         if ((gr = getgrnam(grp)) == NULL)
498                 return(0);
499
500         while(*gr->gr_mem) {
501                 if (!strcmp(*gr->gr_mem, name))
502                         return(1);
503                 gr->gr_mem++;
504         }
505
506         return(0);
507 }
508
509 /*
510  * Check a user against the +@netgroup/-@netgroup lines listed in
511  * the local password database. Also checks +user/-user lines.
512  * If no netgroup exists that matches +@netgroup/-@netgroup,
513  * try searching regular groups with the same name.
514  */
515 static inline int
516 verf(name)
517         const char *name;
518 {
519         DBT key;
520         char bf[sizeof(_pw_keynum) + 1];
521         int keynum = 0;
522
523 again:
524         ++keynum;
525         bf[0] = _PW_KEYYPBYNUM;
526         bcopy((char *)&keynum, bf + 1, sizeof(keynum));
527         key.data = (u_char *)bf;
528         key.size = sizeof(keynum) + 1;
529         if (!__hashpw(&key)) {
530                 /* Try again using old format */
531                 bf[0] = _PW_KEYBYNUM;
532                 bcopy((char *)&keynum, bf + 1, sizeof(keynum));
533                 key.data = (u_char *)bf;
534                 if (!__hashpw(&key))
535                         return(0);
536         }
537         if (_pw_passwd.pw_name[0] != '+' && (_pw_passwd.pw_name[0] != '-'))
538                 goto again;
539         if (_pw_passwd.pw_name[0] == '+') {
540                 if (strlen(_pw_passwd.pw_name) == 1) /* Wildcard */
541                         return(1);
542                 if (_pw_passwd.pw_name[1] == '@') {
543                         if ((innetgr(_pw_passwd.pw_name+2, NULL, name,
544                                                         _pw_yp_domain) ||
545                             ingr(_pw_passwd.pw_name+2, name)) && !lookup(name))
546                                 return(1);
547                         else
548                                 goto again;
549                 } else {
550                         if (!strcmp(name, _pw_passwd.pw_name+1) &&
551                                                                 !lookup(name))
552                                 return(1);
553                         else
554                                 goto again;
555                 }
556         }
557         if (_pw_passwd.pw_name[0] == '-') {
558                 /* Note that a minus wildcard is a no-op. */
559                 if (_pw_passwd.pw_name[1] == '@') {
560                         if (innetgr(_pw_passwd.pw_name+2, NULL, name,
561                                                         _pw_yp_domain) ||
562                             ingr(_pw_passwd.pw_name+2, name)) {
563                                 store(name);
564                                 return(0);
565                         } else
566                                 goto again;
567                 } else {
568                         if (!strcmp(name, _pw_passwd.pw_name+1)) {
569                                 store(name);
570                                 return(0);
571                         } else
572                                 goto again;
573                 }
574                 
575         }
576         return(0);
577 }
578
579 static char *
580 _get_adjunct_pw(name)
581         const char *name;
582 {
583         static char adjunctbuf[YPMAXRECORD+2];
584         int rval;
585         char *result;
586         int resultlen;
587         char *map = "passwd.adjunct.byname";
588         char *s;
589
590         if ((rval = yp_match(_pw_yp_domain, map, name, strlen(name),
591                     &result, &resultlen)))
592                 return(NULL);
593
594         strncpy(adjunctbuf, result, resultlen);
595         adjunctbuf[resultlen] = '\0';
596         free(result);
597         result = (char *)&adjunctbuf;
598
599         /* Don't care about the name. */
600         if ((s = strsep(&result, ":")) == NULL)
601                 return (NULL); /* name */
602         if ((s = strsep(&result, ":")) == NULL)
603                 return (NULL); /* password */
604
605         return(s);
606 }
607
608 static int
609 _pw_breakout_yp(struct passwd *pw, char *res, int resultlen, int master)
610 {
611         char *s, *result;
612         static char resbuf[YPMAXRECORD+2];
613
614         /*
615          * Be triple, ultra super-duper paranoid: reject entries
616          * that start with a + or -. yp_mkdb and /var/yp/Makefile
617          * are _both_ supposed to strip these out, but you never
618          * know.
619          */
620         if (*res == '+' || *res == '-')
621                 return 0;
622
623         /*
624          * The NIS protocol definition limits the size of an NIS
625          * record to YPMAXRECORD bytes. We need to do a copy to
626          * a static buffer here since the memory pointed to by
627          * res will be free()ed when this function returns.
628          */
629         strncpy((char *)&resbuf, res, resultlen);
630         resbuf[resultlen] = '\0';
631         result = (char *)&resbuf;
632
633         /*
634          * XXX Sanity check: make sure all fields are valid (no NULLs).
635          * If we find a badly formatted entry, we punt.
636          */
637         if ((s = strsep(&result, ":")) == NULL) return 0; /* name */
638         /*
639          * We don't care what pw_fields says: we _always_ want the
640          * username returned to us by NIS.
641          */
642         pw->pw_name = s;
643         pw->pw_fields |= _PWF_NAME;
644
645         if ((s = strsep(&result, ":")) == NULL) return 0; /* password */
646         if(!(pw->pw_fields & _PWF_PASSWD)) {
647                 /* SunOS passwd.adjunct hack */
648                 if (master == YP_HAVE_ADJUNCT && strstr(s, "##") != NULL) {
649                         char *realpw;
650                         realpw = _get_adjunct_pw(pw->pw_name);
651                         if (realpw == NULL)
652                                 pw->pw_passwd = s;
653                         else
654                                 pw->pw_passwd = realpw;
655                 } else {
656                         pw->pw_passwd = s;
657                 }
658                 pw->pw_fields |= _PWF_PASSWD;
659         }
660
661         if ((s = strsep(&result, ":")) == NULL) return 0; /* uid */
662         if(!(pw->pw_fields & _PWF_UID)) {
663                 pw->pw_uid = atoi(s);
664                 pw->pw_fields |= _PWF_UID;
665         }
666
667         if ((s = strsep(&result, ":")) == NULL) return 0; /* gid */
668         if(!(pw->pw_fields & _PWF_GID))  {
669                 pw->pw_gid = atoi(s);
670                 pw->pw_fields |= _PWF_GID;
671         }
672
673         if (master == YP_HAVE_MASTER) {
674                 if ((s = strsep(&result, ":")) == NULL) return 0; /* class */
675                 if(!(pw->pw_fields & _PWF_CLASS))  {
676                         pw->pw_class = s;
677                         pw->pw_fields |= _PWF_CLASS;
678                 }
679
680                 if ((s = strsep(&result, ":")) == NULL) return 0; /* change */
681                 if(!(pw->pw_fields & _PWF_CHANGE))  {
682                         pw->pw_change = atol(s);
683                         pw->pw_fields |= _PWF_CHANGE;
684                 }
685
686                 if ((s = strsep(&result, ":")) == NULL) return 0; /* expire */
687                 if(!(pw->pw_fields & _PWF_EXPIRE))  {
688                         pw->pw_expire = atol(s);
689                         pw->pw_fields |= _PWF_EXPIRE;
690                 }
691         }
692
693         if ((s = strsep(&result, ":")) == NULL) return 0; /* gecos */
694         if(!(pw->pw_fields & _PWF_GECOS)) {
695                 pw->pw_gecos = s;
696                 pw->pw_fields |= _PWF_GECOS;
697         }
698
699         if ((s = strsep(&result, ":")) == NULL) return 0; /* dir */
700         if(!(pw->pw_fields & _PWF_DIR)) {
701                 pw->pw_dir = s;
702                 pw->pw_fields |= _PWF_DIR;
703         }
704
705         if ((s = strsep(&result, ":")) == NULL) return 0; /* shell */
706         if(!(pw->pw_fields & _PWF_SHELL)) {
707                 pw->pw_shell = s;
708                 pw->pw_fields |= _PWF_SHELL;
709         }
710
711         /* Be consistent. */
712         if ((s = strchr(pw->pw_shell, '\n'))) *s = '\0';
713
714         return 1;
715 }
716
717 static int
718 _havemaster(char *_yp_domain)
719 {
720         int order;
721         int rval;
722
723         if (!(rval = yp_order(_yp_domain, "master.passwd.byname", &order)))
724                 return(YP_HAVE_MASTER);
725
726         /*
727          * NIS+ in YP compat mode doesn't support
728          * YPPROC_ORDER -- no point in continuing.
729          */
730         if (rval == YPERR_YPERR)
731                 return(YP_HAVE_NONE);
732
733         /* master.passwd doesn't exist -- try passwd.adjunct */
734         if (rval == YPERR_MAP) {
735                 rval = yp_order(_yp_domain, "passwd.adjunct.byname", &order);
736                 if (!rval)
737                         return(YP_HAVE_ADJUNCT);
738         }
739
740         return (YP_HAVE_NONE);
741 }
742
743 static int
744 _getyppass(struct passwd *pw, const char *name, const char *map)
745 {
746         char *result, *s;
747         int resultlen;
748         int rv;
749         char mastermap[YPMAXRECORD];
750
751         if(!_pw_yp_domain) {
752                 if(yp_get_default_domain(&_pw_yp_domain))
753                   return 0;
754         }
755
756         if (_gotmaster == YP_HAVE_MASTER)
757                 snprintf(mastermap, sizeof(mastermap), "master.%s", map);
758         else
759                 snprintf(mastermap, sizeof(mastermap), "%s", map);
760
761         if(yp_match(_pw_yp_domain, (char *)&mastermap, name, strlen(name),
762                     &result, &resultlen)) {
763                 if (_gotmaster != YP_HAVE_MASTER)
764                         return 0;
765                 snprintf(mastermap, sizeof(mastermap), "%s", map);
766                 if (yp_match(_pw_yp_domain, (char *)&mastermap,
767                              name, strlen(name), &result, &resultlen))
768                         return 0;
769                 _gotmaster = YP_HAVE_NONE;
770         }
771
772         if (!_pw_stepping_yp) {
773                 s = strchr(result, ':');
774                 if (s) {
775                         *s = '\0';
776                 } else {
777                         /* Must be a malformed entry if no colons. */
778                         free(result);
779                         return(0);
780                 }
781
782                 if (!verf(result)) {
783                         *s = ':';
784                         free(result);
785                         return(0);
786                 }
787
788                 *s = ':'; /* Put back the colon we previously replaced with a NUL. */
789         }
790
791         rv = _pw_breakout_yp(pw, result, resultlen, _gotmaster);
792         free(result);
793         return(rv);
794 }
795
796 static int
797 _nextyppass(struct passwd *pw)
798 {
799         static char *key;
800         static int keylen;
801         char *lastkey, *result, *s;
802         int resultlen;
803         int rv;
804         char *map = "passwd.byname";
805
806         if(!_pw_yp_domain) {
807                 if(yp_get_default_domain(&_pw_yp_domain))
808                   return 0;
809         }
810
811         if (_gotmaster == YP_HAVE_MASTER)
812                 map = "master.passwd.byname";
813
814         if(!_pw_stepping_yp) {
815                 if(key) free(key);
816                         rv = yp_first(_pw_yp_domain, map,
817                                       &key, &keylen, &result, &resultlen);
818                 if(rv) {
819                         return 0;
820                 }
821                 _pw_stepping_yp = 1;
822                 goto unpack;
823         } else {
824 tryagain:
825                 lastkey = key;
826                         rv = yp_next(_pw_yp_domain, map, key, keylen,
827                              &key, &keylen, &result, &resultlen);
828                 free(lastkey);
829 unpack:
830                 if(rv) {
831                         _pw_stepping_yp = 0;
832                         return 0;
833                 }
834
835                 s = strchr(result, ':');
836                 if (s) {
837                         *s = '\0';
838                 } else {
839                         /* Must be a malformed entry if no colons. */
840                         free(result);
841                         goto tryagain;
842                 }
843
844                 if (lookup(result)) {
845                         *s = ':';
846                         free(result);
847                         goto tryagain;
848                 }
849
850                 *s = ':'; /* Put back the colon we previously replaced with a NUL. */
851                 if (_pw_breakout_yp(pw, result, resultlen, _gotmaster)) {
852                         free(result);
853                         return(1);
854                 } else {
855                         free(result);
856                         goto tryagain;
857                 }
858         }
859 }
860
861 #endif /* YP */