GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: lib/libc/gen/getpwent.c Lines: 145 497 29.2 %
Date: 2017-11-07 Branches: 55 313 17.6 %

Line Branch Exec Source
1
/*	$OpenBSD: getpwent.c,v 1.61 2016/05/07 21:52:29 tedu Exp $ */
2
/*
3
 * Copyright (c) 2008 Theo de Raadt
4
 * Copyright (c) 1988, 1993
5
 *	The Regents of the University of California.  All rights reserved.
6
 * Portions Copyright (c) 1994, 1995, 1996, Jason Downs.  All rights reserved.
7
 *
8
 * Redistribution and use in source and binary forms, with or without
9
 * modification, are permitted provided that the following conditions
10
 * are met:
11
 * 1. Redistributions of source code must retain the above copyright
12
 *    notice, this list of conditions and the following disclaimer.
13
 * 2. Redistributions in binary form must reproduce the above copyright
14
 *    notice, this list of conditions and the following disclaimer in the
15
 *    documentation and/or other materials provided with the distribution.
16
 * 3. Neither the name of the University nor the names of its contributors
17
 *    may be used to endorse or promote products derived from this software
18
 *    without specific prior written permission.
19
 *
20
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30
 * SUCH DAMAGE.
31
 */
32
33
#include <sys/param.h>	/* ALIGN */
34
#include <fcntl.h>
35
#include <db.h>
36
#include <syslog.h>
37
#include <pwd.h>
38
#include <errno.h>
39
#include <unistd.h>
40
#include <stdlib.h>
41
#include <string.h>
42
#include <limits.h>
43
#include <netgroup.h>
44
#ifdef YP
45
#include <stdio.h>
46
#include <rpc/rpc.h>
47
#include <rpcsvc/yp.h>
48
#include <rpcsvc/ypclnt.h>
49
#include "ypinternal.h"
50
#include "ypexclude.h"
51
#endif
52
#include "thread_private.h"
53
54
#define MINIMUM(a, b)	(((a) < (b)) ? (a) : (b))
55
56
_THREAD_PRIVATE_KEY(pw);
57
58
static DB *_pw_db;			/* password database */
59
60
/* Following are used only by setpwent(), getpwent(), and endpwent() */
61
static struct passwd _pw_passwd;	/* password structure */
62
static char _pw_string[_PW_BUF_LEN];	/* string pointed to by _pw_passwd */
63
static int _pw_keynum;			/* key counter */
64
static int _pw_stayopen;		/* keep fd's open */
65
static int _pw_flags;			/* password flags */
66
67
static int __hashpw(DBT *, char *buf, size_t buflen, struct passwd *, int *);
68
static int __initdb(int);
69
static struct passwd *_pwhashbyname(const char *name, char *buf,
70
	size_t buflen, struct passwd *pw, int *);
71
static struct passwd *_pwhashbyuid(uid_t uid, char *buf,
72
	size_t buflen, struct passwd *pw, int *);
73
74
#ifdef YP
75
static char	*__ypdomain;
76
77
/* Following are used only by setpwent(), getpwent(), and endpwent() */
78
enum _ypmode { YPMODE_NONE, YPMODE_FULL, YPMODE_USER, YPMODE_NETGRP };
79
static enum	_ypmode __ypmode;
80
static char	*__ypcurrent;
81
static int	__ypcurrentlen;
82
static int	__yp_pw_flags;
83
static struct passwd *__ypproto;
84
static char	__ypline[_PW_BUF_LEN];
85
static int	__getpwent_has_yppw = -1;
86
static struct _ypexclude *__ypexhead;
87
88
static int __has_yppw(void);
89
static int __has_ypmaster(void);
90
static void __ypproto_set(struct passwd *, long long *, int, int *);
91
static int __ypparse(struct passwd *pw, char *s, int);
92
93
#define LOOKUP_BYNAME 0
94
#define LOOKUP_BYUID 1
95
static struct passwd *__yppwlookup(int, char *, uid_t, struct passwd *,
96
    char *, size_t, int *);
97
98
/* macro for deciding which YP maps to use. */
99
#define PASSWD_BYNAME \
100
	(__has_ypmaster() ? "master.passwd.byname" : "passwd.byname")
101
#define PASSWD_BYUID \
102
	(__has_ypmaster() ? "master.passwd.byuid" : "passwd.byuid")
