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