Project

General

Profile

Download (61.2 KB) Statistics
| Branch: | Tag: | Revision:
1
<?php
2
/*
3
 * auth.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-2018 Rubicon Communications, LLC (Netgate)
10
 * All rights reserved.
11
 *
12
 * Licensed under the Apache License, Version 2.0 (the "License");
13
 * you may not use this file except in compliance with the License.
14
 * You may obtain a copy of the License at
15
 *
16
 * http://www.apache.org/licenses/LICENSE-2.0
17
 *
18
 * Unless required by applicable law or agreed to in writing, software
19
 * distributed under the License is distributed on an "AS IS" BASIS,
20
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
21
 * See the License for the specific language governing permissions and
22
 * limitations under the License.
23
 */
24

    
25
/*
26
 * NOTE : Portions of the mschapv2 support was based on the BSD licensed CHAP.php
27
 * file courtesy of Michael Retterklieber.
28
 */
29
include_once('phpsessionmanager.inc');
30
if (!$do_not_include_config_gui_inc) {
31
	require_once("config.gui.inc");
32
}
33

    
34
// Will be changed to false if security checks fail
35
$security_passed = true;
36

    
37
/* If this function doesn't exist, we're being called from Captive Portal or
38
   another internal subsystem which does not include authgui.inc */
