summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGlenn Strauss <gstrauss@gluelogic.com>2020-06-11 22:12:32 -0400
committerGlenn Strauss <gstrauss@gluelogic.com>2020-07-08 22:51:32 -0400
commit6bf0b577876b3e6d5e84239c8c134d436ed29b1b (patch)
tree95f47b78430d343f71e48ef5c0f49d7aa97bad6a
parent1a02cd7e33fd188af8596c4ff45483a224209349 (diff)
downloadlighttpd-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.c21
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;
}