Sharedwww / cgi-bin / openwebmail / openwebmail.plOpen in CoCalc
Author: William A. Stein
1
#!/usr/bin/perl
2
#################################################################
3
# #
4
# Open WebMail - Provides a web interface to user mailboxes #
5
# #
6
# Copyright (C) 2001-2004 #
7
# The Open Webmail Team #
8
# #
9
# Copyright (C) 2000 #
10
# Ernie Miller (original GPL project: Neomail) #
11
# #
12
# This program is distributed under GNU General Public License #
13
# #
14
#################################################################
15
16
#
17
# openwebmail.pl - entry point of openwebmail
18
#
19
use vars qw($SCRIPT_DIR);
20
if ( $0 =~ m!^(\S*)/[\w\d\-\.]+\.pl! ) { $SCRIPT_DIR=$1 }
21
if ($SCRIPT_DIR eq '' && open(F, '/etc/openwebmail/openwebmail_path.conf')) {
22
$_=<F>; close(F); if ( $_=~/^(\S*)/) { $SCRIPT_DIR=$1 }
23
}
24
if ($SCRIPT_DIR eq '') { print "Content-type: text/html\n\nSCRIPT_DIR not set in /etc/openwebmail/openwebmail_path.conf !\n"; exit 0; }
25
push (@INC, $SCRIPT_DIR);
26
27
foreach (qw(ENV BASH_ENV CDPATH IFS TERM)) {delete $ENV{$_}}; $ENV{PATH}='/bin:/usr/bin'; # secure ENV
28
umask(0002); # make sure the openwebmail group can write
29
30
use strict;
31
use Fcntl qw(:DEFAULT :flock);
32
use CGI qw(-private_tempfiles :standard);
33
use CGI::Carp qw(fatalsToBrowser carpout);
34
use Socket; # for gethostbyaddr() in ip2hostname
35
use MIME::Base64;
36
37
require "modules/dbm.pl";
38
require "modules/suid.pl";
39
require "modules/filelock.pl";
40
require "modules/tool.pl";
41
require "modules/datetime.pl";
42
require "modules/lang.pl";
43
require "modules/mime.pl";
44
require "auth/auth.pl";
45
require "quota/quota.pl";
46
require "shares/ow-shared.pl";
47
require "shares/pop3book.pl";
48
require "shares/upgrade.pl";
49
50
# common globals
51
use vars qw(%config %config_raw);
52
use vars qw($thissession);
53
use vars qw($default_logindomain $loginname $logindomain $loginuser);
54
use vars qw($domain $user $userrealname $uuid $ugid $homedir);
55
use vars qw(%prefs %style);
56
57
# extern vars
58
use vars qw(@openwebmailrcitem); # defined in ow-shared.pl
59
use vars qw(%lang_text %lang_err); # defined in lang/xy
60
61
########## MAIN ##################################################
62
openwebmail_requestbegin();
63
$SIG{PIPE}=\&openwebmail_exit; # for user stop
64
$SIG{TERM}=\&openwebmail_exit; # for user stop
65
66
load_owconf(\%config_raw, "/usr/share/openwebmail/configs/openwebmail.conf");
67
read_owconf(\%config, \%config_raw, "/etc/openwebmail/openwebmail.conf") if (-f "/etc/openwebmail/openwebmail.conf");
68
loadlang($config{'default_language'}); # so %lang... can be used in error msg
69
70
# check & create mapping table for solar/lunar, b2g, g2b convertion
71
foreach my $table ('b2g', 'g2b', 'lunar') {
72
if ( $config{$table.'_map'} && !ow::dbm::exist("$config{'ow_mapsdir'}/$table")) {
73
print qq|Content-type: text/html\n\n|.
74
qq|Please execute '$config{'ow_cgidir'}/openwebmail-tool.pl --init' on server first!|;
75
openwebmail_exit(0);
76
}
77
}
78
79
if ($config{'logfile'}) {
80
my $mailgid=getgrnam('mail');
81
my ($fmode, $fuid, $fgid) = (stat($config{'logfile'}))[2,4,5];
82
if ( !($fmode & 0100000) ) {
83
open (LOGFILE,">>$config{'logfile'}") or
84
openwebmailerror(__FILE__, __LINE__, "$lang_err{'couldnt_open'} $lang_text{'file'} $config{'logfile'}! ($!)");
85
close(LOGFILE);
86
}
87
chmod(0660, $config{'logfile'}) if (($fmode&0660)!=0660);
88
owchown($>, $mailgid, $config{'logfile'}) if ($fuid!=$>||$fgid!=$mailgid);
89
}
90
91
if ( $config{'forced_ssl_login'} && # check the forced use of SSL
92
!($ENV{'HTTPS'}=~/on/i||$ENV{'SERVER_PORT'}==443) ) {
93
my ($start_url, $refresh, $js);
94
$start_url=$config{'start_url'};
95
$start_url="https://$ENV{'HTTP_HOST'}$start_url" if ($start_url!~s!^https?://!https://!i);
96
if ($ENV{'HTTP_USER_AGENT'}!~/MSIE.+Mac/) {
97
# reload page with Refresh header only if not MSIE on Mac
98
$refresh=qq|<meta http-equiv="refresh" content="5;URL=$start_url">|;
99
} else {
100
# reload page with java script if MSIE on Mac
101
$js=qq|<script language="JavaScript">\n<!--\n|.
102
qq|setTimeout("window.location.href='$start_url'", 5000);\n|.
103
qq|//-->\n</script>|;
104
}
105
print qq|Content-type: text/html\n\n|.
106
qq|<html><head>$refresh</head><body>\n|.
107
qq|Service is available over SSL only,<br>\n|.
108
qq|you will be redirected to <a href="$start_url">SSL login</a> page in 5 seconds...\n|.
109
qq|$js\n|.
110
qq|</body></html>\n|;
111
openwebmail_exit(0);
112
}
113
114
if ( param('loginname') && param('password') ) {
115
login();
116
} elsif (matchlist_fromhead('allowed_autologinip', ow::tool::clientip()) &&
117
cookie('openwebmail-autologin')) {
118
autologin();
119
} else {
120
loginmenu(); # display login page if no login
121
}
122
123
openwebmail_requestend();
124
########## END MAIN ##############################################
125
126
########## LOGINMENU #############################################
127
sub loginmenu {
128
# clear vars that may have values from autologin
129
($domain, $user, $userrealname, $uuid, $ugid, $homedir)=('', '', '', '', '', '');
130
131
$logindomain=param('logindomain')||lc($ENV{'HTTP_HOST'});
132
$logindomain=~s/:\d+$//; # remove port number
133
$logindomain=lc(safedomainname($logindomain));
134
$logindomain=$config{'domainname_equiv'}{'map'}{$logindomain} if (defined($config{'domainname_equiv'}{'map'}{$logindomain}));
135
136
matchlist_exact('allowed_serverdomain', $logindomain) or
137
openwebmailerror(__FILE__, __LINE__, "Service is not available for domain '$logindomain'");
138
139
read_owconf(\%config, \%config_raw, "$config{'ow_sitesconfdir'}/$logindomain") if ( -f "$config{'ow_sitesconfdir'}/$logindomain");
140
if ( $>!=0 && # setuid is required if spool is located in system dir
141
($config{'mailspooldir'} eq "/var/mail" ||
142
$config{'mailspooldir'} eq "/var/spool/mail")) {
143
print "Content-type: text/html\n\n'$0' must setuid to root"; openwebmail_exit(0);
144
}
145
146
%prefs = readprefs();
147
%style = readstyle($prefs{'style'});
148
loadlang($prefs{'language'});
149
150
my ($html, $temphtml);
151
$html = applystyle(readtemplate("login.template"));
152
153
$temphtml = startform(-action=>"$config{'ow_cgiurl'}/openwebmail.pl",
154
-name=>'login');
155
if (defined(param('action'))) {
156
$temphtml .= ow::tool::hiddens(action=>param('action'));
157
$temphtml .= ow::tool::hiddens(to=>param('to')) if (defined(param('to')));
158
$temphtml .= ow::tool::hiddens(subject=>param('subject')) if (defined(param('subject')));
159
}
160
$html =~ s/\@\@\@STARTFORM\@\@\@/$temphtml/;
161
162
$temphtml = textfield(-name=>'loginname',
163
-default=>'',
164
-size=>'14',
165
-onChange=>'focuspwd()',
166
-override=>'1');
167
$html =~ s/\@\@\@LOGINNAMEFIELD\@\@\@/$temphtml/;
168
169
$temphtml = password_field(-name=>'password',
170
-default=>'',
171
-size=>'14',
172
-onChange=>'focusloginbutton()',
173
-override=>'1');
174
$html =~ s/\@\@\@PASSWORDFIELD\@\@\@/$temphtml/;
175
176
if ($ENV{'HTTP_ACCEPT_ENCODING'}=~/\bgzip\b/ &&
177
ow::tool::has_module('Compress/Zlib.pm') ) {
178
$temphtml = checkbox(-name=>'httpcompress',
179
-value=>'1',
180
-checked=>cookie("openwebmail-httpcompress")||0,
181
-onClick=>'httpcompresshelp()',
182
-label=>'');
183
} else {
184
$temphtml = checkbox(-name=>'httpcompress',
185
-value=>'1',
186
-checked=>0,
187
-disabled=>1,
188
-label=>'');
189
}
190
$html =~ s/\@\@\@HTTPCOMPRESSIONCHECKBOX\@\@\@/$temphtml/;
191
192
if (matchlist_fromhead('allowed_autologinip', ow::tool::clientip()) ) {
193
templateblock_enable($html, 'AUTOLOGIN');
194
$temphtml = checkbox(-name=>'autologin',
195
-value=>'1',
196
-checked=>cookie("openwebmail-autologin")||0,
197
-onClick=>'autologinhelp()',
198
-label=>'');
199
$html =~ s/\@\@\@AUTOLOGINCHECKBOX\@\@\@/$temphtml/;
200
} else {
201
$temphtml = '';
202
templateblock_disable($html, 'AUTOLOGIN', $temphtml);
203
}
204
205
if ($config{'enable_domainselectmenu'} && $#{$config{'domainnames'}} >0) {
206
templateblock_enable($html, 'DOMAIN');
207
$temphtml = popup_menu(-name=>'logindomain',
208
-default=>$logindomain,
209
-values=>[@{$config{'domainselmenu_list'}}] );
210
$html =~ s/\@\@\@DOMAINMENU\@\@\@/$temphtml/;
211
} else {
212
$temphtml = ow::tool::hiddens(logindomain=>param('logindomain')||'');
213
templateblock_disable($html, 'DOMAIN', $temphtml);
214
}
215
216
$temphtml = submit(-name =>"loginbutton",
217
-value=>$lang_text{'login'} );
218
$html =~ s/\@\@\@LOGINBUTTON\@\@\@/$temphtml/;
219
$temphtml = reset("$lang_text{'clear'}");
220
$html =~ s/\@\@\@CLEARBUTTON\@\@\@/$temphtml/;
221
$temphtml = end_form();
222
$html =~ s/\@\@\@ENDFORM\@\@\@/$temphtml/;
223
224
# undef env to prevent httpprint() doing compression on login page
225
undef $ENV{'HTTP_ACCEPT_ENCODING'};
226
httpprint([], [htmlheader(), $html, htmlfooter(1)]);
227
}
228
########## END LOGINMENU #########################################
229
230
########## LOGIN #################################################
231
sub login {
232
my $clientip=ow::tool::clientip();
233
234
$loginname=param('loginname')||'';
235
$default_logindomain=param('logindomain')||'';
236
237
($logindomain, $loginuser)=login_name2domainuser($loginname, $default_logindomain);
238
239
matchlist_exact('allowed_serverdomain', $logindomain) or
240
openwebmailerror(__FILE__, __LINE__, "Service is not available for domain '$logindomain'");
241
242
if (!is_localuser("$loginuser\@$logindomain") && -f "$config{'ow_sitesconfdir'}/$logindomain") {
243
read_owconf(\%config, \%config_raw, "$config{'ow_sitesconfdir'}/$logindomain");
244
}
245
if ( $>!=0 && # setuid is required if spool is located in system dir
246
($config{'mailspooldir'} eq "/var/mail" ||
247
$config{'mailspooldir'} eq "/var/spool/mail")) {
248
print "Content-type: text/html\n\n'$0' must setuid to root"; openwebmail_exit(0);
249
}
250
ow::auth::load($config{'auth_module'});
251
252
# create domain logfile
253
if ($config{'logfile'}) {
254
my $mailgid=getgrnam('mail');
255
my ($fmode, $fuid, $fgid) = (stat($config{'logfile'}))[2,4,5];
256
if ( !($fmode & 0100000) ) {
257
open (LOGFILE,">>$config{'logfile'}") or
258
openwebmailerror(__FILE__, __LINE__, "$lang_err{'couldnt_open'} $lang_text{'file'} $config{'logfile'}! ($!)");
259
close(LOGFILE);
260
}
261
chmod(0660, $config{'logfile'}) if (($fmode&0660)!=0660);
262
owchown($>, $mailgid, $config{'logfile'}) if ($fuid!=$>||$fgid!=$mailgid);
263
}
264
265
update_virtuserdb(); # update index db of virtusertable
266
267
%prefs = readprefs();
268
%style = readstyle($prefs{'style'});
269
loadlang($prefs{'language'});
270
271
($domain, $user, $userrealname, $uuid, $ugid, $homedir)
272
=get_domain_user_userinfo($logindomain, $loginuser);
273
if ($user eq "") {
274
sleep $config{'loginerrordelay'}; # delayed response
275
writelog("login error - no such user - loginname=$loginname");
276
# show 'pwd incorrect' instead of 'user not exist' for better security
277
my $html = applystyle(readtemplate("loginfailed.template"));
278
$html =~ s/\@\@\@ERRORMSG\@\@\@/$lang_err{'pwd_incorrect'}/;
279
httpprint([], [htmlheader(), $html, htmlfooter(1)]);
280
return;
281
}
282
283
if (!matchlist_fromhead('allowed_rootloginip', $clientip)) {
284
if ($user eq 'root' || $uuid==0) {
285
sleep $config{'loginerrordelay'}; # delayed response
286
writelog("login error - root login attempt");
287
my $html = applystyle(readtemplate("loginfailed.template"));
288
$html =~ s/\@\@\@ERRORMSG\@\@\@/$lang_err{'norootlogin'}/;
289
httpprint([], [htmlheader(), $html, htmlfooter(1)]);
290
return;
291
}
292
}
293
294
my $userconf="$config{'ow_usersconfdir'}/$user";
295
$userconf="$config{'ow_usersconfdir'}/$domain/$user" if ($config{'auth_withdomain'});
296
read_owconf(\%config, \%config_raw, "$userconf") if ( -f "$userconf");
297
298
matchlist_exact('allowed_serverdomain', $logindomain) or
299
openwebmailerror(__FILE__, __LINE__, "Service is not available for $loginuser at '$logindomain'");
300
301
matchlist_fromhead('allowed_clientip', $clientip) or
302
openwebmailerror(__FILE__, __LINE__, $lang_err{'disallowed_client'}."<br> ( ip: $clientip )");
303
304
if (!matchlist_all('allowed_clientdomain')) {
305
my $clientdomain=ip2hostname($clientip);
306
matchlist_fromtail('allowed_clientdomain', $clientdomain) or
307
openwebmailerror(__FILE__, __LINE__, $lang_err{'disallowed_client'}."<br> ( host: $clientdomain )");
308
}
309
310
my $owuserdir = ow::tool::untaint("$config{'ow_usersdir'}/".($config{'auth_withdomain'}?"$domain/$user":$user));
311
$homedir = $owuserdir if ( !$config{'use_syshomedir'} );
312
313
$user=ow::tool::untaint($user);
314
$uuid=ow::tool::untaint($uuid);
315
$ugid=ow::tool::untaint($ugid);
316
$homedir=ow::tool::untaint($homedir);
317
318
# create domainhome for stuff not put in syshomedir
319
if (!$config{'use_syshomedir'} || !$config{'use_syshomedir_for_dotdir'}) {
320
if ($config{'auth_withdomain'}) {
321
my $domainhome=ow::tool::untaint("$config{'ow_usersdir'}/$domain");
322
if (!-d $domainhome) {
323
mkdir($domainhome, 0750);
324
openwebmailerror(__FILE__, __LINE__, "Couldn't create domain homedir $domainhome") if (! -d $domainhome);
325
my $mailgid=getgrnam('mail');
326
owchown($uuid, $mailgid, $domainhome);
327
}
328
}
329
}
330
upgrade_20030323();
331
332
# try to load lang and style based on user's preference (for error msg)
333
if ($>==0 || $>== $uuid) {
334
%prefs = readprefs();
335
%style = readstyle($prefs{'style'});
336
loadlang($prefs{'language'});
337
}
338
339
my ($errorcode, $errormsg, @sessioncount);
340
my $password = param('password') || '';
341
if ($config{'auth_withdomain'}) {
342
($errorcode, $errormsg)=ow::auth::check_userpassword(\%config, "$user\@$domain", $password);
343
} else {
344
($errorcode, $errormsg)=ow::auth::check_userpassword(\%config, $user, $password);
345
}
346
if ( $errorcode==0 ) {
347
# search old alive session and deletes old expired sessionids
348
($thissession, @sessioncount) = search_clean_oldsessions
349
($loginname, $default_logindomain, $uuid, cookie("$user-sessionid"));
350
if ($thissession eq "") { # name the new sessionid
351
my $n=rand(); for (1..5) { last if $n>=0.1; $n*=10; } # cover bug if rand return too small value
352
$thissession = $loginname."*".$default_logindomain."-session-$n";
353
}
354
$thissession =~ s#!##g; # remove !
355
$thissession =~ s#:##g; # remove :
356
$thissession =~ s!\.\.+!!g; # remove ..
357
if ($thissession =~ /^([\w\.\-\%\@]+\*[\w\.\-]*\-session\-0\.\d+)$/) {
358
$thissession = $1; # untaint
359
} else {
360
openwebmailerror(__FILE__, __LINE__, "Session ID $thissession $lang_err{'has_illegal_chars'}");
361
}
362
writelog("login - $thissession - active=$sessioncount[0],$sessioncount[1],$sessioncount[2]");
363
364
# create owuserdir for stuff not put in syshomedir
365
# this must be done before changing to the user's uid.
366
if ( !$config{'use_syshomedir'} || !$config{'use_syshomedir_for_dotdir'} ) {
367
if (!-d $owuserdir) {
368
if (mkdir ($owuserdir, oct(700)) && owchown($uuid, (split(/\s+/,$ugid))[0], $owuserdir)) {
369
writelog("create owuserdir - $owuserdir, uid=$uuid, gid=".(split(/\s+/,$ugid))[0]);
370
} else {
371
openwebmailerror(__FILE__, __LINE__, "$lang_err{'cant_create_dir'} $owuserdir ($!)");
372
}
373
}
374
}
375
376
# create owuserdir for stuff not put in syshomedir
377
# this must be done before changing to the user's uid.
378
if ( !$config{'use_syshomedir'} || !$config{'use_syshomedir_for_dotdir'} ) {
379
if (!-d $owuserdir) {
380
if (mkdir ($owuserdir, oct(700)) && owchown($uuid, (split(/\s+/,$ugid))[0], $owuserdir)) {
381
writelog("create owuserdir - $owuserdir, uid=$uuid, gid=".(split(/\s+/,$ugid))[0]);
382
} else {
383
openwebmailerror(__FILE__, __LINE__, "$lang_err{'cant_create_dir'} $owuserdir ($!)");
384
}
385
}
386
}
387
388
# create the user's syshome directory if necessary.
389
# this must be done before changing to the user's uid.
390
if (!-d $homedir && $config{'create_syshomedir'}) {
391
if (mkdir ($homedir, oct(700)) && owchown($uuid, (split(/\s+/,$ugid))[0], $homedir)) {
392
writelog("create homedir - $homedir, uid=$uuid, gid=".(split(/\s+/,$ugid))[0]);
393
} else {
394
openwebmailerror(__FILE__, __LINE__, "$lang_err{'cant_create_dir'} $homedir ($!)");
395
}
396
}
397
398
umask(0077);
399
if ( $>==0 ) { # switch to uuid:mailgid if script is setuid root.
400
my $mailgid=getgrnam('mail'); # for better compatibility with other mail progs
401
ow::suid::set_euid_egids($uuid, $mailgid, split(/\s+/,$ugid));
402
if ( $)!~/\b$mailgid\b/) { # group mail doesn't exist?
403
openwebmailerror(__FILE__, __LINE__, "Set effective gid to mail($mailgid) failed!");
404
}
405
}
406
407
# get user release date
408
my $user_releasedate=read_releasedatefile();
409
410
# create folderdir if it doesn't exist
411
my $folderdir="$homedir/$config{'homedirfolderdirname'}";
412
if (! -d $folderdir ) {
413
if (mkdir ($folderdir, 0700)) {
414
writelog("create folderdir - $folderdir, euid=$>, egid=$)");
415
} else {
416
openwebmailerror(__FILE__, __LINE__, "$lang_err{'cant_create_dir'} $folderdir ($!)");
417
}
418
upgrade_20021218($user_releasedate);
419
}
420
421
# create dirs under ~/.openwebmail/
422
check_and_create_dotdir(dotpath('/'));
423
424
# create system spool file /var/mail/xxxx
425
my $spoolfile=ow::tool::untaint((get_folderpath_folderdb($user, 'INBOX'))[0]);
426
if ( ! -f "$spoolfile" ) {
427
open (F, ">>$spoolfile"); close(F);
428
owchown($uuid, (split(/\s+/,$ugid))[0], $spoolfile);
429
}
430
431
# create session file
432
my $sessioncookie_value;
433
if ( -f "$config{'ow_sessionsdir'}/$thissession" ) { # continue an old session?
434
$sessioncookie_value = cookie("$user-sessionid");
435
} else { # a brand new sesion?
436
$sessioncookie_value = crypt(rand(),'OW');
437
}
438
open (SESSION, "> $config{'ow_sessionsdir'}/$thissession") or # create sessionid
439
openwebmailerror(__FILE__, __LINE__, "$lang_err{'couldnt_open'} $config{'ow_sessionsdir'}/$thissession! ($!)");
440
print SESSION $sessioncookie_value, "\n";
441
print SESSION $clientip, "\n";
442
print SESSION join("\@\@\@", $domain, $user, $userrealname, $uuid, $ugid, $homedir), "\n";
443
close (SESSION);
444
writehistory("login - $thissession");
445
446
# symbolic link ~/mbox to ~/mail/saved-messages
447
if ( $config{'symboliclink_mbox'} &&
448
((lstat("$homedir/mbox"))[2] & 07770000) eq 0100000) { # regular file
449
if (ow::filelock::lock("$folderdir/saved-messages", LOCK_EX|LOCK_NB)) {
450
writelog("symlink mbox - $homedir/mbox -> $folderdir/saved-messages");
451
452
if (! -f "$folderdir/saved-messages") {
453
open(F,">>$folderdir/saved-messages"); close(F);
454
}
455
rename("$homedir/mbox", "$homedir/mbox.tmp.$$");
456
symlink("$folderdir/saved-messages", "$homedir/mbox");
457
458
open(T,"$homedir/mbox.tmp.$$");
459
open(F,"+<$folderdir/saved-messages");
460
seek(F, 0, 2); # seek to end;
461
while(<T>) { print F $_; }
462
close(F);
463
close(T);
464
465
unlink("$homedir/mbox.tmp.$$");
466
ow::filelock::lock("$folderdir/saved-messages", LOCK_UN);
467
}
468
}
469
470
# check if releaseupgrade() is required
471
if ($user_releasedate ne $config{'releasedate'}) {
472
upgrade_all($user_releasedate) if ($user_releasedate ne "");
473
update_releasedatefile();
474
}
475
update_openwebmailrc($user_releasedate);
476
477
# remove stale folder db
478
my (@validfolders, $inboxusage, $folderusage);
479
getfolders(\@validfolders, \$inboxusage, \$folderusage);
480
del_staledb($user, \@validfolders);
481
482
# create authpop3 book if auth_pop3.pl or auth_ldap_vpopmail.pl
483
if ($config{'auth_module'} eq 'auth_pop3.pl' ||
484
$config{'auth_module'} eq 'auth_ldap_vpopmail.pl') {
485
update_authpop3book(dotpath('authpop3.book'), $domain, $user, $password);
486
}
487
488
# redirect page to openwebmail main/calendar/webdisk/prefs
489
my $refreshurl=refreshurl_after_login(param('action'));
490
if ( ! -f dotpath('openwebmailrc') ) {
491
$refreshurl="$config{'ow_cgiurl'}/openwebmail-prefs.pl?sessionid=$thissession&action=userfirsttime";
492
}
493
if ( !$config{'stay_ssl_afterlogin'} && # leave SSL
494
($ENV{'HTTPS'}=~/on/i || $ENV{'SERVER_PORT'}==443) ) {
495
$refreshurl="http://$ENV{'HTTP_HOST'}$refreshurl" if ($refreshurl!~s!^https?://!http://!i);
496
}
497
498
my @cookies=();
499
500
# cookie for autologin switch, expired until 1 month later
501
my $autologin=param('autologin')||0;
502
if ($autologin && matchlist_fromhead('allowed_autologinip', $clientip)) {
503
$autologin=autologin_add();
504
} else {
505
autologin_rm();
506
$autologin=0;
507
}
508
push(@cookies, cookie(-name => 'openwebmail-autologin',
509
-value => $autologin,
510
-path => '/',
511
-expires => '+1M') );
512
513
# if autologin then expired until 1 week, else expired until browser close
514
my @expire=(); @expire=(-expires => '+7d') if ($autologin);
515
# cookie for openwebmail to verify session,
516
push(@cookies, cookie(-name => "$user-sessionid",
517
-value => $sessioncookie_value,
518
-path => '/',
519
@expire) );
520
# cookie for ssl session, expired if browser closed
521
push(@cookies, cookie(-name => 'openwebmail-ssl',
522
-value => ($ENV{'HTTPS'}=~/on/i ||
523
$ENV{'SERVER_PORT'}==443 ||
524
0),
525
@expire) );
526
527
# cookie for autologin other other ap to find openwebmail loginname, default_logindomain,
528
# expired until 1 month later
529
push(@cookies, cookie(-name => 'openwebmail-loginname',
530
-value => $loginname,
531
-path => '/',
532
-expires => '+1M') );
533
push(@cookies, cookie(-name => 'openwebmail-default_logindomain',
534
-value => $default_logindomain,
535
-path => '/',
536
-expires => '+1M') );
537
# cookie for httpcompress switch, expired until 1 month later
538
push(@cookies, cookie(-name => 'openwebmail-httpcompress',
539
-value => param('httpcompress')||0,
540
-path => '/',
541
-expires => '+1M') );
542
543
my ($js, $repeatstr)=('', 'no-repeat');
544
my @header=(-cookie=>\@cookies);
545
if ($ENV{'HTTP_USER_AGENT'}!~/MSIE.+Mac/) {
546
# reload page with Refresh header only if not MSIE on Mac
547
push(@header, -refresh=>"0.1;URL=$refreshurl");
548
} else {
549
# reload page with java script in 0.1 sec
550
$js=qq|<script language="JavaScript">\n<!--\n|.
551
qq|setTimeout("window.location.href='$refreshurl'", 100);\n|.
552
qq|//-->\n</script>|;
553
}
554
$repeatstr='repeat' if ($prefs{'bgrepeat'});
555
556
my $softwarestr=$config{'name'};
557
if ($config{'enable_about'} && $config{'about_info_software'}) {
558
$softwarestr.=qq| $config{'version'} $config{'releasedate'}|;
559
}
560
561
my $countstr='';
562
if ($config{'session_count_display'}) {
563
$countstr=qq|<br><br><br>\n|.
564
qq|<a href=# title="number of active sessions in the past 1, 5, 15 minutes">Sessions&nbsp; :&nbsp; |.
565
qq|$sessioncount[0],&nbsp; $sessioncount[1],&nbsp; $sessioncount[2]</a>\n|;
566
}
567
568
# display copyright. Don't touch it, please.
569
httpprint(\@header,
570
[qq|<html>\n|.
571
qq|<head><title>Copyright</title></head>\n|.
572
qq|<body bgcolor="#ffffff" background="$prefs{'bgurl'}">\n|.
573
qq|<style type="text/css"><!--\n|.
574
qq|body {\n|.
575
qq|background-image: url($prefs{'bgurl'});\n|.
576
qq|background-repeat: $repeatstr;\n|.
577
qq|font-family: Arial,Helvetica,sans-serif; font-size: 10pt; font-color: #cccccc\n|.
578
qq|}\n|.
579
qq|A:link { color: #cccccc; text-decoration: none }\n|.
580
qq|A:visited { color: #cccccc; text-decoration: none }\n|.
581
qq|A:hover { color: #333333; text-decoration: none }\n|.
582
qq|--></style>\n|.
583
qq|<center><br><br><br>\n|.
584
qq|<a href="$refreshurl" title="click to next page" style="text-decoration: none">|.
585
qq|<font color="#333333"> &nbsp; $lang_text{'loading'} ...</font></a>\n|.
586
qq|<br><br><br>\n\n|.
587
qq|<a href="http://openwebmail.org/" title="click to home of $config{'name'}" target="_blank" style="text-decoration: none">\n|.
588
qq|$softwarestr<br><br>\n|.
589
qq|Copyright (C) 2001-2004<br>\n|.
590
qq|Chung-Kie Tung, Nai-Jung Kuo, Chao-Chiu Wang, Emir Litric,<br>|.
591
qq|Thomas Chung, Dattola Filippo, Bernd Bass, Scott Mazur<br><br>\n|.
592
qq|Copyright (C) 2000<br>\n|.
593
qq|Ernie Miller (original GPL project: Neomail)<br><br>\n|.
594
qq|</a>\n\n|.
595
qq|<a href="$config{'ow_htmlurl'}/doc/copyright.txt" title="click to see GPL version 2 licence" target="_blank" style="text-decoration: none">\n|.
596
qq|This program is free software; you can redistribute it and/or modify<br>\n|.
597
qq|it under the terms of the version 2 of GNU General Public License<br>\n|.
598
qq|as published by the Free Software Foundation<br><br>\n|.
599
qq|This program is distributed in the hope that it will be useful,<br>\n|.
600
qq|but WITHOUT ANY WARRANTY; without even the implied warranty of<br>\n|.
601
qq|MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.<br>\n|.
602
qq|See the GNU General Public License for more details.<br><br>\n|.
603
qq|Removal or change of this copyright is prohibited.\n|.
604
qq|</a>\n|.
605
qq|$countstr$js\n|.
606
qq|</center></body></html>\n|] );
607
608
} else { # Password is INCORRECT
609
writelog("login error - $config{'auth_module'}, ret $errorcode, $errormsg");
610
umask(0077);
611
if ( $>==0 ) { # switch to uuid:mailgid if script is setuid root.
612
my $mailgid=getgrnam('mail');
613
ow::suid::set_euid_egids($uuid, $mailgid, split(/\s+/,$ugid));
614
}
615
my $historyfile=ow::tool::untaint(dotpath('history.log'));
616
if (-f $historyfile ) {
617
writehistory("login error - $config{'auth_module'}, ret $errorcode, $errormsg");
618
}
619
620
my $html = applystyle(readtemplate("loginfailed.template"));
621
622
my $webmsg;
623
if ($errorcode==-1) {
624
$webmsg=$lang_err{'func_notsupported'};
625
} elsif ($errorcode==-2) {
626
$webmsg=$lang_err{'param_fmterr'};
627
} elsif ($errorcode==-3) {
628
$webmsg=$lang_err{'auth_syserr'};
629
} elsif ($errorcode==-4) {
630
$webmsg=$lang_err{'pwd_incorrect'};
631
} else {
632
$webmsg="Unknow error code $errorcode";
633
}
634
$html =~ s/\@\@\@ERRORMSG\@\@\@/$webmsg/;
635
636
sleep $config{'loginerrordelay'}; # delayed response
637
httpprint([], [htmlheader(), $html, htmlfooter(1)]);
638
}
639
}
640
641
sub ip2hostname {
642
my $ip=$_[0];
643
my $hostname;
644
eval {
645
local $SIG{ALRM} = sub { die "alarm\n" }; # NB: \n required
646
alarm 10; # timeout 10sec
647
$hostname=gethostbyaddr(inet_aton($ip),AF_INET);
648
alarm 0;
649
};
650
return($ip) if ([email protected]); # eval error, it means timeout
651
return($hostname);
652
}
653
########## END LOGIN #############################################
654
655
########## AUTOLOGIN #############################################
656
sub autologin {
657
# auto login with cgi parm or cookie
658
$default_logindomain=param('default_logindomain')||cookie('openwebmail-default_logindomain');
659
$loginname=param('loginname')||cookie('openwebmail-loginname');
660
return loginmenu() if ($loginname eq '');
661
662
($logindomain, $loginuser)=login_name2domainuser($loginname, $default_logindomain);
663
if (!is_localuser("$loginuser\@$logindomain") && -f "$config{'ow_sitesconfdir'}/$logindomain") {
664
read_owconf(\%config, \%config_raw, "$config{'ow_sitesconfdir'}/$logindomain");
665
}
666
ow::auth::load($config{'auth_module'});
667
668
($domain, $user, $userrealname, $uuid, $ugid, $homedir)
669
=get_domain_user_userinfo($logindomain, $loginuser);
670
if ($user eq '' ||
671
($uuid==0 && !matchlist_fromhead('allowed_rootloginip', ow::tool::clientip())) ||
672
cookie("$user-sessionid") eq '') {
673
return loginmenu();
674
}
675
676
my $userconf="$config{'ow_usersconfdir'}/$user";
677
$userconf="$config{'ow_usersconfdir'}/$domain/$user" if ($config{'auth_withdomain'});
678
read_owconf(\%config, \%config_raw, "$userconf") if ( -f "$userconf");
679
680
my $owuserdir = ow::tool::untaint("$config{'ow_usersdir'}/".($config{'auth_withdomain'}?"$domain/$user":$user));
681
$homedir = $owuserdir if ( !$config{'use_syshomedir'} );
682
return loginmenu() if (!autologin_check()); # db won't be created if it doesn't exist as euid has not been switched
683
684
# load user prefs for search_clean_oldsessions, it will check $prefs{sessiontimeout}
685
%prefs = readprefs();
686
$thissession = (search_clean_oldsessions
687
($loginname, $default_logindomain, $uuid, cookie("$user-sessionid")))[0];
688
$thissession =~ s!\.\.+!!g; # remove ..
689
return loginmenu() if ($thissession !~ /^([\w\.\-\%\@]+\*[\w\.\-]*\-session\-0\.\d+)$/);
690
691
# redirect page to openwebmail main/calendar/webdisk
692
my $refreshurl=refreshurl_after_login(param('action'));
693
if ( !$config{'stay_ssl_afterlogin'} && # leave SSL
694
($ENV{'HTTPS'}=~/on/i || $ENV{'SERVER_PORT'}==443) ) {
695
$refreshurl="http://$ENV{'HTTP_HOST'}$refreshurl" if ($refreshurl!~s!^https?://!http://!i);
696
}
697
print redirect(-location=>$refreshurl);
698
}
699
########## END AUTOLOGIN #########################################
700
701
########## REFRESHURL_AFTER_LOGIN ################################
702
sub refreshurl_after_login {
703
my $action=$_[0];
704
my $refreshurl='';
705
706
if ( $action eq 'composemessage' ) {
707
my $to=param('to')||'';
708
$to =~ s!^mailto\:!!; # IE passes mailto: with mailaddr to mail client
709
my $subject=param('subject')||'';
710
$refreshurl="$config{'ow_cgiurl'}/openwebmail-send.pl?sessionid=$thissession&action=composemessage&to=$to&subject=$subject";
711
} elsif ( $action eq 'calyear' || $action eq 'calmonth' ||
712
$action eq 'calweek' || $action eq 'calday' ) {
713
$refreshurl="$config{'ow_cgiurl'}/openwebmail-cal.pl?sessionid=$thissession&action=$action";
714
} elsif ( $action eq 'showdir' ) {
715
$refreshurl="$config{'ow_cgiurl'}/openwebmail-webdisk.pl?sessionid=$thissession&action=$action";
716
} elsif ( $action eq 'editfolders' ) {
717
$refreshurl="$config{'ow_cgiurl'}/openwebmail-folder.pl?sessionid=$thissession&action=$action";
718
} else {
719
if ($config{'enable_webmail'}) {
720
$refreshurl="$config{'ow_cgiurl'}/openwebmail-main.pl?sessionid=$thissession&action=listmessages_afterlogin";
721
} elsif ($config{'enable_calendar'}) {
722
$refreshurl="$config{'ow_cgiurl'}/openwebmail-cal.pl?sessionid=$thissession&action=calmonth";
723
} elsif ($config{'enable_webdisk'}) {
724
$refreshurl="$config{'ow_cgiurl'}/openwebmail-webdisk.pl?sessionid=$thissession&action=showdir";
725
} else {
726
openwebmailerror(__FILE__, __LINE__, "$lang_err{'all_module_disabled'}, $lang_err{'access_denied'}");
727
}
728
}
729
return($refreshurl);
730
}
731
########## END REFRESHURL_AFTER_LOGIN ############################
732
733
########## SEARCH_AND_CLEANOLDSESSIONS ###########################
734
# try to find old session that is still valid for the same user cookie
735
# and delete expired session files
736
sub search_clean_oldsessions {
737
my ($loginname, $default_logindomain, $owner_uid, $oldcookie)=@_;
738
my $oldsessionid="";
739
my @sessioncount=(0,0,0); # active sessions in 1, 5, 15 minutes
740
my @delfiles;
741
742
opendir(SESSIONSDIR, "$config{'ow_sessionsdir'}") or
743
openwebmailerror(__FILE__, __LINE__, "$lang_err{'couldnt_open'} $config{'ow_sessionsdir'}! ($!)");
744
my @sessfiles=readdir(SESSIONSDIR);
745
closedir(SESSIONSDIR);
746
747
my $t=time();
748
my $clientip=ow::tool::clientip();
749
foreach my $sessfile (@sessfiles) {
750
next if ($sessfile !~ /^([\w\.\-\%\@]+)\*([\w\.\-]*)\-session\-(0\.\d+)(-.*)?$/);
751
752
my ($sess_loginname, $sess_default_logindomain, $serial, $misc)=($1, $2, $3, $4); # param from sessfile
753
my $modifyage = $t-(stat("$config{'ow_sessionsdir'}/$sessfile"))[9];
754
755
if ($loginname eq $sess_loginname &&
756
$default_logindomain eq $sess_default_logindomain) {
757
# remove user old session if timeout
758
if ( $modifyage > $prefs{'sessiontimeout'}*60 ) {
759
push(@delfiles, $sessfile);
760
} elsif ($misc eq '') { # this is a session info file
761
my ($cookie, $ip, $userinfo)=sessioninfo($sessfile);
762
if ($oldcookie && $cookie eq $oldcookie && $ip eq $clientip &&
763
(stat("$config{'ow_sessionsdir'}/$sessfile"))[4] == $owner_uid ) {
764
$oldsessionid=$sessfile;
765
} elsif (!$config{'session_multilogin'}) { # remove old session of this user
766
push(@delfiles, $sessfile);
767
}
768
}
769
770
} else { # remove old session of other user if more than 1 day
771
push(@delfiles, $sessfile) if ( $modifyage > 86400 );
772
}
773
774
if ($misc eq '') {
775
$sessioncount[0]++ if ($modifyage <= 60);
776
$sessioncount[1]++ if ($modifyage <= 300);
777
$sessioncount[2]++ if ($modifyage <= 900);
778
}
779
}
780
781
foreach my $sessfile (@delfiles) {
782
writelog("session cleanup - $sessfile");
783
unlink ow::tool::untaint("$config{'ow_sessionsdir'}/$sessfile");
784
}
785
786
return($oldsessionid, @sessioncount);
787
}
788
789
# only changes the usersid/groupid if running as root
790
sub owchown {
791
if ( $>==0 ) {
792
chown(@_);
793
} else {
794
return 1;
795
}
796
}
797
798
########## END SEARCH_AND_CLEANOLDSESSIONS #######################
799