1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
|
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")
}
isOwner := repo.Owner.ID == user.ID
if repo.Private && !isOwner {
return fail("repository not found")
}
if verb == "git-receive-pack" && !isOwner {
return fail("you do not have write access to " + repo.Path())
}
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())
}
|