Project

General

Profile

Download (14.8 KB) Statistics
| Branch: | Tag: | Revision:
1
<?php
2
/*
3
 * system_groupmanager.php
4
 *
5
 * part of pfSense (https://www.pfsense.org)
6
 * Copyright (c) 2004-2013 BSD Perimeter
7
 * Copyright (c) 2013-2016 Electric Sheep Fencing
8
 * Copyright (c) 2014-2019 Rubicon Communications, LLC (Netgate)
9
 * Copyright (c) 2005 Paul Taylor <paultaylor@winn-dixie.com>
10
 * Copyright (c) 2008 Shrew Soft Inc
11
 * All rights reserved.
12
 *
13
 * originally based on m0n0wall (http://m0n0.ch/wall)
14
 * Copyright (c) 2003-2004 Manuel Kasper <mk@neon1.net>.
15
 * All rights reserved.
16
 *
17
 * Licensed under the Apache License, Version 2.0 (the "License");
18
 * you may not use this file except in compliance with the License.
19
 * You may obtain a copy of the License at
20
 *
21
 * http://www.apache.org/licenses/LICENSE-2.0
22
 *
23
 * Unless required by applicable law or agreed to in writing, software
24
 * distributed under the License is distributed on an "AS IS" BASIS,
25
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
26
 * See the License for the specific language governing permissions and
27
 * limitations under the License.
28
 */
