-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Hello,
Attached are two patches that allow the tools to operate on fully
qualified names, that is, names in the form of u...@domain.

[PATCH 1/2] Move parsing of names and domains into util/
I used the already existing facility for parsing names from the
responder. This patch moves it into util/ for general consumption.

[PATCH 2/2] Parse fully qualified names in tools
Allow adding users into different domains not only by specifying
ID directly but also by specifying fully qualified name. Exit when
both specifications are used in conflict.

Thanks,
Jakub

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.9 (GNU/Linux)
Comment: Using GnuPG with Fedora - http://enigmail.mozdev.org/

iEYEARECAAYFAkp0XscACgkQHsardTLnvCXhGgCg2wRdt6h54obbb1PVUfK7swCh
JfUAoMQqC2PbmgFamH5r0TtcH7i5/k4L
=5v0C
-----END PGP SIGNATURE-----
>From ab4ed24872959dd06c42c930a3fe53f5d171f79a Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhro...@redhat.com>
Date: Sun, 26 Jul 2009 14:51:55 +0200
Subject: [PATCH 1/2] Move parsing of names and domains into util/

---
 server/responder/common/responder.h        |    7 --
 server/responder/common/responder_common.c |  114 +--------------------------
 server/util/usertools.c                    |  118 ++++++++++++++++++++++++++++
 server/util/util.h                         |   16 ++++
 4 files changed, 135 insertions(+), 120 deletions(-)

diff --git a/server/responder/common/responder.h 
b/server/responder/common/responder.h
index f3d3293..d901704 100644
--- a/server/responder/common/responder.h
+++ b/server/responder/common/responder.h
@@ -53,13 +53,6 @@ struct cli_protocol_version {
     const char *description;
 };
 
