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