mirror of https://github.com/omar-polo/gmid.git
Compare commits
93 Commits
Author | SHA1 | Date |
---|---|---|
Omar Polo | c616a6d6f4 | |
Omar Polo | 96eaf145cb | |
Omar Polo | 44e5992664 | |
Omar Polo | cb384f4280 | |
Omar Polo | a33eaaa925 | |
Omar Polo | a4f18acde3 | |
Omar Polo | 79f0d2d9a4 | |
Omar Polo | 036d43dd73 | |
Omar Polo | 5810af408c | |
Omar Polo | 7f6c46ae1e | |
Omar Polo | 3d06af043c | |
Omar Polo | 1001cc1a1f | |
Omar Polo | f2c45fdab0 | |
Omar Polo | d4955d2891 | |
Omar Polo | 22ce7eb455 | |
Omar Polo | 0965162959 | |
Omar Polo | 4a2e39c23b | |
Omar Polo | 36bdda94c1 | |
Omar Polo | 9325f61db0 | |
Omar Polo | cf62693495 | |
Omar Polo | 62aa1935cc | |
Omar Polo | 60c2f58b75 | |
Omar Polo | bc1190c5d4 | |
Omar Polo | 702b5101d3 | |
Omar Polo | 345a12c766 | |
Omar Polo | 68d36b207f | |
Omar Polo | 910fbe8f00 | |
Omar Polo | 911fd6b6c6 | |
Omar Polo | 5f31f2410e | |
Omar Polo | 401030113e | |
Omar Polo | fcf3f1fa9a | |
Omar Polo | 3b2ee15a6b | |
Omar Polo | 235f5e70ee | |
Omar Polo | 471cae7e8f | |
Omar Polo | 15acd9c6ec | |
Omar Polo | a4ffa32f0e | |
Omar Polo | 4864061c16 | |
Omar Polo | 9089c18ac9 | |
Omar Polo | a1562e847f | |
Omar Polo | 69cfd0a304 | |
Omar Polo | 848189f10a | |
Omar Polo | 1bc73c3bcb | |
Omar Polo | 6174e65dbe | |
Omar Polo | c38417e32d | |
Omar Polo | e030968718 | |
Omar Polo | 5e71e44d26 | |
Omar Polo | 4d207d1050 | |
Omar Polo | b6eb184a95 | |
Omar Polo | d08e2664fc | |
Omar Polo | 0a4a979ccb | |
Omar Polo | da834b5803 | |
Omar Polo | c9ea70a36f | |
Omar Polo | 7c723cf05f | |
Omar Polo | b5dd7091ad | |
Omar Polo | 5b549c2805 | |
Omar Polo | b00f71ba97 | |
Omar Polo | 6ff8de1f8a | |
Omar Polo | 9f675805d0 | |
Omar Polo | a91b0892bf | |
Omar Polo | 610a4666cd | |
Omar Polo | 2f4926259f | |
Omar Polo | cd12ad1132 | |
Omar Polo | b2782022c9 | |
Omar Polo | 1ef0cd0cdb | |
Omar Polo | 42e2af25ae | |
Omar Polo | 89dca7ab54 | |
Omar Polo | 359c56ce35 | |
Omar Polo | c2dcb5fa6e | |
Omar Polo | 5d12e6a104 | |
Omar Polo | 0d8eb9b60c | |
Omar Polo | 5864f3ce3c | |
Omar Polo | 9536c8ca63 | |
Omar Polo | 40b71b6861 | |
Omar Polo | 42235e3fc2 | |
Omar Polo | f53f5e5fe1 | |
Omar Polo | 40ea7b163e | |
Omar Polo | be265175c6 | |
Omar Polo | 8aba5d8b21 | |
Omar Polo | 7c83689428 | |
Omar Polo | 248fb833f9 | |
Omar Polo | 0ed763b03d | |
Omar Polo | 9f1cce3d0e | |
Omar Polo | 8f543d941e | |
Omar Polo | acf244c516 | |
Anna “CyberTailor” | 53ad458e22 | |
Omar Polo | bb5a25d287 | |
Omar Polo | f862d389ff | |
Omar Polo | 574f71f7a3 | |
Omar Polo | ebe2e54900 | |
Omar Polo | ddb089c157 | |
Omar Polo | 3524375abe | |
Omar Polo | fe37d79200 | |
Omar Polo | 33a5425235 |
24
.cirrus.yml
24
.cirrus.yml
|
@ -1,6 +1,9 @@
|
||||||
# gcc' -Werror=use-after-free gets tripped by vis.c: it sees a use
|
# gcc' -Werror=use-after-free gets tripped by vis.c: it sees a use
|
||||||
# after free where it's not possible and breaks the CI.
|
# after free where it's not possible and breaks the CI.
|
||||||
|
|
||||||
|
# seems that inside the CI it's not currently possible to bind to ::1
|
||||||
|
# so set HAVE_IPV6=no.
|
||||||
|
|
||||||
linux_amd64_task:
|
linux_amd64_task:
|
||||||
container:
|
container:
|
||||||
image: alpine:latest
|
image: alpine:latest
|
||||||
|
@ -8,7 +11,7 @@ linux_amd64_task:
|
||||||
- apk add alpine-sdk linux-headers bison libretls-dev libevent-dev
|
- apk add alpine-sdk linux-headers bison libretls-dev libevent-dev
|
||||||
- ./configure CFLAGS='-O2 -pipe -Wno-deprecated-declarations -Wno-use-after-free' -Werror
|
- ./configure CFLAGS='-O2 -pipe -Wno-deprecated-declarations -Wno-use-after-free' -Werror
|
||||||
- make
|
- make
|
||||||
- make regress REGRESS_HOST="*"
|
- make regress REGRESS_HOST="*" HAVE_IPV6=no
|
||||||
|
|
||||||
linux_arm_task:
|
linux_arm_task:
|
||||||
arm_container:
|
arm_container:
|
||||||
|
@ -17,20 +20,25 @@ linux_arm_task:
|
||||||
- apk add alpine-sdk linux-headers bison libretls-dev libevent-dev
|
- apk add alpine-sdk linux-headers bison libretls-dev libevent-dev
|
||||||
- ./configure CFLAGS='-O2 -pipe -Wno-deprecated-declarations -Wno-use-after-free' -Werror
|
- ./configure CFLAGS='-O2 -pipe -Wno-deprecated-declarations -Wno-use-after-free' -Werror
|
||||||
- make
|
- make
|
||||||
- make regress REGRESS_HOST="*"
|
- make regress REGRESS_HOST="*" HAVE_IPV6=no
|
||||||
|
|
||||||
freebsd_13_task:
|
freebsd_14_task:
|
||||||
freebsd_instance:
|
freebsd_instance:
|
||||||
image_family: freebsd-13-0
|
image_family: freebsd-14-0
|
||||||
test_script:
|
install_script: pkg install -y libevent libressl pkgconf
|
||||||
- pkg install -y libevent libressl pkgconf
|
script:
|
||||||
- ./configure CFLAGS='-O2 -pipe -Wno-deprecated-declarations' -Werror
|
- ./configure CFLAGS='-O2 -pipe -Wno-deprecated-declarations' -Werror
|
||||||
- make
|
- make
|
||||||
- make regress
|
- make regress HAVE_IPV6=no
|
||||||
|
|
||||||
|
#
|
||||||
|
# There are some issues with imsg fd passing on macos at the moment that
|
||||||
|
# seem to be triggered only in applications that do a heavy use of them,
|
||||||
|
# like gmid or opensmtpd. Still, keep macos to ensure gmid builds here.
|
||||||
|
#
|
||||||
mac_task:
|
mac_task:
|
||||||
macos_instance:
|
macos_instance:
|
||||||
image: ghcr.io/cirruslabs/macos-ventura-xcode:latest
|
image: ghcr.io/cirruslabs/macos-sonoma-xcode:latest
|
||||||
test_script:
|
test_script:
|
||||||
- brew install libevent openssl libretls
|
- brew install libevent openssl libretls
|
||||||
- PKG_CONFIG_PATH="$(brew --prefix openssl)/lib/pkgconfig" ./configure CFLAGS='-O2 -pipe -Wno-deprecated-declarations' -Werror
|
- PKG_CONFIG_PATH="$(brew --prefix openssl)/lib/pkgconfig" ./configure CFLAGS='-O2 -pipe -Wno-deprecated-declarations' -Werror
|
||||||
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
name: release docker image
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
tags:
|
||||||
|
env:
|
||||||
|
IMAGE_NAME: "gmid"
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
permissions: write-all
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v1
|
||||||
|
|
||||||
|
- name: build the image
|
||||||
|
run: docker build -f contrib/Dockerfile -t gmid:alpine .
|
||||||
|
|
||||||
|
- name: login to ghcr.io
|
||||||
|
uses: docker/login-action@v2
|
||||||
|
with:
|
||||||
|
registry: ghcr.io
|
||||||
|
username: ${{ github.actor }}
|
||||||
|
password: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
|
- name: push the image
|
||||||
|
run: |
|
||||||
|
IMAGE_ID=ghcr.io/${{ github.repository_owner }}/$IMAGE_NAME
|
||||||
|
IMAGE_ID=$(echo $IMAGE_ID | tr A-Z a-z)
|
||||||
|
# strip git ref prefix from version
|
||||||
|
VERSION=$(echo "${{ github.ref }}" | sed -e 's,.*/\(.*\),\1,')
|
||||||
|
echo IMAGE_ID=$IMAGE_ID
|
||||||
|
echo VERSION=$VERSION
|
||||||
|
docker tag gmid:alpine $IMAGE_ID:$VERSION
|
||||||
|
docker push $IMAGE_ID:$VERSION
|
77
ChangeLog
77
ChangeLog
|
@ -1,3 +1,80 @@
|
||||||
|
2024-06-11 Omar Polo <op@omarpolo.com>
|
||||||
|
|
||||||
|
* configure (VERSION): release 2.0.5
|
||||||
|
|
||||||
|
2024-06-10 Omar Polo <op@omarpolo.com>
|
||||||
|
|
||||||
|
* don't error on a '..' component at the start of the path
|
||||||
|
* reject NUL bytes embedded in the request
|
||||||
|
|
||||||
|
2024-06-09 Omar Polo <op@omarpolo.com>
|
||||||
|
|
||||||
|
* check for truncation various strlcpy calls.
|
||||||
|
* clean up of a few unused prototypes and externs.
|
||||||
|
|
||||||
|
2024-06-08 Omar Polo <op@omarpolo.com>
|
||||||
|
|
||||||
|
* configure: change how strnvis(3) is handled: on systems
|
||||||
|
with the broken interface gmid will just use its built-in
|
||||||
|
version.
|
||||||
|
|
||||||
|
2024-06-06 Omar Polo <op@omarpolo.com>
|
||||||
|
|
||||||
|
* parse.y: allow again empty lines at the start of the config
|
||||||
|
* configure (VERSION): release 2.0.4
|
||||||
|
* portability fix for system with a wrong strnvis(3)
|
||||||
|
|
||||||
|
2024-06-05 Omar Polo <op@omarpolo.com>
|
||||||
|
|
||||||
|
* parse.y: add a nicer error message if the removed `cgi' option
|
||||||
|
is still used.
|
||||||
|
|
||||||
|
2024-06-04 Omar Polo <op@omarpolo.com>
|
||||||
|
|
||||||
|
* configure (VERSION): release 2.0.3
|
||||||
|
|
||||||
|
2024-06-03 Omar Polo <op@omarpolo.com>
|
||||||
|
|
||||||
|
* server.c (vhost_fastcgi): fix `fastcgi off' handling.
|
||||||
|
Reported by Alex // nytpu
|
||||||
|
|
||||||
|
2024-05-29 Omar Polo <op@omarpolo.com>
|
||||||
|
|
||||||
|
* server.c (handle_handshake): relax the SNI requirement. There are
|
||||||
|
legitimate use-cases where SNI can't be used, like connecting to a
|
||||||
|
raw IPv6 address.
|
||||||
|
* gg.c (main): add -q to avoid printing "Server Says:"
|
||||||
|
* gg.c (main): unbreak -n
|
||||||
|
* iri.c (parse_authority): add support for raw IPv6 addresses
|
||||||
|
|
||||||
|
2024-04-04 Omar Polo <op@omarpolo.com>
|
||||||
|
|
||||||
|
* configure (VERSION): release 2.0.2
|
||||||
|
|
||||||
|
2024-04-03 Omar Polo <op@omarpolo.com>
|
||||||
|
|
||||||
|
* configure: improve function checking in the configure
|
||||||
|
* have/landlock.c: fix landlock test
|
||||||
|
* gmid.c (main_print_conf): fix config dumping with -nn
|
||||||
|
|
||||||
|
2024-03-03 Omar Polo <op@omarpolo.com>
|
||||||
|
|
||||||
|
* gmid.c: fix `log access path' with a chroot
|
||||||
|
|
||||||
|
2024-01-30 Anna “CyberTailor”
|
||||||
|
|
||||||
|
* contrib/vim/indent/gmid.vim: fix indent
|
||||||
|
|
||||||
|
2024-01-30 Omar Polo <op@omarpolo.com>
|
||||||
|
|
||||||
|
* parse.y: don't make log styles reserved keywords. Unbreaks the
|
||||||
|
example in the manpage with `common = ...'.
|
||||||
|
|
||||||
|
2024-01-26 Omar Polo <op@omarpolo.com>
|
||||||
|
|
||||||
|
* parse.y: rework grammar to allow the semicolon after
|
||||||
|
variables/macros definition and top-level options
|
||||||
|
|
||||||
2024-01-24 Omar Polo <op@omarpolo.com>
|
2024-01-24 Omar Polo <op@omarpolo.com>
|
||||||
|
|
||||||
* configure (VERSION): release 2.0.1
|
* configure (VERSION): release 2.0.1
|
||||||
|
|
8
Makefile
8
Makefile
|
@ -131,7 +131,7 @@ y.tab.c: parse.y
|
||||||
lint:
|
lint:
|
||||||
man -Tlint -Wstyle -l gmid.8 gmid.conf.5 gemexp.1 gg.1 titan.1
|
man -Tlint -Wstyle -l gmid.8 gmid.conf.5 gemexp.1 gg.1 titan.1
|
||||||
|
|
||||||
PUBKEY = keys/gmid-${VERSION}.pub
|
PUBKEY = keys/gmid-2.0.pub
|
||||||
PRIVKEY = set-PRIVKEY
|
PRIVKEY = set-PRIVKEY
|
||||||
DISTFILES = .cirrus.yml .dockerignore .gitignore ChangeLog LICENSE \
|
DISTFILES = .cirrus.yml .dockerignore .gitignore ChangeLog LICENSE \
|
||||||
Makefile README.md config.c configure crypto.c dirs.c fcgi.c \
|
Makefile README.md config.c configure crypto.c dirs.c fcgi.c \
|
||||||
|
@ -158,10 +158,10 @@ ${DISTNAME}.tar.gz: ${DISTFILES}
|
||||||
mkdir -p .dist/${DISTNAME}/
|
mkdir -p .dist/${DISTNAME}/
|
||||||
${INSTALL} -m 0644 ${DISTFILES} .dist/${DISTNAME}/
|
${INSTALL} -m 0644 ${DISTFILES} .dist/${DISTNAME}/
|
||||||
cd .dist/${DISTNAME} && chmod 755 configure
|
cd .dist/${DISTNAME} && chmod 755 configure
|
||||||
${MAKE} -C compat DESTDIR=${PWD}/.dist/${DISTNAME}/compat dist
|
${MAKE} -C compat DESTDIR=${PWD}/.dist/${DISTNAME}/compat dist
|
||||||
${MAKE} -C contrib DESTDIR=${PWD}/.dist/${DISTNAME}/contrib dist
|
${MAKE} -C contrib DESTDIR=${PWD}/.dist/${DISTNAME}/contrib dist
|
||||||
${MAKE} -C have DESTDIR=${PWD}/.dist/${DISTNAME}/have dist
|
${MAKE} -C have DESTDIR=${PWD}/.dist/${DISTNAME}/have dist
|
||||||
${MAKE} -C keys DESTDIR=${PWD}/.dist/${DISTNAME}/keys dist
|
${MAKE} -C keys DESTDIR=${PWD}/.dist/${DISTNAME}/keys dist
|
||||||
${MAKE} -C regress DESTDIR=${PWD}/.dist/${DISTNAME}/regress dist
|
${MAKE} -C regress DESTDIR=${PWD}/.dist/${DISTNAME}/regress dist
|
||||||
cd .dist/ && tar zcf ../$@ ${DISTNAME}
|
cd .dist/ && tar zcf ../$@ ${DISTNAME}
|
||||||
rm -rf .dist/
|
rm -rf .dist/
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
#include <openssl/ecdsa.h>
|
#include <openssl/ecdsa.h>
|
||||||
#include <openssl/err.h>
|
#include <openssl/err.h>
|
||||||
|
|
2
config.c
2
config.c
|
@ -183,7 +183,7 @@ config_send_file(struct privsep *ps, enum privsep_procid id, int type,
|
||||||
|
|
||||||
/* avoid fd rampage */
|
/* avoid fd rampage */
|
||||||
if (proc_flush_imsg(ps, id, -1) == -1) {
|
if (proc_flush_imsg(ps, id, -1) == -1) {
|
||||||
log_warn("%s: proc_fush_imsg", __func__);
|
log_warn("%s: proc_flush_imsg", __func__);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
RELEASE=no
|
RELEASE=no
|
||||||
VERSION=2.0.1
|
VERSION=2.0.5-current
|
||||||
|
|
||||||
usage()
|
usage()
|
||||||
{
|
{
|
||||||
|
@ -59,6 +59,10 @@ CDIAGFLAGS="${CDIAGFLAGS} -Wsign-compare -Wno-unused-parameter" # -Wshadow
|
||||||
CDIAGFLAGS="${CDIAGFLAGS} -Wno-missing-field-initializers"
|
CDIAGFLAGS="${CDIAGFLAGS} -Wno-missing-field-initializers"
|
||||||
CDIAGFLAGS="${CDIAGFLAGS} -Wno-pointer-sign"
|
CDIAGFLAGS="${CDIAGFLAGS} -Wno-pointer-sign"
|
||||||
|
|
||||||
|
# On all OSes except OpenBSD use the bundled one. It may crash at
|
||||||
|
# runtime otherwise since we depend on the libtls internals for the
|
||||||
|
# privsep crypto engine.
|
||||||
|
# See <https://codeberg.org/op/gmid/issues/2>.
|
||||||
LIBTLS=bundled # or system
|
LIBTLS=bundled # or system
|
||||||
if [ "$(uname || true)" = OpenBSD ]; then
|
if [ "$(uname || true)" = OpenBSD ]; then
|
||||||
LIBTLS=system
|
LIBTLS=system
|
||||||
|
@ -139,10 +143,9 @@ echo "file config.log: writing..."
|
||||||
|
|
||||||
NEED_GNU_SOURCE=0
|
NEED_GNU_SOURCE=0
|
||||||
NEED_OPENBSD_SOURCE=0
|
NEED_OPENBSD_SOURCE=0
|
||||||
NEED_LIBBSD_OPENBSD_VIS=0
|
|
||||||
|
|
||||||
COMPATS=
|
COMPATS=
|
||||||
COMP="${CC} ${CFLAGS} -Wno-unused -Werror"
|
COMP="${CC} ${CFLAGS} -Werror=implicit-function-declaration"
|
||||||
|
|
||||||
# singletest name var extra-cflags extra-libs msg
|
# singletest name var extra-cflags extra-libs msg
|
||||||
singletest() {
|
singletest() {
|
||||||
|
@ -212,10 +215,6 @@ runtest() {
|
||||||
NEED_OPENBSD_SOURCE=1
|
NEED_OPENBSD_SOURCE=1
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
if [ "$4" = -DLIBBSD_OPENBSD_VIS ]; then
|
|
||||||
NEED_LIBBSD_OPENBSD_VIS=1
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
if [ -n "$3" ]; then
|
if [ -n "$3" ]; then
|
||||||
CFLAGS="$CFLAGS $3"
|
CFLAGS="$CFLAGS $3"
|
||||||
fi
|
fi
|
||||||
|
@ -311,7 +310,14 @@ runtest strtonum STRTONUM -D_OPENBSD_SOURCE || true
|
||||||
runtest timingsafe_memcmp TIMINGSAFE_MEMCMP || true
|
runtest timingsafe_memcmp TIMINGSAFE_MEMCMP || true
|
||||||
runtest tree_h TREE_H || true
|
runtest tree_h TREE_H || true
|
||||||
runtest vasprintf VASPRINTF -D_GNU_SOURCE || true
|
runtest vasprintf VASPRINTF -D_GNU_SOURCE || true
|
||||||
runtest vis VIS -DLIBBSD_OPENBSD_VIS || true
|
|
||||||
|
# strnvis is a bit special since NetBSD, FreeBSD and MacOS have
|
||||||
|
# the broken version with the wrong semantics and arguments.
|
||||||
|
# Hence the -Wall -Werror check.
|
||||||
|
if ! singletest strnvis STRNVIS "-Wall -Werror"; then
|
||||||
|
CFLAGS="-I ${PWD}/compat/vis ${CFLAGS} ${CFLAGS}"
|
||||||
|
COMPATS="compat/vis.c ${COMPATS}"
|
||||||
|
fi
|
||||||
|
|
||||||
if [ ${HAVE_ARC4RANDOM} -eq 1 -a ${HAVE_ARC4RANDOM_BUF} -eq 0 ]; then
|
if [ ${HAVE_ARC4RANDOM} -eq 1 -a ${HAVE_ARC4RANDOM_BUF} -eq 0 ]; then
|
||||||
COMPATS="compat/arc4random.c ${COMPATS}"
|
COMPATS="compat/arc4random.c ${COMPATS}"
|
||||||
|
@ -384,10 +390,6 @@ if [ ${HAVE_QUEUE_H} -eq 0 -o ${HAVE_IMSG} -eq 0 -o ${HAVE_TREE_H} -eq 0 ]; then
|
||||||
CFLAGS="${CFLAGS} -I ${PWD}/compat"
|
CFLAGS="${CFLAGS} -I ${PWD}/compat"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ ${HAVE_VIS} -eq 0 ]; then
|
|
||||||
CFLAGS="${CFLAGS} -I ${PWD}/compat/vis"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ $HAVE_LIBEVENT2 -eq 1 ]; then
|
if [ $HAVE_LIBEVENT2 -eq 1 ]; then
|
||||||
CFLAGS="$CFLAGS -DHAVE_LIBEVENT2=1"
|
CFLAGS="$CFLAGS -DHAVE_LIBEVENT2=1"
|
||||||
fi
|
fi
|
||||||
|
@ -398,9 +400,6 @@ fi
|
||||||
if [ $NEED_OPENBSD_SOURCE = 1 ]; then
|
if [ $NEED_OPENBSD_SOURCE = 1 ]; then
|
||||||
CFLAGS="$CFLAGS -D_OPENBSD_SOURCE"
|
CFLAGS="$CFLAGS -D_OPENBSD_SOURCE"
|
||||||
fi
|
fi
|
||||||
if [ $NEED_LIBBSD_OPENBSD_VIS = 1 ]; then
|
|
||||||
CFLAGS="$CFLAGS -DLIBBSD_OPENBSD_VIS"
|
|
||||||
fi
|
|
||||||
|
|
||||||
CFLAGS="-I. ${CFLAGS} ${CDIAGFLAGS}"
|
CFLAGS="-I. ${CFLAGS} ${CDIAGFLAGS}"
|
||||||
|
|
||||||
|
|
|
@ -6,8 +6,6 @@ Wants=network-online.target
|
||||||
|
|
||||||
[Service]
|
[Service]
|
||||||
Type=simple
|
Type=simple
|
||||||
User=gmid
|
|
||||||
Group=nobody
|
|
||||||
ExecStart=/usr/local/bin/gmid -f -c /etc/gmid.conf
|
ExecStart=/usr/local/bin/gmid -f -c /etc/gmid.conf
|
||||||
ExecStop=/bin/kill -TERM $MAINPID
|
ExecStop=/bin/kill -TERM $MAINPID
|
||||||
ExecReload=/bin/kill -HUP $MAINPID
|
ExecReload=/bin/kill -HUP $MAINPID
|
||||||
|
|
|
@ -9,3 +9,5 @@ setlocal indentexpr=
|
||||||
setlocal cindent
|
setlocal cindent
|
||||||
" Just make sure that the comments are not reset as defs would be.
|
" Just make sure that the comments are not reset as defs would be.
|
||||||
setlocal cinkeys-=0#
|
setlocal cinkeys-=0#
|
||||||
|
" And indentation works correctly without semicolons.
|
||||||
|
setlocal cinoptions=+0
|
||||||
|
|
11
ge.c
11
ge.c
|
@ -91,7 +91,7 @@ log_request(struct client *c, int code, const char *meta)
|
||||||
*c->domain == '\0' ? c->iri.host : c->domain, b, code, meta);
|
*c->domain == '\0' ? c->iri.host : c->domain, b, code, meta);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
static void
|
||||||
load_local_cert(struct vhost *h, const char *hostname, const char *dir)
|
load_local_cert(struct vhost *h, const char *hostname, const char *dir)
|
||||||
{
|
{
|
||||||
char *cert, *key;
|
char *cert, *key;
|
||||||
|
@ -112,7 +112,9 @@ load_local_cert(struct vhost *h, const char *hostname, const char *dir)
|
||||||
if (h->key == NULL)
|
if (h->key == NULL)
|
||||||
fatal("can't load %s", key);
|
fatal("can't load %s", key);
|
||||||
|
|
||||||
strlcpy(h->domain, hostname, sizeof(h->domain));
|
if (strlcpy(h->domain, hostname, sizeof(h->domain))
|
||||||
|
>= sizeof(h->domain))
|
||||||
|
fatalx("hostname too long: %s", hostname);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* wrapper around dirname(3). dn must be PATH_MAX+1 at least. */
|
/* wrapper around dirname(3). dn must be PATH_MAX+1 at least. */
|
||||||
|
@ -122,7 +124,8 @@ pdirname(const char *path, char *dn)
|
||||||
char p[PATH_MAX+1];
|
char p[PATH_MAX+1];
|
||||||
char *t;
|
char *t;
|
||||||
|
|
||||||
strlcpy(p, path, sizeof(p));
|
if (strlcpy(p, path, sizeof(p)) >= sizeof(p))
|
||||||
|
fatalx("%s: path too long: %s", __func__, path);
|
||||||
t = dirname(p);
|
t = dirname(p);
|
||||||
memmove(dn, t, strlen(t)+1);
|
memmove(dn, t, strlen(t)+1);
|
||||||
}
|
}
|
||||||
|
@ -141,7 +144,7 @@ mkdirs(const char *path, mode_t mode)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* $XDG_DATA_HOME/gemexp */
|
/* $XDG_DATA_HOME/gemexp */
|
||||||
char *
|
static char *
|
||||||
data_dir(void)
|
data_dir(void)
|
||||||
{
|
{
|
||||||
const char *home, *xdg;
|
const char *home, *xdg;
|
||||||
|
|
8
gg.1
8
gg.1
|
@ -1,4 +1,4 @@
|
||||||
.\" Copyright (c) 2021, 2022 Omar Polo <op@omarpolo.com>
|
.\" Copyright (c) 2021-2024 Omar Polo <op@omarpolo.com>
|
||||||
.\"
|
.\"
|
||||||
.\" Permission to use, copy, modify, and distribute this software for any
|
.\" Permission to use, copy, modify, and distribute this software for any
|
||||||
.\" purpose with or without fee is hereby granted, provided that the above
|
.\" purpose with or without fee is hereby granted, provided that the above
|
||||||
|
@ -11,7 +11,7 @@
|
||||||
.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
.Dd $Mdocdate: October 19 2023$
|
.Dd $Mdocdate: May 29 2024$
|
||||||
.Dt GG 1
|
.Dt GG 1
|
||||||
.Os
|
.Os
|
||||||
.Sh NAME
|
.Sh NAME
|
||||||
|
@ -20,7 +20,7 @@
|
||||||
.Sh SYNOPSIS
|
.Sh SYNOPSIS
|
||||||
.Nm
|
.Nm
|
||||||
.Bk -words
|
.Bk -words
|
||||||
.Op Fl 23Nn
|
.Op Fl 23Nnq
|
||||||
.Op Fl C Ar cert
|
.Op Fl C Ar cert
|
||||||
.Op Fl d Ar mode
|
.Op Fl d Ar mode
|
||||||
.Op Fl H Ar sni
|
.Op Fl H Ar sni
|
||||||
|
@ -82,6 +82,8 @@ and
|
||||||
to do the request instead of the ones extracted by the IRI.
|
to do the request instead of the ones extracted by the IRI.
|
||||||
.Ar port
|
.Ar port
|
||||||
is by default 1965.
|
is by default 1965.
|
||||||
|
.It Fl q
|
||||||
|
Don't print server error messages to standard error.
|
||||||
.It Fl T Ar seconds
|
.It Fl T Ar seconds
|
||||||
Kill
|
Kill
|
||||||
.Nm
|
.Nm
|
||||||
|
|
22
gg.c
22
gg.c
|
@ -41,6 +41,7 @@ int flag3;
|
||||||
int nop;
|
int nop;
|
||||||
int redirects = 5;
|
int redirects = 5;
|
||||||
int timer;
|
int timer;
|
||||||
|
int quiet;
|
||||||
const char *cert;
|
const char *cert;
|
||||||
const char *key;
|
const char *key;
|
||||||
const char *proxy_host;
|
const char *proxy_host;
|
||||||
|
@ -212,14 +213,13 @@ get(const char *r)
|
||||||
char req[GEMINI_URL_LEN];
|
char req[GEMINI_URL_LEN];
|
||||||
uint8_t buf[2048];
|
uint8_t buf[2048];
|
||||||
const char *parse_err, *host, *port;
|
const char *parse_err, *host, *port;
|
||||||
|
int ret;
|
||||||
|
|
||||||
if (strlcpy(iribuf, r, sizeof(iribuf)) >= sizeof(iribuf))
|
if (strlcpy(iribuf, r, sizeof(iribuf)) >= sizeof(iribuf))
|
||||||
errx(1, "iri too long: %s", r);
|
errx(1, "iri too long: %s", r);
|
||||||
|
|
||||||
if (strlcpy(req, r, sizeof(req)) >= sizeof(req))
|
ret = snprintf(req, sizeof(req), "%s\r\n", r);
|
||||||
errx(1, "iri too long: %s", r);
|
if (ret < 0 || (size_t)ret >= sizeof(req))
|
||||||
|
|
||||||
if (strlcat(req, "\r\n", sizeof(req)) >= sizeof(req))
|
|
||||||
errx(1, "iri too long: %s", r);
|
errx(1, "iri too long: %s", r);
|
||||||
|
|
||||||
if (!parse_iri(iribuf, &iri, &parse_err))
|
if (!parse_iri(iribuf, &iri, &parse_err))
|
||||||
|
@ -308,8 +308,11 @@ get(const char *r)
|
||||||
assert(t != NULL);
|
assert(t != NULL);
|
||||||
if (code < 20 || code >= 30) {
|
if (code < 20 || code >= 30) {
|
||||||
*t = '\0';
|
*t = '\0';
|
||||||
fprintf(stderr, "Server says: ");
|
if (!quiet) {
|
||||||
safeprint(stderr, buf + 3); /* skip return code */
|
fprintf(stderr, "Server says: ");
|
||||||
|
/* skip return code */
|
||||||
|
safeprint(stderr, buf + 3);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
t += 2; /* skip \r\n */
|
t += 2; /* skip \r\n */
|
||||||
len -= t - buf;
|
len -= t - buf;
|
||||||
|
@ -335,7 +338,7 @@ static void __attribute__((noreturn))
|
||||||
usage(void)
|
usage(void)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "version: " GG_STRING "\n");
|
fprintf(stderr, "version: " GG_STRING "\n");
|
||||||
fprintf(stderr, "usage: %s [-23Nn] [-C cert] [-d mode] [-H sni] "
|
fprintf(stderr, "usage: %s [-23Nnq] [-C cert] [-d mode] [-H sni] "
|
||||||
"[-K key] [-P host[:port]]\n",
|
"[-K key] [-P host[:port]]\n",
|
||||||
getprogname());
|
getprogname());
|
||||||
fprintf(stderr, " [-T seconds] gemini://...\n");
|
fprintf(stderr, " [-T seconds] gemini://...\n");
|
||||||
|
@ -385,7 +388,7 @@ main(int argc, char **argv)
|
||||||
|
|
||||||
setlocale(LC_CTYPE, "");
|
setlocale(LC_CTYPE, "");
|
||||||
|
|
||||||
while ((ch = getopt(argc, argv, "23C:d:H:K:NP:T:")) != -1) {
|
while ((ch = getopt(argc, argv, "23C:d:H:K:nNP:qT:")) != -1) {
|
||||||
switch (ch) {
|
switch (ch) {
|
||||||
case '2':
|
case '2':
|
||||||
flag2 = 1;
|
flag2 = 1;
|
||||||
|
@ -415,6 +418,9 @@ main(int argc, char **argv)
|
||||||
parse_proxy(optarg);
|
parse_proxy(optarg);
|
||||||
dont_verify_name = 1;
|
dont_verify_name = 1;
|
||||||
break;
|
break;
|
||||||
|
case 'q':
|
||||||
|
quiet = 1;
|
||||||
|
break;
|
||||||
case 'T':
|
case 'T':
|
||||||
timer = strtonum(optarg, 1, 1000, &errstr);
|
timer = strtonum(optarg, 1, 1000, &errstr);
|
||||||
if (errstr != NULL)
|
if (errstr != NULL)
|
||||||
|
|
7
gmid.8
7
gmid.8
|
@ -1,4 +1,4 @@
|
||||||
.\" Copyright (c) 2021, 2022, 2023 Omar Polo <op@omarpolo.com>
|
.\" Copyright (c) 2021, 2022, 2023, 2024 Omar Polo <op@omarpolo.com>
|
||||||
.\"
|
.\"
|
||||||
.\" Permission to use, copy, modify, and distribute this software for any
|
.\" Permission to use, copy, modify, and distribute this software for any
|
||||||
.\" purpose with or without fee is hereby granted, provided that the above
|
.\" purpose with or without fee is hereby granted, provided that the above
|
||||||
|
@ -11,7 +11,7 @@
|
||||||
.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
.Dd October 20, 2023
|
.Dd April 27, 2024
|
||||||
.Dt GMID 8
|
.Dt GMID 8
|
||||||
.Os
|
.Os
|
||||||
.Sh NAME
|
.Sh NAME
|
||||||
|
@ -52,7 +52,8 @@ Overrides the definition of
|
||||||
.Ar macro
|
.Ar macro
|
||||||
in the config file if present.
|
in the config file if present.
|
||||||
.It Fl f
|
.It Fl f
|
||||||
Stays and logs on the foreground.
|
Do not daemonize.
|
||||||
|
Stay and log in the foreground.
|
||||||
.It Fl h , Fl -help
|
.It Fl h , Fl -help
|
||||||
Print the usage and exit.
|
Print the usage and exit.
|
||||||
.It Fl n
|
.It Fl n
|
||||||
|
|
16
gmid.c
16
gmid.c
|
@ -314,10 +314,12 @@ main(int argc, char **argv)
|
||||||
if (*conf->chroot != '\0' && *conf->user == '\0')
|
if (*conf->chroot != '\0' && *conf->user == '\0')
|
||||||
fatalx("can't chroot without a user to switch to.");
|
fatalx("can't chroot without a user to switch to.");
|
||||||
} else {
|
} else {
|
||||||
if (user)
|
if (user && strlcpy(conf->user, user, sizeof(conf->user))
|
||||||
strlcpy(conf->user, user, sizeof(conf->user));
|
>= sizeof(conf->user))
|
||||||
if (chroot)
|
fatalx("user name too long: %s", user);
|
||||||
strlcpy(conf->chroot, chroot, sizeof(conf->chroot));
|
if (chroot && strlcpy(conf->chroot, chroot, sizeof(conf->chroot))
|
||||||
|
>= sizeof(conf->chroot))
|
||||||
|
fatalx("chroot path too long: %s", chroot);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((ps = calloc(1, sizeof(*ps))) == NULL)
|
if ((ps = calloc(1, sizeof(*ps))) == NULL)
|
||||||
|
@ -412,7 +414,7 @@ main_send_logfd(struct conf *conf)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
fd = open(conf->log_access, O_WRONLY|O_CREAT|O_APPEND, 0600);
|
fd = open(path, O_WRONLY|O_CREAT|O_APPEND, 0600);
|
||||||
if (fd == -1)
|
if (fd == -1)
|
||||||
log_warn("can't open %s", conf->log_access);
|
log_warn("can't open %s", conf->log_access);
|
||||||
}
|
}
|
||||||
|
@ -605,8 +607,8 @@ main_print_conf(struct conf *conf)
|
||||||
|
|
||||||
TAILQ_FOREACH(h, &conf->hosts, vhosts) {
|
TAILQ_FOREACH(h, &conf->hosts, vhosts) {
|
||||||
printf("\nserver \"%s\" {\n", h->domain);
|
printf("\nserver \"%s\" {\n", h->domain);
|
||||||
printf(" cert \"%s\"\n", h->cert);
|
printf(" cert \"%s\"\n", h->cert_path);
|
||||||
printf(" key \"%s\"\n", h->key);
|
printf(" key \"%s\"\n", h->key_path);
|
||||||
/* TODO: print locations... */
|
/* TODO: print locations... */
|
||||||
printf("}\n");
|
printf("}\n");
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
.Dd January 11, 2024
|
.Dd June 11, 2024
|
||||||
.Dt GMID.CONF 5
|
.Dt GMID.CONF 5
|
||||||
.Os
|
.Os
|
||||||
.Sh NAME
|
.Sh NAME
|
||||||
|
@ -384,7 +384,7 @@ The port the server is listening on.
|
||||||
.Dq GEMINI
|
.Dq GEMINI
|
||||||
.It Ev SERVER_SOFTWARE
|
.It Ev SERVER_SOFTWARE
|
||||||
The name and version of the server, i.e.
|
The name and version of the server, i.e.
|
||||||
.Dq gmid/2.0.1
|
.Dq gmid/2.0.5
|
||||||
.It Ev REMOTE_USER
|
.It Ev REMOTE_USER
|
||||||
The subject of the client certificate if provided, otherwise unset.
|
The subject of the client certificate if provided, otherwise unset.
|
||||||
.It Ev TLS_CLIENT_ISSUER
|
.It Ev TLS_CLIENT_ISSUER
|
||||||
|
|
10
gmid.h
10
gmid.h
|
@ -114,6 +114,9 @@ struct address {
|
||||||
socklen_t slen;
|
socklen_t slen;
|
||||||
int16_t port;
|
int16_t port;
|
||||||
|
|
||||||
|
/* pretty-printed version of `ss' */
|
||||||
|
char pp[NI_MAXHOST];
|
||||||
|
|
||||||
/* used in the server */
|
/* used in the server */
|
||||||
struct conf *conf;
|
struct conf *conf;
|
||||||
int sock;
|
int sock;
|
||||||
|
@ -364,10 +367,6 @@ enum imsg_type {
|
||||||
IMSG_CTL_PROCFD,
|
IMSG_CTL_PROCFD,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* gmid.c */
|
|
||||||
char *data_dir(void);
|
|
||||||
void load_local_cert(struct vhost*, const char*, const char*);
|
|
||||||
|
|
||||||
/* gmid.c / ge.c */
|
/* gmid.c / ge.c */
|
||||||
void log_request(struct client *, int, const char *);
|
void log_request(struct client *, int, const char *);
|
||||||
|
|
||||||
|
@ -383,7 +382,6 @@ void crypto(struct privsep *, struct privsep_proc *);
|
||||||
void crypto_engine_init(struct conf *);
|
void crypto_engine_init(struct conf *);
|
||||||
|
|
||||||
/* parse.y */
|
/* parse.y */
|
||||||
void yyerror(const char*, ...);
|
|
||||||
int parse_conf(struct conf *, const char*);
|
int parse_conf(struct conf *, const char*);
|
||||||
int cmdline_symset(char *);
|
int cmdline_symset(char *);
|
||||||
|
|
||||||
|
@ -396,7 +394,6 @@ const char *mime(struct conf *, struct vhost*, const char*);
|
||||||
void free_mime(struct mime *);
|
void free_mime(struct mime *);
|
||||||
|
|
||||||
/* server.c */
|
/* server.c */
|
||||||
extern int shutting_down;
|
|
||||||
const char *vhost_lang(struct vhost*, const char*);
|
const char *vhost_lang(struct vhost*, const char*);
|
||||||
const char *vhost_default_mime(struct vhost*, const char*);
|
const char *vhost_default_mime(struct vhost*, const char*);
|
||||||
const char *vhost_index(struct vhost*, const char*);
|
const char *vhost_index(struct vhost*, const char*);
|
||||||
|
@ -412,7 +409,6 @@ void mark_nonblock(int);
|
||||||
void client_write(struct bufferevent *, void *);
|
void client_write(struct bufferevent *, void *);
|
||||||
int start_reply(struct client*, int, const char*);
|
int start_reply(struct client*, int, const char*);
|
||||||
void client_close(struct client *);
|
void client_close(struct client *);
|
||||||
struct client *client_by_id(int);
|
|
||||||
void server_accept(int, short, void *);
|
void server_accept(int, short, void *);
|
||||||
void server_init(struct privsep *, struct privsep_proc *, void *);
|
void server_init(struct privsep *, struct privsep_proc *, void *);
|
||||||
int server_configure_done(struct conf *);
|
int server_configure_done(struct conf *);
|
||||||
|
|
|
@ -34,12 +34,12 @@ DISTFILES = ASN1_time_parse.c \
|
||||||
setresuid.c \
|
setresuid.c \
|
||||||
strlcat.c \
|
strlcat.c \
|
||||||
strlcpy.c \
|
strlcpy.c \
|
||||||
|
strnvis.c \
|
||||||
strtonum.c \
|
strtonum.c \
|
||||||
sys_endian_h.c \
|
sys_endian_h.c \
|
||||||
timingsafe_memcmp.c \
|
timingsafe_memcmp.c \
|
||||||
tree_h.c \
|
tree_h.c \
|
||||||
vasprintf.c \
|
vasprintf.c \
|
||||||
vis.c \
|
|
||||||
wait_any.c
|
wait_any.c
|
||||||
|
|
||||||
all:
|
all:
|
||||||
|
|
|
@ -19,6 +19,8 @@
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <sys/syscall.h>
|
#include <sys/syscall.h>
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
#ifndef landlock_create_ruleset
|
#ifndef landlock_create_ruleset
|
||||||
static inline int
|
static inline int
|
||||||
landlock_create_ruleset(const struct landlock_ruleset_attr *attr, size_t size,
|
landlock_create_ruleset(const struct landlock_ruleset_attr *attr, size_t size,
|
||||||
|
|
155
iri.c
155
iri.c
|
@ -1,5 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2020, 2022 Omar Polo <op@omarpolo.com>
|
* Copyright (c) 2020, 2022, 2024 Omar Polo <op@omarpolo.com>
|
||||||
|
* Copyright (c) 2015 Theo de Raadt <deraadt@openbsd.org>
|
||||||
*
|
*
|
||||||
* Permission to use, copy, modify, and distribute this software for any
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
* purpose with or without fee is hereby granted, provided that the above
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
@ -177,25 +178,47 @@ parse_port(struct parser *p)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* TODO: add support for ip-literal and ipv4addr ? */
|
|
||||||
/* *( unreserved / sub-delims / pct-encoded ) */
|
/* *( unreserved / sub-delims / pct-encoded ) */
|
||||||
static int
|
static int
|
||||||
parse_authority(struct parser *p)
|
parse_authority(struct parser *p)
|
||||||
{
|
{
|
||||||
p->parsed->host = p->iri;
|
struct addrinfo hints, *ai;
|
||||||
|
char *end;
|
||||||
|
int err;
|
||||||
|
|
||||||
while (unreserved(*p->iri)
|
if (*p->iri == '[') {
|
||||||
|| sub_delimiters(*p->iri)
|
|
||||||
|| parse_pct_encoded(p)
|
|
||||||
|| valid_multibyte_utf8(p)) {
|
|
||||||
/* normalize the host name. */
|
|
||||||
if (*p->iri < 0x7F)
|
|
||||||
*p->iri = tolower(*p->iri);
|
|
||||||
p->iri++;
|
p->iri++;
|
||||||
}
|
p->parsed->host = p->iri;
|
||||||
|
if ((end = strchr(p->iri, ']')) == NULL) {
|
||||||
|
p->err = "invalid IPv6 address";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
*end++ = '\0';
|
||||||
|
p->iri = end;
|
||||||
|
|
||||||
if (p->err != NULL)
|
memset(&hints, 0, sizeof(hints));
|
||||||
return 0;
|
hints.ai_flags = AI_NUMERICHOST;
|
||||||
|
err = getaddrinfo(p->parsed->host, NULL, &hints, &ai);
|
||||||
|
if (err != 0) {
|
||||||
|
p->err = "invalid IPv6 address";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
freeaddrinfo(ai);
|
||||||
|
} else {
|
||||||
|
p->parsed->host = p->iri;
|
||||||
|
while (unreserved(*p->iri)
|
||||||
|
|| sub_delimiters(*p->iri)
|
||||||
|
|| parse_pct_encoded(p)
|
||||||
|
|| valid_multibyte_utf8(p)) {
|
||||||
|
/* normalize the host name. */
|
||||||
|
if (*p->iri < 0x7F)
|
||||||
|
*p->iri = tolower(*p->iri);
|
||||||
|
p->iri++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (p->err != NULL)
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (*p->iri == ':') {
|
if (*p->iri == ':') {
|
||||||
*p->iri = '\0';
|
*p->iri = '\0';
|
||||||
|
@ -218,78 +241,56 @@ parse_authority(struct parser *p)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Routine for path_clean. Elide the pointed .. with the preceding
|
* Use an algorithm based on canonpath() from kern_pledge.c.
|
||||||
* element. Return 0 if it's not possible. incr is the length of
|
|
||||||
* the increment, 3 for ../ and 2 for ..
|
|
||||||
*/
|
|
||||||
static int
|
|
||||||
path_elide_dotdot(char *path, char *i, int incr)
|
|
||||||
{
|
|
||||||
char *j;
|
|
||||||
|
|
||||||
if (i == path)
|
|
||||||
return 0;
|
|
||||||
for (j = i-2; j != path && *j != '/'; j--)
|
|
||||||
/* noop */ ;
|
|
||||||
if (*j == '/')
|
|
||||||
j++;
|
|
||||||
i += incr;
|
|
||||||
memmove(j, i, strlen(i)+1);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Use an algorithm similar to the one implemented in go' path.Clean:
|
|
||||||
*
|
*
|
||||||
* 1. Replace multiple slashes with a single slash
|
* It's slightly more complicated since even if your paths are
|
||||||
* 2. Eliminate each . path name element
|
* absolutely, they don't start with '/'. q == path asserts
|
||||||
* 3. Eliminate each inner .. along with the non-.. element that precedes it
|
* that we're at the start of the path.
|
||||||
* 4. Eliminate trailing .. if possible or error (go would only discard)
|
|
||||||
*
|
|
||||||
* Unlike path.Clean, this function return the empty string if the
|
|
||||||
* original path is equivalent to "/".
|
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
path_clean(char *path)
|
path_clean(char *path)
|
||||||
{
|
{
|
||||||
char *i;
|
char *p, *q;
|
||||||
|
|
||||||
/* 1. replace multiple slashes with a single one */
|
p = q = path;
|
||||||
for (i = path; *i; ++i) {
|
while (*p) {
|
||||||
if (*i == '/' && *(i+1) == '/') {
|
if (q == path && p[0] == '/') {
|
||||||
memmove(i, i+1, strlen(i)); /* move also the \0 */
|
/* special case, if path is just "/" trim it */
|
||||||
i--;
|
p++;
|
||||||
|
} else if (q == path && p[0] == '.' && p[1] == '.' &&
|
||||||
|
(p[2] == '/' || p[2] == '\0')) {
|
||||||
|
/* ../ at the start of path */
|
||||||
|
p += 2;
|
||||||
|
if (*p == '/')
|
||||||
|
p++;
|
||||||
|
} else if (q == path && p[0] == '.' &&
|
||||||
|
(p[1] == '/' || p[1] == '\0')) {
|
||||||
|
/* ./ at the start of path */
|
||||||
|
p++;
|
||||||
|
if (*p == '/')
|
||||||
|
p++;
|
||||||
|
} else if (p[0] == '/' && p[1] == '/') {
|
||||||
|
/* trim double slashes */
|
||||||
|
p++;
|
||||||
|
} else if (p[0] == '/' && p[1] == '.' && p[2] == '.' &&
|
||||||
|
(p[3] == '/' || p[3] == '\0')) {
|
||||||
|
/* /../ component */
|
||||||
|
while (q > path && *--q != '/')
|
||||||
|
continue;
|
||||||
|
p += 3;
|
||||||
|
if (q == path && *p == '/')
|
||||||
|
p++;
|
||||||
|
} else if (p[0] == '/' && p[1] == '.' &&
|
||||||
|
(p[2] == '/' || p[2] == '\0')) {
|
||||||
|
/* /./ component */
|
||||||
|
p += 2;
|
||||||
|
} else {
|
||||||
|
*q++ = *p++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (*p != '\0')
|
||||||
/* 2. eliminate each . path name element */
|
return 0;
|
||||||
for (i = path; *i; ++i) {
|
*q = '\0';
|
||||||
if ((i == path || *i == '/') &&
|
|
||||||
*i != '.' && i[1] == '.' && i[2] == '/') {
|
|
||||||
/* move also the \0 */
|
|
||||||
memmove(i, i+2, strlen(i)-1);
|
|
||||||
i--;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!strcmp(path, ".") || !strcmp(path, "/.")) {
|
|
||||||
*path = '\0';
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 3. eliminate each inner .. along with the preceding non-.. */
|
|
||||||
for (i = strstr(path, "../"); i != NULL; i = strstr(path, "..")) {
|
|
||||||
/* break if we've found a trailing .. */
|
|
||||||
if (i[2] == '\0')
|
|
||||||
break;
|
|
||||||
if (!path_elide_dotdot(path, i, 3))
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 4. eliminate trailing ..*/
|
|
||||||
if ((i = strstr(path, "..")) != NULL)
|
|
||||||
if (!path_elide_dotdot(path, i, 2))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
183
parse.y
183
parse.y
|
@ -1,7 +1,7 @@
|
||||||
%{
|
%{
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2021, 2022, 2023 Omar Polo <op@omarpolo.com>
|
* Copyright (c) 2021-2024 Omar Polo <op@omarpolo.com>
|
||||||
* Copyright (c) 2018 Florian Obser <florian@openbsd.org>
|
* Copyright (c) 2018 Florian Obser <florian@openbsd.org>
|
||||||
* Copyright (c) 2004, 2005 Esben Norby <norby@openbsd.org>
|
* Copyright (c) 2004, 2005 Esben Norby <norby@openbsd.org>
|
||||||
* Copyright (c) 2004 Ryan McBride <mcbride@openbsd.org>
|
* Copyright (c) 2004 Ryan McBride <mcbride@openbsd.org>
|
||||||
|
@ -46,7 +46,7 @@ static struct file {
|
||||||
TAILQ_ENTRY(file) entry;
|
TAILQ_ENTRY(file) entry;
|
||||||
FILE *stream;
|
FILE *stream;
|
||||||
char *name;
|
char *name;
|
||||||
size_t ungetpos;
|
size_t ungetpos;
|
||||||
size_t ungetsize;
|
size_t ungetsize;
|
||||||
u_char *ungetbuf;
|
u_char *ungetbuf;
|
||||||
int eof_reached;
|
int eof_reached;
|
||||||
|
@ -92,11 +92,9 @@ char *ensure_absolute_path(char*);
|
||||||
int check_block_code(int);
|
int check_block_code(int);
|
||||||
char *check_block_fmt(char*);
|
char *check_block_fmt(char*);
|
||||||
int check_strip_no(int);
|
int check_strip_no(int);
|
||||||
int check_port_num(int);
|
|
||||||
int check_prefork_num(int);
|
int check_prefork_num(int);
|
||||||
void advance_loc(void);
|
void advance_loc(void);
|
||||||
void advance_proxy(void);
|
void advance_proxy(void);
|
||||||
void parsehp(char *, char **, const char **, const char *);
|
|
||||||
int fastcgi_conf(const char *, const char *);
|
int fastcgi_conf(const char *, const char *);
|
||||||
void add_param(char *, char *);
|
void add_param(char *, char *);
|
||||||
int getservice(const char *);
|
int getservice(const char *);
|
||||||
|
@ -125,12 +123,12 @@ typedef struct {
|
||||||
|
|
||||||
%token ACCESS ALIAS AUTO
|
%token ACCESS ALIAS AUTO
|
||||||
%token BLOCK
|
%token BLOCK
|
||||||
%token CA CERT CHROOT CLIENT COMBINED COMMON CONDENSED
|
%token CA CERT CGI CHROOT CLIENT
|
||||||
%token DEFAULT
|
%token DEFAULT
|
||||||
%token FACILITY FASTCGI FOR_HOST
|
%token FACILITY FASTCGI FOR_HOST
|
||||||
%token INCLUDE INDEX IPV6
|
%token INCLUDE INDEX IPV6
|
||||||
%token KEY
|
%token KEY
|
||||||
%token LANG LEGACY LISTEN LOCATION LOG
|
%token LANG LISTEN LOCATION LOG
|
||||||
%token OCSP OFF ON
|
%token OCSP OFF ON
|
||||||
%token PARAM PORT PREFORK PROTO PROTOCOLS PROXY
|
%token PARAM PORT PREFORK PROTO PROTOCOLS PROXY
|
||||||
%token RELAY_TO REQUIRE RETURN ROOT
|
%token RELAY_TO REQUIRE RETURN ROOT
|
||||||
|
@ -149,14 +147,19 @@ typedef struct {
|
||||||
|
|
||||||
%%
|
%%
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Allow empty lines at the start of the configuration.
|
||||||
|
*/
|
||||||
|
grammar : nl conf | conf
|
||||||
|
;
|
||||||
|
|
||||||
conf : /* empty */
|
conf : /* empty */
|
||||||
| conf include '\n'
|
| conf include nl
|
||||||
| conf '\n'
|
| conf varset nl
|
||||||
| conf varset '\n'
|
| conf option nl
|
||||||
| conf option '\n'
|
| conf vhost nl
|
||||||
| conf vhost '\n'
|
| conf types nl
|
||||||
| conf types '\n'
|
| conf error nl { file->errors++; }
|
||||||
| conf error '\n' { file->errors++; }
|
|
||||||
;
|
;
|
||||||
|
|
||||||
include : INCLUDE STRING {
|
include : INCLUDE STRING {
|
||||||
|
@ -265,17 +268,18 @@ logopt : ACCESS string {
|
||||||
free(conf->log_access);
|
free(conf->log_access);
|
||||||
conf->log_access = $2;
|
conf->log_access = $2;
|
||||||
}
|
}
|
||||||
| STYLE COMMON {
|
| STYLE string {
|
||||||
conf->log_format = LOG_FORMAT_COMMON;
|
if (!strcmp("combined", $2))
|
||||||
}
|
conf->log_format = LOG_FORMAT_COMBINED;
|
||||||
| STYLE COMBINED {
|
else if (!strcmp("common", $2))
|
||||||
conf->log_format = LOG_FORMAT_COMBINED;
|
conf->log_format = LOG_FORMAT_COMMON;
|
||||||
}
|
else if (!strcmp("condensed", $2))
|
||||||
| STYLE CONDENSED {
|
conf->log_format = LOG_FORMAT_CONDENSED;
|
||||||
conf->log_format = LOG_FORMAT_CONDENSED;
|
else if (!strcmp("legacy", $2))
|
||||||
}
|
conf->log_format = LOG_FORMAT_LEGACY;
|
||||||
| STYLE LEGACY {
|
else
|
||||||
conf->log_format = LOG_FORMAT_LEGACY;
|
yyerror("unknown log style: %s", $2);
|
||||||
|
free($2);
|
||||||
}
|
}
|
||||||
| SYSLOG FACILITY string {
|
| SYSLOG FACILITY string {
|
||||||
const char *str = $3;
|
const char *str = $3;
|
||||||
|
@ -331,7 +335,10 @@ vhost : SERVER string {
|
||||||
TAILQ_INIT(&host->proxies);
|
TAILQ_INIT(&host->proxies);
|
||||||
|
|
||||||
(void) strlcpy(loc->match, "*", sizeof(loc->match));
|
(void) strlcpy(loc->match, "*", sizeof(loc->match));
|
||||||
(void) strlcpy(host->domain, $2, sizeof(host->domain));
|
|
||||||
|
if (strlcpy(host->domain, $2, sizeof(host->domain))
|
||||||
|
>= sizeof(host->domain))
|
||||||
|
yyerror("server name too long: %s", $2);
|
||||||
|
|
||||||
if (strstr($2, "xn--") != NULL) {
|
if (strstr($2, "xn--") != NULL) {
|
||||||
yywarn("\"%s\" looks like punycode: you "
|
yywarn("\"%s\" looks like punycode: you "
|
||||||
|
@ -377,7 +384,9 @@ servopt : ALIAS string {
|
||||||
struct alist *a;
|
struct alist *a;
|
||||||
|
|
||||||
a = xcalloc(1, sizeof(*a));
|
a = xcalloc(1, sizeof(*a));
|
||||||
(void) strlcpy(a->alias, $2, sizeof(a->alias));
|
if (strlcpy(a->alias, $2, sizeof(a->alias))
|
||||||
|
>= sizeof(a->alias))
|
||||||
|
yyerror("alias too long: %s", $2);
|
||||||
free($2);
|
free($2);
|
||||||
TAILQ_INSERT_TAIL(&host->aliases, a, aliases);
|
TAILQ_INSERT_TAIL(&host->aliases, a, aliases);
|
||||||
}
|
}
|
||||||
|
@ -386,6 +395,11 @@ servopt : ALIAS string {
|
||||||
free(host->cert_path);
|
free(host->cert_path);
|
||||||
host->cert_path = $2;
|
host->cert_path = $2;
|
||||||
}
|
}
|
||||||
|
| CGI string {
|
||||||
|
free($2);
|
||||||
|
yyerror("`cgi' was removed in gmid 2.0."
|
||||||
|
" Please use fastcgi or proxy instead.");
|
||||||
|
}
|
||||||
| KEY string {
|
| KEY string {
|
||||||
ensure_absolute_path($2);
|
ensure_absolute_path($2);
|
||||||
free(host->key_path);
|
free(host->key_path);
|
||||||
|
@ -449,11 +463,17 @@ proxy_port : /* empty */ { $$ = 1965; }
|
||||||
;
|
;
|
||||||
|
|
||||||
proxy_match : PROTO string {
|
proxy_match : PROTO string {
|
||||||
(void) strlcpy(proxy->match_proto, $2, sizeof(proxy->match_proto));
|
if (strlcpy(proxy->match_proto, $2,
|
||||||
|
sizeof(proxy->match_proto))
|
||||||
|
>= sizeof(proxy->match_proto))
|
||||||
|
yyerror("proto too long: %s", $2);
|
||||||
free($2);
|
free($2);
|
||||||
}
|
}
|
||||||
| FOR_HOST string proxy_port {
|
| FOR_HOST string proxy_port {
|
||||||
(void) strlcpy(proxy->match_host, $2, sizeof(proxy->match_host));
|
if (strlcpy(proxy->match_host, $2,
|
||||||
|
sizeof(proxy->match_host))
|
||||||
|
>= sizeof(proxy->match_host))
|
||||||
|
yyerror("for-host too long: %s", $2);
|
||||||
(void) snprintf(proxy->match_port, sizeof(proxy->match_port),
|
(void) snprintf(proxy->match_port, sizeof(proxy->match_port),
|
||||||
"%d", $3);
|
"%d", $3);
|
||||||
free($2);
|
free($2);
|
||||||
|
@ -480,7 +500,9 @@ proxy_opt : CERT string {
|
||||||
free($2);
|
free($2);
|
||||||
}
|
}
|
||||||
| RELAY_TO string proxy_port {
|
| RELAY_TO string proxy_port {
|
||||||
(void) strlcpy(proxy->host, $2, sizeof(proxy->host));
|
if (strlcpy(proxy->host, $2, sizeof(proxy->host))
|
||||||
|
>= sizeof(proxy->host))
|
||||||
|
yyerror("relay-to host too long: %s", $2);
|
||||||
(void) snprintf(proxy->port, sizeof(proxy->port),
|
(void) snprintf(proxy->port, sizeof(proxy->port),
|
||||||
"%d", $3);
|
"%d", $3);
|
||||||
free($2);
|
free($2);
|
||||||
|
@ -490,7 +512,9 @@ proxy_opt : CERT string {
|
||||||
proxy->reqca_path = $4;
|
proxy->reqca_path = $4;
|
||||||
}
|
}
|
||||||
| SNI string {
|
| SNI string {
|
||||||
(void) strlcpy(proxy->sni, $2, sizeof(proxy->sni));
|
if (strlcpy(proxy->sni, $2, sizeof(proxy->sni))
|
||||||
|
>= sizeof(proxy->sni))
|
||||||
|
yyerror("sni hostname too long: %s", $2);
|
||||||
free($2);
|
free($2);
|
||||||
}
|
}
|
||||||
| USE_TLS bool {
|
| USE_TLS bool {
|
||||||
|
@ -505,7 +529,9 @@ location : LOCATION { advance_loc(); } string '{' optnl locopts '}' {
|
||||||
/* drop the starting '/' if any */
|
/* drop the starting '/' if any */
|
||||||
if (*$3 == '/')
|
if (*$3 == '/')
|
||||||
memmove($3, $3+1, strlen($3));
|
memmove($3, $3+1, strlen($3));
|
||||||
(void) strlcpy(loc->match, $3, sizeof(loc->match));
|
if (strlcpy(loc->match, $3, sizeof(loc->match))
|
||||||
|
>= sizeof(loc->match))
|
||||||
|
yyerror("location path too long: %s", $3);
|
||||||
free($3);
|
free($3);
|
||||||
}
|
}
|
||||||
| error '}'
|
| error '}'
|
||||||
|
@ -518,7 +544,9 @@ locopts : /* empty */
|
||||||
locopt : AUTO INDEX bool { loc->auto_index = $3 ? 1 : -1; }
|
locopt : AUTO INDEX bool { loc->auto_index = $3 ? 1 : -1; }
|
||||||
| BLOCK RETURN NUM string {
|
| BLOCK RETURN NUM string {
|
||||||
check_block_fmt($4);
|
check_block_fmt($4);
|
||||||
(void) strlcpy(loc->block_fmt, $4, sizeof(loc->block_fmt));
|
if (strlcpy(loc->block_fmt, $4, sizeof(loc->block_fmt))
|
||||||
|
>= sizeof(loc->block_fmt))
|
||||||
|
yyerror("block return meta too long: %s", $4);
|
||||||
loc->block_code = check_block_code($3);
|
loc->block_code = check_block_code($3);
|
||||||
free($4);
|
free($4);
|
||||||
}
|
}
|
||||||
|
@ -535,18 +563,23 @@ locopt : AUTO INDEX bool { loc->auto_index = $3 ? 1 : -1; }
|
||||||
loc->block_code = 40;
|
loc->block_code = 40;
|
||||||
}
|
}
|
||||||
| DEFAULT TYPE string {
|
| DEFAULT TYPE string {
|
||||||
(void) strlcpy(loc->default_mime, $3,
|
if (strlcpy(loc->default_mime, $3,
|
||||||
sizeof(loc->default_mime));
|
sizeof(loc->default_mime))
|
||||||
|
>= sizeof(loc->default_mime))
|
||||||
|
yyerror("default type too long: %s", $3);
|
||||||
free($3);
|
free($3);
|
||||||
}
|
}
|
||||||
| fastcgi
|
| fastcgi
|
||||||
| INDEX string {
|
| INDEX string {
|
||||||
(void) strlcpy(loc->index, $2, sizeof(loc->index));
|
if (strlcpy(loc->index, $2, sizeof(loc->index))
|
||||||
|
>= sizeof(loc->index))
|
||||||
|
yyerror("index string too long: %s", $2);
|
||||||
free($2);
|
free($2);
|
||||||
}
|
}
|
||||||
| LANG string {
|
| LANG string {
|
||||||
(void) strlcpy(loc->lang, $2,
|
if (strlcpy(loc->lang, $2, sizeof(loc->lang))
|
||||||
sizeof(loc->lang));
|
>= sizeof(loc->lang))
|
||||||
|
yyerror("lang too long: %s", $2);
|
||||||
free($2);
|
free($2);
|
||||||
}
|
}
|
||||||
| LOG bool { loc->disable_log = !$2; }
|
| LOG bool { loc->disable_log = !$2; }
|
||||||
|
@ -555,7 +588,9 @@ locopt : AUTO INDEX bool { loc->auto_index = $3 ? 1 : -1; }
|
||||||
loc->reqca_path = $4;
|
loc->reqca_path = $4;
|
||||||
}
|
}
|
||||||
| ROOT string {
|
| ROOT string {
|
||||||
(void) strlcpy(loc->dir, $2, sizeof(loc->dir));
|
if (strlcpy(loc->dir, $2, sizeof(loc->dir))
|
||||||
|
>= sizeof(loc->dir))
|
||||||
|
yyerror("root path too long: %s", $2);
|
||||||
free($2);
|
free($2);
|
||||||
}
|
}
|
||||||
| STRIP NUM { loc->strip = check_strip_no($2); }
|
| STRIP NUM { loc->strip = check_strip_no($2); }
|
||||||
|
@ -617,7 +652,7 @@ mediaopts_l : mediaopts_l mediaoptsl nl
|
||||||
mediaoptsl : STRING {
|
mediaoptsl : STRING {
|
||||||
free(current_media);
|
free(current_media);
|
||||||
current_media = $1;
|
current_media = $1;
|
||||||
} medianames_l optsemicolon
|
} medianames_l
|
||||||
| include
|
| include
|
||||||
;
|
;
|
||||||
|
|
||||||
|
@ -633,17 +668,13 @@ medianamesl : numberstring {
|
||||||
;
|
;
|
||||||
|
|
||||||
nl : '\n' optnl
|
nl : '\n' optnl
|
||||||
|
| ';' optnl
|
||||||
;
|
;
|
||||||
|
|
||||||
optnl : '\n' optnl /* zero or more newlines */
|
optnl : nl
|
||||||
| ';' optnl /* semicolons too */
|
|
||||||
| /*empty*/
|
| /*empty*/
|
||||||
;
|
;
|
||||||
|
|
||||||
optsemicolon : ';'
|
|
||||||
|
|
|
||||||
;
|
|
||||||
|
|
||||||
%%
|
%%
|
||||||
|
|
||||||
static const struct keyword {
|
static const struct keyword {
|
||||||
|
@ -657,11 +688,9 @@ static const struct keyword {
|
||||||
{"block", BLOCK},
|
{"block", BLOCK},
|
||||||
{"ca", CA},
|
{"ca", CA},
|
||||||
{"cert", CERT},
|
{"cert", CERT},
|
||||||
|
{"cgi", CGI},
|
||||||
{"chroot", CHROOT},
|
{"chroot", CHROOT},
|
||||||
{"client", CLIENT},
|
{"client", CLIENT},
|
||||||
{"combined", COMBINED},
|
|
||||||
{"common", COMMON},
|
|
||||||
{"condensed", CONDENSED},
|
|
||||||
{"default", DEFAULT},
|
{"default", DEFAULT},
|
||||||
{"facility", FACILITY},
|
{"facility", FACILITY},
|
||||||
{"fastcgi", FASTCGI},
|
{"fastcgi", FASTCGI},
|
||||||
|
@ -671,7 +700,6 @@ static const struct keyword {
|
||||||
{"ipv6", IPV6},
|
{"ipv6", IPV6},
|
||||||
{"key", KEY},
|
{"key", KEY},
|
||||||
{"lang", LANG},
|
{"lang", LANG},
|
||||||
{"legacy", LEGACY},
|
|
||||||
{"listen", LISTEN},
|
{"listen", LISTEN},
|
||||||
{"location", LOCATION},
|
{"location", LOCATION},
|
||||||
{"log", LOG},
|
{"log", LOG},
|
||||||
|
@ -1211,16 +1239,6 @@ check_strip_no(int n)
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
|
||||||
check_port_num(int n)
|
|
||||||
{
|
|
||||||
if (n <= 0 || n >= UINT16_MAX)
|
|
||||||
yyerror("port number is %s: %d",
|
|
||||||
n <= 0 ? "too small" : "too large",
|
|
||||||
n);
|
|
||||||
return n;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
int
|
||||||
check_prefork_num(int n)
|
check_prefork_num(int n)
|
||||||
{
|
{
|
||||||
|
@ -1243,25 +1261,6 @@ advance_proxy(void)
|
||||||
TAILQ_INSERT_TAIL(&host->proxies, proxy, proxies);
|
TAILQ_INSERT_TAIL(&host->proxies, proxy, proxies);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
parsehp(char *str, char **host, const char **port, const char *def)
|
|
||||||
{
|
|
||||||
char *at;
|
|
||||||
const char *errstr;
|
|
||||||
|
|
||||||
*host = str;
|
|
||||||
|
|
||||||
if ((at = strchr(str, ':')) != NULL) {
|
|
||||||
*at++ = '\0';
|
|
||||||
*port = at;
|
|
||||||
} else
|
|
||||||
*port = def;
|
|
||||||
|
|
||||||
strtonum(*port, 1, UINT16_MAX, &errstr);
|
|
||||||
if (errstr != NULL)
|
|
||||||
yyerror("port is %s: %s", errstr, *port);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
int
|
||||||
fastcgi_conf(const char *path, const char *port)
|
fastcgi_conf(const char *path, const char *port)
|
||||||
{
|
{
|
||||||
|
@ -1278,9 +1277,11 @@ fastcgi_conf(const char *path, const char *port)
|
||||||
|
|
||||||
f = xcalloc(1, sizeof(*f));
|
f = xcalloc(1, sizeof(*f));
|
||||||
f->id = i;
|
f->id = i;
|
||||||
(void)strlcpy(f->path, path, sizeof(f->path));
|
if (strlcpy(f->path, path, sizeof(f->path)) >= sizeof(f->path))
|
||||||
if (port != NULL)
|
yyerror("fastcgi path is too long: %s", path);
|
||||||
(void)strlcpy(f->port, port, sizeof(f->port));
|
if (port != NULL &&
|
||||||
|
strlcpy(f->port, port, sizeof(f->port)) >= sizeof(f->port))
|
||||||
|
yyerror("port too long: %s", port);
|
||||||
TAILQ_INSERT_TAIL(&conf->fcgi, f, fcgi);
|
TAILQ_INSERT_TAIL(&conf->fcgi, f, fcgi);
|
||||||
|
|
||||||
return f->id;
|
return f->id;
|
||||||
|
@ -1293,8 +1294,10 @@ add_param(char *name, char *val)
|
||||||
struct envhead *h = &loc->params;
|
struct envhead *h = &loc->params;
|
||||||
|
|
||||||
e = xcalloc(1, sizeof(*e));
|
e = xcalloc(1, sizeof(*e));
|
||||||
(void) strlcpy(e->name, name, sizeof(e->name));
|
if (strlcpy(e->name, name, sizeof(e->name)) >= sizeof(e->name))
|
||||||
(void) strlcpy(e->value, val, sizeof(e->value));
|
yyerror("parameter name too long: %s", name);
|
||||||
|
if (strlcpy(e->value, val, sizeof(e->value)) >= sizeof(e->value))
|
||||||
|
yyerror("param value too long: %s", val);
|
||||||
TAILQ_INSERT_TAIL(h, e, envs);
|
TAILQ_INSERT_TAIL(h, e, envs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1319,7 +1322,7 @@ getservice(const char *n)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
add_to_addr_queue(struct addrhead *a, struct addrinfo *ai)
|
add_to_addr_queue(struct addrhead *a, struct addrinfo *ai, const char *pp)
|
||||||
{
|
{
|
||||||
struct address *addr;
|
struct address *addr;
|
||||||
struct sockaddr_in *sin;
|
struct sockaddr_in *sin;
|
||||||
|
@ -1345,6 +1348,7 @@ add_to_addr_queue(struct addrhead *a, struct addrinfo *ai)
|
||||||
addr->ai_protocol = ai->ai_protocol;
|
addr->ai_protocol = ai->ai_protocol;
|
||||||
addr->slen = ai->ai_addrlen;
|
addr->slen = ai->ai_addrlen;
|
||||||
memcpy(&addr->ss, ai->ai_addr, ai->ai_addrlen);
|
memcpy(&addr->ss, ai->ai_addr, ai->ai_addrlen);
|
||||||
|
strlcpy(addr->pp, pp, sizeof(addr->pp));
|
||||||
|
|
||||||
/* for commodity */
|
/* for commodity */
|
||||||
switch (addr->ai_family) {
|
switch (addr->ai_family) {
|
||||||
|
@ -1369,6 +1373,7 @@ void
|
||||||
listen_on(const char *hostname, const char *servname)
|
listen_on(const char *hostname, const char *servname)
|
||||||
{
|
{
|
||||||
struct addrinfo hints, *res, *res0;
|
struct addrinfo hints, *res, *res0;
|
||||||
|
char pp[NI_MAXHOST];
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
memset(&hints, 0, sizeof(hints));
|
memset(&hints, 0, sizeof(hints));
|
||||||
|
@ -1383,8 +1388,14 @@ listen_on(const char *hostname, const char *servname)
|
||||||
}
|
}
|
||||||
|
|
||||||
for (res = res0; res; res = res->ai_next) {
|
for (res = res0; res; res = res->ai_next) {
|
||||||
add_to_addr_queue(&host->addrs, res);
|
if (getnameinfo(res->ai_addr, res->ai_addrlen, pp, sizeof(pp),
|
||||||
add_to_addr_queue(&conf->addrs, res);
|
NULL, 0, NI_NUMERICHOST) == -1) {
|
||||||
|
yyerror("getnameinfo failed: %s", strerror(errno));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
add_to_addr_queue(&host->addrs, res, pp);
|
||||||
|
add_to_addr_queue(&conf->addrs, res, pp);
|
||||||
}
|
}
|
||||||
|
|
||||||
freeaddrinfo(res0);
|
freeaddrinfo(res0);
|
||||||
|
|
4
proxy.c
4
proxy.c
|
@ -22,7 +22,7 @@
|
||||||
|
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
|
|
||||||
#define MIN(a, b) ((a) < (b) ? (a) : (b))
|
#define MINIMUM(a, b) ((a) < (b) ? (a) : (b))
|
||||||
|
|
||||||
static const struct timeval handshake_timeout = { 5, 0 };
|
static const struct timeval handshake_timeout = { 5, 0 };
|
||||||
|
|
||||||
|
@ -50,7 +50,7 @@ proxy_tls_readcb(int fd, short event, void *d)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bufev->wm_read.high != 0)
|
if (bufev->wm_read.high != 0)
|
||||||
howmuch = MIN(sizeof(buf), bufev->wm_read.high);
|
howmuch = MINIMUM(sizeof(buf), bufev->wm_read.high);
|
||||||
|
|
||||||
switch (ret = tls_read(c->proxyctx, buf, howmuch)) {
|
switch (ret = tls_read(c->proxyctx, buf, howmuch)) {
|
||||||
case TLS_WANT_POLLIN:
|
case TLS_WANT_POLLIN:
|
||||||
|
|
|
@ -7,6 +7,9 @@ GENCERT_FLAGS=
|
||||||
# host to bind to during regress
|
# host to bind to during regress
|
||||||
REGRESS_HOST = localhost
|
REGRESS_HOST = localhost
|
||||||
|
|
||||||
|
# set to no if don't have IPv6 working (need to listen on ::1)
|
||||||
|
HAVE_IPV6 = yes
|
||||||
|
|
||||||
DISTFILES = Makefile \
|
DISTFILES = Makefile \
|
||||||
env \
|
env \
|
||||||
err \
|
err \
|
||||||
|
@ -39,7 +42,7 @@ IRI_OBJS = ${IRI_SRCS:.c=.o} ${REG_COMPATS}
|
||||||
.PHONY: all data clean dist
|
.PHONY: all data clean dist
|
||||||
|
|
||||||
all: data puny-test iri_test fcgi-test
|
all: data puny-test iri_test fcgi-test
|
||||||
env REGRESS_HOST="${REGRESS_HOST}" ./regress ${TESTS}
|
env HAVE_IPV6="${HAVE_IPV6}" REGRESS_HOST="${REGRESS_HOST}" ./regress ${TESTS}
|
||||||
|
|
||||||
data: testdata localhost.pem testca.pem valid.crt invalid.pem
|
data: testdata localhost.pem testca.pem valid.crt invalid.pem
|
||||||
|
|
||||||
|
|
|
@ -62,12 +62,12 @@ int run_test(const char*, int, struct iri);
|
||||||
int
|
int
|
||||||
diff_iri(struct iri *p, struct iri *exp)
|
diff_iri(struct iri *p, struct iri *exp)
|
||||||
{
|
{
|
||||||
DIFF(p, exp, schema);
|
DIFF(p, exp, schema);
|
||||||
DIFF(p, exp, host);
|
DIFF(p, exp, host);
|
||||||
DIFF(p, exp, port);
|
DIFF(p, exp, port);
|
||||||
DIFF(p, exp, path);
|
DIFF(p, exp, path);
|
||||||
DIFF(p, exp, query);
|
DIFF(p, exp, query);
|
||||||
DIFF(p, exp, fragment);
|
DIFF(p, exp, fragment);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -162,6 +162,14 @@ main(void)
|
||||||
PASS,
|
PASS,
|
||||||
IRI("gemini", "naïve.omarpolo.com", "", "", "", ""),
|
IRI("gemini", "naïve.omarpolo.com", "", "", "", ""),
|
||||||
"Can percent decode hostnames");
|
"Can percent decode hostnames");
|
||||||
|
TEST("gemini://100.64.3.27/",
|
||||||
|
PASS,
|
||||||
|
IRI("gemini", "100.64.3.27", "", "", "", ""),
|
||||||
|
"Accepts IPv4 addresses");
|
||||||
|
TEST("gemini://[::1]/",
|
||||||
|
PASS,
|
||||||
|
IRI("gemini", "::1", "", "", "", ""),
|
||||||
|
"Accepts IPv6 addresses");
|
||||||
|
|
||||||
/* path */
|
/* path */
|
||||||
TEST("gemini://omarpolo.com/foo/bar/baz",
|
TEST("gemini://omarpolo.com/foo/bar/baz",
|
||||||
|
@ -186,31 +194,31 @@ main(void)
|
||||||
"parse paths with multiple .. elements");
|
"parse paths with multiple .. elements");
|
||||||
TEST("gemini://omarpolo.com/foo/..",
|
TEST("gemini://omarpolo.com/foo/..",
|
||||||
PASS,
|
PASS,
|
||||||
IRI("gemini", "omarpolo.com", "", "", "", ""),
|
IRI("gemini", "omarpolo.com", "", "", "", ""),
|
||||||
"parse paths with a trailing ..");
|
"parse paths with a trailing ..");
|
||||||
TEST("gemini://omarpolo.com/foo/../",
|
TEST("gemini://omarpolo.com/foo/../",
|
||||||
PASS,
|
PASS,
|
||||||
IRI("gemini", "omarpolo.com", "", "", "", ""),
|
IRI("gemini", "omarpolo.com", "", "", "", ""),
|
||||||
"parse paths with a trailing ..");
|
"parse paths with a trailing ..");
|
||||||
TEST("gemini://omarpolo.com/foo/../..",
|
TEST("gemini://omarpolo.com/foo/../..",
|
||||||
FAIL,
|
PASS,
|
||||||
empty,
|
IRI("gemini", "omarpolo.com", "", "", "", ""),
|
||||||
"reject paths that would escape the root");
|
"parse paths that would escape the root");
|
||||||
TEST("gemini://omarpolo.com/foo/../../",
|
TEST("gemini://omarpolo.com/foo/../../",
|
||||||
FAIL,
|
PASS,
|
||||||
empty,
|
IRI("gemini", "omarpolo.com", "", "", "", ""),
|
||||||
"reject paths that would escape the root")
|
"parse paths that would escape the root")
|
||||||
TEST("gemini://omarpolo.com/foo/../foo/../././/bar/baz/.././.././/",
|
TEST("gemini://omarpolo.com/foo/../foo/../././/bar/baz/.././.././/",
|
||||||
PASS,
|
PASS,
|
||||||
IRI("gemini", "omarpolo.com", "", "", "", ""),
|
IRI("gemini", "omarpolo.com", "", "", "", ""),
|
||||||
"parse path with lots of cleaning available");
|
"parse path with lots of cleaning available");
|
||||||
TEST("gemini://omarpolo.com//foo",
|
TEST("gemini://omarpolo.com//foo",
|
||||||
PASS,
|
PASS,
|
||||||
IRI("gemini", "omarpolo.com", "", "foo", "", ""),
|
IRI("gemini", "omarpolo.com", "", "foo", "", ""),
|
||||||
"Trim initial slashes");
|
"Trim initial slashes");
|
||||||
TEST("gemini://omarpolo.com/////foo",
|
TEST("gemini://omarpolo.com/////foo",
|
||||||
PASS,
|
PASS,
|
||||||
IRI("gemini", "omarpolo.com", "", "foo", "", ""),
|
IRI("gemini", "omarpolo.com", "", "foo", "", ""),
|
||||||
"Trim initial slashes (pt. 2)");
|
"Trim initial slashes (pt. 2)");
|
||||||
TEST("http://a/b/c/../..",
|
TEST("http://a/b/c/../..",
|
||||||
PASS,
|
PASS,
|
||||||
|
@ -263,8 +271,8 @@ main(void)
|
||||||
IRI("foo", "bar.com", "", "caffè+macchiato.gmi", "", ""),
|
IRI("foo", "bar.com", "", "caffè+macchiato.gmi", "", ""),
|
||||||
"can decode");
|
"can decode");
|
||||||
TEST("foo://bar.com/foo%2F..%2F..",
|
TEST("foo://bar.com/foo%2F..%2F..",
|
||||||
FAIL,
|
PASS,
|
||||||
empty,
|
IRI("foo", "bar.com", "", "", "", ""),
|
||||||
"conversion and checking are done in the correct order");
|
"conversion and checking are done in the correct order");
|
||||||
TEST("foo://bar.com/foo%00?baz",
|
TEST("foo://bar.com/foo%00?baz",
|
||||||
FAIL,
|
FAIL,
|
||||||
|
@ -272,7 +280,7 @@ main(void)
|
||||||
"rejects %00");
|
"rejects %00");
|
||||||
|
|
||||||
/* IRI */
|
/* IRI */
|
||||||
TEST("foo://bar.com/cafè.gmi",
|
TEST("foo://bar.com/cafè.gmi",
|
||||||
PASS,
|
PASS,
|
||||||
IRI("foo", "bar.com", "", "cafè.gmi", "" , ""),
|
IRI("foo", "bar.com", "", "cafè.gmi", "" , ""),
|
||||||
"decode IRI (with a 2-byte utf8 seq)");
|
"decode IRI (with a 2-byte utf8 seq)");
|
||||||
|
|
|
@ -6,9 +6,12 @@ gemexp="./../gemexp"
|
||||||
gg="./../gg"
|
gg="./../gg"
|
||||||
gmid="./../gmid"
|
gmid="./../gmid"
|
||||||
current_test=
|
current_test=
|
||||||
|
server_name=
|
||||||
|
gghost=
|
||||||
|
|
||||||
run_test() {
|
run_test() {
|
||||||
ggflags=
|
ggflags=
|
||||||
|
host="$REGRESS_HOST"
|
||||||
port=10965
|
port=10965
|
||||||
config_common="log syslog off"
|
config_common="log syslog off"
|
||||||
hdr=
|
hdr=
|
||||||
|
@ -18,9 +21,15 @@ run_test() {
|
||||||
ran_no=$((ran_no + 1))
|
ran_no=$((ran_no + 1))
|
||||||
|
|
||||||
current_test=$1
|
current_test=$1
|
||||||
|
server_name=localhost
|
||||||
|
gghost=localhost
|
||||||
|
|
||||||
rm -f reg.conf
|
rm -f reg.conf
|
||||||
|
|
||||||
if ! $1; then
|
if [ "$2" = "need_ipv6" -a "$HAVE_IPV6" != "yes" ]; then
|
||||||
|
echo "$1 skipped (needs HAVE_IPV6='yes')"
|
||||||
|
return
|
||||||
|
elif ! $1; then
|
||||||
echo "$1 failed"
|
echo "$1 failed"
|
||||||
failed="$failed $1"
|
failed="$failed $1"
|
||||||
failed_no=$((failed_no + 1))
|
failed_no=$((failed_no + 1))
|
||||||
|
@ -58,11 +67,11 @@ gen_config() {
|
||||||
cat <<EOF > reg.conf
|
cat <<EOF > reg.conf
|
||||||
$config_common
|
$config_common
|
||||||
$1
|
$1
|
||||||
server "localhost" {
|
server "$server_name" {
|
||||||
cert "$PWD/localhost.pem"
|
cert "$PWD/localhost.pem"
|
||||||
key "$PWD/localhost.key"
|
key "$PWD/localhost.key"
|
||||||
root "$PWD/testdata"
|
root "$PWD/testdata"
|
||||||
listen on $REGRESS_HOST port $port
|
listen on $host port $port
|
||||||
$2
|
$2
|
||||||
}
|
}
|
||||||
EOF
|
EOF
|
||||||
|
@ -77,7 +86,7 @@ set_proxy() {
|
||||||
server "localhost.local" {
|
server "localhost.local" {
|
||||||
cert "$PWD/localhost.pem"
|
cert "$PWD/localhost.pem"
|
||||||
key "$PWD/localhost.key"
|
key "$PWD/localhost.key"
|
||||||
listen on $REGRESS_HOST port $port
|
listen on $host port $port
|
||||||
proxy {
|
proxy {
|
||||||
relay-to localhost port $port
|
relay-to localhost port $port
|
||||||
$1
|
$1
|
||||||
|
@ -108,13 +117,13 @@ setup_simple_test() {
|
||||||
# usage: get <path>
|
# usage: get <path>
|
||||||
# return the body of the request on stdout
|
# return the body of the request on stdout
|
||||||
get() {
|
get() {
|
||||||
$gg -T10 $ggflags "gemini://localhost:10965/$1" || true
|
$gg -q -T10 $ggflags "gemini://$gghost:10965/$1" || true
|
||||||
}
|
}
|
||||||
|
|
||||||
# usage: head <path>
|
# usage: head <path>
|
||||||
# return the meta response line on stdout
|
# return the meta response line on stdout
|
||||||
head() {
|
head() {
|
||||||
$gg -T10 -d header $ggflags "gemini://localhost:10965/$1" || true
|
$gg -q -T10 -d header $ggflags "gemini://$gghost:10965/$1" || true
|
||||||
}
|
}
|
||||||
|
|
||||||
# usage: fetch <path>
|
# usage: fetch <path>
|
||||||
|
|
|
@ -19,6 +19,11 @@ fi
|
||||||
# Run standalone unit tests.
|
# Run standalone unit tests.
|
||||||
run_test test_punycode
|
run_test test_punycode
|
||||||
run_test test_iri
|
run_test test_iri
|
||||||
|
run_test test_gg_n_flag
|
||||||
|
|
||||||
|
# Run configuration parsing tests.
|
||||||
|
run_test test_parse_comments_at_start
|
||||||
|
run_test test_dump_config
|
||||||
|
|
||||||
if [ "${SKIP_RUNTIME_TESTS:-0}" -eq 1 ]; then
|
if [ "${SKIP_RUNTIME_TESTS:-0}" -eq 1 ]; then
|
||||||
echo
|
echo
|
||||||
|
@ -52,6 +57,7 @@ run_test test_root_inside_location
|
||||||
run_test test_root_inside_location_with_redirect
|
run_test test_root_inside_location_with_redirect
|
||||||
run_test test_fastcgi
|
run_test test_fastcgi
|
||||||
run_test test_fastcgi_inside_location
|
run_test test_fastcgi_inside_location
|
||||||
|
run_test test_fastcgi_location_match
|
||||||
run_test test_fastcgi_deprecated_syntax
|
run_test test_fastcgi_deprecated_syntax
|
||||||
run_test test_macro_expansion
|
run_test test_macro_expansion
|
||||||
run_test test_proxy_relay_to
|
run_test test_proxy_relay_to
|
||||||
|
@ -59,9 +65,13 @@ run_test test_proxy_with_certs
|
||||||
# run_test test_unknown_host # XXX: breaks on some distro
|
# run_test test_unknown_host # XXX: breaks on some distro
|
||||||
run_test test_include_mime
|
run_test test_include_mime
|
||||||
run_test test_log_file
|
run_test test_log_file
|
||||||
|
run_test test_ipv4_addr
|
||||||
|
run_test test_ipv6_addr need_ipv6
|
||||||
|
run_test test_ipv6_server need_ipv6
|
||||||
|
|
||||||
# TODO: add test that uses only a TLSv1.2 or TLSv1.3
|
# TODO: add test that uses only a TLSv1.2 or TLSv1.3
|
||||||
# TODO: add a test that attempt to serve a non-regular file
|
# TODO: add a test that attempt to serve a non-regular file
|
||||||
# TODO: add a test where the index is not a regular file
|
# TODO: add a test where the index is not a regular file
|
||||||
|
# TODO: add a test that logs and uses a client cert
|
||||||
|
|
||||||
tests_done
|
tests_done
|
||||||
|
|
125
regress/tests.sh
125
regress/tests.sh
|
@ -8,6 +8,63 @@ test_iri() {
|
||||||
./iri_test
|
./iri_test
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test_gg_n_flag() {
|
||||||
|
dont_check_server_alive=yes
|
||||||
|
$gg -n gemini://omarpolo.com/ || return 1
|
||||||
|
|
||||||
|
# XXX this fails on macos in the CI, while in
|
||||||
|
# test_iri passes successfully. Unfortunately,
|
||||||
|
# I can't debug stuff on darwin (lacking hardware.)
|
||||||
|
#$gg -n "foo://bar.com/cafè.gmi" || return 1
|
||||||
|
|
||||||
|
$gg -n gemini://omarpolo.com/../ || return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
test_parse_comments_at_start() {
|
||||||
|
dont_check_server_alive=yes
|
||||||
|
|
||||||
|
cat <<EOF >reg.conf
|
||||||
|
# a comment
|
||||||
|
|
||||||
|
server "$server_name" {
|
||||||
|
cert "$PWD/localhost.pem"
|
||||||
|
key "$PWD/localhost.key"
|
||||||
|
root "$PWD/testdata"
|
||||||
|
listen on $host port $port
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
|
||||||
|
$gmid -n -c reg.conf >/dev/null
|
||||||
|
}
|
||||||
|
|
||||||
|
test_dump_config() {
|
||||||
|
dont_check_server_alive=yes
|
||||||
|
gen_config '' ''
|
||||||
|
|
||||||
|
exp="$(mktemp)"
|
||||||
|
got="$(mktemp)"
|
||||||
|
cat <<EOF >$exp
|
||||||
|
prefork 3
|
||||||
|
|
||||||
|
server "localhost" {
|
||||||
|
cert "$PWD/localhost.pem"
|
||||||
|
key "$PWD/localhost.key"
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
|
||||||
|
$gmid -nn -c reg.conf > $got 2>/dev/null
|
||||||
|
|
||||||
|
ret=0
|
||||||
|
if ! cmp -s "$exp" "$got"; then
|
||||||
|
echo "config differs!" >&2
|
||||||
|
diff -u "$exp" "$got" >&2
|
||||||
|
ret=1
|
||||||
|
fi
|
||||||
|
|
||||||
|
rm "$exp" "$got"
|
||||||
|
return $ret
|
||||||
|
}
|
||||||
|
|
||||||
test_gemexp() {
|
test_gemexp() {
|
||||||
dont_check_server_alive=yes
|
dont_check_server_alive=yes
|
||||||
|
|
||||||
|
@ -264,6 +321,35 @@ test_fastcgi_inside_location() {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test_fastcgi_location_match() {
|
||||||
|
./fcgi-test fcgi.sock &
|
||||||
|
fcgi_pid=$!
|
||||||
|
|
||||||
|
setup_simple_test 'prefork 1' '
|
||||||
|
location "/dir/*" {
|
||||||
|
fastcgi off
|
||||||
|
}
|
||||||
|
location "/*" {
|
||||||
|
fastcgi socket "'$PWD'/fcgi.sock"
|
||||||
|
}'
|
||||||
|
|
||||||
|
msg=$(printf "# hello from fastcgi!\nsome more content in the page...")
|
||||||
|
fetch /foo
|
||||||
|
if ! check_reply "20 text/gemini" "$msg"; then
|
||||||
|
kill $fcgi_pid
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
fetch /dir/foo.gmi
|
||||||
|
if ! check_reply "20 text/gemini" "# hello world"; then
|
||||||
|
kill $fcgi_pid
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
kill $fcgi_pid
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
test_fastcgi_deprecated_syntax() {
|
test_fastcgi_deprecated_syntax() {
|
||||||
./fcgi-test fcgi.sock &
|
./fcgi-test fcgi.sock &
|
||||||
fcgi_pid=$!
|
fcgi_pid=$!
|
||||||
|
@ -287,13 +373,15 @@ test_fastcgi_deprecated_syntax() {
|
||||||
test_macro_expansion() {
|
test_macro_expansion() {
|
||||||
cat <<EOF > reg.conf
|
cat <<EOF > reg.conf
|
||||||
pwd = "$PWD"
|
pwd = "$PWD"
|
||||||
|
common = "lang it; auto index on"
|
||||||
|
|
||||||
server "localhost" {
|
server "localhost" {
|
||||||
# the quoting of \$ is for sh
|
# the quoting of \$ is for sh
|
||||||
cert \$pwd "/localhost.pem"
|
cert \$pwd "/localhost.pem"
|
||||||
key \$pwd "/localhost.key"
|
key \$pwd "/localhost.key"
|
||||||
root \$pwd "/testdata"
|
root \$pwd "/testdata"
|
||||||
listen on $REGRESS_HOST port $port
|
listen on $host port $port
|
||||||
|
@common
|
||||||
}
|
}
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
|
@ -305,7 +393,7 @@ EOF
|
||||||
run
|
run
|
||||||
|
|
||||||
fetch /
|
fetch /
|
||||||
check_reply "20 text/gemini" "# hello world"
|
check_reply "20 text/gemini;lang=it" "# hello world"
|
||||||
}
|
}
|
||||||
|
|
||||||
test_proxy_relay_to() {
|
test_proxy_relay_to() {
|
||||||
|
@ -400,3 +488,36 @@ log style legacy'
|
||||||
rm -f log log.edited
|
rm -f log log.edited
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test_ipv4_addr() {
|
||||||
|
server_name="*"
|
||||||
|
host="127.0.0.1"
|
||||||
|
gghost=127.0.0.1
|
||||||
|
ggflags=-N
|
||||||
|
setup_simple_test
|
||||||
|
|
||||||
|
fetch /
|
||||||
|
check_reply "20 text/gemini" "# hello world" || return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
test_ipv6_addr() {
|
||||||
|
server_name="*"
|
||||||
|
host="::1"
|
||||||
|
gghost="[::1]"
|
||||||
|
ggflags=-N
|
||||||
|
setup_simple_test
|
||||||
|
|
||||||
|
fetch /
|
||||||
|
check_reply "20 text/gemini" "# hello world" || return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
test_ipv6_server() {
|
||||||
|
server_name="::1"
|
||||||
|
host="::1"
|
||||||
|
gghost="[::1]"
|
||||||
|
ggflags=-N
|
||||||
|
setup_simple_test
|
||||||
|
|
||||||
|
fetch /
|
||||||
|
check_reply "20 text/gemini" "# hello world" || return 1
|
||||||
|
}
|
||||||
|
|
68
server.c
68
server.c
|
@ -31,7 +31,7 @@
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "proc.h"
|
#include "proc.h"
|
||||||
|
|
||||||
#define MIN(a, b) ((a) < (b) ? (a) : (b))
|
#define MINIMUM(a, b) ((a) < (b) ? (a) : (b))
|
||||||
|
|
||||||
#ifndef nitems
|
#ifndef nitems
|
||||||
#define nitems(_a) (sizeof((_a)) / sizeof((_a)[0]))
|
#define nitems(_a) (sizeof((_a)) / sizeof((_a)[0]))
|
||||||
|
@ -119,6 +119,15 @@ match_host(struct vhost *v, struct client *c)
|
||||||
if (addr == NULL)
|
if (addr == NULL)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
if (*c->domain == '\0') {
|
||||||
|
if (strlcpy(c->domain, addr->pp, sizeof(c->domain))
|
||||||
|
>= sizeof(c->domain)) {
|
||||||
|
log_warnx("%s: domain too long: %s", __func__,
|
||||||
|
addr->pp);
|
||||||
|
*c->domain = '\0';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (matches(v->domain, c->domain))
|
if (matches(v->domain, c->domain))
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
|
@ -246,7 +255,6 @@ struct location *
|
||||||
vhost_fastcgi(struct vhost *v, const char *path)
|
vhost_fastcgi(struct vhost *v, const char *path)
|
||||||
{
|
{
|
||||||
struct location *loc;
|
struct location *loc;
|
||||||
int force_disable = 0;
|
|
||||||
|
|
||||||
if (v == NULL || path == NULL)
|
if (v == NULL || path == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -257,12 +265,9 @@ vhost_fastcgi(struct vhost *v, const char *path)
|
||||||
if (matches(loc->match, path))
|
if (matches(loc->match, path))
|
||||||
return loc;
|
return loc;
|
||||||
if (loc->nofcgi && matches(loc->match, path))
|
if (loc->nofcgi && matches(loc->match, path))
|
||||||
force_disable = 1;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (force_disable)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
loc = TAILQ_FIRST(&v->locations);
|
loc = TAILQ_FIRST(&v->locations);
|
||||||
return loc->fcgi == -1 ? NULL : loc;
|
return loc->fcgi == -1 ? NULL : loc;
|
||||||
}
|
}
|
||||||
|
@ -385,7 +390,7 @@ handle_handshake(int fd, short ev, void *d)
|
||||||
return;
|
return;
|
||||||
default:
|
default:
|
||||||
/* unreachable */
|
/* unreachable */
|
||||||
abort();
|
fatalx("unexpected return value from tls_handshake");
|
||||||
}
|
}
|
||||||
|
|
||||||
c->bev = bufferevent_new(fd, client_read, client_write,
|
c->bev = bufferevent_new(fd, client_read, client_write,
|
||||||
|
@ -403,16 +408,19 @@ handle_handshake(int fd, short ev, void *d)
|
||||||
evbuffer_unfreeze(c->bev->output, 1);
|
evbuffer_unfreeze(c->bev->output, 1);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if ((servname = tls_conn_servername(c->ctx)) == NULL) {
|
if ((servname = tls_conn_servername(c->ctx)) == NULL)
|
||||||
log_debug("handshake: missing SNI");
|
log_debug("handshake: missing SNI");
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!puny_decode(servname, c->domain, sizeof(c->domain), &parse_err)) {
|
if (!puny_decode(servname, c->domain, sizeof(c->domain), &parse_err)) {
|
||||||
log_info("puny_decode: %s", parse_err);
|
log_info("puny_decode: %s", parse_err);
|
||||||
goto err;
|
start_reply(c, BAD_REQUEST, "Wrong/malformed host");
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* match_addr will serialize the (matching) address if c->domain
|
||||||
|
* is empty, so that we can support requests for raw IPv6 address
|
||||||
|
* that can't have a SNI.
|
||||||
|
*/
|
||||||
TAILQ_FOREACH(h, &conf->hosts, vhosts)
|
TAILQ_FOREACH(h, &conf->hosts, vhosts)
|
||||||
if (match_host(h, c))
|
if (match_host(h, c))
|
||||||
break;
|
break;
|
||||||
|
@ -428,8 +436,7 @@ handle_handshake(int fd, short ev, void *d)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
err:
|
start_reply(c, BAD_REQUEST, "Wrong/malformed host");
|
||||||
start_reply(c, BAD_REQUEST, "Wrong/malformed host or missing SNI");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -607,8 +614,7 @@ apply_reverse_proxy(struct client *c)
|
||||||
if (p->reqca != NULL && check_matching_certificate(p->reqca, c))
|
if (p->reqca != NULL && check_matching_certificate(p->reqca, c))
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
log_debug("opening proxy connection for %s:%s",
|
log_debug("opening proxy connection for %s:%s", p->host, p->port);
|
||||||
p->host, p->port);
|
|
||||||
|
|
||||||
if ((c->pfd = proxy_socket(c, p->host, p->port)) == -1) {
|
if ((c->pfd = proxy_socket(c, p->host, p->port)) == -1) {
|
||||||
start_reply(c, PROXY_ERROR, "proxy error");
|
start_reply(c, PROXY_ERROR, "proxy error");
|
||||||
|
@ -712,8 +718,7 @@ apply_fastcgi(struct client *c)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
log_debug("opening fastcgi connection for (%s,%s)",
|
log_debug("opening fastcgi connection for (%s,%s)", f->path, f->port);
|
||||||
f->path, f->port);
|
|
||||||
|
|
||||||
if (*f->port == '\0')
|
if (*f->port == '\0')
|
||||||
c->pfd = fcgi_open_sock(f);
|
c->pfd = fcgi_open_sock(f);
|
||||||
|
@ -812,8 +817,7 @@ open_dir(struct client *c)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
strlcpy(path, c->iri.path, sizeof(path));
|
snprintf(path, sizeof(path), "%s%s", c->iri.path, index);
|
||||||
strlcat(path, index, sizeof(path));
|
|
||||||
|
|
||||||
close(c->pfd);
|
close(c->pfd);
|
||||||
c->pfd = fd;
|
c->pfd = fd;
|
||||||
|
@ -853,7 +857,7 @@ client_tls_readcb(int fd, short event, void *d)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bufev->wm_read.high != 0)
|
if (bufev->wm_read.high != 0)
|
||||||
howmuch = MIN(sizeof(buf), bufev->wm_read.high);
|
howmuch = MINIMUM(sizeof(buf), bufev->wm_read.high);
|
||||||
|
|
||||||
switch (ret = tls_read(client->ctx, buf, howmuch)) {
|
switch (ret = tls_read(client->ctx, buf, howmuch)) {
|
||||||
case TLS_WANT_POLLIN:
|
case TLS_WANT_POLLIN:
|
||||||
|
@ -951,6 +955,8 @@ client_read(struct bufferevent *bev, void *d)
|
||||||
struct evbuffer *src = EVBUFFER_INPUT(bev);
|
struct evbuffer *src = EVBUFFER_INPUT(bev);
|
||||||
const char *path, *p, *parse_err = "invalid request";
|
const char *path, *p, *parse_err = "invalid request";
|
||||||
char decoded[DOMAIN_NAME_LEN];
|
char decoded[DOMAIN_NAME_LEN];
|
||||||
|
char *nul;
|
||||||
|
size_t len;
|
||||||
|
|
||||||
bufferevent_disable(bev, EVBUFFER_READ);
|
bufferevent_disable(bev, EVBUFFER_READ);
|
||||||
|
|
||||||
|
@ -981,6 +987,14 @@ client_read(struct bufferevent *bev, void *d)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nul = strchr(c->req, '\0');
|
||||||
|
len = nul - c->req;
|
||||||
|
if (len != c->reqlen) {
|
||||||
|
log_debug("NUL inside the request IRI");
|
||||||
|
start_reply(c, BAD_REQUEST, "bad request");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!parse_iri(c->req, &c->iri, &parse_err) ||
|
if (!parse_iri(c->req, &c->iri, &parse_err) ||
|
||||||
!puny_decode(c->iri.host, decoded, sizeof(decoded), &parse_err)) {
|
!puny_decode(c->iri.host, decoded, sizeof(decoded), &parse_err)) {
|
||||||
log_debug("IRI parse error: %s", parse_err);
|
log_debug("IRI parse error: %s", parse_err);
|
||||||
|
@ -1294,7 +1308,8 @@ server_accept(int sock, short et, void *d)
|
||||||
if (errno == EWOULDBLOCK || errno == EAGAIN ||
|
if (errno == EWOULDBLOCK || errno == EAGAIN ||
|
||||||
errno == ECONNABORTED)
|
errno == ECONNABORTED)
|
||||||
return;
|
return;
|
||||||
fatal("accept");
|
log_warnx("accept failed");
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
mark_nonblock(fd);
|
mark_nonblock(fd);
|
||||||
|
@ -1329,15 +1344,6 @@ server_accept(int sock, short et, void *d)
|
||||||
connected_clients++;
|
connected_clients++;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct client *
|
|
||||||
client_by_id(int id)
|
|
||||||
{
|
|
||||||
struct client find;
|
|
||||||
|
|
||||||
find.id = id;
|
|
||||||
return SPLAY_FIND(client_tree_id, &clients, &find);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
handle_siginfo(int fd, short ev, void *d)
|
handle_siginfo(int fd, short ev, void *d)
|
||||||
{
|
{
|
||||||
|
|
|
@ -21,7 +21,7 @@ REPOLOGY_URL = https://repology.org/project/gmid/versions
|
||||||
|
|
||||||
SUBST = ./subst GITHUB=https://github.com/omar-polo/gmid \
|
SUBST = ./subst GITHUB=https://github.com/omar-polo/gmid \
|
||||||
SITE=https://ftp.omarpolo.com \
|
SITE=https://ftp.omarpolo.com \
|
||||||
VERS=2.0.1 \
|
VERS=2.0.5 \
|
||||||
PUBKEY=gmid-2.0.pub \
|
PUBKEY=gmid-2.0.pub \
|
||||||
TREE=https://github.com/omar-polo/gmid/blob/master
|
TREE=https://github.com/omar-polo/gmid/blob/master
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,35 @@
|
||||||
# change log
|
# change log
|
||||||
|
|
||||||
|
## 2024/06/11 - 2.0.5 “Lady Stardust” security release
|
||||||
|
|
||||||
|
This release fixes a logic error that can result in a DoS; therefore is a strongly reccomended update for all users. It's safe to update to it from any version of the 2.0.x series.
|
||||||
|
|
||||||
|
* allow again empty lines at the start of the configuration file
|
||||||
|
* change how strnvis(3) is handled: on systems with the broken interface gmid will just use its own built-in version
|
||||||
|
* reject requests with NUL bytes in them.
|
||||||
|
* don't error on a '..' component at the start of the path.
|
||||||
|
|
||||||
|
## 2024/06/06 - 2.0.4 “Lady Stardust” bugfix release
|
||||||
|
|
||||||
|
* add a nicer error message if the removed `cgi' option is still used. Reported by freezr.
|
||||||
|
* portability fix for systems with a wrong strnvis(3).
|
||||||
|
|
||||||
|
## 2024/06/04 - 2.0.3 “Lady Stardust” bugfix release
|
||||||
|
|
||||||
|
* relax the SNI requirements
|
||||||
|
* gg: add -q to avoid printing the "Server Says:" line
|
||||||
|
* gg: unbreak -n
|
||||||
|
* fix parsing of IPv6 addresses
|
||||||
|
* fix `fastcgi off' handling
|
||||||
|
|
||||||
|
## 2024/04/04 - 2.0.2 “Lady Stardust” bugfix release
|
||||||
|
|
||||||
|
* fix `log access path' with `chroot' enabled.
|
||||||
|
* fix config dumping (-nn).
|
||||||
|
* rework grammar to allow semicolons after top-level statements.
|
||||||
|
* don't make the log styles reserved keywords.
|
||||||
|
* contrib/vim: fixed indent, from Anna “CyberTailor”, thanks!
|
||||||
|
|
||||||
## 2024/01/24 - 2.0.1 “Lady Stardust” bugfix release
|
## 2024/01/24 - 2.0.1 “Lady Stardust” bugfix release
|
||||||
|
|
||||||
* convert gmid to the new imsg API
|
* convert gmid to the new imsg API
|
||||||
|
|
3
utils.c
3
utils.c
|
@ -22,6 +22,7 @@
|
||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <vis.h> /* for gmid_strnvis() */
|
||||||
|
|
||||||
#include <openssl/ec.h>
|
#include <openssl/ec.h>
|
||||||
#include <openssl/err.h>
|
#include <openssl/err.h>
|
||||||
|
@ -247,7 +248,7 @@ gencert(const char *hostname, const char *certpath, const char *keypath,
|
||||||
ASN1_INTEGER_set(X509_get_serialNumber(x509), 0);
|
ASN1_INTEGER_set(X509_get_serialNumber(x509), 0);
|
||||||
X509_gmtime_adj(X509_get_notBefore(x509), 0);
|
X509_gmtime_adj(X509_get_notBefore(x509), 0);
|
||||||
X509_gmtime_adj(X509_get_notAfter(x509), 315360000L); /* 10 years */
|
X509_gmtime_adj(X509_get_notAfter(x509), 315360000L); /* 10 years */
|
||||||
X509_set_version(x509, 2); // v3
|
X509_set_version(x509, 2); /* v3 */
|
||||||
|
|
||||||
if (!X509_set_pubkey(x509, pkey)) {
|
if (!X509_set_pubkey(x509, pkey)) {
|
||||||
log_warnx("couldn't set the public key");
|
log_warnx("couldn't set the public key");
|
||||||
|
|
Loading…
Reference in New Issue