| /* Copyright (C) 2005 Red Hat, Inc. */ |
| |
| struct semanage_seuser; |
| struct semanage_seuser_key; |
| typedef struct semanage_seuser_key record_key_t; |
| typedef struct semanage_seuser record_t; |
| #define DBASE_RECORD_DEFINED |
| |
| #include <sepol/policydb.h> |
| #include <sepol/context.h> |
| #include <libaudit.h> |
| #include <errno.h> |
| #include "user_internal.h" |
| #include "seuser_internal.h" |
| #include "handle.h" |
| #include "database.h" |
| #include "debug.h" |
| #include "string.h" |
| #include <stdlib.h> |
| |
| static char *semanage_user_roles(semanage_handle_t * handle, const char *sename) { |
| char *roles = NULL; |
| unsigned int num_roles; |
| size_t i; |
| size_t size = 0; |
| const char **roles_arr; |
| semanage_user_key_t *key = NULL; |
| semanage_user_t * user; |
| if (semanage_user_key_create(handle, sename, &key) >= 0) { |
| if (semanage_user_query(handle, key, &user) >= 0) { |
| if (semanage_user_get_roles(handle, |
| user, |
| &roles_arr, |
| &num_roles) >= 0) { |
| for (i = 0; i<num_roles; i++) { |
| size += (strlen(roles_arr[i]) + 1); |
| } |
| if (num_roles == 0) { |
| roles = strdup(""); |
| } else { |
| roles = malloc(size); |
| if (roles) { |
| strcpy(roles,roles_arr[0]); |
| for (i = 1; i<num_roles; i++) { |
| strcat(roles,","); |
| strcat(roles,roles_arr[i]); |
| } |
| } |
| } |
| } |
| semanage_user_free(user); |
| } |
| semanage_user_key_free(key); |
| } |
| return roles; |
| } |
| |
| static int semanage_seuser_audit(semanage_handle_t * handle, |
| const semanage_seuser_t * seuser, |
| const semanage_seuser_t * previous, |
| int audit_type, |
| int success) { |
| const char *name = NULL; |
| const char *sename = NULL; |
| char *roles = NULL; |
| const char *mls = NULL; |
| const char *psename = NULL; |
| const char *pmls = NULL; |
| char *proles = NULL; |
| char msg[1024]; |
| const char *sep = "-"; |
| int rc = -1; |
| strcpy(msg, "login"); |
| if (previous) { |
| name = semanage_seuser_get_name(previous); |
| psename = semanage_seuser_get_sename(previous); |
| pmls = semanage_seuser_get_mlsrange(previous); |
| proles = semanage_user_roles(handle, psename); |
| } |
| if (seuser) { |
| name = semanage_seuser_get_name(seuser); |
| sename = semanage_seuser_get_sename(seuser); |
| mls = semanage_seuser_get_mlsrange(seuser); |
| roles = semanage_user_roles(handle, sename); |
| } |
| if (audit_type != AUDIT_ROLE_REMOVE) { |
| if (sename && (!psename || strcmp(psename, sename) != 0)) { |
| strcat(msg,sep); |
| strcat(msg,"sename"); |
| sep = ","; |
| } |
| if (roles && (!proles || strcmp(proles, roles) != 0)) { |
| strcat(msg,sep); |
| strcat(msg,"role"); |
| sep = ","; |
| } |
| if (mls && (!pmls || strcmp(pmls, mls) != 0)) { |
| strcat(msg,sep); |
| strcat(msg,"range"); |
| } |
| } |
| |
| int fd = audit_open(); |
| if (fd < 0) |
| { |
| /* If kernel doesn't support audit, bail out */ |
| if (errno == EINVAL || errno == EPROTONOSUPPORT || errno == EAFNOSUPPORT) { |
| rc = 0; |
| goto err; |
| } |
| rc = fd; |
| goto err; |
| } |
| audit_log_semanage_message(fd, audit_type, NULL, msg, name, 0, sename, roles, mls, psename, proles, pmls, NULL, NULL,NULL, success); |
| rc = 0; |
| err: |
| audit_close(fd); |
| free(roles); |
| free(proles); |
| return rc; |
| } |
| |
| int semanage_seuser_modify_local(semanage_handle_t * handle, |
| const semanage_seuser_key_t * key, |
| const semanage_seuser_t * data) |
| { |
| int rc; |
| void *callback = (void *) handle->msg_callback; |
| dbase_config_t *dconfig = semanage_seuser_dbase_local(handle); |
| const char *sename = semanage_seuser_get_sename(data); |
| const char *mls_range = semanage_seuser_get_mlsrange(data); |
| semanage_seuser_t *previous = NULL; |
| semanage_seuser_t *new = NULL; |
| |
| if (!sename) { |
| errno = EINVAL; |
| return -1; |
| } |
| rc = semanage_seuser_clone(handle, data, &new); |
| if (rc < 0) { |
| goto err; |
| } |
| |
| if (!mls_range && semanage_mls_enabled(handle)) { |
| semanage_user_key_t *ukey = NULL; |
| semanage_user_t *u = NULL; |
| rc = semanage_user_key_create(handle, sename, &ukey); |
| if (rc < 0) |
| goto err; |
| |
| rc = semanage_user_query(handle, ukey, &u); |
| semanage_user_key_free(ukey); |
| if (rc >= 0 ) { |
| mls_range = semanage_user_get_mlsrange(u); |
| rc = semanage_seuser_set_mlsrange(handle, new, mls_range); |
| semanage_user_free(u); |
| } |
| if (rc < 0) |
| goto err; |
| } |
| |
| handle->msg_callback = NULL; |
| (void) semanage_seuser_query(handle, key, &previous); |
| handle->msg_callback = callback; |
| rc = dbase_modify(handle, dconfig, key, new); |
| if (semanage_seuser_audit(handle, new, previous, AUDIT_ROLE_ASSIGN, rc == 0) < 0) |
| rc = -1; |
| err: |
| if (previous) |
| semanage_seuser_free(previous); |
| semanage_seuser_free(new); |
| return rc; |
| } |
| |
| int semanage_seuser_del_local(semanage_handle_t * handle, |
| const semanage_seuser_key_t * key) |
| { |
| int rc; |
| semanage_seuser_t *seuser = NULL; |
| dbase_config_t *dconfig = semanage_seuser_dbase_local(handle); |
| rc = dbase_del(handle, dconfig, key); |
| semanage_seuser_query(handle, key, &seuser); |
| if (semanage_seuser_audit(handle, NULL, seuser, AUDIT_ROLE_REMOVE, rc == 0) < 0) |
| rc = -1; |
| if (seuser) |
| semanage_seuser_free(seuser); |
| return rc; |
| } |
| |
| int semanage_seuser_query_local(semanage_handle_t * handle, |
| const semanage_seuser_key_t * key, |
| semanage_seuser_t ** response) |
| { |
| |
| dbase_config_t *dconfig = semanage_seuser_dbase_local(handle); |
| return dbase_query(handle, dconfig, key, response); |
| } |
| |
| int semanage_seuser_exists_local(semanage_handle_t * handle, |
| const semanage_seuser_key_t * key, |
| int *response) |
| { |
| |
| dbase_config_t *dconfig = semanage_seuser_dbase_local(handle); |
| return dbase_exists(handle, dconfig, key, response); |
| } |
| |
| int semanage_seuser_count_local(semanage_handle_t * handle, |
| unsigned int *response) |
| { |
| |
| dbase_config_t *dconfig = semanage_seuser_dbase_local(handle); |
| return dbase_count(handle, dconfig, response); |
| } |
| |
| int semanage_seuser_iterate_local(semanage_handle_t * handle, |
| int (*handler) (const semanage_seuser_t * |
| record, void *varg), |
| void *handler_arg) |
| { |
| |
| dbase_config_t *dconfig = semanage_seuser_dbase_local(handle); |
| return dbase_iterate(handle, dconfig, handler, handler_arg); |
| } |
| |
| |
| int semanage_seuser_list_local(semanage_handle_t * handle, |
| semanage_seuser_t *** records, |
| unsigned int *count) |
| { |
| |
| dbase_config_t *dconfig = semanage_seuser_dbase_local(handle); |
| return dbase_list(handle, dconfig, records, count); |
| } |
| |
| struct validate_handler_arg { |
| semanage_handle_t *handle; |
| const sepol_policydb_t *policydb; |
| }; |
| |
| static int validate_handler(const semanage_seuser_t * seuser, void *varg) |
| { |
| |
| semanage_user_t *user = NULL; |
| semanage_user_key_t *key = NULL; |
| int exists, mls_ok; |
| |
| /* Unpack varg */ |
| struct validate_handler_arg *arg = (struct validate_handler_arg *)varg; |
| semanage_handle_t *handle = arg->handle; |
| const sepol_policydb_t *policydb = arg->policydb; |
| |
| /* Unpack seuser */ |
| const char *name = semanage_seuser_get_name(seuser); |
| const char *sename = semanage_seuser_get_sename(seuser); |
| const char *mls_range = semanage_seuser_get_mlsrange(seuser); |
| const char *user_mls_range; |
| |
| /* Make sure the (SElinux) user exists */ |
| if (semanage_user_key_create(handle, sename, &key) < 0) |
| goto err; |
| if (semanage_user_exists(handle, key, &exists) < 0) |
| goto err; |
| if (!exists) { |
| ERR(handle, "selinux user %s does not exist", sename); |
| goto invalid; |
| } |
| |
| /* Verify that the mls range is valid, and that it's contained |
| * within the (SELinux) user mls range. This range is optional */ |
| if (mls_range && sepol_policydb_mls_enabled(policydb)) { |
| |
| if (semanage_user_query(handle, key, &user) < 0) |
| goto err; |
| user_mls_range = semanage_user_get_mlsrange(user); |
| |
| if (sepol_mls_check(handle->sepolh, policydb, mls_range) < 0) |
| goto invalid; |
| if (sepol_mls_contains(handle->sepolh, policydb, |
| user_mls_range, mls_range, &mls_ok) < 0) |
| goto err; |
| |
| if (!mls_ok) { |
| ERR(handle, "MLS range %s for Unix user %s " |
| "exceeds allowed range %s for SELinux user %s", |
| mls_range, name, user_mls_range, sename); |
| goto invalid; |
| } |
| |
| } else if (mls_range) { |
| ERR(handle, "MLS is disabled, but MLS range %s " |
| "was found for Unix user %s", mls_range, name); |
| goto invalid; |
| } |
| |
| semanage_user_key_free(key); |
| semanage_user_free(user); |
| return 0; |
| |
| err: |
| ERR(handle, "could not check if seuser mapping for %s is valid", name); |
| semanage_user_key_free(key); |
| semanage_user_free(user); |
| return -1; |
| |
| invalid: |
| if (mls_range) |
| ERR(handle, "seuser mapping [%s -> (%s, %s)] is invalid", |
| name, sename, mls_range); |
| else |
| ERR(handle, "seuser mapping [%s -> %s] is invalid", |
| name, sename); |
| semanage_user_key_free(key); |
| semanage_user_free(user); |
| return -1; |
| } |
| |
| /* This function may not be called outside a transaction, or |
| * it will (1) deadlock, because iterate is not reentrant outside |
| * a transaction, and (2) be racy, because it makes multiple dbase calls */ |
| |
| int semanage_seuser_validate_local(semanage_handle_t * handle, |
| const sepol_policydb_t * policydb) |
| { |
| |
| struct validate_handler_arg arg; |
| arg.handle = handle; |
| arg.policydb = policydb; |
| return semanage_seuser_iterate_local(handle, validate_handler, &arg); |
| } |