Project

General

Profile

Download (13.5 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
if (!is_array($config['system']['group'])) {
40
	$config['system']['group'] = array();
41
}
42

    
43
$a_group = &$config['system']['group'];
44

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

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

    
53
function admin_groups_sort() {
54
	global $a_group;
55

    
56
	if (!is_array($a_group)) {
57
		return;
58
	}
59

    
60
	usort($a_group, "cpusercmp");
61
}
62

    
63
if ($_POST['act'] == "delgroup") {
64

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

    
70
	local_group_del($a_group[$id]);
71
	$groupdeleted = $a_group[$id]['name'];
72
	unset($a_group[$id]);
73
	/* Reindex the array to avoid operating on an incorrect index https://redmine.pfsense.org/issues/7733 */
74
	$a_group = array_values($a_group);
75
	write_config();
76
	$savemsg = sprintf(gettext("Group %s successfully deleted."), $groupdeleted);
77
}
78

    
79
if ($_POST['act'] == "delpriv") {
80

    
81
	if (!isset($id) || !isset($a_group[$id])) {
82
		pfSenseHeader("system_groupmanager.php");
83
		exit;
84
	}
85

    
86
	$privdeleted = $priv_list[$a_group[$id]['priv'][$_REQUEST['privid']]]['name'];
87
	unset($a_group[$id]['priv'][$_REQUEST['privid']]);
88

    
89
	if (is_array($a_group[$id]['member'])) {
90
		foreach ($a_group[$id]['member'] as $uid) {
91
			$user = getUserEntryByUID($uid);
92
			if ($user) {
93
				local_user_set($user);
94
			}
95
		}
96
	}
97

    
98
	write_config();
99
	$act = "edit";
100
	$savemsg = sprintf(gettext("Privilege %s successfully deleted."), $privdeleted);
101
}
102

    
103
if ($act == "edit") {
104
	if (isset($id) && isset($a_group[$id])) {
105
		$pconfig['name'] = $a_group[$id]['name'];
106
		$pconfig['gid'] = $a_group[$id]['gid'];
107
		$pconfig['gtype'] = empty($a_group[$id]['scope']) ? "local" : $a_group[$id]['scope'];
108
		$pconfig['description'] = $a_group[$id]['description'];
109
		$pconfig['members'] = $a_group[$id]['member'];
110
		$pconfig['priv'] = $a_group[$id]['priv'];
111
	}
112
}
113

    
114
if (isset($_POST['dellall_x'])) {
115

    
116
	$del_groups = $_POST['delete_check'];
117

    
118
	if (!empty($del_groups)) {
119
		foreach ($del_groups as $groupid) {
120
			if (isset($a_group[$groupid]) && $a_group[$groupid]['scope'] != "system") {
121
				local_group_del($a_group[$groupid]);
122
				unset($a_group[$groupid]);
123
			}
124
		}
125
		/* Reindex the array to avoid operating on an incorrect index https://redmine.pfsense.org/issues/7733 */
126
		$a_group = array_values($a_group);
127
		$savemsg = gettext("Selected groups removed successfully.");
128
		write_config($savemsg);
129
	}
130
}
131

    
132
if (isset($_POST['save'])) {
133
	unset($input_errors);
134
	$pconfig = $_POST;
135

    
136
	/* input validation */
137
	$reqdfields = explode(" ", "groupname");
138
	$reqdfieldsn = array(gettext("Group Name"));
139

    
140
	do_input_validation($_POST, $reqdfields, $reqdfieldsn, $input_errors);
141

    
142
	if ($_POST['gtype'] != "remote") {
143
		if (preg_match("/[^a-zA-Z0-9\.\-_]/", $_POST['groupname'])) {
144
			$input_errors[] = sprintf(gettext("The (%s) group name contains invalid characters."), $_POST['gtype']);
145
		}
146
	} else {
147
		if (preg_match("/[^a-zA-Z0-9\.\- _]/", $_POST['groupname'])) {
148
			$input_errors[] = sprintf(gettext("The (%s) group name contains invalid characters."), $_POST['gtype']);
149
		}
150
	}
151

    
152
	if (strlen($_POST['groupname']) > 16) {
153
		$input_errors[] = gettext("The group name is longer than 16 characters.");
154
	}
155

    
156
	/* Check the POSTed members to ensure they are valid and exist */
157
	if (is_array($_POST['members'])) {
158
		foreach ($_POST['members'] as $newmember) {
159
			if (!is_numeric($newmember) || empty(getUserEntryByUID($newmember))) {
160
				$input_errors[] = gettext("One or more invalid group members was submitted.");
161
			}
162
		}
163
	}
164

    
165
	if (!$input_errors && !(isset($id) && $a_group[$id])) {
166
		/* make sure there are no dupes */
167
		foreach ($a_group as $group) {
168
			if ($group['name'] == $_POST['groupname']) {
169
				$input_errors[] = gettext("Another entry with the same group name already exists.");
170
				break;
171
			}
172
		}
173
	}
174

    
175
	if (!$input_errors) {
176
		$group = array();
177
		if (isset($id) && $a_group[$id]) {
178
			$group = $a_group[$id];
179
		}
180

    
181
		$group['name'] = $_POST['groupname'];
182
		$group['description'] = $_POST['description'];
183
		$group['scope'] = $_POST['gtype'];
184

    
185
		if (empty($_POST['members'])) {
186
			unset($group['member']);
187
		} else if ($group['gid'] != 1998) { // all group
188
			$group['member'] = $_POST['members'];
189
		}
190

    
191
		if (isset($id) && $a_group[$id]) {
192
			$a_group[$id] = $group;
193
		} else {
194
			$group['gid'] = $config['system']['nextgid']++;
195
			$a_group[] = $group;
196
		}
197

    
198
		admin_groups_sort();
199

    
200
		local_group_set($group);
201

    
202
		/* Refresh users in this group since their privileges may have changed. */
203
		if (is_array($group['member'])) {
204
			$a_user = &$config['system']['user'];
205
			foreach ($a_user as & $user) {
206
				if (in_array($user['uid'], $group['member'])) {
207
					local_user_set($user);
208
				}
209
			}
210
		}
211

    
212
		/* Sort it alphabetically */
213
		usort($config['system']['group'], function($a, $b) {
214
			return strcmp($a['name'], $b['name']);
215
		});
216

    
217
		write_config();
218

    
219
		header("Location: system_groupmanager.php");
220
		exit;
221
	}
222

    
223
	$pconfig['name'] = $_POST['groupname'];
224
}
225

    
226
function build_priv_table() {
227
	global $a_group, $id;
228

    
229
	$privhtml = '<div class="table-responsive">';
230
	$privhtml .=	'<table class="table table-striped table-hover table-condensed">';
231
	$privhtml .=		'<thead>';
232
	$privhtml .=			'<tr>';
233
	$privhtml .=				'<th>' . gettext('Name') . '</th>';
234
	$privhtml .=				'<th>' . gettext('Description') . '</th>';
235
	$privhtml .=				'<th>' . gettext('Action') . '</th>';
236
	$privhtml .=			'</tr>';
237
	$privhtml .=		'</thead>';
238
	$privhtml .=		'<tbody>';
239

    
240
	$user_has_root_priv = false;
241

    
242
	foreach (get_user_privdesc($a_group[$id]) as $i => $priv) {
243
		$privhtml .=		'<tr>';
244
		$privhtml .=			'<td>' . htmlspecialchars($priv['name']) . '</td>';
245
		$privhtml .=			'<td>' . htmlspecialchars($priv['descr']);
246
		if (isset($priv['warn']) && ($priv['warn'] == 'standard-warning-root')) {
247
			$privhtml .=			' ' . gettext('(admin privilege)');
248
			$user_has_root_priv = true;
249
		}
250
		$privhtml .=			'</td>';
251
		$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>';
252
		$privhtml .=		'</tr>';
253

    
254
	}
255

    
256
	if ($user_has_root_priv) {
257
		$privhtml .=		'<tr>';
258
		$privhtml .=			'<td colspan="2">';
259
		$privhtml .=				'<b>' . gettext('Security notice: Users in this group effectively have administrator-level access') . '</b>';
260
		$privhtml .=			'</td>';
261
		$privhtml .=			'<td>';
262
		$privhtml .=			'</td>';
263
		$privhtml .=		'</tr>';
264

    
265
	}
266

    
267
	$privhtml .=		'</tbody>';
268
	$privhtml .=	'</table>';
269
	$privhtml .= '</div>';
270

    
271
	$privhtml .= '<nav class="action-buttons">';
272
	$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>';
273
	$privhtml .= '</nav>';
274

    
275
	return($privhtml);
276
}
277

    
278
$pgtitle = array(gettext("System"), gettext("User Manager"), gettext("Groups"));
279
$pglinks = array("", "system_usermanager.php", "system_groupmanager.php");
280

    
281
if ($act == "new" || $act == "edit") {
282
	$pgtitle[] = gettext('Edit');
283
	$pglinks[] = "@self";
284
}
285

    
286
include("head.inc");
287

    
288
if ($input_errors) {
289
	print_input_errors($input_errors);
290
}
291

    
292
if ($savemsg) {
293
	print_info_box($savemsg, 'success');
294
}
295

    
296
$tab_array = array();
297
$tab_array[] = array(gettext("Users"), false, "system_usermanager.php");
298
$tab_array[] = array(gettext("Groups"), true, "system_groupmanager.php");
299
$tab_array[] = array(gettext("Settings"), false, "system_usermanager_settings.php");
300
$tab_array[] = array(gettext("Authentication Servers"), false, "system_authservers.php");
301
display_top_tabs($tab_array);
302

    
303
if (!($act == "new" || $act == "edit")) {
304
?>
305
<div class="panel panel-default">
306
	<div class="panel-heading"><h2 class="panel-title"><?=gettext('Groups')?></h2></div>
307
	<div class="panel-body">
308
		<div class="table-responsive">
309
			<table class="table table-striped table-hover table-condensed sortable-theme-bootstrap table-rowdblclickedit" data-sortable>
310
				<thead>
311
					<tr>
312
						<th><?=gettext("Group name")?></th>
313
						<th><?=gettext("Description")?></th>
314
						<th><?=gettext("Member Count")?></th>
315
						<th><?=gettext("Actions")?></th>
316
					</tr>
317
				</thead>
318
				<tbody>
319
<?php
320
	foreach ($a_group as $i => $group):
321
		if ($group["name"] == "all") {
322
			$groupcount = count($config['system']['user']);
323
		} else {
324
			$groupcount = count($group['member']);
325
		}
326
?>
327
					<tr>
328
						<td>
329
							<?=htmlspecialchars($group['name'])?>
330
						</td>
331
						<td>
332
							<?=htmlspecialchars($group['description'])?>
333
						</td>
334
						<td>
335
							<?=$groupcount?>
336
						</td>
337
						<td>
338
							<a class="fa fa-pencil" title="<?=gettext("Edit group"); ?>" href="?act=edit&amp;groupid=<?=$i?>"></a>
339
							<?php if ($group['scope'] != "system"): ?>
340
								<a class="fa fa-trash"	title="<?=gettext("Delete group")?>" href="?act=delgroup&amp;groupid=<?=$i?>&amp;groupname=<?=$group['name']?>" usepost></a>
341
							<?php endif;?>
342
						</td>
343
					</tr>
344
<?php
345
	endforeach;
346
?>
347
				</tbody>
348
			</table>
349
		</div>
350
	</div>
351
</div>
352

    
353
<nav class="action-buttons">
354
	<a href="?act=new" class="btn btn-success btn-sm">
355
		<i class="fa fa-plus icon-embed-btn"></i>
356
		<?=gettext("Add")?>
357
	</a>
358
</nav>
359
<?php
360
	include('foot.inc');
361
	exit;
362
}
363

    
364
$form = new Form;
365
$form->setAction('system_groupmanager.php?act=edit');
366
$form->addGlobal(new Form_Input(
367
	'groupid',
368
	null,
369
	'hidden',
370
	$id
371
));
372

    
373
if (isset($id) && $a_group[$id]) {
374
	$form->addGlobal(new Form_Input(
375
		'id',
376
		null,
377
		'hidden',
378
		$id
379
	));
380

    
381
	$form->addGlobal(new Form_Input(
382
		'gid',
383
		null,
384
		'hidden',
385
		$pconfig['gid']
386
	));
387
}
388

    
389
$section = new Form_Section('Group Properties');
390

    
391
$section->addInput($input = new Form_Input(
392
	'groupname',
393
	'*Group name',
394
	'text',
395
	$pconfig['name']
396
));
397

    
398
if ($pconfig['gtype'] == "system") {
399
	$input->setReadonly();
400

    
401
	$section->addInput(new Form_Input(
402
		'gtype',
403
		'*Scope',
404
		'text',
405
		$pconfig['gtype']
406
	))->setReadonly();
407
} else {
408
	$section->addInput(new Form_Select(
409
		'gtype',
410
		'*Scope',
411
		$pconfig['gtype'],
412
		["local" => gettext("Local"), "remote" => gettext("Remote")]
413
	));
414
}
415

    
416
$section->addInput(new Form_Input(
417
	'description',
418
	'Description',
419
	'text',
420
	$pconfig['description']
421
))->setHelp('Group description, for administrative information only');
422

    
423

    
424
$form->add($section);
425
if ($pconfig['gid'] != 1998) { // all users group
426

    
427
	// ==== Group membership ==================================================
428
	$group = new Form_Group('Group membership');
429

    
430
	// Make a list of all the groups configured on the system, and a list of
431
	// those which this user is a member of
432
	$systemGroups = array();
433
	$usersGroups = array();
434

    
435
	foreach ($config['system']['user'] as $user) {
436
		if (is_array($pconfig['members']) && in_array($user['uid'], $pconfig['members'])) {
437
			$usersGroups[ $user['uid'] ] = $user['name'];	// Add it to the user's list
438
		} else {
439
			$systemGroups[ $user['uid'] ] = $user['name']; // Add it to the 'not a member of' list
440
		}
441
	}
442

    
443
	$group->add(new Form_Select(
444
		'notmembers',
445
		null,
446
		array_combine((array)$pconfig['groups'], (array)$pconfig['groups']),
447
		$systemGroups,
448
		true
449
	))->setHelp('Not members');
450

    
451
	$group->add(new Form_Select(
452
		'members',
453
		null,
454
		array_combine((array)$pconfig['groups'], (array)$pconfig['groups']),
455
		$usersGroups,
456
		true
457
	))->setHelp('Members');
458

    
459
	$section->add($group);
460

    
461
	$group = new Form_Group('');
462

    
463
	$group->add(new Form_Button(
464
		'movetoenabled',
465
		'Move to "Members"',
466
		null,
467
		'fa-angle-double-right'
468
	))->setAttribute('type','button')->removeClass('btn-primary')->addClass('btn-info btn-sm');
469

    
470
	$group->add(new Form_Button(
471
		'movetodisabled',
472
		'Move to "Not members',
473
		null,
474
		'fa-angle-double-left'
475
	))->setAttribute('type','button')->removeClass('btn-primary')->addClass('btn-info btn-sm');
476

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

    
480
}
481

    
482
if (isset($pconfig['gid'])) {
483
	$section = new Form_Section('Assigned Privileges');
484

    
485
	$section->addInput(new Form_StaticText(
486
		null,
487
		build_priv_table()
488
	));
489

    
490

    
491
	$form->add($section);
492
}
493

    
494
print $form;
495
?>
496
<script type="text/javascript">
497
//<![CDATA[
498
events.push(function() {
499

    
500
	// On click . .
501
	$("#movetodisabled").click(function() {
502
		moveOptions($('[name="members[]"] option'), $('[name="notmembers[]"]'));
503
	});
504

    
505
	$("#movetoenabled").click(function() {
506
		moveOptions($('[name="notmembers[]"] option'), $('[name="members[]"]'));
507
	});
508

    
509
	// On submit mark all the user's groups as "selected"
510
	$('form').submit(function() {
511
		AllServers($('[name="members[]"] option'), true);
512
	});
513
});
514
//]]>
515
</script>
516
<?php
517
include('foot.inc');
(205-205/232)