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