ns_nis.c revision 7c478bd95313f5f23a4c958a745db2134aa03244
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (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
*/
/*
* ns_nis.c
*
* Copyright 2004 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <syslog.h>
#include <string.h>
#include <ctype.h>
#include <nsswitch.h>
#include <sys/param.h>
#include <sys/types.h>
#include <sys/systeminfo.h>
#include <rpc/rpc.h>
#include <rpcsvc/nfs_prot.h>
#include <rpcsvc/ypclnt.h>
#include <rpcsvc/yp_prot.h>
#include <sys/errno.h>
#include "automount.h"
#define KEY 0
#define CONTENTS 1
static int replace_undscr_by_dot(char *);
static int nis_err(int);
static char nis_mydomain[YPMAXDOMAIN];
struct dir_cbdata {
struct dir_entry **list;
struct dir_entry *last;
int error;
};
static int readdir_callback(int, char *, int, const char *,
int, struct dir_cbdata *);
void
init_nis(char **stack, char ***stkptr)
{
#ifdef lint
stack = stack;
stkptr = stkptr;
#endif /* lint */
(void) sysinfo(SI_SRPC_DOMAIN, nis_mydomain, sizeof (nis_mydomain));
(void) __nis_reset_state(); /* XXX temporary hack for csh bug */
}
/*ARGSUSED*/
int
getmapent_nis(key, map, ml, stack, stkptr, iswildcard, isrestricted)
char *key, *map;
struct mapline *ml;
char **stack;
char ***stkptr;
bool_t *iswildcard;
bool_t isrestricted;
{
char *nisline = NULL;
char *my_map = NULL;
char *lp, *lq;
int nislen, len;
int nserr;
if (iswildcard)
*iswildcard = FALSE;
nserr = yp_match(nis_mydomain, map, key, strlen(key),
&nisline, &nislen);
if (nserr == YPERR_MAP) {
my_map = strdup(map);
if (my_map == NULL) {
syslog(LOG_ERR,
"getmapent_nis: memory alloc failed: %m");
return (__NSW_UNAVAIL);
}
if (replace_undscr_by_dot(my_map))
nserr = yp_match(nis_mydomain, my_map, key,
strlen(key), &nisline, &nislen);
}
if (nserr) {
if (nserr == YPERR_KEY) {
/*
* Try the default entry "*"
*/
if (my_map == NULL)
nserr = yp_match(nis_mydomain, map, "*", 1,
&nisline, &nislen);
else
nserr = yp_match(nis_mydomain, my_map, "*", 1,
&nisline, &nislen);
if (!nserr && iswildcard)
*iswildcard = TRUE;
} else {
if (verbose)
syslog(LOG_ERR, "%s: %s",
map, yperr_string(nserr));
nserr = 1;
}
}
if (my_map != NULL)
free(my_map);
nserr = nis_err(nserr);
if (nserr)
goto done;
/*
* at this point we are sure that yp_match succeeded
* so massage the entry by
* 1. ignoring # and beyond
* 2. trim the trailing whitespace
*/
if (lp = strchr(nisline, '#'))
*lp = '\0';
len = strlen(nisline);
if (len == 0) {
nserr = __NSW_NOTFOUND;
goto done;
}
lp = &nisline[len - 1];
while (lp > nisline && isspace(*lp))
*lp-- = '\0';
if (lp == nisline) {
nserr = __NSW_NOTFOUND;
goto done;
}
(void) strcpy(ml->linebuf, nisline);
lp = ml->linebuf;
lq = ml->lineqbuf;
unquote(lp, lq);
/* now we have the correct line */
nserr = __NSW_SUCCESS;
done:
if (nisline)
free((char *)nisline);
return (nserr);
}
loadmaster_nis(mapname, defopts, stack, stkptr)
char *mapname, *defopts;
char **stack;
char ***stkptr;
{
int first, err;
char *key, *nkey, *val;
int kl, nkl, vl;
char dir[256], map[256], qbuff[256];
char *pmap, *opts, *my_mapname;
int count = 0;
first = 1;
key = NULL; kl = 0;
nkey = NULL; nkl = 0;
val = NULL; vl = 0;
/*
* need a private copy of mapname, because we may change
* the underscores by dots. We however do not want the
* orignal to be changed, as we may want to use the
* original name in some other name service
*/
my_mapname = strdup(mapname);
if (my_mapname == NULL) {
syslog(LOG_ERR, "loadmaster_yp: memory alloc failed: %m");
/* not the name svc's fault but ... */
return (__NSW_UNAVAIL);
}
for (;;) {
if (first) {
first = 0;
err = yp_first(nis_mydomain, my_mapname,
&nkey, &nkl, &val, &vl);
if ((err == YPERR_MAP) &&
(replace_undscr_by_dot(my_mapname)))
err = yp_first(nis_mydomain, my_mapname,
&nkey, &nkl, &val, &vl);
if ((err == YPERR_DOMAIN) || (err == YPERR_YPBIND)) {
syslog(LOG_ERR,
"can't read nis map %s: %s - retrying",
my_mapname, yperr_string(err));
while ((err == YPERR_DOMAIN) ||
(err == YPERR_YPBIND)) {
(void) sleep(20);
err = yp_first(nis_mydomain, my_mapname,
&nkey, &nkl, &val, &vl);
}
syslog(LOG_ERR,
"nis map %s: read OK.", my_mapname);
}
} else {
err = yp_next(nis_mydomain, my_mapname, key, kl,
&nkey, &nkl, &val, &vl);
}
if (err) {
if (err != YPERR_NOMORE && err != YPERR_MAP)
if (verbose)
syslog(LOG_ERR, "%s: %s",
my_mapname, yperr_string(err));
break;
}
if (key)
free(key);
key = nkey;
kl = nkl;
if (kl >= 256 || vl >= 256)
break;
if (kl < 2 || vl < 1)
break;
if (isspace(*key) || *key == '#')
break;
(void) strncpy(dir, key, kl);
dir[kl] = '\0';
if (macro_expand("", dir, qbuff, sizeof (dir))) {
syslog(LOG_ERR,
"%s in NIS map %s: entry too long (max %d chars)",
dir, my_mapname, sizeof (dir) - 1);
break;
}
(void) strncpy(map, val, vl);
map[vl] = '\0';
if (macro_expand(dir, map, qbuff, sizeof (map))) {
syslog(LOG_ERR,
"%s in NIS map %s: entry too long (max %d chars)",
map, my_mapname, sizeof (map) - 1);
break;
}
pmap = map;
while (*pmap && isspace(*pmap))
pmap++; /* skip blanks in front of map */
opts = pmap;
while (*opts && !isspace(*opts))
opts++;
if (*opts) {
*opts++ = '\0';
while (*opts && isspace(*opts))
opts++;
if (*opts == '-')
opts++;
else
opts = defopts;
}
free(val);
/*
* Check for no embedded blanks.
*/
if (strcspn(opts, " ") == strlen(opts)) {
dirinit(dir, pmap, opts, 0, stack, stkptr);
count++;
} else {
pr_msg("Warning: invalid entry for %s in NIS map %s ignored.\n", dir, mapname);
}
}
if (my_mapname)
free(my_mapname);
/*
* In the context of a master map, if no entry is
* found, it is like NOTFOUND
*/
if (count > 0 && err == YPERR_NOMORE)
return (__NSW_SUCCESS);
else {
if (err)
return (nis_err(err));
else
/*
* This case will happen if map is empty
* or none of the entries is valid
*/
return (__NSW_NOTFOUND);
}
}
loaddirect_nis(nismap, localmap, opts, stack, stkptr)
char *nismap, *localmap, *opts;
char **stack;
char ***stkptr;
{
int first, err, count;
char *key, *nkey, *val, *my_nismap;
int kl, nkl, vl;
char dir[100];
first = 1;
key = NULL; kl = 0;
nkey = NULL; nkl = 0;
val = NULL; vl = 0;
count = 0;
my_nismap = NULL;
my_nismap = strdup(nismap);
if (my_nismap == NULL) {
syslog(LOG_ERR, "loadmaster_yp: memory alloc failed: %m");
return (__NSW_UNAVAIL);
}
for (;;) {
if (first) {
first = 0;
err = yp_first(nis_mydomain, my_nismap, &nkey, &nkl,
&val, &vl);
if ((err == YPERR_MAP) &&
(replace_undscr_by_dot(my_nismap)))
err = yp_first(nis_mydomain, my_nismap,
&nkey, &nkl, &val, &vl);
if ((err == YPERR_DOMAIN) || (err == YPERR_YPBIND)) {
syslog(LOG_ERR,
"can't read nis map %s: %s - retrying",
my_nismap, yperr_string(err));
while ((err == YPERR_DOMAIN) ||
(err == YPERR_YPBIND)) {
(void) sleep(20);
err = yp_first(nis_mydomain, my_nismap,
&nkey, &nkl, &val, &vl);
}
syslog(LOG_ERR,
"nis map %s: read OK.", my_nismap);
}
} else {
err = yp_next(nis_mydomain, my_nismap, key, kl,
&nkey, &nkl, &val, &vl);
}
if (err) {
if (err != YPERR_NOMORE && err != YPERR_MAP)
syslog(LOG_ERR, "%s: %s",
my_nismap, yperr_string(err));
break;
}
if (key)
free(key);
key = nkey;
kl = nkl;
if (kl < 2 || kl >= 100)
continue;
if (isspace(*key) || *key == '#')
continue;
(void) strncpy(dir, key, kl);
dir[kl] = '\0';
dirinit(dir, localmap, opts, 1, stack, stkptr);
count++;
free(val);
}
if (my_nismap)
free(my_nismap);
if (count > 0 && err == YPERR_NOMORE)
return (__NSW_SUCCESS);
else
return (nis_err(err));
}
static int
replace_undscr_by_dot(map)
char *map;
{
int ret_val = 0;
while (*map) {
if (*map == '_') {
ret_val = 1;
*map = '.';
}
map++;
}
return (ret_val);
}
static int
nis_err(err)
int err;
{
switch (err) {
case 0:
return (__NSW_SUCCESS);
case YPERR_KEY:
return (__NSW_NOTFOUND);
case YPERR_MAP:
return (__NSW_UNAVAIL);
default:
return (__NSW_UNAVAIL);
}
}
int
getmapkeys_nis(nsmap, list, error, cache_time, stack, stkptr)
char *nsmap;
struct dir_entry **list;
int *error;
int *cache_time;
char **stack;
char ***stkptr;
{
int nserr;
struct dir_cbdata readdir_cbdata;
struct ypall_callback cback;
char *my_map = NULL;
char *key = NULL, *val = NULL;
int nkl, vl;
#ifdef lint
stack = stack;
stkptr = stkptr;
#endif /* lint */
*cache_time = RDDIR_CACHE_TIME;
/*
* XXX Hack to determine if we need to replace '_' with '.'
* Have to use yp_first() since yp_all() simply fails if
* the map is not present
*/
my_map = strdup(nsmap);
if (my_map == NULL) {
syslog(LOG_ERR,
"getmapkeys_nis: memory alloc failed: %m");
*error = ENOMEM;
return (__NSW_UNAVAIL);
}
nserr = yp_first(nis_mydomain, my_map, &key, &nkl, &val, &vl);
if (nserr == YPERR_MAP) {
if (replace_undscr_by_dot(my_map)) {
nserr = yp_first(nis_mydomain, my_map,
&key, &nkl, &val, &vl);
}
if (nserr == YPERR_MAP) {
/*
* map not found
*/
*error = 0; /* return an empty list */
if (verbose) {
syslog(LOG_ERR, "%s: %s",
nsmap, yperr_string(nserr));
}
free(my_map);
return (nis_err(nserr));
}
if (key)
free(key);
if (val)
free(val);
}
readdir_cbdata.list = list;
readdir_cbdata.last = NULL;
readdir_cbdata.error = 0;
cback.foreach = readdir_callback;
cback.data = (char *)&readdir_cbdata;
/*
* after all this song and dance we finally
* ask for the list of entries
*/
nserr = yp_all(nis_mydomain, my_map, &cback);
free(my_map);
*error = readdir_cbdata.error;
if (nserr) {
if (verbose)
syslog(LOG_ERR, "%s: %s", nsmap, yperr_string(nserr));
nserr = 1;
if (*error == 0)
*error = ENOENT;
return (nis_err(nserr));
}
return (__NSW_SUCCESS);
}
static int
readdir_callback(instatus, inkey, inkeylen, inval, invallen, indata)
int instatus;
char *inkey;
int inkeylen;
const char *inval;
int invallen;
struct dir_cbdata *indata;
{
struct dir_entry **list = indata->list;
struct dir_entry *last = indata->last;
char key[MAXPATHLEN];
#ifdef lint
inval = inval;
invallen = invallen;
#endif
if (instatus != YP_TRUE)
return (0); /* next entry. yp_all may decide otherwise... */
if (inkeylen == 0 || isspace(*inkey) || *inkey == '#')
return (0);
/*
* yp_all allocates inkey with two extra bytes which contain
* NEWLINE and null but these two bytes are not reflected in
* inkeylen.
*/
strncpy(key, inkey, inkeylen);
key[inkeylen] = '\0';
/*
* Wildcard entry should be ignored - following entries should continue
* to be read to corroborate with the way we search for entries in yp,
* i.e., first for an exact key match and then a wildcard, if there's
* no exact key match.
*/
if (key[0] == '*' && key[1] == '\0')
return (0);
if (add_dir_entry(key, list, &last)) {
indata->error = ENOMEM;
return (1); /* get no more entries */
}
indata->last = last;
indata->error = 0;
return (0);
}