/* * check_flags - check flags and parameters consistency * * It will not return if an error is encountered. */ static void check_flags (void) { /* -o does not make sense without -g */ if (oflg && !gflg) { usage (E_USAGE); } check_new_name (); /* * Check if the group already exist. */ /* local, no need for xgetgrnam */ if (prefix_getgrnam (group_name) != NULL) { /* The group already exist */ if (fflg) { /* OK, no need to do anything */ exit (E_SUCCESS); } fprintf (stderr, _("%s: group '%s' already exists\n"), Prog, group_name); exit (E_NAME_IN_USE); } if (gflg && (prefix_getgrgid (group_id) != NULL)) { /* A GID was specified, and a group already exist with that GID * - either we will use this GID anyway (-o) * - either we ignore the specified GID and * we will use another one (-f) * - either it is a failure */ if (oflg) { /* Continue with this GID */ } else if (fflg) { /* Turn off -g, we can use any GID */ gflg = false; } else { fprintf (stderr, _("%s: GID '%lu' already exists\n"), Prog, (unsigned long int) group_id); exit (E_GID_IN_USE); } } }
static void find_new_gid (void) { const struct group *grp; gid_t gid_min, gid_max; gid_min = getdef_unum ("GID_MIN", 100); gid_max = getdef_unum ("GID_MAX", 60000); /* * Start with some GID value if the user didn't provide us with * one already. */ if (!gflg) group_id = gid_min; /* * Search the entire group file, either looking for this GID (if the * user specified one with -g) or looking for the largest unused * value. */ #ifdef NO_GETGRENT gr_rewind (); while ((grp = gr_next ())) { #else setgrent (); while ((grp = getgrent ())) { #endif if (strcmp (group_name, grp->gr_name) == 0) { if (fflg) { fail_exit (E_SUCCESS); } fprintf (stderr, _("%s: name %s is not unique\n"), Prog, group_name); fail_exit (E_NAME_IN_USE); } if (gflg && group_id == grp->gr_gid) { if (fflg) { /* turn off -g and search again */ gflg = 0; #ifdef NO_GETGRENT gr_rewind (); #else setgrent (); #endif continue; } fprintf (stderr, _("%s: gid %u is not unique\n"), Prog, (unsigned int) group_id); fail_exit (E_GID_IN_USE); } if (!gflg && grp->gr_gid >= group_id) { if (grp->gr_gid > gid_max) continue; group_id = grp->gr_gid + 1; } } if (!gflg && group_id == gid_max + 1) { for (group_id = gid_min; group_id < gid_max; group_id++) { #ifdef NO_GETGRENT gr_rewind (); while ((grp = gr_next ()) && grp->gr_gid != group_id); if (!grp) break; #else if (!getgrgid (group_id)) break; #endif } if (group_id == gid_max) { fprintf (stderr, _("%s: can't get unique gid\n"), Prog); fail_exit (E_GID_IN_USE); } } } /* * check_new_name - check the new name for validity * * check_new_name() insures that the new name doesn't contain any * illegal characters. */ static void check_new_name (void) { if (check_group_name (group_name)) return; /* * All invalid group names land here. */ fprintf (stderr, _("%s: %s is a not a valid group name\n"), Prog, group_name); exit (E_BAD_ARG); } /* * process_flags - perform command line argument setting * * process_flags() interprets the command line arguments and sets the * values that the user will be created with accordingly. The values * are checked for sanity. */ static void process_flags (int argc, char **argv) { char *cp; int arg; while ((arg = getopt (argc, argv, "og:O:f")) != EOF) { switch (arg) { case 'g': gflg++; if (!isdigit (optarg[0])) usage (); group_id = strtoul (optarg, &cp, 10); if (*cp != '\0') { fprintf (stderr, _("%s: invalid group %s\n"), Prog, optarg); fail_exit (E_BAD_ARG); } break; case 'o': oflg++; break; case 'O': /* * override login.defs defaults (-O name=value) * example: -O GID_MIN=100 -O GID_MAX=499 * note: -O GID_MIN=10,GID_MAX=499 doesn't work yet */ cp = strchr (optarg, '='); if (!cp) { fprintf (stderr, _("%s: -O requires NAME=VALUE\n"), Prog); exit (E_BAD_ARG); } /* terminate name, point to value */ *cp++ = '\0'; if (putdef_str (optarg, cp) < 0) exit (E_BAD_ARG); break; case 'f': /* * "force" - do nothing, just exit(0), if the * specified group already exists. With -g, if * specified gid already exists, choose another * (unique) gid (turn off -g). Based on the RedHat's * patch from shadow-utils-970616-9. */ fflg++; break; default: usage (); } } if (oflg && !gflg) usage (); if (optind != argc - 1) usage (); group_name = argv[argc - 1]; check_new_name (); }
/* * main - groupmod command * */ int main (int argc, char **argv) { #ifdef ACCT_TOOLS_SETUID #ifdef USE_PAM pam_handle_t *pamh = NULL; int retval; #endif /* USE_PAM */ #endif /* ACCT_TOOLS_SETUID */ #ifdef WITH_AUDIT audit_help_open (); #endif atexit (do_cleanups); /* * Get my name so that I can use it to report errors. */ Prog = Basename (argv[0]); (void) setlocale (LC_ALL, ""); (void) bindtextdomain (PACKAGE, LOCALEDIR); (void) textdomain (PACKAGE); process_flags (argc, argv); OPENLOG ("groupmod"); #ifdef ACCT_TOOLS_SETUID #ifdef USE_PAM { struct passwd *pampw; pampw = getpwuid (getuid ()); /* local, no need for xgetpwuid */ if (NULL == pampw) { fprintf (stderr, _("%s: Cannot determine your user name.\n"), Prog); exit (1); } retval = pam_start ("groupmod", pampw->pw_name, &conv, &pamh); } if (PAM_SUCCESS == retval) { retval = pam_authenticate (pamh, 0); } if (PAM_SUCCESS == retval) { retval = pam_acct_mgmt (pamh, 0); } if (NULL != pamh) { (void) pam_end (pamh, retval); } if (PAM_SUCCESS != retval) { fprintf (stderr, _("%s: PAM authentication failed\n"), Prog); exit (1); } #endif /* USE_PAM */ #endif /* ACCT_TOOLS_SETUID */ #ifdef SHADOWGRP is_shadow_grp = sgr_file_present (); #endif { struct group *grp; /* * Start with a quick check to see if the group exists. */ grp = getgrnam (group_name); /* local, no need for xgetgrnam */ if (NULL == grp) { fprintf (stderr, _("%s: group '%s' does not exist\n"), Prog, group_name); exit (E_NOTFOUND); } else { group_id = grp->gr_gid; } } #ifdef USE_NIS /* * Now make sure it isn't an NIS group. */ if (__isgrNIS ()) { char *nis_domain; char *nis_master; fprintf (stderr, _("%s: group %s is a NIS group\n"), Prog, group_name); if (!yp_get_default_domain (&nis_domain) && !yp_master (nis_domain, "group.byname", &nis_master)) { fprintf (stderr, _("%s: %s is the NIS master\n"), Prog, nis_master); } exit (E_NOTFOUND); } #endif if (gflg) { check_new_gid (); } if (nflg) { check_new_name (); } lock_files (); /* * Now if the group is not changed, it's our fault. * Make sure failures will be reported. */ prepare_failure_reports (); /* * Do the hard stuff - open the files, create the group entries, * then close and update the files. */ open_files (); grp_update (); close_files (); nscd_flush_cache ("group"); return E_SUCCESS; }