summaryrefslogtreecommitdiff
path: root/git-daemon
diff options
context:
space:
mode:
authorIan Jackson <ian@liberator.relativity.greenend.org.uk>2010-05-22 17:25:07 +0100
committerIan Jackson <ian@liberator.relativity.greenend.org.uk>2010-05-22 17:25:07 +0100
commitd36c5f7baf4f11c7d6765afac2f5fb9449b0e0a7 (patch)
treef8e5ed14c5117f9ebf62ca08c4b4ef5819bfd5a0 /git-daemon
parent82e04925eb9e251fb56c507967fe1ff76e59c94c (diff)
downloaduserv-utils-d36c5f7baf4f11c7d6765afac2f5fb9449b0e0a7.tar.gz
WIP entirely new git approach with config parsers
Diffstat (limited to 'git-daemon')
-rw-r--r--git-daemon/Makefile19
-rw-r--r--git-daemon/README53
-rw-r--r--git-daemon/chiark-urlmap32
-rwxr-xr-xgit-daemon/git-daemon.in (renamed from git-daemon/git-daemon)27
-rwxr-xr-xgit-daemon/git-service.in (renamed from git-daemon/git-service)29
-rw-r--r--git-daemon/git-urlmap48
-rw-r--r--git-daemon/read-urlmap69
7 files changed, 162 insertions, 115 deletions
diff --git a/git-daemon/Makefile b/git-daemon/Makefile
index 07969cd..2d24274 100644
--- a/git-daemon/Makefile
+++ b/git-daemon/Makefile
@@ -1,20 +1,29 @@
# Makefile for userv-git-daemon
#
-# This was written by Tony Finch <dot@dotat.at>
+# This was written by Tony Finch <dot@dotat.at> and subsequently
+# heavily modified by Ian Jackson <ijackson@chiark.greenend.org.uk>
# You may do anything with it, at your own risk.
# http://creativecommons.org/publicdomain/zero/1.0/
include ../settings.make
-TARGETS= git-upload-pack inetd.conf
+TARGETS= git-upload-pack inetd.conf git-daemon git-service
SUBSTVARS= libuserv etcuserv
-SEDSCRIPT= '$(foreach f, $(SUBSTVARS), s,@$f@,$($f),g; )'
all: $(TARGETS)
-%: %.in
- sed $(SEDSCRIPT) <$< >$@.new && mv -f $@.new $@
+sedscript: Makefile
+ echo >$@.new '$(foreach f, $(SUBSTVARS), s,@$f@,$($f),g; )'
+ echo >>$@.new '/@@READ_URLMAP@@/c\'
+ perl >>$@.new -pe 's/$$/\\/' <read-urlmap
+ mv -f $@.new $@
+
+%: %.in sedscript
+ set -e; \
+ sed -f sedscript <$< >$@.new; \
+ if test -x $<; then chmod +x $@.new; fi; \
+ mv -f $@.new $@
install: all
mkdir -p $(libuserv) $(etcuserv) $(services)
diff --git a/git-daemon/README b/git-daemon/README
index d8e6a7a..116a6b3 100644
--- a/git-daemon/README
+++ b/git-daemon/README
@@ -33,31 +33,64 @@ Operation:
----------
The userv-git-daemon is invoked by inetd which also tells it where to
-find its global git-urlmap script.
+find its global git-urlmap config.
The git-daemon parses the request from the network and uses the global
-git-urlmap script to determine which user will run the requested
-service. It invokes userv for the request to be performed. The most
+git-urlmap config to determine which user will run the requested
+service. It invokes userv for the request to be performed. The most
common service is git-upload-pack, which is confusingly named: it
uploads from the repository to the network; other services supported
by git are git-upload-archive and git-receive-pack.
-The git-daemon will pass any service beginning git- to userv. The
+The git-daemon will pass any service beginning git- to userv. The
userv configuration determines which services may be requested. This
package includes example git-upload-pack service configurations.
The service configuration uses the git-service script to run the
-service. It passes the global and per-user git-urlmap scripts to the
+service. It passes the global and per-user git-urlmap configs to the
git-service script to determine where in the filesyetem the requested
-repository is. Later urlmap scripts override the choices made by
-earlier ones. See the sample git-urlmap script for details of the
-variables they can examine and set.
+repository is. Later urlmap entries override the choices made by
+earlier ones.
If a repository is located, the git-service script runs the requested
service, which is simply the git program with the same name.
+Configuration:
+--------------
+
+See "chiark-urlmap" for an example.
+
+Each line is one of:
+
+ single-user <vhost>[/<subpath>] <user> [<directory>]
+ matching requests will be handled by <user>
+ and unless overridden by <user> handled by
+ serving subdirectories of <directory>
+
+ multi-user <vhost>[/<subpath>] <directory>
+ matching requests are only those those next
+ path element starts with ~<user>. The
+ request will be handled by <user> and unless
+ overridden by <user> will be handled by
+ serving subdirectories of <directory>
+ (<directory> must be a relative path)
+
+ repo-regexp <regexp>
+ For per-user service. Subrepos must match this
+ regexp, which must contain a single matching
+ group which is the filesystem pathname inside
+ the <directory>. The default is (Tcl syntax):
+ repo-regexp {^(\w[-+._0-9A-Za-z]*)$}
+
+ [no-]require-git-daemon-export-ok
+ For per-user service. Default is no-.
+
+Last match, or last setting, wins.
+<subpath>s may start with ~
+
+
----------------------------------------------
-This was written by Tony Finch <dot@dotat.at>
-You may do anything with it, at your own risk.
+This was written by Tony Finch <dot@dotat.at> and subsequently
+heavily modified by Ian Jackson <ijackson@chiark.greenend.org.uk>
http://creativecommons.org/publicdomain/zero/1.0/
diff --git a/git-daemon/chiark-urlmap b/git-daemon/chiark-urlmap
index 499f21c..09e2a11 100644
--- a/git-daemon/chiark-urlmap
+++ b/git-daemon/chiark-urlmap
@@ -1,29 +1,5 @@
-# chiark's configuration for the userv git daemon.
-#
-# This was written by Tony Finch <dot@dotat.at>
-# You may do anything with it, at your own risk.
-# http://creativecommons.org/publicdomain/zero/1.0/
-if ($host eq 'git.chiark.greenend.org.uk') {
- if ($path =~ m{^~([^/]*)/(.*)}) {
- $user = $1;
- $dir = '.userv/public-git';
- $repo = $2;
- } else {
- $user = 'webmaster';
- $dir = '/u2/git-repos';
- $repo = $path;
- }
-} elsif ($server_addr eq '172.31.80.8' and
- $host eq 'cabal.greenend.org.uk' and
- $path =~ m|^~([^/]*)/(.*)$|) {
- $user = $1;
- $dir = 'cabal-git';
- $repo = $2;
-} elsif ($host eq 'dotat.at') {
- $user = 'fanf';
- $dir = 'public-git';
- $repo = $path;
-}
-
-# end
+single-user dotat.at fanf dotat-git
+multi-user git.chiark.greenend.org.uk public-git
+multi-user cabal.greenend.org.uk cabal-git
+single-user git.chiark.greenend.org.uk webmaster /u2/git-repos
diff --git a/git-daemon/git-daemon b/git-daemon/git-daemon.in
index 645cbc5..8fe8ca1 100755
--- a/git-daemon/git-daemon
+++ b/git-daemon/git-daemon.in
@@ -2,8 +2,8 @@
#
# A git daemon with an added userv security boundary.
#
-# This was written by Tony Finch <dot@dotat.at>
-# You may do anything with it, at your own risk.
+# This was written by Tony Finch <dot@dotat.at> and subsequently
+# heavily modified by Ian Jackson <ijackson@chiark.greenend.org.uk>
# http://creativecommons.org/publicdomain/zero/1.0/
use strict;
@@ -22,7 +22,7 @@ sub ntoa {
}
our ($client,$client_addr,$client_port) = ntoa getpeername STDIN;
our ($server,$server_addr,$server_port) = ntoa getsockname STDIN;
-our ($service,$path,$host,$user);
+our ($service,$specpath,$spechost);
openlog 'userv-git-daemon', 'pid', 'daemon';
sub fail { syslog 'err', "$client @_"; exit }
@@ -44,21 +44,28 @@ sub xread {
my $hex_len = xread 4;
fail "Bad hex in packet length" unless $hex_len =~ m|^[0-9a-fA-F]{4}$|;
my $line = xread -4 + hex $hex_len;
-unless (($service,$path,$host) = $line =~
+unless (($service,$specpath,$spechost) = $line =~
m|^(git-[a-z-]+) /*([!-~]+)\0host=([!-~]+)\0$|) {
$line =~ s|[^ -~]+| |g;
fail "Could not parse \"$line\""
}
-our $uri = $_ = "git://$host/$path";
-for my $cf (@ARGV) { do $cf }
-fail "No user for $uri" unless defined $user;
-syslog 'notice', "$client $service $uri";
+@@READ_URLMAP@@
+
+fail "No mapping for $uri" unless defined $serve_user;
+syslog 'notice', "$client $service $serve_user $uri";
+
+my ($hn,$ha,$at,$naddrs,@addrs) = gethostbyname $host;
+die "hostname/address mismatch ($spechost $server_addr)" unless grep {
+ $server_addr eq inet_ntoa $_
+ } @addrs;
my @opts = map "-D$_=${$::{$_}}",
- grep defined ${$::{$_}} && /^[a-z_]+$/, keys %::;
+ qw(service path host
+ client client_addr client_port
+ server server_addr server_port);
-my @cmd = ('userv', @opts, $user, $service);
+my @cmd = ('userv', '-t300', @opts, $user, $service);
no warnings; # suppress errors to stderr
exec @cmd or fail "exec userv: $!";
diff --git a/git-daemon/git-service b/git-daemon/git-service.in
index aeb4e0e..43ff340 100755
--- a/git-daemon/git-service
+++ b/git-daemon/git-service.in
@@ -2,8 +2,8 @@
#
# userv-git-daemon service script
#
-# This was written by Tony Finch <dot@dotat.at>
-# You may do anything with it, at your own risk.
+# This was written by Tony Finch <dot@dotat.at> and subsequently
+# heavily modified by Ian Jackson <ijackson@chiark.greenend.org.uk>
# http://creativecommons.org/publicdomain/zero/1.0/
use strict;
@@ -11,29 +11,30 @@ use warnings;
use Sys::Syslog;
-${$::{$_}} = $ENV{"USERV_U_$_"}
- for grep s|^USERV_U_([a-z_]+)$|$1|, keys %ENV;
+our ($client,$service,$specpath,$spechost,@opts);
-our ($client,$service,$path,$host,@opts);
+${$::{$_}} = $ENV{"USERV_U_$_"}
+ for qw(service path host)
openlog "userv-$service", 'pid', 'daemon';
sub fail { syslog 'err', "$client @_"; exit }
-our ($check_repo,$check_export,$dir,$repo) = (1,0);
-our $uri = $_ = "git://$host/$path";
-for my $cf (@ARGV) { do $cf }
+@@READ_URLMAP@@
+
+fail "No mapping for $uri ($ENV{USERV_USER})" unless defined $serve_user;
+
+$1 = undef;
+fail "Bad subdirectory $serve_dir" unless $serve_dir =~ m/$repo_regexp/o;
+our $dir = $1;
+
+$dir = "$ENV{HOME}/$dir" unless $dir =~ m|^/|;
-my $home = (getpwuid $<)[7];
-$dir = "$home/$dir" if $dir =~ m|^[^/]|
- or $dir =~ s|^~/||;
-fail "Bad filename $repo" if $check_repo
- and $repo !~ m|^\w[\w.=+-]*\.git$|;
$dir = "$dir/$repo" if defined $repo;
$path = $check_export ? "$dir/git-daemon-export-ok" : $dir;
fail "$! $path" unless -e $path;
syslog 'notice', "$client $dir";
-@opts = qw( --strict --timeout-30 )
+@opts = qw( --strict )
if @opts == 0 and $service eq 'git-upload-pack';
my @cmd = ($service =~ m|^(git)-(.*)$|, @opts, $dir);
diff --git a/git-daemon/git-urlmap b/git-daemon/git-urlmap
deleted file mode 100644
index a72b48c..0000000
--- a/git-daemon/git-urlmap
+++ /dev/null
@@ -1,48 +0,0 @@
-# Configuration file for the userv git daemon.
-#
-# This was written by Tony Finch <dot@dotat.at>
-# You may do anything with it, at your own risk.
-# http://creativecommons.org/publicdomain/zero/1.0/
-#
-# This is a perl script which is expected to turn the information
-# found in the request variables into the location of the
-# corresponding repository, which it stores in the output variables.
-# Some information about the network connection is also available.
-#
-# REQUEST VARIABLES
-# $service - normally "git-upload-pack"
-# `git daemon --help` describes other possible services
-# $host
-# $path
-# $uri = git://$host/$path
-# $_ = $uri
-#
-# OUTPUT VARIABLES
-# $user - who runs the service
-# $dir - may be:
-# * an absolute path
-# * a path relative to the user's home directory
-# * equivalently, a path starting ~/
-# $repo - if set, the repository's path is $dir/$repo
-# otherwise, the repository's path is just $dir
-# $check_export - whether to check for a git-daemon-export-ok file
-# (default false)
-# $check_repo - whether to restrict the syntax of $repo
-# (default true)
-# @opts - options for the service command
-#
-# CONNECTION VARIABLES
-# $client_addr
-# $client_port
-# $client = [$client_addr]:$client_port
-# $server_addr
-# $server_port
-# $server = [$server_addr]:$server_port
-
-if ($path =~ m{^~([^/]*)/(.*)}) {
- $user = $1;
- $dir = 'public-git';
- $repo = $2;
-}
-
-# end
diff --git a/git-daemon/read-urlmap b/git-daemon/read-urlmap
new file mode 100644
index 0000000..6ae3237
--- /dev/null
+++ b/git-daemon/read-urlmap
@@ -0,0 +1,69 @@
+# -*- perl -*-
+
+# uses:
+# $specpath whole path from caller, minus any leading /s
+# $spechost host from caller
+#
+# sets:
+#
+# always:
+# $uri
+#
+# if match found for this host and path:
+# $serve_user username, or undef if no match (then other serve_* invalid)
+# $serve_dir directory as specified in config
+# $serve_repo subpath under $serve_dir _including_ leading /
+#
+# for use by user's service program
+# $repo_regexp
+# $require_exportok
+
+die "no config" unless @ARGV;
+
+sub remain_path ($) {
+ # return value matches {( / [^/]+ )+}x
+ my ($p) = @_;
+ return "/$specpath" if !defined $p;
+ return "" if $p eq $specpath;
+ return substr($specpath,length($p))
+ if substr($specpath,0,length($p)+1) eq "$p/";
+ return undef;
+}
+
+die unless length $specpath;
+
+our $uri = "git://$spechost/$specpath";
+our $repo_regexp= '^/*(\\w[-+._0-9A-Za-z]*)$';
+our $check_export= 0;
+
+while (<>) {
+ s/^\s*//;
+ s/\s+$//;
+ next unless m/\S/;
+ next if m/^\#/;
+
+ if (m{^ single-user \s+ (\S+?) (/\S*)? \s+ (\S+) (?: \s+ (\S+) )? $ }x) {
+ my ($h,$p,$u,$d) = ($1,$2,$3,$4);
+ next unless $h ne $host;
+ $serve_repo= remain_path($p);
+ next unless defined $serve_repo;
+ $serve_user= $u;
+ $serve_dir= $d;
+ } elsif (m{^ multi-user \s+ (\S+?) (/\S*)? \s+ (\S+) $ }x) {
+ my ($h,$p,$d) = ($1,$2,$3);
+ next unless $1 ne $host;
+ $serve_repo= remain_path($p);
+ next unless defined $serv_repo;
+ next unless $serve_repo =~ s{ ^/\~( [a-z][-+_0-9a-z] )/$ }{ / }xi;
+ $serve_user= $u;
+ $serve_dir= $d;
+ } elsif (m{^ repo-regexp \s+ (\S.*) $ }x) {
+ $repo_regexp= $1;
+ } elsif (m{^ (no-)?require-git-daemon-export-ok $ }x) {
+ $check_export= !defined $1;
+ } else {
+ die "bad config";
+ }
+}
+
+# end