add auth support
authorFelix Fietkau <nbd@openwrt.org>
Wed, 2 Jan 2013 13:47:12 +0000 (14:47 +0100)
committerFelix Fietkau <nbd@openwrt.org>
Wed, 2 Jan 2013 13:47:12 +0000 (14:47 +0100)
auth.c
file.c
uhttpd.h

diff --git a/auth.c b/auth.c
index 05bec66c91b26f47f8eeec74d84bc908dc853ed2..c27488fcb7738bbefec7e40460faf7c704918aab 100644 (file)
--- a/auth.c
+++ b/auth.c
@@ -66,3 +66,62 @@ void uh_auth_add(const char *path, const char *user, const char *pass)
        new->pass = strcpy(dest_pass, new_pass);
        list_add(&new->list, &auth_realms);
 }
+
+bool uh_auth_check(struct client *cl, struct path_info *pi)
+{
+       struct http_request *req = &cl->request;
+       struct auth_realm *realm;
+       bool user_match = false;
+       char *user = NULL;
+       char *pass = NULL;
+       int plen;
+
+       if (pi->auth && !strncasecmp(pi->auth, "Basic ", 6)) {
+               const char *auth = pi->auth + 6;
+
+               uh_b64decode(uh_buf, sizeof(uh_buf), auth, strlen(auth));
+               pass = strchr(uh_buf, ':');
+               if (pass) {
+                       user = uh_buf;
+                       *pass++ = 0;
+               }
+       }
+
+       req->realm = NULL;
+       plen = strlen(pi->name);
+       list_for_each_entry(realm, &auth_realms, list) {
+               int rlen = strlen(realm->path);
+
+               if (plen < rlen)
+                       continue;
+
+               if (strncasecmp(pi->name, realm->path, rlen) != 0)
+                       continue;
+
+               req->realm = realm;
+               if (!user)
+                       break;
+
+               if (strcmp(user, realm->user) != 0)
+                       continue;
+
+               user_match = true;
+               break;
+       }
+
+       if (!req->realm)
+               return true;
+
+       if (user_match && !strcmp(crypt(pass, realm->pass), realm->pass))
+               return true;
+
+       uh_http_header(cl, 401, "Authorization Required");
+       ustream_printf(cl->us,
+                                 "WWW-Authenticate: Basic realm=\"%s\"\r\n"
+                                 "Content-Type: text/plain\r\n\r\n",
+                                 conf.realm);
+       uh_chunk_printf(cl, "Authorization Required\n");
+       uh_request_done(cl);
+
+       return false;
+}
diff --git a/file.c b/file.c
index 4a10eaa2f27f15f7a290bf3b966693d75d4c9af1..62c8ee7ce991d587515a9056a4fa2bbf4331339f 100644 (file)
--- a/file.c
+++ b/file.c
@@ -40,6 +40,7 @@ struct index_file {
 };
 
 enum file_hdr {
+       HDR_AUTHORIZATION,
        HDR_IF_MODIFIED_SINCE,
        HDR_IF_UNMODIFIED_SINCE,
        HDR_IF_MATCH,
@@ -578,22 +579,11 @@ static void uh_file_data(struct client *cl, struct path_info *pi, int fd)
        file_write_cb(cl);
 }
 