103
104
static void
105
__ypproto_set(struct passwd *pw, long long *buf, int flags, int *yp_pw_flagsp)
106
{
107
	char *ptr;
108
109
	/* make this the new prototype */
110
	ptr = (char *)buf;
111
112
	/* first allocate the struct. */
113
	__ypproto = (struct passwd *)ptr;
114
	ptr += sizeof(struct passwd);
115
116
	/* name */
117
	if (pw->pw_name && (pw->pw_name)[0]) {
118
		ptr = (char *)ALIGN(ptr);
119
		bcopy(pw->pw_name, ptr, strlen(pw->pw_name) + 1);
120
		__ypproto->pw_name = ptr;
121
		ptr += (strlen(pw->pw_name) + 1);
122
	} else
123
		__ypproto->pw_name = NULL;
124
125
	/* password */
126
	if (pw->pw_passwd && (pw->pw_passwd)[0]) {
127
		ptr = (char *)ALIGN(ptr);
128
		bcopy(pw->pw_passwd, ptr, strlen(pw->pw_passwd) + 1);
129
		__ypproto->pw_passwd = ptr;
130
		ptr += (strlen(pw->pw_passwd) + 1);
131
	} else
132
		__ypproto->pw_passwd = NULL;
133
134
	/* uid */
135
	__ypproto->pw_uid = pw->pw_uid;
136
137
	/* gid */
138
	__ypproto->pw_gid = pw->pw_gid;
139
140
	/* change (ignored anyway) */
141
	__ypproto->pw_change = pw->pw_change;
142
143
	/* class (ignored anyway) */
144
	__ypproto->pw_class = "";
145
146
	/* gecos */
147
	if (pw->pw_gecos && (pw->pw_gecos)[0]) {
148
		ptr = (char *)ALIGN(ptr);
149
		bcopy(pw->pw_gecos, ptr, strlen(pw->pw_gecos) + 1);
150
		__ypproto->pw_gecos = ptr;
151
		ptr += (strlen(pw->pw_gecos) + 1);
152
	} else
153
		__ypproto->pw_gecos = NULL;
154
155
	/* dir */
156
	if (pw->pw_dir && (pw->pw_dir)[0]) {
157
		ptr = (char *)ALIGN(ptr);
158
		bcopy(pw->pw_dir, ptr, strlen(pw->pw_dir) + 1);
159
		__ypproto->pw_dir = ptr;
160
		ptr += (strlen(pw->pw_dir) + 1);
161
	} else
162
		__ypproto->pw_dir = NULL;
163
164
	/* shell */
165
	if (pw->pw_shell && (pw->pw_shell)[0]) {
166
		ptr = (char *)ALIGN(ptr);
167
		bcopy(pw->pw_shell, ptr, strlen(pw->pw_shell) + 1);
168
		__ypproto->pw_shell = ptr;
169
		ptr += (strlen(pw->pw_shell) + 1);
170
	} else
171
		__ypproto->pw_shell = NULL;
172
173
	/* expire (ignored anyway) */
174
	__ypproto->pw_expire = pw->pw_expire;
175
176
	/* flags */
177
	*yp_pw_flagsp = flags;
178
}
179
180
static int
181
__ypparse(struct passwd *pw, char *s, int yp_pw_flags)
182
{
183
	char *bp, *cp, *endp;
184
	u_long ul;
185
	int count = 0;
186
187
	/* count the colons. */
188
	bp = s;
189
	while (*bp != '\0') {
190
		if (*bp++ == ':')
191
			count++;
192
	}
193
194
	/* since this is currently using strsep(), parse it first */
195
	bp = s;
196
	pw->pw_name = strsep(&bp, ":\n");
197
	pw->pw_passwd = strsep(&bp, ":\n");
198
	if (!(cp = strsep(&bp, ":\n")))
199
		return (1);
200
	ul = strtoul(cp, &endp, 10);
201
	if (endp == cp || *endp != '\0' || ul >= UID_MAX)
202
		return (1);
203
	pw->pw_uid = (uid_t)ul;
204
	if (!(cp = strsep(&bp, ":\n")))
205
		return (1);
206
	ul = strtoul(cp, &endp, 10);
207
	if (endp == cp || *endp != '\0' || ul >= GID_MAX)
208
		return (1);
209
	pw->pw_gid = (gid_t)ul;
210
	if (count == 9) {
211
		long l;
212
213
		/* If the ypserv gave us all the fields, use them. */
214
		pw->pw_class = strsep(&bp, ":\n");
215
		if (!(cp = strsep(&bp, ":\n")))
216
			return (1);
217
		l = strtol(cp, &endp, 10);
218
		if (endp == cp || *endp != '\0' || l >= INT_MAX || l <= INT_MIN)
219
			return (1);
220
		pw->pw_change = (time_t)l;
221
		if (!(cp = strsep(&bp, ":\n")))
222
			return (1);
223
		l = strtol(cp, &endp, 10);
224
		if (endp == cp || *endp != '\0' || l >= INT_MAX || l <= INT_MIN)
225
			return (1);
226
		pw->pw_expire = (time_t)l;
227
	} else {
228
		/* ..else it is a normal ypserv. */
229
		pw->pw_class = "";
230
		pw->pw_change = 0;
231
		pw->pw_expire = 0;
232
	}
233
	pw->pw_gecos = strsep(&bp, ":\n");
234
	pw->pw_dir = strsep(&bp, ":\n");
235
	pw->pw_shell = strsep(&bp, ":\n");
236
237
	/* now let the prototype override, if set. */
238
	if (__ypproto) {
239
		if (!(yp_pw_flags & _PASSWORD_NOUID))
240
			pw->pw_uid = __ypproto->pw_uid;
241
		if (!(yp_pw_flags & _PASSWORD_NOGID))
242
			pw->pw_gid = __ypproto->pw_gid;
243
		if (__ypproto->pw_gecos)
244
			pw->pw_gecos = __ypproto->pw_gecos;
245
		if (__ypproto->pw_dir)
246
			pw->pw_dir = __ypproto->pw_dir;
247
		if (__ypproto->pw_shell)
248
			pw->pw_shell = __ypproto->pw_shell;
249
	}
250
	return (0);
251
}
252
#endif
253
254
struct passwd *
255
getpwent(void)
256
{
257
#ifdef YP
258
	static char *name = NULL;
259
	char *map;
260
#endif
261
	char bf[1 + sizeof(_pw_keynum)];
262
	struct passwd *pw = NULL;
263
	DBT key;
264
265
	_THREAD_PRIVATE_MUTEX_LOCK(pw);
266
	if (!_pw_db && !__initdb(0))
267
		goto done;
268
269
#ifdef YP
270
	map = PASSWD_BYNAME;
271
272
	if (__getpwent_has_yppw == -1)
273
		__getpwent_has_yppw = __has_yppw();
274
275
again:
276
	if (__getpwent_has_yppw && (__ypmode != YPMODE_NONE)) {
277
		const char *user, *host, *dom;
278
		int keylen, datalen, r, s;
279
		char *key, *data = NULL;
280
281
		if (!__ypdomain) {
282
			if (_yp_check(&__ypdomain) == 0) {
283
				__ypmode = YPMODE_NONE;
284
				goto again;
285
			}
286
		}
287
		switch (__ypmode) {
288
		case YPMODE_FULL:
289
			if (__ypcurrent) {
290
				r = yp_next(__ypdomain, map,
291
				    __ypcurrent, __ypcurrentlen,
292
				    &key, &keylen, &data, &datalen);
293
				free(__ypcurrent);
294
				__ypcurrent = NULL;
295
				if (r != 0) {
296
					__ypmode = YPMODE_NONE;
297
					free(data);
298
					goto again;
299
				}
300
				__ypcurrent = key;
301
				__ypcurrentlen = keylen;
302
			} else {
303
				r = yp_first(__ypdomain, map,
304
				    &__ypcurrent, &__ypcurrentlen,
305
				    &data, &datalen);
306
				if (r != 0 ||
307
				    __ypcurrentlen > sizeof(__ypline)) {
308
					__ypmode = YPMODE_NONE;
309
					free(data);
310
					goto again;
311
				}
312
			}
313
			bcopy(data, __ypline, datalen);
314
			free(data);
315
			break;
316
		case YPMODE_NETGRP:
317
			s = getnetgrent(&host, &user, &dom);
318
			if (s == 0) {	/* end of group */
319
				endnetgrent();
320
				__ypmode = YPMODE_NONE;
321
				goto again;
322
			}
323
			if (user && *user) {
324
				r = yp_match(__ypdomain, map,
325
				    user, strlen(user), &data, &datalen);
326
			} else
327
				goto again;
328
			if (r != 0 ||
329
			    __ypcurrentlen > sizeof(__ypline)) {
330
				/*
331
				 * if the netgroup is invalid, keep looking
332
				 * as there may be valid users later on.
333
				 */
334
				free(data);
335
				goto again;
336
			}
337
			bcopy(data, __ypline, datalen);
338
			free(data);
339
			break;
340
		case YPMODE_USER:
341
			if (name) {
342
				r = yp_match(__ypdomain, map,
343
				    name, strlen(name), &data, &datalen);
344
				__ypmode = YPMODE_NONE;
345
				free(name);
346
				name = NULL;
347
				if (r != 0 ||
348
				    __ypcurrentlen > sizeof(__ypline)) {
349
					free(data);
350
					goto again;
351
				}
352
				bcopy(data, __ypline, datalen);
353
				free(data);
354
			} else {		/* XXX */
355
				__ypmode = YPMODE_NONE;
356
				goto again;
357
			}
358
			break;
359
		case YPMODE_NONE:
360
			/* NOTREACHED */
361
			break;
362
		}
363
364
		__ypline[datalen] = '\0';
365
		if (__ypparse(&_pw_passwd, __ypline, __yp_pw_flags))
366
			goto again;
367
		pw = &_pw_passwd;
368
		goto done;
369
	}
370
#endif
371
372
	++_pw_keynum;
373
	bf[0] = _PW_KEYBYNUM;
374
	bcopy((char *)&_pw_keynum, &bf[1], sizeof(_pw_keynum));
375
	key.data = (u_char *)bf;
376
	key.size = 1 + sizeof(_pw_keynum);
377
	if (__hashpw(&key, _pw_string, sizeof _pw_string,
378
	    &_pw_passwd, &_pw_flags)) {
379
#ifdef YP
380
		static long long __yppbuf[_PW_BUF_LEN / sizeof(long long)];
381
		const char *user, *host, *dom;
382
383
		/* if we don't have YP at all, don't bother. */
384
		if (__getpwent_has_yppw) {
385
			if (_pw_passwd.pw_name[0] == '+') {
386
				/* set the mode */
387
				switch (_pw_passwd.pw_name[1]) {
388
				case '\0':
389
					__ypmode = YPMODE_FULL;
390
					break;
391
				case '@':
392
					__ypmode = YPMODE_NETGRP;
393
					setnetgrent(_pw_passwd.pw_name + 2);
394
					break;
395
				default:
396
					__ypmode = YPMODE_USER;
397
					name = strdup(_pw_passwd.pw_name + 1);
398
					break;
399
				}
400
401
				__ypproto_set(&_pw_passwd, __yppbuf,
402
				    _pw_flags, &__yp_pw_flags);
403
				goto again;
404
			} else if (_pw_passwd.pw_name[0] == '-') {
405
				/* an attempted exclusion */
406
				switch (_pw_passwd.pw_name[1]) {
407
				case '\0':
408
					break;
409
				case '@':
410
					setnetgrent(_pw_passwd.pw_name + 2);
411
					while (getnetgrent(&host, &user, &dom)) {
412
						if (user && *user)
413
							__ypexclude_add(&__ypexhead,
414
							    user);
415
					}
416
					endnetgrent();
417
					break;
418
				default:
419
					__ypexclude_add(&__ypexhead,
420
					    _pw_passwd.pw_name + 1);
421
					break;
422
				}
423
				goto again;
424
			}
425
		}
426
#endif
427
		pw = &_pw_passwd;
428
		goto done;
429
	}
430
431
done:
432
	_THREAD_PRIVATE_MUTEX_UNLOCK(pw);
433
	return (pw);
434
}
435
436
#ifdef YP
437
/*
438
 * See if the YP token is in the database.  Only works if pwd_mkdb knows
439
 * about the token.
440
 */
