Project

General

Profile

Download (73 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-2013 BSD Perimeter
10
 * Copyright (c) 2013-2016 Electric Sheep Fencing
11
 * Copyright (c) 2014-2022 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
/*
28
 * NOTE : Portions of the mschapv2 support was based on the BSD licensed CHAP.php
29
 * file courtesy of Michael Retterklieber.
30
 */
31
require_once("config.lib.inc");
32
include_once('phpsessionmanager.inc');
33
if (!$do_not_include_config_gui_inc) {
34
	require_once("config.gui.inc");
35
}
36

    
37
// Will be changed to false if security checks fail
38
$security_passed = true;
39

    
40
/* Possible user password hash types.
41
 * See https://redmine.pfsense.org/issues/12855
42
 */
43
global $auth_password_hash_types;
44
$auth_password_hash_types = array(
45
	'bcrypt' => gettext('bcrypt -- Blowfish-based crypt'),
46
	'sha512' => gettext('SHA-512 -- SHA-512-based crypt')
47
);
48

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

    
55
	/* Fetch the contents of the lockout table. */
56
	$entries = array();
57
	exec("/sbin/pfctl -t 'sshguard' -T show", $entries);
58

    
59
	/* If the client is in the lockout table, print an error, kill states, and exit */
60
	if (in_array($_SERVER['REMOTE_ADDR'], array_map('trim', $entries))) {
61
		if (!security_checks_disabled()) {
62
			/* They may never see the error since the connection will be cut off, but try to be nice anyhow. */
63
			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."));
64
			/* If they are locked out, they shouldn't have a state. Disconnect their connections. */
65
			$retval = pfSense_kill_states(utf8_encode($_SERVER['REMOTE_ADDR']));
66
			if (is_ipaddrv4($_SERVER['REMOTE_ADDR'])) {
67
				$retval = pfSense_kill_states("0.0.0.0/0", utf8_encode($_SERVER['REMOTE_ADDR']));
68
			} elseif (is_ipaddrv6($_SERVER['REMOTE_ADDR'])) {
69
				$retval = pfSense_kill_states("::", utf8_encode($_SERVER['REMOTE_ADDR']));
70
			}
71
			exit;
72
		}
73
		$security_passed = false;
74
	}
75
}
76

    
77
if (function_exists("display_error_form") && !config_path_enabled('system/webgui', 'nodnsrebindcheck')) {
78
	/* DNS ReBinding attack prevention.  https://redmine.pfsense.org/issues/708 */
79
	$found_host = false;
80

    
81
	/* Either a IPv6 address with or without a alternate port */
82
	if (strstr($_SERVER['HTTP_HOST'], "]")) {
83
		$http_host_port = explode("]", $_SERVER['HTTP_HOST']);
84
		/* v6 address has more parts, drop the last part */
85
		if (count($http_host_port) > 1) {
86
			array_pop($http_host_port);
87
			$http_host = str_replace(array("[", "]"), "", implode(":", $http_host_port));
88
		} else {
89
			$http_host = str_replace(array("[", "]"), "", implode(":", $http_host_port));
90
		}
91
	} else {
92
		$http_host = explode(":", $_SERVER['HTTP_HOST']);
93
		$http_host = $http_host[0];
94
	}
95
	if (is_ipaddr($http_host) or $_SERVER['SERVER_ADDR'] == "127.0.0.1" or
96
		strcasecmp($http_host, "localhost") == 0 or $_SERVER['SERVER_ADDR'] == "::1") {
97
		$found_host = true;
98
	}
99
	if (strcasecmp($http_host, config_get_path('system/hostname') . "." . config_get_path('system/domain')) == 0 or
100
		strcasecmp($http_host, config_get_path('system/hostname')) == 0) {
101
		$found_host = true;
102
	}
103

    
104
	if (!$found_host) {
105
		foreach (config_get_path('dyndnses/dyndns', []) as $dyndns) {
106
			if (!is_array($dyndns) || empty($dyndns)) {
107
				continue;
108
			}
109
			if (strcasecmp($dyndns['host'], $http_host) == 0) {
110
				$found_host = true;
111
				break;
112
			}
113
		}
114
	}
115

    
116
	if (!$found_host) {
117
		foreach (config_get_path('dnsupdates/dnsupdate', []) as $rfc2136) {
118
			if (!is_array($rfc2136) || empty($rfc2136)) {
119
				continue;
120
			}
121
			if (strcasecmp($rfc2136['host'], $http_host) == 0) {
122
				$found_host = true;
123
				break;
124
			}
125
		}
126
	}
127

    
128
	if (!$found_host) {
129
		$althosts = explode(" ", config_get_path('system/webgui/althostnames', ""));
130
		foreach ($althosts as $ah) {
131
			if (strcasecmp($ah, $http_host) == 0 or strcasecmp($ah, $_SERVER['SERVER_ADDR']) == 0) {
132
				$found_host = true;
133
				break;
134
			}
135
		}
136
	}
137

    
138
	if ($found_host == false) {
139
		if (!security_checks_disabled()) {
140
			display_error_form("501", gettext("Potential DNS Rebind attack detected, see https://en.wikipedia.org/wiki/DNS_rebinding<br />Try accessing the router by IP address instead of by hostname."));
141
			exit;
142
		}
143
		$security_passed = false;
144
	}
145
}
146

    
147
// If the HTTP_REFERER is something other than ourselves then disallow.
148
if (function_exists("display_error_form") && !config_path_enabled('system/webgui', 'nohttpreferercheck')) {
149
	if ($_SERVER['HTTP_REFERER']) {
150
		if (file_exists("{$g['tmp_path']}/setupwizard_lastreferrer")) {
151
			if ($_SERVER['HTTP_REFERER'] == file_get_contents("{$g['tmp_path']}/setupwizard_lastreferrer")) {
152
				unlink("{$g['tmp_path']}/setupwizard_lastreferrer");
153
				header("Refresh: 1; url=index.php");
154
?>
155
<!DOCTYPE html>
156
<html lang="en">
157
<head>
158
	<link rel="stylesheet" href="/css/pfSense.css" />
159
	<title><?=gettext("Redirecting..."); ?></title>
160
</head>
161
<body id="error" class="no-menu">
162
	<div id="jumbotron">
163
		<div class="container">
164
			<div class="col-sm-offset-3 col-sm-6 col-xs-12">
165
				<p><?=gettext("Redirecting to the dashboard...")?></p>
166
			</div>
167
		</div>
168
	</div>
169
</body>
170
</html>
171
<?php
172
				exit;
173
			}
174
		}
175
		$found_host = false;
176
		$referrer_host = parse_url($_SERVER['HTTP_REFERER'], PHP_URL_HOST);
177
		$referrer_host = str_replace(array("[", "]"), "", $referrer_host);
178
		if ($referrer_host) {
179
			if (strcasecmp($referrer_host, config_get_path('system/hostname') . "." . config_get_path('system/domain')) == 0 ||
180
			    strcasecmp($referrer_host, config_get_path('system/hostname')) == 0) {
181
				$found_host = true;
182
			}
183

    
184
			if (!$found_host) {
185
				$althosts = explode(" ", config_get_path('system/webgui/althostnames', ""));
186
				foreach ($althosts as $ah) {
187
					if (strcasecmp($referrer_host, $ah) == 0) {
188
						$found_host = true;
189
						break;
190
					}
191
				}
192
			}
193

    
194
			if (!$found_host) {
195
				foreach (config_get_path('dyndnses/dyndns', []) as $dyndns) {
196
					if (!is_array($dyndns) || empty($dyndns)) {
197
						continue;
198
					}
199
					if (strcasecmp($dyndns['host'], $referrer_host) == 0) {
200
						$found_host = true;
201
						break;
202
					}
203
				}
204
			}
205

    
206
			if (!$found_host) {
207
				foreach (config_get_path('dnsupdates/dnsupdate', []) as $rfc2136) {
208
					if (!is_array($rfc2136) || empty($rfc2136)) {
209
						continue;
210
					}
211
					if (strcasecmp($rfc2136['host'], $referrer_host) == 0) {
212
						$found_host = true;
213
						break;
214
					}
215
				}
216
			}
217

    
218
			if (!$found_host) {
219
				$interface_list_ips = get_configured_ip_addresses();
220
				foreach ($interface_list_ips as $ilips) {
221
					if (strcasecmp($referrer_host, $ilips) == 0) {
222
						$found_host = true;
223
						break;
224
					}
225
				}
226
				$interface_list_ipv6s = get_configured_ipv6_addresses(true);
227
				foreach ($interface_list_ipv6s as $ilipv6s) {
228
					$ilipv6s = explode('%', $ilipv6s)[0];
229
					if (strcasecmp($referrer_host, $ilipv6s) == 0) {
230
						$found_host = true;
231
						break;
232
					}
233
				}
234
				if ($referrer_host == "127.0.0.1" || $referrer_host == "localhost") {
235
					// allow SSH port forwarded connections and links from localhost
236
					$found_host = true;
237
				}
238
			}
239

    
240
			/* Fall back to probing active interface addresses rather than config.xml to allow
241
			 * changed addresses that have not yet been applied.
242
			 * See https://redmine.pfsense.org/issues/8822
243
			 */
244
			if (!$found_host) {
245
				$refifs = get_interface_arr();
246
				foreach ($refifs as $rif) {
247
					if (($referrer_host == find_interface_ip($rif)) ||
248
					    ($referrer_host == find_interface_ipv6($rif)) ||
249
					    ($referrer_host == find_interface_ipv6_ll($rif))) {
250
						$found_host = true;
251
						break;
252
					}
253
				}
254
			}
255
		}
256
		if ($found_host == false) {
257
			if (!security_checks_disabled()) {
258
				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 Access.");
259
				exit;
260
			}
261
			$security_passed = false;
262
		}
263
	} else {
264
		$security_passed = false;
265
	}
266
}
267

    
268
if (function_exists("display_error_form") && $security_passed) {
269
	/* Security checks passed, so it should be OK to turn them back on */
270
	restore_security_checks();
271
}
272
unset($security_passed);
273

    
274
$groupindex = index_groups();
275
$userindex = index_users();
276

    
277
function index_groups() {
278
	global $g, $debug, $groupindex;
279

    
280
	$groupindex = array();
281

    
282
	$i = 0;
283
	foreach (config_get_path('system/group', []) as $groupent) {
284
		$groupindex[$groupent['name']] = $i;
285
		$i++;
286
	}
287

    
288
	return ($groupindex);
289
}
290

    
291
function index_users() {
292
	$i = 0;
293
	foreach (config_get_path('system/user', []) as $userent) {
294
		$userindex[$userent['name']] = $i;
295
		$i++;
296
	}
297

    
298
	return ($userindex);
299
}
300

    
301
function & getUserEntry($name) {
302
	global $debug, $config, $userindex;
303
	$authcfg = auth_get_authserver($config['system']['webgui']['authmode']);
304

    
305
	if (isset($userindex[$name])) {
306
		return $config['system']['user'][$userindex[$name]];
307
	} elseif ($authcfg['type'] != "Local Database") {
308
		$user = array();
309
		$user['name'] = $name;
310
		return $user;
311
	}
312
}
313

    
314
function & getUserEntryByUID($uid) {
315
	global $debug, $config;
316

    
317
	if (is_array($config['system']['user'])) {
318
		foreach ($config['system']['user'] as & $user) {
319
			if ($user['uid'] == $uid) {
320
				return $user;
321
			}
322
		}
323
	}
324

    
325
	return false;
326
}
327

    
328
function & getGroupEntry($name) {
329
	global $debug, $config, $groupindex;
330
	if (isset($groupindex[$name])) {
331
		return $config['system']['group'][$groupindex[$name]];
332
	}
333
}
334

    
335
function & getGroupEntryByGID($gid) {
336
	global $debug, $config;
337

    
338
	if (is_array($config['system']['group'])) {
339
		foreach ($config['system']['group'] as & $group) {
340
			if ($group['gid'] == $gid) {
341
				return $group;
342
			}
343
		}
344
	}
345

    
346
	return false;
347
}
348

    
349
function get_user_privileges(& $user) {
350
	global $_SESSION;
351

    
352
	$authcfg = auth_get_authserver(config_get_path('system/webgui/authmode'));
353
	$allowed_groups = array();
354

    
355
	$privs = $user['priv'];
356
	if (!is_array($privs)) {
357
		$privs = array();
358
	}
359

    
360
	// cache auth results for a short time to ease load on auth services & logs
361
	$recheck_time = config_get_path('system/webgui/auth_refresh_time', 30);
362

    
363
	if ($authcfg['type'] == "ldap") {
364
		if (isset($_SESSION["ldap_allowed_groups"]) &&
365
		    (time() <= $_SESSION["auth_check_time"] + $recheck_time)) {
366
			$allowed_groups = $_SESSION["ldap_allowed_groups"];
367
		} else {
368
			$allowed_groups = @ldap_get_groups($user['name'], $authcfg);
369
			$_SESSION["ldap_allowed_groups"] = $allowed_groups;
370
			$_SESSION["auth_check_time"] = time();
371
		}
372
	} elseif ($authcfg['type'] == "radius") {
373
		if (isset($_SESSION["radius_allowed_groups"]) &&
374
		    (time() <= $_SESSION["auth_check_time"] + $recheck_time)) {
375
			$allowed_groups = $_SESSION["radius_allowed_groups"];
376
		} else {
377
			$allowed_groups = @radius_get_groups($_SESSION['user_radius_attributes']);
378
			$_SESSION["radius_allowed_groups"] = $allowed_groups;
379
			$_SESSION["auth_check_time"] = time();
380
		}
381
	}
382

    
383
	if (empty($allowed_groups)) {
384
		$allowed_groups = local_user_get_groups($user, true);
385
	}
386

    
387
	if (!is_array($allowed_groups)) {
388
		$allowed_groups = array('all');
389
	} else {
390
		$allowed_groups[] = 'all';
391
	}
392

    
393
	foreach ($allowed_groups as $name) {
394
		$group = getGroupEntry($name);
395
		if (is_array($group['priv'])) {
396
			$privs = array_merge($privs, $group['priv']);
397
		}
398
	}
399

    
400
	return $privs;
401
}
402

    
403
function userHasPrivilege($userent, $privid = false) {
404
	if (!$privid || !is_array($userent)) {
405
		return false;
406
	}
407

    
408
	$privs = get_user_privileges($userent);
409

    
410
	if (!is_array($privs)) {
411
		return false;
412
	}
413

    
414
	if (!in_array($privid, $privs)) {
415
		return false;
416
	}
417

    
418
	/* If someone is in admins group or is admin, do not honor the
419
	 * user-config-readonly privilege to prevent foot-shooting due to a
420
	 * bad privilege config.
421
	 * https://redmine.pfsense.org/issues/10492 */
422
	$userGroups = getUserGroups($userent['name'],
423
			auth_get_authserver(config_get_path('system/webgui/authmode')),
424
			$_SESSION['user_radius_attributes']);
425
	if (($privid == 'user-config-readonly') &&
426
	    (($userent['uid'] === "0") || (in_array('admins', $userGroups)))) {
427
		return false;
428
	}
429

    
430
	return true;
431
}
432

    
433
function local_backed($username, $passwd) {
434

    
435
	$user = getUserEntry($username);
436
	if (!$user) {
437
		return false;
438
	}
439

    
440
	if (is_account_disabled($username) || is_account_expired($username)) {
441
		return false;
442
	}
443

    
444
	if ($user['bcrypt-hash']) {
445
		if (password_verify($passwd, $user['bcrypt-hash'])) {
446
			return true;
447
		}
448
	}
449

    
450
	if ($user['sha512-hash']) {
451
		if (hash_equals($user['sha512-hash'], crypt($passwd, $user['sha512-hash']))) {
452
			return true;
453
		}
454
	}
455

    
456
	// pfSense < 2.3 password hashing, see https://redmine.pfsense.org/issues/4120
457
	if ($user['password']) {
458
		if (hash_equals($user['password'], crypt($passwd, $user['password']))) {
459
			return true;
460
		}
461
	}
462

    
463
	if ($user['md5-hash']) {
464
		if (hash_equals($user['md5-hash'], md5($passwd))) {
465
			return true;
466
		}
467
	}
468

    
469
	return false;
470
}
471

    
472
function local_sync_accounts($u2add, $u2del, $g2add, $g2del) {
473
	global $debug;
474

    
475
	if (empty($u2add) && empty($u2del) && empty($g2add) && empty($g2del)) {
476
		/* Nothing to be done here */
477
		return;
478
	}
479
	$users = config_get_path('system/user', []);
480
	$groups = config_get_path('system/group', []);
481

    
482
	foreach($u2del as $user) {
483
		if ($user['uid'] > 65000) {
484
			continue;
485
		} else if ($user['uid'] < 2000 && !in_array($user, $u2add)) {
486
			continue;
487
		}
488
		/* Don't remove /root */
489
		if ($user['uid'] != 0) {
490
			$rmhome = escapeshellarg('-r');
491
		} else {
492
			$rmhome = '';
493
		}
494

    
495
		/*
496
		 * If a crontab was created to user, pw userdel will be
497
		 * interactive and can cause issues. Just remove crontab
498
		 * before run it when necessary
499
		 */
500
		unlink_if_exists("/var/cron/tabs/{$user['name']}");
501
		$cmd = "/usr/sbin/pw userdel -n " . escapeshellarg($user['name']) . " " . $rmhome;
502
		if ($debug) {
503
			log_error(sprintf(gettext("Running: %s"), $cmd));
504
		}
505
		mwexec($cmd);
506
		local_group_del_user($user);
507

    
508
		for ($i = 0; $i < count($users); $i++) {
509
			if ($users[$i]['name'] == $user['name']) {
510
				log_error("Removing user: {$user['name']}");
511
				unset($users[$i]);
512
				break;
513
			}
514
		}
515
	}
516

    
517
	foreach($g2del as $group) {
518
		if ($group['gid'] < 1999 || $group['gid'] > 65000) {
519
			continue;
520
		}
521

    
522
		$cmd = "/usr/sbin/pw groupdel -g " .
523
		    escapeshellarg($group['name']);
524
		if ($debug) {
525
			log_error(sprintf(gettext("Running: %s"), $cmd));
526
		}
527
		mwexec($cmd);
528

    
529
		for ($i = 0; $i < count($groups); $i++) {
530
			if ($groups[$i]['name'] == $group['name']) {
531
				log_error("Removing group: {$group['name']}");
532
				unset($groups[$i]);
533
				break;
534
			}
535
		}
536
	}
537

    
538
	foreach ($u2add as $user) {
539
		log_error("Adding user: {$user['name']}");
540

    
541
		$users[] = $user;
542
	}
543

    
544
	foreach ($g2add as $group) {
545
		log_error("Adding group: {$group['name']}");
546
		$groups[] = $group;
547
	}
548

    
549
	/* Sort it alphabetically */
550
	usort($users, function($a, $b) {
551
		return strcmp($a['name'], $b['name']);
552
	});
553
	usort($groups, function($a, $b) {
554
		return strcmp($a['name'], $b['name']);
555
	});
556

    
557
	config_set_path('system/user', $users);
558
	config_set_path('system/group', $groups);
559
	write_config("Sync'd users and groups via XMLRPC");
560

    
561
	/* make sure the all group exists */
562
	$allgrp = getGroupEntryByGID(1998);
563
	local_group_set($allgrp, true);
564

    
565
	foreach ($u2add as $user) {
566
		local_user_set($user);
567
	}
568

    
569
	foreach ($g2add as $group) {
570
		local_group_set($group);
571
	}
572
}
573

    
574
function local_reset_accounts() {
575
	global $debug;
576

    
577
	/* remove local users to avoid uid conflicts */
578
	$fd = popen("/usr/sbin/pw usershow -a", "r");
579
	if ($fd) {
580
		while (!feof($fd)) {
581
			$line = explode(":", fgets($fd));
582
			if ($line[0] != "admin") {
583
				if (!strncmp($line[0], "_", 1)) {
584
					continue;
585
				}
586
				if ($line[2] < 2000) {
587
					continue;
588
				}
589
				if ($line[2] > 65000) {
590
					continue;
591
				}
592
			}
593
			/*
594
			 * If a crontab was created to user, pw userdel will be interactive and
595
			 * can cause issues. Just remove crontab before run it when necessary
596
			 */
597
			unlink_if_exists("/var/cron/tabs/{$line[0]}");
598
			$cmd = "/usr/sbin/pw userdel -n " . escapeshellarg($line[0]);
599
			if ($debug) {
600
				log_error(sprintf(gettext("Running: %s"), $cmd));
601
			}
602
			mwexec($cmd);
603
		}
604
		pclose($fd);
605
	}
606

    
607
	/* remove local groups to avoid gid conflicts */
608
	$gids = array();
609
	$fd = popen("/usr/sbin/pw groupshow -a", "r");
610
	if ($fd) {
611
		while (!feof($fd)) {
612
			$line = explode(":", fgets($fd));
613
			if (!strncmp($line[0], "_", 1)) {
614
				continue;
615
			}
616
			if ($line[2] < 2000) {
617
				continue;
618
			}
619
			if ($line[2] > 65000) {
620
				continue;
621
			}
622
			$cmd = "/usr/sbin/pw groupdel -g " . escapeshellarg($line[2]);
623
			if ($debug) {
624
				log_error(sprintf(gettext("Running: %s"), $cmd));
625
			}
626
			mwexec($cmd);
627
		}
628
		pclose($fd);
629
	}
630

    
631
	/* make sure the all group exists */
632
	$allgrp = getGroupEntryByGID(1998);
633
	local_group_set($allgrp, true);
634

    
635
	/* sync all local users */
636
	foreach (config_get_path('system/user', []) as $user) {
637
		local_user_set($user);
638
	}
639

    
640
	/* sync all local groups */
641
	foreach (config_get_path('system/group', []) as $group) {
642
		local_group_set($group);
643
	}
644
}
645

    
646
function local_user_set(& $user) {
647
	global $g, $debug;
648

    
649
	if (empty($user['sha512-hash']) && empty($user['bcrypt-hash']) && empty($user['password'])) {
650
		log_error("There is something wrong in the config because user {$user['name']} password is missing!");
651
		return;
652
	}
653

    
654

    
655
	$home_base = "/home/";
656
	$user_uid = $user['uid'];
657
	$user_name = $user['name'];
658
	$user_home = "{$home_base}{$user_name}";
659
	$user_shell = "/etc/rc.initial";
660
	$user_group = "nobody";
661

    
662
	// Ensure $home_base exists and is writable
663
	if (!is_dir($home_base)) {
664
		mkdir($home_base, 0755);
665
	}
666

    
667
	$lock_account = false;
668
	/* configure shell type */
669
	/* Cases here should be ordered by most privileged to least privileged. */
670
	if (userHasPrivilege($user, "user-shell-access") || userHasPrivilege($user, "page-all")) {
671
		$user_shell = "/bin/tcsh";
672
		$shell_access = true;
673
	} elseif (userHasPrivilege($user, "user-copy-files-chroot")) {
674
		$user_shell = "/usr/local/sbin/scponlyc";
675
	} elseif (userHasPrivilege($user, "user-copy-files")) {
676
		$user_shell = "/usr/local/bin/scponly";
677
	} elseif (userHasPrivilege($user, "user-ssh-tunnel")) {
678
		$user_shell = "/usr/local/sbin/ssh_tunnel_shell";
679
	} elseif (userHasPrivilege($user, "user-ipsec-xauth-dialin")) {
680
		$user_shell = "/sbin/nologin";
681
	} else {
682
		$user_shell = "/sbin/nologin";
683
		$lock_account = true;
684
	}
685

    
686
	/* Lock out disabled or expired users, unless it's root/admin. */
687
	if ((is_account_disabled($user_name) || is_account_expired($user_name)) && ($user_uid != 0)) {
688
		$user_shell = "/sbin/nologin";
689
		$lock_account = true;
690
	}
691

    
692
	/* root user special handling */
693
	if ($user_uid == 0) {
694
		$cmd = "/usr/sbin/pw usermod -q -n root -s /bin/sh -H 0";
695
		if ($debug) {
696
			log_error(sprintf(gettext("Running: %s"), $cmd));
697
		}
698
		$fd = popen($cmd, "w");
699
		if (isset($user['bcrypt-hash'])) {
700
			fwrite($fd, $user['bcrypt-hash']);
701
		} elseif (isset($user['sha512-hash'])) {
702
			fwrite($fd, $user['sha512-hash']);
703
		} else {
704
			fwrite($fd, $user['password']);
705
		}
706
		pclose($fd);
707
		$user_group = "wheel";
708
		$user_home = "/root";
709
		$user_shell = "/etc/rc.initial";
710
		$shell_access = true;
711
	}
712

    
713
	/* read from pw db */
714
	$fd = popen("/usr/sbin/pw usershow -n {$user_name} 2>&1", "r");
715
	$pwread = fgets($fd);
716
	pclose($fd);
717
	$userattrs = explode(":", trim($pwread));
718

    
719
	$skel_dir = '/etc/skel';
720

    
721
	/* determine add or mod */
722
	if (($userattrs[0] != $user['name']) || (!strncmp($pwread, "pw:", 3))) {
723
		$user_op = "useradd -m -k " . escapeshellarg($skel_dir) . " -o";
724
	} else {
725
		$user_op = "usermod";
726
	}
727

    
728
	$comment = str_replace(array(":", "!", "@"), " ", $user['descr']);
729
	/* add or mod pw db */
730
	$cmd = "/usr/sbin/pw {$user_op} -q " .
731
			" -u " . escapeshellarg($user_uid) .
732
			" -n " . escapeshellarg($user_name) .
733
			" -g " . escapeshellarg($user_group) .
734
			" -s " . escapeshellarg($user_shell) .
735
			" -d " . escapeshellarg($user_home) .
736
			" -c " . escapeshellarg($comment) .
737
			" -H 0 2>&1";
738

    
739
	if ($debug) {
740
		log_error(sprintf(gettext("Running: %s"), $cmd));
741
	}
742
	$fd = popen($cmd, "w");
743
	if (isset($user['bcrypt-hash'])) {
744
		fwrite($fd, $user['bcrypt-hash']);
745
	} elseif (isset($user['sha512-hash'])) {
746
		fwrite($fd, $user['sha512-hash']);
747
	} else {
748
		fwrite($fd, $user['password']);
749
	}
750
	pclose($fd);
751

    
752
	/* create user directory if required */
753
	if (!is_dir($user_home)) {
754
		mkdir($user_home, 0700);
755
	}
756
	@chown($user_home, $user_name);
757
	@chgrp($user_home, $user_group);
758

    
759
	/* Make sure all users have last version of config files */
760
	foreach (glob("{$skel_dir}/dot.*") as $dot_file) {
761
		$target = $user_home . '/' . substr(basename($dot_file), 3);
762
		@copy($dot_file, $target);
763
		@chown($target, $user_name);
764
		@chgrp($target, $user_group);
765
	}
766

    
767
	/* write out ssh authorized key file */
768
	$sshdir = "{$user_home}/.ssh";
769
	if ($user['authorizedkeys']) {
770
		if (!is_dir("{$user_home}/.ssh")) {
771
			@mkdir($sshdir, 0700);
772
			@chown($sshdir, $user_name);
773
		} elseif (file_exists($sshdir) && (fileowner($sshdir) != $user['uid'])) {
774
			@chown($sshdir, $user_name);
775
			@chown("{$sshdir}/*", $user_name);
776
		}
777
		$keys = base64_decode($user['authorizedkeys']);
778
		@file_put_contents("{$user_home}/.ssh/authorized_keys", $keys);
779
		@chown("{$user_home}/.ssh/authorized_keys", $user_name);
780
	} else {
781
		unlink_if_exists("{$user_home}/.ssh/authorized_keys");
782
	}
783

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

    
787
}
788

    
789
function local_user_del($user) {
790
	global $debug;
791

    
792
	/* Don't remove /root */
793
	if ($user['uid'] != 0) {
794
		$rmhome = "-r";
795
	}
796

    
797
	/* read from pw db */
798
	$fd = popen("/usr/sbin/pw usershow -n {$user['name']} 2>&1", "r");
799
	$pwread = fgets($fd);
800
	pclose($fd);
801
	$userattrs = explode(":", trim($pwread));
802

    
803
	if ($userattrs[0] != $user['name']) {
804
		log_error("Tried to remove user {$user['name']} but got user {$userattrs[0]} instead. Bailing.");
805
		return;
806
	}
807

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

    
811
	if ($debug) {
812
		log_error(sprintf(gettext("Running: %s"), $cmd));
813
	}
814
	mwexec($cmd);
815

    
816
	/* Delete user from groups needs a call to write_config() */
817
	local_group_del_user($user);
818
}
819

    
820
function local_user_set_password(&$user, $password) {
821
	unset($user['password']);
822
	unset($user['md5-hash']);
823
	unset($user['sha512-hash']);
824
	unset($user['bcrypt-hash']);
825

    
826
	/* Default to bcrypt hashing if unset.
827
	 * See https://redmine.pfsense.org/issues/12855
828
	 */
829
	$hashalgo = config_get_path('system/webgui/pwhash', 'bcrypt');
830

    
831
	switch ($hashalgo) {
832
		case 'sha512':
833
			$salt = substr(bin2hex(random_bytes(16)),0,16);
834
			$user['sha512-hash'] = crypt($password, '$6$'. $salt . '$');
835
			break;
836
		case 'bcrypt':
837
		default:
838
			$user['bcrypt-hash'] = password_hash($password, PASSWORD_BCRYPT);
839
			break;
840
	}
841

    
842
	if (($user['name'] == config_get_path('hasync/username')) &&
843
	    (config_get_path('hasync/adminsync') == 'on')) {
844
		config_set_path('hasync/new_password', $password);
845
	}
846
}
847

    
848
function local_user_get_groups($user, $all = false) {
849
	$sysgroups = config_get_path('system/group', []);
850
	$groups = [];
851
	if(empty($sysgroups)) {
852
		return $groups;
853
	}
854

    
855
	foreach ($sysgroups as $group) {
856
		if ($all || (!$all && ($group['name'] != "all"))) {
857
			if (is_array($group['member'])) {
858
				if (in_array($user['uid'], $group['member'])) {
859
					$groups[] = $group['name'];
860
				}
861
			}
862
		}
863
	}
864

    
865
	if ($all) {
866
		$groups[] = "all";
867
	}
868

    
869
	sort($groups);
870

    
871
	return $groups;
872

    
873
}
874

    
875
function local_user_set_groups($user, $new_groups = NULL) {
876
	global $debug, $groupindex, $userindex;
877

    
878
	$groups = config_get_path('system/group', []);
879
	if (empty($groups)) {
880
		return;
881
	}
882

    
883
	$cur_groups = local_user_get_groups($user, true);
884
	$mod_groups = array();
885

    
886
	if (!is_array($new_groups)) {
887
		$new_groups = array();
888
	}
889

    
890
	if (!is_array($cur_groups)) {
891
		$cur_groups = array();
892
	}
893

    
894
	/* determine which memberships to add */
895
	foreach ($new_groups as $groupname) {
896
		if ($groupname == '' || in_array($groupname, $cur_groups)) {
897
			continue;
898
		}
899
		$group = &$groups[$groupindex[$groupname]];
900
		$group['member'][] = $user['uid'];
901
		$mod_groups[] = $group;
902

    
903
		/*
904
		 * If it's a new user, make sure it is added before try to
905
		 * add it as a member of a group
906
		 */
907
		if (!isset($userindex[$user['uid']])) {
908
			local_user_set($user);
909
		}
910
	}
911

    
912
	/* determine which memberships to remove */
913
	foreach ($cur_groups as $groupname) {
914
		if (in_array($groupname, $new_groups)) {
915
			continue;
916
		}
917
		if (!isset($groups[$groupindex[$groupname]])) {
918
			continue;
919
		}
920
		$group = &$groups[$groupindex[$groupname]];
921
		if (is_array($group['member'])) {
922
			$index = array_search($user['uid'], $group['member']);
923
			array_splice($group['member'], $index, 1);
924
			$mod_groups[] = $group;
925
		}
926
	}
927

    
928
	config_set_path('system/group', $groups);
929

    
930
	/* sync all modified groups */
931
	foreach ($mod_groups as $group) {
932
		local_group_set($group);
933
	}
934
}
935

    
936
function local_group_del_user($user) {
937
	foreach (config_get_path('system/group', []) as $gid => $group) {
938
		foreach (array_get_path($group, 'member', []) as $idx => $uid) {
939
			if ($user['uid'] == $uid) {
940
				config_del_path("system/group/{$gid}/member/{$idx}");
941
				break;
942
			}
943
		}
944
	}
945
}
946

    
947
function local_group_set($group, $reset = false) {
948
	global $debug;
949

    
950
	$group_name = $group['name'];
951
	$group_gid = $group['gid'];
952
	$group_members = '';
953

    
954
	if (!$reset && !empty($group['member']) && count($group['member']) > 0) {
955
		$group_members = implode(",", $group['member']);
956
	}
957

    
958
	if (empty($group_name)) {
959
		return;
960
	}
961

    
962
	// If the group is now remote, make sure there is no local group with the same name
963
	if ($group['scope'] == "remote") {
964
		local_group_del($group);
965
		return;
966
	}
967

    
968
	/* determine add or mod */
969
	if (mwexec("/usr/sbin/pw groupshow -g " . escapeshellarg($group_gid) . " 2>&1", true) == 0) {
970
		$group_op = "groupmod -l";
971
	} else {
972
		$group_op = "groupadd -n";
973
	}
974

    
975
	/* add or mod group db */
976
	$cmd = "/usr/sbin/pw {$group_op} " .
977
		escapeshellarg($group_name) .
978
		" -g " . escapeshellarg($group_gid) .
979
		" -M " . escapeshellarg($group_members) . " 2>&1";
980

    
981
	if ($debug) {
982
		log_error(sprintf(gettext("Running: %s"), $cmd));
983
	}
984

    
985
	mwexec($cmd);
986
}
987

    
988
function local_group_del($group) {
989
	global $debug;
990

    
991
	/* delete from group db */
992
	$cmd = "/usr/sbin/pw groupdel " . escapeshellarg($group['name']);
993

    
994
	if ($debug) {
995
		log_error(sprintf(gettext("Running: %s"), $cmd));
996
	}
997
	mwexec($cmd);
998
}
999

    
1000
function ldap_test_connection($authcfg) {
1001
	if ($authcfg) {
1002
		if (strstr($authcfg['ldap_urltype'], "SSL")) {
1003
			$ldapproto = "ldaps";
1004
		} else {
1005
			$ldapproto = "ldap";
1006
		}
1007
		$ldapserver = "{$ldapproto}://" . ldap_format_host($authcfg['host']);
1008
		$ldapport = $authcfg['ldap_port'];
1009
		if (!empty($ldapport)) {
1010
			$ldapserver .= ":{$ldapport}";
1011
		}
1012
	} else {
1013
		return false;
1014
	}
1015

    
1016
	/* first check if there is even an LDAP server populated */
1017
	if (!$ldapserver) {
1018
		return false;
1019
	}
1020

    
1021
	/* connect and see if server is up */
1022
	$error = false;
1023
	if (!($ldap = ldap_connect($ldapserver))) {
1024
		$error = true;
1025
	}
1026

    
1027
	if ($error == true) {
1028
		log_error(sprintf(gettext("ERROR!  Could not connect to server %s."), $authcfg['name']));
1029
		return false;
1030
	}
1031

    
1032
	/* Setup CA environment if needed. */
1033
	ldap_setup_caenv($ldap, $authcfg);
1034

    
1035
	return true;
1036
}
1037

    
1038
function ldap_setup_caenv($ldap, $authcfg) {
1039
	global $g;
1040
	require_once("certs.inc");
1041

    
1042
	unset($caref);
1043
	if (empty($authcfg['ldap_caref']) || strstr($authcfg['ldap_urltype'], "Standard")) {
1044
		ldap_set_option($ldap, LDAP_OPT_X_TLS_REQUIRE_CERT, LDAP_OPT_X_TLS_NEVER);
1045
		return;
1046
	} elseif ($authcfg['ldap_caref'] == "global") {
1047
		ldap_set_option(NULL, LDAP_OPT_X_TLS_CACERTDIR, "/etc/ssl/");
1048
		ldap_set_option(NULL, LDAP_OPT_X_TLS_CACERTFILE, "/etc/ssl/cert.pem");
1049
		ldap_set_option($ldap, LDAP_OPT_X_TLS_REQUIRE_CERT, LDAP_OPT_X_TLS_HARD);
1050
	} else {
1051
		$caref = lookup_ca($authcfg['ldap_caref']);
1052
		$cert_details = openssl_x509_parse(base64_decode($caref['crt']));
1053
		$param = array('caref' => $authcfg['ldap_caref']);
1054
		$cachain = ca_chain($param);
1055
		if (!$caref) {
1056
			log_error(sprintf(gettext("LDAP: Could not lookup CA by reference for host %s."), $authcfg['ldap_caref']));
1057
			/* XXX: Prevent for credential leaking since we cannot setup the CA env. Better way? */
1058
			ldap_set_option($ldap, LDAP_OPT_X_TLS_REQUIRE_CERT, LDAP_OPT_X_TLS_HARD);
1059
			return;
1060
		}
1061

    
1062
		$cert_path = "{$g['varrun_path']}/certs";
1063
		$cert_filename = "{$cert_path}/{$cert_details['hash']}.0";
1064
		safe_mkdir($cert_path);
1065
		unlink_if_exists($cert_filename);
1066
		file_put_contents($cert_filename, $cachain);
1067
		@chmod($cert_filename, 0600);
1068

    
1069
		ldap_set_option($ldap, LDAP_OPT_X_TLS_REQUIRE_CERT, LDAP_OPT_X_TLS_HARD);
1070
		ldap_set_option(NULL, LDAP_OPT_X_TLS_CACERTDIR, $cert_path);
1071
		ldap_set_option(NULL, LDAP_OPT_X_TLS_CACERTFILE, $cert_filename);
1072
	}
1073
}
1074

    
1075
function ldap_test_bind($authcfg) {
1076
	if ($authcfg) {
1077
		if (strstr($authcfg['ldap_urltype'], "SSL")) {
1078
			$ldapproto = "ldaps";
1079
		} else {
1080
			$ldapproto = "ldap";
1081
		}
1082
		$ldapserver = "{$ldapproto}://" . ldap_format_host($authcfg['host']);
1083
		$ldapport = $authcfg['ldap_port'];
1084
		if (!empty($ldapport)) {
1085
			$ldapserver .= ":{$ldapport}";
1086
		}
1087
		$ldapbasedn = $authcfg['ldap_basedn'];
1088
		$ldapbindun = $authcfg['ldap_binddn'];
1089
		$ldapbindpw = $authcfg['ldap_bindpw'];
1090
		$ldapver = $authcfg['ldap_protver'];
1091
		$ldaptimeout = is_numeric($authcfg['ldap_timeout']) ? $authcfg['ldap_timeout'] : 5;
1092
		if (empty($ldapbindun) || empty($ldapbindpw)) {
1093
			$ldapanon = true;
1094
		} else {
1095
			$ldapanon = false;
1096
		}
1097
	} else {
1098
		return false;
1099
	}
1100

    
1101
	/* first check if there is even an LDAP server populated */
1102
	if (!$ldapserver) {
1103
		return false;
1104
	}
1105

    
1106
	/* connect and see if server is up */
1107
	$error = false;
1108
	if (!($ldap = ldap_connect($ldapserver))) {
1109
		$error = true;
1110
	}
1111

    
1112
	if ($error == true) {
1113
		log_error(sprintf(gettext("ERROR!  Could not connect to server %s."), $ldapname));
1114
		return false;
1115
	}
1116

    
1117
	/* Setup CA environment if needed. */
1118
	ldap_setup_caenv($ldap, $authcfg);
1119

    
1120
	ldap_set_option($ldap, LDAP_OPT_REFERRALS, 0);
1121
	ldap_set_option($ldap, LDAP_OPT_DEREF, LDAP_DEREF_SEARCHING);
1122
	ldap_set_option($ldap, LDAP_OPT_PROTOCOL_VERSION, (int)$ldapver);
1123
	ldap_set_option($ldap, LDAP_OPT_TIMELIMIT, (int)$ldaptimeout);
1124
	ldap_set_option($ldap, LDAP_OPT_NETWORK_TIMEOUT, (int)$ldaptimeout);
1125

    
1126
	if (strstr($authcfg['ldap_urltype'], "STARTTLS")) {
1127
		if (!(@ldap_start_tls($ldap))) {
1128
			log_error(sprintf(gettext("ERROR! ldap_test_bind() could not STARTTLS to server %s."), $ldapname));
1129
			@ldap_close($ldap);
1130
			return false;
1131
		}
1132
	}
1133

    
1134
	$ldapbindun = isset($authcfg['ldap_utf8']) ? utf8_encode($ldapbindun) : $ldapbindun;
1135
	$ldapbindpw = isset($authcfg['ldap_utf8']) ? utf8_encode($ldapbindpw) : $ldapbindpw;
1136
	if ($ldapanon == true) {
1137
		if (!($res = @ldap_bind($ldap))) {
1138
			@ldap_close($ldap);
1139
			return false;
1140
		}
1141
	} else if (!($res = @ldap_bind($ldap, $ldapbindun, $ldapbindpw))) {
1142
		@ldap_close($ldap);
1143
		return false;
1144
	}
1145

    
1146
	@ldap_unbind($ldap);
1147

    
1148
	return true;
1149
}
1150

    
1151
function ldap_get_user_ous($show_complete_ou, $authcfg) {
1152
	if (!function_exists("ldap_connect")) {
1153
		return;
1154
	}
1155

    
1156
	$ous = array();
1157

    
1158
	if ($authcfg) {
1159
		if (strstr($authcfg['ldap_urltype'], "SSL")) {
1160
			$ldapproto = "ldaps";
1161
		} else {
1162
			$ldapproto = "ldap";
1163
		}
1164
		$ldapserver = "{$ldapproto}://" . ldap_format_host($authcfg['host']);
1165
		$ldapport = $authcfg['ldap_port'];
1166
		if (!empty($ldapport)) {
1167
			$ldapserver .= ":{$ldapport}";
1168
		}
1169
		$ldapbasedn = $authcfg['ldap_basedn'];
1170
		$ldapbindun = $authcfg['ldap_binddn'];
1171
		$ldapbindpw = $authcfg['ldap_bindpw'];
1172
		$ldapver = $authcfg['ldap_protver'];
1173
		if (empty($ldapbindun) || empty($ldapbindpw)) {
1174
			$ldapanon = true;
1175
		} else {
1176
			$ldapanon = false;
1177
		}
1178
		$ldapname = $authcfg['name'];
1179
		$ldapfallback = false;
1180
		$ldapscope = $authcfg['ldap_scope'];
1181
		$ldaptimeout = is_numeric($authcfg['ldap_timeout']) ? $authcfg['ldap_timeout'] : 5;
1182
	} else {
1183
		return false;
1184
	}
1185

    
1186
	/* first check if there is even an LDAP server populated */
1187
	if (!$ldapserver) {
1188
		log_error(gettext("ERROR!  ldap_get_user_ous() backed selected with no LDAP authentication server defined."));
1189
		return $ous;
1190
	}
1191

    
1192
	/* connect and see if server is up */
1193
	$error = false;
1194
	if (!($ldap = ldap_connect($ldapserver))) {
1195
		$error = true;
1196
	}
1197

    
1198
	if ($error == true) {
1199
		log_error(sprintf(gettext("ERROR!  Could not connect to server %s."), $ldapname));
1200
		return $ous;
1201
	}
1202

    
1203
	/* Setup CA environment if needed. */
1204
	ldap_setup_caenv($ldap, $authcfg);
1205

    
1206
	$ldapfilter = "(|(ou=*)(cn=Users))";
1207

    
1208
	ldap_set_option($ldap, LDAP_OPT_REFERRALS, 0);
1209
	ldap_set_option($ldap, LDAP_OPT_DEREF, LDAP_DEREF_SEARCHING);
1210
	ldap_set_option($ldap, LDAP_OPT_PROTOCOL_VERSION, (int)$ldapver);
1211
	ldap_set_option($ldap, LDAP_OPT_TIMELIMIT, (int)$ldaptimeout);
1212
	ldap_set_option($ldap, LDAP_OPT_NETWORK_TIMEOUT, (int)$ldaptimeout);
1213

    
1214
	if (strstr($authcfg['ldap_urltype'], "STARTTLS")) {
1215
		if (!(@ldap_start_tls($ldap))) {
1216
			log_error(sprintf(gettext("ERROR! ldap_get_user_ous() could not STARTTLS to server %s."), $ldapname));
1217
			@ldap_close($ldap);
1218
			return false;
1219
		}
1220
	}
1221

    
1222
	$ldapbindun = isset($authcfg['ldap_utf8']) ? utf8_encode($ldapbindun) : $ldapbindun;
1223
	$ldapbindpw = isset($authcfg['ldap_utf8']) ? utf8_encode($ldapbindpw) : $ldapbindpw;
1224
	if ($ldapanon == true) {
1225
		if (!($res = @ldap_bind($ldap))) {
1226
			log_error(sprintf(gettext("ERROR! ldap_get_user_ous() could not bind anonymously to server %s."), $ldapname));
1227
			@ldap_close($ldap);
1228
			return $ous;
1229
		}
1230
	} else if (!($res = @ldap_bind($ldap, $ldapbindun, $ldapbindpw))) {
1231
		log_error(sprintf(gettext("ERROR! ldap_get_user_ous() could not bind to server %s."), $ldapname));
1232
		@ldap_close($ldap);
1233
		return $ous;
1234
	}
1235

    
1236
	if ($ldapscope == "one") {
1237
		$ldapfunc = "ldap_list";
1238
	} else {
1239
		$ldapfunc = "ldap_search";
1240
	}
1241

    
1242
	if (!($search = @$ldapfunc($ldap, $ldapbasedn, $ldapfilter))) {
1243
		goto errout;
1244
	}
1245

    
1246
	if (!is_array($info = @ldap_get_entries($ldap, $search))) {
1247
		goto errout;
1248
	}
1249

    
1250
	foreach ($info as $inf) {
1251
		if (!$show_complete_ou) {
1252
			$inf_split = explode(",", $inf['dn']);
1253
			$ou = $inf_split[0];
1254
			$ou = str_replace("OU=", "", $ou);
1255
			$ou = str_replace("CN=", "", $ou);
1256
		} else {
1257
			if ($inf['dn']) {
1258
				$ou = $inf['dn'];
1259
			}
1260
		}
1261
		if ($ou) {
1262
			$ous[] = $ou;
1263
		}
1264
	}
1265

    
1266
errout: // goto to bailout early
1267

    
1268
	@ldap_unbind($ldap);
1269

    
1270
	return $ous;
1271
}
1272

    
1273
function ldap_get_groups($username, $authcfg) {
1274
	if (!function_exists("ldap_connect")) {
1275
		return array();
1276
	}
1277

    
1278
	if (!$username) {
1279
		return array();
1280
	}
1281

    
1282
	if (!isset($authcfg['ldap_nostrip_at']) && stristr($username, "@")) {
1283
		$username_split = explode("@", $username);
1284
		$username = $username_split[0];
1285
	}
1286

    
1287
	if (stristr($username, "\\")) {
1288
		$username_split = explode("\\", $username);
1289
		$username = $username_split[0];
1290
	}
1291

    
1292
	//log_error("Getting LDAP groups for {$username}.");
1293
	if ($authcfg) {
1294
		if (strstr($authcfg['ldap_urltype'], "SSL")) {
1295
			$ldapproto = "ldaps";
1296
		} else {
1297
			$ldapproto = "ldap";
1298
		}
1299
		$ldapserver = "{$ldapproto}://" . ldap_format_host($authcfg['host']);
1300
		$ldapport = $authcfg['ldap_port'];
1301
		if (!empty($ldapport)) {
1302
			$ldapserver .= ":{$ldapport}";
1303
		}
1304
		$ldapbasedn = $authcfg['ldap_basedn'];
1305
		$ldapbindun = $authcfg['ldap_binddn'];
1306
		$ldapbindpw = $authcfg['ldap_bindpw'];
1307
		$ldapauthcont = $authcfg['ldap_authcn'];
1308
		$ldapnameattribute = strtolower($authcfg['ldap_attr_user']);
1309
		$ldapgroupattribute = strtolower($authcfg['ldap_attr_member']);
1310
		$ldapver = $authcfg['ldap_protver'];
1311
		if (empty($ldapbindun) || empty($ldapbindpw)) {
1312
			$ldapanon = true;
1313
		} else {
1314
			$ldapanon = false;
1315
		}
1316
		$ldapname = $authcfg['name'];
1317
		$ldapfallback = false;
1318
		$ldapscope = $authcfg['ldap_scope'];
1319
		$ldaptimeout = is_numeric($authcfg['ldap_timeout']) ? $authcfg['ldap_timeout'] : 5;
1320
	} else {
1321
		return array();
1322
	}
1323

    
1324
	if (isset($authcfg['ldap_rfc2307'])) {
1325
		$ldapdn = $ldapbasedn;
1326
	} else {
1327
		$ldapdn = $_SESSION['ldapdn'];
1328
	}
1329

    
1330
	/*Convert attribute to lowercase.  php ldap arrays put everything in lowercase */
1331
	$ldapgroupattribute = strtolower($ldapgroupattribute);
1332
	$memberof = array();
1333

    
1334
	/* connect and see if server is up */
1335
	$error = false;
1336
	if (!($ldap = ldap_connect($ldapserver))) {
1337
		$error = true;
1338
	}
1339

    
1340
	if ($error == true) {
1341
		log_error(sprintf(gettext("ERROR! ldap_get_groups() Could not connect to server %s."), $ldapname));
1342
		return $memberof;
1343
	}
1344

    
1345
	/* Setup CA environment if needed. */
1346
	ldap_setup_caenv($ldap, $authcfg);
1347

    
1348
	ldap_set_option($ldap, LDAP_OPT_REFERRALS, 0);
1349
	ldap_set_option($ldap, LDAP_OPT_DEREF, LDAP_DEREF_SEARCHING);
1350
	ldap_set_option($ldap, LDAP_OPT_PROTOCOL_VERSION, (int)$ldapver);
1351
	ldap_set_option($ldap, LDAP_OPT_TIMELIMIT, (int)$ldaptimeout);
1352
	ldap_set_option($ldap, LDAP_OPT_NETWORK_TIMEOUT, (int)$ldaptimeout);
1353

    
1354
	if (strstr($authcfg['ldap_urltype'], "STARTTLS")) {
1355
		if (!(@ldap_start_tls($ldap))) {
1356
			log_error(sprintf(gettext("ERROR! ldap_get_groups() could not STARTTLS to server %s."), $ldapname));
1357
			@ldap_close($ldap);
1358
			return array();
1359
		}
1360
	}
1361

    
1362
	/* bind as user that has rights to read group attributes */
1363
	$ldapbindun = isset($authcfg['ldap_utf8']) ? utf8_encode($ldapbindun) : $ldapbindun;
1364
	$ldapbindpw = isset($authcfg['ldap_utf8']) ? utf8_encode($ldapbindpw) : $ldapbindpw;
1365
	if ($ldapanon == true) {
1366
		if (!($res = @ldap_bind($ldap))) {
1367
			log_error(sprintf(gettext("ERROR! ldap_get_groups() could not bind anonymously to server %s."), $ldapname));
1368
			@ldap_close($ldap);
1369
			return array();
1370
		}
1371
	} else if (!($res = @ldap_bind($ldap, $ldapbindun, $ldapbindpw))) {
1372
		log_error(sprintf(gettext("ERROR! ldap_get_groups() could not bind to server %s."), $ldapname));
1373
		@ldap_close($ldap);
1374
		return $memberof;
1375
	}
1376

    
1377
	/* get groups from DN found */
1378
	/* use ldap_read instead of search so we don't have to do a bunch of extra work */
1379
	/* since we know the DN is in $_SESSION['ldapdn'] */
1380
	//$search    = ldap_read($ldap, $ldapdn, "(objectclass=*)", array($ldapgroupattribute));
1381
	if ($ldapscope == "one") {
1382
		$ldapfunc = "ldap_list";
1383
	} else {
1384
		$ldapfunc = "ldap_search";
1385
	}
1386

    
1387
	if (isset($authcfg['ldap_rfc2307'])) {
1388
		if (isset($authcfg['ldap_rfc2307_userdn'])) {
1389
			$has_userinfo = false;
1390
			$ldac_splits = explode(";", $ldapauthcont);
1391
			foreach ($ldac_splits as $i => $ldac_split) {
1392
				$ldac_split = isset($authcfg['ldap_utf8']) ? utf8_encode($ldac_split) : $ldac_split;
1393
				$ldapsearchbasedn = isset($authcfg['ldap_utf8']) ? utf8_encode("{$ldac_split},{$ldapbasedn}") : "{$ldac_split},{$ldapbasedn}";
1394
				$ldapfilter = "({$ldapnameattribute}={$username})";
1395
				if (stristr($ldac_split, "DC=") || empty($ldapbasedn)) {
1396
					$ldapdn = $ldac_split;
1397
				} else {
1398
					$ldapdn = $ldapsearchbasedn;
1399
				}
1400
				if (($usersearch = @$ldapfunc($ldap, $ldapdn, $ldapfilter))) {
1401
					$userinfo = @ldap_get_entries($ldap, $usersearch);
1402
					$has_userinfo = true;
1403
				}
1404
			}
1405
			/* we can bailout early if the above query fails in rfc2307 mode */
1406
			if (!$has_userinfo) {
1407
				goto errout;
1408
			}
1409
			$username = $userinfo[0]['dn'];
1410
		}
1411
		$ldapfilter = "(&(objectClass={$authcfg['ldap_attr_groupobj']})({$ldapgroupattribute}={$username}))";
1412
	} else {
1413
		$ldapfilter = "({$ldapnameattribute}={$username})";
1414
	}
1415

    
1416
	if (!($search = @$ldapfunc($ldap, $ldapdn, $ldapfilter, array($ldapgroupattribute)))) {
1417
		goto errout;
1418
	}
1419

    
1420
	$info = @ldap_get_entries($ldap, $search);
1421
	$gresults = isset($authcfg['ldap_rfc2307']) ? $info : $info[0][$ldapgroupattribute];
1422

    
1423
	if (is_array($gresults)) {
1424
		/* Iterate through the groups and throw them into an array */
1425
		foreach ($gresults as $grp) {
1426
			if (((isset($authcfg['ldap_rfc2307'])) && (stristr($grp["dn"], "CN=") !== false)) ||
1427
			    ((!isset($authcfg['ldap_rfc2307'])) && (stristr($grp, "CN=") !== false))) {
1428
				$grpsplit = isset($authcfg['ldap_rfc2307']) ? explode(",", $grp["dn"]) : explode(",", $grp);
1429
				$memberof[] = preg_replace("/CN=/i", "", $grpsplit[0]);
1430
			}
1431
		}
1432
	}
1433

    
1434
errout: // goto to bailout early
1435

    
1436
	/* Time to close LDAP connection */
1437
	@ldap_unbind($ldap);
1438

    
1439
	$groups = print_r($memberof, true);
1440

    
1441
	return $memberof;
1442
}
1443

    
1444
function ldap_format_host($host) {
1445
	return is_ipaddrv6($host) ? "[$host]" : $host ;
1446
}
1447

    
1448
function ldap_backed($username, $passwd, $authcfg, &$attributes = array()) {
1449
	global $debug;
1450

    
1451
	if (!$username) {
1452
		$attributes['error_message'] = gettext("Invalid Login.");
1453
		return false;
1454
	}
1455

    
1456
	if (!isset($authcfg['ldap_allow_unauthenticated']) && $passwd == '') {
1457
		$attributes['error_message'] = gettext("Invalid credentials.");
1458
		return false;
1459
	}
1460

    
1461
	if (!function_exists("ldap_connect")) {
1462
		log_error(gettext("ERROR! unable to find ldap_connect() function."));
1463
		$attributes['error_message'] = gettext("Internal error during authentication.");
1464
		return null;
1465
	}
1466

    
1467
	if (!isset($authcfg['ldap_nostrip_at']) && stristr($username, "@")) {
1468
		$username_split = explode("@", $username);
1469
		$username = $username_split[0];
1470
	}
1471
	if (stristr($username, "\\")) {
1472
		$username_split = explode("\\", $username);
1473
		$username = $username_split[0];
1474
	}
1475

    
1476
	$username = ldap_escape($username, null, LDAP_ESCAPE_FILTER);
1477

    
1478
	if ($authcfg) {
1479
		if (strstr($authcfg['ldap_urltype'], "SSL")) {
1480
			$ldapproto = "ldaps";
1481
		} else {
1482
			$ldapproto = "ldap";
1483
		}
1484
		$ldapserver = "{$ldapproto}://" . ldap_format_host($authcfg['host']);
1485
		$ldapport = $authcfg['ldap_port'];
1486
		if (!empty($ldapport)) {
1487
			$ldapserver .= ":{$ldapport}";
1488
		}
1489
		$ldapbasedn = $authcfg['ldap_basedn'];
1490
		$ldapbindun = $authcfg['ldap_binddn'];
1491
		$ldapbindpw = $authcfg['ldap_bindpw'];
1492
		if (empty($ldapbindun) || empty($ldapbindpw)) {
1493
			$ldapanon = true;
1494
		} else {
1495
			$ldapanon = false;
1496
		}
1497
		$ldapauthcont = $authcfg['ldap_authcn'];
1498
		$ldapnameattribute = strtolower($authcfg['ldap_attr_user']);
1499
		$ldapgroupattribute = $authcfg['ldap_attr_member'];
1500
		$ldapextendedqueryenabled = $authcfg['ldap_extended_enabled'];
1501
		if ($ldapextendedqueryenabled) {
1502
			$ldapextendedquery = $authcfg['ldap_extended_query'];
1503
		}
1504
		if (!$ldapextendedqueryenabled) {
1505
			$ldapfilter = "({$ldapnameattribute}={$username})";
1506
		} else {
1507
			if (isset($authcfg['ldap_rfc2307'])) {
1508
				$ldapfilter = "({$ldapnameattribute}={$username})";
1509
				$ldapgroupfilter = "(&({$ldapgroupattribute}={$username})({$ldapextendedquery}))";
1510
			} else {
1511
				$ldapfilter = "(&({$ldapnameattribute}={$username})({$ldapextendedquery}))";
1512
			}
1513
		}
1514
		$ldapver = $authcfg['ldap_protver'];
1515
		$ldapname = $authcfg['name'];
1516
		$ldapscope = $authcfg['ldap_scope'];
1517
		$ldaptimeout = is_numeric($authcfg['ldap_timeout']) ? $authcfg['ldap_timeout'] : 5;
1518
	} else {
1519
		return null;
1520
	}
1521

    
1522
	/* first check if there is even an LDAP server populated */
1523
	if (!$ldapserver) {
1524
		log_error(gettext("ERROR! could not find details of the LDAP server used for authentication."));
1525
		$attributes['error_message'] =  gettext("Internal error during authentication.");
1526
		return null;
1527
	}
1528

    
1529
	if ($debug) {
1530
		log_error(sprintf(gettext("LDAP Debug: Attempting to authenticate %s on %s"), $username, $ldapname));
1531
		log_error(sprintf(gettext("LDAP Debug: URI: %s (v%s)"), $ldapserver, $ldapver));
1532
		log_error(sprintf(gettext("LDAP Debug: Base DN: %s"), $ldapbasedn));
1533
		log_error(sprintf(gettext("LDAP Debug: Scope: %s"), $ldapscope));
1534
		log_error(sprintf(gettext("LDAP Debug: Auth Bind DN: %s"), $ldapbindun));
1535
		log_error(sprintf(gettext("LDAP Debug: Container: %s"), $ldapauthcont));
1536
		log_error(sprintf(gettext("LDAP Debug: Attrs: Name: %s / Group: %s"), $ldapnameattribute, $ldapgroupattribute));
1537
		log_error(sprintf(gettext("LDAP Debug: Extended Query: %s"), $ldapextendedquery));
1538
		log_error(sprintf(gettext("LDAP Debug: Filter: %s"), $ldapfilter));
1539
		log_error(sprintf(gettext("LDAP Debug: Group Filter: %s"), $ldapgroupfilter));
1540
	}
1541

    
1542
	/* Make sure we can connect to LDAP */
1543
	$error = false;
1544
	if (!($ldap = ldap_connect($ldapserver))) {
1545
		$error = true;
1546
	}
1547

    
1548
	if ($debug) {
1549
		log_error(sprintf(gettext("LDAP Debug: LDAP connection error flag: %s"), var_export($error, true)));
1550
	}
1551

    
1552
	/* Setup CA environment if needed. */
1553
	ldap_setup_caenv($ldap, $authcfg);
1554

    
1555
	ldap_set_option($ldap, LDAP_OPT_REFERRALS, 0);
1556
	ldap_set_option($ldap, LDAP_OPT_DEREF, LDAP_DEREF_SEARCHING);
1557
	ldap_set_option($ldap, LDAP_OPT_PROTOCOL_VERSION, (int)$ldapver);
1558
	ldap_set_option($ldap, LDAP_OPT_TIMELIMIT, (int)$ldaptimeout);
1559
	ldap_set_option($ldap, LDAP_OPT_NETWORK_TIMEOUT, (int)$ldaptimeout);
1560

    
1561
	if (strstr($authcfg['ldap_urltype'], "STARTTLS")) {
1562
		if (!(@ldap_start_tls($ldap))) {
1563
			log_error(sprintf(gettext("ERROR! could not connect to LDAP server %s using STARTTLS."), $ldapname));
1564
			$attributes['error_message'] = gettext("Error : could not connect to authentication server.");
1565
			@ldap_close($ldap);
1566
			return null;
1567
		}
1568
	}
1569

    
1570
	if ($error == true) {
1571
		$errormsg = sprintf(gettext("ERROR! Could not connect to server %s."), $ldapname);
1572
		$attributes['error_message'] = gettext("Error : could not connect to authentication server.");
1573
		return null;
1574
	}
1575

    
1576
	/* ok, its up.  now, lets bind as the bind user so we can search it */
1577
	$error = false;
1578
	$ldapbindun = isset($authcfg['ldap_utf8']) ? utf8_encode($ldapbindun) : $ldapbindun;
1579
	$ldapbindpw = isset($authcfg['ldap_utf8']) ? utf8_encode($ldapbindpw) : $ldapbindpw;
1580
	if ($ldapanon == true) {
1581
		if (!($res = @ldap_bind($ldap))) {
1582
			$error = true;
1583
		}
1584
	} else if (!($res = @ldap_bind($ldap, $ldapbindun, $ldapbindpw))) {
1585
		$error = true;
1586
	}
1587

    
1588
	if ($error == true) {
1589
		@ldap_close($ldap);
1590
		log_error(sprintf(gettext("ERROR! Could not bind to LDAP server %s. Please check the bind credentials."), $ldapname));
1591
		$attributes['error_message'] = gettext("Error : could not connect to authentication server.");
1592
		return null;
1593
	}
1594

    
1595
	/* Get LDAP Authcontainers and split em up. */
1596
	$ldac_splits = explode(";", $ldapauthcont);
1597

    
1598
	/* setup the usercount so we think we haven't found anyone yet */
1599
	$usercount = 0;
1600

    
1601
	/*****************************************************************/
1602
	/*  We first find the user based on username and filter          */
1603
	/*  then, once we find the first occurrence of that person       */
1604
	/*  we set session variables to point to the OU and DN of the    */
1605
	/*  person.  To later be used by ldap_get_groups.                */
1606
	/*  that way we don't have to search twice.                      */
1607
	/*****************************************************************/
1608
	if ($debug) {
1609
		log_error(sprintf(gettext("LDAP Debug: Now Searching for %s in directory."), $username));
1610
	}
1611
	/* Iterate through the user containers for search */
1612
	foreach ($ldac_splits as $i => $ldac_split) {
1613
		$ldac_split = isset($authcfg['ldap_utf8']) ? utf8_encode($ldac_split) : $ldac_split;
1614
		$ldapfilter = isset($authcfg['ldap_utf8']) ? utf8_encode($ldapfilter) : $ldapfilter;
1615
		$ldapsearchbasedn = isset($authcfg['ldap_utf8']) ? utf8_encode("{$ldac_split},{$ldapbasedn}") : "{$ldac_split},{$ldapbasedn}";
1616
		/* Make sure we just use the first user we find */
1617
		if ($debug) {
1618
			log_error(sprintf(gettext('LDAP Debug: Now searching in server %1$s, container %2$s with filter %3$s.'), $ldapname, utf8_decode($ldac_split), utf8_decode($ldapfilter)));
1619
		}
1620
		if ($ldapscope == "one") {
1621
			$ldapfunc = "ldap_list";
1622
		} else {
1623
			$ldapfunc = "ldap_search";
1624
		}
1625
		/* Support legacy auth container specification. */
1626
		if (stristr($ldac_split, "DC=") || empty($ldapbasedn)) {
1627
			$ldapdn = $ldac_split;
1628
		} else {
1629
			$ldapdn = $ldapsearchbasedn;
1630
		}
1631
		if (!($search = @$ldapfunc($ldap, $ldapdn, $ldapfilter))) {
1632
			log_error(sprintf(gettext("Search resulted in error: %s"), ldap_error($ldap)));
1633
			continue;
1634
		}
1635
		if (isset($authcfg['ldap_rfc2307']) && isset($ldapgroupfilter)) {
1636
			if (isset($authcfg['ldap_rfc2307_userdn'])) {
1637
				$info = ldap_get_entries($ldap, $search);
1638
				$username = $info[0]['dn'];
1639
			}
1640
			$ldapgroupfilter = "(&({$ldapgroupattribute}={$username})({$ldapextendedquery}))";
1641
			$groupsearch = @$ldapfunc($ldap, $ldapdn, $ldapgroupfilter);
1642
			if ($debug) {
1643
				log_error(sprintf(gettext("LDAP Debug: RFC2307 group filter search: %s"), $ldapgroupfilter));
1644
			}
1645
		}
1646

    
1647
		if (isset($ldapgroupfilter) && !$groupsearch) {
1648
			log_error(sprintf(gettext("LDAP Debug: Extended group search resulted in error: %s"), ldap_error($ldap)));
1649
			continue;
1650
		}
1651
		if (isset($groupsearch)) {
1652
			$validgroup = ldap_count_entries($ldap, $groupsearch);
1653
			if ($debug) {
1654
				log_error(sprintf(gettext("LDAP Debug: Group search contains %s results."), $validgroup));
1655
			}
1656
		}
1657
		$info = ldap_get_entries($ldap, $search);
1658
		$matches = $info['count'];
1659
		if ($matches == 1) {
1660
			$userdn = $_SESSION['ldapdn'] = $info[0]['dn'];
1661
			$_SESSION['ldapou'] = $ldac_split[$i];
1662
			$_SESSION['ldapon'] = "true";
1663
			$usercount = 1;
1664
			break;
1665
		}
1666
	}
1667

    
1668
	if ($usercount != 1) {
1669
		@ldap_unbind($ldap);
1670
		if ($debug) {
1671
			if ($usercount === 0) {
1672
				log_error(sprintf(gettext("LDAP Debug: ERROR! LDAP search failed, no user matching %s was found."), $username));
1673
			} else {
1674
				log_error(sprintf(gettext("LDAP Debug: ERROR! LDAP search failed, multiple users matching %s were found."), $username));
1675
			}
1676
		}
1677
		$attributes['error_message'] = gettext("Invalid login specified.");
1678
		return false;
1679
	}
1680

    
1681
	/* Now lets bind as the user we found */
1682
	$passwd = isset($authcfg['ldap_utf8']) ? utf8_encode($passwd) : $passwd;
1683
	if (!($res = @ldap_bind($ldap, $userdn, $passwd))) {
1684
		if ($debug) {
1685
			log_error(sprintf(gettext('LDAP Debug: ERROR! Could not login to server %1$s as user %2$s: %3$s'), $ldapname, $username, ldap_error($ldap)));
1686
		}
1687
		@ldap_unbind($ldap);
1688
		return false;
1689
	}
1690

    
1691
	if ($debug) {
1692
		$userdn = isset($authcfg['ldap_utf8']) ? utf8_decode($userdn) : $userdn;
1693
		log_error(sprintf(gettext('LDAP Debug: Logged in successfully as %1$s via LDAP server %2$s with DN = %3$s.'), $username, $ldapname, $userdn));
1694
	}
1695

    
1696
	if ($debug && isset($ldapgroupfilter) && $validgroup < 1) {
1697
		log_error(sprintf(gettext('LDAP Debug: Logged in successfully as %1$s but did not match any field in extended query.'), $username));
1698
	}
1699

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

    
1703
	if (isset($ldapgroupfilter) && $validgroup < 1) {
1704
		return false;
1705
	}
1706

    
1707
	return true;
1708
}
1709

    
1710
function radius_backed($username, $password, $authcfg, &$attributes = array()) {
1711
	$ret = false;
1712

    
1713
	require_once("Auth/RADIUS.php");
1714
	require_once("Crypt/CHAP.php");
1715

    
1716
	if ($authcfg) {
1717
		$radiusservers = array();
1718
		$radiusservers[0]['ipaddr'] = $authcfg['host'];
1719
		$radiusservers[0]['port'] = $authcfg['radius_auth_port'];
1720
		$radiusservers[0]['sharedsecret'] = $authcfg['radius_secret'];
1721
		$radiusservers[0]['timeout'] = $authcfg['radius_timeout'];
1722
		if(isset($authcfg['radius_protocol'])) {
1723
			$radius_protocol = $authcfg['radius_protocol'];
1724
		} else {
1725
			$radius_protocol = 'PAP';
1726
		}
1727
	} else {
1728
		log_error(gettext("ERROR! could not find details of the RADIUS server used for authentication."));
1729
		$attributes['error_message'] =  gettext("Internal error during authentication.");
1730
		return null;
1731
	}
1732

    
1733
	// Create our instance
1734
	$classname = 'Auth_RADIUS_' . $radius_protocol;
1735
	$rauth = new $classname($username, $password);
1736

    
1737
	/* Add new servers to our instance */
1738
	foreach ($radiusservers as $radsrv) {
1739
		$timeout = (is_numeric($radsrv['timeout'])) ? $radsrv['timeout'] : 5;
1740
		$rauth->addServer($radsrv['ipaddr'], $radsrv['port'], $radsrv['sharedsecret'], $timeout);
1741
	}
1742

    
1743
	// Construct data package
1744
	$rauth->username = $username;
1745
	switch ($radius_protocol) {
1746
		case 'CHAP_MD5':
1747
		case 'MSCHAPv1':
1748
			$classname = $radius_protocol == 'MSCHAPv1' ? 'Crypt_CHAP_MSv1' : 'Crypt_CHAP_MD5';
1749
			$crpt = new $classname;
1750
			$crpt->username = $username;
1751
			$crpt->password = $password;
1752
			$rauth->challenge = $crpt->challenge;
1753
			$rauth->chapid = $crpt->chapid;
1754
			$rauth->response = $crpt->challengeResponse();
1755
			$rauth->flags = 1;
1756
			break;
1757

    
1758
		case 'MSCHAPv2':
1759
			$crpt = new Crypt_CHAP_MSv2;
1760
			$crpt->username = $username;
1761
			$crpt->password = $password;
1762
			$rauth->challenge = $crpt->authChallenge;
1763
			$rauth->peerChallenge = $crpt->peerChallenge;
1764
			$rauth->chapid = $crpt->chapid;
1765
			$rauth->response = $crpt->challengeResponse();
1766
			break;
1767

    
1768
		default:
1769
			$rauth->password = $password;
1770
			break;
1771
	}
1772

    
1773
	if (PEAR::isError($rauth->start())) {
1774
		$ret = null;
1775
		log_error(sprintf(gettext("Error during RADIUS authentication : %s"), $rauth->getError()));
1776
		$attributes['error_message'] = gettext("Error : could not connect to authentication server.");
1777
	} else {
1778
		$nasid = $attributes['nas_identifier'];
1779
		if (empty($nasid)) {
1780
			$nasid = gethostname(); //If no RADIUS NAS-Identifier is given : we use pfsense's hostname as NAS-Identifier
1781
		}
1782
		$nasip = nasip_fallback($authcfg['radius_nasip_attribute']);
1783
		$nasmac = get_interface_mac(find_ip_interface($nasip));
1784

    
1785
		$rauth->putAttribute(RADIUS_NAS_IP_ADDRESS, $nasip, "addr");
1786
		$rauth->putAttribute(RADIUS_NAS_IDENTIFIER, $nasid);
1787

    
1788
		if(!empty($attributes['calling_station_id'])) {
1789
			$rauth->putAttribute(RADIUS_CALLING_STATION_ID, $attributes['calling_station_id']);
1790
		}
1791
		// Carefully check that interface has a MAC address
1792
		if(!empty($nasmac)) {
1793
			$nasmac = mac_format($nasmac);
1794
			$rauth->putAttribute(RADIUS_CALLED_STATION_ID, $nasmac.':'.gethostname());
1795
		}
1796
		if(!empty($attributes['nas_port_type'])) {
1797
			$rauth->putAttribute(RADIUS_NAS_PORT_TYPE, $attributes['nas_port_type']);
1798
		}
1799
		if(!empty($attributes['nas_port'])) {
1800
			$rauth->putAttribute(RADIUS_NAS_PORT, intval($attributes['nas_port']), 'integer');
1801
		}
1802
		if(!empty($attributes['framed_ip']) && is_ipaddr($attributes['framed_ip'])) {
1803
			$rauth->putAttribute(RADIUS_FRAMED_IP_ADDRESS, $attributes['framed_ip'], "addr");
1804
		}
1805
	}
1806

    
1807
	// XXX - billm - somewhere in here we need to handle securid challenge/response
1808

    
1809
	/* Send request */
1810
	$result = $rauth->send();
1811
	if (PEAR::isError($result)) {
1812
		log_error(sprintf(gettext("Error during RADIUS authentication : %s"), $rauth->getError()));
1813
		$attributes['error_message'] = gettext("Error : could not connect to authentication server.");
1814
		$ret = null;
1815
	} else if ($result === true) {
1816
		$ret = true;
1817
	} else {
1818
		$ret = false;
1819
	}
1820

    
1821

    
1822
	// Get attributes, even if auth failed.
1823
	if ($rauth->getAttributes()) {
1824
	$attributes = array_merge($attributes,$rauth->listAttributes());
1825

    
1826
	// We convert the session_terminate_time to unixtimestamp if its set before returning the whole array to our caller
1827
	if (!empty($attributes['session_terminate_time'])) {
1828
			$stt = &$attributes['session_terminate_time'];
1829
			$stt = strtotime(preg_replace("/\+(\d+):(\d+)$/", " +\${1}\${2}", preg_replace("/(\d+)T(\d+)/", "\${1} \${2}",$stt)));
1830
		}
1831
	}
1832

    
1833
	// close OO RADIUS_AUTHENTICATION
1834
	$rauth->close();
1835

    
1836
	return $ret;
1837
}
1838

    
1839
function nasip_fallback($ip) {
1840
	if (!is_ipaddr($ip)) {
1841
		$nasip = get_interface_ip($ip);
1842

    
1843
		if (!is_ipaddr($nasip)) {
1844
			/* use first interface with IP as fallback for NAS-IP-Address
1845
			 * see https://redmine.pfsense.org/issues/11109 */
1846
			foreach (get_configured_interface_list() as $if) {
1847
				$nasip = get_interface_ip($if);
1848
				if (is_ipaddr($nasip)) {
1849
					break;
1850
				}
1851
			}
1852
		}
1853
	} else {
1854
		$nasip = $ip;
1855
	}
1856

    
1857
	return $nasip;
1858
}
1859

    
1860
/*
1861
	$attributes must contain a "class" key containing the groups and local
1862
	groups must exist to match.
1863
*/
1864
function radius_get_groups($attributes) {
1865
	$groups = array();
1866
	if (!empty($attributes) && is_array($attributes) && (!empty($attributes['class']) || !empty($attributes['class_int']))) {
1867
		/* Some RADIUS servers return multiple class attributes, so check them all. */
1868
		$groups = array();
1869
		if (!empty($attributes['class']) && is_array($attributes['class'])) {
1870
			foreach ($attributes['class'] as $class) {
1871
				$groups = array_unique(array_merge($groups, explode(";", $class)));
1872
			}
1873
		}
1874

    
1875
		foreach ($groups as & $grp) {
1876
			$grp = trim($grp);
1877
			if (strtolower(substr($grp, 0, 3)) == "ou=") {
1878
				$grp = substr($grp, 3);
1879
			}
1880
		}
1881
	}
1882
	return $groups;
1883
}
1884

    
1885
function get_user_expiration_date($username) {
1886
	$user = getUserEntry($username);
1887
	if ($user['expires']) {
1888
		return $user['expires'];
1889
	}
1890
}
1891

    
1892
function is_account_expired($username) {
1893
	$expirydate = get_user_expiration_date($username);
1894
	if ($expirydate) {
1895
		if (strtotime("-1 day") > strtotime(date("m/d/Y", strtotime($expirydate)))) {
1896
			return true;
1897
		}
1898
	}
1899

    
1900
	return false;
1901
}
1902

    
1903
function is_account_disabled($username) {
1904
	$user = getUserEntry($username);
1905
	if (isset($user['disabled'])) {
1906
		return true;
1907
	}
1908

    
1909
	return false;
1910
}
1911

    
1912
function get_user_settings($username) {
1913
	$settings = array();
1914
	$settings['widgets'] = config_get_path('widgets');
1915
	$settings['webgui']['dashboardcolumns'] = config_get_path('system/webgui/dashboardcolumns');
1916
	$settings['webgui']['webguihostnamemenu'] = config_get_path('system/webgui/webguihostnamemenu');
1917
	$settings['webgui']['webguicss'] = config_get_path('system/webgui/webguicss');
1918
	$settings['webgui']['logincss'] = config_get_path('system/webgui/logincss');
1919
	$settings['webgui']['interfacessort'] = config_path_enabled('system/webgui', 'interfacessort');
1920
	$settings['webgui']['dashboardavailablewidgetspanel'] = config_path_enabled('system/webgui', 'dashboardavailablewidgetspanel');
1921
	$settings['webgui']['webguifixedmenu'] = config_path_enabled('system/webgui', 'webguifixedmenu');
1922
	$settings['webgui']['webguileftcolumnhyper'] = config_path_enabled('system/webgui', 'webguileftcolumnhyper');
1923
	$settings['webgui']['disablealiaspopupdetail'] = config_path_enabled('system/webgui', 'disablealiaspopupdetail');
1924
	$settings['webgui']['systemlogsfilterpanel'] = config_path_enabled('system/webgui', 'systemlogsfilterpanel');
1925
	$settings['webgui']['systemlogsmanagelogpanel'] = config_path_enabled('system/webgui', 'systemlogsmanagelogpanel');
1926
	$settings['webgui']['statusmonitoringsettingspanel'] = config_path_enabled('system/webgui', 'statusmonitoringsettingspanel');
1927
	$settings['webgui']['pagenamefirst'] = config_path_enabled('system/webgui', 'pagenamefirst');
1928
	$user = getUserEntry($username);
1929
	if (isset($user['customsettings'])) {
1930
		$settings['customsettings'] = true;
1931
		if (isset($user['widgets'])) {
1932
			// This includes the 'sequence', and any widgetname-config per-widget settings.
1933
			$settings['widgets'] = $user['widgets'];
1934
		}
1935
		if (isset($user['dashboardcolumns'])) {
1936
			$settings['webgui']['dashboardcolumns'] = $user['dashboardcolumns'];
1937
		}
1938
		if (isset($user['webguicss'])) {
1939
			$settings['webgui']['webguicss'] = $user['webguicss'];
1940
		}
1941
		if (isset($user['webguihostnamemenu'])) {
1942
			$settings['webgui']['webguihostnamemenu'] = $user['webguihostnamemenu'];
1943
		}
1944
		$settings['webgui']['interfacessort'] = isset($user['interfacessort']);
1945
		$settings['webgui']['dashboardavailablewidgetspanel'] = isset($user['dashboardavailablewidgetspanel']);
1946
		$settings['webgui']['webguifixedmenu'] = isset($user['webguifixedmenu']);
1947
		$settings['webgui']['webguileftcolumnhyper'] = isset($user['webguileftcolumnhyper']);
1948
		$settings['webgui']['disablealiaspopupdetail'] = isset($user['disablealiaspopupdetail']);
1949
		$settings['webgui']['systemlogsfilterpanel'] = isset($user['systemlogsfilterpanel']);
1950
		$settings['webgui']['systemlogsmanagelogpanel'] = isset($user['systemlogsmanagelogpanel']);
1951
		$settings['webgui']['statusmonitoringsettingspanel'] = isset($user['statusmonitoringsettingspanel']);
1952
		$settings['webgui']['pagenamefirst'] = isset($user['pagenamefirst']);
1953
	} else {
1954
		$settings['customsettings'] = false;
1955
	}
1956

    
1957
	if ($settings['webgui']['dashboardcolumns'] < 1) {
1958
		$settings['webgui']['dashboardcolumns'] = 2;
1959
	}
1960

    
1961
	return $settings;
1962
}
1963

    
1964
function save_widget_settings($username, $settings, $message = "") {
1965
	global $userindex;
1966
	$user = getUserEntry($username);
1967

    
1968
	if (strlen($message) > 0) {
1969
		$msgout = $message;
1970
	} else {
1971
		$msgout = gettext("Widget configuration has been changed.");
1972
	}
1973

    
1974
	if (isset($user['customsettings'])) {
1975
		config_set_path("system/user/{$userindex[$username]}/widgets", $settings);
1976
		write_config($msgout . " " . sprintf(gettext("(User %s)"), $username));
1977
	} else {
1978
		config_set_path('widgets', $settings);
1979
		write_config($msgout);
1980
	}
1981
}
1982

    
1983
function auth_get_authserver($name) {
1984
	foreach (config_get_path('system/authserver', []) as $authcfg) {
1985
		if ($authcfg['name'] == $name) {
1986
			return $authcfg;
1987
		}
1988
	}
1989
	if ($name == "Local Database") {
1990
		return array("name" => "Local Database", "type" => "Local Auth", "host" => config_get_path('system/hostname'));
1991
	}
1992
}
1993

    
1994
function auth_get_authserver_list() {
1995
	$list = array();
1996

    
1997
	foreach (config_get_path('system/authserver', []) as $authcfg) {
1998
		/* Add support for disabled entries? */
1999
		$list[$authcfg['name']] = $authcfg;
2000
	}
2001

    
2002
	$list["Local Database"] = array("name" => "Local Database", "type" => "Local Auth", "host" => config_get_path('system/hostname'));
2003
	return $list;
2004
}
2005

    
2006
function getUserGroups($username, $authcfg, &$attributes = array()) {
2007
	$allowed_groups = array();
2008

    
2009
	switch ($authcfg['type']) {
2010
		case 'ldap':
2011
			$allowed_groups = @ldap_get_groups($username, $authcfg);
2012
			break;
2013
		case 'radius':
2014
			$allowed_groups = @radius_get_groups($attributes);
2015
			break;
2016
		default:
2017
			$user = getUserEntry($username);
2018
			$allowed_groups = @local_user_get_groups($user, true);
2019
			break;
2020
	}
2021

    
2022
	$member_groups = array();
2023
	foreach (config_get_path('system/group', []) as $group) {
2024
		if (in_array($group['name'], $allowed_groups)) {
2025
			$member_groups[] = $group['name'];
2026
		}
2027
	}
2028

    
2029
	return $member_groups;
2030
}
2031

    
2032
/*
2033
Possible return values :
2034
true : authentication worked
2035
false : authentication failed (invalid login/password, not enough permission, etc...)
2036
null : error during authentication process (unable to reach remote server, etc...)
2037
*/
2038
function authenticate_user($username, $password, $authcfg = NULL, &$attributes = array()) {
2039

    
2040
	if (is_array($username) || is_array($password)) {
2041
		return false;
2042
	}
2043

    
2044
	if (!$authcfg) {
2045
		return local_backed($username, $password, $attributes);
2046
	}
2047

    
2048
	$authenticated = false;
2049
	switch ($authcfg['type']) {
2050
		case 'ldap':
2051
			try {
2052
				$authenticated = ldap_backed($username, $password, $authcfg, $attributes);
2053
			} catch (Exception $e) {
2054
				log_error(sprintf(gettext("LDAP authentication error: %s"), $e->getMessage()));
2055
			}
2056
			break;
2057

    
2058
			break;
2059
		case 'radius':
2060
			try {
2061
				$authenticated = radius_backed($username, $password, $authcfg, $attributes);
2062
			} catch (Exception $e) {
2063
				log_error(sprintf(gettext("RADIUS authentication error: %s"), $e->getMessage()));
2064
			}
2065
			break;
2066
		default:
2067
			/* lookup user object by name */
2068
			try {
2069
				$authenticated = local_backed($username, $password, $attributes);
2070
			} catch (Exception $e) {
2071
				log_error(sprintf(gettext("Local authentication error: %s"), $e->getMessage()));
2072
			}
2073
			break;
2074
		}
2075

    
2076
	return $authenticated;
2077
}
2078

    
2079
function session_auth() {
2080
	global $_SESSION, $page;
2081

    
2082
	// Handle HTTPS httponly and secure flags
2083
	$currentCookieParams = session_get_cookie_params();
2084
	session_set_cookie_params(
2085
		$currentCookieParams["lifetime"],
2086
		$currentCookieParams["path"],
2087
		NULL,
2088
		(config_get_path('system/webgui/protocol') == "https"),
2089
		true
2090
	);
2091

    
2092
	phpsession_begin();
2093

    
2094
	// Detect protocol change
2095
	if (!isset($_POST['login']) && !empty($_SESSION['Logged_In']) && $_SESSION['protocol'] != config_get_path('system/webgui/protocol')) {
2096
		phpsession_end();
2097
		return false;
2098
	}
2099

    
2100
	/* Validate incoming login request */
2101
	$attributes = array('nas_identifier' => 'webConfigurator-' . gethostname());
2102
	if (isset($_POST['login']) && !empty($_POST['usernamefld'])) {
2103
		$authcfg = auth_get_authserver(config_get_path('system/webgui/authmode'));
2104
		$remoteauth = authenticate_user($_POST['usernamefld'], $_POST['passwordfld'], $authcfg, $attributes);
2105
		if ($remoteauth || authenticate_user($_POST['usernamefld'], $_POST['passwordfld'])) {
2106
			// Generate a new id to avoid session fixation
2107
			session_regenerate_id();
2108
			$_SESSION['Logged_In'] = "True";
2109
			$_SESSION['remoteauth'] = $remoteauth;
2110
			if ($remoteauth) {
2111
				if (empty($authcfg['type']) || ($authcfg['type'] == "Local Auth")) {
2112
					$_SESSION['authsource'] = "Local Database";
2113
				} else {
2114
					$_SESSION['authsource'] = strtoupper($authcfg['type']) . "/{$authcfg['name']}";
2115
				}
2116
			} else {
2117
				$_SESSION['authsource'] = 'Local Database Fallback';
2118
			}
2119
			$_SESSION['Username'] = $_POST['usernamefld'];
2120
			$_SESSION['user_radius_attributes'] = $attributes;
2121
			$_SESSION['last_access'] = time();
2122
			$_SESSION['protocol'] = config_get_path('system/webgui/protocol');
2123
			phpsession_end(true);
2124
			if (!config_path_enabled('system/webgui', 'quietlogin')) {
2125
				log_auth(sprintf(gettext("Successful login for user '%1\$s' from: %2\$s"), $_POST['usernamefld'], get_user_remote_address() . get_user_remote_authsource()));
2126
			}
2127
			if (isset($_POST['postafterlogin'])) {
2128
				return true;
2129
			} else {
2130
				if (empty($page)) {
2131
					$page = "/";
2132
				}
2133
				header("Location: {$page}");
2134
			}
2135
			exit;
2136
		} else {
2137
			/* give the user an error message */
2138
			$_SESSION['Login_Error'] = gettext("Username or Password incorrect");
2139
			log_auth(sprintf(gettext("webConfigurator authentication error for user '%1\$s' from: %2\$s"), $_POST['usernamefld'], get_user_remote_address(false)));
2140
			if (isAjax()) {
2141
				echo "showajaxmessage('{$_SESSION['Login_Error']}');";
2142
				return;
2143
			}
2144
		}
2145
	}
2146

    
2147
	/* Show login page if they aren't logged in */
2148
	if (empty($_SESSION['Logged_In'])) {
2149
		phpsession_end(true);
2150
		return false;
2151
	}
2152

    
2153
	$session_timeout = config_get_path('system/webgui/session_timeout', 240);
2154
	/* If session timeout isn't set, we don't mark sessions stale */
2155
	if (intval($session_timeout) == 0) {
2156
		/* only update if it wasn't ajax */
2157
		if (!isAjax()) {
2158
			$_SESSION['last_access'] = time();
2159
		}
2160
	} else {
2161
		/* Check for stale session */
2162
		if ($_SESSION['last_access'] < (time() - ($session_timeout * 60))) {
2163
			$_POST['logout'] = true;
2164
			$_SESSION['Logout'] = true;
2165
		} else {
2166
			/* only update if it wasn't ajax */
2167
			if (!isAjax()) {
2168
				$_SESSION['last_access'] = time();
2169
			}
2170
		}
2171
	}
2172

    
2173
	/* user hit the logout button */
2174
	if (isset($_POST['logout'])) {
2175

    
2176
		if ($_SESSION['Logout']) {
2177
			log_error(sprintf(gettext("Session timed out for user '%1\$s' from: %2\$s"), $_SESSION['Username'], get_user_remote_address() . get_user_remote_authsource()));
2178
		} else {
2179
			log_error(sprintf(gettext("User logged out for user '%1\$s' from: %2\$s"), $_SESSION['Username'], get_user_remote_address() . get_user_remote_authsource()));
2180
		}
2181

    
2182
		/* wipe out $_SESSION */
2183
		$_SESSION = array();
2184

    
2185
		if (isset($_COOKIE[session_name()])) {
2186
			setcookie(session_name(), '', time()-42000, '/');
2187
		}
2188

    
2189
		/* and destroy it */
2190
		phpsession_destroy();
2191

    
2192
		$scriptName = explode("/", $_SERVER["SCRIPT_FILENAME"]);
2193
		$scriptElms = count($scriptName);
2194
		$scriptName = $scriptName[$scriptElms-1];
2195

    
2196
		if (isAjax()) {
2197
			return false;
2198
		}
2199

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

    
2203
		return false;
2204
	}
2205

    
2206
	/*
2207
	 * this is for debugging purpose if you do not want to use Ajax
2208
	 * to submit a HTML form. It basically disables the observation
2209
	 * of the submit event and hence does not trigger Ajax.
2210
	 */
2211
	if ($_REQUEST['disable_ajax']) {
2212
		$_SESSION['NO_AJAX'] = "True";
2213
	}
2214

    
2215
	/*
2216
	 * Same to re-enable Ajax.
2217
	 */
2218
	if ($_REQUEST['enable_ajax']) {
2219
		unset($_SESSION['NO_AJAX']);
2220
	}
2221
	phpsession_end(true);
2222
	return true;
2223
}
2224

    
2225
function print_credit() {
2226
	global $g;
2227

    
2228
	return  '<a target="_blank" href="https://pfsense.org">' . g_get('product_label') . '</a>' .
2229
			gettext(' is developed and maintained by ') .
2230
			'<a target="_blank" href="https://netgate.com">Netgate. </a>' . ' &copy; ESF ' . g_get('product_copyright_years') .
2231
			'<a target="_blank" href="https://pfsense.org/license">' .
2232
			gettext(' View license.') . '</a>';
2233
}
2234
function get_user_remote_address($print_all=true) {
2235
	$remote_address = $_SERVER['REMOTE_ADDR'];
2236
	/* Add extra identifying header information upon request */
2237
	if ($print_all) {
2238
		if (!empty($_SERVER['HTTP_CLIENT_IP'] &&
2239
		    is_ipaddr($_SERVER['HTTP_CLIENT_IP']))) {
2240
			$remote_address .= "[{$_SERVER['HTTP_CLIENT_IP']}]";
2241
		} elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR']) &&
2242
			  is_ipaddr($_SERVER['HTTP_X_FORWARDED_FOR'])) {
2243
			$remote_address .= "[{$_SERVER['HTTP_X_FORWARDED_FOR']}]";
2244
		}
2245
	}
