commit 9aeaf23a7e94501bdcb20d18427620cf70b87995
from: Omar Polo <op@omarpolo.com>
date: Sun Jan 22 14:09:47 2023 UTC

gotsh: validate with parse_command before connecting

Export parse_command (now got_serve_parse_command) from lib/serve.c and
use it to validate the command line in gotsh instead of just checking
that the -c argument starts with 'git-receive-pack' or 'git-upload-pack'.
Invalid usage now always fails before opening the socket, while before
it wasn't always the case.  This also means that invalid usage doesn't
count towards the limits.

ok jamsek, stsp

commit - b5225f29d85b32692bdfed88b3e93babf8269494
commit + 9aeaf23a7e94501bdcb20d18427620cf70b87995
blob - acc4545ba9aeab1061576f340ba1ba16ed227d59
blob + fb5f331b5c32503b2fe1e1c4de73a8af9959be9d
--- gotsh/gotsh.c
+++ gotsh/gotsh.c
@@ -67,7 +67,7 @@ main(int argc, char *argv[])
 	char *unix_socket_path_env = getenv("GOTD_UNIX_SOCKET");
 	int gotd_sock = -1;
 	struct sockaddr_un	 sun;
-	char *gitcmd = NULL;
+	char *gitcmd = NULL, *command = NULL, *repo_path = NULL;
 
 #ifndef PROFILE
 	if (pledge("stdio recvfd unix unveil", NULL) == -1)
@@ -79,17 +79,16 @@ main(int argc, char *argv[])
 			usage();
 		if (asprintf(&gitcmd, "%s %s", argv[0], argv[1]) == -1)
 			err(1, "asprintf");
+		error = got_serve_parse_command(&command, &repo_path, gitcmd);
 	} else {
-		if (argc != 3 || strcmp(argv[1], "-c") != 0 ||
-		    (strncmp(argv[2], GOT_SERVE_CMD_SEND,
-		    strlen(GOT_SERVE_CMD_SEND)) != 0 &&
-		    (strncmp(argv[2], GOT_SERVE_CMD_FETCH,
-		    strlen(GOT_SERVE_CMD_FETCH)) != 0)))
+		if (argc != 3 || strcmp(argv[1], "-c") != 0)
 			usage();
-		gitcmd = strdup(argv[2]);
-		if (gitcmd == NULL)
-			err(1, "strdup");
+		error = got_serve_parse_command(&command, &repo_path, argv[2]);
 	}
+	if (error && error->code == GOT_ERR_BAD_PACKET)
+		usage();
+	if (error)
+		goto done;
 
 	if (unix_socket_path_env) {
 		if (strlcpy(unix_socket_path, unix_socket_path_env,
@@ -123,10 +122,12 @@ main(int argc, char *argv[])
 	if (pledge("stdio recvfd", NULL) == -1)
 		err(1, "pledge");
 #endif
-	error = got_serve(STDIN_FILENO, STDOUT_FILENO, gitcmd, gotd_sock,
-	    chattygot);
+	error = got_serve(STDIN_FILENO, STDOUT_FILENO, command, repo_path,
+	    gotd_sock, chattygot);
 done:
 	free(gitcmd);
+	free(command);
+	free(repo_path);
 	if (gotd_sock != -1)
 		close(gotd_sock);
 	if (error) {
blob - 180c362c726680bac4fbe3b5fd47dca9a5e166ae
blob + 437fff67924784d199bc37269ac367e71f2dc063
--- include/got_serve.h
+++ include/got_serve.h
@@ -17,5 +17,6 @@
 #define GOT_SERVE_CMD_SEND "git-receive-pack"
 #define GOT_SERVE_CMD_FETCH "git-upload-pack"
 
-const struct got_error *got_serve(int infd, int outfd, const char *gitcmd,
-    int gotd_sock, int chattygot);
+const struct got_error *got_serve_parse_command(char **, char **, const char *);
+const struct got_error *got_serve(int infd, int outfd, const char *command,
+    const char *repo_path, int gotd_sock, int chattygot);
blob - 8b6e7dae0d002c424ec5925b1f143e4f367f9b96
blob + 6664a0be413a6c6e1b9a90d98cea4891ccaf46c9
--- lib/serve.c
+++ lib/serve.c
@@ -64,8 +64,8 @@ static const struct got_capability write_capabilities[
 #endif
 };
 
-static const struct got_error *
-parse_command(char **command, char **repo_path, const char *gitcmd)
+const struct got_error *
+got_serve_parse_command(char **command, char **repo_path, const char *gitcmd)
 {
 	const struct got_error *err = NULL;
 	size_t len, cmdlen, pathlen;
@@ -1482,15 +1482,11 @@ done:
 }
 
 const struct got_error *
-got_serve(int infd, int outfd, const char *gitcmd, int gotd_sock, int chattygot)
+got_serve(int infd, int outfd, const char *command, const char *repo_path,
+    int gotd_sock, int chattygot)
 {
 	const struct got_error *err = NULL;
-	char *command = NULL, *repo_path = NULL;
 
-	err = parse_command(&command, &repo_path, gitcmd);
-	if (err)
-		return err;
-
 	if (strcmp(command, GOT_SERVE_CMD_FETCH) == 0)
 		err = serve_read(infd, outfd, gotd_sock, repo_path, chattygot);
 	else if (strcmp(command, GOT_SERVE_CMD_SEND) == 0)
@@ -1499,7 +1495,5 @@ got_serve(int infd, int outfd, const char *gitcmd, int
 	else
 		err = got_error(GOT_ERR_BAD_PACKET);
 
-	free(command);
-	free(repo_path);
 	return err;
 }