diff -r 000000000000 -r 2a5f2464f8c6 mergePasswdShadowAliases --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mergePasswdShadowAliases Fri Nov 04 06:29:26 2005 +0000 @@ -0,0 +1,137 @@ +#! /usr/bin/perl +# $Id$ +# $URL$ + +# passwd + shadow + aliases > uid:gecos:[alias ...]:password + +use strict; +use warnings; +use IO::File; + +use AppConfig; + +use constant CONFIG => ( + { CASE => 1 }, + passwd => { ARGS => "=s", DEFAULT => "passwd" }, + shadow => { ARGS => "=s", DEFAULT => "shadow" }, + aliases => { ARGS => "=s", DEFAULT => "aliases" }, +); + + +use constant FS => ":"; +use constant RS => "\n"; + + +my $Cf = new AppConfig CONFIG or die; + $Cf->getopt(\@ARGV) or die; + +MAIN: { + + my %visible; + { + # Zuerst müssen wir die Aliase irgendwie in nutzbare Form bringen. + # Wir können nicht einfach sequentiell durch das Aliasfile rennen und die Aliase + # irgendwie verteilen, sondern wir sammen sie erstmal schön, denn am Ende müssen wir ja + # wissen, welche noch nicht aufgelöst sind. + my $aliases = new IO::File $_ = $Cf->aliases or die "Can't open $_: $!\n"; + while (<$aliases>) { chomp; + s/#.*//g; + next if /^\s*$/; + s/[:,]/ /g; + my ($visible, @real) = split; # "hans.hanson hh" + # "root wgs hh" + + foreach (@real) { + $visible{$_}->{$visible} = 1; # hh -> hans.hanson, root + } + } + } + + my %passwords; + { + my $sh = new IO::File $_ = $Cf->shadow or die "Can't open $_: $!\n"; + %passwords = map { (split /:/, $_)[0,1] } <$sh>; + @passwords{keys %passwords} = map { "{crypt}$passwords{$_}" } keys %passwords; + } + + my %users; + { + # Passwort-File ist die primäre Quelle von Information + my $pw = new IO::File $_ = $Cf->passwd or die "Can't open $_: $!\n"; + while (<$pw>) { + my ($name, undef, $uid, undef, $gecos, undef) = split /:/, $_; + + my ($cn, $sn); + ($cn = $gecos) =~ s/,.*//; + ($sn = (split " ", $cn)[-1]); + + $users{$name}->{gecos} = $gecos; + $users{$name}->{uid} = $uid; + $users{$name}->{cn} = $cn || ""; + $users{$name}->{sn} = $sn || ""; + $users{$name}->{aliases} = []; + $users{$name}->{password} = $passwords{$name}; + $users{$name}->{sorter} = $name; + + + # Gleich mal nach dem Alias sehen + if (exists $visible{$name}) { + my $visible = $visible{$name}; + + foreach (keys %$visible) { + if (/$sn/i) { + push @{$users{$name}->{aliases}}, $_; + delete $visible->{$_}; + } + } + } + } + } + + + # delete users with short password or uid < 1000 + delete @users{grep { + $users{$_}->{password} =~ /^{crypt}.$/ + or $users{$_}->{uid} < 1000 + } keys %users}; + + + # Und nun noch die Aliase, die nicht verarbeitet wurden. + { + + # Alle löschen, die nur noch leere Hashs haben + delete @visible{ grep { not scalar %{$visible{$_}} } keys %visible}; + + # keys sind die Ziele(!) aber wir müssen es wieder genau umgekehrt haben! + # so ist es jetzt: + # uid: alternatives + # wgs: bauleitung wieder.platz + + foreach my $name (keys %visible) { + my @aliases = keys %{$visible{$name}}; + foreach (keys %{$visible{$name}}) { + if (not exists $users{$_}) { + $users{$_}->{gecos} = "ALIAS"; + $users{$_}->{password} = ""; + $users{$_}->{cn} = ""; + $users{$_}->{sn} = ""; + $users{$_}->{sorter} = "00$_"; + } elsif ($users{$_}->{gecos} ne "ALIAS") { + die "ALIAS $_ and user $_ conflict!"; + } + push @{$users{$_}->{aliases}}, $name; + } + } + } + + foreach my $name (sort { $users{$a}->{sorter} cmp $users{$b}->{sorter} } keys %users) { + $users{$name}->{aliases} = join ",", @{$users{$name}->{aliases}}; + print join(FS, $name, @{$users{$name}}{qw/password gecos cn sn aliases/}), RS; + } + + print "\n"; + + +} + +# vim:sts=4 sw=4 aw ai sm: