pkg_install-20080222

This commit is contained in:
joerg 2008-02-22 16:14:57 +00:00
parent ca4e85e5a3
commit e30cd2c074
7 changed files with 723 additions and 12 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: perform.c,v 1.1.1.7 2008/01/27 14:11:27 joerg Exp $ */
/* $NetBSD: perform.c,v 1.1.1.8 2008/02/22 16:14:57 joerg Exp $ */
#if HAVE_CONFIG_H
#include "config.h"
@ -14,7 +14,7 @@
#if 0
static const char *rcsid = "from FreeBSD Id: perform.c,v 1.44 1997/10/13 15:03:46 jkh Exp";
#else
__RCSID("$NetBSD: perform.c,v 1.1.1.7 2008/01/27 14:11:27 joerg Exp $");
__RCSID("$NetBSD: perform.c,v 1.1.1.8 2008/02/22 16:14:57 joerg Exp $");
#endif
#endif
@ -817,7 +817,11 @@ pkg_do(const char *pkg, lpkg_head_t *pkgs)
(void) fexec(CHMOD_CMD, "+x", INSTALL_FNAME, NULL); /* make sure */
if (Verbose)
printf("Running install with PRE-INSTALL for %s.\n", PkgName);
errno = 0;
if (!Fake && fexec("./" INSTALL_FNAME, PkgName, "PRE-INSTALL", NULL)) {
if (errno != 0)
warn("exec of install script failed");
else
warnx("install script returned error status");
errc = 1;
goto success; /* nothing to uninstall yet */

View File

@ -1,4 +1,4 @@
/* $NetBSD: perform.c,v 1.1.1.5 2008/02/07 23:42:16 joerg Exp $ */
/* $NetBSD: perform.c,v 1.1.1.6 2008/02/22 16:14:58 joerg Exp $ */
#if HAVE_CONFIG_H
#include "config.h"
@ -17,7 +17,7 @@
#if 0
static const char *rcsid = "from FreeBSD Id: perform.c,v 1.23 1997/10/13 15:03:53 jkh Exp";
#else
__RCSID("$NetBSD: perform.c,v 1.1.1.5 2008/02/07 23:42:16 joerg Exp $");
__RCSID("$NetBSD: perform.c,v 1.1.1.6 2008/02/22 16:14:58 joerg Exp $");
#endif
#endif
@ -234,6 +234,8 @@ read_meta_data_from_fd(int fd)
(*target)[size] = '\0';
}
archive_read_finish(archive);
return meta;
#endif
}
@ -360,6 +362,14 @@ pkg_do(const char *pkg)
meta = read_meta_data_from_pkgdb(pkg);
}
if (meta->meta_contents == NULL ||
meta->meta_comment == NULL ||
meta->meta_desc == NULL) {
warnx("invalid package `%s' skipped", pkg);
free_pkg_meta(meta);
return 1;
}
/*
* Index is special info type that has to override all others to make
* any sense.

View File

@ -1,4 +1,4 @@
# $NetBSD: Makefile.in,v 1.1.1.4 2007/12/24 00:03:06 joerg Exp $
# $NetBSD: Makefile.in,v 1.1.1.5 2008/02/22 16:14:58 joerg Exp $
srcdir= @srcdir@
@ -13,6 +13,8 @@ man7dir= $(mandir)/man7
tar= @tar@
ftp= @ftp@
BOOTSTRAP= @bootstrap@
RANLIB= @RANLIB@
AR= @AR@
CC= @CC@
@ -24,9 +26,14 @@ INSTALL= @INSTALL@
LIB= libinstall.a
OBJS= automatic.o conflicts.o dewey.o fexec.o file.o ftpio.o global.o iterate.o \
lpkg.o opattern.o path.o pen.o pexec.o pkgdb.o plist.o \
str.o var.o version.o
OBJS= automatic.o conflicts.o decompress.o dewey.o fexec.o file.o \
ftpio.o global.o iterate.o lpkg.o opattern.o \
path.o pen.o pexec.o pkgdb.o plist.o \
str.o var.o version.o vulnerabilities-file.o
.if !empty(BOOTSTRAP)
CPPFLAGS+= -DBOOTSTRAP
.endif
all: $(LIB)

190
dist/pkg_install/lib/decompress.c vendored Normal file
View File

@ -0,0 +1,190 @@
/*-
* Copyright (c) 2008 Joerg Sonnenberger <joerg@NetBSD.org>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if HAVE_CONFIG_H
#include "config.h"
#endif
#include <nbcompat.h>
#if HAVE_SYS_CDEFS_H
#include <sys/cdefs.h>
#endif
__RCSID("$NetBSD: decompress.c,v 1.1.1.1 2008/02/22 16:14:59 joerg Exp $");
#ifdef BOOTSTRAP
#include "lib.h"
int
decompress_buffer(const char *input, size_t input_len, char **output,
size_t *output_len)
{
return 0;
}
#else
#include <bzlib.h>
#if HAVE_ERR_H
#include <err.h>
#endif
#include <limits.h>
#include <stdlib.h>
#include <zlib.h>
#include "lib.h"
static void
decompress_bzip2(const char *in, size_t in_len, char **out, size_t *out_len)
{
bz_stream stream;
size_t output_produced;
if (in_len < SSIZE_MAX / 10)
*out_len = in_len * 10;
else
*out_len = in_len;
if ((*out = malloc(*out_len + 1)) == NULL)
err(EXIT_FAILURE, "malloc failed");
stream.next_in = (char *)in;
stream.avail_in = in_len;
stream.next_out = *out;
stream.avail_out = *out_len;
output_produced = 0;
stream.bzalloc = NULL;
stream.bzfree = NULL;
stream.opaque = NULL;
if (BZ2_bzDecompressInit(&stream, 0, 0) != BZ_OK)
errx(EXIT_FAILURE, "BZ2_bzDecompressInit failed");
for (;;) {
switch (BZ2_bzDecompress(&stream)) {
case BZ_STREAM_END:
if (BZ2_bzDecompressEnd(&stream) != Z_OK)
errx(EXIT_FAILURE, "inflateEnd failed");
output_produced = *out_len - stream.avail_out;
*out = realloc(*out, output_produced + 1);
if (*out == NULL)
err(EXIT_FAILURE, "realloc failed");
*out_len = output_produced;
(*out)[*out_len] = '\0';
return;
case BZ_OK:
output_produced = *out_len - stream.avail_out;
if (*out_len <= SSIZE_MAX / 2)
*out_len *= 2;
else
errx(EXIT_FAILURE, "input too large");
*out = realloc(*out, *out_len + 1);
stream.next_out = *out + output_produced;
stream.avail_out = *out_len - output_produced;
break;
default:
errx(EXIT_FAILURE, "inflate failed");
}
}
}
static void
decompress_zlib(const char *in, size_t in_len, char **out, size_t *out_len)
{
z_stream stream;
size_t output_produced;
if (in_len < SSIZE_MAX / 10)
*out_len = in_len * 10;
else
*out_len = in_len;
if ((*out = malloc(*out_len + 1)) == NULL)
err(EXIT_FAILURE, "malloc failed");
stream.next_in = (unsigned char *)in;
stream.avail_in = in_len;
stream.next_out = (unsigned char *)*out;
stream.avail_out = *out_len;
output_produced = 0;
stream.zalloc = Z_NULL;
stream.zfree = Z_NULL;
stream.opaque = NULL;
if (inflateInit2(&stream, 47) != Z_OK)
errx(EXIT_FAILURE, "inflateInit failed");
for (;;) {
switch (inflate(&stream, Z_FINISH)) {
case Z_STREAM_END:
if (inflateEnd(&stream) != Z_OK)
errx(EXIT_FAILURE, "inflateEnd failed");
output_produced = *out_len - stream.avail_out;
*out = realloc(*out, output_produced + 1);
if (*out == NULL)
err(EXIT_FAILURE, "realloc failed");
*out_len = output_produced;
(*out)[*out_len] = '\0';
return;
case Z_OK:
output_produced = *out_len - stream.avail_out;
if (*out_len < SSIZE_MAX / 2)
*out_len *= 2;
else if (*out_len == SSIZE_MAX - 1)
errx(EXIT_FAILURE, "input too large");
else
*out_len = SSIZE_MAX - 1;
*out = realloc(*out, *out_len + 1);
stream.next_out = (unsigned char *)*out + output_produced;
stream.avail_out = *out_len - output_produced;
break;
default:
errx(EXIT_FAILURE, "inflate failed");
}
}
}
int
decompress_buffer(const char *input, size_t input_len, char **output,
size_t *output_len)
{
if (input_len < 4)
return 0;
if (input[0] == 'B' && input[1] == 'Z' && input[2] == 'h' &&
input[3] >= '1' && input[3] <= '9') {
/* Normal bzip2. */
decompress_bzip2(input, input_len, output, output_len);
} else if (input[0] == 037 && (unsigned char)input[1] == 139 &&
input[2] == 8 && (input[3] & 0xe0) == 0) {
/* gzip header with Deflate method */
decompress_zlib(input, input_len, output, output_len);
} else /* plain text */
return 0;
return 1;
}
#endif /* BOOTSTRAP */

