shithub: git9

Download patch

ref: 1cd7d1dc7454536fdce66e87a5a78cead95ce03d
parent: 29bce68c99b7d73cf9b7956a797e8f2e737d8684
author: Ori Bernstein <ori@eigenstate.org>
date: Sun Aug 30 21:46:05 EDT 2020

git/{fetch,send}: add hjgit (tlsclient -a) protocol

hjgit://dialstr/repo/path will connect to a plan 9 git
server running behind tlsclient -a; this allows us to
have authenticated pushes with a plan 9 host.

--- a/fetch.c
+++ b/fetch.c
@@ -254,9 +254,7 @@
 void
 main(int argc, char **argv)
 {
-	char proto[Nproto], host[Nhost], port[Nport];
-	char repo[Nrepo], path[Npath];
-	int r, pfd;
+	int pfd;
 	Conn c;
 
 	ARGBEGIN{
@@ -271,25 +269,13 @@
 	if(argc != 1)
 		usage();
 
-	r = -1;
 	if(mkoutpath(packtmp) == -1)
 		sysfatal("could not create %s: %r", packtmp);
 	if((pfd = create(packtmp, ORDWR, 0644)) == -1)
 		sysfatal("could not create %s: %r", packtmp);
 
-	if(parseuri(argv[0], proto, host, port, path, repo) == -1)
-		sysfatal("bad uri %s", argv[0]);
-	if(strcmp(proto, "ssh") == 0 || strcmp(proto, "git+ssh") == 0)
-		r = dialssh(&c, host, port, path, "upload");
-	else if(strcmp(proto, "git") == 0)
-		r = dialgit(&c, host, port, path, "upload");
-	else if(strcmp(proto, "http") == 0 || strcmp(proto, "https") == 0)
-		r = dialhttp(&c, host, port, path, "upload");
-	else
-		sysfatal("unknown protocol %s", proto);
-	
-	if(r == -1)
-		sysfatal("could not dial %s:%s: %r", proto, host);
+	if(gitconnect(&c, argv[0]) == -1)
+		sysfatal("could not dial %s: %r", argv[0]);
 	if(fetchpack(&c, pfd, packtmp) == -1)
 		sysfatal("fetch failed: %r");
 	closeconn(&c);
--- a/git.h
+++ b/git.h
@@ -23,13 +23,6 @@
 	Pathmax		= 512,
 	Hashsz		= 20,
 	Pktmax		= 65536,
-
-	Nproto	= 16,
-	Nport	= 16,
-	Nhost	= 256,
-	Npath	= 128,
-	Nrepo	= 64,
-	Nbranch	= 32,
 };
 
 enum {
@@ -51,7 +44,8 @@
 };
 
 enum {
-	ConnRaw,
+	ConnGit,
+	ConnGit9,
 	ConnSsh,
 	ConnHttp,
 };
@@ -274,11 +268,8 @@
 int	readpkt(Conn*, char*, int);
 int	writepkt(Conn*, char*, int);
 int	flushpkt(Conn*);
-int	parseuri(char *, char *, char *, char *, char *, char *);
 void	initconn(Conn*, int, int);
-int	dialssh(Conn*, char *, char *, char *, char *);
-int	dialgit(Conn*, char *, char *, char *, char *);
-int	dialhttp(Conn*, char *, char *, char *, char *);
+int	gitconnect(Conn *, char *);
 int	readphase(Conn *);
 int	writephase(Conn *);
 void	closeconn(Conn *);
--- a/proto.c
+++ b/proto.c
@@ -7,6 +7,15 @@
 #define Contenthdr	"headers Content-Type: application/x-git-%s-pack-request"
 #define Accepthdr	"headers Accept: application/x-git-%s-pack-result"
 
+enum {
+	Nproto	= 16,
+	Nport	= 16,
+	Nhost	= 256,
+	Npath	= 128,
+	Nrepo	= 64,
+	Nbranch	= 32,
+};
+
 int chattygit;
 
 int
@@ -78,7 +87,7 @@
 
 }
 
-int
+static int
 parseuri(char *uri, char *proto, char *host, char *port, char *path, char *repo)
 {
 	char *s, *p, *q;
@@ -138,7 +147,7 @@
 	return 0;
 }
 
-int
+static int
 webclone(Conn *c, char *url)
 {
 	char buf[16];
@@ -167,7 +176,7 @@
 	return -1;
 }
 
-int
+static int
 webopen(Conn *c, char *file, int mode)
 {
 	char path[128];
@@ -179,7 +188,7 @@
 	return fd;
 }
 
-int
+static int
 issmarthttp(Conn *c, char *direction)
 {
 	char buf[Pktmax+1], svc[128];
@@ -200,7 +209,7 @@
 	return 0;
 }
 
-int
+static int
 dialhttp(Conn *c, char *host, char *port, char *path, char *direction)
 {
 	char *geturl, *suff, *hsep, *psep;
@@ -230,7 +239,7 @@
 	return 0;
 }
 
-int
+static int
 dialssh(Conn *c, char *host, char *, char *path, char *direction)
 {
 	int pid, pfd[2];
@@ -254,18 +263,59 @@
 		c->type = ConnSsh;
 		c->rfd = pfd[1];
 		c->wfd = dup(pfd[1], -1);
-		return 0;
 	}
