ref: 674a47f7bfced5a91c621d139b0551826fae299a
parent: ace4e4defa70671fc0747c9899cfa80036efbb3d
author: Ori Bernstein <ori@eigenstate.org>
date: Sat Feb 3 10:06:38 EST 2024
git/serve: provide better errors
--- a/sys/src/cmd/git/serve.c
+++ b/sys/src/cmd/git/serve.c
@@ -8,6 +8,19 @@
char *pathpfx = nil;
int allowwrite;
+_Noreturn static void
+fail(Conn *c, char *fmt, ...)
+{
+ char msg[ERRMAX];
+ va_list ap;
+
+ va_start(ap, fmt);
+ vsnprint(msg, sizeof(msg), fmt, ap);
+ va_end(ap);
+ fmtpkt(c, "ERR %s\n", msg);
+ sysfatal("%s", msg);
+}
+
int
showrefs(Conn *c)
{
@@ -24,7 +37,7 @@
goto error;
if((nrefs = listrefs(&refs, &names)) == -1)
- sysfatal("listrefs: %r");
+ fail(c, "listrefs: %r");
for(i = 0; i < nrefs; i++){
if(strncmp(names[i], "heads/", strlen("heads/")) != 0)
continue;
@@ -128,10 +141,10 @@
dprint(1, "negotiating pack\n");
if(servnegotiate(c, &head, &nhead, &tail, &ntail) == -1)
- sysfatal("negotiate: %r");
+ fail(c, "negotiate: %r");
dprint(1, "writing pack\n");
if(writepack(c->wfd, head, nhead, tail, ntail, &h) == -1)
- sysfatal("send: %r");
+ fail(c, "send: %r");
return 0;
}
@@ -138,6 +151,7 @@
int
validref(char *s)
{
+ cleanname(s);
if(strncmp(s, "refs/", 5) != 0)
return 0;
for(; *s != '\0'; s++)
@@ -149,7 +163,7 @@
int
recvnegotiate(Conn *c, Hash **cur, Hash **upd, char ***ref, int *nupd)
{
- char pkt[Pktmax], *sp[4];
+ char pkt[Pktmax], refpath[512], *sp[4];
Hash old, new;
int n, i;
@@ -186,6 +200,16 @@
(*cur)[*nupd] = old;
(*upd)[*nupd] = new;
(*ref)[*nupd] = estrdup(sp[2]);
+ n = snprint(refpath, sizeof(refpath), ".git/%s", sp[2]);
+ if(n >= sizeof(refpath)-1){
+ fmtpkt(c, "ERR invalid ref %s\n", sp[2]);
+ goto error;
+ }
+ if(access(refpath, AWRITE) == -1
+ && access(refpath, AEXIST) == 0){
+ fmtpkt(c, "ERR read-only ref %s\n", sp[2]);
+ goto error;
+ }
*nupd += 1;
}
return 0;
@@ -446,8 +470,10 @@
char **ref;
int nupd;
+ if(!allowwrite)
+ fail(c, "read-only repo");
if(recvnegotiate(c, &cur, &upd, &ref, &nupd) == -1)
- sysfatal("negotiate refs: %r");
+ fail(c, "negotiate refs: %r");
if(nupd != 0 && updatepack(c) == -1)
sysfatal("update pack: %r");
if(nupd != 0 && updaterefs(c, cur, upd, ref, nupd) == -1)
@@ -520,20 +546,18 @@
repo = parsecmd(buf, cmd, sizeof(cmd));
cleanname(repo);
if(strncmp(repo, "../", 3) == 0)
- sysfatal("invalid path %s\n", repo);
- if(bind(repo, "/", MREPL) == -1){
- fmtpkt(&c, "ERR no repo %r\n");
- sysfatal("enter %s: %r", repo);
- }
+ fail(&c, "invalid path %s\n", repo);
+ if(bind(repo, "/", MREPL) == -1)
+ fail(&c, "no such repo", repo);
if(chdir("/") == -1)
- sysfatal("chdir: %r");
+ fail(&c, "no such repo");
if(access(".git", AREAD) == -1)
- sysfatal("no git repository");
- if(strcmp(cmd, "git-receive-pack") == 0 && allowwrite)
+ fail(&c, "no such repo");
+ if(strcmp(cmd, "git-receive-pack") == 0)
recvpack(&c);
else if(strcmp(cmd, "git-upload-pack") == 0)
servpack(&c);
else
- sysfatal("unsupported command '%s'", cmd);
+ fail(&c, "unsupported command '%s'", cmd);
exits(nil);
}