xref: /freebsd/usr.sbin/pw/pw.c (revision 87d6b5caf6ad8fb8de5a783afcea897c029100a1)
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>
36f1d684faSDavid Nugent #include <sys/wait.h>
375f12594aSDavid Nugent #include "pw.h"
38d6f907dcSJoerg Wunsch 
39923dc0b2SDavid Nugent #if !defined(_PATH_YP)
40923dc0b2SDavid Nugent #define	_PATH_YP	"/var/yp/"
41923dc0b2SDavid Nugent #endif
422399cd14SDavid Nugent const char     *Modes[] = {
432399cd14SDavid Nugent   "add", "del", "mod", "show", "next",
442399cd14SDavid Nugent   NULL};
45d6f907dcSJoerg Wunsch const char     *Which[] = {"user", "group", NULL};
4648aee7f3SJoerg Wunsch static const char *Combo1[] = {
4748aee7f3SJoerg Wunsch   "useradd", "userdel", "usermod", "usershow", "usernext",
482399cd14SDavid Nugent   "lock", "unlock",
4948aee7f3SJoerg Wunsch   "groupadd", "groupdel", "groupmod", "groupshow", "groupnext",
50d6f907dcSJoerg Wunsch   NULL};
5148aee7f3SJoerg Wunsch static const char *Combo2[] = {
5248aee7f3SJoerg Wunsch   "adduser", "deluser", "moduser", "showuser", "nextuser",
532399cd14SDavid Nugent   "lock", "unlock",
5448aee7f3SJoerg Wunsch   "addgroup", "delgroup", "modgroup", "showgroup", "nextgroup",
55d6f907dcSJoerg Wunsch   NULL};
56d6f907dcSJoerg Wunsch 
575f12594aSDavid Nugent struct pwf PWF =
585f12594aSDavid Nugent {
595f12594aSDavid Nugent 	0,
605f12594aSDavid Nugent 	setpwent,
615f12594aSDavid Nugent 	endpwent,
625f12594aSDavid Nugent 	getpwent,
635f12594aSDavid Nugent 	getpwuid,
645f12594aSDavid Nugent 	getpwnam,
655f12594aSDavid Nugent 	pwdb,
665f12594aSDavid Nugent 	setgrent,
675f12594aSDavid Nugent 	endgrent,
685f12594aSDavid Nugent 	getgrent,
695f12594aSDavid Nugent 	getgrgid,
705f12594aSDavid Nugent 	getgrnam,
715f12594aSDavid Nugent 	grdb
725f12594aSDavid Nugent 
735f12594aSDavid Nugent };
745f12594aSDavid Nugent struct pwf VPWF =
755f12594aSDavid Nugent {
765f12594aSDavid Nugent 	1,
775f12594aSDavid Nugent 	vsetpwent,
785f12594aSDavid Nugent 	vendpwent,
795f12594aSDavid Nugent 	vgetpwent,
805f12594aSDavid Nugent 	vgetpwuid,
815f12594aSDavid Nugent 	vgetpwnam,
825f12594aSDavid Nugent 	vpwdb,
835f12594aSDavid Nugent 	vsetgrent,
845f12594aSDavid Nugent 	vendgrent,
855f12594aSDavid Nugent 	vgetgrent,
865f12594aSDavid Nugent 	vgetgrgid,
875f12594aSDavid Nugent 	vgetgrnam,
885f12594aSDavid Nugent 	vgrdb
895f12594aSDavid Nugent };
905f12594aSDavid Nugent 
91d6f907dcSJoerg Wunsch static struct cargs arglist;
92d6f907dcSJoerg Wunsch 
93d6f907dcSJoerg Wunsch static int      getindex(const char *words[], const char *word);
94d6f907dcSJoerg Wunsch static void     cmdhelp(int mode, int which);
95d6f907dcSJoerg Wunsch 
96d6f907dcSJoerg Wunsch 
97d6f907dcSJoerg Wunsch int
98d6f907dcSJoerg Wunsch main(int argc, char *argv[])
99d6f907dcSJoerg Wunsch {
100d6f907dcSJoerg Wunsch 	int             ch;
101d6f907dcSJoerg Wunsch 	int             mode = -1;
102d6f907dcSJoerg Wunsch 	int             which = -1;
1035f12594aSDavid Nugent 	char		*config = NULL;
104d6f907dcSJoerg Wunsch 	struct userconf *cnf;
105d6f907dcSJoerg Wunsch 
106d6f907dcSJoerg Wunsch 	static const char *opts[W_NUM][M_NUM] =
107d6f907dcSJoerg Wunsch 	{
10848aee7f3SJoerg Wunsch 		{ /* user */
10987d6b5caSIan Dowse 			"V:C:qn:u:c:d:e:p:g:G:mk:s:oL:i:w:h:H:Db:NPy:Y",
110e3921b27SDavid Nugent 			"V:C:qn:u:rY",
11187d6b5caSIan Dowse 			"V:C:qn:u:c:d:e:p:g:G:ml:k:s:w:L:h:H:FNPY",
112f3522722SDavid Nugent 			"V:C:qn:u:FPa7",
1132399cd14SDavid Nugent 			"V:C:q",
1142399cd14SDavid Nugent 			"V:C:q",
115e3921b27SDavid Nugent 			"V:C:q"
11648aee7f3SJoerg Wunsch 		},
11748aee7f3SJoerg Wunsch 		{ /* grp  */
11887d6b5caSIan Dowse 			"V:C:qn:g:h:H:M:pNPY",
119e3921b27SDavid Nugent 			"V:C:qn:g:Y",
12087d6b5caSIan Dowse 			"V:C:qn:g:l:h:H:FM:m:NPY",
121e3921b27SDavid Nugent 			"V:C:qn:g:FPa",
122e3921b27SDavid Nugent 			"V:C:q"
12348aee7f3SJoerg Wunsch 		 }
124d6f907dcSJoerg Wunsch 	};
125d6f907dcSJoerg Wunsch 
126d6f907dcSJoerg Wunsch 	static int      (*funcs[W_NUM]) (struct userconf * _cnf, int _mode, struct cargs * _args) =
127d6f907dcSJoerg Wunsch 	{			/* Request handlers */
128d6f907dcSJoerg Wunsch 		pw_user,
129d6f907dcSJoerg Wunsch 		pw_group
130d6f907dcSJoerg Wunsch 	};
131d6f907dcSJoerg Wunsch 
132d6f907dcSJoerg Wunsch 	umask(0);		/* We wish to handle this manually */
133d6f907dcSJoerg Wunsch 	LIST_INIT(&arglist);
134d6f907dcSJoerg Wunsch 
13539610c72SAndrey A. Chernov 	(void)setlocale(LC_ALL, "");
136e7161f36SAndrey A. Chernov 
137d6f907dcSJoerg Wunsch 	/*
138d6f907dcSJoerg Wunsch 	 * Break off the first couple of words to determine what exactly
139d6f907dcSJoerg Wunsch 	 * we're being asked to do
140d6f907dcSJoerg Wunsch 	 */
1415f12594aSDavid Nugent 	while (argc > 1) {
142d6f907dcSJoerg Wunsch 		int             tmp;
143d6f907dcSJoerg Wunsch 
1445f12594aSDavid Nugent 		if (*argv[1] == '-') {
1455f12594aSDavid Nugent 			/*
1465f12594aSDavid Nugent 			 * Special case, allow pw -V<dir> <operation> [args] for scripts etc.
1475f12594aSDavid Nugent 			 */
1485f12594aSDavid Nugent 			if (argv[1][1] == 'V') {
1495f12594aSDavid Nugent 				optarg = &argv[1][2];
1505f12594aSDavid Nugent 				if (*optarg == '\0') {
1515f12594aSDavid Nugent 					optarg = argv[2];
1525f12594aSDavid Nugent 					++argv;
1535f12594aSDavid Nugent 					--argc;
1545f12594aSDavid Nugent 				}
1555f12594aSDavid Nugent 				addarg(&arglist, 'V', optarg);
156e3921b27SDavid Nugent 			} else
1575f12594aSDavid Nugent 				break;
1585f12594aSDavid Nugent 		}
159c4e667b9SDavid Nugent 		else if (mode == -1 && (tmp = getindex(Modes, argv[1])) != -1)
160d6f907dcSJoerg Wunsch 			mode = tmp;
161c4e667b9SDavid Nugent 		else if (which == -1 && (tmp = getindex(Which, argv[1])) != -1)
162d6f907dcSJoerg Wunsch 			which = tmp;
163c4e667b9SDavid Nugent 		else if ((mode == -1 && which == -1) &&
164c4e667b9SDavid Nugent 			 ((tmp = getindex(Combo1, argv[1])) != -1 ||
165c4e667b9SDavid Nugent 			  (tmp = getindex(Combo2, argv[1])) != -1)) {
166d6f907dcSJoerg Wunsch 			which = tmp / M_NUM;
167d6f907dcSJoerg Wunsch 			mode = tmp % M_NUM;
168c4e667b9SDavid Nugent 		} else if (strcmp(argv[1], "help") == 0 && argv[2] == NULL)
169d6f907dcSJoerg Wunsch 			cmdhelp(mode, which);
1707291e217SDavid Nugent 		else if (which != -1 && mode != -1)
171d6f907dcSJoerg Wunsch 			addarg(&arglist, 'n', argv[1]);
172d6f907dcSJoerg Wunsch 		else
1731dcc6ec7SPhilippe Charnier 			errx(EX_USAGE, "unknown keyword `%s'", argv[1]);
174d6f907dcSJoerg Wunsch 		++argv;
175d6f907dcSJoerg Wunsch 		--argc;
176d6f907dcSJoerg Wunsch 	}
177d6f907dcSJoerg Wunsch 
178d6f907dcSJoerg Wunsch 	/*
179d6f907dcSJoerg Wunsch 	 * Bail out unless the user is specific!
180d6f907dcSJoerg Wunsch 	 */
181d6f907dcSJoerg Wunsch 	if (mode == -1 || which == -1)
182d6f907dcSJoerg Wunsch 		cmdhelp(mode, which);
183d6f907dcSJoerg Wunsch 
184d6f907dcSJoerg Wunsch 	/*
185d6f907dcSJoerg Wunsch 	 * We know which mode we're in and what we're about to do, so now
186d6f907dcSJoerg Wunsch 	 * let's dispatch the remaining command line args in a genric way.
187d6f907dcSJoerg Wunsch 	 */
188d6f907dcSJoerg Wunsch 	optarg = NULL;
189d6f907dcSJoerg Wunsch 
190d6f907dcSJoerg Wunsch 	while ((ch = getopt(argc, argv, opts[which][mode])) != -1) {
191d6f907dcSJoerg Wunsch 		if (ch == '?')
192923dc0b2SDavid Nugent 			errx(EX_USAGE, "unknown switch");
193d6f907dcSJoerg Wunsch 		else
194d6f907dcSJoerg Wunsch 			addarg(&arglist, ch, optarg);
195d6f907dcSJoerg Wunsch 		optarg = NULL;
196d6f907dcSJoerg Wunsch 	}
197d6f907dcSJoerg Wunsch 
198d6f907dcSJoerg Wunsch 	/*
19948aee7f3SJoerg Wunsch 	 * Must be root to attempt an update
20048aee7f3SJoerg Wunsch 	 */
201fa7e83d4SDavid Nugent 	if (geteuid() != 0 && mode != M_PRINT && mode != M_NEXT && getarg(&arglist, 'N')==NULL)
2021dcc6ec7SPhilippe Charnier 		errx(EX_NOPERM, "you must be root to run this program");
20348aee7f3SJoerg Wunsch 
20448aee7f3SJoerg Wunsch 	/*
205d6f907dcSJoerg Wunsch 	 * We should immediately look for the -q 'quiet' switch so that we
206d6f907dcSJoerg Wunsch 	 * don't bother with extraneous errors
207d6f907dcSJoerg Wunsch 	 */
208d6f907dcSJoerg Wunsch 	if (getarg(&arglist, 'q') != NULL)
2091a37aa56SDavid E. O'Brien 		freopen(_PATH_DEVNULL, "w", stderr);
210d6f907dcSJoerg Wunsch 
211d6f907dcSJoerg Wunsch 	/*
2125f12594aSDavid Nugent 	 * Set our base working path if not overridden
2135f12594aSDavid Nugent 	 */
2145f12594aSDavid Nugent 
2155f12594aSDavid Nugent 	config = getarg(&arglist, 'C') ? getarg(&arglist, 'C')->val : NULL;
2165f12594aSDavid Nugent 
2175f12594aSDavid Nugent 	if (getarg(&arglist, 'V') != NULL) {
2185f12594aSDavid Nugent 		char * etcpath = getarg(&arglist, 'V')->val;
2195f12594aSDavid Nugent 		if (*etcpath) {
2205f12594aSDavid Nugent 			if (config == NULL) {	/* Only override config location if -C not specified */
2215f12594aSDavid Nugent 				config = malloc(MAXPATHLEN);
2225f12594aSDavid Nugent 				snprintf(config, MAXPATHLEN, "%s/pw.conf", etcpath);
2235f12594aSDavid Nugent 			}
2245f12594aSDavid Nugent 			memcpy(&PWF, &VPWF, sizeof PWF);
2255f12594aSDavid Nugent 			setpwdir(etcpath);
2265f12594aSDavid Nugent 			setgrdir(etcpath);
2275f12594aSDavid Nugent 		}
2285f12594aSDavid Nugent 	}
2295f12594aSDavid Nugent 
2305f12594aSDavid Nugent 	/*
231d6f907dcSJoerg Wunsch 	 * Now, let's do the common initialisation
232d6f907dcSJoerg Wunsch 	 */
2335f12594aSDavid Nugent 	cnf = read_userconfig(config);
2345e91a8acSNate Williams 
235f1d684faSDavid Nugent 	ch = funcs[which] (cnf, mode, &arglist);
236f1d684faSDavid Nugent 
237f1d684faSDavid Nugent 	/*
238f1d684faSDavid Nugent 	 * If everything went ok, and we've been asked to update
239f1d684faSDavid Nugent 	 * the NIS maps, then do it now
240f1d684faSDavid Nugent 	 */
241f1d684faSDavid Nugent 	if (ch == EXIT_SUCCESS && getarg(&arglist, 'Y') != NULL) {
242f1d684faSDavid Nugent 		pid_t	pid;
243f1d684faSDavid Nugent 
244f1d684faSDavid Nugent 		fflush(NULL);
245f1d684faSDavid Nugent 		if (chdir(_PATH_YP) == -1)
2461dcc6ec7SPhilippe Charnier 			warn("chdir(" _PATH_YP ")");
247f1d684faSDavid Nugent 		else if ((pid = fork()) == -1)
2481dcc6ec7SPhilippe Charnier 			warn("fork()");
249f1d684faSDavid Nugent 		else if (pid == 0) {
250f1d684faSDavid Nugent 			/* Is make anywhere else? */
2517bc6d015SBrian Somers 			execlp("/usr/bin/make", "make", (char *)NULL);
252f1d684faSDavid Nugent 			_exit(1);
253f1d684faSDavid Nugent 		} else {
254f1d684faSDavid Nugent 			int   i;
255f1d684faSDavid Nugent 			waitpid(pid, &i, 0);
256f1d684faSDavid Nugent 			if ((i = WEXITSTATUS(i)) != 0)
2571dcc6ec7SPhilippe Charnier 				errx(ch, "make exited with status %d", i);
258f1d684faSDavid Nugent 			else
259f1d684faSDavid Nugent 				pw_log(cnf, mode, which, "NIS maps updated");
260f1d684faSDavid Nugent 		}
261f1d684faSDavid Nugent 	}
262f1d684faSDavid Nugent 	return ch;
263d6f907dcSJoerg Wunsch }
264d6f907dcSJoerg Wunsch 
2655e91a8acSNate Williams 
266d6f907dcSJoerg Wunsch static int
267d6f907dcSJoerg Wunsch getindex(const char *words[], const char *word)
268d6f907dcSJoerg Wunsch {
269d6f907dcSJoerg Wunsch 	int             i = 0;
270d6f907dcSJoerg Wunsch 
271d6f907dcSJoerg Wunsch 	while (words[i]) {
272d6f907dcSJoerg Wunsch 		if (strcmp(words[i], word) == 0)
273d6f907dcSJoerg Wunsch 			return i;
274d6f907dcSJoerg Wunsch 		i++;
275d6f907dcSJoerg Wunsch 	}
276d6f907dcSJoerg Wunsch 	return -1;
277d6f907dcSJoerg Wunsch }
278d6f907dcSJoerg Wunsch 
279d6f907dcSJoerg Wunsch 
280d6f907dcSJoerg Wunsch /*
281d6f907dcSJoerg Wunsch  * This is probably an overkill for a cmdline help system, but it reflects
282d6f907dcSJoerg Wunsch  * the complexity of the command line.
283d6f907dcSJoerg Wunsch  */
284d6f907dcSJoerg Wunsch 
285d6f907dcSJoerg Wunsch static void
286d6f907dcSJoerg Wunsch cmdhelp(int mode, int which)
287d6f907dcSJoerg Wunsch {
288d6f907dcSJoerg Wunsch 	if (which == -1)
2892399cd14SDavid Nugent 		fprintf(stderr, "usage:\n  pw [user|group|lock|unlock] [add|del|mod|show|next] [help|switches/values]\n");
290d6f907dcSJoerg Wunsch 	else if (mode == -1)
2912399cd14SDavid Nugent 		fprintf(stderr, "usage:\n  pw %s [add|del|mod|show|next] [help|switches/values]\n", Which[which]);
292d6f907dcSJoerg Wunsch 	else {
293d6f907dcSJoerg Wunsch 
294d6f907dcSJoerg Wunsch 		/*
295d6f907dcSJoerg Wunsch 		 * We need to give mode specific help
296d6f907dcSJoerg Wunsch 		 */
297d6f907dcSJoerg Wunsch 		static const char *help[W_NUM][M_NUM] =
298d6f907dcSJoerg Wunsch 		{
299d6f907dcSJoerg Wunsch 			{
3001dcc6ec7SPhilippe Charnier 				"usage: pw useradd [name] [switches]\n"
3015f12594aSDavid Nugent 				"\t-V etcdir      alternate /etc location\n"
302d6f907dcSJoerg Wunsch 				"\t-C config      configuration file\n"
303d6f907dcSJoerg Wunsch 				"\t-q             quiet operation\n"
304d6f907dcSJoerg Wunsch 				"  Adding users:\n"
305d6f907dcSJoerg Wunsch 				"\t-n name        login name\n"
306d6f907dcSJoerg Wunsch 				"\t-u uid         user id\n"
307d6f907dcSJoerg Wunsch 				"\t-c comment     user name/comment\n"
308d6f907dcSJoerg Wunsch 				"\t-d directory   home directory\n"
309d6f907dcSJoerg Wunsch 				"\t-e date        account expiry date\n"
310d6f907dcSJoerg Wunsch 				"\t-p date        password expiry date\n"
311d6f907dcSJoerg Wunsch 				"\t-g grp         initial group\n"
312d6f907dcSJoerg Wunsch 				"\t-G grp1,grp2   additional groups\n"
313d6f907dcSJoerg Wunsch 				"\t-m [ -k dir ]  create and set up home\n"
314d6f907dcSJoerg Wunsch 				"\t-s shell       name of login shell\n"
315d6f907dcSJoerg Wunsch 				"\t-o             duplicate uid ok\n"
316d6f907dcSJoerg Wunsch 				"\t-L class       user class\n"
317d6f907dcSJoerg Wunsch 				"\t-h fd          read password on fd\n"
31887d6b5caSIan Dowse 				"\t-H fd          read encrypted password on fd\n"
319f1d684faSDavid Nugent 				"\t-Y             update NIS maps\n"
32048aee7f3SJoerg Wunsch 				"\t-N             no update\n"
321d6f907dcSJoerg Wunsch 				"  Setting defaults:\n"
3225f12594aSDavid Nugent 				"\t-V etcdir      alternate /etc location\n"
323d6f907dcSJoerg Wunsch 			        "\t-D             set user defaults\n"
324d6f907dcSJoerg Wunsch 				"\t-b dir         default home root dir\n"
325d6f907dcSJoerg Wunsch 				"\t-e period      default expiry period\n"
326d6f907dcSJoerg Wunsch 				"\t-p period      default password change period\n"
327d6f907dcSJoerg Wunsch 				"\t-g group       default group\n"
328d6f907dcSJoerg Wunsch 				"\t-G grp1,grp2   additional groups\n"
329d6f907dcSJoerg Wunsch 				"\t-L class       default user class\n"
330d6f907dcSJoerg Wunsch 				"\t-k dir         default home skeleton\n"
331d6f907dcSJoerg Wunsch 				"\t-u min,max     set min,max uids\n"
332d6f907dcSJoerg Wunsch 				"\t-i min,max     set min,max gids\n"
333d6f907dcSJoerg Wunsch 				"\t-w method      set default password method\n"
334f1d684faSDavid Nugent 				"\t-s shell       default shell\n"
335f1d684faSDavid Nugent 				"\t-y path        set NIS passwd file path\n",
3361dcc6ec7SPhilippe Charnier 				"usage: pw userdel [uid|name] [switches]\n"
3375f12594aSDavid Nugent 				"\t-V etcdir      alternate /etc location\n"
338d6f907dcSJoerg Wunsch 				"\t-n name        login name\n"
339d6f907dcSJoerg Wunsch 				"\t-u uid         user id\n"
340f1d684faSDavid Nugent 				"\t-Y             update NIS maps\n"
341d6f907dcSJoerg Wunsch 				"\t-r             remove home & contents\n",
3421dcc6ec7SPhilippe Charnier 				"usage: pw usermod [uid|name] [switches]\n"
3435f12594aSDavid Nugent 				"\t-V etcdir      alternate /etc location\n"
344d6f907dcSJoerg Wunsch 				"\t-C config      configuration file\n"
345d6f907dcSJoerg Wunsch 				"\t-q             quiet operation\n"
346d6f907dcSJoerg Wunsch 				"\t-F             force add if no user\n"
347d6f907dcSJoerg Wunsch 				"\t-n name        login name\n"
348d6f907dcSJoerg Wunsch 				"\t-u uid         user id\n"
349d6f907dcSJoerg Wunsch 				"\t-c comment     user name/comment\n"
350d6f907dcSJoerg Wunsch 				"\t-d directory   home directory\n"
351d6f907dcSJoerg Wunsch 				"\t-e date        account expiry date\n"
352d6f907dcSJoerg Wunsch 				"\t-p date        password expiry date\n"
353d6f907dcSJoerg Wunsch 				"\t-g grp         initial group\n"
354d6f907dcSJoerg Wunsch 				"\t-G grp1,grp2   additional groups\n"
355d6f907dcSJoerg Wunsch 				"\t-l name        new login name\n"
356d6f907dcSJoerg Wunsch 				"\t-L class       user class\n"
357d6f907dcSJoerg Wunsch 				"\t-m [ -k dir ]  create and set up home\n"
358d6f907dcSJoerg Wunsch 				"\t-s shell       name of login shell\n"
35948aee7f3SJoerg Wunsch 				"\t-w method      set new password using method\n"
36048aee7f3SJoerg Wunsch 				"\t-h fd          read password on fd\n"
36187d6b5caSIan Dowse 				"\t-H fd          read encrypted password on fd\n"
362f1d684faSDavid Nugent 				"\t-Y             update NIS maps\n"
36348aee7f3SJoerg Wunsch 				"\t-N             no update\n",
3641dcc6ec7SPhilippe Charnier 				"usage: pw usershow [uid|name] [switches]\n"
3655f12594aSDavid Nugent 				"\t-V etcdir      alternate /etc location\n"
366d6f907dcSJoerg Wunsch 				"\t-n name        login name\n"
367d6f907dcSJoerg Wunsch 				"\t-u uid         user id\n"
368d6f907dcSJoerg Wunsch 				"\t-F             force print\n"
36948aee7f3SJoerg Wunsch 				"\t-P             prettier format\n"
370f3522722SDavid Nugent 				"\t-a             print all users\n"
371f3522722SDavid Nugent 				"\t-7             print in v7 format\n",
3721dcc6ec7SPhilippe Charnier 				"usage: pw usernext [switches]\n"
3735f12594aSDavid Nugent 				"\t-V etcdir      alternate /etc location\n"
37448aee7f3SJoerg Wunsch 				"\t-C config      configuration file\n"
375ed6fd55aSDima Dorfman 				"\t-q             quiet operation\n",
376ed6fd55aSDima Dorfman 				"usage pw: lock [switches]\n"
377ed6fd55aSDima Dorfman 				"\t-V etcdir      alternate /etc locations\n"
378ed6fd55aSDima Dorfman 				"\t-C config      configuration file\n"
379ed6fd55aSDima Dorfman 				"\t-q             quiet operation\n",
380ed6fd55aSDima Dorfman 				"usage pw: unlock [switches]\n"
381ed6fd55aSDima Dorfman 				"\t-V etcdir      alternate /etc locations\n"
382ed6fd55aSDima Dorfman 				"\t-C config      configuration file\n"
383ed6fd55aSDima Dorfman 				"\t-q             quiet operation\n"
384d6f907dcSJoerg Wunsch 			},
385d6f907dcSJoerg Wunsch 			{
3861dcc6ec7SPhilippe Charnier 				"usage: pw groupadd [group|gid] [switches]\n"
3875f12594aSDavid Nugent 				"\t-V etcdir      alternate /etc location\n"
388d6f907dcSJoerg Wunsch 				"\t-C config      configuration file\n"
389d6f907dcSJoerg Wunsch 				"\t-q             quiet operation\n"
390d6f907dcSJoerg Wunsch 				"\t-n group       group name\n"
391d6f907dcSJoerg Wunsch 				"\t-g gid         group id\n"
39248aee7f3SJoerg Wunsch 				"\t-M usr1,usr2   add users as group members\n"
39348aee7f3SJoerg Wunsch 				"\t-o             duplicate gid ok\n"
394f1d684faSDavid Nugent 				"\t-Y             update NIS maps\n"
39548aee7f3SJoerg Wunsch 				"\t-N             no update\n",
3961dcc6ec7SPhilippe Charnier 				"usage: pw groupdel [group|gid] [switches]\n"
3975f12594aSDavid Nugent 				"\t-V etcdir      alternate /etc location\n"
398d6f907dcSJoerg Wunsch 				"\t-n name        group name\n"
399f1d684faSDavid Nugent 				"\t-g gid         group id\n"
400f1d684faSDavid Nugent 				"\t-Y             update NIS maps\n",
4011dcc6ec7SPhilippe Charnier 				"usage: pw groupmod [group|gid] [switches]\n"
4025f12594aSDavid Nugent 				"\t-V etcdir      alternate /etc location\n"
403d6f907dcSJoerg Wunsch 				"\t-C config      configuration file\n"
404d6f907dcSJoerg Wunsch 				"\t-q             quiet operation\n"
405d6f907dcSJoerg Wunsch 				"\t-F             force add if not exists\n"
406d6f907dcSJoerg Wunsch 				"\t-n name        group name\n"
407d6f907dcSJoerg Wunsch 				"\t-g gid         group id\n"
40848aee7f3SJoerg Wunsch 				"\t-M usr1,usr2   replaces users as group members\n"
40948aee7f3SJoerg Wunsch 				"\t-m usr1,usr2   add users as group members\n"
41048aee7f3SJoerg Wunsch 				"\t-l name        new group name\n"
411f1d684faSDavid Nugent 				"\t-Y             update NIS maps\n"
41248aee7f3SJoerg Wunsch 				"\t-N             no update\n",
4131dcc6ec7SPhilippe Charnier 				"usage: pw groupshow [group|gid] [switches]\n"
4145f12594aSDavid Nugent 				"\t-V etcdir      alternate /etc location\n"
415d6f907dcSJoerg Wunsch 				"\t-n name        group name\n"
416d6f907dcSJoerg Wunsch 				"\t-g gid         group id\n"
417d6f907dcSJoerg Wunsch 				"\t-F             force print\n"
41848aee7f3SJoerg Wunsch 				"\t-P             prettier format\n"
41948aee7f3SJoerg Wunsch 				"\t-a             print all accounting groups\n",
4201dcc6ec7SPhilippe Charnier 				"usage: pw groupnext [switches]\n"
4215f12594aSDavid Nugent 				"\t-V etcdir      alternate /etc location\n"
42248aee7f3SJoerg Wunsch 				"\t-C config      configuration file\n"
423ed6fd55aSDima Dorfman 				"\t-q             quiet operation\n"
424d6f907dcSJoerg Wunsch 			}
425d6f907dcSJoerg Wunsch 		};
426d6f907dcSJoerg Wunsch 
427cab0fb4eSKris Kennaway 		fprintf(stderr, "%s", help[which][mode]);
428d6f907dcSJoerg Wunsch 	}
42948aee7f3SJoerg Wunsch 	exit(EXIT_FAILURE);
430d6f907dcSJoerg Wunsch }
431d6f907dcSJoerg Wunsch 
432d6f907dcSJoerg Wunsch struct carg    *
433d6f907dcSJoerg Wunsch getarg(struct cargs * _args, int ch)
434d6f907dcSJoerg Wunsch {
435d0d78e13SBen Smithurst 	struct carg    *c = LIST_FIRST(_args);
436d6f907dcSJoerg Wunsch 
437d6f907dcSJoerg Wunsch 	while (c != NULL && c->ch != ch)
438d0d78e13SBen Smithurst 		c = LIST_NEXT(c, list);
439d6f907dcSJoerg Wunsch 	return c;
440d6f907dcSJoerg Wunsch }
441d6f907dcSJoerg Wunsch 
442d6f907dcSJoerg Wunsch struct carg    *
443d6f907dcSJoerg Wunsch addarg(struct cargs * _args, int ch, char *argstr)
444d6f907dcSJoerg Wunsch {
445d6f907dcSJoerg Wunsch 	struct carg    *ca = malloc(sizeof(struct carg));
446d6f907dcSJoerg Wunsch 
447d6f907dcSJoerg Wunsch 	if (ca == NULL)
4481dcc6ec7SPhilippe Charnier 		errx(EX_OSERR, "out of memory");
449d6f907dcSJoerg Wunsch 	ca->ch = ch;
450d6f907dcSJoerg Wunsch 	ca->val = argstr;
451d6f907dcSJoerg Wunsch 	LIST_INSERT_HEAD(_args, ca, list);
452d6f907dcSJoerg Wunsch 	return ca;
453d6f907dcSJoerg Wunsch }
454