Annotation of embedaddon/strongswan/src/sec-updater/sec-updater.c, revision 1.1
1.1 ! misho 1: /*
! 2: * Copyright (C) 2012-2017 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: #define _GNU_SOURCE
! 17: #include <getopt.h>
! 18: #include <unistd.h>
! 19: #include <stdio.h>
! 20: #include <string.h>
! 21: #include <errno.h>
! 22: #include <syslog.h>
! 23: #include <time.h>
! 24: #include <sys/stat.h>
! 25: #include <stdlib.h>
! 26:
! 27: #include <library.h>
! 28: #include <utils/debug.h>
! 29:
! 30: #define EXIT_NO_UPDATES 80
! 31: #define TMP_DEB_FILE "/tmp/sec-updater.deb"
! 32: #define TMP_TAG_FILE "/tmp/sec-updater.tag"
! 33: #define SWID_GEN_CMD "/usr/local/bin/swid_generator"
! 34: #define TNC_MANAGE_CMD "/var/www/tnc/manage.py"
! 35:
! 36: typedef enum sec_update_state_t sec_update_state_t;
! 37:
! 38: enum sec_update_state_t {
! 39: SEC_UPDATE_STATE_BEGIN_PACKAGE,
! 40: SEC_UPDATE_STATE_VERSION,
! 41: SEC_UPDATE_STATE_FILENAME,
! 42: SEC_UPDATE_STATE_END_PACKAGE
! 43: };
! 44:
! 45: typedef struct stats_t stats_t;
! 46:
! 47: struct stats_t {
! 48: time_t release;
! 49: int product;
! 50: int packages;
! 51: int new_versions;
! 52: int updated_versions;
! 53: };
! 54:
! 55: /**
! 56: * global debug output variables
! 57: */
! 58: static int debug_level = 1;
! 59: static bool stderr_quiet = FALSE;
! 60:
! 61: /**
! 62: * sec_updater dbg function
! 63: */
! 64: static void sec_updater_dbg(debug_t group, level_t level, char *fmt, ...)
! 65: {
! 66: int priority = LOG_INFO;
! 67: char buffer[8192];
! 68: char *current = buffer, *next;
! 69: va_list args;
! 70:
! 71: if (level <= debug_level)
! 72: {
! 73: if (!stderr_quiet)
! 74: {
! 75: va_start(args, fmt);
! 76: vfprintf(stderr, fmt, args);
! 77: fprintf(stderr, "\n");
! 78: va_end(args);
! 79: }
! 80:
! 81: /* write in memory buffer first */
! 82: va_start(args, fmt);
! 83: vsnprintf(buffer, sizeof(buffer), fmt, args);
! 84: va_end(args);
! 85:
! 86: /* do a syslog with every line */
! 87: while (current)
! 88: {
! 89: next = strchr(current, '\n');
! 90: if (next)
! 91: {
! 92: *(next++) = '\0';
! 93: }
! 94: syslog(priority, "%s\n", current);
! 95: current = next;
! 96: }
! 97: }
! 98: }
! 99:
! 100: /**
! 101: * atexit handler to close everything on shutdown
! 102: */
! 103: static void cleanup(void)
! 104: {
! 105: closelog();
! 106: library_deinit();
! 107: }
! 108:
! 109: static void usage(void)
! 110: {
! 111: printf("\
! 112: Usage:\n\
! 113: sec-updater --help\n\
! 114: sec-updater [--debug <level>] [--quiet] [--security] --os <string>\n\
! 115: --arch <string> --uri <uri> --file <filename>\n\n\
! 116: Options:\n\
! 117: --help print usage information\n\
! 118: --debug <level> set debug level\n\
! 119: --quiet suppress debug output to stderr\n\
! 120: --os <string> operating system\n\
! 121: --arch <string> hw architecture\n\
! 122: --security set when parsing a file with security updates\n\
! 123: --file <filename> package information file to parse\n\
! 124: --uri <uri> uri where to download deb package from\n");
! 125: }
! 126:
! 127: /**
! 128: * Update the package database
! 129: */
! 130: static bool update_database(database_t *db, char *package, char *version,
! 131: bool security, stats_t *stats, bool *new)
! 132: {
! 133: int pid = 0, vid = 0, sec_flag;
! 134: bool first = TRUE, found = FALSE;
! 135: char *release;
! 136: enumerator_t *e;
! 137:
! 138: /* increment package count */
! 139: stats->packages++;
! 140:
! 141: /* set new output variable */
! 142: *new = FALSE;
! 143:
! 144: /* check if package is already in database */
! 145: e = db->query(db, "SELECT id FROM packages WHERE name = ?",
! 146: DB_TEXT, package, DB_INT);
! 147: if (!e)
! 148: {
! 149: return FALSE;
! 150: }
! 151: if (!e->enumerate(e, &pid))
! 152: {
! 153: pid = 0;
! 154: }
! 155: e->destroy(e);
! 156:
! 157: if (!pid)
! 158: {
! 159: return TRUE;
! 160: }
! 161:
! 162: /* retrieve all package versions stored in database */
! 163: e = db->query(db,
! 164: "SELECT id, release, security FROM versions "
! 165: "WHERE product = ? AND package = ?",
! 166: DB_INT, stats->product, DB_INT, pid, DB_INT, DB_TEXT, DB_INT);
! 167: if (!e)
! 168: {
! 169: return FALSE;
! 170: }
! 171:
! 172: while (e->enumerate(e, &vid, &release, &sec_flag))
! 173: {
! 174: char command[BUF_LEN];
! 175: char found_char = ' ';
! 176: bool update_version = FALSE;
! 177:
! 178: if (streq(version, release))
! 179: {
! 180: found = TRUE;
! 181: found_char = '*';
! 182: }
! 183: else if (security)
! 184: {
! 185: snprintf(command, BUF_LEN, "dpkg --compare-versions %s lt %s",
! 186: release, version);
! 187: if (system(command) == 0)
! 188: {
! 189: found_char = '!';
! 190: if (!sec_flag)
! 191: {
! 192: if (db->execute(db, NULL, "UPDATE versions "
! 193: "SET security = 1 WHERE id = ?", DB_INT, vid) != 1)
! 194: {
! 195: DBG1(DBG_IMV, " could not update version");
! 196: e->destroy(e);
! 197: return FALSE;
! 198: }
! 199: update_version = TRUE;
! 200: stats->updated_versions++;
! 201: }
! 202: }
! 203: }
! 204: if (debug_level < 2 && !update_version)
! 205: {
! 206: continue;
! 207: }
! 208: if (first)
! 209: {
! 210: DBG1(DBG_IMV, "%s", package);
! 211: first = FALSE;
! 212: }
! 213: DBG1(DBG_IMV, " %c%s %s", found_char , sec_flag ? "s" : " ", release);
! 214: }
! 215: e->destroy(e);
! 216:
! 217: if (!found)
! 218: {
! 219: if (first)
! 220: {
! 221: DBG1(DBG_IMV, "%s", package);
! 222: }
! 223: DBG1(DBG_IMV, " + %s", version);
! 224:
! 225: if (db->execute(db, &vid,
! 226: "INSERT INTO versions "
! 227: "(package, product, release, security, time) "
! 228: "VALUES (?, ?, ?, 0, ?)", DB_INT, pid, DB_INT, stats->product,
! 229: DB_TEXT, version, DB_INT, stats->release) != 1)
! 230: {
! 231: DBG1(DBG_IMV, " could not store version to database");
! 232: return FALSE;
! 233: }
! 234: stats->new_versions++;
! 235: *new = TRUE;
! 236: }
! 237:
! 238: return TRUE;
! 239: }
! 240:
! 241: /**
! 242: * Process a package file and store updates in the database
! 243: */
! 244: static int process_packages(char *path, char *os, char *arch, char *uri,
! 245: bool security)
! 246: {
! 247: char line[BUF_LEN], product[BUF_LEN], command[BUF_LEN];
! 248: char *db_uri, *download_uri = NULL, *swid_regid, *swid_entity;
! 249: char *pos, *package = NULL, *version = NULL, *filename = NULL;
! 250: char *swid_gen_cmd, *tnc_manage_cmd, *tmp_deb_file, *tmp_tag_file;
! 251: sec_update_state_t state;
! 252: enumerator_t *e;
! 253: database_t *db;
! 254: int len, pid;
! 255: chunk_t deb = chunk_empty;
! 256: FILE *file;
! 257: stats_t stats;
! 258: bool success = TRUE, new;
! 259:
! 260: /* initialize statistics */
! 261: memset(&stats, 0x00, sizeof(stats_t));
! 262:
! 263: /* Set release date to current time */
! 264: stats.release = time(NULL);
! 265:
! 266: /* opening package file */
! 267: file = fopen(path, "r");
! 268: if (!file)
! 269: {
! 270: DBG1(DBG_IMV, " could not open \"%s\"", path);
! 271: exit(EXIT_FAILURE);
! 272: }
! 273:
! 274: /* connect package database */
! 275: db_uri = lib->settings->get_str(lib->settings, "sec-updater.database", NULL);
! 276: if (!db_uri)
! 277: {
! 278: DBG1(DBG_IMV, "database URI sec-updater.database not set");
! 279: fclose(file);
! 280: exit(EXIT_FAILURE);
! 281: }
! 282: db = lib->db->create(lib->db, db_uri);
! 283: if (!db)
! 284: {
! 285: DBG1(DBG_IMV, "could not connect to database '%s'", db_uri);
! 286: fclose(file);
! 287: exit(EXIT_FAILURE);
! 288: }
! 289:
! 290: /* form product name by concatenating os and arch strings */
! 291: snprintf(product, BUF_LEN, "%s %s", os, arch);
! 292:
! 293: /* check if product is already in database */
! 294: e = db->query(db, "SELECT id FROM products WHERE name = ?",
! 295: DB_TEXT, product, DB_INT);
! 296: if (e)
! 297: {
! 298: if (e->enumerate(e, &pid))
! 299: {
! 300: stats.product = pid;
! 301: }
! 302: e->destroy(e);
! 303: }
! 304: if (!stats.product)
! 305: {
! 306: if (db->execute(db, &pid, "INSERT INTO products (name) VALUES (?)",
! 307: DB_TEXT, product) != 1)
! 308: {
! 309: DBG1(DBG_IMV, "could not store product '%s' to database",
! 310: product);
! 311: fclose(file);
! 312: db->destroy(db);
! 313: exit(EXIT_FAILURE);
! 314: }
! 315: stats.product = pid;
! 316: }
! 317:
! 318: /* get settings for the loop */
! 319: swid_regid = lib->settings->get_str(lib->settings,
! 320: "sec-updater.swid_gen.tag_creator.regid",
! 321: "strongswan.org");
! 322: swid_entity = lib->settings->get_str(lib->settings,
! 323: "sec-updater.swid_gen.tag_creator.name",
! 324: "strongSwan Project");
! 325: swid_gen_cmd = lib->settings->get_str(lib->settings,
! 326: "sec-updater.swid_gen.command", SWID_GEN_CMD);
! 327: tnc_manage_cmd = lib->settings->get_str(lib->settings,
! 328: "sec-updater.tnc_manage_command", TNC_MANAGE_CMD);
! 329: tmp_deb_file = lib->settings->get_str(lib->settings,
! 330: "sec-updater.tmp.deb_file", TMP_DEB_FILE);
! 331: tmp_tag_file = lib->settings->get_str(lib->settings,
! 332: "sec-updater.tmp.tag_file", TMP_TAG_FILE);
! 333:
! 334: state = SEC_UPDATE_STATE_BEGIN_PACKAGE;
! 335:
! 336: while (fgets(line, sizeof(line), file))
! 337: {
! 338: /* set read pointer to beginning of line */
! 339: pos = line;
! 340:
! 341: switch (state)
! 342: {
! 343: case SEC_UPDATE_STATE_BEGIN_PACKAGE:
! 344: pos = strstr(pos, "Package: ");
! 345: if (!pos)
! 346: {
! 347: continue;
! 348: }
! 349: pos += 9;
! 350: package = pos;
! 351: pos = strchr(pos, '\n');
! 352: if (pos)
! 353: {
! 354: package = strndup(package, pos - package);
! 355: state = SEC_UPDATE_STATE_VERSION;
! 356: }
! 357: break;
! 358: case SEC_UPDATE_STATE_VERSION:
! 359: pos = strstr(pos, "Version: ");
! 360: if (!pos)
! 361: {
! 362: continue;
! 363: }
! 364: pos += 9;
! 365: version = pos;
! 366: pos = strchr(pos, '\n');
! 367: if (pos)
! 368: {
! 369: version = strndup(version, pos - version);
! 370: success = update_database(db, package, version, security,
! 371: &stats, &new);
! 372: state = (success && new) ? SEC_UPDATE_STATE_FILENAME :
! 373: SEC_UPDATE_STATE_END_PACKAGE;
! 374: }
! 375: break;
! 376: case SEC_UPDATE_STATE_FILENAME:
! 377: pos = strstr(pos, "Filename: ");
! 378: if (!pos)
! 379: {
! 380: continue;
! 381: }
! 382: state = SEC_UPDATE_STATE_END_PACKAGE;
! 383:
! 384: pos += 10;
! 385: filename = pos;
! 386: pos = strchr(pos, '\n');
! 387: if (!pos)
! 388: {
! 389: break;
! 390: }
! 391: len = pos - filename;
! 392: if (asprintf(&download_uri, "%s/%.*s", uri, len, filename) == -1)
! 393: {
! 394: break;
! 395: }
! 396:
! 397: /* retrieve deb package file from linux repository */
! 398: if (lib->fetcher->fetch(lib->fetcher, download_uri,
! 399: &deb, FETCH_END) != SUCCESS)
! 400: {
! 401: DBG1(DBG_IMV, " %s failed", download_uri);
! 402: break;
! 403: }
! 404: DBG1(DBG_IMV, " %s (%u bytes)", download_uri, deb.len);
! 405:
! 406: /* store deb package file to temporary location */
! 407: if (!chunk_write(deb, tmp_deb_file, 0022, TRUE))
! 408: {
! 409: DBG1(DBG_IMV, " save to '%s' failed", tmp_deb_file);
! 410: break;
! 411: }
! 412:
! 413: /* generate SWID tag for downloaded deb package */
! 414: snprintf(command, BUF_LEN, "%s swid --full --package-file %s "
! 415: "--regid %s --entity-name '%s' --os '%s' --arch '%s' "
! 416: ">> %s", swid_gen_cmd, tmp_deb_file, swid_regid,
! 417: swid_entity, os, arch, tmp_tag_file);
! 418: if (system(command) != 0)
! 419: {
! 420: DBG1(DBG_IMV, " tag generation failed");
! 421: break;
! 422: }
! 423: break;
! 424: case SEC_UPDATE_STATE_END_PACKAGE:
! 425: if (*pos != '\n')
! 426: {
! 427: continue;
! 428: }
! 429: free(package);
! 430: free(version);
! 431: free(download_uri);
! 432: chunk_free(&deb);
! 433: package = version = download_uri = NULL;
! 434:
! 435: if (!success)
! 436: {
! 437: fclose(file);
! 438: db->destroy(db);
! 439: exit(EXIT_FAILURE);
! 440: }
! 441: state = SEC_UPDATE_STATE_BEGIN_PACKAGE;
! 442: }
! 443: }
! 444:
! 445: free(package);
! 446: free(version);
! 447: free(download_uri);
! 448: fclose(file);
! 449: db->destroy(db);
! 450:
! 451: /* import swid tags into strongTNC */
! 452: if (stats.new_versions > 0)
! 453: {
! 454: snprintf(command, BUF_LEN, "%s importswid %s",
! 455: tnc_manage_cmd, tmp_tag_file);
! 456: if (system(command) != 0)
! 457: {
! 458: DBG1(DBG_IMV, "tag import failed");
! 459: }
! 460: snprintf(command, BUF_LEN, "rm %s %s",
! 461: tmp_deb_file, tmp_tag_file);
! 462: if (system(command) != 0)
! 463: {
! 464: DBG1(DBG_IMV, "removing temporary files failed");
! 465: }
! 466: }
! 467:
! 468: DBG1(DBG_IMV, "processed \"%s\": %d packages, %d new versions, "
! 469: "%d updated versions", path, stats.packages,
! 470: stats.new_versions, stats.updated_versions);
! 471:
! 472: return (stats.new_versions + stats.updated_versions) ?
! 473: EXIT_SUCCESS : EXIT_NO_UPDATES;
! 474: }
! 475:
! 476: static int do_args(int argc, char *argv[])
! 477: {
! 478: char *filename = NULL, *arch = NULL, *os = NULL, *uri = NULL;
! 479: bool security = FALSE;
! 480:
! 481: /* reinit getopt state */
! 482: optind = 0;
! 483:
! 484: while (TRUE)
! 485: {
! 486: int c;
! 487:
! 488: struct option long_opts[] = {
! 489: { "help", no_argument, NULL, 'h' },
! 490: { "arch", required_argument, NULL, 'a' },
! 491: { "debug", required_argument, NULL, 'd' },
! 492: { "file", required_argument, NULL, 'f' },
! 493: { "os", required_argument, NULL, 'o' },
! 494: { "quiet", no_argument, NULL, 'q' },
! 495: { "security", no_argument, NULL, 's' },
! 496: { "uri", required_argument, NULL, 'u' },
! 497: { 0,0,0,0 }
! 498: };
! 499:
! 500: c = getopt_long(argc, argv, "ha:d:f:o:qsu:", long_opts, NULL);
! 501: switch (c)
! 502: {
! 503: case EOF:
! 504: break;
! 505: case 'h':
! 506: usage();
! 507: exit(EXIT_SUCCESS);
! 508: case 'a':
! 509: arch = optarg;
! 510: continue;
! 511: case 'd':
! 512: debug_level = atoi(optarg);
! 513: continue;
! 514: case 'f':
! 515: filename = optarg;
! 516: continue;
! 517: case 'o':
! 518: os = optarg;
! 519: continue;
! 520: case 'q':
! 521: stderr_quiet = TRUE;
! 522: continue;
! 523: case 's':
! 524: security = TRUE;
! 525: continue;
! 526: case 'u':
! 527: uri = optarg;
! 528: continue;
! 529: }
! 530: break;
! 531: }
! 532:
! 533: if (filename && os && arch && uri)
! 534: {
! 535: return process_packages(filename, os, arch, uri, security);
! 536: }
! 537: else
! 538: {
! 539: usage();
! 540: exit(EXIT_FAILURE);
! 541: }
! 542: }
! 543:
! 544: int main(int argc, char *argv[])
! 545: {
! 546: /* enable attest debugging hook */
! 547: dbg = sec_updater_dbg;
! 548: openlog("sec-updater", 0, LOG_DEBUG);
! 549:
! 550: atexit(cleanup);
! 551:
! 552: /* initialize library */
! 553: if (!library_init(NULL, "sec-updater"))
! 554: {
! 555: exit(SS_RC_LIBSTRONGSWAN_INTEGRITY);
! 556: }
! 557: if (!lib->plugins->load(lib->plugins,
! 558: lib->settings->get_str(lib->settings, "sec-updater.load",
! 559: "sqlite curl")))
! 560: {
! 561: exit(SS_RC_INITIALIZATION_FAILED);
! 562: }
! 563: exit(do_args(argc, argv));
! 564: }
! 565:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>