#pragma weak _priv_str_to_set = priv_str_to_set
#pragma weak _priv_set_to_str = priv_set_to_str
#pragma weak _priv_gettext = priv_gettext
#include "lint.h"
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <strings.h>
#include <errno.h>
#include <string.h>
#include <locale.h>
#include <sys/param.h>
#include <priv.h>
#include <alloca.h>
#include <locale.h>
#include "libc.h"
#include "../i18n/_loc_path.h"
#include "priv_private.h"
priv_set_t *
priv_basic(void)
{
priv_data_t *d;
LOADPRIVDATA(d);
return (d->pd_basicset);
}
priv_set_t *
priv_str_to_set(const char *priv_names,
const char *separators,
const char **endptr)
{
char *base;
char *offset;
char *last;
priv_set_t *pset = NULL;
priv_set_t *zone;
priv_set_t *basic;
if (endptr != NULL)
*endptr = NULL;
if ((base = libc_strdup(priv_names)) == NULL ||
(pset = priv_allocset()) == NULL) {
libc_free(base);
return (NULL);
}
priv_emptyset(pset);
basic = priv_basic();
zone = privdata->pd_zoneset;
last = base;
while ((offset = strtok_r(NULL, separators, &last)) != NULL) {
if (basic != NULL && strcasecmp(offset, "basic") == 0) {
priv_union(basic, pset);
} else if (strcasecmp(offset, "none") == 0) {
priv_emptyset(pset);
} else if (strcasecmp(offset, "all") == 0) {
priv_fillset(pset);
} else if (strcasecmp(offset, "zone") == 0) {
priv_union(zone, pset);
} else {
boolean_t neg = (*offset == '-' || *offset == '!');
int privid;
int slen;
privid = priv_getbyname(offset +
((neg || *offset == '+') ? 1 : 0));
if (privid < 0) {
slen = offset - base;
libc_free(base);
priv_freeset(pset);
if (endptr != NULL)
*endptr = priv_names + slen;
errno = EINVAL;
return (NULL);
} else {
if (neg)
PRIV_DELSET(pset, privid);
else
PRIV_ADDSET(pset, privid);
}
}
}
libc_free(base);
return (pset);
}
char *
__priv_set_to_str(
priv_data_t *d,
const priv_set_t *pset,
char separator,
int flag)
{
const char *pstr;
char *res, *resp;
int i;
char neg = separator == '!' ? '-' : '!';
priv_set_t *zone;
boolean_t all;
boolean_t use_libc_data = (d == NULL);
if (use_libc_data)
LOADPRIVDATA(d);
if (flag != PRIV_STR_PORT && __priv_isemptyset(d, pset))
return (strdup("none"));
if (flag != PRIV_STR_LIT && __priv_isfullset(d, pset))
return (strdup("all"));
res = resp = alloca(d->pd_pinfo->priv_globalinfosize);
if (use_libc_data)
LOCKPRIVDATA();
if (flag == PRIV_STR_SHORT) {
int presentbasic, missingbasic, present, missing;
int presentzone, missingzone;
int count;
presentbasic = missingbasic = present = 0;
presentzone = missingzone = 0;
zone = d->pd_zoneset;
for (i = 0; i < d->pd_nprivs; i++) {
int mem = PRIV_ISMEMBER(pset, i);
if (d->pd_basicset != NULL &&
PRIV_ISMEMBER(d->pd_basicset, i)) {
if (mem)
presentbasic++;
else
missingbasic++;
}
if (zone != NULL && PRIV_ISMEMBER(zone, i)) {
if (mem)
presentzone++;
else
missingzone++;
}
if (mem)
present++;
}
missing = d->pd_nprivs - present;
if (1 - presentbasic + missingbasic < 0) {
flag = PRIV_STR_PORT;
count = present + 1 - presentbasic + missingbasic;
} else {
flag = PRIV_STR_LIT;
count = present;
}
if (count >= 1 + missing) {
flag = PRIV_STR_SHORT;
count = 1 + missing;
all = B_TRUE;
}
if (present == presentzone && 1 + missingzone < count) {
flag = PRIV_STR_SHORT;
all = B_FALSE;
}
}
switch (flag) {
case PRIV_STR_LIT:
*res = '\0';
break;
case PRIV_STR_PORT:
(void) strcpy(res, "basic");
if (d->pd_basicset == NULL)
flag = PRIV_STR_LIT;
break;
case PRIV_STR_SHORT:
if (all)
(void) strcpy(res, "all");
else
(void) strcpy(res, "zone");
break;
default:
if (use_libc_data)
UNLOCKPRIVDATA();
return (NULL);
}
res += strlen(res);
for (i = 0; i < d->pd_nprivs; i++) {
int priv = d->pd_setsort[i];
if (PRIV_ISMEMBER(pset, priv)) {
switch (flag) {
case PRIV_STR_SHORT:
if (all || PRIV_ISMEMBER(zone, priv))
continue;
break;
case PRIV_STR_PORT:
if (PRIV_ISMEMBER(d->pd_basicset, priv))
continue;
break;
case PRIV_STR_LIT:
break;
}
if (res != resp)
*res++ = separator;
} else {
switch (flag) {
case PRIV_STR_LIT:
continue;
case PRIV_STR_PORT:
if (!PRIV_ISMEMBER(d->pd_basicset, priv))
continue;
break;
case PRIV_STR_SHORT:
if (!all && !PRIV_ISMEMBER(zone, priv))
continue;
break;
}
if (res != resp)
*res++ = separator;
*res++ = neg;
}
pstr = __priv_getbynum(d, priv);
(void) strcpy(res, pstr);
res += strlen(pstr);
}
if (use_libc_data)
UNLOCKPRIVDATA();
return (strdup(*resp == '\0' ? "none" : resp));
}
char *
priv_set_to_str(const priv_set_t *pset, char separator, int flag)
{
return (__priv_set_to_str(NULL, pset, separator, flag));
}
static char *
do_priv_gettext(const char *priv, const char *file)
{
char buf[8*1024];
boolean_t inentry = B_FALSE;
FILE *namefp;
namefp = fopen(file, "rF");
if (namefp == NULL)
return (NULL);
while (fgets(buf, sizeof (buf), namefp) != NULL) {
char *lp;
if (buf[0] == '#')
continue;
if (buf[0] == '\n') {
inentry = B_FALSE;
continue;
}
if (inentry)
continue;
if (isspace((unsigned char)buf[0]))
goto out;
buf[strlen(buf) - 1] = '\0';
if (strcasecmp(buf, priv) != 0) {
inentry = B_TRUE;
continue;
}
lp = buf;
while (fgets(lp, sizeof (buf) - (lp - buf), namefp) != NULL) {
char *tstart;
int len;
if (*lp == '\n' || !isspace((unsigned char)*lp)) {
*lp = '\0';
(void) fclose(namefp);
return (strdup(buf));
}
tstart = lp;
while (*tstart != '\0' &&
isspace((unsigned char)*tstart)) {
tstart++;
}
len = strlen(tstart);
(void) memmove(lp, tstart, len + 1);
lp += len;
if (lp == &buf[sizeof (buf) - 1])
goto out;
}
if (lp != buf) {
*lp = '\0';
(void) fclose(namefp);
return (strdup(buf));
}
}
out:
(void) fclose(namefp);
return (NULL);
}
char *
priv_gettext(const char *priv)
{
char file[MAXPATHLEN];
locale_t curloc;
const char *loc;
char *ret;
if (priv_getbyname(priv) < 0)
return (NULL);
curloc = uselocale(NULL);
loc = current_locale(curloc, LC_MESSAGES);
if (snprintf(file, sizeof (file),
_DFLT_LOC_PATH "%s/LC_MESSAGES/priv_names", loc) < sizeof (file)) {
ret = do_priv_gettext(priv, (const char *)file);
if (ret != NULL)
return (ret);
}
ret = do_priv_gettext(priv, "/etc/security/priv_names");
return (ret);
}