Sharedwww / cgi-bin / openwebmail / openwebmail-vdomain.plOpen in CoCalc
Author: William A. Stein
1
#!/usr/bin/perl
2
#
3
# openwebmail-vdomain.pl - virtual domain user management
4
#
5
# 2003/02/26 Bernd Bass, [email protected]
6
# 2003/05/09 Scott Mazur, [email protected]
7
#
8
9
#
10
# THIS MODULE MODIFIES IMPORTANT CONFIG FILES OF YOUR SERVER.
11
# !!!USE THIS MODULE ON YOUR OWN RISK, THERE IS NO WARRANTY AT ALL!!!
12
#
13
# Description:
14
#
15
# This module provides the ability for users of virtual domains to manage
16
# their 'own' domain space without any direct access by ssh or telnet
17
# to the server itself. At the current state a user can only manage
18
# the domain accounts of his current logged on e-mail account.
19
# For example, [email protected] can manage all e-mail accounts
20
# of the domain foo.bar :)
21
#
22
# Requirements:
23
#
24
# + Openwebmail with this module of course :)
25
# + Postfix and access to the postfix config files (/etc/postfix)
26
# + vm-pop3d and access to the passwd files (/etc/virtual/)
27
#
28
# + Postfix config file must include the following options:
29
# allow_mail_to_commands = alias,forward,include
30
# allow_mail_to_files = alias,forward,include
31
#
32
# !Backup your config files before using this module the firsttime !
33
#
34
# Configuration:
35
#
36
# 1. enable vdomain module in your openwebmail.conf
37
#
38
# enable_vdomain yes
39
#
40
# 2. override the following option in openwebmail.conf
41
# if any one of them is not appropriate for your system
42
#
43
# vdomain_vmpop3_pwdpath /etc/virtual/
44
# vdomain_vmpop3_pwdname passwd
45
# vdomain_vmpop3_mailpath /var/spool/virtual
46
# vdomain_postfix_virtual /etc/postfix/virtual
47
# vdomain_postfix_aliases /etc/postfix/aliases
48
# vdomain_postfix_postmap /usr/sbin/postmap
49
# vdomain_postfix_postalias /usr/sbin/postalias
50
#
51
# With the above default setting:
52
#
53
# virtual map for each DOMAIN will be /etc/postfix/virtual
54
# aliases map for each DOMAIN will be /etc/postfix/aliases
55
# passwd file for each DOMAIN will be /etc/virtual/DOMAIN/passwd
56
# the mail spool for [email protected] will be /var/spool/virtual/DOMAIN/USER
57
#
58
# ps: this program won't create virtual, aliases or password file for you
59
# you have to create them explicitly by yourself
60
#
61
# 3. add this line to the openwebmail per domain config
62
# (cgi-bin/openwebmail/etc/site.conf/DOMAINANME)
63
#
64
# vdomain_admlist admin foo bar webmaster
65
#
66
# ps: You can specify more "admins" per domain in the site specific config file.
67
#
68
# Thats it ! After these modifications you will get another icon beside
69
# the password change icon of the preferences page.
70
#
71
# Limitations:
72
#
73
# E-Mail address must have an entry in the vm-pop3d passwd file to be
74
# recognized by the module.
75
#
76
# Future wishlist:
77
#
78
# + specify admin users for more than one domain at the same time
79
#
80
# Version 0.61
81
#
82
# + merge local users and local aliases into user display and edit checks if domain is local
83
#
84
# Version 0.6
85
#
86
# + rewrite to manage virtual user mail aliases
87
# + use :include: mechanism in postifx aliases
88
# + new language elements: set_passwd, reset_passwd, email_alias, vdomain_toomanyalias and vdomain_userrequired
89
# + merged edit user and create user templates
90
#
91
# Version 0.5
92
#
93
# + fixed wrong display of usermail settings with duplicate usernames
94
#
95
# Version 0.4 ( initial release )
96
#
97
# + create, modify, delete users of the current logged on domain
98
# + specify "Admin" users per domain which can use this module
99
# + set passwords for virtual user accounts
100
# + supported languages German, English (any translations are welcome)
101
#
102
103
use vars qw($SCRIPT_DIR);
104
if ( $0 =~ m!^(\S*)/[\w\d\-\.]+\.pl! ) { $SCRIPT_DIR=$1 }
105
if ($SCRIPT_DIR eq '' && open(F, '/etc/openwebmail/openwebmail_path.conf')) {
106
$_=<F>; close(F); if ( $_=~/^(\S*)/) { $SCRIPT_DIR=$1 }
107
}
108
if ($SCRIPT_DIR eq '') { print "Content-type: text/html\n\nSCRIPT_DIR not set in /etc/openwebmail/openwebmail_path.conf !\n"; exit 0; }
109
push (@INC, $SCRIPT_DIR);
110
111
foreach (qw(ENV BASH_ENV CDPATH IFS TERM)) {delete $ENV{$_}}; $ENV{PATH}='/bin:/usr/bin'; # secure ENV
112
umask(0002); # make sure the openwebmail group can write
113
114
use strict;
115
use Fcntl qw(:DEFAULT :flock);
116
use CGI qw(-private_tempfiles :standard);
117
use CGI::Carp qw(fatalsToBrowser carpout);
118
use File::Path;
119
120
require "modules/dbm.pl";
121
require "modules/suid.pl";
122
require "modules/filelock.pl";
123
require "modules/tool.pl";
124
require "modules/execute.pl";
125
require "modules/datetime.pl";
126
require "modules/lang.pl";
127
require "auth/auth.pl";
128
require "quota/quota.pl";
129
require "shares/ow-shared.pl";
130
131
# common globals
132
use vars qw(%config %config_raw);
133
use vars qw($thissession);
134
use vars qw($logindomain $domain $user $userrealname $uuid $ugid $homedir);
135
use vars qw(%prefs %style);
136
137
# extern vars
138
use vars qw(%lang_text %lang_err); # defined in lang/xy
139
140
########## MAIN ##################################################
141
openwebmail_requestbegin();
142
userenv_init();
143
144
# If this is a real user (not virtual) then switch to the virtual site config
145
# this allows real user to be administrator of the vdomains, tricky!
146
if ( $config{'auth_module'} ne 'auth_vdomain.pl' ) {
147
read_owconf(\%config, \%config_raw, "$config{'ow_sitesconfdir'}/$logindomain");
148
ow::auth::load($config{'auth_module'});
149
}
150
151
# $user has been determined by openwebmain_init()
152
if (!$config{'enable_vdomain'} || !is_vdomain_adm($user)) {
153
openwebmailerror(__FILE__, __LINE__, "$lang_text{'vdomain_usermgr'} $lang_err{'access_denied'}");
154
}
155
156
# $domain has been determined by openwebmain_init()
157
foreach ("$config{'vdomain_vmpop3_pwdpath'}/$domain/$config{'vdomain_vmpop3_pwdname'}",
158
@{$config{'vdomain_postfix_virtual'}},
159
@{$config{'vdomain_postfix_aliases'}}) {
160
openwebmailerror(__FILE__, __LINE__, "$_ $lang_err{'doesnt_exist'}") if (! -f $_);
161
}
162
163
my $action = param('action');
164
if ($action eq 'display_vuserlist') {
165
display_vuserlist();
166
} elsif ($action eq 'edit_vuser' ||
167
$action eq 'edit_new_vuser') {
168
edit_vuser();
169
} elsif ($action eq 'change_vuser' ||
170
$action eq 'change_new_vuser') {
171
change_vuser();
172
} elsif ($action eq 'delete_vuser') {
173
delete_vuser();
174
} else {
175
openwebmailerror(__FILE__, __LINE__, "Action $lang_err{'has_illegal_chars'}");
176
}
177
178
openwebmail_requestend();
179
########## END MAIN ##############################################
180
181
########## DISPLAY_VUSERLIST #####################################
182
sub display_vuserlist {
183
my $view = param('view')||'';
184
my %vusers=vuser_list();
185
my @vusers_list = sort (keys %vusers);
186
my $html = applystyle(readtemplate("vdomain_userlist.template"));
187
188
my $temphtml = startform(-name=>'indexform',
189
-action=>"$config{'ow_cgiurl'}/openwebmail-vdomain.pl").
190
ow::tool::hiddens(action=>'display_vuserlist',
191
sessionid=>$thissession,
192
view=>$view);
193
$html =~ s/\@\@\@STARTFORM\@\@\@/$temphtml/;
194
$html =~ s/\@\@\@DOMAINNAME\@\@\@/$domain/;
195
196
$temphtml = iconlink("backtofolder.gif", "$lang_text{'backto'} $lang_text{'userprefs'}", qq|accesskey="O" href="$config{'ow_cgiurl'}/openwebmail-prefs.pl?action=editprefs&amp;sessionid=$thissession"|);
197
if ($config{'vdomain_maxuser'}==0 ||
198
$#vusers_list+1<$config{'vdomain_maxuser'}) {
199
$temphtml .= qq|&nbsp;\n|;
200
$temphtml .= iconlink("adduser.gif", $lang_text{'vdomain_createuser'}, qq|accesskey="A" href="$config{'ow_cgiurl'}/openwebmail-vdomain.pl?action=edit_new_vuser&amp;sessionid=$thissession&amp;view=$view"|);
201
}
202
$html =~ s/\@\@\@MENUBARLINKS\@\@\@/$temphtml/g;
203
204
my $txtuonly = qq|<a href="$config{'ow_cgiurl'}/openwebmail-vdomain.pl?action=display_vuserlist&amp;sessionid=$thissession&amp;view=users"|.
205
qq| title="$lang_text{'vdomain_changeview'} $lang_text{'vdomain_usersonly'}">$lang_text{'vdomain_usersonly'}</a>|;
206
my $txtua = qq|<a href="$config{'ow_cgiurl'}/openwebmail-vdomain.pl?action=display_vuserlist&amp;sessionid=$thissession&amp;view=useralias"|.
207
qq| title="$lang_text{'vdomain_changeview'} $lang_text{'vdomain_useralias'}">$lang_text{'vdomain_useralias'}</a>|;
208
my $txtuaf = qq|<a href="$config{'ow_cgiurl'}/openwebmail-vdomain.pl?action=display_vuserlist&amp;sessionid=$thissession&amp;view=default"|.
209
qq| title="$lang_text{'vdomain_changeview'} $lang_text{'vdomain_fmtuseralias'}">$lang_text{'vdomain_fmtuseralias'}</a>|;
210
211
my %vuseralias=vuser_alias_list(%vusers);
212
my %vuserfwd=vuser_fwd_list(@vusers_list);
213
214
$temphtml = '';
215
my %cell=(); my @order=();
216
if ( $view eq 'users' ) {
217
# list only users
218
$temphtml = "$lang_text{'vdomain_usersonly'}, $txtua, $txtuaf";
219
foreach (@vusers_list) {
220
$cell{$_}=displaycell($_,$_,$view,\%vusers,\%vuserfwd);
221
push @order, $_;
222
}
223
} elsif ( $view eq 'useralias' ) {
224
# list users and aliases together
225
$temphtml = "$txtuonly, $lang_text{'vdomain_useralias'}, $txtuaf";
226
foreach (sort keys %{$vuseralias{'list'}}) {
227
$cell{$_}=displaycell($_,$vuseralias{'list'}{$_},$view,\%vusers,\%vuserfwd);
228
push @order, $_;
229
}
230
} else {
231
# list users and aliases grouped by user, formatted
232
$temphtml = "$txtuonly, $txtua, $lang_text{'vdomain_fmtuseralias'}";
233
my $i=0;
234
foreach (@vusers_list) {
235
if (defined $vuseralias{'aliases'}{$_}) {
236
while ($i%4 != 0) {
237
push @order,'@[email protected]';
238
$i++;
239
}
240
$cell{$_}=displaycell($_,$_,$view,\%vusers,\%vuserfwd);
241
push @order, $_;
242
$i++;
243
foreach my $alias (sort @{$vuseralias{'aliases'}{$_}}) {
244
if ($i%4 == 0) {
245
push @order,'@[email protected]';
246
$i++;
247
}
248
$cell{$alias}=$alias;
249
push @order, $alias;
250
$i++;
251
}
252
while ($i%4 != 0) {
253
push @order,'@[email protected]';
254
$i++;
255
}
256
} else {
257
$cell{$_}=displaycell($_,$_,$view,\%vusers,\%vuserfwd);
258
push @order, $_;
259
$i++;
260
}
261
}
262
}
263
$html =~ s/\@\@\@VIEWFMT\@\@\@/$temphtml/;
264
265
$temphtml = '';
266
my $bgcolor=$style{'tablerow_dark'};
267
my $i=0;
268
foreach (@order) {
269
if ($i%4==0 and $_ ne '@[email protected]' ) {
270
if ($bgcolor eq $style{"tablerow_dark"}) {
271
$bgcolor = $style{"tablerow_light"};
272
} else {
273
$bgcolor = $style{"tablerow_dark"};
274
}
275
}
276
$temphtml .= qq|<tr bgcolor=$bgcolor>| if ($i%4==0);
277
$temphtml .= qq|<td width="25%">$cell{$_}</td>|;
278
$temphtml .= qq|</tr>| if ($i%4==3);
279
$i++;
280
}
281
if ($i%4 != 0) {
282
while ($i%4 != 0) {
283
$temphtml .= qq|<td></td>|;
284
$i++;
285
}
286
$temphtml .= qq|</tr>|;
287
}
288
$html =~ s/\@\@\@USERS\@\@\@/$temphtml/;
289
290
$temphtml = end_form();
291
$html =~ s/\@\@\@ENDFORM\@\@\@/$temphtml/;
292
293
httpprint([], [htmlheader(), $html, htmlfooter(2)]);
294
295
}
296
########## END DISPLAY_VUSERLIST #################################
297
298
########## DISPLAYCELL ###########################################
299
sub displaycell {
300
my ($useralias,$useredit,$view,$vusers,$vuserfwd)=@_;
301
my $oldchklogin=0;
302
my $oldchkfwd=0;
303
my $olddirect='';
304
my $userdisp='';
305
306
$userdisp = $lang_text{'vdomain_admin'} if is_vdomain_adm($useredit);
307
if ($$vusers{$useredit}=~/^%/) {
308
$userdisp .= ', ' if ($userdisp);
309
$userdisp .= $lang_text{'vdomain_localuser'};
310
}
311
$oldchklogin=1 if ($$vusers{$useredit}=~/^#/);
312
if ( $$vuserfwd{$useredit} ) {
313
$oldchkfwd=1;
314
$olddirect=$$vuserfwd{$useredit};
315
}
316
my $note='';
317
$note = $lang_text{'disable'} if ($oldchklogin);
318
if ($oldchkfwd) {
319
$note .= ', ' if ($note);
320
$note .= $lang_text{'forward'}
321
}
322
$userdisp= " <I>- $userdisp</I>" if ($userdisp);
323
if ($useralias ne $useredit) {
324
$useralias.=" ($useredit)";
325
} else {
326
$useralias = "$useredit$userdisp";
327
}
328
$useralias="<I>($note)</I> $useralias" if ($note);
329
return $useralias if ($$vusers{$useredit}=~/^%/);
330
return qq|<a href="$config{'ow_cgiurl'}/openwebmail-vdomain.pl?action=edit_vuser&amp;vuser=$useredit&amp;sessionid=$thissession&amp;view=$view| .
331
qq|&amp;oldchklogin=$oldchklogin&amp;oldchkfwd=$oldchkfwd&amp;olddirect=$olddirect" title="$lang_text{'vdomain_changeuser'} $useredit">$useralias</a>|;
332
}
333
########## END DISPLAYCELL #######################################
334
335
########## EDIT USER #############################################
336
sub edit_vuser {
337
my ($focus, $alert, $pwd, $pwd2, $emailkey, $e_realnm, $realnm, %from_list)=@_;
338
my $vuser = param('vuser')||'';
339
my $action = param('action')||'';
340
my $view = param('view')||'';
341
my $oldchklogin=param('oldchklogin')||'';
342
my $oldchkfwd=param('oldchkfwd')||'';
343
my $olddirect=param('olddirect')||'';
344
my $chklogin=$oldchklogin;
345
my $chkfwd=$oldchkfwd;
346
my $direct=$olddirect;
347
$chklogin=param('chklogin') if (param('chklogin'));
348
$chkfwd=param('chkfwd') if (param('chkfwd'));
349
$direct=param('direct') if (param('direct'));
350
351
my ($title_txt, $setpass_txt, $del_txt, $chg_txt, $user_txt);
352
my $new=0;
353
$new=1 if ($action=~/new/);
354
my $admn=is_vdomain_adm($vuser);
355
if ($action=~/edit/) {
356
if ($new) {
357
$focus='vuser';
358
} else {
359
$pwd = '*********';
360
$pwd2=$pwd;
361
($realnm,%from_list) = from_list(lc($vuser));
362
$focus='emailaddr';
363
}
364
$action=~s/edit/change/;
365
}
366
367
if ($new) {
368
$title_txt=$lang_text{'vdomain_createuser'};
369
$setpass_txt=$lang_text{'set_passwd'};
370
$del_txt='';
371
$chg_txt=$lang_text{'vdomain_createuser'};
372
$user_txt = textfield(-name=>'vuser',
373
-default=>$vuser,
374
-size=>'20',
375
-override=>'1');
376
} else {
377
$title_txt="$lang_text{'vdomain_changeuser'} $vuser";
378
$setpass_txt=$lang_text{'reset_passwd'};
379
if ($admn){
380
$del_txt = '';
381
} else {
382
$del_txt = submit(-name => 'deletebutton',
383
-value => $lang_text{'vdomain_deleteuser'});
384
}
385
$chg_txt=$lang_text{'vdomain_changeuser'};
386
$user_txt = "<b>$vuser</b>";
387
}
388
389
my $html = applystyle(readtemplate("vdomain_edituser.template"));
390
$html =~ s/\@\@\@DOMAINNAME\@\@\@/$domain/;
391
$html =~ s/\@\@\@VDOMAINTITLE\@\@\@/$title_txt/;
392
393
my $temphtml = startform(-name=>'userform',
394
-action=>"$config{'ow_cgiurl'}/openwebmail-vdomain.pl").
395
ow::tool::hiddens(action=>$action,
396
sessionid=>$thissession,
397
view=>$view,
398
oldchklogin=>$oldchklogin,
399
oldchkfwd=>$oldchkfwd,
400
olddirect=>$olddirect,
401
addmod=>'',
402
aliasdel=>'').
403
hidden(-name=>'fromlist',
404
-default=>[%from_list],
405
-override=>'1');
406
$temphtml .= ow::tool::hiddens(vuser=>$vuser) if (! $new);
407
$html =~ s/\@\@\@STARTUSERFORM\@\@\@/$temphtml/;
408
409
$html =~ s/\@\@\@FOCUS\@\@\@/$focus/;
410
$html =~ s/\@\@\@VUSER\@\@\@/$user_txt/;
411
$temphtml = textfield(-name=>'realnm',
412
-default=>$realnm,
413
-size=>'50',
414
-override=>'1');
415
$html =~ s/\@\@\@REALNAME\@\@\@/$temphtml/;
416
417
$html =~ s/\@\@\@SETPASS\@\@\@/$setpass_txt/;
418
$temphtml = password_field(-name=>'newpassword',
419
-default=>$pwd,
420
-size=>'16',
421
-override=>'1');
422
$html =~ s/\@\@\@NEWPASSWORDFIELD\@\@\@/$temphtml/;
423
$temphtml = password_field(-name=>'confirmnewpassword',
424
-default=>$pwd2,
425
-size=>'16',
426
-override=>'1');
427
$html =~ s/\@\@\@CONFIRMNEWPASSWORDFIELD\@\@\@/$temphtml/;
428
429
if ( $admn ) {
430
$html =~ s/\@\@\@CHKLOGIN\@\@\@//;
431
$html =~ s/\@\@\@DISABLECHKLOGIN\@\@\@/<I>($lang_text{'disable'}) <\/I>/;
432
} else {
433
$temphtml = checkbox(-name=>'chklogin',
434
-value=>'1',
435
-checked=>$chklogin,
436
-label=>'');
437
$html =~ s/\@\@\@CHKLOGIN\@\@\@/$temphtml/;
438
$html =~ s/\@\@\@DISABLECHKLOGIN\@\@\@//;
439
}
440
$temphtml = checkbox(-name=>'chkfwd',
441
-value=>'1',
442
-checked=>$chkfwd,
443
-label=>'');
444
$html =~ s/\@\@\@CHKFWD\@\@\@/$temphtml/;
445
$temphtml = textfield(-name=>'direct',
446
-default=>$direct,
447
-size=>'40',
448
-override=>'1');
449
$html =~ s/\@\@\@DIRECT\@\@\@/$temphtml/;
450
451
$temphtml = textfield(-name=>'emailaddr',
452
-default=>$emailkey,
453
-size=>'40',
454
-override=>'1');
455
$html =~ s/\@\@\@EMAILFIELD\@\@\@/$temphtml/;
456
457
$temphtml = textfield(-name=>'e_realnm',
458
-default=>$e_realnm,
459
-size=>'50',
460
-override=>'1');
461
$html =~ s/\@\@\@REALNAMEFIELD\@\@\@/$temphtml/;
462
463
$temphtml = submit(-name=>'addmod_button',
464
-value=>$lang_text{'addmod'},
465
-onClick=>'AddMod()',
466
-class=>'medtext');
467
$html =~ s/\@\@\@ADDBUTTON\@\@\@/$temphtml/;
468
469
$temphtml = '';
470
my $bgcolor = $style{"tablerow_dark"};
471
foreach ( sort keys %from_list ) {
472
my $key=$_;$key=~s/'/\\'/; # escape ' for javascript
473
my $val=$from_list{$_};$val=~s/'/\\'/;
474
my $txt=$_;
475
$txt .= " ($lang_text{'email_alias'})" if (/\@$domain$/);
476
$temphtml .= qq|<tr bgcolor=$bgcolor |.
477
qq|onMouseOver='this.style.backgroundColor=$style{tablerow_hicolor};' |.
478
qq|onMouseOut='this.style.backgroundColor=$bgcolor;' |.
479
qq|>\n|.
480
qq|<td><a href="Javascript:Update('$key','$val')">$txt</a></td>|.
481
qq|<td>$from_list{$_}</td>|.
482
qq|<td align="center">|.
483
submit(-name=>'aliasdel_button',
484
-value=>$lang_text{'delete'},
485
-onClick=>"Delete('$key')",
486
-class=>'medtext') .
487
qq|</td></tr>\n|;
488
if ($bgcolor eq $style{"tablerow_dark"}) {
489
$bgcolor = $style{"tablerow_light"};
490
} else {
491
$bgcolor = $style{"tablerow_dark"};
492
}
493
}
494
$html =~ s/\@\@\@ALIASENTRIES\@\@\@/$temphtml/;
495
496
$temphtml = submit(-name => 'changebutton',
497
-value => $chg_txt);
498
$html =~ s/\@\@\@CHANGEBUTTON\@\@\@/$temphtml/;
499
500
# delete button
501
$temphtml = startform(-action=>"$config{'ow_cgiurl'}/openwebmail-vdomain.pl").
502
ow::tool::hiddens(action=>'delete_vuser',
503
sessionid=>$thissession,
504
view=>$view,
505
vuser=>$vuser);
506
$html =~ s/\@\@\@STARTDELFORM\@\@\@/$temphtml/;
507
$html =~ s/\@\@\@DELETEBUTTON\@\@\@/$del_txt/;
508
509
# cancel button
510
$temphtml = startform(-action=>"$config{'ow_cgiurl'}/openwebmail-vdomain.pl").
511
ow::tool::hiddens(action=>'display_vuserlist',
512
sessionid=>$thissession,
513
view=>$view);
514
$html =~ s/\@\@\@STARTCANCELFORM\@\@\@/$temphtml/;
515
$temphtml = submit("$lang_text{'cancel'}");
516
$html =~ s/\@\@\@CANCELBUTTON\@\@\@/$temphtml/;
517
518
$temphtml = end_form();
519
$html =~ s/\@\@\@ENDFORM\@\@\@/$temphtml/g;
520
521
if ($alert) {
522
$html.= qq|<script language="JavaScript">\n<!--\n|.
523
qq|alert('$alert');\n|.
524
qq|//-->\n</script>\n|;
525
}
526
527
httpprint([], [htmlheader(), $html, htmlfooter(2)]);
528
}
529
########## END EDIT USER #########################################
530
531
########## CHANGE USER SETTINGS ##################################
532
sub change_vuser {
533
my $vuser_original=param('vuser')||'';
534
my $realnm=param('realnm')||'';
535
my $vuser=ow::tool::untaint(lc($vuser_original));
536
537
my $action=param('action')||'';
538
my $pwd=param('newpassword')||'';
539
my $pwd2=param('confirmnewpassword')||'';
540
my $emailkey=clean_email(param('emailaddr'));
541
my $alias=$emailkey;
542
$alias=~s/\@.*// if ($emailkey=~/\@$domain$/);
543
544
my $e_realnm=param('e_realnm')||'';
545
$e_realnm=~s/^\s*//;$e_realnm=~s/\s*$//;
546
547
my $oldchklogin=param('oldchklogin')||'';
548
my $oldchkfwd=param('oldchkfwd')||'';
549
my $olddirect=param('olddirect')||'';
550
my $chklogin=param('chklogin')||'';
551
$chklogin=0 if (is_vdomain_adm($vuser));
552
553
my $chkfwd=param('chkfwd')||'';
554
my $direct=param('direct')||'';
555
my %from_list=param('fromlist');
556
557
my %vusers=vuser_list();
558
my @vuser_list = sort (keys %vusers);
559
my @alias_list=from_2_valias($vuser,%from_list);
560
my $new=0;
561
$new=1 if ($action=~/new/);
562
my $focus='emailaddr';
563
my $alert;
564
565
if ($new) {
566
openwebmailerror(__FILE__, __LINE__, $lang_err{'vdomain_toomanyuser'}) if ($config{'vdomain_maxuser'}>0 and @vuser_list>$config{'vdomain_maxuser'});
567
if ( $pwd =~ /\*\*/ ) {
568
$pwd='';
569
$pwd2=$pwd;
570
}
571
} else {
572
openwebmailerror(__FILE__, __LINE__, "$vuser\@$domain $lang_err{'doesnt_exist'}") if (! vuser_exists($vuser,@vuser_list) );
573
}
574
575
delete $from_list{lc(param('aliasdel'))} if ( param('aliasdel') );
576
577
if ( $emailkey ) {
578
if ( $alias ne $emailkey and $alias ne $vuser) {
579
# alias entry needs additional edit checks.
580
if ( ! defined($from_list{$emailkey}) and $config{'vdomain_maxalias'} < ($#alias_list + 2) ) {
581
$alert=$lang_err{'vdomain_toomanyalias'};
582
} elsif ( valias_list_exists($vuser,$alias) ) {
583
$alert="$alias\@$domain $lang_err{'already_exists'}";
584
}
585
}
586
if (! $alert) {
587
if ( $alias eq $vuser ) {$realnm=$e_realnm}
588
else {
589
$from_list{$emailkey}=$e_realnm;
590
@alias_list=from_2_valias($vuser,%from_list); # refresh the alias list
591
}
592
$emailkey='';
593
$e_realnm='';
594
}
595
}
596
597
# changed password ?
598
if ( $pwd !~ /\*\*/ and $pwd ne $pwd2 ) {
599
$alert=$lang_err{'pwd_confirmmismatch'};
600
$focus='newpassword';
601
}
602
603
# check password length
604
if ( length($pwd) < $config{'passwd_minlen'} ) {
605
$alert=$lang_err{'pwd_tooshort'};
606
$alert=~s/\@\@\@PASSWDMINLEN\@\@\@/$config{'passwd_minlen'}/;
607
$focus='newpassword';
608
}
609
610
if ($new) {
611
if (! $vuser ) {
612
$alert = $lang_err{'vdomain_userrequired'};
613
$focus='vuser';
614
}
615
elsif (vuser_exists($vuser,@vuser_list) or valias_list_exists($vuser,$vuser)) {
616
$alert = "$vuser\@$domain $lang_err{'already_exists'}";
617
$focus='vuser';
618
}
619
}
620
621
if ( $chkfwd ) {
622
if ( $direct =~ /[&;\`\<\>\(\)\{\}]/) {
623
$alert = "$lang_text{'forward'} $lang_text{'email'} $lang_err{'has_illegal_chars'}";
624
$focus='direct';
625
} else {
626
# remove self email from forward list
627
my @forwards=();
628
foreach ( split(/[,;\n\r]+/, $direct ) ) {
629
$_=clean_email($_);
630
next if ( /^$/ or /^$vuser\@$domain$/ );
631
push @forwards,$_;
632
}
633
my $tempdirect=join(', ',@forwards);
634
if ( ! $tempdirect ) {
635
$alert = $lang_err{'vdomain_fwdrequired'};
636
$focus='direct';
637
} else { $direct = $tempdirect; }
638
}
639
}
640
641
if ( $alert or param('addmod') or param('aliasdel') ) {
642
edit_vuser($focus, $alert, $pwd, $pwd2, $emailkey, $e_realnm, $realnm, %from_list);
643
return;
644
}
645
646
my $vgid=getgrnam('mail'); # for better compatibility with other mail progs
647
648
if ( $new ) { # CREATE NEW USER
649
my $aliastxt='';
650
$aliastxt=" - aliases: @alias_list" if (@alias_list);
651
writelog("vdomain $user: create vuser $vuser\@$domain$aliastxt" );
652
# CREATE USER IN VIRTUAL PASSWD
653
vpasswd_update($vuser_original,0,$pwd,$chklogin);
654
655
my ($vuid, $vhomedir, $release) = get_uid_home_release($vuser,$domain);
656
657
# switch to root
658
my ($origruid, $origeuid, $origegid)=ow::suid::set_uid_to_root();
659
660
# CREATE USER HOME DIRECTORY
661
if ( !-d $vhomedir ) {
662
if (mkdir ($vhomedir, 0700) && chown($vuid, $vgid, $vhomedir)) {
663
writelog("vdomain $user: $vuser\@$domain create homedir - $vhomedir, uid=$vuid, gid=$vgid");
664
} else {
665
openwebmailerror(__FILE__, __LINE__, "$lang_err{'cant_create_dir'} $vhomedir ($!)");
666
}
667
}
668
669
# switch to virtual user
670
ow::suid::set_euid_egids($vuid,$vgid);
671
672
# create dot directory structure
673
check_and_create_dotdir(_dotpath('/', $domain, $vuser, $vhomedir));
674
675
# default a new release date file
676
my $releasedatefile=_dotpath('release.date', $domain, $vuser, $vhomedir);
677
writelog("vdomain $user: $vuser\@$domain create release.date - $releasedatefile, uid=$vuid, gid=$vgid");
678
open(RD, ">$releasedatefile") or
679
openwebmailerror(__FILE__, __LINE__, "$lang_err{'couldnt_open'} $releasedatefile ($!)");
680
print RD "$config{'releasedate'}\n";
681
close(RD);
682
chmod(0700, $releasedatefile);
683
684
# CREATE USER .forward
685
my $dotforward="$vhomedir/.forward";
686
writelog("vdomain $user: $vuser\@$domain create .forward - $dotforward, uid=$vuid, gid=$vgid");
687
open (DF, ">$dotforward") or
688
openwebmailerror(__FILE__, __LINE__, "$lang_err{'couldnt_open'} $dotforward ($!)");
689
print DF vdomain_userspool($vuser, $vhomedir)."\n";
690
close (DF);
691
chmod(0700, $dotforward);
692
693
# return to orignal uid
694
ow::suid::restore_uid_from_root($origruid, $origeuid, $origegid);
695
696
# CREATE USER .FROM.BOOK
697
from_update($vuser, $vhomedir, $config{'releasedate'}, $vuid, $vgid, $realnm, %from_list);
698
699
# CREATE USER IN POSTFIX VIRTUAL
700
vuser_update($vuser, 0, @alias_list);
701
702
# CREATE USER IN POSTFIX ALIASES
703
if ($chkfwd) {
704
writelog("vdomain $user: $vuser\@$domain forward to $direct");
705
$dotforward=$direct;
706
} else { $dotforward=":include:$dotforward" }
707
valias_update($vuser, 0, $dotforward);
708
709
} else { # UPDATE EXISTING USER
710
# changed password ?
711
if ( $pwd !~ /\*\*/ or $chklogin != $oldchklogin ) {
712
my $action=0;
713
$action=2 if ($pwd =~ /\*\*/);
714
vpasswd_update($vuser_original,$action,$pwd,$chklogin);
715
}
716
717
my ($vuid, $vhomedir, $release) = get_uid_home_release($vuser,$domain);
718
my ($orig_realnm,%orig_from_list) = from_list($vuser); # original values
719
my @orig_alias_list=from_2_valias($vuser,%orig_from_list);
720
721
my $match = 1;
722
# changed virtual alias?
723
if ($#orig_alias_list == $#alias_list) {
724
foreach (@alias_list) {
725
if ($_ ne $orig_alias_list[0] ) {
726
$match=0;
727
last;
728
}
729
shift @orig_alias_list;
730
}
731
$match=0 if ( $#orig_alias_list >= 0 );
732
} else { $match=0; }
733
if (! $match) {
734
vuser_update($vuser, 0, @alias_list);
735
} else {
736
# changed froms?
737
if ($orig_realnm eq $realnm) {
738
foreach (keys %from_list) {
739
if (! defined( $orig_from_list{$_} ) or $orig_from_list{$_} ne $from_list{$_} ) {
740
$match=0;
741
last;
742
}
743
delete $orig_from_list{$_};
744
}
745
$match=0 if ( keys %orig_from_list );
746
} else { $match=0; }
747
}
748
from_update($vuser, $vhomedir, $release, $vuid, $vgid, $realnm, %from_list) if ( ! $match );
749
750
# changed fwd to
751
if ($chkfwd != $oldchkfwd or $direct ne $olddirect) {
752
if ($chkfwd) {
753
writelog("vdomain $user: $vuser\@$domain forward to $direct");
754
valias_update($vuser, 0, $direct);
755
} else {
756
writelog("vdomain $user: $vuser\@$domain remove forward");
757
valias_update($vuser, 0, ":include:$vhomedir/.forward");
758
}
759
}
760
}
761
762
display_vuserlist();
763
}
764
765
########## END CHANGE USER #######################################
766
767
########## DELETE USER ##########################################
768
sub delete_vuser {
769
my $vuser_original = param('vuser')||'';
770
my $vuser=ow::tool::untaint(lc($vuser_original));
771
772
if ( vuser_exists($vuser,vuser_list()) ) {
773
# get the home directory before we remove the user from password file or trouble later!
774
my ($vuid, $vhomedir, $release) = get_uid_home_release($vuser,$domain);
775
776
writelog("vdomain $user: $vuser\@$domain delete $vuser_original");
777
# DELETE USER IN VMPOP3D PASSWD
778
vpasswd_update($vuser_original,1);
779
# DELETE USER IN POSTFIX VIRTUAL
780
vuser_update($vuser, 1);
781
# DELETE USER IN POSTFIX ALIASES
782
valias_update($vuser, 1);
783
784
# switch to root
785
my ($origruid, $origeuid, $origegid)=ow::suid::set_uid_to_root();
786
787
# DELETE MAILBOX FILE
788
my $spoolfile=ow::tool::untaint("$config{'vdomain_vmpop3_mailpath'}/$domain/$vuser");
789
if (-e $spoolfile) {
790
writelog("vdomain $user: $vuser\@$domain remove spool file - $spoolfile");
791
rmtree ($spoolfile);
792
}
793
794
# DELETE OWM USER SETTINGS
795
my $userconf=ow::tool::untaint("$config{'ow_cgidir'}/etc/users.conf/$domain/$vuser");
796
if (-e $userconf) {
797
writelog("vdomain $user: $vuser\@$domain remove userconf file - $userconf");
798
rmtree ($userconf);
799
}
800
801
# DELETE HOME DIRECTORY
802
if (-e $vhomedir) {
803
writelog("vdomain $user: $vuser\@$domain remove vhomedir - $vhomedir");
804
rmtree ($vhomedir);
805
}
806
807
# return to orignal uid
808
ow::suid::restore_uid_from_root($origruid, $origeuid, $origegid);
809
}
810
811
# go back to start and display index
812
display_vuserlist();
813
}
814
########## END DELETE USER #######################################
815
816
########## VUSER_LIST ############################################
817
sub vuser_list {
818
my %vusers;
819
820
# USERLIST FROM VMPOP3D PASSWD
821
my ($fh, $file, $origruid, $origeuid, $origegid) = root_open("$config{'vdomain_vmpop3_pwdpath'}/$domain/$config{'vdomain_vmpop3_pwdname'}");
822
while (<$fh>) {
823
next if (/^#/);
824
chomp;
825
$vusers{$1}=$2 if (/([^:]+):([^\s:]+)/);
826
}
827
root_close($fh, $file, $origruid, $origeuid, $origegid);
828
829
# include users from localusers if this is the local domain
830
foreach ( @{$config{'localusers'}} ) {
831
$vusers{$1} = '%' if (/^([^@]+)\@$domain$/);
832
}
833
return (%vusers);
834
}
835
########## END VUSER_LIST ########################################
836
837
########## VUSER_ALIAS_LIST ######################################
838
sub vuser_alias_list {
839
my (%vuser_list)=@_;
840
my %vusers=();
841
my %temp=();
842
my %alias=();
843
844
# include the user list as default aliases
845
foreach (keys %vuser_list) {
846
$temp{$_}=$_;
847
$vusers{"$_.$domain"}=1if ($vuser_list{$_}!~/^%/);
848
}
849
850
# load up the virtual aliases
851
foreach my $virtualfile (@{$config{'vdomain_postfix_virtual'}}) {
852
my ($fh, $file, $origruid, $origeuid, $origegid) = root_open($virtualfile);
853
while (<$fh>) {
854
next if (/^#/);
855
$temp{lc($1)}=lc($2) if ( /^\s*([^@]+)\@$domain\s+(\S+)\.$domain\s*$/i );
856
}
857
root_close($fh, $file, $origruid, $origeuid, $origegid);
858
}
859
860
# add in the local user aliases
861
if (is_localdomain()) {
862
foreach my $aliasfile (@{$config{'vdomain_postfix_aliases'}}) {
863
my ($fh, $file, $origruid, $origeuid, $origegid) = root_open($aliasfile);
864
while (<$fh>) {
865
s/^\s+//;s/\s+$//;
866
$temp{lc($1)}=lc($2) if( ! /^#/ and /^([^\s:]+)\s*:\s*(.+)$/ and ! $vusers{$1});
867
}
868
root_close($fh, $file, $origruid, $origeuid, $origegid);
869
}
870
# compact the aliases of aliases
871
foreach (keys %temp) {
872
my $brkloop=500; # carefull of alias loops!
873
while ($temp{$temp{$_}} and $temp{$_} ne $temp{$temp{$_}} and $brkloop) { $brkloop--; $temp{$_}=$temp{$temp{$_}} }
874
writelog( "vdomain $user $_ is stuck in an alias loop.") if (! $brkloop);
875
}
876
}
877
878
foreach ( keys %temp ) {
879
$alias{'list'}{$_}=$temp{$_};
880
push @{$alias{'aliases'}{$temp{$_}}}, $_ if ( $temp{$_} ne $_ );
881
}
882
return %alias;
883
}
884
########## END VUSER_ALIAS_LIST ##################################
885
886
########## VUSER_FWD_LIST ########################################
887
sub vuser_fwd_list {
888
my @vusers=@_;
889
my %fwd;
890
foreach (@vusers){$fwd{$_}=0}
891
my ($fh, $file, $origruid, $origeuid, $origegid) = root_open(${$config{'vdomain_postfix_aliases'}}[0]);
892
while (<$fh>) {
893
next if (/^#/);
894
if ( /^\s*(\S+)\.$domain\s*:\s*(.+)/i and defined $fwd{lc($1)}) {
895
my ($user,$entry)=(lc($1),$2);
896
$entry=~s/\s*$//;
897
$fwd{$user}=$entry if ( $entry !~ /:include:/ );
898
}
899
}
900
root_close($fh, $file, $origruid, $origeuid, $origegid);
901
return %fwd;
902
}
903
########## END VUSER_FWD_LIST ####################################
904
905
########## VALIAS_LIST ###########################################
906
sub valias_list {
907
my ($vuser)=@_;
908
my (@alias_list, $alias);
909
910
# POSTFIX VIRTUAL=> [email protected] john.sample.com
911
foreach my $virtualfile (@{$config{'vdomain_postfix_virtual'}}) {
912
my ($fh, $file, $origruid, $origeuid, $origegid) = root_open($virtualfile);
913
while (<$fh>) {
914
next if (/^#/);
915
if ( /^\s*([^@]+)\@$domain\s+$vuser\.$domain\s*$/ ) {
916
if ( $1 ne $vuser ) {
917
$alias=lc($1);
918
push @alias_list, $alias;
919
}
920
}
921
}
922
root_close($fh, $file, $origruid, $origeuid, $origegid);
923
}
924
return (sort @alias_list);
925
}
926
########## END VALIAS_LIST #######################################
927
928
########## VALIAS_LIST_EXISTS ####################################
929
sub valias_list_exists {
930
my ($vuser,$alias)=@_;
931
my $fnd=0;
932
933
foreach my $virtualfile (@{$config{'vdomain_postfix_virtual'}}) {
934
my ($fh, $file, $origruid, $origeuid, $origegid) = root_open($virtualfile);
935
while (<$fh>) {
936
next if (/^#/);
937
chomp; s/^\s*//; s/\s*$//;
938
if ( /^$alias\@$domain\s*(\S+)\.$domain\s*$/ and $1 ne $vuser ) {
939
$fnd=1; last;
940
}
941
}
942
root_close($fh, $file, $origruid, $origeuid, $origegid);
943
last if ($fnd);
944
}
945
946
# check local aliases if localdomain
947
if (! $fnd and is_localdomain()) {
948
foreach my $aliasfile (@{$config{'vdomain_postfix_aliases'}}) {
949
my ($fh, $file, $origruid, $origeuid, $origegid) = root_open($aliasfile);
950
while (<$fh>) {
951
if( /^\s*$alias\s*:/ ) {
952
$fnd=1; last;
953
}
954
}
955
root_close($fh, $file, $origruid, $origeuid, $origegid);
956
last if ($fnd);
957
}
958
}
959
return ($fnd);
960
}
961
########## END VALIAS_LIST_EXISTS ################################
962
963
########## IS_LOCALDOMAIN ########################################
964
sub is_localdomain {
965
foreach ( @{$config{'localusers'}} ) {
966
return 1 if (/^([^@]+)\@$domain$/);
967
}
968
return 0;
969
}
970
########## END IS_LOCALDOMAIN ####################################
971
972
########## FROM_2_VALIAS #########################################
973
sub from_2_valias {
974
my ($vuser, %from_list)=@_;
975
my %alias_list=();
976
foreach (keys %from_list) {
977
$alias_list{$1}=1 if (/([^@]+)\@$domain$/ and $1 ne $vuser);
978
}
979
return (sort keys %alias_list);
980
}
981
########## END FROM_2_VALIAS #####################################
982
983
########## FROM_LIST #############################################
984
# merge the from address book with the postfix aliases
985
# If the Real user (not an alias) has an entry in the from.book then
986
# Use the name value to set the user $realnm (don't include with the rest
987
# of the from names).
988
sub from_list {
989
my ($vuser)=@_;
990
my $realnm='';
991
my ($vuid, $vhomedir, $release) = get_uid_home_release($vuser,$domain);
992
my $frombook=_dotpath('from.book',$domain,$vuser,$vhomedir);
993
994
# the user home directory structure changed pre 20031128
995
# better try to get the correct frombook path
996
if ($release lt "20031128") {
997
$frombook="$vhomedir/$config{'homedirfolderdirname'}/.from.book";
998
$frombook=ow::tool::untaint($frombook);
999
}
1000
1001
my %fromlist=();
1002
if ( root_exists($frombook) ) {
1003
my ($fh, $file, $origruid, $origeuid, $origegid) = root_open($frombook);
1004
while (<$fh>) {
1005
chomp;
1006
if ( /^\s*(\S+)\@\@\@(.*)\s*$/ ) {
1007
my ($mail, $name)=(lc($1),$2);
1008
$mail .= "\@$domain" if ($mail !~/\@/);
1009
if ($mail=~/^$vuser\@$domain$/) {$realnm=$name;}
1010
else {$fromlist{$mail}=$name;}
1011
}
1012
}
1013
root_close($fh, $file, $origruid, $origeuid, $origegid);
1014
}
1015
1016
# add in the email aliases
1017
foreach ( valias_list($vuser) ){
1018
$fromlist{"$_\@$domain"}='' if ( ! defined( $fromlist{"$_\@$domain"} ));
1019
}
1020
return $realnm,%fromlist;
1021
}
1022
########## END FROM_LIST #########################################
1023
1024
########## VUSER_EXISTS ##########################################
1025
sub vuser_exists {
1026
my ($vuser,@vuser_list)=@_;
1027
my $fnd=0;
1028
foreach (@vuser_list) {
1029
if ( $vuser eq lc($_) ) {
1030
$fnd=1; last;
1031
}
1032
}
1033
return ($fnd);
1034
}
1035
########## END VUSER_EXISTS ######################################
1036
1037
########## VUSER_UPDATE ##########################################
1038
sub vuser_update {
1039
my ($vuser,$delete, @alias_list)=@_;
1040
my ($fh, $file, $origruid, $origeuid, $origegid) = root_open(${$config{'vdomain_postfix_virtual'}}[0]);
1041
1042
my $fnd=0;
1043
my @lines;
1044
while (<$fh>) { # read the virtual user file
1045
if (/^#/) {
1046
push @lines, $_;
1047
} elsif ( /^\s*\S+\s+$vuser\.$domain\s*$/ ) { # remove existing entries for this user
1048
if ($delete) {
1049
s/\n//g; writelog("vdomain $user: $vuser\@$domain remove virtual entry - $_");
1050
}
1051
$fnd=1;
1052
} else {
1053
if ($fnd == 1) {
1054
$fnd=2;
1055
if (! $delete) {
1056
push @lines,"$vuser\@$domain\t$vuser.$domain\n";
1057
foreach my $alias (@alias_list) {
1058
push @lines,"$alias\@$domain\t$vuser.$domain\n";
1059
}
1060
writelog("vdomain $user: $vuser\@$domain update aliases: @alias_list") if (@alias_list);
1061
}
1062
}
1063
push @lines, $_;
1064
}
1065
}
1066
close ( $fh );
1067
1068
if ($fnd < 2 and ! $delete) {
1069
push @lines,"$vuser\@$domain\t$vuser.$domain\n";
1070
writelog("vdomain $user: $vuser\@$domain add virtual entry - $vuser.$domain") if (! $fnd);
1071
foreach my $alias (@alias_list) {
1072
push @lines,"$alias\@$domain\t$vuser.$domain\n";
1073
writelog("vdomain $user: $vuser\@$domain add virtual entry - $alias\@$domain $vuser.$domain") if (! $fnd);
1074
}
1075
}
1076
1077
open ($fh, ">$file") or
1078
openwebmailerror(__FILE__, __LINE__, "$lang_err{'couldnt_open'} $file ($!)");
1079
1080
print $fh @lines;
1081
1082
root_close($fh, $file, $origruid, $origeuid, $origegid);
1083
1084
# rebuild postfix virtual map index
1085
root_execute($config{'vdomain_postfix_postmap'}, $file);
1086
1087
return;
1088
}
1089
########## END VUSER_UPDATE ######################################
1090
1091
########## FROM_UPDATE ###########################################
1092
sub from_update {
1093
my ($vuser, $vhomedir, $releasedate, $vuid, $vgid, $realnm, %from_list)=@_;
1094
my ($origruid, $origeuid, $origegid)=ow::suid::set_uid_to_root();
1095
ow::suid::set_euid_egids($vuid,$vgid);
1096
1097
my $frombook=_dotpath('from.book', $domain, $vuser, $vhomedir);
1098
1099
# the user home directory structure changed pre 20031128
1100
# better try to get the correct frombook path
1101
if ($releasedate lt "20031128") {
1102
$frombook="$vhomedir/$config{'homedirfolderdirname'}/.from.book";
1103
$frombook=ow::tool::untaint($frombook);
1104
}
1105
1106
if (-e $frombook) { writelog("vdomain $user: $vuser\@$domain update from.book - $frombook"); }
1107
else { writelog("vdomain $user: $vuser\@$domain create from.book - $frombook, uid=$<, gid=$>"); }
1108
1109
ow::filelock::lock($frombook, LOCK_EX) or
1110
openwebmailerror(__FILE__, __LINE__, "$lang_err{'couldnt_lock'} $frombook");
1111
open (FB, ">$frombook") or
1112
openwebmailerror(__FILE__, __LINE__, "$lang_err{'couldnt_open'} $frombook ($!)");
1113
1114
print FB "$vuser\@$domain\@\@\@$realnm\n" if ($realnm);
1115
foreach (sort keys %from_list) {
1116
print FB "$_\@\@\@$from_list{$_}\n";
1117
}
1118
close (FB);
1119
ow::filelock::lock($frombook, LOCK_UN);
1120
1121
ow::suid::restore_uid_from_root($origruid, $origeuid, $origegid);
1122
return;
1123
}
1124
########## END FROM_UPDATE #######################################
1125
1126
########## VALIAS_UPDATE #########################################
1127
sub valias_update {
1128
my ($vuser,$delete,$entry)=@_;
1129
my ($fh, $file, $origruid, $origeuid, $origegid) = root_open(${$config{'vdomain_postfix_aliases'}}[0]);
1130
1131
my $fnd=0;
1132
$fnd=1 if ($delete);
1133
my @lines;
1134
while (<$fh>) { # read the alias file
1135
if ( /^\s*$vuser\.$domain\s*:/ ) { # replace existing entry for this alias
1136
if ($delete) {
1137
s/\n//g; writelog("vdomain $user: $vuser\@$domain remove aliases entry - $_");
1138
} else {
1139
push @lines, "$vuser.$domain:\t$entry\n"; $fnd=1;
1140
writelog("vdomain $user: $vuser\@$domain update alias entry - $vuser.$domain: $entry");
1141
}
1142
} else {
1143
push @lines, $_;
1144
}
1145
}
1146
close ( $fh );
1147
if (! $fnd) {
1148
push @lines, "$vuser.$domain:\t$entry\n";
1149
writelog("vdomain $user: $vuser\@$domain add alias entry - $vuser.$domain: $entry");
1150
}
1151
1152
open ($fh, ">$file") or
1153
openwebmailerror(__FILE__, __LINE__, "$lang_err{'couldnt_open'} $file ($!)");
1154
1155
print $fh @lines;
1156
1157
root_close($fh, $file, $origruid, $origeuid, $origegid);
1158
1159
# rebuild postfix virtual map index
1160
root_execute($config{'vdomain_postfix_postalias'}, $file);
1161
1162
return;
1163
}
1164
########## END VALIAS_UPDATE #####################################
1165
1166
########## VPASSWD_UPDATE ########################################
1167
sub vpasswd_update {
1168
my ($vuser,$action,$pwd,$disable)=@_;
1169
# $action = 0 encrypt and change password
1170
# $action = 1 delete password entry
1171
# $action = 2 switch enable/disable on existing password
1172
my $encrypted;
1173
if ( $action==0 ) {
1174
srand();
1175
my $table="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
1176
my $salt=substr($table, int(rand(length($table))), 1).
1177
substr($table, int(rand(length($table))), 1);
1178
$encrypted=crypt($pwd, $salt);
1179
$encrypted="#$encrypted" if ($disable);
1180
}
1181
1182
# update the passwd file directly without copying to .tmp file
1183
# why? Password file is only used to validate login by vm-pop3d
1184
# A lock here at worst will only momentarily delay another user pop login.
1185
# We should be in and out of this file fast enough to not be noticed.
1186
1187
my ($fh, $file, $origruid, $origeuid, $origegid) = root_open("$config{'vdomain_vmpop3_pwdpath'}/$domain/$config{'vdomain_vmpop3_pwdname'}");
1188
1189
my $fnd=0;
1190
$fnd=1 if ($action==1);
1191
my @lines;
1192
while (<$fh>) { # read the pwd file
1193
if (/^$vuser:(.)/) {
1194
if ($action==1) {
1195
writelog("vdomain $user: $vuser\@$domain remove password entry");
1196
} else {
1197
$fnd=1;
1198
if ($action==2) {
1199
if ( $1 eq '#' and ! $disable ) {
1200
s/:#/:/;
1201
writelog("vdomain $user: $vuser\@$domain restore user login");
1202
}
1203
s/:/:#/ if ( $1 ne '#' and $disable );
1204
push @lines, $_;
1205
} else {
1206
push @lines, "$vuser:$encrypted\n";
1207
writelog("vdomain $user: $vuser\@$domain update vuser password");
1208
}
1209
}
1210
} else {
1211
push @lines, $_;
1212
}
1213
}
1214
close ( $fh );
1215
if ( ! $fnd ) {
1216
push @lines, "$vuser:$encrypted\n";
1217
writelog("vdomain $user: $vuser\@$domain create passwd entry");
1218
}
1219
writelog("vdomain $user: $vuser\@$domain disable user login") if ($disable);
1220
1221
open ($fh, ">$file") or
1222
openwebmailerror(__FILE__, __LINE__, "$lang_err{'couldnt_open'} $file ($!)");
1223
1224
print $fh @lines;
1225
1226
root_close($fh, $file, $origruid, $origeuid, $origegid);
1227
return;
1228
}
1229
########## END VPASSWD_UPDATE ####################################
1230
1231
########## GET_UID_HOME_RELEASE ##########################################
1232
sub get_uid_home_release {
1233
my ($user, $domain)=@_;
1234
my $releasedate='';
1235
1236
# switch to root
1237
my ($origruid, $origeuid, $origegid)=ow::suid::set_uid_to_root();
1238
1239
my ($ret,$err,$uid,$homedir) = (ow::auth::get_userinfo(\%config, "$user\@$domain"))[0,1,3,5];
1240
openwebmailerror(__FILE__, __LINE__, "$lang_err{'auth_syserr'} ret $ret, $err") if ($ret!=0);
1241
1242
if ( !$config{'use_syshomedir'} ) {
1243
$homedir = "$config{'ow_usersdir'}/".($config{'auth_withdomain'}?"$domain/".$user:$user);
1244
}
1245
$homedir=ow::tool::untaint($homedir);
1246
1247
my $releasedatefile=_dotpath('release.date', $domain, $user, $homedir);
1248
$releasedatefile="$homedir/$config{'homedirfolderdirname'}/.release.date" if (! -f $releasedatefile);
1249
$releasedatefile="$homedir/.release.date" if (! -f $releasedatefile);
1250
$releasedatefile=ow::tool::untaint($releasedatefile);
1251
1252
# the release date file may very well not exist!
1253
if (open(D, $releasedatefile)) {
1254
$releasedate=<D>;
1255
chomp($releasedate);
1256
close(D);
1257
}
1258
1259
# return to original user
1260
ow::suid::restore_uid_from_root($origruid, $origeuid, $origegid);
1261
1262
return ($uid,$homedir,$releasedate);
1263
}
1264
1265
########## ROOT_EXECUTE ##########################################
1266
sub root_execute {
1267
my @cmd;
1268
foreach my $arg (@_) {
1269
foreach (split(/\s+/, $arg)) {
1270
/^(.+)$/ && push(@cmd, $1);
1271
}
1272
}
1273
1274
# switch to root
1275
my ($origruid, $origeuid, $origegid)=ow::suid::set_uid_to_root();
1276
1277
# use execute.pl instead of system() to avoid shell escape chars in @cmd
1278
my ($stdout, $stderr, $exit, $sig)=ow::execute::execute(@cmd);
1279
1280
# return to original user
1281
ow::suid::restore_uid_from_root($origruid, $origeuid, $origegid);
1282
1283
return;
1284
}
1285
########## END ROOT_EXECUTE ######################################
1286
1287
########## ROOT_OPEN #############################################
1288
# open a file using root permissions
1289
sub root_open {
1290
$_[0]=~/^\s*([|><+]*)\s*(\S+)/;
1291
my ($action, $file)=($1, $2);
1292
1293
# create a file handle
1294
my $fh = do { local *FH };
1295
1296
# switch to root
1297
my ($origruid, $origeuid, $origegid)=ow::suid::set_uid_to_root();
1298
1299
if ($action ne '') {
1300
ow::filelock::lock($file, LOCK_EX) or
1301
openwebmailerror(__FILE__, __LINE__, "$lang_err{'couldnt_lock'} $file");
1302
} else {
1303
ow::filelock::lock($file, LOCK_SH|LOCK_NB) or
1304
openwebmailerror(__FILE__, __LINE__, "$lang_err{'couldnt_locksh'} $file");
1305
}
1306
open ($fh, "$action$file") or
1307
openwebmailerror(__FILE__, __LINE__, "$lang_err{'couldnt_open'} $file ($!)");
1308
1309
return ($fh, $file, $origruid, $origeuid, $origegid);
1310
}
1311
########## END ROOT_OPEN #########################################
1312
1313
########## ROOT_CLOSE ############################################
1314
# close a file using root permissions
1315
sub root_close {
1316
my ($fh, $file, $origruid, $origeuid, $origegid)=@_;
1317
1318
close ($fh);
1319
ow::filelock::lock($file, LOCK_UN);
1320
1321
# return to original user
1322
ow::suid::restore_uid_from_root($origruid, $origeuid, $origegid);
1323
1324
return;
1325
}
1326
########## END ROOT_CLOSE ########################################
1327
1328
########## ROOT_EXISTS ###########################################
1329
# check if file exists using root permissions
1330
sub root_exists {
1331
my ($file)=@_;
1332
my $exist=0;
1333
1334
# switch to root
1335
my ($origruid, $origeuid, $origegid)=ow::suid::set_uid_to_root();
1336
1337
$exist=1 if (-e $file);
1338
1339
# return to original user
1340
ow::suid::restore_uid_from_root($origruid, $origeuid, $origegid);
1341
1342
return $exist;
1343
}
1344
########## END FILE_EXISTS #######################################
1345
1346
########## CLEAN_EMAIL ###########################################
1347
sub clean_email {
1348
my $email=lc($_[0]);
1349
$email=~s/\s*//g; # remove spaces
1350
if ($email ne '') {
1351
my @temp=split(/\@/,$email); # split user domain
1352
$temp[1]=$domain if (! $temp[1]); # default local domain
1353
$temp[0]=safedomainname($temp[0]); # cleanup user
1354
$temp[1]=safedomainname($temp[1]); # cleanup domain
1355
$email=join( '@',@temp[0,1]);
1356
}
1357
return $email;
1358
}
1359
########## END CLEAN_EMAIL #######################################
1360