summaryrefslogtreecommitdiffstats
path: root/src/tools/sss_override.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/tools/sss_override.c')
-rw-r--r--src/tools/sss_override.c1975
1 files changed, 1975 insertions, 0 deletions
diff --git a/src/tools/sss_override.c b/src/tools/sss_override.c
new file mode 100644
index 0000000..cfd8f17
--- /dev/null
+++ b/src/tools/sss_override.c
@@ -0,0 +1,1975 @@
+/*
+ Authors:
+ Pavel Březina <pbrezina@redhat.com>
+
+ Copyright (C) 2015 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 <stdlib.h>
+
+#include "util/util.h"
+#include "util/crypto/sss_crypto.h"
+#include "db/sysdb.h"
+#include "tools/common/sss_tools.h"
+#include "tools/common/sss_colondb.h"
+
+#define LOCALVIEW SYSDB_LOCAL_VIEW_NAME
+#define ORIGNAME "originalName"
+
+struct override_user {
+ const char *input_name;
+ const char *orig_name;
+ const char *sysdb_name;
+ struct sss_domain_info *domain;
+
+ const char *name;
+ uid_t uid;
+ gid_t gid;
+ const char *home;
+ const char *shell;
+ const char *gecos;
+ const char *cert;
+};
+
+struct override_group {
+ const char *input_name;
+ const char *orig_name;
+ const char *sysdb_name;
+ struct sss_domain_info *domain;
+
+ const char *name;
+ gid_t gid;
+};
+
+static errno_t parse_cmdline(struct sss_cmdline *cmdline,
+ struct sss_tool_ctx *tool_ctx,
+ struct poptOption *options,
+ const char **_input_name,
+ const char **_orig_name,
+ struct sss_domain_info **_domain)
+{
+ enum sss_tool_opt require;
+ const char *input_name = NULL;
+ const char *orig_name;
+ struct sss_domain_info *domain;
+ errno_t ret;
+
+ *_input_name = NULL;
+ require = options == NULL ? SSS_TOOL_OPT_OPTIONAL : SSS_TOOL_OPT_REQUIRED;
+
+ ret = sss_tool_popt_ex(cmdline, options, require,
+ NULL, NULL, "NAME", _("Specify name."),
+ SSS_TOOL_OPT_REQUIRED, &input_name, NULL);
+ if (ret != EXIT_SUCCESS) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to parse command arguments\n");
+ return ret;
+ }
+
+ ret = sss_tool_parse_name(tool_ctx, tool_ctx, input_name,
+ &orig_name, &domain);
+ if (ret != EOK) {
+ ERROR("Unable to parse name %s.\n", input_name);
+ free(discard_const(input_name));
+ return ret;
+ }
+
+ *_input_name = input_name;
+ *_orig_name = orig_name;
+ *_domain = domain;
+
+ return EXIT_SUCCESS;
+}
+
+static errno_t parse_cmdline_user_add(struct sss_cmdline *cmdline,
+ struct sss_tool_ctx *tool_ctx,
+ struct override_user *user)
+{
+ struct poptOption options[] = {
+ {"name", 'n', POPT_ARG_STRING, &user->name, 0, _("Override name"), NULL },
+ {"uid", 'u', POPT_ARG_INT, &user->uid, 0, _("Override uid (non-zero value)"), NULL },
+ {"gid", 'g', POPT_ARG_INT, &user->gid, 0, _("Override gid (non-zero value)"), NULL },
+ {"home", 'h', POPT_ARG_STRING, &user->home, 0, _("Override home directory"), NULL },
+ {"shell", 's', POPT_ARG_STRING, &user->shell, 0, _("Override shell"), NULL },
+ {"gecos", 'c', POPT_ARG_STRING, &user->gecos, 0, _("Override gecos"), NULL },
+ {"certificate", 'x', POPT_ARG_STRING, &user->cert, 0, _("Override certificate"), NULL },
+ POPT_TABLEEND
+ };
+
+ return parse_cmdline(cmdline, tool_ctx, options, &user->input_name,
+ &user->orig_name, &user->domain);
+}
+
+static errno_t parse_cmdline_user_del(struct sss_cmdline *cmdline,
+ struct sss_tool_ctx *tool_ctx,
+ struct override_user *user)
+{
+ return parse_cmdline(cmdline, tool_ctx, NULL, &user->input_name,
+ &user->orig_name, &user->domain);
+}
+
+static errno_t parse_cmdline_user_show(struct sss_cmdline *cmdline,
+ struct sss_tool_ctx *tool_ctx,
+ struct override_user *user)
+{
+ return parse_cmdline(cmdline, tool_ctx, NULL, &user->input_name,
+ &user->orig_name, &user->domain);
+}
+
+static errno_t parse_cmdline_group_add(struct sss_cmdline *cmdline,
+ struct sss_tool_ctx *tool_ctx,
+ struct override_group *group)
+{
+ struct poptOption options[] = {
+ {"name", 'n', POPT_ARG_STRING, &group->name, 0, _("Override name"), NULL },
+ {"gid", 'g', POPT_ARG_INT, &group->gid, 0, _("Override gid"), NULL },
+ POPT_TABLEEND
+ };
+
+ return parse_cmdline(cmdline, tool_ctx, options, &group->input_name,
+ &group->orig_name, &group->domain);
+}
+
+static errno_t parse_cmdline_group_del(struct sss_cmdline *cmdline,
+ struct sss_tool_ctx *tool_ctx,
+ struct override_group *group)
+{
+ return parse_cmdline(cmdline, tool_ctx, NULL, &group->input_name,
+ &group->orig_name, &group->domain);
+}
+
+static errno_t parse_cmdline_group_show(struct sss_cmdline *cmdline,
+ struct sss_tool_ctx *tool_ctx,
+ struct override_group *group)
+{
+ return parse_cmdline(cmdline, tool_ctx, NULL, &group->input_name,
+ &group->orig_name, &group->domain);
+}
+
+static errno_t parse_cmdline_find(struct sss_cmdline *cmdline,
+ struct sss_tool_ctx *tool_ctx,
+ struct sss_domain_info **_dom)
+{
+ struct sss_domain_info *dom;
+ const char *domname = NULL;
+ errno_t ret;
+ struct poptOption options[] = {
+ {"domain", 'd', POPT_ARG_STRING | POPT_ARGFLAG_OPTIONAL,
+ &domname, 0, _("Domain name"), NULL },
+ POPT_TABLEEND
+ };
+
+ ret = sss_tool_popt_ex(cmdline, options, SSS_TOOL_OPT_OPTIONAL,
+ NULL, NULL, NULL, NULL, SSS_TOOL_OPT_REQUIRED,
+ NULL, NULL);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to parse command arguments\n");
+ return ret;
+ }
+
+ if (domname == NULL) {
+ *_dom = NULL;
+ return EOK;
+ }
+
+ dom = find_domain_by_name(tool_ctx->domains, domname, true);
+ if (dom == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to find domain %s\n", domname);
+ ERROR("Unable to find domain %s\n", domname);
+ return EINVAL;
+ }
+
+ *_dom = dom;
+
+ return EOK;
+}
+
+static errno_t parse_cmdline_import(struct sss_cmdline *cmdline,
+ const char **_file)
+{
+ errno_t ret;
+
+ ret = sss_tool_popt_ex(cmdline, NULL, SSS_TOOL_OPT_OPTIONAL,
+ NULL, NULL, "FILE", "File to import the data from.",
+ SSS_TOOL_OPT_REQUIRED, _file, NULL);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to parse command arguments\n");
+ return ret;
+ }
+
+ return EOK;
+}
+
+static errno_t parse_cmdline_export(struct sss_cmdline *cmdline,
+ const char **_file)
+{
+ errno_t ret;
+
+ ret = sss_tool_popt_ex(cmdline, NULL, SSS_TOOL_OPT_OPTIONAL,
+ NULL, NULL, "FILE", "File to export the data to.",
+ SSS_TOOL_OPT_REQUIRED, _file, NULL);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to parse command arguments\n");
+ return ret;
+ }
+
+ return EOK;
+}
+
+static errno_t prepare_view(struct sss_domain_info *domain)
+{
+ char *viewname = NULL;
+ errno_t ret;
+
+ ret = sysdb_get_view_name(NULL, domain->sysdb, &viewname);
+ if (ret != EOK && ret != ENOENT) {
+ DEBUG(SSSDBG_OP_FAILURE, "sysdb_get_view_name() failed.\n");
+ return ret;
+ }
+
+ if (ret == EOK) {
+ if (is_local_view(viewname)) {
+ DEBUG(SSSDBG_TRACE_FUNC, "%s view is already present.\n", viewname);
+ ret = EOK;
+ goto done;
+ } else if (viewname != NULL) {
+ DEBUG(SSSDBG_MINOR_FAILURE, "There already exists view %s. "
+ "Only one view is supported. Nothing to do.\n", viewname);
+ ret = EEXIST;
+ goto done;
+ }
+ }
+
+ DEBUG(SSSDBG_TRACE_FUNC, "Creating %s view.\n", LOCALVIEW);
+
+ ret = sysdb_update_view_name(domain->sysdb, LOCALVIEW);
+ if (ret == EOK) {
+ printf("SSSD needs to be restarted for the changes to take effect.\n");
+ }
+
+done:
+ talloc_free(viewname);
+ return ret;
+}
+
+errno_t prepare_view_msg(struct sss_domain_info *domain)
+{
+ errno_t ret;
+
+ ret = prepare_view(domain);
+ if (ret == EEXIST) {
+ ERROR("Other than " LOCALVIEW " view already exists "
+ "in domain %s.\n", domain->name);
+ } else if (ret != EOK) {
+ ERROR("Unable to prepare " LOCALVIEW
+ " view in domain %s.\n", domain->name);
+ }
+
+ return ret;
+}
+
+static char *build_anchor(TALLOC_CTX *mem_ctx, const char *obj_dn)
+{
+ char *anchor;
+ char *safe_dn;
+ errno_t ret;
+
+ ret = sysdb_dn_sanitize(mem_ctx, obj_dn, &safe_dn);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "sysdb_dn_sanitize() failed\n");
+ return NULL;
+ }
+
+ anchor = talloc_asprintf(mem_ctx, ":%s:%s", LOCALVIEW, safe_dn);
+
+ talloc_free(safe_dn);
+
+ return anchor;
+}
+
+static struct sysdb_attrs *build_attrs(TALLOC_CTX *mem_ctx,
+ struct sss_domain_info *dom,
+ const char *name,
+ uid_t uid,
+ gid_t gid,
+ const char *home,
+ const char *shell,
+ const char *gecos,
+ const char *cert)
+{
+ struct sysdb_attrs *attrs;
+ errno_t ret;
+ char *fqname;
+
+ attrs = sysdb_new_attrs(mem_ctx);
+ if (attrs == NULL) {
+ return NULL;
+ }
+
+ if (name != NULL) {
+ fqname = sss_create_internal_fqname(attrs, name, dom->name);
+ if (fqname == NULL) {
+ return NULL;
+ }
+
+ ret = sysdb_attrs_add_string(attrs, SYSDB_NAME, fqname);
+ talloc_free(fqname);
+ if (ret != EOK) {
+ goto done;
+ }
+ }
+
+ if (uid != 0) {
+ ret = sysdb_attrs_add_uint32(attrs, SYSDB_UIDNUM, uid);
+ if (ret != EOK) {
+ goto done;
+ }
+ }
+
+ if (gid != 0) {
+ ret = sysdb_attrs_add_uint32(attrs, SYSDB_GIDNUM, gid);
+ if (ret != EOK) {
+ goto done;
+ }
+ }
+
+ if (home != NULL) {
+ ret = sysdb_attrs_add_string(attrs, SYSDB_HOMEDIR, home);
+ if (ret != EOK) {
+ goto done;
+ }
+ }
+
+ if (shell != NULL) {
+ ret = sysdb_attrs_add_string(attrs, SYSDB_SHELL, shell);
+ if (ret != EOK) {
+ goto done;
+ }
+ }
+
+ if (gecos != NULL) {
+ ret = sysdb_attrs_add_string(attrs, SYSDB_GECOS, gecos);
+ if (ret != EOK) {
+ goto done;
+ }
+ }
+
+ if (cert != NULL) {
+ ret = sysdb_attrs_add_base64_blob(attrs, SYSDB_USER_CERT, cert);
+ if (ret != EOK) {
+ goto done;
+ }
+ }
+
+ ret = EOK;
+
+done:
+ if (ret != EOK) {
+ talloc_free(attrs);
+ return NULL;
+ }
+
+ return attrs;
+}
+
+static struct sysdb_attrs *build_user_attrs(TALLOC_CTX *mem_ctx,
+ struct override_user *user)
+{
+ return build_attrs(mem_ctx, user->domain, user->name, user->uid, user->gid,
+ user->home, user->shell, user->gecos, user->cert);
+}
+
+static struct sysdb_attrs *build_group_attrs(TALLOC_CTX *mem_ctx,
+ struct override_group *group)
+{
+ return build_attrs(mem_ctx, group->domain, group->name, 0, group->gid,
+ 0, NULL, NULL, NULL);
+}
+
+static char *get_fqname(TALLOC_CTX *mem_ctx,
+ struct sss_domain_info *domain,
+ const char *name)
+{
+ char *fqname = NULL;
+ char *dummy_domain = NULL;
+ errno_t ret;
+ TALLOC_CTX *tmp_ctx;
+ char *shortname;
+ struct sss_domain_info *dom;
+
+ if (domain == NULL || domain->names == NULL) {
+ return NULL;
+ }
+
+ tmp_ctx = talloc_new(NULL);
+ if (tmp_ctx == NULL) {
+ return NULL;
+ }
+
+ /* the name stored in sysdb already contains the lowercased domain */
+ ret = sss_parse_internal_fqname(tmp_ctx, name, &shortname, &dummy_domain);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_TRACE_FUNC,
+ "sss_parse_internal_fqname failed [%d]: %s\n",
+ ret, sss_strerror(ret));
+ goto done;
+ }
+
+ dom = find_domain_by_name(get_domains_head(domain), dummy_domain, true);
+ if (dom == NULL) {
+ goto done;
+ }
+
+ /* Get length. */
+ fqname = sss_tc_fqname(mem_ctx, dom->names, dom, shortname);
+done:
+ talloc_free(tmp_ctx);
+ return fqname;
+}
+
+static char *get_sysname(TALLOC_CTX *mem_ctx,
+ struct sss_domain_info *domain,
+ const char *name)
+{
+ if (domain == NULL || !domain->fqnames) {
+ return talloc_strdup(mem_ctx, name);
+ }
+
+ return sss_tc_fqname(mem_ctx, domain->names, domain, name);
+}
+
+static struct sss_domain_info *
+get_object_domain(enum sysdb_member_type type,
+ const char *name,
+ struct sss_domain_info *domain,
+ struct sss_domain_info *domains)
+{
+ TALLOC_CTX *tmp_ctx;
+ struct sss_domain_info *dom = NULL;
+ struct ldb_result *res;
+ const char *strtype;
+ char *sysname;
+ char *fqname = NULL;
+ bool check_next;
+ errno_t ret;
+
+ tmp_ctx = talloc_new(NULL);
+ if (tmp_ctx == NULL) {
+ return NULL;
+ }
+
+ sysname = get_sysname(tmp_ctx, domain, name);
+ if (sysname == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ /* Ensure that the object is in cache. */
+ switch (type) {
+ case SYSDB_MEMBER_USER:
+ if (getpwnam(sysname) == NULL) {
+ ret = ENOENT;
+ goto done;
+ }
+ break;
+ case SYSDB_MEMBER_GROUP:
+ if (getgrnam(sysname) == NULL) {
+ ret = ENOENT;
+ goto done;
+ }
+ break;
+ default:
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unsupported member type %d\n", type);
+ ret = ERR_INTERNAL;
+ goto done;
+ }
+
+ /* Find domain if it is unknown. */
+ if (domain == NULL) {
+ check_next = true;
+ dom = domains;
+ } else {
+ check_next = false;
+ dom = domain;
+ }
+
+ do {
+ talloc_zfree(fqname);
+ fqname = sss_create_internal_fqname(tmp_ctx, name, dom->name);
+ if (fqname == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ switch (type) {
+ case SYSDB_MEMBER_USER:
+ DEBUG(SSSDBG_TRACE_FUNC, "Trying to find user %s@%s\n",
+ name, dom->name);
+ ret = sysdb_getpwnam(tmp_ctx, dom, fqname, &res);
+ strtype = "user";
+ break;
+ case SYSDB_MEMBER_GROUP:
+ DEBUG(SSSDBG_TRACE_FUNC, "Trying to find group %s@%s\n",
+ name, dom->name);
+ ret = sysdb_getgrnam(tmp_ctx, dom, fqname, &res);
+ strtype = "group";
+ break;
+ default:
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unsupported member type %d\n", type);
+ ret = ERR_INTERNAL;
+ goto done;
+ }
+
+ if (ret == EOK && res->count == 0) {
+ ret = ENOENT;
+
+ if (check_next) {
+ dom = dom->next;
+ continue;
+ }
+ }
+
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to find %s %s@%s [%d]: %s\n",
+ strtype, name, dom->name, ret, sss_strerror(ret));
+ goto done;
+ } else if (res->count != 1) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "More than one %s found?\n", strtype);
+ ret = ERR_INTERNAL;
+ goto done;
+ }
+
+ check_next = false;
+ } while (check_next && dom != NULL);
+
+ if (dom == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "No domain match for %s\n", name);
+ ret = ENOENT;
+ goto done;
+ }
+
+ DEBUG(SSSDBG_TRACE_FUNC, "Domain of %s %s is %s\n",
+ strtype, name, dom->name);
+
+done:
+ talloc_free(tmp_ctx);
+
+ if (ret != EOK) {
+ return NULL;
+ }
+
+ return dom;
+}
+
+static errno_t get_user_domain_msg(struct sss_tool_ctx *tool_ctx,
+ struct override_user *user)
+{
+ struct sss_domain_info *newdom;
+ const char *domname;
+
+ newdom = get_object_domain(SYSDB_MEMBER_USER, user->orig_name,
+ user->domain, tool_ctx->domains);
+ if (newdom == NULL) {
+ domname = user->domain == NULL ? "[unknown]" : user->domain->name;
+ ERROR("Unable to find user %s@%s.\n", user->orig_name, domname);
+ return ENOENT;
+ }
+
+ user->sysdb_name = sss_create_internal_fqname(tool_ctx, user->orig_name,
+ newdom->name);
+ if (user->sysdb_name == NULL) {
+ return ENOMEM;
+ }
+
+ user->domain = newdom;
+ return EOK;
+}
+
+static errno_t get_group_domain_msg(struct sss_tool_ctx *tool_ctx,
+ struct override_group *group)
+{
+ struct sss_domain_info *newdom;
+ const char *domname;
+
+ newdom = get_object_domain(SYSDB_MEMBER_GROUP, group->orig_name,
+ group->domain, tool_ctx->domains);
+ if (newdom == NULL) {
+ domname = group->domain == NULL ? "[unknown]" : group->domain->name;
+ ERROR("Unable to find group %s@%s.\n", group->orig_name, domname);
+ return ENOENT;
+ }
+
+ group->sysdb_name = sss_create_internal_fqname(tool_ctx, group->orig_name,
+ newdom->name);
+ if (group->sysdb_name == NULL) {
+ return ENOMEM;
+ }
+
+ group->domain = newdom;
+ return EOK;
+}
+
+static errno_t get_object_dn(TALLOC_CTX *mem_ctx,
+ struct sss_domain_info *domain,
+ enum sysdb_member_type type,
+ const char *name,
+ struct ldb_dn **_ldb_dn,
+ const char **_str_dn)
+{
+ TALLOC_CTX *tmp_ctx;
+ struct ldb_dn *ldb_dn;
+ const char *str_dn;
+ errno_t ret;
+ struct ldb_result *res;
+
+ tmp_ctx = talloc_new(NULL);
+ if (tmp_ctx == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "talloc_new() failed\n");
+ return ENOMEM;
+ }
+
+ switch (type) {
+ case SYSDB_MEMBER_USER:
+ ret = sysdb_getpwnam(tmp_ctx, domain, name, &res);
+ break;
+ case SYSDB_MEMBER_GROUP:
+ ret = sysdb_getgrnam(tmp_ctx, domain, name, &res);
+ break;
+ default:
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unsupported member type %d\n", type);
+ ret = ERR_INTERNAL;
+ goto done;
+ }
+
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ "Failed to look up original object in cache.\n");
+ goto done;
+ }
+
+ if (res->count == 0) {
+ DEBUG(SSSDBG_MINOR_FAILURE, "Original object not found in cache.\n");
+ ret = ENOENT;
+ goto done;
+ } else if (res->count > 1) {
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ "There are multiple object with name [%s] in the cache.\n", name);
+ ret = EINVAL;
+ goto done;
+ }
+
+ ldb_dn = res->msgs[0]->dn;
+
+ if (ldb_dn == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ if (_str_dn != NULL) {
+ str_dn = talloc_strdup(tmp_ctx, ldb_dn_get_linearized(ldb_dn));
+ if (str_dn == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ *_str_dn = talloc_steal(mem_ctx, str_dn);
+ }
+
+ if (_ldb_dn != NULL) {
+ *_ldb_dn = talloc_steal(mem_ctx, ldb_dn);
+ }
+
+ ret = EOK;
+
+done:
+ talloc_free(tmp_ctx);
+
+ return ret;
+}
+
+static errno_t override_object_add(struct sss_domain_info *domain,
+ enum sysdb_member_type type,
+ struct sysdb_attrs *attrs,
+ const char *name)
+{
+ TALLOC_CTX *tmp_ctx;
+ const char *anchor;
+ struct ldb_dn *ldb_dn;
+ const char *str_dn;
+ errno_t ret;
+
+ tmp_ctx = talloc_new(NULL);
+ if (tmp_ctx == NULL) {
+ return ENOMEM;
+ }
+
+ ret = get_object_dn(tmp_ctx, domain, type, name, &ldb_dn, &str_dn);
+ if (ret != EOK) {
+ goto done;
+ }
+
+ anchor = build_anchor(tmp_ctx, str_dn);
+ if (anchor == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ ret = sysdb_attrs_add_string(attrs, SYSDB_OVERRIDE_ANCHOR_UUID, anchor);
+ if (ret != EOK) {
+ goto done;
+ }
+
+ DEBUG(SSSDBG_TRACE_FUNC, "Creating override for %s\n", str_dn);
+
+ ret = sysdb_store_override(domain, LOCALVIEW, type, attrs, ldb_dn);
+
+done:
+ talloc_free(tmp_ctx);
+ return ret;
+}
+
+static errno_t override_fqn(TALLOC_CTX *mem_ctx,
+ struct sss_tool_ctx *tool_ctx,
+ struct sss_domain_info *domain,
+ const char *input,
+ const char **_name)
+{
+ struct sss_domain_info *dom;
+ errno_t ret;
+
+ if (input == NULL) {
+ return EOK;
+ }
+
+ ret = sss_tool_parse_name(mem_ctx, tool_ctx, input, _name, &dom);
+ if (ret == EAGAIN) {
+ DEBUG(SSSDBG_OP_FAILURE, "Unable to find domain from "
+ "fqn %s\n", input);
+ ERROR("Changing domain is not allowed!\n");
+ ret = EINVAL;
+ } else if (ret == EOK && dom != NULL && dom != domain) {
+ DEBUG(SSSDBG_OP_FAILURE, "Trying to change domain from "
+ "%s to %s, not allowed!\n", domain->name, dom->name);
+ ERROR("Changing domain is not allowed!\n");
+ ret = EINVAL;
+ } else if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to parse name %s [%d]: %s\n",
+ input, ret, sss_strerror(ret));
+ }
+
+ return ret;
+}
+
+static errno_t override_user(struct sss_tool_ctx *tool_ctx,
+ struct override_user *input_user)
+{
+ TALLOC_CTX *tmp_ctx;
+ struct override_user user;
+ struct sysdb_attrs *attrs;
+ errno_t ret;
+
+ tmp_ctx = talloc_new(NULL);
+ if (tmp_ctx == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "talloc_new() failed\n");
+ return ENOMEM;
+ }
+
+ user = *input_user;
+
+ /* We need to parse the name and ensure that domain did not change. */
+ ret = override_fqn(tmp_ctx, tool_ctx, user.domain, user.name, &user.name);
+ if (ret != EOK) {
+ goto done;
+ }
+
+ ret = prepare_view_msg(user.domain);
+ if (ret != EOK) {
+ goto done;
+ }
+
+ attrs = build_user_attrs(tool_ctx, &user);
+ if (attrs == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to build sysdb attrs.\n");
+ ret = ENOMEM;
+ goto done;
+ }
+
+ ret = override_object_add(user.domain, SYSDB_MEMBER_USER, attrs,
+ user.sysdb_name);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to add override object.\n");
+ goto done;
+ }
+
+ ret = EOK;
+
+done:
+ talloc_free(tmp_ctx);
+ return ret;
+}
+
+static errno_t override_group(struct sss_tool_ctx *tool_ctx,
+ struct override_group *input_group)
+{
+ TALLOC_CTX *tmp_ctx;
+ struct override_group group;
+ struct sysdb_attrs *attrs;
+ errno_t ret;
+
+ tmp_ctx = talloc_new(NULL);
+ if (tmp_ctx == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "talloc_new() failed\n");
+ return ENOMEM;
+ }
+
+ group = *input_group;
+
+ /* We need to parse the name and ensure that domain did not change. */
+ ret = override_fqn(tmp_ctx, tool_ctx, group.domain, group.name,
+ &group.name);
+ if (ret != EOK) {
+ goto done;
+ }
+
+ ret = prepare_view_msg(group.domain);
+ if (ret != EOK) {
+ goto done;
+ }
+
+ attrs = build_group_attrs(tool_ctx, &group);
+ if (attrs == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to build sysdb attrs.\n");
+ ret = ENOMEM;
+ goto done;
+ }
+
+ ret = override_object_add(group.domain, SYSDB_MEMBER_GROUP, attrs,
+ group.sysdb_name);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to add override object.\n");
+ goto done;
+ }
+
+ ret = EOK;
+
+done:
+ talloc_free(tmp_ctx);
+ return ret;
+}
+
+static errno_t override_object_del(struct sss_domain_info *domain,
+ enum sysdb_member_type type,
+ const char *name)
+{
+ TALLOC_CTX *tmp_ctx;
+ struct ldb_message *msg;
+ struct ldb_dn *override_dn;
+ struct ldb_dn *ldb_dn;
+ const char *str_dn;
+ const char *anchor;
+ errno_t ret;
+ int sret;
+ bool in_transaction = false;
+ struct ldb_context *ldb = sysdb_ctx_get_ldb(domain->sysdb);
+
+ tmp_ctx = talloc_new(NULL);
+ if (tmp_ctx == NULL) {
+ return ENOMEM;
+ }
+
+ ret = get_object_dn(tmp_ctx, domain, type, name, &ldb_dn, &str_dn);
+ if (ret != EOK) {
+ goto done;
+ }
+
+ anchor = build_anchor(tmp_ctx, str_dn);
+ if (anchor == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ override_dn = ldb_dn_new_fmt(tmp_ctx, ldb,
+ SYSDB_TMPL_OVERRIDE, anchor, LOCALVIEW);
+ if (override_dn == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ DEBUG(SSSDBG_TRACE_FUNC, "Removing override for %s\n", str_dn);
+
+ ret = sysdb_transaction_start(domain->sysdb);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE, "sysdb_transaction_start() failed.\n");
+ goto done;
+ }
+ in_transaction = true;
+
+ ret = sysdb_delete_entry(domain->sysdb, override_dn, true);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE, "sysdb_delete_entry() failed.\n");
+ goto done;
+ }
+
+ msg = ldb_msg_new(tmp_ctx);
+ if (msg == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ msg->dn = talloc_steal(msg, ldb_dn);
+ if (msg->dn == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ ret = ldb_msg_add_empty(msg, SYSDB_OVERRIDE_DN, LDB_FLAG_MOD_DELETE, NULL);
+ if (ret != LDB_SUCCESS) {
+ DEBUG(SSSDBG_OP_FAILURE, "ldb_msg_add_empty() failed\n");
+ ret = sss_ldb_error_to_errno(ret);
+ goto done;
+ }
+
+ ret = ldb_modify(ldb, msg);
+ if (ret != LDB_SUCCESS && ret != LDB_ERR_NO_SUCH_ATTRIBUTE) {
+ DEBUG(SSSDBG_OP_FAILURE,
+ "ldb_modify() failed: [%s](%d)[%s]\n",
+ ldb_strerror(ret), ret, ldb_errstring(ldb));
+ ret = sss_ldb_error_to_errno(ret);
+ goto done;
+ }
+
+ ret = sysdb_transaction_commit(domain->sysdb);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Failed to commit transaction\n");
+ goto done;
+ }
+ in_transaction = false;
+
+ ret = EOK;
+
+done:
+ if (in_transaction) {
+ sret = sysdb_transaction_cancel(domain->sysdb);
+ if (sret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Could not cancel transaction\n");
+ }
+ }
+
+ talloc_free(tmp_ctx);
+ return ret;
+}
+
+static errno_t append_name(struct sss_domain_info *domain,
+ struct ldb_message *override)
+{
+ TALLOC_CTX *tmp_ctx;
+ struct ldb_context *ldb = sysdb_ctx_get_ldb(domain->sysdb);
+ struct ldb_dn *dn;
+ struct ldb_message **msgs;
+ const char *attrs[] = {SYSDB_NAME, NULL};
+ const char *name;
+ const char *fqname;
+ size_t count;
+ errno_t ret;
+
+ tmp_ctx = talloc_new(NULL);
+ if (tmp_ctx == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "talloc_new() failed.\n");
+ return ENOMEM;
+ }
+
+ dn = ldb_msg_find_attr_as_dn(ldb, tmp_ctx, override,
+ SYSDB_OVERRIDE_OBJECT_DN);
+ if (dn == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Missing overrideObjectDN?\n");
+ ret = ERR_INTERNAL;
+ goto done;
+ }
+
+ ret = sysdb_search_entry(tmp_ctx, domain->sysdb, dn, LDB_SCOPE_BASE,
+ NULL, attrs, &count, &msgs);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "sysdb_search_entry() failed [%d]: %s\n",
+ ret, sss_strerror(ret));
+ goto done;
+ } else if (count != 1) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "More than one user found?\n");
+ ret = ERR_INTERNAL;
+ goto done;
+ }
+
+ name = ldb_msg_find_attr_as_string(msgs[0], SYSDB_NAME, NULL);
+ if (name == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Object with no name?\n");
+ ret = ERR_INTERNAL;
+ goto done;
+ }
+
+ fqname = get_fqname(tmp_ctx, domain, name);
+ if (fqname == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to get fqname\n");
+ ret = ENOMEM;
+ goto done;
+ }
+
+ ret = ldb_msg_add_string(override, ORIGNAME, fqname);
+ if (ret != LDB_SUCCESS) {
+ ret = sss_ldb_error_to_errno(ret);
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to add attribute to msg\n");
+ goto done;
+ }
+
+ talloc_steal(override, fqname);
+
+ ret = EOK;
+
+done:
+ talloc_free(tmp_ctx);
+
+ return ret;
+}
+
+static errno_t list_overrides(TALLOC_CTX *mem_ctx,
+ const char *base_filter,
+ const char *ext_filter,
+ const char **attrs,
+ struct sss_domain_info *domain,
+ size_t *_count,
+ struct ldb_message ***_msgs)
+{
+ TALLOC_CTX *tmp_ctx;
+ struct ldb_dn *dn;
+ struct ldb_context *ldb = sysdb_ctx_get_ldb(domain->sysdb);
+ size_t count;
+ struct ldb_message **msgs;
+ const char *filter;
+ size_t i;
+ errno_t ret;
+
+ tmp_ctx = talloc_new(NULL);
+ if (tmp_ctx == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "talloc_new() failed.\n");
+ return ENOMEM;
+ }
+
+ filter = base_filter;
+ if (ext_filter != NULL) {
+ filter = talloc_asprintf(tmp_ctx, "(&%s%s)", filter, ext_filter);
+ if (filter == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "talloc_asprintf() failed.\n");
+ ret = ENOMEM;
+ goto done;
+ }
+ }
+
+ /* Acquire list of override objects. */
+ dn = ldb_dn_new_fmt(tmp_ctx, ldb, SYSDB_TMPL_VIEW_SEARCH_BASE, LOCALVIEW);
+ if (dn == NULL) {
+ DEBUG(SSSDBG_OP_FAILURE, "ldb_dn_new_fmt() failed.\n");
+ ret = EIO;
+ goto done;
+ }
+
+ ret = sysdb_search_entry(tmp_ctx, domain->sysdb, dn, LDB_SCOPE_SUBTREE,
+ filter, attrs, &count, &msgs);
+ if (ret == ENOENT) {
+ *_msgs = NULL;
+ *_count = 0;
+ ret = EOK;
+ goto done;
+ } else if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "sysdb_search_entry() failed [%d]: %s\n",
+ ret, sss_strerror(ret));
+ goto done;
+ }
+
+ /* Amend messages with original name. */
+ for (i = 0; i < count; i++) {
+ ret = append_name(domain, msgs[i]);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to append name [%d]: %s\n",
+ ret, sss_strerror(ret));
+ goto done;
+ }
+ }
+
+ *_msgs = talloc_steal(mem_ctx, msgs);
+ *_count = count;
+
+ ret = EOK;
+
+done:
+ talloc_free(tmp_ctx);
+
+ return ret;
+}
+
+static struct override_user *
+list_user_overrides(TALLOC_CTX *mem_ctx,
+ struct sss_domain_info *domain,
+ const char *filter)
+{
+ TALLOC_CTX *tmp_ctx;
+ struct override_user *objs = NULL;
+ struct ldb_message **msgs;
+ size_t count;
+ size_t i;
+ errno_t ret;
+ const char *attrs[] = SYSDB_PW_ATTRS;
+ struct ldb_message_element *el;
+ const char *fqname;
+ char *name;
+
+ tmp_ctx = talloc_new(NULL);
+ if (tmp_ctx == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "talloc_new() failed.\n");
+ return NULL;
+ }
+
+ ret = list_overrides(tmp_ctx, "(objectClass=" SYSDB_OVERRIDE_USER_CLASS ")",
+ filter, attrs, domain, &count, &msgs);
+ if (ret != EOK) {
+ goto done;
+ }
+
+ objs = talloc_zero_array(tmp_ctx, struct override_user, count + 1);
+ if (objs == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ for (i = 0; i < count; i++) {
+ objs[i].orig_name = ldb_msg_find_attr_as_string(msgs[i], ORIGNAME,
+ NULL);
+ if (objs[i].orig_name == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Missing name?!\n");
+ ret = ERR_INTERNAL;
+ goto done;
+ }
+
+ fqname = ldb_msg_find_attr_as_string(msgs[i], SYSDB_NAME, NULL);
+ if (fqname != NULL) {
+ ret = sss_parse_internal_fqname(tmp_ctx, fqname, &name, NULL);
+ if (ret != EOK) {
+ ret = ERR_WRONG_NAME_FORMAT;
+ goto done;
+ }
+ objs[i].name = talloc_steal(objs, name);
+ }
+
+ objs[i].uid = ldb_msg_find_attr_as_uint(msgs[i], SYSDB_UIDNUM, 0);
+ objs[i].gid = ldb_msg_find_attr_as_uint(msgs[i], SYSDB_GIDNUM, 0);
+ objs[i].home = ldb_msg_find_attr_as_string(msgs[i], SYSDB_HOMEDIR, NULL);
+ objs[i].shell = ldb_msg_find_attr_as_string(msgs[i], SYSDB_SHELL, NULL);
+ objs[i].gecos = ldb_msg_find_attr_as_string(msgs[i], SYSDB_GECOS, NULL);
+
+ el = ldb_msg_find_element(msgs[i], SYSDB_USER_CERT);
+ if (el != NULL && el->num_values > 0) {
+ /* Currently we support only 1 certificate override */
+ objs[i].cert = sss_base64_encode(objs, el->values[0].data,
+ el->values[0].length);
+ if (objs[i].cert == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "sss_base64_encode failed.\n");
+ ret = ERR_INTERNAL;
+ goto done;
+ }
+ } else {
+ objs[i].cert = NULL;
+ }
+
+ talloc_steal(objs, objs[i].orig_name);
+ talloc_steal(objs, objs[i].home);
+ talloc_steal(objs, objs[i].shell);
+ talloc_steal(objs, objs[i].gecos);
+ }
+
+ talloc_steal(mem_ctx, objs);
+
+done:
+ talloc_free(tmp_ctx);
+
+ if (ret != EOK) {
+ return NULL;
+ }
+
+ return objs;
+}
+
+static struct override_group *
+list_group_overrides(TALLOC_CTX *mem_ctx,
+ struct sss_domain_info *domain,
+ const char *filter)
+{
+ TALLOC_CTX *tmp_ctx;
+ struct override_group *objs = NULL;
+ struct ldb_message **msgs;
+ size_t count;
+ size_t i;
+ errno_t ret;
+ const char *attrs[] = SYSDB_GRSRC_ATTRS;
+ const char *fqname;
+ char *name;
+
+ tmp_ctx = talloc_new(NULL);
+ if (tmp_ctx == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "talloc_new() failed.\n");
+ return NULL;
+ }
+
+ ret = list_overrides(tmp_ctx, "(objectClass=" SYSDB_OVERRIDE_GROUP_CLASS ")",
+ filter, attrs, domain, &count, &msgs);
+ if (ret != EOK) {
+ goto done;
+ }
+
+ objs = talloc_zero_array(tmp_ctx, struct override_group, count + 1);
+ if (objs == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ for (i = 0; i < count; i++) {
+ objs[i].orig_name = ldb_msg_find_attr_as_string(msgs[i], ORIGNAME,
+ NULL);
+ if (objs[i].orig_name == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Missing name?!\n");
+ ret = ERR_INTERNAL;
+ goto done;
+ }
+ talloc_steal(objs, objs[i].orig_name);
+
+ fqname = ldb_msg_find_attr_as_string(msgs[i], SYSDB_NAME, NULL);
+ if (fqname != NULL) {
+ ret = sss_parse_internal_fqname(tmp_ctx, fqname, &name, NULL);
+ if (ret != EOK) {
+ ret = ERR_WRONG_NAME_FORMAT;
+ goto done;
+ }
+ objs[i].name = talloc_steal(objs, name);
+ }
+
+ objs[i].gid = ldb_msg_find_attr_as_uint(msgs[i], SYSDB_GIDNUM, 0);
+ }
+
+ talloc_steal(mem_ctx, objs);
+
+done:
+ talloc_free(tmp_ctx);
+
+ if (ret != EOK) {
+ return NULL;
+ }
+
+ return objs;
+}
+
+static errno_t user_export(const char *filename,
+ struct sss_domain_info *dom,
+ bool iterate,
+ const char *filter)
+{
+ TALLOC_CTX *tmp_ctx;
+ struct sss_colondb *db;
+ struct override_user *objs;
+ errno_t ret;
+ int i;
+
+ tmp_ctx = talloc_new(NULL);
+ if (tmp_ctx == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "talloc_new() failed\n");
+ return ENOMEM;
+ }
+
+ db = sss_colondb_open(tmp_ctx, SSS_COLONDB_WRITE, filename);
+ if (db == NULL) {
+ ERROR("Unable to open %s.\n",
+ filename == NULL ? "stdout" : filename);
+ ret = EIO;
+ goto done;
+ }
+
+ do {
+ objs = list_user_overrides(tmp_ctx, dom, filter);
+ if (objs == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to get override objects\n");
+ ret = ENOMEM;
+ goto done;
+ }
+
+ for (i = 0; objs[i].orig_name != NULL; i++) {
+ /**
+ * Format: orig_name:name:uid:gid:gecos:home:shell:certificate
+ */
+ struct sss_colondb_write_field table[] = {
+ {SSS_COLONDB_STRING, {.str = objs[i].orig_name}},
+ {SSS_COLONDB_STRING, {.str = objs[i].name}},
+ {SSS_COLONDB_UINT32, {.uint32 = objs[i].uid}},
+ {SSS_COLONDB_UINT32, {.uint32 = objs[i].gid}},
+ {SSS_COLONDB_STRING, {.str = objs[i].gecos}},
+ {SSS_COLONDB_STRING, {.str = objs[i].home}},
+ {SSS_COLONDB_STRING, {.str = objs[i].shell}},
+ {SSS_COLONDB_STRING, {.str = objs[i].cert}},
+ {SSS_COLONDB_SENTINEL, {0}}
+ };
+
+ ret = sss_colondb_writeline(db, table);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to write line to db\n");
+ goto done;
+ }
+ }
+
+ /* All overrides are under the same subtree, so we don't want to
+ * descent into subdomains. */
+ dom = get_next_domain(dom, false);
+ } while (dom != NULL && iterate);
+
+ ret = EOK;
+
+done:
+ talloc_free(tmp_ctx);
+
+ return ret;
+}
+
+static errno_t group_export(const char *filename,
+ struct sss_domain_info *dom,
+ bool iterate,
+ const char *filter)
+{
+ TALLOC_CTX *tmp_ctx;
+ struct sss_colondb *db;
+ struct override_group *objs;
+ errno_t ret;
+ int i;
+
+ tmp_ctx = talloc_new(NULL);
+ if (tmp_ctx == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "talloc_new() failed\n");
+ return ENOMEM;
+ }
+
+
+ db = sss_colondb_open(tmp_ctx, SSS_COLONDB_WRITE, filename);
+ if (db == NULL) {
+ ERROR("Unable to open %s.\n",
+ filename == NULL ? "stdout" : filename);
+ ret = EIO;
+ goto done;
+ }
+
+ do {
+ objs = list_group_overrides(tmp_ctx, dom, filter);
+ if (objs == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to get override objects\n");
+ ret = ENOMEM;
+ goto done;
+ }
+
+ for (i = 0; objs[i].orig_name != NULL; i++) {
+ /**
+ * Format: orig_name:name:gid
+ */
+ struct sss_colondb_write_field table[] = {
+ {SSS_COLONDB_STRING, {.str = objs[i].orig_name}},
+ {SSS_COLONDB_STRING, {.str = objs[i].name}},
+ {SSS_COLONDB_UINT32, {.uint32 = objs[i].gid}},
+ {SSS_COLONDB_SENTINEL, {0}}
+ };
+
+ ret = sss_colondb_writeline(db, table);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to write line to db\n");
+ goto done;
+ }
+ }
+
+ /* All overrides are under the same subtree, so we don't want to
+ * descent into subdomains. */
+ dom = get_next_domain(dom, false);
+ } while (dom != NULL && iterate);
+
+ ret = EOK;
+
+done:
+ talloc_free(tmp_ctx);
+
+ return ret;
+}
+
+static int override_user_add(struct sss_cmdline *cmdline,
+ struct sss_tool_ctx *tool_ctx,
+ void *pvt)
+{
+ struct override_user user = {NULL};
+ errno_t ret;
+
+ ret = parse_cmdline_user_add(cmdline, tool_ctx, &user);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to parse command line.\n");
+ goto done;
+ }
+
+ ret = get_user_domain_msg(tool_ctx, &user);
+ if (ret != EOK) {
+ goto done;
+ }
+
+ ret = override_user(tool_ctx, &user);
+ if (ret != EOK) {
+ goto done;
+ }
+
+ ret = EOK;
+
+done:
+ free(discard_const(user.input_name));
+
+ return ret;
+}
+
+static int override_user_del(struct sss_cmdline *cmdline,
+ struct sss_tool_ctx *tool_ctx,
+ void *pvt)
+{
+ struct override_user user = {NULL};
+ errno_t ret;
+
+ ret = parse_cmdline_user_del(cmdline, tool_ctx, &user);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to parse command line.\n");
+ goto done;
+ }
+
+ ret = get_user_domain_msg(tool_ctx, &user);
+ if (ret != EOK) {
+ goto done;
+ }
+
+ ret = override_object_del(user.domain, SYSDB_MEMBER_USER, user.sysdb_name);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to delete override object.\n");
+ goto done;
+ }
+
+ ret = EOK;
+
+done:
+ free(discard_const(user.input_name));
+
+ return ret;
+}
+
+static int override_user_find(struct sss_cmdline *cmdline,
+ struct sss_tool_ctx *tool_ctx,
+ void *pvt)
+{
+ struct sss_domain_info *dom;
+ bool iterate;
+ errno_t ret;
+
+ ret = parse_cmdline_find(cmdline, tool_ctx, &dom);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to parse command line.\n");
+ return ret;
+ }
+
+ if (dom == NULL) {
+ dom = tool_ctx->domains;
+ iterate = true;
+ } else {
+ iterate = false;
+ }
+
+ ret = user_export(NULL, dom, iterate, NULL);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to export users\n");
+ return ret;
+ }
+
+ return EOK;
+}
+
+static int override_user_show(struct sss_cmdline *cmdline,
+ struct sss_tool_ctx *tool_ctx,
+ void *pvt)
+{
+ TALLOC_CTX *tmp_ctx;
+ struct override_user input = {NULL};
+ const char *dn;
+ char *anchor;
+ const char *filter;
+ errno_t ret;
+
+ tmp_ctx = talloc_new(NULL);
+ if (tmp_ctx == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "talloc_new() failed.\n");
+ return ENOMEM;
+ }
+
+ ret = parse_cmdline_user_show(cmdline, tool_ctx, &input);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to parse command line.\n");
+ goto done;
+ }
+
+ ret = get_user_domain_msg(tool_ctx, &input);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to get object domain\n");
+ goto done;
+ }
+
+ ret = get_object_dn(tmp_ctx, input.domain, SYSDB_MEMBER_USER,
+ input.sysdb_name, NULL, &dn);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to get object dn\n");
+ goto done;
+ }
+
+ anchor = build_anchor(tmp_ctx, dn);
+ if (anchor == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ ret = sss_filter_sanitize(tmp_ctx, anchor, &anchor);
+ if (ret != EOK) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ filter = talloc_asprintf(tmp_ctx, "(%s=%s)",
+ SYSDB_OVERRIDE_ANCHOR_UUID, anchor);
+ if (filter == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "talloc_asprintf() failed\n");
+ ret = ENOMEM;
+ goto done;
+ }
+
+ ret = user_export(NULL, input.domain, false, filter);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to export users\n");
+ goto done;
+ }
+
+ ret = EOK;
+
+done:
+ talloc_free(tmp_ctx);
+ free(discard_const(input.input_name));
+
+ return ret;
+}
+
+static int override_user_import(struct sss_cmdline *cmdline,
+ struct sss_tool_ctx *tool_ctx,
+ void *pvt)
+{
+ TALLOC_CTX *tmp_ctx;
+ struct sss_colondb *db;
+ const char *filename = NULL;
+ struct override_user obj = {0};
+ int linenum = 1;
+ errno_t ret;
+
+ tmp_ctx = talloc_new(NULL);
+ if (tmp_ctx == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "talloc_new() failed.\n");
+ return EXIT_FAILURE;
+ }
+
+ /**
+ * Format: orig_name:name:uid:gid:gecos:home:shell:certificate
+ */
+ struct sss_colondb_read_field table[] = {
+ {SSS_COLONDB_STRING, {.str = &obj.input_name}},
+ {SSS_COLONDB_STRING, {.str = &obj.name}},
+ {SSS_COLONDB_UINT32, {.uint32 = &obj.uid}},
+ {SSS_COLONDB_UINT32, {.uint32 = &obj.gid}},
+ {SSS_COLONDB_STRING, {.str = &obj.gecos}},
+ {SSS_COLONDB_STRING, {.str = &obj.home}},
+ {SSS_COLONDB_STRING, {.str = &obj.shell}},
+ {SSS_COLONDB_STRING, {.str = &obj.cert}},
+ {SSS_COLONDB_SENTINEL, {0}}
+ };
+
+ ret = parse_cmdline_import(cmdline, &filename);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to parse command line.\n");
+ goto done;
+ }
+
+ db = sss_colondb_open(tool_ctx, SSS_COLONDB_READ, filename);
+ if (db == NULL) {
+ ERROR("Unable to open %s.\n", filename);
+ ret = EIO;
+ goto done;
+ }
+
+ while ((ret = sss_colondb_readline(tmp_ctx, db, table)) == EOK) {
+ linenum++;
+
+ ret = sss_tool_parse_name(tool_ctx, tool_ctx, obj.input_name,
+ &obj.orig_name, &obj.domain);
+ if (ret != EOK) {
+ ERROR("Unable to parse name %s.\n", obj.input_name);
+ goto done;
+ }
+
+ ret = get_user_domain_msg(tool_ctx, &obj);
+ if (ret != EOK) {
+ goto done;
+ }
+
+ ret = override_user(tool_ctx, &obj);
+ if (ret != EOK) {
+ goto done;
+ }
+
+ talloc_free_children(tmp_ctx);
+ }
+
+ if (ret != EOF) {
+ ERROR("Invalid format on line %d. "
+ "Use --debug option for more information.\n", linenum);
+ goto done;
+ }
+
+ ret = EOK;
+
+done:
+ talloc_free(tmp_ctx);
+ free(discard_const(filename));
+
+ return ret;
+}
+
+static int override_user_export(struct sss_cmdline *cmdline,
+ struct sss_tool_ctx *tool_ctx,
+ void *pvt)
+{
+ const char *filename = NULL;
+ errno_t ret;
+
+ ret = parse_cmdline_export(cmdline, &filename);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to parse command line.\n");
+ goto done;
+ }
+
+ ret = user_export(filename, tool_ctx->domains, true, NULL);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to export users\n");
+ goto done;
+ }
+
+ ret = EOK;
+
+done:
+ free(discard_const(filename));
+
+ return ret;
+}
+
+static int override_group_add(struct sss_cmdline *cmdline,
+ struct sss_tool_ctx *tool_ctx,
+ void *pvt)
+{
+ struct override_group group = {NULL};
+ errno_t ret;
+
+ ret = parse_cmdline_group_add(cmdline, tool_ctx, &group);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to parse command line.\n");
+ goto done;
+ }
+
+ ret = get_group_domain_msg(tool_ctx, &group);
+ if (ret != EOK) {
+ goto done;
+ }
+
+ ret = override_group(tool_ctx, &group);
+ if (ret != EOK) {
+ goto done;
+ }
+
+ ret = EOK;
+
+done:
+ free(discard_const(group.input_name));
+
+ return ret;
+}
+
+static int override_group_del(struct sss_cmdline *cmdline,
+ struct sss_tool_ctx *tool_ctx,
+ void *pvt)
+{
+ struct override_group group = {NULL};
+ errno_t ret;
+
+ ret = parse_cmdline_group_del(cmdline, tool_ctx, &group);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to parse command line.\n");
+ goto done;
+ }
+
+ ret = get_group_domain_msg(tool_ctx, &group);
+ if (ret != EOK) {
+ goto done;
+ }
+
+ ret = override_object_del(group.domain, SYSDB_MEMBER_GROUP,
+ group.sysdb_name);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to delete override object.\n");
+ goto done;
+ }
+
+ ret = EOK;
+
+done:
+ free(discard_const(group.input_name));
+
+ return ret;
+}
+
+static int override_group_find(struct sss_cmdline *cmdline,
+ struct sss_tool_ctx *tool_ctx,
+ void *pvt)
+{
+ struct sss_domain_info *dom;
+ bool iterate;
+ errno_t ret;
+
+ ret = parse_cmdline_find(cmdline, tool_ctx, &dom);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to parse command line.\n");
+ return ret;
+ }
+
+ if (dom == NULL) {
+ dom = tool_ctx->domains;
+ iterate = true;
+ } else {
+ iterate = false;
+ }
+
+ ret = group_export(NULL, dom, iterate, NULL);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to export groups\n");
+ return ret;
+ }
+
+ return EOK;
+}
+
+static int override_group_show(struct sss_cmdline *cmdline,
+ struct sss_tool_ctx *tool_ctx,
+ void *pvt)
+{
+ TALLOC_CTX *tmp_ctx;
+ struct override_group input = {NULL};
+ const char *dn;
+ char *anchor;
+ const char *filter;
+ errno_t ret;
+
+ tmp_ctx = talloc_new(NULL);
+ if (tmp_ctx == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "talloc_new() failed.\n");
+ return ENOMEM;
+ }
+
+ ret = parse_cmdline_group_show(cmdline, tool_ctx, &input);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to parse command line.\n");
+ goto done;
+ }
+
+ ret = get_group_domain_msg(tool_ctx, &input);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to get object domain\n");
+ goto done;
+ }
+
+ ret = get_object_dn(tmp_ctx, input.domain, SYSDB_MEMBER_GROUP,
+ input.sysdb_name, NULL, &dn);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to get object dn\n");
+ goto done;
+ }
+
+ anchor = build_anchor(tmp_ctx, dn);
+ if (anchor == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ ret = sss_filter_sanitize(tmp_ctx, anchor, &anchor);
+ if (ret != EOK) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ filter = talloc_asprintf(tmp_ctx, "(%s=%s)",
+ SYSDB_OVERRIDE_ANCHOR_UUID, anchor);
+ if (filter == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "talloc_asprintf() failed\n");
+ ret = ENOMEM;
+ goto done;
+ }
+
+ ret = group_export(NULL, input.domain, false, filter);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to export groups\n");
+ goto done;
+ }
+
+ ret = EOK;
+
+done:
+ talloc_free(tmp_ctx);
+ free(discard_const(input.input_name));
+
+ return ret;
+}
+
+static int override_group_import(struct sss_cmdline *cmdline,
+ struct sss_tool_ctx *tool_ctx,
+ void *pvt)
+{
+ TALLOC_CTX *tmp_ctx;
+ struct sss_colondb *db;
+ const char *filename = NULL;
+ struct override_group obj = {0};
+ int linenum = 1;
+ errno_t ret;
+
+ tmp_ctx = talloc_new(NULL);
+ if (tmp_ctx == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "talloc_new() failed.\n");
+ return ENOMEM;
+ }
+
+ /**
+ * Format: orig_name:name:gid
+ */
+ struct sss_colondb_read_field table[] = {
+ {SSS_COLONDB_STRING, {.str = &obj.input_name}},
+ {SSS_COLONDB_STRING, {.str = &obj.name}},
+ {SSS_COLONDB_UINT32, {.uint32 = &obj.gid}},
+ {SSS_COLONDB_SENTINEL, {0}}
+ };
+
+ ret = parse_cmdline_import(cmdline, &filename);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to parse command line.\n");
+ goto done;
+ }
+
+ db = sss_colondb_open(tool_ctx, SSS_COLONDB_READ, filename);
+ if (db == NULL) {
+ ERROR("Unable to open %s.\n", filename);
+ ret = EIO;
+ goto done;
+ }
+
+ while ((ret = sss_colondb_readline(tmp_ctx, db, table)) == EOK) {
+ linenum++;
+
+ ret = sss_tool_parse_name(tool_ctx, tool_ctx, obj.input_name,
+ &obj.orig_name, &obj.domain);
+ if (ret != EOK) {
+ ERROR("Unable to parse name %s.\n", obj.input_name);
+ goto done;
+ }
+
+ ret = get_group_domain_msg(tool_ctx, &obj);
+ if (ret != EOK) {
+ goto done;
+ }
+
+ ret = override_group(tool_ctx, &obj);
+ if (ret != EOK) {
+ goto done;
+ }
+
+ talloc_free_children(tmp_ctx);
+ }
+
+ if (ret != EOF) {
+ ERROR("Invalid format on line %d. "
+ "Use --debug option for more information.\n", linenum);
+ goto done;
+ }
+
+ ret = EOK;
+
+done:
+ talloc_free(tmp_ctx);
+ free(discard_const(filename));
+
+ return ret;
+}
+
+static int override_group_export(struct sss_cmdline *cmdline,
+ struct sss_tool_ctx *tool_ctx,
+ void *pvt)
+{
+ const char *filename = NULL;
+ errno_t ret;
+
+ ret = parse_cmdline_export(cmdline, &filename);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to parse command line.\n");
+ goto done;
+ }
+
+ ret = group_export(filename, tool_ctx->domains, true, NULL);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to export groups\n");
+ goto done;
+ }
+
+ ret = EOK;
+
+done:
+ free(discard_const(filename));
+
+ return ret;
+}
+
+int main(int argc, const char **argv)
+{
+ struct sss_route_cmd commands[] = {
+ SSS_TOOL_COMMAND_NOMSG("user-add", 0, override_user_add),
+ SSS_TOOL_COMMAND_NOMSG("user-del", 0, override_user_del),
+ SSS_TOOL_COMMAND_NOMSG("user-find", 0, override_user_find),
+ SSS_TOOL_COMMAND_NOMSG("user-show", 0, override_user_show),
+ SSS_TOOL_COMMAND_NOMSG("user-import", 0, override_user_import),
+ SSS_TOOL_COMMAND_NOMSG("user-export", 0, override_user_export),
+ SSS_TOOL_COMMAND_NOMSG("group-add", 0, override_group_add),
+ SSS_TOOL_COMMAND_NOMSG("group-del", 0, override_group_del),
+ SSS_TOOL_COMMAND_NOMSG("group-find", 0, override_group_find),
+ SSS_TOOL_COMMAND_NOMSG("group-show", 0, override_group_show),
+ SSS_TOOL_COMMAND_NOMSG("group-import", 0, override_group_import),
+ SSS_TOOL_COMMAND_NOMSG("group-export", 0, override_group_export),
+ SSS_TOOL_LAST
+ };
+
+ return sss_tool_main(argc, argv, commands, NULL);
+}