#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#include <tsol/label.h>
#include <bsm/devices.h>
#include <bsm/devalloc.h>
extern char *_strdup_null(char *);
static struct _dabuff {
FILE *_daf;
devalloc_t _interpdevalloc;
char _interpdaline[DA_BUFSIZE + 1];
char *_DEVALLOC;
} *__dabuff;
#define daf (_da->_daf)
#define interpdevalloc (_da->_interpdevalloc)
#define interpdaline (_da->_interpdaline)
#define DEVALLOC_FILE (_da->_DEVALLOC)
static devalloc_t *da_interpret(char *);
int da_matchname(devalloc_t *, char *);
int da_matchtype(devalloc_t *, char *);
static int system_labeled = 0;
char *
trim_white(char *ptr)
{
char *tptr;
if (ptr == NULL)
return (NULL);
while (isspace(*ptr))
ptr++;
tptr = ptr + strlen(ptr);
while (tptr != ptr && isspace(tptr[-1]))
--tptr;
*tptr = '\0';
if (*ptr == '\0')
return (NULL);
return (ptr);
}
int
pack_white(char *ptr)
{
int cnt = 0;
char *tptr, ch;
if (ptr == NULL)
return (0);
tptr = ptr;
while (isspace(*tptr))
tptr++;
for (;;) {
while ((ch = *tptr) != '\0' && !isspace(ch)) {
*ptr++ = ch;
tptr++;
}
while (isspace(*tptr))
tptr++;
if (*tptr == '\0')
break;
*ptr++ = ' ';
cnt++;
}
*ptr = '\0';
return (cnt);
}
int
getdadmline(char *buff, int len, FILE *stream)
{
int tmpcnt;
int charcnt = 0;
int fileerr = 0;
int contline = 0;
char *cp;
char *ccp;
do {
cp = buff;
*cp = '\0';
do {
contline = 0;
if (fgets(cp, len - charcnt, stream) == NULL) {
fileerr = 1;
break;
}
ccp = strchr(cp, '\n');
if (ccp != NULL) {
if (ccp != cp && ccp[-1] == '\\') {
ccp--;
contline = 1;
}
else
contline = 0;
*ccp = '\0';
}
tmpcnt = strlen(cp);
cp += tmpcnt;
charcnt += tmpcnt;
} while ((contline) || (charcnt == 0));
ccp = strpbrk(buff, "#");
if (ccp != NULL)
*ccp = '\0';
charcnt = strlen(buff);
} while ((fileerr == 0) && (charcnt == 0));
if (fileerr && !charcnt)
return (0);
else
return (charcnt);
}
static struct _dabuff *
_daalloc(void)
{
struct _dabuff *_da = __dabuff;
if (_da == NULL) {
_da = (struct _dabuff *)calloc((unsigned)1,
(unsigned)sizeof (*__dabuff));
if (_da == NULL)
return (NULL);
DEVALLOC_FILE = "/etc/security/device_allocate";
daf = NULL;
__dabuff = _da;
system_labeled = is_system_labeled();
}
return (__dabuff);
}
char *
getdadmfield(char *ptr, char *skip)
{
static char *tptr = NULL;
char *pend;
if (ptr == NULL)
ptr = tptr;
if (ptr == NULL || *ptr == '\0')
return (NULL);
pend = strpbrk(ptr, skip);
if (pend != NULL) {
*pend++ = '\0';
tptr = pend;
} else
tptr = NULL;
return (trim_white(ptr));
}
void
setdaent(void)
{
struct _dabuff *_da = _daalloc();
if (_da == NULL)
return;
if (daf == NULL)
daf = fopen(DEVALLOC_FILE, "rF");
else
rewind(daf);
}
void
enddaent(void)
{
struct _dabuff *_da = _daalloc();
if (_da == NULL)
return;
if (daf != NULL) {
(void) fclose(daf);
daf = NULL;
}
}
void
setdafile(char *file)
{
struct _dabuff *_da = _daalloc();
if (_da == NULL)
return;
if (daf != NULL) {
(void) fclose(daf);
daf = NULL;
}
DEVALLOC_FILE = file;
}
void
freedaent(devalloc_t *dap)
{
if (dap == NULL)
return;
_kva_free(dap->da_devopts);
dap->da_devopts = NULL;
}
int
getdaon()
{
int is_on = -1;
char line1[DA_BUFSIZE + 1];
struct _dabuff *_da = _daalloc();
setdaent();
if ((_da == NULL) || (daf == NULL)) {
enddaent();
return (is_on);
}
while (getdadmline(line1, (int)sizeof (line1), daf) != 0) {
if (strncmp(line1, DA_ON_STR, (strlen(DA_ON_STR) - 1)) == 0) {
is_on = 1;
break;
} else if (strncmp(line1, DA_OFF_STR,
(strlen(DA_OFF_STR) - 1)) == 0) {
is_on = 0;
break;
}
}
enddaent();
return (is_on);
}
devalloc_t *
getdaent(void)
{
char line1[DA_BUFSIZE + 1];
devalloc_t *da;
struct _dabuff *_da = _daalloc();
if ((_da == 0) || (daf == NULL))
return (NULL);
while (getdadmline(line1, (int)sizeof (line1), daf) != 0) {
if ((strncmp(line1, DA_ON_STR, (strlen(DA_ON_STR) - 1)) == 0) ||
(strncmp(line1, DA_OFF_STR, (strlen(DA_OFF_STR) - 1)) == 0))
continue;
if ((da = da_interpret(line1)) == NULL)
continue;
return (da);
}
return (NULL);
}
devalloc_t *
getdanam(char *name)
{
char line[DA_BUFSIZE + 1];
devalloc_t *da;
struct _dabuff *_da = _daalloc();
if ((name == NULL) || (_da == 0) || (daf == NULL))
return (NULL);
while (getdadmline(line, (int)sizeof (line), daf) != 0) {
if (strstr(line, name) == NULL)
continue;
if ((da = da_interpret(line)) == NULL)
continue;
if (da_matchname(da, name)) {
enddaent();
return (da);
}
freedaent(da);
}
return (NULL);
}
devalloc_t *
getdatype(char *type)
{
char line1[DA_BUFSIZE + 1];
devalloc_t *da;
struct _dabuff *_da = _daalloc();
if ((type == NULL) || (_da == NULL) || (daf == NULL))
return (NULL);
while (getdadmline(line1, (int)sizeof (line1), daf) != 0) {
if (strstr(line1, type) == NULL)
continue;
if ((da = da_interpret(line1)) == NULL)
continue;
if (da_matchtype(da, type))
return (da);
freedaent(da);
}
return (NULL);
}
int
da_matchname(devalloc_t *dap, char *name)
{
if (dap->da_devname == NULL)
return (0);
return ((strcmp(dap->da_devname, name) == 0));
}
int
da_matchtype(devalloc_t *da, char *type)
{
if (da->da_devtype == NULL)
return (0);
return ((strcmp(da->da_devtype, type) == 0));
}
int
da_match(devalloc_t *dap, da_args *dargs)
{
if (dargs->devinfo->devname)
return (da_matchname(dap, dargs->devinfo->devname));
else if (dargs->devinfo->devtype)
return (da_matchtype(dap, dargs->devinfo->devtype));
return (0);
}
static devalloc_t *
da_interpret(char *val)
{
struct _dabuff *_da = _daalloc();
char *opts;
int i;
kva_t *kvap;
kv_t *kvp;
if (_da == NULL)
return (NULL);
(void) strcpy(interpdaline, val);
interpdevalloc.da_devname = getdadmfield(interpdaline, KV_DELIMITER);
interpdevalloc.da_devtype = getdadmfield(NULL, KV_DELIMITER);
opts = getdadmfield(NULL, KV_DELIMITER);
(void) getdadmfield(NULL, KV_DELIMITER);
interpdevalloc.da_devauth = getdadmfield(NULL, KV_DELIMITER);
interpdevalloc.da_devexec = getdadmfield(NULL, KV_DELIMITER);
interpdevalloc.da_devopts = NULL;
if (interpdevalloc.da_devname == NULL ||
interpdevalloc.da_devtype == NULL)
return (NULL);
if ((opts != NULL) &&
(strncmp(opts, DA_RESERVED, strlen(DA_RESERVED)) != 0)) {
interpdevalloc.da_devopts =
_str2kva(opts, KV_ASSIGN, KV_TOKEN_DELIMIT);
}
if ((kvap = interpdevalloc.da_devopts) != NULL) {
for (i = 0, kvp = kvap->data; i < kvap->length; i++, kvp++) {
(void) pack_white(kvp->key);
(void) pack_white(kvp->value);
}
}
if (system_labeled) {
int i = 0, nlen = 0;
char *minstr = NULL, *maxstr = NULL;
kva_t *nkvap = NULL;
kv_t *ndata = NULL, *odata = NULL;
if (kvap == NULL) {
nlen = 2;
} else {
nlen += kvap->length;
if ((minstr = kva_match(kvap, DAOPT_MINLABEL)) == NULL)
nlen++;
if ((maxstr = kva_match(kvap, DAOPT_MAXLABEL)) == NULL)
nlen++;
}
if ((minstr != NULL) && (maxstr != NULL))
goto out;
nkvap = _new_kva(nlen);
ndata = nkvap->data;
if (kvap != NULL) {
for (i = 0; i < kvap->length; i++) {
odata = kvap->data;
ndata[i].key = _strdup_null(odata[i].key);
ndata[i].value = _strdup_null(odata[i].value);
nkvap->length++;
}
}
if (minstr == NULL) {
ndata[i].key = strdup(DAOPT_MINLABEL);
ndata[i].value = strdup(DA_DEFAULT_MIN);
nkvap->length++;
i++;
}
if (maxstr == NULL) {
ndata[i].key = strdup(DAOPT_MAXLABEL);
ndata[i].value = strdup(DA_DEFAULT_MAX);
nkvap->length++;
}
interpdevalloc.da_devopts = nkvap;
}
out:
return (&interpdevalloc);
}