getpwent.c revision 1.13 1 /* $NetBSD: getpwent.c,v 1.13 1995/05/17 17:36:43 mycroft Exp $ */
2
3 /*
4 * Copyright (c) 1988, 1993
5 * The Regents of the University of California. All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by the University of
18 * California, Berkeley and its contributors.
19 * 4. Neither the name of the University nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 */
35
36 #if defined(LIBC_SCCS) && !defined(lint)
37 #if 0
38 static char sccsid[] = "@(#)getpwent.c 8.1 (Berkeley) 6/4/93";
39 #else
40 static char rcsid[] = "$NetBSD: getpwent.c,v 1.13 1995/05/17 17:36:43 mycroft Exp $";
41 #endif
42 #endif /* LIBC_SCCS and not lint */
43
44 #include <sys/param.h>
45 #include <fcntl.h>
46 #include <db.h>
47 #include <syslog.h>
48 #include <pwd.h>
49 #include <utmp.h>
50 #include <errno.h>
51 #include <unistd.h>
52 #include <stdlib.h>
53 #include <string.h>
54 #include <limits.h>
55 #ifdef YP
56 #include <stdio.h>
57 #include <rpc/rpc.h>
58 #include <rpcsvc/yp_prot.h>
59 #include <rpcsvc/ypclnt.h>
60 #endif
61
62 static struct passwd _pw_passwd; /* password structure */
63 static DB *_pw_db; /* password database */
64 static int _pw_keynum; /* key counter */
65 static int _pw_stayopen; /* keep fd's open */
66 static int __hashpw(), __initdb();
67
68 #ifdef YP
69 static char *__ypcurrent, *__ypdomain;
70 static int __ypcurrentlen, __ypmode=0;
71 static char line[1024];
72
73 static int
74 __ypparse(pw, s)
75 struct passwd *pw;
76 char *s;
77 {
78 char *bp, *cp;
79
80 bp = s;
81 pw->pw_name = strsep(&bp, ":\n");
82 pw->pw_passwd = strsep(&bp, ":\n");
83 if (!(cp = strsep(&bp, ":\n")))
84 return 1;
85 pw->pw_uid = atoi(cp);
86 if (!(cp = strsep(&bp, ":\n")))
87 return 1;
88 pw->pw_gid = atoi(cp);
89 pw->pw_change = 0;
90 pw->pw_class = "";
91 pw->pw_gecos = strsep(&bp, ":\n");
92 pw->pw_dir = strsep(&bp, ":\n");
93 pw->pw_shell = strsep(&bp, ":\n");
94 pw->pw_expire = 0;
95 return 0;
96 }
97 #endif
98
99 struct passwd *
100 getpwent()
101 {
102 DBT key;
103 char bf[sizeof(_pw_keynum) + 1];
104 #ifdef YP
105 char *cp;
106 #endif
107
108 if (!_pw_db && !__initdb())
109 return((struct passwd *)NULL);
110
111 #ifdef YP
112 again:
113 if(__ypmode) {
114 char *key, *data;
115 int keylen, datalen;
116 int r;
117
118 if(!__ypdomain) {
119 if( _yp_check(&__ypdomain) == 0) {
120 __ypmode = 0;
121 goto again;
122 }
123 }
124 if(__ypcurrent) {
125 r = yp_next(__ypdomain, "passwd.byname",
126 __ypcurrent, __ypcurrentlen,
127 &key, &keylen, &data, &datalen);
128 free(__ypcurrent);
129 __ypcurrent = NULL;
130 /*printf("yp_next %d\n", r);*/
131 switch(r) {
132 case 0:
133 break;
134 default:
135 __ypcurrent = NULL;
136 __ypmode = 0;
137 free(data);
138 data = NULL;
139 goto again;
140 }
141 __ypcurrent = key;
142 __ypcurrentlen = keylen;
143 bcopy(data, line, datalen);
144 free(data);
145 data = NULL;
146 } else {
147 r = yp_first(__ypdomain, "passwd.byname",
148 &__ypcurrent, &__ypcurrentlen,
149 &data, &datalen);
150 /*printf("yp_first %d\n", r);*/
151 switch(r) {
152 case 0:
153 break;
154 default:
155 __ypmode = 0;
156 free(data);
157 goto again;
158 }
159 bcopy(data, line, datalen);
160 free(data);
161 data = NULL;
162 }
163 line[datalen] = '\0';
164 /*printf("line = %s\n", line);*/
165 if (__ypparse(&_pw_passwd, line))
166 goto again;
167 return &_pw_passwd;
168 }
169 #endif
170
171 ++_pw_keynum;
172 bf[0] = _PW_KEYBYNUM;
173 bcopy((char *)&_pw_keynum, bf + 1, sizeof(_pw_keynum));
174 key.data = (u_char *)bf;
175 key.size = sizeof(_pw_keynum) + 1;
176 if(__hashpw(&key)) {
177 #ifdef YP
178 if(strcmp(_pw_passwd.pw_name, "+") == 0) {
179 __ypmode = 1;
180 goto again;
181 }
182 #endif
183 return &_pw_passwd;
184 }
185 return (struct passwd *)NULL;
186 }
187
188 struct passwd *
189 getpwnam(name)
190 const char *name;
191 {
192 DBT key;
193 int len, rval;
194 char bf[UT_NAMESIZE + 1];
195
196 if (!_pw_db && !__initdb())
197 return((struct passwd *)NULL);
198
199 #ifdef YP
200 bf[0] = _PW_KEYBYNAME;
201 len = strlen("+");
202 bcopy("+", bf + 1, MIN(len, UT_NAMESIZE));
203 key.data = (u_char *)bf;
204 key.size = len + 1;
205
206 /*
207 * If there is a user called "+", then YP is active. In that
208 * case we must sequence through the passwd file in sequence.
209 */
210 if ( __hashpw(&key)) {
211 int r;
212
213 for(_pw_keynum=1; _pw_keynum; _pw_keynum++) {
214 bf[0] = _PW_KEYBYNUM;
215 bcopy((char *)&_pw_keynum, bf + 1, sizeof(_pw_keynum));
216 key.data = (u_char *)bf;
217 key.size = sizeof(_pw_keynum) + 1;
218 if(__hashpw(&key) == 0)
219 break;
220 if(strcmp(_pw_passwd.pw_name, "+") == 0) {
221 if(!__ypdomain) {
222 if(_yp_check(&__ypdomain) == 0) {
223 continue;
224 }
225 }
226 if(__ypcurrent) {
227 free(__ypcurrent);
228 __ypcurrent = NULL;
229 }
230 r = yp_match(__ypdomain, "passwd.byname",
231 name, strlen(name),
232 &__ypcurrent, &__ypcurrentlen);
233 switch(r) {
234 case 0:
235 break;
236 default:
237 free(__ypcurrent);
238 __ypcurrent = NULL;
239 continue;
240 }
241 bcopy(__ypcurrent, line, __ypcurrentlen);
242 line[__ypcurrentlen] = '\0';
243 if(__ypparse(&_pw_passwd, line))
244 continue;
245 }
246 if( strcmp(_pw_passwd.pw_name, name) == 0) {
247 if (!_pw_stayopen) {
248 (void)(_pw_db->close)(_pw_db);
249 _pw_db = (DB *)NULL;
250 }
251 return &_pw_passwd;
252 }
253 continue;
254 }
255 if (!_pw_stayopen) {
256 (void)(_pw_db->close)(_pw_db);
257 _pw_db = (DB *)NULL;
258 }
259 return (struct passwd *)NULL;
260 }
261 #endif /* YP */
262
263 bf[0] = _PW_KEYBYNAME;
264 len = strlen(name);
265 bcopy(name, bf + 1, MIN(len, UT_NAMESIZE));
266 key.data = (u_char *)bf;
267 key.size = len + 1;
268 rval = __hashpw(&key);
269
270 if (!_pw_stayopen) {
271 (void)(_pw_db->close)(_pw_db);
272 _pw_db = (DB *)NULL;
273 }
274 return(rval ? &_pw_passwd : (struct passwd *)NULL);
275 }
276
277 struct passwd *
278 #ifdef __STDC__
279 getpwuid(uid_t uid)
280 #else
281 getpwuid(uid)
282 int uid;
283 #endif
284 {
285 DBT key;
286 char bf[sizeof(_pw_keynum) + 1];
287 int keyuid, rval, len;
288
289 if (!_pw_db && !__initdb())
290 return((struct passwd *)NULL);
291
292 #ifdef YP
293 bf[0] = _PW_KEYBYNAME;
294 len = strlen("+");
295 bcopy("+", bf + 1, MIN(len, UT_NAMESIZE));
296 key.data = (u_char *)bf;
297 key.size = len + 1;
298
299 /*
300 * If there is a user called "+", then YP is active. In that
301 * case we must sequence through the passwd file in sequence.
302 */
303 if ( __hashpw(&key)) {
304 char uidbuf[20];
305 int r;
306
307 for(_pw_keynum=1; _pw_keynum; _pw_keynum++) {
308 bf[0] = _PW_KEYBYNUM;
309 bcopy((char *)&_pw_keynum, bf + 1, sizeof(_pw_keynum));
310 key.data = (u_char *)bf;
311 key.size = sizeof(_pw_keynum) + 1;
312 if(__hashpw(&key) == 0)
313 break;
314 if(strcmp(_pw_passwd.pw_name, "+") == 0) {
315 if(!__ypdomain) {
316 if(_yp_check(&__ypdomain) == 0) {
317 continue;
318 }
319 }
320 if(__ypcurrent) {
321 free(__ypcurrent);
322 __ypcurrent = NULL;
323 }
324 sprintf(uidbuf, "%d", uid);
325 r = yp_match(__ypdomain, "passwd.byuid",
326 uidbuf, strlen(uidbuf),
327 &__ypcurrent, &__ypcurrentlen);
328 switch(r) {
329 case 0:
330 break;
331 default:
332 free(__ypcurrent);
333 __ypcurrent = NULL;
334 continue;
335 }
336 bcopy(__ypcurrent, line, __ypcurrentlen);
337 line[__ypcurrentlen] = '\0';
338 if(__ypparse(&_pw_passwd, line))
339 continue;
340 }
341 if( _pw_passwd.pw_uid == uid) {
342 if (!_pw_stayopen) {
343 (void)(_pw_db->close)(_pw_db);
344 _pw_db = (DB *)NULL;
345 }
346 return &_pw_passwd;
347 }
348 continue;
349 }
350 if (!_pw_stayopen) {
351 (void)(_pw_db->close)(_pw_db);
352 _pw_db = (DB *)NULL;
353 }
354 return (struct passwd *)NULL;
355 }
356 #endif /* YP */
357
358 bf[0] = _PW_KEYBYUID;
359 keyuid = uid;
360 bcopy(&keyuid, bf + 1, sizeof(keyuid));
361 key.data = (u_char *)bf;
362 key.size = sizeof(keyuid) + 1;
363 rval = __hashpw(&key);
364
365 if (!_pw_stayopen) {
366 (void)(_pw_db->close)(_pw_db);
367 _pw_db = (DB *)NULL;
368 }
369 return(rval ? &_pw_passwd : (struct passwd *)NULL);
370 }
371
372 int
373 setpassent(stayopen)
374 int stayopen;
375 {
376 _pw_keynum = 0;
377 _pw_stayopen = stayopen;
378 #ifdef YP
379 __ypmode = 0;
380 if(__ypcurrent)
381 free(__ypcurrent);
382 __ypcurrent = NULL;
383 #endif
384 return(1);
385 }
386
387 void
388 setpwent()
389 {
390 (void) setpassent(0);
391 }
392
393 void
394 endpwent()
395 {
396 _pw_keynum = 0;
397 if (_pw_db) {
398 (void)(_pw_db->close)(_pw_db);
399 _pw_db = (DB *)NULL;
400 }
401 #ifdef YP
402 __ypmode = 0;
403 if(__ypcurrent)
404 free(__ypcurrent);
405 __ypcurrent = NULL;
406 #endif
407 }
408
409 static int
410 __initdb()
411 {
412 static int warned;
413 char *p;
414
415 p = (geteuid()) ? _PATH_MP_DB : _PATH_SMP_DB;
416 _pw_db = dbopen(p, O_RDONLY, 0, DB_HASH, NULL);
417 if (_pw_db)
418 return(1);
419 if (!warned)
420 syslog(LOG_ERR, "%s: %m", p);
421 warned = 1;
422 return(0);
423 }
424
425 static int
426 __hashpw(key)
427 DBT *key;
428 {
429 register char *p, *t;
430 static u_int max;
431 static char *line;
432 DBT data;
433
434 if ((_pw_db->get)(_pw_db, key, &data, 0))
435 return(0);
436 p = (char *)data.data;
437 if (data.size > max && !(line = realloc(line, max += 1024)))
438 return(0);
439
440 t = line;
441 #define EXPAND(e) e = t; while (*t++ = *p++);
442 EXPAND(_pw_passwd.pw_name);
443 EXPAND(_pw_passwd.pw_passwd);
444 bcopy(p, (char *)&_pw_passwd.pw_uid, sizeof(int));
445 p += sizeof(int);
446 bcopy(p, (char *)&_pw_passwd.pw_gid, sizeof(int));
447 p += sizeof(int);
448 bcopy(p, (char *)&_pw_passwd.pw_change, sizeof(time_t));
449 p += sizeof(time_t);
450 EXPAND(_pw_passwd.pw_class);
451 EXPAND(_pw_passwd.pw_gecos);
452 EXPAND(_pw_passwd.pw_dir);
453 EXPAND(_pw_passwd.pw_shell);
454 bcopy(p, (char *)&_pw_passwd.pw_expire, sizeof(time_t));
455 p += sizeof(time_t);
456 return(1);
457 }
458