View File

@ -1,4 +1,4 @@
/* $NetBSD: lib.h,v 1.1.1.7 2008/02/03 21:21:35 joerg Exp $ */
/* $NetBSD: lib.h,v 1.1.1.8 2008/02/22 16:14:58 joerg Exp $ */
/* from FreeBSD Id: lib.h,v 1.25 1997/10/08 07:48:03 charnier Exp */
@ -281,6 +281,13 @@ typedef struct {
void (*cleanup)(void); /* called on non-zero child exit status */
} pipe_to_system_t;
struct pkg_vulnerabilities {
size_t entries;
char **vulnerability;
char **classification;
char **advisory;
};
/* If URLlength()>0, then there is a ftp:// or http:// in the string,
* and this must be an URL. Hide this behind a more obvious name. */
#define IS_URL(str) (URLlength(str) > 0)
@ -416,9 +423,19 @@ lpkg_t *alloc_lpkg(const char *);
lpkg_t *find_on_queue(lpkg_head_t *, const char *);
void free_lpkg(lpkg_t *);
/* Extract input if compressed to NUL terminated buffer (not counted) */
int decompress_buffer(const char *, size_t, char **, size_t *);
/* Parse NUL terminated inputed, argument is strlen of the input */
struct pkg_vulnerabilities *parse_pkg_vulnerabilities(const char *, size_t, int);
/* Read pkg_vulnerabilities from file */
struct pkg_vulnerabilities *read_pkg_vulnerabilities(const char *, int, int);
void free_pkg_vulnerabilities(struct pkg_vulnerabilities *);
/* Externs */
extern Boolean Verbose;
extern Boolean Fake;
extern Boolean Force;
extern const char *gpg_cmd;
#endif /* _INST_LIB_LIB_H_ */

