Project

General

Profile

Download (11.9 KB) Statistics
| Branch: | Tag: | Revision:
1
<?php
2
/*
3
 * authgui.inc
4
 *
5
 * part of pfSense (https://www.pfsense.org)
6
 * Copyright (c) 2003-2006 Manuel Kasper <mk@neon1.net>
7
 * Copyright (c) 2005-2006 Bill Marquette <bill.marquette@gmail.com>
8
 * Copyright (c) 2006 Paul Taylor <paultaylor@winn-dixie.com>
9
 * Copyright (c) 2004-2013 BSD Perimeter
10
 * Copyright (c) 2013-2016 Electric Sheep Fencing
11
 * Copyright (c) 2014-2025 Rubicon Communications, LLC (Netgate)
12
 * All rights reserved.
13
 *
14
 * Licensed under the Apache License, Version 2.0 (the "License");
15
 * you may not use this file except in compliance with the License.
16
 * You may obtain a copy of the License at
17
 *
18
 * http://www.apache.org/licenses/LICENSE-2.0
19
 *
20
 * Unless required by applicable law or agreed to in writing, software
21
 * distributed under the License is distributed on an "AS IS" BASIS,
22
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
23
 * See the License for the specific language governing permissions and
24
 * limitations under the License.
25
 */
26

    
27
include_once("auth.inc");
28
include_once("config.inc");
29
include_once("config.lib.inc");
30
include_once("priv.inc");
31
if (!function_exists('is_platform_booting')) {
32
	require_once('globals.inc');
33
}
34
require_once('pfsense-utils.inc');
35

    
36
/* Authenticate user - exit if failed */
37
if (!session_auth()) {
38
	display_login_form();
39
	exit;
40
}
41

    
42
phpsession_begin();
43

    
44
/*
45
 * Once here, the user has authenticated with the web server.
46
 * We give them access only to the appropriate pages based on
47
 * the user or group privileges.
48
 */
49
$allowedpages = getAllowedPages($_SESSION['Username'], $_SESSION['user_radius_attributes']);
50

    
51
/*
52
 * Get user-based preference settings so they can be easily referenced.
53
 */
54
$user_settings = get_user_settings($_SESSION['Username']);
55

    
56
/*
57
 * redirect to first allowed page if requesting a wrong url
58
 */
59

    
60
/* Fix this up otherwise the privilege check will fail. See Redmine #5909. */
61
if ($_SERVER['REQUEST_URI'] == "/") {
62
	$_SERVER['REQUEST_URI'] = "/index.php";
63
}
64

    
65
if (!isAllowedPage($_SERVER['REQUEST_URI'])) {
66
	if (count($allowedpages) > 0) {
67
		$page = str_replace('*', '', $allowedpages[0]);
68
		$_SESSION['Post_Login'] = true;
69
		require_once("functions.inc");
70
		pfSenseHeader("/{$page}");
71

    
72
		$username = get_config_user();
73
		log_error("{$username} attempted to access {$_SERVER['SCRIPT_NAME']} but does not have access to that page. Redirecting to {$page}.");
74
		phpsession_end();
75

    
76
		exit;
77
	} else {
78
		// add this so they don't get stuck on the logout page when they have no permissions.
79
		$_SESSION["Logged_In"] = false;
80
		display_error_form("201", gettext("No page assigned to this user! Click here to logout."));
81
		phpsession_end();
82

    
83
		exit;
84
	}
85
} else {
86
	$_SESSION['Post_Login'] = true;
87
}
88

    
89
/*
90
 * redirect browsers post-login to avoid pages
91
 * taking action in response to a POST request
92
 */
93
if (!$_SESSION['Post_Login']) {
94
	$_SESSION['Post_Login'] = true;
95
	require_once("functions.inc");
96
	pfSenseHeader($_SERVER['REQUEST_URI']);
97
	phpsession_end();
98

    
99
	exit;
100
}
101

    
102
/*
103
 * Close session data to allow other scripts from same host to come in.
104
 * A session can be reactivated from calling phpsession_begin again
105
 */
