diff options
author | joerg <joerg@pkgsrc.org> | 2009-02-02 12:34:59 +0000 |
---|---|---|
committer | joerg <joerg@pkgsrc.org> | 2009-02-02 12:34:59 +0000 |
commit | d7cc6db11bfefd0006364a122a40572d9eb9b739 (patch) | |
tree | 4c0fb6728ab9db1b5dc2233bb02e4ef34022a604 /pkgtools/pkg_install/files/lib | |
parent | ea71974691a75ab2e2b9c62a6fb9dcc136b266de (diff) | |
download | pkgsrc-d7cc6db11bfefd0006364a122a40572d9eb9b739.tar.gz |
Merge pkg_install-20090201 from pkg_install-renovation branch.
- DB support is always included from libnbcompat if needed
- pkg_view and linkfarm are not installed any more; they are not moved
into the attic yet, so they can easily be installed as separte package
- common configuration file to customise the behavior of various
components; this supersedes the old audit-packages.conf
- support for PKSC7 signatures (using X509 certs) and GPG signatures for
packages in a secure way. See pkg_admin(8) for how to create them and
pkg_install.conf(5) for the options to use them
- audit-packages and download-vulnerability-list are wrapper scripts
around pkg_admin. They try to mimic the classic options if used sanely.
"pkg_admin audit" is now an order of magnitude faster than before
- pkg_add uses libarchive and libfetch instead of external ftp and tar:
- progress bar is currently missing for downloads
- "pkg_add -" is no longer supported
- no adhoc check for conficts between dependencies and already
installed packages
- "pkg_add -s" has been replaced with an option in pkg_install.conf,
verification of plain detached GPG signatures is no longer supported
- optional check for vulnerabilities before adding a package
- if /var and /usr/pkg are on different fileystems it is twice as fast
now
- conflicts due to overlapping plists are checked before installation
- pkg_add no longer plays with the process limits
- pkg_add and pkg_delete have a new destdir option; scripts have to
either be modified to use PKG_DESTDIR or should be disabled
- pkg_add -u for now can't be used to update to the exact same version
- internal "rm -rf" and "mkdir_p" code
- all memory allocation failures are not explicitly fatal
- if a file is not removed due to a failed checksum, still remove the
entry from pkgdb
Diffstat (limited to 'pkgtools/pkg_install/files/lib')
33 files changed, 2653 insertions, 2477 deletions
diff --git a/pkgtools/pkg_install/files/lib/Makefile.in b/pkgtools/pkg_install/files/lib/Makefile.in index e513a89a7d4..3e361d51df9 100644 --- a/pkgtools/pkg_install/files/lib/Makefile.in +++ b/pkgtools/pkg_install/files/lib/Makefile.in @@ -1,26 +1,25 @@ -# $NetBSD: Makefile.in,v 1.23 2008/04/26 17:40:01 joerg Exp $ +# $NetBSD: Makefile.in,v 1.24 2009/02/02 12:35:01 joerg Exp $ srcdir= @srcdir@ pkgdbdir= @pkgdbdir@ mandir= @mandir@ datarootdir= @datarootdir@ +sysconfdir= @sysconfdir@ cat5dir= $(mandir)/cat5 cat7dir= $(mandir)/cat7 man5dir= $(mandir)/man5 man7dir= $(mandir)/man7 -tar= @tar@ -ftp= @ftp@ - BOOTSTRAP= @bootstrap@ +SSL_SUPPORT= @ssl_support@ RANLIB= @RANLIB@ AR= @AR@ CC= @CC@ CPPFLAGS= @CPPFLAGS@ -I. -I$(srcdir) -DEFS= @DEFS@ -DDEF_LOG_DIR=\"$(pkgdbdir)\" -DTAR_CMD=\"$(tar)\" -DFTP_CMD=\"$(ftp)\" +DEFS= @DEFS@ -DDEF_LOG_DIR=\"$(pkgdbdir)\" CFLAGS= @CFLAGS@ INSTALL= @INSTALL@ @@ -28,9 +27,11 @@ INSTALL= @INSTALL@ LIB= libinstall.a 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 + gpgsig.o global.o iterate.o lpkg.o opattern.o \ + parse-config.o path.o pkgdb.o plist.o remove.o \ + str.o var.o version.o vulnerabilities-file.o xwrapper.o + +CPPFLAGS+= -DSYSCONFDIR=\"$(sysconfdir)\" .if !empty(BOOTSTRAP) CPPFLAGS+= -DBOOTSTRAP @@ -38,6 +39,11 @@ CPPFLAGS+= -DBOOTSTRAP OBJS+= pkg_io.o .endif +.if !empty(SSL_SUPPORT) +CPPFLAGS+= -DHAVE_SSL +OBJS+= pkg_signature.o pkcs7.o +.endif + all: $(LIB) .c.o: @@ -57,5 +63,7 @@ install: $(INSTALL) -m 755 -d ${DESTDIR}$(cat7dir) $(INSTALL) -m 444 pkg_summary.5 ${DESTDIR}$(man5dir)/pkg_summary.5 $(INSTALL) -m 444 pkg_summary.cat5 ${DESTDIR}$(cat5dir)/pkg_summary.0 + $(INSTALL) -m 444 pkg_install.conf.5 ${DESTDIR}$(man5dir)/pkg_install.conf.5 + $(INSTALL) -m 444 pkg_install.conf.cat5 ${DESTDIR}$(cat5dir)/pkg_install.conf.0 $(INSTALL) -m 444 pkgsrc.7 ${DESTDIR}$(man7dir)/pkgsrc.7 $(INSTALL) -m 444 pkgsrc.cat7 ${DESTDIR}$(cat7dir)/pkgsrc.0 diff --git a/pkgtools/pkg_install/files/lib/automatic.c b/pkgtools/pkg_install/files/lib/automatic.c index 865f9ecdd43..3d991dd3333 100644 --- a/pkgtools/pkg_install/files/lib/automatic.c +++ b/pkgtools/pkg_install/files/lib/automatic.c @@ -1,4 +1,4 @@ -/* $NetBSD: automatic.c,v 1.4 2007/08/15 02:08:40 joerg Exp $ */ +/* $NetBSD: automatic.c,v 1.5 2009/02/02 12:35:01 joerg Exp $ */ /*- * Copyright (c) 2005 The NetBSD Foundation, Inc. @@ -39,9 +39,7 @@ #if HAVE_SYS_CDEFS_H #include <sys/cdefs.h> #endif -#ifndef lint -__RCSID("$NetBSD: automatic.c,v 1.4 2007/08/15 02:08:40 joerg Exp $"); -#endif +__RCSID("$NetBSD: automatic.c,v 1.5 2009/02/02 12:35:01 joerg Exp $"); #if HAVE_ASSERT_H #include <assert.h> diff --git a/pkgtools/pkg_install/files/lib/config.h.in b/pkgtools/pkg_install/files/lib/config.h.in index 3a32b2fda26..7ee4d522d24 100644 --- a/pkgtools/pkg_install/files/lib/config.h.in +++ b/pkgtools/pkg_install/files/lib/config.h.in @@ -36,9 +36,6 @@ /* Define to 1 if you have the <fnmatch.h> header file. */ #undef HAVE_FNMATCH_H -/* Define to 1 if you have the `getrlimit' function. */ -#undef HAVE_GETRLIMIT - /* Define to 1 if you have the <glob.h> header file. */ #undef HAVE_GLOB_H @@ -66,9 +63,6 @@ /* Define to 1 if you have the <regex.h> header file. */ #undef HAVE_REGEX_H -/* Define to 1 if you have the `setrlimit' function. */ -#undef HAVE_SETRLIMIT - /* Define to 1 if you have the <signal.h> header file. */ #undef HAVE_SIGNAL_H diff --git a/pkgtools/pkg_install/files/lib/conflicts.c b/pkgtools/pkg_install/files/lib/conflicts.c index 0be50f3b1cc..f77679ae473 100644 --- a/pkgtools/pkg_install/files/lib/conflicts.c +++ b/pkgtools/pkg_install/files/lib/conflicts.c @@ -1,3 +1,34 @@ +/* $NetBSD: conflicts.c,v 1.8 2009/02/02 12:35:01 joerg Exp $ */ + +/*- + * Copyright (c) 2007 Roland Illig <rillig@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. + */ + /* * XXX: Reading the +CONTENTS files of all installed packages is * rather slow. Since this check is necessary to avoid conflicting @@ -13,6 +44,12 @@ #include <nbcompat.h> +#if HAVE_SYS_CDEFS_H +#include <sys/cdefs.h> +#endif + +__RCSID("$NetBSD: conflicts.c,v 1.8 2009/02/02 12:35:01 joerg Exp $"); + #if HAVE_ERR_H #include <err.h> #endif @@ -30,21 +67,11 @@ */ struct package_conflict { const char *pkgname; + const char *skip_pkgname; char **conflicting_pkgname; char **conflicting_pattern; }; -static void * -nonnull(void *p) -{ - - if (p == NULL) { - err(EXIT_FAILURE, "NullPointerException"); - /* NOTREACHED */ - } - return p; -} - static FILE * fopen_contents(const char *pkgname, const char *mode) { @@ -70,6 +97,10 @@ check_package_conflict(const char *pkgname, void *v) FILE *f; int rv; + if (conflict->skip_pkgname != NULL && + strcmp(conflict->skip_pkgname, pkgname) == 0) + return 0; + rv = 0; f = fopen_contents(pkgname, "r"); @@ -81,8 +112,8 @@ check_package_conflict(const char *pkgname, void *v) continue; if (pkg_match(p->name, conflict->pkgname) == 1) { - *(conflict->conflicting_pkgname) = nonnull(strdup(pkgname)); - *(conflict->conflicting_pattern) = nonnull(strdup(p->name)); + *(conflict->conflicting_pkgname) = xstrdup(pkgname); + *(conflict->conflicting_pattern) = xstrdup(p->name); rv = 1 /* nonzero, stop iterating */; break; } @@ -100,12 +131,14 @@ check_package_conflict(const char *pkgname, void *v) * variables are set to NULL. */ int -some_installed_package_conflicts_with(const char *pkgname, char **inst_pkgname, char **inst_pattern) +some_installed_package_conflicts_with(const char *pkgname, + const char *skip_pkgname, char **inst_pkgname, char **inst_pattern) { struct package_conflict cfl; int rv; cfl.pkgname = pkgname; + cfl.skip_pkgname = skip_pkgname; *inst_pkgname = NULL; *inst_pattern = NULL; cfl.conflicting_pkgname = inst_pkgname; diff --git a/pkgtools/pkg_install/files/lib/decompress.c b/pkgtools/pkg_install/files/lib/decompress.c index 79448def1d2..820f988691a 100644 --- a/pkgtools/pkg_install/files/lib/decompress.c +++ b/pkgtools/pkg_install/files/lib/decompress.c @@ -1,3 +1,5 @@ +/* $NetBSD: decompress.c,v 1.2 2009/02/02 12:35:01 joerg Exp $ */ + /*- * Copyright (c) 2008 Joerg Sonnenberger <joerg@NetBSD.org>. * All rights reserved. @@ -37,7 +39,7 @@ #include <sys/cdefs.h> #endif -__RCSID("$NetBSD: decompress.c,v 1.1 2008/02/19 15:16:24 joerg Exp $"); +__RCSID("$NetBSD: decompress.c,v 1.2 2009/02/02 12:35:01 joerg Exp $"); #ifdef BOOTSTRAP #include "lib.h" @@ -71,8 +73,7 @@ decompress_bzip2(const char *in, size_t in_len, char **out, size_t *out_len) *out_len = in_len * 10; else *out_len = in_len; - if ((*out = malloc(*out_len + 1)) == NULL) - err(EXIT_FAILURE, "malloc failed"); + *out = xmalloc(*out_len + 1); stream.next_in = (char *)in; stream.avail_in = in_len; @@ -92,9 +93,7 @@ decompress_bzip2(const char *in, size_t in_len, char **out, size_t *out_len) 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 = xrealloc(*out, output_produced + 1); *out_len = output_produced; (*out)[*out_len] = '\0'; return; @@ -104,7 +103,7 @@ decompress_bzip2(const char *in, size_t in_len, char **out, size_t *out_len) *out_len *= 2; else errx(EXIT_FAILURE, "input too large"); - *out = realloc(*out, *out_len + 1); + *out = xrealloc(*out, *out_len + 1); stream.next_out = *out + output_produced; stream.avail_out = *out_len - output_produced; break; @@ -124,8 +123,7 @@ decompress_zlib(const char *in, size_t in_len, char **out, size_t *out_len) *out_len = in_len * 10; else *out_len = in_len; - if ((*out = malloc(*out_len + 1)) == NULL) - err(EXIT_FAILURE, "malloc failed"); + *out = xmalloc(*out_len + 1); stream.next_in = (unsigned char *)in; stream.avail_in = in_len; @@ -145,9 +143,7 @@ decompress_zlib(const char *in, size_t in_len, char **out, size_t *out_len) 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 = xrealloc(*out, output_produced + 1); *out_len = output_produced; (*out)[*out_len] = '\0'; return; @@ -159,7 +155,7 @@ decompress_zlib(const char *in, size_t in_len, char **out, size_t *out_len) errx(EXIT_FAILURE, "input too large"); else *out_len = SSIZE_MAX - 1; - *out = realloc(*out, *out_len + 1); + *out = xrealloc(*out, *out_len + 1); stream.next_out = (unsigned char *)*out + output_produced; stream.avail_out = *out_len - output_produced; break; diff --git a/pkgtools/pkg_install/files/lib/dewey.c b/pkgtools/pkg_install/files/lib/dewey.c index a133b414535..98240c7221d 100644 --- a/pkgtools/pkg_install/files/lib/dewey.c +++ b/pkgtools/pkg_install/files/lib/dewey.c @@ -1,4 +1,4 @@ -/* $NetBSD: dewey.c,v 1.9 2008/12/14 10:18:16 rillig Exp $ */ +/* $NetBSD: dewey.c,v 1.10 2009/02/02 12:35:01 joerg Exp $ */ /* * Copyright © 2002 Alistair G. Crooks. All rights reserved. diff --git a/pkgtools/pkg_install/files/lib/fexec.c b/pkgtools/pkg_install/files/lib/fexec.c index 8e0f31426d2..5789bd4933c 100644 --- a/pkgtools/pkg_install/files/lib/fexec.c +++ b/pkgtools/pkg_install/files/lib/fexec.c @@ -1,3 +1,5 @@ +/* $NetBSD: fexec.c,v 1.11 2009/02/02 12:35:01 joerg Exp $ */ + /*- * Copyright (c) 2003 The NetBSD Foundation, Inc. * All rights reserved. @@ -57,9 +59,7 @@ #include "lib.h" -#ifndef lint -__RCSID("$NetBSD: fexec.c,v 1.10 2008/04/29 05:46:08 martin Exp $"); -#endif +__RCSID("$NetBSD: fexec.c,v 1.11 2009/02/02 12:35:01 joerg Exp $"); static int vfcexec(const char *, int, const char *, va_list); @@ -106,8 +106,7 @@ vfcexec(const char *path, int skipempty, const char *arg, va_list ap) int retval; argv_size = 16; - if ((argv = malloc(argv_size * sizeof(*argv))) == NULL) - err(EXIT_FAILURE, "vfcexec: malloc failed"); + argv = xcalloc(argv_size, sizeof(*argv)); argv[0] = arg; argc = 1; @@ -115,9 +114,7 @@ vfcexec(const char *path, int skipempty, const char *arg, va_list ap) do { if (argc == argv_size) { argv_size *= 2; - argv = realloc(argv, argv_size * sizeof(*argv)); - if (argv == NULL) - err(EXIT_FAILURE, "vfcexec: realloc failed"); + argv = xrealloc(argv, argv_size * sizeof(*argv)); } arg = va_arg(ap, const char *); if (skipempty && arg && strlen(arg) == 0) diff --git a/pkgtools/pkg_install/files/lib/file.c b/pkgtools/pkg_install/files/lib/file.c index 47146a31cac..5ee81b935a4 100644 --- a/pkgtools/pkg_install/files/lib/file.c +++ b/pkgtools/pkg_install/files/lib/file.c @@ -1,4 +1,4 @@ -/* $NetBSD: file.c,v 1.25 2008/04/26 17:40:01 joerg Exp $ */ +/* $NetBSD: file.c,v 1.26 2009/02/02 12:35:01 joerg Exp $ */ #if HAVE_CONFIG_H #include "config.h" @@ -13,13 +13,7 @@ #if HAVE_SYS_QUEUE_H #include <sys/queue.h> #endif -#ifndef lint -#if 0 -static const char *rcsid = "from FreeBSD Id: file.c,v 1.29 1997/10/08 07:47:54 charnier Exp"; -#else -__RCSID("$NetBSD: file.c,v 1.25 2008/04/26 17:40:01 joerg Exp $"); -#endif -#endif +__RCSID("$NetBSD: file.c,v 1.26 2009/02/02 12:35:01 joerg Exp $"); /* * FreeBSD install - a package for the installation and maintainance @@ -190,6 +184,7 @@ typedef struct url_t { /* A table of valid leading strings for URLs */ static const url_t urls[] = { + {"file://", 7}, {"ftp://", 6}, {"http://", 7}, {NULL} @@ -218,263 +213,6 @@ URLlength(const char *fname) } /* - * Returns the host part of a URL - */ -const char * -fileURLHost(const char *fname, char *where, int max) -{ - const char *ret; - int i; - - assert(where != NULL); - assert(max > 0); - - if ((i = URLlength(fname)) < 0) { /* invalid URL? */ - errx(EXIT_FAILURE, "fileURLhost called with a bad URL: `%s'", fname); - } - fname += i; - /* Do we have a place to stick our work? */ - ret = where; - while (*fname && *fname != '/' && --max) - *where++ = *fname++; - *where = '\0'; - - return ret; -} - -/* - * Returns the filename part of a URL - */ -const char * -fileURLFilename(const char *fname, char *where, int max) -{ - const char *ret; - int i; - - assert(where != NULL); - assert(max > 0); - - if ((i = URLlength(fname)) < 0) { /* invalid URL? */ - errx(EXIT_FAILURE, "fileURLFilename called with a bad URL: `%s'", fname); - } - fname += i; - /* Do we have a place to stick our work? */ - ret = where; - while (*fname && *fname != '/') - ++fname; - if (*fname == '/') { - while (*fname && --max) - *where++ = *fname++; - } - *where = '\0'; - - return ret; -} - -/* - * Try and fetch a file by URL, returning the directory name for where - * it's unpacked, if successful. To be handed to leave_playpen() later. - */ -char * -fileGetURL(const char *spec) -{ - char host[MAXHOSTNAMELEN], file[MaxPathSize]; - const char *cp; - char *rp; - char pen[MaxPathSize]; - int rc; - - rp = NULL; - if (!IS_URL(spec)) { - errx(EXIT_FAILURE, "fileGetURL was called with non-URL arg '%s'", spec); - } - - /* Some sanity checks on the URL */ - cp = fileURLHost(spec, host, MAXHOSTNAMELEN); - if (!*cp) { - warnx("URL `%s' has bad host part!", spec); - return NULL; - } - cp = fileURLFilename(spec, file, MaxPathSize); - if (!*cp) { - warnx("URL `%s' has bad filename part!", spec); - return NULL; - } - - if (Verbose) - printf("Trying to fetch %s.\n", spec); - - pen[0] = '\0'; - rp = make_playpen(pen, sizeof(pen), 0); - if (rp == NULL) { - printf("Error: Unable to construct a new playpen for FTP!\n"); - return NULL; - } - - rp = strdup(pen); - rc = unpackURL(spec, pen); - if (rc < 0) { - leave_playpen(rp); /* Don't leave dir hang around! */ - - printf("Error on unpackURL('%s', '%s')\n", spec, pen); - return NULL; - } - return rp; -} - -static char * -resolvepattern1(const char *name) -{ - static char tmp[MaxPathSize]; - char *cp; - - if (IS_URL(name)) { - /* some package depends on a wildcard pkg */ - int rc; - - rc = expandURL(tmp, name); - if (rc < 0) { - return NULL; - } - if (Verbose) - printf("'%s' expanded to '%s'\n", name, tmp); - return tmp; /* return expanded URL w/ corrent pkg */ - } - else if (ispkgpattern(name)) { - cp = find_best_matching_file(dirname_of(name), basename_of(name), 1, 0); - if (cp) { - snprintf(tmp, sizeof(tmp), "%s/%s", dirname_of(name), cp); - free(cp); - return tmp; - } - } else { - if (isfile(name)) { - strlcpy(tmp, name, sizeof(tmp)); - return tmp; - } - } - - return NULL; -} - -static char * -resolvepattern(const char *name) -{ - char tmp[MaxPathSize]; - char *cp; - const char *suf; - - cp = resolvepattern1(name); - if (cp != NULL) - return cp; - - if (ispkgpattern(name)) - return NULL; - - suf = suffix_of(name); - if (!strcmp(suf, "tbz") || !strcmp(suf, "tgz")) - return NULL; - - /* add suffix and try */ - snprintf(tmp, sizeof(tmp), "%s.tbz", name); - cp = resolvepattern1(tmp); - if (cp != NULL) - return cp; - snprintf(tmp, sizeof(tmp), "%s.tgz", name); - cp = resolvepattern1(tmp); - if (cp != NULL) - return cp; - - /* add version number wildcard and try */ - snprintf(tmp, sizeof(tmp), "%s-[0-9]*", name); - return resolvepattern1(tmp); -} - -/* - * Look for filename/pattern "fname" in - * Returns a full path/URL where the pkg can be found - */ -char * -fileFindByPath(const char *fname) -{ - char tmp[MaxPathSize]; - struct path *path; - - /* - * 1. if fname is an absolute pathname or a URL, - * just use it. - */ - if (IS_FULLPATH(fname) || IS_URL(fname)) - return resolvepattern(fname); - - /* - * 2. otherwise, use PKG_PATH. - */ - TAILQ_FOREACH(path, &PkgPath, pl_entry) { - char *cp; - const char *cp2 = path->pl_path; - - if (Verbose) - printf("trying PKG_PATH %s\n", cp2); - - if (IS_FULLPATH(cp2) || IS_URL(cp2)) { - snprintf(tmp, sizeof(tmp), "%s/%s", cp2, fname); - } - else { - char cwdtmp[MaxPathSize]; - if (getcwd(cwdtmp, sizeof(cwdtmp)) == NULL) - errx(EXIT_FAILURE, "getcwd"); - snprintf(tmp, sizeof(tmp), "%s/%s/%s", cwdtmp, cp2, fname); - } - cp = resolvepattern(tmp); - if (cp) - return cp; - } - -#if 0 - /* - * 3. finally, search current directory. - */ - snprintf(tmp, sizeof(tmp), "./%s", fname); - return resolvepattern(tmp); -#else - return NULL; -#endif -} - -/* - * Expect "fname" to point at a file, and read it into - * the buffer returned. - */ -char * -fileGetContents(char *fname) -{ - char *contents; - struct stat sb; - int fd; - - if (stat(fname, &sb) == FAIL) { - cleanup(0); - errx(2, "can't stat '%s'", fname); - } - - contents = (char *) malloc((size_t) (sb.st_size) + 1); - fd = open(fname, O_RDONLY, 0); - if (fd == FAIL) { - cleanup(0); - errx(2, "unable to open '%s' for reading", fname); - } - if (read(fd, contents, (size_t) sb.st_size) != (size_t) sb.st_size) { - cleanup(0); - errx(2, "short read on '%s' - did not get %lld bytes", - fname, (long long) sb.st_size); - } - close(fd); - contents[(size_t) sb.st_size] = '\0'; - return contents; -} - -/* * Takes a filename and package name, returning (in "try") the canonical * "preserve" name for it. */ @@ -509,97 +247,6 @@ make_preserve_name(char *try, size_t max, char *name, char *file) return TRUE; } -/* - * Write the contents of "str" to a file - */ -void -write_file(char *name, char *str) -{ - size_t len; - FILE *fp; - - if ((fp = fopen(name, "w")) == (FILE *) NULL) { - cleanup(0); - errx(2, "cannot fopen '%s' for writing", name); - } - len = strlen(str); - if (fwrite(str, 1, len, fp) != len) { - cleanup(0); - errx(2, "short fwrite on '%s', tried to write %ld bytes", - name, (long) len); - } - if (fclose(fp)) { - cleanup(0); - errx(2, "failure to fclose '%s'", name); - } -} - -void -copy_file(char *dir, char *fname, char *to) -{ - char fpath[MaxPathSize]; - - (void) snprintf(fpath, sizeof(fpath), "%s%s%s", - (fname[0] != '/') ? dir : "", - (fname[0] != '/') ? "/" : "", - fname); - if (fexec("cp", "-r", fpath, to, NULL)) { - cleanup(0); - errx(2, "could not perform 'cp -r %s %s'", fpath, to); - } -} - -void -move_file(char *dir, char *fname, char *to) -{ - char fpath[MaxPathSize]; - - (void) snprintf(fpath, sizeof(fpath), "%s%s%s", - (fname[0] != '/') ? dir : "", - (fname[0] != '/') ? "/" : "", - fname); - if (fexec("mv", fpath, to, NULL)) { - cleanup(0); - errx(2, "could not perform 'mv %s %s'", fpath, to); - } -} - -void -move_files(const char *dir, const char *pattern, const char *to) -{ - char fpath[MaxPathSize]; - glob_t globbed; - size_t i; - - (void) snprintf(fpath, sizeof(fpath), "%s/%s", dir, pattern); - if ((i=glob(fpath, GLOB_NOSORT, NULL, &globbed)) != 0) { - switch(i) { - case GLOB_NOMATCH: - warn("no files matching ``%s'' found", fpath); - break; - case GLOB_ABORTED: - warn("globbing aborted"); - break; - case GLOB_NOSPACE: - warn("out-of-memory during globbing"); - break; - default: - warn("unknown error during globbing"); - break; - } - return; - } - - /* Moving globbed files -- we just use mv(1) to do the job */ - for (i=0; i<globbed.gl_pathc; i++) - if (fexec("mv", globbed.gl_pathv[i], to, NULL)) { - cleanup(0); - errx(2, "could not perform 'mv %s %s'", globbed.gl_pathv[i], to); - } - - return; -} - void remove_files(const char *path, const char *pattern) { @@ -635,74 +282,6 @@ remove_files(const char *path, const char *pattern) } /* - * Unpack a tar file - */ -int -unpack(const char *pkg, const lfile_head_t *filesp) -{ - const char *decompress_cmd = NULL; - const char *suf; - int count = 0; - lfile_t *lfp; - char **up_argv; - int up_argc = 7; - int i = 0; - int result; - - if (filesp != NULL) - TAILQ_FOREACH(lfp, filesp, lf_link) - count++; - up_argc += count; - up_argv = malloc((count + up_argc + 1) * sizeof(char *)); - if (!IS_STDIN(pkg)) { - suf = suffix_of(pkg); - if (!strcmp(suf, "tbz") || !strcmp(suf, "bz2")) - decompress_cmd = BZIP2_CMD; - else if (!strcmp(suf, "tgz") || !strcmp(suf, "gz")) - decompress_cmd = GZIP_CMD; - else if (!strcmp(suf, "tar")) - ; /* do nothing */ - else - errx(EXIT_FAILURE, "don't know how to decompress %s, sorry", pkg); - } else - decompress_cmd = GZIP_CMD; - - up_argv[i] = (char *)strrchr(TAR_CMD, '/'); - if (up_argv[i] == NULL) - up_argv[i] = TAR_CMD; - else - up_argv[i]++; /* skip / character */ - if (count > 0) - up_argv[++i] = "--fast-read"; - if (decompress_cmd != NULL) { - up_argv[++i] = "--use-compress-program"; - up_argv[++i] = (char *)decompress_cmd; - } - up_argv[++i] = "-xpf"; - up_argv[++i] = (char *)pkg; - if (count > 0) - TAILQ_FOREACH(lfp, filesp, lf_link) - up_argv[++i] = lfp->lf_name; - up_argv[++i] = NULL; - - if (Verbose) { - printf("running: %s", TAR_CMD); - for (i = 1; up_argv[i] != NULL; i++) - printf(" %s", up_argv[i]); - printf("\n"); - } - - result = pfcexec(NULL, TAR_CMD, (const char **)up_argv); - free(up_argv); - if (result != 0) { - warnx("extract of %s failed", pkg); - return 1; - } - - return 0; -} - -/* * Using fmt, replace all instances of: * * %F With the parameter "name" @@ -712,60 +291,84 @@ unpack(const char *pkg, const lfile_head_t *filesp) * * Check that no overflows can occur. */ -void -format_cmd(char *buf, size_t size, char *fmt, char *dir, char *name) +int +format_cmd(char *buf, size_t size, const char *fmt, const char *dir, const char *name) { - char scratch[MaxPathSize * 2]; - char *bufp; + size_t remaining, quoted; + char *bufp, *tmp; char *cp; - for (bufp = buf; (int) (bufp - buf) < size && *fmt;) { - if (*fmt == '%') { - if (*++fmt != 'D' && name == NULL) { - cleanup(0); - errx(2, "no last file available for '%s' command", buf); + for (bufp = buf, remaining = size; remaining > 1 && *fmt;) { + if (*fmt != '%') { + *bufp++ = *fmt++; + --remaining; + continue; + } + + if (*++fmt != 'D' && name == NULL) { + warnx("no last file available for '%s' command", buf); + return -1; + } + switch (*fmt) { + case 'F': + quoted = shquote(name, bufp, remaining); + if (quoted >= remaining) { + warnx("overflow during quoting"); + return -1; + } + bufp += quoted; + remaining -= quoted; + break; + + case 'D': + quoted = shquote(dir, bufp, remaining); + if (quoted >= remaining) { + warnx("overflow during quoting"); + return -1; } - switch (*fmt) { - case 'F': - strlcpy(bufp, name, size - (int) (bufp - buf)); - bufp += strlen(bufp); - break; - - case 'D': - strlcpy(bufp, dir, size - (int) (bufp - buf)); - bufp += strlen(bufp); - break; - - case 'B': - (void) snprintf(scratch, sizeof(scratch), "%s/%s", dir, name); - if ((cp = strrchr(scratch, '/')) == (char *) NULL) { - cp = scratch; - } - *cp = '\0'; - strlcpy(bufp, scratch, size - (int) (bufp - buf)); - bufp += strlen(bufp); - break; - - case 'f': - (void) snprintf(scratch, sizeof(scratch), "%s/%s", dir, name); - if ((cp = strrchr(scratch, '/')) == (char *) NULL) { - cp = scratch; - } else { - cp++; - } - strlcpy(bufp, cp, size - (int) (bufp - buf)); - bufp += strlen(bufp); - break; - - default: - *bufp++ = '%'; - *bufp++ = *fmt; - break; + bufp += quoted; + remaining -= quoted; + break; + + case 'B': + tmp = xasprintf("%s/%s", dir, name); + cp = strrchr(tmp, '/'); + *cp = '\0'; + quoted = shquote(tmp, bufp, remaining); + free(tmp); + if (quoted >= remaining) { + warnx("overflow during quoting"); + return -1; } - ++fmt; - } else { - *bufp++ = *fmt++; + bufp += quoted; + remaining -= quoted; + break; + + case 'f': + tmp = xasprintf("%s/%s", dir, name); + cp = strrchr(tmp, '/') + 1; + quoted = shquote(cp, bufp, remaining); + free(tmp); + if (quoted >= remaining) { + warnx("overflow during quoting"); + return -1; + } + bufp += quoted; + remaining -= quoted; + break; + + default: + if (remaining == 1) { + warnx("overflow during quoting"); + return -1; + } + *bufp++ = '%'; + *bufp++ = *fmt; + remaining -= 2; + break; } + ++fmt; } *bufp = '\0'; + return 0; } diff --git a/pkgtools/pkg_install/files/lib/ftpio.c b/pkgtools/pkg_install/files/lib/ftpio.c deleted file mode 100644 index 4e0c23cf17b..00000000000 --- a/pkgtools/pkg_install/files/lib/ftpio.c +++ /dev/null @@ -1,1252 +0,0 @@ -/* $NetBSD: ftpio.c,v 1.29 2008/04/29 05:46:08 martin Exp $ */ - -#if HAVE_CONFIG_H -#include "config.h" -#endif -#include <nbcompat.h> -#if HAVE_SYS_CDEFS_H -#include <sys/cdefs.h> -#endif -#ifndef lint -__RCSID("$NetBSD: ftpio.c,v 1.29 2008/04/29 05:46:08 martin Exp $"); -#endif - -/*- - * Copyright (c) 1999-2008 The NetBSD Foundation, Inc. - * All rights reserved. - * - * This code is derived from software contributed to The NetBSD Foundation - * by Hubert Feyrer <hubert@feyrer.de> and Thomas Klausner. - * - * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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_SYS_TYPES_H -#include <sys/types.h> -#endif -#if HAVE_SYS_TIME_H -#include <sys/time.h> -#endif -#if HAVE_SYS_POLL_H -#include <sys/poll.h> -#endif -#if HAVE_SYS_WAIT_H -#include <sys/wait.h> -#endif -#if HAVE_SIGNAL_H -#include <signal.h> -#endif -#if HAVE_ASSERT_H -#include <assert.h> -#endif -#if HAVE_CTYPE_H -#include <ctype.h> -#endif -#if HAVE_ERR_H -#include <err.h> -#endif -#if HAVE_ERRNO_H -#include <errno.h> -#endif -#if HAVE_FCNTL_H -#include <fcntl.h> -#endif -#if HAVE_NETDB_H -#include <netdb.h> -#endif -#if HAVE_REGEX_H -#include <regex.h> -#endif -#if HAVE_STRING_H -#include <string.h> -#endif -#if HAVE_STDIO_H -#include <stdio.h> -#endif -#if HAVE_STDLIB_H -#include <stdlib.h> -#endif -#if HAVE_TERMCAP_H -#include <termcap.h> -#endif -#if HAVE_UNISTD_H -#include <unistd.h> -#endif - -#include "../lib/lib.h" - -/* - * Names of environment variables used to pass things to - * subprocesses, for connection caching. - */ -#define PKG_FTPIO_COMMAND "PKG_FTPIO_COMMAND" -#define PKG_FTPIO_ANSWER "PKG_FTPIO_ANSWER" -#define PKG_FTPIO_CNT "PKG_FTPIO_CNT" -#define PKG_FTPIO_CURRENTHOST "PKG_FTPIO_CURRENTHOST" -#define PKG_FTPIO_CURRENTDIR "PKG_FTPIO_CURRENTDIR" - -#undef STANDALONE /* define for standalone debugging */ - -/* File descriptors */ -typedef struct { - int command; - int answer; -} fds; - - -static int needclose=0; -static int ftp_started=0; -static fds ftpio; -static int ftp_pid; -static char term[1024]; -static char bold_on[1024]; -static char bold_off[1024]; - -static char *ftp_expand_URL(const char *, char *); -static int hexvalue(char); -static char *http_expand_URL(const char *, char *); -static int http_extract_fn(char *, char *, size_t); -static void URL_decode(char *); - -/* - * expect "str" (a regular expression) on file descriptor "fd", storing - * the FTP return code of the command in the integer "ftprc". The "str" - * string is expected to match some FTP return codes after a '\n', e.g. - * "\n(550|226).*\n" - */ -static int -expect(int fd, const char *str, int *ftprc) -{ - int rc; - char buf[256]; - regex_t rstr; - int done; - struct pollfd set[1]; - int retval; - regmatch_t match; - int verbose_expect=0; - - if (regcomp(&rstr, str, REG_EXTENDED) != 0) - err(EXIT_FAILURE, "expect: regcomp() failed"); - - memset(buf, '\n', sizeof(buf)); - - done=0; - retval=0; - set[0].fd = fd; - set[0].events = POLLIN; - while(!done) { - rc = poll(set, 1, 60*60*1000); /* seconds until next message from tar */ - switch (rc) { - case -1: - if (errno == EINTR) - break; - warn("expect: poll() failed (probably ftp died because of bad args)"); - done = 1; - retval = -1; - break; - case 0: - warnx("expect: poll() timeout"); - /* need to send ftp coprocess SIGINT to make it stop - * downloading into dir that we'll blow away in a second */ - kill(ftp_pid, SIGINT); - - /* Wait until ftp coprocess is responsive again - * XXX Entering recursion here! - */ - rc = ftp_cmd("cd .\n", "\n(550|250).*\n"); - if (rc != 250) { - /* now we have a really good reason to bail out ;) */ - } - /* ftp is at command prompt again, and will wait for our - * next command. If we were downloading, we can now safely - * continue and remove the dir that the tar command was - * expanding to */ - - done = 1; /* hope that's ok */ - retval = -1; - break; - default: - if (set[0].revents & POLLHUP) { - done = 1; - retval = -1; - break; - } - - rc = read(fd, &buf[sizeof(buf) - 1], 1); - if (rc <= 0) { - done = 1; - retval = -1; - break; - } - - if (verbose_expect) - putchar(buf[sizeof(buf)-1]); - - if (regexec(&rstr, buf, 1, &match, 0) == 0) { - if (ftprc && isdigit((unsigned char)buf[match.rm_so+1])) - *ftprc = atoi(buf+match.rm_so+1); - - done=1; - retval=0; - } - - memmove(buf, buf+1, sizeof(buf)-1); /* yes, this is non-performant */ - break; - } - } - - return retval; -} - -/* - * send a certain ftp-command "cmd" to our FTP coprocess, and wait for - * "expectstr" to be returned. Return numeric FTP return code or -1 - * in case of an error (usually expect() timeout) - */ -int -ftp_cmd(const char *cmd, const char *expectstr) -{ - int rc=0, verbose_ftp=0; - int len; - - if (Verbose) - verbose_ftp=1; - - if (verbose_ftp) - fprintf(stderr, "\n%sftp> %s%s", bold_on, cmd, bold_off); - - fflush(stdout); - len = write(ftpio.command, cmd, strlen(cmd)); - if (len == strlen(cmd)) { - if (expectstr) { - /* set "rc" to the FTP error code: */ - if (expect(ftpio.answer, expectstr, &rc) == -1) - rc = -1; /* some error occurred */ - } - } else { - if (Verbose) - warn("short write"); - } - - return rc; -} - - -/* - * Really fire up FTP coprocess - */ -static int -setupCoproc(const char *base) -{ - int command_pipe[2]; - int answer_pipe[2]; - int rc1, rc2; - char buf[20]; - char *argv0 = (char *)strrchr(FTP_CMD, '/'); - if (argv0 == NULL) - argv0 = FTP_CMD; - else - argv0++; - - rc1 = pipe(command_pipe); - rc2 = pipe(answer_pipe); - - if(rc1==-1 || rc2==-1) { - warn("setupCoproc: pipe() failed"); - return -1; - } - - if (command_pipe[0] == -1 || command_pipe[1] == -1 || - answer_pipe[0] == -1 || answer_pipe[1] == -1 ) { - warn("setupCoproc: pipe() returned bogus descriptor"); - return -1; - } - - rc1 = fork(); - switch (rc1) { - case -1: - /* Error */ - - warn("setupCoproc: fork() failed"); - return -1; - break; - - case 0: - /* Child */ - - (void) close(command_pipe[1]); - rc1 = dup2(command_pipe[0], 0); - if (rc1 == -1) { - err(EXIT_FAILURE, "setupCoproc: dup2 failed (command_pipe[0])"); - } - (void) close(command_pipe[0]); - - (void) close(answer_pipe[0]); - rc1 = dup2(answer_pipe[1], 1); - if (rc1 == -1) { - err(EXIT_FAILURE, "setupCoproc: dup2 failed (answer_pipe[1])"); - } - (void) close(answer_pipe[1]); - - setbuf(stdout, NULL); - - if (Verbose) - fprintf(stderr, "%sftp -detv %s%s\n", bold_on, base, bold_off); - rc1 = execlp(FTP_CMD, argv0, "-detv", base, NULL); - warn("setupCoproc: execlp() failed"); - exit(1); - break; - default: - /* Parent */ - (void) close(command_pipe[0]); - (void) close(answer_pipe[1]); - - (void) snprintf(buf, sizeof(buf), "%d", command_pipe[1]); - setenv(PKG_FTPIO_COMMAND, buf, 1); - (void) snprintf(buf, sizeof(buf), "%d", answer_pipe[0]); - setenv(PKG_FTPIO_ANSWER, buf, 1); - - ftpio.command = command_pipe[1]; - ftpio.answer = answer_pipe[0]; - ftp_pid = rc1; /* to ^C transfers */ - - fcntl(ftpio.command, F_SETFL, O_NONBLOCK); - fcntl(ftpio.answer , F_SETFL, O_NONBLOCK); - - break; - } - - return 0; -} - - -/* - * Dummy signal handler to detect if the ftp(1) coprocess or - * and of the processes of the tar/gzip pipeline dies. - */ -static void -sigchld_handler (int n) -{ - /* Make poll(2) return EINTR */ -} - - -/* - * SIGPIPE only happens when there's something wrong with the FTP - * coprocess. In that case, set mark to not try to close shut down - * the coprocess. - */ -static void -sigpipe_handler(int n) -{ - /* aparently our ftp companion died */ - if (Verbose) - fprintf(stderr, "SIGPIPE!\n"); - needclose = 0; -} - - -/* - * Close the FTP coprocess' current connection, but - * keep the process itself alive. - */ -void -ftp_stop(void) -{ -#if defined(__svr4__) && defined(__sun__) - char env[BUFSIZ]; -#endif - const char *tmp1, *tmp2; - - if (!ftp_started) - return; - - tmp1=getenv(PKG_FTPIO_COMMAND); - tmp2=getenv(PKG_FTPIO_ANSWER); - - /* (Only) the last one closes the link */ - if (tmp1 != NULL && tmp2 != NULL) { - if (needclose) - ftp_cmd("close\n", "\n(221 .*|Not connected.)\n"); - - (void) close(ftpio.command); - (void) close(ftpio.answer); - } - -#if defined(__svr4__) && defined(__sun__) - (void) snprintf(env, sizeof(env), "%s=", PKG_FTPIO_COMMAND); - putenv(env); - (void) snprintf(env, sizeof(env), "%s=", PKG_FTPIO_ANSWER); - putenv(env); -#else - unsetenv(PKG_FTPIO_COMMAND); - unsetenv(PKG_FTPIO_ANSWER); -#endif -} - - -/* - * (Start and re-)Connect the FTP coprocess to some host/dir. - * If the requested host/dir is different than the one that the - * coprocess is currently at, close first. - */ -int -ftp_start(const char *base) -{ - const char *tmp1, *tmp2; - char *p; - int rc; - char newHost[MAXHOSTNAMELEN]; - const char *newDir; - const char *currentHost=getenv(PKG_FTPIO_CURRENTHOST); - const char *currentDir=getenv(PKG_FTPIO_CURRENTDIR); - int urllen; - - /* talk to termcap for bold on/off escape sequences */ - if (getenv("TERM") != NULL && tgetent(term, getenv("TERM")) > 0) { - p = bold_on; tgetstr("md", &p); - p = bold_off; tgetstr("me", &p); - } else { - bold_on[0] = '\0'; - bold_off[0] = '\0'; - } - - fileURLHost(base, newHost, sizeof(newHost)); - urllen = URLlength(base); - if (urllen < 0 || !(newDir = strchr(base + URLlength(base), '/'))) - errx(EXIT_FAILURE, "ftp_start: bad URL '%s'", base); - newDir++; - if (currentHost - && currentDir - && ( strcmp(newHost, currentHost) != 0 - || strcmp(newDir, currentDir) != 0)) { /* could handle new dir case better here, w/o reconnect */ - if (Verbose) { - printf("ftp_start: new host or dir, stopping previous connect...\n"); - printf("currentHost='%s', newHost='%s'\n", currentHost, newHost); - printf("currentDir='%s', newDir='%s'\n", currentDir, newDir); - } - - ftp_stop(); - - if (Verbose) - printf("ftp stopped\n"); - } - setenv(PKG_FTPIO_CURRENTHOST, newHost, 1); /* need to update this in the environment */ - setenv(PKG_FTPIO_CURRENTDIR, newDir, 1); /* for subprocesses to have this available */ - - tmp1=getenv(PKG_FTPIO_COMMAND); - tmp2=getenv(PKG_FTPIO_ANSWER); - if(tmp1==NULL || tmp2==NULL || *tmp1=='\0' || *tmp2=='\0') { - /* no FTP coprocess running yet */ - - if (Verbose) - printf("Spawning FTP coprocess\n"); - - rc = setupCoproc(base); - if (rc == -1) { - warnx("setupCoproc() failed"); - return -1; - } - - needclose=1; - signal(SIGPIPE, sigpipe_handler); - signal(SIGCHLD, sigchld_handler); - - if ((expect(ftpio.answer, "\n(221|250|221|550).*\n", &rc) != 0) - || rc != 250) { - warnx("expect1 failed, rc=%d", rc); - return -1; - } - - /* nbftp now issues a CWD for each part of the path - * and will return a code for each of them. No idea how to - * deal with that other than to issue a 'prompt off' to - * get something that we can wait for and that does NOT - * look like a CWD command's output */ - rc = ftp_cmd("prompt off\n", "\n(Interactive mode off|221).*\n"); - if ((rc == 221) || (rc == -1)) { - /* something is wrong */ - ftp_started=1; /* not really, but for ftp_stop() */ - ftp_stop(); - warnx("prompt failed - wrong dir?"); - return -1; - } - - ftp_started=1; - } else { - /* get FDs of our coprocess */ - - ftpio.command = dup(atoi(tmp1)); - if (ftpio.command == -1 ) { - warnx("command dup() failed, increase 'descriptors' limit"); - return -1; - } - ftpio.answer = dup(atoi(tmp2)); - if (ftpio.answer == -1 ) { - warnx("answer dup() failed, increase 'descriptors' limit"); - return -1; - } - - if (Verbose) - printf("Reusing FDs %s/%s for communication to FTP coprocess\n", tmp1, tmp2); - - fcntl(ftpio.command, F_SETFL, O_NONBLOCK); - fcntl(ftpio.answer , F_SETFL, O_NONBLOCK); - } - - return 0; -} - - -/* - * Expand the given wildcard URL "wildcardurl" if possible, and store the - * expanded value into "expandedurl". return 0 if successful, -1 else. - */ -int -expandURL(char *expandedurl, const char *wildcardurl) -{ - char *pattern; - char *bestmatch; - char base[MaxPathSize]; - - pattern=strrchr(wildcardurl, '/'); - if (pattern == NULL){ - warnx("expandURL: no '/' in URL %s?!", wildcardurl); - return -1; - } - if (pattern-strchr(wildcardurl, '/') < 2) { - /* only one or two slashes in total */ - warnx("expandURL: not enough '/' in URL %s", wildcardurl); - return -1; - } - (void) snprintf(base, sizeof(base), "%.*s/", - (int)(pattern-wildcardurl), wildcardurl); - pattern++; - - if (strncmp(wildcardurl, "ftp://", 6) == 0) - bestmatch=ftp_expand_URL(base, pattern); - else if (strncmp(wildcardurl, "http://", 7) == 0) - bestmatch=http_expand_URL(base, pattern); - else { - warnx("expandURL: unknown protocol in URL `%s'", wildcardurl); - return -1; - } - - /* no match found */ - if (bestmatch == NULL) - return -1; - - snprintf(expandedurl, MaxPathSize, "%s%s", base, bestmatch); - if (Verbose) - printf("best match: '%s'\n", expandedurl); - - return 0; -} - -/* for a given wildcard ftp:// URL, find the best matching pkg */ -static char * -ftp_expand_URL(const char *base, char *pattern) -{ - char *s, buf[MaxPathSize]; - char tmpname[MaxPathSize]; - char best[MaxPathSize]; - char s_best[MaxPathSize]; - int rc, got_list, tfd, retry_tbz; - - retry_tbz = 0; - best[0]='\0'; - s_best[0]='\0'; - - rc = ftp_start(base); - if (rc == -1) { - warnx("ftp_start() failed"); - return NULL; - } - - strlcpy(tmpname, "/var/tmp/pkg.XXXXXX", sizeof(tmpname)); - tfd=mkstemp(tmpname); - if (tfd == -1) { - warnx("Cannot generate temp file for ftp(1)'s nlist output"); - return NULL; - } - close(tfd); /* We don't need the file descriptor, but will use - the file in a second */ - - s=strpbrk(pattern, "<>[]?*{"); /* Could leave out "[]?*" here; - * ftp(1) is not that stupid */ - if (!s) { - /* This should only happen when getting here with (only) a package - * name specified to pkg_add, and PKG_PATH containing some URL. - */ - (void) snprintf(buf, sizeof(buf), "nlist %s %s\n", pattern, tmpname); - } else { - /* replace possible version(wildcard) given with "-*". - * we can't use the pkg wildcards here as dewey compare - * and alternates won't be handled by ftp(1); sort - * out later, using pkg_match() */ - if (retry_tbz) { -retry_with_tbz: - (void) snprintf(buf, sizeof(buf), "nlist %.*s*.tbz %s\n", - (int)(s-pattern), pattern, tmpname); - retry_tbz = 0; - } else { - (void) snprintf(buf, sizeof(buf), "nlist %.*s*.tgz %s\n", - (int)(s-pattern), pattern, tmpname); - retry_tbz = 1; - } - } - - rc = ftp_cmd(buf, "\n(550|450|226).*\n"); /* catch errors */ - if (rc != 226) - got_list = 0; - else - got_list = 1; - - /* Sync - don't remove */ - rc = ftp_cmd("cd .\n", "\n(550|250|257).*\n"); - if (rc != 250) { - warnx("chdir failed!"); - unlink(tmpname); /* remove clutter */ - return NULL; - } - - if (got_list == 1 && access(tmpname, R_OK)==0) { - FILE *f; - char filename[MaxPathSize]; - - f=fopen(tmpname, "r"); - if (f == NULL) { - warn("fopen"); - unlink(tmpname); /* remove clutter */ - return NULL; - } - /* The following loop is basically the same as the readdir() loop - * in findmatchingname() */ - while (fgets(filename, sizeof(filename), f)) { - - /* - * We need to strip off any .t[bg]z etc. - * suffix here - */ - - char s_filename[MaxPathSize]; - char s_pattern[MaxPathSize]; - - filename[strlen(filename)-1] = '\0'; - - strip_txz(s_filename, NULL, filename); - strip_txz(s_pattern, NULL, pattern); - - if (pkg_order(s_pattern, s_filename, - s_best[0] != '\0' ? s_best : NULL) == 1) { - strlcpy(s_best, s_filename, sizeof(s_best)); - strlcpy(best, filename, sizeof(best)); - } - } - (void) fclose(f); - } - - if (retry_tbz) - goto retry_with_tbz; - - if (best[0] == '\0' && Verbose) - warnx("nothing appropriate found"); - - unlink(tmpname); - - if (best[0] == '\0') - return NULL; - - return strdup(best); -} - -/* for a given wildcard http:// URL, find the best matching pkg */ -static char * -http_expand_URL(const char *base, char *pattern) -{ - char best[MaxPathSize]; - char s_best[MaxPathSize]; - char line[BUFSIZ]; - char filename[MaxPathSize]; - FILE *fp; - int pipefds[2]; - int state; - pid_t pid; - - *best = '\0'; - *s_best = '\0'; - - /* Set up a pipe for getting the file list */ - if (pipe(pipefds) == -1) { - warnx("cannot create pipe"); - return NULL; - } - if ((pid = fork()) == -1) { - warnx("cannot fork ftp process"); - return NULL; - } - if (pid == 0) { /* The child */ - if (dup2(pipefds[1], STDOUT_FILENO) == -1) { - warnx("dup2 failed before starting ftp"); - _exit(2); - } - close(pipefds[0]); - close(pipefds[1]); - /* get URL contents to stdout and thus to parent, - * silently */ - execlp("ftp", "ftp", "-V", "-o", "-", base, NULL); - warnx("failed to execute ftp"); - _exit(2); - } - - /* parent */ - close(pipefds[1]); - - if ((fp=fdopen(pipefds[0], "r")) == NULL) - warn("can't fdopen pipe end"); - else { - char s_pattern[MaxPathSize]; - int len, offset; - - /* strip of .t[bg]z for comparison */ - strip_txz(s_pattern, NULL, pattern); - - /* initialize http_extract_fn internal state */ - http_extract_fn(NULL, NULL, 0); - - /* read line from HTTP output and extract filenames */ - while (fgets(line, sizeof(line), fp) != NULL) { - len = offset = 0; - while ((len=http_extract_fn(line+offset, filename, - sizeof(filename))) > 0) { - char s_filename[MaxPathSize]; - - offset += len; - strip_txz(s_filename, NULL, filename); - - if (pkg_order(s_pattern, s_filename, - *s_best != '\0' ? s_best : NULL) == 1) { - strlcpy(best, filename, sizeof(best)); - strlcpy(s_best, s_filename, sizeof(best)); - } - } - } - - } - - fclose(fp); - - /* wait for child to exit */ - if (waitpid(pid, &state, 0) < 0) { - /* error has been reported by child */ - return NULL; - } - - if (best[0] == '\0') { - if (Verbose) - warnx("nothing appropriate found"); - return NULL; - } - - return strdup(best); - -} - -enum http_states { - ST_NONE, - ST_LT, ST_LTA, ST_TAGA, ST_H, ST_R, ST_E, ST_F, ST_HREF, - ST_TAG, ST_TAGAX -}; - -/* return any hrefs found */ -static int -http_extract_fn(char *input, char *outbuf, size_t outbuflen) -{ - /* partial copied hrefs from previous calls are saved here */ - static char tempbuf[MaxPathSize]; - /* fill state of tempbuf */ - static int tempbuffill = 0; - /* parsing state information */ - static enum http_states state; - /* currently in double quotes (in parsing) */ - static int dqflag; - char p; - int offset, found; - - if (outbuf == NULL) { - /* init */ - dqflag = tempbuffill = 0; - state = ST_NONE; - return 0; - } - - offset = 0; - found = 0; - while ((p=input[offset++]) != '\0') { - /* handle anything that's inside double quotes */ - if (dqflag) { - /* incomplete href */ - if (state == ST_HREF) { - /* check if space left in output - * buffer */ - if (tempbuffill >= sizeof(tempbuf)) { - warnx("href starting with `%.*s'" - " too long", 60, tempbuf); - /* ignore remainder */ - tempbuffill = 0; - /* need space before "href" - * can start again (invalidly, - * of course, but we don't - * care) */ - state = ST_TAGAX; - } - - /* href complete */ - if (p == '\"') { - /* complete */ - dqflag = 0; - tempbuf[tempbuffill++] = '\0'; - /* need space before "href" - * can start again (invalidly, - * of course, but we don't - * care) */ - state = ST_TAGAX; - found = 1; - break; - } else { - /* copy one more char */ - tempbuf[tempbuffill++] = p; - } - } else { - /* leaving double quotes */ - if (p == '\"') - dqflag = 0; - } - continue; - } - - /* - * entering double quotes? (only relevant inside a tag) - */ - if (state != ST_NONE && p == '\"') { - dqflag = 1; - continue; - } - - /* other cases */ - switch (state) { - case ST_NONE: - /* plain text, not in markup */ - if (p == '<') - state = ST_LT; - break; - case ST_LT: - /* in tag -- "<" already found */ - if (p == '>') - state = ST_NONE; - else if (p == 'a' || p == 'A') - state = ST_LTA; - else if (!isspace((unsigned char)p)) - state = ST_TAG; - break; - case ST_LTA: - /* in tag -- "<a" already found */ - if (p == '>') - state = ST_NONE; - else if (isspace((unsigned char)p)) - state = ST_TAGA; - else - state = ST_TAG; - break; - case ST_TAG: - /* in tag, but not "<a" -- disregard */ - if (p == '>') - state = ST_NONE; - break; - case ST_TAGA: - /* in a-tag -- "<a " already found */ - if (p == '>') - state = ST_NONE; - else if (p == 'h' || p == 'H') - state = ST_H; - else if (!isspace((unsigned char)p)) - state = ST_TAGAX; - break; - case ST_TAGAX: - /* in unknown keyword in a-tag */ - if (p == '>') - state = ST_NONE; - else if (isspace((unsigned char)p)) - state = ST_TAGA; - break; - case ST_H: - /* in a-tag -- "<a h" already found */ - if (p == '>') - state = ST_NONE; - else if (p == 'r' || p == 'R') - state = ST_R; - else if (isspace((unsigned char)p)) - state = ST_TAGA; - else - state = ST_TAGAX; - break; - case ST_R: - /* in a-tag -- "<a hr" already found */ - if (p == '>') - state = ST_NONE; - else if (p == 'e' || p == 'E') - state = ST_E; - else if (isspace((unsigned char)p)) - state = ST_TAGA; - else - state = ST_TAGAX; - break; - case ST_E: - /* in a-tag -- "<a hre" already found */ - if (p == '>') - state = ST_NONE; - else if (p == 'f' || p == 'F') - state = ST_F; - else if (isspace((unsigned char)p)) - state = ST_TAGA; - else - state = ST_TAGAX; - break; - case ST_F: - /* in a-tag -- "<a href" already found */ - if (p == '>') - state = ST_NONE; - else if (p == '=') - state = ST_HREF; - else if (!isspace((unsigned char)p)) - state = ST_TAGAX; - break; - case ST_HREF: - /* in a-tag -- "<a href=" already found */ - /* XXX: handle missing double quotes? */ - if (p == '>') - state = ST_NONE; - /* skip spaces before URL */ - else if (!isspace((unsigned char)p)) - state = ST_TAGA; - break; - /* no default case by purpose */ - } - } - - if (p == '\0') - return -1; - - if (found) { - char *q; - - URL_decode(tempbuf); - - /* strip path (XXX) */ - if ((q=strrchr(tempbuf, '/')) == NULL) - q = tempbuf; - - (void)strlcpy(outbuf, q, outbuflen); - tempbuffill = 0; - } - - return offset; -} - - -static int -hexvalue(char p) -{ - if (p >= '0' && p <= '9') - return (p-'0'); - else if (p >= 'a' && p <= 'f') - return (p-'a'+10); - else if (p >= 'A' && p <= 'F') - return (p-'A'+10); - else - return -1; -} - -/* fetch and extract URL url into directory path */ -static int -http_fetch(const char *url, const char *path) -{ - int pipefds[2]; - int stateftp, state; - pid_t pidftp, pid; - - /* Set up a pipe for passing the fetched contents. */ - if (pipe(pipefds) == -1) { - warn("cannot create pipe"); - return -1; - } - /* fork ftp child */ - if ((pidftp = fork()) == -1) { - warn("cannot fork process for ftp"); - return -1; - } - if (pidftp == 0) { - /* child */ - if (dup2(pipefds[1], STDOUT_FILENO) == -1) { - warn("dup2 failed before executing ftp"); - _exit(2); - } - close(pipefds[0]); - close(pipefds[1]); - execlp(FTP_CMD, FTP_CMD, "-o", "-", url, NULL); - warnx("failed to execute ftp"); - _exit(2); - } - - /* fork unpack child */ - if ((pid = fork()) == -1) { - warn("cannot fork unpack process"); - return -1; - } - if (pid == 0) { - /* child */ - if (dup2(pipefds[0], STDIN_FILENO) == -1) { - warn("dup2 failed before unpack"); - _exit(2); - } - close(pipefds[0]); - close(pipefds[1]); - if ((path != NULL) && (chdir(path) < 0)) - _exit(127); - - if (unpack("-", NULL) != 0) { - warnx("unpack failed"); - _exit(2); - } - - _exit(0); - } - - close(pipefds[0]); - close(pipefds[1]); - - /* wait for unpack to exit */ - while (waitpid(pid, &state, 0) < 0) { - if (errno != EINTR) { - (void)waitpid(pidftp, &stateftp, 0); - return -1; - } - } - while (waitpid(pidftp, &stateftp, 0) < 0) { - if (errno != EINTR) { - return -1; - } - } - - if (!WIFEXITED(state) || !WIFEXITED(stateftp)) - return -1; - - if (WEXITSTATUS(state) != 0 || WEXITSTATUS(stateftp) != 0) - return -1; - - return 0; -} - -static void -URL_decode(char *URL) -{ - char *in, *out; - - in = out = URL; - - while (*in != '\0') { - if (in[0] == '%' && in[1] != '\0' && in[2] != '\0') { - /* URL-decode character */ - if (hexvalue(in[1]) != -1 && hexvalue(in[2]) != -1) { - *out++ = hexvalue(in[1])*16+hexvalue(in[2]); - } - /* skip invalid encoded signs too */ - in += 3; - } - else - *out++ = *in++; - } - - *out = '\0'; - - return; -} -/* - * extract the given (expanded) URL "url" to the given directory "dir" - * return -1 on error, 0 else; - */ -int -unpackURL(const char *url, const char *dir) -{ - char *pkg; - int rc; - char base[MaxPathSize]; - char pkg_path[MaxPathSize]; - - { - /* Verify if the URL is really ok */ - char expnd[MaxPathSize]; - - rc=expandURL(expnd, url); - if (rc == -1) { - warnx("unpackURL: verification expandURL failed"); - return -1; - } - if (strcmp(expnd, url) != 0) { - warnx("unpackURL: verification expandURL failed, '%s'!='%s'", - expnd, url); - return -1; - } - } - - pkg=strrchr(url, '/'); - if (pkg == NULL){ - warnx("unpackURL: no '/' in URL %s?!", url); - return -1; - } - (void) snprintf(base, sizeof(base), "%.*s/", (int)(pkg-url), url); - (void) snprintf(pkg_path, sizeof(pkg_path), "%.*s", - (int)(pkg-url), url); /* no trailing '/' */ - pkg++; - - /* Leave a hint for any depending pkgs that may need it */ - if (getenv("PKG_PATH") == NULL) { - setenv("PKG_PATH", pkg_path, 1); -#if 0 - path_create(pkg_path); /* XXX */ -#endif - if (Verbose) - printf("setenv PKG_PATH='%s'\n", pkg_path); - } - - if (strncmp(url, "http://", 7) == 0) - return http_fetch(url, dir); - - rc = ftp_start(base); - if (rc == -1) { - warnx("ftp_start() failed"); - return -1; /* error */ - } - - { - char cmd[1024]; - const char *decompress_cmd = NULL; - const char *suf; - - if (Verbose) - printf("unpackURL '%s' to '%s'\n", url, dir); - - suf = suffix_of(pkg); - if (!strcmp(suf, "tbz") || !strcmp(suf, "bz2")) - decompress_cmd = BZIP2_CMD; - else if (!strcmp(suf, "tgz") || !strcmp(suf, "gz")) - decompress_cmd = GZIP_CMD; - else if (!strcmp(suf, "tar")) - ; /* do nothing */ - else - errx(EXIT_FAILURE, "don't know how to decompress %s, sorry", pkg); - - /* yes, this is gross, but needed for borken ftp(1) */ - (void) snprintf(cmd, sizeof(cmd), "get %s \"| ( cd %s; " TAR_CMD " %s %s -vvxp -f - | tee %s )\"\n", - pkg, dir, - decompress_cmd != NULL ? "--use-compress-program" : "", - decompress_cmd != NULL ? decompress_cmd : "", - Verbose ? "/dev/stderr" : "/dev/null"); - - rc = ftp_cmd(cmd, "\n(226|550).*\n"); - if (rc != 226) { - warnx("Cannot fetch file (%d!=226)!", rc); - return -1; - } - } - - return 0; -} - - -#ifdef STANDALONE -static void -usage(void) -{ - errx(EXIT_FAILURE, "Usage: foo [-v] ftp://-pattern"); -} - - -int -main(int argc, char *argv[]) -{ - int rc, ch; - char *argv0 = argv[0]; - - while ((ch = getopt(argc, argv, "v")) != -1) { - switch (ch) { - case 'v': - Verbose=1; - break; - default: - usage(); - } - } - argc -= optind; - argv += optind; - - if (argc<1) - usage(); - - while(argv[0] != NULL) { - char newurl[MaxPathSize]; - - printf("Expand %s:\n", argv[0]); - rc = expandURL(newurl, argv[0]); - if (rc==-1) - warnx("Cannot expand %s", argv[0]); - else - printf("Expanded URL: %s\n", newurl); - - /* test out connection caching */ - if (1) { - char *s, buf[MaxPathSize]; - - if ((s=getenv(PKG_FTPIO_CNT)) && atoi(s)>0){ - (void) snprintf(buf, sizeof(buf),"%d", atoi(s)-1); - setenv(PKG_FTPIO_CNT, buf, 1); - - printf("%s>>> %s -v %s\n", s, argv0, argv[0]); - fexec(argv0, "-v", argv[0], NULL); - } - } - - printf("\n\n\n"); - argv++; - } - - ftp_stop(); - - return 0; -} - -void -cleanup(int i) -{ -} -#endif /* STANDALONE */ diff --git a/pkgtools/pkg_install/files/lib/global.c b/pkgtools/pkg_install/files/lib/global.c index e76cc3c160b..608b9278ac7 100644 --- a/pkgtools/pkg_install/files/lib/global.c +++ b/pkgtools/pkg_install/files/lib/global.c @@ -1,4 +1,4 @@ -/* $NetBSD: global.c,v 1.4 2003/09/23 07:13:53 grant Exp $ */ +/* $NetBSD: global.c,v 1.5 2009/02/02 12:35:01 joerg Exp $ */ #if HAVE_CONFIG_H #include "config.h" @@ -7,13 +7,7 @@ #if HAVE_SYS_CDEFS_H #include <sys/cdefs.h> #endif -#ifndef lint -#if 0 -static const char *rcsid = "from FreeBSD Id: global.c,v 1.6 1997/10/08 07:47:58 charnier Exp"; -#else -__RCSID("$NetBSD: global.c,v 1.4 2003/09/23 07:13:53 grant Exp $"); -#endif -#endif +__RCSID("$NetBSD: global.c,v 1.5 2009/02/02 12:35:01 joerg Exp $"); /* * FreeBSD install - a package for the installation and maintainance diff --git a/pkgtools/pkg_install/files/lib/gpgsig.c b/pkgtools/pkg_install/files/lib/gpgsig.c new file mode 100644 index 00000000000..e01c50d91ae --- /dev/null +++ b/pkgtools/pkg_install/files/lib/gpgsig.c @@ -0,0 +1,252 @@ +/* $NetBSD: gpgsig.c,v 1.2 2009/02/02 12:35:01 joerg Exp $ */ +#if HAVE_CONFIG_H +#include "config.h" +#endif +#include <nbcompat.h> +#if HAVE_SYS_CDEFS_H +#include <sys/cdefs.h> +#endif + +__RCSID("$NetBSD: gpgsig.c,v 1.2 2009/02/02 12:35:01 joerg Exp $"); + +/*- + * 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. + */ + +#include <sys/wait.h> +#ifndef NETBSD +#include <nbcompat/err.h> +#else +#include <err.h> +#endif +#ifndef NETBSD +#include <nbcompat/stdlib.h> +#else +#include <stdlib.h> +#endif + +#include "lib.h" + +#ifndef __UNCONST +#define __UNCONST(a) ((void *)(unsigned long)(const void *)(a)) +#endif + +static void +verify_signature(const char *input, size_t input_len, const char *keyring, + const char *detached_signature) +{ + const char *argv[8], **argvp; + pid_t child; + int fd[2], status; + + 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]); + argvp = argv; + *argvp++ = gpg_cmd; + *argvp++ = "--verify"; + if (keyring != NULL) { + *argvp++ = "--no-default-keyring"; + *argvp++ = "--keyring"; + *argvp++ = keyring; + } + + if (detached_signature != NULL) + *argvp++ = detached_signature; + *argvp++ = "-"; + + *argvp = NULL; + + execvp(gpg_cmd, __UNCONST(argv)); + _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"); +} + +int +inline_gpg_verify(const char *content, size_t len, const char *keyring) +{ + verify_signature(content, len, keyring, NULL); + + return 0; +} + +int +detached_gpg_verify(const char *content, size_t len, + const char *signature, size_t signature_len, const char *keyring) +{ + int fd; + const char *tmpdir; + char *tempsig; + ssize_t ret; + + if (gpg_cmd == NULL) { + warnx("GPG variable not set, failing signature check"); + return -1; + } + + if ((tmpdir = getenv("TMPDIR")) == NULL) + tmpdir = "/tmp"; + tempsig = xasprintf("%s/pkg_install.XXXXXX", tmpdir); + + fd = mkstemp(tempsig); + if (fd == -1) { + warnx("Creating temporary file for GPG signature failed"); + return -1; + } + + while (signature_len) { + ret = write(fd, signature, signature_len); + if (ret == -1) + err(EXIT_FAILURE, "Write to GPG failed"); + if (ret == 0) + errx(EXIT_FAILURE, "Short write to GPG"); + signature_len -= ret; + signature += ret; + } + + verify_signature(content, len, keyring, tempsig); + + unlink(tempsig); + close(fd); + free(tempsig); + + return 0; +} + +int +detached_gpg_sign(const char *content, size_t len, char **sig, size_t *sig_len, + const char *keyring, const char *user) +{ + const char *argv[12], **argvp; + pid_t child; + int fd_in[2], fd_out[2], status; + size_t allocated; + ssize_t ret; + + if (gpg_cmd == NULL) + errx(EXIT_FAILURE, "GPG variable not set"); + + if (pipe(fd_in) == -1) + err(EXIT_FAILURE, "cannot create input pipes"); + if (pipe(fd_out) == -1) + err(EXIT_FAILURE, "cannot create output pipes"); + + child = fork(); + if (child == -1) + err(EXIT_FAILURE, "cannot fork GPG process"); + if (child == 0) { + close(fd_in[1]); + close(STDIN_FILENO); + if (dup2(fd_in[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_in[0]); + + close(fd_out[0]); + close(STDOUT_FILENO); + if (dup2(fd_out[1], STDOUT_FILENO) == -1) { + static const char err_msg[] = + "cannot redirect stdout of GPG process\n"; + write(STDERR_FILENO, err_msg, sizeof(err_msg) - 1); + _exit(255); + } + close(fd_out[1]); + + argvp = argv; + *argvp++ = gpg_cmd; + *argvp++ = "--detach-sign"; + *argvp++ = "--armor"; + *argvp++ = "--output"; + *argvp++ = "-"; + if (user != NULL) { + *argvp++ = "--local-user"; + *argvp++ = user; + } + if (keyring != NULL) { + *argvp++ = "--no-default-keyring"; + *argvp++ = "--secret-keyring"; + *argvp++ = keyring; + } + + *argvp++ = "-"; + *argvp = NULL; + + execvp(gpg_cmd, __UNCONST(argv)); + _exit(255); + } + close(fd_in[0]); + if (write(fd_in[1], content, len) != len) + errx(EXIT_FAILURE, "Short read from GPG"); + close(fd_in[1]); + + allocated = 1024; + *sig = xmalloc(allocated); + *sig_len = 0; + + close(fd_out[1]); + + while ((ret = read(fd_out[0], *sig + *sig_len, + allocated - *sig_len)) > 0) { + *sig_len += ret; + if (*sig_len == allocated) { + allocated *= 2; + *sig = xrealloc(*sig, allocated); + } + } + + close(fd_out[0]); + + waitpid(child, &status, 0); + if (status) + errx(EXIT_FAILURE, "GPG could not create signature"); + + return 0; +} diff --git a/pkgtools/pkg_install/files/lib/iterate.c b/pkgtools/pkg_install/files/lib/iterate.c index 36ddc996789..1ab3b74428d 100644 --- a/pkgtools/pkg_install/files/lib/iterate.c +++ b/pkgtools/pkg_install/files/lib/iterate.c @@ -1,3 +1,5 @@ +/* $NetBSD: iterate.c,v 1.6 2009/02/02 12:35:01 joerg Exp $ */ + /*- * Copyright (c) 2007 Joerg Sonnenberger <joerg@NetBSD.org>. * All rights reserved. @@ -280,8 +282,7 @@ match_best_installed(const char *pkg, void *cookie) case 1: /* Current package is better, remember it. */ free(arg->best_current_match); - if ((arg->best_current_match = strdup(pkg)) == NULL) - return -1; + arg->best_current_match = xstrdup(pkg); break; } return 0; @@ -367,8 +368,7 @@ match_best_file(const char *filename, void *cookie) warnx("filename %s does not contain a recognized suffix", filename); return -1; } - if ((filtered_filename = malloc(len - 4 + 1)) == NULL) - err(EXIT_FAILURE, "malloc failed"); + filtered_filename = xmalloc(len - 4 + 1); memcpy(filtered_filename, filename, len - 4); filtered_filename[len - 4] = '\0'; active_filename = filtered_filename; @@ -390,12 +390,11 @@ match_best_file(const char *filename, void *cookie) /* Current package is better, remember it. */ free(arg->best_current_match); free(arg->best_current_match_filtered); - if ((arg->best_current_match = strdup(filename)) == NULL) - err(EXIT_FAILURE, "strdup failed"); + arg->best_current_match = xstrdup(filename); if (filtered_filename != NULL) arg->best_current_match_filtered = filtered_filename; - else if ((arg->best_current_match_filtered = strdup(active_filename)) == NULL) - err(EXIT_FAILURE, "strdup failed"); + else + arg->best_current_match_filtered = xstrdup(active_filename); return 0; default: errx(EXIT_FAILURE, "Invalid error from pkg_order"); @@ -450,8 +449,7 @@ match_file_and_call(const char *filename, void *cookie) warnx("filename %s does not contain a recognized suffix", filename); return -1; } - if ((filtered_filename = malloc(len - 4 + 1)) == NULL) - err(EXIT_FAILURE, "malloc failed"); + filtered_filename = xmalloc(len - 4 + 1); memcpy(filtered_filename, filename, len - 4); filtered_filename[len - 4] = '\0'; active_filename = filtered_filename; diff --git a/pkgtools/pkg_install/files/lib/lib.h b/pkgtools/pkg_install/files/lib/lib.h index b803b6746e1..2098752e7d0 100644 --- a/pkgtools/pkg_install/files/lib/lib.h +++ b/pkgtools/pkg_install/files/lib/lib.h @@ -1,4 +1,4 @@ -/* $NetBSD: lib.h,v 1.45 2008/09/17 15:21:30 joerg Exp $ */ +/* $NetBSD: lib.h,v 1.46 2009/02/02 12:35:01 joerg Exp $ */ /* from FreeBSD Id: lib.h,v 1.25 1997/10/08 07:48:03 charnier Exp */ @@ -86,55 +86,16 @@ #define DEF_UMASK 022 #endif -/* Usually "rm", but often "echo" during debugging! */ -#define REMOVE_CMD "rm" - -/* Usually "rm", but often "echo" during debugging! */ -#define RMDIR_CMD "rmdir" - -/* Define tar as a string, in case it's called gtar or something */ -#ifndef TAR_CMD -#define TAR_CMD "tar" -#endif - -/* Define pax as a string, used to copy files from staging area */ -#ifndef PAX_CMD -#define PAX_CMD "pax" -#endif - -/* Define gzip and bzip2, used to unpack binary packages */ -#ifndef GZIP_CMD -#define GZIP_CMD "gzip" -#endif - -#ifndef BZIP2_CMD -#define BZIP2_CMD "bzip2" -#endif - -/* Define ftp as a string, in case the ftp client is called something else */ -#ifndef FTP_CMD -#define FTP_CMD "ftp" -#endif - -#ifndef CHOWN_CMD -#define CHOWN_CMD "chown" -#endif - -#ifndef CHMOD_CMD -#define CHMOD_CMD "chmod" -#endif - -#ifndef CHGRP_CMD -#define CHGRP_CMD "chgrp" -#endif - -/* some operating systems don't have this */ -#ifndef MAXPATHLEN -#define MAXPATHLEN 1024 +#ifndef PATH_MAX +# ifdef MAXPATHLEN +# define PATH_MAX MAXPATHLEN +# else +# define PATH_MAX 1024 +# endif #endif enum { - MaxPathSize = MAXPATHLEN + MaxPathSize = PATH_MAX }; /* The names of our "special" files */ @@ -144,6 +105,7 @@ enum { #define INSTALL_FNAME "+INSTALL" #define DEINSTALL_FNAME "+DEINSTALL" #define REQUIRED_BY_FNAME "+REQUIRED_BY" +#define REQUIRED_BY_FNAME_TMP "+REQUIRED_BY.tmp" #define DISPLAY_FNAME "+DISPLAY" #define MTREE_FNAME "+MTREE_DIRS" #define BUILD_VERSION_FNAME "+BUILD_VERSION" @@ -153,22 +115,21 @@ enum { #define SIZE_ALL_FNAME "+SIZE_ALL" #define PRESERVE_FNAME "+PRESERVE" #define VIEWS_FNAME "+VIEWS" +#define VIEWS_FNAME_TMP "+VIEWS.tmp" #define DEPOT_FNAME "+DEPOT" /* The names of special variables */ #define AUTOMATIC_VARNAME "automatic" -/* - * files which we expect to be in every package, passed to - * tar --fast-read. - */ -#define ALL_FNAMES CONTENTS_FNAME" "COMMENT_FNAME" "DESC_FNAME" "MTREE_FNAME" "BUILD_VERSION_FNAME" "BUILD_INFO_FNAME" "SIZE_PKG_FNAME" "SIZE_ALL_FNAME - -#define CMD_CHAR '@' /* prefix for extended PLIST cmd */ +/* Prefix for extended PLIST cmd */ +#define CMD_CHAR '@' /* The name of the "prefix" environment variable given to scripts */ #define PKG_PREFIX_VNAME "PKG_PREFIX" +/* The name of the "destdir" environment variable given to scripts */ +#define PKG_DESTDIR_VNAME "PKG_DESTDIR" + /* * The name of the "metadatadir" environment variable given to scripts. * This variable holds the location of the +-files for this package. @@ -260,7 +221,7 @@ typedef struct _lfile_t { TAILQ_HEAD(_lfile_head_t, _lfile_t); typedef struct _lfile_head_t lfile_head_t; #define LFILE_ADD(lfhead,lfp,str) do { \ - lfp = malloc(sizeof(lfile_t)); \ + lfp = xmalloc(sizeof(lfile_t)); \ lfp->lf_name = str; \ TAILQ_INSERT_TAIL(lfhead,lfp,lf_link); \ } while(0) @@ -273,14 +234,6 @@ typedef struct _lpkg_t { TAILQ_HEAD(_lpkg_head_t, _lpkg_t); typedef struct _lpkg_head_t lpkg_head_t; -/* This structure describes a pipe to a child process */ -typedef struct { - int fds[2]; /* pipe, 0=child stdin, 1=parent output */ - FILE *fp; /* output from parent process */ - pid_t pid; /* process id of child process */ - void (*cleanup)(void); /* called on non-zero child exit status */ -} pipe_to_system_t; - struct pkg_vulnerabilities { size_t entries; char **vulnerability; @@ -296,25 +249,17 @@ struct pkg_vulnerabilities { #define IS_FULLPATH(str) ((str) != NULL && (str)[0] == '/') /* Conflict handling (conflicts.c) */ -int some_installed_package_conflicts_with(const char *, char **, char **); +int some_installed_package_conflicts_with(const char *, const char *, char **, char **); /* Prototypes */ /* Misc */ void cleanup(int); -char *make_playpen(char *, size_t, size_t); -char *where_playpen(void); -void leave_playpen(char *); -uint64_t min_free(const char *); -void save_dirs(char **, char **); -void restore_dirs(char *, char *); void show_version(void); int fexec(const char *, ...); int fexec_skipempty(const char *, ...); int fcexec(const char *, const char *, ...); int pfcexec(const char *, const char *, const char **); -pipe_to_system_t *pipe_to_system_begin(const char *, char *const *, void (*)(void)); -int pipe_to_system_end(pipe_to_system_t *); /* variables file handling */ @@ -335,7 +280,7 @@ const char *suffix_of(const char *); int pkg_match(const char *, const char *); int pkg_order(const char *, const char *, const char *); int ispkgpattern(const char *); -void strip_txz(char *, char *, const char *); +int quick_pkg_match(const char *, const char *); /* Iterator functions */ int iterate_pkg_generic_src(int (*)(const char *, void *), void *, @@ -361,35 +306,20 @@ Boolean isfile(const char *); Boolean isbrokenlink(const char *); Boolean isempty(const char *); int URLlength(const char *); -char *fileGetURL(const char *); -const char *fileURLFilename(const char *, char *, int); -const char *fileURLHost(const char *, char *, int); -char *fileFindByPath(const char *); -char *fileGetContents(char *); Boolean make_preserve_name(char *, size_t, char *, char *); -void write_file(char *, char *); -void copy_file(char *, char *, char *); -void move_file(char *, char *, char *); -void move_files(const char *, const char *, const char *); void remove_files(const char *, const char *); int delete_hierarchy(char *, Boolean, Boolean); -int unpack(const char *, const lfile_head_t *); -void format_cmd(char *, size_t, char *, char *, char *); +int format_cmd(char *, size_t, const char *, const char *, const char *); -/* ftpio.c: FTP handling */ -int expandURL(char *, const char *); -int unpackURL(const char *, const char *); -int ftp_cmd(const char *, const char *); -int ftp_start(const char *); -void ftp_stop(void); +int recursive_remove(const char *, int); /* pkg_io.c: Local and remote archive handling */ struct archive; +struct archive_entry; -struct archive *open_remote_archive(const char *, void **); -void close_remote_archive(void *); -struct archive *open_local_archive(const char *, void **); -void close_local_archive(void *); +struct archive *open_archive(const char *, void **); +void close_archive(void *); +struct archive *find_archive(const char *, void **); /* Packing list */ plist_t *new_plist_entry(void); @@ -404,11 +334,11 @@ void add_plist(package_t *, pl_ent_t, const char *); void add_plist_top(package_t *, pl_ent_t, const char *); void delete_plist(package_t *, Boolean, pl_ent_t, char *); void write_plist(package_t *, FILE *, char *); -void stringify_plist(package_t *, char **, size_t *, char *); +void stringify_plist(package_t *, char **, size_t *, const char *); void parse_plist(package_t *, const char *); void read_plist(package_t *, FILE *); void append_plist(package_t *, FILE *); -int delete_package(Boolean, Boolean, package_t *, Boolean); +int delete_package(Boolean, Boolean, package_t *, Boolean, const char *); /* Package Database */ int pkgdb_open(int); @@ -438,11 +368,66 @@ 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 *); +int audit_package(struct pkg_vulnerabilities *, const char *, const char *, + int, int); + +/* Parse configuration file */ +void pkg_install_config(void); +/* Print configuration variable */ +void pkg_install_show_variable(const char *); + +#ifdef HAVE_SSL +/* Package signature creation and validation */ +int pkg_verify_signature(struct archive **, struct archive_entry **, char **, + void **); +int pkg_full_signature_check(struct archive *); +void pkg_free_signature(void *); +void pkg_sign_x509(const char *, const char *, const char *, const char *); +#endif + +void pkg_sign_gpg(const char *, const char *); + +#ifdef HAVE_SSL +/* PKCS7 signing/verification */ +int easy_pkcs7_verify(const char *, size_t, const char *, size_t, + const char *, int); +int easy_pkcs7_sign(const char *, size_t, char **, size_t *, const char *, + const char *); +#endif + +int inline_gpg_verify(const char *, size_t, const char *); +int detached_gpg_verify(const char *, size_t, const char *, size_t, + const char *); +int detached_gpg_sign(const char *, size_t, char **, size_t *, const char *, + const char *); + +char *xstrdup(const char *); +void *xrealloc(void *, size_t); +void *xcalloc(size_t, size_t); +void *xmalloc(size_t); +char *xasprintf(const char *, ...); /* Externs */ extern Boolean Verbose; extern Boolean Fake; extern Boolean Force; +extern const char *cert_chain_file; +extern const char *certs_packages; +extern const char *certs_pkg_vulnerabilities; +extern const char *check_vulnerabilities; +extern const char *config_file; +extern const char *verified_installation; extern const char *gpg_cmd; +extern const char *gpg_keyring_pkgvuln; +extern const char *gpg_keyring_sign; +extern const char *gpg_keyring_verify; +extern const char *gpg_sign_as; +extern char fetch_flags[]; + +extern const char *pkg_vulnerabilities_dir; +extern const char *pkg_vulnerabilities_file; +extern const char *pkg_vulnerabilities_url; +extern const char *ignore_advisories; +extern const char tnf_vulnerability_base[]; #endif /* _INST_LIB_LIB_H_ */ diff --git a/pkgtools/pkg_install/files/lib/lpkg.c b/pkgtools/pkg_install/files/lib/lpkg.c index 58325d03568..6607467a518 100644 --- a/pkgtools/pkg_install/files/lib/lpkg.c +++ b/pkgtools/pkg_install/files/lib/lpkg.c @@ -1,4 +1,4 @@ -/* $NetBSD: lpkg.c,v 1.5 2003/09/23 07:13:53 grant Exp $ */ +/* $NetBSD: lpkg.c,v 1.6 2009/02/02 12:35:01 joerg Exp $ */ /* * Copyright (c) 1999 Christian E. Hopps @@ -46,10 +46,8 @@ alloc_lpkg(const char *pkgname) { lpkg_t *lpp; - if ((lpp = malloc(sizeof(*lpp))) == 0) - err(EXIT_FAILURE, "cannot allocate recursion data"); - if ((lpp->lp_name = strdup(pkgname)) == 0) - err(EXIT_FAILURE, "cannot allocate recursion data"); + lpp = xmalloc(sizeof(*lpp)); + lpp->lp_name = xstrdup(pkgname); return (lpp); } diff --git a/pkgtools/pkg_install/files/lib/opattern.c b/pkgtools/pkg_install/files/lib/opattern.c index cd0bb186119..3861f3250ae 100644 --- a/pkgtools/pkg_install/files/lib/opattern.c +++ b/pkgtools/pkg_install/files/lib/opattern.c @@ -1,4 +1,4 @@ -/* $NetBSD: opattern.c,v 1.4 2007/10/14 23:24:24 rillig Exp $ */ +/* $NetBSD: opattern.c,v 1.5 2009/02/02 12:35:01 joerg Exp $ */ #if HAVE_CONFIG_H #include "config.h" @@ -7,13 +7,7 @@ #if HAVE_SYS_CDEFS_H #include <sys/cdefs.h> #endif -#ifndef lint -#if 0 -static const char *rcsid = "Id: str.c,v 1.5 1997/10/08 07:48:21 charnier Exp"; -#else -__RCSID("$NetBSD: opattern.c,v 1.4 2007/10/14 23:24:24 rillig Exp $"); -#endif -#endif +__RCSID("$NetBSD: opattern.c,v 1.5 2009/02/02 12:35:01 joerg Exp $"); /* * FreeBSD install - a package for the installation and maintainance @@ -119,11 +113,35 @@ simple_match(const char *pattern, const char *pkg) } /* + * Performs a fast check if pattern can ever match pkg. + * Returns 1 if a match is possible and 0 otherwise. + */ +int +quick_pkg_match(const char *pattern, const char *pkg) +{ +#define simple(x) (isalnum((unsigned char)(x)) || (x) == '-') + if (!simple(pattern[0])) + return 1; + if (pattern[0] != pkg[0]) + return 0; + + if (!simple(pattern[1])) + return 1; + if (pattern[1] != pkg[1]) + return 0; + return 1; +#undef simple +} + +/* * Match pkg against pattern, return 1 if matching, 0 else */ int pkg_match(const char *pattern, const char *pkg) { + if (!quick_pkg_match(pattern, pkg)) + return 0; + if (strchr(pattern, '{') != (char *) NULL) { /* emulate csh-type alternates */ return alternate_match(pattern, pkg); @@ -154,8 +172,7 @@ pkg_match(const char *pattern, const char *pkg) char *pattern_ver; int retval; - if (asprintf(&pattern_ver, "%s-[0-9]*", pattern) == -1) - errx(EXIT_FAILURE, "Out of memory"); + pattern_ver = xasprintf("%s-[0-9]*", pattern); retval = glob_match(pattern_ver, pkg); free(pattern_ver); return retval; diff --git a/pkgtools/pkg_install/files/lib/parse-config.c b/pkgtools/pkg_install/files/lib/parse-config.c new file mode 100644 index 00000000000..66e9ac6f41f --- /dev/null +++ b/pkgtools/pkg_install/files/lib/parse-config.c @@ -0,0 +1,139 @@ +/* $NetBSD: parse-config.c,v 1.2 2009/02/02 12:35:01 joerg Exp $ */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif +#include <nbcompat.h> +#if HAVE_SYS_CDEFS_H +#include <sys/cdefs.h> +#endif +__RCSID("$NetBSD: parse-config.c,v 1.2 2009/02/02 12:35:01 joerg Exp $"); + +/*- + * 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_ERR_H +#include <err.h> +#endif +#if HAVE_STRING_H +#include <string.h> +#endif + +#include "lib.h" + +const char *config_file = SYSCONFDIR"/pkg_install.conf"; + +char fetch_flags[10]; +static const char *active_ftp; +static const char *verbose_netio; +static const char *ignore_proxy; +const char *cert_chain_file; +const char *certs_packages; +const char *certs_pkg_vulnerabilities; +const char *check_vulnerabilities; +const char *verified_installation; +const char *gpg_cmd; +const char *gpg_keyring_pkgvuln; +const char *gpg_keyring_sign; +const char *gpg_keyring_verify; +const char *gpg_sign_as; +const char *pkg_vulnerabilities_dir; +const char *pkg_vulnerabilities_file; +const char *pkg_vulnerabilities_url; +const char *ignore_advisories = NULL; + +const char tnf_vulnerability_base[] = "ftp://ftp.NetBSD.org/pub/NetBSD/packages/vulns"; + +static struct config_variable { + const char *name; + const char **var; +} config_variables[] = { + { "ACTIVE_FTP", &active_ftp }, + { "CERTIFICATE_ANCHOR_PKGS", &certs_packages }, + { "CERTIFICATE_ANCHOR_PKGVULN", &certs_pkg_vulnerabilities }, + { "CERTIFICATE_CHAIN", &cert_chain_file }, + { "CHECK_VULNERABILITIES", &check_vulnerabilities }, + { "GPG", &gpg_cmd }, + { "GPG_KEYRING_PKGVULN", &gpg_keyring_pkgvuln }, + { "GPG_KEYRING_SIGN", &gpg_keyring_sign }, + { "GPG_KEYRING_VERIFY", &gpg_keyring_verify }, + { "GPG_SIGN_AS", &gpg_sign_as }, + { "IGNORE_PROXY", &ignore_proxy }, + { "IGNORE_URL", &ignore_advisories }, + { "PKGVULNDIR", &pkg_vulnerabilities_dir }, + { "PKGVULNURL", &pkg_vulnerabilities_url }, + { "VERBOSE_NETIO", &verbose_netio }, + { "VERIFIED_INSTALLATION", &verified_installation }, + { NULL, NULL } +}; + +void +pkg_install_config(void) +{ + char *value; + struct config_variable *var; + + for (var = config_variables; var->name != NULL; ++var) { + value = var_get(config_file, var->name); + if (value != NULL) + *var->var = value; + } + + if (pkg_vulnerabilities_dir == NULL) + pkg_vulnerabilities_dir = _pkgdb_getPKGDB_DIR(); + pkg_vulnerabilities_file = xasprintf("%s/pkg-vulnerabilities", + pkg_vulnerabilities_dir); + if (pkg_vulnerabilities_url == NULL) { + pkg_vulnerabilities_url = xasprintf("%s/pkg-vulnerabilities.gz", + tnf_vulnerability_base); + } + if (verified_installation == NULL) + verified_installation = "never"; + + if (check_vulnerabilities == NULL) + check_vulnerabilities = "never"; + + snprintf(fetch_flags, sizeof(fetch_flags), "%s%s%s", + (verbose_netio && *verbose_netio) ? "v" : "", + (active_ftp && *active_ftp) ? "" : "p", + (ignore_proxy && *ignore_proxy) ? "d" : ""); +} + +void +pkg_install_show_variable(const char *var_name) +{ + struct config_variable *var; + + for (var = config_variables; var->name != NULL; ++var) { + if (strcmp(var->name, var_name) != 0) + continue; + if (*var->var != NULL) + puts(*var->var); + } +} diff --git a/pkgtools/pkg_install/files/lib/path.c b/pkgtools/pkg_install/files/lib/path.c index 5ef484ebffd..982510bc577 100644 --- a/pkgtools/pkg_install/files/lib/path.c +++ b/pkgtools/pkg_install/files/lib/path.c @@ -1,4 +1,4 @@ -/* $NetBSD: path.c,v 1.6 2004/12/29 12:16:56 agc Exp $ */ +/* $NetBSD: path.c,v 1.7 2009/02/02 12:35:01 joerg Exp $ */ /*- * Copyright (c)2002 YAMAMOTO Takashi, @@ -33,9 +33,7 @@ #if HAVE_SYS_CDEFS_H #include <sys/cdefs.h> #endif -#ifndef lint -__RCSID("$NetBSD: path.c,v 1.6 2004/12/29 12:16:56 agc Exp $"); -#endif +__RCSID("$NetBSD: path.c,v 1.7 2009/02/02 12:35:01 joerg Exp $"); #if HAVE_ERR_H #include <err.h> @@ -113,29 +111,18 @@ path_new_entry(const char *cp, size_t len) { struct path *new; - new = malloc(sizeof(*new)); - if (new == NULL) - err(EXIT_FAILURE, "path_create"); + new = xmalloc(sizeof(*new)); if (!IS_FULLPATH(cp) && !IS_URL(cp)) { /* this is a relative path */ - size_t total; char cwd[MaxPathSize]; - size_t cwdlen; if (getcwd(cwd, sizeof(cwd)) == NULL) err(EXIT_FAILURE, "getcwd"); - cwdlen = strlen(cwd); - total = cwdlen + 1 + len + 1; - new->pl_path = malloc(total); - if (new->pl_path == NULL) - err(EXIT_FAILURE, "path_create"); - snprintf(new->pl_path, total, "%s/%*.*s", cwd, (int)len, (int)len, cp); + new->pl_path = xasprintf("%s/%*.*s", cwd, (int)len, (int)len, cp); } else { - new->pl_path = malloc(len + 1); - if (new->pl_path == NULL) - err(EXIT_FAILURE, "path_create"); + new->pl_path = xmalloc(len + 1); memcpy(new->pl_path, cp, len); new->pl_path[len] = '\0'; } @@ -183,9 +170,7 @@ path_setenv(const char *envname) TAILQ_FOREACH(p, &PkgPath, pl_entry) len += strlen(p->pl_path) + 1; - env = malloc(len); - if (env == NULL) - err(EXIT_FAILURE, "path_setenv"); + env = xmalloc(len); env0 = env; envend = env + len; diff --git a/pkgtools/pkg_install/files/lib/pen.c b/pkgtools/pkg_install/files/lib/pen.c deleted file mode 100644 index 65451e7e4e7..00000000000 --- a/pkgtools/pkg_install/files/lib/pen.c +++ /dev/null @@ -1,206 +0,0 @@ -/* $NetBSD: pen.c,v 1.24 2008/04/26 17:40:01 joerg Exp $ */ - -#if HAVE_CONFIG_H -#include "config.h" -#endif -#include <nbcompat.h> -#if HAVE_SYS_CDEFS_H -#include <sys/cdefs.h> -#endif -#ifndef lint -#if 0 -static const char *rcsid = "from FreeBSD Id: pen.c,v 1.25 1997/10/08 07:48:12 charnier Exp"; -#else -__RCSID("$NetBSD: pen.c,v 1.24 2008/04/26 17:40:01 joerg Exp $"); -#endif -#endif - -/* - * FreeBSD install - a package for the installation and maintainance - * of non-core utilities. - * - * 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. - * - * Jordan K. Hubbard - * 18 July 1993 - * - * Routines for managing the "play pen". - * - */ - -#if HAVE_ERR_H -#include <err.h> -#endif -#include "lib.h" -#if HAVE_SYS_SIGNAL_H -#include <sys/signal.h> -#endif - -/* For keeping track of where we are */ -static char Current[MaxPathSize]; -static char Previous[MaxPathSize]; -static int CurrentSet; /* rm -fr Current only if it's really set! */ - /* CurrentSet is set to 0 before strcpy()s - * to prevent rm'ing of a partial string - * when interrupted by ^C */ - -char * -where_playpen(void) -{ - return Current; -} - -/* - * Find a good place to play. - */ -static char * -find_play_pen(char *pen, size_t pensize, size_t sz) -{ - const char **cp; - struct stat sb; - char *r; - const char *tmpdir[] = { - "PKG_TMPDIR", - "TMPDIR", - "/var/tmp", - "/tmp", - "/usr/tmp", - NULL - }; - - if (pen == NULL) { - cleanup(0); - errx(2, "find_play_pen(): 'pen' variable is NULL\n" - "(this should not happen, please report!)"); - return NULL; - } - - if (pen[0] && (r = strrchr(pen, '/')) != NULL) { - *r = '\0'; - if (stat(pen, &sb) != FAIL && (min_free(pen) >= sz)) { - *r = '/'; - return pen; - } - } - - for (cp = tmpdir; *cp; cp++) { - const char *d = (**cp == '/') ? *cp : getenv(*cp); - - if (d == NULL || stat(d, &sb) == FAIL || min_free(d) < sz) - continue; - - (void)snprintf(pen, pensize, "%s/instmp.XXXXXX", d); - return pen; - } - - cleanup(0); - errx(2, "Can't find enough temporary space to extract the files.\n" - "Please set your PKG_TMPDIR environment variable to a location " - "with at least %zu bytes free", sz); - return NULL; -} - -/* - * Make a temporary directory to play in and chdir() to it, returning - * pathname of previous working directory. - */ -char * -make_playpen(char *pen, size_t pensize, size_t sz) -{ - if (!find_play_pen(pen, pensize, sz)) - return NULL; - - if (!mkdtemp(pen)) { - cleanup(0); - errx(2, "can't mkdtemp '%s'", pen); - } - - /* - * On at least NetBSD, the temporary directory may have a group - * that isn't in the group list of the current user. In that - * case, it is impossible to extract setgid binaries from the - * package, since chmod(2) doesn't allow to set the S_ISGID bit - * for a group that isn't yours. - */ - (void)chown(pen, -1, getegid()); - - if (Verbose) { - if (sz) - fprintf(stderr, - "Requested space: %lu bytes, free space: %lld bytes in %s\n", - (u_long) sz, (long long) min_free(pen), pen); - } - if (min_free(pen) < sz) { - rmdir(pen); - cleanup(0); - errx(2, "not enough free space to create '%s'.\n" - "Please set your PKG_TMPDIR environment variable to a location\n" - "with more space and\ntry the command again", pen); - } - if (Current[0]) - strlcpy(Previous, Current, sizeof(Previous)); - else if (!getcwd(Previous, MaxPathSize)) { - cleanup(0); - err(EXIT_FAILURE, "fatal error during execution: getcwd"); - } - if (chdir(pen) == FAIL) { - cleanup(0); - errx(2, "can't chdir to '%s'", pen); - } - CurrentSet = 0; strlcpy(Current, pen, sizeof(Current)); CurrentSet = 1; - - return Previous; -} - -/* - * Convenience routine for getting out of playpen - */ -void -leave_playpen(char *save) -{ - void (*oldsig) (int); - - /* Make us interruptable while we're cleaning up - just in case... */ - oldsig = signal(SIGINT, SIG_DFL); - if (Previous[0] && chdir(Previous) == FAIL) { - cleanup(0); - errx(2, "can't chdir back to '%s'", Previous); - } else if (CurrentSet && Current[0] && strcmp(Current, Previous)) { - if (strcmp(Current, "/") == 0) { - fprintf(stderr, "PANIC: About to rm -fr / (not doing so, aborting)\n"); - abort(); - } - if (fexec("rm", "-fr", Current, NULL)) - warnx("couldn't remove temporary dir '%s'", Current); - strlcpy(Current, Previous, sizeof(Current)); - } - if (save) - strlcpy(Previous, save, sizeof(Previous)); - else - Previous[0] = '\0'; - signal(SIGINT, oldsig); -} - -/* - * Return free disk space (in bytes) on given file system. - * Returns size in a uint64_t since off_t isn't 64 bits on all - * operating systems. - */ -uint64_t -min_free(const char *tmpdir) -{ - struct statvfs buf; - - if (statvfs(tmpdir, &buf) != 0) { - warn("statvfs"); - return 0; - } - return (uint64_t)buf.f_bavail * buf.f_bsize; -} diff --git a/pkgtools/pkg_install/files/lib/pexec.c b/pkgtools/pkg_install/files/lib/pexec.c deleted file mode 100644 index 1358aedb910..00000000000 --- a/pkgtools/pkg_install/files/lib/pexec.c +++ /dev/null @@ -1,110 +0,0 @@ -#if HAVE_CONFIG_H -#include "config.h" -#endif -#include <nbcompat.h> -#if HAVE_SYS_WAIT_H -#include <sys/wait.h> -#endif -#if HAVE_ERR_H -#include <err.h> -#endif -#if HAVE_ERRNO_H -#include <errno.h> -#endif -#if HAVE_STDLIB_H -#include <stdlib.h> -#endif -#if HAVE_UNISTD_H -#include <unistd.h> -#endif -#if HAVE_STDIO_H -#include <stdio.h> -#endif - -#include "lib.h" - -/* - * If the supplied callback is not NULL, then call it. - */ -static void call_callback(void (*callback)(void)) -{ - if (callback != NULL) { - callback(); - } -} - -/* - * create pipe, fork and exec file with arguments in argv - * child takes stdin from pipe, set up fp for parent to - * output to pipe, and return this information. - */ -pipe_to_system_t *pipe_to_system_begin(const char *file, char *const argv[], - void (*cleanup_callback)(void)) -{ - pipe_to_system_t *retval; - - retval = malloc(sizeof(pipe_to_system_t)); - if (retval == NULL) { - call_callback(cleanup_callback); - errx(2, "can't get pipe space"); - } - - retval->cleanup = cleanup_callback; - - if (pipe(retval->fds) == -1) { - call_callback(retval->cleanup); - errx(2, "cannot create pipe"); - } - - retval->pid = fork(); - if (retval->pid == -1) { - call_callback(retval->cleanup); - errx(2, "cannot fork process for %s", file); - } - - if (retval->pid == 0) { /* The child */ - if (retval->fds[0] != 0) { - dup2(retval->fds[0], 0); - close(retval->fds[0]); - } - close(retval->fds[1]); - execvp(file, argv); - warn("failed to execute %s command", file); - _exit(2); - } - - /* Meanwhile, back in the parent process ... */ - close(retval->fds[0]); - retval->fp = fdopen(retval->fds[1], "w"); - if (retval->fp == NULL) { - call_callback(retval->cleanup); - errx(2, "fdopen failed"); - } - return retval; -} - -/* - * close pipe and wait for child to exit. on non-zero exit status, - * call cleanup callback. return exit status. - */ -int pipe_to_system_end(pipe_to_system_t *to_pipe) -{ - int status; - int wait_ret; - - fclose(to_pipe->fp); - do { - wait_ret = waitpid(to_pipe->pid, &status, 0); - } while (wait_ret == -1 && errno == EINTR); - - if (wait_ret < 0) { - call_callback(to_pipe->cleanup); - errx(2, "waitpid returned failure"); - } - if (!WIFEXITED(status)) { - call_callback(to_pipe->cleanup); - errx(2, "waitpid: process terminated abnormally"); - } - free(to_pipe); - return WEXITSTATUS(status); -} diff --git a/pkgtools/pkg_install/files/lib/pkcs7.c b/pkgtools/pkg_install/files/lib/pkcs7.c new file mode 100644 index 00000000000..c5a1b7f7464 --- /dev/null +++ b/pkgtools/pkg_install/files/lib/pkcs7.c @@ -0,0 +1,326 @@ +/* $NetBSD: pkcs7.c,v 1.2 2009/02/02 12:35:01 joerg Exp $ */ +#if HAVE_CONFIG_H +#include "config.h" +#endif +#include <nbcompat.h> +#if HAVE_SYS_CDEFS_H +#include <sys/cdefs.h> +#endif + +__RCSID("$NetBSD: pkcs7.c,v 1.2 2009/02/02 12:35:01 joerg Exp $"); + +/*- + * Copyright (c) 2004, 2008 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Love Hörnquist Åstrand <lha@it.su.se> + * + * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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_ERR_H +#include <err.h> +#endif + +#include <openssl/pkcs7.h> +#include <openssl/evp.h> +#include <openssl/x509.h> +#include <openssl/x509v3.h> +#include <openssl/pem.h> +#include <openssl/err.h> +#include <openssl/ui.h> + +#include "lib.h" + +#ifndef __UNCONST +#define __UNCONST(a) ((void *)(unsigned long)(const void *)(a)) +#endif + +static const int pkg_key_usage = XKU_CODE_SIGN | XKU_SMIME; + +static int +check_ca(X509 *cert) +{ + if ((cert->ex_flags & EXFLAG_KUSAGE) != 0 && + (cert->ex_kusage & KU_KEY_CERT_SIGN) != KU_KEY_CERT_SIGN) + return 0; + if ((cert->ex_flags & EXFLAG_BCONS) != 0) + return (cert->ex_flags & EXFLAG_CA) == EXFLAG_CA; + if ((cert->ex_flags & (EXFLAG_V1|EXFLAG_SS)) == (EXFLAG_V1|EXFLAG_SS)) + return 1; + if ((cert->ex_flags & EXFLAG_KUSAGE) != 0) + return 1; + if ((cert->ex_flags & EXFLAG_NSCERT) != 0 && + (cert->ex_nscert & NS_ANY_CA) != 0) + return 1; + return 0; +} + +static STACK_OF(X509) * +file_to_certs(const char *file) +{ + unsigned long ret; + STACK_OF(X509) *certs; + FILE *f; + + if ((f = fopen(file, "r")) == NULL) { + warn("open failed %s", file); + return NULL; + } + + certs = sk_X509_new_null(); + for (;;) { + X509 *cert; + + cert = PEM_read_X509(f, NULL, NULL, NULL); + if (cert == NULL) { + ret = ERR_GET_REASON(ERR_peek_error()); + if (ret == PEM_R_NO_START_LINE) { + /* End of file reached. no error */ + ERR_clear_error(); + break; + } + sk_X509_free(certs); + warnx("Can't read certificate in file: %s", file); + return NULL; + } + sk_X509_insert(certs, cert, sk_X509_num(certs)); + } + + fclose(f); + + if (sk_X509_num(certs) == 0) { + sk_X509_free(certs); + certs = NULL; + warnx("No certificate found in file %s", file); + } + + return certs; +} + +int +easy_pkcs7_verify(const char *content, size_t len, + const char *signature, size_t signature_len, + const char *anchor, int is_pkg) +{ + STACK_OF(X509) *cert_chain, *signers; + X509_STORE *store; + BIO *sig, *in; + PKCS7 *p7; + int i, status; + X509_NAME *name; + char *subject; + + OpenSSL_add_all_algorithms(); + ERR_load_crypto_strings(); + + status = -1; + + if (cert_chain_file) + cert_chain = file_to_certs(cert_chain_file); + else + cert_chain = NULL; + + store = X509_STORE_new(); + if (store == NULL) { + sk_X509_free(cert_chain); + warnx("Failed to create certificate store"); + return -1; + } + + X509_STORE_load_locations(store, anchor, NULL); + + in = BIO_new_mem_buf(__UNCONST(content), len); + sig = BIO_new_mem_buf(__UNCONST(signature), signature_len); + signers = NULL; + + p7 = PEM_read_bio_PKCS7(sig, NULL, NULL, NULL); + if (p7 == NULL) { + warnx("Failed to parse the signature"); + goto cleanup; + } + + if (PKCS7_verify(p7, cert_chain, store, in, NULL, 0) != 1) { + warnx("Failed to verify signature"); + goto cleanup; + } + + signers = PKCS7_get0_signers(p7, NULL, 0); + if (signers == NULL) { + warnx("Failed to get signers"); + goto cleanup; + } + + if (sk_X509_num(signers) == 0) { + warnx("No signers found"); + goto cleanup; + } + + for (i = 0; i < sk_X509_num(signers); i++) { + /* Compute ex_xkusage */ + X509_check_purpose(sk_X509_value(signers, i), -1, -1); + + if (check_ca(sk_X509_value(signers, i))) { + warnx("CA keys are not valid for signatures"); + goto cleanup; + } + if (is_pkg) { + if (sk_X509_value(signers, i)->ex_xkusage != pkg_key_usage) { + warnx("Certificate must have CODE SIGNING " + "and EMAIL PROTECTION property"); + goto cleanup; + } + } else { + if (sk_X509_value(signers, i)->ex_xkusage != 0) { + warnx("Certificate must not have any property"); + goto cleanup; + } + } + } + + printf("Sigature ok, signed by:\n"); + + for (i = 0; i < sk_X509_num(signers); i++) { + name = X509_get_subject_name(sk_X509_value(signers, i)); + subject = X509_NAME_oneline(name, NULL, 0); + + printf("\t%s\n", subject); + + OPENSSL_free(subject); + } + + status = 0; + +cleanup: + sk_X509_free(cert_chain); + sk_X509_free(signers); + X509_STORE_free(store); + + PKCS7_free(p7); + BIO_free(in); + BIO_free(sig); + + return status; +} + +static int +ssl_pass_cb(char *buf, int size, int rwflag, void *u) +{ + + if (UI_UTIL_read_pw_string(buf, size, "Passphrase: ", 0)) + return 0; + return strlen(buf); +} + +int +easy_pkcs7_sign(const char *content, size_t len, + char **signature, size_t *signature_len, + const char *key_file, const char *cert_file) +{ + FILE *f; + X509 *certificate; + STACK_OF(X509) *c, *cert_chain; + EVP_PKEY *private_key; + char *tmp_sig; + BIO *out, *in; + PKCS7 *p7; + int status; + + OpenSSL_add_all_algorithms(); + ERR_load_crypto_strings(); + + status = -1; + private_key = NULL; + cert_chain = NULL; + in = NULL; + + c = file_to_certs(cert_file); + + if (sk_X509_num(c) != 1) { + warnx("More then one certificate in the certificate file"); + goto cleanup; + } + certificate = sk_X509_value(c, 0); + + /* Compute ex_kusage */ + X509_check_purpose(certificate, -1, 0); + + if (check_ca(certificate)) { + warnx("CA keys are not valid for signatures"); + goto cleanup; + } + + if (certificate->ex_xkusage != pkg_key_usage) { + warnx("Certificate must have CODE SIGNING " + "and EMAIL PROTECTION property"); + goto cleanup; + } + + if (cert_chain_file) + cert_chain = file_to_certs(cert_chain_file); + + if ((f = fopen(key_file, "r")) == NULL) { + warn("Failed to open private key file %s", key_file); + goto cleanup; + } + private_key = PEM_read_PrivateKey(f, NULL, ssl_pass_cb, NULL); + fclose(f); + if (private_key == NULL) { + warnx("Can't read private key: %s", key_file); + goto cleanup; + } + + if (X509_check_private_key(certificate, private_key) != 1) { + warnx("The private key %s doesn't match the certificate %s", + key_file, cert_file); + goto cleanup; + } + + in = BIO_new_mem_buf(__UNCONST(content), len); + + p7 = PKCS7_sign(certificate, private_key, cert_chain, in, + PKCS7_DETACHED|PKCS7_NOATTR|PKCS7_BINARY); + if (p7 == NULL) { + warnx("Failed to create signature structure"); + goto cleanup; + } + + out = BIO_new(BIO_s_mem()); + PEM_write_bio_PKCS7(out, p7); + *signature_len = BIO_get_mem_data(out, &tmp_sig); + *signature = xmalloc(*signature_len); + memcpy(*signature, tmp_sig, *signature_len); + BIO_free_all(out); + + PKCS7_free(p7); + + status = 0; + +cleanup: + sk_X509_free(c); + sk_X509_free(cert_chain); + EVP_PKEY_free(private_key); + BIO_free(in); + + return status; +} diff --git a/pkgtools/pkg_install/files/lib/pkg_install.conf.5 b/pkgtools/pkg_install/files/lib/pkg_install.conf.5 new file mode 100644 index 00000000000..15841f809b8 --- /dev/null +++ b/pkgtools/pkg_install/files/lib/pkg_install.conf.5 @@ -0,0 +1,158 @@ +.\" $NetBSD: pkg_install.conf.5,v 1.2 2009/02/02 12:35:01 joerg Exp $ +.\" +.\" Copyright (c) 2008, 2009 The NetBSD Foundation, Inc. +.\" All rights reserved. +.\" +.\" This code is derived from software contributed to The NetBSD Foundation +.\" by Thomas Klausner. +.\" +.\" 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. +.\" +.Dd January 8, 2009 +.Dt PKG_INSTALL.CONF 5 +.Os +.Sh NAME +.Nm pkg_install.conf +.Nd configuration file for package installation tools +.Sh DESCRIPTION +The file +.Nm +contains system defaults for the package installation tools +as a list of variable-value pairs. +Each line has the format +.Ev VARIABLE=VALUE . +If the value consists of more than one line, each line is prefixed with +.Ev VARIABLE= . +.Pp +The current value of a variable can be checked by running +.Dl Ic pkg_admin config-var VARIABLE +.Pp +The following variables are supported: +.Bl -tag -width indent +.It Dv ACTIVE_FTP +Force the use of active FTP. +.It Dv CERTIFICATE_ANCHOR_PKGS +Path to the file containing the certificates used for validating +binary packages. +A package is trusted when a certificate chain ends in one of the +certificates contained in this file. +The certificates must be PEM-encoded. +.It Dv CERTIFICATE_ANCHOR_PKGVULN +Analogous to +.Dv CERTIFICATE_ANCHOR_PKGS . +The +.Pa pkg-vulnerabilities +is trusted when a certificate chain ends in one of the certificates +contained in this file. +.It Dv CERTIFICATE_CHAIN +Path to a file containing additional certificates that can be used +for completing certicate chains when validating binary packages or +pkg-vulnerabilities files. +.Dv CHECK_VULNERABILITIES +Check for vulnerabilities when installing packages. +Supported values are: +.Bl -tag -width interactiveXX +.It Dv never +No check is performed. +.It Dv always +Passing the vulnerability check is required. +A missing pkg-vulnerabilities file is considered an error. +.It Dv interactive +The user is always asked to confirm installation of vulnerable packages. +.El +.It Dv GPG +Path to +.Xr gpg 1 , +which can be used to verify the signature in the +.Pa pkg-vulnerabilities +file when running +.Dl Ic pkg_admin check-pkg-vulnerabilities -s +or +.Dl Ic pkg_admin fetch-pkg-vulnerabilities -s +It can also be used to verify and sign binary packages. +.It Dv GPG_KEYRING_PKGVULN +Non-default keyring to use for verifying GPG signatures of +.Pa pkg-vulnerabilities . +.It Dv GPG_KEYRING_SIGN +Non-default keyring to use for signing packages with GPG. +.It Dv GPG_KEYRING_VERIFY +Non-default keyring to use for verifying GPG signature of packages. +.It Dv GPG_SIGN_AS +User-id to use for signing packages. +.It Dv IGNORE_PROXY +Use direct connections and ignore +.Ev FTP_PROXY +and +.Ev HTTP_PROXY . +.It Dv IGNORE_URL +One line per advisory which should be ignored when running +.Dl Ic pkg_admin audit +The URL from the +.Pa pkg-vulnerabilities +file should be used as value. +.It Dv PKGVULNDIR +Directory name in which the +.Pa pkg-vulnerabilities +file resides. +Default is +.Pa ${PKG_DBDIR} . +.It Dv PKGVULNURL +URL which is used for updating the local +.Pa pkg-vulnerabilities +file when running +.Dl Ic pkg_admin fetch-pkg-vulnerabilities +The default is +.Pa ftp://ftp.NetBSD.org/pub/NetBSD/packages/vulns/pkg-vulnerabilities.gz +.Em Note : +Usually, only the compression type should be changed. +Currently supported are uncompressed files and files compressed by +.Xr bzip2 1 +.Pq Pa .bz2 +or +.Xr gzip 1 +.Pq Pa .gz . +.It Dv VERBOSE_NETIO +Log details of network IO to stderr. +.It Dv VERIFIED_INSTALLATION +Set trust level used when installation. +Supported values are: +.Bl -tag -width interactiveXX +.It Dv never +No signature checks are performed. +.It Dv always +A valid signature is required. +If the binary package can not be verified, the installation is terminated +.It Dv trusted +A valid signature is required. +If the binary package can not be verified, the user is asked interactively. +.It Dv interactive +The user is always asked interactively when installing a package. +.El +.El +.Sh FILES +.Bl -tag +.It Pa @SYSCONFDIR@/pkg_install.conf +Default location for the file described in this manual page. +.El +.Sh SEE ALSO +.Xr pkg_add 1 , +.Xr pkg_admin 1 diff --git a/pkgtools/pkg_install/files/lib/pkg_install.conf.cat5 b/pkgtools/pkg_install/files/lib/pkg_install.conf.cat5 new file mode 100644 index 00000000000..fee89cf98a1 --- /dev/null +++ b/pkgtools/pkg_install/files/lib/pkg_install.conf.cat5 @@ -0,0 +1,117 @@ +PKG_INSTALL.CONF(5) NetBSD File Formats Manual PKG_INSTALL.CONF(5) + +NNAAMMEE + ppkkgg__iinnssttaallll..ccoonnff -- configuration file for package installation tools + +DDEESSCCRRIIPPTTIIOONN + The file ppkkgg__iinnssttaallll..ccoonnff contains system defaults for the package + installation tools as a list of variable-value pairs. Each line has the + format VARIABLE=VALUE. If the value consists of more than one line, each + line is prefixed with VARIABLE=. + + The current value of a variable can be checked by running + ppkkgg__aaddmmiinn ccoonnffiigg--vvaarr VVAARRIIAABBLLEE + + The following variables are supported: + + ACTIVE_FTP + Force the use of active FTP. + + CERTIFICATE_ANCHOR_PKGS + Path to the file containing the certificates used for validating + binary packages. A package is trusted when a certificate chain + ends in one of the certificates contained in this file. The cer- + tificates must be PEM-encoded. + + CERTIFICATE_ANCHOR_PKGVULN + Analogous to CERTIFICATE_ANCHOR_PKGS. The _p_k_g_-_v_u_l_n_e_r_a_b_i_l_i_t_i_e_s is + trusted when a certificate chain ends in one of the certificates + contained in this file. + + CERTIFICATE_CHAIN + Path to a file containing additional certificates that can be + used for completing certicate chains when validating binary pack- + ages or pkg-vulnerabilities files. CHECK_VULNERABILITIES Check + for vulnerabilities when installing packages. Supported values + are: + + never No check is performed. + + always Passing the vulnerability check is required. A + missing pkg-vulnerabilities file is considered an + error. + + interactive The user is always asked to confirm installation + of vulnerable packages. + + GPG Path to gpg(1), which can be used to verify the signature in the + _p_k_g_-_v_u_l_n_e_r_a_b_i_l_i_t_i_e_s file when running + ppkkgg__aaddmmiinn cchheecckk--ppkkgg--vvuullnneerraabbiilliittiieess --ss + or + ppkkgg__aaddmmiinn ffeettcchh--ppkkgg--vvuullnneerraabbiilliittiieess --ss + It can also be used to verify and sign binary packages. + + GPG_KEYRING_PKGVULN + Non-default keyring to use for verifying GPG signatures of + _p_k_g_-_v_u_l_n_e_r_a_b_i_l_i_t_i_e_s. + + GPG_KEYRING_SIGN + Non-default keyring to use for signing packages with GPG. + + GPG_KEYRING_VERIFY + Non-default keyring to use for verifying GPG signature of pack- + ages. + + GPG_SIGN_AS + User-id to use for signing packages. + + IGNORE_PROXY + Use direct connections and ignore FTP_PROXY and HTTP_PROXY. + + IGNORE_URL + One line per advisory which should be ignored when running + ppkkgg__aaddmmiinn aauuddiitt + The URL from the _p_k_g_-_v_u_l_n_e_r_a_b_i_l_i_t_i_e_s file should be used as + value. + + PKGVULNDIR + Directory name in which the _p_k_g_-_v_u_l_n_e_r_a_b_i_l_i_t_i_e_s file resides. + Default is _$_{_P_K_G___D_B_D_I_R_}. + + PKGVULNURL + URL which is used for updating the local _p_k_g_-_v_u_l_n_e_r_a_b_i_l_i_t_i_e_s file + when running + ppkkgg__aaddmmiinn ffeettcchh--ppkkgg--vvuullnneerraabbiilliittiieess + The default is + _f_t_p_:_/_/_f_t_p_._N_e_t_B_S_D_._o_r_g_/_p_u_b_/_N_e_t_B_S_D_/_p_a_c_k_a_g_e_s_/_v_u_l_n_s_/_p_k_g_-_v_u_l_n_e_r_a_b_i_l_i_t_i_e_s_._g_z + _N_o_t_e: Usually, only the compression type should be changed. Cur- + rently supported are uncompressed files and files compressed by + bzip2(1) (_._b_z_2) or gzip(1) (_._g_z). + + VERBOSE_NETIO + Log details of network IO to stderr. + + VERIFIED_INSTALLATION + Set trust level used when installation. Supported values are: + + never No signature checks are performed. + + always A valid signature is required. If the binary + package can not be verified, the installation is + terminated + + trusted A valid signature is required. If the binary + package can not be verified, the user is asked + interactively. + + interactive The user is always asked interactively when + installing a package. + +FFIILLEESS + @SYSCONFDIR@/pkg_install.conf Default location for the file described + in this manual page. + +SSEEEE AALLSSOO + pkg_add(1), pkg_admin(1) + +NetBSD 5.0 January 8, 2009 NetBSD 5.0 diff --git a/pkgtools/pkg_install/files/lib/pkg_io.c b/pkgtools/pkg_install/files/lib/pkg_io.c index e8496eb2c2f..abc973c8ed8 100644 --- a/pkgtools/pkg_install/files/lib/pkg_io.c +++ b/pkgtools/pkg_install/files/lib/pkg_io.c @@ -1,4 +1,4 @@ -/* $NetBSD: pkg_io.c,v 1.3 2008/04/26 17:40:01 joerg Exp $ */ +/* $NetBSD: pkg_io.c,v 1.4 2009/02/02 12:35:01 joerg Exp $ */ /*- * Copyright (c) 2008 Joerg Sonnenberger <joerg@NetBSD.org>. * All rights reserved. @@ -36,7 +36,7 @@ #include <sys/cdefs.h> #endif -__RCSID("$NetBSD: pkg_io.c,v 1.3 2008/04/26 17:40:01 joerg Exp $"); +__RCSID("$NetBSD: pkg_io.c,v 1.4 2009/02/02 12:35:01 joerg Exp $"); #include <archive.h> #include <archive_entry.h> @@ -52,7 +52,7 @@ __RCSID("$NetBSD: pkg_io.c,v 1.3 2008/04/26 17:40:01 joerg Exp $"); #include "lib.h" struct fetch_archive { - const char *url; + struct url *url; fetchIO *fetch; char buffer[32768]; }; @@ -62,7 +62,7 @@ fetch_archive_open(struct archive *a, void *client_data) { struct fetch_archive *f = client_data; - f->fetch = fetchGetURL(f->url, ""); + f->fetch = fetchGet(f->url, fetch_flags); if (f->fetch == NULL) return ENOENT; return 0; @@ -88,52 +88,194 @@ fetch_archive_close(struct archive *a, void *client_data) return 0; } -struct archive * -open_remote_archive(const char *url, void **cookie) +static struct archive * +open_archive_by_url(struct url *url, void **cookie) { struct fetch_archive *f; - struct archive *archive; + struct archive *a; - f = malloc(sizeof(*f)); - if (f == NULL) - err(2, "cannot allocate memory for remote archive"); + f = xmalloc(sizeof(*f)); f->url = url; - archive = archive_read_new(); - archive_read_support_compression_all(archive); - archive_read_support_format_all(archive); - if (archive_read_open(archive, f, fetch_archive_open, fetch_archive_read, - fetch_archive_close)) - errx(2, "cannot open archive: %s", archive_error_string(archive)); + a = archive_read_new(); + archive_read_support_compression_all(a); + archive_read_support_format_all(a); + if (archive_read_open(a, f, fetch_archive_open, fetch_archive_read, + fetch_archive_close)) { + archive_read_close(a); + free(f); + return NULL; + } *cookie = f; + return a; +} + +struct archive * +open_archive(const char *url, void **cookie) +{ + struct url *u; + struct archive *a; + + if (!IS_URL(url)) { + a = archive_read_new(); + archive_read_support_compression_all(a); + archive_read_support_format_all(a); + if (archive_read_open_filename(a, url, 1024)) { + archive_read_close(a); + return NULL; + } + *cookie = NULL; + return a; + } + + if ((u = fetchParseURL(url)) == NULL) + return NULL; - return archive; + a = open_archive_by_url(u, cookie); + + fetchFreeURL(u); + return a; } void -close_remote_archive(void *cookie) +close_archive(void *cookie) { free(cookie); } -struct archive * -open_local_archive(const char *path, void **cookie) +static int +strip_suffix(char *filename) { - struct archive *archive; + size_t len; - archive = archive_read_new(); - archive_read_support_compression_all(archive); - archive_read_support_format_all(archive); - if (archive_read_open_filename(archive, path, 1024)) - errx(2, "cannot open archive: %s", - archive_error_string(archive)); - *cookie = NULL; + len = strlen(filename); + if (len <= 4) + return 0; + if (strcmp(filename + len - 4, ".tgz") == 0 || + strcmp(filename + len - 4, ".tbz") == 0) { + filename[len - 4] = '\0'; + return 1; + } else + return 0; +} + +static int +find_best_package(struct url *url, const char *pattern, struct url **best_url) +{ + char *cur_match, *url_pattern, *best_match = NULL; + struct url_list ue; + size_t i; - return archive; + if (*best_url) { + if ((best_match = fetchUnquoteFilename(*best_url)) == NULL) + return -1; + } else + best_match = NULL; + + if (best_match && strip_suffix(best_match) == 0) { + free(best_match); + return -1; + } + + for (i = 0; pattern[i] != '\0'; ++i) { + if (!isalnum((unsigned char)(pattern[i])) && + (pattern[i]) != '-') + break; + } + url_pattern = xasprintf("%*.*s*", (int)i, (int)i, pattern); + + fetchInitURLList(&ue); + if (fetchList(&ue, url, url_pattern, fetch_flags)) { + char *base_url; + base_url = fetchStringifyURL(url); + warnx("Can't process %s%s: %s", base_url, url_pattern, + fetchLastErrString); + free(base_url); + free(url_pattern); + fetchFreeURLList(&ue); + return -1; + } + free(url_pattern); + + for (i = 0; i < ue.length; ++i) { + cur_match = fetchUnquoteFilename(ue.urls + i); + + if (cur_match == NULL) { + free(best_match); + fetchFreeURLList(&ue); + return -1; + } + if (strip_suffix(cur_match) == 0) { + free(cur_match); + continue; + } + if (pkg_order(pattern, cur_match, best_match) == 1) { + if (*best_url) + fetchFreeURL(*best_url); + *best_url = fetchCopyURL(ue.urls + i); + free(best_match); + best_match = cur_match; + cur_match = NULL; + if (*best_url == NULL) { + free(best_match); + return -1; + } + } + free(cur_match); + } + free(best_match); + fetchFreeURLList(&ue); + return 0; } -void -close_local_archive(void *cookie) +struct archive * +find_archive(const char *fname, void **cookie) { + struct archive *a; + struct path *path; + const char *cur_path; + struct url *url, *best_match; + char tmp[MaxPathSize]; + + best_match = NULL; + + a = open_archive(fname, cookie); + if (a != NULL) + return a; + + if (strchr(fname, '/') != NULL) { + const char *last_slash; + + last_slash = strrchr(fname, '/'); + snprintf(tmp, sizeof(tmp), "%s%.*s", + IS_URL(fname) ? "" : "file://", + (int)(last_slash - fname + 1), fname); + url = fetchParseURL(tmp); + if (url == NULL) + return NULL; + fname = last_slash + 1; /* XXX fetchUnquoteFilename */ + find_best_package(url, fname, &best_match); + fetchFreeURL(url); + } else { + TAILQ_FOREACH(path, &PkgPath, pl_entry) { + cur_path = path->pl_path; + if (!IS_URL(cur_path)) { + snprintf(tmp, sizeof(tmp), "file://%s", cur_path); + cur_path = tmp; + } + url = fetchParseURL(cur_path); + if (url == NULL) + continue; + find_best_package(url, fname, &best_match); + /* XXX Check return value and complain */ + fetchFreeURL(url); + } + } + + if (best_match == NULL) + return NULL; + a = open_archive_by_url(best_match, cookie); + fetchFreeURL(best_match); + return a; } diff --git a/pkgtools/pkg_install/files/lib/pkg_signature.c b/pkgtools/pkg_install/files/lib/pkg_signature.c new file mode 100644 index 00000000000..3f4bb1f039c --- /dev/null +++ b/pkgtools/pkg_install/files/lib/pkg_signature.c @@ -0,0 +1,686 @@ +/* $NetBSD: pkg_signature.c,v 1.2 2009/02/02 12:35:01 joerg Exp $ */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif +#include <nbcompat.h> +#if HAVE_SYS_CDEFS_H +#include <sys/cdefs.h> +#endif +__RCSID("$NetBSD: pkg_signature.c,v 1.2 2009/02/02 12:35:01 joerg Exp $"); + +/*- + * 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_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 <stdlib.h> +#ifndef NETBSD +#include <nbcompat/sha2.h> +#else +#include <sha2.h> +#endif +#include <signal.h> +#ifdef NETBSD +#include <unistd.h> +#else +#include <nbcompat/unistd.h> +#endif + +#include <archive.h> +#include <archive_entry.h> + +#include "lib.h" + +#define HASH_FNAME "+PKG_HASH" +#define SIGNATURE_FNAME "+PKG_SIGNATURE" +#define GPG_SIGNATURE_FNAME "+PKG_GPG_SIGNATURE" + +struct signature_archive { + struct archive *archive; + off_t pkg_size; + size_t sign_block_len, sign_block_number, sign_cur_block; + char **sign_blocks; + unsigned char *sign_buf; +}; + +static void +hash_block(unsigned char *buf, size_t buf_len, + char hash[SHA512_DIGEST_STRING_LENGTH]) +{ + unsigned char digest[SHA512_DIGEST_LENGTH]; + SHA512_CTX hash_ctx; + int i; + + SHA512_Init(&hash_ctx); + SHA512_Update(&hash_ctx, buf, buf_len); + SHA512_Final(digest, &hash_ctx); + for (i = 0; i < SHA512_DIGEST_LENGTH; ++i) { + unsigned char c; + + c = digest[i] / 16; + if (c < 10) + hash[2 * i] = '0' + c; + else + hash[2 * i] = 'a' - 10 + c; + + c = digest[i] % 16; + if (c < 10) + hash[2 * i + 1] = '0' + c; + else + hash[2 * i + 1] = 'a' - 10 + c; + } + hash[2 * i] = '\0'; +} + +static ssize_t +verify_signature_read_cb(struct archive *archive, void *cookie, const void **buf) +{ + struct signature_archive *state = cookie; + char hash[SHA512_DIGEST_STRING_LENGTH]; + ssize_t len, expected; + + if (state->sign_cur_block >= state->sign_block_number) + return 0; + + /* The following works for sign_block_len > 1 */ + if (state->sign_cur_block + 1 == state->sign_block_number) + expected = state->pkg_size % state->sign_block_len; + else + expected = state->sign_block_len; + + len = archive_read_data(state->archive, state->sign_buf, expected); + if (len != expected) { + warnx("Short read from package"); + return -1; + } + + hash_block(state->sign_buf, len, hash); + + if (strcmp(hash, state->sign_blocks[state->sign_cur_block]) != 0) { + warnx("Invalid signature of block %llu", + (unsigned long long)state->sign_cur_block); + return -1; + } + ++state->sign_cur_block; + *buf = state->sign_buf; + return len; +} + +static void +free_signature_int(struct signature_archive *state) +{ + size_t i; + + if (state->sign_blocks != NULL) { + for (i = 0; i < state->sign_block_number; ++i) + free(state->sign_blocks[i]); + } + free(state->sign_blocks); + free(state->sign_buf); + free(state); +} + +void +pkg_free_signature(void *cookie) +{ + struct signature_archive *state = cookie; + + if (state == NULL) + return; + + archive_read_finish(state->archive); + free_signature_int(state); +} + +static int +read_file_from_archive(struct archive *archive, struct archive_entry **entry, + const char *fname, char **content, size_t *len) +{ + int r; + + *content = NULL; + *len = 0; + +retry: + if (*entry == NULL && + (r = archive_read_next_header(archive, entry)) != ARCHIVE_OK) { + if (r == ARCHIVE_FATAL) + warnx("Cannot read from archive: %s", + archive_error_string(archive)); + return -1; + } + if (strcmp(archive_entry_pathname(*entry), "//") == 0) { + archive_read_data_skip(archive); + *entry = NULL; + goto retry; + } + + if (strcmp(fname, archive_entry_pathname(*entry)) != 0) + return -1; + + if (archive_entry_size(*entry) > SSIZE_MAX - 1) { + warnx("signature too large to process"); + return 1; + } + *len = archive_entry_size(*entry); + *content = xmalloc(*len + 1); + + if (archive_read_data(archive, *content, *len) != *len) { + warnx("cannot read complete %s from archive", fname); + free(*content); + *len = 0; + *content = NULL; + return 1; + } + (*content)[*len] = '\0'; + *entry = NULL; + + return 0; +} + +static int +parse_hash_file(const char *hash_file, char **pkgname, + struct signature_archive *state) +{ + static const char block1[] = "pkgsrc signature\n\nversion: 1\npkgname: "; + static const char block2[] = "algorithm: SHA512\nblock size: "; + static const char block3[] = "file size: "; + static const char block4[] = "end pkgsrc signature\n"; + char *next; + size_t i, len; + + *pkgname = NULL; + + if (strncmp(hash_file, block1, strlen(block1)) != 0) + goto cleanup; + hash_file += strlen(block1); + + len = strcspn(hash_file, "\n"); + *pkgname = xmalloc(len + 1); + memcpy(*pkgname, hash_file, len); + (*pkgname)[len] = '\0'; + for (i = 0; i < len; ++i) { + if (!isgraph((unsigned char)(*pkgname)[i])) + goto cleanup; + } + hash_file += len + 1; + + if (strncmp(hash_file, block2, strlen(block2)) != 0) + goto cleanup; + hash_file += strlen(block2); + + errno = 0; + if (!isdigit((unsigned char)*hash_file)) + goto cleanup; + state->sign_block_len = strtoul(hash_file, &next, 10); + hash_file = next; + + /* Assert sane minimum block size of 1KB */ + if (*hash_file++ != '\n' || errno == ERANGE || state->sign_block_len < 1024) + goto cleanup; + + if (strncmp(hash_file, block3, strlen(block3)) != 0) + goto cleanup; + hash_file += strlen(block3); + + errno = 0; + if (!isdigit((unsigned char)*hash_file)) + goto cleanup; + if (sizeof(off_t) >= sizeof(long long)) + state->pkg_size = strtoll(hash_file, &next, 10); + else + state->pkg_size = strtol(hash_file, &next, 10); + hash_file = next; + if (*hash_file++ != '\n' || errno == ERANGE || state->pkg_size < 1) + goto cleanup; + + if (*hash_file++ != '\n') + goto cleanup; + + if (state->pkg_size / state->sign_block_len > SSIZE_MAX) + goto cleanup; + state->sign_block_number = (state->pkg_size + + state->sign_block_len - 1) / state->sign_block_len; + + state->sign_buf = xmalloc(state->sign_block_len); + state->sign_blocks = xcalloc(state->sign_block_number, sizeof(char *)); + + for (i = 0; i < state->sign_block_number; ++i) { + len = strspn(hash_file, "01234567889abcdef"); + if (len != SHA512_DIGEST_LENGTH * 2 || hash_file[len] != '\n') + goto cleanup_hashes; + state->sign_blocks[i] = xmalloc(len + 1); + memcpy(state->sign_blocks[i], hash_file, len); + state->sign_blocks[i][len] = '\0'; + hash_file += len + 1; + } + + if (strcmp(hash_file, block4) != 0) + goto cleanup_hashes; + + return 0; + +cleanup_hashes: + for (i = 0; i < state->sign_block_number; ++i) + free(state->sign_blocks[i]); + free(state->sign_blocks); + state->sign_blocks = NULL; + +cleanup: + warnx("Unknown format of hash file"); + free(*pkgname); + *pkgname = NULL; + return -1; +} + +int +pkg_verify_signature(struct archive **archive, struct archive_entry **entry, + char **pkgname, void **cookie) +{ + struct signature_archive *state; + struct archive_entry *my_entry; + struct archive *a; + char *hash_file, *signature_file; + size_t hash_len, signature_len; + int r, has_sig; + + *pkgname = NULL; + *cookie = NULL; + + state = xmalloc(sizeof(*state)); + state->sign_blocks = NULL; + state->sign_buf = NULL; + state->archive = NULL; + + r = read_file_from_archive(*archive, entry, HASH_FNAME, + &hash_file, &hash_len); + if (r == -1) { + free(state); + goto no_valid_signature; + } else if (r == 1) { + free(state); + goto no_valid_signature; + } + + if (parse_hash_file(hash_file, pkgname, state)) + goto no_valid_signature; + + r = read_file_from_archive(*archive, entry, SIGNATURE_FNAME, + &signature_file, &signature_len); + if (r != 0) { + if (*entry != NULL) + r = read_file_from_archive(*archive, entry, + GPG_SIGNATURE_FNAME, + &signature_file, &signature_len); + if (r != 0) { + free(hash_file); + free(state); + goto no_valid_signature; + } + has_sig = !detached_gpg_verify(hash_file, hash_len, + signature_file, signature_len, gpg_keyring_verify); + + free(signature_file); + } else { + has_sig = !easy_pkcs7_verify(hash_file, hash_len, signature_file, + signature_len, certs_packages, 1); + + free(signature_file); + } + + r = archive_read_next_header(*archive, &my_entry); + if (r != ARCHIVE_OK) { + warnx("Cannot read inner package: %s", + archive_error_string(*archive)); + free_signature_int(state); + goto no_valid_signature; + } + + if (archive_entry_size(my_entry) != state->pkg_size) { + warnx("Package size doesn't match signature"); + free_signature_int(state); + goto no_valid_signature; + } + + state->archive = *archive; + + a = archive_read_new(); + archive_read_support_compression_all(a); + archive_read_support_format_all(a); + if (archive_read_open(a, state, NULL, verify_signature_read_cb, NULL)) { + warnx("Can't open signed package file"); + archive_read_finish(a); + free_signature_int(state); + goto no_valid_signature; + } + *archive = a; + *entry = NULL; + *cookie = state; + + return has_sig ? 0 : -1; + +no_valid_signature: + return -1; +} + +int +pkg_full_signature_check(struct archive *archive) +{ + struct archive_entry *entry = NULL; + char *pkgname; + void *cookie; + int r; + + if (pkg_verify_signature(&archive, &entry, &pkgname, &cookie)) + return -1; + if (pkgname == NULL) + return 0; + + /* XXX read PLIST and compare pkgname */ + while ((r = archive_read_next_header(archive, &entry)) == ARCHIVE_OK) + archive_read_data_skip(archive); + + pkg_free_signature(cookie); + free(pkgname); + return r == ARCHIVE_EOF ? 0 : -1; +} + +static char * +extract_pkgname(int fd) +{ + package_t plist; + plist_t *p; + struct archive *a; + struct archive_entry *entry; + char *buf; + ssize_t len; + int r; + + a = archive_read_new(); + archive_read_support_compression_all(a); + archive_read_support_format_all(a); + if (archive_read_open_fd(a, fd, 1024)) { + warnx("Cannot open binary package: %s", + archive_error_string(a)); + archive_read_finish(a); + return NULL; + } + + r = archive_read_next_header(a, &entry); + if (r != ARCHIVE_OK) { + warnx("Cannot extract package name: %s", + r == ARCHIVE_EOF ? "EOF" : archive_error_string(a)); + archive_read_finish(a); + return NULL; + } + if (strcmp(archive_entry_pathname(entry), "+CONTENTS") != 0) { + warnx("Invalid binary package, doesn't start with +CONTENTS"); + archive_read_finish(a); + return NULL; + } + if (archive_entry_size(entry) > SSIZE_MAX - 1) { + warnx("+CONTENTS too large to process"); + archive_read_finish(a); + return NULL; + } + + len = archive_entry_size(entry); + buf = xmalloc(len + 1); + + if (archive_read_data(a, buf, len) != len) { + warnx("Short read when extracing +CONTENTS"); + free(buf); + archive_read_finish(a); + return NULL; + } + buf[len] = '\0'; + + archive_read_finish(a); + + parse_plist(&plist, buf); + free(buf); + p = find_plist(&plist, PLIST_NAME); + if (p != NULL) { + buf = xstrdup(p->name); + } else { + warnx("Invalid PLIST: missing @name"); + buf = NULL; + } + free_plist(&plist); + + if (lseek(fd, 0, SEEK_SET) != 0) { + warn("Cannot seek in archive"); + free(buf); + return NULL; + } + + return buf; +} + +static const char hash_template[] = +"pkgsrc signature\n" +"\n" +"version: 1\n" +"pkgname: %s\n" +"algorithm: SHA512\n" +"block size: 65536\n" +"file size: %lld\n" +"\n"; + +static const char hash_trailer[] = "end pkgsrc signature\n"; + +void +pkg_sign_x509(const char *name, const char *output, const char *key_file, const char *cert_file) +{ + struct archive *pkg; + struct archive_entry *entry, *hash_entry, *sign_entry; + int fd; + struct stat sb; + char *hash_file, *signature_file, *tmp, *pkgname, hash[SHA512_DIGEST_STRING_LENGTH]; + unsigned char block[65536]; + off_t i, size; + size_t block_len, signature_len; + + if ((fd = open(name, O_RDONLY)) == -1) + err(EXIT_FAILURE, "Cannot open binary package %s", name); + if (fstat(fd, &sb) == -1) + err(EXIT_FAILURE, "Cannot stat %s", name); + + entry = archive_entry_new(); + archive_entry_copy_stat(entry, &sb); + + pkgname = extract_pkgname(fd); + hash_file = xasprintf(hash_template, pkgname, + (long long)archive_entry_size(entry)); + free(pkgname); + + for (i = 0; i < archive_entry_size(entry); i += block_len) { + if (i + sizeof(block) < archive_entry_size(entry)) + block_len = sizeof(block); + else + block_len = archive_entry_size(entry) % sizeof(block); + if (read(fd, block, block_len) != block_len) + err(2, "short read"); + hash_block(block, block_len, hash); + tmp = xasprintf("%s%s\n", hash_file, hash); + free(hash_file); + hash_file = tmp; + } + tmp = xasprintf("%s%s", hash_file, hash_trailer); + free(hash_file); + hash_file = tmp; + + if (easy_pkcs7_sign(hash_file, strlen(hash_file), &signature_file, + &signature_len, key_file, cert_file)) + err(EXIT_FAILURE, "Cannot sign hash file"); + + lseek(fd, 0, SEEK_SET); + + sign_entry = archive_entry_clone(entry); + hash_entry = archive_entry_clone(entry); + pkgname = strrchr(name, '/'); + archive_entry_set_pathname(entry, pkgname != NULL ? pkgname + 1 : name); + archive_entry_set_pathname(hash_entry, HASH_FNAME); + archive_entry_set_pathname(sign_entry, SIGNATURE_FNAME); + archive_entry_set_size(hash_entry, strlen(hash_file)); + archive_entry_set_size(sign_entry, signature_len); + + pkg = archive_write_new(); + archive_write_set_compression_none(pkg); + archive_write_set_format_ar_bsd(pkg); + archive_write_open_filename(pkg, output); + + archive_write_header(pkg, hash_entry); + archive_write_data(pkg, hash_file, strlen(hash_file)); + archive_write_finish_entry(pkg); + archive_entry_free(hash_entry); + + archive_write_header(pkg, sign_entry); + archive_write_data(pkg, signature_file, signature_len); + archive_write_finish_entry(pkg); + archive_entry_free(sign_entry); + + size = archive_entry_size(entry); + archive_write_header(pkg, entry); + + for (i = 0; i < size; i += block_len) { + if (i + sizeof(block) < size) + block_len = sizeof(block); + else + block_len = size % sizeof(block); + if (read(fd, block, block_len) != block_len) + err(2, "short read"); + archive_write_data(pkg, block, block_len); + } + archive_write_finish_entry(pkg); + archive_entry_free(entry); + + archive_write_finish(pkg); + + exit(0); +} + +void +pkg_sign_gpg(const char *name, const char *output) +{ + struct archive *pkg; + struct archive_entry *entry, *hash_entry, *sign_entry; + int fd; + struct stat sb; + char *hash_file, *signature_file, *tmp, *pkgname, hash[SHA512_DIGEST_STRING_LENGTH]; + unsigned char block[65536]; + off_t i, size; + size_t block_len, signature_len; + + if ((fd = open(name, O_RDONLY)) == -1) + err(EXIT_FAILURE, "Cannot open binary package %s", name); + if (fstat(fd, &sb) == -1) + err(EXIT_FAILURE, "Cannot stat %s", name); + + entry = archive_entry_new(); + archive_entry_copy_stat(entry, &sb); + + pkgname = extract_pkgname(fd); + hash_file = xasprintf(hash_template, pkgname, + (long long)archive_entry_size(entry)); + free(pkgname); + + for (i = 0; i < archive_entry_size(entry); i += block_len) { + if (i + sizeof(block) < archive_entry_size(entry)) + block_len = sizeof(block); + else + block_len = archive_entry_size(entry) % sizeof(block); + if (read(fd, block, block_len) != block_len) + err(2, "short read"); + hash_block(block, block_len, hash); + tmp = xasprintf("%s%s\n", hash_file, hash); + free(hash_file); + hash_file = tmp; + } + tmp = xasprintf("%s%s", hash_file, hash_trailer); + free(hash_file); + hash_file = tmp; + + if (detached_gpg_sign(hash_file, strlen(hash_file), &signature_file, + &signature_len, gpg_keyring_sign, gpg_sign_as)) + err(EXIT_FAILURE, "Cannot sign hash file"); + + lseek(fd, 0, SEEK_SET); + + sign_entry = archive_entry_clone(entry); + hash_entry = archive_entry_clone(entry); + pkgname = strrchr(name, '/'); + archive_entry_set_pathname(entry, pkgname != NULL ? pkgname + 1 : name); + archive_entry_set_pathname(hash_entry, HASH_FNAME); + archive_entry_set_pathname(sign_entry, GPG_SIGNATURE_FNAME); + archive_entry_set_size(hash_entry, strlen(hash_file)); + archive_entry_set_size(sign_entry, signature_len); + + pkg = archive_write_new(); + archive_write_set_compression_none(pkg); + archive_write_set_format_ar_bsd(pkg); + archive_write_open_filename(pkg, output); + + archive_write_header(pkg, hash_entry); + archive_write_data(pkg, hash_file, strlen(hash_file)); + archive_write_finish_entry(pkg); + archive_entry_free(hash_entry); + + archive_write_header(pkg, sign_entry); + archive_write_data(pkg, signature_file, signature_len); + archive_write_finish_entry(pkg); + archive_entry_free(sign_entry); + + size = archive_entry_size(entry); + archive_write_header(pkg, entry); + + for (i = 0; i < size; i += block_len) { + if (i + sizeof(block) < size) + block_len = sizeof(block); + else + block_len = size % sizeof(block); + if (read(fd, block, block_len) != block_len) + err(2, "short read"); + archive_write_data(pkg, block, block_len); + } + archive_write_finish_entry(pkg); + archive_entry_free(entry); + + archive_write_finish(pkg); + + exit(0); +} diff --git a/pkgtools/pkg_install/files/lib/pkgdb.c b/pkgtools/pkg_install/files/lib/pkgdb.c index afeefb13655..3270da9ada9 100644 --- a/pkgtools/pkg_install/files/lib/pkgdb.c +++ b/pkgtools/pkg_install/files/lib/pkgdb.c @@ -1,4 +1,4 @@ -/* $NetBSD: pkgdb.c,v 1.30 2008/04/29 05:46:08 martin Exp $ */ +/* $NetBSD: pkgdb.c,v 1.31 2009/02/02 12:35:01 joerg Exp $ */ #if HAVE_CONFIG_H #include "config.h" @@ -7,9 +7,7 @@ #if HAVE_SYS_CDEFS_H #include <sys/cdefs.h> #endif -#ifndef lint -__RCSID("$NetBSD: pkgdb.c,v 1.30 2008/04/29 05:46:08 martin Exp $"); -#endif +__RCSID("$NetBSD: pkgdb.c,v 1.31 2009/02/02 12:35:01 joerg Exp $"); /*- * Copyright (c) 1999-2008 The NetBSD Foundation, Inc. @@ -341,10 +339,5 @@ _pkgdb_setPKGDB_DIR(const char *dir) char * pkgdb_pkg_file(const char *pkg, const char *file) { - char *buf; - - if (asprintf(&buf, "%s/%s/%s", _pkgdb_getPKGDB_DIR(), pkg, file) == -1) - err(EXIT_FAILURE, "asprintf failed"); - - return buf; + return xasprintf("%s/%s/%s", _pkgdb_getPKGDB_DIR(), pkg, file); } diff --git a/pkgtools/pkg_install/files/lib/plist.c b/pkgtools/pkg_install/files/lib/plist.c index 6701edda7cd..b55cd3f6239 100644 --- a/pkgtools/pkg_install/files/lib/plist.c +++ b/pkgtools/pkg_install/files/lib/plist.c @@ -1,4 +1,4 @@ -/* $NetBSD: plist.c,v 1.21 2008/09/17 15:21:30 joerg Exp $ */ +/* $NetBSD: plist.c,v 1.22 2009/02/02 12:35:01 joerg Exp $ */ #if HAVE_CONFIG_H #include "config.h" @@ -7,13 +7,7 @@ #if HAVE_SYS_CDEFS_H #include <sys/cdefs.h> #endif -#ifndef lint -#if 0 -static const char *rcsid = "from FreeBSD Id: plist.c,v 1.24 1997/10/08 07:48:15 charnier Exp"; -#else -__RCSID("$NetBSD: plist.c,v 1.21 2008/09/17 15:21:30 joerg Exp $"); -#endif -#endif +__RCSID("$NetBSD: plist.c,v 1.22 2009/02/02 12:35:01 joerg Exp $"); /* * FreeBSD install - a package for the installation and maintainance @@ -118,7 +112,7 @@ add_plist(package_t *p, pl_ent_t type, const char *arg) plist_t *tmp; tmp = new_plist_entry(); - tmp->name = (arg == (char *) NULL) ? (char *) NULL : strdup(arg); + tmp->name = (arg == NULL) ? NULL : xstrdup(arg); tmp->type = type; if (!p->head) { p->head = p->tail = tmp; @@ -138,7 +132,7 @@ add_plist_top(package_t *p, pl_ent_t type, const char *arg) plist_t *tmp; tmp = new_plist_entry(); - tmp->name = (arg == (char *) NULL) ? (char *) NULL : strdup(arg); + tmp->name = (arg == NULL) ? NULL : xstrdup(arg); tmp->type = type; if (!p->head) { p->head = p->tail = tmp; @@ -239,13 +233,7 @@ delete_plist(package_t *pkg, Boolean all, pl_ent_t type, char *name) plist_t * new_plist_entry(void) { - plist_t *ret; - - if ((ret = (plist_t *) malloc(sizeof(plist_t))) == (plist_t *) NULL) { - err(EXIT_FAILURE, "can't allocate %ld bytes", (long) sizeof(plist_t)); - } - memset(ret, 0, sizeof(plist_t)); - return ret; + return xcalloc(1, sizeof(plist_t)); } /* @@ -290,9 +278,7 @@ plist_cmd(const char *s, char **arg) while (isspace((unsigned char)*sp)) ++sp; - *arg = strdup(sp); - if (*arg == NULL) - err(2, "strdup failed"); + *arg = xstrdup(sp); if (*sp) { sp2 = *arg + strlen(*arg) - 1; /* @@ -317,6 +303,9 @@ parse_plist(package_t *pkg, const char *buf) const char *eol, *next; size_t len; + pkg->head = NULL; + pkg->tail = NULL; + for (; *buf; buf = next) { /* Until add_plist can deal with trailing whitespace. */ if ((eol = strchr(buf, '\n')) != NULL) { @@ -333,9 +322,7 @@ parse_plist(package_t *pkg, const char *buf) if (len == 0) continue; - line = malloc(len + 1); - if (line == NULL) - err(2, "malloc failed"); + line = xmalloc(len + 1); memcpy(line, buf, len); line[len] = '\0'; @@ -439,7 +426,8 @@ write_plist(package_t *pkg, FILE * fp, char *realprefix) * Like write_plist, but compute memory string. */ void -stringify_plist(package_t *pkg, char **real_buf, size_t *real_len, char *realprefix) +stringify_plist(package_t *pkg, char **real_buf, size_t *real_len, + const char *realprefix) { plist_t *p; const cmd_t *cmdp; @@ -468,8 +456,7 @@ stringify_plist(package_t *pkg, char **real_buf, size_t *real_len, char *realpre } /* Pass Two: build actual string. */ - if ((buf = malloc(len + 1)) == NULL) - err(2, "malloc failed"); + buf = xmalloc(len + 1); *real_buf = buf; *real_len = len; ++len; @@ -517,7 +504,8 @@ do { \ * run it too in cases of failure. */ int -delete_package(Boolean ign_err, Boolean nukedirs, package_t *pkg, Boolean NoDeleteFiles) +delete_package(Boolean ign_err, Boolean nukedirs, package_t *pkg, + Boolean NoDeleteFiles, const char *destdir) { plist_t *p; char *Where = ".", *last_file = ""; @@ -550,6 +538,7 @@ delete_package(Boolean ign_err, Boolean nukedirs, package_t *pkg, Boolean NoDele if (NoDeleteFiles) break; format_cmd(tmp, sizeof(tmp), p->name, Where, last_file); + /* XXX cleanup(0); */ printf("Executing `%s'\n", tmp); if (!Fake && system(tmp)) { warnx("unexec command for `%s' failed", tmp); @@ -559,7 +548,9 @@ delete_package(Boolean ign_err, Boolean nukedirs, package_t *pkg, Boolean NoDele case PLIST_FILE: last_file = p->name; - (void) snprintf(tmp, sizeof(tmp), "%s/%s", Where, p->name); + (void) snprintf(tmp, sizeof(tmp), "%s%s%s/%s", + destdir ? destdir : "", destdir ? "/" : "", + Where, p->name); if (isdir(tmp)) { warnx("attempting to delete directory `%s' as a file\n" "this packing list is incorrect - ignoring delete request", tmp); @@ -577,7 +568,7 @@ delete_package(Boolean ign_err, Boolean nukedirs, package_t *pkg, Boolean NoDele Force ? "deleting anyway" : "not deleting", tmp); if (!Force) { fail = FAIL; - continue; + goto pkgdb_cleanup; } } } @@ -590,7 +581,7 @@ delete_package(Boolean ign_err, Boolean nukedirs, package_t *pkg, Boolean NoDele if ((cc = readlink(tmp, &buf[SymlinkHeaderLen], sizeof(buf) - SymlinkHeaderLen - 1)) < 0) { warn("can't readlink `%s'", tmp); - continue; + goto pkgdb_cleanup; } buf[SymlinkHeaderLen + cc] = 0x0; if (strcmp(buf, p->next->name) != 0) { @@ -600,7 +591,7 @@ delete_package(Boolean ign_err, Boolean nukedirs, package_t *pkg, Boolean NoDele buf, Force ? "deleting anyway" : "not deleting", tmp); if (!Force) { fail = FAIL; - continue; + goto pkgdb_cleanup; } } buf[SymlinkHeaderLen + cc] = 0x0; @@ -609,7 +600,7 @@ delete_package(Boolean ign_err, Boolean nukedirs, package_t *pkg, Boolean NoDele buf, Force ? "deleting anyway" : "not deleting", tmp); if (!Force) { fail = FAIL; - continue; + goto pkgdb_cleanup; } } } @@ -635,21 +626,12 @@ delete_package(Boolean ign_err, Boolean nukedirs, package_t *pkg, Boolean NoDele } } +pkgdb_cleanup: if (!Fake) { if (!restored) { -#ifdef PKGDB_DEBUG - printf("pkgdb_remove(\"%s\")\n", tmp); /* HF */ -#endif errno = 0; - if (pkgdb_remove(tmp)) { - if (errno) { - perror("pkgdb_remove"); - } - } else { -#ifdef PKGDB_DEBUG - printf("pkgdb_remove: ok\n"); -#endif - } + if (pkgdb_remove(tmp) && errno) + perror("pkgdb_remove"); } } } @@ -659,7 +641,9 @@ delete_package(Boolean ign_err, Boolean nukedirs, package_t *pkg, Boolean NoDele if (NoDeleteFiles) break; - (void) snprintf(tmp, sizeof(tmp), "%s/%s", Where, p->name); + (void) snprintf(tmp, sizeof(tmp), "%s%s%s/%s", + destdir ? destdir : "", destdir ? "/" : "", + Where, p->name); if (fexists(tmp)) { if (!isdir(tmp)) { warnx("cannot remove `%s' as a directory\n" @@ -686,14 +670,6 @@ delete_package(Boolean ign_err, Boolean nukedirs, package_t *pkg, Boolean NoDele return fail; } -#ifdef DEBUG -#define RMDIR(dir) fexec(RMDIR_CMD, dir, NULL) -#define REMOVE(dir,ie) fexec_skipemtpy(REMOVE_CMD, (ie) ? "-f " : "", dir, NULL) -#else -#define RMDIR rmdir -#define REMOVE(file,ie) (remove(file) && !(ie)) -#endif - /* * Selectively delete a hierarchy * Returns 1 on error, 0 else. @@ -710,13 +686,15 @@ delete_hierarchy(char *dir, Boolean ign_err, Boolean nukedirs) isdir(dir) ? "directory" : "file", dir); return !ign_err; } else if (nukedirs) { - if (fexec_skipempty(REMOVE_CMD, "-r", ign_err ? "-f" : "", dir, NULL)) + if (recursive_remove(dir, ign_err)) { + warn("Couldn't remove %s", dir); return 1; + } } else if (isdir(dir)) { - if (RMDIR(dir) && !ign_err) + if (rmdir(dir) && !ign_err) return 1; } else { - if (REMOVE(dir, ign_err)) + if (remove(dir) && !ign_err) return 1; } @@ -727,7 +705,7 @@ delete_hierarchy(char *dir, Boolean ign_err, Boolean nukedirs) *cp2 = '\0'; if (!isemptydir(dir)) return 0; - if (RMDIR(dir) && !ign_err) { + if (rmdir(dir) && !ign_err) { if (!fexists(dir)) warnx("directory `%s' doesn't really exist", dir); else diff --git a/pkgtools/pkg_install/files/lib/remove.c b/pkgtools/pkg_install/files/lib/remove.c new file mode 100644 index 00000000000..03249766e45 --- /dev/null +++ b/pkgtools/pkg_install/files/lib/remove.c @@ -0,0 +1,196 @@ +/* $NetBSD: remove.c,v 1.2 2009/02/02 12:35:01 joerg Exp $ */ + +/*- + * 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: remove.c,v 1.2 2009/02/02 12:35:01 joerg Exp $"); + +#if HAVE_DIRENT_H +#include <dirent.h> +#endif +#if HAVE_ERR_H +#include <err.h> +#endif +#include <errno.h> +#if HAVE_FCNTL_H +#include <fcntl.h> +#endif +#include <limits.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "lib.h" + +static int +safe_fchdir(int cwd) +{ + int tmp_errno, rv; + + tmp_errno = errno; + rv = fchdir(cwd); + errno = tmp_errno; + + return rv; +} + +static int +long_remove(const char **path_ptr, int missing_ok, int *did_chdir) +{ + char tmp_path[PATH_MAX + 1]; + const char *slash, *path; + size_t i, len; + int rv; + + path = *path_ptr; + len = strlen(path); + *did_chdir = 0; + + while (len >= PATH_MAX) { + slash = path; + for (i = PATH_MAX - 1; i > 0; --i) { + if (path[i] == '/') + break; + } + if (i == 0) { + errno = ENAMETOOLONG; + return -1; /* Assumes PATH_MAX > NAME_MAX */ + } + memcpy(tmp_path, path, i); + tmp_path[i] = '\0'; + if (chdir(tmp_path)) + return -1; + *did_chdir = 1; + path += i + 1; + len -= i + 1; + } + + if (remove(path) == 0 || (errno == ENOENT && missing_ok)) + rv = 0; + else + rv = -1; + + *path_ptr = path; + + return rv; +} + +static int +recursive_remove_internal(const char *path, int missing_ok, int cwd) +{ + DIR *dir; + struct dirent *de; + const char *sub_path; + char *subdir; + int did_chdir, rv; + + /* + * If the argument is longer than PATH_MAX, long_remove + * will try to shorten it using chdir. So before returning, + * make sure to fchdir back to the original cwd. + */ + sub_path = path; + if (long_remove(&sub_path, missing_ok, &did_chdir) == 0) + rv = 0; + else if (errno != ENOTEMPTY) /* Other errors are terminal. */ + rv = -1; + else + rv = 1; + + if (rv != 1) { + if (did_chdir && safe_fchdir(cwd) == -1 && rv == 0) + rv = -1; + return rv; + } + + if ((dir = opendir(sub_path)) == NULL) { + if (errno == EMFILE) + warn("opendir failed"); + return -1; + } + + if (did_chdir && fchdir(cwd) == -1) + return -1; + + rv = 0; + + while ((de = readdir(dir)) != NULL) { + if (strcmp(de->d_name, ".") == 0) + continue; + if (strcmp(de->d_name, "..") == 0) + continue; + subdir = xasprintf("%s/%s", path, de->d_name); + rv = recursive_remove_internal(subdir, 1, cwd); + free(subdir); + } + + closedir(dir); + + safe_fchdir(cwd); + + rv |= long_remove(&path, missing_ok, &did_chdir); + + if (did_chdir && safe_fchdir(cwd) == -1 && rv == 0) + rv = -1; + + return rv; +} + +int +recursive_remove(const char *path, int missing_ok) +{ + int orig_cwd, rv; + + /* First try the easy case of regular file or empty directory. */ + if (remove(path) == 0 || (errno == ENOENT && missing_ok)) + return 0; + + /* + * If the path is too long, long_remove will use chdir to shorten it, + * so remember the current directory first. + */ + if ((orig_cwd = open(".", O_RDONLY)) == -1) + return -1; + + rv = recursive_remove_internal(path, missing_ok, orig_cwd); + + close(orig_cwd); + return rv; +} diff --git a/pkgtools/pkg_install/files/lib/str.c b/pkgtools/pkg_install/files/lib/str.c index dc76af31976..b190a1e8a77 100644 --- a/pkgtools/pkg_install/files/lib/str.c +++ b/pkgtools/pkg_install/files/lib/str.c @@ -1,4 +1,4 @@ -/* $NetBSD: str.c,v 1.25 2008/10/13 15:54:24 erh Exp $ */ +/* $NetBSD: str.c,v 1.26 2009/02/02 12:35:01 joerg Exp $ */ #if HAVE_CONFIG_H #include "config.h" @@ -7,13 +7,7 @@ #if HAVE_SYS_CDEFS_H #include <sys/cdefs.h> #endif -#ifndef lint -#if 0 -static const char *rcsid = "Id: str.c,v 1.5 1997/10/08 07:48:21 charnier Exp"; -#else -__RCSID("$NetBSD: str.c,v 1.25 2008/10/13 15:54:24 erh Exp $"); -#endif -#endif +__RCSID("$NetBSD: str.c,v 1.26 2009/02/02 12:35:01 joerg Exp $"); /* * FreeBSD install - a package for the installation and maintainance @@ -106,44 +100,3 @@ ispkgpattern(const char *pkg) { return strpbrk(pkg, "<>[]?*{") != NULL; } - -/* - * Strip off any .tgz, .tbz or .t[bg]z suffix from fname, - * and copy into buffer "buf", the suffix is stored in "sfx" - * if "sfx" is not NULL. If no suffix is found, "sfx" is set - * to an empty string. - */ -void -strip_txz(char *buf, char *sfx, const char *fname) -{ - static const char *const suffixes[] = { - ".tgz", ".tbz", ".t[bg]z", 0}; - const char *const *suffixp; - size_t len; - - len = strlen(fname); - assert(len < PKG_PATTERN_MAX); - - if (sfx) - sfx[0] = '\0'; - - for (suffixp = suffixes; *suffixp; suffixp++) { - size_t suffixlen = strlen(*suffixp); - - if (memcmp(&fname[len - suffixlen], *suffixp, suffixlen)) - continue; - - /* matched! */ - memcpy(buf, fname, len - suffixlen); - buf[len - suffixlen] = 0; - if (sfx) { - if (suffixlen >= PKG_SUFFIX_MAX) - errx(EXIT_FAILURE, "too long suffix '%s'", fname); - memcpy(sfx, *suffixp, suffixlen+1); - } - return; - } - - /* not found */ - memcpy(buf, fname, len+1); -} diff --git a/pkgtools/pkg_install/files/lib/var.c b/pkgtools/pkg_install/files/lib/var.c index bc902bd6702..af93f456557 100644 --- a/pkgtools/pkg_install/files/lib/var.c +++ b/pkgtools/pkg_install/files/lib/var.c @@ -1,4 +1,4 @@ -/* $NetBSD: var.c,v 1.6 2008/02/02 16:21:46 joerg Exp $ */ +/* $NetBSD: var.c,v 1.7 2009/02/02 12:35:01 joerg Exp $ */ /*- * Copyright (c) 2005, 2008 The NetBSD Foundation, Inc. @@ -39,9 +39,7 @@ #if HAVE_SYS_CDEFS_H #include <sys/cdefs.h> #endif -#ifndef lint -__RCSID("$NetBSD: var.c,v 1.6 2008/02/02 16:21:46 joerg Exp $"); -#endif +__RCSID("$NetBSD: var.c,v 1.7 2009/02/02 12:35:01 joerg Exp $"); #if HAVE_SYS_STAT_H #include <sys/stat.h> @@ -128,11 +126,11 @@ var_get(const char *fname, const char *variable) thislen = line+len - p; if (value) { - value = realloc(value, valuelen+thislen+2); + value = xrealloc(value, valuelen+thislen+2); value[valuelen++] = '\n'; } else { - value = malloc(thislen+1); + value = xmalloc(thislen+1); } sprintf(value+valuelen, "%.*s", (int)thislen, p); valuelen += thislen; @@ -171,11 +169,11 @@ var_get_memory(const char *buf, const char *variable) thislen = buf + len - data; if (value) { - value = realloc(value, valuelen+thislen+2); + value = xrealloc(value, valuelen+thislen+2); value[valuelen++] = '\n'; } else { - value = malloc(thislen+1); + value = xmalloc(thislen+1); } sprintf(value + valuelen, "%.*s", (int)thislen, data); valuelen += thislen; @@ -214,9 +212,8 @@ var_set(const char *fname, const char *variable, const char *value) return 0; /* Nothing to do */ } - tmpname = malloc(strlen(fname)+8); - sprintf(tmpname, "%s.XXXXXX", fname); - if ((fd=mkstemp(tmpname)) < 0) { + tmpname = xasprintf("%s.XXXXXX", fname); + if ((fd = mkstemp(tmpname)) < 0) { free(tmpname); if (fp != NULL) fclose(fp); diff --git a/pkgtools/pkg_install/files/lib/version.c b/pkgtools/pkg_install/files/lib/version.c index effebae1c95..f7cb6ec51ad 100644 --- a/pkgtools/pkg_install/files/lib/version.c +++ b/pkgtools/pkg_install/files/lib/version.c @@ -1,4 +1,4 @@ -/* $NetBSD: version.c,v 1.5 2008/05/08 15:30:17 wiz Exp $ */ +/* $NetBSD: version.c,v 1.6 2009/02/02 12:35:01 joerg Exp $ */ #if HAVE_CONFIG_H #include "config.h" @@ -7,9 +7,7 @@ #if HAVE_SYS_CDEFS_H #include <sys/cdefs.h> #endif -#ifndef lint -__RCSID("$NetBSD: version.c,v 1.5 2008/05/08 15:30:17 wiz Exp $"); -#endif +__RCSID("$NetBSD: version.c,v 1.6 2009/02/02 12:35:01 joerg Exp $"); /* * Copyright (c) 2001 Thomas Klausner. All rights reserved. diff --git a/pkgtools/pkg_install/files/lib/version.h b/pkgtools/pkg_install/files/lib/version.h index 47e7475c966..4ce786660d8 100644 --- a/pkgtools/pkg_install/files/lib/version.h +++ b/pkgtools/pkg_install/files/lib/version.h @@ -1,4 +1,4 @@ -/* $NetBSD: version.h,v 1.107 2008/10/13 15:54:24 erh Exp $ */ +/* $NetBSD: version.h,v 1.108 2009/02/02 12:35:01 joerg Exp $ */ /* * Copyright (c) 2001 Thomas Klausner. All rights reserved. @@ -27,6 +27,6 @@ #ifndef _INST_LIB_VERSION_H_ #define _INST_LIB_VERSION_H_ -#define PKGTOOLS_VERSION "20081013" +#define PKGTOOLS_VERSION "20090201" #endif /* _INST_LIB_VERSION_H_ */ diff --git a/pkgtools/pkg_install/files/lib/vulnerabilities-file.c b/pkgtools/pkg_install/files/lib/vulnerabilities-file.c index e0195a41130..aca293bb5f5 100644 --- a/pkgtools/pkg_install/files/lib/vulnerabilities-file.c +++ b/pkgtools/pkg_install/files/lib/vulnerabilities-file.c @@ -1,3 +1,5 @@ +/* $NetBSD: vulnerabilities-file.c,v 1.4 2009/02/02 12:35:01 joerg Exp $ */ + /*- * Copyright (c) 2008 Joerg Sonnenberger <joerg@NetBSD.org>. * All rights reserved. @@ -36,7 +38,7 @@ #if HAVE_SYS_CDEFS_H #include <sys/cdefs.h> #endif -__RCSID("$NetBSD: vulnerabilities-file.c,v 1.3 2008/03/31 16:52:13 tron Exp $"); +__RCSID("$NetBSD: vulnerabilities-file.c,v 1.4 2009/02/02 12:35:01 joerg Exp $"); #if HAVE_SYS_STAT_H #include <sys/stat.h> @@ -64,47 +66,52 @@ __RCSID("$NetBSD: vulnerabilities-file.c,v 1.3 2008/03/31 16:52:13 tron Exp $"); #include "lib.h" -/* - * We explicitely initialize this to NULL to stop Mac OS X Leopard's linker - * from turning this into a common symbol which causes a link failure. - */ -const char *gpg_cmd = NULL; +static const char pgp_msg_start[] = "-----BEGIN PGP SIGNED MESSAGE-----\n"; +static const char pgp_msg_end[] = "-----BEGIN PGP SIGNATURE-----\n"; +static const char pkcs7_begin[] = "-----BEGIN PKCS7-----\n"; +static const char pkcs7_end[] = "-----END PKCS7-----\n"; static void -verify_signature(const char *input, size_t input_len) +verify_signature_pkcs7(const char *input) { - pid_t child; - int fd[2], status; - - if (gpg_cmd == NULL) - errx(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); +#ifdef HAVE_SSL + const char *begin_pkgvul, *end_pkgvul, *begin_sig, *end_sig; + + if (strncmp(input, pgp_msg_start, strlen(pgp_msg_start)) == 0) { + begin_pkgvul = input + strlen(pgp_msg_start); + if ((end_pkgvul = strstr(begin_pkgvul, pgp_msg_end)) == NULL) + errx(EXIT_FAILURE, "Invalid PGP signature"); + if ((begin_sig = strstr(end_pkgvul, pkcs7_begin)) == NULL) + errx(EXIT_FAILURE, "No PKCS7 signature"); + } else { + begin_pkgvul = input; + if ((begin_sig = strstr(begin_pkgvul, pkcs7_begin)) == NULL) + errx(EXIT_FAILURE, "No PKCS7 signature"); + end_pkgvul = begin_sig; } - 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"); + if ((end_sig = strstr(begin_sig, pkcs7_end)) == NULL) + errx(EXIT_FAILURE, "Invalid PKCS7 signature"); + end_sig += strlen(pkcs7_end); + + if (easy_pkcs7_verify(begin_pkgvul, end_pkgvul - begin_pkgvul, + begin_sig, end_sig - begin_sig, certs_pkg_vulnerabilities, 0)) + errx(EXIT_FAILURE, "Unable to verify PKCS7 signature"); +#else + errx(EXIT_FAILURE, "OpenSSL support is not compiled in"); +#endif +} + +static void +verify_signature(const char *input, size_t input_len) +{ + if (gpg_cmd == NULL && certs_pkg_vulnerabilities == NULL) + errx(EXIT_FAILURE, + "At least GPG or CERTIFICATE_ANCHOR_PKGVULN " + "must be configured"); + if (gpg_cmd != NULL) + inline_gpg_verify(input, input_len, gpg_keyring_pkgvuln); + if (certs_pkg_vulnerabilities != NULL) + verify_signature_pkcs7(input); } static void * @@ -128,9 +135,27 @@ static const char * sha512_hash_finish(void *ctx) { static char hash[SHA512_DIGEST_STRING_LENGTH]; + unsigned char digest[SHA512_DIGEST_LENGTH]; SHA512_CTX *hash_ctx = ctx; + int i; + + SHA512_Final(digest, hash_ctx); + for (i = 0; i < SHA512_DIGEST_LENGTH; ++i) { + unsigned char c; - SHA512_End(hash_ctx, hash); + c = digest[i] / 16; + if (c < 10) + hash[2 * i] = '0' + c; + else + hash[2 * i] = 'a' - 10 + c; + + c = digest[i] % 16; + if (c < 10) + hash[2 * i + 1] = '0' + c; + else + hash[2 * i + 1] = 'a' - 10 + c; + } + hash[2 * i] = '\0'; return hash; } @@ -183,6 +208,7 @@ verify_hash(const char *input, const char *hash_line) const struct hash_algorithm *hash; void *ctx; const char *last_start, *next, *hash_value; + int in_pgp_msg; for (hash = hash_algorithms; hash->name != NULL; ++hash) { if (strncmp(hash_line, hash->name, hash->name_len)) @@ -211,19 +237,27 @@ verify_hash(const char *input, const char *hash_line) errx(EXIT_FAILURE, "Invalid #CHECKSUM"); ctx = (*hash->init)(); + if (strncmp(input, pgp_msg_start, strlen(pgp_msg_start)) == 0) { + input += strlen(pgp_msg_start); + in_pgp_msg = 1; + } else { + in_pgp_msg = 0; + } for (last_start = input; *input != '\0'; input = next) { if ((next = strchr(input, '\n')) == NULL) errx(EXIT_FAILURE, "Missing newline in pkg-vulnerabilities"); ++next; + if (in_pgp_msg && strncmp(input, pgp_msg_end, strlen(pgp_msg_end)) == 0) + break; + if (!in_pgp_msg && strncmp(input, pkcs7_begin, strlen(pkcs7_begin)) == 0) + break; 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); @@ -280,27 +314,21 @@ add_vulnerability(struct pkg_vulnerabilities *pv, size_t *allocated, const char *allocated *= 2; else errx(EXIT_FAILURE, "Too many vulnerabilities"); - pv->vulnerability = realloc(pv->vulnerability, + pv->vulnerability = xrealloc(pv->vulnerability, sizeof(char *) * *allocated); - pv->classification = realloc(pv->classification, + pv->classification = xrealloc(pv->classification, sizeof(char *) * *allocated); - pv->advisory = realloc(pv->advisory, + pv->advisory = xrealloc(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"); + pv->vulnerability[pv->entries] = xmalloc(len_pattern + 1); 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"); + pv->classification[pv->entries] = xmalloc(len_class + 1); 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"); + pv->advisory[pv->entries] = xmalloc(len_url + 1); memcpy(pv->advisory[pv->entries], start_url, len_url); pv->advisory[pv->entries][len_url] = '\0'; @@ -334,8 +362,7 @@ read_pkg_vulnerabilities(const char *path, int ignore_missing, int check_sum) 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"); + input = xmalloc(input_len + 1); if ((bytes_read = read(fd, input, input_len)) == -1) err(1, "Failed to read input"); if (bytes_read != st.st_size) @@ -361,10 +388,9 @@ parse_pkg_vulnerabilities(const char *input, size_t input_len, int check_sum) char *end; const char *iter, *next; size_t allocated_vulns; + int in_pgp_msg; - pv = malloc(sizeof(*pv)); - if (pv == NULL) - err(EXIT_FAILURE, "malloc failed"); + pv = xmalloc(sizeof(*pv)); allocated_vulns = pv->entries = 0; pv->vulnerability = NULL; @@ -377,14 +403,20 @@ parse_pkg_vulnerabilities(const char *input, size_t input_len, int check_sum) if (check_sum) verify_signature(input, input_len); - for (iter = input; *iter; iter = next) { + if (strncmp(input, pgp_msg_start, strlen(pgp_msg_start)) == 0) { + iter = input + strlen(pgp_msg_start); + in_pgp_msg = 1; + } else { + iter = input; + in_pgp_msg = 0; + } + + for (; *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) @@ -430,7 +462,9 @@ parse_pkg_vulnerabilities(const char *input, size_t input_len, int check_sum) ++next; if (*iter == '\0' || *iter == '\n') continue; - if (strncmp(iter, "Version:", 5) == 0) + if (in_pgp_msg && strncmp(iter, pgp_msg_end, strlen(pgp_msg_end)) == 0) + break; + if (!in_pgp_msg && strncmp(iter, pkcs7_begin, strlen(pkcs7_begin)) == 0) break; if (*iter == '#' && (iter[1] == '\0' || iter[1] == '\n' || isspace((unsigned char)iter[1]))) @@ -456,15 +490,12 @@ parse_pkg_vulnerabilities(const char *input, size_t input_len, int check_sum) } if (pv->entries != allocated_vulns) { - pv->vulnerability = realloc(pv->vulnerability, + pv->vulnerability = xrealloc(pv->vulnerability, sizeof(char *) * pv->entries); - pv->classification = realloc(pv->classification, + pv->classification = xrealloc(pv->classification, sizeof(char *) * pv->entries); - pv->advisory = realloc(pv->advisory, + pv->advisory = xrealloc(pv->advisory, sizeof(char *) * pv->entries); - if (pv->vulnerability == NULL || - pv->classification == NULL || pv->advisory == NULL) - errx(EXIT_FAILURE, "realloc failed"); } return pv; @@ -485,3 +516,73 @@ free_pkg_vulnerabilities(struct pkg_vulnerabilities *pv) free(pv->advisory); free(pv); } + +static int +check_ignored_entry(struct pkg_vulnerabilities *pv, size_t i) +{ + const char *iter, *next; + size_t entry_len, url_len; + + if (ignore_advisories == NULL) + return 0; + + url_len = strlen(pv->advisory[i]); + + for (iter = ignore_advisories; *iter; iter = next) { + if ((next = strchr(iter, '\n')) == NULL) { + entry_len = strlen(iter); + next = iter + entry_len; + } else { + entry_len = next - iter; + ++next; + } + if (url_len != entry_len) + continue; + if (strncmp(pv->advisory[i], iter, entry_len) == 0) + return 1; + } + return 0; +} + +int +audit_package(struct pkg_vulnerabilities *pv, const char *pkgname, + const char *limit_vul_types, int check_eol, int output_type) +{ + FILE *output = output_type == 1 ? stdout : stderr; + size_t i; + int retval; + + retval = 0; + + for (i = 0; i < pv->entries; ++i) { + if (check_ignored_entry(pv, i)) + continue; + if (limit_vul_types != NULL && + strcmp(limit_vul_types, pv->classification[i])) + continue; + if (!pkg_match(pv->vulnerability[i], pkgname)) + continue; + if (strcmp("eol", pv->classification[i]) == 0) { + if (!check_eol) + continue; + if (output_type == 0) { + puts(pkgname); + continue; + } + fprintf(output, + "Package %s has reached end-of-life (eol), " + "see %s/eol-packages\n", pkgname, + tnf_vulnerability_base); + continue; + } + retval = 1; + if (output_type == 0) { + puts(pkgname); + } else { + fprintf(output, + "Package %s has a %s vulnerability, see %s\n", + pkgname, pv->classification[i], pv->advisory[i]); + } + } + return retval; +} diff --git a/pkgtools/pkg_install/files/lib/xwrapper.c b/pkgtools/pkg_install/files/lib/xwrapper.c new file mode 100644 index 00000000000..75f5fa3108f --- /dev/null +++ b/pkgtools/pkg_install/files/lib/xwrapper.c @@ -0,0 +1,102 @@ +/* $NetBSD: xwrapper.c,v 1.2 2009/02/02 12:35:01 joerg Exp $ */ + +/*- + * 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: xwrapper.c,v 1.2 2009/02/02 12:35:01 joerg Exp $"); + +#if HAVE_ERR_H +#include <err.h> +#endif +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "lib.h" + +char * +xasprintf(const char *fmt, ...) +{ + va_list ap; + char *buf; + + va_start(ap, fmt); + if (vasprintf(&buf, fmt, ap) == -1) + err(1, "asprintf failed"); + va_end(ap); + return buf; +} + +void * +xmalloc(size_t len) +{ + void *ptr; + + if ((ptr = malloc(len)) == NULL) + err(1, "malloc failed"); + return ptr; +} + +void * +xcalloc(size_t len, size_t n) +{ + void *ptr; + + if ((ptr = calloc(len, n)) == NULL) + err(1, "calloc failed"); + return ptr; +} + +void * +xrealloc(void *buf, size_t len) +{ + void *ptr; + + if ((ptr = realloc(buf, len)) == NULL) + err(1, "realloc failed"); + return ptr; +} + +char * +xstrdup(const char *str) +{ + char *buf; + + if ((buf = strdup(str)) == NULL) + err(1, "strdup failed"); + return buf; +} |