4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
29 * This module fetches group and passwd structs for the caller. It
30 * uses a hash table to speed up retrieval of repeated entries. If
31 * the attempts to initialize the hash tables fail, this just
32 * continues the slow way.
42 #include "pkglocale.h"
48 #define ERR_DUPFAIL "%s: strdup(%s) failed.\n"
49 #define ERR_ADDFAIL "%s: add_cache() failed.\n"
50 #define ERR_BADMEMB "%s: %s in \"%s\" %s structure is invalid.\n"
51 #define ERR_NOGRP "dup_gr_ent(): no group entry provided.\n"
52 #define ERR_NOPWD "dup_pw_ent(): no passwd entry provided.\n"
53 #define ERR_NOINIT "%s: init_cache() failed.\n"
54 #define ERR_MALLOC "%s: malloc(%d) failed for %s.\n"
56 static Cache
*pwnam_cache
= (Cache
*) NULL
;
57 static Cache
*grnam_cache
= (Cache
*) NULL
;
58 static Cache
*pwuid_cache
= (Cache
*) NULL
;
59 static Cache
*grgid_cache
= (Cache
*) NULL
;
61 static int dup_gr_ent(struct group
*grp
);
62 static int dup_pw_ent(struct passwd
*pwp
);
65 * These indicate whether the hash table has been initialized for the four
68 static int is_a_pwnam_cache
;
69 static int is_a_grnam_cache
;
70 static int is_a_pwuid_cache
;
71 static int is_a_grgid_cache
;
73 extern char *get_install_root(void);
76 * If there's a grnam cache, then update it with this new
77 * group, otherwise, skip it.
80 cache_alloc(char *fname
, int len
, size_t struct_size
)
85 * Allocate space for the Item pointer, key and data.
87 if ((itemp
= (Item
*) malloc(sizeof (*itemp
))) ==
89 (void) fprintf(stderr
,
90 pkg_gt(ERR_MALLOC
), fname
,
91 sizeof (*itemp
), "itemp");
92 } else if ((itemp
->key
= (char *)malloc(len
)) == NULL
) {
93 (void) fprintf(stderr
, pkg_gt(ERR_MALLOC
), fname
, len
,
96 } else if ((itemp
->data
= malloc(struct_size
)) == NULL
) {
97 (void) fprintf(stderr
, pkg_gt(ERR_MALLOC
), fname
,
98 struct_size
, "itemp->data");
102 /* Set length parameters. */
104 itemp
->datal
= struct_size
;
109 return ((Item
*) NULL
);
112 /* Get the required group structure based upon the group name. */
119 static int cache_failed
;
121 /* Attempt to initialize the grname cache. */
122 if (!is_a_grnam_cache
&& !cache_failed
) {
123 if (init_cache(&grnam_cache
, HASHSIZE
, BSZ
,
124 (int (*)())NULL
, (int (*)())NULL
) == -1) {
125 (void) fprintf(stderr
, pkg_gt(ERR_NOINIT
), "cgrnam()");
126 grnam_cache
= (Cache
*) NULL
;
129 is_a_grnam_cache
= 1;
132 len
= strlen(nam
) + 1;
134 /* First look in the cache. Failing that, do it the hard way. */
135 if ((itemp
= lookup_cache(grnam_cache
, nam
, len
)) == Null_Item
) {
137 /* Get the group by name. */
138 if ((grp
= clgrnam(nam
)) != NULL
||
139 (grp
= getgrnam(nam
)) != NULL
) {
140 /* A group by that name exists on this machine. */
143 * Effectively no such group since struct
144 * couldn't be duplicated.
146 grp
= (struct group
*)NULL
;
148 * If there's a grnam cache, then update it with this
149 * new group, otherwise, skip it.
151 else if (is_a_grnam_cache
) {
152 if ((itemp
= cache_alloc("cgrnam()", len
,
153 sizeof (struct group
))) != Null_Item
) {
155 * With that allocated, insert the
156 * group name as key and set the key
159 (void) memmove(itemp
->key
, nam
, len
);
162 * Insert the data associated with
163 * the key and the data length.
165 (void) memmove(itemp
->data
, grp
,
166 sizeof (struct group
));
168 /* Insert the Item into the cache. */
169 if (add_cache(grnam_cache
, itemp
) == -1)
170 (void) fprintf(stderr
,
177 } else /* Found it in the cache. */
178 return ((struct group
*)itemp
->data
);
187 static int cache_failed
;
189 if (!is_a_pwnam_cache
&& !cache_failed
) {
190 if (init_cache(&pwnam_cache
, HASHSIZE
, BSZ
,
191 (int (*)())NULL
, (int (*)())NULL
) == -1) {
192 (void) fprintf(stderr
, pkg_gt(ERR_NOINIT
), "cpwnam()");
193 pwnam_cache
= (Cache
*) NULL
;
196 is_a_pwnam_cache
= 1;
199 len
= strlen(nam
) + 1;
201 /* First look in the cache. Failing that, do it the hard way. */
202 if ((itemp
= lookup_cache(pwnam_cache
, nam
, len
)) == Null_Item
) {
204 /* Get the passwd by name. */
205 if ((pwd
= clpwnam(nam
)) != NULL
||
206 (pwd
= getpwnam(nam
)) != NULL
) {
207 /* A passwd by that name exists on this machine. */
210 * Effectively no such passwd since struct
211 * couldn't be duplicated.
213 pwd
= (struct passwd
*)NULL
;
215 * If there's a pwnam cache, then update it with this
216 * new passwd, otherwise, skip it.
218 else if (is_a_pwnam_cache
) {
220 * Allocate space for the Item pointer, key
223 if ((itemp
= cache_alloc("cpwnam()", len
,
224 sizeof (struct passwd
))) != Null_Item
) {
226 * With that allocated, insert the
227 * group name as key and set the key
230 (void) memmove(itemp
->key
, nam
, len
);
233 * Insert the data associated with
234 * the key and the data length.
236 (void) memmove(itemp
->data
, pwd
,
237 sizeof (struct passwd
));
239 if (add_cache(pwnam_cache
, itemp
) == -1)
240 (void) fprintf(stderr
,
247 } else /* Found it in the cache. */
248 return ((struct passwd
*)itemp
->data
);
252 uid_hash(void *datap
, int datalen
, int hsz
)
259 return (*((uid_t
*)datap
) % hsz
);
263 uid_comp(void *datap1
, void *datap2
, int datalen
)
270 return (*((uid_t
*)datap1
) - *((uid_t
*)datap2
));
279 static int cache_failed
;
281 if (!is_a_grgid_cache
&& !cache_failed
) {
282 if (init_cache(&grgid_cache
, HASHSIZE
, BSZ
,
283 uid_hash
, uid_comp
) == -1) {
284 (void) fprintf(stderr
, pkg_gt(ERR_NOINIT
), "cgrgid()");
285 grgid_cache
= (Cache
*) NULL
;
288 is_a_grgid_cache
= 1;
291 len
= sizeof (uid_t
);
293 /* First look in the cache. Failing that, do it the hard way. */
294 if ((itemp
= lookup_cache(grgid_cache
, &gid
, len
)) == Null_Item
) {
295 if ((grp
= clgrgid(gid
)) != NULL
||
296 (grp
= getgrgid(gid
)) != NULL
) {
297 /* A group by that number exists on this machine. */
300 * Effectively no such group since struct
301 * couldn't be duplicated.
303 grp
= (struct group
*)NULL
;
305 * If there's a grnam cache, then update it with this
306 * new group, otherwise, skip it.
308 else if (is_a_grgid_cache
) {
309 if ((itemp
= cache_alloc("cgrgid()", len
,
310 sizeof (struct group
))) != Null_Item
) {
312 * With that allocated, insert the
313 * group name as key and set the key
316 (void) memmove(itemp
->key
, &gid
, len
);
319 * Insert the data associated with
320 * the key and the data length.
322 (void) memmove(itemp
->data
, grp
,
323 sizeof (struct group
));
325 if (add_cache(grgid_cache
, itemp
) == -1)
326 (void) fprintf(stderr
,
333 } else /* Found it in the cache. */
334 return ((struct group
*)itemp
->data
);
343 static int cache_failed
;
345 if (!is_a_pwuid_cache
&& !cache_failed
) {
346 if (init_cache(&pwuid_cache
, HASHSIZE
, BSZ
,
347 uid_hash
, uid_comp
) == -1) {
348 (void) fprintf(stderr
,
349 pkg_gt(ERR_NOINIT
), "cpwuid()");
350 pwuid_cache
= (Cache
*) NULL
;
353 is_a_pwuid_cache
= 1;
356 len
= sizeof (uid_t
);
358 /* First look in the cache. Failing that, do it the hard way. */
359 if ((itemp
= lookup_cache(pwuid_cache
, &uid
, len
)) == Null_Item
) {
361 /* Get the passwd by number. */
362 if ((pwd
= clpwuid(uid
)) != NULL
||
363 (pwd
= getpwuid(uid
)) != NULL
) {
364 /* A passwd by that user ID exists on this machine. */
367 * Effectively no such passwd since struct
368 * couldn't be duplicated.
370 pwd
= (struct passwd
*)NULL
;
372 * If there's a pwuid cache, then update it with this
373 * new passwd, otherwise, skip it.
375 else if (is_a_pwuid_cache
) {
376 if ((itemp
= cache_alloc("cpwuid()", len
,
377 sizeof (struct passwd
))) != Null_Item
) {
379 * With that allocated, insert the
380 * group name as key and set the key
383 (void) memmove(itemp
->key
, &uid
, len
);
386 * Insert the data associated with
387 * the key and the data length.
389 (void) memmove(itemp
->data
, pwd
,
390 sizeof (struct passwd
));
392 if (add_cache(pwuid_cache
, itemp
) == -1)
393 (void) fprintf(stderr
,
400 } else /* Found it in the cache. */
401 return ((struct passwd
*)itemp
->data
);
405 * This function duplicates the group structure provided from kernel static
406 * memory. There is a lot of defensive coding here because there have been
407 * problems with the getgr*() functions. They will sometimes provide NULL
408 * values instead of pointers to NULL values. There has been no explanation
409 * for the reason behind this; but, this function takes a NULL to be an
410 * invalid (char *) and returns an error.
413 dup_gr_ent(struct group
*grp
)
417 int nent
= 0; /* Number of entries in the member list. */
420 if (grp
->gr_name
== NULL
) {
421 (void) fprintf(stderr
,
422 pkg_gt(ERR_BADMEMB
), "dup_gr_ent()", "gr_name",
425 } else if ((grp
->gr_name
= strdup(grp
->gr_name
)) == NULL
) {
426 (void) fprintf(stderr
,
427 pkg_gt(ERR_DUPFAIL
), "dup_gr_ent()", "gr_name");
430 if (grp
->gr_passwd
== NULL
) {
431 (void) fprintf(stderr
,
432 pkg_gt(ERR_BADMEMB
), "dup_gr_ent()", "gr_passwd",
433 grp
->gr_name
, "group");
435 } else if ((grp
->gr_passwd
= strdup(grp
->gr_passwd
)) == NULL
) {
436 (void) fprintf(stderr
,
437 pkg_gt(ERR_DUPFAIL
), "dup_gr_ent()", "gr_passwd");
441 * Allocate space for the member list and move the members
446 * First count the members. The nent variable will be
447 * the number of members + 1 for the terminator.
449 for (tp
= grp
->gr_mem
; *tp
; nent
++, tp
++);
451 /* Now allocate room for the pointers. */
452 memp
= malloc(sizeof (char **)* (nent
+1));
455 (void) fprintf(stderr
,
456 pkg_gt(ERR_MALLOC
), "dup_gr_ent()",
457 (sizeof (char **)* (nent
+1)),
463 * Now copy over the pointers and entries. It should
464 * be noted that if the structure is messed up here,
465 * the resulting member list will be truncated at the
468 for (nent
= 0, tp
= grp
->gr_mem
; *tp
; tp
++) {
469 if ((memp
[nent
++] = strdup(*tp
)) == NULL
) {
470 (void) fprintf(stderr
,
471 pkg_gt(ERR_DUPFAIL
), "dup_gr_ent()",
477 (void) fprintf(stderr
,
478 pkg_gt(ERR_BADMEMB
), "dup_gr_ent()", "gr_mem",
479 grp
->gr_name
, "group");
483 (void) fprintf(stderr
, pkg_gt(ERR_NOGRP
));
491 * This function duplicates the passwd structure provided from kernel static
492 * memory. As in the above function, since there have been problems with the
493 * getpw*() functions, the structure provided is rigorously scrubbed. This
494 * function takes a NULL to be an invalid (char *) and returns an error if
498 dup_pw_ent(struct passwd
*pwd
)
501 if (pwd
->pw_name
== NULL
) {
502 (void) fprintf(stderr
,
503 pkg_gt(ERR_BADMEMB
), "dup_pw_ent()", "pw_name",
504 "unknown", "passwd");
506 } else if ((pwd
->pw_name
= strdup(pwd
->pw_name
)) == NULL
) {
507 (void) fprintf(stderr
,
508 pkg_gt(ERR_DUPFAIL
), "dup_pw_ent()", "pw_name");
512 if (pwd
->pw_passwd
== NULL
) {
513 (void) fprintf(stderr
,
514 pkg_gt(ERR_BADMEMB
), "dup_pw_ent()", "pw_passwd",
515 pwd
->pw_name
, "passwd");
517 } else if ((pwd
->pw_passwd
= strdup(pwd
->pw_passwd
)) == NULL
) {
518 (void) fprintf(stderr
,
519 pkg_gt(ERR_DUPFAIL
), "dup_pw_ent()", "pw_passwd");
523 if (pwd
->pw_age
== NULL
) {
524 (void) fprintf(stderr
,
525 pkg_gt(ERR_BADMEMB
), "dup_pw_ent()", "pw_age",
526 pwd
->pw_name
, "passwd");
528 } else if ((pwd
->pw_age
= strdup(pwd
->pw_age
)) == NULL
) {
529 (void) fprintf(stderr
,
530 pkg_gt(ERR_DUPFAIL
), "dup_pw_ent()", "pw_age");
534 if (pwd
->pw_comment
== NULL
) {
535 (void) fprintf(stderr
,
536 pkg_gt(ERR_BADMEMB
), "dup_pw_ent()", "pw_comment",
537 pwd
->pw_name
, "passwd");
539 } else if ((pwd
->pw_comment
= strdup(pwd
->pw_comment
)) ==
541 (void) fprintf(stderr
,
542 pkg_gt(ERR_DUPFAIL
), "dup_pw_ent()", "pw_comment");
546 if (pwd
->pw_gecos
== NULL
) {
547 (void) fprintf(stderr
,
548 pkg_gt(ERR_BADMEMB
), "dup_pw_ent()", "pw_gecos",
549 pwd
->pw_name
, "passwd");
551 } else if ((pwd
->pw_gecos
= strdup(pwd
->pw_gecos
)) == NULL
) {
552 (void) fprintf(stderr
,
553 pkg_gt(ERR_DUPFAIL
), "dup_pw_ent()", "pw_gecos");
557 if (pwd
->pw_dir
== NULL
) {
558 (void) fprintf(stderr
,
559 pkg_gt(ERR_BADMEMB
), "dup_pw_ent()", "pw_dir",
560 pwd
->pw_name
, "passwd");
562 } else if ((pwd
->pw_dir
= strdup(pwd
->pw_dir
)) == NULL
) {
563 (void) fprintf(stderr
,
564 pkg_gt(ERR_DUPFAIL
), "dup_pw_ent()", "pw_dir");
568 if (pwd
->pw_shell
== NULL
) {
569 (void) fprintf(stderr
,
570 pkg_gt(ERR_BADMEMB
), "dup_pw_ent()", "pw_shell",
571 pwd
->pw_name
, "passwd");
573 } else if ((pwd
->pw_shell
= strdup(pwd
->pw_shell
)) == NULL
) {
574 (void) fprintf(stderr
,
575 pkg_gt(ERR_DUPFAIL
), "dup_pw_ent()", "pw_shell");
579 (void) fprintf(stderr
, pkg_gt(ERR_NOPWD
));
587 * Check the client's etc/group file for the group name
589 * returns a pointer to the group structure if the group is found
590 * returns NULL if not found
596 char *instroot
, *buf
;
600 if ((instroot
= get_install_root()) != NULL
) {
601 bufsz
= strlen(instroot
) + strlen(GROUP
) + 1;
602 if ((buf
= (char *)malloc(bufsz
)) == NULL
) {
603 (void) fprintf(stderr
,
604 pkg_gt(ERR_MALLOC
), "clgrnam()",
605 strlen(instroot
) + strlen(GROUP
), "buf");
607 (void) snprintf(buf
, bufsz
, "%s%s", instroot
, GROUP
);
608 if ((gr_ptr
= fopen(buf
, "r")) == NULL
) {
612 while ((gr
= fgetgrent(gr_ptr
)) != NULL
) {
613 if (strcmp(gr
->gr_name
, nam
) == 0) {
619 (void) fclose(gr_ptr
);
627 * Check the client's etc/passwd file for the user name
629 * returns a pointer to the passwd structure if the passwd is found
630 * returns NULL if not found
636 char *instroot
, *buf
;
639 if ((instroot
= get_install_root()) != NULL
) {
640 if (asprintf(&buf
, "%s%s", instroot
, PASSWD
) < 0) {
641 (void) fprintf(stderr
,
642 pkg_gt(ERR_MALLOC
), "clpwnam()",
643 strlen(instroot
) + strlen(PASSWD
), "buf");
646 if ((pw_ptr
= fopen(buf
, "r")) == NULL
) {
650 while ((pw
= fgetpwent(pw_ptr
)) != NULL
) {
651 if (strcmp(pw
->pw_name
, nam
) == 0) {
657 (void) fclose(pw_ptr
);
665 * Check the client's etc/group file for the group id
667 * returns a pointer to the group structure if the group id is found
668 * returns NULL if not found
674 char *instroot
, *buf
;
677 if ((instroot
= get_install_root()) != NULL
) {
678 if (asprintf(&buf
, "%s%s", instroot
, GROUP
) < 0) {
679 (void) fprintf(stderr
,
680 pkg_gt(ERR_MALLOC
), "clgrgid()",
681 strlen(instroot
) + strlen(GROUP
), "buf");
685 if ((gr_ptr
= fopen(buf
, "r")) == NULL
) {
689 while ((gr
= fgetgrent(gr_ptr
)) != NULL
) {
690 if (gr
->gr_gid
== gid
) {
696 (void) fclose(gr_ptr
);
704 * Check the client's etc/passwd file for the user id
706 * returns a pointer to the passwd structure if the user id is found
707 * returns NULL if not found
713 char *instroot
, *buf
;
716 if ((instroot
= get_install_root()) != NULL
) {
717 if (asprintf(&buf
, "%s%s", instroot
, PASSWD
) < 0) {
718 (void) fprintf(stderr
, pkg_gt(ERR_MALLOC
), "clpwuid()",
719 strlen(instroot
) + strlen(PASSWD
), "buf");
722 if ((pw_ptr
= fopen(buf
, "r")) == NULL
) {
726 while ((pw
= fgetpwent(pw_ptr
)) != NULL
) {
727 if (pw
->pw_uid
== uid
) {
733 (void) fclose(pw_ptr
);