xref: /original-bsd/lib/libc/gen/getpwent.c (revision 2622b709)
1 /*
2  * Copyright (c) 1988 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * %sccs.include.redist.c%
6  */
7 
8 #if defined(LIBC_SCCS) && !defined(lint)
9 static char sccsid[] = "@(#)getpwent.c	5.14 (Berkeley) 06/01/90";
10 #endif /* LIBC_SCCS and not lint */
11 
12 #include <sys/types.h>
13 #include <sys/file.h>
14 #include <stdio.h>
15 #include <pwd.h>
16 #include <ndbm.h>
17 
18 static DBM *_pw_db;
19 static FILE *_pw_fp;
20 static struct passwd _pw_passwd;
21 static int _pw_getfirstkey, _pw_stayopen;
22 static char _pw_flag, *_pw_file = _PATH_PASSWD, _pw_master;
23 
24 #define	MAXLINELENGTH	1024
25 static char line[MAXLINELENGTH];
26 
27 struct passwd *
28 getpwent()
29 {
30 
31 	if (!_pw_fp && !start_pw(1))
32 		return((struct passwd *)NULL);
33 	if (!scanpw())
34 		return((struct passwd *)NULL);
35 	getpw();
36 	return(&_pw_passwd);
37 }
38 
39 struct passwd *
40 getpwnam(nam)
41 	char *nam;
42 {
43 	int rval;
44 
45 	if (!start_pw(0))
46 		return((struct passwd *)NULL);
47 	if (_pw_db) {
48 		datum key;
49 
50 		key.dptr = nam;
51 		key.dsize = strlen(nam);
52 		rval = fetch_pw(key);
53 	} else /* _pw_fp */
54 		for (rval = 0; scanpw();)
55 			if (!strcmp(nam, _pw_passwd.pw_name)) {
56 				rval = 1;
57 				break;
58 			}
59 	if (!_pw_stayopen)
60 		endpwent();
61 	if (rval)
62 		getpw();
63 	return(rval ? &_pw_passwd : (struct passwd *)NULL);
64 }
65 
66 struct passwd *
67 getpwuid(uid)
68 	int uid;
69 {
70 	int rval;
71 
72 	if (!start_pw(0))
73 		return((struct passwd *)NULL);
74 	if (_pw_db) {
75 		datum key;
76 
77 		key.dptr = (char *)&uid;
78 		key.dsize = sizeof(uid);
79 		rval = fetch_pw(key);
80 	} else /* _pw_fp */
81 		for (rval = 0; scanpw();)
82 			if (_pw_passwd.pw_uid == uid) {
83 				rval = 1;
84 				break;
85 			}
86 	if (!_pw_stayopen)
87 		endpwent();
88 	if (rval)
89 		getpw();
90 	return(rval ? &_pw_passwd : (struct passwd *)NULL);
91 }
92 
93 static
94 start_pw(want_fp)
95 	char want_fp;		/* open _pw_fp also */
96 {
97 	char *p;
98 
99 	if (_pw_db) {
100 		_pw_getfirstkey = 1;
101 		if (!want_fp)
102 			return(1);
103 	}
104 	if (_pw_fp) {
105 		rewind(_pw_fp);
106 		return(1);
107 	}
108 	if (!_pw_db && (_pw_db = dbm_open(_pw_file, O_RDONLY, 0))) {
109 		_pw_getfirstkey = 1;
110 		if (!want_fp)
111 			return(1);
112 	}
113 	/*
114 	 * special case; if it's the official password file, look in
115 	 * the master password file, otherwise, look in the file itself.
116 	 */
117 	p = strcmp(_pw_file, _PATH_PASSWD) ? _pw_file : _PATH_MASTERPASSWD;
118 	if (_pw_fp = fopen(p, "r")) {
119 		_pw_master = 1;
120 		return(1);
121 	}
122 	/*
123 	 * If we really want to set up _pw_fp, then try again
124 	 * with the old file.
125 	 */
126 	if (want_fp && p != _pw_file && (_pw_fp = fopen(_pw_file, "r"))) {
127 		_pw_master = 0;
128 		return(1);
129 	}
130 	return(0);
131 }
132 
133 setpwent()
134 {
135 	return(setpassent(0));
136 }
137 
138 setpassent(stayopen)
139 	int stayopen;
140 {
141 	if (!start_pw(0))
142 		return(0);
143 	_pw_stayopen = stayopen;
144 	return(1);
145 }
146 
147 void
148 endpwent()
149 {
150 	if (_pw_db) {
151 		dbm_close(_pw_db);
152 		_pw_db = (DBM *)NULL;
153 	}
154 	if (_pw_fp) {
155 		(void)fclose(_pw_fp);
156 		_pw_fp = (FILE *)NULL;
157 	}
158 }
159 
160 void
161 setpwfile(file)
162 	char *file;
163 {
164 	_pw_file = file;
165 }
166 
167 static
168 scanpw()
169 {
170 	register char *cp;
171 	long atol();
172 	char *bp;
173 	char *fgets(), *strsep(), *index();
174 
175 	for (;;) {
176 		if (!(fgets(line, sizeof(line), _pw_fp)))
177 			return(0);
178 		bp = line;
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(&bp, ":\n");
188 		_pw_passwd.pw_passwd = strsep(&bp, ":\n");
189 		if (!(cp = strsep(&bp, ":\n")))
190 			continue;
191 		_pw_passwd.pw_uid = atoi(cp);
192 		if (!(cp = strsep(&bp, ":\n")))
193 			continue;
194 		_pw_passwd.pw_gid = atoi(cp);
195 		if (_pw_master) {
196 			_pw_passwd.pw_class = strsep(&bp, ":\n");
197 			if (!(cp = strsep(&bp, ":\n")))
198 				continue;
199 			_pw_passwd.pw_change = atol(cp);
200 			if (!(cp = strsep(&bp, ":\n")))
201 				continue;
202 			_pw_passwd.pw_expire = atol(cp);
203 		}
204 		_pw_passwd.pw_gecos = strsep(&bp, ":\n");
205 		_pw_passwd.pw_dir = strsep(&bp, ":\n");
206 		_pw_passwd.pw_shell = strsep(&bp, ":\n");
207 		if (!_pw_passwd.pw_shell)
208 			continue;
209 		return(1);
210 	}
211 	/* NOTREACHED */
212 }
213 
214 static
215 fetch_pw(key)
216 	datum key;
217 {
218 	register char *p, *t;
219 
220 	/*
221 	 * the .dir file is LOCK_EX locked by programs that are
222 	 * renaming the various password files.
223 	 */
224 	if (flock(dbm_dirfno(_pw_db), LOCK_SH))
225 		return(0);
226 	if (!key.dptr)
227 		if (_pw_getfirstkey) {
228 			_pw_getfirstkey = 0;
229 			key = dbm_firstkey(_pw_db);
230 		} else
231 			key = dbm_nextkey(_pw_db);
232 	if (key.dptr)
233 		key = dbm_fetch(_pw_db, key);
234 	(void)flock(dbm_dirfno(_pw_db), LOCK_UN);
235 	if (!(p = key.dptr))
236 		return(0);
237 	t = line;
238 #define	EXPAND(e)	e = t; while (*t++ = *p++);
239 	EXPAND(_pw_passwd.pw_name);
240 	EXPAND(_pw_passwd.pw_passwd);
241 	bcopy(p, (char *)&_pw_passwd.pw_uid, sizeof(int));
242 	p += sizeof(int);
243 	bcopy(p, (char *)&_pw_passwd.pw_gid, sizeof(int));
244 	p += sizeof(int);
245 	bcopy(p, (char *)&_pw_passwd.pw_change, sizeof(time_t));
246 	p += sizeof(time_t);
247 	EXPAND(_pw_passwd.pw_class);
248 	EXPAND(_pw_passwd.pw_gecos);
249 	EXPAND(_pw_passwd.pw_dir);
250 	EXPAND(_pw_passwd.pw_shell);
251 	bcopy(p, (char *)&_pw_passwd.pw_expire, sizeof(time_t));
252 	p += sizeof(time_t);
253 	_pw_flag = *p;
254 	return(1);
255 }
256 
257 #define	_MAX_PASSWD_SIZE	50
258 static char pwbuf[_MAX_PASSWD_SIZE];
259 
260 static
261 getpw()
262 {
263 	long pos, atol();
264 	int fd, n;
265 	char *p;
266 	off_t lseek();
267 
268 	if (geteuid())
269 		return;
270 	/*
271 	 * special case; if it's the official password file, look in
272 	 * the master password file, otherwise, look in the file itself.
273 	 */
274 	p = strcmp(_pw_file, _PATH_PASSWD) ? _pw_file : _PATH_MASTERPASSWD;
275 	if ((fd = open(p, O_RDONLY, 0)) < 0)
276 		return;
277 	pos = atol(_pw_passwd.pw_passwd);
278 	if (lseek(fd, pos, L_SET) != pos)
279 		goto bad;
280 	if ((n = read(fd, pwbuf, sizeof(pwbuf) - 1)) < 0)
281 		goto bad;
282 	pwbuf[n] = '\0';
283 	for (p = pwbuf; *p; ++p)
284 		if (*p == ':') {
285 			*p = '\0';
286 			_pw_passwd.pw_passwd = pwbuf;
287 			break;
288 		}
289 bad:	(void)close(fd);
290 }
291