Bug Summary

File:src/usr.sbin/radiusd/radiusd_standard/../radiusd_standard.c
Warning:line 150, column 15
Access to field 'type' results in a dereference of a null pointer (loaded from variable 'attr')

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple amd64-unknown-openbsd7.4 -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name radiusd_standard.c -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 -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -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_standard -resource-dir /usr/local/llvm16/lib/clang/16 -I /usr/src/usr.sbin/radiusd/radiusd_standard/.. -internal-isystem /usr/local/llvm16/lib/clang/16/include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -fdebug-compilation-dir=/usr/src/usr.sbin/radiusd/radiusd_standard -ferror-limit 19 -fwrapv -D_RET_PROTECTOR -ret-protector -fcf-protection=branch -fno-jump-tables -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/scan/2024-01-11-140451-98009-1 -x c /usr/src/usr.sbin/radiusd/radiusd_standard/../radiusd_standard.c
1/* $OpenBSD: radiusd_standard.c,v 1.2 2024/01/08 04:16:48 yasuoka Exp $ */
2
3/*
4 * Copyright (c) 2013, 2023 Internet Initiative Japan Inc.
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#include <sys/types.h>
19#include <sys/queue.h>
20
21#include <err.h>
22#include <errno(*__errno()).h>
23#include <radius.h>
24#include <stdbool.h>
25#include <stdint.h>
26#include <stdio.h>
27#include <stdlib.h>
28#include <string.h>
29#include <syslog.h>
30#include <unistd.h>
31
32#include "radiusd.h"
33#include "radiusd_module.h"
34
35TAILQ_HEAD(attrs,attr)struct attrs { struct attr *tqh_first; struct attr **tqh_last
; }
;
36
37struct attr {
38 uint8_t type;
39 uint32_t vendor;
40 uint32_t vtype;
41 TAILQ_ENTRY(attr)struct { struct attr *tqe_next; struct attr **tqe_prev; } next;
42};
43
44struct module_standard {
45 struct module_base *base;
46 bool_Bool strip_atmark_realm;
47 bool_Bool strip_nt_domain;
48 struct attrs remove_reqattrs;
49 struct attrs remove_resattrs;
50};
51
52static void module_standard_config_set(void *, const char *, int,
53 char * const *);
54static void module_standard_reqdeco(void *, u_int, const u_char *, size_t);
55static void module_standard_resdeco(void *, u_int, const u_char *, size_t,
56 const u_char *, size_t);
57
58int
59main(int argc, char *argv[])
60{
61 struct module_standard module_standard;
62 struct module_handlers handlers = {
63 .config_set = module_standard_config_set,
64 .request_decoration = module_standard_reqdeco,
65 .response_decoration = module_standard_resdeco
66 };
67 struct attr *attr;
68
69 memset(&module_standard, 0, sizeof(module_standard));
70 TAILQ_INIT(&module_standard.remove_reqattrs)do { (&module_standard.remove_reqattrs)->tqh_first = (
(void *)0); (&module_standard.remove_reqattrs)->tqh_last
= &(&module_standard.remove_reqattrs)->tqh_first;
} while (0)
;
71 TAILQ_INIT(&module_standard.remove_resattrs)do { (&module_standard.remove_resattrs)->tqh_first = (
(void *)0); (&module_standard.remove_resattrs)->tqh_last
= &(&module_standard.remove_resattrs)->tqh_first;
} while (0)
;
72
73 if ((module_standard.base = module_create(
74 STDIN_FILENO0, &module_standard, &handlers)) == NULL((void *)0))
75 err(1, "Could not create a module instance");
76
77 module_drop_privilege(module_standard.base);
78 if (pledge("stdio", NULL((void *)0)) == -1)
79 err(1, "pledge");
80
81 module_load(module_standard.base);
82
83 openlog(NULL((void *)0), LOG_PID0x01, LOG_DAEMON(3<<3));
84
85 while (module_run(module_standard.base) == 0)
86 ;
87
88 module_destroy(module_standard.base);
89 while ((attr = TAILQ_FIRST(&module_standard.remove_reqattrs)((&module_standard.remove_reqattrs)->tqh_first)) != NULL((void *)0)) {
90 TAILQ_REMOVE(&module_standard.remove_reqattrs, attr, next)do { if (((attr)->next.tqe_next) != ((void *)0)) (attr)->
next.tqe_next->next.tqe_prev = (attr)->next.tqe_prev; else
(&module_standard.remove_reqattrs)->tqh_last = (attr)
->next.tqe_prev; *(attr)->next.tqe_prev = (attr)->next
.tqe_next; ; ; } while (0)
;
91 freezero(attr, sizeof(struct attr));
92 }
93 while ((attr = TAILQ_FIRST(&module_standard.remove_resattrs)((&module_standard.remove_resattrs)->tqh_first)) != NULL((void *)0)) {
94 TAILQ_REMOVE(&module_standard.remove_resattrs, attr, next)do { if (((attr)->next.tqe_next) != ((void *)0)) (attr)->
next.tqe_next->next.tqe_prev = (attr)->next.tqe_prev; else
(&module_standard.remove_resattrs)->tqh_last = (attr)
->next.tqe_prev; *(attr)->next.tqe_prev = (attr)->next
.tqe_next; ; ; } while (0)
;
95 freezero(attr, sizeof(struct attr));
96 }
97
98 exit(EXIT_SUCCESS0);
99}
100
101static void
102module_standard_config_set(void *ctx, const char *name, int argc,
103 char * const * argv)
104{
105 struct module_standard *module = ctx;
106 struct attr *attr;
107 const char *errmsg = "none";
108 const char *errstr;
109
110 if (strcmp(name, "strip-atmark-realm") == 0) {
1
Assuming the condition is false
2
Taking false branch
111 SYNTAX_ASSERT(argc == 1,do { if (!(argc == 1)) { errmsg = ("`strip-atmark-realm' must have only one argment"
); goto syntax_error; } } while (0 )
112 "`strip-atmark-realm' must have only one argment")do { if (!(argc == 1)) { errmsg = ("`strip-atmark-realm' must have only one argment"
); goto syntax_error; } } while (0 )
;
113 if (strcmp(argv[0], "true") == 0)
114 module->strip_atmark_realm = true1;
115 else if (strcmp(argv[0], "false") == 0)
116 module->strip_atmark_realm = false0;
117 else
118 SYNTAX_ASSERT(0,do { if (!(0)) { errmsg = ("`strip-atmark-realm' must `true' or `false'"
); goto syntax_error; } } while (0 )
119 "`strip-atmark-realm' must `true' or `false'")do { if (!(0)) { errmsg = ("`strip-atmark-realm' must `true' or `false'"
); goto syntax_error; } } while (0 )
;
120 } else if (strcmp(name, "strip-nt-domain") == 0) {
3
Assuming the condition is false
121 SYNTAX_ASSERT(argc == 1,do { if (!(argc == 1)) { errmsg = ("`strip-nt-domain' must have only one argment"
); goto syntax_error; } } while (0 )
122 "`strip-nt-domain' must have only one argment")do { if (!(argc == 1)) { errmsg = ("`strip-nt-domain' must have only one argment"
); goto syntax_error; } } while (0 )
;
123 if (strcmp(argv[0], "true") == 0)
124 module->strip_nt_domain = true1;
125 else if (strcmp(argv[0], "false") == 0)
126 module->strip_nt_domain = false0;
127 else
128 SYNTAX_ASSERT(0,do { if (!(0)) { errmsg = ("`strip-nt-domain' must `true' or `false'"
); goto syntax_error; } } while (0 )
129 "`strip-nt-domain' must `true' or `false'")do { if (!(0)) { errmsg = ("`strip-nt-domain' must `true' or `false'"
); goto syntax_error; } } while (0 )
;
130 } else if (strcmp(name, "remove-request-attribute") == 0 ||
131 strcmp(name, "remove-response-attribute") == 0) {
132 struct attrs *attrs;
133
134 if (strcmp(name, "remove-request-attribute") == 0) {
135 SYNTAX_ASSERT(argc == 1 || argc == 2,do { if (!(argc == 1 || argc == 2)) { errmsg = ("`remove-request-attribute' must have one or two "
"argment"); goto syntax_error; } } while (0 )
4
Taking true branch
5
Assuming 'argc' is equal to 1
6
Taking false branch
7
Loop condition is false. Exiting loop
136 "`remove-request-attribute' must have one or two "do { if (!(argc == 1 || argc == 2)) { errmsg = ("`remove-request-attribute' must have one or two "
"argment"); goto syntax_error; } } while (0 )
137 "argment")do { if (!(argc == 1 || argc == 2)) { errmsg = ("`remove-request-attribute' must have one or two "
"argment"); goto syntax_error; } } while (0 )
;
138 attrs = &module->remove_reqattrs;
139 } else {
140 SYNTAX_ASSERT(argc == 1 || argc == 2,do { if (!(argc == 1 || argc == 2)) { errmsg = ("`remove-response-attribute' must have one or two "
"argment"); goto syntax_error; } } while (0 )
141 "`remove-response-attribute' must have one or two "do { if (!(argc == 1 || argc == 2)) { errmsg = ("`remove-response-attribute' must have one or two "
"argment"); goto syntax_error; } } while (0 )
142 "argment")do { if (!(argc == 1 || argc == 2)) { errmsg = ("`remove-response-attribute' must have one or two "
"argment"); goto syntax_error; } } while (0 )
;
143 attrs = &module->remove_resattrs;
144 }
145 if ((attr = calloc(1, sizeof(struct attr))) == NULL((void *)0)) {
8
Value assigned to 'attr'
9
Assuming pointer value is null
10
Taking true branch
146 module_send_message(module->base, IMSG_NG,
147 "Out of memory: %s", strerror(errno(*__errno())));
148 }
149 if (argc
10.1
'argc' is equal to 1
== 1) {
11
Taking true branch
150 attr->type = strtonum(argv[0], 0, 255, &errstr);
12
Access to field 'type' results in a dereference of a null pointer (loaded from variable 'attr')
151 if (errstr == NULL((void *)0) &&
152 attr->type != RADIUS_TYPE_VENDOR_SPECIFIC26) {
153 TAILQ_INSERT_TAIL(attrs, attr, next)do { (attr)->next.tqe_next = ((void *)0); (attr)->next.
tqe_prev = (attrs)->tqh_last; *(attrs)->tqh_last = (attr
); (attrs)->tqh_last = &(attr)->next.tqe_next; } while
(0)
;
154 attr = NULL((void *)0);
155 }
156 } else {
157 attr->type = RADIUS_TYPE_VENDOR_SPECIFIC26;
158 attr->vendor = strtonum(argv[0], 0, UINT32_MAX0xffffffffU,
159 &errstr);
160 if (errstr == NULL((void *)0))
161 attr->vtype = strtonum(argv[1], 0, 255,
162 &errstr);
163 if (errstr == NULL((void *)0)) {
164 TAILQ_INSERT_TAIL(attrs, attr, next)do { (attr)->next.tqe_next = ((void *)0); (attr)->next.
tqe_prev = (attrs)->tqh_last; *(attrs)->tqh_last = (attr
); (attrs)->tqh_last = &(attr)->next.tqe_next; } while
(0)
;
165 attr = NULL((void *)0);
166 }
167 }
168 freezero(attr, sizeof(struct attr));
169 if (strcmp(name, "remove-request-attribute") == 0)
170 SYNTAX_ASSERT(attr == NULL,do { if (!(attr == ((void *)0))) { errmsg = ("wrong number for `remove-request-attribute`"
); goto syntax_error; } } while (0 )
171 "wrong number for `remove-request-attribute`")do { if (!(attr == ((void *)0))) { errmsg = ("wrong number for `remove-request-attribute`"
); goto syntax_error; } } while (0 )
;
172 else
173 SYNTAX_ASSERT(attr == NULL,do { if (!(attr == ((void *)0))) { errmsg = ("wrong number for `remove-response-attribute`"
); goto syntax_error; } } while (0 )
174 "wrong number for `remove-response-attribute`")do { if (!(attr == ((void *)0))) { errmsg = ("wrong number for `remove-response-attribute`"
); goto syntax_error; } } while (0 )
;
175 } else if (strncmp(name, "_", 1) == 0)
176 /* nothing */; /* ignore all internal messages */
177 else {
178 module_send_message(module->base, IMSG_NG,
179 "Unknown config parameter name `%s'", name);
180 return;
181 }
182 module_send_message(module->base, IMSG_OK, NULL((void *)0));
183 return;
184
185 syntax_error:
186 module_send_message(module->base, IMSG_NG, "%s", errmsg);
187}
188
189/* request message decoration */
190static void
191module_standard_reqdeco(void *ctx, u_int q_id, const u_char *pkt, size_t pktlen)
192{
193 struct module_standard *module = ctx;
194 RADIUS_PACKET *radpkt = NULL((void *)0);
195 int changed = 0;
196 char *ch, *username, buf[256];
197 struct attr *attr;
198
199 if (module->strip_atmark_realm || module->strip_nt_domain) {
200 if ((radpkt = radius_convert_packet(pkt, pktlen)) == NULL((void *)0)) {
201 syslog(LOG_ERR3,
202 "%s: radius_convert_packet() failed: %m", __func__);
203 module_stop(module->base);
204 return;
205 }
206
207 username = buf;
208 if (radius_get_string_attr(radpkt, RADIUS_TYPE_USER_NAME1,
209 username, sizeof(buf)) != 0) {
210 syslog(LOG_WARNING4,
211 "standard: q=%u could not get User-Name attribute",
212 q_id);
213 goto skip;
214 }
215
216 if (module->strip_atmark_realm &&
217 (ch = strrchr(username, '@')) != NULL((void *)0)) {
218 *ch = '\0';
219 changed++;
220 }
221 if (module->strip_nt_domain &&
222 (ch = strchr(username, '\\')) != NULL((void *)0)) {
223 username = ch + 1;
224 changed++;
225 }
226 if (changed > 0) {
227 radius_del_attr_all(radpkt, RADIUS_TYPE_USER_NAME1);
228 radius_put_string_attr(radpkt,
229 RADIUS_TYPE_USER_NAME1, username);
230 }
231 }
232 skip:
233 TAILQ_FOREACH(attr, &module->remove_reqattrs, next)for((attr) = ((&module->remove_reqattrs)->tqh_first
); (attr) != ((void *)0); (attr) = ((attr)->next.tqe_next)
)
{
234 if (radpkt == NULL((void *)0) &&
235 (radpkt = radius_convert_packet(pkt, pktlen)) == NULL((void *)0)) {
236 syslog(LOG_ERR3,
237 "%s: radius_convert_packet() failed: %m", __func__);
238 module_stop(module->base);
239 return;
240 }
241 if (attr->type != RADIUS_TYPE_VENDOR_SPECIFIC26)
242 radius_del_attr_all(radpkt, attr->type);
243 else
244 radius_del_vs_attr_all(radpkt, attr->vendor,
245 attr->vtype);
246 }
247 if (radpkt == NULL((void *)0)) {
248 pkt = NULL((void *)0);
249 pktlen = 0;
250 } else {
251 pkt = radius_get_data(radpkt);
252 pktlen = radius_get_length(radpkt);
253 }
254 if (module_reqdeco_done(module->base, q_id, pkt, pktlen) == -1) {
255 syslog(LOG_ERR3, "%s: module_reqdeco_done() failed: %m",
256 __func__);
257 module_stop(module->base);
258 }
259 if (radpkt != NULL((void *)0))
260 radius_delete_packet(radpkt);
261}
262
263/* response message decoration */
264static void
265module_standard_resdeco(void *ctx, u_int q_id, const u_char *req, size_t reqlen,
266 const u_char *res, size_t reslen)
267{
268 struct module_standard *module = ctx;
269 RADIUS_PACKET *radres = NULL((void *)0);
270 struct attr *attr;
271
272 TAILQ_FOREACH(attr, &module->remove_reqattrs, next)for((attr) = ((&module->remove_reqattrs)->tqh_first
); (attr) != ((void *)0); (attr) = ((attr)->next.tqe_next)
)
{
273 if (radres == NULL((void *)0) &&
274 (radres = radius_convert_packet(res, reslen)) == NULL((void *)0)) {
275 syslog(LOG_ERR3,
276 "%s: radius_convert_packet() failed: %m", __func__);
277 module_stop(module->base);
278 return;
279 }
280 if (attr->type != RADIUS_TYPE_VENDOR_SPECIFIC26)
281 radius_del_attr_all(radres, attr->type);
282 else
283 radius_del_vs_attr_all(radres, attr->vendor,
284 attr->vtype);
285 }
286 if (radres == NULL((void *)0)) {
287 res = NULL((void *)0);
288 reslen = 0;
289 } else {
290 res = radius_get_data(radres);
291 reslen = radius_get_length(radres);
292 }
293 if (module_resdeco_done(module->base, q_id, res, reslen) == -1) {
294 syslog(LOG_ERR3, "%s: module_resdeco_done() failed: %m",
295 __func__);
296 module_stop(module->base);
297 }
298 if (radres != NULL((void *)0))
299 radius_delete_packet(radres);
300}