1
0
forked from mirrors/pacman

Compare commits

..

11 Commits

Author SHA1 Message Date
morganamilo
83838214b7 Remove unused variables / assignments 2024-02-09 11:24:20 +10:00
morganamilo
4baeb8e40b libalpm: print errors when unknown keys in database 2024-02-09 11:24:20 +10:00
morganamilo
18b65ec909 pacman: remove uses of atoi 2024-02-09 11:24:20 +10:00
morganamilo
45ce932fd0 pacman: check for end of string when stripping ascii escapes 2024-02-09 11:24:20 +10:00
morganamilo
da4b590bce pacman: check if pkgname is empty instead of null in progress
The progress callback always uses an empty string when there is no
pkgname. However pacman checks if the argument is null.

Check if the string is empty instead and better document what is passed
to the progress callback.
2024-02-09 11:24:20 +10:00
Allan McRae
0649a66ee5 Add ALPM_PKG_REASON_UNKNOWN type
Return ALPM_PKG_REASON_UNKNOWN when parsing of %REASON% in the local
database fails.

Signed-off-by: Allan McRae <allan@archlinux.org>
2024-02-09 11:14:38 +10:00
morganamilo
6e6d3f18e3 libalpm: don't use atio for pkgreason
atio's behaviour is undefined if the input is not valid. Also it does
all sorts of whitespace and prefix handling which we don't need for
pkgreason.

Instead of going into UB on invalid input we now return EXPLICIT as the
fallback and print an error. However we don't actually error out as the
DB parsing tries to be error tolerant.

Signed-off-by: Allan McRae <allan@archlinux.org>
2024-02-09 11:14:38 +10:00
Andrew Gregory
0a394144b2 validate package metadata after loading
alpm has certain requirements for package metadata necessary for proper
functioning, name and version in particular.  These requirements are
already enforced in makepkg, but nowhere in alpm.

Exceptions are treated as errors for non-local packages because they
cannot be installed without potentially resulting in undefined behavior.
Exceptions for local packages are treated as warnings because they are
already installed, so any damage has already been done, and the user
would otherwise have no way to uninstall them.

Signed-off-by: Andrew Gregory <andrew.gregory.8@gmail.com>
2024-02-07 12:27:26 +00:00
Andrew Gregory
fde59b99e8 be_package: delay freeing archive resource
The error path uconditinally tries to free the archive, leading to a
double-free segmentation fault if the error path is triggered after
already freeing it.

Signed-off-by: Andrew Gregory <andrew.gregory.8@gmail.com>
2024-02-07 12:27:26 +00:00
Andrew Gregory
edd57c8b96 perform cleanup on sync db parsing errors
Cleanup was only being performed when libarchive failed to actually read
the file.

Signed-off-by: Andrew Gregory <andrew.gregory.8@gmail.com>
2024-02-07 12:27:26 +00:00
Andrew Gregory
5c75a55c7d allow freeing partial db package cache
The free function was checking DB_STATUS_PKGCACHE, which is only set
once the package cache has been fully built.

Signed-off-by: Andrew Gregory <andrew.gregory.8@gmail.com>
2024-02-07 12:27:26 +00:00
35 changed files with 410 additions and 838 deletions

View File

@@ -207,10 +207,6 @@ Options
positive integer. If this config option is not set then only one download
stream is used (i.e. downloads happen sequentially).
*DownloadUser =* username::
Specifies the user to switch to for downloading files. If this config
option is not set then the downloads are done as the user running pacman.
Repository Sections
-------------------

View File

@@ -1149,7 +1149,9 @@ typedef enum _alpm_progress_t {
* make take a while to complete.
* @param ctx user-provided context
* @param progress the kind of event that is progressing
* @param pkg for package operations, the name of the package being operated on
* @param pkg the name of the package being operated on. if the progress kind
* is a packae operation (add, upgrade, downgrade, reinstall, remove).
* otherwise this will be an empty string.
* @param percent the percent completion of the action
* @param howmany the total amount of items in the action
* @param current the current amount of items completed
@@ -1870,28 +1872,6 @@ int alpm_option_set_gpgdir(alpm_handle_t *handle, const char *gpgdir);
/** @} */
/** @name Accessors for use sandboxuser
*
* This controls the user that libalpm will use for sensitive operations like
* downloading files.
* @{
*/
/** Returns the user to switch to for sensitive operations.
* @return the user name
*/
const char *alpm_option_get_sandboxuser(alpm_handle_t *handle);
/** Sets the user to switch to for sensitive operations.
* @param handle the context handle
* @param sandboxuser the user to set
*/
int alpm_option_set_sandboxuser(alpm_handle_t *handle, const char *sandboxuser);
/* End of sandboxuser accessors */
/** @} */
/** @name Accessors for use syslog
*
* This controls whether libalpm will also use the syslog. Even if this option
@@ -2315,7 +2295,9 @@ typedef enum _alpm_pkgreason_t {
/** Explicitly requested by the user. */
ALPM_PKG_REASON_EXPLICIT = 0,
/** Installed as a dependency for another package. */
ALPM_PKG_REASON_DEPEND = 1
ALPM_PKG_REASON_DEPEND = 1,
/** Failed parsing of local database */
ALPM_PKG_REASON_UNKNOWN = 2
} alpm_pkgreason_t;
/** Location a package object was loaded from. */
@@ -2951,12 +2933,6 @@ const char *alpm_version(void);
* */
int alpm_capabilities(void);
/** Drop privileges by switching to a different user.
* @param sandboxuser the user to switch to
* @return 0 on success, -1 on failure
*/
int alpm_sandbox_setup_child(const char *sandboxuser);
/* End of libalpm_misc */
/** @} */

View File

@@ -630,6 +630,10 @@ static int local_db_populate(alpm_db_t *db)
continue;
}
/* treat local metadata errors as warning-only,
* they are already installed and otherwise they can't be operated on */
_alpm_pkg_check_meta(pkg);
/* add to the collection */
_alpm_log(db->handle, ALPM_LOG_FUNCTION, "adding '%s' to package cache for db '%s'\n",
pkg->name, db->treename);
@@ -650,6 +654,17 @@ static int local_db_populate(alpm_db_t *db)
return 0;
}
static alpm_pkgreason_t _read_pkgreason(alpm_handle_t *handle, const char *pkgname, const char *line) {
if(strcmp(line, "0") == 0) {
return ALPM_PKG_REASON_EXPLICIT;
} else if(strcmp(line, "1") == 0) {
return ALPM_PKG_REASON_DEPEND;
} else {
_alpm_log(handle, ALPM_LOG_ERROR, _("unknown install reason for package %s: %s\n"), pkgname, line);
return ALPM_PKG_REASON_UNKNOWN;
}
}
/* Note: the return value must be freed by the caller */
char *_alpm_local_db_pkgpath(alpm_db_t *db, alpm_pkg_t *info,
const char *filename)
@@ -772,7 +787,7 @@ static int local_db_read(alpm_pkg_t *info, int inforeq)
READ_AND_STORE(info->packager);
} else if(strcmp(line, "%REASON%") == 0) {
READ_NEXT();
info->reason = (alpm_pkgreason_t)atoi(line);
info->reason = _read_pkgreason(db->handle, info->name, line);
} else if(strcmp(line, "%VALIDATION%") == 0) {
alpm_list_t *i, *v = NULL;
READ_AND_STORE_ALL(v);
@@ -822,6 +837,12 @@ static int local_db_read(alpm_pkg_t *info, int inforeq)
}
}
FREELIST(lines);
} else {
_alpm_log(db->handle, ALPM_LOG_ERROR, _("%s: unknown key '%s' in sync database\n"), info->name, line);
alpm_list_t *lines = NULL;
READ_AND_STORE_ALL(lines);
FREELIST(lines);
}
}
fclose(fp);

View File

@@ -251,8 +251,10 @@ static int parse_descfile(alpm_handle_t *handle, struct archive *a, alpm_pkg_t *
return -1;
}
} else {
const char *pkgname = newpkg->name ? newpkg->name : "error";
_alpm_log(handle, ALPM_LOG_ERROR, _("%s: unknown key '%s' in package description\n"), pkgname, key);
_alpm_log(handle, ALPM_LOG_DEBUG, "%s: unknown key '%s' in description file line %d\n",
newpkg->name ? newpkg->name : "error", key, linenum);
pkgname, key, linenum);
}
}
}
@@ -652,8 +654,6 @@ alpm_pkg_t *_alpm_pkg_load_internal(alpm_handle_t *handle,
goto pkg_invalid;
}
_alpm_archive_read_free(archive);
/* internal fields for package struct */
newpkg->origin = ALPM_PKG_FROM_FILE;
STRDUP(newpkg->origin_data.file, pkgfile, goto error);
@@ -675,6 +675,11 @@ alpm_pkg_t *_alpm_pkg_load_internal(alpm_handle_t *handle,
newpkg->infolevel |= INFRQ_FILES;
}
if(_alpm_pkg_check_meta(newpkg) != 0) {
goto pkg_invalid;
}
_alpm_archive_read_free(archive);
close(fd);
return newpkg;

