2009-08-25 05:14:46 +02:00
|
|
|
#!/usr/bin/perl
|
2009-08-23 07:35:14 +02:00
|
|
|
|
|
|
|
use strict;
|
2009-08-25 05:14:46 +02:00
|
|
|
use warnings;
|
2009-08-23 10:16:45 +02:00
|
|
|
use Data::Dumper;
|
2009-09-18 14:30:14 +02:00
|
|
|
$Data::Dumper::Indent = 1;
|
2009-08-23 07:35:14 +02:00
|
|
|
|
|
|
|
# === add-auth-keys ===
|
|
|
|
|
2009-08-26 02:47:27 +02:00
|
|
|
# part of the gitolite (GL) suite
|
2009-08-23 07:35:14 +02:00
|
|
|
|
2009-08-23 10:16:45 +02:00
|
|
|
# (1) - "compiles" ~/.ssh/authorized_keys from the list of pub-keys
|
|
|
|
# (2) - also "compiles" the user-friendly GL conf file into something easier
|
|
|
|
# to parse. We're doing this because both the gl-auth-command and the
|
|
|
|
# (gl-)update hook need this, and it seems easier to do this than
|
|
|
|
# replicate the parsing code in both those places. As a bonus, it's
|
|
|
|
# probably more efficient.
|
2009-09-25 08:47:33 +02:00
|
|
|
# (3) - finally does what I have resisted doing all along -- handle gitweb and
|
|
|
|
# git-daemon access. It won't *setup* gitweb/daemon for you -- you have
|
|
|
|
# to that yourself. What this does is make sure that "repo.git"
|
|
|
|
# contains the file "git-daemon-export-ok" (for daemon case) and the
|
|
|
|
# line "repo.git" exists in the "projects.list" file (for gitweb case).
|
2009-08-23 10:16:45 +02:00
|
|
|
|
2009-08-23 07:35:14 +02:00
|
|
|
# how run: manual, by GL admin
|
2009-08-23 10:16:45 +02:00
|
|
|
# when:
|
2009-08-23 11:25:50 +02:00
|
|
|
# - anytime a pubkey is added/deleted
|
2009-08-26 02:47:27 +02:00
|
|
|
# - anytime gitolite.conf is changed
|
2009-08-23 10:16:45 +02:00
|
|
|
# input:
|
2009-08-26 02:47:27 +02:00
|
|
|
# - GL_CONF (default: ~/.gitolite/gitolite.conf)
|
|
|
|
# - GL_KEYDIR (default: ~/.gitolite/keydir)
|
2009-08-23 10:16:45 +02:00
|
|
|
# output:
|
2009-08-23 11:25:50 +02:00
|
|
|
# - ~/.ssh/authorized_keys (dictated by sshd)
|
2009-08-26 02:47:27 +02:00
|
|
|
# - GL_CONF_COMPILED (default: ~/.gitolite/gitolite.conf-compiled.pm)
|
2009-08-23 07:35:14 +02:00
|
|
|
# security:
|
|
|
|
# - touches a very critical system file that manages the restrictions on
|
|
|
|
# incoming users. Be sure to audit AUTH_COMMAND and AUTH_OPTIONS (see
|
|
|
|
# below) on any change to this script
|
|
|
|
# - no security checks within program. The GL admin runs this manually
|
|
|
|
|
2009-08-23 10:16:45 +02:00
|
|
|
# warnings:
|
2009-08-23 07:35:14 +02:00
|
|
|
# - if the "start" line exists, but the "end" line does not, you lose the
|
|
|
|
# rest of the existing authkey file. In general, "don't do that (TM)",
|
|
|
|
# but we do have a "vim -d" popping up so you can see the changes being
|
|
|
|
# made, just in case...
|
|
|
|
|
2009-08-23 11:25:50 +02:00
|
|
|
# ----------------------------------------------------------------------------
|
|
|
|
# common definitions
|
|
|
|
# ----------------------------------------------------------------------------
|
|
|
|
|
2009-09-25 08:47:33 +02:00
|
|
|
our ($GL_ADMINDIR, $GL_CONF, $GL_KEYDIR, $GL_CONF_COMPILED, $REPO_BASE, $REPO_UMASK, $PROJECTS_LIST);
|
2009-08-23 11:25:50 +02:00
|
|
|
|
2009-09-15 17:32:23 +02:00
|
|
|
# now that this thing *may* be run via "push to admin", any errors have to
|
|
|
|
# grab the admin's ATTENTION so he won't miss them among the other messages a
|
|
|
|
# typical push generates
|
2009-09-17 07:09:13 +02:00
|
|
|
my $ATTN = "\n\t\t***** ERROR *****\n ";
|
2009-09-15 17:32:23 +02:00
|
|
|
|
2009-08-26 02:47:27 +02:00
|
|
|
my $glrc = $ENV{HOME} . "/.gitolite.rc";
|
2009-09-15 17:32:23 +02:00
|
|
|
die "$ATTN parse $glrc failed: " . ($! or $@) unless do $glrc;
|
2009-08-23 11:25:50 +02:00
|
|
|
|
|
|
|
# ----------------------------------------------------------------------------
|
|
|
|
# definitions specific to this program
|
|
|
|
# ----------------------------------------------------------------------------
|
2009-08-23 07:35:14 +02:00
|
|
|
|
|
|
|
# command and options for authorized_keys
|
2009-08-27 11:54:08 +02:00
|
|
|
my $AUTH_COMMAND="$GL_ADMINDIR/src/gl-auth-command";
|
2009-08-25 05:38:11 +02:00
|
|
|
my $AUTH_OPTIONS="no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty";
|
2009-09-15 17:37:00 +02:00
|
|
|
# note that REPONAME_PATT allows a "/" also, which USERNAME_PATT doesn't
|
|
|
|
my $REPONAME_PATT=qr(^\@?[0-9a-zA-Z][0-9a-zA-Z._/-]*$); # very simple pattern
|
|
|
|
my $USERNAME_PATT=qr(^\@?[0-9a-zA-Z][0-9a-zA-Z._-]*$); # very simple pattern
|
2009-08-23 07:35:14 +02:00
|
|
|
|
2009-09-15 17:37:00 +02:00
|
|
|
# groups can now represent user groups or repo groups
|
2009-08-25 05:38:11 +02:00
|
|
|
my %groups = ();
|
|
|
|
my %repos = ();
|
2009-09-27 04:32:36 +02:00
|
|
|
my %user_list = (); # only to catch lint; search for "lint" below
|
2009-08-23 10:16:45 +02:00
|
|
|
|
2009-09-21 11:11:37 +02:00
|
|
|
# set the umask before creating any files
|
|
|
|
umask($REPO_UMASK);
|
2009-08-25 03:36:36 +02:00
|
|
|
|
2009-08-23 11:25:50 +02:00
|
|
|
# ----------------------------------------------------------------------------
|
|
|
|
# subroutines
|
|
|
|
# ----------------------------------------------------------------------------
|
|
|
|
|
2009-08-31 04:28:08 +02:00
|
|
|
sub wrap_chdir {
|
2009-09-15 17:32:23 +02:00
|
|
|
chdir($_[0]) or die "$ATTN chdir $_[0] failed: $! at ", (caller)[1], " line ", (caller)[2], "\n";
|
2009-08-31 04:28:08 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
sub wrap_open {
|
2009-09-17 07:09:13 +02:00
|
|
|
open (my $fh, $_[0], $_[1]) or die "$ATTN open $_[1] failed: $! at ", (caller)[1], " line ", (caller)[2], "\n" .
|
|
|
|
( $_[2] || '' ); # suffix custom error message if given
|
2009-08-31 04:28:08 +02:00
|
|
|
return $fh;
|
2009-08-23 07:35:14 +02:00
|
|
|
}
|
|
|
|
|
2009-09-15 17:37:00 +02:00
|
|
|
sub expand_list
|
2009-08-23 10:16:45 +02:00
|
|
|
{
|
|
|
|
my @list = @_;
|
|
|
|
my @new_list = ();
|
|
|
|
|
|
|
|
for my $item (@list)
|
|
|
|
{
|
2009-09-15 17:37:00 +02:00
|
|
|
# we test with the slightly more relaxed pattern here; we'll catch the
|
|
|
|
# "/" in user name thing later; it doesn't affect security anyway
|
|
|
|
die "$ATTN bad user or repo name $item\n" unless $item =~ $REPONAME_PATT;
|
2009-08-23 10:16:45 +02:00
|
|
|
if ($item =~ /^@/) # nested group
|
|
|
|
{
|
2009-09-15 17:32:23 +02:00
|
|
|
die "$ATTN undefined group $item\n" unless $groups{$item};
|
2009-08-23 10:16:45 +02:00
|
|
|
# add those names to the list
|
2009-10-02 18:24:23 +02:00
|
|
|
push @new_list, sort keys %{ $groups{$item} };
|
2009-08-23 10:16:45 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
push @new_list, $item;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return @new_list;
|
|
|
|
}
|
|
|
|
|
|
|
|
# ----------------------------------------------------------------------------
|
|
|
|
# "compile" GL conf
|
|
|
|
# ----------------------------------------------------------------------------
|
|
|
|
|
2009-10-02 18:47:51 +02:00
|
|
|
sub parse_conf_file
|
|
|
|
{
|
2009-10-04 06:26:40 +02:00
|
|
|
my ($conffile, $fragment) = @_;
|
|
|
|
# the second arg, $fragment, is passed in as "master" when parsing the
|
|
|
|
# main config, and the fragment name when parsing a fragment. In the
|
|
|
|
# latter case, the parser uses that information to ignore (and warn about)
|
|
|
|
# any repos in the fragment that are not members of the "repo group" of
|
|
|
|
# the same name.
|
|
|
|
my %ignored = ();
|
|
|
|
|
2009-10-02 18:47:51 +02:00
|
|
|
my $conf_fh = wrap_open( "<", $conffile );
|
2009-08-23 10:16:45 +02:00
|
|
|
|
2009-10-02 18:47:51 +02:00
|
|
|
# the syntax is fairly simple, so we parse it inline
|
2009-08-23 10:16:45 +02:00
|
|
|
|
2009-10-02 18:47:51 +02:00
|
|
|
my @repos;
|
|
|
|
while (<$conf_fh>)
|
2009-08-23 10:16:45 +02:00
|
|
|
{
|
2009-10-02 18:47:51 +02:00
|
|
|
# normalise whitespace; keeps later regexes very simple
|
|
|
|
s/=/ = /;
|
|
|
|
s/\s+/ /g;
|
|
|
|
s/^ //;
|
|
|
|
s/ $//;
|
|
|
|
# kill comments
|
|
|
|
s/#.*//;
|
|
|
|
# and blank lines
|
|
|
|
next unless /\S/;
|
|
|
|
|
|
|
|
# user or repo groups
|
|
|
|
if (/^(@\S+) = (.*)/)
|
|
|
|
{
|
2009-10-04 06:26:40 +02:00
|
|
|
# store the members of each group as hash key. Keep track of when
|
|
|
|
# the group was *first* created by using $fragment as the *value*
|
|
|
|
do { $groups{$1}{$_} ||= $fragment } for ( expand_list( split(' ', $2) ) );
|
2009-10-02 18:47:51 +02:00
|
|
|
# again, we take the more "relaxed" pattern
|
|
|
|
die "$ATTN bad group $1\n" unless $1 =~ $REPONAME_PATT;
|
|
|
|
}
|
|
|
|
# repo(s)
|
|
|
|
elsif (/^repo (.*)/)
|
|
|
|
{
|
|
|
|
# grab the list and expand any @stuff in it
|
|
|
|
@repos = split ' ', $1;
|
|
|
|
@repos = expand_list ( @repos );
|
|
|
|
}
|
|
|
|
# actual permission line
|
|
|
|
elsif (/^(R|RW|RW\+) (.* )?= (.+)/)
|
2009-08-23 10:16:45 +02:00
|
|
|
{
|
2009-10-02 18:47:51 +02:00
|
|
|
my $perms = $1;
|
|
|
|
my @refs; @refs = split(' ', $2) if $2;
|
|
|
|
my @users = split ' ', $3;
|
|
|
|
|
|
|
|
# if no ref is given, this PERM applies to all refs
|
|
|
|
@refs = qw(refs/.*) unless @refs;
|
|
|
|
# fully qualify refs that dont start with "refs/"; prefix them with
|
|
|
|
# "refs/heads/"
|
|
|
|
@refs = map { m(^refs/) or s(^)(refs/heads/); $_ } @refs;
|
|
|
|
|
|
|
|
# expand the user list, unless it is just "@all"
|
|
|
|
@users = expand_list ( @users )
|
|
|
|
unless (@users == 1 and $users[0] eq '@all');
|
|
|
|
do { die "$ATTN bad username $_\n" unless $_ =~ $USERNAME_PATT } for @users;
|
|
|
|
|
|
|
|
# ok, we can finally populate the %repos hash
|
|
|
|
for my $repo (@repos) # each repo in the current stanza
|
2009-08-23 10:16:45 +02:00
|
|
|
{
|
2009-10-04 06:26:40 +02:00
|
|
|
# if we're processing a delegated config file (not the master
|
|
|
|
# config), and if that fragment name is not the same as the
|
|
|
|
# current repo
|
|
|
|
if ($fragment ne 'master' and $fragment ne $repo)
|
|
|
|
{
|
|
|
|
# then the fragment must be a group name and the repo
|
|
|
|
# being processed must be a member of that "@group".
|
|
|
|
# Also, the value of the hash for that combination must be
|
|
|
|
# "master", signifying a group created in the master
|
|
|
|
# config file and not in one of the delegates
|
|
|
|
unless ( ($groups{"\@$fragment"}{$repo} || '') eq 'master')
|
|
|
|
{
|
|
|
|
$ignored{$fragment}{$repo} = 1;
|
|
|
|
next;
|
|
|
|
}
|
|
|
|
}
|
2009-10-02 18:47:51 +02:00
|
|
|
for my $user (@users)
|
|
|
|
{
|
|
|
|
$user_list{$user}++; # only to catch lint, see later
|
2009-09-27 04:32:36 +02:00
|
|
|
|
2009-10-02 18:47:51 +02:00
|
|
|
# for 1st level check (see faq/tips doc)
|
|
|
|
$repos{$repo}{R}{$user} = 1 if $perms =~ /R/;
|
|
|
|
$repos{$repo}{W}{$user} = 1 if $perms =~ /W/;
|
2009-09-18 14:30:14 +02:00
|
|
|
|
2009-10-02 18:47:51 +02:00
|
|
|
# for 2nd level check, store each "ref, perms" pair in order
|
|
|
|
for my $ref (@refs)
|
|
|
|
{
|
|
|
|
push @{ $repos{$repo}{$user} }, { $ref => $perms };
|
|
|
|
}
|
2009-08-23 10:16:45 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2009-10-02 18:47:51 +02:00
|
|
|
else
|
|
|
|
{
|
|
|
|
die "$ATTN can't make head or tail of '$_'\n";
|
|
|
|
}
|
2009-08-24 10:00:58 +02:00
|
|
|
}
|
2009-10-04 06:26:40 +02:00
|
|
|
for my $ig (sort keys %ignored)
|
|
|
|
{
|
|
|
|
warn "\n\t\t***** WARNING *****\n" .
|
|
|
|
"\t$ig.conf attempting to set access for " .
|
|
|
|
join (", ", sort keys %{ $ignored{$ig} }) . "\n";
|
|
|
|
}
|
2009-08-23 10:16:45 +02:00
|
|
|
}
|
|
|
|
|
2009-10-04 06:26:40 +02:00
|
|
|
# parse the main config file
|
|
|
|
parse_conf_file($GL_CONF, 'master');
|
|
|
|
|
|
|
|
# parse any delegated fragments
|
|
|
|
wrap_chdir($GL_ADMINDIR);
|
|
|
|
for my $fragment_file (glob("conf/fragments/*.conf"))
|
|
|
|
{
|
|
|
|
my $fragment = $fragment_file;
|
|
|
|
$fragment =~ s/^conf\/fragments\/(.*).conf$/$1/;
|
|
|
|
parse_conf_file($fragment_file, $fragment);
|
|
|
|
}
|
2009-10-02 18:47:51 +02:00
|
|
|
|
2009-08-31 04:28:08 +02:00
|
|
|
my $compiled_fh = wrap_open( ">", $GL_CONF_COMPILED );
|
2009-08-25 06:27:19 +02:00
|
|
|
print $compiled_fh Data::Dumper->Dump([\%repos], [qw(*repos)]);
|
2009-09-15 17:32:23 +02:00
|
|
|
close $compiled_fh or die "$ATTN close compiled-conf failed: $!\n";
|
2009-08-23 11:25:50 +02:00
|
|
|
|
|
|
|
# ----------------------------------------------------------------------------
|
2009-09-27 04:32:36 +02:00
|
|
|
# any new repos to be created?
|
2009-08-23 11:25:50 +02:00
|
|
|
# ----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
# modern gits allow cloning from an empty repo, so we just create it. Gitosis
|
|
|
|
# did not have that luxury, so it was forced to detect the first push and
|
|
|
|
# create it then
|
|
|
|
|
2009-09-21 04:18:30 +02:00
|
|
|
# but it turns out not everyone has "modern" gits :)
|
|
|
|
my $git_version = `git --version`;
|
|
|
|
my ($gv_maj, $gv_min, $gv_patchrel) = ($git_version =~ m/git version (\d+)\.(\d+)\.(\d+)/);
|
|
|
|
die "$ATTN I can't understand $git_version\n" unless ($gv_maj >= 1);
|
|
|
|
$git_version = $gv_maj*10000 + $gv_min*100 + $gv_patchrel; # now it's "normalised"
|
|
|
|
my $git_too_old = 0;
|
|
|
|
|
2009-08-29 08:06:26 +02:00
|
|
|
# repo-base needs to be an absolute path for this loop to work right
|
|
|
|
# so if it was not already absolute, prefix $HOME.
|
|
|
|
my $repo_base_abs = ( $REPO_BASE =~ m(^/) ? $REPO_BASE : "$ENV{HOME}/$REPO_BASE" );
|
2009-08-31 04:28:08 +02:00
|
|
|
wrap_chdir("$repo_base_abs");
|
2009-08-23 11:25:50 +02:00
|
|
|
for my $repo (keys %repos)
|
|
|
|
{
|
|
|
|
unless (-d "$repo.git")
|
|
|
|
{
|
2009-09-15 17:32:23 +02:00
|
|
|
mkdir("$repo.git") or die "$ATTN mkdir $repo.git failed: $!\n";
|
2009-08-31 04:28:08 +02:00
|
|
|
wrap_chdir("$repo.git");
|
2009-09-21 04:18:30 +02:00
|
|
|
system("git --bare init");
|
2009-08-27 11:54:08 +02:00
|
|
|
system("cp $GL_ADMINDIR/src/update-hook.pl hooks/update");
|
2009-09-01 16:10:42 +02:00
|
|
|
chmod 0755, "hooks/update";
|
2009-08-31 04:28:08 +02:00
|
|
|
wrap_chdir("$repo_base_abs");
|
2009-09-21 04:18:30 +02:00
|
|
|
$git_too_old++ if $git_version < 10602; # that's 1.6.2 to you
|
2009-08-23 11:25:50 +02:00
|
|
|
}
|
|
|
|
}
|
2009-09-21 04:18:30 +02:00
|
|
|
warn "\n\t\t***** WARNING *****\n" .
|
|
|
|
"\tyour git version is older than 1.6.2\n" .
|
|
|
|
"\tgitolite will work but you MUST read the section on\n" .
|
|
|
|
"\t\"git version dependency\" in doc/3-faq-tips-etc.mkd\n"
|
|
|
|
if $git_too_old;
|
2009-08-24 10:00:58 +02:00
|
|
|
|
|
|
|
# ----------------------------------------------------------------------------
|
2009-09-25 08:47:33 +02:00
|
|
|
# handle gitweb and daemon
|
|
|
|
# ----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
# How you specify gitweb and daemon access is quite different from gitosis. I
|
|
|
|
# just assume you'll never have any *real* users called "gitweb" or "daemon"
|
|
|
|
# :-) These are now "pseduo users" -- giving them "R" access to a repo is all
|
|
|
|
# you have to do
|
|
|
|
|
|
|
|
wrap_chdir("$repo_base_abs");
|
|
|
|
|
|
|
|
# get the current project list; note that the file may not yet exist if no
|
|
|
|
# gitweb access has been specified so far
|
|
|
|
my %projlist = ();
|
|
|
|
if (-f $PROJECTS_LIST) {
|
|
|
|
my $projlist_fh = wrap_open( "<", $PROJECTS_LIST);
|
|
|
|
while(<$projlist_fh>) {
|
|
|
|
chomp;
|
|
|
|
$projlist{$_} = 1;
|
|
|
|
}
|
|
|
|
close $projlist_fh;
|
|
|
|
}
|
|
|
|
my $projlist_changed = 0;
|
|
|
|
|
|
|
|
# daemons first...
|
|
|
|
for my $repo (sort keys %repos) {
|
|
|
|
my $export_ok = "$repo.git/git-daemon-export-ok";
|
|
|
|
if ($repos{$repo}{'R'}{'daemon'}) {
|
|
|
|
unless (-f $export_ok) {
|
|
|
|
system("touch $export_ok");
|
|
|
|
print STDERR "daemon add $repo.git\n";
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (-f $export_ok) {
|
|
|
|
unlink($export_ok);
|
|
|
|
print STDERR "daemon del $repo.git\n";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
# ...then gitwebs
|
|
|
|
for my $repo (sort keys %repos) {
|
|
|
|
if ($repos{$repo}{'R'}{'gitweb'}) {
|
|
|
|
unless ($projlist{"$repo.git"}) {
|
|
|
|
# not in the old list; add it to the new one
|
|
|
|
$projlist{"$repo.git"} = 1;
|
|
|
|
$projlist_changed = 1;
|
|
|
|
print STDERR "gitweb add $repo.git\n";
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if ($projlist{"$repo.git"}) {
|
|
|
|
# delete it from new list
|
|
|
|
delete $projlist{"$repo.git"};
|
|
|
|
$projlist_changed = 1;
|
|
|
|
print STDERR "gitweb del $repo.git\n";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-09-27 04:32:36 +02:00
|
|
|
# has there been a change in the gitweb projects list?
|
2009-09-25 08:47:33 +02:00
|
|
|
if ($projlist_changed) {
|
|
|
|
print STDERR "updating gitweb project list $PROJECTS_LIST\n";
|
|
|
|
my $projlist_fh = wrap_open( ">", $PROJECTS_LIST);
|
|
|
|
print $projlist_fh join("\n", sort keys %projlist), "\n" if %projlist;
|
|
|
|
close $projlist_fh;
|
|
|
|
}
|
|
|
|
|
|
|
|
# ----------------------------------------------------------------------------
|
2009-08-24 10:00:58 +02:00
|
|
|
# "compile" ssh authorized_keys
|
|
|
|
# ----------------------------------------------------------------------------
|
|
|
|
|
2009-09-17 07:09:13 +02:00
|
|
|
my $authkeys_fh = wrap_open( "<", $ENV{HOME} . "/.ssh/authorized_keys",
|
|
|
|
"\tFor security reasons, gitolite will not *create* this file if it does\n" .
|
|
|
|
"\tnot already exist. Please see the \"admin\" document for details\n");
|
2009-08-31 04:28:08 +02:00
|
|
|
my $newkeys_fh = wrap_open( ">", $ENV{HOME} . "/.ssh/new_authkeys" );
|
2009-08-24 10:00:58 +02:00
|
|
|
# save existing authkeys minus the GL-added stuff
|
2009-08-25 06:27:19 +02:00
|
|
|
while (<$authkeys_fh>)
|
2009-08-24 10:00:58 +02:00
|
|
|
{
|
2009-08-26 03:35:04 +02:00
|
|
|
print $newkeys_fh $_ unless (/^# gito(sis-)?lite start/../^# gito(sis-)?lite end/);
|
2009-08-24 10:00:58 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
# add our "start" line, each key on its own line (prefixed by command and
|
|
|
|
# options, in the standard ssh authorized_keys format), then the "end" line.
|
2009-08-26 02:47:27 +02:00
|
|
|
print $newkeys_fh "# gitolite start\n";
|
2009-08-31 04:28:08 +02:00
|
|
|
wrap_chdir($GL_KEYDIR);
|
2009-09-27 04:32:36 +02:00
|
|
|
for my $pubkey (glob("*"))
|
2009-08-24 10:00:58 +02:00
|
|
|
{
|
2009-09-27 04:32:36 +02:00
|
|
|
# lint check 1
|
|
|
|
unless ($pubkey =~ /\.pub$/)
|
|
|
|
{
|
|
|
|
print STDERR "WARNING: pubkey files should end with \".pub\", ignoring $pubkey\n";
|
|
|
|
next;
|
|
|
|
}
|
2009-08-27 02:15:48 +02:00
|
|
|
my $user = $pubkey; $user =~ s/(\@.+)?\.pub$//;
|
2009-09-27 04:32:36 +02:00
|
|
|
# lint check 2
|
|
|
|
print STDERR "WARNING: pubkey $pubkey exists but user $user not in config\n"
|
|
|
|
unless $user_list{$user};
|
|
|
|
$user_list{$user} = 'has pubkey';
|
2009-08-25 06:27:19 +02:00
|
|
|
print $newkeys_fh "command=\"$AUTH_COMMAND $user\",$AUTH_OPTIONS ";
|
|
|
|
print $newkeys_fh `cat $pubkey`;
|
2009-08-24 10:00:58 +02:00
|
|
|
}
|
2009-09-27 04:32:36 +02:00
|
|
|
# lint check 3; a little more severe than the first two I guess...
|
|
|
|
for my $user (sort keys %user_list)
|
|
|
|
{
|
2009-10-03 07:25:30 +02:00
|
|
|
next if $user =~ /^(gitweb|daemon|\@all)$/ or $user_list{$user} eq 'has pubkey';
|
2009-09-27 04:32:36 +02:00
|
|
|
print STDERR "$ATTN user $user in config, but has no pubkey!\n";
|
|
|
|
}
|
|
|
|
|
2009-08-26 02:47:27 +02:00
|
|
|
print $newkeys_fh "# gitolite end\n";
|
2009-09-15 17:32:23 +02:00
|
|
|
close $newkeys_fh or die "$ATTN close newkeys failed: $!\n";
|
2009-08-24 10:00:58 +02:00
|
|
|
|
|
|
|
# all done; overwrite the file (use cat to avoid perm changes)
|
2009-09-01 16:10:42 +02:00
|
|
|
system("cat $ENV{HOME}/.ssh/authorized_keys > $ENV{HOME}/.ssh/old_authkeys");
|
2009-08-30 17:44:15 +02:00
|
|
|
system("cat $ENV{HOME}/.ssh/new_authkeys > $ENV{HOME}/.ssh/authorized_keys");
|
|
|
|
system("rm $ENV{HOME}/.ssh/new_authkeys");
|
2009-08-24 10:00:58 +02:00
|
|
|
|
2009-08-26 02:47:27 +02:00
|
|
|
# if the gl admin directory (~/.gitolite) is itself a git repo, do an
|
2009-08-24 10:00:58 +02:00
|
|
|
# autocheckin. nothing fancy; this is a "just in case" type of thing.
|
2009-08-31 04:28:08 +02:00
|
|
|
wrap_chdir($GL_ADMINDIR);
|
2009-08-24 10:00:58 +02:00
|
|
|
if (-d ".git")
|
|
|
|
{
|
2009-08-27 11:54:08 +02:00
|
|
|
system("git add -A conf keydir"); # stage all operational data
|
2009-08-24 10:00:58 +02:00
|
|
|
# and if there are any
|
|
|
|
if (system("git diff --cached --quiet") )
|
|
|
|
{
|
2009-08-25 06:27:19 +02:00
|
|
|
open my $commit_ph, "|-", "git commit -F -"
|
2009-09-15 17:32:23 +02:00
|
|
|
or die "$ATTN open commit failed: $!\n";
|
2009-08-25 06:27:19 +02:00
|
|
|
print $commit_ph "keydir changed\n\n";
|
|
|
|
print $commit_ph `git diff --cached --name-status`;
|
2009-09-15 17:32:23 +02:00
|
|
|
close $commit_ph or die "$ATTN close commit failed: $!\n";
|
2009-08-24 10:00:58 +02:00
|
|
|
}
|
|
|
|
}
|