-	return -1;
+	return 0;
 }
 
-int
+static int
+dialhjgit(Conn *c, char *host, char *port, char *path, char *direction)
+{
+	char *ds, *p, *e, cmd[512];
+	int pid, pfd[2];
+
+	if((ds = netmkaddr(host, "tcp", port)) == nil)
+		return -1;
+	if(pipe(pfd) == -1)
+		sysfatal("unable to open pipe: %r");
+	pid = fork();
+	if(pid == -1)
+		sysfatal("unable to fork");
+	if(pid == 0){
+		close(pfd[1]);
+		dup(pfd[0], 0);
+		dup(pfd[0], 1);
+		if(chattygit)
+			fprint(2, "exec tlsclient -a %s\n", ds);
+		execl("/bin/tlsclient", "tlsclient", "-a", ds, nil);
+		sysfatal("exec: %r");
+	}else{
+		close(pfd[0]);
+		p = cmd;
+		e = cmd + sizeof(cmd);
+		p = seprint(p, e - 1, "git-%s-pack %s", direction, path);
+		p = seprint(p + 1, e, "host=%s", host);
+		c->type = ConnGit9;
+		c->rfd = pfd[1];
+		c->wfd = dup(pfd[1], -1);
+		if(writepkt(c, cmd, p - cmd + 1) == -1){
+			fprint(2, "failed to write message\n");
+			close(c->rfd);
+			close(c->wfd);
+			return -1;
+		}
+	}
+	return 0;
+}
+
+
+static int
 dialgit(Conn *c, char *host, char *port, char *path, char *direction)
 {
 	char *ds, *p, *e, cmd[512];
 	int fd;
 
-	ds = netmkaddr(host, "tcp", port);
+	if((ds = netmkaddr(host, "tcp", port)) == nil)
+		return -1;
 	if(chattygit)
 		fprint(2, "dial %s git-%s-pack %s\n", ds, direction, path);
 	fd = dial(ds, nil, nil, nil);
@@ -275,7 +325,7 @@
 	e = cmd + sizeof(cmd);
 	p = seprint(p, e - 1, "git-%s-pack %s", direction, path);
 	p = seprint(p + 1, e, "host=%s", host);
-	c->type = ConnRaw;
+	c->type = ConnGit;
 	c->rfd = fd;
 	c->wfd = dup(fd, -1);
 	if(writepkt(c, cmd, p - cmd + 1) == -1){
@@ -289,12 +339,36 @@
 void
 initconn(Conn *c, int rd, int wr)
 {
-	c->type = ConnRaw;
+	c->type = ConnGit;
 	c->rfd = rd;
 	c->wfd = wr;
 }
 
 int
+gitconnect(Conn *c, char *uri)
+{
+	char proto[Nproto], host[Nhost], port[Nport];
+	char repo[Nrepo], path[Npath];
+
+	if(parseuri(uri, proto, host, port, path, repo) == -1){
+		werrstr("bad uri %s", uri);
+		return -1;
+	}
+
+	memset(c, 0, sizeof(Conn));
+	if(strcmp(proto, "ssh") == 0)
+		return dialssh(c, host, port, path, "receive");
+	else if(strcmp(proto, "git") == 0)
+		return dialgit(c, host, port, path, "receive");
+	else if(strcmp(proto, "hjgit") == 0)
+		return dialhjgit(c, host, port, path, "receive");
+	else if(strcmp(proto, "http") == 0 || strcmp(proto, "https") == 0)
+		return dialhttp(c, host, port, path, "receive");
+	werrstr("unknown protocol %s", proto);
+	return -1;
+}
+
+int
 writephase(Conn *c)
 {
 	char hdr[128];
@@ -344,8 +418,9 @@
 	close(c->rfd);
 	close(c->wfd);
 	switch(c->type){
-	case ConnRaw:
+	case ConnGit:
 		break;
+	case ConnGit9:
 	case ConnSsh:
 		free(wait());
 		break;
--- a/send.c
+++ b/send.c
@@ -413,11 +413,8 @@
 void
 main(int argc, char **argv)
 {
-	char proto[Nproto], host[Nhost], port[Nport];
-	char repo[Nrepo], path[Npath];
 	char *br;
 	Conn c;
-	int r;
 
 	ARGBEGIN{
 	default:
@@ -454,21 +451,8 @@
 	gitinit();
 	if(argc != 1)
 		usage();
-	r = -1;
-	if(parseuri(argv[0], proto, host, port, path, repo) == -1)
-		sysfatal("bad uri %s", argv[0]);
-
-	if(strcmp(proto, "ssh") == 0)
-		r = dialssh(&c, host, port, path, "receive");
-	else if(strcmp(proto, "git") == 0)
-		r = dialgit(&c, host, port, path, "receive");
-	else if(strcmp(proto, "http") == 0 || strcmp(proto, "https") == 0)
-		r = dialhttp(&c, host, port, path, "receive");
-	else
-		sysfatal("unknown protocol %s", proto);
-	
-	if(r == -1)
-		sysfatal("could not dial %s:%s: %r", proto, host);
+	if(gitconnect(&c, argv[0]) == -1)
+		sysfatal("git connect: %s: %r", argv[0]);
 	if(sendpack(&c) == -1)
 		sysfatal("send failed: %r");
 	closeconn(&c);