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 |
|
|
DBT key, data, pkey, pdata; |
445 |
|
|
char bf[2]; |
446 |
|
|
|
447 |
|
|
key.data = (u_char *)_PW_YPTOKEN; |
448 |
|
|
key.size = strlen(_PW_YPTOKEN); |
449 |
|
|
|
450 |
|
|
/* Pre-token database support. */ |
451 |
|
|
bf[0] = _PW_KEYBYNAME; |
452 |
|
|
bf[1] = '+'; |
453 |
|
|
pkey.data = (u_char *)bf; |
454 |
|
|
pkey.size = sizeof(bf); |
455 |
|
|
|
456 |
|
|
if ((_pw_db->get)(_pw_db, &key, &data, 0) && |
457 |
|
|
(_pw_db->get)(_pw_db, &pkey, &pdata, 0)) |
458 |
|
|
return (0); /* No YP. */ |
459 |
|
|
return (1); |
460 |
|
|
} |
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 |
|
|
char bf[1 + _PW_NAME_LEN]; |
663 |
|
|
size_t len; |
664 |
|
|
DBT key; |
665 |
|
|
int r; |
666 |
|
|
|
667 |
|
|
len = strlen(name); |
668 |
|
|
if (len > _PW_NAME_LEN) |
669 |
|
|
return (NULL); |
670 |
|
|
bf[0] = _PW_KEYBYNAME; |
671 |
|
|
bcopy(name, &bf[1], MINIMUM(len, _PW_NAME_LEN)); |
672 |
|
|
key.data = (u_char *)bf; |
673 |
|
|
key.size = 1 + MINIMUM(len, _PW_NAME_LEN); |
674 |
|
|
r = __hashpw(&key, buf, buflen, pw, flagsp); |
675 |
|
|
if (r) |
676 |
|
|
return (pw); |
677 |
|
|
return (NULL); |
678 |
|
|
} |
679 |
|
|
|
680 |
|
|
static struct passwd * |
681 |
|
|
_pwhashbyuid(uid_t uid, char *buf, size_t buflen, struct passwd *pw, |
682 |
|
|
int *flagsp) |
683 |
|
|
{ |
684 |
|
|
char bf[1 + sizeof(int)]; |
685 |
|
|
DBT key; |
686 |
|
|
int r; |
687 |
|
|
|
688 |
|
|
bf[0] = _PW_KEYBYUID; |
689 |
|
|
bcopy(&uid, &bf[1], sizeof(uid)); |
690 |
|
|
key.data = (u_char *)bf; |
691 |
|
|
key.size = 1 + sizeof(uid); |
692 |
|
|
r = __hashpw(&key, buf, buflen, pw, flagsp); |
693 |
|
|
if (r) |
694 |
|
|
return (pw); |
695 |
|
|
return (NULL); |
696 |
|
|
} |
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 |
|
|
int flags = 0, *flagsp; |
704 |
|
|
int my_errno = 0; |
705 |
|
|
int saved_errno, tmp_errno; |
706 |
|
|
|
707 |
|
|
_THREAD_PRIVATE_MUTEX_LOCK(pw); |
708 |
|
|
saved_errno = errno; |
709 |
|
|
errno = 0; |
710 |
|
|
if (!_pw_db && !__initdb(shadow)) |
711 |
|
|
goto fail; |
712 |
|
|
|
713 |
|
|
if (pw == &_pw_passwd) |
714 |
|
|
flagsp = &_pw_flags; |
715 |
|
|
else |
716 |
|
|
flagsp = &flags; |
717 |
|
|
|
718 |
|
|
#ifdef YP |
719 |
|
|
if (__has_yppw()) |
720 |
|
|
pwret = __yppwlookup(LOOKUP_BYNAME, (char *)name, 0, pw, |
721 |
|
|
buf, buflen, flagsp); |
722 |
|
|
#endif /* YP */ |
723 |
|
|
if (!pwret) |
724 |
|
|
pwret = _pwhashbyname(name, buf, buflen, pw, flagsp); |
725 |
|
|
|
726 |
|
|
if (!_pw_stayopen) { |
727 |
|
|
tmp_errno = errno; |
728 |
|
|
(void)(_pw_db->close)(_pw_db); |
729 |
|
|
_pw_db = NULL; |
730 |
|
|
errno = tmp_errno; |
731 |
|
|
} |
732 |
|
|
fail: |
733 |
|
|
if (pwretp) |
734 |
|
|
*pwretp = pwret; |
735 |
|
|
if (pwret == NULL) |
736 |
|
|
my_errno = errno; |
737 |
|
|
errno = saved_errno; |
738 |
|
|
_THREAD_PRIVATE_MUTEX_UNLOCK(pw); |
739 |
|
|
return (my_errno); |
740 |
|
|
} |
741 |
|
|
|
742 |
|
|
int |
743 |
|
|
getpwnam_r(const char *name, struct passwd *pw, char *buf, size_t buflen, |
744 |
|
|
struct passwd **pwretp) |
745 |
|
|
{ |
746 |
|
|
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 |
|
|
struct passwd *pw = NULL; |
754 |
|
|
int my_errno; |
755 |
|
|
|
756 |
|
|
my_errno = getpwnam_r(name, &_pw_passwd, _pw_string, |
757 |
|
|
sizeof _pw_string, &pw); |
758 |
|
|
if (my_errno) { |
759 |
|
|
pw = NULL; |
760 |
|
|
errno = my_errno; |
761 |
|
|
} |
762 |
|
|
return (pw); |
763 |
|
|
} |
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 |
|
|
int flags = 0, *flagsp; |
787 |
|
|
int my_errno = 0; |
788 |
|
|
int saved_errno, tmp_errno; |
789 |
|
|
|
790 |
|
|
_THREAD_PRIVATE_MUTEX_LOCK(pw); |
791 |
|
|
saved_errno = errno; |
792 |
|
|
errno = 0; |
793 |
|
|
if (!_pw_db && !__initdb(shadow)) |
794 |
|
|
goto fail; |
795 |
|
|
|
796 |
|
|
if (pw == &_pw_passwd) |
797 |
|
|
flagsp = &_pw_flags; |
798 |
|
|
else |
799 |
|
|
flagsp = &flags; |
800 |
|
|
|
801 |
|
|
#ifdef YP |
802 |
|
|
if (__has_yppw()) |
803 |
|
|
pwret = __yppwlookup(LOOKUP_BYUID, NULL, uid, pw, |
804 |
|
|
buf, buflen, flagsp); |
805 |
|
|
#endif /* YP */ |
806 |
|
|
if (!pwret) |
807 |
|
|
pwret = _pwhashbyuid(uid, buf, buflen, pw, flagsp); |
808 |
|
|
|
809 |
|
|
if (!_pw_stayopen) { |
810 |
|
|
tmp_errno = errno; |
811 |
|
|
(void)(_pw_db->close)(_pw_db); |
812 |
|
|
_pw_db = NULL; |
813 |
|
|
errno = tmp_errno; |
814 |
|
|
} |
815 |
|
|
fail: |
816 |
|
|
if (pwretp) |
817 |
|
|
*pwretp = pwret; |
818 |
|
|
if (pwret == NULL) |
819 |
|
|
my_errno = errno; |
820 |
|
|
errno = saved_errno; |
821 |
|
|
_THREAD_PRIVATE_MUTEX_UNLOCK(pw); |
822 |
|
|
return (my_errno); |
823 |
|
|
} |
824 |
|
|
|
825 |
|
|
|
826 |
|
|
int |
827 |
|
|
getpwuid_r(uid_t uid, struct passwd *pw, char *buf, size_t buflen, |
828 |
|
|
struct passwd **pwretp) |
829 |
|
|
{ |
830 |
|
|
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 |
|
|
_THREAD_PRIVATE_MUTEX_LOCK(pw); |
869 |
|
|
_pw_keynum = 0; |
870 |
|
|
_pw_stayopen = stayopen; |
871 |
|
|
#ifdef YP |
872 |
|
|
__ypmode = YPMODE_NONE; |
873 |
|
|
free(__ypcurrent); |
874 |
|
|
__ypcurrent = NULL; |
875 |
|
|
__ypexclude_free(&__ypexhead); |
876 |
|
|
__ypproto = NULL; |
877 |
|
|
#endif |
878 |
|
|
_THREAD_PRIVATE_MUTEX_UNLOCK(pw); |
879 |
|
|
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 |
|
|
_THREAD_PRIVATE_MUTEX_LOCK(pw); |
895 |
|
|
saved_errno = errno; |
896 |
|
|
_pw_keynum = 0; |
897 |
|
|
if (_pw_db) { |
898 |
|
|
(void)(_pw_db->close)(_pw_db); |
899 |
|
|
_pw_db = NULL; |
900 |
|
|
} |
901 |
|
|
#ifdef YP |
902 |
|
|
__ypmode = YPMODE_NONE; |
903 |
|
|
free(__ypcurrent); |
904 |
|
|
__ypcurrent = NULL; |
905 |
|
|
__ypexclude_free(&__ypexhead); |
906 |
|
|
__ypproto = NULL; |
907 |
|
|
#endif |
908 |
|
|
errno = saved_errno; |
909 |
|
|
_THREAD_PRIVATE_MUTEX_UNLOCK(pw); |
910 |
|
|
} |
911 |
|
|
|
912 |
|
|
static int |
913 |
|
|
__initdb(int shadow) |
914 |
|
|
{ |
915 |
|
|
static int warned; |
916 |
|
|
int saved_errno = errno; |
917 |
|
|
|
918 |
|
|
#ifdef YP |
919 |
|
|
/* |
920 |
|
|
* Hint to the kernel that a passwd database operation is happening. |
921 |
|
|
*/ |
922 |
|
|
(void)access("/var/run/ypbind.lock", R_OK); |
923 |
|
|
|
924 |
|
|
__ypmode = YPMODE_NONE; |
925 |
|
|
__getpwent_has_yppw = -1; |
926 |
|
|
#endif |
927 |
|
|
if (shadow) |
928 |
|
|
_pw_db = dbopen(_PATH_SMP_DB, O_RDONLY, 0, DB_HASH, NULL); |
929 |
|
|
if (!_pw_db) |
930 |
|
|
_pw_db = dbopen(_PATH_MP_DB, O_RDONLY, 0, DB_HASH, NULL); |
931 |
|
|
if (_pw_db) { |
932 |
|
|
errno = saved_errno; |
933 |
|
|
return (1); |
934 |
|
|
} |
935 |
|
|
if (!warned) { |
936 |
|
|
saved_errno = errno; |
937 |
|
|
errno = saved_errno; |
938 |
|
|
warned = 1; |
939 |
|
|
} |
940 |
|
|
return (0); |
941 |
|
|
} |
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 |
|
|
DBT data; |
949 |
|
|
|
950 |
|
|
if ((_pw_db->get)(_pw_db, key, &data, 0)) |
951 |
|
|
return (0); |
952 |
|
|
p = (char *)data.data; |
953 |
|
|
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 |
|
|
EXPAND(pw->pw_name); |
961 |
|
|
EXPAND(pw->pw_passwd); |
962 |
|
|
bcopy(p, (char *)&pw->pw_uid, sizeof(int)); |
963 |
|
|
p += sizeof(int); |
964 |
|
|
bcopy(p, (char *)&pw->pw_gid, sizeof(int)); |
965 |
|
|
p += sizeof(int); |
966 |
|
|
bcopy(p, (char *)&pw->pw_change, sizeof(time_t)); |
967 |
|
|
p += sizeof(time_t); |
968 |
|
|
EXPAND(pw->pw_class); |
969 |
|
|
EXPAND(pw->pw_gecos); |
970 |
|
|
EXPAND(pw->pw_dir); |
971 |
|
|
EXPAND(pw->pw_shell); |
972 |
|
|
bcopy(p, (char *)&pw->pw_expire, sizeof(time_t)); |
973 |
|
|
p += sizeof(time_t); |
974 |
|
|
|
975 |
|
|
/* See if there's any data left. If so, read in flags. */ |
976 |
|
|
if (data.size > (p - (char *)data.data)) { |
977 |
|
|
bcopy(p, (char *)flagsp, sizeof(int)); |
978 |
|
|
p += sizeof(int); |
979 |
|
|
} else |
980 |
|
|
*flagsp = _PASSWORD_NOUID|_PASSWORD_NOGID; /* default */ |
981 |
|
|
return (1); |
982 |
|
|
} |