Project

General

Profile

Download (46.1 KB) Statistics
| Branch: | Tag: | Revision:
1
<?php
2
/* $Id$ */
3
/* ====================================================================
4
 *	Copyright (c)  2004-2015  Electric Sheep Fencing, LLC. All rights reserved.
5
 *	Copyright (c)  2004, 2005 Scott Ullrich
6
 *  Copyright (c)  2010 Ermal Luçi
7
 *  Copyright (c)  2005-2006 Bill Marquette <bill.marquette@gmail.com>
8
 *  Copyright (c)  2006 Paul Taylor <paultaylor@winn-dixie.com>Copyright (C) 2003-2006 Manuel Kasper <mk@neon1.net>
9
 *
10
 *	Redistribution and use in source and binary forms, with or without modification,
11
 *	are permitted provided that the following conditions are met:
12
 *
13
 *	1. Redistributions of source code must retain the above copyright notice,
14
 *		this list of conditions and the following disclaimer.
15
 *
16
 *	2. Redistributions in binary form must reproduce the above copyright
17
 *		notice, this list of conditions and the following disclaimer in
18
 *		the documentation and/or other materials provided with the
19
 *		distribution.
20
 *
21
 *	3. All advertising materials mentioning features or use of this software
22
 *		must display the following acknowledgment:
23
 *		"This product includes software developed by the pfSense Project
24
 *		 for use in the pfSense software distribution. (http://www.pfsense.org/).
25
 *
26
 *	4. The names "pfSense" and "pfSense Project" must not be used to
27
 *		 endorse or promote products derived from this software without
28
 *		 prior written permission. For written permission, please contact
29
 *		 coreteam@pfsense.org.
30
 *
31
 *	5. Products derived from this software may not be called "pfSense"
32
 *		nor may "pfSense" appear in their names without prior written
33
 *		permission of the Electric Sheep Fencing, LLC.
34
 *
35
 *	6. Redistributions of any form whatsoever must retain the following
36
 *		acknowledgment:
37
 *
38
 *	"This product includes software developed by the pfSense Project
39
 *	for use in the pfSense software distribution (http://www.pfsense.org/).
40
 *
41
 *	THIS SOFTWARE IS PROVIDED BY THE pfSense PROJECT ``AS IS'' AND ANY
42
 *	EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
43
 *	IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
44
 *	PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE pfSense PROJECT OR
45
 *	ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
46
 *	SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
47
 *	NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
48
 *	LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
49
 *	HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
50
 *	STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
51
 *	ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
52
 *	OF THE POSSIBILITY OF SUCH DAMAGE.
53
 *
54
 *	====================================================================
55
 *
56
 */
57
/*
58
 * NOTE : Portions of the mschapv2 support was based on the BSD licensed CHAP.php
59
 * file courtesy of Michael Retterklieber.
60
 */
61
if (!$do_not_include_config_gui_inc) {
62
	require_once("config.gui.inc");
63
}
64

    
65
// Will be changed to false if security checks fail
66
$security_passed = true;
67

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

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

    
97
	if (is_array($config['dyndnses']['dyndns']) && !$found_host) {
98
		foreach ($config['dyndnses']['dyndns'] as $dyndns) {
99
			if (strcasecmp($dyndns['host'], $http_host) == 0) {
100
				$found_host = true;
101
				break;
102
			}
103
		}
104
	}
105

    
106
	if (is_array($config['dnsupdates']['dnsupdate']) && !$found_host) {
107
		foreach ($config['dnsupdates']['dnsupdate'] as $rfc2136) {
108
			if (strcasecmp($rfc2136['host'], $http_host) == 0) {
109
				$found_host = true;
110
				break;
111
			}
112
		}
113
	}
114

    
115
	if (!empty($config['system']['webgui']['althostnames']) && !$found_host) {
116
		$althosts = explode(" ", $config['system']['webgui']['althostnames']);
117
		foreach ($althosts as $ah) {
118
			if (strcasecmp($ah, $http_host) == 0 or strcasecmp($ah, $_SERVER['SERVER_ADDR']) == 0) {
119
				$found_host = true;
120
				break;
121
			}
122
		}
123
	}
124

    
125
	if ($found_host == false) {
126
		if (!security_checks_disabled()) {
127
			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."));
128
			exit;
129
		}
130
		$security_passed = false;
131
	}
132
}
133

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

    
171
			if (!empty($config['system']['webgui']['althostnames']) && !$found_host) {
172
				$althosts = explode(" ", $config['system']['webgui']['althostnames']);
173
				foreach ($althosts as $ah) {
174
					if (strcasecmp($referrer_host, $ah) == 0) {
175
						$found_host = true;
176
						break;
177
					}
178
				}
179
			}
180

    
181
			if (is_array($config['dyndnses']['dyndns']) && !$found_host) {
182
				foreach ($config['dyndnses']['dyndns'] as $dyndns) {
183
					if (strcasecmp($dyndns['host'], $referrer_host) == 0) {
184
						$found_host = true;
185
						break;
186
					}
187
				}
188
			}
189

    
190
			if (is_array($config['dnsupdates']['dnsupdate']) && !$found_host) {
191
				foreach ($config['dnsupdates']['dnsupdate'] as $rfc2136) {
192
					if (strcasecmp($rfc2136['host'], $referrer_host) == 0) {
193
						$found_host = true;
194
						break;
195
					}
196
				}
197
			}
198

    
199
			if (!$found_host) {
200
				$interface_list_ips = get_configured_ip_addresses();
201
				foreach ($interface_list_ips as $ilips) {
202
					if (strcasecmp($referrer_host, $ilips) == 0) {
203
						$found_host = true;
204
						break;
205
					}
206
				}
207
				$interface_list_ipv6s = get_configured_ipv6_addresses();
208
				foreach ($interface_list_ipv6s as $ilipv6s) {
209
					if (strcasecmp($referrer_host, $ilipv6s) == 0) {
210
						$found_host = true;
211
						break;
212
					}
213
				}
214
				if ($referrer_host == "127.0.0.1" || $referrer_host == "localhost") {
215
					// allow SSH port forwarded connections and links from localhost
216
					$found_host = true;
217
				}
218
			}
219
		}
220
		if ($found_host == false) {
221
			if (!security_checks_disabled()) {
222
				display_error_form("501", "An HTTP_REFERER was detected other than what is defined in System -> Advanced (" . htmlspecialchars($_SERVER['HTTP_REFERER']) . ").  You can disable this check if needed in System -> Advanced -> Admin.");
223
				exit;
224
			}
225
			$security_passed = false;
226
		}
227
	} else {
228
		$security_passed = false;
229
	}