2246
	return $remote_address;
2247
}
2248
function get_user_remote_authsource() {
2249
	$authsource = "";
2250
	if (!empty($_SESSION['authsource'])) {
2251
		$authsource .= " ({$_SESSION['authsource']})";
2252
	}
2253
	return $authsource;
2254
}
2255

    
2256
function set_pam_auth() {
2257
	$authcfg = auth_get_authserver(config_get_path('system/webgui/authmode'));
2258

    
2259
	unlink_if_exists("/etc/radius.conf");
2260
	unlink_if_exists("/var/etc/pam_ldap.conf");
2261
	unlink_if_exists("/var/etc/pam_ldap_ca.crt");
2262

    
2263
	$header = "# This file is automatically generated. Do not edit.\n\n";
2264
	$pam_sshd =<<<EOD
2265
# auth
2266
auth		required	pam_unix.so		no_warn try_first_pass
2267

    
2268
# account
2269
account		required	pam_nologin.so
2270
account		required	pam_login_access.so
2271
account		required	pam_unix.so
2272

    
2273
# session
2274
session		required	pam_permit.so
2275

    
2276
# password
2277
password	required	pam_unix.so		no_warn try_first_pass
2278

    
2279
EOD;
2280

    
2281
	$pam_system =<<<EOD
2282
# auth
2283
auth		required	pam_unix.so		no_warn try_first_pass
2284

    
2285
# account
2286
account		required	pam_login_access.so
2287
account		required	pam_unix.so
2288

    
2289
# session
2290
session		required	pam_lastlog.so		no_fail
2291

    
2292
# password
2293
password	required	pam_unix.so		no_warn try_first_pass
2294

    
2295
EOD;
2296

    
2297
	$nsswitch =<<<EOD
2298
group: files
2299
hosts: files dns
2300
netgroup: files
2301
networks: files
2302
passwd: files
2303
shells: files
2304
services: files
2305
protocols: files
2306
rpc: files
2307

    
2308
EOD;
2309

    
2310
	if (config_path_enabled('system/webgui', 'shellauth')) {
2311
		if (($authcfg['type'] == "radius") && isset($authcfg['radius_auth_port'])) {
2312
			$radius_conf = "auth {$authcfg['host']}:{$authcfg['radius_auth_port']} " .
2313
					"{$authcfg['radius_secret']} {$authcfg['radius_timeout']}\n";
2314
			if (isset($authcfg['radius_acct_port'])) {
2315
				$radius_conf .= "acct {$authcfg['host']}:{$authcfg['radius_acct_port']} " .
2316
					"{$authcfg['radius_secret']} {$authcfg['radius_timeout']}\n";
2317
			}
2318
			
2319
			$pam_sshd =<<<EOD
2320
# auth
2321
auth            sufficient      pam_radius.so
2322
auth		required	pam_unix.so		no_warn try_first_pass
2323

    
2324
# account
2325
account		required	pam_nologin.so
2326
account		required	pam_login_access.so
2327
account         sufficient      pam_radius.so
2328

    
2329
# session
2330
session		required	pam_permit.so
2331

    
2332
# password
2333
password        sufficient      pam_radius.so
2334
password	required	pam_unix.so		no_warn try_first_pass
2335

    
2336
EOD;
2337

    
2338
			$pam_system =<<<EOD
2339
# auth
2340
auth            sufficient      pam_radius.so
2341
auth		required	pam_unix.so		no_warn try_first_pass
2342

    
2343
# account
2344
account		required	pam_login_access.so
2345
account         sufficient      pam_radius.so
2346

    
2347
# session
2348
session		required	pam_lastlog.so		no_fail
2349

    
2350
# password
2351
password        sufficient      pam_radius.so
2352
password	required	pam_unix.so		no_warn try_first_pass
2353

    
2354
EOD;
2355

    
2356
			@file_put_contents("/etc/radius.conf", $header . $radius_conf);
2357
		} elseif (($authcfg['type'] == "ldap") && !empty($authcfg['ldap_pam_groupdn'])) {
2358
			// do not try to reconnect
2359
			$ldapconf = "bind_policy soft\n";
2360
			// Bind/connect timelimit
2361
			$ldapconf .= "bind_timelimit {$authcfg['ldap_timeout']}\n";
2362
			$uri = ($authcfg['ldap_urltype'] == 'SSL/TLS Encrypted') ? 'ldaps' : 'ldap';
2363
			$ldapconf .= "uri {$uri}://{$authcfg['host']}/\n";
2364
			$ldapconf .= "port {$authcfg['ldap_port']}\n";
2365
			if ($authcfg['ldap_urltype'] == 'STARTTLS Encrypted')  {
2366
				$ldapconf .= "ssl start_tls\n";
2367
			} elseif ($authcfg['ldap_urltype'] == 'SSL/TLS Encrypted')  {
2368
				$ldapconf .= "ssl on\n";
2369
			}
2370
			if ($authcfg['ldap_urltype'] != 'Standard TCP') {
2371
				if ($authcfg['ldap_caref'] == 'global') {
2372
					$ldapconf .= "tls_cacertfile /etc/ssl/cert.pem\n";
2373
				} else {
2374
					$ca = array();
2375
					$ldappamcafile = "/var/etc/pam_ldap_ca.crt";
2376
					$ca['caref'] = $authcfg['ldap_caref'];
2377
					$cacrt = ca_chain($ca);
2378
					@file_put_contents($ldappamcafile, $cacrt); 
2379
					$ldapconf .= "tls_cacertfile {$ldappamcafile}\n";
2380
				}
2381
				$ldapconf .= "tls_checkpeer yes\n";
2382
			}
2383
			$ldapconf .= "ldap_version {$authcfg['ldap_protver']}\n";
2384
			$ldapconf .= "timelimit {$authcfg['ldap_timeout']}\n";
2385
			$ldapconf .= "base {$authcfg['ldap_basedn']}\n";
2386
			$scope = ($authcfg['ldap_scope' == 'one']) ? 'one' : 'sub';
2387
			$ldapconf .= "scope {$scope}\n";
2388
			$ldapconf .= "binddn {$authcfg['ldap_binddn']}\n";
2389
			$ldapconf .= "bindpw {$authcfg['ldap_bindpw']}\n";
2390
			$ldapconf .= "pam_login_attribute {$authcfg['ldap_attr_user']}\n";
2391
			$ldapconf .= "pam_member_attribute {$authcfg['ldap_attr_member']}\n";
2392
			//$ldapconf .= "pam_filter objectclass={$authcfg['ldap_attr_user']}\n";
2393
			$ldapconf .= "pam_groupdn {$authcfg['ldap_pam_groupdn']}\n";
2394
			//$ldapconf .= "pam_password ad\n";
2395

    
2396
			$pam_sshd =<<<EOD
2397
# auth
2398
auth            sufficient      /usr/local/lib/pam_ldap.so	config=/var/etc/pam_ldap.conf
2399
auth		required	pam_unix.so		no_warn try_first_pass
2400

    
2401
# account
2402
account		required	pam_nologin.so
2403
account		required	pam_login_access.so
2404
account         sufficient      /usr/local/lib/pam_ldap.so	ignore_authinfo_unavail ignore_unknown_user config=/var/etc/pam_ldap.conf
2405

    
2406
# session
2407
session		required	/usr/local/lib/pam_mkhomedir.so	umask=0077 skel=/etc/skel/ silent
2408
session		sufficient	/usr/local/lib/pam_ldap.so	config=/var/etc/pam_ldap.conf
2409
session		required	pam_permit.so
2410

    
2411
# password
2412
password        sufficient      /usr/local/lib/pam_ldap.so	config=/var/etc/pam_ldap.conf
2413
password	required	pam_unix.so		no_warn try_first_pass
2414

    
2415
EOD;
2416

    
2417
			$pam_system =<<<EOD
2418
# auth
2419
auth            sufficient      /usr/local/lib/pam_ldap.so	config=/var/etc/pam_ldap.conf
2420
auth		required	pam_unix.so		no_warn try_first_pass
2421

    
2422
# account
2423
account		required	pam_login_access.so
2424
account         sufficient      pam_radius.so
2425
account         sufficient      /usr/local/lib/pam_ldap.so	ignore_authinfo_unavail ignore_unknown_user config=/var/etc/pam_ldap.conf
2426

    
2427
# session
2428
session		required	/usr/local/lib/pam_mkhomedir.so	umask=0077 skel=/etc/skel/ silent
2429
session		sufficient	/usr/local/lib/pam_ldap.so	config=/var/etc/pam_ldap.conf
2430
session		required	pam_lastlog.so		no_fail
2431

    
2432
# password
2433
password        sufficient      /usr/local/lib/pam_ldap.so	config=/var/etc/pam_ldap.conf
2434
password	required	pam_unix.so		no_warn try_first_pass
2435

    
2436
EOD;
2437

    
2438
			$nsswitch =<<<EOD
2439
group: files ldap
2440
hosts: files dns
2441
netgroup: files
2442
networks: files
2443
passwd: files ldap
2444
shells: files
2445
services: files
2446
protocols: files
2447
rpc: files
2448

    
2449
EOD;
2450

    
2451
			@file_put_contents("/var/etc/pam_ldap.conf", $ldapconf);
2452
			@chmod("/var/etc/pam_ldap.conf", 0600);
2453
			@unlink_if_exists("/usr/local/etc/nss_ldap.conf");
2454
			@symlink("/var/etc/pam_ldap.conf", "/usr/local/etc/nss_ldap.conf");
2455
		}
2456
	}
2457

    
2458
	@file_put_contents("/etc/pam.d/sshd", $header . $pam_sshd);
2459
	@file_put_contents("/etc/pam.d/system", $header . $pam_system);
2460
	@file_put_contents("/etc/nsswitch.conf", $header . $nsswitch);
2461
}
2462
?>
(3-3/61)