/* * process_flags - parse the command line options * * It will not return if an error is encountered. */ static void process_flags (int argc, char **argv) { /* * Parse the command line options. */ char *cp; int c; static struct option long_options[] = { {"force", no_argument, NULL, 'f'}, {"gid", required_argument, NULL, 'g'}, {"help", no_argument, NULL, 'h'}, {"key", required_argument, NULL, 'K'}, {"non-unique", no_argument, NULL, 'o'}, {"password", required_argument, NULL, 'p'}, {"system", no_argument, NULL, 'r'}, {"root", required_argument, NULL, 'R'}, {"prefix", required_argument, NULL, 'P'}, {NULL, 0, NULL, '\0'} }; while ((c = getopt_long (argc, argv, "fg:hK:op:rR:P:", long_options, NULL)) != -1) { switch (c) { 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 = true; break; case 'g': gflg = true; if ( (get_gid (optarg, &group_id) == 0) || (group_id == (gid_t)-1)) { fprintf (stderr, _("%s: invalid group ID '%s'\n"), Prog, optarg); exit (E_BAD_ARG); } break; case 'h': usage (E_SUCCESS); /*@notreached@*/break; case 'K': /* * override login.defs defaults (-K name=value) * example: -K GID_MIN=100 -K GID_MAX=499 * note: -K GID_MIN=10,GID_MAX=499 doesn't work yet */ cp = strchr (optarg, '='); if (NULL == cp) { fprintf (stderr, _("%s: -K requires KEY=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 'o': oflg = true; break; case 'p': pflg = true; group_passwd = optarg; break; case 'r': rflg = true; break; case 'R': /* no-op, handled in process_root_flag () */ break; case 'P': /* no-op, handled in process_prefix_flag () */ break; default: usage (E_USAGE); } } /* * Check the flags consistency */ if (optind != argc - 1) { usage (E_USAGE); } group_name = argv[optind]; check_flags (); }
static void def_load (void) { int i; FILE *fp; char buf[1024], *name, *value, *s; /* * Open the configuration definitions file. */ fp = fopen (def_fname, "r"); if (NULL == fp) { int err = errno; SYSLOG ((LOG_CRIT, "cannot open login definitions %s [%s]", def_fname, strerror (err))); exit (EXIT_FAILURE); } /* * Set the initialized flag. * (do it early to prevent recursion in putdef_str()) */ def_loaded = true; /* * Go through all of the lines in the file. */ while (fgets (buf, (int) sizeof (buf), fp) != NULL) { /* * Trim trailing whitespace. */ for (i = (int) strlen (buf) - 1; i >= 0; --i) { if (!isspace (buf[i])) { break; } } i++; buf[i] = '\0'; /* * Break the line into two fields. */ name = buf + strspn (buf, " \t"); /* first nonwhite */ if (*name == '\0' || *name == '#') continue; /* comment or empty */ s = name + strcspn (name, " \t"); /* end of field */ if (*s == '\0') continue; /* only 1 field?? */ *s++ = '\0'; value = s + strspn (s, " \"\t"); /* next nonwhite */ *(value + strcspn (value, "\"")) = '\0'; /* * Store the value in def_table. * * Ignore failures to load the login.defs file. * The error was already reported to the user and to * syslog. The tools will just use their default values. */ (void)putdef_str (name, value); } if (ferror (fp) != 0) { int err = errno; SYSLOG ((LOG_CRIT, "cannot read login definitions %s [%s]", def_fname, strerror (err))); exit (EXIT_FAILURE); } (void) fclose (fp); }
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 (); }