Project

General

Profile

Download (49.5 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-2016 Electric Sheep Fencing, LLC
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
if (!$do_not_include_config_gui_inc) {
30
	require_once("config.gui.inc");
31
}
32

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

    
36
/* If this function doesn't exist, we're being called from Captive Portal or
37
   another internal subsystem which does not include authgui.inc */
38
if (function_exists("display_error_form") && !isset($config['system']['webgui']['nodnsrebindcheck'])) {
39
	/* DNS ReBinding attack prevention.  https://redmine.pfsense.org/issues/708 */
40
	$found_host = false;
41

    
42
	/* Either a IPv6 address with or without a alternate port */
43
	if (strstr($_SERVER['HTTP_HOST'], "]")) {
44
		$http_host_port = explode("]", $_SERVER['HTTP_HOST']);
45
		/* v6 address has more parts, drop the last part */
46
		if (count($http_host_port) > 1) {
47
			array_pop($http_host_port);
48
			$http_host = str_replace(array("[", "]"), "", implode(":", $http_host_port));
49
		} else {
50
			$http_host = str_replace(array("[", "]"), "", implode(":", $http_host_port));
51
		}
52
	} else {
53
		$http_host = explode(":", $_SERVER['HTTP_HOST']);
54
		$http_host = $http_host[0];
55
	}
56
	if (is_ipaddr($http_host) or $_SERVER['SERVER_ADDR'] == "127.0.0.1" or
57
		strcasecmp($http_host, "localhost") == 0 or $_SERVER['SERVER_ADDR'] == "::1") {
58
		$found_host = true;
59
	}
60
	if (strcasecmp($http_host, $config['system']['hostname'] . "." . $config['system']['domain']) == 0 or
61
		strcasecmp($http_host, $config['system']['hostname']) == 0) {
62
		$found_host = true;
63
	}
64

    
65
	if (is_array($config['dyndnses']['dyndns']) && !$found_host) {
66
		foreach ($config['dyndnses']['dyndns'] as $dyndns) {
67
			if (strcasecmp($dyndns['host'], $http_host) == 0) {
68
				$found_host = true;
69
				break;
70
			}
71
		}
72
	}
73

    
74
	if (is_array($config['dnsupdates']['dnsupdate']) && !$found_host) {
75
		foreach ($config['dnsupdates']['dnsupdate'] as $rfc2136) {
76
			if (strcasecmp($rfc2136['host'], $http_host) == 0) {
77
				$found_host = true;
78
				break;
79
			}
80
		}
81
	}
82

    
83
	if (!empty($config['system']['webgui']['althostnames']) && !$found_host) {
84
		$althosts = explode(" ", $config['system']['webgui']['althostnames']);
85
		foreach ($althosts as $ah) {
86
			if (strcasecmp($ah, $http_host) == 0 or strcasecmp($ah, $_SERVER['SERVER_ADDR']) == 0) {
87
				$found_host = true;
88
				break;
89
			}
90
		}
91
	}
92

    
93
	if ($found_host == false) {
94
		if (!security_checks_disabled()) {
95
			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."));
96
			exit;
97
		}
98
		$security_passed = false;
99
	}
100
}
101

    
102
// If the HTTP_REFERER is something other than ourselves then disallow.
103
if (function_exists("display_error_form") && !isset($config['system']['webgui']['nohttpreferercheck'])) {
104
	if ($_SERVER['HTTP_REFERER']) {
105
		if (file_exists("{$g['tmp_path']}/setupwizard_lastreferrer")) {
106
			if ($_SERVER['HTTP_REFERER'] == file_get_contents("{$g['tmp_path']}/setupwizard_lastreferrer")) {
107
				unlink("{$g['tmp_path']}/setupwizard_lastreferrer");
108
				header("Refresh: 1; url=index.php");
109
?>
110
<!DOCTYPE html>
111
<html lang="en">
112
<head>
113
	<link rel="stylesheet" href="/css/pfSense.css" />
114
	<title><?=gettext("Redirecting..."); ?></title>
115
</head>
116
<body id="error" class="no-menu">
117
	<div id="jumbotron">
118
		<div class="container">
119
			<div class="col-sm-offset-3 col-sm-6 col-xs-12">
120
				<p><?=gettext("Redirecting to the dashboard...")?></p>
121
			</div>
122
		</div>
123
	</div>
124
</body>
125
</html>
126
<?php
127
				exit;
128
			}
129
		}
130
		$found_host = false;
131
		$referrer_host = parse_url($_SERVER['HTTP_REFERER'], PHP_URL_HOST);
132
		$referrer_host = str_replace(array("[", "]"), "", $referrer_host);
133
		if ($referrer_host) {
134
			if (strcasecmp($referrer_host, $config['system']['hostname'] . "." . $config['system']['domain']) == 0 ||
135
			    strcasecmp($referrer_host, $config['system']['hostname']) == 0) {
136
				$found_host = true;
137
			}
138

    
139
			if (!empty($config['system']['webgui']['althostnames']) && !$found_host) {
140
				$althosts = explode(" ", $config['system']['webgui']['althostnames']);
141
				foreach ($althosts as $ah) {
142
					if (strcasecmp($referrer_host, $ah) == 0) {
143
						$found_host = true;
144
						break;
145
					}
146
				}
147
			}
148

    
149
			if (is_array($config['dyndnses']['dyndns']) && !$found_host) {
150
				foreach ($config['dyndnses']['dyndns'] as $dyndns) {
151
					if (strcasecmp($dyndns['host'], $referrer_host) == 0) {
152
						$found_host = true;
153
						break;
154
					}
155
				}
156
			}
157

    
158
			if (is_array($config['dnsupdates']['dnsupdate']) && !$found_host) {
159
				foreach ($config['dnsupdates']['dnsupdate'] as $rfc2136) {
160
					if (strcasecmp($rfc2136['host'], $referrer_host) == 0) {
161
						$found_host = true;
162
						break;
163
					}
164
				}
165
			}
166

    
167
			if (!$found_host) {
168
				$interface_list_ips = get_configured_ip_addresses();
169
				foreach ($interface_list_ips as $ilips) {
170
					if (strcasecmp($referrer_host, $ilips) == 0) {
171
						$found_host = true;
172
						break;
173
					}
174
				}
175
				$interface_list_ipv6s = get_configured_ipv6_addresses(true);
176
				foreach ($interface_list_ipv6s as $ilipv6s) {
177
					$ilipv6s = explode('%', $ilipv6s)[0];
178
					if (strcasecmp($referrer_host, $ilipv6s) == 0) {
179
						$found_host = true;
180
						break;
181
					}
182
				}
183
				if ($referrer_host == "127.0.0.1" || $referrer_host == "localhost") {
184
					// allow SSH port forwarded connections and links from localhost
185
					$found_host = true;
186
				}
187
			}
188
		}
189
		if ($found_host == false) {
190
			if (!security_checks_disabled()) {
191
				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.");
192
				exit;
193
			}
194
			$security_passed = false;
195
		}
196
	} else {
197
		$security_passed = false;
198
	}
199
}
200

    
201
if (function_exists("display_error_form") && $security_passed) {
202
	/* Security checks passed, so it should be OK to turn them back on */
203
	restore_security_checks();
204
}
205
unset($security_passed);
206

    
207
$groupindex = index_groups();
208
$userindex = index_users();
209

    
210
function index_groups() {
211
	global $g, $debug, $config, $groupindex;
212

    
213
	$groupindex = array();
214

    
215
	if (is_array($config['system']['group'])) {
216
		$i = 0;
217
		foreach ($config['system']['group'] as $groupent) {
218
			$groupindex[$groupent['name']] = $i;
219
			$i++;
220
		}
221
	}
222

    
223
	return ($groupindex);
224
}
225

    
226
function index_users() {
227
	global $g, $debug, $config;
228

    
229
	if (is_array($config['system']['user'])) {
230
		$i = 0;
231
		foreach ($config['system']['user'] as $userent) {
232
			$userindex[$userent['name']] = $i;
233
			$i++;
234
		}
235
	}
236

    
237
	return ($userindex);
238
}
239

    
240
function & getUserEntry($name) {
241
	global $debug, $config, $userindex;
242
	$authcfg = auth_get_authserver($config['system']['webgui']['authmode']);
243

    
244
	if (isset($userindex[$name])) {
245
		return $config['system']['user'][$userindex[$name]];
246
	} elseif ($authcfg['type'] != "Local Database") {
247
		$user = array();
248
		$user['name'] = $name;
249
		return $user;
250
	}
251
}
252

    
253
function & getUserEntryByUID($uid) {
254
	global $debug, $config;
255

    
256
	if (is_array($config['system']['user'])) {
257
		foreach ($config['system']['user'] as & $user) {
258
			if ($user['uid'] == $uid) {
259
				return $user;
260
			}
261
		}
262
	}
263

    
264
	return false;
265
}
266

    
267
function & getGroupEntry($name) {
268
	global $debug, $config, $groupindex;
269
	if (isset($groupindex[$name])) {
270
		return $config['system']['group'][$groupindex[$name]];
271
	}
272
}
273

    
274
function & getGroupEntryByGID($gid) {
275
	global $debug, $config;
276

    
277
	if (is_array($config['system']['group'])) {
278
		foreach ($config['system']['group'] as & $group) {
279
			if ($group['gid'] == $gid) {
280
				return $group;
281
			}
282
		}
283
	}
284

    
285
	return false;
286
}
287

    
288
function get_user_privileges(& $user) {
289
	global $config;
290

    
291
	$authcfg = auth_get_authserver($config['system']['webgui']['authmode']);
292
	$names = array();
293

    
294
	$privs = $user['priv'];
295
	if (!is_array($privs)) {
296
		$privs = array();
297
	}
298

    
299
	if ($authcfg['type'] == "ldap") {
300
		$names = @ldap_get_groups($user['name'], $authcfg);
301
	} elseif ($authcfg['type'] == "radius") {
302
		$names = @radius_get_groups($_SESSION['user_radius_attributes']);
303
	}
304

    
305
	if (empty($names)) {
306
		$names = local_user_get_groups($user, true);
307
	}
308

    
309
	foreach ($names as $name) {
310
		$group = getGroupEntry($name);
311
		if (is_array($group['priv'])) {
312
			$privs = array_merge($privs, $group['priv']);
313
		}
314
	}
315

    
316
	return $privs;
317
}
318

    
319
function userHasPrivilege($userent, $privid = false) {
320

    
321
	if (!$privid || !is_array($userent)) {
322
		return false;
323
	}
324

    
325
	$privs = get_user_privileges($userent);
326

    
327
	if (!is_array($privs)) {
328
		return false;
329
	}
330

    
331
	if (!in_array($privid, $privs)) {
332
		return false;
333
	}
334

    
335
	return true;
336
}
337

    
338
function local_backed($username, $passwd) {
339

    
340
	$user = getUserEntry($username);
341
	if (!$user) {
342
		return false;
343
	}
344

    
345
	if (is_account_disabled($username) || is_account_expired($username)) {
346
		return false;
347
	}
348

    
349
	if ($user['bcrypt-hash']) {
350
		if (password_verify($passwd, $user['bcrypt-hash'])) {
351
			return true;
352
		}
353
	}
354

    
355
	//for backwards compatibility
356
	if ($user['password']) {
357
		if (crypt($passwd, $user['password']) == $user['password']) {
358
			return true;
359
		}
360
	}
361

    
362
	if ($user['md5-hash']) {
363
		if (md5($passwd) == $user['md5-hash']) {
364
			return true;
365
		}
366
	}
367

    
368
	return false;
369
}
370

    
371
function local_sync_accounts() {
372
	global $debug, $config;
373
	conf_mount_rw();
374

    
375
	/* remove local users to avoid uid conflicts */
376
	$fd = popen("/usr/sbin/pw usershow -a", "r");
377
	if ($fd) {
378
		while (!feof($fd)) {
379
			$line = explode(":", fgets($fd));
380
			if ($line[0] != "admin") {
381
				if (!strncmp($line[0], "_", 1)) {
382
					continue;
383
				}
384
				if ($line[2] < 2000) {
385
					continue;
386
				}
387
				if ($line[2] > 65000) {
388
					continue;
389
				}
390
			}
391
			/*
392
			 * If a crontab was created to user, pw userdel will be interactive and
393
			 * can cause issues. Just remove crontab before run it when necessary
394
			 */
395
			unlink_if_exists("/var/cron/tabs/{$line[0]}");
396
			$cmd = "/usr/sbin/pw userdel -n " . escapeshellarg($line[0]);
397
			if ($debug) {
398
				log_error(sprintf(gettext("Running: %s"), $cmd));
399
			}
400
			mwexec($cmd);
401
		}
402
		pclose($fd);
403
	}
404

    
405
	/* remove local groups to avoid gid conflicts */
406
	$gids = array();
407
	$fd = popen("/usr/sbin/pw groupshow -a", "r");
408
	if ($fd) {
409
		while (!feof($fd)) {
410
			$line = explode(":", fgets($fd));
411
			if (!strncmp($line[0], "_", 1)) {
412
				continue;
413
			}
414
			if ($line[2] < 2000) {
415
				continue;
416
			}
417
			if ($line[2] > 65000) {
418
				continue;
419
			}
420
			$cmd = "/usr/sbin/pw groupdel -g " . escapeshellarg($line[2]);
421
			if ($debug) {
422
				log_error(sprintf(gettext("Running: %s"), $cmd));
423
			}
424
			mwexec($cmd);
425
		}
426
		pclose($fd);
427
	}
428

    
429
	/* make sure the all group exists */
430
	$allgrp = getGroupEntryByGID(1998);
431
	local_group_set($allgrp, true);
432

    
433
	/* sync all local users */
434
	if (is_array($config['system']['user'])) {
435
		foreach ($config['system']['user'] as $user) {
436
			local_user_set($user);
437
		}
438
	}
439

    
440
	/* sync all local groups */
441
	if (is_array($config['system']['group'])) {
442
		foreach ($config['system']['group'] as $group) {
443
			local_group_set($group);
444
		}
445
	}
446

    
447
	conf_mount_ro();
448

    
449
}
450

    
451
function local_user_set(& $user) {
452
	global $g, $debug;
453

    
454
	if (empty($user['password']) && empty($user['bcrypt-hash'])) {
455
		log_error("There is something wrong in the config because user {$user['name']} password is missing!");
456
		return;
457
	}
458

    
459
	conf_mount_rw();
460

    
461
	$home_base = "/home/";
462
	$user_uid = $user['uid'];
463
	$user_name = $user['name'];
464
	$user_home = "{$home_base}{$user_name}";
465
	$user_shell = "/etc/rc.initial";
466
	$user_group = "nobody";
467

    
468
	// Ensure $home_base exists and is writable
469
	if (!is_dir($home_base)) {
470
		mkdir($home_base, 0755);
471
	}
472

    
473
	$lock_account = false;
474
	/* configure shell type */
475
	/* Cases here should be ordered by most privileged to least privileged. */
476
	if (userHasPrivilege($user, "user-shell-access") || userHasPrivilege($user, "page-all")) {
477
		$user_shell = "/bin/tcsh";
478
	} elseif (userHasPrivilege($user, "user-copy-files")) {
479
		$user_shell = "/usr/local/bin/scponly";
480
	} elseif (userHasPrivilege($user, "user-ssh-tunnel")) {
481
		$user_shell = "/usr/local/sbin/ssh_tunnel_shell";
482
	} elseif (userHasPrivilege($user, "user-ipsec-xauth-dialin")) {
483
		$user_shell = "/sbin/nologin";
484
	} else {
485
		$user_shell = "/sbin/nologin";
486
		$lock_account = true;
487
	}
488

    
489
	/* Lock out disabled or expired users, unless it's root/admin. */
490
	if ((is_account_disabled($user_name) || is_account_expired($user_name)) && ($user_uid != 0)) {
491
		$user_shell = "/sbin/nologin";
492
		$lock_account = true;
493
	}
494

    
495
	/* root user special handling */
496
	if ($user_uid == 0) {
497
		$cmd = "/usr/sbin/pw usermod -q -n root -s /bin/sh -H 0";
498
		if ($debug) {
499
			log_error(sprintf(gettext("Running: %s"), $cmd));
500
		}
501
		$fd = popen($cmd, "w");
502
		if (empty($user['bcrypt-hash'])) {
503
			fwrite($fd, $user['password']);
504
		} else {
505
			fwrite($fd, $user['bcrypt-hash']);
506
		}
507
		pclose($fd);
508
		$user_group = "wheel";
509
		$user_home = "/root";
510
		$user_shell = "/etc/rc.initial";
511
	}
512

    
513
	/* read from pw db */
514
	$fd = popen("/usr/sbin/pw usershow -n {$user_name} 2>&1", "r");
515
	$pwread = fgets($fd);
516
	pclose($fd);
517
	$userattrs = explode(":", trim($pwread));
518

    
519
	$skel_dir = '/etc/skel';
520

    
521
	/* determine add or mod */
522
	if (($userattrs[0] != $user['name']) || (!strncmp($pwread, "pw:", 3))) {
523
		$user_op = "useradd -m -k " . escapeshellarg($skel_dir) . " -o";
524
	} else {
525
		$user_op = "usermod";
526
	}
527

    
528
	$comment = str_replace(array(":", "!", "@"), " ", $user['descr']);
529
	/* add or mod pw db */
530
	$cmd = "/usr/sbin/pw {$user_op} -q " .
531
			" -u " . escapeshellarg($user_uid) .
532
			" -n " . escapeshellarg($user_name) .
533
			" -g " . escapeshellarg($user_group) .
534
			" -s " . escapeshellarg($user_shell) .
535
			" -d " . escapeshellarg($user_home) .
536
			" -c " . escapeshellarg($comment) .
537
			" -H 0 2>&1";
538

    
539
	if ($debug) {
540
		log_error(sprintf(gettext("Running: %s"), $cmd));
541
	}
542
	$fd = popen($cmd, "w");
543
	if (empty($user['bcrypt-hash'])) {
544
		fwrite($fd, $user['password']);
545
	} else {
546
		fwrite($fd, $user['bcrypt-hash']);
547
	}
548
	pclose($fd);
549

    
550
	/* create user directory if required */
551
	if (!is_dir($user_home)) {
552
		mkdir($user_home, 0700);
553
	}
554
	@chown($user_home, $user_name);
555
	@chgrp($user_home, $user_group);
556

    
557
	/* Make sure all users have last version of config files */
558
	foreach (glob("{$skel_dir}/dot.*") as $dot_file) {
559
		$target = $user_home . '/' . substr(basename($dot_file), 3);
560
		@copy($dot_file, $target);
561
		@chown($target, $user_name);
562
		@chgrp($target, $user_group);
563
	}
564

    
565
	/* write out ssh authorized key file */
566
	if ($user['authorizedkeys']) {
567
		if (!is_dir("{$user_home}/.ssh")) {
568
			@mkdir("{$user_home}/.ssh", 0700);
569
			@chown("{$user_home}/.ssh", $user_name);
570
		}
571
		$keys = base64_decode($user['authorizedkeys']);
572
		@file_put_contents("{$user_home}/.ssh/authorized_keys", $keys);
573
		@chown("{$user_home}/.ssh/authorized_keys", $user_name);
574
	} else {
575
		unlink_if_exists("{$user_home}/.ssh/authorized_keys");
576
	}
577

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

    
581
	conf_mount_ro();
582
}
583

    
584
function local_user_del($user) {
585
	global $debug;
586

    
587
	/* remove all memberships */
588
	local_user_set_groups($user);
589

    
590
	/* Don't remove /root */
591
	if ($user['uid'] != 0) {
592
		$rmhome = "-r";
593
	}
594

    
595
	/* read from pw db */
596
	$fd = popen("/usr/sbin/pw usershow -n {$user['name']} 2>&1", "r");
597
	$pwread = fgets($fd);
598
	pclose($fd);
599
	$userattrs = explode(":", trim($pwread));
600

    
601
	if ($userattrs[0] != $user['name']) {
602
		log_error("Tried to remove user {$user['name']} but got user {$userattrs[0]} instead. Bailing.");
603
		return;
604
	}
605

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

    
609
	if ($debug) {
610
		log_error(sprintf(gettext("Running: %s"), $cmd));
611
	}
612
	mwexec($cmd);
613

    
614
	/* Delete user from groups needs a call to write_config() */
615
	local_group_del_user($user);
616
}
617

    
618
function local_user_set_password(&$user, $password) {
619

    
620
	unset($user['password']);
621
	unset($user['md5-hash']);
622
	$user['bcrypt-hash'] = password_hash($password, PASSWORD_BCRYPT);
623

    
624
	/* Maintain compatibility with FreeBSD - change $2y$ prefix to $2b$
625
	 * https://reviews.freebsd.org/D2742
626
	 * XXX: Can be removed as soon as r284483 is MFC'd.
627
	 */
628
	if ($user['bcrypt-hash'][2] == "y") {
629
		$user['bcrypt-hash'][2] = "b";
630
	}
631

    
632
	// Converts ascii to unicode.
633
	$astr = (string) $password;
634
	$ustr = '';
635
	for ($i = 0; $i < strlen($astr); $i++) {
636
		$a = ord($astr{$i}) << 8;
637
		$ustr .= sprintf("%X", $a);
638
	}
639

    
640
}
641

    
642
function local_user_get_groups($user, $all = false) {
643
	global $debug, $config;
644

    
645
	$groups = array();
646
	if (!is_array($config['system']['group'])) {
647
		return $groups;
648
	}
649

    
650
	foreach ($config['system']['group'] as $group) {
651
		if ($all || (!$all && ($group['name'] != "all"))) {
652
			if (is_array($group['member'])) {
653
				if (in_array($user['uid'], $group['member'])) {
654
					$groups[] = $group['name'];
655
				}
656
			}
657
		}
658
	}
659

    
660
	if ($all) {
661
		$groups[] = "all";
662
	}
663

    
664
	sort($groups);
665

    
666
	return $groups;
667

    
668
}
669

    
670
function local_user_set_groups($user, $new_groups = NULL) {
671
	global $debug, $config, $groupindex;
672

    
673
	if (!is_array($config['system']['group'])) {
674
		return;
675
	}
676

    
677
	$cur_groups = local_user_get_groups($user, true);
678
	$mod_groups = array();
679

    
680
	if (!is_array($new_groups)) {
681
		$new_groups = array();
682
	}
683

    
684
	if (!is_array($cur_groups)) {
685
		$cur_groups = array();
686
	}
687

    
688
	/* determine which memberships to add */
689
	foreach ($new_groups as $groupname) {
690
		if ($groupname == '' || in_array($groupname, $cur_groups)) {
691
			continue;
692
		}
693
		$group = & $config['system']['group'][$groupindex[$groupname]];
694
		$group['member'][] = $user['uid'];
695
		$mod_groups[] = $group;
696
	}
697
	unset($group);
698

    
699
	/* determine which memberships to remove */
700
	foreach ($cur_groups as $groupname) {
701
		if (in_array($groupname, $new_groups)) {
702
			continue;
703
		}
704
		if (!isset($config['system']['group'][$groupindex[$groupname]])) {
705
			continue;
706
		}
707
		$group = & $config['system']['group'][$groupindex[$groupname]];
708
		if (is_array($group['member'])) {
709
			$index = array_search($user['uid'], $group['member']);
710
			array_splice($group['member'], $index, 1);
711
			$mod_groups[] = $group;
712
		}
713
	}
714
	unset($group);
715

    
716
	/* sync all modified groups */
717
	foreach ($mod_groups as $group) {
718
		local_group_set($group);
719
	}
720
}
721

    
722
function local_group_del_user($user) {
723
	global $config;
724

    
725
	if (!is_array($config['system']['group'])) {
726
		return;
727
	}
728

    
729
	foreach ($config['system']['group'] as $group) {
730
		if (is_array($group['member'])) {
731
			foreach ($group['member'] as $idx => $uid) {
732
				if ($user['uid'] == $uid) {
733
					unset($config['system']['group']['member'][$idx]);
734
				}
735
			}
736
		}
737
	}
738
}
739

    
740
function local_group_set($group, $reset = false) {
741
	global $debug;
742

    
743
	$group_name = $group['name'];
744
	$group_gid = $group['gid'];
745
	$group_members = '';
746
	if (!$reset && !empty($group['member']) && count($group['member']) > 0) {
747
		$group_members = implode(",", $group['member']);
748
	}
749

    
750
	if (empty($group_name) || $group['scope'] == "remote") {
751
		return;
752
	}
753

    
754
	/* determine add or mod */
755
	if (mwexec("/usr/sbin/pw groupshow -g " . escapeshellarg($group_gid) . " 2>&1", true) == 0) {
756
		$group_op = "groupmod -l";
757
	} else {
758
		$group_op = "groupadd -n";
759
	}
760

    
761
	/* add or mod group db */
762
	$cmd = "/usr/sbin/pw {$group_op} " .
763
		escapeshellarg($group_name) .
764
		" -g " . escapeshellarg($group_gid) .
765
		" -M " . escapeshellarg($group_members) . " 2>&1";
766

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

    
772
}
773

    
774
function local_group_del($group) {
775
	global $debug;
776

    
777
	/* delete from group db */
778
	$cmd = "/usr/sbin/pw groupdel " . escapeshellarg($group['name']);
779

    
780
	if ($debug) {
781
		log_error(sprintf(gettext("Running: %s"), $cmd));
782
	}
783
	mwexec($cmd);
784
}
785

    
786
function ldap_test_connection($authcfg) {
787
	global $debug, $config, $g;
788

    
789
	if ($authcfg) {
790
		if (strstr($authcfg['ldap_urltype'], "Standard")) {
791
			$ldapproto = "ldap";
792
		} else {
793
			$ldapproto = "ldaps";
794
		}
795
		$ldapserver = "{$ldapproto}://" . ldap_format_host($authcfg['host']);
796
		$ldapport = $authcfg['ldap_port'];
797
		if (!empty($ldapport)) {
798
			$ldapserver .= ":{$ldapport}";
799
		}
800
		$ldapbasedn = $authcfg['ldap_basedn'];
801
		$ldapbindun = $authcfg['ldap_binddn'];
802
		$ldapbindpw = $authcfg['ldap_bindpw'];
803
	} else {
804
		return false;
805
	}
806

    
807
	/* first check if there is even an LDAP server populated */
808
	if (!$ldapserver) {
809
		return false;
810
	}
811

    
812
	/* Setup CA environment if needed. */
813
	ldap_setup_caenv($authcfg);
814

    
815
	/* connect and see if server is up */
816
	$error = false;
817
	if (!($ldap = ldap_connect($ldapserver))) {
818
		$error = true;
819
	}
820

    
821
	if ($error == true) {
822
		log_error(sprintf(gettext("ERROR!  Could not connect to server %s."), $ldapname));
823
		return false;
824
	}
825

    
826
	return true;
827
}
828

    
829
function ldap_setup_caenv($authcfg) {
830
	global $g;
831
	require_once("certs.inc");
832

    
833
	unset($caref);
834
	if (empty($authcfg['ldap_caref']) || !strstr($authcfg['ldap_urltype'], "SSL")) {
835
		putenv('LDAPTLS_REQCERT=never');
836
		return;
837
	} else {
838
		$caref = lookup_ca($authcfg['ldap_caref']);
839
		if (!$caref) {
840
			log_error(sprintf(gettext("LDAP: Could not lookup CA by reference for host %s."), $authcfg['ldap_caref']));
841
			/* XXX: Prevent for credential leaking since we cannot setup the CA env. Better way? */
842
			putenv('LDAPTLS_REQCERT=hard');
843
			return;
844
		}
845
		if (!is_dir("{$g['varrun_path']}/certs")) {
846
			@mkdir("{$g['varrun_path']}/certs");
847
		}
848
		if (file_exists("{$g['varrun_path']}/certs/{$caref['refid']}.ca")) {
849
			@unlink("{$g['varrun_path']}/certs/{$caref['refid']}.ca");
850
		}
851
		file_put_contents("{$g['varrun_path']}/certs/{$caref['refid']}.ca", base64_decode($caref['crt']));
852
		@chmod("{$g['varrun_path']}/certs/{$caref['refid']}.ca", 0600);
853
		putenv('LDAPTLS_REQCERT=hard');
854
		/* XXX: Probably even the hashed link should be created for this? */
855
		putenv("LDAPTLS_CACERTDIR={$g['varrun_path']}/certs");
856
		putenv("LDAPTLS_CACERT={$g['varrun_path']}/certs/{$caref['refid']}.ca");
857
	}
858
}
859

    
860
function ldap_test_bind($authcfg) {
861
	global $debug, $config, $g;
862

    
863
	if ($authcfg) {
864
		if (strstr($authcfg['ldap_urltype'], "Standard")) {
865
			$ldapproto = "ldap";
866
		} else {
867
			$ldapproto = "ldaps";
868
		}
869
		$ldapserver = "{$ldapproto}://" . ldap_format_host($authcfg['host']);
870
		$ldapport = $authcfg['ldap_port'];
871
		if (!empty($ldapport)) {
872
			$ldapserver .= ":{$ldapport}";
873
		}
874
		$ldapbasedn = $authcfg['ldap_basedn'];
875
		$ldapbindun = $authcfg['ldap_binddn'];
876
		$ldapbindpw = $authcfg['ldap_bindpw'];
877
		$ldapver = $authcfg['ldap_protver'];
878
		$ldaptimeout = is_numeric($authcfg['ldap_timeout']) ? $authcfg['ldap_timeout'] : 5;
879
		if (empty($ldapbndun) || empty($ldapbindpw)) {
880
			$ldapanon = true;
881
		} else {
882
			$ldapanon = false;
883
		}
884
	} else {
885
		return false;
886
	}
887

    
888
	/* first check if there is even an LDAP server populated */
889
	if (!$ldapserver) {
890
		return false;
891
	}
892

    
893
	/* Setup CA environment if needed. */
894
	ldap_setup_caenv($authcfg);
895

    
896
	/* connect and see if server is up */
897
	$error = false;
898
	if (!($ldap = ldap_connect($ldapserver))) {
899
		$error = true;
900
	}
901

    
902
	if ($error == true) {
903
		log_error(sprintf(gettext("ERROR!  Could not connect to server %s."), $ldapname));
904
		return false;
905
	}
906

    
907
	ldap_set_option($ldap, LDAP_OPT_REFERRALS, 0);
908
	ldap_set_option($ldap, LDAP_OPT_DEREF, LDAP_DEREF_SEARCHING);
909
	ldap_set_option($ldap, LDAP_OPT_PROTOCOL_VERSION, (int)$ldapver);
910
	ldap_set_option($ldap, LDAP_OPT_TIMELIMIT, (int)$ldaptimeout);
911
	ldap_set_option($ldap, LDAP_OPT_NETWORK_TIMEOUT, (int)$ldaptimeout);
912

    
913
	$ldapbindun = isset($authcfg['ldap_utf8']) ? utf8_encode($ldapbindun) : $ldapbindun;
914
	$ldapbindpw = isset($authcfg['ldap_utf8']) ? utf8_encode($ldapbindpw) : $ldapbindpw;
915
	if ($ldapanon == true) {
916
		if (!($res = @ldap_bind($ldap))) {
917
			@ldap_close($ldap);
918
			return false;
919
		}
920
	} else if (!($res = @ldap_bind($ldap, $ldapbindun, $ldapbindpw))) {
921
		@ldap_close($ldap);
922
		return false;
923
	}
924

    
925
	@ldap_unbind($ldap);
926

    
927
	return true;
928
}
929

    
930
function ldap_get_user_ous($show_complete_ou=true, $authcfg) {
931
	global $debug, $config, $g;
932

    
933
	if (!function_exists("ldap_connect")) {
934
		return;
935
	}
936

    
937
	$ous = array();
938

    
939
	if ($authcfg) {
940
		if (strstr($authcfg['ldap_urltype'], "Standard")) {
941
			$ldapproto = "ldap";
942
		} else {
943
			$ldapproto = "ldaps";
944
		}
945
		$ldapserver = "{$ldapproto}://" . ldap_format_host($authcfg['host']);
946
		$ldapport = $authcfg['ldap_port'];
947
		if (!empty($ldapport)) {
948
			$ldapserver .= ":{$ldapport}";
949
		}
950
		$ldapbasedn = $authcfg['ldap_basedn'];
951
		$ldapbindun = $authcfg['ldap_binddn'];
952
		$ldapbindpw = $authcfg['ldap_bindpw'];
953
		$ldapver = $authcfg['ldap_protver'];
954
		if (empty($ldapbindun) || empty($ldapbindpw)) {
955
			$ldapanon = true;
956
		} else {
957
			$ldapanon = false;
958
		}
959
		$ldapname = $authcfg['name'];
960
		$ldapfallback = false;
961
		$ldapscope = $authcfg['ldap_scope'];
962
		$ldaptimeout = is_numeric($authcfg['ldap_timeout']) ? $authcfg['ldap_timeout'] : 5;
963
	} else {
964
		return false;
965
	}
966

    
967
	/* first check if there is even an LDAP server populated */
968
	if (!$ldapserver) {
969
		log_error(gettext("ERROR!  ldap_get_user_ous() backed selected with no LDAP authentication server defined."));
970
		return $ous;
971
	}
972

    
973
	/* Setup CA environment if needed. */
974
	ldap_setup_caenv($authcfg);
975

    
976
	/* connect and see if server is up */
977
	$error = false;
978
	if (!($ldap = ldap_connect($ldapserver))) {
979
		$error = true;
980
	}
981

    
982
	if ($error == true) {
983
		log_error(sprintf(gettext("ERROR!  Could not connect to server %s."), $ldapname));
984
		return $ous;
985
	}
986

    
987
	$ldapfilter = "(|(ou=*)(cn=Users))";
988

    
989
	ldap_set_option($ldap, LDAP_OPT_REFERRALS, 0);
990
	ldap_set_option($ldap, LDAP_OPT_DEREF, LDAP_DEREF_SEARCHING);
991
	ldap_set_option($ldap, LDAP_OPT_PROTOCOL_VERSION, (int)$ldapver);
992
	ldap_set_option($ldap, LDAP_OPT_TIMELIMIT, (int)$ldaptimeout);
993
	ldap_set_option($ldap, LDAP_OPT_NETWORK_TIMEOUT, (int)$ldaptimeout);
994

    
995
	$ldapbindun = isset($authcfg['ldap_utf8']) ? utf8_encode($ldapbindun) : $ldapbindun;
996
	$ldapbindpw = isset($authcfg['ldap_utf8']) ? utf8_encode($ldapbindpw) : $ldapbindpw;
997
	if ($ldapanon == true) {
998
		if (!($res = @ldap_bind($ldap))) {
999
			log_error(sprintf(gettext("ERROR! ldap_get_user_ous() could not bind anonymously to server %s."), $ldapname));
1000
			@ldap_close($ldap);
1001
			return $ous;
1002
		}
1003
	} else if (!($res = @ldap_bind($ldap, $ldapbindun, $ldapbindpw))) {
1004
		log_error(sprintf(gettext("ERROR! ldap_get_user_ous() could not bind to server %s."), $ldapname));
1005
		@ldap_close($ldap);
1006
		return $ous;
1007
	}
1008

    
1009
	if ($ldapscope == "one") {
1010
		$ldapfunc = "ldap_list";
1011
	} else {
1012
		$ldapfunc = "ldap_search";
1013
	}
1014

    
1015
	$search = @$ldapfunc($ldap, $ldapbasedn, $ldapfilter);
1016
	$info = @ldap_get_entries($ldap, $search);
1017

    
1018
	if (is_array($info)) {
1019
		foreach ($info as $inf) {
1020
			if (!$show_complete_ou) {
1021
				$inf_split = explode(",", $inf['dn']);
1022
				$ou = $inf_split[0];
1023
				$ou = str_replace("OU=", "", $ou);
1024
				$ou = str_replace("CN=", "", $ou);
1025
			} else {
1026
				if ($inf['dn']) {
1027
					$ou = $inf['dn'];
1028
				}
1029
			}
1030
			if ($ou) {
1031
				$ous[] = $ou;
1032
			}
1033
		}
1034
	}
1035

    
1036
	@ldap_unbind($ldap);
1037

    
1038
	return $ous;
1039
}
1040

    
1041
function ldap_get_groups($username, $authcfg) {
1042
	global $debug, $config;
1043

    
1044
	if (!function_exists("ldap_connect")) {
1045
		return;
1046
	}
1047

    
1048
	if (!$username) {
1049
		return false;
1050
	}
1051

    
1052
	if (!isset($authcfg['ldap_nostrip_at']) && stristr($username, "@")) {
1053
		$username_split = explode("@", $username);
1054
		$username = $username_split[0];
1055
	}
1056

    
1057
	if (stristr($username, "\\")) {
1058
		$username_split = explode("\\", $username);
1059
		$username = $username_split[0];
1060
	}
1061

    
1062
	//log_error("Getting LDAP groups for {$username}.");
1063
	if ($authcfg) {
1064
		if (strstr($authcfg['ldap_urltype'], "Standard")) {
1065
			$ldapproto = "ldap";
1066
		} else {
1067
			$ldapproto = "ldaps";
1068
		}
1069
		$ldapserver = "{$ldapproto}://" . ldap_format_host($authcfg['host']);
1070
		$ldapport = $authcfg['ldap_port'];
1071
		if (!empty($ldapport)) {
1072
			$ldapserver .= ":{$ldapport}";
1073
		}
1074
		$ldapbasedn = $authcfg['ldap_basedn'];
1075
		$ldapbindun = $authcfg['ldap_binddn'];
1076
		$ldapbindpw = $authcfg['ldap_bindpw'];
1077
		$ldapauthcont = $authcfg['ldap_authcn'];
1078
		$ldapnameattribute = strtolower($authcfg['ldap_attr_user']);
1079
		$ldapgroupattribute = strtolower($authcfg['ldap_attr_member']);
1080
		if (isset($authcfg['ldap_rfc2307'])) {
1081
			$ldapfilter         = "(&(objectClass={$authcfg['ldap_attr_groupobj']})({$ldapgroupattribute}={$username}))";
1082
		} else {
1083
			$ldapfilter         = "({$ldapnameattribute}={$username})";
1084
		}
1085
		$ldaptype = "";
1086
		$ldapver = $authcfg['ldap_protver'];
1087
		if (empty($ldapbindun) || empty($ldapbindpw)) {
1088
			$ldapanon = true;
1089
		} else {
1090
			$ldapanon = false;
1091
		}
1092
		$ldapname = $authcfg['name'];
1093
		$ldapfallback = false;
1094
		$ldapscope = $authcfg['ldap_scope'];
1095
		$ldaptimeout = is_numeric($authcfg['ldap_timeout']) ? $authcfg['ldap_timeout'] : 5;
1096
	} else {
1097
		return false;
1098
	}
1099

    
1100
	if (isset($authcfg['ldap_rfc2307'])) {
1101
		$ldapdn = $ldapbasedn;
1102
	} else {
1103
		$ldapdn = $_SESSION['ldapdn'];
1104
	}
1105

    
1106
	/*Convert attribute to lowercase.  php ldap arrays put everything in lowercase */
1107
	$ldapgroupattribute = strtolower($ldapgroupattribute);
1108
	$memberof = array();
1109

    
1110
	/* Setup CA environment if needed. */
1111
	ldap_setup_caenv($authcfg);
1112

    
1113
	/* connect and see if server is up */
1114
	$error = false;
1115
	if (!($ldap = ldap_connect($ldapserver))) {
1116
		$error = true;
1117
	}
1118

    
1119
	if ($error == true) {
1120
		log_error(sprintf(gettext("ERROR! ldap_get_groups() Could not connect to server %s."), $ldapname));
1121
		return memberof;
1122
	}
1123

    
1124
	ldap_set_option($ldap, LDAP_OPT_REFERRALS, 0);
1125
	ldap_set_option($ldap, LDAP_OPT_DEREF, LDAP_DEREF_SEARCHING);
1126
	ldap_set_option($ldap, LDAP_OPT_PROTOCOL_VERSION, (int)$ldapver);
1127
	ldap_set_option($ldap, LDAP_OPT_TIMELIMIT, (int)$ldaptimeout);
1128
	ldap_set_option($ldap, LDAP_OPT_NETWORK_TIMEOUT, (int)$ldaptimeout);
1129

    
1130
	/* bind as user that has rights to read group attributes */
1131
	$ldapbindun = isset($authcfg['ldap_utf8']) ? utf8_encode($ldapbindun) : $ldapbindun;
1132
	$ldapbindpw = isset($authcfg['ldap_utf8']) ? utf8_encode($ldapbindpw) : $ldapbindpw;
1133
	if ($ldapanon == true) {
1134
		if (!($res = @ldap_bind($ldap))) {
1135
			log_error(sprintf(gettext("ERROR! ldap_get_groups() could not bind anonymously to server %s."), $ldapname));
1136
			@ldap_close($ldap);
1137
			return false;
1138
		}
1139
	} else if (!($res = @ldap_bind($ldap, $ldapbindun, $ldapbindpw))) {
1140
		log_error(sprintf(gettext("ERROR! ldap_get_groups() could not bind to server %s."), $ldapname));
1141
		@ldap_close($ldap);
1142
		return memberof;
1143
	}
1144

    
1145
	/* get groups from DN found */
1146
	/* use ldap_read instead of search so we don't have to do a bunch of extra work */
1147
	/* since we know the DN is in $_SESSION['ldapdn'] */
1148
	//$search    = ldap_read($ldap, $ldapdn, "(objectclass=*)", array($ldapgroupattribute));
1149
	if ($ldapscope == "one") {
1150
		$ldapfunc = "ldap_list";
1151
	} else {
1152
		$ldapfunc = "ldap_search";
1153
	}
1154

    
1155
	$search = @$ldapfunc($ldap, $ldapdn, $ldapfilter, array($ldapgroupattribute));
1156
	$info = @ldap_get_entries($ldap, $search);
1157

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

    
1160
	if (is_array($gresults)) {
1161
		/* Iterate through the groups and throw them into an array */
1162
		foreach ($gresults as $grp) {
1163
			if (((isset($authcfg['ldap_rfc2307'])) && (stristr($grp["dn"], "CN=") !== false)) ||
1164
			    ((!isset($authcfg['ldap_rfc2307'])) && (stristr($grp, "CN=") !== false))) {
1165
				$grpsplit = isset($authcfg['ldap_rfc2307']) ? explode(",", $grp["dn"]) : explode(",", $grp);
1166
				$memberof[] = preg_replace("/CN=/i", "", $grpsplit[0]);
1167
			}
1168
		}
1169
	}
1170

    
1171
	/* Time to close LDAP connection */
1172
	@ldap_unbind($ldap);
1173

    
1174
	$groups = print_r($memberof, true);
1175

    
1176
	//log_error("Returning groups ".$groups." for user $username");
1177

    
1178
	return $memberof;
1179
}
1180

    
1181
function ldap_format_host($host) {
1182
	return is_ipaddrv6($host) ? "[$host]" : $host ;
1183
}
1184

    
1185
function ldap_backed($username, $passwd, $authcfg) {
1186
	global $debug, $config;
1187

    
1188
	if (!$username) {
1189
		return;
1190
	}
1191

    
1192
	if (!function_exists("ldap_connect")) {
1193
		return;
1194
	}
1195

    
1196
	if (!isset($authcfg['ldap_nostrip_at']) && stristr($username, "@")) {
1197
		$username_split = explode("@", $username);
1198
		$username = $username_split[0];
1199
	}
1200
	if (stristr($username, "\\")) {
1201
		$username_split = explode("\\", $username);
1202
		$username = $username_split[0];
1203
	}
1204

    
1205
	if ($authcfg) {
1206
		if (strstr($authcfg['ldap_urltype'], "Standard")) {
1207
			$ldapproto = "ldap";
1208
		} else {
1209
			$ldapproto = "ldaps";
1210
		}
1211
		$ldapserver = "{$ldapproto}://" . ldap_format_host($authcfg['host']);
1212
		$ldapport = $authcfg['ldap_port'];
1213
		if (!empty($ldapport)) {
1214
			$ldapserver .= ":{$ldapport}";
1215
		}
1216
		$ldapbasedn = $authcfg['ldap_basedn'];
1217
		$ldapbindun = $authcfg['ldap_binddn'];
1218
		$ldapbindpw = $authcfg['ldap_bindpw'];
1219
		if (empty($ldapbindun) || empty($ldapbindpw)) {
1220
			$ldapanon = true;
1221
		} else {
1222
			$ldapanon = false;
1223
		}
1224
		$ldapauthcont = $authcfg['ldap_authcn'];
1225
		$ldapnameattribute = strtolower($authcfg['ldap_attr_user']);
1226
		$ldapextendedqueryenabled = $authcfg['ldap_extended_enabled'];
1227
		$ldapextendedquery = $authcfg['ldap_extended_query'];
1228
		$ldapfilter = "";
1229
		if (!$ldapextendedqueryenabled) {
1230
			$ldapfilter = "({$ldapnameattribute}={$username})";
1231
		} else {
1232
			$ldapfilter = "(&({$ldapnameattribute}={$username})({$ldapextendedquery}))";
1233
		}
1234
		$ldaptype = "";
1235
		$ldapver = $authcfg['ldap_protver'];
1236
		$ldapname = $authcfg['name'];
1237
		$ldapscope = $authcfg['ldap_scope'];
1238
		$ldaptimeout = is_numeric($authcfg['ldap_timeout']) ? $authcfg['ldap_timeout'] : 5;
1239
	} else {
1240
		return false;
1241
	}
1242

    
1243
	/* first check if there is even an LDAP server populated */
1244
	if (!$ldapserver) {
1245
		if ($ldapfallback) {
1246
			log_error(gettext("ERROR! ldap_backed() called with no LDAP authentication server defined.  Defaulting to local user database. Visit System -> User Manager."));
1247
			return local_backed($username, $passwd);
1248
		} else {
1249
			log_error(gettext("ERROR! ldap_backed() called with no LDAP authentication server defined."));
1250
		}
1251

    
1252
		return false;
1253
	}
1254

    
1255
	/* Setup CA environment if needed. */
1256
	ldap_setup_caenv($authcfg);
1257

    
1258
	ldap_set_option($ldap, LDAP_OPT_REFERRALS, 0);
1259
	ldap_set_option($ldap, LDAP_OPT_DEREF, LDAP_DEREF_SEARCHING);
1260
	ldap_set_option($ldap, LDAP_OPT_PROTOCOL_VERSION, (int)$ldapver);
1261
	ldap_set_option($ldap, LDAP_OPT_TIMELIMIT, (int)$ldaptimeout);
1262
	ldap_set_option($ldap, LDAP_OPT_NETWORK_TIMEOUT, (int)$ldaptimeout);
1263

    
1264
	/* Make sure we can connect to LDAP */
1265
	$error = false;
1266
	if (!($ldap = ldap_connect($ldapserver))) {
1267
		$error = true;
1268
	}
1269

    
1270
	if ($error == true) {
1271
		log_error(sprintf(gettext("ERROR!  Could not connect to server %s."), $ldapname));
1272
		return false;
1273
	}
1274

    
1275
	/* ok, its up.  now, lets bind as the bind user so we can search it */
1276
	$error = false;
1277
	$ldapbindun = isset($authcfg['ldap_utf8']) ? utf8_encode($ldapbindun) : $ldapbindun;
1278
	$ldapbindpw = isset($authcfg['ldap_utf8']) ? utf8_encode($ldapbindpw) : $ldapbindpw;
1279
	if ($ldapanon == true) {
1280
		if (!($res = @ldap_bind($ldap))) {
1281
			$error = true;
1282
		}
1283
	} else if (!($res = @ldap_bind($ldap, $ldapbindun, $ldapbindpw))) {
1284
		$error = true;
1285
	}
1286

    
1287
	if ($error == true) {
1288
		@ldap_close($ldap);
1289
		log_error(sprintf(gettext("ERROR! Could not bind to server %s."), $ldapname));
1290
		return false;
1291
	}
1292

    
1293
	/* Get LDAP Authcontainers and split em up. */
1294
	$ldac_splits = explode(";", $ldapauthcont);
1295

    
1296
	/* setup the usercount so we think we haven't found anyone yet */
1297
	$usercount = 0;
1298

    
1299
	/*****************************************************************/
1300
	/*  We first find the user based on username and filter          */
1301
	/*  then, once we find the first occurrence of that person       */
1302
	/*  we set session variables to point to the OU and DN of the    */
1303
	/*  person.  To later be used by ldap_get_groups.                */
1304
	/*  that way we don't have to search twice.                      */
1305
	/*****************************************************************/
1306
	if ($debug) {
1307
		log_auth(sprintf(gettext("Now Searching for %s in directory."), $username));
1308
	}
1309
	/* Iterate through the user containers for search */
1310
	foreach ($ldac_splits as $i => $ldac_split) {
1311
		$ldac_split = isset($authcfg['ldap_utf8']) ? utf8_encode($ldac_split) : $ldac_split;
1312
		$ldapfilter = isset($authcfg['ldap_utf8']) ? utf8_encode($ldapfilter) : $ldapfilter;
1313
		$ldapsearchbasedn = isset($authcfg['ldap_utf8']) ? utf8_encode("{$ldac_split},{$ldapbasedn}") : "{$ldac_split},{$ldapbasedn}";
1314
		/* Make sure we just use the first user we find */
1315
		if ($debug) {
1316
			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)));
1317
		}
