diff options
Diffstat (limited to 'src/libimcv/plugins/imv_os/pacman.c')
-rw-r--r-- | src/libimcv/plugins/imv_os/pacman.c | 489 |
1 files changed, 236 insertions, 253 deletions
diff --git a/src/libimcv/plugins/imv_os/pacman.c b/src/libimcv/plugins/imv_os/pacman.c index 25e63760b..57cc62a08 100644 --- a/src/libimcv/plugins/imv_os/pacman.c +++ b/src/libimcv/plugins/imv_os/pacman.c @@ -21,12 +21,33 @@ #include <errno.h> #include <syslog.h> #include <time.h> +#include <sys/stat.h> #include "imv_os_state.h" #include <library.h> #include <utils/debug.h> +typedef enum pacman_state_t pacman_state_t; + +enum pacman_state_t { + PACMAN_STATE_BEGIN_PACKAGE, + PACMAN_STATE_VERSION, + PACMAN_STATE_END_PACKAGE +}; + +typedef struct stats_t stats_t; + +struct stats_t { + time_t release; + int product; + int packages; + int new_packages; + int new_versions; + int updated_versions; + int deleted_versions; +}; + /** * global debug output variables */ @@ -88,54 +109,186 @@ static void usage(void) } /** - * Extract the time the package file was generated + * Update the package database */ -static time_t extract_time(char *line) +static bool update_database(database_t *db, char *package, char *version, + bool security, stats_t *stats) { - struct tm t; - char wday[4], mon[4]; - char* months[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", - "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; - int i; - - if (sscanf(line, "Generated: %3s %3s %2d %2d:%2d:%2d %4d UTC", wday, mon, - &t.tm_mday, &t.tm_hour, &t.tm_min, &t.tm_sec, &t.tm_year) != 7) + char *cur_version, *version_update = NULL, *version_delete = NULL; + int cur_security, security_update = 0, security_delete = 0; + int pac_id = 0, vid = 0, vid_update = 0, vid_delete = 0; + u_int cur_time; + bool add_version = TRUE; + enumerator_t *e; + + /* increment package count */ + stats->packages++; + + /* check if package is already in database */ + e = db->query(db, "SELECT id FROM packages WHERE name = ?", + DB_TEXT, package, DB_INT); + if (!e) { - return UNDEFINED_TIME; + return FALSE; } - t.tm_isdst = 0; - t.tm_year -= 1900; - t.tm_mon = 12; + if (!e->enumerate(e, &pac_id)) + { + pac_id = 0; + } + e->destroy(e); - for (i = 0; i < countof(months); i++) + if (!pac_id && security) { - if (streq(mon, months[i])) + if (db->execute(db, &pac_id, "INSERT INTO packages (name) VALUES (?)", + DB_TEXT, package) != 1) { - t.tm_mon = i; + fprintf(stderr, "could not store package '%s' to database\n", + package); + return FALSE; + } + stats->new_packages++; + } + + /* check for package versions already in database */ + e = db->query(db, + "SELECT id, release, security, time FROM versions " + "WHERE package = ? AND product = ?", DB_INT, pac_id, + DB_INT, stats->product, DB_INT, DB_TEXT, DB_INT, DB_UINT); + if (!e) + { + return FALSE; + } + + while (e->enumerate(e, &vid, &cur_version, &cur_security, &cur_time)) + { + if (streq(version, cur_version)) + { + /* already in data base */ + add_version = FALSE; break; } + else if (stats->release >= cur_time) + { + if (security) + { + if (cur_security) + { + vid_update = vid; + version_update = strdup(cur_version); + security_update = cur_security; + } + else + { + vid_delete = vid; + version_delete = strdup(cur_version); + security_delete = cur_security; + } + } + else + { + if (!cur_security) + { + vid_update = vid; + version_update = strdup(cur_version); + security_update = cur_security; + } + } + } + else + { + if (security == cur_security) + { + add_version = FALSE; + } + } + } + e->destroy(e); + + if ((!vid && !security) || (vid && !add_version)) + { + free(version_update); + free(version_delete); + return TRUE; + } + + if ((!vid && security) || (vid && !vid_update)) + { + printf("%s (%s) %s\n", package, version, security ? "[s]" : ""); + + if (db->execute(db, &vid, + "INSERT INTO versions " + "(package, product, release, security, time) " + "VALUES (?, ?, ?, ?, ?)", DB_INT, pac_id, DB_INT, stats->product, + DB_TEXT, version, DB_INT, security, DB_INT, stats->release) != 1) + { + fprintf(stderr, "could not store version '%s' to database\n", + version); + free(version_update); + free(version_delete); + return FALSE; + } + stats->new_versions++; + } + else + { + printf("%s (%s) %s updated by\n", + package, version_update, security_update ? "[s]" : ""); + printf("%s (%s) %s\n", package, version, security ? "[s]" : ""); + + if (db->execute(db, NULL, + "UPDATE versions SET release = ?, time = ? WHERE id = ?", + DB_TEXT, version, DB_INT, stats->release, DB_INT, vid_update) <= 0) + { + fprintf(stderr, "could not update version '%s' to database\n", + version); + free(version_update); + free(version_delete); + return FALSE; + } + stats->updated_versions++; } - if (t.tm_mon == 12) + + if (vid_delete) { - return UNDEFINED_TIME; + printf("%s (%s) %s deleted\n", + package, version_delete, security_delete ? "[s]" : ""); + if (db->execute(db, NULL, + "DELETE FROM versions WHERE id = ?", + DB_INT, vid_delete) <= 0) + { + fprintf(stderr, "could not delete version '%s' from database\n", + version_delete); + free(version_update); + free(version_delete); + return FALSE; + } + stats->deleted_versions++; } + free(version_update); + free(version_delete); - return mktime(&t) - timezone; + return TRUE; } /** * Process a package file and store updates in the database */ -static void process_packages(char *filename, char *product, bool update) +static void process_packages(char *filename, char *product, bool security) { - char *uri, line[12288], *pos; - int count = 0, errored = 0, vulnerable = 0, new_packages = 0; - int new_versions = 0, updated_versions = 0, deleted_versions = 0; - time_t gen_time; - u_int32_t pid = 0; + char *uri, line[BUF_LEN], *pos, *package = NULL, *version = NULL; + pacman_state_t pacman_state; enumerator_t *e; database_t *db; + int pid; FILE *file; + stats_t stats; + bool success; + + /* initialize statistics */ + memset(&stats, 0x00, sizeof(stats_t)); + + /* Set release date to current time */ + stats.release = time(NULL); /* opening package file */ printf("loading\"%s\"\n", filename); @@ -167,13 +320,13 @@ static void process_packages(char *filename, char *product, bool update) DB_TEXT, product, DB_INT); if (e) { - if (!e->enumerate(e, &pid)) + if (e->enumerate(e, &pid)) { - pid = 0; + stats.product = pid; } e->destroy(e); } - if (!pid) + if (!stats.product) { if (db->execute(db, &pid, "INSERT INTO products (name) VALUES (?)", DB_TEXT, product) != 1) @@ -184,248 +337,78 @@ static void process_packages(char *filename, char *product, bool update) db->destroy(db); exit(EXIT_FAILURE); } + stats.product = pid; } + pacman_state = PACMAN_STATE_BEGIN_PACKAGE; + while (fgets(line, sizeof(line), file)) { - char *package, *version; - char *cur_version, *version_update = NULL, *version_delete = NULL; - bool security, add_version = TRUE; - int cur_security, security_update = 0, security_delete = 0; - u_int32_t gid = 0, vid = 0, vid_update = 0, vid_delete = 0; - time_t cur_time; - - count++; - if (count == 1) - { - printf("%s", line); - } - if (count == 3) - { - gen_time = extract_time(line); - - if (gen_time == UNDEFINED_TIME) - { - fprintf(stderr, "could not extract generation time\n"); - fclose(file); - db->destroy(db); - exit(EXIT_FAILURE); - } - printf("Generated: %T\n", &gen_time, TRUE); - } - if (count < 7) - { - continue; - } + /* set read pointer to beginning of line */ + pos = line; - /* look for the package name */ - pos = strchr(line, ' '); - if (!pos) + switch (pacman_state) { - fprintf(stderr, "could not extract package name from '%.*s'\n", - (int)(strlen(line)-1), line); - errored++; - continue; - } - *pos++ = '\0'; - package = line; - - /* look for version string in parentheses */ - if (*pos == '(') - { - version = ++pos; - pos = strchr(pos, ')'); - if (pos) - { - *pos++ = '\0'; - } - else - { - fprintf(stderr, "could not extract package version from " - "'%.*s'\n", (int)(strlen(line)-1), line); - errored++; - continue; - } - } - else - { - /* no version information, skip entry */ - continue; - } - security = (strstr(pos, "[security]") != NULL); - if (security) - { - vulnerable++; - } - - /* handle non-security packages in update mode only */ - if (!update && !security) - { - continue; - } - - /* check if package is already in database */ - e = db->query(db, "SELECT id FROM packages WHERE name = ?", - DB_TEXT, package, DB_INT); - if (e) - { - if (!e->enumerate(e, &gid)) - { - gid = 0; - } - e->destroy(e); - } - if (!gid && security) - { - if (db->execute(db, &gid, "INSERT INTO packages (name) VALUES (?)", - DB_TEXT, package) != 1) - { - fprintf(stderr, "could not store package '%s' to database\n", - package); - fclose(file); - db->destroy(db); - exit(EXIT_FAILURE); - } - new_packages++; - } - - /* check for package versions already in database */ - e = db->query(db, - "SELECT id, release, security, time FROM versions " - "WHERE package = ? AND product = ?", - DB_INT, gid, DB_INT, pid, DB_INT, DB_TEXT, DB_INT, DB_INT); - if (!e) - { - break; - } - while (e->enumerate(e, &vid, &cur_version, &cur_security, &cur_time)) - { - if (streq(version, cur_version)) - { - /* already in data base */ - add_version = FALSE; + case PACMAN_STATE_BEGIN_PACKAGE: + pos = strstr(pos, "Package: "); + if (!pos) + { + continue; + } + pos += 9; + package = pos; + pos = strchr(pos, '\n'); + if (pos) + { + package = strndup(package, pos - package); + pacman_state = PACMAN_STATE_VERSION; + } break; - } - else if (gen_time > cur_time) - { - if (security) + case PACMAN_STATE_VERSION: + pos = strstr(pos, "Version: "); + if (!pos) { - if (cur_security) - { - vid_update = vid; - version_update = strdup(cur_version); - security_update = cur_security; - } - else - { - vid_delete = vid; - version_delete = strdup(cur_version); - security_delete = cur_security; - } + continue; } - else + pos += 9; + version = pos; + pos = strchr(pos, '\n'); + if (pos) { - if (!cur_security) - { - vid_update = vid; - version_update = strdup(cur_version); - security_update = cur_security; - } + version = strndup(version, pos - version); + pacman_state = PACMAN_STATE_END_PACKAGE; } - } - else - { - if (security == cur_security) + break; + case PACMAN_STATE_END_PACKAGE: + if (*pos != '\n') { - add_version = FALSE; + continue; } - } - } - e->destroy(e); - - if ((!vid && !security) || (vid && !add_version)) - { - free(version_update); - free(version_delete); - continue; - } - - if ((!vid && security) || (vid && !vid_update)) - { - printf("%s (%s) %s\n", package, version, security ? "[s]" : ""); - - if (db->execute(db, &vid, - "INSERT INTO versions " - "(package, product, release, security, time) " - "VALUES (?, ?, ?, ?, ?)", DB_INT, gid, DB_INT, pid, - DB_TEXT, version, DB_INT, security, DB_INT, gen_time) != 1) - { - fprintf(stderr, "could not store version '%s' to database\n", - version); - free(version_update); - free(version_delete); - fclose(file); - db->destroy(db); - exit(EXIT_FAILURE); - } - new_versions++; - } - else - { - printf("%s (%s) %s updated by\n", - package, version_update, security_update ? "[s]" : ""); - printf("%s (%s) %s\n", package, version, security ? "[s]" : ""); - - if (db->execute(db, NULL, - "UPDATE versions SET release = ?, time = ? WHERE id = ?", - DB_TEXT, version, DB_INT, gen_time, DB_INT, vid_update) <= 0) - { - fprintf(stderr, "could not update version '%s' to database\n", - version); - free(version_update); - free(version_delete); - fclose(file); - db->destroy(db); - exit(EXIT_FAILURE); - } - updated_versions++; - } - - if (vid_delete) - { - printf("%s (%s) %s deleted\n", - package, version_delete, security_delete ? "[s]" : ""); - - if (db->execute(db, NULL, - "DELETE FROM versions WHERE id = ?", - DB_INT, vid_delete) <= 0) - { - fprintf(stderr, "could not delete version '%s' from database\n", - version_delete); - free(version_update); - free(version_delete); - fclose(file); - db->destroy(db); - exit(EXIT_FAILURE); - } - deleted_versions++; + success = update_database(db, package, version, security, &stats); + free(package); + free(version); + if (!success) + { + fclose(file); + db->destroy(db); + exit(EXIT_FAILURE); + } + pacman_state = PACMAN_STATE_BEGIN_PACKAGE; } - free(version_update); - free(version_delete); } fclose(file); db->destroy(db); - printf("processed %d packages, %d security, %d new packages, " - "%d new versions, %d updated versions, %d deleted versions, " - "%d errored\n", count - 6, vulnerable, new_packages, new_versions, - updated_versions, deleted_versions, errored); + printf("processed %d packages, %d new packages, %d new versions, " + "%d updated versions, %d deleted versions\n", + stats.packages, stats.new_packages, stats.new_versions, + stats.updated_versions, stats.deleted_versions); } static void do_args(int argc, char *argv[]) { char *filename = NULL, *product = NULL; - bool update = FALSE; + bool security = FALSE; /* reinit getopt state */ optind = 0; @@ -438,7 +421,7 @@ static void do_args(int argc, char *argv[]) { "help", no_argument, NULL, 'h' }, { "file", required_argument, NULL, 'f' }, { "product", required_argument, NULL, 'p' }, - { "update", no_argument, NULL, 'u' }, + { "security", no_argument, NULL, 's' }, { 0,0,0,0 } }; @@ -456,8 +439,8 @@ static void do_args(int argc, char *argv[]) case 'p': product = optarg; continue; - case 'u': - update = TRUE; + case 's': + security = TRUE; continue; } break; @@ -465,7 +448,7 @@ static void do_args(int argc, char *argv[]) if (filename && product) { - process_packages(filename, product, update); + process_packages(filename, product, security); } else { @@ -487,7 +470,7 @@ int main(int argc, char *argv[]) { exit(SS_RC_LIBSTRONGSWAN_INTEGRITY); } - if (!lib->plugins->load(lib->plugins, NULL, + if (!lib->plugins->load(lib->plugins, lib->settings->get_str(lib->settings, "attest.load", "sqlite"))) { exit(SS_RC_INITIALIZATION_FAILED); |