Project

General

Profile

Download (43.2 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
				echo "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n        \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">";
129
				echo "<html><head><title>" . gettext("Redirecting...") . "</title></head><body>" . gettext("Redirecting to the dashboard...") . "</body></html>";
130
				exit;
131
			}
132
		}
133
		$found_host = false;
134
		$referrer_host = parse_url($_SERVER['HTTP_REFERER'], PHP_URL_HOST);
135
		$referrer_host = str_replace(array("[", "]"), "", $referrer_host);
136
		if ($referrer_host) {
137
			if (strcasecmp($referrer_host, $config['system']['hostname'] . "." . $config['system']['domain']) == 0 ||
138
			    strcasecmp($referrer_host, $config['system']['hostname']) == 0) {
139
				$found_host = true;
140
			}
141

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

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

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

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

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

    
209
$groupindex = index_groups();
210
$userindex = index_users();
211

    
212
function index_groups() {
213
	global $g, $debug, $config, $groupindex;
214

    
215
	$groupindex = array();
216

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

    
225
	return ($groupindex);
226
}
227

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

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

    
239
	return ($userindex);
240
}
241

    
242
function & getUserEntry($name) {
243
	global $debug, $config, $userindex;
244
	if (isset($userindex[$name])) {
245
		return $config['system']['user'][$userindex[$name]];
246
	}
247
}
248

    
249
function & getUserEntryByUID($uid) {
250
	global $debug, $config;
251

    
252
	if (is_array($config['system']['user'])) {
253
		foreach ($config['system']['user'] as & $user) {
254
			if ($user['uid'] == $uid) {
255
				return $user;
256
			}
257
		}
258
	}
259

    
260
	return false;
261
}
262

    
263
function & getGroupEntry($name) {
264
	global $debug, $config, $groupindex;
265
	if (isset($groupindex[$name])) {
266
		return $config['system']['group'][$groupindex[$name]];
267
	}
268
}
269

    
270
function & getGroupEntryByGID($gid) {
271
	global $debug, $config;
272

    
273
	if (is_array($config['system']['group'])) {
274
		foreach ($config['system']['group'] as & $group) {
275
			if ($group['gid'] == $gid) {
276
				return $group;
277
			}
278
		}
279
	}
280

    
281
	return false;
282
}
283

    
284
function get_user_privileges(& $user) {
285

    
286
	$privs = $user['priv'];
287
	if (!is_array($privs)) {
288
		$privs = array();
289
	}
290

    
291
	$names = local_user_get_groups($user, true);
292

    
293
	foreach ($names as $name) {
294
		$group = getGroupEntry($name);
295
		if (is_array($group['priv'])) {
296
			$privs = array_merge( $privs, $group['priv']);
297
		}
298
	}
299

    
300
	return $privs;
301
}
302

    
303
function userHasPrivilege($userent, $privid = false) {
304

    
305
	if (!$privid || !is_array($userent)) {
306
		return false;
307
	}
308

    
309
	$privs = get_user_privileges($userent);
310

    
311
	if (!is_array($privs)) {
312
		return false;
313
	}
314

    
315
	if (!in_array($privid, $privs)) {
316
		return false;
317
	}
318

    
319
	return true;
320
}
321

    
322
function local_backed($username, $passwd) {
323

    
324
	$user = getUserEntry($username);
325
	if (!$user) {
326
		return false;
327
	}
328

    
329
	if (is_account_disabled($username) || is_account_expired($username)) {
330
		return false;
331
	}
332

    
333
	if ($user['password']) {
334
		if (crypt($passwd, $user['password']) == $user['password']) {
335
			return true;
336
		}
337
	}
338

    
339
	if ($user['md5-hash']) {
340
		if (md5($passwd) == $user['md5-hash']) {
341
			return true;
342
		}
343
	}
344

    
345
	return false;
346
}
347

    
348
function local_sync_accounts() {
349
	global $debug, $config;
350
	conf_mount_rw();
351

    
352
	/* remove local users to avoid uid conflicts */
353
	$fd = popen("/usr/sbin/pw usershow -a", "r");
354
	if ($fd) {
355
		while (!feof($fd)) {
356
			$line = explode(":",fgets($fd));
357
			if (((!strncmp($line[0], "_", 1)) || ($line[2] < 2000) || ($line[2] > 65000)) && ($line[0] != "admin")) {
358
				continue;
359
			}
360
			/*
361
			 * If a crontab was created to user, pw userdel will be interactive and
362
			 * can cause issues. Just remove crontab before run it when necessary
363
			 */
364
			unlink_if_exists("/var/cron/tabs/{$line[0]}");
365
			$cmd = "/usr/sbin/pw userdel -n '{$line[0]}'";
366
			if ($debug) {
367
				log_error(sprintf(gettext("Running: %s"), $cmd));
368
			}
369
			mwexec($cmd);
370
		}
371
		pclose($fd);
372
	}
373

    
374
	/* remove local groups to avoid gid conflicts */
375
	$gids = array();
376
	$fd = popen("/usr/sbin/pw groupshow -a", "r");
377
	if ($fd) {
378
		while (!feof($fd)) {
379
			$line = explode(":",fgets($fd));
380
			if (!strncmp($line[0], "_", 1)) {
381
				continue;
382
			}
383
			if ($line[2] < 2000) {
384
				continue;
385
			}
386
			if ($line[2] > 65000) {
387
				continue;
388
			}
389
			$cmd = "/usr/sbin/pw groupdel {$line[2]}";
390
			if ($debug) {
391
				log_error(sprintf(gettext("Running: %s"), $cmd));
392
			}
393
			mwexec($cmd);
394
		}
395
		pclose($fd);
396
	}
397

    
398
	/* make sure the all group exists */
399
	$allgrp = getGroupEntryByGID(1998);
400
	local_group_set($allgrp, true);
401

    
402
	/* sync all local users */
403
	if (is_array($config['system']['user'])) {
404
		foreach ($config['system']['user'] as $user) {
405
			local_user_set($user);
406
		}
407
	}
408

    
409
	/* sync all local groups */
410
	if (is_array($config['system']['group'])) {
411
		foreach ($config['system']['group'] as $group) {
412
			local_group_set($group);
413
		}
414
	}
415

    
416
	conf_mount_ro();
417

    
418
}
419

    
420
function local_user_set(& $user) {
421
	global $g, $debug;
422

    
423
	if (empty($user['password'])) {
424
		log_error("There is something wrong in your config because user {$user['name']} password is missing!");
425
		return;
426
	}
427

    
428
	conf_mount_rw();
429

    
430
	$home_base = "/home/";
431
	$user_uid = $user['uid'];
432
	$user_name = $user['name'];
433
	$user_home = "{$home_base}{$user_name}";
434
	$user_shell = "/etc/rc.initial";
435
	$user_group = "nobody";
436

    
437
	// Ensure $home_base exists and is writable
438
	if (!is_dir($home_base)) {
439
		mkdir($home_base, 0755);
440
	}
441

    
442
	$lock_account = false;
443
	/* configure shell type */
444
	/* Cases here should be ordered by most privileged to least privileged. */
445
	if (userHasPrivilege($user, "user-shell-access") || userHasPrivilege($user, "page-all")) {
446
		$user_shell = "/bin/tcsh";
447
	} elseif (userHasPrivilege($user, "user-copy-files")) {
448
		$user_shell = "/usr/local/bin/scponly";
449
	} elseif (userHasPrivilege($user, "user-ssh-tunnel")) {
450
		$user_shell = "/usr/local/sbin/ssh_tunnel_shell";
451
	} elseif (userHasPrivilege($user, "user-ipsec-xauth-dialin")) {
452
		$user_shell = "/sbin/nologin";
453
	} else {
454
		$user_shell = "/sbin/nologin";
455
		$lock_account = true;
456
	}
457

    
458
	/* Lock out disabled or expired users, unless it's root/admin. */
459
	if ((is_account_disabled($user_name) || is_account_expired($user_name)) && ($user_uid != 0)) {
460
		$user_shell = "/sbin/nologin";
461
		$lock_account = true;
462
	}
463

    
464
	/* root user special handling */
465
	if ($user_uid == 0) {
466
		$cmd = "/usr/sbin/pw usermod -q -n root -s /bin/sh -H 0";
467
		if ($debug) {
468
			log_error(sprintf(gettext("Running: %s"), $cmd));
469
		}
470
		$fd = popen($cmd, "w");
471
		fwrite($fd, $user['password']);
472
		pclose($fd);
473
		$user_group = "wheel";
474
		$user_home = "/root";
475
		$user_shell = "/etc/rc.initial";
476
	}
477

    
478
	/* read from pw db */
479
	$fd = popen("/usr/sbin/pw usershow -n {$user_name} 2>&1", "r");
480
	$pwread = fgets($fd);
481
	pclose($fd);
482
	$userattrs = explode(":", trim($pwread));
483

    
484
	/* determine add or mod */
485
	if (($userattrs[0] != $user['name']) || (!strncmp($pwread, "pw:", 3))) {
486
		$user_op = "useradd -m -k /etc/skel -o";
487
	} else {
488
		$user_op = "usermod";
489
	}
490

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

    
497
	if ($debug) {
498
		log_error(sprintf(gettext("Running: %s"), $cmd));
499
	}
500
	$fd = popen($cmd, "w");
501
	fwrite($fd, $user['password']);
502
	pclose($fd);
503

    
504
	/* create user directory if required */
505
	if (!is_dir($user_home)) {
506
		mkdir($user_home, 0700);
507
		mwexec("/bin/cp /root/.* {$home_base}/", true);
508
	}
509
	@chown($user_home, $user_name);
510
	@chgrp($user_home, $user_group);
511

    
512
	/* write out ssh authorized key file */
513
	if ($user['authorizedkeys']) {
514
		if (!is_dir("{$user_home}/.ssh")) {
515
			@mkdir("{$user_home}/.ssh", 0700);
516
			@chown("{$user_home}/.ssh", $user_name);
517
		}
518
		$keys = base64_decode($user['authorizedkeys']);
519
		@file_put_contents("{$user_home}/.ssh/authorized_keys", $keys);
520
		@chown("{$user_home}/.ssh/authorized_keys", $user_name);
521
	} else {
522
		unlink_if_exists("{$user_home}/.ssh/authorized_keys");
523
	}
524

    
525
	$un = $lock_account ? "" : "un";
526
	exec("/usr/sbin/pw {$un}lock {$user_name} -q");
527

    
528
	conf_mount_ro();
529
}
530

    
531
function local_user_del($user) {
532
	global $debug;
533

    
534
	/* remove all memberships */
535
	local_user_set_groups($user);
536

    
537
	/* Don't remove /root */
538
	if ($user['uid'] != 0) {
539
		$rmhome = "-r";
540
	}
541

    
542
	/* read from pw db */
543
	$fd = popen("/usr/sbin/pw usershow -n {$user['name']} 2>&1", "r");
544
	$pwread = fgets($fd);
545
	pclose($fd);
546
	$userattrs = explode(":", trim($pwread));
547

    
548
	if ($userattrs[0] != $user['name']) {
549
		log_error("Tried to remove user {$user['name']} but got user {$userattrs[0]} instead. Bailing.");
550
		return;
551
	}
552

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

    
556
	if ($debug) {
557
		log_error(sprintf(gettext("Running: %s"), $cmd));
558
	}
559
	mwexec($cmd);
560

    
561
	/* Delete user from groups needs a call to write_config() */
562
	local_group_del_user($user);
563
}
564

    
565
function local_user_set_password(& $user, $password) {
566

    
567
	$user['password'] = crypt($password);
568
	$user['md5-hash'] = md5($password);
569

    
570
	// Converts ascii to unicode.
571
	$astr = (string) $password;
572
	$ustr = '';
573
	for ($i = 0; $i < strlen($astr); $i++) {
574
		$a = ord($astr{$i}) << 8;
575
		$ustr.= sprintf("%X", $a);
576
	}
577

    
578
	// Generate the NT-HASH from the unicode string
579
	$user['nt-hash'] = bin2hex(hash("md4", $ustr));
580
}
581

    
582
function local_user_get_groups($user, $all = false) {
583
	global $debug, $config;
584

    
585
	$groups = array();
586
	if (!is_array($config['system']['group'])) {
587
		return $groups;
588
	}
589

    
590
	foreach ($config['system']['group'] as $group) {
591
		if ( $all || ( !$all && ($group['name'] != "all"))) {
592
			if (is_array($group['member'])) {
593
				if (in_array($user['uid'], $group['member'])) {
594
					$groups[] = $group['name'];
595
				}
596
			}
597
		}
598
	}
599

    
600
	if ($all) {
601
		$groups[] = "all";
602
	}
603

    
604
	sort($groups);
605

    
606
	return $groups;
607

    
608
}
609

    
610
function local_user_set_groups($user, $new_groups = NULL ) {
611
	global $debug, $config, $groupindex;
612

    
613
	if (!is_array($config['system']['group'])) {
614
		return;
615
	}
616

    
617
	$cur_groups = local_user_get_groups($user, true);
618
	$mod_groups = array();
619

    
620
	if (!is_array($new_groups)) {
621
		$new_groups = array();
622
	}
623

    
624
	if (!is_array($cur_groups)) {
625
		$cur_groups = array();
626
	}
627

    
628
	/* determine which memberships to add */
629
	foreach ($new_groups as $groupname) {
630
		if ($groupname == '' || in_array($groupname,$cur_groups)) {
631
			continue;
632
		}
633
		$group = & $config['system']['group'][$groupindex[$groupname]];
634
		$group['member'][] = $user['uid'];
635
		$mod_groups[] = $group;
636
	}
637
	unset($group);
638

    
639
	/* determine which memberships to remove */
640
	foreach ($cur_groups as $groupname) {
641
		if (in_array($groupname,$new_groups)) {
642
			continue;
643
		}
644
		if (!isset($config['system']['group'][$groupindex[$groupname]])) {
645
			continue;
646
		}
647
		$group = & $config['system']['group'][$groupindex[$groupname]];
648
		if (is_array($group['member'])) {
649
			$index = array_search($user['uid'], $group['member']);
650
			array_splice($group['member'], $index, 1);
651
			$mod_groups[] = $group;
652
		}
653
	}
654
	unset($group);
655

    
656
	/* sync all modified groups */
657
	foreach ($mod_groups as $group) {
658
		local_group_set($group);
659
	}
660
}
661

    
662
function local_group_del_user($user) {
663
	global $config;
664

    
665
	if (!is_array($config['system']['group'])) {
666
		return;
667
	}
668

    
669
	foreach ($config['system']['group'] as $group) {
670
		if (is_array($group['member'])) {
671
			foreach ($group['member'] as $idx => $uid) {
672
				if ($user['uid'] == $uid) {
673
					unset($config['system']['group']['member'][$idx]);
674
				}
675
			}
676
		}
677
	}
678
}
679

    
680
function local_group_set($group, $reset = false) {
681
	global $debug;
682

    
683
	$group_name = $group['name'];
684
	$group_gid = $group['gid'];
685
	$group_members = '';
686
	if (!$reset && !empty($group['member']) && count($group['member']) > 0) {
687
		$group_members = implode(",",$group['member']);
688
	}
689

    
690
	if (empty($group_name)) {
691
		return;
692
	}
693

    
694
	/* read from group db */
695
	$fd = popen("/usr/sbin/pw groupshow {$group_name} 2>&1", "r");
696
	$pwread = fgets($fd);
697
	pclose($fd);
698

    
699
	/* determine add or mod */
700
	if (!strncmp($pwread, "pw:", 3)) {
701
		$group_op = "groupadd";
702
	} else {
703
		$group_op = "groupmod";
704
	}
705

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

    
709
	if ($debug) {
710
		log_error(sprintf(gettext("Running: %s"), $cmd));
711
	}
712
	mwexec($cmd);
713

    
714
}
715

    
716
function local_group_del($group) {
717
	global $debug;
718

    
719
	/* delete from group db */
720
	$cmd = "/usr/sbin/pw groupdel {$group['name']}";
721

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

    
728
function ldap_test_connection($authcfg) {
729
	global $debug, $config, $g;
730

    
731
	if ($authcfg) {
732
		if (strstr($authcfg['ldap_urltype'], "Standard")) {
733
			$ldapproto = "ldap";
734
		} else {
735
			$ldapproto = "ldaps";
736
		}
737
		$ldapserver = "{$ldapproto}://" . ldap_format_host($authcfg['host']);
738
		$ldapport = $authcfg['ldap_port'];
739
		if (!empty($ldapport)) {
740
			$ldapserver .= ":{$ldapport}";
741
		}
742
		$ldapbasedn = $authcfg['ldap_basedn'];
743
		$ldapbindun = $authcfg['ldap_binddn'];
744
		$ldapbindpw = $authcfg['ldap_bindpw'];
745
	} else {
746
		return false;
747
	}
748

    
749
	/* first check if there is even an LDAP server populated */
750
	if ( !$ldapserver) {
751
		return false;
752
	}
753

    
754
	/* Setup CA environment if needed. */
755
	ldap_setup_caenv($authcfg);
756

    
757
	/* connect and see if server is up */
758
	$error = false;
759
	if (!($ldap = ldap_connect($ldapserver))) {
760
		$error = true;
761
	}
762

    
763
	if ($error == true) {
764
		log_error(sprintf(gettext("ERROR!  Could not connect to server %s."), $ldapname));
765
		return false;
766
	}
767

    
768
	return true;
769
}
770

    
771
function ldap_setup_caenv($authcfg) {
772
	global $g;
773
	require_once("certs.inc");
774

    
775
	unset($caref);
776
	if (empty($authcfg['ldap_caref']) || !strstr($authcfg['ldap_urltype'], "SSL")) {
777
		putenv('LDAPTLS_REQCERT=never');
778
		return;
779
	} else {
780
		$caref = lookup_ca($authcfg['ldap_caref']);
781
		if (!$caref) {
782
			log_error(sprintf(gettext("LDAP: Could not lookup CA by reference for host %s."), $authcfg['ldap_caref']));
783
			/* XXX: Prevent for credential leaking since we cannot setup the CA env. Better way? */
784
			putenv('LDAPTLS_REQCERT=hard');
785
			return;
786
		}
787
		if (!is_dir("{$g['varrun_path']}/certs")) {
788
			@mkdir("{$g['varrun_path']}/certs");
789
		}
790
		if (file_exists("{$g['varrun_path']}/certs/{$caref['refid']}.ca")) {
791
			@unlink("{$g['varrun_path']}/certs/{$caref['refid']}.ca");
792
		}
793
		file_put_contents("{$g['varrun_path']}/certs/{$caref['refid']}.ca", base64_decode($caref['crt']));
794
		@chmod("{$g['varrun_path']}/certs/{$caref['refid']}.ca", 0600);
795
		putenv('LDAPTLS_REQCERT=hard');
796
		/* XXX: Probably even the hashed link should be created for this? */
797
		putenv("LDAPTLS_CACERTDIR={$g['varrun_path']}/certs");
798
		putenv("LDAPTLS_CACERT={$g['varrun_path']}/certs/{$caref['refid']}.ca");
799
	}
800
}
801

    
802
function ldap_test_bind($authcfg) {
803
	global $debug, $config, $g;
804

    
805
	if ($authcfg) {
806
		if (strstr($authcfg['ldap_urltype'], "Standard")) {
807
			$ldapproto = "ldap";
808
		} else {
809
			$ldapproto = "ldaps";
810
		}
811
		$ldapserver = "{$ldapproto}://" . ldap_format_host($authcfg['host']);
812
		$ldapport = $authcfg['ldap_port'];
813
		if (!empty($ldapport)) {
814
			$ldapserver .= ":{$ldapport}";
815
		}
816
		$ldapbasedn = $authcfg['ldap_basedn'];
817
		$ldapbindun = $authcfg['ldap_binddn'];
818
		$ldapbindpw = $authcfg['ldap_bindpw'];
819
		$ldapver = $authcfg['ldap_protver'];
820
		if (empty($ldapbndun) || empty($ldapbindpw)) {
821
			$ldapanon = true;
822
		} else {
823
			$ldapanon = false;
824
		}
825
	} else {
826
		return false;
827
	}
828

    
829
	/* first check if there is even an LDAP server populated */
830
	if (!$ldapserver) {
831
		return false;
832
	}
833

    
834
	/* Setup CA environment if needed. */
835
	ldap_setup_caenv($authcfg);
836

    
837
	/* connect and see if server is up */
838
	$error = false;
839
	if (!($ldap = ldap_connect($ldapserver))) {
840
		$error = true;
841
	}
842

    
843
	if ($error == true) {
844
		log_error(sprintf(gettext("ERROR!  Could not connect to server %s."), $ldapname));
845
		return false;
846
	}
847

    
848
	ldap_set_option($ldap, LDAP_OPT_REFERRALS, 0);
849
	ldap_set_option($ldap, LDAP_OPT_DEREF, LDAP_DEREF_SEARCHING);
850
	ldap_set_option($ldap, LDAP_OPT_PROTOCOL_VERSION, (int)$ldapver);
851

    
852
	$ldapbindun = isset($authcfg['ldap_utf8']) ? utf8_encode($ldapbindun) : $ldapbindun;
853
	$ldapbindpw = isset($authcfg['ldap_utf8']) ? utf8_encode($ldapbindpw) : $ldapbindpw;
854
	if ($ldapanon == true) {
855
		if (!($res = @ldap_bind($ldap))) {
856
			@ldap_close($ldap);
857
			return false;
858
		}
859
	} else if (!($res = @ldap_bind($ldap, $ldapbindun, $ldapbindpw))) {
860
		@ldap_close($ldap);
861
		return false;
862
	}
863

    
864
	@ldap_unbind($ldap);
865

    
866
	return true;
867
}
868

    
869
function ldap_get_user_ous($show_complete_ou=true, $authcfg) {
870
	global $debug, $config, $g;
871

    
872
	if (!function_exists("ldap_connect")) {
873
		return;
874
	}
875

    
876
	$ous = array();
877

    
878
	if ($authcfg) {
879
		if (strstr($authcfg['ldap_urltype'], "Standard")) {
880
			$ldapproto = "ldap";
881
		} else {
882
			$ldapproto = "ldaps";
883
		}
884
		$ldapserver = "{$ldapproto}://" . ldap_format_host($authcfg['host']);
885
		$ldapport = $authcfg['ldap_port'];
886
		if (!empty($ldapport)) {
887
			$ldapserver .= ":{$ldapport}";
888
		}
889
		$ldapbasedn = $authcfg['ldap_basedn'];
890
		$ldapbindun = $authcfg['ldap_binddn'];
891
		$ldapbindpw = $authcfg['ldap_bindpw'];
892
		$ldapver = $authcfg['ldap_protver'];
893
		if (empty($ldapbindun) || empty($ldapbindpw)) {
894
			$ldapanon = true;
895
		} else {
896
			$ldapanon = false;
897
		}
898
		$ldapname = $authcfg['name'];
899
		$ldapfallback = false;
900
		$ldapscope = $authcfg['ldap_scope'];
901
	} else {
902
		return false;
903
	}
904

    
905
	/* first check if there is even an LDAP server populated */
906
	if (!$ldapserver) {
907
		log_error(gettext("ERROR!  ldap_get_user_ous() backed selected with no LDAP authentication server defined."));
908
		return $ous;
909
	}
910

    
911
	/* Setup CA environment if needed. */
912
	ldap_setup_caenv($authcfg);
913

    
914
	/* connect and see if server is up */
915
	$error = false;
916
	if (!($ldap = ldap_connect($ldapserver))) {
917
		$error = true;
918
	}
919

    
920
	if ($error == true) {
921
		log_error(sprintf(gettext("ERROR!  Could not connect to server %s."), $ldapname));
922
		return $ous;
923
	}
924

    
925
	$ldapfilter = "(|(ou=*)(cn=Users))";
926

    
927
	ldap_set_option($ldap, LDAP_OPT_REFERRALS, 0);
928
	ldap_set_option($ldap, LDAP_OPT_DEREF, LDAP_DEREF_SEARCHING);
929
	ldap_set_option($ldap, LDAP_OPT_PROTOCOL_VERSION, (int)$ldapver);
930

    
931
	$ldapbindun = isset($authcfg['ldap_utf8']) ? utf8_encode($ldapbindun) : $ldapbindun;
932
	$ldapbindpw = isset($authcfg['ldap_utf8']) ? utf8_encode($ldapbindpw) : $ldapbindpw;
933
	if ($ldapanon == true) {
934
		if (!($res = @ldap_bind($ldap))) {
935
			log_error(sprintf(gettext("ERROR! ldap_get_user_ous() could not bind anonymously to server %s."), $ldapname));
936
			@ldap_close($ldap);
937
			return $ous;
938
		}
939
	} else if (!($res = @ldap_bind($ldap, $ldapbindun, $ldapbindpw))) {
940
		log_error(sprintf(gettext("ERROR! ldap_get_user_ous() could not bind to server %s."), $ldapname));
941
		@ldap_close($ldap);
942
		return $ous;
943
	}
944

    
945
	if ($ldapscope == "one") {
946
		$ldapfunc = "ldap_list";
947
	} else {
948
		$ldapfunc = "ldap_search";
949
	}
950

    
951
	$search = @$ldapfunc($ldap, $ldapbasedn, $ldapfilter);
952
	$info = @ldap_get_entries($ldap, $search);
953

    
954
	if (is_array($info)) {
955
		foreach ($info as $inf) {
956
			if (!$show_complete_ou) {
957
				$inf_split = explode(",", $inf['dn']);
958
				$ou = $inf_split[0];
959
				$ou = str_replace("OU=","", $ou);
960
				$ou = str_replace("CN=","", $ou);
961
			} else {
962
				if ($inf['dn']) {
963
					$ou = $inf['dn'];
964
				}
965
			}
966
			if ($ou) {
967
				$ous[] = $ou;
968
			}
969
		}
970
	}
971

    
972
	@ldap_unbind($ldap);
973

    
974
	return $ous;
975
}
976

    
977
function ldap_get_groups($username, $authcfg) {
978
	global $debug, $config;
979

    
980
	if (!function_exists("ldap_connect")) {
981
		return;
982
	}
983

    
984
	if (!$username) {
985
		return false;
986
	}
987

    
988
	if (!isset($authcfg['ldap_nostrip_at']) && stristr($username, "@")) {
989
		$username_split = explode("@", $username);
990
		$username = $username_split[0];
991
	}
992

    
993
	if (stristr($username, "\\")) {
994
		$username_split = explode("\\", $username);
995
		$username = $username_split[0];
996
	}
997

    
998
	//log_error("Getting LDAP groups for {$username}.");
999
	if ($authcfg) {
1000
		if (strstr($authcfg['ldap_urltype'], "Standard")) {
1001
			$ldapproto = "ldap";
1002
		} else {
1003
			$ldapproto = "ldaps";
1004
		}
1005
		$ldapserver = "{$ldapproto}://" . ldap_format_host($authcfg['host']);
1006
		$ldapport = $authcfg['ldap_port'];
1007
		if (!empty($ldapport)) {
1008
			$ldapserver .= ":{$ldapport}";
1009
		}
1010
		$ldapbasedn = $authcfg['ldap_basedn'];
1011
		$ldapbindun = $authcfg['ldap_binddn'];
1012
		$ldapbindpw = $authcfg['ldap_bindpw'];
1013
		$ldapauthcont = $authcfg['ldap_authcn'];
1014
		$ldapnameattribute = strtolower($authcfg['ldap_attr_user']);
1015
		$ldapgroupattribute = strtolower($authcfg['ldap_attr_member']);
1016
		$ldapfilter = "({$ldapnameattribute}={$username})";
1017
		$ldaptype = "";
1018
		$ldapver = $authcfg['ldap_protver'];
1019
		if (empty($ldapbindun) || empty($ldapbindpw)) {
1020
			$ldapanon = true;
1021
		} else {
1022
			$ldapanon = false;
1023
		}
1024
		$ldapname = $authcfg['name'];
1025
		$ldapfallback = false;
1026
		$ldapscope = $authcfg['ldap_scope'];
1027
	} else {
1028
		return false;
1029
	}
1030

    
1031
	$ldapdn = $_SESSION['ldapdn'];
1032

    
1033
	/*Convert attribute to lowercase.  php ldap arrays put everything in lowercase */
1034
	$ldapgroupattribute = strtolower($ldapgroupattribute);
1035
	$memberof = array();
1036

    
1037
	/* Setup CA environment if needed. */
1038
	ldap_setup_caenv($authcfg);
1039

    
1040
	/* connect and see if server is up */
1041
	$error = false;
1042
	if (!($ldap = ldap_connect($ldapserver))) {
1043
		$error = true;
1044
	}
1045

    
1046
	if ($error == true) {
1047
		log_error(sprintf(gettext("ERROR! ldap_get_groups() Could not connect to server %s."), $ldapname));
1048
		return memberof;
1049
	}
1050

    
1051
	ldap_set_option($ldap, LDAP_OPT_REFERRALS, 0);
1052
	ldap_set_option($ldap, LDAP_OPT_DEREF, LDAP_DEREF_SEARCHING);
1053
	ldap_set_option($ldap, LDAP_OPT_PROTOCOL_VERSION, (int)$ldapver);
1054

    
1055
	/* bind as user that has rights to read group attributes */
1056
	$ldapbindun = isset($authcfg['ldap_utf8']) ? utf8_encode($ldapbindun) : $ldapbindun;
1057
	$ldapbindpw = isset($authcfg['ldap_utf8']) ? utf8_encode($ldapbindpw) : $ldapbindpw;
1058
	if ($ldapanon == true) {
1059
		if (!($res = @ldap_bind($ldap))) {
1060
			log_error(sprintf(gettext("ERROR! ldap_get_groups() could not bind anonymously to server %s."), $ldapname));
1061
			@ldap_close($ldap);
1062
			return false;
1063
		}
1064
	} else if (!($res = @ldap_bind($ldap, $ldapbindun, $ldapbindpw))) {
1065
		log_error(sprintf(gettext("ERROR! ldap_get_groups() could not bind to server %s."), $ldapname));
1066
		@ldap_close($ldap);
1067
		return memberof;
1068
	}
1069

    
1070
	/* get groups from DN found */
1071
	/* use ldap_read instead of search so we don't have to do a bunch of extra work */
1072
	/* since we know the DN is in $_SESSION['ldapdn'] */
1073
	//$search    = ldap_read($ldap, $ldapdn, "(objectclass=*)", array($ldapgroupattribute));
1074
	if ($ldapscope == "one") {
1075
		$ldapfunc = "ldap_list";
1076
	} else {
1077
		$ldapfunc = "ldap_search";
1078
	}
1079

    
1080
	$search = @$ldapfunc($ldap, $ldapdn, $ldapfilter, array($ldapgroupattribute));
1081
	$info = @ldap_get_entries($ldap, $search);
1082

    
1083
	$countem = $info["count"];
1084

    
1085
	if (is_array($info[0][$ldapgroupattribute])) {
1086
		/* Iterate through the groups and throw them into an array */
1087
		foreach ($info[0][$ldapgroupattribute] as $member) {
1088
			if (stristr($member, "CN=") !== false) {
1089
				$membersplit = explode(",", $member);
1090
				$memberof[] = preg_replace("/CN=/i", "", $membersplit[0]);
1091
			}
1092
		}
1093
	}
1094

    
1095
	/* Time to close LDAP connection */
1096
	@ldap_unbind($ldap);
1097

    
1098
	$groups = print_r($memberof,true);
1099

    
1100
	//log_error("Returning groups ".$groups." for user $username");
1101

    
1102
	return $memberof;
1103
}
1104

    
1105
function ldap_format_host($host) {
1106
	return is_ipaddrv6($host) ? "[$host]" : $host ;
1107
}
1108

    
1109
function ldap_backed($username, $passwd, $authcfg) {
1110
	global $debug, $config;
1111

    
1112
	if (!$username) {
1113
		return;
1114
	}
1115

    
1116
	if (!function_exists("ldap_connect")) {
1117
		return;
1118
	}
1119

    
1120
	if (!isset($authcfg['ldap_nostrip_at']) && stristr($username, "@")) {
1121
		$username_split = explode("@", $username);
1122
		$username = $username_split[0];
1123
	}
1124
	if (stristr($username, "\\")) {
1125
		$username_split = explode("\\", $username);
1126
		$username = $username_split[0];
1127
	}
1128

    
1129
	if ($authcfg) {
1130
		if (strstr($authcfg['ldap_urltype'], "Standard")) {
1131
			$ldapproto = "ldap";
1132
		} else {
1133
			$ldapproto = "ldaps";
1134
		}
1135
		$ldapserver = "{$ldapproto}://" . ldap_format_host($authcfg['host']);
1136
		$ldapport = $authcfg['ldap_port'];
1137
		if (!empty($ldapport)) {
1138
			$ldapserver .= ":{$ldapport}";
1139
		}
1140
		$ldapbasedn = $authcfg['ldap_basedn'];
1141
		$ldapbindun = $authcfg['ldap_binddn'];
1142
		$ldapbindpw = $authcfg['ldap_bindpw'];
1143
		if (empty($ldapbindun) || empty($ldapbindpw)) {
1144
			$ldapanon = true;
1145
		} else {
1146
			$ldapanon = false;
1147
		}
1148
		$ldapauthcont = $authcfg['ldap_authcn'];
1149
		$ldapnameattribute = strtolower($authcfg['ldap_attr_user']);
1150
		$ldapextendedqueryenabled = $authcfg['ldap_extended_enabled'];
1151
		$ldapextendedquery = $authcfg['ldap_extended_query'];
1152
		$ldapfilter = "";
1153
		if (!$ldapextendedqueryenabled) {
1154
			$ldapfilter = "({$ldapnameattribute}={$username})";
1155
		} else {
1156
			$ldapfilter = "(&({$ldapnameattribute}={$username})({$ldapextendedquery}))";
1157
		}
1158
		$ldaptype = "";
1159
		$ldapver = $authcfg['ldap_protver'];
1160
		$ldapname = $authcfg['name'];
1161
		$ldapscope = $authcfg['ldap_scope'];
1162
	} else {
1163
		return false;
1164
	}
1165

    
1166
	/* first check if there is even an LDAP server populated */
1167
	if (!$ldapserver) {
1168
		if ($ldapfallback) {
1169
			log_error(gettext("ERROR! ldap_backed() called with no LDAP authentication server defined.  Defaulting to local user database. Visit System -> User Manager."));
1170
			return local_backed($username, $passwd);
1171
		} else {
1172
			log_error(gettext("ERROR! ldap_backed() called with no LDAP authentication server defined."));
1173
		}
1174

    
1175
		return false;
1176
	}
1177

    
1178
	/* Setup CA environment if needed. */
1179
	ldap_setup_caenv($authcfg);
1180

    
1181
	ldap_set_option($ldap, LDAP_OPT_REFERRALS, 0);
1182
	ldap_set_option($ldap, LDAP_OPT_DEREF, LDAP_DEREF_SEARCHING);
1183
	ldap_set_option($ldap, LDAP_OPT_PROTOCOL_VERSION, (int)$ldapver);
1184

    
1185
	/* Make sure we can connect to LDAP */
1186
	$error = false;
1187
	if (!($ldap = ldap_connect($ldapserver))) {
1188
		$error = true;
1189
	}
1190

    
1191
	if ($error == true) {
1192
		log_error(sprintf(gettext("ERROR!  Could not connect to server %s."), $ldapname));
1193
		return false;
1194
	}
1195

    
1196
	/* ok, its up.  now, lets bind as the bind user so we can search it */
1197
	$error = false;
1198
	$ldapbindun = isset($authcfg['ldap_utf8']) ? utf8_encode($ldapbindun) : $ldapbindun;
1199
	$ldapbindpw = isset($authcfg['ldap_utf8']) ? utf8_encode($ldapbindpw) : $ldapbindpw;
1200
	if ($ldapanon == true) {
1201
		if (!($res = @ldap_bind($ldap))) {
1202
			$error = true;
1203
		}
1204
	} else if (!($res = @ldap_bind($ldap, $ldapbindun, $ldapbindpw))) {
1205
		$error = true;
1206
	}
1207

    
1208
	if ($error == true) {
1209
		@ldap_close($ldap);
1210
		log_error(sprintf(gettext("ERROR! Could not bind to server %s."), $ldapname));
1211
		return false;
1212
	}
1213

    
1214
	/* Get LDAP Authcontainers and split em up. */
1215
	$ldac_splits = explode(";", $ldapauthcont);
1216

    
1217
	/* setup the usercount so we think we havn't found anyone yet */
1218
	$usercount  = 0;
1219

    
1220
	/*****************************************************************/
1221
	/*  We First find the user based on username and filter          */
1222
	/*  Then, once we find the first occurrence of that person       */
1223
	/*  We set session variables to point to the OU and DN of the    */
1224
	/*  Person.  To later be used by ldap_get_groups.                */
1225
	/*  that way we don't have to search twice.                      */
1226
	/*****************************************************************/
1227
	if ($debug) {
1228
		log_auth(sprintf(gettext("Now Searching for %s in directory."), $username));
1229
	}
1230
	/* Iterate through the user containers for search */
1231
	foreach ($ldac_splits as $i => $ldac_split) {
1232
		$ldac_split = isset($authcfg['ldap_utf8']) ? utf8_encode($ldac_split) : $ldac_split;
1233
		$ldapfilter = isset($authcfg['ldap_utf8']) ? utf8_encode($ldapfilter) : $ldapfilter;
1234
		$ldapsearchbasedn = isset($authcfg['ldap_utf8']) ? utf8_encode("{$ldac_split},{$ldapbasedn}") : "{$ldac_split},{$ldapbasedn}";
1235
		/* Make sure we just use the first user we find */
1236
		if ($debug) {
1237
			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)));
1238
		}