1318
		if ($ldapscope == "one") {
1319
			$ldapfunc = "ldap_list";
1320
		} else {
1321
			$ldapfunc = "ldap_search";
1322
		}
1323
		/* Support legacy auth container specification. */
1324
		if (stristr($ldac_split, "DC=") || empty($ldapbasedn)) {
1325
			$search = @$ldapfunc($ldap, $ldac_split, $ldapfilter);
1326
		} else {
1327
			$search = @$ldapfunc($ldap, $ldapsearchbasedn, $ldapfilter);
1328
		}
1329
		if (!$search) {
1330
			log_error(sprintf(gettext("Search resulted in error: %s"), ldap_error($ldap)));
1331
			continue;
1332
		}
1333
		$info = ldap_get_entries($ldap, $search);
1334
		$matches = $info['count'];
1335
		if ($matches == 1) {
1336
			$userdn = $_SESSION['ldapdn'] = $info[0]['dn'];
1337
			$_SESSION['ldapou'] = $ldac_split[$i];
1338
			$_SESSION['ldapon'] = "true";
1339
			$usercount = 1;
1340
			break;
1341
		}
1342
	}
1343

    
1344
	if ($usercount != 1) {
1345
		@ldap_unbind($ldap);
1346
		log_error(gettext("ERROR! Either LDAP search failed, or multiple users were found."));
1347
		return false;
1348
	}
