"GOT", but the "O" is a cute, smiling pufferfish. Index | Thread | Search

From:
Stefan Sperling <stsp@stsp.name>
Subject:
make gitwrapper ignore "realpath: permission denied"
To:
gameoftrees@openbsd.org
Date:
Fri, 7 Jul 2023 14:42:31 +0200

Download raw body.

Thread
I came across this misbehaviour of gitwrapper while setting up
a private repository to be served by gotd.

ok?

-----------------------------------------------
 make gitwrapper ignore 'permission denied' for repository paths
 
 We recommend that gotsh users should not have direct filesystem
 access to repositories served by gotd. Which means admins will be
 setting things up as follows if public read-access should be denied:
 
   chown _gotd /git
   chmod 700 /git
   su -m _gotd -c 'gotadmin init /git/repo.git"
 
 However, gitwrapper would error out when repositories listed in
 gotd.conf were inaccessible to the user invoking gitwrapper:
 
 git-upload-pack: /etc/gotd.conf:2: realpath /git/repo.git: Permission denied
 
 Make gitwrapper ignore such errors as they are expected in this situation.
 
 While here, add a PROC_GITWRAPPER process ID for use as a global variable
 parse.y can check while special-casing any specific behaviour required by
 gitwrapper. (The worse alternative would have been adding a new global
 variable to parse.y just to control the behaviour on realpath errors.)
 
diff bafea5babab6072bfa7528ad7c767bde76a446a3 c097e1a4fa86a111f516a37aff5394f8c6695d24
commit - bafea5babab6072bfa7528ad7c767bde76a446a3
commit + c097e1a4fa86a111f516a37aff5394f8c6695d24
blob - 1ed8d3dc9b6ae29d105bff2710d33de54cf0bc13
blob + 28645f07dc93480582fce4b5f7dea5813b028a23
--- gitwrapper/gitwrapper.c
+++ gitwrapper/gitwrapper.c
@@ -131,7 +131,7 @@ main(int argc, char *argv[])
 	confpath = getenv("GOTD_CONF_PATH");
 	if (confpath == NULL)
 		confpath = GOTD_CONF_PATH;
-	parse_config(confpath, PROC_GOTD, &gotd, 0);
+	parse_config(confpath, PROC_GITWRAPPER, &gotd);
 
 	error = apply_unveil(myserver);
 	if (error)
blob - 68a99a122229289490584888ded7f2beb2d99042
blob + 4432aec44c71cf0db3723fa870ba885b23ddd037
--- gotd/gotd.c
+++ gotd/gotd.c
@@ -729,7 +729,8 @@ static const char *gotd_proc_names[PROC_MAX] = {
 	"session_read",
 	"session_write",
 	"repo_read",
-	"repo_write"
+	"repo_write",
+	"gitwrapper"
 };
 
 static void
@@ -1858,7 +1859,7 @@ main(int argc, char **argv)
 	if (geteuid() && (proc_id == PROC_GOTD || proc_id == PROC_LISTEN))
 		fatalx("need root privileges");
 
-	if (parse_config(confpath, proc_id, &gotd, 1) != 0)
+	if (parse_config(confpath, proc_id, &gotd) != 0)
 		return 1;
 
 	pw = getpwnam(gotd.user_name);
blob - e902d6f53b03f7682202e2b9b3d0af5fc28c25b6
blob + acb40dee8cd351b48669c3c3247c42ed5f44501b
--- gotd/gotd.h
+++ gotd/gotd.h
@@ -40,6 +40,7 @@ enum gotd_procid {
 	PROC_SESSION_WRITE,
 	PROC_REPO_READ,
 	PROC_REPO_WRITE,
+	PROC_GITWRAPPER,
 	PROC_MAX,
 };
 
@@ -442,7 +443,7 @@ int parse_config(const char *, enum gotd_procid, struc
 	uint32_t client_id;
 };
 
-int parse_config(const char *, enum gotd_procid, struct gotd *, int);
+int parse_config(const char *, enum gotd_procid, struct gotd *);
 struct gotd_repo *gotd_find_repo_by_name(const char *, struct gotd *);
 struct gotd_repo *gotd_find_repo_by_path(const char *, struct gotd *);
 struct gotd_uid_connection_limit *gotd_find_uid_connection_limit(
blob - a3860760379f26a53fcf3788e84f9efb36efbdd3
blob + 6f3e0a082e72aca4ecc41d9b9980d9b1b7325746
--- gotd/parse.y
+++ gotd/parse.y
@@ -293,7 +293,8 @@ repository	: REPOSITORY STRING {
 
 			if (gotd_proc_id == PROC_GOTD ||
 			    gotd_proc_id == PROC_AUTH ||
-			    gotd_proc_id == PROC_REPO_WRITE) {
+			    gotd_proc_id == PROC_REPO_WRITE ||
+			    gotd_proc_id == PROC_GITWRAPPER) {
 				new_repo = conf_new_repo($2);
 			}
 			free($2);
@@ -304,7 +305,8 @@ repoopts1	: PATH STRING {
 repoopts1	: PATH STRING {
 			if (gotd_proc_id == PROC_GOTD ||
 			    gotd_proc_id == PROC_AUTH ||
-			    gotd_proc_id == PROC_REPO_WRITE) {
+			    gotd_proc_id == PROC_REPO_WRITE ||
+			    gotd_proc_id == PROC_GITWRAPPER) {
 				if (!got_path_is_absolute($2)) {
 					yyerror("%s: path %s is not absolute",
 					    __func__, $2);
@@ -312,16 +314,28 @@ repoopts1	: PATH STRING {
 					YYERROR;
 				}
 				if (realpath($2, new_repo->path) == NULL) {
-					yyerror("realpath %s: %s", $2,
-					    strerror(errno));
 					/*
-					 * Give admin a chance to create
-					 * missing repositories at run-time.
+					 * To give admins a chance to create
+					 * missing repositories at run-time
+					 * we only warn about ENOENT here.
+					 *
+					 * And ignore 'permission denied' when
+					 * running in gitwrapper. Users may be
+					 * able to access this repository via
+					 * gotd regardless.
 					 */
-					if (errno != ENOENT) {
+					if (errno == ENOENT) {
+						yyerror("realpath %s: %s", $2,
+						    strerror(errno));
+					} else if (errno != EACCES ||
+					    gotd_proc_id != PROC_GITWRAPPER) {
+						yyerror("realpath %s: %s", $2,
+						    strerror(errno));
 						free($2);
 						YYERROR;
-					} else if (strlcpy(new_repo->path, $2,
+					}
+
+					if (strlcpy(new_repo->path, $2,
 					    sizeof(new_repo->path)) >=
 					    sizeof(new_repo->path))
 						yyerror("path too long");
@@ -740,10 +754,11 @@ parse_config(const char *filename, enum gotd_procid pr
 
 int
 parse_config(const char *filename, enum gotd_procid proc_id,
-    struct gotd *env, int require_config_file)
+    struct gotd *env)
 {
 	struct sym *sym, *next;
 	struct gotd_repo *repo;
+	int require_config_file = (proc_id == PROC_GITWRAPPER ? 0 : 1);
 
 	memset(env, 0, sizeof(*env));