xref: /freebsd/usr.sbin/pw/pw.c (revision 3bfc59e83b540cd527cffba13487e14e8d43e30b)
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>
362cc63cd1SBaptiste 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 
882cc63cd1SBaptiste Daroussin struct pwconf conf;
892cc63cd1SBaptiste 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;
102a9237189SBaptiste Daroussin 	long		id = -1;
1035f12594aSDavid Nugent 	char		*config = NULL;
10490edef4fSBaptiste Daroussin 	struct stat	st;
105a9237189SBaptiste Daroussin 	const char	*errstr;
106a9237189SBaptiste Daroussin 	char		arg, *name;
10782a3c75aSBaptiste Daroussin 	bool		relocated, nis;
108d6f907dcSJoerg Wunsch 
109d6f907dcSJoerg Wunsch 	static const char *opts[W_NUM][M_NUM] =
110d6f907dcSJoerg Wunsch 	{
11148aee7f3SJoerg Wunsch 		{ /* user */
112ac72be28SBaptiste Daroussin 			"R:V:C:qn:u:c:d:e:p:g:G:mM:k:s:oL:i:w:h:H:Db:NPy:Y",
113ac72be28SBaptiste Daroussin 			"R:V:C:qn:u:rY",
114ac72be28SBaptiste Daroussin 			"R:V:C:qn:u:c:d:e:p:g:G:mM:l:k:s:w:L:h:H:FNPY",
115ac72be28SBaptiste Daroussin 			"R:V:C:qn:u:FPa7",
116*3bfc59e8SBaptiste Daroussin 			"R:V:C:q",
117ac72be28SBaptiste Daroussin 			"R:V:C:q",
118ac72be28SBaptiste Daroussin 			"R:V:C:q"
11948aee7f3SJoerg Wunsch 		},
12048aee7f3SJoerg Wunsch 		{ /* grp  */
121ac72be28SBaptiste Daroussin 			"R:V:C:qn:g:h:H:M:opNPY",
122ac72be28SBaptiste Daroussin 			"R:V:C:qn:g:Y",
123ac72be28SBaptiste Daroussin 			"R:V:C:qn:d:g:l:h:H:FM:m:NPY",
124ac72be28SBaptiste Daroussin 			"R:V:C:qn:g:FPa",
125*3bfc59e8SBaptiste Daroussin 			"R:V:C:q"
12648aee7f3SJoerg Wunsch 		 }
127d6f907dcSJoerg Wunsch 	};
128d6f907dcSJoerg Wunsch 
129a9237189SBaptiste Daroussin 	static int      (*funcs[W_NUM]) (int _mode, char *_name, long _id,
130a9237189SBaptiste Daroussin 	    struct cargs * _args) =
131d6f907dcSJoerg Wunsch 	{			/* Request handlers */
132d6f907dcSJoerg Wunsch 		pw_user,
133d6f907dcSJoerg Wunsch 		pw_group
134d6f907dcSJoerg Wunsch 	};
135d6f907dcSJoerg Wunsch 
136a9237189SBaptiste Daroussin 	name = NULL;
13782a3c75aSBaptiste Daroussin 	relocated = nis = false;
138bbe09b2eSBaptiste Daroussin 	memset(&conf, 0, sizeof(conf));
1392cc63cd1SBaptiste Daroussin 	strlcpy(conf.etcpath, _PATH_PWD, sizeof(conf.etcpath));
1402cc63cd1SBaptiste Daroussin 
141d6f907dcSJoerg Wunsch 	LIST_INIT(&arglist);
142d6f907dcSJoerg Wunsch 
14339610c72SAndrey A. Chernov 	(void)setlocale(LC_ALL, "");
144e7161f36SAndrey A. Chernov 
145d6f907dcSJoerg Wunsch 	/*
146d6f907dcSJoerg Wunsch 	 * Break off the first couple of words to determine what exactly
147d6f907dcSJoerg Wunsch 	 * we're being asked to do
148d6f907dcSJoerg Wunsch 	 */
1495f12594aSDavid Nugent 	while (argc > 1) {
150d6f907dcSJoerg Wunsch 		int             tmp;
151d6f907dcSJoerg Wunsch 
1525f12594aSDavid Nugent 		if (*argv[1] == '-') {
1535f12594aSDavid Nugent 			/*
1545f12594aSDavid Nugent 			 * Special case, allow pw -V<dir> <operation> [args] for scripts etc.
1555f12594aSDavid Nugent 			 */
156ac72be28SBaptiste Daroussin 			arg = argv[1][1];
157ac72be28SBaptiste Daroussin 			if (arg == 'V' || arg == 'R') {
1582cc63cd1SBaptiste Daroussin 				if (relocated)
1592cc63cd1SBaptiste Daroussin 					errx(EXIT_FAILURE, "Both '-R' and '-V' "
1602cc63cd1SBaptiste Daroussin 					    "specified, only one accepted");
1612cc63cd1SBaptiste Daroussin 				relocated = true;
1625f12594aSDavid Nugent 				optarg = &argv[1][2];
1635f12594aSDavid Nugent 				if (*optarg == '\0') {
16490edef4fSBaptiste Daroussin 					if (stat(argv[2], &st) != 0)
16590edef4fSBaptiste Daroussin 						errx(EX_OSFILE, \
16690edef4fSBaptiste Daroussin 						    "no such directory `%s'",
16790edef4fSBaptiste Daroussin 						    argv[2]);
16890edef4fSBaptiste Daroussin 					if (!S_ISDIR(st.st_mode))
16990edef4fSBaptiste Daroussin 						errx(EX_OSFILE, "`%s' not a "
17090edef4fSBaptiste Daroussin 						    "directory", argv[2]);
1715f12594aSDavid Nugent 					optarg = argv[2];
1725f12594aSDavid Nugent 					++argv;
1735f12594aSDavid Nugent 					--argc;
1745f12594aSDavid Nugent 				}
1752cc63cd1SBaptiste Daroussin 				memcpy(&PWF, &VPWF, sizeof PWF);
1762cc63cd1SBaptiste Daroussin 				if (arg == 'R') {
1772cc63cd1SBaptiste Daroussin 					strlcpy(conf.rootdir, optarg,
1782cc63cd1SBaptiste Daroussin 					    sizeof(conf.rootdir));
1792cc63cd1SBaptiste Daroussin 					PWF._altdir = PWF_ROOTDIR;
1802cc63cd1SBaptiste Daroussin 				}
1812cc63cd1SBaptiste Daroussin 				snprintf(conf.etcpath, sizeof(conf.etcpath),
1822cc63cd1SBaptiste Daroussin 				    "%s%s", optarg, arg == 'R' ? "/etc" : "");
183e3921b27SDavid Nugent 			} else
1845f12594aSDavid Nugent 				break;
1855f12594aSDavid Nugent 		}
186c4e667b9SDavid Nugent 		else if (mode == -1 && (tmp = getindex(Modes, argv[1])) != -1)
187d6f907dcSJoerg Wunsch 			mode = tmp;
188c4e667b9SDavid Nugent 		else if (which == -1 && (tmp = getindex(Which, argv[1])) != -1)
189d6f907dcSJoerg Wunsch 			which = tmp;
190c4e667b9SDavid Nugent 		else if ((mode == -1 && which == -1) &&
191c4e667b9SDavid Nugent 			 ((tmp = getindex(Combo1, argv[1])) != -1 ||
192c4e667b9SDavid Nugent 			  (tmp = getindex(Combo2, argv[1])) != -1)) {
193d6f907dcSJoerg Wunsch 			which = tmp / M_NUM;
194d6f907dcSJoerg Wunsch 			mode = tmp % M_NUM;
195c4e667b9SDavid Nugent 		} else if (strcmp(argv[1], "help") == 0 && argv[2] == NULL)
196d6f907dcSJoerg Wunsch 			cmdhelp(mode, which);
197a9237189SBaptiste Daroussin 		else if (which != -1 && mode != -1) {
198a9237189SBaptiste Daroussin 			if (strspn(argv[1], "0123456789") == strlen(argv[1])) {
199a9237189SBaptiste Daroussin 				id = strtonum(argv[1], 0, LONG_MAX, &errstr);
200a9237189SBaptiste Daroussin 				if (errstr != NULL)
201a9237189SBaptiste Daroussin 					errx(EX_USAGE, "Bad id '%s': %s",
202a9237189SBaptiste Daroussin 					    argv[1], errstr);
203a9237189SBaptiste Daroussin 			} else
204a9237189SBaptiste Daroussin 				name = argv[1];
205a9237189SBaptiste Daroussin 		} else
2061dcc6ec7SPhilippe Charnier 			errx(EX_USAGE, "unknown keyword `%s'", argv[1]);
207d6f907dcSJoerg Wunsch 		++argv;
208d6f907dcSJoerg Wunsch 		--argc;
209d6f907dcSJoerg Wunsch 	}
210d6f907dcSJoerg Wunsch 
211d6f907dcSJoerg Wunsch 	/*
212d6f907dcSJoerg Wunsch 	 * Bail out unless the user is specific!
213d6f907dcSJoerg Wunsch 	 */
214d6f907dcSJoerg Wunsch 	if (mode == -1 || which == -1)
215d6f907dcSJoerg Wunsch 		cmdhelp(mode, which);
216d6f907dcSJoerg Wunsch 
217d6f907dcSJoerg Wunsch 	/*
218d6f907dcSJoerg Wunsch 	 * We know which mode we're in and what we're about to do, so now
219d6f907dcSJoerg Wunsch 	 * let's dispatch the remaining command line args in a genric way.
220d6f907dcSJoerg Wunsch 	 */
221d6f907dcSJoerg Wunsch 	optarg = NULL;
222d6f907dcSJoerg Wunsch 
223d6f907dcSJoerg Wunsch 	while ((ch = getopt(argc, argv, opts[which][mode])) != -1) {
22482a3c75aSBaptiste Daroussin 		switch (ch) {
22582a3c75aSBaptiste Daroussin 		case '?':
226923dc0b2SDavid Nugent 			errx(EX_USAGE, "unknown switch");
22782a3c75aSBaptiste Daroussin 			break;
228c86f7ad5SBaptiste Daroussin 		case '7':
229c86f7ad5SBaptiste Daroussin 			conf.v7 = true;
230c86f7ad5SBaptiste Daroussin 			break;
23182a3c75aSBaptiste Daroussin 		case 'C':
232a68fbadbSBaptiste Daroussin 			conf.config = optarg;
233a68fbadbSBaptiste Daroussin 			config = conf.config;
23482a3c75aSBaptiste Daroussin 			break;
235363cefdbSBaptiste Daroussin 		case 'N':
236363cefdbSBaptiste Daroussin 			conf.dryrun = true;
237363cefdbSBaptiste Daroussin 			break;
238bae068d2SBaptiste Daroussin 		case 'l':
239bae068d2SBaptiste Daroussin 			if (strlen(optarg) >= MAXLOGNAME)
240bae068d2SBaptiste Daroussin 				errx(EX_USAGE, "new name too long: %s", optarg);
241bae068d2SBaptiste Daroussin 			conf.newname = optarg;
242bae068d2SBaptiste Daroussin 			break;
2432166b4d1SBaptiste Daroussin 		case 'P':
2442166b4d1SBaptiste Daroussin 			conf.pretty = true;
2452166b4d1SBaptiste Daroussin 			break;
24682a3c75aSBaptiste Daroussin 		case 'Y':
24782a3c75aSBaptiste Daroussin 			nis = true;
24882a3c75aSBaptiste Daroussin 			break;
249a9237189SBaptiste Daroussin 		case 'g':
250a9237189SBaptiste Daroussin 			if (which == 0) { /* for user* */
251a9237189SBaptiste Daroussin 				addarg(&arglist, 'g', optarg);
252a9237189SBaptiste Daroussin 				break;
253a9237189SBaptiste Daroussin 			}
254a9237189SBaptiste Daroussin 			if (strspn(optarg, "0123456789") != strlen(optarg))
2551718a38fSBaptiste Daroussin 				errx(EX_USAGE, "-g expects a number");
2561718a38fSBaptiste Daroussin 			id = strtonum(optarg, 0, LONG_MAX, &errstr);
2571718a38fSBaptiste Daroussin 			if (errstr != NULL)
2581718a38fSBaptiste Daroussin 				errx(EX_USAGE, "Bad id '%s': %s", optarg,
2591718a38fSBaptiste Daroussin 				    errstr);
2601718a38fSBaptiste Daroussin 			break;
2611718a38fSBaptiste Daroussin 		case 'u':
2621718a38fSBaptiste Daroussin 			if (strspn(optarg, "0123456789,") != strlen(optarg))
2631718a38fSBaptiste Daroussin 				errx(EX_USAGE, "-u expects a number");
2641718a38fSBaptiste Daroussin 			if (strchr(optarg, ',') != NULL) {
2651718a38fSBaptiste Daroussin 				addarg(&arglist, 'u', optarg);
2661718a38fSBaptiste Daroussin 				break;
2671718a38fSBaptiste Daroussin 			}
268a9237189SBaptiste Daroussin 			id = strtonum(optarg, 0, LONG_MAX, &errstr);
269a9237189SBaptiste Daroussin 			if (errstr != NULL)
270a9237189SBaptiste Daroussin 				errx(EX_USAGE, "Bad id '%s': %s", optarg,
271a9237189SBaptiste Daroussin 				    errstr);
272a9237189SBaptiste Daroussin 			break;
273a9237189SBaptiste Daroussin 		case 'n':
274a9237189SBaptiste Daroussin 			if (strspn(optarg, "0123456789") != strlen(optarg)) {
275a9237189SBaptiste Daroussin 				name = optarg;
276a9237189SBaptiste Daroussin 				break;
277a9237189SBaptiste Daroussin 			}
278a9237189SBaptiste Daroussin 			id = strtonum(optarg, 0, LONG_MAX, &errstr);
279a9237189SBaptiste Daroussin 			if (errstr != NULL)
280a9237189SBaptiste Daroussin 				errx(EX_USAGE, "Bad id '%s': %s", optarg,
281a9237189SBaptiste Daroussin 				    errstr);
28291860967SBaptiste Daroussin 			break;
28391860967SBaptiste Daroussin 		case 'o':
28491860967SBaptiste Daroussin 			conf.checkduplicate = true;
28591860967SBaptiste Daroussin 			break;
28682a3c75aSBaptiste Daroussin 		default:
287d6f907dcSJoerg Wunsch 			addarg(&arglist, ch, optarg);
28882a3c75aSBaptiste Daroussin 			break;
28982a3c75aSBaptiste Daroussin 		}
290d6f907dcSJoerg Wunsch 		optarg = NULL;
291d6f907dcSJoerg Wunsch 	}
292d6f907dcSJoerg Wunsch 
293a9237189SBaptiste Daroussin 	if (name != NULL && strlen(name) >= MAXLOGNAME)
294a9237189SBaptiste Daroussin 		errx(EX_USAGE, "name too long: %s", name);
295a9237189SBaptiste Daroussin 
296d6f907dcSJoerg Wunsch 	/*
29748aee7f3SJoerg Wunsch 	 * Must be root to attempt an update
29848aee7f3SJoerg Wunsch 	 */
299363cefdbSBaptiste Daroussin 	if (geteuid() != 0 && mode != M_PRINT && mode != M_NEXT && !conf.dryrun)
3001dcc6ec7SPhilippe Charnier 		errx(EX_NOPERM, "you must be root to run this program");
30148aee7f3SJoerg Wunsch 
30248aee7f3SJoerg Wunsch 	/*
303d6f907dcSJoerg Wunsch 	 * We should immediately look for the -q 'quiet' switch so that we
304d6f907dcSJoerg Wunsch 	 * don't bother with extraneous errors
305d6f907dcSJoerg Wunsch 	 */
306d6f907dcSJoerg Wunsch 	if (getarg(&arglist, 'q') != NULL)
3071a37aa56SDavid E. O'Brien 		freopen(_PATH_DEVNULL, "w", stderr);
308d6f907dcSJoerg Wunsch 
309d6f907dcSJoerg Wunsch 	/*
3105f12594aSDavid Nugent 	 * Set our base working path if not overridden
3115f12594aSDavid Nugent 	 */
3125f12594aSDavid Nugent 
3135f12594aSDavid Nugent 	if (config == NULL) {	/* Only override config location if -C not specified */
3142cc63cd1SBaptiste Daroussin 		asprintf(&config, "%s/pw.conf", conf.etcpath);
31519741915SBaptiste Daroussin 		if (config == NULL)
31619741915SBaptiste Daroussin 			errx(EX_OSERR, "out of memory");
3175f12594aSDavid Nugent 	}
3185f12594aSDavid Nugent 
3195f12594aSDavid Nugent 	/*
320d6f907dcSJoerg Wunsch 	 * Now, let's do the common initialisation
321d6f907dcSJoerg Wunsch 	 */
3222cc63cd1SBaptiste Daroussin 	conf.userconf = read_userconfig(config);
3235e91a8acSNate Williams 
324a9237189SBaptiste Daroussin 	ch = funcs[which] (mode, name, id, &arglist);
325f1d684faSDavid Nugent 
326f1d684faSDavid Nugent 	/*
327f1d684faSDavid Nugent 	 * If everything went ok, and we've been asked to update
328f1d684faSDavid Nugent 	 * the NIS maps, then do it now
329f1d684faSDavid Nugent 	 */
33082a3c75aSBaptiste Daroussin 	if (ch == EXIT_SUCCESS && nis) {
331f1d684faSDavid Nugent 		pid_t	pid;
332f1d684faSDavid Nugent 
333f1d684faSDavid Nugent 		fflush(NULL);
334f1d684faSDavid Nugent 		if (chdir(_PATH_YP) == -1)
3351dcc6ec7SPhilippe Charnier 			warn("chdir(" _PATH_YP ")");
336f1d684faSDavid Nugent 		else if ((pid = fork()) == -1)
3371dcc6ec7SPhilippe Charnier 			warn("fork()");
338f1d684faSDavid Nugent 		else if (pid == 0) {
339f1d684faSDavid Nugent 			/* Is make anywhere else? */
3407bc6d015SBrian Somers 			execlp("/usr/bin/make", "make", (char *)NULL);
341f1d684faSDavid Nugent 			_exit(1);
342f1d684faSDavid Nugent 		} else {
343f1d684faSDavid Nugent 			int   i;
344f1d684faSDavid Nugent 			waitpid(pid, &i, 0);
345f1d684faSDavid Nugent 			if ((i = WEXITSTATUS(i)) != 0)
3461dcc6ec7SPhilippe Charnier 				errx(ch, "make exited with status %d", i);
347f1d684faSDavid Nugent 			else
3482cc63cd1SBaptiste Daroussin 				pw_log(conf.userconf, mode, which, "NIS maps updated");
349f1d684faSDavid Nugent 		}
350f1d684faSDavid Nugent 	}
351f1d684faSDavid Nugent 	return ch;
352d6f907dcSJoerg Wunsch }
353d6f907dcSJoerg Wunsch 
3545e91a8acSNate Williams 
355d6f907dcSJoerg Wunsch static int
356d6f907dcSJoerg Wunsch getindex(const char *words[], const char *word)
357d6f907dcSJoerg Wunsch {
358d6f907dcSJoerg Wunsch 	int             i = 0;
359d6f907dcSJoerg Wunsch 
360d6f907dcSJoerg Wunsch 	while (words[i]) {
361d6f907dcSJoerg Wunsch 		if (strcmp(words[i], word) == 0)
362d6f907dcSJoerg Wunsch 			return i;
363d6f907dcSJoerg Wunsch 		i++;
364d6f907dcSJoerg Wunsch 	}
365d6f907dcSJoerg Wunsch 	return -1;
366d6f907dcSJoerg Wunsch }
367d6f907dcSJoerg Wunsch 
368d6f907dcSJoerg Wunsch 
369d6f907dcSJoerg Wunsch /*
370d6f907dcSJoerg Wunsch  * This is probably an overkill for a cmdline help system, but it reflects
371d6f907dcSJoerg Wunsch  * the complexity of the command line.
372d6f907dcSJoerg Wunsch  */
373d6f907dcSJoerg Wunsch 
374d6f907dcSJoerg Wunsch static void
375d6f907dcSJoerg Wunsch cmdhelp(int mode, int which)
376d6f907dcSJoerg Wunsch {
377d6f907dcSJoerg Wunsch 	if (which == -1)
3782399cd14SDavid Nugent 		fprintf(stderr, "usage:\n  pw [user|group|lock|unlock] [add|del|mod|show|next] [help|switches/values]\n");
379d6f907dcSJoerg Wunsch 	else if (mode == -1)
3802399cd14SDavid Nugent 		fprintf(stderr, "usage:\n  pw %s [add|del|mod|show|next] [help|switches/values]\n", Which[which]);
381d6f907dcSJoerg Wunsch 	else {
382d6f907dcSJoerg Wunsch 
383d6f907dcSJoerg Wunsch 		/*
384d6f907dcSJoerg Wunsch 		 * We need to give mode specific help
385d6f907dcSJoerg Wunsch 		 */
386d6f907dcSJoerg Wunsch 		static const char *help[W_NUM][M_NUM] =
387d6f907dcSJoerg Wunsch 		{
388d6f907dcSJoerg Wunsch 			{
3891dcc6ec7SPhilippe Charnier 				"usage: pw useradd [name] [switches]\n"
3905f12594aSDavid Nugent 				"\t-V etcdir      alternate /etc location\n"
391ac72be28SBaptiste Daroussin 				"\t-R rootir      alternate root directory\n"
392d6f907dcSJoerg Wunsch 				"\t-C config      configuration file\n"
393d6f907dcSJoerg Wunsch 				"\t-q             quiet operation\n"
394d6f907dcSJoerg Wunsch 				"  Adding users:\n"
395d6f907dcSJoerg Wunsch 				"\t-n name        login name\n"
396d6f907dcSJoerg Wunsch 				"\t-u uid         user id\n"
397d6f907dcSJoerg Wunsch 				"\t-c comment     user name/comment\n"
398d6f907dcSJoerg Wunsch 				"\t-d directory   home directory\n"
399d6f907dcSJoerg Wunsch 				"\t-e date        account expiry date\n"
400d6f907dcSJoerg Wunsch 				"\t-p date        password expiry date\n"
401d6f907dcSJoerg Wunsch 				"\t-g grp         initial group\n"
402d6f907dcSJoerg Wunsch 				"\t-G grp1,grp2   additional groups\n"
403d6f907dcSJoerg Wunsch 				"\t-m [ -k dir ]  create and set up home\n"
4041dd634b0SLukas Ertl 				"\t-M mode        home directory permissions\n"
405d6f907dcSJoerg Wunsch 				"\t-s shell       name of login shell\n"
406d6f907dcSJoerg Wunsch 				"\t-o             duplicate uid ok\n"
407d6f907dcSJoerg Wunsch 				"\t-L class       user class\n"
408d6f907dcSJoerg Wunsch 				"\t-h fd          read password on fd\n"
40987d6b5caSIan Dowse 				"\t-H fd          read encrypted password on fd\n"
410f1d684faSDavid Nugent 				"\t-Y             update NIS maps\n"
41148aee7f3SJoerg Wunsch 				"\t-N             no update\n"
412d6f907dcSJoerg Wunsch 				"  Setting defaults:\n"
4135f12594aSDavid Nugent 				"\t-V etcdir      alternate /etc location\n"
414ac72be28SBaptiste Daroussin 				"\t-R rootir      alternate root directory\n"
415d6f907dcSJoerg Wunsch 			        "\t-D             set user defaults\n"
416d6f907dcSJoerg Wunsch 				"\t-b dir         default home root dir\n"
417d6f907dcSJoerg Wunsch 				"\t-e period      default expiry period\n"
418d6f907dcSJoerg Wunsch 				"\t-p period      default password change period\n"
419d6f907dcSJoerg Wunsch 				"\t-g group       default group\n"
420d6f907dcSJoerg Wunsch 				"\t-G grp1,grp2   additional groups\n"
421d6f907dcSJoerg Wunsch 				"\t-L class       default user class\n"
422d6f907dcSJoerg Wunsch 				"\t-k dir         default home skeleton\n"
42385204142SLukas Ertl 				"\t-M mode        home directory permissions\n"
424d6f907dcSJoerg Wunsch 				"\t-u min,max     set min,max uids\n"
425d6f907dcSJoerg Wunsch 				"\t-i min,max     set min,max gids\n"
426d6f907dcSJoerg Wunsch 				"\t-w method      set default password method\n"
427f1d684faSDavid Nugent 				"\t-s shell       default shell\n"
428f1d684faSDavid Nugent 				"\t-y path        set NIS passwd file path\n",
4291dcc6ec7SPhilippe Charnier 				"usage: pw userdel [uid|name] [switches]\n"
4305f12594aSDavid Nugent 				"\t-V etcdir      alternate /etc location\n"
431ac72be28SBaptiste Daroussin 				"\t-R rootir      alternate root directory\n"
432d6f907dcSJoerg Wunsch 				"\t-n name        login name\n"
433d6f907dcSJoerg Wunsch 				"\t-u uid         user id\n"
434f1d684faSDavid Nugent 				"\t-Y             update NIS maps\n"
435d6f907dcSJoerg Wunsch 				"\t-r             remove home & contents\n",
4361dcc6ec7SPhilippe Charnier 				"usage: pw usermod [uid|name] [switches]\n"
4375f12594aSDavid Nugent 				"\t-V etcdir      alternate /etc location\n"
438ac72be28SBaptiste Daroussin 				"\t-R rootir      alternate root directory\n"
439d6f907dcSJoerg Wunsch 				"\t-C config      configuration file\n"
440d6f907dcSJoerg Wunsch 				"\t-q             quiet operation\n"
441d6f907dcSJoerg Wunsch 				"\t-F             force add if no user\n"
442d6f907dcSJoerg Wunsch 				"\t-n name        login name\n"
443d6f907dcSJoerg Wunsch 				"\t-u uid         user id\n"
444d6f907dcSJoerg Wunsch 				"\t-c comment     user name/comment\n"
445d6f907dcSJoerg Wunsch 				"\t-d directory   home directory\n"
446d6f907dcSJoerg Wunsch 				"\t-e date        account expiry date\n"
447d6f907dcSJoerg Wunsch 				"\t-p date        password expiry date\n"
448d6f907dcSJoerg Wunsch 				"\t-g grp         initial group\n"
449d6f907dcSJoerg Wunsch 				"\t-G grp1,grp2   additional groups\n"
450d6f907dcSJoerg Wunsch 				"\t-l name        new login name\n"
451d6f907dcSJoerg Wunsch 				"\t-L class       user class\n"
452d6f907dcSJoerg Wunsch 				"\t-m [ -k dir ]  create and set up home\n"
4531dd634b0SLukas Ertl 				"\t-M mode        home directory permissions\n"
454d6f907dcSJoerg Wunsch 				"\t-s shell       name of login shell\n"
45548aee7f3SJoerg Wunsch 				"\t-w method      set new password using method\n"
45648aee7f3SJoerg Wunsch 				"\t-h fd          read password on fd\n"
45787d6b5caSIan Dowse 				"\t-H fd          read encrypted password on fd\n"
458f1d684faSDavid Nugent 				"\t-Y             update NIS maps\n"
45948aee7f3SJoerg Wunsch 				"\t-N             no update\n",
4601dcc6ec7SPhilippe Charnier 				"usage: pw usershow [uid|name] [switches]\n"
4615f12594aSDavid Nugent 				"\t-V etcdir      alternate /etc location\n"
462ac72be28SBaptiste Daroussin 				"\t-R rootir      alternate root directory\n"
463d6f907dcSJoerg Wunsch 				"\t-n name        login name\n"
464d6f907dcSJoerg Wunsch 				"\t-u uid         user id\n"
465d6f907dcSJoerg Wunsch 				"\t-F             force print\n"
46648aee7f3SJoerg Wunsch 				"\t-P             prettier format\n"
467f3522722SDavid Nugent 				"\t-a             print all users\n"
468f3522722SDavid Nugent 				"\t-7             print in v7 format\n",
4691dcc6ec7SPhilippe Charnier 				"usage: pw usernext [switches]\n"
4705f12594aSDavid Nugent 				"\t-V etcdir      alternate /etc location\n"
471ac72be28SBaptiste Daroussin 				"\t-R rootir      alternate root directory\n"
472*3bfc59e8SBaptiste Daroussin 				"\t-C config      configuration file\n"
473*3bfc59e8SBaptiste Daroussin 				"\t-q             quiet operation\n",
474ed6fd55aSDima Dorfman 				"usage pw: lock [switches]\n"
475ed6fd55aSDima Dorfman 				"\t-V etcdir      alternate /etc locations\n"
476ed6fd55aSDima Dorfman 				"\t-C config      configuration file\n"
477ed6fd55aSDima Dorfman 				"\t-q             quiet operation\n",
478ed6fd55aSDima Dorfman 				"usage pw: unlock [switches]\n"
479ed6fd55aSDima Dorfman 				"\t-V etcdir      alternate /etc locations\n"
480ed6fd55aSDima Dorfman 				"\t-C config      configuration file\n"
481ed6fd55aSDima Dorfman 				"\t-q             quiet operation\n"
482d6f907dcSJoerg Wunsch 			},
483d6f907dcSJoerg Wunsch 			{
4841dcc6ec7SPhilippe Charnier 				"usage: pw groupadd [group|gid] [switches]\n"
4855f12594aSDavid Nugent 				"\t-V etcdir      alternate /etc location\n"
486ac72be28SBaptiste Daroussin 				"\t-R rootir      alternate root directory\n"
487d6f907dcSJoerg Wunsch 				"\t-C config      configuration file\n"
488d6f907dcSJoerg Wunsch 				"\t-q             quiet operation\n"
489d6f907dcSJoerg Wunsch 				"\t-n group       group name\n"
490d6f907dcSJoerg Wunsch 				"\t-g gid         group id\n"
49148aee7f3SJoerg Wunsch 				"\t-M usr1,usr2   add users as group members\n"
49248aee7f3SJoerg Wunsch 				"\t-o             duplicate gid ok\n"
493f1d684faSDavid Nugent 				"\t-Y             update NIS maps\n"
49448aee7f3SJoerg Wunsch 				"\t-N             no update\n",
4951dcc6ec7SPhilippe Charnier 				"usage: pw groupdel [group|gid] [switches]\n"
4965f12594aSDavid Nugent 				"\t-V etcdir      alternate /etc location\n"
497ac72be28SBaptiste Daroussin 				"\t-R rootir      alternate root directory\n"
498d6f907dcSJoerg Wunsch 				"\t-n name        group name\n"
499f1d684faSDavid Nugent 				"\t-g gid         group id\n"
500f1d684faSDavid Nugent 				"\t-Y             update NIS maps\n",
5011dcc6ec7SPhilippe Charnier 				"usage: pw groupmod [group|gid] [switches]\n"
5025f12594aSDavid Nugent 				"\t-V etcdir      alternate /etc location\n"
503ac72be28SBaptiste Daroussin 				"\t-R rootir      alternate root directory\n"
504d6f907dcSJoerg Wunsch 				"\t-C config      configuration file\n"
505d6f907dcSJoerg Wunsch 				"\t-q             quiet operation\n"
506d6f907dcSJoerg Wunsch 				"\t-F             force add if not exists\n"
507d6f907dcSJoerg Wunsch 				"\t-n name        group name\n"
508d6f907dcSJoerg Wunsch 				"\t-g gid         group id\n"
50948aee7f3SJoerg Wunsch 				"\t-M usr1,usr2   replaces users as group members\n"
51048aee7f3SJoerg Wunsch 				"\t-m usr1,usr2   add users as group members\n"
511bc991a6dSSean Farley 				"\t-d usr1,usr2   delete users as group members\n"
51248aee7f3SJoerg Wunsch 				"\t-l name        new group name\n"
513f1d684faSDavid Nugent 				"\t-Y             update NIS maps\n"
51448aee7f3SJoerg Wunsch 				"\t-N             no update\n",
5151dcc6ec7SPhilippe Charnier 				"usage: pw groupshow [group|gid] [switches]\n"
5165f12594aSDavid Nugent 				"\t-V etcdir      alternate /etc location\n"
517ac72be28SBaptiste Daroussin 				"\t-R rootir      alternate root directory\n"
518d6f907dcSJoerg Wunsch 				"\t-n name        group name\n"
519d6f907dcSJoerg Wunsch 				"\t-g gid         group id\n"
520d6f907dcSJoerg Wunsch 				"\t-F             force print\n"
52148aee7f3SJoerg Wunsch 				"\t-P             prettier format\n"
52248aee7f3SJoerg Wunsch 				"\t-a             print all accounting groups\n",
5231dcc6ec7SPhilippe Charnier 				"usage: pw groupnext [switches]\n"
5245f12594aSDavid Nugent 				"\t-V etcdir      alternate /etc location\n"
525ac72be28SBaptiste Daroussin 				"\t-R rootir      alternate root directory\n"
52648aee7f3SJoerg Wunsch 				"\t-C config      configuration file\n"
527*3bfc59e8SBaptiste Daroussin 				"\t-q             quiet operation\n"
528d6f907dcSJoerg Wunsch 			}
529d6f907dcSJoerg Wunsch 		};
530d6f907dcSJoerg Wunsch 
531cab0fb4eSKris Kennaway 		fprintf(stderr, "%s", help[which][mode]);
532d6f907dcSJoerg Wunsch 	}
53348aee7f3SJoerg Wunsch 	exit(EXIT_FAILURE);
534d6f907dcSJoerg Wunsch }
535d6f907dcSJoerg Wunsch 
536d6f907dcSJoerg Wunsch struct carg    *
537d6f907dcSJoerg Wunsch getarg(struct cargs * _args, int ch)
538d6f907dcSJoerg Wunsch {
539d0d78e13SBen Smithurst 	struct carg    *c = LIST_FIRST(_args);
540d6f907dcSJoerg Wunsch 
541d6f907dcSJoerg Wunsch 	while (c != NULL && c->ch != ch)
542d0d78e13SBen Smithurst 		c = LIST_NEXT(c, list);
543d6f907dcSJoerg Wunsch 	return c;
544d6f907dcSJoerg Wunsch }
545d6f907dcSJoerg Wunsch 
546d6f907dcSJoerg Wunsch struct carg    *
547d6f907dcSJoerg Wunsch addarg(struct cargs * _args, int ch, char *argstr)
548d6f907dcSJoerg Wunsch {
549d6f907dcSJoerg Wunsch 	struct carg    *ca = malloc(sizeof(struct carg));
550d6f907dcSJoerg Wunsch 
551d6f907dcSJoerg Wunsch 	if (ca == NULL)
5521dcc6ec7SPhilippe Charnier 		errx(EX_OSERR, "out of memory");
553d6f907dcSJoerg Wunsch 	ca->ch = ch;
554d6f907dcSJoerg Wunsch 	ca->val = argstr;
555d6f907dcSJoerg Wunsch 	LIST_INSERT_HEAD(_args, ca, list);
556d6f907dcSJoerg Wunsch 	return ca;
557d6f907dcSJoerg Wunsch }
558