441
static int
442
__has_yppw(void)
443
{
444
2360
	DBT key, data, pkey, pdata;
445
1180
	char bf[2];
446
447
1180
	key.data = (u_char *)_PW_YPTOKEN;
448
1180
	key.size = strlen(_PW_YPTOKEN);
449
450
	/* Pre-token database support. */
451
1180
	bf[0] = _PW_KEYBYNAME;
452
1180
	bf[1] = '+';
453
1180
	pkey.data = (u_char *)bf;
454
1180
	pkey.size = sizeof(bf);
455
456

2360
	if ((_pw_db->get)(_pw_db, &key, &data, 0) &&
457
1180
	    (_pw_db->get)(_pw_db, &pkey, &pdata, 0))
458
1180
		return (0);	/* No YP. */
459
	return (1);
460
1180
}
461
462
/*
463
 * See if there's a master.passwd map.
464
 */
465
static int
466
__has_ypmaster(void)
467
{
468
	int keylen, resultlen;
469
	char *key, *result;
470
	static int checked = -1;
471
	static uid_t saved_uid, saved_euid;
472
	uid_t uid = getuid(), euid = geteuid();
473
474
	/*
475
	 * Do not recheck IFF the saved UID and the saved
476
	 * EUID are the same. In all other cases, recheck.
477
	 */
478
	if (checked != -1 && saved_uid == uid && saved_euid == euid)
479
		return (checked);
480
481
	if (euid != 0) {
482
		saved_uid = uid;
483
		saved_euid = euid;
484
		checked = 0;
485
		return (checked);
486
	}
487
488
	if (!__ypdomain) {
489
		if (_yp_check(&__ypdomain) == 0) {
490
			saved_uid = uid;
491
			saved_euid = euid;
492
			checked = 0;
493
			return (checked);	/* No domain. */
494
		}
495
	}
496
497
	if (yp_first(__ypdomain, "master.passwd.byname",
498
	    &key, &keylen, &result, &resultlen)) {
499
		saved_uid = uid;
500
		saved_euid = euid;
501
		checked = 0;
502
		return (checked);
503
	}
504
	free(result);
505
	free(key);
506
507
	saved_uid = uid;
508
	saved_euid = euid;
509
	checked = 1;
510
	return (checked);
511
}
512
513
static struct passwd *
514
__yppwlookup(int lookup, char *name, uid_t uid, struct passwd *pw,
515
    char *buf, size_t buflen, int *flagsp)
