GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: sbin/isakmpd/isakmp_cfg.c Lines: 0 377 0.0 %
Date: 2016-12-06 Branches: 0 228 0.0 %

Line Branch Exec Source
1
/* $OpenBSD: isakmp_cfg.c,v 1.39 2014/01/23 01:04:28 deraadt 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_ATTRIBUTE,	/* Initiator -> responder.  */
60
	EXCHANGE_SCRIPT_SWITCH,
61
	ISAKMP_PAYLOAD_ATTRIBUTE,	/* Responder -> initiator.  */
62
	EXCHANGE_SCRIPT_END
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_MAX ISAKMP_CFG_ATTR_FUTURE_MIN	/* XXX */
104
	bitstr_t        bit_decl(attrbits, CFG_ATTR_BIT_MAX);
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);
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_SET;
132
133
		LOG_DBG((LOG_NEGOTIATION, 10,
134
		    "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)	\
139
			switch (sa->sa_family) {			\
140
			case AF_INET:					\
141
				bit_set (attrbits, ATTR4);		\
142
				attrlen += ISAKMP_ATTR_SZ + LEN4;	\
143
				break;					\
144
			case AF_INET6:					\
145
				bit_set (attrbits, ATTR6);		\
146
				attrlen += ISAKMP_ATTR_SZ + 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_ADDRESS, 4,
159
		    ISAKMP_CFG_ATTR_INTERNAL_IP6_ADDRESS, 16);
160
		ATTRFIND("Netmask", ISAKMP_CFG_ATTR_INTERNAL_IP4_NETMASK, 4,
161
		    ISAKMP_CFG_ATTR_INTERNAL_IP6_NETMASK, 16);
162
		ATTRFIND("Nameserver", ISAKMP_CFG_ATTR_INTERNAL_IP4_DNS, 4,
163
		    ISAKMP_CFG_ATTR_INTERNAL_IP6_DNS, 16);
164
		ATTRFIND("WINS-server", ISAKMP_CFG_ATTR_INTERNAL_IP4_NBNS, 4,
165
		    ISAKMP_CFG_ATTR_INTERNAL_IP6_NBNS, 16);
166
		ATTRFIND("DHCP-server", ISAKMP_CFG_ATTR_INTERNAL_IP4_DHCP, 4,
167
		    ISAKMP_CFG_ATTR_INTERNAL_IP6_DHCP, 16);
168
#ifdef notyet
169
		ATTRFIND("Network", ISAKMP_CFG_ATTR_INTERNAL_IP4_SUBNET, 8,
170
		    ISAKMP_CFG_ATTR_INTERNAL_IP6_SUBNET, 17);
171
#endif
172
#undef ATTRFIND
173
174
		if (conf_get_str(id_string, "Lifetime")) {
175
			bit_set(attrbits,
176
			    ISAKMP_CFG_ATTR_INTERNAL_ADDRESS_EXPIRY);
177
			attrlen += ISAKMP_ATTR_SZ + 4;
178
		}
179
	} else {
180
		struct conf_list *alist;
181
		struct conf_list_node *anode;
182
183
		ie->cfg_type = ISAKMP_CFG_REQUEST;
184
185
		LOG_DBG((LOG_NEGOTIATION, 10,
186
		    "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); anode;
191
			    anode = TAILQ_NEXT(anode, link)) {
192
				if (strcasecmp(anode->field, "Address") == 0) {
193
					bit_set(attrbits, ISAKMP_CFG_ATTR_INTERNAL_IP4_ADDRESS);
194
					bit_set(attrbits, ISAKMP_CFG_ATTR_INTERNAL_IP6_ADDRESS);
195
					attrlen += ISAKMP_ATTR_SZ * 2;
196
				} else if (strcasecmp(anode->field, "Netmask")
197
				    == 0) {
198
					bit_set(attrbits, ISAKMP_CFG_ATTR_INTERNAL_IP4_NETMASK);
199
					bit_set(attrbits, ISAKMP_CFG_ATTR_INTERNAL_IP6_NETMASK);
200
					attrlen += ISAKMP_ATTR_SZ * 2;
201
				} else if (strcasecmp(anode->field,
202
				    "Nameserver") == 0) {
203
					bit_set(attrbits, ISAKMP_CFG_ATTR_INTERNAL_IP4_DNS);
204
					bit_set(attrbits, ISAKMP_CFG_ATTR_INTERNAL_IP6_DNS);
205
					attrlen += ISAKMP_ATTR_SZ * 2;
206
				} else if (strcasecmp(anode->field,
207
				    "WINS-server") == 0) {
208
					bit_set(attrbits, ISAKMP_CFG_ATTR_INTERNAL_IP4_NBNS);
209
					bit_set(attrbits, ISAKMP_CFG_ATTR_INTERNAL_IP6_NBNS);
210
					attrlen += ISAKMP_ATTR_SZ * 2;
211
				} else if (strcasecmp(anode->field,
212
				    "DHCP-server") == 0) {
213
					bit_set(attrbits, ISAKMP_CFG_ATTR_INTERNAL_IP4_DHCP);
214
					bit_set(attrbits, ISAKMP_CFG_ATTR_INTERNAL_IP6_DHCP);
215
					attrlen += ISAKMP_ATTR_SZ * 2;
216
				} else if (strcasecmp(anode->field,
217
				    "Lifetime") == 0) {
218
					bit_set(attrbits, ISAKMP_CFG_ATTR_INTERNAL_ADDRESS_EXPIRY);
219
					attrlen += ISAKMP_ATTR_SZ;
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_SZ;
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_ATTRIBUTE, attrp, attrlen,
252
	    1)) {
253
		free(attrp);
254
		goto fail;
255
	}
256
	SET_ISAKMP_ATTRIBUTE_TYPE(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);
259
260
	off = ISAKMP_ATTRIBUTE_SZ;
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_MAX; bit++)
267
		if (bit_test(attrbits, bit)) {
268
			attr = attrp + off;
269
			SET_ISAKMP_ATTR_TYPE(attr, bit);
270
271
			if (ie->cfg_type == ISAKMP_CFG_REQUEST) {
272
				off += ISAKMP_ATTR_SZ;
273
				continue;
274
			}
275
			/* All the other are similar, this is the odd one.  */
276
			if (bit == ISAKMP_CFG_ATTR_INTERNAL_ADDRESS_EXPIRY) {
277
				life = conf_get_num(id_string, "Lifetime",
278
				    1200);
279
				SET_ISAKMP_ATTR_LENGTH_VALUE(attr, 4);
280
				encode_32(attr + ISAKMP_ATTR_VALUE_OFF, life);
281
				off += ISAKMP_ATTR_SZ + 4;
282
				continue;
283
			}
284
			switch (bit) {
285
			case ISAKMP_CFG_ATTR_INTERNAL_IP4_ADDRESS:
286
			case ISAKMP_CFG_ATTR_INTERNAL_IP4_NETMASK:
287
			case ISAKMP_CFG_ATTR_INTERNAL_IP4_DNS:
288
			case ISAKMP_CFG_ATTR_INTERNAL_IP4_DHCP:
289
			case ISAKMP_CFG_ATTR_INTERNAL_IP4_NBNS:
290
				length = 4;
291
				break;
292
293
			case ISAKMP_CFG_ATTR_INTERNAL_IP6_ADDRESS:
294
			case ISAKMP_CFG_ATTR_INTERNAL_IP6_NETMASK:
295
			case ISAKMP_CFG_ATTR_INTERNAL_IP6_DNS:
296
			case ISAKMP_CFG_ATTR_INTERNAL_IP6_DHCP:
297
			case ISAKMP_CFG_ATTR_INTERNAL_IP6_NBNS:
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_ADDRESS:
307
			case ISAKMP_CFG_ATTR_INTERNAL_IP6_ADDRESS:
308
				field = "Address";
309
				break;
310
			case ISAKMP_CFG_ATTR_INTERNAL_IP4_NETMASK:
311
			case ISAKMP_CFG_ATTR_INTERNAL_IP6_NETMASK:
312
				field = "Netmask";
313
				break;
314
			case ISAKMP_CFG_ATTR_INTERNAL_IP4_DNS:
315
			case ISAKMP_CFG_ATTR_INTERNAL_IP6_DNS:
316
				field = "Nameserver";
317
				break;
318
			case ISAKMP_CFG_ATTR_INTERNAL_IP4_DHCP:
319
			case ISAKMP_CFG_ATTR_INTERNAL_IP6_DHCP:
320
				field = "DHCP-server";
321
				break;
322
			case ISAKMP_CFG_ATTR_INTERNAL_IP4_NBNS:
323
			case ISAKMP_CFG_ATTR_INTERNAL_IP6_NBNS:
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);
333
			memcpy(attr + ISAKMP_ATTR_VALUE_OFF,
334
			    sockaddr_addrdata(sa), length);
335
336
			free(sa);
337
338
			off += ISAKMP_ATTR_SZ + 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_ATTRIBUTE);
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)) {
372
		log_print("cfg_initiator_recv_ATTR: "
373
		    "cfg packet ID does not match!");
374
		message_drop(msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED, 0, 1, 0);
375
		return -1;
376
	}
