2 * Copyright (c) 1999-2002 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
7 * Reserved. This file contains Original Code and/or Modifications of
8 * Original Code as defined in and that are subject to the Apple Public
9 * Source License Version 1.1 (the "License"). You may not use this file
10 * except in compliance with the License. Please obtain a copy of the
11 * License at http://www.apple.com/publicsource and read it before using
14 * The Original Code and all software distributed under the License are
15 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT. Please see the
19 * License for the specific language governing rights and limitations
22 * @APPLE_LICENSE_HEADER_END@
25 * user information (passwd) lookup
26 * Copyright (C) 1989 by NeXT, Inc.
29 #include <mach/mach.h>
33 #include <netinet/in.h>
38 #include "lu_overrides.h"
40 #define USER_CACHE_SIZE 10
42 static pthread_mutex_t _user_cache_lock
= PTHREAD_MUTEX_INITIALIZER
;
43 static void *_user_cache
[USER_CACHE_SIZE
] = { NULL
};
44 static unsigned int _user_cache_index
= 0;
45 static unsigned int _user_cache_init
= 0;
47 static pthread_mutex_t _user_lock
= PTHREAD_MUTEX_INITIALIZER
;
53 #define ENTRY_SIZE sizeof(struct passwd)
54 #define ENTRY_KEY _li_data_key_user
56 __private_extern__
struct passwd
*LI_files_getpwent();
57 __private_extern__
struct passwd
*LI_files_getpwnam(const char *name
);
58 __private_extern__
struct passwd
*LI_files_getpwuid(uid_t uid
);
59 __private_extern__
void LI_files_setpwent();
60 __private_extern__
void LI_files_endpwent();
62 static struct passwd
*
63 copy_user(struct passwd
*in
)
65 if (in
== NULL
) return NULL
;
67 return (struct passwd
*)LI_ils_create("ss44LssssL", in
->pw_name
, in
->pw_passwd
, in
->pw_uid
, in
->pw_gid
, in
->pw_change
, in
->pw_class
, in
->pw_gecos
, in
->pw_dir
, in
->pw_shell
, in
->pw_expire
);
71 * Extract the next user entry from a kvarray.
74 extract_user(kvarray_t
*in
)
77 uint32_t d
, k
, kcount
;
79 if (in
== NULL
) return NULL
;
84 if (d
>= in
->count
) return NULL
;
86 memset(&tmp
, 0, ENTRY_SIZE
);
91 kcount
= in
->dict
[d
].kcount
;
93 for (k
= 0; k
< kcount
; k
++)
95 if (!strcmp(in
->dict
[d
].key
[k
], "pw_name"))
97 if (tmp
.pw_name
!= NULL
) continue;
98 if (in
->dict
[d
].vcount
[k
] == 0) continue;
100 tmp
.pw_name
= (char *)in
->dict
[d
].val
[k
][0];
102 else if (!strcmp(in
->dict
[d
].key
[k
], "pw_passwd"))
104 if (tmp
.pw_passwd
!= NULL
) continue;
105 if (in
->dict
[d
].vcount
[k
] == 0) continue;
107 tmp
.pw_passwd
= (char *)in
->dict
[d
].val
[k
][0];
109 else if (!strcmp(in
->dict
[d
].key
[k
], "pw_uid"))
111 if (in
->dict
[d
].vcount
[k
] == 0) continue;
112 tmp
.pw_uid
= atoi(in
->dict
[d
].val
[k
][0]);
114 else if (!strcmp(in
->dict
[d
].key
[k
], "pw_gid"))
116 if (in
->dict
[d
].vcount
[k
] == 0) continue;
117 tmp
.pw_gid
= atoi(in
->dict
[d
].val
[k
][0]);
119 else if (!strcmp(in
->dict
[d
].key
[k
], "pw_change"))
121 if (in
->dict
[d
].vcount
[k
] == 0) continue;
122 tmp
.pw_change
= atol(in
->dict
[d
].val
[k
][0]);
124 else if (!strcmp(in
->dict
[d
].key
[k
], "pw_expire"))
126 if (in
->dict
[d
].vcount
[k
] == 0) continue;
127 tmp
.pw_expire
= atol(in
->dict
[d
].val
[k
][0]);
129 else if (!strcmp(in
->dict
[d
].key
[k
], "pw_class"))
131 if (tmp
.pw_class
!= NULL
) continue;
132 if (in
->dict
[d
].vcount
[k
] == 0) continue;
134 tmp
.pw_class
= (char *)in
->dict
[d
].val
[k
][0];
136 else if (!strcmp(in
->dict
[d
].key
[k
], "pw_gecos"))
138 if (tmp
.pw_gecos
!= NULL
) continue;
139 if (in
->dict
[d
].vcount
[k
] == 0) continue;
141 tmp
.pw_gecos
= (char *)in
->dict
[d
].val
[k
][0];
143 else if (!strcmp(in
->dict
[d
].key
[k
], "pw_dir"))
145 if (tmp
.pw_dir
!= NULL
) continue;
146 if (in
->dict
[d
].vcount
[k
] == 0) continue;
148 tmp
.pw_dir
= (char *)in
->dict
[d
].val
[k
][0];
150 else if (!strcmp(in
->dict
[d
].key
[k
], "pw_shell"))
152 if (tmp
.pw_shell
!= NULL
) continue;
153 if (in
->dict
[d
].vcount
[k
] == 0) continue;
155 tmp
.pw_shell
= (char *)in
->dict
[d
].val
[k
][0];
159 if (tmp
.pw_name
== NULL
) tmp
.pw_name
= "";
160 if (tmp
.pw_passwd
== NULL
) tmp
.pw_passwd
= "";
161 if (tmp
.pw_class
== NULL
) tmp
.pw_class
= "";
162 if (tmp
.pw_gecos
== NULL
) tmp
.pw_gecos
= "";
163 if (tmp
.pw_dir
== NULL
) tmp
.pw_dir
= "";
164 if (tmp
.pw_shell
== NULL
) tmp
.pw_shell
= "";
166 return copy_user(&tmp
);
170 copy_user_r(struct passwd
*in
, struct passwd
*out
, char *buffer
, int buflen
)
175 if (in
== NULL
) return -1;
176 if (out
== NULL
) return -1;
178 if (buffer
== NULL
) buflen
= 0;
180 /* Calculate size of input */
182 if (in
->pw_name
!= NULL
) hsize
+= (strlen(in
->pw_name
) + 1);
183 if (in
->pw_passwd
!= NULL
) hsize
+= (strlen(in
->pw_passwd
) + 1);
184 if (in
->pw_class
!= NULL
) hsize
+= (strlen(in
->pw_class
) + 1);
185 if (in
->pw_gecos
!= NULL
) hsize
+= (strlen(in
->pw_gecos
) + 1);
186 if (in
->pw_dir
!= NULL
) hsize
+= (strlen(in
->pw_dir
) + 1);
187 if (in
->pw_shell
!= NULL
) hsize
+= (strlen(in
->pw_shell
) + 1);
189 /* Check buffer space */
190 if (hsize
> buflen
) return -1;
192 /* Copy result into caller's struct passwd, using buffer for memory */
196 if (in
->pw_name
!= NULL
)
199 hsize
= strlen(in
->pw_name
) + 1;
200 memmove(bp
, in
->pw_name
, hsize
);
204 out
->pw_passwd
= NULL
;
205 if (in
->pw_passwd
!= NULL
)
208 hsize
= strlen(in
->pw_passwd
) + 1;
209 memmove(bp
, in
->pw_passwd
, hsize
);
213 out
->pw_uid
= in
->pw_uid
;
215 out
->pw_gid
= in
->pw_gid
;
217 out
->pw_change
= in
->pw_change
;
219 out
->pw_class
= NULL
;
220 if (in
->pw_class
!= NULL
)
223 hsize
= strlen(in
->pw_class
) + 1;
224 memmove(bp
, in
->pw_class
, hsize
);
228 out
->pw_gecos
= NULL
;
229 if (in
->pw_gecos
!= NULL
)
232 hsize
= strlen(in
->pw_gecos
) + 1;
233 memmove(bp
, in
->pw_gecos
, hsize
);
238 if (in
->pw_dir
!= NULL
)
241 hsize
= strlen(in
->pw_dir
) + 1;
242 memmove(bp
, in
->pw_dir
, hsize
);
246 out
->pw_shell
= NULL
;
247 if (in
->pw_shell
!= NULL
)
250 hsize
= strlen(in
->pw_shell
) + 1;
251 memmove(bp
, in
->pw_shell
, hsize
);
255 out
->pw_expire
= in
->pw_expire
;
261 cache_user(struct passwd
*pw
)
263 struct passwd
*pwcache
;
265 if (pw
== NULL
) return;
267 pthread_mutex_lock(&_user_cache_lock
);
269 pwcache
= copy_user(pw
);
271 if (_user_cache
[_user_cache_index
] != NULL
) LI_ils_free(_user_cache
[_user_cache_index
], ENTRY_SIZE
);
273 _user_cache
[_user_cache_index
] = pwcache
;
274 _user_cache_index
= (_user_cache_index
+ 1) % USER_CACHE_SIZE
;
276 _user_cache_init
= 1;
278 pthread_mutex_unlock(&_user_cache_lock
);
286 /* don't consult cache if it has not been initialized */
287 if (_user_cache_init
== 0) return 1;
289 status
= LI_L1_cache_check(ENTRY_KEY
);
291 /* don't consult cache if it is disabled or if we can't validate */
292 if ((status
== LI_L1_CACHE_DISABLED
) || (status
== LI_L1_CACHE_FAILED
)) return 1;
294 /* return 0 if cache is OK */
295 if (status
== LI_L1_CACHE_OK
) return 0;
298 pthread_mutex_lock(&_user_cache_lock
);
300 for (i
= 0; i
< USER_CACHE_SIZE
; i
++)
302 LI_ils_free(_user_cache
[i
], ENTRY_SIZE
);
303 _user_cache
[i
] = NULL
;
306 _user_cache_index
= 0;
308 pthread_mutex_unlock(&_user_cache_lock
);
310 /* don't consult cache - it's now empty */
314 static struct passwd
*
315 cache_getpwnam(const char *name
)
318 struct passwd
*pw
, *res
;
320 if (name
== NULL
) return NULL
;
321 if (user_cache_check() != 0) return NULL
;
323 pthread_mutex_lock(&_user_cache_lock
);
325 for (i
= 0; i
< USER_CACHE_SIZE
; i
++)
327 pw
= (struct passwd
*)_user_cache
[i
];
328 if (pw
== NULL
) continue;
329 if (pw
->pw_name
== NULL
) continue;
331 if (!strcmp(name
, pw
->pw_name
))
334 pthread_mutex_unlock(&_user_cache_lock
);
339 pthread_mutex_unlock(&_user_cache_lock
);
343 static struct passwd
*
344 cache_getpwuid(uid_t uid
)
347 struct passwd
*pw
, *res
;
349 if (user_cache_check() != 0) return NULL
;
351 pthread_mutex_lock(&_user_cache_lock
);
353 for (i
= 0; i
< USER_CACHE_SIZE
; i
++)
355 pw
= (struct passwd
*)_user_cache
[i
];
356 if (pw
== NULL
) continue;
358 if (uid
== pw
->pw_uid
)
361 pthread_mutex_unlock(&_user_cache_lock
);
366 pthread_mutex_unlock(&_user_cache_lock
);
371 static struct passwd
*
372 ds_getpwuid(uid_t uid
)
374 static int proc
= -1;
377 snprintf(val
, sizeof(val
), "%d", (int)uid
);
378 return (struct passwd
*)LI_getone("getpwuid", &proc
, extract_user
, "uid", val
);
381 static struct passwd
*
382 ds_getpwnam(const char *name
)
384 static int proc
= -1;
386 return (struct passwd
*)LI_getone("getpwnam", &proc
, extract_user
, "login", name
);
392 LI_data_free_kvarray(LI_data_find_key(ENTRY_KEY
));
402 static struct passwd
*
405 static int proc
= -1;
407 return (struct passwd
*)LI_getent("getpwent", &proc
, extract_user
, ENTRY_KEY
, ENTRY_SIZE
);
410 static struct passwd
*
411 getpw_internal(const char *name
, uid_t uid
, int source
)
422 res
= cache_getpwnam(name
);
425 res
= cache_getpwuid(uid
);
433 else if (_ds_running())
438 res
= ds_getpwnam(name
);
441 res
= ds_getpwuid(uid
);
449 if (res
!= NULL
) add_to_cache
= 1;
453 pthread_mutex_lock(&_user_lock
);
458 res
= copy_user(LI_files_getpwnam(name
));
461 res
= copy_user(LI_files_getpwuid(uid
));
464 res
= copy_user(LI_files_getpwent());
469 pthread_mutex_unlock(&_user_lock
);
472 if (add_to_cache
== 1) cache_user(res
);
477 static struct passwd
*
478 getpw(const char *name
, uid_t uid
, int source
)
480 struct passwd
*res
= NULL
;
481 struct li_thread_info
*tdata
;
483 tdata
= LI_data_create_key(ENTRY_KEY
, ENTRY_SIZE
);
484 if (tdata
== NULL
) return NULL
;
486 res
= getpw_internal(name
, uid
, source
);
488 LI_data_recycle(tdata
, res
, ENTRY_SIZE
);
489 return (struct passwd
*)tdata
->li_entry
;
493 getpw_r(const char *name
, uid_t uid
, int source
, struct passwd
*pwd
, char *buffer
, size_t bufsize
, struct passwd
**result
)
495 struct passwd
*res
= NULL
;
500 res
= getpw_internal(name
, uid
, source
);
501 if (res
== NULL
) return 0;
503 status
= copy_user_r(res
, pwd
, buffer
, bufsize
);
505 LI_ils_free(res
, ENTRY_SIZE
);
507 if (status
!= 0) return ERANGE
;
514 getpwnam(const char *name
)
516 return getpw(name
, -2, PW_GET_NAME
);
522 return getpw(NULL
, uid
, PW_GET_UID
);
528 return getpw(NULL
, -2, PW_GET_ENT
);
534 if (_ds_running()) ds_setpwent();
535 else LI_files_setpwent();
541 if (_ds_running()) ds_endpwent();
542 else LI_files_endpwent();
546 getpwnam_r(const char *name
, struct passwd
*pwd
, char *buffer
, size_t bufsize
, struct passwd
**result
)
548 return getpw_r(name
, -2, PW_GET_NAME
, pwd
, buffer
, bufsize
, result
);
552 getpwuid_r(uid_t uid
, struct passwd
*pwd
, char *buffer
, size_t bufsize
, struct passwd
**result
)
554 return getpw_r(NULL
, uid
, PW_GET_UID
, pwd
, buffer
, bufsize
, result
);