xref: /freebsd/usr.sbin/pw/pw.c (revision 90edef4fe08a34a5144d81e5b564a460d34b8e29)
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 	setgrent,
665f12594aSDavid Nugent 	endgrent,
675f12594aSDavid Nugent 	getgrent,
685f12594aSDavid Nugent 	getgrgid,
695f12594aSDavid Nugent 	getgrnam,
705f12594aSDavid Nugent 
715f12594aSDavid Nugent };
725f12594aSDavid Nugent struct pwf VPWF =
735f12594aSDavid Nugent {
745f12594aSDavid Nugent 	1,
755f12594aSDavid Nugent 	vsetpwent,
765f12594aSDavid Nugent 	vendpwent,
775f12594aSDavid Nugent 	vgetpwent,
785f12594aSDavid Nugent 	vgetpwuid,
795f12594aSDavid Nugent 	vgetpwnam,
805f12594aSDavid Nugent 	vsetgrent,
815f12594aSDavid Nugent 	vendgrent,
825f12594aSDavid Nugent 	vgetgrent,
835f12594aSDavid Nugent 	vgetgrgid,
845f12594aSDavid Nugent 	vgetgrnam,
855f12594aSDavid Nugent };
865f12594aSDavid Nugent 
87d6f907dcSJoerg Wunsch static struct cargs arglist;
88d6f907dcSJoerg Wunsch 
89d6f907dcSJoerg Wunsch static int      getindex(const char *words[], const char *word);
90d6f907dcSJoerg Wunsch static void     cmdhelp(int mode, int which);
91d6f907dcSJoerg Wunsch 
92d6f907dcSJoerg Wunsch 
93d6f907dcSJoerg Wunsch int
94d6f907dcSJoerg Wunsch main(int argc, char *argv[])
95d6f907dcSJoerg Wunsch {
96d6f907dcSJoerg Wunsch 	int             ch;
97d6f907dcSJoerg Wunsch 	int             mode = -1;
98d6f907dcSJoerg Wunsch 	int             which = -1;
995f12594aSDavid Nugent 	char		*config = NULL;
100d6f907dcSJoerg Wunsch 	struct userconf *cnf;
101*90edef4fSBaptiste Daroussin 	struct stat	st;
102d6f907dcSJoerg Wunsch 
103d6f907dcSJoerg Wunsch 	static const char *opts[W_NUM][M_NUM] =
104d6f907dcSJoerg Wunsch 	{
10548aee7f3SJoerg Wunsch 		{ /* user */
106eebbeceeSLukas Ertl 			"V:C:qn:u:c:d:e:p:g:G:mM:k:s:oL:i:w:h:H:Db:NPy:Y",
107e3921b27SDavid Nugent 			"V:C:qn:u:rY",
108eebbeceeSLukas Ertl 			"V:C:qn:u:c:d:e:p:g:G:mM:l:k:s:w:L:h:H:FNPY",
109f3522722SDavid Nugent 			"V:C:qn:u:FPa7",
1102399cd14SDavid Nugent 			"V:C:q",
1112399cd14SDavid Nugent 			"V:C:q",
112e3921b27SDavid Nugent 			"V:C:q"
11348aee7f3SJoerg Wunsch 		},
11448aee7f3SJoerg Wunsch 		{ /* grp  */
11504cfd91bSMaxim Konovalov 			"V:C:qn:g:h:H:M:opNPY",
116e3921b27SDavid Nugent 			"V:C:qn:g:Y",
117bc991a6dSSean Farley 			"V:C:qn:d:g:l:h:H:FM:m:NPY",
118e3921b27SDavid Nugent 			"V:C:qn:g:FPa",
119e3921b27SDavid Nugent 			"V:C:q"
12048aee7f3SJoerg Wunsch 		 }
121d6f907dcSJoerg Wunsch 	};
122d6f907dcSJoerg Wunsch 
123d6f907dcSJoerg Wunsch 	static int      (*funcs[W_NUM]) (struct userconf * _cnf, int _mode, struct cargs * _args) =
124d6f907dcSJoerg Wunsch 	{			/* Request handlers */
125d6f907dcSJoerg Wunsch 		pw_user,
126d6f907dcSJoerg Wunsch 		pw_group
127d6f907dcSJoerg Wunsch 	};
128d6f907dcSJoerg Wunsch 
129d6f907dcSJoerg Wunsch 	LIST_INIT(&arglist);
130d6f907dcSJoerg Wunsch 
13139610c72SAndrey A. Chernov 	(void)setlocale(LC_ALL, "");
132e7161f36SAndrey A. Chernov 
133d6f907dcSJoerg Wunsch 	/*
134d6f907dcSJoerg Wunsch 	 * Break off the first couple of words to determine what exactly
135d6f907dcSJoerg Wunsch 	 * we're being asked to do
136d6f907dcSJoerg Wunsch 	 */
1375f12594aSDavid Nugent 	while (argc > 1) {
138d6f907dcSJoerg Wunsch 		int             tmp;
139d6f907dcSJoerg Wunsch 
1405f12594aSDavid Nugent 		if (*argv[1] == '-') {
1415f12594aSDavid Nugent 			/*
1425f12594aSDavid Nugent 			 * Special case, allow pw -V<dir> <operation> [args] for scripts etc.
1435f12594aSDavid Nugent 			 */
1445f12594aSDavid Nugent 			if (argv[1][1] == 'V') {
1455f12594aSDavid Nugent 				optarg = &argv[1][2];
1465f12594aSDavid Nugent 				if (*optarg == '\0') {
147*90edef4fSBaptiste Daroussin 					if (stat(argv[2], &st) != 0)
148*90edef4fSBaptiste Daroussin 						errx(EX_OSFILE, \
149*90edef4fSBaptiste Daroussin 						    "no such directory `%s'",
150*90edef4fSBaptiste Daroussin 						    argv[2]);
151*90edef4fSBaptiste Daroussin 					if (!S_ISDIR(st.st_mode))
152*90edef4fSBaptiste Daroussin 						errx(EX_OSFILE, "`%s' not a "
153*90edef4fSBaptiste Daroussin 						    "directory", argv[2]);
1545f12594aSDavid Nugent 					optarg = argv[2];
1555f12594aSDavid Nugent 					++argv;
1565f12594aSDavid Nugent 					--argc;
1575f12594aSDavid Nugent 				}
1585f12594aSDavid Nugent 				addarg(&arglist, 'V', optarg);
159e3921b27SDavid Nugent 			} else
1605f12594aSDavid Nugent 				break;
1615f12594aSDavid Nugent 		}
162c4e667b9SDavid Nugent 		else if (mode == -1 && (tmp = getindex(Modes, argv[1])) != -1)
163d6f907dcSJoerg Wunsch 			mode = tmp;
164c4e667b9SDavid Nugent 		else if (which == -1 && (tmp = getindex(Which, argv[1])) != -1)
165d6f907dcSJoerg Wunsch 			which = tmp;
166c4e667b9SDavid Nugent 		else if ((mode == -1 && which == -1) &&
167c4e667b9SDavid Nugent 			 ((tmp = getindex(Combo1, argv[1])) != -1 ||
168c4e667b9SDavid Nugent 			  (tmp = getindex(Combo2, argv[1])) != -1)) {
169d6f907dcSJoerg Wunsch 			which = tmp / M_NUM;
170d6f907dcSJoerg Wunsch 			mode = tmp % M_NUM;
171c4e667b9SDavid Nugent 		} else if (strcmp(argv[1], "help") == 0 && argv[2] == NULL)
172d6f907dcSJoerg Wunsch 			cmdhelp(mode, which);
1737291e217SDavid Nugent 		else if (which != -1 && mode != -1)
174d6f907dcSJoerg Wunsch 			addarg(&arglist, 'n', argv[1]);
175d6f907dcSJoerg Wunsch 		else
1761dcc6ec7SPhilippe Charnier 			errx(EX_USAGE, "unknown keyword `%s'", argv[1]);
177d6f907dcSJoerg Wunsch 		++argv;
178d6f907dcSJoerg Wunsch 		--argc;
179d6f907dcSJoerg Wunsch 	}
180d6f907dcSJoerg Wunsch 
181d6f907dcSJoerg Wunsch 	/*
182d6f907dcSJoerg Wunsch 	 * Bail out unless the user is specific!
183d6f907dcSJoerg Wunsch 	 */
184d6f907dcSJoerg Wunsch 	if (mode == -1 || which == -1)
185d6f907dcSJoerg Wunsch 		cmdhelp(mode, which);
186d6f907dcSJoerg Wunsch 
187d6f907dcSJoerg Wunsch 	/*
188d6f907dcSJoerg Wunsch 	 * We know which mode we're in and what we're about to do, so now
189d6f907dcSJoerg Wunsch 	 * let's dispatch the remaining command line args in a genric way.
190d6f907dcSJoerg Wunsch 	 */
191d6f907dcSJoerg Wunsch 	optarg = NULL;
192d6f907dcSJoerg Wunsch 
193d6f907dcSJoerg Wunsch 	while ((ch = getopt(argc, argv, opts[which][mode])) != -1) {
194d6f907dcSJoerg Wunsch 		if (ch == '?')
195923dc0b2SDavid Nugent 			errx(EX_USAGE, "unknown switch");
196d6f907dcSJoerg Wunsch 		else
197d6f907dcSJoerg Wunsch 			addarg(&arglist, ch, optarg);
198d6f907dcSJoerg Wunsch 		optarg = NULL;
199d6f907dcSJoerg Wunsch 	}
200d6f907dcSJoerg Wunsch 
201d6f907dcSJoerg Wunsch 	/*
20248aee7f3SJoerg Wunsch 	 * Must be root to attempt an update
20348aee7f3SJoerg Wunsch 	 */
204fa7e83d4SDavid Nugent 	if (geteuid() != 0 && mode != M_PRINT && mode != M_NEXT && getarg(&arglist, 'N')==NULL)
2051dcc6ec7SPhilippe Charnier 		errx(EX_NOPERM, "you must be root to run this program");
20648aee7f3SJoerg Wunsch 
20748aee7f3SJoerg Wunsch 	/*
208d6f907dcSJoerg Wunsch 	 * We should immediately look for the -q 'quiet' switch so that we
209d6f907dcSJoerg Wunsch 	 * don't bother with extraneous errors
210d6f907dcSJoerg Wunsch 	 */
211d6f907dcSJoerg Wunsch 	if (getarg(&arglist, 'q') != NULL)
2121a37aa56SDavid E. O'Brien 		freopen(_PATH_DEVNULL, "w", stderr);
213d6f907dcSJoerg Wunsch 
214d6f907dcSJoerg Wunsch 	/*
2155f12594aSDavid Nugent 	 * Set our base working path if not overridden
2165f12594aSDavid Nugent 	 */
2175f12594aSDavid Nugent 
2185f12594aSDavid Nugent 	config = getarg(&arglist, 'C') ? getarg(&arglist, 'C')->val : NULL;
2195f12594aSDavid Nugent 
2205f12594aSDavid Nugent 	if (getarg(&arglist, 'V') != NULL) {
2215f12594aSDavid Nugent 		char * etcpath = getarg(&arglist, 'V')->val;
2225f12594aSDavid Nugent 		if (*etcpath) {
2235f12594aSDavid Nugent 			if (config == NULL) {	/* Only override config location if -C not specified */
2245f12594aSDavid Nugent 				config = malloc(MAXPATHLEN);
2255f12594aSDavid Nugent 				snprintf(config, MAXPATHLEN, "%s/pw.conf", etcpath);
2265f12594aSDavid Nugent 			}
2275f12594aSDavid Nugent 			memcpy(&PWF, &VPWF, sizeof PWF);
2285f12594aSDavid Nugent 			setpwdir(etcpath);
2295f12594aSDavid Nugent 			setgrdir(etcpath);
2305f12594aSDavid Nugent 		}
2315f12594aSDavid Nugent 	}
2325f12594aSDavid Nugent 
2335f12594aSDavid Nugent 	/*
234d6f907dcSJoerg Wunsch 	 * Now, let's do the common initialisation
235d6f907dcSJoerg Wunsch 	 */
2365f12594aSDavid Nugent 	cnf = read_userconfig(config);
2375e91a8acSNate Williams 
238f1d684faSDavid Nugent 	ch = funcs[which] (cnf, mode, &arglist);
239f1d684faSDavid Nugent 
240f1d684faSDavid Nugent 	/*
241f1d684faSDavid Nugent 	 * If everything went ok, and we've been asked to update
242f1d684faSDavid Nugent 	 * the NIS maps, then do it now
243f1d684faSDavid Nugent 	 */
244f1d684faSDavid Nugent 	if (ch == EXIT_SUCCESS && getarg(&arglist, 'Y') != NULL) {
245f1d684faSDavid Nugent 		pid_t	pid;
246f1d684faSDavid Nugent 
247f1d684faSDavid Nugent 		fflush(NULL);
248f1d684faSDavid Nugent 		if (chdir(_PATH_YP) == -1)
2491dcc6ec7SPhilippe Charnier 			warn("chdir(" _PATH_YP ")");
250f1d684faSDavid Nugent 		else if ((pid = fork()) == -1)
2511dcc6ec7SPhilippe Charnier 			warn("fork()");
252f1d684faSDavid Nugent 		else if (pid == 0) {
253f1d684faSDavid Nugent 			/* Is make anywhere else? */
2547bc6d015SBrian Somers 			execlp("/usr/bin/make", "make", (char *)NULL);
255f1d684faSDavid Nugent 			_exit(1);
256f1d684faSDavid Nugent 		} else {
257f1d684faSDavid Nugent 			int   i;
258f1d684faSDavid Nugent 			waitpid(pid, &i, 0);
259f1d684faSDavid Nugent 			if ((i = WEXITSTATUS(i)) != 0)
2601dcc6ec7SPhilippe Charnier 				errx(ch, "make exited with status %d", i);
261f1d684faSDavid Nugent 			else
262f1d684faSDavid Nugent 				pw_log(cnf, mode, which, "NIS maps updated");
263f1d684faSDavid Nugent 		}
264f1d684faSDavid Nugent 	}
265f1d684faSDavid Nugent 	return ch;
266d6f907dcSJoerg Wunsch }
267d6f907dcSJoerg Wunsch 
2685e91a8acSNate Williams 
269d6f907dcSJoerg Wunsch static int
270d6f907dcSJoerg Wunsch getindex(const char *words[], const char *word)
271d6f907dcSJoerg Wunsch {
272d6f907dcSJoerg Wunsch 	int             i = 0;
273d6f907dcSJoerg Wunsch 
274d6f907dcSJoerg Wunsch 	while (words[i]) {
275d6f907dcSJoerg Wunsch 		if (strcmp(words[i], word) == 0)
276d6f907dcSJoerg Wunsch 			return i;
277d6f907dcSJoerg Wunsch 		i++;
278d6f907dcSJoerg Wunsch 	}
279d6f907dcSJoerg Wunsch 	return -1;
280d6f907dcSJoerg Wunsch }
281d6f907dcSJoerg Wunsch 
282d6f907dcSJoerg Wunsch 
283d6f907dcSJoerg Wunsch /*
284d6f907dcSJoerg Wunsch  * This is probably an overkill for a cmdline help system, but it reflects
285d6f907dcSJoerg Wunsch  * the complexity of the command line.
286d6f907dcSJoerg Wunsch  */
287d6f907dcSJoerg Wunsch 
288d6f907dcSJoerg Wunsch static void
289d6f907dcSJoerg Wunsch cmdhelp(int mode, int which)
290d6f907dcSJoerg Wunsch {
291d6f907dcSJoerg Wunsch 	if (which == -1)
2922399cd14SDavid Nugent 		fprintf(stderr, "usage:\n  pw [user|group|lock|unlock] [add|del|mod|show|next] [help|switches/values]\n");
293d6f907dcSJoerg Wunsch 	else if (mode == -1)
2942399cd14SDavid Nugent 		fprintf(stderr, "usage:\n  pw %s [add|del|mod|show|next] [help|switches/values]\n", Which[which]);
295d6f907dcSJoerg Wunsch 	else {
296d6f907dcSJoerg Wunsch 
297d6f907dcSJoerg Wunsch 		/*
298d6f907dcSJoerg Wunsch 		 * We need to give mode specific help
299d6f907dcSJoerg Wunsch 		 */
300d6f907dcSJoerg Wunsch 		static const char *help[W_NUM][M_NUM] =
301d6f907dcSJoerg Wunsch 		{
302d6f907dcSJoerg Wunsch 			{
3031dcc6ec7SPhilippe Charnier 				"usage: pw useradd [name] [switches]\n"
3045f12594aSDavid Nugent 				"\t-V etcdir      alternate /etc location\n"
305d6f907dcSJoerg Wunsch 				"\t-C config      configuration file\n"
306d6f907dcSJoerg Wunsch 				"\t-q             quiet operation\n"
307d6f907dcSJoerg Wunsch 				"  Adding users:\n"
308d6f907dcSJoerg Wunsch 				"\t-n name        login name\n"
309d6f907dcSJoerg Wunsch 				"\t-u uid         user id\n"
310d6f907dcSJoerg Wunsch 				"\t-c comment     user name/comment\n"
311d6f907dcSJoerg Wunsch 				"\t-d directory   home directory\n"
312d6f907dcSJoerg Wunsch 				"\t-e date        account expiry date\n"
313d6f907dcSJoerg Wunsch 				"\t-p date        password expiry date\n"
314d6f907dcSJoerg Wunsch 				"\t-g grp         initial group\n"
315d6f907dcSJoerg Wunsch 				"\t-G grp1,grp2   additional groups\n"
316d6f907dcSJoerg Wunsch 				"\t-m [ -k dir ]  create and set up home\n"
3171dd634b0SLukas Ertl 				"\t-M mode        home directory permissions\n"
318d6f907dcSJoerg Wunsch 				"\t-s shell       name of login shell\n"
319d6f907dcSJoerg Wunsch 				"\t-o             duplicate uid ok\n"
320d6f907dcSJoerg Wunsch 				"\t-L class       user class\n"
321d6f907dcSJoerg Wunsch 				"\t-h fd          read password on fd\n"
32287d6b5caSIan Dowse 				"\t-H fd          read encrypted password on fd\n"
323f1d684faSDavid Nugent 				"\t-Y             update NIS maps\n"
32448aee7f3SJoerg Wunsch 				"\t-N             no update\n"
325d6f907dcSJoerg Wunsch 				"  Setting defaults:\n"
3265f12594aSDavid Nugent 				"\t-V etcdir      alternate /etc location\n"
327d6f907dcSJoerg Wunsch 			        "\t-D             set user defaults\n"
328d6f907dcSJoerg Wunsch 				"\t-b dir         default home root dir\n"
329d6f907dcSJoerg Wunsch 				"\t-e period      default expiry period\n"
330d6f907dcSJoerg Wunsch 				"\t-p period      default password change period\n"
331d6f907dcSJoerg Wunsch 				"\t-g group       default group\n"
332d6f907dcSJoerg Wunsch 				"\t-G grp1,grp2   additional groups\n"
333d6f907dcSJoerg Wunsch 				"\t-L class       default user class\n"
334d6f907dcSJoerg Wunsch 				"\t-k dir         default home skeleton\n"
33585204142SLukas Ertl 				"\t-M mode        home directory permissions\n"
336d6f907dcSJoerg Wunsch 				"\t-u min,max     set min,max uids\n"
337d6f907dcSJoerg Wunsch 				"\t-i min,max     set min,max gids\n"
338d6f907dcSJoerg Wunsch 				"\t-w method      set default password method\n"
339f1d684faSDavid Nugent 				"\t-s shell       default shell\n"
340f1d684faSDavid Nugent 				"\t-y path        set NIS passwd file path\n",
3411dcc6ec7SPhilippe Charnier 				"usage: pw userdel [uid|name] [switches]\n"
3425f12594aSDavid Nugent 				"\t-V etcdir      alternate /etc location\n"
343d6f907dcSJoerg Wunsch 				"\t-n name        login name\n"
344d6f907dcSJoerg Wunsch 				"\t-u uid         user id\n"
345f1d684faSDavid Nugent 				"\t-Y             update NIS maps\n"
346d6f907dcSJoerg Wunsch 				"\t-r             remove home & contents\n",
3471dcc6ec7SPhilippe Charnier 				"usage: pw usermod [uid|name] [switches]\n"
3485f12594aSDavid Nugent 				"\t-V etcdir      alternate /etc location\n"
349d6f907dcSJoerg Wunsch 				"\t-C config      configuration file\n"
350d6f907dcSJoerg Wunsch 				"\t-q             quiet operation\n"
351d6f907dcSJoerg Wunsch 				"\t-F             force add if no user\n"
352d6f907dcSJoerg Wunsch 				"\t-n name        login name\n"
353d6f907dcSJoerg Wunsch 				"\t-u uid         user id\n"
354d6f907dcSJoerg Wunsch 				"\t-c comment     user name/comment\n"
355d6f907dcSJoerg Wunsch 				"\t-d directory   home directory\n"
356d6f907dcSJoerg Wunsch 				"\t-e date        account expiry date\n"
357d6f907dcSJoerg Wunsch 				"\t-p date        password expiry date\n"
358d6f907dcSJoerg Wunsch 				"\t-g grp         initial group\n"
359d6f907dcSJoerg Wunsch 				"\t-G grp1,grp2   additional groups\n"
360d6f907dcSJoerg Wunsch 				"\t-l name        new login name\n"
361d6f907dcSJoerg Wunsch 				"\t-L class       user class\n"
362d6f907dcSJoerg Wunsch 				"\t-m [ -k dir ]  create and set up home\n"
3631dd634b0SLukas Ertl 				"\t-M mode        home directory permissions\n"
364d6f907dcSJoerg Wunsch 				"\t-s shell       name of login shell\n"
36548aee7f3SJoerg Wunsch 				"\t-w method      set new password using method\n"
36648aee7f3SJoerg Wunsch 				"\t-h fd          read password on fd\n"
36787d6b5caSIan Dowse 				"\t-H fd          read encrypted password on fd\n"
368f1d684faSDavid Nugent 				"\t-Y             update NIS maps\n"
36948aee7f3SJoerg Wunsch 				"\t-N             no update\n",
3701dcc6ec7SPhilippe Charnier 				"usage: pw usershow [uid|name] [switches]\n"
3715f12594aSDavid Nugent 				"\t-V etcdir      alternate /etc location\n"
372d6f907dcSJoerg Wunsch 				"\t-n name        login name\n"
373d6f907dcSJoerg Wunsch 				"\t-u uid         user id\n"
374d6f907dcSJoerg Wunsch 				"\t-F             force print\n"
37548aee7f3SJoerg Wunsch 				"\t-P             prettier format\n"
376f3522722SDavid Nugent 				"\t-a             print all users\n"
377f3522722SDavid Nugent 				"\t-7             print in v7 format\n",
3781dcc6ec7SPhilippe Charnier 				"usage: pw usernext [switches]\n"
3795f12594aSDavid Nugent 				"\t-V etcdir      alternate /etc location\n"
38048aee7f3SJoerg Wunsch 				"\t-C config      configuration file\n"
381ed6fd55aSDima Dorfman 				"\t-q             quiet operation\n",
382ed6fd55aSDima Dorfman 				"usage pw: lock [switches]\n"
383ed6fd55aSDima Dorfman 				"\t-V etcdir      alternate /etc locations\n"
384ed6fd55aSDima Dorfman 				"\t-C config      configuration file\n"
385ed6fd55aSDima Dorfman 				"\t-q             quiet operation\n",
386ed6fd55aSDima Dorfman 				"usage pw: unlock [switches]\n"
387ed6fd55aSDima Dorfman 				"\t-V etcdir      alternate /etc locations\n"
388ed6fd55aSDima Dorfman 				"\t-C config      configuration file\n"
389ed6fd55aSDima Dorfman 				"\t-q             quiet operation\n"
390d6f907dcSJoerg Wunsch 			},
391d6f907dcSJoerg Wunsch 			{
3921dcc6ec7SPhilippe Charnier 				"usage: pw groupadd [group|gid] [switches]\n"
3935f12594aSDavid Nugent 				"\t-V etcdir      alternate /etc location\n"
394d6f907dcSJoerg Wunsch 				"\t-C config      configuration file\n"
395d6f907dcSJoerg Wunsch 				"\t-q             quiet operation\n"
396d6f907dcSJoerg Wunsch 				"\t-n group       group name\n"
397d6f907dcSJoerg Wunsch 				"\t-g gid         group id\n"
39848aee7f3SJoerg Wunsch 				"\t-M usr1,usr2   add users as group members\n"
39948aee7f3SJoerg Wunsch 				"\t-o             duplicate gid ok\n"
400f1d684faSDavid Nugent 				"\t-Y             update NIS maps\n"
40148aee7f3SJoerg Wunsch 				"\t-N             no update\n",
4021dcc6ec7SPhilippe Charnier 				"usage: pw groupdel [group|gid] [switches]\n"
4035f12594aSDavid Nugent 				"\t-V etcdir      alternate /etc location\n"
404d6f907dcSJoerg Wunsch 				"\t-n name        group name\n"
405f1d684faSDavid Nugent 				"\t-g gid         group id\n"
406f1d684faSDavid Nugent 				"\t-Y             update NIS maps\n",
4071dcc6ec7SPhilippe Charnier 				"usage: pw groupmod [group|gid] [switches]\n"
4085f12594aSDavid Nugent 				"\t-V etcdir      alternate /etc location\n"
409d6f907dcSJoerg Wunsch 				"\t-C config      configuration file\n"
410d6f907dcSJoerg Wunsch 				"\t-q             quiet operation\n"
411d6f907dcSJoerg Wunsch 				"\t-F             force add if not exists\n"
412d6f907dcSJoerg Wunsch 				"\t-n name        group name\n"
413d6f907dcSJoerg Wunsch 				"\t-g gid         group id\n"
41448aee7f3SJoerg Wunsch 				"\t-M usr1,usr2   replaces users as group members\n"
41548aee7f3SJoerg Wunsch 				"\t-m usr1,usr2   add users as group members\n"
416bc991a6dSSean Farley 				"\t-d usr1,usr2   delete users as group members\n"
41748aee7f3SJoerg Wunsch 				"\t-l name        new group name\n"
418f1d684faSDavid Nugent 				"\t-Y             update NIS maps\n"
41948aee7f3SJoerg Wunsch 				"\t-N             no update\n",
4201dcc6ec7SPhilippe Charnier 				"usage: pw groupshow [group|gid] [switches]\n"
4215f12594aSDavid Nugent 				"\t-V etcdir      alternate /etc location\n"
422d6f907dcSJoerg Wunsch 				"\t-n name        group name\n"
423d6f907dcSJoerg Wunsch 				"\t-g gid         group id\n"
424d6f907dcSJoerg Wunsch 				"\t-F             force print\n"
42548aee7f3SJoerg Wunsch 				"\t-P             prettier format\n"
42648aee7f3SJoerg Wunsch 				"\t-a             print all accounting groups\n",
4271dcc6ec7SPhilippe Charnier 				"usage: pw groupnext [switches]\n"
4285f12594aSDavid Nugent 				"\t-V etcdir      alternate /etc location\n"
42948aee7f3SJoerg Wunsch 				"\t-C config      configuration file\n"
430ed6fd55aSDima Dorfman 				"\t-q             quiet operation\n"
431d6f907dcSJoerg Wunsch 			}
432d6f907dcSJoerg Wunsch 		};
433d6f907dcSJoerg Wunsch 
434cab0fb4eSKris Kennaway 		fprintf(stderr, "%s", help[which][mode]);
435d6f907dcSJoerg Wunsch 	}
43648aee7f3SJoerg Wunsch 	exit(EXIT_FAILURE);
437d6f907dcSJoerg Wunsch }
438d6f907dcSJoerg Wunsch 
439d6f907dcSJoerg Wunsch struct carg    *
440d6f907dcSJoerg Wunsch getarg(struct cargs * _args, int ch)
441d6f907dcSJoerg Wunsch {
442d0d78e13SBen Smithurst 	struct carg    *c = LIST_FIRST(_args);
443d6f907dcSJoerg Wunsch 
444d6f907dcSJoerg Wunsch 	while (c != NULL && c->ch != ch)
445d0d78e13SBen Smithurst 		c = LIST_NEXT(c, list);
446d6f907dcSJoerg Wunsch 	return c;
447d6f907dcSJoerg Wunsch }
448d6f907dcSJoerg Wunsch 
449d6f907dcSJoerg Wunsch struct carg    *
450d6f907dcSJoerg Wunsch addarg(struct cargs * _args, int ch, char *argstr)
451d6f907dcSJoerg Wunsch {
452d6f907dcSJoerg Wunsch 	struct carg    *ca = malloc(sizeof(struct carg));
453d6f907dcSJoerg Wunsch 
454d6f907dcSJoerg Wunsch 	if (ca == NULL)
4551dcc6ec7SPhilippe Charnier 		errx(EX_OSERR, "out of memory");
456d6f907dcSJoerg Wunsch 	ca->ch = ch;
457d6f907dcSJoerg Wunsch 	ca->val = argstr;
458d6f907dcSJoerg Wunsch 	LIST_INSERT_HEAD(_args, ca, list);
459d6f907dcSJoerg Wunsch 	return ca;
460d6f907dcSJoerg Wunsch }
461