ncgrpw.c revision 9781:ccf49524d5dc
1292932Sdim/*
2292932Sdim * CDDL HEADER START
3292932Sdim *
4292932Sdim * The contents of this file are subject to the terms of the
5292932Sdim * Common Development and Distribution License (the "License").
6292932Sdim * You may not use this file except in compliance with the License.
7292932Sdim *
8292932Sdim * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9292932Sdim * or http://www.opensolaris.org/os/licensing.
10292932Sdim * See the License for the specific language governing permissions
11292932Sdim * and limitations under the License.
12292932Sdim *
13292932Sdim * When distributing Covered Code, include this CDDL HEADER in each
14292932Sdim * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15292932Sdim * If applicable, add the following below this CDDL HEADER, with the
16292932Sdim * fields enclosed by brackets "[]" replaced with your own identifying
17292932Sdim * information: Portions Copyright [yyyy] [name of copyright owner]
18292932Sdim *
19292932Sdim * CDDL HEADER END
20292932Sdim */
21292932Sdim
22292932Sdim/*
23292932Sdim * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
24292932Sdim * Use is subject to license terms.
25292932Sdim */
26292932Sdim
27292932Sdim
28292932Sdim/*
29292932Sdim * This module fetches group and passwd structs for the caller. It
30292932Sdim * uses a hash table to speed up retrieval of repeated entries. If
31292932Sdim * the attempts to initialize the hash tables fail, this just
32292932Sdim * continues the slow way.
33292932Sdim */
34292932Sdim
35292932Sdim#include <pwd.h>
36292932Sdim#include <grp.h>
37292932Sdim#include <string.h>
38292932Sdim#include <stdio.h>
39292932Sdim#include <stdlib.h>
40292932Sdim#include <unistd.h>
41292932Sdim#include "pkglib.h"
42292932Sdim#include "pkglocale.h"
43292932Sdim#include "nhash.h"
44292932Sdim
45292932Sdim#define	HASHSIZE	151
46292932Sdim#define	BSZ		4
47292932Sdim
48292932Sdim#define	ERR_DUPFAIL	"%s: strdup(%s) failed.\n"
49292932Sdim#define	ERR_ADDFAIL	"%s: add_cache() failed.\n"
50292932Sdim#define	ERR_BADMEMB	"%s: %s in \"%s\" %s structure is invalid.\n"
51292932Sdim#define	ERR_NOGRP	"dup_gr_ent(): no group entry provided.\n"
52292932Sdim#define	ERR_NOPWD	"dup_pw_ent(): no passwd entry provided.\n"
53292932Sdim#define	ERR_NOINIT	"%s: init_cache() failed.\n"
54292932Sdim#define	ERR_MALLOC	"%s: malloc(%d) failed for %s.\n"
55292932Sdim
56292932Sdimstatic Cache *pwnam_cache = (Cache *) NULL;
57292932Sdimstatic Cache *grnam_cache = (Cache *) NULL;
58292932Sdimstatic Cache *pwuid_cache = (Cache *) NULL;
59292932Sdimstatic Cache *grgid_cache = (Cache *) NULL;
60292932Sdim
61292932Sdimstatic int dup_gr_ent(struct group *grp);
62292932Sdimstatic int dup_pw_ent(struct passwd *pwp);
63292932Sdim
64292932Sdim/*
65292932Sdim * These indicate whether the hash table has been initialized for the four
66292932Sdim * categories.
67292932Sdim */
68292932Sdimstatic int is_a_pwnam_cache;
69292932Sdimstatic int is_a_grnam_cache;
70292932Sdimstatic int is_a_pwuid_cache;
71292932Sdimstatic int is_a_grgid_cache;
72292932Sdim
73292932Sdimextern char *get_install_root(void);
74292932Sdim
75292932Sdim/*
76292932Sdim * If there's a grnam cache, then update it with this new
77292932Sdim * group, otherwise, skip it.
78292932Sdim */
79292932Sdimstatic Item *
80292932Sdimcache_alloc(char *fname, int len, size_t struct_size)
81292932Sdim{
82292932Sdim	Item *itemp;
83292932Sdim
84292932Sdim	/*
85292932Sdim	 * Allocate space for the Item pointer, key and data.
86292932Sdim	 */
87292932Sdim	if ((itemp = (Item *) malloc(sizeof (*itemp))) ==
88292932Sdim	    Null_Item) {
89292932Sdim		(void) fprintf(stderr,
90292932Sdim		    pkg_gt(ERR_MALLOC), fname,
91292932Sdim		    sizeof (*itemp), "itemp");
92292932Sdim	} else if ((itemp->key = (char *)malloc(len)) == NULL) {
93292932Sdim		(void) fprintf(stderr, pkg_gt(ERR_MALLOC), fname, len,
94292932Sdim		    "itemp->key");
95292932Sdim		free(itemp);
96292932Sdim	} else if ((itemp->data = malloc(struct_size)) == NULL) {
97292932Sdim		(void) fprintf(stderr, pkg_gt(ERR_MALLOC), fname,
98292932Sdim		    struct_size, "itemp->data");
99292932Sdim		free(itemp->key);
100292932Sdim		free(itemp);
101292932Sdim	} else {
102292932Sdim		/* Set length parameters. */
103292932Sdim		itemp->keyl = len;
104292932Sdim		itemp->datal = struct_size;
105292932Sdim
106292932Sdim		return (itemp);
107292932Sdim	}
108292932Sdim
109292932Sdim	return ((Item *) NULL);
110292932Sdim}
111292932Sdim
112292932Sdim/* Get the required group structure based upon the group name. */
113292932Sdimstruct group *
114292932Sdimcgrnam(char *nam)
115292932Sdim{
116292932Sdim	struct group *grp;
117292932Sdim	Item *itemp;
118292932Sdim	int len;
119292932Sdim	static int cache_failed;
120292932Sdim
121292932Sdim	/* Attempt to initialize the grname cache. */
122292932Sdim	if (!is_a_grnam_cache && !cache_failed) {
123292932Sdim		if (init_cache(&grnam_cache, HASHSIZE, BSZ,
124292932Sdim		    (int (*)())NULL, (int (*)())NULL) == -1) {
125292932Sdim			(void) fprintf(stderr, pkg_gt(ERR_NOINIT), "cgrnam()");
126292932Sdim			grnam_cache = (Cache *) NULL;
127292932Sdim			cache_failed = 1;
128292932Sdim		} else
129292932Sdim			is_a_grnam_cache = 1;
130292932Sdim	}
131292932Sdim
132292932Sdim	len = strlen(nam) + 1;
133292932Sdim
134292932Sdim	/* First look in the cache. Failing that, do it the hard way. */
135292932Sdim	if ((itemp = lookup_cache(grnam_cache, nam, len)) == Null_Item) {
136292932Sdim
137292932Sdim		/* Get the group by name. */
138292932Sdim		if ((grp = clgrnam(nam)) != NULL ||
139292932Sdim				(grp = getgrnam(nam)) != NULL) {
140292932Sdim			/* A group by that name exists on this machine. */
141292932Sdim			if (dup_gr_ent(grp))
142292932Sdim				/*
143292932Sdim				 * Effectively no such group since struct
144292932Sdim				 * couldn't be duplicated.
145292932Sdim				 */
146292932Sdim				grp = (struct group *)NULL;
147292932Sdim			/*
148292932Sdim			 * If there's a grnam cache, then update it with this
149292932Sdim			 * new group, otherwise, skip it.
150292932Sdim			 */
151292932Sdim			else if (is_a_grnam_cache) {
152292932Sdim				if ((itemp = cache_alloc("cgrnam()", len,
153292932Sdim				    sizeof (struct group))) != Null_Item) {
154292932Sdim					/*
155292932Sdim					 * With that allocated, insert the
156292932Sdim					 * group name as key and set the key
157292932Sdim					 * length.
158292932Sdim					 */
159292932Sdim					(void) memmove(itemp->key, nam, len);
160292932Sdim
161292932Sdim					/*
162292932Sdim					 * Insert the data associated with
163292932Sdim					 * the key and the data length.
164292932Sdim					 */
165292932Sdim					(void) memmove(itemp->data, grp,
166292932Sdim					    sizeof (struct group));
167292932Sdim
168292932Sdim					/* Insert the Item into the cache. */
169292932Sdim					if (add_cache(grnam_cache, itemp) == -1)
170292932Sdim						(void) fprintf(stderr,
171292932Sdim						    pkg_gt(ERR_ADDFAIL),
172292932Sdim						    "cgrnam()");
173292932Sdim				}
174292932Sdim			}
175292932Sdim		}
176292932Sdim		return (grp);
177292932Sdim	} else	/* Found it in the cache. */
178292932Sdim		return ((struct group *)itemp->data);
179292932Sdim}
180292932Sdim
181292932Sdimstruct passwd *
182292932Sdimcpwnam(char *nam)
183292932Sdim{
184292932Sdim	struct passwd *pwd;
185292932Sdim	Item *itemp;
186292932Sdim	int len;
187292932Sdim	static int cache_failed;
188292932Sdim
189292932Sdim	if (!is_a_pwnam_cache && !cache_failed) {
190292932Sdim		if (init_cache(&pwnam_cache, HASHSIZE, BSZ,
191292932Sdim		    (int (*)())NULL, (int (*)())NULL) == -1) {
192292932Sdim			(void) fprintf(stderr, pkg_gt(ERR_NOINIT), "cpwnam()");
193292932Sdim			pwnam_cache = (Cache *) NULL;
194292932Sdim			cache_failed = 1;
195292932Sdim		} else
196292932Sdim			is_a_pwnam_cache = 1;
197292932Sdim	}
198292932Sdim
199292932Sdim	len = strlen(nam) + 1;
200292932Sdim
201292932Sdim	/* First look in the cache. Failing that, do it the hard way. */
202292932Sdim	if ((itemp = lookup_cache(pwnam_cache, nam, len)) == Null_Item) {
203292932Sdim
204292932Sdim		/* Get the passwd by name. */
205292932Sdim		if ((pwd = clpwnam(nam)) != NULL ||
206292932Sdim				(pwd = getpwnam(nam)) != NULL) {
207292932Sdim			/* A passwd by that name exists on this machine. */
208292932Sdim			if (dup_pw_ent(pwd))
209292932Sdim				/*
210292932Sdim				 * Effectively no such passwd since struct
211292932Sdim				 * couldn't be duplicated.
212292932Sdim				 */
213292932Sdim				pwd = (struct passwd *)NULL;
214292932Sdim			/*
215292932Sdim			 * If there's a pwnam cache, then update it with this
216292932Sdim			 * new passwd, otherwise, skip it.
217292932Sdim			 */
218292932Sdim			else if (is_a_pwnam_cache) {
219292932Sdim				/*
220292932Sdim				 * Allocate space for the Item pointer, key
221292932Sdim				 * and data.
222292932Sdim				 */
223292932Sdim				if ((itemp = cache_alloc("cpwnam()", len,
224292932Sdim				    sizeof (struct passwd))) != Null_Item) {
225292932Sdim					/*
226292932Sdim					 * With that allocated, insert the
227292932Sdim					 * group name as key and set the key
228292932Sdim					 * length.
229292932Sdim					 */
230292932Sdim					(void) memmove(itemp->key, nam, len);
231292932Sdim
232292932Sdim					/*
233292932Sdim					 * Insert the data associated with
234292932Sdim					 * the key and the data length.
235292932Sdim					 */
236292932Sdim					(void) memmove(itemp->data, pwd,
237292932Sdim					    sizeof (struct passwd));
238292932Sdim
239292932Sdim					if (add_cache(pwnam_cache, itemp) == -1)
240292932Sdim						(void) fprintf(stderr,
241292932Sdim						    pkg_gt(ERR_ADDFAIL),
242292932Sdim						    "cpwnam()");
243292932Sdim				}
244292932Sdim			}
245292932Sdim		}
246292932Sdim		return (pwd);
247292932Sdim	} else	/* Found it in the cache. */
248292932Sdim		return ((struct passwd *)itemp->data);
249292932Sdim}
250292932Sdim
251292932Sdimstatic int
252292932Sdimuid_hash(void *datap, int datalen, int hsz)
253292932Sdim{
254292932Sdim#ifdef lint
255292932Sdim	int i = datalen;
256292932Sdim	datalen = i;
257292932Sdim#endif	/* lint */
258292932Sdim
259292932Sdim	return (*((uid_t *)datap) % hsz);
260292932Sdim}
261292932Sdim
262292932Sdimstatic int
263292932Sdimuid_comp(void *datap1, void *datap2, int datalen)
264292932Sdim{
265292932Sdim#ifdef lint
266292932Sdim	int i = datalen;
267292932Sdim	datalen = i;
268292932Sdim#endif	/* lint */
269292932Sdim
270292932Sdim	return (*((uid_t *)datap1) - *((uid_t *)datap2));
271292932Sdim}
272292932Sdim
273292932Sdimstruct group *
274292932Sdimcgrgid(gid_t gid)
275292932Sdim{
276292932Sdim	struct group *grp;
277292932Sdim	Item *itemp;
278292932Sdim	int len;
279292932Sdim	static int cache_failed;
280292932Sdim
281292932Sdim	if (!is_a_grgid_cache && !cache_failed) {
282292932Sdim		if (init_cache(&grgid_cache, HASHSIZE, BSZ,
283292932Sdim		    uid_hash, uid_comp) == -1) {
284292932Sdim			(void) fprintf(stderr, pkg_gt(ERR_NOINIT), "cgrgid()");
285292932Sdim			grgid_cache = (Cache *) NULL;
286292932Sdim			cache_failed = 1;
287292932Sdim		} else
288292932Sdim			is_a_grgid_cache = 1;
289292932Sdim	}
290292932Sdim
291292932Sdim	len = sizeof (uid_t);
292292932Sdim
293292932Sdim	/* First look in the cache. Failing that, do it the hard way. */
294292932Sdim	if ((itemp = lookup_cache(grgid_cache, &gid, len)) == Null_Item) {
295292932Sdim		if ((grp = clgrgid(gid)) != NULL ||
296292932Sdim				(grp = getgrgid(gid)) != NULL) {
297292932Sdim			/* A group by that number exists on this machine. */
298292932Sdim			if (dup_gr_ent(grp))
299292932Sdim				/*
300292932Sdim				 * Effectively no such group since struct
301292932Sdim				 * couldn't be duplicated.
302292932Sdim				 */
303292932Sdim				grp = (struct group *)NULL;
304292932Sdim			/*
305292932Sdim			 * If there's a grnam cache, then update it with this
306292932Sdim			 * new group, otherwise, skip it.
307292932Sdim			 */
308292932Sdim			else if (is_a_grgid_cache) {
309292932Sdim				if ((itemp = cache_alloc("cgrgid()", len,
310292932Sdim				    sizeof (struct group))) != Null_Item) {
311292932Sdim					/*
312292932Sdim					 * With that allocated, insert the
313292932Sdim					 * group name as key and set the key
314292932Sdim					 * length.
315292932Sdim					 */
316292932Sdim					(void) memmove(itemp->key, &gid, len);
317292932Sdim
318292932Sdim					/*
319292932Sdim					 * Insert the data associated with
320292932Sdim					 * the key and the data length.
321292932Sdim					 */
322292932Sdim					(void) memmove(itemp->data, grp,
323292932Sdim					    sizeof (struct group));
324292932Sdim
325292932Sdim					if (add_cache(grgid_cache, itemp) == -1)
326292932Sdim						(void) fprintf(stderr,
327292932Sdim						    pkg_gt(ERR_ADDFAIL),
328292932Sdim						    "cgrgid()");
329292932Sdim				}
330292932Sdim			}
331292932Sdim		}
332292932Sdim		return (grp);
333292932Sdim	} else	/* Found it in the cache. */
334292932Sdim		return ((struct group *)itemp->data);
335292932Sdim}
336292932Sdim
337292932Sdimstruct passwd *
338292932Sdimcpwuid(uid_t uid)
339292932Sdim{
340292932Sdim	struct passwd *pwd;
341292932Sdim	Item *itemp;
342292932Sdim	int len;
343292932Sdim	static int cache_failed;
344292932Sdim
345292932Sdim	if (!is_a_pwuid_cache && !cache_failed) {
346292932Sdim		if (init_cache(&pwuid_cache, HASHSIZE, BSZ,
347292932Sdim		    uid_hash, uid_comp) == -1) {
348292932Sdim			(void) fprintf(stderr,
349292932Sdim			    pkg_gt(ERR_NOINIT), "cpwuid()");
350292932Sdim			pwuid_cache = (Cache *) NULL;
351292932Sdim			cache_failed = 1;
352292932Sdim		} else
353292932Sdim			is_a_pwuid_cache = 1;
354292932Sdim	}
355292932Sdim
356292932Sdim	len = sizeof (uid_t);
357292932Sdim
358292932Sdim	/* First look in the cache. Failing that, do it the hard way. */
359292932Sdim	if ((itemp = lookup_cache(pwuid_cache, &uid, len)) == Null_Item) {
360292932Sdim
361292932Sdim		/* Get the passwd by number. */
362292932Sdim		if ((pwd = clpwuid(uid)) != NULL ||
363292932Sdim				(pwd = getpwuid(uid)) != NULL) {
364292932Sdim			/* A passwd by that user ID exists on this machine. */
365292932Sdim			if (dup_pw_ent(pwd))
366292932Sdim				/*
367292932Sdim				 * Effectively no such passwd since struct
368292932Sdim				 * couldn't be duplicated.
369292932Sdim				 */
370292932Sdim				pwd = (struct passwd *)NULL;
371292932Sdim			/*
372292932Sdim			 * If there's a pwuid cache, then update it with this
373292932Sdim			 * new passwd, otherwise, skip it.
374292932Sdim			 */
375292932Sdim			else if (is_a_pwuid_cache) {
376292932Sdim				if ((itemp = cache_alloc("cpwuid()", len,
377292932Sdim				    sizeof (struct passwd))) != Null_Item) {
378292932Sdim					/*
379292932Sdim					 * With that allocated, insert the
380292932Sdim					 * group name as key and set the key
381292932Sdim					 * length.
382292932Sdim					 */
383292932Sdim					(void) memmove(itemp->key, &uid, len);
384292932Sdim
385292932Sdim					/*
386292932Sdim					 * Insert the data associated with
387292932Sdim					 * the key and the data length.
388292932Sdim					 */
389292932Sdim					(void) memmove(itemp->data, pwd,
390292932Sdim					    sizeof (struct passwd));
391292932Sdim
392292932Sdim					if (add_cache(pwuid_cache, itemp) == -1)
393292932Sdim						(void) fprintf(stderr,
394292932Sdim						    pkg_gt(ERR_ADDFAIL),
395292932Sdim						    "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 */
412static int
413dup_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 */
497static int
498dup_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 */
592struct group *
593clgrnam(char *nam)
594{
595	struct group *gr;
596	char *instroot, *buf;
597	FILE *gr_ptr;
598
599	if ((instroot = get_install_root()) != NULL) {
600		if ((buf = (char *)malloc(strlen(instroot) +
601			strlen(GROUP) + 1)) == NULL) {
602			(void) fprintf(stderr,
603				pkg_gt(ERR_MALLOC), "clgrnam()",
604				strlen(instroot) + strlen(GROUP), "buf");
605		}
606		(void) sprintf(buf, "%s%s", instroot, GROUP);
607		if ((gr_ptr = fopen(buf, "r")) == NULL) {
608			free(buf);
609			return (NULL);
610		} else {
611			while ((gr = fgetgrent(gr_ptr)) != NULL) {
612				if (strcmp(gr->gr_name, nam) == 0) {
613					break;
614				}
615			}
616		}
617		free(buf);
618		(void) fclose(gr_ptr);
619		return (gr);
620	} else {
621		return (NULL);
622	}
623}
624
625/*
626 * Check the client's etc/passwd file for the user name
627 *
628 * returns a pointer to the passwd structure if the passwd is found
629 * returns NULL if not found
630 */
631struct passwd *
632clpwnam(char *nam)
633{
634	struct passwd *pw;
635	char *instroot, *buf;
636	FILE *pw_ptr;
637
638	if ((instroot = get_install_root()) != NULL) {
639		if ((buf = (char *)malloc(strlen(instroot) +
640			strlen(PASSWD) + 1)) == NULL) {
641			(void) fprintf(stderr,
642				pkg_gt(ERR_MALLOC), "clpwnam()",
643				strlen(instroot) + strlen(PASSWD), "buf");
644		}
645		(void) sprintf(buf, "%s%s", instroot, PASSWD);
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 */
670struct group *
671clgrgid(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 ((buf = (char *)malloc(strlen(instroot) +
679			strlen(GROUP) + 1)) == NULL) {
680			(void) fprintf(stderr,
681				pkg_gt(ERR_MALLOC), "clgrgid()",
682				strlen(instroot) + strlen(GROUP), "buf");
683		}
684		(void) sprintf(buf, "%s%s", instroot, GROUP);
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 */
709struct passwd *
710clpwuid(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 ((buf = (char *)malloc(strlen(instroot) +
718			strlen(PASSWD) + 1)) == NULL) {
719			(void) fprintf(stderr,
720				pkg_gt(ERR_MALLOC), "clpwuid()",
721				strlen(instroot) + strlen(PASSWD), "buf");
722		}
723		(void) sprintf(buf, "%s%s", instroot, PASSWD);
724		if ((pw_ptr = fopen(buf, "r")) == NULL) {
725			free(buf);
726			return (NULL);
727		} else {
728			while ((pw = fgetpwent(pw_ptr)) != NULL) {
729				if (pw->pw_uid == uid) {
730					break;
731				}
732			}
733		}
734		free(buf);
735		(void) fclose(pw_ptr);
736		return (pw);
737	} else {
738		return (NULL);
739	}
740}
741