0bc94708fc09ceeb9a834f381964a7b52769a4d5
[strongswan.git] / src / libcharon / encoding / payloads / configuration_attribute.c
1 /*
2 * Copyright (C) 2005-2010 Martin Willi
3 * Copyright (C) 2010 revosec AG
4 * Copyright (C) 2005 Jan Hutter
5 * Hochschule fuer Technik Rapperswil
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2 of the License, or (at your
10 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 * for more details.
16 */
17
18 #include <stddef.h>
19
20 #include "configuration_attribute.h"
21
22 #include <encoding/payloads/encodings.h>
23 #include <library.h>
24 #include <daemon.h>
25
26 typedef struct private_configuration_attribute_t private_configuration_attribute_t;
27
28 /**
29 * Private data of an configuration_attribute_t object.
30 */
31 struct private_configuration_attribute_t {
32
33 /**
34 * Public configuration_attribute_t interface.
35 */
36 configuration_attribute_t public;
37
38 /**
39 * Value encoded in length field?
40 */
41 bool af_flag;
42
43 /**
44 * Reserved bit (af_flag in IKEv2)
45 */
46 bool reserved;
47
48 /**
49 * Type of the attribute.
50 */
51 u_int16_t attr_type;
52
53 /**
54 * Length of the attribute, value if af_flag set.
55 */
56 u_int16_t length_or_value;
57
58 /**
59 * Attribute value as chunk.
60 */
61 chunk_t value;
62
63 /**
64 * Payload type, PLV2_CONFIGURATION_ATTRIBUTE or DATA_ATTRIBUTE_V1
65 */
66 payload_type_t type;
67 };
68
69 /**
70 * Encoding rules for a IKEv2 configuration attribute / IKEv1 data attribute
71 */
72 static encoding_rule_t encodings_v2[] = {
73 /* 1 reserved bit */
74 { RESERVED_BIT, offsetof(private_configuration_attribute_t, reserved) },
75 /* type of the attribute as 15 bit unsigned integer */
76 { ATTRIBUTE_TYPE, offsetof(private_configuration_attribute_t, attr_type) },
77 /* Length of attribute value */
78 { ATTRIBUTE_LENGTH, offsetof(private_configuration_attribute_t, length_or_value)},
79 /* Value of attribute if attribute format flag is zero */
80 { ATTRIBUTE_VALUE, offsetof(private_configuration_attribute_t, value) },
81 };
82
83 /*
84 1 2 3
85 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
86 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
87 !R| Attribute Type ! Length |
88 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
89 | |
90 ~ Value ~
91 | |
92 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
93 */
94
95 /**
96 * Encoding rules for a IKEv1 data attribute
97 */
98 static encoding_rule_t encodings_v1[] = {
99 /* AF Flag */
100 { ATTRIBUTE_FORMAT, offsetof(private_configuration_attribute_t, af_flag) },
101 /* type of the attribute as 15 bit unsigned integer */
102 { ATTRIBUTE_TYPE, offsetof(private_configuration_attribute_t, attr_type) },
103 /* Length of attribute value */
104 { ATTRIBUTE_LENGTH_OR_VALUE, offsetof(private_configuration_attribute_t, length_or_value)},
105 /* Value of attribute if attribute format flag is zero */
106 { ATTRIBUTE_VALUE, offsetof(private_configuration_attribute_t, value) },
107 };
108
109 /*
110 1 2 3
111 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
112 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
113 !F| Attribute Type ! Length |
114 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
115 | |
116 ~ Value ~
117 | |
118 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
119 */
120
121
122 METHOD(payload_t, verify, status_t,
123 private_configuration_attribute_t *this)
124 {
125 bool failed = FALSE;
126
127 switch (this->attr_type)
128 {
129 case INTERNAL_IP4_ADDRESS:
130 case INTERNAL_IP4_NETMASK:
131 case INTERNAL_IP4_DNS:
132 case INTERNAL_IP4_NBNS:
133 case INTERNAL_ADDRESS_EXPIRY:
134 case INTERNAL_IP4_DHCP:
135 if (this->length_or_value != 0 && this->length_or_value != 4)
136 {
137 failed = TRUE;
138 }
139 break;
140 case INTERNAL_IP4_SUBNET:
141 if (this->length_or_value != 0 && this->length_or_value != 8)
142 {
143 failed = TRUE;
144 }
145 break;
146 case INTERNAL_IP6_ADDRESS:
147 if (this->type == PLV1_CONFIGURATION_ATTRIBUTE &&
148 this->length_or_value == 16)
149 { /* 16 bytes are correct for IKEv1, but older releases sent a
150 * prefix byte so we still accept 0 or 17 as in IKEv2 */
151 break;
152 }
153 /* fall-through */
154 case INTERNAL_IP6_SUBNET:
155 if (this->length_or_value != 0 && this->length_or_value != 17)
156 {
157 failed = TRUE;
158 }
159 break;
160 case INTERNAL_IP6_DNS:
161 case INTERNAL_IP6_NBNS:
162 case INTERNAL_IP6_DHCP:
163 if (this->length_or_value != 0 && this->length_or_value != 16)
164 {
165 failed = TRUE;
166 }
167 break;
168 case SUPPORTED_ATTRIBUTES:
169 if (this->length_or_value % 2)
170 {
171 failed = TRUE;
172 }
173 break;
174 case APPLICATION_VERSION:
175 case INTERNAL_IP4_SERVER:
176 case INTERNAL_IP6_SERVER:
177 case XAUTH_TYPE:
178 case XAUTH_USER_NAME:
179 case XAUTH_USER_PASSWORD:
180 case XAUTH_PASSCODE:
181 case XAUTH_MESSAGE:
182 case XAUTH_CHALLENGE:
183 case XAUTH_DOMAIN:
184 case XAUTH_STATUS:
185 case XAUTH_NEXT_PIN:
186 case XAUTH_ANSWER:
187 case UNITY_BANNER:
188 case UNITY_SAVE_PASSWD:
189 case UNITY_DEF_DOMAIN:
190 case UNITY_SPLITDNS_NAME:
191 case UNITY_SPLIT_INCLUDE:
192 case UNITY_NATT_PORT:
193 case UNITY_LOCAL_LAN:
194 case UNITY_PFS:
195 case UNITY_FW_TYPE:
196 case UNITY_BACKUP_SERVERS:
197 case UNITY_DDNS_HOSTNAME:
198 /* any length acceptable */
199 break;
200 default:
201 DBG1(DBG_ENC, "unknown attribute type %N",
202 configuration_attribute_type_names, this->attr_type);
203 break;
204 }
205
206 if (failed)
207 {
208 DBG1(DBG_ENC, "invalid attribute length %d for %N",
209 this->length_or_value, configuration_attribute_type_names,
210 this->attr_type);
211 return FAILED;
212 }
213 return SUCCESS;
214 }
215
216 METHOD(payload_t, get_encoding_rules, int,
217 private_configuration_attribute_t *this, encoding_rule_t **rules)
218 {
219 if (this->type == PLV2_CONFIGURATION_ATTRIBUTE)
220 {
221 *rules = encodings_v2;
222 return countof(encodings_v2);
223 }
224 *rules = encodings_v1;
225 return countof(encodings_v1);
226 }
227
228 METHOD(payload_t, get_header_length, int,
229 private_configuration_attribute_t *this)
230 {
231 return 4;
232 }
233
234 METHOD(payload_t, get_type, payload_type_t,
235 private_configuration_attribute_t *this)
236 {
237 return this->type;
238 }
239
240 METHOD(payload_t, get_next_type, payload_type_t,
241 private_configuration_attribute_t *this)
242 {
243 return PL_NONE;
244 }
245
246 METHOD(payload_t, set_next_type, void,
247 private_configuration_attribute_t *this, payload_type_t type)
248 {
249 }
250
251 METHOD(payload_t, get_length, size_t,
252 private_configuration_attribute_t *this)
253 {
254 return get_header_length(this) + this->value.len;
255 }
256
257 METHOD(configuration_attribute_t, get_cattr_type, configuration_attribute_type_t,
258 private_configuration_attribute_t *this)
259 {
260 return this->attr_type;
261 }
262
263 METHOD(configuration_attribute_t, get_chunk, chunk_t,
264 private_configuration_attribute_t *this)
265 {
266 if (this->af_flag)
267 {
268 return chunk_from_thing(this->length_or_value);
269 }
270 return this->value;
271 }
272
273 METHOD(configuration_attribute_t, get_value, u_int16_t,
274 private_configuration_attribute_t *this)
275 {
276 if (this->af_flag)
277 {
278 return this->length_or_value;
279 }
280 return 0;
281 }
282
283 METHOD2(payload_t, configuration_attribute_t, destroy, void,
284 private_configuration_attribute_t *this)
285 {
286 free(this->value.ptr);
287 free(this);
288 }
289
290 /*
291 * Described in header.
292 */
293 configuration_attribute_t *configuration_attribute_create(payload_type_t type)
294 {
295 private_configuration_attribute_t *this;
296
297 INIT(this,
298 .public = {
299 .payload_interface = {
300 .verify = _verify,
301 .get_encoding_rules = _get_encoding_rules,
302 .get_header_length = _get_header_length,
303 .get_length = _get_length,
304 .get_next_type = _get_next_type,
305 .set_next_type = _set_next_type,
306 .get_type = _get_type,
307 .destroy = _destroy,
308 },
309 .get_chunk = _get_chunk,
310 .get_value = _get_value,
311 .get_type = _get_cattr_type,
312 .destroy = _destroy,
313 },
314 .type = type
315 );
316 return &this->public;
317 }
318
319 /*
320 * Described in header.
321 */
322 configuration_attribute_t *configuration_attribute_create_chunk(
323 payload_type_t type, configuration_attribute_type_t attr_type, chunk_t chunk)
324 {
325 private_configuration_attribute_t *this;
326
327 this = (private_configuration_attribute_t*)
328 configuration_attribute_create(type);
329 this->attr_type = ((u_int16_t)attr_type) & 0x7FFF;
330 this->value = chunk_clone(chunk);
331 this->length_or_value = chunk.len;
332
333 return &this->public;
334 }
335
336 /*
337 * Described in header.
338 */
339 configuration_attribute_t *configuration_attribute_create_value(
340 configuration_attribute_type_t attr_type, u_int16_t value)
341 {
342 private_configuration_attribute_t *this;
343
344 this = (private_configuration_attribute_t*)
345 configuration_attribute_create(PLV1_CONFIGURATION_ATTRIBUTE);
346 this->attr_type = ((u_int16_t)attr_type) & 0x7FFF;
347 this->length_or_value = value;
348 this->af_flag = TRUE;
349
350 return &this->public;
351 }
352