516
{
517
	char bf[1 + _PW_NAME_LEN], *ypcurrent = NULL, *map = NULL;
518
	int yp_pw_flags = 0, ypcurrentlen, r, s = -1, pw_keynum;
519
	static long long yppbuf[_PW_BUF_LEN / sizeof(long long)];
520
	struct _ypexclude *ypexhead = NULL;
521
	const char *host, *user, *dom;
522
	DBT key;
523
524
	for (pw_keynum = 1; pw_keynum; pw_keynum++) {
525
		bf[0] = _PW_KEYBYNUM;
526
		bcopy((char *)&pw_keynum, &bf[1], sizeof(pw_keynum));
527
		key.data = (u_char *)bf;
528
		key.size = 1 + sizeof(pw_keynum);
529
		if (__hashpw(&key, buf, buflen, pw, flagsp) == 0)
530
			break;
531
		switch (pw->pw_name[0]) {
532
		case '+':
533
			if (!__ypdomain) {
534
				if (_yp_check(&__ypdomain) == 0)
535
					continue;
536
			}
537
			__ypproto_set(pw, yppbuf, *flagsp, &yp_pw_flags);
538
			if (!map) {
539
				if (lookup == LOOKUP_BYNAME) {
540
					if ((name = strdup(name)) == NULL) {
541
						pw = NULL;
542
						goto done;
543
					}
544
					map = PASSWD_BYNAME;
545
				} else {
546
					if (asprintf(&name, "%u", uid) == -1) {
547
						pw = NULL;
548
						goto done;
549
					}
550
					map = PASSWD_BYUID;
551
				}
552
			}
553
554
			switch (pw->pw_name[1]) {
555
			case '\0':
556
				free(ypcurrent);
557
				ypcurrent = NULL;
558
				r = yp_match(__ypdomain, map,
559
				    name, strlen(name),
560
				    &ypcurrent, &ypcurrentlen);
561
				if (r != 0 || ypcurrentlen > buflen) {
562
					free(ypcurrent);
563
					ypcurrent = NULL;
564
					continue;
565
				}
566
				break;
567
			case '@':
568
pwnam_netgrp:
569
				free(ypcurrent);
570
				ypcurrent = NULL;
571
				if (s == -1)	/* first time */
572
					setnetgrent(pw->pw_name + 2);
573
				s = getnetgrent(&host, &user, &dom);
574
				if (s == 0) {	/* end of group */
575
					endnetgrent();
576
					s = -1;
577
					continue;
578
				} else {
579
					if (user && *user) {
580
						r = yp_match(__ypdomain, map,
581
						    user, strlen(user),
582
						    &ypcurrent, &ypcurrentlen);
583
					} else
584
						goto pwnam_netgrp;
585
					if (r != 0 || ypcurrentlen > buflen) {
586
						free(ypcurrent);
587
						ypcurrent = NULL;
588
						/*
589
						 * just because this
590
						 * user is bad, doesn't
591
						 * mean they all are.
592
						 */
593
						goto pwnam_netgrp;
594
					}
595
				}
596
				break;
597
			default:
598
				free(ypcurrent);
599
				ypcurrent = NULL;
600
				user = pw->pw_name + 1;
601
				r = yp_match(__ypdomain, map,
602
				    user, strlen(user),
603
				    &ypcurrent, &ypcurrentlen);
604
				if (r != 0 || ypcurrentlen > buflen) {
605
					free(ypcurrent);
606
					ypcurrent = NULL;
607
					continue;
608
				}
609
				break;
610
			}
611
			bcopy(ypcurrent, buf, ypcurrentlen);
612
			buf[ypcurrentlen] = '\0';
613
			if (__ypparse(pw, buf, yp_pw_flags) ||
614
			    __ypexclude_is(&ypexhead, pw->pw_name)) {
615
				if (s == 1)	/* inside netgrp */
616
					goto pwnam_netgrp;
617
				continue;
618
			}
619
			break;
620
		case '-':
621
			/* attempted exclusion */
622
			switch (pw->pw_name[1]) {
623
			case '\0':
624
				break;
625
			case '@':
626
				setnetgrent(pw->pw_name + 2);
627
				while (getnetgrent(&host, &user, &dom)) {
628
					if (user && *user)
629
						__ypexclude_add(&ypexhead, user);
630
				}
631
				endnetgrent();
632
				break;
633
			default:
634
				__ypexclude_add(&ypexhead, pw->pw_name + 1);
635
				break;
636
			}
637
			break;
638
		}
639
		if ((lookup == LOOKUP_BYUID && pw->pw_uid == uid) ||
640
		    (lookup == LOOKUP_BYNAME && strcmp(pw->pw_name, name) == 0))
641
			goto done;
642
		if (s == 1)	/* inside netgrp */
643
			goto pwnam_netgrp;
644
		continue;
645
	}
646
	pw = NULL;
647
done:
648
	__ypexclude_free(&ypexhead);
649
	__ypproto = NULL;
650
	free(ypcurrent);
651
	ypcurrent = NULL;
652
	if (map)
653
		free(name);
654
	return (pw);
655
}
656
#endif /* YP */
657
658
static struct passwd *
659
_pwhashbyname(const char *name, char *buf, size_t buflen, struct passwd *pw,
660
    int *flagsp)
