2N/A/*
2N/A * CDDL HEADER START
2N/A *
2N/A * The contents of this file are subject to the terms of the
2N/A * Common Development and Distribution License (the "License").
2N/A * You may not use this file except in compliance with the License.
2N/A *
2N/A * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
2N/A * or http://www.opensolaris.org/os/licensing.
2N/A * See the License for the specific language governing permissions
2N/A * and limitations under the License.
2N/A *
2N/A * When distributing Covered Code, include this CDDL HEADER in each
2N/A * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
2N/A * If applicable, add the following below this CDDL HEADER, with the
2N/A * fields enclosed by brackets "[]" replaced with your own identifying
2N/A * information: Portions Copyright [yyyy] [name of copyright owner]
2N/A *
2N/A * CDDL HEADER END
2N/A */
2N/A
2N/A/*
2N/A * Copyright (c) 1989, 2011, Oracle and/or its affiliates. All rights reserved.
2N/A */
2N/A/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
2N/A/* All Rights Reserved */
2N/A
2N/A#include "lint.h"
2N/A#include <mtlib.h>
2N/A#include <ctype.h>
2N/A#include <stdio.h>
2N/A#include <stdlib.h>
2N/A#include <string.h>
2N/A#include <nss_dbdefs.h>
2N/A#include <limits.h>
2N/A#include <dlfcn.h>
2N/A#include <link.h>
2N/A#include <thread.h>
2N/A#include <atomic.h>
2N/A/* headers for key2str/str2key routines */
2N/A#include <sys/ethernet.h>
2N/A#include <exec_attr.h>
2N/A#include <grp.h>
2N/A
2N/A/*
2N/A * functions in nss_dbdefs.c deal more with the mechanics of
2N/A * the data structures like nss_XbyY_args_t and the interaction
2N/A * with the packed buffers etc. versus the mechanics of the
2N/A * actual policy component operations such as nss_search sequencing.
2N/A */
2N/A
2N/A/*
2N/A * ALIGN? is there an official definition of this?
2N/A * We use sizeof(long) to cover what we want
2N/A * for both the 32-bit world and 64-bit world.
2N/A */
2N/A
2N/A#define ALIGN(x) ((((long)(x)) + sizeof (long) - 1) & ~(sizeof (long) - 1))
2N/A
2N/Anss_XbyY_buf_t *
2N/A_nss_XbyY_buf_alloc(int struct_size, int buffer_size)
2N/A{
2N/A nss_XbyY_buf_t *b;
2N/A
2N/A /* Use one malloc for dbargs, result struct and buffer */
2N/A b = (nss_XbyY_buf_t *)
2N/A malloc(ALIGN(sizeof (*b)) + struct_size + buffer_size);
2N/A if (b == 0) {
2N/A return (0);
2N/A }
2N/A b->result = (void *)ALIGN(&b[1]);
2N/A b->buffer = (char *)(b->result) + struct_size;
2N/A b->buflen = buffer_size;
2N/A return (b);
2N/A}
2N/A
2N/Avoid
2N/A_nss_XbyY_buf_free(nss_XbyY_buf_t *b)
2N/A{
2N/A if (b != 0) {
2N/A free(b);
2N/A }
2N/A}
2N/A
2N/A/* === Comment: used by fget{gr,pw,sp}ent */
2N/A/* ==== Should do ye olde syslog()ing of suspiciously long lines */
2N/A
2N/Avoid
2N/A_nss_XbyY_fgets(FILE *f, nss_XbyY_args_t *b)
2N/A{
2N/A char *buffer, *buf_offset, *new_buffer;
2N/A int len, parsestat, bufsize;
2N/A
2N/A /* Allocate initial input buffer */
2N/A buffer = malloc(LINE_MAX);
2N/A if (buffer == NULL) {
2N/A b->returnval = 0;
2N/A b->erange = 1;
2N/A return;
2N/A }
2N/A bufsize = LINE_MAX;
2N/A buf_offset = buffer;
2N/A len = 0;
2N/A
2N/A /* Loop reading input until newline or end-of-file */
2N/A while (fgets(buf_offset, (bufsize - len), f) != NULL) {
2N/A
2N/A /* Break on newline or end-of-file */
2N/A len += strlen(buf_offset);
2N/A if (buffer[len - 1] == '\n' || feof(f)) {
2N/A break;
2N/A }
2N/A
2N/A /* Allocate larger buffer to continue input */
2N/A new_buffer = realloc(buffer, bufsize + LINE_MAX);
2N/A if (new_buffer == NULL) {
2N/A free(buffer);
2N/A b->returnval = 0;
2N/A b->erange = 1;
2N/A return;
2N/A }
2N/A buffer = new_buffer;
2N/A bufsize += LINE_MAX;
2N/A buf_offset = buffer + len;
2N/A }
2N/A
2N/A /* Check for end-of-file */
2N/A if (!len) {
2N/A free(buffer);
2N/A b->returnval = 0;
2N/A b->erange = 0;
2N/A return;
2N/A }
2N/A
2N/A /*
2N/A * The input line parser uses the length of valid characters
2N/A * to copy the buffer, appending a null terminator to the copy.
2N/A * Use this to remove any trailing newlines.
2N/A */
2N/A if (buffer[len - 1] == '\n') {
2N/A len--;
2N/A }
2N/A
2N/A /* Call the input line parser */
2N/A parsestat = (*b->str2ent)(buffer, len, b->buf.result, b->buf.buffer,
2N/A b->buf.buflen);
2N/A if (parsestat == NSS_STR_PARSE_ERANGE) {
2N/A b->returnval = 0;
2N/A b->erange = 1;
2N/A } else if (parsestat == NSS_STR_PARSE_SUCCESS) {
2N/A b->returnval = b->buf.result;
2N/A }
2N/A
2N/A /* Release the input buffer */
2N/A free(buffer);
2N/A}
2N/A
2N/A/*
2N/A * parse the aliases string into the buffer and if successful return
2N/A * a char ** pointer to the beginning of the aliases.
2N/A *
2N/A * CAUTION: (instr, instr+lenstr) and (buffer, buffer+buflen) are
2N/A * non-intersecting memory areas. Since this is an internal interface,
2N/A * we should be able to live with that.
2N/A */
2N/Achar **
2N/A_nss_netdb_aliases(const char *instr, int lenstr, char *buffer, int buflen)
2N/A /* "instr" is the beginning of the aliases string */
2N/A /* "buffer" has the return val for success */
2N/A /* "buflen" is the length of the buffer available for aliases */
2N/A{
2N/A /*
2N/A * Build the alias-list in the start of the buffer, and copy
2N/A * the strings to the end of the buffer.
2N/A */
2N/A const char
2N/A *instr_limit = instr + lenstr;
2N/A char *copyptr = buffer + buflen;
2N/A char **aliasp = (char **)ROUND_UP(buffer, sizeof (*aliasp));
2N/A char **alias_start = aliasp;
2N/A int nstrings = 0;
2N/A
2N/A for (;;) {
2N/A const char *str_start;
2N/A size_t str_len;
2N/A
2N/A while (instr < instr_limit && isspace(*instr)) {
2N/A instr++;
2N/A }
2N/A if (instr >= instr_limit || *instr == '#') {
2N/A break;
2N/A }
2N/A str_start = instr;
2N/A while (instr < instr_limit && !isspace(*instr)) {
2N/A instr++;
2N/A }
2N/A
2N/A ++nstrings;
2N/A
2N/A str_len = instr - str_start;
2N/A copyptr -= str_len + 1;
2N/A if (copyptr <= (char *)(&aliasp[nstrings + 1])) {
2N/A /* Has to be room for the pointer to */
2N/A /* the alias we're about to add, */
2N/A /* as well as the final NULL ptr. */
2N/A return (0);
2N/A }
2N/A *aliasp++ = copyptr;
2N/A (void) memcpy(copyptr, str_start, str_len);
2N/A copyptr[str_len] = '\0';
2N/A }
2N/A *aliasp++ = 0;
2N/A return (alias_start);
2N/A}
2N/A
2N/A
2N/Aextern nss_status_t process_cstr(const char *, int, struct nss_groupsbymem *);
2N/A
2N/A/*
2N/A * pack well known getXbyY keys to packed buffer prior to the door_call
2N/A * to nscd. Some consideration is given to ordering the tests based on
2N/A * usage. Note: buf is nssuint_t aligned.
2N/A */
2N/A
2N/Atypedef struct {
2N/A const char *name; /* NSS_DBNAM_* */
2N/A const char *defconf; /* NSS_DEFCONF_* */
2N/A const char *initfn; /* init function name */
2N/A const char *strfn; /* str2X function name */
2N/A const char *cstrfn; /* cstr2X function name */
2N/A void *initfnp; /* init function pointer */
2N/A void *strfnp; /* str2X function pointer */
2N/A uint32_t dbop; /* NSS_DBOP_* */
2N/A const char *tostr; /* key2str cvt str */
2N/A} getXbyY_to_dbop_t;
2N/A
2N/A#define NSS_MK_GETXYDBOP(x, y, f, e) \
2N/A { NSS_DBNAM_##x, NSS_DEFCONF_##x, "_nss_initf_" f, "str2" f, \
2N/A NULL, NULL, NULL, NSS_DBOP_##x##_##y, (e) }
2N/A
2N/A#define NSS_MK_GETXYDBOPA(x, a, f, e) \
2N/A { NSS_DBNAM_##x, NSS_DEFCONF_##x, "_nss_initf_" f, "str2" f, \
2N/A NULL, NULL, NULL, NSS_DBOP_##a, (e) }
2N/A
2N/A#define NSS_MK_GETXYDBOPB(x, b, a, f, s, e) \
2N/A { NSS_DBNAM_##x, NSS_DEFCONF_##b, "_nss_initf_" f, s, \
2N/A NULL, NULL, NULL, NSS_DBOP_##a, (e) }
2N/A
2N/A#define NSS_MK_GETXYDBOPC(x, a, f, s, e) \
2N/A { NSS_DBNAM_##x, NSS_DEFCONF_##x, "_nss_initf_" f, s, \
2N/A NULL, NULL, NULL, NSS_DBOP_##x##_##a, (e) }
2N/A
2N/A#define NSS_MK_GETXYDBOPD(x, y, i, f, e) \
2N/A { NSS_DBNAM_##x, NSS_DEFCONF_##x, "_nss_initf_" i, "str2" f, \
2N/A NULL, NULL, NULL, NSS_DBOP_##x##_##y, (e) }
2N/A
2N/A#define NSS_MK_GETXYDBOPCSTR(x, a, f, s, e) \
2N/A { NSS_DBNAM_##x, NSS_DEFCONF_##x, "_nss_initf_" f, s, \
2N/A "process_cstr", NULL, NULL, NSS_DBOP_##x##_##a, (e) }
2N/A
2N/A/*
2N/A * The getXbyY_to_dbop structure is hashed on first call in order to
2N/A * reduce the search time for the well known getXbyY operations.
2N/A * A binary search was not fast enough. There were on average
2N/A * 3-4 tests (strcmps) per getXbyY call.
2N/A *
2N/A * DBOP_PRIME_HASH must be a prime number (reasonably small) but that
2N/A * is sufficient to uniquely map the entries in the following table
2N/A * without collision.
2N/A *
2N/A * The DBOP_PRIME_HASH was selected as the smallest hash value
2N/A * for this table without collisions. Changing this table WILL
2N/A * necessitate re-testing for possible collisions.
2N/A */
2N/A
2N/A#define DBOP_PRIME_HASH 227
2N/A#define DBOP_HASH_TAG 0xf0000000
2N/Astatic int getXbyYdbopHASH[DBOP_PRIME_HASH] = { 0 };
2N/Astatic mutex_t getXbydbop_hash_lock = DEFAULTMUTEX;
2N/Astatic int getXbyYdbop_hashed = 0;
2N/A
2N/A/*
2N/A * If the size of getXbyY_to_dbop[] is changed then hash function must be
2N/A * corrected to be without collisions in nss_dbop_search().
2N/A */
2N/Astatic getXbyY_to_dbop_t getXbyY_to_dbop[] = {
2N/A /* NSS_MK_GETXYDBOP(ALIASES, ?, ?), */
2N/A NSS_MK_GETXYDBOPD(AUDITUSER, BYNAME, "auuser", "audituser", "n"),
2N/A NSS_MK_GETXYDBOP(AUTHATTR, BYNAME, "authattr", "n"),
2N/A /* NSS_MK_GETXYDBOP(AUTOMOUNT, ?, ?), */
2N/A NSS_MK_GETXYDBOP(BOOTPARAMS, BYNAME, "bootparams", "n"),
2N/A NSS_MK_GETXYDBOPC(ETHERS, HOSTTON, "ethers", "str2ether", "n"),
2N/A NSS_MK_GETXYDBOPC(ETHERS, NTOHOST, "ethers", "str2ether", "e"),
2N/A NSS_MK_GETXYDBOP(EXECATTR, BYNAME, "execattr", "A"),
2N/A NSS_MK_GETXYDBOP(EXECATTR, BYID, "execattr", "A"),
2N/A NSS_MK_GETXYDBOP(EXECATTR, BYNAMEID, "execattr", "A"),
2N/A NSS_MK_GETXYDBOP(GROUP, BYNAME, "group", "n"),
2N/A NSS_MK_GETXYDBOP(GROUP, BYGID, "group", "g"),
2N/A NSS_MK_GETXYDBOPCSTR(GROUP, BYMEMBER, "group", "str2group", "I"),
2N/A NSS_MK_GETXYDBOPC(HOSTS, BYNAME, "hosts", "str2hostent", "n"),
2N/A NSS_MK_GETXYDBOPC(HOSTS, BYADDR, "hosts", "str2hostent", "h"),
2N/A NSS_MK_GETXYDBOPC(IPNODES, BYNAME, "ipnodes", "str2hostent", "i"),
2N/A NSS_MK_GETXYDBOPC(IPNODES, BYADDR, "ipnodes", "str2hostent", "h"),
2N/A NSS_MK_GETXYDBOP(NETGROUP, IN, "netgroup", "t"),
2N/A NSS_MK_GETXYDBOP(NETGROUP, SET, "netgroup", "T"),
2N/A NSS_MK_GETXYDBOPC(NETMASKS, BYNET, "netmasks", "str2addr", "n"),
2N/A NSS_MK_GETXYDBOPC(NETWORKS, BYNAME, "net", "str2netent", "n"),
2N/A NSS_MK_GETXYDBOPC(NETWORKS, BYADDR, "net", "str2netent", "a"),
2N/A NSS_MK_GETXYDBOP(PASSWD, BYNAME, "passwd", "n"),
2N/A NSS_MK_GETXYDBOP(PASSWD, BYUID, "passwd", "u"),
2N/A NSS_MK_GETXYDBOP(PRINTERS, BYNAME, "printers", "n"),
2N/A NSS_MK_GETXYDBOP(PROFATTR, BYNAME, "profattr", "n"),
2N/A NSS_MK_GETXYDBOP(PROJECT, BYNAME, "project", "n"),
2N/A NSS_MK_GETXYDBOP(PROJECT, BYID, "project", "p"),
2N/A NSS_MK_GETXYDBOPC(PROTOCOLS, BYNAME, "proto", "str2protoent", "n"),
2N/A NSS_MK_GETXYDBOPC(PROTOCOLS, BYNUMBER, "proto", "str2protoent", "N"),
2N/A NSS_MK_GETXYDBOPA(PUBLICKEY, KEYS_BYNAME, "publickey", "k"),
2N/A NSS_MK_GETXYDBOPC(RPC, BYNAME, "rpc", "str2rpcent", "n"),
2N/A NSS_MK_GETXYDBOPC(RPC, BYNUMBER, "rpc", "str2rpcent", "N"),
2N/A NSS_MK_GETXYDBOPC(SERVICES, BYNAME, "services", "str2servent", "s"),
2N/A NSS_MK_GETXYDBOPC(SERVICES, BYPORT, "services", "str2servent", "S"),
2N/A NSS_MK_GETXYDBOPB(SHADOW, PASSWD, PASSWD_BYNAME, "shadow",
2N/A "str2spwd", "n"),
2N/A NSS_MK_GETXYDBOPC(TSOL_RH, BYADDR, "tsol_rh", "str_to_rhstr", "h"),
2N/A NSS_MK_GETXYDBOPC(TSOL_TP, BYNAME, "tsol_tp", "str_to_tpstr", "n"),
2N/A NSS_MK_GETXYDBOPC(TSOL_ZC, BYNAME, "tsol_zc", "str_to_zcstr", "n"),
2N/A NSS_MK_GETXYDBOP(USERATTR, BYNAME, "userattr", "n"),
2N/A};
2N/A
2N/Astatic int
2N/Anss_dbop_search(const char *name, uint32_t dbop)
2N/A{
2N/A getXbyY_to_dbop_t *hptr;
2N/A int count = (sizeof (getXbyY_to_dbop) / sizeof (getXbyY_to_dbop_t));
2N/A uint32_t hval, g;
2N/A const char *cp;
2N/A int i, idx;
2N/A static const uint32_t hbits_tst = 0xf0000000;
2N/A
2N/A /* Uses a table size is known to have no collisions */
2N/A if (getXbyYdbop_hashed == 0) {
2N/A lmutex_lock(&getXbydbop_hash_lock);
2N/A if (getXbyYdbop_hashed == 0) {
2N/A for (i = 0; i < count; i++) {
2N/A cp = getXbyY_to_dbop[i].name;
2N/A hval = 0;
2N/A while (*cp) {
2N/A hval = (hval << 4) + *cp++;
2N/A if ((g = (hval & hbits_tst)) != 0)
2N/A hval ^= g >> 24;
2N/A hval &= ~g;
2N/A }
2N/A hval += getXbyY_to_dbop[i].dbop;
2N/A hval %= DBOP_PRIME_HASH;
2N/A if (getXbyYdbopHASH[hval] != 0) {
2N/A /* hash table collision-see above */
2N/A lmutex_unlock(&getXbydbop_hash_lock);
2N/A return (-1);
2N/A }
2N/A getXbyYdbopHASH[hval] = i | DBOP_HASH_TAG;
2N/A }
2N/A membar_producer();
2N/A getXbyYdbop_hashed = 1;
2N/A }
2N/A lmutex_unlock(&getXbydbop_hash_lock);
2N/A }
2N/A membar_consumer();
2N/A cp = name;
2N/A hval = 0;
2N/A while (*cp) {
2N/A hval = (hval << 4) + *cp++;
2N/A if ((g = (hval & hbits_tst)) != 0)
2N/A hval ^= g >> 24;
2N/A hval &= ~g;
2N/A }
2N/A hval += dbop;
2N/A hval %= DBOP_PRIME_HASH;
2N/A idx = getXbyYdbopHASH[hval];
2N/A if ((idx & DBOP_HASH_TAG) != DBOP_HASH_TAG)
2N/A return (-1);
2N/A idx &= ~DBOP_HASH_TAG;
2N/A if (idx >= count)
2N/A return (-1);
2N/A hptr = &getXbyY_to_dbop[idx];
2N/A if (hptr->dbop != dbop || strcmp(name, hptr->name) != 0)
2N/A return (-1);
2N/A return (idx);
2N/A}
2N/A
2N/A/*
2N/A * nss_pack_key2str
2N/A * Private key to string packing function for getXbyY routines
2N/A * This routine performs a printf like parse over the argument
2N/A * key, given a string of items to pack and assembles the key in
2N/A * the packed structure. This routine is called (currently) by
2N/A * nss_default_key2str, but will be used by other external
2N/A * APIs in the future.
2N/A *
2N/A * buffer - Start of the key buffer location [in packed buffer]
2N/A * length - Length of key buffer component
2N/A * Key offsets are relative to start of key buffer location.
2N/A *
2N/A * Pack fields Key
2N/A * key.name n
2N/A * key.number N
2N/A * key.uid u
2N/A * key.gid g
2N/A * key.hostaddr h
2N/A * key.ipnode i
2N/A * key.projid p
2N/A * key.serv(name) s
2N/A * key.serv(port) S
2N/A * key.ether e
2N/A * key.pkey k
2N/A * key.netaddr a
2N/A * key.attrp A
2N/A * groupsbymember I
2N/A * innetgr_args t
2N/A * setnetgr_args T
2N/A */
2N/A
2N/A/*ARGSUSED*/
2N/Astatic nss_status_t
2N/Anss_pack_key2str(void *buffer, size_t length, nss_XbyY_args_t *arg,
2N/A const char *dbname, int dbop, size_t *rlen, const char *typestr)
2N/A{
2N/A int i, j;
2N/A size_t len, len2, len3, len4, len5, slop;
2N/A nssuint_t *uptr, offv, offc;
2N/A struct nss_setnetgrent_args *sng;
2N/A struct nss_innetgr_args *ing;
2N/A struct nss_groupsbymem *gbm;
2N/A char **cv, *dptr;
2N/A nss_pnetgr_t *pptr;
2N/A _priv_execattr *pe;
2N/A
2N/A if (buffer == NULL || length == 0 || arg == NULL ||
2N/A dbname == NULL || rlen == NULL || typestr == NULL)
2N/A return (NSS_ERROR);
2N/A
2N/A while (typestr && *typestr) {
2N/A switch (*typestr++) {
2N/A case 'n':
2N/A if (arg->key.name == NULL)
2N/A return (NSS_NOTFOUND);
2N/A len = strlen(arg->key.name) + 1;
2N/A if (len >= length)
2N/A return (NSS_ERROR);
2N/A (void) strlcpy(buffer, arg->key.name, len);
2N/A *rlen = len;
2N/A break;
2N/A case 'N':
2N/A len = sizeof (nssuint_t);
2N/A if (len >= length)
2N/A return (NSS_ERROR);
2N/A *(nssuint_t *)buffer = (nssuint_t)arg->key.number;
2N/A *rlen = len;
2N/A break;
2N/A case 'u':
2N/A len = sizeof (nssuint_t);
2N/A if (len >= length)
2N/A return (NSS_ERROR);
2N/A *(nssuint_t *)buffer = (nssuint_t)arg->key.uid;
2N/A *rlen = len;
2N/A break;
2N/A case 'g':
2N/A len = sizeof (nssuint_t);
2N/A if (len >= length)
2N/A return (NSS_ERROR);
2N/A *(nssuint_t *)buffer = (nssuint_t)arg->key.gid;
2N/A *rlen = len;
2N/A break;
2N/A case 'h':
2N/A if (arg->key.hostaddr.addr == NULL)
2N/A return (-1);
2N/A len = arg->key.hostaddr.len;
2N/A len = ROUND_UP(len, sizeof (nssuint_t));
2N/A len2 = (sizeof (nssuint_t) * 2) + len;
2N/A if (len2 >= length)
2N/A return (NSS_ERROR);
2N/A *(nssuint_t *)buffer =
2N/A (nssuint_t)arg->key.hostaddr.len;
2N/A buffer = (void *)((char *)buffer + sizeof (nssuint_t));
2N/A *(nssuint_t *)buffer =
2N/A (nssuint_t)arg->key.hostaddr.type;
2N/A buffer = (void *)((char *)buffer + sizeof (nssuint_t));
2N/A (void) memcpy(buffer, arg->key.hostaddr.addr,
2N/A arg->key.hostaddr.len);
2N/A *rlen = len2;
2N/A break;
2N/A case 'i':
2N/A if (arg->key.ipnode.name == NULL)
2N/A return (NSS_NOTFOUND);
2N/A len = strlen(arg->key.ipnode.name) + 1;
2N/A len = ROUND_UP(len, sizeof (nssuint_t));
2N/A len2 = (sizeof (nssuint_t) * 2) + len;
2N/A if (len2 >= length)
2N/A return (NSS_ERROR);
2N/A *(nssuint_t *)buffer =
2N/A (nssuint_t)arg->key.ipnode.af_family;
2N/A buffer = (void *)((char *)buffer + sizeof (nssuint_t));
2N/A *(nssuint_t *)buffer =
2N/A (nssuint_t)arg->key.ipnode.flags;
2N/A buffer = (void *)((char *)buffer + sizeof (nssuint_t));
2N/A (void) strlcpy(buffer, arg->key.ipnode.name, len);
2N/A *rlen = len2;
2N/A break;
2N/A case 'p':
2N/A len = sizeof (nssuint_t);
2N/A if (len >= length)
2N/A return (NSS_ERROR);
2N/A *(nssuint_t *)buffer = (nssuint_t)arg->key.projid;
2N/A *rlen = len;
2N/A break;
2N/A case 's':
2N/A if (arg->key.serv.serv.name == NULL)
2N/A return (NSS_NOTFOUND);
2N/A len = strlen(arg->key.serv.serv.name) + 1;
2N/A len2 = 1;
2N/A if (arg->key.serv.proto != NULL)
2N/A len2 += strlen(arg->key.serv.proto);
2N/A len3 = len + len2;
2N/A len3 = ROUND_UP(len3, sizeof (nssuint_t));
2N/A if (len3 >= length)
2N/A return (NSS_ERROR);
2N/A (void) strlcpy(buffer, arg->key.serv.serv.name, len);
2N/A buffer = (void *)((char *)buffer + len);
2N/A if (len2 > 1)
2N/A (void) strlcpy(buffer, arg->key.serv.proto,
2N/A len2);
2N/A else
2N/A *(char *)buffer = '\0';
2N/A *rlen = len3;
2N/A break;
2N/A case 'S':
2N/A len2 = 0;
2N/A if (arg->key.serv.proto != NULL)
2N/A len2 = strlen(arg->key.serv.proto) + 1;
2N/A len = sizeof (nssuint_t) + len2;
2N/A if (len >= length)
2N/A return (NSS_ERROR);
2N/A uptr = (nssuint_t *)buffer;
2N/A *uptr++ = (nssuint_t)arg->key.serv.serv.port;
2N/A if (len2) {
2N/A (void) strlcpy((char *)uptr,
2N/A arg->key.serv.proto, len2);
2N/A }
2N/A *rlen = len;
2N/A break;
2N/A case 'e':
2N/A if (arg->key.ether == NULL)
2N/A return (NSS_NOTFOUND);
2N/A len = sizeof (struct ether_addr);
2N/A len = ROUND_UP(len, sizeof (nssuint_t));
2N/A if (len >= length)
2N/A return (NSS_ERROR);
2N/A *(struct ether_addr *)buffer =
2N/A *(struct ether_addr *)arg->key.ether;
2N/A *rlen = len;
2N/A break;
2N/A case 'k':
2N/A if (arg->key.pkey.name == NULL ||
2N/A arg->key.pkey.keytype == NULL)
2N/A return (NSS_NOTFOUND);
2N/A len = strlen(arg->key.pkey.name) + 1;
2N/A len2 = strlen(arg->key.pkey.keytype) + 1;
2N/A len3 = len + len2;
2N/A len3 = ROUND_UP(len3, sizeof (nssuint_t));
2N/A if (len3 >= length)
2N/A return (NSS_ERROR);
2N/A (void) strlcpy(buffer, arg->key.pkey.name, len);
2N/A buffer = (void *)((char *)buffer + len);
2N/A (void) strlcpy(buffer, arg->key.pkey.keytype, len2);
2N/A *rlen = len3;
2N/A break;
2N/A case 'a':
2N/A uptr = (nssuint_t *)buffer;
2N/A len = sizeof (nssuint_t) * 2;
2N/A if (len >= length)
2N/A return (NSS_ERROR);
2N/A *uptr++ = (nssuint_t)arg->key.netaddr.net;
2N/A *uptr++ = (nssuint_t)arg->key.netaddr.type;
2N/A *rlen = len;
2N/A break;
2N/A case 'A':
2N/A pe = (_priv_execattr *)(arg->key.attrp);
2N/A if (pe == NULL)
2N/A return (NSS_NOTFOUND);
2N/A /* for search flag */
2N/A len = sizeof (nssuint_t);
2N/A /* for sizeof (_priv_execattr) static buffer */
2N/A /* Plus lots of slop just in case... */
2N/A slop = sizeof (nssuint_t) * 16;
2N/A len += slop;
2N/A
2N/A len2 = len3 = len4 = len5 = 1;
2N/A if (pe->name != NULL)
2N/A len2 = strlen(pe->name) + 1;
2N/A if (pe->type != NULL)
2N/A len3 = strlen(pe->type) + 1;
2N/A if (pe->id != NULL)
2N/A len4 = strlen(pe->id) + 1;
2N/A if (pe->policy != NULL)
2N/A len5 = strlen(pe->policy) + 1;
2N/A /* head_exec, prev_exec - are client side only... */
2N/A len += len2 + len3 + len4 + len5;
2N/A len = ROUND_UP(len, sizeof (nssuint_t));
2N/A if (len >= length)
2N/A return (NSS_ERROR);
2N/A (void) memset((void *)buffer, 0, slop);
2N/A uptr = (nssuint_t *)((void *)((char *)buffer + slop));
2N/A *uptr++ = (nssuint_t)pe->search_flag;
2N/A dptr = (char *)uptr;
2N/A if (len2 == 1)
2N/A *dptr++ = '\0';
2N/A else {
2N/A (void) strlcpy(dptr, pe->name, len2);
2N/A dptr += len2;
2N/A }
2N/A if (len3 == 1)
2N/A *dptr++ = '\0';
2N/A else {
2N/A (void) strlcpy(dptr, pe->type, len3);
2N/A dptr += len3;
2N/A }
2N/A if (len4 == 1)
2N/A *dptr++ = '\0';
2N/A else {
2N/A (void) strlcpy(dptr, pe->id, len4);
2N/A dptr += len4;
2N/A }
2N/A if (len5 == 1)
2N/A *dptr++ = '\0';
2N/A else
2N/A (void) strlcpy(dptr, pe->policy, len5);
2N/A *rlen = len;
2N/A break;
2N/A case 'I':
2N/A gbm = (struct nss_groupsbymem *)arg;
2N/A if (gbm->username == NULL)
2N/A return (NSS_NOTFOUND);
2N/A len = strlen(gbm->username) + 1;
2N/A len2 = sizeof (nssuint_t) * 4;
2N/A len2 += ROUND_UP(len, sizeof (nssuint_t));
2N/A if (len2 >= length)
2N/A return (NSS_ERROR);
2N/A uptr = (nssuint_t *)buffer;
2N/A *uptr++ = (nssuint_t)gbm->force_slow_way;
2N/A *uptr++ = (nssuint_t)gbm->maxgids;
2N/A *uptr++ = (nssuint_t)gbm->numgids;
2N/A if (gbm->numgids == 1) {
2N/A *uptr++ = (nssuint_t)gbm->gid_array[0];
2N/A } else {
2N/A *uptr++ = (nssuint_t)0;
2N/A }
2N/A (void) strlcpy((void *)uptr, gbm->username, len);
2N/A *rlen = len2;
2N/A break;
2N/A case 't':
2N/A pptr = (nss_pnetgr_t *)buffer;
2N/A ing = (struct nss_innetgr_args *)arg;
2N/A len = sizeof (nss_pnetgr_t);
2N/A len2 = ing->arg[NSS_NETGR_MACHINE].argc +
2N/A ing->arg[NSS_NETGR_USER].argc +
2N/A ing->arg[NSS_NETGR_DOMAIN].argc +
2N/A ing->groups.argc;
2N/A len2 *= sizeof (nssuint_t);
2N/A len3 = 0;
2N/A for (j = 0; j < NSS_NETGR_N; j++) {
2N/A cv = ing->arg[j].argv;
2N/A for (i = ing->arg[j].argc; --i >= 0; ) {
2N/A if (*cv)
2N/A len3 += strlen(*cv++) + 1;
2N/A }
2N/A }
2N/A cv = ing->groups.argv;
2N/A for (i = ing->groups.argc; --i >= 0; ) {
2N/A if (*cv)
2N/A len3 += strlen(*cv++) + 1;
2N/A }
2N/A len3 = ROUND_UP(len3, sizeof (nssuint_t));
2N/A /*
2N/A * Double argv space. Reason:
2N/A * First 1/2 offsets
2N/A * Second 1/2 for client side pointer arrays
2N/A * resolves malloc/free issues with unpacked argvs
2N/A */
2N/A if ((len + (len2 << 1) + len3) >= length)
2N/A return (NSS_ERROR);
2N/A *rlen = len + (len2 << 1) + len3;
2N/A
2N/A pptr->machine_argc = ing->arg[NSS_NETGR_MACHINE].argc;
2N/A pptr->user_argc = ing->arg[NSS_NETGR_USER].argc;
2N/A pptr->domain_argc = ing->arg[NSS_NETGR_DOMAIN].argc;
2N/A pptr->groups_argc = ing->groups.argc;
2N/A offv = len;
2N/A uptr = (nssuint_t *)((void *)((char *)buffer + offv));
2N/A offc = len + (len2 << 1);
2N/A dptr = (char *)buffer + offc;
2N/A if (pptr->machine_argc == 0) {
2N/A pptr->machine_offv = (nssuint_t)0;
2N/A } else {
2N/A pptr->machine_offv = offv;
2N/A cv = ing->arg[NSS_NETGR_MACHINE].argv;
2N/A i = pptr->machine_argc;
2N/A offv += sizeof (nssuint_t) * i;
2N/A for (; --i >= 0; ) {
2N/A *uptr++ = offc;
2N/A len3 = strlen(*cv) + 1;
2N/A (void) strlcpy(dptr, *cv++, len3);
2N/A offc += len3;
2N/A dptr += len3;
2N/A }
2N/A }
2N/A if (pptr->user_argc == 0) {
2N/A pptr->user_offv = (nssuint_t)0;
2N/A } else {
2N/A pptr->user_offv = offv;
2N/A cv = ing->arg[NSS_NETGR_USER].argv;
2N/A i = pptr->user_argc;
2N/A offv += sizeof (nssuint_t) * i;
2N/A for (; --i >= 0; ) {
2N/A *uptr++ = offc;
2N/A len3 = strlen(*cv) + 1;
2N/A (void) strlcpy(dptr, *cv++, len3);
2N/A offc += len3;
2N/A dptr += len3;
2N/A }
2N/A }
2N/A if (pptr->domain_argc == 0) {
2N/A pptr->domain_offv = (nssuint_t)0;
2N/A } else {
2N/A pptr->domain_offv = offv;
2N/A cv = ing->arg[NSS_NETGR_DOMAIN].argv;
2N/A i = pptr->domain_argc;
2N/A offv += sizeof (nssuint_t) * i;
2N/A for (; --i >= 0; ) {
2N/A *uptr++ = offc;
2N/A len3 = strlen(*cv) + 1;
2N/A (void) strlcpy(dptr, *cv++, len3);
2N/A offc += len3;
2N/A dptr += len3;
2N/A }
2N/A }
2N/A if (pptr->groups_argc == 0) {
2N/A pptr->groups_offv = (nssuint_t)0;
2N/A } else {
2N/A pptr->groups_offv = offv;
2N/A cv = ing->groups.argv;
2N/A i = pptr->groups_argc;
2N/A offv += sizeof (nssuint_t) * i;
2N/A for (; --i >= 0; ) {
2N/A *uptr++ = offc;
2N/A len3 = strlen(*cv) + 1;
2N/A (void) strlcpy(dptr, *cv++, len3);
2N/A offc += len3;
2N/A dptr += len3;
2N/A }
2N/A }
2N/A break;
2N/A case 'T':
2N/A sng = (struct nss_setnetgrent_args *)arg;
2N/A if (sng->netgroup == NULL)
2N/A return (NSS_NOTFOUND);
2N/A len = strlen(sng->netgroup) + 1;
2N/A if (len >= length)
2N/A return (NSS_ERROR);
2N/A (void) strlcpy(buffer, sng->netgroup, len);
2N/A *rlen = len;
2N/A break;
2N/A default:
2N/A return (NSS_ERROR);
2N/A }
2N/A }
2N/A return (NSS_SUCCESS);
2N/A}
2N/A
2N/Anss_status_t
2N/Anss_default_key2str(void *buffer, size_t length, nss_XbyY_args_t *arg,
2N/A const char *dbname, int dbop, size_t *rlen)
2N/A{
2N/A int index;
2N/A
2N/A if (buffer == NULL || length == 0 || arg == NULL ||
2N/A dbname == NULL || rlen == NULL)
2N/A return (NSS_ERROR);
2N/A
2N/A /*
2N/A * If this is not one of the well known getXbyYs
2N/A * (IE _printers special processing etc.) use a
2N/A * local (non-nscd) getXbyY lookup.
2N/A */
2N/A if ((index = nss_dbop_search(dbname, (uint32_t)dbop)) < 0)
2N/A return (NSS_TRYLOCAL);
2N/A
2N/A return (nss_pack_key2str(buffer, length, arg, dbname,
2N/A dbop, rlen, getXbyY_to_dbop[index].tostr));
2N/A}
2N/A
2N/A/*ARGSUSED*/
2N/Avoid
2N/Anss_packed_set_status(void *buffer, size_t length, nss_status_t status,
2N/A nss_XbyY_args_t *arg)
2N/A{
2N/A nss_pheader_t *pbuf = (nss_pheader_t *)buffer;
2N/A nss_dbd_t *pdbd;
2N/A char *dbn;
2N/A
2N/A /* sidestep odd cases */
2N/A pdbd = (nss_dbd_t *)((void *)((char *)buffer + pbuf->dbd_off));
2N/A dbn = (char *)pdbd + pdbd->o_name;
2N/A if (pbuf->nss_dbop == NSS_DBOP_GROUP_BYMEMBER) {
2N/A if (strcmp(dbn, NSS_DBNAM_GROUP) == 0) {
2N/A struct nss_groupsbymem *in =
2N/A (struct nss_groupsbymem *)arg;
2N/A
2N/A if (in->numgids >= 0) {
2N/A pbuf->p_status = NSS_SUCCESS;
2N/A pbuf->data_len = in->numgids *
2N/A sizeof (gid_t);
2N/A pbuf->p_herrno = 0;
2N/A } else {
2N/A pbuf->p_status = status;
2N/A pbuf->p_errno = errno;
2N/A pbuf->data_len = 0;
2N/A pbuf->p_herrno = (uint32_t)arg->h_errno;
2N/A }
2N/A return;
2N/A }
2N/A }
2N/A if (pbuf->nss_dbop == NSS_DBOP_NETGROUP_IN) {
2N/A if (strcmp(dbn, NSS_DBNAM_NETGROUP) == 0) {
2N/A struct nss_innetgr_args *in =
2N/A (struct nss_innetgr_args *)arg;
2N/A
2N/A /* tell nss_unpack() operation is successful */
2N/A pbuf->data_len = 1;
2N/A
2N/A if (status != NSS_SUCCESS && status != NSS_NOTFOUND) {
2N/A pbuf->p_status = status;
2N/A pbuf->p_errno = errno;
2N/A return;
2N/A }
2N/A
2N/A if (in->status == NSS_NETGR_FOUND) {
2N/A pbuf->p_status = NSS_SUCCESS;
2N/A } else {
2N/A pbuf->p_status = NSS_NOTFOUND;
2N/A pbuf->p_errno = errno;
2N/A }
2N/A return;
2N/A }
2N/A }
2N/A
2N/A /* process normal cases */
2N/A if ((pbuf->p_status = status) != NSS_SUCCESS) {
2N/A if (arg->erange == 1)
2N/A pbuf->p_errno = ERANGE;
2N/A else
2N/A pbuf->p_errno = errno;
2N/A } else
2N/A pbuf->p_errno = 0;
2N/A if (arg != NULL) {
2N/A pbuf->p_herrno = (uint32_t)arg->h_errno;
2N/A pbuf->data_len = (nssuint_t)arg->returnlen;
2N/A } else {
2N/A pbuf->p_herrno = 0;
2N/A pbuf->data_len = 0;
2N/A }
2N/A}
2N/A
2N/A/*
2N/A * nss_upack_key2arg
2N/A * Private string to key unpacking function for getXbyY routines
2N/A * This routine performs a scanf/printf like parse over the packed
2N/A * string, to uppack and re-assemble the key in the args structure.
2N/A *
2N/A * buffer - Start of the key buffer location [in packed buffer]
2N/A * length - Length of key buffer component
2N/A * Key offsets are relative to start of key buffer location.
2N/A *
2N/A * Unpack fields Key
2N/A * key.name n
2N/A * key.number N
2N/A * key.uid u
2N/A * key.gid g
2N/A * key.hostaddr h
2N/A * key.ipnode i
2N/A * key.projid p
2N/A * key.serv(name) s
2N/A * key.serv(port) S
2N/A * key.ether e
2N/A * key.pkey k
2N/A * key.netaddr a
2N/A * key.attrp A
2N/A * groupsbymember I
2N/A * innetgr_args t
2N/A * setnetgr_args T
2N/A * Assumes arguments are all valid
2N/A */
2N/A
2N/A/*ARGSUSED*/
2N/Astatic nss_status_t
2N/Anss_upack_key2arg(void *buffer, size_t length, char **dbname,
2N/A int *dbop, nss_XbyY_args_t *arg, int index)
2N/A{
2N/A nss_pheader_t *pbuf = (nss_pheader_t *)buffer;
2N/A const char *strtype = NULL;
2N/A nssuint_t off, *uptr, keysize;
2N/A size_t len, slop;
2N/A int i, j;
2N/A char **cv, *bptr;
2N/A struct nss_setnetgrent_args *sng;
2N/A struct nss_innetgr_args *ing;
2N/A struct nss_groupsbymem *gbm;
2N/A nss_pnetgr_t *pptr;
2N/A _priv_execattr *pe;
2N/A
2N/A /* keysize is length of the key area */
2N/A keysize = pbuf->data_off - pbuf->key_off;
2N/A
2N/A off = pbuf->key_off;
2N/A bptr = (char *)buffer + off;
2N/A uptr = (nssuint_t *)((void *)bptr);
2N/A strtype = getXbyY_to_dbop[index].tostr;
2N/A if (strtype == NULL)
2N/A return (NSS_ERROR);
2N/A while (*strtype) {
2N/A switch (*strtype++) {
2N/A case 'n':
2N/A arg->key.name = (const char *)bptr;
2N/A break;
2N/A case 'N':
2N/A arg->key.number = (int)(*uptr);
2N/A break;
2N/A case 'u':
2N/A arg->key.uid = (uid_t)(*uptr);
2N/A break;
2N/A case 'g':
2N/A arg->key.gid = (gid_t)(*uptr);
2N/A break;
2N/A case 'h':
2N/A arg->key.hostaddr.len = (int)(*uptr++);
2N/A arg->key.hostaddr.type = (int)(*uptr++);
2N/A arg->key.hostaddr.addr = (const char *)uptr;
2N/A break;
2N/A case 'i':
2N/A arg->key.ipnode.af_family = (int)(*uptr++);
2N/A arg->key.ipnode.flags = (int)(*uptr++);
2N/A arg->key.ipnode.name = (const char *)uptr;
2N/A break;
2N/A case 'p':
2N/A arg->key.projid = (projid_t)(*uptr);
2N/A break;
2N/A case 's':
2N/A arg->key.serv.serv.name = (const char *)bptr;
2N/A len = strlen(arg->key.serv.serv.name) + 1;
2N/A bptr += len;
2N/A if (*(const char *)bptr == '\0')
2N/A arg->key.serv.proto = NULL;
2N/A else
2N/A arg->key.serv.proto = (const char *)bptr;
2N/A break;
2N/A case 'S':
2N/A arg->key.serv.serv.port = (int)(*uptr++);
2N/A if (pbuf->key_len == sizeof (nssuint_t)) {
2N/A arg->key.serv.proto = NULL;
2N/A } else {
2N/A bptr += sizeof (nssuint_t);
2N/A arg->key.serv.proto = (const char *)bptr;
2N/A }
2N/A break;
2N/A case 'e':
2N/A arg->key.ether = bptr;
2N/A break;
2N/A case 'k':
2N/A arg->key.pkey.name = (const char *)bptr;
2N/A len = strlen(arg->key.pkey.name) + 1;
2N/A bptr += len;
2N/A arg->key.pkey.keytype = (const char *)bptr;
2N/A break;
2N/A case 'a':
2N/A arg->key.netaddr.net = (uint32_t)(*uptr++);
2N/A arg->key.netaddr.type = (int)(*uptr++);
2N/A break;
2N/A case 'A':
2N/A pe = (_priv_execattr *)((void *)bptr);
2N/A /* use slop space as priv_execattr structure */
2N/A arg->key.attrp = (void *)pe;
2N/A /* skip over slop ... */
2N/A slop = sizeof (nssuint_t) * 16;
2N/A uptr = (nssuint_t *)((void *)((char *)bptr + slop));
2N/A pe->search_flag = (int)*uptr++;
2N/A bptr = (char *)uptr;
2N/A if (*bptr == '\0') {
2N/A pe->name = NULL;
2N/A bptr++;
2N/A } else {
2N/A pe->name = (char *)bptr;
2N/A bptr += strlen(pe->name) + 1;
2N/A }
2N/A if (*bptr == '\0') {
2N/A pe->type = NULL;
2N/A bptr++;
2N/A } else {
2N/A pe->type = (char *)bptr;
2N/A bptr += strlen(pe->type) + 1;
2N/A }
2N/A if (*bptr == '\0') {
2N/A pe->id = NULL;
2N/A bptr++;
2N/A } else {
2N/A pe->id = (char *)bptr;
2N/A bptr += strlen(pe->id) + 1;
2N/A }
2N/A if (*bptr == '\0') {
2N/A pe->policy = NULL;
2N/A } else {
2N/A pe->policy = (char *)bptr;
2N/A }
2N/A pe->head_exec = NULL;
2N/A pe->prev_exec = NULL;
2N/A break;
2N/A case 'I':
2N/A gbm = (struct nss_groupsbymem *)arg;
2N/A gbm->gid_array = (gid_t *)
2N/A ((void *)((char *)pbuf + pbuf->data_off));
2N/A gbm->force_slow_way = (int)(*uptr++);
2N/A gbm->maxgids = (int)(*uptr++);
2N/A gbm->numgids = (int)(*uptr++);
2N/A if (gbm->numgids == 1) {
2N/A /* insert initial group into data area */
2N/A gbm->gid_array[0] = (gid_t)(*uptr++);
2N/A } else
2N/A uptr++;
2N/A gbm->username = (const char *)uptr;
2N/A break;
2N/A case 't':
2N/A pptr = (nss_pnetgr_t *)((void *)bptr);
2N/A ing = (struct nss_innetgr_args *)arg;
2N/A ing->arg[NSS_NETGR_MACHINE].argc = pptr->machine_argc;
2N/A ing->arg[NSS_NETGR_USER].argc = pptr->user_argc;
2N/A ing->arg[NSS_NETGR_DOMAIN].argc = pptr->domain_argc;
2N/A ing->groups.argc = pptr->groups_argc;
2N/A
2N/A /*
2N/A * Start of argv pointer storage
2N/A */
2N/A off = ing->arg[NSS_NETGR_MACHINE].argc +
2N/A ing->arg[NSS_NETGR_USER].argc +
2N/A ing->arg[NSS_NETGR_DOMAIN].argc +
2N/A ing->groups.argc;
2N/A off *= sizeof (nssuint_t);
2N/A off += sizeof (nss_pnetgr_t);
2N/A
2N/A cv = (char **)((void *)(bptr + off));
2N/A uptr = (nssuint_t *)
2N/A ((void *)(bptr + sizeof (nss_pnetgr_t)));
2N/A for (j = 0; j < NSS_NETGR_N; j++) {
2N/A ing->arg[j].argv = cv;
2N/A for (i = 0; i < ing->arg[j].argc; i++) {
2N/A if (*uptr >= keysize)
2N/A return (NSS_ERROR);
2N/A *cv++ = (bptr + *uptr++);
2N/A }
2N/A }
2N/A ing->groups.argv = cv;
2N/A for (i = 0; i < ing->groups.argc; i++) {
2N/A if (*uptr >= keysize)
2N/A return (NSS_ERROR);
2N/A *cv++ = (bptr + *uptr++);
2N/A }
2N/A break;
2N/A case 'T':
2N/A sng = (struct nss_setnetgrent_args *)arg;
2N/A sng->netgroup = (const char *)bptr;
2N/A sng->iterator = 0;
2N/A break;
2N/A
2N/A default:
2N/A return (NSS_ERROR);
2N/A }
2N/A }
2N/A return (NSS_SUCCESS);
2N/A}
2N/A
2N/Astatic nss_status_t
2N/Anss_pinit_funcs(int index, nss_db_initf_t *initf, nss_str2ent_t *s2e)
2N/A{
2N/A const char *name;
2N/A void *htmp = NULL;
2N/A void *sym;
2N/A static void *handle = NULL;
2N/A static mutex_t handle_lock = DEFAULTMUTEX;
2N/A static mutex_t initf_lock = DEFAULTMUTEX;
2N/A static mutex_t s2e_lock = DEFAULTMUTEX;
2N/A
2N/A if (handle == NULL) {
2N/A htmp = dlopen((const char *)0, RTLD_LAZY);
2N/A
2N/A lmutex_lock(&handle_lock);
2N/A if (handle == NULL) {
2N/A if (htmp == NULL) {
2N/A lmutex_unlock(&handle_lock);
2N/A return (NSS_ERROR);
2N/A } else {
2N/A membar_producer();
2N/A handle = htmp;
2N/A htmp = NULL;
2N/A }
2N/A }
2N/A lmutex_unlock(&handle_lock);
2N/A if (htmp)
2N/A (void) dlclose(htmp);
2N/A }
2N/A membar_consumer();
2N/A
2N/A if (initf) {
2N/A if (getXbyY_to_dbop[index].initfnp == NULL) {
2N/A name = getXbyY_to_dbop[index].initfn;
2N/A if ((sym = dlsym(handle, name)) == NULL)
2N/A return (NSS_ERROR);
2N/A lmutex_lock(&initf_lock);
2N/A if (getXbyY_to_dbop[index].initfnp == NULL)
2N/A getXbyY_to_dbop[index].initfnp = sym;
2N/A membar_producer();
2N/A lmutex_unlock(&initf_lock);
2N/A }
2N/A membar_consumer();
2N/A *initf = (nss_db_initf_t)getXbyY_to_dbop[index].initfnp;
2N/A }
2N/A if (s2e) {
2N/A if (getXbyY_to_dbop[index].strfnp == NULL) {
2N/A name = getXbyY_to_dbop[index].strfn;
2N/A if ((sym = dlsym(handle, name)) == NULL)
2N/A return (NSS_ERROR);
2N/A lmutex_lock(&s2e_lock);
2N/A if (getXbyY_to_dbop[index].strfnp == NULL)
2N/A getXbyY_to_dbop[index].strfnp = sym;
2N/A membar_producer();
2N/A lmutex_unlock(&s2e_lock);
2N/A }
2N/A membar_consumer();
2N/A *s2e = (nss_str2ent_t)getXbyY_to_dbop[index].strfnp;
2N/A }
2N/A
2N/A return (NSS_SUCCESS);
2N/A}
2N/A
2N/Anss_status_t
2N/Anss_packed_getkey(void *buffer, size_t length, char **dbname,
2N/A int *dbop, nss_XbyY_args_t *arg)
2N/A{
2N/A nss_pheader_t *pbuf = (nss_pheader_t *)buffer;
2N/A nss_dbd_t *pdbd;
2N/A nssuint_t off, dbdsize;
2N/A int index;
2N/A
2N/A if (buffer == NULL || length == 0 || dbop == NULL ||
2N/A arg == NULL || dbname == NULL)
2N/A return (NSS_ERROR);
2N/A
2N/A *dbop = pbuf->nss_dbop;
2N/A off = pbuf->dbd_off;
2N/A pdbd = (nss_dbd_t *)((void *)((char *)buffer + off));
2N/A dbdsize = pbuf->key_off - pbuf->dbd_off;
2N/A if (pdbd->o_name >= dbdsize || pdbd->o_config_name >= dbdsize ||
2N/A pdbd->o_default_config >= dbdsize)
2N/A return (NSS_ERROR);
2N/A *dbname = (char *)buffer + off + pdbd->o_name;
2N/A if ((index = nss_dbop_search(*dbname, (uint32_t)*dbop)) < 0)
2N/A return (NSS_ERROR);
2N/A return (nss_upack_key2arg(buffer, length, dbname, dbop, arg, index));
2N/A}
2N/A
2N/A
2N/A/*
2N/A * str2packent: Standard format interposed str2X function for normal APIs
2N/A *
2N/A * Return values: 0 = success, 1 = parse error, 2 = erange ...
2N/A *
2N/A * The structure pointer is ignored since this is a nscd side packed request.
2N/A * The client side routine does all the real parsing; we just check limits and
2N/A * store the entry in the buffer we were passed by the caller.
2N/A */
2N/A
2N/A/*ARGSUSED*/
2N/Aint
2N/Astr2packent(
2N/A const char *instr,
2N/A int lenstr,
2N/A void *ent, /* really (char *) */
2N/A char *buffer,
2N/A int buflen
2N/A)
2N/A{
2N/A if (buflen <= lenstr) { /* not enough buffer */
2N/A return (NSS_STR_PARSE_ERANGE);
2N/A }
2N/A (void) memmove(buffer, instr, lenstr);
2N/A buffer[lenstr] = '\0';
2N/A
2N/A return (NSS_STR_PARSE_SUCCESS);
2N/A}
2N/A
2N/A/*
2N/A * Initialize db_root, initf, dbop and arg from a packed buffer
2N/A */
2N/A
2N/A/*ARGSUSED*/
2N/Anss_status_t
2N/Anss_packed_arg_init(void *buffer, size_t length, nss_db_root_t *db_root,
2N/A nss_db_initf_t *initf, int *dbop, nss_XbyY_args_t *arg)
2N/A{
2N/A nss_pheader_t *pbuf = (nss_pheader_t *)buffer;
2N/A nss_str2ent_t s2e = str2packent;
2N/A nss_str2ent_t real_s2e = NULL;
2N/A nss_dbd_t *pdbd;
2N/A nssuint_t off, dbdsize;
2N/A char *dbname, *bptr;
2N/A size_t len;
2N/A int index;
2N/A
2N/A if (buffer == NULL || length == 0 ||
2N/A dbop == NULL || arg == NULL)
2N/A return (NSS_ERROR);
2N/A
2N/A /* init dbop */
2N/A *dbop = pbuf->nss_dbop;
2N/A off = pbuf->dbd_off;
2N/A pdbd = (nss_dbd_t *)((void *)((char *)buffer + off));
2N/A dbdsize = pbuf->key_off - pbuf->dbd_off;
2N/A if (pdbd->o_name >= dbdsize || pdbd->o_config_name >= dbdsize ||
2N/A pdbd->o_default_config >= dbdsize)
2N/A return (NSS_ERROR);
2N/A dbname = (char *)buffer + off + pdbd->o_name;
2N/A if ((index = nss_dbop_search(dbname, (uint32_t)*dbop)) < 0)
2N/A return (NSS_ERROR);
2N/A
2N/A /* db_root is initialized by nscd's based on door info */
2N/A /* do nothing here */
2N/A
2N/A /* init key information - (and get dbname dbop etc...) */
2N/A if (nss_upack_key2arg(buffer, length, &dbname,
2N/A dbop, arg, index) != NSS_SUCCESS)
2N/A return (NSS_ERROR);
2N/A
2N/A /* possible audituser init */
2N/A if (strcmp(dbname, NSS_DBNAM_AUTHATTR) == 0)
2N/A arg->h_errno = (int)pbuf->p_herrno;
2N/A
2N/A bptr = (char *)buffer + pbuf->data_off;
2N/A len = (size_t)pbuf->data_len;
2N/A
2N/A /* sidestep odd arg cases */
2N/A if (*dbop == NSS_DBOP_GROUP_BYMEMBER &&
2N/A strcmp(dbname, NSS_DBNAM_GROUP) == 0) {
2N/A /* get initf and str2ent functions */
2N/A if (nss_pinit_funcs(index, initf, &real_s2e) != NSS_SUCCESS)
2N/A return (NSS_ERROR);
2N/A ((struct nss_groupsbymem *)arg)->str2ent = real_s2e;
2N/A ((struct nss_groupsbymem *)arg)->process_cstr = process_cstr;
2N/A return (NSS_SUCCESS);
2N/A }
2N/A if (pbuf->nss_dbop == NSS_DBOP_NETGROUP_IN &&
2N/A strcmp(dbname, NSS_DBNAM_NETGROUP) == 0) {
2N/A return (NSS_SUCCESS);
2N/A }
2N/A
2N/A /* get initf and str2ent functions */
2N/A if (nss_pinit_funcs(index, initf, NULL) != NSS_SUCCESS)
2N/A return (NSS_ERROR);
2N/A
2N/A /* init normal arg cases */
2N/A NSS_XbyY_INIT(arg, NULL, bptr, len, s2e);
2N/A arg->h_errno = 0;
2N/A
2N/A return (NSS_SUCCESS);
2N/A}
2N/A
2N/A/*
2N/A * Initialize db_root, initf, dbop, contextp and arg from a packed buffer
2N/A */
2N/A
2N/A/*ARGSUSED*/
2N/Anss_status_t
2N/Anss_packed_context_init(void *buffer, size_t length, nss_db_root_t *db_root,
2N/A nss_db_initf_t *initf, nss_getent_t **contextp,
2N/A nss_XbyY_args_t *arg)
2N/A{
2N/A nss_pheader_t *pbuf = (nss_pheader_t *)buffer;
2N/A nss_str2ent_t s2e = str2packent;
2N/A char *bptr;
2N/A size_t len;
2N/A
2N/A /* init arg */
2N/A if (arg != NULL) {
2N/A bptr = (char *)buffer + pbuf->data_off;
2N/A len = (size_t)pbuf->data_len;
2N/A NSS_XbyY_INIT(arg, NULL, bptr, len, s2e);
2N/A }
2N/A
2N/A return (NSS_SUCCESS);
2N/A}