Project

General

Profile

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

    
60
##|+PRIV
61
##|*IDENT=page-system-usermanager
62
##|*NAME=System: User Manager
63
##|*DESCR=Allow access to the 'System: User Manager' page.
64
##|*MATCH=system_usermanager.php*
65
##|-PRIV
66

    
67
require_once("certs.inc");
68
require_once("guiconfig.inc");
69

    
70
// start admin user code
71
if (isset($_POST['userid']) && is_numericint($_POST['userid'])) {
72
	$id = $_POST['userid'];
73
}
74

    
75
if (isset($_GET['userid']) && is_numericint($_GET['userid'])) {
76
	$id = $_GET['userid'];
77
}
78

    
79
if (!isset($config['system']['user']) || !is_array($config['system']['user'])) {
80
	$config['system']['user'] = array();
81
}
82

    
83
$a_user = &$config['system']['user'];
84
$act = $_GET['act'];
85

    
86
if (isset($_SERVER['HTTP_REFERER'])) {
87
	$referer = $_SERVER['HTTP_REFERER'];
88
} else {
89
	$referer = '/system_usermanager.php';
90
}
91

    
92
if (isset($id) && $a_user[$id]) {
93
	$pconfig['usernamefld'] = $a_user[$id]['name'];
94
	$pconfig['descr'] = $a_user[$id]['descr'];
95
	$pconfig['expires'] = $a_user[$id]['expires'];
96
	$pconfig['customsettings'] = isset($a_user[$id]['customsettings']);
97
	$pconfig['webguicss'] = $a_user[$id]['webguicss'];
98
	$pconfig['webguifixedmenu'] = $a_user[$id]['webguifixedmenu'];
99
	$pconfig['webguihostnamemenu'] = $a_user[$id]['webguihostnamemenu'];
100
	$pconfig['dashboardcolumns'] = $a_user[$id]['dashboardcolumns'];
101
	$pconfig['interfacessort'] = isset($a_user[$id]['interfacessort']);
102
	$pconfig['dashboardavailablewidgetspanel'] = isset($a_user[$id]['dashboardavailablewidgetspanel']);
103
	$pconfig['systemlogsfilterpanel'] = isset($a_user[$id]['systemlogsfilterpanel']);
104
	$pconfig['systemlogsmanagelogpanel'] = isset($a_user[$id]['systemlogsmanagelogpanel']);
105
	$pconfig['statusmonitoringsettingspanel'] = isset($a_user[$id]['statusmonitoringsettingspanel']);
106
	$pconfig['webguileftcolumnhyper'] = isset($a_user[$id]['webguileftcolumnhyper']);
107
	$pconfig['pagenamefirst'] = isset($a_user[$id]['pagenamefirst']);
108
	$pconfig['groups'] = local_user_get_groups($a_user[$id]);
109
	$pconfig['utype'] = $a_user[$id]['scope'];
110
	$pconfig['uid'] = $a_user[$id]['uid'];
111
	$pconfig['authorizedkeys'] = base64_decode($a_user[$id]['authorizedkeys']);
112
	$pconfig['priv'] = $a_user[$id]['priv'];
113
	$pconfig['ipsecpsk'] = $a_user[$id]['ipsecpsk'];
114
	$pconfig['disabled'] = isset($a_user[$id]['disabled']);
115
}
116

    
117
if ($_GET['act'] == "deluser") {
118

    
119
	if (!isset($_GET['username']) || !isset($a_user[$id]) || ($_GET['username'] != $a_user[$id]['name'])) {
120
		pfSenseHeader("system_usermanager.php");
121
		exit;
122
	}
123

    
124
	if ($_GET['username'] == $_SESSION['Username']) {
125
		$delete_errors[] = sprintf(gettext("Cannot delete user %s because you are currently logged in as that user."), $_GET['username']);
126
	} else {
127
		conf_mount_rw();
128
		local_user_del($a_user[$id]);
129
		conf_mount_ro();
130
		$userdeleted = $a_user[$id]['name'];
131
		unset($a_user[$id]);
132
		/* Reindex the array to avoid operating on an incorrect index https://redmine.pfsense.org/issues/7733 */
133
		$a_user = array_values($a_user);
134
		write_config();
135
		$savemsg = sprintf(gettext("User %s successfully deleted."), $userdeleted);
136
	}
137
} else if ($act == "new") {
138
	/*
139
	 * set this value cause the text field is read only
140
	 * and the user should not be able to mess with this
141
	 * setting.
142
	 */
143
	$pconfig['utype'] = "user";
144
	$pconfig['lifetime'] = 3650;
145
}
146

    
147
if (isset($_POST['dellall'])) {
148

    
149
	$del_users = $_POST['delete_check'];
150
	$deleted_users = "";
151
	$deleted_count = 0;
152
	$comma = "";
153

    
154
	if (!empty($del_users)) {
155
		foreach ($del_users as $userid) {
156
			if (isset($a_user[$userid]) && $a_user[$userid]['scope'] != "system") {
157
				if ($a_user[$userid]['name'] == $_SESSION['Username']) {
158
					$delete_errors[] = sprintf(gettext("Cannot delete user %s because you are currently logged in as that user."), $a_user[$userid]['name']);
159
				} else {
160
					conf_mount_rw();
161
					$deleted_users = $deleted_users . $comma . $a_user[$userid]['name'];
162
					$comma = ", ";
163
					$deleted_count++;
164
					local_user_del($a_user[$userid]);
165
					conf_mount_ro();
166
					unset($a_user[$userid]);
167
				}
168
			} else {
169
				$delete_errors[] = sprintf(gettext("Cannot delete user %s because it is a system user."), $a_user[$userid]['name']);
170
			}
171
		}
172

    
173
		if ($deleted_count > 0) {
174
			if ($deleted_count == 1) {
175
				$savemsg = sprintf(gettext("User %s successfully deleted."), $deleted_users);
176
			} else {
177
				$savemsg = sprintf(gettext("Users %s successfully deleted."), $deleted_users);
178
			}
179
			/* Reindex the array to avoid operating on an incorrect index https://redmine.pfsense.org/issues/7733 */
180
			$a_user = array_values($a_user);
181
			write_config($savemsg);
182
		}
183
	}
184
}
185

    
186
if ($_POST['act'] == "delcert") {
187

    
188
	if (!$a_user[$id]) {
189
		pfSenseHeader("system_usermanager.php");
190
		exit;
191
	}
192

    
193
	$certdeleted = lookup_cert($a_user[$id]['cert'][$_POST['certid']]);
194
	$certdeleted = $certdeleted['descr'];
195
	unset($a_user[$id]['cert'][$_POST['certid']]);
196
	write_config();
197
	$_POST['act'] = "edit";
198
	$savemsg = sprintf(gettext("Certificate %s association removed."), $certdeleted);
199
}
200

    
201
if ($_POST['act'] == "delprivid") {
202
	$privdeleted = $priv_list[$a_user[$id]['priv'][$_POST['privid']]]['name'];
203
	unset($a_user[$id]['priv'][$_POST['privid']]);
204
	local_user_set($a_user[$id]);
205
	write_config();
206
	$_POST['act'] = "edit";
207
	$savemsg = sprintf(gettext("Privilege %s removed."), $privdeleted);
208
}
209

    
210
if ($_POST['save']) {
211
	unset($input_errors);
212
	$pconfig = $_POST;
213

    
214
	/* input validation */
215
	if (isset($id) && ($a_user[$id])) {
216
		$reqdfields = explode(" ", "usernamefld");
217
		$reqdfieldsn = array(gettext("Username"));
218
	} else {
219
		if (empty($_POST['name'])) {
220
			$reqdfields = explode(" ", "usernamefld passwordfld1");
221
			$reqdfieldsn = array(
222
				gettext("Username"),
223
				gettext("Password"));
224
		} else {
225
			$reqdfields = explode(" ", "usernamefld passwordfld1 name caref keylen lifetime");
226
			$reqdfieldsn = array(
227
				gettext("Username"),
228
				gettext("Password"),
229
				gettext("Descriptive name"),
230
				gettext("Certificate authority"),
231
				gettext("Key length"),
232
				gettext("Lifetime"));
233
		}
234
	}
235

    
236
	do_input_validation($_POST, $reqdfields, $reqdfieldsn, $input_errors);
237

    
238
	if (preg_match("/[^a-zA-Z0-9\.\-_]/", $_POST['usernamefld'])) {
239
		$input_errors[] = gettext("The username contains invalid characters.");
240
	}
241

    
242
	if (strlen($_POST['usernamefld']) > 16) {
243
		$input_errors[] = gettext("The username is longer than 16 characters.");
244
	}
245

    
246
	if (($_POST['passwordfld1']) && ($_POST['passwordfld1'] != $_POST['passwordfld2'])) {
247
		$input_errors[] = gettext("The passwords do not match.");
248
	}
249

    
250
	if (isset($_POST['ipsecpsk']) && !preg_match('/^[[:ascii:]]*$/', $_POST['ipsecpsk'])) {
251
		$input_errors[] = gettext("IPsec Pre-Shared Key contains invalid characters.");
252
	}
253

    
254
	/* Check the POSTed groups to ensure they are valid and exist */
255
	if (is_array($_POST['groups'])) {
256
		foreach ($_POST['groups'] as $newgroup) {
257
			if (empty(getGroupEntry($newgroup))) {
258
				$input_errors[] = gettext("One or more invalid groups was submitted.");
259
			}
260
		}
261
	}
262

    
263
	if (isset($id) && $a_user[$id]) {
264
		$oldusername = $a_user[$id]['name'];
265
	} else {
266
		$oldusername = "";
267
	}
268
	/* make sure this user name is unique */
269
	if (!$input_errors) {
270
		foreach ($a_user as $userent) {
271
			if ($userent['name'] == $_POST['usernamefld'] && $oldusername != $_POST['usernamefld']) {
272
				$input_errors[] = gettext("Another entry with the same username already exists.");
273
				break;
274
			}
275
		}
276
	}
277
	/* also make sure it is not reserved */
278
	if (!$input_errors) {
279
		$system_users = explode("\n", file_get_contents("/etc/passwd"));
280
		foreach ($system_users as $s_user) {
281
			$ent = explode(":", $s_user);
282
			if ($ent[0] == $_POST['usernamefld'] && $oldusername != $_POST['usernamefld']) {
283
				$input_errors[] = gettext("That username is reserved by the system.");
284
				break;
285
			}
286
		}
287
	}
288

    
289
	/*
290
	 * Check for a valid expiration date if one is set at all (valid means,
291
	 * DateTime puts out a time stamp so any DateTime compatible time
292
	 * format may be used. to keep it simple for the enduser, we only
293
	 * claim to accept MM/DD/YYYY as inputs. Advanced users may use inputs
294
	 * like "+1 day", which will be converted to MM/DD/YYYY based on "now".
295
	 * Otherwise such an entry would lead to an invalid expiration data.
296
	 */
297
	if ($_POST['expires']) {
298
		try {
299
			$expdate = new DateTime($_POST['expires']);
300
			//convert from any DateTime compatible date to MM/DD/YYYY
301
			$_POST['expires'] = $expdate->format("m/d/Y");
302
		} catch (Exception $ex) {
303
			$input_errors[] = gettext("Invalid expiration date format; use MM/DD/YYYY instead.");
304
		}
305
	}
306

    
307
	if (!empty($_POST['name'])) {
308
		$ca = lookup_ca($_POST['caref']);
309
		if (!$ca) {
310
			$input_errors[] = gettext("Invalid internal Certificate Authority") . "\n";
311
		}
312
	}
313

    
314
	if (!$input_errors) {
315

    
316
		conf_mount_rw();
317
		$userent = array();
318
		if (isset($id) && $a_user[$id]) {
319
			$userent = $a_user[$id];
320
		}
321

    
322
		isset($_POST['utype']) ? $userent['scope'] = $_POST['utype'] : $userent['scope'] = "system";
323

    
324
		/* the user name was modified */
325
		if (!empty($_POST['oldusername']) && ($_POST['usernamefld'] <> $_POST['oldusername'])) {
326
			$_SERVER['REMOTE_USER'] = $_POST['usernamefld'];
327
			local_user_del($userent);
328
		}
329

    
330
		/* the user password was modified */
331
		if ($_POST['passwordfld1']) {
332
			local_user_set_password($userent, $_POST['passwordfld1']);
333
		}
334

    
335
		/* only change description if sent */
336
		if (isset($_POST['descr'])) {
337
			$userent['descr'] = $_POST['descr'];
338
		}
339

    
340
		$userent['name'] = $_POST['usernamefld'];
341
		$userent['expires'] = $_POST['expires'];
342
		$userent['dashboardcolumns'] = $_POST['dashboardcolumns'];
343
		$userent['authorizedkeys'] = base64_encode($_POST['authorizedkeys']);
344
		$userent['ipsecpsk'] = $_POST['ipsecpsk'];
345

    
346
		if ($_POST['disabled']) {
347
			$userent['disabled'] = true;
348
		} else {
349
			unset($userent['disabled']);
350
		}
351

    
352
		if ($_POST['customsettings']) {
353
			$userent['customsettings'] = true;
354
		} else {
355
			unset($userent['customsettings']);
356
		}
357

    
358
		if ($_POST['webguicss']) {
359
			$userent['webguicss'] = $_POST['webguicss'];
360
		} else {
361
			unset($userent['webguicss']);
362
		}
363

    
364
		if ($_POST['webguifixedmenu']) {
365
			$userent['webguifixedmenu'] = $_POST['webguifixedmenu'];
366
		} else {
367
			unset($userent['webguifixedmenu']);
368
		}
369

    
370
		if ($_POST['webguihostnamemenu']) {
371
			$userent['webguihostnamemenu'] = $_POST['webguihostnamemenu'];
372
		} else {
373
			unset($userent['webguihostnamemenu']);
374
		}
375

    
376
		if ($_POST['interfacessort']) {
377
			$userent['interfacessort'] = true;
378
		} else {
379
			unset($userent['interfacessort']);
380
		}
381

    
382
		if ($_POST['dashboardavailablewidgetspanel']) {
383
			$userent['dashboardavailablewidgetspanel'] = true;
384
		} else {
385
			unset($userent['dashboardavailablewidgetspanel']);
386
		}
387

    
388
		if ($_POST['systemlogsfilterpanel']) {
389
			$userent['systemlogsfilterpanel'] = true;
390
		} else {
391
			unset($userent['systemlogsfilterpanel']);
392
		}
393

    
394
		if ($_POST['systemlogsmanagelogpanel']) {
395
			$userent['systemlogsmanagelogpanel'] = true;
396
		} else {
397
			unset($userent['systemlogsmanagelogpanel']);
398
		}
399

    
400
		if ($_POST['statusmonitoringsettingspanel']) {
401
			$userent['statusmonitoringsettingspanel'] = true;
402
		} else {
403
			unset($userent['statusmonitoringsettingspanel']);
404
		}
405

    
406
		if ($_POST['webguileftcolumnhyper']) {
407
			$userent['webguileftcolumnhyper'] = true;
408
		} else {
409
			unset($userent['webguileftcolumnhyper']);
410
		}
411

    
412
		if ($_POST['pagenamefirst']) {
413
			$userent['pagenamefirst'] = true;
414
		} else {
415
			unset($userent['pagenamefirst']);
416
		}
417

    
418
		if (isset($id) && $a_user[$id]) {
419
			$a_user[$id] = $userent;
420
		} else {
421
			if (!empty($_POST['name'])) {
422
				$cert = array();
423
				$cert['refid'] = uniqid();
424
				$userent['cert'] = array();
425

    
426
				$cert['descr'] = $_POST['name'];
427

    
428
				$subject = cert_get_subject_array($ca['crt']);
429

    
430
				$dn = array(
431
					'countryName' => $subject[0]['v'],
432
					'stateOrProvinceName' => $subject[1]['v'],
433
					'localityName' => $subject[2]['v'],
434
					'organizationName' => $subject[3]['v'],
435
					'emailAddress' => $subject[4]['v'],
436
					'commonName' => $userent['name']);
437

    
438
				cert_create($cert, $_POST['caref'], $_POST['keylen'],
439
					(int)$_POST['lifetime'], $dn);
440

    
441
				if (!is_array($config['cert'])) {
442
					$config['cert'] = array();
443
				}
444
				$config['cert'][] = $cert;
445
				$userent['cert'][] = $cert['refid'];
446
			}
447
			$userent['uid'] = $config['system']['nextuid']++;
448
			/* Add the user to All Users group. */
449
			foreach ($config['system']['group'] as $gidx => $group) {
450
				if ($group['name'] == "all") {
451
					if (!is_array($config['system']['group'][$gidx]['member'])) {
452
						$config['system']['group'][$gidx]['member'] = array();
453
					}
454
					$config['system']['group'][$gidx]['member'][] = $userent['uid'];
455
					break;
456
				}
457
			}
458

    
459
			$a_user[] = $userent;
460
		}
461

    
462
		/* Add user to groups so PHP can see the memberships properly or else the user's shell account does not get proper permissions (if applicable) See #5152. */
463
		local_user_set_groups($userent, $_POST['groups']);
464
		local_user_set($userent);
465
		/* Add user to groups again to ensure they are set everywhere, otherwise the user may not appear to be a member of the group. See commit:5372d26d9d25d751d16865ed9d46869d3b0ec5e1. */
466
		local_user_set_groups($userent, $_POST['groups']);
467
		write_config();
468

    
469
		if (is_dir("/etc/inc/privhooks")) {
470
			run_plugins("/etc/inc/privhooks");
471
		}
472

    
473
		conf_mount_ro();
474

    
475
		pfSenseHeader("system_usermanager.php");
476
	}
477
}
478

    
479
function build_priv_table() {
480
	global $a_user, $id;
481

    
482
	$privhtml = '<div class="table-responsive">';
483
	$privhtml .=	'<table class="table table-striped table-hover table-condensed">';
484
	$privhtml .=		'<thead>';
485
	$privhtml .=			'<tr>';
486
	$privhtml .=				'<th>' . gettext('Inherited from') . '</th>';
487
	$privhtml .=				'<th>' . gettext('Name') . '</th>';
488
	$privhtml .=				'<th>' . gettext('Description') . '</th>';
489
	$privhtml .=				'<th>' . gettext('Action') . '</th>';
490
	$privhtml .=			'</tr>';
491
	$privhtml .=		'</thead>';
492
	$privhtml .=		'<tbody>';
493

    
494
	$i = 0;
495

    
496
	foreach (get_user_privdesc($a_user[$id]) as $priv) {
497
		$group = false;
498
		if ($priv['group']) {
499
			$group = $priv['group'];
500
		}
501

    
502
		$privhtml .=		'<tr>';
503
		$privhtml .=			'<td>' . htmlspecialchars($priv['group']) . '</td>';
504
		$privhtml .=			'<td>' . htmlspecialchars($priv['name']) . '</td>';
505
		$privhtml .=			'<td>' . htmlspecialchars($priv['descr']) . '</td>';
506
		$privhtml .=			'<td>';
507
		if (!$group) {
508
			$privhtml .=			'<a class="fa fa-trash no-confirm icon-pointer" title="' . gettext('Delete Privilege') . '" id="delprivid' . $i . '"></a>';
509
		}
510

    
511
		$privhtml .=			'</td>';
512
		$privhtml .=		'</tr>';
513

    
514
		if (!$group) {
515
			$i++;
516
		}
517
	}
518

    
519
	$privhtml .=		'</tbody>';
520
	$privhtml .=	'</table>';
521
	$privhtml .= '</div>';
522

    
523
	$privhtml .= '<nav class="action-buttons">';
524
	$privhtml .=	'<a href="system_usermanager_addprivs.php?userid=' . $id . '" class="btn btn-success"><i class="fa fa-plus icon-embed-btn"></i>' . gettext("Add") . '</a>';
525
	$privhtml .= '</nav>';
526

    
527
	return($privhtml);
528
}
529

    
530
function build_cert_table() {
531
	global $a_user, $id;
532

    
533
	$certhtml = '<div class="table-responsive">';
534
	$certhtml .=	'<table class="table table-striped table-hover table-condensed">';
535
	$certhtml .=		'<thead>';
536
	$certhtml .=			'<tr>';
537
	$certhtml .=				'<th>' . gettext('Name') . '</th>';
538
	$certhtml .=				'<th>' . gettext('CA') . '</th>';
539
	$certhtml .=				'<th></th>';
540
	$certhtml .=			'</tr>';
541
	$certhtml .=		'</thead>';
542
	$certhtml .=		'<tbody>';
543

    
544
	$a_cert = $a_user[$id]['cert'];
545
	if (is_array($a_cert)) {
546
		$i = 0;
547
		foreach ($a_cert as $certref) {
548
			$cert = lookup_cert($certref);
549
			$ca = lookup_ca($cert['caref']);
550
			$revokedstr =	is_cert_revoked($cert) ? '<b> Revoked</b>':'';
551

    
552
			$certhtml .=	'<tr>';
553
			$certhtml .=		'<td>' . htmlspecialchars($cert['descr']) . $revokedstr . '</td>';
554
			$certhtml .=		'<td>' . htmlspecialchars($ca['descr']) . '</td>';
555
			$certhtml .=		'<td>';
556
			$certhtml .=			'<a id="delcert' . $i .'" class="fa fa-trash no-confirm icon-pointer" title="';
557
			$certhtml .=			gettext('Remove this certificate association? (Certificate will not be deleted)') . '"></a>';
558
			$certhtml .=		'</td>';
559
			$certhtml .=	'</tr>';
560
			$i++;
561
		}
562

    
563
	}
564

    
565
	$certhtml .=		'</tbody>';
566
	$certhtml .=	'</table>';
567
	$certhtml .= '</div>';
568

    
569
	$certhtml .= '<nav class="action-buttons">';
570
	$certhtml .=	'<a href="system_certmanager.php?act=new&amp;userid=' . $id . '" class="btn btn-success"><i class="fa fa-plus icon-embed-btn"></i>' . gettext("Add") . '</a>';
571
	$certhtml .= '</nav>';
572

    
573
	return($certhtml);
574
}
575

    
576
$pgtitle = array(gettext("System"), gettext("User Manager"), gettext("Users"));
577
$pglinks = array("", "system_usermanager.php", "system_usermanager.php");
578

    
579
if ($act == "new" || $act == "edit" || $input_errors) {
580
	$pgtitle[] = gettext('Edit');
581
	$pglinks[] = "@self";
582
}
583
include("head.inc");
584

    
585
if ($delete_errors) {
586
	print_input_errors($delete_errors);
587
}
588

    
589
if ($input_errors) {
590
	print_input_errors($input_errors);
591
}
592

    
593
if ($savemsg) {
594
	print_info_box($savemsg, 'success');
595
}
596

    
597
$tab_array = array();
598
$tab_array[] = array(gettext("Users"), true, "system_usermanager.php");
599
$tab_array[] = array(gettext("Groups"), false, "system_groupmanager.php");
600
$tab_array[] = array(gettext("Settings"), false, "system_usermanager_settings.php");
601
$tab_array[] = array(gettext("Authentication Servers"), false, "system_authservers.php");
602
display_top_tabs($tab_array);
603

    
604
if (!($act == "new" || $act == "edit" || $input_errors)) {
605
?>
606
<form method="post">
607
<div class="panel panel-default">
608
	<div class="panel-heading"><h2 class="panel-title"><?=gettext('Users')?></h2></div>
609
	<div class="panel-body">
610
		<div class="table-responsive">
611
			<table class="table table-striped table-hover table-condensed sortable-theme-bootstrap table-rowdblclickedit" data-sortable>
612
				<thead>
613
					<tr>
614
						<th>&nbsp;</th>
615
						<th><?=gettext("Username")?></th>
616
						<th><?=gettext("Full name")?></th>
617
						<th><?=gettext("Status")?></th>
618
						<th><?=gettext("Groups")?></th>
619
						<th><?=gettext("Actions")?></th>
620
					</tr>
621
				</thead>
622
				<tbody>
623
<?php
624
foreach ($a_user as $i => $userent):
625
	?>
626
					<tr>
627
						<td>
628
							<input type="checkbox" id="frc<?=$i?>" name="delete_check[]" value="<?=$i?>" <?=((($userent['scope'] == "system") || ($userent['name'] == $_SESSION['Username'])) ? 'disabled' : '')?>/>
629
						</td>
630
						<td>
631
<?php
632
	if ($userent['scope'] != "user") {
633
		$usrimg = 'eye-open';
634
	} else {
635
		$usrimg = 'user';
636
	}
637
?>
638
							<i class="fa fa-<?=$usrimg?>"></i>
639
							<?=htmlspecialchars($userent['name'])?>
640
						</td>
641
						<td><?=htmlspecialchars($userent['descr'])?></td>
642
						<td><i class="fa fa-<?= (isset($userent['disabled'])) ? 'ban" title="' . gettext("Disabled") . '"' : 'check" title="' . gettext("Enabled") . '"' ; ?>><span style='display: none'><?= (isset($userent['disabled'])) ? gettext("Disabled") : gettext("Enabled") ; ?></span></i></td>
643
						<td><?=implode(",", local_user_get_groups($userent))?></td>
644
						<td>
645
							<a class="fa fa-pencil" title="<?=gettext("Edit user"); ?>" href="?act=edit&amp;userid=<?=$i?>"></a>
646
<?php if (($userent['scope'] != "system") && ($userent['name'] != $_SESSION['Username'])): ?>
647
							<a class="fa fa-trash"	title="<?=gettext("Delete user")?>" href="?act=deluser&amp;userid=<?=$i?>&amp;username=<?=$userent['name']?>"></a>
648
<?php endif; ?>
649
						</td>
650
					</tr>
651
<?php endforeach; ?>
652
				</tbody>
653
			</table>
654
		</div>
655
	</div>
656
</div>
657
<nav class="action-buttons">
658
	<a href="?act=new" class="btn btn-sm btn-success">
659
		<i class="fa fa-plus icon-embed-btn"></i>
660
		<?=gettext("Add")?>
661
	</a>
662

    
663
	<button type="submit" class="btn btn-sm btn-danger" name="dellall" value="dellall" title="<?=gettext('Delete selected users')?>">
664
		<i class="fa fa-trash icon-embed-btn"></i>
665
		<?=gettext("Delete")?>
666
	</button>
667
</nav>
668
</form>
669
<div class="infoblock">
670
<?php
671
	print_callout('<p>' . gettext("Additional users can be added here. User permissions for accessing " .
672
		"the webConfigurator can be assigned directly or inherited from group memberships. " .
673
		"Some system object properties can be modified but they cannot be deleted.") . '</p>' .
674
		'<p>' . gettext("Accounts added here are also used for other parts of the system " .
675
		"such as OpenVPN, IPsec, and Captive Portal.") . '</p>'
676
	);
677
?></div><?php
678
	include("foot.inc");
679
	exit;
680
}
681

    
682
$form = new Form;
683

    
684
if ($act == "new" || $act == "edit" || $input_errors):
685

    
686
	$form->addGlobal(new Form_Input(
687
		'act',
688
		null,
689
		'hidden',
690
		''
691
	));