661
{
662
1626
	char bf[1 + _PW_NAME_LEN];
663
	size_t len;
664
813
	DBT key;
665
	int r;
666
667
813
	len = strlen(name);
668
813
	if (len > _PW_NAME_LEN)
669
		return (NULL);
670
813
	bf[0] = _PW_KEYBYNAME;
671
813
	bcopy(name, &bf[1], MINIMUM(len, _PW_NAME_LEN));
672
813
	key.data = (u_char *)bf;
673
813
	key.size = 1 + MINIMUM(len, _PW_NAME_LEN);
674
813
	r = __hashpw(&key, buf, buflen, pw, flagsp);
675
813
	if (r)
676
763
		return (pw);
677
50
	return (NULL);
678
813
}
679
680
static struct passwd *
681
_pwhashbyuid(uid_t uid, char *buf, size_t buflen, struct passwd *pw,
682
    int *flagsp)
683
{
684
367
	char bf[1 + sizeof(int)];
685
367
	DBT key;
686
	int r;
687
688
367
	bf[0] = _PW_KEYBYUID;
689
367
	bcopy(&uid, &bf[1], sizeof(uid));
690
367
	key.data = (u_char *)bf;
691
367
	key.size = 1 + sizeof(uid);
692
367
	r = __hashpw(&key, buf, buflen, pw, flagsp);
693
367
	if (r)
694
367
		return (pw);
695
	return (NULL);
696
367
}
697
698
static int
699
getpwnam_internal(const char *name, struct passwd *pw, char *buf, size_t buflen,
700
    struct passwd **pwretp, int shadow)
