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