692

    
693
	$form->addGlobal(new Form_Input(
694
		'userid',
695
		null,
696
		'hidden',
697
		isset($id) ? $id:''
698
	));
699

    
700
	$form->addGlobal(new Form_Input(
701
		'privid',
702
		null,
703
		'hidden',
704
		''
705
	));
706

    
707
	$form->addGlobal(new Form_Input(
708
		'certid',
709
		null,
710
		'hidden',
711
		''
712
	));
713

    
714
	$ro = "";
715
	if ($pconfig['utype'] == "system") {
716
		$ro = "readonly";
717
	}
718

    
719
	$section = new Form_Section('User Properties');
720

    
721
	$section->addInput(new Form_StaticText(
722
		'Defined by',
723
		strtoupper($pconfig['utype'])
724
	));
725

    
726
	$form->addGlobal(new Form_Input(
727
		'utype',
728
		null,
729
		'hidden',
730
		$pconfig['utype']
731
	));
732

    
733
	$section->addInput(new Form_Checkbox(
734
		'disabled',
735
		'Disabled',
736
		'This user cannot login',
737
		$pconfig['disabled']
738
	));
739

    
740
	$section->addInput($input = new Form_Input(
741
		'usernamefld',
742
		'*Username',
743
		'text',
744
		$pconfig['usernamefld']
745
	));