View File

@@ -189,18 +189,6 @@ int SYMEXPORT alpm_db_update(alpm_handle_t *handle, alpm_list_t *dbs, int force)
MALLOC(payload->filepath, len,
FREE(payload); GOTO_ERR(handle, ALPM_ERR_MEMORY, cleanup));
snprintf(payload->filepath, len, "%s%s", db->treename, dbext);
STRDUP(payload->remote_name, payload->filepath,
_alpm_dload_payload_reset(payload); FREE(payload);
GOTO_ERR(handle, ALPM_ERR_MEMORY, cleanup));
payload->destfile_name = _alpm_get_fullpath(syncpath, payload->remote_name, "");
payload->tempfile_name = _alpm_get_fullpath(syncpath, payload->remote_name, ".part");
if(!payload->destfile_name || !payload->tempfile_name) {
_alpm_dload_payload_reset(payload);
FREE(payload);
GOTO_ERR(handle, ALPM_ERR_MEMORY, cleanup);
}
payload->handle = handle;
payload->force = dbforce;
payload->unlink_on_fail = 1;
@@ -356,6 +344,11 @@ static alpm_pkg_t *load_pkg_for_entry(alpm_db_t *db, const char *entryname,
pkg->ops = get_sync_pkg_ops();
pkg->handle = db->handle;
if(_alpm_pkg_check_meta(pkg) != 0) {
_alpm_pkg_free(pkg);
RET_ERR(db->handle, ALPM_ERR_PKG_INVALID, NULL);
}
/* add to the collection */
_alpm_log(db->handle, ALPM_LOG_FUNCTION, "adding '%s' to package cache for db '%s'\n",
pkg->name, db->treename);
@@ -464,6 +457,14 @@ static int sync_db_populate(alpm_db_t *db)
}
}
}
/* the db file was successfully read, but contained errors */
if(ret == -1) {
db->status &= ~DB_STATUS_VALID;
db->status |= DB_STATUS_INVALID;
_alpm_db_free_pkgcache(db);
GOTO_ERR(db->handle, ALPM_ERR_DB_INVALID, cleanup);
}
/* reading the db file failed */
if(archive_ret != ARCHIVE_EOF) {
_alpm_log(db->handle, ALPM_LOG_ERROR, _("could not read db '%s' (%s)\n"),
db->treename, archive_error_string(archive));
@@ -690,6 +691,11 @@ static int sync_db_read(alpm_db_t *db, struct archive *archive,
}
}
FREELIST(lines);
} else {
_alpm_log(db->handle, ALPM_LOG_ERROR, _("%s: unknown key '%s' in local database\n"), pkg->name, line);
alpm_list_t *lines = NULL;
READ_AND_STORE_ALL(lines);
FREELIST(lines);
}
}
if(ret != ARCHIVE_EOF) {

View File

@@ -563,18 +563,17 @@ static void free_groupcache(alpm_db_t *db)
void _alpm_db_free_pkgcache(alpm_db_t *db)
{
if(db == NULL || !(db->status & DB_STATUS_PKGCACHE)) {
if(db == NULL || db->pkgcache == NULL) {
return;
}
_alpm_log(db->handle, ALPM_LOG_DEBUG,
"freeing package cache for repository '%s'\n", db->treename);
if(db->pkgcache) {
alpm_list_free_inner(db->pkgcache->list,
(alpm_list_fn_free)_alpm_pkg_free);
_alpm_pkghash_free(db->pkgcache);
}
alpm_list_free_inner(db->pkgcache->list,
(alpm_list_fn_free)_alpm_pkg_free);
_alpm_pkghash_free(db->pkgcache);
db->pkgcache = NULL;
db->status &= ~DB_STATUS_PKGCACHE;
free_groupcache(db);

View File

@@ -556,7 +556,7 @@ static void _alpm_select_depends(alpm_list_t **from, alpm_list_t **to,
for(i = *from; i; i = next) {
alpm_pkg_t *deppkg = i->data;
next = i->next;
if((explicit || alpm_pkg_get_reason(deppkg) != ALPM_PKG_REASON_EXPLICIT)
if((explicit || alpm_pkg_get_reason(deppkg) == ALPM_PKG_REASON_DEPEND)
&& _alpm_pkg_depends_on(pkg, deppkg)) {
*to = alpm_list_add(*to, deppkg);
*from = alpm_list_remove_item(*from, i);

View File

@@ -28,9 +28,7 @@
#include <sys/time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <signal.h>
#include <pwd.h>
#ifdef HAVE_NETINET_IN_H
#include <netinet/in.h> /* IPPROTO_TCP */
@@ -50,145 +48,6 @@
#include "log.h"
#include "util.h"
#include "handle.h"
#include "sandbox.h"
static const char *get_filename(const char *url)
{
char *filename = strrchr(url, '/');
if(filename != NULL) {
return filename + 1;
}
/* no slash found, it's a filename */
return url;
}
/* prefix to avoid possible future clash with getumask(3) */
static mode_t _getumask(void)
{
mode_t mask = umask(0);
umask(mask);
return mask;
}
static int touch_and_own_file(const char *filename, const char *user)
{
int fd;
struct passwd const *pw = NULL;
ASSERT(filename != NULL, return -1);
ASSERT(user != NULL, return -1);
ASSERT((fd = open(filename, O_CREAT | O_WRONLY, 0644)) != -1, return -1);
close(fd);
ASSERT((pw = getpwnam(user)) != NULL, return -1);
ASSERT(chown(filename, pw->pw_uid, pw->pw_gid) != -1, return -1);
return 0;
}
static int intialize_download_file(struct dload_payload *p)
{
int ret = 0;
ret = touch_and_own_file(p->tempfile_name, p->handle->sandboxuser);
if(ret == 0 && p->download_signature) {
int len = strlen(p->destfile_name) + strlen(".sig") + strlen(".part") + 1;
char * sig;
MALLOC(sig, len, FREE(sig); RET_ERR(p->handle, ALPM_ERR_MEMORY, -1));
snprintf(sig, len, "%s.sig.part", p->destfile_name);
ret = touch_and_own_file(sig, p->handle->sandboxuser);
free(sig);
}
return ret;
}
static int unlink_or_move(const char *file, const char* dest) {
struct stat st;
ASSERT(stat(file, &st) == 0, return -1);
if(st.st_size == 0) {
unlink(file);
} else {
ASSERT(chown(file, 0, 0) != -1, return -1);
if(rename(file, dest)) {
return -1;
}
}
return 0;
}
static int finalize_download_file(struct dload_payload *p)
{
int ret = 0;
ret = unlink_or_move(p->tempfile_name, p->destfile_name);
if(ret == -1) {
_alpm_log(p->handle, ALPM_LOG_ERROR, _("could not rename %s to %s (%s)\n"),
p->tempfile_name, p->destfile_name, strerror(errno));
return -1;
}
if(p->download_signature) {
char *sig_temp, *sig_dest;
int len = strlen(p->destfile_name) + strlen(".sig") + 1;
MALLOC(sig_dest, len, RET_ERR(p->handle, ALPM_ERR_MEMORY, -1));
snprintf(sig_dest, len, "%s.sig", p->destfile_name);
len = len + 5;
MALLOC(sig_temp, len, FREE(sig_dest); RET_ERR(p->handle, ALPM_ERR_MEMORY, -1));
snprintf(sig_temp, len, "%s.sig.part", p->destfile_name);
ret = unlink_or_move(sig_temp, sig_dest);
if(ret == -1) {
_alpm_log(p->handle, ALPM_LOG_ERROR, _("could not rename %s to %s (%s)\n"),
sig_temp, sig_dest, strerror(errno));
}
free(sig_dest);
free(sig_temp);
}
return ret;
}
static FILE *create_tempfile(struct dload_payload *payload, const char *localpath)
{
int fd;
FILE *fp;
char *randpath;
size_t len;
/* create a random filename, which is opened with O_EXCL */
len = strlen(localpath) + 14 + 1;
MALLOC(randpath, len, RET_ERR(payload->handle, ALPM_ERR_MEMORY, NULL));
snprintf(randpath, len, "%salpmtmp.XXXXXX", localpath);
if((fd = mkstemp(randpath)) == -1 ||
fchmod(fd, ~(_getumask()) & 0666) ||
!(fp = fdopen(fd, payload->tempfile_openmode))) {
unlink(randpath);
close(fd);
_alpm_log(payload->handle, ALPM_LOG_ERROR,
_("failed to create temporary file for download\n"));
free(randpath);
return NULL;
}
/* fp now points to our alpmtmp.XXXXXX */
free(payload->tempfile_name);
payload->tempfile_name = randpath;
free(payload->remote_name);
STRDUP(payload->remote_name, strrchr(randpath, '/') + 1,
fclose(fp); RET_ERR(payload->handle, ALPM_ERR_MEMORY, NULL));
return fp;
}
#ifdef HAVE_LIBCURL
@@ -196,7 +55,7 @@ static FILE *create_tempfile(struct dload_payload *payload, const char *localpat
#define HOSTNAME_SIZE 256
static int curl_add_payload(alpm_handle_t *handle, CURLM *curlm,
struct dload_payload *payload);
struct dload_payload *payload, const char *localpath);
static int curl_gethost(const char *url, char *buffer, size_t buf_len);
/* number of "soft" errors required to blacklist a server, set to 0 to disable
@@ -314,6 +173,29 @@ static const char *payload_next_server(struct dload_payload *payload)
return NULL;
}
static const char *get_filename(const char *url)
{
char *filename = strrchr(url, '/');
if(filename != NULL) {
return filename + 1;
}
/* no slash found, it's a filename */
return url;
}
static char *get_fullpath(const char *path, const char *filename,
const char *suffix)
{
char *filepath;
/* len = localpath len + filename len + suffix len + null */
size_t len = strlen(path) + strlen(filename) + strlen(suffix) + 1;
MALLOC(filepath, len, return NULL);
snprintf(filepath, len, "%s%s%s", path, filename, suffix);
return filepath;
}
enum {
ABORT_OVER_MAXFILESIZE = 1,
};
@@ -424,12 +306,45 @@ static int utimes_long(const char *path, long seconds)
return 0;
}
/* prefix to avoid possible future clash with getumask(3) */
static mode_t _getumask(void)
{
mode_t mask = umask(0);
umask(mask);
return mask;
}
static size_t dload_parseheader_cb(void *ptr, size_t size, size_t nmemb, void *user)
{
size_t realsize = size * nmemb;
const char *fptr, *endptr = NULL;
const char * const cd_header = "Content-Disposition:";
const char * const fn_key = "filename=";
struct dload_payload *payload = (struct dload_payload *)user;
long respcode;
(void) ptr;
if(_alpm_raw_ncmp(cd_header, ptr, strlen(cd_header)) == 0) {
if((fptr = strstr(ptr, fn_key))) {
fptr += strlen(fn_key);
/* find the end of the field, which is either a semi-colon, or the end of
* the data. As per curl_easy_setopt(3), we cannot count on headers being
* null terminated, so we look for the closing \r\n */
endptr = fptr + strcspn(fptr, ";\r\n") - 1;
/* remove quotes */
if(*fptr == '"' && *endptr == '"') {
fptr++;
endptr--;
}
/* avoid information leakage with badly formed headers */
if(endptr > fptr) {
STRNDUP(payload->content_disp_name, fptr, endptr - fptr + 1,
RET_ERR(payload->handle, ALPM_ERR_MEMORY, realsize));
}
}
}
curl_easy_getinfo(payload->curl, CURLINFO_RESPONSE_CODE, &respcode);
if(payload->respcode != respcode) {
@@ -503,6 +418,37 @@ static void curl_set_handle_opts(CURL *curl, struct dload_payload *payload)
}
}
static FILE *create_tempfile(struct dload_payload *payload, const char *localpath)
{
int fd;
FILE *fp;
char *randpath;
size_t len;
/* create a random filename, which is opened with O_EXCL */
len = strlen(localpath) + 14 + 1;
MALLOC(randpath, len, RET_ERR(payload->handle, ALPM_ERR_MEMORY, NULL));
snprintf(randpath, len, "%salpmtmp.XXXXXX", localpath);
if((fd = mkstemp(randpath)) == -1 ||
fchmod(fd, ~(_getumask()) & 0666) ||
!(fp = fdopen(fd, payload->tempfile_openmode))) {
unlink(randpath);
close(fd);
_alpm_log(payload->handle, ALPM_LOG_ERROR,
_("failed to create temporary file for download\n"));
free(randpath);
return NULL;
}
/* fp now points to our alpmtmp.XXXXXX */
free(payload->tempfile_name);
payload->tempfile_name = randpath;
free(payload->remote_name);
STRDUP(payload->remote_name, strrchr(randpath, '/') + 1,
fclose(fp); RET_ERR(payload->handle, ALPM_ERR_MEMORY, NULL));
return fp;
}
/* Return 0 if retry was successful, -1 otherwise */
static int curl_retry_next_server(CURLM *curlm, CURL *curl, struct dload_payload *payload)
{
@@ -566,7 +512,7 @@ static int curl_retry_next_server(CURLM *curlm, CURL *curl, struct dload_payload
* Returns -2 if an error happened for an optional file
*/
static int curl_check_finished_download(alpm_handle_t *handle, CURLM *curlm, CURLMsg *msg,
int *active_downloads_num)
const char *localpath, int *active_downloads_num)
{
struct dload_payload *payload = NULL;
CURL *curl = msg->easy_handle;
@@ -627,7 +573,6 @@ static int curl_check_finished_download(alpm_handle_t *handle, CURLM *curlm, CUR
case CURLE_ABORTED_BY_CALLBACK:
/* handle the interrupt accordingly */
if(dload_interrupted == ABORT_OVER_MAXFILESIZE) {
curlerr = CURLE_FILESIZE_EXCEEDED;
payload->unlink_on_fail = 1;
handle->pm_errno = ALPM_ERR_LIBCURL;
_alpm_log(handle, ALPM_LOG_ERROR,
@@ -680,6 +625,31 @@ static int curl_check_finished_download(alpm_handle_t *handle, CURLM *curlm, CUR
curl_easy_getinfo(curl, CURLINFO_CONDITION_UNMET, &timecond);
curl_easy_getinfo(curl, CURLINFO_EFFECTIVE_URL, &effective_url);
if(payload->trust_remote_name) {
if(payload->content_disp_name) {
/* content-disposition header has a better name for our file */
free(payload->destfile_name);
payload->destfile_name = get_fullpath(localpath,
get_filename(payload->content_disp_name), "");
} else {
const char *effective_filename = strrchr(effective_url, '/');
if(effective_filename && strlen(effective_filename) > 2) {
effective_filename++;
/* if destfile was never set, we wrote to a tempfile. even if destfile is
* set, we may have followed some redirects and the effective url may
* have a better suggestion as to what to name our file. in either case,
* refactor destfile to this newly derived name. */
if(!payload->destfile_name || strcmp(effective_filename,
strrchr(payload->destfile_name, '/') + 1) != 0) {
free(payload->destfile_name);
payload->destfile_name = get_fullpath(localpath, effective_filename, "");
}
}
}
}
/* Let's check if client requested downloading accompanion *.sig file */
if(!payload->signature && payload->download_signature && curlerr == CURLE_OK && payload->respcode < 400) {
struct dload_payload *sig = NULL;
@@ -711,23 +681,22 @@ static int curl_check_finished_download(alpm_handle_t *handle, CURLM *curlm, CUR
MALLOC(sig->fileurl, len, FREE(sig); GOTO_ERR(handle, ALPM_ERR_MEMORY, cleanup));
snprintf(sig->fileurl, len, "%s.sig", url);
int remote_name_len = strlen(payload->remote_name) + 5;
MALLOC(sig->remote_name, remote_name_len, _alpm_dload_payload_reset(sig);
FREE(sig); GOTO_ERR(handle, ALPM_ERR_MEMORY, cleanup));
snprintf(sig->remote_name, remote_name_len, "%s.sig", payload->remote_name);
if(payload->trust_remote_name) {
/* In this case server might provide a new name for the main payload.
* Choose *.sig filename based on this new name.
*/
const char *final_file = get_filename(realname);
int remote_name_len = strlen(final_file) + 5;
MALLOC(sig->remote_name, remote_name_len, FREE(sig->fileurl); FREE(sig); GOTO_ERR(handle, ALPM_ERR_MEMORY, cleanup));
snprintf(sig->remote_name, remote_name_len, "%s.sig", final_file);
}
/* force the filename to be realname + ".sig" */
int destfile_name_len = strlen(realname) + 5;
MALLOC(sig->destfile_name, destfile_name_len, _alpm_dload_payload_reset(sig);
FREE(sig); GOTO_ERR(handle, ALPM_ERR_MEMORY, cleanup));
MALLOC(sig->destfile_name, destfile_name_len, FREE(sig->remote_name);
FREE(sig->fileurl); FREE(sig); GOTO_ERR(handle, ALPM_ERR_MEMORY, cleanup));
snprintf(sig->destfile_name, destfile_name_len, "%s.sig", realname);
int tempfile_name_len = strlen(realname) + 10;
MALLOC(sig->tempfile_name, tempfile_name_len, _alpm_dload_payload_reset(sig);
FREE(sig); GOTO_ERR(handle, ALPM_ERR_MEMORY, cleanup));
snprintf(sig->tempfile_name, tempfile_name_len, "%s.sig.part", realname);
sig->signature = 1;
sig->handle = handle;
sig->force = payload->force;
@@ -736,7 +705,7 @@ static int curl_check_finished_download(alpm_handle_t *handle, CURLM *curlm, CUR
/* set hard upper limit of 16KiB */
sig->max_size = 16 * 1024;
curl_add_payload(handle, curlm, sig);
curl_add_payload(handle, curlm, sig, localpath);
(*active_downloads_num)++;
}
@@ -775,7 +744,7 @@ cleanup:
}
if(ret == 0) {
if(payload->destfile_name && handle->sandboxuser == NULL) {
if(payload->destfile_name) {
if(rename(payload->tempfile_name, payload->destfile_name)) {
_alpm_log(handle, ALPM_LOG_ERROR, _("could not rename %s to %s (%s)\n"),
payload->tempfile_name, payload->destfile_name, strerror(errno));
@@ -819,7 +788,7 @@ cleanup:
* Returns -1 if am error happened while starting a new download
*/
static int curl_add_payload(alpm_handle_t *handle, CURLM *curlm,
struct dload_payload *payload)
struct dload_payload *payload, const char *localpath)
{
size_t len;
CURL *curl = NULL;
@@ -845,11 +814,35 @@ static int curl_add_payload(alpm_handle_t *handle, CURLM *curlm,
}
payload->tempfile_openmode = "wb";
if(!payload->remote_name) {
STRDUP(payload->remote_name, get_filename(payload->fileurl),
GOTO_ERR(handle, ALPM_ERR_MEMORY, cleanup));
}
if(curl_gethost(payload->fileurl, hostname, sizeof(hostname)) != 0) {
_alpm_log(handle, ALPM_LOG_ERROR, _("url '%s' is invalid\n"), payload->fileurl);
GOTO_ERR(handle, ALPM_ERR_SERVER_BAD_URL, cleanup);
}
if(!payload->random_partfile && payload->remote_name && strlen(payload->remote_name) > 0) {
if(!payload->destfile_name) {
payload->destfile_name = get_fullpath(localpath, payload->remote_name, "");
}
payload->tempfile_name = get_fullpath(localpath, payload->remote_name, ".part");
if(!payload->destfile_name || !payload->tempfile_name) {
goto cleanup;
}
} else {
/* We want a random filename or the URL does not contain a filename, so download to a
* temporary location. We can not support resuming this kind of download; any partial
* transfers will be destroyed */
payload->unlink_on_fail = 1;
payload->localf = create_tempfile(payload, localpath);
if(payload->localf == NULL) {
goto cleanup;
}
}
curl_set_handle_opts(curl, payload);
if(payload->max_size == payload->initial_size && payload->max_size != 0) {
@@ -907,7 +900,8 @@ static int compare_dload_payload_sizes(const void *left_ptr, const void *right_p
* Returns 1 if no files were downloaded and all errors were non-fatal
*/
static int curl_download_internal(alpm_handle_t *handle,
alpm_list_t *payloads /* struct dload_payload */)
alpm_list_t *payloads /* struct dload_payload */,
const char *localpath)
{
int active_downloads_num = 0;
int err = 0;
@@ -925,7 +919,7 @@ static int curl_download_internal(alpm_handle_t *handle,
for(; active_downloads_num < max_streams && payloads; active_downloads_num++) {
struct dload_payload *payload = payloads->data;
if(curl_add_payload(handle, curlm, payload) == 0) {
if(curl_add_payload(handle, curlm, payload, localpath) == 0) {
payloads = payloads->next;
} else {
/* The payload failed to start. Do not start any new downloads.
@@ -956,7 +950,7 @@ static int curl_download_internal(alpm_handle_t *handle,
}
if(msg->msg == CURLMSG_DONE) {
int ret = curl_check_finished_download(handle, curlm, msg,
&active_downloads_num);
localpath, &active_downloads_num);
if(ret == -1) {
/* if current payload failed to download then stop adding new payloads but wait for the
* current ones
@@ -972,160 +966,9 @@ static int curl_download_internal(alpm_handle_t *handle,
}
}
_alpm_log(handle, ALPM_LOG_DEBUG, "curl_download_internal return code is %d\n", err);
return err ? -1 : updated ? 0 : 1;
}
/* Download the requested files by launching a process inside a sandbox.
* Returns -1 if an error happened for a required file
* Returns 0 if a payload was actually downloaded
* Returns 1 if no files were downloaded and all errors were non-fatal
*/
static int curl_download_internal_sandboxed(alpm_handle_t *handle,
alpm_list_t *payloads /* struct dload_payload */,
const char *localpath)
{
int pid, err = 0, ret = -1, callbacks_fd[2];
sigset_t oldblock;
struct sigaction sa_ign, oldint, oldquit;
_alpm_sandbox_callback_context callbacks_ctx;
sigemptyset(&sa_ign.sa_mask);
sa_ign.sa_handler = SIG_IGN;
sa_ign.sa_flags=0;
if(pipe(callbacks_fd) != 0) {
return -1;
}
sigaction(SIGINT, &sa_ign, &oldint);
sigaction(SIGQUIT, &sa_ign, &oldquit);
sigaddset(&sa_ign.sa_mask, SIGCHLD);
sigprocmask(SIG_BLOCK, &sa_ign.sa_mask, &oldblock);
pid = fork();
if(pid == -1) {
/* fork failed, make sure errno is preserved after cleanup */
err = errno;
}
/* child */
if(pid == 0) {
close(callbacks_fd[0]);
fcntl(callbacks_fd[1], F_SETFD, FD_CLOEXEC);
callbacks_ctx.callback_pipe = callbacks_fd[1];
alpm_option_set_logcb(handle, _alpm_sandbox_cb_log, &callbacks_ctx);
alpm_option_set_dlcb(handle, _alpm_sandbox_cb_dl, &callbacks_ctx);
alpm_option_set_fetchcb(handle, NULL, NULL);
alpm_option_set_eventcb(handle, NULL, NULL);
alpm_option_set_questioncb(handle, NULL, NULL);
alpm_option_set_progresscb(handle, NULL, NULL);
/* restore default signal handling in the child */
_alpm_reset_signals();
/* cwd to the download directory */
ret = chdir(localpath);
if(ret != 0) {
handle->pm_errno = errno;
_alpm_log(handle, ALPM_LOG_ERROR, _("could not chdir to download directory %s\n"), localpath);
ret = -1;
} else {
ret = alpm_sandbox_setup_child(handle->sandboxuser);
if (ret != 0) {
_alpm_log(handle, ALPM_LOG_ERROR, _("switching to sandbox user '%s' failed!\n"), handle->sandboxuser);
_Exit(ret | 128);
}
ret = curl_download_internal(handle, payloads);
}
/* pass the result back to the parent */
if(ret == 0) {
/* a payload was actually downloaded */
_Exit(0);
}
else if(ret == 1) {
/* no files were downloaded and all errors were non-fatal */
_Exit(handle->pm_errno);
}
else {
/* an error happened for a required file */
_Exit(handle->pm_errno | 128);
}
}
/* parent */
close(callbacks_fd[1]);
if(pid != -1) {
bool had_error = false;
while(true) {
_alpm_sandbox_callback_t callback_type;
ssize_t got = read(callbacks_fd[0], &callback_type, sizeof(callback_type));
if(got < 0 || (size_t)got != sizeof(callback_type)) {
had_error = true;
break;
}
if(callback_type == ALPM_SANDBOX_CB_DOWNLOAD) {
if(!_alpm_sandbox_process_cb_download(handle, callbacks_fd[0])) {
had_error = true;
break;
}
}
else if(callback_type == ALPM_SANDBOX_CB_LOG) {
if(!_alpm_sandbox_process_cb_log(handle, callbacks_fd[0])) {
had_error = true;
break;
}
}
}
if(had_error) {
kill(pid, SIGTERM);
}
int wret;
while((wret = waitpid(pid, &ret, 0)) == -1 && errno == EINTR);
if(wret > 0) {
if(!WIFEXITED(ret)) {
/* the child did not terminate normally */
ret = -1;
}
else {
ret = WEXITSTATUS(ret);
if(ret != 0) {
if(ret & 128) {
/* an error happened for a required file, or unexpected exit status */
handle->pm_errno = ret & ~128;
ret = -1;
}
else {
handle->pm_errno = ret;
ret = 1;
}
}
}
}
else {
/* waitpid failed */
err = errno;
}
}
close(callbacks_fd[0]);
sigaction(SIGINT, &oldint, NULL);
sigaction(SIGQUIT, &oldquit, NULL);
sigprocmask(SIG_SETMASK, &oldblock, NULL);
if(err) {
errno = err;
ret = -1;
}
return ret;
int ret = err ? -1 : updated ? 0 : 1;
_alpm_log(handle, ALPM_LOG_DEBUG, "curl_download_internal return code is %d\n", ret);
return ret;
}
#endif
@@ -1157,26 +1000,7 @@ int _alpm_download(alpm_handle_t *handle,
{
if(handle->fetchcb == NULL) {
#ifdef HAVE_LIBCURL
if(handle->sandboxuser) {
int ret = 0;
alpm_list_t *i;
for(i = payloads; i; i = i->next) {
struct dload_payload *p = i->data;
intialize_download_file(p);
}
ret = curl_download_internal_sandboxed(handle, payloads, localpath);
for(i = payloads; i; i = i->next) {
struct dload_payload *p = i->data;
finalize_download_file(p);
}
return ret;
} else {
return curl_download_internal(handle, payloads);
}
return curl_download_internal(handle, payloads, localpath);
#else
RET_ERR(handle, ALPM_ERR_EXTERNAL_DOWNLOAD, -1);
#endif
@@ -1255,34 +1079,16 @@ int SYMEXPORT alpm_fetch_pkgurl(alpm_handle_t *handle, const alpm_list_t *urls,
CALLOC(payload, 1, sizeof(*payload), GOTO_ERR(handle, ALPM_ERR_MEMORY, err));
STRDUP(payload->fileurl, url, FREE(payload); GOTO_ERR(handle, ALPM_ERR_MEMORY, err));
STRDUP(payload->remote_name, get_filename(payload->fileurl),
GOTO_ERR(handle, ALPM_ERR_MEMORY, err));
c = strrchr(url, '/');
if(payload->remote_name && strlen(payload->remote_name) > 0 && strstr(c, ".pkg")) {
if(strstr(c, ".pkg")) {
/* we probably have a usable package filename to download to */
payload->destfile_name = _alpm_get_fullpath(cachedir, payload->remote_name, "");
payload->tempfile_name = _alpm_get_fullpath(cachedir, payload->remote_name, ".part");
payload->allow_resume = 1;
if(!payload->destfile_name || !payload->tempfile_name) {
goto err;
}
} else {
/* The URL does not contain a filename, so download to a temporary location.
* We can not support resuming this kind of download; any partial transfers
* will be destroyed */
payload->unlink_on_fail = 1;
payload->tempfile_openmode = "wb";
payload->localf = create_tempfile(payload, cachedir);
if(payload->localf == NULL) {
goto err;
}
payload->random_partfile = 1;
}
payload->handle = handle;
payload->trust_remote_name = 1;
payload->download_signature = (handle->siglevel & ALPM_SIG_PACKAGE);
payload->signature_optional = (handle->siglevel & ALPM_SIG_PACKAGE_OPTIONAL);
payloads = alpm_list_add(payloads, payload);
@@ -1343,6 +1149,7 @@ void _alpm_dload_payload_reset(struct dload_payload *payload)
FREE(payload->remote_name);
FREE(payload->tempfile_name);
FREE(payload->destfile_name);
FREE(payload->content_disp_name);
FREE(payload->fileurl);
FREE(payload->filepath);
*payload = (struct dload_payload){0};

View File

@@ -26,12 +26,10 @@
struct dload_payload {
alpm_handle_t *handle;
const char *tempfile_openmode;
/* name of the remote file */
char *remote_name;
/* temporary file name, to which the payload is downloaded */
char *tempfile_name;
/* name to which the downloaded file will be renamed */
char *destfile_name;
char *content_disp_name;
/* client has to provide either
* 1) fileurl - full URL to the file
* 2) pair of (servers, filepath), in this case ALPM iterates over the
@@ -47,17 +45,19 @@ struct dload_payload {
off_t prevprogress;
int force;
int allow_resume;
int random_partfile;
int errors_ok;
int unlink_on_fail;
int trust_remote_name;
int download_signature; /* specifies if an accompanion *.sig file need to be downloaded*/
int signature_optional; /* *.sig file is optional */
#ifdef HAVE_LIBCURL
CURL *curl;
char error_buffer[CURL_ERROR_SIZE];
FILE *localf; /* temp download file */
int signature; /* specifies if this payload is for a signature file */
int request_errors_ok; /* per-request errors-ok */
#endif
FILE *localf; /* temp download file */
};
void _alpm_dload_payload_reset(struct dload_payload *payload);

View File

@@ -101,7 +101,6 @@ void _alpm_handle_free(alpm_handle_t *handle)
FREE(handle->lockfile);
FREELIST(handle->architectures);
FREE(handle->gpgdir);
FREE(handle->sandboxuser);
FREELIST(handle->noupgrade);
FREELIST(handle->noextract);
FREELIST(handle->ignorepkg);
@@ -293,12 +292,6 @@ const char SYMEXPORT *alpm_option_get_gpgdir(alpm_handle_t *handle)
return handle->gpgdir;
}
const char SYMEXPORT *alpm_option_get_sandboxuser(alpm_handle_t *handle)
{
CHECK_HANDLE(handle, return NULL);
return handle->sandboxuser;
}
int SYMEXPORT alpm_option_get_usesyslog(alpm_handle_t *handle)
{
CHECK_HANDLE(handle, return -1);
@@ -602,19 +595,6 @@ int SYMEXPORT alpm_option_set_gpgdir(alpm_handle_t *handle, const char *gpgdir)
return 0;
}
int SYMEXPORT alpm_option_set_sandboxuser(alpm_handle_t *handle, const char *sandboxuser)
{
CHECK_HANDLE(handle, return -1);
if(handle->sandboxuser) {
FREE(handle->sandboxuser);
}
STRDUP(handle->sandboxuser, sandboxuser, RET_ERR(handle, ALPM_ERR_MEMORY, -1));
_alpm_log(handle, ALPM_LOG_DEBUG, "option 'sandboxuser' = %s\n", handle->sandboxuser);
return 0;
}
int SYMEXPORT alpm_option_set_usesyslog(alpm_handle_t *handle, int usesyslog)
{
CHECK_HANDLE(handle, return -1);

View File

@@ -91,7 +91,6 @@ 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 *sandboxuser; /* User to switch to for sensitive operations */
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 */

View File

@@ -24,7 +24,6 @@ libalpm_sources = files('''
pkghash.h pkghash.c
rawstr.c
remove.h remove.c
sandbox.h sandbox.c
signing.c signing.h
sync.h sync.c
trans.h trans.c

View File

@@ -21,6 +21,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <limits.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
@@ -844,3 +845,58 @@ int SYMEXPORT alpm_pkg_should_ignore(alpm_handle_t *handle, alpm_pkg_t *pkg)
return 0;
}
/* check that package metadata meets our requirements */
int _alpm_pkg_check_meta(alpm_pkg_t *pkg)
{
char *c;
int error_found = 0;
#define EPKGMETA(error) do { \
error_found = -1; \
_alpm_log(pkg->handle, ALPM_LOG_ERROR, error, pkg->name, pkg->version); \
} while(0)
/* sanity check */
if(pkg->handle == NULL) {
return -1;
}
/* immediate bail if package doesn't have name or version */
if(pkg->name == NULL || pkg->name[0] == '\0'
|| pkg->version == NULL || pkg->version[0] == '\0') {
_alpm_log(pkg->handle, ALPM_LOG_ERROR,
_("invalid package metadata (name or version missing)"));
return -1;
}
if(pkg->name[0] == '-' || pkg->name[0] == '.') {
EPKGMETA(_("invalid metadata for package %s-%s "
"(package name cannot start with '.' or '-')\n"));
}
if(_alpm_fnmatch(pkg->name, "[![:alnum:]+_.@-]") == 0) {
EPKGMETA(_("invalid metadata for package %s-%s "
"(package name contains invalid characters)\n"));
}
/* multiple '-' in pkgver can cause local db entries for different packages
* to overlap (e.g. foo-1=2-3 and foo=1-2-3 both give foo-1-2-3) */
if((c = strchr(pkg->version, '-')) && (strchr(c + 1, '-'))) {
EPKGMETA(_("invalid metadata for package %s-%s "
"(package version contains invalid characters)\n"));
}
if(strchr(pkg->version, '/')) {
EPKGMETA(_("invalid metadata for package %s-%s "
"(package version contains invalid characters)\n"));
}
/* local db entry is <pkgname>-<pkgver> */
if(strlen(pkg->name) + strlen(pkg->version) + 1 > NAME_MAX) {
EPKGMETA(_("invalid metadata for package %s-%s "
"(package name and version too long)\n"));
}
#undef EPKGMETA
return error_found;
}

View File

@@ -165,4 +165,6 @@ int _alpm_pkg_compare_versions(alpm_pkg_t *local_pkg, alpm_pkg_t *pkg);
alpm_pkg_xdata_t *_alpm_pkg_parse_xdata(const char *string);
void _alpm_pkg_xdata_free(alpm_pkg_xdata_t *pd);
int _alpm_pkg_check_meta(alpm_pkg_t *pkg);
#endif /* ALPM_PACKAGE_H */

View File

@@ -1,224 +0,0 @@
/*
* sandbox.c
*
* Copyright (c) 2021-2022 Pacman Development Team <pacman-dev@lists.archlinux.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 <errno.h>
#include <grp.h>
#include <pwd.h>
#include <sys/types.h>
#include <unistd.h>
#include "alpm.h"
#include "log.h"
#include "sandbox.h"
#include "util.h"
int SYMEXPORT alpm_sandbox_setup_child(const char* sandboxuser)
{
struct passwd const *pw = NULL;
ASSERT(sandboxuser != NULL, return EINVAL);
ASSERT(getuid() == 0, return EPERM);
ASSERT((pw = getpwnam(sandboxuser)), return errno);
ASSERT(setgid(pw->pw_gid) == 0, return errno);
ASSERT(setgroups(0, NULL) == 0, return errno);
ASSERT(setuid(pw->pw_uid) == 0, return errno);
return 0;
}
static int should_retry(int errnum)
{
return errnum == EINTR;
}
static int read_from_pipe(int fd, void *buf, size_t count)
{
size_t nread = 0;
ASSERT(count > 0, return -1);
while(nread < count) {
ssize_t r = read(fd, (char *)buf + nread, count-nread);
if(r < 0) {
if(!should_retry(errno)) {
return -1;
}
continue;
}
if(r == 0) {
/* we hit EOF unexpectedly - bail */
return -1;
}
nread += r;
}
return 0;
}
static int write_to_pipe(int fd, const void *buf, size_t count)
{
size_t nwrite = 0;
ASSERT(count > 0, return -1);
while(nwrite < count) {
ssize_t r = write(fd, (char *)buf + nwrite, count-nwrite);
if(r < 0) {
if(!should_retry(errno)) {
return -1;
}
continue;
}
nwrite += r;
}
return 0;
}
void _alpm_sandbox_cb_log(void *ctx, alpm_loglevel_t level, const char *fmt, va_list args)
{
_alpm_sandbox_callback_t type = ALPM_SANDBOX_CB_LOG;
_alpm_sandbox_callback_context *context = ctx;
char *string = NULL;
int string_size = 0;
if(!context || context->callback_pipe == -1) {
return;
}
/* compute the required size, as allowed by POSIX.1-2001 and C99 */
/* first we need to copy the va_list as it will be consumed by the first call */
va_list copy;
va_copy(copy, args);
string_size = vsnprintf(NULL, 0, fmt, copy);
if(string_size <= 0) {
va_end(copy);
return;
}
MALLOC(string, string_size + 1, return);
string_size = vsnprintf(string, string_size + 1, fmt, args);
if(string_size > 0) {
write_to_pipe(context->callback_pipe, &type, sizeof(type));
write_to_pipe(context->callback_pipe, &level, sizeof(level));
write_to_pipe(context->callback_pipe, &string_size, sizeof(string_size));
write_to_pipe(context->callback_pipe, string, string_size);
}
va_end(copy);
FREE(string);
}
void _alpm_sandbox_cb_dl(void *ctx, const char *filename, alpm_download_event_type_t event, void *data)
{
_alpm_sandbox_callback_t type = ALPM_SANDBOX_CB_DOWNLOAD;
_alpm_sandbox_callback_context *context = ctx;
size_t filename_len;
if(!context || context->callback_pipe == -1) {
return;
}
ASSERT(filename != NULL, return);
ASSERT(event == ALPM_DOWNLOAD_INIT || event == ALPM_DOWNLOAD_PROGRESS || event == ALPM_DOWNLOAD_RETRY || event == ALPM_DOWNLOAD_COMPLETED, return);
filename_len = strlen(filename);
write_to_pipe(context->callback_pipe, &type, sizeof(type));
write_to_pipe(context->callback_pipe, &event, sizeof(event));
switch(event) {
case ALPM_DOWNLOAD_INIT:
write_to_pipe(context->callback_pipe, data, sizeof(alpm_download_event_init_t));
break;
case ALPM_DOWNLOAD_PROGRESS:
write_to_pipe(context->callback_pipe, data, sizeof(alpm_download_event_progress_t));
break;
case ALPM_DOWNLOAD_RETRY:
write_to_pipe(context->callback_pipe, data, sizeof(alpm_download_event_retry_t));
break;
case ALPM_DOWNLOAD_COMPLETED:
write_to_pipe(context->callback_pipe, data, sizeof(alpm_download_event_completed_t));
break;
}
write_to_pipe(context->callback_pipe, &filename_len, sizeof(filename_len));
write_to_pipe(context->callback_pipe, filename, filename_len);
}
bool _alpm_sandbox_process_cb_log(alpm_handle_t *handle, int callback_pipe) {
alpm_loglevel_t level;
char *string = NULL;
int string_size = 0;
ASSERT(read_from_pipe(callback_pipe, &level, sizeof(level)) != -1, return false);
ASSERT(read_from_pipe(callback_pipe, &string_size, sizeof(string_size)) != -1, return false);
MALLOC(string, string_size + 1, return false);
ASSERT(read_from_pipe(callback_pipe, string, string_size) != -1, FREE(string); return false);
string[string_size] = '\0';
_alpm_log(handle, level, "%s", string);
FREE(string);
return true;
}
bool _alpm_sandbox_process_cb_download(alpm_handle_t *handle, int callback_pipe) {
alpm_download_event_type_t type;
char *filename = NULL;
size_t filename_size, cb_data_size;
union {
alpm_download_event_init_t init;
alpm_download_event_progress_t progress;
alpm_download_event_retry_t retry;
alpm_download_event_completed_t completed;
} cb_data;
ASSERT(read_from_pipe(callback_pipe, &type, sizeof(type)) != -1, return false);
switch (type) {
case ALPM_DOWNLOAD_INIT:
cb_data_size = sizeof(alpm_download_event_init_t);
ASSERT(read_from_pipe(callback_pipe, &cb_data.init, cb_data_size) != -1, return false);
break;
case ALPM_DOWNLOAD_PROGRESS:
cb_data_size = sizeof(alpm_download_event_progress_t);
ASSERT(read_from_pipe(callback_pipe, &cb_data.progress, cb_data_size) != -1, return false);
break;
case ALPM_DOWNLOAD_RETRY:
cb_data_size = sizeof(alpm_download_event_retry_t);
ASSERT(read_from_pipe(callback_pipe, &cb_data.retry, cb_data_size) != -1, return false);
break;
case ALPM_DOWNLOAD_COMPLETED:
cb_data_size = sizeof(alpm_download_event_completed_t);
ASSERT(read_from_pipe(callback_pipe, &cb_data.completed, cb_data_size) != -1, return false);
break;
default:
return false;
}
ASSERT(read_from_pipe(callback_pipe, &filename_size, sizeof(filename_size)) != -1, return false);;
MALLOC(filename, filename_size + 1, return false);
ASSERT(read_from_pipe(callback_pipe, filename, filename_size) != -1, FREE(filename); return false);
filename[filename_size] = '\0';
handle->dlcb(handle->dlcb_ctx, filename, type, &cb_data);
FREE(filename);
return true;
}

View File

@@ -1,51 +0,0 @@
/*
* sandbox.h
*
* Copyright (c) 2021-2022 Pacman Development Team <pacman-dev@lists.archlinux.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_SANDBOX_H
#define ALPM_SANDBOX_H
#include <stdbool.h>
/* The type of callbacks that can happen during a sandboxed operation */
typedef enum {
ALPM_SANDBOX_CB_LOG,
ALPM_SANDBOX_CB_DOWNLOAD
} _alpm_sandbox_callback_t;
typedef struct {
int callback_pipe;
} _alpm_sandbox_callback_context;
/* Sandbox callbacks */
__attribute__((format(printf, 3, 0)))
void _alpm_sandbox_cb_log(void *ctx, alpm_loglevel_t level, const char *fmt, va_list args);
void _alpm_sandbox_cb_dl(void *ctx, const char *filename, alpm_download_event_type_t event, void *data);
/* Functions to capture sandbox callbacks and convert them to alpm callbacks */
bool _alpm_sandbox_process_cb_log(alpm_handle_t *handle, int callback_pipe);
bool _alpm_sandbox_process_cb_download(alpm_handle_t *handle, int callback_pipe);
#endif /* ALPM_SANDBOX_H */

View File

@@ -767,7 +767,6 @@ static int find_dl_candidates(alpm_handle_t *handle, alpm_list_t **files)
return 0;
}
static int download_files(alpm_handle_t *handle)
{
const char *cachedir;
@@ -826,15 +825,8 @@ static int download_files(alpm_handle_t *handle)
CALLOC(payload, 1, sizeof(*payload), GOTO_ERR(handle, ALPM_ERR_MEMORY, finish));
STRDUP(payload->remote_name, pkg->filename, FREE(payload); GOTO_ERR(handle, ALPM_ERR_MEMORY, finish));
STRDUP(payload->filepath, pkg->filename,
_alpm_dload_payload_reset(payload); FREE(payload);
FREE(payload->remote_name); FREE(payload);
GOTO_ERR(handle, ALPM_ERR_MEMORY, finish));
payload->destfile_name = _alpm_get_fullpath(cachedir, payload->remote_name, "");
payload->tempfile_name = _alpm_get_fullpath(cachedir, payload->remote_name, ".part");
if(!payload->destfile_name || !payload->tempfile_name) {
_alpm_dload_payload_reset(payload);
FREE(payload);
GOTO_ERR(handle, ALPM_ERR_MEMORY, finish);
}
payload->max_size = pkg->size;
payload->cache_servers = pkg->origin_data.db->cache_servers;
payload->servers = pkg->origin_data.db->servers;

View File

@@ -197,23 +197,6 @@ cleanup:
return ret;
}
/** Combines a directory, filename and suffix to provide full path of a file
* @param path directory path
* @param filename file name
* @param suffix suffix
* @return file path
*/
char *_alpm_get_fullpath(const char *path, const char *filename, const char *suffix)
{
char *filepath;
/* len = localpath len + filename len + suffix len + null */
size_t len = strlen(path) + strlen(filename) + strlen(suffix) + 1;
MALLOC(filepath, len, return NULL);
snprintf(filepath, len, "%s%s%s", path, filename, suffix);
return filepath;
}
/** Trim trailing newlines from a string (if any exist).
* @param str a single line of text
* @param len size of str, if known, else 0
@@ -572,7 +555,7 @@ static int _alpm_chroot_read_from_child(alpm_handle_t *handle, int fd,
return 0;
}
void _alpm_reset_signals(void)
static void _alpm_reset_signals(void)
{
/* reset POSIX defined signals (see signal.h) */
/* there are likely more but there is no easy way

View File

@@ -116,7 +116,6 @@ struct archive_read_buffer {
int _alpm_makepath(const char *path);
int _alpm_makepath_mode(const char *path, mode_t mode);
int _alpm_copyfile(const char *src, const char *dest);
char *_alpm_get_fullpath(const char *path, const char *filename, const char *suffix);
size_t _alpm_strip_newline(char *str, size_t len);
int _alpm_open_archive(alpm_handle_t *handle, const char *path,
@@ -130,7 +129,6 @@ ssize_t _alpm_files_in_directory(alpm_handle_t *handle, const char *path, int fu
typedef ssize_t (*_alpm_cb_io)(void *buf, ssize_t len, void *ctx);
void _alpm_reset_signals(void);
int _alpm_run_chroot(alpm_handle_t *handle, const char *cmd, char *const argv[],
_alpm_cb_io in_cb, void *in_ctx);
int _alpm_ldconfig(alpm_handle_t *handle);

View File

@@ -57,7 +57,7 @@ static alpm_list_t *output = NULL;
#endif
struct pacman_progress_bar {
char *filename;
const char *filename;
off_t xfered; /* Current amount of transferred data */
off_t total_size;
size_t downloaded;
@@ -589,7 +589,7 @@ void cb_progress(void *ctx, alpm_progress_t event, const char *pkgname,
} else {
if(current != prevcurrent) {
/* update always */
} else if(!pkgname || percent == prevpercent ||
} else if(pkgname[0] == '\0' || percent == prevpercent ||
get_update_timediff(0) < UPDATE_SPEED_MS) {
/* only update the progress bar when we have a package name, the
* percentage has changed, and it has been long enough. */
@@ -653,7 +653,7 @@ void cb_progress(void *ctx, alpm_progress_t event, const char *pkgname,
* by the output, and then pad it accordingly so we fill the terminal.
*/
/* len = opr len + pkgname len (if available) + space + null */
len = strlen(opr) + ((pkgname) ? strlen(pkgname) : 0) + 2;
len = strlen(opr) + strlen(pkgname) + 2;
wcstr = calloc(len, sizeof(wchar_t));
/* print our strings to the alloc'ed memory */
#if defined(HAVE_SWPRINTF)
@@ -745,8 +745,7 @@ static void init_total_progressbar(void)
{
totalbar = calloc(1, sizeof(struct pacman_progress_bar));
assert(totalbar);
totalbar->filename = strdup(_("Total"));
assert(totalbar->filename);
totalbar->filename = _("Total");
totalbar->init_time = get_time_ms();
totalbar->total_size = list_total;
totalbar->howmany = list_total_pkgs;
@@ -883,8 +882,7 @@ static void dload_init_event(const char *filename, alpm_download_event_init_t *d
struct pacman_progress_bar *bar = calloc(1, sizeof(struct pacman_progress_bar));
assert(bar);
bar->filename = strdup(filename);
assert(bar->filename);
bar->filename = filename;
bar->init_time = get_time_ms();
bar->rate = 0.0;
multibar_ui.active_downloads = alpm_list_add(multibar_ui.active_downloads, bar);
@@ -1089,7 +1087,6 @@ static void dload_complete_event(const char *filename, alpm_download_event_compl
multibar_ui.active_downloads = alpm_list_remove_item(
multibar_ui.active_downloads, head);
free(head);
free(j->filename);
free(j);
} else {
break;

View File

@@ -155,7 +155,6 @@ int config_free(config_t *oldconfig)
free(oldconfig->dbpath);
free(oldconfig->logfile);
free(oldconfig->gpgdir);
free(oldconfig->sandboxuser);
FREELIST(oldconfig->hookdirs);
FREELIST(oldconfig->cachedirs);
free(oldconfig->xfercommand);
@@ -670,11 +669,6 @@ static int _parse_options(const char *key, char *value,
config->logfile = strdup(value);
pm_printf(ALPM_LOG_DEBUG, "config: logfile: %s\n", value);
}
} else if(strcmp(key, "DownloadUser") == 0) {
if(!config->sandboxuser) {
config->sandboxuser = strdup(value);
pm_printf(ALPM_LOG_DEBUG, "config: sandboxuser: %s\n", value);
}
} else if(strcmp(key, "XferCommand") == 0) {
char **c;
if((config->xfercommand_argv = wordsplit(value)) == NULL) {
@@ -927,7 +921,6 @@ static int setup_libalpm(void)
alpm_option_set_architectures(handle, config->architectures);
alpm_option_set_checkspace(handle, config->checkspace);
alpm_option_set_usesyslog(handle, config->usesyslog);
alpm_option_set_sandboxuser(handle, config->sandboxuser);
alpm_option_set_ignorepkgs(handle, config->ignorepkg);
alpm_option_set_ignoregroups(handle, config->ignoregrp);

View File

@@ -68,7 +68,6 @@ typedef struct __config_t {
char *logfile;
char *gpgdir;
char *sysroot;
char *sandboxuser;
alpm_list_t *hookdirs;
alpm_list_t *cachedirs;
alpm_list_t *architectures;

View File

@@ -252,7 +252,6 @@ static void dump_config(void)
show_list_str("HookDir", config->hookdirs);
show_str("GPGDir", config->gpgdir);
show_str("LogFile", config->logfile);
show_str("DownloadUser", config->sandboxuser);
show_list_str("HoldPkg", config->holdpkg);
show_list_str("IgnorePkg", config->ignorepkg);
@@ -353,8 +352,6 @@ static int list_directives(void)
show_str("GPGDir", config->gpgdir);
} else if(strcasecmp(i->data, "LogFile") == 0) {
show_str("LogFile", config->logfile);
} else if(strcasecmp(i->data, "DownloadUser") == 0) {
show_str("DownloadUser", config->sandboxuser);
} else if(strcasecmp(i->data, "HoldPkg") == 0) {
show_list_str("HoldPkg", config->holdpkg);

View File

@@ -381,7 +381,7 @@ static int parsearg_global(int opt)
break;
case OP_ASK:
config->noask = 1;
config->ask = (unsigned int)atoi(optarg);
config->ask = (unsigned int)strtol(optarg, NULL, 10);
break;
case OP_CACHEDIR:
config->cachedirs = alpm_list_add(config->cachedirs, strdup(optarg));
@@ -409,7 +409,7 @@ static int parsearg_global(int opt)
* here, error and warning are set in config_new, though perhaps a
* --quiet option will remove these later */
if(optarg) {
unsigned short debug = (unsigned short)atoi(optarg);
int debug = strtol(optarg, NULL, 10);
switch(debug) {
case 2:
config->logmask |= ALPM_LOG_FUNCTION;

View File

@@ -462,7 +462,7 @@ static size_t string_length(const char *s)
int iter = 0;
for(; *s; s++) {
if(*s == '\033') {
while(*s != 'm') {
while(*s != 'm' && *s != '\0') {
s++;
}
} else {

View File

@@ -97,6 +97,9 @@ pacman_tests = [
'tests/pacman003.py',
'tests/pacman004.py',
'tests/pacman005.py',
'tests/pkg-meta-invalid-name-file.py',
'tests/pkg-meta-invalid-name-local.py',
'tests/pkg-meta-invalid-name-sync.py',
'tests/provision001.py',
'tests/provision002.py',
'tests/provision003.py',
@@ -155,8 +158,6 @@ pacman_tests = [
'tests/replace103.py',
'tests/replace104.py',
'tests/replace110.py',
'tests/sandbox-download-upgrade.py',
'tests/sandbox-download-basic.py',
'tests/scriptlet001.py',
'tests/scriptlet002.py',
'tests/scriptlet-signal-handling.py',
@@ -336,6 +337,7 @@ pacman_tests = [
'tests/xfercommand001.py',
'tests/upgrade-download-404.py',
'tests/upgrade-download-pkg-and-sig-with-filename.py',
'tests/upgrade-download-pkg-and-sig-without-filename.py',
'tests/upgrade-download-with-xfercommand.py',
]
@@ -348,6 +350,7 @@ xfail_tests = {
'tests/sync403.py': true,
'tests/sync406.py': true,
'tests/upgrade078.py': true,
'tests/upgrade-download-with-xfercommand.py': true,
}
foreach input : pacman_tests

View File

@@ -1,11 +0,0 @@
self.description = "refresh databases with Optional siglevel"
self.require_capability("curl")
p1 = pmpkg('pkg1', '1.0-1')
self.addpkg2db('sync', p1)
self.db['sync'].option['SigLevel'] = ["Optional"]
self.args = '-Syy'
self.addrule("PACMAN_RETCODE=0")

View File

@@ -0,0 +1,9 @@
self.description = "package name with invalid characters cannot be installed (file)"
p = pmpkg("-foo")
self.addpkg(p)
self.args = "-U -- %s" % p.filename()
self.addrule("!PACMAN_RETCODE=0")
self.addrule("!PKG_EXIST=-foo")

View File

@@ -0,0 +1,9 @@
self.description = "local package name with invalid characters can be removed"
sp = pmpkg("-foo")
self.addpkg2db("local", sp)
self.args = "-R -- %s" % sp.name
self.addrule("PACMAN_RETCODE=0")
self.addrule("!PKG_EXIST=-foo")

View File

@@ -0,0 +1,9 @@
self.description = "package name with invalid characters cannot be installed"
sp = pmpkg("-foo")
self.addpkg2db("sync", sp)
self.args = "-S -- %s" % sp.name
self.addrule("!PACMAN_RETCODE=0")
self.addrule("!PKG_EXIST=-foo")

View File

@@ -1,20 +0,0 @@
self.description = "--sync with DownloadUser set"
self.require_capability("curl")
p1 = pmpkg('pkg1', '1.0-1')
self.addpkg2db('sync', p1)
url = self.add_simple_http_server({
'/{}'.format(p1.filename()): p1.makepkg_bytes(),
})
self.option['DownloadUser'] = ['root']
self.db['sync'].option['Server'] = [ url ]
self.db['sync'].syncdir = False
self.cachepkgs = False
self.args = '-S pkg1'
self.addrule("PACMAN_RETCODE=0")
self.addrule("PKG_EXIST=pkg1")
self.addrule("CACHE_EXISTS=pkg1|1.0-1")

View File

@@ -1,17 +0,0 @@
self.description = "--upgrade with DownloadUser set"
self.require_capability("curl")
self.option['DownloadUser'] = ['root']
p1 = pmpkg('pkg1', '1.0-1')
self.addpkg(p1)
url = self.add_simple_http_server({
'/{}'.format(p1.filename()): p1.makepkg_bytes(),
})
self.args = '-U {url}/{}'.format(p1.filename(), url=url)
self.addrule("PACMAN_RETCODE=0")
self.addrule("PKG_EXIST=pkg1")
self.addrule("CACHE_EXISTS=pkg1|1.0-1")

View File

@@ -10,7 +10,7 @@ url = self.add_simple_http_server({
'body': 'simple.sig',
},
# content-disposition filename is now ignored
# content-disposition filename
'/cd.pkg': {
'headers': { 'Content-Disposition': 'attachment; filename="cd-alt.pkg"' },
'body': 'cd'
@@ -64,26 +64,19 @@ self.addrule('!PACMAN_RETCODE=0')
self.addrule('CACHE_FCONTENTS=simple.pkg|simple')
self.addrule('CACHE_FCONTENTS=simple.pkg.sig|simple.sig')
self.addrule('!CACHE_FEXISTS=cd-alt.pkg')
self.addrule('!CACHE_FEXISTS=cd-alt.pkg.sig')
self.addrule('CACHE_FCONTENTS=cd.pkg|cd')
self.addrule('CACHE_FCONTENTS=cd.pkg.sig|cd.sig')
self.addrule('!CACHE_FEXISTS=cd.pkg')
self.addrule('!CACHE_FEXISTS=cd.pkg.sig')
self.addrule('CACHE_FCONTENTS=cd-alt.pkg|cd')
self.addrule('CACHE_FCONTENTS=cd-alt.pkg.sig|cd.sig')
self.addrule('!CACHE_FEXISTS=redir-dest.pkg')
self.addrule('CACHE_FCONTENTS=redir.pkg|redir-dest')
self.addrule('CACHE_FCONTENTS=redir.pkg.sig|redir-dest.sig')
self.addrule('!CACHE_FEXISTS=redir.pkg')
self.addrule('CACHE_FCONTENTS=redir-dest.pkg|redir-dest')
self.addrule('CACHE_FCONTENTS=redir-dest.pkg.sig|redir-dest.sig')
self.addrule('CACHE_FCONTENTS=redir-cdn.pkg|redir-dest')
self.addrule('CACHE_FCONTENTS=redir-cdn.pkg.sig|redir-dest.sig')
self.addrule('!CACHE_FEXISTS=cd-redir.pkg')
self.addrule('!CACHE_FEXISTS=cd-redir-dest.pkg')
self.addrule('CACHE_FCONTENTS=cd-redir-dest-alt.pkg|cd-redir-dest')
self.addrule('CACHE_FCONTENTS=cd-redir-dest-alt.pkg.sig|cd-redir-dest.sig')
self.addrule('!CACHE_FEXISTS=cd-redir-dest-alt.pkg')
self.addrule('!CACHE_FEXISTS=cd-redir-dest-alt.pkg')
self.addrule('CACHE_FCONTENTS=cd-redir.pkg|cd-redir-dest')
self.addrule('CACHE_FCONTENTS=cd-redir.pkg.sig|cd-redir-dest.sig')
self.addrule('!CACHE_FEXISTS=cdn-3')
self.addrule('!CACHE_FEXISTS=cdn-4')
self.addrule('!CACHE_FEXISTS=cdn-alt.pkg')
self.addrule('!CACHE_FEXISTS=cdn-alt.pkg.sig')
self.addrule('CACHE_FCONTENTS=cd-redir-cdn.pkg|cdn-alt')
self.addrule('CACHE_FCONTENTS=cd-redir-cdn.pkg.sig|cdn-alt.sig')
self.addrule('CACHE_FCONTENTS=cdn-alt.pkg|cdn-alt')
self.addrule('CACHE_FCONTENTS=cdn-alt.pkg.sig|cdn-alt.sig')

View File

@@ -0,0 +1,63 @@
self.description = 'download remote packages with -U without a URL filename'
self.require_capability("gpg")
self.require_capability("curl")
url = self.add_simple_http_server({
# simple
'/simple.pkg/': 'simple',
'/simple.pkg/.sig': 'simple.sig',
# content-disposition filename
'/cd.pkg/': {
'headers': { 'Content-Disposition': 'attachment; filename="cd-alt.pkg"' },
'body': 'cd'
},
'/cd.pkg/.sig': {
'headers': { 'Content-Disposition': 'attachment; filename="cd-alt-bad.pkg.sig"' },
'body': 'cd.sig'
},
# redirect
'/redir.pkg/': { 'code': 303, 'headers': { 'Location': '/redir-dest.pkg' } },
'/redir-dest.pkg': 'redir-dest',
'/redir-dest.pkg.sig': 'redir-dest.sig',
# content-disposition and redirect
'/cd-redir.pkg/': { 'code': 303, 'headers': { 'Location': '/cd-redir-dest.pkg' } },
'/cd-redir-dest.pkg': {
'headers': { 'Content-Disposition': 'attachment; filename="cd-redir-dest-alt.pkg"' },
'body': 'cd-redir-dest'
},
'/cd-redir-dest.pkg.sig': 'cd-redir-dest.sig',
# TODO: absolutely terrible hack to prevent pacman from attempting to
# validate packages, which causes failure under --valgrind thanks to
# a memory leak in gpgme that is too general for inclusion in valgrind.supp
'/404': { 'code': 404 },
'': 'fallback',
})
self.args = '-Uw {url}/simple.pkg/ {url}/cd.pkg/ {url}/redir.pkg/ {url}/cd-redir.pkg/ {url}/404'.format(url=url)
# packages/sigs are not valid, error is expected
self.addrule('!PACMAN_RETCODE=0')
# TODO: use a predictable file name
#self.addrule('CACHE_FCONTENTS=simple.pkg|simple')
#self.addrule('CACHE_FCONTENTS=simple.pkg.sig|simple.sig')
self.addrule('!CACHE_FEXISTS=cd.pkg')
self.addrule('CACHE_FCONTENTS=cd-alt.pkg|cd')
self.addrule('CACHE_FCONTENTS=cd-alt.pkg.sig|cd.sig')
self.addrule('!CACHE_FEXISTS=redir.pkg')
self.addrule('CACHE_FCONTENTS=redir-dest.pkg|redir-dest')
self.addrule('CACHE_FCONTENTS=redir-dest.pkg.sig|redir-dest.sig')
self.addrule('!CACHE_FEXISTS=cd-redir.pkg')
self.addrule('!CACHE_FEXISTS=cd-redir-dest.pkg')
self.addrule('CACHE_FCONTENTS=cd-redir-dest-alt.pkg|cd-redir-dest')
self.addrule('CACHE_FCONTENTS=cd-redir-dest-alt.pkg.sig|cd-redir-dest.sig')
self.addrule('!CACHE_FEXISTS=.sig')

View File

@@ -20,3 +20,7 @@ self.addrule("PKG_EXIST=pkg1")
self.addrule("PKG_EXIST=pkg2")
self.addrule("CACHE_EXISTS=pkg1|1.0-1")
self.addrule("CACHE_EXISTS=pkg2|2.0-2")
# --upgrade fails hard with XferCommand because the fetch callback has no way
# to return the file path to alpm
self.expectfailure = True