payloads: Verify P-CSCF configuration attributes like others carrying IP addresses
[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 case P_CSCF_IP4_ADDRESS:
136 if (this->length_or_value != 0 && this->length_or_value != 4)
137 {
138 failed = TRUE;
139 }
140 break;
141 case INTERNAL_IP4_SUBNET:
142 if (this->length_or_value != 0 && this->length_or_value != 8)
143 {
144 failed = TRUE;
145 }
146 break;
147 case INTERNAL_IP6_ADDRESS:
148 if (this->type == PLV1_CONFIGURATION_ATTRIBUTE &&
149 this->length_or_value == 16)
150 { /* 16 bytes are correct for IKEv1, but older releases sent a
151 * prefix byte so we still accept 0 or 17 as in IKEv2 */
152 break;
153 }
154 /* fall-through */
155 case INTERNAL_IP6_SUBNET:
156 if (this->length_or_value != 0 && this->length_or_value != 17)
157 {
158 failed = TRUE;
159 }
160 break;
161 case INTERNAL_IP6_DNS:
162 case INTERNAL_IP6_NBNS:
163 case INTERNAL_IP6_DHCP:
164 case P_CSCF_IP6_ADDRESS:
165 if (this->length_or_value != 0 && this->length_or_value != 16)
166 {
167 failed = TRUE;
168 }
169 break;
170 case SUPPORTED_ATTRIBUTES:
171 if (this->length_or_value % 2)
172 {
173 failed = TRUE;
174 }
175 break;
176 case APPLICATION_VERSION:
177 case INTERNAL_IP4_SERVER:
178 case INTERNAL_IP6_SERVER:
179 case XAUTH_TYPE:
180 case XAUTH_USER_NAME:
181 case XAUTH_USER_PASSWORD:
182 case XAUTH_PASSCODE:
183 case XAUTH_MESSAGE:
184 case XAUTH_CHALLENGE:
185 case XAUTH_DOMAIN:
186 case XAUTH_STATUS:
187 case XAUTH_NEXT_PIN:
188 case XAUTH_ANSWER:
189 case UNITY_BANNER:
190 case UNITY_SAVE_PASSWD:
191 case UNITY_DEF_DOMAIN:
192 case UNITY_SPLITDNS_NAME:
193 case UNITY_SPLIT_INCLUDE:
194 case UNITY_NATT_PORT:
195 case UNITY_LOCAL_LAN:
196 case UNITY_PFS:
197 case UNITY_FW_TYPE:
198 case UNITY_BACKUP_SERVERS:
199 case UNITY_DDNS_HOSTNAME:
200 /* any length acceptable */
201 break;
202 default:
203 DBG1(DBG_ENC, "unknown attribute type %N",
204 configuration_attribute_type_names, this->attr_type);
205 break;
206 }
207
208 if (failed)
209 {
210 DBG1(DBG_ENC, "invalid attribute length %d for %N",
211 this->length_or_value, configuration_attribute_type_names,
212 this->attr_type);
213 return FAILED;
214 }
215 return SUCCESS;
216 }
217
218 METHOD(payload_t, get_encoding_rules, int,
219 private_configuration_attribute_t *this, encoding_rule_t **rules)
220 {
221 if (this->type == PLV2_CONFIGURATION_ATTRIBUTE)
222 {
223 *rules = encodings_v2;
224 return countof(encodings_v2);
225 }
226 *rules = encodings_v1;
227 return countof(encodings_v1);
228 }
229
230 METHOD(payload_t, get_header_length, int,
231 private_configuration_attribute_t *this)
232 {
233 return 4;
234 }
235
236 METHOD(payload_t, get_type, payload_type_t,
237 private_configuration_attribute_t *this)
238 {
239 return this->type;
240 }
241
242 METHOD(payload_t, get_next_type, payload_type_t,
243 private_configuration_attribute_t *this)
244 {
245 return PL_NONE;
246 }
247
248 METHOD(payload_t, set_next_type, void,
249 private_configuration_attribute_t *this, payload_type_t type)
250 {
251 }
252
253 METHOD(payload_t, get_length, size_t,
254 private_configuration_attribute_t *this)
255 {
256 return get_header_length(this) + this->value.len;
257 }
258
259 METHOD(configuration_attribute_t, get_cattr_type, configuration_attribute_type_t,
260 private_configuration_attribute_t *this)
261 {
262 return this->attr_type;
263 }
264
265 METHOD(configuration_attribute_t, get_chunk, chunk_t,
266 private_configuration_attribute_t *this)
267 {
268 if (this->af_flag)
269 {
270 return chunk_from_thing(this->length_or_value);
271 }
272 return this->value;
273 }
274
275 METHOD(configuration_attribute_t, get_value, u_int16_t,
276 private_configuration_attribute_t *this)
277 {
278 if (this->af_flag)
279 {
280 return this->length_or_value;
281 }
282 return 0;
283 }
284
285 METHOD2(payload_t, configuration_attribute_t, destroy, void,
286 private_configuration_attribute_t *this)
287 {
288 free(this->value.ptr);
289 free(this);
290 }
291
292 /*
293 * Described in header.
294 */
295 configuration_attribute_t *configuration_attribute_create(payload_type_t type)
296 {
297 private_configuration_attribute_t *this;
298
299 INIT(this,
300 .public = {
301 .payload_interface = {
302 .verify = _verify,
303 .get_encoding_rules = _get_encoding_rules,
304 .get_header_length = _get_header_length,
305 .get_length = _get_length,
306 .get_next_type = _get_next_type,
307 .set_next_type = _set_next_type,
308 .get_type = _get_type,
309 .destroy = _destroy,
310 },
311 .get_chunk = _get_chunk,
312 .get_value = _get_value,
313 .get_type = _get_cattr_type,
314 .destroy = _destroy,
315 },
316 .type = type
317 );
318 return &this->public;
319 }
320
321 /*
322 * Described in header.
323 */
324 configuration_attribute_t *configuration_attribute_create_chunk(
325 payload_type_t type, configuration_attribute_type_t attr_type, chunk_t chunk)
326 {
327 private_configuration_attribute_t *this;
328
329 this = (private_configuration_attribute_t*)
330 configuration_attribute_create(type);
331 this->attr_type = ((u_int16_t)attr_type) & 0x7FFF;
332 this->value = chunk_clone(chunk);
333 this->length_or_value = chunk.len;
334
335 return &this->public;
336 }
337
338 /*
339 * Described in header.
340 */
341 configuration_attribute_t *configuration_attribute_create_value(
342 configuration_attribute_type_t attr_type, u_int16_t value)
343 {
344 private_configuration_attribute_t *this;
345
346 this = (private_configuration_attribute_t*)
347 configuration_attribute_create(PLV1_CONFIGURATION_ATTRIBUTE);
348 this->attr_type = ((u_int16_t)attr_type) & 0x7FFF;
349 this->length_or_value = value;
350 this->af_flag = TRUE;
351
352 return &this->public;
353 }
354