summaryrefslogtreecommitdiffstats
path: root/src/providers/ipa/ipa_deskprofile_rules_util.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/providers/ipa/ipa_deskprofile_rules_util.c')
-rw-r--r--src/providers/ipa/ipa_deskprofile_rules_util.c1147
1 files changed, 1147 insertions, 0 deletions
diff --git a/src/providers/ipa/ipa_deskprofile_rules_util.c b/src/providers/ipa/ipa_deskprofile_rules_util.c
new file mode 100644
index 0000000..d6fa3cc
--- /dev/null
+++ b/src/providers/ipa/ipa_deskprofile_rules_util.c
@@ -0,0 +1,1147 @@
+/*
+ SSSD
+
+ Authors:
+ Fabiano FidĂȘncio <fidencio@redhat.com>
+
+ Copyright (C) 2017 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 <http://www.gnu.org/licenses/>.
+*/
+
+#include "providers/ipa/ipa_deskprofile_rules_util.h"
+#include "providers/ipa/ipa_deskprofile_private.h"
+#include "providers/ipa/ipa_rules_common.h"
+#include <ctype.h>
+#include <fcntl.h>
+
+#define DESKPROFILE_GLOBAL_POLICY_MIN_VALUE 1
+#define DESKPROFILE_GLOBAL_POLICY_MAX_VALUE 24
+
+enum deskprofile_name {
+ RULES_DIR = 0,
+ DOMAIN,
+ USERNAME,
+ PRIORITY,
+ USER,
+ GROUP,
+ HOST,
+ HOSTGROUP,
+ RULE_NAME,
+ EXTENSION,
+ DESKPROFILE_NAME_SENTINEL
+};
+
+/*
+ * The rule's filename has to follow a global policy, used by FleetCommander
+ * client that shows how the profile should be applied.
+ *
+ * This global policy is represented by an integer from 1 to 24 (inclusive) and
+ * has the following meaning:
+ * 1 = user, group, host, hostgroup
+ * 2 = user, group, hostgroup, host
+ * 3 = user, host, group, hostgroup
+ * 4 = user, host, hostgroup, group
+ * 5 = user, hostgroup, group, host
+ * 6 = user, hostgroup, host, group
+ * 7 = group, user, host, hostgroup
+ * 8 = group, user, hostgroup, host
+ * 9 = group, host, user, hostgroup
+ * 10 = group, host, hostgroup, user
+ * 11 = group, hostgroup, user, host
+ * 12 = group, hostgroup, host, user
+ * 13 = host, user, group, hostgroup
+ * 14 = host, user, hostgroup, group
+ * 15 = host, group, user, hostgroup
+ * 16 = host, group, hostgroup, user
+ * 17 = host, hostgroup, user, group
+ * 18 = host, hostgroup, group, user
+ * 19 = hostgroup, user, group, host
+ * 20 = hostgroup, user, host, group
+ * 21 = hostgroup, group, user, host
+ * 22 = hostgroup, group, host, user
+ * 23 = hostgroup, host, user, group
+ * 24 = hostgroup, host, group, user
+ *
+ * Having the table above in mind and considering the following example:
+ * - rule name: testrule
+ * - policy: 22
+ * - priority: 420
+ * - client's machine matches: host and group
+ *
+ * So, the filename will be: "000420_000000_000420_000420_000000_testrule.json"
+ *
+ * The function below not only helps us to create this filename in the correct
+ * format, but also create the whole path for this rule's file.
+ *
+ * An example of the full path would be:
+ * "/var/lib/sss/deskprofile/ipa.example/user_foobar/000420_000000_000420_000420_000000_testrule.json"
+ * | RULES DIR | DOMAIN | USERNAME | | |GROUP | HOST | USER | |
+ * PRIORITY RULE NAME
+ * HOSTGROUP EXTENSION
+ *
+ * In case a element has to be added/remove, please, remember to update:
+ * - deskprofile_name enum;
+ * - permuts's matrix;
+ * - vals array;
+ */
+errno_t
+ipa_deskprofile_get_filename_path(TALLOC_CTX *mem_ctx,
+ uint16_t config_priority,
+ const char *rules_dir,
+ const char *domain,
+ const char *username,
+ const char *priority,
+ const char *user_priority,
+ const char *group_priority,
+ const char *host_priority,
+ const char *hostgroup_priority,
+ const char *rule_name,
+ const char *extension,
+ char **_filename_path)
+{
+ TALLOC_CTX *tmp_ctx;
+ static const uint8_t permuts[][DESKPROFILE_NAME_SENTINEL] = {
+ {RULES_DIR, DOMAIN, USERNAME, PRIORITY, USER, GROUP, HOST, HOSTGROUP, RULE_NAME, EXTENSION},
+ {RULES_DIR, DOMAIN, USERNAME, PRIORITY, USER, GROUP, HOSTGROUP, HOST, RULE_NAME, EXTENSION},
+ {RULES_DIR, DOMAIN, USERNAME, PRIORITY, USER, HOST, GROUP, HOSTGROUP, RULE_NAME, EXTENSION},
+ {RULES_DIR, DOMAIN, USERNAME, PRIORITY, USER, HOST, HOSTGROUP, GROUP, RULE_NAME, EXTENSION},
+ {RULES_DIR, DOMAIN, USERNAME, PRIORITY, USER, HOSTGROUP, GROUP, HOST, RULE_NAME, EXTENSION},
+ {RULES_DIR, DOMAIN, USERNAME, PRIORITY, USER, HOSTGROUP, HOST, GROUP, RULE_NAME, EXTENSION},
+ {RULES_DIR, DOMAIN, USERNAME, PRIORITY, GROUP, USER, HOST, HOSTGROUP, RULE_NAME, EXTENSION},
+ {RULES_DIR, DOMAIN, USERNAME, PRIORITY, GROUP, USER, HOSTGROUP, HOST, RULE_NAME, EXTENSION},
+ {RULES_DIR, DOMAIN, USERNAME, PRIORITY, GROUP, HOST, USER, HOSTGROUP, RULE_NAME, EXTENSION},
+ {RULES_DIR, DOMAIN, USERNAME, PRIORITY, GROUP, HOST, HOSTGROUP, USER, RULE_NAME, EXTENSION},
+ {RULES_DIR, DOMAIN, USERNAME, PRIORITY, GROUP, HOSTGROUP, USER, HOST, RULE_NAME, EXTENSION},
+ {RULES_DIR, DOMAIN, USERNAME, PRIORITY, GROUP, HOSTGROUP, HOST, USER, RULE_NAME, EXTENSION},
+ {RULES_DIR, DOMAIN, USERNAME, PRIORITY, HOST, USER, GROUP, HOSTGROUP, RULE_NAME, EXTENSION},
+ {RULES_DIR, DOMAIN, USERNAME, PRIORITY, HOST, USER, HOSTGROUP, GROUP, RULE_NAME, EXTENSION},
+ {RULES_DIR, DOMAIN, USERNAME, PRIORITY, HOST, GROUP, USER, HOSTGROUP, RULE_NAME, EXTENSION},
+ {RULES_DIR, DOMAIN, USERNAME, PRIORITY, HOST, GROUP, HOSTGROUP, USER, RULE_NAME, EXTENSION},
+ {RULES_DIR, DOMAIN, USERNAME, PRIORITY, HOST, HOSTGROUP, USER, GROUP, RULE_NAME, EXTENSION},
+ {RULES_DIR, DOMAIN, USERNAME, PRIORITY, HOST, HOSTGROUP, GROUP, USER, RULE_NAME, EXTENSION},
+ {RULES_DIR, DOMAIN, USERNAME, PRIORITY, HOSTGROUP, USER, GROUP, HOST, RULE_NAME, EXTENSION},
+ {RULES_DIR, DOMAIN, USERNAME, PRIORITY, HOSTGROUP, USER, HOST, GROUP, RULE_NAME, EXTENSION},
+ {RULES_DIR, DOMAIN, USERNAME, PRIORITY, HOSTGROUP, GROUP, USER, HOST, RULE_NAME, EXTENSION},
+ {RULES_DIR, DOMAIN, USERNAME, PRIORITY, HOSTGROUP, GROUP, HOST, USER, RULE_NAME, EXTENSION},
+ {RULES_DIR, DOMAIN, USERNAME, PRIORITY, HOSTGROUP, HOST, USER, GROUP, RULE_NAME, EXTENSION},
+ {RULES_DIR, DOMAIN, USERNAME, PRIORITY, HOSTGROUP, HOST, GROUP, USER, RULE_NAME, EXTENSION},
+ };
+ const char *vals[] = {
+ rules_dir,
+ domain,
+ username,
+ priority,
+ user_priority,
+ group_priority,
+ host_priority,
+ hostgroup_priority,
+ rule_name,
+ extension,
+ NULL,
+ };
+ const uint8_t *perms;
+ char *result;
+ errno_t ret;
+
+ tmp_ctx = talloc_new(mem_ctx);
+ if (tmp_ctx == NULL) {
+ return ENOMEM;
+ }
+
+ if (config_priority < DESKPROFILE_GLOBAL_POLICY_MIN_VALUE ||
+ config_priority > DESKPROFILE_GLOBAL_POLICY_MAX_VALUE) {
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ "The configuration priority has an invalid value: %d!\n",
+ config_priority);
+ ret = EINVAL;
+ goto done;
+ }
+
+ perms = permuts[config_priority - 1];
+
+ result = talloc_strdup(tmp_ctx, "");
+ if (result == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ for (int i = 0; i < DESKPROFILE_NAME_SENTINEL; i++) {
+ switch(perms[i]) {
+ case RULES_DIR:
+ case DOMAIN:
+ case USERNAME:
+ result = talloc_asprintf_append(result, "%s/", vals[perms[i]]);
+ break;
+ case PRIORITY:
+ case USER:
+ case GROUP:
+ case HOST:
+ case HOSTGROUP:
+ result = talloc_asprintf_append(result, "%s_", vals[perms[i]]);
+ break;
+ case RULE_NAME:
+ result = talloc_asprintf_append(result, "%s", vals[perms[i]]);
+ break;
+ case EXTENSION:
+ result = talloc_asprintf_append(result, ".%s", vals[perms[i]]);
+ break;
+ default:
+ DEBUG(SSSDBG_MINOR_FAILURE,
+ "This situation should never happen\n");
+ ret = EINVAL;
+ goto done;
+ }
+
+ if (result == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+ }
+
+ *_filename_path = talloc_steal(mem_ctx, result);
+ ret = EOK;
+
+done:
+ talloc_free(tmp_ctx);
+ return ret;
+}
+
+errno_t
+ipa_deskprofile_rules_create_user_dir(
+ const char *username, /* fully-qualified */
+ uid_t uid,
+ gid_t gid)
+{
+ TALLOC_CTX *tmp_ctx;
+ char *shortname;
+ char *domain;
+ char *domain_dir;
+ errno_t ret;
+ mode_t old_umask;
+
+ tmp_ctx = talloc_new(NULL);
+ if (tmp_ctx == NULL) {
+ return ENOMEM;
+ }
+
+ ret = sss_parse_internal_fqname(tmp_ctx, username, &shortname, &domain);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ "sss_parse_internal_fqname() failed [%d]: %s\n",
+ ret, sss_strerror(ret));
+ goto done;
+ }
+
+ old_umask = umask(0026);
+ ret = sss_create_dir(IPA_DESKPROFILE_RULES_USER_DIR, domain, 0751,
+ getuid(), getgid());
+ umask(old_umask);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ "Failed to create the directory \"%s/%s\" that would be used to "
+ "store the Desktop Profile rules users' directory [%d]: %s\n",
+ IPA_DESKPROFILE_RULES_USER_DIR, domain,
+ ret, sss_strerror(ret));
+ goto done;
+ }
+
+ domain_dir = talloc_asprintf(tmp_ctx, IPA_DESKPROFILE_RULES_USER_DIR"/%s",
+ domain);
+ if (domain_dir == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ /* In order to read, create and traverse the directory, we need to have its
+ * permissions set as 'rwx------' (700). */
+ old_umask = umask(0077);
+ ret = sss_create_dir(domain_dir, shortname, 0700, uid, gid);
+ umask(old_umask);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ "Failed to create the directory \"%s/%s/%s\" that would be used "
+ "to store the Desktop Profile rules for the user \"%s\" [%d]: "
+ "%s\n",
+ IPA_DESKPROFILE_RULES_USER_DIR, domain, shortname, username,
+ ret, sss_strerror(ret));
+ goto done;
+ }
+
+ ret = EOK;
+
+done:
+ talloc_free(tmp_ctx);
+ return ret;
+}
+
+static errno_t
+ipa_deskprofile_get_normalized_rule_name(TALLOC_CTX *mem_ctx,
+ const char *name,
+ char **_rule_name)
+{
+ char buffer[PATH_MAX];
+ size_t buffer_len;
+ size_t name_len;
+
+ name_len = strlen(name);
+ buffer_len = 0;
+ for (size_t i = 0; i < name_len; i++) {
+ char character;
+ bool replace;
+
+ character = name[i];
+ replace = false;
+
+ if (isalnum(character) == 0) {
+ char next_character;
+
+ next_character = name[i+1];
+ if (i + 1 >= name_len || isalnum(next_character) == 0) {
+ continue;
+ }
+
+ replace = true;
+ }
+
+ buffer[buffer_len] = replace ? '_' : character;
+ buffer_len++;
+ }
+ buffer[buffer_len] = '\0';
+
+ *_rule_name = talloc_strdup(mem_ctx, buffer);
+ if (*_rule_name == NULL) {
+ return ENOMEM;
+ }
+
+ return EOK;
+}
+
+static errno_t
+ipa_deskprofile_rule_check_memberuser(
+ TALLOC_CTX *mem_ctx,
+ struct sss_domain_info *domain,
+ struct sysdb_attrs *rule,
+ const char *rule_name,
+ const char *rule_prio,
+ const char *base_dn,
+ const char *username, /* fully-qualified */
+ char **_user_prio,
+ char **_group_prio)
+{
+ TALLOC_CTX *tmp_ctx;
+ struct ldb_message_element *el;
+ struct ldb_result *res;
+ size_t num_groups;
+ char **groups = NULL;
+ const char *fqgroupname = NULL;
+ char *groupname = NULL;
+ char *shortname;
+ char *domainname;
+ char *data;
+ char *memberuser;
+ char *membergroup;
+ char *user_prio;
+ char *group_prio;
+ bool user = false;
+ bool group = false;
+ errno_t ret;
+
+ tmp_ctx = talloc_new(mem_ctx);
+ if (tmp_ctx == NULL) {
+ return ENOMEM;
+ }
+
+ ret = sss_parse_internal_fqname(tmp_ctx, username,
+ &shortname, &domainname);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ "sss_parse_internal_fqname() failed [%d]: %s\n",
+ ret, sss_strerror(ret));
+ goto done;
+ }
+
+ ret = sysdb_initgroups(tmp_ctx, domain, username, &res);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ "sysdb_initgroups() failed [%d]: %s\n",
+ ret, sss_strerror(ret));
+ goto done;
+ }
+
+ if (res->count == 0) {
+ /* This really should NOT happen at this point */
+ DEBUG(SSSDBG_MINOR_FAILURE,
+ "User [%s] not found in cache\n", username);
+ ret = ENOENT;
+ goto done;
+ }
+
+ groups = talloc_array(tmp_ctx, char *, res->count);
+ if (groups == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ num_groups = 0;
+ /* Start counting from 1 to exclude the user entry */
+ for (size_t i = 1; i < res->count; i++) {
+ fqgroupname = ldb_msg_find_attr_as_string(res->msgs[i],
+ SYSDB_NAME,
+ NULL);
+ if (fqgroupname == NULL) {
+ DEBUG(SSSDBG_MINOR_FAILURE,
+ "Skipping malformed entry [%s]\n",
+ ldb_dn_get_linearized(res->msgs[i]->dn));
+ continue;
+ }
+
+ ret = sss_parse_internal_fqname(tmp_ctx, fqgroupname,
+ &groupname, NULL);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_MINOR_FAILURE,
+ "Malformed name %s, skipping!\n", fqgroupname);
+ continue;
+ }
+
+ groups[num_groups] = groupname;
+ num_groups++;
+ }
+ groups[num_groups] = NULL;
+
+ ret = sysdb_attrs_get_el(rule, IPA_MEMBER_USER, &el);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_TRACE_FUNC,
+ "Failed to get the Desktop Profile Rule memberUser for rule "
+ "\"%s\" [%d]: %s\n",
+ rule_name, ret, sss_strerror(ret));
+
+ goto done;
+ }
+
+ memberuser = talloc_asprintf(tmp_ctx, "uid=%s,cn=users,cn=accounts,%s",
+ shortname, base_dn);
+ if (memberuser == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Failed to allocate memberuser\n");
+ ret = ENOMEM;
+ goto done;
+ }
+
+ for (size_t i = 0; i < el->num_values; i++) {
+ if (user && group) {
+ break;
+ }
+
+ data = (char *)el->values[i].data;
+
+ if (!user && data != NULL && strcmp(memberuser, data) == 0) {
+ DEBUG(SSSDBG_TRACE_FUNC,
+ "Desktop Profile rule \"%s\" matches with the user \"%s\" "
+ "for the \"%s\" domain!\n",
+ rule_name, shortname, domainname);
+ user = true;
+ continue;
+ }
+
+ if (!group && data != NULL) {
+ for (size_t j = 0; !group && groups[j] != NULL; j++) {
+ membergroup = talloc_asprintf(tmp_ctx,
+ "cn=%s,cn=groups,cn=accounts,%s",
+ groups[j], base_dn);
+ if (membergroup == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ "Failed to allocate membergroup\n");
+ ret = ENOMEM;
+ goto done;
+ }
+
+ if (strcmp(membergroup, data) == 0) {
+ DEBUG(SSSDBG_TRACE_FUNC,
+ "Desktop Profile rule \"%s\" matches with (at least) "
+ "the group \"%s\" for the \"%s\" domain!\n",
+ rule_name, groups[j], domainname);
+ group = true;
+ }
+ }
+ }
+ }
+
+ user_prio = user ? talloc_strdup(tmp_ctx, rule_prio) :
+ talloc_asprintf(tmp_ctx, "%06d", 0);
+ if (user_prio == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Failed to allocate the user priority\n");
+ ret = ENOMEM;
+ goto done;
+ }
+
+ group_prio = group ? talloc_strdup(tmp_ctx, rule_prio) :
+ talloc_asprintf(tmp_ctx, "%06d", 0);
+ if (group_prio == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Failed to allocate the group priority\n");
+ ret = ENOMEM;
+ goto done;
+ }
+
+ *_user_prio = talloc_steal(mem_ctx, user_prio);
+ *_group_prio = talloc_steal(mem_ctx, group_prio);
+
+ ret = EOK;
+
+done:
+ talloc_free(tmp_ctx);
+ return ret;
+}
+
+static errno_t
+ipa_deskprofile_rule_check_memberhost(TALLOC_CTX *mem_ctx,
+ struct sss_domain_info *domain,
+ struct sysdb_attrs *rule,
+ const char *rule_name,
+ const char *rule_prio,
+ const char *base_dn,
+ const char *hostname,
+ char **_host_prio,
+ char **_hostgroup_prio)
+{
+ TALLOC_CTX *tmp_ctx;
+ struct ldb_dn *host_dn;
+ struct ldb_message_element *el_orig_memberof = NULL;
+ struct ldb_message_element *el = NULL;
+ struct ldb_message **msgs;
+ size_t count;
+ size_t num_memberhostgroup;
+ char **memberhostgroups = NULL;
+ char *data;
+ char *memberhost;
+ char *memberhostgroup;
+ char *name;
+ char *host_prio;
+ char *hostgroup_prio;
+ const char *memberof_attrs[] = { SYSDB_ORIG_MEMBEROF, NULL };
+ bool host = false;
+ bool hostgroup = false;
+ errno_t ret;
+
+ tmp_ctx = talloc_new(mem_ctx);
+ if (tmp_ctx == NULL) {
+ return ENOMEM;
+ }
+
+ host_dn = sysdb_custom_dn(tmp_ctx, domain, hostname,
+ DESKPROFILE_HOSTS_SUBDIR);
+ if (host_dn == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ ret = sysdb_search_entry(tmp_ctx, domain->sysdb, host_dn,
+ LDB_SCOPE_BASE, NULL,
+ memberof_attrs,
+ &count, &msgs);
+ if (ret == ENOENT || count == 0) {
+ memberhostgroups = talloc_array(tmp_ctx, char *, 1);
+ memberhostgroups[0] = NULL;
+ } else if (ret != EOK) {
+ goto done;
+ } else if (count > 1) {
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ "More than one result for a BASE search!\n");
+ ret = EIO;
+ goto done;
+ } else { /* ret == EOK && count == 1 */
+ el_orig_memberof = ldb_msg_find_element(msgs[0], SYSDB_ORIG_MEMBEROF);
+ memberhostgroups = talloc_array(tmp_ctx,
+ char *,
+ el_orig_memberof->num_values);
+ }
+
+ if (el_orig_memberof != NULL) {
+ num_memberhostgroup = 0;
+ for (size_t i = 0; i < el_orig_memberof->num_values; i++) {
+ data = (char *)el_orig_memberof->values[i].data;
+
+ ret = ipa_common_get_hostgroupname(tmp_ctx, domain->sysdb, data,
+ &name);
+
+ /* ERR_UNEXPECTED_ENTRY_TYPE means we had a memberOf entry that
+ * wasn't a host group, thus we'll just ignore those.
+ */
+ if (ret != EOK && ret != ERR_UNEXPECTED_ENTRY_TYPE) {
+ DEBUG(SSSDBG_MINOR_FAILURE,
+ "Skipping malformed entry [%s]\n",
+ data);
+ continue;
+ } else if (ret == EOK) {
+ memberhostgroups[num_memberhostgroup] = name;
+ num_memberhostgroup++;
+ }
+ }
+ memberhostgroups[num_memberhostgroup] = NULL;
+ }
+
+ ret = sysdb_attrs_get_el(rule, IPA_MEMBER_HOST, &el);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_TRACE_FUNC,
+ "Failed to get the Desktop Profile Rule memberHost for rule "
+ "\"%s\" [%d]: %s\n",
+ rule_name, ret, sss_strerror(ret));
+
+ goto done;
+ }
+
+ memberhost = talloc_asprintf(tmp_ctx, "fqdn=%s,cn=computers,cn=accounts,%s",
+ hostname, base_dn);
+ if (memberhost == NULL) {
+ ret = ENOMEM;
+ DEBUG(SSSDBG_CRIT_FAILURE, "Failed to allocate memberhost\n");
+ goto done;
+ }
+
+ for (size_t i = 0; i < el->num_values; i++) {
+ if (host && hostgroup) {
+ break;
+ }
+
+ data = (char *)el->values[i].data;
+
+ if (!host && data != NULL && strcmp(memberhost, data) == 0) {
+ host = true;
+ DEBUG(SSSDBG_TRACE_FUNC,
+ "Desktop Profile rule \"%s\" matches with the host \"%s\" "
+ "for the \"%s\" domain!\n",
+ rule_name, hostname, domain->name);
+ continue;
+ }
+
+ if (!hostgroup && data != NULL) {
+ for (size_t j = 0; !hostgroup && memberhostgroups[j] != NULL; j++) {
+ memberhostgroup = talloc_asprintf(
+ tmp_ctx,
+ "cn=%s,cn=hostgroups,cn=accounts,%s",
+ memberhostgroups[j], base_dn);
+
+ if (memberhostgroup == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ "Failed to allocate memberhostgroup\n");
+ ret = ENOMEM;
+ goto done;
+ }
+
+ if (strcmp(memberhostgroup, data) == 0) {
+ hostgroup = true;
+ DEBUG(SSSDBG_TRACE_FUNC,
+ "Desktop Profile rule \"%s\" matches with (at least) "
+ "the hostgroup \"%s\" for the \"%s\" domain!\n",
+ rule_name, memberhostgroups[j], domain->name);
+ continue;
+ }
+ }
+ }
+ }
+
+ host_prio = host ? talloc_strdup(tmp_ctx, rule_prio) :
+ talloc_asprintf(tmp_ctx, "%06d", 0);
+ if (host_prio == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Failed to allocate the host priority\n");
+ ret = ENOMEM;
+ goto done;
+ }
+
+ hostgroup_prio = hostgroup ? talloc_strdup(tmp_ctx, rule_prio) :
+ talloc_asprintf(tmp_ctx, "%06d", 0);
+ if (hostgroup_prio == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Failed to allocate the hostgroup priority\n");
+ ret = ENOMEM;
+ goto done;
+ }
+
+ *_host_prio = talloc_steal(mem_ctx, host_prio);
+ *_hostgroup_prio = talloc_steal(mem_ctx, hostgroup_prio);
+
+ ret = EOK;
+
+done:
+ talloc_free(tmp_ctx);
+ return ret;
+}
+
+
+errno_t
+ipa_deskprofile_rules_save_rule_to_disk(
+ TALLOC_CTX *mem_ctx,
+ uint16_t priority,
+ struct sysdb_attrs *rule,
+ struct sss_domain_info *domain,
+ const char *hostname,
+ const char *username, /* fully-qualified */
+ uid_t uid,
+ gid_t gid)
+{
+ TALLOC_CTX *tmp_ctx;
+ const char *rule_name;
+ const char *data;
+ const char *hostcat;
+ const char *usercat;
+ char *shortname;
+ char *domainname;
+ char *base_dn;
+ char *rule_prio;
+ char *user_prio;
+ char *group_prio;
+ char *host_prio;
+ char *hostgroup_prio;
+ char *normalized_rule_name = NULL;
+ char *filename_path = NULL;
+ const char *extension = "json";
+ uint32_t prio;
+ int fd = -1;
+ gid_t orig_gid;
+ uid_t orig_uid;
+ errno_t ret;
+
+ tmp_ctx = talloc_new(mem_ctx);
+ if (tmp_ctx == NULL) {
+ return ENOMEM;
+ }
+
+ orig_gid = getegid();
+ orig_uid = geteuid();
+
+ ret = sysdb_attrs_get_string(rule, IPA_CN, &rule_name);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_TRACE_FUNC,
+ "Failed to get the Desktop Profile Rule name [%d]: %s\n",
+ ret, sss_strerror(ret));
+
+ goto done;
+ }
+
+ ret = sysdb_attrs_get_uint32_t(rule, IPA_DESKPROFILE_PRIORITY, &prio);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_TRACE_FUNC,
+ "Failed to get the Desktop Profile Rule priority for rule "
+ "\"%s\" [%d]: %s\n",
+ rule_name, ret, sss_strerror(ret));
+ goto done;
+ }
+
+ ret = sysdb_attrs_get_string(rule, IPA_HOST_CATEGORY, &hostcat);
+ if (ret == ENOENT) {
+ hostcat = NULL;
+ } else if (ret != EOK) {
+ DEBUG(SSSDBG_TRACE_FUNC,
+ "Failed to get the Desktop Profile Rule host category for rule "
+ "\"%s\" [%d]: %s\n",
+ rule_name, ret, sss_strerror(ret));
+ goto done;
+ }
+
+ ret = sysdb_attrs_get_string(rule, IPA_USER_CATEGORY, &usercat);
+ if (ret == ENOENT) {
+ usercat = NULL;
+ } else if (ret != EOK) {
+ DEBUG(SSSDBG_TRACE_FUNC,
+ "Failed to get the Desktop Profile Rule user category for rule "
+ "\"%s\" [%d]: %s\n",
+ rule_name, ret, sss_strerror(ret));
+ goto done;
+ }
+
+ rule_prio = talloc_asprintf(tmp_ctx, "%06d", prio);
+ if (rule_prio == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Failed to allocate rule priority\n");
+ ret = ENOMEM;
+ goto done;
+ }
+
+ ret = sysdb_attrs_get_string(rule, IPA_DESKPROFILE_DATA, &data);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_TRACE_FUNC,
+ "Failed to get the Desktop Profile Rule data for rule \"%s\" "
+ "[%d]: %s\n",
+ rule_name, ret, sss_strerror(ret));
+ goto done;
+ }
+
+ ret = sss_parse_internal_fqname(tmp_ctx, username, &shortname, &domainname);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ "sss_parse_internal_fqname() failed [%d]: %s\n",
+ ret, sss_strerror(ret));
+ goto done;
+ }
+
+ ret = domain_to_basedn(tmp_ctx, domainname, &base_dn);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "domain_to_basedn() failed [%d]: %s\n",
+ ret, sss_strerror(ret));
+ goto done;
+ }
+
+ if (usercat != NULL && strcasecmp(usercat, "all") == 0) {
+ user_prio = talloc_strdup(tmp_ctx, rule_prio);
+ if (user_prio == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ "Failed to allocate the user priority "
+ "when user category is \"all\"\n");
+ ret = ENOMEM;
+ goto done;
+ }
+
+ group_prio = talloc_strdup(tmp_ctx, rule_prio);
+ if (group_prio == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ "Failed to allocate the group priority "
+ "when user category is \"all\"\n");
+ ret = ENOMEM;
+ goto done;
+ }
+ } else {
+ ret = ipa_deskprofile_rule_check_memberuser(tmp_ctx, domain, rule,
+ rule_name, rule_prio,
+ base_dn, username,
+ &user_prio, &group_prio);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ "ipa_deskprofile_rule_check_memberuser() failed [%d]: %s\n",
+ ret, sss_strerror(ret));
+ goto done;
+ }
+ }
+
+ if (hostcat != NULL && strcasecmp(hostcat, "all") == 0) {
+ host_prio = talloc_strdup(tmp_ctx, rule_prio);
+ if (host_prio == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ "Failed to allocate the host priority "
+ "when host category is \"all\"\n");
+ ret = ENOMEM;
+ goto done;
+ }
+
+ hostgroup_prio = talloc_strdup(tmp_ctx, rule_prio);
+ if (hostgroup_prio == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ "Failed to allocate the hostgroup priority "
+ "when host category is \"all\"\n");
+ ret = ENOMEM;
+ goto done;
+ }
+ } else {
+ ret = ipa_deskprofile_rule_check_memberhost(tmp_ctx, domain, rule,
+ rule_name, rule_prio,
+ base_dn, hostname,
+ &host_prio, &hostgroup_prio);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ "ipa_deskprofile_rule_check_memberhost() failed [%d]: %s\n",
+ ret, sss_strerror(ret));
+ goto done;
+ }
+ }
+
+ ret = ipa_deskprofile_get_normalized_rule_name(mem_ctx, rule_name,
+ &normalized_rule_name);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ "ipa_deskprofile_get_normalized_rule_name() failed [%d]: %s\n",
+ ret, sss_strerror(ret));
+ goto done;
+ }
+
+ ret = ipa_deskprofile_get_filename_path(tmp_ctx,
+ priority,
+ IPA_DESKPROFILE_RULES_USER_DIR,
+ domainname,
+ shortname,
+ rule_prio,
+ user_prio,
+ group_prio,
+ host_prio,
+ hostgroup_prio,
+ normalized_rule_name,
+ extension,
+ &filename_path);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ "ipa_deskprofile_get_filename_path() failed [%d]: %s\n",
+ ret, sss_strerror(ret));
+ goto done;
+ }
+
+ ret = setegid(gid);
+ if (ret == -1) {
+ ret = errno;
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ "Unable to set effective group id (%"PRIu32") of the domain's "
+ "process [%d]: %s\n",
+ gid, ret, sss_strerror(ret));
+ goto done;
+ }
+
+ ret = seteuid(uid);
+ if (ret == -1) {
+ ret = errno;
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ "Unable to set effective user id (%"PRIu32") of the domain's "
+ "process [%d]: %s\n",
+ uid, ret, sss_strerror(ret));
+ goto done;
+ }
+
+ fd = open(filename_path, O_WRONLY | O_CREAT | O_TRUNC, 0400);
+ if (fd == -1) {
+ ret = errno;
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ "Failed to create the Desktop Profile rule file \"%s\" "
+ "[%d]: %s\n",
+ filename_path, ret, sss_strerror(ret));
+ goto done;
+ }
+
+ ret = dprintf(fd, "%s", data);
+ if (ret < 0) {
+ ret = EIO;
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ "Failed to write the content of the Desktop Profile rule for "
+ "the \"%s\" file.\n",
+ filename_path);
+ goto done;
+ }
+
+ ret = seteuid(orig_uid);
+ if (ret == -1) {
+ ret = errno;
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ "Failed to set the effect user id (%"PRIu32") of the domain's "
+ "process [%d]: %s\n",
+ orig_uid, ret, sss_strerror(ret));
+ goto done;
+ }
+
+ ret = setegid(orig_gid);
+ if (ret == -1) {
+ ret = errno;
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ "Failed to set the effect group id (%"PRIu32") of the domain's "
+ "process [%d]: %s\n",
+ orig_gid, ret, sss_strerror(ret));
+ goto done;
+ }
+
+ ret = EOK;
+
+done:
+ if (fd != -1) {
+ close(fd);
+ }
+ if (geteuid() != orig_uid) {
+ ret = seteuid(orig_uid);
+ if (ret == -1) {
+ ret = errno;
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ "Unable to set effective user id (%"PRIu32") of the "
+ "domain's process [%d]: %s\n",
+ orig_uid, ret, sss_strerror(ret));
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ "Sending SIGUSR2 to the process: %d\n", getpid());
+ kill(getpid(), SIGUSR2);
+ }
+ }
+ if (getegid() != orig_gid) {
+ ret = setegid(orig_gid);
+ if (ret == -1) {
+ ret = errno;
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ "Unable to set effective group id (%"PRIu32") of the "
+ "domain's process. Let's have the process restarted!\n",
+ orig_gid);
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ "Sending SIGUSR2 to the process: %d\n", getpid());
+ kill(getpid(), SIGUSR2);
+ }
+ }
+ talloc_free(tmp_ctx);
+ return ret;
+}
+
+errno_t
+ipa_deskprofile_rules_remove_user_dir(const char *user_dir,
+ uid_t uid,
+ gid_t gid)
+{
+ gid_t orig_gid;
+ uid_t orig_uid;
+ errno_t ret;
+
+ orig_gid = getegid();
+ orig_uid = geteuid();
+
+ ret = setegid(gid);
+ if (ret == -1) {
+ ret = errno;
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ "Unable to set effective group id (%"PRIu32") of the domain's "
+ "process [%d]: %s\n",
+ gid, ret, sss_strerror(ret));
+ goto done;
+ }
+
+ ret = seteuid(uid);
+ if (ret == -1) {
+ ret = errno;
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ "Unable to set effective user id (%"PRIu32") of the domain's "
+ "process [%d]: %s\n",
+ uid, ret, sss_strerror(ret));
+ goto done;
+ }
+
+ ret = sss_remove_subtree(user_dir);
+ if (ret != EOK && ret != ENOENT) {
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ "Cannot remove \"%s\" directory [%d]: %s\n",
+ user_dir, ret, sss_strerror(ret));
+ goto done;
+ }
+
+ ret = seteuid(orig_uid);
+ if (ret == -1) {
+ ret = errno;
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ "Failed to set the effect user id (%"PRIu32") of the domain's "
+ "process [%d]: %s\n",
+ orig_uid, ret, sss_strerror(ret));
+ goto done;
+ }
+
+ ret = setegid(orig_gid);
+ if (ret == -1) {
+ ret = errno;
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ "Failed to set the effect group id (%"PRIu32") of the domain's "
+ "process [%d]: %s\n",
+ orig_gid, ret, sss_strerror(ret));
+ goto done;
+ }
+
+ ret = sss_remove_tree(user_dir);
+ if ((ret != EOK) && (ret != ENOENT)) {
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ "Cannot remove \"%s\" directory [%d]: %s\n",
+ user_dir, ret, sss_strerror(ret));
+ goto done;
+ }
+
+ ret = EOK;
+
+done:
+ if (geteuid() != orig_uid) {
+ ret = seteuid(orig_uid);
+ if (ret == -1) {
+ ret = errno;
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ "unable to set effective user id (%"PRIu32") of the "
+ "domain's process [%d]: %s\n",
+ orig_uid, ret, sss_strerror(ret));
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ "Sending SIGUSR2 to the process: %d\n", getpid());
+ kill(getpid(), SIGUSR2);
+ }
+ }
+ if (getegid() != orig_gid) {
+ ret = setegid(orig_gid);
+ if (ret == -1) {
+ ret = errno;
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ "Unable to set effective user id (%"PRIu32") of the "
+ "domain's process [%d]: %s\n",
+ orig_uid, ret, sss_strerror(ret));
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ "Sending SIGUSR2 to the process: %d\n", getpid());
+ kill(getpid(), SIGUSR2);
+ }
+ }
+ return ret;
+}
+
+errno_t
+deskprofile_get_cached_priority(struct sss_domain_info *domain,
+ uint16_t *_priority)
+{
+ TALLOC_CTX *tmp_ctx;
+ const char *attrs[] = { IPA_DESKPROFILE_PRIORITY, NULL };
+ struct ldb_message **resp;
+ size_t resp_count;
+ errno_t ret;
+
+ tmp_ctx = talloc_new(NULL);
+ if (tmp_ctx == NULL) {
+ return ENOMEM;
+ }
+
+ ret = sysdb_search_custom_by_name(tmp_ctx,
+ domain,
+ IPA_DESKPROFILE_PRIORITY,
+ DESKPROFILE_CONFIG_SUBDIR,
+ attrs, &resp_count, &resp);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ "sysdb_search_custom_by_name() failed [%d]: %s\n",
+ ret, sss_strerror(ret));
+ goto done;
+ }
+
+ if (resp_count != 1) {
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ "sysdb_search_custom_by_name() got more attributes than "
+ "expected. Expected (1), got (%zu)\n", resp_count);
+ ret = EINVAL;
+ goto done;
+ }
+
+ *_priority = ldb_msg_find_attr_as_uint(resp[0],
+ IPA_DESKPROFILE_PRIORITY,
+ 0);
+ ret = EOK;
+
+done:
+ talloc_free(tmp_ctx);
+ return ret;
+}
+
+const char **
+deskprofile_get_attrs_to_get_cached_rules(TALLOC_CTX *mem_ctx)
+{
+ const char **attrs = talloc_zero_array(mem_ctx, const char *, 11);
+ if (attrs == NULL) {
+ DEBUG(SSSDBG_OP_FAILURE, "talloc_zero_array() failed\n");
+ goto done;
+ }
+
+ attrs[0] = OBJECTCLASS;
+ attrs[1] = IPA_CN;
+ attrs[2] = IPA_UNIQUE_ID;
+ attrs[3] = IPA_ENABLED_FLAG;
+ attrs[4] = IPA_MEMBER_USER;
+ attrs[5] = IPA_USER_CATEGORY;
+ attrs[6] = IPA_MEMBER_HOST;
+ attrs[7] = IPA_HOST_CATEGORY;
+ attrs[8] = IPA_DESKPROFILE_PRIORITY;
+ attrs[9] = IPA_DESKPROFILE_DATA;
+ attrs[10] = NULL;
+
+done:
+ return attrs;
+}