#!/usr/bin/env fish # load environment source (status dirname)/env # global variables set gitCommand set repoDir set currentUser (whoami) function log --on-event log echo "$(date -Is): $argv[1..2] user=$currentUser $argv[3..] ip=$SSH_CONNECTION" >> $_LOG end function parseCommand set -l matcher (string match -r -g $_GIT_VALIDATION_REGEX -- "$argv") # check given git command # basic form is '' if test (count $matcher) -ne 2 emit log DENY bad_format "argv=$argv" return 1 end # extract variables set gitCommand $matcher[1] # adjust repo path to /srv/repos set repoDir /(string join -n '/' srv repos (string split '/' $matcher[2])) end function verifyRepoJail set -l realPath (realpath $repoDir) if not string match -r -q -- "/srv/repos/.*" "$realPath" emit log 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 DENY unkown_git_command "gitCommand=$gitCommand" return 3 end # check for permissions if not grep -q -E "^$repoDir:$currentUser:$permission\$" < $_REPO_PERMISSIONS_FILE emit log DENY no_permissions return 4 end end # redirect stdout/stderr to file, no information to potential attacker begin parseCommand $argv; or exit $status verifyRepoJail; or exit $status verifyPermissions; or exit $status emit log ALLOW ok "argv=$argv" end &>>$_LOG exec /usr/bin/sudo -n -u git /usr/bin/git-shell -c "$gitCommand '$repoDir'"