#!/usr/bin/env perl use strict; use warnings; use feature q{say}; my $GIT_COMMANDS = q{git-receive-pack|git-upload-pack|git-upload-archive}; my $OUR_COMMANDS = q{help|list}; my $GIT_SHELL = q{/usr/bin/git-shell}; local ($ENV{HOME}) = $ENV{HOME} =~ m/^(.*)$/msx; # Untaint path sub log_info { ## no critic (Subroutines::RequireArgUnpacking) open my $logfile, '>>', $ENV{HOME} . q{/bin/git-shell-wrapper.log} || die "Could not open log file!\n"; say {$logfile} @_; ## no critic (InputOutput::RequireCheckedSyscalls) my $ok = close $logfile; return; } sub allowed_repositories { my $list_cmd = $ENV{HOME} . q{/git-shell-commands/list}; my @paths = `$list_cmd`; ## no critic (InputOutput::ProhibitBacktickOperators) return map { m/^([^\n]+)$/msx; } @paths; } sub path_is_allowed { my $path = shift; return (grep { /^$path$/msx } allowed_repositories() ) == 1; } my $user = $ENV{USER}; log_info( q{User '}, $user, q{' logged in.} ); log_info( q{SSH_ORIGINAL_COMMAND: '}, $ENV{SSH_ORIGINAL_COMMAND}//q{}, q{'.} ); local ($ENV{PATH}) = $ENV{PATH} =~ m/^(.*)$/msx; # Untaint path my ($arg_cmd, $arg_par) = split q{ }, $ENV{SSH_ORIGINAL_COMMAND}//q{}; log_info( q{arg_cmd:}, $arg_cmd//q{} ); log_info( q{arg_par:}, $arg_par//q{} ); if( defined $arg_cmd ) { if( $arg_cmd =~ m/^(?:$GIT_COMMANDS)$/msx ) { my ($git_cmd) = $arg_cmd =~ m/^($GIT_COMMANDS)$/msx; # Untaint command if( defined $arg_par ) { my ($git_cmd_arg) = $arg_par =~ m/^(.+)$/msx; # Untaint my ($repo_path_candidate) = $git_cmd_arg =~ m/^'?([^']+)'?$/msx; # Can have ' around path. my ($repo_path) = grep { /^$repo_path_candidate$/msx } allowed_repositories(); if( defined $repo_path ) { log_info( q{repo_path: '}, $repo_path, q{'.} ); exec $GIT_SHELL, q{-c}, "$git_cmd '$repo_path'"; # Yes, git-shell wants the params as one! } else { die q{Repository '}, $repo_path_candidate, q{' not available!}, qq{\n}; } } else { die q{Command '}, $arg_cmd, q{' missing parameter !}, qq{\n}; } } elsif( $arg_cmd =~ m/^(?:$OUR_COMMANDS)$/msx ) { my ($our_cmd) = $arg_cmd =~ m/^($OUR_COMMANDS)$/msx; # Untaint command exec $GIT_SHELL, q{-c}, $our_cmd; } else { die q{Command '}, $arg_cmd, q{' not allowed!}, qq{\n}; } } else { exec $GIT_SHELL; }