1*036a3c97Sguenther /* $OpenBSD: auth_subr.c,v 1.56 2020/10/13 04:42:28 guenther Exp $ */
2e802aa69Smillert
39cb2850aSmillert /*
4bf198cc6Smillert * Copyright (c) 2000-2002,2004 Todd C. Miller <millert@openbsd.org>
59cb2850aSmillert *
69cb2850aSmillert * Permission to use, copy, modify, and distribute this software for any
79cb2850aSmillert * purpose with or without fee is hereby granted, provided that the above
89cb2850aSmillert * copyright notice and this permission notice appear in all copies.
99cb2850aSmillert *
109cb2850aSmillert * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
119cb2850aSmillert * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
129cb2850aSmillert * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
139cb2850aSmillert * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
149cb2850aSmillert * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
159cb2850aSmillert * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
169cb2850aSmillert * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
179cb2850aSmillert */
18e802aa69Smillert /*-
19e802aa69Smillert * Copyright (c) 1995,1996,1997 Berkeley Software Design, Inc.
20e802aa69Smillert * All rights reserved.
21e802aa69Smillert *
22e802aa69Smillert * Redistribution and use in source and binary forms, with or without
23e802aa69Smillert * modification, are permitted provided that the following conditions
24e802aa69Smillert * are met:
25e802aa69Smillert * 1. Redistributions of source code must retain the above copyright
26e802aa69Smillert * notice, this list of conditions and the following disclaimer.
27e802aa69Smillert * 2. Redistributions in binary form must reproduce the above copyright
28e802aa69Smillert * notice, this list of conditions and the following disclaimer in the
29e802aa69Smillert * documentation and/or other materials provided with the distribution.
30e802aa69Smillert * 3. All advertising materials mentioning features or use of this software
31e802aa69Smillert * must display the following acknowledgement:
32e802aa69Smillert * This product includes software developed by Berkeley Software Design,
33e802aa69Smillert * Inc.
34e802aa69Smillert * 4. The name of Berkeley Software Design, Inc. may not be used to endorse
35e802aa69Smillert * or promote products derived from this software without specific prior
36e802aa69Smillert * written permission.
37e802aa69Smillert *
38e802aa69Smillert * THIS SOFTWARE IS PROVIDED BY BERKELEY SOFTWARE DESIGN, INC. ``AS IS'' AND
39e802aa69Smillert * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
40e802aa69Smillert * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
41e802aa69Smillert * ARE DISCLAIMED. IN NO EVENT SHALL BERKELEY SOFTWARE DESIGN, INC. BE LIABLE
42e802aa69Smillert * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
43e802aa69Smillert * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
44e802aa69Smillert * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
45e802aa69Smillert * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
46e802aa69Smillert * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
47e802aa69Smillert * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
48e802aa69Smillert * SUCH DAMAGE.
49e802aa69Smillert *
50e802aa69Smillert * BSDI $From: auth_subr.c,v 2.4 1999/09/08 04:10:40 prb Exp $
51e802aa69Smillert */
5269245ebdSmillert
53e802aa69Smillert #include <sys/time.h>
54e802aa69Smillert #include <sys/resource.h>
55e802aa69Smillert #include <sys/socket.h>
56e802aa69Smillert #include <sys/wait.h>
57e802aa69Smillert
58e802aa69Smillert #include <ctype.h>
59e802aa69Smillert #include <err.h>
60e802aa69Smillert #include <errno.h>
61e802aa69Smillert #include <fcntl.h>
6269245ebdSmillert #include <limits.h>
63e802aa69Smillert #include <paths.h>
64e802aa69Smillert #include <pwd.h>
65e802aa69Smillert #include <stdarg.h>
66e802aa69Smillert #include <stdio.h>
67e802aa69Smillert #include <stdlib.h>
68e802aa69Smillert #include <string.h>
69e802aa69Smillert #include <syslog.h>
70e802aa69Smillert #include <unistd.h>
71e802aa69Smillert
72e802aa69Smillert #include <login_cap.h>
73e802aa69Smillert
74e802aa69Smillert #define MAXSPOOLSIZE (8*1024) /* Spool up to 8K of back info */
75e802aa69Smillert
76e802aa69Smillert struct rmfiles {
77e802aa69Smillert struct rmfiles *next;
78e802aa69Smillert char *file;
79e802aa69Smillert };
80e802aa69Smillert
81e802aa69Smillert struct authopts {
82e802aa69Smillert struct authopts *next;
83e802aa69Smillert char *opt;
84e802aa69Smillert };
85e802aa69Smillert
86e802aa69Smillert struct authdata {
87e802aa69Smillert struct authdata *next;
88e802aa69Smillert void *ptr;
89e802aa69Smillert size_t len;
90e802aa69Smillert };
91e802aa69Smillert
92e802aa69Smillert struct auth_session_t {
93e802aa69Smillert char *name; /* name of use being authenticated */
94e802aa69Smillert char *style; /* style of authentication used */
95e802aa69Smillert char *class; /* class of user */
96e802aa69Smillert char *service; /* type of service being performed */
97e802aa69Smillert char *challenge; /* last challenge issued */
98e802aa69Smillert int flags; /* see below */
99e802aa69Smillert struct passwd *pwd; /* password entry for user */
100e802aa69Smillert struct timeval now; /* time of authentication */
101e802aa69Smillert
102e802aa69Smillert int state; /* authenticated state */
103e802aa69Smillert
104e802aa69Smillert struct rmfiles *rmlist; /* list of files to remove on failure */
105e802aa69Smillert struct authopts *optlist; /* list of options to scripts */
106e802aa69Smillert struct authdata *data; /* additional data to send to scripts */
107e802aa69Smillert
108e802aa69Smillert char spool[MAXSPOOLSIZE]; /* data returned from login script */
109e802aa69Smillert int index; /* how much returned thus far */
110e802aa69Smillert
1116e2de6bbSmillert int fd; /* connection to authenticator */
1126e2de6bbSmillert
113e802aa69Smillert va_list ap0; /* argument list to auth_call */
114e802aa69Smillert va_list ap; /* additional arguments to auth_call */
115e802aa69Smillert };
116e802aa69Smillert
117e802aa69Smillert /*
118e802aa69Smillert * Internal flags
119e802aa69Smillert */
120e802aa69Smillert #define AF_INTERACTIVE 0x0001 /* This is an interactive session */
121e802aa69Smillert
122e802aa69Smillert /*
123e802aa69Smillert * We cannot include bsd_auth.h until we define the above structures
124e802aa69Smillert */
125e802aa69Smillert #include <bsd_auth.h>
126e802aa69Smillert
127e802aa69Smillert /*
128e802aa69Smillert * Internally used functions
129e802aa69Smillert */
130e802aa69Smillert static void _add_rmlist(auth_session_t *, char *);
131e802aa69Smillert static void _auth_spool(auth_session_t *, int);
1326e2de6bbSmillert static void _recv_fd(auth_session_t *, int);
133e802aa69Smillert static char *_auth_next_arg(auth_session_t *);
134e802aa69Smillert /*
135e802aa69Smillert * Set up a known environment for all authentication scripts.
136e802aa69Smillert */
137*036a3c97Sguenther static char * const auth_environ[] = {
138e802aa69Smillert "PATH=" _PATH_DEFPATH,
139e802aa69Smillert "SHELL=" _PATH_BSHELL,
140e802aa69Smillert NULL,
141e802aa69Smillert };
142e802aa69Smillert
143e802aa69Smillert static char defservice[] = LOGIN_DEFSERVICE;
144e802aa69Smillert
1454808f726Smillert static va_list nilap;
1464808f726Smillert
147e802aa69Smillert /*
148e802aa69Smillert * Quick one liners that only exist to keep auth_session_t opaque
149e802aa69Smillert */
auth_setstate(auth_session_t * as,int s)150e802aa69Smillert void auth_setstate(auth_session_t *as, int s){ as->state = s; }
auth_set_va_list(auth_session_t * as,va_list ap)151c942b0a5Sdaniel void auth_set_va_list(auth_session_t *as, va_list ap) { va_copy(as->ap, ap); }
auth_getstate(auth_session_t * as)152e802aa69Smillert int auth_getstate(auth_session_t *as) { return (as->state); }
auth_getpwd(auth_session_t * as)153e802aa69Smillert struct passwd *auth_getpwd(auth_session_t *as) { return (as->pwd); }
154753e8795Sguenther DEF_WEAK(auth_setstate);
155753e8795Sguenther DEF_WEAK(auth_set_va_list);
156753e8795Sguenther DEF_WEAK(auth_getstate);
157753e8795Sguenther DEF_WEAK(auth_getpwd);
158e802aa69Smillert
159e802aa69Smillert /*
160e802aa69Smillert * Open a new BSD Authentication session with the default service
161e802aa69Smillert * (which can be changed later).
162e802aa69Smillert */
163e802aa69Smillert auth_session_t *
auth_open(void)164f723aa39Sderaadt auth_open(void)
165e802aa69Smillert {
166e802aa69Smillert auth_session_t *as;
167e802aa69Smillert
168c7421165Stedu if ((as = calloc(1, sizeof(auth_session_t))) != NULL) {
169e802aa69Smillert as->service = defservice;
1706e2de6bbSmillert as->fd = -1;
171e802aa69Smillert }
172e802aa69Smillert
173e802aa69Smillert return (as);
174e802aa69Smillert }
175753e8795Sguenther DEF_WEAK(auth_open);
176e802aa69Smillert
177e802aa69Smillert /*
178e802aa69Smillert * Clean the specified BSD Authentication session.
179e802aa69Smillert */
180e802aa69Smillert void
auth_clean(auth_session_t * as)181e802aa69Smillert auth_clean(auth_session_t *as)
182e802aa69Smillert {
183e802aa69Smillert struct rmfiles *rm;
184e802aa69Smillert struct authdata *data;
185e802aa69Smillert
186e802aa69Smillert as->state = 0;
187e802aa69Smillert
188e802aa69Smillert auth_clrenv(as);
189e802aa69Smillert
190e802aa69Smillert /*
191e802aa69Smillert * Clean out the rmlist and remove specified files
192e802aa69Smillert */
193e802aa69Smillert while ((rm = as->rmlist) != NULL) {
194e802aa69Smillert as->rmlist = rm->next;
195e802aa69Smillert unlink(rm->file);
196e802aa69Smillert free(rm);
197e802aa69Smillert }
198e802aa69Smillert
199e802aa69Smillert /*
200e802aa69Smillert * Clean out data
201e802aa69Smillert */
202e802aa69Smillert while ((data = as->data) != NULL) {
203e802aa69Smillert if (as->data->len)
2048fbd7fcbSdoug explicit_bzero(as->data->ptr, as->data->len);
205e802aa69Smillert as->data = data->next;
206e802aa69Smillert free(data);
207e802aa69Smillert }
208e802aa69Smillert
209e802aa69Smillert auth_setitem(as, AUTHV_ALL, NULL);
210e802aa69Smillert
211e802aa69Smillert if (as->pwd != NULL) {
2128fbd7fcbSdoug explicit_bzero(as->pwd->pw_passwd, strlen(as->pwd->pw_passwd));
213e802aa69Smillert free(as->pwd);
214e802aa69Smillert as->pwd = NULL;
215e802aa69Smillert }
2166e2de6bbSmillert
2176e2de6bbSmillert if (as->fd != -1) {
2186e2de6bbSmillert close(as->fd);
2196e2de6bbSmillert as->fd = -1;
2206e2de6bbSmillert }
221e802aa69Smillert }
222753e8795Sguenther DEF_WEAK(auth_clean);
223e802aa69Smillert
224e802aa69Smillert /*
225e802aa69Smillert * Close the specified BSD Authentication session.
226e802aa69Smillert * Return 0 if not authenticated.
227e802aa69Smillert */
228e802aa69Smillert int
auth_close(auth_session_t * as)229e802aa69Smillert auth_close(auth_session_t *as)
230e802aa69Smillert {
231e802aa69Smillert struct rmfiles *rm;
232e802aa69Smillert struct authopts *opt;
233e802aa69Smillert struct authdata *data;
234e802aa69Smillert int s;
235e802aa69Smillert
236e802aa69Smillert /*
237e802aa69Smillert * Save our return value
238e802aa69Smillert */
239e802aa69Smillert s = as->state & AUTH_ALLOW;
240e802aa69Smillert
241e802aa69Smillert if (s == 0)
242e802aa69Smillert as->index = 0;
243e802aa69Smillert
244e802aa69Smillert auth_setenv(as);
245e802aa69Smillert
246e802aa69Smillert
247e802aa69Smillert /*
248e802aa69Smillert * Clean out the rmlist and remove specified files if the
249e802aa69Smillert * authentication failed
250e802aa69Smillert */
251e802aa69Smillert while ((rm = as->rmlist) != NULL) {
252e802aa69Smillert as->rmlist = rm->next;
253e802aa69Smillert if (s == 0)
254e802aa69Smillert unlink(rm->file);
255e802aa69Smillert free(rm);
256e802aa69Smillert }
257e802aa69Smillert
258e802aa69Smillert /*
259e802aa69Smillert * Clean out the opt list
260e802aa69Smillert */
261e802aa69Smillert while ((opt = as->optlist) != NULL) {
262e802aa69Smillert as->optlist = opt->next;
263e802aa69Smillert free(opt);
264e802aa69Smillert }
265e802aa69Smillert
266e802aa69Smillert /*
267e802aa69Smillert * Clean out data
268e802aa69Smillert */
269e802aa69Smillert while ((data = as->data) != NULL) {
270e802aa69Smillert if (as->data->len)
2718fbd7fcbSdoug explicit_bzero(as->data->ptr, as->data->len);
272e802aa69Smillert as->data = data->next;
273e802aa69Smillert free(data);
274e802aa69Smillert }
275e802aa69Smillert
2762877ca5fSmpech if (as->pwd != NULL) {
2778fbd7fcbSdoug explicit_bzero(as->pwd->pw_passwd, strlen(as->pwd->pw_passwd));
2782877ca5fSmpech free(as->pwd);
2792877ca5fSmpech as->pwd = NULL;
2802877ca5fSmpech }
2812877ca5fSmpech
282e802aa69Smillert /*
283e802aa69Smillert * Clean up random variables
284e802aa69Smillert */
285e802aa69Smillert if (as->service && as->service != defservice)
286e802aa69Smillert free(as->service);
287e802aa69Smillert free(as->challenge);
288e802aa69Smillert free(as->class);
289e802aa69Smillert free(as->style);
290e802aa69Smillert free(as->name);
291e802aa69Smillert
292e802aa69Smillert free(as);
293e802aa69Smillert return (s);
294e802aa69Smillert }
295753e8795Sguenther DEF_WEAK(auth_close);
296e802aa69Smillert
297e802aa69Smillert /*
298c0141d96Sderaadt * Request a challenge for the session.
299e802aa69Smillert * The name and style must have already been specified
300e802aa69Smillert */
301e802aa69Smillert char *
auth_challenge(auth_session_t * as)302e802aa69Smillert auth_challenge(auth_session_t *as)
303e802aa69Smillert {
30469245ebdSmillert char path[PATH_MAX];
305bb14a393Smoritz int len;
306e802aa69Smillert
307a314d10bSderaadt if (as == NULL || as->style == NULL || as->name == NULL ||
308a314d10bSderaadt !_auth_validuser(as->name))
309e802aa69Smillert return (NULL);
310e802aa69Smillert
311bb14a393Smoritz len = snprintf(path, sizeof(path), _PATH_AUTHPROG "%s", as->style);
312bb14a393Smoritz if (len < 0 || len >= sizeof(path))
313bb14a393Smoritz return (NULL);
314bb14a393Smoritz
3157ed757dfSmillert as->state = 0;
3167ed757dfSmillert
317e802aa69Smillert free(as->challenge);
318e802aa69Smillert as->challenge = NULL;
319e802aa69Smillert
320a314d10bSderaadt auth_call(as, path, as->style, "-s", "challenge", "--", as->name,
32102f55c3dSmillert as->class, (char *)NULL);
322e802aa69Smillert if (as->state & AUTH_CHALLENGE)
323e802aa69Smillert as->challenge = auth_getvalue(as, "challenge");
324e802aa69Smillert as->state = 0;
325e802aa69Smillert as->index = 0; /* toss our data */
326e802aa69Smillert return (as->challenge);
327e802aa69Smillert }
328753e8795Sguenther DEF_WEAK(auth_challenge);
329e802aa69Smillert
330e802aa69Smillert /*
331e802aa69Smillert * Set/unset the requested environment variables.
332e802aa69Smillert * Mark the variables as set so they will not be set a second time.
333e802aa69Smillert * XXX - should provide a way to detect setenv() failure.
334e802aa69Smillert */
335e802aa69Smillert void
auth_setenv(auth_session_t * as)336e802aa69Smillert auth_setenv(auth_session_t *as)
337e802aa69Smillert {
338e802aa69Smillert char *line, *name;
339e802aa69Smillert
340e802aa69Smillert /*
341e802aa69Smillert * Set any environment variables we were asked for
342e802aa69Smillert */
343e802aa69Smillert for (line = as->spool; line < as->spool + as->index;) {
344e802aa69Smillert if (!strncasecmp(line, BI_SETENV, sizeof(BI_SETENV)-1)) {
345dfe5467eSderaadt if (isblank((unsigned char)line[sizeof(BI_SETENV) - 1])) {
346e802aa69Smillert /* only do it once! */
347e802aa69Smillert line[0] = 'd'; line[1] = 'i'; line[2] = 'd';
348e802aa69Smillert line += sizeof(BI_SETENV) - 1;
349dfe5467eSderaadt for (name = line;
350dfe5467eSderaadt isblank((unsigned char)*name); ++name)
351e802aa69Smillert ;
352dfe5467eSderaadt for (line = name;
353dfe5467eSderaadt *line && !isblank((unsigned char)*line);
354e802aa69Smillert ++line)
355e802aa69Smillert ;
356e802aa69Smillert if (*line)
357e802aa69Smillert *line++ = '\0';
358dfe5467eSderaadt for (; isblank((unsigned char)*line); ++line)
359e802aa69Smillert ;
360e802aa69Smillert if (*line != '\0' && setenv(name, line, 1))
3619b9d2a55Sguenther warn("setenv(%s, %s)", name, line);
362e802aa69Smillert }
363e802aa69Smillert } else
364e802aa69Smillert if (!strncasecmp(line, BI_UNSETENV, sizeof(BI_UNSETENV)-1)) {
365fb6201afSmmcc if (isblank((unsigned char)line[sizeof(BI_UNSETENV) - 1])) {
366e802aa69Smillert /* only do it once! */
367e802aa69Smillert line[2] = 'd'; line[3] = 'i'; line[4] = 'd';
368e802aa69Smillert line += sizeof(BI_UNSETENV) - 1;
369dfe5467eSderaadt for (name = line;
370dfe5467eSderaadt isblank((unsigned char)*name); ++name)
371e802aa69Smillert ;
372dfe5467eSderaadt for (line = name;
373dfe5467eSderaadt *line && !isblank((unsigned char)*line);
374e802aa69Smillert ++line)
375e802aa69Smillert ;
376e802aa69Smillert if (*line)
377e802aa69Smillert *line++ = '\0';
378e802aa69Smillert unsetenv(name);
379e802aa69Smillert }
380e802aa69Smillert }
381e802aa69Smillert while (*line++)
382e802aa69Smillert ;
383e802aa69Smillert }
384e802aa69Smillert }
385753e8795Sguenther DEF_WEAK(auth_setenv);
386e802aa69Smillert
387e802aa69Smillert /*
388e802aa69Smillert * Clear out any requested environment variables.
389e802aa69Smillert */
390e802aa69Smillert void
auth_clrenv(auth_session_t * as)391e802aa69Smillert auth_clrenv(auth_session_t *as)
392e802aa69Smillert {
393e802aa69Smillert char *line;
394e802aa69Smillert
395e802aa69Smillert for (line = as->spool; line < as->spool + as->index;) {
396e802aa69Smillert if (!strncasecmp(line, BI_SETENV, sizeof(BI_SETENV)-1)) {
397dfe5467eSderaadt if (isblank((unsigned char)line[sizeof(BI_SETENV) - 1])) {
398e802aa69Smillert line[0] = 'i'; line[1] = 'g'; line[2] = 'n';
399e802aa69Smillert }
400e802aa69Smillert } else
401e802aa69Smillert if (!strncasecmp(line, BI_UNSETENV, sizeof(BI_UNSETENV)-1)) {
402dfe5467eSderaadt if (isblank((unsigned char)line[sizeof(BI_UNSETENV) - 1])) {
403e802aa69Smillert line[2] = 'i'; line[3] = 'g'; line[4] = 'n';
404e802aa69Smillert }
405e802aa69Smillert }
406e802aa69Smillert while (*line++)
407e802aa69Smillert ;
408e802aa69Smillert }
409e802aa69Smillert }
410753e8795Sguenther DEF_WEAK(auth_clrenv);
411e802aa69Smillert
412e802aa69Smillert char *
auth_getitem(auth_session_t * as,auth_item_t item)413e802aa69Smillert auth_getitem(auth_session_t *as, auth_item_t item)
414e802aa69Smillert {
415e802aa69Smillert if (as != NULL) {
416e802aa69Smillert switch (item) {
417e802aa69Smillert case AUTHV_CHALLENGE:
418e802aa69Smillert return (as->challenge);
419e802aa69Smillert case AUTHV_CLASS:
420e802aa69Smillert return (as->class);
421e802aa69Smillert case AUTHV_NAME:
422e802aa69Smillert return (as->name);
423e802aa69Smillert case AUTHV_SERVICE:
424e802aa69Smillert return (as->service ? as->service : defservice);
425e802aa69Smillert case AUTHV_STYLE:
426e802aa69Smillert return (as->style);
427e802aa69Smillert case AUTHV_INTERACTIVE:
428e802aa69Smillert return ((as->flags & AF_INTERACTIVE) ? "True" : NULL);
429e802aa69Smillert default:
430e802aa69Smillert break;
431e802aa69Smillert }
432e802aa69Smillert }
433e802aa69Smillert return (NULL);
434e802aa69Smillert }
435753e8795Sguenther DEF_WEAK(auth_getitem);
436e802aa69Smillert
437e802aa69Smillert int
auth_setitem(auth_session_t * as,auth_item_t item,char * value)438e802aa69Smillert auth_setitem(auth_session_t *as, auth_item_t item, char *value)
439e802aa69Smillert {
440e802aa69Smillert if (as == NULL) {
441e802aa69Smillert errno = EINVAL;
442e802aa69Smillert return (-1);
443e802aa69Smillert }
444e802aa69Smillert
445e802aa69Smillert switch (item) {
446e802aa69Smillert case AUTHV_ALL:
447e802aa69Smillert if (value != NULL) {
448e802aa69Smillert errno = EINVAL;
449e802aa69Smillert return (-1);
450e802aa69Smillert }
451e802aa69Smillert auth_setitem(as, AUTHV_CHALLENGE, NULL);
452e802aa69Smillert auth_setitem(as, AUTHV_CLASS, NULL);
453e802aa69Smillert auth_setitem(as, AUTHV_NAME, NULL);
454e802aa69Smillert auth_setitem(as, AUTHV_SERVICE, NULL);
455e802aa69Smillert auth_setitem(as, AUTHV_STYLE, NULL);
456e802aa69Smillert auth_setitem(as, AUTHV_INTERACTIVE, NULL);
457e802aa69Smillert return (0);
458e802aa69Smillert
459e802aa69Smillert case AUTHV_CHALLENGE:
46008d1e6e6Smillert if (value == as->challenge)
461f4f98523Smillert return (0);
462e802aa69Smillert if (value != NULL && (value = strdup(value)) == NULL)
463e802aa69Smillert return (-1);
464e802aa69Smillert free(as->challenge);
465e802aa69Smillert as->challenge = value;
466e802aa69Smillert return (0);
467e802aa69Smillert
468e802aa69Smillert case AUTHV_CLASS:
46908d1e6e6Smillert if (value == as->class)
470f4f98523Smillert return (0);
471e802aa69Smillert if (value != NULL && (value = strdup(value)) == NULL)
472e802aa69Smillert return (-1);
473e802aa69Smillert free(as->class);
474e802aa69Smillert as->class = value;
475e802aa69Smillert return (0);
476e802aa69Smillert
477e802aa69Smillert case AUTHV_NAME:
47808d1e6e6Smillert if (value == as->name)
479f4f98523Smillert return (0);
480a314d10bSderaadt if (value != NULL && !_auth_validuser(value)) {
481a314d10bSderaadt errno = EINVAL;
482a314d10bSderaadt return (-1);
483a314d10bSderaadt }
484e802aa69Smillert if (value != NULL && (value = strdup(value)) == NULL)
485e802aa69Smillert return (-1);
486e802aa69Smillert free(as->name);
487e802aa69Smillert as->name = value;
488e802aa69Smillert return (0);
489e802aa69Smillert
490e802aa69Smillert case AUTHV_SERVICE:
49108d1e6e6Smillert if (value == as->service)
492f4f98523Smillert return (0);
493e802aa69Smillert if (value == NULL || strcmp(value, defservice) == 0)
494e802aa69Smillert value = defservice;
495e802aa69Smillert else if ((value = strdup(value)) == NULL)
496e802aa69Smillert return (-1);
497e802aa69Smillert if (as->service && as->service != defservice)
498e802aa69Smillert free(as->service);
499e802aa69Smillert as->service = value;
500e802aa69Smillert return (0);
501e802aa69Smillert
502e802aa69Smillert case AUTHV_STYLE:
50308d1e6e6Smillert if (value == as->style)
504f4f98523Smillert return (0);
505e802aa69Smillert if (value == NULL || strchr(value, '/') != NULL ||
506e802aa69Smillert (value = strdup(value)) == NULL)
507e802aa69Smillert return (-1);
508e802aa69Smillert free(as->style);
509e802aa69Smillert as->style = value;
510e802aa69Smillert return (0);
511e802aa69Smillert
512e802aa69Smillert case AUTHV_INTERACTIVE:
513e802aa69Smillert if (value == NULL)
514e802aa69Smillert as->flags &= ~AF_INTERACTIVE;
515e802aa69Smillert else
516e802aa69Smillert as->flags |= ~AF_INTERACTIVE;
517e802aa69Smillert return (0);
518e802aa69Smillert
519e802aa69Smillert default:
520e802aa69Smillert errno = EINVAL;
521e802aa69Smillert return (-1);
522e802aa69Smillert }
523e802aa69Smillert }
524753e8795Sguenther DEF_WEAK(auth_setitem);
525e802aa69Smillert
526e802aa69Smillert int
auth_setoption(auth_session_t * as,char * n,char * v)527e802aa69Smillert auth_setoption(auth_session_t *as, char *n, char *v)
528e802aa69Smillert {
529e802aa69Smillert struct authopts *opt;
530bb14a393Smoritz size_t len = strlen(n) + strlen(v) + 2;
531bb14a393Smoritz int ret;
532e802aa69Smillert
533bb14a393Smoritz if ((opt = malloc(sizeof(*opt) + len)) == NULL)
534e802aa69Smillert return (-1);
535e802aa69Smillert
536e802aa69Smillert opt->opt = (char *)(opt + 1);
537e802aa69Smillert
538bb14a393Smoritz ret = snprintf(opt->opt, len, "%s=%s", n, v);
539bb14a393Smoritz if (ret < 0 || ret >= len) {
540bb14a393Smoritz free(opt);
541bb14a393Smoritz errno = ENAMETOOLONG;
542bb14a393Smoritz return (-1);
543bb14a393Smoritz }
544e802aa69Smillert opt->next = as->optlist;
545e802aa69Smillert as->optlist = opt;
546e802aa69Smillert return(0);
547e802aa69Smillert }
548753e8795Sguenther DEF_WEAK(auth_setoption);
549e802aa69Smillert
550e802aa69Smillert void
auth_clroptions(auth_session_t * as)551e802aa69Smillert auth_clroptions(auth_session_t *as)
552e802aa69Smillert {
553e802aa69Smillert struct authopts *opt;
554e802aa69Smillert
555e802aa69Smillert while ((opt = as->optlist) != NULL) {
556e802aa69Smillert as->optlist = opt->next;
557e802aa69Smillert free(opt);
558e802aa69Smillert }
559e802aa69Smillert }
560753e8795Sguenther DEF_WEAK(auth_clroptions);
561e802aa69Smillert
562e802aa69Smillert void
auth_clroption(auth_session_t * as,char * option)563e802aa69Smillert auth_clroption(auth_session_t *as, char *option)
564e802aa69Smillert {
565e802aa69Smillert struct authopts *opt, *oopt;
566e17b29d3Sderaadt size_t len;
567e802aa69Smillert
568e802aa69Smillert len = strlen(option);
569e802aa69Smillert
570e802aa69Smillert if ((opt = as->optlist) == NULL)
571e802aa69Smillert return;
572e802aa69Smillert
573e802aa69Smillert if (strncmp(opt->opt, option, len) == 0 &&
574e802aa69Smillert (opt->opt[len] == '=' || opt->opt[len] == '\0')) {
575e802aa69Smillert as->optlist = opt->next;
576e802aa69Smillert free(opt);
577e802aa69Smillert return;
578e802aa69Smillert }
579e802aa69Smillert
580e802aa69Smillert while ((oopt = opt->next) != NULL) {
581e802aa69Smillert if (strncmp(oopt->opt, option, len) == 0 &&
582e802aa69Smillert (oopt->opt[len] == '=' || oopt->opt[len] == '\0')) {
583e802aa69Smillert opt->next = oopt->next;
584e802aa69Smillert free(oopt);
585e802aa69Smillert return;
586e802aa69Smillert }
587e802aa69Smillert opt = oopt;
588e802aa69Smillert }
589e802aa69Smillert }
590753e8795Sguenther DEF_WEAK(auth_clroption);
591e802aa69Smillert
592e802aa69Smillert int
auth_setdata(auth_session_t * as,void * ptr,size_t len)593e802aa69Smillert auth_setdata(auth_session_t *as, void *ptr, size_t len)
594e802aa69Smillert {
595e802aa69Smillert struct authdata *data, *dp;
596e802aa69Smillert
597e802aa69Smillert if (len <= 0)
598e802aa69Smillert return (0);
599e802aa69Smillert
600e802aa69Smillert if ((data = malloc(sizeof(*data) + len)) == NULL)
601e802aa69Smillert return (-1);
602e802aa69Smillert
603e802aa69Smillert data->next = NULL;
604e802aa69Smillert data->len = len;
605e802aa69Smillert data->ptr = data + 1;
606e802aa69Smillert memcpy(data->ptr, ptr, len);
607e802aa69Smillert
608e802aa69Smillert if (as->data == NULL)
609e802aa69Smillert as->data = data;
610e802aa69Smillert else {
611e802aa69Smillert for (dp = as->data; dp->next != NULL; dp = dp->next)
612e802aa69Smillert ;
613e802aa69Smillert dp->next = data;
614e802aa69Smillert }
615e802aa69Smillert return (0);
616e802aa69Smillert }
617753e8795Sguenther DEF_WEAK(auth_setdata);
618e802aa69Smillert
619e802aa69Smillert int
auth_setpwd(auth_session_t * as,struct passwd * pwd)620e802aa69Smillert auth_setpwd(auth_session_t *as, struct passwd *pwd)
621e802aa69Smillert {
622cd245bcaSmillert struct passwd pwstore;
623cd245bcaSmillert char *instance, pwbuf[_PW_BUF_LEN];
624e802aa69Smillert
625e802aa69Smillert if (pwd == NULL && as->pwd == NULL && as->name == NULL)
626e802aa69Smillert return (-1); /* true failure */
627e802aa69Smillert
628e802aa69Smillert if (pwd == NULL) {
629e802aa69Smillert /*
630e802aa69Smillert * If we were not passed in a pwd structure we need to
631e802aa69Smillert * go find one for ourself. Always look up the username
632e802aa69Smillert * (if it is defined) in the passwd database to see if there
633e802aa69Smillert * is an entry for the user. If not, either use the current
634e802aa69Smillert * entry or simply return a 1 which implies there is
635e802aa69Smillert * no user by that name here. This is not a failure, just
636e802aa69Smillert * a point of information.
637e802aa69Smillert */
638e802aa69Smillert if (as->name == NULL)
639e802aa69Smillert return (0);
640cd245bcaSmillert getpwnam_r(as->name, &pwstore, pwbuf, sizeof(pwbuf), &pwd);
641cd245bcaSmillert if (pwd == NULL) {
642fa843023Smillert instance = strchr(as->name, '/');
643fa843023Smillert if (instance == NULL)
644e802aa69Smillert return (as->pwd ? 0 : 1);
645cd245bcaSmillert if (strcmp(instance, "/root") == 0) {
646cd245bcaSmillert getpwnam_r(instance + 1, &pwstore, pwbuf,
647cd245bcaSmillert sizeof(pwbuf), &pwd);
648cd245bcaSmillert }
649e802aa69Smillert if (pwd == NULL)
650e802aa69Smillert return (as->pwd ? 0 : 1);
651e802aa69Smillert }
652e802aa69Smillert }
653e802aa69Smillert if ((pwd = pw_dup(pwd)) == NULL)
654e802aa69Smillert return (-1); /* true failure */
655efca3e07Smillert if (as->pwd) {
6568fbd7fcbSdoug explicit_bzero(as->pwd->pw_passwd, strlen(as->pwd->pw_passwd));
657e802aa69Smillert free(as->pwd);
658efca3e07Smillert }
659e802aa69Smillert as->pwd = pwd;
660e802aa69Smillert return (0);
661e802aa69Smillert }
662753e8795Sguenther DEF_WEAK(auth_setpwd);
663e802aa69Smillert
664e802aa69Smillert char *
auth_getvalue(auth_session_t * as,char * what)665e802aa69Smillert auth_getvalue(auth_session_t *as, char *what)
666e802aa69Smillert {
667e802aa69Smillert char *line, *v, *value;
668e802aa69Smillert int n, len;
669e802aa69Smillert
670e802aa69Smillert len = strlen(what);
671e802aa69Smillert
672e802aa69Smillert for (line = as->spool; line < as->spool + as->index;) {
673e802aa69Smillert if (strncasecmp(line, BI_VALUE, sizeof(BI_VALUE)-1) != 0)
674e802aa69Smillert goto next;
675e802aa69Smillert line += sizeof(BI_VALUE) - 1;
676e802aa69Smillert
677dfe5467eSderaadt if (!isblank((unsigned char)*line))
678e802aa69Smillert goto next;
679e802aa69Smillert
680dfe5467eSderaadt while (isblank((unsigned char)*++line))
681e802aa69Smillert ;
682e802aa69Smillert
683e802aa69Smillert if (strncmp(line, what, len) != 0 ||
684dfe5467eSderaadt !isblank((unsigned char)line[len]))
685e802aa69Smillert goto next;
686e802aa69Smillert line += len;
687dfe5467eSderaadt while (isblank((unsigned char)*++line))
688e802aa69Smillert ;
689e802aa69Smillert value = strdup(line);
690e802aa69Smillert if (value == NULL)
691e802aa69Smillert return (NULL);
692e802aa69Smillert
693e802aa69Smillert /*
694e802aa69Smillert * XXX - There should be a more standardized
695e802aa69Smillert * routine for doing this sort of thing.
696e802aa69Smillert */
697e802aa69Smillert for (line = v = value; *line; ++line) {
698e802aa69Smillert if (*line == '\\') {
699e802aa69Smillert switch (*++line) {
700e802aa69Smillert case 'r':
701e802aa69Smillert *v++ = '\r';
702e802aa69Smillert break;
703e802aa69Smillert case 'n':
704e802aa69Smillert *v++ = '\n';
705e802aa69Smillert break;
706e802aa69Smillert case 't':
707e802aa69Smillert *v++ = '\t';
708e802aa69Smillert break;
709e802aa69Smillert case '0': case '1': case '2':
710e802aa69Smillert case '3': case '4': case '5':
711e802aa69Smillert case '6': case '7':
712e802aa69Smillert n = *line - '0';
713dfe5467eSderaadt if (isdigit((unsigned char)line[1])) {
714e802aa69Smillert ++line;
715e802aa69Smillert n <<= 3;
716e802aa69Smillert n |= *line-'0';
717e802aa69Smillert }
718dfe5467eSderaadt if (isdigit((unsigned char)line[1])) {
719e802aa69Smillert ++line;
720e802aa69Smillert n <<= 3;
721e802aa69Smillert n |= *line-'0';
722e802aa69Smillert }
723e802aa69Smillert break;
724e802aa69Smillert default:
725e802aa69Smillert *v++ = *line;
726e802aa69Smillert break;
727e802aa69Smillert }
728e802aa69Smillert } else
729e802aa69Smillert *v++ = *line;
730e802aa69Smillert }
731e802aa69Smillert *v = '\0';
732e802aa69Smillert return (value);
733e802aa69Smillert next:
734e802aa69Smillert while (*line++)
735e802aa69Smillert ;
736e802aa69Smillert }
737e802aa69Smillert return (NULL);
738e802aa69Smillert }
739753e8795Sguenther DEF_WEAK(auth_getvalue);
740e802aa69Smillert
741e802aa69Smillert quad_t
auth_check_expire(auth_session_t * as)742e802aa69Smillert auth_check_expire(auth_session_t *as)
743e802aa69Smillert {
744e802aa69Smillert if (as->pwd == NULL && auth_setpwd(as, NULL) < 0) {
745e802aa69Smillert as->state &= ~AUTH_ALLOW;
746e802aa69Smillert as->state |= AUTH_EXPIRED; /* XXX */
747e802aa69Smillert return (-1);
748e802aa69Smillert }
749e802aa69Smillert
750e802aa69Smillert if (as->pwd == NULL)
751e802aa69Smillert return (0);
752e802aa69Smillert
753e802aa69Smillert if (as->pwd && (quad_t)as->pwd->pw_expire != 0) {
754e802aa69Smillert if (as->now.tv_sec == 0)
755d82e6535Spirofti WRAP(gettimeofday)(&as->now, NULL);
756e802aa69Smillert if ((quad_t)as->now.tv_sec >= (quad_t)as->pwd->pw_expire) {
757e802aa69Smillert as->state &= ~AUTH_ALLOW;
758e802aa69Smillert as->state |= AUTH_EXPIRED;
759e802aa69Smillert }
760e802aa69Smillert if ((quad_t)as->now.tv_sec == (quad_t)as->pwd->pw_expire)
761e802aa69Smillert return (-1);
762e802aa69Smillert return ((quad_t)as->pwd->pw_expire - (quad_t)as->now.tv_sec);
763e802aa69Smillert }
764e802aa69Smillert return (0);
765e802aa69Smillert }
766753e8795Sguenther DEF_WEAK(auth_check_expire);
767e802aa69Smillert
768e802aa69Smillert quad_t
auth_check_change(auth_session_t * as)769e802aa69Smillert auth_check_change(auth_session_t *as)
770e802aa69Smillert {
771e802aa69Smillert if (as->pwd == NULL && auth_setpwd(as, NULL) < 0) {
772e802aa69Smillert as->state &= ~AUTH_ALLOW;
773e802aa69Smillert as->state |= AUTH_PWEXPIRED; /* XXX */
774e802aa69Smillert return (-1);
775e802aa69Smillert }
776e802aa69Smillert
777e802aa69Smillert if (as->pwd == NULL)
778e802aa69Smillert return (0);
779e802aa69Smillert
780e802aa69Smillert if (as->pwd && (quad_t)as->pwd->pw_change) {
781e802aa69Smillert if (as->now.tv_sec == 0)
782d82e6535Spirofti WRAP(gettimeofday)(&as->now, NULL);
783e802aa69Smillert if (as->now.tv_sec >= (quad_t)as->pwd->pw_change) {
784e802aa69Smillert as->state &= ~AUTH_ALLOW;
785e802aa69Smillert as->state |= AUTH_PWEXPIRED;
786e802aa69Smillert }
787e802aa69Smillert if ((quad_t)as->now.tv_sec == (quad_t)as->pwd->pw_change)
788e802aa69Smillert return (-1);
789e802aa69Smillert return ((quad_t)as->pwd->pw_change - (quad_t)as->now.tv_sec);
790e802aa69Smillert }
791e802aa69Smillert return (0);
792e802aa69Smillert }
793753e8795Sguenther DEF_WEAK(auth_check_change);
794e802aa69Smillert
795e802aa69Smillert /*
796e802aa69Smillert * The down and dirty call to the login script
797e802aa69Smillert * okay contains the default return value, typically 0 but
798e802aa69Smillert * is AUTH_OKAY for approval like scripts.
799e802aa69Smillert *
800e802aa69Smillert * Internally additional trailing arguments can be read from as->ap
8017ed757dfSmillert * Options will be placed just after the first argument (not including path).
802e802aa69Smillert *
8037ed757dfSmillert * Any data will be sent to (and freed by) the script
804e802aa69Smillert */
805e802aa69Smillert int
auth_call(auth_session_t * as,char * path,...)806e802aa69Smillert auth_call(auth_session_t *as, char *path, ...)
807e802aa69Smillert {
808e802aa69Smillert char *line;
809e802aa69Smillert struct authdata *data;
810e802aa69Smillert struct authopts *opt;
811e802aa69Smillert pid_t pid;
812e802aa69Smillert int status;
813e802aa69Smillert int okay;
814e802aa69Smillert int pfd[2];
815e802aa69Smillert int argc;
8167ed757dfSmillert char *argv[64]; /* 64 args should be more than enough */
817e802aa69Smillert #define Nargc (sizeof(argv)/sizeof(argv[0]))
818e802aa69Smillert
819e802aa69Smillert va_start(as->ap0, path);
820e802aa69Smillert
821e802aa69Smillert argc = 0;
822e802aa69Smillert if ((argv[argc] = _auth_next_arg(as)) != NULL)
823e802aa69Smillert ++argc;
824e802aa69Smillert
8256e2de6bbSmillert if (as->fd != -1) {
8266e2de6bbSmillert argv[argc++] = "-v";
8276e2de6bbSmillert argv[argc++] = "fd=4"; /* AUTH_FD, see below */
8286e2de6bbSmillert }
829a314d10bSderaadt /* XXX - fail if out of space in argv */
830e802aa69Smillert for (opt = as->optlist; opt != NULL; opt = opt->next) {
831e802aa69Smillert if (argc < Nargc - 2) {
832e802aa69Smillert argv[argc++] = "-v";
833e802aa69Smillert argv[argc++] = opt->opt;
834e802aa69Smillert } else {
835e802aa69Smillert syslog(LOG_ERR, "too many authentication options");
836e802aa69Smillert goto fail;
837e802aa69Smillert }
838e802aa69Smillert }
839e802aa69Smillert while (argc < Nargc - 1 && (argv[argc] = _auth_next_arg(as)))
840e802aa69Smillert ++argc;
841e802aa69Smillert
842e802aa69Smillert if (argc >= Nargc - 1 && _auth_next_arg(as)) {
8434808f726Smillert if (memcmp(&nilap, &(as->ap0), sizeof(nilap)) != 0) {
844e802aa69Smillert va_end(as->ap0);
8458fbd7fcbSdoug explicit_bzero(&(as->ap0), sizeof(as->ap0));
846e802aa69Smillert }
8474808f726Smillert if (memcmp(&nilap, &(as->ap), sizeof(nilap)) != 0) {
848e802aa69Smillert va_end(as->ap);
8498fbd7fcbSdoug explicit_bzero(&(as->ap), sizeof(as->ap));
850e802aa69Smillert }
851e802aa69Smillert syslog(LOG_ERR, "too many arguments");
852e802aa69Smillert goto fail;
853e802aa69Smillert }
854e802aa69Smillert
855e802aa69Smillert argv[argc] = NULL;
856e802aa69Smillert
857df69c215Sderaadt if (socketpair(PF_LOCAL, SOCK_STREAM, 0, pfd) == -1) {
858e802aa69Smillert syslog(LOG_ERR, "unable to create backchannel %m");
8599b9d2a55Sguenther warnx("internal resource failure");
860e802aa69Smillert goto fail;
861e802aa69Smillert }
862e802aa69Smillert
863e802aa69Smillert switch (pid = fork()) {
864e802aa69Smillert case -1:
865e802aa69Smillert syslog(LOG_ERR, "%s: %m", path);
8669b9d2a55Sguenther warnx("internal resource failure");
867fb18cfd4Smillert close(pfd[0]);
868fb18cfd4Smillert close(pfd[1]);
869e802aa69Smillert goto fail;
870e802aa69Smillert case 0:
871e802aa69Smillert #define COMM_FD 3
8726e2de6bbSmillert #define AUTH_FD 4
873df69c215Sderaadt if (dup2(pfd[1], COMM_FD) == -1)
874e802aa69Smillert err(1, "dup of backchannel");
8756e2de6bbSmillert if (as->fd != -1) {
876df69c215Sderaadt if (dup2(as->fd, AUTH_FD) == -1)
8776e2de6bbSmillert err(1, "dup of auth fd");
8786e2de6bbSmillert closefrom(AUTH_FD + 1);
8796e2de6bbSmillert } else
880188b81b3Sderaadt closefrom(COMM_FD + 1);
881e802aa69Smillert execve(path, argv, auth_environ);
882e802aa69Smillert syslog(LOG_ERR, "%s: %m", path);
883e802aa69Smillert err(1, "%s", path);
884e802aa69Smillert default:
885e802aa69Smillert close(pfd[1]);
8866e2de6bbSmillert if (as->fd != -1) {
8876e2de6bbSmillert close(as->fd); /* so child has only ref */
8886e2de6bbSmillert as->fd = -1;
8896e2de6bbSmillert }
890e802aa69Smillert while ((data = as->data) != NULL) {
891e802aa69Smillert as->data = data->next;
892e802aa69Smillert if (data->len > 0) {
893e802aa69Smillert write(pfd[0], data->ptr, data->len);
8948fbd7fcbSdoug explicit_bzero(data->ptr, data->len);
895e802aa69Smillert }
896e802aa69Smillert free(data);
897e802aa69Smillert }
898e802aa69Smillert as->index = 0;
899e802aa69Smillert _auth_spool(as, pfd[0]);
900e802aa69Smillert close(pfd[0]);
901b2251c56Sguenther do {
902b2251c56Sguenther if (waitpid(pid, &status, 0) != -1) {
903b2251c56Sguenther if (!WIFEXITED(status))
904e802aa69Smillert goto fail;
905b2251c56Sguenther break;
906e802aa69Smillert }
907b2251c56Sguenther /*
908b2251c56Sguenther * could get ECHILD if it was waited for by
909b2251c56Sguenther * another thread or from a signal handler
910b2251c56Sguenther */
911b2251c56Sguenther } while (errno == EINTR);
912e802aa69Smillert }
913e802aa69Smillert
914e802aa69Smillert /*
915e802aa69Smillert * Now scan the spooled data
916e802aa69Smillert * It is easier to wait for all the data before starting
917e802aa69Smillert * to scan it.
918e802aa69Smillert */
919e802aa69Smillert for (line = as->spool; line < as->spool + as->index;) {
920e802aa69Smillert if (!strncasecmp(line, BI_REJECT, sizeof(BI_REJECT)-1)) {
921e802aa69Smillert line += sizeof(BI_REJECT) - 1;
922e802aa69Smillert if (!*line || *line == ' ' || *line == '\t') {
923e802aa69Smillert while (*line == ' ' || *line == '\t')
924e802aa69Smillert ++line;
925e802aa69Smillert if (!strcasecmp(line, "silent")) {
926e802aa69Smillert as->state = AUTH_SILENT;
927e802aa69Smillert break;
928e802aa69Smillert }
929e802aa69Smillert if (!strcasecmp(line, "challenge")) {
930e802aa69Smillert as->state = AUTH_CHALLENGE;
931e802aa69Smillert break;
932e802aa69Smillert }
933e802aa69Smillert if (!strcasecmp(line, "expired")) {
934e802aa69Smillert as->state = AUTH_EXPIRED;
935e802aa69Smillert break;
936e802aa69Smillert }
937e802aa69Smillert if (!strcasecmp(line, "pwexpired")) {
938e802aa69Smillert as->state = AUTH_PWEXPIRED;
939e802aa69Smillert break;
940e802aa69Smillert }
941e802aa69Smillert }
942e802aa69Smillert break;
943e802aa69Smillert } else if (!strncasecmp(line, BI_AUTH, sizeof(BI_AUTH)-1)) {
944e802aa69Smillert line += sizeof(BI_AUTH) - 1;
945e802aa69Smillert if (!*line || *line == ' ' || *line == '\t') {
946e802aa69Smillert while (*line == ' ' || *line == '\t')
947e802aa69Smillert ++line;
948e802aa69Smillert if (*line == '\0')
949e802aa69Smillert as->state |= AUTH_OKAY;
950e802aa69Smillert else if (!strcasecmp(line, "root"))
951e802aa69Smillert as->state |= AUTH_ROOTOKAY;
952e802aa69Smillert else if (!strcasecmp(line, "secure"))
953e802aa69Smillert as->state |= AUTH_SECURE;
954e802aa69Smillert }
955e802aa69Smillert } else if (!strncasecmp(line, BI_REMOVE, sizeof(BI_REMOVE)-1)) {
956e802aa69Smillert line += sizeof(BI_REMOVE) - 1;
957e802aa69Smillert while (*line == ' ' || *line == '\t')
958e802aa69Smillert ++line;
959e802aa69Smillert if (*line)
960e802aa69Smillert _add_rmlist(as, line);
961e802aa69Smillert }
962e802aa69Smillert while (*line++)
963e802aa69Smillert ;
964e802aa69Smillert }
965e802aa69Smillert
966e802aa69Smillert if (WEXITSTATUS(status))
967e802aa69Smillert as->state &= ~AUTH_ALLOW;
968e802aa69Smillert
969e802aa69Smillert okay = as->state & AUTH_ALLOW;
970e802aa69Smillert
971e802aa69Smillert if (!okay)
972e802aa69Smillert auth_clrenv(as);
973e802aa69Smillert
974e802aa69Smillert if (0) {
975e802aa69Smillert fail:
976e802aa69Smillert auth_clrenv(as);
977e802aa69Smillert as->state = 0;
978e802aa69Smillert okay = -1;
979e802aa69Smillert }
980e802aa69Smillert
981e802aa69Smillert while ((data = as->data) != NULL) {
982e802aa69Smillert as->data = data->next;
983e802aa69Smillert free(data);
984e802aa69Smillert }
985e802aa69Smillert
9864808f726Smillert if (memcmp(&nilap, &(as->ap0), sizeof(nilap)) != 0) {
987e802aa69Smillert va_end(as->ap0);
9888fbd7fcbSdoug explicit_bzero(&(as->ap0), sizeof(as->ap0));
989e802aa69Smillert }
990e802aa69Smillert
9914808f726Smillert if (memcmp(&nilap, &(as->ap), sizeof(nilap)) != 0) {
992e802aa69Smillert va_end(as->ap);
9938fbd7fcbSdoug explicit_bzero(&(as->ap), sizeof(as->ap));
994e802aa69Smillert }
995e802aa69Smillert return (okay);
996e802aa69Smillert }
997753e8795Sguenther DEF_WEAK(auth_call);
998e802aa69Smillert
999e802aa69Smillert static void
_recv_fd(auth_session_t * as,int fd)10006e2de6bbSmillert _recv_fd(auth_session_t *as, int fd)
10016e2de6bbSmillert {
10026e2de6bbSmillert struct msghdr msg;
10036e2de6bbSmillert struct cmsghdr *cmp;
10040827ab61Sderaadt union {
10050827ab61Sderaadt struct cmsghdr hdr;
10060827ab61Sderaadt char buf[CMSG_SPACE(sizeof(int))];
10070827ab61Sderaadt } cmsgbuf;
10086e2de6bbSmillert
10096e2de6bbSmillert memset(&msg, 0, sizeof(msg));
10100827ab61Sderaadt msg.msg_control = &cmsgbuf.buf;
1011da15c7b9Sderaadt msg.msg_controllen = sizeof(cmsgbuf.buf);
1012df69c215Sderaadt if (recvmsg(fd, &msg, 0) == -1)
10136e2de6bbSmillert syslog(LOG_ERR, "recvmsg: %m");
10146e2de6bbSmillert else if (msg.msg_flags & MSG_TRUNC)
10156e2de6bbSmillert syslog(LOG_ERR, "message truncated");
10166e2de6bbSmillert else if (msg.msg_flags & MSG_CTRUNC)
10176e2de6bbSmillert syslog(LOG_ERR, "control message truncated");
10186e2de6bbSmillert else if ((cmp = CMSG_FIRSTHDR(&msg)) == NULL)
10196e2de6bbSmillert syslog(LOG_ERR, "missing control message");
10206e2de6bbSmillert else {
10216e2de6bbSmillert if (cmp->cmsg_level != SOL_SOCKET)
10226e2de6bbSmillert syslog(LOG_ERR, "unexpected cmsg_level %d",
10236e2de6bbSmillert cmp->cmsg_level);
10246e2de6bbSmillert else if (cmp->cmsg_type != SCM_RIGHTS)
10256e2de6bbSmillert syslog(LOG_ERR, "unexpected cmsg_type %d",
10266e2de6bbSmillert cmp->cmsg_type);
10278a182787Smillert else if (cmp->cmsg_len != CMSG_LEN(sizeof(int)))
10286e2de6bbSmillert syslog(LOG_ERR, "bad cmsg_len %d",
10296e2de6bbSmillert cmp->cmsg_len);
10306e2de6bbSmillert else {
10316e2de6bbSmillert if (as->fd != -1)
10326e2de6bbSmillert close(as->fd);
10336e2de6bbSmillert as->fd = *(int *)CMSG_DATA(cmp);
10346e2de6bbSmillert }
10356e2de6bbSmillert }
10366e2de6bbSmillert }
10376e2de6bbSmillert
10386e2de6bbSmillert static void
_auth_spool(auth_session_t * as,int fd)1039e802aa69Smillert _auth_spool(auth_session_t *as, int fd)
1040e802aa69Smillert {
10416e2de6bbSmillert ssize_t r;
10426e2de6bbSmillert char *b, *s;
1043e802aa69Smillert
10446e2de6bbSmillert for (s = as->spool + as->index; as->index < sizeof(as->spool) - 1; ) {
1045e802aa69Smillert r = read(fd, as->spool + as->index,
1046e802aa69Smillert sizeof(as->spool) - as->index);
1047e802aa69Smillert if (r <= 0) {
1048e802aa69Smillert as->spool[as->index] = '\0';
1049e802aa69Smillert return;
1050e802aa69Smillert }
1051e802aa69Smillert b = as->spool + as->index;
1052e802aa69Smillert as->index += r;
1053e802aa69Smillert /*
10546e2de6bbSmillert * Convert newlines into NULs to allow easy scanning of the
10556e2de6bbSmillert * file and receive an fd if there is a BI_FDPASS message.
10566e2de6bbSmillert * XXX - checking for BI_FDPASS here is annoying but
10576e2de6bbSmillert * we need to avoid the read() slurping in control data.
1058e802aa69Smillert */
10596e2de6bbSmillert while (r-- > 0) {
10606e2de6bbSmillert if (*b++ == '\n') {
1061e802aa69Smillert b[-1] = '\0';
10626e2de6bbSmillert if (strcasecmp(s, BI_FDPASS) == 0)
10636e2de6bbSmillert _recv_fd(as, fd);
10646e2de6bbSmillert s = b;
10656e2de6bbSmillert }
10666e2de6bbSmillert }
1067e802aa69Smillert }
1068e802aa69Smillert
1069e802aa69Smillert syslog(LOG_ERR, "Overflowed backchannel spool buffer");
1070e802aa69Smillert errx(1, "System error in authentication program");
1071e802aa69Smillert }
1072e802aa69Smillert
1073e802aa69Smillert static void
_add_rmlist(auth_session_t * as,char * file)1074e802aa69Smillert _add_rmlist(auth_session_t *as, char *file)
1075e802aa69Smillert {
1076e802aa69Smillert struct rmfiles *rm;
1077e17b29d3Sderaadt size_t i = strlen(file) + 1;
1078e17b29d3Sderaadt
1079e17b29d3Sderaadt // XXX should rangecheck i since we are about to add?
1080e802aa69Smillert
1081e802aa69Smillert if ((rm = malloc(sizeof(struct rmfiles) + i)) == NULL) {
1082e802aa69Smillert syslog(LOG_ERR, "Failed to allocate rmfiles: %m");
1083e802aa69Smillert return;
1084e802aa69Smillert }
1085e802aa69Smillert rm->file = (char *)(rm + 1);
1086e802aa69Smillert rm->next = as->rmlist;
10875af14704Sderaadt strlcpy(rm->file, file, i);
1088e802aa69Smillert as->rmlist = rm;
1089e802aa69Smillert }
1090e802aa69Smillert
1091e802aa69Smillert static char *
_auth_next_arg(auth_session_t * as)1092e802aa69Smillert _auth_next_arg(auth_session_t *as)
1093e802aa69Smillert {
1094e802aa69Smillert char *arg;
1095e802aa69Smillert
10964808f726Smillert if (memcmp(&nilap, &(as->ap0), sizeof(nilap)) != 0) {
1097e802aa69Smillert if ((arg = va_arg(as->ap0, char *)) != NULL)
1098e802aa69Smillert return (arg);
1099e802aa69Smillert va_end(as->ap0);
11008fbd7fcbSdoug explicit_bzero(&(as->ap0), sizeof(as->ap0));
1101e802aa69Smillert }
11024808f726Smillert if (memcmp(&nilap, &(as->ap), sizeof(nilap)) != 0) {
1103e802aa69Smillert if ((arg = va_arg(as->ap, char *)) != NULL)
1104e802aa69Smillert return (arg);
1105e802aa69Smillert va_end(as->ap);
11068fbd7fcbSdoug explicit_bzero(&(as->ap), sizeof(as->ap));
1107e802aa69Smillert }
1108e802aa69Smillert return (NULL);
1109e802aa69Smillert }
1110