xref: /original-bsd/lib/libc/gen/getpwent.c (revision 54e6d6c7)
1 /*
2  * Copyright (c) 1988 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms are permitted
6  * provided that the above copyright notice and this paragraph are
7  * duplicated in all such forms and that any documentation,
8  * advertising materials, and other materials related to such
9  * distribution and use acknowledge that the software was developed
10  * by the University of California, Berkeley.  The name of the
11  * University may not be used to endorse or promote products derived
12  * from this software without specific prior written permission.
13  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
16  */
17 
18 #if defined(LIBC_SCCS) && !defined(lint)
19 static char sccsid[] = "@(#)getpwent.c	5.9 (Berkeley) 04/01/89";
20 #endif /* LIBC_SCCS and not lint */
21 
22 #include <sys/types.h>
23 #include <sys/file.h>
24 #include <stdio.h>
25 #include <pwd.h>
26 #include <ndbm.h>
27 
28 static DBM *_pw_db;
29 static FILE *_pw_fp;
30 static struct passwd _pw_passwd;
31 static int _pw_rewind = 1, _pw_stayopen;
32 static char _pw_flag, *_pw_file = _PATH_PASSWD;
33 
34 #define	MAXLINELENGTH	1024
35 static char line[MAXLINELENGTH];
36 
37 struct passwd *
38 getpwent()
39 {
40 	datum key;
41 	int rval;
42 
43 	if (!_pw_db && !_pw_fp && !start_pw())
44 		return((struct passwd *)NULL);
45 	do {
46 		if (_pw_db) {
47 			key.dptr = NULL;
48 			rval = fetch_pw(key);
49 		} else /* _pw_fp */
50 			rval = scanpw();
51 	} while (rval && _pw_flag != _PW_KEYBYNAME);
52 	if (rval)
53 		getpw();
54 	return(rval ? &_pw_passwd : (struct passwd *)NULL);
55 }
56 
57 struct passwd *
58 getpwnam(nam)
59 	char *nam;
60 {
61 	int rval;
62 
63 	if (!start_pw())
64 		return((struct passwd *)NULL);
65 	if (_pw_db) {
66 		datum key;
67 
68 		key.dptr = nam;
69 		key.dsize = strlen(nam);
70 		rval = fetch_pw(key);
71 	} else /* _pw_fp */
72 		for (rval = 0; scanpw();)
73 			if (!strcmp(nam, _pw_passwd.pw_name)) {
74 				rval = 1;
75 				break;
76 			}
77 	if (!_pw_stayopen)
78 		endpwent();
79 	if (rval)
80 		getpw();
81 	return(rval ? &_pw_passwd : (struct passwd *)NULL);
82 }
83 
84 struct passwd *
85 getpwuid(uid)
86 	int uid;
87 {
88 	int rval;
89 
90 	if (!start_pw())
91 		return((struct passwd *)NULL);
92 	if (_pw_db) {
93 		datum key;
94 
95 		key.dptr = (char *)&uid;
96 		key.dsize = sizeof(uid);
97 		rval = fetch_pw(key);
98 	} else /* _pw_fp */
99 		for (rval = 0; scanpw();)
100 			if (_pw_passwd.pw_uid == uid) {
101 				rval = 1;
102 				break;
103 			}
104 	if (!_pw_stayopen)
105 		endpwent();
106 	if (rval)
107 		getpw();
108 	return(rval ? &_pw_passwd : (struct passwd *)NULL);
109 }
110 
111 static
112 start_pw()
113 {
114 	char *p;
115 
116 	if (_pw_db) {
117 		_pw_rewind = 1;
118 		return(1);
119 	}
120 	if (_pw_fp) {
121 		rewind(_pw_fp);
122 		return(1);
123 	}
124 	if (_pw_db = dbm_open(_pw_file, O_RDONLY, 0))
125 		return(1);
126 	/*
127 	 * special case; if it's the official password file, look in
128 	 * the master password file, otherwise, look in the file itself.
129 	 */
130 	p = strcmp(_pw_file, _PATH_PASSWD) ? _pw_file : _PATH_MASTERPASSWD;
131 	if (_pw_fp = fopen(p, "r"))
132 		return(1);
133 	return(0);
134 }
135 
136 setpwent()
137 {
138 	return(setpassent(0));
139 }
140 
141 setpassent(stayopen)
142 	int stayopen;
143 {
144 	if (!start_pw())
145 		return(0);
146 	_pw_stayopen = stayopen;
147 	return(1);
148 }
149 
150 void
151 endpwent()
152 {
153 	if (_pw_db) {
154 		dbm_close(_pw_db);
155 		_pw_db = (DBM *)NULL;
156 	} else if (_pw_fp) {
157 		(void)fclose(_pw_fp);
158 		_pw_fp = (FILE *)NULL;
159 	}
160 }
161 
162 void
163 setpwfile(file)
164 	char *file;
165 {
166 	_pw_file = file;
167 }
168 
169 static
170 scanpw()
171 {
172 	register char *cp;
173 	long atol();
174 	char *fgets(), *strsep(), *index();
175 
176 	for (;;) {
177 		if (!(fgets(line, sizeof(line), _pw_fp)))
178 			return(0);
179 		/* skip lines that are too big */
180 		if (!index(line, '\n')) {
181 			int ch;
182 
183 			while ((ch = getc(_pw_fp)) != '\n' && ch != EOF)
184 				;
185 			continue;
186 		}
187 		_pw_passwd.pw_name = strsep(line, ":\n");
188 		_pw_passwd.pw_passwd = strsep((char *)NULL, ":\n");
189 		if (!(cp = strsep((char *)NULL, ":\n")))
190 			continue;
191 		_pw_passwd.pw_uid = atoi(cp);
192 		if (!(cp = strsep((char *)NULL, ":\n")))
193 			continue;
194 		_pw_passwd.pw_gid = atoi(cp);
195 		_pw_passwd.pw_class = strsep((char *)NULL, ":\n");
196 		if (!(cp = strsep((char *)NULL, ":\n")))
197 			continue;
198 		_pw_passwd.pw_change = atol(cp);
199 		if (!(cp = strsep((char *)NULL, ":\n")))
200 			continue;
201 		_pw_passwd.pw_expire = atol(cp);
202 		_pw_passwd.pw_gecos = strsep((char *)NULL, ":\n");
203 		_pw_passwd.pw_dir = strsep((char *)NULL, ":\n");
204 		_pw_passwd.pw_shell = strsep((char *)NULL, ":\n");
205 		if (!_pw_passwd.pw_shell)
206 			continue;
207 		return(1);
208 	}
209 	/* NOTREACHED */
210 }
211 
212 static
213 fetch_pw(key)
214 	datum key;
215 {
216 	register char *p, *t;
217 
218 	/*
219 	 * the .dir file is LOCK_EX locked by programs that are
220 	 * renaming the various password files.
221 	 */
222 	if (flock(dbm_dirfno(_pw_db), LOCK_SH))
223 		return(0);
224 	if (!key.dptr)
225 		if (_pw_rewind) {
226 			_pw_rewind = 0;
227 			key = dbm_firstkey(_pw_db);
228 		} else
229 			key = dbm_nextkey(_pw_db);
230 	if (key.dptr)
231 		key = dbm_fetch(_pw_db, key);
232 	(void)flock(dbm_dirfno(_pw_db), LOCK_UN);
233 	if (!(p = key.dptr))
234 		return(0);
235 	t = line;
236 #define	EXPAND(e)	e = t; while (*t++ = *p++);
237 	EXPAND(_pw_passwd.pw_name);
238 	EXPAND(_pw_passwd.pw_passwd);
239 	bcopy(p, (char *)&_pw_passwd.pw_uid, sizeof(int));
240 	p += sizeof(int);
241 	bcopy(p, (char *)&_pw_passwd.pw_gid, sizeof(int));
242 	p += sizeof(int);
243 	bcopy(p, (char *)&_pw_passwd.pw_change, sizeof(time_t));
244 	p += sizeof(time_t);
245 	EXPAND(_pw_passwd.pw_class);
246 	EXPAND(_pw_passwd.pw_gecos);
247 	EXPAND(_pw_passwd.pw_dir);
248 	EXPAND(_pw_passwd.pw_shell);
249 	bcopy(p, (char *)&_pw_passwd.pw_expire, sizeof(time_t));
250 	p += sizeof(time_t);
251 	_pw_flag = *p;
252 	return(1);
253 }
254 
255 static
256 getpw()
257 {
258 	static char pwbuf[50];
259 	off_t lseek();
260 	long pos, atol();
261 	int fd, n;
262 	char *p;
263 
264 	if (geteuid())
265 		return;
266 	/*
267 	 * special case; if it's the official password file, look in
268 	 * the master password file, otherwise, look in the file itself.
269 	 */
270 	p = strcmp(_pw_file, _PATH_PASSWD) ? _pw_file : _PATH_MASTERPASSWD;
271 	if ((fd = open(p, O_RDONLY, 0)) < 0)
272 		return;
273 	pos = atol(_pw_passwd.pw_passwd);
274 	if (lseek(fd, pos, L_SET) != pos)
275 		goto bad;
276 	if ((n = read(fd, pwbuf, sizeof(pwbuf) - 1)) < 0)
277 		goto bad;
278 	pwbuf[n] = '\0';
279 	for (p = pwbuf; *p; ++p)
280 		if (*p == ':') {
281 			*p = '\0';
282 			_pw_passwd.pw_passwd = pwbuf;
283 			break;
284 		}
285 bad:	(void)close(fd);
286 }
287