230
}
231

    
232
if (function_exists("display_error_form") && $security_passed) {
233
	/* Security checks passed, so it should be OK to turn them back on */
234
	restore_security_checks();
235
}
236
unset($security_passed);
237

    
238
$groupindex = index_groups();
239
$userindex = index_users();
240

    
241
function index_groups() {
242
	global $g, $debug, $config, $groupindex;
243

    
244
	$groupindex = array();
245

    
246
	if (is_array($config['system']['group'])) {
247
		$i = 0;
248
		foreach ($config['system']['group'] as $groupent) {
249
			$groupindex[$groupent['name']] = $i;
250
			$i++;
251
		}
252
	}
253

    
254
	return ($groupindex);
255
}
256

    
257
function index_users() {
258
	global $g, $debug, $config;
259

    
260
	if (is_array($config['system']['user'])) {
261
		$i = 0;
262
		foreach ($config['system']['user'] as $userent) {
263
			$userindex[$userent['name']] = $i;
264
			$i++;
265
		}
266
	}
267

    
268
	return ($userindex);
269
}
270

    
271
function & getUserEntry($name) {
272
	global $debug, $config, $userindex;
273
	if (isset($userindex[$name])) {
274
		return $config['system']['user'][$userindex[$name]];
275
	}
276
}
277

    
278
function & getUserEntryByUID($uid) {
279
	global $debug, $config;
280

    
281
	if (is_array($config['system']['user'])) {
282
		foreach ($config['system']['user'] as & $user) {
283
			if ($user['uid'] == $uid) {
284
				return $user;
285
			}
286
		}
287
	}
288

    
289
	return false;
290
}
291

    
292
function & getGroupEntry($name) {
293
	global $debug, $config, $groupindex;
294
	if (isset($groupindex[$name])) {
295
		return $config['system']['group'][$groupindex[$name]];
296
	}
297
}
298

    
299
function & getGroupEntryByGID($gid) {
300
	global $debug, $config;
301

    
302
	if (is_array($config['system']['group'])) {
303
		foreach ($config['system']['group'] as & $group) {
304
			if ($group['gid'] == $gid) {
305
				return $group;
306
			}
307
		}
308
	}
309

    
310
	return false;
311
}
312

    
313
function get_user_privileges(& $user) {
314

    
315
	$privs = $user['priv'];
316
	if (!is_array($privs)) {
317
		$privs = array();
318
	}
319

    
320
	$names = local_user_get_groups($user, true);
321

    
322
	foreach ($names as $name) {
323
		$group = getGroupEntry($name);
324
		if (is_array($group['priv'])) {
325
			$privs = array_merge($privs, $group['priv']);
326
		}
327
	}
328

    
329
	return $privs;
330
}
331

    
332
function userHasPrivilege($userent, $privid = false) {
333

    
334
	if (!$privid || !is_array($userent)) {
335
		return false;
336
	}
337

    
338
	$privs = get_user_privileges($userent);
339

    
340
	if (!is_array($privs)) {
341
		return false;
342
	}
343

    
344
	if (!in_array($privid, $privs)) {
345
		return false;
346
	}
347

    
348
	return true;
349
}
350

    
351
function local_backed($username, $passwd) {
352

    
353
	$user = getUserEntry($username);
354
	if (!$user) {
355
		return false;
356
	}
357

    
358
	if (is_account_disabled($username) || is_account_expired($username)) {
359
		return false;
360
	}
361

    
362
	if ($user['password']) {
363
		if (crypt($passwd, $user['password']) == $user['password']) {
364
			return true;
365
		}
366
	}
367

    
368
	if ($user['md5-hash']) {
369
		if (md5($passwd) == $user['md5-hash']) {
370
			return true;
371
		}
372
	}
373

    
374
	return false;
375
}
376

    
377
function local_sync_accounts() {
378
	global $debug, $config;
379
	conf_mount_rw();
380

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

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

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

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

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

    
445
	conf_mount_ro();
446

    
447
}
448

    
449
function local_user_set(& $user) {
450
	global $g, $debug;
451

    
452
	if (empty($user['password'])) {
453
		log_error("There is something wrong in your config because user {$user['name']} password is missing!");
454
		return;
455
	}
456

    
457
	conf_mount_rw();
458

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

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

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

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

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

    
507
	/* read from pw db */
508
	$fd = popen("/usr/sbin/pw usershow -n {$user_name} 2>&1", "r");
509
	$pwread = fgets($fd);
510
	pclose($fd);
511
	$userattrs = explode(":", trim($pwread));
512

    
513
	/* determine add or mod */
514
	if (($userattrs[0] != $user['name']) || (!strncmp($pwread, "pw:", 3))) {
515
		$user_op = "useradd -m -k /etc/skel -o";
516
	} else {
517
		$user_op = "usermod";
518
	}
519

    
520
	$comment = str_replace(array(":", "!", "@"), " ", $user['descr']);
521
	/* add or mod pw db */
522
	$cmd = "/usr/sbin/pw {$user_op} -q -u {$user_uid} -n {$user_name}".
523
			" -g {$user_group} -s {$user_shell} -d {$user_home}".
524
			" -c ".escapeshellarg($comment)." -H 0 2>&1";
525

    
526
	if ($debug) {
527
		log_error(sprintf(gettext("Running: %s"), $cmd));
528
	}
529
	$fd = popen($cmd, "w");
530
	fwrite($fd, $user['password']);
531
	pclose($fd);
532

    
533
	/* create user directory if required */
534
	if (!is_dir($user_home)) {
535
		mkdir($user_home, 0700);
536
	}
537
	@chown($user_home, $user_name);
538
	@chgrp($user_home, $user_group);
539

    
540
	/* write out ssh authorized key file */
541
	if ($user['authorizedkeys']) {
542
		if (!is_dir("{$user_home}/.ssh")) {
543
			@mkdir("{$user_home}/.ssh", 0700);
544
			@chown("{$user_home}/.ssh", $user_name);
545
		}
546
		$keys = base64_decode($user['authorizedkeys']);
547
		@file_put_contents("{$user_home}/.ssh/authorized_keys", $keys);
548
		@chown("{$user_home}/.ssh/authorized_keys", $user_name);
549
	} else {
550
		unlink_if_exists("{$user_home}/.ssh/authorized_keys");
551
	}
552

    
553
	$un = $lock_account ? "" : "un";
554
	exec("/usr/sbin/pw {$un}lock {$user_name} -q 2>/dev/null");
555

    
556
	conf_mount_ro();
557
}
558

    
559
function local_user_del($user) {
560
	global $debug;
561

    
562
	/* remove all memberships */
563
	local_user_set_groups($user);
564

    
565
	/* Don't remove /root */
566
	if ($user['uid'] != 0) {
567
		$rmhome = "-r";
568
	}
569

    
570
	/* read from pw db */
571
	$fd = popen("/usr/sbin/pw usershow -n {$user['name']} 2>&1", "r");
572
	$pwread = fgets($fd);
573
	pclose($fd);
574
	$userattrs = explode(":", trim($pwread));
575

    
576
	if ($userattrs[0] != $user['name']) {
577
		log_error("Tried to remove user {$user['name']} but got user {$userattrs[0]} instead. Bailing.");
578
		return;
579
	}
580

    
581
	/* delete from pw db */
582
	$cmd = "/usr/sbin/pw userdel -n {$user['name']} {$rmhome}";
583

    
584
	if ($debug) {
585
		log_error(sprintf(gettext("Running: %s"), $cmd));
586
	}
587
	mwexec($cmd);
588

    
589
	/* Delete user from groups needs a call to write_config() */
590
	local_group_del_user($user);
591
}
592

    
593
function local_user_set_password(&$user, $password) {
594

    
595
	$user['password'] = crypt($password);
596
	$user['md5-hash'] = md5($password);
597

    
598
	// Converts ascii to unicode.
599
	$astr = (string) $password;
600
	$ustr = '';
601
	for ($i = 0; $i < strlen($astr); $i++) {
602
		$a = ord($astr{$i}) << 8;
603
		$ustr .= sprintf("%X", $a);
604
	}
605

    
606
}
607

    
608
function local_user_get_groups($user, $all = false) {
609
	global $debug, $config;
610

    
611
	$groups = array();
612
	if (!is_array($config['system']['group'])) {
613
		return $groups;
614
	}
615

    
616
	foreach ($config['system']['group'] as $group) {
617
		if ($all || (!$all && ($group['name'] != "all"))) {
618
			if (is_array($group['member'])) {
619
				if (in_array($user['uid'], $group['member'])) {
620
					$groups[] = $group['name'];
621
				}
622
			}
623
		}
624
	}
625

    
626
	if ($all) {
627
		$groups[] = "all";
628
	}
629

    
630
	sort($groups);
631

    
632
	return $groups;
633

    
634
}
635

    
636
function local_user_set_groups($user, $new_groups = NULL) {
637
	global $debug, $config, $groupindex;
638

    
639
	if (!is_array($config['system']['group'])) {
640
		return;
641
	}
642

    
643
	$cur_groups = local_user_get_groups($user, true);
644
	$mod_groups = array();
645

    
646
	if (!is_array($new_groups)) {
647
		$new_groups = array();
648
	}
649

    
650
	if (!is_array($cur_groups)) {
651
		$cur_groups = array();
652
	}
653

    
654
	/* determine which memberships to add */
655
	foreach ($new_groups as $groupname) {
656
		if ($groupname == '' || in_array($groupname, $cur_groups)) {
657
			continue;
658
		}
659
		$group = & $config['system']['group'][$groupindex[$groupname]];
660
		$group['member'][] = $user['uid'];
661
		$mod_groups[] = $group;
662
	}
663
	unset($group);
664

    
665
	/* determine which memberships to remove */
666
	foreach ($cur_groups as $groupname) {
667
		if (in_array($groupname, $new_groups)) {
668
			continue;
669
		}
670
		if (!isset($config['system']['group'][$groupindex[$groupname]])) {
671
			continue;
672
		}
673
		$group = & $config['system']['group'][$groupindex[$groupname]];
674
		if (is_array($group['member'])) {
675
			$index = array_search($user['uid'], $group['member']);
676
			array_splice($group['member'], $index, 1);
677
			$mod_groups[] = $group;
678
		}
679
	}
680
	unset($group);
681

    
682
	/* sync all modified groups */
683
	foreach ($mod_groups as $group) {
684
		local_group_set($group);
685
	}
686
}
687

    
688
function local_group_del_user($user) {
689
	global $config;
690

    
691
	if (!is_array($config['system']['group'])) {
692
		return;
693
	}
694

    
695
	foreach ($config['system']['group'] as $group) {
696
		if (is_array($group['member'])) {
697
			foreach ($group['member'] as $idx => $uid) {
698
				if ($user['uid'] == $uid) {
699
					unset($config['system']['group']['member'][$idx]);
700
				}
701
			}
702
		}
703
	}
704
}
705

    
706
function local_group_set($group, $reset = false) {
707
	global $debug;
708

    
709
	$group_name = $group['name'];
710
	$group_gid = $group['gid'];
711
	$group_members = '';
712
	if (!$reset && !empty($group['member']) && count($group['member']) > 0) {
713
		$group_members = implode(",", $group['member']);
714
	}
715

    
716
	if (empty($group_name)) {
717
		return;
718
	}
719

    
720
	/* read from group db */
721
	$fd = popen("/usr/sbin/pw groupshow {$group_name} 2>&1", "r");
722
	$pwread = fgets($fd);
723
	pclose($fd);
724

    
725
	/* determine add or mod */
726
	if (!strncmp($pwread, "pw:", 3)) {
727
		$group_op = "groupadd";
728
	} else {
729
		$group_op = "groupmod";
730
	}
731

    
732
	/* add or mod group db */
733
	$cmd = "/usr/sbin/pw {$group_op} {$group_name} -g {$group_gid} -M '{$group_members}' 2>&1";
734

    
735
	if ($debug) {
736
		log_error(sprintf(gettext("Running: %s"), $cmd));
737
	}
738
	mwexec($cmd);
739

    
740
}
741

    
742
function local_group_del($group) {
743
	global $debug;
744

    
745
	/* delete from group db */
746
	$cmd = "/usr/sbin/pw groupdel {$group['name']}";
747

    
748
	if ($debug) {
749
		log_error(sprintf(gettext("Running: %s"), $cmd));
750
	}
751
	mwexec($cmd);
752
}
753

    
754
function ldap_test_connection($authcfg) {
755
	global $debug, $config, $g;
756

    
757
	if ($authcfg) {
758
		if (strstr($authcfg['ldap_urltype'], "Standard")) {
759
			$ldapproto = "ldap";
760
		} else {
761
			$ldapproto = "ldaps";
762
		}
763
		$ldapserver = "{$ldapproto}://" . ldap_format_host($authcfg['host']);
764
		$ldapport = $authcfg['ldap_port'];
765
		if (!empty($ldapport)) {
766
			$ldapserver .= ":{$ldapport}";
767
		}
768
		$ldapbasedn = $authcfg['ldap_basedn'];
769
		$ldapbindun = $authcfg['ldap_binddn'];
770
		$ldapbindpw = $authcfg['ldap_bindpw'];
771
	} else {
772
		return false;
773
	}
774

    
775
	/* first check if there is even an LDAP server populated */
776
	if (!$ldapserver) {
777
		return false;
778
	}
779

    
780
	/* Setup CA environment if needed. */
781
	ldap_setup_caenv($authcfg);
782

    
783
	/* connect and see if server is up */
784
	$error = false;
785
	if (!($ldap = ldap_connect($ldapserver))) {
786
		$error = true;
787
	}
788

    
789
	if ($error == true) {
790
		log_error(sprintf(gettext("ERROR!  Could not connect to server %s."), $ldapname));
791
		return false;
792
	}
793

    
794
	return true;
795
}
796

    
797
function ldap_setup_caenv($authcfg) {
798
	global $g;
799
	require_once("certs.inc");
800

    
801
	unset($caref);
802
	if (empty($authcfg['ldap_caref']) || !strstr($authcfg['ldap_urltype'], "SSL")) {
803
		putenv('LDAPTLS_REQCERT=never');
804
		return;
805
	} else {
806
		$caref = lookup_ca($authcfg['ldap_caref']);
807
		if (!$caref) {
808
			log_error(sprintf(gettext("LDAP: Could not lookup CA by reference for host %s."), $authcfg['ldap_caref']));
809
			/* XXX: Prevent for credential leaking since we cannot setup the CA env. Better way? */
810
			putenv('LDAPTLS_REQCERT=hard');
811
			return;
812
		}
813
		if (!is_dir("{$g['varrun_path']}/certs")) {
814
			@mkdir("{$g['varrun_path']}/certs");
815
		}
816
		if (file_exists("{$g['varrun_path']}/certs/{$caref['refid']}.ca")) {
817
			@unlink("{$g['varrun_path']}/certs/{$caref['refid']}.ca");
818
		}
819
		file_put_contents("{$g['varrun_path']}/certs/{$caref['refid']}.ca", base64_decode($caref['crt']));
820
		@chmod("{$g['varrun_path']}/certs/{$caref['refid']}.ca", 0600);
821
		putenv('LDAPTLS_REQCERT=hard');
822
		/* XXX: Probably even the hashed link should be created for this? */
823
		putenv("LDAPTLS_CACERTDIR={$g['varrun_path']}/certs");
824
		putenv("LDAPTLS_CACERT={$g['varrun_path']}/certs/{$caref['refid']}.ca");
825
	}
826
}
827

    
828
function ldap_test_bind($authcfg) {
829
	global $debug, $config, $g;
830

    
831
	if ($authcfg) {
832
		if (strstr($authcfg['ldap_urltype'], "Standard")) {
833
			$ldapproto = "ldap";
834
		} else {
835
			$ldapproto = "ldaps";
836
		}
837
		$ldapserver = "{$ldapproto}://" . ldap_format_host($authcfg['host']);
838
		$ldapport = $authcfg['ldap_port'];
839
		if (!empty($ldapport)) {
840
			$ldapserver .= ":{$ldapport}";
841
		}
842
		$ldapbasedn = $authcfg['ldap_basedn'];
843
		$ldapbindun = $authcfg['ldap_binddn'];
844
		$ldapbindpw = $authcfg['ldap_bindpw'];
845
		$ldapver = $authcfg['ldap_protver'];
846
		$ldaptimeout = is_numeric($authcfg['ldap_timeout']) ? $authcfg['ldap_timeout'] : 25;
847
		if (empty($ldapbndun) || empty($ldapbindpw)) {
848
			$ldapanon = true;
849
		} else {
850
			$ldapanon = false;
851
		}
852
	} else {
853
		return false;
854
	}
855

    
856
	/* first check if there is even an LDAP server populated */
857
	if (!$ldapserver) {
858
		return false;
859
	}
860

    
861
	/* Setup CA environment if needed. */
862
	ldap_setup_caenv($authcfg);
863

    
864
	/* connect and see if server is up */
865
	$error = false;
866
	if (!($ldap = ldap_connect($ldapserver))) {
867
		$error = true;
868
	}
869

    
870
	if ($error == true) {
871
		log_error(sprintf(gettext("ERROR!  Could not connect to server %s."), $ldapname));
872
		return false;
873
	}
874

    
875
	ldap_set_option($ldap, LDAP_OPT_REFERRALS, 0);
876
	ldap_set_option($ldap, LDAP_OPT_DEREF, LDAP_DEREF_SEARCHING);
877
	ldap_set_option($ldap, LDAP_OPT_PROTOCOL_VERSION, (int)$ldapver);
878
	ldap_set_option($ldap, LDAP_OPT_TIMELIMIT, (int)$ldaptimeout);
879
	ldap_set_option($ldap, LDAP_OPT_NETWORK_TIMEOUT, (int)$ldaptimeout);
880

    
881
	$ldapbindun = isset($authcfg['ldap_utf8']) ? utf8_encode($ldapbindun) : $ldapbindun;
882
	$ldapbindpw = isset($authcfg['ldap_utf8']) ? utf8_encode($ldapbindpw) : $ldapbindpw;
883
	if ($ldapanon == true) {
884
		if (!($res = @ldap_bind($ldap))) {
885
			@ldap_close($ldap);
886
			return false;
887
		}
888
	} else if (!($res = @ldap_bind($ldap, $ldapbindun, $ldapbindpw))) {
889
		@ldap_close($ldap);
890
		return false;
891
	}
892

    
893
	@ldap_unbind($ldap);
894

    
895
	return true;
896
}
897

    
898
function ldap_get_user_ous($show_complete_ou=true, $authcfg) {
899
	global $debug, $config, $g;
900

    
901
	if (!function_exists("ldap_connect")) {
902
		return;
903
	}
904

    
905
	$ous = array();
906

    
907
	if ($authcfg) {
908
		if (strstr($authcfg['ldap_urltype'], "Standard")) {
909
			$ldapproto = "ldap";
910
		} else {
911
			$ldapproto = "ldaps";
912
		}
913
		$ldapserver = "{$ldapproto}://" . ldap_format_host($authcfg['host']);
914
		$ldapport = $authcfg['ldap_port'];
915
		if (!empty($ldapport)) {
916
			$ldapserver .= ":{$ldapport}";
917
		}
918
		$ldapbasedn = $authcfg['ldap_basedn'];
919
		$ldapbindun = $authcfg['ldap_binddn'];
920
		$ldapbindpw = $authcfg['ldap_bindpw'];
921
		$ldapver = $authcfg['ldap_protver'];
922
		if (empty($ldapbindun) || empty($ldapbindpw)) {
923
			$ldapanon = true;
924
		} else {
925
			$ldapanon = false;
926
		}
927
		$ldapname = $authcfg['name'];
928
		$ldapfallback = false;
929
		$ldapscope = $authcfg['ldap_scope'];
930
		$ldaptimeout = is_numeric($authcfg['ldap_timeout']) ? $authcfg['ldap_timeout'] : 25;
931
	} else {
932
		return false;
933
	}
934

    
935
	/* first check if there is even an LDAP server populated */
936
	if (!$ldapserver) {
937
		log_error(gettext("ERROR!  ldap_get_user_ous() backed selected with no LDAP authentication server defined."));
938
		return $ous;
939
	}
940

    
941
	/* Setup CA environment if needed. */
942
	ldap_setup_caenv($authcfg);
943

    
944
	/* connect and see if server is up */
945
	$error = false;
946
	if (!($ldap = ldap_connect($ldapserver))) {
947
		$error = true;
948
	}
949

    
950
	if ($error == true) {
951
		log_error(sprintf(gettext("ERROR!  Could not connect to server %s."), $ldapname));
952
		return $ous;
953
	}
954

    
955
	$ldapfilter = "(|(ou=*)(cn=Users))";
956

    
957
	ldap_set_option($ldap, LDAP_OPT_REFERRALS, 0);
958
	ldap_set_option($ldap, LDAP_OPT_DEREF, LDAP_DEREF_SEARCHING);
959
	ldap_set_option($ldap, LDAP_OPT_PROTOCOL_VERSION, (int)$ldapver);
960
	ldap_set_option($ldap, LDAP_OPT_TIMELIMIT, (int)$ldaptimeout);
961
	ldap_set_option($ldap, LDAP_OPT_NETWORK_TIMEOUT, (int)$ldaptimeout);
962

    
963
	$ldapbindun = isset($authcfg['ldap_utf8']) ? utf8_encode($ldapbindun) : $ldapbindun;
964
	$ldapbindpw = isset($authcfg['ldap_utf8']) ? utf8_encode($ldapbindpw) : $ldapbindpw;
965
	if ($ldapanon == true) {
966
		if (!($res = @ldap_bind($ldap))) {
967
			log_error(sprintf(gettext("ERROR! ldap_get_user_ous() could not bind anonymously to server %s."), $ldapname));
968
			@ldap_close($ldap);
969
			return $ous;
970
		}
971
	} else if (!($res = @ldap_bind($ldap, $ldapbindun, $ldapbindpw))) {
972
		log_error(sprintf(gettext("ERROR! ldap_get_user_ous() could not bind to server %s."), $ldapname));
973
		@ldap_close($ldap);
974
		return $ous;
975
	}
976

    
977
	if ($ldapscope == "one") {
978
		$ldapfunc = "ldap_list";
979
	} else {
980
		$ldapfunc = "ldap_search";
981
	}
982

    
983
	$search = @$ldapfunc($ldap, $ldapbasedn, $ldapfilter);
984
	$info = @ldap_get_entries($ldap, $search);
985

    
986
	if (is_array($info)) {
987
		foreach ($info as $inf) {
988
			if (!$show_complete_ou) {
989
				$inf_split = explode(",", $inf['dn']);
990
				$ou = $inf_split[0];
991
				$ou = str_replace("OU=", "", $ou);
992
				$ou = str_replace("CN=", "", $ou);
993
			} else {
994
				if ($inf['dn']) {
995
					$ou = $inf['dn'];
996
				}
997
			}
998
			if ($ou) {
999
				$ous[] = $ou;
1000
			}
1001
		}
1002
	}
1003

    
1004
	@ldap_unbind($ldap);
1005

    
1006
	return $ous;
1007
}
1008

    
1009
function ldap_get_groups($username, $authcfg) {
1010
	global $debug, $config;
1011

    
1012
	if (!function_exists("ldap_connect")) {
1013
		return;
1014
	}
1015

    
1016
	if (!$username) {
1017
		return false;
1018
	}
1019

    
1020
	if (!isset($authcfg['ldap_nostrip_at']) && stristr($username, "@")) {
1021
		$username_split = explode("@", $username);
1022
		$username = $username_split[0];
1023
	}
1024

    
1025
	if (stristr($username, "\\")) {
1026
		$username_split = explode("\\", $username);
1027
		$username = $username_split[0];
1028
	}
1029

    
1030
	//log_error("Getting LDAP groups for {$username}.");
1031
	if ($authcfg) {
1032
		if (strstr($authcfg['ldap_urltype'], "Standard")) {
1033
			$ldapproto = "ldap";
1034
		} else {
1035
			$ldapproto = "ldaps";
1036
		}
1037
		$ldapserver = "{$ldapproto}://" . ldap_format_host($authcfg['host']);
1038
		$ldapport = $authcfg['ldap_port'];
1039
		if (!empty($ldapport)) {
1040
			$ldapserver .= ":{$ldapport}";
1041
		}
1042
		$ldapbasedn = $authcfg['ldap_basedn'];
1043
		$ldapbindun = $authcfg['ldap_binddn'];
1044
		$ldapbindpw = $authcfg['ldap_bindpw'];
1045
		$ldapauthcont = $authcfg['ldap_authcn'];
1046
		$ldapnameattribute = strtolower($authcfg['ldap_attr_user']);
1047
		$ldapgroupattribute = strtolower($authcfg['ldap_attr_member']);
1048
		if (isset($authcfg['ldap_rfc2307'])) {
1049
			$ldapfilter         = "(&(objectClass={$authcfg['ldap_attr_groupobj']})({$ldapgroupattribute}={$username}))";
1050
		} else {
1051
			$ldapfilter         = "({$ldapnameattribute}={$username})";
1052
		}
1053
		$ldaptype = "";
1054
		$ldapver = $authcfg['ldap_protver'];
1055
		if (empty($ldapbindun) || empty($ldapbindpw)) {
1056
			$ldapanon = true;
1057
		} else {
1058
			$ldapanon = false;
1059
		}
1060
		$ldapname = $authcfg['name'];
1061
		$ldapfallback = false;
1062
		$ldapscope = $authcfg['ldap_scope'];
1063
		$ldaptimeout = is_numeric($authcfg['ldap_timeout']) ? $authcfg['ldap_timeout'] : 25;
1064
	} else {
1065
		return false;
1066
	}
1067

    
1068
	if (isset($authcfg['ldap_rfc2307'])) {
1069
		$ldapdn = $ldapbasedn;
1070
	} else {
1071
		$ldapdn = $_SESSION['ldapdn'];
1072
	}
1073

    
1074
	/*Convert attribute to lowercase.  php ldap arrays put everything in lowercase */
1075
	$ldapgroupattribute = strtolower($ldapgroupattribute);
1076
	$memberof = array();
1077

    
1078
	/* Setup CA environment if needed. */
1079
	ldap_setup_caenv($authcfg);
1080

    
1081
	/* connect and see if server is up */
1082
	$error = false;
1083
	if (!($ldap = ldap_connect($ldapserver))) {
1084
		$error = true;
1085
	}
1086

    
1087
	if ($error == true) {
1088
		log_error(sprintf(gettext("ERROR! ldap_get_groups() Could not connect to server %s."), $ldapname));
1089
		return memberof;
1090
	}
1091

    
1092
	ldap_set_option($ldap, LDAP_OPT_REFERRALS, 0);
1093
	ldap_set_option($ldap, LDAP_OPT_DEREF, LDAP_DEREF_SEARCHING);
1094
	ldap_set_option($ldap, LDAP_OPT_PROTOCOL_VERSION, (int)$ldapver);
1095
	ldap_set_option($ldap, LDAP_OPT_TIMELIMIT, (int)$ldaptimeout);
1096
	ldap_set_option($ldap, LDAP_OPT_NETWORK_TIMEOUT, (int)$ldaptimeout);
1097

    
1098
	/* bind as user that has rights to read group attributes */
1099
	$ldapbindun = isset($authcfg['ldap_utf8']) ? utf8_encode($ldapbindun) : $ldapbindun;
1100
	$ldapbindpw = isset($authcfg['ldap_utf8']) ? utf8_encode($ldapbindpw) : $ldapbindpw;
1101
	if ($ldapanon == true) {
1102
		if (!($res = @ldap_bind($ldap))) {
1103
			log_error(sprintf(gettext("ERROR! ldap_get_groups() could not bind anonymously to server %s."), $ldapname));
1104
			@ldap_close($ldap);
1105
			return false;
1106
		}
1107
	} else if (!($res = @ldap_bind($ldap, $ldapbindun, $ldapbindpw))) {
1108
		log_error(sprintf(gettext("ERROR! ldap_get_groups() could not bind to server %s."), $ldapname));
1109
		@ldap_close($ldap);
1110
		return memberof;
1111
	}
1112

    
1113
	/* get groups from DN found */
1114
	/* use ldap_read instead of search so we don't have to do a bunch of extra work */
1115
	/* since we know the DN is in $_SESSION['ldapdn'] */
1116
	//$search    = ldap_read($ldap, $ldapdn, "(objectclass=*)", array($ldapgroupattribute));
1117
	if ($ldapscope == "one") {
1118
		$ldapfunc = "ldap_list";
1119
	} else {
1120
		$ldapfunc = "ldap_search";
1121
	}
1122

    
1123
	$search = @$ldapfunc($ldap, $ldapdn, $ldapfilter, array($ldapgroupattribute));
1124
	$info = @ldap_get_entries($ldap, $search);
1125

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

    
1128
	if(is_array($gresults)) {
1129
		/* Iterate through the groups and throw them into an array */
1130
		foreach ($gresults as $grp) {
1131
			if (((isset($authcfg['ldap_rfc2307'])) && (stristr($grp["dn"], "CN=") !== false))
1132
				|| ((!isset($authcfg['ldap_rfc2307'])) && (stristr($grp, "CN=") !== false))) {
1133
				$grpsplit = isset($authcfg['ldap_rfc2307']) ? explode(",", $grp["dn"]) : explode(",", $grp);
1134
				$memberof[] = preg_replace("/CN=/i", "", $grpsplit[0]);
1135
			}
1136
		}
1137
	}
1138

    
1139
	/* Time to close LDAP connection */
1140
	@ldap_unbind($ldap);
1141

    
1142
	$groups = print_r($memberof, true);
1143

    
1144
	//log_error("Returning groups ".$groups." for user $username");
1145

    
1146
	return $memberof;
1147
}
1148

    
1149
function ldap_format_host($host) {
1150
	return is_ipaddrv6($host) ? "[$host]" : $host ;
1151
}
1152

    
1153
function ldap_backed($username, $passwd, $authcfg) {
1154
	global $debug, $config;
1155

    
1156
	if (!$username) {
1157
		return;
1158
	}
1159

    
1160
	if (!function_exists("ldap_connect")) {
1161
		return;
1162
	}
1163

    
1164
	if (!isset($authcfg['ldap_nostrip_at']) && stristr($username, "@")) {
1165
		$username_split = explode("@", $username);
1166
		$username = $username_split[0];
1167
	}
1168
	if (stristr($username, "\\")) {
1169
		$username_split = explode("\\", $username);
1170
		$username = $username_split[0];
1171
	}
1172

    
1173
	if ($authcfg) {
1174
		if (strstr($authcfg['ldap_urltype'], "Standard")) {
1175
			$ldapproto = "ldap";
1176
		} else {
1177
			$ldapproto = "ldaps";
1178
		}
1179
		$ldapserver = "{$ldapproto}://" . ldap_format_host($authcfg['host']);
1180
		$ldapport = $authcfg['ldap_port'];
1181
		if (!empty($ldapport)) {
1182
			$ldapserver .= ":{$ldapport}";
1183
		}
1184
		$ldapbasedn = $authcfg['ldap_basedn'];
1185
		$ldapbindun = $authcfg['ldap_binddn'];
1186
		$ldapbindpw = $authcfg['ldap_bindpw'];
1187
		if (empty($ldapbindun) || empty($ldapbindpw)) {
1188
			$ldapanon = true;
1189
		} else {
1190
			$ldapanon = false;
1191
		}
1192
		$ldapauthcont = $authcfg['ldap_authcn'];
1193
		$ldapnameattribute = strtolower($authcfg['ldap_attr_user']);
1194
		$ldapextendedqueryenabled = $authcfg['ldap_extended_enabled'];
1195
		$ldapextendedquery = $authcfg['ldap_extended_query'];
1196
		$ldapfilter = "";
1197
		if (!$ldapextendedqueryenabled) {
1198
			$ldapfilter = "({$ldapnameattribute}={$username})";
1199
		} else {
1200
			$ldapfilter = "(&({$ldapnameattribute}={$username})({$ldapextendedquery}))";
1201
		}
1202
		$ldaptype = "";
1203
		$ldapver = $authcfg['ldap_protver'];
1204
		$ldapname = $authcfg['name'];
1205
		$ldapscope = $authcfg['ldap_scope'];
1206
		$ldaptimeout = is_numeric($authcfg['ldap_timeout']) ? $authcfg['ldap_timeout'] : 25;
1207
	} else {
1208
		return false;
1209
	}
1210

    
1211
	/* first check if there is even an LDAP server populated */
1212
	if (!$ldapserver) {
1213
		if ($ldapfallback) {
1214
			log_error(gettext("ERROR! ldap_backed() called with no LDAP authentication server defined.  Defaulting to local user database. Visit System -> User Manager."));
1215
			return local_backed($username, $passwd);
1216
		} else {
1217
			log_error(gettext("ERROR! ldap_backed() called with no LDAP authentication server defined."));
1218
		}
1219

    
1220
		return false;
1221
	}
1222

    
1223
	/* Setup CA environment if needed. */
1224
	ldap_setup_caenv($authcfg);
1225

    
1226
	ldap_set_option($ldap, LDAP_OPT_REFERRALS, 0);
1227
	ldap_set_option($ldap, LDAP_OPT_DEREF, LDAP_DEREF_SEARCHING);
1228
	ldap_set_option($ldap, LDAP_OPT_PROTOCOL_VERSION, (int)$ldapver);
1229
	ldap_set_option($ldap, LDAP_OPT_TIMELIMIT, (int)$ldaptimeout);
1230
	ldap_set_option($ldap, LDAP_OPT_NETWORK_TIMEOUT, (int)$ldaptimeout);
1231

    
1232
	/* Make sure we can connect to LDAP */
1233
	$error = false;
1234
	if (!($ldap = ldap_connect($ldapserver))) {
1235
		$error = true;
1236
	}
1237

    
1238
	if ($error == true) {
1239
		log_error(sprintf(gettext("ERROR!  Could not connect to server %s."), $ldapname));
1240
		return false;
1241
	}
1242

    
1243
	/* ok, its up.  now, lets bind as the bind user so we can search it */
1244
	$error = false;
1245
	$ldapbindun = isset($authcfg['ldap_utf8']) ? utf8_encode($ldapbindun) : $ldapbindun;
1246
	$ldapbindpw = isset($authcfg['ldap_utf8']) ? utf8_encode($ldapbindpw) : $ldapbindpw;
1247
	if ($ldapanon == true) {
1248
		if (!($res = @ldap_bind($ldap))) {
1249
			$error = true;
1250
		}
1251
	} else if (!($res = @ldap_bind($ldap, $ldapbindun, $ldapbindpw))) {
1252
		$error = true;
1253
	}
1254

    
1255
	if ($error == true) {
1256
		@ldap_close($ldap);
1257
		log_error(sprintf(gettext("ERROR! Could not bind to server %s."), $ldapname));
1258
		return false;
1259
	}
1260

    
1261
	/* Get LDAP Authcontainers and split em up. */
1262
	$ldac_splits = explode(";", $ldapauthcont);
1263

    
1264
	/* setup the usercount so we think we haven't found anyone yet */
1265
	$usercount = 0;
1266

    
1267
	/*****************************************************************/
1268
	/*  We first find the user based on username and filter          */
1269
	/*  then, once we find the first occurrence of that person       */
1270
	/*  we set session variables to point to the OU and DN of the    */
1271
	/*  person.  To later be used by ldap_get_groups.                */
1272
	/*  that way we don't have to search twice.                      */
1273
	/*****************************************************************/
1274
	if ($debug) {
1275
		log_auth(sprintf(gettext("Now Searching for %s in directory."), $username));
1276
	}
1277
	/* Iterate through the user containers for search */
1278
	foreach ($ldac_splits as $i => $ldac_split) {
1279
		$ldac_split = isset($authcfg['ldap_utf8']) ? utf8_encode($ldac_split) : $ldac_split;
1280
		$ldapfilter = isset($authcfg['ldap_utf8']) ? utf8_encode($ldapfilter) : $ldapfilter;
1281
		$ldapsearchbasedn = isset($authcfg['ldap_utf8']) ? utf8_encode("{$ldac_split},{$ldapbasedn}") : "{$ldac_split},{$ldapbasedn}";
1282
		/* Make sure we just use the first user we find */
1283
		if ($debug) {
1284
			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)));
