Keep repo metadata if possible when updating repodata (xbps-rindex -a/-c).

API/ABI incompat changes, you've been warned.
This commit is contained in:
Juan RP 2014-01-30 13:07:34 +01:00
parent c6cae9e6ef
commit d08e76a386
9 changed files with 99 additions and 93 deletions

View File

@ -1,7 +1,7 @@
Almost all code in XBPS uses the following license Almost all code in XBPS uses the following license
(some exceptions are shown below): (some exceptions are shown below):
/* Copyright (c) 2008-2012 Juan Romero Pardines. /* Copyright (c) 2008-2014 Juan Romero Pardines.
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without

14
NEWS
View File

@ -1,5 +1,19 @@
xbps-0.31 (??): xbps-0.31 (??):
* Removed 0.27 compat from repodata.
* If a repository has been signed previously respect its settings
in repodata (unless there were new changes). This allows us to
accomplish the following:
$ xbps-rindex repo/*.xbps
$ xbps-rindex --sign ... repo
$ xbps-rindex repo/new-pkg.xbps
... and repository is still signed after updating repodata.
API/ABI incompatible changes, you've been warned :-)
* xbps-rindex(8): -c [clean] mode now is fully multithread safe. * xbps-rindex(8): -c [clean] mode now is fully multithread safe.
* Fixed a double free while downloading binpkgs from remote repositories * Fixed a double free while downloading binpkgs from remote repositories

View File

@ -1,5 +1,5 @@
/*- /*-
* Copyright (c) 2008-2013 Juan Romero Pardines. * Copyright (c) 2008-2014 Juan Romero Pardines.
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -156,15 +156,25 @@ list_pkgs_pkgdb(struct xbps_handle *xhp)
static int static int
repo_list_uri_cb(struct xbps_repo *repo, void *arg _unused, bool *done _unused) repo_list_uri_cb(struct xbps_repo *repo, void *arg _unused, bool *done _unused)
{ {
const char *signedby, *hexfp;
uint16_t pubkeysize;
printf("%5zd %s", printf("%5zd %s",
repo->idx ? (ssize_t)xbps_dictionary_count(repo->idx) : -1, repo->idx ? (ssize_t)xbps_dictionary_count(repo->idx) : -1,
repo->uri); repo->uri);
printf(" (RSA %s)\n", repo->is_signed ? "signed" : "unsigned"); printf(" (RSA %s)\n", repo->is_signed ? "signed" : "unsigned");
if (repo->xhp->flags & XBPS_FLAG_VERBOSE) { if (repo->xhp->flags & XBPS_FLAG_VERBOSE) {
if (repo->signedby) xbps_data_t pubkey;
printf(" Signed-by: %s\n", repo->signedby);
if (repo->hexfp) xbps_dictionary_get_cstring_nocopy(repo->idxmeta, "signature-by", &signedby);
printf(" %u %s\n", repo->pubkey_size, repo->hexfp); xbps_dictionary_get_uint16(repo->idxmeta, "public-key-size", &pubkeysize);
pubkey = xbps_dictionary_get(repo->idxmeta, "public-key");
hexfp = xbps_pubkey2fp(repo->xhp, pubkey);
if (signedby)
printf(" Signed-by: %s\n", signedby);
if (pubkeysize && hexfp)
printf(" %u %s\n", pubkeysize, hexfp);
} }
return 0; return 0;
} }

View File

@ -1,5 +1,5 @@
/*- /*-
* Copyright (c) 2012-2013 Juan Romero Pardines. * Copyright (c) 2012-2014 Juan Romero Pardines.
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -41,7 +41,7 @@ int
index_add(struct xbps_handle *xhp, int argc, char **argv, bool force) index_add(struct xbps_handle *xhp, int argc, char **argv, bool force)
{ {
xbps_array_t array, pkg_files, pkg_links, pkg_cffiles; xbps_array_t array, pkg_files, pkg_links, pkg_cffiles;
xbps_dictionary_t idx, idxfiles, binpkgd, pkg_filesd, curpkgd; xbps_dictionary_t idx, idxmeta, idxfiles, binpkgd, pkg_filesd, curpkgd;
xbps_object_t obj, fileobj; xbps_object_t obj, fileobj;
struct xbps_repo *repo; struct xbps_repo *repo;
struct stat st; struct stat st;
@ -62,10 +62,12 @@ index_add(struct xbps_handle *xhp, int argc, char **argv, bool force)
if (repo && repo->idx) { if (repo && repo->idx) {
xbps_repo_open_idxfiles(repo); xbps_repo_open_idxfiles(repo);
idx = xbps_dictionary_copy(repo->idx); idx = xbps_dictionary_copy(repo->idx);
idxmeta = xbps_dictionary_copy(repo->idxmeta);
idxfiles = xbps_dictionary_copy(repo->idxfiles); idxfiles = xbps_dictionary_copy(repo->idxfiles);
xbps_repo_close(repo); xbps_repo_close(repo);
} else { } else {
idx = xbps_dictionary_create(); idx = xbps_dictionary_create();
idxmeta = NULL;
idxfiles = xbps_dictionary_create(); idxfiles = xbps_dictionary_create();
} }
@ -241,7 +243,7 @@ index_add(struct xbps_handle *xhp, int argc, char **argv, bool force)
* Generate repository data files. * Generate repository data files.
*/ */
if (flush) { if (flush) {
if (!repodata_flush(xhp, repodir, idx, idxfiles, NULL)) { if (!repodata_flush(xhp, repodir, idx, idxfiles, idxmeta)) {
fprintf(stderr, "failed to write repodata: %s\n", strerror(errno)); fprintf(stderr, "failed to write repodata: %s\n", strerror(errno));
return -1; return -1;
} }

View File

@ -121,7 +121,7 @@ index_clean(struct xbps_handle *xhp, const char *repodir)
struct xbps_repo *repo; struct xbps_repo *repo;
struct cbdata cbd; struct cbdata cbd;
xbps_array_t allkeys; xbps_array_t allkeys;
xbps_dictionary_t idx, idxfiles; xbps_dictionary_t idx, idxmeta, idxfiles;
char *keyname, *pkgname; char *keyname, *pkgname;
int rv = 0; int rv = 0;
bool flush = false; bool flush = false;
@ -135,6 +135,7 @@ index_clean(struct xbps_handle *xhp, const char *repodir)
} }
xbps_repo_open_idxfiles(repo); xbps_repo_open_idxfiles(repo);
idx = xbps_dictionary_copy(repo->idx); idx = xbps_dictionary_copy(repo->idx);
idxmeta = xbps_dictionary_copy(repo->idxmeta);
idxfiles = xbps_dictionary_copy(repo->idxfiles); idxfiles = xbps_dictionary_copy(repo->idxfiles);
xbps_repo_close(repo); xbps_repo_close(repo);
if (idx == NULL || idxfiles == NULL) { if (idx == NULL || idxfiles == NULL) {
@ -185,7 +186,7 @@ index_clean(struct xbps_handle *xhp, const char *repodir)
xbps_object_release(allkeys); xbps_object_release(allkeys);
if (flush) { if (flush) {
if (!repodata_flush(xhp, repodir, idx, idxfiles, NULL)) { if (!repodata_flush(xhp, repodir, idx, idxfiles, idxmeta)) {
fprintf(stderr, "failed to write repodata: %s\n", fprintf(stderr, "failed to write repodata: %s\n",
strerror(errno)); strerror(errno));
return -1; return -1;

View File

@ -119,14 +119,14 @@ sign_repo(struct xbps_handle *xhp, const char *repodir,
struct stat st; struct stat st;
struct xbps_repo *repo; struct xbps_repo *repo;
xbps_dictionary_t pkgd, meta = NULL; xbps_dictionary_t pkgd, meta = NULL;
xbps_data_t data = NULL; xbps_data_t data = NULL, rpubkey = NULL;
xbps_object_iterator_t iter = NULL; xbps_object_iterator_t iter = NULL;
xbps_object_t obj; xbps_object_t obj;
RSA *rsa = NULL; RSA *rsa = NULL;
unsigned char *sig; unsigned char *sig;
unsigned int siglen; unsigned int siglen;
uint16_t pubkeysize; uint16_t rpubkeysize, pubkeysize;
const char *arch, *pkgver; const char *arch, *pkgver, *rsignedby;
char *binpkg, *binpkg_sig, *buf, *defprivkey; char *binpkg, *binpkg_sig, *buf, *defprivkey;
int binpkg_fd, binpkg_sig_fd, rv = 0; int binpkg_fd, binpkg_sig_fd, rv = 0;
bool flush = false; bool flush = false;
@ -244,7 +244,7 @@ sign_repo(struct xbps_handle *xhp, const char *repodir,
} }
xbps_object_iterator_release(iter); xbps_object_iterator_release(iter);
/* /*
* Check if repository meta contains changes compared to its * Check if repository index-meta contains changes compared to its
* current state. * current state.
*/ */
if ((buf = pubkey_from_privkey(rsa)) == NULL) { if ((buf = pubkey_from_privkey(rsa)) == NULL) {
@ -254,15 +254,19 @@ sign_repo(struct xbps_handle *xhp, const char *repodir,
meta = xbps_dictionary_create(); meta = xbps_dictionary_create();
data = xbps_data_create_data(buf, strlen(buf)); data = xbps_data_create_data(buf, strlen(buf));
if (!xbps_data_equals(repo->pubkey, data)) rpubkey = xbps_dictionary_get(repo->idxmeta, "public-key");
if (!xbps_data_equals(rpubkey, data))
flush = true; flush = true;
free(buf); free(buf);
pubkeysize = RSA_size(rsa) * 8; pubkeysize = RSA_size(rsa) * 8;
if (repo->pubkey_size != pubkeysize) xbps_dictionary_get_uint16(repo->idxmeta, "public-key-size", &rpubkeysize);
if (rpubkeysize != pubkeysize)
flush = true; flush = true;
if (repo->signedby == NULL || strcmp(repo->signedby, signedby)) xbps_dictionary_get_cstring_nocopy(repo->idxmeta, "signedby", &rsignedby);
if (rsignedby == NULL || strcmp(rsignedby, signedby))
flush = true; flush = true;
if (!flush) if (!flush)
@ -273,22 +277,7 @@ sign_repo(struct xbps_handle *xhp, const char *repodir,
xbps_dictionary_set_cstring_nocopy(meta, "signature-by", signedby); xbps_dictionary_set_cstring_nocopy(meta, "signature-by", signedby);
xbps_dictionary_set_cstring_nocopy(meta, "signature-type", "rsa"); xbps_dictionary_set_cstring_nocopy(meta, "signature-type", "rsa");
xbps_object_release(data); xbps_object_release(data);
/* data = NULL;
* Compatibility with 0.27.
*/
if ((buf = xbps_dictionary_externalize(repo->idx)) == NULL) {
rv = errno;
fprintf(stderr, "failed to externalize repository index: %s\n", strerror(errno));
goto out;
}
if (!rsa_sign_buf(rsa, buf, strlen(buf), &sig, &siglen)) {
rv = errno;
fprintf(stderr, "failed to create repository index signature: %s\n", strerror(errno));
goto out;
}
data = xbps_data_create_data_nocopy(sig, siglen);
xbps_dictionary_set(meta, "signature", data);
free(buf);
if (!repodata_flush(xhp, repodir, repo->idx, repo->idxfiles, meta)) { if (!repodata_flush(xhp, repodir, repo->idx, repo->idxfiles, meta)) {
fprintf(stderr, "failed to write repodata: %s\n", strerror(errno)); fprintf(stderr, "failed to write repodata: %s\n", strerror(errno));
@ -304,10 +293,6 @@ out:
RSA_free(rsa); RSA_free(rsa);
rsa = NULL; rsa = NULL;
} }
if (data)
xbps_object_release(data);
if (meta)
xbps_object_release(meta);
if (repo) if (repo)
xbps_repo_close(repo); xbps_repo_close(repo);

View File

@ -50,7 +50,7 @@
* *
* This header documents the full API for the XBPS Library. * This header documents the full API for the XBPS Library.
*/ */
#define XBPS_API_VERSION "20131224" #define XBPS_API_VERSION "20140130"
#ifndef XBPS_VERSION #ifndef XBPS_VERSION
#define XBPS_VERSION "UNSET" #define XBPS_VERSION "UNSET"
@ -1123,36 +1123,18 @@ struct xbps_repo {
* Proplib dictionary associated with the repository index. * Proplib dictionary associated with the repository index.
*/ */
xbps_dictionary_t idx; xbps_dictionary_t idx;
/**
* @var idxmeta
*
* Proplib dictionary associated with the repository index-meta.
*/
xbps_dictionary_t idxmeta;
/** /**
* @var idxfiles * @var idxfiles
* *
* Proplib dictionary associated with the repository index-files. * Proplib dictionary associated with the repository index-files.
*/ */
xbps_dictionary_t idxfiles; xbps_dictionary_t idxfiles;
/**
* @var pubkey
*
* RSA public key associated with this repository in a prop_data object.
*/
xbps_data_t pubkey;
/**
* @var hexfp
*
* OpenSSH fingerprint in hexadecimal of the RSA public key.
*/
char *hexfp;
/**
* @var signedby;
*
* The signee of the RSA signature associated with this repository (string).
*/
const char *signedby;
/**
* @var pubkey_size;
*
* Size in bits of the RSA public key associacted with this repository.
*/
uint16_t pubkey_size;
/** /**
* @var uri * @var uri
* *

View File

@ -1,5 +1,5 @@
/*- /*-
* Copyright (c) 2012-2013 Juan Romero Pardines. * Copyright (c) 2012-2014 Juan Romero Pardines.
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -106,7 +106,6 @@ repo_get_dict(struct xbps_repo *repo)
struct xbps_repo * struct xbps_repo *
xbps_repo_open(struct xbps_handle *xhp, const char *url) xbps_repo_open(struct xbps_handle *xhp, const char *url)
{ {
xbps_dictionary_t meta;
struct xbps_repo *repo; struct xbps_repo *repo;
struct stat st; struct stat st;
const char *arch; const char *arch;
@ -165,15 +164,9 @@ xbps_repo_open(struct xbps_handle *xhp, const char *url)
repo->ar = NULL; repo->ar = NULL;
goto out; goto out;
} }
if ((meta = repo_get_dict(repo))) { repo->idxmeta = repo_get_dict(repo);
xbps_dictionary_get_cstring_nocopy(meta, "signature-by", &repo->signedby); if (repo->idxmeta != NULL)
xbps_dictionary_get_uint16(meta, "public-key-size", &repo->pubkey_size);
repo->pubkey = xbps_dictionary_get(meta, "public-key");
if (repo->pubkey) {
repo->is_signed = true; repo->is_signed = true;
repo->hexfp = xbps_pubkey2fp(repo->xhp, repo->pubkey);
}
}
out: out:
free(repofile); free(repofile);
@ -199,12 +192,14 @@ xbps_repo_close(struct xbps_repo *repo)
xbps_object_release(repo->idx); xbps_object_release(repo->idx);
repo->idx = NULL; repo->idx = NULL;
} }
if (repo->idxmeta != NULL) {
xbps_object_release(repo->idxmeta);
repo->idxmeta = NULL;
}
if (repo->idxfiles != NULL) { if (repo->idxfiles != NULL) {
xbps_object_release(repo->idxfiles); xbps_object_release(repo->idxfiles);
repo->idxfiles = NULL; repo->idxfiles = NULL;
} }
if (repo->hexfp != NULL)
free(repo->hexfp);
} }
xbps_dictionary_t xbps_dictionary_t
@ -417,6 +412,9 @@ int
xbps_repo_key_import(struct xbps_repo *repo) xbps_repo_key_import(struct xbps_repo *repo)
{ {
xbps_dictionary_t repokeyd = NULL; xbps_dictionary_t repokeyd = NULL;
xbps_data_t pubkey = NULL;
uint16_t pubkey_size = 0;
const char *hexfp = NULL, *signedby = NULL;
char *p, *dbkeyd, *rkeyfile = NULL; char *p, *dbkeyd, *rkeyfile = NULL;
int import, rv = 0; int import, rv = 0;
@ -424,27 +422,34 @@ xbps_repo_key_import(struct xbps_repo *repo)
/* /*
* If repository does not have required metadata plist, ignore it. * If repository does not have required metadata plist, ignore it.
*/ */
if (repo->pubkey == NULL) { if (!xbps_dictionary_count(repo->idxmeta)) {
xbps_dbg_printf(repo->xhp, xbps_dbg_printf(repo->xhp,
"[repo] `%s' unsigned repository!\n", repo->uri); "[repo] `%s' unsigned repository!\n", repo->uri);
return 0; return 0;
} }
/* /*
* Check the repository provides a working public-key data object. * Check for required objects in index-meta:
* - signature-by (string)
* - public-key (data)
* - public-key-size (number)
*/ */
repo->is_signed = true; xbps_dictionary_get_cstring_nocopy(repo->idxmeta, "signature-by", &signedby);
if (repo->hexfp == NULL) { xbps_dictionary_get_uint16(repo->idxmeta, "public-key-size", &pubkey_size);
pubkey = xbps_dictionary_get(repo->idxmeta, "public-key");
if (signedby == NULL || pubkey_size == 0 ||
xbps_object_type(pubkey) != XBPS_TYPE_DATA) {
xbps_dbg_printf(repo->xhp, xbps_dbg_printf(repo->xhp,
"[repo] `%s': invalid hex fingerprint: %s\n", "[repo] `%s': incomplete signed repository "
repo->uri, strerror(errno)); "(missing objs)\n", repo->uri);
rv = EINVAL; rv = EINVAL;
goto out; goto out;
} }
hexfp = xbps_pubkey2fp(repo->xhp, pubkey);
/* /*
* Check if the public key is alredy stored. * Check if the public key is alredy stored.
*/ */
rkeyfile = xbps_xasprintf("%s/keys/%s.plist", rkeyfile = xbps_xasprintf("%s/keys/%s.plist", repo->xhp->metadir, hexfp);
repo->xhp->metadir, repo->hexfp);
repokeyd = xbps_dictionary_internalize_from_zfile(rkeyfile); repokeyd = xbps_dictionary_internalize_from_zfile(rkeyfile);
if (xbps_object_type(repokeyd) == XBPS_TYPE_DICTIONARY) { if (xbps_object_type(repokeyd) == XBPS_TYPE_DICTIONARY) {
xbps_dbg_printf(repo->xhp, xbps_dbg_printf(repo->xhp,
@ -457,8 +462,8 @@ xbps_repo_key_import(struct xbps_repo *repo)
* to the client. * to the client.
*/ */
import = xbps_set_cb_state(repo->xhp, XBPS_STATE_REPO_KEY_IMPORT, 0, import = xbps_set_cb_state(repo->xhp, XBPS_STATE_REPO_KEY_IMPORT, 0,
repo->hexfp, "`%s' repository has been RSA signed by \"%s\"", hexfp, "`%s' repository has been RSA signed by \"%s\"",
repo->uri, repo->signedby); repo->uri, signedby);
if (import <= 0) { if (import <= 0) {
rv = EAGAIN; rv = EAGAIN;
goto out; goto out;
@ -482,9 +487,9 @@ xbps_repo_key_import(struct xbps_repo *repo)
free(p); free(p);
repokeyd = xbps_dictionary_create(); repokeyd = xbps_dictionary_create();
xbps_dictionary_set(repokeyd, "public-key", repo->pubkey); xbps_dictionary_set(repokeyd, "public-key", pubkey);
xbps_dictionary_set_uint16(repokeyd, "public-key-size", repo->pubkey_size); xbps_dictionary_set_uint16(repokeyd, "public-key-size", pubkey_size);
xbps_dictionary_set_cstring_nocopy(repokeyd, "signature-by", repo->signedby); xbps_dictionary_set_cstring_nocopy(repokeyd, "signature-by", signedby);
if (!xbps_dictionary_externalize_to_zfile(repokeyd, rkeyfile)) { if (!xbps_dictionary_externalize_to_zfile(repokeyd, rkeyfile)) {
rv = errno; rv = errno;

View File

@ -1,5 +1,5 @@
/*- /*-
* Copyright (c) 2013 Juan Romero Pardines. * Copyright (c) 2013-2014 Juan Romero Pardines.
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -82,18 +82,25 @@ xbps_verify_file_signature(struct xbps_repo *repo, const char *fname)
xbps_dictionary_t repokeyd = NULL; xbps_dictionary_t repokeyd = NULL;
xbps_data_t pubkey; xbps_data_t pubkey;
struct stat st, sig_st; struct stat st, sig_st;
const char *hexfp = NULL;
unsigned char *buf = NULL, *sig_buf = NULL; unsigned char *buf = NULL, *sig_buf = NULL;
char *rkeyfile = NULL, *sig = NULL; char *rkeyfile = NULL, *sig = NULL;
int fd = -1, sig_fd = -1; int fd = -1, sig_fd = -1;
bool val = false; bool val = false;
if (!repo->hexfp) if (!xbps_dictionary_count(repo->idxmeta)) {
xbps_dbg_printf(repo->xhp, "%s: unsigned repository\n", repo->uri);
return false; return false;
}
xbps_dictionary_get_cstring_nocopy(repo->idxmeta, "hexfp", &hexfp);
if (hexfp == NULL) {
xbps_dbg_printf(repo->xhp, "%s: incomplete signed repo, missing hexfp obj\n", repo->uri);
return false;
}
/* /*
* Prepare repository RSA public key to verify fname signature. * Prepare repository RSA public key to verify fname signature.
*/ */
rkeyfile = xbps_xasprintf("%s/keys/%s.plist", rkeyfile = xbps_xasprintf("%s/keys/%s.plist", repo->xhp->metadir, hexfp);
repo->xhp->metadir, repo->hexfp);
repokeyd = xbps_dictionary_internalize_from_zfile(rkeyfile); repokeyd = xbps_dictionary_internalize_from_zfile(rkeyfile);
if (xbps_object_type(repokeyd) != XBPS_TYPE_DICTIONARY) { if (xbps_object_type(repokeyd) != XBPS_TYPE_DICTIONARY) {
xbps_dbg_printf(repo->xhp, "cannot read rkey data at %s: %s\n", xbps_dbg_printf(repo->xhp, "cannot read rkey data at %s: %s\n",