xref: /freebsd/usr.sbin/pw/pw.c (revision 2cc63cd136ff7481a16bbe2d1a878a504e5ec26f)
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>
36*2cc63cd1SBaptiste 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 
88*2cc63cd1SBaptiste Daroussin struct pwconf conf;
89*2cc63cd1SBaptiste 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;
1025f12594aSDavid Nugent 	char		*config = NULL;
10390edef4fSBaptiste Daroussin 	struct stat	st;
104ac72be28SBaptiste Daroussin 	char		arg;
105*2cc63cd1SBaptiste Daroussin 	bool		relocated = false;
106d6f907dcSJoerg Wunsch 
107d6f907dcSJoerg Wunsch 	static const char *opts[W_NUM][M_NUM] =
108d6f907dcSJoerg Wunsch 	{
10948aee7f3SJoerg Wunsch 		{ /* user */
110ac72be28SBaptiste Daroussin 			"R:V:C:qn:u:c:d:e:p:g:G:mM:k:s:oL:i:w:h:H:Db:NPy:Y",
111ac72be28SBaptiste Daroussin 			"R:V:C:qn:u:rY",
112ac72be28SBaptiste Daroussin 			"R:V:C:qn:u:c:d:e:p:g:G:mM:l:k:s:w:L:h:H:FNPY",
113ac72be28SBaptiste Daroussin 			"R:V:C:qn:u:FPa7",
114ac72be28SBaptiste Daroussin 			"R:V:C:q",
115ac72be28SBaptiste Daroussin 			"R:V:C:q",
116ac72be28SBaptiste Daroussin 			"R:V:C:q"
11748aee7f3SJoerg Wunsch 		},
11848aee7f3SJoerg Wunsch 		{ /* grp  */
119ac72be28SBaptiste Daroussin 			"R:V:C:qn:g:h:H:M:opNPY",
120ac72be28SBaptiste Daroussin 			"R:V:C:qn:g:Y",
121ac72be28SBaptiste Daroussin 			"R:V:C:qn:d:g:l:h:H:FM:m:NPY",
122ac72be28SBaptiste Daroussin 			"R:V:C:qn:g:FPa",
123ac72be28SBaptiste Daroussin 			"R:V:C:q"
12448aee7f3SJoerg Wunsch 		 }
125d6f907dcSJoerg Wunsch 	};
126d6f907dcSJoerg Wunsch 
127*2cc63cd1SBaptiste Daroussin 	static int      (*funcs[W_NUM]) (int _mode, struct cargs * _args) =
128d6f907dcSJoerg Wunsch 	{			/* Request handlers */
129d6f907dcSJoerg Wunsch 		pw_user,
130d6f907dcSJoerg Wunsch 		pw_group
131d6f907dcSJoerg Wunsch 	};
132d6f907dcSJoerg Wunsch 
133*2cc63cd1SBaptiste Daroussin 	conf.rootdir[0] = '\0';
134*2cc63cd1SBaptiste Daroussin 	strlcpy(conf.etcpath, _PATH_PWD, sizeof(conf.etcpath));
135*2cc63cd1SBaptiste Daroussin 
136d6f907dcSJoerg Wunsch 	LIST_INIT(&arglist);
137d6f907dcSJoerg Wunsch 
13839610c72SAndrey A. Chernov 	(void)setlocale(LC_ALL, "");
139e7161f36SAndrey A. Chernov 
140d6f907dcSJoerg Wunsch 	/*
141d6f907dcSJoerg Wunsch 	 * Break off the first couple of words to determine what exactly
142d6f907dcSJoerg Wunsch 	 * we're being asked to do
143d6f907dcSJoerg Wunsch 	 */
1445f12594aSDavid Nugent 	while (argc > 1) {
145d6f907dcSJoerg Wunsch 		int             tmp;
146d6f907dcSJoerg Wunsch 
1475f12594aSDavid Nugent 		if (*argv[1] == '-') {
1485f12594aSDavid Nugent 			/*
1495f12594aSDavid Nugent 			 * Special case, allow pw -V<dir> <operation> [args] for scripts etc.
1505f12594aSDavid Nugent 			 */
151ac72be28SBaptiste Daroussin 			arg = argv[1][1];
152ac72be28SBaptiste Daroussin 			if (arg == 'V' || arg == 'R') {
153*2cc63cd1SBaptiste Daroussin 				if (relocated)
154*2cc63cd1SBaptiste Daroussin 					errx(EXIT_FAILURE, "Both '-R' and '-V' "
155*2cc63cd1SBaptiste Daroussin 					    "specified, only one accepted");
156*2cc63cd1SBaptiste Daroussin 				relocated = true;
1575f12594aSDavid Nugent 				optarg = &argv[1][2];
1585f12594aSDavid Nugent 				if (*optarg == '\0') {
15990edef4fSBaptiste Daroussin 					if (stat(argv[2], &st) != 0)
16090edef4fSBaptiste Daroussin 						errx(EX_OSFILE, \
16190edef4fSBaptiste Daroussin 						    "no such directory `%s'",
16290edef4fSBaptiste Daroussin 						    argv[2]);
16390edef4fSBaptiste Daroussin 					if (!S_ISDIR(st.st_mode))
16490edef4fSBaptiste Daroussin 						errx(EX_OSFILE, "`%s' not a "
16590edef4fSBaptiste Daroussin 						    "directory", argv[2]);
1665f12594aSDavid Nugent 					optarg = argv[2];
1675f12594aSDavid Nugent 					++argv;
1685f12594aSDavid Nugent 					--argc;
1695f12594aSDavid Nugent 				}
170*2cc63cd1SBaptiste Daroussin 				memcpy(&PWF, &VPWF, sizeof PWF);
171*2cc63cd1SBaptiste Daroussin 				if (arg == 'R') {
172*2cc63cd1SBaptiste Daroussin 					strlcpy(conf.rootdir, optarg,
173*2cc63cd1SBaptiste Daroussin 					    sizeof(conf.rootdir));
174*2cc63cd1SBaptiste Daroussin 					PWF._altdir = PWF_ROOTDIR;
175*2cc63cd1SBaptiste Daroussin 				}
176*2cc63cd1SBaptiste Daroussin 				snprintf(conf.etcpath, sizeof(conf.etcpath),
177*2cc63cd1SBaptiste Daroussin 				    "%s%s", optarg, arg == 'R' ? "/etc" : "");
178e3921b27SDavid Nugent 			} else
1795f12594aSDavid Nugent 				break;
1805f12594aSDavid Nugent 		}
181c4e667b9SDavid Nugent 		else if (mode == -1 && (tmp = getindex(Modes, argv[1])) != -1)
182d6f907dcSJoerg Wunsch 			mode = tmp;
183c4e667b9SDavid Nugent 		else if (which == -1 && (tmp = getindex(Which, argv[1])) != -1)
184d6f907dcSJoerg Wunsch 			which = tmp;
185c4e667b9SDavid Nugent 		else if ((mode == -1 && which == -1) &&
186c4e667b9SDavid Nugent 			 ((tmp = getindex(Combo1, argv[1])) != -1 ||
187c4e667b9SDavid Nugent 			  (tmp = getindex(Combo2, argv[1])) != -1)) {
188d6f907dcSJoerg Wunsch 			which = tmp / M_NUM;
189d6f907dcSJoerg Wunsch 			mode = tmp % M_NUM;
190c4e667b9SDavid Nugent 		} else if (strcmp(argv[1], "help") == 0 && argv[2] == NULL)
191d6f907dcSJoerg Wunsch 			cmdhelp(mode, which);
1927291e217SDavid Nugent 		else if (which != -1 && mode != -1)
193d6f907dcSJoerg Wunsch 			addarg(&arglist, 'n', argv[1]);
194d6f907dcSJoerg Wunsch 		else
1951dcc6ec7SPhilippe Charnier 			errx(EX_USAGE, "unknown keyword `%s'", argv[1]);
196d6f907dcSJoerg Wunsch 		++argv;
197d6f907dcSJoerg Wunsch 		--argc;
198d6f907dcSJoerg Wunsch 	}
199d6f907dcSJoerg Wunsch 
200d6f907dcSJoerg Wunsch 	/*
201d6f907dcSJoerg Wunsch 	 * Bail out unless the user is specific!
202d6f907dcSJoerg Wunsch 	 */
203d6f907dcSJoerg Wunsch 	if (mode == -1 || which == -1)
204d6f907dcSJoerg Wunsch 		cmdhelp(mode, which);
205d6f907dcSJoerg Wunsch 
206d6f907dcSJoerg Wunsch 	/*
207d6f907dcSJoerg Wunsch 	 * We know which mode we're in and what we're about to do, so now
208d6f907dcSJoerg Wunsch 	 * let's dispatch the remaining command line args in a genric way.
209d6f907dcSJoerg Wunsch 	 */
210d6f907dcSJoerg Wunsch 	optarg = NULL;
211d6f907dcSJoerg Wunsch 
212d6f907dcSJoerg Wunsch 	while ((ch = getopt(argc, argv, opts[which][mode])) != -1) {
213d6f907dcSJoerg Wunsch 		if (ch == '?')
214923dc0b2SDavid Nugent 			errx(EX_USAGE, "unknown switch");
215d6f907dcSJoerg Wunsch 		else
216d6f907dcSJoerg Wunsch 			addarg(&arglist, ch, optarg);
217d6f907dcSJoerg Wunsch 		optarg = NULL;
218d6f907dcSJoerg Wunsch 	}
219d6f907dcSJoerg Wunsch 
220d6f907dcSJoerg Wunsch 	/*
22148aee7f3SJoerg Wunsch 	 * Must be root to attempt an update
22248aee7f3SJoerg Wunsch 	 */
223fa7e83d4SDavid Nugent 	if (geteuid() != 0 && mode != M_PRINT && mode != M_NEXT && getarg(&arglist, 'N')==NULL)
2241dcc6ec7SPhilippe Charnier 		errx(EX_NOPERM, "you must be root to run this program");
22548aee7f3SJoerg Wunsch 
22648aee7f3SJoerg Wunsch 	/*
227d6f907dcSJoerg Wunsch 	 * We should immediately look for the -q 'quiet' switch so that we
228d6f907dcSJoerg Wunsch 	 * don't bother with extraneous errors
229d6f907dcSJoerg Wunsch 	 */
230d6f907dcSJoerg Wunsch 	if (getarg(&arglist, 'q') != NULL)
2311a37aa56SDavid E. O'Brien 		freopen(_PATH_DEVNULL, "w", stderr);
232d6f907dcSJoerg Wunsch 
233d6f907dcSJoerg Wunsch 	/*
2345f12594aSDavid Nugent 	 * Set our base working path if not overridden
2355f12594aSDavid Nugent 	 */
2365f12594aSDavid Nugent 
2375f12594aSDavid Nugent 	config = getarg(&arglist, 'C') ? getarg(&arglist, 'C')->val : NULL;
2385f12594aSDavid Nugent 	if (config == NULL) {	/* Only override config location if -C not specified */
239*2cc63cd1SBaptiste Daroussin 		asprintf(&config, "%s/pw.conf", conf.etcpath);
24019741915SBaptiste Daroussin 		if (config == NULL)
24119741915SBaptiste Daroussin 			errx(EX_OSERR, "out of memory");
2425f12594aSDavid Nugent 	}
2435f12594aSDavid Nugent 
2445f12594aSDavid Nugent 	/*
245d6f907dcSJoerg Wunsch 	 * Now, let's do the common initialisation
246d6f907dcSJoerg Wunsch 	 */
247*2cc63cd1SBaptiste Daroussin 	conf.userconf = read_userconfig(config);
2485e91a8acSNate Williams 
249*2cc63cd1SBaptiste Daroussin 	ch = funcs[which] (mode, &arglist);
250f1d684faSDavid Nugent 
251f1d684faSDavid Nugent 	/*
252f1d684faSDavid Nugent 	 * If everything went ok, and we've been asked to update
253f1d684faSDavid Nugent 	 * the NIS maps, then do it now
254f1d684faSDavid Nugent 	 */
255f1d684faSDavid Nugent 	if (ch == EXIT_SUCCESS && getarg(&arglist, 'Y') != NULL) {
256f1d684faSDavid Nugent 		pid_t	pid;
257f1d684faSDavid Nugent 
258f1d684faSDavid Nugent 		fflush(NULL);
259f1d684faSDavid Nugent 		if (chdir(_PATH_YP) == -1)
2601dcc6ec7SPhilippe Charnier 			warn("chdir(" _PATH_YP ")");
261f1d684faSDavid Nugent 		else if ((pid = fork()) == -1)
2621dcc6ec7SPhilippe Charnier 			warn("fork()");
263f1d684faSDavid Nugent 		else if (pid == 0) {
264f1d684faSDavid Nugent 			/* Is make anywhere else? */
2657bc6d015SBrian Somers 			execlp("/usr/bin/make", "make", (char *)NULL);
266f1d684faSDavid Nugent 			_exit(1);
267f1d684faSDavid Nugent 		} else {
268f1d684faSDavid Nugent 			int   i;
269f1d684faSDavid Nugent 			waitpid(pid, &i, 0);
270f1d684faSDavid Nugent 			if ((i = WEXITSTATUS(i)) != 0)
2711dcc6ec7SPhilippe Charnier 				errx(ch, "make exited with status %d", i);
272f1d684faSDavid Nugent 			else
273*2cc63cd1SBaptiste Daroussin 				pw_log(conf.userconf, mode, which, "NIS maps updated");
274f1d684faSDavid Nugent 		}
275f1d684faSDavid Nugent 	}
276f1d684faSDavid Nugent 	return ch;
277d6f907dcSJoerg Wunsch }
278d6f907dcSJoerg Wunsch 
2795e91a8acSNate Williams 
280d6f907dcSJoerg Wunsch static int
281d6f907dcSJoerg Wunsch getindex(const char *words[], const char *word)
282d6f907dcSJoerg Wunsch {
283d6f907dcSJoerg Wunsch 	int             i = 0;
284d6f907dcSJoerg Wunsch 
285d6f907dcSJoerg Wunsch 	while (words[i]) {
286d6f907dcSJoerg Wunsch 		if (strcmp(words[i], word) == 0)
287d6f907dcSJoerg Wunsch 			return i;
288d6f907dcSJoerg Wunsch 		i++;
289d6f907dcSJoerg Wunsch 	}
290d6f907dcSJoerg Wunsch 	return -1;
291d6f907dcSJoerg Wunsch }
292d6f907dcSJoerg Wunsch 
293d6f907dcSJoerg Wunsch 
294d6f907dcSJoerg Wunsch /*
295d6f907dcSJoerg Wunsch  * This is probably an overkill for a cmdline help system, but it reflects
296d6f907dcSJoerg Wunsch  * the complexity of the command line.
297d6f907dcSJoerg Wunsch  */
298d6f907dcSJoerg Wunsch 
299d6f907dcSJoerg Wunsch static void
300d6f907dcSJoerg Wunsch cmdhelp(int mode, int which)
301d6f907dcSJoerg Wunsch {
302d6f907dcSJoerg Wunsch 	if (which == -1)
3032399cd14SDavid Nugent 		fprintf(stderr, "usage:\n  pw [user|group|lock|unlock] [add|del|mod|show|next] [help|switches/values]\n");
304d6f907dcSJoerg Wunsch 	else if (mode == -1)
3052399cd14SDavid Nugent 		fprintf(stderr, "usage:\n  pw %s [add|del|mod|show|next] [help|switches/values]\n", Which[which]);
306d6f907dcSJoerg Wunsch 	else {
307d6f907dcSJoerg Wunsch 
308d6f907dcSJoerg Wunsch 		/*
309d6f907dcSJoerg Wunsch 		 * We need to give mode specific help
310d6f907dcSJoerg Wunsch 		 */
311d6f907dcSJoerg Wunsch 		static const char *help[W_NUM][M_NUM] =
312d6f907dcSJoerg Wunsch 		{
313d6f907dcSJoerg Wunsch 			{
3141dcc6ec7SPhilippe Charnier 				"usage: pw useradd [name] [switches]\n"
3155f12594aSDavid Nugent 				"\t-V etcdir      alternate /etc location\n"
316ac72be28SBaptiste Daroussin 				"\t-R rootir      alternate root directory\n"
317d6f907dcSJoerg Wunsch 				"\t-C config      configuration file\n"
318d6f907dcSJoerg Wunsch 				"\t-q             quiet operation\n"
319d6f907dcSJoerg Wunsch 				"  Adding users:\n"
320d6f907dcSJoerg Wunsch 				"\t-n name        login name\n"
321d6f907dcSJoerg Wunsch 				"\t-u uid         user id\n"
322d6f907dcSJoerg Wunsch 				"\t-c comment     user name/comment\n"
323d6f907dcSJoerg Wunsch 				"\t-d directory   home directory\n"
324d6f907dcSJoerg Wunsch 				"\t-e date        account expiry date\n"
325d6f907dcSJoerg Wunsch 				"\t-p date        password expiry date\n"
326d6f907dcSJoerg Wunsch 				"\t-g grp         initial group\n"
327d6f907dcSJoerg Wunsch 				"\t-G grp1,grp2   additional groups\n"
328d6f907dcSJoerg Wunsch 				"\t-m [ -k dir ]  create and set up home\n"
3291dd634b0SLukas Ertl 				"\t-M mode        home directory permissions\n"
330d6f907dcSJoerg Wunsch 				"\t-s shell       name of login shell\n"
331d6f907dcSJoerg Wunsch 				"\t-o             duplicate uid ok\n"
332d6f907dcSJoerg Wunsch 				"\t-L class       user class\n"
333d6f907dcSJoerg Wunsch 				"\t-h fd          read password on fd\n"
33487d6b5caSIan Dowse 				"\t-H fd          read encrypted password on fd\n"
335f1d684faSDavid Nugent 				"\t-Y             update NIS maps\n"
33648aee7f3SJoerg Wunsch 				"\t-N             no update\n"
337d6f907dcSJoerg Wunsch 				"  Setting defaults:\n"
3385f12594aSDavid Nugent 				"\t-V etcdir      alternate /etc location\n"
339ac72be28SBaptiste Daroussin 				"\t-R rootir      alternate root directory\n"
340d6f907dcSJoerg Wunsch 			        "\t-D             set user defaults\n"
341d6f907dcSJoerg Wunsch 				"\t-b dir         default home root dir\n"
342d6f907dcSJoerg Wunsch 				"\t-e period      default expiry period\n"
343d6f907dcSJoerg Wunsch 				"\t-p period      default password change period\n"
344d6f907dcSJoerg Wunsch 				"\t-g group       default group\n"
345d6f907dcSJoerg Wunsch 				"\t-G grp1,grp2   additional groups\n"
346d6f907dcSJoerg Wunsch 				"\t-L class       default user class\n"
347d6f907dcSJoerg Wunsch 				"\t-k dir         default home skeleton\n"
34885204142SLukas Ertl 				"\t-M mode        home directory permissions\n"
349d6f907dcSJoerg Wunsch 				"\t-u min,max     set min,max uids\n"
350d6f907dcSJoerg Wunsch 				"\t-i min,max     set min,max gids\n"
351d6f907dcSJoerg Wunsch 				"\t-w method      set default password method\n"
352f1d684faSDavid Nugent 				"\t-s shell       default shell\n"
353f1d684faSDavid Nugent 				"\t-y path        set NIS passwd file path\n",
3541dcc6ec7SPhilippe Charnier 				"usage: pw userdel [uid|name] [switches]\n"
3555f12594aSDavid Nugent 				"\t-V etcdir      alternate /etc location\n"
356ac72be28SBaptiste Daroussin 				"\t-R rootir      alternate root directory\n"
357d6f907dcSJoerg Wunsch 				"\t-n name        login name\n"
358d6f907dcSJoerg Wunsch 				"\t-u uid         user id\n"
359f1d684faSDavid Nugent 				"\t-Y             update NIS maps\n"
360d6f907dcSJoerg Wunsch 				"\t-r             remove home & contents\n",
3611dcc6ec7SPhilippe Charnier 				"usage: pw usermod [uid|name] [switches]\n"
3625f12594aSDavid Nugent 				"\t-V etcdir      alternate /etc location\n"
363ac72be28SBaptiste Daroussin 				"\t-R rootir      alternate root directory\n"
364d6f907dcSJoerg Wunsch 				"\t-C config      configuration file\n"
365d6f907dcSJoerg Wunsch 				"\t-q             quiet operation\n"
366d6f907dcSJoerg Wunsch 				"\t-F             force add if no user\n"
367d6f907dcSJoerg Wunsch 				"\t-n name        login name\n"
368d6f907dcSJoerg Wunsch 				"\t-u uid         user id\n"
369d6f907dcSJoerg Wunsch 				"\t-c comment     user name/comment\n"
370d6f907dcSJoerg Wunsch 				"\t-d directory   home directory\n"
371d6f907dcSJoerg Wunsch 				"\t-e date        account expiry date\n"
372d6f907dcSJoerg Wunsch 				"\t-p date        password expiry date\n"
373d6f907dcSJoerg Wunsch 				"\t-g grp         initial group\n"
374d6f907dcSJoerg Wunsch 				"\t-G grp1,grp2   additional groups\n"
375d6f907dcSJoerg Wunsch 				"\t-l name        new login name\n"
376d6f907dcSJoerg Wunsch 				"\t-L class       user class\n"
377d6f907dcSJoerg Wunsch 				"\t-m [ -k dir ]  create and set up home\n"
3781dd634b0SLukas Ertl 				"\t-M mode        home directory permissions\n"
379d6f907dcSJoerg Wunsch 				"\t-s shell       name of login shell\n"
38048aee7f3SJoerg Wunsch 				"\t-w method      set new password using method\n"
38148aee7f3SJoerg Wunsch 				"\t-h fd          read password on fd\n"
38287d6b5caSIan Dowse 				"\t-H fd          read encrypted password on fd\n"
383f1d684faSDavid Nugent 				"\t-Y             update NIS maps\n"
38448aee7f3SJoerg Wunsch 				"\t-N             no update\n",
3851dcc6ec7SPhilippe Charnier 				"usage: pw usershow [uid|name] [switches]\n"
3865f12594aSDavid Nugent 				"\t-V etcdir      alternate /etc location\n"
387ac72be28SBaptiste Daroussin 				"\t-R rootir      alternate root directory\n"
388d6f907dcSJoerg Wunsch 				"\t-n name        login name\n"
389d6f907dcSJoerg Wunsch 				"\t-u uid         user id\n"
390d6f907dcSJoerg Wunsch 				"\t-F             force print\n"
39148aee7f3SJoerg Wunsch 				"\t-P             prettier format\n"
392f3522722SDavid Nugent 				"\t-a             print all users\n"
393f3522722SDavid Nugent 				"\t-7             print in v7 format\n",
3941dcc6ec7SPhilippe Charnier 				"usage: pw usernext [switches]\n"
3955f12594aSDavid Nugent 				"\t-V etcdir      alternate /etc location\n"
396ac72be28SBaptiste Daroussin 				"\t-R rootir      alternate root directory\n"
39748aee7f3SJoerg Wunsch 				"\t-C config      configuration file\n"
398ed6fd55aSDima Dorfman 				"\t-q             quiet operation\n",
399ed6fd55aSDima Dorfman 				"usage pw: lock [switches]\n"
400ed6fd55aSDima Dorfman 				"\t-V etcdir      alternate /etc locations\n"
401ed6fd55aSDima Dorfman 				"\t-C config      configuration file\n"
402ed6fd55aSDima Dorfman 				"\t-q             quiet operation\n",
403ed6fd55aSDima Dorfman 				"usage pw: unlock [switches]\n"
404ed6fd55aSDima Dorfman 				"\t-V etcdir      alternate /etc locations\n"
405ed6fd55aSDima Dorfman 				"\t-C config      configuration file\n"
406ed6fd55aSDima Dorfman 				"\t-q             quiet operation\n"
407d6f907dcSJoerg Wunsch 			},
408d6f907dcSJoerg Wunsch 			{
4091dcc6ec7SPhilippe Charnier 				"usage: pw groupadd [group|gid] [switches]\n"
4105f12594aSDavid Nugent 				"\t-V etcdir      alternate /etc location\n"
411ac72be28SBaptiste Daroussin 				"\t-R rootir      alternate root directory\n"
412d6f907dcSJoerg Wunsch 				"\t-C config      configuration file\n"
413d6f907dcSJoerg Wunsch 				"\t-q             quiet operation\n"
414d6f907dcSJoerg Wunsch 				"\t-n group       group name\n"
415d6f907dcSJoerg Wunsch 				"\t-g gid         group id\n"
41648aee7f3SJoerg Wunsch 				"\t-M usr1,usr2   add users as group members\n"
41748aee7f3SJoerg Wunsch 				"\t-o             duplicate gid ok\n"
418f1d684faSDavid Nugent 				"\t-Y             update NIS maps\n"
41948aee7f3SJoerg Wunsch 				"\t-N             no update\n",
4201dcc6ec7SPhilippe Charnier 				"usage: pw groupdel [group|gid] [switches]\n"
4215f12594aSDavid Nugent 				"\t-V etcdir      alternate /etc location\n"
422ac72be28SBaptiste Daroussin 				"\t-R rootir      alternate root directory\n"
423d6f907dcSJoerg Wunsch 				"\t-n name        group name\n"
424f1d684faSDavid Nugent 				"\t-g gid         group id\n"
425f1d684faSDavid Nugent 				"\t-Y             update NIS maps\n",
4261dcc6ec7SPhilippe Charnier 				"usage: pw groupmod [group|gid] [switches]\n"
4275f12594aSDavid Nugent 				"\t-V etcdir      alternate /etc location\n"
428ac72be28SBaptiste Daroussin 				"\t-R rootir      alternate root directory\n"
429d6f907dcSJoerg Wunsch 				"\t-C config      configuration file\n"
430d6f907dcSJoerg Wunsch 				"\t-q             quiet operation\n"
431d6f907dcSJoerg Wunsch 				"\t-F             force add if not exists\n"
432d6f907dcSJoerg Wunsch 				"\t-n name        group name\n"
433d6f907dcSJoerg Wunsch 				"\t-g gid         group id\n"
43448aee7f3SJoerg Wunsch 				"\t-M usr1,usr2   replaces users as group members\n"
43548aee7f3SJoerg Wunsch 				"\t-m usr1,usr2   add users as group members\n"
436bc991a6dSSean Farley 				"\t-d usr1,usr2   delete users as group members\n"
43748aee7f3SJoerg Wunsch 				"\t-l name        new group name\n"
438f1d684faSDavid Nugent 				"\t-Y             update NIS maps\n"
43948aee7f3SJoerg Wunsch 				"\t-N             no update\n",
4401dcc6ec7SPhilippe Charnier 				"usage: pw groupshow [group|gid] [switches]\n"
4415f12594aSDavid Nugent 				"\t-V etcdir      alternate /etc location\n"
442ac72be28SBaptiste Daroussin 				"\t-R rootir      alternate root directory\n"
443d6f907dcSJoerg Wunsch 				"\t-n name        group name\n"
444d6f907dcSJoerg Wunsch 				"\t-g gid         group id\n"
445d6f907dcSJoerg Wunsch 				"\t-F             force print\n"
44648aee7f3SJoerg Wunsch 				"\t-P             prettier format\n"
44748aee7f3SJoerg Wunsch 				"\t-a             print all accounting groups\n",
4481dcc6ec7SPhilippe Charnier 				"usage: pw groupnext [switches]\n"
4495f12594aSDavid Nugent 				"\t-V etcdir      alternate /etc location\n"
450ac72be28SBaptiste Daroussin 				"\t-R rootir      alternate root directory\n"
45148aee7f3SJoerg Wunsch 				"\t-C config      configuration file\n"
452ed6fd55aSDima Dorfman 				"\t-q             quiet operation\n"
453d6f907dcSJoerg Wunsch 			}
454d6f907dcSJoerg Wunsch 		};
455d6f907dcSJoerg Wunsch 
456cab0fb4eSKris Kennaway 		fprintf(stderr, "%s", help[which][mode]);
457d6f907dcSJoerg Wunsch 	}
45848aee7f3SJoerg Wunsch 	exit(EXIT_FAILURE);
459d6f907dcSJoerg Wunsch }
460d6f907dcSJoerg Wunsch 
461d6f907dcSJoerg Wunsch struct carg    *
462d6f907dcSJoerg Wunsch getarg(struct cargs * _args, int ch)
463d6f907dcSJoerg Wunsch {
464d0d78e13SBen Smithurst 	struct carg    *c = LIST_FIRST(_args);
465d6f907dcSJoerg Wunsch 
466d6f907dcSJoerg Wunsch 	while (c != NULL && c->ch != ch)
467d0d78e13SBen Smithurst 		c = LIST_NEXT(c, list);
468d6f907dcSJoerg Wunsch 	return c;
469d6f907dcSJoerg Wunsch }
470d6f907dcSJoerg Wunsch 
471d6f907dcSJoerg Wunsch struct carg    *
472d6f907dcSJoerg Wunsch addarg(struct cargs * _args, int ch, char *argstr)
473d6f907dcSJoerg Wunsch {
474d6f907dcSJoerg Wunsch 	struct carg    *ca = malloc(sizeof(struct carg));
475d6f907dcSJoerg Wunsch 
476d6f907dcSJoerg Wunsch 	if (ca == NULL)
4771dcc6ec7SPhilippe Charnier 		errx(EX_OSERR, "out of memory");
478d6f907dcSJoerg Wunsch 	ca->ch = ch;
479d6f907dcSJoerg Wunsch 	ca->val = argstr;
480d6f907dcSJoerg Wunsch 	LIST_INSERT_HEAD(_args, ca, list);
481d6f907dcSJoerg Wunsch 	return ca;
482d6f907dcSJoerg Wunsch }
483