377
	switch (attrp->p[ISAKMP_ATTRIBUTE_TYPE_OFF]) {
378
	case ISAKMP_CFG_ACK:
379
		if (ie->cfg_type != ISAKMP_CFG_SET) {
380
			log_print("cfg_initiator_recv_ATTR: "
381
			    "bad packet type ACK");
382
			message_drop(msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED,
383
			    0, 1, 0);
384
			return -1;
385
		}
386
		break;
387
	case ISAKMP_CFG_REPLY:
388
		if (ie->cfg_type != ISAKMP_CFG_REQUEST) {
389
			log_print("cfg_initiator_recv_ATTR: "
390
			    "bad packet type REPLY");
391
			message_drop(msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED,
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_OFF]);
400
		message_drop(msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED, 0, 1, 0);
401
		return -1;
402
	}
403
404
	attribute_map(attrp->p + ISAKMP_ATTRIBUTE_ATTRS_OFF,
405
	    GET_ISAKMP_GEN_LENGTH(attrp->p) - ISAKMP_TRANSFORM_SA_ATTRS_OFF,
406
	    cfg_decode_attribute, ie);
407
408
	switch (ie->cfg_type) {
409
	case ISAKMP_CFG_ACK: {
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); attr;
417
			    attr = LIST_NEXT(attr, link))
