Commit Diff


commit - 64eb24873b5b63f89f43071f87f0b68d67ade4e6
commit + e240092c03160c453e59bea3aff1b6ec606b1539
blob - 14c25fdd2c16e640ef31c1abeedcb12aedee9b94
blob + 29487341845ed5d0e00ec472e2593c862e4503d1
--- gotwebd/access.c
+++ gotwebd/access.c
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2025 Stefan Sperling <stsp@openbsd.org>
+ * Copyright (c) 2015 Ted Unangst <tedu@openbsd.org>
  *
  * Permission to use, copy, modify, and distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -19,15 +20,126 @@
 #include <errno.h>
 #include <event.h>
 #include <imsg.h>
+#include <pwd.h>
+#include <grp.h>
+#include <stdlib.h>
+#include <unistd.h>
 
 #include "got_reference.h"
 
 #include "gotwebd.h"
 #include "log.h"
 
+#if 0
+static int
+parseuid(const char *s, uid_t *uid)
+{
+	struct passwd *pw;
+	const char *errstr;
+
+	if ((pw = getpwnam(s)) != NULL) {
+		*uid = pw->pw_uid;
+		if (*uid == UID_MAX)
+			return -1;
+		return 0;
+	}
+	*uid = strtonum(s, 0, UID_MAX - 1, &errstr);
+	if (errstr)
+		return -1;
+	return 0;
+}
+
+static int
+uidcheck(const char *s, uid_t desired)
+{
+	uid_t uid;
+
+	if (parseuid(s, &uid) != 0)
+		return -1;
+	if (uid != desired)
+		return -1;
+	return 0;
+}
+
+static int
+parsegid(const char *s, gid_t *gid)
+{
+	struct group *gr;
+	const char *errstr;
+
+	if ((gr = getgrnam(s)) != NULL) {
+		*gid = gr->gr_gid;
+		if (*gid == GID_MAX)
+			return -1;
+		return 0;
+	}
+	*gid = strtonum(s, 0, GID_MAX - 1, &errstr);
+	if (errstr)
+		return -1;
+	return 0;
+}
+
+static int
+match_identifier(const char *identifier, gid_t *groups, int ngroups,
+    uid_t euid, gid_t egid)
+{
+	int i;
+
+	if (identifier[0] == ':') {
+		gid_t rgid;
+		if (parsegid(identifier + 1, &rgid) == -1)
+			return 0;
+		if (rgid == egid)
+			return 1;
+		for (i = 0; i < ngroups; i++) {
+			if (rgid == groups[i])
+				break;
+		}
+		if (i == ngroups)
+			return 0;
+	} else if (uidcheck(identifier, euid) != 0)
+		return 0;
+
+	return 1;
+}
+#endif
 enum gotwebd_access
 access_check(uid_t uid, struct gotwebd_access_rule_list *rules)
 {
+#if 1
 	/* TODO */
 	return GOTWEBD_ACCESS_PERMITTED;
+#else
+	struct gotwebd_access_rule *rule;
+	enum gotwebd_access access = GOTWEBD_ACCESS_DENIED;
+	struct passwd *pw;
+	gid_t groups[NGROUPS_MAX];
+	int ngroups = NGROUPS_MAX;
+	int matched_user = 0;
+
+	pw = getpwuid(uid);
+	if (pw == NULL)
+		return GOTWEBD_ACCESS_NOTFOUND;
+
+	if (getgrouplist(pw->pw_name, pw->pw_gid, groups, &ngroups) == -1)
+		log_warnx("group membership list truncated");
+
+	STAILQ_FOREACH(rule, rules, entry) {
+		if (!match_identifier(rule->identifier, groups, ngroups,
+		    pw->pw_uid, pw->pw_gid))
+			continue;
+
+		matched_user = 1;
+		access = rule->access;
+	}
+
+	/*
+	 * If a user has no explicit read or write access then
+	 * do not leak the existence of a repository to them.
+	 */
+	if (access == GOTWEBD_ACCESS_DENIED && !matched_user)
+		access = GOTWEBD_ACCESS_NOTFOUND;
+
+	return access;
+#endif
 }
blob - ac8d4da6aca037eb97d5d8c2129641b85fb71305
blob + cc02ed610da95de3915587d1b15df67214fff46e
--- gotwebd/gotwebd.h
+++ gotwebd/gotwebd.h
@@ -319,6 +319,7 @@ enum gotwebd_auth_config {
 };
 
 enum gotwebd_access {
+	GOTWEBD_ACCESS_NOTFOUND = -2,
 	GOTWEBD_ACCESS_DENIED = -1,
 	GOTWEBD_ACCESS_PERMITTED = 1
 };
blob - 68741fc55a01a2ca13342f6e819878bbe5a48823
blob + 9a0ec573dc71633cac84edcd4b1cf9c6889c3fa4
--- gotwebd/login.c
+++ gotwebd/login.c
@@ -336,13 +336,19 @@ process_request(struct request *c, struct imsg *imsg)
 	if (qs->action == INDEX) {
 		access = access_check(c->client_uid, &c->srv->access_rules);
 		switch (access) {
-		case GOTWEBD_ACCESS_PERMITTED:
-			break;
+		case GOTWEBD_ACCESS_NOTFOUND:
+			/* Return an empty index page. */
+			if (gotweb_reply(c, 200, "text/html", NULL) == -1)
+				return -1;
+			gotweb_render_page(c->tp, gotweb_render_repo_table_hdr);
+			return -1;
 		case GOTWEBD_ACCESS_DENIED:
 			if (gotweb_reply(c, 401, "text/html", NULL) == -1)
 				return -1;
 			gotweb_render_page(c->tp, gotweb_render_unauthorized);
 			return -1;
+		case GOTWEBD_ACCESS_PERMITTED:
+			break;
 		default:
 			log_debug("access check error for uid %u\n",
 			    c->client_uid);
@@ -359,8 +365,15 @@ process_request(struct request *c, struct imsg *imsg)
 			access = access_check(c->client_uid,
 			    &repo->access_rules);
 			switch (access) {
-			case GOTWEBD_ACCESS_PERMITTED:
-				break;
+			case GOTWEBD_ACCESS_NOTFOUND:
+				if (qs->path) {
+					error = got_error_path(qs->path,
+					    GOT_ERR_NOT_GIT_REPO);
+				} else {
+					error = got_error(
+					    GOT_ERR_BAD_QUERYSTRING);
+				}
+				goto err;
 			case GOTWEBD_ACCESS_DENIED:
 				if (gotweb_reply(c, 401,
 				    "text/html", NULL) == -1)
@@ -368,6 +381,8 @@ process_request(struct request *c, struct imsg *imsg)
 				gotweb_render_page(c->tp,
 				    gotweb_render_unauthorized);
 				return -1;
+			case GOTWEBD_ACCESS_PERMITTED:
+				break;
 			default:
 				log_debug("access check error for uid %u\n",
 				    c->client_uid);