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