#include <stdlib.h>
#include <limits.h>
#include <string.h>
#include <ctype.h>
#define __NSS_PRIVATE_INTERFACE
#include "nsswitch_priv.h"
#undef __NSS_PRIVATE_INTERFACE
#define islabel(c) (isalnum(c) || (c) == '_')
static char *skip(char **, char);
static char *labelskip(char *);
static char *spaceskip(char *);
static void freeconf_v1(struct __nsw_switchconfig_v1 *);
static int alldigits(char *);
static int dns_tryagain_retry = 3;
static void
set_dns_default_lkp(struct __nsw_lookup_v1 *lkp)
{
if (strcasecmp(lkp->service_name, "dns") == 0) {
lkp->actions[__NSW_TRYAGAIN] =
__NSW_TRYAGAIN_NTIMES;
lkp->max_retries = dns_tryagain_retry;
}
}
static void
freeconf_v1(struct __nsw_switchconfig_v1 *cfp)
{
if (cfp) {
if (cfp->dbase)
free(cfp->dbase);
if (cfp->lookups) {
struct __nsw_lookup_v1 *nex, *cur;
for (cur = cfp->lookups; cur; cur = nex) {
free(cur->service_name);
nex = cur->next;
free(cur);
}
}
free(cfp);
}
}
static char *
labelskip(char *cur)
{
char *p = cur;
while (islabel(*p))
++p;
return (p);
}
static char *
spaceskip(char *cur)
{
char *p = cur;
while (*p == ' ' || *p == '\t')
++p;
return (p);
}
static char *
skip(char **cur, char key)
{
char *p, *tmp;
char *q = *cur;
int found, tmpfound;
tmp = labelskip(*cur);
p = tmp;
found = (*p == key);
if (found) {
*p++ = '\0';
p = spaceskip(p);
} else {
while (*p == ' ' || *p == '\t') {
tmpfound = (*++p == key);
if (tmpfound) {
found = tmpfound;
*tmp = '\0';
p++;
}
}
}
if (!found)
return (NULL);
*cur = p;
return (q);
}
static int
alldigits(char *s)
{
for (; *s; s++)
if (!isdigit(*s))
return (0);
return (1);
}
struct __nsw_switchconfig_v1 *
_nsw_getoneconfig_v1(const char *name, char *linep, enum __nsw_parse_err *errp)
{
struct __nsw_switchconfig_v1 *cfp;
struct __nsw_lookup_v1 *lkp, **lkq;
int end_crit;
action_t act;
char *p, *tokenp;
*errp = __NSW_CONF_PARSE_SUCCESS;
if ((cfp = calloc(1, sizeof (struct __nsw_switchconfig_v1)))
== NULL) {
*errp = __NSW_CONF_PARSE_SYSERR;
return (NULL);
}
cfp->dbase = strdup(name);
lkq = &cfp->lookups;
for (;;) {
int i;
if (*linep == '\0' || *linep == '\n') {
return (cfp);
}
if ((lkp = calloc(1, sizeof (struct __nsw_lookup_v1)))
== NULL) {
*errp = __NSW_CONF_PARSE_SYSERR;
freeconf_v1(cfp);
return (NULL);
}
*lkq = lkp;
lkq = &lkp->next;
for (i = 0; i < __NSW_STD_ERRS_V1; i++)
if (i == __NSW_SUCCESS)
lkp->actions[i] = __NSW_RETURN;
else if (i == __NSW_TRYAGAIN)
lkp->actions[i] = __NSW_TRYAGAIN_FOREVER;
else
lkp->actions[i] = __NSW_CONTINUE;
if (tokenp = skip(&linep, '[')) {
if (!islabel(*linep))
goto barf_line;
lkp->service_name = strdup(tokenp);
cfp->num_lookups++;
set_dns_default_lkp(lkp);
end_crit = 0;
for (;;) {
int ntimes = 0;
int dns_continue = 0;
if ((tokenp = skip(&linep, '=')) == NULL) {
goto barf_line;
}
if (!islabel(*linep))
goto barf_line;
p = labelskip(linep);
if (*p == ']')
end_crit = 1;
else if (*p != ' ' && *p != '\t')
goto barf_line;
*p++ = '\0';
p = spaceskip(p);
if (!end_crit) {
if (*p == ']') {
end_crit = 1;
*p++ = '\0';
} else if (*p == '\0' || *p == '\n') {
return (cfp);
} else if (!islabel(*p))
goto barf_line;
}
if (strcasecmp(linep, __NSW_STR_RETURN) == 0)
act = __NSW_RETURN;
else if (strcasecmp(linep,
__NSW_STR_CONTINUE) == 0) {
if (strcasecmp(lkp->service_name,
"dns") == 0 &&
strcasecmp(tokenp,
__NSW_STR_TRYAGAIN)
== 0) {
dns_continue = 1;
act = __NSW_TRYAGAIN_NTIMES;
} else
act = __NSW_CONTINUE;
} else if (strcasecmp(linep,
__NSW_STR_FOREVER) == 0)
act = __NSW_TRYAGAIN_FOREVER;
else if (alldigits(linep)) {
act = __NSW_TRYAGAIN_NTIMES;
ntimes = atoi(linep);
if (ntimes < 0 || ntimes > INT_MAX)
ntimes = 0;
}
else
goto barf_line;
if (__NSW_SUCCESS_ACTION(act) &&
strcasecmp(tokenp,
__NSW_STR_SUCCESS) == 0) {
lkp->actions[__NSW_SUCCESS] = act;
} else if (__NSW_NOTFOUND_ACTION(act) &&
strcasecmp(tokenp,
__NSW_STR_NOTFOUND) == 0) {
lkp->actions[__NSW_NOTFOUND] = act;
} else if (__NSW_UNAVAIL_ACTION(act) &&
strcasecmp(tokenp,
__NSW_STR_UNAVAIL) == 0) {
lkp->actions[__NSW_UNAVAIL] = act;
} else if (__NSW_TRYAGAIN_ACTION(act) &&
strcasecmp(tokenp,
__NSW_STR_TRYAGAIN) == 0) {
lkp->actions[__NSW_TRYAGAIN] = act;
if (strcasecmp(lkp->service_name,
"nis") == 0)
lkp->actions[
__NSW_NISSERVDNS_TRYAGAIN]
= act;
if (act == __NSW_TRYAGAIN_NTIMES)
lkp->max_retries =
dns_continue ?
dns_tryagain_retry : ntimes;
} else {
}
if (end_crit) {
linep = spaceskip(p);
if (*linep == '\0' || *linep == '\n')
return (cfp);
break;
}
linep = p;
}
} else {
p = labelskip(linep);
if (*p == '\0' || *p == '\n') {
*p = '\0';
lkp->service_name = strdup(linep);
set_dns_default_lkp(lkp);
cfp->num_lookups++;
return (cfp);
}
if (*p != ' ' && *p != '\t')
goto barf_line;
*p++ = '\0';
lkp->service_name = strdup(linep);
set_dns_default_lkp(lkp);
cfp->num_lookups++;
linep = spaceskip(p);
}
}
barf_line:
freeconf_v1(cfp);
*errp = __NSW_CONF_PARSE_NOPOLICY;
return (NULL);
}
int
__nsw_freeconfig_v1(
struct __nsw_switchconfig_v1 *conf)
{
freeconf_v1(conf);
return (0);
}