[pacman-dev] [RFC] Add Server-specific options, currently only PinnedPubKey
Travis Burtrum
travis.archlinux at burtrum.org
Wed Nov 2 17:13:15 UTC 2016
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 at 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 at archlinux.org>
+ * Copyright (c) 2002-2006 by Judd Vinet <jvinet at zeroflux.org>
+ * Copyright (c) 2005 by Aurelien Foret <orelien at chez.com>
+ * Copyright (c) 2005, 2006 by Christian Hamar <krics at linuxforum.hu>
+ * Copyright (c) 2005, 2006 by Miklos Vajna <vmiklos at 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 at archlinux.org>
+ * Copyright (c) 2002-2006 by Judd Vinet <jvinet at zeroflux.org>
+ * Copyright (c) 2005 by Aurelien Foret <orelien at chez.com>
+ * Copyright (c) 2006 by David Kimpe <dnaku at frugalware.org>
+ * Copyright (c) 2005, 2006 by Christian Hamar <krics at linuxforum.hu>
+ * Copyright (c) 2005, 2006 by Miklos Vajna <vmiklos at 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
More information about the pacman-dev
mailing list