diff options
Diffstat (limited to 'git-daemon')
-rw-r--r-- | git-daemon/git-daemon-vhosts.pl | 4 | ||||
-rwxr-xr-x[-rw-r--r--] | git-daemon/git-daemon.pl | 95 |
2 files changed, 64 insertions, 35 deletions
diff --git a/git-daemon/git-daemon-vhosts.pl b/git-daemon/git-daemon-vhosts.pl index 4c6fb62..2046f9f 100644 --- a/git-daemon/git-daemon-vhosts.pl +++ b/git-daemon/git-daemon-vhosts.pl @@ -8,6 +8,10 @@ # git://HOSTNAME/REPO.git # git://HOSTNAME/~TILDE/REPO.git +$HOSTNAME = qr{[-.0-9a-z]+}; +$TILDE = qr{[0-9a-z]+}; +$REPO = qr{[-+._0-9A-Za-z]+}; + # The vhost_default_user hash specifies what user handles git requests # for each virtual host, if the URL does not have a tilde part, or if # the virtual host does not appear in the vhost_user_from_tilde hash. diff --git a/git-daemon/git-daemon.pl b/git-daemon/git-daemon.pl index f18f6b9..df753e1 100644..100755 --- a/git-daemon/git-daemon.pl +++ b/git-daemon/git-daemon.pl @@ -1,10 +1,10 @@ #!/usr/bin/perl # -# A very simple userv git-daemon wrapper. +# A git daemon with an added userv security boundary. # # This reads the first packet-line of the protocol, checks the syntax -# of the user, pathname, and hostname, then uses userv to invoke the -# real git daemon as the target user with safe arguments. +# of the pathname and hostname, then uses userv to invoke the +# git-upload-pack as the target user with safe arguments. # # This was written by Tony Finch <dot@dotat.at> # You may do anything with it, at your own risk. @@ -14,49 +14,74 @@ use strict; use warnings; use POSIX; +use Socket; +use Sys::Syslog; -my $USER = qr{[0-9a-z]+}; -my $PATH = qr{[-+,._/0-9A-Za-z]+}; -my $HOST = qr{[-.0-9A-Za-z]+}; +use vars qw{ %vhost_default_user %vhost_user_from_tilde + $TILDE $REPO $HOSTNAME }; + +use lib '/etc/userv'; +require 'git-daemon-vhosts.pl'; + +my $peer = getpeername STDIN; +my ($port,$addr); +if (defined $peer) { + ($port,$addr) = sockaddr_in $peer; + $addr = inet_ntoa $addr; + $peer = "[$addr]:$port"; +} else { + $peer = "[?.?.?.?]:?"; + undef $!; +} + +openlog 'userv-git-daemon', 'pid', 'daemon'; + +sub fail { + syslog 'err', "$peer @_"; + exit; +} sub xread { my $length = shift; my $buffer = ""; my $count = 0; + # simply die if the client takes too long + alarm 30; while ($length > length $buffer) { - my $data; - my $ret = sysread STDIN, $data, $len - while not defined $ret and ($! == EINTR or $! == EAGAIN); - die "read" unless defined $ret; - die "short read: expected $length bytes, got $count\n" if $ret == 0; - $buffer .= $data; - $count += $ret; + my ($data,$ret); + do { + $ret = sysread STDIN, $data, $length + } while not defined $ret and ($! == EINTR or $! == EAGAIN); + fail "read: $!" unless defined $ret; + fail "short read: expected $length bytes, got $count" if $ret == 0; + $buffer .= $data; + $count += $ret; } + alarm 0; return $buffer; } my $len_hex = xread 4; -die "bad packet length" unless $len_hex =~ m{^[0-9a-zA-Z]{4}$}; -my $len = hex $len; +fail "non-hexadecimal packet length" unless $len_hex =~ m{^[0-9a-zA-Z]{4}$}; +my $len = hex $len_hex; my $line = xread $len; -$line =~ m{^git-upload-pack ~($USER)/($PATH[.]git)\0host=($HOST)\0$}; -my ($user,$path,$host) = ($1,$2,$3); - -# child's output will go directly to inetd -open CHILD, '-|', 'userv', $user, - qw(git daemon --inetd --strict-paths - --user-path=public-git --forbid-override=receive-pack) - or die "open pipe to userv: $!\n"; - -# proxy command line to child -syswrite CHILD, $len_hex.$line - or die "write to userv: $!\n"; - -# relay stdin to child -open STDOUT, ">&CHILD" - or die "dup: $!\n"; -exec 'cat' - or die "exec: $!\n"; - -die +unless ($line =~ m{^git-upload-pack (?:~($TILDE)/)?($REPO[.]git)\0host=($HOSTNAME)\0$}) { + $line =~ s/[^ -~]+/ /g; + fail "could not parse \"$line\"" +} +my ($tilde,$repo,$host) = ($1,$2,$3); +my $url = $tilde ? "git://$host/~$tilde/$repo" : "git://$host/$repo"; + +my $user = $vhost_user_from_tilde{$host} ? $tilde : $vhost_default_user{$host}; +fail "no user configuration for $url" unless defined $user; + +syslog 'info', "$peer $user $url"; + +my @opts = ("-DCLIENT=$addr", "-DHOST=$host", "-DREPO=$repo"); +push @opts, "-DTILDE=$tilde" if defined $tilde; + +exec 'userv', @opts, $user, 'git-upload-pack' + or fail "exec userv: $!"; + +# end |