39
if (function_exists("display_error_form")) {
40
	/* Extra layer of lockout protection. Check if the user is in the GUI
41
	 * lockout table before processing a request */
42

    
43
	/* Fetch the contents of the lockout table. */
44
	$entries = array();
45
	exec("/sbin/pfctl -t 'sshguard' -T show", $entries);
46

    
47
	/* If the client is in the lockout table, print an error, kill states, and exit */
48
	if (in_array($_SERVER['REMOTE_ADDR'], array_map('trim', $entries))) {
49
		if (!security_checks_disabled()) {
50
			/* They may never see the error since the connection will be cut off, but try to be nice anyhow. */
51
			display_error_form("501", gettext("Access Denied<br/><br/>Access attempt from a temporarily locked out client address.<br /><br />Try accessing the firewall again after the lockout expires."));
52
			/* If they are locked out, they shouldn't have a state. Disconnect their connections. */
53
			$retval = pfSense_kill_states($_SERVER['REMOTE_ADDR']);
54
			if (is_ipaddrv4($_SERVER['REMOTE_ADDR'])) {
55
				$retval = pfSense_kill_states("0.0.0.0/0", $_SERVER['REMOTE_ADDR']);
56
			} elseif (is_ipaddrv6($_SERVER['REMOTE_ADDR'])) {
57
				$retval = pfSense_kill_states("::", $_SERVER['REMOTE_ADDR']);
58
			}
59
			exit;
60
		}
61
		$security_passed = false;
62
	}
63
}
64

    
65
if (function_exists("display_error_form") && !isset($config['system']['webgui']['nodnsrebindcheck'])) {
66
	/* DNS ReBinding attack prevention.  https://redmine.pfsense.org/issues/708 */
67
	$found_host = false;
68

    
69
	/* Either a IPv6 address with or without a alternate port */
70
	if (strstr($_SERVER['HTTP_HOST'], "]")) {
71
		$http_host_port = explode("]", $_SERVER['HTTP_HOST']);
72
		/* v6 address has more parts, drop the last part */
73
		if (count($http_host_port) > 1) {
74
			array_pop($http_host_port);
75
			$http_host = str_replace(array("[", "]"), "", implode(":", $http_host_port));
76
		} else {
77
			$http_host = str_replace(array("[", "]"), "", implode(":", $http_host_port));
78
		}
79
	} else {
80
		$http_host = explode(":", $_SERVER['HTTP_HOST']);
81
		$http_host = $http_host[0];
82
	}
83
	if (is_ipaddr($http_host) or $_SERVER['SERVER_ADDR'] == "127.0.0.1" or
84
		strcasecmp($http_host, "localhost") == 0 or $_SERVER['SERVER_ADDR'] == "::1") {
85
		$found_host = true;
86
	}
87
	if (strcasecmp($http_host, $config['system']['hostname'] . "." . $config['system']['domain']) == 0 or
88
		strcasecmp($http_host, $config['system']['hostname']) == 0) {
89
		$found_host = true;
90
	}
91

    
92
	if (is_array($config['dyndnses']['dyndns']) && !$found_host) {
93
		foreach ($config['dyndnses']['dyndns'] as $dyndns) {
94
			if (strcasecmp($dyndns['host'], $http_host) == 0) {
95
				$found_host = true;
96
				break;
97
			}
98
		}
99
	}
100

    
101
	if (is_array($config['dnsupdates']['dnsupdate']) && !$found_host) {
102
		foreach ($config['dnsupdates']['dnsupdate'] as $rfc2136) {
103
			if (strcasecmp($rfc2136['host'], $http_host) == 0) {
104
				$found_host = true;
105
				break;
106
			}
107
		}
108
	}
109

    
110
	if (!empty($config['system']['webgui']['althostnames']) && !$found_host) {
111
		$althosts = explode(" ", $config['system']['webgui']['althostnames']);
112
		foreach ($althosts as $ah) {
113
			if (strcasecmp($ah, $http_host) == 0 or strcasecmp($ah, $_SERVER['SERVER_ADDR']) == 0) {
114
				$found_host = true;
115
				break;
116
			}
117
		}
118
	}
119

    
120
	if ($found_host == false) {
121
		if (!security_checks_disabled()) {
122
			display_error_form("501", gettext("Potential DNS Rebind attack detected, see http://en.wikipedia.org/wiki/DNS_rebinding<br />Try accessing the router by IP address instead of by hostname."));
123
			exit;
124
		}
125
		$security_passed = false;
126
	}
127
}
128

    
129
// If the HTTP_REFERER is something other than ourselves then disallow.
130
if (function_exists("display_error_form") && !isset($config['system']['webgui']['nohttpreferercheck'])) {
131
	if ($_SERVER['HTTP_REFERER']) {
132
		if (file_exists("{$g['tmp_path']}/setupwizard_lastreferrer")) {
133
			if ($_SERVER['HTTP_REFERER'] == file_get_contents("{$g['tmp_path']}/setupwizard_lastreferrer")) {
134
				unlink("{$g['tmp_path']}/setupwizard_lastreferrer");
135
				header("Refresh: 1; url=index.php");
136
?>
137
<!DOCTYPE html>
138
<html lang="en">
139
<head>
140
	<link rel="stylesheet" href="/css/pfSense.css" />
141
	<title><?=gettext("Redirecting..."); ?></title>
142
</head>
143
<body id="error" class="no-menu">
144
	<div id="jumbotron">
145
		<div class="container">
146
			<div class="col-sm-offset-3 col-sm-6 col-xs-12">
147
				<p><?=gettext("Redirecting to the dashboard...")?></p>
148
			</div>
149
		</div>
150
	</div>
151
</body>
152
</html>
153
<?php
154
				exit;
155
			}
156
		}
157
		$found_host = false;
158
		$referrer_host = parse_url($_SERVER['HTTP_REFERER'], PHP_URL_HOST);
159
		$referrer_host = str_replace(array("[", "]"), "", $referrer_host);
160
		if ($referrer_host) {
161
			if (strcasecmp($referrer_host, $config['system']['hostname'] . "." . $config['system']['domain']) == 0 ||
162
			    strcasecmp($referrer_host, $config['system']['hostname']) == 0) {
163
				$found_host = true;
164
			}
165

    
166
			if (!empty($config['system']['webgui']['althostnames']) && !$found_host) {
167
				$althosts = explode(" ", $config['system']['webgui']['althostnames']);
168
				foreach ($althosts as $ah) {
169
					if (strcasecmp($referrer_host, $ah) == 0) {
170
						$found_host = true;
171
						break;
172
					}
173
				}
174
			}
175

    
176
			if (is_array($config['dyndnses']['dyndns']) && !$found_host) {
177
				foreach ($config['dyndnses']['dyndns'] as $dyndns) {
178
					if (strcasecmp($dyndns['host'], $referrer_host) == 0) {
179
						$found_host = true;
180
						break;
181
					}
182
				}
183
			}
184

    
185
			if (is_array($config['dnsupdates']['dnsupdate']) && !$found_host) {
186
				foreach ($config['dnsupdates']['dnsupdate'] as $rfc2136) {
187
					if (strcasecmp($rfc2136['host'], $referrer_host) == 0) {
188
						$found_host = true;
189
						break;
190
					}
191
				}
192
			}
193

    
194
			if (!$found_host) {
195
				$interface_list_ips = get_configured_ip_addresses();
196
				foreach ($interface_list_ips as $ilips) {
197
					if (strcasecmp($referrer_host, $ilips) == 0) {
198
						$found_host = true;
199
						break;
200
					}
201
				}
202
				$interface_list_ipv6s = get_configured_ipv6_addresses(true);
203
				foreach ($interface_list_ipv6s as $ilipv6s) {
204
					$ilipv6s = explode('%', $ilipv6s)[0];
205
					if (strcasecmp($referrer_host, $ilipv6s) == 0) {
206
						$found_host = true;
207
						break;
208
					}
209
				}
210
				if ($referrer_host == "127.0.0.1" || $referrer_host == "localhost") {
211
					// allow SSH port forwarded connections and links from localhost
212
					$found_host = true;
213
				}
214
			}
215

    
216
			/* Fall back to probing active interface addresses rather than config.xml to allow
217
			 * changed addresses that have not yet been applied.
218
			 * See https://redmine.pfsense.org/issues/8822
219
			 */
220
			if (!$found_host) {
221
				$refifs = get_interface_arr();
222
				foreach ($refifs as $rif) {
223
					if (($referrer_host == find_interface_ip($rif)) ||
224
					    ($referrer_host == find_interface_ipv6($rif)) ||
225
					    ($referrer_host == find_interface_ipv6_ll($rif))) {
226
						$found_host = true;
227
						break;
228
					}
229
				}
230
			}
231
		}
232
		if ($found_host == false) {
233
			if (!security_checks_disabled()) {
234
				display_error_form("501", "An HTTP_REFERER was detected other than what is defined in System -> Advanced (" . htmlspecialchars($_SERVER['HTTP_REFERER']) . ").  If not needed, this check can be disabled in System -> Advanced -> Admin.");
235
				exit;
236
			}
237
			$security_passed = false;
238
		}
239
	} else {
240
		$security_passed = false;
241
	}
242
}
243

    
244
if (function_exists("display_error_form") && $security_passed) {
245
	/* Security checks passed, so it should be OK to turn them back on */
246
	restore_security_checks();
247
}
248
unset($security_passed);
249

    
250
$groupindex = index_groups();
251
$userindex = index_users();
252

    
253
function index_groups() {
254
	global $g, $debug, $config, $groupindex;
255

    
256
	$groupindex = array();
257

    
258
	if (is_array($config['system']['group'])) {
259
		$i = 0;
260
		foreach ($config['system']['group'] as $groupent) {
261
			$groupindex[$groupent['name']] = $i;
262
			$i++;
263
		}
264
	}
265

    
266
	return ($groupindex);
267
}
268

    
269
function index_users() {
270
	global $g, $debug, $config;
271

    
272
	if (is_array($config['system']['user'])) {
273
		$i = 0;
274
		foreach ($config['system']['user'] as $userent) {
275
			$userindex[$userent['name']] = $i;
276
			$i++;
277
		}
278
	}
279

    
280
	return ($userindex);
281
}
282

    
283
function & getUserEntry($name) {
284
	global $debug, $config, $userindex;
285
	$authcfg = auth_get_authserver($config['system']['webgui']['authmode']);
286

    
287
	if (isset($userindex[$name])) {
288
		return $config['system']['user'][$userindex[$name]];
289
	} elseif ($authcfg['type'] != "Local Database") {
290
		$user = array();
291
		$user['name'] = $name;
292
		return $user;
293
	}
294
}
295

    
296
function & getUserEntryByUID($uid) {
297
	global $debug, $config;
298

    
299
	if (is_array($config['system']['user'])) {
300
		foreach ($config['system']['user'] as & $user) {
301
			if ($user['uid'] == $uid) {
302
				return $user;
303
			}
304
		}
305
	}
306

    
307
	return false;
308
}
309

    
310
function & getGroupEntry($name) {
311
	global $debug, $config, $groupindex;
312
	if (isset($groupindex[$name])) {
313
		return $config['system']['group'][$groupindex[$name]];
314
	}
315
}
316

    
317
function & getGroupEntryByGID($gid) {
318
	global $debug, $config;
319

    
320
	if (is_array($config['system']['group'])) {
321
		foreach ($config['system']['group'] as & $group) {
322
			if ($group['gid'] == $gid) {
323
				return $group;
324
			}
325
		}
326
	}
327

    
328
	return false;
329
}
330

    
331
function get_user_privileges(& $user) {
332
	global $config, $_SESSION;
333

    
334
	$authcfg = auth_get_authserver($config['system']['webgui']['authmode']);
335
	$allowed_groups = array();
336

    
337
	$privs = $user['priv'];
338
	if (!is_array($privs)) {
339
		$privs = array();
340
	}
341

    
342
	// cache auth results for a short time to ease load on auth services & logs
343
	if (isset($config['system']['webgui']['auth_refresh_time'])) {
344
		$recheck_time = $config['system']['webgui']['auth_refresh_time'];
345
	} else {
346
		$recheck_time = 30;
347
	}
348

    
349
	if ($authcfg['type'] == "ldap") {
350
		if (isset($_SESSION["ldap_allowed_groups"]) &&
351
		    (time() <= $_SESSION["auth_check_time"] + $recheck_time)) {
352
			$allowed_groups = $_SESSION["ldap_allowed_groups"];
353
		} else {
354
			$allowed_groups = @ldap_get_groups($user['name'], $authcfg);
355
			$_SESSION["ldap_allowed_groups"] = $allowed_groups;
356
			$_SESSION["auth_check_time"] = time();
357
		}
358
	} elseif ($authcfg['type'] == "radius") {
359
		if (isset($_SESSION["radius_allowed_groups"]) &&
360
		    (time() <= $_SESSION["auth_check_time"] + $recheck_time)) {
361
			$allowed_groups = $_SESSION["radius_allowed_groups"];
362
		} else {
363
			$allowed_groups = @radius_get_groups($_SESSION['user_radius_attributes']);
364
			$_SESSION["radius_allowed_groups"] = $allowed_groups;
365
			$_SESSION["auth_check_time"] = time();
366
		}
367
	}
368

    
369
	if (empty($allowed_groups)) {
370
		$allowed_groups = local_user_get_groups($user, true);
371
	}
372

    
373
	if (!is_array($allowed_groups)) {
374
		$allowed_groups = array('all');
375
	} else {
376
		$allowed_groups[] = 'all';
377
	}
378

    
379
	foreach ($allowed_groups as $name) {
380
		$group = getGroupEntry($name);
381
		if (is_array($group['priv'])) {
382
			$privs = array_merge($privs, $group['priv']);
383
		}
384
	}
385

    
386
	return $privs;
387
}
388

    
389
function userHasPrivilege($userent, $privid = false) {
390

    
391
	if (!$privid || !is_array($userent)) {
392
		return false;
393
	}
394

    
395
	$privs = get_user_privileges($userent);
396

    
397
	if (!is_array($privs)) {
398
		return false;
399
	}
400

    
401
	if (!in_array($privid, $privs)) {
402
		return false;
403
	}
404

    
405
	return true;
406
}
407

    
408
function local_backed($username, $passwd) {
409

    
410
	$user = getUserEntry($username);
411
	if (!$user) {
412
		return false;
413
	}
414

    
415
	if (is_account_disabled($username) || is_account_expired($username)) {
416
		return false;
417
	}
418

    
419
	if ($user['bcrypt-hash']) {
420
		if (password_verify($passwd, $user['bcrypt-hash'])) {
421
			return true;
422
		}
423
	}
424

    
425
	//for backwards compatibility
426
	if ($user['password']) {
427
		if (crypt($passwd, $user['password']) == $user['password']) {
428
			return true;
429
		}
430
	}
431

    
432
	if ($user['md5-hash']) {
433
		if (md5($passwd) == $user['md5-hash']) {
434
			return true;
435
		}
436
	}
437

    
438
	return false;
439
}
440

    
441
function local_sync_accounts($u2add, $u2del, $g2add, $g2del) {
442
	global $config, $debug;
443

    
444
	if (empty($u2add) && empty($u2del) && empty($g2add) && empty($g2del)) {
445
		/* Nothing to be done here */
446
		return;
447
	}
448

    
449
	foreach($u2del as $user) {
450
		if ($user['uid'] < 2000 || $user['uid'] > 65000) {
451
			continue;
452
		}
453

    
454
		/*
455
		 * If a crontab was created to user, pw userdel will be
456
		 * interactive and can cause issues. Just remove crontab
457
		 * before run it when necessary
458
		 */
459
		unlink_if_exists("/var/cron/tabs/{$user['name']}");
460
		$cmd = "/usr/sbin/pw userdel -n " .
461
		    escapeshellarg($user['name']);
462
		if ($debug) {
463
			log_error(sprintf(gettext("Running: %s"), $cmd));
464
		}
465
		mwexec($cmd);
466
		local_group_del_user($user);
467

    
468
		$system_user = $config['system']['user'];
469
		for ($i = 0; $i < count($system_user); $i++) {
470
			if ($system_user[$i]['name'] == $user['name']) {
471
				log_error("Removing user: {$user['name']}");
472
				unset($config['system']['user'][$i]);
473
				break;
474
			}
475
		}
476
	}
477

    
478
	foreach($g2del as $group) {
479
		if ($group['gid'] < 1999 || $group['gid'] > 65000) {
480
			continue;
481
		}
482

    
483
		$cmd = "/usr/sbin/pw groupdel -g " .
484
		    escapeshellarg($group['name']);
485
		if ($debug) {
486
			log_error(sprintf(gettext("Running: %s"), $cmd));
487
		}
488
		mwexec($cmd);
489

    
490
		$system_group = $config['system']['group'];
491
		for ($i = 0; $i < count($system_group); $i++) {
492
			if ($system_group[$i]['name'] == $group['name']) {
493
				log_error("Removing group: {$group['name']}");
494
				unset($config['system']['group'][$i]);
495
				break;
496
			}
497
		}
498
	}
499

    
500
	foreach ($u2add as $user) {
501
		log_error("Adding user: {$user['name']}");
502
		$config['system']['user'][] = $user;
503
	}
504

    
505
	foreach ($g2add as $group) {
506
		log_error("Adding group: {$group['name']}");
507
		$config['system']['group'][] = $group;
508
	}
509

    
510
	/* Sort it alphabetically */
511
	usort($config['system']['user'], function($a, $b) {
512
		return strcmp($a['name'], $b['name']);
513
	});
514
	usort($config['system']['group'], function($a, $b) {
515
		return strcmp($a['name'], $b['name']);
516
	});
517

    
518
	write_config("Sync'd users and groups via XMLRPC");
519

    
520
	/* make sure the all group exists */
521
	$allgrp = getGroupEntryByGID(1998);
522
	local_group_set($allgrp, true);
523

    
524
	foreach ($u2add as $user) {
525
		local_user_set($user);
526
	}
527

    
528
	foreach ($g2add as $group) {
529
		local_group_set($group);
530
	}
531
}
532

    
533
function local_reset_accounts() {
534
	global $debug, $config;
535

    
536
	/* remove local users to avoid uid conflicts */
537
	$fd = popen("/usr/sbin/pw usershow -a", "r");
538
	if ($fd) {
539
		while (!feof($fd)) {
540
			$line = explode(":", fgets($fd));
541
			if ($line[0] != "admin") {
542
				if (!strncmp($line[0], "_", 1)) {
543
					continue;
544
				}
545
				if ($line[2] < 2000) {
546
					continue;
547
				}
548
				if ($line[2] > 65000) {
549
					continue;
550
				}
551
			}
552
			/*
553
			 * If a crontab was created to user, pw userdel will be interactive and
554
			 * can cause issues. Just remove crontab before run it when necessary
555
			 */
556
			unlink_if_exists("/var/cron/tabs/{$line[0]}");
557
			$cmd = "/usr/sbin/pw userdel -n " . escapeshellarg($line[0]);
558
			if ($debug) {
559
				log_error(sprintf(gettext("Running: %s"), $cmd));
560
			}
561
			mwexec($cmd);
562
		}
563
		pclose($fd);
564
	}
565

    
566
	/* remove local groups to avoid gid conflicts */
567
	$gids = array();
568
	$fd = popen("/usr/sbin/pw groupshow -a", "r");
569
	if ($fd) {
570
		while (!feof($fd)) {
571
			$line = explode(":", fgets($fd));
572
			if (!strncmp($line[0], "_", 1)) {
573
				continue;
574
			}
575
			if ($line[2] < 2000) {
576
				continue;
577
			}
578
			if ($line[2] > 65000) {
579
				continue;
580
			}
581
			$cmd = "/usr/sbin/pw groupdel -g " . escapeshellarg($line[2]);
582
			if ($debug) {
583
				log_error(sprintf(gettext("Running: %s"), $cmd));
584
			}
585
			mwexec($cmd);
586
		}
587
		pclose($fd);
588
	}
589

    
590
	/* make sure the all group exists */
591
	$allgrp = getGroupEntryByGID(1998);
592
	local_group_set($allgrp, true);
593

    
594
	/* sync all local users */
595
	if (is_array($config['system']['user'])) {
596
		foreach ($config['system']['user'] as $user) {
597
			local_user_set($user);
598
		}
599
	}
600

    
601
	/* sync all local groups */
602
	if (is_array($config['system']['group'])) {
603
		foreach ($config['system']['group'] as $group) {
604
			local_group_set($group);
605
		}
606
	}
607
}
608

    
609
function local_user_set(& $user) {
610
	global $g, $debug;
611

    
612
	if (empty($user['password']) && empty($user['bcrypt-hash'])) {
613
		log_error("There is something wrong in the config because user {$user['name']} password is missing!");
614
		return;
615
	}
616

    
617

    
618
	$home_base = "/home/";
619
	$user_uid = $user['uid'];
620
	$user_name = $user['name'];
621
	$user_home = "{$home_base}{$user_name}";
622
	$user_shell = "/etc/rc.initial";
623
	$user_group = "nobody";
624

    
625
	// Ensure $home_base exists and is writable
626
	if (!is_dir($home_base)) {
627
		mkdir($home_base, 0755);
628
	}
629

    
630
	$lock_account = false;
631
	/* configure shell type */
632
	/* Cases here should be ordered by most privileged to least privileged. */
633
	if (userHasPrivilege($user, "user-shell-access") || userHasPrivilege($user, "page-all")) {
634
		$user_shell = "/bin/tcsh";
635
	} elseif (userHasPrivilege($user, "user-copy-files-chroot")) {
636
		$user_shell = "/usr/local/sbin/scponlyc";
637
	} elseif (userHasPrivilege($user, "user-copy-files")) {
638
		$user_shell = "/usr/local/bin/scponly";
639
	} elseif (userHasPrivilege($user, "user-ssh-tunnel")) {
640
		$user_shell = "/usr/local/sbin/ssh_tunnel_shell";
641
	} elseif (userHasPrivilege($user, "user-ipsec-xauth-dialin")) {
642
		$user_shell = "/sbin/nologin";
643
	} else {
644
		$user_shell = "/sbin/nologin";
645
		$lock_account = true;
646
	}
647

    
648
	/* Lock out disabled or expired users, unless it's root/admin. */
649
	if ((is_account_disabled($user_name) || is_account_expired($user_name)) && ($user_uid != 0)) {
650
		$user_shell = "/sbin/nologin";
651
		$lock_account = true;
652
	}
653

    
654
	/* root user special handling */
655
	if ($user_uid == 0) {
656
		$cmd = "/usr/sbin/pw usermod -q -n root -s /bin/sh -H 0";
657
		if ($debug) {
658
			log_error(sprintf(gettext("Running: %s"), $cmd));
659
		}
660
		$fd = popen($cmd, "w");
661
		if (empty($user['bcrypt-hash'])) {
662
			fwrite($fd, $user['password']);
663
		} else {
664
			fwrite($fd, $user['bcrypt-hash']);
665
		}
666
		pclose($fd);
667
		$user_group = "wheel";
668
		$user_home = "/root";
669
		$user_shell = "/etc/rc.initial";
670
	}
671

    
672
	/* read from pw db */
673
	$fd = popen("/usr/sbin/pw usershow -n {$user_name} 2>&1", "r");
674
	$pwread = fgets($fd);
675
	pclose($fd);
676
	$userattrs = explode(":", trim($pwread));
677

    
678
	$skel_dir = '/etc/skel';
679

    
680
	/* determine add or mod */
681
	if (($userattrs[0] != $user['name']) || (!strncmp($pwread, "pw:", 3))) {
682
		$user_op = "useradd -m -k " . escapeshellarg($skel_dir) . " -o";
683
	} else {
684
		$user_op = "usermod";
685
	}
686

    
687
	$comment = str_replace(array(":", "!", "@"), " ", $user['descr']);
688
	/* add or mod pw db */
689
	$cmd = "/usr/sbin/pw {$user_op} -q " .
690
			" -u " . escapeshellarg($user_uid) .
691
			" -n " . escapeshellarg($user_name) .
692
			" -g " . escapeshellarg($user_group) .
693
			" -s " . escapeshellarg($user_shell) .
694
			" -d " . escapeshellarg($user_home) .
695
			" -c " . escapeshellarg($comment) .
696
			" -H 0 2>&1";
697

    
698
	if ($debug) {
699
		log_error(sprintf(gettext("Running: %s"), $cmd));
700
	}
701
	$fd = popen($cmd, "w");
702
	if (empty($user['bcrypt-hash'])) {
703
		fwrite($fd, $user['password']);
704
	} else {
705
		fwrite($fd, $user['bcrypt-hash']);
706
	}
707
	pclose($fd);
708

    
709
	/* create user directory if required */
710
	if (!is_dir($user_home)) {
711
		mkdir($user_home, 0700);
712
	}
713
	@chown($user_home, $user_name);
714
	@chgrp($user_home, $user_group);
715

    
716
	/* Make sure all users have last version of config files */
717
	foreach (glob("{$skel_dir}/dot.*") as $dot_file) {
718
		$target = $user_home . '/' . substr(basename($dot_file), 3);
719
		@copy($dot_file, $target);
720
		@chown($target, $user_name);
721
		@chgrp($target, $user_group);
722
	}
723

    
724
	/* write out ssh authorized key file */
725
	if ($user['authorizedkeys']) {
726
		if (!is_dir("{$user_home}/.ssh")) {
727
			@mkdir("{$user_home}/.ssh", 0700);
728
			@chown("{$user_home}/.ssh", $user_name);
729
		}
730
		$keys = base64_decode($user['authorizedkeys']);
731
		@file_put_contents("{$user_home}/.ssh/authorized_keys", $keys);
732
		@chown("{$user_home}/.ssh/authorized_keys", $user_name);
733
	} else {
734
		unlink_if_exists("{$user_home}/.ssh/authorized_keys");
735
	}
736

    
737
	$un = $lock_account ? "" : "un";
738
	exec("/usr/sbin/pw {$un}lock " . escapeshellarg($user_name) . " -q 2>/dev/null");
739

    
740
}
741

    
742
function local_user_del($user) {
743
	global $debug;
744

    
745
	/* remove all memberships */
746
	local_user_set_groups($user);
747

    
748
	/* Don't remove /root */
749
	if ($user['uid'] != 0) {
750
		$rmhome = "-r";
751
	}
752

    
753
	/* read from pw db */
754
	$fd = popen("/usr/sbin/pw usershow -n {$user['name']} 2>&1", "r");
755
	$pwread = fgets($fd);
756
	pclose($fd);
757
	$userattrs = explode(":", trim($pwread));
758

    
759
	if ($userattrs[0] != $user['name']) {
760
		log_error("Tried to remove user {$user['name']} but got user {$userattrs[0]} instead. Bailing.");
761
		return;
762
	}
763

    
764
	/* delete from pw db */
765
	$cmd = "/usr/sbin/pw userdel -n " . escapeshellarg($user['name']) . " " . escapeshellarg($rmhome);
766

    
767
	if ($debug) {
768
		log_error(sprintf(gettext("Running: %s"), $cmd));
769
	}
770
	mwexec($cmd);
771

    
772
	/* Delete user from groups needs a call to write_config() */
773
	local_group_del_user($user);
774
}
775

    
776
function local_user_set_password(&$user, $password) {
777
	unset($user['password']);
778
	unset($user['md5-hash']);
779
	$user['bcrypt-hash'] = password_hash($password, PASSWORD_BCRYPT);
780
}
781

    
782
function local_user_get_groups($user, $all = false) {
783
	global $debug, $config;
784

    
785
	$groups = array();
786
	if (!is_array($config['system']['group'])) {
787
		return $groups;
788
	}
789

    
790
	foreach ($config['system']['group'] as $group) {
791
		if ($all || (!$all && ($group['name'] != "all"))) {
792
			if (is_array($group['member'])) {
793
				if (in_array($user['uid'], $group['member'])) {
794
					$groups[] = $group['name'];
795
				}
796
			}
797
		}
798
	}
799

    
800
	if ($all) {
801
		$groups[] = "all";
802
	}
803

    
804
	sort($groups);
805

    
806
	return $groups;
807

    
808
}
809

    
810
function local_user_set_groups($user, $new_groups = NULL) {
811
	global $debug, $config, $groupindex, $userindex;
812

    
813
	if (!is_array($config['system']['group'])) {
814
		return;
815
	}
816

    
817
	$cur_groups = local_user_get_groups($user, true);
818
	$mod_groups = array();
819

    
820
	if (!is_array($new_groups)) {
821
		$new_groups = array();
822
	}
823

    
824
	if (!is_array($cur_groups)) {
825
		$cur_groups = array();
826
	}
827

    
828
	/* determine which memberships to add */
829
	foreach ($new_groups as $groupname) {
830
		if ($groupname == '' || in_array($groupname, $cur_groups)) {
831
			continue;
832
		}
833
		$group = &$config['system']['group'][$groupindex[$groupname]];
834
		$group['member'][] = $user['uid'];
835
		$mod_groups[] = $group;
836

    
837
		/*
838
		 * If it's a new user, make sure it is added before try to
839
		 * add it as a member of a group
840
		 */
841
		if (!isset($userindex[$user['uid']])) {
842
			local_user_set($user);
843
		}
844
	}
845
	unset($group);
846

    
847
	/* determine which memberships to remove */
848
	foreach ($cur_groups as $groupname) {
849
		if (in_array($groupname, $new_groups)) {
850
			continue;
851
		}
852
		if (!isset($config['system']['group'][$groupindex[$groupname]])) {
853
			continue;
854
		}
855
		$group = &$config['system']['group'][$groupindex[$groupname]];
856
		if (is_array($group['member'])) {
857
			$index = array_search($user['uid'], $group['member']);
858
			array_splice($group['member'], $index, 1);
859
			$mod_groups[] = $group;
860
		}
861
	}
862
	unset($group);
863

    
864
	/* sync all modified groups */
865
	foreach ($mod_groups as $group) {
866
		local_group_set($group);
867
	}
868
}
869

    
870
function local_group_del_user($user) {
871
	global $config;
872

    
873
	if (!is_array($config['system']['group'])) {
874
		return;
875
	}
876

    
877
	foreach ($config['system']['group'] as $group) {
878
		if (is_array($group['member'])) {
879
			foreach ($group['member'] as $idx => $uid) {
880
				if ($user['uid'] == $uid) {
881
					unset($config['system']['group']['member'][$idx]);
882
				}
883
			}
884
		}
885
	}
886
}
887

    
888
function local_group_set($group, $reset = false) {
889
	global $debug;
890

    
891
	$group_name = $group['name'];
892
	$group_gid = $group['gid'];
893
	$group_members = '';
894

    
895
	if (!$reset && !empty($group['member']) && count($group['member']) > 0) {
896
		$group_members = implode(",", $group['member']);
897
	}
898

    
899
	if (empty($group_name)) {
900
		return;
901
	}
902

    
903
	// If the group is now remote, make sure there is no local group with the same name
904
	if ($group['scope'] == "remote") {
905
		local_group_del($group);
906
		return;
907
	}
908

    
909
	/* determine add or mod */
910
	if (mwexec("/usr/sbin/pw groupshow -g " . escapeshellarg($group_gid) . " 2>&1", true) == 0) {
911
		$group_op = "groupmod -l";
912
	} else {
913
		$group_op = "groupadd -n";
914
	}
915

    
916
	/* add or mod group db */
917
	$cmd = "/usr/sbin/pw {$group_op} " .
918
		escapeshellarg($group_name) .
919
		" -g " . escapeshellarg($group_gid) .
920
		" -M " . escapeshellarg($group_members) . " 2>&1";
921

    
922
	if ($debug) {
923
		log_error(sprintf(gettext("Running: %s"), $cmd));
924
	}
925

    
926
	mwexec($cmd);
927
}
928

    
929
function local_group_del($group) {
930
	global $debug;
931

    
932
	/* delete from group db */
933
	$cmd = "/usr/sbin/pw groupdel " . escapeshellarg($group['name']);
934

    
935
	if ($debug) {
936
		log_error(sprintf(gettext("Running: %s"), $cmd));
937
	}
938
	mwexec($cmd);
939
}
940

    
941
function ldap_test_connection($authcfg) {
942
	if ($authcfg) {
943
		if (strstr($authcfg['ldap_urltype'], "SSL")) {
944
			$ldapproto = "ldaps";
945
		} else {
946
			$ldapproto = "ldap";
947
		}
948
		$ldapserver = "{$ldapproto}://" . ldap_format_host($authcfg['host']);
949
		$ldapport = $authcfg['ldap_port'];
950
		if (!empty($ldapport)) {
951
			$ldapserver .= ":{$ldapport}";
952
		}
953
	} else {
954
		return false;
955
	}
956

    
957
	/* first check if there is even an LDAP server populated */
958
	if (!$ldapserver) {
959
		return false;
960
	}
961

    
962
	/* Setup CA environment if needed. */
963
	ldap_setup_caenv($authcfg);
964

    
965
	/* connect and see if server is up */
966
	$error = false;
967
	if (!($ldap = ldap_connect($ldapserver))) {
968
		$error = true;
969
	}
970

    
971
	if ($error == true) {
972
		log_error(sprintf(gettext("ERROR!  Could not connect to server %s."), $authcfg['name']));
973
		return false;
974
	}
975

    
976
	return true;
977
}
978

    
979
function ldap_setup_caenv($authcfg) {
980
	global $g;
981
	require_once("certs.inc");
982

    
983
	unset($caref);
984
	if (empty($authcfg['ldap_caref']) || strstr($authcfg['ldap_urltype'], "Standard")) {
985
		putenv('LDAPTLS_REQCERT=never');
986
		return;
987
	} elseif ($authcfg['ldap_caref'] == "global") {
988
		putenv('LDAPTLS_REQCERT=hard');
989
		putenv("LDAPTLS_CACERTDIR=/etc/ssl/");
990
		putenv("LDAPTLS_CACERT=/etc/ssl/cert.pem");
991
	} else {
992
		$caref = lookup_ca($authcfg['ldap_caref']);
993
		$param = array('caref' => $authcfg['ldap_caref']);
994
		$cachain = ca_chain($param);
995
		if (!$caref) {
996
			log_error(sprintf(gettext("LDAP: Could not lookup CA by reference for host %s."), $authcfg['ldap_caref']));
997
			/* XXX: Prevent for credential leaking since we cannot setup the CA env. Better way? */
998
			putenv('LDAPTLS_REQCERT=hard');
999
			return;
1000
		}
1001
		if (!is_dir("{$g['varrun_path']}/certs")) {
1002
			@mkdir("{$g['varrun_path']}/certs");
1003
		}
1004
		if (file_exists("{$g['varrun_path']}/certs/{$caref['refid']}.ca")) {
1005
			@unlink("{$g['varrun_path']}/certs/{$caref['refid']}.ca");
1006
		}
1007
		file_put_contents("{$g['varrun_path']}/certs/{$caref['refid']}.ca", $cachain);
1008
		@chmod("{$g['varrun_path']}/certs/{$caref['refid']}.ca", 0600);
1009
		putenv('LDAPTLS_REQCERT=hard');
1010
		/* XXX: Probably even the hashed link should be created for this? */
1011
		putenv("LDAPTLS_CACERTDIR={$g['varrun_path']}/certs");
1012
		putenv("LDAPTLS_CACERT={$g['varrun_path']}/certs/{$caref['refid']}.ca");
1013
	}
1014
}
1015

    
1016
function ldap_test_bind($authcfg) {
1017
	global $debug, $config, $g;
1018

    
1019
	if ($authcfg) {
1020
		if (strstr($authcfg['ldap_urltype'], "SSL")) {
1021
			$ldapproto = "ldaps";
1022
		} else {
1023
			$ldapproto = "ldap";
1024
		}
1025
		$ldapserver = "{$ldapproto}://" . ldap_format_host($authcfg['host']);
1026
		$ldapport = $authcfg['ldap_port'];
1027
		if (!empty($ldapport)) {
1028
			$ldapserver .= ":{$ldapport}";
1029
		}
1030
		$ldapbasedn = $authcfg['ldap_basedn'];
1031
		$ldapbindun = $authcfg['ldap_binddn'];
1032
		$ldapbindpw = $authcfg['ldap_bindpw'];
1033
		$ldapver = $authcfg['ldap_protver'];
1034
		$ldaptimeout = is_numeric($authcfg['ldap_timeout']) ? $authcfg['ldap_timeout'] : 5;
1035
		if (empty($ldapbindun) || empty($ldapbindpw)) {
1036
			$ldapanon = true;
1037
		} else {
1038
			$ldapanon = false;
1039
		}
1040
	} else {
1041
		return false;
1042
	}
1043

    
1044
	/* first check if there is even an LDAP server populated */
1045
	if (!$ldapserver) {
1046
		return false;
1047
	}
1048

    
1049
	/* Setup CA environment if needed. */
1050
	ldap_setup_caenv($authcfg);
1051

    
1052
	/* connect and see if server is up */
1053
	$error = false;
1054
	if (!($ldap = ldap_connect($ldapserver))) {
1055
		$error = true;
1056
	}
1057

    
1058
	if ($error == true) {
1059
		log_error(sprintf(gettext("ERROR!  Could not connect to server %s."), $ldapname));
1060
		return false;
1061
	}
1062

    
1063
	ldap_set_option($ldap, LDAP_OPT_REFERRALS, 0);
1064
	ldap_set_option($ldap, LDAP_OPT_DEREF, LDAP_DEREF_SEARCHING);
1065
	ldap_set_option($ldap, LDAP_OPT_PROTOCOL_VERSION, (int)$ldapver);
1066
	ldap_set_option($ldap, LDAP_OPT_TIMELIMIT, (int)$ldaptimeout);
1067
	ldap_set_option($ldap, LDAP_OPT_NETWORK_TIMEOUT, (int)$ldaptimeout);
1068

    
1069
	if (strstr($authcfg['ldap_urltype'], "STARTTLS")) {
1070
		if (!(@ldap_start_tls($ldap))) {
1071
			log_error(sprintf(gettext("ERROR! ldap_test_bind() could not STARTTLS to server %s."), $ldapname));
1072
			@ldap_close($ldap);
1073
			return false;
1074
		}
1075
	}
1076

    
1077
	$ldapbindun = isset($authcfg['ldap_utf8']) ? utf8_encode($ldapbindun) : $ldapbindun;
1078
	$ldapbindpw = isset($authcfg['ldap_utf8']) ? utf8_encode($ldapbindpw) : $ldapbindpw;
1079
	if ($ldapanon == true) {
1080
		if (!($res = @ldap_bind($ldap))) {
1081
			@ldap_close($ldap);
1082
			return false;
1083
		}
1084
	} else if (!($res = @ldap_bind($ldap, $ldapbindun, $ldapbindpw))) {
1085
		@ldap_close($ldap);
1086
		return false;
1087
	}
1088

    
1089
	@ldap_unbind($ldap);
1090

    
1091
	return true;
1092
}
1093

    
1094
function ldap_get_user_ous($show_complete_ou=true, $authcfg) {
1095
	global $debug, $config, $g;
1096

    
1097
	if (!function_exists("ldap_connect")) {
1098
		return;
1099
	}
1100

    
1101
	$ous = array();
1102

    
1103
	if ($authcfg) {
1104
		if (strstr($authcfg['ldap_urltype'], "SSL")) {
1105
			$ldapproto = "ldaps";
1106
		} else {
1107
			$ldapproto = "ldap";
1108
		}
1109
		$ldapserver = "{$ldapproto}://" . ldap_format_host($authcfg['host']);
1110
		$ldapport = $authcfg['ldap_port'];
1111
		if (!empty($ldapport)) {
1112
			$ldapserver .= ":{$ldapport}";
1113
		}
1114
		$ldapbasedn = $authcfg['ldap_basedn'];
1115
		$ldapbindun = $authcfg['ldap_binddn'];
1116
		$ldapbindpw = $authcfg['ldap_bindpw'];
1117
		$ldapver = $authcfg['ldap_protver'];
1118
		if (empty($ldapbindun) || empty($ldapbindpw)) {
1119
			$ldapanon = true;
1120
		} else {
1121
			$ldapanon = false;
1122
		}
1123
		$ldapname = $authcfg['name'];
1124
		$ldapfallback = false;
1125
		$ldapscope = $authcfg['ldap_scope'];
1126
		$ldaptimeout = is_numeric($authcfg['ldap_timeout']) ? $authcfg['ldap_timeout'] : 5;
1127
	} else {
1128
		return false;
1129
	}
1130

    
1131
	/* first check if there is even an LDAP server populated */
1132
	if (!$ldapserver) {
1133
		log_error(gettext("ERROR!  ldap_get_user_ous() backed selected with no LDAP authentication server defined."));
1134
		return $ous;
1135
	}
1136

    
1137
	/* Setup CA environment if needed. */
1138
	ldap_setup_caenv($authcfg);
1139

    
1140
	/* connect and see if server is up */
1141
	$error = false;
1142
	if (!($ldap = ldap_connect($ldapserver))) {
1143
		$error = true;
1144
	}
1145

    
1146
	if ($error == true) {
1147
		log_error(sprintf(gettext("ERROR!  Could not connect to server %s."), $ldapname));
1148
		return $ous;
1149
	}
1150

    
1151
	$ldapfilter = "(|(ou=*)(cn=Users))";
1152

    
1153
	ldap_set_option($ldap, LDAP_OPT_REFERRALS, 0);
1154
	ldap_set_option($ldap, LDAP_OPT_DEREF, LDAP_DEREF_SEARCHING);
1155
	ldap_set_option($ldap, LDAP_OPT_PROTOCOL_VERSION, (int)$ldapver);
1156
	ldap_set_option($ldap, LDAP_OPT_TIMELIMIT, (int)$ldaptimeout);
1157
	ldap_set_option($ldap, LDAP_OPT_NETWORK_TIMEOUT, (int)$ldaptimeout);
1158

    
1159
	if (strstr($authcfg['ldap_urltype'], "STARTTLS")) {
1160
		if (!(@ldap_start_tls($ldap))) {
1161
			log_error(sprintf(gettext("ERROR! ldap_get_user_ous() could not STARTTLS to server %s."), $ldapname));
1162
			@ldap_close($ldap);
1163
			return false;
1164
		}
1165
	}
1166

    
1167
	$ldapbindun = isset($authcfg['ldap_utf8']) ? utf8_encode($ldapbindun) : $ldapbindun;
1168
	$ldapbindpw = isset($authcfg['ldap_utf8']) ? utf8_encode($ldapbindpw) : $ldapbindpw;
1169
	if ($ldapanon == true) {
1170
		if (!($res = @ldap_bind($ldap))) {
1171
			log_error(sprintf(gettext("ERROR! ldap_get_user_ous() could not bind anonymously to server %s."), $ldapname));
1172
			@ldap_close($ldap);
1173
			return $ous;
1174
		}
1175
	} else if (!($res = @ldap_bind($ldap, $ldapbindun, $ldapbindpw))) {
1176
		log_error(sprintf(gettext("ERROR! ldap_get_user_ous() could not bind to server %s."), $ldapname));
1177
		@ldap_close($ldap);
1178
		return $ous;
1179
	}
1180

    
1181
	if ($ldapscope == "one") {
1182
		$ldapfunc = "ldap_list";
1183
	} else {
1184
		$ldapfunc = "ldap_search";
1185
	}
1186

    
1187
	$search = @$ldapfunc($ldap, $ldapbasedn, $ldapfilter);
1188
	$info = @ldap_get_entries($ldap, $search);
1189

    
1190
	if (is_array($info)) {
1191
		foreach ($info as $inf) {
1192
			if (!$show_complete_ou) {
1193
				$inf_split = explode(",", $inf['dn']);
1194
				$ou = $inf_split[0];
1195
				$ou = str_replace("OU=", "", $ou);
1196
				$ou = str_replace("CN=", "", $ou);
1197
			} else {
1198
				if ($inf['dn']) {
1199
					$ou = $inf['dn'];
1200
				}
1201
			}
1202
			if ($ou) {
1203
				$ous[] = $ou;
1204
			}
1205
		}
1206
	}
1207

    
1208
	@ldap_unbind($ldap);
1209

    
1210
	return $ous;
1211
}
1212

    
1213
function ldap_get_groups($username, $authcfg) {
1214
	global $debug, $config;
1215

    
1216
	if (!function_exists("ldap_connect")) {
1217
		return;
1218
	}
1219

    
1220
	if (!$username) {
1221
		return false;
1222
	}
1223

    
1224
	if (!isset($authcfg['ldap_nostrip_at']) && stristr($username, "@")) {
1225
		$username_split = explode("@", $username);
1226
		$username = $username_split[0];
1227
	}
1228

    
1229
	if (stristr($username, "\\")) {
1230
		$username_split = explode("\\", $username);
1231
		$username = $username_split[0];
1232
	}
1233

    
1234
	//log_error("Getting LDAP groups for {$username}.");
1235
	if ($authcfg) {
1236
		if (strstr($authcfg['ldap_urltype'], "SSL")) {
1237
			$ldapproto = "ldaps";
1238
		} else {
1239
			$ldapproto = "ldap";
1240
		}
1241
		$ldapserver = "{$ldapproto}://" . ldap_format_host($authcfg['host']);
1242
		$ldapport = $authcfg['ldap_port'];
1243
		if (!empty($ldapport)) {
1244
			$ldapserver .= ":{$ldapport}";
1245
		}
1246
		$ldapbasedn = $authcfg['ldap_basedn'];
1247
		$ldapbindun = $authcfg['ldap_binddn'];
1248
		$ldapbindpw = $authcfg['ldap_bindpw'];
1249
		$ldapauthcont = $authcfg['ldap_authcn'];
1250
		$ldapnameattribute = strtolower($authcfg['ldap_attr_user']);
1251
		$ldapgroupattribute = strtolower($authcfg['ldap_attr_member']);
1252
		if (isset($authcfg['ldap_rfc2307'])) {
1253
			$ldapfilter         = "(&(objectClass={$authcfg['ldap_attr_groupobj']})({$ldapgroupattribute}={$username}))";
1254
		} else {
1255
			$ldapfilter         = "({$ldapnameattribute}={$username})";
1256
		}
1257
		$ldaptype = "";
1258
		$ldapver = $authcfg['ldap_protver'];
1259
		if (empty($ldapbindun) || empty($ldapbindpw)) {
1260
			$ldapanon = true;
1261
		} else {
1262
			$ldapanon = false;
1263
		}
1264
		$ldapname = $authcfg['name'];
1265
		$ldapfallback = false;
1266
		$ldapscope = $authcfg['ldap_scope'];
1267
		$ldaptimeout = is_numeric($authcfg['ldap_timeout']) ? $authcfg['ldap_timeout'] : 5;
1268
	} else {
1269
		return false;
1270
	}
1271

    
1272
	if (isset($authcfg['ldap_rfc2307'])) {
1273
		$ldapdn = $ldapbasedn;
1274
	} else {
1275
		$ldapdn = $_SESSION['ldapdn'];
1276
	}
1277

    
1278
	/*Convert attribute to lowercase.  php ldap arrays put everything in lowercase */
1279
	$ldapgroupattribute = strtolower($ldapgroupattribute);
1280
	$memberof = array();
1281

    
1282
	/* Setup CA environment if needed. */
1283
	ldap_setup_caenv($authcfg);
1284

    
1285
	/* connect and see if server is up */
1286
	$error = false;
1287
	if (!($ldap = ldap_connect($ldapserver))) {
1288
		$error = true;
1289
	}
1290

    
1291
	if ($error == true) {
1292
		log_error(sprintf(gettext("ERROR! ldap_get_groups() Could not connect to server %s."), $ldapname));
1293
		return $memberof;
1294
	}
1295

    
1296
	ldap_set_option($ldap, LDAP_OPT_REFERRALS, 0);
1297
	ldap_set_option($ldap, LDAP_OPT_DEREF, LDAP_DEREF_SEARCHING);
1298
	ldap_set_option($ldap, LDAP_OPT_PROTOCOL_VERSION, (int)$ldapver);
1299
	ldap_set_option($ldap, LDAP_OPT_TIMELIMIT, (int)$ldaptimeout);
1300
	ldap_set_option($ldap, LDAP_OPT_NETWORK_TIMEOUT, (int)$ldaptimeout);
1301

    
1302
	if (strstr($authcfg['ldap_urltype'], "STARTTLS")) {
1303
		if (!(@ldap_start_tls($ldap))) {
1304
			log_error(sprintf(gettext("ERROR! ldap_get_groups() could not STARTTLS to server %s."), $ldapname));
1305
			@ldap_close($ldap);
1306
			return false;
1307
		}
1308
	}
1309

    
1310
	/* bind as user that has rights to read group attributes */
1311
	$ldapbindun = isset($authcfg['ldap_utf8']) ? utf8_encode($ldapbindun) : $ldapbindun;
1312
	$ldapbindpw = isset($authcfg['ldap_utf8']) ? utf8_encode($ldapbindpw) : $ldapbindpw;
1313
	if ($ldapanon == true) {
1314
		if (!($res = @ldap_bind($ldap))) {
1315
			log_error(sprintf(gettext("ERROR! ldap_get_groups() could not bind anonymously to server %s."), $ldapname));
1316
			@ldap_close($ldap);
1317
			return false;
1318
		}
1319
	} else if (!($res = @ldap_bind($ldap, $ldapbindun, $ldapbindpw))) {
1320
		log_error(sprintf(gettext("ERROR! ldap_get_groups() could not bind to server %s."), $ldapname));
1321
		@ldap_close($ldap);
1322
		return $memberof;
1323
	}
1324

    
1325
	/* get groups from DN found */
1326
	/* use ldap_read instead of search so we don't have to do a bunch of extra work */
1327
	/* since we know the DN is in $_SESSION['ldapdn'] */
1328
	//$search    = ldap_read($ldap, $ldapdn, "(objectclass=*)", array($ldapgroupattribute));
1329
	if ($ldapscope == "one") {
1330
		$ldapfunc = "ldap_list";
1331
	} else {
1332
		$ldapfunc = "ldap_search";
1333
	}
1334

    
1335
	$search = @$ldapfunc($ldap, $ldapdn, $ldapfilter, array($ldapgroupattribute));
1336
	$info = @ldap_get_entries($ldap, $search);
1337

    
1338
	$gresults = isset($authcfg['ldap_rfc2307']) ? $info : $info[0][$ldapgroupattribute];
1339

    
1340
	if (is_array($gresults)) {
1341
		/* Iterate through the groups and throw them into an array */
1342
		foreach ($gresults as $grp) {
1343
			if (((isset($authcfg['ldap_rfc2307'])) && (stristr($grp["dn"], "CN=") !== false)) ||
1344
			    ((!isset($authcfg['ldap_rfc2307'])) && (stristr($grp, "CN=") !== false))) {
1345
				$grpsplit = isset($authcfg['ldap_rfc2307']) ? explode(",", $grp["dn"]) : explode(",", $grp);
1346
				$memberof[] = preg_replace("/CN=/i", "", $grpsplit[0]);
1347
			}
1348
		}
1349
	}
1350

    
1351
	/* Time to close LDAP connection */
1352
	@ldap_unbind($ldap);
1353

    
1354
	$groups = print_r($memberof, true);
1355

    
1356
	//log_error("Returning groups ".$groups." for user $username");
1357

    
1358
	return $memberof;
1359
}
1360

    
1361
function ldap_format_host($host) {
1362
	return is_ipaddrv6($host) ? "[$host]" : $host ;
1363
}
1364

    
1365
function ldap_backed($username, $passwd, $authcfg, &$attributes = array()) {
1366
	global $debug, $config;
1367

    
1368
	if (!$username) {
1369
		$attributes['error_message'] = gettext("Invalid Login.");
1370
		return false;
1371
	}
1372

    
1373
	if (!function_exists("ldap_connect")) {
1374
		log_error(gettext("ERROR! unable to find ldap_connect() function."));
1375
		$attributes['error_message'] = gettext("Internal error during authentication.");
1376
		return null;
1377
	}
1378

    
1379
	if (!isset($authcfg['ldap_nostrip_at']) && stristr($username, "@")) {
1380
		$username_split = explode("@", $username);
1381
		$username = $username_split[0];
1382
	}
1383
	if (stristr($username, "\\")) {
1384
		$username_split = explode("\\", $username);
1385
		$username = $username_split[0];
1386
	}
1387

    
1388
	$username = ldap_escape($username, null, LDAP_ESCAPE_FILTER);
1389

    
1390
	if ($authcfg) {
1391
		if (strstr($authcfg['ldap_urltype'], "SSL")) {
1392
			$ldapproto = "ldaps";
1393
		} else {
1394
			$ldapproto = "ldap";
1395
		}
1396
		$ldapserver = "{$ldapproto}://" . ldap_format_host($authcfg['host']);
1397
		$ldapport = $authcfg['ldap_port'];
1398
		if (!empty($ldapport)) {
1399
			$ldapserver .= ":{$ldapport}";
1400
		}
1401
		$ldapbasedn = $authcfg['ldap_basedn'];
1402
		$ldapbindun = $authcfg['ldap_binddn'];
1403
		$ldapbindpw = $authcfg['ldap_bindpw'];
1404
		if (empty($ldapbindun) || empty($ldapbindpw)) {
1405
			$ldapanon = true;
1406
		} else {
1407
			$ldapanon = false;
1408
		}
1409
		$ldapauthcont = $authcfg['ldap_authcn'];
1410
		$ldapnameattribute = strtolower($authcfg['ldap_attr_user']);
1411
		$ldapextendedqueryenabled = $authcfg['ldap_extended_enabled'];
1412
		$ldapextendedquery = $authcfg['ldap_extended_query'];
1413
		$ldapfilter = "";
1414
		if (!$ldapextendedqueryenabled) {
1415
			$ldapfilter = "({$ldapnameattribute}={$username})";
1416
		} else {
1417
			$ldapfilter = "(&({$ldapnameattribute}={$username})({$ldapextendedquery}))";
1418
		}
1419
		$ldaptype = "";
1420
		$ldapver = $authcfg['ldap_protver'];
1421
		$ldapname = $authcfg['name'];
1422
		$ldapscope = $authcfg['ldap_scope'];
1423
		$ldaptimeout = is_numeric($authcfg['ldap_timeout']) ? $authcfg['ldap_timeout'] : 5;
1424
	} else {
1425
		return null;
1426
	}
1427

    
1428
	/* first check if there is even an LDAP server populated */
1429
	if (!$ldapserver) {
1430
		log_error(gettext("ERROR! could not find details of the LDAP server used for authentication."));
1431
		$attributes['error_message'] =  gettext("Internal error during authentication.");
1432
		return null;
1433
	}
1434

    
1435
	/* Setup CA environment if needed. */
1436
	ldap_setup_caenv($authcfg);
1437

    
1438
	/* Make sure we can connect to LDAP */
1439
	$error = false;
1440
	if (!($ldap = ldap_connect($ldapserver))) {
1441
		$error = true;
1442
	}
1443

    
1444
	ldap_set_option($ldap, LDAP_OPT_REFERRALS, 0);
1445
	ldap_set_option($ldap, LDAP_OPT_DEREF, LDAP_DEREF_SEARCHING);
1446
	ldap_set_option($ldap, LDAP_OPT_PROTOCOL_VERSION, (int)$ldapver);
1447
	ldap_set_option($ldap, LDAP_OPT_TIMELIMIT, (int)$ldaptimeout);
1448
	ldap_set_option($ldap, LDAP_OPT_NETWORK_TIMEOUT, (int)$ldaptimeout);
1449

    
1450
	if (strstr($authcfg['ldap_urltype'], "STARTTLS")) {
1451
		if (!(@ldap_start_tls($ldap))) {
1452
			log_error(sprintf(gettext("ERROR! could not connect to LDAP server %s using STARTTLS."), $ldapname));
1453
			$attributes['error_message'] = gettext("Error : could not connect to authentication server.");
1454
			@ldap_close($ldap);
1455
			return null;
1456
		}
1457
	}
1458

    
1459
	if ($error == true) {
1460
		$errormsg = sprintf(gettext("ERROR! Could not connect to server %s."), $ldapname);
1461
		$attributes['error_message'] = gettext("Error : could not connect to authentication server.");
1462
		return null;
1463
	}
1464

    
1465
	/* ok, its up.  now, lets bind as the bind user so we can search it */
1466
	$error = false;
1467
	$ldapbindun = isset($authcfg['ldap_utf8']) ? utf8_encode($ldapbindun) : $ldapbindun;
1468
	$ldapbindpw = isset($authcfg['ldap_utf8']) ? utf8_encode($ldapbindpw) : $ldapbindpw;
1469
	if ($ldapanon == true) {
1470
		if (!($res = @ldap_bind($ldap))) {
1471
			$error = true;
1472
		}
1473
	} else if (!($res = @ldap_bind($ldap, $ldapbindun, $ldapbindpw))) {
1474
		$error = true;
1475
	}
1476

    
1477
	if ($error == true) {
1478
		@ldap_close($ldap);
1479
		log_error(sprintf(gettext("ERROR! Could not bind to LDAP server %s. Please check the bind credentials."), $ldapname));
1480
		$attributes['error_message'] = gettext("Error : could not connect to authentication server.");
1481
		return null;
1482
	}
1483

    
1484
	/* Get LDAP Authcontainers and split em up. */
1485
	$ldac_splits = explode(";", $ldapauthcont);
1486

    
1487
	/* setup the usercount so we think we haven't found anyone yet */
1488
	$usercount = 0;
1489

    
1490
	/*****************************************************************/
1491
	/*  We first find the user based on username and filter          */
1492
	/*  then, once we find the first occurrence of that person       */
1493
	/*  we set session variables to point to the OU and DN of the    */
1494
	/*  person.  To later be used by ldap_get_groups.                */
1495
	/*  that way we don't have to search twice.                      */
1496
	/*****************************************************************/
1497
	if ($debug) {
1498
		log_auth(sprintf(gettext("Now Searching for %s in directory."), $username));
1499
	}
1500
	/* Iterate through the user containers for search */
1501
	foreach ($ldac_splits as $i => $ldac_split) {
1502
		$ldac_split = isset($authcfg['ldap_utf8']) ? utf8_encode($ldac_split) : $ldac_split;
1503
		$ldapfilter = isset($authcfg['ldap_utf8']) ? utf8_encode($ldapfilter) : $ldapfilter;
1504
		$ldapsearchbasedn = isset($authcfg['ldap_utf8']) ? utf8_encode("{$ldac_split},{$ldapbasedn}") : "{$ldac_split},{$ldapbasedn}";
1505
		/* Make sure we just use the first user we find */
1506
		if ($debug) {
1507
			log_auth(sprintf(gettext('Now Searching in server %1$s, container %2$s with filter %3$s.'), $ldapname, utf8_decode($ldac_split), utf8_decode($ldapfilter)));
1508
		}
1509
		if ($ldapscope == "one") {
1510
			$ldapfunc = "ldap_list";
1511
		} else {
1512
			$ldapfunc = "ldap_search";
1513
		}
1514
		/* Support legacy auth container specification. */
1515
		if (stristr($ldac_split, "DC=") || empty($ldapbasedn)) {
1516
			$search = @$ldapfunc($ldap, $ldac_split, $ldapfilter);
1517
		} else {
1518
			$search = @$ldapfunc($ldap, $ldapsearchbasedn, $ldapfilter);
1519
		}
1520
		if (!$search) {
1521
			log_error(sprintf(gettext("Search resulted in error: %s"), ldap_error($ldap)));
1522
			continue;
1523
		}
1524
		$info = ldap_get_entries($ldap, $search);
1525
		$matches = $info['count'];
1526
		if ($matches == 1) {
1527
			$userdn = $_SESSION['ldapdn'] = $info[0]['dn'];
1528
			$_SESSION['ldapou'] = $ldac_split[$i];
1529
			$_SESSION['ldapon'] = "true";
1530
			$usercount = 1;
1531
			break;
1532
		}
1533
	}
1534

    
1535
	if ($usercount != 1) {
1536
		@ldap_unbind($ldap);
1537
		if ($debug) {
1538
			if ($usercount === 0) {
1539
				log_error(sprintf(gettext("ERROR! LDAP search failed, no user matching %s was found."), $username));
1540
			} else {
1541
				log_error(sprintf(gettext("ERROR! LDAP search failed, multiple users matching %s were found."), $username));
1542
			}
1543
		}
1544
		$attributes['error_message'] = gettext("Invalid login specified.");
1545
		return false;
1546
	}
1547

    
1548
	/* Now lets bind as the user we found */
1549
	$passwd = isset($authcfg['ldap_utf8']) ? utf8_encode($passwd) : $passwd;
1550
	if (!($res = @ldap_bind($ldap, $userdn, $passwd))) {
1551
		if ($debug) {
1552
			log_error(sprintf(gettext('ERROR! Could not login to server %1$s as user %2$s: %3$s'), $ldapname, $username, ldap_error($ldap)));
1553
		}
1554
		@ldap_unbind($ldap);
1555
		return false;
1556
	}
1557

    
1558
	if ($debug) {
1559
		$userdn = isset($authcfg['ldap_utf8']) ? utf8_decode($userdn) : $userdn;
1560
		log_auth(sprintf(gettext('Logged in successfully as %1$s via LDAP server %2$s with DN = %3$s.'), $username, $ldapname, $userdn));
1561
	}
1562

    
1563
	/* At this point we are bound to LDAP so the user was auth'd okay. Close connection. */
1564
	@ldap_unbind($ldap);
1565

    
1566
	return true;
1567
}
1568

    
1569
function radius_backed($username, $password, $authcfg, &$attributes = array()) {
1570
	global $debug, $config;
1571
	$ret = false;
1572

    
1573
	require_once("Auth/RADIUS.php");
1574
	require_once("Crypt/CHAP.php");
1575

    
1576
	if ($authcfg) {
1577
		$radiusservers = array();
1578
		$radiusservers[0]['ipaddr'] = $authcfg['host'];
1579
		$radiusservers[0]['port'] = $authcfg['radius_auth_port'];
1580
		$radiusservers[0]['sharedsecret'] = $authcfg['radius_secret'];
1581
		$radiusservers[0]['timeout'] = $authcfg['radius_timeout'];
1582
		if(isset($authcfg['radius_protocol'])) {
1583
			$radius_protocol = $authcfg['radius_protocol'];
1584
		} else {
1585
			$radius_protocol = 'PAP';
1586
		}
1587
	} else {
1588
		log_error(gettext("ERROR! could not find details of the RADIUS server used for authentication."));
1589
		$attributes['error_message'] =  gettext("Internal error during authentication.");
1590
		return null;
1591
	}
1592

    
1593
	// Create our instance
1594
	$classname = 'Auth_RADIUS_' . $radius_protocol;
1595
	$rauth = new $classname($username, $password);
1596

    
1597
	/* Add new servers to our instance */
1598
	foreach ($radiusservers as $radsrv) {
1599
		$timeout = (is_numeric($radsrv['timeout'])) ? $radsrv['timeout'] : 5;
1600
		$rauth->addServer($radsrv['ipaddr'], $radsrv['port'], $radsrv['sharedsecret'], $timeout);
1601
	}
1602

    
1603
	// Construct data package
1604
	$rauth->username = $username;
1605
	switch ($radius_protocol) {
1606
		case 'CHAP_MD5':
1607
		case 'MSCHAPv1':
1608
			$classname = $radius_protocol == 'MSCHAPv1' ? 'Crypt_CHAP_MSv1' : 'Crypt_CHAP_MD5';
1609
			$crpt = new $classname;
1610
			$crpt->username = $username;
1611
			$crpt->password = $password;
1612
			$rauth->challenge = $crpt->challenge;
1613
			$rauth->chapid = $crpt->chapid;
1614
			$rauth->response = $crpt->challengeResponse();
1615
			$rauth->flags = 1;
1616
			break;
1617

    
1618
		case 'MSCHAPv2':
1619
			$crpt = new Crypt_CHAP_MSv2;
1620
			$crpt->username = $username;
1621
			$crpt->password = $password;
1622
			$rauth->challenge = $crpt->authChallenge;
1623
			$rauth->peerChallenge = $crpt->peerChallenge;
1624
			$rauth->chapid = $crpt->chapid;
1625
			$rauth->response = $crpt->challengeResponse();
1626
			break;
1627

    
1628
		default:
1629
			$rauth->password = $password;
1630
			break;
1631
	}
1632

    
1633
	if (PEAR::isError($rauth->start())) {
1634
		$ret = null;
1635
		log_error(sprintf(gettext("Error during RADIUS authentication : %s"), $rauth->getError()));
1636
		$attributes['error_message'] = gettext("Error : could not connect to authentication server.");
1637
	} else {
1638
		$nasid = $attributes['nas_identifier'];
1639
		$nasip = $authcfg['radius_nasip_attribute'];
1640
		if (empty($nasid)) {
1641
			$nasid = gethostname(); //If no RADIUS NAS-Identifier is given : we use pfsense's hostname as NAS-Identifier
1642
		}
1643
		if (!is_ipaddr($nasip)) {
1644
			$nasip = get_interface_ip($nasip);
1645
			
1646
			if (!is_ipaddr($nasip)) {
1647
				$nasip = get_interface_ip();//We use wan interface IP as fallback for NAS-IP-Address
1648
			}
1649
		}
1650
		$nasmac = get_interface_mac(find_ip_interface($nasip));
1651

    
1652
		$rauth->putAttribute(RADIUS_NAS_IP_ADDRESS, $nasip, "addr");
1653
		$rauth->putAttribute(RADIUS_NAS_IDENTIFIER, $nasid);
1654
		
1655
		if(!empty($attributes['calling_station_id'])) {
1656
			$rauth->putAttribute(RADIUS_CALLING_STATION_ID, $attributes['calling_station_id']);
1657
		}
1658
		// Carefully check that interface has a MAC address
1659
		if(!empty($nasmac)) {
1660
			$nasmac = mac_format($nasmac);
1661
			$rauth->putAttribute(RADIUS_CALLED_STATION_ID, $nasmac.':'.gethostname());
1662
		}
1663
		if(!empty($attributes['nas_port_type'])) {
1664
			$rauth->putAttribute(RADIUS_NAS_PORT_TYPE, $attributes['nas_port_type']);
1665
		}		
1666
		if(!empty($attributes['nas_port'])) {
1667
			$rauth->putAttribute(RADIUS_NAS_PORT, intval($attributes['nas_port']), 'integer');
1668
		}
1669
		if(!empty($attributes['framed_ip']) && is_ipaddr($attributes['framed_ip'])) {
1670
			$rauth->putAttribute(RADIUS_FRAMED_IP_ADDRESS, $attributes['framed_ip'], "addr");
1671
		}
1672
	}
1673

    
1674
	// XXX - billm - somewhere in here we need to handle securid challenge/response
1675

    
1676
	/* Send request */
1677
	$result = $rauth->send();
1678
	if (PEAR::isError($result)) {
1679
		log_error(sprintf(gettext("Error during RADIUS authentication : %s"), $rauth->getError()));
1680
		$attributes['error_message'] = gettext("Error : could not connect to authentication server.");
1681
		$ret = null;
1682
	} else if ($result === true) {
1683
		$ret = true;
1684
	} else {
1685
		$ret = false;
1686
	}
1687

    
1688
	
1689
	// Get attributes, even if auth failed.
1690
	if ($rauth->getAttributes()) {
1691
	$attributes = array_merge($attributes,$rauth->listAttributes());
1692

    
1693
	// We convert the session_terminate_time to unixtimestamp if its set before returning the whole array to our caller
1694
	if (!empty($attributes['session_terminate_time'])) {
1695
			$stt = &$attributes['session_terminate_time'];
1696
			$stt = strtotime(preg_replace("/\+(\d+):(\d+)$/", " +\${1}\${2}", preg_replace("/(\d+)T(\d+)/", "\${1} \${2}",$stt)));
1697
		}
1698
	}
1699
	
1700
	// close OO RADIUS_AUTHENTICATION
1701
	$rauth->close();
1702

    
1703
	return $ret;
1704
}
1705

    
1706
/*
1707
	$attributes must contain a "class" key containing the groups and local
1708
	groups must exist to match.
1709
*/
1710
function radius_get_groups($attributes) {
1711
	$groups = array();
1712
	if (!empty($attributes) && is_array($attributes) && (!empty($attributes['class']) || !empty($attributes['class_int']))) {
1713
		/* Some RADIUS servers return multiple class attributes, so check them all. */
1714
		$groups = array();
1715
		if (!empty($attributes['class']) && is_array($attributes['class'])) {
1716
			foreach ($attributes['class'] as $class) {
1717
				$groups = array_unique(array_merge($groups, explode(";", $class)));
1718
			}
1719
		}
1720

    
1721
		foreach ($groups as & $grp) {
1722
			$grp = trim($grp);
1723
			if (strtolower(substr($grp, 0, 3)) == "ou=") {
1724
				$grp = substr($grp, 3);
1725
			}
1726
		}
1727
	}
1728
	return $groups;
1729
}
1730

    
1731
function get_user_expiration_date($username) {
1732
	$user = getUserEntry($username);
1733
	if ($user['expires']) {
1734
		return $user['expires'];
1735
	}
1736
}
1737

    
1738
function is_account_expired($username) {
1739
	$expirydate = get_user_expiration_date($username);
1740
	if ($expirydate) {
1741
		if (strtotime("-1 day") > strtotime(date("m/d/Y", strtotime($expirydate)))) {
1742
			return true;
1743
		}
1744
	}
1745

    
1746
	return false;
1747
}
1748

    
1749
function is_account_disabled($username) {
1750
	$user = getUserEntry($username);
1751
	if (isset($user['disabled'])) {
1752
		return true;
1753
	}
1754

    
1755
	return false;
1756
}
1757

    
1758
function get_user_settings($username) {
1759
	global $config;
1760
	$settings = array();
1761
	$settings['widgets'] = $config['widgets'];
1762
	$settings['webgui']['dashboardcolumns'] = $config['system']['webgui']['dashboardcolumns'];
1763
	$settings['webgui']['webguihostnamemenu'] = $config['system']['webgui']['webguihostnamemenu'];
1764
	$settings['webgui']['webguicss'] = $config['system']['webgui']['webguicss'];
1765
	$settings['webgui']['logincss'] = $config['system']['webgui']['logincss'];
1766
	$settings['webgui']['interfacessort'] = isset($config['system']['webgui']['interfacessort']);
1767
	$settings['webgui']['dashboardavailablewidgetspanel'] = isset($config['system']['webgui']['dashboardavailablewidgetspanel']);
1768
	$settings['webgui']['webguifixedmenu'] = isset($config['system']['webgui']['webguifixedmenu']);
1769
	$settings['webgui']['webguileftcolumnhyper'] = isset($config['system']['webgui']['webguileftcolumnhyper']);
1770
	$settings['webgui']['disablealiaspopupdetail'] = isset($config['system']['webgui']['disablealiaspopupdetail']);
1771
	$settings['webgui']['systemlogsfilterpanel'] = isset($config['system']['webgui']['systemlogsfilterpanel']);
1772
	$settings['webgui']['systemlogsmanagelogpanel'] = isset($config['system']['webgui']['systemlogsmanagelogpanel']);
1773
	$settings['webgui']['statusmonitoringsettingspanel'] = isset($config['system']['webgui']['statusmonitoringsettingspanel']);
1774
	$settings['webgui']['pagenamefirst'] = isset($config['system']['webgui']['pagenamefirst']);
1775
	$user = getUserEntry($username);
1776
	if (isset($user['customsettings'])) {
1777
		$settings['customsettings'] = true;
1778
		if (isset($user['widgets'])) {
1779
			// This includes the 'sequence', and any widgetname-config per-widget settings.
1780
			$settings['widgets'] = $user['widgets'];
1781
		}
1782
		if (isset($user['dashboardcolumns'])) {
1783
			$settings['webgui']['dashboardcolumns'] = $user['dashboardcolumns'];
1784
		}
1785
		if (isset($user['webguicss'])) {
1786
			$settings['webgui']['webguicss'] = $user['webguicss'];
1787
		}
1788
		if (isset($user['webguihostnamemenu'])) {
1789
			$settings['webgui']['webguihostnamemenu'] = $user['webguihostnamemenu'];
1790
		}
1791
		$settings['webgui']['interfacessort'] = isset($user['interfacessort']);
1792
		$settings['webgui']['dashboardavailablewidgetspanel'] = isset($user['dashboardavailablewidgetspanel']);
1793
		$settings['webgui']['webguifixedmenu'] = isset($user['webguifixedmenu']);
1794
		$settings['webgui']['webguileftcolumnhyper'] = isset($user['webguileftcolumnhyper']);
1795
		$settings['webgui']['disablealiaspopupdetail'] = isset($user['disablealiaspopupdetail']);
1796
		$settings['webgui']['systemlogsfilterpanel'] = isset($user['systemlogsfilterpanel']);
1797
		$settings['webgui']['systemlogsmanagelogpanel'] = isset($user['systemlogsmanagelogpanel']);
1798
		$settings['webgui']['statusmonitoringsettingspanel'] = isset($user['statusmonitoringsettingspanel']);
1799
		$settings['webgui']['pagenamefirst'] = isset($user['pagenamefirst']);
1800
	} else {
1801
		$settings['customsettings'] = false;
1802
	}
1803

    
1804
	if ($settings['webgui']['dashboardcolumns'] < 1) {
1805
		$settings['webgui']['dashboardcolumns'] = 2;
1806
	}
1807

    
1808
	return $settings;
1809
}
1810

    
1811
function save_widget_settings($username, $settings, $message = "") {
1812
	global $config, $userindex;
1813
	$user = getUserEntry($username);
1814

    
1815
	if (strlen($message) > 0) {
1816
		$msgout = $message;
1817
	} else {
1818
		$msgout = gettext("Widget configuration has been changed.");
1819
	}
1820

    
1821
	if (isset($user['customsettings'])) {
1822
		$config['system']['user'][$userindex[$username]]['widgets'] = $settings;
1823
		write_config($msgout . " " . sprintf(gettext("(User %s)"), $username));
1824
	} else {
1825
		$config['widgets'] = $settings;
1826
		write_config($msgout);
1827
	}
1828
}
1829

    
1830
function auth_get_authserver($name) {
1831
	global $config;
1832

    
1833
	if (is_array($config['system']['authserver'])) {
1834
		foreach ($config['system']['authserver'] as $authcfg) {
1835
			if ($authcfg['name'] == $name) {
1836
				return $authcfg;
1837
			}
1838
		}
1839
	}
1840
	if ($name == "Local Database") {
1841
		return array("name" => "Local Database", "type" => "Local Auth", "host" => $config['system']['hostname']);
1842
	}
1843
}
1844

    
1845
function auth_get_authserver_list() {
1846
	global $config;
1847

    
1848
	$list = array();
1849

    
1850
	if (is_array($config['system']['authserver'])) {
1851
		foreach ($config['system']['authserver'] as $authcfg) {
1852
			/* Add support for disabled entries? */
1853
			$list[$authcfg['name']] = $authcfg;
1854
		}
1855
	}
1856

    
1857
	$list["Local Database"] = array("name" => "Local Database", "type" => "Local Auth", "host" => $config['system']['hostname']);
1858
	return $list;
1859
}
1860

    
1861
function getUserGroups($username, $authcfg, &$attributes = array()) {
1862
	global $config;
1863

    
1864
	$allowed_groups = array();
1865

    
1866
	switch ($authcfg['type']) {
1867
		case 'ldap':
1868
			$allowed_groups = @ldap_get_groups($username, $authcfg);
1869
			break;
1870
		case 'radius':
1871
			$allowed_groups = @radius_get_groups($attributes);
1872
			break;
1873
		default:
1874
			$user = getUserEntry($username);
1875
			$allowed_groups = @local_user_get_groups($user, true);
1876
			break;
1877
	}
1878

    
1879
	$member_groups = array();
1880
	if (is_array($config['system']['group'])) {
1881
		foreach ($config['system']['group'] as $group) {
1882
			if (in_array($group['name'], $allowed_groups)) {
1883
				$member_groups[] = $group['name'];
1884
			}
1885
		}
1886
	}
1887

    
1888
	return $member_groups;
1889
}
1890

    
1891
/*
1892
Possible return values : 
1893
true : authentication worked
1894
false : authentication failed (invalid login/password, not enought permission, etc...)
1895
null : error during authentication process (unable to reach remote server, etc...)
1896
*/
1897
function authenticate_user($username, $password, $authcfg = NULL, &$attributes = array()) {
1898

    
1899
	if (is_array($username) || is_array($password)) {
1900
		return false;
1901
	}
1902

    
1903
	if (!$authcfg) {
1904
		return local_backed($username, $password, $attributes);
1905
	}
1906

    
1907
	$authenticated = false;
1908
	switch ($authcfg['type']) {
1909
		case 'ldap':
1910
			$authenticated = ldap_backed($username, $password, $authcfg, $attributes);
1911
			break;
1912
		case 'radius':
1913
			$authenticated = radius_backed($username, $password, $authcfg, $attributes);
1914
			break;
1915
		default:
1916
			/* lookup user object by name */
1917
			$authenticated = local_backed($username, $password, $attributes);
1918
			break;
1919
		}
1920

    
1921
	return $authenticated;
1922
}
1923

    
1924
function session_auth() {
1925
	global $config, $_SESSION, $page;
1926

    
1927
	// Handle HTTPS httponly and secure flags
1928
	$currentCookieParams = session_get_cookie_params();
1929
	session_set_cookie_params(
1930
		$currentCookieParams["lifetime"],
1931
		$currentCookieParams["path"],
1932
		NULL,
1933
		($config['system']['webgui']['protocol'] == "https"),
1934
		true
1935
	);
1936

    
1937
	phpsession_begin();
1938

    
1939
	// Detect protocol change
1940
	if (!isset($_POST['login']) && !empty($_SESSION['Logged_In']) && $_SESSION['protocol'] != $config['system']['webgui']['protocol']) {
1941
		phpsession_end();
1942
		return false;
1943
	}
1944

    
1945
	/* Validate incoming login request */
1946
	$attributes = array();
1947
	if (isset($_POST['login']) && !empty($_POST['usernamefld']) && !empty($_POST['passwordfld'])) {
1948
		$authcfg = auth_get_authserver($config['system']['webgui']['authmode']);
1949
		$remoteauth = authenticate_user($_POST['usernamefld'], $_POST['passwordfld'], $authcfg, $attributes);
1950
		if ($remoteauth || authenticate_user($_POST['usernamefld'], $_POST['passwordfld'])) {
1951
			// Generate a new id to avoid session fixation
1952
			session_regenerate_id();
1953
			$_SESSION['Logged_In'] = "True";
1954
			$_SESSION['remoteauth'] = $remoteauth;
1955
			if ($remoteauth) {
1956
				if (empty($authcfg['type']) || ($authcfg['type'] == "Local Auth")) {
1957
					$_SESSION['authsource'] = "Local Database";
1958
				} else {
1959
					$_SESSION['authsource'] = strtoupper($authcfg['type']) . "/{$authcfg['name']}";
1960
				}
1961
			} else {
1962
				$_SESSION['authsource'] = 'Local Database Fallback';
1963
			}
1964
			$_SESSION['Username'] = $_POST['usernamefld'];
1965
			$_SESSION['user_radius_attributes'] = $attributes;
1966
			$_SESSION['last_access'] = time();
1967
			$_SESSION['protocol'] = $config['system']['webgui']['protocol'];
1968
			phpsession_end(true);
1969
			if (!isset($config['system']['webgui']['quietlogin'])) {
1970
				log_auth(sprintf(gettext("Successful login for user '%1\$s' from: %2\$s"), $_POST['usernamefld'], get_user_remote_address() . get_user_remote_authsource()));
1971
			}
1972
			if (isset($_POST['postafterlogin'])) {
1973
				return true;
1974
			} else {
1975
				if (empty($page)) {
1976
					$page = "/";
1977
				}
1978
				header("Location: {$page}");
1979
			}
1980
			exit;
1981
		} else {
1982
			/* give the user an error message */
1983
			$_SESSION['Login_Error'] = gettext("Username or Password incorrect");
1984
			log_auth(sprintf(gettext("webConfigurator authentication error for user '%1\$s' from: %2\$s"), $_POST['usernamefld'], get_user_remote_address() . get_user_remote_authsource()));
1985
			if (isAjax()) {
1986
				echo "showajaxmessage('{$_SESSION['Login_Error']}');";
1987
				return;
1988
			}
1989
		}
1990
	}
1991

    
1992
	/* Show login page if they aren't logged in */
1993
	if (empty($_SESSION['Logged_In'])) {
1994
		phpsession_end(true);
1995
		return false;
1996
	}
1997

    
1998
	/* If session timeout isn't set, we don't mark sessions stale */
1999
	if (!isset($config['system']['webgui']['session_timeout'])) {
2000
		/* Default to 4 hour timeout if one is not set */
2001
		if ($_SESSION['last_access'] < (time() - 14400)) {
2002
			$_POST['logout'] = true;
2003
			$_SESSION['Logout'] = true;
2004
		} else {
2005
			$_SESSION['last_access'] = time();
2006
		}
2007
	} else if (intval($config['system']['webgui']['session_timeout']) == 0) {
2008
		/* only update if it wasn't ajax */
2009
		if (!isAjax()) {
2010
			$_SESSION['last_access'] = time();
2011
		}
2012
	} else {
2013
		/* Check for stale session */
2014
		if ($_SESSION['last_access'] < (time() - ($config['system']['webgui']['session_timeout'] * 60))) {
2015
			$_POST['logout'] = true;
2016
			$_SESSION['Logout'] = true;
2017
		} else {
2018
			/* only update if it wasn't ajax */
2019
			if (!isAjax()) {
2020
				$_SESSION['last_access'] = time();
2021
			}
2022
		}
2023
	}
2024

    
2025
	/* user hit the logout button */
2026
	if (isset($_POST['logout'])) {
2027

    
2028
		if ($_SESSION['Logout']) {
2029
			log_error(sprintf(gettext("Session timed out for user '%1\$s' from: %2\$s"), $_SESSION['Username'], get_user_remote_address() . get_user_remote_authsource()));
2030
		} else {
2031
			log_error(sprintf(gettext("User logged out for user '%1\$s' from: %2\$s"), $_SESSION['Username'], get_user_remote_address() . get_user_remote_authsource()));
2032
		}
2033

    
2034
		/* wipe out $_SESSION */
2035
		$_SESSION = array();
2036

    
2037
		if (isset($_COOKIE[session_name()])) {
2038
			setcookie(session_name(), '', time()-42000, '/');
2039
		}
2040

    
2041
		/* and destroy it */
2042
		phpsession_destroy();
2043

    
2044
		$scriptName = explode("/", $_SERVER["SCRIPT_FILENAME"]);
2045
		$scriptElms = count($scriptName);
2046
		$scriptName = $scriptName[$scriptElms-1];
2047

    
2048
		if (isAjax()) {
2049
			return false;
2050
		}
2051

    
2052
		/* redirect to page the user is on, it'll prompt them to login again */
2053
		header("Location: {$scriptName}");
2054

    
2055
		return false;
2056
	}
2057

    
2058
	/*
2059
	 * this is for debugging purpose if you do not want to use Ajax
2060
	 * to submit a HTML form. It basically disables the observation
2061
	 * of the submit event and hence does not trigger Ajax.
2062
	 */
2063
	if ($_REQUEST['disable_ajax']) {
2064
		$_SESSION['NO_AJAX'] = "True";
2065
	}
2066

    
2067
	/*
2068
	 * Same to re-enable Ajax.
2069
	 */
2070
	if ($_REQUEST['enable_ajax']) {
2071
		unset($_SESSION['NO_AJAX']);
2072
	}
2073
	phpsession_end(true);
2074
	return true;
2075
}
2076

    
2077
function print_credit() {
2078
	global $g;
2079

    
2080
	return  '<a target="_blank" href="https://pfsense.org">' . $g["product_name"] . '</a>' .
2081
			gettext(' is developed and maintained by ') .
2082
			'<a target="_blank" href="https://netgate.com">Netgate. </a>' . ' &copy; ESF ' . $g["product_copyright_years"] .
2083
			'<a target="_blank" href="https://pfsense.org/license">' .
2084
			gettext(' View license.') . '</a>';
2085
}
2086
function get_user_remote_address() {
2087
	$remote_address = $_SERVER['REMOTE_ADDR'];
2088
	if (!empty($_SERVER['HTTP_CLIENT_IP'])) {
2089
		$remote_address .= "[{$_SERVER['HTTP_CLIENT_IP']}]";
2090
	} elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
2091
		$remote_address .= "[{$_SERVER['HTTP_X_FORWARDED_FOR']}]";
2092
	}
2093
	return $remote_address;
2094
}
2095
function get_user_remote_authsource() {
2096
	$authsource = "";
2097
	if (!empty($_SESSION['authsource'])) {
2098
		$authsource .= " ({$_SESSION['authsource']})";
2099
	}
2100
	return $authsource;
2101
}
2102
?>
(2-2/60)