diff options
author | Steve Langasek <vorlon@debian.org> | 2008-08-19 13:06:36 -0700 |
---|---|---|
committer | Steve Langasek <steve.langasek@ubuntu.com> | 2019-01-03 17:28:23 -0800 |
commit | d91f63093adeb151457e464602c7fe8c5a31ccdd (patch) | |
tree | 1d4e49a4b5218c59447c81a2066cbdf6817608cd /debian/local | |
parent | 3b5828bda8784d0663bcb204b5a4555b1f39b558 (diff) |
new diff_profiles function, which spits out information about any local mods
to the autogenerated config
Diffstat (limited to 'debian/local')
-rwxr-xr-x | debian/local/pam-auth-update | 168 |
1 files changed, 167 insertions, 1 deletions
diff --git a/debian/local/pam-auth-update b/debian/local/pam-auth-update index ddb6cfbd..6c80ea04 100755 --- a/debian/local/pam-auth-update +++ b/debian/local/pam-auth-update @@ -33,6 +33,7 @@ my $capb=capb('backup'); my $inputdir = '/usr/share/pam-configs'; my $template = 'libpam-runtime/profiles'; my $errtemplate = 'libpam-runtime/conflicts'; +my $confdir = '/etc/pam.d'; my (%profiles, @sorted, @enabled, @conflicts); opendir(DIR, $inputdir) || die "could not open config directory: $!"; @@ -53,11 +54,45 @@ subst($template, 'profiles', join(', ', map { $profiles{$_}->{'Name'} } @sorted)); # this needs to be replaced by proper detection of any profiles that are -# already enabled. +# already enabled; i.e., use diff_profiles() to figure out what's +# currently selected fset($template,'seen','false'); set($template, join(', ', grep { $profiles{$_}->{'Default'} eq 'yes' } @sorted)); +my $diff = diff_profiles($confdir); + +# we need a commandline '--force' arg to specify that /etc/pam.d should be +# overwritten; used only on upgrades where the postinst has already +# determined that the checksums match. Module packages other than +# libpam-runtime itself must NEVER use this option! Document with big +# skullses and crossboneses! It needs to be exposed for libpam-runtime +# because that's the package that decides whether we have a pristine config +# to be converted, and knows whether the version being upgraded from is one +# for which the conversion should be done. + +# if diff_profiles() fails, and we weren't passed a 'force' argument +# (either because this isn't an upgrade from an old version, or because the +# checksum didn't match, or because we're being called by some other module +# package), prompt the user whether to override. If the user declines +# (which is the default), we never again manage this config unless manually +# called with '--force'. + +# at the end of a successful write, reset the 'seen' flag and the value of +# the debconf override question. + +# FIXME: none of the above comments are implemented! + +if (!$diff) { + print STDERR <<EOF; + +pam-auth-update: Local modifications to /etc/pam.d/common-*, not updating. +pam-auth-update: Run pam-auth-config --force to override. + +EOF + exit; +} + do { @conflicts = (); input('high',$template); @@ -88,6 +123,137 @@ do { set($template, join(', ', @enabled)); } while (@conflicts); +# @enabled now contains our list of profiles to use for piecing together +# a config +# we have: +# - templates into which we insert the specialness +# - magic comments denoting the beginning and end of our managed block; +# looking at only the functional config lines would potentially let us +# handle more cases, at the expense of much greater complexity, so +# pass on this at least for the first round +# - a representation of the autogenerated config stored in /var/lib/pam, +# that we can diff against in order to account for changed options or +# manually dropped modules +# - a hash describing the local modifications the user has made to the +# config; these are always preserved unless manually overridden with +# the --force option + +write_profiles(\%profiles, \@enabled, $diff); + +# merge a set of module declarations into a set of new config files, +# using the information returned from diff_profiles(). +sub write_profiles +{ +} + +# reconcile the current config in /etc/pam.d with the saved ones in +# /var/lib/pam; returns a hash of profile names and the corresponding +# options that should be added/removed relative to the stock config. +# returns false if any of the markers are missing that permit a merge, +# or on any other failure. +sub diff_profiles +{ + my ($sourcedir) = @_; + my $savedir = '/var/lib/pam'; + my (%diff); + + # Load the saved config from /var/lib/pam, then iterate through all + # lines in the current config that are in the managed block. + # If anything fails here, just return immediately since we then + # have nothing to merge; instead, the caller will decide later + # whether to force an overwrite. + for my $type ('auth','account','password','session') { + my (@saved,$modname); + + open(SAVED,$savedir . '/' . $type) || return 0; + while (<SAVED>) { + if (/^Module: (.*)/) { + $modname = $1; + next; + } + chomp; + # trim out the destination of any jumps; this saves + # us from having to re-parse everything just to fix + # up the jump lengths, when changes to these will + # already show up as inconsistencies elsewhere + s/(end|[0-9]+)//; + my (@temp) = ($modname,$_); + push(@saved,\@temp); + } + close(SAVED); + + my $state = 0; + my (@prev_opts,$curmod); + + open(CURRENT,$sourcedir . '/common-' . $type) || return 0; + while (<CURRENT>) { + if ($state == 0) { + $state = 1 + if (/^# here are the per-package modules \(the "Primary" block\)/); + next; + } + if ($state == 1) { + s/^$type\s+//; + if (/^# here's the fallback if no module succeeds/) { + $state = 2; + next; + } + } + if ($state == 2) { + $state = 3 + if (/^# and here are more per-package modules \(the "Additional" block\)/); + next; + } + if ($state == 3) { + last if (/^# end of pam-auth-update config/); + s/^$type\s+//; + } + + my $found = 0; + do { + my $line; + ($modname,$line) = shift(@saved); + $line =~ /^((\[[^]]+\]|\w+)\s+\S+)\s*(.*)/; + @prev_opts = split(/\s+/,$3); + $curmod = $1; + $curmod =~ s/(end|[0-9]+)//; + # check if this is a match for the current line + if ($_ =~ /^$curmod\s*(.*)$/) { + $found = 1; + } else { + push(@{$diff{$type}{'del'}},$modname); + } + } while (!$found && $#saved >= 0); + + # there's a line in the live config that doesn't + # correspond to anything from the saved config. + # treat this as a failure; it's very error-prone + # to decide what to do with an added line that + # didn't come from a package. + return 0 if (!$found); + + for my $opt (split(/\s+/,$1)) { + my $found = 0; + for (my $i = 0; $i <= $#prev_opts; $i++) { + if ($prev_opts[$i] eq $opt) { + $found = 1; + splice(@prev_opts,$i,0); + } + } + push(@{$diff{$type}{'add'}{$curmod}},$opt) if (!$found); + } + for my $opt (@prev_opts) { + $diff{$type}{'remove'}{$curmod}{$opt} = 1; + } + } + close(CURRENT); + + # we couldn't parse the config, so the merge fails + return 0 if ($state < 3); + } + return \%diff; +} + # simple function to parse a provided config file, in pseudo-RFC822 # format, sub parse_pam_profile |