/* SSSD SELinux-related utility functions Authors: Jan Zeleny Copyright (C) 2012 Red Hat This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "util/sss_selinux.h" #include "util/sss_utf8.h" #include "db/sysdb_selinux.h" static bool match_entity(struct ldb_message_element *values, struct ldb_message_element *sought_values) { int i, j; for (i = 0; i < values->num_values; i++) { for (j = 0; j < sought_values->num_values; j++) { if (values->values[i].length != sought_values->values[j].length) { continue; } if (strncasecmp((char *)values->values[i].data, (char *)sought_values->values[j].data, values->values[i].length) == 0) return true; } } return false; } bool sss_selinux_match(struct sysdb_attrs *usermap, struct sysdb_attrs *user, struct sysdb_attrs *host, uint32_t *_priority) { struct ldb_message_element *users_el = NULL; struct ldb_message_element *usercat = NULL; struct ldb_message_element *hosts_el = NULL; struct ldb_message_element *hostcat = NULL; struct ldb_message_element *dn; struct ldb_message_element *memberof; int i; uint32_t priority = 0; bool matched_name; bool matched_group; bool matched_category; errno_t ret; if (usermap == NULL) { DEBUG(SSSDBG_MINOR_FAILURE, ("NULL given as usermap! Skipping ...\n")); return false; } /* Search for user and host related elements */ for (i = 0; i < usermap->num; i++) { if (!strcasecmp(usermap->a[i].name, SYSDB_ORIG_MEMBER_USER)) { users_el = &usermap->a[i]; } else if (!strcasecmp(usermap->a[i].name, SYSDB_ORIG_MEMBER_HOST)) { hosts_el = &usermap->a[i]; } else if (!strcasecmp(usermap->a[i].name, SYSDB_USER_CATEGORY)) { usercat = &usermap->a[i]; } else if (!strcasecmp(usermap->a[i].name, SYSDB_HOST_CATEGORY)) { hostcat = &usermap->a[i]; } } if (user) { ret = sysdb_attrs_get_el(user, SYSDB_ORIG_DN, &dn); if (ret != EOK) { DEBUG(SSSDBG_MINOR_FAILURE, ("User does not have origDN\n")); return false; } ret = sysdb_attrs_get_el(user, SYSDB_ORIG_MEMBEROF, &memberof); if (ret != EOK) { DEBUG(SSSDBG_TRACE_ALL, ("User does not have orig memberof, " "therefore it can't match to any rule\n")); return false; } /** * The rule won't match if user category != "all" and user map doesn't * contain neither user nor any of his groups in memberUser attribute */ matched_category = false; if (usercat != NULL) { for (i = 0; i < usercat->num_values; i++) { if (strcasecmp((char *)usercat->values[i].data, "all") == 0) { matched_category = true; break; } } } if (!matched_category) { if (users_el == NULL) { DEBUG(SSSDBG_TRACE_ALL, ("No users specified in the rule!\n")); return false; } else { matched_name = match_entity(users_el, dn); matched_group = match_entity(users_el, memberof); if (matched_name) { priority |= SELINUX_PRIORITY_USER_NAME; } else if (matched_group) { priority |= SELINUX_PRIORITY_USER_GROUP; } else { DEBUG(SSSDBG_TRACE_ALL, ("User did not match\n")); return false; } } } else { priority |= SELINUX_PRIORITY_USER_CAT; } } if (host) { ret = sysdb_attrs_get_el(host, SYSDB_ORIG_DN, &dn); if (ret != EOK) { DEBUG(SSSDBG_MINOR_FAILURE, ("Host does not have origDN\n")); return false; } ret = sysdb_attrs_get_el(host, SYSDB_ORIG_MEMBEROF, &memberof); if (ret != EOK) { DEBUG(SSSDBG_TRACE_ALL, ("Host does not have orig memberof, " "therefore it can't match to any rule\n")); return false; } /** * The rule won't match if host category != "all" and user map doesn't * contain neither host nor any of its groups in memberHost attribute */ matched_category = false; if (hostcat != NULL) { for (i = 0; i < hostcat->num_values; i++) { if (strcasecmp((char *)hostcat->values[i].data, "all") == 0) { matched_category = true; break; } } } if (!matched_category) { if (hosts_el == NULL) { DEBUG(SSSDBG_TRACE_ALL, ("No users specified in the rule!\n")); return false; } else { matched_name = match_entity(hosts_el, dn); matched_group = match_entity(hosts_el, memberof); if (matched_name) { priority |= SELINUX_PRIORITY_HOST_NAME; } else if (matched_group) { priority |= SELINUX_PRIORITY_HOST_GROUP; } else { DEBUG(SSSDBG_TRACE_ALL, ("Host did not match\n")); return false; } } } else { priority |= SELINUX_PRIORITY_HOST_CAT; } } if (_priority != NULL) { *_priority = priority; } return true; } errno_t sss_selinux_extract_user(TALLOC_CTX *mem_ctx, struct sysdb_ctx *sysdb, const char *username, struct sysdb_attrs **_user_attrs) { TALLOC_CTX *tmp_ctx; const char **attrs; struct sysdb_attrs *user_attrs; struct ldb_message *user_msg; errno_t ret; tmp_ctx = talloc_new(NULL); if (tmp_ctx == NULL) { ret = ENOMEM; goto done; } attrs = talloc_array(tmp_ctx, const char *, 3); if (attrs == NULL) { DEBUG(SSSDBG_CRIT_FAILURE, ("talloc_array failed.\n")); ret = ENOMEM; goto done; } attrs[0] = SYSDB_ORIG_DN; attrs[1] = SYSDB_ORIG_MEMBEROF; attrs[2] = NULL; ret = sysdb_search_user_by_name(tmp_ctx, sysdb, username, attrs, &user_msg); if (ret != EOK) { DEBUG(SSSDBG_OP_FAILURE, ("sysdb_search_user_by_name failed.\n")); goto done; } user_attrs = talloc_zero(tmp_ctx, struct sysdb_attrs); if (user_attrs == NULL) { ret = ENOMEM; goto done; } user_attrs->a = talloc_steal(user_attrs, user_msg->elements); user_attrs->num = user_msg->num_elements; *_user_attrs = talloc_steal(mem_ctx, user_attrs); ret = EOK; done: talloc_free(tmp_ctx); return ret; } const char *sss_selinux_map_get_seuser(struct ldb_message *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; if (sss_utf8_case_eq(name, template) == 0) { return (const char *)usermap->elements[i].values[0].data; } } return NULL; }