1285
		}
1286
		if ($ldapscope == "one") {
1287
			$ldapfunc = "ldap_list";
1288
		} else {
1289
			$ldapfunc = "ldap_search";
1290
		}
1291
		/* Support legacy auth container specification. */
1292
		if (stristr($ldac_split, "DC=") || empty($ldapbasedn)) {
1293
			$search = @$ldapfunc($ldap, $ldac_split, $ldapfilter);
1294
		} else {
1295
			$search = @$ldapfunc($ldap, $ldapsearchbasedn, $ldapfilter);
1296
		}
1297
		if (!$search) {
1298
			log_error(sprintf(gettext("Search resulted in error: %s"), ldap_error($ldap)));
1299
			continue;
1300
		}
1301
		$info = ldap_get_entries($ldap, $search);
1302
		$matches = $info['count'];
1303
		if ($matches == 1) {
1304
			$userdn = $_SESSION['ldapdn'] = $info[0]['dn'];
1305
			$_SESSION['ldapou'] = $ldac_split[$i];
1306
			$_SESSION['ldapon'] = "true";
1307
			$usercount = 1;
1308
			break;
1309
		}
1310
	}
1311

    
1312
	if ($usercount != 1) {
1313
		@ldap_unbind($ldap);
1314
		log_error(gettext("ERROR! Either LDAP search failed, or multiple users were found."));
1315
		return false;
1316
	}
