From e21ec58ea8d79ac70605dcc765b110fb7e4011c6 Mon Sep 17 00:00:00 2001
From: Sergey Lyubka <valenok@gmail.com>
Date: Wed, 26 Mar 2014 23:13:14 +0000
Subject: [PATCH] dav fixes: using auth if auth file is set

---
 mongoose.c | 94 ++++++++++++++++++++++++++++--------------------------
 1 file changed, 48 insertions(+), 46 deletions(-)

diff --git a/mongoose.c b/mongoose.c
index b483a92b1..68b09a5a4 100644
--- a/mongoose.c
+++ b/mongoose.c
@@ -1531,7 +1531,7 @@ static void send_http_error(struct connection *conn, int code,
     body_len += mg_vsnprintf(body + body_len, sizeof(body) - body_len, fmt, ap);
     va_end(ap);
   }
-  if (code >= 300 && code <= 399) {
+  if ((code >= 300 && code <= 399) || code == 204) {
     // 3xx errors do not have body
     body_len = 0;
   }
@@ -2081,12 +2081,10 @@ int mg_url_decode(const char *src, int src_len, char *dst,
   return i >= src_len ? j : -1;
 }
 
-static int is_valid_http_method(const char *method) {
-  return !strcmp(method, "GET") || !strcmp(method, "POST") ||
-    !strcmp(method, "HEAD") || !strcmp(method, "CONNECT") ||
-    !strcmp(method, "PUT") || !strcmp(method, "DELETE") ||
-    !strcmp(method, "OPTIONS") || !strcmp(method, "PROPFIND")
-    || !strcmp(method, "MKCOL");
+static int is_valid_http_method(const char *s) {
+  return !strcmp(s, "GET") || !strcmp(s, "POST") || !strcmp(s, "HEAD") ||
+    !strcmp(s, "CONNECT") || !strcmp(s, "PUT") || !strcmp(s, "DELETE") ||
+    !strcmp(s, "OPTIONS") || !strcmp(s, "PROPFIND") || !strcmp(s, "MKCOL");
 }
 
 // Parse HTTP request, fill in mg_request structure.
@@ -3170,36 +3168,34 @@ static void handle_propfind(struct connection *conn, const char *path,
         *list_dir = conn->server->config_options[ENABLE_DIRECTORY_LISTING];
 
   conn->mg_conn.status_code = 207;
-  ns_send(conn->ns_conn, header, sizeof(header) - 1);
 
   // Print properties for the requested resource itself
-  if (exists) {
-    print_props(conn, conn->mg_conn.uri, stp);
+  if (!exists) {
+    conn->mg_conn.status_code = 404;
+    mg_printf(&conn->mg_conn, "%s", "HTTP/1.1 404 Not Found\r\n\r\n");
+  } else if (S_ISDIR(stp->st_mode) && mg_strcasecmp(list_dir, "yes") != 0) {
+    conn->mg_conn.status_code = 403;
+    mg_printf(&conn->mg_conn, "%s",
+              "HTTP/1.1 403 Directory Listing Denied\r\n\r\n");
   } else {
-    mg_printf(&conn->mg_conn,
-              "<d:response>"
-              "<d:href>%s</d:href>"
-              "<d:propstat>"
-              "<d:status>HTTP/1.1 404 Not Found</d:status>"
-              "</d:propstat>"
-              "</d:response>\n", path);
-  }
-
-  // If it is a directory, print directory entries too if Depth is not 0
-  if (exists && S_ISDIR(stp->st_mode) && !mg_strcasecmp(list_dir, "yes") &&
-      (depth == NULL || strcmp(depth, "0") != 0)) {
-    struct dir_entry *arr = NULL;
-    int i, num_entries = scan_directory(conn, path, &arr);
-
-    for (i = 0; i < num_entries; i++) {
-      char buf[MAX_PATH_SIZE * 3];
-      struct dir_entry *de = &arr[i];
-      mg_url_encode(de->file_name, buf, sizeof(buf) - 1);
-      print_props(conn, buf, &de->st);
+    ns_send(conn->ns_conn, header, sizeof(header) - 1);
+    print_props(conn, conn->mg_conn.uri, stp);
+
+    if (S_ISDIR(stp->st_mode) &&
+             (depth == NULL || strcmp(depth, "0") != 0)) {
+      struct dir_entry *arr = NULL;
+      int i, num_entries = scan_directory(conn, path, &arr);
+
+      for (i = 0; i < num_entries; i++) {
+        char buf[MAX_PATH_SIZE * 3];
+        struct dir_entry *de = &arr[i];
+        mg_url_encode(de->file_name, buf, sizeof(buf) - 1);
+        print_props(conn, buf, &de->st);
+      }
     }
+    ns_send(conn->ns_conn, footer, sizeof(footer) - 1);
   }
 
-  ns_send(conn->ns_conn, footer, sizeof(footer) - 1);
   close_local_endpoint(conn);
 }
 
@@ -3252,7 +3248,7 @@ static void handle_delete(struct connection *conn, const char *path) {
   } else if (S_ISDIR(st.st_mode)) {
     remove_directory(path);
     send_http_error(conn, 204, NULL);
-  } else if (!remove(path) == 0) {
+  } else if (remove(path) == 0) {
     send_http_error(conn, 204, NULL);
   } else {
     send_http_error(conn, 423, NULL);
@@ -3322,22 +3318,24 @@ static void handle_put(struct connection *conn, const char *path) {
 
 static void forward_put_data(struct connection *conn) {
   struct iobuf *io = &conn->ns_conn->recv_iobuf;
-  int n = write(conn->endpoint.fd, io->buf, io->len);
+  int n = conn->cl < io->len ? conn->cl : io->len;  // How many bytes to write
+  n = write(conn->endpoint.fd, io->buf, n);         // Write them!
   if (n > 0) {
     iobuf_remove(io, n);
     conn->cl -= n;
-    if (conn->cl <= 0) {
-      close_local_endpoint(conn);
-    }
+  }
+  if (conn->cl <= 0) {
+    close_local_endpoint(conn);
   }
 }
 #endif //  MONGOOSE_NO_DAV
 
 static void send_options(struct connection *conn) {
-  static const char reply[] = "HTTP/1.1 200 OK\r\nAllow: GET, POST, HEAD, "
-    "CONNECT, PUT, DELETE, OPTIONS, PROPFIND, MKCOL\r\nDAV: 1\r\n\r\n";
-  ns_send(conn->ns_conn, reply, sizeof(reply) - 1);
-  conn->ns_conn->flags |= NSF_FINISHED_SENDING_DATA;
+  conn->mg_conn.status_code = 200;
+  mg_printf(&conn->mg_conn, "%s",
+            "HTTP/1.1 200 OK\r\nAllow: GET, POST, HEAD, CONNECT, PUT, "
+            "DELETE, OPTIONS, PROPFIND, MKCOL\r\nDAV: 1\r\n\r\n");
+  close_local_endpoint(conn);
 }
 
 #ifndef MONGOOSE_NO_AUTH
@@ -3668,10 +3666,14 @@ static int is_authorized(struct connection *conn, const char *path) {
 
 static int is_authorized_for_dav(struct connection *conn) {
   const char *auth_file = conn->server->config_options[DAV_AUTH_FILE];
+  const char *method = conn->mg_conn.request_method;
   FILE *fp;
   int authorized = MG_FALSE;
 
-  if (auth_file != NULL && (fp = fopen(auth_file, "r")) != NULL) {
+  // If dav_auth_file is not set, allow non-authorized PROPFIND
+  if (method != NULL && !strcmp(method, "PROPFIND") && auth_file == NULL) {
+    authorized = MG_TRUE;
+  } else if (auth_file != NULL && (fp = fopen(auth_file, "r")) != NULL) {
     authorized = mg_authorize_digest(&conn->mg_conn, fp);
     fclose(fp);
   }
@@ -3679,10 +3681,10 @@ static int is_authorized_for_dav(struct connection *conn) {
   return authorized;
 }
 
-static int is_dav_mutation(const struct connection *conn) {
+static int is_dav_request(const struct connection *conn) {
   const char *s = conn->mg_conn.request_method;
-  return s && (!strcmp(s, "PUT") || !strcmp(s, "DELETE") ||
-               !strcmp(s, "MKCOL"));
+  return !strcmp(s, "PUT") || !strcmp(s, "DELETE") ||
+    !strcmp(s, "MKCOL") || !strcmp(s, "PROPFIND");
 }
 #endif // MONGOOSE_NO_AUTH
 
@@ -3939,8 +3941,8 @@ static void open_local_endpoint(struct connection *conn, int skip_user) {
   } else if (conn->server->config_options[DOCUMENT_ROOT] == NULL) {
     send_http_error(conn, 404, NULL);
 #ifndef MONGOOSE_NO_AUTH
-  } else if ((!is_dav_mutation(conn) && !is_authorized(conn, path)) ||
-             (is_dav_mutation(conn) && !is_authorized_for_dav(conn))) {
+  } else if ((!is_dav_request(conn) && !is_authorized(conn, path)) ||
+             (is_dav_request(conn) && !is_authorized_for_dav(conn))) {
     mg_send_digest_auth_request(&conn->mg_conn);
     close_local_endpoint(conn);
 #endif
-- 
GitLab