2 * Copyright (c) 1988, 1993
3 * The Regents of the University of California. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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
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 $
38 #include "namespace.h"
40 #include <sys/param.h>
51 #include "un-namespace.h"
55 extern void setnetgrent ( char * );
56 extern int getnetgrent ( char **, char **, char ** );
57 extern int innetgr ( const char *, const char *, const char *, const char * );
60 * The lookup techniques and data extraction code here must be kept
61 * in sync with that in `pwd_mkdb'.
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 */
70 #include <rpcsvc/yp_prot.h>
71 #include <rpcsvc/ypclnt.h>
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 *);
96 static int __hashpw(DBT *);
97 static int __initdb(void);
103 char bf[sizeof(_pw_keynum) + 1];
106 if (!_pw_db && !__initdb())
107 return((struct passwd *)NULL);
110 if(_pw_stepping_yp) {
111 _pw_passwd = _pw_copy;
112 if (unwind((char *)&_ypnam))
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;
124 if(!rv) return (struct passwd *)NULL;
126 if(_pw_passwd.pw_name[0] == '+' || _pw_passwd.pw_name[0] == '-') {
127 if (_yp_enabled == -1)
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)
139 /* Ignore YP password file entries when YP is disabled. */
140 if(_pw_passwd.pw_name[0] == '+' || _pw_passwd.pw_name[0] == '-') {
148 getpwnam(const char *name)
152 char bf[UT_NAMESIZE + 2];
154 if (!_pw_db && !__initdb())
155 return((struct passwd *)NULL);
157 bf[0] = _PW_KEYBYNAME;
159 if (len > UT_NAMESIZE)
161 bcopy(name, bf + 1, len);
162 key.data = (u_char *)bf;
164 rval = __hashpw(&key);
168 if (_yp_enabled == -1)
171 rval = _getyppass(&_pw_passwd, name, "passwd.byname");
175 * Prevent login attempts when YP is not enabled but YP entries
176 * are in /etc/master.passwd.
178 if (rval && (_pw_passwd.pw_name[0] == '+'||
179 _pw_passwd.pw_name[0] == '-')) rval = 0;
183 return(rval ? &_pw_passwd : (struct passwd *)NULL);
191 char bf[sizeof(keyuid) + 1];
193 if (!_pw_db && !__initdb())
194 return((struct passwd *)NULL);
196 bf[0] = _PW_KEYBYUID;
198 bcopy(&keyuid, bf + 1, sizeof(keyuid));
199 key.data = (u_char *)bf;
200 key.size = sizeof(keyuid) + 1;
201 rval = __hashpw(&key);
205 if (_yp_enabled == -1)
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");
215 * Prevent login attempts when YP is not enabled but YP entries
216 * are in /etc/master.passwd.
218 if (rval && (_pw_passwd.pw_name[0] == '+'||
219 _pw_passwd.pw_name[0] == '-')) rval = 0;
223 return(rval ? &_pw_passwd : (struct passwd *)NULL);
227 setpassent(int stayopen)
235 _pw_stayopen = stayopen;
253 (_pw_db->close)(_pw_db);
258 (_ypcache->close)(_ypcache);
259 _ypcache = (DB *)NULL;
262 /* Fix for PR #12008 */
273 p = (geteuid()) ? _PATH_MP_DB : _PATH_SMP_DB;
274 _pw_db = dbopen(p, O_RDONLY, 0, DB_HASH, NULL);
278 syslog(LOG_ERR, "%s: %m", p);
290 if ((_pw_db->get)(_pw_db, key, &data, 0))
292 p = (char *)data.data;
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)))
301 /* THIS CODE MUST MATCH THAT IN pwd_mkdb. */
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;
326 char buf[] = { _PW_KEYYPENABLED };
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. */
335 if (yp_get_default_domain(&_pw_yp_domain))
337 _gotmaster = _havemaster(_pw_yp_domain);
338 } else _gotmaster = YP_HAVE_NONE;
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.
343 if (_ypcache == (DB *)NULL)
344 _ypcache = dbopen(NULL, O_RDWR, 600, DB_HASH, NULL);
349 * See if a user is in the blackballed list.
352 lookup(const char *name)
359 key.data = (char *)name;
360 key.size = strlen(name);
362 if ((_ypcache->get)(_ypcache, &key, &empty, 0)) {
370 * Store a blackballed user in an in-core hash database.
373 store(const char *key)
383 lkey.data = (char *)key;
384 lkey.size = strlen(key);
386 (_ypcache->put)(_ypcache, &lkey, &empty, R_NOOVERWRITE);
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
404 char *user, *host, *domain;
405 static int latch = 0;
406 static struct group *gr = NULL;
410 if (strlen(grp) == 1) {
411 return(_nextyppass(&_pw_passwd));
417 if (*gr->gr_mem != NULL) {
418 if (lookup(*gr->gr_mem)) {
422 rv = _getyppass(&_pw_passwd,
439 if (getnetgrent(&host, &user, &domain) == 0) {
440 if ((gr = getgrnam(grp+2)) != NULL)
448 if (_getyppass(&_pw_passwd, user,
457 return(_getyppass(&_pw_passwd, grp+1, "passwd.byname"));
463 while(getnetgrent(&host, &user, &domain) != 0) {
467 if (!rv && (gr = getgrnam(grp+2)) != NULL) {
481 * See if a user is a member of a particular group.
484 ingr(const char *grp, const char *name)
488 if ((gr = getgrnam(grp)) == NULL)
492 if (!strcmp(*gr->gr_mem, name))
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.
507 verf(const char *name)
510 char bf[sizeof(_pw_keynum) + 1];
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;
527 if (_pw_passwd.pw_name[0] != '+' && (_pw_passwd.pw_name[0] != '-'))
529 if (_pw_passwd.pw_name[0] == '+') {
530 if (strlen(_pw_passwd.pw_name) == 1) /* Wildcard */
532 if (_pw_passwd.pw_name[1] == '@') {
533 if ((innetgr(_pw_passwd.pw_name+2, NULL, name,
535 ingr(_pw_passwd.pw_name+2, name)) && !lookup(name))
540 if (!strcmp(name, _pw_passwd.pw_name+1) &&
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,
552 ingr(_pw_passwd.pw_name+2, name)) {
558 if (!strcmp(name, _pw_passwd.pw_name+1)) {
570 _get_adjunct_pw(const char *name)
572 static char adjunctbuf[YPMAXRECORD+2];
576 char *map = "passwd.adjunct.byname";
579 if ((rval = yp_match(_pw_yp_domain, map, name, strlen(name),
580 &result, &resultlen)))
583 strncpy(adjunctbuf, result, resultlen);
584 adjunctbuf[resultlen] = '\0';
586 result = (char *)&adjunctbuf;
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 */
598 _pw_breakout_yp(struct passwd *pw, char *res, int resultlen, int master)
601 static char resbuf[YPMAXRECORD+2];
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
609 if (*res == '+' || *res == '-')
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.
618 strncpy((char *)&resbuf, res, resultlen);
619 resbuf[resultlen] = '\0';
620 result = (char *)&resbuf;
623 * XXX Sanity check: make sure all fields are valid (no NULLs).
624 * If we find a badly formatted entry, we punt.
626 if ((s = strsep(&result, ":")) == NULL) return 0; /* name */
628 * We don't care what pw_fields says: we _always_ want the
629 * username returned to us by NIS.
632 pw->pw_fields |= _PWF_NAME;
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) {
639 realpw = _get_adjunct_pw(pw->pw_name);
643 pw->pw_passwd = realpw;
647 pw->pw_fields |= _PWF_PASSWD;
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;
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;
662 if (master == YP_HAVE_MASTER) {
663 if ((s = strsep(&result, ":")) == NULL) return 0; /* class */
664 if(!(pw->pw_fields & _PWF_CLASS)) {
666 pw->pw_fields |= _PWF_CLASS;
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;
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;
682 if ((s = strsep(&result, ":")) == NULL) return 0; /* gecos */
683 if(!(pw->pw_fields & _PWF_GECOS)) {
685 pw->pw_fields |= _PWF_GECOS;
688 if ((s = strsep(&result, ":")) == NULL) return 0; /* dir */
689 if(!(pw->pw_fields & _PWF_DIR)) {
691 pw->pw_fields |= _PWF_DIR;
694 if ((s = strsep(&result, ":")) == NULL) return 0; /* shell */
695 if(!(pw->pw_fields & _PWF_SHELL)) {
697 pw->pw_fields |= _PWF_SHELL;
701 if ((s = strchr(pw->pw_shell, '\n'))) *s = '\0';
707 _havemaster(char *_yp_domain)
712 if (!(rval = yp_order(_yp_domain, "master.passwd.byname", &order)))
713 return(YP_HAVE_MASTER);
716 * NIS+ in YP compat mode doesn't support
717 * YPPROC_ORDER -- no point in continuing.
719 if (rval == YPERR_YPERR)
720 return(YP_HAVE_NONE);
722 /* master.passwd doesn't exist -- try passwd.adjunct */
723 if (rval == YPERR_MAP) {
724 rval = yp_order(_yp_domain, "passwd.adjunct.byname", &order);
726 return(YP_HAVE_ADJUNCT);
729 return (YP_HAVE_NONE);
733 _getyppass(struct passwd *pw, const char *name, const char *map)
738 char mastermap[YPMAXRECORD];
741 if(yp_get_default_domain(&_pw_yp_domain))
745 if (_gotmaster == YP_HAVE_MASTER)
746 snprintf(mastermap, sizeof(mastermap), "master.%s", map);
748 snprintf(mastermap, sizeof(mastermap), "%s", map);
750 if(yp_match(_pw_yp_domain, (char *)&mastermap, name, strlen(name),
751 &result, &resultlen)) {
752 if (_gotmaster != YP_HAVE_MASTER)
754 snprintf(mastermap, sizeof(mastermap), "%s", map);
755 if (yp_match(_pw_yp_domain, (char *)&mastermap,
756 name, strlen(name), &result, &resultlen))
758 _gotmaster = YP_HAVE_NONE;
761 if (!_pw_stepping_yp) {
762 s = strchr(result, ':');
766 /* Must be a malformed entry if no colons. */
777 *s = ':'; /* Put back the colon we previously replaced with a NUL. */
780 rv = _pw_breakout_yp(pw, result, resultlen, _gotmaster);
786 _nextyppass(struct passwd *pw)
790 char *lastkey, *result, *s;
793 char *map = "passwd.byname";
796 if(yp_get_default_domain(&_pw_yp_domain))
800 if (_gotmaster == YP_HAVE_MASTER)
801 map = "master.passwd.byname";
803 if(!_pw_stepping_yp) {
805 rv = yp_first(_pw_yp_domain, map,
806 &key, &keylen, &result, &resultlen);
815 rv = yp_next(_pw_yp_domain, map, key, keylen,
816 &key, &keylen, &result, &resultlen);
824 s = strchr(result, ':');
828 /* Must be a malformed entry if no colons. */
833 if (lookup(result)) {
839 *s = ':'; /* Put back the colon we previously replaced with a NUL. */
840 if (_pw_breakout_yp(pw, result, resultlen, _gotmaster)) {