746

    
747
	if ($ro) {
748
		$input->setReadonly();
749
	}
750

    
751
	$form->addGlobal(new Form_Input(
752
		'oldusername',
753
		null,
754
		'hidden',
755
		$pconfig['usernamefld']
756
	));
757

    
758
	if ($act == "edit") {
759
		$pwd_required = "";
760
	} else {
761
		$pwd_required = "*";
762
	}
763

    
764
	$group = new Form_Group($pwd_required . 'Password');
765
	$group->add(new Form_Input(
766
		'passwordfld1',
767
		'Password',
768
		'password'
769
	));
770
	$group->add(new Form_Input(
771
		'passwordfld2',
772
		'Confirm Password',
773
		'password'
774
	));
775

    
776
	$section->add($group);
777

    
778
	$section->addInput($input = new Form_Input(
779
		'descr',
780
		'Full name',
781
		'text',
782
		htmlspecialchars($pconfig['descr'])
783
	))->setHelp('User\'s full name, for administrative information only');
784

    
785
	if ($ro) {
786
		$input->setDisabled();
787
	}
788

    
789
	$section->addInput(new Form_Input(
790
		'expires',
791
		'Expiration date',
792
		'text',
793
		$pconfig['expires']
794
	))->setHelp('Leave blank if the account shouldn\'t expire, otherwise enter '.
795
		'the expiration date as MM/DD/YYYY');
