diff options
author | Andreas Steffen <andreas.steffen@strongswan.org> | 2017-09-09 13:13:28 +0200 |
---|---|---|
committer | Andreas Steffen <andreas.steffen@strongswan.org> | 2017-09-09 20:23:19 +0200 |
commit | 8aad7ffb11beb1c39bde41a456b7c21b240667c8 (patch) | |
tree | 4bc91c9c3e6676a43bdd67bfc713519b77a8fa7e | |
parent | 33a729fac2f6637d1eaacfdc6fd9e6f16259b42c (diff) | |
download | strongswan-8aad7ffb11beb1c39bde41a456b7c21b240667c8.tar.bz2 strongswan-8aad7ffb11beb1c39bde41a456b7c21b240667c8.tar.xz |
sec-updater: Import SWID tags of updated packages
sec-updater downloads the deb package files from security updates from
a given linux repository and uses the swid_generator command to
derive a SWID tag. The SWID tag is then imported into strongTNC
using the manage.py importswid command.
-rw-r--r-- | conf/Makefile.am | 1 | ||||
-rw-r--r-- | conf/options/sec-updater.opt | 29 | ||||
-rw-r--r-- | src/sec-updater/sec-updater.8.in | 31 | ||||
-rw-r--r-- | src/sec-updater/sec-updater.c | 185 | ||||
-rwxr-xr-x | src/sec-updater/sec-updater.sh | 48 |
5 files changed, 237 insertions, 57 deletions
diff --git a/conf/Makefile.am b/conf/Makefile.am index 87319db22..0a4a8597f 100644 --- a/conf/Makefile.am +++ b/conf/Makefile.am @@ -25,6 +25,7 @@ options = \ options/starter.opt \ options/swanctl.opt \ options/tnc.opt \ + options/sec-updater.opt \ options/sw-collector.opt plugins = \ diff --git a/conf/options/sec-updater.opt b/conf/options/sec-updater.opt new file mode 100644 index 000000000..1162efecc --- /dev/null +++ b/conf/options/sec-updater.opt @@ -0,0 +1,29 @@ +sec-updater {} + Options for the sec-updater tool. + + Options for the sec-updater tool. + +sec-updater.database = + Global IMV policy database URI. If it contains a password, make sure to + adjust the permissions of the config file accordingly. + +sec-updater.swid_gen.command = /usr/local/bin/swid_generator + SWID generator command to be executed. + +sec-updater.swid_gen.tag_creator.name = strongSwan Project + Name of the tagCreator entity. + +sec-updater.swid_gen.tag_creator.regid = strongswan.org + regid of the tagCreator entity. + +sec-updater.tnc_manager_command = /var/www/tnc/manager.py + strongTNC manage.py command used to import SWID tags. + +sec-updater.tmp.deb_file = /tmp/sec-updater.deb + Temporary storage for downloaded deb package file. + +sec-updater.tmp.tag_file = /tmp/sec-updater.tag + Temporary storage for generated SWID tags. + +sec-updater.load = + Plugins to load in sec-updater tool. diff --git a/src/sec-updater/sec-updater.8.in b/src/sec-updater/sec-updater.8.in index e58f3b99a..f17198f56 100644 --- a/src/sec-updater/sec-updater.8.in +++ b/src/sec-updater/sec-updater.8.in @@ -10,7 +10,9 @@ sec-updater \- Extracts security update information of Linux distributions .OP \-\-debug level .OP \-\-quiet .OP \-\-security -.BI \-\-product " name" +.BI \-\-os " string" +.BI \-\-arch " string" +.BI \-\-uri " uri" .BI \-\-file " filename" .YS . @@ -44,20 +46,37 @@ Disable debug output to stderr. .B "\-s, \-\-security" Set when parsing a distributions file with security updates. .TP -.BI "\-p, \-\-product " name -Name of Linux version as stored in database. eg. "Ubuntu 16.04 x86_64". +.BI "\-o, \-\-os " string +Name of operating system (OS). eg. "Ubuntu 16.04". +.TP +.BI "\-o, \-\-arch " string +Name of HW architecture. eg. "x86_64". +.TP +.BI "\-o, \-\-uri " uri +URI where to download deb package from. .TP .BI "\-f, \-\-file " filename Linux package information file to parse. . .SH "CONFIGURATION" . -The following parameter must be configured in strongswan.conf: +The following parameters can be configured in strongswan.conf: .P sec-updater { - database = sqlite:///etc/pts/config.db + database = sqlite:///etc/pts/config.db + swid_gen { + command = /usr/local/bin/swid_generator + tag_creator { + name = strongSwan Project + regid = strongswan.org + } + } + tnc_manage_command = /var/www/tnc/manage.py + tmp { + deb_file = /tmp/sec-updater.deb + tag_file = /tmp/sec-updater.tag + } } -.P . .SH "SEE ALSO" . diff --git a/src/sec-updater/sec-updater.c b/src/sec-updater/sec-updater.c index e6e672d99..9d48621f0 100644 --- a/src/sec-updater/sec-updater.c +++ b/src/sec-updater/sec-updater.c @@ -28,12 +28,17 @@ #include <utils/debug.h> #define EXIT_NO_UPDATES 80 +#define TMP_DEB_FILE "/tmp/sec-updater.deb" +#define TMP_TAG_FILE "/tmp/sec-updater.tag" +#define SWID_GEN_CMD "/usr/local/bin/swid_generator" +#define TNC_MANAGE_CMD "/var/www/tnc/manage.py" typedef enum sec_update_state_t sec_update_state_t; enum sec_update_state_t { SEC_UPDATE_STATE_BEGIN_PACKAGE, SEC_UPDATE_STATE_VERSION, + SEC_UPDATE_STATE_FILENAME, SEC_UPDATE_STATE_END_PACKAGE }; @@ -106,21 +111,24 @@ static void usage(void) printf("\ Usage:\n\ sec-updater --help\n\ - sec-updater [--debug <level>] [--quiet] [--security] --product <name> --file <filename>\n\n\ + sec-updater [--debug <level>] [--quiet] [--security] --os <string>\n\ + --arch <string> --uri <uri> --file <filename>\n\n\ Options:\n\ --help print usage information\n\ - --debug set debug level\n\ + --debug <level> set debug level\n\ --quiet suppress debug output to stderr\n\ + --os <string> operating system\n\ + --arch <string> hw architecture\n\ --security set when parsing a file with security updates\n\ - --product <name> name of the Linux version as stored in the database\n\ - --file <filename> package information file to parse"); -} + --file <filename> package information file to parse\n\ + --uri <uri> uri where to download deb package from\n"); + } /** * Update the package database */ static bool update_database(database_t *db, char *package, char *version, - bool security, stats_t *stats) + bool security, stats_t *stats, bool *new) { int pid = 0, vid = 0, sec_flag; bool first = TRUE, found = FALSE; @@ -130,6 +138,9 @@ static bool update_database(database_t *db, char *package, char *version, /* increment package count */ stats->packages++; + /* set new output variable */ + *new = FALSE; + /* check if package is already in database */ e = db->query(db, "SELECT id FROM packages WHERE name = ?", DB_TEXT, package, DB_INT); @@ -221,6 +232,7 @@ static bool update_database(database_t *db, char *package, char *version, return FALSE; } stats->new_versions++; + *new = TRUE; } return TRUE; @@ -229,16 +241,21 @@ static bool update_database(database_t *db, char *package, char *version, /** * Process a package file and store updates in the database */ -static int process_packages(char *filename, char *product, bool security) +static int process_packages(char *path, char *os, char *arch, char *uri, + bool security) { - char *uri, line[BUF_LEN], *pos, *package = NULL, *version = NULL; + char line[BUF_LEN], product[BUF_LEN], command[BUF_LEN]; + char *db_uri, *download_uri = NULL, *swid_regid, *swid_entity; + char *pos, *package = NULL, *version = NULL, *filename = NULL; + char *swid_gen_cmd, *tnc_manage_cmd, *tmp_deb_file, *tmp_tag_file; sec_update_state_t state; enumerator_t *e; database_t *db; - int pid; + int len, pid; + chunk_t deb = chunk_empty; FILE *file; stats_t stats; - bool success; + bool success, new; /* initialize statistics */ memset(&stats, 0x00, sizeof(stats_t)); @@ -247,29 +264,32 @@ static int process_packages(char *filename, char *product, bool security) stats.release = time(NULL); /* opening package file */ - file = fopen(filename, "r"); + file = fopen(path, "r"); if (!file) { - DBG1(DBG_IMV, " could not open \"%s\"", filename); + DBG1(DBG_IMV, " could not open \"%s\"", path); exit(EXIT_FAILURE); } /* connect package database */ - uri = lib->settings->get_str(lib->settings, "sec-updater.database", NULL); - if (!uri) + db_uri = lib->settings->get_str(lib->settings, "sec-updater.database", NULL); + if (!db_uri) { DBG1(DBG_IMV, "database URI sec-updater.database not set"); fclose(file); exit(EXIT_FAILURE); } - db = lib->db->create(lib->db, uri); + db = lib->db->create(lib->db, db_uri); if (!db) { - DBG1(DBG_IMV, "could not connect to database '%s'", uri); + DBG1(DBG_IMV, "could not connect to database '%s'", db_uri); fclose(file); exit(EXIT_FAILURE); } + /* form product name by concatenating os and arch strings */ + snprintf(product, BUF_LEN, "%s %s", os, arch); + /* check if product is already in database */ e = db->query(db, "SELECT id FROM products WHERE name = ?", DB_TEXT, product, DB_INT); @@ -295,6 +315,22 @@ static int process_packages(char *filename, char *product, bool security) stats.product = pid; } + /* get settings for the loop */ + swid_regid = lib->settings->get_str(lib->settings, + "sec-updater.swid_gen.tag_creator.regid", + "strongswan.org"); + swid_entity = lib->settings->get_str(lib->settings, + "sec-updater.swid_gen.tag_creator.name", + "strongSwan Project"); + swid_gen_cmd = lib->settings->get_str(lib->settings, + "sec-updater.swid_gen.command", SWID_GEN_CMD); + tnc_manage_cmd = lib->settings->get_str(lib->settings, + "sec-updater.tnc_manage_command", TNC_MANAGE_CMD); + tmp_deb_file = lib->settings->get_str(lib->settings, + "sec-updater.tmp.deb_file", TMP_DEB_FILE); + tmp_tag_file = lib->settings->get_str(lib->settings, + "sec-updater.tmp.tag_file", TMP_TAG_FILE); + state = SEC_UPDATE_STATE_BEGIN_PACKAGE; while (fgets(line, sizeof(line), file)) @@ -331,7 +367,58 @@ static int process_packages(char *filename, char *product, bool security) if (pos) { version = strndup(version, pos - version); - state = SEC_UPDATE_STATE_END_PACKAGE; + success = update_database(db, package, version, security, + &stats, &new); + state = (success && new) ? SEC_UPDATE_STATE_FILENAME : + SEC_UPDATE_STATE_END_PACKAGE; + } + break; + case SEC_UPDATE_STATE_FILENAME: + pos = strstr(pos, "Filename: "); + if (!pos) + { + continue; + } + state = SEC_UPDATE_STATE_END_PACKAGE; + + pos += 10; + filename = pos; + pos = strchr(pos, '\n'); + if (!pos) + { + break; + } + len = pos - filename; + if (asprintf(&download_uri, "%s/%.*s", uri, len, filename) == -1) + { + break; + } + + /* retrieve deb package file from linux repository */ + if (lib->fetcher->fetch(lib->fetcher, download_uri, + &deb, FETCH_END) != SUCCESS) + { + DBG1(DBG_IMV, " %s failed", download_uri); + break; + } + DBG1(DBG_IMV, " %s (%u bytes)", download_uri, deb.len); + + /* store deb package file to temporary location */ + if (!chunk_write(deb, tmp_deb_file, 0022, TRUE)) + { + DBG1(DBG_IMV, " save to '%s' failed", tmp_deb_file); + break; + } + + /* generate SWID tag for downloaded deb package */ + snprintf(command, BUF_LEN, "%s swid --full --package-file %s " + "--regid %s --entity-name '%s' --os '%s' --arch '%s' " + ">> %s", swid_gen_cmd, tmp_deb_file, swid_regid, + swid_entity, os, arch, tmp_tag_file); + if (system(command) != 0) + { + DBG1(DBG_IMV, " tag generation failed"); + break; } break; case SEC_UPDATE_STATE_END_PACKAGE: @@ -339,9 +426,12 @@ static int process_packages(char *filename, char *product, bool security) { continue; } - success = update_database(db, package, version, security, &stats); free(package); free(version); + free(download_uri); + chunk_free(&deb); + package = version = download_uri = NULL; + if (!success) { fclose(file); @@ -351,22 +441,32 @@ static int process_packages(char *filename, char *product, bool security) state = SEC_UPDATE_STATE_BEGIN_PACKAGE; } } - switch (state) - { - case SEC_UPDATE_STATE_END_PACKAGE: - free(version); - /* fall-through */ - case SEC_UPDATE_STATE_VERSION: - free(package); - break; - default: - break; - } + + free(package); + free(version); + free(download_uri); fclose(file); db->destroy(db); + /* import swid tags into strongTNC */ + if (stats.new_versions > 0) + { + snprintf(command, BUF_LEN, "%s importswid %s", + tnc_manage_cmd, tmp_tag_file); + if (system(command) != 0) + { + DBG1(DBG_IMV, "tag import failed"); + } + snprintf(command, BUF_LEN, "rm %s %s", + tmp_deb_file, tmp_tag_file); + if (system(command) != 0) + { + DBG1(DBG_IMV, "removing temporary files failed"); + } + } + DBG1(DBG_IMV, "processed \"%s\": %d packages, %d new versions, " - "%d updated versions", filename, stats.packages, + "%d updated versions", path, stats.packages, stats.new_versions, stats.updated_versions); return (stats.new_versions + stats.updated_versions) ? @@ -375,7 +475,7 @@ static int process_packages(char *filename, char *product, bool security) static int do_args(int argc, char *argv[]) { - char *filename = NULL, *product = NULL; + char *filename = NULL, *arch = NULL, *os = NULL, *uri = NULL; bool security = FALSE; /* reinit getopt state */ @@ -387,15 +487,17 @@ static int do_args(int argc, char *argv[]) struct option long_opts[] = { { "help", no_argument, NULL, 'h' }, + { "arch", required_argument, NULL, 'a' }, { "debug", required_argument, NULL, 'd' }, { "file", required_argument, NULL, 'f' }, - { "product", required_argument, NULL, 'p' }, + { "os", required_argument, NULL, 'o' }, { "quiet", no_argument, NULL, 'q' }, { "security", no_argument, NULL, 's' }, + { "uri", required_argument, NULL, 'u' }, { 0,0,0,0 } }; - c = getopt_long(argc, argv, "", long_opts, NULL); + c = getopt_long(argc, argv, "ha:d:f:o:qsu:", long_opts, NULL); switch (c) { case EOF: @@ -403,14 +505,17 @@ static int do_args(int argc, char *argv[]) case 'h': usage(); exit(EXIT_SUCCESS); + case 'a': + arch = optarg; + continue; case 'd': debug_level = atoi(optarg); continue; case 'f': filename = optarg; continue; - case 'p': - product = optarg; + case 'o': + os = optarg; continue; case 'q': stderr_quiet = TRUE; @@ -418,13 +523,16 @@ static int do_args(int argc, char *argv[]) case 's': security = TRUE; continue; + case 'u': + uri = optarg; + continue; } break; } - if (filename && product) + if (filename && os && arch && uri) { - return process_packages(filename, product, security); + return process_packages(filename, os, arch, uri, security); } else { @@ -447,7 +555,8 @@ int main(int argc, char *argv[]) exit(SS_RC_LIBSTRONGSWAN_INTEGRITY); } if (!lib->plugins->load(lib->plugins, - lib->settings->get_str(lib->settings, "sec-updater.load", "sqlite"))) + lib->settings->get_str(lib->settings, "sec-updater.load", + "sqlite curl"))) { exit(SS_RC_INITIALIZATION_FAILED); } diff --git a/src/sec-updater/sec-updater.sh b/src/sec-updater/sec-updater.sh index 1177c8bef..ca7b89841 100755 --- a/src/sec-updater/sec-updater.sh +++ b/src/sec-updater/sec-updater.sh @@ -10,7 +10,7 @@ UBUNTU_ARCH="binary-amd64" DEBIAN="http://security.debian.org" DEBIAN_VERSIONS="jessie wheezy" DEBIAN_DIRS="main contrib non-free" -DEBIAN_ARCH="binary-amd64" +DEBIAN_ARCH="binary-amd64 binary-armhf" RASPIAN="http://archive.raspberrypi.org/debian" RASPIAN_VERSIONS="jessie wheezy" RASPIAN_DIRS="main" @@ -74,66 +74,88 @@ done for f in xenial-security/binary-amd64/* do echo "security: $f" - $CMD --product "Ubuntu 16.04 x86_64" --file $f --security >> $CMD_LOG 2>&1 + $CMD --os "Ubuntu 16.04" --arch "x86_64" --file $f --security \ + --uri $UBUNTU >> $CMD_LOG 2>&1 if [ $? -eq 0 ] then DEL_LOG=0 - echo $DEL_LOG fi done for f in xenial-updates/binary-amd64/* do echo "updates: $f" - $CMD --product "Ubuntu 16.04 x86_64" --file $f >> $CMD_LOG 2>&1 + $CMD --os "Ubuntu 16.04" --arch "x86_64" --file $f \ + --uri $UBUNTU >> $CMD_LOG 2>&1 if [ $? -eq 0 ] then DEL_LOG=0 - echo $DEL_LOG fi done for f in jessie-updates/binary-amd64/* do echo "security: $f" - $CMD --product "Debian 8.0 x86_64" --file $f --security >> $CMD_LOG 2>&1 + $CMD --os "Debian 8.0" --arch "x86_64" --file $f --security \ + --uri $DEBIAN >> $CMD_LOG 2>&1 if [ $? -eq 0 ] then DEL_LOG=0 - echo $DEL_LOG fi done for f in wheezy-updates/binary-amd64/* do echo "security: $f" - $CMD --product "Debian 7.0 x86_64" --file $f --security >> $CMD_LOG 2>&1 + $CMD --os "Debian 7.0" --arch "x86_64" --file $f --security \ + --uri $DEBIAN >> $CMD_LOG 2>&1 + if [ $? -eq 0 ] + then + DEL_LOG=0 + fi +done + +for f in jessie-updates/binary-armhf/* +do + echo "security: $f" + $CMD --os "Debian 8.0" --arch "armhf" --file $f --security \ + --uri $DEBIAN >> $CMD_LOG 2>&1 + if [ $? -eq 0 ] + then + DEL_LOG=0 + fi +done + +for f in wheezy-updates/binary-armhf/* +do + echo "security: $f" + $CMD --os "Debian 7.0" --arch "armhf" --file $f --security \ + --uri $DEBIAN >> $CMD_LOG 2>&1 if [ $? -eq 0 ] then DEL_LOG=0 - echo $DEL_LOG fi done for f in jessie-raspian/binary-armhf/* do echo "security: $f" - $CMD --product "Debian 8.0 armv7l" --file $f --security >> $CMD_LOG 2>&1 + $CMD --os "Debian 8.0" --arch "armv7l" --file $f --security \ + --uri $RASPIAN >> $CMD_LOG 2>&1 if [ $? -eq 0 ] then DEL_LOG=0 - echo $DEL_LOG fi done for f in wheezy-raspian/binary-armhf/* do echo "security: $f" - $CMD --product "Debian 7.11 armv7l" --file $f --security >> $CMD_LOG 2>&1 + $CMD --os "Debian 7.11" --arch "armv7l" --file $f --security \ + --uri $RASPIAN >> $CMD_LOG 2>&1 if [ $? -eq 0 ] then DEL_LOG=0 - echo $DEL_LOG fi done |