X-Git-Url: https://git.cameronkatri.com/pw-darwin.git/blobdiff_plain/ed070f3fb430bf14b9fae10c25312f6dc4235aa6..a8e235f6926f727fd30a1fc881bda8f39c16ac1b:/pw/pw.c diff --git a/pw/pw.c b/pw/pw.c index 991019d..5ad2511 100644 --- a/pw/pw.c +++ b/pw/pw.c @@ -99,9 +99,11 @@ main(int argc, char *argv[]) int ch; int mode = -1; int which = -1; + long id = -1; char *config = NULL; struct stat st; - char arg; + const char *errstr; + char arg, *name; bool relocated, nis; static const char *opts[W_NUM][M_NUM] = @@ -124,15 +126,20 @@ main(int argc, char *argv[]) } }; - static int (*funcs[W_NUM]) (int _mode, struct cargs * _args) = + static int (*funcs[W_NUM]) (int _mode, char *_name, long _id, + struct cargs * _args) = { /* Request handlers */ pw_user, pw_group }; + name = NULL; relocated = nis = false; - conf.rootdir[0] = '\0'; + memset(&conf, 0, sizeof(conf)); + strlcpy(conf.rootdir, "/", sizeof(conf.rootdir)); strlcpy(conf.etcpath, _PATH_PWD, sizeof(conf.etcpath)); + conf.fd = -1; + conf.checkduplicate = true; LIST_INIT(&arglist); @@ -190,9 +197,15 @@ main(int argc, char *argv[]) mode = tmp % M_NUM; } else if (strcmp(argv[1], "help") == 0 && argv[2] == NULL) cmdhelp(mode, which); - else if (which != -1 && mode != -1) - addarg(&arglist, 'n', argv[1]); - else + else if (which != -1 && mode != -1) { + if (strspn(argv[1], "0123456789") == strlen(argv[1])) { + id = strtonum(argv[1], 0, LONG_MAX, &errstr); + if (errstr != NULL) + errx(EX_USAGE, "Bad id '%s': %s", + argv[1], errstr); + } else + name = argv[1]; + } else errx(EX_USAGE, "unknown keyword `%s'", argv[1]); ++argv; --argc; @@ -204,6 +217,10 @@ main(int argc, char *argv[]) if (mode == -1 || which == -1) cmdhelp(mode, which); + conf.rootfd = open(conf.rootdir, O_DIRECTORY|O_CLOEXEC); + if (conf.rootfd == -1) + errx(EXIT_FAILURE, "Unable to open '%s'", conf.rootdir); + conf.which = which; /* * We know which mode we're in and what we're about to do, so now * let's dispatch the remaining command line args in a genric way. @@ -215,12 +232,108 @@ main(int argc, char *argv[]) case '?': errx(EX_USAGE, "unknown switch"); break; + case '7': + conf.v7 = true; + break; case 'C': - config = optarg; + conf.config = optarg; + config = conf.config; + break; + case 'F': + conf.force = true; + break; + case 'N': + conf.dryrun = true; + break; + case 'l': + if (strlen(optarg) >= MAXLOGNAME) + errx(EX_USAGE, "new name too long: %s", optarg); + conf.newname = optarg; + break; + case 'P': + conf.pretty = true; break; case 'Y': nis = true; break; + case 'a': + conf.all = true; + break; + case 'c': + conf.gecos = pw_checkname(optarg, 1); + break; + case 'g': + if (which == 0) { /* for user* */ + addarg(&arglist, 'g', optarg); + break; + } + if (strspn(optarg, "0123456789") != strlen(optarg)) + errx(EX_USAGE, "-g expects a number"); + id = strtonum(optarg, 0, LONG_MAX, &errstr); + if (errstr != NULL) + errx(EX_USAGE, "Bad id '%s': %s", optarg, + errstr); + break; + case 'u': + if (strspn(optarg, "0123456789,") != strlen(optarg)) + errx(EX_USAGE, "-u expects a number"); + if (strchr(optarg, ',') != NULL) { + addarg(&arglist, 'u', optarg); + break; + } + id = strtonum(optarg, 0, LONG_MAX, &errstr); + if (errstr != NULL) + errx(EX_USAGE, "Bad id '%s': %s", optarg, + errstr); + break; + case 'n': + if (strspn(optarg, "0123456789") != strlen(optarg)) { + name = optarg; + break; + } + id = strtonum(optarg, 0, LONG_MAX, &errstr); + if (errstr != NULL) + errx(EX_USAGE, "Bad id '%s': %s", optarg, + errstr); + break; + case 'H': + if (conf.fd != -1) + errx(EX_USAGE, "'-h' and '-H' are mutually " + "exclusive options"); + conf.precrypted = true; + if (strspn(optarg, "0123456789") != strlen(optarg)) + errx(EX_USAGE, "'-H' expects a file descriptor"); + + conf.fd = strtonum(optarg, 0, INT_MAX, &errstr); + if (errstr != NULL) + errx(EX_USAGE, "Bad file descriptor '%s': %s", + optarg, errstr); + break; + case 'h': + if (conf.fd != -1) + errx(EX_USAGE, "'-h' and '-H' are mutually " + "exclusive options"); + + if (strcmp(optarg, "-") == 0) + conf.fd = '-'; + else if (strspn(optarg, "0123456789") == strlen(optarg)) { + conf.fd = strtonum(optarg, 0, INT_MAX, &errstr); + if (errstr != NULL) + errx(EX_USAGE, "'-h' expects a " + "file descriptor or '-'"); + } else + errx(EX_USAGE, "'-h' expects a file " + "descriptor or '-'"); + break; + case 'o': + conf.checkduplicate = false; + break; + case 'q': + conf.quiet = true; + break; + case 'r': + conf.deletehome = true; + break; default: addarg(&arglist, ch, optarg); break; @@ -228,17 +341,20 @@ main(int argc, char *argv[]) optarg = NULL; } + if (name != NULL && strlen(name) >= MAXLOGNAME) + errx(EX_USAGE, "name too long: %s", name); + /* * Must be root to attempt an update */ - if (geteuid() != 0 && mode != M_PRINT && mode != M_NEXT && getarg(&arglist, 'N')==NULL) + if (geteuid() != 0 && mode != M_PRINT && mode != M_NEXT && !conf.dryrun) errx(EX_NOPERM, "you must be root to run this program"); /* * We should immediately look for the -q 'quiet' switch so that we * don't bother with extraneous errors */ - if (getarg(&arglist, 'q') != NULL) + if (conf.quiet) freopen(_PATH_DEVNULL, "w", stderr); /* @@ -256,7 +372,7 @@ main(int argc, char *argv[]) */ conf.userconf = read_userconfig(config); - ch = funcs[which] (mode, &arglist); + ch = funcs[which] (mode, name, id, &arglist); /* * If everything went ok, and we've been asked to update @@ -471,7 +587,12 @@ cmdhelp(int mode, int which) struct carg * getarg(struct cargs * _args, int ch) { - struct carg *c = LIST_FIRST(_args); + struct carg *c; + + if (_args == NULL) + return (NULL); + + c = LIST_FIRST(_args); while (c != NULL && c->ch != ch) c = LIST_NEXT(c, list);