796

    
797
	$section->addInput(new Form_Checkbox(
798
		'customsettings',
799
		'Custom Settings',
800
		'Use individual customized GUI options and dashboard layout for this user.',
801
		$pconfig['customsettings']
802
	));
803

    
804
	gen_user_settings_fields($section, $pconfig);
805

    
806
	// ==== Group membership ==================================================
807
	$group = new Form_Group('Group membership');
808

    
809
	// Make a list of all the groups configured on the system, and a list of
810
	// those which this user is a member of
811
	$systemGroups = array();
812
	$usersGroups = array();
813

    
814
	$usergid = [$pconfig['usernamefld']];
815

    
816
	foreach ($config['system']['group'] as $Ggroup) {
817
		if ($Ggroup['name'] != "all") {
818
			if (($act == 'edit') && $Ggroup['member'] && in_array($pconfig['uid'], $Ggroup['member'])) {
819
				$usersGroups[ $Ggroup['name'] ] = $Ggroup['name'];	// Add it to the user's list
820
			} else {
821
				$systemGroups[ $Ggroup['name'] ] = $Ggroup['name']; // Add it to the 'not a member of' list
822
			}
823
		}
824
	}
825

    
826
	$group->add(new Form_Select(
827
		'sysgroups',
828
		null,
829
		array_combine((array)$pconfig['groups'], (array)$pconfig['groups']),
830
		$systemGroups,
831
		true
832
	))->setHelp('Not member of');
