aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--usr.sbin/pkg/config.c158
-rw-r--r--usr.sbin/pkg/config.h24
-rw-r--r--usr.sbin/pkg/pkg.c149
3 files changed, 216 insertions, 115 deletions
diff --git a/usr.sbin/pkg/config.c b/usr.sbin/pkg/config.c
index d8e15d44da3d..23bccb7eb96e 100644
--- a/usr.sbin/pkg/config.c
+++ b/usr.sbin/pkg/config.c
@@ -59,6 +59,8 @@ struct config_entry {
bool main_only; /* Only set in pkg.conf. */
};
+static struct repositories repositories = STAILQ_HEAD_INITIALIZER(repositories);
+
static struct config_entry c[] = {
[PACKAGESITE] = {
PKG_CONFIG_STRING,
@@ -211,7 +213,7 @@ boolstr_to_bool(const char *str)
}
static void
-config_parse(const ucl_object_t *obj, pkg_conf_file_t conftype)
+config_parse(const ucl_object_t *obj)
{
FILE *buffp;
char *buf = NULL;
@@ -238,29 +240,9 @@ config_parse(const ucl_object_t *obj, pkg_conf_file_t conftype)
memset(buf, 0, bufsz);
rewind(buffp);
- if (conftype == CONFFILE_PKG) {
for (j = 0; j < strlen(key); ++j)
fputc(toupper(key[j]), buffp);
fflush(buffp);
- } else if (conftype == CONFFILE_REPO) {
- if (strcasecmp(key, "url") == 0)
- fputs("PACKAGESITE", buffp);
- else if (strcasecmp(key, "mirror_type") == 0)
- fputs("MIRROR_TYPE", buffp);
- else if (strcasecmp(key, "signature_type") == 0)
- fputs("SIGNATURE_TYPE", buffp);
- else if (strcasecmp(key, "fingerprints") == 0)
- fputs("FINGERPRINTS", buffp);
- else if (strcasecmp(key, "pubkey") == 0)
- fputs("PUBKEY", buffp);
- else if (strcasecmp(key, "enabled") == 0) {
- if ((cur->type != UCL_BOOLEAN) ||
- !ucl_object_toboolean(cur))
- goto cleanup;
- } else
- continue;
- fflush(buffp);
- }
for (i = 0; i < CONFIG_SIZE; i++) {
if (strcmp(buf, c[i].key) == 0)
@@ -324,7 +306,7 @@ config_parse(const ucl_object_t *obj, pkg_conf_file_t conftype)
if (c[i].envset)
continue;
/* Prevent overriding ABI, ASSUME_ALWAYS_YES, etc. */
- if (conftype != CONFFILE_PKG && c[i].main_only == true)
+ if (c[i].main_only == true)
continue;
switch (c[i].type) {
case PKG_CONFIG_LIST:
@@ -336,12 +318,91 @@ config_parse(const ucl_object_t *obj, pkg_conf_file_t conftype)
}
}
-cleanup:
free(temp_config);
fclose(buffp);
free(buf);
}
+
+static void
+parse_mirror_type(struct repository *r, const char *mt)
+{
+ if (strcasecmp(mt, "srv") == 0)
+ r->mirror_type = MIRROR_SRV;
+ r->mirror_type = MIRROR_NONE;
+}
+
+static bool
+parse_signature_type(struct repository *repo, const char *st)
+{
+ if (strcasecmp(st, "FINGERPRINTS") == 0)
+ repo->signature_type = SIGNATURE_FINGERPRINT;
+ else if (strcasecmp(st, "PUBKEY") == 0)
+ repo->signature_type = SIGNATURE_PUBKEY;
+ else if (strcasecmp(st, "NONE") == 0)
+ repo->signature_type = SIGNATURE_NONE;
+ else {
+ warnx("Signature type %s is not supported for bootstraping,"
+ " ignoring repository %s", st, repo->name);
+ free(repo->url);
+ free(repo->name);
+ free(repo->fingerprints);
+ free(repo->pubkey);
+ free(repo);
+ return false;
+ }
+ return (true);
+}
+
+static void
+parse_repo(const ucl_object_t *o)
+{
+ const ucl_object_t *cur;
+ const char *key;
+ ucl_object_iter_t it = NULL;
+
+ struct repository *repo = calloc(1, sizeof(struct repository));
+ if (repo == NULL)
+ err(EXIT_FAILURE, "calloc");
+
+ repo->name = strdup(ucl_object_key(o));
+ if (repo->name == NULL)
+ err(EXIT_FAILURE, "strdup");
+ while ((cur = ucl_iterate_object(o, &it, true))) {
+ key = ucl_object_key(cur);
+ if (key == NULL)
+ continue;
+ if (strcasecmp(key, "url") == 0) {
+ repo->url = strdup(ucl_object_tostring(cur));
+ if (repo->url == NULL)
+ err(EXIT_FAILURE, "strdup");
+ } else if (strcasecmp(key, "mirror_type") == 0) {
+ parse_mirror_type(repo, ucl_object_tostring(cur));
+ } else if (strcasecmp(key, "signature_type") == 0) {
+ if (!parse_signature_type(repo, ucl_object_tostring(cur)))
+ return;
+ } else if (strcasecmp(key, "fingerprints") == 0) {
+ repo->fingerprints = strdup(ucl_object_tostring(cur));
+ if (repo->fingerprints == NULL)
+ err(EXIT_FAILURE, "strdup");
+ } else if (strcasecmp(key, "pubkey") == 0) {
+ repo->pubkey = strdup(ucl_object_tostring(cur));
+ if (repo->pubkey == NULL)
+ err(EXIT_FAILURE, "strdup");
+ } else if (strcasecmp(key, "enabled") == 0) {
+ if ((cur->type != UCL_BOOLEAN) ||
+ !ucl_object_toboolean(cur)) {
+ free(repo->url);
+ free(repo->name);
+ free(repo);
+ return;
+ }
+ }
+ }
+ STAILQ_INSERT_TAIL(&repositories, repo, next);
+ return;
+}
+
/*-
* Parse new repo style configs in style:
* Name:
@@ -367,8 +428,7 @@ parse_repo_file(ucl_object_t *obj, const char *requested_repo)
if (requested_repo != NULL && strcmp(requested_repo, key) != 0)
continue;
-
- config_parse(cur, CONFFILE_REPO);
+ parse_repo(cur);
}
}
@@ -379,8 +439,12 @@ read_conf_file(const char *confpath, const char *requested_repo,
{
struct ucl_parser *p;
ucl_object_t *obj = NULL;
+ const char *abi = pkg_get_myabi();
+ if (abi == NULL)
+ errx(EXIT_FAILURE, "Fail do determine ABI");
p = ucl_parser_new(0);
+ ucl_parser_register_variable(p, "ABI", abi);
if (!ucl_parser_add_file(p, confpath)) {
if (errno != ENOENT)
@@ -397,7 +461,7 @@ read_conf_file(const char *confpath, const char *requested_repo,
"configuration file %s", confpath);
else {
if (conftype == CONFFILE_PKG)
- config_parse(obj, conftype);
+ config_parse(obj);
else if (conftype == CONFFILE_REPO)
parse_repo_file(obj, requested_repo);
}
@@ -408,7 +472,7 @@ read_conf_file(const char *confpath, const char *requested_repo,
return (0);
}
-static int
+static void
load_repositories(const char *repodir, const char *requested_repo)
{
struct dirent *ent;
@@ -416,12 +480,9 @@ load_repositories(const char *repodir, const char *requested_repo)
char *p;
size_t n;
char path[MAXPATHLEN];
- int ret;
-
- ret = 0;
if ((d = opendir(repodir)) == NULL)
- return (1);
+ return;
while ((ent = readdir(d))) {
/* Trim out 'repos'. */
@@ -437,7 +498,6 @@ load_repositories(const char *repodir, const char *requested_repo)
continue;
if (read_conf_file(path, requested_repo,
CONFFILE_REPO)) {
- ret = 1;
goto cleanup;
}
}
@@ -445,8 +505,6 @@ load_repositories(const char *repodir, const char *requested_repo)
cleanup:
closedir(d);
-
- return (ret);
}
int
@@ -508,8 +566,7 @@ config_init(const char *requested_repo)
}
STAILQ_FOREACH(cv, c[REPOS_DIR].list, next)
- if (load_repositories(cv->value, requested_repo))
- goto finalize;
+ load_repositories(cv->value, requested_repo);
finalize:
if (c[ABI].val == NULL && c[ABI].value == NULL) {
@@ -520,8 +577,6 @@ finalize:
c[ABI].val = abi;
}
- subst_packagesite(c[ABI].value != NULL ? c[ABI].value : c[ABI].val);
-
return (0);
}
@@ -560,6 +615,33 @@ config_bool(pkg_config_key k, bool *val)
return (0);
}
+struct repositories *
+config_get_repositories(void)
+{
+ if (STAILQ_EMPTY(&repositories)) {
+ /* Fall back to PACKAGESITE - deprecated - */
+ struct repository *r = calloc(1, sizeof(r));
+ if (r == NULL)
+ err(EXIT_FAILURE, "calloc");
+ r->name = strdup("fallback");
+ if (r->name == NULL)
+ err(EXIT_FAILURE, "strdup");
+ subst_packagesite(c[ABI].value != NULL ? c[ABI].value : c[ABI].val);
+ r->url = c[PACKAGESITE].value;
+ if (c[SIGNATURE_TYPE].value != NULL)
+ if (!parse_signature_type(r, c[SIGNATURE_TYPE].value))
+ exit(EXIT_FAILURE);
+ if (c[MIRROR_TYPE].value != NULL)
+ parse_mirror_type(r, c[MIRROR_TYPE].value);
+ if (c[PUBKEY].value != NULL)
+ r->pubkey = c[PUBKEY].value;
+ if (c[FINGERPRINTS].value != NULL)
+ r->fingerprints = c[FINGERPRINTS].value;
+ STAILQ_INSERT_TAIL(&repositories, r, next);
+ }
+ return (&repositories);
+}
+
void
config_finish(void) {
int i;
diff --git a/usr.sbin/pkg/config.h b/usr.sbin/pkg/config.h
index 21d115e41db2..26f3ff79541b 100644
--- a/usr.sbin/pkg/config.h
+++ b/usr.sbin/pkg/config.h
@@ -30,6 +30,7 @@
#define _PKG_CONFIG_H
#include <paths.h>
+#include <sys/queue.h>
#define URL_SCHEME_PREFIX "pkg+"
@@ -58,9 +59,32 @@ typedef enum {
CONFFILE_REPO,
} pkg_conf_file_t;
+typedef enum {
+ SIGNATURE_NONE = 0,
+ SIGNATURE_FINGERPRINT,
+ SIGNATURE_PUBKEY,
+} signature_t;
+
+typedef enum {
+ MIRROR_NONE = 0,
+ MIRROR_SRV,
+} mirror_t;
+
+struct repository {
+ char *name;
+ char *url;
+ mirror_t mirror_type;
+ signature_t signature_type;
+ char *fingerprints;
+ char *pubkey;
+ STAILQ_ENTRY(repository) next;
+};
+STAILQ_HEAD(repositories, repository);
+
int config_init(const char *);
void config_finish(void);
int config_string(pkg_config_key, const char **);
int config_bool(pkg_config_key, bool *);
+struct repositories *config_get_repositories(void);
#endif
diff --git a/usr.sbin/pkg/pkg.c b/usr.sbin/pkg/pkg.c
index 54884dbe0b23..0b46d2831e9e 100644
--- a/usr.sbin/pkg/pkg.c
+++ b/usr.sbin/pkg/pkg.c
@@ -255,7 +255,7 @@ install_pkg_static(const char *path, const char *pkgpath, bool force)
}
static int
-fetch_to_fd(const char *url, char *path, const char *fetchOpts)
+fetch_to_fd(struct repository *repo, const char *url, char *path, const char *fetchOpts)
{
struct url *u;
struct dns_srvinfo *mirrors, *current;
@@ -267,18 +267,11 @@ fetch_to_fd(const char *url, char *path, const char *fetchOpts)
ssize_t r;
char buf[10240];
char zone[MAXHOSTNAMELEN + 13];
- static const char *mirror_type = NULL;
max_retry = 3;
current = mirrors = NULL;
remote = NULL;
- if (mirror_type == NULL && config_string(MIRROR_TYPE, &mirror_type)
- != 0) {
- warnx("No MIRROR_TYPE defined");
- return (-1);
- }
-
if ((fd = mkstemp(path)) == -1) {
warn("mkstemp()");
return (-1);
@@ -294,7 +287,7 @@ fetch_to_fd(const char *url, char *path, const char *fetchOpts)
while (remote == NULL) {
if (retry == max_retry) {
if (strcmp(u->scheme, "file") != 0 &&
- strcasecmp(mirror_type, "srv") == 0) {
+ repo->mirror_type == MIRROR_SRV) {
snprintf(zone, sizeof(zone),
"_%s._tcp.%s", u->scheme, u->host);
mirrors = dns_getsrvinfo(zone);
@@ -653,23 +646,31 @@ parse_cert(int fd) {
}
static bool
-verify_pubsignature(int fd_pkg, int fd_sig)
+verify_pubsignature(int fd_pkg, int fd_sig, struct repository *r)
{
struct pubkey *pk;
- const char *pubkey;
char *data;
struct pkgsign_ctx *sctx;
size_t datasz;
bool ret;
+ const char *pubkey;
pk = NULL;
- pubkey = NULL;
sctx = NULL;
data = NULL;
ret = false;
- if (config_string(PUBKEY, &pubkey) != 0) {
- warnx("No CONFIG_PUBKEY defined");
- goto cleanup;
+
+ if (r != NULL) {
+ if (r->pubkey == NULL) {
+ warnx("No CONFIG_PUBKEY defined for %s", r->name);
+ goto cleanup;
+ }
+ pubkey = r->pubkey;
+ } else {
+ if (config_string(PUBKEY, &pubkey) != 0) {
+ warnx("No CONFIG_PUBKEY defined for %s", r->name);
+ goto cleanup;
+ }
}
if ((pk = read_pubkey(fd_sig)) == NULL) {
@@ -703,8 +704,8 @@ verify_pubsignature(int fd_pkg, int fd_sig)
}
/* Verify the signature. */
- printf("Verifying signature with public key %s... ", pubkey);
- if (pkgsign_verify_data(sctx, data, datasz, pubkey, NULL, 0, pk->sig,
+ printf("Verifying signature with public key %s.a.. ", r->pubkey);
+ if (pkgsign_verify_data(sctx, data, datasz, r->pubkey, NULL, 0, pk->sig,
pk->siglen) == false) {
fprintf(stderr, "Signature is not valid\n");
goto cleanup;
@@ -723,7 +724,7 @@ cleanup:
}
static bool
-verify_signature(int fd_pkg, int fd_sig)
+verify_signature(int fd_pkg, int fd_sig, struct repository *r)
{
struct fingerprint_list *trusted, *revoked;
struct fingerprint *fingerprint;
@@ -742,9 +743,17 @@ verify_signature(int fd_pkg, int fd_sig)
ret = false;
/* Read and parse fingerprints. */
- if (config_string(FINGERPRINTS, &fingerprints) != 0) {
- warnx("No CONFIG_FINGERPRINTS defined");
- goto cleanup;
+ if (r != NULL) {
+ if (r->fingerprints == NULL) {
+ warnx("No FINGERPRINTS defined for %s", r->name);
+ goto cleanup;
+ }
+ fingerprints = r->fingerprints;
+ } else {
+ if (config_string(FINGERPRINTS, &fingerprints) != 0) {
+ warnx("No FINGERPRINTS defined");
+ goto cleanup;
+ }
}
snprintf(path, MAXPATHLEN, "%s/trusted", fingerprints);
@@ -833,7 +842,7 @@ cleanup:
}
static int
-bootstrap_pkg(bool force, const char *fetchOpts)
+bootstrap_pkg(bool force, const char *fetchOpts, struct repository *repo)
{
int fd_pkg, fd_sig;
int ret;
@@ -841,28 +850,18 @@ bootstrap_pkg(bool force, const char *fetchOpts)
char tmppkg[MAXPATHLEN];
char tmpsig[MAXPATHLEN];
const char *packagesite;
- const char *signature_type;
char pkgstatic[MAXPATHLEN];
const char *bootstrap_name;
fd_sig = -1;
ret = -1;
- if (config_string(PACKAGESITE, &packagesite) != 0) {
- warnx("No PACKAGESITE defined");
- return (-1);
- }
-
- if (config_string(SIGNATURE_TYPE, &signature_type) != 0) {
- warnx("Error looking up SIGNATURE_TYPE");
- return (-1);
- }
-
- printf("Bootstrapping pkg from %s, please wait...\n", packagesite);
+ printf("Bootstrapping pkg from %s, please wait...\n", repo->url);
/* Support pkg+http:// for PACKAGESITE which is the new format
in 1.2 to avoid confusion on why http://pkg.FreeBSD.org has
no A record. */
+ packagesite = repo->url;
if (strncmp(URL_SCHEME_PREFIX, packagesite,
strlen(URL_SCHEME_PREFIX)) == 0)
packagesite += strlen(URL_SCHEME_PREFIX);
@@ -873,53 +872,44 @@ bootstrap_pkg(bool force, const char *fetchOpts)
snprintf(tmppkg, MAXPATHLEN, "%s/%s.XXXXXX",
getenv("TMPDIR") ? getenv("TMPDIR") : _PATH_TMP,
bootstrap_name);
- if ((fd_pkg = fetch_to_fd(url, tmppkg, fetchOpts)) != -1)
+ if ((fd_pkg = fetch_to_fd(repo, url, tmppkg, fetchOpts)) != -1)
break;
bootstrap_name = NULL;
}
if (bootstrap_name == NULL)
goto fetchfail;
- if (signature_type != NULL &&
- strcasecmp(signature_type, "NONE") != 0) {
- if (strcasecmp(signature_type, "FINGERPRINTS") == 0) {
-
- snprintf(tmpsig, MAXPATHLEN, "%s/%s.sig.XXXXXX",
- getenv("TMPDIR") ? getenv("TMPDIR") : _PATH_TMP,
- bootstrap_name);
- snprintf(url, MAXPATHLEN, "%s/Latest/%s.sig",
- packagesite, bootstrap_name);
-
- if ((fd_sig = fetch_to_fd(url, tmpsig, fetchOpts)) == -1) {
- fprintf(stderr, "Signature for pkg not "
- "available.\n");
- goto fetchfail;
- }
+ if (repo->signature_type == SIGNATURE_FINGERPRINT) {
+ snprintf(tmpsig, MAXPATHLEN, "%s/%s.sig.XXXXXX",
+ getenv("TMPDIR") ? getenv("TMPDIR") : _PATH_TMP,
+ bootstrap_name);
+ snprintf(url, MAXPATHLEN, "%s/Latest/%s.sig",
+ packagesite, bootstrap_name);
- if (verify_signature(fd_pkg, fd_sig) == false)
- goto cleanup;
- } else if (strcasecmp(signature_type, "PUBKEY") == 0) {
+ if ((fd_sig = fetch_to_fd(repo, url, tmpsig, fetchOpts)) == -1) {
+ fprintf(stderr, "Signature for pkg not "
+ "available.\n");
+ goto fetchfail;
+ }
- snprintf(tmpsig, MAXPATHLEN,
- "%s/%s.pubkeysig.XXXXXX",
- getenv("TMPDIR") ? getenv("TMPDIR") : _PATH_TMP,
- bootstrap_name);
- snprintf(url, MAXPATHLEN, "%s/Latest/%s.pubkeysig",
- packagesite, bootstrap_name);
+ if (verify_signature(fd_pkg, fd_sig, repo) == false)
+ goto cleanup;
+ } else if (repo->signature_type == SIGNATURE_PUBKEY) {
+ snprintf(tmpsig, MAXPATHLEN,
+ "%s/%s.pubkeysig.XXXXXX",
+ getenv("TMPDIR") ? getenv("TMPDIR") : _PATH_TMP,
+ bootstrap_name);
+ snprintf(url, MAXPATHLEN, "%s/Latest/%s.pubkeysig",
+ repo->url, bootstrap_name);
- if ((fd_sig = fetch_to_fd(url, tmpsig, fetchOpts)) == -1) {
- fprintf(stderr, "Signature for pkg not "
- "available.\n");
- goto fetchfail;
- }
+ if ((fd_sig = fetch_to_fd(repo, url, tmpsig, fetchOpts)) == -1) {
+ fprintf(stderr, "Signature for pkg not "
+ "available.\n");
+ goto fetchfail;
+ }
- if (verify_pubsignature(fd_pkg, fd_sig) == false)
- goto cleanup;
- } else {
- warnx("Signature type %s is not supported for "
- "bootstrapping.", signature_type);
+ if (verify_pubsignature(fd_pkg, fd_sig, repo) == false)
goto cleanup;
- }
}
if ((ret = extract_pkg_static(fd_pkg, pkgstatic, MAXPATHLEN)) == 0)
@@ -929,18 +919,15 @@ bootstrap_pkg(bool force, const char *fetchOpts)
fetchfail:
for (int j = 0; bootstrap_names[j] != NULL; j++) {
- warnx("Attempted to fetch %s/Latest/%s", packagesite,
+ warnx("Attempted to fetch %s/Latest/%s", repo->url,
bootstrap_names[j]);
}
warnx("Error: %s", fetchLastErrString);
if (fetchLastErrCode == FETCH_RESOLV) {
fprintf(stderr, "Address resolution failed for %s.\n", packagesite);
- fprintf(stderr, "Consider changing PACKAGESITE.\n");
} else {
fprintf(stderr, "A pre-built version of pkg could not be found for "
"your system.\n");
- fprintf(stderr, "Consider changing PACKAGESITE or installing it from "
- "ports: 'ports-mgmt/pkg'.\n");
}
cleanup:
@@ -1024,7 +1011,7 @@ bootstrap_pkg_local(const char *pkgpath, bool force)
goto cleanup;
}
- if (verify_signature(fd_pkg, fd_sig) == false)
+ if (verify_signature(fd_pkg, fd_sig, NULL) == false)
goto cleanup;
} else if (strcasecmp(signature_type, "PUBKEY") == 0) {
@@ -1037,7 +1024,7 @@ bootstrap_pkg_local(const char *pkgpath, bool force)
goto cleanup;
}
- if (verify_pubsignature(fd_pkg, fd_sig) == false)
+ if (verify_pubsignature(fd_pkg, fd_sig, NULL) == false)
goto cleanup;
} else {
@@ -1105,6 +1092,7 @@ main(int argc, char *argv[])
signed char ch;
const char *fetchOpts;
char *command;
+ struct repositories *repositories;
activation_test = false;
add_pkg = false;
@@ -1232,6 +1220,8 @@ main(int argc, char *argv[])
fetchDebug = 1;
if ((bootstrap_only && force) || access(pkgpath, X_OK) == -1) {
+ struct repository *repo;
+ int ret = 0;
/*
* To allow 'pkg -N' to be used as a reliable test for whether
* a system is configured to use pkg, don't bootstrap pkg
@@ -1272,7 +1262,12 @@ main(int argc, char *argv[])
if (pkg_query_yes_no() == 0)
exit(EXIT_FAILURE);
}
- if (bootstrap_pkg(force, fetchOpts) != 0)
+ repositories = config_get_repositories();
+ STAILQ_FOREACH(repo, repositories, next) {
+ if ((ret = bootstrap_pkg(force, fetchOpts, repo)) == 0)
+ break;
+ }
+ if (ret != 0)
exit(EXIT_FAILURE);
config_finish();