Project

General

Profile

Download (45.1 KB) Statistics
| Branch: | Tag: | Revision:
1
<?php
2
/* $Id$ */
3
/*
4
	Copyright (C) 2010 Ermal Luçi
5
	All rights reserved.
6

    
7
	Copyright (C) 2007, 2008 Scott Ullrich <sullrich@gmail.com>
8
	All rights reserved.
9

    
10
	Copyright (C) 2005-2006 Bill Marquette <bill.marquette@gmail.com>
11
	All rights reserved.
12

    
13
	Copyright (C) 2006 Paul Taylor <paultaylor@winn-dixie.com>.
14
	All rights reserved.
15

    
16
	Copyright (C) 2003-2006 Manuel Kasper <mk@neon1.net>.
17
	All rights reserved.
18

    
19
	Redistribution and use in source and binary forms, with or without
20
	modification, are permitted provided that the following conditions are met:
21

    
22
	1. Redistributions of source code must retain the above copyright notice,
23
	   this list of conditions and the following disclaimer.
24

    
25
	2. Redistributions in binary form must reproduce the above copyright
26
	   notice, this list of conditions and the following disclaimer in the
27
	   documentation and/or other materials provided with the distribution.
28

    
29
	THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
30
	INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
31
	AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
32
	AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
33
	OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
34
	SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
35
	INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
36
	CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
37
	ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
38
	POSSIBILITY OF SUCH DAMAGE.
39

    
40
	pfSense_BUILDER_BINARIES:	/usr/sbin/pw	/bin/cp
41
	pfSense_MODULE:	auth
42
*/
43

    
44
/*
45
 * NOTE : Portions of the mschapv2 support was based on the BSD licensed CHAP.php
46
 * file courtesy of Michael Retterklieber.
47
 */
48
if (!$do_not_include_config_gui_inc) {
49
	require_once("config.gui.inc");
50
}
51

    
52
// Will be changed to false if security checks fail
53
$security_passed = true;
54

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

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

    
84
	if (is_array($config['dyndnses']['dyndns']) && !$found_host) {
85
		foreach ($config['dyndnses']['dyndns'] as $dyndns) {
86
			if (strcasecmp($dyndns['host'], $http_host) == 0) {
87
				$found_host = true;
88
				break;
89
			}
90
		}
91
	}
92

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

    
102
	if (!empty($config['system']['webgui']['althostnames']) && !$found_host) {
103
		$althosts = explode(" ", $config['system']['webgui']['althostnames']);
104
		foreach ($althosts as $ah) {
105
			if (strcasecmp($ah, $http_host) == 0 or strcasecmp($ah, $_SERVER['SERVER_ADDR']) == 0) {
106
				$found_host = true;
107
				break;
108
			}
109
		}
110
	}
111

    
112
	if ($found_host == false) {
113
		if (!security_checks_disabled()) {
114
			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."));
115
			exit;
116
		}
117
		$security_passed = false;
118
	}
119
}
120

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

    
158
			if (!empty($config['system']['webgui']['althostnames']) && !$found_host) {
159
				$althosts = explode(" ", $config['system']['webgui']['althostnames']);
160
				foreach ($althosts as $ah) {
161
					if (strcasecmp($referrer_host, $ah) == 0) {
162
						$found_host = true;
163
						break;
164
					}
165
				}
166
			}
167

    
168
			if (is_array($config['dyndnses']['dyndns']) && !$found_host) {
169
				foreach ($config['dyndnses']['dyndns'] as $dyndns) {
170
					if (strcasecmp($dyndns['host'], $referrer_host) == 0) {
171
						$found_host = true;
172
						break;
173
					}
174
				}
175
			}
176

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

    
186
			if (!$found_host) {
187
				$interface_list_ips = get_configured_ip_addresses();
188
				foreach ($interface_list_ips as $ilips) {
189
					if (strcasecmp($referrer_host, $ilips) == 0) {
190
						$found_host = true;
191
						break;
192
					}
193
				}
194
				$interface_list_ipv6s = get_configured_ipv6_addresses();
195
				foreach ($interface_list_ipv6s as $ilipv6s) {
196
					if (strcasecmp($referrer_host, $ilipv6s) == 0) {
197
						$found_host = true;
198
						break;
199
					}
200
				}
201
				if ($referrer_host == "127.0.0.1" || $referrer_host == "localhost") {
202
					// allow SSH port forwarded connections and links from localhost
203
					$found_host = true;
204
				}
205
			}
206
		}
207
		if ($found_host == false) {
208
			if (!security_checks_disabled()) {
209
				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.");
210
				exit;
211
			}
212
			$security_passed = false;
213
		}
214
	} else {
215
		$security_passed = false;
216
	}
217
}
218

    
219
if (function_exists("display_error_form") && $security_passed) {
220
	/* Security checks passed, so it should be OK to turn them back on */
221
	restore_security_checks();
222
}
223
unset($security_passed);
224

    
225
$groupindex = index_groups();
226
$userindex = index_users();
227

    
228
function index_groups() {
229
	global $g, $debug, $config, $groupindex;
230

    
231
	$groupindex = array();
232

    
233
	if (is_array($config['system']['group'])) {
234
		$i = 0;
235
		foreach ($config['system']['group'] as $groupent) {
236
			$groupindex[$groupent['name']] = $i;
237
			$i++;
238
		}
239
	}
240

    
241
	return ($groupindex);
242
}
243

    
244
function index_users() {
245
	global $g, $debug, $config;
246

    
247
	if (is_array($config['system']['user'])) {
248
		$i = 0;
249
		foreach ($config['system']['user'] as $userent) {
250
			$userindex[$userent['name']] = $i;
251
			$i++;
252
		}
253
	}
254

    
255
	return ($userindex);
256
}
257

    
258
function & getUserEntry($name) {
259
	global $debug, $config, $userindex;
260
	if (isset($userindex[$name])) {
261
		return $config['system']['user'][$userindex[$name]];
262
	}
263
}
264

    
265
function & getUserEntryByUID($uid) {
266
	global $debug, $config;
267

    
268
	if (is_array($config['system']['user'])) {
269
		foreach ($config['system']['user'] as & $user) {
270
			if ($user['uid'] == $uid) {
271
				return $user;
272
			}
273
		}
274
	}
275

    
276
	return false;
277
}
278

    
279
function & getGroupEntry($name) {
280
	global $debug, $config, $groupindex;
281
	if (isset($groupindex[$name])) {
282
		return $config['system']['group'][$groupindex[$name]];
283
	}
284
}
285

    
286
function & getGroupEntryByGID($gid) {
287
	global $debug, $config;
288

    
289
	if (is_array($config['system']['group'])) {
290
		foreach ($config['system']['group'] as & $group) {
291
			if ($group['gid'] == $gid) {
292
				return $group;
293
			}
294
		}
295
	}
296

    
297
	return false;
298
}
299

    
300
function get_user_privileges(& $user) {
301

    
302
	$privs = $user['priv'];
303
	if (!is_array($privs)) {
304
		$privs = array();
305
	}
306

    
307
	$names = local_user_get_groups($user, true);
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['password']) {
350
		if (crypt($passwd, $user['password']) == $user['password']) {
351
			return true;
352
		}
353
	}
354

    
355
	if ($user['md5-hash']) {
356
		if (md5($passwd) == $user['md5-hash']) {
357
			return true;
358
		}
359
	}
360

    
361
	return false;
362
}
363

    
364
function local_sync_accounts() {
365
	global $debug, $config;
366
	conf_mount_rw();
367

    
368
	/* remove local users to avoid uid conflicts */
369
	$fd = popen("/usr/sbin/pw usershow -a", "r");
370
	if ($fd) {
371
		while (!feof($fd)) {
372
			$line = explode(":", fgets($fd));
373
			if (((!strncmp($line[0], "_", 1)) || ($line[2] < 2000) || ($line[2] > 65000)) && ($line[0] != "admin")) {
374
				continue;
375
			}
376
			/*
377
			 * If a crontab was created to user, pw userdel will be interactive and
378
			 * can cause issues. Just remove crontab before run it when necessary
379
			 */
380
			unlink_if_exists("/var/cron/tabs/{$line[0]}");
381
			$cmd = "/usr/sbin/pw userdel -n '{$line[0]}'";
382
			if ($debug) {
383
				log_error(sprintf(gettext("Running: %s"), $cmd));
384
			}
385
			mwexec($cmd);
386
		}
387
		pclose($fd);
388
	}
389

    
390
	/* remove local groups to avoid gid conflicts */
391
	$gids = array();
392
	$fd = popen("/usr/sbin/pw groupshow -a", "r");
393
	if ($fd) {
394
		while (!feof($fd)) {
395
			$line = explode(":", fgets($fd));
396
			if (!strncmp($line[0], "_", 1)) {
397
				continue;
398
			}
399
			if ($line[2] < 2000) {
400
				continue;
401
			}
402
			if ($line[2] > 65000) {
403
				continue;
404
			}
405
			$cmd = "/usr/sbin/pw groupdel {$line[2]}";
406
			if ($debug) {
407
				log_error(sprintf(gettext("Running: %s"), $cmd));
408
			}
409
			mwexec($cmd);
410
		}
411
		pclose($fd);
412
	}
413

    
414
	/* make sure the all group exists */
415
	$allgrp = getGroupEntryByGID(1998);
416
	local_group_set($allgrp, true);
417

    
418
	/* sync all local users */
419
	if (is_array($config['system']['user'])) {
420
		foreach ($config['system']['user'] as $user) {
421
			local_user_set($user);
422
		}
423
	}
424

    
425
	/* sync all local groups */
426
	if (is_array($config['system']['group'])) {
427
		foreach ($config['system']['group'] as $group) {
428
			local_group_set($group);
429
		}
430
	}
431

    
432
	conf_mount_ro();
433

    
434
}
435

    
436
function local_user_set(& $user) {
437
	global $g, $debug;
438

    
439
	if (empty($user['password'])) {
440
		log_error("There is something wrong in your config because user {$user['name']} password is missing!");
441
		return;
442
	}
443

    
444
	conf_mount_rw();
445

    
446
	$home_base = "/home/";
447
	$user_uid = $user['uid'];
448
	$user_name = $user['name'];
449
	$user_home = "{$home_base}{$user_name}";
450
	$user_shell = "/etc/rc.initial";
451
	$user_group = "nobody";
452

    
453
	// Ensure $home_base exists and is writable
454
	if (!is_dir($home_base)) {
455
		mkdir($home_base, 0755);
456
	}
457

    
458
	$lock_account = false;
459
	/* configure shell type */
460
	/* Cases here should be ordered by most privileged to least privileged. */
461
	if (userHasPrivilege($user, "user-shell-access") || userHasPrivilege($user, "page-all")) {
462
		$user_shell = "/bin/tcsh";
463
	} elseif (userHasPrivilege($user, "user-copy-files")) {
464
		$user_shell = "/usr/local/bin/scponly";
465
	} elseif (userHasPrivilege($user, "user-ssh-tunnel")) {
466
		$user_shell = "/usr/local/sbin/ssh_tunnel_shell";
467
	} elseif (userHasPrivilege($user, "user-ipsec-xauth-dialin")) {
468
		$user_shell = "/sbin/nologin";
469
	} else {
470
		$user_shell = "/sbin/nologin";
471
		$lock_account = true;
472
	}
473

    
474
	/* Lock out disabled or expired users, unless it's root/admin. */
475
	if ((is_account_disabled($user_name) || is_account_expired($user_name)) && ($user_uid != 0)) {
476
		$user_shell = "/sbin/nologin";
477
		$lock_account = true;
478
	}
479

    
480
	/* root user special handling */
481
	if ($user_uid == 0) {
482
		$cmd = "/usr/sbin/pw usermod -q -n root -s /bin/sh -H 0";
483
		if ($debug) {
484
			log_error(sprintf(gettext("Running: %s"), $cmd));
485
		}
486
		$fd = popen($cmd, "w");
487
		fwrite($fd, $user['password']);
488
		pclose($fd);
489
		$user_group = "wheel";
490
		$user_home = "/root";
491
		$user_shell = "/etc/rc.initial";
492
	}
493

    
494
	/* read from pw db */
495
	$fd = popen("/usr/sbin/pw usershow -n {$user_name} 2>&1", "r");
496
	$pwread = fgets($fd);
497
	pclose($fd);
498
	$userattrs = explode(":", trim($pwread));
499

    
500
	/* determine add or mod */
501
	if (($userattrs[0] != $user['name']) || (!strncmp($pwread, "pw:", 3))) {
502
		$user_op = "useradd -m -k /etc/skel -o";
503
	} else {
504
		$user_op = "usermod";
505
	}
506

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

    
513
	if ($debug) {
514
		log_error(sprintf(gettext("Running: %s"), $cmd));
515
	}
516
	$fd = popen($cmd, "w");
517
	fwrite($fd, $user['password']);
518
	pclose($fd);
519

    
520
	/* create user directory if required */
521
	if (!is_dir($user_home)) {
522
		mkdir($user_home, 0700);
523
	}
524
	@chown($user_home, $user_name);
525
	@chgrp($user_home, $user_group);
526

    
527
	/* write out ssh authorized key file */
528
	if ($user['authorizedkeys']) {
529
		if (!is_dir("{$user_home}/.ssh")) {
530
			@mkdir("{$user_home}/.ssh", 0700);
531
			@chown("{$user_home}/.ssh", $user_name);
532
		}
533
		$keys = base64_decode($user['authorizedkeys']);
534
		@file_put_contents("{$user_home}/.ssh/authorized_keys", $keys);
535
		@chown("{$user_home}/.ssh/authorized_keys", $user_name);
536
	} else {
537
		unlink_if_exists("{$user_home}/.ssh/authorized_keys");
538
	}
539

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

    
543
	conf_mount_ro();
544
}
545

    
546
function local_user_del($user) {
547
	global $debug;
548

    
549
	/* remove all memberships */
550
	local_user_set_groups($user);
551

    
552
	/* Don't remove /root */
553
	if ($user['uid'] != 0) {
554
		$rmhome = "-r";
555
	}
556

    
557
	/* read from pw db */
558
	$fd = popen("/usr/sbin/pw usershow -n {$user['name']} 2>&1", "r");
559
	$pwread = fgets($fd);
560
	pclose($fd);
561
	$userattrs = explode(":", trim($pwread));
562

    
563
	if ($userattrs[0] != $user['name']) {
564
		log_error("Tried to remove user {$user['name']} but got user {$userattrs[0]} instead. Bailing.");
565
		return;
566
	}
567

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

    
571
	if ($debug) {
572
		log_error(sprintf(gettext("Running: %s"), $cmd));
573
	}
574
	mwexec($cmd);
575

    
576
	/* Delete user from groups needs a call to write_config() */
577
	local_group_del_user($user);
578
}
579

    
580
function local_user_set_password(&$user, $password) {
581

    
582
	$user['password'] = crypt($password);
583
	$user['md5-hash'] = md5($password);
584

    
585
	// Converts ascii to unicode.
586
	$astr = (string) $password;
587
	$ustr = '';
588
	for ($i = 0; $i < strlen($astr); $i++) {
589
		$a = ord($astr{$i}) << 8;
590
		$ustr .= sprintf("%X", $a);
591
	}
592

    
593
}
594

    
595
function local_user_get_groups($user, $all = false) {
596
	global $debug, $config;
597

    
598
	$groups = array();
599
	if (!is_array($config['system']['group'])) {
600
		return $groups;
601
	}
602

    
603
	foreach ($config['system']['group'] as $group) {
604
		if ($all || (!$all && ($group['name'] != "all"))) {
605
			if (is_array($group['member'])) {
606
				if (in_array($user['uid'], $group['member'])) {
607
					$groups[] = $group['name'];
608
				}
609
			}
610
		}
611
	}
612

    
613
	if ($all) {
614
		$groups[] = "all";
615
	}
616

    
617
	sort($groups);
618

    
619
	return $groups;
620

    
621
}
622

    
623
function local_user_set_groups($user, $new_groups = NULL) {
624
	global $debug, $config, $groupindex;
625

    
626
	if (!is_array($config['system']['group'])) {
627
		return;
628
	}
629

    
630
	$cur_groups = local_user_get_groups($user, true);
631
	$mod_groups = array();
632

    
633
	if (!is_array($new_groups)) {
634
		$new_groups = array();
635
	}
636

    
637
	if (!is_array($cur_groups)) {
638
		$cur_groups = array();
639
	}
640

    
641
	/* determine which memberships to add */
642
	foreach ($new_groups as $groupname) {
643
		if ($groupname == '' || in_array($groupname, $cur_groups)) {
644
			continue;
645
		}
646
		$group = & $config['system']['group'][$groupindex[$groupname]];
647
		$group['member'][] = $user['uid'];
648
		$mod_groups[] = $group;
649
	}
650
	unset($group);
651

    
652
	/* determine which memberships to remove */
653
	foreach ($cur_groups as $groupname) {
654
		if (in_array($groupname, $new_groups)) {
655
			continue;
656
		}
657
		if (!isset($config['system']['group'][$groupindex[$groupname]])) {
658
			continue;
659
		}
660
		$group = & $config['system']['group'][$groupindex[$groupname]];
661
		if (is_array($group['member'])) {
662
			$index = array_search($user['uid'], $group['member']);
663
			array_splice($group['member'], $index, 1);
664
			$mod_groups[] = $group;
665
		}
666
	}
667
	unset($group);
668

    
669
	/* sync all modified groups */
670
	foreach ($mod_groups as $group) {
671
		local_group_set($group);
672
	}
673
}
674

    
675
function local_group_del_user($user) {
676
	global $config;
677

    
678
	if (!is_array($config['system']['group'])) {
679
		return;
680
	}
681

    
682
	foreach ($config['system']['group'] as $group) {
683
		if (is_array($group['member'])) {
684
			foreach ($group['member'] as $idx => $uid) {
685
				if ($user['uid'] == $uid) {
686
					unset($config['system']['group']['member'][$idx]);
687
				}
688
			}
689
		}
690
	}
691
}
692

    
693
function local_group_set($group, $reset = false) {
694
	global $debug;
695

    
696
	$group_name = $group['name'];
697
	$group_gid = $group['gid'];
698
	$group_members = '';
699
	if (!$reset && !empty($group['member']) && count($group['member']) > 0) {
700
		$group_members = implode(",", $group['member']);
701
	}
702

    
703
	if (empty($group_name)) {
704
		return;
705
	}
706

    
707
	/* read from group db */
708
	$fd = popen("/usr/sbin/pw groupshow {$group_name} 2>&1", "r");
709
	$pwread = fgets($fd);
710
	pclose($fd);
711

    
712
	/* determine add or mod */
713
	if (!strncmp($pwread, "pw:", 3)) {
714
		$group_op = "groupadd";
715
	} else {
716
		$group_op = "groupmod";
717
	}
718

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

    
722
	if ($debug) {
723
		log_error(sprintf(gettext("Running: %s"), $cmd));
724
	}
725
	mwexec($cmd);
726

    
727
}
728

    
729
function local_group_del($group) {
730
	global $debug;
731

    
732
	/* delete from group db */
733
	$cmd = "/usr/sbin/pw groupdel {$group['name']}";
734

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

    
741
function ldap_test_connection($authcfg) {
742
	global $debug, $config, $g;
743

    
744
	if ($authcfg) {
745
		if (strstr($authcfg['ldap_urltype'], "Standard")) {
746
			$ldapproto = "ldap";
747
		} else {
748
			$ldapproto = "ldaps";
749
		}
750
		$ldapserver = "{$ldapproto}://" . ldap_format_host($authcfg['host']);
751
		$ldapport = $authcfg['ldap_port'];
752
		if (!empty($ldapport)) {
753
			$ldapserver .= ":{$ldapport}";
754
		}
755
		$ldapbasedn = $authcfg['ldap_basedn'];
756
		$ldapbindun = $authcfg['ldap_binddn'];
757
		$ldapbindpw = $authcfg['ldap_bindpw'];
758
	} else {
759
		return false;
760
	}
761

    
762
	/* first check if there is even an LDAP server populated */
763
	if (!$ldapserver) {
764
		return false;
765
	}
766

    
767
	/* Setup CA environment if needed. */
768
	ldap_setup_caenv($authcfg);
769

    
770
	/* connect and see if server is up */
771
	$error = false;
772
	if (!($ldap = ldap_connect($ldapserver))) {
773
		$error = true;
774
	}
775

    
776
	if ($error == true) {
777
		log_error(sprintf(gettext("ERROR!  Could not connect to server %s."), $ldapname));
778
		return false;
779
	}
780

    
781
	return true;
782
}
783

    
784
function ldap_setup_caenv($authcfg) {
785
	global $g;
786
	require_once("certs.inc");
787

    
788
	unset($caref);
789
	if (empty($authcfg['ldap_caref']) || !strstr($authcfg['ldap_urltype'], "SSL")) {
790
		putenv('LDAPTLS_REQCERT=never');
791
		return;
792
	} else {
793
		$caref = lookup_ca($authcfg['ldap_caref']);
794
		if (!$caref) {
795
			log_error(sprintf(gettext("LDAP: Could not lookup CA by reference for host %s."), $authcfg['ldap_caref']));
796
			/* XXX: Prevent for credential leaking since we cannot setup the CA env. Better way? */
797
			putenv('LDAPTLS_REQCERT=hard');
798
			return;
799
		}
800
		if (!is_dir("{$g['varrun_path']}/certs")) {
801
			@mkdir("{$g['varrun_path']}/certs");
802
		}
803
		if (file_exists("{$g['varrun_path']}/certs/{$caref['refid']}.ca")) {
804
			@unlink("{$g['varrun_path']}/certs/{$caref['refid']}.ca");
805
		}
806
		file_put_contents("{$g['varrun_path']}/certs/{$caref['refid']}.ca", base64_decode($caref['crt']));
807
		@chmod("{$g['varrun_path']}/certs/{$caref['refid']}.ca", 0600);
808
		putenv('LDAPTLS_REQCERT=hard');
809
		/* XXX: Probably even the hashed link should be created for this? */
810
		putenv("LDAPTLS_CACERTDIR={$g['varrun_path']}/certs");
811
		putenv("LDAPTLS_CACERT={$g['varrun_path']}/certs/{$caref['refid']}.ca");
812
	}
813
}
814

    
815
function ldap_test_bind($authcfg) {
816
	global $debug, $config, $g;
817

    
818
	if ($authcfg) {
819
		if (strstr($authcfg['ldap_urltype'], "Standard")) {
820
			$ldapproto = "ldap";
821
		} else {
822
			$ldapproto = "ldaps";
823
		}
824
		$ldapserver = "{$ldapproto}://" . ldap_format_host($authcfg['host']);
825
		$ldapport = $authcfg['ldap_port'];
826
		if (!empty($ldapport)) {
827
			$ldapserver .= ":{$ldapport}";
828
		}
829
		$ldapbasedn = $authcfg['ldap_basedn'];
830
		$ldapbindun = $authcfg['ldap_binddn'];
831
		$ldapbindpw = $authcfg['ldap_bindpw'];
832
		$ldapver = $authcfg['ldap_protver'];
833
		$ldaptimeout = is_numeric($authcfg['ldap_timeout']) ? $authcfg['ldap_timeout'] : 25;
834
		if (empty($ldapbndun) || empty($ldapbindpw)) {
835
			$ldapanon = true;
836
		} else {
837
			$ldapanon = false;
838
		}
839
	} else {
840
		return false;
841
	}
842

    
843
	/* first check if there is even an LDAP server populated */
844
	if (!$ldapserver) {
845
		return false;
846
	}
847

    
848
	/* Setup CA environment if needed. */
849
	ldap_setup_caenv($authcfg);
850

    
851
	/* connect and see if server is up */
852
	$error = false;
853
	if (!($ldap = ldap_connect($ldapserver))) {
854
		$error = true;
855
	}
856

    
857
	if ($error == true) {
858
		log_error(sprintf(gettext("ERROR!  Could not connect to server %s."), $ldapname));
859
		return false;
860
	}
861

    
862
	ldap_set_option($ldap, LDAP_OPT_REFERRALS, 0);
863
	ldap_set_option($ldap, LDAP_OPT_DEREF, LDAP_DEREF_SEARCHING);
864
	ldap_set_option($ldap, LDAP_OPT_PROTOCOL_VERSION, (int)$ldapver);
865
	ldap_set_option($ldap, LDAP_OPT_TIMELIMIT, (int)$ldaptimeout);
866
	ldap_set_option($ldap, LDAP_OPT_NETWORK_TIMEOUT, (int)$ldaptimeout);
867

    
868
	$ldapbindun = isset($authcfg['ldap_utf8']) ? utf8_encode($ldapbindun) : $ldapbindun;
869
	$ldapbindpw = isset($authcfg['ldap_utf8']) ? utf8_encode($ldapbindpw) : $ldapbindpw;
870
	if ($ldapanon == true) {
871
		if (!($res = @ldap_bind($ldap))) {
872
			@ldap_close($ldap);
873
			return false;
874
		}
875
	} else if (!($res = @ldap_bind($ldap, $ldapbindun, $ldapbindpw))) {
876
		@ldap_close($ldap);
877
		return false;
878
	}
879

    
880
	@ldap_unbind($ldap);
881

    
882
	return true;
883
}
884

    
885
function ldap_get_user_ous($show_complete_ou=true, $authcfg) {
886
	global $debug, $config, $g;
887

    
888
	if (!function_exists("ldap_connect")) {
889
		return;
890
	}
891

    
892
	$ous = array();
893

    
894
	if ($authcfg) {
895
		if (strstr($authcfg['ldap_urltype'], "Standard")) {
896
			$ldapproto = "ldap";
897
		} else {
898
			$ldapproto = "ldaps";
899
		}
900
		$ldapserver = "{$ldapproto}://" . ldap_format_host($authcfg['host']);
901
		$ldapport = $authcfg['ldap_port'];
902
		if (!empty($ldapport)) {
903
			$ldapserver .= ":{$ldapport}";
904
		}
905
		$ldapbasedn = $authcfg['ldap_basedn'];
906
		$ldapbindun = $authcfg['ldap_binddn'];
907
		$ldapbindpw = $authcfg['ldap_bindpw'];
908
		$ldapver = $authcfg['ldap_protver'];
909
		if (empty($ldapbindun) || empty($ldapbindpw)) {
910
			$ldapanon = true;
911
		} else {
912
			$ldapanon = false;
913
		}
914
		$ldapname = $authcfg['name'];
915
		$ldapfallback = false;
916
		$ldapscope = $authcfg['ldap_scope'];
917
		$ldaptimeout = is_numeric($authcfg['ldap_timeout']) ? $authcfg['ldap_timeout'] : 25;
918
	} else {
919
		return false;
920
	}
921

    
922
	/* first check if there is even an LDAP server populated */
923
	if (!$ldapserver) {
924
		log_error(gettext("ERROR!  ldap_get_user_ous() backed selected with no LDAP authentication server defined."));
925
		return $ous;
926
	}
927

    
928
	/* Setup CA environment if needed. */
929
	ldap_setup_caenv($authcfg);
930

    
931
	/* connect and see if server is up */
932
	$error = false;
933
	if (!($ldap = ldap_connect($ldapserver))) {
934
		$error = true;
935
	}
936

    
937
	if ($error == true) {
938
		log_error(sprintf(gettext("ERROR!  Could not connect to server %s."), $ldapname));
939
		return $ous;
940
	}
941

    
942
	$ldapfilter = "(|(ou=*)(cn=Users))";
943

    
944
	ldap_set_option($ldap, LDAP_OPT_REFERRALS, 0);
945
	ldap_set_option($ldap, LDAP_OPT_DEREF, LDAP_DEREF_SEARCHING);
946
	ldap_set_option($ldap, LDAP_OPT_PROTOCOL_VERSION, (int)$ldapver);
947
	ldap_set_option($ldap, LDAP_OPT_TIMELIMIT, (int)$ldaptimeout);
948
	ldap_set_option($ldap, LDAP_OPT_NETWORK_TIMEOUT, (int)$ldaptimeout);
949

    
950
	$ldapbindun = isset($authcfg['ldap_utf8']) ? utf8_encode($ldapbindun) : $ldapbindun;
951
	$ldapbindpw = isset($authcfg['ldap_utf8']) ? utf8_encode($ldapbindpw) : $ldapbindpw;
952
	if ($ldapanon == true) {
953
		if (!($res = @ldap_bind($ldap))) {
954
			log_error(sprintf(gettext("ERROR! ldap_get_user_ous() could not bind anonymously to server %s."), $ldapname));
955
			@ldap_close($ldap);
956
			return $ous;
957
		}
958
	} else if (!($res = @ldap_bind($ldap, $ldapbindun, $ldapbindpw))) {
959
		log_error(sprintf(gettext("ERROR! ldap_get_user_ous() could not bind to server %s."), $ldapname));
960
		@ldap_close($ldap);
961
		return $ous;
962
	}
963

    
964
	if ($ldapscope == "one") {
965
		$ldapfunc = "ldap_list";
966
	} else {
967
		$ldapfunc = "ldap_search";
968
	}
969

    
970
	$search = @$ldapfunc($ldap, $ldapbasedn, $ldapfilter);
971
	$info = @ldap_get_entries($ldap, $search);
972

    
973
	if (is_array($info)) {
974
		foreach ($info as $inf) {
975
			if (!$show_complete_ou) {
976
				$inf_split = explode(",", $inf['dn']);
977
				$ou = $inf_split[0];
978
				$ou = str_replace("OU=", "", $ou);
979
				$ou = str_replace("CN=", "", $ou);
980
			} else {
981
				if ($inf['dn']) {
982
					$ou = $inf['dn'];
983
				}
984
			}
985
			if ($ou) {
986
				$ous[] = $ou;
987
			}
988
		}
989
	}
990

    
991
	@ldap_unbind($ldap);
992

    
993
	return $ous;
994
}
995

    
996
function ldap_get_groups($username, $authcfg) {
997
	global $debug, $config;
998

    
999
	if (!function_exists("ldap_connect")) {
1000
		return;
1001
	}
1002

    
1003
	if (!$username) {
1004
		return false;
1005
	}
1006

    
1007
	if (!isset($authcfg['ldap_nostrip_at']) && stristr($username, "@")) {
1008
		$username_split = explode("@", $username);
1009
		$username = $username_split[0];
1010
	}
1011

    
1012
	if (stristr($username, "\\")) {
1013
		$username_split = explode("\\", $username);
1014
		$username = $username_split[0];
1015
	}
1016

    
1017
	//log_error("Getting LDAP groups for {$username}.");
1018
	if ($authcfg) {
1019
		if (strstr($authcfg['ldap_urltype'], "Standard")) {
1020
			$ldapproto = "ldap";
1021
		} else {
1022
			$ldapproto = "ldaps";
1023
		}
1024
		$ldapserver = "{$ldapproto}://" . ldap_format_host($authcfg['host']);
1025
		$ldapport = $authcfg['ldap_port'];
1026
		if (!empty($ldapport)) {
1027
			$ldapserver .= ":{$ldapport}";
1028
		}
1029
		$ldapbasedn = $authcfg['ldap_basedn'];
1030
		$ldapbindun = $authcfg['ldap_binddn'];
1031
		$ldapbindpw = $authcfg['ldap_bindpw'];
1032
		$ldapauthcont = $authcfg['ldap_authcn'];
1033
		$ldapnameattribute = strtolower($authcfg['ldap_attr_user']);
1034
		$ldapgroupattribute = strtolower($authcfg['ldap_attr_member']);
1035
		if (isset($authcfg['ldap_rfc2307'])) {
1036
			$ldapfilter         = "(&(objectClass={$authcfg['ldap_attr_groupobj']})({$ldapgroupattribute}={$username}))";
1037
		} else {
1038
			$ldapfilter         = "({$ldapnameattribute}={$username})";
1039
		}
1040
		$ldaptype = "";
1041
		$ldapver = $authcfg['ldap_protver'];
1042
		if (empty($ldapbindun) || empty($ldapbindpw)) {
1043
			$ldapanon = true;
1044
		} else {
1045
			$ldapanon = false;
1046
		}
1047
		$ldapname = $authcfg['name'];
1048
		$ldapfallback = false;
1049
		$ldapscope = $authcfg['ldap_scope'];
1050
		$ldaptimeout = is_numeric($authcfg['ldap_timeout']) ? $authcfg['ldap_timeout'] : 25;
1051
	} else {
1052
		return false;
1053
	}
1054

    
1055
	if (isset($authcfg['ldap_rfc2307'])) {
1056
		$ldapdn = $ldapbasedn;
1057
	} else {
1058
		$ldapdn = $_SESSION['ldapdn'];
1059
	}
1060

    
1061
	/*Convert attribute to lowercase.  php ldap arrays put everything in lowercase */
1062
	$ldapgroupattribute = strtolower($ldapgroupattribute);
1063
	$memberof = array();
1064

    
1065
	/* Setup CA environment if needed. */
1066
	ldap_setup_caenv($authcfg);
1067

    
1068
	/* connect and see if server is up */
1069
	$error = false;
1070
	if (!($ldap = ldap_connect($ldapserver))) {
1071
		$error = true;
1072
	}
1073

    
1074
	if ($error == true) {
1075
		log_error(sprintf(gettext("ERROR! ldap_get_groups() Could not connect to server %s."), $ldapname));
1076
		return memberof;
1077
	}
1078

    
1079
	ldap_set_option($ldap, LDAP_OPT_REFERRALS, 0);
1080
	ldap_set_option($ldap, LDAP_OPT_DEREF, LDAP_DEREF_SEARCHING);
1081
	ldap_set_option($ldap, LDAP_OPT_PROTOCOL_VERSION, (int)$ldapver);
1082
	ldap_set_option($ldap, LDAP_OPT_TIMELIMIT, (int)$ldaptimeout);
1083
	ldap_set_option($ldap, LDAP_OPT_NETWORK_TIMEOUT, (int)$ldaptimeout);
1084

    
1085
	/* bind as user that has rights to read group attributes */
1086
	$ldapbindun = isset($authcfg['ldap_utf8']) ? utf8_encode($ldapbindun) : $ldapbindun;
1087
	$ldapbindpw = isset($authcfg['ldap_utf8']) ? utf8_encode($ldapbindpw) : $ldapbindpw;
1088
	if ($ldapanon == true) {
1089
		if (!($res = @ldap_bind($ldap))) {
1090
			log_error(sprintf(gettext("ERROR! ldap_get_groups() could not bind anonymously to server %s."), $ldapname));
1091
			@ldap_close($ldap);
1092
			return false;
1093
		}
1094
	} else if (!($res = @ldap_bind($ldap, $ldapbindun, $ldapbindpw))) {
1095
		log_error(sprintf(gettext("ERROR! ldap_get_groups() could not bind to server %s."), $ldapname));
1096
		@ldap_close($ldap);
1097
		return memberof;
1098
	}
1099

    
1100
	/* get groups from DN found */
1101
	/* use ldap_read instead of search so we don't have to do a bunch of extra work */
1102
	/* since we know the DN is in $_SESSION['ldapdn'] */
1103
	//$search    = ldap_read($ldap, $ldapdn, "(objectclass=*)", array($ldapgroupattribute));
1104
	if ($ldapscope == "one") {
1105
		$ldapfunc = "ldap_list";
1106
	} else {
1107
		$ldapfunc = "ldap_search";
1108
	}
1109

    
1110
	$search = @$ldapfunc($ldap, $ldapdn, $ldapfilter, array($ldapgroupattribute));
1111
	$info = @ldap_get_entries($ldap, $search);
1112

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

    
1115
	if(is_array($gresults)) {
1116
		/* Iterate through the groups and throw them into an array */
1117
		foreach ($gresults as $grp) {
1118
			if (((isset($authcfg['ldap_rfc2307'])) && (stristr($grp["dn"], "CN=") !== false))
1119
				|| ((!isset($authcfg['ldap_rfc2307'])) && (stristr($grp, "CN=") !== false))) {
1120
				$grpsplit = isset($authcfg['ldap_rfc2307']) ? explode(",", $grp["dn"]) : explode(",", $grp);
1121
				$memberof[] = preg_replace("/CN=/i", "", $grpsplit[0]);
1122
			}
1123
		}
1124
	}
1125

    
1126
	/* Time to close LDAP connection */
1127
	@ldap_unbind($ldap);
1128

    
1129
	$groups = print_r($memberof, true);
1130

    
1131
	//log_error("Returning groups ".$groups." for user $username");
1132

    
1133
	return $memberof;
1134
}
1135

    
1136
function ldap_format_host($host) {
1137
	return is_ipaddrv6($host) ? "[$host]" : $host ;
1138
}
1139

    
1140
function ldap_backed($username, $passwd, $authcfg) {
1141
	global $debug, $config;
1142

    
1143
	if (!$username) {
1144
		return;
1145
	}
1146

    
1147
	if (!function_exists("ldap_connect")) {
1148
		return;
1149
	}
1150

    
1151
	if (!isset($authcfg['ldap_nostrip_at']) && stristr($username, "@")) {
1152
		$username_split = explode("@", $username);
1153
		$username = $username_split[0];
1154
	}
1155
	if (stristr($username, "\\")) {
1156
		$username_split = explode("\\", $username);
1157
		$username = $username_split[0];
1158
	}
1159

    
1160
	if ($authcfg) {
1161
		if (strstr($authcfg['ldap_urltype'], "Standard")) {
1162
			$ldapproto = "ldap";
1163
		} else {
1164
			$ldapproto = "ldaps";
1165
		}
1166
		$ldapserver = "{$ldapproto}://" . ldap_format_host($authcfg['host']);
1167
		$ldapport = $authcfg['ldap_port'];
1168
		if (!empty($ldapport)) {
1169
			$ldapserver .= ":{$ldapport}";
1170
		}
1171
		$ldapbasedn = $authcfg['ldap_basedn'];
1172
		$ldapbindun = $authcfg['ldap_binddn'];
1173
		$ldapbindpw = $authcfg['ldap_bindpw'];
1174
		if (empty($ldapbindun) || empty($ldapbindpw)) {
1175
			$ldapanon = true;
1176
		} else {
1177
			$ldapanon = false;
1178
		}
1179
		$ldapauthcont = $authcfg['ldap_authcn'];
1180
		$ldapnameattribute = strtolower($authcfg['ldap_attr_user']);
1181
		$ldapextendedqueryenabled = $authcfg['ldap_extended_enabled'];
1182
		$ldapextendedquery = $authcfg['ldap_extended_query'];
1183
		$ldapfilter = "";
1184
		if (!$ldapextendedqueryenabled) {
1185
			$ldapfilter = "({$ldapnameattribute}={$username})";
1186
		} else {
1187
			$ldapfilter = "(&({$ldapnameattribute}={$username})({$ldapextendedquery}))";
1188
		}
1189
		$ldaptype = "";
1190
		$ldapver = $authcfg['ldap_protver'];
1191
		$ldapname = $authcfg['name'];
1192
		$ldapscope = $authcfg['ldap_scope'];
1193
		$ldaptimeout = is_numeric($authcfg['ldap_timeout']) ? $authcfg['ldap_timeout'] : 25;
1194
	} else {
1195
		return false;
1196
	}
1197

    
1198
	/* first check if there is even an LDAP server populated */
1199
	if (!$ldapserver) {
1200
		if ($ldapfallback) {
1201
			log_error(gettext("ERROR! ldap_backed() called with no LDAP authentication server defined.  Defaulting to local user database. Visit System -> User Manager."));
1202
			return local_backed($username, $passwd);
1203
		} else {
1204
			log_error(gettext("ERROR! ldap_backed() called with no LDAP authentication server defined."));
1205
		}
1206

    
1207
		return false;
1208
	}
1209

    
1210
	/* Setup CA environment if needed. */
1211
	ldap_setup_caenv($authcfg);
1212

    
1213
	ldap_set_option($ldap, LDAP_OPT_REFERRALS, 0);
1214
	ldap_set_option($ldap, LDAP_OPT_DEREF, LDAP_DEREF_SEARCHING);
1215
	ldap_set_option($ldap, LDAP_OPT_PROTOCOL_VERSION, (int)$ldapver);
1216
	ldap_set_option($ldap, LDAP_OPT_TIMELIMIT, (int)$ldaptimeout);
1217
	ldap_set_option($ldap, LDAP_OPT_NETWORK_TIMEOUT, (int)$ldaptimeout);
1218

    
1219
	/* Make sure we can connect to LDAP */
1220
	$error = false;
1221
	if (!($ldap = ldap_connect($ldapserver))) {
1222
		$error = true;
1223
	}
1224

    
1225
	if ($error == true) {
1226
		log_error(sprintf(gettext("ERROR!  Could not connect to server %s."), $ldapname));
1227
		return false;
1228
	}
1229

    
1230
	/* ok, its up.  now, lets bind as the bind user so we can search it */
1231
	$error = false;
1232
	$ldapbindun = isset($authcfg['ldap_utf8']) ? utf8_encode($ldapbindun) : $ldapbindun;
1233
	$ldapbindpw = isset($authcfg['ldap_utf8']) ? utf8_encode($ldapbindpw) : $ldapbindpw;
1234
	if ($ldapanon == true) {
1235
		if (!($res = @ldap_bind($ldap))) {
1236
			$error = true;
1237
		}
1238
	} else if (!($res = @ldap_bind($ldap, $ldapbindun, $ldapbindpw))) {
1239
		$error = true;
1240
	}
1241

    
1242
	if ($error == true) {
1243
		@ldap_close($ldap);
1244
		log_error(sprintf(gettext("ERROR! Could not bind to server %s."), $ldapname));
1245
		return false;
1246
	}
1247

    
1248
	/* Get LDAP Authcontainers and split em up. */
1249
	$ldac_splits = explode(";", $ldapauthcont);
1250

    
1251
	/* setup the usercount so we think we haven't found anyone yet */
1252
	$usercount = 0;
1253

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

    
1299
	if ($usercount != 1) {
1300
		@ldap_unbind($ldap);
1301
		log_error(gettext("ERROR! Either LDAP search failed, or multiple users were found."));
1302
		return false;
1303
	}
1304

    
1305
	/* Now lets bind as the user we found */
1306
	$passwd = isset($authcfg['ldap_utf8']) ? utf8_encode($passwd) : $passwd;
1307
	if (!($res = @ldap_bind($ldap, $userdn, $passwd))) {
1308
		log_error(sprintf(gettext('ERROR! Could not login to server %1$s as user %2$s: %3$s'), $ldapname, $username, ldap_error($ldap)));
1309
		@ldap_unbind($ldap);
1310
		return false;
1311
	}
1312

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

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

    
1321
	return true;
1322
}
1323

    
1324
function radius_backed($username, $passwd, $authcfg, &$attributes = array()) {
1325
	global $debug, $config;
1326
	$ret = false;
1327

    
1328
	require_once("radius.inc");
1329

    
1330
	$rauth = new Auth_RADIUS_PAP($username, $passwd);
1331
	if ($authcfg) {
1332
		$radiusservers = array();
1333
		$radiusservers[0]['ipaddr'] = $authcfg['host'];
1334
		$radiusservers[0]['port'] = $authcfg['radius_auth_port'];
1335
		$radiusservers[0]['sharedsecret'] = $authcfg['radius_secret'];
1336
		$radiusservers[0]['timeout'] = $authcfg['radius_timeout'];
1337
	} else {
1338
		return false;
1339
	}
1340

    
1341
	/* Add new servers to our instance */
1342
	foreach ($radiusservers as $radsrv) {
1343
		$timeout = (is_numeric($radsrv['timeout'])) ? $radsrv['timeout'] : 5;
1344
		$rauth->addServer($radsrv['ipaddr'], $radsrv['port'], $radsrv['sharedsecret'], $timeout);
1345
	}
1346

    
1347
	if (PEAR::isError($rauth->start())) {
1348
		$retvalue['auth_val'] = 1;
1349
		$retvalue['error'] = $rauth->getError();
1350
		if ($debug) {
1351
			printf(gettext("Radius start: %s<br />\n"), $retvalue['error']);
1352
		}
1353
	}
1354

    
1355
	// XXX - billm - somewhere in here we need to handle securid challenge/response
1356

    
1357
	/* Send request */
1358
	$result = $rauth->send();
1359
	if (PEAR::isError($result)) {
1360
		$retvalue['auth_val'] = 1;
1361
		$retvalue['error'] = $result->getMessage();
1362
		if ($debug) {
1363
			printf(gettext("Radius send failed: %s<br />\n"), $retvalue['error']);
1364
		}
1365
	} else if ($result === true) {
1366
		if ($rauth->getAttributes()) {
1367
			$attributes = $rauth->listAttributes();
1368
		}
1369
		$retvalue['auth_val'] = 2;
1370
		if ($debug) {
1371
			printf(gettext("Radius Auth succeeded")."<br />\n");
1372
		}
1373
		$ret = true;
1374
	} else {
1375
		$retvalue['auth_val'] = 3;
1376
		if ($debug) {
1377
			printf(gettext("Radius Auth rejected")."<br />\n");
1378
		}
1379
	}
1380

    
1381
	// close OO RADIUS_AUTHENTICATION
1382
	$rauth->close();
1383

    
1384
	return $ret;
1385
}
1386

    
1387
/*
1388
	$attributes must contain a "class" key containing the groups and local
1389
	groups must exist to match.
1390
*/
1391
function radius_get_groups($attributes) {
1392
	$groups = array();
1393
	if (!empty($attributes) && is_array($attributes) && !empty($attributes['class'])) {
1394
		$groups = explode(";", $attributes['class']);
1395
		foreach ($groups as & $grp) {
1396
			$grp = trim($grp);
1397
			if (strtolower(substr($grp, 0, 3)) == "ou=") {
1398
				$grp = substr($grp, 3);
1399
			}
1400
		}
1401
	}
1402
	return $groups;
1403
}
1404

    
1405
function get_user_expiration_date($username) {
1406
	$user = getUserEntry($username);
1407
	if ($user['expires']) {
1408
		return $user['expires'];
1409
	}
1410
}
1411

    
1412
function is_account_expired($username) {
1413
	$expirydate = get_user_expiration_date($username);
1414
	if ($expirydate) {
1415
		if (strtotime("-1 day") > strtotime(date("m/d/Y", strtotime($expirydate)))) {
1416
			return true;
1417
		}
1418
	}
1419

    
1420
	return false;
1421
}
1422

    
1423
function is_account_disabled($username) {
1424
	$user = getUserEntry($username);
1425
	if (isset($user['disabled'])) {
1426
		return true;
1427
	}
1428

    
1429
	return false;
1430
}
1431

    
1432
function auth_get_authserver($name) {
1433
	global $config;
1434

    
1435
	if (is_array($config['system']['authserver'])) {
1436
		foreach ($config['system']['authserver'] as $authcfg) {
1437
			if ($authcfg['name'] == $name) {
1438
				return $authcfg;
1439
			}
1440
		}
1441
	}
1442
	if ($name == "Local Database") {
1443
		return array("name" => gettext("Local Database"), "type" => "Local Auth", "host" => $config['system']['hostname']);
1444
	}
1445
}
1446

    
1447
function auth_get_authserver_list() {
1448
	global $config;
1449

    
1450
	$list = array();
1451

    
1452
	if (is_array($config['system']['authserver'])) {
1453
		foreach ($config['system']['authserver'] as $authcfg) {
1454
			/* Add support for disabled entries? */
1455
			$list[$authcfg['name']] = $authcfg;
1456
		}
1457
	}
1458

    
1459
	$list["Local Database"] = array("name" => gettext("Local Database"), "type" => "Local Auth", "host" => $config['system']['hostname']);
1460
	return $list;
1461
}
1462

    
1463
function getUserGroups($username, $authcfg, &$attributes = array()) {
1464
	global $config;
1465

    
1466
	$allowed_groups = array();
1467

    
1468
	switch ($authcfg['type']) {
1469
		case 'ldap':
1470
			$allowed_groups = @ldap_get_groups($username, $authcfg);
1471
			break;
1472
		case 'radius':
1473
			$allowed_groups = @radius_get_groups($attributes);
1474
			break;
1475
		default:
1476
			$user = getUserEntry($username);
1477
			$allowed_groups = @local_user_get_groups($user, true);
1478
			break;
1479
	}
1480

    
1481
	$member_groups = array();
1482
	if (is_array($config['system']['group'])) {
1483
		foreach ($config['system']['group'] as $group) {
1484
			if (in_array($group['name'], $allowed_groups)) {
1485
				$member_groups[] = $group['name'];
1486
			}
1487
		}
1488
	}
1489

    
1490
	return $member_groups;
1491
}
1492

    
1493
function authenticate_user($username, $password, $authcfg = NULL, &$attributes = array()) {
1494

    
1495
	if (!$authcfg) {
1496
		return local_backed($username, $password);
1497
	}
1498

    
1499
	$authenticated = false;
1500
	switch ($authcfg['type']) {
1501
		case 'ldap':
1502
			if (ldap_backed($username, $password, $authcfg)) {
1503
				$authenticated = true;
1504
			}
1505
			break;
1506
		case 'radius':
1507
			if (radius_backed($username, $password, $authcfg, $attributes)) {
1508
				$authenticated = true;
1509
			}
1510
			break;
1511
		default:
1512
			/* lookup user object by name */
1513
			if (local_backed($username, $password)) {
1514
				$authenticated = true;
1515
			}
1516
			break;
1517
		}
1518

    
1519
	return $authenticated;
1520
}
1521

    
1522
function session_auth() {
1523
	global $config, $_SESSION, $page;
1524

    
1525
	// Handle HTTPS httponly and secure flags
1526
	$currentCookieParams = session_get_cookie_params();
1527
	session_set_cookie_params(
1528
		$currentCookieParams["lifetime"],
1529
		$currentCookieParams["path"],
1530
		NULL,
1531
		($config['system']['webgui']['protocol'] == "https"),
1532
		true
1533
	);
1534

    
1535
	if (!session_id()) {
1536
		session_start();
1537
	}
1538

    
1539
	// Detect protocol change
1540
	if (!isset($_POST['login']) && !empty($_SESSION['Logged_In']) && $_SESSION['protocol'] != $config['system']['webgui']['protocol']) {
1541
		return false;
1542
	}
1543

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

    
1580
	/* Show login page if they aren't logged in */
1581
	if (empty($_SESSION['Logged_In'])) {
1582
		return false;
1583
	}
1584

    
1585
	/* If session timeout isn't set, we don't mark sessions stale */
1586
	if (!isset($config['system']['webgui']['session_timeout'])) {
1587
		/* Default to 4 hour timeout if one is not set */
1588
		if ($_SESSION['last_access'] < (time() - 14400)) {
1589
			$_GET['logout'] = true;
1590
			$_SESSION['Logout'] = true;
1591
		} else {
1592
			$_SESSION['last_access'] = time();
1593
		}
1594
	} else if (intval($config['system']['webgui']['session_timeout']) == 0) {
1595
		/* only update if it wasn't ajax */
1596
		if (!isAjax()) {
1597
			$_SESSION['last_access'] = time();
1598
		}
1599
	} else {
1600
		/* Check for stale session */
1601
		if ($_SESSION['last_access'] < (time() - ($config['system']['webgui']['session_timeout'] * 60))) {
1602
			$_GET['logout'] = true;
1603
			$_SESSION['Logout'] = true;
1604
		} else {
1605
			/* only update if it wasn't ajax */
1606
			if (!isAjax()) {
1607
				$_SESSION['last_access'] = time();
1608
			}
1609
		}
1610
	}
1611

    
1612
	/* user hit the logout button */
1613
	if (isset($_GET['logout'])) {
1614

    
1615
		if ($_SESSION['Logout']) {
1616
			log_error(sprintf(gettext("Session timed out for user '%1\$s' from: %2\$s"), $_SESSION['Username'], $_SERVER['REMOTE_ADDR']));
1617
		} else {
1618
			log_error(sprintf(gettext("User logged out for user '%1\$s' from: %2\$s"), $_SESSION['Username'], $_SERVER['REMOTE_ADDR']));
1619
		}
1620

    
1621
		/* wipe out $_SESSION */
1622
		$_SESSION = array();
1623

    
1624
		if (isset($_COOKIE[session_name()])) {
1625
			setcookie(session_name(), '', time()-42000, '/');
1626
		}
1627

    
1628
		/* and destroy it */
1629
		session_destroy();
1630

    
1631
		$scriptName = explode("/", $_SERVER["SCRIPT_FILENAME"]);
1632
		$scriptElms = count($scriptName);
1633
		$scriptName = $scriptName[$scriptElms-1];
1634

    
1635
		if (isAjax()) {
1636
			return false;
1637
		}
1638

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

    
1642
		return false;
1643
	}
1644

    
1645
	/*
1646
	 * this is for debugging purpose if you do not want to use Ajax
1647
	 * to submit a HTML form. It basically disables the observation
1648
	 * of the submit event and hence does not trigger Ajax.
1649
	 */
1650
	if ($_GET['disable_ajax']) {
1651
		$_SESSION['NO_AJAX'] = "True";
1652
	}
1653

    
1654
	/*
1655
	 * Same to re-enable Ajax.
1656
	 */
1657
	if ($_GET['enable_ajax']) {
1658
		unset($_SESSION['NO_AJAX']);
1659
	}
1660

    
1661
	return true;
1662
}
1663

    
1664
?>
(4-4/68)