1###############################################################################
2# LogInOut.pm                                                                 #
3# $Date: 12.02.14 $                                                           #
4###############################################################################
5# YaBB: Yet another Bulletin Board                                            #
6# Open-Source Community Software for Webmasters                               #
7# Version:        YaBB 2.6.11                                                 #
8# Packaged:       December 2, 2014                                            #
9# Distributed by: http://www.yabbforum.com                                    #
10# =========================================================================== #
11# Copyright (c) 2000-2014 YaBB (www.yabbforum.com) - All Rights Reserved.     #
12# Software by:  The YaBB Development Team                                     #
13#               with assistance from the YaBB community.                      #
14###############################################################################
15use CGI::Carp qw(fatalsToBrowser);
16our $VERSION = '2.6.11';
17
18$loginoutpmver = 'YaBB 2.6.11 $Revision: 1611 $';
19if ( $action eq 'detailedversion' ) { return 1; }
20
21if ($regcheck) { require Sources::Decoder; }
22LoadLanguage('LogInOut');
23
24$regstyle = q{};
25
26sub Login {
27    if ( !$iamguest && $sessionvalid == 1 ) {
28        fatal_error( 'logged_in_already', $username );
29    }
30    $sharedLogin_title = $loginout_txt{'34'};
31    $yymain .= sharedLogin() . q~<script type="text/javascript">
32    document.loginform.username.focus();
33</script>~;
34    $yytitle = $loginout_txt{'34'};
35    template();
36    return;
37}
38
39sub Login2 {
40    if ( !$iamguest && $sessionvalid == 1 ) {
41        fatal_error( 'logged_in_already', $username );
42    }
43    if ( $FORM{'username'} eq q{} ) { fatal_error('no_username'); }
44    if ( $FORM{'passwrd'}  eq q{} ) { fatal_error('no_password'); }
45    $username = $FORM{'username'};
46    $username =~ s/\s/_/gxsm;
47    if ( $username =~ /[^ \w\x80-\xFF\[\]\(\)#\%\+,\-\|\.:=\?\@\^]/sm ) {
48        $error_txt = isempty($loginout_txt{'35a'}, "$loginout_txt{'35'} $loginout_txt{'241'}");
49        fatal_error( 'invalid_character',
50            "$error_txt" );
51    }
52
53    ## Check if login ID is not an email address ##
54    if ( !-e "$memberdir/$username.vars" ) {
55        $test_id = MemberIndex( 'who_is', "$FORM{'username'}" );
56        if ( $test_id ) { $username = $test_id; }
57    }
58
59    if ( -e "$memberdir/$username.pre" && ( $regtype == 1 || $regtype == 2 ) ) {
60        fatal_error('not_activated');
61    }
62    elsif ( -e "$memberdir/$username.wait" && $regtype == 1 ) {
63        fatal_error('prereg_wait');
64    }
65    elsif ( !-e "$memberdir/$username.vars" ) { fatal_error('bad_credentials'); }
66
67    if ( -e "$memberdir/$username.pre" && -e "$memberdir/$username.vars" ) {
68        unlink "$memberdir/$username.pre";
69    }
70
71    # Need to do this to get correct case of user ID,
72    # for case insensitive systems. Can cause weird issues otherwise
73    $caseright = 0;
74    ManageMemberlist('load');
75    while ( ( $curmemb, $value ) = each %memberlist ) {
76        if ( $username eq $curmemb ) { $caseright = 1; last; }
77    }
78    undef %memberlist;
79
80    if ( !$caseright ) {
81        $username = 'Guest';
82        fatal_error('bad_credentials');
83    }
84
85    if ( -e "$memberdir/$username.vars" ) {
86        LoadUser($username);
87        my $spass     = ${ $uid . $username }{'password'};
88        my $cryptpass = encode_password("$FORM{'passwrd'}");
89
90        # convert non encrypted password to MD5 encrypted one
91        if ( $spass eq $FORM{'passwrd'} && $spass ne $cryptpass ) {
92
93            # only encrypt the password if it's not already MD5 encrypted
94            # MD5 hashes in YaBB are always 22 chars long (base64)
95            if ( length( ${ $uid . $username }{'password'} ) != 22 ) {
96                ${ $uid . $username }{'password'} = $cryptpass;
97                UserAccount($username);
98                $spass = $cryptpass;
99            }
100        }
101        if ( $spass ne $cryptpass ) {
102            $username = 'Guest';
103            fatal_error('bad_credentials');
104        }
105    }
106    else {
107        $username = 'Guest';
108        fatal_error('bad_credentials');
109    }
110
111    $iamadmin = ${ $uid . $username }{'position'} eq 'Administrator'    ? 1 : 0;
112    $iamgmod  = ${ $uid . $username }{'position'} eq 'Global Moderator' ? 1 : 0;
113    $sessionvalid = 1;
114    $iamguest     = 0;
115
116    if ( $maintenance && !$iamadmin ) {
117        $username = 'Guest';
118        fatal_error('admin_login_only');
119    }
120    banning();
121
122    if ( $FORM{'cookielength'} == 1 ) {
123        $ck{'len'} = 'Sunday, 17-Jan-2038 00:00:00 GMT';
124    }
125    else { $ck{'len'} = q{}; }
126
127    ${ $uid . $username }{'session'} = encode_password($user_ip);
128    UpdateCookie(
129        'write', $username,
130        encode_password( $FORM{'passwrd'} ),
131        ${ $uid . $username }{'session'},
132        q{/}, $ck{'len'}
133    );
134
135    UserAccount( $username, 'update', q{-} );
136
137    # "-" to not update 'lastonline' here
138    buildIMS( $username, 'load' );    # isn't loaded because was Guest before
139    buildIMS( $username, q{} );
140
141    # rebuild the Members/$username.ims file on login
142    WriteLog();
143
144    if ( $FORM{'sredir'} ) {
145        $FORM{'sredir'} =~ s/\~/\=/gxsm;
146        $FORM{'sredir'} =~ s/x3B/;/gsm;
147        $FORM{'sredir'} =~ s/search2/search/gsm;
148        $FORM{'sredir'} = qq~?$FORM{'sredir'}~;
149        if ( $FORM{'sredir'} =~
150            /action=(register|login2|reminder|reminder2)/xsm )
151        {
152            $FORM{'sredir'} = q{};
153        }
154    }
155    $yySetLocation = qq~$scripturl$FORM{'sredir'}~;
156    redirectexit();
157    return;
158}
159
160sub Logout {
161    if ( $username ne 'Guest' ) {
162        RemoveUserOnline($username);    # Remove user from online log
163        UserAccount( $username, 'update', 'lastonline' );
164    }
165
166    UpdateCookie('delete');
167    $yySetLocation = $guestaccess ? $scripturl : qq~$scripturl?action=login~;
168    $username = 'Guest';
169    redirectexit();
170    return;
171}
172
173sub sharedLogin {
174    get_template('Loginout');
175    if ( $action eq 'login' || $maintenance ) {
176        $yynavigation = qq~&rsaquo; $loginout_txt{'34'}~;
177    }
178
179    #cookie length is now all or nothing.
180    if ( $sharedLogin_title ne q{} ) {
181        $sharedlog = $mysharedloga;
182        $sharedlog =~ s/{yabb sharedLogin_title}/$sharedLogin_title/sm;
183        if ( $sharedLogin_text ne q{} ) {
184            $sharedlog .= $mysharedlogb;
185            $sharedlog =~ s/{yabb sharedLogin_text}/$sharedLogin_text/sm;
186        }
187        $sharedlog .= $mysharedlogc;
188        $sharedbot = $myborder_bottom;
189    }
190    else {
191        $sharedlog = $mysharedlog_top;
192        $sharedbot = $mysharedbot;
193    }
194    if ($maintenance) { $hide_passlink = ' style="visibility: hidden;"' }
195    if ( $maintenance || !$regtype ) {
196        $hide_reglink = ' style="visibility: hidden;"';;
197    }
198    $sharedlog .= qq~
199            <form id="loginform" name="loginform" action="$scripturl?action=login2" method="post" accept-charset="$yymycharset">
200                <input type="hidden" name="sredir" value="$INFO{'sesredir'}" />
201    $mysharedlog_bodya
202    $sharedbot~;
203    $sharedlog =~ s/{yabb regstyle}/$regstyle/sm;
204    $sharedlog =~ s/{yabb hide_reglink}/$hide_reglink/gsm;
205    $sharedlog =~ s/{yabb hide_passlink}/$hide_passlink/gsm;
206    my $cookielength_sel = q{};
207    if ( $Cookie_Length  ) { $cookielength_sel = ' checked="checked"'}
208    $sharedlog =~ s/{yabb cookielength_sel}/$cookielength_sel/gsm;
209    $loginform         = 1;
210    $sharedLogin_title = q{};
211    $sharedLogin_text  = q{};
212    return $sharedlog;
213}
214
215sub Reminder {
216    if ( !$iamguest && $sessionvalid == 1 ) {
217        fatal_error( 'logged_in_already', $username );
218    }
219    get_template('Loginout');
220
221    $yymain .= qq~<br /><br />
222<form action="$scripturl?action=reminder2" method="post" name="reminder" onsubmit="return CheckReminderField();" accept-charset="$yymycharset">
223$myremindera~;
224    $yymain =~ s/{yabb mbname}/$mbname/sm;
225    $yymain =~ s/{yabb regstyle}/$regstyle/sm;
226
227    if ($regcheck) {
228        validation_code();
229        $yymain .= $myreminder_regcheck;
230        $yymain =~ s/{yabb flood_text}/$flood_text/sm;
231        $yymain =~ s/{yabb showcheck}/$showcheck/sm;
232    }
233    if ( $spam_questions_send && -e "$langdir/$language/spam.questions" ) {
234        SpamQuestion();
235        my $verification_question_desc;
236        if ($spam_questions_case) {
237            $verification_question_desc =
238              qq~<br />$loginout_txt{'verification_question_case'}~;
239        }
240        $yymain .= $myreminder_vericheck;
241        $yymain =~ s/{yabb spam_question}/$spam_question/sm;
242        $yymain =~ s/{yabb spam_question_id}/$spam_question_id/sm;
243        $yymain =~ s/{yabb spam_question_image}/$spam_image/sm;
244        $yymain =~
245          s/{yabb verification_question_desc}/$verification_question_desc/sm;
246    }
247
248    $yymain .= $myreminder_endform;
249    $yymain .= qq~
250<script type="text/javascript">
251    document.reminder.user.focus();
252
253    function CheckReminderField() {
254        if (document.reminder.user.value == '') {
255            alert("$loginout_txt{'error_user_info'}");
256            document.reminder.user.focus();
257            return false;
258        }~ .
259
260      (
261        $regcheck
262        ? qq~
263        if (document.reminder.verification.value == '') {
264            alert("$loginout_txt{'error_verification'}");
265            document.reminder.verification.focus();
266            return false;
267        }~
268        : q{}
269      )
270      .
271
272      (
273        $spam_questions_send && -e "$langdir/$language/spam.questions"
274        ? qq~
275        if (document.reminder.verification_question.value == '') {
276            alert("$loginout_txt{'error_verification_question'}");
277            document.reminder.verification_question.focus();
278            return false;
279        }~
280        : q{}
281      )
282
283      . q~
284        return true;
285    }
286</script>
287<br /><br />
288~;
289
290    $yytitle      = $loginout_txt{'669'};
291    $yynavigation = qq~&rsaquo; $loginout_txt{'669'}~;
292    template();
293    return;
294}
295
296sub Reminder2 {
297    if ( !$FORM{'user'} ) {
298        fatal_error( q{}, "$loginout_txt{'error_user_info'}" );
299    }
300
301    if ( !$iamguest && $sessionvalid == 1 && !$iamadmin ) {
302        fatal_error( 'logged_in_already', $username );
303    }
304
305    # generate random ID for password reset.
306    my $randid = keygen( 8, 'A' );
307
308    if ( $regcheck && !$iamadmin ) {
309        validation_check( $FORM{'verification'} );
310    }
311    if ( $spam_questions_send && -e "$langdir/$language/spam.questions" ) {
312        SpamQuestionCheck( $FORM{'verification_question'},
313            $FORM{'verification_question_id'} );
314    }
315
316    my $user = $FORM{'user'};
317    $user =~ s/\s/_/gxsm;
318
319    if ( !-e "$memberdir/$user.vars" ) {
320        $test_id = MemberIndex( 'who_is', $FORM{'user'} );
321        if ($test_id) { $user = $test_id; }
322        else { fatal_error( q{}, "$loginout_txt{'no_user_info_exists'}" ); }
323    }
324
325    # Fix to make it load in their own language
326    LoadUser($user);
327    if ( !${ $uid . $user }{'email'} ) { fatal_error('corrupt_member_file'); }
328
329    $username = $user;
330    WhatLanguage();
331    LoadLanguage('LogInOut');
332    LoadLanguage('Email');
333    undef $username;
334
335    $userfound = 0;
336
337    if ( -e "$memberdir/forgotten.passes" ) {
338        require "$memberdir/forgotten.passes";
339    }
340    if ( exists $pass{$user} ) { delete $pass{$user}; }
341    $pass{"$user"} = $randid;
342
343    fopen( FILE, ">$memberdir/forgotten.passes" )
344      or fatal_error( 'cannot_open', "$memberdir/forgotten.passes", 1 );
345    while ( ( $key, $value ) = each %pass ) {
346        print {FILE} qq~\$pass{'$key'} = '$value';\n~
347          or croak "$croak{'print'} forgotten.passes";
348    }
349    print {FILE} '1;' or croak "$croak{'print'} forgotten.passes";
350    fclose(FILE);
351
352    $subject = "$mbname $loginout_txt{'36b'}: ${$uid.$user}{'realname'}";
353    if   ($do_scramble_id) { $cryptusername = cloak($user); }
354    else                   { $cryptusername = $user; }
355    require Sources::Mailer;
356    LoadLanguage('Email');
357    my $message = template_email(
358        $passwordreminderemail,
359        {
360            'displayname'   => ${ $uid . $user }{'realname'},
361            'cryptusername' => $cryptusername,
362            'remindercode'  => $randid
363        }
364    );
365    sendmail( ${ $uid . $user }{'email'}, $subject, $message );
366    get_template('Loginout');
367
368    $yymain .= $myreminder2;
369    $yymain =~ s/{yabb mbname}/$mbname/sm;
370    $yymain =~ s/{yabb forum_user}/$FORM{'user'}/sm;
371
372    $yytitle = "$loginout_txt{'669'}";
373    template();
374    return;
375}
376
377sub Reminder3 {
378    $id = $INFO{'ID'};
379    if   ($do_scramble_id) { $user = decloak( $INFO{'user'} ); }
380    else                   { $user = $INFO{'user'}; }
381
382    if ( $id !~ /[a-zA-Z0-9]+/xsm ) {
383        fatal_error( 'invalid_character', "ID $loginout_txt{'241'}" );
384    }
385    if ( $user =~ /[^\w#\%\+\-\.\@\^]/xsm ) {
386        fatal_error( 'invalid_character', "User $loginout_txt{'241'}" );
387    }
388
389    # generate a new random password as the old one is one-way encrypted.
390    @chararray =
391      qw(0 1 2 3 4 5 6 7 8 9 a b c d e f g h i j k l m n o p q r s t u v w x y z A B C D E F G H I J K L M N O P Q R S T U V W X Y Z);
392    my $newpassword;
393    for my $i ( 0 .. 7 ) {
394        $newpassword .= $chararray[ int rand 61 ];
395    }
396
397    # load old userdata
398    LoadUser($user);
399
400    # update forgotten passwords database
401    require "$memberdir/forgotten.passes";
402    if ( $pass{$user} ne $id ) { fatal_error('wrong_id'); }
403    delete $pass{$user};
404    fopen( FORGOTTEN, ">$memberdir/forgotten.passes" )
405      or fatal_error( 'cannot_open', "$memberdir/forgotten.passes", 1 );
406    while ( ( $key, $value ) = each %pass ) {
407        print {FORGOTTEN} qq~\$pass{'$key'} = '$value';\n~
408          or croak "$croak{'print'} FORGOTTEN";
409    }
410    print {FORGOTTEN} "\n1;" or croak "$croak{'print'} FORGOTTEN";
411    fclose(FORGOTTEN);
412
413    # add newly generated password to user data
414    ${ $uid . $user }{'password'} = encode_password($newpassword);
415    UserAccount( $user, 'update' );
416
417    $FORM{'username'}     = $user;
418    $FORM{'passwrd'}      = $newpassword;
419    $FORM{'cookielength'} = 10;
420    $FORM{'sredir'} =
421qq*action~profileCheck2;redir~myprofile;username~$INFO{'user'};passwrd~$newpassword;newpassword~1*;
422    Login2();
423    return;
424}
425
426sub InMaintenance {
427    if ( $maintenancetext ne q{} ) { $maintxt{'157'} = $maintenancetext; }
428    $sharedLogin_title = "$maintxt{'114'}";
429    $sharedLogin_text  = "<b>$maintxt{'156'}</b><br />$maintxt{'157'}";
430    $yymain .= sharedLogin();
431    $yytitle = "$maintxt{'155'}";
432    template();
433    return;
434}
435
4361;
437