xref: /netbsd-src/lib/libc/gen/pw_scan.c (revision c5e820cae412164fcbee52f470436200af5358ea)
1*c5e820caSchristos /*	$NetBSD: pw_scan.c,v 1.23 2012/03/13 21:13:36 christos Exp $	*/
29557a710Slukem 
39557a710Slukem /*
49557a710Slukem  * Copyright (c) 1987, 1993, 1994, 1995
59557a710Slukem  *	The Regents of the University of California.  All rights reserved.
69557a710Slukem  *
79557a710Slukem  * Redistribution and use in source and binary forms, with or without
89557a710Slukem  * modification, are permitted provided that the following conditions
99557a710Slukem  * are met:
109557a710Slukem  * 1. Redistributions of source code must retain the above copyright
119557a710Slukem  *    notice, this list of conditions and the following disclaimer.
129557a710Slukem  * 2. Redistributions in binary form must reproduce the above copyright
139557a710Slukem  *    notice, this list of conditions and the following disclaimer in the
149557a710Slukem  *    documentation and/or other materials provided with the distribution.
15eb7c1594Sagc  * 3. Neither the name of the University nor the names of its contributors
169557a710Slukem  *    may be used to endorse or promote products derived from this software
179557a710Slukem  *    without specific prior written permission.
189557a710Slukem  *
199557a710Slukem  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
209557a710Slukem  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
219557a710Slukem  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
229557a710Slukem  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
239557a710Slukem  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
249557a710Slukem  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
259557a710Slukem  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
269557a710Slukem  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
279557a710Slukem  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
289557a710Slukem  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
299557a710Slukem  * SUCH DAMAGE.
309557a710Slukem  */
319557a710Slukem 
32171d6532Slukem #if HAVE_NBTOOL_CONFIG_H
33171d6532Slukem #include "nbtool_config.h"
34a328e341Stv #include "compat_pwd.h"
35171d6532Slukem 
36a328e341Stv #else
379557a710Slukem #include <sys/cdefs.h>
389557a710Slukem #if defined(LIBC_SCCS) && !defined(lint)
39*c5e820caSchristos __RCSID("$NetBSD: pw_scan.c,v 1.23 2012/03/13 21:13:36 christos Exp $");
409557a710Slukem #endif /* LIBC_SCCS and not lint */
419557a710Slukem 
42f0d001c2Skleink #if defined(_LIBC)
4324a514c5Skleink #include "namespace.h"
44f0d001c2Skleink #endif
459557a710Slukem #include <sys/types.h>
46b48252f3Slukem 
47b48252f3Slukem #include <assert.h>
489557a710Slukem #include <err.h>
499557a710Slukem #include <limits.h>
509557a710Slukem #include <pwd.h>
519557a710Slukem #include <stdio.h>
529557a710Slukem #include <stdlib.h>
539557a710Slukem #include <string.h>
549557a710Slukem #include <unistd.h>
55a31e08fdSchristos #include <errno.h>
569557a710Slukem 
570453a51cSkleink #ifdef _LIBC
5843c06f3fSthorpej #include "pw_private.h"
5943c06f3fSthorpej #endif
60171d6532Slukem #endif /* ! HAVE_NBTOOL_CONFIG_H */
6143c06f3fSthorpej 
62a31e08fdSchristos static int
gettime(time_t * res,const char * p,int * flags,int dowarn,int flag)63*c5e820caSchristos gettime(time_t *res, const char *p, int *flags, int dowarn, int flag)
64a31e08fdSchristos {
65461a86f9Schristos 	long long l;
66a31e08fdSchristos 	char *ep;
67461a86f9Schristos 	const char *vp;
68a31e08fdSchristos 
69a31e08fdSchristos 	if (*p == '\0') {
70a31e08fdSchristos 		*flags |= flag;
71b51e7f15Schristos 		*res = 0;
72a31e08fdSchristos 		return 1;
73a31e08fdSchristos 	}
74461a86f9Schristos 	l = strtoll(p, &ep, 0);
75a31e08fdSchristos 	if (p == ep || *ep != '\0') {
76461a86f9Schristos 		vp = "Invalid number";
77a31e08fdSchristos 		goto done;
78a31e08fdSchristos 	}
79461a86f9Schristos 	if (errno == ERANGE && (l == LLONG_MAX || l == LLONG_MIN)) {
80461a86f9Schristos 		vp = strerror(errno);
81a31e08fdSchristos 		goto done;
82a31e08fdSchristos 	}
83*c5e820caSchristos 	_DIAGASSERT(__type_fit(time_t, l));
84*c5e820caSchristos 	*res = (time_t)l;
85a31e08fdSchristos 	return 1;
86a31e08fdSchristos done:
87a31e08fdSchristos 	if (dowarn) {
88461a86f9Schristos 		warnx("%s `%s' for %s time", vp, p,
89a31e08fdSchristos 		    flag == _PASSWORD_NOEXP ? "expiration" : "change");
90a31e08fdSchristos 	}
91a31e08fdSchristos 	return 0;
92a31e08fdSchristos 
93a31e08fdSchristos }
94a31e08fdSchristos 
95a31e08fdSchristos static int
getid(unsigned long * res,const char * p,int * flags,int dowarn,int flag)96a31e08fdSchristos getid(unsigned long *res, const char *p, int *flags, int dowarn, int flag)
97a31e08fdSchristos {
98a10b4794Schristos 	unsigned long ul;
99a31e08fdSchristos 	char *ep;
100a31e08fdSchristos 
101a31e08fdSchristos 	if (*p == '\0') {
102a31e08fdSchristos 		*flags |= flag;
103a31e08fdSchristos 		*res = 0;
104a31e08fdSchristos 		return 1;
105a31e08fdSchristos 	}
106a31e08fdSchristos 	ul = strtoul(p, &ep, 0);
107a31e08fdSchristos 	if (p == ep || *ep != '\0') {
108a31e08fdSchristos 		ep = __UNCONST("Invalid number");
109a31e08fdSchristos 		goto done;
110a31e08fdSchristos 	}
111a31e08fdSchristos 	if (errno == ERANGE && ul == ULONG_MAX) {
112a31e08fdSchristos 		ep = strerror(errno);
113a31e08fdSchristos 		goto done;
114a31e08fdSchristos 	}
115a31e08fdSchristos 	if (ul > *res) {
116a31e08fdSchristos 		ep = strerror(ERANGE);
117a31e08fdSchristos 		goto done;
118a31e08fdSchristos 	}
119a31e08fdSchristos 
120a31e08fdSchristos 	*res = ul;
121a31e08fdSchristos 	return 1;
122a31e08fdSchristos done:
123a31e08fdSchristos 	if (dowarn)
124b1c3c949Schristos 		warnx("%s %s `%s'", ep,
125a31e08fdSchristos 		    flag == _PASSWORD_NOUID ? "uid" : "gid", p);
126a31e08fdSchristos 	return 0;
127a31e08fdSchristos 
128a31e08fdSchristos }
129a10b4794Schristos 
1309557a710Slukem int
1310453a51cSkleink #ifdef _LIBC
__pw_scan(char * bp,struct passwd * pw,int * flags)132a31e08fdSchristos __pw_scan(char *bp, struct passwd *pw, int *flags)
1330453a51cSkleink #else
134a31e08fdSchristos pw_scan( char *bp, struct passwd *pw, int *flags)
13543c06f3fSthorpej #endif
1369557a710Slukem {
1379557a710Slukem 	unsigned long id;
138*c5e820caSchristos 	time_t ti;
1399557a710Slukem 	int root, inflags;
140b51e7f15Schristos 	int dowarn;
141e5d98237Smycroft 	const char *p, *sh;
1429557a710Slukem 
143b48252f3Slukem 	_DIAGASSERT(bp != NULL);
144b48252f3Slukem 	_DIAGASSERT(pw != NULL);
145b48252f3Slukem 
146a31e08fdSchristos 	if (flags) {
1479557a710Slukem 		inflags = *flags;
1489557a710Slukem 		*flags = 0;
149b51e7f15Schristos 	} else {
150b51e7f15Schristos 		inflags = 0;
151b51e7f15Schristos 		flags = &inflags;
1529557a710Slukem 	}
153b51e7f15Schristos 	dowarn = !(inflags & _PASSWORD_NOWARN);
1549557a710Slukem 
1559557a710Slukem 	if (!(pw->pw_name = strsep(&bp, ":")))		/* login */
1569557a710Slukem 		goto fmt;
157a31e08fdSchristos 	if (strlen(pw->pw_name) > (LOGIN_NAME_MAX - 1)) {
158a31e08fdSchristos 		if (dowarn)
159a31e08fdSchristos 			warnx("username too long, `%s' > %d", pw->pw_name,
160a31e08fdSchristos 			    LOGIN_NAME_MAX - 1);
161a31e08fdSchristos 		return 0;
162a31e08fdSchristos 	}
163a31e08fdSchristos 
1649557a710Slukem 	root = !strcmp(pw->pw_name, "root");
1659557a710Slukem 
1669557a710Slukem 	if (!(pw->pw_passwd = strsep(&bp, ":")))	/* passwd */
1679557a710Slukem 		goto fmt;
1689557a710Slukem 
1699557a710Slukem 	if (!(p = strsep(&bp, ":")))			/* uid */
1709557a710Slukem 		goto fmt;
171a31e08fdSchristos 
172a31e08fdSchristos 	id = UID_MAX;
173a31e08fdSchristos 	if (!getid(&id, p, flags, dowarn, _PASSWORD_NOUID))
174a31e08fdSchristos 		return 0;
175a31e08fdSchristos 
1769557a710Slukem 	if (root && id) {
177a31e08fdSchristos 		if (dowarn)
1789557a710Slukem 			warnx("root uid should be 0");
179a31e08fdSchristos 		return 0;
1809557a710Slukem 	}
181a31e08fdSchristos 
1829557a710Slukem 	pw->pw_uid = (uid_t)id;
1839557a710Slukem 
1849557a710Slukem 	if (!(p = strsep(&bp, ":")))			/* gid */
1859557a710Slukem 		goto fmt;
186a31e08fdSchristos 
187a31e08fdSchristos 	id = GID_MAX;
188a31e08fdSchristos 	if (!getid(&id, p, flags, dowarn, _PASSWORD_NOGID))
189a31e08fdSchristos 		return 0;
190a31e08fdSchristos 
1919557a710Slukem 	pw->pw_gid = (gid_t)id;
1929557a710Slukem 
1939557a710Slukem 	if (inflags & _PASSWORD_OLDFMT) {
1947462bd3eSchristos 		pw->pw_class = __UNCONST("");
1959557a710Slukem 		pw->pw_change = 0;
1969557a710Slukem 		pw->pw_expire = 0;
1979557a710Slukem 		*flags |= (_PASSWORD_NOCHG | _PASSWORD_NOEXP);
1989557a710Slukem 	} else {
1999557a710Slukem 		pw->pw_class = strsep(&bp, ":");	/* class */
2009557a710Slukem 		if (!(p = strsep(&bp, ":")))		/* change */
2019557a710Slukem 			goto fmt;
2024e5aed7eSenami 		if (!gettime(&ti, p, flags, dowarn, _PASSWORD_NOCHG))
203a31e08fdSchristos 			return 0;
2044e5aed7eSenami 		pw->pw_change = ti;
205691a6224Schristos 
2069557a710Slukem 		if (!(p = strsep(&bp, ":")))		/* expire */
2079557a710Slukem 			goto fmt;
2084e5aed7eSenami 		if (!gettime(&ti, p, flags, dowarn, _PASSWORD_NOEXP))
209a31e08fdSchristos 			return 0;
2104e5aed7eSenami 		pw->pw_expire = ti;
2119557a710Slukem 	}
212a31e08fdSchristos 
2139557a710Slukem 	pw->pw_gecos = strsep(&bp, ":");		/* gecos */
2149557a710Slukem 	pw->pw_dir = strsep(&bp, ":");			/* directory */
2159557a710Slukem 	if (!(pw->pw_shell = strsep(&bp, ":")))		/* shell */
2169557a710Slukem 		goto fmt;
2179557a710Slukem 
218171d6532Slukem #if ! HAVE_NBTOOL_CONFIG_H
2199557a710Slukem 	p = pw->pw_shell;
2209557a710Slukem 	if (root && *p)					/* empty == /bin/sh */
2219557a710Slukem 		for (setusershell();;) {
2229557a710Slukem 			if (!(sh = getusershell())) {
223a31e08fdSchristos 				if (dowarn)
2249557a710Slukem 					warnx("warning, unknown root shell");
2259557a710Slukem 				break;
2269557a710Slukem 			}
2279557a710Slukem 			if (!strcmp(p, sh))
2289557a710Slukem 				break;
2299557a710Slukem 		}
230a328e341Stv #endif
2319557a710Slukem 
232d6f53054Schristos 	if ((p = strsep(&bp, ":")) != NULL) {			/* too many */
2339557a710Slukem fmt:
234a31e08fdSchristos 		if (dowarn)
2359557a710Slukem 			warnx("corrupted entry");
236a31e08fdSchristos 		return 0;
2379557a710Slukem 	}
2389557a710Slukem 
239a31e08fdSchristos 	return 1;
2409557a710Slukem }
241