#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 -- */