[pacman-dev] [RFC] Add Server-specific options, currently only PinnedPubKey
Hi all, Here is a rough go at a patch for server-specific options. It works, but what still needs done is: 1. Changing alpm_db_remove_server, does it still take a char* url? or the entire alpm_server_t struct that alpm_db_add_server does? 2. Deciding what to do with alpm_cb_fetch's signature, should a new struct be added to make adding new server options easier? Should alpm_server_t be sent in instead? (this gets messy in some places). 3. Documentation updates. The end result looks like: Server = https://example.org/ PinnedPubKey=sha256//eEHQC9au2QRAP1FnvcYEsmvXT7511EXQ2gw8ppBfseM= Is this a sound approach? Any other comments appreciated. Thanks, Travis
From ebf448cd4da77bdea833dc75e60de5c992f21eaf Mon Sep 17 00:00:00 2001 From: Travis Burtrum <travis.archlinux@burtrum.org> Date: Tue, 1 Nov 2016 23:02:43 -0400 Subject: [PATCH] [RFC] Add Server-specific options, currently only PinnedPubKey supported
--- lib/libalpm/Makefile.am | 1 + lib/libalpm/alpm.c | 1 + lib/libalpm/alpm.h | 18 ++++++++-- lib/libalpm/be_sync.c | 7 +++- lib/libalpm/db.c | 16 ++++++--- lib/libalpm/dload.c | 8 ++++- lib/libalpm/dload.h | 1 + lib/libalpm/hook.c | 10 +++--- lib/libalpm/server.c | 91 +++++++++++++++++++++++++++++++++++++++++++++++++ lib/libalpm/server.h | 36 +++++++++++++++++++ lib/libalpm/sync.c | 4 ++- src/pacman/conf.c | 68 ++++++++++++++++++++++++++++-------- 12 files changed, 234 insertions(+), 27 deletions(-) create mode 100644 lib/libalpm/server.c create mode 100644 lib/libalpm/server.h diff --git a/lib/libalpm/Makefile.am b/lib/libalpm/Makefile.am index f4f20e6..197459c 100644 --- a/lib/libalpm/Makefile.am +++ b/lib/libalpm/Makefile.am @@ -48,6 +48,7 @@ libalpm_la_SOURCES = \ libarchive-compat.h \ log.h log.c \ package.h package.c \ + server.h server.c \ pkghash.h pkghash.c \ rawstr.c \ remove.h remove.c \ diff --git a/lib/libalpm/alpm.c b/lib/libalpm/alpm.c index 5225e4f..82df39f 100644 --- a/lib/libalpm/alpm.c +++ b/lib/libalpm/alpm.c @@ -29,6 +29,7 @@ #include "alpm.h" #include "alpm_list.h" #include "handle.h" +#include "server.h" #include "log.h" #include "util.h" diff --git a/lib/libalpm/alpm.h b/lib/libalpm/alpm.h index 2d2491d..53b48e5 100644 --- a/lib/libalpm/alpm.h +++ b/lib/libalpm/alpm.h @@ -48,6 +48,7 @@ typedef struct __alpm_handle_t alpm_handle_t; typedef struct __alpm_db_t alpm_db_t; typedef struct __alpm_pkg_t alpm_pkg_t; typedef struct __alpm_trans_t alpm_trans_t; +typedef struct __alpm_server_t alpm_server_t; /** @addtogroup alpm_api_errors Error Codes * @{ @@ -750,11 +751,12 @@ typedef void (*alpm_cb_totaldl)(off_t total); * @param url the URL of the file to be downloaded * @param localpath the directory to which the file should be downloaded * @param force whether to force an update, even if the file is the same + * @param pinnedpubkey a pinned public key string * @return 0 on success, 1 if the file exists and is identical, -1 on * error. */ typedef int (*alpm_cb_fetch)(const char *url, const char *localpath, - int force); + int force, const char *pinnedpubkey); /** Fetch a remote pkg. * @param handle the context handle @@ -998,7 +1000,7 @@ int alpm_db_get_valid(alpm_db_t *db); */ alpm_list_t *alpm_db_get_servers(const alpm_db_t *db); int alpm_db_set_servers(alpm_db_t *db, alpm_list_t *servers); -int alpm_db_add_server(alpm_db_t *db, const char *url); +int alpm_db_add_server(alpm_db_t *db, alpm_server_t *url); int alpm_db_remove_server(alpm_db_t *db, const char *url); /** @} */ @@ -1061,6 +1063,18 @@ int alpm_db_get_usage(alpm_db_t *db, int *usage); /** @} */ +alpm_server_t *alpm_server_new(void); +int alpm_server_free(alpm_server_t *server); + +const char *alpm_server_get_url(const alpm_server_t *server); +const char *alpm_server_get_pinnedpubkey(const alpm_server_t *server); +int alpm_server_set_url(alpm_server_t *server, const char *url); +int alpm_server_set_pinnedpubkey(alpm_server_t *server, const char *pinnedpubkey); + +char **alpm_wordsplit(char *str); +int alpm_wordsplit_free(char **ws); + + /** @addtogroup alpm_api_packages Package Functions * Functions to manipulate libalpm packages * @{ diff --git a/lib/libalpm/be_sync.c b/lib/libalpm/be_sync.c index 7774975..79a35d2 100644 --- a/lib/libalpm/be_sync.c +++ b/lib/libalpm/be_sync.c @@ -219,7 +219,8 @@ int SYMEXPORT alpm_db_update(int force, alpm_db_t *db) dbext = db->handle->dbext; for(i = db->servers; i; i = i->next) { - const char *server = i->data, *final_db_url = NULL; + alpm_server_t *server_t = i->data; + const char *server = alpm_server_get_url(server_t), *final_db_url = NULL; struct dload_payload payload; size_t len; int sig_ret = 0; @@ -242,6 +243,8 @@ int SYMEXPORT alpm_db_update(int force, alpm_db_t *db) payload.handle = handle; payload.force = force; payload.unlink_on_fail = 1; + + payload.pinnedpubkey = alpm_server_get_pinnedpubkey(server_t); ret = _alpm_download(&payload, syncpath, NULL, &final_db_url); _alpm_dload_payload_reset(&payload); @@ -297,6 +300,8 @@ int SYMEXPORT alpm_db_update(int force, alpm_db_t *db) /* set hard upper limit of 16KiB */ payload.max_size = 16 * 1024; + payload.pinnedpubkey = alpm_server_get_pinnedpubkey(server_t); + sig_ret = _alpm_download(&payload, syncpath, NULL, NULL); /* errors_ok suppresses error messages, but not the return code */ sig_ret = payload.errors_ok ? 0 : sig_ret; diff --git a/lib/libalpm/db.c b/lib/libalpm/db.c index 5d78ee5..7c8dd4b 100644 --- a/lib/libalpm/db.c +++ b/lib/libalpm/db.c @@ -150,7 +150,8 @@ alpm_list_t SYMEXPORT *alpm_db_get_servers(const alpm_db_t *db) int SYMEXPORT alpm_db_set_servers(alpm_db_t *db, alpm_list_t *servers) { ASSERT(db != NULL, return -1); - FREELIST(db->servers); + alpm_list_free_inner(db->servers, (alpm_list_fn_free) alpm_server_free); + alpm_list_free(db->servers); db->servers = servers; return 0; } @@ -173,9 +174,10 @@ static char *sanitize_url(const char *url) * @param url url of the server * @return 0 on success, -1 on error (pm_errno is set accordingly) */ -int SYMEXPORT alpm_db_add_server(alpm_db_t *db, const char *url) +int SYMEXPORT alpm_db_add_server(alpm_db_t *db, alpm_server_t *server) { char *newurl; + const char *url = alpm_server_get_url(server); /* Sanity checks */ ASSERT(db != NULL, return -1); @@ -186,7 +188,12 @@ int SYMEXPORT alpm_db_add_server(alpm_db_t *db, const char *url) if(!newurl) { return -1; } - db->servers = alpm_list_add(db->servers, newurl); + + alpm_server_t *copy = alpm_server_new(); + alpm_server_set_url(copy, newurl); + alpm_server_set_pinnedpubkey(copy, alpm_server_get_pinnedpubkey(server)); + + db->servers = alpm_list_add(db->servers, copy); _alpm_log(db->handle, ALPM_LOG_DEBUG, "adding new server URL to database '%s': %s\n", db->treename, newurl); @@ -348,7 +355,8 @@ void _alpm_db_free(alpm_db_t *db) /* cleanup pkgcache */ _alpm_db_free_pkgcache(db); /* cleanup server list */ - FREELIST(db->servers); + alpm_list_free_inner(db->servers, (alpm_list_fn_free) alpm_server_free); + alpm_list_free(db->servers); FREE(db->_path); FREE(db->treename); FREE(db); diff --git a/lib/libalpm/dload.c b/lib/libalpm/dload.c index 9d80358..6d5b371 100644 --- a/lib/libalpm/dload.c +++ b/lib/libalpm/dload.c @@ -327,6 +327,12 @@ static void curl_set_handle_opts(struct dload_payload *payload, curl_easy_setopt(curl, CURLOPT_USERAGENT, useragent); } + if(payload->pinnedpubkey != NULL) { + _alpm_log(handle, ALPM_LOG_DEBUG, + "using curl pinnedpubkey: %s\n", payload->pinnedpubkey); + curl_easy_setopt(curl, CURLOPT_PINNEDPUBLICKEY, payload->pinnedpubkey); + } + if(!payload->allow_resume && !payload->force && payload->destfile_name && stat(payload->destfile_name, &st) == 0) { /* start from scratch, but only download if our local is out of date. */ @@ -646,7 +652,7 @@ int _alpm_download(struct dload_payload *payload, const char *localpath, RET_ERR(handle, ALPM_ERR_EXTERNAL_DOWNLOAD, -1); #endif } else { - int ret = handle->fetchcb(payload->fileurl, localpath, payload->force); + int ret = handle->fetchcb(payload->fileurl, localpath, payload->force, payload->pinnedpubkey); if(ret == -1 && !payload->errors_ok) { RET_ERR(handle, ALPM_ERR_EXTERNAL_DOWNLOAD, -1); } diff --git a/lib/libalpm/dload.h b/lib/libalpm/dload.h index 427c486..9b8453a 100644 --- a/lib/libalpm/dload.h +++ b/lib/libalpm/dload.h @@ -41,6 +41,7 @@ struct dload_payload { int errors_ok; int unlink_on_fail; int trust_remote_name; + const char *pinnedpubkey; #ifdef HAVE_LIBCURL CURLcode curlerr; /* last error produced by curl */ #endif diff --git a/lib/libalpm/hook.c b/lib/libalpm/hook.c index ccde225..9e84d78 100644 --- a/lib/libalpm/hook.c +++ b/lib/libalpm/hook.c @@ -71,7 +71,7 @@ static void _alpm_trigger_free(struct _alpm_trigger_t *trigger) } } -static void _alpm_wordsplit_free(char **ws) +int SYMEXPORT alpm_wordsplit_free(char **ws) { if(ws) { char **c; @@ -79,7 +79,9 @@ static void _alpm_wordsplit_free(char **ws) free(*c); } free(ws); + return 0; } + return -1; } static void _alpm_hook_free(struct _alpm_hook_t *hook) @@ -87,7 +89,7 @@ static void _alpm_hook_free(struct _alpm_hook_t *hook) if(hook) { free(hook->name); free(hook->desc); - _alpm_wordsplit_free(hook->cmd); + alpm_wordsplit_free(hook->cmd); alpm_list_free_inner(hook->triggers, (alpm_list_fn_free) _alpm_trigger_free); alpm_list_free(hook->triggers); alpm_list_free(hook->matches); @@ -158,7 +160,7 @@ static int _alpm_hook_validate(alpm_handle_t *handle, return ret; } -static char **_alpm_wordsplit(char *str) +char SYMEXPORT **alpm_wordsplit(char *str) { char *c = str, *end; char **out = NULL, **outsave; @@ -330,7 +332,7 @@ static int _alpm_hook_parse_cb(const char *file, int line, } else if(strcmp(key, "NeedsTargets") == 0) { hook->needs_targets = 1; } else if(strcmp(key, "Exec") == 0) { - if((hook->cmd = _alpm_wordsplit(value)) == NULL) { + if((hook->cmd = alpm_wordsplit(value)) == NULL) { if(errno == EINVAL) { error(_("hook %s line %d: invalid value %s\n"), file, line, value); } else { diff --git a/lib/libalpm/server.c b/lib/libalpm/server.c new file mode 100644 index 0000000..29aa365 --- /dev/null +++ b/lib/libalpm/server.c @@ -0,0 +1,91 @@ +/* + * server.c + * + * Copyright (c) 2006-2016 Pacman Development Team <pacman-dev@archlinux.org> + * Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org> + * Copyright (c) 2005 by Aurelien Foret <orelien@chez.com> + * Copyright (c) 2005, 2006 by Christian Hamar <krics@linuxforum.hu> + * Copyright (c) 2005, 2006 by Miklos Vajna <vmiklos@frugalware.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> + +/* libalpm */ +#include "server.h" +#include "alpm_list.h" +#include "log.h" +#include "util.h" +#include "db.h" +#include "delta.h" +#include "handle.h" +#include "deps.h" + +/** \addtogroup alpm_packages Server Functions + * @brief Functions to manipulate libalpm servers + * @{ + */ + +alpm_server_t SYMEXPORT *alpm_server_new(void) +{ + alpm_server_t *server; + + CALLOC(server, 1, sizeof(alpm_server_t), return NULL); + + return server; +} + +/** Free a package. */ +int SYMEXPORT alpm_server_free(alpm_server_t *server) +{ + ASSERT(server != NULL, return -1); + FREE(server->url); + FREE(server->pinnedpubkey); + return 0; +} + +const char SYMEXPORT *alpm_server_get_url(const alpm_server_t *server) +{ + ASSERT(server != NULL, return NULL); + return server->url; +} + +const char SYMEXPORT *alpm_server_get_pinnedpubkey(const alpm_server_t *server) +{ + ASSERT(server != NULL, return NULL); + return server->pinnedpubkey; +} + +int SYMEXPORT alpm_server_set_url(alpm_server_t *server, const char *url) +{ + ASSERT(server != NULL, return -1); + ASSERT(url != NULL, return 0); + FREE(server->url); + server->url = strdup(url); + return 0; +} + +int SYMEXPORT alpm_server_set_pinnedpubkey(alpm_server_t *server, const char *pinnedpubkey) +{ + ASSERT(server != NULL, return -1); + ASSERT(pinnedpubkey != NULL, return 0); + FREE(server->pinnedpubkey); + server->pinnedpubkey = strdup(pinnedpubkey); + return 0; +} + +/* vim: set noet: */ diff --git a/lib/libalpm/server.h b/lib/libalpm/server.h new file mode 100644 index 0000000..b88f9ee --- /dev/null +++ b/lib/libalpm/server.h @@ -0,0 +1,36 @@ +/* + * server.h + * + * Copyright (c) 2006-2016 Pacman Development Team <pacman-dev@archlinux.org> + * Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org> + * Copyright (c) 2005 by Aurelien Foret <orelien@chez.com> + * Copyright (c) 2006 by David Kimpe <dnaku@frugalware.org> + * Copyright (c) 2005, 2006 by Christian Hamar <krics@linuxforum.hu> + * Copyright (c) 2005, 2006 by Miklos Vajna <vmiklos@frugalware.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +#ifndef ALPM_SERVER_H +#define ALPM_SERVER_H + +#include "alpm.h" + +struct __alpm_server_t { + char *url; + char *pinnedpubkey; +}; + +#endif /* ALPM_SERVER_H */ + +/* vim: set noet: */ diff --git a/lib/libalpm/sync.c b/lib/libalpm/sync.c index 837639d..c54f951 100644 --- a/lib/libalpm/sync.c +++ b/lib/libalpm/sync.c @@ -933,7 +933,9 @@ static int download_single_file(alpm_handle_t *handle, struct dload_payload *pay EVENT(handle, &event); for(server = payload->servers; server; server = server->next) { - const char *server_url = server->data; + const alpm_server_t *server_t = server->data; + payload->pinnedpubkey = alpm_server_get_pinnedpubkey(server_t); + const char *server_url = alpm_server_get_url(server_t); size_t len; /* print server + filename into a buffer */ diff --git a/src/pacman/conf.c b/src/pacman/conf.c index d8d64fb..4905310 100644 --- a/src/pacman/conf.c +++ b/src/pacman/conf.c @@ -164,7 +164,8 @@ void config_repo_free(config_repo_t *repo) return; } free(repo->name); - FREELIST(repo->servers); + alpm_list_free_inner(repo->servers, (alpm_list_fn_free) alpm_server_free); + alpm_list_free(repo->servers); free(repo); } @@ -204,7 +205,7 @@ static char *get_tempfile(const char *path, const char *filename) /** External fetch callback */ static int download_with_xfercommand(const char *url, const char *localpath, - int force) + int force, const char *pinnedpubkey) { int ret = 0, retval; int usepart = 0; @@ -232,6 +233,16 @@ static int download_with_xfercommand(const char *url, const char *localpath, } tempcmd = strdup(config->xfercommand); + /* replace all occurrences of %p with pinnedpubkey */ + if(strstr(tempcmd, "%p")) { + if(pinnedpubkey == NULL) { + parsedcmd = strreplace(tempcmd, "%p", ""); + } else { + parsedcmd = strreplace(tempcmd, "%p", pinnedpubkey); + } + free(tempcmd); + tempcmd = parsedcmd; + } /* replace all occurrences of %o with fn.part */ if(strstr(tempcmd, "%o")) { usepart = 1; @@ -613,16 +624,17 @@ static int _parse_options(const char *key, char *value, return 0; } -static int _add_mirror(alpm_db_t *db, char *value) +static int _add_mirror(alpm_db_t *db, alpm_server_t *server) { + const char *value = alpm_server_get_url(server); const char *dbname = alpm_db_get_name(db); /* let's attempt a replacement for the current repo */ char *temp = strreplace(value, "$repo", dbname); /* let's attempt a replacement for the arch */ const char *arch = config->arch; - char *server; + char *url; if(arch) { - server = strreplace(temp, "$arch", arch); + url = strreplace(temp, "$arch", arch); free(temp); } else { if(strstr(temp, "$arch")) { @@ -632,18 +644,19 @@ static int _add_mirror(alpm_db_t *db, char *value) value, "$arch", "Architecture"); return 1; } - server = temp; + url = temp; } + alpm_server_set_url(server, url); if(alpm_db_add_server(db, server) != 0) { /* pm_errno is set by alpm_db_setserver */ pm_printf(ALPM_LOG_ERROR, _("could not add server URL to database '%s': %s (%s)\n"), - dbname, server, alpm_strerror(alpm_errno(config->handle))); - free(server); + dbname, url, alpm_strerror(alpm_errno(config->handle))); + free(url); return 1; } - free(server); + free(url); return 0; } @@ -669,11 +682,11 @@ static int register_repo(config_repo_t *repo) alpm_db_set_usage(db, repo->usage == 0 ? ALPM_DB_USAGE_ALL : repo->usage); for(i = repo->servers; i; i = alpm_list_next(i)) { - char *value = i->data; - if(_add_mirror(db, value) != 0) { + alpm_server_t *server = i->data; + if(_add_mirror(db, server) != 0) { pm_printf(ALPM_LOG_ERROR, _("could not add mirror '%s' to database '%s' (%s)\n"), - value, repo->name, alpm_strerror(alpm_errno(config->handle))); + alpm_server_get_url(server), repo->name, alpm_strerror(alpm_errno(config->handle))); return 1; } } @@ -883,6 +896,7 @@ static int _parse_repo(const char *key, char *value, const char *file, { int ret = 0; config_repo_t *repo = section->repo; + char *server_key, *server_value; if(strcmp(key, "Server") == 0) { if(!value) { @@ -890,7 +904,34 @@ static int _parse_repo(const char *key, char *value, const char *file, file, line, key); ret = 1; } else { - repo->servers = alpm_list_add(repo->servers, strdup(value)); + alpm_server_t *server = alpm_server_new(); + char **cmd = alpm_wordsplit(value); + alpm_server_set_url(server, cmd[0]); + char **c; + for(c = cmd + 1; *c; c++) { + server_key = *c; + server_value = *c; + strsep(&server_value, "="); + strtrim(server_key); + strtrim(server_value); + + if(strcmp(server_key, "PinnedPubKey") == 0) { + if(!server_value) { + pm_printf(ALPM_LOG_ERROR, _("config file %s, line %d: directive '%s' needs a value\n"), + file, line, server_key); + } else { + alpm_server_set_pinnedpubkey(server, server_value); + pm_printf(ALPM_LOG_DEBUG, "server config: server: %s, pinnedpubkey: %s\n", cmd[0], server_value); + } + } else { + pm_printf(ALPM_LOG_WARNING, + _("config file %s, line %d: directive '%s' in section '%s', server '%s', key '%s' not recognized.\n"), + file, line, key, repo->name, cmd[0], server_key); + } + + } + alpm_wordsplit_free(cmd); + repo->servers = alpm_list_add(repo->servers, server); } } else if(strcmp(key, "SigLevel") == 0) { if(!value) { @@ -920,7 +961,6 @@ static int _parse_repo(const char *key, char *value, const char *file, _("config file %s, line %d: directive '%s' in section '%s' not recognized.\n"), file, line, key, repo->name); } - return ret; } -- 2.10.2
participants (1)
-
Travis Burtrum