func handleChannel(conn *ssh.ServerConn, newChan ssh.NewChannel) { ch, reqs, err := newChan.Accept() if err != nil { log.Println("newChan.Accept failed:", err) return } defer ch.Close() for req := range reqs { switch req.Type { case "exec": fail := func(at string, err error) { log.Printf("%s failed: %s", at, err) ch.Stderr().Write([]byte("Internal error.\n")) } if req.WantReply { req.Reply(true, nil) } cmdline := string(req.Payload[4:]) cmdargs, err := shlex.Split(cmdline) if err != nil || len(cmdargs) != 2 { ch.Stderr().Write([]byte("Invalid arguments.\n")) return } if cmdargs[0] != "git-receive-pack" { ch.Stderr().Write([]byte("Only `git push` is supported.\n")) return } cmdargs[1] = strings.TrimSuffix(strings.TrimPrefix(cmdargs[1], "/"), ".git") if strings.Contains(cmdargs[1], "..") { ch.Stderr().Write([]byte("Invalid repo.\n")) return } if err := ensureCacheRepo(cmdargs[1]); err != nil { fail("ensureCacheRepo", err) return } cmd := exec.Command("git-shell", "-c", cmdargs[0]+" '"+cmdargs[1]+"'") cmd.Dir = *repoPath cmd.Env = append(os.Environ(), "RECEIVE_USER="******"RECEIVE_REPO="+cmdargs[1], ) done, err := attachCmd(cmd, ch, ch.Stderr(), ch) if err != nil { fail("attachCmd", err) return } if err := cmd.Start(); err != nil { fail("cmd.Start", err) return } done.Wait() status, err := exitStatus(cmd.Wait()) if err != nil { fail("exitStatus", err) return } if _, err := ch.SendRequest("exit-status", false, ssh.Marshal(&status)); err != nil { fail("sendExit", err) } return case "env": if req.WantReply { req.Reply(true, nil) } } } }
func handleChannel(conn *ssh.ServerConn, newChan ssh.NewChannel) { ch, reqs, err := newChan.Accept() if err != nil { log.Println("newChan.Accept failed:", err) return } defer ch.Close() for req := range reqs { switch req.Type { case "exec": fail := func(at string, err error) { log.Printf("%s failed: %s", at, err) ch.Stderr().Write([]byte("Internal error.\n")) } if req.WantReply { req.Reply(true, nil) } cmdline := string(req.Payload[4:]) cmdargs, err := shlex.Split(cmdline) if err != nil || len(cmdargs) != 2 { ch.Stderr().Write([]byte("Invalid arguments.\n")) return } if cmdargs[0] != "git-receive-pack" { ch.Stderr().Write([]byte("Only `git push` is supported.\n")) return } cmdargs[1] = strings.TrimSuffix(strings.TrimPrefix(cmdargs[1], "/"), ".git") if strings.Contains(cmdargs[1], "..") { ch.Stderr().Write([]byte("Invalid repo.\n")) return } cacheKey := cmdargs[1] if *cacheKeyHook != "" { var result bytes.Buffer var errout bytes.Buffer cmd := exec.Command(*cacheKeyHook, cmdargs[0], cmdargs[1]) cmd.Stdout = &result cmd.Stderr = &errout if err := cmd.Run(); err != nil { fail("cacheKeyHook", errors.New(errout.String())) return } cacheKey = result.String() } tempDir := *repoPath if *useBlobstore { path, err := ioutil.TempDir("", "") if err != nil { fail("generateTempDir", err) return } tempDir = path } if err := ensureCacheRepo(tempDir, cacheKey); err != nil { fail("ensureCacheRepo", err) return } if *useBlobstore { if err := restoreBlobstoreCache(tempDir, cacheKey); err != nil { fail("restoreBlobstoreCache", err) return } } cmd := exec.Command("git-shell", "-c", cmdargs[0]+" '"+cacheKey+"'") cmd.Dir = tempDir cmd.Env = append(os.Environ(), "RECEIVE_USER="******"RECEIVE_REPO="+cmdargs[1], ) done, err := attachCmd(cmd, ch, ch.Stderr(), ch) if err != nil { fail("attachCmd", err) return } if err := cmd.Start(); err != nil { fail("cmd.Start", err) return } done.Wait() status, err := exitStatus(cmd.Wait()) if err != nil { fail("exitStatus", err) return } if *useBlobstore { if err := uploadCache(tempDir, cacheKey); err != nil { fail("uploadCache", err) } } if _, err := ch.SendRequest("exit-status", false, ssh.Marshal(&status)); err != nil { fail("sendExit", err) return } return case "env": if req.WantReply { req.Reply(true, nil) } } } }