xref: /freebsd/usr.sbin/pw/pw.c (revision 4835c3b1df5ea124ae8423ae742e8fb43bcdba77)
1d6f907dcSJoerg Wunsch /*-
21de7b4b8SPedro F. Giffuni  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
31de7b4b8SPedro F. Giffuni  *
4ad7cf975SJoerg Wunsch  * Copyright (C) 1996
5ad7cf975SJoerg Wunsch  *	David L. Nugent.  All rights reserved.
6d6f907dcSJoerg Wunsch  *
7d6f907dcSJoerg Wunsch  * Redistribution and use in source and binary forms, with or without
8d6f907dcSJoerg Wunsch  * modification, are permitted provided that the following conditions
9d6f907dcSJoerg Wunsch  * are met:
10d6f907dcSJoerg Wunsch  * 1. Redistributions of source code must retain the above copyright
11ad7cf975SJoerg Wunsch  *    notice, this list of conditions and the following disclaimer.
12d6f907dcSJoerg Wunsch  * 2. Redistributions in binary form must reproduce the above copyright
13d6f907dcSJoerg Wunsch  *    notice, this list of conditions and the following disclaimer in the
14d6f907dcSJoerg Wunsch  *    documentation and/or other materials provided with the distribution.
15d6f907dcSJoerg Wunsch  *
16ad7cf975SJoerg Wunsch  * THIS SOFTWARE IS PROVIDED BY DAVID L. NUGENT AND CONTRIBUTORS ``AS IS'' AND
17d6f907dcSJoerg Wunsch  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18d6f907dcSJoerg Wunsch  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19ad7cf975SJoerg Wunsch  * ARE DISCLAIMED.  IN NO EVENT SHALL DAVID L. NUGENT OR CONTRIBUTORS BE LIABLE
20d6f907dcSJoerg Wunsch  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21d6f907dcSJoerg Wunsch  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22d6f907dcSJoerg Wunsch  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23d6f907dcSJoerg Wunsch  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24d6f907dcSJoerg Wunsch  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25d6f907dcSJoerg Wunsch  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26d6f907dcSJoerg Wunsch  * SUCH DAMAGE.
27d6f907dcSJoerg Wunsch  */
28d6f907dcSJoerg Wunsch 
291dcc6ec7SPhilippe Charnier #ifndef lint
301dcc6ec7SPhilippe Charnier static const char rcsid[] =
3197d92980SPeter Wemm   "$FreeBSD$";
321dcc6ec7SPhilippe Charnier #endif /* not lint */
331dcc6ec7SPhilippe Charnier 
341dcc6ec7SPhilippe Charnier #include <err.h>
355e91a8acSNate Williams #include <fcntl.h>
36e7161f36SAndrey A. Chernov #include <locale.h>
37bcbdb01eSBaptiste Daroussin #include <string.h>
38bcbdb01eSBaptiste Daroussin #include <sysexits.h>
39bcbdb01eSBaptiste Daroussin #include <unistd.h>
40bcbdb01eSBaptiste Daroussin 
415f12594aSDavid Nugent #include "pw.h"
42d6f907dcSJoerg Wunsch 
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 
88d2d022b9SBaptiste Daroussin static int (*cmdfunc[W_NUM][M_NUM])(int argc, char **argv, char *_name) = {
89d2d022b9SBaptiste Daroussin 	{ /* user */
90d2d022b9SBaptiste Daroussin 		pw_user_add,
91d2d022b9SBaptiste Daroussin 		pw_user_del,
92d2d022b9SBaptiste Daroussin 		pw_user_mod,
93d2d022b9SBaptiste Daroussin 		pw_user_show,
94d2d022b9SBaptiste Daroussin 		pw_user_next,
95d2d022b9SBaptiste Daroussin 		pw_user_lock,
96d2d022b9SBaptiste Daroussin 		pw_user_unlock,
97d2d022b9SBaptiste Daroussin 	},
98d2d022b9SBaptiste Daroussin 	{ /* group */
99d2d022b9SBaptiste Daroussin 		pw_group_add,
100d2d022b9SBaptiste Daroussin 		pw_group_del,
101d2d022b9SBaptiste Daroussin 		pw_group_mod,
102d2d022b9SBaptiste Daroussin 		pw_group_show,
103d2d022b9SBaptiste Daroussin 		pw_group_next,
104d2d022b9SBaptiste Daroussin 	}
105d2d022b9SBaptiste Daroussin };
1062cc63cd1SBaptiste Daroussin 
107d2d022b9SBaptiste Daroussin struct pwconf conf;
108d6f907dcSJoerg Wunsch 
109d6f907dcSJoerg Wunsch static int	getindex(const char *words[], const char *word);
110d6f907dcSJoerg Wunsch static void	cmdhelp(int mode, int which);
111d6f907dcSJoerg Wunsch 
112d6f907dcSJoerg Wunsch int
113d6f907dcSJoerg Wunsch main(int argc, char *argv[])
114d6f907dcSJoerg Wunsch {
115d2d022b9SBaptiste Daroussin 	int		mode = -1, which = -1, tmp;
11690edef4fSBaptiste Daroussin 	struct stat	st;
117d2d022b9SBaptiste Daroussin 	char		arg, *arg1;
11882a3c75aSBaptiste Daroussin 	bool		relocated, nis;
119d6f907dcSJoerg Wunsch 
120d2d022b9SBaptiste Daroussin 	arg1 = NULL;
12182a3c75aSBaptiste Daroussin 	relocated = nis = false;
122bbe09b2eSBaptiste Daroussin 	memset(&conf, 0, sizeof(conf));
12365730d93SBaptiste Daroussin 	strlcpy(conf.rootdir, "/", sizeof(conf.rootdir));
1242cc63cd1SBaptiste Daroussin 	strlcpy(conf.etcpath, _PATH_PWD, sizeof(conf.etcpath));
12511621f96SBaptiste Daroussin 	conf.fd = -1;
126a70fbf7eSBaptiste Daroussin 	conf.checkduplicate = true;
1272cc63cd1SBaptiste Daroussin 
128d2d022b9SBaptiste Daroussin 	setlocale(LC_ALL, "");
129e7161f36SAndrey A. Chernov 
130d6f907dcSJoerg Wunsch 	/*
131d6f907dcSJoerg Wunsch 	 * Break off the first couple of words to determine what exactly
132d6f907dcSJoerg Wunsch 	 * we're being asked to do
133d6f907dcSJoerg Wunsch 	 */
1345f12594aSDavid Nugent 	while (argc > 1) {
1355f12594aSDavid Nugent 		if (*argv[1] == '-') {
1365f12594aSDavid Nugent 			/*
1375f12594aSDavid Nugent 			 * Special case, allow pw -V<dir> <operation> [args] for scripts etc.
1385f12594aSDavid Nugent 			 */
139ac72be28SBaptiste Daroussin 			arg = argv[1][1];
140ac72be28SBaptiste Daroussin 			if (arg == 'V' || arg == 'R') {
1412cc63cd1SBaptiste Daroussin 				if (relocated)
1422cc63cd1SBaptiste Daroussin 					errx(EXIT_FAILURE, "Both '-R' and '-V' "
1432cc63cd1SBaptiste Daroussin 					    "specified, only one accepted");
1442cc63cd1SBaptiste Daroussin 				relocated = true;
1455f12594aSDavid Nugent 				optarg = &argv[1][2];
1465f12594aSDavid Nugent 				if (*optarg == '\0') {
14790edef4fSBaptiste Daroussin 					if (stat(argv[2], &st) != 0)
14890edef4fSBaptiste Daroussin 						errx(EX_OSFILE, \
14990edef4fSBaptiste Daroussin 						    "no such directory `%s'",
15090edef4fSBaptiste Daroussin 						    argv[2]);
15190edef4fSBaptiste Daroussin 					if (!S_ISDIR(st.st_mode))
15290edef4fSBaptiste Daroussin 						errx(EX_OSFILE, "`%s' not a "
15390edef4fSBaptiste Daroussin 						    "directory", argv[2]);
1545f12594aSDavid Nugent 					optarg = argv[2];
1555f12594aSDavid Nugent 					++argv;
1565f12594aSDavid Nugent 					--argc;
1575f12594aSDavid Nugent 				}
1582cc63cd1SBaptiste Daroussin 				memcpy(&PWF, &VPWF, sizeof PWF);
1592cc63cd1SBaptiste Daroussin 				if (arg == 'R') {
1602cc63cd1SBaptiste Daroussin 					strlcpy(conf.rootdir, optarg,
1612cc63cd1SBaptiste Daroussin 					    sizeof(conf.rootdir));
1622cc63cd1SBaptiste Daroussin 					PWF._altdir = PWF_ROOTDIR;
1632cc63cd1SBaptiste Daroussin 				}
1642cc63cd1SBaptiste Daroussin 				snprintf(conf.etcpath, sizeof(conf.etcpath),
165*4835c3b1SYuri Pankov 				    "%s%s", optarg, arg == 'R' ?
166*4835c3b1SYuri Pankov 				    _PATH_PWD : "");
167e3921b27SDavid Nugent 			} else
1685f12594aSDavid Nugent 				break;
1695f12594aSDavid Nugent 		}
170c4e667b9SDavid Nugent 		else if (mode == -1 && (tmp = getindex(Modes, argv[1])) != -1)
171d6f907dcSJoerg Wunsch 			mode = tmp;
172c4e667b9SDavid Nugent 		else if (which == -1 && (tmp = getindex(Which, argv[1])) != -1)
173d6f907dcSJoerg Wunsch 			which = tmp;
174c4e667b9SDavid Nugent 		else if ((mode == -1 && which == -1) &&
175c4e667b9SDavid Nugent 			 ((tmp = getindex(Combo1, argv[1])) != -1 ||
176c4e667b9SDavid Nugent 			  (tmp = getindex(Combo2, argv[1])) != -1)) {
177d6f907dcSJoerg Wunsch 			which = tmp / M_NUM;
178d6f907dcSJoerg Wunsch 			mode = tmp % M_NUM;
179c4e667b9SDavid Nugent 		} else if (strcmp(argv[1], "help") == 0 && argv[2] == NULL)
180d6f907dcSJoerg Wunsch 			cmdhelp(mode, which);
181d2d022b9SBaptiste Daroussin 		else if (which != -1 && mode != -1)
182d2d022b9SBaptiste Daroussin 				arg1 = argv[1];
183d2d022b9SBaptiste Daroussin 		else
1841dcc6ec7SPhilippe Charnier 			errx(EX_USAGE, "unknown keyword `%s'", argv[1]);
185d6f907dcSJoerg Wunsch 		++argv;
186d6f907dcSJoerg Wunsch 		--argc;
187d6f907dcSJoerg Wunsch 	}
188d6f907dcSJoerg Wunsch 
189d6f907dcSJoerg Wunsch 	/*
190d6f907dcSJoerg Wunsch 	 * Bail out unless the user is specific!
191d6f907dcSJoerg Wunsch 	 */
192d6f907dcSJoerg Wunsch 	if (mode == -1 || which == -1)
193d6f907dcSJoerg Wunsch 		cmdhelp(mode, which);
194d6f907dcSJoerg Wunsch 
19565730d93SBaptiste Daroussin 	conf.rootfd = open(conf.rootdir, O_DIRECTORY|O_CLOEXEC);
19665730d93SBaptiste Daroussin 	if (conf.rootfd == -1)
19765730d93SBaptiste Daroussin 		errx(EXIT_FAILURE, "Unable to open '%s'", conf.rootdir);
198d6f907dcSJoerg Wunsch 
199d2d022b9SBaptiste Daroussin 	return (cmdfunc[which][mode](argc, argv, arg1));
200d6f907dcSJoerg Wunsch }
201d6f907dcSJoerg Wunsch 
2025e91a8acSNate Williams 
203d6f907dcSJoerg Wunsch static int
204d6f907dcSJoerg Wunsch getindex(const char *words[], const char *word)
205d6f907dcSJoerg Wunsch {
206d6f907dcSJoerg Wunsch 	int	i = 0;
207d6f907dcSJoerg Wunsch 
208d6f907dcSJoerg Wunsch 	while (words[i]) {
209d6f907dcSJoerg Wunsch 		if (strcmp(words[i], word) == 0)
210d2d022b9SBaptiste Daroussin 			return (i);
211d6f907dcSJoerg Wunsch 		i++;
212d6f907dcSJoerg Wunsch 	}
213d2d022b9SBaptiste Daroussin 	return (-1);
214d6f907dcSJoerg Wunsch }
215d6f907dcSJoerg Wunsch 
216d6f907dcSJoerg Wunsch 
217d6f907dcSJoerg Wunsch /*
218d6f907dcSJoerg Wunsch  * This is probably an overkill for a cmdline help system, but it reflects
219d6f907dcSJoerg Wunsch  * the complexity of the command line.
220d6f907dcSJoerg Wunsch  */
221d6f907dcSJoerg Wunsch 
222d6f907dcSJoerg Wunsch static void
223d6f907dcSJoerg Wunsch cmdhelp(int mode, int which)
224d6f907dcSJoerg Wunsch {
225d6f907dcSJoerg Wunsch 	if (which == -1)
2262399cd14SDavid Nugent 		fprintf(stderr, "usage:\n  pw [user|group|lock|unlock] [add|del|mod|show|next] [help|switches/values]\n");
227d6f907dcSJoerg Wunsch 	else if (mode == -1)
2282399cd14SDavid Nugent 		fprintf(stderr, "usage:\n  pw %s [add|del|mod|show|next] [help|switches/values]\n", Which[which]);
229d6f907dcSJoerg Wunsch 	else {
230d6f907dcSJoerg Wunsch 
231d6f907dcSJoerg Wunsch 		/*
232d6f907dcSJoerg Wunsch 		 * We need to give mode specific help
233d6f907dcSJoerg Wunsch 		 */
234d6f907dcSJoerg Wunsch 		static const char *help[W_NUM][M_NUM] =
235d6f907dcSJoerg Wunsch 		{
236d6f907dcSJoerg Wunsch 			{
2371dcc6ec7SPhilippe Charnier 				"usage: pw useradd [name] [switches]\n"
2385f12594aSDavid Nugent 				"\t-V etcdir      alternate /etc location\n"
2396a3133efSWarren Block 				"\t-R rootdir     alternate root directory\n"
240d6f907dcSJoerg Wunsch 				"\t-C config      configuration file\n"
241d6f907dcSJoerg Wunsch 				"\t-q             quiet operation\n"
242d6f907dcSJoerg Wunsch 				"  Adding users:\n"
243d6f907dcSJoerg Wunsch 				"\t-n name        login name\n"
244d6f907dcSJoerg Wunsch 				"\t-u uid         user id\n"
245d6f907dcSJoerg Wunsch 				"\t-c comment     user name/comment\n"
246d6f907dcSJoerg Wunsch 				"\t-d directory   home directory\n"
247d6f907dcSJoerg Wunsch 				"\t-e date        account expiry date\n"
248d6f907dcSJoerg Wunsch 				"\t-p date        password expiry date\n"
249d6f907dcSJoerg Wunsch 				"\t-g grp         initial group\n"
250d6f907dcSJoerg Wunsch 				"\t-G grp1,grp2   additional groups\n"
251d6f907dcSJoerg Wunsch 				"\t-m [ -k dir ]  create and set up home\n"
2521dd634b0SLukas Ertl 				"\t-M mode        home directory permissions\n"
253d6f907dcSJoerg Wunsch 				"\t-s shell       name of login shell\n"
254d6f907dcSJoerg Wunsch 				"\t-o             duplicate uid ok\n"
255d6f907dcSJoerg Wunsch 				"\t-L class       user class\n"
256d6f907dcSJoerg Wunsch 				"\t-h fd          read password on fd\n"
25787d6b5caSIan Dowse 				"\t-H fd          read encrypted password on fd\n"
258f1d684faSDavid Nugent 				"\t-Y             update NIS maps\n"
25948aee7f3SJoerg Wunsch 				"\t-N             no update\n"
260d6f907dcSJoerg Wunsch 				"  Setting defaults:\n"
2615f12594aSDavid Nugent 				"\t-V etcdir      alternate /etc location\n"
2626a3133efSWarren Block 				"\t-R rootdir     alternate root directory\n"
263d6f907dcSJoerg Wunsch 				"\t-D             set user defaults\n"
264d6f907dcSJoerg Wunsch 				"\t-b dir         default home root dir\n"
265d6f907dcSJoerg Wunsch 				"\t-e period      default expiry period\n"
266d6f907dcSJoerg Wunsch 				"\t-p period      default password change period\n"
267d6f907dcSJoerg Wunsch 				"\t-g group       default group\n"
268d6f907dcSJoerg Wunsch 				"\t-G grp1,grp2   additional groups\n"
269d6f907dcSJoerg Wunsch 				"\t-L class       default user class\n"
270d6f907dcSJoerg Wunsch 				"\t-k dir         default home skeleton\n"
27185204142SLukas Ertl 				"\t-M mode        home directory permissions\n"
272d6f907dcSJoerg Wunsch 				"\t-u min,max     set min,max uids\n"
273d6f907dcSJoerg Wunsch 				"\t-i min,max     set min,max gids\n"
274d6f907dcSJoerg Wunsch 				"\t-w method      set default password method\n"
275f1d684faSDavid Nugent 				"\t-s shell       default shell\n"
276f1d684faSDavid Nugent 				"\t-y path        set NIS passwd file path\n",
2771dcc6ec7SPhilippe Charnier 				"usage: pw userdel [uid|name] [switches]\n"
2785f12594aSDavid Nugent 				"\t-V etcdir      alternate /etc location\n"
2796a3133efSWarren Block 				"\t-R rootdir     alternate root directory\n"
280d6f907dcSJoerg Wunsch 				"\t-n name        login name\n"
281d6f907dcSJoerg Wunsch 				"\t-u uid         user id\n"
282f1d684faSDavid Nugent 				"\t-Y             update NIS maps\n"
283d2d022b9SBaptiste Daroussin 				"\t-y path        set NIS passwd file path\n"
284d6f907dcSJoerg Wunsch 				"\t-r             remove home & contents\n",
2851dcc6ec7SPhilippe Charnier 				"usage: pw usermod [uid|name] [switches]\n"
2865f12594aSDavid Nugent 				"\t-V etcdir      alternate /etc location\n"
2876a3133efSWarren Block 				"\t-R rootdir     alternate root directory\n"
288d6f907dcSJoerg Wunsch 				"\t-C config      configuration file\n"
289d6f907dcSJoerg Wunsch 				"\t-q             quiet operation\n"
290d6f907dcSJoerg Wunsch 				"\t-F             force add if no user\n"
291d6f907dcSJoerg Wunsch 				"\t-n name        login name\n"
292d6f907dcSJoerg Wunsch 				"\t-u uid         user id\n"
293d6f907dcSJoerg Wunsch 				"\t-c comment     user name/comment\n"
294d6f907dcSJoerg Wunsch 				"\t-d directory   home directory\n"
295d6f907dcSJoerg Wunsch 				"\t-e date        account expiry date\n"
296d6f907dcSJoerg Wunsch 				"\t-p date        password expiry date\n"
297d6f907dcSJoerg Wunsch 				"\t-g grp         initial group\n"
298d6f907dcSJoerg Wunsch 				"\t-G grp1,grp2   additional groups\n"
299d6f907dcSJoerg Wunsch 				"\t-l name        new login name\n"
300d6f907dcSJoerg Wunsch 				"\t-L class       user class\n"
301d6f907dcSJoerg Wunsch 				"\t-m [ -k dir ]  create and set up home\n"
3021dd634b0SLukas Ertl 				"\t-M mode        home directory permissions\n"
303d6f907dcSJoerg Wunsch 				"\t-s shell       name of login shell\n"
30448aee7f3SJoerg Wunsch 				"\t-w method      set new password using method\n"
30548aee7f3SJoerg Wunsch 				"\t-h fd          read password on fd\n"
30687d6b5caSIan Dowse 				"\t-H fd          read encrypted password on fd\n"
307f1d684faSDavid Nugent 				"\t-Y             update NIS maps\n"
308d2d022b9SBaptiste Daroussin 				"\t-y path        set NIS passwd file path\n"
30948aee7f3SJoerg Wunsch 				"\t-N             no update\n",
3101dcc6ec7SPhilippe Charnier 				"usage: pw usershow [uid|name] [switches]\n"
3115f12594aSDavid Nugent 				"\t-V etcdir      alternate /etc location\n"
3126a3133efSWarren Block 				"\t-R rootdir     alternate root directory\n"
313d6f907dcSJoerg Wunsch 				"\t-n name        login name\n"
314d6f907dcSJoerg Wunsch 				"\t-u uid         user id\n"
315d6f907dcSJoerg Wunsch 				"\t-F             force print\n"
31648aee7f3SJoerg Wunsch 				"\t-P             prettier format\n"
317f3522722SDavid Nugent 				"\t-a             print all users\n"
318f3522722SDavid Nugent 				"\t-7             print in v7 format\n",
3191dcc6ec7SPhilippe Charnier 				"usage: pw usernext [switches]\n"
3205f12594aSDavid Nugent 				"\t-V etcdir      alternate /etc location\n"
3216a3133efSWarren Block 				"\t-R rootdir     alternate root directory\n"
3223bfc59e8SBaptiste Daroussin 				"\t-C config      configuration file\n"
3233bfc59e8SBaptiste Daroussin 				"\t-q             quiet operation\n",
324ed6fd55aSDima Dorfman 				"usage pw: lock [switches]\n"
325ed6fd55aSDima Dorfman 				"\t-V etcdir      alternate /etc locations\n"
326ed6fd55aSDima Dorfman 				"\t-C config      configuration file\n"
327ed6fd55aSDima Dorfman 				"\t-q             quiet operation\n",
328ed6fd55aSDima Dorfman 				"usage pw: unlock [switches]\n"
329ed6fd55aSDima Dorfman 				"\t-V etcdir      alternate /etc locations\n"
330ed6fd55aSDima Dorfman 				"\t-C config      configuration file\n"
331ed6fd55aSDima Dorfman 				"\t-q             quiet operation\n"
332d6f907dcSJoerg Wunsch 			},
333d6f907dcSJoerg Wunsch 			{
3341dcc6ec7SPhilippe Charnier 				"usage: pw groupadd [group|gid] [switches]\n"
3355f12594aSDavid Nugent 				"\t-V etcdir      alternate /etc location\n"
3366a3133efSWarren Block 				"\t-R rootdir     alternate root directory\n"
337d6f907dcSJoerg Wunsch 				"\t-C config      configuration file\n"
338d6f907dcSJoerg Wunsch 				"\t-q             quiet operation\n"
339d6f907dcSJoerg Wunsch 				"\t-n group       group name\n"
340d6f907dcSJoerg Wunsch 				"\t-g gid         group id\n"
34148aee7f3SJoerg Wunsch 				"\t-M usr1,usr2   add users as group members\n"
34248aee7f3SJoerg Wunsch 				"\t-o             duplicate gid ok\n"
343f1d684faSDavid Nugent 				"\t-Y             update NIS maps\n"
34448aee7f3SJoerg Wunsch 				"\t-N             no update\n",
3451dcc6ec7SPhilippe Charnier 				"usage: pw groupdel [group|gid] [switches]\n"
3465f12594aSDavid Nugent 				"\t-V etcdir      alternate /etc location\n"
3476a3133efSWarren Block 				"\t-R rootdir     alternate root directory\n"
348d6f907dcSJoerg Wunsch 				"\t-n name        group name\n"
349f1d684faSDavid Nugent 				"\t-g gid         group id\n"
350f1d684faSDavid Nugent 				"\t-Y             update NIS maps\n",
3511dcc6ec7SPhilippe Charnier 				"usage: pw groupmod [group|gid] [switches]\n"
3525f12594aSDavid Nugent 				"\t-V etcdir      alternate /etc location\n"
3536a3133efSWarren Block 				"\t-R rootdir     alternate root directory\n"
354d6f907dcSJoerg Wunsch 				"\t-C config      configuration file\n"
355d6f907dcSJoerg Wunsch 				"\t-q             quiet operation\n"
356d6f907dcSJoerg Wunsch 				"\t-F             force add if not exists\n"
357d6f907dcSJoerg Wunsch 				"\t-n name        group name\n"
358d6f907dcSJoerg Wunsch 				"\t-g gid         group id\n"
35948aee7f3SJoerg Wunsch 				"\t-M usr1,usr2   replaces users as group members\n"
36048aee7f3SJoerg Wunsch 				"\t-m usr1,usr2   add users as group members\n"
361bc991a6dSSean Farley 				"\t-d usr1,usr2   delete users as group members\n"
36248aee7f3SJoerg Wunsch 				"\t-l name        new group name\n"
363f1d684faSDavid Nugent 				"\t-Y             update NIS maps\n"
36448aee7f3SJoerg Wunsch 				"\t-N             no update\n",
3651dcc6ec7SPhilippe Charnier 				"usage: pw groupshow [group|gid] [switches]\n"
3665f12594aSDavid Nugent 				"\t-V etcdir      alternate /etc location\n"
3676a3133efSWarren Block 				"\t-R rootdir     alternate root directory\n"
368d6f907dcSJoerg Wunsch 				"\t-n name        group name\n"
369d6f907dcSJoerg Wunsch 				"\t-g gid         group id\n"
370d6f907dcSJoerg Wunsch 				"\t-F             force print\n"
37148aee7f3SJoerg Wunsch 				"\t-P             prettier format\n"
37248aee7f3SJoerg Wunsch 				"\t-a             print all accounting groups\n",
3731dcc6ec7SPhilippe Charnier 				"usage: pw groupnext [switches]\n"
3745f12594aSDavid Nugent 				"\t-V etcdir      alternate /etc location\n"
3756a3133efSWarren Block 				"\t-R rootdir     alternate root directory\n"
37648aee7f3SJoerg Wunsch 				"\t-C config      configuration file\n"
3773bfc59e8SBaptiste Daroussin 				"\t-q             quiet operation\n"
378d6f907dcSJoerg Wunsch 			}
379d6f907dcSJoerg Wunsch 		};
380d6f907dcSJoerg Wunsch 
381cab0fb4eSKris Kennaway 		fprintf(stderr, "%s", help[which][mode]);
382d6f907dcSJoerg Wunsch 	}
38348aee7f3SJoerg Wunsch 	exit(EXIT_FAILURE);
384d6f907dcSJoerg Wunsch }
385