xref: /illumos-gate/usr/src/lib/libpkg/common/ncgrpw.c (revision 0774d909988cf217e4b3c0e093f4790d5aa9c965)
1 /*
2  * CDDL HEADER START
3  *
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.
7  *
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.
12  *
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]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 
28 /*
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.
33  */
34 
35 #include <pwd.h>
36 #include <grp.h>
37 #include <string.h>
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <unistd.h>
41 #include "pkglib.h"
42 #include "pkglocale.h"
43 #include "nhash.h"
44 
45 #define	HASHSIZE	151
46 #define	BSZ		4
47 
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"
55 
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;
60 
61 static int dup_gr_ent(struct group *grp);
62 static int dup_pw_ent(struct passwd *pwp);
63 
64 /*
65  * These indicate whether the hash table has been initialized for the four
66  * categories.
67  */
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;
72 
73 extern char *get_install_root(void);
74 
75 /*
76  * If there's a grnam cache, then update it with this new
77  * group, otherwise, skip it.
78  */
79 static Item *
80 cache_alloc(char *fname, int len, size_t struct_size)
81 {
82 	Item *itemp;
83 
84 	/*
85 	 * Allocate space for the Item pointer, key and data.
86 	 */
87 	if ((itemp = (Item *) malloc(sizeof (*itemp))) ==
88 	    Null_Item) {
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,
94 		    "itemp->key");
95 		free(itemp);
96 	} else if ((itemp->data = malloc(struct_size)) == NULL) {
97 		(void) fprintf(stderr, pkg_gt(ERR_MALLOC), fname,
98 		    struct_size, "itemp->data");
99 		free(itemp->key);
100 		free(itemp);
101 	} else {
102 		/* Set length parameters. */
103 		itemp->keyl = len;
104 		itemp->datal = struct_size;
105 
106 		return (itemp);
107 	}
108 
109 	return ((Item *) NULL);
110 }
111 
112 /* Get the required group structure based upon the group name. */
113 struct group *
114 cgrnam(char *nam)
115 {
116 	struct group *grp;
117 	Item *itemp;
118 	int len;
119 	static int cache_failed;
120 
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;
127 			cache_failed = 1;
128 		} else
129 			is_a_grnam_cache = 1;
130 	}
131 
132 	len = strlen(nam) + 1;
133 
134 	/* First look in the cache. Failing that, do it the hard way. */
135 	if ((itemp = lookup_cache(grnam_cache, nam, len)) == Null_Item) {
136 
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. */
141 			if (dup_gr_ent(grp))
142 				/*
143 				 * Effectively no such group since struct
144 				 * couldn't be duplicated.
145 				 */
146 				grp = (struct group *)NULL;
147 			/*
148 			 * If there's a grnam cache, then update it with this
149 			 * new group, otherwise, skip it.
150 			 */
151 			else if (is_a_grnam_cache) {
152 				if ((itemp = cache_alloc("cgrnam()", len,
153 				    sizeof (struct group))) != Null_Item) {
154 					/*
155 					 * With that allocated, insert the
156 					 * group name as key and set the key
157 					 * length.
158 					 */
159 					(void) memmove(itemp->key, nam, len);
160 
161 					/*
162 					 * Insert the data associated with
163 					 * the key and the data length.
164 					 */
165 					(void) memmove(itemp->data, grp,
166 					    sizeof (struct group));
167 
168 					/* Insert the Item into the cache. */
169 					if (add_cache(grnam_cache, itemp) == -1)
170 						(void) fprintf(stderr,
171 						    pkg_gt(ERR_ADDFAIL),
172 						    "cgrnam()");
173 				}
174 			}
175 		}
176 		return (grp);
177 	} else	/* Found it in the cache. */
178 		return ((struct group *)itemp->data);
179 }
180 
181 struct passwd *
182 cpwnam(char *nam)
183 {
184 	struct passwd *pwd;
185 	Item *itemp;
186 	int len;
187 	static int cache_failed;
188 
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;
194 			cache_failed = 1;
195 		} else
196 			is_a_pwnam_cache = 1;
197 	}
198 
199 	len = strlen(nam) + 1;
200 
201 	/* First look in the cache. Failing that, do it the hard way. */
202 	if ((itemp = lookup_cache(pwnam_cache, nam, len)) == Null_Item) {
203 
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. */
208 			if (dup_pw_ent(pwd))
209 				/*
210 				 * Effectively no such passwd since struct
211 				 * couldn't be duplicated.
212 				 */
213 				pwd = (struct passwd *)NULL;
214 			/*
215 			 * If there's a pwnam cache, then update it with this
216 			 * new passwd, otherwise, skip it.
217 			 */
218 			else if (is_a_pwnam_cache) {
219 				/*
220 				 * Allocate space for the Item pointer, key
221 				 * and data.
222 				 */
223 				if ((itemp = cache_alloc("cpwnam()", len,
224 				    sizeof (struct passwd))) != Null_Item) {
225 					/*
226 					 * With that allocated, insert the
227 					 * group name as key and set the key
228 					 * length.
229 					 */
230 					(void) memmove(itemp->key, nam, len);
231 
232 					/*
233 					 * Insert the data associated with
234 					 * the key and the data length.
235 					 */
236 					(void) memmove(itemp->data, pwd,
237 					    sizeof (struct passwd));
238 
239 					if (add_cache(pwnam_cache, itemp) == -1)
240 						(void) fprintf(stderr,
241 						    pkg_gt(ERR_ADDFAIL),
242 						    "cpwnam()");
243 				}
244 			}
245 		}
246 		return (pwd);
247 	} else	/* Found it in the cache. */
248 		return ((struct passwd *)itemp->data);
249 }
250 
251 static int
252 uid_hash(void *datap, int datalen, int hsz)
253 {
254 #ifdef lint
255 	int i = datalen;
256 	datalen = i;
257 #endif	/* lint */
258 
259 	return (*((uid_t *)datap) % hsz);
260 }
261 
262 static int
263 uid_comp(void *datap1, void *datap2, int datalen)
264 {
265 #ifdef lint
266 	int i = datalen;
267 	datalen = i;
268 #endif	/* lint */
269 
270 	return (*((uid_t *)datap1) - *((uid_t *)datap2));
271 }
272 
273 struct group *
274 cgrgid(gid_t gid)
275 {
276 	struct group *grp;
277 	Item *itemp;
278 	int len;
279 	static int cache_failed;
280 
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;
286 			cache_failed = 1;
287 		} else
288 			is_a_grgid_cache = 1;
289 	}
290 
291 	len = sizeof (uid_t);
292 
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. */
298 			if (dup_gr_ent(grp))
299 				/*
300 				 * Effectively no such group since struct
301 				 * couldn't be duplicated.
302 				 */
303 				grp = (struct group *)NULL;
304 			/*
305 			 * If there's a grnam cache, then update it with this
306 			 * new group, otherwise, skip it.
307 			 */
308 			else if (is_a_grgid_cache) {
309 				if ((itemp = cache_alloc("cgrgid()", len,
310 				    sizeof (struct group))) != Null_Item) {
311 					/*
312 					 * With that allocated, insert the
313 					 * group name as key and set the key
314 					 * length.
315 					 */
316 					(void) memmove(itemp->key, &gid, len);
317 
318 					/*
319 					 * Insert the data associated with
320 					 * the key and the data length.
321 					 */
322 					(void) memmove(itemp->data, grp,
323 					    sizeof (struct group));
324 
325 					if (add_cache(grgid_cache, itemp) == -1)
326 						(void) fprintf(stderr,
327 						    pkg_gt(ERR_ADDFAIL),
328 						    "cgrgid()");
329 				}
330 			}
331 		}
332 		return (grp);
333 	} else	/* Found it in the cache. */
334 		return ((struct group *)itemp->data);
335 }
336 
337 struct passwd *
338 cpwuid(uid_t uid)
339 {
340 	struct passwd *pwd;
341 	Item *itemp;
342 	int len;
343 	static int cache_failed;
344 
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;
351 			cache_failed = 1;
352 		} else
353 			is_a_pwuid_cache = 1;
354 	}
355 
356 	len = sizeof (uid_t);
357 
358 	/* First look in the cache. Failing that, do it the hard way. */
359 	if ((itemp = lookup_cache(pwuid_cache, &uid, len)) == Null_Item) {
360 
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. */
365 			if (dup_pw_ent(pwd))
366 				/*
367 				 * Effectively no such passwd since struct
368 				 * couldn't be duplicated.
369 				 */
370 				pwd = (struct passwd *)NULL;
371 			/*
372 			 * If there's a pwuid cache, then update it with this
373 			 * new passwd, otherwise, skip it.
374 			 */
375 			else if (is_a_pwuid_cache) {
376 				if ((itemp = cache_alloc("cpwuid()", len,
377 				    sizeof (struct passwd))) != Null_Item) {
378 					/*
379 					 * With that allocated, insert the
380 					 * group name as key and set the key
381 					 * length.
382 					 */
383 					(void) memmove(itemp->key, &uid, len);
384 
385 					/*
386 					 * Insert the data associated with
387 					 * the key and the data length.
388 					 */
389 					(void) memmove(itemp->data, pwd,
390 					    sizeof (struct passwd));
391 
392 					if (add_cache(pwuid_cache, itemp) == -1)
393 						(void) fprintf(stderr,
394 						    pkg_gt(ERR_ADDFAIL),
395 						    "cpwuid()");
396 				}
397 			}
398 		}
399 		return (pwd);
400 	} else	/* Found it in the cache. */
401 		return ((struct passwd *)itemp->data);
402 }
403 
404 /*
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.
411  */
412 static int
413 dup_gr_ent(struct group *grp)
414 {
415 	char **tp = NULL;
416 	char **memp = NULL;
417 	int	nent = 0;	/* Number of entries in the member list. */
418 
419 	if (grp) {
420 		if (grp->gr_name == NULL) {
421 			(void) fprintf(stderr,
422 			    pkg_gt(ERR_BADMEMB), "dup_gr_ent()", "gr_name",
423 			    "unknown", "group");
424 			return (-1);
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");
428 			return (-1);
429 		}
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");
434 			return (-1);
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");
438 			return (-1);
439 		}
440 		/*
441 		 * Allocate space for the member list and move the members
442 		 * into it.
443 		 */
444 		if (grp->gr_mem) {
445 			/*
446 			 * First count the members. The nent variable will be
447 			 * the number of members + 1 for the terminator.
448 			 */
449 			for (tp = grp->gr_mem; *tp; nent++, tp++);
450 
451 			/* Now allocate room for the pointers. */
452 			memp = malloc(sizeof (char **)* (nent+1));
453 
454 			if (memp == NULL) {
455 				(void) fprintf(stderr,
456 				    pkg_gt(ERR_MALLOC), "dup_gr_ent()",
457 				    (sizeof (char **)* (nent+1)),
458 				    "memp");
459 				return (-1);
460 			}
461 
462 			/*
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
466 			 * NULL entry.
467 			 */
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()",
472 					    "gr_mem");
473 					return (-1);
474 				}
475 			}
476 		} else {
477 			(void) fprintf(stderr,
478 			    pkg_gt(ERR_BADMEMB), "dup_gr_ent()", "gr_mem",
479 			    grp->gr_name, "group");
480 			return (-1);
481 		}
482 	} else {
483 		(void) fprintf(stderr, pkg_gt(ERR_NOGRP));
484 		return (-1);
485 	}
486 	memp[nent++] = '\0';
487 	return (0);
488 }
489 
490 /*
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
495  * one is detected.
496  */
497 static int
498 dup_pw_ent(struct passwd *pwd)
499 {
500 	if (pwd) {
501 		if (pwd->pw_name == NULL) {
502 			(void) fprintf(stderr,
503 			    pkg_gt(ERR_BADMEMB), "dup_pw_ent()", "pw_name",
504 			    "unknown", "passwd");
505 			return (-1);
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");
509 			return (-1);
510 		}
511 
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");
516 			return (-1);
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");
520 			return (-1);
521 		}
522 
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");
527 			return (-1);
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");
531 			return (-1);
532 		}
533 
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");
538 			return (-1);
539 		} else if ((pwd->pw_comment = strdup(pwd->pw_comment)) ==
540 		    NULL) {
541 			(void) fprintf(stderr,
542 			    pkg_gt(ERR_DUPFAIL), "dup_pw_ent()", "pw_comment");
543 			return (-1);
544 		}
545 
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");
550 			return (-1);
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");
554 			return (-1);
555 		}
556 
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");
561 			return (-1);
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");
565 			return (-1);
566 		}
567 
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");
572 			return (-1);
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");
576 			return (-1);
577 		}
578 	} else {
579 		(void) fprintf(stderr, pkg_gt(ERR_NOPWD));
580 		return (-1);
581 	}
582 
583 	return (0);
584 }
585 
586 /*
587  * Check the client's etc/group file for the group name
588  *
589  * returns a pointer to the group structure if the group is found
590  * returns NULL if not found
591  */
592 struct group *
593 clgrnam(char *nam)
594 {
595 	struct group *gr;
596 	char *instroot, *buf;
597 	FILE *gr_ptr;
598 	size_t bufsz;
599 
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");
606 		}
607 		(void) snprintf(buf, bufsz, "%s%s", instroot, GROUP);
608 		if ((gr_ptr = fopen(buf, "r")) == NULL) {
609 			free(buf);
610 			return (NULL);
611 		} else {
612 			while ((gr = fgetgrent(gr_ptr)) != NULL) {
613 				if (strcmp(gr->gr_name, nam) == 0) {
614 					break;
615 				}
616 			}
617 		}
618 		free(buf);
619 		(void) fclose(gr_ptr);
620 		return (gr);
621 	} else {
622 		return (NULL);
623 	}
624 }
625 
626 /*
627  * Check the client's etc/passwd file for the user name
628  *
629  * returns a pointer to the passwd structure if the passwd is found
630  * returns NULL if not found
631  */
632 struct passwd *
633 clpwnam(char *nam)
634 {
635 	struct passwd *pw;
636 	char *instroot, *buf;
637 	FILE *pw_ptr;
638 
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");
644 			return (NULL);
645 		}
646 		if ((pw_ptr = fopen(buf, "r")) == NULL) {
647 			free(buf);
648 			return (NULL);
649 		} else {
650 			while ((pw = fgetpwent(pw_ptr)) != NULL) {
651 				if (strcmp(pw->pw_name, nam) == 0) {
652 					break;
653 				}
654 			}
655 		}
656 		free(buf);
657 		(void) fclose(pw_ptr);
658 		return (pw);
659 	} else {
660 		return (NULL);
661 	}
662 }
663 
664 /*
665  * Check the client's etc/group file for the group id
666  *
667  * returns a pointer to the group structure if the group id is found
668  * returns NULL if not found
669  */
670 struct group *
671 clgrgid(gid_t gid)
672 {
673 	struct group *gr;
674 	char *instroot, *buf;
675 	FILE *gr_ptr;
676 
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");
682 			return (NULL);
683 		}
684 
685 		if ((gr_ptr = fopen(buf, "r")) == NULL) {
686 			free(buf);
687 			return (NULL);
688 		} else {
689 			while ((gr = fgetgrent(gr_ptr)) != NULL) {
690 				if (gr->gr_gid == gid) {
691 					break;
692 				}
693 			}
694 		}
695 		free(buf);
696 		(void) fclose(gr_ptr);
697 		return (gr);
698 	} else {
699 		return (NULL);
700 	}
701 }
702 
703 /*
704  * Check the client's etc/passwd file for the user id
705  *
706  * returns a pointer to the passwd structure if the user id is found
707  * returns NULL if not found
708  */
709 struct passwd *
710 clpwuid(uid_t uid)
711 {
712 	struct passwd *pw;
713 	char *instroot, *buf;
714 	FILE *pw_ptr;
715 
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");
720 			return (NULL);
721 		}
722 		if ((pw_ptr = fopen(buf, "r")) == NULL) {
723 			free(buf);
724 			return (NULL);
725 		} else {
726 			while ((pw = fgetpwent(pw_ptr)) != NULL) {
727 				if (pw->pw_uid == uid) {
728 					break;
729 				}
730 			}
731 		}
732 		free(buf);
733 		(void) fclose(pw_ptr);
734 		return (pw);
735 	} else {
736 		return (NULL);
737 	}
738 }
739