/* * Generalized labeling frontend for userspace object managers. * * Author : Eamon Walsh <ewalsh@epoch.ncsc.mil> */ #include <sys/types.h> #include <ctype.h> #include <errno.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <selinux/selinux.h> #include "callbacks.h" #include "label_internal.h" #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) typedef int (*selabel_initfunc)(struct selabel_handle *rec, struct selinux_opt *opts, unsigned nopts); static selabel_initfunc initfuncs[] = { &selabel_file_init, &selabel_media_init, &selabel_x_init, &selabel_db_init, &selabel_property_init, }; static void selabel_subs_fini(struct selabel_sub *ptr) { struct selabel_sub *next; while (ptr) { next = ptr->next; free(ptr->src); free(ptr->dst); free(ptr); ptr = next; } } static char *selabel_sub(struct selabel_sub *ptr, const char *src) { char *dst = NULL; int len; while (ptr) { if (strncmp(src, ptr->src, ptr->slen) == 0 ) { if (src[ptr->slen] == '/' || src[ptr->slen] == 0) { if ((src[ptr->slen] == '/') && (strcmp(ptr->dst, "/") == 0)) len = ptr->slen + 1; else len = ptr->slen; if (asprintf(&dst, "%s%s", ptr->dst, &src[len]) < 0) return NULL; return dst; } } ptr = ptr->next; } return NULL; } struct selabel_sub *selabel_subs_init(const char *path, struct selabel_sub *list) { char buf[1024]; FILE *cfg = fopen(path, "r"); struct selabel_sub *sub; if (!cfg) return list; while (fgets_unlocked(buf, sizeof(buf) - 1, cfg)) { char *ptr = NULL; char *src = buf; char *dst = NULL; while (*src && isspace(*src)) src++; if (src[0] == '#') continue; ptr = src; while (*ptr && ! isspace(*ptr)) ptr++; *ptr++ = '\0'; if (! *src) continue; dst = ptr; while (*dst && isspace(*dst)) dst++; ptr=dst; while (*ptr && ! isspace(*ptr)) ptr++; *ptr='\0'; if (! *dst) continue; sub = malloc(sizeof(*sub)); if (! sub) goto err; memset(sub, 0, sizeof(*sub)); sub->src=strdup(src); if (! sub->src) goto err; sub->dst=strdup(dst); if (! sub->dst) goto err; sub->slen = strlen(src); sub->next = list; list = sub; } out: fclose(cfg); return list; err: if (sub) free(sub->src); free(sub); goto out; } /* * Validation functions */ static inline int selabel_is_validate_set(struct selinux_opt *opts, unsigned n) { while (n--) if (opts[n].type == SELABEL_OPT_VALIDATE) return !!opts[n].value; return 0; } int selabel_validate(struct selabel_handle *rec, struct selabel_lookup_rec *contexts) { int rc = 0; if (!rec->validating || contexts->validated) goto out; rc = selinux_validate(&contexts->ctx_raw); if (rc < 0) goto out; contexts->validated = 1; out: return rc; } /* * Public API */ struct selabel_handle *selabel_open(unsigned int backend, struct selinux_opt *opts, unsigned nopts) { struct selabel_handle *rec = NULL; if (backend >= ARRAY_SIZE(initfuncs)) { errno = EINVAL; goto out; } rec = (struct selabel_handle *)malloc(sizeof(*rec)); if (!rec) goto out; memset(rec, 0, sizeof(*rec)); rec->backend = backend; rec->validating = selabel_is_validate_set(opts, nopts); rec->subs = NULL; rec->dist_subs = NULL; if ((*initfuncs[backend])(rec, opts, nopts)) { free(rec); rec = NULL; } out: return rec; } static struct selabel_lookup_rec * selabel_lookup_common(struct selabel_handle *rec, int translating, const char *key, int type) { struct selabel_lookup_rec *lr; char *ptr = NULL; char *dptr = NULL; if (key == NULL) { errno = EINVAL; return NULL; } ptr = selabel_sub(rec->subs, key); if (ptr) { dptr = selabel_sub(rec->dist_subs, ptr); if (dptr) { free(ptr); ptr = dptr; } } else { ptr = selabel_sub(rec->dist_subs, key); } if (ptr) { lr = rec->func_lookup(rec, ptr, type); free(ptr); } else { lr = rec->func_lookup(rec, key, type); } if (!lr) return NULL; if (compat_validate(rec, lr, rec->spec_file, 0)) return NULL; if (translating && !lr->ctx_trans && selinux_raw_to_trans_context(lr->ctx_raw, &lr->ctx_trans)) return NULL; return lr; } int selabel_lookup(struct selabel_handle *rec, char **con, const char *key, int type) { struct selabel_lookup_rec *lr; lr = selabel_lookup_common(rec, 1, key, type); if (!lr) return -1; *con = strdup(lr->ctx_trans); return *con ? 0 : -1; } int selabel_lookup_raw(struct selabel_handle *rec, char **con, const char *key, int type) { struct selabel_lookup_rec *lr; lr = selabel_lookup_common(rec, 0, key, type); if (!lr) return -1; *con = strdup(lr->ctx_raw); return *con ? 0 : -1; } void selabel_close(struct selabel_handle *rec) { selabel_subs_fini(rec->subs); selabel_subs_fini(rec->dist_subs); rec->func_close(rec); free(rec->spec_file); free(rec); } void selabel_stats(struct selabel_handle *rec) { rec->func_stats(rec); }