xref: /openbsd-src/lib/libc/gen/authenticate.c (revision b7041c0781c8668129da8084451ded41b0c43954)
1*b7041c07Sderaadt /*	$OpenBSD: authenticate.c,v 1.29 2021/10/24 21:24:20 deraadt Exp $	*/
2e802aa69Smillert 
3e802aa69Smillert /*-
4e802aa69Smillert  * Copyright (c) 1997 Berkeley Software Design, Inc. All rights reserved.
5e802aa69Smillert  *
6e802aa69Smillert  * Redistribution and use in source and binary forms, with or without
7e802aa69Smillert  * modification, are permitted provided that the following conditions
8e802aa69Smillert  * are met:
9e802aa69Smillert  * 1. Redistributions of source code must retain the above copyright
10e802aa69Smillert  *    notice, this list of conditions and the following disclaimer.
11e802aa69Smillert  * 2. Redistributions in binary form must reproduce the above copyright
12e802aa69Smillert  *    notice, this list of conditions and the following disclaimer in the
13e802aa69Smillert  *    documentation and/or other materials provided with the distribution.
14e802aa69Smillert  * 3. All advertising materials mentioning features or use of this software
15e802aa69Smillert  *    must display the following acknowledgement:
16e802aa69Smillert  *	This product includes software developed by Berkeley Software Design,
17e802aa69Smillert  *	Inc.
18e802aa69Smillert  * 4. The name of Berkeley Software Design, Inc.  may not be used to endorse
19e802aa69Smillert  *    or promote products derived from this software without specific prior
20e802aa69Smillert  *    written permission.
21e802aa69Smillert  *
22e802aa69Smillert  * THIS SOFTWARE IS PROVIDED BY BERKELEY SOFTWARE DESIGN, INC. ``AS IS'' AND
23e802aa69Smillert  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24e802aa69Smillert  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25e802aa69Smillert  * ARE DISCLAIMED.  IN NO EVENT SHALL BERKELEY SOFTWARE DESIGN, INC. BE LIABLE
26e802aa69Smillert  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27e802aa69Smillert  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28e802aa69Smillert  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29e802aa69Smillert  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30e802aa69Smillert  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31e802aa69Smillert  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32e802aa69Smillert  * SUCH DAMAGE.
33e802aa69Smillert  *
34e802aa69Smillert  *	BSDI $From: authenticate.c,v 2.21 1999/09/08 22:33:26 prb Exp $
35e802aa69Smillert  */
3669245ebdSmillert 
37e802aa69Smillert #include <sys/stat.h>
38e802aa69Smillert 
39e802aa69Smillert #include <ctype.h>
40e802aa69Smillert #include <err.h>
41e802aa69Smillert #include <fcntl.h>
4269245ebdSmillert #include <limits.h>
43e802aa69Smillert #include <login_cap.h>
44e802aa69Smillert #include <paths.h>
45e802aa69Smillert #include <pwd.h>
46e802aa69Smillert #include <stdarg.h>
47e802aa69Smillert #include <stdio.h>
48e802aa69Smillert #include <stdlib.h>
49e802aa69Smillert #include <string.h>
50e802aa69Smillert #include <syslog.h>
51e802aa69Smillert #include <unistd.h>
52e802aa69Smillert 
53e802aa69Smillert #include <bsd_auth.h>
54e802aa69Smillert 
55e802aa69Smillert static int _auth_checknologin(login_cap_t *, int);
56e802aa69Smillert 
57e802aa69Smillert char *
auth_mkvalue(char * value)58e802aa69Smillert auth_mkvalue(char *value)
59e802aa69Smillert {
60e802aa69Smillert 	char *big, *p;
61e802aa69Smillert 
62e802aa69Smillert 	big = malloc(strlen(value) * 4 + 1);
63e802aa69Smillert 	if (big == NULL)
64e802aa69Smillert 		return (NULL);
65e802aa69Smillert 	/*
66e802aa69Smillert 	 * XXX - There should be a more standardized
67e802aa69Smillert 	 * routine for doing this sort of thing.
68e802aa69Smillert 	 */
69e802aa69Smillert 	for (p = big; *value; ++value) {
70e802aa69Smillert 		switch (*value) {
71e802aa69Smillert 		case '\r':
72e802aa69Smillert 			*p++ = '\\';
73e802aa69Smillert 			*p++ = 'r';
74e802aa69Smillert 			break;
75e802aa69Smillert 		case '\n':
76e802aa69Smillert 			*p++ = '\\';
77e802aa69Smillert 			*p++ = 'n';
78e802aa69Smillert 			break;
79e802aa69Smillert 		case '\\':
80e802aa69Smillert 			*p++ = '\\';
81e802aa69Smillert 			*p++ = *value;
82e802aa69Smillert 			break;
83e802aa69Smillert 		case '\t':
84e802aa69Smillert 		case ' ':
85e802aa69Smillert 			if (p == big)
86e802aa69Smillert 				*p++ = '\\';
87e802aa69Smillert 			*p++ = *value;
88e802aa69Smillert 			break;
89e802aa69Smillert 		default:
90dfe5467eSderaadt 			if (!isprint((unsigned char)*value)) {
91e802aa69Smillert 				*p++ = '\\';
92e802aa69Smillert 				*p++ = ((*value >> 6) & 0x3) + '0';
93e802aa69Smillert 				*p++ = ((*value >> 3) & 0x7) + '0';
94e802aa69Smillert 				*p++ = ((*value     ) & 0x7) + '0';
95e802aa69Smillert 			} else
96e802aa69Smillert 				*p++ = *value;
97e802aa69Smillert 			break;
98e802aa69Smillert 		}
99e802aa69Smillert 	}
100e802aa69Smillert 	*p = '\0';
101e802aa69Smillert 	return (big);
102e802aa69Smillert }
103753e8795Sguenther DEF_WEAK(auth_mkvalue);
104e802aa69Smillert 
105e802aa69Smillert void
auth_checknologin(login_cap_t * lc)106e802aa69Smillert auth_checknologin(login_cap_t *lc)
107e802aa69Smillert {
108e802aa69Smillert 	if (_auth_checknologin(lc, 1))
109e802aa69Smillert 		exit(1);
110e802aa69Smillert }
111753e8795Sguenther DEF_WEAK(auth_checknologin);
112e802aa69Smillert 
113e802aa69Smillert static int
_auth_checknologin(login_cap_t * lc,int print)114e802aa69Smillert _auth_checknologin(login_cap_t *lc, int print)
115e802aa69Smillert {
116e802aa69Smillert 	struct stat sb;
117e802aa69Smillert 	char *nologin;
1182877ca5fSmpech 	int mustfree;
1192877ca5fSmpech 
1202877ca5fSmpech 	if (login_getcapbool(lc, "ignorenologin", 0))
1212877ca5fSmpech 		return (0);
122e802aa69Smillert 
123e802aa69Smillert 	/*
124e802aa69Smillert 	 * If we fail to get the nologin file due to a database error,
125e802aa69Smillert 	 * assume there should have been one...
126e802aa69Smillert 	 */
1272877ca5fSmpech 	nologin = login_getcapstr(lc, "nologin", "", NULL);
1282877ca5fSmpech 	mustfree = nologin && *nologin != '\0';
1292877ca5fSmpech 	if (nologin == NULL)
1302877ca5fSmpech 		goto print_nologin;
1312877ca5fSmpech 
1322877ca5fSmpech 	/* First try the nologin file specified in login.conf. */
1332877ca5fSmpech 	if (*nologin != '\0' && stat(nologin, &sb) == 0)
1342877ca5fSmpech 		goto print_nologin;
135122af69aSderaadt 	if (mustfree) {
1362877ca5fSmpech 		free(nologin);
137122af69aSderaadt 		mustfree = 0;
138122af69aSderaadt 	}
1392877ca5fSmpech 
1402877ca5fSmpech 	/* If that doesn't exist try _PATH_NOLOGIN. */
1412877ca5fSmpech 	if (stat(_PATH_NOLOGIN, &sb) == 0) {
1422877ca5fSmpech 		nologin = _PATH_NOLOGIN;
1432877ca5fSmpech 		goto print_nologin;
1442877ca5fSmpech 	}
1452877ca5fSmpech 
1462877ca5fSmpech 	/* Couldn't stat any nologin files, must be OK to login. */
1472877ca5fSmpech 	return (0);
1482877ca5fSmpech 
1492877ca5fSmpech print_nologin:
150e802aa69Smillert 	if (print) {
1512877ca5fSmpech 		if (!nologin || *nologin == '\0' || auth_cat(nologin) == 0) {
1522877ca5fSmpech 			puts("Logins are not allowed at this time.");
153e802aa69Smillert 			fflush(stdout);
154e802aa69Smillert 		}
1552877ca5fSmpech 	}
1562877ca5fSmpech 	if (mustfree)
1572877ca5fSmpech 		free(nologin);
158e802aa69Smillert 	return (-1);
159e802aa69Smillert }
160e802aa69Smillert 
161e802aa69Smillert int
auth_cat(char * file)162e802aa69Smillert auth_cat(char *file)
163e802aa69Smillert {
164e802aa69Smillert 	int fd, nchars;
165e802aa69Smillert 	char tbuf[8192];
166e802aa69Smillert 
167*b7041c07Sderaadt 	if ((fd = open(file, O_RDONLY)) == -1)
168e802aa69Smillert 		return (0);
169e802aa69Smillert 	while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0)
170e802aa69Smillert 		(void)write(fileno(stdout), tbuf, nchars);
171e802aa69Smillert 	(void)close(fd);
172e802aa69Smillert 	return (1);
173e802aa69Smillert }
174753e8795Sguenther DEF_WEAK(auth_cat);
175e802aa69Smillert 
176e802aa69Smillert int
_auth_validuser(const char * name)177a314d10bSderaadt _auth_validuser(const char *name)
178a314d10bSderaadt {
179a314d10bSderaadt 	/* User name must be specified and may not start with a '-'. */
180a314d10bSderaadt 	if (*name == '\0' || *name == '-') {
181a314d10bSderaadt 		syslog(LOG_ERR, "invalid user name %s", name);
182a314d10bSderaadt 		return 0;
183a314d10bSderaadt 	}
184a314d10bSderaadt 	return 1;
185a314d10bSderaadt }
186a314d10bSderaadt 
187a314d10bSderaadt int
auth_approval(auth_session_t * as,login_cap_t * lc,char * name,char * type)188e802aa69Smillert auth_approval(auth_session_t *as, login_cap_t *lc, char *name, char *type)
189e802aa69Smillert {
190bb14a393Smoritz 	int close_on_exit, close_lc_on_exit, len;
191cd245bcaSmillert 	struct passwd pwstore, *pwd;
192cd245bcaSmillert 	char *approve, *s, path[PATH_MAX], pwbuf[_PW_BUF_LEN];
193e802aa69Smillert 
194e802aa69Smillert 	pwd = NULL;
195e802aa69Smillert 	close_on_exit = as == NULL;
196e802aa69Smillert 	close_lc_on_exit = lc == NULL;
197e802aa69Smillert 
198e802aa69Smillert 	if (as != NULL && name == NULL)
199e802aa69Smillert 		name = auth_getitem(as, AUTHV_NAME);
200e802aa69Smillert 
201e802aa69Smillert 	if (as != NULL)
202e802aa69Smillert 		pwd = auth_getpwd(as);
203e802aa69Smillert 
20420675415Sderaadt 	if (pwd == NULL) {
205cd245bcaSmillert 		if (name != NULL) {
206a314d10bSderaadt 			if (!_auth_validuser(name)) {
207a314d10bSderaadt 				warnx("cannot approve who we don't recognize");
208a314d10bSderaadt 				return (0);
209a314d10bSderaadt 			}
210cd245bcaSmillert 			getpwnam_r(name, &pwstore, pwbuf, sizeof(pwbuf), &pwd);
211cd245bcaSmillert 		} else {
212cd245bcaSmillert 			getpwuid_r(getuid(), &pwstore, pwbuf, sizeof(pwbuf),
213cd245bcaSmillert 			    &pwd);
214cd245bcaSmillert 			if (pwd == NULL) {
21502d24a42Sderaadt 				syslog(LOG_ERR, "no such user id %u", getuid());
2169b9d2a55Sguenther 				warnx("cannot approve who we don't recognize");
217e802aa69Smillert 				return (0);
218e802aa69Smillert 			}
219e802aa69Smillert 			name = pwd->pw_name;
220e802aa69Smillert 		}
22120675415Sderaadt 	}
222e802aa69Smillert 
223e802aa69Smillert 	if (name == NULL)
224e802aa69Smillert 		name = pwd->pw_name;
225e802aa69Smillert 
226e802aa69Smillert 	if (lc == NULL) {
22769245ebdSmillert 		if (strlen(name) >= PATH_MAX) {
228e802aa69Smillert 			syslog(LOG_ERR, "username to login %.*s...",
22969245ebdSmillert 			    PATH_MAX, name);
2309b9d2a55Sguenther 			warnx("username too long");
231e802aa69Smillert 			return (0);
232e802aa69Smillert 		}
233e802aa69Smillert 		if (pwd == NULL && (approve = strchr(name, '.')) != NULL) {
2345af14704Sderaadt 			strlcpy(path, name, sizeof path);
235e802aa69Smillert 			path[approve - name] = '\0';
236cd245bcaSmillert 			getpwnam_r(name, &pwstore, pwbuf, sizeof(pwbuf), &pwd);
237e802aa69Smillert 		}
238e802aa69Smillert 		lc = login_getclass(pwd ? pwd->pw_class : NULL);
239e802aa69Smillert 		if (lc == NULL) {
2409b9d2a55Sguenther 			warnx("unable to classify user");
241e802aa69Smillert 			return (0);
242e802aa69Smillert 		}
243e802aa69Smillert 	}
244e802aa69Smillert 
245e802aa69Smillert 	if (!type)
246e802aa69Smillert 		type = LOGIN_DEFSERVICE;
247e802aa69Smillert 	else {
248e802aa69Smillert 		if (strncmp(type, "approve-", 8) == 0)
249e802aa69Smillert 			type += 8;
250e802aa69Smillert 
251bb14a393Smoritz 		len = snprintf(path, sizeof(path), "approve-%s", type);
252bb14a393Smoritz 		if (len < 0 || len >= sizeof(path)) {
253bb14a393Smoritz 			if (close_lc_on_exit)
254bb14a393Smoritz 				login_close(lc);
255bb14a393Smoritz 			syslog(LOG_ERR, "approval path too long %.*s...",
25669245ebdSmillert 			    PATH_MAX, type);
2579b9d2a55Sguenther 			warnx("approval script path too long");
258bb14a393Smoritz 			return (0);
259bb14a393Smoritz 		}
260e802aa69Smillert 	}
261e802aa69Smillert 
262e802aa69Smillert 	if ((approve = login_getcapstr(lc, s = path, NULL, NULL)) == NULL)
263e802aa69Smillert 		approve = login_getcapstr(lc, s = "approve", NULL, NULL);
264e802aa69Smillert 
265e802aa69Smillert 	if (approve && approve[0] != '/') {
266e802aa69Smillert 		if (close_lc_on_exit)
267e802aa69Smillert 			login_close(lc);
268e802aa69Smillert 		syslog(LOG_ERR, "Invalid %s script: %s", s, approve);
2699b9d2a55Sguenther 		warnx("invalid path to approval script");
270c89dc092Smpech 		free(approve);
271e802aa69Smillert 		return (0);
272e802aa69Smillert 	}
273e802aa69Smillert 
274e802aa69Smillert 	if (as == NULL && (as = auth_open()) == NULL) {
275e802aa69Smillert 		if (close_lc_on_exit)
276e802aa69Smillert 			login_close(lc);
277e802aa69Smillert 		syslog(LOG_ERR, "%m");
2789b9d2a55Sguenther 		warn(NULL);
279c89dc092Smpech 		free(approve);
280e802aa69Smillert 		return (0);
281e802aa69Smillert 	}
282e802aa69Smillert 
283e802aa69Smillert 	auth_setstate(as, AUTH_OKAY);
284e802aa69Smillert 	if (auth_setitem(as, AUTHV_NAME, name) < 0) {
285e802aa69Smillert 		syslog(LOG_ERR, "%m");
2869b9d2a55Sguenther 		warn(NULL);
287e802aa69Smillert 		goto out;
288e802aa69Smillert 	}
289c39118a5Smarkus 	if (auth_check_expire(as) < 0)	/* is this account expired */
290e802aa69Smillert 		goto out;
291e802aa69Smillert 	if (_auth_checknologin(lc,
292e802aa69Smillert 	    auth_getitem(as, AUTHV_INTERACTIVE) != NULL)) {
293e802aa69Smillert 		auth_setstate(as, (auth_getstate(as) & ~AUTH_ALLOW));
294e802aa69Smillert 		goto out;
295e802aa69Smillert 	}
296e802aa69Smillert 	if (login_getcapbool(lc, "requirehome", 0) && pwd && pwd->pw_dir &&
297e802aa69Smillert 	    pwd->pw_dir[0]) {
298e802aa69Smillert 		struct stat sb;
299e802aa69Smillert 
300df69c215Sderaadt 		if (stat(pwd->pw_dir, &sb) == -1 || !S_ISDIR(sb.st_mode) ||
301e802aa69Smillert 		    (pwd->pw_uid && sb.st_uid == pwd->pw_uid &&
302e802aa69Smillert 		    (sb.st_mode & S_IXUSR) == 0)) {
303e802aa69Smillert 			auth_setstate(as, (auth_getstate(as) & ~AUTH_ALLOW));
304e802aa69Smillert 			goto out;
305e802aa69Smillert 		}
306e802aa69Smillert 	}
307e802aa69Smillert 	if (approve)
308a314d10bSderaadt 		auth_call(as, approve, strrchr(approve, '/') + 1, "--", name,
3090ecd7014Smillert 		    lc->lc_class, type, (char *)NULL);
310e802aa69Smillert 
311e802aa69Smillert out:
312c89dc092Smpech 	free(approve);
313e802aa69Smillert 	if (close_lc_on_exit)
314e802aa69Smillert 		login_close(lc);
315e802aa69Smillert 
316e802aa69Smillert 	if (close_on_exit)
317e802aa69Smillert 		return (auth_close(as));
318e802aa69Smillert 	return (auth_getstate(as) & AUTH_ALLOW);
319e802aa69Smillert }
320753e8795Sguenther DEF_WEAK(auth_approval);
321e802aa69Smillert 
322e802aa69Smillert auth_session_t *
auth_usercheck(char * name,char * style,char * type,char * password)323e802aa69Smillert auth_usercheck(char *name, char *style, char *type, char *password)
324e802aa69Smillert {
32569245ebdSmillert 	char namebuf[LOGIN_NAME_MAX + 1 + NAME_MAX + 1];
326cd245bcaSmillert 	char pwbuf[_PW_BUF_LEN];
327e802aa69Smillert 	auth_session_t *as;
328e802aa69Smillert 	login_cap_t *lc;
329cd245bcaSmillert 	struct passwd pwstore, *pwd = NULL;
330fa843023Smillert 	char *slash;
331e802aa69Smillert 
332a314d10bSderaadt 	if (!_auth_validuser(name))
333a314d10bSderaadt 		return (NULL);
334d57f22e5Smillert 	if (strlcpy(namebuf, name, sizeof(namebuf)) >= sizeof(namebuf))
335e802aa69Smillert 		return (NULL);
336e802aa69Smillert 	name = namebuf;
337e802aa69Smillert 
338e802aa69Smillert 	/*
339e802aa69Smillert 	 * Split up user:style names if we were not given a style
340e802aa69Smillert 	 */
341e802aa69Smillert 	if (style == NULL && (style = strchr(name, ':')) != NULL)
342e802aa69Smillert 		*style++ = '\0';
343e802aa69Smillert 
344e802aa69Smillert 	/*
345fa843023Smillert 	 * Cope with user/instance.  We are only using this to get
346fa843023Smillert 	 * the class so it is okay if we strip a /root instance
347e802aa69Smillert 	 * The actual login script will pay attention to the instance.
348e802aa69Smillert 	 */
349cd245bcaSmillert 	getpwnam_r(name, &pwstore, pwbuf, sizeof(pwbuf), &pwd);
350cd245bcaSmillert 	if (pwd == NULL) {
351fa843023Smillert 		if ((slash = strchr(name, '/')) != NULL) {
352fa843023Smillert 			*slash = '\0';
353cd245bcaSmillert 			getpwnam_r(name, &pwstore, pwbuf, sizeof(pwbuf), &pwd);
354fa843023Smillert 			*slash = '/';
355e802aa69Smillert 		}
356e802aa69Smillert 	}
3570bc1d88dSmillert 	if ((lc = login_getclass(pwd ? pwd->pw_class : NULL)) == NULL)
358e802aa69Smillert 		return (NULL);
359e802aa69Smillert 
360e802aa69Smillert 	if ((style = login_getstyle(lc, style, type)) == NULL) {
361e802aa69Smillert 		login_close(lc);
362e802aa69Smillert 		return (NULL);
363e802aa69Smillert 	}
364e802aa69Smillert 
365e802aa69Smillert 	if (password) {
366e802aa69Smillert 		if ((as = auth_open()) == NULL) {
367e802aa69Smillert 			login_close(lc);
368e802aa69Smillert 			return (NULL);
369e802aa69Smillert 		}
370e802aa69Smillert 		auth_setitem(as, AUTHV_SERVICE, "response");
371e802aa69Smillert 		auth_setdata(as, "", 1);
372e802aa69Smillert 		auth_setdata(as, password, strlen(password) + 1);
373c41446b5Sdlg 		explicit_bzero(password, strlen(password));
374e802aa69Smillert 	} else
375e802aa69Smillert 		as = NULL;
3760ecd7014Smillert 	as = auth_verify(as, style, name, lc->lc_class, (char *)NULL);
377e802aa69Smillert 	login_close(lc);
378e802aa69Smillert 	return (as);
379e802aa69Smillert }
380753e8795Sguenther DEF_WEAK(auth_usercheck);
381e802aa69Smillert 
382e802aa69Smillert int
auth_userokay(char * name,char * style,char * type,char * password)383e802aa69Smillert auth_userokay(char *name, char *style, char *type, char *password)
384e802aa69Smillert {
385e802aa69Smillert 	auth_session_t *as;
38608b57e3dSmillert 
387e802aa69Smillert 	as = auth_usercheck(name, style, type, password);
388e802aa69Smillert 
389e802aa69Smillert 	return (as != NULL ? auth_close(as) : 0);
390e802aa69Smillert }
391753e8795Sguenther DEF_WEAK(auth_userokay);
392e802aa69Smillert 
393e802aa69Smillert auth_session_t *
auth_userchallenge(char * name,char * style,char * type,char ** challengep)394e802aa69Smillert auth_userchallenge(char *name, char *style, char *type, char **challengep)
395e802aa69Smillert {
39669245ebdSmillert 	char namebuf[LOGIN_NAME_MAX + 1 + NAME_MAX + 1];
397e802aa69Smillert 	auth_session_t *as;
398e802aa69Smillert 	login_cap_t *lc;
399cd245bcaSmillert 	struct passwd pwstore, *pwd = NULL;
400cd245bcaSmillert 	char *slash, pwbuf[_PW_BUF_LEN];
401e802aa69Smillert 
402a314d10bSderaadt 	if (!_auth_validuser(name))
403a314d10bSderaadt 		return (NULL);
404e802aa69Smillert 	if (strlen(name) >= sizeof(namebuf))
405e802aa69Smillert 		return (NULL);
4065af14704Sderaadt 	strlcpy(namebuf, name, sizeof namebuf);
407e802aa69Smillert 	name = namebuf;
408e802aa69Smillert 
409e802aa69Smillert 	/*
410e802aa69Smillert 	 * Split up user:style names if we were not given a style
411e802aa69Smillert 	 */
412e802aa69Smillert 	if (style == NULL && (style = strchr(name, ':')) != NULL)
413e802aa69Smillert 		*style++ = '\0';
414e802aa69Smillert 
415e802aa69Smillert 	/*
416fa843023Smillert 	 * Cope with user/instance.  We are only using this to get
417fa843023Smillert 	 * the class so it is okay if we strip a /root instance
418e802aa69Smillert 	 * The actual login script will pay attention to the instance.
419e802aa69Smillert 	 */
420cd245bcaSmillert 	getpwnam_r(name, &pwstore, pwbuf, sizeof(pwbuf), &pwd);
421cd245bcaSmillert 	if (pwd == NULL) {
422fa843023Smillert 		if ((slash = strchr(name, '/')) != NULL) {
423fa843023Smillert 			*slash = '\0';
424cd245bcaSmillert 			getpwnam_r(name, &pwstore, pwbuf, sizeof(pwbuf), &pwd);
425fa843023Smillert 			*slash = '/';
426e802aa69Smillert 		}
427e802aa69Smillert 	}
4280bc1d88dSmillert 	if ((lc = login_getclass(pwd ? pwd->pw_class : NULL)) == NULL)
429e802aa69Smillert 		return (NULL);
430e802aa69Smillert 
431e802aa69Smillert 	if ((style = login_getstyle(lc, style, type)) == NULL ||
432e802aa69Smillert 	    (as = auth_open()) == NULL) {
433e802aa69Smillert 		login_close(lc);
434e802aa69Smillert 		return (NULL);
435e802aa69Smillert 	}
436e802aa69Smillert 	if (auth_setitem(as, AUTHV_STYLE, style) < 0 ||
437e802aa69Smillert 	    auth_setitem(as, AUTHV_NAME, name) < 0 ||
4380bc1d88dSmillert 	    auth_setitem(as, AUTHV_CLASS, lc->lc_class) < 0) {
439e802aa69Smillert 		auth_close(as);
440e802aa69Smillert 		login_close(lc);
441e802aa69Smillert 		return (NULL);
442e802aa69Smillert 	}
443e802aa69Smillert 	login_close(lc);
444e802aa69Smillert 	*challengep = auth_challenge(as);
445e802aa69Smillert 	return (as);
446e802aa69Smillert }
447753e8795Sguenther DEF_WEAK(auth_userchallenge);
448e802aa69Smillert 
449e802aa69Smillert int
auth_userresponse(auth_session_t * as,char * response,int more)450e802aa69Smillert auth_userresponse(auth_session_t *as, char *response, int more)
451e802aa69Smillert {
45269245ebdSmillert 	char path[PATH_MAX];
453e802aa69Smillert 	char *style, *name, *challenge, *class;
454bb14a393Smoritz 	int len;
455e802aa69Smillert 
456e802aa69Smillert 	if (as == NULL)
457e802aa69Smillert 		return (0);
458e802aa69Smillert 
459e802aa69Smillert 	auth_setstate(as, 0);
460e802aa69Smillert 
461e802aa69Smillert 	if ((style = auth_getitem(as, AUTHV_STYLE)) == NULL ||
462a314d10bSderaadt 	    (name = auth_getitem(as, AUTHV_NAME)) == NULL ||
463a314d10bSderaadt 	    !_auth_validuser(name)) {
464e802aa69Smillert 		if (more == 0)
465e802aa69Smillert 			return (auth_close(as));
466e802aa69Smillert 		return(0);
467e802aa69Smillert 	}
468bb14a393Smoritz 
469bb14a393Smoritz 	len = snprintf(path, sizeof(path), _PATH_AUTHPROG "%s", style);
470bb14a393Smoritz 	if (len < 0 || len >= sizeof(path)) {
471bb14a393Smoritz 		if (more == 0)
472bb14a393Smoritz 			return (auth_close(as));
473bb14a393Smoritz 		return (0);
474bb14a393Smoritz 	}
475bb14a393Smoritz 
476e802aa69Smillert 	challenge = auth_getitem(as, AUTHV_CHALLENGE);
477e802aa69Smillert 	class = auth_getitem(as, AUTHV_CLASS);
478e802aa69Smillert 
479e802aa69Smillert 	if (challenge)
480e802aa69Smillert 		auth_setdata(as, challenge, strlen(challenge) + 1);
481e802aa69Smillert 	else
482e802aa69Smillert 		auth_setdata(as, "", 1);
4832b0e3e01Smillert 	if (response) {
484e802aa69Smillert 		auth_setdata(as, response, strlen(response) + 1);
485c41446b5Sdlg 		explicit_bzero(response, strlen(response));
4862b0e3e01Smillert 	} else
487e802aa69Smillert 		auth_setdata(as, "", 1);
488e802aa69Smillert 
489a314d10bSderaadt 	auth_call(as, path, style, "-s", "response", "--", name,
490a314d10bSderaadt 	    class, (char *)NULL);
491e802aa69Smillert 
492e802aa69Smillert 	/*
493e802aa69Smillert 	 * If they authenticated then make sure they did not expire
494e802aa69Smillert 	 */
495e802aa69Smillert 	if (auth_getstate(as) & AUTH_ALLOW)
496e802aa69Smillert 		auth_check_expire(as);
497e802aa69Smillert 	if (more == 0)
498e802aa69Smillert 		return (auth_close(as));
499e802aa69Smillert 	return (auth_getstate(as) & AUTH_ALLOW);
500e802aa69Smillert }
501753e8795Sguenther DEF_WEAK(auth_userresponse);
502e802aa69Smillert 
503e802aa69Smillert /*
504e802aa69Smillert  * Authenticate name with the specified style.
505e802aa69Smillert  * If ``as'' is NULL a new session is formed with the default service.
506e802aa69Smillert  * Returns NULL only if ``as'' is NULL and we were unable to allocate
507e802aa69Smillert  * a new session.
508e802aa69Smillert  *
509e802aa69Smillert  * Use auth_close() or auth_getstate() to determine if the authentication
510e802aa69Smillert  * worked.
511e802aa69Smillert  */
512e802aa69Smillert auth_session_t *
auth_verify(auth_session_t * as,char * style,char * name,...)513e802aa69Smillert auth_verify(auth_session_t *as, char *style, char *name, ...)
514e802aa69Smillert {
515e802aa69Smillert 	va_list ap;
51669245ebdSmillert 	char path[PATH_MAX];
517e802aa69Smillert 
518e802aa69Smillert 	if ((name == NULL || style == NULL) && as == NULL)
519a314d10bSderaadt 		return (NULL);
520e802aa69Smillert 
521e802aa69Smillert 	if (as == NULL && (as = auth_open()) == NULL)
522e802aa69Smillert 		return (NULL);
523e802aa69Smillert 	auth_setstate(as, 0);
524e802aa69Smillert 
525e802aa69Smillert 	if (style != NULL && auth_setitem(as, AUTHV_STYLE, style) < 0)
526e802aa69Smillert 		return (as);
527e802aa69Smillert 
528e802aa69Smillert 	if (name != NULL && auth_setitem(as, AUTHV_NAME, name) < 0)
529e802aa69Smillert 		return (as);
530e802aa69Smillert 
531e802aa69Smillert 	style = auth_getitem(as, AUTHV_STYLE);
532e802aa69Smillert 	name = auth_getitem(as, AUTHV_NAME);
533a314d10bSderaadt 	if (!_auth_validuser(name))
534a314d10bSderaadt 		return (as);
535e802aa69Smillert 
536e802aa69Smillert 	snprintf(path, sizeof(path), _PATH_AUTHPROG "%s", style);
537e802aa69Smillert 	va_start(ap, name);
538e802aa69Smillert 	auth_set_va_list(as, ap);
539e802aa69Smillert 	auth_call(as, path, auth_getitem(as, AUTHV_STYLE), "-s",
540a314d10bSderaadt 	    auth_getitem(as, AUTHV_SERVICE), "--", name, (char *)NULL);
5414bd92a99Smillert 	va_end(ap);
542e802aa69Smillert 	return (as);
543e802aa69Smillert }
544753e8795Sguenther DEF_WEAK(auth_verify);
545