1239
		if ($ldapscope == "one") {
1240
			$ldapfunc = "ldap_list";
1241
		} else {
1242
			$ldapfunc = "ldap_search";
1243
		}
1244
		/* Support legacy auth container specification. */
1245
		if (stristr($ldac_split, "DC=") || empty($ldapbasedn)) {
1246
			$search	 = @$ldapfunc($ldap,$ldac_split,$ldapfilter);
1247
		} else {
1248
			$search  = @$ldapfunc($ldap,$ldapsearchbasedn,$ldapfilter);
1249
		}
1250
		if (!$search) {
1251
			log_error(sprintf(gettext("Search resulted in error: %s"), ldap_error($ldap)));
1252
			continue;
1253
		}
1254
		$info = ldap_get_entries($ldap,$search);
1255
		$matches = $info['count'];
1256
		if ($matches == 1) {
1257
			$userdn = $_SESSION['ldapdn'] = $info[0]['dn'];
1258
			$_SESSION['ldapou'] = $ldac_split[$i];
1259
			$_SESSION['ldapon'] = "true";
1260
			$usercount = 1;
1261
			break;
1262
		}
1263
	}
1264

    
1265
	if ($usercount != 1) {
1266
		@ldap_unbind($ldap);
1267
		log_error(gettext("ERROR! Either LDAP search failed, or multiple users were found."));
1268
		return false;
1269
	}