418
				LOG_DBG((LOG_NEGOTIATION, 50,
419
				    "cfg_initiator_recv_ATTR: "
420
				    "client %s ACKs attribute %s", addr,
421
				    constant_name(isakmp_cfg_attr_cst,
422
					attr->type)));
423
424
			if (addr != uk_addr)
425
				free(addr);
426
		}
427
		break;
428
429
	case ISAKMP_CFG_REPLY: {
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); attr;
440
			    attr = LIST_NEXT(attr, link))
441
				LOG_DBG((LOG_NEGOTIATION, 50,
442
				    "cfg_initiator_recv_ATTR: "
443
				    "server %s replied with attribute %s",
444
				    addr, constant_name(isakmp_cfg_attr_cst,
445
					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_MARK;
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_ATTRIBUTE);
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);
479
	ie->cfg_type = attrp->p[ISAKMP_ATTRIBUTE_TYPE_OFF];
480
481
	switch (ie->cfg_type) {
482
	case ISAKMP_CFG_REQUEST:
483
	case ISAKMP_CFG_SET:
484
		break;
485
486
	default:
487
		message_drop(msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED, 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_OFF,
494
	    GET_ISAKMP_GEN_LENGTH(attrp->p) - ISAKMP_TRANSFORM_SA_ATTRS_OFF,
495
	    cfg_decode_attribute, ie);
496
497
	switch (ie->cfg_type) {
498
	case ISAKMP_CFG_REQUEST:
499
		/* We're done.  */
500
		break;
501
502
	case ISAKMP_CFG_SET: {
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); attr;
512
			    attr = LIST_NEXT(attr, link))
513
				LOG_DBG((LOG_NEGOTIATION, 50,
514
				    "cfg_responder_recv_ATTR: "
515
				    "server %s asks us to SET attribute %s",
516
				    addr, constant_name(isakmp_cfg_attr_cst,
517
					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_MARK;
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_REQUEST))
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_SET ?
571
	    ISAKMP_CFG_ACK : ISAKMP_CFG_REPLY), 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_ATTRIBUTE, 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_SZ + hash->hashsize);
598
	if (!hashp) {
599
		log_error("cfg_add_hash: malloc (%lu) failed",
600
		    ISAKMP_HASH_SZ + (unsigned long)hash->hashsize);
601
		return 0;
602
	}
603
	if (message_add_payload(msg, ISAKMP_PAYLOAD_HASH, hashp,
604
	    ISAKMP_HASH_SZ + 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_LEN);
626
	prf->Update(prf->prfctx, data, length);
627
	prf->Final(hashp + ISAKMP_GEN_SZ, 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_HASH);
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_INFORMATION,
644
		    0, 1, 0);
645
		return -1;
646
	}