106
phpsession_end(true);
107

    
108
/*
109
 * determine if the user is allowed access to the requested page
110
 */
111
function display_error_form($http_code, $desc) {
112
	if (isAjax()) {
113
		printf(gettext('Error: %1$s Description: %2$s'), $http_code, $desc);
114
		return;
115
	}
116

    
117
	$logincssfile = "#770101";
118
?>
119

    
120
<!DOCTYPE html>
121
<html lang="en">
122
	<head>
123
		<meta name="viewport" content="width=device-width, initial-scale=1">
124
	    <link rel="stylesheet" href="/vendor/bootstrap/css/bootstrap.min.css" type="text/css">
125
	    <link rel="stylesheet" href="/css/login.css?v=<?=filemtime('/usr/local/www/css/login.css')?>" type="text/css">
126
		<title><?=gettext("Error"); ?></title>
127
	</head>
128

    
129
	<body id="error" >
130
		<div id="total">
131
			<header>
132
				<div id="headerrow">
133
					<div class="row">
134
						<div class="col-sm-4">
135
							<div id="logodiv" style="text-align:center" class="nowarning">
136
								<?php include("/usr/local/www/logo.svg"); ?>
137
							</div>
138
						</div>
139
						<div class="col-sm-8 nowarning msgbox text-center">
140
							<span id="hostspan">
141
							</span>
142
						</div>
143
					</div>
144
				</div>
145
			</header>
146

    
147
			<div style="background: <?=$logincssfile?>;" class="pagebody">
148
				<div class="col-sm-2"></div>
149

    
150
				<div class="col-sm-8 offset-md-4 logoCol">
151
					<div class="loginCont center-block error-panel">
152
						<a href="index.php?logout"><?=$desc;?></a>
153
					</div>
154
				</div>
155

    
156
			<div class="col-sm-2"></div>
157
			</div>
158

    
159
			<footer id="3">
160
			<div id="footertext">
161
					<p class="text-muted">
162
						<?=print_credit()?>
163
					</p>
164
				</div>
165
			</footer>
166
		</div>
167
	</body>
168
</html>
169

    
170
<?php
171

    
172
} // end function
173

    
174

    
175
function display_login_form() {
176
	require_once("globals.inc");
177
	global $g;
178

    
179
	unset($input_errors);
180

    
181
	if (isAjax()) {
182
		if (isset($_POST['login'])) {
183
			if ($_SESSION['Logged_In'] <> "True") {
184
				isset($_SESSION['Login_Error']) ? $login_error = $_SESSION['Login_Error'] : $login_error = gettext("unknown reason");
185
				printf("showajaxmessage('" . gettext("Invalid login (%s).") . "')", $login_error);
186
			}
187
			if (file_exists("{$g['tmp_path']}/webconfigurator.lock")) {
188
				// TODO: add the IP from the user who did lock the device
189
				$whom = file_get_contents("{$g['tmp_path']}/webconfigurator.lock");
190
				printf("showajaxmessage('" . gettext("This device is currently being maintained by: %s.") . "');", $whom);
191
			}
192
		}
193
		//If session ended
194
		echo "SESSION_TIMEOUT";
195
		exit;
196
	}
197

    
198
	/* Check against locally configured IP addresses, which will catch when someone
199
	   port forwards WebGUI access from WAN to an internal IP on the router. */
200
	global $FilterIflist;
201

    
202
	$local_ip = false;
203

    
204
	if (strpos($_SERVER['HTTP_HOST'], ":") === FALSE) {
205
		$http_host_port = explode(":", $_SERVER['HTTP_HOST']);
206
		$http_host = $http_host_port[0];
207
	} else {
208
		$http_host = $_SERVER['HTTP_HOST'];
209
	}
210

    
211
	if (empty($FilterIflist)) {
212
		require_once('filter.inc');
213
		require_once('shaper.inc');
214
		filter_generate_optcfg_array();
215
	}
216

    
217
	foreach ($FilterIflist as $iflist) {
218
		if ($iflist['ip'] == $http_host) {
219
			$local_ip = true;
220
		} else if ($iflist['ipv6'] == $http_host) {
221
			$local_ip = true;
222
		} else if (is_array($iflist['vips'])) {
223
			foreach ($iflist['vips'] as $vip) {
224
				if ($vip['ip'] == $http_host) {
225
					$local_ip = true;
226
					break;
227
				}
228
			}
229

    
230
			unset($vip);
231
		}
232

    
233
		if ($local_ip == true) {
234
			break;
235
		}
236
	}
237

    
238
	unset($FilterIflist);
239
	unset($iflist);
240

    
241
	if ($local_ip == false) {
242
		foreach (config_get_path('openvpn/openvpn-server', []) as $ovpns) {
243
			if (is_ipaddrv4($http_host) && !empty($ovpns['tunnel_network']) && ip_in_subnet($http_host, $ovpns['tunnel_network'])) {
244
				$local_ip = true;
245
			} else if (is_ipaddrv6($http_host) && !empty($ovpns['tunnel_networkv6']) && ip_in_subnet($http_host, $ovpns['tunnel_networkv6'])) {
246
				$local_ip = true;
247
			}
248

    
249
			if ($local_ip == true) {
250
				break;
251
			}
252
		}
253
	}
254

    
255
	// For the login form, get the settings of no particular user.
256
	// That ensures we will use the system default theme for the login form.
257
	$user_settings = get_user_settings("");
258
	$logincssfile = "#1e3f75";
259
	$login_message = print_login_message();
260

    
261
	if (isset($user_settings['webgui']['logincss']) && strlen($user_settings['webgui']['logincss']) == 6) {
262
		$logincssfile = "#" . $user_settings['webgui']['logincss'];
263
	}
264

    
265
	if (config_path_enabled('system/webgui','loginshowhost')) {
266
		$loginbannerstr = sprintf(gettext('%1$s.%2$s'),
267
								  htmlspecialchars(config_get_path('system/hostname', "")),
268
								  htmlspecialchars(config_get_path('system/domain', "")));
269
		$login_title = gettext(htmlspecialchars(config_get_path('system/hostname', "") . " - Login"));
270
	} Else {
271
		$loginbannerstr = sprintf(gettext('Login to %1$s'), g_get('product_label'));
272
		$login_title = sprintf(gettext("%s - Login"), g_get('product_label'));
273
	}
274

    
275
	$loginautocomplete = config_path_enabled('system/webgui','loginautocomplete') ? '' : 'autocomplete="off"';
276

    
277
	if (is_ipaddr($http_host) && !$local_ip &&
278
		!config_path_enabled('system/webgui','nohttpreferercheck')) {
279
		$warnclass = "pagebodywarn";	// Make room for a warning display row
280
	} else {
281
		$warnclass = "pagebody";
282
	}
283
?>
284
<!DOCTYPE html>
285
<html lang="en">
286
	<head>
287
		<meta name="viewport" content="width=device-width, initial-scale=1">
288
	    <link rel="stylesheet" href="/vendor/bootstrap/css/bootstrap.min.css" type="text/css">
289
	    <link rel="stylesheet" href="/css/login.css?v=<?=filemtime('/usr/local/www/css/login.css')?>" type="text/css">
290
		<title><?=$login_title; ?></title>
291
		<script type="text/javascript">
292
			//<![CDATA{
293
			var events = events || [];
294
			//]]>
295
		</script>
296
	</head>
297

    
298
	<body id="login" >
299
		<div id="total">
300
			<header>
301
				<div id="headerrow">
302
					<div class="row">
303
						<!-- Header left logo box -->
304
						<div class="col-sm-4">
305
							<div id="logodiv" style="text-align:center" class="nowarning">
306
								<?php include("/usr/local/www/logo.svg"); ?>
307
							</div>
308
						</div>
309

    
310
						<!-- Header center message box -->
311
						<div class="col-sm-4 nowarning msgbox text-center text-danger">
312
<?php
313
						if (!empty($_POST['usernamefld'])) {
314
							print("<h4>" . $_SESSION['Login_Error'] . "</h4>");
315
						}
316
?>
317
						</div>
318

    
319
						<!-- Header right message box (hostname or msg)-->
320
						<div class="col-sm-4 nowarning msgbox text-center">
321
							<span id="hostspan">
322
								<h4><?=$loginbannerstr?></h4>
323
							</span>
324
						</div>
325
					</div>
326
<?php
327
	if ($warnclass == "pagebodywarn") {
328
?>
329
					<div class="row">
330
						<div class="col-sm-12">
331
							<div class="alert alert-warning <?=$warnclass?>">
332
								<?=gettext("The IP address being used to access this router is not configured locally, which may be forwarded by NAT or other means.
333
								If this forwarding is unexpected, it should be verified that a man-in-the-middle attack is not taking place.")?>
334
							</div>
335
						</div>
336
					</div>
337
<?php
338
	}
339
?>
340
	            </div>
341
	        </header>
342

    
343
	        <div style="background: <?=$logincssfile?>;" class="<?=$warnclass?>">
344
				<?=(empty($login_message) ? '' : $login_message)?>
345
	        	<div class="col-sm-4"></div>
346

    
347
	        	<div class="col-sm-4 offset-md-4 <?=(empty($login_message) ? 'logoCol' : '')?>">
348
					<div class="loginCont center-block">
349
		                <form method="post" <?=$loginautocomplete?> class="login">
350
			                <p class="form-title">Sign In</p>
351
			                <input name="usernamefld" id="usernamefld" type="text" placeholder="Username" autocorrect="off" autocapitalize="none"/>
352
			                <input name="passwordfld" id="passwordfld" type="password" placeholder="Password" />
353
			                <input type="submit" name="login" value="Sign In" class="btn btn-success btn-sm" />
354
		                </form>
355
					</div>
356
	            </div>
357

    
358
	        	<div class="col-sm-4"></div>
359
	        </div>
360

    
361
	        <footer id="3">
362
	            <div id="footertext">
363
					<p class="text-muted">
364
						<?=print_credit()?>
365
					</p>
366
	            </div>
367
	        </footer>
368
	    </div>
369

    
370
		<script type="text/javascript">
371
		//<![CDATA[
372
			/* Prevent duplicate submission  */
373
			events.push(function() {
374
				var submitted = false;
375

    
376
				$(form).submit(function(e){
377
					if (submitted) {
378
						e.preventDefault();
379
					} else {
380
						submitted = true;
381
						// Form is submitted because default action is not prevented
382
					}
383
				});
384
			});
385
		//]]>
386
		</script>
387

    
388
	    <script src="/vendor/jquery/jquery-3.7.1.min.js?v=<?=filemtime('/usr/local/www/vendor/jquery/jquery-3.7.1.min.js')?>"></script>
389
		<script src="/vendor/bootstrap/js/bootstrap.min.js?v=<?=filemtime('/usr/local/www/vendor/bootstrap/js/bootstrap.min.js')?>"></script>
390
		<script src="/js/pfSense.js?v=<?=filemtime('/usr/local/www/js/pfSense.js')?>"></script>
391

    
392
		<script type="text/javascript">
393
		//!<[CDATA[
394
		events.push(function() {
395
			document.cookie=
396
				"cookie_test=1" +
397
				"<?php echo config_get_path('system/webgui/protocol') == 'https' ? '; secure' : '';?>";
398

    
399
			if (document.cookie.indexOf("cookie_test") == -1) {
400
				alert("<?=gettext('The browser must support cookies to login.')?>");
401
			}
402

    
403
			// Delete it
404
			document.cookie = "cookie_test=1; expires=Thu, 01-Jan-1970 00:00:01 GMT";
405
		});
406
		//]]>
407
		</script>
408

    
409
	</body>
410
</html>
411

    
412
<?php
413
} // end function
(5-5/61)