Files
seta75D 7c4988eac0 Init
2021-10-11 19:38:01 -03:00

437 lines
9.8 KiB
C
Executable File

#include "synonyms.h"
#include <mtlib.h>
#include <synch.h>
#include <sys/types.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <limits.h>
#include <dlfcn.h>
#include <nsswitch.h>
#include <syslog.h>
#define islabel(c) (isalnum(c) || (c) == '_')
/*
* This file has all the routines that access the configuration
* information.
*/
static struct cons_cell { /* private to the parser */
struct __nsw_switchconfig *sw;
struct cons_cell *next;
};
/*
* Local routines
*/
static char *skip(), *labelskip(), *spaceskip();
static struct __nsw_switchconfig *scrounge_cache();
static struct cons_cell *concell_list; /* stays with add_concell() */
/*
* Private interface used by nss_common.c, hence this function is not static
*/
struct __nsw_switchconfig *
_nsw_getoneconfig(name, linep, errp)
const char *name;
char *linep; /* Nota Bene: not const char * */
enum __nsw_parse_err *errp; /* Meanings are abused a bit */
{
struct __nsw_switchconfig *cfp;
struct __nsw_lookup *lkp, **lkq;
int act, end_crit;
char *p, *tokenp;
*errp = __NSW_CONF_PARSE_SUCCESS;
if ((cfp = (struct __nsw_switchconfig *)
calloc(1, sizeof (struct __nsw_switchconfig))) == NULL) {
*errp = __NSW_CONF_PARSE_SYSERR;
return (NULL);
}
cfp->dbase = strdup(name);
lkq = &cfp->lookups;
/* linep points to a naming service name */
while (1) {
int i;
/* white space following the last service */
if (*linep == '\0' || *linep == '\n') {
return (cfp);
}
if ((lkp = (struct __nsw_lookup *)
calloc(1, sizeof (struct __nsw_lookup))) == NULL) {
*errp = __NSW_CONF_PARSE_SYSERR;
freeconf(cfp);
return (NULL);
}
*lkq = lkp;
lkq = &lkp->next;
for (i = 0; i < __NSW_STD_ERRS; i++)
if (i == __NSW_SUCCESS)
lkp->actions[i] = 1;
else
lkp->actions[i] = 0;
/* get criteria for the naming service */
if (tokenp = skip(&linep, '[')) { /* got criteria */
/* premature end, illegal char following [ */
if (!islabel(*linep))
goto barf_line;
lkp->service_name = strdup(tokenp);
cfp->num_lookups++;
end_crit = 0;
/* linep points to a switch_err */
while (1) {
if ((tokenp = skip(&linep, '=')) == NULL) {
goto barf_line;
}
/* premature end, ill char following = */
if (!islabel(*linep))
goto barf_line;
/* linep points to the string following '=' */
p = labelskip(linep);
if (*p == ']')
end_crit = 1;
else if (*p != ' ' && *p != '\t')
goto barf_line;
*p++ = '\0'; /* null terminate linep */
p = spaceskip(p);
if (!end_crit && *p == ']') {
end_crit = 1;
*p++ = '\0';
} else if (*p == '\0' || *p == '\n')
return (cfp);
else if (!islabel(*p))
/* p better be the next switch_err */
goto barf_line;
if (strcasecmp(linep, __NSW_STR_RETURN) == 0)
act = 1;
else if (strcasecmp(linep,
__NSW_STR_CONTINUE) == 0)
act = 0;
else
goto barf_line;
if (strcasecmp(tokenp,
__NSW_STR_SUCCESS) == 0) {
lkp->actions[__NSW_SUCCESS] = act;
} else if (strcasecmp(tokenp,
__NSW_STR_NOTFOUND) == 0) {
lkp->actions[__NSW_NOTFOUND] = act;
} else if (strcasecmp(tokenp,
__NSW_STR_UNAVAIL) == 0) {
lkp->actions[__NSW_UNAVAIL] = act;
} else if (strcasecmp(tokenp,
__NSW_STR_TRYAGAIN) == 0) {
lkp->actions[__NSW_TRYAGAIN] = act;
} else {
/*
* convert string tokenp to integer
* and put in long_errs
*/
}
if (end_crit) {
linep = spaceskip(p);
if (*linep == '\0' || *linep == '\n')
return (cfp);
break; /* process next naming service */
}
linep = p;
} /* end of while loop for a name service's criteria */
} else {
/*
* no criteria for this naming service.
* linep points to name service, but not null
* terminated.
*/
p = labelskip(linep);
if (*p == '\0' || *p == '\n') {
*p = '\0';
lkp->service_name = strdup(linep);
cfp->num_lookups++;
return (cfp);
}
if (*p != ' ' && *p != '\t')
goto barf_line;
*p++ = '\0';
lkp->service_name = strdup(linep);
cfp->num_lookups++;
linep = spaceskip(p);
}
} /* end of while(1) loop for a name service */
barf_line:
freeconf(cfp);
*errp = __NSW_CONF_PARSE_NOPOLICY;
return (NULL);
}
static struct __nsw_switchconfig *
do_getconfig(dbase, errp)
const char *dbase;
enum __nsw_parse_err *errp;
{
struct __nsw_switchconfig *cfp, *retp = NULL;
FILE *fp;
char *linep, *lineq;
/* openlog("libc", LOG_CONS | LOG_NOWAIT, 0); */
if (cfp = scrounge_cache(dbase)) {
*errp = __NSW_CONF_PARSE_SUCCESS;
return (cfp);
}
if ((fp = fopen(__NSW_CONFIG_FILE, "r")) == NULL) {
*errp = __NSW_CONF_PARSE_NOFILE;
return (NULL);
}
if ((lineq = (char *)malloc(BUFSIZ)) == NULL) {
fclose(fp);
*errp = __NSW_CONF_PARSE_SYSERR;
return (NULL);
}
*errp = __NSW_CONF_PARSE_NOPOLICY;
while (linep = fgets(lineq, BUFSIZ, fp)) {
enum __nsw_parse_err line_err;
char *tokenp, *comment;
/*
* Ignore portion of line following the comment character '#'.
*/
if ((comment = strchr(linep, '#')) != NULL) {
*comment = '\0';
}
/*
* skip past blank lines.
* otherwise, cache as a struct switchconfig.
*/
if ((*linep == '\0') || isspace(*linep)) {
continue;
}
if ((tokenp = skip(&linep, ':')) == NULL) {
continue; /* ignore this line */
}
if (cfp = scrounge_cache(tokenp)) {
continue; /* ? somehow this database is in the cache */
}
if (cfp = _nsw_getoneconfig(tokenp, linep, &line_err)) {
add_concell(cfp);
if (strcmp(cfp->dbase, dbase) == 0) {
*errp = __NSW_CONF_PARSE_SUCCESS;
retp = cfp;
}
} else {
/*
* Got an error on this line, if it is a system
* error we might as well give right now. If it
* is a parse error on the second entry of the
* database we are looking for and the first one
* was a good entry we end up logging the following
* syslog message and using a default policy instead.
*/
if (line_err == __NSW_CONF_PARSE_SYSERR) {
*errp = __NSW_CONF_PARSE_SYSERR;
break;
} else if (line_err == __NSW_CONF_PARSE_NOPOLICY &&
strcmp(tokenp, dbase) == 0) {
syslog(LOG_WARNING,
"libc: bad lookup policy for %s in %s, using defaults..\n",
dbase, __NSW_CONFIG_FILE);
*errp = __NSW_CONF_PARSE_NOPOLICY;
break;
}
/*
* Else blithely ignore problems on this line and
* go ahead with the next line.
*/
}
}
free(lineq);
fclose(fp);
return (retp);
}
static struct __nsw_switchconfig *
scrounge_cache(dbase)
char *dbase;
{
struct cons_cell *cellp = concell_list;
for (; cellp; cellp = cellp->next)
if (strcmp(dbase, cellp->sw->dbase) == 0)
return (cellp->sw);
return (NULL);
}
static
freeconf(cfp)
struct __nsw_switchconfig *cfp;
{
if (cfp) {
if (cfp->dbase)
free(cfp->dbase);
if (cfp->lookups) {
struct __nsw_lookup *nex, *cur;
for (cur = cfp->lookups; cur; cur = nex) {
free(cur->service_name);
nex = cur->next;
free(cur);
}
}
free(cfp);
}
}
action_t
__nsw_extended_action(lkp, err)
struct __nsw_lookup *lkp;
int err;
{
struct __nsw_long_err *lerrp;
for (lerrp = lkp->long_errs; lerrp; lerrp = lerrp->next) {
if (lerrp->nsw_errno == err)
return (lerrp->action);
}
return (__NSW_CONTINUE);
}
/* give the next non-alpha character */
static char *
labelskip(cur)
register char *cur;
{
char *p = cur;
while (islabel(*p))
++p;
return (p);
}
/* give the next non-space character */
static char *
spaceskip(cur)
register char *cur;
{
char *p = cur;
while (*p == ' ' || *p == '\t')
++p;
return (p);
}
/*
* terminate the *cur pointed string by null only if it is
* followed by "key" surrounded by zero or more spaces and
* return value is the same as the original *cur pointer and
* *cur pointer is advanced to the first non {space, key} char
* followed by the key. Otherwise, return NULL and keep
* *cur unchanged.
*/
static char *
skip(cur, key)
register char **cur;
register char key;
{
char *p = *cur, *q = *cur, *tmp;
int found = 0, tmpfound = 0;
tmp = labelskip(*cur);
p = tmp;
if (found = (*p == key)) {
*p++ = '\0'; /* overwrite the key */
p = spaceskip(p);
} else {
while (*p == ' ' || *p == '\t')
if (tmpfound = (*++p == key)) {
found = tmpfound;
/* null terminate the return token */
*tmp = '\0';
p++; /* skip the key */
}
}
if (!found)
return (NULL); /* *cur unchanged */
*cur = p;
return (q);
}
/* add to the front: LRU */
static int
add_concell(cfp)
struct __nsw_switchconfig *cfp;
{
struct cons_cell *cp;
if (cfp == NULL)
return (1);
if ((cp = (struct cons_cell *)malloc(sizeof (struct cons_cell)))
== NULL)
return (1);
cp->sw = cfp;
cp->next = concell_list;
concell_list = cp;
return (0);
}
static mutex_t serialize_config = DEFAULTMUTEX;
struct __nsw_switchconfig *
__nsw_getconfig(dbase, errp)
const char *dbase;
enum __nsw_parse_err *errp;
{
struct __nsw_switchconfig *res;
/*
* ==== I don't feel entirely comfortable disabling signals for the
* duration of this, but maybe we have to. Or maybe we should
* use mutex_trylock to detect recursion? (Not clear what's
* the right thing to do when it happens, though).
*/
mutex_lock(&serialize_config);
res = do_getconfig(dbase, errp);
mutex_unlock(&serialize_config);
return (res);
}
int
__nsw_freeconfig(conf)
struct __nsw_switchconfig *conf;
{
struct cons_cell *cellp;
if (conf == NULL) {
return (-1);
}
/*
* Hacked to make life easy for the code in nss_common.c. Free conf
* iff it was created by calling _nsw_getoneconfig() directly
* rather than by calling nsw_getconfig.
*/
mutex_lock(&serialize_config);
for (cellp = concell_list; cellp; cellp = cellp->next) {
if (cellp->sw == conf) {
break;
}
}
mutex_unlock(&serialize_config);
if (cellp == NULL) {
/* Not in the cache; free it */
freeconf(conf);
return (1);
} else {
/* In the cache; don't free it */
return (0);
}
}