Fixed typo
[strongswan.git] / src / libpts / swid / swid_inventory.c
1 /*
2 * Copyright (C) 2013-2014 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 "swid_inventory.h"
17 #include "swid_tag.h"
18 #include "swid_tag_id.h"
19
20 #include <collections/linked_list.h>
21 #include <bio/bio_writer.h>
22 #include <utils/debug.h>
23
24 #include <stdio.h>
25 #include <fcntl.h>
26 #include <unistd.h>
27 #include <sys/stat.h>
28 #include <libgen.h>
29 #include <errno.h>
30
31 typedef struct private_swid_inventory_t private_swid_inventory_t;
32
33 /**
34 * Private data of a swid_inventory_t object.
35 *
36 */
37 struct private_swid_inventory_t {
38
39 /**
40 * Public swid_inventory_t interface.
41 */
42 swid_inventory_t public;
43
44 /**
45 * Full SWID tags or just SWID tag IDs
46 */
47 bool full_tags;
48
49 /**
50 * List of SWID tags or tag IDs
51 */
52 linked_list_t *list;
53 };
54
55 static status_t generate_tags(private_swid_inventory_t *this, char *generator,
56 swid_inventory_t *targets, bool pretty, bool full)
57 {
58 FILE *file;
59 char command[512], line[2048];
60 chunk_t tag_creator, unique_sw_id, tag_file_path = chunk_empty;
61 swid_tag_id_t *tag_id;
62 swid_tag_t *tag;
63 status_t status = SUCCESS;
64
65 /* Assemble the SWID generator command */
66 snprintf(command, sizeof(command), "%s %s%s%s%s\n", generator,
67 (this->full_tags) ? "swid" : "software-id",
68 (this->full_tags && pretty) ? " --pretty" : "",
69 (this->full_tags && !pretty) ? " --doc-separator $'\n\n'" : "",
70 (this->full_tags && full) ? " --full" : "");
71
72 /* Open a pipe stream for reading the output of the dpkg-query commmand */
73 file = popen(command, "r");
74 if (!file)
75 {
76 DBG1(DBG_IMC, "failed to run swid_generator command");
77 return NOT_SUPPORTED;
78 }
79 if (this->full_tags)
80 {
81 bio_writer_t *writer;
82 chunk_t tag_encoding;
83 bool more_tags = TRUE, end_of_tag;
84
85 DBG2(DBG_IMC, "SWID tags generated by package manager:");
86 while (more_tags)
87 {
88 end_of_tag = FALSE;
89 writer = bio_writer_create(512);
90 do
91 {
92 if (fgets(line, sizeof(line), file) <= 0)
93 {
94 more_tags = FALSE;
95 end_of_tag = TRUE;
96 break;
97 }
98 if (line[0] == '\n')
99 {
100 end_of_tag = TRUE;
101 break;
102 }
103 else
104 {
105 writer->write_data(writer, chunk_from_str(line));
106 }
107 }
108 while (!end_of_tag);
109
110 tag_encoding = writer->get_buf(writer);
111
112 if (tag_encoding.len > 1)
113 {
114 /* remove trailing newline if present */
115 if (tag_encoding.ptr[tag_encoding.len - 1] == '\n')
116 {
117 tag_encoding.len--;
118 }
119 DBG2(DBG_IMC, " %.*s", tag_encoding.len, tag_encoding.ptr);
120
121 tag = swid_tag_create(tag_encoding, tag_file_path);
122 this->list->insert_last(this->list, tag);
123 }
124 writer->destroy(writer);
125 }
126 }
127 else
128 {
129 DBG2(DBG_IMC, "SWID tag IDs generated by package manager:");
130 while (TRUE)
131 {
132 char *separator;
133 size_t len;
134
135 if (fgets(line, sizeof(line), file) <= 0)
136 {
137 goto end;
138 }
139 len = strlen(line);
140
141 /* remove trailing newline if present */
142 if (len > 0 && line[len - 1] == '\n')
143 {
144 len--;
145 }
146 DBG2(DBG_IMC, " %.*s", len, line);
147
148 separator = strchr(line, '_');
149 if (!separator)
150 {
151 DBG1(DBG_IMC, "separation of regid from unique software ID "
152 "failed");
153 status = FAILED;
154 goto end;
155 }
156 tag_creator = chunk_create(line, separator - line);
157 separator++;
158
159 unique_sw_id = chunk_create(separator, len - (separator - line));
160 tag_id = swid_tag_id_create(tag_creator, unique_sw_id, tag_file_path);
161 this->list->insert_last(this->list, tag_id);
162 }
163 }
164
165 end:
166 pclose(file);
167 return status;
168 }
169
170 static bool collect_tags(private_swid_inventory_t *this, char *pathname,
171 swid_inventory_t *targets)
172 {
173 char *rel_name, *abs_name;
174 struct stat st;
175 bool success = FALSE;
176 enumerator_t *enumerator;
177
178 enumerator = enumerator_create_directory(pathname);
179 if (!enumerator)
180 {
181 DBG1(DBG_IMC, "directory '%s' can not be opened, %s",
182 pathname, strerror(errno));
183 return FALSE;
184 }
185 DBG2(DBG_IMC, "entering %s", pathname);
186
187 while (enumerator->enumerate(enumerator, &rel_name, &abs_name, &st))
188 {
189 char * start, *stop;
190 chunk_t tag_creator;
191 chunk_t unique_sw_id = chunk_empty, tag_file_path = chunk_empty;
192 if (!strstr(rel_name, "regid."))
193 {
194 continue;
195 }
196 if (S_ISDIR(st.st_mode))
197 {
198 /* In case of a targeted request */
199 if (targets->get_count(targets))
200 {
201 enumerator_t *target_enumerator;
202 swid_tag_id_t *tag_id;
203 bool match = FALSE;
204
205 target_enumerator = targets->create_enumerator(targets);
206 while (target_enumerator->enumerate(target_enumerator, &tag_id))
207 {
208 if (chunk_equals(tag_id->get_tag_creator(tag_id),
209 chunk_from_str(rel_name)))
210 {
211 match = TRUE;
212 break;
213 }
214 }
215 target_enumerator->destroy(target_enumerator);
216
217 if (!match)
218 {
219 continue;
220 }
221 }
222
223 if (!collect_tags(this, abs_name, targets))
224 {
225 goto end;
226 }
227 continue;
228 }
229
230 /* parse the regid filename into its components */
231 start = rel_name;
232 stop = strchr(start, '_');
233 if (!stop)
234 {
235 DBG1(DBG_IMC, " %s", rel_name);
236 DBG1(DBG_IMC, " '_' separator not found");
237 goto end;
238 }
239 tag_creator = chunk_create(start, stop-start);
240 start = stop + 1;
241
242 stop = strstr(start, ".swidtag");
243 if (!stop)
244 {
245 DBG1(DBG_IMC, " %s", rel_name);
246 DBG1(DBG_IMC, " swidtag postfix not found");
247 goto end;
248 }
249 unique_sw_id = chunk_create(start, stop-start);
250 tag_file_path = chunk_from_str(abs_name);
251
252 /* In case of a targeted request */
253 if (targets->get_count(targets))
254 {
255 enumerator_t *target_enumerator;
256 swid_tag_id_t *tag_id;
257 bool match = FALSE;
258
259 target_enumerator = targets->create_enumerator(targets);
260 while (target_enumerator->enumerate(target_enumerator, &tag_id))
261 {
262 if (chunk_equals(tag_id->get_unique_sw_id(tag_id, NULL),
263 unique_sw_id) &&
264 chunk_equals(tag_id->get_tag_creator(tag_id),
265 tag_creator))
266 {
267 match = TRUE;
268 break;
269 }
270 }
271 target_enumerator->destroy(target_enumerator);
272
273 if (!match)
274 {
275 continue;
276 }
277 }
278 DBG2(DBG_IMC, " %s", rel_name);
279
280 if (this->full_tags)
281 {
282 swid_tag_t *tag;
283 chunk_t *xml_tag;
284
285 xml_tag = chunk_map(abs_name, FALSE);
286 if (!xml_tag)
287 {
288 DBG1(DBG_IMC, " opening '%s' failed: %s", abs_name,
289 strerror(errno));
290 goto end;
291 }
292
293 tag = swid_tag_create(*xml_tag, tag_file_path);
294 this->list->insert_last(this->list, tag);
295 chunk_unmap(xml_tag);
296 }
297 else
298 {
299 swid_tag_id_t *tag_id;
300
301 tag_id = swid_tag_id_create(tag_creator, unique_sw_id, tag_file_path);
302 this->list->insert_last(this->list, tag_id);
303 }
304 }
305 success = TRUE;
306
307 end:
308 enumerator->destroy(enumerator);
309 DBG2(DBG_IMC, "leaving %s", pathname);
310
311 return success;
312 }
313
314 METHOD(swid_inventory_t, collect, bool,
315 private_swid_inventory_t *this, char *directory, char *generator,
316 swid_inventory_t *targets, bool pretty, bool full)
317 {
318 /**
319 * Tags are generated by a package manager
320 */
321 generate_tags(this, generator, targets, pretty, full);
322
323 /**
324 * Collect swidtag files by iteratively entering all directories in
325 * the tree under the "directory" path.
326 */
327 return collect_tags(this, directory, targets);
328 }
329
330 METHOD(swid_inventory_t, add, void,
331 private_swid_inventory_t *this, void *item)
332 {
333 this->list->insert_last(this->list, item);
334 }
335
336 METHOD(swid_inventory_t, get_count, int,
337 private_swid_inventory_t *this)
338 {
339 return this->list->get_count(this->list);
340 }
341
342 METHOD(swid_inventory_t, create_enumerator, enumerator_t*,
343 private_swid_inventory_t *this)
344 {
345 return this->list->create_enumerator(this->list);
346 }
347
348 METHOD(swid_inventory_t, destroy, void,
349 private_swid_inventory_t *this)
350 {
351 if (this->full_tags)
352 {
353 this->list->destroy_offset(this->list, offsetof(swid_tag_t, destroy));
354 }
355 else
356 {
357 this->list->destroy_offset(this->list, offsetof(swid_tag_id_t, destroy));
358 }
359 free(this);
360 }
361
362 /**
363 * See header
364 */
365 swid_inventory_t *swid_inventory_create(bool full_tags)
366 {
367 private_swid_inventory_t *this;
368
369 INIT(this,
370 .public = {
371 .collect = _collect,
372 .add = _add,
373 .get_count = _get_count,
374 .create_enumerator = _create_enumerator,
375 .destroy = _destroy,
376 },
377 .full_tags = full_tags,
378 .list = linked_list_create(),
379 );
380
381 return &this->public;
382 }