833

    
834
	$group->add(new Form_Select(
835
		'groups',
836
		null,
837
		array_combine((array)$pconfig['groups'], (array)$pconfig['groups']),
838
		$usersGroups,
839
		true
840
	))->setHelp('Member of');
841

    
842
	$section->add($group);
843

    
844
	$group = new Form_Group('');
845

    
846
	$group->add(new Form_Button(
847
		'movetoenabled',
848
		'Move to "Member of" list',
849
		null,
850
		'fa-angle-double-right'
851
	))->setAttribute('type','button')->removeClass('btn-primary')->addClass('btn-info btn-sm');
852

    
853
	$group->add(new Form_Button(
854
		'movetodisabled',
855
		'Move to "Not member of" list',
856
		null,
857
		'fa-angle-double-left'
858
	))->setAttribute('type','button')->removeClass('btn-primary')->addClass('btn-info btn-sm');
859

    
860
	$group->setHelp('Hold down CTRL (PC)/COMMAND (Mac) key to select multiple items.');
861
	$section->add($group);
862

    
863
	// ==== Button for adding user certificate ================================
864
	if ($act == 'new') {
865
		$section->addInput(new Form_Checkbox(
866
			'showcert',
867
			'Certificate',
868
			'Click to create a user certificate',
869
			false
870
		));
871
	}
