I have been trying to figure this one out but I am having a hard time doing so. I am currently working on an open source project that requires me to allow a user to
You can write a wrapper script on the remote, and prepend command="/path/to/wrapper" to the authorized_keys' lines.
command="/usr/local/bin/gitaccess" ssh-rsa ...
In this wrapper you would check SSH_ORIGINAL_COMMAND. Git issues these commands:
git receive-pack '/path/provided' # when pushing
git upload-pack '/path/provided' # when pulling
If SSH_ORIGINAL_COMMAND is not empty and starts with one of these, you check the path, create the repository if necessary, install any configuration you need in it, and execute the command.
If SSH_ORIGINAL_COMMAND is empty and you want to provide users with shell access, you invoke a shell.
If SSH_ORIGINAL_COMMAND is not empty but doesn't start with a git command, if you want to allow users to have shell access, you just execute the command provided.
Here's a bit of Ruby code to demonstrate. Note that I didn't test it and there's room for improvement (for example we should not hardcode /bin/bash).
#!/usr/bin/env ruby
orig_command = ENV['SSH_ORIGINAL_COMMAND']
if orig_command.nil?
# If you want to preserve shell access
exec '/bin/bash' # not tested, I hope it's interactive if executed this way
end
cmd_parts = orig_command.match /([a-z-]+) '([a-z0-9.\/]+)'/
if cmd_parts.nil?
# If you want to preserve shell access
exec '/bin/bash', '-c', orig_command
end
command = cmd_parts[1]
path = '/var/repositories/'+cmd_parts[2] # not secured (could contain '..')
if command == 'git-receive-pack' || command == 'git-upload-pack'
if not File.directory?(path)
`git init --bare #{path}` # not secured, I didn't escape path
# Do any configuration here
end
exec 'git-shell', '-c', "#{command} '#{path}'"
end
# If you want to preserve shell access
exec '/bin/bash', '-c', orig_command
You can also pass an argument to this script in the authorized_keys to identify users and choose whether they should have shell access. I also do this to control access on a per-repository basis. If you want to carry this argument to the git hooks, just create an environment variable.