#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <errno.h>
#include <limits.h>
#include <sepol/policydb/policydb.h>
#ifndef DARWIN
#include <stdio_ext.h>
#endif
#include <stdarg.h>
#include "debug.h"
#include "private.h"
#include "dso.h"
#include "mls.h"
/* -- Deprecated -- */
void sepol_set_delusers(int on __attribute((unused)))
{
WARN(NULL, "Deprecated interface");
}
#undef BADLINE
#define BADLINE() { \
ERR(NULL, "invalid entry %s (%s:%u)", \
buffer, path, lineno); \
continue; \
}
static int load_users(struct policydb *policydb, const char *path)
{
FILE *fp;
char *buffer = NULL, *p, *q, oldc;
size_t len = 0;
ssize_t nread;
unsigned lineno = 0, islist = 0, bit;
user_datum_t *usrdatum;
role_datum_t *roldatum;
ebitmap_node_t *rnode;
fp = fopen(path, "r");
if (fp == NULL)
return -1;
#ifdef DARWIN
if ((buffer = (char *)malloc(255 * sizeof(char))) == NULL) {
ERR(NULL, "out of memory");
return -1;
}
while(fgets(buffer, 255, fp) != NULL) {
#else
__fsetlocking(fp, FSETLOCKING_BYCALLER);
while ((nread = getline(&buffer, &len, fp)) > 0) {
#endif
lineno++;
if (buffer[nread - 1] == '\n')
buffer[nread - 1] = 0;
p = buffer;
while (*p && isspace(*p))
p++;
if (!(*p) || *p == '#')
continue;
if (strncasecmp(p, "user", 4))
BADLINE();
p += 4;
if (!isspace(*p))
BADLINE();
while (*p && isspace(*p))
p++;
if (!(*p))
BADLINE();
q = p;
while (*p && !isspace(*p))
p++;
if (!(*p))
BADLINE();
*p++ = 0;
usrdatum = hashtab_search(policydb->p_users.table, q);
if (usrdatum) {
/* Replacing an existing user definition. */
ebitmap_destroy(&usrdatum->roles.roles);
ebitmap_init(&usrdatum->roles.roles);
} else {
char *id = strdup(q);
/* Adding a new user definition. */
usrdatum =
(user_datum_t *) malloc(sizeof(user_datum_t));
if (!id || !usrdatum) {
ERR(NULL, "out of memory");
free(buffer);
fclose(fp);
return -1;
}
memset(usrdatum, 0, sizeof(user_datum_t));
usrdatum->s.value = ++policydb->p_users.nprim;
ebitmap_init(&usrdatum->roles.roles);
if (hashtab_insert(policydb->p_users.table,
id, (hashtab_datum_t) usrdatum)) {
ERR(NULL, "out of memory");
free(buffer);
fclose(fp);
return -1;
}
}
while (*p && isspace(*p))
p++;
if (!(*p))
BADLINE();
if (strncasecmp(p, "roles", 5))
BADLINE();
p += 5;
if (!isspace(*p))
BADLINE();
while (*p && isspace(*p))
p++;
if (!(*p))
BADLINE();
if (*p == '{') {
islist = 1;
p++;
} else
islist = 0;
oldc = 0;
do {
while (*p && isspace(*p))
p++;
if (!(*p))
break;
q = p;
while (*p && *p != ';' && *p != '}' && !isspace(*p))
p++;
if (!(*p))
break;
if (*p == '}')
islist = 0;
oldc = *p;
*p++ = 0;
if (!q[0])
break;
roldatum = hashtab_search(policydb->p_roles.table, q);
if (!roldatum) {
ERR(NULL, "undefined role %s (%s:%u)",
q, path, lineno);
continue;
}
/* Set the role and every role it dominates */
ebitmap_for_each_bit(&roldatum->dominates, rnode, bit) {
if (ebitmap_node_get_bit(rnode, bit))
if (ebitmap_set_bit
(&usrdatum->roles.roles, bit, 1)) {
ERR(NULL, "out of memory");
free(buffer);
fclose(fp);
return -1;
}
}
} while (islist);
if (oldc == 0)
BADLINE();
if (policydb->mls) {
context_struct_t context;
char *scontext, *r, *s;
while (*p && isspace(*p))
p++;
if (!(*p))
BADLINE();
if (strncasecmp(p, "level", 5))
BADLINE();
p += 5;
if (!isspace(*p))
BADLINE();
while (*p && isspace(*p))
p++;
if (!(*p))
BADLINE();
q = p;
while (*p && strncasecmp(p, "range", 5))
p++;
if (!(*p))
BADLINE();
*--p = 0;
p++;
scontext = malloc(p - q);
if (!scontext) {
ERR(NULL, "out of memory");
free(buffer);
fclose(fp);
return -1;
}
r = scontext;
s = q;
while (*s) {
if (!isspace(*s))
*r++ = *s;
s++;
}
*r = 0;
r = scontext;
context_init(&context);
if (mls_context_to_sid(policydb, oldc, &r, &context) <
0) {
ERR(NULL, "invalid level %s (%s:%u)", scontext,
path, lineno);
free(scontext);
continue;
}
free(scontext);
memcpy(&usrdatum->dfltlevel, &context.range.level[0],
sizeof(usrdatum->dfltlevel));
if (strncasecmp(p, "range", 5))
BADLINE();
p += 5;
if (!isspace(*p))
BADLINE();
while (*p && isspace(*p))
p++;
if (!(*p))
BADLINE();
q = p;
while (*p && *p != ';')
p++;
if (!(*p))
BADLINE();
*p++ = 0;
scontext = malloc(p - q);
if (!scontext) {
ERR(NULL, "out of memory");
free(buffer);
fclose(fp);
return -1;
}
r = scontext;
s = q;
while (*s) {
if (!isspace(*s))
*r++ = *s;
s++;
}
*r = 0;
r = scontext;
context_init(&context);
if (mls_context_to_sid(policydb, oldc, &r, &context) <
0) {
ERR(NULL, "invalid range %s (%s:%u)", scontext,
path, lineno);
free(scontext);
continue;
}
free(scontext);
memcpy(&usrdatum->range, &context.range,
sizeof(usrdatum->range));
}
}
free(buffer);
fclose(fp);
return 0;
}
int sepol_genusers(void *data, size_t len,
const char *usersdir, void **newdata, size_t * newlen)
{
struct policydb policydb;
char path[PATH_MAX];
/* Construct policy database */
if (policydb_init(&policydb))
goto err;
if (policydb_from_image(NULL, data, len, &policydb) < 0)
goto err;
/* Load locally defined users. */
snprintf(path, sizeof path, "%s/local.users", usersdir);
if (load_users(&policydb, path) < 0)
goto err_destroy;
/* Write policy database */
if (policydb_to_image(NULL, &policydb, newdata, newlen) < 0)
goto err_destroy;
policydb_destroy(&policydb);
return 0;
err_destroy:
policydb_destroy(&policydb);
err:
return -1;
}
int hidden sepol_genusers_policydb(policydb_t * policydb, const char *usersdir)
{
char path[PATH_MAX];
/* Load locally defined users. */
snprintf(path, sizeof path, "%s/local.users", usersdir);
if (load_users(policydb, path) < 0) {
ERR(NULL, "unable to load local.users: %s", strerror(errno));
return -1;
}
if (policydb_reindex_users(policydb) < 0) {
ERR(NULL, "unable to reindex users: %s", strerror(errno));
return -1;
}
return 0;
}
/* -- End Deprecated -- */