static uid_t pw_gidpolicy(struct userconf *cnf, char *grname, char *nam, gid_t prefer, bool dryrun) { struct group *grp; gid_t gid = (uid_t) - 1; /* * Check the given gid, if any */ SETGRENT(); if (grname) { if ((grp = GETGRNAM(grname)) == NULL) { gid = pw_checkid(grname, GID_MAX); grp = GETGRGID(gid); } gid = grp->gr_gid; } else if ((grp = GETGRNAM(nam)) != NULL && (grp->gr_mem == NULL || grp->gr_mem[0] == NULL)) { gid = grp->gr_gid; /* Already created? Use it anyway... */ } else { intmax_t grid = -1; /* * We need to auto-create a group with the user's name. We * can send all the appropriate output to our sister routine * bit first see if we can create a group with gid==uid so we * can keep the user and group ids in sync. We purposely do * NOT check the gid range if we can force the sync. If the * user's name dups an existing group, then the group add * function will happily handle that case for us and exit. */ if (GETGRGID(prefer) == NULL) grid = prefer; if (dryrun) { gid = pw_groupnext(cnf, true); } else { if (grid == -1) grid = pw_groupnext(cnf, true); groupadd(cnf, nam, grid, NULL, -1, false, false, false); if ((grp = GETGRNAM(nam)) != NULL) gid = grp->gr_gid; } } ENDGRENT(); return (gid); }
int main(int argc, const char **argv) { gid_t pc_gid = 0; int pc_debug = SSSDBG_DEFAULT; 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 }, { "gid", 'g', POPT_ARG_INT, &pc_gid, 0, _("The GID of the group"), NULL }, POPT_TABLEEND }; poptContext pc = NULL; struct tools_ctx *tctx = NULL; int ret = EXIT_SUCCESS; errno_t sret; const char *pc_groupname = NULL; bool in_transaction = false; debug_prg_name = argv[0]; ret = set_locale(); if (ret != EOK) { DEBUG(1, ("set_locale failed (%d): %s\n", ret, strerror(ret))); ERROR("Error setting the locale\n"); ret = EXIT_FAILURE; goto fini; } /* parse params */ pc = poptGetContext(NULL, argc, argv, long_options, 0); poptSetOtherOptionHelp(pc, "GROUPNAME"); if ((ret = poptGetNextOpt(pc)) < -1) { BAD_POPT_PARAMS(pc, poptStrerror(ret), ret, fini); } DEBUG_INIT(pc_debug); /* groupname is an argument, not option */ pc_groupname = poptGetArg(pc); if (pc_groupname == NULL) { BAD_POPT_PARAMS(pc, _("Specify group to add\n"), ret, fini); } CHECK_ROOT(ret, debug_prg_name); ret = init_sss_tools(&tctx); if (ret != EOK) { DEBUG(1, ("init_sss_tools failed (%d): %s\n", ret, strerror(ret))); if (ret == ENOENT) { ERROR("Error initializing the tools - no local domain\n"); } else { ERROR("Error initializing the tools\n"); } ret = EXIT_FAILURE; goto fini; } /* if the domain was not given as part of FQDN, default to local domain */ ret = parse_name_domain(tctx, pc_groupname); if (ret != EOK) { ERROR("Invalid domain specified in FQDN\n"); ret = EXIT_FAILURE; goto fini; } tctx->octx->gid = pc_gid; /* arguments processed, go on to actual work */ if (id_in_range(tctx->octx->gid, tctx->octx->domain) != EOK) { ERROR("The selected GID is outside the allowed range\n"); ret = EXIT_FAILURE; goto fini; } tctx->error = sysdb_transaction_start(tctx->sysdb); if (tctx->error != EOK) { DEBUG(SSSDBG_CRIT_FAILURE, ("Failed to start transaction\n")); goto done; } in_transaction = true; /* groupadd */ tctx->error = groupadd(tctx->sysdb, tctx->octx); if (tctx->error) { goto done; } tctx->error = sysdb_transaction_commit(tctx->sysdb); if (tctx->error != EOK) { DEBUG(SSSDBG_CRIT_FAILURE, ("Failed to commit transaction\n")); goto done; } in_transaction = false; done: if (in_transaction) { sret = sysdb_transaction_cancel(tctx->sysdb); if (sret != EOK) { DEBUG(SSSDBG_CRIT_FAILURE, ("Failed to cancel transaction\n")); } } if (tctx->error) { ret = tctx->error; switch (ret) { case ERANGE: ERROR("Could not allocate ID for the group - domain full?\n"); break; case EEXIST: ERROR("A group with the same name or GID already exists\n"); break; default: DEBUG(1, ("sysdb operation failed (%d)[%s]\n", ret, strerror(ret))); ERROR("Transaction error. Could not add group.\n"); break; } ret = EXIT_FAILURE; goto fini; } ret = EXIT_SUCCESS; fini: talloc_free(tctx); poptFreeContext(pc); exit(ret); }