summaryrefslogtreecommitdiff
path: root/src/git-run
blob: 8afed3ef781b26ab91ce71caf78af8d6832626fa (plain) (blame)
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
#!/usr/bin/env fish

# load environment
source (status dirname)/env

# global variables
set gitCommand
set repoDir
set currentUser (whoami)

function log --on-event log_event
	echo "$(date -Is): $argv[1..2] user=$currentUser $argv[3..] ip=$SSH_CONNECTION" >> $_LOG
end

function verifyGitCommand
	# check given git command
	# basic form is <git-command> '<path-to-repo>'
	if test (count $argv) -ne 2
		emit log_event DENY bad_format "argv=$argv"
		return 1
	end
end

function verifyRepoJail
	set -l realPath (realpath $repoDir)
	if not string match -r -q -- "/srv/repos/.*" "$realPath"
		emit log_event DENY jail_escape "realPath=$realPath"
		return 2
	end
end

function verifyPermissions
	set -l permission
	switch "$gitCommand"
		case "git-upload-pack"
			# allow clone/fetch/pull
			set permission [rw]
		case "git-upload-archive"
			# allow remote archive
			set permission [rw]
		case "git-receive-pack"
			# only allow for write users
			set permission [w]
		case '*'
			# this should not happend because we sanitize above the git command
			emit log_event DENY unkown_git_command "gitCommand=$gitCommand"
			return 3
	end

	# check for permissions
	if not cat $_REPO_PERMISSIONS_FILE | grep -q -E "^$repoDir:$currentUser:$permission\$"
		emit log_event DENY no_permissions
		return 4
	end
end

# redirect stdout/stderr to file, no information to potential attacker
begin
	# parse command
	set -l parsedCommand (string match -r -g $_GIT_VALIDATION_REGEX -- "$argv")

	verifyGitCommand $parsedCommand; or exit $status

	# extract variables
	set gitCommand $parsedCommand[1]

	# adjust repo path to /srv/repos
	set repoDir /(string join -n '/' srv repos (string split '/' $parsedCommand[2]))

	# check if realPath is in jail under /srv/repos
	verifyRepoJail; or exit $status
	
	# check for permissions needed
	verifyPermissions; or exit $status

	# info logging
	emit log_event ALLOW ok "argv=$argv"
end &>>$_LOG

# execute parsed git command
exec /usr/bin/sudo -n -u git /usr/bin/git-shell -c "$gitCommand '$repoDir'"