701
{
702
	struct passwd *pwret = NULL;
703
1626
	int flags = 0, *flagsp;
704
	int my_errno = 0;
705
	int saved_errno, tmp_errno;
706
707
813
	_THREAD_PRIVATE_MUTEX_LOCK(pw);
708
813
	saved_errno = errno;
709
813
	errno = 0;
710

1626
	if (!_pw_db && !__initdb(shadow))
711
		goto fail;
712
713
813
	if (pw == &_pw_passwd)
714
813
		flagsp = &_pw_flags;
715
	else
716
		flagsp = &flags;
717
718
#ifdef YP
719
813
	if (__has_yppw())
720
		pwret = __yppwlookup(LOOKUP_BYNAME, (char *)name, 0, pw,
721
		    buf, buflen, flagsp);
722
#endif /* YP */
723
813
	if (!pwret)
724
813
		pwret = _pwhashbyname(name, buf, buflen, pw, flagsp);
725
726
813
	if (!_pw_stayopen) {
727
713
		tmp_errno = errno;
728
713
		(void)(_pw_db->close)(_pw_db);
729
713
		_pw_db = NULL;
730
713
		errno = tmp_errno;
731
713
	}
732
fail:
733
813
	if (pwretp)
734
813
		*pwretp = pwret;
735
813
	if (pwret == NULL)
736
50
		my_errno = errno;
737
813
	errno = saved_errno;
738
813
	_THREAD_PRIVATE_MUTEX_UNLOCK(pw);
739
813
	return (my_errno);
740
813
}
741
742
int
743
getpwnam_r(const char *name, struct passwd *pw, char *buf, size_t buflen,
744
    struct passwd **pwretp)
