clang -cc1 -cc1 -triple amd64-unknown-openbsd7.4 -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name bootp.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/dhcpd/obj -resource-dir /usr/local/llvm16/lib/clang/16 -internal-isystem /usr/local/llvm16/lib/clang/16/include -internal-externc-isystem /usr/include -O2 -fdebug-compilation-dir=/usr/src/usr.sbin/dhcpd/obj -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/dhcpd/bootp.c
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | |
15 | |
16 | |
17 | |
18 | |
19 | |
20 | |
21 | |
22 | |
23 | |
24 | |
25 | |
26 | |
27 | |
28 | |
29 | |
30 | |
31 | |
32 | |
33 | |
34 | |
35 | |
36 | |
37 | |
38 | |
39 | |
40 | |
41 | |
42 | |
43 | |
44 | |
45 | #include <sys/socket.h> |
46 | |
47 | #include <arpa/inet.h> |
48 | |
49 | #include <net/if.h> |
50 | |
51 | #include <netinet/in.h> |
52 | |
53 | #include <errno.h> |
54 | #include <stdio.h> |
55 | #include <string.h> |
56 | |
57 | #include "dhcp.h" |
58 | #include "tree.h" |
59 | #include "dhcpd.h" |
60 | #include "log.h" |
61 | |
62 | void |
63 | bootp(struct packet *packet) |
64 | { |
65 | struct host_decl *hp, *host = NULL; |
66 | struct packet outgoing; |
67 | struct dhcp_packet raw; |
68 | struct sockaddr_in to; |
69 | struct in_addr from; |
70 | struct tree_cache *options[256]; |
71 | struct shared_network *s; |
72 | struct subnet *subnet = NULL; |
73 | struct lease *lease; |
74 | struct iaddr ip_address; |
75 | int i; |
76 | |
77 | if (packet->raw->op != BOOTREQUEST) |
| 1 | Assuming field 'op' is equal to BOOTREQUEST | |
|
| |
78 | return; |
79 | |
80 | log_info("BOOTREQUEST from %s via %s%s", |
81 | print_hw_addr(packet->raw->htype, packet->raw->hlen, |
82 | packet->raw->chaddr), packet->raw->giaddr.s_addr ? |
| 3 | | Assuming field 's_addr' is 0 | |
|
| |
83 | inet_ntoa(packet->raw->giaddr) : packet->interface->name, |
84 | packet->options_valid ? "" : " (non-rfc1048)"); |
| 5 | | Assuming field 'options_valid' is 0 | |
|
| |
85 | |
86 | if (!locate_network(packet)) |
| 7 | | Assuming the condition is false | |
|
| |
87 | return; |
88 | |
89 | hp = find_hosts_by_haddr(packet->raw->htype, packet->raw->chaddr, |
90 | packet->raw->hlen); |
91 | |
92 | s = packet->shared_network; |
93 | lease = find_lease(packet, s, 0); |
94 | |
95 | |
96 | |
97 | |
98 | |
99 | if (hp) |
| 9 | | Assuming 'hp' is non-null | |
|
| |
100 | subnet = find_host_for_network(&hp, &ip_address, s); |
| |
101 | |
102 | if (!subnet) { |
| 12 | | Assuming 'subnet' is non-null | |
|
103 | |
104 | |
105 | |
106 | |
107 | |
108 | |
109 | if (hp) |
110 | for (; hp; hp = hp->n_ipaddr) |
111 | if (!hp->fixed_addr) { |
112 | host = hp; |
113 | break; |
114 | } |
115 | |
116 | if (host && (!host->group->allow_booting)) { |
117 | log_info("Ignoring excluded BOOTP client %s", |
118 | host->name ? host->name : |
119 | print_hw_addr (packet->raw->htype, |
120 | packet->raw->hlen, packet->raw->chaddr)); |
121 | return; |
122 | } |
123 | |
124 | if (host && (!host->group->allow_bootp)) { |
125 | log_info("Ignoring BOOTP request from client %s", |
126 | host->name ? host->name : |
127 | print_hw_addr(packet->raw->htype, |
128 | packet->raw->hlen, packet->raw->chaddr)); |
129 | return; |
130 | } |
131 | |
132 | |
133 | |
134 | |
135 | |
136 | if (!host && !(s->group->boot_unknown_clients)) { |
137 | log_info("Ignoring unknown BOOTP client %s via %s", |
138 | print_hw_addr(packet->raw->htype, |
139 | packet->raw->hlen, packet->raw->chaddr), |
140 | packet->raw->giaddr.s_addr ? |
141 | inet_ntoa(packet->raw->giaddr) : |
142 | packet->interface->name); |
143 | return; |
144 | } |
145 | |
146 | |
147 | |
148 | |
149 | |
150 | if (!host && !(s->group->allow_bootp)) { |
151 | log_info("Ignoring BOOTP request from client %s via " |
152 | "%s", print_hw_addr(packet->raw->htype, |
153 | packet->raw->hlen, packet->raw->chaddr), |
154 | packet->raw->giaddr.s_addr ? |
155 | inet_ntoa(packet->raw->giaddr) : |
156 | packet->interface->name); |
157 | return; |
158 | } |
159 | |
160 | |
161 | |
162 | |
163 | |
164 | |
165 | if (!(s->group->dynamic_bootp)) { |
166 | lose: |
167 | log_info("No applicable record for BOOTP host %s via " |
168 | "%s", print_hw_addr(packet->raw->htype, |
169 | packet->raw->hlen, packet->raw->chaddr), |
170 | packet->raw->giaddr.s_addr ? |
171 | inet_ntoa(packet->raw->giaddr) : |
172 | packet->interface->name); |
173 | return; |
174 | } |
175 | |
176 | |
177 | |
178 | |
179 | |
180 | if (lease) { |
181 | |
182 | |
183 | |
184 | if ((lease->flags & DYNAMIC_BOOTP_OK)) { |
185 | |
186 | |
187 | |
188 | |
189 | |
190 | if (!(lease->flags & BOOTP_LEASE)) |
191 | release_lease(lease); |
192 | |
193 | lease->host = host; |
194 | ack_lease(packet, lease, 0, 0); |
195 | return; |
196 | } |
197 | |
198 | |
199 | |
200 | |
201 | |
202 | release_lease(lease); |
203 | } |
204 | |
205 | |
206 | |
207 | |
208 | |
209 | for (lease = s->last_lease; |
210 | lease && lease->ends <= cur_time; |
211 | lease = lease->prev) { |
212 | if ((lease->flags & DYNAMIC_BOOTP_OK)) { |
213 | lease->host = host; |
214 | ack_lease(packet, lease, 0, 0); |
215 | return; |
216 | } |
217 | } |
218 | goto lose; |
219 | } |
220 | |
221 | |
222 | if (hp && (!hp->group->allow_booting)) { |
| |
223 | log_info("Ignoring excluded BOOTP client %s", hp->name); |
224 | return; |
225 | } |
226 | |
227 | |
228 | if (hp && (!hp->group->allow_bootp)) { |
229 | log_info("Ignoring BOOTP request from client %s", hp->name); |
230 | return; |
231 | } |
232 | |
233 | |
234 | memset(&outgoing, 0, sizeof outgoing); |
235 | memset(&raw, 0, sizeof raw); |
236 | outgoing.raw = &raw; |
237 | |
238 | |
239 | |
240 | |
241 | |
242 | if (!packet->options_valid && !subnet->group->always_reply_rfc1048 && |
| 14 | | Assuming field 'options_valid' is 0 | |
|
| 15 | | Assuming field 'always_reply_rfc1048' is 0 | |
|
243 | (!hp || !hp->group->always_reply_rfc1048)) { |
244 | memcpy(outgoing.raw->options, packet->raw->options, |
245 | DHCP_OPTION_LEN); |
246 | outgoing.packet_length = BOOTP_MIN_LEN; |
247 | } else { |
248 | struct tree_cache netmask_tree; |
249 | |
250 | |
251 | |
252 | |
253 | |
254 | |
255 | |
256 | memcpy(options, subnet->group->options, sizeof(options)); |
257 | |
258 | for (i = 0; i < 256; i++) |
259 | if (hp->group->options[i]) |
260 | options[i] = hp->group->options[i]; |
261 | |
262 | |
263 | |
264 | |
265 | |
266 | if (!options[DHO_SUBNET_MASK]) { |
267 | options[DHO_SUBNET_MASK] = &netmask_tree; |
268 | netmask_tree.flags = TC_TEMPORARY; |
269 | netmask_tree.value = lease->subnet->netmask.iabuf; |
270 | netmask_tree.len = lease->subnet->netmask.len; |
271 | netmask_tree.buf_size = lease->subnet->netmask.len; |
272 | netmask_tree.timeout = -1; |
273 | netmask_tree.tree = NULL; |
274 | } |
275 | |
276 | |
277 | |
278 | |
279 | |
280 | |
281 | outgoing.packet_length = cons_options(packet, outgoing.raw, |
282 | 0, options, 0, 0, 1, NULL, 0); |
283 | |
284 | if (outgoing.packet_length < BOOTP_MIN_LEN) |
285 | outgoing.packet_length = BOOTP_MIN_LEN; |
286 | } |
287 | |
288 | |
289 | raw.op = BOOTREPLY; |
290 | raw.htype = packet->raw->htype; |
291 | raw.hlen = packet->raw->hlen; |
292 | memcpy(raw.chaddr, packet->raw->chaddr, sizeof(raw.chaddr)); |
293 | raw.hops = packet->raw->hops; |
294 | raw.xid = packet->raw->xid; |
295 | raw.secs = packet->raw->secs; |
296 | raw.flags = packet->raw->flags; |
297 | raw.ciaddr = packet->raw->ciaddr; |
298 | memcpy(&raw.yiaddr, ip_address.iabuf, sizeof(raw.yiaddr)); |
299 | |
300 | |
301 | if (hp && hp->group->next_server.len) |
302 | memcpy(&raw.siaddr, hp->group->next_server.iabuf, 4); |
303 | else if (subnet->group->next_server.len) |
| 16 | | Assuming field 'len' is not equal to 0 | |
|
| |
304 | memcpy(&raw.siaddr, subnet->group->next_server.iabuf, 4); |
305 | else if (subnet->interface_address.len) |
306 | memcpy(&raw.siaddr, subnet->interface_address.iabuf, 4); |
307 | else |
308 | raw.siaddr = packet->interface->primary_address; |
309 | |
310 | raw.giaddr = packet->raw->giaddr; |
311 | if (hp->group->server_name) |
| 18 | | Access to field 'group' results in a dereference of a null pointer (loaded from variable 'hp') |
|
312 | strncpy(raw.sname, hp->group->server_name, sizeof(raw.sname)); |
313 | else if (subnet->group->server_name) |
314 | strncpy(raw.sname, subnet->group->server_name, |
315 | sizeof(raw.sname)); |
316 | |
317 | if (hp->group->filename) |
318 | strncpy(raw.file, hp->group->filename, sizeof(raw.file)); |
319 | else if (subnet->group->filename) |
320 | strncpy(raw.file, subnet->group->filename, sizeof(raw.file)); |
321 | else |
322 | memcpy(raw.file, packet->raw->file, sizeof(raw.file)); |
323 | |
324 | from = packet->interface->primary_address; |
325 | |
326 | |
327 | log_info("BOOTREPLY for %s to %s (%s) via %s", piaddr(ip_address), |
328 | hp->name, print_hw_addr(packet->raw->htype, packet->raw->hlen, |
329 | packet->raw->chaddr), packet->raw->giaddr.s_addr ? |
330 | inet_ntoa(packet->raw->giaddr) : packet->interface->name); |
331 | |
332 | |
333 | memset(&to, 0, sizeof(to)); |
334 | to.sin_family = AF_INET; |
335 | #ifdef HAVE_SA_LEN |
336 | to.sin_len = sizeof(to); |
337 | #endif |
338 | |
339 | |
340 | if (raw.giaddr.s_addr) { |
341 | to.sin_addr = raw.giaddr; |
342 | to.sin_port = server_port; |
343 | |
344 | (void) packet->interface->send_packet(packet->interface, &raw, |
345 | outgoing.packet_length, from, &to, packet->haddr); |
346 | return; |
347 | } |
348 | |
349 | |
350 | |
351 | |
352 | |
353 | |
354 | else if (!(raw.flags & htons(BOOTP_BROADCAST))) { |
355 | to.sin_addr = raw.yiaddr; |
356 | to.sin_port = client_port; |
357 | } else { |
358 | |
359 | to.sin_addr.s_addr = INADDR_BROADCAST; |
360 | to.sin_port = client_port; |
361 | } |
362 | |
363 | errno = 0; |
364 | (void) packet->interface->send_packet(packet->interface, &raw, |
365 | outgoing.packet_length, from, &to, packet->haddr); |
366 | } |