Project

General

Profile

[Solved] lighttpd 1.4.71 Web_dav with symlinks support

Added by giuseppe.dibiase 12 months ago

I'm trying to configure lighttpd to support webdav export with symlink without success.
For example:
in /dav folder, under Document Root I have:

|-- file3.txt -> folder1/file1.txt |-- folder1 | |-- file1.txt | `-- file2.txt |-- folder2 |-- folder3 | `-- pippo.txt |-- folder4 > folder3
`-
test -> /opt/test

But when I mount it on a remote server o by "cadaver" application I obtain this error:

dav:/dav/> ls
Listing collection `/dav/': succeeded.
Coll: folder1 40 Jun 29 09:25
Coll: folder2 6 Jun 29 09:24
Coll: folder3 38 Jun 30 10:03
Coll: folder4 38 Jun 30 10:03
Coll: test 23 Jun 29 09:26
file3.txt 0 Jun 29 09:24

and here my error:

dav:/dav/> cd folder4
dav:/dav/folder4/> ls
Listing collection `/dav/folder4/': collection is empty.

I compiled with:
./configure -C --prefix=/usr/local --with-webdav-props --with-webdav-locks --with-sqlite

...without error
and modules/plugins envolved seem to be enabled:
Plugins:

enabled:
mod_access
mod_accesslog
mod_ajp13
mod_alias
mod_auth
mod_authn_file
mod_cgi
mod_deflate
mod_dirlisting
mod_evhost
mod_expire
mod_extforward
mod_fastcgi
mod_indexfile
mod_proxy
mod_redirect
mod_rewrite
mod_rrdtool
mod_scgi
mod_setenv
mod_simple_vhost
mod_sockproxy
mod_ssi
mod_staticfile
mod_status
mod_userdir
mod_vhostdb
mod_webdav
mod_wstunnel
disabled:
mod_authn_dbi
mod_authn_gssapi
mod_authn_ldap
mod_authn_pam
mod_gnutls
mod_magnet
mod_maxminddb
mod_mbedtls
mod_nss
mod_openssl
mod_vhostdb_dbi
mod_vhostdb_ldap
mod_vhostdb_mysql
mod_vhostdb_pgsql
mod_wolfssl

Features:

enabled:
auth-crypt
compress-deflate
compress-gzip
large-files
network-ipv6
regex-conditionals
stat-cache-inotify
webdav-locks
webdav-properties
disabled:
compress-brotli
compress-bzip2
compress-zstd
dbi
kerberos
ldap
lua
maxminddb
mysql
network-gnutls
network-mbedtls
network-nss
network-openssl
network-wolfssl
pam
postgresql

Below the part of lighttpd.conf regarding /webdav:

$HTTP["host"] == "***" {
var.server_name = "***"
server.name = server_name

server.document-root = "/var/www/html/htdocs"
alias.url                 = ( "/dav" => "/var/www/html/htdocs/dav" )
$HTTP["url"] =~ "^/dav($|/)" {
dir-listing.activate = "enable"
dir-listing.encoding = "utf-8"
webdav.activate = "enable"
webdav.opts += ("unsafe-propfind-follow-symlink" => "enable")
webdav.opts += ("propfind-depth-infinity" => "enable")
webdav.is-readonly = "enable"
}
}

My question is: Has someone been able to get symlinks to work within a folder exported via webdav using lighttd?

Thank you all for your support.


Replies (8)

RE: lighttpd 1.4.71 Web_dav with symlinks support - Added by gstrauss 12 months ago

lighttpd -f /etc/lighttpd/lighttpd.conf -p and verify that you have isolated your webdav config, and that the webdav directives are not being modified by some other part of your config file.

Try webdav.log-xml = "enable" and review what cadaver is sending in PROPFIND requests, and how lighttpd is responding.

Have you tested a different DAV client for comparison?

RE: lighttpd 1.4.71 Web_dav with symlinks support - Added by gstrauss 12 months ago

An strace of lighttpd might also be useful to see the arguments and return value for fstatat().

RE: lighttpd 1.4.71 Web_dav with symlinks support - Added by giuseppe.dibiase 12 months ago

Thank for your reply.

this is the output of lighttpd -f /etc/lighttpd/lighttpd.conf -p :

config {
var.CWD = "/usr/local/src/lighttpd-1.4.71"
var.PID = 10586
var.log_root = "/var/log/lighttpd"
var.server_root = "/var/www/html"
var.state_dir = "/run"
var.home_dir = "/var/lib/lighttpd"
var.conf_dir = "/etc/lighttpd"
var.vhosts_dir = "/var/www/html/vhosts"
var.cache_dir = "/var/cache/lighttpd"
var.socket_dir = "/var/lib/lighttpd/sockets"
server.port = 88
server.username = "lighttpd"
server.groupname = "lighttpd"
server.document-root = "/var/www/html/htdocs"
server.pid-file = "/run/lighttpd.pid"
server.errorlog = "/var/log/lighttpd/error.log"
server.follow-symlink = "disable"
accesslog.filename = "/var/log/lighttpd/access.log"
debug.log-request-handling = "enable"
debug.log-request-header = "enable"
debug.log-request-header-on-error = "enable"
debug.log-response-header = "enable"
debug.log-file-not-found = "enable"
debug.log-condition-handling = "enable"
server.max-fds = 16384
index-file.names = ("index.xhtml", "index.html", "index.htm", "default.htm", "index.php")
url.access-deny = ("~", ".inc")
static-file.exclude-extensions = (".php", ".pl", ".fcgi", ".scgi")
server.modules = (
"mod_accesslog",
"mod_rewrite",
"mod_access",
"mod_auth",
"mod_webdav",
"mod_authn_file",
"mod_alias",
)

$HTTP["host"] == "***" {
    # block 1
var.server_name = "***"
server.name = "***"
server.document-root = "/var/www/html/htdocs"
alias.url = (
"/dav" => "/var/www/html/htdocs/dav",
)
$HTTP["url"] =~ "^/dav($|/)" {
    # block 2
dir-listing.activate = "enable"
dir-listing.encoding = "utf-8"
webdav.activate = "enable"
webdav.opts = (
"unsafe-propfind-follow-symlink" => "enable",
"propfind-depth-infinity" => "enable",
)
webdav.is-readonly = "enable"
webdav.log-xml = "enable"
webdav.sqlite-db-name = "/var/lib/lighttpd/webdav.db"
} # end of $HTTP["url"] =~ "^/dav($|/)" 
} # end of $HTTP["host"] "***"
}

And it seems ok.

But now in error.log I see these entries when I try a list of content (ls folder4):

2023-06-30 14:52:16: (h1.c.497) fd:12 rqst: PROPFIND /dav/folder4/ HTTP/1.1
2023-06-30 14:52:16: (h1.c.497) fd:12 rqst: User-Agent: cadaver/0.23.3 neon/0.30.0
2023-06-30 14:52:16: (h1.c.497) fd:12 rqst: Connection: TE
2023-06-30 14:52:16: (h1.c.497) fd:12 rqst: TE: trailers
2023-06-30 14:52:16: (h1.c.497) fd:12 rqst: Host: webonline.virgo-gw.eu:88
2023-06-30 14:52:16: (h1.c.497) fd:12 rqst: Depth: 1
2023-06-30 14:52:16: (h1.c.497) fd:12 rqst: Content-Length: 288
2023-06-30 14:52:16: (h1.c.497) fd:12 rqst: Content-Type: application/xml
2023-06-30 14:52:16: (h1.c.497) fd:12 rqst:
2023-06-30 14:52:16: (configfile-glue.c.600) = start of condition block ===
2023-06-30 14:52:16: (configfile-glue.c.531) $HTTP["host"] "***" compare to
2023-06-30 14:52:16: (configfile-glue.c.388) 1 (uncached) result: true (cond: global / $HTTP["host"] "
")
2023-06-30 14:52:16: (response.c.260) -- parsed Request-URI
2023-06-30 14:52:16: (response.c.262) Request-URI : /dav/folder4/
2023-06-30 14:52:16: (response.c.264) URI-scheme : http
2023-06-30 14:52:16: (response.c.266) URI-authority :
2023-06-30 14:52:16: (response.c.268) URI-path (clean): /dav/folder4/
2023-06-30 14:52:16: (response.c.270) URI-query :
2023-06-30 14:52:16: (configfile-glue.c.600) === start of condition block ===
2023-06-30 14:52:16: (configfile-glue.c.422) go parent global / $HTTP["host"] "
"
2023-06-30 14:52:16: (configfile-glue.c.388) 1 (cached) result: true (cond: global / $HTTP["host"] "***")
2023-06-30 14:52:16: (configfile-glue.c.531) $HTTP["url"] =~ "^/dav($|/)" compare to /dav/folder4/
2023-06-30 14:52:16: (configfile-glue.c.388) 2 (uncached) result: true (cond: global / $HTTP["host"] == "***" / $HTTP["url"] =~ "^/dav($|/)")
2023-06-30 14:52:16: (mod_webdav.c.3887) XML-request-body: \n<propfind xmlns="DAV:"><prop>\n<getcontentlength xmlns="DAV:"/>\n<getlastmodified xmlns="DAV:"/>\n<executable xmlns="http://apache.org/dav/props/&quot;/&gt;\n&lt;resourcetype xmlns="DAV:"/>\n<checked-in xmlns="DAV:"/>\n<checked-out xmlns="DAV:"/>\n</prop></propfind>\n
2023-06-30 14:52:16: (mod_webdav.c.795) XML-response-body: \n<D:multistatus xmlns:D="DAV:" xmlns:ns0="urn:uuid:c2f41010-65b3-11d1-a29f-00aa00c14882/">\n<D:response>\n<D:href>/dav/folder4/</D:href>\n<D:propstat>\n<D:status>HTTP/1.1 403 Forbidden</D:status>\n</D:propstat>\n</D:response>\n</D:multistatus>\n
2023-06-30 14:52:16: (h1.c.248) fd:12 resp: HTTP/1.1 207 Multi-status
2023-06-30 14:52:16: (h1.c.248) fd:12 resp: Content-Type: application/xml;charset=utf-8
2023-06-30 14:52:16: (h1.c.248) fd:12 resp: Content-Length: 275
2023-06-30 14:52:16: (h1.c.248) fd:12 resp: Date: Fri, 30 Jun 2023 12:52:16 GMT
2023-06-30 14:52:16: (h1.c.248) fd:12 resp: Server: lighttpd/1.4.71
2023-06-30 14:52:16: (h1.c.248) fd:12 resp:
2023-06-30 14:52:22: (h1.c.881) connection closed - keep-alive timeout: 12

Where I can see now:

2023-06-30 14:52:16: (mod_webdav.c.795) XML-response-body: \n<D:multistatus xmlns:D="DAV:" xmlns:ns0="urn:uuid:c2f41010-65b3-11d1-a29f-00aa00c14882/">\n<D:response>\n<D:href>/dav/folder4/</D:href>\n<D:propstat>\n<D:status>HTTP/1.1 403 Forbidden</D:status>\n</D:propstat>\n</D:response>\n</D:multistatus>\n

but I cannot understand what it means.

And yes I tried also with a simple mount davfs2 on a remote server: mount -t davfs http://***/dav /basemnt/lighttpd -o ro,_netdev,uid=apache,gid=apache

and when I ls folder4... it is empty.

Thanks for your help.

RE: lighttpd 1.4.71 Web_dav with symlinks support - Added by gstrauss 12 months ago

Your config contains:
server.follow-symlink = "disable"

Why would you do this?

RE: lighttpd 1.4.71 Web_dav with symlinks support - Added by giuseppe.dibiase 12 months ago

Ok, you are right. It's only an attempt to see if something change... even if changing it to server.follow-symlink = "enable" the issue remain.

Very strange.

Thanks

RE: lighttpd 1.4.71 Web_dav with symlinks support - Added by cortese 12 months ago

I found a way to make it work.

In mod_webdav.c in the function webdav_propfind_dir() the line:

const int dfd = fdevent_open_dirname(dst->path.ptr, 0)

opens the directory with the second argument "symlink" set 0 which I understand tells to "NOT" follow the symbolic links even if the proper workaraund options are chosen in the configuration.

changing the line setting the flag to 1:

const int dfd = fdevent_open_dirname(dst->path.ptr, 1)

solves the problem and the directories are now populated in cadaver.

I don't know whether this could cause side effects in the general case, but it seems not for us since our use case requires to use webdav just in readonly.

RE: lighttpd 1.4.71 Web_dav with symlinks support - Added by gstrauss 12 months ago

Thanks for digging in.

When I saw server.follow-symlink = "disable" in the config, I knew that was probably at least one issue.

Now that it is removed, you identified in webdav_propfind_dir():
const int dfd = fdevent_open_dirname(dst->path.ptr, 0);

Perhaps in webdav_propfind_dir() that should be
const int dfd = fdevent_open_dirname(dst->path.ptr, (pb->atflags != AT_SYMLINK_NOFOLLOW));

I need to do some testing and to check the git source history to see if there was specific reason for that, but at first glance this patch looks ok to me.

reference: in mod_webdav_propfind

    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 */

    (1-8/8)