File: | src/lib/libc/gen/getpwent.c |
Warning: | line 414, column 3 Array subscript is undefined |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* $OpenBSD: getpwent.c,v 1.66 2022/08/02 17:00:15 deraadt 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/types.h> | |||
34 | #include <sys/mman.h> | |||
35 | #include <fcntl.h> | |||
36 | #include <db.h> | |||
37 | #include <syslog.h> | |||
38 | #include <pwd.h> | |||
39 | #include <errno(*__errno()).h> | |||
40 | #include <unistd.h> | |||
41 | #include <stdbool.h> | |||
42 | #include <stdlib.h> | |||
43 | #include <string.h> | |||
44 | #include <limits.h> | |||
45 | #include <netgroup.h> | |||
46 | #ifdef YP1 | |||
47 | #include <stdio.h> | |||
48 | #include <rpc/rpc.h> | |||
49 | #include <rpcsvc/yp.h> | |||
50 | #include <rpcsvc/ypclnt.h> | |||
51 | #include "ypinternal.h" | |||
52 | #include "ypexclude.h" | |||
53 | #endif | |||
54 | #include "thread_private.h" | |||
55 | ||||
56 | #define MINIMUM(a, b)(((a) < (b)) ? (a) : (b)) (((a) < (b)) ? (a) : (b)) | |||
57 | ||||
58 | struct pw_storage { | |||
59 | struct passwd pw; | |||
60 | uid_t uid; | |||
61 | char name[_PW_NAME_LEN31 + 1]; | |||
62 | char pwbuf[_PW_BUF_LEN1024]; | |||
63 | }; | |||
64 | ||||
65 | _THREAD_PRIVATE_KEY(pw)static void *_thread_tagname_pw; | |||
66 | ||||
67 | static DB *_pw_db; /* password database */ | |||
68 | ||||
69 | /* mmap'd password storage */ | |||
70 | static struct pw_storage *_pw_storage = MAP_FAILED((void *)-1); | |||
71 | ||||
72 | /* Following are used only by setpwent(), getpwent(), and endpwent() */ | |||
73 | static int _pw_keynum; /* key counter */ | |||
74 | static int _pw_stayopen; /* keep fd's open */ | |||
75 | static int _pw_flags; /* password flags */ | |||
76 | ||||
77 | static int __hashpw(DBT *, char *buf, size_t buflen, struct passwd *, int *); | |||
78 | static int __initdb(int); | |||
79 | static struct passwd *_pwhashbyname(const char *name, char *buf, | |||
80 | size_t buflen, struct passwd *pw, int *); | |||
81 | static struct passwd *_pwhashbyuid(uid_t uid, char *buf, | |||
82 | size_t buflen, struct passwd *pw, int *); | |||
83 | ||||
84 | #ifdef YP1 | |||
85 | static char *__ypdomain; | |||
86 | ||||
87 | /* Following are used only by setpwent(), getpwent(), and endpwent() */ | |||
88 | enum _ypmode { YPMODE_NONE, YPMODE_FULL, YPMODE_USER, YPMODE_NETGRP }; | |||
89 | static enum _ypmode __ypmode; | |||
90 | static char *__ypcurrent; | |||
91 | static int __ypcurrentlen; | |||
92 | static int __yp_pw_flags; | |||
93 | static int __getpwent_has_yppw = -1; | |||
94 | static struct _ypexclude *__ypexhead; | |||
95 | ||||
96 | static int __has_yppw(void); | |||
97 | static int __has_ypmaster(void); | |||
98 | static int __ypparse(struct passwd *pw, char *s, int); | |||
99 | ||||
100 | #define LOOKUP_BYNAME0 0 | |||
101 | #define LOOKUP_BYUID1 1 | |||
102 | static struct passwd *__yppwlookup(int, char *, uid_t, struct passwd *, | |||
103 | char *, size_t, int *); | |||
104 | ||||
105 | /* macro for deciding which YP maps to use. */ | |||
106 | #define PASSWD_BYNAME(__has_ypmaster() ? "master.passwd.byname" : "passwd.byname") \ | |||
107 | (__has_ypmaster() ? "master.passwd.byname" : "passwd.byname") | |||
108 | #define PASSWD_BYUID(__has_ypmaster() ? "master.passwd.byuid" : "passwd.byuid") \ | |||
109 | (__has_ypmaster() ? "master.passwd.byuid" : "passwd.byuid") | |||
110 | ||||
111 | static struct passwd *__ypproto; | |||
112 | ||||
113 | static void __ypproto_set(struct passwd *, struct pw_storage *, int, int *); | |||
114 | ||||
115 | static void | |||
116 | __ypproto_set(struct passwd *pw, struct pw_storage *buf, int flags, | |||
117 | int *yp_pw_flagsp) | |||
118 | { | |||
119 | char *ptr = buf->pwbuf; | |||
120 | __ypproto = &buf->pw; | |||
121 | ||||
122 | /* name */ | |||
123 | if (pw->pw_name && (pw->pw_name)[0]) { | |||
124 | bcopy(pw->pw_name, ptr, strlen(pw->pw_name) + 1); | |||
125 | __ypproto->pw_name = ptr; | |||
126 | ptr += (strlen(pw->pw_name) + 1); | |||
127 | } else | |||
128 | __ypproto->pw_name = NULL((void *)0); | |||
129 | ||||
130 | /* password */ | |||
131 | if (pw->pw_passwd && (pw->pw_passwd)[0]) { | |||
132 | bcopy(pw->pw_passwd, ptr, strlen(pw->pw_passwd) + 1); | |||
133 | __ypproto->pw_passwd = ptr; | |||
134 | ptr += (strlen(pw->pw_passwd) + 1); | |||
135 | } else | |||
136 | __ypproto->pw_passwd = NULL((void *)0); | |||
137 | ||||
138 | /* uid */ | |||
139 | __ypproto->pw_uid = pw->pw_uid; | |||
140 | ||||
141 | /* gid */ | |||
142 | __ypproto->pw_gid = pw->pw_gid; | |||
143 | ||||
144 | /* change (ignored anyway) */ | |||
145 | __ypproto->pw_change = pw->pw_change; | |||
146 | ||||
147 | /* class (ignored anyway) */ | |||
148 | __ypproto->pw_class = ""; | |||
149 | ||||
150 | /* gecos */ | |||
151 | if (pw->pw_gecos && (pw->pw_gecos)[0]) { | |||
152 | bcopy(pw->pw_gecos, ptr, strlen(pw->pw_gecos) + 1); | |||
153 | __ypproto->pw_gecos = ptr; | |||
154 | ptr += (strlen(pw->pw_gecos) + 1); | |||
155 | } else | |||
156 | __ypproto->pw_gecos = NULL((void *)0); | |||
157 | ||||
158 | /* dir */ | |||
159 | if (pw->pw_dir && (pw->pw_dir)[0]) { | |||
160 | bcopy(pw->pw_dir, ptr, strlen(pw->pw_dir) + 1); | |||
161 | __ypproto->pw_dir = ptr; | |||
162 | ptr += (strlen(pw->pw_dir) + 1); | |||
163 | } else | |||
164 | __ypproto->pw_dir = NULL((void *)0); | |||
165 | ||||
166 | /* shell */ | |||
167 | if (pw->pw_shell && (pw->pw_shell)[0]) { | |||
168 | bcopy(pw->pw_shell, ptr, strlen(pw->pw_shell) + 1); | |||
169 | __ypproto->pw_shell = ptr; | |||
170 | ptr += (strlen(pw->pw_shell) + 1); | |||
171 | } else | |||
172 | __ypproto->pw_shell = NULL((void *)0); | |||
173 | ||||
174 | /* expire (ignored anyway) */ | |||
175 | __ypproto->pw_expire = pw->pw_expire; | |||
176 | ||||
177 | /* flags */ | |||
178 | *yp_pw_flagsp = flags; | |||
179 | } | |||
180 | ||||
181 | static int | |||
182 | __ypparse(struct passwd *pw, char *s, int yp_pw_flags) | |||
183 | { | |||
184 | char *bp, *cp, *endp; | |||
185 | u_long ul; | |||
186 | int count = 0; | |||
187 | ||||
188 | /* count the colons. */ | |||
189 | bp = s; | |||
190 | while (*bp != '\0') { | |||
191 | if (*bp++ == ':') | |||
192 | count++; | |||
193 | } | |||
194 | ||||
195 | /* since this is currently using strsep(), parse it first */ | |||
196 | bp = s; | |||
197 | pw->pw_name = strsep(&bp, ":\n"); | |||
198 | pw->pw_passwd = strsep(&bp, ":\n"); | |||
199 | if (!(cp = strsep(&bp, ":\n"))) | |||
200 | return (1); | |||
201 | ul = strtoul(cp, &endp, 10); | |||
202 | if (endp == cp || *endp != '\0' || ul >= UID_MAX0xffffffffU) | |||
203 | return (1); | |||
204 | pw->pw_uid = (uid_t)ul; | |||
205 | if (!(cp = strsep(&bp, ":\n"))) | |||
206 | return (1); | |||
207 | ul = strtoul(cp, &endp, 10); | |||
208 | if (endp == cp || *endp != '\0' || ul >= GID_MAX0xffffffffU) | |||
209 | return (1); | |||
210 | pw->pw_gid = (gid_t)ul; | |||
211 | if (count == 9) { | |||
212 | long l; | |||
213 | ||||
214 | /* If the ypserv gave us all the fields, use them. */ | |||
215 | pw->pw_class = strsep(&bp, ":\n"); | |||
216 | if (!(cp = strsep(&bp, ":\n"))) | |||
217 | return (1); | |||
218 | l = strtol(cp, &endp, 10); | |||
219 | if (endp == cp || *endp != '\0' || l >= INT_MAX0x7fffffff || l <= INT_MIN(-0x7fffffff-1)) | |||
220 | return (1); | |||
221 | pw->pw_change = (time_t)l; | |||
222 | if (!(cp = strsep(&bp, ":\n"))) | |||
223 | return (1); | |||
224 | l = strtol(cp, &endp, 10); | |||
225 | if (endp == cp || *endp != '\0' || l >= INT_MAX0x7fffffff || l <= INT_MIN(-0x7fffffff-1)) | |||
226 | return (1); | |||
227 | pw->pw_expire = (time_t)l; | |||
228 | } else { | |||
229 | /* ..else it is a normal ypserv. */ | |||
230 | pw->pw_class = ""; | |||
231 | pw->pw_change = 0; | |||
232 | pw->pw_expire = 0; | |||
233 | } | |||
234 | pw->pw_gecos = strsep(&bp, ":\n"); | |||
235 | pw->pw_dir = strsep(&bp, ":\n"); | |||
236 | pw->pw_shell = strsep(&bp, ":\n"); | |||
237 | ||||
238 | /* now let the prototype override, if set. */ | |||
239 | if (__ypproto) { | |||
240 | if (!(yp_pw_flags & _PASSWORD_NOUID0x01)) | |||
241 | pw->pw_uid = __ypproto->pw_uid; | |||
242 | if (!(yp_pw_flags & _PASSWORD_NOGID0x02)) | |||
243 | pw->pw_gid = __ypproto->pw_gid; | |||
244 | if (__ypproto->pw_gecos) | |||
245 | pw->pw_gecos = __ypproto->pw_gecos; | |||
246 | if (__ypproto->pw_dir) | |||
247 | pw->pw_dir = __ypproto->pw_dir; | |||
248 | if (__ypproto->pw_shell) | |||
249 | pw->pw_shell = __ypproto->pw_shell; | |||
250 | } | |||
251 | return (0); | |||
252 | } | |||
253 | #endif | |||
254 | ||||
255 | static struct passwd * | |||
256 | __get_pw_buf(char **bufp, size_t *buflenp, uid_t uid, const char *name) | |||
257 | { | |||
258 | bool_Bool remap = true1; | |||
259 | ||||
260 | /* Unmap the old buffer unless we are looking up the same uid/name */ | |||
261 | if (_pw_storage != MAP_FAILED((void *)-1)) { | |||
262 | if (name != NULL((void *)0)) { | |||
263 | if (strcmp(_pw_storage->name, name) == 0) { | |||
264 | #ifdef PWDEBUG | |||
265 | struct syslog_data sdata = SYSLOG_DATA_INIT{0, (const char *)0, (1<<3), 0xff}; | |||
266 | syslog_r(LOG_CRIT2 | LOG_CONS0x02, &sdata, | |||
267 | "repeated passwd lookup of user \"%s\"", | |||
268 | name); | |||
269 | #endif | |||
270 | remap = false0; | |||
271 | } | |||
272 | } else if (uid != (uid_t)-1) { | |||
273 | if (_pw_storage->uid == uid) { | |||
274 | #ifdef PWDEBUG | |||
275 | struct syslog_data sdata = SYSLOG_DATA_INIT{0, (const char *)0, (1<<3), 0xff}; | |||
276 | syslog_r(LOG_CRIT2 | LOG_CONS0x02, &sdata, | |||
277 | "repeated passwd lookup of uid %u", | |||
278 | uid); | |||
279 | #endif | |||
280 | remap = false0; | |||
281 | } | |||
282 | } | |||
283 | if (remap) | |||
284 | munmap(_pw_storage, sizeof(*_pw_storage)); | |||
285 | } | |||
286 | ||||
287 | if (remap) { | |||
288 | _pw_storage = mmap(NULL((void *)0), sizeof(*_pw_storage), | |||
289 | PROT_READ0x01|PROT_WRITE0x02, MAP_PRIVATE0x0002|MAP_ANON0x1000, -1, 0); | |||
290 | if (_pw_storage == MAP_FAILED((void *)-1)) | |||
291 | return NULL((void *)0); | |||
292 | if (name != NULL((void *)0)) | |||
293 | strlcpy(_pw_storage->name, name, sizeof(_pw_storage->name)); | |||
294 | _pw_storage->uid = uid; | |||
295 | } | |||
296 | ||||
297 | *bufp = _pw_storage->pwbuf; | |||
298 | *buflenp = sizeof(_pw_storage->pwbuf); | |||
299 | return &_pw_storage->pw; | |||
300 | } | |||
301 | ||||
302 | struct passwd * | |||
303 | getpwent(void) | |||
304 | { | |||
305 | #ifdef YP1 | |||
306 | static char *name = NULL((void *)0); | |||
307 | char *map; | |||
308 | #endif | |||
309 | char bf[1 + sizeof(_pw_keynum)]; | |||
310 | struct passwd *pw, *ret = NULL((void *)0); | |||
311 | char *pwbuf; | |||
312 | size_t buflen; | |||
313 | DBT key; | |||
314 | ||||
315 | _THREAD_PRIVATE_MUTEX_LOCK(pw)do { if (_thread_cb.tc_tag_lock != ((void *)0)) _thread_cb.tc_tag_lock (&(_thread_tagname_pw)); } while (0); | |||
| ||||
316 | if (!_pw_db && !__initdb(0)) | |||
317 | goto done; | |||
318 | ||||
319 | /* Allocate space for struct and strings, unmapping the old. */ | |||
320 | if ((pw = __get_pw_buf(&pwbuf, &buflen, -1, NULL((void *)0))) == NULL((void *)0)) | |||
321 | goto done; | |||
322 | ||||
323 | #ifdef YP1 | |||
324 | map = PASSWD_BYNAME(__has_ypmaster() ? "master.passwd.byname" : "passwd.byname"); | |||
325 | ||||
326 | if (__getpwent_has_yppw == -1) | |||
327 | __getpwent_has_yppw = __has_yppw(); | |||
328 | ||||
329 | again: | |||
330 | if (__getpwent_has_yppw && (__ypmode != YPMODE_NONE)) { | |||
331 | const char *user, *host, *dom; | |||
332 | int keylen, datalen, r, s; | |||
333 | char *key, *data = NULL((void *)0); | |||
334 | ||||
335 | if (!__ypdomain) | |||
336 | yp_get_default_domain(&__ypdomain); | |||
337 | switch (__ypmode) { | |||
338 | case YPMODE_FULL: | |||
339 | if (__ypcurrent) { | |||
340 | r = yp_next(__ypdomain, map, | |||
341 | __ypcurrent, __ypcurrentlen, | |||
342 | &key, &keylen, &data, &datalen); | |||
343 | free(__ypcurrent); | |||
344 | __ypcurrent = NULL((void *)0); | |||
345 | if (r != 0) { | |||
346 | __ypmode = YPMODE_NONE; | |||
347 | free(data); | |||
348 | goto again; | |||
349 | } | |||
350 | __ypcurrent = key; | |||
351 | __ypcurrentlen = keylen; | |||
352 | } else { | |||
353 | r = yp_first(__ypdomain, map, | |||
354 | &__ypcurrent, &__ypcurrentlen, | |||
355 | &data, &datalen); | |||
356 | if (r != 0 || | |||
357 | __ypcurrentlen > buflen) { | |||
358 | __ypmode = YPMODE_NONE; | |||
359 | free(data); | |||
360 | goto again; | |||
361 | } | |||
362 | } | |||
363 | bcopy(data, pwbuf, datalen); | |||
364 | free(data); | |||
365 | break; | |||
366 | case YPMODE_NETGRP: | |||
367 | s = getnetgrent(&host, &user, &dom); | |||
368 | if (s == 0) { /* end of group */ | |||
369 | endnetgrent(); | |||
370 | __ypmode = YPMODE_NONE; | |||
371 | goto again; | |||
372 | } | |||
373 | if (user && *user) { | |||
374 | r = yp_match(__ypdomain, map, | |||
375 | user, strlen(user), &data, &datalen); | |||
376 | } else | |||
377 | goto again; | |||
378 | if (r != 0 || | |||
379 | __ypcurrentlen > buflen) { | |||
380 | /* | |||
381 | * if the netgroup is invalid, keep looking | |||
382 | * as there may be valid users later on. | |||
383 | */ | |||
384 | free(data); | |||
385 | goto again; | |||
386 | } | |||
387 | bcopy(data, pwbuf, datalen); | |||
388 | free(data); | |||
389 | break; | |||
390 | case YPMODE_USER: | |||
391 | if (name) { | |||
392 | r = yp_match(__ypdomain, map, | |||
393 | name, strlen(name), &data, &datalen); | |||
394 | __ypmode = YPMODE_NONE; | |||
395 | free(name); | |||
396 | name = NULL((void *)0); | |||
397 | if (r != 0 || | |||
398 | __ypcurrentlen > buflen) { | |||
399 | free(data); | |||
400 | goto again; | |||
401 | } | |||
402 | bcopy(data, pwbuf, datalen); | |||
403 | free(data); | |||
404 | } else { /* XXX */ | |||
405 | __ypmode = YPMODE_NONE; | |||
406 | goto again; | |||
407 | } | |||
408 | break; | |||
409 | case YPMODE_NONE: | |||
410 | /* NOTREACHED */ | |||
411 | break; | |||
412 | } | |||
413 | ||||
414 | pwbuf[datalen] = '\0'; | |||
| ||||
415 | if (__ypparse(pw, pwbuf, __yp_pw_flags)) | |||
416 | goto again; | |||
417 | ret = pw; | |||
418 | goto done; | |||
419 | } | |||
420 | #endif | |||
421 | ||||
422 | ++_pw_keynum; | |||
423 | bf[0] = _PW_KEYBYNUM'2'; | |||
424 | bcopy((char *)&_pw_keynum, &bf[1], sizeof(_pw_keynum)); | |||
425 | key.data = (u_char *)bf; | |||
426 | key.size = 1 + sizeof(_pw_keynum); | |||
427 | if (__hashpw(&key, pwbuf, buflen, pw, &_pw_flags)) { | |||
428 | #ifdef YP1 | |||
429 | static struct pw_storage __yppbuf; | |||
430 | const char *user, *host, *dom; | |||
431 | ||||
432 | /* if we don't have YP at all, don't bother. */ | |||
433 | if (__getpwent_has_yppw) { | |||
434 | if (pw->pw_name[0] == '+') { | |||
435 | /* set the mode */ | |||
436 | switch (pw->pw_name[1]) { | |||
437 | case '\0': | |||
438 | __ypmode = YPMODE_FULL; | |||
439 | break; | |||
440 | case '@': | |||
441 | __ypmode = YPMODE_NETGRP; | |||
442 | setnetgrent(pw->pw_name + 2); | |||
443 | break; | |||
444 | default: | |||
445 | __ypmode = YPMODE_USER; | |||
446 | name = strdup(pw->pw_name + 1); | |||
447 | break; | |||
448 | } | |||
449 | ||||
450 | __ypproto_set(pw, &__yppbuf, _pw_flags, | |||
451 | &__yp_pw_flags); | |||
452 | goto again; | |||
453 | } else if (pw->pw_name[0] == '-') { | |||
454 | /* an attempted exclusion */ | |||
455 | switch (pw->pw_name[1]) { | |||
456 | case '\0': | |||
457 | break; | |||
458 | case '@': | |||
459 | setnetgrent(pw->pw_name + 2); | |||
460 | while (getnetgrent(&host, &user, &dom)) { | |||
461 | if (user && *user) | |||
462 | __ypexclude_add(&__ypexhead, | |||
463 | user); | |||
464 | } | |||
465 | endnetgrent(); | |||
466 | break; | |||
467 | default: | |||
468 | __ypexclude_add(&__ypexhead, | |||
469 | pw->pw_name + 1); | |||
470 | break; | |||
471 | } | |||
472 | goto again; | |||
473 | } | |||
474 | } | |||
475 | #endif | |||
476 | ret = pw; | |||
477 | goto done; | |||
478 | } | |||
479 | ||||
480 | done: | |||
481 | _THREAD_PRIVATE_MUTEX_UNLOCK(pw)do { if (_thread_cb.tc_tag_unlock != ((void *)0)) _thread_cb. tc_tag_unlock(&(_thread_tagname_pw)); } while (0); | |||
482 | return (ret); | |||
483 | } | |||
484 | ||||
485 | #ifdef YP1 | |||
486 | /* | |||
487 | * See if the YP token is in the database. Only works if pwd_mkdb knows | |||
488 | * about the token. | |||
489 | */ | |||
490 | static int | |||
491 | __has_yppw(void) | |||
492 | { | |||
493 | DBT key, data, pkey, pdata; | |||
494 | char bf[2]; | |||
495 | ||||
496 | key.data = (u_char *)_PW_YPTOKEN"__YP!"; | |||
497 | key.size = strlen(_PW_YPTOKEN"__YP!"); | |||
498 | ||||
499 | /* Pre-token database support. */ | |||
500 | bf[0] = _PW_KEYBYNAME'1'; | |||
501 | bf[1] = '+'; | |||
502 | pkey.data = (u_char *)bf; | |||
503 | pkey.size = sizeof(bf); | |||
504 | ||||
505 | if ((_pw_db->get)(_pw_db, &key, &data, 0) && | |||
506 | (_pw_db->get)(_pw_db, &pkey, &pdata, 0)) | |||
507 | return (0); /* No YP. */ | |||
508 | return (1); | |||
509 | } | |||
510 | ||||
511 | /* | |||
512 | * See if there's a master.passwd map. | |||
513 | */ | |||
514 | static int | |||
515 | __has_ypmaster(void) | |||
516 | { | |||
517 | int keylen, resultlen; | |||
518 | char *key, *result; | |||
519 | static int checked = -1; | |||
520 | static uid_t saved_uid, saved_euid; | |||
521 | uid_t uid = getuid(), euid = geteuid(); | |||
522 | ||||
523 | /* | |||
524 | * Do not recheck IFF the saved UID and the saved | |||
525 | * EUID are the same. In all other cases, recheck. | |||
526 | */ | |||
527 | if (checked != -1 && saved_uid == uid && saved_euid == euid) | |||
528 | return (checked); | |||
529 | ||||
530 | if (euid != 0) { | |||
531 | saved_uid = uid; | |||
532 | saved_euid = euid; | |||
533 | checked = 0; | |||
534 | return (checked); | |||
535 | } | |||
536 | ||||
537 | if (!__ypdomain) | |||
538 | yp_get_default_domain(&__ypdomain); | |||
539 | ||||
540 | if (yp_first(__ypdomain, "master.passwd.byname", | |||
541 | &key, &keylen, &result, &resultlen)) { | |||
542 | saved_uid = uid; | |||
543 | saved_euid = euid; | |||
544 | checked = 0; | |||
545 | return (checked); | |||
546 | } | |||
547 | free(result); | |||
548 | free(key); | |||
549 | ||||
550 | saved_uid = uid; | |||
551 | saved_euid = euid; | |||
552 | checked = 1; | |||
553 | return (checked); | |||
554 | } | |||
555 | ||||
556 | static struct passwd * | |||
557 | __yppwlookup(int lookup, char *name, uid_t uid, struct passwd *pw, | |||
558 | char *buf, size_t buflen, int *flagsp) | |||
559 | { | |||
560 | char bf[1 + _PW_NAME_LEN31], *ypcurrent = NULL((void *)0), *map = NULL((void *)0); | |||
561 | int yp_pw_flags = 0, ypcurrentlen, r, s = -1, pw_keynum; | |||
562 | static struct pw_storage __yppbuf; | |||
563 | struct _ypexclude *ypexhead = NULL((void *)0); | |||
564 | const char *host, *user, *dom; | |||
565 | DBT key; | |||
566 | ||||
567 | for (pw_keynum = 1; pw_keynum; pw_keynum++) { | |||
568 | bf[0] = _PW_KEYBYNUM'2'; | |||
569 | bcopy((char *)&pw_keynum, &bf[1], sizeof(pw_keynum)); | |||
570 | key.data = (u_char *)bf; | |||
571 | key.size = 1 + sizeof(pw_keynum); | |||
572 | if (__hashpw(&key, buf, buflen, pw, flagsp) == 0) | |||
573 | break; | |||
574 | switch (pw->pw_name[0]) { | |||
575 | case '+': | |||
576 | if (!__ypdomain) | |||
577 | yp_get_default_domain(&__ypdomain); | |||
578 | __ypproto_set(pw, &__yppbuf, *flagsp, &yp_pw_flags); | |||
579 | if (!map) { | |||
580 | if (lookup == LOOKUP_BYNAME0) { | |||
581 | if ((name = strdup(name)) == NULL((void *)0)) { | |||
582 | pw = NULL((void *)0); | |||
583 | goto done; | |||
584 | } | |||
585 | map = PASSWD_BYNAME(__has_ypmaster() ? "master.passwd.byname" : "passwd.byname"); | |||
586 | } else { | |||
587 | if (asprintf(&name, "%u", uid) == -1) { | |||
588 | pw = NULL((void *)0); | |||
589 | goto done; | |||
590 | } | |||
591 | map = PASSWD_BYUID(__has_ypmaster() ? "master.passwd.byuid" : "passwd.byuid"); | |||
592 | } | |||
593 | } | |||
594 | ||||
595 | switch (pw->pw_name[1]) { | |||
596 | case '\0': | |||
597 | free(ypcurrent); | |||
598 | ypcurrent = NULL((void *)0); | |||
599 | r = yp_match(__ypdomain, map, | |||
600 | name, strlen(name), | |||
601 | &ypcurrent, &ypcurrentlen); | |||
602 | if (r != 0 || ypcurrentlen > buflen) { | |||
603 | free(ypcurrent); | |||
604 | ypcurrent = NULL((void *)0); | |||
605 | continue; | |||
606 | } | |||
607 | break; | |||
608 | case '@': | |||
609 | pwnam_netgrp: | |||
610 | free(ypcurrent); | |||
611 | ypcurrent = NULL((void *)0); | |||
612 | if (s == -1) /* first time */ | |||
613 | setnetgrent(pw->pw_name + 2); | |||
614 | s = getnetgrent(&host, &user, &dom); | |||
615 | if (s == 0) { /* end of group */ | |||
616 | endnetgrent(); | |||
617 | s = -1; | |||
618 | continue; | |||
619 | } else { | |||
620 | if (user && *user) { | |||
621 | r = yp_match(__ypdomain, map, | |||
622 | user, strlen(user), | |||
623 | &ypcurrent, &ypcurrentlen); | |||
624 | } else | |||
625 | goto pwnam_netgrp; | |||
626 | if (r != 0 || ypcurrentlen > buflen) { | |||
627 | free(ypcurrent); | |||
628 | ypcurrent = NULL((void *)0); | |||
629 | /* | |||
630 | * just because this | |||
631 | * user is bad, doesn't | |||
632 | * mean they all are. | |||
633 | */ | |||
634 | goto pwnam_netgrp; | |||
635 | } | |||
636 | } | |||
637 | break; | |||
638 | default: | |||
639 | free(ypcurrent); | |||
640 | ypcurrent = NULL((void *)0); | |||
641 | user = pw->pw_name + 1; | |||
642 | r = yp_match(__ypdomain, map, | |||
643 | user, strlen(user), | |||
644 | &ypcurrent, &ypcurrentlen); | |||
645 | if (r != 0 || ypcurrentlen > buflen) { | |||
646 | free(ypcurrent); | |||
647 | ypcurrent = NULL((void *)0); | |||
648 | continue; | |||
649 | } | |||
650 | break; | |||
651 | } | |||
652 | bcopy(ypcurrent, buf, ypcurrentlen); | |||
653 | buf[ypcurrentlen] = '\0'; | |||
654 | if (__ypparse(pw, buf, yp_pw_flags) || | |||
655 | __ypexclude_is(&ypexhead, pw->pw_name)) { | |||
656 | if (s == 1) /* inside netgrp */ | |||
657 | goto pwnam_netgrp; | |||
658 | continue; | |||
659 | } | |||
660 | break; | |||
661 | case '-': | |||
662 | /* attempted exclusion */ | |||
663 | switch (pw->pw_name[1]) { | |||
664 | case '\0': | |||
665 | break; | |||
666 | case '@': | |||
667 | setnetgrent(pw->pw_name + 2); | |||
668 | while (getnetgrent(&host, &user, &dom)) { | |||
669 | if (user && *user) | |||
670 | __ypexclude_add(&ypexhead, user); | |||
671 | } | |||
672 | endnetgrent(); | |||
673 | break; | |||
674 | default: | |||
675 | __ypexclude_add(&ypexhead, pw->pw_name + 1); | |||
676 | break; | |||
677 | } | |||
678 | break; | |||
679 | } | |||
680 | if ((lookup == LOOKUP_BYUID1 && pw->pw_uid == uid) || | |||
681 | (lookup == LOOKUP_BYNAME0 && strcmp(pw->pw_name, name) == 0)) | |||
682 | goto done; | |||
683 | if (s == 1) /* inside netgrp */ | |||
684 | goto pwnam_netgrp; | |||
685 | continue; | |||
686 | } | |||
687 | pw = NULL((void *)0); | |||
688 | done: | |||
689 | __ypexclude_free(&ypexhead); | |||
690 | __ypproto = NULL((void *)0); | |||
691 | free(ypcurrent); | |||
692 | ypcurrent = NULL((void *)0); | |||
693 | if (map) | |||
694 | free(name); | |||
695 | return (pw); | |||
696 | } | |||
697 | #endif /* YP */ | |||
698 | ||||
699 | static struct passwd * | |||
700 | _pwhashbyname(const char *name, char *buf, size_t buflen, struct passwd *pw, | |||
701 | int *flagsp) | |||
702 | { | |||
703 | char bf[1 + _PW_NAME_LEN31]; | |||
704 | size_t len; | |||
705 | DBT key; | |||
706 | int r; | |||
707 | ||||
708 | len = strlen(name); | |||
709 | if (len > _PW_NAME_LEN31) | |||
710 | return (NULL((void *)0)); | |||
711 | bf[0] = _PW_KEYBYNAME'1'; | |||
712 | bcopy(name, &bf[1], MINIMUM(len, _PW_NAME_LEN)(((len) < (31)) ? (len) : (31))); | |||
713 | key.data = (u_char *)bf; | |||
714 | key.size = 1 + MINIMUM(len, _PW_NAME_LEN)(((len) < (31)) ? (len) : (31)); | |||
715 | r = __hashpw(&key, buf, buflen, pw, flagsp); | |||
716 | if (r) | |||
717 | return (pw); | |||
718 | return (NULL((void *)0)); | |||
719 | } | |||
720 | ||||
721 | static struct passwd * | |||
722 | _pwhashbyuid(uid_t uid, char *buf, size_t buflen, struct passwd *pw, | |||
723 | int *flagsp) | |||
724 | { | |||
725 | char bf[1 + sizeof(int)]; | |||
726 | DBT key; | |||
727 | int r; | |||
728 | ||||
729 | bf[0] = _PW_KEYBYUID'3'; | |||
730 | bcopy(&uid, &bf[1], sizeof(uid)); | |||
731 | key.data = (u_char *)bf; | |||
732 | key.size = 1 + sizeof(uid); | |||
733 | r = __hashpw(&key, buf, buflen, pw, flagsp); | |||
734 | if (r) | |||
735 | return (pw); | |||
736 | return (NULL((void *)0)); | |||
737 | } | |||
738 | ||||
739 | static int | |||
740 | getpwnam_internal(const char *name, struct passwd *pw, char *buf, size_t buflen, | |||
741 | struct passwd **pwretp, bool_Bool shadow, bool_Bool reentrant) | |||
742 | { | |||
743 | struct passwd *pwret = NULL((void *)0); | |||
744 | int flags = 0, *flagsp = &flags; | |||
745 | int my_errno = 0; | |||
746 | int saved_errno, tmp_errno; | |||
747 | ||||
748 | _THREAD_PRIVATE_MUTEX_LOCK(pw)do { if (_thread_cb.tc_tag_lock != ((void *)0)) _thread_cb.tc_tag_lock (&(_thread_tagname_pw)); } while (0); | |||
749 | saved_errno = errno(*__errno()); | |||
750 | errno(*__errno()) = 0; | |||
751 | if (!_pw_db && !__initdb(shadow)) | |||
752 | goto fail; | |||
753 | ||||
754 | if (!reentrant) { | |||
755 | /* Allocate space for struct and strings, unmapping the old. */ | |||
756 | if ((pw = __get_pw_buf(&buf, &buflen, -1, name)) == NULL((void *)0)) | |||
757 | goto fail; | |||
758 | flagsp = &_pw_flags; | |||
759 | } | |||
760 | ||||
761 | #ifdef YP1 | |||
762 | if (__has_yppw()) | |||
763 | pwret = __yppwlookup(LOOKUP_BYNAME0, (char *)name, 0, pw, | |||
764 | buf, buflen, flagsp); | |||
765 | #endif /* YP */ | |||
766 | if (!pwret) | |||
767 | pwret = _pwhashbyname(name, buf, buflen, pw, flagsp); | |||
768 | ||||
769 | if (!_pw_stayopen) { | |||
770 | tmp_errno = errno(*__errno()); | |||
771 | (void)(_pw_db->close)(_pw_db); | |||
772 | _pw_db = NULL((void *)0); | |||
773 | errno(*__errno()) = tmp_errno; | |||
774 | } | |||
775 | fail: | |||
776 | if (pwretp) | |||
777 | *pwretp = pwret; | |||
778 | if (pwret == NULL((void *)0)) | |||
779 | my_errno = errno(*__errno()); | |||
780 | errno(*__errno()) = saved_errno; | |||
781 | _THREAD_PRIVATE_MUTEX_UNLOCK(pw)do { if (_thread_cb.tc_tag_unlock != ((void *)0)) _thread_cb. tc_tag_unlock(&(_thread_tagname_pw)); } while (0); | |||
782 | return (my_errno); | |||
783 | } | |||
784 | ||||
785 | int | |||
786 | getpwnam_r(const char *name, struct passwd *pw, char *buf, size_t buflen, | |||
787 | struct passwd **pwretp) | |||
788 | { | |||
789 | return getpwnam_internal(name, pw, buf, buflen, pwretp, false0, true1); | |||
790 | } | |||
791 | DEF_WEAK(getpwnam_r)__asm__(".weak " "getpwnam_r" " ; " "getpwnam_r" " = " "_libc_getpwnam_r" ); | |||
792 | ||||
793 | struct passwd * | |||
794 | getpwnam(const char *name) | |||
795 | { | |||
796 | struct passwd *pw = NULL((void *)0); | |||
797 | int my_errno; | |||
798 | ||||
799 | my_errno = getpwnam_internal(name, NULL((void *)0), NULL((void *)0), 0, &pw, false0, false0); | |||
800 | if (my_errno) { | |||
801 | pw = NULL((void *)0); | |||
802 | errno(*__errno()) = my_errno; | |||
803 | } | |||
804 | return (pw); | |||
805 | } | |||
806 | ||||
807 | struct passwd * | |||
808 | getpwnam_shadow(const char *name) | |||
809 | { | |||
810 | struct passwd *pw = NULL((void *)0); | |||
811 | int my_errno; | |||
812 | ||||
813 | my_errno = getpwnam_internal(name, NULL((void *)0), NULL((void *)0), 0, &pw, true1, false0); | |||
814 | if (my_errno) { | |||
815 | pw = NULL((void *)0); | |||
816 | errno(*__errno()) = my_errno; | |||
817 | } | |||
818 | return (pw); | |||
819 | } | |||
820 | DEF_WEAK(getpwnam_shadow)__asm__(".weak " "getpwnam_shadow" " ; " "getpwnam_shadow" " = " "_libc_getpwnam_shadow"); | |||
821 | ||||
822 | static int | |||
823 | getpwuid_internal(uid_t uid, struct passwd *pw, char *buf, size_t buflen, | |||
824 | struct passwd **pwretp, bool_Bool shadow, bool_Bool reentrant) | |||
825 | { | |||
826 | struct passwd *pwret = NULL((void *)0); | |||
827 | int flags = 0, *flagsp = &flags; | |||
828 | int my_errno = 0; | |||
829 | int saved_errno, tmp_errno; | |||
830 | ||||
831 | _THREAD_PRIVATE_MUTEX_LOCK(pw)do { if (_thread_cb.tc_tag_lock != ((void *)0)) _thread_cb.tc_tag_lock (&(_thread_tagname_pw)); } while (0); | |||
832 | saved_errno = errno(*__errno()); | |||
833 | errno(*__errno()) = 0; | |||
834 | if (!_pw_db && !__initdb(shadow)) | |||
835 | goto fail; | |||
836 | ||||
837 | if (!reentrant) { | |||
838 | /* Allocate space for struct and strings, unmapping the old. */ | |||
839 | if ((pw = __get_pw_buf(&buf, &buflen, uid, NULL((void *)0))) == NULL((void *)0)) | |||
840 | goto fail; | |||
841 | flagsp = &_pw_flags; | |||
842 | } | |||
843 | ||||
844 | #ifdef YP1 | |||
845 | if (__has_yppw()) | |||
846 | pwret = __yppwlookup(LOOKUP_BYUID1, NULL((void *)0), uid, pw, | |||
847 | buf, buflen, flagsp); | |||
848 | #endif /* YP */ | |||
849 | if (!pwret) | |||
850 | pwret = _pwhashbyuid(uid, buf, buflen, pw, flagsp); | |||
851 | ||||
852 | if (!_pw_stayopen) { | |||
853 | tmp_errno = errno(*__errno()); | |||
854 | (void)(_pw_db->close)(_pw_db); | |||
855 | _pw_db = NULL((void *)0); | |||
856 | errno(*__errno()) = tmp_errno; | |||
857 | } | |||
858 | fail: | |||
859 | if (pwretp) | |||
860 | *pwretp = pwret; | |||
861 | if (pwret == NULL((void *)0)) | |||
862 | my_errno = errno(*__errno()); | |||
863 | errno(*__errno()) = saved_errno; | |||
864 | _THREAD_PRIVATE_MUTEX_UNLOCK(pw)do { if (_thread_cb.tc_tag_unlock != ((void *)0)) _thread_cb. tc_tag_unlock(&(_thread_tagname_pw)); } while (0); | |||
865 | return (my_errno); | |||
866 | } | |||
867 | ||||
868 | ||||
869 | int | |||
870 | getpwuid_r(uid_t uid, struct passwd *pw, char *buf, size_t buflen, | |||
871 | struct passwd **pwretp) | |||
872 | { | |||
873 | return getpwuid_internal(uid, pw, buf, buflen, pwretp, false0, true1); | |||
874 | } | |||
875 | DEF_WEAK(getpwuid_r)__asm__(".weak " "getpwuid_r" " ; " "getpwuid_r" " = " "_libc_getpwuid_r" ); | |||
876 | ||||
877 | struct passwd * | |||
878 | getpwuid(uid_t uid) | |||
879 | { | |||
880 | struct passwd *pw = NULL((void *)0); | |||
881 | int my_errno; | |||
882 | ||||
883 | my_errno = getpwuid_internal(uid, NULL((void *)0), NULL((void *)0), 0, &pw, false0, false0); | |||
884 | if (my_errno) { | |||
885 | pw = NULL((void *)0); | |||
886 | errno(*__errno()) = my_errno; | |||
887 | } | |||
888 | return (pw); | |||
889 | } | |||
890 | ||||
891 | struct passwd * | |||
892 | getpwuid_shadow(uid_t uid) | |||
893 | { | |||
894 | struct passwd *pw = NULL((void *)0); | |||
895 | int my_errno; | |||
896 | ||||
897 | my_errno = getpwuid_internal(uid, NULL((void *)0), NULL((void *)0), 0, &pw, true1, false0); | |||
898 | if (my_errno) { | |||
899 | pw = NULL((void *)0); | |||
900 | errno(*__errno()) = my_errno; | |||
901 | } | |||
902 | return (pw); | |||
903 | } | |||
904 | DEF_WEAK(getpwuid_shadow)__asm__(".weak " "getpwuid_shadow" " ; " "getpwuid_shadow" " = " "_libc_getpwuid_shadow"); | |||
905 | ||||
906 | int | |||
907 | setpassent(int stayopen) | |||
908 | { | |||
909 | _THREAD_PRIVATE_MUTEX_LOCK(pw)do { if (_thread_cb.tc_tag_lock != ((void *)0)) _thread_cb.tc_tag_lock (&(_thread_tagname_pw)); } while (0); | |||
910 | _pw_keynum = 0; | |||
911 | _pw_stayopen = stayopen; | |||
912 | #ifdef YP1 | |||
913 | __ypmode = YPMODE_NONE; | |||
914 | free(__ypcurrent); | |||
915 | __ypcurrent = NULL((void *)0); | |||
916 | __ypexclude_free(&__ypexhead); | |||
917 | __ypproto = NULL((void *)0); | |||
918 | #endif | |||
919 | _THREAD_PRIVATE_MUTEX_UNLOCK(pw)do { if (_thread_cb.tc_tag_unlock != ((void *)0)) _thread_cb. tc_tag_unlock(&(_thread_tagname_pw)); } while (0); | |||
920 | return (1); | |||
921 | } | |||
922 | DEF_WEAK(setpassent)__asm__(".weak " "setpassent" " ; " "setpassent" " = " "_libc_setpassent" ); | |||
923 | ||||
924 | void | |||
925 | setpwent(void) | |||
926 | { | |||
927 | (void) setpassent(0); | |||
928 | } | |||
929 | ||||
930 | void | |||
931 | endpwent(void) | |||
932 | { | |||
933 | int saved_errno; | |||
934 | ||||
935 | _THREAD_PRIVATE_MUTEX_LOCK(pw)do { if (_thread_cb.tc_tag_lock != ((void *)0)) _thread_cb.tc_tag_lock (&(_thread_tagname_pw)); } while (0); | |||
936 | saved_errno = errno(*__errno()); | |||
937 | _pw_keynum = 0; | |||
938 | if (_pw_db) { | |||
939 | (void)(_pw_db->close)(_pw_db); | |||
940 | _pw_db = NULL((void *)0); | |||
941 | } | |||
942 | #ifdef YP1 | |||
943 | __ypmode = YPMODE_NONE; | |||
944 | free(__ypcurrent); | |||
945 | __ypcurrent = NULL((void *)0); | |||
946 | __ypexclude_free(&__ypexhead); | |||
947 | __ypproto = NULL((void *)0); | |||
948 | #endif | |||
949 | errno(*__errno()) = saved_errno; | |||
950 | _THREAD_PRIVATE_MUTEX_UNLOCK(pw)do { if (_thread_cb.tc_tag_unlock != ((void *)0)) _thread_cb. tc_tag_unlock(&(_thread_tagname_pw)); } while (0); | |||
951 | } | |||
952 | ||||
953 | static int | |||
954 | __initdb(int shadow) | |||
955 | { | |||
956 | static int warned; | |||
957 | int saved_errno = errno(*__errno()); | |||
958 | ||||
959 | #ifdef YP1 | |||
960 | __ypmode = YPMODE_NONE; | |||
961 | __getpwent_has_yppw = -1; | |||
962 | #endif | |||
963 | if (shadow) | |||
964 | _pw_db = dbopen(_PATH_SMP_DB"/etc/spwd.db", O_RDONLY0x0000, 0, DB_HASH, NULL((void *)0)); | |||
965 | if (!_pw_db) | |||
966 | _pw_db = dbopen(_PATH_MP_DB"/etc/pwd.db", O_RDONLY0x0000, 0, DB_HASH, NULL((void *)0)); | |||
967 | if (_pw_db) { | |||
968 | errno(*__errno()) = saved_errno; | |||
969 | return (1); | |||
970 | } | |||
971 | if (!warned) { | |||
972 | saved_errno = errno(*__errno()); | |||
973 | errno(*__errno()) = saved_errno; | |||
974 | warned = 1; | |||
975 | } | |||
976 | return (0); | |||
977 | } | |||
978 | ||||
979 | static int | |||
980 | __hashpw(DBT *key, char *buf, size_t buflen, struct passwd *pw, | |||
981 | int *flagsp) | |||
982 | { | |||
983 | char *p, *t; | |||
984 | DBT data; | |||
985 | ||||
986 | if ((_pw_db->get)(_pw_db, key, &data, 0)) | |||
987 | return (0); | |||
988 | p = (char *)data.data; | |||
989 | if (data.size > buflen) { | |||
990 | errno(*__errno()) = ERANGE34; | |||
991 | return (0); | |||
992 | } | |||
993 | ||||
994 | t = buf; | |||
995 | #define EXPAND(e)e = t; while ((*t++ = *p++)); e = t; while ((*t++ = *p++)); | |||
996 | EXPAND(pw->pw_name)pw->pw_name = t; while ((*t++ = *p++));; | |||
997 | EXPAND(pw->pw_passwd)pw->pw_passwd = t; while ((*t++ = *p++));; | |||
998 | bcopy(p, (char *)&pw->pw_uid, sizeof(int)); | |||
999 | p += sizeof(int); | |||
1000 | bcopy(p, (char *)&pw->pw_gid, sizeof(int)); | |||
1001 | p += sizeof(int); | |||
1002 | bcopy(p, (char *)&pw->pw_change, sizeof(time_t)); | |||
1003 | p += sizeof(time_t); | |||
1004 | EXPAND(pw->pw_class)pw->pw_class = t; while ((*t++ = *p++));; | |||
1005 | EXPAND(pw->pw_gecos)pw->pw_gecos = t; while ((*t++ = *p++));; | |||
1006 | EXPAND(pw->pw_dir)pw->pw_dir = t; while ((*t++ = *p++));; | |||
1007 | EXPAND(pw->pw_shell)pw->pw_shell = t; while ((*t++ = *p++));; | |||
1008 | bcopy(p, (char *)&pw->pw_expire, sizeof(time_t)); | |||
1009 | p += sizeof(time_t); | |||
1010 | ||||
1011 | /* See if there's any data left. If so, read in flags. */ | |||
1012 | if (data.size > (p - (char *)data.data)) { | |||
1013 | bcopy(p, (char *)flagsp, sizeof(int)); | |||
1014 | p += sizeof(int); | |||
1015 | } else | |||
1016 | *flagsp = _PASSWORD_NOUID0x01|_PASSWORD_NOGID0x02; /* default */ | |||
1017 | return (1); | |||
1018 | } |