]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/network/networkd-dhcp-common.c
network: fix double free()
[thirdparty/systemd.git] / src / network / networkd-dhcp-common.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2
3 #include "dhcp-internal.h"
4 #include "escape.h"
5 #include "in-addr-util.h"
6 #include "networkd-dhcp-common.h"
7 #include "networkd-network.h"
8 #include "parse-util.h"
9 #include "string-table.h"
10 #include "strv.h"
11
12 int config_parse_dhcp(
13 const char* unit,
14 const char *filename,
15 unsigned line,
16 const char *section,
17 unsigned section_line,
18 const char *lvalue,
19 int ltype,
20 const char *rvalue,
21 void *data,
22 void *userdata) {
23
24 AddressFamily *dhcp = data, s;
25
26 assert(filename);
27 assert(lvalue);
28 assert(rvalue);
29 assert(data);
30
31 /* Note that this is mostly like
32 * config_parse_address_family(), except that it
33 * understands some old names for the enum values */
34
35 s = address_family_from_string(rvalue);
36 if (s < 0) {
37
38 /* Previously, we had a slightly different enum here,
39 * support its values for compatibility. */
40
41 if (streq(rvalue, "none"))
42 s = ADDRESS_FAMILY_NO;
43 else if (streq(rvalue, "v4"))
44 s = ADDRESS_FAMILY_IPV4;
45 else if (streq(rvalue, "v6"))
46 s = ADDRESS_FAMILY_IPV6;
47 else if (streq(rvalue, "both"))
48 s = ADDRESS_FAMILY_YES;
49 else {
50 log_syntax(unit, LOG_ERR, filename, line, 0,
51 "Failed to parse DHCP option, ignoring: %s", rvalue);
52 return 0;
53 }
54
55 log_syntax(unit, LOG_WARNING, filename, line, 0,
56 "DHCP=%s is deprecated, please use DHCP=%s instead.",
57 rvalue, address_family_to_string(s));
58 }
59
60 *dhcp = s;
61 return 0;
62 }
63
64 int config_parse_dhcp_use_dns(
65 const char* unit,
66 const char *filename,
67 unsigned line,
68 const char *section,
69 unsigned section_line,
70 const char *lvalue,
71 int ltype,
72 const char *rvalue,
73 void *data,
74 void *userdata) {
75
76 Network *network = data;
77 int r;
78
79 assert(filename);
80 assert(lvalue);
81 assert(rvalue);
82 assert(data);
83
84 r = parse_boolean(rvalue);
85 if (r < 0) {
86 log_syntax(unit, LOG_ERR, filename, line, r,
87 "Failed to parse UseDNS=%s, ignoring assignment: %m", rvalue);
88 return 0;
89 }
90
91 network->dhcp_use_dns = r;
92 network->dhcp6_use_dns = r;
93
94 return 0;
95 }
96
97 int config_parse_dhcp_use_sip(
98 const char* unit,
99 const char *filename,
100 unsigned line,
101 const char *section,
102 unsigned section_line,
103 const char *lvalue,
104 int ltype,
105 const char *rvalue,
106 void *data,
107 void *userdata) {
108
109 Network *network = data;
110 int r;
111
112 assert(filename);
113 assert(lvalue);
114 assert(rvalue);
115 assert(data);
116
117 r = parse_boolean(rvalue);
118 if (r < 0) {
119 log_syntax(unit, LOG_ERR, filename, line, r,
120 "Failed to parse UseSIP=%s, ignoring assignment: %m", rvalue);
121 return 0;
122 }
123
124 network->dhcp_use_sip = r;
125
126 return 0;
127 }
128
129 int config_parse_dhcp_use_ntp(
130 const char* unit,
131 const char *filename,
132 unsigned line,
133 const char *section,
134 unsigned section_line,
135 const char *lvalue,
136 int ltype,
137 const char *rvalue,
138 void *data,
139 void *userdata) {
140
141 Network *network = data;
142 int r;
143
144 assert(filename);
145 assert(lvalue);
146 assert(rvalue);
147 assert(data);
148
149 r = parse_boolean(rvalue);
150 if (r < 0) {
151 log_syntax(unit, LOG_ERR, filename, line, r,
152 "Failed to parse UseNTP=%s, ignoring assignment: %m", rvalue);
153 return 0;
154 }
155
156 network->dhcp_use_ntp = r;
157 network->dhcp6_use_ntp = r;
158
159 return 0;
160 }
161
162 int config_parse_section_route_table(
163 const char *unit,
164 const char *filename,
165 unsigned line,
166 const char *section,
167 unsigned section_line,
168 const char *lvalue,
169 int ltype,
170 const char *rvalue,
171 void *data,
172 void *userdata) {
173
174 Network *network = data;
175 uint32_t rt;
176 int r;
177
178 assert(filename);
179 assert(lvalue);
180 assert(rvalue);
181 assert(data);
182
183 r = safe_atou32(rvalue, &rt);
184 if (r < 0) {
185 log_syntax(unit, LOG_ERR, filename, line, r,
186 "Failed to parse RouteTable=%s, ignoring assignment: %m", rvalue);
187 return 0;
188 }
189
190 if (STRPTR_IN_SET(section, "DHCP", "DHCPv4")) {
191 network->dhcp_route_table = rt;
192 network->dhcp_route_table_set = true;
193 } else { /* section is IPv6AcceptRA */
194 network->ipv6_accept_ra_route_table = rt;
195 network->ipv6_accept_ra_route_table_set = true;
196 }
197
198 return 0;
199 }
200
201 int config_parse_iaid(const char *unit,
202 const char *filename,
203 unsigned line,
204 const char *section,
205 unsigned section_line,
206 const char *lvalue,
207 int ltype,
208 const char *rvalue,
209 void *data,
210 void *userdata) {
211 Network *network = data;
212 uint32_t iaid;
213 int r;
214
215 assert(filename);
216 assert(lvalue);
217 assert(rvalue);
218 assert(network);
219
220 r = safe_atou32(rvalue, &iaid);
221 if (r < 0) {
222 log_syntax(unit, LOG_ERR, filename, line, r,
223 "Unable to read IAID, ignoring assignment: %s", rvalue);
224 return 0;
225 }
226
227 network->iaid = iaid;
228 network->iaid_set = true;
229
230 return 0;
231 }
232
233 int config_parse_dhcp6_pd_hint(
234 const char* unit,
235 const char *filename,
236 unsigned line,
237 const char *section,
238 unsigned section_line,
239 const char *lvalue,
240 int ltype,
241 const char *rvalue,
242 void *data,
243 void *userdata) {
244
245 Network *network = data;
246 int r;
247
248 assert(filename);
249 assert(lvalue);
250 assert(rvalue);
251 assert(data);
252
253 r = in_addr_prefix_from_string(rvalue, AF_INET6, (union in_addr_union *) &network->dhcp6_pd_address, &network->dhcp6_pd_length);
254 if (r < 0) {
255 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse PrefixDelegationHint=%s, ignoring assignment", rvalue);
256 return 0;
257 }
258
259 if (network->dhcp6_pd_length < 1 || network->dhcp6_pd_length > 128) {
260 log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid prefix length='%d', ignoring assignment", network->dhcp6_pd_length);
261 network->dhcp6_pd_length = 0;
262 return 0;
263 }
264
265 return 0;
266 }
267
268 int config_parse_dhcp_send_option(
269 const char *unit,
270 const char *filename,
271 unsigned line,
272 const char *section,
273 unsigned section_line,
274 const char *lvalue,
275 int ltype,
276 const char *rvalue,
277 void *data,
278 void *userdata) {
279
280 _cleanup_(sd_dhcp_option_unrefp) sd_dhcp_option *opt = NULL, *old = NULL;
281 _cleanup_free_ char *word = NULL, *q = NULL;
282 OrderedHashmap **options = userdata;
283 union in_addr_union addr;
284 DHCPOptionDataType type;
285 uint8_t u, uint8_data;
286 uint16_t uint16_data;
287 uint32_t uint32_data;
288 const void *udata;
289 const char *p;
290 ssize_t sz;
291 int r;
292
293 assert(filename);
294 assert(lvalue);
295 assert(rvalue);
296 assert(data);
297
298 if (isempty(rvalue)) {
299 *options = ordered_hashmap_free(*options);
300 return 0;
301 }
302
303 p = rvalue;
304 r = extract_first_word(&p, &word, ":", 0);
305 if (r == -ENOMEM)
306 return log_oom();
307 if (r <= 0) {
308 log_syntax(unit, LOG_ERR, filename, line, r,
309 "Invalid DHCP option, ignoring assignment: %s", rvalue);
310 return 0;
311 }
312
313 r = safe_atou8(word, &u);
314 if (r < 0) {
315 log_syntax(unit, LOG_ERR, filename, line, r,
316 "Invalid DHCP option, ignoring assignment: %s", rvalue);
317 return 0;
318 }
319 if (u < 1 || u >= 255) {
320 log_syntax(unit, LOG_ERR, filename, line, 0,
321 "Invalid DHCP option, valid range is 1-254, ignoring assignment: %s", rvalue);
322 return 0;
323 }
324
325 word = mfree(word);
326 r = extract_first_word(&p, &word, ":", 0);
327 if (r == -ENOMEM)
328 return log_oom();
329 if (r <= 0) {
330 log_syntax(unit, LOG_ERR, filename, line, r,
331 "Invalid DHCP option, ignoring assignment: %s", rvalue);
332 return 0;
333 }
334
335 type = dhcp_option_data_type_from_string(word);
336 if (type < 0) {
337 log_syntax(unit, LOG_ERR, filename, line, 0,
338 "Invalid DHCP option data type, ignoring assignment: %s", p);
339 return 0;
340 }
341
342 switch(type) {
343 case DHCP_OPTION_DATA_UINT8:{
344 r = safe_atou8(p, &uint8_data);
345 if (r < 0) {
346 log_syntax(unit, LOG_ERR, filename, line, r,
347 "Failed to parse DHCPv4 uint8 data, ignoring assignment: %s", p);
348 return 0;
349 }
350
351 udata = &uint8_data;
352 sz = sizeof(uint8_t);
353 break;
354 }
355 case DHCP_OPTION_DATA_UINT16:{
356 r = safe_atou16(p, &uint16_data);
357 if (r < 0) {
358 log_syntax(unit, LOG_ERR, filename, line, r,
359 "Failed to parse DHCPv4 uint16 data, ignoring assignment: %s", p);
360 return 0;
361 }
362
363 udata = &uint16_data;
364 sz = sizeof(uint16_t);
365 break;
366 }
367 case DHCP_OPTION_DATA_UINT32: {
368 r = safe_atou32(p, &uint32_data);
369 if (r < 0) {
370 log_syntax(unit, LOG_ERR, filename, line, r,
371 "Failed to parse DHCPv4 uint32 data, ignoring assignment: %s", p);
372 return 0;
373 }
374
375 udata = &uint32_data;
376 sz = sizeof(uint32_t);
377
378 break;
379 }
380 case DHCP_OPTION_DATA_IPV4ADDRESS: {
381 r = in_addr_from_string(AF_INET, p, &addr);
382 if (r < 0) {
383 log_syntax(unit, LOG_ERR, filename, line, r,
384 "Failed to parse DHCPv4 ipv4address data, ignoring assignment: %s", p);
385 return 0;
386 }
387
388 udata = &addr.in;
389 sz = sizeof(addr.in.s_addr);
390 break;
391 }
392 case DHCP_OPTION_DATA_STRING:
393 sz = cunescape(p, 0, &q);
394 if (sz < 0) {
395 log_syntax(unit, LOG_ERR, filename, line, sz,
396 "Failed to decode DHCPv4 option data, ignoring assignment: %s", p);
397 }
398
399 udata = q;
400 break;
401 default:
402 return -EINVAL;
403 }
404
405 r = sd_dhcp_option_new(u, udata, sz, &opt);
406 if (r < 0) {
407 log_syntax(unit, LOG_ERR, filename, line, r,
408 "Failed to store DHCPv4 option '%s', ignoring assignment: %m", rvalue);
409 return 0;
410 }
411
412 r = ordered_hashmap_ensure_allocated(options, &dhcp_option_hash_ops);
413 if (r < 0)
414 return log_oom();
415
416 /* Overwrite existing option */
417 old = ordered_hashmap_remove(*options, UINT_TO_PTR(u));
418 r = ordered_hashmap_put(*options, UINT_TO_PTR(u), opt);
419 if (r < 0) {
420 log_syntax(unit, LOG_ERR, filename, line, r,
421 "Failed to store DHCPv4 option '%s', ignoring assignment: %m", rvalue);
422 return 0;
423 }
424
425 TAKE_PTR(opt);
426 return 0;
427 }
428
429 DEFINE_CONFIG_PARSE_ENUM(config_parse_dhcp_use_domains, dhcp_use_domains, DHCPUseDomains,
430 "Failed to parse DHCP use domains setting");
431
432 static const char* const dhcp_use_domains_table[_DHCP_USE_DOMAINS_MAX] = {
433 [DHCP_USE_DOMAINS_NO] = "no",
434 [DHCP_USE_DOMAINS_ROUTE] = "route",
435 [DHCP_USE_DOMAINS_YES] = "yes",
436 };
437
438 DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(dhcp_use_domains, DHCPUseDomains, DHCP_USE_DOMAINS_YES);
439
440 static const char * const dhcp_option_data_type_table[_DHCP_OPTION_DATA_MAX] = {
441 [DHCP_OPTION_DATA_UINT8] = "uint8",
442 [DHCP_OPTION_DATA_UINT16] = "uint16",
443 [DHCP_OPTION_DATA_UINT32] = "uint32",
444 [DHCP_OPTION_DATA_STRING] = "string",
445 [DHCP_OPTION_DATA_IPV4ADDRESS] = "ipv4address",
446 };
447
448 DEFINE_STRING_TABLE_LOOKUP(dhcp_option_data_type, DHCPOptionDataType);