compile: (large changes) parse delegated fragments if any
[Note: this is a fairly involved commit, compared to most of the others. See doc/5-delegation.mkd for a user-level feature description.] parse delegated config fragments (found as conf/fragments/*.conf). Any repos being referenced within a fragment config *must* belong to the "@group" with the same name as the fragment. That is, a fragment called conf/fragments/abc.conf can only refer to repos that are members of the "@abc" repo group. It cannot specify access control for any other repos. If it does, those settings are ignored, and a warning message is produced. since the delegated config must have the flexibility of (re-)defining group names for internal convenience, and since all such definitions go into the same "groups" hash, it is quite easy for conf/fragments/abc.conf to write in its own (re-)definition of "@abc"! That would be a neat little security hole :) The way to close it is to consider only members of the "@abc" groupset defined in the main ("master") config file for this purpose.
This commit is contained in:
parent
fa5567f22c
commit
616d8a5f7d
|
@ -121,7 +121,14 @@ sub expand_list
|
||||||
|
|
||||||
sub parse_conf_file
|
sub parse_conf_file
|
||||||
{
|
{
|
||||||
my ($conffile) = @_;
|
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 = ();
|
||||||
|
|
||||||
my $conf_fh = wrap_open( "<", $conffile );
|
my $conf_fh = wrap_open( "<", $conffile );
|
||||||
|
|
||||||
# the syntax is fairly simple, so we parse it inline
|
# the syntax is fairly simple, so we parse it inline
|
||||||
|
@ -142,7 +149,9 @@ sub parse_conf_file
|
||||||
# user or repo groups
|
# user or repo groups
|
||||||
if (/^(@\S+) = (.*)/)
|
if (/^(@\S+) = (.*)/)
|
||||||
{
|
{
|
||||||
do { $groups{$1}{$_} = 1 } for ( expand_list( split(' ', $2) ) );
|
# 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) ) );
|
||||||
# again, we take the more "relaxed" pattern
|
# again, we take the more "relaxed" pattern
|
||||||
die "$ATTN bad group $1\n" unless $1 =~ $REPONAME_PATT;
|
die "$ATTN bad group $1\n" unless $1 =~ $REPONAME_PATT;
|
||||||
}
|
}
|
||||||
|
@ -174,6 +183,22 @@ sub parse_conf_file
|
||||||
# ok, we can finally populate the %repos hash
|
# ok, we can finally populate the %repos hash
|
||||||
for my $repo (@repos) # each repo in the current stanza
|
for my $repo (@repos) # each repo in the current stanza
|
||||||
{
|
{
|
||||||
|
# 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
for my $user (@users)
|
for my $user (@users)
|
||||||
{
|
{
|
||||||
$user_list{$user}++; # only to catch lint, see later
|
$user_list{$user}++; # only to catch lint, see later
|
||||||
|
@ -195,9 +220,25 @@ sub parse_conf_file
|
||||||
die "$ATTN can't make head or tail of '$_'\n";
|
die "$ATTN can't make head or tail of '$_'\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
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";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
parse_conf_file($GL_CONF);
|
# 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);
|
||||||
|
}
|
||||||
|
|
||||||
my $compiled_fh = wrap_open( ">", $GL_CONF_COMPILED );
|
my $compiled_fh = wrap_open( ">", $GL_CONF_COMPILED );
|
||||||
print $compiled_fh Data::Dumper->Dump([\%repos], [qw(*repos)]);
|
print $compiled_fh Data::Dumper->Dump([\%repos], [qw(*repos)]);
|
||||||
|
|
Loading…
Reference in a new issue