#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <ctype.h>
#include <priv.h>
#include <string.h>
#include <libgen.h>
#include <errno.h>
#include <libintl.h>
#include <sys/devpolicy.h>
#include <sys/modctl.h>
#include "message.h"
#include "plcysubr.h"
#define err_print devfsadm_errprint
extern void err_print(char *, ...);
#define PLCY_CHUNK 128
static int
qcmp(const void *a, const void *b)
{
const devplcysys_t *pa = a;
const devplcysys_t *pb = b;
int wilda, wildb;
if (pa->dps_maj == DEVPOLICY_DFLT_MAJ)
return (-1);
if (pb->dps_maj == DEVPOLICY_DFLT_MAJ)
return (1);
if (pa->dps_maj > pb->dps_maj)
return (1);
else if (pa->dps_maj < pb->dps_maj)
return (-1);
wilda = strchr(pa->dps_minornm, '*') != NULL;
wildb = strchr(pb->dps_minornm, '*') != NULL;
if (wilda != wildb)
return (wilda - wildb);
if (wilda == 0)
return (strcmp(pa->dps_minornm, pb->dps_minornm));
return ((int)(strlen(pb->dps_minornm) - strlen(pa->dps_minornm)));
}
static int
loadprivs(const char *infile)
{
char *line, *col;
FILE *in;
struct fileentry *fep;
int res = 0;
in = fopen(infile, "r");
if (in == NULL)
return (0);
while ((fep = fgetline(in)) != NULL && fep->entry != NULL) {
line = fep->entry;
if (*line == '\0')
continue;
line[strlen(line)-1] = '\0';
col = strchr(line, ':');
if (col != NULL) {
major_t maj;
*col = '\0';
if (modctl(MODGETMAJBIND, line, col - line + 1, &maj)
!= 0)
continue;
line = col + 1;
}
if (modctl(MODALLOCPRIV, line) != 0) {
(void) err_print("modctl(MODALLOCPRIV, %s): %s\n",
line, strerror(errno));
res = -1;
}
}
return (res);
}
static int
loadpolicy(const char *infile)
{
char *line;
int nalloc = 0, cnt = 0;
char *mem = NULL;
devplcysys_t *dp, *dflt = NULL;
FILE *in;
struct fileentry *fep;
int res;
char *maj;
char *tok;
char *min;
in = fopen(infile, "r");
if (in == NULL) {
err_print(OPEN_FAILED, infile, strerror(errno));
return (-1);
}
while ((fep = fgetline(in)) != NULL && fep->entry != NULL) {
line = fep->entry;
if (cnt >= nalloc) {
nalloc += PLCY_CHUNK;
mem = realloc(mem, nalloc * devplcysys_sz);
if (mem == NULL) {
err_print(MALLOC_FAILED,
nalloc * devplcysys_sz);
return (-1);
}
if (dflt != NULL)
dflt = (devplcysys_t *)mem;
}
maj = strtok(line, "\n\t ");
if (maj == NULL)
continue;
dp = (devplcysys_t *)(mem + devplcysys_sz * cnt);
if (strcmp(maj, "*") == 0) {
if (dflt != NULL) {
err_print(DPLCY_ONE_DFLT, infile);
return (-1);
}
(void) memset(dp, 0, devplcysys_sz);
dp->dps_maj = DEVPOLICY_DFLT_MAJ;
dflt = dp;
} else {
if (dflt == NULL) {
err_print(DPLCY_FIRST, infile);
return (-1);
}
(void) memcpy(dp, dflt, devplcysys_sz);
min = strchr(maj, ':');
if (min != NULL) {
*min++ = '\0';
if (strchr(min, ':') != NULL) {
(void) fprintf(stderr,
"Too many ``:'' in entry\n");
return (-1);
}
} else
min = "*";
if (modctl(MODGETMAJBIND, maj, strlen(maj) + 1,
&dp->dps_maj) != 0)
continue;
if (*min == '(') {
char type;
if (parse_minor_range(min, &dp->dps_lomin,
&dp->dps_himin, &type) == -1) {
err_print(INVALID_MINOR, min);
return (-1);
}
dp->dps_isblock = type == 'b';
} else {
if (strlen(min) >= sizeof (dp->dps_minornm)) {
err_print(MINOR_TOO_LONG, maj, min);
return (-1);
}
(void) strcpy(dp->dps_minornm, min);
}
}
while (tok = strtok(NULL, "\n\t ")) {
if (parse_plcy_token(tok, dp)) {
err_print(BAD_ENTRY, fep->startline,
fep->orgentry);
return (-1);
}
}
cnt++;
}
if (fep == NULL) {
if (feof(in))
err_print(UNEXPECTED_EOF, infile);
else
err_print(NO_MEMORY);
return (-1);
}
qsort(mem, cnt, devplcysys_sz, qcmp);
if ((res = modctl(MODSETDEVPOLICY, cnt, devplcysys_sz, mem)) != 0)
err_print("modctl(MODSETDEVPOLICY): %s\n", strerror(errno));
return (res);
}
int
load_devpolicy(void)
{
int res;
devplcy_init();
res = loadprivs(EXTRA_PRIVS);
res += loadpolicy(DEV_POLICY);
return (res);
}