mergePasswdShadowAliases
changeset 0 2a5f2464f8c6
equal deleted inserted replaced
-1:000000000000 0:2a5f2464f8c6
       
     1 #! /usr/bin/perl
       
     2 # $Id$
       
     3 # $URL$
       
     4 
       
     5 # passwd + shadow + aliases > uid:gecos:[alias ...]:password
       
     6 
       
     7 use strict;
       
     8 use warnings;
       
     9 use IO::File;
       
    10 
       
    11 use AppConfig;
       
    12 
       
    13 use constant CONFIG => (
       
    14     { CASE => 1 },
       
    15     passwd =>	    { ARGS => "=s", DEFAULT => "passwd" },
       
    16     shadow =>	    { ARGS => "=s", DEFAULT => "shadow" },
       
    17     aliases =>	    { ARGS => "=s", DEFAULT => "aliases" },
       
    18 );
       
    19 
       
    20 
       
    21 use constant FS => ":";
       
    22 use constant RS => "\n";
       
    23 
       
    24 
       
    25 my $Cf = new AppConfig CONFIG or die;
       
    26    $Cf->getopt(\@ARGV) or die;
       
    27 
       
    28 MAIN: {
       
    29 
       
    30     my %visible;
       
    31     {
       
    32 	# Zuerst müssen wir die Aliase irgendwie in nutzbare Form bringen.
       
    33 	# Wir können nicht einfach sequentiell durch das Aliasfile rennen und die Aliase 
       
    34 	# irgendwie verteilen, sondern wir sammen sie erstmal schön, denn am Ende müssen wir ja 
       
    35 	# wissen, welche noch nicht aufgelöst sind.
       
    36 	my $aliases = new IO::File $_ = $Cf->aliases or die "Can't open $_: $!\n";
       
    37 	while (<$aliases>) { chomp;
       
    38 	    s/#.*//g;
       
    39 	    next if /^\s*$/;
       
    40 	    s/[:,]/ /g;
       
    41 	    my ($visible, @real) = split;	# "hans.hanson hh"
       
    42 						# "root wgs hh"
       
    43 
       
    44 	    foreach (@real) {
       
    45 		$visible{$_}->{$visible} = 1;	# hh -> hans.hanson, root
       
    46 	    }
       
    47 	}
       
    48     }
       
    49 
       
    50     my %passwords;
       
    51     {   
       
    52 	my $sh = new IO::File $_ = $Cf->shadow or die "Can't open $_: $!\n";
       
    53 	%passwords = map { (split /:/, $_)[0,1] } <$sh>;
       
    54 	@passwords{keys %passwords} = map { "{crypt}$passwords{$_}" } keys %passwords;
       
    55     }
       
    56 
       
    57     my %users;
       
    58     {
       
    59 	# Passwort-File ist die primäre Quelle von Information
       
    60 	my $pw = new IO::File $_ = $Cf->passwd or die "Can't open $_: $!\n";
       
    61 	while (<$pw>) {
       
    62 	    my ($name, undef, $uid, undef, $gecos, undef) = split /:/, $_;
       
    63 
       
    64 	    my ($cn, $sn);
       
    65 	    ($cn = $gecos) =~ s/,.*//;
       
    66 	    ($sn = (split " ", $cn)[-1]);
       
    67 
       
    68 	    $users{$name}->{gecos} = $gecos;
       
    69 	    $users{$name}->{uid} = $uid;
       
    70 	    $users{$name}->{cn} = $cn || "";
       
    71 	    $users{$name}->{sn} = $sn || "";
       
    72 	    $users{$name}->{aliases} = [];
       
    73 	    $users{$name}->{password} = $passwords{$name};
       
    74 	    $users{$name}->{sorter} = $name;
       
    75 
       
    76 
       
    77 	    # Gleich mal nach dem Alias sehen
       
    78 	    if (exists $visible{$name}) {
       
    79 		my $visible = $visible{$name};	
       
    80 
       
    81 		foreach (keys %$visible) {
       
    82 		    if (/$sn/i) {
       
    83 			push @{$users{$name}->{aliases}}, $_;
       
    84 			delete $visible->{$_};
       
    85 		    }
       
    86 		}
       
    87 	    }
       
    88 	}
       
    89     }
       
    90 
       
    91 
       
    92     # delete users with short password or uid < 1000
       
    93     delete @users{grep {
       
    94 	$users{$_}->{password} =~ /^{crypt}.$/
       
    95 	or $users{$_}->{uid} < 1000
       
    96     } keys %users};
       
    97 
       
    98 
       
    99     # Und nun noch die Aliase, die nicht verarbeitet wurden.
       
   100     {
       
   101 	
       
   102 	# Alle löschen, die nur noch leere Hashs haben
       
   103 	delete @visible{ grep { not scalar %{$visible{$_}} } keys %visible};
       
   104 
       
   105 	# keys sind die Ziele(!) aber wir müssen es wieder genau umgekehrt haben!
       
   106 	# so ist es jetzt:
       
   107 	# uid: alternatives
       
   108 	# wgs: bauleitung wieder.platz
       
   109 
       
   110 	foreach my $name (keys %visible) {
       
   111 	    my @aliases = keys %{$visible{$name}};
       
   112 	    foreach (keys %{$visible{$name}}) {
       
   113 		if (not exists $users{$_}) {
       
   114 		    $users{$_}->{gecos} = "ALIAS";
       
   115 		    $users{$_}->{password} = "";
       
   116 		    $users{$_}->{cn} = "";
       
   117 		    $users{$_}->{sn} = "";
       
   118 		    $users{$_}->{sorter} = "00$_";
       
   119 		} elsif ($users{$_}->{gecos} ne "ALIAS") {
       
   120 		    die "ALIAS $_ and user $_ conflict!";
       
   121 		}
       
   122 		push @{$users{$_}->{aliases}}, $name;
       
   123 	    }
       
   124 	}
       
   125     }
       
   126 
       
   127     foreach my $name (sort { $users{$a}->{sorter} cmp $users{$b}->{sorter} } keys %users) {
       
   128 	$users{$name}->{aliases} = join ",", @{$users{$name}->{aliases}};
       
   129 	print join(FS, $name, @{$users{$name}}{qw/password gecos cn sn aliases/}), RS;
       
   130     }
       
   131 
       
   132     print "\n";
       
   133 
       
   134 
       
   135 }
       
   136 
       
   137 # vim:sts=4 sw=4 aw ai sm: