]> git.ipfire.org Git - thirdparty/strongswan.git/blob - src/libimcv/pa_tnc/pa_tnc_attr_manager.c
Update copyright headers after acquisition by secunet
[thirdparty/strongswan.git] / src / libimcv / pa_tnc / pa_tnc_attr_manager.c
1 /*
2 * Copyright (C) 2011-2014 Andreas Steffen
3 *
4 *
5 * Copyright (C) secunet Security Networks AG
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 "pa_tnc_attr_manager.h"
19
20 #include "imcv.h"
21 #include "pa_tnc_attr.h"
22 #include "ietf/ietf_attr_pa_tnc_error.h"
23
24 #include <collections/linked_list.h>
25 #include <utils/debug.h>
26
27 typedef struct private_pa_tnc_attr_manager_t private_pa_tnc_attr_manager_t;
28 typedef struct entry_t entry_t;
29
30 struct entry_t {
31 pen_t vendor_id;
32 enum_name_t *attr_names;
33 pa_tnc_attr_create_t attr_create;
34 };
35
36 /**
37 * Private data of a pa_tnc_attr_manager_t object.
38 *
39 */
40 struct private_pa_tnc_attr_manager_t {
41
42 /**
43 * Public pa_tnc_attr_manager_t interface.
44 */
45 pa_tnc_attr_manager_t public;
46
47 /**
48 * List of PA-TNC vendor attributes
49 */
50 linked_list_t *list;
51 };
52
53 METHOD(pa_tnc_attr_manager_t, add_vendor, void,
54 private_pa_tnc_attr_manager_t *this, pen_t vendor_id,
55 pa_tnc_attr_create_t attr_create, enum_name_t *attr_names)
56 {
57 entry_t *entry;
58
59 entry = malloc_thing(entry_t);
60 entry->vendor_id = vendor_id;
61 entry->attr_create = attr_create;
62 entry->attr_names = attr_names;
63
64 this->list->insert_last(this->list, entry);
65 DBG2(DBG_TNC, "added %N attributes", pen_names, vendor_id);
66 }
67
68 METHOD(pa_tnc_attr_manager_t, remove_vendor, void,
69 private_pa_tnc_attr_manager_t *this, pen_t vendor_id)
70 {
71 enumerator_t *enumerator;
72 entry_t *entry;
73
74 enumerator = this->list->create_enumerator(this->list);
75 while (enumerator->enumerate(enumerator, &entry))
76 {
77 if (entry->vendor_id == vendor_id)
78 {
79 this->list->remove_at(this->list, enumerator);
80 free(entry);
81 DBG2(DBG_TNC, "removed %N attributes", pen_names, vendor_id);
82 }
83 }
84 enumerator->destroy(enumerator);
85 }
86
87 METHOD(pa_tnc_attr_manager_t, get_names, enum_name_t*,
88 private_pa_tnc_attr_manager_t *this, pen_t vendor_id)
89 {
90 enumerator_t *enumerator;
91 entry_t *entry;
92 enum_name_t *attr_names = NULL;
93
94 enumerator = this->list->create_enumerator(this->list);
95 while (enumerator->enumerate(enumerator, &entry))
96 {
97 if (entry->vendor_id == vendor_id)
98 {
99 attr_names = entry->attr_names;
100 break;
101 }
102 }
103 enumerator->destroy(enumerator);
104
105 return attr_names;
106 }
107
108 /**
109 * PA-TNC attribute
110 *
111 * 1 2 3
112 * 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
113 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
114 * | Flags | PA-TNC Attribute Vendor ID |
115 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
116 * | PA-TNC Attribute Type |
117 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
118 * | PA-TNC Attribute Length |
119 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
120 * | Attribute Value (Variable Length) |
121 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
122 */
123
124 METHOD(pa_tnc_attr_manager_t, create, pa_tnc_attr_t*,
125 private_pa_tnc_attr_manager_t *this, bio_reader_t *reader, bool segmented,
126 uint32_t *offset, chunk_t msg_info, pa_tnc_attr_t **error)
127 {
128 uint8_t flags;
129 uint32_t type, length, value_len;
130 chunk_t value;
131 ietf_attr_pa_tnc_error_t *error_attr;
132 pen_t vendor_id;
133 pen_type_t unsupported_type;
134 pen_type_t error_code = { PEN_IETF, PA_ERROR_INVALID_PARAMETER };
135 pa_tnc_attr_t *attr = NULL;
136 enumerator_t *enumerator;
137 entry_t *entry;
138
139 /* properly initialize error return argument in case of no error */
140 *error = NULL;
141
142 if (reader->remaining(reader) < PA_TNC_ATTR_HEADER_SIZE)
143 {
144 DBG1(DBG_TNC, "insufficient bytes for PA-TNC attribute header");
145 *error = ietf_attr_pa_tnc_error_create_with_offset(error_code,
146 msg_info, *offset);
147 return NULL;
148 }
149 reader->read_uint8 (reader, &flags);
150 reader->read_uint24(reader, &vendor_id);
151 reader->read_uint32(reader, &type);
152 reader->read_uint32(reader, &length);
153
154 imcv_list_pa_tnc_attribute_type("processing", vendor_id, type);
155
156 if (length < PA_TNC_ATTR_HEADER_SIZE)
157 {
158 DBG1(DBG_TNC, "%u bytes too small for PA-TNC attribute length",
159 length);
160 *error = ietf_attr_pa_tnc_error_create_with_offset(error_code,
161 msg_info, *offset + PA_TNC_ATTR_INFO_SIZE);
162 return NULL;
163 }
164 length -= PA_TNC_ATTR_HEADER_SIZE;
165 value_len = segmented ? reader->remaining(reader) : length;
166
167 if (!reader->read_data(reader, value_len, &value))
168 {
169 DBG1(DBG_TNC, "insufficient bytes for PA-TNC attribute value");
170 *error = ietf_attr_pa_tnc_error_create_with_offset(error_code,
171 msg_info, *offset + PA_TNC_ATTR_INFO_SIZE);
172 return NULL;
173 }
174 DBG3(DBG_TNC, "%B", &value);
175
176 if (vendor_id == PEN_RESERVED)
177 {
178 *error = ietf_attr_pa_tnc_error_create_with_offset(error_code,
179 msg_info, *offset + 1);
180 return NULL;
181 }
182 if (type == IETF_ATTR_RESERVED)
183 {
184 *error = ietf_attr_pa_tnc_error_create_with_offset(error_code,
185 msg_info, *offset + 4);
186 return NULL;
187 }
188
189 /* check if the attribute type is registered */
190 enumerator = this->list->create_enumerator(this->list);
191 while (enumerator->enumerate(enumerator, &entry))
192 {
193 if (entry->vendor_id == vendor_id)
194 {
195 if (entry->attr_create)
196 {
197 attr = entry->attr_create(type, length, value);
198 }
199 break;
200 }
201 }
202 enumerator->destroy(enumerator);
203
204 if (!attr)
205 {
206 if (!(flags & PA_TNC_ATTR_FLAG_NOSKIP))
207 {
208 DBG1(DBG_TNC, "skipping unsupported PA-TNC attribute");
209 (*offset) += PA_TNC_ATTR_HEADER_SIZE + length;
210 return NULL;
211 }
212
213 DBG1(DBG_TNC, "unsupported PA-TNC attribute with NOSKIP flag");
214 unsupported_type = pen_type_create(vendor_id, type);
215 error_code = pen_type_create(PEN_IETF, PA_ERROR_ATTR_TYPE_NOT_SUPPORTED);
216 *error = ietf_attr_pa_tnc_error_create(error_code, msg_info);
217 error_attr = (ietf_attr_pa_tnc_error_t*)(*error);
218 error_attr->set_unsupported_attr(error_attr, flags, unsupported_type);
219 return NULL;
220 }
221 (*offset) += PA_TNC_ATTR_HEADER_SIZE;
222
223 return attr;
224 }
225
226 METHOD(pa_tnc_attr_manager_t, construct, pa_tnc_attr_t*,
227 private_pa_tnc_attr_manager_t *this, pen_t vendor_id, uint32_t type,
228 chunk_t value)
229 {
230 enum_name_t *pa_attr_names;
231 pa_tnc_attr_t *attr = NULL;
232 enumerator_t *enumerator;
233 entry_t *entry;
234
235 pa_attr_names = imcv_pa_tnc_attributes->get_names(imcv_pa_tnc_attributes,
236 vendor_id);
237 if (pa_attr_names)
238 {
239 DBG2(DBG_TNC, "generating PA-TNC attribute type '%N/%N' "
240 "0x%06x/0x%08x", pen_names, vendor_id,
241 pa_attr_names, type, vendor_id, type);
242 }
243 else
244 {
245 DBG2(DBG_TNC, "generating PA-TNC attribute type '%N' "
246 "0x%06x/0x%08x", pen_names, vendor_id,
247 vendor_id, type);
248 }
249 enumerator = this->list->create_enumerator(this->list);
250 while (enumerator->enumerate(enumerator, &entry))
251 {
252 if (entry->vendor_id == vendor_id)
253 {
254 if (entry->attr_create)
255 {
256 attr = entry->attr_create(type, value.len, value);
257 }
258 break;
259 }
260 }
261 enumerator->destroy(enumerator);
262 return attr;
263 }
264
265 METHOD(pa_tnc_attr_manager_t, destroy, void,
266 private_pa_tnc_attr_manager_t *this)
267 {
268 this->list->destroy_function(this->list, free);
269 free(this);
270 }
271
272 /**
273 * See header
274 */
275 pa_tnc_attr_manager_t *pa_tnc_attr_manager_create(void)
276 {
277 private_pa_tnc_attr_manager_t *this;
278
279 INIT(this,
280 .public = {
281 .add_vendor = _add_vendor,
282 .remove_vendor = _remove_vendor,
283 .get_names = _get_names,
284 .create = _create,
285 .construct = _construct,
286 .destroy = _destroy,
287 },
288 .list = linked_list_create(),
289 );
290
291 return &this->public;
292 }
293