summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJakub Hrozek <jhrozek@redhat.com>2009-04-23 22:07:05 +0200
committerSimo Sorce <ssorce@redhat.com>2009-04-28 11:57:15 -0400
commitc1a1b0464b5fad4daa9868b846182ad391f716a2 (patch)
treeb739f02ccea1b92d16a774d8f6270388fc1094d5
parent6207b76613168e6aa386b7b71b492b66b14fff57 (diff)
downloadsssd-c1a1b0464b5fad4daa9868b846182ad391f716a2.tar.gz
sssd-c1a1b0464b5fad4daa9868b846182ad391f716a2.tar.bz2
sssd-c1a1b0464b5fad4daa9868b846182ad391f716a2.zip
Invoke shadow-utils in sss_ tools
Make shadow-utils base path configurable Use default values for params, allow configuring them
-rw-r--r--server/Makefile.in4
-rw-r--r--server/conf_macros.m413
-rw-r--r--server/configure.ac1
-rw-r--r--server/tools/sss_groupadd.c73
-rw-r--r--server/tools/sss_groupdel.c70
-rw-r--r--server/tools/sss_groupmod.c96
-rw-r--r--server/tools/sss_useradd.c117
-rw-r--r--server/tools/sss_userdel.c69
-rw-r--r--server/tools/sss_usermod.c132
-rw-r--r--server/tools/tools_util.c88
-rw-r--r--server/tools/tools_util.h28
11 files changed, 643 insertions, 48 deletions
diff --git a/server/Makefile.in b/server/Makefile.in
index 69f74a36..ce66c2aa 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 f6821e07..27006e6d 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 be6f6783..79eb7305 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 6dde7ae8..09bc89d6 100644
--- a/server/tools/sss_groupadd.c
+++ b/server/tools/sss_groupadd.c
@@ -25,11 +25,24 @@
#include <popt.h>
#include <errno.h>
#include <sys/types.h>
+#include <sys/wait.h>
#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 8e85003c..5d405b64 100644
--- a/server/tools/sss_groupdel.c
+++ b/server/tools/sss_groupdel.c
@@ -23,16 +23,28 @@
#include <stdlib.h>
#include <talloc.h>
#include <popt.h>
+#include <grp.h>
#include <sys/types.h>
+#include <sys/wait.h>
#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 922555f0..5665c25e 100644
--- a/server/tools/sss_groupmod.c
+++ b/server/tools/sss_groupmod.c
@@ -24,12 +24,26 @@
#include <talloc.h>
#include <popt.h>
#include <errno.h>
+#include <grp.h>
#include <sys/types.h>
+#include <sys/wait.h>
#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 d3b930d1..e0c6feac 100644
--- a/server/tools/sss_useradd.c
+++ b/server/tools/sss_useradd.c
@@ -26,11 +26,54 @@
#include <popt.h>
#include <errno.h>
#include <sys/types.h>
+#include <sys/wait.h>
#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 47188824..642e02ba 100644
--- a/server/tools/sss_userdel.c
+++ b/server/tools/sss_userdel.c
@@ -23,15 +23,27 @@
#include <stdlib.h>
#include <talloc.h>
#include <popt.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <pwd.h>
#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 fd245610..f71350e0 100644
--- a/server/tools/sss_usermod.c
+++ b/server/tools/sss_usermod.c
@@ -24,7 +24,9 @@
#include <talloc.h>
#include <popt.h>
#include <errno.h>
+#include <pwd.h>
#include <sys/types.h>
+#include <sys/wait.h>
#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 a3669001..72ab1664 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 ef55dede..e055fe23 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__ */