Home | History | Annotate | Download | only in src
      1 #include <stdlib.h>
      2 #include <stddef.h>
      3 #include <string.h>
      4 
      5 #include "private.h"
      6 #include "debug.h"
      7 #include "handle.h"
      8 
      9 #include <sepol/policydb/policydb.h>
     10 #include <sepol/policydb/hashtab.h>
     11 #include <sepol/policydb/expand.h>
     12 #include "user_internal.h"
     13 #include "mls.h"
     14 
     15 static int user_to_record(sepol_handle_t * handle,
     16 			  const policydb_t * policydb,
     17 			  int user_idx, sepol_user_t ** record)
     18 {
     19 
     20 	const char *name = policydb->p_user_val_to_name[user_idx];
     21 	user_datum_t *usrdatum = policydb->user_val_to_struct[user_idx];
     22 	ebitmap_t *roles;
     23 	ebitmap_node_t *rnode;
     24 	unsigned bit;
     25 
     26 	sepol_user_t *tmp_record = NULL;
     27 
     28 	if (!usrdatum)
     29 		goto err;
     30 
     31 	roles = &(usrdatum->roles.roles);
     32 
     33 	if (sepol_user_create(handle, &tmp_record) < 0)
     34 		goto err;
     35 
     36 	if (sepol_user_set_name(handle, tmp_record, name) < 0)
     37 		goto err;
     38 
     39 	/* Extract roles */
     40 	ebitmap_for_each_bit(roles, rnode, bit) {
     41 		if (ebitmap_node_get_bit(rnode, bit)) {
     42 			char *role = policydb->p_role_val_to_name[bit];
     43 			if (sepol_user_add_role(handle, tmp_record, role) < 0)
     44 				goto err;
     45 		}
     46 	}
     47 
     48 	/* Extract MLS info */
     49 	if (policydb->mls) {
     50 		context_struct_t context;
     51 		char *str;
     52 
     53 		context_init(&context);
     54 		if (mls_level_cpy(&context.range.level[0],
     55 				  &usrdatum->exp_dfltlevel) < 0) {
     56 			ERR(handle, "could not copy MLS level");
     57 			context_destroy(&context);
     58 			goto err;
     59 		}
     60 		if (mls_level_cpy(&context.range.level[1],
     61 				  &usrdatum->exp_dfltlevel) < 0) {
     62 			ERR(handle, "could not copy MLS level");
     63 			context_destroy(&context);
     64 			goto err;
     65 		}
     66 		if (mls_to_string(handle, policydb, &context, &str) < 0) {
     67 			context_destroy(&context);
     68 			goto err;
     69 		}
     70 		context_destroy(&context);
     71 
     72 		if (sepol_user_set_mlslevel(handle, tmp_record, str) < 0) {
     73 			free(str);
     74 			goto err;
     75 		}
     76 		free(str);
     77 
     78 		context_init(&context);
     79 		if (mls_range_cpy(&context.range, &usrdatum->exp_range) < 0) {
     80 			ERR(handle, "could not copy MLS range");
     81 			context_destroy(&context);
     82 			goto err;
     83 		}
     84 		if (mls_to_string(handle, policydb, &context, &str) < 0) {
     85 			context_destroy(&context);
     86 			goto err;
     87 		}
     88 		context_destroy(&context);
     89 
     90 		if (sepol_user_set_mlsrange(handle, tmp_record, str) < 0) {
     91 			free(str);
     92 			goto err;
     93 		}
     94 		free(str);
     95 	}
     96 
     97 	*record = tmp_record;
     98 	return STATUS_SUCCESS;
     99 
    100       err:
    101 	/* FIXME: handle error */
    102 	sepol_user_free(tmp_record);
    103 	return STATUS_ERR;
    104 }
    105 
    106 int sepol_user_modify(sepol_handle_t * handle,
    107 		      sepol_policydb_t * p,
    108 		      const sepol_user_key_t * key, const sepol_user_t * user)
    109 {
    110 
    111 	policydb_t *policydb = &p->p;
    112 
    113 	/* For user data */
    114 	const char *cname, *cmls_level, *cmls_range;
    115 	char *name = NULL;
    116 
    117 	const char **roles = NULL;
    118 	unsigned int num_roles = 0;
    119 
    120 	/* Low-level representation */
    121 	user_datum_t *usrdatum = NULL;
    122 	role_datum_t *roldatum;
    123 	unsigned int i;
    124 
    125 	context_struct_t context;
    126 	unsigned bit;
    127 	int new = 0;
    128 
    129 	ebitmap_node_t *rnode;
    130 
    131 	/* First, extract all the data */
    132 	sepol_user_key_unpack(key, &cname);
    133 
    134 	cmls_level = sepol_user_get_mlslevel(user);
    135 	cmls_range = sepol_user_get_mlsrange(user);
    136 
    137 	/* Make sure that worked properly */
    138 	if (sepol_user_get_roles(handle, user, &roles, &num_roles) < 0)
    139 		goto err;
    140 
    141 	/* Now, see if a user exists */
    142 	usrdatum = hashtab_search(policydb->p_users.table, cname);
    143 
    144 	/* If it does, we will modify it */
    145 	if (usrdatum) {
    146 
    147 		int value_cp = usrdatum->s.value;
    148 		user_datum_destroy(usrdatum);
    149 		user_datum_init(usrdatum);
    150 		usrdatum->s.value = value_cp;
    151 
    152 		/* Otherwise, create a new one */
    153 	} else {
    154 		usrdatum = (user_datum_t *) malloc(sizeof(user_datum_t));
    155 		if (!usrdatum)
    156 			goto omem;
    157 		user_datum_init(usrdatum);
    158 		new = 1;
    159 	}
    160 
    161 	/* For every role */
    162 	for (i = 0; i < num_roles; i++) {
    163 
    164 		/* Search for the role */
    165 		roldatum = hashtab_search(policydb->p_roles.table, roles[i]);
    166 		if (!roldatum) {
    167 			ERR(handle, "undefined role %s for user %s",
    168 			    roles[i], cname);
    169 			goto err;
    170 		}
    171 
    172 		/* Set the role and every role it dominates */
    173 		ebitmap_for_each_bit(&roldatum->dominates, rnode, bit) {
    174 			if (ebitmap_node_get_bit(rnode, bit)) {
    175 				if (ebitmap_set_bit
    176 				    (&(usrdatum->roles.roles), bit, 1))
    177 					goto omem;
    178 			}
    179 		}
    180 	}
    181 
    182 	/* For MLS systems */
    183 	if (policydb->mls) {
    184 
    185 		/* MLS level */
    186 		if (cmls_level == NULL) {
    187 			ERR(handle, "MLS is enabled, but no MLS "
    188 			    "default level was defined for user %s", cname);
    189 			goto err;
    190 		}
    191 
    192 		context_init(&context);
    193 		if (mls_from_string(handle, policydb, cmls_level, &context) < 0) {
    194 			context_destroy(&context);
    195 			goto err;
    196 		}
    197 		if (mls_level_cpy(&usrdatum->exp_dfltlevel,
    198 				  &context.range.level[0]) < 0) {
    199 			ERR(handle, "could not copy MLS level %s", cmls_level);
    200 			context_destroy(&context);
    201 			goto err;
    202 		}
    203 		context_destroy(&context);
    204 
    205 		/* MLS range */
    206 		if (cmls_range == NULL) {
    207 			ERR(handle, "MLS is enabled, but no MLS"
    208 			    "range was defined for user %s", cname);
    209 			goto err;
    210 		}
    211 
    212 		context_init(&context);
    213 		if (mls_from_string(handle, policydb, cmls_range, &context) < 0) {
    214 			context_destroy(&context);
    215 			goto err;
    216 		}
    217 		if (mls_range_cpy(&usrdatum->exp_range, &context.range) < 0) {
    218 			ERR(handle, "could not copy MLS range %s", cmls_range);
    219 			context_destroy(&context);
    220 			goto err;
    221 		}
    222 		context_destroy(&context);
    223 	} else if (cmls_level != NULL || cmls_range != NULL) {
    224 		ERR(handle, "MLS is disabled, but MLS level/range "
    225 		    "was found for user %s", cname);
    226 		goto err;
    227 	}
    228 
    229 	/* If there are no errors, and this is a new user, add the user to policy */
    230 	if (new) {
    231 		void *tmp_ptr;
    232 
    233 		/* Ensure reverse lookup array has enough space */
    234 		tmp_ptr = realloc(policydb->user_val_to_struct,
    235 				  (policydb->p_users.nprim +
    236 				   1) * sizeof(user_datum_t *));
    237 		if (!tmp_ptr)
    238 			goto omem;
    239 		policydb->user_val_to_struct = tmp_ptr;
    240 		policydb->user_val_to_struct[policydb->p_users.nprim] = NULL;
    241 
    242 		tmp_ptr = realloc(policydb->sym_val_to_name[SYM_USERS],
    243 				  (policydb->p_users.nprim +
    244 				   1) * sizeof(char *));
    245 		if (!tmp_ptr)
    246 			goto omem;
    247 		policydb->sym_val_to_name[SYM_USERS] = tmp_ptr;
    248 		policydb->p_user_val_to_name[policydb->p_users.nprim] = NULL;
    249 
    250 		/* Need to copy the user name */
    251 		name = strdup(cname);
    252 		if (!name)
    253 			goto omem;
    254 
    255 		/* Store user */
    256 		usrdatum->s.value = ++policydb->p_users.nprim;
    257 		if (hashtab_insert(policydb->p_users.table, name,
    258 				   (hashtab_datum_t) usrdatum) < 0)
    259 			goto omem;
    260 
    261 		/* Set up reverse entry */
    262 		policydb->p_user_val_to_name[usrdatum->s.value - 1] = name;
    263 		policydb->user_val_to_struct[usrdatum->s.value - 1] = usrdatum;
    264 		name = NULL;
    265 
    266 		/* Expand roles */
    267 		if (role_set_expand(&usrdatum->roles, &usrdatum->cache,
    268 				    policydb, NULL, NULL)) {
    269 			ERR(handle, "unable to expand role set");
    270 			goto err;
    271 		}
    272 	}
    273 
    274 	free(roles);
    275 	return STATUS_SUCCESS;
    276 
    277       omem:
    278 	ERR(handle, "out of memory");
    279 
    280       err:
    281 	ERR(handle, "could not load %s into policy", name);
    282 
    283 	free(name);
    284 	free(roles);
    285 	if (new && usrdatum) {
    286 		role_set_destroy(&usrdatum->roles);
    287 		free(usrdatum);
    288 	}
    289 	return STATUS_ERR;
    290 }
    291 
    292 int sepol_user_exists(sepol_handle_t * handle __attribute__ ((unused)),
    293 		      const sepol_policydb_t * p,
    294 		      const sepol_user_key_t * key, int *response)
    295 {
    296 
    297 	const policydb_t *policydb = &p->p;
    298 
    299 	const char *cname;
    300 	sepol_user_key_unpack(key, &cname);
    301 
    302 	*response = (hashtab_search(policydb->p_users.table, cname) != NULL);
    303 
    304 	return STATUS_SUCCESS;
    305 }
    306 
    307 int sepol_user_count(sepol_handle_t * handle __attribute__ ((unused)),
    308 		     const sepol_policydb_t * p, unsigned int *response)
    309 {
    310 
    311 	const policydb_t *policydb = &p->p;
    312 	*response = policydb->p_users.nprim;
    313 
    314 	return STATUS_SUCCESS;
    315 }
    316 
    317 int sepol_user_query(sepol_handle_t * handle,
    318 		     const sepol_policydb_t * p,
    319 		     const sepol_user_key_t * key, sepol_user_t ** response)
    320 {
    321 
    322 	const policydb_t *policydb = &p->p;
    323 	user_datum_t *usrdatum = NULL;
    324 
    325 	const char *cname;
    326 	sepol_user_key_unpack(key, &cname);
    327 
    328 	usrdatum = hashtab_search(policydb->p_users.table, cname);
    329 
    330 	if (!usrdatum) {
    331 		*response = NULL;
    332 		return STATUS_SUCCESS;
    333 	}
    334 
    335 	if (user_to_record(handle, policydb, usrdatum->s.value - 1, response) <
    336 	    0)
    337 		goto err;
    338 
    339 	return STATUS_SUCCESS;
    340 
    341       err:
    342 	ERR(handle, "could not query user %s", cname);
    343 	return STATUS_ERR;
    344 }
    345 
    346 int sepol_user_iterate(sepol_handle_t * handle,
    347 		       const sepol_policydb_t * p,
    348 		       int (*fn) (const sepol_user_t * user,
    349 				  void *fn_arg), void *arg)
    350 {
    351 
    352 	const policydb_t *policydb = &p->p;
    353 	unsigned int nusers = policydb->p_users.nprim;
    354 	sepol_user_t *user = NULL;
    355 	unsigned int i;
    356 
    357 	/* For each user */
    358 	for (i = 0; i < nusers; i++) {
    359 
    360 		int status;
    361 
    362 		if (user_to_record(handle, policydb, i, &user) < 0)
    363 			goto err;
    364 
    365 		/* Invoke handler */
    366 		status = fn(user, arg);
    367 		if (status < 0)
    368 			goto err;
    369 
    370 		sepol_user_free(user);
    371 		user = NULL;
    372 
    373 		/* Handler requested exit */
    374 		if (status > 0)
    375 			break;
    376 	}
    377 
    378 	return STATUS_SUCCESS;
    379 
    380       err:
    381 	ERR(handle, "could not iterate over users");
    382 	sepol_user_free(user);
    383 	return STATUS_ERR;
    384 }
    385