diff options
author | Glenn Strauss <gstrauss@gluelogic.com> | 2020-06-11 22:12:32 -0400 |
---|---|---|
committer | Glenn Strauss <gstrauss@gluelogic.com> | 2020-07-08 22:51:32 -0400 |
commit | 6bf0b577876b3e6d5e84239c8c134d436ed29b1b (patch) | |
tree | 95f47b78430d343f71e48ef5c0f49d7aa97bad6a | |
parent | 1a02cd7e33fd188af8596c4ff45483a224209349 (diff) | |
download | lighttpd-git-6bf0b577876b3e6d5e84239c8c134d436ed29b1b.tar.gz |
[mod_webdav] unsafe-propfind-follow-symlink option
webdav.opts = ("unsafe-propfind-follow-symlink" => "enable")
This option is unsafe and unsupported. This option enables non-standard
behavior. If it works for you, great. If it does not work for you,
then too bad.
WebDAV resource and collection concepts do not have an equivalence
to unix symlinks. If "unsafe-propfind-follow-symlink" is "enable",
then lighttpd mod_webdav PROPFIND handling will follow symlinks
if and only if webdav.is_readonly = "enable" is also set.
Allowing symlinks is unsafe in the general case. Using WebDAV methods
to MOVE a relative symlink does not update the symlink relative target.
LOCK is on the resource (e.g. a symlink), not the target of the symlink.
COPY replaces the resource (e.g. a symlink), not the target of the
symlink. There are only a few examples of possibly many more reasons
why using symlinks in a WebDAV-writable collection is unsafe.
-rw-r--r-- | src/mod_webdav.c | 21 |
1 files changed, 19 insertions, 2 deletions
diff --git a/src/mod_webdav.c b/src/mod_webdav.c index a04cc345..53a3f83a 100644 --- a/src/mod_webdav.c +++ b/src/mod_webdav.c @@ -317,6 +317,7 @@ typedef struct { enum { /* opts bitflags */ MOD_WEBDAV_UNSAFE_PARTIAL_PUT_COMPAT = 0x1 + ,MOD_WEBDAV_UNSAFE_PROPFIND_FOLLOW_SYMLINK = 0x2 }; typedef struct { @@ -498,6 +499,13 @@ SETDEFAULTS_FUNC(mod_webdav_set_defaults) { opts |= MOD_WEBDAV_UNSAFE_PARTIAL_PUT_COMPAT; continue; } + if (buffer_is_equal_string(&ds->key, + CONST_STR_LEN("unsafe-propfind-follow-symlink")) + && buffer_eq_slen(&ds->value, + CONST_STR_LEN("enable"))) { + opts |= MOD_WEBDAV_UNSAFE_PROPFIND_FOLLOW_SYMLINK; + continue; + } log_error(srv->errh, __FILE__, __LINE__, "unrecognized webdav.opts: %.*s", BUFFER_INTLEN_PTR(&ds->key)); @@ -2882,6 +2890,7 @@ typedef struct webdav_propfind_bufs { int lockdiscovery; int depth; int recursed; + int atflags; struct stat st; } webdav_propfind_bufs; @@ -3307,7 +3316,7 @@ webdav_propfind_dir (webdav_propfind_bufs * const restrict pb) || (de->d_name[1] == '.' && de->d_name[2] == '\0'))) continue; /* ignore "." and ".." */ - if (0 != fstatat(dfd, de->d_name, &pb->st, AT_SYMLINK_NOFOLLOW)) + if (0 != fstatat(dfd, de->d_name, &pb->st, pb->atflags)) continue; /* file *just* disappeared? */ const uint32_t len = (uint32_t) _D_EXACT_NAMLEN(de); @@ -3808,7 +3817,15 @@ mod_webdav_propfind (request_st * const r, const plugin_config * const pconf) return HANDLER_FINISHED; } - if (0 != lstat(r->physical.path.ptr, &pb.st)) { + pb.atflags = + ((pconf->opts & MOD_WEBDAV_UNSAFE_PROPFIND_FOLLOW_SYMLINK) + && pconf->is_readonly) + ? 0 /* non-standard */ + : AT_SYMLINK_NOFOLLOW; /* WebDAV does not have symlink concept */ + + if (pb.atflags == AT_SYMLINK_NOFOLLOW + ? 0 != lstat(r->physical.path.ptr, &pb.st) + : 0 != stat(r->physical.path.ptr, &pb.st)) { /* non-standard */ http_status_set_error(r, (errno == ENOENT) ? 404 : 403); return HANDLER_FINISHED; } |