-static void uh_file_request(struct client *cl, const char *url, struct path_info *pi)
+static void uh_file_request(struct client *cl, const char *url,
+                           struct path_info *pi, struct blob_attr **tb)
 {
-       static const struct blobmsg_policy hdr_policy[__HDR_MAX] = {
-               [HDR_IF_MODIFIED_SINCE] = { "if-modified-since", BLOBMSG_TYPE_STRING },
-               [HDR_IF_UNMODIFIED_SINCE] = { "if-unmodified-since", BLOBMSG_TYPE_STRING },
-               [HDR_IF_MATCH] = { "if-match", BLOBMSG_TYPE_STRING },
-               [HDR_IF_NONE_MATCH] = { "if-none-match", BLOBMSG_TYPE_STRING },
-               [HDR_IF_RANGE] = { "if-range", BLOBMSG_TYPE_STRING },
-       };
-       struct blob_attr *tb[__HDR_MAX];
        int fd;
 
-       blobmsg_parse(hdr_policy, __HDR_MAX, tb, blob_data(cl->hdr.head), blob_len(cl->hdr.head));
-
-       cl->dispatch.file.hdr = tb;
-
        if (!(pi->stat.st_mode & S_IROTH))
                goto error;
 
@@ -602,24 +592,24 @@ static void uh_file_request(struct client *cl, const char *url, struct path_info
                if (fd < 0)
                        goto error;
 
+               cl->dispatch.file.hdr = tb;
                uh_file_data(cl, pi, fd);
-       } else if ((pi->stat.st_mode & S_IFDIR)) {
+               cl->dispatch.file.hdr = NULL;
+               return;
+       }
+
+       if ((pi->stat.st_mode & S_IFDIR)) {
                if (conf.no_dirlists)
                        goto error;
 
                uh_file_dirlist(cl, pi);
-       } else {
-               goto error;
+               return;
        }
 
-       cl->dispatch.file.hdr = NULL;
-       return;
-
 error:
        uh_client_error(cl, 403, "Forbidden",
                        "You don't have permission to access %s on this server.",
                        url);
-       cl->dispatch.file.hdr = NULL;
 }
 
 void uh_dispatch_add(struct dispatch_handler *d)
@@ -653,7 +643,16 @@ dispatch_find(const char *url, struct path_info *pi)
 
 static bool __handle_file_request(struct client *cl, const char *url)
 {
+       static const struct blobmsg_policy hdr_policy[__HDR_MAX] = {
+               [HDR_AUTHORIZATION] = { "authorization", BLOBMSG_TYPE_STRING },
+               [HDR_IF_MODIFIED_SINCE] = { "if-modified-since", BLOBMSG_TYPE_STRING },
+               [HDR_IF_UNMODIFIED_SINCE] = { "if-unmodified-since", BLOBMSG_TYPE_STRING },
+               [HDR_IF_MATCH] = { "if-match", BLOBMSG_TYPE_STRING },
+               [HDR_IF_NONE_MATCH] = { "if-none-match", BLOBMSG_TYPE_STRING },
+               [HDR_IF_RANGE] = { "if-range", BLOBMSG_TYPE_STRING },
+       };
        struct dispatch_handler *d;
+       struct blob_attr *tb[__HDR_MAX];
        struct path_info *pi;
 
        pi = uh_path_lookup(cl, url);
@@ -663,11 +662,18 @@ static bool __handle_file_request(struct client *cl, const char *url)
        if (pi->redirected)
                return true;
 
+       blobmsg_parse(hdr_policy, __HDR_MAX, tb, blob_data(cl->hdr.head), blob_len(cl->hdr.head));
+       if (tb[HDR_AUTHORIZATION])
+               pi->auth = blobmsg_data(tb[HDR_AUTHORIZATION]);
+
+       if (!uh_auth_check(cl, pi))
+               return true;
+
        d = dispatch_find(url, pi);
        if (d)
                d->handle_request(cl, url, pi);
        else
-               uh_file_request(cl, url, pi);
+               uh_file_request(cl, url, pi, tb);
 
        return true;
 }
index e1d061f6e7208a81dadc2e5455ef91154e679271..cb56fcdc5b6a940f34abf5554558f982461e7d76 100644 (file)
--- a/uhttpd.h
+++ b/uhttpd.h
@@ -103,6 +103,7 @@ struct path_info {
        const char *name;
        const char *info;
        const char *query;
+       const char *auth;
        bool redirected;
        struct stat stat;
        const struct interpreter *ip;
@@ -213,6 +214,7 @@ uh_client_error(struct client *cl, int code, const char *summary, const char *fm
 void uh_handle_request(struct client *cl);
 
 void uh_auth_add(const char *path, const char *user, const char *pass);
+bool uh_auth_check(struct client *cl, struct path_info *pi);
 
 void uh_close_listen_fds(void);
 void uh_close_fds(void);