File: | src/lib/libc/gen/getpwent.c |
Warning: | line 418, column 3 Array subscript is undefined |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* $OpenBSD: getpwent.c,v 1.64 2021/12/07 18:13:45 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_MAX(2147483647 *2U +1U)) | |||
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_MAX(2147483647 *2U +1U)) | |||
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_MAX2147483647 || l <= INT_MIN(-2147483647 -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_MAX2147483647 || l <= INT_MIN(-2147483647 -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 | if (_yp_check(&__ypdomain) == 0) { | |||
337 | __ypmode = YPMODE_NONE; | |||
338 | goto again; | |||
339 | } | |||
340 | } | |||
341 | switch (__ypmode) { | |||
342 | case YPMODE_FULL: | |||
343 | if (__ypcurrent) { | |||
344 | r = yp_next(__ypdomain, map, | |||
345 | __ypcurrent, __ypcurrentlen, | |||
346 | &key, &keylen, &data, &datalen); | |||
347 | free(__ypcurrent); | |||
348 | __ypcurrent = NULL((void *)0); | |||
349 | if (r != 0) { | |||
350 | __ypmode = YPMODE_NONE; | |||
351 | free(data); | |||
352 | goto again; | |||
353 | } | |||
354 | __ypcurrent = key; | |||
355 | __ypcurrentlen = keylen; | |||
356 | } else { | |||
357 | r = yp_first(__ypdomain, map, | |||
358 | &__ypcurrent, &__ypcurrentlen, | |||
359 | &data, &datalen); | |||
360 | if (r != 0 || | |||
361 | __ypcurrentlen > buflen) { | |||
362 | __ypmode = YPMODE_NONE; | |||
363 | free(data); | |||
364 | goto again; | |||
365 | } | |||
366 | } | |||
367 | bcopy(data, pwbuf, datalen); | |||
368 | free(data); | |||
369 | break; | |||
370 | case YPMODE_NETGRP: | |||
371 | s = getnetgrent(&host, &user, &dom); | |||
372 | if (s == 0) { /* end of group */ | |||
373 | endnetgrent(); | |||
374 | __ypmode = YPMODE_NONE; | |||
375 | goto again; | |||
376 | } | |||
377 | if (user && *user) { | |||
378 | r = yp_match(__ypdomain, map, | |||
379 | user, strlen(user), &data, &datalen); | |||
380 | } else | |||
381 | goto again; | |||
382 | if (r != 0 || | |||
383 | __ypcurrentlen > buflen) { | |||
384 | /* | |||
385 | * if the netgroup is invalid, keep looking | |||
386 | * as there may be valid users later on. | |||
387 | */ | |||
388 | free(data); | |||
389 | goto again; | |||
390 | } | |||
391 | bcopy(data, pwbuf, datalen); | |||
392 | free(data); | |||
393 | break; | |||
394 | case YPMODE_USER: | |||
395 | if (name) { | |||
396 | r = yp_match(__ypdomain, map, | |||
397 | name, strlen(name), &data, &datalen); | |||
398 | __ypmode = YPMODE_NONE; | |||
399 | free(name); | |||
400 | name = NULL((void *)0); | |||
401 | if (r != 0 || | |||
402 | __ypcurrentlen > buflen) { | |||
403 | free(data); | |||
404 | goto again; | |||
405 | } | |||
406 | bcopy(data, pwbuf, datalen); | |||
407 | free(data); | |||
408 | } else { /* XXX */ | |||
409 | __ypmode = YPMODE_NONE; | |||
410 | goto again; | |||
411 | } | |||
412 | break; | |||
413 | case YPMODE_NONE: | |||
414 | /* NOTREACHED */ | |||
415 | break; | |||
416 | } | |||
417 | ||||
418 | pwbuf[datalen] = '\0'; | |||
| ||||
419 | if (__ypparse(pw, pwbuf, __yp_pw_flags)) | |||
420 | goto again; | |||
421 | ret = pw; | |||
422 | goto done; | |||
423 | } | |||
424 | #endif | |||
425 | ||||
426 | ++_pw_keynum; | |||
427 | bf[0] = _PW_KEYBYNUM'2'; | |||
428 | bcopy((char *)&_pw_keynum, &bf[1], sizeof(_pw_keynum)); | |||
429 | key.data = (u_char *)bf; | |||
430 | key.size = 1 + sizeof(_pw_keynum); | |||
431 | if (__hashpw(&key, pwbuf, buflen, pw, &_pw_flags)) { | |||
432 | #ifdef YP1 | |||
433 | static struct pw_storage __yppbuf; | |||
434 | const char *user, *host, *dom; | |||
435 | ||||
436 | /* if we don't have YP at all, don't bother. */ | |||
437 | if (__getpwent_has_yppw) { | |||
438 | if (pw->pw_name[0] == '+') { | |||
439 | /* set the mode */ | |||
440 | switch (pw->pw_name[1]) { | |||
441 | case '\0': | |||
442 | __ypmode = YPMODE_FULL; | |||
443 | break; | |||
444 | case '@': | |||
445 | __ypmode = YPMODE_NETGRP; | |||
446 | setnetgrent(pw->pw_name + 2); | |||
447 | break; | |||
448 | default: | |||
449 | __ypmode = YPMODE_USER; | |||
450 | name = strdup(pw->pw_name + 1); | |||
451 | break; | |||
452 | } | |||
453 | ||||
454 | __ypproto_set(pw, &__yppbuf, _pw_flags, | |||
455 | &__yp_pw_flags); | |||
456 | goto again; | |||
457 | } else if (pw->pw_name[0] == '-') { | |||
458 | /* an attempted exclusion */ | |||
459 | switch (pw->pw_name[1]) { | |||
460 | case '\0': | |||
461 | break; | |||
462 | case '@': | |||
463 | setnetgrent(pw->pw_name + 2); | |||
464 | while (getnetgrent(&host, &user, &dom)) { | |||
465 | if (user && *user) | |||
466 | __ypexclude_add(&__ypexhead, | |||
467 | user); | |||
468 | } | |||
469 | endnetgrent(); | |||
470 | break; | |||
471 | default: | |||
472 | __ypexclude_add(&__ypexhead, | |||
473 | pw->pw_name + 1); | |||
474 | break; | |||
475 | } | |||
476 | goto again; | |||
477 | } | |||
478 | } | |||
479 | #endif | |||
480 | ret = pw; | |||
481 | goto done; | |||
482 | } | |||
483 | ||||
484 | done: | |||
485 | _THREAD_PRIVATE_MUTEX_UNLOCK(pw)do { if (_thread_cb.tc_tag_unlock != ((void *)0)) _thread_cb. tc_tag_unlock(&(_thread_tagname_pw)); } while (0); | |||
486 | return (ret); | |||
487 | } | |||
488 | ||||
489 | #ifdef YP1 | |||
490 | /* | |||
491 | * See if the YP token is in the database. Only works if pwd_mkdb knows | |||
492 | * about the token. | |||
493 | */ | |||
494 | static int | |||
495 | __has_yppw(void) | |||
496 | { | |||
497 | DBT key, data, pkey, pdata; | |||
498 | char bf[2]; | |||
499 | ||||
500 | key.data = (u_char *)_PW_YPTOKEN"__YP!"; | |||
501 | key.size = strlen(_PW_YPTOKEN"__YP!"); | |||
502 | ||||
503 | /* Pre-token database support. */ | |||
504 | bf[0] = _PW_KEYBYNAME'1'; | |||
505 | bf[1] = '+'; | |||
506 | pkey.data = (u_char *)bf; | |||
507 | pkey.size = sizeof(bf); | |||
508 | ||||
509 | if ((_pw_db->get)(_pw_db, &key, &data, 0) && | |||
510 | (_pw_db->get)(_pw_db, &pkey, &pdata, 0)) | |||
511 | return (0); /* No YP. */ | |||
512 | return (1); | |||
513 | } | |||
514 | ||||
515 | /* | |||
516 | * See if there's a master.passwd map. | |||
517 | */ | |||
518 | static int | |||
519 | __has_ypmaster(void) | |||
520 | { | |||
521 | int keylen, resultlen; | |||
522 | char *key, *result; | |||
523 | static int checked = -1; | |||
524 | static uid_t saved_uid, saved_euid; | |||
525 | uid_t uid = getuid(), euid = geteuid(); | |||
526 | ||||
527 | /* | |||
528 | * Do not recheck IFF the saved UID and the saved | |||
529 | * EUID are the same. In all other cases, recheck. | |||
530 | */ | |||
531 | if (checked != -1 && saved_uid == uid && saved_euid == euid) | |||
532 | return (checked); | |||
533 | ||||
534 | if (euid != 0) { | |||
535 | saved_uid = uid; | |||
536 | saved_euid = euid; | |||
537 | checked = 0; | |||
538 | return (checked); | |||
539 | } | |||
540 | ||||
541 | if (!__ypdomain) { | |||
542 | if (_yp_check(&__ypdomain) == 0) { | |||
543 | saved_uid = uid; | |||
544 | saved_euid = euid; | |||
545 | checked = 0; | |||
546 | return (checked); /* No domain. */ | |||
547 | } | |||
548 | } | |||
549 | ||||
550 | if (yp_first(__ypdomain, "master.passwd.byname", | |||
551 | &key, &keylen, &result, &resultlen)) { | |||
552 | saved_uid = uid; | |||
553 | saved_euid = euid; | |||
554 | checked = 0; | |||
555 | return (checked); | |||
556 | } | |||
557 | free(result); | |||
558 | free(key); | |||
559 | ||||
560 | saved_uid = uid; | |||
561 | saved_euid = euid; | |||
562 | checked = 1; | |||
563 | return (checked); | |||
564 | } | |||
565 | ||||
566 | static struct passwd * | |||
567 | __yppwlookup(int lookup, char *name, uid_t uid, struct passwd *pw, | |||
568 | char *buf, size_t buflen, int *flagsp) | |||
569 | { | |||
570 | char bf[1 + _PW_NAME_LEN31], *ypcurrent = NULL((void *)0), *map = NULL((void *)0); | |||
571 | int yp_pw_flags = 0, ypcurrentlen, r, s = -1, pw_keynum; | |||
572 | static struct pw_storage __yppbuf; | |||
573 | struct _ypexclude *ypexhead = NULL((void *)0); | |||
574 | const char *host, *user, *dom; | |||
575 | DBT key; | |||
576 | ||||
577 | for (pw_keynum = 1; pw_keynum; pw_keynum++) { | |||
578 | bf[0] = _PW_KEYBYNUM'2'; | |||
579 | bcopy((char *)&pw_keynum, &bf[1], sizeof(pw_keynum)); | |||
580 | key.data = (u_char *)bf; | |||
581 | key.size = 1 + sizeof(pw_keynum); | |||
582 | if (__hashpw(&key, buf, buflen, pw, flagsp) == 0) | |||
583 | break; | |||
584 | switch (pw->pw_name[0]) { | |||
585 | case '+': | |||
586 | if (!__ypdomain) { | |||
587 | if (_yp_check(&__ypdomain) == 0) | |||
588 | continue; | |||
589 | } | |||
590 | __ypproto_set(pw, &__yppbuf, *flagsp, &yp_pw_flags); | |||
591 | if (!map) { | |||
592 | if (lookup == LOOKUP_BYNAME0) { | |||
593 | if ((name = strdup(name)) == NULL((void *)0)) { | |||
594 | pw = NULL((void *)0); | |||
595 | goto done; | |||
596 | } | |||
597 | map = PASSWD_BYNAME(__has_ypmaster() ? "master.passwd.byname" : "passwd.byname"); | |||
598 | } else { | |||
599 | if (asprintf(&name, "%u", uid) == -1) { | |||
600 | pw = NULL((void *)0); | |||
601 | goto done; | |||
602 | } | |||
603 | map = PASSWD_BYUID(__has_ypmaster() ? "master.passwd.byuid" : "passwd.byuid"); | |||
604 | } | |||
605 | } | |||
606 | ||||
607 | switch (pw->pw_name[1]) { | |||
608 | case '\0': | |||
609 | free(ypcurrent); | |||
610 | ypcurrent = NULL((void *)0); | |||
611 | r = yp_match(__ypdomain, map, | |||
612 | name, strlen(name), | |||
613 | &ypcurrent, &ypcurrentlen); | |||
614 | if (r != 0 || ypcurrentlen > buflen) { | |||
615 | free(ypcurrent); | |||
616 | ypcurrent = NULL((void *)0); | |||
617 | continue; | |||
618 | } | |||
619 | break; | |||
620 | case '@': | |||
621 | pwnam_netgrp: | |||
622 | free(ypcurrent); | |||
623 | ypcurrent = NULL((void *)0); | |||
624 | if (s == -1) /* first time */ | |||
625 | setnetgrent(pw->pw_name + 2); | |||
626 | s = getnetgrent(&host, &user, &dom); | |||
627 | if (s == 0) { /* end of group */ | |||
628 | endnetgrent(); | |||
629 | s = -1; | |||
630 | continue; | |||
631 | } else { | |||
632 | if (user && *user) { | |||
633 | r = yp_match(__ypdomain, map, | |||
634 | user, strlen(user), | |||
635 | &ypcurrent, &ypcurrentlen); | |||
636 | } else | |||
637 | goto pwnam_netgrp; | |||
638 | if (r != 0 || ypcurrentlen > buflen) { | |||
639 | free(ypcurrent); | |||
640 | ypcurrent = NULL((void *)0); | |||
641 | /* | |||
642 | * just because this | |||
643 | * user is bad, doesn't | |||
644 | * mean they all are. | |||
645 | */ | |||
646 | goto pwnam_netgrp; | |||
647 | } | |||
648 | } | |||
649 | break; | |||
650 | default: | |||
651 | free(ypcurrent); | |||
652 | ypcurrent = NULL((void *)0); | |||
653 | user = pw->pw_name + 1; | |||
654 | r = yp_match(__ypdomain, map, | |||
655 | user, strlen(user), | |||
656 | &ypcurrent, &ypcurrentlen); | |||
657 | if (r != 0 || ypcurrentlen > buflen) { | |||
658 | free(ypcurrent); | |||
659 | ypcurrent = NULL((void *)0); | |||
660 | continue; | |||
661 | } | |||
662 | break; | |||
663 | } | |||
664 | bcopy(ypcurrent, buf, ypcurrentlen); | |||
665 | buf[ypcurrentlen] = '\0'; | |||
666 | if (__ypparse(pw, buf, yp_pw_flags) || | |||
667 | __ypexclude_is(&ypexhead, pw->pw_name)) { | |||
668 | if (s == 1) /* inside netgrp */ | |||
669 | goto pwnam_netgrp; | |||
670 | continue; | |||
671 | } | |||
672 | break; | |||
673 | case '-': | |||
674 | /* attempted exclusion */ | |||
675 | switch (pw->pw_name[1]) { | |||
676 | case '\0': | |||
677 | break; | |||
678 | case '@': | |||
679 | setnetgrent(pw->pw_name + 2); | |||
680 | while (getnetgrent(&host, &user, &dom)) { | |||
681 | if (user && *user) | |||
682 | __ypexclude_add(&ypexhead, user); | |||
683 | } | |||
684 | endnetgrent(); | |||
685 | break; | |||
686 | default: | |||
687 | __ypexclude_add(&ypexhead, pw->pw_name + 1); | |||
688 | break; | |||
689 | } | |||
690 | break; | |||
691 | } | |||
692 | if ((lookup == LOOKUP_BYUID1 && pw->pw_uid == uid) || | |||
693 | (lookup == LOOKUP_BYNAME0 && strcmp(pw->pw_name, name) == 0)) | |||
694 | goto done; | |||
695 | if (s == 1) /* inside netgrp */ | |||
696 | goto pwnam_netgrp; | |||
697 | continue; | |||
698 | } | |||
699 | pw = NULL((void *)0); | |||
700 | done: | |||
701 | __ypexclude_free(&ypexhead); | |||
702 | __ypproto = NULL((void *)0); | |||
703 | free(ypcurrent); | |||
704 | ypcurrent = NULL((void *)0); | |||
705 | if (map) | |||
706 | free(name); | |||
707 | return (pw); | |||
708 | } | |||
709 | #endif /* YP */ | |||
710 | ||||
711 | static struct passwd * | |||
712 | _pwhashbyname(const char *name, char *buf, size_t buflen, struct passwd *pw, | |||
713 | int *flagsp) | |||
714 | { | |||
715 | char bf[1 + _PW_NAME_LEN31]; | |||
716 | size_t len; | |||
717 | DBT key; | |||
718 | int r; | |||
719 | ||||
720 | len = strlen(name); | |||
721 | if (len > _PW_NAME_LEN31) | |||
722 | return (NULL((void *)0)); | |||
723 | bf[0] = _PW_KEYBYNAME'1'; | |||
724 | bcopy(name, &bf[1], MINIMUM(len, _PW_NAME_LEN)(((len) < (31)) ? (len) : (31))); | |||
725 | key.data = (u_char *)bf; | |||
726 | key.size = 1 + MINIMUM(len, _PW_NAME_LEN)(((len) < (31)) ? (len) : (31)); | |||
727 | r = __hashpw(&key, buf, buflen, pw, flagsp); | |||
728 | if (r) | |||
729 | return (pw); | |||
730 | return (NULL((void *)0)); | |||
731 | } | |||
732 | ||||
733 | static struct passwd * | |||
734 | _pwhashbyuid(uid_t uid, char *buf, size_t buflen, struct passwd *pw, | |||
735 | int *flagsp) | |||
736 | { | |||
737 | char bf[1 + sizeof(int)]; | |||
738 | DBT key; | |||
739 | int r; | |||
740 | ||||
741 | bf[0] = _PW_KEYBYUID'3'; | |||
742 | bcopy(&uid, &bf[1], sizeof(uid)); | |||
743 | key.data = (u_char *)bf; | |||
744 | key.size = 1 + sizeof(uid); | |||
745 | r = __hashpw(&key, buf, buflen, pw, flagsp); | |||
746 | if (r) | |||
747 | return (pw); | |||
748 | return (NULL((void *)0)); | |||
749 | } | |||
750 | ||||
751 | static int | |||
752 | getpwnam_internal(const char *name, struct passwd *pw, char *buf, size_t buflen, | |||
753 | struct passwd **pwretp, bool_Bool shadow, bool_Bool reentrant) | |||
754 | { | |||
755 | struct passwd *pwret = NULL((void *)0); | |||
756 | int flags = 0, *flagsp = &flags; | |||
757 | int my_errno = 0; | |||
758 | int saved_errno, tmp_errno; | |||
759 | ||||
760 | _THREAD_PRIVATE_MUTEX_LOCK(pw)do { if (_thread_cb.tc_tag_lock != ((void *)0)) _thread_cb.tc_tag_lock (&(_thread_tagname_pw)); } while (0); | |||
761 | saved_errno = errno(*__errno()); | |||
762 | errno(*__errno()) = 0; | |||
763 | if (!_pw_db && !__initdb(shadow)) | |||
764 | goto fail; | |||
765 | ||||
766 | if (!reentrant) { | |||
767 | /* Allocate space for struct and strings, unmapping the old. */ | |||
768 | if ((pw = __get_pw_buf(&buf, &buflen, -1, name)) == NULL((void *)0)) | |||
769 | goto fail; | |||
770 | flagsp = &_pw_flags; | |||
771 | } | |||
772 | ||||
773 | #ifdef YP1 | |||
774 | if (__has_yppw()) | |||
775 | pwret = __yppwlookup(LOOKUP_BYNAME0, (char *)name, 0, pw, | |||
776 | buf, buflen, flagsp); | |||
777 | #endif /* YP */ | |||
778 | if (!pwret) | |||
779 | pwret = _pwhashbyname(name, buf, buflen, pw, flagsp); | |||
780 | ||||
781 | if (!_pw_stayopen) { | |||
782 | tmp_errno = errno(*__errno()); | |||
783 | (void)(_pw_db->close)(_pw_db); | |||
784 | _pw_db = NULL((void *)0); | |||
785 | errno(*__errno()) = tmp_errno; | |||
786 | } | |||
787 | fail: | |||
788 | if (pwretp) | |||
789 | *pwretp = pwret; | |||
790 | if (pwret == NULL((void *)0)) | |||
791 | my_errno = errno(*__errno()); | |||
792 | errno(*__errno()) = saved_errno; | |||
793 | _THREAD_PRIVATE_MUTEX_UNLOCK(pw)do { if (_thread_cb.tc_tag_unlock != ((void *)0)) _thread_cb. tc_tag_unlock(&(_thread_tagname_pw)); } while (0); | |||
794 | return (my_errno); | |||
795 | } | |||
796 | ||||
797 | int | |||
798 | getpwnam_r(const char *name, struct passwd *pw, char *buf, size_t buflen, | |||
799 | struct passwd **pwretp) | |||
800 | { | |||
801 | return getpwnam_internal(name, pw, buf, buflen, pwretp, false0, true1); | |||
802 | } | |||
803 | DEF_WEAK(getpwnam_r)__asm__(".weak " "getpwnam_r" " ; " "getpwnam_r" " = " "_libc_getpwnam_r" ); | |||
804 | ||||
805 | struct passwd * | |||
806 | getpwnam(const char *name) | |||
807 | { | |||
808 | struct passwd *pw = NULL((void *)0); | |||
809 | int my_errno; | |||
810 | ||||
811 | my_errno = getpwnam_internal(name, NULL((void *)0), NULL((void *)0), 0, &pw, false0, false0); | |||
812 | if (my_errno) { | |||
813 | pw = NULL((void *)0); | |||
814 | errno(*__errno()) = my_errno; | |||
815 | } | |||
816 | return (pw); | |||
817 | } | |||
818 | ||||
819 | struct passwd * | |||
820 | getpwnam_shadow(const char *name) | |||
821 | { | |||
822 | struct passwd *pw = NULL((void *)0); | |||
823 | int my_errno; | |||
824 | ||||
825 | my_errno = getpwnam_internal(name, NULL((void *)0), NULL((void *)0), 0, &pw, true1, false0); | |||
826 | if (my_errno) { | |||
827 | pw = NULL((void *)0); | |||
828 | errno(*__errno()) = my_errno; | |||
829 | } | |||
830 | return (pw); | |||
831 | } | |||
832 | DEF_WEAK(getpwnam_shadow)__asm__(".weak " "getpwnam_shadow" " ; " "getpwnam_shadow" " = " "_libc_getpwnam_shadow"); | |||
833 | ||||
834 | static int | |||
835 | getpwuid_internal(uid_t uid, struct passwd *pw, char *buf, size_t buflen, | |||
836 | struct passwd **pwretp, bool_Bool shadow, bool_Bool reentrant) | |||
837 | { | |||
838 | struct passwd *pwret = NULL((void *)0); | |||
839 | int flags = 0, *flagsp = &flags; | |||
840 | int my_errno = 0; | |||
841 | int saved_errno, tmp_errno; | |||
842 | ||||
843 | _THREAD_PRIVATE_MUTEX_LOCK(pw)do { if (_thread_cb.tc_tag_lock != ((void *)0)) _thread_cb.tc_tag_lock (&(_thread_tagname_pw)); } while (0); | |||
844 | saved_errno = errno(*__errno()); | |||
845 | errno(*__errno()) = 0; | |||
846 | if (!_pw_db && !__initdb(shadow)) | |||
847 | goto fail; | |||
848 | ||||
849 | if (!reentrant) { | |||
850 | /* Allocate space for struct and strings, unmapping the old. */ | |||
851 | if ((pw = __get_pw_buf(&buf, &buflen, uid, NULL((void *)0))) == NULL((void *)0)) | |||
852 | goto fail; | |||
853 | flagsp = &_pw_flags; | |||
854 | } | |||
855 | ||||
856 | #ifdef YP1 | |||
857 | if (__has_yppw()) | |||
858 | pwret = __yppwlookup(LOOKUP_BYUID1, NULL((void *)0), uid, pw, | |||
859 | buf, buflen, flagsp); | |||
860 | #endif /* YP */ | |||
861 | if (!pwret) | |||
862 | pwret = _pwhashbyuid(uid, buf, buflen, pw, flagsp); | |||
863 | ||||
864 | if (!_pw_stayopen) { | |||
865 | tmp_errno = errno(*__errno()); | |||
866 | (void)(_pw_db->close)(_pw_db); | |||
867 | _pw_db = NULL((void *)0); | |||
868 | errno(*__errno()) = tmp_errno; | |||
869 | } | |||
870 | fail: | |||
871 | if (pwretp) | |||
872 | *pwretp = pwret; | |||
873 | if (pwret == NULL((void *)0)) | |||
874 | my_errno = errno(*__errno()); | |||
875 | errno(*__errno()) = saved_errno; | |||
876 | _THREAD_PRIVATE_MUTEX_UNLOCK(pw)do { if (_thread_cb.tc_tag_unlock != ((void *)0)) _thread_cb. tc_tag_unlock(&(_thread_tagname_pw)); } while (0); | |||
877 | return (my_errno); | |||
878 | } | |||
879 | ||||
880 | ||||
881 | int | |||
882 | getpwuid_r(uid_t uid, struct passwd *pw, char *buf, size_t buflen, | |||
883 | struct passwd **pwretp) | |||
884 | { | |||
885 | return getpwuid_internal(uid, pw, buf, buflen, pwretp, false0, true1); | |||
886 | } | |||
887 | DEF_WEAK(getpwuid_r)__asm__(".weak " "getpwuid_r" " ; " "getpwuid_r" " = " "_libc_getpwuid_r" ); | |||
888 | ||||
889 | struct passwd * | |||
890 | getpwuid(uid_t uid) | |||
891 | { | |||
892 | struct passwd *pw = NULL((void *)0); | |||
893 | int my_errno; | |||
894 | ||||
895 | my_errno = getpwuid_internal(uid, NULL((void *)0), NULL((void *)0), 0, &pw, false0, false0); | |||
896 | if (my_errno) { | |||
897 | pw = NULL((void *)0); | |||
898 | errno(*__errno()) = my_errno; | |||
899 | } | |||
900 | return (pw); | |||
901 | } | |||
902 | ||||
903 | struct passwd * | |||
904 | getpwuid_shadow(uid_t uid) | |||
905 | { | |||
906 | struct passwd *pw = NULL((void *)0); | |||
907 | int my_errno; | |||
908 | ||||
909 | my_errno = getpwuid_internal(uid, NULL((void *)0), NULL((void *)0), 0, &pw, true1, false0); | |||
910 | if (my_errno) { | |||
911 | pw = NULL((void *)0); | |||
912 | errno(*__errno()) = my_errno; | |||
913 | } | |||
914 | return (pw); | |||
915 | } | |||
916 | DEF_WEAK(getpwuid_shadow)__asm__(".weak " "getpwuid_shadow" " ; " "getpwuid_shadow" " = " "_libc_getpwuid_shadow"); | |||
917 | ||||
918 | int | |||
919 | setpassent(int stayopen) | |||
920 | { | |||
921 | _THREAD_PRIVATE_MUTEX_LOCK(pw)do { if (_thread_cb.tc_tag_lock != ((void *)0)) _thread_cb.tc_tag_lock (&(_thread_tagname_pw)); } while (0); | |||
922 | _pw_keynum = 0; | |||
923 | _pw_stayopen = stayopen; | |||
924 | #ifdef YP1 | |||
925 | __ypmode = YPMODE_NONE; | |||
926 | free(__ypcurrent); | |||
927 | __ypcurrent = NULL((void *)0); | |||
928 | __ypexclude_free(&__ypexhead); | |||
929 | __ypproto = NULL((void *)0); | |||
930 | #endif | |||
931 | _THREAD_PRIVATE_MUTEX_UNLOCK(pw)do { if (_thread_cb.tc_tag_unlock != ((void *)0)) _thread_cb. tc_tag_unlock(&(_thread_tagname_pw)); } while (0); | |||
932 | return (1); | |||
933 | } | |||
934 | DEF_WEAK(setpassent)__asm__(".weak " "setpassent" " ; " "setpassent" " = " "_libc_setpassent" ); | |||
935 | ||||
936 | void | |||
937 | setpwent(void) | |||
938 | { | |||
939 | (void) setpassent(0); | |||
940 | } | |||
941 | ||||
942 | void | |||
943 | endpwent(void) | |||
944 | { | |||
945 | int saved_errno; | |||
946 | ||||
947 | _THREAD_PRIVATE_MUTEX_LOCK(pw)do { if (_thread_cb.tc_tag_lock != ((void *)0)) _thread_cb.tc_tag_lock (&(_thread_tagname_pw)); } while (0); | |||
948 | saved_errno = errno(*__errno()); | |||
949 | _pw_keynum = 0; | |||
950 | if (_pw_db) { | |||
951 | (void)(_pw_db->close)(_pw_db); | |||
952 | _pw_db = NULL((void *)0); | |||
953 | } | |||
954 | #ifdef YP1 | |||
955 | __ypmode = YPMODE_NONE; | |||
956 | free(__ypcurrent); | |||
957 | __ypcurrent = NULL((void *)0); | |||
958 | __ypexclude_free(&__ypexhead); | |||
959 | __ypproto = NULL((void *)0); | |||
960 | #endif | |||
961 | errno(*__errno()) = saved_errno; | |||
962 | _THREAD_PRIVATE_MUTEX_UNLOCK(pw)do { if (_thread_cb.tc_tag_unlock != ((void *)0)) _thread_cb. tc_tag_unlock(&(_thread_tagname_pw)); } while (0); | |||
963 | } | |||
964 | ||||
965 | static int | |||
966 | __initdb(int shadow) | |||
967 | { | |||
968 | static int warned; | |||
969 | int saved_errno = errno(*__errno()); | |||
970 | ||||
971 | #ifdef YP1 | |||
972 | /* | |||
973 | * Hint to the kernel that a passwd database operation is happening. | |||
974 | */ | |||
975 | (void)access("/var/run/ypbind.lock", R_OK0x04); | |||
976 | errno(*__errno()) = saved_errno; | |||
977 | ||||
978 | __ypmode = YPMODE_NONE; | |||
979 | __getpwent_has_yppw = -1; | |||
980 | #endif | |||
981 | if (shadow) | |||
982 | _pw_db = dbopen(_PATH_SMP_DB"/etc/spwd.db", O_RDONLY0x0000, 0, DB_HASH, NULL((void *)0)); | |||
983 | if (!_pw_db) | |||
984 | _pw_db = dbopen(_PATH_MP_DB"/etc/pwd.db", O_RDONLY0x0000, 0, DB_HASH, NULL((void *)0)); | |||
985 | if (_pw_db) { | |||
986 | errno(*__errno()) = saved_errno; | |||
987 | return (1); | |||
988 | } | |||
989 | if (!warned) { | |||
990 | saved_errno = errno(*__errno()); | |||
991 | errno(*__errno()) = saved_errno; | |||
992 | warned = 1; | |||
993 | } | |||
994 | return (0); | |||
995 | } | |||
996 | ||||
997 | static int | |||
998 | __hashpw(DBT *key, char *buf, size_t buflen, struct passwd *pw, | |||
999 | int *flagsp) | |||
1000 | { | |||
1001 | char *p, *t; | |||
1002 | DBT data; | |||
1003 | ||||
1004 | if ((_pw_db->get)(_pw_db, key, &data, 0)) | |||
1005 | return (0); | |||
1006 | p = (char *)data.data; | |||
1007 | if (data.size > buflen) { | |||
1008 | errno(*__errno()) = ERANGE34; | |||
1009 | return (0); | |||
1010 | } | |||
1011 | ||||
1012 | t = buf; | |||
1013 | #define EXPAND(e)e = t; while ((*t++ = *p++)); e = t; while ((*t++ = *p++)); | |||
1014 | EXPAND(pw->pw_name)pw->pw_name = t; while ((*t++ = *p++));; | |||
1015 | EXPAND(pw->pw_passwd)pw->pw_passwd = t; while ((*t++ = *p++));; | |||
1016 | bcopy(p, (char *)&pw->pw_uid, sizeof(int)); | |||
1017 | p += sizeof(int); | |||
1018 | bcopy(p, (char *)&pw->pw_gid, sizeof(int)); | |||
1019 | p += sizeof(int); | |||
1020 | bcopy(p, (char *)&pw->pw_change, sizeof(time_t)); | |||
1021 | p += sizeof(time_t); | |||
1022 | EXPAND(pw->pw_class)pw->pw_class = t; while ((*t++ = *p++));; | |||
1023 | EXPAND(pw->pw_gecos)pw->pw_gecos = t; while ((*t++ = *p++));; | |||
1024 | EXPAND(pw->pw_dir)pw->pw_dir = t; while ((*t++ = *p++));; | |||
1025 | EXPAND(pw->pw_shell)pw->pw_shell = t; while ((*t++ = *p++));; | |||
1026 | bcopy(p, (char *)&pw->pw_expire, sizeof(time_t)); | |||
1027 | p += sizeof(time_t); | |||
1028 | ||||
1029 | /* See if there's any data left. If so, read in flags. */ | |||
1030 | if (data.size > (p - (char *)data.data)) { | |||
1031 | bcopy(p, (char *)flagsp, sizeof(int)); | |||
1032 | p += sizeof(int); | |||
1033 | } else | |||
1034 | *flagsp = _PASSWORD_NOUID0x01|_PASSWORD_NOGID0x02; /* default */ | |||
1035 | return (1); | |||
1036 | } |