1/* 2 * Generalized labeling frontend for userspace object managers. 3 * 4 * Author : Eamon Walsh <ewalsh@epoch.ncsc.mil> 5 */ 6 7#include <sys/types.h> 8#include <ctype.h> 9#include <errno.h> 10#include <stdio.h> 11#include <stdlib.h> 12#include <string.h> 13#include <selinux/selinux.h> 14#include "callbacks.h" 15#include "label_internal.h" 16 17#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) 18 19typedef int (*selabel_initfunc)(struct selabel_handle *rec, 20 struct selinux_opt *opts, unsigned nopts); 21 22static selabel_initfunc initfuncs[] = { 23 &selabel_file_init, 24 &selabel_media_init, 25 &selabel_x_init, 26 &selabel_db_init, 27 &selabel_property_init, 28}; 29 30static void selabel_subs_fini(struct selabel_sub *ptr) 31{ 32 struct selabel_sub *next; 33 34 while (ptr) { 35 next = ptr->next; 36 free(ptr->src); 37 free(ptr->dst); 38 free(ptr); 39 ptr = next; 40 } 41} 42 43static char *selabel_sub(struct selabel_sub *ptr, const char *src) 44{ 45 char *dst = NULL; 46 int len; 47 48 while (ptr) { 49 if (strncmp(src, ptr->src, ptr->slen) == 0 ) { 50 if (src[ptr->slen] == '/' || 51 src[ptr->slen] == 0) { 52 if ((src[ptr->slen] == '/') && 53 (strcmp(ptr->dst, "/") == 0)) 54 len = ptr->slen + 1; 55 else 56 len = ptr->slen; 57 if (asprintf(&dst, "%s%s", ptr->dst, &src[len]) < 0) 58 return NULL; 59 return dst; 60 } 61 } 62 ptr = ptr->next; 63 } 64 return NULL; 65} 66 67struct selabel_sub *selabel_subs_init(const char *path, struct selabel_sub *list) 68{ 69 char buf[1024]; 70 FILE *cfg = fopen(path, "r"); 71 struct selabel_sub *sub; 72 73 if (!cfg) 74 return list; 75 76 while (fgets_unlocked(buf, sizeof(buf) - 1, cfg)) { 77 char *ptr = NULL; 78 char *src = buf; 79 char *dst = NULL; 80 81 while (*src && isspace(*src)) 82 src++; 83 if (src[0] == '#') continue; 84 ptr = src; 85 while (*ptr && ! isspace(*ptr)) 86 ptr++; 87 *ptr++ = '\0'; 88 if (! *src) continue; 89 90 dst = ptr; 91 while (*dst && isspace(*dst)) 92 dst++; 93 ptr=dst; 94 while (*ptr && ! isspace(*ptr)) 95 ptr++; 96 *ptr='\0'; 97 if (! *dst) 98 continue; 99 100 sub = malloc(sizeof(*sub)); 101 if (! sub) 102 goto err; 103 memset(sub, 0, sizeof(*sub)); 104 105 sub->src=strdup(src); 106 if (! sub->src) 107 goto err; 108 109 sub->dst=strdup(dst); 110 if (! sub->dst) 111 goto err; 112 113 sub->slen = strlen(src); 114 sub->next = list; 115 list = sub; 116 } 117out: 118 fclose(cfg); 119 return list; 120err: 121 if (sub) 122 free(sub->src); 123 free(sub); 124 goto out; 125} 126 127/* 128 * Validation functions 129 */ 130 131static inline int selabel_is_validate_set(struct selinux_opt *opts, unsigned n) 132{ 133 while (n--) 134 if (opts[n].type == SELABEL_OPT_VALIDATE) 135 return !!opts[n].value; 136 137 return 0; 138} 139 140int selabel_validate(struct selabel_handle *rec, 141 struct selabel_lookup_rec *contexts) 142{ 143 int rc = 0; 144 145 if (!rec->validating || contexts->validated) 146 goto out; 147 148 rc = selinux_validate(&contexts->ctx_raw); 149 if (rc < 0) 150 goto out; 151 152 contexts->validated = 1; 153out: 154 return rc; 155} 156 157/* 158 * Public API 159 */ 160 161struct selabel_handle *selabel_open(unsigned int backend, 162 struct selinux_opt *opts, unsigned nopts) 163{ 164 struct selabel_handle *rec = NULL; 165 166 if (backend >= ARRAY_SIZE(initfuncs)) { 167 errno = EINVAL; 168 goto out; 169 } 170 171 rec = (struct selabel_handle *)malloc(sizeof(*rec)); 172 if (!rec) 173 goto out; 174 175 memset(rec, 0, sizeof(*rec)); 176 rec->backend = backend; 177 rec->validating = selabel_is_validate_set(opts, nopts); 178 179 rec->subs = NULL; 180 rec->dist_subs = NULL; 181 182 if ((*initfuncs[backend])(rec, opts, nopts)) { 183 free(rec); 184 rec = NULL; 185 } 186 187out: 188 return rec; 189} 190 191static struct selabel_lookup_rec * 192selabel_lookup_common(struct selabel_handle *rec, int translating, 193 const char *key, int type) 194{ 195 struct selabel_lookup_rec *lr; 196 char *ptr = NULL; 197 char *dptr = NULL; 198 199 if (key == NULL) { 200 errno = EINVAL; 201 return NULL; 202 } 203 204 ptr = selabel_sub(rec->subs, key); 205 if (ptr) { 206 dptr = selabel_sub(rec->dist_subs, ptr); 207 if (dptr) { 208 free(ptr); 209 ptr = dptr; 210 } 211 } else { 212 ptr = selabel_sub(rec->dist_subs, key); 213 } 214 if (ptr) { 215 lr = rec->func_lookup(rec, ptr, type); 216 free(ptr); 217 } else { 218 lr = rec->func_lookup(rec, key, type); 219 } 220 if (!lr) 221 return NULL; 222 223 if (compat_validate(rec, lr, rec->spec_file, 0)) 224 return NULL; 225 226 if (translating && !lr->ctx_trans && 227 selinux_raw_to_trans_context(lr->ctx_raw, &lr->ctx_trans)) 228 return NULL; 229 230 return lr; 231} 232 233int selabel_lookup(struct selabel_handle *rec, char **con, 234 const char *key, int type) 235{ 236 struct selabel_lookup_rec *lr; 237 238 lr = selabel_lookup_common(rec, 1, key, type); 239 if (!lr) 240 return -1; 241 242 *con = strdup(lr->ctx_trans); 243 return *con ? 0 : -1; 244} 245 246int selabel_lookup_raw(struct selabel_handle *rec, char **con, 247 const char *key, int type) 248{ 249 struct selabel_lookup_rec *lr; 250 251 lr = selabel_lookup_common(rec, 0, key, type); 252 if (!lr) 253 return -1; 254 255 *con = strdup(lr->ctx_raw); 256 return *con ? 0 : -1; 257} 258 259void selabel_close(struct selabel_handle *rec) 260{ 261 selabel_subs_fini(rec->subs); 262 selabel_subs_fini(rec->dist_subs); 263 rec->func_close(rec); 264 free(rec->spec_file); 265 free(rec); 266} 267 268void selabel_stats(struct selabel_handle *rec) 269{ 270 rec->func_stats(rec); 271} 272