static void check_vulnerable(struct pkg_audit *audit, struct pkgdb *db, int sock) { struct pkgdb_it *it = NULL; struct pkg *pkg = NULL; kh_pkgs_t *check = NULL; const char *uid; UT_string *sb; int ret; FILE *out; out = fdopen(sock, "w"); if (out == NULL) { warn("unable to open stream"); return; } if ((it = pkgdb_query(db, NULL, MATCH_ALL)) == NULL) { warnx("Error accessing the package database"); pkg_audit_free(audit); fclose(out); return; } else { check = kh_init_pkgs(); while ((ret = pkgdb_it_next(it, &pkg, PKG_LOAD_BASIC|PKG_LOAD_RDEPS)) == EPKG_OK) { add_to_check(check, pkg); pkg = NULL; } ret = EX_OK; } if (db != NULL) { pkgdb_it_free(it); pkgdb_close(db); } if (ret != EX_OK) { pkg_audit_free(audit); kh_destroy_pkgs(check); fclose(out); return; } drop_privileges(); if (pkg_audit_load(audit, NULL) != EPKG_OK) { warn("unable to open vulnxml file"); fclose(out); pkg_audit_free(audit); return; } #ifdef HAVE_CAPSICUM if (cap_enter() < 0 && errno != ENOSYS) { warn("cap_enter() failed"); pkg_audit_free(audit); kh_destroy_pkgs(check); fclose(out); return; } #endif if (pkg_audit_process(audit) == EPKG_OK) { kh_foreach_value(check, pkg, { if (pkg_audit_is_vulnerable(audit, pkg, true, &sb)) { pkg_get(pkg, PKG_UNIQUEID, &uid); fprintf(out, "%s\n", uid); fflush(out); utstring_free(sb); } pkg_free(pkg); });
int exec_audit(int argc, char **argv) { struct pkg_audit *audit; struct pkgdb *db = NULL; struct pkgdb_it *it = NULL; struct pkg *pkg = NULL; const char *db_dir; char *name; char *version; char audit_file_buf[MAXPATHLEN]; char *audit_file = audit_file_buf; unsigned int vuln = 0; bool fetch = false, recursive = false; int ch, i; int ret = EX_OK; const char *portaudit_site = NULL; struct sbuf *sb; kh_pkgs_t *check = NULL; db_dir = pkg_object_string(pkg_config_get("PKG_DBDIR")); snprintf(audit_file_buf, sizeof(audit_file_buf), "%s/vuln.xml", db_dir); struct option longopts[] = { { "fetch", no_argument, NULL, 'F' }, { "file", required_argument, NULL, 'f' }, { "recursive", no_argument, NULL, 'r' }, { "quiet", no_argument, NULL, 'q' }, { NULL, 0, NULL, 0 }, }; while ((ch = getopt_long(argc, argv, "+Ff:qr", longopts, NULL)) != -1) { switch (ch) { case 'F': fetch = true; break; case 'f': audit_file = optarg; break; case 'q': quiet = true; break; case 'r': recursive = true; break; default: usage_audit(); return(EX_USAGE); } } argc -= optind; argv += optind; audit = pkg_audit_new(); if (fetch == true) { portaudit_site = pkg_object_string(pkg_config_get("VULNXML_SITE")); if (pkg_audit_fetch(portaudit_site, audit_file) != EPKG_OK) { pkg_audit_free(audit); return (EX_IOERR); } } if (pkg_audit_load(audit, audit_file) != EPKG_OK) { if (errno == ENOENT) warnx("vulnxml file %s does not exist. " "Try running 'pkg audit -F' first", audit_file); else warn("unable to open vulnxml file %s", audit_file); pkg_audit_free(audit); return (EX_DATAERR); } check = kh_init_pkgs(); if (argc >= 1) { for (i = 0; i < argc; i ++) { name = argv[i]; version = strrchr(name, '-'); if (version != NULL) { version[0] = '\0'; version++; } if (pkg_new(&pkg, PKG_FILE) != EPKG_OK) err(EX_OSERR, "malloc"); if (version != NULL) pkg_set(pkg, PKG_NAME, name, PKG_VERSION, version); else pkg_set(pkg, PKG_NAME, name); /* Fake uniqueid */ pkg_set(pkg, PKG_UNIQUEID, name); add_to_check(check, pkg); pkg = NULL; } } else { /* * if the database doesn't exist it just means there are no * packages to audit. */ ret = pkgdb_access(PKGDB_MODE_READ, PKGDB_DB_LOCAL); if (ret == EPKG_ENODB) { pkg_audit_free(audit); kh_destroy_pkgs(check); return (EX_OK); } else if (ret == EPKG_ENOACCESS) { warnx("Insufficient privileges to read the package database"); pkg_audit_free(audit); kh_destroy_pkgs(check); return (EX_NOPERM); } else if (ret != EPKG_OK) { warnx("Error accessing the package database"); pkg_audit_free(audit); kh_destroy_pkgs(check); return (EX_IOERR); } if (pkgdb_open(&db, PKGDB_DEFAULT) != EPKG_OK) { pkg_audit_free(audit); kh_destroy_pkgs(check); return (EX_IOERR); } if (pkgdb_obtain_lock(db, PKGDB_LOCK_READONLY) != EPKG_OK) { pkgdb_close(db); pkg_audit_free(audit); kh_destroy_pkgs(check); warnx("Cannot get a read lock on a database, it is locked by another process"); return (EX_TEMPFAIL); } if ((it = pkgdb_query(db, NULL, MATCH_ALL)) == NULL) { warnx("Error accessing the package database"); ret = EX_IOERR; } else { while ((ret = pkgdb_it_next(it, &pkg, PKG_LOAD_BASIC|PKG_LOAD_RDEPS)) == EPKG_OK) { add_to_check(check, pkg); pkg = NULL; } ret = EX_OK; } if (db != NULL) { pkgdb_it_free(it); pkgdb_release_lock(db, PKGDB_LOCK_READONLY); pkgdb_close(db); } if (ret != EX_OK) { pkg_audit_free(audit); kh_destroy_pkgs(check); return (ret); } } /* Now we have vulnxml loaded and check list formed */ #ifdef HAVE_CAPSICUM if (cap_enter() < 0 && errno != ENOSYS) { warn("cap_enter() failed"); pkg_audit_free(audit); kh_destroy_pkgs(check); return (EPKG_FATAL); } #endif if (pkg_audit_process(audit) == EPKG_OK) { kh_foreach_value(check, pkg, { if (pkg_audit_is_vulnerable(audit, pkg, quiet, &sb)) { vuln ++; printf("%s", sbuf_data(sb)); if (recursive) { const char *name; kh_pkgs_t *seen = kh_init_pkgs(); pkg_get(pkg, PKG_NAME, &name); sbuf_clear(sb); sbuf_printf(sb, "Packages that depend on %s: ", name); print_recursive_rdeps(check, pkg , sb, seen, true); sbuf_finish(sb); printf("%s\n\n", sbuf_data(sb)); kh_destroy_pkgs(seen); } sbuf_delete(sb); } pkg_free(pkg); });