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>
39 #include "_lu_types.h"
42 #include "lu_overrides.h"
44 #define USER_CACHE_SIZE 10
45 #define DEFAULT_USER_CACHE_TTL 10
47 static pthread_mutex_t _user_cache_lock
= PTHREAD_MUTEX_INITIALIZER
;
48 static void *_user_cache
[USER_CACHE_SIZE
] = { NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
};
49 static unsigned int _user_cache_best_before
[USER_CACHE_SIZE
] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
50 static unsigned int _user_cache_index
= 0;
51 static unsigned int _user_cache_ttl
= DEFAULT_USER_CACHE_TTL
;
53 static pthread_mutex_t _user_lock
= PTHREAD_MUTEX_INITIALIZER
;
60 free_user_data(struct passwd
*p
)
62 if (p
== NULL
) return;
64 if (p
->pw_name
!= NULL
) free(p
->pw_name
);
65 if (p
->pw_passwd
!= NULL
) free(p
->pw_passwd
);
66 if (p
->pw_class
!= NULL
) free(p
->pw_class
);
67 if (p
->pw_gecos
!= NULL
) free(p
->pw_gecos
);
68 if (p
->pw_dir
!= NULL
) free(p
->pw_dir
);
69 if (p
->pw_shell
!= NULL
) free(p
->pw_shell
);
73 free_user(struct passwd
*p
)
75 if (p
== NULL
) return;
81 free_lu_thread_info_user(void *x
)
83 struct lu_thread_info
*tdata
;
85 if (x
== NULL
) return;
87 tdata
= (struct lu_thread_info
*)x
;
89 if (tdata
->lu_entry
!= NULL
)
91 free_user((struct passwd
*)tdata
->lu_entry
);
92 tdata
->lu_entry
= NULL
;
95 _lu_data_free_vm_xdr(tdata
);
100 static struct passwd
*
101 extract_user(XDR
*xdr
)
103 int i
, j
, nvals
, nkeys
, status
;
107 if (xdr
== NULL
) return NULL
;
109 if (!xdr_int(xdr
, &nkeys
)) return NULL
;
111 p
= (struct passwd
*)calloc(1, sizeof(struct passwd
));
116 for (i
= 0; i
< nkeys
; i
++)
122 status
= _lu_xdr_attribute(xdr
, &key
, &vals
, &nvals
);
137 if ((p
->pw_name
== NULL
) && (!strcmp("name", key
)))
139 p
->pw_name
= vals
[0];
142 else if ((p
->pw_passwd
== NULL
) && (!strcmp("passwd", key
)))
144 p
->pw_passwd
= vals
[0];
147 else if ((p
->pw_class
== NULL
) && (!strcmp("class", key
)))
149 p
->pw_class
= vals
[0];
152 else if ((p
->pw_gecos
== NULL
) && (!strcmp("realname", key
)))
154 p
->pw_gecos
= vals
[0];
157 else if ((p
->pw_dir
== NULL
) && (!strcmp("home", key
)))
162 else if ((p
->pw_shell
== NULL
) && (!strcmp("shell", key
)))
164 p
->pw_shell
= vals
[0];
167 else if ((p
->pw_uid
== (uid_t
)-2) && (!strcmp("uid", key
)))
169 p
->pw_uid
= atoi(vals
[0]);
170 if ((p
->pw_uid
== 0) && (strcmp(vals
[0], "0"))) p
->pw_uid
= -2;
172 else if ((p
->pw_gid
== (gid_t
)-2) && (!strcmp("gid", key
)))
174 p
->pw_gid
= atoi(vals
[0]);
175 if ((p
->pw_gid
== 0) && (strcmp(vals
[0], "0"))) p
->pw_gid
= -2;
177 else if (!strcmp("change", key
))
179 p
->pw_change
= atoi(vals
[0]);
181 else if (!strcmp("expire", key
))
183 p
->pw_expire
= atoi(vals
[0]);
189 for (; j
< nvals
; j
++) free(vals
[j
]);
194 if (p
->pw_name
== NULL
) p
->pw_name
= strdup("");
195 if (p
->pw_passwd
== NULL
) p
->pw_passwd
= strdup("");
196 if (p
->pw_class
== NULL
) p
->pw_class
= strdup("");
197 if (p
->pw_gecos
== NULL
) p
->pw_gecos
= strdup("");
198 if (p
->pw_dir
== NULL
) p
->pw_dir
= strdup("");
199 if (p
->pw_shell
== NULL
) p
->pw_shell
= strdup("");
204 static struct passwd
*
205 copy_user(struct passwd
*in
)
209 if (in
== NULL
) return NULL
;
211 p
= (struct passwd
*)calloc(1, sizeof(struct passwd
));
213 p
->pw_name
= LU_COPY_STRING(in
->pw_name
);
214 p
->pw_passwd
= LU_COPY_STRING(in
->pw_passwd
);
215 p
->pw_uid
= in
->pw_uid
;
216 p
->pw_gid
= in
->pw_gid
;
217 p
->pw_change
= in
->pw_change
;
218 p
->pw_class
= LU_COPY_STRING(in
->pw_class
);
219 p
->pw_gecos
= LU_COPY_STRING(in
->pw_gecos
);
220 p
->pw_dir
= LU_COPY_STRING(in
->pw_dir
);
221 p
->pw_shell
= LU_COPY_STRING(in
->pw_shell
);
222 p
->pw_expire
= in
->pw_expire
;
228 copy_user_r(struct passwd
*in
, struct passwd
*out
, char *buffer
, int buflen
)
233 if (in
== NULL
) return -1;
234 if (out
== NULL
) return -1;
236 if (buffer
== NULL
) buflen
= 0;
238 /* Calculate size of input */
240 if (in
->pw_name
!= NULL
) hsize
+= strlen(in
->pw_name
);
241 if (in
->pw_passwd
!= NULL
) hsize
+= strlen(in
->pw_passwd
);
242 if (in
->pw_class
!= NULL
) hsize
+= strlen(in
->pw_class
);
243 if (in
->pw_gecos
!= NULL
) hsize
+= strlen(in
->pw_gecos
);
244 if (in
->pw_dir
!= NULL
) hsize
+= strlen(in
->pw_dir
);
245 if (in
->pw_shell
!= NULL
) hsize
+= strlen(in
->pw_shell
);
247 /* Check buffer space */
248 if (hsize
> buflen
) return -1;
250 /* Copy result into caller's struct passwd, using buffer for memory */
254 if (in
->pw_name
!= NULL
)
257 hsize
= strlen(in
->pw_name
) + 1;
258 memmove(bp
, in
->pw_name
, hsize
);
262 out
->pw_passwd
= NULL
;
263 if (in
->pw_passwd
!= NULL
)
266 hsize
= strlen(in
->pw_passwd
) + 1;
267 memmove(bp
, in
->pw_passwd
, hsize
);
271 out
->pw_uid
= in
->pw_uid
;
273 out
->pw_gid
= in
->pw_gid
;
275 out
->pw_change
= in
->pw_change
;
277 out
->pw_class
= NULL
;
278 if (in
->pw_class
!= NULL
)
281 hsize
= strlen(in
->pw_class
) + 1;
282 memmove(bp
, in
->pw_class
, hsize
);
286 out
->pw_gecos
= NULL
;
287 if (in
->pw_gecos
!= NULL
)
290 hsize
= strlen(in
->pw_gecos
) + 1;
291 memmove(bp
, in
->pw_gecos
, hsize
);
296 if (in
->pw_dir
!= NULL
)
299 hsize
= strlen(in
->pw_dir
) + 1;
300 memmove(bp
, in
->pw_dir
, hsize
);
304 out
->pw_shell
= NULL
;
305 if (in
->pw_shell
!= NULL
)
308 hsize
= strlen(in
->pw_shell
) + 1;
309 memmove(bp
, in
->pw_shell
, hsize
);
313 out
->pw_expire
= in
->pw_expire
;
319 recycle_user(struct lu_thread_info
*tdata
, struct passwd
*in
)
323 if (tdata
== NULL
) return;
324 p
= (struct passwd
*)tdata
->lu_entry
;
329 tdata
->lu_entry
= NULL
;
332 if (tdata
->lu_entry
== NULL
)
334 tdata
->lu_entry
= in
;
340 p
->pw_name
= in
->pw_name
;
341 p
->pw_passwd
= in
->pw_passwd
;
342 p
->pw_uid
= in
->pw_uid
;
343 p
->pw_gid
= in
->pw_gid
;
344 p
->pw_change
= in
->pw_change
;
345 p
->pw_class
= in
->pw_class
;
346 p
->pw_gecos
= in
->pw_gecos
;
347 p
->pw_dir
= in
->pw_dir
;
348 p
->pw_shell
= in
->pw_shell
;
349 p
->pw_expire
= in
->pw_expire
;
354 __private_extern__
unsigned int
357 return _user_cache_ttl
;
360 __private_extern__
void
361 set_user_cache_ttl(unsigned int ttl
)
365 pthread_mutex_lock(&_user_cache_lock
);
367 _user_cache_ttl
= ttl
;
371 for (i
= 0; i
< USER_CACHE_SIZE
; i
++)
373 if (_user_cache
[i
] == NULL
) continue;
375 free_user((struct passwd
*)_user_cache
[i
]);
376 _user_cache
[i
] = NULL
;
377 _user_cache_best_before
[i
] = 0;
381 pthread_mutex_unlock(&_user_cache_lock
);
385 cache_user(struct passwd
*pw
)
388 struct passwd
*pwcache
;
390 if (_user_cache_ttl
== 0) return;
391 if (pw
== NULL
) return;
393 pthread_mutex_lock(&_user_cache_lock
);
395 pwcache
= copy_user(pw
);
397 gettimeofday(&now
, NULL
);
399 if (_user_cache
[_user_cache_index
] != NULL
)
400 free_user((struct passwd
*)_user_cache
[_user_cache_index
]);
402 _user_cache
[_user_cache_index
] = pwcache
;
403 _user_cache_best_before
[_user_cache_index
] = now
.tv_sec
+ _user_cache_ttl
;
404 _user_cache_index
= (_user_cache_index
+ 1) % USER_CACHE_SIZE
;
406 pthread_mutex_unlock(&_user_cache_lock
);
409 static struct passwd
*
410 cache_getpwnam(const char *name
)
413 struct passwd
*pw
, *res
;
416 if (_user_cache_ttl
== 0) return NULL
;
417 if (name
== NULL
) return NULL
;
419 pthread_mutex_lock(&_user_cache_lock
);
421 gettimeofday(&now
, NULL
);
423 for (i
= 0; i
< USER_CACHE_SIZE
; i
++)
425 if (_user_cache_best_before
[i
] == 0) continue;
426 if ((unsigned int)now
.tv_sec
> _user_cache_best_before
[i
]) continue;
428 pw
= (struct passwd
*)_user_cache
[i
];
430 if (pw
->pw_name
== NULL
) continue;
432 if (!strcmp(name
, pw
->pw_name
))
435 pthread_mutex_unlock(&_user_cache_lock
);
440 pthread_mutex_unlock(&_user_cache_lock
);
444 static struct passwd
*
445 cache_getpwuid(int uid
)
448 struct passwd
*pw
, *res
;
451 if (_user_cache_ttl
== 0) return NULL
;
453 pthread_mutex_lock(&_user_cache_lock
);
455 gettimeofday(&now
, NULL
);
457 for (i
= 0; i
< USER_CACHE_SIZE
; i
++)
459 if (_user_cache_best_before
[i
] == 0) continue;
460 if ((unsigned int)now
.tv_sec
> _user_cache_best_before
[i
]) continue;
462 pw
= (struct passwd
*)_user_cache
[i
];
464 if ((uid_t
)uid
== pw
->pw_uid
)
467 pthread_mutex_unlock(&_user_cache_lock
);
472 pthread_mutex_unlock(&_user_cache_lock
);
476 static struct passwd
*
480 unsigned int datalen
;
482 static int proc
= -1;
488 if (_lookup_link(_lu_port
, "getpwuid_A", &proc
) != KERN_SUCCESS
)
498 if (_lookup_all(_lu_port
, proc
, (unit
*)&uid
, 1, &lookup_buf
, &datalen
)
504 datalen
*= BYTES_PER_XDR_UNIT
;
505 if ((lookup_buf
== NULL
) || (datalen
== 0)) return NULL
;
507 xdrmem_create(&inxdr
, lookup_buf
, datalen
, XDR_DECODE
);
510 if (!xdr_int(&inxdr
, &count
))
513 vm_deallocate(mach_task_self(), (vm_address_t
)lookup_buf
, datalen
);
520 vm_deallocate(mach_task_self(), (vm_address_t
)lookup_buf
, datalen
);
524 p
= extract_user(&inxdr
);
526 vm_deallocate(mach_task_self(), (vm_address_t
)lookup_buf
, datalen
);
531 static struct passwd
*
532 lu_getpwnam(const char *name
)
535 unsigned int datalen
;
536 char namebuf
[_LU_MAXLUSTRLEN
+ BYTES_PER_XDR_UNIT
];
539 static int proc
= -1;
545 if (_lookup_link(_lu_port
, "getpwnam_A", &proc
) != KERN_SUCCESS
)
551 xdrmem_create(&outxdr
, namebuf
, sizeof(namebuf
), XDR_ENCODE
);
552 if (!xdr__lu_string(&outxdr
, (_lu_string
*)&name
))
554 xdr_destroy(&outxdr
);
561 if (_lookup_all(_lu_port
, proc
, (unit
*)namebuf
,
562 xdr_getpos(&outxdr
) / BYTES_PER_XDR_UNIT
, &lookup_buf
, &datalen
)
565 xdr_destroy(&outxdr
);
569 xdr_destroy(&outxdr
);
571 datalen
*= BYTES_PER_XDR_UNIT
;
572 if ((lookup_buf
== NULL
) || (datalen
== 0)) return NULL
;
574 xdrmem_create(&inxdr
, lookup_buf
, datalen
, XDR_DECODE
);
577 if (!xdr_int(&inxdr
, &count
))
580 vm_deallocate(mach_task_self(), (vm_address_t
)lookup_buf
, datalen
);
587 vm_deallocate(mach_task_self(), (vm_address_t
)lookup_buf
, datalen
);
591 p
= extract_user(&inxdr
);
593 vm_deallocate(mach_task_self(), (vm_address_t
)lookup_buf
, datalen
);
602 struct lu_thread_info
*tdata
;
604 tdata
= _lu_data_create_key(_lu_data_key_user
, free_lu_thread_info_user
);
605 _lu_data_free_vm_xdr(tdata
);
615 static struct passwd
*
619 static int proc
= -1;
620 struct lu_thread_info
*tdata
;
622 tdata
= _lu_data_create_key(_lu_data_key_user
, free_lu_thread_info_user
);
625 tdata
= (struct lu_thread_info
*)calloc(1, sizeof(struct lu_thread_info
));
626 _lu_data_set_key(_lu_data_key_user
, tdata
);
629 if (tdata
->lu_vm
== NULL
)
633 if (_lookup_link(_lu_port
, "getpwent_A", &proc
) != KERN_SUCCESS
)
640 if (_lookup_all(_lu_port
, proc
, NULL
, 0, &(tdata
->lu_vm
), &(tdata
->lu_vm_length
)) != KERN_SUCCESS
)
646 /* mig stubs measure size in words (4 bytes) */
647 tdata
->lu_vm_length
*= 4;
649 if (tdata
->lu_xdr
!= NULL
)
651 xdr_destroy(tdata
->lu_xdr
);
654 tdata
->lu_xdr
= (XDR
*)calloc(1, sizeof(XDR
));
656 xdrmem_create(tdata
->lu_xdr
, tdata
->lu_vm
, tdata
->lu_vm_length
, XDR_DECODE
);
657 if (!xdr_int(tdata
->lu_xdr
, &tdata
->lu_vm_cursor
))
664 if (tdata
->lu_vm_cursor
== 0)
670 p
= extract_user(tdata
->lu_xdr
);
677 tdata
->lu_vm_cursor
--;
682 static struct passwd
*
683 getpw_internal(const char *name
, uid_t uid
, int source
)
685 static char *loginName
= NULL
;
686 static struct passwd
*loginEnt
= NULL
;
691 if (loginName
== NULL
)
694 if ((l
!= NULL
) && (strcmp("root", l
) != 0))
696 pthread_mutex_lock(&_user_lock
);
697 if ((loginEnt
== NULL
) && (l
!= NULL
) && (*l
!= '\0'))
701 loginEnt
= lu_getpwnam(l
);
705 loginEnt
= copy_user(_old_getpwnam(l
));
710 pthread_mutex_unlock(&_user_lock
);
714 if (loginEnt
!= NULL
)
719 if (strcmp(name
, loginEnt
->pw_name
) == 0)
723 if (strcmp(name
, loginEnt
->pw_gecos
) == 0)
729 if (uid
== loginEnt
->pw_uid
)
731 source
= PW_GET_NAME
;
746 res
= cache_getpwnam(name
);
749 res
= cache_getpwuid(uid
);
758 else if (_lu_running())
763 res
= lu_getpwnam(name
);
766 res
= lu_getpwuid(uid
);
776 pthread_mutex_lock(&_user_lock
);
780 res
= copy_user(_old_getpwnam(name
));
783 res
= copy_user(_old_getpwuid(uid
));
786 res
= copy_user(_old_getpwent());
790 pthread_mutex_unlock(&_user_lock
);
793 if (from_cache
== 0) cache_user(res
);
798 static struct passwd
*
799 getpw(const char *name
, uid_t uid
, int source
)
801 struct passwd
*res
= NULL
;
802 struct lu_thread_info
*tdata
;
804 tdata
= _lu_data_create_key(_lu_data_key_user
, free_lu_thread_info_user
);
807 tdata
= (struct lu_thread_info
*)calloc(1, sizeof(struct lu_thread_info
));
808 _lu_data_set_key(_lu_data_key_user
, tdata
);
811 res
= getpw_internal(name
, uid
, source
);
813 recycle_user(tdata
, res
);
815 return (struct passwd
*)tdata
->lu_entry
;
819 getpw_r(const char *name
, uid_t uid
, int source
, struct passwd
*pwd
, char *buffer
, size_t bufsize
, struct passwd
**result
)
821 struct passwd
*res
= NULL
;
827 res
= getpw_internal(name
, uid
, source
);
828 if (res
== NULL
) return -1;
830 status
= copy_user_r(res
, pwd
, buffer
, bufsize
);
844 getpwnam(const char *name
)
846 return getpw(name
, -2, PW_GET_NAME
);
852 return getpw(NULL
, uid
, PW_GET_UID
);
858 return getpw(NULL
, -2, PW_GET_ENT
);
864 if (_lu_running()) lu_setpwent();
865 else _old_setpwent();
872 if (_lu_running()) lu_endpwent();
873 else _old_endpwent();
877 getpwnam_r(const char *name
, struct passwd
*pwd
, char *buffer
, size_t bufsize
, struct passwd
**result
)
879 return getpw_r(name
, -2, PW_GET_NAME
, pwd
, buffer
, bufsize
, result
);
883 getpwuid_r(uid_t uid
, struct passwd
*pwd
, char *buffer
, size_t bufsize
, struct passwd
**result
)
885 return getpw_r(NULL
, uid
, PW_GET_UID
, pwd
, buffer
, bufsize
, result
);