Project

General

Profile

Download (37.5 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
		DISABLE_PHP_LINT_CHECKING
41
		pfSense_BUILDER_BINARIES:	/usr/sbin/pw	/bin/cp
42
		pfSense_MODULE:	auth
43
*/
44

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

    
52
/* If this function doesn't exist, we're being called from Captive Portal or 
53
   another internal subsystem which does not include authgui.inc */
54
if (function_exists("display_error_form") && !isset($config['system']['webgui']['nodnsrebindcheck'])) {
55
	/* DNS ReBinding attack prevention.  http://redmine.pfsense.org/issues/708 */
56
	$found_host = false;
57
	if(strstr($_SERVER['HTTP_HOST'], ":")) {
58
		$http_host_port = explode(":", $_SERVER['HTTP_HOST']);
59
		$http_host = $http_host_port[0];
60
	} else {
61
		$http_host = $_SERVER['HTTP_HOST'];
62
	}
63
	if(is_ipaddr($http_host) or $_SERVER['SERVER_ADDR'] == "127.0.0.1" or
64
			strcasecmp($http_host, "localhost") == 0)
65
		$found_host = true;
66
	if(strcasecmp($http_host, $config['system']['hostname'] . "." . $config['system']['domain']) == 0 or
67
			strcasecmp($http_host, $config['system']['hostname']) == 0)
68
		$found_host = true;
69

    
70
	if(is_array($config['dyndnses']['dyndns']) && !$found_host)
71
		foreach($config['dyndnses']['dyndns'] as $dyndns)
72
			if(strcasecmp($dyndns['host'], $http_host) == 0) {
73
				$found_host = true;
74
				break;
75
			}
76

    
77
	if(!empty($config['system']['webgui']['althostnames']) && !$found_host) {
78
		$althosts = explode(" ", $config['system']['webgui']['althostnames']);
79
		foreach ($althosts as $ah)
80
			if(strcasecmp($ah, $http_host) == 0 or strcasecmp($ah, $_SERVER['SERVER_ADDR']) == 0) {
81
				$found_host = true;
82
				break;
83
			}
84
	}
85

    
86
	if($found_host == false) {
87
		display_error_form("501", "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.");
88
		exit;
89
	}
90
}
91

    
92
// If the HTTP_REFERER is something other than ourselves then disallow.
93
if(function_exists("display_error_form") && !isset($config['system']['webgui']['nohttpreferercheck'])) {
94
	if($_SERVER['HTTP_REFERER']) {
95
		if(file_exists("{$g['tmp_path']}/setupwizard_lastreferrer")) {
96
			if($_SERVER['HTTP_REFERER'] == file_get_contents("{$g['tmp_path']}/setupwizard_lastreferrer")) {
97
				unlink("{$g['tmp_path']}/setupwizard_lastreferrer");
98
				header("Refresh: 1; url=index.php");
99
				echo "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n        \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">";
100
				echo "<html><head><title>" . gettext("Redirecting...") . "</title></head><body>" . gettext("Redirecting to the dashboard...") . "</body></html>";
101
				exit;
102
			}
103
		}
104
		$found_host = false;
105
		$referrer_host = parse_url($_SERVER['HTTP_REFERER'], PHP_URL_HOST);
106
		if($referrer_host) {
107
			if(strcasecmp($referrer_host, $config['system']['hostname'] . "." . $config['system']['domain']) == 0
108
					|| strcasecmp($referrer_host, $config['system']['hostname']) == 0)
109
				$found_host = true;
110
			if(!empty($config['system']['webgui']['althostnames']) && !$found_host) {
111
				$althosts = explode(" ", $config['system']['webgui']['althostnames']);
112
				foreach ($althosts as $ah) {
113
					if(strcasecmp($referrer_host, $ah) == 0) {
114
						$found_host = true;
115
						break;
116
					}
117
				}
118
			}
119
			if(!$found_host) {
120
				$interface_list_ips = get_configured_ip_addresses();
121
				foreach($interface_list_ips as $ilips) {
122
					if(strcasecmp($referrer_host, $ilips) == 0) {
123
						$found_host = true;
124
						break;
125
					}
126
				}
127
			}
128
		}
129
		if($found_host == false) {
130
			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.");
131
			exit;
132
		}
133
	}
134
}
135

    
136
$groupindex = index_groups();
137
$userindex = index_users();
138

    
139
function index_groups() {
140
	global $g, $debug, $config, $groupindex;
141

    
142
	$groupindex = array();
143

    
144
	if (is_array($config['system']['group'])) {
145
		$i = 0;
146
		foreach($config['system']['group'] as $groupent) {
147
			$groupindex[$groupent['name']] = $i;
148
			$i++;
149
		}
150
	}
151

    
152
	return ($groupindex);
153
}
154

    
155
function index_users() {
156
	global $g, $debug, $config;
157

    
158
	if (is_array($config['system']['user'])) {
159
		$i = 0;
160
		foreach($config['system']['user'] as $userent) {
161
			$userindex[$userent['name']] = $i;
162
			$i++;
163
		}
164
	}
165

    
166
	return ($userindex);
167
}
168

    
169
function & getUserEntry($name) {
170
	global $debug, $config, $userindex;
171
	if (isset($userindex[$name]))
172
		return $config['system']['user'][$userindex[$name]];
173
}
174

    
175
function & getUserEntryByUID($uid) {
176
	global $debug, $config;
177
	foreach ($config['system']['user'] as & $user)
178
		if ($user['uid'] == $uid)
179
			return $user;
180

    
181
	return false;
182
}
183

    
184
function & getGroupEntry($name) {
185
	global $debug, $config, $groupindex;
186
	if (isset($groupindex[$name]))
187
		return $config['system']['group'][$groupindex[$name]];
188
}
189

    
190
function & getGroupEntryByGID($gid) {
191
	global $debug, $config;
192
	foreach ($config['system']['group'] as & $group)
193
		if ($group['gid'] == $gid)
194
			return $group;
195

    
196
	return false;
197
}
198

    
199
function get_user_privileges(& $user) {
200

    
201
        $privs = $user['priv'];
202
        if (!is_array($privs))
203
                $privs = array();
204

    
205
        $names = local_user_get_groups($user, true);
206

    
207
        foreach ($names as $name) {
208
                $group = getGroupEntry($name);
209
                if (is_array($group['priv']))
210
                        $privs = array_merge( $privs, $group['priv']);
211
        }
212

    
213
        return $privs;
214
}
215

    
216
function userHasPrivilege($userent, $privid = false) {
217

    
218
        if (!$privid || !is_array($userent))
219
                return false;
220

    
221
        $privs = get_user_privileges($userent);
222

    
223
        if (!is_array($privs))
224
                return false;
225

    
226
        if (!in_array($privid, $privs))
227
                return false;
228

    
229
        return true;
230
}
231

    
232
function local_backed($username, $passwd) {
233

    
234
	$user = getUserEntry($username);
235
	if (!$user)
236
		return false;
237

    
238
	if (is_account_disabled($username) || is_account_expired($username))
239
		return false;
240

    
241
	if ($user['password'])
242
	{
243
		$passwd = crypt($passwd, $user['password']);
244
		if ($passwd == $user['password'])
245
			return true;
246
	}
247

    
248
	if ($user['md5-hash'])
249
	{
250
		$passwd = md5($passwd);
251
		if ($passwd == $user['md5-hash'])
252
			return true;
253
	}
254

    
255
	return false;
256
}
257

    
258
function local_sync_accounts() {
259
	global $debug, $config;
260
	conf_mount_rw();
261

    
262
	/* remove local users to avoid uid conflicts */
263
	$fd = popen("/usr/sbin/pw usershow -a", "r");
264
	if ($fd) {
265
		while (!feof($fd)) {
266
			$line = explode(":",fgets($fd));
267
			if (!strncmp($line[0], "_", 1))
268
				continue;
269
			if ($line[2] < 2000)
270
				continue;
271
			if ($line[2] > 65000)
272
				continue;
273
			$cmd = "/usr/sbin/pw userdel {$line[2]}";
274
			if($debug)
275
				log_error("Running: {$cmd}");
276
			mwexec($cmd);
277
		}
278
		pclose($fd);
279
	}
280

    
281
	/* remove local groups to avoid gid conflicts */
282
	$gids = array();
283
	$fd = popen("/usr/sbin/pw groupshow -a", "r");
284
	if ($fd) {
285
		while (!feof($fd)) {
286
			$line = explode(":",fgets($fd));
287
			if (!strncmp($line[0], "_", 1))
288
				continue;
289
			if ($line[2] < 2000)
290
				continue;
291
			if ($line[2] > 65000)
292
				continue;
293
			$cmd = "/usr/sbin/pw groupdel {$line[2]}";
294
			if($debug)
295
				log_error("Running: {$cmd}");
296
			mwexec($cmd);
297
		}
298
		pclose($fd);
299
	}
300

    
301
	/* make sure the all group exists */
302
	$allgrp = getGroupEntryByGID(1998);
303
	local_group_set($allgrp, true);
304

    
305
	/* sync all local users */
306
	if (is_array($config['system']['user']))
307
		foreach ($config['system']['user'] as $user)
308
			local_user_set($user);
309

    
310
	/* sync all local groups */
311
	if (is_array($config['system']['group']))
312
		foreach ($config['system']['group'] as $group)
313
			local_group_set($group);
314

    
315
	conf_mount_ro();
316

    
317
}
318

    
319
function local_user_set(& $user) {
320
	global $g, $debug;
321

    
322
	conf_mount_rw();
323

    
324
	$home_base = "/home/";	
325
	$user_uid = $user['uid'];
326
	$user_name = $user['name'];
327
	$user_home = "{$home_base}{$user_name}";
328
	$user_shell = "/etc/rc.initial";
329
	$user_group = "nobody";
330

    
331
	// Ensure $home_base exists and is writable
332
	if (!is_dir($home_base)) 
333
		mkdir($home_base, 0755);
334

    
335
	$lock_account = false;
336
	/* configure shell type */
337
	/* Cases here should be ordered by most privileged to least privileged. */
338
	if (userHasPrivilege($user, "user-shell-access") || userHasPrivilege($user, "page-all")) {
339
		$user_shell = "/bin/tcsh";
340
	} elseif (userHasPrivilege($user, "user-copy-files")) {
341
		$user_shell = "/usr/local/bin/scponly";
342
	} elseif (userHasPrivilege($user, "user-ssh-tunnel")) {
343
		$user_shell = "/usr/local/sbin/ssh_tunnel_shell";
344
	} else {
345
		$user_shell = "/sbin/nologin";
346
		$lock_account = true;
347
	}
348

    
349
	/* Lock out disabled or expired users, unless it's root/admin. */
350
	if ((is_account_disabled($user_name) || is_account_expired($user_name)) && ($user_uid != 0)) {
351
		$user_shell = "/sbin/nologin";
352
		$lock_account = true;
353
	}
354

    
355
	/* root user special handling */
356
	if ($user_uid == 0) {
357
		$cmd = "/usr/sbin/pw usermod -q -n root -s /bin/sh -H 0";
358
		if($debug)
359
			log_error("Running: {$cmd}");
360
		$fd = popen($cmd, "w");
361
		fwrite($fd, $user['password']);
362
		pclose($fd);
363
		$user_group = "wheel";
364
		$user_home = "/root";
365
		$user_shell = "/etc/rc.initial";
366
	}
367

    
368
	/* read from pw db */
369
	$fd = popen("/usr/sbin/pw usershow {$user_name} 2>&1", "r");
370
	$pwread = fgets($fd);
371
	pclose($fd);
372

    
373
	/* determine add or mod */
374
	if (!strncmp($pwread, "pw:", 3)) {
375
		$user_op = "useradd -m -k /etc/skel -o";
376
	} else {
377
		$user_op = "usermod";
378
	}
379

    
380
	/* add or mod pw db */
381
	$cmd = "/usr/sbin/pw {$user_op} -q -u {$user_uid} -n {$user_name}".
382
			" -g {$user_group} -s {$user_shell} -d {$user_home}".
383
			" -c ".escapeshellarg($user['descr'])." -H 0 2>&1";
384

    
385
	if($debug)
386
		log_error("Running: {$cmd}");
387
	$fd = popen($cmd, "w");
388
	fwrite($fd, $user['password']);
389
	pclose($fd);
390

    
391
	/* create user directory if required */
392
	if (!is_dir($user_home)) {
393
		mkdir($user_home, 0700);
394
		mwexec("cp /root/.* {$home_base}/");
395
	}
396
	chown($user_home, $user_name);
397
	chgrp($user_home, $user_group);
398

    
399
	/* write out ssh authorized key file */
400
	if($user['authorizedkeys']) {
401
		if (!is_dir("{$user_home}/.ssh")) {
402
			mkdir("{$user_home}/.ssh", 0700);
403
			chown("{$user_home}/.ssh", $user_name);
404
		}
405
		$keys = base64_decode($user['authorizedkeys']);
406
		file_put_contents("{$user_home}/.ssh/authorized_keys", $keys);
407
		chown("{$user_home}/.ssh/authorized_keys", $user_name);
408
	}
409

    
410
	$un = $lock_account ? "" : "un";
411
	exec("/usr/sbin/pw {$un}lock -q {$user_name}");
412
	
413
	conf_mount_ro();
414
}
415

    
416
function local_user_del($user) {
417
	global $debug;
418

    
419
	/* remove all memberships */
420
	local_user_set_groups($user);
421

    
422
	/* Don't remove /root */
423
	if ($user['uid'] != 0)
424
		$rmhome = "-r";
425

    
426
	/* delete from pw db */
427
	$cmd = "/usr/sbin/pw userdel {$user['name']} {$rmhome}";
428

    
429
	if($debug)
430
		log_error("Running: {$cmd}");
431
	mwexec($cmd);
432

    
433
	/* Delete user from groups needs a call to write_config() */
434
	local_group_del_user($user);
435
}
436

    
437
function local_user_set_password(& $user, $password) {
438

    
439
	$user['password'] = crypt($password);
440
	$user['md5-hash'] = md5($password);
441

    
442
	// Converts ascii to unicode.
443
	$astr = (string) $password;
444
	$ustr = '';
445
	for ($i = 0; $i < strlen($astr); $i++) {
446
		$a = ord($astr{$i}) << 8;
447
		$ustr.= sprintf("%X", $a);
448
	}
449

    
450
	// Generate the NT-HASH from the unicode string
451
	$user['nt-hash'] = bin2hex(mhash(MHASH_MD4, $ustr));
452
}
453

    
454
function local_user_get_groups($user, $all = false) {
455
	global $debug, $config;
456

    
457
	$groups = array();
458
	if (!is_array($config['system']['group']))
459
		return $groups;
460

    
461
	foreach ($config['system']['group'] as $group)
462
		if ( $all || ( !$all && ($group['name'] != "all")))
463
			if (is_array($group['member']))
464
				if (in_array($user['uid'], $group['member']))
465
					$groups[] = $group['name'];
466

    
467
	if ( $all )
468
		$groups[] = "all";
469

    
470
	sort($groups);
471

    
472
	return $groups;
473
	
474
}
475

    
476
function local_user_set_groups($user, $new_groups = NULL ) {
477
	global $debug, $config, $groupindex;
478

    
479
	if (!is_array($config['system']['group']))
480
		return;
481

    
482
	$cur_groups = local_user_get_groups($user, true);
483
	$mod_groups = array();
484

    
485
	if (!is_array($new_groups))
486
		$new_groups = array();
487

    
488
	if (!is_array($cur_groups))
489
		$cur_groups = array();
490

    
491
	/* determine which memberships to add */
492
	foreach ($new_groups as $groupname) {
493
		if (in_array($groupname,$cur_groups))
494
			continue;
495
		$group = & $config['system']['group'][$groupindex[$groupname]];
496
		$group['member'][] = $user['uid'];
497
		$mod_groups[] = $group;
498
	}
499
	unset($group);
500

    
501
	/* determine which memberships to remove */
502
	foreach ($cur_groups as $groupname) {
503
		if (in_array($groupname,$new_groups))
504
			continue;
505
		if (!isset($config['system']['group'][$groupindex[$groupname]]))
506
			continue;
507
		$group = & $config['system']['group'][$groupindex[$groupname]];
508
		if (is_array($group['member'])) {
509
			$index = array_search($user['uid'], $group['member']);
510
			array_splice($group['member'], $index, 1);
511
			$mod_groups[] = $group;
512
		}
513
	}
514
	unset($group);
515

    
516
	/* sync all modified groups */
517
	foreach ($mod_groups as $group)
518
		local_group_set($group);
519
}
520

    
521
function local_group_del_user($user) {
522
	global $config;
523

    
524
	if (!is_array($config['system']['group']))
525
                return;
526

    
527
        foreach ($config['system']['group'] as $group) {
528
		if (is_array($group['member'])) {
529
			foreach ($group['member'] as $idx => $uid) {
530
				if ($user['uid'] == $uid)
531
					unset($config['system']['group']['member'][$idx]);
532
			}
533
		}
534
	}
535
}
536

    
537
function local_group_set($group, $reset = false) {
538
	global $debug;
539

    
540
	$group_name = $group['name'];
541
	$group_gid = $group['gid'];
542
	$group_members = "''";
543
	if (!$reset && !empty($group['member']) && count($group['member']) > 0)
544
		$group_members = implode(",",$group['member']);
545

    
546
	/* read from group db */
547
	$fd = popen("/usr/sbin/pw groupshow {$group_name} 2>&1", "r");
548
	$pwread = fgets($fd);
549
	pclose($fd);
550

    
551
	/* determine add or mod */
552
	if (!strncmp($pwread, "pw:", 3))
553
		$group_op = "groupadd";
554
	else
555
		$group_op = "groupmod";
556

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

    
560
	if($debug)
561
		log_error("Running: {$cmd}");
562
	mwexec($cmd);
563

    
564
}
565

    
566
function local_group_del($group) {
567
	global $debug;
568

    
569
	/* delete from group db */
570
	$cmd = "/usr/sbin/pw groupdel {$group['name']}";
571

    
572
	if($debug)
573
		log_error("Running: {$cmd}");
574
	mwexec($cmd);
575
}
576

    
577
function ldap_test_connection($authcfg) {
578
	global $debug, $config, $g;
579

    
580
	if ($authcfg) {
581
                if (strstr($authcfg['ldap_urltype'], "Standard"))
582
                        $ldapproto = "ldap";
583
                else
584
                        $ldapproto = "ldaps";
585
                $ldapserver         = "{$ldapproto}://{$authcfg['host']}";
586
                $ldapport           = $authcfg['ldap_port'];
587
                $ldapbasedn         = $authcfg['ldap_basedn'];
588
                $ldapbindun         = $authcfg['ldap_binddn'];
589
                $ldapbindpw         = $authcfg['ldap_bindpw'];
590
        } else
591
		return false;
592

    
593
        /* first check if there is even an LDAP server populated */
594
        if(!$ldapserver)
595
                return false;
596

    
597
        /* connect and see if server is up */
598
        putenv('LDAPTLS_REQCERT=never');
599
        $error = false;
600
        if (empty($ldapport)) {
601
                if (!($ldap = ldap_connect($ldapserver)))
602
                        $error = true;
603
        } else if (!($ldap = ldap_connect($ldapserver, $ldapport)))
604
                $error = true;
605

    
606
        if ($error == true) {
607
                log_error("ERROR!  Could not connect to server {$ldapname}.");
608
                return false;
609
        }
610

    
611
	return true;
612
}
613

    
614
function ldap_test_bind($authcfg) {
615
	global $debug, $config, $g;
616

    
617
	if ($authcfg) {
618
                if (strstr($authcfg['ldap_urltype'], "Standard"))
619
                        $ldapproto = "ldap";
620
                else
621
                        $ldapproto = "ldaps";
622
                $ldapserver         = "{$ldapproto}://{$authcfg['host']}";
623
                $ldapport           = $authcfg['ldap_port'];
624
                $ldapbasedn         = $authcfg['ldap_basedn'];
625
                $ldapbindun         = $authcfg['ldap_binddn'];
626
                $ldapbindpw         = $authcfg['ldap_bindpw'];
627
                $ldapver            = $authcfg['ldap_protver'];
628
		if (empty($ldapbndun) || empty($ldapbindpw))
629
                        $ldapanon = true;
630
                else
631
                        $ldapanon = false;
632
	} else
633
		return false;
634

    
635
	/* first check if there is even an LDAP server populated */
636
        if(!$ldapserver)
637
                return false;
638

    
639
        /* connect and see if server is up */
640
        putenv('LDAPTLS_REQCERT=never');
641
        $error = false;
642
        if (empty($ldapport)) {
643
                if (!($ldap = ldap_connect($ldapserver)))
644
                        $error = true;
645
        } else if (!($ldap = ldap_connect($ldapserver, $ldapport)))
646
                $error = true;
647

    
648
        if ($error == true) {
649
                log_error("ERROR!  Could not connect to server {$ldapname}.");
650
                return false;
651
        }
652

    
653
	ldap_set_option($ldap, LDAP_OPT_REFERRALS, 0);
654
	ldap_set_option($ldap, LDAP_OPT_PROTOCOL_VERSION, (int)$ldapver);
655
 
656
	if ($ldapanon == true) {
657
		if (!($res = @ldap_bind($ldap))) {
658
			@ldap_close($ldap);
659
			return false;
660
		}
661
	} else if (!($res = @ldap_bind($ldap, $ldapbindun, $ldapbindpw))) {
662
		@ldap_close($ldap);
663
		return false;
664
	}
665

    
666
	@ldap_unbind($ldap);
667

    
668
	return true;
669
}
670

    
671
function ldap_get_user_ous($show_complete_ou=true, $authcfg) {
672
	global $debug, $config, $g;
673

    
674
	if(!function_exists("ldap_connect"))
675
		return;
676

    
677
	$ous = array();
678

    
679
	if ($authcfg) {
680
                if (strstr($authcfg['ldap_urltype'], "Standard"))
681
                        $ldapproto = "ldap";
682
                else
683
                        $ldapproto = "ldaps";
684
                $ldapserver         = "{$ldapproto}://{$authcfg['host']}";
685
                $ldapport           = $authcfg['ldap_port'];
686
                $ldapbasedn         = $authcfg['ldap_basedn'];
687
                $ldapbindun         = $authcfg['ldap_binddn'];
688
                $ldapbindpw         = $authcfg['ldap_bindpw'];
689
                $ldapver            = $authcfg['ldap_protver'];
690
		if (empty($ldapbindun) || empty($ldapbindpw))
691
                        $ldapanon = true;
692
                else
693
                        $ldapanon = false;
694
                $ldapname           = $authcfg['name'];
695
                $ldapfallback       = false;
696
		$ldapscope          = $authcfg['ldap_scope'];
697
        } else
698
		return false;
699

    
700
        /* first check if there is even an LDAP server populated */
701
        if(!$ldapserver) {
702
                log_error("ERROR!  ldap_get_user_ous() backed selected with no LDAP authentication server defined.");
703
                return $ous;
704
        }
705

    
706
	/* connect and see if server is up */
707
        putenv('LDAPTLS_REQCERT=never');
708
        $error = false;
709
        if (empty($ldapport)) {
710
                if (!($ldap = ldap_connect($ldapserver)))
711
                        $error = true;
712
        } else if (!($ldap = ldap_connect($ldapserver, $ldapport)))
713
                $error = true;
714

    
715
        if ($error == true) {
716
		log_error("ERROR!  Could not connect to server {$ldapname}.");
717
                return $ous;
718
        }
719

    
720
	$ldapfilter = "(|(ou=*)(cn=Users))";
721

    
722
	ldap_set_option($ldap, LDAP_OPT_REFERRALS, 0);
723
	ldap_set_option($ldap, LDAP_OPT_PROTOCOL_VERSION, (int)$ldapver);
724

    
725
	if ($ldapanon == true) {
726
                if (!($res = @ldap_bind($ldap))) {
727
			log_error("ERROR! ldap_get_user_ous() could not bind anonymously to server {$ldapname}.");
728
			@ldap_close($ldap);
729
                        return $ous;
730
		}
731
	} else if (!($res = @ldap_bind($ldap, $ldapbindun, $ldapbindpw))) {
732
		log_error("ERROR! ldap_get_user_ous() could not bind to server {$ldapname}.");
733
		@ldap_close($ldap);
734
		return $ous;
735
	}
736

    
737
	if ($ldapscope == "one")
738
		$ldapfunc = "ldap_list";
739
	else
740
		$ldapfunc = "ldap_search";
741

    
742
	$search = @$ldapfunc($ldap, $ldapbasedn, $ldapfilter);
743
	$info = @ldap_get_entries($ldap, $search);
744

    
745
	if (is_array($info)) {
746
		foreach ($info as $inf) {
747
			if (!$show_complete_ou) {
748
				$inf_split = split(",", $inf['dn']);
749
				$ou = $inf_split[0];
750
				$ou = str_replace("OU=","", $ou);
751
				$ou = str_replace("CN=","", $ou);
752
			} else
753
				if($inf['dn'])
754
					$ou = $inf['dn'];
755
			if($ou)
756
				$ous[] = $ou;
757
		}
758
	}
759

    
760
	@ldap_unbind($ldap);
761

    
762
	return $ous;
763
}
764

    
765
function ldap_get_groups($username, $authcfg) {
766
	global $debug, $config;
767
	
768
	if(!function_exists("ldap_connect"))
769
		return;
770
	
771
	if(!$username) 
772
		return false;
773

    
774
	if(stristr($username, "@")) {
775
		$username_split=split("\@", $username);
776
		$username = $username_split[0];		
777
	}
778

    
779
	if(stristr($username, "\\")) {
780
		$username_split=split("\\", $username);
781
		$username = $username_split[0];        
782
	}    
783
	
784
	//log_error("Getting LDAP groups for {$username}.");
785
        if ($authcfg) {
786
                if (strstr($authcfg['ldap_urltype'], "Standard"))
787
                        $ldapproto = "ldap";
788
                else
789
                        $ldapproto = "ldaps";
790
                $ldapserver         = "{$ldapproto}://{$authcfg['host']}";
791
                $ldapport           = $authcfg['ldap_port'];
792
                $ldapbasedn         = $authcfg['ldap_basedn'];
793
                $ldapbindun         = $authcfg['ldap_binddn'];
794
                $ldapbindpw         = $authcfg['ldap_bindpw'];
795
                $ldapauthcont       = $authcfg['ldap_authcn'];
796
                $ldapnameattribute  = strtolower($authcfg['ldap_attr_user']);
797
                $ldapgroupattribute  = strtolower($authcfg['ldap_attr_member']);
798
                $ldapfilter         = "({$ldapnameattribute}={$username})";
799
                $ldaptype           = "";
800
                $ldapver            = $authcfg['ldap_protver'];
801
		if (empty($ldapbindun) || empty($ldapbindpw))
802
                        $ldapanon = true;
803
                else
804
                        $ldapanon = false;
805
                $ldapname           = $authcfg['name'];
806
                $ldapfallback       = false;
807
		$ldapscope          = $authcfg['ldap_scope'];
808
	} else
809
		return false;
810

    
811
	$ldapdn             = $_SESSION['ldapdn'];
812

    
813
	/*Convert attribute to lowercase.  php ldap arrays put everything in lowercase */
814
	$ldapgroupattribute = strtolower($ldapgroupattribute);
815
	$memberof = array();
816

    
817
	/* connect and see if server is up */
818
	putenv('LDAPTLS_REQCERT=never');
819
	$error = false;
820
        if (empty($ldapport)) {
821
                if (!($ldap = ldap_connect($ldapserver)))
822
                        $error = true;
823
        } else if (!($ldap = ldap_connect($ldapserver, $ldapport)))
824
                $error = true;
825

    
826
	if ($error == true) {
827
		log_error("ERROR! ldap_get_groups() Could not connect to server {$ldapname}.");
828
                return memberof;
829
        }
830
    
831
	ldap_set_option($ldap, LDAP_OPT_REFERRALS, 0);
832
	ldap_set_option($ldap, LDAP_OPT_PROTOCOL_VERSION, (int)$ldapver);
833

    
834
	/* bind as user that has rights to read group attributes */
835
	if ($ldapanon == true) {
836
                if (!($res = @ldap_bind($ldap))) {
837
			log_error("ERROR! ldap_get_groups() could not bind anonymously to server {$ldapname}.");
838
			@ldap_close($ldap);
839
                        return false;
840
		}
841
	} else if (!($res = @ldap_bind($ldap, $ldapbindun, $ldapbindpw))) {
842
		log_error("ERROR! ldap_get_groups() could not bind to server {$ldapname}.");
843
		@ldap_close($ldap);
844
		return memberof;
845
	}
846

    
847
	/* get groups from DN found */
848
	/* use ldap_read instead of search so we don't have to do a bunch of extra work */
849
	/* since we know the DN is in $_SESSION['ldapdn'] */
850
	//$search    = ldap_read($ldap, $ldapdn, "(objectclass=*)", array($ldapgroupattribute));
851
	if ($ldapscope == "one")
852
                $ldapfunc = "ldap_list";
853
        else
854
                $ldapfunc = "ldap_search";
855

    
856
	$search    = @$ldapfunc($ldap, $ldapdn, $ldapfilter, array($ldapgroupattribute));
857
	$info      = @ldap_get_entries($ldap, $search);
858

    
859
	$countem = $info["count"];	
860
	
861
	if(is_array($info[0][$ldapgroupattribute])) {
862
		/* Iterate through the groups and throw them into an array */
863
		foreach ($info[0][$ldapgroupattribute] as $member) {
864
			if (stristr($member, "CN=") !== false) {
865
				$membersplit = split(",", $member);
866
				$memberof[] = preg_replace("/CN=/i", "", $membersplit[0]);
867
			}
868
		}
869
	}
870
	
871
	/* Time to close LDAP connection */
872
	@ldap_unbind($ldap);
873
	
874
	$groups = print_r($memberof,true);
875
	
876
	//log_error("Returning groups ".$groups." for user $username");
877
	
878
	return $memberof;
879
}
880

    
881
function ldap_backed($username, $passwd, $authcfg) {
882
	global $debug, $config;
883
	
884
	if(!$username) 
885
		return;
886

    
887
	if(!function_exists("ldap_connect"))
888
		return;
889

    
890
	if(stristr($username, "@")) {
891
		$username_split=split("\@", $username);
892
		$username = $username_split[0];        
893
	}
894
	if(stristr($username, "\\")) {
895
		$username_split=split("\\", $username);
896
		$username = $username_split[0];        
897
	}
898

    
899
	if ($authcfg) {
900
		if (strstr($authcfg['ldap_urltype'], "Standard"))
901
			$ldapproto = "ldap";
902
		else
903
			$ldapproto = "ldaps";
904
		$ldapserver         = "{$ldapproto}://{$authcfg['host']}";
905
		$ldapport	    = $authcfg['ldap_port'];
906
                $ldapbasedn         = $authcfg['ldap_basedn'];
907
                $ldapbindun         = $authcfg['ldap_binddn'];
908
                $ldapbindpw         = $authcfg['ldap_bindpw'];
909
		if (empty($ldapbindun) || empty($ldapbindpw))
910
			$ldapanon = true;
911
		else
912
			$ldapanon = false;
913
                $ldapauthcont       = $authcfg['ldap_authcn'];
914
                $ldapnameattribute  = strtolower($authcfg['ldap_attr_user']);
915
                $ldapfilter         = "({$ldapnameattribute}={$username})";
916
                $ldaptype           = "";
917
                $ldapver            = $authcfg['ldap_protver'];
918
		$ldapname	    = $authcfg['name'];
919
		$ldapscope	    = $authcfg['ldap_scope'];
920
	} else
921
		return false;
922

    
923
	/* first check if there is even an LDAP server populated */ 
924
	if(!$ldapserver) {
925
		if ($ldapfallback) {
926
			log_error("ERROR! ldap_backed() called with no LDAP authentication server defined.  Defaulting to local user database. Visit System -> User Manager.");
927
			return local_backed($username, $passwd);
928
		} else
929
			log_error("ERROR! ldap_backed() called with no LDAP authentication server defined.");
930

    
931
		return false;
932
	}
933
	
934
	ldap_set_option($ldap, LDAP_OPT_REFERRALS, 0);
935
	ldap_set_option($ldap, LDAP_OPT_PROTOCOL_VERSION, (int)$ldapver);
936

    
937
	/* Make sure we can connect to LDAP */
938
	putenv('LDAPTLS_REQCERT=never');
939
	$error = false;
940
	if (empty($ldapport)) {
941
		if (!($ldap = ldap_connect($ldapserver)))
942
			$error = true;
943
	} else if (!($ldap = ldap_connect($ldapserver, $ldapport)))
944
		$error = true;
945

    
946
	if ($error == true) {
947
		log_error("ERROR!  Could not connect to server {$ldapname}.");
948
		return false;
949
	}
950

    
951
	/* ok, its up.  now, lets bind as the bind user so we can search it */
952
	$error = false;
953
	if ($ldapanon == true) {
954
                if (!($res = @ldap_bind($ldap)))
955
                        $error = true;
956
	} else if (!($res = ldap_bind($ldap, $ldapbindun, $ldapbindpw)))
957
		$error = true;
958

    
959
	if ($error == true) {
960
		@ldap_close($ldap);
961
		log_error("ERROR! Could not bind to server {$ldapname}.");
962
		return false;
963
	}
964
	
965
	/* Get LDAP Authcontainers and split em up. */
966
	$ldac_splits = split(";", $ldapauthcont);
967
	
968
	/* setup the usercount so we think we havn't found anyone yet */
969
	$usercount  = 0;
970

    
971
	/*****************************************************************/
972
	/*  We First find the user based on username and filter          */
973
	/*  Then, once we find the first occurance of that person        */
974
	/*  We set seesion variables to ponit to the OU and DN of the    */
975
	/*  Person.  To later be used by ldap_get_groups.                */
976
	/*  that way we don't have to search twice.                      */
977
	/*****************************************************************/
978
	log_error("Now Searching for {$username} in directory.");
979
	/* Iterate through the user containers for search */
980
	foreach ($ldac_splits as $i => $ldac_split) {
981
		/* Make sure we just use the first user we find */
982
		log_error("Now Searching in server {$ldapname}, container {$ldac_split} with filter {$ldapfilter}.");
983
		if ($ldapscope == "one")
984
			$ldapfunc = "ldap_list";
985
		else
986
			$ldapfunc = "ldap_search";
987
		/* Support legacy auth container specification. */
988
		if (stristr($ldac_split, "DC=") || empty($ldapbasedn))
989
			$search	 = @$ldapfunc($ldap,$ldac_split,$ldapfilter);
990
		else
991
			$search  = @$ldapfunc($ldap,"{$ldac_split},{$ldapbasedn}",$ldapfilter);
992
		if (!$search) {
993
			log_error("Search resulted in error: " . ldap_error($ldap));
994
			continue;
995
		}
996
		$info	 = ldap_get_entries($ldap,$search);
997
		$matches = $info['count'];
998
		if ($matches == 1){
999
			$userdn = $_SESSION['ldapdn'] = $info[0]['dn'];
1000
			$_SESSION['ldapou'] = $ldac_split[$i];
1001
			$_SESSION['ldapon'] = "true";
1002
			$usercount = 1;
1003
			break;
1004
		}
1005
	}
1006

    
1007
	if ($usercount != 1){
1008
		@ldap_unbind($ldap);
1009
		log_error("ERROR! Either LDAP search failed, or multiple users were found.");
1010
		return false;                         
1011
	}
1012

    
1013
	/* Now lets bind as the user we found */
1014
	if (!($res = @ldap_bind($ldap, $userdn, $passwd))) {
1015
		log_error("ERROR! Could not login to server {$ldapname} as user {$username}.");
1016
		@ldap_unbind($ldap);
1017
		return false;
1018
	}
1019

    
1020
	log_error("Logged in successfully as {$username} via LDAP server {$ldapname} with DN = {$userdn}.");
1021

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

    
1025
	return true;
1026
}
1027

    
1028
function radius_backed($username, $passwd, $authcfg){
1029
	global $debug, $config;
1030
	$ret = false;
1031

    
1032
	require_once("radius.inc");
1033

    
1034
	$rauth = new Auth_RADIUS_PAP($username, $passwd);
1035
	if ($authcfg) {
1036
		$radiusservers = array();
1037
		$radiusservers[0]['ipaddr'] = $authcfg['host'];
1038
		$radiusservers[0]['port'] = $authcfg['radius_auth_port'];
1039
		$radiusservers[0]['sharedsecret'] = $authcfg['radius_secret'];
1040
	} else
1041
		return false;
1042

    
1043
	/* Add a new servers to our instance */
1044
	foreach ($radiusservers as $radsrv)
1045
		$rauth->addServer($radsrv['ipaddr'], $radsrv['port'], $radsrv['sharedsecret']);
1046

    
1047
	if (PEAR::isError($rauth->start())) {
1048
		$retvalue['auth_val'] = 1;
1049
		$retvalue['error'] = $rauth->getError();
1050
		if ($debug)
1051
			printf("Radius start: %s<br>\n", $retvalue['error']);
1052
	}
1053

    
1054
	// XXX - billm - somewhere in here we need to handle securid challenge/response
1055

    
1056
	/* Send request */
1057
	$result = $rauth->send();
1058
	if (PEAR::isError($result)) {
1059
		$retvalue['auth_val'] = 1;
1060
		$retvalue['error'] = $result->getMessage();
1061
		if ($debug)
1062
			printf("Radius send failed: %s<br>\n", $retvalue['error']);
1063
	} else if ($result === true) {
1064
		$retvalue['auth_val'] = 2;
1065
		if ($debug)
1066
			printf(gettext("Radius Auth succeeded")."<br>\n");
1067
		$ret = true;
1068
	} else {
1069
		$retvalue['auth_val'] = 3;
1070
		if ($debug)
1071
			printf(gettext("Radius Auth rejected")."<br>\n");
1072
	}
1073

    
1074
	// close OO RADIUS_AUTHENTICATION
1075
	$rauth->close();
1076

    
1077
	return $ret;
1078
}
1079

    
1080
function get_user_expiration_date($username) {
1081
	$user = getUserEntry($username);
1082
	if ($user['expires']) 
1083
		return $user['expires'];
1084
}
1085

    
1086
function is_account_expired($username) {
1087
	$expirydate = get_user_expiration_date($username);
1088
	if ($expirydate) {
1089
		if (strtotime("-1 day") > strtotime(date("m/d/Y",strtotime($expirydate))))
1090
			return true;
1091
	}
1092

    
1093
	return false;
1094
}
1095

    
1096
function is_account_disabled($username) {
1097
	$user = getUserEntry($username);
1098
	if (isset($user['disabled']))
1099
		return true;
1100

    
1101
	return false;
1102
}
1103

    
1104
function auth_get_authserver($name) {
1105
        global $config;
1106

    
1107
        if (is_array($config['system']['authserver'])) {
1108
                foreach ($config['system']['authserver'] as $authcfg) {
1109
                        if ($authcfg['name'] == $name)
1110
                                return $authcfg;
1111
                }
1112
        }
1113
	if ($name == "Local Database")
1114
		return array("name" => "Local Database", "type" => "Local Auth", "host" => $config['system']['hostname']);
1115
}
1116

    
1117
function auth_get_authserver_list() {
1118
        global $config;
1119

    
1120
	$list = array();
1121

    
1122
        if (is_array($config['system']['authserver'])) {
1123
                foreach ($config['system']['authserver'] as $authcfg) {
1124
			/* Add support for disabled entries? */
1125
			$list[$authcfg['name']] = $authcfg;
1126
                }
1127
        }
1128

    
1129
	$list["Local Database"] = array( "name" => "Local Database", "type" => "Local Auth", "host" => $config['system']['hostname']);
1130
	return $list;
1131
}
1132

    
1133
function getUserGroups($username, $authcfg) {
1134
	global $config;
1135

    
1136
	$allowed_groups = array();
1137

    
1138
	switch($authcfg['type']) {
1139
        case 'ldap':
1140
		$allowed_groups = @ldap_get_groups($username, $authcfg);
1141
		break;
1142
	case 'radius':
1143
		break;
1144
	default:
1145
		$user = getUserEntry($username);
1146
		$allowed_groups = @local_user_get_groups($user, true);
1147
		break;
1148
	}
1149

    
1150
	$member_groups = array();
1151
        if (is_array($config['system']['group'])) {
1152
                foreach ($config['system']['group'] as $group)
1153
                        if (in_array($group['name'], $allowed_groups))
1154
				$member_groups[] = $group['name'];
1155
	}
1156

    
1157
	return $member_groups;
1158
}
1159

    
1160
function authenticate_user($username, $password, $authcfg = NULL) {
1161

    
1162
	if (!$authcfg) {
1163
		return local_backed($username, $password);
1164
	}
1165

    
1166
	$authenticated = false;
1167
	switch($authcfg['type']) {
1168
        case 'ldap':
1169
                if (ldap_backed($username, $password, $authcfg))
1170
                        $authenticated = true;
1171
                break;
1172
        case 'radius':
1173
                if (radius_backed($username, $password, $authcfg))
1174
                        $authenticated = true;
1175
                break;
1176
        default:
1177
                /* lookup user object by name */
1178
                if (local_backed($username, $password))
1179
                        $authenticated = true;
1180
                break;
1181
        }
1182

    
1183
	return $authenticated;
1184
}
1185

    
1186
function session_auth() {
1187
	global $HTTP_SERVER_VARS, $config, $_SESSION, $page;
1188

    
1189
	session_start();
1190

    
1191
	/* Validate incoming login request */
1192
	if (isset($_POST['login'])) {
1193
		$authcfg = auth_get_authserver($config['system']['webgui']['authmode']);
1194
		if (authenticate_user($_POST['usernamefld'], $_POST['passwordfld'], $authcfg) || 
1195
		    authenticate_user($_POST['usernamefld'], $_POST['passwordfld'])) {
1196
			$_SESSION['Logged_In'] = "True";
1197
			$_SESSION['Username'] = $_POST['usernamefld'];
1198
			$_SESSION['last_access'] = time();
1199
			log_error("Successful login for user '{$_POST['usernamefld']}' from: {$_SERVER['REMOTE_ADDR']}");
1200
			$HTTP_SERVER_VARS['AUTH_USER'] = $_SESSION['Username'];
1201
			if (isset($_POST['postafterlogin']))
1202
				return true;
1203
			else {
1204
				if (empty($page))
1205
					$page = "/";
1206
				header("Location: {$page}");
1207
			}
1208
			exit;
1209
		} else {
1210
			/* give the user an error message */
1211
			$_SESSION['Login_Error'] = "Username or Password incorrect";
1212
			log_error("Login attempt with user: '{$_POST['usernamefld']}' from: '{$_SERVER['REMOTE_ADDR']}' failed.");
1213
			if(isAjax()) {
1214
				echo "showajaxmessage('{$_SESSION['Login_Error']}');";
1215
				return;
1216
			}
1217
		}
1218
	}
1219

    
1220
	/* Show login page if they aren't logged in */
1221
	if (empty($_SESSION['Logged_In']))
1222
		return false;
1223

    
1224
	/* If session timeout isn't set, we don't mark sessions stale */
1225
	if (!isset($config['system']['webgui']['session_timeout'])) {
1226
		/* Default to 4 hour timeout if one is not set */
1227
		if ($_SESSION['last_access'] < (time() - 14400)) {
1228
			$_GET['logout'] = true;
1229
			$_SESSION['Logout'] = true;
1230
		} else
1231
			$_SESSION['last_access'] = time();	
1232
	} else if (intval($config['system']['webgui']['session_timeout']) == 0) {
1233
		/* only update if it wasn't ajax */
1234
		if (!isAjax())
1235
			$_SESSION['last_access'] = time();
1236
	} else {
1237
		/* Check for stale session */
1238
		if ($_SESSION['last_access'] < (time() - ($config['system']['webgui']['session_timeout'] * 60))) {
1239
			$_GET['logout'] = true;
1240
			$_SESSION['Logout'] = true;
1241
		} else {
1242
			/* only update if it wasn't ajax */
1243
			if (!isAjax())
1244
				$_SESSION['last_access'] = time();
1245
		}
1246
	}
1247

    
1248
	/* user hit the logout button */
1249
	if (isset($_GET['logout'])) {
1250

    
1251
		if ($_SESSION['Logout'])
1252
			log_error("Session timed out for user '{$_SESSION['Username']}' from: {$_SERVER['REMOTE_ADDR']}");
1253
		else
1254
			log_error("User logged out for user '{$_SESSION['Username']}' from: {$_SERVER['REMOTE_ADDR']}");
1255

    
1256
		/* wipe out $_SESSION */
1257
		$_SESSION = array();
1258

    
1259
		if (isset($_COOKIE[session_name()]))
1260
			setcookie(session_name(), '', time()-42000, '/');
1261

    
1262
		/* and destroy it */
1263
		session_destroy();
1264

    
1265
		$scriptName = split("/", $_SERVER["SCRIPT_FILENAME"]);
1266
		$scriptElms = count($scriptName);
1267
		$scriptName = $scriptName[$scriptElms-1];
1268

    
1269
		if (isAjax())
1270
			return false;
1271

    
1272
		/* redirect to page the user is on, it'll prompt them to login again */
1273
		Header("Location: {$scriptName}");
1274

    
1275
		return false;
1276
	}
1277

    
1278
	/*
1279
	 * this is for debugging purpose if you do not want to use Ajax
1280
	 * to submit a HTML form. It basically diables the observation
1281
	 * of the submit event and hence does not trigger Ajax.
1282
	 */
1283
	if ($_GET['disable_ajax'])
1284
		$_SESSION['NO_AJAX'] = "True";
1285

    
1286
	/*
1287
	 * Same to re-enable Ajax.
1288
	 */
1289
	if ($_GET['enable_ajax'])
1290
		unset($_SESSION['NO_AJAX']);
1291

    
1292
	$HTTP_SERVER_VARS['AUTH_USER'] = $_SESSION['Username'];
1293
	return true;
1294
}
1295

    
1296
?>
(4-4/54)