Giter Site home page Giter Site logo

webdav-server-rs's Introduction

WEBDAV-SERVER

An implementation of a webdav server with support for user accounts, and switching uid/gid to those users accounts. That last feature is Linux-only, since the server is threaded and no other OSes have support for thread-local credentials.

Uses PAM authentication and local unix accounts.

This server does not implement logging. For now, it is assumed that most users of this software want to put an NGNIX or Apache reverse-proxy in front of it anyway, and that frontend can implement TLS, logging, enforcing a maximum number of connections, and timeouts.

This crate uses futures 0.3 and async/await, so the minimum rust compiler version is 1.39.

Features.

  • RFC4918: webdav, full support
  • RFC4331: webdav quota support (linux quota, NFS quota, statfs)
  • locking support (fake locking, enough for macOS and Windows clients)
  • can be case insensitive for Windows clients
  • files starting with a dot get the HIDDEN attribute on windows
  • optimizations for macOS (spotlight indexing disabled, thumbnail previews disabled, some light directory caching for ._ files)
  • partial put support
  • tested with Windows, macOS, Linux clients

Building.

By default the server builds with pam and quota support. If your OS does not support these one of features, use cargo command line options to disable all features and enable only the ones your OS supports.

For example, to build on OpenBSD, which does not have pam:

cargo build --release --no-default-features --features=quota

Configuration.

See the example webdav-server.toml file

There is also an example nginx proxy configuration.

Notes.

The built-in PAM client will add the client IP address to PAM requests. If the client IP adress is localhost (127/8 or ::1) then the content of the X-Forwarded-For header is used instead (if present) to allow for aforementioned frontend proxies.

Copyright and License.

webdav-server-rs's People

Contributors

mgottschlag avatar miquels avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

webdav-server-rs's Issues

[Question] Compile for an old nas ARM+2.6 kernel

Hi,

I compile webdav-server-rs with "armv5te-unknown-linux-musleabi" target.
I am pretty happy when I run "./webdav-server --help" on my old nas and I saw the help message.
However, when I try to run the server with my configuration, I get this message :

Error: Os { code: 38, kind: Unsupported, message: "Function not implemented" }

I think my kernel is too old, maybe my compilation options are not correct.

Any idea about cross compiling webdav-server for an old server with 2.6 kernel ?

Thanks

Unsatisifiable requirement

There are no docs how to install this and Cargo just fails:

webdav-handler = { path = "../webdav-handler-rs", version = "=0.2.0-alpha.4" }

Troublesome Windows 10 Clients

I have many troubles connecting with a Windows 10 Explorer client to a Linux server. From the Readme, this should work?
If you have tested this, maybe you could share a working configuration / way of setting up a Windows 10 client?

Both client and server seem to eventually crash. I tried “add network location”, “map network drive”, but the most stable way seems to be to use the command line like this:

net use Z: https://example.org/Share /user:username *

While displaying and reading from an anonymously-readble share seems to work, if I try to write to a share, Explorer crashes.
If I connect to a drive that requires authentication, I get a “Network path is not found”.

On the server part, individual tokio threads crash with this message:

webdav-server: thread 'tokio-runtime-worker' panicked at 'already mutably borrowed: BorrowError', /build/rustc-1.45.2-src/src/libcore/cell.rs:797:9
nginx: *1544 upstream prematurely closed connection while reading response header from upstream, server: example.org, request: "PROPFIND /Share HTTP/2.0", upstream: "http://[::1]:4918/Share", host: "example.org"

I know that this information is not enough for debugging, I'm mainly asking for one way that works for someone else that I can try to reproduce, and then see what's different from that what I am trying.

Thank you for this piece of software, KDE/Plasma with Dolphin and MacOS Finder works very well, and especially with Finder I never was able to get samba working!

Feature?: User mapping

Thanks for creating this nice piece of software. Maybe I'm too dumb to configure this correctly, but it seems to me I'm missing a few bits to replace my current nginx (mod dav) setup.

At the moment I'm mapping usernames to foldernames. E.g. if mike logs in, he sees the folder pictures, but it's mapped to the folder pictures_mike - same for user peter who sees pictures as well, but will be served pictures_peter. As stated in the example config, only the path variable is considered for the path, so neither can't I create a per-user folder and map the user folders in there nor can I incorporate the username in the foldername to serve.

