Project

General

Profile

Download (14.6 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-2018 Rubicon Communications, LLC (Netgate)
7
 * Copyright (c) 2005 Paul Taylor <paultaylor@winn-dixie.com>
8
 * Copyright (c) 2008 Shrew Soft Inc
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
 * Licensed under the Apache License, Version 2.0 (the "License");
16
 * you may not use this file except in compliance with the License.
17
 * You may obtain a copy of the License at
18
 *
19
 * http://www.apache.org/licenses/LICENSE-2.0
20
 *
21
 * Unless required by applicable law or agreed to in writing, software
22
 * distributed under the License is distributed on an "AS IS" BASIS,
23
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
24
 * See the License for the specific language governing permissions and
25
 * limitations under the License.
26
 */
27

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

    
36
require_once("guiconfig.inc");
37
require_once("pfsense-utils.inc");
38

    
39
$logging_level = LOG_WARNING;
40
$logging_prefix = gettext("Local User Database");
41

    
42
if (!is_array($config['system']['group'])) {
43
	$config['system']['group'] = array();
44
}
45

    
46
$a_group = &$config['system']['group'];
47

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
115
	$act = "edit";
116
}
117

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

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

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

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

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

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

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

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

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

    
183
	if (strlen($_POST['groupname']) > 16) {
184
		$input_errors[] = gettext(
185
		    "The group name is longer than 16 characters.");
186
	}
187

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

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

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

    
216
		$group['name'] = $_POST['groupname'];
217
		$group['description'] = $_POST['description'];
218
		$group['scope'] = $_POST['gtype'];
219

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

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

    
233
		admin_groups_sort();
234

    
235
		local_group_set($group);
236

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

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

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

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

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

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

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

    
282
	$user_has_root_priv = false;
283

    
284
	foreach (get_user_privdesc($a_group[$id]) as $i => $priv) {
285
		$privhtml .=		'<tr>';
286
		$privhtml .=			'<td>' . htmlspecialchars($priv['name']) . '</td>';
287
		$privhtml .=			'<td>' . htmlspecialchars($priv['descr']);
288
		if (isset($priv['warn']) && ($priv['warn'] == 'standard-warning-root')) {
289
			$privhtml .=			' ' . gettext('(admin privilege)');
290
			$user_has_root_priv = true;
291
		}
292
		$privhtml .=			'</td>';
293
		$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>';
294
		$privhtml .=		'</tr>';
295

    
296
	}
297

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

    
307
	}
308

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

    
313
	$privhtml .= '<nav class="action-buttons">';
314
	$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>';
315
	$privhtml .= '</nav>';
316

    
317
	return($privhtml);
318
}
319

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

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

    
328
include("head.inc");
329

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

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

    
338
$tab_array = array();
339
$tab_array[] = array(gettext("Users"), false, "system_usermanager.php");
340
$tab_array[] = array(gettext("Groups"), true, "system_groupmanager.php");
341
$tab_array[] = array(gettext("Settings"), false, "system_usermanager_settings.php");
342
$tab_array[] = array(gettext("Authentication Servers"), false, "system_authservers.php");
343
display_top_tabs($tab_array);
344

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

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

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

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

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

    
433
$section = new Form_Section('Group Properties');
434

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

    
442
if ($pconfig['gtype'] == "system") {
443
	$input->setReadonly();
444

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

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

    
469
$form->add($section);
470

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

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

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

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

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

    
512
	$section->add($group);
513

    
514
	$group = new Form_Group('');
515

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

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

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

    
536
}
537

    
538
if (isset($pconfig['gid'])) {
539
	$section = new Form_Section('Assigned Privileges');
540

    
541
	$section->addInput(new Form_StaticText(
542
		null,
543
		build_priv_table()
544
	));
545

    
546

    
547
	$form->add($section);
548
}
549

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

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

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

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