From 5e14f8c1d93ad37425344d1b9a4c56d2bff3422f Mon Sep 17 00:00:00 2001 From: Pavel Březina Date: Fri, 24 Jul 2015 09:58:11 +0200 Subject: TOOLS: add sss_override for local overrides Resolves: https://fedorahosted.org/sssd/ticket/2584 --- Makefile.am | 16 +- contrib/sssd.spec.in | 2 + src/man/Makefile.am | 1 + src/man/po/po4a.cfg | 1 + src/man/sss_override.8.xml | 108 +++++++ src/tools/sss_override.c | 718 +++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 845 insertions(+), 1 deletion(-) create mode 100644 src/man/sss_override.8.xml create mode 100644 src/tools/sss_override.c diff --git a/Makefile.am b/Makefile.am index 1edecc483..912bfc664 100644 --- a/Makefile.am +++ b/Makefile.am @@ -117,7 +117,9 @@ sbin_PROGRAMS = \ sss_groupshow \ sss_cache \ sss_debuglevel \ - sss_seed + sss_override \ + sss_seed \ + $(NULL) sssdlibexec_PROGRAMS = \ sssd_nss \ @@ -1297,6 +1299,18 @@ sss_signal_LDADD = \ $(SSSD_INTERNAL_LTLIBS) \ $(NULL) +sss_override_SOURCES = \ + src/tools/sss_override.c \ + $(SSSD_TOOLS_OBJ) \ + $(NULL) +sss_override_LDADD = \ + $(TOOLS_LIBS) \ + $(SSSD_INTERNAL_LTLIBS) \ + $(NULL) +sss_override_CFLAGS = \ + $(AM_CFLAGS) \ + $(NULL) + if BUILD_SUDO sss_sudo_cli_SOURCES = \ src/sss_client/common.c \ diff --git a/contrib/sssd.spec.in b/contrib/sssd.spec.in index 15f7c582c..f050501ff 100644 --- a/contrib/sssd.spec.in +++ b/contrib/sssd.spec.in @@ -837,6 +837,7 @@ rm -rf $RPM_BUILD_ROOT %{_sbindir}/sss_groupmod %{_sbindir}/sss_groupshow %{_sbindir}/sss_obfuscate +%{_sbindir}/sss_override %{_sbindir}/sss_debuglevel %{_sbindir}/sss_seed %{_mandir}/man8/sss_groupadd.8* @@ -847,6 +848,7 @@ rm -rf $RPM_BUILD_ROOT %{_mandir}/man8/sss_userdel.8* %{_mandir}/man8/sss_usermod.8* %{_mandir}/man8/sss_obfuscate.8* +%{_mandir}/man8/sss_override.8* %{_mandir}/man8/sss_debuglevel.8* %{_mandir}/man8/sss_seed.8* diff --git a/src/man/Makefile.am b/src/man/Makefile.am index 1ef1da48c..70cadf595 100644 --- a/src/man/Makefile.am +++ b/src/man/Makefile.am @@ -51,6 +51,7 @@ man_MANS = \ sssd-krb5.5 sssd-simple.5 \ sssd_krb5_locator_plugin.8 sss_groupshow.8 \ pam_sss.8 sss_obfuscate.8 sss_cache.8 sss_debuglevel.8 sss_seed.8 \ + sss_override.8 $(NULL) if BUILD_SAMBA diff --git a/src/man/po/po4a.cfg b/src/man/po/po4a.cfg index 25d20c6f0..67e87ba70 100644 --- a/src/man/po/po4a.cfg +++ b/src/man/po/po4a.cfg @@ -11,6 +11,7 @@ [type:docbook] sssd-sudo.5.xml $lang:$(builddir)/$lang/sssd-sudo.5.xml [type:docbook] sssd.8.xml $lang:$(builddir)/$lang/sssd.8.xml [type:docbook] sss_obfuscate.8.xml $lang:$(builddir)/$lang/sss_obfuscate.8.xml +[type:docbook] sss_override.8.xml $lang:$(builddir)/$lang/sss_override.8.xml [type:docbook] sss_useradd.8.xml $lang:$(builddir)/$lang/sss_useradd.8.xml [type:docbook] sssd-krb5.5.xml $lang:$(builddir)/$lang/sssd-krb5.5.xml [type:docbook] sss_groupadd.8.xml $lang:$(builddir)/$lang/sss_groupadd.8.xml diff --git a/src/man/sss_override.8.xml b/src/man/sss_override.8.xml new file mode 100644 index 000000000..307cb5585 --- /dev/null +++ b/src/man/sss_override.8.xml @@ -0,0 +1,108 @@ + + + +SSSD Manual pages + + + + + sss_override + 8 + + + + sss_override + create local overrides of user and group attributes + + + + + sss_override + COMMAND + + options + + + + + + DESCRIPTION + + sss_override enables to create a client-side + view and allows to change selected values of specific user + and groups. This change takes effect only on local machine. + + + Overrides data are stored in SSSD cache. If the cache is deleted + all local overrides are lost. + + + + + AVAILABLE COMMANDS + + Argument NAME is the name of original object + in all commands. It is not possible to override + uid or gid to 0. + + + + + + NAME + NAME + UID + GID + HOME + SHELL + GECOS + + + + Override attributes of an user. + + + + + + + NAME + + + + Remove user overrides. + + + + + + + NAME + NAME + GID + + + + Override attributes of a group. + + + + + + + NAME + + + + Remove group overrides. + + + + + + + + + + diff --git a/src/tools/sss_override.c b/src/tools/sss_override.c new file mode 100644 index 000000000..5e901e2e3 --- /dev/null +++ b/src/tools/sss_override.c @@ -0,0 +1,718 @@ +/* + Authors: + Pavel Březina + + 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 . +*/ + +#include + +#include "util/util.h" +#include "db/sysdb.h" +#include "tools/common/sss_tools.h" + +#define LOCALVIEW SYSDB_LOCAL_VIEW_NAME + +struct override_user { + const char *input_name; + const char *orig_name; + struct sss_domain_info *domain; + + const char *name; + uid_t uid; + gid_t gid; + const char *home; + const char *shell; + const char *gecos; +}; + +struct override_group { + const char *input_name; + const char *orig_name; + struct sss_domain_info *domain; + + const char *name; + gid_t gid; +}; + +static int 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; + const char *orig_name; + struct sss_domain_info *domain; + int ret; + + require = options == NULL ? SSS_TOOL_OPT_OPTIONAL : SSS_TOOL_OPT_REQUIRED; + + ret = sss_tool_popt_ex(cmdline, options, require, + NULL, NULL, "NAME", _("Specify name of modified " + "object."), &input_name); + 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) { + fprintf(stderr, _("Unable to parse name.\n")); + return ret; + } + + *_input_name = input_name; + *_orig_name = orig_name; + *_domain = domain; + + return EXIT_SUCCESS; +} + +static int parse_cmdline_user_add(struct sss_cmdline *cmdline, + struct sss_tool_ctx *tool_ctx, + struct override_user *user) +{ + struct poptOption options[] = { + POPT_AUTOHELP + {"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 }, + POPT_TABLEEND + }; + + return parse_cmdline(cmdline, tool_ctx, options, &user->input_name, + &user->orig_name, &user->domain); +} + +static int 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 int parse_cmdline_group_add(struct sss_cmdline *cmdline, + struct sss_tool_ctx *tool_ctx, + struct override_group *group) +{ + struct poptOption options[] = { + POPT_AUTOHELP + {"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 int 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 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; +} + +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, + const char *name, + uid_t uid, + gid_t gid, + const char *home, + const char *shell, + const char *gecos) +{ + struct sysdb_attrs *attrs; + errno_t ret; + + attrs = sysdb_new_attrs(mem_ctx); + if (attrs == NULL) { + return NULL; + } + + if (name != NULL) { + ret = sysdb_attrs_add_string(attrs, SYSDB_NAME, name); + 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; + } + } + + 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->name, user->uid, user->gid, user->home, + user->shell, user->gecos); +} + +static struct sysdb_attrs *build_group_attrs(TALLOC_CTX *mem_ctx, + struct override_group *group) +{ + return build_attrs(mem_ctx, group->name, 0, group->gid, 0, NULL, NULL); +} + +static const char *get_object_dn_and_domain(TALLOC_CTX *mem_ctx, + enum sysdb_member_type type, + const char *name, + struct sss_domain_info *domain, + struct sss_domain_info *domains, + struct sss_domain_info **_new_domain) +{ + TALLOC_CTX *tmp_ctx; + struct sss_domain_info *dom; + struct ldb_result *res; + const char *dn; + const char *strtype; + bool check_next; + errno_t ret; + + tmp_ctx = talloc_new(NULL); + if (tmp_ctx == NULL) { + return NULL; + } + + /* Ensure that the object is in cache. */ + switch (type) { + case SYSDB_MEMBER_USER: + if (getpwnam(name) == NULL) { + ret = ENOENT; + goto done; + } + break; + case SYSDB_MEMBER_GROUP: + if (getgrnam(name) == 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 { + 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, name, &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, name, &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); + + dn = ldb_dn_get_linearized(res->msgs[0]->dn); + if (dn == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, "ldb_dn_get_linearized() failed.\n"); + ret = ENOMEM; + goto done; + } + + talloc_steal(mem_ctx, dn); + *_new_domain = dom; + + ret = EOK; + +done: + talloc_free(tmp_ctx); + + if (ret != EOK) { + return NULL; + } + + return dn; +} + +static const char * get_user_dn_and_domain(TALLOC_CTX *mem_ctx, + struct sss_domain_info *domains, + struct override_user *user) +{ + return get_object_dn_and_domain(mem_ctx, SYSDB_MEMBER_USER, + user->orig_name, user->domain, domains, + &user->domain); +} + +static const char * get_group_dn_and_domain(TALLOC_CTX *mem_ctx, + struct sss_domain_info *domains, + struct override_group *group) +{ + return get_object_dn_and_domain(mem_ctx, SYSDB_MEMBER_GROUP, + group->orig_name, group->domain, domains, + &group->domain); +} + +static errno_t override_object_add(struct sss_domain_info *domain, + enum sysdb_member_type type, + struct sysdb_attrs *attrs, + const char *obj_dn) +{ + TALLOC_CTX *tmp_ctx; + const char *anchor; + struct ldb_dn *ldb_dn; + errno_t ret; + + tmp_ctx = talloc_new(NULL); + if (tmp_ctx == NULL) { + return ENOMEM; + } + + ldb_dn = ldb_dn_new(tmp_ctx, sysdb_ctx_get_ldb(domain->sysdb), obj_dn); + if (ldb_dn == NULL) { + ret = ENOMEM; + goto done; + } + + anchor = build_anchor(tmp_ctx, obj_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", obj_dn); + + ret = sysdb_store_override(domain, LOCALVIEW, type, attrs, ldb_dn); + +done: + talloc_free(tmp_ctx); + return ret; +} + +static errno_t override_object_del(struct sss_domain_info *domain, + const char *obj_dn) +{ + TALLOC_CTX *tmp_ctx; + const char *anchor; + struct ldb_dn *override_dn; + struct ldb_message *msg; + 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; + } + + anchor = build_anchor(tmp_ctx, obj_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", obj_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 = ldb_dn_new(msg, ldb, obj_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 = sysdb_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 = sysdb_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 int override_user_add(struct sss_cmdline *cmdline, + struct sss_tool_ctx *tool_ctx, + void *pvt) +{ + struct override_user user = {NULL}; + struct sysdb_attrs *attrs; + const char *dn; + int ret; + + ret = parse_cmdline_user_add(cmdline, tool_ctx, &user); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, "Unable to parse command line.\n"); + return EXIT_FAILURE; + } + + dn = get_user_dn_and_domain(tool_ctx, tool_ctx->domains, &user); + if (dn == NULL) { + fprintf(stderr, _("Unable to find user %s@%s.\n"), + user.orig_name, + user.domain == NULL ? "[unknown]" : user.domain->name); + return EXIT_FAILURE; + } + + ret = prepare_view(user.domain); + if (ret == EEXIST) { + fprintf(stderr, _("Other than LOCAL view already exist in " + "domain %s.\n"), user.domain->name); + return EXIT_FAILURE; + } else if (ret != EOK) { + fprintf(stderr, _("Unable to prepare view [%d]: %s.\n"), + ret, sss_strerror(ret)); + return EXIT_FAILURE; + } + + attrs = build_user_attrs(tool_ctx, &user); + if (attrs == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, "Unable to build sysdb attrs.\n"); + return EXIT_FAILURE; + } + + ret = override_object_add(user.domain, SYSDB_MEMBER_USER, attrs, dn); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, "Unable to add override object.\n"); + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +} + +static int override_user_del(struct sss_cmdline *cmdline, + struct sss_tool_ctx *tool_ctx, + void *pvt) +{ + struct override_user user = {NULL}; + const char *dn; + int ret; + + ret = parse_cmdline_user_del(cmdline, tool_ctx, &user); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, "Unable to parse command line.\n"); + return EXIT_FAILURE; + } + + dn = get_user_dn_and_domain(tool_ctx, tool_ctx->domains, &user); + if (dn == NULL) { + fprintf(stderr, _("Unable to find user %s@%s.\n"), + user.orig_name, user.domain->name); + return EXIT_FAILURE; + } + + ret = override_object_del(user.domain, dn); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, "Unable to add override object.\n"); + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +} + +static int override_group_add(struct sss_cmdline *cmdline, + struct sss_tool_ctx *tool_ctx, + void *pvt) +{ + struct override_group group = {NULL}; + struct sysdb_attrs *attrs; + const char *dn; + int ret; + + ret = parse_cmdline_group_add(cmdline, tool_ctx, &group); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, "Unable to parse command line.\n"); + return EXIT_FAILURE; + } + + dn = get_group_dn_and_domain(tool_ctx, tool_ctx->domains, &group); + if (dn == NULL) { + fprintf(stderr, _("Unable to find group %s@%s.\n"), + group.orig_name, group.domain->name); + return EXIT_FAILURE; + } + + ret = prepare_view(group.domain); + if (ret == EEXIST) { + fprintf(stderr, _("Other than LOCAL view already exist in " + "domain %s.\n"), group.domain->name); + return EXIT_FAILURE; + } else if (ret != EOK) { + fprintf(stderr, _("Unable to prepare view [%d]: %s.\n"), + ret, sss_strerror(ret)); + return EXIT_FAILURE; + } + + attrs = build_group_attrs(tool_ctx, &group); + if (attrs == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, "Unable to build sysdb attrs.\n"); + return EXIT_FAILURE; + } + + ret = override_object_add(group.domain, SYSDB_MEMBER_GROUP, attrs, dn); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, "Unable to add override object.\n"); + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +} + +static int override_group_del(struct sss_cmdline *cmdline, + struct sss_tool_ctx *tool_ctx, + void *pvt) +{ + struct override_group group = {NULL}; + const char *dn; + int ret; + + ret = parse_cmdline_group_del(cmdline, tool_ctx, &group); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, "Unable to parse command line.\n"); + return EXIT_FAILURE; + } + + dn = get_group_dn_and_domain(tool_ctx, tool_ctx->domains, &group); + if (dn == NULL) { + fprintf(stderr, _("Unable to find group %s@%s.\n"), + group.orig_name, group.domain->name); + return EXIT_FAILURE; + } + + ret = override_object_del(group.domain, dn); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, "Unable to add override object.\n"); + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +} + +int main(int argc, const char **argv) +{ + struct sss_route_cmd commands[] = { + {"user-add", override_user_add}, + {"user-del", override_user_del}, + {"group-add", override_group_add}, + {"group-del", override_group_del}, + {NULL, NULL} + }; + + return sss_tool_main(argc, argv, commands, NULL); +} -- cgit