/src/strongswan/src/libimcv/ita/ita_attr_settings.c
Line | Count | Source |
1 | | /* |
2 | | * Copyright (C) 2012-2014 Andreas Steffen |
3 | | * |
4 | | * Copyright (C) secunet Security Networks AG |
5 | | * |
6 | | * This program is free software; you can redistribute it and/or modify it |
7 | | * under the terms of the GNU General Public License as published by the |
8 | | * Free Software Foundation; either version 2 of the License, or (at your |
9 | | * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. |
10 | | * |
11 | | * This program is distributed in the hope that it will be useful, but |
12 | | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY |
13 | | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
14 | | * for more details. |
15 | | */ |
16 | | |
17 | | #define _GNU_SOURCE /* for stdndup() */ |
18 | | #include <string.h> |
19 | | |
20 | | #include "ita_attr.h" |
21 | | #include "ita_attr_settings.h" |
22 | | |
23 | | #include <bio/bio_reader.h> |
24 | | #include <bio/bio_writer.h> |
25 | | #include <collections/linked_list.h> |
26 | | #include <pen/pen.h> |
27 | | #include <utils/debug.h> |
28 | | |
29 | | typedef struct private_ita_attr_settings_t private_ita_attr_settings_t; |
30 | | typedef struct entry_t entry_t; |
31 | | |
32 | | /** |
33 | | * Contains a settings name/value pair |
34 | | */ |
35 | | struct entry_t { |
36 | | char *name; |
37 | | chunk_t value; |
38 | | }; |
39 | | |
40 | | /** |
41 | | * Free an entry_t object |
42 | | */ |
43 | | static void free_entry(entry_t *this) |
44 | 96.6k | { |
45 | 96.6k | free(this->name); |
46 | 96.6k | free(this->value.ptr); |
47 | 96.6k | free(this); |
48 | 96.6k | } |
49 | | |
50 | | /** |
51 | | * ITA Settings |
52 | | * |
53 | | * 1 2 3 |
54 | | * 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 |
55 | | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
56 | | * | Settings Count | |
57 | | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
58 | | * | Name Length | Name (Variable Length) ~ |
59 | | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
60 | | * ~ Name (Variable Length) ~ |
61 | | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
62 | | * | Value Length | Value (Variable Length) ~ |
63 | | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
64 | | * ~ Value (Variable Length) ~ |
65 | | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
66 | | * | Name Length | Name (Variable Length) ~ |
67 | | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
68 | | * ~ Name (Variable Length) ~ |
69 | | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
70 | | * | Value Length | Value (Variable Length) ~ |
71 | | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
72 | | * ~ Value (Variable Length) ~ |
73 | | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
74 | | * ........................... |
75 | | */ |
76 | | |
77 | 1.52k | #define ITA_SETTINGS_MIN_SIZE 4 |
78 | | |
79 | | /** |
80 | | * Private data of an ita_attr_settings_t object. |
81 | | */ |
82 | | struct private_ita_attr_settings_t { |
83 | | |
84 | | /** |
85 | | * Public members of ita_attr_settings_t |
86 | | */ |
87 | | ita_attr_settings_t public; |
88 | | |
89 | | /** |
90 | | * Vendor-specific attribute type |
91 | | */ |
92 | | pen_type_t type; |
93 | | |
94 | | /** |
95 | | * Length of attribute value |
96 | | */ |
97 | | size_t length; |
98 | | |
99 | | /** |
100 | | * Attribute value or segment |
101 | | */ |
102 | | chunk_t value; |
103 | | |
104 | | /** |
105 | | * Noskip flag |
106 | | */ |
107 | | bool noskip_flag; |
108 | | |
109 | | /** |
110 | | * List of settings |
111 | | */ |
112 | | linked_list_t *list; |
113 | | |
114 | | /** |
115 | | * Reference count |
116 | | */ |
117 | | refcount_t ref; |
118 | | }; |
119 | | |
120 | | METHOD(pa_tnc_attr_t, get_type, pen_type_t, |
121 | | private_ita_attr_settings_t *this) |
122 | 1.04k | { |
123 | 1.04k | return this->type; |
124 | 1.04k | } |
125 | | |
126 | | METHOD(pa_tnc_attr_t, get_value, chunk_t, |
127 | | private_ita_attr_settings_t *this) |
128 | 765 | { |
129 | 765 | return this->value; |
130 | 765 | } |
131 | | |
132 | | METHOD(pa_tnc_attr_t, get_noskip_flag, bool, |
133 | | private_ita_attr_settings_t *this) |
134 | 654 | { |
135 | 654 | return this->noskip_flag; |
136 | 654 | } |
137 | | |
138 | | METHOD(pa_tnc_attr_t, set_noskip_flag,void, |
139 | | private_ita_attr_settings_t *this, bool noskip) |
140 | 0 | { |
141 | 0 | this->noskip_flag = noskip; |
142 | 0 | } |
143 | | |
144 | | METHOD(pa_tnc_attr_t, build, void, |
145 | | private_ita_attr_settings_t *this) |
146 | 0 | { |
147 | 0 | bio_writer_t *writer; |
148 | 0 | enumerator_t *enumerator; |
149 | 0 | entry_t *entry; |
150 | |
|
151 | 0 | if (this->value.ptr) |
152 | 0 | { |
153 | 0 | return; |
154 | 0 | } |
155 | 0 | writer = bio_writer_create(ITA_SETTINGS_MIN_SIZE); |
156 | 0 | writer->write_uint32(writer, this->list->get_count(this->list)); |
157 | |
|
158 | 0 | enumerator = this->list->create_enumerator(this->list); |
159 | 0 | while (enumerator->enumerate(enumerator, &entry)) |
160 | 0 | { |
161 | 0 | writer->write_data16(writer, chunk_create(entry->name, |
162 | 0 | strlen(entry->name))); |
163 | 0 | writer->write_data16(writer, entry->value); |
164 | 0 | } |
165 | 0 | enumerator->destroy(enumerator); |
166 | |
|
167 | 0 | this->value = writer->extract_buf(writer); |
168 | 0 | this->length = this->value.len; |
169 | 0 | writer->destroy(writer); |
170 | 0 | } |
171 | | |
172 | | METHOD(pa_tnc_attr_t, process, status_t, |
173 | | private_ita_attr_settings_t *this, uint32_t *offset) |
174 | 765 | { |
175 | 765 | bio_reader_t *reader; |
176 | 765 | uint32_t count; |
177 | 765 | chunk_t name, value; |
178 | 765 | entry_t *entry; |
179 | 765 | status_t status = FAILED; |
180 | | |
181 | 765 | *offset = 0; |
182 | | |
183 | 765 | if (this->value.len < this->length) |
184 | 0 | { |
185 | 0 | return NEED_MORE; |
186 | 0 | } |
187 | 765 | if (this->value.len < ITA_SETTINGS_MIN_SIZE) |
188 | 10 | { |
189 | 10 | DBG1(DBG_TNC, "insufficient data for ITA Settings attribute"); |
190 | 10 | return FAILED; |
191 | 10 | } |
192 | | |
193 | 755 | reader = bio_reader_create(this->value); |
194 | 755 | reader->read_uint32(reader, &count); |
195 | | |
196 | 755 | *offset = ITA_SETTINGS_MIN_SIZE; |
197 | | |
198 | 97.4k | while (count--) |
199 | 96.7k | { |
200 | 96.7k | if (!reader->read_data16(reader, &name)) |
201 | 85 | { |
202 | 85 | DBG1(DBG_TNC, "insufficient data for setting name"); |
203 | 85 | goto end; |
204 | 85 | } |
205 | 96.6k | *offset += 2 + name.len; |
206 | | |
207 | 96.6k | if (!reader->read_data16(reader, &value)) |
208 | 16 | { |
209 | 16 | DBG1(DBG_TNC, "insufficient data for setting value"); |
210 | 16 | goto end; |
211 | 16 | } |
212 | 96.6k | *offset += 2 + value.len; |
213 | | |
214 | | /* remove a terminating newline character */ |
215 | 96.6k | if (value.len && value.ptr[value.len - 1] == '\n') |
216 | 225 | { |
217 | 225 | value.len--; |
218 | 225 | } |
219 | 96.6k | entry = malloc_thing(entry_t); |
220 | 96.6k | entry->name = strndup(name.ptr, name.len); |
221 | 96.6k | entry->value = chunk_clone(value); |
222 | 96.6k | this->list->insert_last(this->list, entry); |
223 | 96.6k | } |
224 | 654 | status = SUCCESS; |
225 | | |
226 | 755 | end: |
227 | 755 | reader->destroy(reader); |
228 | 755 | return status; |
229 | 654 | } |
230 | | |
231 | | METHOD(pa_tnc_attr_t, add_segment, void, |
232 | | private_ita_attr_settings_t *this, chunk_t segment) |
233 | 0 | { |
234 | 0 | this->value = chunk_cat("mc", this->value, segment); |
235 | 0 | } |
236 | | |
237 | | METHOD(pa_tnc_attr_t, get_ref, pa_tnc_attr_t*, |
238 | | private_ita_attr_settings_t *this) |
239 | 0 | { |
240 | 0 | ref_get(&this->ref); |
241 | 0 | return &this->public.pa_tnc_attribute; |
242 | 0 | } |
243 | | |
244 | | METHOD(pa_tnc_attr_t, destroy, void, |
245 | | private_ita_attr_settings_t *this) |
246 | 765 | { |
247 | 765 | if (ref_put(&this->ref)) |
248 | 765 | { |
249 | 765 | this->list->destroy_function(this->list, (void*)free_entry); |
250 | 765 | free(this->value.ptr); |
251 | 765 | free(this); |
252 | 765 | } |
253 | 765 | } |
254 | | |
255 | | METHOD(ita_attr_settings_t, add, void, |
256 | | private_ita_attr_settings_t *this, char *name, chunk_t value) |
257 | 0 | { |
258 | 0 | entry_t *entry; |
259 | |
|
260 | 0 | entry = malloc_thing(entry_t); |
261 | 0 | entry->name = strdup(name); |
262 | 0 | entry->value = chunk_clone(value); |
263 | 0 | this->list->insert_last(this->list, entry); |
264 | 0 | } |
265 | | |
266 | | CALLBACK(entry_filter, bool, |
267 | | void *null, enumerator_t *orig, va_list args) |
268 | 0 | { |
269 | 0 | entry_t *entry; |
270 | 0 | chunk_t *value; |
271 | 0 | char **name; |
272 | |
|
273 | 0 | VA_ARGS_VGET(args, name, value); |
274 | |
|
275 | 0 | while (orig->enumerate(orig, &entry)) |
276 | 0 | { |
277 | 0 | *name = entry->name; |
278 | 0 | *value = entry->value; |
279 | 0 | return TRUE; |
280 | 0 | } |
281 | 0 | return FALSE; |
282 | 0 | } |
283 | | |
284 | | METHOD(ita_attr_settings_t, create_enumerator, enumerator_t*, |
285 | | private_ita_attr_settings_t *this) |
286 | 0 | { |
287 | 0 | return enumerator_create_filter(this->list->create_enumerator(this->list), |
288 | 0 | entry_filter, NULL, NULL); |
289 | 0 | } |
290 | | |
291 | | /** |
292 | | * Described in header. |
293 | | */ |
294 | | pa_tnc_attr_t *ita_attr_settings_create(void) |
295 | 0 | { |
296 | 0 | private_ita_attr_settings_t *this; |
297 | |
|
298 | 0 | INIT(this, |
299 | 0 | .public = { |
300 | 0 | .pa_tnc_attribute = { |
301 | 0 | .get_type = _get_type, |
302 | 0 | .get_value = _get_value, |
303 | 0 | .get_noskip_flag = _get_noskip_flag, |
304 | 0 | .set_noskip_flag = _set_noskip_flag, |
305 | 0 | .build = _build, |
306 | 0 | .process = _process, |
307 | 0 | .add_segment = _add_segment, |
308 | 0 | .get_ref = _get_ref, |
309 | 0 | .destroy = _destroy, |
310 | 0 | }, |
311 | 0 | .add = _add, |
312 | 0 | .create_enumerator = _create_enumerator, |
313 | 0 | }, |
314 | 0 | .type = { PEN_ITA, ITA_ATTR_SETTINGS }, |
315 | 0 | .list = linked_list_create(), |
316 | 0 | .ref = 1, |
317 | 0 | ); |
318 | |
|
319 | 0 | return &this->public.pa_tnc_attribute; |
320 | 0 | } |
321 | | |
322 | | /** |
323 | | * Described in header. |
324 | | */ |
325 | | pa_tnc_attr_t *ita_attr_settings_create_from_data(size_t length, chunk_t data) |
326 | 765 | { |
327 | 765 | private_ita_attr_settings_t *this; |
328 | | |
329 | 765 | INIT(this, |
330 | 765 | .public = { |
331 | 765 | .pa_tnc_attribute = { |
332 | 765 | .get_type = _get_type, |
333 | 765 | .get_value = _get_value, |
334 | 765 | .get_noskip_flag = _get_noskip_flag, |
335 | 765 | .set_noskip_flag = _set_noskip_flag, |
336 | 765 | .build = _build, |
337 | 765 | .process = _process, |
338 | 765 | .add_segment = _add_segment, |
339 | 765 | .get_ref = _get_ref, |
340 | 765 | .destroy = _destroy, |
341 | 765 | }, |
342 | 765 | .add = _add, |
343 | 765 | .create_enumerator = _create_enumerator, |
344 | 765 | }, |
345 | 765 | .type = { PEN_ITA, ITA_ATTR_SETTINGS }, |
346 | 765 | .length = length, |
347 | 765 | .value = chunk_clone(data), |
348 | 765 | .list = linked_list_create(), |
349 | 765 | .ref = 1, |
350 | 765 | ); |
351 | | |
352 | 765 | return &this->public.pa_tnc_attribute; |
353 | 765 | } |
354 | | |
355 | | |