745
{
746
1626
	return getpwnam_internal(name, pw, buf, buflen, pwretp, 0);
747
}
748
DEF_WEAK(getpwnam_r);
749
750
struct passwd *
751
getpwnam(const char *name)
752
{
753
1626
	struct passwd *pw = NULL;
754
	int my_errno;
755
756
813
	my_errno = getpwnam_r(name, &_pw_passwd, _pw_string,
757
	    sizeof _pw_string, &pw);
758
813
	if (my_errno) {
759
		pw = NULL;
760
		errno = my_errno;
761
	}
762
1626
	return (pw);
763
813
}
764
765
struct passwd *
766
getpwnam_shadow(const char *name)
767
{
768
	struct passwd *pw = NULL;
769
	int my_errno;
770
771
	my_errno = getpwnam_internal(name, &_pw_passwd, _pw_string,
772
	    sizeof _pw_string, &pw, 1);
773
	if (my_errno) {
774
		pw = NULL;
775
		errno = my_errno;
776
	}
777
	return (pw);
778
}
779
DEF_WEAK(getpwnam_shadow);
780
781
static int
782
getpwuid_internal(uid_t uid, struct passwd *pw, char *buf, size_t buflen,
783
    struct passwd **pwretp, int shadow)
784
{
785
	struct passwd *pwret = NULL;
786
734
	int flags = 0, *flagsp;
787
	int my_errno = 0;
788
	int saved_errno, tmp_errno;
789
790
367
	_THREAD_PRIVATE_MUTEX_LOCK(pw);
791
367
	saved_errno = errno;
792
367
	errno = 0;
793

724
	if (!_pw_db && !__initdb(shadow))
794
		goto fail;
795
796
367
	if (pw == &_pw_passwd)
797
		flagsp = &_pw_flags;
798
	else
799
		flagsp = &flags;
800
801
#ifdef YP
802
367
	if (__has_yppw())
803
		pwret = __yppwlookup(LOOKUP_BYUID, NULL, uid, pw,
804
		    buf, buflen, flagsp);
805
#endif /* YP */
806
367
	if (!pwret)
807
367
		pwret = _pwhashbyuid(uid, buf, buflen, pw, flagsp);
808
809
367
	if (!_pw_stayopen) {
810
357
		tmp_errno = errno;
811
357
		(void)(_pw_db->close)(_pw_db);
812
357
		_pw_db = NULL;
813
357
		errno = tmp_errno;
814
357
	}
815
fail:
816
367
	if (pwretp)
817
367
		*pwretp = pwret;
818
367
	if (pwret == NULL)
819
		my_errno = errno;
820
367
	errno = saved_errno;
821
367
	_THREAD_PRIVATE_MUTEX_UNLOCK(pw);
822
367
	return (my_errno);
823
367
}
824
825
826
int
827
getpwuid_r(uid_t uid, struct passwd *pw, char *buf, size_t buflen,
828
    struct passwd **pwretp)
