| /* |
| * 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, |
| const struct selinux_opt *opts, |
| unsigned nopts); |
| |
| static selabel_initfunc initfuncs[] = { |
| &selabel_file_init, |
| NULL, |
| NULL, |
| NULL, |
| &selabel_property_init, |
| }; |
| |
| /* |
| * Validation functions |
| */ |
| |
| static inline int selabel_is_validate_set(const 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, |
| const struct selinux_opt *opts, |
| unsigned nopts) |
| { |
| struct selabel_handle *rec = NULL; |
| |
| if (backend >= ARRAY_SIZE(initfuncs)) { |
| errno = EINVAL; |
| goto out; |
| } |
| |
| if (initfuncs[backend] == NULL) |
| 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); |
| |
| if ((*initfuncs[backend])(rec, opts, nopts)) { |
| free(rec->spec_file); |
| free(rec); |
| rec = NULL; |
| } |
| |
| out: |
| return rec; |
| } |
| |
| static struct selabel_lookup_rec * |
| selabel_lookup_common(struct selabel_handle *rec, |
| const char *key, int type) |
| { |
| struct selabel_lookup_rec *lr; |
| lr = rec->func_lookup(rec, key, type); |
| if (!lr) |
| 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, key, type); |
| if (!lr) |
| return -1; |
| |
| *con = strdup(lr->ctx_raw); |
| return *con ? 0 : -1; |
| } |
| |
| bool selabel_partial_match(struct selabel_handle *rec, const char *key) |
| { |
| if (!rec->func_partial_match) { |
| /* |
| * If the label backend does not support partial matching, |
| * then assume a match is possible. |
| */ |
| return true; |
| } |
| return rec->func_partial_match(rec, key); |
| } |
| |
| int selabel_lookup_best_match(struct selabel_handle *rec, char **con, |
| const char *key, const char **aliases, int type) |
| { |
| struct selabel_lookup_rec *lr; |
| |
| if (!rec->func_lookup_best_match) { |
| errno = ENOTSUP; |
| return -1; |
| } |
| |
| lr = rec->func_lookup_best_match(rec, key, aliases, type); |
| if (!lr) |
| return -1; |
| |
| *con = strdup(lr->ctx_raw); |
| return *con ? 0 : -1; |
| } |
| |
| enum selabel_cmp_result selabel_cmp(struct selabel_handle *h1, |
| struct selabel_handle *h2) |
| { |
| if (!h1->func_cmp || h1->func_cmp != h2->func_cmp) |
| return SELABEL_INCOMPARABLE; |
| |
| return h1->func_cmp(h1, h2); |
| } |
| |
| void selabel_close(struct selabel_handle *rec) |
| { |
| rec->func_close(rec); |
| free(rec->spec_file); |
| free(rec); |
| } |
| |
| void selabel_stats(struct selabel_handle *rec) |
| { |
| rec->func_stats(rec); |
| } |