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