Moved data structures to new collections subfolder
[strongswan.git] / src / libimcv / ietf / ietf_attr_installed_packages.c
1 /*
2 * Copyright (C) 2012 Andreas Steffen
3 * HSR Hochschule fuer Technik Rapperswil
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * for more details.
14 */
15
16 #include "ietf_attr_installed_packages.h"
17
18 #include <string.h>
19
20 #include <pa_tnc/pa_tnc_msg.h>
21 #include <bio/bio_writer.h>
22 #include <bio/bio_reader.h>
23 #include <collections/linked_list.h>
24 #include <debug.h>
25
26
27 typedef struct private_ietf_attr_installed_packages_t private_ietf_attr_installed_packages_t;
28 typedef struct package_entry_t package_entry_t;
29
30 /**
31 * PA-TNC Installed Packages Type (see section 4.2.7 of RFC 5792)
32 *
33 * 1 2 3
34 * 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
35 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
36 * | Reserved | Package Count |
37 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
38 * | Pkg Name Len | Package Name (Variable Length) |
39 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
40 * | Version Len | Package Version Number (Variable Length) |
41 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
42 */
43
44 #define INSTALLED_PACKAGES_MIN_SIZE 4
45
46 /**
47 * Private data of an ietf_attr_installed_packages_t object.
48 */
49 struct private_ietf_attr_installed_packages_t {
50
51 /**
52 * Public members of ietf_attr_installed_packages_t
53 */
54 ietf_attr_installed_packages_t public;
55
56 /**
57 * Vendor-specific attribute type
58 */
59 pen_type_t type;
60
61 /**
62 * Attribute value
63 */
64 chunk_t value;
65
66 /**
67 * Noskip flag
68 */
69 bool noskip_flag;
70
71 /**
72 * List of Installed Package entries
73 */
74 linked_list_t *packages;
75
76 /**
77 * Reference count
78 */
79 refcount_t ref;
80 };
81
82 /**
83 * Package entry
84 */
85 struct package_entry_t {
86 chunk_t name;
87 chunk_t version;
88 };
89
90 /**
91 * Free a package entry
92 */
93 static void free_package_entry(package_entry_t *entry)
94 {
95 free(entry->name.ptr);
96 free(entry->version.ptr);
97 free(entry);
98 }
99
100 METHOD(pa_tnc_attr_t, get_type, pen_type_t,
101 private_ietf_attr_installed_packages_t *this)
102 {
103 return this->type;
104 }
105
106 METHOD(pa_tnc_attr_t, get_value, chunk_t,
107 private_ietf_attr_installed_packages_t *this)
108 {
109 return this->value;
110 }
111
112 METHOD(pa_tnc_attr_t, get_noskip_flag, bool,
113 private_ietf_attr_installed_packages_t *this)
114 {
115 return this->noskip_flag;
116 }
117
118 METHOD(pa_tnc_attr_t, set_noskip_flag,void,
119 private_ietf_attr_installed_packages_t *this, bool noskip)
120 {
121 this->noskip_flag = noskip;
122 }
123
124 METHOD(pa_tnc_attr_t, build, void,
125 private_ietf_attr_installed_packages_t *this)
126 {
127 bio_writer_t *writer;
128 enumerator_t *enumerator;
129 package_entry_t *entry;
130
131 if (this->value.ptr)
132 {
133 return;
134 }
135 writer = bio_writer_create(INSTALLED_PACKAGES_MIN_SIZE);
136 writer->write_uint16(writer, 0x0000);
137 writer->write_uint16(writer, this->packages->get_count(this->packages));
138
139 enumerator = this->packages->create_enumerator(this->packages);
140 while (enumerator->enumerate(enumerator, &entry))
141 {
142 writer->write_data8(writer, entry->name);
143 writer->write_data8(writer, entry->version);
144 }
145 enumerator->destroy(enumerator);
146
147 this->value = chunk_clone(writer->get_buf(writer));
148 writer->destroy(writer);
149 }
150
151 METHOD(pa_tnc_attr_t, process, status_t,
152 private_ietf_attr_installed_packages_t *this, u_int32_t *offset)
153 {
154 bio_reader_t *reader;
155 package_entry_t *entry;
156 status_t status = FAILED;
157 chunk_t name, version;
158 u_int16_t reserved, count;
159 u_char *pos;
160
161 *offset = 0;
162
163 if (this->value.len < INSTALLED_PACKAGES_MIN_SIZE)
164 {
165 DBG1(DBG_TNC, "insufficient data for IETF installed packages");
166 return FAILED;
167 }
168 reader = bio_reader_create(this->value);
169 reader->read_uint16(reader, &reserved);
170 reader->read_uint16(reader, &count);
171 *offset = INSTALLED_PACKAGES_MIN_SIZE;
172
173 while (reader->remaining(reader))
174 {
175 if (!reader->read_data8(reader, &name))
176 {
177 DBG1(DBG_TNC, "insufficient data for IETF installed package name");
178 goto end;
179 }
180 pos = memchr(name.ptr, '\0', name.len);
181 if (pos)
182 {
183 DBG1(DBG_TNC, "nul termination in IETF installed package name");
184 *offset += 1 + (pos - name.ptr);
185 goto end;
186 }
187 *offset += 1 + name.len;
188
189 if (!reader->read_data8(reader, &version))
190 {
191 DBG1(DBG_TNC, "insufficient data for IETF installed package version");
192 goto end;
193 }
194 pos = memchr(version.ptr, '\0', version.len);
195 if (pos)
196 {
197 DBG1(DBG_TNC, "nul termination in IETF installed package version");
198 *offset += 1 + (pos - version.ptr);
199 goto end;
200 }
201 *offset += 1 + version.len;
202
203 entry = malloc_thing(package_entry_t);
204 entry->name = chunk_clone(name);
205 entry->version = chunk_clone(version);
206 this->packages->insert_last(this->packages, entry);
207 }
208
209 if (count != this->packages->get_count(this->packages))
210 {
211 DBG1(DBG_TNC, "IETF installed package count unequal to "
212 "number of included packages");
213 goto end;
214 }
215 status = SUCCESS;
216
217 end:
218 reader->destroy(reader);
219 return status;
220 }
221
222 METHOD(pa_tnc_attr_t, get_ref, pa_tnc_attr_t*,
223 private_ietf_attr_installed_packages_t *this)
224 {
225 ref_get(&this->ref);
226 return &this->public.pa_tnc_attribute;
227 }
228
229 METHOD(pa_tnc_attr_t, destroy, void,
230 private_ietf_attr_installed_packages_t *this)
231 {
232 if (ref_put(&this->ref))
233 {
234 this->packages->destroy_function(this->packages, (void*)free_package_entry);
235 free(this->value.ptr);
236 free(this);
237 }
238 }
239
240 METHOD(ietf_attr_installed_packages_t, add, void,
241 private_ietf_attr_installed_packages_t *this, chunk_t name, chunk_t version)
242 {
243 package_entry_t *entry;
244
245 /* restrict package name and package version number fields to 255 octets */
246 name.len = min(255, name.len);
247 version.len = min(255, version.len);
248
249 entry = malloc_thing(package_entry_t);
250 entry->name = chunk_clone(name);
251 entry->version = chunk_clone(version);
252 this->packages->insert_last(this->packages, entry);
253 }
254
255 /**
256 * Enumerate package filter entries
257 */
258 static bool package_filter(void *null, package_entry_t **entry, chunk_t *name,
259 void *i2, chunk_t *version)
260 {
261 *name = (*entry)->name;
262 *version = (*entry)->version;
263 return TRUE;
264 }
265
266 METHOD(ietf_attr_installed_packages_t, create_enumerator, enumerator_t*,
267 private_ietf_attr_installed_packages_t *this)
268 {
269 return enumerator_create_filter(
270 this->packages->create_enumerator(this->packages),
271 (void*)package_filter, NULL, NULL);
272 }
273
274 /**
275 * Described in header.
276 */
277 pa_tnc_attr_t *ietf_attr_installed_packages_create(void)
278 {
279 private_ietf_attr_installed_packages_t *this;
280
281 INIT(this,
282 .public = {
283 .pa_tnc_attribute = {
284 .get_type = _get_type,
285 .get_value = _get_value,
286 .get_noskip_flag = _get_noskip_flag,
287 .set_noskip_flag = _set_noskip_flag,
288 .build = _build,
289 .process = _process,
290 .get_ref = _get_ref,
291 .destroy = _destroy,
292 },
293 .add = _add,
294 .create_enumerator = _create_enumerator,
295 },
296 .type = { PEN_IETF, IETF_ATTR_INSTALLED_PACKAGES },
297 .packages = linked_list_create(),
298 .ref = 1,
299 );
300
301 return &this->public.pa_tnc_attribute;
302 }
303
304 /**
305 * Described in header.
306 */
307 pa_tnc_attr_t *ietf_attr_installed_packages_create_from_data(chunk_t data)
308 {
309 private_ietf_attr_installed_packages_t *this;
310
311 INIT(this,
312 .public = {
313 .pa_tnc_attribute = {
314 .get_type = _get_type,
315 .get_value = _get_value,
316 .build = _build,
317 .process = _process,
318 .get_ref = _get_ref,
319 .destroy = _destroy,
320 },
321 .add = _add,
322 .create_enumerator = _create_enumerator,
323 },
324 .type = {PEN_IETF, IETF_ATTR_INSTALLED_PACKAGES },
325 .value = chunk_clone(data),
326 .packages = linked_list_create(),
327 .ref = 1,
328 );
329
330 return &this->public.pa_tnc_attribute;
331 }
332
333