diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/db/sysdb_selinux.c | 107 | ||||
-rw-r--r-- | src/providers/ipa/ipa_selinux.c | 412 | ||||
-rw-r--r-- | src/providers/ipa/ipa_selinux.h | 7 | ||||
-rw-r--r-- | src/responder/pam/pamsrv_cmd.c | 309 | ||||
-rw-r--r-- | src/util/sss_selinux.c | 8 | ||||
-rw-r--r-- | src/util/sss_selinux.h | 2 |
6 files changed, 393 insertions, 452 deletions
diff --git a/src/db/sysdb_selinux.c b/src/db/sysdb_selinux.c index b27e0a92..80cfe539 100644 --- a/src/db/sysdb_selinux.c +++ b/src/db/sysdb_selinux.c @@ -336,113 +336,6 @@ sysdb_get_selinux_usermaps(TALLOC_CTX *mem_ctx, return EOK; } -errno_t sysdb_search_selinux_usermap_by_username(TALLOC_CTX *mem_ctx, - struct sysdb_ctx *sysdb, - struct sss_domain_info *domain, - const char *username, - struct ldb_message ***_usermaps) -{ - TALLOC_CTX *tmp_ctx; - struct ldb_message **msgs = NULL; - const char *attrs[] = { SYSDB_NAME, - SYSDB_USER_CATEGORY, - SYSDB_HOST_CATEGORY, - SYSDB_ORIG_MEMBER_USER, - SYSDB_ORIG_MEMBER_HOST, - SYSDB_SELINUX_HOST_PRIORITY, - SYSDB_SELINUX_USER, - NULL }; - struct sysdb_attrs *user; - struct sysdb_attrs *tmp_attrs; - struct ldb_message **usermaps = NULL; - size_t msgs_count = 0; - size_t usermaps_cnt; - uint32_t priority = 0; - uint32_t host_priority = 0; - uint32_t top_priority = 0; - errno_t ret; - int i; - - tmp_ctx = talloc_new(NULL); - if (!tmp_ctx) { - return ENOMEM; - } - - /* Now extract user attributes */ - ret = sss_selinux_extract_user(tmp_ctx, sysdb, domain, username, &user); - if (ret != EOK) { - goto done; - } - - /* Now extract all SELinux user maps */ - ret = sysdb_get_selinux_usermaps(tmp_ctx, sysdb, domain, - attrs, &msgs_count, &msgs); - if (ret) { - goto done; - } - - /* Now filter those that match */ - tmp_attrs = talloc_zero(tmp_ctx, struct sysdb_attrs); - if (tmp_attrs == NULL) { - ret = ENOMEM; - goto done; - } - - usermaps = talloc_zero_array(tmp_ctx, struct ldb_message *, msgs_count + 1); - if (usermaps == NULL) { - ret = ENOMEM; - goto done; - } - - usermaps_cnt = 0; - for (i = 0; i < msgs_count; i++) { - tmp_attrs->a = msgs[i]->elements; - tmp_attrs->num = msgs[i]->num_elements; - - if (sss_selinux_match(tmp_attrs, user, NULL, &priority)) { - priority &= ~(SELINUX_PRIORITY_HOST_NAME | - SELINUX_PRIORITY_HOST_GROUP | - SELINUX_PRIORITY_HOST_CAT); - - /* Now figure out host priority */ - ret = sysdb_attrs_get_uint32_t(tmp_attrs, - SYSDB_SELINUX_HOST_PRIORITY, - &host_priority); - if (ret != EOK) { - continue; - } - - priority += host_priority; - if (priority < top_priority) { - /* This rule has lower priority than what we already have, - * skip it */ - continue; - } else if (priority > top_priority) { - /* If the rule has higher priority, drop what we already - * have */ - while (usermaps_cnt > 0) { - usermaps_cnt--; - talloc_zfree(usermaps[usermaps_cnt]); - } - top_priority = priority; - } - - - usermaps[usermaps_cnt] = talloc_steal(usermaps, msgs[i]); - usermaps_cnt++; - } else { - talloc_zfree(msgs[i]); - } - } - - *_usermaps = talloc_steal(mem_ctx, usermaps); - - ret = EOK; -done: - talloc_zfree(tmp_ctx); - return ret; -} - errno_t sysdb_search_selinux_config(TALLOC_CTX *mem_ctx, struct sysdb_ctx *sysdb, struct sss_domain_info *domain, diff --git a/src/providers/ipa/ipa_selinux.c b/src/providers/ipa/ipa_selinux.c index 29e98870..0e65a377 100644 --- a/src/providers/ipa/ipa_selinux.c +++ b/src/providers/ipa/ipa_selinux.c @@ -21,7 +21,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ - +#include <selinux/selinux.h> #include <security/pam_modules.h> #include "db/sysdb_selinux.h" @@ -37,6 +37,8 @@ #include "providers/ipa/ipa_selinux_common.h" #include "providers/ipa/ipa_selinux_maps.h" +#ifdef HAVE_SELINUX_LOGIN_DIR + static struct tevent_req * ipa_get_selinux_send(TALLOC_CTX *mem_ctx, struct be_ctx *be_ctx, @@ -65,12 +67,14 @@ static void ipa_get_config_step(struct tevent_req *req); static void ipa_get_selinux_config_done(struct tevent_req *subreq); static void ipa_get_selinux_maps_done(struct tevent_req *subreq); static void ipa_get_selinux_hbac_done(struct tevent_req *subreq); -static errno_t ipa_selinux_process_maps(struct sysdb_attrs *user, +static errno_t ipa_selinux_process_maps(TALLOC_CTX *mem_ctx, + struct sysdb_attrs *user, struct sysdb_attrs *host, struct sysdb_attrs **selinux_maps, size_t selinux_map_count, struct sysdb_attrs **hbac_rules, - size_t hbac_rule_count); + size_t hbac_rule_count, + struct sysdb_attrs ***usermaps); struct ipa_selinux_op_ctx { struct be_req *be_req; @@ -184,6 +188,14 @@ fail: return NULL; } +static errno_t create_order_array(TALLOC_CTX *mem_ctx, const char *map_order, + char ***_order_array, size_t *_order_count); +static errno_t choose_best_seuser(struct sysdb_attrs **usermaps, + struct pam_data *pd, + char **order_array, int order_count, + const char *default_user); + + static void ipa_selinux_handler_done(struct tevent_req *req) { struct ipa_selinux_op_ctx *op_ctx = tevent_req_callback_data(req, struct ipa_selinux_op_ctx); @@ -199,6 +211,9 @@ static void ipa_selinux_handler_done(struct tevent_req *req) char *map_order = NULL; size_t hbac_count = 0; struct sysdb_attrs **hbac_rules = 0; + struct sysdb_attrs **best_match_maps; + size_t order_count; + char **order_array; ret = ipa_get_selinux_recv(req, breq, &map_count, &maps, &hbac_count, &hbac_rules, @@ -207,10 +222,31 @@ static void ipa_selinux_handler_done(struct tevent_req *req) goto fail; } - ret = ipa_selinux_process_maps(op_ctx->user, op_ctx->host, + /* Process the maps and return list of best matches (maps with + * highest priority). The input maps are also parent memory + * context for the output list of best matches. The best match + * maps should never be freed explicitly but always through + * their parent (or any indirect parent) */ + ret = ipa_selinux_process_maps(maps, op_ctx->user, op_ctx->host, maps, map_count, - hbac_rules, hbac_count); + hbac_rules, hbac_count, &best_match_maps); + if (ret != EOK) { + goto fail; + } + + ret = create_order_array(op_ctx, map_order, + &order_array, &order_count); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, + ("Failed to create ordered SELinux users array.\n")); + goto fail; + } + + ret = choose_best_seuser(best_match_maps, pd, order_array, order_count, + default_user); if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, + ("Failed to evaluate ordered SELinux users array.\n")); goto fail; } @@ -272,22 +308,30 @@ ipa_selinux_process_seealso_maps(struct sysdb_attrs *user, struct sysdb_attrs **seealso_rules, size_t seealso_rules_count, struct sysdb_attrs **hbac_rules, - size_t hbac_rule_count); + size_t hbac_rule_count, + uint32_t top_priority, + struct sysdb_attrs **usermaps, + size_t best_match_maps_cnt); static errno_t -ipa_selinux_process_maps(struct sysdb_attrs *user, +ipa_selinux_process_maps(TALLOC_CTX *mem_ctx, + struct sysdb_attrs *user, struct sysdb_attrs *host, struct sysdb_attrs **selinux_maps, size_t selinux_map_count, struct sysdb_attrs **hbac_rules, - size_t hbac_rule_count) + size_t hbac_rule_count, + struct sysdb_attrs ***_usermaps) { TALLOC_CTX *tmp_ctx; int i; errno_t ret; uint32_t priority = 0; + uint32_t top_priority = 0; struct sysdb_attrs **seealso_rules; - size_t num_seealso_rules; + size_t num_seealso_rules = 0; const char *seealso_str; + struct sysdb_attrs **usermaps; + size_t best_match_maps_cnt = 0; tmp_ctx = talloc_new(NULL); if (!tmp_ctx) { @@ -300,23 +344,36 @@ ipa_selinux_process_maps(struct sysdb_attrs *user, ret = ENOMEM; goto done; } - num_seealso_rules = 0; + + usermaps = talloc_zero_array(tmp_ctx, struct sysdb_attrs *, selinux_map_count + 1); + if (usermaps == NULL) { + ret = ENOMEM; + goto done; + } for (i = 0; i < selinux_map_count; i++) { - if (sss_selinux_match(selinux_maps[i], user, - host, &priority)) { - priority &= ~(SELINUX_PRIORITY_USER_NAME | - SELINUX_PRIORITY_USER_GROUP | - SELINUX_PRIORITY_USER_CAT); - ret = sysdb_attrs_add_uint32(selinux_maps[i], - SYSDB_SELINUX_HOST_PRIORITY, - priority); - if (ret != EOK) { - goto done; + if (sss_selinux_match(selinux_maps[i], user, host, &priority)) { + if (priority < top_priority) { + /* This rule has lower priority than what we already have, + * skip it. */ + continue; + } else if (priority > top_priority) { + /* This rule has higher priority, drop what we already have */ + while (best_match_maps_cnt > 0) { + best_match_maps_cnt--; + usermaps[best_match_maps_cnt] = NULL; + } + top_priority = priority; } + + usermaps[best_match_maps_cnt] = selinux_maps[i]; + best_match_maps_cnt++; + continue; } + /* SELinux map did not matched -> check sealso attribute for + * possible HBAC match */ ret = sysdb_attrs_get_string(selinux_maps[i], SYSDB_SELINUX_SEEALSO, &seealso_str); if (ret == ENOENT) { @@ -331,11 +388,14 @@ ipa_selinux_process_maps(struct sysdb_attrs *user, ret = ipa_selinux_process_seealso_maps(user, host, seealso_rules, num_seealso_rules, - hbac_rules, hbac_rule_count); + hbac_rules, hbac_rule_count, + top_priority, usermaps, best_match_maps_cnt); if (ret != EOK) { goto done; } + *_usermaps = talloc_steal(mem_ctx, usermaps); + ret = EOK; done: talloc_free(tmp_ctx); @@ -348,15 +408,18 @@ ipa_selinux_process_seealso_maps(struct sysdb_attrs *user, struct sysdb_attrs **seealso_rules, size_t seealso_rules_count, struct sysdb_attrs **hbac_rules, - size_t hbac_rule_count) + size_t hbac_rule_count, + uint32_t top_priority, + struct sysdb_attrs **usermaps, + size_t best_match_maps_cnt) { int i, j; errno_t ret; struct ldb_message_element *el; - uint32_t priority = 0; struct sysdb_attrs *usermap; const char *seealso_dn; const char *hbac_dn; + uint32_t priority; for (i = 0; i < hbac_rule_count; i++) { ret = sysdb_attrs_get_string(hbac_rules[i], SYSDB_ORIG_DN, &hbac_dn); @@ -399,16 +462,24 @@ ipa_selinux_process_seealso_maps(struct sysdb_attrs *user, DEBUG(SSSDBG_TRACE_FUNC, ("HBAC rule [%s] matched, copying its" "attributes to SELinux user map [%s]\n", hbac_dn, seealso_dn)); - priority &= ~(SELINUX_PRIORITY_USER_NAME | - SELINUX_PRIORITY_USER_GROUP | - SELINUX_PRIORITY_USER_CAT); - ret = sysdb_attrs_add_uint32(usermap, - SYSDB_SELINUX_HOST_PRIORITY, - priority); - if (ret != EOK) { - return ret; + + /* Selinux maps priority evaluation removed --DELETE this comment before pushing*/ + if (priority < top_priority) { + /* This rule has lower priority than what we already have, + * skip it. */ + continue; + } else if (priority > top_priority) { + /* This rule has higher priority, drop what we already have */ + while (best_match_maps_cnt > 0) { + best_match_maps_cnt--; + usermaps[best_match_maps_cnt] = NULL; + } + top_priority = priority; } + usermaps[best_match_maps_cnt] = usermap; + best_match_maps_cnt++; + ret = sysdb_attrs_copy_values(hbac_rules[i], usermap, SYSDB_ORIG_MEMBER_USER); if (ret != EOK) { return ret; @@ -428,6 +499,271 @@ ipa_selinux_process_seealso_maps(struct sysdb_attrs *user, return EOK; } +static errno_t create_order_array(TALLOC_CTX *mem_ctx, const char *map_order, + char ***_order_array, size_t *_order_count) +{ + TALLOC_CTX *tmp_ctx; + char *order = NULL; + char **order_array; + errno_t ret; + int i; + int len; + size_t order_count; + + tmp_ctx = talloc_new(NULL); + if (tmp_ctx == NULL) { + ret = ENOMEM; + goto done; + } + + order = talloc_strdup(tmp_ctx, map_order); + if (order == NULL) { + ret = ENOMEM; + goto done; + } + len = strlen(order); + + /* The "order" string contains one or more SELinux user records + * separated by $. Now we need to create an array of string from + * this one string. First find out how many elements in the array + * will be. This way only one alloc will be necessary for the array + */ + order_count = 1; + for (i = 0; i < len; i++) { + if (order[i] == '$') order_count++; + } + + order_array = talloc_array(tmp_ctx, char *, order_count); + if (order_array == NULL) { + ret = ENOMEM; + goto done; + } + + /* Now fill the array with pointers to the original string. Also + * use binary zeros to make multiple string out of the one. + */ + order_array[0] = order; + order_count = 1; + for (i = 0; i < len; i++) { + if (order[i] == '$') { + order[i] = '\0'; + order_array[order_count] = &order[i+1]; + order_count++; + } + } + + *_order_array = talloc_steal(mem_ctx, order_array); + *_order_count = order_count; + + ret = EOK; +done: + talloc_free(tmp_ctx); + return ret; +} + +static errno_t write_selinux_login_file(const char *username, char *string); +static errno_t remove_selinux_login_file(const char *username); + +/* Choose best selinux user based on given order and write + * the user to selinux login file. */ +static errno_t choose_best_seuser(struct sysdb_attrs **usermaps, + struct pam_data *pd, + char **order_array, int order_count, + const char *default_user) +{ + TALLOC_CTX *tmp_ctx; + char *file_content = NULL; + const char *tmp_str; + errno_t ret, err; + int i, j; + + tmp_ctx = talloc_new(NULL); + if (tmp_ctx == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, ("talloc_new() failed\n")); + return ENOMEM; + } + + /* If no maps match, we'll use the default SELinux user from the + * config */ + file_content = talloc_strdup(tmp_ctx, default_user); + if (file_content == NULL) { + ret = ENOMEM; + goto done; + } + + /* Iterate through the order array and try to find SELinux users + * in fetched maps. The order array contains all SELinux users + * allowed in the domain in the same order they should appear + * in the SELinux config file. If any user from the order array + * is not in fetched user maps, it means it should not be allowed + * for the user who is just logging in. + * + * Right now we have empty content of the SELinux config file, + * we shall add only those SELinux users that are present both in + * the order array and user maps applicable to the user who is + * logging in. + */ + for (i = 0; i < order_count; i++) { + for (j = 0; usermaps[j] != NULL; j++) { + tmp_str = sss_selinux_map_get_seuser(usermaps[j]); + + if (tmp_str && !strcasecmp(tmp_str, order_array[i])) { + /* If file_content contained something, overwrite it. + * This record has higher priority. + */ + talloc_zfree(file_content); + file_content = talloc_strdup(tmp_ctx, tmp_str); + if (file_content == NULL) { + ret = ENOMEM; + goto done; + } + break; + } + } + } + + ret = write_selinux_login_file(pd->user, file_content); +done: + if (!file_content) { + err = remove_selinux_login_file(pd->user); + /* Don't overwrite original error condition if there was one */ + if (ret == EOK) ret = err; + } + talloc_free(tmp_ctx); + return ret; +} + +static errno_t write_selinux_login_file(const char *username, char *string) +{ + char *path = NULL; + char *tmp_path = NULL; + ssize_t written; + int len; + int fd = -1; + mode_t oldmask; + TALLOC_CTX *tmp_ctx; + char *full_string = NULL; + int enforce; + errno_t ret = EOK; + + len = strlen(string); + if (len == 0) { + return EINVAL; + } + + tmp_ctx = talloc_new(NULL); + if (tmp_ctx == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, ("talloc_new() failed\n")); + return ENOMEM; + } + + path = selogin_path(tmp_ctx, username); + if (path == NULL) { + ret = ENOMEM; + goto done; + } + + tmp_path = talloc_asprintf(tmp_ctx, "%sXXXXXX", path); + if (tmp_path == NULL) { + ret = ENOMEM; + goto done; + } + + oldmask = umask(022); + fd = mkstemp(tmp_path); + ret = errno; + umask(oldmask); + if (fd < 0) { + if (ret == ENOENT) { + /* if selinux is disabled and selogin dir does not exist, + * just ignore the error */ + if (selinux_getenforcemode(&enforce) == 0 && enforce == -1) { + ret = EOK; + goto done; + } + + /* continue if we can't get enforce mode or selinux is enabled */ + } + + DEBUG(SSSDBG_OP_FAILURE, ("unable to create temp file [%s] " + "for SELinux data [%d]: %s\n", tmp_path, ret, strerror(ret))); + goto done; + } + + full_string = talloc_asprintf(tmp_ctx, "%s:%s", ALL_SERVICES, string); + if (full_string == NULL) { + ret = ENOMEM; + goto done; + } + + len = strlen(full_string); + + errno = 0; + written = sss_atomic_write_s(fd, full_string, len); + if (written == -1) { + ret = errno; + DEBUG(SSSDBG_OP_FAILURE, ("writing to SELinux data file %s" + "failed [%d]: %s", tmp_path, ret, + strerror(ret))); + goto done; + } + + if (written != len) { + DEBUG(SSSDBG_OP_FAILURE, ("Expected to write %d bytes, wrote %d", + written, len)); + ret = EIO; + goto done; + } + + errno = 0; + if (rename(tmp_path, path) < 0) { + ret = errno; + } else { + ret = EOK; + } + close(fd); + fd = -1; + +done: + if (fd != -1) { + close(fd); + if (unlink(tmp_path) < 0) { + DEBUG(SSSDBG_MINOR_FAILURE, ("Could not remove file [%s]", + tmp_path)); + } + } + + talloc_free(tmp_ctx); + return ret; +} + +static errno_t remove_selinux_login_file(const char *username) +{ + char *path; + errno_t ret; + + path = selogin_path(NULL, username); + if (!path) return ENOMEM; + + errno = 0; + ret = unlink(path); + if (ret < 0) { + ret = errno; + if (ret == ENOENT) { + /* Just return success if the file was not there */ + ret = EOK; + } else { + DEBUG(SSSDBG_OP_FAILURE, + ("Could not remove login file %s [%d]: %s\n", + path, ret, strerror(ret))); + } + } + + talloc_free(path); + return ret; +} + + /* A more generic request to gather all SELinux and HBAC rules. Updates * cache if necessary */ @@ -912,3 +1248,17 @@ ipa_get_selinux_recv(struct tevent_req *req, return EOK; } + +#else +/* Simply return success if HAVE_SELINUX_LOGIN_DIR is not defined. */ +void ipa_selinux_handler(struct be_req *be_req) +{ + struct be_ctx *be_ctx = be_req_get_be_ctx(be_req); + struct pam_data *pd; + + pd = talloc_get_type(be_req_get_data(be_req), struct pam_data); + + pd->pam_status = PAM_SUCCESS; + be_req_terminate(be_req, DP_ERR_OK, EOK, "Success"); +} +#endif diff --git a/src/providers/ipa/ipa_selinux.h b/src/providers/ipa/ipa_selinux.h index 60c22110..0f3fadd3 100644 --- a/src/providers/ipa/ipa_selinux.h +++ b/src/providers/ipa/ipa_selinux.h @@ -27,6 +27,13 @@ #include "providers/ldap/ldap_common.h" +#ifdef HAVE_SELINUX_LOGIN_DIR + +#define ALL_SERVICES "*" +#define selogin_path(mem_ctx, username) \ + talloc_asprintf(mem_ctx, "%s/logins/%s", selinux_policy_root(), username) +#endif + struct ipa_selinux_ctx { struct ipa_id_ctx *id_ctx; diff --git a/src/responder/pam/pamsrv_cmd.c b/src/responder/pam/pamsrv_cmd.c index 69791a0e..647f8276 100644 --- a/src/responder/pam/pamsrv_cmd.c +++ b/src/responder/pam/pamsrv_cmd.c @@ -22,7 +22,6 @@ #include <time.h> #include "util/util.h" -#include "util/sss_selinux.h" #include "util/auth_utils.h" #include "db/sysdb.h" #include "confdb/confdb.h" @@ -33,10 +32,6 @@ #include "responder/pam/pamsrv.h" #include "responder/pam/pam_helpers.h" #include "db/sysdb.h" -#include "db/sysdb_selinux.h" -#ifdef HAVE_SELINUX_LOGIN_DIR -#include <selinux/selinux.h> -#endif enum pam_verbosity { PAM_VERBOSITY_NO_MESSAGES = 0, @@ -371,298 +366,6 @@ fail: return ret; } -#ifdef HAVE_SELINUX_LOGIN_DIR - -#define ALL_SERVICES "*" -#define selogin_path(mem_ctx, username) \ - talloc_asprintf(mem_ctx, "%s/logins/%s", selinux_policy_root(), username) - -static errno_t write_selinux_login_file(const char *username, char *string) -{ - char *path = NULL; - char *tmp_path = NULL; - ssize_t written; - int len; - int fd = -1; - mode_t oldmask; - TALLOC_CTX *tmp_ctx; - char *full_string = NULL; - int enforce; - errno_t ret = EOK; - - len = strlen(string); - if (len == 0) { - return EINVAL; - } - - tmp_ctx = talloc_new(NULL); - if (tmp_ctx == NULL) { - DEBUG(SSSDBG_CRIT_FAILURE, ("talloc_new() failed\n")); - return ENOMEM; - } - - path = selogin_path(tmp_ctx, username); - if (path == NULL) { - ret = ENOMEM; - goto done; - } - - tmp_path = talloc_asprintf(tmp_ctx, "%sXXXXXX", path); - if (tmp_path == NULL) { - ret = ENOMEM; - goto done; - } - - oldmask = umask(022); - fd = mkstemp(tmp_path); - ret = errno; - umask(oldmask); - if (fd < 0) { - if (ret == ENOENT) { - /* if selinux is disabled and selogin dir does not exist, - * just ignore the error */ - if (selinux_getenforcemode(&enforce) == 0 && enforce == -1) { - ret = EOK; - goto done; - } - - /* continue if we can't get enforce mode or selinux is enabled */ - } - - DEBUG(SSSDBG_OP_FAILURE, ("unable to create temp file [%s] " - "for SELinux data [%d]: %s\n", tmp_path, ret, strerror(ret))); - goto done; - } - - full_string = talloc_asprintf(tmp_ctx, "%s:%s", ALL_SERVICES, string); - if (full_string == NULL) { - ret = ENOMEM; - goto done; - } - - len = strlen(full_string); - - errno = 0; - written = sss_atomic_write_s(fd, full_string, len); - if (written == -1) { - ret = errno; - DEBUG(SSSDBG_OP_FAILURE, ("writing to SELinux data file %s" - "failed [%d]: %s", tmp_path, ret, - strerror(ret))); - goto done; - } - - if (written != len) { - DEBUG(SSSDBG_OP_FAILURE, ("Expected to write %d bytes, wrote %d", - written, len)); - ret = EIO; - goto done; - } - - errno = 0; - if (rename(tmp_path, path) < 0) { - ret = errno; - } else { - ret = EOK; - } - close(fd); - fd = -1; - -done: - if (fd != -1) { - close(fd); - if (unlink(tmp_path) < 0) { - DEBUG(SSSDBG_MINOR_FAILURE, ("Could not remove file [%s]", - tmp_path)); - } - } - - talloc_free(tmp_ctx); - return ret; -} - -static errno_t remove_selinux_login_file(const char *username) -{ - char *path; - errno_t ret; - - path = selogin_path(NULL, username); - if (!path) return ENOMEM; - - errno = 0; - ret = unlink(path); - if (ret < 0) { - ret = errno; - if (ret == ENOENT) { - /* Just return success if the file was not there */ - ret = EOK; - } else { - DEBUG(SSSDBG_OP_FAILURE, - ("Could not remove login file %s [%d]: %s\n", - path, ret, strerror(ret))); - } - } - - talloc_free(path); - return ret; -} - -static errno_t process_selinux_mappings(struct pam_auth_req *preq) -{ - struct sysdb_ctx *sysdb; - TALLOC_CTX *tmp_ctx; - struct pam_data *pd = preq->pd; - char *file_content = NULL; - struct ldb_message **usermaps; - struct ldb_message *config; - const char *default_user = NULL; - const char *tmp_str; - char *order = NULL; - char **order_array; - errno_t ret, err; - int i, j; - size_t order_count; - size_t len = 0; - - tmp_ctx = talloc_new(NULL); - if (tmp_ctx == NULL) { - ret = ENOMEM; - goto done; - } - - sysdb = preq->domain->sysdb; - if (sysdb == NULL) { - DEBUG(SSSDBG_FATAL_FAILURE, ("Fatal: Sysdb CTX not found for " - "domain [%s]!\n", preq->domain->name)); - ret = EINVAL; - goto done; - } - - ret = sysdb_search_selinux_config(tmp_ctx, sysdb, - preq->domain, NULL, &config); - if (ret == ENOENT) { - DEBUG(SSSDBG_TRACE_INTERNAL, ("No SELinux support found for the domain\n")); - ret = EOK; - goto done; - } else if (ret != EOK) { - goto done; - } - - default_user = ldb_msg_find_attr_as_string(config, - SYSDB_SELINUX_DEFAULT_USER, - NULL); - if (!default_user || default_user[0] == '\0') { - /* Skip creating the maps altogether if there is no default - * or empty default - */ - ret = EOK; - goto done; - } - - tmp_str = ldb_msg_find_attr_as_string(config, - SYSDB_SELINUX_DEFAULT_ORDER, - NULL); - if (tmp_str == NULL) { - DEBUG(SSSDBG_OP_FAILURE, ("No map order given!\n")); - ret = EINVAL; - goto done; - } - - order = talloc_strdup(tmp_ctx, tmp_str); - if (order == NULL) { - ret = ENOMEM; - goto done; - } - len = strlen(order); - - /* The "order" string contains one or more SELinux user records - * separated by $. Now we need to create an array of string from - * this one string. First find out how many elements in the array - * will be. This way only one alloc will be necessary for the array - */ - order_count = 1; - for (i = 0; i < len; i++) { - if (order[i] == '$') order_count++; - } - - order_array = talloc_array(tmp_ctx, char *, order_count); - if (order_array == NULL) { - ret = ENOMEM; - goto done; - } - - /* Now fill the array with pointers to the original string. Also - * use binary zeros to make multiple string out of the one. - */ - order_array[0] = order; - order_count = 1; - for (i = 0; i < len; i++) { - if (order[i] == '$') { - order[i] = '\0'; - order_array[order_count] = &order[i+1]; - order_count++; - } - } - - /* Fetch all maps applicable to the user who is currently logging in */ - ret = sysdb_search_selinux_usermap_by_username(tmp_ctx, sysdb, - preq->domain, pd->user, - &usermaps); - if (ret != EOK && ret != ENOENT) { - goto done; - } - - /* If no maps match, we'll use the default SELinux user from the - * config */ - file_content = talloc_strdup(tmp_ctx, default_user); - if (file_content == NULL) { - ret = ENOMEM; - goto done; - } - - /* Iterate through the order array and try to find SELinux users - * in fetched maps. The order array contains all SELinux users - * allowed in the domain in the same order they should appear - * in the SELinux config file. If any user from the order array - * is not in fetched user maps, it means it should not be allowed - * for the user who is just logging in. - * - * Right now we have empty content of the SELinux config file, - * we shall add only those SELinux users that are present both in - * the order array and user maps applicable to the user who is - * logging in. - */ - for (i = 0; i < order_count; i++) { - for (j = 0; usermaps[j] != NULL; j++) { - tmp_str = sss_selinux_map_get_seuser(usermaps[j]); - - if (tmp_str && !strcasecmp(tmp_str, order_array[i])) { - /* If file_content contained something, overwrite it. - * This record has higher priority. - */ - talloc_zfree(file_content); - file_content = talloc_strdup(tmp_ctx, tmp_str); - if (file_content == NULL) { - ret = ENOMEM; - goto done; - } - break; - } - } - } - - ret = write_selinux_login_file(pd->user, file_content); -done: - if (!file_content) { - err = remove_selinux_login_file(pd->user); - /* Don't overwrite original error condition if there was one */ - if (ret == EOK) ret = err; - } - talloc_free(tmp_ctx); - return ret; -} -#endif - static errno_t filter_responses(struct confdb_ctx *cdb, struct response_data *resp_list) { @@ -863,18 +566,6 @@ static void pam_reply(struct pam_auth_req *preq) return; } -#ifdef HAVE_SELINUX_LOGIN_DIR - if (pd->cmd == SSS_PAM_ACCT_MGMT && - pd->pam_status == PAM_SUCCESS) { - /* Try to fetch data from sysdb - * (auth already passed -> we should have them) */ - ret = process_selinux_mappings(preq); - if (ret != EOK) { - pd->pam_status = PAM_SYSTEM_ERR; - } - } -#endif - ret = sss_packet_new(cctx->creq, 0, sss_packet_get_cmd(cctx->creq->in), &cctx->creq->out); if (ret != EOK) { diff --git a/src/util/sss_selinux.c b/src/util/sss_selinux.c index ee5ddab6..dcac9ee6 100644 --- a/src/util/sss_selinux.c +++ b/src/util/sss_selinux.c @@ -239,16 +239,16 @@ done: return ret; } -const char *sss_selinux_map_get_seuser(struct ldb_message *usermap) +const char *sss_selinux_map_get_seuser(struct sysdb_attrs *usermap) { int i; const uint8_t *name; const uint8_t *template = (const uint8_t *)SYSDB_SELINUX_USER; - for (i = 0; i < usermap->num_elements; i++) { - name = (const uint8_t *)usermap->elements[i].name; + for (i = 0; i < usermap->num; i++) { + name = (const uint8_t *)usermap->a[i].name; if (sss_utf8_case_eq(name, template) == 0) { - return (const char *)usermap->elements[i].values[0].data; + return (const char *)usermap->a[i].values[0].data; } } diff --git a/src/util/sss_selinux.h b/src/util/sss_selinux.h index 5dae5dd3..ae5b2f35 100644 --- a/src/util/sss_selinux.h +++ b/src/util/sss_selinux.h @@ -50,6 +50,6 @@ bool sss_selinux_match(struct sysdb_attrs *usermap, struct sysdb_attrs *host, uint32_t *_priority); -const char *sss_selinux_map_get_seuser(struct ldb_message *usermap); +const char *sss_selinux_map_get_seuser(struct sysdb_attrs *usermap); #endif /* SSS_SELINUX_H_ */ |