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