Browse Source

add auth support

Felix Fietkau 11 years ago
parent
commit
76f5d84671
3 changed files with 88 additions and 21 deletions
  1. 59 0
      auth.c
  2. 27 21
      file.c
  3. 2 0
      uhttpd.h

+ 59 - 0
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;
+}

+ 27 - 21
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;
 }

+ 2 - 0
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);