1270

    
1271
	/* Now lets bind as the user we found */
1272
	$passwd = isset($authcfg['ldap_utf8']) ? utf8_encode($passwd) : $passwd;
1273
	if (!($res = @ldap_bind($ldap, $userdn, $passwd))) {
1274
		log_error(sprintf(gettext('ERROR! Could not login to server %1$s as user %2$s: %3$s'), $ldapname, $username, ldap_error($ldap)));
1275
		@ldap_unbind($ldap);
1276
		return false;
1277
	}
1278

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

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

    
1287
	return true;
1288
}
1289

    
1290
function radius_backed($username, $passwd, $authcfg, &$attributes = array()) {
1291
	global $debug, $config;
1292
	$ret = false;
1293

    
1294
	require_once("radius.inc");
1295

    
1296
	$rauth = new Auth_RADIUS_PAP($username, $passwd);
1297
	if ($authcfg) {
1298
		$radiusservers = array();
1299
		$radiusservers[0]['ipaddr'] = $authcfg['host'];
1300
		$radiusservers[0]['port'] = $authcfg['radius_auth_port'];
1301
		$radiusservers[0]['sharedsecret'] = $authcfg['radius_secret'];
1302
		$radiusservers[0]['timeout'] = $authcfg['radius_timeout'];
1303
	} else {
1304
		return false;
1305
	}
1306

    
1307
	/* Add new servers to our instance */
1308
	foreach ($radiusservers as $radsrv) {
1309
		$timeout = (is_numeric($radsrv['timeout'])) ? $radsrv['timeout'] : 5;
1310
		$rauth->addServer($radsrv['ipaddr'], $radsrv['port'], $radsrv['sharedsecret'], $timeout);
1311
	}
1312

    
1313
	if (PEAR::isError($rauth->start())) {
1314
		$retvalue['auth_val'] = 1;
1315
		$retvalue['error'] = $rauth->getError();
1316
		if ($debug) {
1317
			printf(gettext("Radius start: %s<br />\n"), $retvalue['error']);
1318
		}
1319
	}
1320

    
1321
	// XXX - billm - somewhere in here we need to handle securid challenge/response
1322

    
1323
	/* Send request */
1324
	$result = $rauth->send();
1325
	if (PEAR::isError($result)) {
1326
		$retvalue['auth_val'] = 1;
1327
		$retvalue['error'] = $result->getMessage();
1328
		if ($debug) {
1329
			printf(gettext("Radius send failed: %s<br />\n"), $retvalue['error']);
1330
		}
1331
	} else if ($result === true) {
1332
		if ($rauth->getAttributes()) {
1333
			$attributes = $rauth->listAttributes();
1334
		}
1335
		$retvalue['auth_val'] = 2;
1336
		if ($debug) {
1337
			printf(gettext("Radius Auth succeeded")."<br />\n");
1338
		}
1339
		$ret = true;
1340
	} else {
1341
		$retvalue['auth_val'] = 3;
1342
		if ($debug) {
1343
			printf(gettext("Radius Auth rejected")."<br />\n");
1344
		}
1345
	}
1346

    
1347
	// close OO RADIUS_AUTHENTICATION
1348
	$rauth->close();
1349

    
1350
	return $ret;
1351
}
1352

    
1353
function get_user_expiration_date($username) {
1354
	$user = getUserEntry($username);
1355
	if ($user['expires']) {
1356
		return $user['expires'];
1357
	}
1358
}
1359

    
1360
function is_account_expired($username) {
1361
	$expirydate = get_user_expiration_date($username);
1362
	if ($expirydate) {
1363
		if (strtotime("-1 day") > strtotime(date("m/d/Y",strtotime($expirydate)))) {
1364
			return true;
1365
		}
1366
	}
1367

    
1368
	return false;
1369
}
1370

    
1371
function is_account_disabled($username) {
1372
	$user = getUserEntry($username);
1373
	if (isset($user['disabled'])) {
1374
		return true;
1375
	}
1376

    
1377
	return false;
1378
}
1379

    
1380
function auth_get_authserver($name) {
1381
	global $config;
1382

    
1383
	if (is_array($config['system']['authserver'])) {
1384
		foreach ($config['system']['authserver'] as $authcfg) {
1385
			if ($authcfg['name'] == $name) {
1386
				return $authcfg;
1387
			}
1388
		}
1389
	}
1390
	if ($name == "Local Database") {
1391
		return array("name" => gettext("Local Database"), "type" => "Local Auth", "host" => $config['system']['hostname']);
1392
	}
1393
}
1394

    
1395
function auth_get_authserver_list() {
1396
	global $config;
1397

    
1398
	$list = array();
1399

    
1400
	if (is_array($config['system']['authserver'])) {
1401
		foreach ($config['system']['authserver'] as $authcfg) {
1402
			/* Add support for disabled entries? */
1403
			$list[$authcfg['name']] = $authcfg;
1404
		}
1405
	}
1406

    
1407
	$list["Local Database"] = array( "name" => gettext("Local Database"), "type" => "Local Auth", "host" => $config['system']['hostname']);
1408
	return $list;
1409
}
1410

    
1411
function getUserGroups($username, $authcfg) {
1412
	global $config;
1413

    
1414
	$allowed_groups = array();
1415

    
1416
	switch ($authcfg['type']) {
1417
		case 'ldap':
1418
			$allowed_groups = @ldap_get_groups($username, $authcfg);
1419
			break;
1420
		case 'radius':
1421
			break;
1422
		default:
1423
			$user = getUserEntry($username);
1424
			$allowed_groups = @local_user_get_groups($user, true);
1425
			break;
1426
	}
1427

    
1428
	$member_groups = array();
1429
	if (is_array($config['system']['group'])) {
1430
		foreach ($config['system']['group'] as $group) {
1431
			if (in_array($group['name'], $allowed_groups)) {
1432
				$member_groups[] = $group['name'];
1433
			}
1434
		}
1435
	}
1436

    
1437
	return $member_groups;
1438
}
1439

    
1440
function authenticate_user($username, $password, $authcfg = NULL, &$attributes = array()) {
1441

    
1442
	if (!$authcfg) {
1443
		return local_backed($username, $password);
1444
	}
1445

    
1446
	$authenticated = false;
1447
	switch ($authcfg['type']) {
1448
		case 'ldap':
1449
			if (ldap_backed($username, $password, $authcfg)) {
1450
				$authenticated = true;
1451
			}
1452
			break;
1453
		case 'radius':
1454
			if (radius_backed($username, $password, $authcfg, $attributes)) {
1455
				$authenticated = true;
1456
			}
1457
			break;
1458
		default:
1459
			/* lookup user object by name */
1460
			if (local_backed($username, $password)) {
1461
				$authenticated = true;
1462
			}
1463
			break;
1464
		}
1465

    
1466
	return $authenticated;
1467
}
1468

    
1469
function session_auth() {
1470
	global $config, $_SESSION, $page;
1471

    
1472
	// Handle HTTPS httponly and secure flags
1473
	$currentCookieParams = session_get_cookie_params();
1474
	session_set_cookie_params(
1475
		$currentCookieParams["lifetime"],
1476
		$currentCookieParams["path"],
1477
		NULL,
1478
		($config['system']['webgui']['protocol'] == "https"),
1479
		true
1480
	);
1481

    
1482
	if (!session_id()) {
1483
		session_start();
1484
	}
1485

    
1486
	// Detect protocol change
1487
	if (!isset($_POST['login']) && !empty($_SESSION['Logged_In']) && $_SESSION['protocol'] != $config['system']['webgui']['protocol']) {
1488
		return false;
1489
	}
1490

    
1491
	/* Validate incoming login request */
1492
	if (isset($_POST['login']) && !empty($_POST['usernamefld']) && !empty($_POST['passwordfld'])) {
1493
		$authcfg = auth_get_authserver($config['system']['webgui']['authmode']);
1494
		if (authenticate_user($_POST['usernamefld'], $_POST['passwordfld'], $authcfg) ||
1495
		    authenticate_user($_POST['usernamefld'], $_POST['passwordfld'])) {
1496
			// Generate a new id to avoid session fixation
1497
			session_regenerate_id();
1498
			$_SESSION['Logged_In'] = "True";
1499
			$_SESSION['Username'] = $_POST['usernamefld'];
1500
			$_SESSION['last_access'] = time();
1501
			$_SESSION['protocol'] = $config['system']['webgui']['protocol'];
1502
			if (!isset($config['system']['webgui']['quietlogin'])) {
1503
				log_auth(sprintf(gettext("Successful login for user '%1\$s' from: %2\$s"), $_POST['usernamefld'], $_SERVER['REMOTE_ADDR']));
1504
			}
1505
			if (isset($_POST['postafterlogin'])) {
1506
				return true;
1507
			} else {
1508
				if (empty($page)) {
1509
					$page = "/";
1510
				}
1511
				header("Location: {$page}");
1512
			}
1513
			exit;
1514
		} else {
1515
			/* give the user an error message */
1516
			$_SESSION['Login_Error'] = "Username or Password incorrect";
1517
			log_auth("webConfigurator authentication error for '{$_POST['usernamefld']}' from {$_SERVER['REMOTE_ADDR']}");
1518
			if (isAjax()) {
1519
				echo "showajaxmessage('{$_SESSION['Login_Error']}');";
1520
				return;
1521
			}
1522
		}
1523
	}
1524

    
1525
	/* Show login page if they aren't logged in */
1526
	if (empty($_SESSION['Logged_In'])) {
1527
		return false;
1528
	}
1529

    
1530
	/* If session timeout isn't set, we don't mark sessions stale */
1531
	if (!isset($config['system']['webgui']['session_timeout'])) {
1532
		/* Default to 4 hour timeout if one is not set */
1533
		if ($_SESSION['last_access'] < (time() - 14400)) {
1534
			$_GET['logout'] = true;
1535
			$_SESSION['Logout'] = true;
1536
		} else {
1537
			$_SESSION['last_access'] = time();
1538
		}
1539
	} else if (intval($config['system']['webgui']['session_timeout']) == 0) {
1540
		/* only update if it wasn't ajax */
1541
		if (!isAjax()) {
1542
			$_SESSION['last_access'] = time();
1543
		}
1544
	} else {
1545
		/* Check for stale session */
1546
		if ($_SESSION['last_access'] < (time() - ($config['system']['webgui']['session_timeout'] * 60))) {
1547
			$_GET['logout'] = true;
1548
			$_SESSION['Logout'] = true;
1549
		} else {
1550
			/* only update if it wasn't ajax */
1551
			if (!isAjax()) {
1552
				$_SESSION['last_access'] = time();
1553
			}
1554
		}
1555
	}
1556

    
1557
	/* user hit the logout button */
1558
	if (isset($_GET['logout'])) {
1559

    
1560
		if ($_SESSION['Logout']) {
1561
			log_error(sprintf(gettext("Session timed out for user '%1\$s' from: %2\$s"), $_SESSION['Username'], $_SERVER['REMOTE_ADDR']));
1562
		} else {
1563
			log_error(sprintf(gettext("User logged out for user '%1\$s' from: %2\$s"), $_SESSION['Username'], $_SERVER['REMOTE_ADDR']));
1564
		}
1565

    
1566
		/* wipe out $_SESSION */
1567
		$_SESSION = array();
1568

    
1569
		if (isset($_COOKIE[session_name()])) {
1570
			setcookie(session_name(), '', time()-42000, '/');
1571
		}
1572

    
1573
		/* and destroy it */
1574
		session_destroy();
1575

    
1576
		$scriptName = explode("/", $_SERVER["SCRIPT_FILENAME"]);
1577
		$scriptElms = count($scriptName);
1578
		$scriptName = $scriptName[$scriptElms-1];
1579

    
1580
		if (isAjax()) {
1581
			return false;
1582
		}
1583

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

    
1587
		return false;
1588
	}
1589

    
1590
	/*
1591
	 * this is for debugging purpose if you do not want to use Ajax
1592
	 * to submit a HTML form. It basically disables the observation
1593
	 * of the submit event and hence does not trigger Ajax.
1594
	 */
1595
	if ($_GET['disable_ajax']) {
1596
		$_SESSION['NO_AJAX'] = "True";
1597
	}
1598

    
1599
	/*
1600
	 * Same to re-enable Ajax.
1601
	 */
1602
	if ($_GET['enable_ajax']) {
1603
		unset($_SESSION['NO_AJAX']);
1604
	}
1605

    
1606
	return true;
1607
}
1608

    
1609
?>
(4-4/67)