1317

    
1318
	/* Now lets bind as the user we found */
1319
	$passwd = isset($authcfg['ldap_utf8']) ? utf8_encode($passwd) : $passwd;
1320
	if (!($res = @ldap_bind($ldap, $userdn, $passwd))) {
1321
		log_error(sprintf(gettext('ERROR! Could not login to server %1$s as user %2$s: %3$s'), $ldapname, $username, ldap_error($ldap)));
1322
		@ldap_unbind($ldap);
1323
		return false;
1324
	}
1325

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

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

    
1334
	return true;
1335
}
1336

    
1337
function radius_backed($username, $passwd, $authcfg, &$attributes = array()) {
1338
	global $debug, $config;
1339
	$ret = false;
1340

    
1341
	require_once("radius.inc");
1342

    
1343
	$rauth = new Auth_RADIUS_PAP($username, $passwd);
1344
	if ($authcfg) {
1345
		$radiusservers = array();
1346
		$radiusservers[0]['ipaddr'] = $authcfg['host'];
1347
		$radiusservers[0]['port'] = $authcfg['radius_auth_port'];
1348
		$radiusservers[0]['sharedsecret'] = $authcfg['radius_secret'];
1349
		$radiusservers[0]['timeout'] = $authcfg['radius_timeout'];
1350
	} else {
1351
		return false;
1352
	}
1353

    
1354
	/* Add new servers to our instance */
1355
	foreach ($radiusservers as $radsrv) {
1356
		$timeout = (is_numeric($radsrv['timeout'])) ? $radsrv['timeout'] : 5;
1357
		$rauth->addServer($radsrv['ipaddr'], $radsrv['port'], $radsrv['sharedsecret'], $timeout);
1358
	}
1359

    
1360
	if (PEAR::isError($rauth->start())) {
1361
		$retvalue['auth_val'] = 1;
1362
		$retvalue['error'] = $rauth->getError();
1363
		if ($debug) {
1364
			printf(gettext("Radius start: %s<br />\n"), $retvalue['error']);
1365
		}
1366
	}
1367

    
1368
	// XXX - billm - somewhere in here we need to handle securid challenge/response
1369

    
1370
	/* Send request */
1371
	$result = $rauth->send();
1372
	if (PEAR::isError($result)) {
1373
		$retvalue['auth_val'] = 1;
1374
		$retvalue['error'] = $result->getMessage();
1375
		if ($debug) {
1376
			printf(gettext("Radius send failed: %s<br />\n"), $retvalue['error']);
1377
		}
1378
	} else if ($result === true) {
1379
		if ($rauth->getAttributes()) {
1380
			$attributes = $rauth->listAttributes();
1381
		}
1382
		$retvalue['auth_val'] = 2;
1383
		if ($debug) {
1384
			printf(gettext("Radius Auth succeeded")."<br />\n");
1385
		}
1386
		$ret = true;
1387
	} else {
1388
		$retvalue['auth_val'] = 3;
1389
		if ($debug) {
1390
			printf(gettext("Radius Auth rejected")."<br />\n");
1391
		}
1392
	}
1393

    
1394
	// close OO RADIUS_AUTHENTICATION
1395
	$rauth->close();
1396

    
1397
	return $ret;
1398
}
1399

    
1400
/*
1401
	$attributes must contain a "class" key containing the groups and local
1402
	groups must exist to match.
1403
*/
1404
function radius_get_groups($attributes) {
1405
	$groups = array();
1406
	if (!empty($attributes) && is_array($attributes) && !empty($attributes['class'])) {
1407
		$groups = explode(";", $attributes['class']);
1408
		foreach ($groups as & $grp) {
1409
			$grp = trim($grp);
1410
			if (strtolower(substr($grp, 0, 3)) == "ou=") {
1411
				$grp = substr($grp, 3);
1412
			}
1413
		}
1414
	}
1415
	return $groups;
1416
}
1417

    
1418
function get_user_expiration_date($username) {
1419
	$user = getUserEntry($username);
1420
	if ($user['expires']) {
1421
		return $user['expires'];
1422
	}
1423
}
1424

    
1425
function is_account_expired($username) {
1426
	$expirydate = get_user_expiration_date($username);
1427
	if ($expirydate) {
1428
		if (strtotime("-1 day") > strtotime(date("m/d/Y", strtotime($expirydate)))) {
1429
			return true;
1430
		}
1431
	}
1432

    
1433
	return false;
1434
}
1435

    
1436
function is_account_disabled($username) {
1437
	$user = getUserEntry($username);
1438
	if (isset($user['disabled'])) {
1439
		return true;
1440
	}
1441

    
1442
	return false;
1443
}
1444

    
1445
function auth_get_authserver($name) {
1446
	global $config;
1447

    
1448
	if (is_array($config['system']['authserver'])) {
1449
		foreach ($config['system']['authserver'] as $authcfg) {
1450
			if ($authcfg['name'] == $name) {
1451
				return $authcfg;
1452
			}
1453
		}
1454
	}
1455
	if ($name == "Local Database") {
1456
		return array("name" => gettext("Local Database"), "type" => "Local Auth", "host" => $config['system']['hostname']);
1457
	}
1458
}
1459

    
1460
function auth_get_authserver_list() {
1461
	global $config;
1462

    
1463
	$list = array();
1464

    
1465
	if (is_array($config['system']['authserver'])) {
1466
		foreach ($config['system']['authserver'] as $authcfg) {
1467
			/* Add support for disabled entries? */
1468
			$list[$authcfg['name']] = $authcfg;
1469
		}
1470
	}
1471

    
1472
	$list["Local Database"] = array("name" => gettext("Local Database"), "type" => "Local Auth", "host" => $config['system']['hostname']);
1473
	return $list;
1474
}
1475

    
1476
function getUserGroups($username, $authcfg, &$attributes = array()) {
1477
	global $config;
1478

    
1479
	$allowed_groups = array();
1480

    
1481
	switch ($authcfg['type']) {
1482
		case 'ldap':
1483
			$allowed_groups = @ldap_get_groups($username, $authcfg);
1484
			break;
1485
		case 'radius':
1486
			$allowed_groups = @radius_get_groups($attributes);
1487
			break;
1488
		default:
1489
			$user = getUserEntry($username);
1490
			$allowed_groups = @local_user_get_groups($user, true);
1491
			break;
1492
	}
1493

    
1494
	$member_groups = array();
1495
	if (is_array($config['system']['group'])) {
1496
		foreach ($config['system']['group'] as $group) {
1497
			if (in_array($group['name'], $allowed_groups)) {
1498
				$member_groups[] = $group['name'];
1499
			}
1500
		}
1501
	}
1502

    
1503
	return $member_groups;
1504
}
1505

    
1506
function authenticate_user($username, $password, $authcfg = NULL, &$attributes = array()) {
1507

    
1508
	if (!$authcfg) {
1509
		return local_backed($username, $password);
1510
	}
1511

    
1512
	$authenticated = false;
1513
	switch ($authcfg['type']) {
1514
		case 'ldap':
1515
			if (ldap_backed($username, $password, $authcfg)) {
1516
				$authenticated = true;
1517
			}
1518
			break;
1519
		case 'radius':
1520
			if (radius_backed($username, $password, $authcfg, $attributes)) {
1521
				$authenticated = true;
1522
			}
1523
			break;
1524
		default:
1525
			/* lookup user object by name */
1526
			if (local_backed($username, $password)) {
1527
				$authenticated = true;
1528
			}
1529
			break;
1530
		}
1531

    
1532
	return $authenticated;
1533
}
1534

    
1535
function session_auth() {
1536
	global $config, $_SESSION, $page;
1537

    
1538
	// Handle HTTPS httponly and secure flags
1539
	$currentCookieParams = session_get_cookie_params();
1540
	session_set_cookie_params(
1541
		$currentCookieParams["lifetime"],
1542
		$currentCookieParams["path"],
1543
		NULL,
1544
		($config['system']['webgui']['protocol'] == "https"),
1545
		true
1546
	);
1547

    
1548
	if (!session_id()) {
1549
		session_start();
1550
	}
1551

    
1552
	// Detect protocol change
1553
	if (!isset($_POST['login']) && !empty($_SESSION['Logged_In']) && $_SESSION['protocol'] != $config['system']['webgui']['protocol']) {
1554
		return false;
1555
	}
1556

    
1557
	/* Validate incoming login request */
1558
	$attributes = array();
1559
	if (isset($_POST['login']) && !empty($_POST['usernamefld']) && !empty($_POST['passwordfld'])) {
1560
		$authcfg = auth_get_authserver($config['system']['webgui']['authmode']);
1561
		if (authenticate_user($_POST['usernamefld'], $_POST['passwordfld'], $authcfg, $attributes) ||
1562
		    authenticate_user($_POST['usernamefld'], $_POST['passwordfld'])) {
1563
			// Generate a new id to avoid session fixation
1564
			session_regenerate_id();
1565
			$_SESSION['Logged_In'] = "True";
1566
			$_SESSION['Username'] = $_POST['usernamefld'];
1567
			$_SESSION['user_radius_attributes'] = $attributes;
1568
			$_SESSION['last_access'] = time();
1569
			$_SESSION['protocol'] = $config['system']['webgui']['protocol'];
1570
			if (!isset($config['system']['webgui']['quietlogin'])) {
1571
				log_auth(sprintf(gettext("Successful login for user '%1\$s' from: %2\$s"), $_POST['usernamefld'], $_SERVER['REMOTE_ADDR']));
1572
			}
1573
			if (isset($_POST['postafterlogin'])) {
1574
				return true;
1575
			} else {
1576
				if (empty($page)) {
1577
					$page = "/";
1578
				}
1579
				header("Location: {$page}");
1580
			}
1581
			exit;
1582
		} else {
1583
			/* give the user an error message */
1584
			$_SESSION['Login_Error'] = "Username or Password incorrect";
1585
			log_auth("webConfigurator authentication error for '{$_POST['usernamefld']}' from {$_SERVER['REMOTE_ADDR']}");
1586
			if (isAjax()) {
1587
				echo "showajaxmessage('{$_SESSION['Login_Error']}');";
1588
				return;
1589
			}
1590
		}
1591
	}
1592

    
1593
	/* Show login page if they aren't logged in */
1594
	if (empty($_SESSION['Logged_In'])) {
1595
		return false;
1596
	}
1597

    
1598
	/* If session timeout isn't set, we don't mark sessions stale */
1599
	if (!isset($config['system']['webgui']['session_timeout'])) {
1600
		/* Default to 4 hour timeout if one is not set */
1601
		if ($_SESSION['last_access'] < (time() - 14400)) {
1602
			$_GET['logout'] = true;
1603
			$_SESSION['Logout'] = true;
1604
		} else {
1605
			$_SESSION['last_access'] = time();
1606
		}
1607
	} else if (intval($config['system']['webgui']['session_timeout']) == 0) {
1608
		/* only update if it wasn't ajax */
1609
		if (!isAjax()) {
1610
			$_SESSION['last_access'] = time();
1611
		}
1612
	} else {
1613
		/* Check for stale session */
1614
		if ($_SESSION['last_access'] < (time() - ($config['system']['webgui']['session_timeout'] * 60))) {
1615
			$_GET['logout'] = true;
1616
			$_SESSION['Logout'] = true;
1617
		} else {
1618
			/* only update if it wasn't ajax */
1619
			if (!isAjax()) {
1620
				$_SESSION['last_access'] = time();
1621
			}
1622
		}
1623
	}
1624

    
1625
	/* user hit the logout button */
1626
	if (isset($_GET['logout'])) {
1627

    
1628
		if ($_SESSION['Logout']) {
1629
			log_error(sprintf(gettext("Session timed out for user '%1\$s' from: %2\$s"), $_SESSION['Username'], $_SERVER['REMOTE_ADDR']));
1630
		} else {
1631
			log_error(sprintf(gettext("User logged out for user '%1\$s' from: %2\$s"), $_SESSION['Username'], $_SERVER['REMOTE_ADDR']));
1632
		}
1633

    
1634
		/* wipe out $_SESSION */
1635
		$_SESSION = array();
1636

    
1637
		if (isset($_COOKIE[session_name()])) {
1638
			setcookie(session_name(), '', time()-42000, '/');
1639
		}
1640

    
1641
		/* and destroy it */
1642
		session_destroy();
1643

    
1644
		$scriptName = explode("/", $_SERVER["SCRIPT_FILENAME"]);
1645
		$scriptElms = count($scriptName);
1646
		$scriptName = $scriptName[$scriptElms-1];
1647

    
1648
		if (isAjax()) {
1649
			return false;
1650
		}
1651

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

    
1655
		return false;
1656
	}
1657

    
1658
	/*
1659
	 * this is for debugging purpose if you do not want to use Ajax
1660
	 * to submit a HTML form. It basically disables the observation
1661
	 * of the submit event and hence does not trigger Ajax.
1662
	 */
1663
	if ($_GET['disable_ajax']) {
1664
		$_SESSION['NO_AJAX'] = "True";
1665
	}
1666

    
1667
	/*
1668
	 * Same to re-enable Ajax.
1669
	 */
1670
	if ($_GET['enable_ajax']) {
1671
		unset($_SESSION['NO_AJAX']);
1672
	}
1673

    
1674
	return true;
1675
}
1676

    
1677
?>
(4-4/67)