9c1c342df8a62ebc1020d303b0d93191dbf28cd4
- Author
- Ayman Bagabas <ayman.bagabas@gmail.com>
- Committer
- Ayman Bagabas <ayman.bagabas@gmail.com>
- Date
Message
Diff
This diff is truncated to protect this page.
1diff --git a/server/daemon.go b/server/daemon.go
2index 0055ff9c6ce05726dbdb39d3e51eaeabc5935be0..34600792da6c289c3cb860d30849a07bf73093b7 100644
3--- a/server/daemon.go
4+++ b/server/daemon.go
5@@ -5,10 +5,8 @@ import (
6 "context"
7 "errors"
8 "io"
9- "log"
10 "net"
11 "path/filepath"
12- "strings"
13 "sync"
14 "time"
15
16@@ -97,7 +95,7 @@ func (d *GitDaemon) Start() error {
17 case <-d.finished:
18 return ErrServerClosed
19 default:
20- log.Printf("git: error accepting connection: %v", err)
21+ logger.Debugf("git: error accepting connection: %v", err)
22 }
23 if ne, ok := err.(net.Error); ok && ne.Temporary() {
24 if tempDelay == 0 {
25@@ -116,7 +114,7 @@ func (d *GitDaemon) Start() error {
26
27 // Close connection if there are too many open connections.
28 if d.conns.Size()+1 >= d.cfg.Git.MaxConnections {
29- log.Printf("git: max connections reached, closing %s", conn.RemoteAddr())
30+ logger.Debugf("git: max connections reached, closing %s", conn.RemoteAddr())
31 fatal(conn, ErrMaxConnections)
32 continue
33 }
34@@ -132,7 +130,7 @@ func (d *GitDaemon) Start() error {
35 func fatal(c net.Conn, err error) {
36 WritePktline(c, err)
37 if err := c.Close(); err != nil {
38- log.Printf("git: error closing connection: %v", err)
39+ logger.Debugf("git: error closing connection: %v", err)
40 }
41 }
42
43@@ -162,7 +160,7 @@ func (d *GitDaemon) handleClient(conn net.Conn) {
44 if nerr, ok := err.(net.Error); ok && nerr.Timeout() {
45 fatal(c, ErrTimeout)
46 } else {
47- log.Printf("git: error scanning pktline: %v", err)
48+ logger.Debugf("git: error scanning pktline: %v", err)
49 fatal(c, ErrSystemMalfunction)
50 }
51 }
52@@ -174,7 +172,7 @@ func (d *GitDaemon) handleClient(conn net.Conn) {
53 select {
54 case <-ctx.Done():
55 if err := ctx.Err(); err != nil {
56- log.Printf("git: connection context error: %v", err)
57+ logger.Debugf("git: connection context error: %v", err)
58 }
59 return
60 case <-readc:
61@@ -186,7 +184,6 @@ func (d *GitDaemon) handleClient(conn net.Conn) {
62 }
63
64 var gitPack func(io.Reader, io.Writer, io.Writer, string) error
65- var repo string
66 cmd := string(split[0])
67 switch cmd {
68 case UploadPackBin:
69@@ -204,21 +201,26 @@ func (d *GitDaemon) handleClient(conn net.Conn) {
70 return
71 }
72
73- repo = filepath.Clean(string(opts[0]))
74- log.Printf("git: connect %s %s %s", c.RemoteAddr(), cmd, repo)
75- defer log.Printf("git: disconnect %s %s %s", c.RemoteAddr(), cmd, repo)
76- repo = strings.TrimPrefix(repo, "/")
77- auth := d.cfg.Access.AccessLevel(strings.TrimSuffix(repo, ".git"), nil)
78+ name := sanitizeRepoName(string(opts[0]))
79+ logger.Debugf("git: connect %s %s %s", c.RemoteAddr(), cmd, name)
80+ defer logger.Debugf("git: disconnect %s %s %s", c.RemoteAddr(), cmd, name)
81+ // git bare repositories should end in ".git"
82+ // https://git-scm.com/docs/gitrepository-layout
83+ repo := name + ".git"
84+ // FIXME: determine repositories path
85+ reposDir := filepath.Join(d.cfg.DataPath, "repos")
86+ if err := ensureWithin(reposDir, repo); err != nil {
87+ fatal(c, err)
88+ return
89+ }
90+
91+ auth := d.cfg.Access.AccessLevel(name, nil)
92 if auth < backend.ReadOnlyAccess {
93 fatal(c, ErrNotAuthed)
94 return
95 }
96- // git bare repositories should end in ".git"
97- // https://git-scm.com/docs/gitrepository-layout
98- repo = strings.TrimSuffix(repo, ".git") + ".git"
99- // FIXME: determine repositories path
100- repoDir := filepath.Join(d.cfg.DataPath, "repos", repo)
101- if err := gitPack(c, c, c, repoDir); err != nil {
102+
103+ if err := gitPack(c, c, c, filepath.Join(reposDir, repo)); err != nil {
104 fatal(c, err)
105diff --git a/server/git.go b/server/git.go
106index 812dddfc46c37f6952bcd2bfebaf7286a16d129e..1748f1ec4d7a1fcc6579a1b0ab7a1b6f4b726d2e 100644
107--- a/server/git.go
108+++ b/server/git.go
109@@ -4,10 +4,11 @@ import (
110 "errors"
111 "fmt"
112 "io"
113- "log"
114 "os"
115 "path/filepath"
116+ "strings"
117
118+ "github.com/charmbracelet/log"
119 "github.com/charmbracelet/soft-serve/git"
120 "github.com/go-git/go-git/v5/plumbing/format/pktline"
121 )
122@@ -90,13 +91,36 @@ func WritePktline(w io.Writer, v ...interface{}) {
123 msg := fmt.Sprintln(v...)
124 pkt := pktline.NewEncoder(w)
125 if err := pkt.EncodeString(msg); err != nil {
126- log.Printf("git: error writing pkt-line message: %s", err)
127+ log.Debugf("git: error writing pkt-line message: %s", err)
128 }
129 if err := pkt.Flush(); err != nil {
130- log.Printf("git: error flushing pkt-line message: %s", err)
131+ log.Debugf("git: error flushing pkt-line message: %s", err)
132 }
133 }
134
135+// ensureWithin ensures the given repo is within the repos directory.
136+func ensureWithin(reposDir string, repo string) error {
137+ repoDir := filepath.Join(reposDir, repo)
138+ absRepos, err := filepath.Abs(reposDir)
139+ if err != nil {
140+ log.Debugf("failed to get absolute path for repo: %s", err)
141+ return ErrSystemMalfunction
142+ }
143+ absRepo, err := filepath.Abs(repoDir)
144+ if err != nil {
145+ log.Debugf("failed to get absolute path for repos: %s", err)
146+ return ErrSystemMalfunction
147+ }
148+
149+ // ensure the repo is within the repos directory
150+ if !strings.HasPrefix(absRepo, absRepos) {
151+ log.Debugf("repo path is outside of repos directory: %s", absRepo)
152+ return ErrInvalidRepo
153+ }
154+
155+ return nil
156+}
157+
158 func fileExists(path string) (bool, error) {
159 _, err := os.Stat(path)
160 if err == nil {
161diff --git a/server/ssh.go b/server/ssh.go
162index 5a1752a4fbe92747787e224666070da295ed9df7..6f7898ca3f207c80b47ce7771784e5643aed5453 100644
163--- a/server/ssh.go
164+++ b/server/ssh.go
165@@ -2,7 +2,6 @@ package server
166
167 import (
168 "errors"
169- "fmt"
170 "path/filepath"
171 "strings"
172 "time"
173@@ -88,20 +87,21 @@ func (s *SSHServer) Middleware(cfg *config.Config) wish.Middleware {
174 if len(cmd) >= 2 && strings.HasPrefix(cmd[0], "git") {
175 gc := cmd[0]
176 // repo should be in the form of "repo.git"
177- repo := sanitizeRepoName(cmd[1])
178- name := repo
179- if strings.Contains(repo, "/") {
180- log.Printf("invalid repo: %s", repo)
181- sshFatal(s, fmt.Errorf("%s: %s", ErrInvalidRepo, "user repos not supported"))
182- return
183- }
184+ name := sanitizeRepoName(cmd[1])
185 pk := s.PublicKey()
186 access := cfg.Access.AccessLevel(name, pk)
187 // git bare repositories should end in ".git"
188 // https://git-scm.com/docs/gitrepository-layout
189- repo = strings.TrimSuffix(repo, ".git") + ".git"
190+ repo := name + ".git"
191+
192 // FIXME: determine repositories path
193- repoDir := filepath.Join(cfg.DataPath, "repos", repo)
194+ reposDir := filepath.Join(cfg.DataPath, "repos")
195+ if err := ensureWithin(reposDir, repo); err != nil {
196+ sshFatal(s, err)
197+ return
198+ }
199+
200+ repoDir := filepath.Join(reposDir, repo)
201 switch gc {
202 case ReceivePackBin:
203 if access < backend.ReadWriteAccess {