872

    
873
	$form->add($section);
874

    
875
	// ==== Effective privileges section ======================================
876
	if (isset($pconfig['uid'])) {
877
		// We are going to build an HTML table and add it to an Input_StaticText. It may be ugly, but it
878
		// is the best way to make the display we need.
879

    
880
		$section = new Form_Section('Effective Privileges');
881

    
882
		$section->addInput(new Form_StaticText(
883
			null,
884
			build_priv_table()
885
		));
886

    
887
		$form->add($section);
888

    
889
		// ==== Certificate table section =====================================
890
		$section = new Form_Section('User Certificates');
891

    
892
		$section->addInput(new Form_StaticText(
893
			null,
894
			build_cert_table()
895
		));
896

    
897
		$form->add($section);
898
	}
899

    
900
	// ==== Add user certificate for a new user
901
	if (is_array($config['ca']) && count($config['ca']) > 0) {
902
		$section = new Form_Section('Create Certificate for User');
903
		$section->addClass('cert-options');
904

    
905
		$nonPrvCas = array();
906
		foreach ($config['ca'] as $ca) {
907
			if (!$ca['prv']) {
908
				continue;
909
			}
910

    
911
			$nonPrvCas[ $ca['refid'] ] = $ca['descr'];
912
		}
913

    
914
		if (!empty($nonPrvCas)) {
915
			$section->addInput(new Form_Input(
916
				'name',
917
				'Descriptive name',
918
				'text',
919
				$pconfig['name']
920
			));
921

    
922
			$section->addInput(new Form_Select(
923
				'caref',
924
				'Certificate authority',
925
				null,
926
				$nonPrvCas
927
			));
928

    
929
			$section->addInput(new Form_Select(
930
				'keylen',
931
				'Key length',
932
				2048,
933
				array(
934
					512 => '512 bits',
935
					1024 => '1024 bits',
936
					2048 => '2048 bits',
937
					3072 => '3072 bits',
938
					4096 => '4096 bits',
939
					7680 => '7680 bits',
940
					8192 => '8192 bits',
941
					15360 => '15360 bits',
942
					16384 => '16384 bits'
943
				)
944
			))->setHelp('The larger the key, the more security it offers, but larger keys take considerably more time to generate, and take slightly longer to validate leading to a slight slowdown in setting up new sessions (not always noticeable). As of 2016, 2048 bit is the minimum and most common selection and 4096 is the maximum in common use. For more information see &lt;a href="https://keylength.com"&gt;keylength.com&lt;/a&gt;.');
945

    
946
			$section->addInput(new Form_Input(
947
				'lifetime',
948
				'Lifetime',
949
				'number',
950
				$pconfig['lifetime']
951
			));
952
		}
953

    
954
		$form->add($section);
955
	}
