Project

General

Profile

Download (35.2 KB) Statistics
| Branch: | Tag: | Revision:
1 1df17ba9 Scott Ullrich
<?php
2
/* $Id$ */
3 fab7ff44 Bill Marquette
/*
4 1df17ba9 Scott Ullrich
    system_usermanager.php
5
    part of m0n0wall (http://m0n0.ch/wall)
6
7 6b07c15a Matthew Grooms
    Copyright (C) 2008 Shrew Soft Inc.
8
    All rights reserved.
9
10 1df17ba9 Scott Ullrich
    Copyright (C) 2005 Paul Taylor <paultaylor@winn-dixie.com>.
11
    All rights reserved.
12
13
    Copyright (C) 2003-2005 Manuel Kasper <mk@neon1.net>.
14
    All rights reserved.
15
16
    Redistribution and use in source and binary forms, with or without
17
    modification, are permitted provided that the following conditions are met:
18
19
    1. Redistributions of source code must retain the above copyright notice,
20
       this list of conditions and the following disclaimer.
21
22
    2. Redistributions in binary form must reproduce the above copyright
23
       notice, this list of conditions and the following disclaimer in the
24
       documentation and/or other materials provided with the distribution.
25
26
    THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
27
    INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
28
    AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
29
    AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
30
    OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31
    SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32
    INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33
    CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34
    ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35
    POSSIBILITY OF SUCH DAMAGE.
36 fab7ff44 Bill Marquette
*/
37 1d333258 Scott Ullrich
/*
38
	pfSense_BUILDER_BINARIES:	
39
	pfSense_MODULE:	auth
40
*/
41 fab7ff44 Bill Marquette
42 6b07c15a Matthew Grooms
##|+PRIV
43
##|*IDENT=page-system-usermanager
44
##|*NAME=System: User Manager page
45
##|*DESCR=Allow access to the 'System: User Manager' page.
46
##|*MATCH=system_usermanager.php*
47
##|-PRIV
48
49 ead24d63 sullrich
require("certs.inc");
50 fab7ff44 Bill Marquette
require("guiconfig.inc");
51
52 45ee90ed Matthew Grooms
if (isAllowedPage("system_usermanager")) {
53 31b53653 Scott Ullrich
54 45ee90ed Matthew Grooms
	// start admin user code
55 b79454a7 Carlos Eduardo Ramos
	$pgtitle = array(gettext("System"),gettext("User Manager"));
56 fab7ff44 Bill Marquette
57 45ee90ed Matthew Grooms
	$id = $_GET['id'];
58
	if (isset($_POST['id']))
59
		$id = $_POST['id'];
60 1df17ba9 Scott Ullrich
61 7e4a4513 Scott Ullrich
	if (!is_array($config['system']['user'])) 
62
		$config['system']['user'] = array();
63 1df17ba9 Scott Ullrich
64 6b07c15a Matthew Grooms
	$a_user = &$config['system']['user'];
65 45ee90ed Matthew Grooms
66 6b07c15a Matthew Grooms
	if ($_GET['act'] == "deluser") {
67 45ee90ed Matthew Grooms
68 58fdb8ad Matthew Grooms
		if (!$a_user[$id]) {
69 6b07c15a Matthew Grooms
			pfSenseHeader("system_usermanager.php");
70
			exit;
71 45ee90ed Matthew Grooms
		}
72
73 58fdb8ad Matthew Grooms
		local_user_del($a_user[$id]);
74
		$userdeleted = $a_user[$id]['name'];
75
		unset($a_user[$id]);
76 6b07c15a Matthew Grooms
		write_config();
77
		$savemsg = gettext("User")." {$userdeleted} ".
78
					gettext("successfully deleted")."<br/>";
79
	}
80
81
	if ($_GET['act'] == "delpriv") {
82
83 58fdb8ad Matthew Grooms
		if (!$a_user[$id]) {
84 6b07c15a Matthew Grooms
			pfSenseHeader("system_usermanager.php");
85
			exit;
86 45ee90ed Matthew Grooms
		}
87 6b07c15a Matthew Grooms
88
		$privdeleted = $priv_list[$a_user[$id]['priv'][$_GET['privid']]]['name'];
89
		unset($a_user[$id]['priv'][$_GET['privid']]);
90
		write_config();
91
		$_GET['act'] = "edit";
92
		$savemsg = gettext("Privilege")." {$privdeleted} ".
93
					gettext("successfully deleted")."<br/>";
94 45ee90ed Matthew Grooms
	}
95
96 93823b10 Matthew Grooms
	if ($_GET['act'] == "expcert") {
97
98
		if (!$a_user[$id]) {
99
			pfSenseHeader("system_usermanager.php");
100
			exit;
101
		}
102
103
		$cert =& $a_user[$id]['cert'][$_GET['certid']];
104
105
		$exp_name = urlencode("{$a_user[$id]['name']}-{$cert['name']}.crt");
106
		$exp_data = base64_decode($cert['crt']);
107
		$exp_size = strlen($exp_data);
108
109
		header("Content-Type: application/octet-stream");
110
		header("Content-Disposition: attachment; filename={$exp_name}");
111
		header("Content-Length: $exp_size");
112
		echo $exp_data;
113
		exit;
114
	}
115
116
	if ($_GET['act'] == "expckey") {
117
118
		if (!$a_user[$id]) {
119
			pfSenseHeader("system_usermanager.php");
120
			exit;
121
		}
122
123
		$cert =& $a_user[$id]['cert'][$_GET['certid']];
124
125
		$exp_name = urlencode("{$a_user[$id]['name']}-{$cert['name']}.key");
126
		$exp_data = base64_decode($cert['prv']);
127
		$exp_size = strlen($exp_data);
128
129
		header("Content-Type: application/octet-stream");
130
		header("Content-Disposition: attachment; filename={$exp_name}");
131
		header("Content-Length: $exp_size");
132
		echo $exp_data;
133
		exit;
134
	}
135
136 58fdb8ad Matthew Grooms
	if ($_GET['act'] == "delcert") {
137
138
		if (!$a_user[$id]) {
139
			pfSenseHeader("system_usermanager.php");
140
			exit;
141
		}
142
143
		$certdeleted = $a_user[$id]['cert'][$_GET['certid']]['name'];
144
		unset($a_user[$id]['cert'][$_GET['certid']]);
145
		write_config();
146
		$_GET['act'] = "edit";
147
		$savemsg = gettext("Certificate")." {$certdeleted} ".
148
					gettext("successfully deleted")."<br/>";
149
	}
150
151 45ee90ed Matthew Grooms
	if ($_GET['act'] == "edit") {
152
		if (isset($id) && $a_user[$id]) {
153
			$pconfig['usernamefld'] = $a_user[$id]['name'];
154
			$pconfig['fullname'] = $a_user[$id]['fullname'];
155 0092b3bd mgrooms
			$pconfig['expires'] = $a_user[$id]['expires'];
156 659fa7f2 Matthew Grooms
			$pconfig['groups'] = local_user_get_groups($a_user[$id]);
157 45ee90ed Matthew Grooms
			$pconfig['utype'] = $a_user[$id]['scope'];
158
			$pconfig['uid'] = $a_user[$id]['uid'];
159
			$pconfig['authorizedkeys'] = base64_decode($a_user[$id]['authorizedkeys']);
160 6b07c15a Matthew Grooms
			$pconfig['priv'] = $a_user[$id]['priv'];
161 ddd1fb7f jim-p
			$pconfig['ipsecpsk'] = $a_user[$id]['ipsecpsk'];
162 b4bfd25d sullrich
			$pconfig['disabled'] = isset($a_user[$id]['disabled']);
163 45ee90ed Matthew Grooms
		}
164
	}
165
166
	if ($_GET['act'] == "new") {
167
		/*
168
		 * set this value cause the text field is read only
169
		 * and the user should not be able to mess with this
170
		 * setting.
171
		 */
172
		$pconfig['utype'] = "user";
173 13646069 Ermal
		$pconfig['lifetime'] = 3650;
174 45ee90ed Matthew Grooms
	}
175
176
	if ($_POST) {
177
		unset($input_errors);
178
		$pconfig = $_POST;
179
180
		/* input validation */
181
		if (isset($id) && ($a_user[$id])) {
182
			$reqdfields = explode(" ", "usernamefld");
183 76d49f20 Renato Botelho
			$reqdfieldsn = array(gettext("Username"));
184 45ee90ed Matthew Grooms
		} else {
185 c9794c06 Ermal
			if (empty($_POST['name'])) {
186
				$reqdfields = explode(" ", "usernamefld passwordfld1");
187 76d49f20 Renato Botelho
				$reqdfieldsn = array(
188
					gettext("Username"),
189
					gettext("Password"));
190 c9794c06 Ermal
			} else {
191
				$reqdfields = explode(" ", "usernamefld passwordfld1 name caref keylen lifetime");
192 76d49f20 Renato Botelho
				$reqdfieldsn = array(
193
					gettext("Username"),
194
					gettext("Password"),
195
					gettext("Descriptive name"),
196
					gettext("Certificate authority"),
197
					gettext("Key length"),
198
					gettext("Lifetime"));
199 c9794c06 Ermal
			}
200 45ee90ed Matthew Grooms
		}
201
202
		do_input_validation($_POST, $reqdfields, $reqdfieldsn, &$input_errors);
203
204
		if (preg_match("/[^a-zA-Z0-9\.\-_]/", $_POST['usernamefld']))
205
			$input_errors[] = gettext("The username contains invalid characters.");
206
207
		if (($_POST['passwordfld1']) && ($_POST['passwordfld1'] != $_POST['passwordfld2']))
208
			$input_errors[] = gettext("The passwords do not match.");
209
210 3dec33d4 Erik Fonnesbeck
		if (isset($id) && $a_user[$id])
211
			$oldusername = $a_user[$id]['name'];
212
		else
213
			$oldusername = "";
214 45ee90ed Matthew Grooms
		/* make sure this user name is unique */
215 3dec33d4 Erik Fonnesbeck
		if (!$input_errors) {
216 45ee90ed Matthew Grooms
			foreach ($a_user as $userent) {
217 3dec33d4 Erik Fonnesbeck
				if ($userent['name'] == $_POST['usernamefld'] && $oldusername != $_POST['usernamefld']) {
218 45ee90ed Matthew Grooms
					$input_errors[] = gettext("Another entry with the same username already exists.");
219
					break;
220
				}
221 58664cc9 Scott Ullrich
			}
222 3dec33d4 Erik Fonnesbeck
		}
223
		/* also make sure it is not reserved */
224
		if (!$input_errors) {
225 8339ab6d jim-p
			$system_users = explode("\n", file_get_contents("/etc/passwd"));
226
			foreach ($system_users as $s_user) {
227
				$ent = explode(":", $s_user);
228 3dec33d4 Erik Fonnesbeck
				if ($ent[0] == $_POST['usernamefld'] && $oldusername != $_POST['usernamefld']) {
229
					$input_errors[] = gettext("That username is reserved by the system.");
230 8339ab6d jim-p
					break;
231
				}
232
			}
233 7e4a4513 Scott Ullrich
		}
234 1df17ba9 Scott Ullrich
235 0092b3bd mgrooms
		/*
236
		 * Check for a valid expirationdate if one is set at all (valid means,
237
		 * strtotime() puts out a time stamp so any strtotime compatible time
238
		 * format may be used. to keep it simple for the enduser, we only
239
		 * claim to accept MM/DD/YYYY as inputs. Advanced users may use inputs
240
		 * like "+1 day", which will be converted to MM/DD/YYYY based on "now".
241
		 * Otherwhise such an entry would lead to an invalid expiration data.
242
		 */
243
		if ($_POST['expires']){
244
			if(strtotime($_POST['expires']) > 0){
245
				if (strtotime("-1 day") > strtotime(date("m/d/Y",strtotime($_POST['expires'])))) {
246 0a82fa9b sullrich
					// Allow items to lie in the past which ends up disabling.
247 0092b3bd mgrooms
				} else {
248
					//convert from any strtotime compatible date to MM/DD/YYYY
249
					$expdate = strtotime($_POST['expires']);
250
					$_POST['expires'] = date("m/d/Y",$expdate);
251
				}
252
			} else {
253 b79454a7 Carlos Eduardo Ramos
				$input_errors[] = gettext("Invalid expiration date format; use MM/DD/YYYY instead.");
254 0092b3bd mgrooms
			}
255
		}
256
257 c9794c06 Ermal
		if (!empty($_POST['name'])) {
258
			$ca = lookup_ca($_POST['caref']);
259
        		if (!$ca)
260 39c0be7b Vinicius Coque
                		$input_errors[] = gettext("Invalid internal Certificate Authority") . "\n";
261 c9794c06 Ermal
		}
262
263 45ee90ed Matthew Grooms
		/* if this is an AJAX caller then handle via JSON */
264
		if (isAjax() && is_array($input_errors)) {
265
			input_errors2Ajax($input_errors);
266
			exit;
267
		}
268 1df17ba9 Scott Ullrich
269 45ee90ed Matthew Grooms
		if (!$input_errors) {
270 e879fc81 Ermal
			conf_mount_rw();
271 45ee90ed Matthew Grooms
			$userent = array();
272
			if (isset($id) && $a_user[$id])
273
				$userent = $a_user[$id];
274 1df17ba9 Scott Ullrich
275 fb1266d3 Matthew Grooms
			isset($_POST['utype']) ? $userent['scope'] = $_POST['utype'] : $userent['scope'] = "system";
276
277 659fa7f2 Matthew Grooms
			/* the user name was modified */
278 45ee90ed Matthew Grooms
			if ($_POST['usernamefld'] <> $_POST['oldusername'])
279
				$_SERVER['REMOTE_USER'] = $_POST['usernamefld'];
280 7e4a4513 Scott Ullrich
281 659fa7f2 Matthew Grooms
			/* the user password was mofified */
282
			if ($_POST['passwordfld1'])
283
				local_user_set_password($userent, $_POST['passwordfld1']);
284
285 45ee90ed Matthew Grooms
			$userent['name'] = $_POST['usernamefld'];
286
			$userent['fullname'] = $_POST['fullname'];
287 0092b3bd mgrooms
			$userent['expires'] = $_POST['expires'];
288 fb1266d3 Matthew Grooms
			$userent['authorizedkeys'] = base64_encode($_POST['authorizedkeys']);
289 ddd1fb7f jim-p
			$userent['ipsecpsk'] = $_POST['ipsecpsk'];
290 b4bfd25d sullrich
			
291
			if($_POST['disabled'])
292
				$userent['disabled'] = true;
293
			else 
294
				unset($userent['disabled']);
295 1df17ba9 Scott Ullrich
296 45ee90ed Matthew Grooms
			if (isset($id) && $a_user[$id])
297
				$a_user[$id] = $userent;
298
			else {
299 c9794c06 Ermal
				if (!empty($_POST['name'])) {
300
					$cert = array();
301
                        		$userent['cert'] = array();
302
303
            				$cert['name'] = $_POST['name'];
304
305
                			$subject = cert_get_subject_array($ca['crt']);
306
307
                			$dn = array(
308
                        			'countryName' => $subject[0]['v'],
309
                        			'stateOrProvinceName' => $subject[1]['v'],
310
                        			'localityName' => $subject[2]['v'],
311
                        			'organizationName' => $subject[3]['v'],
312
                        			'emailAddress' => $subject[4]['v'],
313
                        			'commonName' => $userent['name']);
314
315
					cert_create($cert, $_POST['caref'], $_POST['keylen'],
316
						(int)$_POST['lifetime'], $dn);
317
318
					$userent['cert'][] = $cert;
319
				}
320 45ee90ed Matthew Grooms
				$userent['uid'] = $config['system']['nextuid']++;
321 e879fc81 Ermal
				/* Add the user to All Users group. */
322
				foreach ($config['system']['group'] as $gidx => $group) {
323
					if ($group['name'] == "all") {
324 a803793f jim-p
						if (!is_array($config['system']['group'][$gidx]['member']))
325
							$config['system']['group'][$gidx]['member'] = array();
326 e879fc81 Ermal
						$config['system']['group'][$gidx]['member'][] = $userent['uid'];
327
						break;
328
					}
329
				}
330
331 45ee90ed Matthew Grooms
				$a_user[] = $userent;
332
			}
333 1df17ba9 Scott Ullrich
334 659fa7f2 Matthew Grooms
			local_user_set_groups($userent,$_POST['groups']);
335 2934322e jim-p
			local_user_set($userent);
336 45ee90ed Matthew Grooms
			write_config();
337 1df17ba9 Scott Ullrich
338 970db70b Scott Ullrich
			if(is_dir("/etc/inc/privhooks"))
339
				run_plugins("/etc/inc/privhooks");
340
341 dff1a09d Scott Ullrich
			conf_mount_ro();
342
			
343 45ee90ed Matthew Grooms
			pfSenseHeader("system_usermanager.php");
344
		}
345
	}
346 fab7ff44 Bill Marquette
347 45ee90ed Matthew Grooms
	include("head.inc");
348 1df17ba9 Scott Ullrich
?>
349 fab7ff44 Bill Marquette
350 1df17ba9 Scott Ullrich
<body link="#000000" vlink="#000000" alink="#000000" onload="<?= $jsevents["body"]["onload"] ?>">
351 6b07c15a Matthew Grooms
<?php include("fbegin.inc"); ?>
352 0092b3bd mgrooms
<!--
353
//Date Time Picker script- by TengYong Ng of http://www.rainforestnet.com
354
//Script featured on JavaScript Kit (http://www.javascriptkit.com)
355
//For this script, visit http://www.javascriptkit.com
356
// -->
357 9344dd7b mgrooms
<script language="javascript" type="text/javascript" src="javascript/datetimepicker.js"></script>
358 6b07c15a Matthew Grooms
<script language="JavaScript">
359
<!--
360
361
function setall_selected(id) {
362
	selbox = document.getElementById(id);
363
	count = selbox.options.length;
364
	for (index = 0; index<count; index++)
365
		selbox.options[index].selected = true;
366
}
367
368
function clear_selected(id) {
369
	selbox = document.getElementById(id);
370
	count = selbox.options.length;
371
	for (index = 0; index<count; index++)
372
		selbox.options[index].selected = false;
373
}
374
375
function remove_selected(id) {
376
	selbox = document.getElementById(id);
377
	index = selbox.options.length - 1;
378
	for (; index >= 0; index--)
379
		if (selbox.options[index].selected)
380
			selbox.remove(index);
381
}
382
383
function copy_selected(srcid, dstid) {
384
	src_selbox = document.getElementById(srcid);
385
	dst_selbox = document.getElementById(dstid);
386
	count = src_selbox.options.length;
387
	for (index = 0; index < count; index++) {
388
		if (src_selbox.options[index].selected) {
389
			option = document.createElement('option');
390
			option.text = src_selbox.options[index].text;
391
			option.value = src_selbox.options[index].value;
392
			dst_selbox.add(option, null);
393
		}
394
	}
395
}
396
397
function move_selected(srcid, dstid) {
398
	copy_selected(srcid, dstid);
399
	remove_selected(srcid);
400
}
401
402
function presubmit() {
403
	clear_selected('notgroups');
404
	setall_selected('groups');
405
}
406
407 c9794c06 Ermal
function usercertClicked(obj) {
408
	if (obj.checked) {
409
		document.getElementById("usercertchck").style.display="none";
410
		document.getElementById("usercert").style.display="";
411
	} else {
412
		document.getElementById("usercert").style.display="none";
413
		document.getElementById("usercertchck").style.display="";
414
	}
415
}
416
417
function sshkeyClicked(obj) {
418
        if (obj.checked) {
419
                document.getElementById("sshkeychck").style.display="none";
420
                document.getElementById("sshkey").style.display="";
421
        } else {
422
                document.getElementById("sshkey").style.display="none";
423
                document.getElementById("sshkeychck").style.display="";
424
        }
425
}
426 6b07c15a Matthew Grooms
//-->
427
</script>
428 1df17ba9 Scott Ullrich
<?php
429 45ee90ed Matthew Grooms
	if ($input_errors)
430
		print_input_errors($input_errors);
431
	if ($savemsg)
432
		print_info_box($savemsg);
433 1df17ba9 Scott Ullrich
?>
434 45ee90ed Matthew Grooms
<table width="100%" border="0" cellpadding="0" cellspacing="0">
435
	<tr>
436 e30001cf Matthew Grooms
		<td>
437 45ee90ed Matthew Grooms
		<?php
438
			$tab_array = array();
439
			$tab_array[] = array(gettext("Users"), true, "system_usermanager.php");
440 6b07c15a Matthew Grooms
			$tab_array[] = array(gettext("Groups"), false, "system_groupmanager.php");
441 45ee90ed Matthew Grooms
			$tab_array[] = array(gettext("Settings"), false, "system_usermanager_settings.php");
442 d799787e Matthew Grooms
			$tab_array[] = array(gettext("Servers"), false, "system_authservers.php");
443 45ee90ed Matthew Grooms
			display_top_tabs($tab_array);
444
		?>
445
		</td>
446
	</tr>
447
	<tr>
448 e30001cf Matthew Grooms
		<td id="mainarea">
449
			<div class="tabcont">
450
451
				<?php if ($_GET['act'] == "new" || $_GET['act'] == "edit" || $input_errors): ?>
452
453
				<form action="system_usermanager.php" method="post" name="iform" id="iform" onsubmit="presubmit()">
454
					<table width="100%" border="0" cellpadding="6" cellspacing="0">
455
						<?php
456
							$ro = "";
457
							if ($pconfig['utype'] == "system")
458
								$ro = "readonly = \"readonly\"";
459
						?>
460
	                    <tr>
461
	                        <td width="22%" valign="top" class="vncell"><?=gettext("Defined by");?></td>
462
	                        <td width="78%" class="vtable">
463 93458966 Carlos Eduardo Ramos
	                            <strong><?=strtoupper($pconfig['utype']);?></strong>
464 e30001cf Matthew Grooms
								<input name="utype" type="hidden" value="<?=$pconfig['utype']?>"/>
465
	                        </td>
466
	                    </tr>
467 b4bfd25d sullrich
						<tr>
468 2afddcb1 sullrich
							<td width="22%" valign="top" class="vncell"><?=gettext("Disabled");?></td>
469 b4bfd25d sullrich
							<td width="78%" class="vtable">
470
								<input name="disabled" type="checkbox" id="disabled" <?php if($pconfig['disabled']) echo "CHECKED"; ?>>
471
							</td>
472
						</tr>
473 e30001cf Matthew Grooms
						<tr>
474
							<td width="22%" valign="top" class="vncellreq"><?=gettext("Username");?></td>
475
							<td width="78%" class="vtable">
476
								<input name="usernamefld" type="text" class="formfld user" id="usernamefld" size="20" value="<?=htmlspecialchars($pconfig['usernamefld']);?>" <?=$ro;?>/>
477
								<input name="oldusername" type="hidden" id="oldusername" value="<?=htmlspecialchars($pconfig['usernamefld']);?>" />
478
							</td>
479
						</tr>
480
						<tr>
481
							<td width="22%" valign="top" class="vncellreq" rowspan="2"><?=gettext("Password");?></td>
482
							<td width="78%" class="vtable">
483
								<input name="passwordfld1" type="password" class="formfld pwd" id="passwordfld1" size="20" value="" />
484
							</td>
485
						</tr>
486
						<tr>
487
							<td width="78%" class="vtable">
488
								<input name="passwordfld2" type="password" class="formfld pwd" id="passwordfld2" size="20" value="" />&nbsp;<?= gettext("(confirmation)"); ?>
489
							</td>
490
						</tr>
491
						<tr>
492
							<td width="22%" valign="top" class="vncell"><?=gettext("Full name");?></td>
493
							<td width="78%" class="vtable">
494
								<input name="fullname" type="text" class="formfld unknown" id="fullname" size="20" value="<?=htmlspecialchars($pconfig['fullname']);?>" <?=$ro;?>/>
495
								<br/>
496
								<?=gettext("User's full name, for your own information only");?>
497
							</td>
498
						</tr>
499 0092b3bd mgrooms
						<tr>
500 b79454a7 Carlos Eduardo Ramos
							<td width="22%" valign="top" class="vncell"><?=gettext("Expiration date"); ?></td>
501 0092b3bd mgrooms
							<td width="78%" class="vtable">
502
								<input name="expires" type="text" class="formfld unknown" id="expires" size="10" value="<?=$pconfig['expires'];?>">
503
								<a href="javascript:NewCal('expires','mmddyyyy')">
504 2b33f342 Renato Botelho
									<img src="/themes/<?php echo $g['theme']; ?>/images/icons/icon_cal.gif" width="16" height="16" border="0" alt="<?=gettext("Pick a date");?>">
505 0092b3bd mgrooms
								</a>
506
								<br>
507 b79454a7 Carlos Eduardo Ramos
								<span class="vexpl"><?=gettext("Leave blank if the account shouldn't expire, otherwise enter the expiration date in the following format: mm/dd/yyyy"); ?></span></td>
508 0092b3bd mgrooms
						</tr>
509 e30001cf Matthew Grooms
						<tr>
510
							<td width="22%" valign="top" class="vncell"><?=gettext("Group Memberships");?></td>
511
							<td width="78%" class="vtable" align="center">
512
								<table class="tabcont" width="100%" border="0" cellpadding="0" cellspacing="0">
513
									<tr>
514
										<td align="center" width="50%">
515 b79454a7 Carlos Eduardo Ramos
											<strong><?=gettext("Not Member Of"); ?></strong><br/>
516 e30001cf Matthew Grooms
											<br/>
517
											<select size="10" style="width: 75%" name="notgroups[]" class="formselect" id="notgroups" onChange="clear_selected('groups')" multiple>
518
												<?php
519
													foreach ($config['system']['group'] as $group):
520
														if ($group['gid'] == 1998) /* all users group */
521
															continue;
522
														if (in_array($group['name'],$pconfig['groups']))
523
															continue;
524
												?>
525
												<option value="<?=$group['name'];?>" <?=$selected;?>>
526
													<?=htmlspecialchars($group['name']);?>
527
												</option>
528
												<?php endforeach; ?>
529
											</select>
530
											<br/>
531
										</td>
532
										<td>
533
											<br/>
534
											<a href="javascript:move_selected('notgroups','groups')">
535 b79454a7 Carlos Eduardo Ramos
												<img src="/themes/<?= $g['theme'];?>/images/icons/icon_right.gif" title="<?=gettext("Add Groups"); ?>" alt="<?=gettext("Add Groups"); ?>" width="17" height="17" border="0" />
536 e30001cf Matthew Grooms
											</a>
537
											<br/><br/>
538
											<a href="javascript:move_selected('groups','notgroups')">
539 b79454a7 Carlos Eduardo Ramos
												<img src="/themes/<?= $g['theme'];?>/images/icons/icon_left.gif" title="<?=gettext("Remove Groups"); ?>" alt="<?=gettext("Remove Groups"); ?>" width="17" height="17" border="0" />
540 e30001cf Matthew Grooms
											</a>
541
										</td>
542
										<td align="center" width="50%">
543 b79454a7 Carlos Eduardo Ramos
											<strong><?=gettext("Member Of"); ?></strong><br/>
544 e30001cf Matthew Grooms
											<br/>
545
											<select size="10" style="width: 75%" name="groups[]" class="formselect" id="groups" onChange="clear_selected('nogroups')" multiple>
546
												<?php
547
													foreach ($config['system']['group'] as $group):
548
														if ($group['gid'] == 1998) /* all users group */
549
															continue;
550
														if (!in_array($group['name'],$pconfig['groups']))
551
															continue;
552
												?>
553
												<option value="<?=$group['name'];?>">
554
													<?=htmlspecialchars($group['name']);?>
555
												</option>
556
												<?php endforeach; ?>
557
											</select>
558
											<br/>
559
										</td>
560
									</tr>
561
								</table>
562
								<?=gettext("Hold down CTRL (pc)/COMMAND (mac) key to select multiple items");?>
563
							</td>
564
						</tr>
565
566
						<?php if ($pconfig['uid']): ?>
567
568
						<tr>
569
							<td width="22%" valign="top" class="vncell"><?=gettext("Effective Privileges");?></td>
570
							<td width="78%" class="vtable">
571
								<table class="tabcont" width="100%" border="0" cellpadding="0" cellspacing="0">
572
									<tr>
573
										<td width="20%" class="listhdrr"><?=gettext("Inherited From");?></td>
574
										<td width="30%" class="listhdrr"><?=gettext("Name");?></td>
575
										<td width="40%" class="listhdrr"><?=gettext("Description");?></td>
576
										<td class="list"></td>
577
									</tr>
578
									<?php
579
											
580
										$privdesc = get_user_privdesc($a_user[$id]);
581
										if(is_array($privdesc)):
582
											$i = 0;
583
											foreach ($privdesc as $priv):
584
											$group = false;
585
											if ($priv['group'])
586
												$group = $priv['group'];
587
									?>
588
									<tr>
589
										<td class="listlr"><?=$group;?></td>
590
										<td class="listr">
591
											<?=htmlspecialchars($priv['name']);?>
592
										</td>
593
										<td class="listbg">
594
												<?=htmlspecialchars($priv['descr']);?>
595
										</td>
596
										<td valign="middle" nowrap class="list">
597
											<?php if (!$group): ?>
598
											<a href="system_usermanager.php?act=delpriv&id=<?=$id?>&privid=<?=$i;?>" onclick="return confirm('<?=gettext("Do you really want to delete this privilege?");?>')">
599
												<img src="/themes/<?= $g['theme']; ?>/images/icons/icon_x.gif" width="17" height="17" border="0" alt="" />
600
											</a>
601
											<?php endif; ?>
602
										</td>
603
									</tr>
604
									<?php
605
											/* can only delete user priv indexes */
606
											if (!$group)
607
												$i++;
608
											endforeach;
609
										endif;
610
									?>
611
									<tr>
612
										<td class="list" colspan="3"></td>
613
										<td class="list">
614
											<a href="system_usermanager_addprivs.php?userid=<?=$id?>">
615
												<img src="/themes/<?= $g['theme']; ?>/images/icons/icon_plus.gif" width="17" height="17" border="0" alt="" />
616
											</a>
617
										</td>
618
									</tr>
619
								</table>
620
							</td>
621
						</tr>
622
						<tr>
623
							<td width="22%" valign="top" class="vncell"><?=gettext("User Certificates");?></td>
624
							<td width="78%" class="vtable">
625
								<table class="tabcont" width="100%" border="0" cellpadding="0" cellspacing="0">
626
									<tr>
627
										<td width="45%" class="listhdrr"><?=gettext("Name");?></td>
628
										<td width="45%" class="listhdrr"><?=gettext("CA");?></td>
629
										<td class="list"></td>
630
									</tr>
631
									<?php
632
										
633
										$a_cert = $a_user[$id]['cert'];
634
										if(is_array($a_cert)):
635
											$i = 0;
636
											foreach ($a_cert as $cert):
637
						                        $ca = lookup_ca($cert['caref']);
638
									?>
639
									<tr>
640
										<td class="listlr">
641
											<?=htmlspecialchars($cert['name']);?>
642
										</td>
643
										<td class="listr">
644
											<?=htmlspecialchars($ca['name']);?>
645
										</td>
646
										<td valign="middle" nowrap class="list">
647
											<a href="system_usermanager.php?act=expckey&id=<?=$id;?>&certid=<?=$i;?>">
648 b79454a7 Carlos Eduardo Ramos
												<img src="/themes/<?= $g['theme'];?>/images/icons/icon_down.gif" title="<?=gettext("export private key"); ?>" alt="<?=gettext("export private key"); ?>" width="17" height="17" border="0" />
649 e30001cf Matthew Grooms
											</a>
650
											<a href="system_usermanager.php?act=expcert&id=<?=$id;?>&certid=<?=$i;?>">
651 b79454a7 Carlos Eduardo Ramos
												<img src="/themes/<?= $g['theme'];?>/images/icons/icon_down.gif" title="<?=gettext("export cert"); ?>" alt="<?=gettext("export cert"); ?>" width="17" height="17" border="0" />
652 e30001cf Matthew Grooms
											</a>
653
											<a href="system_usermanager.php?act=delcert&id=<?=$id?>&certid=<?=$i;?>" onclick="return confirm('<?=gettext("Do you really want to delete this certificate?");?>')">
654 2b33f342 Renato Botelho
												<img src="/themes/<?= $g['theme']; ?>/images/icons/icon_x.gif" width="17" height="17" border="0" alt="<?=gettext("delete cert");?>" />
655 e30001cf Matthew Grooms
											</a>
656
										</td>
657
									</tr>
658
									<?php
659
												$i++;
660
											endforeach;
661
										endif;
662
									?>
663
									<tr>
664
										<td class="list" colspan="2"></td>
665
										<td class="list">
666
											<a href="system_usermanager_addcert.php?userid=<?=$id?>">
667
												<img src="/themes/<?= $g['theme']; ?>/images/icons/icon_plus.gif" width="17" height="17" border="0" alt="" />
668
											</a>
669
										</td>
670
									</tr>
671
								</table>
672
							</td>
673
						</tr>
674 45ee90ed Matthew Grooms
675 c9794c06 Ermal
						<?php else : ?>
676
						<?php 	if (is_array($config['system']['ca']) && count($config['system']['ca']) > 0): ?>
677
						<?php		$i = 0; foreach( $config['system']['ca'] as $ca) {
678
                                                                        	if (!$ca['prv'])
679
                                                                                	continue;
680
										$i++;
681
									}
682
						?>
683
684
						<tr id="usercertchck" name="usercertchck" >
685
							<td width="22%" valign="top" class="vncell"><?=gettext("Certificate");?></td>
686
                                                	<td width="78%" class="vtable">
687 b79454a7 Carlos Eduardo Ramos
							<input type="checkbox" onClick="javascript:usercertClicked(this)"> <?=gettext("Click to create a user certificate."); ?>
688 c9794c06 Ermal
							</td>
689
						</tr>
690
691
						<?php		if ($i > 0): ?>
692
693
						<tr id="usercert" name="usercert" style="display:none">
694
							<td width="22%" valign="top" class="vncell"><?=gettext("Certificate");?></td>
695
                                                	<td width="78%" class="vtable">
696 d0412d85 Ermal
							<table width="100%" border="0" cellpadding="6" cellspacing="0">
697 c9794c06 Ermal
							<tr>
698
                                                        	<td width="22%" valign="top" class="vncellreq"><?=gettext("Descriptive name");?></td>
699
                                                        	<td width="78%" class="vtable">
700
                                                                	<input name="name" type="text" class="formfld unknown" id="name" size="20" value="<?=htmlspecialchars($pconfig['name']);?>"/>
701
                                                        	</td>
702
                                                	</tr>
703
                                                	<tr>
704
                                                        	<td width="22%" valign="top" class="vncellreq"><?=gettext("Certificate authority");?></td>
705
                                                        	<td width="78%" class="vtable">
706
                                                                	<select name='caref' id='caref' class="formselect" onChange='internalca_change()'>
707
                                                                <?php
708
                                                                        foreach( $config['system']['ca'] as $ca):
709
                                                                        if (!$ca['prv'])
710
                                                                                continue;
711
                                                                ?>
712
                                                                        <option value="<?=$ca['refid'];?>"><?=$ca['name'];?></option>
713
                                                                <?php endforeach; ?>
714
                                                                	</select>
715
                                                        	</td>
716
                                                	</tr>
717
                                                	<tr>
718
                                                        	<td width="22%" valign="top" class="vncellreq"><?=gettext("Key length");?></td>
719
                                                        	<td width="78%" class="vtable">
720
                                                                	<select name='keylen' class="formselect">
721
                                                                <?php
722 3b4b9ff3 Ermal
									$cert_keylens = array( "2048", "512", "1024", "4096");
723 c9794c06 Ermal
                                                                        foreach( $cert_keylens as $len):
724
                                                                ?>
725
                                                                        <option value="<?=$len;?>"><?=$len;?></option>
726
                                                                <?php endforeach; ?>
727
                                                                	</select>
728
                                                                	bits
729
                                                        	</td>
730
                                                	</tr>
731
							<tr>
732
                                                        	<td width="22%" valign="top" class="vncellreq"><?=gettext("Lifetime");?></td>
733
                                                        	<td width="78%" class="vtable">
734
                                                                	<input name="lifetime" type="text" class="formfld unknown" id="lifetime" size="5" value="<?=htmlspecialchars($pconfig['lifetime']);?>"/>days
735
                                                        	</td>
736
                                                	</tr>
737
						</table>
738
							</td>
739
						</tr>
740
741
						<?php 	endif; endif; ?>
742 e30001cf Matthew Grooms
						<?php endif; ?>
743 45ee90ed Matthew Grooms
744 c9794c06 Ermal
						<tr id="sshkeychck" name="sshkeychck" >
745
                                                        <td width="22%" valign="top" class="vncell"><?=gettext("Authorized keys");?></td>
746
                                                        <td width="78%" class="vtable">
747 b79454a7 Carlos Eduardo Ramos
                                                        <input type="checkbox" onClick="javascript:sshkeyClicked(this)"> <?=gettext("Click to paste an authorized key."); ?>
748 c9794c06 Ermal
                                                        </td>
749
                                                </tr>
750
						<tr id="sshkey" name="sshkey" style="display:none">
751 e30001cf Matthew Grooms
							<td width="22%" valign="top" class="vncell"><?=gettext("Authorized keys");?></td>
752
							<td width="78%" class="vtable">
753
								<textarea name="authorizedkeys" cols="65" rows="7" id="authorizedkeys" class="formfld_cert" wrap="off"><?=htmlspecialchars($pconfig['authorizedkeys']);?></textarea>
754
								<br/>
755
								<?=gettext("Paste an authorized keys file here.");?>
756
							</td>
757
						</tr>
758 ddd1fb7f jim-p
						<tr id="ipsecpskrow" name="ipsecpskrow">
759
							<td width="22%" valign="top" class="vncell"><?=gettext("IPsec Pre-Shared Key");?></td>
760
							<td width="78%" class="vtable">
761
								<input name="ipsecpsk" type="text" class="formfld unknown" id="ipsecpsk" size="65" value="<?=htmlspecialchars($pconfig['ipsecpsk']);?>">
762
							</td>
763
						</tr>
764 e30001cf Matthew Grooms
						<tr>
765
							<td width="22%" valign="top">&nbsp;</td>
766
							<td width="78%">
767 6e707e77 Vinicius Coque
								<input id="submit" name="save" type="submit" class="formbtn" value="<?=gettext("Save");?>" />
768 e30001cf Matthew Grooms
								<?php if (isset($id) && $a_user[$id]): ?>
769
								<input name="id" type="hidden" value="<?=$id;?>" />
770
								<?php endif;?>
771
							</td>
772
						</tr>
773
					</table>
774
				</form>
775
776
				<?php else: ?>
777
778
				<table width="100%" border="0" cellpadding="0" cellspacing="0">
779 45ee90ed Matthew Grooms
					<tr>
780 b79454a7 Carlos Eduardo Ramos
						<td width="25%" class="listhdrr"><?=gettext("Username"); ?></td>
781
						<td width="25%" class="listhdrr"><?=gettext("Full name"); ?></td>
782
						<td width="5%" class="listhdrr"><?=gettext("Disabled"); ?></td>
783
						<td width="25%" class="listhdrr"><?=gettext("Groups"); ?></td>
784 e30001cf Matthew Grooms
						<td width="10%" class="list"></td>
785 45ee90ed Matthew Grooms
					</tr>
786 e30001cf Matthew Grooms
					<?php
787
						$i = 0;
788
						foreach($a_user as $userent):
789
					?>
790
					<tr ondblclick="document.location='system_usermanager.php?act=edit&id=<?=$i;?>'">
791
						<td class="listlr">
792
							<table border="0" cellpadding="0" cellspacing="0">
793 6b07c15a Matthew Grooms
								<tr>
794 e30001cf Matthew Grooms
									<td align="left" valign="center">
795
										<?php
796
											if($userent['scope'] != "user")
797
												$usrimg = "/themes/{$g['theme']}/images/icons/icon_system-user-grey.png";
798
											else
799
												$usrimg = "/themes/{$g['theme']}/images/icons/icon_system-user.png";
800
										?>
801 b79454a7 Carlos Eduardo Ramos
										<img src="<?=$usrimg;?>" alt="<?=gettext("User"); ?>" title="<?=gettext("User"); ?>" border="0" height="16" width="16" />
802 6b07c15a Matthew Grooms
									</td>
803 e30001cf Matthew Grooms
									<td align="left" valign="middle">
804
										<?=htmlspecialchars($userent['name']);?>
805 6b07c15a Matthew Grooms
									</td>
806
								</tr>
807
							</table>
808 45ee90ed Matthew Grooms
						</td>
809 e30001cf Matthew Grooms
						<td class="listr"><?=htmlspecialchars($userent['fullname']);?>&nbsp;</td>
810 b4bfd25d sullrich
						<td class="listr"><?php if(isset($userent['disabled'])) echo "*"; ?></td>
811 e30001cf Matthew Grooms
						<td class="listbg">
812
								<?=implode(",",local_user_get_groups($userent));?>
813
							&nbsp;
814 45ee90ed Matthew Grooms
						</td>
815 e30001cf Matthew Grooms
						<td valign="middle" nowrap class="list">
816
							<a href="system_usermanager.php?act=edit&id=<?=$i;?>">
817 b79454a7 Carlos Eduardo Ramos
								<img src="/themes/<?= $g['theme'];?>/images/icons/icon_e.gif" title="<?=gettext("edit user"); ?>" alt="<?=gettext("edit user"); ?>" width="17" height="17" border="0" />
818 e30001cf Matthew Grooms
							</a>
819
							<?php if($userent['scope'] != "system"): ?>
820
							&nbsp;
821
							<a href="system_usermanager.php?act=deluser&id=<?=$i;?>" onclick="return confirm('<?=gettext("Do you really want to delete this User?");?>')">
822 b79454a7 Carlos Eduardo Ramos
								<img src="/themes/<?= $g['theme'];?>/images/icons/icon_x.gif" title="<?=gettext("delete user"); ?>" alt="<?=gettext("delete user"); ?>" width="17" height="17" border="0" />
823 e30001cf Matthew Grooms
							</a>
824
							<?php endif; ?>
825 58fdb8ad Matthew Grooms
						</td>
826
					</tr>
827 e30001cf Matthew Grooms
					<?php
828
							$i++;
829
						endforeach;
830
					?>
831 fb1266d3 Matthew Grooms
					<tr>
832 b4bfd25d sullrich
						<td class="list" colspan="4"></td>
833 e30001cf Matthew Grooms
						<td class="list">
834
							<a href="system_usermanager.php?act=new">
835 b79454a7 Carlos Eduardo Ramos
								<img src="/themes/<?= $g['theme'];?>/images/icons/icon_plus.gif" title="<?=gettext("add user"); ?>" alt="<?=gettext("add user"); ?>" width="17" height="17" border="0" />
836 e30001cf Matthew Grooms
							</a>
837 fb1266d3 Matthew Grooms
						</td>
838
					</tr>
839 45ee90ed Matthew Grooms
					<tr>
840 b4bfd25d sullrich
						<td colspan="4">
841 e30001cf Matthew Grooms
							<p>
842 5b1dcebf Vinicius Coque
								<?=gettext("Additional webConfigurator users can be added here.
843
								User permissions can be assigned directly or inherited from group memberships.
844
								An icon that appears grey indicates that it is a system defined object. 
845
								Some system object properties can be modified but they cannot be deleted."); ?>
846 e30001cf Matthew Grooms
							</p>
847 45ee90ed Matthew Grooms
						</td>
848
					</tr>
849
				</table>
850
851 e30001cf Matthew Grooms
				<?php endif; ?>
852 45ee90ed Matthew Grooms
853 e30001cf Matthew Grooms
			</div>
854 45ee90ed Matthew Grooms
		</td>
855
	</tr>
856 1df17ba9 Scott Ullrich
</table>
857 45ee90ed Matthew Grooms
<?php include("fend.inc");?>
858
</body>
859
860 1df17ba9 Scott Ullrich
<?php
861
862 45ee90ed Matthew Grooms
	// end admin user code
863
864
} else {
865
866
	// start normal user code
867 6b07c15a Matthew Grooms
868 b79454a7 Carlos Eduardo Ramos
	$pgtitle = array(gettext("System"),gettext("User Password"));
869 45ee90ed Matthew Grooms
870
	if (isset($_POST['save'])) {
871
		unset($input_errors);
872
873
		/* input validation */
874
		$reqdfields = explode(" ", "passwordfld1");
875 76d49f20 Renato Botelho
		$reqdfieldsn = array(gettext("Password"));
876 1df17ba9 Scott Ullrich
877 45ee90ed Matthew Grooms
		do_input_validation($_POST, $reqdfields, $reqdfieldsn, &$input_errors);
878 1df17ba9 Scott Ullrich
879 45ee90ed Matthew Grooms
		if ($_POST['passwordfld1'] != $_POST['passwordfld2'])
880 b79454a7 Carlos Eduardo Ramos
			$input_errors[] = gettext("The passwords do not match.");
881 1df17ba9 Scott Ullrich
882 45ee90ed Matthew Grooms
		if (!$input_errors) {
883
			// all values are okay --> saving changes
884
			$config['system']['user'][$userindex[$HTTP_SERVER_VARS['AUTH_USER']]]['password'] = crypt(trim($_POST['passwordfld1']));
885 1df17ba9 Scott Ullrich
886 45ee90ed Matthew Grooms
			write_config();
887 683c26cf Vinicius Coque
			$savemsg = gettext("Password successfully changed") . "<br />";
888 45ee90ed Matthew Grooms
		}
889
	}
890
891 4494cf6a Chris Buechler
	/* determine if user is not local to system */
892 45ee90ed Matthew Grooms
	$islocal = false;
893
	foreach($config['system']['user'] as $user) 
894
		if($user['name'] == $_SESSION['Username'])
895
			$islocal = true;
896 fab7ff44 Bill Marquette
?>
897 1df17ba9 Scott Ullrich
898 45ee90ed Matthew Grooms
<body link="#000000" vlink="#000000" alink="#000000" onload="<?= $jsevents["body"]["onload"] ?>">
899 1df17ba9 Scott Ullrich
<?php
900
    include("head.inc");
901 45ee90ed Matthew Grooms
	include("fbegin.inc");
902
	if ($input_errors)
903
		print_input_errors($input_errors);
904
	if ($savemsg)
905
		print_info_box($savemsg);
906
907
	if($islocal == false) {
908 b79454a7 Carlos Eduardo Ramos
		echo gettext("Sorry, you cannot change the password for a LDAP user.");
909 45ee90ed Matthew Grooms
		include("fend.inc");
910
		exit;
911
	}
912 1df17ba9 Scott Ullrich
?>
913 e30001cf Matthew Grooms
<div id="mainarea">
914
	<div class="tabcont">
915
		<form action="system_usermanager.php" method="post" name="iform" id="iform">
916
			<table width="100%" border="0" cellpadding="6" cellspacing="0">
917
				<tr>
918 b79454a7 Carlos Eduardo Ramos
					<td colspan="2" valign="top" class="listtopic"><?=$HTTP_SERVER_VARS['AUTH_USER']?>'s <?=gettext("Password"); ?></td>
919 e30001cf Matthew Grooms
				</tr>
920
				<tr>
921 b79454a7 Carlos Eduardo Ramos
					<td width="22%" valign="top" class="vncell" rowspan="2"><?=gettext("Password"); ?></td>
922 e30001cf Matthew Grooms
					<td width="78%" class="vtable">
923
						<input name="passwordfld1" type="password" class="formfld pwd" id="passwordfld1" size="20" />
924
					</td>
925
				</tr>
926
				<tr>
927
					<td width="78%" class="vtable">
928
						<input name="passwordfld2" type="password" class="formfld pwd" id="passwordfld2" size="20" />
929
						&nbsp;<?=gettext("(confirmation)");?>
930
						<br/>
931
						<span class="vexpl">
932
							<?=gettext("Select a new password");?>
933
						</span>
934
					</td>
935
				</tr>
936
				<tr>
937
					<td width="22%" valign="top">&nbsp;</td>
938
					<td width="78%">
939
						<input name="save" type="submit" class="formbtn" value="<?=gettext("Save");?>" />
940
					</td>
941
				</tr>
942
			</table>
943
		</form>
944
	</div>
945
</div>
946 45ee90ed Matthew Grooms
<?php include("fend.inc");?>
947
</body>
948 82e913df Scott Ullrich
949 1df17ba9 Scott Ullrich
<?php
950
951 6b07c15a Matthew Grooms
} // end of normal user code
952 45ee90ed Matthew Grooms
953
?>