From 616d8a5f7d2c8c08c7cc1f52dc89bd5846695d19 Mon Sep 17 00:00:00 2001 From: Sitaram Chamarty Date: Sun, 4 Oct 2009 09:56:40 +0530 Subject: [PATCH] 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. --- src/gl-compile-conf | 47 ++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 44 insertions(+), 3 deletions(-) diff --git a/src/gl-compile-conf b/src/gl-compile-conf index 281eafd..8f97bf0 100755 --- a/src/gl-compile-conf +++ b/src/gl-compile-conf @@ -121,7 +121,14 @@ sub expand_list 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 ); # the syntax is fairly simple, so we parse it inline @@ -142,7 +149,9 @@ sub parse_conf_file # user or repo groups 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 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 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) { $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"; } } + 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 ); print $compiled_fh Data::Dumper->Dump([\%repos], [qw(*repos)]);