956

    
957
endif;
958
// ==== Paste a key for the new user
959
$section = new Form_Section('Keys');
960

    
961
$section->addInput(new Form_Checkbox(
962
	'showkey',
963
	'Authorized keys',
964
	'Click to paste an authorized key',
965
	false
966
));
967

    
968
$section->addInput(new Form_Textarea(
969
	'authorizedkeys',
970
	'Authorized SSH Keys',
971
	$pconfig['authorizedkeys']
972
))->setHelp('Enter authorized SSH keys for this user');
973

    
974
$section->addInput(new Form_Input(
975
	'ipsecpsk',
976
	'IPsec Pre-Shared Key',
977
	'text',
978
	$pconfig['ipsecpsk']
979
));
980

    
981
$form->add($section);
982

    
983
print $form;
984

    
985
$csswarning = sprintf(gettext("%sUser-created themes are unsupported, use at your own risk."), "<br />");
986
?>
987
<script type="text/javascript">
988
//<![CDATA[
989
events.push(function() {
990

    
991
	function setcustomoptions() {
992
		var adv = $('#customsettings').prop('checked');
993

    
994
		hideInput('webguicss', !adv);
995
		hideInput('webguifixedmenu', !adv);
996
		hideInput('webguihostnamemenu', !adv);
997
		hideInput('dashboardcolumns', !adv);
998
		hideCheckbox('interfacessort', !adv);
999
		hideCheckbox('dashboardavailablewidgetspanel', !adv);
1000
		hideCheckbox('systemlogsfilterpanel', !adv);
1001
		hideCheckbox('systemlogsmanagelogpanel', !adv);
1002
		hideCheckbox('statusmonitoringsettingspanel', !adv);
1003
		hideCheckbox('webguileftcolumnhyper', !adv);
1004
		hideCheckbox('pagenamefirst', !adv);
1005
	}
1006

    
1007
	// Handle displaying a warning message if a user-created theme is selected.
1008
	function setThemeWarning() {
1009
		if ($('#webguicss').val().startsWith("pfSense")) {
1010
			$('#csstxt').html("").addClass("text-default");
1011
		} else {
1012
			$('#csstxt').html("<?=$csswarning?>").addClass("text-danger");
1013
		}
1014
	}
1015

    
1016
	$('#webguicss').change(function() {
1017
		setThemeWarning();
1018
	});
1019

    
1020
	setThemeWarning();
1021

    
1022
	// On click . .
1023
	$('#customsettings').click(function () {
1024
		setcustomoptions();
1025
	});
1026

    
1027
	$("#movetodisabled").click(function() {
1028
		moveOptions($('[name="groups[]"] option'), $('[name="sysgroups[]"]'));
1029
	});
1030

    
1031
	$("#movetoenabled").click(function() {
1032
		moveOptions($('[name="sysgroups[]"] option'), $('[name="groups[]"]'));
1033
	});
1034

    
1035
	$("#showcert").click(function() {
1036
		hideClass('cert-options', !this.checked);
1037
	});
1038

    
1039
	$("#showkey").click(function() {
1040
		hideInput('authorizedkeys', false);
1041
		hideCheckbox('showkey', true);
1042
	});
1043

    
1044
	$('[id^=delcert]').click(function(event) {
1045
		if (confirm(event.target.title)) {
1046
			$('#certid').val(event.target.id.match(/\d+$/)[0]);
1047
			$('#userid').val('<?=$id;?>');
1048
			$('#act').val('delcert');
1049
			$('form').submit();
1050
		}
1051
	});
1052

    
1053
	$('[id^=delprivid]').click(function(event) {
1054
		if (confirm(event.target.title)) {
1055
			$('#privid').val(event.target.id.match(/\d+$/)[0]);
1056
			$('#userid').val('<?=$id;?>');
1057
			$('#act').val('delprivid');
1058
			$('form').submit();
1059
		}
1060
	});
1061

    
1062
	$('#expires').datepicker();
1063

    
1064
	// ---------- On initial page load ------------------------------------------------------------
1065

    
1066
	hideClass('cert-options', true);
1067
	//hideInput('authorizedkeys', true);
1068
	hideCheckbox('showkey', true);
1069
	setcustomoptions();
1070

    
1071
	// On submit mark all the user's groups as "selected"
1072
	$('form').submit(function() {
1073
		AllServers($('[name="groups[]"] option'), true);
1074
	});
1075
});
1076
//]]>
1077
</script>
1078
<?php
1079
include('foot.inc');
1080
?>
(212-212/231)