summaryrefslogtreecommitdiff
path: root/pkgtools/pkg_install/files/lib
diff options
context:
space:
mode:
authorjoerg <joerg@pkgsrc.org>2009-02-02 12:34:59 +0000
committerjoerg <joerg@pkgsrc.org>2009-02-02 12:34:59 +0000
commitd7cc6db11bfefd0006364a122a40572d9eb9b739 (patch)
tree4c0fb6728ab9db1b5dc2233bb02e4ef34022a604 /pkgtools/pkg_install/files/lib
parentea71974691a75ab2e2b9c62a6fb9dcc136b266de (diff)
downloadpkgsrc-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')
-rw-r--r--pkgtools/pkg_install/files/lib/Makefile.in24
-rw-r--r--pkgtools/pkg_install/files/lib/automatic.c6
-rw-r--r--pkgtools/pkg_install/files/lib/config.h.in6
-rw-r--r--pkgtools/pkg_install/files/lib/conflicts.c61
-rw-r--r--pkgtools/pkg_install/files/lib/decompress.c22
-rw-r--r--pkgtools/pkg_install/files/lib/dewey.c2
-rw-r--r--pkgtools/pkg_install/files/lib/fexec.c13
-rw-r--r--pkgtools/pkg_install/files/lib/file.c547
-rw-r--r--pkgtools/pkg_install/files/lib/ftpio.c1252
-rw-r--r--pkgtools/pkg_install/files/lib/global.c10
-rw-r--r--pkgtools/pkg_install/files/lib/gpgsig.c252
-rw-r--r--pkgtools/pkg_install/files/lib/iterate.c18
-rw-r--r--pkgtools/pkg_install/files/lib/lib.h177
-rw-r--r--pkgtools/pkg_install/files/lib/lpkg.c8
-rw-r--r--pkgtools/pkg_install/files/lib/opattern.c37
-rw-r--r--pkgtools/pkg_install/files/lib/parse-config.c139
-rw-r--r--pkgtools/pkg_install/files/lib/path.c27
-rw-r--r--pkgtools/pkg_install/files/lib/pen.c206
-rw-r--r--pkgtools/pkg_install/files/lib/pexec.c110
-rw-r--r--pkgtools/pkg_install/files/lib/pkcs7.c326
-rw-r--r--pkgtools/pkg_install/files/lib/pkg_install.conf.5158
-rw-r--r--pkgtools/pkg_install/files/lib/pkg_install.conf.cat5117
-rw-r--r--pkgtools/pkg_install/files/lib/pkg_io.c204
-rw-r--r--pkgtools/pkg_install/files/lib/pkg_signature.c686
-rw-r--r--pkgtools/pkg_install/files/lib/pkgdb.c13
-rw-r--r--pkgtools/pkg_install/files/lib/plist.c92
-rw-r--r--pkgtools/pkg_install/files/lib/remove.c196
-rw-r--r--pkgtools/pkg_install/files/lib/str.c51
-rw-r--r--pkgtools/pkg_install/files/lib/var.c19
-rw-r--r--pkgtools/pkg_install/files/lib/version.c6
-rw-r--r--pkgtools/pkg_install/files/lib/version.h4
-rw-r--r--pkgtools/pkg_install/files/lib/vulnerabilities-file.c239
-rw-r--r--pkgtools/pkg_install/files/lib/xwrapper.c102
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;
+}