pw.c revision 27474
11539Srgrimes/*- 21539Srgrimes * Copyright (C) 1996 336888Speter * David L. Nugent. All rights reserved. 436888Speter * 51539Srgrimes * Redistribution and use in source and binary forms, with or without 61539Srgrimes * modification, are permitted provided that the following conditions 71539Srgrimes * are met: 81539Srgrimes * 1. Redistributions of source code must retain the above copyright 91539Srgrimes * notice, this list of conditions and the following disclaimer. 101539Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 111539Srgrimes * notice, this list of conditions and the following disclaimer in the 121539Srgrimes * documentation and/or other materials provided with the distribution. 131539Srgrimes * 141539Srgrimes * THIS SOFTWARE IS PROVIDED BY DAVID L. NUGENT AND CONTRIBUTORS ``AS IS'' AND 1536888Speter * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1636888Speter * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 171539Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL DAVID L. NUGENT OR CONTRIBUTORS BE LIABLE 181539Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 191539Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2036888Speter * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 211539Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 221539Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 231539Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 241539Srgrimes * SUCH DAMAGE. 251539Srgrimes * 261539Srgrimes * $Id: pw.c,v 1.5 1997/02/22 16:12:25 peter Exp $ 271539Srgrimes */ 281539Srgrimes 291539Srgrimes#include "pw.h" 301539Srgrimes#include <paths.h> 311539Srgrimes#include <sys/wait.h> 3236888Speter 3336888Speterstatic char *progname = "pw"; 3436888Speter 3536888Speterconst char *Modes[] = {"add", "del", "mod", "show", "next", NULL}; 361539Srgrimesconst char *Which[] = {"user", "group", NULL}; 371539Srgrimesstatic const char *Combo1[] = { 381539Srgrimes "useradd", "userdel", "usermod", "usershow", "usernext", 3936888Speter "groupadd", "groupdel", "groupmod", "groupshow", "groupnext", 408858Srgrimes NULL}; 4136888Speterstatic const char *Combo2[] = { 4236888Speter "adduser", "deluser", "moduser", "showuser", "nextuser", 4336888Speter "addgroup", "delgroup", "modgroup", "showgroup", "nextgroup", 4436888SpeterNULL}; 451539Srgrimes 461539Srgrimesstatic struct cargs arglist; 471539Srgrimes 481539Srgrimesstatic int getindex(const char *words[], const char *word); 4936888Speterstatic void cmdhelp(int mode, int which); 5036888Speter 5136888Speter 5236888Speterint 5350473Spetermain(int argc, char *argv[]) 541539Srgrimes{ 551539Srgrimes int ch; 5610132Speter int mode = -1; 5736888Speter int which = -1; 581539Srgrimes struct userconf *cnf; 5936888Speter 6036888Speter static const char *opts[W_NUM][M_NUM] = 611539Srgrimes { 623070Spst { /* user */ 631539Srgrimes "C:qn:u:c:d:e:p:g:G:mk:s:oL:i:w:h:Db:NPy:Y", 641539Srgrimes "C:qn:u:rY", 653070Spst "C:qn:u:c:d:e:p:g:G:ml:k:s:w:L:h:FNPY", 663070Spst "C:qn:u:FPa", 6736888Speter "C:q" 6836888Speter }, 693070Spst { /* grp */ 703070Spst "C:qn:g:h:M:pNPY", 713070Spst "C:qn:g:Y", 7236888Speter "C:qn:g:l:h:FM:m:NPY", 7336888Speter "C:qn:g:FPa", 743070Spst "C:q" 753070Spst } 7636888Speter }; 771539Srgrimes 7836888Speter static int (*funcs[W_NUM]) (struct userconf * _cnf, int _mode, struct cargs * _args) = 7936888Speter { /* Request handlers */ 8036888Speter pw_user, 8136888Speter pw_group 8236888Speter }; 8336888Speter 8436888Speter umask(0); /* We wish to handle this manually */ 8536888Speter progname = strrchr(argv[0], '/'); 8636888Speter if (progname != NULL) 8736888Speter ++progname; 8836888Speter else 8936888Speter progname = argv[0]; 9036888Speter 9136888Speter LIST_INIT(&arglist); 921539Srgrimes 931539Srgrimes /* 9436888Speter * Break off the first couple of words to determine what exactly 9536888Speter * we're being asked to do 961539Srgrimes */ 9736888Speter while (argc > 1 && *argv[1] != '-') { 9836888Speter int tmp; 9936888Speter 10036888Speter if ((tmp = getindex(Modes, argv[1])) != -1) 10136888Speter mode = tmp; 10236888Speter else if ((tmp = getindex(Which, argv[1])) != -1) 10336888Speter which = tmp; 10436888Speter else if ((tmp = getindex(Combo1, argv[1])) != -1 || (tmp = getindex(Combo2, argv[1])) != -1) { 10536888Speter which = tmp / M_NUM; 10636888Speter mode = tmp % M_NUM; 1071539Srgrimes } else if (strcmp(argv[1], "help") == 0) 1081539Srgrimes cmdhelp(mode, which); 10936888Speter else if (which != -1 && mode != -1 && arglist.lh_first == NULL) 11036888Speter addarg(&arglist, 'n', argv[1]); 11136888Speter else 1121539Srgrimes cmderr(EX_USAGE, "Unknown keyword `%s'\n", argv[1]); 11336888Speter ++argv; 11436888Speter --argc; 11536888Speter } 11636888Speter 11736888Speter /* 11836888Speter * Bail out unless the user is specific! 11936888Speter */ 12036888Speter if (mode == -1 || which == -1) 12136888Speter cmdhelp(mode, which); 12236888Speter 12336888Speter /* 12436888Speter * We know which mode we're in and what we're about to do, so now 12536888Speter * let's dispatch the remaining command line args in a genric way. 12636888Speter */ 12736888Speter argv[0] = progname; /* Preserve this */ 12836888Speter optarg = NULL; 12936888Speter 13036888Speter while ((ch = getopt(argc, argv, opts[which][mode])) != -1) { 13136888Speter if (ch == '?') 13236888Speter cmderr(EX_USAGE, NULL); 13336888Speter else 13436888Speter addarg(&arglist, ch, optarg); 13536888Speter optarg = NULL; 13636888Speter } 1371539Srgrimes 13836888Speter /* 1391539Srgrimes * Must be root to attempt an update 14036888Speter */ 14136888Speter if (geteuid() != 0 && mode != M_PRINT && mode != M_NEXT && getarg(&arglist, 'N')==NULL) 14236888Speter cmderr(EX_NOPERM, "you must be root to run this program\n"); 14347742Speter 14436888Speter /* 14536888Speter * We should immediately look for the -q 'quiet' switch so that we 14636888Speter * don't bother with extraneous errors 14736888Speter */ 1481539Srgrimes if (getarg(&arglist, 'q') != NULL) 14936888Speter freopen("/dev/null", "w", stderr); 15036888Speter 15136888Speter /* 15247742Speter * Now, let's do the common initialisation 15336888Speter */ 15436888Speter cnf = read_userconfig(getarg(&arglist, 'C') ? getarg(&arglist, 'C')->val : NULL); 15536888Speter ch = funcs[which] (cnf, mode, &arglist); 15636888Speter 1571539Srgrimes /* 15836888Speter * If everything went ok, and we've been asked to update 15936888Speter * the NIS maps, then do it now 16036888Speter */ 1611539Srgrimes if (ch == EXIT_SUCCESS && getarg(&arglist, 'Y') != NULL) { 16236888Speter pid_t pid; 16336888Speter 16436888Speter fflush(NULL); 16536888Speter if (chdir(_PATH_YP) == -1) 16636888Speter perror("chdir(" _PATH_YP ")"); 16736888Speter else if ((pid = fork()) == -1) 16836888Speter perror("fork()"); 16936888Speter else if (pid == 0) { 17036888Speter /* Is make anywhere else? */ 17136888Speter execlp("/usr/bin/make", "make", NULL); 17236888Speter _exit(1); 17336888Speter } else { 17436888Speter int i; 1751539Srgrimes waitpid(pid, &i, 0); 1761539Srgrimes if ((i = WEXITSTATUS(i)) != 0) 17736888Speter cmderr(ch, "warning: make exited with status %d\n", i); 17836888Speter else 17936888Speter pw_log(cnf, mode, which, "NIS maps updated"); 18036888Speter } 18136888Speter } 18236888Speter return ch; 18336888Speter} 18436888Speter 18536888Speterstatic int 18636888Spetergetindex(const char *words[], const char *word) 18736888Speter{ 18836888Speter int i = 0; 18936888Speter 19036888Speter while (words[i]) { 19136888Speter if (strcmp(words[i], word) == 0) 19236888Speter return i; 19336888Speter i++; 19436888Speter } 19536888Speter return -1; 19636888Speter} 19736888Speter 19836888Speter 19936888Speter/* 20036888Speter * This is probably an overkill for a cmdline help system, but it reflects 20136888Speter * the complexity of the command line. 20236888Speter */ 20336888Speter 20436888Speterstatic void 20536888Speterbanner(void) 20636888Speter{ 20736888Speter fprintf(stderr, "%s: ", progname); 20836888Speter} 20936888Speter 21036888Spetervoid 21136888Spetercmderr(int ec, char const * fmt,...) 21236888Speter{ 21336888Speter if (fmt != NULL) { 21436888Speter va_list argp; 21536888Speter 21636888Speter banner(); 21736888Speter va_start(argp, fmt); 21836888Speter vfprintf(stderr, fmt, argp); 21936888Speter va_end(argp); 22036888Speter } 22136888Speter exit(ec); 22236888Speter} 22336888Speter 22436888Speterstatic void 22536888Spetercmdhelp(int mode, int which) 22636888Speter{ 22736888Speter banner(); 22836888Speter if (which == -1) 22936888Speter fprintf(stderr, "usage: %s [user|group] [add|del|mod|show|next] [ help | switches/values ]\n", progname); 23036888Speter else if (mode == -1) 23136888Speter fprintf(stderr, "usage: %s %s [add|del|mod|show|next] [ help | switches/values ]\n", progname, Which[which]); 23236888Speter else { 23336888Speter 23436888Speter /* 23536888Speter * We need to give mode specific help 23636888Speter */ 23736888Speter static const char *help[W_NUM][M_NUM] = 23836888Speter { 23936888Speter { 24036888Speter "usage: %s useradd [name] [switches]\n" 24136888Speter "\t-C config configuration file\n" 24236888Speter "\t-q quiet operation\n" 24336888Speter " Adding users:\n" 24436888Speter "\t-n name login name\n" 24536888Speter "\t-u uid user id\n" 24636888Speter "\t-c comment user name/comment\n" 24736888Speter "\t-d directory home directory\n" 24836888Speter "\t-e date account expiry date\n" 24936888Speter "\t-p date password expiry date\n" 25036888Speter "\t-g grp initial group\n" 25136888Speter "\t-G grp1,grp2 additional groups\n" 25236888Speter "\t-m [ -k dir ] create and set up home\n" 25336888Speter "\t-s shell name of login shell\n" 25436888Speter "\t-o duplicate uid ok\n" 25536888Speter "\t-L class user class\n" 25636888Speter "\t-h fd read password on fd\n" 25736888Speter "\t-Y update NIS maps\n" 25836888Speter "\t-N no update\n" 25936888Speter " Setting defaults:\n" 26036888Speter "\t-D set user defaults\n" 26136888Speter "\t-b dir default home root dir\n" 26236888Speter "\t-e period default expiry period\n" 26336888Speter "\t-p period default password change period\n" 26436888Speter "\t-g group default group\n" 26536888Speter "\t-G grp1,grp2 additional groups\n" 26636888Speter "\t-L class default user class\n" 26736888Speter "\t-k dir default home skeleton\n" 26836888Speter "\t-u min,max set min,max uids\n" 26936888Speter "\t-i min,max set min,max gids\n" 27036888Speter "\t-w method set default password method\n" 27136888Speter "\t-s shell default shell\n" 27236888Speter "\t-y path set NIS passwd file path\n", 27336888Speter "usage: %s userdel [uid|name] [switches]\n" 27436888Speter "\t-n name login name\n" 27536888Speter "\t-u uid user id\n" 27678012Sume "\t-Y update NIS maps\n" 27736888Speter "\t-r remove home & contents\n", 27836888Speter "usage: %s usermod [uid|name] [switches]\n" 27936888Speter "\t-C config configuration file\n" 28036888Speter "\t-q quiet operation\n" 28136888Speter "\t-F force add if no user\n" 28236888Speter "\t-n name login name\n" 28336888Speter "\t-u uid user id\n" 28436888Speter "\t-c comment user name/comment\n" 28536888Speter "\t-d directory home directory\n" 28636888Speter "\t-e date account expiry date\n" 2871539Srgrimes "\t-p date password expiry date\n" 2881539Srgrimes "\t-g grp initial group\n" 28936888Speter "\t-G grp1,grp2 additional groups\n" 29036888Speter "\t-l name new login name\n" 29136888Speter "\t-L class user class\n" 29236888Speter "\t-m [ -k dir ] create and set up home\n" 29336888Speter "\t-s shell name of login shell\n" 2941539Srgrimes "\t-w method set new password using method\n" 29536888Speter "\t-h fd read password on fd\n" 29636888Speter "\t-Y update NIS maps\n" 29736888Speter "\t-N no update\n", 29836888Speter "usage: %s usershow [uid|name] [switches]\n" 2991539Srgrimes "\t-n name login name\n" 3001539Srgrimes "\t-u uid user id\n" 30121056Speter "\t-F force print\n" 30221056Speter "\t-P prettier format\n" 30336888Speter "\t-a print all users\n", 30436888Speter "usage: %s usernext [switches]\n" 30536888Speter "\t-C config configuration file\n" 30636888Speter }, 30736888Speter { 30821056Speter "usage: %s groupadd [group|gid] [switches]\n" 30936888Speter "\t-C config configuration file\n" 31036888Speter "\t-q quiet operation\n" 31136888Speter "\t-n group group name\n" 31236888Speter "\t-g gid group id\n" 31336888Speter "\t-M usr1,usr2 add users as group members\n" 31436888Speter "\t-o duplicate gid ok\n" 31536888Speter "\t-Y update NIS maps\n" 31636888Speter "\t-N no update\n", 31736888Speter "usage: %s groupdel [group|gid] [switches]\n" 31836888Speter "\t-n name group name\n" 31936888Speter "\t-g gid group id\n" 32036888Speter "\t-Y update NIS maps\n", 32136888Speter "usage: %s groupmod [group|gid] [switches]\n" 32221056Speter "\t-C config configuration file\n" 32336888Speter "\t-q quiet operation\n" 32436888Speter "\t-F force add if not exists\n" 32536888Speter "\t-n name group name\n" 32636888Speter "\t-g gid group id\n" 32721056Speter "\t-M usr1,usr2 replaces users as group members\n" 32821056Speter "\t-m usr1,usr2 add users as group members\n" 32936888Speter "\t-l name new group name\n" 33036888Speter "\t-Y update NIS maps\n" 33136888Speter "\t-N no update\n", 33221056Speter "usage: %s groupshow [group|gid] [switches]\n" 33321056Speter "\t-n name group name\n" 33436888Speter "\t-g gid group id\n" 33536888Speter "\t-F force print\n" 33636888Speter "\t-P prettier format\n" 33736888Speter "\t-a print all accounting groups\n", 33836888Speter "usage: %s groupnext [switches]\n" 33936888Speter "\t-C config configuration file\n" 34021056Speter } 34136888Speter }; 34236888Speter 34336888Speter fprintf(stderr, help[which][mode], progname); 34436888Speter } 34536888Speter exit(EXIT_FAILURE); 34636888Speter} 34736888Speter 34836888Speterstruct carg * 34936888Spetergetarg(struct cargs * _args, int ch) 3501539Srgrimes{ 35136888Speter struct carg *c = _args->lh_first; 35236888Speter 35336888Speter while (c != NULL && c->ch != ch) 35436888Speter c = c->list.le_next; 35536888Speter return c; 35621056Speter} 3571539Srgrimes 3581539Srgrimesstruct carg * 3591539Srgrimesaddarg(struct cargs * _args, int ch, char *argstr) 3601539Srgrimes{ 36136888Speter struct carg *ca = malloc(sizeof(struct carg)); 3621539Srgrimes 3633070Spst if (ca == NULL) 3643070Spst cmderr(EX_OSERR, "Abort - out of memory\n"); 3653070Spst ca->ch = ch; 36636888Speter ca->val = argstr; 3671539Srgrimes LIST_INSERT_HEAD(_args, ca, list); 3681539Srgrimes return ca; 36936888Speter} 3701539Srgrimes