]> git.ipfire.org Git - thirdparty/strongswan.git/blame - src/libimcv/swid/swid_inventory.c
swid-gen: Share SWID generator between sw-collector, imc-swima and imc-swid
[thirdparty/strongswan.git] / src / libimcv / swid / swid_inventory.c
CommitLineData
4e2a1762 1/*
6795de04 2 * Copyright (C) 2013-2017 Andreas Steffen
4e2a1762
AS
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 "swid_inventory.h"
17#include "swid_tag.h"
18#include "swid_tag_id.h"
88501a64 19#include "swid_gen/swid_gen.h"
4e2a1762
AS
20
21#include <collections/linked_list.h>
88501a64 22#include <utils/lexparser.h>
4e2a1762
AS
23#include <utils/debug.h>
24
25#include <stdio.h>
26#include <fcntl.h>
27#include <unistd.h>
28#include <sys/stat.h>
4e2a1762
AS
29#include <libgen.h>
30#include <errno.h>
31
32typedef struct private_swid_inventory_t private_swid_inventory_t;
33
4e2a1762
AS
34/**
35 * Private data of a swid_inventory_t object.
36 *
37 */
38struct private_swid_inventory_t {
39
40 /**
41 * Public swid_inventory_t interface.
42 */
43 swid_inventory_t public;
44
45 /**
46 * Full SWID tags or just SWID tag IDs
47 */
48 bool full_tags;
49
50 /**
51 * List of SWID tags or tag IDs
52 */
53 linked_list_t *list;
54};
55
88501a64
AS
56static status_t generate_tags(private_swid_inventory_t *this,
57 swid_inventory_t *targets, bool pretty, bool full)
8c40609f 58{
88501a64 59 swid_gen_t *swid_gen;
8c40609f 60 swid_tag_t *tag;
b7679e90 61 swid_tag_id_t *tag_id;
88501a64 62 enumerator_t *enumerator;
b7679e90 63 status_t status = SUCCESS;
88501a64
AS
64 chunk_t out;
65
66 swid_gen = swid_gen_create();
b7679e90
AS
67
68 if (targets->get_count(targets) == 0)
69 {
88501a64
AS
70 DBG2(DBG_IMC, "SWID tag%s generation by package manager",
71 this->full_tags ? "" : " ID");
b7679e90 72
88501a64
AS
73 enumerator = swid_gen->create_tag_enumerator(swid_gen, !this->full_tags,
74 full, pretty);
75 if (enumerator)
b7679e90 76 {
88501a64
AS
77 while (enumerator->enumerate(enumerator, &out))
78 {
79 if (this->full_tags)
80 {
81 chunk_t swid_tag = out;
b7679e90 82
88501a64
AS
83 tag = swid_tag_create(swid_tag, chunk_empty);
84 this->list->insert_last(this->list, tag);
85 }
86 else
87 {
88 chunk_t tag_creator, sw_id = out;
89
90 if (extract_token_str(&tag_creator, "__", &sw_id))
91 {
92 tag_id = swid_tag_id_create(tag_creator, sw_id,
93 chunk_empty);
94 this->list->insert_last(this->list, tag_id);
95 }
96 else
97 {
98 DBG1(DBG_IMC, "separation of regid from unique "
99 "software ID failed");
100 status = FAILED;
101 chunk_free(&out);
102 break;
103 }
104 }
105 chunk_free(&out);
106 }
107 enumerator->destroy(enumerator);
b7679e90
AS
108 }
109 else
110 {
88501a64 111 status = NOT_SUPPORTED;
b7679e90 112 }
b7679e90
AS
113 }
114 else if (this->full_tags)
115 {
88501a64 116 DBG2(DBG_IMC, "targeted SWID tag generation");
f82d7aff 117
b7679e90
AS
118 enumerator = targets->create_enumerator(targets);
119 while (enumerator->enumerate(enumerator, &tag_id))
120 {
88501a64
AS
121 char software_id[BUF_LEN], *swid_tag;
122 chunk_t tag_creator, sw_id;
b7679e90 123
88501a64 124 /* Construct software ID from tag creator and unique software ID */
b7679e90 125 tag_creator = tag_id->get_tag_creator(tag_id);
88501a64
AS
126 sw_id = tag_id->get_unique_sw_id(tag_id, NULL);
127 snprintf(software_id, BUF_LEN, "%.*s__%.*s",
128 tag_creator.len, tag_creator.ptr, sw_id.len, sw_id.ptr);
8c40609f 129
88501a64
AS
130 swid_tag = swid_gen->generate_tag(swid_gen, software_id, NULL, NULL,
131 full, pretty);
132 if (swid_tag)
8c40609f 133 {
88501a64
AS
134 tag = swid_tag_create(chunk_from_str(swid_tag), chunk_empty);
135 this->list->insert_last(this->list, tag);
136 free(swid_tag);
8c40609f 137 }
8c40609f 138 }
b7679e90 139 enumerator->destroy(enumerator);
8c40609f 140 }
88501a64 141 swid_gen->destroy(swid_gen);
8c40609f 142
8c40609f
AS
143 return status;
144}
145
3adffcd9 146static bool collect_tags(private_swid_inventory_t *this, char *pathname,
6795de04 147 swid_inventory_t *targets, bool is_swidtag_dir)
4e2a1762
AS
148{
149 char *rel_name, *abs_name;
150 struct stat st;
151 bool success = FALSE;
152 enumerator_t *enumerator;
153
154 enumerator = enumerator_create_directory(pathname);
155 if (!enumerator)
156 {
d1696c0e 157 DBG1(DBG_IMC, "directory '%s' can not be opened, %s",
4e2a1762
AS
158 pathname, strerror(errno));
159 return FALSE;
160 }
6795de04
AS
161 if (is_swidtag_dir)
162 {
163 DBG2(DBG_IMC, "entering %s", pathname);
164 }
751670a9 165
4e2a1762
AS
166 while (enumerator->enumerate(enumerator, &rel_name, &abs_name, &st))
167 {
6795de04 168 char *separator, *suffix;
4e2a1762 169 chunk_t tag_creator;
8c40609f 170 chunk_t unique_sw_id = chunk_empty, tag_file_path = chunk_empty;
b7679e90 171
4e2a1762
AS
172 if (S_ISDIR(st.st_mode))
173 {
6795de04
AS
174 if (!collect_tags(this, abs_name, targets, is_swidtag_dir ||
175 streq(rel_name, "swidtag")))
4e2a1762
AS
176 {
177 goto end;
178 }
179 continue;
180 }
6795de04
AS
181 if (!is_swidtag_dir)
182 {
183 continue;
184 }
4e2a1762 185
6795de04
AS
186 /* found a swidtag file? */
187 suffix = strstr(rel_name, ".swidtag");
188 if (!suffix)
4e2a1762 189 {
6795de04 190 continue;
4e2a1762 191 }
4e2a1762 192
6795de04 193 /* parse the swidtag filename into its components */
88501a64 194 separator = strstr(rel_name, "__");
6795de04 195 if (!separator)
4e2a1762 196 {
3adffcd9 197 DBG1(DBG_IMC, " %s", rel_name);
88501a64 198 DBG1(DBG_IMC, " '__' separator not found");
4e2a1762
AS
199 goto end;
200 }
6795de04
AS
201 tag_creator = chunk_create(rel_name, separator-rel_name);
202
88501a64 203 unique_sw_id = chunk_create(separator+2, suffix-separator-2);
8c40609f 204 tag_file_path = chunk_from_str(abs_name);
4e2a1762 205
3adffcd9
AS
206 /* In case of a targeted request */
207 if (targets->get_count(targets))
208 {
b7679e90 209 chunk_t target_unique_sw_id, target_tag_creator;
3adffcd9
AS
210 enumerator_t *target_enumerator;
211 swid_tag_id_t *tag_id;
212 bool match = FALSE;
213
214 target_enumerator = targets->create_enumerator(targets);
215 while (target_enumerator->enumerate(target_enumerator, &tag_id))
216 {
b7679e90
AS
217 target_unique_sw_id = tag_id->get_unique_sw_id(tag_id, NULL);
218 target_tag_creator = tag_id->get_tag_creator(tag_id);
219
220 if (chunk_equals(target_unique_sw_id, unique_sw_id) &&
6795de04 221 chunk_equals(target_tag_creator, tag_creator))
3adffcd9
AS
222 {
223 match = TRUE;
224 break;
225 }
226 }
227 target_enumerator->destroy(target_enumerator);
228
229 if (!match)
230 {
231 continue;
232 }
233 }
234 DBG2(DBG_IMC, " %s", rel_name);
235
4e2a1762
AS
236 if (this->full_tags)
237 {
238 swid_tag_t *tag;
85349815 239 chunk_t *xml_tag;
4e2a1762 240
85349815
MW
241 xml_tag = chunk_map(abs_name, FALSE);
242 if (!xml_tag)
4e2a1762 243 {
d1696c0e 244 DBG1(DBG_IMC, " opening '%s' failed: %s", abs_name,
6795de04 245 strerror(errno));
4e2a1762
AS
246 goto end;
247 }
248
8c40609f 249 tag = swid_tag_create(*xml_tag, tag_file_path);
4e2a1762 250 this->list->insert_last(this->list, tag);
85349815 251 chunk_unmap(xml_tag);
4e2a1762
AS
252 }
253 else
254 {
255 swid_tag_id_t *tag_id;
256
8c40609f 257 tag_id = swid_tag_id_create(tag_creator, unique_sw_id, tag_file_path);
4e2a1762
AS
258 this->list->insert_last(this->list, tag_id);
259 }
260 }
261 success = TRUE;
262
263end:
264 enumerator->destroy(enumerator);
6795de04
AS
265 if (is_swidtag_dir)
266 {
267 DBG2(DBG_IMC, "leaving %s", pathname);
268 }
4e2a1762
AS
269
270 return success;
271}
272
273METHOD(swid_inventory_t, collect, bool,
88501a64
AS
274 private_swid_inventory_t *this, char *directory, swid_inventory_t *targets,
275 bool pretty, bool full)
4e2a1762 276{
8c40609f
AS
277 /**
278 * Tags are generated by a package manager
279 */
88501a64 280 generate_tags(this, targets, pretty, full);
8c40609f
AS
281
282 /**
283 * Collect swidtag files by iteratively entering all directories in
284 * the tree under the "directory" path.
285 */
6795de04 286 return collect_tags(this, directory, targets, FALSE);
4e2a1762
AS
287}
288
289METHOD(swid_inventory_t, add, void,
290 private_swid_inventory_t *this, void *item)
291{
292 this->list->insert_last(this->list, item);
293}
294
295METHOD(swid_inventory_t, get_count, int,
296 private_swid_inventory_t *this)
297{
298 return this->list->get_count(this->list);
299}
300
301METHOD(swid_inventory_t, create_enumerator, enumerator_t*,
302 private_swid_inventory_t *this)
303{
304 return this->list->create_enumerator(this->list);
305}
306
307METHOD(swid_inventory_t, destroy, void,
308 private_swid_inventory_t *this)
309{
310 if (this->full_tags)
311 {
312 this->list->destroy_offset(this->list, offsetof(swid_tag_t, destroy));
313 }
314 else
315 {
316 this->list->destroy_offset(this->list, offsetof(swid_tag_id_t, destroy));
317 }
318 free(this);
319}
320
321/**
322 * See header
323 */
324swid_inventory_t *swid_inventory_create(bool full_tags)
325{
326 private_swid_inventory_t *this;
327
328 INIT(this,
329 .public = {
330 .collect = _collect,
331 .add = _add,
332 .get_count = _get_count,
333 .create_enumerator = _create_enumerator,
334 .destroy = _destroy,
335 },
336 .full_tags = full_tags,
337 .list = linked_list_create(),
338 );
339
340 return &this->public;
341}