package main import ( "fmt" "os" "os/exec" "path/filepath" "strings" "syscall" ) func keys(root, binary string, args []string) int { if len(args) != 4 { return 1 } store, err := openStore(filepath.Join(root, "basin.db"), true) if err != nil { return 1 } user, err := store.UserByKey(args[2] + " " + args[3]) if err != nil { return 1 } fmt.Printf("command=\"%s -root %s shell %s\",restrict %s %s\n", binary, root, user.Name, args[2], args[3]) return 0 } func shell(root, name string) int { original := os.Getenv("SSH_ORIGINAL_COMMAND") fail := func(msg string) int { fmt.Fprintln(os.Stderr, msg) return 1 } if original == "" { return fail("hello " + name + ", this host only serves git") } verb, arg, ok := strings.Cut(original, " ") if !ok { return fail("unsupported command") } switch verb { case "git-upload-pack", "git-receive-pack", "git-upload-archive": default: return fail("unsupported command") } arg = strings.Trim(strings.TrimSpace(arg), "'\"") arg = strings.TrimPrefix(strings.TrimPrefix(arg, "/"), "~") arg = strings.TrimSuffix(arg, ".git") owner, repoName, ok := strings.Cut(arg, "/") if !ok || !validName(owner) || !validName(repoName) { return fail("repository path must be ~owner/repo") } store, err := openStore(filepath.Join(root, "basin.db"), true) if err != nil { return fail("database unavailable") } user, err := store.UserByName(name) if err != nil { return fail("unknown user") } repo, err := store.RepoByPath(owner, repoName) if err != nil { return fail("repository not found") } canWrite := store.CanWrite(repo, &user) if repo.Private && !canWrite { return fail("repository not found") } if verb == "git-receive-pack" && !canWrite { return fail("you do not have write access to " + repo.Path()) } if verb == "git-receive-pack" && repo.Archived { return fail("repository is archived and read only") } if verb == "git-receive-pack" { if over, used, quota := overQuota(root, repo.Owner.Name); over { return fail(quotaMessage(used, quota)) } } dir := filepath.Join(root, "repos", repo.Owner.Name, repo.Name+".git") git, err := exec.LookPath("git") if err != nil { return fail("git not installed") } env := []string{"PATH=" + os.Getenv("PATH"), "HOME=" + os.Getenv("HOME")} if p := os.Getenv("GIT_PROTOCOL"); p != "" { env = append(env, "GIT_PROTOCOL="+p) } err = syscall.Exec(git, []string{"git", strings.TrimPrefix(verb, "git-"), dir}, env) return fail(err.Error()) }