Project

General

Profile

Download (14.7 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-2019 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
init_config_arr(array('system', 'group'));
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']) ||
66
	    !isset($a_group[$id]) ||
67
	    ($_REQUEST['groupname'] != $a_group[$id]['name'])) {
68
		pfSenseHeader("system_groupmanager.php");
69
		exit;
70
	}
71

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

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

    
87
if ($_POST['act'] == "delpriv") {
88

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

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

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

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

    
112
	$act = "edit";
113
}
114

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

    
127
if (isset($_POST['dellall_x'])) {
128

    
129
	$del_groups = $_POST['delete_check'];
130
	$deleted_groups = array();
131

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

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

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

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

    
164
	do_input_validation($_POST, $reqdfields, $reqdfieldsn, $input_errors);
165

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

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

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

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

    
212
		$group['name'] = $_POST['groupname'];
213
		$group['description'] = $_POST['description'];
214
		$group['scope'] = $_POST['gtype'];
215

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

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

    
229
		admin_groups_sort();
230

    
231
		local_group_set($group);
232

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

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

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

    
258
		header("Location: system_groupmanager.php");
259
		exit;
260
	}
261

    
262
	$pconfig['name'] = $_POST['groupname'];
263
}
264

    
265
function build_priv_table() {
266
	global $a_group, $id;
267

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

    
279
	$user_has_root_priv = false;
280

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

    
293
	}
294

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

    
304
	}
305

    
306
	$privhtml .=		'</tbody>';
307
	$privhtml .=	'</table>';
308
	$privhtml .= '</div>';
309

    
310
	$privhtml .= '<nav class="action-buttons">';
311
	$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>';
312
	$privhtml .= '</nav>';
313

    
314
	return($privhtml);
315
}
316

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

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

    
325
include("head.inc");
326

    
327
if ($input_errors) {
328
	print_input_errors($input_errors);
329
}
330

    
331
if ($savemsg) {
332
	print_info_box($savemsg, 'success');
333
}
334

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
537
}
538

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

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

    
547

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

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

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

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

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