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>
32 #include <rpc/types.h>
35 #include <netinet/in.h>
40 #include "_lu_types.h"
43 #include "lu_overrides.h"
45 #define USER_CACHE_SIZE 10
46 #define DEFAULT_USER_CACHE_TTL 10
48 static pthread_mutex_t _user_cache_lock
= PTHREAD_MUTEX_INITIALIZER
;
49 static void *_user_cache
[USER_CACHE_SIZE
] = { NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
};
50 static unsigned int _user_cache_best_before
[USER_CACHE_SIZE
] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
51 static unsigned int _user_cache_index
= 0;
52 static unsigned int _user_cache_ttl
= DEFAULT_USER_CACHE_TTL
;
54 static pthread_mutex_t _user_lock
= PTHREAD_MUTEX_INITIALIZER
;
61 free_user_data(struct passwd
*p
)
63 if (p
== NULL
) return;
65 if (p
->pw_name
!= NULL
) free(p
->pw_name
);
66 if (p
->pw_passwd
!= NULL
) free(p
->pw_passwd
);
67 if (p
->pw_class
!= NULL
) free(p
->pw_class
);
68 if (p
->pw_gecos
!= NULL
) free(p
->pw_gecos
);
69 if (p
->pw_dir
!= NULL
) free(p
->pw_dir
);
70 if (p
->pw_shell
!= NULL
) free(p
->pw_shell
);
74 free_user(struct passwd
*p
)
76 if (p
== NULL
) return;
82 free_lu_thread_info_user(void *x
)
84 struct lu_thread_info
*tdata
;
86 if (x
== NULL
) return;
88 tdata
= (struct lu_thread_info
*)x
;
90 if (tdata
->lu_entry
!= NULL
)
92 free_user((struct passwd
*)tdata
->lu_entry
);
93 tdata
->lu_entry
= NULL
;
96 _lu_data_free_vm_xdr(tdata
);
101 static struct passwd
*
102 extract_user(XDR
*xdr
)
104 int i
, j
, nvals
, nkeys
, status
;
108 if (xdr
== NULL
) return NULL
;
110 if (!xdr_int(xdr
, &nkeys
)) return NULL
;
112 p
= (struct passwd
*)calloc(1, sizeof(struct passwd
));
117 for (i
= 0; i
< nkeys
; i
++)
123 status
= _lu_xdr_attribute(xdr
, &key
, &vals
, &nvals
);
138 if ((p
->pw_name
== NULL
) && (!strcmp("name", key
)))
140 p
->pw_name
= vals
[0];
143 else if ((p
->pw_passwd
== NULL
) && (!strcmp("passwd", key
)))
145 p
->pw_passwd
= vals
[0];
148 else if ((p
->pw_class
== NULL
) && (!strcmp("class", key
)))
150 p
->pw_class
= vals
[0];
153 else if ((p
->pw_gecos
== NULL
) && (!strcmp("realname", key
)))
155 p
->pw_gecos
= vals
[0];
158 else if ((p
->pw_dir
== NULL
) && (!strcmp("home", key
)))
163 else if ((p
->pw_shell
== NULL
) && (!strcmp("shell", key
)))
165 p
->pw_shell
= vals
[0];
168 else if ((p
->pw_uid
== (uid_t
)-2) && (!strcmp("uid", key
)))
170 p
->pw_uid
= atoi(vals
[0]);
171 if ((p
->pw_uid
== 0) && (strcmp(vals
[0], "0"))) p
->pw_uid
= -2;
173 else if ((p
->pw_gid
== (gid_t
)-2) && (!strcmp("gid", key
)))
175 p
->pw_gid
= atoi(vals
[0]);
176 if ((p
->pw_gid
== 0) && (strcmp(vals
[0], "0"))) p
->pw_gid
= -2;
178 else if (!strcmp("change", key
))
180 p
->pw_change
= atoi(vals
[0]);
182 else if (!strcmp("expire", key
))
184 p
->pw_expire
= atoi(vals
[0]);
190 for (; j
< nvals
; j
++) free(vals
[j
]);
195 if (p
->pw_name
== NULL
) p
->pw_name
= strdup("");
196 if (p
->pw_passwd
== NULL
) p
->pw_passwd
= strdup("");
197 if (p
->pw_class
== NULL
) p
->pw_class
= strdup("");
198 if (p
->pw_gecos
== NULL
) p
->pw_gecos
= strdup("");
199 if (p
->pw_dir
== NULL
) p
->pw_dir
= strdup("");
200 if (p
->pw_shell
== NULL
) p
->pw_shell
= strdup("");
205 static struct passwd
*
206 copy_user(struct passwd
*in
)
210 if (in
== NULL
) return NULL
;
212 p
= (struct passwd
*)calloc(1, sizeof(struct passwd
));
214 p
->pw_name
= LU_COPY_STRING(in
->pw_name
);
215 p
->pw_passwd
= LU_COPY_STRING(in
->pw_passwd
);
216 p
->pw_uid
= in
->pw_uid
;
217 p
->pw_gid
= in
->pw_gid
;
218 p
->pw_change
= in
->pw_change
;
219 p
->pw_class
= LU_COPY_STRING(in
->pw_class
);
220 p
->pw_gecos
= LU_COPY_STRING(in
->pw_gecos
);
221 p
->pw_dir
= LU_COPY_STRING(in
->pw_dir
);
222 p
->pw_shell
= LU_COPY_STRING(in
->pw_shell
);
223 p
->pw_expire
= in
->pw_expire
;
229 copy_user_r(struct passwd
*in
, struct passwd
*out
, char *buffer
, int buflen
)
234 if (in
== NULL
) return -1;
235 if (out
== NULL
) return -1;
237 if (buffer
== NULL
) buflen
= 0;
239 /* Calculate size of input */
241 if (in
->pw_name
!= NULL
) hsize
+= (strlen(in
->pw_name
) + 1);
242 if (in
->pw_passwd
!= NULL
) hsize
+= (strlen(in
->pw_passwd
) + 1);
243 if (in
->pw_class
!= NULL
) hsize
+= (strlen(in
->pw_class
) + 1);
244 if (in
->pw_gecos
!= NULL
) hsize
+= (strlen(in
->pw_gecos
) + 1);
245 if (in
->pw_dir
!= NULL
) hsize
+= (strlen(in
->pw_dir
) + 1);
246 if (in
->pw_shell
!= NULL
) hsize
+= (strlen(in
->pw_shell
) + 1);
248 /* Check buffer space */
249 if (hsize
> buflen
) return -1;
251 /* Copy result into caller's struct passwd, using buffer for memory */
255 if (in
->pw_name
!= NULL
)
258 hsize
= strlen(in
->pw_name
) + 1;
259 memmove(bp
, in
->pw_name
, hsize
);
263 out
->pw_passwd
= NULL
;
264 if (in
->pw_passwd
!= NULL
)
267 hsize
= strlen(in
->pw_passwd
) + 1;
268 memmove(bp
, in
->pw_passwd
, hsize
);
272 out
->pw_uid
= in
->pw_uid
;
274 out
->pw_gid
= in
->pw_gid
;
276 out
->pw_change
= in
->pw_change
;
278 out
->pw_class
= NULL
;
279 if (in
->pw_class
!= NULL
)
282 hsize
= strlen(in
->pw_class
) + 1;
283 memmove(bp
, in
->pw_class
, hsize
);
287 out
->pw_gecos
= NULL
;
288 if (in
->pw_gecos
!= NULL
)
291 hsize
= strlen(in
->pw_gecos
) + 1;
292 memmove(bp
, in
->pw_gecos
, hsize
);
297 if (in
->pw_dir
!= NULL
)
300 hsize
= strlen(in
->pw_dir
) + 1;
301 memmove(bp
, in
->pw_dir
, hsize
);
305 out
->pw_shell
= NULL
;
306 if (in
->pw_shell
!= NULL
)
309 hsize
= strlen(in
->pw_shell
) + 1;
310 memmove(bp
, in
->pw_shell
, hsize
);
314 out
->pw_expire
= in
->pw_expire
;
320 recycle_user(struct lu_thread_info
*tdata
, struct passwd
*in
)
324 if (tdata
== NULL
) return;
325 p
= (struct passwd
*)tdata
->lu_entry
;
330 tdata
->lu_entry
= NULL
;
333 if (tdata
->lu_entry
== NULL
)
335 tdata
->lu_entry
= in
;
341 p
->pw_name
= in
->pw_name
;
342 p
->pw_passwd
= in
->pw_passwd
;
343 p
->pw_uid
= in
->pw_uid
;
344 p
->pw_gid
= in
->pw_gid
;
345 p
->pw_change
= in
->pw_change
;
346 p
->pw_class
= in
->pw_class
;
347 p
->pw_gecos
= in
->pw_gecos
;
348 p
->pw_dir
= in
->pw_dir
;
349 p
->pw_shell
= in
->pw_shell
;
350 p
->pw_expire
= in
->pw_expire
;
355 __private_extern__
unsigned int
358 return _user_cache_ttl
;
361 __private_extern__
void
362 set_user_cache_ttl(unsigned int ttl
)
366 pthread_mutex_lock(&_user_cache_lock
);
368 _user_cache_ttl
= ttl
;
372 for (i
= 0; i
< USER_CACHE_SIZE
; i
++)
374 if (_user_cache
[i
] == NULL
) continue;
376 free_user((struct passwd
*)_user_cache
[i
]);
377 _user_cache
[i
] = NULL
;
378 _user_cache_best_before
[i
] = 0;
382 pthread_mutex_unlock(&_user_cache_lock
);
386 cache_user(struct passwd
*pw
)
389 struct passwd
*pwcache
;
391 if (_user_cache_ttl
== 0) return;
392 if (pw
== NULL
) return;
394 pthread_mutex_lock(&_user_cache_lock
);
396 pwcache
= copy_user(pw
);
398 gettimeofday(&now
, NULL
);
400 if (_user_cache
[_user_cache_index
] != NULL
)
401 free_user((struct passwd
*)_user_cache
[_user_cache_index
]);
403 _user_cache
[_user_cache_index
] = pwcache
;
404 _user_cache_best_before
[_user_cache_index
] = now
.tv_sec
+ _user_cache_ttl
;
405 _user_cache_index
= (_user_cache_index
+ 1) % USER_CACHE_SIZE
;
407 pthread_mutex_unlock(&_user_cache_lock
);
410 static struct passwd
*
411 cache_getpwnam(const char *name
)
414 struct passwd
*pw
, *res
;
417 if (_user_cache_ttl
== 0) return NULL
;
418 if (name
== NULL
) return NULL
;
420 pthread_mutex_lock(&_user_cache_lock
);
422 gettimeofday(&now
, NULL
);
424 for (i
= 0; i
< USER_CACHE_SIZE
; i
++)
426 if (_user_cache_best_before
[i
] == 0) continue;
427 if ((unsigned int)now
.tv_sec
> _user_cache_best_before
[i
]) continue;
429 pw
= (struct passwd
*)_user_cache
[i
];
431 if (pw
->pw_name
== NULL
) continue;
433 if (!strcmp(name
, pw
->pw_name
))
436 pthread_mutex_unlock(&_user_cache_lock
);
441 pthread_mutex_unlock(&_user_cache_lock
);
445 static struct passwd
*
446 cache_getpwuid(int uid
)
449 struct passwd
*pw
, *res
;
452 if (_user_cache_ttl
== 0) return NULL
;
454 pthread_mutex_lock(&_user_cache_lock
);
456 gettimeofday(&now
, NULL
);
458 for (i
= 0; i
< USER_CACHE_SIZE
; i
++)
460 if (_user_cache_best_before
[i
] == 0) continue;
461 if ((unsigned int)now
.tv_sec
> _user_cache_best_before
[i
]) continue;
463 pw
= (struct passwd
*)_user_cache
[i
];
465 if ((uid_t
)uid
== pw
->pw_uid
)
468 pthread_mutex_unlock(&_user_cache_lock
);
473 pthread_mutex_unlock(&_user_cache_lock
);
477 static struct passwd
*
481 unsigned int datalen
;
483 static int proc
= -1;
489 if (_lookup_link(_lu_port
, "getpwuid_A", &proc
) != KERN_SUCCESS
)
499 if (_lookup_all(_lu_port
, proc
, (unit
*)&uid
, 1, &lookup_buf
, &datalen
)
505 datalen
*= BYTES_PER_XDR_UNIT
;
506 if ((lookup_buf
== NULL
) || (datalen
== 0)) return NULL
;
508 xdrmem_create(&inxdr
, lookup_buf
, datalen
, XDR_DECODE
);
511 if (!xdr_int(&inxdr
, &count
))
514 vm_deallocate(mach_task_self(), (vm_address_t
)lookup_buf
, datalen
);
521 vm_deallocate(mach_task_self(), (vm_address_t
)lookup_buf
, datalen
);
525 p
= extract_user(&inxdr
);
527 vm_deallocate(mach_task_self(), (vm_address_t
)lookup_buf
, datalen
);
532 static struct passwd
*
533 lu_getpwnam(const char *name
)
536 unsigned int datalen
;
537 char namebuf
[_LU_MAXLUSTRLEN
+ BYTES_PER_XDR_UNIT
];
540 static int proc
= -1;
546 if (_lookup_link(_lu_port
, "getpwnam_A", &proc
) != KERN_SUCCESS
)
552 xdrmem_create(&outxdr
, namebuf
, sizeof(namebuf
), XDR_ENCODE
);
553 if (!xdr__lu_string(&outxdr
, (_lu_string
*)&name
))
555 xdr_destroy(&outxdr
);
562 if (_lookup_all(_lu_port
, proc
, (unit
*)namebuf
,
563 xdr_getpos(&outxdr
) / BYTES_PER_XDR_UNIT
, &lookup_buf
, &datalen
)
566 xdr_destroy(&outxdr
);
570 xdr_destroy(&outxdr
);
572 datalen
*= BYTES_PER_XDR_UNIT
;
573 if ((lookup_buf
== NULL
) || (datalen
== 0)) return NULL
;
575 xdrmem_create(&inxdr
, lookup_buf
, datalen
, XDR_DECODE
);
578 if (!xdr_int(&inxdr
, &count
))
581 vm_deallocate(mach_task_self(), (vm_address_t
)lookup_buf
, datalen
);
588 vm_deallocate(mach_task_self(), (vm_address_t
)lookup_buf
, datalen
);
592 p
= extract_user(&inxdr
);
594 vm_deallocate(mach_task_self(), (vm_address_t
)lookup_buf
, datalen
);
603 struct lu_thread_info
*tdata
;
605 tdata
= _lu_data_create_key(_lu_data_key_user
, free_lu_thread_info_user
);
606 _lu_data_free_vm_xdr(tdata
);
616 static struct passwd
*
620 static int proc
= -1;
621 struct lu_thread_info
*tdata
;
623 tdata
= _lu_data_create_key(_lu_data_key_user
, free_lu_thread_info_user
);
626 tdata
= (struct lu_thread_info
*)calloc(1, sizeof(struct lu_thread_info
));
627 _lu_data_set_key(_lu_data_key_user
, tdata
);
630 if (tdata
->lu_vm
== NULL
)
634 if (_lookup_link(_lu_port
, "getpwent_A", &proc
) != KERN_SUCCESS
)
641 if (_lookup_all(_lu_port
, proc
, NULL
, 0, &(tdata
->lu_vm
), &(tdata
->lu_vm_length
)) != KERN_SUCCESS
)
647 /* mig stubs measure size in words (4 bytes) */
648 tdata
->lu_vm_length
*= 4;
650 if (tdata
->lu_xdr
!= NULL
)
652 xdr_destroy(tdata
->lu_xdr
);
655 tdata
->lu_xdr
= (XDR
*)calloc(1, sizeof(XDR
));
657 xdrmem_create(tdata
->lu_xdr
, tdata
->lu_vm
, tdata
->lu_vm_length
, XDR_DECODE
);
658 if (!xdr_int(tdata
->lu_xdr
, &tdata
->lu_vm_cursor
))
665 if (tdata
->lu_vm_cursor
== 0)
671 p
= extract_user(tdata
->lu_xdr
);
678 tdata
->lu_vm_cursor
--;
683 static struct passwd
*
684 getpw_internal(const char *name
, uid_t uid
, int source
)
686 static char *loginName
= NULL
;
687 static struct passwd
*loginEnt
= NULL
;
692 if (loginName
== NULL
)
695 if ((l
!= NULL
) && (strcmp("root", l
) != 0))
697 pthread_mutex_lock(&_user_lock
);
698 if ((loginEnt
== NULL
) && (l
!= NULL
) && (*l
!= '\0'))
702 loginEnt
= lu_getpwnam(l
);
706 loginEnt
= copy_user(_old_getpwnam(l
));
711 pthread_mutex_unlock(&_user_lock
);
715 if (loginEnt
!= NULL
)
720 if (strcmp(name
, loginEnt
->pw_name
) == 0)
724 if (strcmp(name
, loginEnt
->pw_gecos
) == 0)
730 if (uid
== loginEnt
->pw_uid
)
732 source
= PW_GET_NAME
;
747 res
= cache_getpwnam(name
);
750 res
= cache_getpwuid(uid
);
759 else if (_lu_running())
764 res
= lu_getpwnam(name
);
767 res
= lu_getpwuid(uid
);
777 pthread_mutex_lock(&_user_lock
);
781 res
= copy_user(_old_getpwnam(name
));
784 res
= copy_user(_old_getpwuid(uid
));
787 res
= copy_user(_old_getpwent());
791 pthread_mutex_unlock(&_user_lock
);
794 if (from_cache
== 0) cache_user(res
);
799 static struct passwd
*
800 getpw(const char *name
, uid_t uid
, int source
)
802 struct passwd
*res
= NULL
;
803 struct lu_thread_info
*tdata
;
805 tdata
= _lu_data_create_key(_lu_data_key_user
, free_lu_thread_info_user
);
808 tdata
= (struct lu_thread_info
*)calloc(1, sizeof(struct lu_thread_info
));
809 _lu_data_set_key(_lu_data_key_user
, tdata
);
812 res
= getpw_internal(name
, uid
, source
);
814 recycle_user(tdata
, res
);
816 return (struct passwd
*)tdata
->lu_entry
;
820 getpw_r(const char *name
, uid_t uid
, int source
, struct passwd
*pwd
, char *buffer
, size_t bufsize
, struct passwd
**result
)
822 struct passwd
*res
= NULL
;
828 res
= getpw_internal(name
, uid
, source
);
829 if (res
== NULL
) return -1;
831 status
= copy_user_r(res
, pwd
, buffer
, bufsize
);
845 getpwnam(const char *name
)
847 return getpw(name
, -2, PW_GET_NAME
);
853 return getpw(NULL
, uid
, PW_GET_UID
);
859 return getpw(NULL
, -2, PW_GET_ENT
);
865 if (_lu_running()) lu_setpwent();
866 else _old_setpwent();
873 if (_lu_running()) lu_endpwent();
874 else _old_endpwent();
878 getpwnam_r(const char *name
, struct passwd
*pwd
, char *buffer
, size_t bufsize
, struct passwd
**result
)
880 return getpw_r(name
, -2, PW_GET_NAME
, pwd
, buffer
, bufsize
, result
);
884 getpwuid_r(uid_t uid
, struct passwd
*pwd
, char *buffer
, size_t bufsize
, struct passwd
**result
)
886 return getpw_r(NULL
, uid
, PW_GET_UID
, pwd
, buffer
, bufsize
, result
);