1+ <?php
2+
3+ /*
4+ Copyright (c) 2021, Till Brehm, ISPConfig UG
5+ All rights reserved.
6+
7+ Redistribution and use in source and binary forms, with or without modification,
8+ are permitted provided that the following conditions are met:
9+
10+ * Redistributions of source code must retain the above copyright notice,
11+ this list of conditions and the following disclaimer.
12+ * Redistributions in binary form must reproduce the above copyright notice,
13+ this list of conditions and the following disclaimer in the documentation
14+ and/or other materials provided with the distribution.
15+ * Neither the name of ISPConfig nor the names of its contributors
16+ may be used to endorse or promote products derived from this software without
17+ specific prior written permission.
18+
19+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
20+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22+ IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
23+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
24+ BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
26+ OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
27+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
28+ EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29+ */
30+
31+ require_once '../../lib/config.inc.php ' ;
32+ require_once '../../lib/app.inc.php ' ;
33+
34+ //* Check if we have an active users ession
35+ if ($ _SESSION ['s ' ]['user ' ]['active ' ] == 1 ) {
36+ header ('Location: /index.php ' );
37+ die ();
38+ }
39+
40+ //* If we don't have a 2fa session go back to login page
41+ if (!isset ($ _SESSION ['otp ' ])) {
42+ header ('Location: index.php ' );
43+ die ();
44+ }
45+
46+ //* Variables and settings
47+ $ error = '' ;
48+ $ msg = '' ;
49+ $ max_session_code_retry = 3 ;
50+ $ max_global_code_retry = 10 ;
51+
52+
53+ //* CSRF Check if we got POST data
54+ if (count ($ _POST ) >= 1 ) {
55+ $ app ->auth ->csrf_token_check ();
56+ }
57+
58+ //* Handle recovery code
59+ if (isset ($ _POST ['code ' ]) && strlen ($ _POST ['code ' ]) == 32 && $ _SESSION ['otp ' ]['recovery ' ])) {
60+ //* TODO Recovery code handling
61+
62+ $ user = $ app ->db ->queryOneRecord ('SELECT otp_attempts FROM sys_user WHERE userid = ? ' ,$ _SESSION ['s_pending ' ]['user ' ]['userid ' ]);
63+
64+ //* We allow one more try to enter recovery code
65+ if ($ user ['otp_attempts ' ] > $ max_global_code_retry + 1 ) {
66+
67+ }
68+
69+
70+ die ('Handle recovery code ' );
71+ }
72+
73+
74+ //* Begin 2fa via Email
75+ if ($ _SESSION ['otp ' ]['type ' ] == 'email ' ) {
76+
77+ //* Email 2fa handler settings
78+ $ max_code_resend = 3 ;
79+ $ max_time = 600 ; // time in seconds until the code gets invalidated
80+ $ code_length = 6 ;
81+
82+ if (isset ($ _POST ['code ' ]) && strlen ($ _POST ['code ' ]) == $ code_length && isset ($ _SESSION ['otp ' ]['code ' ])) {
83+
84+ if (strlen ($ _SESSION ['otp ' ]['code ' ]) != $ code_length ) die (); // wrong code lenght, this should never happen
85+
86+ $ user = $ app ->db ->queryOneRecord ('SELECT otp_attempts FROM sys_user WHERE userid = ? ' ,$ _SESSION ['s_pending ' ]['user ' ]['userid ' ]);
87+
88+ //* Check if we reached limits
89+ if ($ _SESSION ['otp ' ]['sent ' ] > $ max_code_resend
90+ || $ _SESSION ['otp ' ]['session_attempts ' ] > $ max_session_code_retry
91+ || $ user ['otp_attempts ' ] > $ max_global_code_retry
92+ || time () > $ _SESSION ['otp ' ]['starttime ' ] + $ max_time ) {
93+ unset($ _SESSION ['otp ' ]);
94+ unset($ _SESSION ['s_pending ' ]);
95+ $ app ->error ('2FA failed ' ,'index.php ' );
96+ }
97+
98+ //* 2fa success
99+ if ($ _POST ['code ' ] == $ _SESSION ['otp ' ]['code ' ]) {
100+ $ _SESSION ['s ' ] = $ _SESSION ['s_pending ' ];
101+ unset($ _SESSION ['s_pending ' ]);
102+ unset($ _SESSION ['otp ' ]);
103+ header ('Location: ../index.php ' );
104+ die ();
105+ } else {
106+ //* 2fa wrong code
107+ $ _SESSION ['otp ' ]['session_attempts ' ]++;
108+ $ app ->db ->query ()
109+ }
110+ }
111+
112+ //* set code
113+ if (!isset ($ _SESSION ['otp ' ]['code ' ]) || empty ($ _SESSION ['otp ' ]['code ' ])) {
114+ // TODO Code generator
115+ $ _SESSION ['otp ' ]['code ' ] = 123456 ;
116+ $ _SESSION ['otp ' ]['starttime ' ] = time ();
117+ }
118+
119+ //* Send code via email
120+ if (!isset ($ _SESSION ['otp ' ]['sent ' ]) || $ _GET ['action ' ] == 'resend ' ) {
121+
122+ //* Ensure that code is not sent too often
123+ if (isset ($ _SESSION ['otp ' ]['sent ' ]) && $ _SESSION ['otp ' ]['sent ' ] > $ max_code_resend ) {
124+ $ app ->error ('Code resend limit reached ' ,'index.php ' );
125+ }
126+
127+ $ app ->uses ('functions ' );
128+
129+ //* send email
130+ $ email_to = $ _SESSION ['otp ' ]['data ' ];
131+ $ subject = 'ISPConfig Login authentication ' ;
132+ $ text = '' ;
133+ $ from = 'root@localhost ' ;
134+
135+ $ app ->functions ->mail ($ email_to , $ subject , $ text , $ from );
136+
137+ //* increase sent counter
138+ if (!isset ($ _SESSION ['otp ' ]['sent ' ])) {
139+ $ _SESSION ['otp ' ]['sent ' ] = 1 ;
140+ } else {
141+ $ _SESSION ['otp ' ]['sent ' ]++;
142+ }
143+
144+ }
145+
146+ //* Show form to enter email code
147+
148+
149+
150+ } else {
151+ //* unsupported 2fa type
152+ $ app ->error ('Code resend limit reached ' ,'index.php ' );
153+ }
154+
155+
156+
157+
158+
159+ //* Load templating system and lang file
160+ $ app ->uses ('tpl ' );
161+ $ app ->tpl ->newTemplate ('main_login.tpl.htm ' );
162+ $ app ->tpl ->setInclude ('content_tpl ' , 'templates/otp.htm ' );
163+
164+
165+ //* SET csrf token
166+ $ csrf_token = $ app ->auth ->csrf_token_get ('language_edit ' );
167+ $ app ->tpl ->setVar ('_csrf_id ' ,$ csrf_token ['csrf_id ' ]);
168+ $ app ->tpl ->setVar ('_csrf_key ' ,$ csrf_token ['csrf_key ' ]);
169+
170+
171+ $ app ->load_language_file ('web/login/lib/lang/ ' .$ conf ["language " ].'.lng ' );
172+
173+
174+
175+
176+
177+ $ app ->tpl_defaults ();
178+ $ app ->tpl ->pparse ();
179+
180+
181+ ?>
0 commit comments