diff --git a/bin/xbps-install/main.c b/bin/xbps-install/main.c index 639847a6..ab4f0bb0 100644 --- a/bin/xbps-install/main.c +++ b/bin/xbps-install/main.c @@ -53,6 +53,7 @@ usage(bool fail) " -h, --help Show usage\n" " -i, --ignore-conf-repos Ignore repositories defined in xbps.d\n" " -I, --ignore-file-conflicts Ignore detected file conflicts\n" + " -k, --import-key Import specified key without confirmation\n" " -U, --unpack-only Unpack packages in transaction, do not configure them\n" " -M, --memory-sync Remote repository data is fetched and stored\n" " in memory, ignoring on-disk repodata archives\n" @@ -82,11 +83,11 @@ unpack_progress_cb(const struct xbps_unpack_cb_data *xpd, void *cbdata UNUSED) } static int -repo_import_key_cb(struct xbps_repo *repo, void *arg UNUSED, bool *done UNUSED) +repo_import_key_cb(struct xbps_repo *repo, void *expfps, bool *done UNUSED) { int rv; - if ((rv = xbps_repo_key_import(repo)) != 0) + if ((rv = xbps_repo_key_import(repo, expfps)) != 0) xbps_error_printf("Failed to import pubkey from %s: %s\n", repo->uri, strerror(rv)); @@ -96,7 +97,7 @@ repo_import_key_cb(struct xbps_repo *repo, void *arg UNUSED, bool *done UNUSED) int main(int argc, char **argv) { - const char *shortopts = "AC:c:DdfhIiMnR:r:SuUVvy"; + const char *shortopts = "AC:c:DdfhIik:MnR:r:SuUVvy"; const struct option longopts[] = { { "automatic", no_argument, NULL, 'A' }, { "config", required_argument, NULL, 'C' }, @@ -107,6 +108,7 @@ main(int argc, char **argv) { "help", no_argument, NULL, 'h' }, { "ignore-conf-repos", no_argument, NULL, 'i' }, { "ignore-file-conflicts", no_argument, NULL, 'I' }, + { "import-key", required_argument, NULL, 'k' }, { "memory-sync", no_argument, NULL, 'M' }, { "dry-run", no_argument, NULL, 'n' }, { "repository", required_argument, NULL, 'R' }, @@ -126,6 +128,7 @@ main(int argc, char **argv) int i, c, flags, rv, fflag = 0; bool syncf, yes, force, drun, update; int maxcols, eexist = 0; + xbps_array_t expfps = NULL; rootdir = cachedir = confdir = NULL; flags = rv = 0; @@ -168,6 +171,11 @@ main(int argc, char **argv) case 'i': flags |= XBPS_FLAG_IGNORE_CONF_REPOS; break; + case 'k': + if (expfps == NULL) + expfps = xbps_array_create(); + xbps_array_add_cstring_nocopy(expfps, optarg); + break; case 'M': flags |= XBPS_FLAG_REPOS_MEMSYNC; break; @@ -235,7 +243,7 @@ main(int argc, char **argv) if (syncf && !drun) { if ((rv = xbps_rpool_sync(&xh, NULL)) != 0) exit(rv); - rv = xbps_rpool_foreach(&xh, repo_import_key_cb, NULL); + rv = xbps_rpool_foreach(&xh, repo_import_key_cb, expfps); if (rv != 0) exit(rv); } diff --git a/bin/xbps-install/state_cb.c b/bin/xbps-install/state_cb.c index a13ebbaf..416e7466 100644 --- a/bin/xbps-install/state_cb.c +++ b/bin/xbps-install/state_cb.c @@ -155,6 +155,10 @@ state_cb(const struct xbps_state_cb_data *xscd, void *cbdata UNUSED) printf("Fingerprint: %s\n", xscd->arg); rv = yesno("Do you want to import this public key?"); break; + case XBPS_STATE_REPO_KEY_EXPECTED: + printf("%s\n", xscd->desc); + printf("Importing key with fingerprint: %s\n", xscd->arg); + break; case XBPS_STATE_SHOW_INSTALL_MSG: printf("%s: post-install message:\n", xscd->arg); printf("========================================================================\n"); diff --git a/bin/xbps-install/xbps-install.1 b/bin/xbps-install/xbps-install.1 index a68f3ed7..80c4d8ed 100644 --- a/bin/xbps-install/xbps-install.1 +++ b/bin/xbps-install/xbps-install.1 @@ -123,8 +123,14 @@ Ignore detected file conflicts in a transaction. .It Fl i , Fl -ignore-conf-repos Ignore repositories defined in configuration files. Only repositories specified in the command line via -.Ar --repository +.Fl -repository will be used. +.It Fl k , Fl -import-key Ar fingerprint +Import the key with the specified +.Ar fingerprint +without confirmation. +Specified keys will only be imported if the key is used by a remote repository and has not already been imported. +This option can be specified multiple times. .It Fl M , Fl -memory-sync For remote repositories, the data is fetched and stored in memory for the current operation. diff --git a/include/xbps.h.in b/include/xbps.h.in index 45025d03..6b0a0d20 100644 --- a/include/xbps.h.in +++ b/include/xbps.h.in @@ -316,6 +316,7 @@ extern "C" { * - XBPS_STATE_UNPACK_FAIL: package unpack 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_KEY_EXPECTED: repository is signed and will import expected pubkey. * - XBPS_STATE_INVALID_DEP: package has an invalid dependency. * - XBPS_STATE_SHOW_INSTALL_MSG: package must show a post-install message. * - XBPS_STATE_SHOW_REMOVE_MSG: package must show a pre-remove message. @@ -369,6 +370,7 @@ typedef enum xbps_state { XBPS_STATE_REPOSYNC_FAIL, XBPS_STATE_CONFIGURE_DONE, XBPS_STATE_REPO_KEY_IMPORT, + XBPS_STATE_REPO_KEY_EXPECTED, XBPS_STATE_INVALID_DEP, XBPS_STATE_SHOW_INSTALL_MSG, XBPS_STATE_SHOW_REMOVE_MSG, @@ -1755,10 +1757,11 @@ xbps_array_t xbps_repo_get_pkg_revdeps(struct xbps_repo *repo, const char *pkg); * signed properly for this to work. * * @param[in] repo Pointer to the target xbps_repo structure. + * @param[in] expfps Proplib array of expected key fingerprints. * * @return 0 on success, an errno value otherwise. */ -int xbps_repo_key_import(struct xbps_repo *repo); +int xbps_repo_key_import(struct xbps_repo *repo, xbps_array_t expfps); /**@}*/ diff --git a/lib/repo.c b/lib/repo.c index 95acd906..b2297f26 100644 --- a/lib/repo.c +++ b/lib/repo.c @@ -187,7 +187,7 @@ repo_open_remote(struct xbps_repo *repo) free(rpath); if (rv) { xbps_dbg_printf("[repo] `%s' used remotely (kept in memory).\n", repo->uri); - if (repo->xhp->state_cb && xbps_repo_key_import(repo) != 0) + if (repo->xhp->state_cb && xbps_repo_key_import(repo, NULL) != 0) rv = false; } return rv; @@ -621,13 +621,14 @@ xbps_repo_get_pkg_revdeps(struct xbps_repo *repo, const char *pkg) } int -xbps_repo_key_import(struct xbps_repo *repo) +xbps_repo_key_import(struct xbps_repo *repo, xbps_array_t expfps) { xbps_dictionary_t repokeyd = NULL; xbps_data_t pubkey = NULL; uint16_t pubkey_size = 0; const char *signedby = NULL; char *hexfp = NULL; + const char *expfp = NULL; char *p, *dbkeyd, *rkeyfile = NULL; int import, rv = 0; @@ -662,7 +663,7 @@ xbps_repo_key_import(struct xbps_repo *repo) goto out; } /* - * Check if the public key is alredy stored. + * Check if the public key is already stored. */ rkeyfile = xbps_xasprintf("%s/keys/%s.plist", repo->xhp->metadir, hexfp); repokeyd = xbps_plist_dictionary_from_file(rkeyfile); @@ -670,6 +671,20 @@ xbps_repo_key_import(struct xbps_repo *repo) xbps_dbg_printf("[repo] `%s' public key already stored.\n", repo->uri); goto out; } + /* + * Check if the public key is expected. If so, import the key + * without prompting for user input. + */ + if (expfps != NULL) { + for (unsigned int i = 0; i < xbps_array_count(expfps); i++) { + if (xbps_array_get_cstring_nocopy(expfps, i, &expfp) && strcmp(hexfp, expfp) == 0) { + xbps_set_cb_state(repo->xhp, XBPS_STATE_REPO_KEY_EXPECTED, 0, + hexfp, "`%s' repository has been RSA signed by \"%s\"", + repo->uri, signedby); + goto importkey; + } + } + } /* * Notify the client and take appropiate action to import * the repository public key. Pass back the public key openssh fingerprint @@ -683,6 +698,7 @@ xbps_repo_key_import(struct xbps_repo *repo) goto out; } +importkey: p = strdup(rkeyfile); dbkeyd = dirname(p); assert(dbkeyd);