Am I missing something?

Debian packaging

This looks like a great tool - please consider packaging it officially for Debian :-)

only insecure htpasswd passwords supported

htpasswd files like generated from apache is not properly supported.
The format is:

test:{SHA}Or7xoUzOzSDWzoksvgQq5tdJRsg=

{SHA} is the hashing algorithmus used, can be MD5, SHA, without, the CRYPT function is used.

htpasswd --help
....
 -m  Force MD5 encryption of the password (default).
 -B  Force bcrypt encryption of the password (very secure).
 -C  Set the computing time used for the bcrypt algorithm
     (higher is more secure but slower, default: 5, valid: 4 to 17).
 -d  Force CRYPT encryption of the password (8 chars max, insecure).
 -s  Force SHA encryption of the password (insecure).

Currently, the server uses verify() which does not properly detect anything but crypt, rendering the file unsecure.

Failed to work with NFS4ACL's group rules

read_dir Forbidden if the user isn't its owner. (with setuid=true). It's strange.
I'm using TrueNAS-SCALE-22.12.3.3, the acl of my folder is:

  • root: full control
  • group Foo: read-only

And the user Test is in the group Foo.

But it showed that "read_dir Forbidden" unless I changed the owner of my folder to user Test.

Support for setuid with supplementary groups

I've configured my webdav-server-rs like this to allow authenticated access to user homes:

[[location]]
  route = [ "/*path" ]
  methods = [ "webdav-rw" ]
  auth = "true"
  handler = "filesystem"
  on_notfound = "return"
  setuid = true
  directory = "~"
  autoindex = false
  hide-symlinks = false
  case-insensitive = "false"

This works well, with one exception: the users have symlinks to the groups they're in in a subfolder "Groups":

martin.mein-iserv.de /home/martin/Groups # ll
insgesamt 0
lrwxrwxrwx 1 root martin 19 Feb 20  2020  Admins -> /group/admins/Files/
lrwxrwxrwx 1 root martin 24 Jul 19  2019  Datenschutz -> /group/datenschutz/Files/
lrwxrwxrwx 1 root martin 26 Feb 20  2020 'Domain Admins' -> /group/domain.admins/Files/
lrwxrwxrwx 1 root martin 24 Aug 22  2018  Moderatoren -> /group/moderatoren/Files/

The permissions of these groups look like this:

martin.mein-iserv.de ~ # ll -d /group/admins 
drwxr-s--x 4 admins admins 4,0K Jan  9  2018 /group/admins/

My user has access to this folder via a supplementary group:

martin.mein-iserv.de ~ # id martin
uid=1004(martin) gid=1004(martin) Gruppen=1004(martin),27(sudo),1001(domain.admins),1011(moderatoren),1000(admins),12165(datenschutz),100000(domain.users),3000008(builtin.users),3000000(administrators),3000004(deny.rodc.password.replication)

webdav-server-rs will neither list these symlinks nor allow access to them when I manually input the path:

[2020-12-10T00:03:32Z DEBUG webdav_handler::davhandler] == START REQUEST PropFind "/Groups/"
[2020-12-10T00:03:32Z DEBUG webdav_handler::davhandler] == END REQUEST result OK
[2020-12-10T00:03:32Z DEBUG webdav_handler::davhandler] == START REQUEST PropFind "/Groups/Admins/"
[2020-12-10T00:03:32Z DEBUG webdav_handler::davhandler] == END REQUEST result OK
[2020-12-10T00:03:32Z ERROR webdav_handler::handle_props] read_dir error Forbidden
[2020-12-10T00:03:32Z DEBUG webdav_handler::davhandler] == START REQUEST PropFind "/Groups/Admins"
[2020-12-10T00:03:32Z DEBUG webdav_handler::davhandler] == END REQUEST result OK
[2020-12-10T00:03:32Z DEBUG webdav_handler::davhandler] == START REQUEST PropFind "/Groups/Admins"
[2020-12-10T00:03:32Z DEBUG webdav_handler::davhandler] == END REQUEST result OK

If I understand the issue correctly, this is most probably due to the fact that webdav-server-rs doesn't set the supplementary groups of the user it is setuid'ing to. Sounds like this might be resolvable with initgroups, but so far I haven't been able to figure out how to adapt webdav-server-rs to use this.

