File: | src/sbin/isakmpd/isakmp_cfg.c |
Warning: | line 126, column 2 The left expression of the compound assignment is an uninitialized value. The computed value will also be garbage |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* $OpenBSD: isakmp_cfg.c,v 1.41 2018/01/15 09:54:48 mpi Exp $ */ | |||
2 | ||||
3 | /* | |||
4 | * Copyright (c) 2001 Niklas Hallqvist. All rights reserved. | |||
5 | * Copyright (c) 2002 Håkan Olsson. All rights reserved. | |||
6 | * | |||
7 | * Redistribution and use in source and binary forms, with or without | |||
8 | * modification, are permitted provided that the following conditions | |||
9 | * are met: | |||
10 | * 1. Redistributions of source code must retain the above copyright | |||
11 | * notice, this list of conditions and the following disclaimer. | |||
12 | * 2. Redistributions in binary form must reproduce the above copyright | |||
13 | * notice, this list of conditions and the following disclaimer in the | |||
14 | * documentation and/or other materials provided with the distribution. | |||
15 | * | |||
16 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | |||
17 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | |||
18 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | |||
19 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | |||
20 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | |||
21 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |||
22 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |||
23 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | |||
25 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |||
26 | */ | |||
27 | ||||
28 | /* | |||
29 | * This code was written under funding by Gatespace | |||
30 | * (http://www.gatespace.com/). | |||
31 | */ | |||
32 | ||||
33 | #include <sys/types.h> | |||
34 | #include <stdlib.h> | |||
35 | #include <netinet/in.h> | |||
36 | #include <arpa/inet.h> | |||
37 | #include <string.h> | |||
38 | #include <bitstring.h> | |||
39 | ||||
40 | #include "attribute.h" | |||
41 | #include "conf.h" | |||
42 | #include "exchange.h" | |||
43 | #include "hash.h" | |||
44 | #include "ipsec.h" | |||
45 | #include "isakmp_fld.h" | |||
46 | #include "isakmp_num.h" | |||
47 | #include "log.h" | |||
48 | #include "message.h" | |||
49 | #include "prf.h" | |||
50 | #include "sa.h" | |||
51 | #include "transport.h" | |||
52 | #include "util.h" | |||
53 | ||||
54 | /* | |||
55 | * Validation script used to test messages for correct content of | |||
56 | * payloads depending on the exchange type. | |||
57 | */ | |||
58 | int16_t script_transaction[] = { | |||
59 | ISAKMP_PAYLOAD_ATTRIBUTE14, /* Initiator -> responder. */ | |||
60 | EXCHANGE_SCRIPT_SWITCH-3, | |||
61 | ISAKMP_PAYLOAD_ATTRIBUTE14, /* Responder -> initiator. */ | |||
62 | EXCHANGE_SCRIPT_END-4 | |||
63 | }; | |||
64 | ||||
65 | static int cfg_decode_attribute(u_int16_t, u_int8_t *, u_int16_t, void *); | |||
66 | static int cfg_encode_attributes(struct isakmp_cfg_attr_head *, u_int32_t, | |||
67 | u_int32_t, char *, u_int8_t **, u_int16_t *); | |||
68 | static int cfg_initiator_send_ATTR(struct message *); | |||
69 | static int cfg_initiator_recv_ATTR(struct message *); | |||
70 | static int cfg_responder_recv_ATTR(struct message *); | |||
71 | static int cfg_responder_send_ATTR(struct message *); | |||
72 | ||||
73 | u_int8_t *cfg_add_hash(struct message *); | |||
74 | int cfg_finalize_hash(struct message *, u_int8_t *, u_int8_t *, | |||
75 | u_int16_t); | |||
76 | int cfg_verify_hash(struct message *); | |||
77 | ||||
78 | /* Server: SET/ACK Client; REQ/REPLY */ | |||
79 | int (*isakmp_cfg_initiator[]) (struct message *) = { | |||
80 | cfg_initiator_send_ATTR, | |||
81 | cfg_initiator_recv_ATTR | |||
82 | }; | |||
83 | ||||
84 | /* Server: REQ/REPLY Client: SET/ACK */ | |||
85 | int (*isakmp_cfg_responder[]) (struct message *) = { | |||
86 | cfg_responder_recv_ATTR, | |||
87 | cfg_responder_send_ATTR | |||
88 | }; | |||
89 | ||||
90 | /* | |||
91 | * When we are "the server", this starts SET/ACK mode | |||
92 | * When we are "the client", this starts REQ/REPLY mode | |||
93 | */ | |||
94 | static int | |||
95 | cfg_initiator_send_ATTR(struct message *msg) | |||
96 | { | |||
97 | struct sa *isakmp_sa = msg->isakmp_sa; | |||
98 | struct ipsec_exch *ie = msg->exchange->data; | |||
99 | u_int8_t *hashp = 0, *attrp, *attr; | |||
100 | size_t attrlen, off; | |||
101 | char *id_string, *cfg_mode, *field; | |||
102 | struct sockaddr *sa; | |||
103 | #define CFG_ATTR_BIT_MAX16 ISAKMP_CFG_ATTR_FUTURE_MIN16 /* XXX */ | |||
104 | bitstr_t bit_decl(attrbits, CFG_ATTR_BIT_MAX)((attrbits)[(((16) + 7) >> 3)]); | |||
105 | u_int16_t bit, length; | |||
106 | u_int32_t life; | |||
107 | ||||
108 | if (msg->exchange->phase == 2) { | |||
| ||||
109 | hashp = cfg_add_hash(msg); | |||
110 | if (!hashp) | |||
111 | return -1; | |||
112 | } | |||
113 | /* We initiated this exchange, check isakmp_sa for other side. */ | |||
114 | if (isakmp_sa->initiator) | |||
115 | id_string = ipsec_id_string(isakmp_sa->id_r, | |||
116 | isakmp_sa->id_r_len); | |||
117 | else | |||
118 | id_string = ipsec_id_string(isakmp_sa->id_i, | |||
119 | isakmp_sa->id_i_len); | |||
120 | if (!id_string) { | |||
121 | log_print("cfg_initiator_send_ATTR: cannot parse ID"); | |||
122 | goto fail; | |||
123 | } | |||
124 | /* Check for attribute list to send to the other side */ | |||
125 | attrlen = 0; | |||
126 | bit_nclear(attrbits, 0, CFG_ATTR_BIT_MAX - 1)do { register bitstr_t *__name = (attrbits); register int __start = (0), __stop = (16 - 1); while (__start <= __stop) { ((__name )[((__start) >> 3)] &= ~(1 << ((__start)& 0x7))); __start++; } } while(0); | |||
| ||||
127 | ||||
128 | cfg_mode = conf_get_str(id_string, "Mode"); | |||
129 | if (!cfg_mode || strcmp(cfg_mode, "SET") == 0) { | |||
130 | /* SET/ACK mode */ | |||
131 | ie->cfg_type = ISAKMP_CFG_SET3; | |||
132 | ||||
133 | LOG_DBG((LOG_NEGOTIATION, 10,log_debug (LOG_NEGOTIATION, 10, "cfg_initiator_send_ATTR: SET/ACK mode" ) | |||
134 | "cfg_initiator_send_ATTR: SET/ACK mode"))log_debug (LOG_NEGOTIATION, 10, "cfg_initiator_send_ATTR: SET/ACK mode" ); | |||
135 | ||||
136 | #define ATTRFIND(STR,ATTR4,LEN4,ATTR6,LEN6) do \ | |||
137 | { \ | |||
138 | if ((sa = conf_get_address (id_string, STR)) != NULL((void *)0)) \ | |||
139 | switch (sa->sa_family) { \ | |||
140 | case AF_INET2: \ | |||
141 | bit_set (attrbits, ATTR4)((attrbits)[((ATTR4) >> 3)] |= (1 << ((ATTR4)& 0x7))); \ | |||
142 | attrlen += ISAKMP_ATTR_SZ4 + LEN4; \ | |||
143 | break; \ | |||
144 | case AF_INET624: \ | |||
145 | bit_set (attrbits, ATTR6)((attrbits)[((ATTR6) >> 3)] |= (1 << ((ATTR6)& 0x7))); \ | |||
146 | attrlen += ISAKMP_ATTR_SZ4 + LEN6; \ | |||
147 | break; \ | |||
148 | default: \ | |||
149 | break; \ | |||
150 | } \ | |||
151 | free (sa); \ | |||
152 | } while (0) | |||
153 | ||||
154 | /* | |||
155 | * XXX We don't simultaneously support IPv4 and IPv6 | |||
156 | * addresses. | |||
157 | */ | |||
158 | ATTRFIND("Address", ISAKMP_CFG_ATTR_INTERNAL_IP4_ADDRESS1, 4, | |||
159 | ISAKMP_CFG_ATTR_INTERNAL_IP6_ADDRESS8, 16); | |||
160 | ATTRFIND("Netmask", ISAKMP_CFG_ATTR_INTERNAL_IP4_NETMASK2, 4, | |||
161 | ISAKMP_CFG_ATTR_INTERNAL_IP6_NETMASK9, 16); | |||
162 | ATTRFIND("Nameserver", ISAKMP_CFG_ATTR_INTERNAL_IP4_DNS3, 4, | |||
163 | ISAKMP_CFG_ATTR_INTERNAL_IP6_DNS10, 16); | |||
164 | ATTRFIND("WINS-server", ISAKMP_CFG_ATTR_INTERNAL_IP4_NBNS4, 4, | |||
165 | ISAKMP_CFG_ATTR_INTERNAL_IP6_NBNS11, 16); | |||
166 | ATTRFIND("DHCP-server", ISAKMP_CFG_ATTR_INTERNAL_IP4_DHCP6, 4, | |||
167 | ISAKMP_CFG_ATTR_INTERNAL_IP6_DHCP12, 16); | |||
168 | #ifdef notyet | |||
169 | ATTRFIND("Network", ISAKMP_CFG_ATTR_INTERNAL_IP4_SUBNET13, 8, | |||
170 | ISAKMP_CFG_ATTR_INTERNAL_IP6_SUBNET15, 17); | |||
171 | #endif | |||
172 | #undef ATTRFIND | |||
173 | ||||
174 | if (conf_get_str(id_string, "Lifetime")) { | |||
175 | bit_set(attrbits,((attrbits)[((5) >> 3)] |= (1 << ((5)&0x7))) | |||
176 | ISAKMP_CFG_ATTR_INTERNAL_ADDRESS_EXPIRY)((attrbits)[((5) >> 3)] |= (1 << ((5)&0x7))); | |||
177 | attrlen += ISAKMP_ATTR_SZ4 + 4; | |||
178 | } | |||
179 | } else { | |||
180 | struct conf_list *alist; | |||
181 | struct conf_list_node *anode; | |||
182 | ||||
183 | ie->cfg_type = ISAKMP_CFG_REQUEST1; | |||
184 | ||||
185 | LOG_DBG((LOG_NEGOTIATION, 10,log_debug (LOG_NEGOTIATION, 10, "cfg_initiator_send_ATTR: REQ/REPLY mode" ) | |||
186 | "cfg_initiator_send_ATTR: REQ/REPLY mode"))log_debug (LOG_NEGOTIATION, 10, "cfg_initiator_send_ATTR: REQ/REPLY mode" ); | |||
187 | ||||
188 | alist = conf_get_list(id_string, "Attributes"); | |||
189 | if (alist) { | |||
190 | for (anode = TAILQ_FIRST(&alist->fields)((&alist->fields)->tqh_first); anode; | |||
191 | anode = TAILQ_NEXT(anode, link)((anode)->link.tqe_next)) { | |||
192 | if (strcasecmp(anode->field, "Address") == 0) { | |||
193 | bit_set(attrbits, ISAKMP_CFG_ATTR_INTERNAL_IP4_ADDRESS)((attrbits)[((1) >> 3)] |= (1 << ((1)&0x7))); | |||
194 | bit_set(attrbits, ISAKMP_CFG_ATTR_INTERNAL_IP6_ADDRESS)((attrbits)[((8) >> 3)] |= (1 << ((8)&0x7))); | |||
195 | attrlen += ISAKMP_ATTR_SZ4 * 2; | |||
196 | } else if (strcasecmp(anode->field, "Netmask") | |||
197 | == 0) { | |||
198 | bit_set(attrbits, ISAKMP_CFG_ATTR_INTERNAL_IP4_NETMASK)((attrbits)[((2) >> 3)] |= (1 << ((2)&0x7))); | |||
199 | bit_set(attrbits, ISAKMP_CFG_ATTR_INTERNAL_IP6_NETMASK)((attrbits)[((9) >> 3)] |= (1 << ((9)&0x7))); | |||
200 | attrlen += ISAKMP_ATTR_SZ4 * 2; | |||
201 | } else if (strcasecmp(anode->field, | |||
202 | "Nameserver") == 0) { | |||
203 | bit_set(attrbits, ISAKMP_CFG_ATTR_INTERNAL_IP4_DNS)((attrbits)[((3) >> 3)] |= (1 << ((3)&0x7))); | |||
204 | bit_set(attrbits, ISAKMP_CFG_ATTR_INTERNAL_IP6_DNS)((attrbits)[((10) >> 3)] |= (1 << ((10)&0x7)) ); | |||
205 | attrlen += ISAKMP_ATTR_SZ4 * 2; | |||
206 | } else if (strcasecmp(anode->field, | |||
207 | "WINS-server") == 0) { | |||
208 | bit_set(attrbits, ISAKMP_CFG_ATTR_INTERNAL_IP4_NBNS)((attrbits)[((4) >> 3)] |= (1 << ((4)&0x7))); | |||
209 | bit_set(attrbits, ISAKMP_CFG_ATTR_INTERNAL_IP6_NBNS)((attrbits)[((11) >> 3)] |= (1 << ((11)&0x7)) ); | |||
210 | attrlen += ISAKMP_ATTR_SZ4 * 2; | |||
211 | } else if (strcasecmp(anode->field, | |||
212 | "DHCP-server") == 0) { | |||
213 | bit_set(attrbits, ISAKMP_CFG_ATTR_INTERNAL_IP4_DHCP)((attrbits)[((6) >> 3)] |= (1 << ((6)&0x7))); | |||
214 | bit_set(attrbits, ISAKMP_CFG_ATTR_INTERNAL_IP6_DHCP)((attrbits)[((12) >> 3)] |= (1 << ((12)&0x7)) ); | |||
215 | attrlen += ISAKMP_ATTR_SZ4 * 2; | |||
216 | } else if (strcasecmp(anode->field, | |||
217 | "Lifetime") == 0) { | |||
218 | bit_set(attrbits, ISAKMP_CFG_ATTR_INTERNAL_ADDRESS_EXPIRY)((attrbits)[((5) >> 3)] |= (1 << ((5)&0x7))); | |||
219 | attrlen += ISAKMP_ATTR_SZ4; | |||
220 | } else { | |||
221 | log_print("cfg_initiator_send_ATTR: " | |||
222 | "unknown attribute %.20s in " | |||
223 | "section [%s]", anode->field, | |||
224 | id_string); | |||
225 | } | |||
226 | } | |||
227 | ||||
228 | conf_free_list(alist); | |||
229 | } | |||
230 | } | |||
231 | ||||
232 | if (attrlen == 0) { | |||
233 | /* No data found. */ | |||
234 | log_print("cfg_initiator_send_ATTR: no IKECFG attributes " | |||
235 | "found for [%s]", id_string); | |||
236 | ||||
237 | /* | |||
238 | * We can continue, but this indicates a configuration error | |||
239 | * that the user probably will want to correct. | |||
240 | */ | |||
241 | free(id_string); | |||
242 | return 0; | |||
243 | } | |||
244 | attrlen += ISAKMP_ATTRIBUTE_SZ8; | |||
245 | attrp = calloc(1, attrlen); | |||
246 | if (!attrp) { | |||
247 | log_error("cfg_initiator_send_ATTR: calloc (1, %lu) failed", | |||
248 | (unsigned long)attrlen); | |||
249 | goto fail; | |||
250 | } | |||
251 | if (message_add_payload(msg, ISAKMP_PAYLOAD_ATTRIBUTE14, attrp, attrlen, | |||
252 | 1)) { | |||
253 | free(attrp); | |||
254 | goto fail; | |||
255 | } | |||
256 | SET_ISAKMP_ATTRIBUTE_TYPE(attrp, ie->cfg_type)field_set_num (isakmp_attribute_fld + 0, attrp, ie->cfg_type ); | |||
257 | arc4random_buf((u_int8_t *) & ie->cfg_id, sizeof ie->cfg_id); | |||
258 | SET_ISAKMP_ATTRIBUTE_ID(attrp, ie->cfg_id)field_set_num (isakmp_attribute_fld + 2, attrp, ie->cfg_id ); | |||
259 | ||||
260 | off = ISAKMP_ATTRIBUTE_SZ8; | |||
261 | ||||
262 | /* | |||
263 | * Use the bitstring built previously to collect the right | |||
264 | * parameters for attrp. | |||
265 | */ | |||
266 | for (bit = 0; bit < CFG_ATTR_BIT_MAX16; bit++) | |||
267 | if (bit_test(attrbits, bit)((attrbits)[((bit) >> 3)] & (1 << ((bit)& 0x7)))) { | |||
268 | attr = attrp + off; | |||
269 | SET_ISAKMP_ATTR_TYPE(attr, bit)field_set_num (isakmp_attr_fld + 0, attr, bit); | |||
270 | ||||
271 | if (ie->cfg_type == ISAKMP_CFG_REQUEST1) { | |||
272 | off += ISAKMP_ATTR_SZ4; | |||
273 | continue; | |||
274 | } | |||
275 | /* All the other are similar, this is the odd one. */ | |||
276 | if (bit == ISAKMP_CFG_ATTR_INTERNAL_ADDRESS_EXPIRY5) { | |||
277 | life = conf_get_num(id_string, "Lifetime", | |||
278 | 1200); | |||
279 | SET_ISAKMP_ATTR_LENGTH_VALUE(attr, 4)field_set_num (isakmp_attr_fld + 1, attr, 4); | |||
280 | encode_32(attr + ISAKMP_ATTR_VALUE_OFF4, life); | |||
281 | off += ISAKMP_ATTR_SZ4 + 4; | |||
282 | continue; | |||
283 | } | |||
284 | switch (bit) { | |||
285 | case ISAKMP_CFG_ATTR_INTERNAL_IP4_ADDRESS1: | |||
286 | case ISAKMP_CFG_ATTR_INTERNAL_IP4_NETMASK2: | |||
287 | case ISAKMP_CFG_ATTR_INTERNAL_IP4_DNS3: | |||
288 | case ISAKMP_CFG_ATTR_INTERNAL_IP4_DHCP6: | |||
289 | case ISAKMP_CFG_ATTR_INTERNAL_IP4_NBNS4: | |||
290 | length = 4; | |||
291 | break; | |||
292 | ||||
293 | case ISAKMP_CFG_ATTR_INTERNAL_IP6_ADDRESS8: | |||
294 | case ISAKMP_CFG_ATTR_INTERNAL_IP6_NETMASK9: | |||
295 | case ISAKMP_CFG_ATTR_INTERNAL_IP6_DNS10: | |||
296 | case ISAKMP_CFG_ATTR_INTERNAL_IP6_DHCP12: | |||
297 | case ISAKMP_CFG_ATTR_INTERNAL_IP6_NBNS11: | |||
298 | length = 16; | |||
299 | break; | |||
300 | ||||
301 | default: | |||
302 | length = 0; /* Silence gcc. */ | |||
303 | } | |||
304 | ||||
305 | switch (bit) { | |||
306 | case ISAKMP_CFG_ATTR_INTERNAL_IP4_ADDRESS1: | |||
307 | case ISAKMP_CFG_ATTR_INTERNAL_IP6_ADDRESS8: | |||
308 | field = "Address"; | |||
309 | break; | |||
310 | case ISAKMP_CFG_ATTR_INTERNAL_IP4_NETMASK2: | |||
311 | case ISAKMP_CFG_ATTR_INTERNAL_IP6_NETMASK9: | |||
312 | field = "Netmask"; | |||
313 | break; | |||
314 | case ISAKMP_CFG_ATTR_INTERNAL_IP4_DNS3: | |||
315 | case ISAKMP_CFG_ATTR_INTERNAL_IP6_DNS10: | |||
316 | field = "Nameserver"; | |||
317 | break; | |||
318 | case ISAKMP_CFG_ATTR_INTERNAL_IP4_DHCP6: | |||
319 | case ISAKMP_CFG_ATTR_INTERNAL_IP6_DHCP12: | |||
320 | field = "DHCP-server"; | |||
321 | break; | |||
322 | case ISAKMP_CFG_ATTR_INTERNAL_IP4_NBNS4: | |||
323 | case ISAKMP_CFG_ATTR_INTERNAL_IP6_NBNS11: | |||
324 | field = "WINS-server"; | |||
325 | break; | |||
326 | default: | |||
327 | field = 0; /* Silence gcc. */ | |||
328 | } | |||
329 | ||||
330 | sa = conf_get_address(id_string, field); | |||
331 | ||||
332 | SET_ISAKMP_ATTR_LENGTH_VALUE(attr, length)field_set_num (isakmp_attr_fld + 1, attr, length); | |||
333 | memcpy(attr + ISAKMP_ATTR_VALUE_OFF4, | |||
334 | sockaddr_addrdata(sa), length); | |||
335 | ||||
336 | free(sa); | |||
337 | ||||
338 | off += ISAKMP_ATTR_SZ4 + length; | |||
339 | } | |||
340 | if (msg->exchange->phase == 2) | |||
341 | if (cfg_finalize_hash(msg, hashp, attrp, attrlen)) | |||
342 | goto fail; | |||
343 | ||||
344 | return 0; | |||
345 | ||||
346 | fail: | |||
347 | free(id_string); | |||
348 | return -1; | |||
349 | } | |||
350 | ||||
351 | /* | |||
352 | * As "the server", this ends SET/ACK. | |||
353 | * As "the client", this ends REQ/REPLY. | |||
354 | */ | |||
355 | static int | |||
356 | cfg_initiator_recv_ATTR(struct message *msg) | |||
357 | { | |||
358 | struct payload *attrp = payload_first(msg, ISAKMP_PAYLOAD_ATTRIBUTE14); | |||
359 | struct ipsec_exch *ie = msg->exchange->data; | |||
360 | struct sa *isakmp_sa = msg->isakmp_sa; | |||
361 | struct isakmp_cfg_attr *attr; | |||
362 | struct sockaddr *sa; | |||
363 | const char *uk_addr = "<unknown>"; | |||
364 | char *addr; | |||
365 | ||||
366 | if (msg->exchange->phase == 2) | |||
367 | if (cfg_verify_hash(msg)) | |||
368 | return -1; | |||
369 | ||||
370 | /* Sanity. */ | |||
371 | if (ie->cfg_id != GET_ISAKMP_ATTRIBUTE_ID(attrp->p)field_get_num (isakmp_attribute_fld + 2, attrp->p)) { | |||
372 | log_print("cfg_initiator_recv_ATTR: " | |||
373 | "cfg packet ID does not match!"); | |||
374 | message_drop(msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED16, 0, 1, 0); | |||
375 | return -1; | |||
376 | } | |||
377 | switch (attrp->p[ISAKMP_ATTRIBUTE_TYPE_OFF4]) { | |||
378 | case ISAKMP_CFG_ACK4: | |||
379 | if (ie->cfg_type != ISAKMP_CFG_SET3) { | |||
380 | log_print("cfg_initiator_recv_ATTR: " | |||
381 | "bad packet type ACK"); | |||
382 | message_drop(msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED16, | |||
383 | 0, 1, 0); | |||
384 | return -1; | |||
385 | } | |||
386 | break; | |||
387 | case ISAKMP_CFG_REPLY2: | |||
388 | if (ie->cfg_type != ISAKMP_CFG_REQUEST1) { | |||
389 | log_print("cfg_initiator_recv_ATTR: " | |||
390 | "bad packet type REPLY"); | |||
391 | message_drop(msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED16, | |||
392 | 0, 1, 0); | |||
393 | return -1; | |||
394 | } | |||
395 | break; | |||
396 | ||||
397 | default: | |||
398 | log_print("cfg_initiator_recv_ATTR: unexpected configuration " | |||
399 | "message type %d", attrp->p[ISAKMP_ATTRIBUTE_TYPE_OFF4]); | |||
400 | message_drop(msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED16, 0, 1, 0); | |||
401 | return -1; | |||
402 | } | |||
403 | ||||
404 | attribute_map(attrp->p + ISAKMP_ATTRIBUTE_ATTRS_OFF8, | |||
405 | GET_ISAKMP_GEN_LENGTH(attrp->p)field_get_num (isakmp_gen_fld + 2, attrp->p) - ISAKMP_TRANSFORM_SA_ATTRS_OFF8, | |||
406 | cfg_decode_attribute, ie); | |||
407 | ||||
408 | switch (ie->cfg_type) { | |||
409 | case ISAKMP_CFG_ACK4: { | |||
410 | /* SET/ACK -- Server side (ACK from client) */ | |||
411 | msg->transport->vtbl->get_src(isakmp_sa->transport, | |||
412 | &sa); | |||
413 | if (sockaddr2text(sa, &addr, 0) < 0) | |||
414 | addr = (char *) uk_addr; | |||
415 | ||||
416 | for (attr = LIST_FIRST(&ie->attrs)((&ie->attrs)->lh_first); attr; | |||
417 | attr = LIST_NEXT(attr, link)((attr)->link.le_next)) | |||
418 | LOG_DBG((LOG_NEGOTIATION, 50,log_debug (LOG_NEGOTIATION, 50, "cfg_initiator_recv_ATTR: " "client %s ACKs attribute %s" , addr, constant_name(isakmp_cfg_attr_cst, attr->type)) | |||
419 | "cfg_initiator_recv_ATTR: "log_debug (LOG_NEGOTIATION, 50, "cfg_initiator_recv_ATTR: " "client %s ACKs attribute %s" , addr, constant_name(isakmp_cfg_attr_cst, attr->type)) | |||
420 | "client %s ACKs attribute %s", addr,log_debug (LOG_NEGOTIATION, 50, "cfg_initiator_recv_ATTR: " "client %s ACKs attribute %s" , addr, constant_name(isakmp_cfg_attr_cst, attr->type)) | |||
421 | constant_name(isakmp_cfg_attr_cst,log_debug (LOG_NEGOTIATION, 50, "cfg_initiator_recv_ATTR: " "client %s ACKs attribute %s" , addr, constant_name(isakmp_cfg_attr_cst, attr->type)) | |||
422 | attr->type)))log_debug (LOG_NEGOTIATION, 50, "cfg_initiator_recv_ATTR: " "client %s ACKs attribute %s" , addr, constant_name(isakmp_cfg_attr_cst, attr->type)); | |||
423 | ||||
424 | if (addr != uk_addr) | |||
425 | free(addr); | |||
426 | } | |||
427 | break; | |||
428 | ||||
429 | case ISAKMP_CFG_REPLY2: { | |||
430 | /* | |||
431 | * REQ/REPLY: effect attributes we've gotten | |||
432 | * responses on. | |||
433 | */ | |||
434 | msg->transport->vtbl->get_src(isakmp_sa->transport, | |||
435 | &sa); | |||
436 | if (sockaddr2text(sa, &addr, 0) < 0) | |||
437 | addr = (char *) uk_addr; | |||
438 | ||||
439 | for (attr = LIST_FIRST(&ie->attrs)((&ie->attrs)->lh_first); attr; | |||
440 | attr = LIST_NEXT(attr, link)((attr)->link.le_next)) | |||
441 | LOG_DBG((LOG_NEGOTIATION, 50,log_debug (LOG_NEGOTIATION, 50, "cfg_initiator_recv_ATTR: " "server %s replied with attribute %s" , addr, constant_name(isakmp_cfg_attr_cst, attr->type)) | |||
442 | "cfg_initiator_recv_ATTR: "log_debug (LOG_NEGOTIATION, 50, "cfg_initiator_recv_ATTR: " "server %s replied with attribute %s" , addr, constant_name(isakmp_cfg_attr_cst, attr->type)) | |||
443 | "server %s replied with attribute %s",log_debug (LOG_NEGOTIATION, 50, "cfg_initiator_recv_ATTR: " "server %s replied with attribute %s" , addr, constant_name(isakmp_cfg_attr_cst, attr->type)) | |||
444 | addr, constant_name(isakmp_cfg_attr_cst,log_debug (LOG_NEGOTIATION, 50, "cfg_initiator_recv_ATTR: " "server %s replied with attribute %s" , addr, constant_name(isakmp_cfg_attr_cst, attr->type)) | |||
445 | attr->type)))log_debug (LOG_NEGOTIATION, 50, "cfg_initiator_recv_ATTR: " "server %s replied with attribute %s" , addr, constant_name(isakmp_cfg_attr_cst, attr->type)); | |||
446 | ||||
447 | if (addr != uk_addr) | |||
448 | free(addr); | |||
449 | } | |||
450 | break; | |||
451 | ||||
452 | default: | |||
453 | break; | |||
454 | } | |||
455 | ||||
456 | attrp->flags |= PL_MARK1; | |||
457 | return 0; | |||
458 | } | |||
459 | ||||
460 | /* | |||
461 | * As "the server", this starts REQ/REPLY (initiated by the client). | |||
462 | * As "the client", this starts SET/ACK (initiated by the server). | |||
463 | */ | |||
464 | static int | |||
465 | cfg_responder_recv_ATTR(struct message *msg) | |||
466 | { | |||
467 | struct payload *attrp = payload_first(msg, ISAKMP_PAYLOAD_ATTRIBUTE14); | |||
468 | struct ipsec_exch *ie = msg->exchange->data; | |||
469 | struct sa *isakmp_sa = msg->isakmp_sa; | |||
470 | struct isakmp_cfg_attr *attr; | |||
471 | struct sockaddr *sa; | |||
472 | char *addr; | |||
473 | ||||
474 | if (msg->exchange->phase == 2) | |||
475 | if (cfg_verify_hash(msg)) | |||
476 | return -1; | |||
477 | ||||
478 | ie->cfg_id = GET_ISAKMP_ATTRIBUTE_ID(attrp->p)field_get_num (isakmp_attribute_fld + 2, attrp->p); | |||
479 | ie->cfg_type = attrp->p[ISAKMP_ATTRIBUTE_TYPE_OFF4]; | |||
480 | ||||
481 | switch (ie->cfg_type) { | |||
482 | case ISAKMP_CFG_REQUEST1: | |||
483 | case ISAKMP_CFG_SET3: | |||
484 | break; | |||
485 | ||||
486 | default: | |||
487 | message_drop(msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED16, 0, 1, 0); | |||
488 | log_print("cfg_responder_recv_ATTR: " | |||
489 | "unexpected configuration message type %d", ie->cfg_type); | |||
490 | return -1; | |||
491 | } | |||
492 | ||||
493 | attribute_map(attrp->p + ISAKMP_ATTRIBUTE_ATTRS_OFF8, | |||
494 | GET_ISAKMP_GEN_LENGTH(attrp->p)field_get_num (isakmp_gen_fld + 2, attrp->p) - ISAKMP_TRANSFORM_SA_ATTRS_OFF8, | |||
495 | cfg_decode_attribute, ie); | |||
496 | ||||
497 | switch (ie->cfg_type) { | |||
498 | case ISAKMP_CFG_REQUEST1: | |||
499 | /* We're done. */ | |||
500 | break; | |||
501 | ||||
502 | case ISAKMP_CFG_SET3: { | |||
503 | /* SET/ACK -- Client side (SET from server) */ | |||
504 | const char *uk_addr = "<unknown>"; | |||
505 | ||||
506 | msg->transport->vtbl->get_dst(isakmp_sa->transport, | |||
507 | &sa); | |||
508 | if (sockaddr2text(sa, &addr, 0) < 0) | |||
509 | addr = (char *) uk_addr; | |||
510 | ||||
511 | for (attr = LIST_FIRST(&ie->attrs)((&ie->attrs)->lh_first); attr; | |||
512 | attr = LIST_NEXT(attr, link)((attr)->link.le_next)) | |||
513 | LOG_DBG((LOG_NEGOTIATION, 50,log_debug (LOG_NEGOTIATION, 50, "cfg_responder_recv_ATTR: " "server %s asks us to SET attribute %s" , addr, constant_name(isakmp_cfg_attr_cst, attr->type)) | |||
514 | "cfg_responder_recv_ATTR: "log_debug (LOG_NEGOTIATION, 50, "cfg_responder_recv_ATTR: " "server %s asks us to SET attribute %s" , addr, constant_name(isakmp_cfg_attr_cst, attr->type)) | |||
515 | "server %s asks us to SET attribute %s",log_debug (LOG_NEGOTIATION, 50, "cfg_responder_recv_ATTR: " "server %s asks us to SET attribute %s" , addr, constant_name(isakmp_cfg_attr_cst, attr->type)) | |||
516 | addr, constant_name(isakmp_cfg_attr_cst,log_debug (LOG_NEGOTIATION, 50, "cfg_responder_recv_ATTR: " "server %s asks us to SET attribute %s" , addr, constant_name(isakmp_cfg_attr_cst, attr->type)) | |||
517 | attr->type)))log_debug (LOG_NEGOTIATION, 50, "cfg_responder_recv_ATTR: " "server %s asks us to SET attribute %s" , addr, constant_name(isakmp_cfg_attr_cst, attr->type)); | |||
518 | ||||
519 | /* | |||
520 | * XXX Here's the place to add code to walk through | |||
521 | * XXX each attribute and send them along to dhclient | |||
522 | * XXX or whatever. Each attribute that we act upon | |||
523 | * XXX (such as setting a netmask), should be marked | |||
524 | * XXX like this for us to send the proper ACK | |||
525 | * XXX response: attr->attr_used++; | |||
526 | */ | |||
527 | ||||
528 | if (addr != uk_addr) | |||
529 | free(addr); | |||
530 | } | |||
531 | break; | |||
532 | ||||
533 | default: | |||
534 | break; | |||
535 | } | |||
536 | ||||
537 | attrp->flags |= PL_MARK1; | |||
538 | return 0; | |||
539 | } | |||
540 | ||||
541 | /* | |||
542 | * As "the server", this ends REQ/REPLY mode. | |||
543 | * As "the client", this ends SET/ACK mode. | |||
544 | */ | |||
545 | static int | |||
546 | cfg_responder_send_ATTR(struct message *msg) | |||
547 | { | |||
548 | struct ipsec_exch *ie = msg->exchange->data; | |||
549 | struct sa *isakmp_sa = msg->isakmp_sa; | |||
550 | u_int8_t *hashp = 0, *attrp; | |||
551 | u_int16_t attrlen; | |||
552 | char *id_string; | |||
553 | ||||
554 | if (msg->exchange->phase == 2) { | |||
555 | hashp = cfg_add_hash(msg); | |||
556 | if (!hashp) | |||
557 | return -1; | |||
558 | } | |||
559 | /* We are responder, check isakmp_sa for other side. */ | |||
560 | if (isakmp_sa->initiator ^ (ie->cfg_type == ISAKMP_CFG_REQUEST1)) | |||
561 | id_string = ipsec_id_string(isakmp_sa->id_i, | |||
562 | isakmp_sa->id_i_len); | |||
563 | else | |||
564 | id_string = ipsec_id_string(isakmp_sa->id_r, | |||
565 | isakmp_sa->id_r_len); | |||
566 | if (!id_string) { | |||
567 | log_print("cfg_responder_send_ATTR: cannot parse client's ID"); | |||
568 | return -1; | |||
569 | } | |||
570 | if (cfg_encode_attributes(&ie->attrs, (ie->cfg_type == ISAKMP_CFG_SET3 ? | |||
571 | ISAKMP_CFG_ACK4 : ISAKMP_CFG_REPLY2), ie->cfg_id, id_string, &attrp, | |||
572 | &attrlen)) { | |||
573 | free(id_string); | |||
574 | return -1; | |||
575 | } | |||
576 | free(id_string); | |||
577 | ||||
578 | if (message_add_payload(msg, ISAKMP_PAYLOAD_ATTRIBUTE14, attrp, attrlen, | |||
579 | 1)) { | |||
580 | free(attrp); | |||
581 | return -1; | |||
582 | } | |||
583 | if (msg->exchange->phase == 2) | |||
584 | if (cfg_finalize_hash(msg, hashp, attrp, attrlen)) | |||
585 | return -1; | |||
586 | ||||
587 | return 0; | |||
588 | } | |||
589 | ||||
590 | u_int8_t * | |||
591 | cfg_add_hash(struct message *msg) | |||
592 | { | |||
593 | struct ipsec_sa *isa = msg->isakmp_sa->data; | |||
594 | struct hash *hash = hash_get(isa->hash); | |||
595 | u_int8_t *hashp; | |||
596 | ||||
597 | hashp = malloc(ISAKMP_HASH_SZ4 + hash->hashsize); | |||
598 | if (!hashp) { | |||
599 | log_error("cfg_add_hash: malloc (%lu) failed", | |||
600 | ISAKMP_HASH_SZ4 + (unsigned long)hash->hashsize); | |||
601 | return 0; | |||
602 | } | |||
603 | if (message_add_payload(msg, ISAKMP_PAYLOAD_HASH8, hashp, | |||
604 | ISAKMP_HASH_SZ4 + hash->hashsize, 1)) { | |||
605 | free(hashp); | |||
606 | return 0; | |||
607 | } | |||
608 | return hashp; | |||
609 | } | |||
610 | ||||
611 | int | |||
612 | cfg_finalize_hash(struct message *msg, u_int8_t *hashp, u_int8_t *data, | |||
613 | u_int16_t length) | |||
614 | { | |||
615 | struct ipsec_sa *isa = msg->isakmp_sa->data; | |||
616 | struct prf *prf; | |||
617 | ||||
618 | prf = prf_alloc(isa->prf_type, isa->hash, isa->skeyid_a, | |||
619 | isa->skeyid_len); | |||
620 | if (!prf) | |||
621 | return -1; | |||
622 | ||||
623 | prf->Init(prf->prfctx); | |||
624 | prf->Update(prf->prfctx, msg->exchange->message_id, | |||
625 | ISAKMP_HDR_MESSAGE_ID_LEN4); | |||
626 | prf->Update(prf->prfctx, data, length); | |||
627 | prf->Final(hashp + ISAKMP_GEN_SZ4, prf->prfctx); | |||
628 | prf_free(prf); | |||
629 | return 0; | |||
630 | } | |||
631 | ||||
632 | int | |||
633 | cfg_verify_hash(struct message *msg) | |||
634 | { | |||
635 | struct payload *hashp = payload_first(msg, ISAKMP_PAYLOAD_HASH8); | |||
636 | struct ipsec_sa *isa = msg->isakmp_sa->data; | |||
637 | struct prf *prf; | |||
638 | u_int8_t *hash, *comp_hash; | |||
639 | size_t hash_len; | |||
640 | ||||
641 | if (!hashp) { | |||
642 | log_print("cfg_verify_hash: phase 2 message missing HASH"); | |||
643 | message_drop(msg, ISAKMP_NOTIFY_INVALID_HASH_INFORMATION23, | |||
644 | 0, 1, 0); | |||
645 | return -1; | |||
646 | } | |||
647 | hash = hashp->p; | |||
648 | hash_len = GET_ISAKMP_GEN_LENGTH(hash)field_get_num (isakmp_gen_fld + 2, hash); | |||
649 | comp_hash = malloc(hash_len - ISAKMP_GEN_SZ4); | |||
650 | if (!comp_hash) { | |||
651 | log_error("cfg_verify_hash: malloc (%lu) failed", | |||
652 | (unsigned long)hash_len - ISAKMP_GEN_SZ4); | |||
653 | return -1; | |||
654 | } | |||
655 | /* Verify hash. */ | |||
656 | prf = prf_alloc(isa->prf_type, isa->hash, isa->skeyid_a, | |||
657 | isa->skeyid_len); | |||
658 | if (!prf) { | |||
659 | free(comp_hash); | |||
660 | return -1; | |||
661 | } | |||
662 | prf->Init(prf->prfctx); | |||
663 | prf->Update(prf->prfctx, msg->exchange->message_id, | |||
664 | ISAKMP_HDR_MESSAGE_ID_LEN4); | |||
665 | prf->Update(prf->prfctx, hash + hash_len, | |||
666 | msg->iov[0].iov_len - ISAKMP_HDR_SZ28 - hash_len); | |||
667 | prf->Final(comp_hash, prf->prfctx); | |||
668 | prf_free(prf); | |||
669 | ||||
670 | if (memcmp(hash + ISAKMP_GEN_SZ4, comp_hash, hash_len - ISAKMP_GEN_SZ4) | |||
671 | != 0) { | |||
672 | message_drop(msg, ISAKMP_NOTIFY_INVALID_HASH_INFORMATION23, | |||
673 | 0, 1, 0); | |||
674 | free(comp_hash); | |||
675 | return -1; | |||
676 | } | |||
677 | free(comp_hash); | |||
678 | ||||
679 | /* Mark the HASH as handled. */ | |||
680 | hashp->flags |= PL_MARK1; | |||
681 | ||||
682 | /* Mark message authenticated. */ | |||
683 | msg->flags |= MSG_AUTHENTICATED0x10; | |||
684 | ||||
685 | return 0; | |||
686 | } | |||
687 | ||||
688 | /* | |||
689 | * Decode the attribute of type TYPE with a LEN length value pointed to by | |||
690 | * VALUE. VIE is a pointer to the IPsec exchange context holding the | |||
691 | * attributes indexed by type for easy retrieval. | |||
692 | */ | |||
693 | static int | |||
694 | cfg_decode_attribute(u_int16_t type, u_int8_t * value, u_int16_t len, | |||
695 | void *vie) | |||
696 | { | |||
697 | struct ipsec_exch *ie = vie; | |||
698 | struct isakmp_cfg_attr *attr; | |||
699 | ||||
700 | if (type >= ISAKMP_CFG_ATTR_PRIVATE_MIN16384 && | |||
701 | type <= ISAKMP_CFG_ATTR_PRIVATE_MAX32767) | |||
702 | return 0; | |||
703 | if (type == 0 || type >= ISAKMP_CFG_ATTR_FUTURE_MIN16) { | |||
704 | LOG_DBG((LOG_NEGOTIATION, 30,log_debug (LOG_NEGOTIATION, 30, "cfg_decode_attribute: invalid attr type %u" , type) | |||
705 | "cfg_decode_attribute: invalid attr type %u", type))log_debug (LOG_NEGOTIATION, 30, "cfg_decode_attribute: invalid attr type %u" , type); | |||
706 | return -1; | |||
707 | } | |||
708 | attr = calloc(1, sizeof *attr); | |||
709 | if (!attr) { | |||
710 | log_error("cfg_decode_attribute: calloc (1, %lu) failed", | |||
711 | (unsigned long)sizeof *attr); | |||
712 | return -1; | |||
713 | } | |||
714 | attr->type = type; | |||
715 | attr->length = len; | |||
716 | if (len) { | |||
717 | attr->value = malloc(len); | |||
718 | if (!attr->value) { | |||
719 | log_error("cfg_decode_attribute: malloc (%d) failed", | |||
720 | len); | |||
721 | free(attr); | |||
722 | /* Should we also deallocate all other values? */ | |||
723 | return -1; | |||
724 | } | |||
725 | memcpy(attr->value, value, len); | |||
726 | } | |||
727 | LIST_INSERT_HEAD(&ie->attrs, attr, link)do { if (((attr)->link.le_next = (&ie->attrs)->lh_first ) != ((void *)0)) (&ie->attrs)->lh_first->link.le_prev = &(attr)->link.le_next; (&ie->attrs)->lh_first = (attr); (attr)->link.le_prev = &(&ie->attrs) ->lh_first; } while (0); | |||
728 | return 0; | |||
729 | } | |||
730 | ||||
731 | /* | |||
732 | * Encode list of attributes from ie->attrs into a attribute payload. | |||
733 | */ | |||
734 | static int | |||
735 | cfg_encode_attributes(struct isakmp_cfg_attr_head *attrs, u_int32_t type, | |||
736 | u_int32_t cfg_id, char *id_string, u_int8_t **attrp, u_int16_t *len) | |||
737 | { | |||
738 | struct isakmp_cfg_attr *attr; | |||
739 | struct sockaddr *sa; | |||
740 | sa_family_t family; | |||
741 | u_int32_t value; | |||
742 | u_int16_t off; | |||
743 | char *field; | |||
744 | ||||
745 | /* Compute length */ | |||
746 | *len = ISAKMP_ATTRIBUTE_SZ8; | |||
747 | for (attr = LIST_FIRST(attrs)((attrs)->lh_first); attr; attr = LIST_NEXT(attr, link)((attr)->link.le_next)) { | |||
748 | /* With ACK we only include the attrs we've actually used. */ | |||
749 | if (type == ISAKMP_CFG_ACK4 && attr->attr_used == 0) | |||
750 | continue; | |||
751 | ||||
752 | switch (attr->type) { | |||
753 | case ISAKMP_CFG_ATTR_INTERNAL_IP4_ADDRESS1: | |||
754 | case ISAKMP_CFG_ATTR_INTERNAL_IP4_NETMASK2: | |||
755 | case ISAKMP_CFG_ATTR_INTERNAL_IP4_DHCP6: | |||
756 | case ISAKMP_CFG_ATTR_INTERNAL_IP4_DNS3: | |||
757 | case ISAKMP_CFG_ATTR_INTERNAL_IP4_NBNS4: | |||
758 | case ISAKMP_CFG_ATTR_INTERNAL_ADDRESS_EXPIRY5: | |||
759 | attr->length = 4; | |||
760 | break; | |||
761 | ||||
762 | case ISAKMP_CFG_ATTR_INTERNAL_IP4_SUBNET13: | |||
763 | attr->length = 8; | |||
764 | break; | |||
765 | ||||
766 | case ISAKMP_CFG_ATTR_APPLICATION_VERSION7: | |||
767 | /* XXX So far no version identifier of isakmpd here. */ | |||
768 | attr->length = 0; | |||
769 | break; | |||
770 | ||||
771 | case ISAKMP_CFG_ATTR_SUPPORTED_ATTRIBUTES14: | |||
772 | attr->length = 2 * 15; | |||
773 | break; | |||
774 | ||||
775 | case ISAKMP_CFG_ATTR_INTERNAL_IP6_ADDRESS8: | |||
776 | case ISAKMP_CFG_ATTR_INTERNAL_IP6_NETMASK9: | |||
777 | case ISAKMP_CFG_ATTR_INTERNAL_IP6_DHCP12: | |||
778 | case ISAKMP_CFG_ATTR_INTERNAL_IP6_DNS10: | |||
779 | case ISAKMP_CFG_ATTR_INTERNAL_IP6_NBNS11: | |||
780 | attr->length = 16; | |||
781 | break; | |||
782 | ||||
783 | case ISAKMP_CFG_ATTR_INTERNAL_IP6_SUBNET15: | |||
784 | attr->length = 17; | |||
785 | break; | |||
786 | ||||
787 | default: | |||
788 | attr->ignore++; | |||
789 | /* XXX Log! */ | |||
790 | } | |||
791 | *len += ISAKMP_ATTR_SZ4 + attr->length; | |||
792 | } | |||
793 | ||||
794 | /* Allocate enough space for the payload */ | |||
795 | *attrp = calloc(1, *len); | |||
796 | if (!*attrp) { | |||
797 | log_error("cfg_encode_attributes: calloc (1, %lu) failed", | |||
798 | (unsigned long)*len); | |||
799 | return -1; | |||
800 | } | |||
801 | SET_ISAKMP_ATTRIBUTE_TYPE(*attrp, type)field_set_num (isakmp_attribute_fld + 0, *attrp, type); | |||
802 | SET_ISAKMP_ATTRIBUTE_ID(*attrp, cfg_id)field_set_num (isakmp_attribute_fld + 2, *attrp, cfg_id); | |||
803 | ||||
804 | off = ISAKMP_ATTRIBUTE_SZ8; | |||
805 | for (attr = LIST_FIRST(attrs)((attrs)->lh_first); attr; attr = LIST_NEXT(attr, link)((attr)->link.le_next)) { | |||
806 | /* With ACK we only include the attrs we've actually used. */ | |||
807 | if (type == ISAKMP_CFG_ACK4 && attr->attr_used == 0) | |||
808 | continue; | |||
809 | ||||
810 | switch (attr->type) { | |||
811 | case ISAKMP_CFG_ATTR_INTERNAL_IP4_ADDRESS1: | |||
812 | case ISAKMP_CFG_ATTR_INTERNAL_IP4_NETMASK2: | |||
813 | case ISAKMP_CFG_ATTR_INTERNAL_IP4_SUBNET13: | |||
814 | case ISAKMP_CFG_ATTR_INTERNAL_IP4_DHCP6: | |||
815 | case ISAKMP_CFG_ATTR_INTERNAL_IP4_DNS3: | |||
816 | case ISAKMP_CFG_ATTR_INTERNAL_IP4_NBNS4: | |||
817 | family = AF_INET2; | |||
818 | break; | |||
819 | ||||
820 | case ISAKMP_CFG_ATTR_INTERNAL_IP6_ADDRESS8: | |||
821 | case ISAKMP_CFG_ATTR_INTERNAL_IP6_NETMASK9: | |||
822 | case ISAKMP_CFG_ATTR_INTERNAL_IP6_SUBNET15: | |||
823 | case ISAKMP_CFG_ATTR_INTERNAL_IP6_DHCP12: | |||
824 | case ISAKMP_CFG_ATTR_INTERNAL_IP6_DNS10: | |||
825 | case ISAKMP_CFG_ATTR_INTERNAL_IP6_NBNS11: | |||
826 | family = AF_INET624; | |||
827 | break; | |||
828 | ||||
829 | default: | |||
830 | family = 0; | |||
831 | break; | |||
832 | } | |||
833 | ||||
834 | switch (attr->type) { | |||
835 | case ISAKMP_CFG_ATTR_INTERNAL_IP4_ADDRESS1: | |||
836 | case ISAKMP_CFG_ATTR_INTERNAL_IP6_ADDRESS8: | |||
837 | field = "Address"; | |||
838 | break; | |||
839 | ||||
840 | case ISAKMP_CFG_ATTR_INTERNAL_IP4_SUBNET13: | |||
841 | case ISAKMP_CFG_ATTR_INTERNAL_IP6_SUBNET15: | |||
842 | field = "Network"; /* XXX or just "Address" */ | |||
843 | break; | |||
844 | ||||
845 | case ISAKMP_CFG_ATTR_INTERNAL_IP4_NETMASK2: | |||
846 | case ISAKMP_CFG_ATTR_INTERNAL_IP6_NETMASK9: | |||
847 | field = "Netmask"; | |||
848 | break; | |||
849 | ||||
850 | case ISAKMP_CFG_ATTR_INTERNAL_IP4_DHCP6: | |||
851 | case ISAKMP_CFG_ATTR_INTERNAL_IP6_DHCP12: | |||
852 | field = "DHCP-server"; | |||
853 | break; | |||
854 | ||||
855 | case ISAKMP_CFG_ATTR_INTERNAL_IP4_DNS3: | |||
856 | case ISAKMP_CFG_ATTR_INTERNAL_IP6_DNS10: | |||
857 | field = "Nameserver"; | |||
858 | break; | |||
859 | ||||
860 | case ISAKMP_CFG_ATTR_INTERNAL_IP4_NBNS4: | |||
861 | case ISAKMP_CFG_ATTR_INTERNAL_IP6_NBNS11: | |||
862 | field = "WINS-server"; | |||
863 | break; | |||
864 | ||||
865 | default: | |||
866 | field = 0; | |||
867 | } | |||
868 | ||||
869 | switch (attr->type) { | |||
870 | case ISAKMP_CFG_ATTR_INTERNAL_IP4_ADDRESS1: | |||
871 | case ISAKMP_CFG_ATTR_INTERNAL_IP6_ADDRESS8: | |||
872 | case ISAKMP_CFG_ATTR_INTERNAL_IP4_NETMASK2: | |||
873 | case ISAKMP_CFG_ATTR_INTERNAL_IP6_NETMASK9: | |||
874 | case ISAKMP_CFG_ATTR_INTERNAL_IP4_DHCP6: | |||
875 | case ISAKMP_CFG_ATTR_INTERNAL_IP6_DHCP12: | |||
876 | case ISAKMP_CFG_ATTR_INTERNAL_IP4_DNS3: | |||
877 | case ISAKMP_CFG_ATTR_INTERNAL_IP6_DNS10: | |||
878 | case ISAKMP_CFG_ATTR_INTERNAL_IP4_NBNS4: | |||
879 | case ISAKMP_CFG_ATTR_INTERNAL_IP6_NBNS11: | |||
880 | sa = conf_get_address(id_string, field); | |||
881 | if (!sa) { | |||
882 | LOG_DBG((LOG_NEGOTIATION, 10,log_debug (LOG_NEGOTIATION, 10, "cfg_responder_send_ATTR: " "attribute not found: %s" , field) | |||
883 | "cfg_responder_send_ATTR: "log_debug (LOG_NEGOTIATION, 10, "cfg_responder_send_ATTR: " "attribute not found: %s" , field) | |||
884 | "attribute not found: %s", field))log_debug (LOG_NEGOTIATION, 10, "cfg_responder_send_ATTR: " "attribute not found: %s" , field); | |||
885 | attr->length = 0; | |||
886 | break; | |||
887 | } | |||
888 | if (sa->sa_family != family) { | |||
889 | log_print("cfg_responder_send_ATTR: " | |||
890 | "attribute %s - expected %s got %s data", | |||
891 | field, | |||
892 | (family == AF_INET2 ? "IPv4" : "IPv6"), | |||
893 | (sa->sa_family == | |||
894 | AF_INET2 ? "IPv4" : "IPv6")); | |||
895 | free(sa); | |||
896 | attr->length = 0; | |||
897 | break; | |||
898 | } | |||
899 | /* Temporary limit length for the _SUBNET types. */ | |||
900 | if (attr->type == ISAKMP_CFG_ATTR_INTERNAL_IP4_SUBNET13) | |||
901 | attr->length = 4; | |||
902 | else if (attr->type == | |||
903 | ISAKMP_CFG_ATTR_INTERNAL_IP6_SUBNET15) | |||
904 | attr->length = 16; | |||
905 | ||||
906 | memcpy(*attrp + off + ISAKMP_ATTR_VALUE_OFF4, | |||
907 | sockaddr_addrdata(sa), attr->length); | |||
908 | free(sa); | |||
909 | ||||
910 | /* _SUBNET types need some extra work. */ | |||
911 | if (attr->type == | |||
912 | ISAKMP_CFG_ATTR_INTERNAL_IP4_SUBNET13) { | |||
913 | sa = conf_get_address(id_string, "Netmask"); | |||
914 | if (!sa) { | |||
915 | LOG_DBG((LOG_NEGOTIATION, 10,log_debug (LOG_NEGOTIATION, 10, "cfg_responder_send_ATTR: " "attribute not found: Netmask" ) | |||
916 | "cfg_responder_send_ATTR: "log_debug (LOG_NEGOTIATION, 10, "cfg_responder_send_ATTR: " "attribute not found: Netmask" ) | |||
917 | "attribute not found: Netmask"))log_debug (LOG_NEGOTIATION, 10, "cfg_responder_send_ATTR: " "attribute not found: Netmask" ); | |||
918 | attr->length = 0; | |||
919 | break; | |||
920 | } | |||
921 | if (sa->sa_family != AF_INET2) { | |||
922 | log_print("cfg_responder_send_ATTR: " | |||
923 | "attribute Netmask - expected " | |||
924 | "IPv4 got IPv6 data"); | |||
925 | free(sa); | |||
926 | attr->length = 0; | |||
927 | break; | |||
928 | } | |||
929 | memcpy(*attrp + off + ISAKMP_ATTR_VALUE_OFF4 + | |||
930 | attr->length, sockaddr_addrdata(sa), | |||
931 | attr->length); | |||
932 | attr->length = 8; | |||
933 | free(sa); | |||
934 | } else if (attr->type == | |||
935 | ISAKMP_CFG_ATTR_INTERNAL_IP6_SUBNET15) { | |||
936 | int prefix = conf_get_num(id_string, "Prefix", | |||
937 | -1); | |||
938 | ||||
939 | if (prefix == -1) { | |||
940 | log_print("cfg_responder_send_ATTR: " | |||
941 | "attribute not found: Prefix"); | |||
942 | attr->length = 0; | |||
943 | break; | |||
944 | } else if (prefix < -1 || prefix > 128) { | |||
945 | log_print("cfg_responder_send_ATTR: " | |||
946 | "attribute Prefix - invalid " | |||
947 | "value %d", prefix); | |||
948 | attr->length = 0; | |||
949 | break; | |||
950 | } | |||
951 | *(*attrp + off + ISAKMP_ATTR_VALUE_OFF4 + 16) = | |||
952 | (u_int8_t)prefix; | |||
953 | attr->length = 17; | |||
954 | } | |||
955 | break; | |||
956 | ||||
957 | case ISAKMP_CFG_ATTR_INTERNAL_ADDRESS_EXPIRY5: | |||
958 | value = conf_get_num(id_string, "Lifetime", 1200); | |||
959 | encode_32(*attrp + off + ISAKMP_ATTR_VALUE_OFF4, value); | |||
960 | break; | |||
961 | ||||
962 | case ISAKMP_CFG_ATTR_APPLICATION_VERSION7: | |||
963 | /* XXX So far no version identifier of isakmpd here. */ | |||
964 | break; | |||
965 | ||||
966 | case ISAKMP_CFG_ATTR_SUPPORTED_ATTRIBUTES14: | |||
967 | break; | |||
968 | ||||
969 | default: | |||
970 | break; | |||
971 | } | |||
972 | ||||
973 | SET_ISAKMP_ATTR_TYPE(*attrp + off, attr->type)field_set_num (isakmp_attr_fld + 0, *attrp + off, attr->type ); | |||
974 | SET_ISAKMP_ATTR_LENGTH_VALUE(*attrp + off, attr->length)field_set_num (isakmp_attr_fld + 1, *attrp + off, attr->length ); | |||
975 | off += ISAKMP_ATTR_VALUE_OFF4 + attr->length; | |||
976 | } | |||
977 | ||||
978 | return 0; | |||
979 | } |