#include "nis_common.h"
#include <string.h>
#include <synch.h>
#include <rpcsvc/ypclnt.h>
#include <rpcsvc/yp_prot.h>
#include <thread.h>
#include <ctype.h>
#include <stdlib.h>
#include <signal.h>
#ifndef MT_UNSAFE_YP
#define MT_UNSAFE_YP 0
#endif
#if MT_UNSAFE_YP
static mutex_t one_lane = DEFAULTMUTEX;
#endif
typedef char *grrr;
static nss_status_t
switch_err(ypstatus, ismatch)
int ypstatus;
int ismatch;
{
switch (ypstatus) {
case 0:
errno = 0;
return (NSS_SUCCESS);
case YPERR_BADARGS:
case YPERR_KEY:
errno = 0;
return (NSS_NOTFOUND);
case YPERR_NOMORE:
if (ismatch)
return (NSS_NISSERVDNS_TRYAGAIN);
else
return (NSS_NOTFOUND);
case YPERR_DOMAIN:
case YPERR_YPSERV:
case YPERR_BUSY:
return (NSS_TRYAGAIN);
default:
return (NSS_UNAVAIL);
}
}
nss_status_t
_nss_nis_setent(be, dummy)
nis_backend_ptr_t be;
void *dummy;
{
if (be->enum_key != 0) {
free(be->enum_key);
be->enum_key = 0;
}
be->enum_keylen = 0;
return (NSS_SUCCESS);
}
nss_status_t
_nss_nis_endent(be, dummy)
nis_backend_ptr_t be;
void *dummy;
{
return (_nss_nis_setent(be, dummy));
}
void
massage_netdb(const char **valp, int *vallenp)
{
const char *first;
const char *last;
const char *val = *valp;
int vallen = *vallenp;
if ((last = memchr(val, '#', vallen)) == 0) {
last = val + vallen;
}
for (first = val; first < last && isspace(*first); first++) {
;
}
for (; first < last && isspace(last[-1]); last--) {
;
}
*valp = first;
*vallenp = (int)(last - first);
}
nss_status_t
_nss_nis_ypmatch(domain, map, key, valp, vallenp, ypstatusp)
const char *domain;
const char *map;
const char *key;
char **valp;
int *vallenp;
int *ypstatusp;
{
int ypstatus;
#if MT_UNSAFE_YP
sigset_t oldmask, newmask;
(void) sigfillset(&newmask);
(void) thr_sigsetmask(SIG_SETMASK, &newmask, &oldmask);
(void) mutex_lock(&one_lane);
#endif
ypstatus = __yp_match_cflookup((grrr)domain, (grrr)map,
(grrr)key, (int)strlen(key), valp, vallenp, 0);
#if MT_UNSAFE_YP
(void) mutex_unlock(&one_lane);
(void) thr_sigsetmask(SIG_SETMASK, &oldmask, NULL);
#endif
if (ypstatusp != 0) {
*ypstatusp = ypstatus;
}
return (switch_err(ypstatus, 1));
}
static nss_status_t
_nss_nis_ypmatch_rsvdport(domain, map, key, valp, vallenp, ypstatusp)
const char *domain;
const char *map;
const char *key;
char **valp;
int *vallenp;
int *ypstatusp;
{
int ypstatus;
#if MT_UNSAFE_YP
sigset_t oldmask, newmask;
(void) sigfillset(&newmask);
(void) thr_sigsetmask(SIG_SETMASK, &newmask, &oldmask);
(void) mutex_lock(&one_lane);
#endif
ypstatus = __yp_match_rsvdport_cflookup((grrr)domain, (grrr)map,
(grrr)key, strlen(key), valp, vallenp, 0);
#if MT_UNSAFE_YP
(void) mutex_unlock(&one_lane);
(void) thr_sigsetmask(SIG_SETMASK, &oldmask, NULL);
#endif
if (ypstatusp != 0) {
*ypstatusp = ypstatus;
}
return (switch_err(ypstatus, 1));
}
nss_status_t
_nss_nis_lookup(be, args, netdb, map, key, ypstatusp)
nis_backend_ptr_t be;
nss_XbyY_args_t *args;
int netdb;
const char *map;
const char *key;
int *ypstatusp;
{
nss_status_t res;
int vallen;
char *val;
char *free_ptr;
int parsestat;
if ((res = _nss_nis_ypmatch(be->domain, map, key, &val, &vallen,
ypstatusp)) != NSS_SUCCESS) {
return (res);
}
parsestat = NSS_STR_PARSE_SUCCESS;
if (strcmp(map, "passwd.byname") == 0 ||
strcmp(map, "passwd.byuid") == 0) {
parsestat = validate_passwd_ids(&val, &vallen, 1);
} else if (strcmp(map, "group.byname") == 0)
parsestat = validate_group_ids(&val, &vallen, 1);
if (parsestat != NSS_STR_PARSE_SUCCESS) {
free(val);
return (NSS_NOTFOUND);
}
free_ptr = val;
if (netdb) {
massage_netdb((const char **)&val, &vallen);
}
args->returnval = NULL;
args->returnlen = 0;
parsestat = (*args->str2ent)(val, vallen,
args->buf.result, args->buf.buffer, args->buf.buflen);
if (parsestat == NSS_STR_PARSE_SUCCESS) {
args->returnval = args->buf.result;
args->returnlen = vallen;
res = NSS_SUCCESS;
} else if (parsestat == NSS_STR_PARSE_ERANGE) {
args->erange = 1;
res = NSS_NOTFOUND;
}
free(free_ptr);
return (res);
}
nss_status_t
_nss_nis_lookup_rsvdport(be, args, netdb, map, key, ypstatusp)
nis_backend_ptr_t be;
nss_XbyY_args_t *args;
int netdb;
const char *map;
const char *key;
int *ypstatusp;
{
nss_status_t res;
int vallen;
char *val;
char *free_ptr;
int parsestat;
if ((res = _nss_nis_ypmatch_rsvdport(be->domain, map, key, &val,
&vallen, ypstatusp)) != NSS_SUCCESS) {
return (res);
}
free_ptr = val;
if (netdb) {
massage_netdb((const char **)&val, &vallen);
}
args->returnval = NULL;
args->returnlen = 0;
parsestat = (*args->str2ent)(val, vallen,
args->buf.result, args->buf.buffer, args->buf.buflen);
if (parsestat == NSS_STR_PARSE_SUCCESS) {
args->returnval = args->buf.result;
args->returnlen = vallen;
res = NSS_SUCCESS;
} else if (parsestat == NSS_STR_PARSE_ERANGE) {
args->erange = 1;
res = NSS_NOTFOUND;
}
free(free_ptr);
return (res);
}
static nss_status_t
do_getent(be, args, netdb)
nis_backend_ptr_t be;
nss_XbyY_args_t *args;
int netdb;
{
nss_status_t res;
int ypstatus;
int outkeylen, outvallen;
char *outkey, *outval;
char *free_ptr;
int parsestat;
#if MT_UNSAFE_YP
sigset_t oldmask, newmask;
(void) sigfillset(&newmask);
(void) thr_sigsetmask(SIG_SETMASK, &newmask, &oldmask);
(void) mutex_lock(&one_lane);
#endif
if (be->enum_key == 0) {
ypstatus = __yp_first_cflookup((grrr)be->domain,
(grrr)be->enum_map, &outkey,
&outkeylen, &outval,
&outvallen, 0);
} else {
ypstatus = __yp_next_cflookup((grrr)be->domain,
(grrr)be->enum_map, be->enum_key,
be->enum_keylen, &outkey,
&outkeylen, &outval,
&outvallen, 0);
}
#if MT_UNSAFE_YP
(void) mutex_unlock(&one_lane);
(void) thr_sigsetmask(SIG_SETMASK, &oldmask, NULL);
#endif
if ((res = switch_err(ypstatus, 0)) != NSS_SUCCESS) {
return (res);
}
free_ptr = outval;
if (netdb) {
massage_netdb((const char **)&outval, &outvallen);
}
args->returnval = NULL;
args->returnlen = 0;
parsestat = (*args->str2ent)(outval, outvallen,
args->buf.result, args->buf.buffer, args->buf.buflen);
if (parsestat == NSS_STR_PARSE_SUCCESS) {
args->returnval = args->buf.result;
args->returnlen = outvallen;
res = NSS_SUCCESS;
} else if (parsestat == NSS_STR_PARSE_ERANGE) {
args->erange = 1;
res = NSS_NOTFOUND;
}
free(free_ptr);
if (be->enum_key != 0) {
free(be->enum_key);
}
be->enum_key = outkey;
be->enum_keylen = outkeylen;
return (res);
}
nss_status_t
_nss_nis_getent_rigid(be, args)
nis_backend_ptr_t be;
void *args;
{
return (do_getent(be, (nss_XbyY_args_t *)args, 0));
}
nss_status_t
_nss_nis_getent_netdb(be, args)
nis_backend_ptr_t be;
void *args;
{
return (do_getent(be, (nss_XbyY_args_t *)args, 1));
}
struct cb_data {
void *args;
const char *filter;
nis_do_all_func_t func;
nss_status_t result;
};
enum { ITER_NEXT = 0, ITER_STOP = 1 };
static int
do_cback(instatus, inkey, inkeylen, inval, invallen, indata)
int instatus;
const char *inkey;
int inkeylen;
const char *inval;
int invallen;
struct cb_data *indata;
{
nss_status_t res;
if (instatus != YP_TRUE) {
return (ITER_NEXT);
}
if (indata->filter != 0 && strstr(inval, indata->filter) == 0) {
return (ITER_NEXT);
}
res = (*indata->func)(inval, invallen, indata->args);
if (res == NSS_NOTFOUND) {
return (ITER_NEXT);
} else {
indata->result = res;
return (ITER_STOP);
}
}
nss_status_t
_nss_nis_do_all(be, args, filter, func)
nis_backend_ptr_t be;
void *args;
const char *filter;
nis_do_all_func_t func;
{
int ypall_status;
struct cb_data data;
struct ypall_callback cback;
data.args = args;
data.filter = filter;
data.func = func;
data.result = NSS_NOTFOUND;
cback.foreach = do_cback;
cback.data = (char *)&data;
#if MT_UNSAFE_YP
sigset_t oldmask, newmask;
(void) sigfillset(&newmask);
(void) thr_sigsetmask(SIG_SETMASK, &newmask, &oldmask);
(void) mutex_lock(&one_lane);
#endif
ypall_status = __yp_all_cflookup((grrr)be->domain,
(grrr) be->enum_map, &cback, 0);
#if MT_UNSAFE_YP
(void) mutex_unlock(&one_lane);
(void) thr_sigsetmask(SIG_SETMASK, &oldmask, NULL);
#endif
switch (ypall_status) {
case 0:
return (data.result);
case YPERR_DOMAIN:
case YPERR_YPSERV:
case YPERR_BUSY:
return (NSS_TRYAGAIN);
default:
return (NSS_UNAVAIL);
}
}
struct XbyY_data {
nss_XbyY_args_t *args;
nis_XY_check_func func;
int netdb;
};
static nss_status_t
XbyY_iterator(instr, instr_len, a)
const char *instr;
int instr_len;
void *a;
{
struct XbyY_data *xydata = (struct XbyY_data *)a;
nss_XbyY_args_t *args = xydata->args;
nss_status_t res;
int parsestat;
if (xydata->netdb) {
massage_netdb(&instr, &instr_len);
}
args->returnval = NULL;
args->returnlen = 0;
parsestat = (*args->str2ent)(instr, instr_len,
args->buf.result, args->buf.buffer, args->buf.buflen);
if (parsestat == NSS_STR_PARSE_SUCCESS) {
args->returnval = args->buf.result;
if ((*xydata->func)(args)) {
res = NSS_SUCCESS;
args->returnlen = instr_len;
} else {
res = NSS_NOTFOUND;
args->returnval = 0;
}
} else if (parsestat == NSS_STR_PARSE_ERANGE) {
args->erange = 1;
res = NSS_NOTFOUND;
}
return (res);
}
nss_status_t
_nss_nis_XY_all(be, args, netdb, filter, func)
nis_backend_ptr_t be;
nss_XbyY_args_t *args;
int netdb;
const char *filter;
nis_XY_check_func func;
{
struct XbyY_data data;
data.args = args;
data.func = func;
data.netdb = netdb;
return (_nss_nis_do_all(be, &data, filter, XbyY_iterator));
}
nss_status_t
_nss_nis_destr(be, dummy)
nis_backend_ptr_t be;
void *dummy;
{
if (be != 0) {
(void) _nss_nis_endent(be, 0);
free(be);
}
return (NSS_SUCCESS);
}
static mutex_t yp_domain_lock = DEFAULTMUTEX;
static char *yp_domain;
const char *
_nss_nis_domain()
{
char *domain;
sigset_t oldmask, newmask;
(void) sigfillset(&newmask);
(void) thr_sigsetmask(SIG_SETMASK, &newmask, &oldmask);
(void) mutex_lock(&yp_domain_lock);
if ((domain = yp_domain) == 0) {
#if MT_UNSAFE_YP
(void) mutex_lock(&one_lane);
#endif
if (yp_get_default_domain(&yp_domain) == 0) {
domain = yp_domain;
}
#if MT_UNSAFE_YP
(void) mutex_unlock(&one_lane);
#endif
}
(void) mutex_unlock(&yp_domain_lock);
(void) thr_sigsetmask(SIG_SETMASK, &oldmask, NULL);
return (domain);
}
nss_backend_t *
_nss_nis_constr(ops, n_ops, enum_map)
nis_backend_op_t ops[];
int n_ops;
const char *enum_map;
{
const char *domain;
nis_backend_ptr_t be;
if ((domain = _nss_nis_domain()) == 0 ||
(be = (nis_backend_ptr_t)malloc(sizeof (*be))) == 0) {
return (0);
}
be->ops = ops;
be->n_ops = n_ops;
be->domain = domain;
be->enum_map = enum_map;
be->enum_key = 0;
be->enum_keylen = 0;
return ((nss_backend_t *)be);
}
int
_nss_nis_check_name_aliases(nss_XbyY_args_t *argp, const char *line,
int linelen)
{
const char *limit, *linep, *keyp;
linep = line;
limit = line + linelen;
keyp = argp->key.name;
while (*keyp && linep < limit && !isspace(*linep) && *keyp == *linep) {
keyp++;
linep++;
}
if (*keyp == '\0' && linep < limit && isspace(*linep))
return (1);
while (linep < limit && !isspace(*linep))
linep++;
while (linep < limit && isspace(*linep))
linep++;
while (linep < limit) {
while (linep < limit && !isspace(*linep))
linep++;
while (linep < limit && isspace(*linep))
linep++;
keyp = argp->key.name;
while (*keyp && linep < limit && !isspace(*linep) &&
*keyp == *linep) {
keyp++;
linep++;
}
if (*keyp == '\0' && (linep == limit || isspace(*linep)))
return (1);
}
return (0);
}