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