mergePasswdShadowAliases
changeset 0 2a5f2464f8c6
--- /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: