--- /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: