xref: /openbsd-src/lib/libutil/passwd.c (revision df69c215c7c66baf660f3f65414fd34796c96152)
1*df69c215Sderaadt /*	$OpenBSD: passwd.c,v 1.56 2019/06/28 13:32:43 deraadt Exp $	*/
242cbcc77Sniklas 
34b826ba8Sderaadt /*
44b826ba8Sderaadt  * Copyright (c) 1987, 1993, 1994, 1995
54b826ba8Sderaadt  *	The Regents of the University of California.  All rights reserved.
64b826ba8Sderaadt  *
74b826ba8Sderaadt  * Redistribution and use in source and binary forms, with or without
84b826ba8Sderaadt  * modification, are permitted provided that the following conditions
94b826ba8Sderaadt  * are met:
104b826ba8Sderaadt  * 1. Redistributions of source code must retain the above copyright
114b826ba8Sderaadt  *    notice, this list of conditions and the following disclaimer.
124b826ba8Sderaadt  * 2. Redistributions in binary form must reproduce the above copyright
134b826ba8Sderaadt  *    notice, this list of conditions and the following disclaimer in the
144b826ba8Sderaadt  *    documentation and/or other materials provided with the distribution.
156580fee3Smillert  * 3. Neither the name of the University nor the names of its contributors
164b826ba8Sderaadt  *    may be used to endorse or promote products derived from this software
174b826ba8Sderaadt  *    without specific prior written permission.
184b826ba8Sderaadt  *
194b826ba8Sderaadt  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
204b826ba8Sderaadt  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
214b826ba8Sderaadt  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
224b826ba8Sderaadt  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
234b826ba8Sderaadt  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
244b826ba8Sderaadt  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
254b826ba8Sderaadt  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
264b826ba8Sderaadt  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
274b826ba8Sderaadt  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
284b826ba8Sderaadt  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
294b826ba8Sderaadt  * SUCH DAMAGE.
304b826ba8Sderaadt  */
314b826ba8Sderaadt 
324b826ba8Sderaadt #include <sys/types.h>
334b826ba8Sderaadt #include <sys/stat.h>
344b826ba8Sderaadt #include <sys/time.h>
354b826ba8Sderaadt #include <sys/resource.h>
364b826ba8Sderaadt #include <sys/wait.h>
374b826ba8Sderaadt 
384b826ba8Sderaadt #include <fcntl.h>
394b826ba8Sderaadt #include <unistd.h>
404b826ba8Sderaadt #include <stdlib.h>
414b826ba8Sderaadt #include <stdio.h>
424b826ba8Sderaadt #include <string.h>
43abf39cbdSmillert #include <ctype.h>
444b826ba8Sderaadt #include <pwd.h>
45abf39cbdSmillert #include <err.h>
464b826ba8Sderaadt #include <errno.h>
474b826ba8Sderaadt #include <paths.h>
484b826ba8Sderaadt #include <signal.h>
494b826ba8Sderaadt #include <limits.h>
50ad69070aSdownsj 
51ad69070aSdownsj #include "util.h"
524b826ba8Sderaadt 
5342cbcc77Sniklas static char pw_defdir[] = "/etc";
5442cbcc77Sniklas static char *pw_dir = pw_defdir;
5542cbcc77Sniklas static char *pw_lck;
5642cbcc77Sniklas 
5742cbcc77Sniklas char *
pw_file(const char * nm)5853fedb49Sderaadt pw_file(const char *nm)
5942cbcc77Sniklas {
6042cbcc77Sniklas 	const char *p = strrchr(nm, '/');
6142cbcc77Sniklas 	char *new_nm;
6242cbcc77Sniklas 
6342cbcc77Sniklas 	if (p)
6442cbcc77Sniklas 		p++;
6542cbcc77Sniklas 	else
6642cbcc77Sniklas 		p = nm;
674369fe5bSderaadt 
684369fe5bSderaadt 	if (asprintf(&new_nm, "%s/%s", pw_dir, p) == -1)
6942cbcc77Sniklas 		return NULL;
7042cbcc77Sniklas 	return new_nm;
7142cbcc77Sniklas }
7242cbcc77Sniklas 
7342cbcc77Sniklas void
pw_setdir(const char * dir)7453fedb49Sderaadt pw_setdir(const char *dir)
7542cbcc77Sniklas {
7642cbcc77Sniklas 	char *p;
7742cbcc77Sniklas 
7842cbcc77Sniklas 	if (strcmp (dir, pw_dir) == 0)
7942cbcc77Sniklas 		return;
8042cbcc77Sniklas 	if (pw_dir != pw_defdir)
8142cbcc77Sniklas 		free(pw_dir);
8242cbcc77Sniklas 	pw_dir = strdup(dir);
8342cbcc77Sniklas 	if (pw_lck) {
8442cbcc77Sniklas 		p = pw_file(pw_lck);
8542cbcc77Sniklas 		free(pw_lck);
8642cbcc77Sniklas 		pw_lck = p;
8742cbcc77Sniklas 	}
8842cbcc77Sniklas }
8942cbcc77Sniklas 
9042cbcc77Sniklas 
914b826ba8Sderaadt int
pw_lock(int retries)9253fedb49Sderaadt pw_lock(int retries)
934b826ba8Sderaadt {
944b826ba8Sderaadt 	int i, fd;
954b826ba8Sderaadt 	mode_t old_mode;
964b826ba8Sderaadt 
9777621a77Sray 	if (!pw_lck) {
9877621a77Sray 		errno = EINVAL;
9942cbcc77Sniklas 		return (-1);
10077621a77Sray 	}
1014b826ba8Sderaadt 	/* Acquire the lock file.  */
1024b826ba8Sderaadt 	old_mode = umask(0);
1030205f8e6Sguenther 	fd = open(pw_lck, O_WRONLY|O_CREAT|O_EXCL|O_CLOEXEC, 0600);
104*df69c215Sderaadt 	for (i = 0; i < retries && fd == -1 && errno == EEXIST; i++) {
1054b826ba8Sderaadt 		sleep(1);
1060205f8e6Sguenther 		fd = open(pw_lck, O_WRONLY|O_CREAT|O_EXCL|O_CLOEXEC, 0600);
107ce4f9069Sprovos 	}
1080eea03c6Sderaadt 	(void) umask(old_mode);
1094b826ba8Sderaadt 	return (fd);
1104b826ba8Sderaadt }
1114b826ba8Sderaadt 
1124b826ba8Sderaadt int
pw_mkdb(char * username,int flags)11353fedb49Sderaadt pw_mkdb(char *username, int flags)
1144b826ba8Sderaadt {
11556c841abSmillert 	int pstat, ac;
1164b826ba8Sderaadt 	pid_t pid;
11756c841abSmillert 	char *av[8];
118e7770534Smillert 	struct stat sb;
119e7770534Smillert 
12056c841abSmillert 	if (pw_lck == NULL)
12156c841abSmillert 		return(-1);
12256c841abSmillert 
123e7770534Smillert 	/* A zero length passwd file is never ok */
12456c841abSmillert 	if (stat(pw_lck, &sb) == 0 && sb.st_size == 0) {
125e7770534Smillert 		warnx("%s is zero length", pw_lck);
126e7770534Smillert 		return (-1);
127e7770534Smillert 	}
12856c841abSmillert 
12956c841abSmillert 	ac = 0;
13056c841abSmillert 	av[ac++] = "pwd_mkdb";
13156c841abSmillert 	av[ac++] = "-d";
13256c841abSmillert 	av[ac++] = pw_dir;
13300ca34bfSmillert 	if (flags & _PASSWORD_SECUREONLY)
13456c841abSmillert 		av[ac++] = "-s";
13500ca34bfSmillert 	else if (!(flags & _PASSWORD_OMITV7))
13656c841abSmillert 		av[ac++] = "-p";
13756c841abSmillert 	if (username) {
13856c841abSmillert 		av[ac++] = "-u";
13956c841abSmillert 		av[ac++] = username;
140e7770534Smillert 	}
14156c841abSmillert 	av[ac++] = pw_lck;
14256c841abSmillert 	av[ac] = NULL;
1434b826ba8Sderaadt 
1444b826ba8Sderaadt 	pid = vfork();
1452f447894Sderaadt 	if (pid == -1)
1462f447894Sderaadt 		return (-1);
1474b826ba8Sderaadt 	if (pid == 0) {
14856c841abSmillert 		if (pw_lck)
14956c841abSmillert 			execv(_PATH_PWD_MKDB, av);
15031375ee3Sderaadt 		_exit(1);
1514b826ba8Sderaadt 	}
1524b826ba8Sderaadt 	pid = waitpid(pid, &pstat, 0);
153961df418Sderaadt 	if (pid == -1 || !WIFEXITED(pstat) || WEXITSTATUS(pstat) != 0)
1544b826ba8Sderaadt 		return (-1);
1554b826ba8Sderaadt 	return (0);
1564b826ba8Sderaadt }
1574b826ba8Sderaadt 
1584b826ba8Sderaadt int
pw_abort(void)15953fedb49Sderaadt pw_abort(void)
1604b826ba8Sderaadt {
16142cbcc77Sniklas 	return (pw_lck ? unlink(pw_lck) : -1);
1624b826ba8Sderaadt }
1634b826ba8Sderaadt 
1644b826ba8Sderaadt /* Everything below this point is intended for the convenience of programs
1654b826ba8Sderaadt  * which allow a user to interactively edit the passwd file.  Errors in the
1664b826ba8Sderaadt  * routines below will cause the process to abort. */
1674b826ba8Sderaadt 
1684b826ba8Sderaadt static pid_t editpid = -1;
1694b826ba8Sderaadt 
1704b826ba8Sderaadt static void
pw_cont(int signo)17153fedb49Sderaadt pw_cont(int signo)
1724b826ba8Sderaadt {
173d0314c52Sderaadt 	int save_errno = errno;
1744b826ba8Sderaadt 
1754b826ba8Sderaadt 	if (editpid != -1)
17653fedb49Sderaadt 		kill(editpid, signo);
177d0314c52Sderaadt 	errno = save_errno;
1784b826ba8Sderaadt }
1794b826ba8Sderaadt 
1804b826ba8Sderaadt void
pw_init(void)18153fedb49Sderaadt pw_init(void)
1824b826ba8Sderaadt {
1834b826ba8Sderaadt 	struct rlimit rlim;
1844b826ba8Sderaadt 
1854b826ba8Sderaadt 	/* Unlimited resource limits. */
1864b826ba8Sderaadt 	rlim.rlim_cur = rlim.rlim_max = RLIM_INFINITY;
1874b826ba8Sderaadt 	(void)setrlimit(RLIMIT_CPU, &rlim);
1884b826ba8Sderaadt 	(void)setrlimit(RLIMIT_FSIZE, &rlim);
1894b826ba8Sderaadt 	(void)setrlimit(RLIMIT_STACK, &rlim);
1904b826ba8Sderaadt 	(void)setrlimit(RLIMIT_DATA, &rlim);
1914b826ba8Sderaadt 	(void)setrlimit(RLIMIT_RSS, &rlim);
1924b826ba8Sderaadt 
1934b826ba8Sderaadt 	/* Don't drop core (not really necessary, but GP's). */
1944b826ba8Sderaadt 	rlim.rlim_cur = rlim.rlim_max = 0;
1954b826ba8Sderaadt 	(void)setrlimit(RLIMIT_CORE, &rlim);
1964b826ba8Sderaadt 
1974b826ba8Sderaadt 	/* Turn off signals. */
1984b826ba8Sderaadt 	(void)signal(SIGALRM, SIG_IGN);
1994b826ba8Sderaadt 	(void)signal(SIGHUP, SIG_IGN);
2004b826ba8Sderaadt 	(void)signal(SIGINT, SIG_IGN);
2014b826ba8Sderaadt 	(void)signal(SIGPIPE, SIG_IGN);
2024b826ba8Sderaadt 	(void)signal(SIGQUIT, SIG_IGN);
2034b826ba8Sderaadt 	(void)signal(SIGTERM, SIG_IGN);
2044b826ba8Sderaadt 	(void)signal(SIGCONT, pw_cont);
20542cbcc77Sniklas 
20642cbcc77Sniklas 	if (!pw_lck)
20742cbcc77Sniklas 		pw_lck = pw_file(_PATH_MASTERPASSWD_LOCK);
2084b826ba8Sderaadt }
2094b826ba8Sderaadt 
2104b826ba8Sderaadt void
pw_edit(int notsetuid,const char * filename)21153fedb49Sderaadt pw_edit(int notsetuid, const char *filename)
2124b826ba8Sderaadt {
2134b826ba8Sderaadt 	int pstat;
214fc804817Smillert 	char *p;
21555adf1d4Sderaadt 	char *editor;
216961df418Sderaadt 	char *argp[] = {"sh", "-c", NULL, NULL};
2174b826ba8Sderaadt 
21842cbcc77Sniklas 	if (!filename) {
21942cbcc77Sniklas 		filename = pw_lck;
2204b826ba8Sderaadt 		if (!filename)
22142cbcc77Sniklas 			return;
22242cbcc77Sniklas 	}
22342cbcc77Sniklas 
224d378a4a8Smillert 	if ((editor = getenv("EDITOR")) == NULL)
2254b826ba8Sderaadt 		editor = _PATH_VI;
2261bfae893Sderaadt 
2270ddc0c87Sderaadt 	if (asprintf(&p, "%s %s", editor, filename) == -1)
2281bfae893Sderaadt 		return;
229961df418Sderaadt 	argp[2] = p;
2304b826ba8Sderaadt 
231961df418Sderaadt 	switch (editpid = vfork()) {
232961df418Sderaadt 	case -1:			/* error */
233961df418Sderaadt 		free(p);
234961df418Sderaadt 		return;
235961df418Sderaadt 	case 0:				/* child */
2364b826ba8Sderaadt 		if (notsetuid) {
2374b826ba8Sderaadt 			setgid(getgid());
2384b826ba8Sderaadt 			setuid(getuid());
2394b826ba8Sderaadt 		}
240961df418Sderaadt 		execv(_PATH_BSHELL, argp);
241961df418Sderaadt 		_exit(127);
2424b826ba8Sderaadt 	}
243961df418Sderaadt 
2441bfae893Sderaadt 	free(p);
2454b826ba8Sderaadt 	for (;;) {
2464b826ba8Sderaadt 		editpid = waitpid(editpid, (int *)&pstat, WUNTRACED);
2474b826ba8Sderaadt 		if (editpid == -1)
2484b826ba8Sderaadt 			pw_error(editor, 1, 1);
2494b826ba8Sderaadt 		else if (WIFSTOPPED(pstat))
2504b826ba8Sderaadt 			raise(WSTOPSIG(pstat));
2514b826ba8Sderaadt 		else if (WIFEXITED(pstat) && WEXITSTATUS(pstat) == 0)
2524b826ba8Sderaadt 			break;
2534b826ba8Sderaadt 		else
2544b826ba8Sderaadt 			pw_error(editor, 1, 1);
2554b826ba8Sderaadt 	}
2564b826ba8Sderaadt 	editpid = -1;
2574b826ba8Sderaadt }
2584b826ba8Sderaadt 
2594b826ba8Sderaadt void
pw_prompt(void)26053fedb49Sderaadt pw_prompt(void)
2614b826ba8Sderaadt {
2625b322417Sderaadt 	int first, c;
2634b826ba8Sderaadt 
2644b826ba8Sderaadt 	(void)printf("re-edit the password file? [y]: ");
2654b826ba8Sderaadt 	(void)fflush(stdout);
2665b322417Sderaadt 	first = c = getchar();
2675b322417Sderaadt 	while (c != '\n' && c != EOF)
2684b826ba8Sderaadt 		c = getchar();
269eafde64aSmillert 	switch (first) {
270eafde64aSmillert 	case EOF:
271eafde64aSmillert 		putchar('\n');
272eafde64aSmillert 		/* FALLTHROUGH */
273eafde64aSmillert 	case 'n':
274eafde64aSmillert 	case 'N':
2754b826ba8Sderaadt 		pw_error(NULL, 0, 0);
276eafde64aSmillert 		break;
277eafde64aSmillert 	}
2784b826ba8Sderaadt }
2794b826ba8Sderaadt 
28046bc4394Smillert static int
pw_equal(const struct passwd * pw1,const struct passwd * pw2)28146bc4394Smillert pw_equal(const struct passwd *pw1, const struct passwd *pw2)
2824b826ba8Sderaadt {
28346bc4394Smillert 	return (strcmp(pw1->pw_name, pw2->pw_name) == 0 &&
28446bc4394Smillert 	    pw1->pw_uid == pw2->pw_uid &&
28546bc4394Smillert 	    pw1->pw_gid == pw2->pw_gid &&
28646bc4394Smillert 	    strcmp(pw1->pw_class, pw2->pw_class) == 0 &&
28746bc4394Smillert 	    pw1->pw_change == pw2->pw_change &&
28846bc4394Smillert 	    pw1->pw_expire == pw2->pw_expire &&
28946bc4394Smillert 	    strcmp(pw1->pw_gecos, pw2->pw_gecos) == 0 &&
29046bc4394Smillert 	    strcmp(pw1->pw_dir, pw2->pw_dir) == 0 &&
29146bc4394Smillert 	    strcmp(pw1->pw_shell, pw2->pw_shell) == 0);
29246bc4394Smillert }
29346bc4394Smillert 
29416e2f483Smillert static int
pw_write_entry(FILE * to,const struct passwd * pw)29516e2f483Smillert pw_write_entry(FILE *to, const struct passwd *pw)
29616e2f483Smillert {
29716e2f483Smillert 	char	gidstr[16], uidstr[16];
29816e2f483Smillert 
29916e2f483Smillert 	/* Preserve gid/uid -1 */
30016e2f483Smillert 	if (pw->pw_gid == (gid_t)-1)
30116e2f483Smillert 		strlcpy(gidstr, "-1", sizeof(gidstr));
30216e2f483Smillert 	else
30316e2f483Smillert 		snprintf(gidstr, sizeof(gidstr), "%u", (u_int)pw->pw_gid);
30416e2f483Smillert 
30516e2f483Smillert 	if (pw->pw_uid == (uid_t)-1)
30616e2f483Smillert 		strlcpy(uidstr, "-1", sizeof(uidstr));
30716e2f483Smillert 	else
30816e2f483Smillert 		snprintf(uidstr, sizeof(uidstr), "%u", (u_int)pw->pw_uid);
30916e2f483Smillert 
31016e2f483Smillert 	return fprintf(to, "%s:%s:%s:%s:%s:%lld:%lld:%s:%s:%s\n",
31116e2f483Smillert 	    pw->pw_name, pw->pw_passwd, uidstr, gidstr, pw->pw_class,
31216e2f483Smillert 	    (long long)pw->pw_change, (long long)pw->pw_expire,
31316e2f483Smillert 	    pw->pw_gecos, pw->pw_dir, pw->pw_shell);
31416e2f483Smillert }
31516e2f483Smillert 
31646bc4394Smillert void
pw_copy(int ffd,int tfd,const struct passwd * pw,const struct passwd * opw)31746bc4394Smillert pw_copy(int ffd, int tfd, const struct passwd *pw, const struct passwd *opw)
31846bc4394Smillert {
31946bc4394Smillert 	struct passwd tpw;
3204b826ba8Sderaadt 	FILE   *from, *to;
3214b826ba8Sderaadt 	int	done;
32246bc4394Smillert 	char   *p, *ep, buf[8192];
32342cbcc77Sniklas 	char   *master = pw_file(_PATH_MASTERPASSWD);
3244b826ba8Sderaadt 
32542cbcc77Sniklas 	if (!master)
32642cbcc77Sniklas 		pw_error(NULL, 0, 1);
3274b826ba8Sderaadt 	if (!(from = fdopen(ffd, "r")))
32842cbcc77Sniklas 		pw_error(master, 1, 1);
3294b826ba8Sderaadt 	if (!(to = fdopen(tfd, "w")))
33042cbcc77Sniklas 		pw_error(pw_lck ? pw_lck : NULL, pw_lck ? 1 : 0, 1);
3314b826ba8Sderaadt 
3326d61a838Sderaadt 	for (done = 0; fgets(buf, (int)sizeof(buf), from);) {
33346bc4394Smillert 		if ((ep = strchr(buf, '\n')) == NULL) {
33442cbcc77Sniklas 			warnx("%s: line too long", master);
3354b826ba8Sderaadt 			pw_error(NULL, 0, 1);
3364b826ba8Sderaadt 		}
3374b826ba8Sderaadt 		if (done) {
33816e2f483Smillert 			if (fputs(buf, to))
33960bcd9b8Sray 				goto fail;
3404b826ba8Sderaadt 			continue;
3414b826ba8Sderaadt 		}
3424b826ba8Sderaadt 		if (!(p = strchr(buf, ':'))) {
34342cbcc77Sniklas 			warnx("%s: corrupted entry", master);
3444b826ba8Sderaadt 			pw_error(NULL, 0, 1);
3454b826ba8Sderaadt 		}
3464b826ba8Sderaadt 		*p = '\0';
34746bc4394Smillert 		if (strcmp(buf, opw ? opw->pw_name : pw->pw_name)) {
3484b826ba8Sderaadt 			*p = ':';
34916e2f483Smillert 			if (fputs(buf, to))
35060bcd9b8Sray 				goto fail;
3514b826ba8Sderaadt 			continue;
3524b826ba8Sderaadt 		}
35346bc4394Smillert 		if (opw != NULL) {
35446bc4394Smillert 			*p = ':';
35546bc4394Smillert 			*ep = '\0';
35646bc4394Smillert 			if (!pw_scan(buf, &tpw, NULL))
35746bc4394Smillert 				pw_error(NULL, 0, 1);
35846bc4394Smillert 			if (!pw_equal(&tpw, opw)) {
35946bc4394Smillert 				warnx("%s: inconsistent entry", master);
36046bc4394Smillert 				pw_error(NULL, 0, 1);
36146bc4394Smillert 			}
36246bc4394Smillert 		}
36316e2f483Smillert 		if (pw_write_entry(to, pw) == -1)
36460bcd9b8Sray 			goto fail;
36516e2f483Smillert 		done = 1;
3664b826ba8Sderaadt 	}
36716e2f483Smillert 	if (!done && pw_write_entry(to, pw) == -1)
36816e2f483Smillert 		goto fail;
3694b826ba8Sderaadt 
37016e2f483Smillert 	if (ferror(to) || fflush(to))
37160bcd9b8Sray fail:
37242cbcc77Sniklas 		pw_error(NULL, 0, 1);
373cabd162fSaaron 	free(master);
3744b826ba8Sderaadt 	(void)fclose(to);
3754b826ba8Sderaadt }
3764b826ba8Sderaadt 
3774b826ba8Sderaadt int
pw_scan(char * bp,struct passwd * pw,int * flags)37853fedb49Sderaadt pw_scan(char *bp, struct passwd *pw, int *flags)
3794b826ba8Sderaadt {
3804b826ba8Sderaadt 	int root;
38116e2f483Smillert 	char *p, *sh;
38216e2f483Smillert 	const char *errstr;
3834b826ba8Sderaadt 
38416e2f483Smillert 	if (flags != NULL)
3854b826ba8Sderaadt 		*flags = 0;
3864b826ba8Sderaadt 
387eeea6988Smillert 	if (!(p = strsep(&bp, ":")) || *p == '\0')	/* login */
3884b826ba8Sderaadt 		goto fmt;
389eeea6988Smillert 	pw->pw_name = p;
3904b826ba8Sderaadt 	root = !strcmp(pw->pw_name, "root");
3914b826ba8Sderaadt 
3924b826ba8Sderaadt 	if (!(pw->pw_passwd = strsep(&bp, ":")))	/* passwd */
3934b826ba8Sderaadt 		goto fmt;
3944b826ba8Sderaadt 
3954b826ba8Sderaadt 	if (!(p = strsep(&bp, ":")))			/* uid */
3964b826ba8Sderaadt 		goto fmt;
39716e2f483Smillert 	pw->pw_uid = strtonum(p, -1, UID_MAX, &errstr);
39816e2f483Smillert 	if (errstr != NULL) {
39916e2f483Smillert 		if (*p != '\0') {
40016e2f483Smillert 			warnx("uid is %s", errstr);
40116e2f483Smillert 			return (0);
40216e2f483Smillert 		}
40316e2f483Smillert 		if (flags != NULL)
40416e2f483Smillert 			*flags |= _PASSWORD_NOUID;
40516e2f483Smillert 	}
40616e2f483Smillert 	if (root && pw->pw_uid) {
4074b826ba8Sderaadt 		warnx("root uid should be 0");
4084b826ba8Sderaadt 		return (0);
4094b826ba8Sderaadt 	}
4104b826ba8Sderaadt 
4114b826ba8Sderaadt 	if (!(p = strsep(&bp, ":")))			/* gid */
4124b826ba8Sderaadt 		goto fmt;
41316e2f483Smillert 	pw->pw_gid = strtonum(p, -1, GID_MAX, &errstr);
41416e2f483Smillert 	if (errstr != NULL) {
41516e2f483Smillert 		if (*p != '\0') {
41616e2f483Smillert 			warnx("gid is %s", errstr);
4174b826ba8Sderaadt 			return (0);
4184b826ba8Sderaadt 		}
41916e2f483Smillert 		if (flags != NULL)
4204b826ba8Sderaadt 			*flags |= _PASSWORD_NOGID;
42116e2f483Smillert 	}
4224b826ba8Sderaadt 
4234b826ba8Sderaadt 	pw->pw_class = strsep(&bp, ":");		/* class */
4244b826ba8Sderaadt 	if (!(p = strsep(&bp, ":")))			/* change */
4254b826ba8Sderaadt 		goto fmt;
426a219de85Sguenther 	pw->pw_change = atoll(p);
4274b826ba8Sderaadt 	if ((*p == '\0') && (flags != (int *)NULL))
4284b826ba8Sderaadt 		*flags |= _PASSWORD_NOCHG;
4294b826ba8Sderaadt 	if (!(p = strsep(&bp, ":")))			/* expire */
4304b826ba8Sderaadt 		goto fmt;
431a219de85Sguenther 	pw->pw_expire = atoll(p);
4324b826ba8Sderaadt 	if ((*p == '\0') && (flags != (int *)NULL))
4334b826ba8Sderaadt 		*flags |= _PASSWORD_NOEXP;
4344b826ba8Sderaadt 	pw->pw_gecos = strsep(&bp, ":");		/* gecos */
4354b826ba8Sderaadt 	pw->pw_dir = strsep(&bp, ":");			/* directory */
4364b826ba8Sderaadt 	if (!(pw->pw_shell = strsep(&bp, ":")))		/* shell */
4374b826ba8Sderaadt 		goto fmt;
4384b826ba8Sderaadt 
4394b826ba8Sderaadt 	p = pw->pw_shell;
44009fa58d5Smillert 	if (root && *p) {				/* empty == /bin/sh */
4414b826ba8Sderaadt 		for (setusershell();;) {
4424b826ba8Sderaadt 			if (!(sh = getusershell())) {
4434b826ba8Sderaadt 				warnx("warning, unknown root shell");
4444b826ba8Sderaadt 				break;
4454b826ba8Sderaadt 			}
4464b826ba8Sderaadt 			if (!strcmp(p, sh))
4474b826ba8Sderaadt 				break;
4484b826ba8Sderaadt 		}
44909fa58d5Smillert 		endusershell();
45009fa58d5Smillert 	}
4514b826ba8Sderaadt 
452abf39cbdSmillert 	if ((p = strsep(&bp, ":"))) {			/* too many */
4534b826ba8Sderaadt fmt:		warnx("corrupted entry");
4544b826ba8Sderaadt 		return (0);
4554b826ba8Sderaadt 	}
4564b826ba8Sderaadt 
4574b826ba8Sderaadt 	return (1);
4584b826ba8Sderaadt }
4594b826ba8Sderaadt 
46010977e17Smillert __dead void
pw_error(const char * name,int error,int eval)46160bcd9b8Sray pw_error(const char *name, int error, int eval)
4624b826ba8Sderaadt {
46342cbcc77Sniklas 	char   *master = pw_file(_PATH_MASTERPASSWD);
46442cbcc77Sniklas 
46560bcd9b8Sray 	if (error) {
46659c6398fSmillert 		if (name)
467b638aa94Smillert 			warn("%s", name);
46859c6398fSmillert 		else
46959c6398fSmillert 			warn(NULL);
47059c6398fSmillert 	}
471cb0e69f6Smpech 	if (master) {
47242cbcc77Sniklas 		warnx("%s: unchanged", master);
473cb0e69f6Smpech 		free(master);
474cb0e69f6Smpech 	}
475cb0e69f6Smpech 
4764b826ba8Sderaadt 	pw_abort();
4774b826ba8Sderaadt 	exit(eval);
4784b826ba8Sderaadt }
479