Bug Summary

File:src/lib/libc/gen/auth_subr.c
Warning:line 721, column 7
Value stored to 'n' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple amd64-unknown-openbsd7.0 -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name auth_subr.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 1 -fhalf-no-semantic-interposition -mframe-pointer=all -relaxed-aliasing -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -target-feature +retpoline-indirect-calls -target-feature +retpoline-indirect-branches -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/usr/src/lib/libc/obj -resource-dir /usr/local/lib/clang/13.0.0 -include namespace.h -I /usr/src/lib/libc/include -I /usr/src/lib/libc/hidden -D __LIBC__ -D APIWARN -D YP -I /usr/src/lib/libc/yp -I /usr/src/lib/libc -I /usr/src/lib/libc/gdtoa -I /usr/src/lib/libc/arch/amd64/gdtoa -D INFNAN_CHECK -D MULTIPLE_THREADS -D NO_FENV_H -D USE_LOCALE -I /usr/src/lib/libc -I /usr/src/lib/libc/citrus -D RESOLVSORT -D FLOATING_POINT -D PRINTF_WIDE_CHAR -D SCANF_WIDE_CHAR -D FUTEX -D PIC -internal-isystem /usr/local/lib/clang/13.0.0/include -internal-externc-isystem /usr/include -O2 -fdebug-compilation-dir=/usr/src/lib/libc/obj -ferror-limit 19 -fwrapv -D_RET_PROTECTOR -ret-protector -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-valloc -fno-builtin-free -fno-builtin-strdup -fno-builtin-strndup -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /home/ben/Projects/vmm/scan-build/2022-01-12-194120-40624-1 -x c /usr/src/lib/libc/gen/auth_subr.c
1/* $OpenBSD: auth_subr.c,v 1.56 2020/10/13 04:42:28 guenther Exp $ */
2
3/*
4 * Copyright (c) 2000-2002,2004 Todd C. Miller <millert@openbsd.org>
5 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18/*-
19 * Copyright (c) 1995,1996,1997 Berkeley Software Design, Inc.
20 * All rights reserved.
21 *
22 * Redistribution and use in source and binary forms, with or without
23 * modification, are permitted provided that the following conditions
24 * are met:
25 * 1. Redistributions of source code must retain the above copyright
26 * notice, this list of conditions and the following disclaimer.
27 * 2. Redistributions in binary form must reproduce the above copyright
28 * notice, this list of conditions and the following disclaimer in the
29 * documentation and/or other materials provided with the distribution.
30 * 3. All advertising materials mentioning features or use of this software
31 * must display the following acknowledgement:
32 * This product includes software developed by Berkeley Software Design,
33 * Inc.
34 * 4. The name of Berkeley Software Design, Inc. may not be used to endorse
35 * or promote products derived from this software without specific prior
36 * written permission.
37 *
38 * THIS SOFTWARE IS PROVIDED BY BERKELEY SOFTWARE DESIGN, INC. ``AS IS'' AND
39 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
40 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
41 * ARE DISCLAIMED. IN NO EVENT SHALL BERKELEY SOFTWARE DESIGN, INC. BE LIABLE
42 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
43 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
44 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
45 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
46 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
47 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
48 * SUCH DAMAGE.
49 *
50 * BSDI $From: auth_subr.c,v 2.4 1999/09/08 04:10:40 prb Exp $
51 */
52
53#include <sys/time.h>
54#include <sys/resource.h>
55#include <sys/socket.h>
56#include <sys/wait.h>
57
58#include <ctype.h>
59#include <err.h>
60#include <errno(*__errno()).h>
61#include <fcntl.h>
62#include <limits.h>
63#include <paths.h>
64#include <pwd.h>
65#include <stdarg.h>
66#include <stdio.h>
67#include <stdlib.h>
68#include <string.h>
69#include <syslog.h>
70#include <unistd.h>
71
72#include <login_cap.h>
73
74#define MAXSPOOLSIZE(8*1024) (8*1024) /* Spool up to 8K of back info */
75
76struct rmfiles {
77 struct rmfiles *next;
78 char *file;
79};
80
81struct authopts {
82 struct authopts *next;
83 char *opt;
84};
85
86struct authdata {
87 struct authdata *next;
88 void *ptr;
89 size_t len;
90};
91
92struct auth_session_t {
93 char *name; /* name of use being authenticated */
94 char *style; /* style of authentication used */
95 char *class; /* class of user */
96 char *service; /* type of service being performed */
97 char *challenge; /* last challenge issued */
98 int flags; /* see below */
99 struct passwd *pwd; /* password entry for user */
100 struct timeval now; /* time of authentication */
101
102 int state; /* authenticated state */
103
104 struct rmfiles *rmlist; /* list of files to remove on failure */
105 struct authopts *optlist; /* list of options to scripts */
106 struct authdata *data; /* additional data to send to scripts */
107
108 char spool[MAXSPOOLSIZE(8*1024)]; /* data returned from login script */
109 int index; /* how much returned thus far */
110
111 int fd; /* connection to authenticator */
112
113 va_list ap0; /* argument list to auth_call */
114 va_list ap; /* additional arguments to auth_call */
115};
116
117/*
118 * Internal flags
119 */
120#define AF_INTERACTIVE0x0001 0x0001 /* This is an interactive session */
121
122/*
123 * We cannot include bsd_auth.h until we define the above structures
124 */
125#include <bsd_auth.h>
126
127/*
128 * Internally used functions
129 */
130static void _add_rmlist(auth_session_t *, char *);
131static void _auth_spool(auth_session_t *, int);
132static void _recv_fd(auth_session_t *, int);
133static char *_auth_next_arg(auth_session_t *);
134/*
135 * Set up a known environment for all authentication scripts.
136 */
137static char * const auth_environ[] = {
138 "PATH=" _PATH_DEFPATH"/usr/bin:/bin:/usr/sbin:/sbin:/usr/X11R6/bin:/usr/local/bin:/usr/local/sbin",
139 "SHELL=" _PATH_BSHELL"/bin/sh",
140 NULL((void *)0),
141};
142
143static char defservice[] = LOGIN_DEFSERVICE"login";
144
145static va_list nilap;
146
147/*
148 * Quick one liners that only exist to keep auth_session_t opaque
149 */
150void auth_setstate(auth_session_t *as, int s){ as->state = s; }
151void auth_set_va_list(auth_session_t *as, va_list ap) { va_copy(as->ap, ap)__builtin_va_copy(as->ap, ap); }
152int auth_getstate(auth_session_t *as) { return (as->state); }
153struct passwd *auth_getpwd(auth_session_t *as) { return (as->pwd); }
154DEF_WEAK(auth_setstate)__asm__(".weak " "auth_setstate" " ; " "auth_setstate" " = " "_libc_auth_setstate"
)
;
155DEF_WEAK(auth_set_va_list)__asm__(".weak " "auth_set_va_list" " ; " "auth_set_va_list" " = "
"_libc_auth_set_va_list")
;
156DEF_WEAK(auth_getstate)__asm__(".weak " "auth_getstate" " ; " "auth_getstate" " = " "_libc_auth_getstate"
)
;
157DEF_WEAK(auth_getpwd)__asm__(".weak " "auth_getpwd" " ; " "auth_getpwd" " = " "_libc_auth_getpwd"
)
;
158
159/*
160 * Open a new BSD Authentication session with the default service
161 * (which can be changed later).
162 */
163auth_session_t *
164auth_open(void)
165{
166 auth_session_t *as;
167
168 if ((as = calloc(1, sizeof(auth_session_t))) != NULL((void *)0)) {
169 as->service = defservice;
170 as->fd = -1;
171 }
172
173 return (as);
174}
175DEF_WEAK(auth_open)__asm__(".weak " "auth_open" " ; " "auth_open" " = " "_libc_auth_open"
)
;
176
177/*
178 * Clean the specified BSD Authentication session.
179 */
180void
181auth_clean(auth_session_t *as)
182{
183 struct rmfiles *rm;
184 struct authdata *data;
185
186 as->state = 0;
187
188 auth_clrenv(as);
189
190 /*
191 * Clean out the rmlist and remove specified files
192 */
193 while ((rm = as->rmlist) != NULL((void *)0)) {
194 as->rmlist = rm->next;
195 unlink(rm->file);
196 free(rm);
197 }
198
199 /*
200 * Clean out data
201 */
202 while ((data = as->data) != NULL((void *)0)) {
203 if (as->data->len)
204 explicit_bzero(as->data->ptr, as->data->len);
205 as->data = data->next;
206 free(data);
207 }
208
209 auth_setitem(as, AUTHV_ALL, NULL((void *)0));
210
211 if (as->pwd != NULL((void *)0)) {
212 explicit_bzero(as->pwd->pw_passwd, strlen(as->pwd->pw_passwd));
213 free(as->pwd);
214 as->pwd = NULL((void *)0);
215 }
216
217 if (as->fd != -1) {
218 close(as->fd);
219 as->fd = -1;
220 }
221}
222DEF_WEAK(auth_clean)__asm__(".weak " "auth_clean" " ; " "auth_clean" " = " "_libc_auth_clean"
)
;
223
224/*
225 * Close the specified BSD Authentication session.
226 * Return 0 if not authenticated.
227 */
228int
229auth_close(auth_session_t *as)
230{
231 struct rmfiles *rm;
232 struct authopts *opt;
233 struct authdata *data;
234 int s;
235
236 /*
237 * Save our return value
238 */
239 s = as->state & AUTH_ALLOW(0x01 | 0x02 | 0x04);
240
241 if (s == 0)
242 as->index = 0;
243
244 auth_setenv(as);
245
246
247 /*
248 * Clean out the rmlist and remove specified files if the
249 * authentication failed
250 */
251 while ((rm = as->rmlist) != NULL((void *)0)) {
252 as->rmlist = rm->next;
253 if (s == 0)
254 unlink(rm->file);
255 free(rm);
256 }
257
258 /*
259 * Clean out the opt list
260 */
261 while ((opt = as->optlist) != NULL((void *)0)) {
262 as->optlist = opt->next;
263 free(opt);
264 }
265
266 /*
267 * Clean out data
268 */
269 while ((data = as->data) != NULL((void *)0)) {
270 if (as->data->len)
271 explicit_bzero(as->data->ptr, as->data->len);
272 as->data = data->next;
273 free(data);
274 }
275
276 if (as->pwd != NULL((void *)0)) {
277 explicit_bzero(as->pwd->pw_passwd, strlen(as->pwd->pw_passwd));
278 free(as->pwd);
279 as->pwd = NULL((void *)0);
280 }
281
282 /*
283 * Clean up random variables
284 */
285 if (as->service && as->service != defservice)
286 free(as->service);
287 free(as->challenge);
288 free(as->class);
289 free(as->style);
290 free(as->name);
291
292 free(as);
293 return (s);
294}
295DEF_WEAK(auth_close)__asm__(".weak " "auth_close" " ; " "auth_close" " = " "_libc_auth_close"
)
;
296
297/*
298 * Request a challenge for the session.
299 * The name and style must have already been specified
300 */
301char *
302auth_challenge(auth_session_t *as)
303{
304 char path[PATH_MAX1024];
305 int len;
306
307 if (as == NULL((void *)0) || as->style == NULL((void *)0) || as->name == NULL((void *)0) ||
308 !_auth_validuser(as->name))
309 return (NULL((void *)0));
310
311 len = snprintf(path, sizeof(path), _PATH_AUTHPROG"/usr/libexec/auth/login_" "%s", as->style);
312 if (len < 0 || len >= sizeof(path))
313 return (NULL((void *)0));
314
315 as->state = 0;
316
317 free(as->challenge);
318 as->challenge = NULL((void *)0);
319
320 auth_call(as, path, as->style, "-s", "challenge", "--", as->name,
321 as->class, (char *)NULL((void *)0));
322 if (as->state & AUTH_CHALLENGE0x10)
323 as->challenge = auth_getvalue(as, "challenge");
324 as->state = 0;
325 as->index = 0; /* toss our data */
326 return (as->challenge);
327}
328DEF_WEAK(auth_challenge)__asm__(".weak " "auth_challenge" " ; " "auth_challenge" " = "
"_libc_auth_challenge")
;
329
330/*
331 * Set/unset the requested environment variables.
332 * Mark the variables as set so they will not be set a second time.
333 * XXX - should provide a way to detect setenv() failure.
334 */
335void
336auth_setenv(auth_session_t *as)
337{
338 char *line, *name;
339
340 /*
341 * Set any environment variables we were asked for
342 */
343 for (line = as->spool; line < as->spool + as->index;) {
344 if (!strncasecmp(line, BI_SETENV"setenv", sizeof(BI_SETENV"setenv")-1)) {
345 if (isblank((unsigned char)line[sizeof(BI_SETENV"setenv") - 1])) {
346 /* only do it once! */
347 line[0] = 'd'; line[1] = 'i'; line[2] = 'd';
348 line += sizeof(BI_SETENV"setenv") - 1;
349 for (name = line;
350 isblank((unsigned char)*name); ++name)
351 ;
352 for (line = name;
353 *line && !isblank((unsigned char)*line);
354 ++line)
355 ;
356 if (*line)
357 *line++ = '\0';
358 for (; isblank((unsigned char)*line); ++line)
359 ;
360 if (*line != '\0' && setenv(name, line, 1))
361 warn("setenv(%s, %s)", name, line);
362 }
363 } else
364 if (!strncasecmp(line, BI_UNSETENV"unsetenv", sizeof(BI_UNSETENV"unsetenv")-1)) {
365 if (isblank((unsigned char)line[sizeof(BI_UNSETENV"unsetenv") - 1])) {
366 /* only do it once! */
367 line[2] = 'd'; line[3] = 'i'; line[4] = 'd';
368 line += sizeof(BI_UNSETENV"unsetenv") - 1;
369 for (name = line;
370 isblank((unsigned char)*name); ++name)
371 ;
372 for (line = name;
373 *line && !isblank((unsigned char)*line);
374 ++line)
375 ;
376 if (*line)
377 *line++ = '\0';
378 unsetenv(name);
379 }
380 }
381 while (*line++)
382 ;
383 }
384}
385DEF_WEAK(auth_setenv)__asm__(".weak " "auth_setenv" " ; " "auth_setenv" " = " "_libc_auth_setenv"
)
;
386
387/*
388 * Clear out any requested environment variables.
389 */
390void
391auth_clrenv(auth_session_t *as)
392{
393 char *line;
394
395 for (line = as->spool; line < as->spool + as->index;) {
396 if (!strncasecmp(line, BI_SETENV"setenv", sizeof(BI_SETENV"setenv")-1)) {
397 if (isblank((unsigned char)line[sizeof(BI_SETENV"setenv") - 1])) {
398 line[0] = 'i'; line[1] = 'g'; line[2] = 'n';
399 }
400 } else
401 if (!strncasecmp(line, BI_UNSETENV"unsetenv", sizeof(BI_UNSETENV"unsetenv")-1)) {
402 if (isblank((unsigned char)line[sizeof(BI_UNSETENV"unsetenv") - 1])) {
403 line[2] = 'i'; line[3] = 'g'; line[4] = 'n';
404 }
405 }
406 while (*line++)
407 ;
408 }
409}
410DEF_WEAK(auth_clrenv)__asm__(".weak " "auth_clrenv" " ; " "auth_clrenv" " = " "_libc_auth_clrenv"
)
;
411
412char *
413auth_getitem(auth_session_t *as, auth_item_t item)
414{
415 if (as != NULL((void *)0)) {
416 switch (item) {
417 case AUTHV_CHALLENGE:
418 return (as->challenge);
419 case AUTHV_CLASS:
420 return (as->class);
421 case AUTHV_NAME:
422 return (as->name);
423 case AUTHV_SERVICE:
424 return (as->service ? as->service : defservice);
425 case AUTHV_STYLE:
426 return (as->style);
427 case AUTHV_INTERACTIVE:
428 return ((as->flags & AF_INTERACTIVE0x0001) ? "True" : NULL((void *)0));
429 default:
430 break;
431 }
432 }
433 return (NULL((void *)0));
434}
435DEF_WEAK(auth_getitem)__asm__(".weak " "auth_getitem" " ; " "auth_getitem" " = " "_libc_auth_getitem"
)
;
436
437int
438auth_setitem(auth_session_t *as, auth_item_t item, char *value)
439{
440 if (as == NULL((void *)0)) {
441 errno(*__errno()) = EINVAL22;
442 return (-1);
443 }
444
445 switch (item) {
446 case AUTHV_ALL:
447 if (value != NULL((void *)0)) {
448 errno(*__errno()) = EINVAL22;
449 return (-1);
450 }
451 auth_setitem(as, AUTHV_CHALLENGE, NULL((void *)0));
452 auth_setitem(as, AUTHV_CLASS, NULL((void *)0));
453 auth_setitem(as, AUTHV_NAME, NULL((void *)0));
454 auth_setitem(as, AUTHV_SERVICE, NULL((void *)0));
455 auth_setitem(as, AUTHV_STYLE, NULL((void *)0));
456 auth_setitem(as, AUTHV_INTERACTIVE, NULL((void *)0));
457 return (0);
458
459 case AUTHV_CHALLENGE:
460 if (value == as->challenge)
461 return (0);
462 if (value != NULL((void *)0) && (value = strdup(value)) == NULL((void *)0))
463 return (-1);
464 free(as->challenge);
465 as->challenge = value;
466 return (0);
467
468 case AUTHV_CLASS:
469 if (value == as->class)
470 return (0);
471 if (value != NULL((void *)0) && (value = strdup(value)) == NULL((void *)0))
472 return (-1);
473 free(as->class);
474 as->class = value;
475 return (0);
476
477 case AUTHV_NAME:
478 if (value == as->name)
479 return (0);
480 if (value != NULL((void *)0) && !_auth_validuser(value)) {
481 errno(*__errno()) = EINVAL22;
482 return (-1);
483 }
484 if (value != NULL((void *)0) && (value = strdup(value)) == NULL((void *)0))
485 return (-1);
486 free(as->name);
487 as->name = value;
488 return (0);
489
490 case AUTHV_SERVICE:
491 if (value == as->service)
492 return (0);
493 if (value == NULL((void *)0) || strcmp(value, defservice) == 0)
494 value = defservice;
495 else if ((value = strdup(value)) == NULL((void *)0))
496 return (-1);
497 if (as->service && as->service != defservice)
498 free(as->service);
499 as->service = value;
500 return (0);
501
502 case AUTHV_STYLE:
503 if (value == as->style)
504 return (0);
505 if (value == NULL((void *)0) || strchr(value, '/') != NULL((void *)0) ||
506 (value = strdup(value)) == NULL((void *)0))
507 return (-1);
508 free(as->style);
509 as->style = value;
510 return (0);
511
512 case AUTHV_INTERACTIVE:
513 if (value == NULL((void *)0))
514 as->flags &= ~AF_INTERACTIVE0x0001;
515 else
516 as->flags |= ~AF_INTERACTIVE0x0001;
517 return (0);
518
519 default:
520 errno(*__errno()) = EINVAL22;
521 return (-1);
522 }
523}
524DEF_WEAK(auth_setitem)__asm__(".weak " "auth_setitem" " ; " "auth_setitem" " = " "_libc_auth_setitem"
)
;
525
526int
527auth_setoption(auth_session_t *as, char *n, char *v)
528{
529 struct authopts *opt;
530 size_t len = strlen(n) + strlen(v) + 2;
531 int ret;
532
533 if ((opt = malloc(sizeof(*opt) + len)) == NULL((void *)0))
534 return (-1);
535
536 opt->opt = (char *)(opt + 1);
537
538 ret = snprintf(opt->opt, len, "%s=%s", n, v);
539 if (ret < 0 || ret >= len) {
540 free(opt);
541 errno(*__errno()) = ENAMETOOLONG63;
542 return (-1);
543 }
544 opt->next = as->optlist;
545 as->optlist = opt;
546 return(0);
547}
548DEF_WEAK(auth_setoption)__asm__(".weak " "auth_setoption" " ; " "auth_setoption" " = "
"_libc_auth_setoption")
;
549
550void
551auth_clroptions(auth_session_t *as)
552{
553 struct authopts *opt;
554
555 while ((opt = as->optlist) != NULL((void *)0)) {
556 as->optlist = opt->next;
557 free(opt);
558 }
559}
560DEF_WEAK(auth_clroptions)__asm__(".weak " "auth_clroptions" " ; " "auth_clroptions" " = "
"_libc_auth_clroptions")
;
561
562void
563auth_clroption(auth_session_t *as, char *option)
564{
565 struct authopts *opt, *oopt;
566 size_t len;
567
568 len = strlen(option);
569
570 if ((opt = as->optlist) == NULL((void *)0))
571 return;
572
573 if (strncmp(opt->opt, option, len) == 0 &&
574 (opt->opt[len] == '=' || opt->opt[len] == '\0')) {
575 as->optlist = opt->next;
576 free(opt);
577 return;
578 }
579
580 while ((oopt = opt->next) != NULL((void *)0)) {
581 if (strncmp(oopt->opt, option, len) == 0 &&
582 (oopt->opt[len] == '=' || oopt->opt[len] == '\0')) {
583 opt->next = oopt->next;
584 free(oopt);
585 return;
586 }
587 opt = oopt;
588 }
589}
590DEF_WEAK(auth_clroption)__asm__(".weak " "auth_clroption" " ; " "auth_clroption" " = "
"_libc_auth_clroption")
;
591
592int
593auth_setdata(auth_session_t *as, void *ptr, size_t len)
594{
595 struct authdata *data, *dp;
596
597 if (len <= 0)
598 return (0);
599
600 if ((data = malloc(sizeof(*data) + len)) == NULL((void *)0))
601 return (-1);
602
603 data->next = NULL((void *)0);
604 data->len = len;
605 data->ptr = data + 1;
606 memcpy(data->ptr, ptr, len);
607
608 if (as->data == NULL((void *)0))
609 as->data = data;
610 else {
611 for (dp = as->data; dp->next != NULL((void *)0); dp = dp->next)
612 ;
613 dp->next = data;
614 }
615 return (0);
616}
617DEF_WEAK(auth_setdata)__asm__(".weak " "auth_setdata" " ; " "auth_setdata" " = " "_libc_auth_setdata"
)
;
618
619int
620auth_setpwd(auth_session_t *as, struct passwd *pwd)
621{
622 struct passwd pwstore;
623 char *instance, pwbuf[_PW_BUF_LEN1024];
624
625 if (pwd == NULL((void *)0) && as->pwd == NULL((void *)0) && as->name == NULL((void *)0))
626 return (-1); /* true failure */
627
628 if (pwd == NULL((void *)0)) {
629 /*
630 * If we were not passed in a pwd structure we need to
631 * go find one for ourself. Always look up the username
632 * (if it is defined) in the passwd database to see if there
633 * is an entry for the user. If not, either use the current
634 * entry or simply return a 1 which implies there is
635 * no user by that name here. This is not a failure, just
636 * a point of information.
637 */
638 if (as->name == NULL((void *)0))
639 return (0);
640 getpwnam_r(as->name, &pwstore, pwbuf, sizeof(pwbuf), &pwd);
641 if (pwd == NULL((void *)0)) {
642 instance = strchr(as->name, '/');
643 if (instance == NULL((void *)0))
644 return (as->pwd ? 0 : 1);
645 if (strcmp(instance, "/root") == 0) {
646 getpwnam_r(instance + 1, &pwstore, pwbuf,
647 sizeof(pwbuf), &pwd);
648 }
649 if (pwd == NULL((void *)0))
650 return (as->pwd ? 0 : 1);
651 }
652 }
653 if ((pwd = pw_dup(pwd)) == NULL((void *)0))
654 return (-1); /* true failure */
655 if (as->pwd) {
656 explicit_bzero(as->pwd->pw_passwd, strlen(as->pwd->pw_passwd));
657 free(as->pwd);
658 }
659 as->pwd = pwd;
660 return (0);
661}
662DEF_WEAK(auth_setpwd)__asm__(".weak " "auth_setpwd" " ; " "auth_setpwd" " = " "_libc_auth_setpwd"
)
;
663
664char *
665auth_getvalue(auth_session_t *as, char *what)
666{
667 char *line, *v, *value;
668 int n, len;
669
670 len = strlen(what);
671
672 for (line = as->spool; line < as->spool + as->index;) {
673 if (strncasecmp(line, BI_VALUE"value", sizeof(BI_VALUE"value")-1) != 0)
674 goto next;
675 line += sizeof(BI_VALUE"value") - 1;
676
677 if (!isblank((unsigned char)*line))
678 goto next;
679
680 while (isblank((unsigned char)*++line))
681 ;
682
683 if (strncmp(line, what, len) != 0 ||
684 !isblank((unsigned char)line[len]))
685 goto next;
686 line += len;
687 while (isblank((unsigned char)*++line))
688 ;
689 value = strdup(line);
690 if (value == NULL((void *)0))
691 return (NULL((void *)0));
692
693 /*
694 * XXX - There should be a more standardized
695 * routine for doing this sort of thing.
696 */
697 for (line = v = value; *line; ++line) {
698 if (*line == '\\') {
699 switch (*++line) {
700 case 'r':
701 *v++ = '\r';
702 break;
703 case 'n':
704 *v++ = '\n';
705 break;
706 case 't':
707 *v++ = '\t';
708 break;
709 case '0': case '1': case '2':
710 case '3': case '4': case '5':
711 case '6': case '7':
712 n = *line - '0';
713 if (isdigit((unsigned char)line[1])) {
714 ++line;
715 n <<= 3;
716 n |= *line-'0';
717 }
718 if (isdigit((unsigned char)line[1])) {
719 ++line;
720 n <<= 3;
721 n |= *line-'0';
Value stored to 'n' is never read
722 }
723 break;
724 default:
725 *v++ = *line;
726 break;
727 }
728 } else
729 *v++ = *line;
730 }
731 *v = '\0';
732 return (value);
733next:
734 while (*line++)
735 ;
736 }
737 return (NULL((void *)0));
738}
739DEF_WEAK(auth_getvalue)__asm__(".weak " "auth_getvalue" " ; " "auth_getvalue" " = " "_libc_auth_getvalue"
)
;
740
741quad_t
742auth_check_expire(auth_session_t *as)
743{
744 if (as->pwd == NULL((void *)0) && auth_setpwd(as, NULL((void *)0)) < 0) {
745 as->state &= ~AUTH_ALLOW(0x01 | 0x02 | 0x04);
746 as->state |= AUTH_EXPIRED0x20; /* XXX */
747 return (-1);
748 }
749
750 if (as->pwd == NULL((void *)0))
751 return (0);
752
753 if (as->pwd && (quad_t)as->pwd->pw_expire != 0) {
754 if (as->now.tv_sec == 0)
755 WRAP(gettimeofday)_libc_gettimeofday_wrap(&as->now, NULL((void *)0));
756 if ((quad_t)as->now.tv_sec >= (quad_t)as->pwd->pw_expire) {
757 as->state &= ~AUTH_ALLOW(0x01 | 0x02 | 0x04);
758 as->state |= AUTH_EXPIRED0x20;
759 }
760 if ((quad_t)as->now.tv_sec == (quad_t)as->pwd->pw_expire)
761 return (-1);
762 return ((quad_t)as->pwd->pw_expire - (quad_t)as->now.tv_sec);
763 }
764 return (0);
765}
766DEF_WEAK(auth_check_expire)__asm__(".weak " "auth_check_expire" " ; " "auth_check_expire"
" = " "_libc_auth_check_expire")
;
767
768quad_t
769auth_check_change(auth_session_t *as)
770{
771 if (as->pwd == NULL((void *)0) && auth_setpwd(as, NULL((void *)0)) < 0) {
772 as->state &= ~AUTH_ALLOW(0x01 | 0x02 | 0x04);
773 as->state |= AUTH_PWEXPIRED0x40; /* XXX */
774 return (-1);
775 }
776
777 if (as->pwd == NULL((void *)0))
778 return (0);
779
780 if (as->pwd && (quad_t)as->pwd->pw_change) {
781 if (as->now.tv_sec == 0)
782 WRAP(gettimeofday)_libc_gettimeofday_wrap(&as->now, NULL((void *)0));
783 if (as->now.tv_sec >= (quad_t)as->pwd->pw_change) {
784 as->state &= ~AUTH_ALLOW(0x01 | 0x02 | 0x04);
785 as->state |= AUTH_PWEXPIRED0x40;
786 }
787 if ((quad_t)as->now.tv_sec == (quad_t)as->pwd->pw_change)
788 return (-1);
789 return ((quad_t)as->pwd->pw_change - (quad_t)as->now.tv_sec);
790 }
791 return (0);
792}
793DEF_WEAK(auth_check_change)__asm__(".weak " "auth_check_change" " ; " "auth_check_change"
" = " "_libc_auth_check_change")
;
794
795/*
796 * The down and dirty call to the login script
797 * okay contains the default return value, typically 0 but
798 * is AUTH_OKAY for approval like scripts.
799 *
800 * Internally additional trailing arguments can be read from as->ap
801 * Options will be placed just after the first argument (not including path).
802 *
803 * Any data will be sent to (and freed by) the script
804 */
805int
806auth_call(auth_session_t *as, char *path, ...)
807{
808 char *line;
809 struct authdata *data;
810 struct authopts *opt;
811 pid_t pid;
812 int status;
813 int okay;
814 int pfd[2];
815 int argc;
816 char *argv[64]; /* 64 args should be more than enough */
817#define Nargc(sizeof(argv)/sizeof(argv[0])) (sizeof(argv)/sizeof(argv[0]))
818
819 va_start(as->ap0, path)__builtin_va_start(as->ap0, path);
820
821 argc = 0;
822 if ((argv[argc] = _auth_next_arg(as)) != NULL((void *)0))
823 ++argc;
824
825 if (as->fd != -1) {
826 argv[argc++] = "-v";
827 argv[argc++] = "fd=4"; /* AUTH_FD, see below */
828 }
829 /* XXX - fail if out of space in argv */
830 for (opt = as->optlist; opt != NULL((void *)0); opt = opt->next) {
831 if (argc < Nargc(sizeof(argv)/sizeof(argv[0])) - 2) {
832 argv[argc++] = "-v";
833 argv[argc++] = opt->opt;
834 } else {
835 syslog(LOG_ERR3, "too many authentication options");
836 goto fail;
837 }
838 }
839 while (argc < Nargc(sizeof(argv)/sizeof(argv[0])) - 1 && (argv[argc] = _auth_next_arg(as)))
840 ++argc;
841
842 if (argc >= Nargc(sizeof(argv)/sizeof(argv[0])) - 1 && _auth_next_arg(as)) {
843 if (memcmp(&nilap, &(as->ap0), sizeof(nilap)) != 0) {
844 va_end(as->ap0)__builtin_va_end(as->ap0);
845 explicit_bzero(&(as->ap0), sizeof(as->ap0));
846 }
847 if (memcmp(&nilap, &(as->ap), sizeof(nilap)) != 0) {
848 va_end(as->ap)__builtin_va_end(as->ap);
849 explicit_bzero(&(as->ap), sizeof(as->ap));
850 }
851 syslog(LOG_ERR3, "too many arguments");
852 goto fail;
853 }
854
855 argv[argc] = NULL((void *)0);
856
857 if (socketpair(PF_LOCAL1, SOCK_STREAM1, 0, pfd) == -1) {
858 syslog(LOG_ERR3, "unable to create backchannel %m");
859 warnx("internal resource failure");
860 goto fail;
861 }
862
863 switch (pid = fork()) {
864 case -1:
865 syslog(LOG_ERR3, "%s: %m", path);
866 warnx("internal resource failure");
867 close(pfd[0]);
868 close(pfd[1]);
869 goto fail;
870 case 0:
871#define COMM_FD3 3
872#define AUTH_FD4 4
873 if (dup2(pfd[1], COMM_FD3) == -1)
874 err(1, "dup of backchannel");
875 if (as->fd != -1) {
876 if (dup2(as->fd, AUTH_FD4) == -1)
877 err(1, "dup of auth fd");
878 closefrom(AUTH_FD4 + 1);
879 } else
880 closefrom(COMM_FD3 + 1);
881 execve(path, argv, auth_environ);
882 syslog(LOG_ERR3, "%s: %m", path);
883 err(1, "%s", path);
884 default:
885 close(pfd[1]);
886 if (as->fd != -1) {
887 close(as->fd); /* so child has only ref */
888 as->fd = -1;
889 }
890 while ((data = as->data) != NULL((void *)0)) {
891 as->data = data->next;
892 if (data->len > 0) {
893 write(pfd[0], data->ptr, data->len);
894 explicit_bzero(data->ptr, data->len);
895 }
896 free(data);
897 }
898 as->index = 0;
899 _auth_spool(as, pfd[0]);
900 close(pfd[0]);
901 do {
902 if (waitpid(pid, &status, 0) != -1) {
903 if (!WIFEXITED(status)(((status) & 0177) == 0))
904 goto fail;
905 break;
906 }
907 /*
908 * could get ECHILD if it was waited for by
909 * another thread or from a signal handler
910 */
911 } while (errno(*__errno()) == EINTR4);
912 }
913
914 /*
915 * Now scan the spooled data
916 * It is easier to wait for all the data before starting
917 * to scan it.
918 */
919 for (line = as->spool; line < as->spool + as->index;) {
920 if (!strncasecmp(line, BI_REJECT"reject", sizeof(BI_REJECT"reject")-1)) {
921 line += sizeof(BI_REJECT"reject") - 1;
922 if (!*line || *line == ' ' || *line == '\t') {
923 while (*line == ' ' || *line == '\t')
924 ++line;
925 if (!strcasecmp(line, "silent")) {
926 as->state = AUTH_SILENT0x08;
927 break;
928 }
929 if (!strcasecmp(line, "challenge")) {
930 as->state = AUTH_CHALLENGE0x10;
931 break;
932 }
933 if (!strcasecmp(line, "expired")) {
934 as->state = AUTH_EXPIRED0x20;
935 break;
936 }
937 if (!strcasecmp(line, "pwexpired")) {
938 as->state = AUTH_PWEXPIRED0x40;
939 break;
940 }
941 }
942 break;
943 } else if (!strncasecmp(line, BI_AUTH"authorize", sizeof(BI_AUTH"authorize")-1)) {
944 line += sizeof(BI_AUTH"authorize") - 1;
945 if (!*line || *line == ' ' || *line == '\t') {
946 while (*line == ' ' || *line == '\t')
947 ++line;
948 if (*line == '\0')
949 as->state |= AUTH_OKAY0x01;
950 else if (!strcasecmp(line, "root"))
951 as->state |= AUTH_ROOTOKAY0x02;
952 else if (!strcasecmp(line, "secure"))
953 as->state |= AUTH_SECURE0x04;
954 }
955 } else if (!strncasecmp(line, BI_REMOVE"remove", sizeof(BI_REMOVE"remove")-1)) {
956 line += sizeof(BI_REMOVE"remove") - 1;
957 while (*line == ' ' || *line == '\t')
958 ++line;
959 if (*line)
960 _add_rmlist(as, line);
961 }
962 while (*line++)
963 ;
964 }
965
966 if (WEXITSTATUS(status)(int)(((unsigned)(status) >> 8) & 0xff))
967 as->state &= ~AUTH_ALLOW(0x01 | 0x02 | 0x04);
968
969 okay = as->state & AUTH_ALLOW(0x01 | 0x02 | 0x04);
970
971 if (!okay)
972 auth_clrenv(as);
973
974 if (0) {
975fail:
976 auth_clrenv(as);
977 as->state = 0;
978 okay = -1;
979 }
980
981 while ((data = as->data) != NULL((void *)0)) {
982 as->data = data->next;
983 free(data);
984 }
985
986 if (memcmp(&nilap, &(as->ap0), sizeof(nilap)) != 0) {
987 va_end(as->ap0)__builtin_va_end(as->ap0);
988 explicit_bzero(&(as->ap0), sizeof(as->ap0));
989 }
990
991 if (memcmp(&nilap, &(as->ap), sizeof(nilap)) != 0) {
992 va_end(as->ap)__builtin_va_end(as->ap);
993 explicit_bzero(&(as->ap), sizeof(as->ap));
994 }
995 return (okay);
996}
997DEF_WEAK(auth_call)__asm__(".weak " "auth_call" " ; " "auth_call" " = " "_libc_auth_call"
)
;
998
999static void
1000_recv_fd(auth_session_t *as, int fd)
1001{
1002 struct msghdr msg;
1003 struct cmsghdr *cmp;
1004 union {
1005 struct cmsghdr hdr;
1006 char buf[CMSG_SPACE(sizeof(int))((((unsigned long)(sizeof(struct cmsghdr)) + (sizeof(long) - 1
)) &~(sizeof(long) - 1)) + (((unsigned long)(sizeof(int))
+ (sizeof(long) - 1)) &~(sizeof(long) - 1)))
];
1007 } cmsgbuf;
1008
1009 memset(&msg, 0, sizeof(msg));
1010 msg.msg_control = &cmsgbuf.buf;
1011 msg.msg_controllen = sizeof(cmsgbuf.buf);
1012 if (recvmsg(fd, &msg, 0) == -1)
1013 syslog(LOG_ERR3, "recvmsg: %m");
1014 else if (msg.msg_flags & MSG_TRUNC0x10)
1015 syslog(LOG_ERR3, "message truncated");
1016 else if (msg.msg_flags & MSG_CTRUNC0x20)
1017 syslog(LOG_ERR3, "control message truncated");
1018 else if ((cmp = CMSG_FIRSTHDR(&msg)((&msg)->msg_controllen >= sizeof(struct cmsghdr) ?
(struct cmsghdr *)(&msg)->msg_control : (struct cmsghdr
*)((void *)0))
) == NULL((void *)0))
1019 syslog(LOG_ERR3, "missing control message");
1020 else {
1021 if (cmp->cmsg_level != SOL_SOCKET0xffff)
1022 syslog(LOG_ERR3, "unexpected cmsg_level %d",
1023 cmp->cmsg_level);
1024 else if (cmp->cmsg_type != SCM_RIGHTS0x01)
1025 syslog(LOG_ERR3, "unexpected cmsg_type %d",
1026 cmp->cmsg_type);
1027 else if (cmp->cmsg_len != CMSG_LEN(sizeof(int))((((unsigned long)(sizeof(struct cmsghdr)) + (sizeof(long) - 1
)) &~(sizeof(long) - 1)) + (sizeof(int)))
)
1028 syslog(LOG_ERR3, "bad cmsg_len %d",
1029 cmp->cmsg_len);
1030 else {
1031 if (as->fd != -1)
1032 close(as->fd);
1033 as->fd = *(int *)CMSG_DATA(cmp)((unsigned char *)(cmp) + (((unsigned long)(sizeof(struct cmsghdr
)) + (sizeof(long) - 1)) &~(sizeof(long) - 1)))
;
1034 }
1035 }
1036}
1037
1038static void
1039_auth_spool(auth_session_t *as, int fd)
1040{
1041 ssize_t r;
1042 char *b, *s;
1043
1044 for (s = as->spool + as->index; as->index < sizeof(as->spool) - 1; ) {
1045 r = read(fd, as->spool + as->index,
1046 sizeof(as->spool) - as->index);
1047 if (r <= 0) {
1048 as->spool[as->index] = '\0';
1049 return;
1050 }
1051 b = as->spool + as->index;
1052 as->index += r;
1053 /*
1054 * Convert newlines into NULs to allow easy scanning of the
1055 * file and receive an fd if there is a BI_FDPASS message.
1056 * XXX - checking for BI_FDPASS here is annoying but
1057 * we need to avoid the read() slurping in control data.
1058 */
1059 while (r-- > 0) {
1060 if (*b++ == '\n') {
1061 b[-1] = '\0';
1062 if (strcasecmp(s, BI_FDPASS"fd") == 0)
1063 _recv_fd(as, fd);
1064 s = b;
1065 }
1066 }
1067 }
1068
1069 syslog(LOG_ERR3, "Overflowed backchannel spool buffer");
1070 errx(1, "System error in authentication program");
1071}
1072
1073static void
1074_add_rmlist(auth_session_t *as, char *file)
1075{
1076 struct rmfiles *rm;
1077 size_t i = strlen(file) + 1;
1078
1079 // XXX should rangecheck i since we are about to add?
1080
1081 if ((rm = malloc(sizeof(struct rmfiles) + i)) == NULL((void *)0)) {
1082 syslog(LOG_ERR3, "Failed to allocate rmfiles: %m");
1083 return;
1084 }
1085 rm->file = (char *)(rm + 1);
1086 rm->next = as->rmlist;
1087 strlcpy(rm->file, file, i);
1088 as->rmlist = rm;
1089}
1090
1091static char *
1092_auth_next_arg(auth_session_t *as)
1093{
1094 char *arg;
1095
1096 if (memcmp(&nilap, &(as->ap0), sizeof(nilap)) != 0) {
1097 if ((arg = va_arg(as->ap0, char *)__builtin_va_arg(as->ap0, char *)) != NULL((void *)0))
1098 return (arg);
1099 va_end(as->ap0)__builtin_va_end(as->ap0);
1100 explicit_bzero(&(as->ap0), sizeof(as->ap0));
1101 }
1102 if (memcmp(&nilap, &(as->ap), sizeof(nilap)) != 0) {
1103 if ((arg = va_arg(as->ap, char *)__builtin_va_arg(as->ap, char *)) != NULL((void *)0))
1104 return (arg);
1105 va_end(as->ap)__builtin_va_end(as->ap);
1106 explicit_bzero(&(as->ap), sizeof(as->ap));
1107 }
1108 return (NULL((void *)0));
1109}