Added support for the long awaited feature: RSA signed repositories.
This commit is contained in:
parent
ae2eea8937
commit
8d5c48b861
17
NEWS
17
NEWS
@ -1,3 +1,20 @@
|
|||||||
|
xbps-0.27 (???):
|
||||||
|
|
||||||
|
* Support for RSA signed repositories. A repository can be signed with your
|
||||||
|
preferred RSA key (any ssh key works) as follows:
|
||||||
|
|
||||||
|
$ xbps-rindex -s --signedby "foobar <foo@bar>" --privkey /priv/key /path/to/repo
|
||||||
|
|
||||||
|
The first time xbps-install(8) access to a signed repository it will ask you
|
||||||
|
to import its public key to verify the signature. Please double-check the
|
||||||
|
hex fingerprint of the public key is the real one!
|
||||||
|
|
||||||
|
Once the public key has been imported it's not expected to change, hence if the
|
||||||
|
repository index has been modified or signed with another key, it will be ignored.
|
||||||
|
|
||||||
|
Starting from now on all remote repositories must be signed and verified.
|
||||||
|
Local repos do not need to be signed and they will work as before.
|
||||||
|
|
||||||
xbps-0.26 (2013-09-25):
|
xbps-0.26 (2013-09-25):
|
||||||
|
|
||||||
* xbps-query(8): the `-D --defrepo' argument has been superseded by
|
* xbps-query(8): the `-D --defrepo' argument has been superseded by
|
||||||
|
5
TODO
5
TODO
@ -7,9 +7,6 @@ xbps-create:
|
|||||||
- Move all configuration files to <prefix>/share/<pkgname>/conf/<cffile>.
|
- Move all configuration files to <prefix>/share/<pkgname>/conf/<cffile>.
|
||||||
- Add -i --installed option to create binpkg from an installed version.
|
- Add -i --installed option to create binpkg from an installed version.
|
||||||
|
|
||||||
All:
|
Issues listed at https://github.com/xtraeme/xbps/issues
|
||||||
- Add support to sign with PGP or RSA the repository index files.
|
|
||||||
|
|
||||||
Issues listed at http://code.google.com/p/xbps/issues/list
|
|
||||||
|
|
||||||
Surely more stuff...
|
Surely more stuff...
|
||||||
|
@ -48,7 +48,7 @@ bool noyes(const char *, ...);
|
|||||||
void fetch_file_progress_cb(struct xbps_fetch_cb_data *, void *);
|
void fetch_file_progress_cb(struct xbps_fetch_cb_data *, void *);
|
||||||
|
|
||||||
/* from state_cb.c */
|
/* from state_cb.c */
|
||||||
void state_cb(struct xbps_state_cb_data *, void *);
|
int state_cb(struct xbps_state_cb_data *, void *);
|
||||||
|
|
||||||
/* From util.c */
|
/* From util.c */
|
||||||
void print_package_line(const char *, int, bool);
|
void print_package_line(const char *, int, bool);
|
||||||
|
@ -31,13 +31,14 @@
|
|||||||
#include <xbps.h>
|
#include <xbps.h>
|
||||||
#include "defs.h"
|
#include "defs.h"
|
||||||
|
|
||||||
void
|
int
|
||||||
state_cb(struct xbps_state_cb_data *xscd, void *cbdata _unused)
|
state_cb(struct xbps_state_cb_data *xscd, void *cbdata _unused)
|
||||||
{
|
{
|
||||||
xbps_dictionary_t pkgd;
|
xbps_dictionary_t pkgd;
|
||||||
const char *instver, *newver;
|
const char *instver, *newver;
|
||||||
char *pkgname;
|
char *pkgname;
|
||||||
bool syslog_enabled = false;
|
bool syslog_enabled = false;
|
||||||
|
int rv = 0;
|
||||||
|
|
||||||
if (xscd->xhp->flags & XBPS_FLAG_SYSLOG) {
|
if (xscd->xhp->flags & XBPS_FLAG_SYSLOG) {
|
||||||
syslog_enabled = true;
|
syslog_enabled = true;
|
||||||
@ -46,6 +47,19 @@ state_cb(struct xbps_state_cb_data *xscd, void *cbdata _unused)
|
|||||||
|
|
||||||
switch (xscd->state) {
|
switch (xscd->state) {
|
||||||
/* notifications */
|
/* notifications */
|
||||||
|
case XBPS_STATE_REPO_KEY_IMPORT:
|
||||||
|
printf("%s\n", xscd->desc);
|
||||||
|
printf("Fingerprint: ");
|
||||||
|
xbps_print_hexfp(xscd->arg);
|
||||||
|
printf("\n");
|
||||||
|
rv = noyes("Do you want to import this public key?");
|
||||||
|
break;
|
||||||
|
case XBPS_STATE_REPO_SIGVERIFIED:
|
||||||
|
printf("[*] RSA signature verified correctly\n");
|
||||||
|
break;
|
||||||
|
case XBPS_STATE_REPO_SIGUNVERIFIED:
|
||||||
|
printf("[*] RSA signature UNVERIFIED! ignoring...\n");
|
||||||
|
break;
|
||||||
case XBPS_STATE_TRANS_DOWNLOAD:
|
case XBPS_STATE_TRANS_DOWNLOAD:
|
||||||
printf("\n[*] Downloading binary packages\n");
|
printf("\n[*] Downloading binary packages\n");
|
||||||
break;
|
break;
|
||||||
@ -141,7 +155,7 @@ state_cb(struct xbps_state_cb_data *xscd, void *cbdata _unused)
|
|||||||
case XBPS_STATE_REMOVE_FILE_OBSOLETE_FAIL:
|
case XBPS_STATE_REMOVE_FILE_OBSOLETE_FAIL:
|
||||||
/* Ignore errors due to not empty directories */
|
/* Ignore errors due to not empty directories */
|
||||||
if (xscd->err == ENOTEMPTY)
|
if (xscd->err == ENOTEMPTY)
|
||||||
return;
|
return 0;
|
||||||
|
|
||||||
xbps_error_printf("%s\n", xscd->desc);
|
xbps_error_printf("%s\n", xscd->desc);
|
||||||
if (syslog_enabled)
|
if (syslog_enabled)
|
||||||
@ -152,4 +166,6 @@ state_cb(struct xbps_state_cb_data *xscd, void *cbdata _unused)
|
|||||||
"%s: unknown state %d\n", xscd->arg, xscd->state);
|
"%s: unknown state %d\n", xscd->arg, xscd->state);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return rv;
|
||||||
}
|
}
|
||||||
|
@ -156,8 +156,15 @@ 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)
|
||||||
{
|
{
|
||||||
printf("%5zd %s\n", repo->idx ? (ssize_t)xbps_dictionary_count(repo->idx) : -1, repo->uri);
|
printf("%5zd %s",
|
||||||
|
repo->idx ? (ssize_t)xbps_dictionary_count(repo->idx) : -1,
|
||||||
|
repo->uri);
|
||||||
|
if (xbps_repository_is_remote(repo->uri)) {
|
||||||
|
printf(" (RSA %s, %s)",
|
||||||
|
repo->is_signed ? "signed" : "unsigned",
|
||||||
|
repo->is_verified ? "verified" : "unverified");
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -162,7 +162,7 @@ repo_ownedby_cb(struct xbps_repo *repo, void *arg, bool *done _unused)
|
|||||||
struct ffdata *ffd = arg;
|
struct ffdata *ffd = arg;
|
||||||
int rv;
|
int rv;
|
||||||
|
|
||||||
filesd = xbps_repo_get_plist(repo, XBPS_PKGINDEX_FILES);
|
filesd = xbps_repo_get_plist(repo, XBPS_REPOIDX_FILES);
|
||||||
if (filesd == NULL)
|
if (filesd == NULL)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
@ -131,6 +131,9 @@ search_pkgs_cb(struct xbps_repo *repo, void *arg, bool *done _unused)
|
|||||||
struct search_data *sd = arg;
|
struct search_data *sd = arg;
|
||||||
int rv;
|
int rv;
|
||||||
|
|
||||||
|
if (repo->idx == NULL)
|
||||||
|
return 0;
|
||||||
|
|
||||||
allkeys = xbps_dictionary_all_keys(repo->idx);
|
allkeys = xbps_dictionary_all_keys(repo->idx);
|
||||||
rv = xbps_array_foreach_cb(repo->xhp, allkeys, repo->idx, search_array_cb, sd);
|
rv = xbps_array_foreach_cb(repo->xhp, allkeys, repo->idx, search_array_cb, sd);
|
||||||
xbps_object_release(allkeys);
|
xbps_object_release(allkeys);
|
||||||
|
@ -50,7 +50,7 @@ usage(bool fail)
|
|||||||
exit(fail ? EXIT_FAILURE : EXIT_SUCCESS);
|
exit(fail ? EXIT_FAILURE : EXIT_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static int
|
||||||
state_cb(struct xbps_state_cb_data *xscd, void *cbd _unused)
|
state_cb(struct xbps_state_cb_data *xscd, void *cbd _unused)
|
||||||
{
|
{
|
||||||
bool syslog_enabled = false;
|
bool syslog_enabled = false;
|
||||||
@ -84,6 +84,8 @@ state_cb(struct xbps_state_cb_data *xscd, void *cbd _unused)
|
|||||||
"%s: unknown state %d\n", xscd->arg, xscd->state);
|
"%s: unknown state %d\n", xscd->arg, xscd->state);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
|
@ -62,7 +62,7 @@ usage(bool fail)
|
|||||||
exit(fail ? EXIT_FAILURE : EXIT_SUCCESS);
|
exit(fail ? EXIT_FAILURE : EXIT_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static int
|
||||||
state_cb_rm(struct xbps_state_cb_data *xscd, void *cbdata _unused)
|
state_cb_rm(struct xbps_state_cb_data *xscd, void *cbdata _unused)
|
||||||
{
|
{
|
||||||
bool syslog_enabled = false;
|
bool syslog_enabled = false;
|
||||||
@ -101,7 +101,7 @@ state_cb_rm(struct xbps_state_cb_data *xscd, void *cbdata _unused)
|
|||||||
case XBPS_STATE_REMOVE_FILE_OBSOLETE_FAIL:
|
case XBPS_STATE_REMOVE_FILE_OBSOLETE_FAIL:
|
||||||
/* Ignore errors due to not empty directories */
|
/* Ignore errors due to not empty directories */
|
||||||
if (xscd->err == ENOTEMPTY)
|
if (xscd->err == ENOTEMPTY)
|
||||||
return;
|
return 0;
|
||||||
|
|
||||||
xbps_error_printf("%s\n", xscd->desc);
|
xbps_error_printf("%s\n", xscd->desc);
|
||||||
if (syslog_enabled)
|
if (syslog_enabled)
|
||||||
@ -112,6 +112,8 @@ state_cb_rm(struct xbps_state_cb_data *xscd, void *cbdata _unused)
|
|||||||
"%s: unknown state %d\n", xscd->arg, xscd->state);
|
"%s: unknown state %d\n", xscd->arg, xscd->state);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
|
@ -3,5 +3,7 @@ TOPDIR = ../..
|
|||||||
|
|
||||||
BIN = xbps-rindex
|
BIN = xbps-rindex
|
||||||
OBJS = main.o index-add.o index-clean.o remove-obsoletes.o repoflush.o
|
OBJS = main.o index-add.o index-clean.o remove-obsoletes.o repoflush.o
|
||||||
|
OBJS += readpassphrase.o sign.o
|
||||||
|
EXTRA_CFLAGS = -Wno-unused-result
|
||||||
|
|
||||||
include $(TOPDIR)/mk/prog.mk
|
include $(TOPDIR)/mk/prog.mk
|
||||||
|
@ -28,23 +28,6 @@
|
|||||||
|
|
||||||
#include <xbps.h>
|
#include <xbps.h>
|
||||||
|
|
||||||
/* From index-add.c */
|
|
||||||
int index_add(struct xbps_handle *, int, char **, bool);
|
|
||||||
|
|
||||||
/* From index-clean.c */
|
|
||||||
int index_clean(struct xbps_handle *, const char *);
|
|
||||||
|
|
||||||
/* From index-files.c */
|
|
||||||
int index_files_add(struct xbps_handle *, int, char **);
|
|
||||||
int index_files_clean(struct xbps_handle *, const char *);
|
|
||||||
|
|
||||||
/* From remove-obsoletes.c */
|
|
||||||
int remove_obsoletes(struct xbps_handle *, const char *);
|
|
||||||
|
|
||||||
/* From repoflush.c */
|
|
||||||
int repodata_flush(struct xbps_handle *, const char *,
|
|
||||||
xbps_dictionary_t, xbps_dictionary_t);
|
|
||||||
|
|
||||||
/* libarchive compat */
|
/* libarchive compat */
|
||||||
#if ARCHIVE_VERSION_NUMBER >= 3000000
|
#if ARCHIVE_VERSION_NUMBER >= 3000000
|
||||||
|
|
||||||
@ -77,4 +60,41 @@ int repodata_flush(struct xbps_handle *, const char *,
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef __UNCONST
|
||||||
|
#define __UNCONST(a) ((void *)(unsigned long)(const void *)(a))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
struct repodata {
|
||||||
|
struct archive *ar;
|
||||||
|
char *repofile;
|
||||||
|
char *tname;
|
||||||
|
int repofd;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* From index-add.c */
|
||||||
|
int index_add(struct xbps_handle *, int, char **, bool);
|
||||||
|
|
||||||
|
/* From index-clean.c */
|
||||||
|
int index_clean(struct xbps_handle *, const char *);
|
||||||
|
|
||||||
|
/* From index-files.c */
|
||||||
|
int index_files_add(struct xbps_handle *, int, char **);
|
||||||
|
int index_files_clean(struct xbps_handle *, const char *);
|
||||||
|
|
||||||
|
/* From remove-obsoletes.c */
|
||||||
|
int remove_obsoletes(struct xbps_handle *, const char *);
|
||||||
|
|
||||||
|
/* From sign.c */
|
||||||
|
int sign_repo(struct xbps_handle *, const char *, const char *,
|
||||||
|
const char *);
|
||||||
|
|
||||||
|
/* From readpass.c */
|
||||||
|
char *readpassphrase(const char *, char *, size_t, int);
|
||||||
|
|
||||||
|
/* From repoflush.c */
|
||||||
|
struct repodata *repodata_init(struct xbps_handle *xhp, const char *);
|
||||||
|
int repodata_add_buf(struct repodata *, const char *, const char *);
|
||||||
|
void repodata_flush(struct repodata *);
|
||||||
|
|
||||||
#endif /* !_XBPS_RINDEX_DEFS_H_ */
|
#endif /* !_XBPS_RINDEX_DEFS_H_ */
|
||||||
|
@ -52,7 +52,7 @@ index_add(struct xbps_handle *xhp, int argc, char **argv, bool force)
|
|||||||
const char *oldpkgver, *arch, *oldarch;
|
const char *oldpkgver, *arch, *oldarch;
|
||||||
char *pkgver, *pkgname, *sha256, *repodir, *buf;
|
char *pkgver, *pkgname, *sha256, *repodir, *buf;
|
||||||
char *tmprepodir;
|
char *tmprepodir;
|
||||||
int rv, ret = 0;
|
int rv = 0, ret = 0;
|
||||||
bool flush = false, found = false;
|
bool flush = false, found = false;
|
||||||
|
|
||||||
idx = idxfiles = newpkgd = newpkgfilesd = curpkgd = NULL;
|
idx = idxfiles = newpkgd = newpkgfilesd = curpkgd = NULL;
|
||||||
@ -67,8 +67,8 @@ index_add(struct xbps_handle *xhp, int argc, char **argv, bool force)
|
|||||||
|
|
||||||
repo = xbps_repo_open(xhp, repodir);
|
repo = xbps_repo_open(xhp, repodir);
|
||||||
if (repo != NULL) {
|
if (repo != NULL) {
|
||||||
idx = xbps_repo_get_plist(repo, XBPS_PKGINDEX);
|
idx = xbps_repo_get_plist(repo, XBPS_REPOIDX);
|
||||||
idxfiles = xbps_repo_get_plist(repo, XBPS_PKGINDEX_FILES);
|
idxfiles = xbps_repo_get_plist(repo, XBPS_REPOIDX_FILES);
|
||||||
}
|
}
|
||||||
if (idx == NULL)
|
if (idx == NULL)
|
||||||
idx = xbps_dictionary_create();
|
idx = xbps_dictionary_create();
|
||||||
@ -267,9 +267,19 @@ index_add(struct xbps_handle *xhp, int argc, char **argv, bool force)
|
|||||||
* Generate repository data file.
|
* Generate repository data file.
|
||||||
*/
|
*/
|
||||||
if (flush) {
|
if (flush) {
|
||||||
rv = repodata_flush(xhp, repodir, idx, idxfiles);
|
struct repodata *rd;
|
||||||
if (rv != 0)
|
char *xml;
|
||||||
return rv;
|
|
||||||
|
rd = repodata_init(xhp, repodir);
|
||||||
|
xml = xbps_dictionary_externalize(idx);
|
||||||
|
assert(idx);
|
||||||
|
rv = repodata_add_buf(rd, xml, XBPS_REPOIDX);
|
||||||
|
free(xml);
|
||||||
|
xml = xbps_dictionary_externalize(idxfiles);
|
||||||
|
assert(idx);
|
||||||
|
rv = repodata_add_buf(rd, xml, XBPS_REPOIDX_FILES);
|
||||||
|
free(xml);
|
||||||
|
repodata_flush(rd);
|
||||||
}
|
}
|
||||||
printf("index: %u packages registered.\n",
|
printf("index: %u packages registered.\n",
|
||||||
xbps_dictionary_count(idx));
|
xbps_dictionary_count(idx));
|
||||||
@ -279,5 +289,5 @@ index_add(struct xbps_handle *xhp, int argc, char **argv, bool force)
|
|||||||
xbps_object_release(idx);
|
xbps_object_release(idx);
|
||||||
xbps_object_release(idxfiles);
|
xbps_object_release(idxfiles);
|
||||||
|
|
||||||
return 0;
|
return rv;
|
||||||
}
|
}
|
||||||
|
@ -71,7 +71,7 @@ idx_cleaner_cb(struct xbps_handle *xhp,
|
|||||||
* File can be read; check its hash.
|
* File can be read; check its hash.
|
||||||
*/
|
*/
|
||||||
xbps_dictionary_get_cstring_nocopy(obj,
|
xbps_dictionary_get_cstring_nocopy(obj,
|
||||||
"filename-sha256", &sha256);
|
"filename-sha256", &sha256);
|
||||||
if (xbps_file_hash_check(filen, sha256) != 0)
|
if (xbps_file_hash_check(filen, sha256) != 0)
|
||||||
xbps_array_add_cstring_nocopy(cbd->array, pkgver);
|
xbps_array_add_cstring_nocopy(cbd->array, pkgver);
|
||||||
}
|
}
|
||||||
@ -80,7 +80,7 @@ idx_cleaner_cb(struct xbps_handle *xhp,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Removes stalled pkg entries in repository's index.plist file, if any
|
* Removes stalled pkg entries in repository's XBPS_REPOIDX file, if any
|
||||||
* binary package cannot be read (unavailable, not enough perms, etc).
|
* binary package cannot be read (unavailable, not enough perms, etc).
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
@ -102,8 +102,8 @@ index_clean(struct xbps_handle *xhp, const char *repodir)
|
|||||||
fprintf(stderr, "index: cannot read repository data: %s\n", strerror(errno));
|
fprintf(stderr, "index: cannot read repository data: %s\n", strerror(errno));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
idx = xbps_repo_get_plist(repo, XBPS_PKGINDEX);
|
idx = xbps_repo_get_plist(repo, XBPS_REPOIDX);
|
||||||
idxfiles = xbps_repo_get_plist(repo, XBPS_PKGINDEX_FILES);
|
idxfiles = xbps_repo_get_plist(repo, XBPS_REPOIDX_FILES);
|
||||||
xbps_repo_close(repo);
|
xbps_repo_close(repo);
|
||||||
if (idx == NULL || idxfiles == NULL) {
|
if (idx == NULL || idxfiles == NULL) {
|
||||||
fprintf(stderr, "incomplete repository data file!");
|
fprintf(stderr, "incomplete repository data file!");
|
||||||
@ -111,7 +111,7 @@ index_clean(struct xbps_handle *xhp, const char *repodir)
|
|||||||
}
|
}
|
||||||
if (chdir(repodir) == -1) {
|
if (chdir(repodir) == -1) {
|
||||||
fprintf(stderr, "index: cannot chdir to %s: %s\n",
|
fprintf(stderr, "index: cannot chdir to %s: %s\n",
|
||||||
repodir, strerror(errno));
|
repodir, strerror(errno));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
printf("Cleaning `%s' index, please wait...\n", repodir);
|
printf("Cleaning `%s' index, please wait...\n", repodir);
|
||||||
@ -134,14 +134,25 @@ index_clean(struct xbps_handle *xhp, const char *repodir)
|
|||||||
xbps_object_release(cbd.array);
|
xbps_object_release(cbd.array);
|
||||||
|
|
||||||
if (flush) {
|
if (flush) {
|
||||||
rv = repodata_flush(xhp, repodir, idx, idxfiles);
|
struct repodata *rd;
|
||||||
if (rv != 0)
|
char *xml;
|
||||||
return rv;
|
|
||||||
|
rd = repodata_init(xhp, repodir);
|
||||||
|
xml = xbps_dictionary_externalize(idx);
|
||||||
|
assert(idx);
|
||||||
|
rv = repodata_add_buf(rd, xml, XBPS_REPOIDX);
|
||||||
|
free(xml);
|
||||||
|
xml = xbps_dictionary_externalize(idxfiles);
|
||||||
|
assert(idx);
|
||||||
|
rv = repodata_add_buf(rd, xml, XBPS_REPOIDX_FILES);
|
||||||
|
free(xml);
|
||||||
|
repodata_flush(rd);
|
||||||
|
|
||||||
}
|
}
|
||||||
printf("index: %u packages registered.\n",
|
printf("index: %u packages registered.\n",
|
||||||
xbps_dictionary_count(idx));
|
xbps_dictionary_count(idx));
|
||||||
printf("index-files: %u packages registered.\n",
|
printf("index-files: %u packages registered.\n",
|
||||||
xbps_dictionary_count(idxfiles));
|
xbps_dictionary_count(idxfiles));
|
||||||
|
|
||||||
xbps_object_release(idx);
|
xbps_object_release(idx);
|
||||||
xbps_object_release(idxfiles);
|
xbps_object_release(idxfiles);
|
||||||
|
@ -39,11 +39,14 @@ usage(bool fail)
|
|||||||
"OPTIONS\n"
|
"OPTIONS\n"
|
||||||
" -f --force Force mode to overwrite entry in add mode\n"
|
" -f --force Force mode to overwrite entry in add mode\n"
|
||||||
" -h --help Show help usage\n"
|
" -h --help Show help usage\n"
|
||||||
" -V --version Show XBPS version\n\n"
|
" -V --version Show XBPS version\n"
|
||||||
|
" --privkey <key> Path to the private key for signing\n"
|
||||||
|
" --signedby <string> Signature details, i.e \"name <email>\"\n\n"
|
||||||
"MODE\n"
|
"MODE\n"
|
||||||
" -a --add <repodir/pkg> ... Add package(s) to repository index\n"
|
" -a --add <repodir/pkg> ... Add package(s) to repository index\n"
|
||||||
" -c --clean <repodir> Cleans obsolete entries in repository index\n"
|
" -c --clean <repodir> Cleans obsolete entries in repository index\n"
|
||||||
" -r --remove-obsoletes <repodir> Removes obsolete packages from repository\n\n");
|
" -r --remove-obsoletes <repodir> Removes obsolete packages from repository\n"
|
||||||
|
" -s --sign <repodir> Sign repository index\n\n");
|
||||||
exit(fail ? EXIT_FAILURE : EXIT_SUCCESS);
|
exit(fail ? EXIT_FAILURE : EXIT_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -58,14 +61,26 @@ main(int argc, char **argv)
|
|||||||
{ "help", no_argument, NULL, 'h' },
|
{ "help", no_argument, NULL, 'h' },
|
||||||
{ "remove-obsoletes", no_argument, NULL, 'r' },
|
{ "remove-obsoletes", no_argument, NULL, 'r' },
|
||||||
{ "version", no_argument, NULL, 'V' },
|
{ "version", no_argument, NULL, 'V' },
|
||||||
|
{ "privkey", required_argument, NULL, 0},
|
||||||
|
{ "signedby", required_argument, NULL, 1},
|
||||||
|
{ "sign", no_argument, NULL, 's'},
|
||||||
{ NULL, 0, NULL, 0 }
|
{ NULL, 0, NULL, 0 }
|
||||||
};
|
};
|
||||||
struct xbps_handle xh;
|
struct xbps_handle xh;
|
||||||
|
const char *privkey = NULL, *signedby = NULL;
|
||||||
int rv, c;
|
int rv, c;
|
||||||
bool clean_mode = false, add_mode = false, rm_mode = false, force = false;
|
bool clean_mode, add_mode, rm_mode, sign_mode, force;
|
||||||
|
|
||||||
|
clean_mode = add_mode = rm_mode = sign_mode = force = false;
|
||||||
|
|
||||||
while ((c = getopt_long(argc, argv, shortopts, longopts, NULL)) != -1) {
|
while ((c = getopt_long(argc, argv, shortopts, longopts, NULL)) != -1) {
|
||||||
switch (c) {
|
switch (c) {
|
||||||
|
case 0:
|
||||||
|
privkey = optarg;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
signedby = optarg;
|
||||||
|
break;
|
||||||
case 'a':
|
case 'a':
|
||||||
add_mode = true;
|
add_mode = true;
|
||||||
break;
|
break;
|
||||||
@ -81,18 +96,22 @@ main(int argc, char **argv)
|
|||||||
case 'r':
|
case 'r':
|
||||||
rm_mode = true;
|
rm_mode = true;
|
||||||
break;
|
break;
|
||||||
|
case 's':
|
||||||
|
sign_mode = true;
|
||||||
|
break;
|
||||||
case 'V':
|
case 'V':
|
||||||
printf("%s\n", XBPS_RELVER);
|
printf("%s\n", XBPS_RELVER);
|
||||||
exit(EXIT_SUCCESS);
|
exit(EXIT_SUCCESS);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ((argc == optind) || (!add_mode && !clean_mode && !rm_mode)) {
|
if ((argc == optind) || (!add_mode && !clean_mode && !rm_mode && !sign_mode)) {
|
||||||
usage(true);
|
usage(true);
|
||||||
} else if ((add_mode && (clean_mode || rm_mode)) ||
|
} else if ((add_mode && (clean_mode || rm_mode)) ||
|
||||||
(clean_mode && (add_mode || rm_mode)) ||
|
(clean_mode && (add_mode || rm_mode)) ||
|
||||||
(rm_mode && (add_mode || clean_mode))) {
|
(rm_mode && (add_mode || clean_mode)) ||
|
||||||
fprintf(stderr, "Only one mode can be specified: add, clean "
|
(sign_mode && (add_mode || clean_mode || rm_mode))) {
|
||||||
"or remove-obsoletes.\n");
|
fprintf(stderr, "Only one mode can be specified: add, clean, "
|
||||||
|
"remove-obsoletes or sign.\n");
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -110,6 +129,8 @@ main(int argc, char **argv)
|
|||||||
rv = index_clean(&xh, argv[optind]);
|
rv = index_clean(&xh, argv[optind]);
|
||||||
else if (rm_mode)
|
else if (rm_mode)
|
||||||
rv = remove_obsoletes(&xh, argv[optind]);
|
rv = remove_obsoletes(&xh, argv[optind]);
|
||||||
|
else if (sign_mode)
|
||||||
|
rv = sign_repo(&xh, argv[optind], privkey, signedby);
|
||||||
|
|
||||||
exit(rv ? EXIT_FAILURE : EXIT_SUCCESS);
|
exit(rv ? EXIT_FAILURE : EXIT_SUCCESS);
|
||||||
}
|
}
|
||||||
|
123
bin/xbps-rindex/readpassphrase.c
Normal file
123
bin/xbps-rindex/readpassphrase.c
Normal file
@ -0,0 +1,123 @@
|
|||||||
|
/* $NetBSD: readpassphrase.c,v 1.1 2009/06/07 22:38:47 christos Exp $ */
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2000 Todd C. Miller <Todd.Miller@courtesan.com>
|
||||||
|
* 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.
|
||||||
|
* 3. The name of the author may not be used to endorse or promote products
|
||||||
|
* derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED ``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 AUTHOR 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 <ctype.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <paths.h>
|
||||||
|
#include <pwd.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <termios.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "defs.h"
|
||||||
|
|
||||||
|
#define RPP_ECHO_OFF 0x00 /* Turn off echo (default). */
|
||||||
|
#define RPP_ECHO_ON 0x01 /* Leave echo on. */
|
||||||
|
#define RPP_REQUIRE_TTY 0x02 /* Fail if there is no tty. */
|
||||||
|
#define RPP_FORCELOWER 0x04 /* Force input to lower case. */
|
||||||
|
#define RPP_FORCEUPPER 0x08 /* Force input to upper case. */
|
||||||
|
#define RPP_SEVENBIT 0x10 /* Strip the high bit from input. */
|
||||||
|
|
||||||
|
char *
|
||||||
|
readpassphrase(const char *prompt, char *buf, size_t bufsiz, int flags)
|
||||||
|
{
|
||||||
|
struct termios term, oterm;
|
||||||
|
char ch, *p, *end;
|
||||||
|
int input, output;
|
||||||
|
sigset_t oset, nset;
|
||||||
|
|
||||||
|
/* I suppose we could alloc on demand in this case (XXX). */
|
||||||
|
if (bufsiz == 0) {
|
||||||
|
errno = EINVAL;
|
||||||
|
return(NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Read and write to /dev/tty if available. If not, read from
|
||||||
|
* stdin and write to stderr unless a tty is required.
|
||||||
|
*/
|
||||||
|
if ((input = output = open(_PATH_TTY, O_RDWR)) == -1) {
|
||||||
|
if (flags & RPP_REQUIRE_TTY) {
|
||||||
|
errno = ENOTTY;
|
||||||
|
return(NULL);
|
||||||
|
}
|
||||||
|
input = STDIN_FILENO;
|
||||||
|
output = STDERR_FILENO;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We block SIGINT and SIGTSTP so the terminal is not left
|
||||||
|
* in an inconsistent state (ie: no echo). It would probably
|
||||||
|
* be better to simply catch these though.
|
||||||
|
*/
|
||||||
|
sigemptyset(&nset);
|
||||||
|
sigaddset(&nset, SIGINT);
|
||||||
|
sigaddset(&nset, SIGTSTP);
|
||||||
|
(void)sigprocmask(SIG_BLOCK, &nset, &oset);
|
||||||
|
|
||||||
|
/* Turn off echo if possible. */
|
||||||
|
if (tcgetattr(input, &oterm) == 0) {
|
||||||
|
memcpy(&term, &oterm, sizeof(term));
|
||||||
|
if (!(flags & RPP_ECHO_ON) && (term.c_lflag & ECHO))
|
||||||
|
term.c_lflag &= ~ECHO;
|
||||||
|
(void)tcsetattr(input, TCSAFLUSH, &term);
|
||||||
|
} else {
|
||||||
|
memset(&term, 0, sizeof(term));
|
||||||
|
memset(&oterm, 0, sizeof(oterm));
|
||||||
|
}
|
||||||
|
|
||||||
|
(void)write(output, prompt, strlen(prompt));
|
||||||
|
end = buf + bufsiz - 1;
|
||||||
|
for (p = buf; read(input, &ch, 1) == 1 && ch != '\n' && ch != '\r';) {
|
||||||
|
if (p < end) {
|
||||||
|
if ((flags & RPP_SEVENBIT))
|
||||||
|
ch &= 0x7f;
|
||||||
|
if (isalpha((unsigned char)ch)) {
|
||||||
|
if ((flags & RPP_FORCELOWER))
|
||||||
|
ch = tolower((unsigned char)ch);
|
||||||
|
if ((flags & RPP_FORCEUPPER))
|
||||||
|
ch = toupper((unsigned char)ch);
|
||||||
|
}
|
||||||
|
*p++ = ch;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*p = '\0';
|
||||||
|
if (!(term.c_lflag & ECHO))
|
||||||
|
(void)write(output, "\n", 1);
|
||||||
|
|
||||||
|
/* Restore old terminal settings and signal mask. */
|
||||||
|
if (memcmp(&term, &oterm, sizeof(term)) != 0)
|
||||||
|
(void)tcsetattr(input, TCSAFLUSH, &oterm);
|
||||||
|
(void)sigprocmask(SIG_SETMASK, &oset, NULL);
|
||||||
|
if (input != STDIN_FILENO)
|
||||||
|
(void)close(input);
|
||||||
|
|
||||||
|
return(buf);
|
||||||
|
}
|
@ -119,7 +119,7 @@ remove_obsoletes(struct xbps_handle *xhp, const char *repodir)
|
|||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if ((repo->idx = xbps_repo_get_plist(repo, XBPS_PKGINDEX)) == NULL) {
|
if ((repo->idx = xbps_repo_get_plist(repo, XBPS_REPOIDX)) == NULL) {
|
||||||
xbps_repo_close(repo);
|
xbps_repo_close(repo);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -37,58 +37,54 @@
|
|||||||
#include <xbps.h>
|
#include <xbps.h>
|
||||||
#include "defs.h"
|
#include "defs.h"
|
||||||
|
|
||||||
int
|
struct repodata *
|
||||||
repodata_flush(struct xbps_handle *xhp, const char *repodir,
|
repodata_init(struct xbps_handle *xhp, const char *repodir)
|
||||||
xbps_dictionary_t idx, xbps_dictionary_t idxfiles)
|
|
||||||
{
|
{
|
||||||
struct archive *ar;
|
struct repodata *rd;
|
||||||
mode_t myumask;
|
|
||||||
char *repofile, *tname, *xml;
|
rd = malloc(sizeof(struct repodata));
|
||||||
int repofd;
|
assert(rd);
|
||||||
|
|
||||||
/* Create a tempfile for our repository archive */
|
/* Create a tempfile for our repository archive */
|
||||||
repofile = xbps_repo_path(xhp, repodir);
|
rd->repofile = xbps_repo_path(xhp, repodir);
|
||||||
tname = xbps_xasprintf("%s.XXXXXXXXXX", repofile);
|
rd->tname = xbps_xasprintf("%s.XXXXXXXXXX", rd->repofile);
|
||||||
if ((repofd = mkstemp(tname)) == -1)
|
if ((rd->repofd = mkstemp(rd->tname)) == -1) {
|
||||||
return errno;
|
free(rd);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
/* Create and write our repository archive */
|
/* Create and write our repository archive */
|
||||||
ar = archive_write_new();
|
rd->ar = archive_write_new();
|
||||||
assert(ar);
|
assert(rd->ar);
|
||||||
archive_write_set_compression_gzip(ar);
|
archive_write_set_compression_gzip(rd->ar);
|
||||||
archive_write_set_format_pax_restricted(ar);
|
archive_write_set_format_pax_restricted(rd->ar);
|
||||||
archive_write_set_options(ar, "compression-level=9");
|
archive_write_set_options(rd->ar, "compression-level=9");
|
||||||
archive_write_open_fd(ar, repofd);
|
archive_write_open_fd(rd->ar, rd->repofd);
|
||||||
|
|
||||||
xml = xbps_dictionary_externalize(idx);
|
return rd;
|
||||||
assert(xml);
|
}
|
||||||
if (xbps_archive_append_buf(ar, xml, strlen(xml),
|
|
||||||
XBPS_PKGINDEX, 0644, "root", "root") != 0) {
|
|
||||||
free(xml);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
free(xml);
|
|
||||||
|
|
||||||
xml = xbps_dictionary_externalize(idxfiles);
|
int
|
||||||
assert(xml);
|
repodata_add_buf(struct repodata *rd, const char *buf, const char *filename)
|
||||||
if (xbps_archive_append_buf(ar, xml, strlen(xml),
|
{
|
||||||
XBPS_PKGINDEX_FILES, 0644, "root", "root") != 0) {
|
return xbps_archive_append_buf(rd->ar, buf, strlen(buf),
|
||||||
free(xml);
|
filename, 0644, "root", "root");
|
||||||
return -1;
|
}
|
||||||
}
|
|
||||||
free(xml);
|
|
||||||
|
|
||||||
archive_write_finish(ar);
|
void
|
||||||
|
repodata_flush(struct repodata *rd)
|
||||||
|
{
|
||||||
|
mode_t myumask;
|
||||||
|
|
||||||
/* Write data to tempfile and rename */
|
/* Write data to tempfile and rename */
|
||||||
fdatasync(repofd);
|
archive_write_finish(rd->ar);
|
||||||
|
fdatasync(rd->repofd);
|
||||||
myumask = umask(0);
|
myumask = umask(0);
|
||||||
(void)umask(myumask);
|
(void)umask(myumask);
|
||||||
assert(fchmod(repofd, 0666 & ~myumask) != -1);
|
assert(fchmod(rd->repofd, 0666 & ~myumask) != -1);
|
||||||
close(repofd);
|
close(rd->repofd);
|
||||||
rename(tname, repofile);
|
rename(rd->tname, rd->repofile);
|
||||||
free(repofile);
|
free(rd->repofile);
|
||||||
free(tname);
|
free(rd->tname);
|
||||||
|
free(rd);
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
231
bin/xbps-rindex/sign.c
Normal file
231
bin/xbps-rindex/sign.c
Normal file
@ -0,0 +1,231 @@
|
|||||||
|
/*-
|
||||||
|
* Copyright (c) 2013 Juan Romero Pardines.
|
||||||
|
* 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 AUTHOR ``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 AUTHOR 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 <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
#include <openssl/err.h>
|
||||||
|
#include <openssl/sha.h>
|
||||||
|
#include <openssl/rsa.h>
|
||||||
|
#include <openssl/ssl.h>
|
||||||
|
#include <openssl/pem.h>
|
||||||
|
|
||||||
|
#include "defs.h"
|
||||||
|
|
||||||
|
static int
|
||||||
|
password_cb(char *buf, int size)
|
||||||
|
{
|
||||||
|
int len = 0;
|
||||||
|
char pass[BUFSIZ];
|
||||||
|
|
||||||
|
if (readpassphrase("Enter passphrase: ", pass, BUFSIZ, 0) == NULL)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
len = strlen(pass);
|
||||||
|
|
||||||
|
if (len <= 0)
|
||||||
|
return 0;
|
||||||
|
if (len > size)
|
||||||
|
len = size;
|
||||||
|
|
||||||
|
memset(buf, '\0', size);
|
||||||
|
memcpy(buf, pass, len);
|
||||||
|
memset(&pass, 0, BUFSIZ);
|
||||||
|
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
static RSA *
|
||||||
|
load_rsa_privkey(const char *path)
|
||||||
|
{
|
||||||
|
FILE *fp;
|
||||||
|
RSA *rsa = NULL;
|
||||||
|
|
||||||
|
if ((fp = fopen(path, "r")) == 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if ((rsa = RSA_new()) == NULL) {
|
||||||
|
fclose(fp);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
rsa = PEM_read_RSAPrivateKey(fp, 0,
|
||||||
|
(pem_password_cb *)password_cb,
|
||||||
|
__UNCONST(path));
|
||||||
|
fclose(fp);
|
||||||
|
return rsa;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *
|
||||||
|
pubkey_from_privkey(RSA *rsa)
|
||||||
|
{
|
||||||
|
BIO *bp;
|
||||||
|
char *buf;
|
||||||
|
|
||||||
|
bp = BIO_new(BIO_s_mem());
|
||||||
|
assert(bp);
|
||||||
|
|
||||||
|
if (!PEM_write_bio_RSA_PUBKEY(bp, rsa)) {
|
||||||
|
fprintf(stderr, "error writing public key: %s\n",
|
||||||
|
ERR_error_string(ERR_get_error(), NULL));
|
||||||
|
BIO_free(bp);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
/* XXX (xtraeme) 8192 should be always enough? */
|
||||||
|
buf = malloc(8192);
|
||||||
|
assert(buf);
|
||||||
|
BIO_read(bp, buf, 8192);
|
||||||
|
BIO_free(bp);
|
||||||
|
ERR_free_strings();
|
||||||
|
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
static RSA *
|
||||||
|
rsa_sign_buf(const char *privkey, const char *buf,
|
||||||
|
unsigned char **sigret, unsigned int *siglen)
|
||||||
|
{
|
||||||
|
SHA256_CTX context;
|
||||||
|
RSA *rsa;
|
||||||
|
unsigned char sha256[SHA256_DIGEST_LENGTH];
|
||||||
|
|
||||||
|
ERR_load_crypto_strings();
|
||||||
|
SSL_load_error_strings();
|
||||||
|
OpenSSL_add_all_algorithms();
|
||||||
|
OpenSSL_add_all_ciphers();
|
||||||
|
OpenSSL_add_all_digests();
|
||||||
|
|
||||||
|
rsa = load_rsa_privkey(privkey);
|
||||||
|
if (rsa == NULL) {
|
||||||
|
fprintf(stderr, "can't load private key from %s\n", privkey);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
SHA256_Init(&context);
|
||||||
|
SHA256_Update(&context, buf, strlen(buf));
|
||||||
|
SHA256_Final(sha256, &context);
|
||||||
|
|
||||||
|
*sigret = calloc(1, RSA_size(rsa) + 1);
|
||||||
|
if (RSA_sign(NID_sha1, sha256, sizeof(sha256),
|
||||||
|
*sigret, siglen, rsa) == 0) {
|
||||||
|
fprintf(stderr, "%s: %s\n", privkey,
|
||||||
|
ERR_error_string(ERR_get_error(), NULL));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return rsa;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
sign_repo(struct xbps_handle *xhp, const char *repodir,
|
||||||
|
const char *privkey, const char *signedby)
|
||||||
|
{
|
||||||
|
RSA *rsa = NULL;
|
||||||
|
struct repodata *rd;
|
||||||
|
struct xbps_repo *repo;
|
||||||
|
xbps_dictionary_t idx, meta;
|
||||||
|
xbps_data_t data;
|
||||||
|
unsigned int siglen;
|
||||||
|
unsigned char *sig;
|
||||||
|
char *buf, *xml, *defprivkey = NULL;
|
||||||
|
int rv = 0;
|
||||||
|
|
||||||
|
if (signedby == NULL) {
|
||||||
|
fprintf(stderr, "--signedby unset! cannot sign repository\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* Check that repository index exists and not empty, otherwise bail out.
|
||||||
|
*/
|
||||||
|
repo = xbps_repo_open(xhp, repodir);
|
||||||
|
if (repo == NULL) {
|
||||||
|
fprintf(stderr, "cannot read repository data: %s\n", strerror(errno));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
idx = xbps_repo_get_plist(repo, XBPS_REPOIDX);
|
||||||
|
xbps_repo_close(repo);
|
||||||
|
if (xbps_dictionary_count(idx) == 0) {
|
||||||
|
fprintf(stderr, "invalid number of objects in repository index!\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* Externalize the index and then sign it.
|
||||||
|
*/
|
||||||
|
xml = xbps_dictionary_externalize(idx);
|
||||||
|
if (xml == NULL) {
|
||||||
|
fprintf(stderr, "failed to externalize repository index: %s\n", strerror(errno));
|
||||||
|
xbps_object_release(idx);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* If privkey not set, default to ~/.ssh/id_rsa.
|
||||||
|
*/
|
||||||
|
if (privkey == NULL)
|
||||||
|
defprivkey = xbps_xasprintf("%s/.ssh/id_rsa", getenv("HOME"));
|
||||||
|
else
|
||||||
|
defprivkey = strdup(privkey);
|
||||||
|
|
||||||
|
rsa = rsa_sign_buf(defprivkey, xml, &sig, &siglen);
|
||||||
|
if (rsa == NULL) {
|
||||||
|
free(xml);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* Prepare the XBPS_REPOMETA for our repository data.
|
||||||
|
*/
|
||||||
|
meta = xbps_dictionary_create();
|
||||||
|
xbps_dictionary_set_cstring_nocopy(meta, "signature-by", signedby);
|
||||||
|
xbps_dictionary_set_cstring_nocopy(meta, "signature-type", "rsa");
|
||||||
|
data = xbps_data_create_data_nocopy(sig, siglen);
|
||||||
|
xbps_dictionary_set(meta, "signature", data);
|
||||||
|
|
||||||
|
buf = pubkey_from_privkey(rsa);
|
||||||
|
assert(buf);
|
||||||
|
data = xbps_data_create_data_nocopy(buf, strlen(buf));
|
||||||
|
xbps_dictionary_set(meta, "public-key", data);
|
||||||
|
xbps_dictionary_set_uint16(meta, "public-key-size", RSA_size(rsa) * 8);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* and finally write our repodata file!
|
||||||
|
*/
|
||||||
|
rd = repodata_init(xhp, repodir);
|
||||||
|
assert(rd);
|
||||||
|
xml = xbps_dictionary_externalize(idx);
|
||||||
|
assert(xml);
|
||||||
|
rv = repodata_add_buf(rd, xml, XBPS_REPOIDX);
|
||||||
|
free(xml);
|
||||||
|
xml = xbps_dictionary_externalize(meta);
|
||||||
|
assert(xml);
|
||||||
|
rv = repodata_add_buf(rd, xml, XBPS_REPOMETA);
|
||||||
|
free(xml);
|
||||||
|
repodata_flush(rd);
|
||||||
|
free(buf);
|
||||||
|
RSA_free(rsa);
|
||||||
|
|
||||||
|
return rv;
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
.Dd August 18, 2013
|
.Dd October 5, 2013
|
||||||
.Os Void Linux
|
.Os Void Linux
|
||||||
.Dt xbps-rindex 8
|
.Dt xbps-rindex 8
|
||||||
.Sh NAME
|
.Sh NAME
|
||||||
@ -38,6 +38,17 @@ Removes obsolete packages from
|
|||||||
.Ar repository .
|
.Ar repository .
|
||||||
Packages that are not currently registered in repository's index will
|
Packages that are not currently registered in repository's index will
|
||||||
be removed (out of date, invalid archives, etc).
|
be removed (out of date, invalid archives, etc).
|
||||||
|
.It Sy -s, --sign
|
||||||
|
Signs a repository with your specified RSA key. If
|
||||||
|
.Fl --privkey
|
||||||
|
argument not set, it defaults to
|
||||||
|
.Sy ~/.ssh/id_rsa .
|
||||||
|
.It Sy --signedby Ar string
|
||||||
|
This is required to sign a repository, use something like
|
||||||
|
.Ar name <email> .
|
||||||
|
.It Sy --privkey Ar key
|
||||||
|
Path to the private RSA key to sign the repository. If unset, defaults to
|
||||||
|
.Sy ~/.ssh/id_rsa .
|
||||||
.Sh ENVIRONMENT
|
.Sh ENVIRONMENT
|
||||||
.Bl -tag -width XBPS_TARGET_ARCH
|
.Bl -tag -width XBPS_TARGET_ARCH
|
||||||
.It Sy XBPS_TARGET_ARCH
|
.It Sy XBPS_TARGET_ARCH
|
||||||
|
@ -46,7 +46,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 "20130918"
|
#define XBPS_API_VERSION "20131005"
|
||||||
|
|
||||||
#ifndef XBPS_VERSION
|
#ifndef XBPS_VERSION
|
||||||
#define XBPS_VERSION "UNSET"
|
#define XBPS_VERSION "UNSET"
|
||||||
@ -80,6 +80,12 @@
|
|||||||
*/
|
*/
|
||||||
#define XBPS_PKGDB "pkgdb-0.21.plist"
|
#define XBPS_PKGDB "pkgdb-0.21.plist"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @def XBPS_REPOKEYS
|
||||||
|
* Filename for the repository keys.
|
||||||
|
*/
|
||||||
|
#define XBPS_REPOKEYS "repokeys.plist"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @def XBPS_PKGPROPS
|
* @def XBPS_PKGPROPS
|
||||||
* Filename for package metadata property list.
|
* Filename for package metadata property list.
|
||||||
@ -93,16 +99,22 @@
|
|||||||
#define XBPS_PKGFILES "files.plist"
|
#define XBPS_PKGFILES "files.plist"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @def XBPS_PKGINDEX
|
* @def XBPS_REPOIDX
|
||||||
* Filename for the repository package index property list.
|
* Filename for the repository index property list.
|
||||||
*/
|
*/
|
||||||
#define XBPS_PKGINDEX "index.plist"
|
#define XBPS_REPOIDX "index.plist"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @def XBPS_PKGINDEX_FILES
|
* @def XBPS_REPOIDX_FILES
|
||||||
* Filename for the repository package index files property list.
|
* Filename for the repository index files property list.
|
||||||
*/
|
*/
|
||||||
#define XBPS_PKGINDEX_FILES "index-files.plist"
|
#define XBPS_REPOIDX_FILES "index-files.plist"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @def XBPS_REPOMETA
|
||||||
|
* Filename for the repository metadata property list.
|
||||||
|
*/
|
||||||
|
#define XBPS_REPOMETA "meta.plist"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @def XBPS_SYSCONF_PATH
|
* @def XBPS_SYSCONF_PATH
|
||||||
@ -238,6 +250,9 @@ extern "C" {
|
|||||||
* - XBPS_STATE_UPDATE_FAIL: package update has failed.
|
* - XBPS_STATE_UPDATE_FAIL: package update has failed.
|
||||||
* - XBPS_STATE_UNPACK_FAIL: package unpack has failed.
|
* - XBPS_STATE_UNPACK_FAIL: package unpack has failed.
|
||||||
* - XBPS_STATE_REPOSYNC_FAIL: syncing remote repositories has failed.
|
* - XBPS_STATE_REPOSYNC_FAIL: syncing remote repositories has failed.
|
||||||
|
* - XBPS_STATE_REPO_KEY_IMPORT: repository is signed and needs to import pubkey.
|
||||||
|
* - XBPS_STATE_REPO_SIGVERIFIED: repository is signed and verified.
|
||||||
|
* - XBPS_STATE_REPO_SIGUNVERIFIED: repository is signed and UNVERIFIED.
|
||||||
*/
|
*/
|
||||||
typedef enum xbps_state {
|
typedef enum xbps_state {
|
||||||
XBPS_STATE_UNKNOWN = 0,
|
XBPS_STATE_UNKNOWN = 0,
|
||||||
@ -274,7 +289,10 @@ typedef enum xbps_state {
|
|||||||
XBPS_STATE_UPDATE_FAIL,
|
XBPS_STATE_UPDATE_FAIL,
|
||||||
XBPS_STATE_UNPACK_FAIL,
|
XBPS_STATE_UNPACK_FAIL,
|
||||||
XBPS_STATE_REPOSYNC_FAIL,
|
XBPS_STATE_REPOSYNC_FAIL,
|
||||||
XBPS_STATE_CONFIGURE_DONE
|
XBPS_STATE_CONFIGURE_DONE,
|
||||||
|
XBPS_STATE_REPO_KEY_IMPORT,
|
||||||
|
XBPS_STATE_REPO_SIGVERIFIED,
|
||||||
|
XBPS_STATE_REPO_SIGUNVERIFIED
|
||||||
} xbps_state_t;
|
} xbps_state_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -485,7 +503,7 @@ struct xbps_handle {
|
|||||||
* Pointer to the supplifed function callback to be used
|
* Pointer to the supplifed function callback to be used
|
||||||
* in the XBPS possible states.
|
* in the XBPS possible states.
|
||||||
*/
|
*/
|
||||||
void (*state_cb)(struct xbps_state_cb_data *, void *);
|
int (*state_cb)(struct xbps_state_cb_data *, void *);
|
||||||
/**
|
/**
|
||||||
* @var state_cb_data
|
* @var state_cb_data
|
||||||
*
|
*
|
||||||
@ -1086,6 +1104,7 @@ xbps_dictionary_t xbps_get_pkg_plist_from_binpkg(const char *fname,
|
|||||||
/** @addtogroup repopool */
|
/** @addtogroup repopool */
|
||||||
/*@{*/
|
/*@{*/
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @struct xbps_repo xbps.h "xbps.h"
|
* @struct xbps_repo xbps.h "xbps.h"
|
||||||
* @brief Repository structure
|
* @brief Repository structure
|
||||||
@ -1110,17 +1129,36 @@ struct xbps_repo {
|
|||||||
* 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 meta
|
||||||
|
*
|
||||||
|
* Proplib dictionary associated with the repository metadata.
|
||||||
|
*/
|
||||||
|
xbps_dictionary_t meta;
|
||||||
/**
|
/**
|
||||||
* @var uri
|
* @var uri
|
||||||
*
|
*
|
||||||
* URI string associated with repository.
|
* URI string associated with repository.
|
||||||
*/
|
*/
|
||||||
const char *uri;
|
const char *uri;
|
||||||
|
/**
|
||||||
|
* var is_signed
|
||||||
|
*
|
||||||
|
* True if this repository has been signed, false otherwise.
|
||||||
|
* (read-only).
|
||||||
|
*/
|
||||||
|
bool is_signed;
|
||||||
|
/**
|
||||||
|
* var is_verified
|
||||||
|
*
|
||||||
|
* True if this repository has been signed and verified against its public key.
|
||||||
|
* False if the stored public key did not match its signature.
|
||||||
|
*/
|
||||||
|
bool is_verified;
|
||||||
/**
|
/**
|
||||||
* @var xhp
|
* @var xhp
|
||||||
*
|
*
|
||||||
* Pointer to our xbps_handle struct passed to xbps_rpool_foreach.
|
* Pointer to our xbps_handle struct passed to xbps_rpool_foreach.
|
||||||
* (read-only).
|
|
||||||
*/
|
*/
|
||||||
struct xbps_handle *xhp;
|
struct xbps_handle *xhp;
|
||||||
};
|
};
|
||||||
@ -1154,8 +1192,8 @@ int xbps_rpool_sync(struct xbps_handle *xhp, const char *uri);
|
|||||||
* @return 0 on success, otherwise an errno value.
|
* @return 0 on success, otherwise an errno value.
|
||||||
*/
|
*/
|
||||||
int xbps_rpool_foreach(struct xbps_handle *xhp,
|
int xbps_rpool_foreach(struct xbps_handle *xhp,
|
||||||
int (*fn)(struct xbps_repo *, void *, bool *),
|
int (*fn)(struct xbps_repo *, void *, bool *),
|
||||||
void *arg);
|
void *arg);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Finds a package dictionary in the repository pool by specifying a
|
* Finds a package dictionary in the repository pool by specifying a
|
||||||
@ -1617,6 +1655,24 @@ int xbps_humanize_number(char *buf, int64_t bytes);
|
|||||||
*/
|
*/
|
||||||
int xbps_cmpver(const char *pkg1, const char *pkg2);
|
int xbps_cmpver(const char *pkg1, const char *pkg2);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts a RSA public key in PEM format to a hex fingerprint.
|
||||||
|
*
|
||||||
|
* @param[in] xhp The pointer to an xbps_handle struct.
|
||||||
|
* @param[in] pubkey The public-key in PEM format as xbps_data_t.
|
||||||
|
*
|
||||||
|
* @return The hex fingerprint. The returned buffer must be free(3)d
|
||||||
|
* when necessary.
|
||||||
|
*/
|
||||||
|
unsigned char *xbps_pubkey2fp(struct xbps_handle *xhp, xbps_data_t pubkey);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prints to stdout the hex fingerprint of a public key.
|
||||||
|
*
|
||||||
|
* @param[in] fp String returned by xbps_pubkey2fp();
|
||||||
|
*/
|
||||||
|
void xbps_print_hexfp(const char *fp);
|
||||||
|
|
||||||
/*@}*/
|
/*@}*/
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
@ -159,6 +159,14 @@ int HIDDEN xbps_entry_install_conf_file(struct xbps_handle *,
|
|||||||
const char *,
|
const char *,
|
||||||
const char *,
|
const char *,
|
||||||
const char *);
|
const char *);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
* From lib/repo_keys.c
|
||||||
|
*/
|
||||||
|
int HIDDEN xbps_repo_key_import(struct xbps_repo *);
|
||||||
|
int HIDDEN xbps_repo_key_verify(struct xbps_repo *);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
* From lib/repo_pkgdeps.c
|
* From lib/repo_pkgdeps.c
|
||||||
@ -225,8 +233,8 @@ int HIDDEN xbps_file_exec(struct xbps_handle *, const char *, ...);
|
|||||||
*/
|
*/
|
||||||
void HIDDEN xbps_set_cb_fetch(struct xbps_handle *, off_t, off_t, off_t,
|
void HIDDEN xbps_set_cb_fetch(struct xbps_handle *, off_t, off_t, off_t,
|
||||||
const char *, bool, bool, bool);
|
const char *, bool, bool, bool);
|
||||||
void HIDDEN xbps_set_cb_state(struct xbps_handle *, xbps_state_t, int,
|
int HIDDEN xbps_set_cb_state(struct xbps_handle *, xbps_state_t, int,
|
||||||
const char *, const char *, ...);
|
const char *, const char *, ...);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
|
@ -38,11 +38,11 @@ OBJS += package_remove.o package_find_obsoletes.o package_state.o
|
|||||||
OBJS += package_unpack.o package_register.o package_script.o
|
OBJS += package_unpack.o package_register.o package_script.o
|
||||||
OBJS += transaction_commit.o transaction_package_replace.o
|
OBJS += transaction_commit.o transaction_package_replace.o
|
||||||
OBJS += transaction_dictionary.o transaction_sortdeps.o transaction_ops.o
|
OBJS += transaction_dictionary.o transaction_sortdeps.o transaction_ops.o
|
||||||
OBJS += transaction_revdeps.o
|
OBJS += transaction_revdeps.o pubkey2fp.o
|
||||||
OBJS += download.o initend.o pkgdb.o package_conflicts.o
|
OBJS += download.o initend.o pkgdb.o package_conflicts.o
|
||||||
OBJS += plist.o plist_find.o plist_match.o archive.o
|
OBJS += plist.o plist_find.o plist_match.o archive.o
|
||||||
OBJS += plist_remove.o plist_fetch.o util.o util_hash.o
|
OBJS += plist_remove.o plist_fetch.o util.o util_hash.o
|
||||||
OBJS += repo.o repo_pkgdeps.o repo_sync.o
|
OBJS += repo.o repo_pkgdeps.o repo_sync.o repo_keys.o
|
||||||
OBJS += rpool.o rpool_get.o cb_util.o proplib_wrapper.o
|
OBJS += rpool.o rpool_get.o cb_util.o proplib_wrapper.o
|
||||||
OBJS += $(EXTOBJS) $(COMPAT_SRCS)
|
OBJS += $(EXTOBJS) $(COMPAT_SRCS)
|
||||||
|
|
||||||
|
@ -70,7 +70,7 @@ xbps_set_cb_fetch(struct xbps_handle *xhp,
|
|||||||
(*xhp->fetch_cb)(&xfcd, xhp->fetch_cb_data);
|
(*xhp->fetch_cb)(&xfcd, xhp->fetch_cb_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
void HIDDEN
|
int HIDDEN
|
||||||
xbps_set_cb_state(struct xbps_handle *xhp,
|
xbps_set_cb_state(struct xbps_handle *xhp,
|
||||||
xbps_state_t state,
|
xbps_state_t state,
|
||||||
int err,
|
int err,
|
||||||
@ -84,7 +84,7 @@ xbps_set_cb_state(struct xbps_handle *xhp,
|
|||||||
int retval;
|
int retval;
|
||||||
|
|
||||||
if (xhp->state_cb == NULL)
|
if (xhp->state_cb == NULL)
|
||||||
return;
|
return 0;
|
||||||
|
|
||||||
xscd.xhp = xhp;
|
xscd.xhp = xhp;
|
||||||
xscd.state = state;
|
xscd.state = state;
|
||||||
@ -99,7 +99,9 @@ xbps_set_cb_state(struct xbps_handle *xhp,
|
|||||||
else
|
else
|
||||||
xscd.desc = buf;
|
xscd.desc = buf;
|
||||||
}
|
}
|
||||||
(*xhp->state_cb)(&xscd, xhp->state_cb_data);
|
retval = (*xhp->state_cb)(&xscd, xhp->state_cb_data);
|
||||||
if (buf != NULL)
|
if (buf != NULL)
|
||||||
free(buf);
|
free(buf);
|
||||||
|
|
||||||
|
return retval;
|
||||||
}
|
}
|
||||||
|
143
lib/pubkey2fp.c
Normal file
143
lib/pubkey2fp.c
Normal file
@ -0,0 +1,143 @@
|
|||||||
|
/*
|
||||||
|
* An implementation of convertion from OpenSSL to OpenSSH public key format
|
||||||
|
*
|
||||||
|
* Copyright (c) 2008 Mounir IDRASSI <mounir.idrassi@idrix.fr>. All rights reserved.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
*/
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
#include <openssl/bio.h>
|
||||||
|
#include <openssl/evp.h>
|
||||||
|
#include <openssl/pem.h>
|
||||||
|
#include <openssl/err.h>
|
||||||
|
|
||||||
|
#include "xbps_api_impl.h"
|
||||||
|
|
||||||
|
static unsigned char pSshHeader[11] = {
|
||||||
|
0x00, 0x00, 0x00, 0x07, 0x73, 0x73, 0x68, 0x2D, 0x72, 0x73, 0x61
|
||||||
|
};
|
||||||
|
|
||||||
|
static
|
||||||
|
int SshEncodeBuffer(unsigned char *pEncoding, int bufferLen,
|
||||||
|
unsigned char *pBuffer)
|
||||||
|
{
|
||||||
|
int adjustedLen = bufferLen, index;
|
||||||
|
|
||||||
|
if (*pBuffer & 0x80) {
|
||||||
|
adjustedLen++;
|
||||||
|
pEncoding[4] = 0;
|
||||||
|
index = 5;
|
||||||
|
} else {
|
||||||
|
index = 4;
|
||||||
|
}
|
||||||
|
pEncoding[0] = (unsigned char) (adjustedLen >> 24);
|
||||||
|
pEncoding[1] = (unsigned char) (adjustedLen >> 16);
|
||||||
|
pEncoding[2] = (unsigned char) (adjustedLen >> 8);
|
||||||
|
pEncoding[3] = (unsigned char) (adjustedLen );
|
||||||
|
memcpy(&pEncoding[index], pBuffer, bufferLen);
|
||||||
|
return index + bufferLen;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char *
|
||||||
|
xbps_pubkey2fp(struct xbps_handle *xhp, xbps_data_t pubkey)
|
||||||
|
{
|
||||||
|
EVP_MD_CTX mdctx;
|
||||||
|
EVP_PKEY *pPubKey = NULL;
|
||||||
|
RSA *pRsa = NULL;
|
||||||
|
BIO *bio = NULL;
|
||||||
|
const void *pubkeydata;
|
||||||
|
unsigned char *fpstr = NULL, md_value[EVP_MAX_MD_SIZE];
|
||||||
|
unsigned char *nBytes = NULL, *eBytes = NULL, *pEncoding = NULL;
|
||||||
|
unsigned int md_len = 0;
|
||||||
|
int index = 0, nLen = 0, eLen = 0, encodingLength = 0;
|
||||||
|
|
||||||
|
ERR_load_crypto_strings();
|
||||||
|
OpenSSL_add_all_algorithms();
|
||||||
|
|
||||||
|
pubkeydata = xbps_data_data_nocopy(pubkey);
|
||||||
|
bio = BIO_new_mem_buf(__UNCONST(pubkeydata), xbps_data_size(pubkey));
|
||||||
|
assert(bio);
|
||||||
|
|
||||||
|
pPubKey = PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL);
|
||||||
|
if (!pPubKey) {
|
||||||
|
xbps_dbg_printf(xhp,
|
||||||
|
"unable to decode public key from the given file: %s\n",
|
||||||
|
ERR_error_string(ERR_get_error(), NULL));
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (EVP_PKEY_type(pPubKey->type) != EVP_PKEY_RSA) {
|
||||||
|
xbps_dbg_printf(xhp, "only RSA public keys are currently supported\n");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
pRsa = EVP_PKEY_get1_RSA(pPubKey);
|
||||||
|
if (!pRsa) {
|
||||||
|
xbps_dbg_printf(xhp, "failed to get RSA public key : %s\n",
|
||||||
|
ERR_error_string(ERR_get_error(), NULL));
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
// reading the modulus
|
||||||
|
nLen = BN_num_bytes(pRsa->n);
|
||||||
|
nBytes = (unsigned char*) malloc(nLen);
|
||||||
|
BN_bn2bin(pRsa->n, nBytes);
|
||||||
|
|
||||||
|
// reading the public exponent
|
||||||
|
eLen = BN_num_bytes(pRsa->e);
|
||||||
|
eBytes = (unsigned char*) malloc(eLen);
|
||||||
|
BN_bn2bin(pRsa->e, eBytes);
|
||||||
|
|
||||||
|
encodingLength = 11 + 4 + eLen + 4 + nLen;
|
||||||
|
// correct depending on the MSB of e and N
|
||||||
|
if (eBytes[0] & 0x80)
|
||||||
|
encodingLength++;
|
||||||
|
if (nBytes[0] & 0x80)
|
||||||
|
encodingLength++;
|
||||||
|
|
||||||
|
pEncoding = malloc(encodingLength);
|
||||||
|
memcpy(pEncoding, pSshHeader, 11);
|
||||||
|
|
||||||
|
index = SshEncodeBuffer(&pEncoding[11], eLen, eBytes);
|
||||||
|
index = SshEncodeBuffer(&pEncoding[11 + index], nLen, nBytes);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Compute the RSA fingerprint (MD5).
|
||||||
|
*/
|
||||||
|
EVP_MD_CTX_init(&mdctx);
|
||||||
|
EVP_DigestInit_ex(&mdctx, EVP_md5(), NULL);
|
||||||
|
assert(EVP_DigestUpdate(&mdctx, pEncoding, encodingLength) != -1);
|
||||||
|
assert(EVP_DigestFinal_ex(&mdctx, md_value, &md_len) != -1);
|
||||||
|
EVP_MD_CTX_cleanup(&mdctx);
|
||||||
|
|
||||||
|
fpstr = malloc(md_len+1);
|
||||||
|
for (unsigned int i = 0; i < md_len; i++)
|
||||||
|
fpstr[i] = md_value[i];
|
||||||
|
|
||||||
|
fpstr[md_len] = '\0';
|
||||||
|
|
||||||
|
error:
|
||||||
|
if (bio)
|
||||||
|
BIO_free_all(bio);
|
||||||
|
if (pRsa)
|
||||||
|
RSA_free(pRsa);
|
||||||
|
if (pPubKey)
|
||||||
|
EVP_PKEY_free(pPubKey);
|
||||||
|
if (nBytes)
|
||||||
|
free(nBytes);
|
||||||
|
if (eBytes)
|
||||||
|
free(eBytes);
|
||||||
|
if (pEncoding)
|
||||||
|
free(pEncoding);
|
||||||
|
|
||||||
|
EVP_cleanup();
|
||||||
|
ERR_free_strings();
|
||||||
|
|
||||||
|
return fpstr;
|
||||||
|
}
|
44
lib/repo.c
44
lib/repo.c
@ -88,16 +88,17 @@ xbps_repo_open(struct xbps_handle *xhp, const char *url)
|
|||||||
archive_read_support_format_tar(repo->ar);
|
archive_read_support_format_tar(repo->ar);
|
||||||
|
|
||||||
if (stat(repofile, &st) == -1) {
|
if (stat(repofile, &st) == -1) {
|
||||||
xbps_dbg_printf(xhp, "[repo] cannot stat repository file %s: %s\n",
|
xbps_dbg_printf(xhp, "[repo] `%s' missing repodata %s: %s\n",
|
||||||
repofile, strerror(errno));
|
url, repofile, strerror(errno));
|
||||||
archive_read_finish(repo->ar);
|
archive_read_finish(repo->ar);
|
||||||
free(repo);
|
free(repo);
|
||||||
repo = NULL;
|
repo = NULL;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
if (archive_read_open_filename(repo->ar, repofile, st.st_blksize) == ARCHIVE_FATAL) {
|
if (archive_read_open_filename(repo->ar, repofile, st.st_blksize) == ARCHIVE_FATAL) {
|
||||||
xbps_dbg_printf(xhp, "[repo] cannot open repository file %s: %s\n",
|
xbps_dbg_printf(xhp,
|
||||||
repofile, strerror(archive_errno(repo->ar)));
|
"[repo] `%s' failed to open repodata archive %s: %s\n",
|
||||||
|
url, repofile, strerror(archive_errno(repo->ar)));
|
||||||
archive_read_finish(repo->ar);
|
archive_read_finish(repo->ar);
|
||||||
free(repo);
|
free(repo);
|
||||||
repo = NULL;
|
repo = NULL;
|
||||||
@ -152,15 +153,21 @@ xbps_repo_close(struct xbps_repo *repo)
|
|||||||
{
|
{
|
||||||
assert(repo);
|
assert(repo);
|
||||||
|
|
||||||
if (repo->ar == NULL)
|
if (repo->ar != NULL)
|
||||||
return;
|
archive_read_finish(repo->ar);
|
||||||
|
|
||||||
archive_read_finish(repo->ar);
|
if (repo->meta != NULL) {
|
||||||
if (xbps_object_type(repo->idx) == XBPS_TYPE_DICTIONARY)
|
xbps_object_release(repo->meta);
|
||||||
|
repo->meta = NULL;
|
||||||
|
}
|
||||||
|
if (repo->idx != NULL) {
|
||||||
xbps_object_release(repo->idx);
|
xbps_object_release(repo->idx);
|
||||||
if (xbps_object_type(repo->idxfiles) == XBPS_TYPE_DICTIONARY)
|
repo->idx = NULL;
|
||||||
|
}
|
||||||
|
if (repo->idxfiles != NULL) {
|
||||||
xbps_object_release(repo->idxfiles);
|
xbps_object_release(repo->idxfiles);
|
||||||
free(repo);
|
repo->idxfiles = NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
xbps_dictionary_t
|
xbps_dictionary_t
|
||||||
@ -171,14 +178,9 @@ xbps_repo_get_virtualpkg(struct xbps_repo *repo, const char *pkg)
|
|||||||
assert(repo);
|
assert(repo);
|
||||||
assert(pkg);
|
assert(pkg);
|
||||||
|
|
||||||
if (repo->ar == NULL)
|
if (repo->ar == NULL || repo->idx == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
if (xbps_object_type(repo->idx) != XBPS_TYPE_DICTIONARY) {
|
|
||||||
repo->idx = xbps_repo_get_plist(repo, XBPS_PKGINDEX);
|
|
||||||
if (repo->idx == NULL)
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
pkgd = xbps_find_virtualpkg_in_dict(repo->xhp, repo->idx, pkg);
|
pkgd = xbps_find_virtualpkg_in_dict(repo->xhp, repo->idx, pkg);
|
||||||
if (pkgd) {
|
if (pkgd) {
|
||||||
xbps_dictionary_set_cstring_nocopy(pkgd,
|
xbps_dictionary_set_cstring_nocopy(pkgd,
|
||||||
@ -196,14 +198,9 @@ xbps_repo_get_pkg(struct xbps_repo *repo, const char *pkg)
|
|||||||
assert(repo);
|
assert(repo);
|
||||||
assert(pkg);
|
assert(pkg);
|
||||||
|
|
||||||
if (repo->ar == NULL)
|
if (repo->ar == NULL || repo->idx == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
if (xbps_object_type(repo->idx) != XBPS_TYPE_DICTIONARY) {
|
|
||||||
repo->idx = xbps_repo_get_plist(repo, XBPS_PKGINDEX);
|
|
||||||
if (repo->idx == NULL)
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
pkgd = xbps_find_pkg_in_dict(repo->idx, pkg);
|
pkgd = xbps_find_pkg_in_dict(repo->idx, pkg);
|
||||||
if (pkgd) {
|
if (pkgd) {
|
||||||
xbps_dictionary_set_cstring_nocopy(pkgd,
|
xbps_dictionary_set_cstring_nocopy(pkgd,
|
||||||
@ -336,6 +333,9 @@ xbps_repo_get_pkg_revdeps(struct xbps_repo *repo, const char *pkg)
|
|||||||
char *buf = NULL;
|
char *buf = NULL;
|
||||||
bool match = false;
|
bool match = false;
|
||||||
|
|
||||||
|
if (repo->idx == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
if (((pkgd = xbps_rpool_get_pkg(repo->xhp, pkg)) == NULL) &&
|
if (((pkgd = xbps_rpool_get_pkg(repo->xhp, pkg)) == NULL) &&
|
||||||
((pkgd = xbps_rpool_get_virtualpkg(repo->xhp, pkg)) == NULL)) {
|
((pkgd = xbps_rpool_get_virtualpkg(repo->xhp, pkg)) == NULL)) {
|
||||||
errno = ENOENT;
|
errno = ENOENT;
|
||||||
|
233
lib/repo_keys.c
Normal file
233
lib/repo_keys.c
Normal file
@ -0,0 +1,233 @@
|
|||||||
|
/*-
|
||||||
|
* Copyright (c) 2013 Juan Romero Pardines.
|
||||||
|
* 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 AUTHOR ``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 AUTHOR 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 <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
#include <openssl/err.h>
|
||||||
|
#include <openssl/sha.h>
|
||||||
|
#include <openssl/rsa.h>
|
||||||
|
#include <openssl/ssl.h>
|
||||||
|
#include <openssl/pem.h>
|
||||||
|
|
||||||
|
#include "xbps_api_impl.h"
|
||||||
|
|
||||||
|
int HIDDEN
|
||||||
|
xbps_repo_key_import(struct xbps_repo *repo)
|
||||||
|
{
|
||||||
|
xbps_dictionary_t repokeyd, rkeysd = NULL, newmetad = NULL;
|
||||||
|
xbps_data_t rpubkey;
|
||||||
|
const char *signedby;
|
||||||
|
unsigned char *fp;
|
||||||
|
char *rkeypath = NULL;
|
||||||
|
int import, rv = 0;
|
||||||
|
|
||||||
|
assert(repo);
|
||||||
|
/*
|
||||||
|
* If repository does not have required metadata plist, ignore it.
|
||||||
|
*/
|
||||||
|
if (xbps_dictionary_count(repo->meta) == 0) {
|
||||||
|
xbps_dbg_printf(repo->xhp,
|
||||||
|
"[repo] `%s' missing required metadata, ignoring.\n", repo->uri);
|
||||||
|
repo->is_verified = false;
|
||||||
|
repo->is_signed = false;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* Check the repository provides a working public-key data object.
|
||||||
|
*/
|
||||||
|
rpubkey = xbps_dictionary_get(repo->meta, "public-key");
|
||||||
|
if (xbps_object_type(rpubkey) != XBPS_TYPE_DATA) {
|
||||||
|
rv = EINVAL;
|
||||||
|
xbps_dbg_printf(repo->xhp,
|
||||||
|
"[repo] `%s' invalid public-key object!\n", repo->uri);
|
||||||
|
repo->is_verified = false;
|
||||||
|
repo->is_signed = false;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
repo->is_signed = true;
|
||||||
|
/*
|
||||||
|
* Check if the public key has been stored for this repository.
|
||||||
|
*/
|
||||||
|
rkeypath = xbps_xasprintf("%s/%s", repo->xhp->metadir, XBPS_REPOKEYS);
|
||||||
|
rkeysd = xbps_dictionary_internalize_from_file(rkeypath);
|
||||||
|
if (xbps_object_type(rkeysd) != XBPS_TYPE_DICTIONARY)
|
||||||
|
rkeysd = xbps_dictionary_create();
|
||||||
|
|
||||||
|
repokeyd = xbps_dictionary_get(rkeysd, repo->uri);
|
||||||
|
if (xbps_object_type(repokeyd) == XBPS_TYPE_DICTIONARY) {
|
||||||
|
if (xbps_dictionary_get(repokeyd, "public-key")) {
|
||||||
|
xbps_dbg_printf(repo->xhp,
|
||||||
|
"[repo] `%s' public key already stored.\n",
|
||||||
|
repo->uri);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* Notify the client and take appropiate action to import
|
||||||
|
* the repository public key. Pass back the public key openssh fingerprint
|
||||||
|
* to the client.
|
||||||
|
*/
|
||||||
|
fp = xbps_pubkey2fp(repo->xhp, rpubkey);
|
||||||
|
xbps_dictionary_get_cstring_nocopy(repo->meta, "signature-by", &signedby);
|
||||||
|
import = xbps_set_cb_state(repo->xhp, XBPS_STATE_REPO_KEY_IMPORT,
|
||||||
|
0, (const char *)fp,
|
||||||
|
"This repository is RSA signed by \"%s\"",
|
||||||
|
signedby);
|
||||||
|
free(fp);
|
||||||
|
if (import <= 0)
|
||||||
|
goto out;
|
||||||
|
/*
|
||||||
|
* Add the meta dictionary into XBPS_REPOKEYS and externalize it.
|
||||||
|
*/
|
||||||
|
newmetad = xbps_dictionary_copy_mutable(repo->meta);
|
||||||
|
xbps_dictionary_remove(newmetad, "signature");
|
||||||
|
xbps_dictionary_set(rkeysd, repo->uri, newmetad);
|
||||||
|
|
||||||
|
if (access(repo->xhp->metadir, R_OK|W_OK) == -1) {
|
||||||
|
if (errno == ENOENT) {
|
||||||
|
xbps_mkpath(repo->xhp->metadir, 0755);
|
||||||
|
} else {
|
||||||
|
rv = errno;
|
||||||
|
xbps_dbg_printf(repo->xhp,
|
||||||
|
"[repo] `%s' cannot create metadir: %s\n",
|
||||||
|
repo->uri, strerror(errno));
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!xbps_dictionary_externalize_to_file(rkeysd, rkeypath)) {
|
||||||
|
rv = errno;
|
||||||
|
xbps_dbg_printf(repo->xhp,
|
||||||
|
"[repo] `%s' failed to externalize %s: %s\n",
|
||||||
|
repo->uri, XBPS_REPOKEYS, strerror(rv));
|
||||||
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
if (newmetad)
|
||||||
|
xbps_object_release(newmetad);
|
||||||
|
if (xbps_object_type(rkeysd) == XBPS_TYPE_DICTIONARY)
|
||||||
|
xbps_object_release(rkeysd);
|
||||||
|
free(rkeypath);
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
rsa_verify_buf(struct xbps_repo *repo, xbps_data_t sigdata,
|
||||||
|
xbps_data_t pubkey, const char *buf)
|
||||||
|
{
|
||||||
|
SHA256_CTX context;
|
||||||
|
BIO *bio;
|
||||||
|
RSA *rsa;
|
||||||
|
unsigned char sha256[SHA256_DIGEST_LENGTH];
|
||||||
|
int rv = 0;
|
||||||
|
|
||||||
|
ERR_load_crypto_strings();
|
||||||
|
SSL_load_error_strings();
|
||||||
|
OpenSSL_add_all_algorithms();
|
||||||
|
OpenSSL_add_all_ciphers();
|
||||||
|
|
||||||
|
bio = BIO_new_mem_buf(__UNCONST(xbps_data_data_nocopy(pubkey)),
|
||||||
|
xbps_data_size(pubkey));
|
||||||
|
assert(bio);
|
||||||
|
|
||||||
|
rsa = PEM_read_bio_RSA_PUBKEY(bio, NULL, NULL, NULL);
|
||||||
|
if (rsa == NULL) {
|
||||||
|
xbps_dbg_printf(repo->xhp,
|
||||||
|
"[repo] `%s' error reading public key: %s\n",
|
||||||
|
repo->uri, ERR_error_string(ERR_get_error(), NULL));
|
||||||
|
return EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
SHA256_Init(&context);
|
||||||
|
SHA256_Update(&context, buf, strlen(buf));
|
||||||
|
SHA256_Final(sha256, &context);
|
||||||
|
|
||||||
|
if (RSA_verify(NID_sha1, sha256, sizeof(sha256),
|
||||||
|
xbps_data_data_nocopy(sigdata),
|
||||||
|
xbps_data_size(sigdata), rsa) == 0) {
|
||||||
|
xbps_dbg_printf(repo->xhp,
|
||||||
|
"[repo] `%s' failed to verify signature: %s\n",
|
||||||
|
repo->uri, ERR_error_string(ERR_get_error(), NULL));
|
||||||
|
rv = EPERM;
|
||||||
|
}
|
||||||
|
RSA_free(rsa);
|
||||||
|
BIO_free(bio);
|
||||||
|
ERR_free_strings();
|
||||||
|
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
int HIDDEN
|
||||||
|
xbps_repo_key_verify(struct xbps_repo *repo)
|
||||||
|
{
|
||||||
|
xbps_dictionary_t rkeysd, repokeyd;
|
||||||
|
xbps_data_t sigdata, pubkey;
|
||||||
|
char *rkeyspath, *idx_xml;
|
||||||
|
bool verified = false;
|
||||||
|
|
||||||
|
/* unsigned repo */
|
||||||
|
if (!repo->is_signed) {
|
||||||
|
xbps_dbg_printf(repo->xhp,
|
||||||
|
"[repo] `%s' ignoring unsigned repository.\n", repo->uri);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
rkeyspath = xbps_xasprintf("%s/%s", repo->xhp->metadir, XBPS_REPOKEYS);
|
||||||
|
rkeysd = xbps_dictionary_internalize_from_file(rkeyspath);
|
||||||
|
if (xbps_dictionary_count(rkeysd) == 0) {
|
||||||
|
xbps_dbg_printf(repo->xhp,
|
||||||
|
"[repo] `%s': failed to internalize %s: %s\n",
|
||||||
|
repo->uri, rkeyspath, strerror(errno));
|
||||||
|
free(rkeyspath);
|
||||||
|
return ENODEV;
|
||||||
|
}
|
||||||
|
free(rkeyspath);
|
||||||
|
|
||||||
|
repokeyd = xbps_dictionary_get(rkeysd, repo->uri);
|
||||||
|
if (xbps_dictionary_count(repokeyd) == 0) {
|
||||||
|
xbps_dbg_printf(repo->xhp,
|
||||||
|
"[repo] `%s': empty %s dictionary\n",
|
||||||
|
repo->uri, XBPS_REPOKEYS);
|
||||||
|
xbps_object_release(rkeysd);
|
||||||
|
return ENOENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
idx_xml = xbps_dictionary_externalize(repo->idx);
|
||||||
|
assert(idx_xml);
|
||||||
|
|
||||||
|
sigdata = xbps_dictionary_get(repo->meta, "signature");
|
||||||
|
assert(xbps_object_type(sigdata) == XBPS_TYPE_DATA);
|
||||||
|
pubkey = xbps_dictionary_get(repokeyd, "public-key");
|
||||||
|
assert(xbps_object_type(pubkey) == XBPS_TYPE_DATA);
|
||||||
|
/* XXX ignore 'signature-type' for now */
|
||||||
|
if (rsa_verify_buf(repo, sigdata, pubkey, idx_xml) == 0) {
|
||||||
|
repo->is_verified = true;
|
||||||
|
verified = true;
|
||||||
|
}
|
||||||
|
free(idx_xml);
|
||||||
|
|
||||||
|
return verified ? 0 : EPERM;
|
||||||
|
}
|
68
lib/rpool.c
68
lib/rpool.c
@ -53,7 +53,7 @@ xbps_rpool_init(struct xbps_handle *xhp)
|
|||||||
struct rpool *rp;
|
struct rpool *rp;
|
||||||
const char *repouri;
|
const char *repouri;
|
||||||
bool foundrepo = false;
|
bool foundrepo = false;
|
||||||
int rv = 0;
|
int retval, rv = 0;
|
||||||
|
|
||||||
assert(xhp);
|
assert(xhp);
|
||||||
|
|
||||||
@ -65,15 +65,59 @@ xbps_rpool_init(struct xbps_handle *xhp)
|
|||||||
assert(rp);
|
assert(rp);
|
||||||
xbps_array_get_cstring_nocopy(xhp->repositories, i, &repouri);
|
xbps_array_get_cstring_nocopy(xhp->repositories, i, &repouri);
|
||||||
if ((rp->repo = xbps_repo_open(xhp, repouri)) == NULL) {
|
if ((rp->repo = xbps_repo_open(xhp, repouri)) == NULL) {
|
||||||
rp->repo = calloc(1, sizeof(struct xbps_repo));
|
rp->repo = malloc(sizeof(struct xbps_repo));
|
||||||
assert(rp->repo);
|
assert(rp->repo);
|
||||||
|
rp->repo->ar = NULL;
|
||||||
|
rp->repo->is_verified = false;
|
||||||
|
rp->repo->is_signed = false;
|
||||||
}
|
}
|
||||||
rp->repo->idx = xbps_repo_get_plist(rp->repo, XBPS_PKGINDEX);
|
rp->repo->idx = xbps_repo_get_plist(rp->repo, XBPS_REPOIDX);
|
||||||
|
if (xbps_object_type(rp->repo->idx) == XBPS_TYPE_DICTIONARY)
|
||||||
|
xbps_dictionary_make_immutable(rp->repo->idx);
|
||||||
|
|
||||||
|
rp->repo->meta = xbps_repo_get_plist(rp->repo, XBPS_REPOMETA);
|
||||||
|
if (xbps_object_type(rp->repo->meta) == XBPS_TYPE_DICTIONARY)
|
||||||
|
xbps_dictionary_make_immutable(rp->repo->meta);
|
||||||
|
|
||||||
rp->repo->uri = repouri;
|
rp->repo->uri = repouri;
|
||||||
rp->repo->xhp = xhp;
|
rp->repo->xhp = xhp;
|
||||||
|
|
||||||
|
if (xbps_repository_is_remote(repouri)) {
|
||||||
|
/*
|
||||||
|
* Import the RSA public key (if it's signed).
|
||||||
|
*/
|
||||||
|
retval = xbps_repo_key_import(rp->repo);
|
||||||
|
if (retval != 0) {
|
||||||
|
/* any error */
|
||||||
|
xbps_dbg_printf(xhp, "[rpool] %s: key_import %s\n",
|
||||||
|
rp->repo->uri, strerror(retval));
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* Check the repository signature against stored public key.
|
||||||
|
*/
|
||||||
|
retval = xbps_repo_key_verify(rp->repo);
|
||||||
|
if (retval == 0) {
|
||||||
|
/* signed, verified */
|
||||||
|
xbps_set_cb_state(xhp, XBPS_STATE_REPO_SIGVERIFIED, 0, NULL, NULL);
|
||||||
|
} else if (retval == EPERM) {
|
||||||
|
/* signed, unverified */
|
||||||
|
xbps_set_cb_state(xhp, XBPS_STATE_REPO_SIGUNVERIFIED, 0, NULL, NULL);
|
||||||
|
xbps_repo_close(rp->repo);
|
||||||
|
} else {
|
||||||
|
/* any error */
|
||||||
|
xbps_dbg_printf(xhp, "[rpool] %s: key_verify %s\n",
|
||||||
|
rp->repo->uri, strerror(retval));
|
||||||
|
xbps_repo_close(rp->repo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* If repository has passed signature checks, add it to the pool.
|
||||||
|
*/
|
||||||
SIMPLEQ_INSERT_TAIL(&rpool_queue, rp, entries);
|
SIMPLEQ_INSERT_TAIL(&rpool_queue, rp, entries);
|
||||||
foundrepo = true;
|
foundrepo = true;
|
||||||
xbps_dbg_printf(xhp, "[rpool] `%s' registered.\n", repouri);
|
xbps_dbg_printf(xhp, "[rpool] `%s' registered (%s, %s).\n",
|
||||||
|
repouri, rp->repo->is_signed ? "signed" : "unsigned",
|
||||||
|
rp->repo->is_verified ? "verified" : "unverified");
|
||||||
}
|
}
|
||||||
if (!foundrepo) {
|
if (!foundrepo) {
|
||||||
/* no repositories available, error out */
|
/* no repositories available, error out */
|
||||||
@ -101,6 +145,7 @@ xbps_rpool_release(struct xbps_handle *xhp)
|
|||||||
while ((rp = SIMPLEQ_FIRST(&rpool_queue))) {
|
while ((rp = SIMPLEQ_FIRST(&rpool_queue))) {
|
||||||
SIMPLEQ_REMOVE(&rpool_queue, rp, rpool, entries);
|
SIMPLEQ_REMOVE(&rpool_queue, rp, rpool, entries);
|
||||||
xbps_repo_close(rp->repo);
|
xbps_repo_close(rp->repo);
|
||||||
|
free(rp->repo);
|
||||||
free(rp);
|
free(rp);
|
||||||
}
|
}
|
||||||
xhp->rpool_initialized = false;
|
xhp->rpool_initialized = false;
|
||||||
@ -131,8 +176,8 @@ xbps_rpool_sync(struct xbps_handle *xhp, const char *uri)
|
|||||||
|
|
||||||
int
|
int
|
||||||
xbps_rpool_foreach(struct xbps_handle *xhp,
|
xbps_rpool_foreach(struct xbps_handle *xhp,
|
||||||
int (*fn)(struct xbps_repo *, void *, bool *),
|
int (*fn)(struct xbps_repo *, void *, bool *),
|
||||||
void *arg)
|
void *arg)
|
||||||
{
|
{
|
||||||
struct rpool *rp;
|
struct rpool *rp;
|
||||||
int rv = 0;
|
int rv = 0;
|
||||||
@ -142,21 +187,14 @@ xbps_rpool_foreach(struct xbps_handle *xhp,
|
|||||||
/* Initialize repository pool */
|
/* Initialize repository pool */
|
||||||
if ((rv = xbps_rpool_init(xhp)) != 0) {
|
if ((rv = xbps_rpool_init(xhp)) != 0) {
|
||||||
if (rv == ENOTSUP) {
|
if (rv == ENOTSUP) {
|
||||||
xbps_dbg_printf(xhp,
|
xbps_dbg_printf(xhp, "[rpool] empty repository list.\n");
|
||||||
"[rpool] empty repository list.\n");
|
|
||||||
} else if (rv != ENOENT && rv != ENOTSUP) {
|
} else if (rv != ENOENT && rv != ENOTSUP) {
|
||||||
xbps_dbg_printf(xhp,
|
xbps_dbg_printf(xhp, "[rpool] couldn't initialize: %s\n", strerror(rv));
|
||||||
"[rpool] couldn't initialize: %s\n",
|
|
||||||
strerror(rv));
|
|
||||||
}
|
}
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
/* Iterate over repository pool */
|
/* Iterate over repository pool */
|
||||||
SIMPLEQ_FOREACH(rp, &rpool_queue, entries) {
|
SIMPLEQ_FOREACH(rp, &rpool_queue, entries) {
|
||||||
/* ignore invalid repos */
|
|
||||||
if (rp->repo->idx == NULL)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
rv = (*fn)(rp->repo, arg, &done);
|
rv = (*fn)(rp->repo, arg, &done);
|
||||||
if (rv != 0 || done)
|
if (rv != 0 || done)
|
||||||
break;
|
break;
|
||||||
|
17
lib/util.c
17
lib/util.c
@ -297,3 +297,20 @@ xbps_humanize_number(char *buf, int64_t bytes)
|
|||||||
return humanize_number(buf, 7, bytes, "B",
|
return humanize_number(buf, 7, bytes, "B",
|
||||||
HN_AUTOSCALE, HN_DECIMAL|HN_NOSPACE);
|
HN_AUTOSCALE, HN_DECIMAL|HN_NOSPACE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
xbps_print_hexfp(const char *fp)
|
||||||
|
{
|
||||||
|
unsigned char *fpstr;
|
||||||
|
unsigned int i, c, len;
|
||||||
|
|
||||||
|
fpstr = (unsigned char *)(void *)(unsigned long)(const void *)fp;
|
||||||
|
len = strlen(fp);
|
||||||
|
|
||||||
|
for (i = 0; i < len; i++) {
|
||||||
|
printf("%02x", fpstr[i]);
|
||||||
|
c = i + 1;
|
||||||
|
if (c < len)
|
||||||
|
putchar(':');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -41,7 +41,7 @@ endif
|
|||||||
|
|
||||||
%.o: %.c
|
%.o: %.c
|
||||||
@printf " [CC]\t\t$@\n"
|
@printf " [CC]\t\t$@\n"
|
||||||
${SILENT}$(CC) $(CPPFLAGS) $(CFLAGS) -c $<
|
${SILENT}$(CC) $(CPPFLAGS) $(CFLAGS) $(EXTRA_CFLAGS) -c $<
|
||||||
|
|
||||||
$(BIN).static: $(OBJS)
|
$(BIN).static: $(OBJS)
|
||||||
@printf " [CCLD]\t\t$@\n"
|
@printf " [CCLD]\t\t$@\n"
|
||||||
|
Loading…
Reference in New Issue
Block a user