View File

@ -1,4 +1,4 @@
/* $NetBSD: version.h,v 1.1.1.10 2008/02/07 23:42:17 joerg Exp $ */
/* $NetBSD: version.h,v 1.1.1.11 2008/02/22 16:14:59 joerg Exp $ */
/*
* Copyright (c) 2001 Thomas Klausner. All rights reserved.
@ -33,6 +33,6 @@
#ifndef _INST_LIB_VERSION_H_
#define _INST_LIB_VERSION_H_
#define PKGTOOLS_VERSION "20080208"
#define PKGTOOLS_VERSION "20080222"
#endif /* _INST_LIB_VERSION_H_ */

View File

@ -0,0 +1,483 @@
/*-
* Copyright (c) 2008 Joerg Sonnenberger <joerg@NetBSD.org>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if HAVE_CONFIG_H
#include "config.h"
#endif
#include <nbcompat.h>
#if HAVE_SYS_CDEFS_H
#include <sys/cdefs.h>
#endif
__RCSID("$NetBSD: vulnerabilities-file.c,v 1.1.1.1 2008/02/22 16:14:59 joerg Exp $");
#if HAVE_SYS_STAT_H
#include <sys/stat.h>
#endif
#if HAVE_SYS_WAIT_H
#include <sys/wait.h>
#endif
#include <ctype.h>
#if HAVE_ERR_H
#include <err.h>
#endif
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <stdlib.h>
#include <string.h>
#ifndef NETBSD
#include <nbcompat/sha1.h>
#include <nbcompat/sha2.h>
#else
#include <sha1.h>
#include <sha2.h>
#endif
#include <unistd.h>
#include "lib.h"
const char *gpg_cmd;
static void
verify_signature(const char *input, size_t input_len)
{
pid_t child;
int fd[2], status;
if (gpg_cmd == NULL)
err(EXIT_FAILURE, "GPG variable not set in configuration file");
if (pipe(fd) == -1)
err(EXIT_FAILURE, "cannot create input pipes");
child = vfork();
if (child == -1)
err(EXIT_FAILURE, "cannot fork GPG process");
if (child == 0) {
close(fd[1]);
close(STDIN_FILENO);
if (dup2(fd[0], STDIN_FILENO) == -1) {
static const char err_msg[] =
"cannot redirect stdin of GPG process\n";
write(STDERR_FILENO, err_msg, sizeof(err_msg) - 1);
_exit(255);
}
close(fd[0]);
execlp(gpg_cmd, gpg_cmd, "--verify", "-", (char *)NULL);
_exit(255);
}
close(fd[0]);
if (write(fd[1], input, input_len) != input_len)
errx(EXIT_FAILURE, "Short read from GPG");
close(fd[1]);
waitpid(child, &status, 0);
if (status)
errx(EXIT_FAILURE, "GPG could not verify the signature");
}
static void *
sha512_hash_init(void)
{
static SHA512_CTX hash_ctx;
SHA512_Init(&hash_ctx);
return &hash_ctx;
}
static void
sha512_hash_update(void *ctx, const void *data, size_t len)
{
SHA512_CTX *hash_ctx = ctx;
SHA512_Update(hash_ctx, data, len);
}
static const char *
sha512_hash_finish(void *ctx)
{
static char hash[SHA512_DIGEST_STRING_LENGTH];
SHA512_CTX *hash_ctx = ctx;
SHA512_End(hash_ctx, hash);
return hash;
}
static void *
sha1_hash_init(void)
{
static SHA1_CTX hash_ctx;
SHA1Init(&hash_ctx);
return &hash_ctx;
}
static void
sha1_hash_update(void *ctx, const void *data, size_t len)
{
SHA1_CTX *hash_ctx = ctx;
SHA1Update(hash_ctx, data, len);
}
static const char *
sha1_hash_finish(void *ctx)
{
static char hash[SHA1_DIGEST_STRING_LENGTH];
SHA1_CTX *hash_ctx = ctx;
SHA1End(hash_ctx, hash);
return hash;
}
static const struct hash_algorithm {
const char *name;
size_t name_len;
void * (*init)(void);
void (*update)(void *, const void *, size_t);
const char * (* finish)(void *);
} hash_algorithms[] = {
{ "SHA512", 6, sha512_hash_init, sha512_hash_update,
sha512_hash_finish },
{ "SHA1", 4, sha1_hash_init, sha1_hash_update,
sha1_hash_finish },
{ NULL, 0, NULL, NULL, NULL }
};
static void
verify_hash(const char *input, const char *hash_line)
{
const struct hash_algorithm *hash;
void *ctx;
const char *last_start, *next, *hash_value;
for (hash = hash_algorithms; hash->name != NULL; ++hash) {
if (strncmp(hash_line, hash->name, hash->name_len))
continue;
if (isspace((unsigned char)hash_line[hash->name_len]))
break;
}
if (hash->name == NULL) {
const char *end_name;
for (end_name = hash_line; *end_name != '\0'; ++end_name) {
if (!isalnum((unsigned char)*end_name))
break;
}
warnx("Unsupported hash algorithm: %.*s",
(int)(end_name - hash_line), hash_line);
return;
}
hash_line += hash->name_len;
if (!isspace((unsigned char)*hash_line))
errx(EXIT_FAILURE, "Invalid #CHECKSUM");
while (isspace((unsigned char)*hash_line) && *hash_line != '\n')
++hash_line;
if (*hash_line == '\n')
errx(EXIT_FAILURE, "Invalid #CHECKSUM");
ctx = (*hash->init)();
for (last_start = input; *input != '\0'; input = next) {
if ((next = strchr(input, '\n')) == NULL)
errx(EXIT_FAILURE, "Missing newline in pkg-vulnerabilities");
++next;
if (*input == '\n' ||
strncmp(input, "-----BEGIN", 10) == 0 ||
strncmp(input, "Hash:", 5) == 0 ||
strncmp(input, "# $NetBSD", 9) == 0 ||
strncmp(input, "#CHECKSUM", 9) == 0) {
(*hash->update)(ctx, last_start, input - last_start);
last_start = next;
} else if (strncmp(input, "Version:", 8) == 0)
break;
}
(*hash->update)(ctx, last_start, input - last_start);
hash_value = (*hash->finish)(ctx);
if (strncmp(hash_line, hash_value, strlen(hash_value)))
errx(EXIT_FAILURE, "%s hash doesn't match", hash->name);
hash_line += strlen(hash_value);
while (isspace((unsigned char)*hash_line) && *hash_line != '\n')
++hash_line;
if (!isspace((unsigned char)*hash_line))
errx(EXIT_FAILURE, "Invalid #CHECKSUM");
}
static void
add_vulnerability(struct pkg_vulnerabilities *pv, size_t *allocated, const char *line)
{
size_t len_pattern, len_class, len_url;
const char *start_pattern, *start_class, *start_url;
start_pattern = line;
start_class = line;
while (*start_class != '\0' && !isspace((unsigned char)*start_class))
++start_class;
len_pattern = start_class - line;
while (*start_class != '\n' && isspace((unsigned char)*start_class))
++start_class;
if (*start_class == '0' || *start_class == '\n')
errx(EXIT_FAILURE, "Input error: missing classification");
start_url = start_class;
while (*start_url != '\0' && !isspace((unsigned char)*start_url))
++start_url;
len_class = start_url - start_class;
while (*start_url != '\n' && isspace((unsigned char)*start_url))
++start_url;
if (*start_url == '0' || *start_url == '\n')
errx(EXIT_FAILURE, "Input error: missing URL");
line = start_url;
while (*line != '\0' && !isspace((unsigned char)*line))
++line;
len_url = line - start_url;
if (pv->entries == *allocated) {
if (*allocated == 0)
*allocated = 16;
else if (*allocated <= SSIZE_MAX / 2)
*allocated *= 2;
else
errx(EXIT_FAILURE, "Too many vulnerabilities");
pv->vulnerability = realloc(pv->vulnerability,
sizeof(char *) * *allocated);
pv->classification = realloc(pv->classification,
sizeof(char *) * *allocated);
pv->advisory = realloc(pv->advisory,
sizeof(char *) * *allocated);
if (pv->vulnerability == NULL ||
pv->classification == NULL || pv->advisory == NULL)
errx(EXIT_FAILURE, "realloc failed");
}
if ((pv->vulnerability[pv->entries] = malloc(len_pattern + 1)) == NULL)
errx(EXIT_FAILURE, "malloc failed");
memcpy(pv->vulnerability[pv->entries], start_pattern, len_pattern);
pv->vulnerability[pv->entries][len_pattern] = '\0';
if ((pv->classification[pv->entries] = malloc(len_class + 1)) == NULL)
errx(EXIT_FAILURE, "malloc failed");
memcpy(pv->classification[pv->entries], start_class, len_class);
pv->classification[pv->entries][len_class] = '\0';
if ((pv->advisory[pv->entries] = malloc(len_url + 1)) == NULL)
errx(EXIT_FAILURE, "malloc failed");
memcpy(pv->advisory[pv->entries], start_url, len_url);
pv->advisory[pv->entries][len_url] = '\0';
++pv->entries;
}
struct pkg_vulnerabilities *
read_pkg_vulnerabilities(const char *path, int ignore_missing, int check_sum)
{
struct pkg_vulnerabilities *pv;
struct stat st;
int fd;
char *input, *decompressed_input;
size_t input_len, decompressed_len;
ssize_t bytes_read;
if ((fd = open(path, O_RDONLY)) == -1) {
if (errno == ENOENT && ignore_missing)
return NULL;
err(EXIT_FAILURE, "Cannot open %s", path);
}
if (fstat(fd, &st) == -1)
err(EXIT_FAILURE, "Cannot stat %s", path);
if ((st.st_mode & S_IFMT) != S_IFREG)
errx(EXIT_FAILURE, "Input is not regular file");
if (st.st_size > SSIZE_MAX - 1)
errx(EXIT_FAILURE, "Input too large");
input_len = (size_t)st.st_size;
if (input_len < 4)
err(EXIT_FAILURE, "Input too short for a pkg_vulnerability file");
if ((input = malloc(input_len + 1)) == NULL)
err(EXIT_FAILURE, "malloc failed");
if ((bytes_read = read(fd, input, input_len)) == -1)
err(1, "Failed to read input");
if (bytes_read != st.st_size)
errx(1, "Unexpected short read");
if (decompress_buffer(input, input_len, &decompressed_input,
&decompressed_len)) {
free(input);
input = decompressed_input;
input_len = decompressed_len;
}
pv = parse_pkg_vulnerabilities(input, input_len, check_sum);
free(input);
return pv;
}
struct pkg_vulnerabilities *
parse_pkg_vulnerabilities(const char *input, size_t input_len, int check_sum)
{
struct pkg_vulnerabilities *pv;
long version;
char *end;
const char *iter, *next;
size_t allocated_vulns;
pv = malloc(sizeof(*pv));
if (pv == NULL)
err(EXIT_FAILURE, "malloc failed");
allocated_vulns = pv->entries = 0;
pv->vulnerability = NULL;
pv->classification = NULL;
pv->advisory = NULL;
if (strlen(input) != input_len)
errx(1, "Invalid input (NUL character found)");
if (check_sum)
verify_signature(input, input_len);
for (iter = input; *iter; iter = next) {
if ((next = strchr(iter, '\n')) == NULL)
errx(EXIT_FAILURE, "Missing newline in pkg-vulnerabilities");
++next;
if (*iter == '\0' || *iter == '\n')
continue;
if (strncmp(iter, "-----BEGIN", 10) == 0)
continue;
if (strncmp(iter, "Hash:", 5) == 0)
continue;
if (strncmp(iter, "# $NetBSD", 9) == 0)
continue;
if (*iter == '#' && isspace((unsigned char)iter[1])) {
for (++iter; iter != next; ++iter) {
if (!isspace((unsigned char)*iter))
errx(EXIT_FAILURE, "Invalid header");
}
continue;
}
if (strncmp(iter, "#FORMAT", 7) != 0)
errx(EXIT_FAILURE, "Input header is malformed");
iter += 7;
if (!isspace((unsigned char)*iter))
errx(EXIT_FAILURE, "Invalid #FORMAT");
++iter;
version = strtol(iter, &end, 10);
if (iter == end || version != 1 || *end != '.')
errx(EXIT_FAILURE, "Input #FORMAT");
iter = end + 1;
version = strtol(iter, &end, 10);
if (iter == end || version != 1 || *end != '.')
errx(EXIT_FAILURE, "Input #FORMAT");
iter = end + 1;
version = strtol(iter, &end, 10);
if (iter == end || version != 0)
errx(EXIT_FAILURE, "Input #FORMAT");
for (iter = end; iter != next; ++iter) {
if (!isspace((unsigned char)*iter))
errx(EXIT_FAILURE, "Input #FORMAT");
}
break;
}
if (*iter == '\0')
errx(EXIT_FAILURE, "Missing #CHECKSUM or content");
for (iter = next; *iter; iter = next) {
if ((next = strchr(iter, '\n')) == NULL)
errx(EXIT_FAILURE, "Missing newline in pkg-vulnerabilities");
++next;
if (*iter == '\0' || *iter == '\n')
continue;
if (strncmp(iter, "Version:", 5) == 0)
break;
if (*iter == '#' &&
(iter[1] == '\0' || iter[1] == '\n' || isspace((unsigned char)iter[1])))
continue;
if (strncmp(iter, "#CHECKSUM", 9) == 0) {
iter += 9;
if (!isspace((unsigned char)*iter))
errx(EXIT_FAILURE, "Invalid #CHECKSUM");
while (isspace((unsigned char)*iter))
++iter;
verify_hash(input, iter);
continue;
}
if (*iter == '#') {
/*
* This should really be an error,
* but it is still used.
*/
/* errx(EXIT_FAILURE, "Invalid data line starting with #"); */
continue;
}
add_vulnerability(pv, &allocated_vulns, iter);
}
if (pv->entries != allocated_vulns) {
pv->vulnerability = realloc(pv->vulnerability,
sizeof(char *) * pv->entries);
pv->classification = realloc(pv->classification,
sizeof(char *) * pv->entries);
pv->advisory = realloc(pv->advisory,
sizeof(char *) * pv->entries);
if (pv->vulnerability == NULL ||
pv->classification == NULL || pv->advisory == NULL)
errx(EXIT_FAILURE, "realloc failed");
}
return pv;
}
void
free_pkg_vulnerabilities(struct pkg_vulnerabilities *pv)
{
size_t i;
for (i = 0; i < pv->entries; ++i) {
free(pv->vulnerability[i]);
free(pv->classification[i]);
free(pv->advisory[i]);
}
free(pv->vulnerability);
free(pv->classification);
free(pv->advisory);
free(pv);
}