2 * Copyright (C) 2012 Andreas Steffen
3 * HSR Hochschule fuer Technik Rapperswil
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>.
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
25 #include "imv_os_state.h"
28 #include <utils/debug.h>
31 * global debug output variables
33 static int debug_level
= 1;
34 static bool stderr_quiet
= TRUE
;
39 static void pacman_dbg(debug_t group
, level_t level
, char *fmt
, ...)
41 int priority
= LOG_INFO
;
43 char *current
= buffer
, *next
;
46 if (level
<= debug_level
)
51 vfprintf(stderr
, fmt
, args
);
52 fprintf(stderr
, "\n");
56 /* write in memory buffer first */
58 vsnprintf(buffer
, sizeof(buffer
), fmt
, args
);
61 /* do a syslog with every line */
64 next
= strchr(current
, '\n');
69 syslog(priority
, "%s\n", current
);
76 * atexit handler to close everything on shutdown
78 static void cleanup(void)
84 static void usage(void)
87 "ipsec pacman --product <name> --file <filename> [--update]\n");
91 * Extract the time the package file was generated
93 static time_t extract_time(char *line
)
97 char* months
[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
98 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
101 if (sscanf(line
, "Generated: %3s %3s %2d %2d:%2d:%2d %4d UTC", wday
, mon
,
102 &t
.tm_mday
, &t
.tm_hour
, &t
.tm_min
, &t
.tm_sec
, &t
.tm_year
) != 7)
104 return UNDEFINED_TIME
;
110 for (i
= 0; i
< countof(months
); i
++)
112 if (streq(mon
, months
[i
]))
120 return UNDEFINED_TIME
;
123 return mktime(&t
) - timezone
;
127 * Process a package file and store updates in the database
129 static void process_packages(char *filename
, char *product
, bool update
)
131 char *uri
, line
[12288], *pos
;
132 int count
= 0, errored
= 0, vulnerable
= 0, new_packages
= 0;
133 int new_versions
= 0, updated_versions
= 0, deleted_versions
= 0;
139 /* opening package file */
140 printf("loading\"%s\"\n", filename
);
141 file
= fopen(filename
, "r");
144 fprintf(stderr
, "could not open \"%s\"\n", filename
);
148 /* connect package database */
149 uri
= lib
->settings
->get_str(lib
->settings
, "pacman.database", NULL
);
152 fprintf(stderr
, "database URI pacman.database not set\n");
156 db
= lib
->db
->create(lib
->db
, uri
);
159 fprintf(stderr
, "could not connect to database '%s'\n", uri
);
164 /* check if product is already in database */
165 e
= db
->query(db
, "SELECT id FROM products WHERE name = ?",
166 DB_TEXT
, product
, DB_INT
);
169 if (!e
->enumerate(e
, &pid
))
177 if (db
->execute(db
, &pid
, "INSERT INTO products (name) VALUES (?)",
178 DB_TEXT
, product
) != 1)
180 fprintf(stderr
, "could not store product '%s' to database\n",
188 while (fgets(line
, sizeof(line
), file
))
190 char *package
, *version
;
191 char *cur_version
, *version_update
= NULL
, *version_delete
= NULL
;
192 bool security
, add_version
= TRUE
;
193 int cur_security
, security_update
= 0, security_delete
= 0;
194 u_int32_t gid
= 0, vid
= 0, vid_update
= 0, vid_delete
= 0;
195 time_t gen_time
, cur_time
;
204 gen_time
= extract_time(line
);
206 if (gen_time
== UNDEFINED_TIME
)
208 fprintf(stderr
, "could not extract generation time\n");
213 printf("Generated: %T\n", &gen_time
, TRUE
);
220 /* look for the package name */
221 pos
= strchr(line
, ' ');
224 fprintf(stderr
, "could not extract package name from '%.*s'\n",
225 (int)(strlen(line
)-1), line
);
232 /* look for version string in parentheses */
236 pos
= strchr(pos
, ')');
243 fprintf(stderr
, "could not extract package version from "
244 "'%.*s'\n", (int)(strlen(line
)-1), line
);
251 /* no version information, skip entry */
254 security
= (strstr(pos
, "[security]") != NULL
);
260 /* handle non-security packages in update mode only */
261 if (!update
&& !security
)
266 /* check if package is already in database */
267 e
= db
->query(db
, "SELECT id FROM packages WHERE name = ?",
268 DB_TEXT
, package
, DB_INT
);
271 if (!e
->enumerate(e
, &gid
))
277 if (!gid
&& security
)
279 if (db
->execute(db
, &gid
, "INSERT INTO packages (name) VALUES (?)",
280 DB_TEXT
, package
) != 1)
282 fprintf(stderr
, "could not store package '%s' to database\n",
291 /* check for package versions already in database */
293 "SELECT id, release, security, time FROM versions "
294 "WHERE package = ? AND product = ?",
295 DB_INT
, gid
, DB_INT
, pid
, DB_INT
, DB_TEXT
, DB_INT
, DB_INT
);
300 while (e
->enumerate(e
, &vid
, &cur_version
, &cur_security
, &cur_time
))
302 if (streq(version
, cur_version
))
304 /* already in data base */
308 else if (gen_time
> cur_time
)
315 version_update
= strdup(cur_version
);
316 security_update
= cur_security
;
321 version_delete
= strdup(cur_version
);
322 security_delete
= cur_security
;
330 version_update
= strdup(cur_version
);
331 security_update
= cur_security
;
337 if (security
== cur_security
)
345 if ((!vid
&& !security
) || (vid
&& !add_version
))
347 free(version_update
);
348 free(version_delete
);
352 if ((!vid
&& security
) || (vid
&& !vid_update
))
354 printf("%s (%s) %s\n", package
, version
, security ?
"[s]" : "");
356 if (db
->execute(db
, &vid
,
357 "INSERT INTO versions "
358 "(package, product, release, security, time) "
359 "VALUES (?, ?, ?, ?, ?)", DB_INT
, gid
, DB_INT
, pid
,
360 DB_TEXT
, version
, DB_INT
, security
, DB_INT
, gen_time
) != 1)
362 fprintf(stderr
, "could not store version '%s' to database\n",
364 free(version_update
);
365 free(version_delete
);
374 printf("%s (%s) %s updated by\n",
375 package
, version_update
, security_update ?
"[s]" : "");
376 printf("%s (%s) %s\n", package
, version
, security ?
"[s]" : "");
378 if (db
->execute(db
, NULL
,
379 "UPDATE versions SET release = ?, time = ? WHERE id = ?",
380 DB_TEXT
, version
, DB_INT
, gen_time
, DB_INT
, vid_update
) <= 0)
382 fprintf(stderr
, "could not update version '%s' to database\n",
384 free(version_update
);
385 free(version_delete
);
395 printf("%s (%s) %s deleted\n",
396 package
, version_delete
, security_delete ?
"[s]" : "");
398 if (db
->execute(db
, NULL
,
399 "DELETE FROM versions WHERE id = ?",
400 DB_INT
, vid_delete
) <= 0)
402 fprintf(stderr
, "could not delete version '%s' from database\n",
404 free(version_update
);
405 free(version_delete
);
412 free(version_update
);
413 free(version_delete
);
418 printf("processed %d packages, %d security, %d new packages, "
419 "%d new versions, %d updated versions, %d deleted versions, "
420 "%d errored\n", count
- 6, vulnerable
, new_packages
, new_versions
,
421 updated_versions
, deleted_versions
, errored
);
424 static void do_args(int argc
, char *argv
[])
426 char *filename
= NULL
, *product
= NULL
;
429 /* reinit getopt state */
436 struct option long_opts
[] = {
437 { "help", no_argument
, NULL
, 'h' },
438 { "file", required_argument
, NULL
, 'f' },
439 { "product", required_argument
, NULL
, 'p' },
440 { "update", no_argument
, NULL
, 'u' },
444 c
= getopt_long(argc
, argv
, "", long_opts
, NULL
);
465 if (filename
&& product
)
467 process_packages(filename
, product
, update
);
476 int main(int argc
, char *argv
[])
478 /* enable attest debugging hook */
480 openlog("pacman", 0, LOG_DEBUG
);
484 /* initialize library */
485 if (!library_init(NULL
))
487 exit(SS_RC_LIBSTRONGSWAN_INTEGRITY
);
489 if (!lib
->plugins
->load(lib
->plugins
, NULL
,
490 lib
->settings
->get_str(lib
->settings
, "attest.load", "sqlite")))
492 exit(SS_RC_INITIALIZATION_FAILED
);