6 use strict; |
6 use strict; |
7 use warnings; |
7 use warnings; |
8 use Net::LDAP; |
8 use Net::LDAP; |
9 use Net::LDAP::Constant qw(LDAP_ALREADY_EXISTS LDAP_NO_SUCH_OBJECT LDAP_TYPE_OR_VALUE_EXISTS); |
9 use Net::LDAP::Constant qw(LDAP_ALREADY_EXISTS LDAP_NO_SUCH_OBJECT LDAP_TYPE_OR_VALUE_EXISTS); |
10 use Net::LDAP::Entry; |
10 use Net::LDAP::Entry; |
11 use Cyrus::IMAP::Admin; |
11 use Mail::IMAPTalk; |
12 use Text::Wrap; |
12 use Text::Wrap; |
13 use password; |
13 use password; |
14 |
14 |
15 |
15 |
16 my $Cf; |
16 my $Cf; |
17 my ($ldap, $ubase, $abase); |
17 my ($ldap, $ubase, $abase); |
18 my ($imap); |
18 my ($imap, $imap_password); |
19 END { $imap and $imap = undef; }; |
19 END { $imap and $imap = undef; }; |
20 |
20 |
21 |
21 |
22 sub _add(); |
22 sub _add(); |
23 sub _list(); |
23 sub _list(); |
43 import constant OC_RECIPIENT => $Cf->ldap_oc_recipient; |
44 import constant OC_RECIPIENT => $Cf->ldap_oc_recipient; |
44 import constant AT_PRIMARYADDRESS => $Cf->ldap_at_primaryaddress; |
45 import constant AT_PRIMARYADDRESS => $Cf->ldap_at_primaryaddress; |
45 import constant AT_ADDRESS => $Cf->ldap_at_address; |
46 import constant AT_ADDRESS => $Cf->ldap_at_address; |
46 import constant AT_GROUP => $Cf->ldap_at_group; |
47 import constant AT_GROUP => $Cf->ldap_at_group; |
47 import constant AT_FORWARDINGADDRESS => $Cf->ldap_at_forwardingaddress; |
48 import constant AT_FORWARDINGADDRESS => $Cf->ldap_at_forwardingaddress; |
|
49 import constant AT_QUOTA => $Cf->ldap_at_quota; |
48 |
50 |
49 $ubase = OU_ACCOUNTS . "," . $Cf->ldap_base; |
51 $ubase = OU_ACCOUNTS . "," . $Cf->ldap_base; |
50 $abase = OU_ALIASES . "," . $Cf->ldap_base; |
52 $abase = OU_ALIASES . "," . $Cf->ldap_base; |
51 } |
53 } |
52 |
54 |
55 $ldap = new Net::LDAP $Cf->ldap_server or die; |
57 $ldap = new Net::LDAP $Cf->ldap_server or die; |
56 my $r = $ldap->bind($Cf->ldap_bind_dn, |
58 my $r = $ldap->bind($Cf->ldap_bind_dn, |
57 password => $Cf->ldap_password || $ENV{LDAP_PASS} || password::ask("LDAP (". $Cf->ldap_bind_dn .") password: ")); |
59 password => $Cf->ldap_password || $ENV{LDAP_PASS} || password::ask("LDAP (". $Cf->ldap_bind_dn .") password: ")); |
58 die $r->error, "\n" if $r->code; |
60 die $r->error, "\n" if $r->code; |
59 |
61 |
60 $imap = new Cyrus::IMAP::Admin or die $@; |
62 $imap = Mail::IMAPTalk->new(Server => $Cf->imap_server, Port => $Cf->imap_port) |
61 $imap->authenticate(-server => $Cf->imap_server, -user => $Cf->imap_admin, |
63 or die "Can't connect to IMAP Server '", $Cf->imap_server, "', Port '", $Cf->imap_port, "': ", $@; |
62 -password => $Cf->imap_password || $ENV{IMAP_PASS} || password::ask("IMAP (". $Cf->imap_admin .") password: ")) |
64 $imap_password = $Cf->imap_password || $ENV{IMAP_PASS} || password::ask("IMAP (". $Cf->imap_admin .") password: "); |
63 or die $@; |
|
64 |
|
65 |
65 |
66 if ($Cf->list) { _list() } |
66 if ($Cf->list) { _list() } |
67 elsif ($Cf->add) { _add() } |
67 elsif ($Cf->add) { _add() } |
68 elsif ($Cf->delete) { _delete() } |
68 elsif ($Cf->delete) { _delete() } |
69 elsif ($Cf->modify) { _modify() } |
69 elsif ($Cf->modify) { _modify() } |
86 my $user = shift @ARGV; |
86 my $user = shift @ARGV; |
87 my $mailPrimaryAddress = $Cf->primary || $user; # evtl. mit ! |
87 my $mailPrimaryAddress = $Cf->primary || $user; # evtl. mit ! |
88 my $mailAddress = [$user, split /,/, $Cf->other || ""]; # ditto |
88 my $mailAddress = [$user, split /,/, $Cf->other || ""]; # ditto |
89 |
89 |
90 $user =~ s/!$//; # jetzt können wir ! nicht mehr brauchn |
90 $user =~ s/!$//; # jetzt können wir ! nicht mehr brauchn |
91 my $mbox = "user/$user"; |
|
92 my $cn = $Cf->fullname || $user; |
91 my $cn = $Cf->fullname || $user; |
93 my $sn = (reverse split " ", $cn)[0]; |
92 my $sn = (reverse split " ", $cn)[0]; |
94 my $mailGroup = [split /,/, $Cf->group || ""]; |
93 my $mailGroup = [split /,/, $Cf->group || ""]; |
95 my $mailForwardingAddress = [split /,/, $Cf->forward || ""]; |
94 my $mailForwardingAddress = [split /,/, $Cf->forward || ""]; |
96 my $pw = _mkpw($Cf->password || "{pwgen}"); |
95 my $pw = _mkpw($Cf->password || "{pwgen}"); |
|
96 # assuming usernames of the form localpart@domain |
|
97 $user =~ /@(.+)$/; |
|
98 my $escapes; |
|
99 die "Invalid username '$user'" unless $escapes->{'%u'} = $user |
|
100 and $escapes->{'%1'} = substr $user, 0, 1 |
|
101 and $escapes->{'%d'} = $1; |
|
102 my $mbox = $Cf->imap_mail_location; |
|
103 $mbox =~ s/$_/$escapes->{$_}/ for keys %{$escapes}; |
97 |
104 |
98 if ($mailPrimaryAddress !~ /@/) { |
105 if ($mailPrimaryAddress !~ /@/) { |
99 $mailPrimaryAddress .= "@" . $Cf->default_domain; |
106 $mailPrimaryAddress .= "@" . $Cf->default_domain; |
100 } |
107 } |
101 |
108 |
137 $e->replace(objectClass => [uniq $e->get("objectClass"), qw/uidObject person/, OC_RECIPIENT]); |
144 $e->replace(objectClass => [uniq $e->get("objectClass"), qw/uidObject person/, OC_RECIPIENT]); |
138 $e->replace(uid => [uniq $e->get("uid"), $user]); |
145 $e->replace(uid => [uniq $e->get("uid"), $user]); |
139 |
146 |
140 $e->add((AT_ADDRESS) => $mailAddress); |
147 $e->add((AT_ADDRESS) => $mailAddress); |
141 $e->add((AT_PRIMARYADDRESS) => $mailPrimaryAddress); |
148 $e->add((AT_PRIMARYADDRESS) => $mailPrimaryAddress); |
142 $e->add(userPassword => $pw); |
149 $e->add(userPassword => "{plain}$pw"); |
143 $e->add((AT_GROUP) => $mailGroup) if @$mailGroup; |
150 $e->add((AT_GROUP) => $mailGroup) if @$mailGroup; |
144 $e->add((AT_FORWARDINGADDRESS) => $mailForwardingAddress) if @$mailForwardingAddress; |
151 $e->add((AT_FORWARDINGADDRESS) => $mailForwardingAddress) if @$mailForwardingAddress; |
|
152 $e->add((AT_QUOTA) => $Cf->imap_quota); |
145 |
153 |
146 # $e->add(iusRestrictedMail => $Cf->internal) if $Cf->internal ne ":"; |
154 # $e->add(iusRestrictedMail => $Cf->internal) if $Cf->internal ne ":"; |
147 |
155 |
148 $e->exists("sn") or $e->add(sn => $sn); |
156 $e->exists("sn") or $e->add(sn => $sn); |
149 $e->exists("cn") or $e->add(cn => $cn); |
157 $e->exists("cn") or $e->add(cn => $cn); |
150 |
158 |
151 |
159 |
152 $r = $e->update($ldap); |
160 $r = $e->update($ldap); |
153 die $r->error if $r->code; |
161 die $r->error if $r->code; |
154 |
162 |
155 verbose("ok"); |
163 verbose('ok'); |
156 verbose(" Password: $pw") if not $Cf->password or $Cf->password eq "{pwgen}"; |
164 verbose(" Password: $pw") if not $Cf->password or $Cf->password eq "{pwgen}"; |
157 } |
165 } |
158 |
166 |
159 if($Cf->mbox) { |
167 if($Cf->mbox) { |
160 verbose("\n\t$mbox..."); |
168 verbose("\n\t$mbox..."); |
161 |
169 |
162 if ($imap->list($mbox)) { verbose("exists") } |
170 if (-d $mbox) { verbose('exists') } |
163 else { |
171 else { |
164 $imap->create($mbox) and verbose("ok") or die $@; |
172 |
165 $imap->setacl($mbox, $Cf->imap_admin => "lrswipcda") or die $@; |
173 $imap->login($user, $pw) or die $@; |
166 $imap->setquota($mbox, STORAGE => 1024 * $Cf->imap_quota) or die $@; |
174 # 'list' seems to trigger acl file (and thus the maildir) creation with dovecot |
167 } |
175 $imap->list('', '*') or die $@; |
168 } |
176 verbose('ok'); |
169 |
177 } |
|
178 |
|
179 } |
170 |
180 |
171 verbose("\n"); |
181 verbose("\n"); |
172 } |
182 } |
173 |
183 |
174 sub _modify() { |
184 sub _modify() { |
294 die $r->error.$r->code if $r->code; |
303 die $r->error.$r->code if $r->code; |
295 } |
304 } |
296 |
305 |
297 # FIXME: Wenn keine Mailbox existiert, gibt es hier ein Problem |
306 # FIXME: Wenn keine Mailbox existiert, gibt es hier ein Problem |
298 if (defined $Cf->imap_quota) { |
307 if (defined $Cf->imap_quota) { |
299 $imap->setquota($mbox, STORAGE => $Cf->imap_quota * 1024) |
308 # $imap->setquota($mbox, STORAGE => $Cf->imap_quota * 1024) |
300 or die $@; |
309 # or die $@; |
301 } |
310 } |
302 |
311 |
303 verbose "ok\n"; |
312 verbose "ok\n"; |
304 |
313 |
305 print "\n"; |
314 print "\n"; |
320 |
329 |
321 |
330 |
322 foreach (@ARGV) { |
331 foreach (@ARGV) { |
323 my $user = $_; |
332 my $user = $_; |
324 my $dn = "uid=$user,$ubase"; |
333 my $dn = "uid=$user,$ubase"; |
325 my $mbox = "user/$user"; |
|
326 |
334 |
327 verbose("$user:\n"); |
335 verbose("$user:\n"); |
328 |
336 |
329 # Nachsehen, ob es noch aliase gibt, in denen dieser Nutzer steht: |
337 # Nachsehen, ob es noch aliase gibt, in denen dieser Nutzer steht: |
330 my $r = $ldap->search(base => $abase, |
338 my $r = $ldap->search(base => $abase, |
382 my $cn = join(", ", $e->get_value("cn")); |
392 my $cn = join(", ", $e->get_value("cn")); |
383 my $mr = $e->get_value(AT_PRIMARYADDRESS) || ""; # ?? |
393 my $mr = $e->get_value(AT_PRIMARYADDRESS) || ""; # ?? |
384 my $ml = join(", ", $e->get_value(AT_ADDRESS)) || ""; # ?? |
394 my $ml = join(", ", $e->get_value(AT_ADDRESS)) || ""; # ?? |
385 my $mg = join(", ", $e->get_value(AT_GROUP)) || ""; # ?? |
395 my $mg = join(", ", $e->get_value(AT_GROUP)) || ""; # ?? |
386 my $forw = join (", ", $e->get_value(AT_FORWARDINGADDRESS)) || ""; |
396 my $forw = join (", ", $e->get_value(AT_FORWARDINGADDRESS)) || ""; |
387 my $mbox = "user/$uid"; |
|
388 |
397 |
389 print "$uid: $cn <$mr>"; |
398 print "$uid: $cn <$mr>"; |
390 |
399 |
391 #if (($e->get_value("iusRestrictedMail")||"") eq "TRUE") { |
400 #if (($e->get_value("iusRestrictedMail")||"") eq "TRUE") { |
392 #print " INTERNAL"; |
401 #print " INTERNAL"; |
393 #} |
402 #} |
394 |
403 |
|
404 $imap->login("$uid*" . $Cf->imap_admin, $imap_password ) or die $@; |
|
405 |
395 MBOX: { |
406 MBOX: { |
396 if (!$imap->list($mbox)) { |
407 if (!$imap->list()) { |
397 print ", no mbox"; |
408 print ", no mbox"; |
398 last MBOX; |
409 last MBOX; |
399 } |
410 } |
400 print ", mbox"; |
411 print ", mbox"; |
401 my %q = $imap->listquota($mbox); |
412 my %q = $imap->listquota(); |
402 my ($used, $max) = map { int($_ / 1024) } @{$q{STORAGE}}; |
413 my ($used, $max) = map { int($_ / 1024) } @{$q{STORAGE}}; |
403 |
414 |
404 if (!$max) { |
415 if (!$max) { |
405 print ", no quota"; |
416 print ", no quota"; |
406 last MBOX; |
417 last MBOX; |