1349

    
1350
	/* Now lets bind as the user we found */
1351
	$passwd = isset($authcfg['ldap_utf8']) ? utf8_encode($passwd) : $passwd;
1352
	if (!($res = @ldap_bind($ldap, $userdn, $passwd))) {
1353
		log_error(sprintf(gettext('ERROR! Could not login to server %1$s as user %2$s: %3$s'), $ldapname, $username, ldap_error($ldap)));
1354
		@ldap_unbind($ldap);
1355
		return false;
1356
	}
1357

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

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

    
1366
	return true;
1367
}
1368

    
1369
function radius_backed($username, $passwd, $authcfg, &$attributes = array()) {
1370
	global $debug, $config;
1371
	$ret = false;
1372

    
1373
	require_once("radius.inc");
1374

    
1375
	$rauth = new Auth_RADIUS_PAP($username, $passwd);
1376
	if ($authcfg) {
1377
		$radiusservers = array();
1378
		$radiusservers[0]['ipaddr'] = $authcfg['host'];
1379
		$radiusservers[0]['port'] = $authcfg['radius_auth_port'];
1380
		$radiusservers[0]['sharedsecret'] = $authcfg['radius_secret'];
1381
		$radiusservers[0]['timeout'] = $authcfg['radius_timeout'];
1382
	} else {
1383
		return false;
1384
	}
1385

    
1386
	/* Add new servers to our instance */
1387
	foreach ($radiusservers as $radsrv) {
1388
		$timeout = (is_numeric($radsrv['timeout'])) ? $radsrv['timeout'] : 5;
1389
		$rauth->addServer($radsrv['ipaddr'], $radsrv['port'], $radsrv['sharedsecret'], $timeout);
1390
	}
1391

    
1392
	if (PEAR::isError($rauth->start())) {
1393
		$retvalue['auth_val'] = 1;
1394
		$retvalue['error'] = $rauth->getError();
1395
		if ($debug) {
1396
			printf(gettext("RADIUS start: %s<br />\n"), $retvalue['error']);
1397
		}
1398
	}
1399

    
1400
	// XXX - billm - somewhere in here we need to handle securid challenge/response
1401

    
1402
	/* Send request */
1403
	$result = $rauth->send();
1404
	if (PEAR::isError($result)) {
1405
		$retvalue['auth_val'] = 1;
1406
		$retvalue['error'] = $result->getMessage();
1407
		if ($debug) {
1408
			printf(gettext("RADIUS send failed: %s<br />\n"), $retvalue['error']);
1409
		}
1410
	} else if ($result === true) {
1411
		if ($rauth->getAttributes()) {
1412
			$attributes = $rauth->listAttributes();
1413
		}
1414
		$retvalue['auth_val'] = 2;
1415
		if ($debug) {
1416
			printf(gettext("RADIUS Auth succeeded")."<br />\n");
1417
		}
1418
		$ret = true;
1419
	} else {
1420
		$retvalue['auth_val'] = 3;
1421
		if ($debug) {
1422
			printf(gettext("RADIUS Auth rejected")."<br />\n");
1423
		}
1424
	}
1425

    
1426
	// close OO RADIUS_AUTHENTICATION
1427
	$rauth->close();
1428

    
1429
	return $ret;
1430
}
1431

    
1432
/*
1433
	$attributes must contain a "class" key containing the groups and local
1434
	groups must exist to match.
1435
*/
1436
function radius_get_groups($attributes) {
1437
	$groups = array();
1438
	if (!empty($attributes) && is_array($attributes) && (!empty($attributes['class']) || !empty($attributes['class_int']))) {
1439
		/* Some RADIUS servers return multiple class attributes, so check them all. */
1440
		$groups = array();
1441
		if (!empty($attributes['class']) && is_array($attributes['class'])) {
1442
			foreach ($attributes['class'] as $class) {
1443
				$groups = array_unique(array_merge($groups, explode(";", $class)));
1444
			}
1445
		}
1446

    
1447
		foreach ($groups as & $grp) {
1448
			$grp = trim($grp);
1449
			if (strtolower(substr($grp, 0, 3)) == "ou=") {
1450
				$grp = substr($grp, 3);
1451
			}
1452
		}
1453
	}
1454
	return $groups;
1455
}
1456

    
1457
function get_user_expiration_date($username) {
1458
	$user = getUserEntry($username);
1459
	if ($user['expires']) {
1460
		return $user['expires'];
1461
	}
1462
}
1463

    
1464
function is_account_expired($username) {
1465
	$expirydate = get_user_expiration_date($username);
1466
	if ($expirydate) {
1467
		if (strtotime("-1 day") > strtotime(date("m/d/Y", strtotime($expirydate)))) {
1468
			return true;
1469
		}
1470
	}
1471

    
1472
	return false;
1473
}
1474

    
1475
function is_account_disabled($username) {
1476
	$user = getUserEntry($username);
1477
	if (isset($user['disabled'])) {
1478
		return true;
1479
	}
1480

    
1481
	return false;
1482
}
1483

    
1484
function get_user_settings($username) {
1485
	global $config;
1486
	$settings = array();
1487
	$settings['widgets'] = $config['widgets'];
1488
	$settings['webgui']['dashboardcolumns'] = $config['system']['webgui']['dashboardcolumns'];
1489
	$settings['webgui']['webguihostnamemenu'] = $config['system']['webgui']['webguihostnamemenu'];
1490
	$settings['webgui']['webguicss'] = $config['system']['webgui']['webguicss'];
1491
	$settings['webgui']['dashboardavailablewidgetspanel'] = isset($config['system']['webgui']['dashboardavailablewidgetspanel']);
1492
	$settings['webgui']['webguifixedmenu'] = isset($config['system']['webgui']['webguifixedmenu']);
1493
	$settings['webgui']['webguileftcolumnhyper'] = isset($config['system']['webgui']['webguileftcolumnhyper']);
1494
	$settings['webgui']['systemlogsfilterpanel'] = isset($config['system']['webgui']['systemlogsfilterpanel']);
1495
	$settings['webgui']['systemlogsmanagelogpanel'] = isset($config['system']['webgui']['systemlogsmanagelogpanel']);
1496
	$settings['webgui']['statusmonitoringsettingspanel'] = isset($config['system']['webgui']['statusmonitoringsettingspanel']);
1497
	$settings['webgui']['pagenamefirst'] = isset($config['system']['webgui']['pagenamefirst']);
1498
	$user = getUserEntry($username);
1499
	if (isset($user['customsettings'])) {
1500
		$settings['customsettings'] = true;
1501
		if (isset($user['widgets'])) {
1502
			// This includes the 'sequence', and any widgetname-config per-widget settings.
1503
			$settings['widgets'] = $user['widgets'];
1504
		}
1505
		if (isset($user['dashboardcolumns'])) {
1506
			$settings['webgui']['dashboardcolumns'] = $user['dashboardcolumns'];
1507
		}
1508
		if (isset($user['webguicss'])) {
1509
			$settings['webgui']['webguicss'] = $user['webguicss'];
1510
		}
1511
		if (isset($user['webguihostnamemenu'])) {
1512
			$settings['webgui']['webguihostnamemenu'] = $user['webguihostnamemenu'];
1513
		}
1514
		$settings['webgui']['dashboardavailablewidgetspanel'] = isset($user['dashboardavailablewidgetspanel']);
1515
		$settings['webgui']['webguifixedmenu'] = isset($user['webguifixedmenu']);
1516
		$settings['webgui']['webguileftcolumnhyper'] = isset($user['webguileftcolumnhyper']);
1517
		$settings['webgui']['systemlogsfilterpanel'] = isset($user['systemlogsfilterpanel']);
1518
		$settings['webgui']['systemlogsmanagelogpanel'] = isset($user['systemlogsmanagelogpanel']);
1519
		$settings['webgui']['statusmonitoringsettingspanel'] = isset($user['statusmonitoringsettingspanel']);
1520
		$settings['webgui']['pagenamefirst'] = isset($user['pagenamefirst']);
1521
	} else {
1522
		$settings['customsettings'] = false;
1523
	}
1524

    
1525
	if ($settings['webgui']['dashboardcolumns'] < 1) {
1526
		$settings['webgui']['dashboardcolumns'] = 2;
1527
	}
1528

    
1529
	return $settings;
1530
}
1531

    
1532
function save_widget_settings($username, $settings, $message = "") {
1533
	global $config, $userindex;
1534
	$user = getUserEntry($username);
1535

    
1536
	if (strlen($message) > 0) {
1537
		$msgout = $message;
1538
	} else {
1539
		$msgout = gettext("Widget configuration has been changed.");
1540
	}
1541

    
1542
	if (isset($user['customsettings'])) {
1543
		$config['system']['user'][$userindex[$username]]['widgets'] = $settings;
1544
		write_config($msgout . " " . sprintf(gettext("(User %s)"), $username));
1545
	} else {
1546
		$config['widgets'] = $settings;
1547
		write_config($msgout);
1548
	}
1549
}
1550

    
1551
function auth_get_authserver($name) {
1552
	global $config;
1553

    
1554
	if (is_array($config['system']['authserver'])) {
1555
		foreach ($config['system']['authserver'] as $authcfg) {
1556
			if ($authcfg['name'] == $name) {
1557
				return $authcfg;
1558
			}
1559
		}
1560
	}
1561
	if ($name == "Local Database") {
1562
		return array("name" => gettext("Local Database"), "type" => "Local Auth", "host" => $config['system']['hostname']);
1563
	}
1564
}
1565

    
1566
function auth_get_authserver_list() {
1567
	global $config;
1568

    
1569
	$list = array();
1570

    
1571
	if (is_array($config['system']['authserver'])) {
1572
		foreach ($config['system']['authserver'] as $authcfg) {
1573
			/* Add support for disabled entries? */
1574
			$list[$authcfg['name']] = $authcfg;
1575
		}
1576
	}
1577

    
1578
	$list["Local Database"] = array("name" => gettext("Local Database"), "type" => "Local Auth", "host" => $config['system']['hostname']);
1579
	return $list;
1580
}
1581

    
1582
function getUserGroups($username, $authcfg, &$attributes = array()) {
1583
	global $config;
1584

    
1585
	$allowed_groups = array();
1586

    
1587
	switch ($authcfg['type']) {
1588
		case 'ldap':
1589
			$allowed_groups = @ldap_get_groups($username, $authcfg);
1590
			break;
1591
		case 'radius':
1592
			$allowed_groups = @radius_get_groups($attributes);
1593
			break;
1594
		default:
1595
			$user = getUserEntry($username);
1596
			$allowed_groups = @local_user_get_groups($user, true);
1597
			break;
1598
	}
1599

    
1600
	$member_groups = array();
1601
	if (is_array($config['system']['group'])) {
1602
		foreach ($config['system']['group'] as $group) {
1603
			if (in_array($group['name'], $allowed_groups)) {
1604
				$member_groups[] = $group['name'];
1605
			}
1606
		}
1607
	}
1608

    
1609
	return $member_groups;
1610
}
1611

    
1612
function authenticate_user($username, $password, $authcfg = NULL, &$attributes = array()) {
1613

    
1614
	if (is_array($username) || is_array($password)) {
1615
		return false;
1616
	}
1617

    
1618
	if (!$authcfg) {
1619
		return local_backed($username, $password);
1620
	}
1621

    
1622
	$authenticated = false;
1623
	switch ($authcfg['type']) {
1624
		case 'ldap':
1625
			if (ldap_backed($username, $password, $authcfg)) {
1626
				$authenticated = true;
1627
			}
1628
			break;
1629
		case 'radius':
1630
			if (radius_backed($username, $password, $authcfg, $attributes)) {
1631
				$authenticated = true;
1632
			}
1633
			break;
1634
		default:
1635
			/* lookup user object by name */
1636
			if (local_backed($username, $password)) {
1637
				$authenticated = true;
1638
			}
1639
			break;
1640
		}
1641

    
1642
	return $authenticated;
1643
}
1644

    
1645
function session_auth() {
1646
	global $config, $_SESSION, $page;
1647

    
1648
	// Handle HTTPS httponly and secure flags
1649
	$currentCookieParams = session_get_cookie_params();
1650
	session_set_cookie_params(
1651
		$currentCookieParams["lifetime"],
1652
		$currentCookieParams["path"],
1653
		NULL,
1654
		($config['system']['webgui']['protocol'] == "https"),
1655
		true
1656
	);
1657

    
1658
	if (!session_id()) {
1659
		session_start();
1660
	}
1661

    
1662
	// Detect protocol change
1663
	if (!isset($_POST['login']) && !empty($_SESSION['Logged_In']) && $_SESSION['protocol'] != $config['system']['webgui']['protocol']) {
1664
		return false;
1665
	}
1666

    
1667
	/* Validate incoming login request */
1668
	$attributes = array();
1669
	if (isset($_POST['login']) && !empty($_POST['usernamefld']) && !empty($_POST['passwordfld'])) {
1670
		$authcfg = auth_get_authserver($config['system']['webgui']['authmode']);
1671
		if (authenticate_user($_POST['usernamefld'], $_POST['passwordfld'], $authcfg, $attributes) ||
1672
		    authenticate_user($_POST['usernamefld'], $_POST['passwordfld'])) {
1673
			// Generate a new id to avoid session fixation
1674
			session_regenerate_id();
1675
			$_SESSION['Logged_In'] = "True";
1676
			$_SESSION['Username'] = $_POST['usernamefld'];
1677
			$_SESSION['user_radius_attributes'] = $attributes;
1678
			$_SESSION['last_access'] = time();
1679
			$_SESSION['protocol'] = $config['system']['webgui']['protocol'];
1680
			if (!isset($config['system']['webgui']['quietlogin'])) {
1681
				log_auth(sprintf(gettext("Successful login for user '%1\$s' from: %2\$s"), $_POST['usernamefld'], $_SERVER['REMOTE_ADDR']));
1682
			}
1683
			if (isset($_POST['postafterlogin'])) {
1684
				return true;
1685
			} else {
1686
				if (empty($page)) {
1687
					$page = "/";
1688
				}
1689
				header("Location: {$page}");
1690
			}
1691
			exit;
1692
		} else {
1693
			/* give the user an error message */
1694
			$_SESSION['Login_Error'] = "Username or Password incorrect";
1695
			log_auth("webConfigurator authentication error for '{$_POST['usernamefld']}' from {$_SERVER['REMOTE_ADDR']}");
1696
			if (isAjax()) {
1697
				echo "showajaxmessage('{$_SESSION['Login_Error']}');";
1698
				return;
1699
			}
1700
		}
1701
	}
1702

    
1703
	/* Show login page if they aren't logged in */
1704
	if (empty($_SESSION['Logged_In'])) {
1705
		return false;
1706
	}
1707

    
1708
	/* If session timeout isn't set, we don't mark sessions stale */
1709
	if (!isset($config['system']['webgui']['session_timeout'])) {
1710
		/* Default to 4 hour timeout if one is not set */
1711
		if ($_SESSION['last_access'] < (time() - 14400)) {
1712
			$_GET['logout'] = true;
1713
			$_SESSION['Logout'] = true;
1714
		} else {
1715
			$_SESSION['last_access'] = time();
1716
		}
1717
	} else if (intval($config['system']['webgui']['session_timeout']) == 0) {
1718
		/* only update if it wasn't ajax */
1719
		if (!isAjax()) {
1720
			$_SESSION['last_access'] = time();
1721
		}
1722
	} else {
1723
		/* Check for stale session */
1724
		if ($_SESSION['last_access'] < (time() - ($config['system']['webgui']['session_timeout'] * 60))) {
1725
			$_GET['logout'] = true;
1726
			$_SESSION['Logout'] = true;
1727
		} else {
1728
			/* only update if it wasn't ajax */
1729
			if (!isAjax()) {
1730
				$_SESSION['last_access'] = time();
1731
			}
1732
		}
1733
	}
1734

    
1735
	/* user hit the logout button */
1736
	if (isset($_GET['logout'])) {
1737

    
1738
		if ($_SESSION['Logout']) {
1739
			log_error(sprintf(gettext("Session timed out for user '%1\$s' from: %2\$s"), $_SESSION['Username'], $_SERVER['REMOTE_ADDR']));
1740
		} else {
1741
			log_error(sprintf(gettext("User logged out for user '%1\$s' from: %2\$s"), $_SESSION['Username'], $_SERVER['REMOTE_ADDR']));
1742
		}
1743

    
1744
		/* wipe out $_SESSION */
1745
		$_SESSION = array();
1746

    
1747
		if (isset($_COOKIE[session_name()])) {
1748
			setcookie(session_name(), '', time()-42000, '/');
1749
		}
1750

    
1751
		/* and destroy it */
1752
		session_destroy();
1753

    
1754
		$scriptName = explode("/", $_SERVER["SCRIPT_FILENAME"]);
1755
		$scriptElms = count($scriptName);
1756
		$scriptName = $scriptName[$scriptElms-1];
1757

    
1758
		if (isAjax()) {
1759
			return false;
1760
		}
1761

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

    
1765
		return false;
1766
	}
1767

    
1768
	/*
1769
	 * this is for debugging purpose if you do not want to use Ajax
1770
	 * to submit a HTML form. It basically disables the observation
1771
	 * of the submit event and hence does not trigger Ajax.
1772
	 */
1773
	if ($_GET['disable_ajax']) {
1774
		$_SESSION['NO_AJAX'] = "True";
1775
	}
1776

    
1777
	/*
1778
	 * Same to re-enable Ajax.
1779
	 */
1780
	if ($_GET['enable_ajax']) {
1781
		unset($_SESSION['NO_AJAX']);
1782
	}
1783

    
1784
	return true;
1785
}
1786

    
1787
?>
(1-1/50)