1d6f907dcSJoerg Wunsch /*- 2ad7cf975SJoerg Wunsch * Copyright (C) 1996 3ad7cf975SJoerg Wunsch * David L. Nugent. All rights reserved. 4d6f907dcSJoerg Wunsch * 5d6f907dcSJoerg Wunsch * Redistribution and use in source and binary forms, with or without 6d6f907dcSJoerg Wunsch * modification, are permitted provided that the following conditions 7d6f907dcSJoerg Wunsch * are met: 8d6f907dcSJoerg Wunsch * 1. Redistributions of source code must retain the above copyright 9ad7cf975SJoerg Wunsch * notice, this list of conditions and the following disclaimer. 10d6f907dcSJoerg Wunsch * 2. Redistributions in binary form must reproduce the above copyright 11d6f907dcSJoerg Wunsch * notice, this list of conditions and the following disclaimer in the 12d6f907dcSJoerg Wunsch * documentation and/or other materials provided with the distribution. 13d6f907dcSJoerg Wunsch * 14ad7cf975SJoerg Wunsch * THIS SOFTWARE IS PROVIDED BY DAVID L. NUGENT AND CONTRIBUTORS ``AS IS'' AND 15d6f907dcSJoerg Wunsch * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16d6f907dcSJoerg Wunsch * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17ad7cf975SJoerg Wunsch * ARE DISCLAIMED. IN NO EVENT SHALL DAVID L. NUGENT OR CONTRIBUTORS BE LIABLE 18d6f907dcSJoerg Wunsch * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19d6f907dcSJoerg Wunsch * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20d6f907dcSJoerg Wunsch * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21d6f907dcSJoerg Wunsch * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22d6f907dcSJoerg Wunsch * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23d6f907dcSJoerg Wunsch * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24d6f907dcSJoerg Wunsch * SUCH DAMAGE. 25d6f907dcSJoerg Wunsch */ 26d6f907dcSJoerg Wunsch 271dcc6ec7SPhilippe Charnier #ifndef lint 281dcc6ec7SPhilippe Charnier static const char rcsid[] = 2997d92980SPeter Wemm "$FreeBSD$"; 301dcc6ec7SPhilippe Charnier #endif /* not lint */ 311dcc6ec7SPhilippe Charnier 321dcc6ec7SPhilippe Charnier #include <err.h> 335e91a8acSNate Williams #include <fcntl.h> 34e7161f36SAndrey A. Chernov #include <locale.h> 35f1d684faSDavid Nugent #include <paths.h> 362cc63cd1SBaptiste Daroussin #include <stdbool.h> 37f1d684faSDavid Nugent #include <sys/wait.h> 385f12594aSDavid Nugent #include "pw.h" 39d6f907dcSJoerg Wunsch 40923dc0b2SDavid Nugent #if !defined(_PATH_YP) 41923dc0b2SDavid Nugent #define _PATH_YP "/var/yp/" 42923dc0b2SDavid Nugent #endif 432399cd14SDavid Nugent const char *Modes[] = { 442399cd14SDavid Nugent "add", "del", "mod", "show", "next", 452399cd14SDavid Nugent NULL}; 46d6f907dcSJoerg Wunsch const char *Which[] = {"user", "group", NULL}; 4748aee7f3SJoerg Wunsch static const char *Combo1[] = { 4848aee7f3SJoerg Wunsch "useradd", "userdel", "usermod", "usershow", "usernext", 492399cd14SDavid Nugent "lock", "unlock", 5048aee7f3SJoerg Wunsch "groupadd", "groupdel", "groupmod", "groupshow", "groupnext", 51d6f907dcSJoerg Wunsch NULL}; 5248aee7f3SJoerg Wunsch static const char *Combo2[] = { 5348aee7f3SJoerg Wunsch "adduser", "deluser", "moduser", "showuser", "nextuser", 542399cd14SDavid Nugent "lock", "unlock", 5548aee7f3SJoerg Wunsch "addgroup", "delgroup", "modgroup", "showgroup", "nextgroup", 56d6f907dcSJoerg Wunsch NULL}; 57d6f907dcSJoerg Wunsch 585f12594aSDavid Nugent struct pwf PWF = 595f12594aSDavid Nugent { 60ac72be28SBaptiste Daroussin PWF_REGULAR, 615f12594aSDavid Nugent setpwent, 625f12594aSDavid Nugent endpwent, 635f12594aSDavid Nugent getpwent, 645f12594aSDavid Nugent getpwuid, 655f12594aSDavid Nugent getpwnam, 665f12594aSDavid Nugent setgrent, 675f12594aSDavid Nugent endgrent, 685f12594aSDavid Nugent getgrent, 695f12594aSDavid Nugent getgrgid, 705f12594aSDavid Nugent getgrnam, 715f12594aSDavid Nugent 725f12594aSDavid Nugent }; 735f12594aSDavid Nugent struct pwf VPWF = 745f12594aSDavid Nugent { 75ac72be28SBaptiste Daroussin PWF_ALT, 765f12594aSDavid Nugent vsetpwent, 775f12594aSDavid Nugent vendpwent, 785f12594aSDavid Nugent vgetpwent, 795f12594aSDavid Nugent vgetpwuid, 805f12594aSDavid Nugent vgetpwnam, 815f12594aSDavid Nugent vsetgrent, 825f12594aSDavid Nugent vendgrent, 835f12594aSDavid Nugent vgetgrent, 845f12594aSDavid Nugent vgetgrgid, 855f12594aSDavid Nugent vgetgrnam, 865f12594aSDavid Nugent }; 875f12594aSDavid Nugent 882cc63cd1SBaptiste Daroussin struct pwconf conf; 892cc63cd1SBaptiste Daroussin 90d6f907dcSJoerg Wunsch static struct cargs arglist; 91d6f907dcSJoerg Wunsch 92d6f907dcSJoerg Wunsch static int getindex(const char *words[], const char *word); 93d6f907dcSJoerg Wunsch static void cmdhelp(int mode, int which); 94d6f907dcSJoerg Wunsch 95d6f907dcSJoerg Wunsch 96d6f907dcSJoerg Wunsch int 97d6f907dcSJoerg Wunsch main(int argc, char *argv[]) 98d6f907dcSJoerg Wunsch { 99d6f907dcSJoerg Wunsch int ch; 100d6f907dcSJoerg Wunsch int mode = -1; 101d6f907dcSJoerg Wunsch int which = -1; 102a9237189SBaptiste Daroussin long id = -1; 1035f12594aSDavid Nugent char *config = NULL; 10490edef4fSBaptiste Daroussin struct stat st; 105a9237189SBaptiste Daroussin const char *errstr; 106a9237189SBaptiste Daroussin char arg, *name; 10782a3c75aSBaptiste Daroussin bool relocated, nis; 108d6f907dcSJoerg Wunsch 109d6f907dcSJoerg Wunsch static const char *opts[W_NUM][M_NUM] = 110d6f907dcSJoerg Wunsch { 11148aee7f3SJoerg Wunsch { /* user */ 112ac72be28SBaptiste Daroussin "R:V:C:qn:u:c:d:e:p:g:G:mM:k:s:oL:i:w:h:H:Db:NPy:Y", 113ac72be28SBaptiste Daroussin "R:V:C:qn:u:rY", 114ac72be28SBaptiste Daroussin "R:V:C:qn:u:c:d:e:p:g:G:mM:l:k:s:w:L:h:H:FNPY", 115ac72be28SBaptiste Daroussin "R:V:C:qn:u:FPa7", 116*3bfc59e8SBaptiste Daroussin "R:V:C:q", 117ac72be28SBaptiste Daroussin "R:V:C:q", 118ac72be28SBaptiste Daroussin "R:V:C:q" 11948aee7f3SJoerg Wunsch }, 12048aee7f3SJoerg Wunsch { /* grp */ 121ac72be28SBaptiste Daroussin "R:V:C:qn:g:h:H:M:opNPY", 122ac72be28SBaptiste Daroussin "R:V:C:qn:g:Y", 123ac72be28SBaptiste Daroussin "R:V:C:qn:d:g:l:h:H:FM:m:NPY", 124ac72be28SBaptiste Daroussin "R:V:C:qn:g:FPa", 125*3bfc59e8SBaptiste Daroussin "R:V:C:q" 12648aee7f3SJoerg Wunsch } 127d6f907dcSJoerg Wunsch }; 128d6f907dcSJoerg Wunsch 129a9237189SBaptiste Daroussin static int (*funcs[W_NUM]) (int _mode, char *_name, long _id, 130a9237189SBaptiste Daroussin struct cargs * _args) = 131d6f907dcSJoerg Wunsch { /* Request handlers */ 132d6f907dcSJoerg Wunsch pw_user, 133d6f907dcSJoerg Wunsch pw_group 134d6f907dcSJoerg Wunsch }; 135d6f907dcSJoerg Wunsch 136a9237189SBaptiste Daroussin name = NULL; 13782a3c75aSBaptiste Daroussin relocated = nis = false; 138bbe09b2eSBaptiste Daroussin memset(&conf, 0, sizeof(conf)); 1392cc63cd1SBaptiste Daroussin strlcpy(conf.etcpath, _PATH_PWD, sizeof(conf.etcpath)); 1402cc63cd1SBaptiste Daroussin 141d6f907dcSJoerg Wunsch LIST_INIT(&arglist); 142d6f907dcSJoerg Wunsch 14339610c72SAndrey A. Chernov (void)setlocale(LC_ALL, ""); 144e7161f36SAndrey A. Chernov 145d6f907dcSJoerg Wunsch /* 146d6f907dcSJoerg Wunsch * Break off the first couple of words to determine what exactly 147d6f907dcSJoerg Wunsch * we're being asked to do 148d6f907dcSJoerg Wunsch */ 1495f12594aSDavid Nugent while (argc > 1) { 150d6f907dcSJoerg Wunsch int tmp; 151d6f907dcSJoerg Wunsch 1525f12594aSDavid Nugent if (*argv[1] == '-') { 1535f12594aSDavid Nugent /* 1545f12594aSDavid Nugent * Special case, allow pw -V<dir> <operation> [args] for scripts etc. 1555f12594aSDavid Nugent */ 156ac72be28SBaptiste Daroussin arg = argv[1][1]; 157ac72be28SBaptiste Daroussin if (arg == 'V' || arg == 'R') { 1582cc63cd1SBaptiste Daroussin if (relocated) 1592cc63cd1SBaptiste Daroussin errx(EXIT_FAILURE, "Both '-R' and '-V' " 1602cc63cd1SBaptiste Daroussin "specified, only one accepted"); 1612cc63cd1SBaptiste Daroussin relocated = true; 1625f12594aSDavid Nugent optarg = &argv[1][2]; 1635f12594aSDavid Nugent if (*optarg == '\0') { 16490edef4fSBaptiste Daroussin if (stat(argv[2], &st) != 0) 16590edef4fSBaptiste Daroussin errx(EX_OSFILE, \ 16690edef4fSBaptiste Daroussin "no such directory `%s'", 16790edef4fSBaptiste Daroussin argv[2]); 16890edef4fSBaptiste Daroussin if (!S_ISDIR(st.st_mode)) 16990edef4fSBaptiste Daroussin errx(EX_OSFILE, "`%s' not a " 17090edef4fSBaptiste Daroussin "directory", argv[2]); 1715f12594aSDavid Nugent optarg = argv[2]; 1725f12594aSDavid Nugent ++argv; 1735f12594aSDavid Nugent --argc; 1745f12594aSDavid Nugent } 1752cc63cd1SBaptiste Daroussin memcpy(&PWF, &VPWF, sizeof PWF); 1762cc63cd1SBaptiste Daroussin if (arg == 'R') { 1772cc63cd1SBaptiste Daroussin strlcpy(conf.rootdir, optarg, 1782cc63cd1SBaptiste Daroussin sizeof(conf.rootdir)); 1792cc63cd1SBaptiste Daroussin PWF._altdir = PWF_ROOTDIR; 1802cc63cd1SBaptiste Daroussin } 1812cc63cd1SBaptiste Daroussin snprintf(conf.etcpath, sizeof(conf.etcpath), 1822cc63cd1SBaptiste Daroussin "%s%s", optarg, arg == 'R' ? "/etc" : ""); 183e3921b27SDavid Nugent } else 1845f12594aSDavid Nugent break; 1855f12594aSDavid Nugent } 186c4e667b9SDavid Nugent else if (mode == -1 && (tmp = getindex(Modes, argv[1])) != -1) 187d6f907dcSJoerg Wunsch mode = tmp; 188c4e667b9SDavid Nugent else if (which == -1 && (tmp = getindex(Which, argv[1])) != -1) 189d6f907dcSJoerg Wunsch which = tmp; 190c4e667b9SDavid Nugent else if ((mode == -1 && which == -1) && 191c4e667b9SDavid Nugent ((tmp = getindex(Combo1, argv[1])) != -1 || 192c4e667b9SDavid Nugent (tmp = getindex(Combo2, argv[1])) != -1)) { 193d6f907dcSJoerg Wunsch which = tmp / M_NUM; 194d6f907dcSJoerg Wunsch mode = tmp % M_NUM; 195c4e667b9SDavid Nugent } else if (strcmp(argv[1], "help") == 0 && argv[2] == NULL) 196d6f907dcSJoerg Wunsch cmdhelp(mode, which); 197a9237189SBaptiste Daroussin else if (which != -1 && mode != -1) { 198a9237189SBaptiste Daroussin if (strspn(argv[1], "0123456789") == strlen(argv[1])) { 199a9237189SBaptiste Daroussin id = strtonum(argv[1], 0, LONG_MAX, &errstr); 200a9237189SBaptiste Daroussin if (errstr != NULL) 201a9237189SBaptiste Daroussin errx(EX_USAGE, "Bad id '%s': %s", 202a9237189SBaptiste Daroussin argv[1], errstr); 203a9237189SBaptiste Daroussin } else 204a9237189SBaptiste Daroussin name = argv[1]; 205a9237189SBaptiste Daroussin } else 2061dcc6ec7SPhilippe Charnier errx(EX_USAGE, "unknown keyword `%s'", argv[1]); 207d6f907dcSJoerg Wunsch ++argv; 208d6f907dcSJoerg Wunsch --argc; 209d6f907dcSJoerg Wunsch } 210d6f907dcSJoerg Wunsch 211d6f907dcSJoerg Wunsch /* 212d6f907dcSJoerg Wunsch * Bail out unless the user is specific! 213d6f907dcSJoerg Wunsch */ 214d6f907dcSJoerg Wunsch if (mode == -1 || which == -1) 215d6f907dcSJoerg Wunsch cmdhelp(mode, which); 216d6f907dcSJoerg Wunsch 217d6f907dcSJoerg Wunsch /* 218d6f907dcSJoerg Wunsch * We know which mode we're in and what we're about to do, so now 219d6f907dcSJoerg Wunsch * let's dispatch the remaining command line args in a genric way. 220d6f907dcSJoerg Wunsch */ 221d6f907dcSJoerg Wunsch optarg = NULL; 222d6f907dcSJoerg Wunsch 223d6f907dcSJoerg Wunsch while ((ch = getopt(argc, argv, opts[which][mode])) != -1) { 22482a3c75aSBaptiste Daroussin switch (ch) { 22582a3c75aSBaptiste Daroussin case '?': 226923dc0b2SDavid Nugent errx(EX_USAGE, "unknown switch"); 22782a3c75aSBaptiste Daroussin break; 228c86f7ad5SBaptiste Daroussin case '7': 229c86f7ad5SBaptiste Daroussin conf.v7 = true; 230c86f7ad5SBaptiste Daroussin break; 23182a3c75aSBaptiste Daroussin case 'C': 232a68fbadbSBaptiste Daroussin conf.config = optarg; 233a68fbadbSBaptiste Daroussin config = conf.config; 23482a3c75aSBaptiste Daroussin break; 235363cefdbSBaptiste Daroussin case 'N': 236363cefdbSBaptiste Daroussin conf.dryrun = true; 237363cefdbSBaptiste Daroussin break; 238bae068d2SBaptiste Daroussin case 'l': 239bae068d2SBaptiste Daroussin if (strlen(optarg) >= MAXLOGNAME) 240bae068d2SBaptiste Daroussin errx(EX_USAGE, "new name too long: %s", optarg); 241bae068d2SBaptiste Daroussin conf.newname = optarg; 242bae068d2SBaptiste Daroussin break; 2432166b4d1SBaptiste Daroussin case 'P': 2442166b4d1SBaptiste Daroussin conf.pretty = true; 2452166b4d1SBaptiste Daroussin break; 24682a3c75aSBaptiste Daroussin case 'Y': 24782a3c75aSBaptiste Daroussin nis = true; 24882a3c75aSBaptiste Daroussin break; 249a9237189SBaptiste Daroussin case 'g': 250a9237189SBaptiste Daroussin if (which == 0) { /* for user* */ 251a9237189SBaptiste Daroussin addarg(&arglist, 'g', optarg); 252a9237189SBaptiste Daroussin break; 253a9237189SBaptiste Daroussin } 254a9237189SBaptiste Daroussin if (strspn(optarg, "0123456789") != strlen(optarg)) 2551718a38fSBaptiste Daroussin errx(EX_USAGE, "-g expects a number"); 2561718a38fSBaptiste Daroussin id = strtonum(optarg, 0, LONG_MAX, &errstr); 2571718a38fSBaptiste Daroussin if (errstr != NULL) 2581718a38fSBaptiste Daroussin errx(EX_USAGE, "Bad id '%s': %s", optarg, 2591718a38fSBaptiste Daroussin errstr); 2601718a38fSBaptiste Daroussin break; 2611718a38fSBaptiste Daroussin case 'u': 2621718a38fSBaptiste Daroussin if (strspn(optarg, "0123456789,") != strlen(optarg)) 2631718a38fSBaptiste Daroussin errx(EX_USAGE, "-u expects a number"); 2641718a38fSBaptiste Daroussin if (strchr(optarg, ',') != NULL) { 2651718a38fSBaptiste Daroussin addarg(&arglist, 'u', optarg); 2661718a38fSBaptiste Daroussin break; 2671718a38fSBaptiste Daroussin } 268a9237189SBaptiste Daroussin id = strtonum(optarg, 0, LONG_MAX, &errstr); 269a9237189SBaptiste Daroussin if (errstr != NULL) 270a9237189SBaptiste Daroussin errx(EX_USAGE, "Bad id '%s': %s", optarg, 271a9237189SBaptiste Daroussin errstr); 272a9237189SBaptiste Daroussin break; 273a9237189SBaptiste Daroussin case 'n': 274a9237189SBaptiste Daroussin if (strspn(optarg, "0123456789") != strlen(optarg)) { 275a9237189SBaptiste Daroussin name = optarg; 276a9237189SBaptiste Daroussin break; 277a9237189SBaptiste Daroussin } 278a9237189SBaptiste Daroussin id = strtonum(optarg, 0, LONG_MAX, &errstr); 279a9237189SBaptiste Daroussin if (errstr != NULL) 280a9237189SBaptiste Daroussin errx(EX_USAGE, "Bad id '%s': %s", optarg, 281a9237189SBaptiste Daroussin errstr); 28291860967SBaptiste Daroussin break; 28391860967SBaptiste Daroussin case 'o': 28491860967SBaptiste Daroussin conf.checkduplicate = true; 28591860967SBaptiste Daroussin break; 28682a3c75aSBaptiste Daroussin default: 287d6f907dcSJoerg Wunsch addarg(&arglist, ch, optarg); 28882a3c75aSBaptiste Daroussin break; 28982a3c75aSBaptiste Daroussin } 290d6f907dcSJoerg Wunsch optarg = NULL; 291d6f907dcSJoerg Wunsch } 292d6f907dcSJoerg Wunsch 293a9237189SBaptiste Daroussin if (name != NULL && strlen(name) >= MAXLOGNAME) 294a9237189SBaptiste Daroussin errx(EX_USAGE, "name too long: %s", name); 295a9237189SBaptiste Daroussin 296d6f907dcSJoerg Wunsch /* 29748aee7f3SJoerg Wunsch * Must be root to attempt an update 29848aee7f3SJoerg Wunsch */ 299363cefdbSBaptiste Daroussin if (geteuid() != 0 && mode != M_PRINT && mode != M_NEXT && !conf.dryrun) 3001dcc6ec7SPhilippe Charnier errx(EX_NOPERM, "you must be root to run this program"); 30148aee7f3SJoerg Wunsch 30248aee7f3SJoerg Wunsch /* 303d6f907dcSJoerg Wunsch * We should immediately look for the -q 'quiet' switch so that we 304d6f907dcSJoerg Wunsch * don't bother with extraneous errors 305d6f907dcSJoerg Wunsch */ 306d6f907dcSJoerg Wunsch if (getarg(&arglist, 'q') != NULL) 3071a37aa56SDavid E. O'Brien freopen(_PATH_DEVNULL, "w", stderr); 308d6f907dcSJoerg Wunsch 309d6f907dcSJoerg Wunsch /* 3105f12594aSDavid Nugent * Set our base working path if not overridden 3115f12594aSDavid Nugent */ 3125f12594aSDavid Nugent 3135f12594aSDavid Nugent if (config == NULL) { /* Only override config location if -C not specified */ 3142cc63cd1SBaptiste Daroussin asprintf(&config, "%s/pw.conf", conf.etcpath); 31519741915SBaptiste Daroussin if (config == NULL) 31619741915SBaptiste Daroussin errx(EX_OSERR, "out of memory"); 3175f12594aSDavid Nugent } 3185f12594aSDavid Nugent 3195f12594aSDavid Nugent /* 320d6f907dcSJoerg Wunsch * Now, let's do the common initialisation 321d6f907dcSJoerg Wunsch */ 3222cc63cd1SBaptiste Daroussin conf.userconf = read_userconfig(config); 3235e91a8acSNate Williams 324a9237189SBaptiste Daroussin ch = funcs[which] (mode, name, id, &arglist); 325f1d684faSDavid Nugent 326f1d684faSDavid Nugent /* 327f1d684faSDavid Nugent * If everything went ok, and we've been asked to update 328f1d684faSDavid Nugent * the NIS maps, then do it now 329f1d684faSDavid Nugent */ 33082a3c75aSBaptiste Daroussin if (ch == EXIT_SUCCESS && nis) { 331f1d684faSDavid Nugent pid_t pid; 332f1d684faSDavid Nugent 333f1d684faSDavid Nugent fflush(NULL); 334f1d684faSDavid Nugent if (chdir(_PATH_YP) == -1) 3351dcc6ec7SPhilippe Charnier warn("chdir(" _PATH_YP ")"); 336f1d684faSDavid Nugent else if ((pid = fork()) == -1) 3371dcc6ec7SPhilippe Charnier warn("fork()"); 338f1d684faSDavid Nugent else if (pid == 0) { 339f1d684faSDavid Nugent /* Is make anywhere else? */ 3407bc6d015SBrian Somers execlp("/usr/bin/make", "make", (char *)NULL); 341f1d684faSDavid Nugent _exit(1); 342f1d684faSDavid Nugent } else { 343f1d684faSDavid Nugent int i; 344f1d684faSDavid Nugent waitpid(pid, &i, 0); 345f1d684faSDavid Nugent if ((i = WEXITSTATUS(i)) != 0) 3461dcc6ec7SPhilippe Charnier errx(ch, "make exited with status %d", i); 347f1d684faSDavid Nugent else 3482cc63cd1SBaptiste Daroussin pw_log(conf.userconf, mode, which, "NIS maps updated"); 349f1d684faSDavid Nugent } 350f1d684faSDavid Nugent } 351f1d684faSDavid Nugent return ch; 352d6f907dcSJoerg Wunsch } 353d6f907dcSJoerg Wunsch 3545e91a8acSNate Williams 355d6f907dcSJoerg Wunsch static int 356d6f907dcSJoerg Wunsch getindex(const char *words[], const char *word) 357d6f907dcSJoerg Wunsch { 358d6f907dcSJoerg Wunsch int i = 0; 359d6f907dcSJoerg Wunsch 360d6f907dcSJoerg Wunsch while (words[i]) { 361d6f907dcSJoerg Wunsch if (strcmp(words[i], word) == 0) 362d6f907dcSJoerg Wunsch return i; 363d6f907dcSJoerg Wunsch i++; 364d6f907dcSJoerg Wunsch } 365d6f907dcSJoerg Wunsch return -1; 366d6f907dcSJoerg Wunsch } 367d6f907dcSJoerg Wunsch 368d6f907dcSJoerg Wunsch 369d6f907dcSJoerg Wunsch /* 370d6f907dcSJoerg Wunsch * This is probably an overkill for a cmdline help system, but it reflects 371d6f907dcSJoerg Wunsch * the complexity of the command line. 372d6f907dcSJoerg Wunsch */ 373d6f907dcSJoerg Wunsch 374d6f907dcSJoerg Wunsch static void 375d6f907dcSJoerg Wunsch cmdhelp(int mode, int which) 376d6f907dcSJoerg Wunsch { 377d6f907dcSJoerg Wunsch if (which == -1) 3782399cd14SDavid Nugent fprintf(stderr, "usage:\n pw [user|group|lock|unlock] [add|del|mod|show|next] [help|switches/values]\n"); 379d6f907dcSJoerg Wunsch else if (mode == -1) 3802399cd14SDavid Nugent fprintf(stderr, "usage:\n pw %s [add|del|mod|show|next] [help|switches/values]\n", Which[which]); 381d6f907dcSJoerg Wunsch else { 382d6f907dcSJoerg Wunsch 383d6f907dcSJoerg Wunsch /* 384d6f907dcSJoerg Wunsch * We need to give mode specific help 385d6f907dcSJoerg Wunsch */ 386d6f907dcSJoerg Wunsch static const char *help[W_NUM][M_NUM] = 387d6f907dcSJoerg Wunsch { 388d6f907dcSJoerg Wunsch { 3891dcc6ec7SPhilippe Charnier "usage: pw useradd [name] [switches]\n" 3905f12594aSDavid Nugent "\t-V etcdir alternate /etc location\n" 391ac72be28SBaptiste Daroussin "\t-R rootir alternate root directory\n" 392d6f907dcSJoerg Wunsch "\t-C config configuration file\n" 393d6f907dcSJoerg Wunsch "\t-q quiet operation\n" 394d6f907dcSJoerg Wunsch " Adding users:\n" 395d6f907dcSJoerg Wunsch "\t-n name login name\n" 396d6f907dcSJoerg Wunsch "\t-u uid user id\n" 397d6f907dcSJoerg Wunsch "\t-c comment user name/comment\n" 398d6f907dcSJoerg Wunsch "\t-d directory home directory\n" 399d6f907dcSJoerg Wunsch "\t-e date account expiry date\n" 400d6f907dcSJoerg Wunsch "\t-p date password expiry date\n" 401d6f907dcSJoerg Wunsch "\t-g grp initial group\n" 402d6f907dcSJoerg Wunsch "\t-G grp1,grp2 additional groups\n" 403d6f907dcSJoerg Wunsch "\t-m [ -k dir ] create and set up home\n" 4041dd634b0SLukas Ertl "\t-M mode home directory permissions\n" 405d6f907dcSJoerg Wunsch "\t-s shell name of login shell\n" 406d6f907dcSJoerg Wunsch "\t-o duplicate uid ok\n" 407d6f907dcSJoerg Wunsch "\t-L class user class\n" 408d6f907dcSJoerg Wunsch "\t-h fd read password on fd\n" 40987d6b5caSIan Dowse "\t-H fd read encrypted password on fd\n" 410f1d684faSDavid Nugent "\t-Y update NIS maps\n" 41148aee7f3SJoerg Wunsch "\t-N no update\n" 412d6f907dcSJoerg Wunsch " Setting defaults:\n" 4135f12594aSDavid Nugent "\t-V etcdir alternate /etc location\n" 414ac72be28SBaptiste Daroussin "\t-R rootir alternate root directory\n" 415d6f907dcSJoerg Wunsch "\t-D set user defaults\n" 416d6f907dcSJoerg Wunsch "\t-b dir default home root dir\n" 417d6f907dcSJoerg Wunsch "\t-e period default expiry period\n" 418d6f907dcSJoerg Wunsch "\t-p period default password change period\n" 419d6f907dcSJoerg Wunsch "\t-g group default group\n" 420d6f907dcSJoerg Wunsch "\t-G grp1,grp2 additional groups\n" 421d6f907dcSJoerg Wunsch "\t-L class default user class\n" 422d6f907dcSJoerg Wunsch "\t-k dir default home skeleton\n" 42385204142SLukas Ertl "\t-M mode home directory permissions\n" 424d6f907dcSJoerg Wunsch "\t-u min,max set min,max uids\n" 425d6f907dcSJoerg Wunsch "\t-i min,max set min,max gids\n" 426d6f907dcSJoerg Wunsch "\t-w method set default password method\n" 427f1d684faSDavid Nugent "\t-s shell default shell\n" 428f1d684faSDavid Nugent "\t-y path set NIS passwd file path\n", 4291dcc6ec7SPhilippe Charnier "usage: pw userdel [uid|name] [switches]\n" 4305f12594aSDavid Nugent "\t-V etcdir alternate /etc location\n" 431ac72be28SBaptiste Daroussin "\t-R rootir alternate root directory\n" 432d6f907dcSJoerg Wunsch "\t-n name login name\n" 433d6f907dcSJoerg Wunsch "\t-u uid user id\n" 434f1d684faSDavid Nugent "\t-Y update NIS maps\n" 435d6f907dcSJoerg Wunsch "\t-r remove home & contents\n", 4361dcc6ec7SPhilippe Charnier "usage: pw usermod [uid|name] [switches]\n" 4375f12594aSDavid Nugent "\t-V etcdir alternate /etc location\n" 438ac72be28SBaptiste Daroussin "\t-R rootir alternate root directory\n" 439d6f907dcSJoerg Wunsch "\t-C config configuration file\n" 440d6f907dcSJoerg Wunsch "\t-q quiet operation\n" 441d6f907dcSJoerg Wunsch "\t-F force add if no user\n" 442d6f907dcSJoerg Wunsch "\t-n name login name\n" 443d6f907dcSJoerg Wunsch "\t-u uid user id\n" 444d6f907dcSJoerg Wunsch "\t-c comment user name/comment\n" 445d6f907dcSJoerg Wunsch "\t-d directory home directory\n" 446d6f907dcSJoerg Wunsch "\t-e date account expiry date\n" 447d6f907dcSJoerg Wunsch "\t-p date password expiry date\n" 448d6f907dcSJoerg Wunsch "\t-g grp initial group\n" 449d6f907dcSJoerg Wunsch "\t-G grp1,grp2 additional groups\n" 450d6f907dcSJoerg Wunsch "\t-l name new login name\n" 451d6f907dcSJoerg Wunsch "\t-L class user class\n" 452d6f907dcSJoerg Wunsch "\t-m [ -k dir ] create and set up home\n" 4531dd634b0SLukas Ertl "\t-M mode home directory permissions\n" 454d6f907dcSJoerg Wunsch "\t-s shell name of login shell\n" 45548aee7f3SJoerg Wunsch "\t-w method set new password using method\n" 45648aee7f3SJoerg Wunsch "\t-h fd read password on fd\n" 45787d6b5caSIan Dowse "\t-H fd read encrypted password on fd\n" 458f1d684faSDavid Nugent "\t-Y update NIS maps\n" 45948aee7f3SJoerg Wunsch "\t-N no update\n", 4601dcc6ec7SPhilippe Charnier "usage: pw usershow [uid|name] [switches]\n" 4615f12594aSDavid Nugent "\t-V etcdir alternate /etc location\n" 462ac72be28SBaptiste Daroussin "\t-R rootir alternate root directory\n" 463d6f907dcSJoerg Wunsch "\t-n name login name\n" 464d6f907dcSJoerg Wunsch "\t-u uid user id\n" 465d6f907dcSJoerg Wunsch "\t-F force print\n" 46648aee7f3SJoerg Wunsch "\t-P prettier format\n" 467f3522722SDavid Nugent "\t-a print all users\n" 468f3522722SDavid Nugent "\t-7 print in v7 format\n", 4691dcc6ec7SPhilippe Charnier "usage: pw usernext [switches]\n" 4705f12594aSDavid Nugent "\t-V etcdir alternate /etc location\n" 471ac72be28SBaptiste Daroussin "\t-R rootir alternate root directory\n" 472*3bfc59e8SBaptiste Daroussin "\t-C config configuration file\n" 473*3bfc59e8SBaptiste Daroussin "\t-q quiet operation\n", 474ed6fd55aSDima Dorfman "usage pw: lock [switches]\n" 475ed6fd55aSDima Dorfman "\t-V etcdir alternate /etc locations\n" 476ed6fd55aSDima Dorfman "\t-C config configuration file\n" 477ed6fd55aSDima Dorfman "\t-q quiet operation\n", 478ed6fd55aSDima Dorfman "usage pw: unlock [switches]\n" 479ed6fd55aSDima Dorfman "\t-V etcdir alternate /etc locations\n" 480ed6fd55aSDima Dorfman "\t-C config configuration file\n" 481ed6fd55aSDima Dorfman "\t-q quiet operation\n" 482d6f907dcSJoerg Wunsch }, 483d6f907dcSJoerg Wunsch { 4841dcc6ec7SPhilippe Charnier "usage: pw groupadd [group|gid] [switches]\n" 4855f12594aSDavid Nugent "\t-V etcdir alternate /etc location\n" 486ac72be28SBaptiste Daroussin "\t-R rootir alternate root directory\n" 487d6f907dcSJoerg Wunsch "\t-C config configuration file\n" 488d6f907dcSJoerg Wunsch "\t-q quiet operation\n" 489d6f907dcSJoerg Wunsch "\t-n group group name\n" 490d6f907dcSJoerg Wunsch "\t-g gid group id\n" 49148aee7f3SJoerg Wunsch "\t-M usr1,usr2 add users as group members\n" 49248aee7f3SJoerg Wunsch "\t-o duplicate gid ok\n" 493f1d684faSDavid Nugent "\t-Y update NIS maps\n" 49448aee7f3SJoerg Wunsch "\t-N no update\n", 4951dcc6ec7SPhilippe Charnier "usage: pw groupdel [group|gid] [switches]\n" 4965f12594aSDavid Nugent "\t-V etcdir alternate /etc location\n" 497ac72be28SBaptiste Daroussin "\t-R rootir alternate root directory\n" 498d6f907dcSJoerg Wunsch "\t-n name group name\n" 499f1d684faSDavid Nugent "\t-g gid group id\n" 500f1d684faSDavid Nugent "\t-Y update NIS maps\n", 5011dcc6ec7SPhilippe Charnier "usage: pw groupmod [group|gid] [switches]\n" 5025f12594aSDavid Nugent "\t-V etcdir alternate /etc location\n" 503ac72be28SBaptiste Daroussin "\t-R rootir alternate root directory\n" 504d6f907dcSJoerg Wunsch "\t-C config configuration file\n" 505d6f907dcSJoerg Wunsch "\t-q quiet operation\n" 506d6f907dcSJoerg Wunsch "\t-F force add if not exists\n" 507d6f907dcSJoerg Wunsch "\t-n name group name\n" 508d6f907dcSJoerg Wunsch "\t-g gid group id\n" 50948aee7f3SJoerg Wunsch "\t-M usr1,usr2 replaces users as group members\n" 51048aee7f3SJoerg Wunsch "\t-m usr1,usr2 add users as group members\n" 511bc991a6dSSean Farley "\t-d usr1,usr2 delete users as group members\n" 51248aee7f3SJoerg Wunsch "\t-l name new group name\n" 513f1d684faSDavid Nugent "\t-Y update NIS maps\n" 51448aee7f3SJoerg Wunsch "\t-N no update\n", 5151dcc6ec7SPhilippe Charnier "usage: pw groupshow [group|gid] [switches]\n" 5165f12594aSDavid Nugent "\t-V etcdir alternate /etc location\n" 517ac72be28SBaptiste Daroussin "\t-R rootir alternate root directory\n" 518d6f907dcSJoerg Wunsch "\t-n name group name\n" 519d6f907dcSJoerg Wunsch "\t-g gid group id\n" 520d6f907dcSJoerg Wunsch "\t-F force print\n" 52148aee7f3SJoerg Wunsch "\t-P prettier format\n" 52248aee7f3SJoerg Wunsch "\t-a print all accounting groups\n", 5231dcc6ec7SPhilippe Charnier "usage: pw groupnext [switches]\n" 5245f12594aSDavid Nugent "\t-V etcdir alternate /etc location\n" 525ac72be28SBaptiste Daroussin "\t-R rootir alternate root directory\n" 52648aee7f3SJoerg Wunsch "\t-C config configuration file\n" 527*3bfc59e8SBaptiste Daroussin "\t-q quiet operation\n" 528d6f907dcSJoerg Wunsch } 529d6f907dcSJoerg Wunsch }; 530d6f907dcSJoerg Wunsch 531cab0fb4eSKris Kennaway fprintf(stderr, "%s", help[which][mode]); 532d6f907dcSJoerg Wunsch } 53348aee7f3SJoerg Wunsch exit(EXIT_FAILURE); 534d6f907dcSJoerg Wunsch } 535d6f907dcSJoerg Wunsch 536d6f907dcSJoerg Wunsch struct carg * 537d6f907dcSJoerg Wunsch getarg(struct cargs * _args, int ch) 538d6f907dcSJoerg Wunsch { 539d0d78e13SBen Smithurst struct carg *c = LIST_FIRST(_args); 540d6f907dcSJoerg Wunsch 541d6f907dcSJoerg Wunsch while (c != NULL && c->ch != ch) 542d0d78e13SBen Smithurst c = LIST_NEXT(c, list); 543d6f907dcSJoerg Wunsch return c; 544d6f907dcSJoerg Wunsch } 545d6f907dcSJoerg Wunsch 546d6f907dcSJoerg Wunsch struct carg * 547d6f907dcSJoerg Wunsch addarg(struct cargs * _args, int ch, char *argstr) 548d6f907dcSJoerg Wunsch { 549d6f907dcSJoerg Wunsch struct carg *ca = malloc(sizeof(struct carg)); 550d6f907dcSJoerg Wunsch 551d6f907dcSJoerg Wunsch if (ca == NULL) 5521dcc6ec7SPhilippe Charnier errx(EX_OSERR, "out of memory"); 553d6f907dcSJoerg Wunsch ca->ch = ch; 554d6f907dcSJoerg Wunsch ca->val = argstr; 555d6f907dcSJoerg Wunsch LIST_INSERT_HEAD(_args, ca, list); 556d6f907dcSJoerg Wunsch return ca; 557d6f907dcSJoerg Wunsch } 558