Incorrect HTTP status code

A 404 Not Found status code is returned when methods is set to "http-ro" or "webdav-ro" and a write method (PUT, PATCH, etc) is sent. The expected status code is 405 Method Not Allowed.

Config file:

[server]
listen = ["0.0.0.0:4918", "[::]:4918"]

[[location]]
auth = "false"
route = ["/*path"]
directory = "/srv/public"
handler = "filesystem"
methods = ["webdav-ro"]

The HTTP request:

-> touch /srv/public/test

-> curl -v -X PUT localhost:4918/test
*   Trying 127.0.0.1:4918...
* Connected to localhost (127.0.0.1) port 4918 (#0)
> PUT /test HTTP/1.1
> Host: localhost:4918
> User-Agent: curl/7.79.1
> Accept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 404 Not Found
< server: webdav-server-rs
< content-type: text/xml
< transfer-encoding: chunked
< date: Mon, 22 Nov 2021 07:01:30 GMT
<
<error>404 Not Found</error>
* Connection #0 to host localhost left intact

Certificates not recognized

webdav-server-rs is too picky.

[server]
  # Port(s) to listen on.
  # listen = [ "0.0.0.0:5018", "[::]:5018" ]

  # Tls config.
  tls_listen = [ "0.0.0.0:5443", "[::]:5443" ]
  tls_cert = "/tmp/invoice2storage/.ssl/server.crt"
  tls_key = "/tmp/invoice2storage/.ssl/server.key"

Generating certificates:

mkcert -cert-file /tmp/invoice2storage/.ssl/server.crt -key-file /tmp/invoice2storage/.ssl/server.key localhost

# webdav-server -c test-data/webdav/webdav-server.toml
Error: Custom { kind: InvalidData, error: "/tmp/invoice2storage/.ssl/server.key: expected one private key (found 0)" }
mkcert -ecdsa -cert-file /tmp/invoice2storage/.ssl/server.crt -key-file /tmp/invoice2storage/.ssl/server.key localhost

# webdav-server -c test-data/webdav/webdav-server.toml
Error: Custom { kind: InvalidData, error: "/tmp/invoice2storage/.ssl/server.key: expected one private key (found 0)" }
openssl req  -nodes -new -x509  -keyout /tmp/invoice2storage/.ssl/server.key -out /tmp/invoice2storage/.ssl/server.crt -subj '/CN=localhost'

webdav-server -c test-data/webdav/webdav-server.toml
Error: Custom { kind: InvalidData, error: "/tmp/invoice2storage/.ssl/server.key: expected one private key (found 0)" }
cat /tmp/invoice2storage/.ssl/server.key

-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCZuoDDhKSN++Bc
wXG9TEV7pvGbr5ag6etx+LSk6f76PjKgR+HPARWH99b8P30lJXYHduzs6D0T6mG4
LaockIms7O3bHJc5JK/yL+GqZsxdQTXDNtyZVmOO91yeVvMAMkEcUV8d6PNKARnl
zjylsDUi2TIl0TZI1iNeUi6Q0+aiPoilPJwl0VoOQmwSWQiU6zKqSf8vbtFb6sY+
hXsNBT9e/ffbb7s+tmDX7B6PQYzsN6W9K+/biB6evYCtpZZGfqh5ru0RQPoF8Bso
gwgbh8ZXJ/9jy7fAAl+i0u0l6eLExRf0wHy15VYQ6hOcbshQRhBzAiMvtJF8LI7z
sT+uOuulAgMBAAECggEAFCojHsJk5VzvKquTNE3vZU9aLN5E51mXsSz64RDyibej
42NaatFNFjc7w32+eCNoToVagZ7a+CRL6iFPSYzqCj1P2+htq6i0zZNbSgNO9kKJ
/0/Qcuqih4vJ4dks6c8tvD2uONmoJAJt97dsPB2XcrlDuzMsqDQykno8MnIhNBHE
....

So, what is the required magic ?

build errors introduced by a536270?

I'm trying to build webdav-server-rs, but I'm getting the following errors:

martin.mein-iserv.de ~/webdav-server-rs # cargo build
   Compiling webdav-server v0.3.0 (/var/lib/iserv/remote-support/iserv-martin.von.wittich/webdav-server-rs)
error[E0433]: failed to resolve: use of undeclared crate or module `cache`
  --> src/auth.rs:28:17
   |
28 |                 cache::cached::set_pamcache_timeout(timeout);
   |                 ^^^^^ use of undeclared crate or module `cache`

error[E0433]: failed to resolve: use of undeclared type `IpAddr`
  --> src/auth.rs:78:17
   |
78 |                 IpAddr::V4(ip) => ip.to_string(),
   |                 ^^^^^^ use of undeclared type `IpAddr`

error[E0433]: failed to resolve: use of undeclared type `IpAddr`
  --> src/auth.rs:79:17
   |
79 |                 IpAddr::V6(ip) => ip.to_string(),
   |                 ^^^^^^ use of undeclared type `IpAddr`

error[E0433]: failed to resolve: use of undeclared crate or module `cache`
  --> src/auth.rs:87:15
   |
87 |         match cache::cached::pam_auth(pam_auth, service, user, pass, ip_ref).await {
   |               ^^^^^ use of undeclared crate or module `cache`

error[E0412]: cannot find type `PamAuth` in this scope
   --> src/cache.rs:142:19
    |
142 |         pam_auth: PamAuth,
    |                   ^^^^^^^ not found in this scope
    |
help: consider importing this struct
    |
98  |     use pam_sandboxed::PamAuth;
    |

error[E0412]: cannot find type `PamError` in this scope
   --> src/cache.rs:147:21
    |
147 |     ) -> Result<(), PamError>
    |                     ^^^^^^^^ not found in this scope
    |
help: consider importing this struct
    |
98  |     use pam_sandboxed::PamError;
    |

warning: unused imports: `PamAuth`, `PamError`
   --> src/cache.rs:151:29
    |
151 |         use pam_sandboxed::{PamAuth, PamError};
    |                             ^^^^^^^  ^^^^^^^^
    |
    = note: `#[warn(unused_imports)]` on by default

error: aborting due to 6 previous errors; 1 warning emitted

Some errors have detailed explanations: E0412, E0433.
For more information about an error, try `rustc --explain E0412`.
error: could not compile `webdav-server`

To learn more, run the command again with --verbose.

Looks to me like these errors were introduced in a536270; if I check out b20f569, it works. I haphazardly patched the issues like this:

martin.mein-iserv.de ~/webdav-server-rs (master) # git diff
diff --git a/src/auth.rs b/src/auth.rs
index fcfc876..429c1db 100644
--- a/src/auth.rs
+++ b/src/auth.rs
@@ -1,7 +1,8 @@
 use std::io;
-use std::net::SocketAddr;
+use std::net::{SocketAddr,IpAddr};
 use std::sync::Arc;
 
+use crate::cache;
 use crate::config::{AuthType, Config, Location};
 
 use headers::{authorization::Basic, Authorization, HeaderMapExt};
diff --git a/src/cache.rs b/src/cache.rs
index 1a72b91..ccb48d0 100644
--- a/src/cache.rs
+++ b/src/cache.rs
@@ -7,6 +7,9 @@ use std::option::Option;
 use std::sync::{Arc, Mutex};
 use std::time::{Duration, Instant};
 
+#[cfg(feature = "pam")]
+use pam_sandboxed::{PamAuth, PamError};
+
 #[allow(dead_code)]
 pub struct Cache<K, V> {
     intern: Mutex<Intern<K, V>>,
@@ -139,16 +142,15 @@ pub(crate) mod cached {
 
     #[cfg(feature = "pam")]
     pub async fn pam_auth<'a>(
-        pam_auth: PamAuth,
+        pam_auth: pam_sandboxed::PamAuth,
         service: &'a str,
         user: &'a str,
         pass: &'a str,
         remip: Option<&'a str>,
-    ) -> Result<(), PamError>
+    ) -> Result<(), pam_sandboxed::PamError>
     {
         use std::collections::hash_map::DefaultHasher;
         use std::hash::{Hash, Hasher};
-        use pam_sandboxed::{PamAuth, PamError};
 
         let mut s = DefaultHasher::new();
         service.hash(&mut s);

I'm still learning Rust, so take this with a grain of salt :)

Publish on crates.io

Please consider releasing this crate via crates.io; this would bring:

  • Easy installation cargo install webdav-server
  • Availability in crater runs
  • Discoverability for potential users of webdav-handler as a reverse dependency

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.