git-run (1853B)
1 #!/usr/bin/env fish 2 3 # load common environment 4 source (status dirname)/env 5 6 set gitCommand 7 set repoDir 8 set currentUser (whoami) 9 10 ### 11 ### 12 ### functions 13 ### 14 ### 15 16 function log --on-event log 17 echo "$(date -Is): $argv[1..2] user=$currentUser $argv[3..] ip=$SSH_CONNECTION" >> $_LOG 18 end 19 20 function parseCommand 21 set -l matcher (string match -r -g $_GIT_VALIDATION_REGEX -- "$argv") 22 23 # check given git command 24 # basic form is <git-command> '<path-to-repo>' 25 if test (count $matcher) -ne 2 26 emit log DENY bad_format "argv=$argv" 27 return 1 28 end 29 30 # extract variables 31 set gitCommand $matcher[1] 32 33 # adjust repo path to /srv/repos 34 set repoDir /(string join -n '/' srv repos (string split '/' $matcher[2])) 35 end 36 37 function verifyRepoJail 38 set -l realPath (realpath $repoDir) 39 if not string match -r -q -- "/srv/repos/.*" "$realPath" 40 emit log DENY jail_escape "realPath=$realPath" 41 return 2 42 end 43 end 44 45 function verifyPermissions 46 set -l permission 47 switch "$gitCommand" 48 case "git-upload-pack" 49 # allow clone/fetch/pull 50 set permission [rw] 51 case "git-upload-archive" 52 # allow remote archive 53 set permission [rw] 54 case "git-receive-pack" 55 # only allow for write users 56 set permission [w] 57 case '*' 58 # this should not happend because we sanitize above the git command 59 emit log DENY unkown_git_command "gitCommand=$gitCommand" 60 return 3 61 end 62 63 # check for permissions 64 if not grep -q -E "^$repoDir:$currentUser:$permission\$" < $_REPO_PERMISSIONS_FILE 65 emit log DENY no_permissions 66 return 4 67 end 68 end 69 70 ### 71 ### 72 ### main 73 ### 74 ### 75 76 # redirect stdout/stderr to file, no information to potential attacker 77 begin 78 parseCommand $argv; or exit $status 79 80 verifyRepoJail; or exit $status 81 82 verifyPermissions; or exit $status 83 84 emit log ALLOW ok "argv=$argv" 85 end &>>$_LOG 86 87 exec /usr/bin/sudo -n -u git /usr/bin/git-shell -c "$gitCommand '$repoDir'"