forgejo-aneksajo_auto_patch.../data/0/ref_aneksajo_u.diff
2025-01-23 01:26:39 +01:00

120 lines
4.6 KiB
Diff

--- 9.0.3 2024-12-12 08:06:13.000000000 +0100
+++ aneksajo 2024-12-16 08:23:15.000000000 +0100
@@ -38,6 +38,7 @@
const (
lfsAuthenticateVerb = "git-lfs-authenticate"
+ gitAnnexShellVerb = "git-annex-shell"
)
// CmdServ represents the available serv sub-command.
@@ -79,6 +80,7 @@
"git-upload-archive": perm.AccessModeRead,
"git-receive-pack": perm.AccessModeWrite,
lfsAuthenticateVerb: perm.AccessModeNone,
+ gitAnnexShellVerb: perm.AccessModeNone, // annex permissions are enforced by GIT_ANNEX_SHELL_READONLY, rather than the Gitea API
}
alphaDashDotPattern = regexp.MustCompile(`[^\w-\.]`)
)
@@ -212,6 +214,28 @@
}
}
+ if verb == gitAnnexShellVerb {
+ if !setting.Annex.Enabled {
+ return fail(ctx, "Unknown git command", "git-annex request over SSH denied, git-annex support is disabled")
+ }
+
+ if len(words) < 3 {
+ return fail(ctx, "Too few arguments", "Too few arguments in cmd: %s", cmd)
+ }
+
+ // git-annex always puts the repo in words[2], unlike most other
+ // git subcommands; and it sometimes names repos like /~/, as if
+ // $HOME should get expanded while also being rooted. e.g.:
+ // git-annex-shell 'configlist' '/~/user/repo'
+ // git-annex-shell 'sendkey' '/user/repo 'key'
+ repoPath = words[2]
+ repoPath = strings.TrimPrefix(repoPath, "/")
+ repoPath = strings.TrimPrefix(repoPath, "~/")
+ }
+
+ // prevent directory traversal attacks
+ repoPath = filepath.Clean("/" + repoPath)[1:]
+
rr := strings.SplitN(repoPath, "/", 2)
if len(rr) != 2 {
return fail(ctx, "Invalid repository path", "Invalid repository path: %v", repoPath)
@@ -225,6 +249,18 @@
// so that username and reponame are not affected.
repoPath = strings.ToLower(strings.TrimSpace(repoPath))
+ // put the sanitized repoPath back into the argument list for later
+ if verb == gitAnnexShellVerb {
+ // git-annex-shell demands an absolute path
+ absRepoPath, err := filepath.Abs(filepath.Join(setting.RepoRootPath, repoPath))
+ if err != nil {
+ return fail(ctx, "Error locating repoPath", "%v", err)
+ }
+ words[2] = absRepoPath
+ } else {
+ words[1] = repoPath
+ }
+
if alphaDashDotPattern.MatchString(reponame) {
return fail(ctx, "Invalid repo name", "Invalid repo name: %s", reponame)
}
@@ -303,21 +339,45 @@
return nil
}
- var gitcmd *exec.Cmd
- gitBinPath := filepath.Dir(git.GitExecutable) // e.g. /usr/bin
- gitBinVerb := filepath.Join(gitBinPath, verb) // e.g. /usr/bin/git-upload-pack
- if _, err := os.Stat(gitBinVerb); err != nil {
+ gitBinVerb, err := exec.LookPath(verb)
+ if err != nil {
// if the command "git-upload-pack" doesn't exist, try to split "git-upload-pack" to use the sub-command with git
// ps: Windows only has "git.exe" in the bin path, so Windows always uses this way
+ // ps: git-annex-shell and other extensions may not necessarily be in gitBinPath,
+ // but '{gitBinPath}/git annex-shell' should be able to find them on $PATH.
verbFields := strings.SplitN(verb, "-", 2)
if len(verbFields) == 2 {
// use git binary with the sub-command part: "C:\...\bin\git.exe", "upload-pack", ...
- gitcmd = exec.CommandContext(ctx, git.GitExecutable, verbFields[1], repoPath)
+ gitBinVerb = git.GitExecutable
+ words = append([]string{verbFields[1]}, words...)
}
}
- if gitcmd == nil {
- // by default, use the verb (it has been checked above by allowedCommands)
- gitcmd = exec.CommandContext(ctx, gitBinVerb, repoPath)
+
+ // by default, use the verb (it has been checked above by allowedCommands)
+ gitcmd := exec.CommandContext(ctx, gitBinVerb, words[1:]...)
+
+ if verb == gitAnnexShellVerb {
+ // This doesn't get its own isolated section like LFS does, because LFS
+ // is handled by internal Gitea routines, but git-annex has to be shelled out
+ // to like other git subcommands, so we need to build up gitcmd.
+
+ // TODO: does this work on Windows?
+ gitcmd.Env = append(gitcmd.Env,
+ // "If set, disallows running git-shell to handle unknown commands."
+ // - git-annex-shell(1)
+ "GIT_ANNEX_SHELL_LIMITED=True",
+ // "If set, git-annex-shell will refuse to run commands
+ // that do not operate on the specified directory."
+ // - git-annex-shell(1)
+ fmt.Sprintf("GIT_ANNEX_SHELL_DIRECTORY=%s", words[2]),
+ )
+ if results.UserMode < perm.AccessModeWrite {
+ // "If set, disallows any action that could modify the git-annex repository."
+ // - git-annex-shell(1)
+ // We set this when the backend API has told us that we don't have write permission to this repo.
+ log.Debug("Setting GIT_ANNEX_SHELL_READONLY=True")
+ gitcmd.Env = append(gitcmd.Env, "GIT_ANNEX_SHELL_READONLY=True")
+ }
}
process.SetSysProcAttribute(gitcmd)