#include "lint.h"
#include <mtlib.h>
#include <dlfcn.h>
#include <atomic.h>
#define __NSS_PRIVATE_INTERFACE
#include "nsswitch_priv.h"
#undef __NSS_PRIVATE_INTERFACE
#include <nss_common.h>
#include <nss_dbdefs.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <thread.h>
#include <synch.h>
#include <pthread.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <errno.h>
#include "libc.h"
#include "tsd.h"
#include <getxby_door.h>
#define NSS_BUFLEN_PRACTICAL (512*1024)
static size_t __nss_buflen_group = NSS_BUFLEN_PRACTICAL;
static size_t __nss_buflen_default = NSS_BUFLEN_DOOR;
typedef struct {
void *p;
#if 0
void (*nss_delete_fp)(nss_db_root_t *rootp);
nss_status_t (*nss_search_fp)(nss_db_root_t *rootp,
nss_db_initf_t initf, int search_fnum,
void *search_args);
void (*nss_setent_u_fp)(nss_db_root_t *,
nss_db_initf_t, nss_getent_t *);
nss_status_t (*nss_getent_u_fp)(nss_db_root_t *,
nss_db_initf_t, nss_getent_t *, void *);
void (*nss_endent_u_fp)(nss_db_root_t *,
nss_db_initf_t, nss_getent_t *);
void (*end_iter_u_fp)(nss_db_root_t *rootp,
struct nss_getent_context *contextp);
#endif
} nss_policyf_t;
static mutex_t nss_policyf_lock = DEFAULTMUTEX;
static nss_policyf_t nss_policyf_ptrs =
{ (void *)NULL };
struct nss_db_state {
nss_db_root_t orphan_root;
unsigned refcount;
nss_db_params_t p;
struct __nsw_switchconfig_v1 *config;
int max_src;
struct nss_src_state *src;
};
struct nss_src_state {
struct __nsw_lookup_v1 *lkp;
int n_active;
int n_dormant;
int n_waiting;
cond_t wanna_be;
union {
nss_backend_t *single;
nss_backend_t **multi;
} dormant;
nss_backend_constr_t be_constr;
nss_backend_finder_t *finder;
void *finder_priv;
};
static struct nss_db_state *_nss_db_state_constr(nss_db_initf_t);
void _nss_db_state_destr(struct nss_db_state *);
#define NSS_ROOTLOCK(r, sp) (cancel_safe_mutex_lock(&(r)->lock), \
*(sp) = (r)->s)
#define NSS_UNLOCK(r) (cancel_safe_mutex_unlock(&(r)->lock))
#define NSS_CHECKROOT(rp, s) ((s) != (*(rp))->s && \
(cancel_safe_mutex_unlock(&(*(rp))->lock), \
cancel_safe_mutex_lock(&(s)->orphan_root.lock), \
*(rp) = &(s)->orphan_root))
#define NSS_RELOCK(rp, s) (cancel_safe_mutex_lock(&(*(rp))->lock), \
NSS_CHECKROOT(rp, s))
#define NSS_STATE_REF_u(s) (++(s)->refcount)
#define NSS_UNREF_UNLOCK(r, s) (--(s)->refcount != 0 \
? ((void)NSS_UNLOCK(r)) \
: ((void)NSS_UNLOCK(r), (void)_nss_db_state_destr(s)))
#define NSS_LOCK_CHECK(r, f, sp) (NSS_ROOTLOCK((r), (sp)), \
*(sp) == 0 && \
(r->s = *(sp) = _nss_db_state_constr(f)))
static int checked_env = 0;
FILE *__nss_debug_file = stdout;
int __nss_debug_eng_loop;
FILE *__nis_debug_file = stdout;
int __nis_debug_bind;
int __nis_debug_rpc;
int __nis_debug_calls;
char *__nis_prefsrv;
char *__nis_preftype;
char *__nis_server;
#define OPT_INT 1
#define OPT_STRING 2
#ifdef NSS_DEBUG_INSECURE
#define OPT_FILE 3
#endif
struct option {
char *name;
int type;
void *address;
};
static struct option nss_options[] = {
#ifdef NSS_DEBUG_INSECURE
{ "debug_file", OPT_FILE, &__nss_debug_file },
#endif
{ "debug_eng_loop", OPT_INT, &__nss_debug_eng_loop },
{ 0, 0, 0 },
};
static struct option nis_options[] = {
#ifdef NSS_DEBUG_INSECURE
{ "debug_file", OPT_FILE, &__nis_debug_file },
#endif
{ "debug_bind", OPT_INT, &__nis_debug_bind },
{ "debug_rpc", OPT_INT, &__nis_debug_rpc },
{ "debug_calls", OPT_INT, &__nis_debug_calls },
{ "server", OPT_STRING, &__nis_server },
{ "pref_srvr", OPT_STRING, &__nis_prefsrv },
{ "pref_type", OPT_STRING, &__nis_preftype },
{ 0, 0, 0 },
};
typedef struct nss_cfgparam {
char *name;
mutex_t *lock;
void *buffer;
size_t length;
} nss_cfgparam_t;
typedef struct nss_cfglist {
char *name;
nss_cfgparam_t *list;
int count;
int max;
} nss_cfglist_t;
#define NSS_CFG_INCR 16
static nss_cfglist_t *nss_cfg = NULL;
static int nss_cfgcount = 0;
static int nss_cfgmax = 0;
static mutex_t nss_cfglock = DEFAULTMUTEX;
static int nss_cfg_policy_init();
#define NSS_CONFIG_BRK ':'
static nss_config_t nss_policy_params[] = {
{ "nss:policyfunc", NSS_CONFIG_ADD, &nss_policyf_lock,
(void *)&nss_policyf_ptrs, (size_t)sizeof (nss_policyf_t) },
{ NULL, NSS_CONFIG_ADD, (mutex_t *)NULL, (void *)NULL, (size_t)0 },
};
static int
nss_cfgcn_cmp(const char *cfgname, const char *compname)
{
char *c;
size_t len, len2;
if ((c = strchr(cfgname, NSS_CONFIG_BRK)) == NULL)
return (-1);
len = (size_t)(c - cfgname);
len2 = strlen(compname);
if (len2 != len)
return (-1);
return (strncmp(cfgname, compname, len));
}
static int
nss_cfg_init()
{
nss_cfglist_t *cfg;
int i;
if (nss_cfg != NULL) {
membar_consumer();
return (0);
}
lmutex_lock(&nss_cfglock);
if (nss_cfg != NULL) {
lmutex_unlock(&nss_cfglock);
membar_consumer();
return (0);
}
cfg = libc_malloc(NSS_CFG_INCR * sizeof (nss_cfglist_t));
if (cfg == NULL) {
errno = ENOMEM;
lmutex_unlock(&nss_cfglock);
return (-1);
}
for (i = 0; i < NSS_CFG_INCR; i++) {
cfg[i].list = libc_malloc(
NSS_CFG_INCR * sizeof (nss_cfgparam_t));
if (cfg[i].list == NULL) {
while (--i >= 0)
libc_free(cfg[i].list);
libc_free(cfg);
errno = ENOMEM;
lmutex_unlock(&nss_cfglock);
return (-1);
}
cfg[i].max = NSS_CFG_INCR;
}
nss_cfgmax = NSS_CFG_INCR;
membar_producer();
nss_cfg = cfg;
lmutex_unlock(&nss_cfglock);
if (nss_cfg_policy_init() < 0) {
return (-1);
}
return (0);
}
static nss_cfglist_t *
nss_cfgcomp_get(char *name, int add)
{
nss_cfglist_t *next;
char *c;
int i, len;
size_t nsize;
if (nss_cfg_init() < 0)
return ((nss_cfglist_t *)NULL);
if (name == NULL || (c = strchr(name, NSS_CONFIG_BRK)) == NULL)
return ((nss_cfglist_t *)NULL);
lmutex_lock(&nss_cfglock);
next = nss_cfg;
for (i = 0; i < nss_cfgcount; i++) {
if (next->name && nss_cfgcn_cmp(name, next->name) == 0) {
lmutex_unlock(&nss_cfglock);
return (next);
}
next++;
}
if (!add) {
lmutex_unlock(&nss_cfglock);
return (NULL);
}
if (nss_cfgcount >= nss_cfgmax) {
nsize = (nss_cfgmax + NSS_CFG_INCR) * sizeof (nss_cfgparam_t);
next = (nss_cfglist_t *)libc_realloc(nss_cfg, nsize);
if (next == NULL) {
errno = ENOMEM;
lmutex_unlock(&nss_cfglock);
return ((nss_cfglist_t *)NULL);
}
(void) memset((void *)(next + nss_cfgcount), '\0',
NSS_CFG_INCR * sizeof (nss_cfglist_t));
nss_cfgmax += NSS_CFG_INCR;
nss_cfg = next;
}
next = nss_cfg + nss_cfgcount;
len = (size_t)(c - name) + 1;
if ((next->name = libc_malloc(len)) == NULL) {
errno = ENOMEM;
lmutex_unlock(&nss_cfglock);
return ((nss_cfglist_t *)NULL);
}
nss_cfgcount++;
(void) strlcpy(next->name, name, len);
lmutex_unlock(&nss_cfglock);
return (next);
}
static nss_cfgparam_t *
nss_cfgparam_get(char *name, int add)
{
nss_cfglist_t *comp;
nss_cfgparam_t *next;
int count, i;
size_t nsize;
if ((comp = nss_cfgcomp_get(name, add)) == NULL)
return ((nss_cfgparam_t *)NULL);
lmutex_lock(&nss_cfglock);
count = comp->count;
next = comp->list;
for (i = 0; i < count; i++) {
if (next->name && strcmp(name, next->name) == 0) {
lmutex_unlock(&nss_cfglock);
return (next);
}
next++;
}
if (!add) {
lmutex_unlock(&nss_cfglock);
return (NULL);
}
if (count >= comp->max) {
nsize = (comp->max + NSS_CFG_INCR) * sizeof (nss_cfgparam_t);
next = (nss_cfgparam_t *)libc_realloc(comp->list, nsize);
if (next == NULL) {
errno = ENOMEM;
lmutex_unlock(&nss_cfglock);
return ((nss_cfgparam_t *)NULL);
}
comp->max += NSS_CFG_INCR;
comp->list = next;
}
next = comp->list + comp->count;
if ((next->name = libc_strdup(name)) == NULL) {
errno = ENOMEM;
lmutex_unlock(&nss_cfglock);
return ((nss_cfgparam_t *)NULL);
}
comp->count++;
lmutex_unlock(&nss_cfglock);
return (next);
}
static void
nss_cfg_del(nss_config_t *cfgp)
{
char *name;
nss_cfglist_t *comp;
nss_cfgparam_t *next, *cur;
int count, i, j;
if ((name = cfgp->name) == NULL ||
(comp = nss_cfgcomp_get(name, 0)) == NULL)
return;
lmutex_lock(&nss_cfglock);
count = comp->count;
next = comp->list;
for (i = 0; i < count; i++) {
if (next->name && strcmp(name, next->name) == 0) {
break;
}
next++;
}
if (i >= count) {
lmutex_unlock(&nss_cfglock);
return;
}
cur = next;
next++;
for (j = i+1; j < count; j++) {
*cur = *next;
cur++;
next++;
}
if (cur->name) {
libc_free(cur->name);
cur->name = (char *)NULL;
}
cur->lock = (mutex_t *)NULL;
cur->buffer = (void *)NULL;
cur->length = 0;
comp->count--;
lmutex_unlock(&nss_cfglock);
}
static int
nss_cfg_get(nss_config_t *next)
{
nss_cfgparam_t *param;
errno = 0;
if ((param = nss_cfgparam_get(next->name, 0)) == NULL)
return (-1);
next->lock = param->lock;
next->buffer = param->buffer;
next->length = param->length;
return (0);
}
static int
nss_cfg_put(nss_config_t *next, int add)
{
nss_cfgparam_t *param;
errno = 0;
if ((param = nss_cfgparam_get(next->name, add)) == NULL)
return (-1);
param->lock = next->lock;
param->buffer = next->buffer;
param->length = next->length;
return (0);
}
nss_status_t
nss_config(nss_config_t **plist, int cnt)
{
nss_config_t *next;
int i;
if (_nsc_proc_is_cache() <= 0) {
return (NSS_UNAVAIL);
}
if (plist == NULL || cnt <= 0)
return (NSS_SUCCESS);
for (i = 0; i < cnt; i++) {
next = plist[i];
if (next == NULL)
break;
if (next->name == NULL) {
errno = EFAULT;
return (NSS_ERROR);
}
switch (next->cop) {
case NSS_CONFIG_GET:
if (nss_cfg_get(next) < 0) {
return (NSS_ERROR);
}
break;
case NSS_CONFIG_PUT:
if (nss_cfg_put(next, 0) < 0) {
return (NSS_ERROR);
}
break;
case NSS_CONFIG_ADD:
if (nss_cfg_put(next, 1) < 0) {
return (NSS_ERROR);
}
break;
case NSS_CONFIG_DELETE:
nss_cfg_del(next);
break;
case NSS_CONFIG_LIST:
break;
default:
continue;
}
}
return (NSS_SUCCESS);
}
static int
nss_cfg_policy_init()
{
nss_config_t *next = &nss_policy_params[0];
for (; next && next->name != NULL; next++) {
if (nss_cfg_put(next, 1) < 0)
return (-1);
}
return (0);
}
static
void
set_option(struct option *opt, char *name, char *val)
{
int n;
char *p;
#ifdef NSS_DEBUG_INSECURE
FILE *fp;
#endif
for (; opt->name; opt++) {
if (strcmp(name, opt->name) == 0) {
switch (opt->type) {
case OPT_STRING:
p = libc_strdup(val);
*((char **)opt->address) = p;
break;
case OPT_INT:
if (strcmp(val, "") == 0)
n = 1;
else
n = atoi(val);
*((int *)opt->address) = n;
break;
#ifdef NSS_DEBUG_INSECURE
case OPT_FILE:
fp = fopen(val, "wF");
*((FILE **)opt->address) = fp;
break;
#endif
}
break;
}
}
}
static
void
__parse_environment(struct option *opt, char *p)
{
char *base;
char optname[100];
char optval[100];
while (*p) {
while (isspace(*p))
p++;
if (*p == '\0')
break;
base = p;
while (*p && *p != '=' && !isspace(*p))
p++;
if ((p-base) >= sizeof (optname))
return;
(void) strncpy(optname, base, p-base);
optname[p-base] = '\0';
if (*p == '=') {
p++;
base = p;
while (*p && !isspace(*p))
p++;
if ((p-base) >= sizeof (optval))
return;
(void) strncpy(optval, base, p-base);
optval[p-base] = '\0';
} else {
optval[0] = '\0';
}
set_option(opt, optname, optval);
}
}
static
void
nss_get_environment()
{
char *p;
p = getenv("NSS_OPTIONS");
if (p == NULL)
return;
__parse_environment(nss_options, p);
}
void
__nis_get_environment()
{
char *p;
p = getenv("NIS_OPTIONS");
if (p == NULL)
return;
__parse_environment(nis_options, p);
}
static nss_backend_t *
nss_get_backend_u(nss_db_root_t **rootpp, struct nss_db_state *s, int n_src)
{
struct nss_src_state *src = &s->src[n_src];
nss_backend_t *be;
int cancel_state;
for (;;) {
if (src->n_dormant > 0) {
src->n_dormant--;
src->n_active++;
if (s->p.max_dormant_per_src == 1) {
be = src->dormant.single;
} else {
be = src->dormant.multi[src->n_dormant];
}
break;
}
if (src->be_constr == 0) {
nss_backend_finder_t *bf;
for (bf = s->p.finders; bf != 0; bf = bf->next) {
nss_backend_constr_t c;
c = (*bf->lookup) (bf->lookup_priv, s->p.name,
src->lkp->service_name, &src->finder_priv);
if (c != 0) {
src->be_constr = c;
src->finder = bf;
break;
}
}
if (src->be_constr == 0) {
be = 0;
break;
}
}
if (src->n_active < s->p.max_active_per_src) {
be = (*src->be_constr)(s->p.name,
src->lkp->service_name, 0 );
if (be != 0) {
src->n_active++;
break;
} else if (src->n_active == 0) {
break;
}
}
src->n_waiting++;
(void) pthread_setcancelstate(PTHREAD_CANCEL_DISABLE,
&cancel_state);
(void) cond_wait(&src->wanna_be, &(*rootpp)->lock);
(void) pthread_setcancelstate(cancel_state, NULL);
NSS_CHECKROOT(rootpp, s);
src->n_waiting--;
}
return (be);
}
static void
nss_put_backend_u(struct nss_db_state *s, int n_src, nss_backend_t *be)
{
struct nss_src_state *src = &s->src[n_src];
if (be == 0) {
return;
}
src->n_active--;
if (src->n_dormant < s->p.max_dormant_per_src) {
if (s->p.max_dormant_per_src == 1) {
src->dormant.single = be;
src->n_dormant++;
} else if (src->dormant.multi != 0 ||
(src->dormant.multi =
libc_malloc(s->p.max_dormant_per_src *
sizeof (nss_backend_t *))) != NULL) {
src->dormant.multi[src->n_dormant] = be;
src->n_dormant++;
} else {
(void) NSS_INVOKE_DBOP(be, NSS_DBOP_DESTRUCTOR, 0);
}
} else {
(void) NSS_INVOKE_DBOP(be, NSS_DBOP_DESTRUCTOR, 0);
}
if (src->n_waiting > 0) {
(void) cond_signal(&src->wanna_be);
}
}
static struct nss_db_state *
_nss_db_state_constr(nss_db_initf_t initf)
{
struct nss_db_state *s;
struct __nsw_switchconfig_v1 *config = 0;
struct __nsw_lookup_v1 *lkp;
enum __nsw_parse_err err;
const char *config_name;
int n_src;
if ((s = libc_malloc(sizeof (*s))) == 0) {
return (0);
}
(void) mutex_init(&s->orphan_root.lock, USYNC_THREAD, 0);
s->p.max_active_per_src = 10;
s->p.max_dormant_per_src = 1;
s->p.finders = nss_default_finders;
(*initf)(&s->p);
if (s->p.name == 0) {
_nss_db_state_destr(s);
return (0);
}
if (!checked_env) {
nss_get_environment();
checked_env = 1;
}
config_name = s->p.config_name ? s->p.config_name : s->p.name;
if (! (s->p.flags & NSS_USE_DEFAULT_CONFIG)) {
config = __nsw_getconfig_v1(config_name, &err);
}
if (config == 0) {
char *str;
if ((str = libc_strdup(s->p.default_config)) != 0) {
config = _nsw_getoneconfig_v1(config_name, str, &err);
libc_free(str);
}
if (config == 0) {
_nss_db_state_destr(s);
return (0);
}
}
s->config = config;
if ((s->max_src = config->num_lookups) <= 0 ||
(s->src = libc_malloc(s->max_src * sizeof (*s->src))) == 0) {
_nss_db_state_destr(s);
return (0);
}
for (n_src = 0, lkp = config->lookups;
n_src < s->max_src; n_src++, lkp = lkp->next) {
s->src[n_src].lkp = lkp;
(void) cond_init(&s->src[n_src].wanna_be, USYNC_THREAD, 0);
}
s->refcount = 1;
return (s);
}
void
_nss_src_state_destr(struct nss_src_state *src, int max_dormant)
{
if (max_dormant == 1) {
if (src->n_dormant != 0) {
(void) NSS_INVOKE_DBOP(src->dormant.single,
NSS_DBOP_DESTRUCTOR, 0);
};
} else if (src->dormant.multi != 0) {
int n;
for (n = 0; n < src->n_dormant; n++) {
(void) NSS_INVOKE_DBOP(src->dormant.multi[n],
NSS_DBOP_DESTRUCTOR, 0);
}
libc_free(src->dormant.multi);
}
if (src->finder != 0) {
(*src->finder->delete)(src->finder_priv, src->be_constr);
}
}
void
_nss_db_state_destr(struct nss_db_state *s)
{
if (s == NULL)
return;
if (s->p.cleanup != 0) {
(*s->p.cleanup)(&s->p);
}
if (s->config != 0) {
(void) __nsw_freeconfig_v1(s->config);
}
if (s->src != 0) {
int n_src;
for (n_src = 0; n_src < s->max_src; n_src++) {
_nss_src_state_destr(&s->src[n_src],
s->p.max_dormant_per_src);
}
libc_free(s->src);
}
libc_free(s);
}
static uint_t *
_nss_status_vec_p()
{
return (tsdalloc(_T_NSS_STATUS_VEC, sizeof (uint_t), NULL));
}
unsigned int
_nss_status_vec(void)
{
unsigned int *status_vec_p = _nss_status_vec_p();
return ((status_vec_p != NULL) ? *status_vec_p : (1 << NSS_UNAVAIL));
}
static void
output_loop_diag_a(int n,
char *dbase,
struct __nsw_lookup_v1 *lkp)
{
(void) fprintf(__nss_debug_file,
"NSS_retry(%d): '%s': trying '%s' ... ",
n, dbase, lkp->service_name);
(void) fflush(__nss_debug_file);
}
static void
output_loop_diag_b(nss_status_t res,
struct __nsw_lookup_v1 *lkp)
{
(void) fprintf(__nss_debug_file, "result=");
switch (res) {
case NSS_SUCCESS:
(void) fprintf(__nss_debug_file, "SUCCESS");
break;
case NSS_NOTFOUND:
(void) fprintf(__nss_debug_file, "NOTFOUND");
break;
case NSS_UNAVAIL:
(void) fprintf(__nss_debug_file, "UNAVAIL");
break;
case NSS_TRYAGAIN:
(void) fprintf(__nss_debug_file, "TRYAGAIN");
break;
case NSS_NISSERVDNS_TRYAGAIN:
(void) fprintf(__nss_debug_file, "NISSERVDNS_TRYAGAIN");
break;
default:
(void) fprintf(__nss_debug_file, "undefined");
}
(void) fprintf(__nss_debug_file, ", action=");
switch (lkp->actions[res]) {
case __NSW_CONTINUE:
(void) fprintf(__nss_debug_file, "CONTINUE");
break;
case __NSW_RETURN:
(void) fprintf(__nss_debug_file, "RETURN");
break;
case __NSW_TRYAGAIN_FOREVER:
(void) fprintf(__nss_debug_file, "TRYAGAIN_FOREVER");
break;
case __NSW_TRYAGAIN_NTIMES:
(void) fprintf(__nss_debug_file, "TRYAGAIN_NTIMES (N=%d)",
lkp->max_retries);
break;
case __NSW_TRYAGAIN_PAUSED:
(void) fprintf(__nss_debug_file, "TRYAGAIN_PAUSED");
break;
default:
(void) fprintf(__nss_debug_file, "undefined");
}
(void) fprintf(__nss_debug_file, "\n");
}
#define NSS_BACKOFF(n, b, t) \
((n) > ((b) + 3) ? t : (1 << ((n) - ((b) + 1))))
static int
retry_test(nss_status_t res, int n, struct __nsw_lookup_v1 *lkp)
{
if (res != NSS_TRYAGAIN && res != NSS_NISSERVDNS_TRYAGAIN) {
if (res == NSS_SUCCESS) {
__NSW_UNPAUSE_ACTION(lkp->actions[__NSW_TRYAGAIN]);
__NSW_UNPAUSE_ACTION(
lkp->actions[__NSW_NISSERVDNS_TRYAGAIN]);
}
return (0);
}
if ((res == NSS_TRYAGAIN &&
lkp->actions[__NSW_TRYAGAIN] == __NSW_TRYAGAIN_FOREVER) ||
(res == NSS_NISSERVDNS_TRYAGAIN &&
lkp->actions[__NSW_NISSERVDNS_TRYAGAIN] == __NSW_TRYAGAIN_FOREVER))
return (1);
if (res == NSS_TRYAGAIN &&
lkp->actions[__NSW_TRYAGAIN] == __NSW_TRYAGAIN_NTIMES)
if (n <= lkp->max_retries)
return (1);
else {
lkp->actions[__NSW_TRYAGAIN] = __NSW_TRYAGAIN_PAUSED;
return (0);
}
if (res == NSS_NISSERVDNS_TRYAGAIN &&
lkp->actions[__NSW_NISSERVDNS_TRYAGAIN] == __NSW_TRYAGAIN_NTIMES)
if (n <= lkp->max_retries)
return (1);
else {
lkp->actions[__NSW_NISSERVDNS_TRYAGAIN] =
__NSW_TRYAGAIN_PAUSED;
return (0);
}
return (0);
}
void
nss_delete(nss_db_root_t *rootp)
{
struct nss_db_state *s;
NSS_ROOTLOCK(rootp, &s);
if (s == 0) {
NSS_UNLOCK(rootp);
} else {
rootp->s = 0;
NSS_UNREF_UNLOCK(rootp, s);
}
}
nss_status_t
nss_search(nss_db_root_t *rootp, nss_db_initf_t initf, int search_fnum,
void *search_args)
{
nss_status_t res = NSS_UNAVAIL;
struct nss_db_state *s;
int n_src;
unsigned int *status_vec_p;
res = _nsc_search(rootp, initf, search_fnum, search_args);
if (res != NSS_TRYLOCAL)
return (res);
errno = 0;
res = NSS_UNAVAIL;
status_vec_p = _nss_status_vec_p();
if (status_vec_p == NULL) {
return (NSS_UNAVAIL);
}
*status_vec_p = 0;
NSS_LOCK_CHECK(rootp, initf, &s);
if (s == 0) {
NSS_UNLOCK(rootp);
return (res);
}
NSS_STATE_REF_u(s);
for (n_src = 0; n_src < s->max_src; n_src++) {
nss_backend_t *be;
nss_backend_op_t funcp;
res = NSS_UNAVAIL;
if ((be = nss_get_backend_u(&rootp, s, n_src)) != 0) {
if ((funcp = NSS_LOOKUP_DBOP(be, search_fnum)) != 0) {
int n_loop = 0;
int no_backoff = 19;
int max_backoff = 5;
do {
NSS_UNLOCK(rootp);
if (n_loop > no_backoff) {
if (__nss_debug_eng_loop > 1)
(void) fprintf(
__nss_debug_file,
"NSS: loop: "
"sleeping %d ...\n",
NSS_BACKOFF(n_loop,
no_backoff,
max_backoff));
(void) sleep(NSS_BACKOFF(n_loop,
no_backoff, max_backoff));
}
if (__nss_debug_eng_loop)
output_loop_diag_a(n_loop,
s->config->dbase,
s->src[n_src].lkp);
res = (*funcp)(be, search_args);
NSS_RELOCK(&rootp, s);
n_loop++;
if (__nss_debug_eng_loop)
output_loop_diag_b(res,
s->src[n_src].lkp);
} while (retry_test(res, n_loop,
s->src[n_src].lkp));
}
nss_put_backend_u(s, n_src, be);
}
*status_vec_p |= (1 << res);
if (__NSW_ACTION_V1(s->src[n_src].lkp, res) == __NSW_RETURN) {
if (__nss_debug_eng_loop)
(void) fprintf(__nss_debug_file,
"NSS: '%s': return.\n",
s->config->dbase);
break;
} else
if (__nss_debug_eng_loop)
(void) fprintf(__nss_debug_file,
"NSS: '%s': continue ...\n",
s->config->dbase);
}
NSS_UNREF_UNLOCK(rootp, s);
return (res);
}
struct nss_getent_context {
int n_src;
nss_backend_t *be;
struct nss_db_state *s;
nssuint_t cookie;
nssuint_t seq_num;
nssuint_t cookie_setent;
nss_db_params_t param;
};
static void nss_setent_u(nss_db_root_t *, nss_db_initf_t, nss_getent_t *);
static nss_status_t nss_getent_u(nss_db_root_t *, nss_db_initf_t,
nss_getent_t *, void *);
static void nss_endent_u(nss_db_root_t *, nss_db_initf_t, nss_getent_t *);
void
nss_setent(nss_db_root_t *rootp, nss_db_initf_t initf, nss_getent_t *contextpp)
{
if (contextpp == 0) {
return;
}
cancel_safe_mutex_lock(&contextpp->lock);
nss_setent_u(rootp, initf, contextpp);
cancel_safe_mutex_unlock(&contextpp->lock);
}
nss_status_t
nss_getent(nss_db_root_t *rootp, nss_db_initf_t initf, nss_getent_t *contextpp,
void *args)
{
nss_status_t status;
if (contextpp == 0) {
return (NSS_UNAVAIL);
}
cancel_safe_mutex_lock(&contextpp->lock);
status = nss_getent_u(rootp, initf, contextpp, args);
cancel_safe_mutex_unlock(&contextpp->lock);
return (status);
}
void
nss_endent(nss_db_root_t *rootp, nss_db_initf_t initf, nss_getent_t *contextpp)
{
if (contextpp == 0) {
return;
}
cancel_safe_mutex_lock(&contextpp->lock);
nss_endent_u(rootp, initf, contextpp);
cancel_safe_mutex_unlock(&contextpp->lock);
}
static void
end_iter_u(nss_db_root_t *rootp, struct nss_getent_context *contextp)
{
struct nss_db_state *s;
nss_backend_t *be;
int n_src;
s = contextp->s;
n_src = contextp->n_src;
be = contextp->be;
if (s != 0) {
if (n_src < s->max_src && be != 0) {
(void) NSS_INVOKE_DBOP(be, NSS_DBOP_ENDENT, 0);
NSS_RELOCK(&rootp, s);
nss_put_backend_u(s, n_src, be);
contextp->be = 0;
NSS_UNREF_UNLOCK(rootp, s);
}
contextp->s = 0;
}
}
static void
nss_setent_u(nss_db_root_t *rootp, nss_db_initf_t initf,
nss_getent_t *contextpp)
{
nss_status_t status;
struct nss_db_state *s;
struct nss_getent_context *contextp;
nss_backend_t *be;
int n_src;
if ((contextp = contextpp->ctx) == 0) {
if ((contextp = libc_malloc(sizeof (*contextp))) == 0) {
return;
}
contextpp->ctx = contextp;
contextp->cookie = NSCD_NEW_COOKIE;
contextp->seq_num = 0;
s = 0;
} else {
s = contextp->s;
if (contextp->cookie != NSCD_LOCAL_COOKIE)
contextp->cookie = NSCD_NEW_COOKIE;
}
if (contextp->cookie == NSCD_NEW_COOKIE) {
status = _nsc_setent_u(rootp, initf, contextpp);
if (status != NSS_TRYLOCAL)
return;
}
if (s == 0) {
NSS_LOCK_CHECK(rootp, initf, &s);
if (s == 0) {
NSS_UNLOCK(rootp);
contextpp->ctx = 0;
libc_free(contextp);
return;
}
NSS_STATE_REF_u(s);
contextp->s = s;
} else {
s = contextp->s;
n_src = contextp->n_src;
be = contextp->be;
if (n_src == 0 && be != 0) {
(void) NSS_INVOKE_DBOP(be, NSS_DBOP_SETENT, 0);
return;
}
if (n_src < s->max_src && be != 0) {
(void) NSS_INVOKE_DBOP(be, NSS_DBOP_ENDENT, 0);
NSS_RELOCK(&rootp, s);
nss_put_backend_u(s, n_src, be);
contextp->be = 0;
} else {
NSS_RELOCK(&rootp, s);
}
}
for (n_src = 0, be = 0; n_src < s->max_src &&
(be = nss_get_backend_u(&rootp, s, n_src)) == 0; n_src++) {
;
}
NSS_UNLOCK(rootp);
contextp->n_src = n_src;
contextp->be = be;
if (be == 0) {
nss_endent_u(rootp, initf, contextpp);
return;
}
(void) NSS_INVOKE_DBOP(be, NSS_DBOP_SETENT, 0);
}
static nss_status_t
nss_getent_u(nss_db_root_t *rootp, nss_db_initf_t initf,
nss_getent_t *contextpp, void *args)
{
nss_status_t status;
struct nss_db_state *s;
struct nss_getent_context *contextp;
int n_src;
nss_backend_t *be;
if ((contextp = contextpp->ctx) == 0) {
nss_setent_u(rootp, initf, contextpp);
if ((contextp = contextpp->ctx) == 0) {
return (NSS_UNAVAIL);
}
}
status = _nsc_getent_u(rootp, initf, contextpp, args);
if (status != NSS_TRYLOCAL)
return (status);
s = contextp->s;
n_src = contextp->n_src;
be = contextp->be;
if (s == 0) {
return (NSS_SUCCESS);
}
while (n_src < s->max_src) {
nss_status_t res;
if (be == 0) {
res = NSS_UNAVAIL;
} else {
res = NSS_INVOKE_DBOP(be, NSS_DBOP_GETENT, args);
}
if (__NSW_ACTION_V1(s->src[n_src].lkp, res) == __NSW_RETURN) {
if (res != __NSW_SUCCESS) {
end_iter_u(rootp, contextp);
}
return (res);
}
(void) NSS_INVOKE_DBOP(be, NSS_DBOP_ENDENT, 0);
NSS_RELOCK(&rootp, s);
nss_put_backend_u(s, n_src, be);
do {
n_src++;
} while (n_src < s->max_src &&
(be = nss_get_backend_u(&rootp, s, n_src)) == 0);
contextp->be = be;
if (be == 0) {
NSS_UNREF_UNLOCK(rootp, s);
contextp->s = 0;
break;
} else {
NSS_UNLOCK(rootp);
contextp->n_src = n_src;
(void) NSS_INVOKE_DBOP(be, NSS_DBOP_SETENT, 0);
}
}
end_iter_u(rootp, contextp);
return (NSS_SUCCESS);
}
static void
nss_endent_u(nss_db_root_t *rootp, nss_db_initf_t initf,
nss_getent_t *contextpp)
{
nss_status_t status;
struct nss_getent_context *contextp;
if ((contextp = contextpp->ctx) == 0) {
return;
}
status = _nsc_endent_u(rootp, initf, contextpp);
if (status != NSS_TRYLOCAL) {
libc_free(contextp);
contextpp->ctx = 0;
return;
}
end_iter_u(rootp, contextp);
libc_free(contextp);
contextpp->ctx = 0;
}
static nss_status_t
nss_pack_dbd(void *buffer, size_t bufsize, nss_db_params_t *p, size_t *poff)
{
nss_pheader_t *pbuf = (nss_pheader_t *)buffer;
nss_dbd_t *pdbd;
size_t off = *poff;
size_t len, blen;
size_t n, nc, dc;
char *bptr;
pbuf->dbd_off = (nssuint_t)off;
bptr = (char *)buffer + off;
blen = bufsize - off;
len = sizeof (nss_dbd_t);
n = nc = dc = 0;
if (p->name == NULL) {
errno = ERANGE;
return (NSS_ERROR);
}
if (p->default_config == NULL) {
p->default_config = "<NULL>";
p->flags = p->flags & ~NSS_USE_DEFAULT_CONFIG;
}
n = strlen(p->name) + 1;
dc = strlen(p->default_config) + 1;
if (n < 2 || dc < 2) {
errno = ERANGE;
return (NSS_ERROR);
}
if (p->config_name != NULL) {
nc = strlen(p->config_name) + 1;
}
if ((len + n + nc + dc) >= blen) {
errno = ERANGE;
return (NSS_ERROR);
}
pdbd = (nss_dbd_t *)((void *)bptr);
bptr += len;
pdbd->flags = p->flags;
pdbd->o_name = len;
(void) strlcpy(bptr, p->name, n);
len += n;
bptr += n;
if (nc == 0) {
pdbd->o_config_name = 0;
} else {
pdbd->o_config_name = len;
(void) strlcpy(bptr, p->config_name, nc);
bptr += nc;
len += nc;
}
pdbd->o_default_config = len;
(void) strlcpy(bptr, p->default_config, dc);
len += dc;
pbuf->dbd_len = (nssuint_t)len;
off += ROUND_UP(len, sizeof (nssuint_t));
*poff = off;
return (NSS_SUCCESS);
}
nss_status_t
nss_pack(void *buffer, size_t bufsize, nss_db_root_t *rootp __unused,
nss_db_initf_t initf, int search_fnum, void *search_args)
{
nss_pheader_t *pbuf = (nss_pheader_t *)buffer;
nss_XbyY_args_t *in = (nss_XbyY_args_t *)search_args;
nss_db_params_t tparam = { 0 };
nss_status_t ret = NSS_ERROR;
const char *dbn;
size_t blen, len, off = 0;
char *bptr;
struct nss_groupsbymem *gbm;
if (pbuf == NULL || in == NULL || initf == (nss_db_initf_t)NULL) {
errno = ERANGE;
return (ret);
}
tparam.cleanup = NULL;
(*initf)(&tparam);
if ((dbn = tparam.name) == 0) {
if (tparam.cleanup != 0)
(tparam.cleanup)(&tparam);
errno = ERANGE;
return (ret);
}
pbuf->pbufsiz = (nssuint_t)bufsize;
pbuf->p_ruid = (uint32_t)getuid();
pbuf->p_euid = (uint32_t)geteuid();
pbuf->p_version = NSCD_HEADER_REV;
pbuf->p_status = 0;
pbuf->p_errno = 0;
pbuf->p_herrno = 0;
if (strcmp(dbn, NSS_DBNAM_AUTHATTR) == 0 && in->h_errno != 0)
pbuf->p_herrno = (uint32_t)in->h_errno;
pbuf->libpriv = 0;
off = sizeof (nss_pheader_t);
pbuf->nss_dbop = (uint32_t)search_fnum;
ret = nss_pack_dbd(buffer, bufsize, &tparam, &off);
if (ret != NSS_SUCCESS) {
errno = ERANGE;
return (ret);
}
ret = NSS_ERROR;
pbuf->key_off = (nssuint_t)off;
bptr = (char *)buffer + off;
blen = bufsize - off;
if (strcmp(dbn, NSS_DBNAM_NETGROUP) == 0) {
if (search_fnum == NSS_DBOP_NETGROUP_SET) {
errno = 0;
return (NSS_TRYLOCAL);
}
ret = nss_default_key2str(bptr, blen, in, dbn,
search_fnum, &len);
} else if (in->key2str == NULL ||
(search_fnum == NSS_DBOP_GROUP_BYMEMBER &&
strcmp(dbn, NSS_DBNAM_GROUP) == 0)) {
ret = nss_default_key2str(bptr, blen, in, dbn,
search_fnum, &len);
} else {
ret = (*in->key2str)(bptr, blen, &in->key, &len);
}
if (tparam.cleanup != 0)
(tparam.cleanup)(&tparam);
if (ret != NSS_SUCCESS) {
errno = ERANGE;
return (ret);
}
pbuf->key_len = (nssuint_t)len;
off += ROUND_UP(len, sizeof (nssuint_t));
pbuf->data_off = (nssuint_t)off;
pbuf->data_len = (nssuint_t)(bufsize - off);
gbm = (struct nss_groupsbymem *)search_args;
if (search_fnum == NSS_DBOP_GROUP_BYMEMBER &&
strcmp(dbn, NSS_DBNAM_GROUP) == 0 && gbm->numgids == 1) {
gid_t *gidp;
gidp = (gid_t *)((void *)((char *)buffer + off));
*gidp = gbm->gid_array[0];
}
errno = 0;
return (NSS_SUCCESS);
}
nss_status_t
nss_pack_ent(void *buffer, size_t bufsize, nss_db_root_t *rootp __unused,
nss_db_initf_t initf, nss_getent_t *contextpp)
{
nss_pheader_t *pbuf = (nss_pheader_t *)buffer;
struct nss_getent_context *contextp = contextpp->ctx;
nss_status_t ret = NSS_ERROR;
size_t blen, len = 0, off = 0;
char *bptr;
nssuint_t *nptr;
if (pbuf == NULL || initf == (nss_db_initf_t)NULL) {
errno = ERANGE;
return (ret);
}
pbuf->pbufsiz = (nssuint_t)bufsize;
pbuf->p_ruid = (uint32_t)getuid();
pbuf->p_euid = (uint32_t)geteuid();
pbuf->p_version = NSCD_HEADER_REV;
pbuf->p_status = 0;
pbuf->p_errno = 0;
pbuf->p_herrno = 0;
pbuf->libpriv = 0;
off = sizeof (nss_pheader_t);
pbuf->nss_dbop = (uint32_t)0;
ret = nss_pack_dbd(buffer, bufsize, &contextp->param, &off);
if (ret != NSS_SUCCESS) {
errno = ERANGE;
return (ret);
}
ret = NSS_ERROR;
off += ROUND_UP(len, sizeof (nssuint_t));
pbuf->key_off = (nssuint_t)off;
bptr = (char *)buffer + off;
blen = bufsize - off;
len = (size_t)(sizeof (nssuint_t) * 2);
if (len >= blen) {
errno = ERANGE;
return (ret);
}
nptr = (nssuint_t *)((void *)bptr);
*nptr++ = contextp->cookie;
*nptr = contextp->seq_num;
pbuf->key_len = (nssuint_t)len;
off += len;
pbuf->data_off = (nssuint_t)off;
pbuf->data_len = (nssuint_t)(bufsize - off);
return (NSS_SUCCESS);
}
nss_status_t
nss_unpack(void *buffer, size_t bufsize __unused, nss_db_root_t *rootp __unused,
nss_db_initf_t initf __unused, int search_fnum, void *search_args)
{
nss_pheader_t *pbuf = (nss_pheader_t *)buffer;
nss_XbyY_args_t *in = (nss_XbyY_args_t *)search_args;
nss_dbd_t *pdbd;
char *dbn;
nss_status_t status;
char *buf;
int len;
int ret;
int i;
int fmt_type;
gid_t *gidp;
gid_t *gptr;
struct nss_groupsbymem *arg;
if (pbuf == NULL || in == NULL)
return (-1);
status = pbuf->p_status;
pdbd = (nss_dbd_t *)((void *)((char *)buffer + pbuf->dbd_off));
dbn = (char *)pdbd + pdbd->o_name;
fmt_type = 0;
if (search_fnum == NSS_DBOP_GROUP_BYMEMBER &&
strcmp(dbn, NSS_DBNAM_GROUP) == 0)
fmt_type = 1;
else if (search_fnum == NSS_DBOP_NETGROUP_IN &&
strcmp(dbn, NSS_DBNAM_NETGROUP) == 0)
fmt_type = 2;
if (status != NSS_SUCCESS) {
if (fmt_type == 0) {
in->h_errno = (int)pbuf->p_herrno;
if (pbuf->p_errno == ERANGE)
in->erange = 1;
}
return (status);
}
if (pbuf->data_off == 0 || pbuf->data_len == 0)
return (NSS_NOTFOUND);
buf = (char *)buffer + pbuf->data_off;
len = pbuf->data_len;
if (fmt_type == 1) {
arg = (struct nss_groupsbymem *)in;
i = len / sizeof (gid_t);
if (i > arg->maxgids) {
i = arg->maxgids;
}
arg->numgids = i;
gidp = arg->gid_array;
gptr = (gid_t *)((void *)buf);
(void) memcpy(gidp, gptr, len);
return (NSS_SUCCESS);
}
if (fmt_type == 2) {
struct nss_innetgr_args *arg = (struct nss_innetgr_args *)in;
if (pbuf->p_status == NSS_SUCCESS) {
arg->status = NSS_NETGR_FOUND;
return (NSS_SUCCESS);
} else {
arg->status = NSS_NETGR_NO;
return (NSS_NOTFOUND);
}
}
ret = (*in->str2ent)(buf, len, in->buf.result, in->buf.buffer,
in->buf.buflen);
if (ret == NSS_STR_PARSE_ERANGE) {
in->returnval = 0;
in->returnlen = 0;
in->erange = 1;
ret = NSS_NOTFOUND;
} else if (ret == NSS_STR_PARSE_SUCCESS) {
in->returnval = in->buf.result;
in->returnlen = len;
ret = NSS_SUCCESS;
}
in->h_errno = (int)pbuf->p_herrno;
return ((nss_status_t)ret);
}
nss_status_t
nss_unpack_ent(void *buffer, size_t bufsize __unused,
nss_db_root_t *rootp __unused, nss_db_initf_t initf __unused,
nss_getent_t *contextpp, void *args)
{
nss_pheader_t *pbuf = (nss_pheader_t *)buffer;
nss_XbyY_args_t *in = (nss_XbyY_args_t *)args;
struct nss_getent_context *contextp = contextpp->ctx;
nssuint_t *nptr;
nssuint_t cookie;
nss_status_t status;
char *buf;
int len;
int ret;
if (pbuf == NULL)
return (-1);
status = pbuf->p_status;
if (status != NSS_SUCCESS)
return (status);
if (pbuf->key_off == 0 ||
pbuf->key_len != (sizeof (nssuint_t) * 2))
return (NSS_NOTFOUND);
nptr = (nssuint_t *)((void *)((char *)buffer + pbuf->key_off));
cookie = contextp->cookie;
if (cookie != NSCD_NEW_COOKIE && cookie != contextp->cookie_setent &&
cookie != *nptr) {
return (NSS_NOTFOUND);
}
contextp->cookie = *nptr++;
contextp->seq_num = *nptr;
if (args == NULL)
return (NSS_SUCCESS);
if (pbuf->data_off == 0 || pbuf->data_len == 0)
return (NSS_NOTFOUND);
buf = (char *)buffer + pbuf->data_off;
len = pbuf->data_len;
ret = (*in->str2ent)(buf, len, in->buf.result, in->buf.buffer,
in->buf.buflen);
if (ret == NSS_STR_PARSE_ERANGE) {
in->returnval = 0;
in->returnlen = 0;
in->erange = 1;
} else if (ret == NSS_STR_PARSE_SUCCESS) {
in->returnval = in->buf.result;
in->returnlen = len;
}
in->h_errno = (int)pbuf->p_herrno;
return ((nss_status_t)ret);
}
nss_status_t
_nsc_search(nss_db_root_t *rootp, nss_db_initf_t initf, int search_fnum,
void *search_args)
{
nss_pheader_t *pbuf;
void *doorptr = NULL;
size_t bufsize = 0;
size_t datasize = 0;
nss_status_t status;
if (_nsc_proc_is_cache() > 0) {
return (NSS_TRYLOCAL);
}
if (search_args == NULL)
return (NSS_NOTFOUND);
bufsize = ((nss_XbyY_args_t *)search_args)->buf.buflen;
if (_nsc_getdoorbuf(&doorptr, &bufsize) != 0)
return (NSS_TRYLOCAL);
if (doorptr == NULL || bufsize == 0)
return (NSS_TRYLOCAL);
pbuf = (nss_pheader_t *)doorptr;
pbuf->nsc_callnumber = NSCD_SEARCH;
status = nss_pack((void *)pbuf, bufsize, rootp,
initf, search_fnum, search_args);
if (status != NSS_SUCCESS)
return (status);
datasize = pbuf->data_off;
status = _nsc_trydoorcall_ext(&doorptr, &bufsize, &datasize);
if (status != NSS_SUCCESS) {
if (doorptr != (void *)pbuf) {
_nsc_resizedoorbuf(bufsize);
(void) munmap((void *)doorptr, bufsize);
}
return (NSS_TRYLOCAL);
}
status = nss_unpack((void *)doorptr, bufsize, rootp, initf,
search_fnum, search_args);
if (doorptr != (void *)pbuf) {
_nsc_resizedoorbuf(bufsize);
(void) munmap((void *)doorptr, bufsize);
}
return (status);
}
nss_status_t
_nsc_setent_u(nss_db_root_t *rootp, nss_db_initf_t initf,
nss_getent_t *contextpp)
{
nss_status_t status = NSS_TRYLOCAL;
struct nss_getent_context *contextp = contextpp->ctx;
nss_pheader_t *pbuf;
void *doorptr = NULL;
size_t bufsize = 0;
size_t datasize = 0;
if (contextp->cookie == NSCD_LOCAL_COOKIE)
return (NSS_TRYLOCAL);
if (_nsc_proc_is_cache() > 0) {
contextp->cookie = NSCD_LOCAL_COOKIE;
return (NSS_TRYLOCAL);
}
if (_nsc_getdoorbuf(&doorptr, &bufsize) != 0) {
contextp->cookie = NSCD_LOCAL_COOKIE;
return (NSS_TRYLOCAL);
}
if (doorptr == NULL || bufsize == 0) {
contextp->cookie = NSCD_LOCAL_COOKIE;
return (NSS_TRYLOCAL);
}
pbuf = (nss_pheader_t *)doorptr;
pbuf->nsc_callnumber = NSCD_SETENT;
contextp->param.cleanup = NULL;
(*initf)(&contextp->param);
if (contextp->param.name == 0) {
if (contextp->param.cleanup != 0)
(contextp->param.cleanup)(&contextp->param);
errno = ERANGE;
return (NSS_ERROR);
}
status = nss_pack_ent((void *)pbuf, bufsize, rootp, initf, contextpp);
if (status != NSS_SUCCESS)
return (status);
datasize = pbuf->data_off;
status = _nsc_trydoorcall_ext(&doorptr, &bufsize, &datasize);
if (status != NSS_SUCCESS) {
if (contextp->cookie == NSCD_NEW_COOKIE) {
contextp->cookie = NSCD_LOCAL_COOKIE;
return (NSS_TRYLOCAL);
}
return (NSS_UNAVAIL);
}
status = nss_unpack_ent((void *)doorptr, bufsize, rootp,
initf, contextpp, NULL);
contextp->cookie_setent = contextp->cookie;
if (doorptr != (void *)pbuf) {
_nsc_resizedoorbuf(bufsize);
(void) munmap((void *)doorptr, bufsize);
}
return (status);
}
nss_status_t
_nsc_getent_u(nss_db_root_t *rootp, nss_db_initf_t initf,
nss_getent_t *contextpp, void *args)
{
nss_status_t status = NSS_TRYLOCAL;
struct nss_getent_context *contextp = contextpp->ctx;
nss_pheader_t *pbuf;
void *doorptr = NULL;
size_t bufsize = 0;
size_t datasize = 0;
if (contextp->cookie == NSCD_LOCAL_COOKIE)
return (NSS_TRYLOCAL);
if (args == NULL)
return (NSS_NOTFOUND);
bufsize = ((nss_XbyY_args_t *)args)->buf.buflen;
if (_nsc_getdoorbuf(&doorptr, &bufsize) != 0)
return (NSS_UNAVAIL);
if (doorptr == NULL || bufsize == 0)
return (NSS_UNAVAIL);
pbuf = (nss_pheader_t *)doorptr;
pbuf->nsc_callnumber = NSCD_GETENT;
status = nss_pack_ent((void *)pbuf, bufsize, rootp, initf, contextpp);
if (status != NSS_SUCCESS)
return (status);
datasize = pbuf->data_off;
status = _nsc_trydoorcall_ext(&doorptr, &bufsize, &datasize);
if (status != NSS_SUCCESS) {
if (status == NSS_TRYLOCAL ||
contextp->cookie == NSCD_NEW_COOKIE) {
contextp->cookie = NSCD_LOCAL_COOKIE;
nss_setent_u(rootp, initf, contextpp);
if (contextpp->ctx == 0)
return (NSS_UNAVAIL);
return (NSS_TRYLOCAL);
}
return (NSS_UNAVAIL);
}
status = nss_unpack_ent((void *)doorptr, bufsize, rootp,
initf, contextpp, args);
if (doorptr != (void *)pbuf) {
_nsc_resizedoorbuf(bufsize);
(void) munmap((void *)doorptr, bufsize);
}
return (status);
}
nss_status_t
_nsc_endent_u(nss_db_root_t *rootp, nss_db_initf_t initf,
nss_getent_t *contextpp)
{
nss_status_t status = NSS_TRYLOCAL;
struct nss_getent_context *contextp = contextpp->ctx;
nss_pheader_t *pbuf;
void *doorptr = NULL;
size_t bufsize = 0;
size_t datasize = 0;
if (contextp->cookie == NSCD_LOCAL_COOKIE)
return (NSS_TRYLOCAL);
if (_nsc_getdoorbuf(&doorptr, &bufsize) != 0)
return (NSS_UNAVAIL);
if (doorptr == NULL || bufsize == 0)
return (NSS_UNAVAIL);
pbuf = (nss_pheader_t *)doorptr;
pbuf->nsc_callnumber = NSCD_ENDENT;
status = nss_pack_ent((void *)pbuf, bufsize, rootp, initf, contextpp);
if (status != NSS_SUCCESS)
return (status);
datasize = pbuf->data_off;
(void) _nsc_trydoorcall_ext(&doorptr, &bufsize, &datasize);
if (doorptr != (void *)pbuf) {
_nsc_resizedoorbuf(bufsize);
(void) munmap((void *)doorptr, bufsize);
}
if (contextp->param.cleanup != 0)
(contextp->param.cleanup)(&contextp->param);
contextp->param.cleanup = NULL;
contextp->cookie = NSCD_NEW_COOKIE;
return (NSS_SUCCESS);
}
size_t
_nss_get_bufsizes(int arg)
{
switch (arg) {
case _SC_GETGR_R_SIZE_MAX:
return (__nss_buflen_group);
}
return (__nss_buflen_default);
}
void *
_nss_XbyY_fini(nss_XbyY_args_t *args)
{
if ((args->returnval == NULL) && (args->erange != 0))
errno = ERANGE;
return (args->returnval);
}