diff options
author | Jakub Hrozek <jhrozek@redhat.com> | 2009-07-27 09:49:45 +0200 |
---|---|---|
committer | Stephen Gallagher <sgallagh@redhat.com> | 2009-08-05 10:19:20 -0400 |
commit | 1f6d7dfad2956cb2f6c33104eda4fdbefe380a42 (patch) | |
tree | 3763e4fd1cfe233bbdcd342b26545577f141273e | |
parent | a5fe74914ab920bfaed87c046c525ee7148623f2 (diff) | |
download | sssd-1f6d7dfad2956cb2f6c33104eda4fdbefe380a42.tar.gz sssd-1f6d7dfad2956cb2f6c33104eda4fdbefe380a42.tar.bz2 sssd-1f6d7dfad2956cb2f6c33104eda4fdbefe380a42.zip |
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.
-rw-r--r-- | server/tools/sss_groupadd.c | 34 | ||||
-rw-r--r-- | server/tools/sss_groupdel.c | 34 | ||||
-rw-r--r-- | server/tools/sss_groupmod.c | 47 | ||||
-rw-r--r-- | server/tools/sss_useradd.c | 33 | ||||
-rw-r--r-- | server/tools/sss_userdel.c | 33 | ||||
-rw-r--r-- | server/tools/sss_usermod.c | 54 | ||||
-rw-r--r-- | server/tools/tools_util.c | 125 | ||||
-rw-r--r-- | 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 b7994080..05f814a7 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->gid && 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 a8b93578..96782084 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->gid && 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 d6088846..5420fc03 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->gid && 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 22698e6f..35dcee76 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 f7cb7571..be35b4fa 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 ca6463fa..0e1055dd 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 b580300b..1e0e91de 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 5bf3b384..772ba36b 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__ */ |