29

    
30
##|+PRIV
31
##|*IDENT=page-system-groupmanager
32
##|*NAME=System: Group Manager
33
##|*DESCR=Allow access to the 'System: Group Manager' page.
34
##|*WARN=standard-warning-root
35
##|*MATCH=system_groupmanager.php*
36
##|-PRIV
37

    
38
require_once("guiconfig.inc");
39
require_once("pfsense-utils.inc");
40

    
41
$logging_level = LOG_WARNING;
42
$logging_prefix = gettext("Local User Database");
43

    
44
init_config_arr(array('system', 'group'));
45
$a_group = &$config['system']['group'];
46

    
47
unset($id);
48
$id = $_REQUEST['groupid'];
49
$act = (isset($_REQUEST['act']) ? $_REQUEST['act'] : '');
50

    
51
function cpusercmp($a, $b) {
52
	return strcasecmp($a['name'], $b['name']);
53
}
54

    
55
function admin_groups_sort() {
56
	global $a_group;
57

    
58
	if (!is_array($a_group)) {
59
		return;
60
	}
61

    
62
	usort($a_group, "cpusercmp");
63
}
64

    
65
if ($_POST['act'] == "delgroup") {
66

    
67
	if (!isset($id) || !isset($_REQUEST['groupname']) ||
68
	    !isset($a_group[$id]) ||
69
	    ($_REQUEST['groupname'] != $a_group[$id]['name'])) {
70
		pfSenseHeader("system_groupmanager.php");
71
		exit;
72
	}
73

    
74
	local_group_del($a_group[$id]);
75
	$groupdeleted = $a_group[$id]['name'];
76
	unset($a_group[$id]);
77
	/*
78
	 * Reindex the array to avoid operating on an incorrect index
79
	 * https://redmine.pfsense.org/issues/7733
80
	 */
81
	$a_group = array_values($a_group);
82

    
83
	$savemsg = sprintf(gettext("Successfully deleted group: %s"),
84
	    $groupdeleted);
85
	write_config($savemsg);
86
	syslog($logging_level, "{$logging_prefix}: {$savemsg}");
87
}
88

    
89
if ($_POST['act'] == "delpriv") {
90

    
91
	if (!isset($id) || !isset($a_group[$id])) {
92
		pfSenseHeader("system_groupmanager.php");
93
		exit;
94
	}
95

    
96
	$privdeleted =
97
	    $priv_list[$a_group[$id]['priv'][$_REQUEST['privid']]]['name'];
98
	unset($a_group[$id]['priv'][$_REQUEST['privid']]);
99

    
100
	if (is_array($a_group[$id]['member'])) {
101
		foreach ($a_group[$id]['member'] as $uid) {
102
			$user = getUserEntryByUID($uid);
103
			if ($user) {
104
				local_user_set($user);
105
			}
106
		}
107
	}
108

    
109
	$savemsg = sprintf(gettext("Removed Privilege \"%s\" from group %s"),
110
	    $privdeleted, $a_group[$id]['name']);
111
	write_config($savemsg);
112
	syslog($logging_level, "{$logging_prefix}: {$savemsg}");
113

    
114
	$act = "edit";
115
}
116

    
117
if ($act == "edit") {
118
	if (isset($id) && isset($a_group[$id])) {
119
		$pconfig['name'] = $a_group[$id]['name'];
120
		$pconfig['gid'] = $a_group[$id]['gid'];
121
		$pconfig['gtype'] = empty($a_group[$id]['scope'])
122
		    ? "local" : $a_group[$id]['scope'];
123
		$pconfig['description'] = $a_group[$id]['description'];
124
		$pconfig['members'] = $a_group[$id]['member'];
125
		$pconfig['priv'] = $a_group[$id]['priv'];
126
	}
127
}
128

    
129
if (isset($_POST['dellall_x'])) {
130

    
131
	$del_groups = $_POST['delete_check'];
132
	$deleted_groups = array();
133

    
134
	if (!empty($del_groups)) {
135
		foreach ($del_groups as $groupid) {
136
			if (isset($a_group[$groupid]) &&
137
			    $a_group[$groupid]['scope'] != "system") {
138
				$deleted_groups[] = $a_group[$groupid]['name'];
139
				local_group_del($a_group[$groupid]);
140
				unset($a_group[$groupid]);
141
			}
142
		}
143

    
144
		$savemsg = sprintf(gettext("Successfully deleted %s: %s"),
145
		    (count($deleted_groups) == 1)
146
		    ? gettext("group") : gettext("groups"),
147
		    implode(', ', $deleted_groups));
148
		/*
149
		 * Reindex the array to avoid operating on an incorrect index
150
		 * https://redmine.pfsense.org/issues/7733
151
		 */
152
		$a_group = array_values($a_group);
153
		write_config($savemsg);
154
		syslog($logging_level, "{$logging_prefix}: {$savemsg}");
155
	}
156
}
157

    
158
if (isset($_POST['save'])) {
159
	unset($input_errors);
160
	$pconfig = $_POST;
161

    
162
	/* input validation */
163
	$reqdfields = explode(" ", "groupname");
164
	$reqdfieldsn = array(gettext("Group Name"));
165

    
166
	do_input_validation($_POST, $reqdfields, $reqdfieldsn, $input_errors);
167

    
168
	if ($_POST['gtype'] != "remote") {
169
		if (preg_match("/[^a-zA-Z0-9\.\-_]/", $_POST['groupname'])) {
170
			$input_errors[] = sprintf(gettext(
171
			    "The (%s) group name contains invalid characters."),
172
			    $_POST['gtype']);
173
		}
174
		if (strlen($_POST['groupname']) > 16) {
175
			$input_errors[] = gettext(
176
			    "The group name is longer than 16 characters.");
177
		}
178
	} else {
179
		if (preg_match("/[^a-zA-Z0-9\.\- _]/", $_POST['groupname'])) {
180
			$input_errors[] = sprintf(gettext(
181
			    "The (%s) group name contains invalid characters."),
182
			    $_POST['gtype']);
183
		}
184
	}
185

    
186
	/* Check the POSTed members to ensure they are valid and exist */
187
	if (is_array($_POST['members'])) {
188
		foreach ($_POST['members'] as $newmember) {
189
			if (!is_numeric($newmember) ||
190
			    empty(getUserEntryByUID($newmember))) {
191
				$input_errors[] = gettext("One or more " .
192
				    "invalid group members was submitted.");
193
			}
194
		}
195
	}
196

    
197
	if (!$input_errors && !(isset($id) && $a_group[$id])) {
198
		/* make sure there are no dupes */
199
		foreach ($a_group as $group) {
200
			if ($group['name'] == $_POST['groupname']) {
201
				$input_errors[] = gettext("Another entry " .
202
				    "with the same group name already exists.");
203
				break;
204
			}
205
		}
206
	}
207

    
208
	if (!$input_errors) {
209
		$group = array();
210
		if (isset($id) && $a_group[$id]) {
211
			$group = $a_group[$id];
212
		}
213

    
214
		$group['name'] = $_POST['groupname'];
215
		$group['description'] = $_POST['description'];
216
		$group['scope'] = $_POST['gtype'];
217

    
218
		if (empty($_POST['members'])) {
219
			unset($group['member']);
220
		} else if ($group['gid'] != 1998) { // all group
221
			$group['member'] = $_POST['members'];
222
		}
223

    
224
		if (isset($id) && $a_group[$id]) {
225
			$a_group[$id] = $group;
226
		} else {
227
			$group['gid'] = $config['system']['nextgid']++;
228
			$a_group[] = $group;
229
		}
230

    
231
		admin_groups_sort();
232

    
233
		local_group_set($group);
234

    
235
		/*
236
		 * Refresh users in this group since their privileges may have
237
		 * changed.
238
		 */
239
		if (is_array($group['member'])) {
240
			init_config_arr(array('system', 'user'));
241
			$a_user = &$config['system']['user'];
242
			foreach ($a_user as & $user) {
243
				if (in_array($user['uid'], $group['member'])) {
244
					local_user_set($user);
245
				}
246
			}
247
		}
248

    
249
		/* Sort it alphabetically */
250
		usort($config['system']['group'], function($a, $b) {
251
			return strcmp($a['name'], $b['name']);
252
		});
253

    
254
		$savemsg = sprintf(gettext("Successfully %s group %s"),
255
		    (strlen($id) > 0) ? gettext("edited") : gettext("created"),
256
		    $group['name']);
257
		write_config($savemsg);
258
		syslog($logging_level, "{$logging_prefix}: {$savemsg}");
259

    
260
		header("Location: system_groupmanager.php");
261
		exit;
262
	}
263

    
264
	$pconfig['name'] = $_POST['groupname'];
265
}
266

    
267
function build_priv_table() {
268
	global $a_group, $id;
269

    
270
	$privhtml = '<div class="table-responsive">';
271
	$privhtml .=	'<table class="table table-striped table-hover table-condensed">';
272
	$privhtml .=		'<thead>';
273
	$privhtml .=			'<tr>';
274
	$privhtml .=				'<th>' . gettext('Name') . '</th>';
275
	$privhtml .=				'<th>' . gettext('Description') . '</th>';
276
	$privhtml .=				'<th>' . gettext('Action') . '</th>';
277
	$privhtml .=			'</tr>';
278
	$privhtml .=		'</thead>';
279
	$privhtml .=		'<tbody>';
280

    
281
	$user_has_root_priv = false;
282

    
283
	foreach (get_user_privdesc($a_group[$id]) as $i => $priv) {
284
		$privhtml .=		'<tr>';
285
		$privhtml .=			'<td>' . htmlspecialchars($priv['name']) . '</td>';
286
		$privhtml .=			'<td>' . htmlspecialchars($priv['descr']);
287
		if (isset($priv['warn']) && ($priv['warn'] == 'standard-warning-root')) {
288
			$privhtml .=			' ' . gettext('(admin privilege)');
289
			$user_has_root_priv = true;
290
		}
291
		$privhtml .=			'</td>';
292
		$privhtml .=			'<td><a class="fa fa-trash" title="' . gettext('Delete Privilege') . '"	href="system_groupmanager.php?act=delpriv&amp;groupid=' . $id . '&amp;privid=' . $i . '" usepost></a></td>';
293
		$privhtml .=		'</tr>';
294

    
295
	}
296

    
297
	if ($user_has_root_priv) {
298
		$privhtml .=		'<tr>';
299
		$privhtml .=			'<td colspan="2">';
300
		$privhtml .=				'<b>' . gettext('Security notice: Users in this group effectively have administrator-level access') . '</b>';
301
		$privhtml .=			'</td>';
302
		$privhtml .=			'<td>';
303
		$privhtml .=			'</td>';
304
		$privhtml .=		'</tr>';
305

    
306
	}
307

    
308
	$privhtml .=		'</tbody>';
309
	$privhtml .=	'</table>';
310
	$privhtml .= '</div>';
311

    
312
	$privhtml .= '<nav class="action-buttons">';
313
	$privhtml .=	'<a href="system_groupmanager_addprivs.php?groupid=' . $id . '" class="btn btn-success"><i class="fa fa-plus icon-embed-btn"></i>' . gettext("Add") . '</a>';
314
	$privhtml .= '</nav>';
315

    
316
	return($privhtml);
317
}
318

    
319
$pgtitle = array(gettext("System"), gettext("User Manager"), gettext("Groups"));
320
$pglinks = array("", "system_usermanager.php", "system_groupmanager.php");
321

    
322
if ($act == "new" || $act == "edit") {
323
	$pgtitle[] = gettext('Edit');
324
	$pglinks[] = "@self";
325
}
326

    
327
include("head.inc");
328

    
329
if ($input_errors) {
330
	print_input_errors($input_errors);
331
}
332

    
333
if ($savemsg) {
334
	print_info_box($savemsg, 'success');
335
}
336

    
337
$tab_array = array();
338
if (!isAllowedPage("system_usermanager.php")) {
339
	$tab_array[] = array(gettext("User Password"), false, "system_usermanager_passwordmg.php");
340
} else {
341
	$tab_array[] = array(gettext("Users"), false, "system_usermanager.php");
342
}
343
$tab_array[] = array(gettext("Groups"), true, "system_groupmanager.php");
344
$tab_array[] = array(gettext("Settings"), false, "system_usermanager_settings.php");
345
$tab_array[] = array(gettext("Authentication Servers"), false, "system_authservers.php");
346
display_top_tabs($tab_array);
347

    
348
if (!($act == "new" || $act == "edit")) {
349
?>
350
<div class="panel panel-default">
351
	<div class="panel-heading"><h2 class="panel-title"><?=gettext('Groups')?></h2></div>
352
	<div class="panel-body">
353
		<div class="table-responsive">
354
			<table class="table table-striped table-hover table-condensed sortable-theme-bootstrap table-rowdblclickedit" data-sortable>
355
				<thead>
356
					<tr>
357
						<th><?=gettext("Group name")?></th>
358
						<th><?=gettext("Description")?></th>
359
						<th><?=gettext("Member Count")?></th>
360
						<th><?=gettext("Actions")?></th>
361
					</tr>
362
				</thead>
363
				<tbody>
364
<?php
365
	foreach ($a_group as $i => $group):
366
		if ($group["name"] == "all") {
367
			$groupcount = count($config['system']['user']);
368
		} elseif (is_array($group['member'])) {
369
			$groupcount = count($group['member']);
370
		} else {
371
			$groupcount = 0;
372
		}
373
?>
374
					<tr>
375
						<td>
376
							<?=htmlspecialchars($group['name'])?>
377
						</td>
378
						<td>
379
							<?=htmlspecialchars($group['description'])?>
380
						</td>
381
						<td>
382
							<?=$groupcount?>
383
						</td>
384
						<td>
385
							<a class="fa fa-pencil" title="<?=gettext("Edit group"); ?>" href="?act=edit&amp;groupid=<?=$i?>"></a>
386
							<?php if ($group['scope'] != "system"): ?>
387
								<a class="fa fa-trash"	title="<?=gettext("Delete group")?>" href="?act=delgroup&amp;groupid=<?=$i?>&amp;groupname=<?=$group['name']?>" usepost></a>
388
							<?php endif;?>
389
						</td>
390
					</tr>
391
<?php
392
	endforeach;
393
?>
394
				</tbody>
395
			</table>
396
		</div>
397
	</div>
398
</div>
399

    
400
<nav class="action-buttons">
401
	<a href="?act=new" class="btn btn-success btn-sm">
402
		<i class="fa fa-plus icon-embed-btn"></i>
403
		<?=gettext("Add")?>
404
	</a>
405
</nav>
406
<?php
407
	include('foot.inc');
408
	exit;
409
}
410

    
411
$form = new Form;
412
$form->setAction('system_groupmanager.php?act=edit');
413
$form->addGlobal(new Form_Input(
414
	'groupid',
415
	null,
416
	'hidden',
417
	$id
418
));
419

    
420
if (isset($id) && $a_group[$id]) {
421
	$form->addGlobal(new Form_Input(
422
		'id',
423
		null,
424
		'hidden',
425
		$id
426
	));
427

    
428
	$form->addGlobal(new Form_Input(
429
		'gid',
430
		null,
431
		'hidden',
432
		$pconfig['gid']
433
	));
434
}
435

    
436
$section = new Form_Section('Group Properties');
437

    
438
$section->addInput($input = new Form_Input(
439
	'groupname',
440
	'*Group name',
441
	'text',
442
	$pconfig['name']
443
));
444

    
445
if ($pconfig['gtype'] == "system") {
446
	$input->setReadonly();
447

    
448
	$section->addInput(new Form_Input(
449
		'gtype',
450
		'*Scope',
451
		'text',
452
		$pconfig['gtype']
453
	))->setReadonly();
454
} else {
455
	$section->addInput(new Form_Select(
456
		'gtype',
457
		'*Scope',
458
		$pconfig['gtype'],
459
		["local" => gettext("Local"), "remote" => gettext("Remote")]
460
	))->setHelp("<span class=\"text-danger\">Warning: Changing this " .
461
	    "setting may affect the local groups file, in which case a " .
462
	    "reboot may be required for the changes to take effect.</span>");
463
}
464

    
465
$section->addInput(new Form_Input(
466
	'description',
467
	'Description',
468
	'text',
469
	$pconfig['description']
470
))->setHelp('Group description, for administrative information only');
471

    
472
$form->add($section);
473

    
474
/* all users group */
475
if ($pconfig['gid'] != 1998) {
476
	/* Group membership */
477
	$group = new Form_Group('Group membership');
478

    
479
	/*
480
	 * Make a list of all the groups configured on the system, and a list of
481
	 * those which this user is a member of
482
	 */
483
	$systemGroups = array();
484
	$usersGroups = array();
485

    
486
	foreach ($config['system']['user'] as $user) {
487
		if (is_array($pconfig['members']) && in_array($user['uid'],
488
		    $pconfig['members'])) {
489
			/* Add it to the user's list */
490
			$usersGroups[ $user['uid'] ] = $user['name'];
491
		} else {
492
			/* Add it to the 'not a member of' list */
493
			$systemGroups[ $user['uid'] ] = $user['name'];
494
		}
495
	}
496

    
497
	$group->add(new Form_Select(
498
		'notmembers',
499
		null,
500
		array_combine((array)$pconfig['groups'],
501
		    (array)$pconfig['groups']),
502
		$systemGroups,
503
		true
504
	))->setHelp('Not members');
505

    
506
	$group->add(new Form_Select(
507
		'members',
508
		null,
509
		array_combine((array)$pconfig['groups'],
510
		    (array)$pconfig['groups']),
511
		$usersGroups,
512
		true
513
	))->setHelp('Members');
514

    
515
	$section->add($group);
516

    
517
	$group = new Form_Group('');
518

    
519
	$group->add(new Form_Button(
520
		'movetoenabled',
521
		'Move to "Members"',
522
		null,
523
		'fa-angle-double-right'
524
	))->setAttribute('type','button')->removeClass('btn-primary')->addClass(
525
	    'btn-info btn-sm');
526

    
527
	$group->add(new Form_Button(
528
		'movetodisabled',
529
		'Move to "Not members',
530
		null,
531
		'fa-angle-double-left'
532
	))->setAttribute('type','button')->removeClass('btn-primary')->addClass(
533
	    'btn-info btn-sm');
534

    
535
	$group->setHelp(
536
	    'Hold down CTRL (PC)/COMMAND (Mac) key to select multiple items.');
537
	$section->add($group);
538

    
539
}
540

    
541
if (isset($pconfig['gid'])) {
542
	$section = new Form_Section('Assigned Privileges');
543

    
544
	$section->addInput(new Form_StaticText(
545
		null,
546
		build_priv_table()
547
	));
548

    
549

    
550
	$form->add($section);
551
}
552

    
553
print $form;
554
?>
555
<script type="text/javascript">
556
//<![CDATA[
557
events.push(function() {
558

    
559
	// On click . .
560
	$("#movetodisabled").click(function() {
561
		moveOptions($('[name="members[]"] option'),
562
		    $('[name="notmembers[]"]'));
563
	});
564

    
565
	$("#movetoenabled").click(function() {
566
		moveOptions($('[name="notmembers[]"] option'),
567
		    $('[name="members[]"]'));
568
	});
569

    
570
	// On submit mark all the user's groups as "selected"
571
	$('form').submit(function() {
572
		AllServers($('[name="members[]"] option'), true);
573
	});
574
});
575
//]]>
576
</script>
577
<?php
578
include('foot.inc');
(198-198/225)