Bug Summary

File:src/usr.sbin/radiusd/radiusd_bsdauth/../radiusd_bsdauth.c
Warning:line 378, column 9
Although the value stored to 'n' is used in the enclosing expression, the value is never actually read from 'n'

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 radiusd_bsdauth.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 -pic-is-pie -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/usr.sbin/radiusd/radiusd_bsdauth/obj -resource-dir /usr/local/lib/clang/13.0.0 -I /usr/src/usr.sbin/radiusd/radiusd_bsdauth/.. -internal-isystem /usr/local/lib/clang/13.0.0/include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -fdebug-compilation-dir=/usr/src/usr.sbin/radiusd/radiusd_bsdauth/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/usr.sbin/radiusd/radiusd_bsdauth/../radiusd_bsdauth.c
1/* $OpenBSD: radiusd_bsdauth.c,v 1.14 2019/12/14 15:56:20 millert Exp $ */
2
3/*
4 * Copyright (c) 2015 YASUOKA Masahiko <yasuoka@yasuoka.net>
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#include <sys/types.h>
20#include <sys/queue.h>
21#include <sys/socket.h>
22#include <sys/uio.h>
23#include <sys/wait.h>
24
25#include <bsd_auth.h>
26#include <err.h>
27#include <errno(*__errno()).h>
28#include <fcntl.h>
29#include <grp.h>
30#include <imsg.h>
31#include <login_cap.h>
32#include <pwd.h>
33#include <stdbool.h>
34#include <stdio.h>
35#include <stdlib.h>
36#include <string.h>
37#include <syslog.h>
38#include <unistd.h>
39
40#include "radiusd.h"
41#include "radiusd_module.h"
42
43struct module_bsdauth {
44 struct module_base *base;
45 struct imsgbuf ibuf;
46 char **okgroups;
47};
48
49/* IPC between priv and main */
50enum {
51 IMSG_BSDAUTH_OK = 1000,
52 IMSG_BSDAUTH_NG,
53 IMSG_BSDAUTH_USERCHECK,
54 IMSG_BSDAUTH_GROUPCHECK
55};
56struct auth_usercheck_args {
57 size_t userlen;
58 size_t passlen;
59};
60struct auth_groupcheck_args {
61 size_t userlen;
62 size_t grouplen;
63};
64
65__dead__attribute__((__noreturn__)) static void
66 module_bsdauth_main(void);
67static void module_bsdauth_config_set(void *, const char *, int,
68 char * const *);
69static void module_bsdauth_userpass(void *, u_int, const char *,
70 const char *);
71static pid_t start_child(char *, int);
72__dead__attribute__((__noreturn__)) static void
73 fatal(const char *);
74
75static struct module_handlers module_bsdauth_handlers = {
76 .userpass = module_bsdauth_userpass,
77 .config_set = module_bsdauth_config_set
78};
79
80int
81main(int argc, char *argv[])
82{
83 int ch, pairsock[2], status;
84 struct imsgbuf ibuf;
85 struct imsg imsg;
86 ssize_t n;
87 size_t datalen;
88 pid_t pid;
89 char *saved_argv0;
90
91 while ((ch = getopt(argc, argv, "M")) != -1)
92 switch (ch) {
93 case 'M':
94 module_bsdauth_main();
95 /* never return, not rearched here */
96 break;
97 default:
98 break;
99 }
100 saved_argv0 = argv[0];
101 argc -= optind;
102 argv += optind;
103
104 if (socketpair(AF_UNIX1, SOCK_STREAM1 | SOCK_CLOEXEC0x8000, PF_UNSPEC0,
105 pairsock) == -1)
106 err(EXIT_FAILURE1, "socketpair");
107
108 openlog(NULL((void *)0), LOG_PID0x01, LOG_DAEMON(3<<3));
109
110 pid = start_child(saved_argv0, pairsock[1]);
111
112 /*
113 * Privileged process
114 */
115 setproctitle("[priv]");
116 imsg_init(&ibuf, pairsock[0]);
117
118 if (pledge("stdio getpw rpath proc exec", NULL((void *)0)) == -1)
119 err(EXIT_FAILURE1, "pledge");
120
121 for (;;) {
122 if ((n = imsg_read(&ibuf)) <= 0 && errno(*__errno()) != EAGAIN35)
123 break;
124 for (;;) {
125 if ((n = imsg_get(&ibuf, &imsg)) == -1)
126 break;
127 if (n == 0)
128 break;
129 datalen = imsg.hdr.len - IMSG_HEADER_SIZEsizeof(struct imsg_hdr);
130 switch (imsg.hdr.type) {
131 case IMSG_BSDAUTH_USERCHECK:
132 {
133 char *user, *pass;
134 bool_Bool authok = false0;
135 struct auth_usercheck_args
136 *args;
137
138 if (datalen < sizeof(
139 struct auth_usercheck_args)) {
140 syslog(LOG_ERR3, "Short message");
141 break;
142 }
143 args = (struct auth_usercheck_args *)imsg.data;
144
145 if (datalen < sizeof(struct auth_usercheck_args)
146 + args->userlen + args->passlen) {
147 syslog(LOG_ERR3, "Short message");
148 break;
149 }
150 user = (char *)(args + 1);
151 user[args->userlen - 1] = '\0';
152 pass = user + args->userlen;
153 pass[args->passlen - 1] = '\0';
154
155 if (auth_userokay(user, NULL((void *)0), NULL((void *)0), pass))
156 authok = true1;
157 explicit_bzero(pass, args->passlen);
158
159 imsg_compose(&ibuf, (authok)
160 ? IMSG_BSDAUTH_OK : IMSG_BSDAUTH_NG,
161 0, 0, -1, NULL((void *)0), 0);
162 break;
163 }
164 case IMSG_BSDAUTH_GROUPCHECK:
165 {
166 int i;
167 char *user, *group;
168 struct passwd *pw;
169 struct group gr0, *gr;
170 char g_buf[4096];
171 bool_Bool group_ok = false0;
172 struct auth_groupcheck_args
173 *args;
174
175 if (datalen < sizeof(
176 struct auth_groupcheck_args)) {
177 syslog(LOG_ERR3, "Short message");
178 break;
179 }
180 args = (struct auth_groupcheck_args *)imsg.data;
181 if (datalen <
182 sizeof(struct auth_groupcheck_args) +
183 args->userlen + args->grouplen) {
184 syslog(LOG_ERR3, "Short message");
185 break;
186 }
187 user = (char *)(args + 1);
188 user[args->userlen - 1] = '\0';
189 group = user + args->userlen;
190 group[args->grouplen - 1] = '\0';
191
192 user[strcspn(user, ":")] = '\0';
193 pw = getpwnam(user);
194 if (pw == NULL((void *)0))
195 goto invalid;
196 if (getgrnam_r(group, &gr0, g_buf,
197 sizeof(g_buf), &gr) == -1 || gr == NULL((void *)0))
198 goto invalid;
199
200 if (gr->gr_gid == pw->pw_gid) {
201 group_ok = true1;
202 goto invalid;
203 }
204 for (i = 0; gr->gr_mem[i] != NULL((void *)0); i++) {
205 if (strcmp(gr->gr_mem[i], pw->pw_name)
206 == 0) {
207 group_ok = true1;
208 goto invalid;
209 }
210 }
211invalid:
212 endgrent();
213
214 imsg_compose(&ibuf, (group_ok)
215 ? IMSG_BSDAUTH_OK : IMSG_BSDAUTH_NG,
216 0, 0, -1, NULL((void *)0), 0);
217 break;
218 }
219 }
220 imsg_free(&imsg);
221 imsg_flush(&ibuf);
222 }
223 imsg_flush(&ibuf);
224 }
225 imsg_clear(&ibuf);
226
227 while (waitpid(pid, &status, 0) == -1) {
228 if (errno(*__errno()) != EINTR4)
229 break;
230 }
231 exit(WEXITSTATUS(status)(int)(((unsigned)(status) >> 8) & 0xff));
232}
233
234static void
235module_bsdauth_main(void)
236{
237 int i;
238 struct module_bsdauth module_bsdauth;
239
240 /*
241 * main process
242 */
243 setproctitle("[main]");
244 openlog(NULL((void *)0), LOG_PID0x01, LOG_DAEMON(3<<3));
245 memset(&module_bsdauth, 0, sizeof(module_bsdauth));
246 if ((module_bsdauth.base = module_create(STDIN_FILENO0, &module_bsdauth,
247 &module_bsdauth_handlers)) == NULL((void *)0))
248 err(1, "Could not create a module instance");
249
250 module_drop_privilege(module_bsdauth.base);
251
252 module_load(module_bsdauth.base);
253 imsg_init(&module_bsdauth.ibuf, 3);
254
255 if (pledge("stdio proc", NULL((void *)0)) == -1)
256 err(EXIT_FAILURE1, "pledge");
257
258 while (module_run(module_bsdauth.base) == 0)
259 ;
260
261 module_destroy(module_bsdauth.base);
262 imsg_clear(&module_bsdauth.ibuf);
263
264 if (module_bsdauth.okgroups) {
265 for (i = 0; module_bsdauth.okgroups[i] != NULL((void *)0); i++)
266 free(module_bsdauth.okgroups[i]);
267 }
268 free(module_bsdauth.okgroups);
269
270 exit(EXIT_SUCCESS0);
271}
272
273static void
274module_bsdauth_config_set(void *ctx, const char *name, int argc,
275 char * const * argv)
276{
277 struct module_bsdauth *module = ctx;
278 int i;
279 char **groups = NULL((void *)0);
280
281 if (strcmp(name, "restrict-group") == 0) {
282 if (module->okgroups != NULL((void *)0)) {
283 module_send_message(module->base, IMSG_NG,
284 "`restrict-group' is already defined");
285 goto on_error;
286 }
287 if ((groups = calloc(sizeof(char *), argc + 1)) == NULL((void *)0)) {
288 module_send_message(module->base, IMSG_NG,
289 "Out of memory");
290 goto on_error;
291 }
292 for (i = 0; i < argc; i++) {
293 if ((groups[i] = strdup(argv[i])) == NULL((void *)0)) {
294 module_send_message(module->base,
295 IMSG_NG, "Out of memory");
296 goto on_error;
297 }
298 }
299 groups[i] = NULL((void *)0);
300 module->okgroups = groups;
301 module_send_message(module->base, IMSG_OK, NULL((void *)0));
302 } else if (strncmp(name, "_", 1) == 0)
303 /* ignore all internal messages */
304 module_send_message(module->base, IMSG_OK, NULL((void *)0));
305 else
306 module_send_message(module->base, IMSG_NG,
307 "Unknown config parameter `%s'", name);
308 return;
309on_error:
310 if (groups != NULL((void *)0)) {
311 for (i = 0; groups[i] != NULL((void *)0); i++)
312 free(groups[i]);
313 free(groups);
314 }
315 return;
316}
317
318
319static void
320module_bsdauth_userpass(void *ctx, u_int q_id, const char *user,
321 const char *pass)
322{
323 struct module_bsdauth *module = ctx;
324 struct auth_usercheck_args
325 usercheck;
326 struct auth_groupcheck_args
327 groupcheck;
328 struct iovec iov[4];
329 const char *group;
330 u_int i;
331 const char *reason;
332 struct imsg imsg;
333 ssize_t n;
334
335 memset(&imsg, 0, sizeof(imsg));
336 if (pass == NULL((void *)0))
337 pass = "";
338
339 usercheck.userlen = strlen(user) + 1;
340 usercheck.passlen = strlen(pass) + 1;
341 iov[0].iov_base = &usercheck;
342 iov[0].iov_len = sizeof(usercheck);
343 iov[1].iov_base = (char *)user;
344 iov[1].iov_len = usercheck.userlen;
345 iov[2].iov_base = (char *)pass;
346 iov[2].iov_len = usercheck.passlen;
347
348 imsg_composev(&module->ibuf, IMSG_BSDAUTH_USERCHECK, 0, 0, -1, iov, 3);
349 imsg_flush(&module->ibuf);
350 if ((n = imsg_read(&module->ibuf)) == -1 || n == 0)
351 fatal("imsg_read() failed in module_bsdauth_userpass()");
352 if ((n = imsg_get(&module->ibuf, &imsg)) <= 0)
353 fatal("imsg_get() failed in module_bsdauth_userpass()");
354
355 if (imsg.hdr.type != IMSG_BSDAUTH_OK) {
356 reason = "Authentication failed";
357 goto auth_ng;
358 }
359 if (module->okgroups != NULL((void *)0)) {
360 reason = "Group restriction is not allowed";
361 for (i = 0; module->okgroups[i] != NULL((void *)0); i++) {
362 group = module->okgroups[i];
363
364 groupcheck.userlen = strlen(user) + 1;
365 groupcheck.grouplen = strlen(group) + 1;
366 iov[0].iov_base = &groupcheck;
367 iov[0].iov_len = sizeof(groupcheck);
368 iov[1].iov_base = (char *)user;
369 iov[1].iov_len = groupcheck.userlen;
370 iov[2].iov_base = (char *)group;
371 iov[2].iov_len = groupcheck.grouplen;
372 imsg_composev(&module->ibuf, IMSG_BSDAUTH_GROUPCHECK,
373 0, 0, -1, iov, 3);
374 imsg_flush(&module->ibuf);
375 if ((n = imsg_read(&module->ibuf)) == -1 || n == 0)
376 fatal("imsg_read() failed in "
377 "module_bsdauth_userpass()");
378 if ((n = imsg_get(&module->ibuf, &imsg)) <= 0)
Although the value stored to 'n' is used in the enclosing expression, the value is never actually read from 'n'
379 fatal("imsg_get() failed in "
380 "module_bsdauth_userpass()");
381 if (imsg.hdr.type == IMSG_BSDAUTH_OK)
382 goto group_ok;
383 }
384 goto auth_ng;
385 }
386group_ok:
387 module_userpass_ok(module->base, q_id, "Authentication succeeded");
388 imsg_free(&imsg);
389 return;
390auth_ng:
391 module_userpass_fail(module->base, q_id, reason);
392 imsg_free(&imsg);
393 return;
394}
395
396pid_t
397start_child(char *argv0, int fd)
398{
399 char *argv[5];
400 int argc = 0;
401 pid_t pid;
402
403 switch (pid = fork()) {
404 case -1:
405 fatal("cannot fork");
406 case 0:
407 break;
408 default:
409 close(fd);
410 return (pid);
411 }
412
413 if (fd != 3) {
414 if (dup2(fd, 3) == -1)
415 fatal("cannot setup imsg fd");
416 } else if (fcntl(fd, F_SETFD2, 0) == -1)
417 fatal("cannot setup imsg fd");
418
419 argv[argc++] = argv0;
420 argv[argc++] = "-M"; /* main proc */
421 execvp(argv0, argv);
422 fatal("execvp");
423}
424
425static void
426fatal(const char *msg)
427{
428 syslog(LOG_ERR3, "%s: %m", msg);
429 abort();
430}