-struct sss_names_ctx {
-    char *re_pattern;
-    char *fq_fmt;
-
-    pcre *re;
-};
-
 struct resp_ctx {
     struct tevent_context *ev;
     struct tevent_fd *lfde;
diff --git a/server/responder/common/responder_common.c 
b/server/responder/common/responder_common.c
index 52be780..825d77e 100644
--- a/server/responder/common/responder_common.c
+++ b/server/responder/common/responder_common.c
@@ -43,8 +43,6 @@
 #include "monitor/monitor_interfaces.h"
 #include "sbus/sbus_client.h"
 
-#define NAMES_CONFIG "config/names"
-
 static void set_nonblocking(int fd)
 {
     unsigned v;
@@ -453,62 +451,6 @@ failed:
     return EIO;
 }
 
-int sss_names_init(struct resp_ctx *rctx)
-{
-    struct sss_names_ctx *ctx;
-    const char *errstr;
-    int errval;
-    int errpos;
-    int ret;
-
-    ctx = talloc_zero(rctx, struct sss_names_ctx);
-    if (!ctx) return ENOMEM;
-
-    ret = confdb_get_string(rctx->cdb, ctx, NAMES_CONFIG,
-                            "re-expression", NULL, &ctx->re_pattern);
-    if (ret != EOK) goto done;
-
-    if (!ctx->re_pattern) {
-        ctx->re_pattern = talloc_strdup(ctx,
-                                "(?<name>[...@]+)@?(?<domain>[...@]*$)");
-        if (!ctx->re_pattern) {
-            ret = ENOMEM;
-            goto done;
-        }
-    }
-
-    ret = confdb_get_string(rctx->cdb, ctx, NAMES_CONFIG,
-                            "full-name-format", NULL, &ctx->fq_fmt);
-    if (ret != EOK) goto done;
-
-    if (!ctx->fq_fmt) {
-        ctx->fq_fmt = talloc_strdup(ctx, "%...@%2$s");
-        if (!ctx->fq_fmt) {
-            ret = ENOMEM;
-            goto done;
-        }
-    }
-
-    ctx->re = pcre_compile2(ctx->re_pattern,
-                            PCRE_DUPNAMES | PCRE_EXTENDED,
-                            &errval, &errstr, &errpos, NULL);
-    if (!ctx->re) {
-        DEBUG(1, ("Invalid Regular Expression pattern at position %d."
-                  " (Error: %d [%s])\n", errpos, errval, errstr));
-        ret = EFAULT;
-        goto done;
-    }
-
-    rctx->names = ctx;
-    ret = EOK;
-
-done:
-    if (ret != EOK) {
-        talloc_free(ctx);
-    }
-    return ret;
-}
-
 int sss_process_init(TALLOC_CTX *mem_ctx,
                      struct tevent_context *ev,
                      struct confdb_ctx *cdb,
@@ -565,7 +507,7 @@ int sss_process_init(TALLOC_CTX *mem_ctx,
         return ret;
     }
 
-    ret = sss_names_init(rctx);
+    ret = sss_names_init(rctx, rctx->cdb, &rctx->names);
     if (ret != EOK) {
         DEBUG(0, ("fatal error initializing regex data\n"));
         return ret;
@@ -584,57 +526,3 @@ int sss_process_init(TALLOC_CTX *mem_ctx,
     return EOK;
 }
 
-int sss_parse_name(TALLOC_CTX *memctx,
-                   struct sss_names_ctx *snctx,
-                   const char *orig, char **domain, char **name)
-{
-    pcre *re = snctx->re;
-    const char *result;
-    int ovec[30];
-    int origlen;
-    int ret, strnum;
-
-    origlen = strlen(orig);
-
-    ret = pcre_exec(re, NULL, orig, origlen, 0, PCRE_NOTEMPTY, ovec, 30);
-    if (ret < 0) {
-        DEBUG(2, ("PCRE Matching error, %d\n", ret));
-        return EINVAL;
-    }
-
-    if (ret == 0) {
-        DEBUG(1, ("Too many matches, the pattern is invalid.\n"));
-    }
-
-    strnum = ret;
-
-    result = NULL;
-    ret = pcre_get_named_substring(re, orig, ovec, strnum, "name", &result);
-    if (ret < 0  || !result) {
-        DEBUG(2, ("Name not found!\n"));
-        return EINVAL;
-    }
-    *name = talloc_strdup(memctx, result);
-    pcre_free_substring(result);
-    if (!*name) return ENOMEM;
-
-
-    result = NULL;
-    ret = pcre_get_named_substring(re, orig, ovec, strnum, "domain", &result);
-    if (ret < 0  || !result) {
-        DEBUG(4, ("Domain not provided!\n"));
-        *domain = NULL;
-    } else {
-        /* ignore "" string */
-        if (*result) {
-            *domain = talloc_strdup(memctx, result);
-            pcre_free_substring(result);
-            if (!*domain) return ENOMEM;
-        } else {
-            pcre_free_substring(result);
-            *domain = NULL;
-        }
-    }
-
-    return EOK;
-}
diff --git a/server/util/usertools.c b/server/util/usertools.c
index 0793061..220b52c 100644
--- a/server/util/usertools.c
+++ b/server/util/usertools.c
@@ -20,8 +20,15 @@
 */
 
 #include <pwd.h>
+#include <pcre.h>
+#include <errno.h>
 #include <talloc.h>
 
+#include "confdb/confdb.h"
+#include "util/util.h"
+
+#define NAMES_CONFIG "config/names"
+
 char *get_username_from_uid(TALLOC_CTX *mem_ctx, uid_t uid)
 {
     char *username;
@@ -33,3 +40,114 @@ char *get_username_from_uid(TALLOC_CTX *mem_ctx, uid_t uid)
     username = talloc_strdup(mem_ctx, pwd->pw_name);
     return username;
 }
+
+int sss_names_init(TALLOC_CTX *mem_ctx, struct confdb_ctx *cdb, struct 
sss_names_ctx **out)
+{
+    struct sss_names_ctx *ctx = NULL;
+    const char *errstr;
+    int errval;
+    int errpos;
+    int ret;
+
+    ctx = talloc_zero(ctx, struct sss_names_ctx);
+    if (!ctx) return ENOMEM;
+
+    ret = confdb_get_string(cdb, ctx, NAMES_CONFIG,
+                            "re-expression", NULL, &ctx->re_pattern);
+    if (ret != EOK) goto done;
+
+    if (!ctx->re_pattern) {
+        ctx->re_pattern = talloc_strdup(ctx,
+                                "(?<name>[...@]+)@?(?<domain>[...@]*$)");
+        if (!ctx->re_pattern) {
+            ret = ENOMEM;
+            goto done;
+        }
+    }
+
+    ret = confdb_get_string(cdb, ctx, NAMES_CONFIG,
+                            "full-name-format", NULL, &ctx->fq_fmt);
+    if (ret != EOK) goto done;
+
+    if (!ctx->fq_fmt) {
+        ctx->fq_fmt = talloc_strdup(ctx, "%...@%2$s");
+        if (!ctx->fq_fmt) {
+            ret = ENOMEM;
+            goto done;
+        }
+    }
+
+    ctx->re = pcre_compile2(ctx->re_pattern,
+                            PCRE_DUPNAMES | PCRE_EXTENDED,
+                            &errval, &errstr, &errpos, NULL);
+    if (!ctx->re) {
+        DEBUG(1, ("Invalid Regular Expression pattern at position %d."
+                  " (Error: %d [%s])\n", errpos, errval, errstr));
+        ret = EFAULT;
+        goto done;
+    }
+
+    *out = ctx;
+    ret = EOK;
+
+done:
+    if (ret != EOK) {
+        talloc_free(ctx);
+    }
+    return ret;
+}
+
+int sss_parse_name(TALLOC_CTX *memctx,
+                   struct sss_names_ctx *snctx,
+                   const char *orig, char **domain, char **name)
+{
+    pcre *re = snctx->re;
+    const char *result;
+    int ovec[30];
+    int origlen;
+    int ret, strnum;
+
+    origlen = strlen(orig);
+
+    ret = pcre_exec(re, NULL, orig, origlen, 0, PCRE_NOTEMPTY, ovec, 30);
+    if (ret < 0) {
+        DEBUG(2, ("PCRE Matching error, %d\n", ret));
+        return EINVAL;
+    }
+
+    if (ret == 0) {
+        DEBUG(1, ("Too many matches, the pattern is invalid.\n"));
+    }
+
+    strnum = ret;
+
+    result = NULL;
+    ret = pcre_get_named_substring(re, orig, ovec, strnum, "name", &result);
+    if (ret < 0  || !result) {
+        DEBUG(2, ("Name not found!\n"));
+        return EINVAL;
+    }
+    *name = talloc_strdup(memctx, result);
+    pcre_free_substring(result);
+    if (!*name) return ENOMEM;
+
+
+    result = NULL;
+    ret = pcre_get_named_substring(re, orig, ovec, strnum, "domain", &result);
+    if (ret < 0  || !result) {
+        DEBUG(4, ("Domain not provided!\n"));
+        *domain = NULL;
+    } else {
+        /* ignore "" string */
+        if (*result) {
+            *domain = talloc_strdup(memctx, result);
+            pcre_free_substring(result);
+            if (!*domain) return ENOMEM;
+        } else {
+            pcre_free_substring(result);
+            *domain = NULL;
+        }
+    }
+
+    return EOK;
+}
diff --git a/server/util/util.h b/server/util/util.h
index 02916c1..3badb29 100644
--- a/server/util/util.h
+++ b/server/util/util.h
@@ -9,6 +9,7 @@
 #include <errno.h>
 #include <limits.h>
 #include <time.h>
+#include <pcre.h>
 #include "config.h"
 #include "talloc.h"
 #include "tevent.h"
@@ -119,4 +120,19 @@ int password_destructor(void *memctx);
 /* from usertools.c */
 char *get_username_from_uid(TALLOC_CTX *mem_ctx, uid_t uid);
 
+struct sss_names_ctx {
+    char *re_pattern;
+    char *fq_fmt;
+
+    pcre *re;
+};
+
+int sss_names_init(TALLOC_CTX *mem_ctx,
+                   struct confdb_ctx *cdb,
+                   struct sss_names_ctx **out);
+
+int sss_parse_name(TALLOC_CTX *memctx,
+                   struct sss_names_ctx *snctx,
+                   const char *orig, char **domain, char **name);
+
 #endif /* __SSSD_UTIL_H__ */
-- 
1.6.2.5

>From 0d7c367e30cc907231d01768df65dc3b6eb4901d Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhro...@redhat.com>
Date: Mon, 27 Jul 2009 09:49:45 +0200
Subject: [PATCH 2/2] Parse fully qualified names in tools

Allow adding users into different domains not only by specifying
ID directly but also by specifying fully qualified name. Exit when
both specifications are used in conflict.
---
 server/tools/sss_groupadd.c |   34 +++++++++---
 server/tools/sss_groupdel.c |   34 ++++++++++--
 server/tools/sss_groupmod.c |   47 +++++++++++++----
 server/tools/sss_useradd.c  |   33 +++++++++--
 server/tools/sss_userdel.c  |   33 +++++++++--
 server/tools/sss_usermod.c  |   54 +++++++++++++++----
 server/tools/tools_util.c   |  125 ++++++++++++++++++++++++++++++-------------
 server/tools/tools_util.h   |   17 ++++--
 8 files changed, 289 insertions(+), 88 deletions(-)

diff --git a/server/tools/sss_groupadd.c b/server/tools/sss_groupadd.c
index b799408..4faa8ee 100644
--- a/server/tools/sss_groupadd.c
+++ b/server/tools/sss_groupadd.c
@@ -158,6 +158,7 @@ int main(int argc, const char **argv)
     struct tevent_req *req;
     struct ops_ctx *data = NULL;
     int ret = EXIT_SUCCESS;
+    const char *pc_groupname = NULL;
 
     debug_prg_name = argv[0];
 
@@ -199,24 +200,43 @@ int main(int argc, const char **argv)
     debug_level = pc_debug;
 
     /* groupname is an argument, not option */
-    data->name = poptGetArg(pc);
-    if (data->name == NULL) {
+    pc_groupname = poptGetArg(pc);
+    if (pc_groupname == NULL) {
         usage(pc, _("Specify group to add\n"));
         ret = EXIT_FAILURE;
         goto fini;
     }
 
+    ret = parse_name_domain(data, pc_groupname);
+    if (ret != EOK) {
+        ret = EXIT_FAILURE;
+        goto fini;
+    }
+
     data->gid = pc_gid;
 
-    /* arguments processed, go on to actual work */
-    ret = find_domain_for_id(ctx, data->gid, &dom);
+    ret = get_domain_by_id(data->ctx, data->gid, &dom);
+    if (ret != EOK) {
+        ERROR("Cannot get domain info\n");
+        ret = EXIT_FAILURE;
+        goto fini;
+    }
+    if (data->domain && data->uid && data->domain != dom) {
+        ERROR("Selected domain %s conflicts with selected GID %llu\n",
+                data->domain->name, (unsigned long long int) data->gid);
+        ret = EXIT_FAILURE;
+        goto fini;
+    }
+    if (data->domain == NULL && dom) {
+        data->domain = dom;
+    }
+
+    ret = get_domain_type(data->ctx, data->domain);
     switch (ret) {
         case ID_IN_LOCAL:
-            data->domain = dom;
             break;
 
         case ID_IN_LEGACY_LOCAL:
-            data->domain = dom;
         case ID_OUTSIDE:
             ret = groupadd_legacy(data);
             if(ret != EOK) {
@@ -231,7 +251,7 @@ int main(int argc, const char **argv)
             goto fini;
 
         default:
-            DEBUG(1, ("Unknown return code %d from find_domain_for_id\n", 
ret));
+            DEBUG(1, ("Unknown return code %d from get_domain_type\n", ret));
             ERROR("Error looking up domain\n");
             ret = EXIT_FAILURE;
             goto fini;
diff --git a/server/tools/sss_groupdel.c b/server/tools/sss_groupdel.c
index a8b9357..d547904 100644
--- a/server/tools/sss_groupdel.c
+++ b/server/tools/sss_groupdel.c
@@ -147,6 +147,7 @@ int main(int argc, const char **argv)
     struct tevent_req *req;
     struct sss_domain_info *dom;
     struct group *grp_info;
+    const char *pc_groupname = NULL;
 
     poptContext pc = NULL;
     struct poptOption long_options[] = {
@@ -195,27 +196,48 @@ int main(int argc, const char **argv)
 
     debug_level = pc_debug;
 
-    data->name = poptGetArg(pc);
-    if(data->name == NULL) {
+    pc_groupname = poptGetArg(pc);
+    if(pc_groupname == NULL) {
         usage(pc, _("Specify group to delete\n"));
         ret = EXIT_FAILURE;
         goto fini;
     }
 
+    ret = parse_name_domain(data, pc_groupname);
+    if (ret != EOK) {
+        ret = EXIT_FAILURE;
+        goto fini;
+    }
+
     /* arguments processed, go on to actual work */
     grp_info = getgrnam(data->name);
     if (grp_info) {
         data->gid = grp_info->gr_gid;
     }
 
-    ret = find_domain_for_id(ctx, data->gid, &dom);
+    /* arguments processed, go on to actual work */
+    ret = get_domain_by_id(data->ctx, data->gid, &dom);
+    if (ret != EOK) {
+        ERROR("Cannot get domain info\n");
+        ret = EXIT_FAILURE;
+        goto fini;
+    }
+    if (data->domain && data->uid && data->domain != dom) {
+        ERROR("Selected domain %s conflicts with selected GID %llu\n",
+                data->domain->name, (unsigned long long int) data->gid);
+        ret = EXIT_FAILURE;
+        goto fini;
+    }
+    if (data->domain == NULL && dom) {
+        data->domain = dom;
+    }
+
+    ret = get_domain_type(data->ctx, data->domain);
     switch (ret) {
         case ID_IN_LOCAL:
-            data->domain = dom;
             break;
 
         case ID_IN_LEGACY_LOCAL:
-            data->domain = dom;
         case ID_OUTSIDE:
             ret = groupdel_legacy(data);
             if(ret != EOK) {
@@ -232,7 +254,7 @@ int main(int argc, const char **argv)
             goto fini;
 
         default:
-            DEBUG(1, ("Unknown return code %d from find_domain_for_id\n", 
ret));
+            DEBUG(1, ("Unknown return code %d from get_domain_type\n", ret));
             ERROR("Error looking up domain\n");
             ret = EXIT_FAILURE;
             goto fini;
diff --git a/server/tools/sss_groupmod.c b/server/tools/sss_groupmod.c
index d608884..089b765 100644
--- a/server/tools/sss_groupmod.c
+++ b/server/tools/sss_groupmod.c
@@ -261,7 +261,8 @@ static void add_to_groups_done(struct tevent_req *req)
 }
 
 static int groupmod_legacy(struct tools_ctx *tools_ctx,
-                           struct ops_ctx *ctx, int old_domain)
+                           struct ops_ctx *ctx,
+                           struct sss_domain_info *old_domain)
 {
     int ret = EOK;
     char *command = NULL;
@@ -276,8 +277,13 @@ static int groupmod_legacy(struct tools_ctx *tools_ctx,
     }
 
     if (ctx->gid) {
-        ret = find_domain_for_id(tools_ctx, ctx->gid, &dom);
-        if (ret == old_domain) {
+        ret = get_domain_by_id(tools_ctx, ctx->gid, &dom);
+        if (ret != EOK) {
+            ERROR("Cannot get domain info\n");
+            talloc_free(command);
+            return EINVAL;
+        }
+        if (dom == old_domain) {
             APPEND_PARAM(command, GROUPMOD_GID, ctx->gid);
         } else {
             ERROR("Changing gid only allowed inside the same domain\n");
@@ -329,6 +335,7 @@ int main(int argc, const char **argv)
     int ret;
     struct group *grp_info;
     gid_t old_gid = 0;
+    const char *pc_groupname = NULL;
 
     debug_prg_name = argv[0];
 
@@ -389,13 +396,19 @@ int main(int argc, const char **argv)
     }
 
     /* groupname is an argument without --option */
-    data->name = poptGetArg(pc);
-    if (data->name == NULL) {
+    pc_groupname = poptGetArg(pc);
+    if (pc_groupname == NULL) {
         usage(pc, _("Specify group to modify\n"));
         ret = EXIT_FAILURE;
         goto fini;
     }
 
+    ret = parse_name_domain(data, pc_groupname);
+    if (ret != EOK) {
+        ret = EXIT_FAILURE;
+        goto fini;
+    }
+
     data->gid = pc_gid;
 
     /* arguments processed, go on to actual work */
@@ -404,16 +417,30 @@ int main(int argc, const char **argv)
        old_gid = grp_info->gr_gid;
     }
 
-    ret = find_domain_for_id(ctx, old_gid, &dom);
+    ret = get_domain_by_id(data->ctx, data->gid, &dom);
+    if (ret != EOK) {
+        ERROR("Cannot get domain info\n");
+        ret = EXIT_FAILURE;
+        goto fini;
+    }
+    if (data->domain && data->uid && data->domain != dom) {
+        ERROR("Selected domain %s conflicts with selected GID %llu\n",
+                data->domain->name, (unsigned long long int) data->gid);
+        ret = EXIT_FAILURE;
+        goto fini;
+    }
+    if (data->domain == NULL && dom) {
+        data->domain = dom;
+    }
+
+    ret = get_domain_type(data->ctx, data->domain);
     switch (ret) {
         case ID_IN_LOCAL:
-            data->domain = dom;
             break;
 
         case ID_IN_LEGACY_LOCAL:
-            data->domain = dom;
         case ID_OUTSIDE:
-            ret = groupmod_legacy(ctx, data, ret);
+            ret = groupmod_legacy(ctx, data, data->domain);
             if(ret != EOK) {
                 ERROR("Cannot delete group from domain using the legacy 
tools\n");
             }
@@ -426,7 +453,7 @@ int main(int argc, const char **argv)
             goto fini;
 
         default:
-            DEBUG(1, ("Unknown return code %d from find_domain_for_id\n", 
ret));
+            DEBUG(1, ("Unknown return code %d from get_domain_type\n", ret));
             ERROR("Error looking up domain\n");
             ret = EXIT_FAILURE;
             goto fini;
diff --git a/server/tools/sss_useradd.c b/server/tools/sss_useradd.c
index b284179..8dbecd8 100644
--- a/server/tools/sss_useradd.c
+++ b/server/tools/sss_useradd.c
@@ -327,6 +327,7 @@ int main(int argc, const char **argv)
     char *pc_shell = NULL;
     char *basedir = NULL;
     int pc_debug = 0;
+    const char *pc_username = NULL;
     struct poptOption long_options[] = {
         POPT_AUTOHELP
         { "debug", '\0', POPT_ARG_INT | POPT_ARGFLAG_DOC_HIDDEN, &pc_debug, 0, 
_("The debug level to run with"), NULL },
@@ -401,13 +402,19 @@ int main(int argc, const char **argv)
     }
 
     /* username is an argument without --option */
-    data->name = poptGetArg(pc);
-    if (data->name == NULL) {
+    pc_username = poptGetArg(pc);
+    if (pc_username == NULL) {
         usage(pc, (_("Specify user to add\n")));
         ret = EXIT_FAILURE;
         goto fini;
     }
 
+    ret = parse_name_domain(data, pc_username);
+    if (ret != EOK) {
+        ret = EXIT_FAILURE;
+        goto fini;
+    }
+
     /* Same as shadow-utils useradd, -g can specify gid or group name */
     if (pc_group != NULL) {
         ret = get_gid(data, pc_group);
@@ -470,14 +477,28 @@ int main(int argc, const char **argv)
     }
 
     /* arguments processed, go on to actual work */
-    ret = find_domain_for_id(ctx, data->uid, &dom);
+    ret = get_domain_by_id(data->ctx, data->uid, &dom);
+    if (ret != EOK) {
+        ERROR("Cannot get domain info\n");
+        ret = EXIT_FAILURE;
+        goto fini;
+    }
+    if (data->domain && data->uid && data->domain != dom) {
+        ERROR("Selected domain %s conflicts with selected UID %llu\n",
+                data->domain->name, (unsigned long long int) data->uid);
+        ret = EXIT_FAILURE;
+        goto fini;
+    }
+    if (data->domain == NULL && dom) {
+        data->domain = dom;
+    }
+
+    ret = get_domain_type(data->ctx, data->domain);
     switch (ret) {
         case ID_IN_LOCAL:
-            data->domain = dom;
             break;
 
         case ID_IN_LEGACY_LOCAL:
-            data->domain = dom;
         case ID_OUTSIDE:
             ret = useradd_legacy(data, groups);
             if(ret != EOK) {
@@ -492,7 +513,7 @@ int main(int argc, const char **argv)
             goto fini;
 
         default:
-            DEBUG(1, ("Unknown return code %d from find_domain_for_id\n", 
ret));
+            DEBUG(1, ("Unknown return code %d from get_domain_type\n", ret));
             ERROR("Error looking up domain\n");
             ret = EXIT_FAILURE;
             goto fini;
diff --git a/server/tools/sss_userdel.c b/server/tools/sss_userdel.c
index f7cb757..be35b4f 100644
--- a/server/tools/sss_userdel.c
+++ b/server/tools/sss_userdel.c
@@ -147,6 +147,7 @@ int main(int argc, const char **argv)
     struct tevent_req *req;
     struct sss_domain_info *dom;
     struct passwd *pwd_info;
+    const char *pc_username = NULL;
 
     int pc_debug = 0;
     poptContext pc = NULL;
@@ -196,27 +197,47 @@ int main(int argc, const char **argv)
 
     debug_level = pc_debug;
 
-    data->name = poptGetArg(pc);
-    if (data->name == NULL) {
+    pc_username = poptGetArg(pc);
+    if (pc_username == NULL) {
         usage(pc, _("Specify user to delete\n"));
         ret = EXIT_FAILURE;
         goto fini;
     }
 
+    ret = parse_name_domain(data, pc_username);
+    if (ret != EOK) {
+        ret = EXIT_FAILURE;
+        goto fini;
+    }
+
     /* arguments processed, go on to actual work */
     pwd_info = getpwnam(data->name);
     if (pwd_info) {
         data->uid = pwd_info->pw_uid;
     }
 
-    ret = find_domain_for_id(ctx, data->uid, &dom);
+    ret = get_domain_by_id(data->ctx, data->uid, &dom);
+    if (ret != EOK) {
+        ERROR("Cannot get domain info\n");
+        ret = EXIT_FAILURE;
+        goto fini;
+    }
+    if (data->domain && data->uid && data->domain != dom) {
+        ERROR("Selected domain %s conflicts with selected UID %llu\n",
+                data->domain->name, (unsigned long long int) data->uid);
+        ret = EXIT_FAILURE;
+        goto fini;
+    }
+    if (data->domain == NULL && dom) {
+        data->domain = dom;
+    }
+
+    ret = get_domain_type(data->ctx, data->domain);
     switch (ret) {
         case ID_IN_LOCAL:
-            data->domain = dom;
             break;
 
         case ID_IN_LEGACY_LOCAL:
-            data->domain = dom;
         case ID_OUTSIDE:
             ret = userdel_legacy(data);
             if(ret != EOK) {
@@ -233,7 +254,7 @@ int main(int argc, const char **argv)
             goto fini;
 
         default:
-            DEBUG(1, ("Unknown return code %d from find_domain_for_id\n", 
ret));
+            DEBUG(1, ("Unknown return code %d from get_domain_type\n", ret));
             ERROR("Error looking up domain\n");
             ret = EXIT_FAILURE;
             goto fini;
diff --git a/server/tools/sss_usermod.c b/server/tools/sss_usermod.c
index ca6463f..0e1055d 100644
--- a/server/tools/sss_usermod.c
+++ b/server/tools/sss_usermod.c
@@ -289,7 +289,8 @@ static void add_to_groups_done(struct tevent_req *req)
 static int usermod_legacy(struct tools_ctx *tools_ctx, struct ops_ctx *ctx,
                           uid_t uid, gid_t gid,
                           const char *gecos, const char *home,
-                          const char *shell, int lock, int old_domain)
+                          const char *shell, int lock,
+                          struct sss_domain_info *old_domain)
 {
     int ret = EOK;
     char *command = NULL;
@@ -298,8 +299,13 @@ static int usermod_legacy(struct tools_ctx *tools_ctx, 
struct ops_ctx *ctx,
     APPEND_STRING(command, USERMOD);
 
     if (uid) {
-        ret = find_domain_for_id(tools_ctx, uid, &dom);
-        if (ret == old_domain) {
+        ret = get_domain_by_id(tools_ctx, ctx->gid, &dom);
+        if (ret != EOK) {
+            ERROR("Cannot get domain info\n");
+            talloc_free(command);
+            return EINVAL;
+        }
+        if (dom == old_domain) {
             APPEND_PARAM(command, USERMOD_UID, uid);
         } else {
             ERROR("Changing uid only allowed inside the same domain\n");
@@ -309,8 +315,13 @@ static int usermod_legacy(struct tools_ctx *tools_ctx, 
struct ops_ctx *ctx,
     }
 
     if (gid) {
-        ret = find_domain_for_id(tools_ctx, gid, &dom);
-        if (ret == old_domain) {
+        ret = get_domain_by_id(tools_ctx, ctx->gid, &dom);
+        if (ret != EOK) {
+            ERROR("Cannot get domain info\n");
+            talloc_free(command);
+            return EINVAL;
+        }
+        if (dom == old_domain) {
             APPEND_PARAM(command, USERMOD_GID, gid);
         } else {
             ERROR("Changing gid only allowed inside the same domain\n");
@@ -381,6 +392,7 @@ int main(int argc, const char **argv)
     int ret;
     struct passwd *pwd_info;
     uid_t old_uid = 0;
+    const char *pc_username = NULL;
 
     debug_prg_name = argv[0];
 
@@ -452,29 +464,49 @@ int main(int argc, const char **argv)
     }
 
     /* username is an argument without --option */
-    data->name = poptGetArg(pc);
-    if (data->name == NULL) {
+    pc_username = poptGetArg(pc);
+    if (pc_username == NULL) {
         usage(pc, _("Specify user to modify\n"));
         ret = EXIT_FAILURE;
         goto fini;
     }
 
+    ret = parse_name_domain(data, pc_username);
+    if (ret != EOK) {
+        ret = EXIT_FAILURE;
+        goto fini;
+    }
+
     pwd_info = getpwnam(data->name);
     if (pwd_info) {
         old_uid = pwd_info->pw_uid;
     }
 
-    ret = find_domain_for_id(ctx, old_uid, &dom);
+    ret = get_domain_by_id(data->ctx, data->uid, &dom);
+    if (ret != EOK) {
+        ERROR("Cannot get domain info\n");
+        ret = EXIT_FAILURE;
+        goto fini;
+    }
+    if (data->domain && data->uid && data->domain != dom) {
+        ERROR("Selected domain %s conflicts with selected UID %llu\n",
+                data->domain->name, (unsigned long long int) data->uid);
+        ret = EXIT_FAILURE;
+        goto fini;
+    }
+    if (data->domain == NULL && dom) {
+        data->domain = dom;
+    }
+
+    ret = get_domain_type(data->ctx, data->domain);
     switch (ret) {
         case ID_IN_LOCAL:
-            data->domain = dom;
             break;
 
         case ID_IN_LEGACY_LOCAL:
-            data->domain = dom;
         case ID_OUTSIDE:
             ret = usermod_legacy(ctx, data, pc_uid, pc_gid, pc_gecos,
-                                 pc_home, pc_shell, pc_lock, ret);
+                                 pc_home, pc_shell, pc_lock, data->domain);
             if(ret != EOK) {
                 ERROR("Cannot delete user from domain using the legacy 
tools\n");
             }
diff --git a/server/tools/tools_util.c b/server/tools/tools_util.c
index b580300..1e0e91d 100644
--- a/server/tools/tools_util.c
+++ b/server/tools/tools_util.c
@@ -69,52 +69,61 @@ static int is_domain_local_legacy(struct tools_ctx *ctx, 
struct sss_domain_info
     return -1;
 }
 
-enum id_domain find_domain_for_id(struct tools_ctx *ctx,
-                                  uint32_t id,
-                                  struct sss_domain_info **dom_ret)
+enum id_domain get_domain_type(struct tools_ctx *ctx,
+                               struct sss_domain_info *dom)
+{
+    if (dom == NULL) {
+        return ID_OUTSIDE;
+    }
+
+    if (strcasecmp(dom->provider, "local") == 0) {
+        return ID_IN_LOCAL;
+    } else if (is_domain_local_legacy(ctx, dom) == 0) {
+        return ID_IN_LEGACY_LOCAL;
+    }
+
+    return ID_IN_OTHER;
+}
+
+static struct sss_domain_info *get_local_domain(struct tools_ctx *ctx)
 {
     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->provider, "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;
+    /* No ID specified, find LOCAL */
+    for (dom = ctx->domains; dom; dom = dom->next) {
+        if (strcasecmp(dom->provider, "local") == 0) {
+            break;
         }
-    } else {
-        /* No ID specified, find LOCAL */
+    }
+
+    return dom;
+}
+
+int get_domain_by_id(struct tools_ctx *ctx,
+                     uint32_t id,
+                     struct sss_domain_info **_dom)
+{
+    struct sss_domain_info *dom = NULL;
+    int ret = EOK;
+
+    if (id) {
         for (dom = ctx->domains; dom; dom = dom->next) {
-            if (strcasecmp(dom->provider, "local") == 0) {
-                *dom_ret = dom;
-                return ID_IN_LOCAL;
+            if (id >= dom->id_min && id <= dom->id_max) {
+                break;
             }
         }
+    }
+
+    if (dom == NULL && id == 0) {
+        dom = get_local_domain(ctx);
         if (dom == NULL) {
-            DEBUG(1, ("Could not get LOCAL domain info\n"));
-            *dom_ret = dom;
-            return ID_ERROR;
+            DEBUG(1, ("Cannot find local domain info\n"));
+            ret = ENOENT;
         }
     }
 
-    /* We should never end up here */
-    *dom_ret = NULL;
-    return ID_ERROR;
+    *_dom = dom;
+    return ret;
 }
 
 int setup_db(struct tools_ctx **tools_ctx)
@@ -229,6 +238,40 @@ int parse_groups(TALLOC_CTX *mem_ctx, const char *optstr, 
char ***_out)
     return EOK;
 }
 
+int parse_name_domain(struct ops_ctx *octx,
+                      const char *fullname)
+{
+    int ret;
+    char *domain = NULL;
+    struct sss_domain_info *dom;
+
+    ret = sss_parse_name(octx, octx->ctx->snctx, fullname, &domain, 
&octx->name);
+    if (ret != EOK) {
+        DEBUG(0, ("Cannot parse full name\n"));
+        return ret;
+    }
+    DEBUG(5, ("Parsed username: %s\n", octx->name));
+
+    if (domain) {
+        DEBUG(5, ("Parsed domain: %s\n", domain));
+
+        /* Got string domain name, find corresponding sss_domain_info */
+        for (dom = octx->ctx->domains; dom; dom = dom->next) {
+            if (strcasecmp(dom->name, domain) == 0) {
+                DEBUG(6, ("Found sss_domain_info for given domain name\n"));
+                octx->domain = dom;
+                break;
+            }
+        }
+        if (octx->domain == NULL) {
+            DEBUG(0, ("Invalid domain %s specified in FQDN\n", domain));
+            return EINVAL;
+        }
+    }
+
+    return EOK;
+}
+
 int set_locale(void)
 {
     char *c;
@@ -253,18 +296,26 @@ int set_locale(void)
     return EOK;
 }
 
-int init_sss_tools(struct tools_ctx **ctx)
+int init_sss_tools(struct tools_ctx **_ctx)
 {
     int ret;
+    struct tools_ctx *ctx;
 
     /* Connect to the database */
-    ret = setup_db(ctx);
+    ret = setup_db(&ctx);
     if (ret != EOK) {
         DEBUG(1, ("Could not set up database\n"));
         ret = EXIT_FAILURE;
         goto fini;
     }
 
+    ret = sss_names_init(ctx, ctx->confdb, &ctx->snctx);
+    if (ret != EOK) {
+        DEBUG(1, ("Could not set up parsing\n"));
+        goto fini;
+    }
+
+    *_ctx = ctx;
     ret = EOK;
 fini:
     return ret;
diff --git a/server/tools/tools_util.h b/server/tools/tools_util.h
index 5bf3b38..772ba36 100644
--- a/server/tools/tools_util.h
+++ b/server/tools/tools_util.h
@@ -44,6 +44,7 @@ struct tools_ctx {
     struct tevent_context *ev;
     struct confdb_ctx *confdb;
     struct sysdb_ctx *sysdb;
+    struct sss_names_ctx *snctx;
 
     struct sss_domain_info *domains;
 };
@@ -53,7 +54,7 @@ struct ops_ctx {
     struct tevent_context *ev;
     struct sss_domain_info *domain;
 
-    const char *name;
+    char *name;
     uid_t uid;
     gid_t gid;
     char *gecos;
@@ -71,7 +72,7 @@ struct ops_ctx {
     bool done;
 };
 
-int init_sss_tools(struct tools_ctx **ctx);
+int init_sss_tools(struct tools_ctx **_ctx);
 
 int setup_db(struct tools_ctx **ctx);
 
@@ -79,10 +80,16 @@ 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);
+enum id_domain get_domain_type(struct tools_ctx *ctx,
+                               struct sss_domain_info *dom);
+
+int get_domain_by_id(struct tools_ctx *ctx,
+                     uint32_t id,
+                     struct sss_domain_info **_dom);
 
 int set_locale(void);
 
+int parse_name_domain(struct ops_ctx *octx,
+                      const char *fullname);
+
 #endif  /* __TOOLS_UTIL_H__ */
-- 
1.6.2.5

Attachment: 0001-Move-parsing-of-names-and-domains-into-util.patch.sig
Description: PGP signature

Attachment: 0002-Parse-fully-qualified-names-in-tools.patch.sig
Description: PGP signature

_______________________________________________
Freeipa-devel mailing list
Freeipa-devel@redhat.com
https://www.redhat.com/mailman/listinfo/freeipa-devel

Reply via email to