647
	hash = hashp->p;
648
	hash_len = GET_ISAKMP_GEN_LENGTH(hash);
649
	comp_hash = malloc(hash_len - ISAKMP_GEN_SZ);
650
	if (!comp_hash) {
651
		log_error("cfg_verify_hash: malloc (%lu) failed",
652
		    (unsigned long)hash_len - ISAKMP_GEN_SZ);
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_LEN);
665
	prf->Update(prf->prfctx, hash + hash_len,
666
	    msg->iov[0].iov_len - ISAKMP_HDR_SZ - hash_len);
667
	prf->Final(comp_hash, prf->prfctx);
668
	prf_free(prf);
669
670
	if (memcmp(hash + ISAKMP_GEN_SZ, comp_hash, hash_len - ISAKMP_GEN_SZ)
671
	    != 0) {
672
		message_drop(msg, ISAKMP_NOTIFY_INVALID_HASH_INFORMATION,
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_MARK;
681
682
	/* Mark message authenticated. */
683
	msg->flags |= MSG_AUTHENTICATED;
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_MIN &&
701
	    type <= ISAKMP_CFG_ATTR_PRIVATE_MAX)
702
		return 0;
703
	if (type == 0 || type >= ISAKMP_CFG_ATTR_FUTURE_MIN) {
704
		LOG_DBG((LOG_NEGOTIATION, 30,
705
		    "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);
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_SZ;
747
	for (attr = LIST_FIRST(attrs); attr; attr = LIST_NEXT(attr, link)) {
748
		/* With ACK we only include the attrs we've actually used.  */
749
		if (type == ISAKMP_CFG_ACK && attr->attr_used == 0)
750
			continue;
751
752
		switch (attr->type) {
753
		case ISAKMP_CFG_ATTR_INTERNAL_IP4_ADDRESS:
754
		case ISAKMP_CFG_ATTR_INTERNAL_IP4_NETMASK:
755
		case ISAKMP_CFG_ATTR_INTERNAL_IP4_DHCP:
756
		case ISAKMP_CFG_ATTR_INTERNAL_IP4_DNS:
757
		case ISAKMP_CFG_ATTR_INTERNAL_IP4_NBNS:
758
		case ISAKMP_CFG_ATTR_INTERNAL_ADDRESS_EXPIRY:
759
			attr->length = 4;
760
			break;
761
762
		case ISAKMP_CFG_ATTR_INTERNAL_IP4_SUBNET:
763
			attr->length = 8;
764
			break;
765
766
		case ISAKMP_CFG_ATTR_APPLICATION_VERSION:
767
			/* XXX So far no version identifier of isakmpd here. */
768
			attr->length = 0;
769
			break;
770
771
		case ISAKMP_CFG_ATTR_SUPPORTED_ATTRIBUTES:
772
			attr->length = 2 * 15;
773
			break;
774
775
		case ISAKMP_CFG_ATTR_INTERNAL_IP6_ADDRESS:
776
		case ISAKMP_CFG_ATTR_INTERNAL_IP6_NETMASK:
777
		case ISAKMP_CFG_ATTR_INTERNAL_IP6_DHCP:
778
		case ISAKMP_CFG_ATTR_INTERNAL_IP6_DNS:
779
		case ISAKMP_CFG_ATTR_INTERNAL_IP6_NBNS:
780
			attr->length = 16;
781
			break;
782
783
		case ISAKMP_CFG_ATTR_INTERNAL_IP6_SUBNET:
784
			attr->length = 17;
785
			break;
786
787
		default:
788
			attr->ignore++;
789
			/* XXX Log!  */
790
		}
791
		*len += ISAKMP_ATTR_SZ + 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);
802
	SET_ISAKMP_ATTRIBUTE_ID(*attrp, cfg_id);
803
804
	off = ISAKMP_ATTRIBUTE_SZ;
805
	for (attr = LIST_FIRST(attrs); attr; attr = LIST_NEXT(attr, link)) {
806
		/* With ACK we only include the attrs we've actually used.  */
807
		if (type == ISAKMP_CFG_ACK && attr->attr_used == 0)
808
			continue;
809
810
		switch (attr->type) {
811
		case ISAKMP_CFG_ATTR_INTERNAL_IP4_ADDRESS:
812
		case ISAKMP_CFG_ATTR_INTERNAL_IP4_NETMASK:
813
		case ISAKMP_CFG_ATTR_INTERNAL_IP4_SUBNET:
814
		case ISAKMP_CFG_ATTR_INTERNAL_IP4_DHCP:
815
		case ISAKMP_CFG_ATTR_INTERNAL_IP4_DNS:
816
		case ISAKMP_CFG_ATTR_INTERNAL_IP4_NBNS:
817
			family = AF_INET;
818
			break;
819
820
		case ISAKMP_CFG_ATTR_INTERNAL_IP6_ADDRESS:
821
		case ISAKMP_CFG_ATTR_INTERNAL_IP6_NETMASK:
822
		case ISAKMP_CFG_ATTR_INTERNAL_IP6_SUBNET:
823
		case ISAKMP_CFG_ATTR_INTERNAL_IP6_DHCP:
824
		case ISAKMP_CFG_ATTR_INTERNAL_IP6_DNS:
825
		case ISAKMP_CFG_ATTR_INTERNAL_IP6_NBNS:
826
			family = AF_INET6;
827
			break;
828
829
		default:
830
			family = 0;
831
			break;
832
		}
833
834
		switch (attr->type) {
835
		case ISAKMP_CFG_ATTR_INTERNAL_IP4_ADDRESS:
836
		case ISAKMP_CFG_ATTR_INTERNAL_IP6_ADDRESS:
837
			field = "Address";
838
			break;
839
840
		case ISAKMP_CFG_ATTR_INTERNAL_IP4_SUBNET:
841
		case ISAKMP_CFG_ATTR_INTERNAL_IP6_SUBNET:
842
			field = "Network";	/* XXX or just "Address" */
843
			break;
844
845
		case ISAKMP_CFG_ATTR_INTERNAL_IP4_NETMASK:
846
		case ISAKMP_CFG_ATTR_INTERNAL_IP6_NETMASK:
847
			field = "Netmask";
848
			break;
849
850
		case ISAKMP_CFG_ATTR_INTERNAL_IP4_DHCP:
851
		case ISAKMP_CFG_ATTR_INTERNAL_IP6_DHCP:
852
			field = "DHCP-server";
853
			break;
854
855
		case ISAKMP_CFG_ATTR_INTERNAL_IP4_DNS:
856
		case ISAKMP_CFG_ATTR_INTERNAL_IP6_DNS:
857
			field = "Nameserver";
858
			break;
859
860
		case ISAKMP_CFG_ATTR_INTERNAL_IP4_NBNS:
861
		case ISAKMP_CFG_ATTR_INTERNAL_IP6_NBNS:
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_ADDRESS:
871
		case ISAKMP_CFG_ATTR_INTERNAL_IP6_ADDRESS:
872
		case ISAKMP_CFG_ATTR_INTERNAL_IP4_NETMASK:
873
		case ISAKMP_CFG_ATTR_INTERNAL_IP6_NETMASK:
874
		case ISAKMP_CFG_ATTR_INTERNAL_IP4_DHCP:
875
		case ISAKMP_CFG_ATTR_INTERNAL_IP6_DHCP:
876
		case ISAKMP_CFG_ATTR_INTERNAL_IP4_DNS:
877
		case ISAKMP_CFG_ATTR_INTERNAL_IP6_DNS:
878
		case ISAKMP_CFG_ATTR_INTERNAL_IP4_NBNS:
879
		case ISAKMP_CFG_ATTR_INTERNAL_IP6_NBNS:
880
			sa = conf_get_address(id_string, field);
881
			if (!sa) {
882
				LOG_DBG((LOG_NEGOTIATION, 10,
883
				    "cfg_responder_send_ATTR: "
884
				    "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_INET ? "IPv4" : "IPv6"),
893
				    (sa->sa_family ==
894
					AF_INET ? "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_SUBNET)
901
				attr->length = 4;
902
			else if (attr->type ==
903
			    ISAKMP_CFG_ATTR_INTERNAL_IP6_SUBNET)
904
				attr->length = 16;
905
906
			memcpy(*attrp + off + ISAKMP_ATTR_VALUE_OFF,
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_SUBNET) {
913
				sa = conf_get_address(id_string, "Netmask");
914
				if (!sa) {
915
					LOG_DBG((LOG_NEGOTIATION, 10,
916
					    "cfg_responder_send_ATTR: "
917
					   "attribute not found: Netmask"));
918
					attr->length = 0;
919
					break;
920
				}
921
				if (sa->sa_family != AF_INET) {
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_OFF +
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_SUBNET) {
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_OFF + 16) =
952
				    (u_int8_t)prefix;
953
				attr->length = 17;
954
			}
955
			break;
956
957
		case ISAKMP_CFG_ATTR_INTERNAL_ADDRESS_EXPIRY:
958
			value = conf_get_num(id_string, "Lifetime", 1200);
959
			encode_32(*attrp + off + ISAKMP_ATTR_VALUE_OFF, value);
960
			break;
961
962
		case ISAKMP_CFG_ATTR_APPLICATION_VERSION:
963
			/* XXX So far no version identifier of isakmpd here. */
964
			break;
965
966
		case ISAKMP_CFG_ATTR_SUPPORTED_ATTRIBUTES:
967
			break;
968
969
		default:
970
			break;
971
		}
972
973
		SET_ISAKMP_ATTR_TYPE(*attrp + off, attr->type);
974
		SET_ISAKMP_ATTR_LENGTH_VALUE(*attrp + off, attr->length);
975
		off += ISAKMP_ATTR_VALUE_OFF + attr->length;
976
	}
977
978
	return 0;
979
}