829
{
830
734
	return getpwuid_internal(uid, pw, buf, buflen, pwretp, 0);
831
}
832
DEF_WEAK(getpwuid_r);
833
834
struct passwd *
835
getpwuid(uid_t uid)
836
{
837
	struct passwd *pw = NULL;
838
	int my_errno;
839
840
	my_errno = getpwuid_r(uid, &_pw_passwd, _pw_string,
841
	    sizeof _pw_string, &pw);
842
	if (my_errno) {
843
		pw = NULL;
844
		errno = my_errno;
845
	}
846
	return (pw);
847
}
848
849
struct passwd *
850
getpwuid_shadow(uid_t uid)
851
{
852
	struct passwd *pw = NULL;
853
	int my_errno;
854
855
	my_errno = getpwuid_internal(uid, &_pw_passwd, _pw_string,
856
	    sizeof _pw_string, &pw, 1);
857
	if (my_errno) {
858
		pw = NULL;
859
		errno = my_errno;
860
	}
861
	return (pw);
862
}
863
DEF_WEAK(getpwuid_shadow);
864
865
int
866
setpassent(int stayopen)
867
{
868
200
	_THREAD_PRIVATE_MUTEX_LOCK(pw);
869
100
	_pw_keynum = 0;
870
100
	_pw_stayopen = stayopen;
871
#ifdef YP
872
100
	__ypmode = YPMODE_NONE;
873
100
	free(__ypcurrent);
874
100
	__ypcurrent = NULL;
875
100
	__ypexclude_free(&__ypexhead);
876
100
	__ypproto = NULL;
877
#endif
878
100
	_THREAD_PRIVATE_MUTEX_UNLOCK(pw);
879
100
	return (1);
880
}
881
DEF_WEAK(setpassent);
882
883
void
884
setpwent(void)
885
{
886
	(void) setpassent(0);
887
}
888
889
void
890
endpwent(void)
891
{
892
	int saved_errno;
893
894
84
	_THREAD_PRIVATE_MUTEX_LOCK(pw);
895
42
	saved_errno = errno;
896
42
	_pw_keynum = 0;
897
42
	if (_pw_db) {
898
		(void)(_pw_db->close)(_pw_db);
899
		_pw_db = NULL;
900
	}
901
#ifdef YP
902
42
	__ypmode = YPMODE_NONE;
903
42
	free(__ypcurrent);
904
42
	__ypcurrent = NULL;
905
42
	__ypexclude_free(&__ypexhead);
906
42
	__ypproto = NULL;
907
#endif
908
42
	errno = saved_errno;
909
42
	_THREAD_PRIVATE_MUTEX_UNLOCK(pw);
910
42
}
911
912
static int
913
__initdb(int shadow)
914
{
915
	static int warned;
916
2340
	int saved_errno = errno;
917
918
#ifdef YP
919
	/*
920
	 * Hint to the kernel that a passwd database operation is happening.
921
	 */
922
1170
	(void)access("/var/run/ypbind.lock", R_OK);
923
924
1170
	__ypmode = YPMODE_NONE;
925
1170
	__getpwent_has_yppw = -1;
926
#endif
927
1170
	if (shadow)
928
		_pw_db = dbopen(_PATH_SMP_DB, O_RDONLY, 0, DB_HASH, NULL);
929
1170
	if (!_pw_db)
930
1170
	    _pw_db = dbopen(_PATH_MP_DB, O_RDONLY, 0, DB_HASH, NULL);
931
1170
	if (_pw_db) {
932
1170
		errno = saved_errno;
933
1170
		return (1);
934
	}
935
	if (!warned) {
936
		saved_errno = errno;
937
		errno = saved_errno;
938
		warned = 1;
939
	}
940
	return (0);
941
1170
}
942
943
static int
944
__hashpw(DBT *key, char *buf, size_t buflen, struct passwd *pw,
945
    int *flagsp)
946
{
947
	char *p, *t;
948
2360
	DBT data;
949
950
1180
	if ((_pw_db->get)(_pw_db, key, &data, 0))
951
50
		return (0);
952
1130
	p = (char *)data.data;
953
1130
	if (data.size > buflen) {
954
		errno = ERANGE;
955
		return (0);
956
	}
957
958
	t = buf;
959
#define	EXPAND(e)	e = t; while ((*t++ = *p++));
960
9066
	EXPAND(pw->pw_name);
961
3390
	EXPAND(pw->pw_passwd);
962
1130
	bcopy(p, (char *)&pw->pw_uid, sizeof(int));
963
1130
	p += sizeof(int);
964
1130
	bcopy(p, (char *)&pw->pw_gid, sizeof(int));
965
1130
	p += sizeof(int);
966
1130
	bcopy(p, (char *)&pw->pw_change, sizeof(time_t));
967
1130
	p += sizeof(time_t);
968
5374
	EXPAND(pw->pw_class);
969
15184
	EXPAND(pw->pw_gecos);
970
11121
	EXPAND(pw->pw_dir);
971
14355
	EXPAND(pw->pw_shell);
972
1130
	bcopy(p, (char *)&pw->pw_expire, sizeof(time_t));
973
1130
	p += sizeof(time_t);
974
975
	/* See if there's any data left.  If so, read in flags. */
976
1130
	if (data.size > (p - (char *)data.data)) {
977
1130
		bcopy(p, (char *)flagsp, sizeof(int));
978
		p += sizeof(int);
979
1130
	} else
980
		*flagsp = _PASSWORD_NOUID|_PASSWORD_NOGID;	/* default */
981
1130
	return (1);
982
1180
}