1<?php
2/*
3 * e107 website system
4 *
5 * Copyright (C) 2008-2016 e107 Inc (e107.org)
6 * Released under the terms and conditions of the
7 * GNU General Public License (http://www.gnu.org/licenses/gpl.txt)
8 *
9 * Administration Area Authorization
10 *
11 * $Source: /cvs_backup/e107_0.8/e107_admin/auth.php,v $
12 * $Revision$
13 * $Date$
14 * $Author$
15 */
16
17if (!defined('e107_INIT'))
18{
19	exit;
20}
21
22
23e107::getDebug()->logTime('(Start auth.php)');
24
25define('e_CAPTCHA_FONTCOLOR','#F9A533');
26
27
28
29
30// Required for a clean v1.x -> v2 upgrade.
31$core = e107::getConfig('core');
32
33if($core->get('admintheme') != 'bootstrap3')
34{
35	$core->update('admintheme','bootstrap3');
36	$core->update('adminstyle','infopanel');
37	$core->update('admincss','admin_dark.css');
38	$core->set('e_jslib_core',array('prototype' => 'none', 'jquery'=> 'auto'));
39	$core->save();
40	e107::getRedirect()->redirect(e_SELF);
41}
42
43$admincss = trim($core->get('admincss'));
44if(empty($admincss) || $admincss === 'style.css'|| $admincss === 'admin_dark.css' || $admincss === 'admin_light.css')
45{
46	$core->update('admincss','css/bootstrap-dark.min.css');
47	$core->save(false,true);
48	e107::getRedirect()->redirect(e_SELF);
49}
50
51// Check Admin-Perms for current language and redirect if necessary.
52if(USER && !getperms('0') && vartrue($pref['multilanguage']) && !getperms(e_LANGUAGE) && empty($_E107['no_language_perm_check']))
53{
54	$lng = e107::getLanguage();
55
56	$tmp = explode(".",ADMINPERMS);
57	foreach($tmp as $ln)
58	{
59		if(strlen($ln) < 3) // not a language perm.
60		{
61			continue;
62		}
63
64		if($lng->isValid($ln))
65		{
66			$redirect = deftrue("MULTILANG_SUBDOMAIN") ? $lng->subdomainUrl($ln) : e_SELF."?elan=".$ln;
67			//		echo "redirect to: ".$redirect;
68			e107::getRedirect()->go($redirect);
69		//	break;
70		}
71	}
72}
73
74
75/* done in class2
76 @include_once(e_LANGUAGEDIR.e_LANGUAGE."/admin/lan_admin.php");
77 @include_once(e_LANGUAGEDIR."English/admin/lan_admin.php");
78 */
79if (ADMIN)
80{
81	define('ADMIN_PAGE', true);
82	//don't include it if it'a an AJAX call or not wanted
83	if (!e_AJAX_REQUEST && !defset('e_NOHEADER'))
84	{
85		// XXX LOGIN AS Temporary solution, we need something smarter, e.g. reserved message stack 'admin' which will be always printed
86		// inside admin area
87		if(e107::getUser()->getSessionDataAs())
88		{
89			$asuser = e107::getSystemUser(e107::getUser()->getSessionDataAs(), false);
90
91			$lanVars = array ('x' => ($asuser->getId() ? $asuser->getName().' ('.$asuser->getValue('email').')' : 'unknown')) ;
92			e107::getMessage()->addInfo($tp->lanVars(ADLAN_164, $lanVars).' <a href="'.e_ADMIN_ABS.'users.php?mode=main&amp;action=logoutas">['.LAN_LOGOUT.']</a>');
93
94		}
95		// NEW, legacy 3rd party code fix, header called inside the footer o.O
96		if(deftrue('e_ADMIN_UI'))
97		{
98			// boot.php already loaded
99			require_once (e_ADMIN."header.php");
100		}
101		else
102		{
103			// boot.php is included in admin dispatcher constructor, so do it only for legacy code
104			require_once(e_ADMIN.'boot.php');
105		}
106	}
107
108	/*
109	 * FIXME - missing $style for tablerender
110	 * The Solution: parse_admin() without sending it to the browser if it's an ajax call
111	 * The Problem: doubled render time for the ajax called page!!!
112	 */
113}
114else
115{
116	//login via AJAX call is not allowed
117	if (e_AJAX_REQUEST)
118	{
119		require_once (e_HANDLER.'js_helper.php');
120		e_jshelper::sendAjaxError(403, ADLAN_86, ADLAN_87, true);
121	}
122
123	require_once(e_ADMIN.'boot.php');
124
125	$sec_img = e107::getSecureImg();
126
127	$use_imagecode = (vartrue($pref['admincode']) && extension_loaded("gd"));
128
129	if ($_POST['authsubmit'])
130	{
131		$obj = new auth;
132
133		if ($use_imagecode)
134		{
135			if ($sec_img->invalidCode($_POST['rand_num'], $_POST['code_verify']))
136			{
137				e107::getRedirect()->redirect('admin.php?failed');
138				exit;
139			//	echo "<script type='text/javascript'>document.location.href='../index.php'</script>\n";
140			//	header("location: ../index.php");
141			//	exit;
142			}
143		}
144
145	//	require_once (e_HANDLER.'user_handler.php');
146		/** @var array $row */
147		$row = $authresult = $obj->authcheck($_POST['authname'], $_POST['authpass'], varset($_POST['hashchallenge'], ''));
148
149		if ($row[0] == "authfail")
150		{
151			$admin_log->e_log_event(4, __FILE__."|".__FUNCTION__."@".__LINE__, "LOGIN", LAN_ROLL_LOG_11, "U: ".$tp->toDB($_POST['authname']), FALSE, LOG_TO_ROLLING);
152			echo "<script type='text/javascript'>document.location.href='../index.php'</script>\n";
153
154			e107::getRedirect()->redirect('admin.php?failed');
155			exit;
156		}
157		else
158		{
159
160			$reHashedPass = e107::getUserSession()->rehashPassword($row,$_POST['authpass']);
161			if($reHashedPass !==false)
162			{
163				e107::getLog()->add('ADMINPW_02', '', E_LOG_INFORMATIVE, '', LOG_TO_ADMIN, $row);
164				$row['user_password'] = $reHashedPass;
165			}
166
167			$cookieval = $row['user_id'].".".md5($row['user_password']);
168
169			//	  $sql->db_Select("user", "*", "user_name='".$tp -> toDB($_POST['authname'])."'");
170			//	  list($user_id, $user_name, $userpass) = $sql->db_Fetch();
171
172			// Calculate class membership - needed for a couple of things
173			// Problem is that USERCLASS_LIST just contains 'guest' and 'everyone' at this point
174			$class_list = explode(',', $row['user_class']);
175			if ($row['user_admin'] && strlen($row['user_perms']))
176			{
177				$class_list[] = e_UC_ADMIN;
178				if (strpos($row['user_perms'], '0') === 0)
179				{
180					$class_list[] = e_UC_MAINADMIN;
181				}
182			}
183			$class_list[] = e_UC_MEMBER;
184			$class_list[] = e_UC_PUBLIC;
185
186
187			if (in_array(varset($pref['user_audit_class'], ''), $class_list))
188			{
189				e107::getAdminLog()->user_audit(USER_AUDIT_LOGIN, 'Login via admin page', $row['user_id'], $row['user_name']);
190			}
191
192			$edata_li = array("user_id"=>$row['user_id'], "user_name"=>$row['user_name'], 'class_list'=>implode(',', $class_list), 'user_admin'=> $row['user_admin']);
193
194			// Fix - set cookie before login trigger
195			$sessionLife = (int) e107::getPref('session_lifetime', ( 3600 * 24 * 30)); // default 1 month.
196
197			if($sessionLife > 0)
198			{
199				$sessionLife = time() + $sessionLife;
200			}
201
202			session_set(e_COOKIE, $cookieval, $sessionLife);
203
204			unset($sessionLife,$cookieval);
205
206			// ---
207
208			e107::getEvent()->trigger("login", $edata_li);
209
210
211
212			e107::getRedirect()->redirect(e_ADMIN_ABS.'admin.php');
213			//echo "<script type='text/javascript'>document.location.href='admin.php'</script>\n";
214		}
215	}
216
217	$e_sub_cat = 'logout';
218	if (ADMIN == FALSE)
219	{
220		define("e_IFRAME",TRUE);
221	}
222	if (!defset('NO_HEADER'))
223		require_once (e_ADMIN."header.php");
224
225	if (ADMIN == FALSE)
226	{
227		// Needs help from Deso, Vesko and Stoev! :-)
228
229		e107::css('inline',"
230
231			body 				{ 	text-align: left; font-size:15px; line-height:1.5em; font-weight:normal;
232									font-family:Arial, Helvetica, sans-serif; background-attachment: scroll;
233									/* background-color: rgb(47, 47, 47); color: rgb(198, 198, 198); */
234
235									background-repeat: no-repeat; background-size: auto auto
236								}
237			a					{ 	color:#F6931E; text-decoration:none; }
238			a:hover				{ 	color:silver; text-decoration:none; }
239			.bold				{ 	font-weight:bold; }
240			.field				{ 	text-align:center;padding:5px }
241			.field input		{	padding:5px;
242
243								}
244
245			.field input:focus	{
246
247								}
248
249			.field input:hover	{
250
251								}
252			#logo				{
253									height:140px;
254									max-width:310px;
255									padding-right:5px;
256									margin-left:auto;
257									margin-right:auto;
258									margin-top:2%;
259									width:95%;
260
261								}
262
263			#login-admin 		{
264									margin-left:auto;
265									margin-right:auto;
266									margin-top:2%;
267									min-width:250px;
268									width:30%;
269									padding: 0px;
270									max-width:100%;
271
272									/*
273
274									*/
275								}
276
277			#login-admin div.panel { padding: 0 }
278
279			#login-admin label 	{ 	display: none; text-align: right	}
280
281
282			.admin-submit 		{ 	text-align: center; 	padding-top:20px;	}
283
284			.submit				{  }
285
286
287
288			.placeholder 		{ color: #646667; font-style:italic	}
289
290			::-webkit-input-placeholder { font-style:italic;	color: #bbb; 	}
291
292			:-moz-placeholder 	{ font-style:italic;	color: #bbb; 		}
293
294			h2					{ text-align: center; color: #FAAD3D;  }
295
296			#username			{background: url(".e_IMAGE."admin_images/admins_16.png) no-repeat scroll 7px 9px; padding:7px; padding-left:30px; width:80%; max-width:218px; }
297
298			#userpass			{background: url(".e_IMAGE."admin_images/lock_16.png) no-repeat scroll 7px 9px; padding:7px;padding-left:30px; width:80%; max-width:218px; }
299
300			#code-verify		{ width: 220px; padding: 7px; margin-left: auto; margin-right: auto; }
301
302			input[disabled] 	{ color: silver;	}
303			button[disabled] span	{	color: silver;	}
304			.title_clean		{ display:none; }
305
306		");
307
308
309		$obj = new auth;
310		$obj->authform();
311		if (!defset('NO_HEADER'))
312			require_once (e_ADMIN."footer.php");
313		exit;
314	}
315}
316
317//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------//
318class auth
319{
320
321	/**
322	 * Admin auth login
323	 * @return null
324	 */
325	public function authform()  // NOTE: this should NOT be a template of the admin-template, however themes may style it using css.
326	{
327		global $use_imagecode,$sec_img;
328
329		$pref = e107::getPref();
330		$frm = e107::getForm();
331
332		$incChap = (vartrue($pref['password_CHAP'], 0)) ? " onsubmit='hashLoginPassword(this)'" : "";
333
334	// Start Clean
335	// NOTE: this should NOT be a template of the admin-template, however themes may style it using css.
336
337		$class = (e_QUERY == 'failed') ? "class='e-shake'" : "";
338
339
340
341		$text = "<form id='admin-login' method='post' action='".e_SELF."' {$incChap} >
342		<div id='logo' ><img src='".e_IMAGE."logo_template_large.png' alt='".LAN_LOGIN."' /></div>
343		<div id='login-admin' class='center'>
344		<div>";
345
346		if(e_QUERY == 'failed')
347		{
348			e107::lan('core', 'login');
349			$text .= "<div class='alert alert-danger'>".LAN_LOGIN_21."</div>";
350			$text .= "<script type='text/javascript'>
351				window.setTimeout(function() {
352			    $('.alert').fadeTo(500, 0).slideUp(500, function(){
353			        $(this).remove();
354			    });
355			}, 5000);
356			</script>";
357
358		}
359
360
361
362		$text .= "
363		<div class='panel well panel-primary'>
364			<div class='panel-heading'><h3 class='panel-title'>".LAN_HEADER_04."</h3></div>
365
366        <div class='panel-body'>
367		    <div class='field'>
368		    	<label for='username'>".ADLAN_89."</label>
369		    	<input class='tbox e-tip' type='text' autofocus required='required' name='authname' placeholder='".ADLAN_89."' id='username' size='30' value='' maxlength='".varset($pref['loginname_maxlength'], 30)."' />
370		    	<div class='field-help' data-placement='right'>".LAN_ENTER_USRNAME_EMAIL."</div>
371		   	</div>
372
373		    <div class='field'>
374		    	<label for='userpass'>".ADLAN_90."</label>
375		    	<input class='tbox e-tip'  type='password' required='required' name='authpass' placeholder='".ADLAN_90."' id='userpass' size='30' value='' maxlength='30' />
376		    	<div class='field-help' data-placement='right'>".LAN_PWD_REQUIRED."</div>
377		    </div>";
378
379		if ($use_imagecode)
380		{
381			$text .= "
382			<div class='field'>
383				<label for='code-verify'>".LAN_ENTER_CODE."</label>"
384				.$sec_img->renderImage().
385				$sec_img->renderInput()."
386			</div>";
387		}
388
389		    $text .= "<div class='admin-submit'>"
390		       	.$frm->admin_button('authsubmit',ADLAN_91,'login');
391
392			if (e107::getSession()->is('challenge') && varset($pref['password_CHAP'], 0))
393			{
394				$text .= "<input type='hidden' name='hashchallenge' id='hashchallenge' value='".e107::getSession()->get('challenge')."' />\n\n";
395			}
396
397		$text .= "</div></div>
398		</div>
399		</div>
400		 </div>
401		</form>";
402
403		e107::getRender()->tablerender("", $text, 'admin-login');
404		echo "<div class='row-fluid'>
405						<div class='center' style='margin-top:25%; color:silver'><span style='padding:0 40px 0 0px;'><a target='_blank' href='http://e107.org'>".ADLAN_165."</a></span> <a href='".e_BASE."index.php'>".ADLAN_166."</a></div>
406			</div>";
407	}
408
409
410	/**
411	 * Admin auth check
412	 * @param string $authname, entered name
413	 * @param string $authpass, entered pass
414	 * @param object $authresponse [optional]
415	 * @return boolean if fail, else result array
416	 */
417	public function authcheck($authname, $authpass, $authresponse = '')
418	{
419		$pref 		= e107::getPref();
420		$tp 		= e107::getParser();
421		$sql_auth 	= e107::getDb('sql_auth');
422		$user_info 	= e107::getUserSession();
423		$reason 	= '';
424
425		$authname = $tp->toDB(preg_replace("/\sOR\s|\=|\#/", "", trim($authname)));
426		$authpass = trim($authpass);
427
428		if ((($authpass == '') && ($authresponse == '')) || ($authname == ''))
429			$reason = 'np';
430		if (strlen($authname) > varset($pref['loginname_maxlength'], 30))
431			$reason = 'lu';
432
433		if (!$reason)
434		{
435			if ($sql_auth->select("user", "*", "user_loginname='{$authname}' AND user_admin = 1 "))
436			{
437				$row = $sql_auth->fetch();
438			}
439			elseif ($sql_auth->select("user", "*", "(user_name='{$authname}' OR user_email='{$authname}' ) AND user_admin=1 "))
440			{
441				$row = $sql_auth->fetch();
442				$authname = $row['user_loginname'];
443			}
444			else
445			{
446				$reason = 'iu';
447			}
448		}
449
450		if (!$reason && ($row['user_id'])) // Can validate password
451		{
452			$session = e107::getSession();
453			if (($authresponse && $session->is('prevchallenge')) && ($authresponse != $session->get('prevchallenge')))
454			{ // Verify using CHAP (can't handle login by email address - only loginname - although with this code it does still work if the password is stored unsalted)
455				/*
456				$title = 'Login via admin';
457				$extra_text = 'C: '.$session->get('challenge').' PC: '.$session->get('prevchallenge').' PPC: '.$session->get('prevprevchallenge').' R:'.$authresponse.' P:'.$row['user_password'];
458				$text = 'CHAP: '.$username.' ('.$extra_text.')';
459				$title = e107::getParser()->toDB($title);
460				$text  = e107::getParser()->toDB($text);
461				e107::getAdminLog()->e_log_event(4, __FILE__."|".__FUNCTION__."@".__LINE__, "LOGIN", $title, $text, FALSE, LOG_TO_ROLLING);
462
463				$logfp = fopen(e_LOG.'authlog.txt', 'a+'); fwrite($logfp, $title.': '.$text."\n"); fclose($logfp);
464				*/
465
466				if (($pass_result = $user_info->CheckCHAP($session->get('prevchallenge'), $authresponse, $authname, $row['user_password'])) !== PASSWORD_INVALID)
467				{
468					return $row;
469				}
470			}
471			else
472			{ // Plaintext password
473				/*
474				$title = 'Login via admin';
475				$extra_text = 'C: '.$session->get('challenge').' PC: '.$session->get('prevchallenge').' PPC: '.$session->get('prevprevchallenge').' R:'.$authresponse.' P:'.$row['user_password'];
476				$text = 'STD: '.$username.' ('.$extra_text.')';
477				$title = e107::getParser()->toDB($title);
478				$text  = e107::getParser()->toDB($text);
479				e107::getAdminLog()->e_log_event(4, __FILE__."|".__FUNCTION__."@".__LINE__, "LOGIN", $title, $text, FALSE, LOG_TO_ROLLING);
480
481//				$logfp = fopen(e_LOG.'authlog.txt', 'a+'); fwrite($logfp, $title.': '.$text."\n"); fclose($logfp);
482				*/
483
484				if (($pass_result = $user_info->CheckPassword($authpass, $authname, $row['user_password'])) !== PASSWORD_INVALID)
485				{
486					return $row;
487				}
488
489			}
490		}
491		return array("authfail", "reason"=>$reason);
492	}
493}
494
495//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------//
496?>
497