These patches add support for client certificates to alpm and pacman. This can already be achieved currently by setting an XferCommand, but doing so significantly reduces the quality of the feedback pacman gives during the downloads. Especially annoying are the 404 errors on most database signature files, but that's not the only issue. I admit this is a bit of an edge case, but I find myself in the situation where I have to download packages from a private repository that requires a valid client certificate. I really want the nice regular pacman feedback back though, so I figured I'd hack it in myself. I tried to follow naming schemes and other conventions the best I could, but please let me know if I should change anything, or forgot something. --- lib/libalpm/alpm.h | 6 ++++ lib/libalpm/dload.c | 3 ++ lib/libalpm/handle.c | 75 ++++++++++++++++++++++++++++++++++++++++++++ lib/libalpm/handle.h | 2 ++ 4 files changed, 86 insertions(+) diff --git a/lib/libalpm/alpm.h b/lib/libalpm/alpm.h index 2d3d198a..b894e249 100644 --- a/lib/libalpm/alpm.h +++ b/lib/libalpm/alpm.h @@ -933,6 +933,12 @@ int alpm_option_set_remote_file_siglevel(alpm_handle_t *handle, int level); int alpm_option_set_disable_dl_timeout(alpm_handle_t *handle, unsigned short disable_dl_timeout); +const char *alpm_option_get_dlclientcert(alpm_handle_t *handle); +int alpm_option_set_dlclientcert(alpm_handle_t *handle, const char * path); + +const char *alpm_option_get_dlclientkey(alpm_handle_t *handle); +int alpm_option_set_dlclientkey(alpm_handle_t *handle, const char * path); + /** @} */ /** @addtogroup alpm_api_databases Database Functions diff --git a/lib/libalpm/dload.c b/lib/libalpm/dload.c index 36ae4ee1..df57e175 100644 --- a/lib/libalpm/dload.c +++ b/lib/libalpm/dload.c @@ -276,6 +276,9 @@ static void curl_set_handle_opts(struct dload_payload *payload, curl_easy_setopt(curl, CURLOPT_TCP_KEEPINTVL, 60L); curl_easy_setopt(curl, CURLOPT_HTTPAUTH, CURLAUTH_ANY); + curl_easy_setopt(curl, CURLOPT_SSLCERT, alpm_option_get_dlclientcert(handle)); + curl_easy_setopt(curl, CURLOPT_SSLKEY, alpm_option_get_dlclientkey(handle)); + _alpm_log(handle, ALPM_LOG_DEBUG, "url: %s\n", payload->fileurl); if(payload->max_size) { diff --git a/lib/libalpm/handle.c b/lib/libalpm/handle.c index 2213ce53..a9481837 100644 --- a/lib/libalpm/handle.c +++ b/lib/libalpm/handle.c @@ -88,6 +88,8 @@ void _alpm_handle_free(alpm_handle_t *handle) FREE(handle->lockfile); FREE(handle->arch); FREE(handle->gpgdir); + FREE(handle->dlclientcert); + FREE(handle->dlclientkey); FREELIST(handle->noupgrade); FREELIST(handle->noextract); FREELIST(handle->ignorepkg); @@ -417,6 +419,37 @@ alpm_errno_t _alpm_set_directory_option(const char *value, return 0; } +alpm_errno_t _alpm_set_file_option(const char *value, + char **storage, int must_exist) +{ + struct stat st; + char real[PATH_MAX]; + const char *path; + + path = value; + if(!path) { + return ALPM_ERR_WRONG_ARGS; + } + if(must_exist) { + if(stat(path, &st) == -1 || !S_ISREG(st.st_mode)) { + return ALPM_ERR_NOT_A_FILE; + } + if(!realpath(path, real)) { + return ALPM_ERR_NOT_A_FILE; + } + path = real; + } + + if(*storage) { + FREE(*storage); + } + *storage = strdup(path); + if(!*storage) { + return ALPM_ERR_MEMORY; + } + return 0; +} + int SYMEXPORT alpm_option_add_hookdir(alpm_handle_t *handle, const char *hookdir) { char *newhookdir; @@ -876,3 +909,45 @@ int SYMEXPORT alpm_option_set_disable_dl_timeout(alpm_handle_t *handle, #endif return 0; } + +const char * SYMEXPORT alpm_option_get_dlclientcert(alpm_handle_t *handle) +{ + CHECK_HANDLE(handle, return NULL); + return handle->dlclientcert; +} + +int SYMEXPORT alpm_option_set_dlclientcert(alpm_handle_t *handle, const char * path) +{ + int err; + CHECK_HANDLE(handle, return -1); + if(!path) { + FREE(handle->dlclientcert); + return 0; + } + if((err = _alpm_set_file_option(path, &(handle->dlclientcert), 1))) { + RET_ERR(handle, err, -1); + } + _alpm_log(handle, ALPM_LOG_DEBUG, "option 'dlclient_cert' = %s\n", handle->dlclientcert); + return 0; +} + +const char * SYMEXPORT alpm_option_get_dlclientkey(alpm_handle_t *handle) +{ + CHECK_HANDLE(handle, return NULL); + return handle->dlclientkey; +} + +int SYMEXPORT alpm_option_set_dlclientkey(alpm_handle_t *handle, const char * path) +{ + int err; + CHECK_HANDLE(handle, return -1); + if(!path) { + FREE(handle->dlclientkey); + return 0; + } + if((err = _alpm_set_file_option(path, &(handle->dlclientkey), 1))) { + RET_ERR(handle, err, -1); + } + _alpm_log(handle, ALPM_LOG_DEBUG, "option 'dlclient_key' = %s\n", handle->dlclientkey); + return 0; +} diff --git a/lib/libalpm/handle.h b/lib/libalpm/handle.h index 44c4904b..4bcfeb8a 100644 --- a/lib/libalpm/handle.h +++ b/lib/libalpm/handle.h @@ -82,6 +82,8 @@ struct __alpm_handle_t { char *logfile; /* Name of the log file */ char *lockfile; /* Name of the lock file */ char *gpgdir; /* Directory where GnuPG files are stored */ + char *dlclientcert; /* Name of the client certificate */ + char *dlclientkey; /* Name of the client key */ alpm_list_t *cachedirs; /* Paths to pacman cache directories */ alpm_list_t *hookdirs; /* Paths to hook directories */ alpm_list_t *overwrite_files; /* Paths that may be overwritten */ -- 2.19.1