From c1a1b0464b5fad4daa9868b846182ad391f716a2 Mon Sep 17 00:00:00 2001 From: Jakub Hrozek Date: Thu, 23 Apr 2009 22:07:05 +0200 Subject: Invoke shadow-utils in sss_ tools Make shadow-utils base path configurable Use default values for params, allow configuring them --- server/Makefile.in | 4 +- server/conf_macros.m4 | 13 +++++ server/configure.ac | 1 + server/tools/sss_groupadd.c | 73 ++++++++++++++++++++---- server/tools/sss_groupdel.c | 70 ++++++++++++++++++++--- server/tools/sss_groupmod.c | 96 +++++++++++++++++++++++++++++--- server/tools/sss_useradd.c | 117 +++++++++++++++++++++++++++++++++++---- server/tools/sss_userdel.c | 69 ++++++++++++++++++++--- server/tools/sss_usermod.c | 132 ++++++++++++++++++++++++++++++++++++++++++++ server/tools/tools_util.c | 88 +++++++++++++++++++++++++++++ server/tools/tools_util.h | 28 ++++++++++ 11 files changed, 643 insertions(+), 48 deletions(-) (limited to 'server') diff --git a/server/Makefile.in b/server/Makefile.in index 69f74a368..ce66c2aa8 100644 --- a/server/Makefile.in +++ b/server/Makefile.in @@ -28,6 +28,7 @@ srvdir = @srcdir@ SSSD_PIPE_PATH = @pipepath@ SSSD_DB_PATH = @dbpath@ SSSD_PID_PATH = @pidpath@ +SHADOW_UTILS_PATH = @shadow_utils_path@ TALLOC_LIBS = @TALLOC_LIBS@ TALLOC_CFLAGS = @TALLOC_CFLAGS@ @@ -87,7 +88,8 @@ CFLAGS := -I$(srcdir)/include -Iinclude -I$(srcdir) -I$(srcdir)/.. \ $(LDB_CFLAGS) $(DBUS_CFLAGS) $(CHECK_CFLAGS) $(PCRE_CFLAGS) \ $(COLLECTION_CFLAGS) $(INI_CFG_CFLAGS)\ -DLIBDIR=\"$(libdir)\" -DVARDIR=\"$(localstatedir)\" -DSHLIBEXT=\"$(SHLIBEXT)\" -DSSSD_LIBEXEC_PATH=\"$(SSSD_LIBEXEC_PATH)\" \ - -DSSSD_INTROSPECT_PATH=\"$(SSSD_INTROSPECT_PATH)\" -DSSSD_CONF_DIR=\"$(SSSD_CONF_DIR)\" -DUSE_MMAP=1 $(CFLAGS) + -DSHADOW_UTILS_PATH=\"$(SHADOW_UTILS_PATH)\" -DSSSD_INTROSPECT_PATH=\"$(SSSD_INTROSPECT_PATH)\" -DSSSD_CONF_DIR=\"$(SSSD_CONF_DIR)\" \ + -DUSE_MMAP=1 $(CFLAGS) MDLD = @MDLD@ MDLD_FLAGS = @MDLD_FLAGS@ diff --git a/server/conf_macros.m4 b/server/conf_macros.m4 index f6821e070..27006e6dd 100644 --- a/server/conf_macros.m4 +++ b/server/conf_macros.m4 @@ -130,3 +130,16 @@ AC_DEFUN(WITH_INIT_DIR, ]) +AC_DEFUN(WITH_SHADOW_UTILS_PATH, + [ AC_ARG_WITH([shadow-utils-path], + [AC_HELP_STRING([--with-shadow-utils-path=PATH], + [Where to look for shadow-utils binaries [/usr/sbin]] + ) + ] + ) + shadow_utils_path="${sbindir}" + if test x"$with_shadow_utils_path" != x; then + shadow_utils_path=$with_shadow_utils_path + fi + AC_SUBST(shadow_utils_path) + ]) diff --git a/server/configure.ac b/server/configure.ac index be6f67839..79eb7305c 100644 --- a/server/configure.ac +++ b/server/configure.ac @@ -39,6 +39,7 @@ WITH_INFOPIPE WITH_POLICYKIT WITH_TESTS WITH_INIT_DIR +WITH_SHADOW_UTILS_PATH m4_include(pkg.m4) m4_include(libpopt.m4) diff --git a/server/tools/sss_groupadd.c b/server/tools/sss_groupadd.c index 6dde7ae83..09bc89d6f 100644 --- a/server/tools/sss_groupadd.c +++ b/server/tools/sss_groupadd.c @@ -25,11 +25,24 @@ #include #include #include +#include #include "util/util.h" #include "db/sysdb.h" #include "tools/tools_util.h" +#ifndef GROUPADD +#define GROUPADD SHADOW_UTILS_PATH"/groupadd " +#endif + +#ifndef GROUPADD_GID +#define GROUPADD_GID "-g %u " +#endif + +#ifndef GROUPADD_GROUPNAME +#define GROUPADD_GROUPNAME "%s " +#endif + struct group_add_ctx { struct sysdb_req *sysreq; @@ -75,6 +88,34 @@ static void add_group(struct sysdb_req *req, void *pvt) add_group_done(group_ctx, ret, NULL); } +static int groupadd_legacy(struct group_add_ctx *ctx) +{ + int ret = EOK; + char *command = NULL; + + command = talloc_asprintf(ctx, "%s ", GROUPADD); + if (command == NULL) { + return ENOMEM; + } + + APPEND_PARAM(command, GROUPADD_GID, ctx->gid); + APPEND_STRING(command, ctx->groupname); + + ret = system(command); + if (ret) { + if (ret == -1) { + DEBUG(0, ("system(3) failed\n")); + } else { + DEBUG(0,("Could not exec '%s', return code: %d\n", command, WEXITSTATUS(ret))); + } + talloc_free(command); + return EFAULT; + } + + talloc_free(command); + return ret; +} + int main(int argc, const char **argv) { gid_t pc_gid = 0; @@ -91,8 +132,6 @@ int main(int argc, const char **argv) debug_prg_name = argv[0]; - - /* arguments processed, go on to actual work */ ret = setup_db(&ctx); if(ret != EOK) { DEBUG(0, ("Could not set up database\n")); @@ -127,16 +166,28 @@ int main(int argc, const char **argv) group_ctx->gid = pc_gid; /* arguments processed, go on to actual work */ - - for (dom = ctx->domains; dom; dom = dom->next) { - if (strcasecmp(dom->name, "LOCAL") == 0) break; - } - if (dom == NULL) { - DEBUG(0, ("Could not get domain info\n")); - ret = EXIT_FAILURE; - goto fini; + ret = find_domain_for_id(ctx, group_ctx->gid, &dom); + switch (ret) { + case ID_IN_LOCAL: + group_ctx->domain = dom; + break; + + case ID_IN_LEGACY_LOCAL: + group_ctx->domain = dom; + case ID_OUTSIDE: + ret = groupadd_legacy(group_ctx); + goto fini; + + case ID_IN_OTHER: + DEBUG(0, ("Cannot add group to domain %s\n", dom->name)); + ret = EXIT_FAILURE; + goto fini; + + default: + DEBUG(0, ("Unknown return code from find_domain_for_id")); + ret = EXIT_FAILURE; + goto fini; } - group_ctx->domain = dom; /* add_group */ ret = sysdb_transaction(ctx, ctx->sysdb, add_group, group_ctx); diff --git a/server/tools/sss_groupdel.c b/server/tools/sss_groupdel.c index 8e85003c9..5d405b64e 100644 --- a/server/tools/sss_groupdel.c +++ b/server/tools/sss_groupdel.c @@ -23,16 +23,28 @@ #include #include #include +#include #include +#include #include "db/sysdb.h" #include "util/util.h" #include "tools/tools_util.h" +#ifndef GROUPDEL +#define GROUPDEL SHADOW_UTILS_PATH"/groupdel " +#endif + +#ifndef GROUPDEL_GROUPNAME +#define GROUPDEL_GROUPNAME "%s " +#endif + + struct group_del_ctx { struct sysdb_req *sysreq; sysdb_callback_t next_fn; + gid_t gid; const char *groupname; struct ldb_dn *group_dn; @@ -74,12 +86,36 @@ static void group_del(struct sysdb_req *req, void *pvt) groupdel_done(group_ctx, ret, NULL); } +static int groupdel_legacy(struct group_del_ctx *ctx) +{ + int ret = EOK; + char *command = NULL; + + APPEND_STRING(command, GROUPDEL); + APPEND_PARAM(command, GROUPDEL_GROUPNAME, ctx->groupname); + + ret = system(command); + if (ret) { + if (ret == -1) { + DEBUG(0, ("system(3) failed\n")); + } else { + DEBUG(0,("Could not exec '%s', return code: %d\n", command, WEXITSTATUS(ret))); + } + talloc_free(command); + return EFAULT; + } + + talloc_free(command); + return ret; +} + int main(int argc, const char **argv) { int ret = EXIT_SUCCESS; struct group_del_ctx *group_ctx = NULL; struct tools_ctx *ctx = NULL; struct sss_domain_info *dom; + struct group *grp_info; poptContext pc = NULL; struct poptOption long_options[] = { @@ -120,17 +156,33 @@ int main(int argc, const char **argv) } /* arguments processed, go on to actual work */ - - for (dom = ctx->domains; dom; dom = dom->next) { - if (strcasecmp(dom->name, "LOCAL") == 0) break; - } - if (dom == NULL) { - DEBUG(0, ("Could not get domain info\n")); - ret = EXIT_FAILURE; - goto fini; + grp_info = getgrnam(group_ctx->groupname); + if (grp_info) { + group_ctx->gid = grp_info->gr_gid; } - group_ctx->domain = dom; + ret = find_domain_for_id(ctx, group_ctx->gid, &dom); + switch (ret) { + case ID_IN_LOCAL: + group_ctx->domain = dom; + break; + + case ID_IN_LEGACY_LOCAL: + group_ctx->domain = dom; + case ID_OUTSIDE: + ret = groupdel_legacy(group_ctx); + break; /* Also delete possible cached entries in sysdb */ + + case ID_IN_OTHER: + DEBUG(0, ("Cannot delete group from domain %s\n", dom->name)); + ret = EXIT_FAILURE; + goto fini; + + default: + DEBUG(0, ("Unknown return code from find_domain_for_id")); + ret = EXIT_FAILURE; + goto fini; + } group_ctx->group_dn = sysdb_group_dn(ctx->sysdb, ctx, group_ctx->domain->name, diff --git a/server/tools/sss_groupmod.c b/server/tools/sss_groupmod.c index 922555f0b..5665c25e3 100644 --- a/server/tools/sss_groupmod.c +++ b/server/tools/sss_groupmod.c @@ -24,12 +24,26 @@ #include #include #include +#include #include +#include #include "util/util.h" #include "db/sysdb.h" #include "tools/tools_util.h" +#ifndef GROUPMOD +#define GROUPMOD SHADOW_UTILS_PATH"/groupmod " +#endif + +#ifndef GROUPMOD_GID +#define GROUPMOD_GID "-g %u " +#endif + +#ifndef GROUPMOD_GROUPNAME +#define GROUPMOD_GROUPNAME "%s " +#endif + struct group_mod_ctx { struct sysdb_req *sysreq; struct sss_domain_info *domain; @@ -175,6 +189,48 @@ static void add_to_groups(void *pvt, int error, struct ldb_result *ignore) group_ctx->cur++; } +static int groupmod_legacy(struct tools_ctx *tools_ctx, struct group_mod_ctx *ctx, int old_domain) +{ + int ret = EOK; + char *command = NULL; + struct sss_domain_info *dom = NULL; + + APPEND_STRING(command, GROUPMOD); + + if (ctx->addgroups || ctx->rmgroups) { + DEBUG(0, ("Groups nesting is not supported in this domain\n")); + talloc_free(command); + return EINVAL; + } + + if (ctx->gid) { + ret = find_domain_for_id(tools_ctx, ctx->gid, &dom); + if (ret == old_domain) { + APPEND_PARAM(command, GROUPMOD_GID, ctx->gid); + } else { + DEBUG(0, ("Changing gid only allowed inside the same domain\n")); + talloc_free(command); + return EINVAL; + } + } + + APPEND_PARAM(command, GROUPMOD_GROUPNAME, ctx->groupname); + + ret = system(command); + if (ret) { + if (ret == -1) { + DEBUG(0, ("system(3) failed\n")); + } else { + DEBUG(0,("Could not exec '%s', return code: %d\n", command, WEXITSTATUS(ret))); + } + talloc_free(command); + return EFAULT; + } + + talloc_free(command); + return ret; +} + int main(int argc, const char **argv) { gid_t pc_gid = 0; @@ -191,6 +247,8 @@ int main(int argc, const char **argv) struct tools_ctx *ctx = NULL; char *groups; int ret; + struct group *grp_info; + gid_t old_gid = 0; debug_prg_name = argv[0]; @@ -247,16 +305,38 @@ int main(int argc, const char **argv) group_ctx->gid = pc_gid; /* arguments processed, go on to actual work */ - - for (dom = ctx->domains; dom; dom = dom->next) { - if (strcasecmp(dom->name, "LOCAL") == 0) break; + grp_info = getgrnam(group_ctx->groupname); + if (grp_info) { + old_gid = grp_info->gr_gid; } - if (dom == NULL) { - DEBUG(0, ("Could not get domain info\n")); - ret = EXIT_FAILURE; - goto fini; + + ret = find_domain_for_id(ctx, old_gid, &dom); + switch (ret) { + case ID_IN_LOCAL: + group_ctx->domain = dom; + break; + + case ID_OUTSIDE: + DEBUG(5, ("Group ID outside range\n")); + ret = groupmod_legacy(ctx, group_ctx, ret); + goto fini; + + case ID_IN_LEGACY_LOCAL: + DEBUG(5, ("group ID in legacy domain\n")); + group_ctx->domain = dom; + ret = groupmod_legacy(ctx, group_ctx, ret); + goto fini; + + case ID_IN_OTHER: + DEBUG(0, ("Cannot modify group from domain %s\n", dom->name)); + ret = EXIT_FAILURE; + goto fini; + + default: + DEBUG(0, ("Unknown return code from find_domain_for_id")); + ret = EXIT_FAILURE; + goto fini; } - group_ctx->domain = dom; ret = sysdb_transaction(ctx, ctx->sysdb, mod_group, group_ctx); if (ret != EOK) { diff --git a/server/tools/sss_useradd.c b/server/tools/sss_useradd.c index d3b930d1a..e0c6feac2 100644 --- a/server/tools/sss_useradd.c +++ b/server/tools/sss_useradd.c @@ -26,11 +26,54 @@ #include #include #include +#include #include "util/util.h" #include "db/sysdb.h" #include "tools/tools_util.h" +/* Define default command strings if not redefined by user */ +#ifndef USERADD +#define USERADD SHADOW_UTILS_PATH"/useradd " +#endif + +#ifndef USERADD_UID +#define USERADD_UID "-u %u " +#endif + +#ifndef USERADD_GID +#define USERADD_GID "-g %u " +#endif + +#ifndef USERADD_GECOS +#define USERADD_GECOS "-c %s " +#endif + +#ifndef USERADD_HOME +#define USERADD_HOME "-d %s " +#endif + +#ifndef USERADD_SHELL +#define USERADD_SHELL "-s %s " +#endif + +#ifndef USERADD_GROUPS +#define USERADD_GROUPS "-G %s " +#endif + +#ifndef USERADD_UID_MIN +#define USERADD_UID_MIN "-K UID_MIN=%d " +#endif + +#ifndef USERADD_UID_MAX +#define USERADD_UID_MAX "-K UID_MAX=%d " +#endif + +#ifndef USERADD_USERNAME +#define USERADD_USERNAME "%s " +#endif + + struct user_add_ctx { struct sysdb_req *sysreq; @@ -215,6 +258,46 @@ static void add_to_groups(void *pvt, int error, struct ldb_result *ignore) user_ctx->cur++; } +static int useradd_legacy(struct user_add_ctx *ctx, char *grouplist) +{ + int ret = EOK; + char *command = NULL; + + APPEND_STRING(command, USERADD); + + APPEND_PARAM(command, USERADD_SHELL, ctx->shell); + + APPEND_PARAM(command, USERADD_GECOS, ctx->gecos); + + APPEND_PARAM(command, USERADD_HOME, ctx->home); + + APPEND_PARAM(command, USERADD_UID, ctx->uid); + + APPEND_PARAM(command, USERADD_GID, ctx->gid); + + APPEND_PARAM(command, USERADD_UID_MIN, ctx->domain->id_min); + + APPEND_PARAM(command, USERADD_UID_MAX, ctx->domain->id_max); + + APPEND_PARAM(command, USERADD_GROUPS, grouplist); + + APPEND_PARAM(command, USERADD_USERNAME, ctx->username); + + ret = system(command); + if (ret) { + if (ret == -1) { + DEBUG(0, ("system(3) failed\n")); + } else { + DEBUG(0,("Could not exec '%s', return code: %d\n", command, WEXITSTATUS(ret))); + } + talloc_free(command); + return EFAULT; + } + + talloc_free(command); + return ret; +} + int main(int argc, const char **argv) { uid_t pc_uid = 0; @@ -233,10 +316,10 @@ int main(int argc, const char **argv) POPT_TABLEEND }; poptContext pc = NULL; - struct sss_domain_info *dom; + struct sss_domain_info *dom = NULL; struct user_add_ctx *user_ctx = NULL; struct tools_ctx *ctx = NULL; - char *groups; + char *groups = NULL; int ret; debug_prg_name = argv[0]; @@ -267,7 +350,6 @@ int main(int argc, const char **argv) } ret = parse_groups(ctx, groups, &user_ctx->groups); - free(groups); if (ret != EOK) { break; } @@ -332,16 +414,28 @@ int main(int argc, const char **argv) } /* arguments processed, go on to actual work */ + ret = find_domain_for_id(ctx, user_ctx->uid, &dom); + switch (ret) { + case ID_IN_LOCAL: + user_ctx->domain = dom; + break; + + case ID_IN_LEGACY_LOCAL: + user_ctx->domain = dom; + case ID_OUTSIDE: + ret = useradd_legacy(user_ctx, groups); + goto fini; - for (dom = ctx->domains; dom; dom = dom->next) { - if (strcasecmp(dom->name, "LOCAL") == 0) break; - } - if (dom == NULL) { - DEBUG(0, ("Could not get domain info\n")); - ret = EXIT_FAILURE; - goto fini; + case ID_IN_OTHER: + DEBUG(0, ("Cannot add user to domain %s\n", dom->name)); + ret = EXIT_FAILURE; + goto fini; + + default: + DEBUG(0, ("Unknown return code from find_domain_for_id")); + ret = EXIT_FAILURE; + goto fini; } - user_ctx->domain = dom; /* useradd */ ret = sysdb_transaction(ctx, ctx->sysdb, add_user, user_ctx); @@ -368,5 +462,6 @@ int main(int argc, const char **argv) fini: poptFreeContext(pc); talloc_free(ctx); + free(groups); exit(ret); } diff --git a/server/tools/sss_userdel.c b/server/tools/sss_userdel.c index 47188824c..642e02bae 100644 --- a/server/tools/sss_userdel.c +++ b/server/tools/sss_userdel.c @@ -23,15 +23,27 @@ #include #include #include +#include +#include +#include #include "db/sysdb.h" #include "util/util.h" #include "tools/tools_util.h" +#ifndef USERDEL +#define USERDEL SHADOW_UTILS_PATH"/userdel " +#endif + +#ifndef USERDEL_USERNAME +#define USERDEL_USERNAME "%s " +#endif + struct user_del_ctx { struct sysdb_req *sysreq; sysdb_callback_t next_fn; + uid_t uid; const char *username; struct ldb_dn *user_dn; @@ -73,12 +85,36 @@ static void user_del(struct sysdb_req *req, void *pvt) userdel_done(user_ctx, ret, NULL); } +static int userdel_legacy(struct user_del_ctx *ctx) +{ + int ret = EOK; + char *command = NULL; + + APPEND_STRING(command, USERDEL); + APPEND_PARAM(command, USERDEL_USERNAME, ctx->username); + + ret = system(command); + if (ret) { + if (ret == -1) { + DEBUG(0, ("system(3) failed\n")); + } else { + DEBUG(0,("Could not exec '%s', return code: %d\n", command, WEXITSTATUS(ret))); + } + talloc_free(command); + return EFAULT; + } + + talloc_free(command); + return ret; +} + int main(int argc, const char **argv) { int ret = EXIT_SUCCESS; struct user_del_ctx *user_ctx = NULL; struct tools_ctx *ctx = NULL; struct sss_domain_info *dom; + struct passwd *pwd_info; poptContext pc = NULL; struct poptOption long_options[] = { @@ -119,16 +155,33 @@ int main(int argc, const char **argv) } /* arguments processed, go on to actual work */ - - for (dom = ctx->domains; dom; dom = dom->next) { - if (strcasecmp(dom->name, "LOCAL") == 0) break; + pwd_info = getpwnam(user_ctx->username); + if (pwd_info) { + user_ctx->uid = pwd_info->pw_uid; } - if (dom == NULL) { - DEBUG(0, ("Could not get domain info\n")); - ret = EXIT_FAILURE; - goto fini; + + ret = find_domain_for_id(ctx, user_ctx->uid, &dom); + switch (ret) { + case ID_IN_LOCAL: + user_ctx->domain = dom; + break; + + case ID_IN_LEGACY_LOCAL: + user_ctx->domain = dom; + case ID_OUTSIDE: + ret = userdel_legacy(user_ctx); + break; /* Also delete possible cached entries in sysdb */ + + case ID_IN_OTHER: + DEBUG(0, ("Cannot delete user from domain %s\n", dom->name)); + ret = EXIT_FAILURE; + goto fini; + + default: + DEBUG(0, ("Unknown return code from find_domain_for_id")); + ret = EXIT_FAILURE; + goto fini; } - user_ctx->domain = dom; user_ctx->user_dn = sysdb_user_dn(ctx->sysdb, ctx, user_ctx->domain->name, diff --git a/server/tools/sss_usermod.c b/server/tools/sss_usermod.c index fd2456104..f71350e06 100644 --- a/server/tools/sss_usermod.c +++ b/server/tools/sss_usermod.c @@ -24,7 +24,9 @@ #include #include #include +#include #include +#include #include "util/util.h" #include "db/sysdb.h" @@ -41,6 +43,43 @@ } \ } while(0) +/* Define default command strings if not redefined by user */ +#ifndef USERMOD +#define USERMOD SHADOW_UTILS_PATH"/usermod " +#endif + +#ifndef USERMOD_UID +#define USERMOD_UID "-u %u " +#endif + +#ifndef USERMOD_GID +#define USERMOD_GID "-g %u " +#endif + +#ifndef USERMOD_GECOS +#define USERMOD_GECOS "-c %s " +#endif + +#ifndef USERMOD_HOME +#define USERMOD_HOME "-d %s " +#endif + +#ifndef USERMOD_SHELL +#define USERMOD_SHELL "-s %s " +#endif + +#ifndef USERMOD_LOCK +#define USERMOD_LOCK "--lock " +#endif + +#ifndef USERMOD_UNLOCK +#define USERMOD_UNLOCK "--unlock " +#endif + +#ifndef USERMOD_USERNAME +#define USERMOD_USERNAME "%s" +#endif + struct user_mod_ctx { struct sysdb_req *sysreq; @@ -188,6 +227,68 @@ static void add_to_groups(void *pvt, int error, struct ldb_result *ignore) user_ctx->cur++; } +static int usermod_legacy(struct tools_ctx *tools_ctx, struct user_mod_ctx *ctx, + uid_t uid, gid_t gid, + const char *gecos, const char *home, + const char *shell, int lock, int old_domain) +{ + int ret = EOK; + char *command = NULL; + struct sss_domain_info *dom = NULL; + + APPEND_STRING(command, USERMOD); + + if (uid) { + ret = find_domain_for_id(tools_ctx, uid, &dom); + if (ret == old_domain) { + APPEND_PARAM(command, USERMOD_UID, uid); + } else { + DEBUG(0, ("Changing uid only allowed inside the same domain\n")); + talloc_free(command); + return EINVAL; + } + } + + if (gid) { + ret = find_domain_for_id(tools_ctx, gid, &dom); + if (ret == old_domain) { + APPEND_PARAM(command, USERMOD_GID, gid); + } else { + DEBUG(0, ("Changing gid only allowed inside the same domain\n")); + talloc_free(command); + return EINVAL; + } + } + + APPEND_PARAM(command, USERMOD_GECOS, gecos); + APPEND_PARAM(command, USERMOD_HOME, home); + APPEND_PARAM(command, USERMOD_SHELL, shell); + + if (lock == DO_LOCK) { + APPEND_STRING(command, USERMOD_LOCK); + } + + if (lock == DO_UNLOCK) { + APPEND_STRING(command, USERMOD_UNLOCK); + } + + APPEND_PARAM(command, USERMOD_USERNAME, ctx->username); + + ret = system(command); + if (ret) { + if (ret == -1) { + DEBUG(0, ("system(3) failed\n")); + } else { + DEBUG(0,("Could not exec '%s', return code: %d\n", command, WEXITSTATUS(ret))); + } + talloc_free(command); + return EFAULT; + } + + talloc_free(command); + return ret; +} + int main(int argc, const char **argv) { int pc_lock; @@ -215,6 +316,8 @@ int main(int argc, const char **argv) struct tools_ctx *ctx = NULL; char *groups; int ret; + struct passwd *pwd_info; + uid_t old_uid = 0; debug_prg_name = argv[0]; @@ -274,6 +377,35 @@ int main(int argc, const char **argv) goto fini; } + pwd_info = getpwnam(user_ctx->username); + if (pwd_info) { + old_uid = pwd_info->pw_uid; + } + + ret = find_domain_for_id(ctx, old_uid, &dom); + switch (ret) { + case ID_IN_LOCAL: + user_ctx->domain = dom; + break; + + case ID_IN_LEGACY_LOCAL: + user_ctx->domain = dom; + case ID_OUTSIDE: + ret = usermod_legacy(ctx, user_ctx, pc_uid, pc_gid, pc_gecos, + pc_home, pc_shell, pc_lock, ret); + goto fini; + + case ID_IN_OTHER: + DEBUG(0, ("Cannot delete user from domain %s\n", dom->name)); + ret = EXIT_FAILURE; + goto fini; + + default: + DEBUG(0, ("Unknown return code from find_domain_for_id")); + ret = EXIT_FAILURE; + goto fini; + } + /* add parameters to changeset */ /* FIXME - might want to do this via attr:pc_var mapping in a loop */ diff --git a/server/tools/tools_util.c b/server/tools/tools_util.c index a3669001f..72ab16644 100644 --- a/server/tools/tools_util.c +++ b/server/tools/tools_util.c @@ -28,6 +28,94 @@ #include "db/sysdb.h" #include "tools/tools_util.h" +/* + * Returns: + * 0 = yes, local domain proxying to files + * -1 = no, other type of domain + * > 0 = error code + */ +static int is_domain_local_legacy(struct tools_ctx *ctx, struct sss_domain_info *dom) +{ + char *libname = NULL; + char *conf_path = NULL; + int ret = -1; + + /* Is there a better way to find out? Having LEGACYLOCAL as reserved would help */ + conf_path = talloc_asprintf(ctx, "config/domains/%s", dom->name); + if (conf_path == NULL ) { + return ENOMEM; + } + + ret = confdb_get_string(ctx->confdb, ctx, conf_path, + "libName", NULL, &libname); + if (ret != EOK) { + talloc_free(conf_path); + return ret; + } + if (libname == NULL) { + talloc_free(conf_path); + return -1; + } + + if (strcasecmp(libname, "files") == 0) { + talloc_free(conf_path); + talloc_free(libname); + return EOK; + } + + talloc_free(conf_path); + talloc_free(libname); + return -1; +} + +enum id_domain find_domain_for_id(struct tools_ctx *ctx, + uint32_t id, + struct sss_domain_info **dom_ret) +{ + struct sss_domain_info *dom = NULL; + + if (id) { + /* ID specified, find which domain it's in */ + for (dom = ctx->domains; dom; dom = dom->next) { + if (id < dom->id_min || id > dom->id_max) { + continue; + } else { + if (strcasecmp(dom->name, "LOCAL") == 0) { + *dom_ret = dom; + return ID_IN_LOCAL; + } else if (is_domain_local_legacy(ctx, dom) == 0) { + *dom_ret = dom; + return ID_IN_LEGACY_LOCAL; + } else { + *dom_ret = dom; + return ID_IN_OTHER; + } + } + } + if (dom == NULL) { + *dom_ret = NULL; + return ID_OUTSIDE; + } + } else { + /* No ID specified, find LOCAL */ + for (dom = ctx->domains; dom; dom = dom->next) { + if (strcasecmp(dom->name, "LOCAL") == 0) { + *dom_ret = dom; + return ID_IN_LOCAL; + } + } + if (dom == NULL) { + DEBUG(0, ("Could not get LOCAL domain info\n")); + *dom_ret = dom; + return ID_ERROR; + } + } + + /* We should never end up here */ + *dom_ret = NULL; + return ID_ERROR; +} + int setup_db(struct tools_ctx **tools_ctx) { TALLOC_CTX *tmp_ctx; diff --git a/server/tools/tools_util.h b/server/tools/tools_util.h index ef55dede0..e055fe23b 100644 --- a/server/tools/tools_util.h +++ b/server/tools/tools_util.h @@ -4,6 +4,30 @@ #define UID_NOT_SET 0 #define GID_NOT_SET 0 +#define APPEND_PARAM(str, param, val) do { \ + if (val) { \ + str = talloc_asprintf_append(str, param, val); \ + if (str == NULL) { \ + return ENOMEM; \ + } \ + } \ +} while(0) + +#define APPEND_STRING(str, val) do { \ + str = talloc_asprintf_append(str, "%s ", val); \ + if (str == NULL) { \ + return ENOMEM; \ + } \ +} while(0) + +enum id_domain { + ID_IN_LOCAL = 0, + ID_IN_LEGACY_LOCAL, + ID_IN_OTHER, + ID_OUTSIDE, + ID_ERROR +}; + struct tools_ctx { struct tevent_context *ev; struct confdb_ctx *confdb; @@ -18,4 +42,8 @@ void usage(poptContext pc, const char *error); int parse_groups(TALLOC_CTX *mem_ctx, const char *optstr, char ***_out); +enum id_domain find_domain_for_id(struct tools_ctx *ctx, + uint32_t id, + struct sss_domain_info **dom_ret); + #endif /* __TOOLS_UTIL_H__ */ -- cgit