From 307741092df8c85c32a95d4c162bd73d28b28c4a Mon Sep 17 00:00:00 2001 From: Keve Date: Wed, 13 Nov 2024 11:01:25 +0100 Subject: [PATCH] Fix host component handling in file:// URLs pkg handles file:// URLs in libpkg/fetch_file.c which translates the file URL into an access to the local filesystem. Ignoring the host component altogether in this process is semantically wrong. The host component, if given, directs the file to be fetched from that host, not from the local filesystem. Extend the handling of the host component to accept the localhost host component - the null host component file:/// is anyway accepted already, but reject any other host component, as the code is not intended to go around looking for files on other hosts. --- libpkg/fetch_file.c | 21 +++++++++++++++----- tests/frontend/update.sh | 42 +++++++++++++++++++++++++++++++++++++--- 2 files changed, 55 insertions(+), 8 deletions(-) diff --git a/libpkg/fetch_file.c b/libpkg/fetch_file.c index 9bcb886f5..e9b20fb9c 100644 --- a/libpkg/fetch_file.c +++ b/libpkg/fetch_file.c @@ -54,14 +54,25 @@ file_open(struct pkg_repo *repo, struct fetch_item *fi) return (EPKG_FATAL); } u+=2; - /* if we don't have a '/' it means we have a host we should ignore */ + /* if we don't have a '/' it means we have a host FQDN component, otherwise just proceed */ + /* we can fetch local files only, so we accept the localhost FQDN */ + /* TODO: consider accepting gethostname/getdomainname and combinations of these. */ + /* TODO: delegate to curl to fetch any URL, btw. curl bails on this as well. */ if (*u != '/') { - u = strchr(u+1, '/'); - if (u == NULL) { - pkg_emit_error("Invalid url: %s'\n', " - "file:// expected", fi->url); + char fqdn[256]=""; + char *path = strchr(u+1, '/'); + if (path == NULL) { + pkg_emit_error("Invalid url: '%s',\n" + "file:/// or file://localhost/ expected.", fi->url); return (EPKG_FATAL); } + strncat(fqdn, u, MIN(255, path-u)); + if (0 != strncmp("localhost", fqdn, sizeof(fqdn))) { + pkg_emit_error("Invalid url: '%s'\n" + "file:/// or file://localhost/ expected.", fi->url); + return (EPKG_FATAL); + } + u = path; } if (stat(u, &st) == -1) { if (!repo->silent) diff --git a/tests/frontend/update.sh b/tests/frontend/update.sh index 8f0cfcb80..df542d8b5 100644 --- a/tests/frontend/update.sh +++ b/tests/frontend/update.sh @@ -18,7 +18,7 @@ EOF atf_check \ -o match:"Unable to update repository test" \ - -e match:"pkg: file://empty//packagesite.pkg: No such file or directory" \ + -e match:"Invalid url: 'file://empty//meta.conf'" \ -s exit:1 \ pkg -R repos update } @@ -28,6 +28,10 @@ file_url_body() { touch meta.conf here=$(pwd) + +# +# test file:/empty/, which is invalid +# cat > repos/test.conf << EOF test: { url: "file:/empty/", @@ -40,6 +44,9 @@ EOF -s exit:1 \ pkg -R repos update +# +# test file://here, which is invalid +# cat > repos/test.conf << EOF test: { url: "file://here", @@ -47,11 +54,14 @@ test: { EOF atf_check \ -o match:"Unable to update repository test" \ - -e match:"meta.*No such file or directory" \ + -e match:"Invalid url: 'file://here/meta.conf'" \ -s exit:1 \ pkg -R repos update +# +# test file://here//path, which is invalid +# cat > repos/test.conf << EOF test: { url: "file://here/${here}", @@ -63,6 +73,9 @@ EOF -s exit:1 \ pkg -R repos update +# +# test file:////path, which is valid +# cat > repos/test.conf << EOF test: { url: "file:///${here}", @@ -75,6 +88,9 @@ EOF -s exit:1 \ pkg -R repos update +# +# test file:///path, which is valid +# cat > repos/test.conf << EOF test: { url: "file://${here}", @@ -87,6 +103,9 @@ EOF -s exit:1 \ pkg -R repos update +# +# test file://path, which is invalid +# cat > repos/test.conf << EOF test: { url: "file:/${here}", @@ -95,7 +114,24 @@ EOF atf_check \ -o match:"Unable to update repository test" \ - -e match:"meta.*No such file or directory" \ + -e match:"Invalid url: 'file:/${here}/meta.conf'" \ + -s exit:1 \ + pkg -R repos update + + +# +# test file://localhost/path, which is a valid +# + cat > repos/test.conf << EOF +test: { + url: "file://localhost${here}", +} +EOF + + atf_check \ + -o match:"Unable to update repository test" \ + -e not-match:"meta.*No such file or directory" \ -s exit:1 \ pkg -R repos update + }