diff options
author | Moriah Waterland <Moriah.Waterland@Sun.COM> | 2009-06-03 20:16:25 -0600 |
---|---|---|
committer | Moriah Waterland <Moriah.Waterland@Sun.COM> | 2009-06-03 20:16:25 -0600 |
commit | 5c51f1241dbbdf2656d0e10011981411ed0c9673 (patch) | |
tree | 0f30a2e38fe4e5d53a5a67264ba548577d82a86f /usr/src/lib/libpkg/common/ncgrpw.c | |
parent | 2b79d384d32b4ea1e278466cd9b0f3bb56daae22 (diff) | |
download | illumos-joyent-5c51f1241dbbdf2656d0e10011981411ed0c9673.tar.gz |
6739234 move SVR4 packaging to ONNV gate
Diffstat (limited to 'usr/src/lib/libpkg/common/ncgrpw.c')
-rw-r--r-- | usr/src/lib/libpkg/common/ncgrpw.c | 740 |
1 files changed, 740 insertions, 0 deletions
diff --git a/usr/src/lib/libpkg/common/ncgrpw.c b/usr/src/lib/libpkg/common/ncgrpw.c new file mode 100644 index 0000000000..cf3151164e --- /dev/null +++ b/usr/src/lib/libpkg/common/ncgrpw.c @@ -0,0 +1,740 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + + +/* + * This module fetches group and passwd structs for the caller. It + * uses a hash table to speed up retrieval of repeated entries. If + * the attempts to initialize the hash tables fail, this just + * continues the slow way. + */ + +#include <pwd.h> +#include <grp.h> +#include <string.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include "pkglib.h" +#include "pkglocale.h" +#include "nhash.h" + +#define HASHSIZE 151 +#define BSZ 4 + +#define ERR_DUPFAIL "%s: strdup(%s) failed.\n" +#define ERR_ADDFAIL "%s: add_cache() failed.\n" +#define ERR_BADMEMB "%s: %s in \"%s\" %s structure is invalid.\n" +#define ERR_NOGRP "dup_gr_ent(): no group entry provided.\n" +#define ERR_NOPWD "dup_pw_ent(): no passwd entry provided.\n" +#define ERR_NOINIT "%s: init_cache() failed.\n" +#define ERR_MALLOC "%s: malloc(%d) failed for %s.\n" + +static Cache *pwnam_cache = (Cache *) NULL; +static Cache *grnam_cache = (Cache *) NULL; +static Cache *pwuid_cache = (Cache *) NULL; +static Cache *grgid_cache = (Cache *) NULL; + +static int dup_gr_ent(struct group *grp); +static int dup_pw_ent(struct passwd *pwp); + +/* + * These indicate whether the hash table has been initialized for the four + * categories. + */ +static int is_a_pwnam_cache; +static int is_a_grnam_cache; +static int is_a_pwuid_cache; +static int is_a_grgid_cache; + +extern char *get_install_root(void); + +/* + * If there's a grnam cache, then update it with this new + * group, otherwise, skip it. + */ +static Item * +cache_alloc(char *fname, int len, size_t struct_size) +{ + Item *itemp; + + /* + * Allocate space for the Item pointer, key and data. + */ + if ((itemp = (Item *) malloc(sizeof (*itemp))) == + Null_Item) { + (void) fprintf(stderr, + pkg_gt(ERR_MALLOC), fname, + sizeof (*itemp), "itemp"); + } else if ((itemp->key = (char *)malloc(len)) == NULL) { + (void) fprintf(stderr, pkg_gt(ERR_MALLOC), fname, len, + "itemp->key"); + free(itemp); + } else if ((itemp->data = malloc(struct_size)) == NULL) { + (void) fprintf(stderr, pkg_gt(ERR_MALLOC), fname, + struct_size, "itemp->data"); + free(itemp->key); + free(itemp); + } else { + /* Set length parameters. */ + itemp->keyl = len; + itemp->datal = struct_size; + + return (itemp); + } + + return ((Item *) NULL); +} + +/* Get the required group structure based upon the group name. */ +struct group * +cgrnam(char *nam) +{ + struct group *grp; + Item *itemp; + int len; + static int cache_failed; + + /* Attempt to initialize the grname cache. */ + if (!is_a_grnam_cache && !cache_failed) { + if (init_cache(&grnam_cache, HASHSIZE, BSZ, + (int (*)())NULL, (int (*)())NULL) == -1) { + (void) fprintf(stderr, pkg_gt(ERR_NOINIT), "cgrnam()"); + grnam_cache = (Cache *) NULL; + cache_failed = 1; + } else + is_a_grnam_cache = 1; + } + + len = strlen(nam) + 1; + + /* First look in the cache. Failing that, do it the hard way. */ + if ((itemp = lookup_cache(grnam_cache, nam, len)) == Null_Item) { + + /* Get the group by name. */ + if ((grp = clgrnam(nam)) != NULL || + (grp = getgrnam(nam)) != NULL) { + /* A group by that name exists on this machine. */ + if (dup_gr_ent(grp)) + /* + * Effectively no such group since struct + * couldn't be duplicated. + */ + grp = (struct group *)NULL; + /* + * If there's a grnam cache, then update it with this + * new group, otherwise, skip it. + */ + else if (is_a_grnam_cache) { + if ((itemp = cache_alloc("cgrnam()", len, + sizeof (struct group))) != Null_Item) { + /* + * With that allocated, insert the + * group name as key and set the key + * length. + */ + (void) memmove(itemp->key, nam, len); + + /* + * Insert the data associated with + * the key and the data length. + */ + (void) memmove(itemp->data, grp, + sizeof (struct group)); + + /* Insert the Item into the cache. */ + if (add_cache(grnam_cache, itemp) == -1) + (void) fprintf(stderr, + pkg_gt(ERR_ADDFAIL), + "cgrnam()"); + } + } + } + return (grp); + } else /* Found it in the cache. */ + return ((struct group *)itemp->data); +} + +struct passwd * +cpwnam(char *nam) +{ + struct passwd *pwd; + Item *itemp; + int len; + static int cache_failed; + + if (!is_a_pwnam_cache && !cache_failed) { + if (init_cache(&pwnam_cache, HASHSIZE, BSZ, + (int (*)())NULL, (int (*)())NULL) == -1) { + (void) fprintf(stderr, pkg_gt(ERR_NOINIT), "cpwnam()"); + pwnam_cache = (Cache *) NULL; + cache_failed = 1; + } else + is_a_pwnam_cache = 1; + } + + len = strlen(nam) + 1; + + /* First look in the cache. Failing that, do it the hard way. */ + if ((itemp = lookup_cache(pwnam_cache, nam, len)) == Null_Item) { + + /* Get the passwd by name. */ + if ((pwd = clpwnam(nam)) != NULL || + (pwd = getpwnam(nam)) != NULL) { + /* A passwd by that name exists on this machine. */ + if (dup_pw_ent(pwd)) + /* + * Effectively no such passwd since struct + * couldn't be duplicated. + */ + pwd = (struct passwd *)NULL; + /* + * If there's a pwnam cache, then update it with this + * new passwd, otherwise, skip it. + */ + else if (is_a_pwnam_cache) { + /* + * Allocate space for the Item pointer, key + * and data. + */ + if ((itemp = cache_alloc("cpwnam()", len, + sizeof (struct passwd))) != Null_Item) { + /* + * With that allocated, insert the + * group name as key and set the key + * length. + */ + (void) memmove(itemp->key, nam, len); + + /* + * Insert the data associated with + * the key and the data length. + */ + (void) memmove(itemp->data, pwd, + sizeof (struct passwd)); + + if (add_cache(pwnam_cache, itemp) == -1) + (void) fprintf(stderr, + pkg_gt(ERR_ADDFAIL), + "cpwnam()"); + } + } + } + return (pwd); + } else /* Found it in the cache. */ + return ((struct passwd *)itemp->data); +} + +static int +uid_hash(void *datap, int datalen, int hsz) +{ +#ifdef lint + int i = datalen; + datalen = i; +#endif /* lint */ + + return (*((uid_t *)datap) % hsz); +} + +static int +uid_comp(void *datap1, void *datap2, int datalen) +{ +#ifdef lint + int i = datalen; + datalen = i; +#endif /* lint */ + + return (*((uid_t *)datap1) - *((uid_t *)datap2)); +} + +struct group * +cgrgid(gid_t gid) +{ + struct group *grp; + Item *itemp; + int len; + static int cache_failed; + + if (!is_a_grgid_cache && !cache_failed) { + if (init_cache(&grgid_cache, HASHSIZE, BSZ, + uid_hash, uid_comp) == -1) { + (void) fprintf(stderr, pkg_gt(ERR_NOINIT), "cgrgid()"); + grgid_cache = (Cache *) NULL; + cache_failed = 1; + } else + is_a_grgid_cache = 1; + } + + len = sizeof (uid_t); + + /* First look in the cache. Failing that, do it the hard way. */ + if ((itemp = lookup_cache(grgid_cache, &gid, len)) == Null_Item) { + if ((grp = clgrgid(gid)) != NULL || + (grp = getgrgid(gid)) != NULL) { + /* A group by that number exists on this machine. */ + if (dup_gr_ent(grp)) + /* + * Effectively no such group since struct + * couldn't be duplicated. + */ + grp = (struct group *)NULL; + /* + * If there's a grnam cache, then update it with this + * new group, otherwise, skip it. + */ + else if (is_a_grgid_cache) { + if ((itemp = cache_alloc("cgrgid()", len, + sizeof (struct group))) != Null_Item) { + /* + * With that allocated, insert the + * group name as key and set the key + * length. + */ + (void) memmove(itemp->key, &gid, len); + + /* + * Insert the data associated with + * the key and the data length. + */ + (void) memmove(itemp->data, grp, + sizeof (struct group)); + + if (add_cache(grgid_cache, itemp) == -1) + (void) fprintf(stderr, + pkg_gt(ERR_ADDFAIL), + "cgrgid()"); + } + } + } + return (grp); + } else /* Found it in the cache. */ + return ((struct group *)itemp->data); +} + +struct passwd * +cpwuid(uid_t uid) +{ + struct passwd *pwd; + Item *itemp; + int len; + static int cache_failed; + + if (!is_a_pwuid_cache && !cache_failed) { + if (init_cache(&pwuid_cache, HASHSIZE, BSZ, + uid_hash, uid_comp) == -1) { + (void) fprintf(stderr, + pkg_gt(ERR_NOINIT), "cpwuid()"); + pwuid_cache = (Cache *) NULL; + cache_failed = 1; + } else + is_a_pwuid_cache = 1; + } + + len = sizeof (uid_t); + + /* First look in the cache. Failing that, do it the hard way. */ + if ((itemp = lookup_cache(pwuid_cache, &uid, len)) == Null_Item) { + + /* Get the passwd by number. */ + if ((pwd = clpwuid(uid)) != NULL || + (pwd = getpwuid(uid)) != NULL) { + /* A passwd by that user ID exists on this machine. */ + if (dup_pw_ent(pwd)) + /* + * Effectively no such passwd since struct + * couldn't be duplicated. + */ + pwd = (struct passwd *)NULL; + /* + * If there's a pwuid cache, then update it with this + * new passwd, otherwise, skip it. + */ + else if (is_a_pwuid_cache) { + if ((itemp = cache_alloc("cpwuid()", len, + sizeof (struct passwd))) != Null_Item) { + /* + * With that allocated, insert the + * group name as key and set the key + * length. + */ + (void) memmove(itemp->key, &uid, len); + + /* + * Insert the data associated with + * the key and the data length. + */ + (void) memmove(itemp->data, pwd, + sizeof (struct passwd)); + + if (add_cache(pwuid_cache, itemp) == -1) + (void) fprintf(stderr, + pkg_gt(ERR_ADDFAIL), + "cpwuid()"); + } + } + } + return (pwd); + } else /* Found it in the cache. */ + return ((struct passwd *)itemp->data); +} + +/* + * This function duplicates the group structure provided from kernel static + * memory. There is a lot of defensive coding here because there have been + * problems with the getgr*() functions. They will sometimes provide NULL + * values instead of pointers to NULL values. There has been no explanation + * for the reason behind this; but, this function takes a NULL to be an + * invalid (char *) and returns an error. + */ +static int +dup_gr_ent(struct group *grp) +{ + char **tp = NULL; + char **memp = NULL; + int nent = 0; /* Number of entries in the member list. */ + + if (grp) { + if (grp->gr_name == NULL) { + (void) fprintf(stderr, + pkg_gt(ERR_BADMEMB), "dup_gr_ent()", "gr_name", + "unknown", "group"); + return (-1); + } else if ((grp->gr_name = strdup(grp->gr_name)) == NULL) { + (void) fprintf(stderr, + pkg_gt(ERR_DUPFAIL), "dup_gr_ent()", "gr_name"); + return (-1); + } + if (grp->gr_passwd == NULL) { + (void) fprintf(stderr, + pkg_gt(ERR_BADMEMB), "dup_gr_ent()", "gr_passwd", + grp->gr_name, "group"); + return (-1); + } else if ((grp->gr_passwd = strdup(grp->gr_passwd)) == NULL) { + (void) fprintf(stderr, + pkg_gt(ERR_DUPFAIL), "dup_gr_ent()", "gr_passwd"); + return (-1); + } + /* + * Allocate space for the member list and move the members + * into it. + */ + if (grp->gr_mem) { + /* + * First count the members. The nent variable will be + * the number of members + 1 for the terminator. + */ + for (tp = grp->gr_mem; *tp; nent++, tp++); + + /* Now allocate room for the pointers. */ + memp = malloc(sizeof (char **)* (nent+1)); + + if (memp == NULL) { + (void) fprintf(stderr, + pkg_gt(ERR_MALLOC), "dup_gr_ent()", + (sizeof (char **)* (nent+1)), + "memp"); + return (-1); + } + + /* + * Now copy over the pointers and entries. It should + * be noted that if the structure is messed up here, + * the resulting member list will be truncated at the + * NULL entry. + */ + for (nent = 0, tp = grp->gr_mem; *tp; tp++) { + if ((memp[nent++] = strdup(*tp)) == NULL) { + (void) fprintf(stderr, + pkg_gt(ERR_DUPFAIL), "dup_gr_ent()", + "gr_mem"); + return (-1); + } + } + } else { + (void) fprintf(stderr, + pkg_gt(ERR_BADMEMB), "dup_gr_ent()", "gr_mem", + grp->gr_name, "group"); + return (-1); + } + } else { + (void) fprintf(stderr, pkg_gt(ERR_NOGRP)); + return (-1); + } + memp[nent++] = '\0'; + return (0); +} + +/* + * This function duplicates the passwd structure provided from kernel static + * memory. As in the above function, since there have been problems with the + * getpw*() functions, the structure provided is rigorously scrubbed. This + * function takes a NULL to be an invalid (char *) and returns an error if + * one is detected. + */ +static int +dup_pw_ent(struct passwd *pwd) +{ + if (pwd) { + if (pwd->pw_name == NULL) { + (void) fprintf(stderr, + pkg_gt(ERR_BADMEMB), "dup_pw_ent()", "pw_name", + "unknown", "passwd"); + return (-1); + } else if ((pwd->pw_name = strdup(pwd->pw_name)) == NULL) { + (void) fprintf(stderr, + pkg_gt(ERR_DUPFAIL), "dup_pw_ent()", "pw_name"); + return (-1); + } + + if (pwd->pw_passwd == NULL) { + (void) fprintf(stderr, + pkg_gt(ERR_BADMEMB), "dup_pw_ent()", "pw_passwd", + pwd->pw_name, "passwd"); + return (-1); + } else if ((pwd->pw_passwd = strdup(pwd->pw_passwd)) == NULL) { + (void) fprintf(stderr, + pkg_gt(ERR_DUPFAIL), "dup_pw_ent()", "pw_passwd"); + return (-1); + } + + if (pwd->pw_age == NULL) { + (void) fprintf(stderr, + pkg_gt(ERR_BADMEMB), "dup_pw_ent()", "pw_age", + pwd->pw_name, "passwd"); + return (-1); + } else if ((pwd->pw_age = strdup(pwd->pw_age)) == NULL) { + (void) fprintf(stderr, + pkg_gt(ERR_DUPFAIL), "dup_pw_ent()", "pw_age"); + return (-1); + } + + if (pwd->pw_comment == NULL) { + (void) fprintf(stderr, + pkg_gt(ERR_BADMEMB), "dup_pw_ent()", "pw_comment", + pwd->pw_name, "passwd"); + return (-1); + } else if ((pwd->pw_comment = strdup(pwd->pw_comment)) == + NULL) { + (void) fprintf(stderr, + pkg_gt(ERR_DUPFAIL), "dup_pw_ent()", "pw_comment"); + return (-1); + } + + if (pwd->pw_gecos == NULL) { + (void) fprintf(stderr, + pkg_gt(ERR_BADMEMB), "dup_pw_ent()", "pw_gecos", + pwd->pw_name, "passwd"); + return (-1); + } else if ((pwd->pw_gecos = strdup(pwd->pw_gecos)) == NULL) { + (void) fprintf(stderr, + pkg_gt(ERR_DUPFAIL), "dup_pw_ent()", "pw_gecos"); + return (-1); + } + + if (pwd->pw_dir == NULL) { + (void) fprintf(stderr, + pkg_gt(ERR_BADMEMB), "dup_pw_ent()", "pw_dir", + pwd->pw_name, "passwd"); + return (-1); + } else if ((pwd->pw_dir = strdup(pwd->pw_dir)) == NULL) { + (void) fprintf(stderr, + pkg_gt(ERR_DUPFAIL), "dup_pw_ent()", "pw_dir"); + return (-1); + } + + if (pwd->pw_shell == NULL) { + (void) fprintf(stderr, + pkg_gt(ERR_BADMEMB), "dup_pw_ent()", "pw_shell", + pwd->pw_name, "passwd"); + return (-1); + } else if ((pwd->pw_shell = strdup(pwd->pw_shell)) == NULL) { + (void) fprintf(stderr, + pkg_gt(ERR_DUPFAIL), "dup_pw_ent()", "pw_shell"); + return (-1); + } + } else { + (void) fprintf(stderr, pkg_gt(ERR_NOPWD)); + return (-1); + } + + return (0); +} + +/* + * Check the client's etc/group file for the group name + * + * returns a pointer to the group structure if the group is found + * returns NULL if not found + */ +struct group * +clgrnam(char *nam) +{ + struct group *gr; + char *instroot, *buf; + FILE *gr_ptr; + + if ((instroot = get_install_root()) != NULL) { + if ((buf = (char *)malloc(strlen(instroot) + + strlen(GROUP) + 1)) == NULL) { + (void) fprintf(stderr, + pkg_gt(ERR_MALLOC), "clgrnam()", + strlen(instroot) + strlen(GROUP), "buf"); + } + (void) sprintf(buf, "%s%s", instroot, GROUP); + if ((gr_ptr = fopen(buf, "r")) == NULL) { + free(buf); + return (NULL); + } else { + while ((gr = fgetgrent(gr_ptr)) != NULL) { + if (strcmp(gr->gr_name, nam) == 0) { + break; + } + } + } + free(buf); + (void) fclose(gr_ptr); + return (gr); + } else { + return (NULL); + } +} + +/* + * Check the client's etc/passwd file for the user name + * + * returns a pointer to the passwd structure if the passwd is found + * returns NULL if not found + */ +struct passwd * +clpwnam(char *nam) +{ + struct passwd *pw; + char *instroot, *buf; + FILE *pw_ptr; + + if ((instroot = get_install_root()) != NULL) { + if ((buf = (char *)malloc(strlen(instroot) + + strlen(PASSWD) + 1)) == NULL) { + (void) fprintf(stderr, + pkg_gt(ERR_MALLOC), "clpwnam()", + strlen(instroot) + strlen(PASSWD), "buf"); + } + (void) sprintf(buf, "%s%s", instroot, PASSWD); + if ((pw_ptr = fopen(buf, "r")) == NULL) { + free(buf); + return (NULL); + } else { + while ((pw = fgetpwent(pw_ptr)) != NULL) { + if (strcmp(pw->pw_name, nam) == 0) { + break; + } + } + } + free(buf); + (void) fclose(pw_ptr); + return (pw); + } else { + return (NULL); + } +} + +/* + * Check the client's etc/group file for the group id + * + * returns a pointer to the group structure if the group id is found + * returns NULL if not found + */ +struct group * +clgrgid(gid_t gid) +{ + struct group *gr; + char *instroot, *buf; + FILE *gr_ptr; + + if ((instroot = get_install_root()) != NULL) { + if ((buf = (char *)malloc(strlen(instroot) + + strlen(GROUP) + 1)) == NULL) { + (void) fprintf(stderr, + pkg_gt(ERR_MALLOC), "clgrgid()", + strlen(instroot) + strlen(GROUP), "buf"); + } + (void) sprintf(buf, "%s%s", instroot, GROUP); + if ((gr_ptr = fopen(buf, "r")) == NULL) { + free(buf); + return (NULL); + } else { + while ((gr = fgetgrent(gr_ptr)) != NULL) { + if (gr->gr_gid == gid) { + break; + } + } + } + free(buf); + (void) fclose(gr_ptr); + return (gr); + } else { + return (NULL); + } +} + +/* + * Check the client's etc/passwd file for the user id + * + * returns a pointer to the passwd structure if the user id is found + * returns NULL if not found + */ +struct passwd * +clpwuid(uid_t uid) +{ + struct passwd *pw; + char *instroot, *buf; + FILE *pw_ptr; + + if ((instroot = get_install_root()) != NULL) { + if ((buf = (char *)malloc(strlen(instroot) + + strlen(PASSWD) + 1)) == NULL) { + (void) fprintf(stderr, + pkg_gt(ERR_MALLOC), "clpwuid()", + strlen(instroot) + strlen(PASSWD), "buf"); + } + (void) sprintf(buf, "%s%s", instroot, PASSWD); + if ((pw_ptr = fopen(buf, "r")) == NULL) { + free(buf); + return (NULL); + } else { + while ((pw = fgetpwent(pw_ptr)) != NULL) { + if (pw->pw_uid == uid) { + break; + } + } + } + free(buf); + (void) fclose(pw_ptr); + return (pw); + } else { + return (NULL); + } +} |