core/src/www/system_usermanager.php

1082 lines
50 KiB
PHP

<?php
/*
* Copyright (C) 2014-2016 Deciso B.V.
* Copyright (C) 2008 Shrew Soft Inc. <mgrooms@shrew.net>
* Copyright (C) 2005 Paul Taylor <paultaylor@winn-dixie.com>
* Copyright (C) 2003-2005 Manuel Kasper <mk@neon1.net>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
require_once 'guiconfig.inc';
require_once 'system.inc';
require_once 'base32/Base32.php';
function get_user_privdesc(& $user)
{
global $priv_list;
$privs = array();
if (!isset($user['priv']) || !is_array($user['priv'])) {
$user_privs = array();
} else {
$user_privs = $user['priv'];
}
$names = local_user_get_groups($user);
foreach ($names as $name) {
$group = getGroupEntry($name);
if (isset($group['priv']) && is_array($group['priv'])) {
foreach ($group['priv'] as $pname) {
if (in_array($pname, $user_privs)) {
continue;
}
if (empty($priv_list[$pname])) {
continue;
}
$priv = $priv_list[$pname];
$priv['group'] = $group['name'];
$priv['id'] = $pname;
$privs[] = $priv;
}
}
}
foreach ($user_privs as $pname) {
if (!empty($priv_list[$pname])) {
$priv_list[$pname]['id'] = $pname;
$privs[] = $priv_list[$pname];
}
}
legacy_html_escape_form_data($privs);
return $privs;
}
$a_user = &config_read_array('system', 'user');
// reset errors and action
$act = null;
if ($_SERVER['REQUEST_METHOD'] === 'GET') {
// process get type actions
if (isset($_GET['userid']) && isset($a_user[$_GET['userid']])) {
$id = $_GET['userid'];
}
if (isset($_GET['act'])) {
$act = $_GET['act'];
}
if (isset($_GET['savemsg'])) {
$savemsg = htmlspecialchars($_GET['savemsg']);
}
if ($act == "expcert" && isset($id)) {
// export certificate
$cert = &lookup_cert($a_user[$id]['cert'][$_GET['certid']]);
$exp_name = urlencode("{$a_user[$id]['name']}-{$cert['descr']}.crt");
$exp_data = base64_decode($cert['crt']);
$exp_size = strlen($exp_data);
header("Content-Type: application/octet-stream");
header("Content-Disposition: attachment; filename={$exp_name}");
header("Content-Length: $exp_size");
echo $exp_data;
exit;
} elseif ($act == "expckey" && isset($id)) {
// export private key
$cert = &lookup_cert($a_user[$id]['cert'][$_GET['certid']]);
$exp_name = urlencode("{$a_user[$id]['name']}-{$cert['descr']}.key");
$exp_data = base64_decode($cert['prv']);
$exp_size = strlen($exp_data);
header("Content-Type: application/octet-stream");
header("Content-Disposition: attachment; filename={$exp_name}");
header("Content-Length: $exp_size");
echo $exp_data;
exit;
} elseif ($act == 'new' || $act == 'edit') {
// edit user, load or init data
$fieldnames = array('user_dn', 'descr', 'expires', 'scope', 'uid', 'priv',
'otp_seed', 'email', 'shell', 'comment', 'landing_page');
if (isset($id)) {
if (isset($a_user[$id]['authorizedkeys'])) {
$pconfig['authorizedkeys'] = base64_decode($a_user[$id]['authorizedkeys']);
}
if (isset($a_user[$id]['name'])) {
$pconfig['usernamefld'] = $a_user[$id]['name'];
}
$pconfig['groups'] = local_user_get_groups($a_user[$id]);
$pconfig['disabled'] = isset($a_user[$id]['disabled']);
foreach ($fieldnames as $fieldname) {
if (isset($a_user[$id][$fieldname])) {
$pconfig[$fieldname] = $a_user[$id][$fieldname];
} else {
$pconfig[$fieldname] = null;
}
}
foreach (get_locale_list() as $lcode => $ldesc) {
if ($a_user[$id]['language'] == $lcode) {
$pconfig['language'] = $ldesc;
break;
}
}
} else {
// set defaults
$pconfig['groups'] = null;
$pconfig['disabled'] = false;
$pconfig['scope'] = "user";
$pconfig['usernamefld'] = null;
foreach ($fieldnames as $fieldname) {
if (!isset($pconfig[$fieldname])) {
$pconfig[$fieldname] = null;
}
}
}
}
if (empty($pconfig['language'])) {
$pconfig['language'] = gettext('Default');
}
} elseif ($_SERVER['REQUEST_METHOD'] === 'POST') {
// process post type requests
if (isset($_POST['userid']) && isset($a_user[$_POST['userid']])) {
$id = $_POST['userid'];
}
if (isset($_POST['act'])) {
$act = $_POST['act'];
}
$pconfig = $_POST;
$input_errors = array();
$user = getUserEntry($_SESSION['Username']);
if (userHasPrivilege($user, 'user-config-readonly')) {
$input_errors[] = gettext('You do not have the permission to perform this action.');
} elseif ($act == "deluser" && isset($id)) {
// drop user
if ($_SESSION['Username'] === $a_user[$id]['name']) {
$input_errors[] = gettext('You cannot delete yourself.');
} else {
local_user_del($a_user[$id]);
$userdeleted = $a_user[$id]['name'];
unset($a_user[$id]);
write_config(sprintf('The user "%s" was successfully removed.', $userdeleted));
$savemsg = sprintf(gettext('The user "%s" was successfully removed.'), $userdeleted);
header(url_safe('Location: /system_usermanager.php?savemsg=%s', array($savemsg)));
exit;
}
} elseif ($act == "delcert" && isset($id)) {
// remove certificate association
$certdeleted = lookup_cert($a_user[$id]['cert'][$pconfig['certid']]);
$certdeleted = $certdeleted['descr'];
unset($a_user[$id]['cert'][$pconfig['certid']]);
write_config(sprintf('The certificate association "%s" was successfully removed.', $certdeleted));
$savemsg = sprintf(gettext('The certificate association "%s" was successfully removed.'), $certdeleted);
header(url_safe('Location: /system_usermanager.php?savemsg=%s&act=edit&userid=%d', array($savemsg, $id)));
exit;
} elseif ($act == "newApiKey" && isset($id)) {
// every action is using the sequence of the user, to keep it understandable, we will use
// the same strategy here (although we need a username to work with)
//
// the client side is (jquery) generates the actual download file.
$username = $a_user[$id]['name'];
$authFactory = new \OPNsense\Auth\AuthenticationFactory();
$authenticator = $authFactory->get("Local API");
$keyData = $authenticator->createKey($username);
if ($keyData != null) {
echo json_encode($keyData);
}
exit;
} elseif ($act =='delApiKey' && isset($id)) {
$username = $a_user[$id]['name'];
if (!empty($pconfig['api_delete'])) {
$authFactory = new \OPNsense\Auth\AuthenticationFactory();
$authenticator = $authFactory->get("Local API");
$authenticator->dropKey($username, $pconfig['api_delete']);
$savemsg = sprintf(gettext('The API key "%s" was successfully removed.'), $pconfig['api_delete']);
} else {
$savemsg = gettext('No API key found');
}
// redirect
header(url_safe('Location: /system_usermanager.php?savemsg=%s&act=edit&userid=%d', array($savemsg, $id)));
exit;
} elseif (isset($pconfig['save']) || isset($pconfig['save_close'])) {
$reqdfields = explode(' ', 'usernamefld');
$reqdfieldsn = array(gettext('Username'));
do_input_validation($pconfig, $reqdfields, $reqdfieldsn, $input_errors);
if (preg_match("/[^a-zA-Z0-9\.\-_]/", $pconfig['usernamefld'])) {
$input_errors[] = gettext("The username contains invalid characters.");
}
if (strlen($pconfig['usernamefld']) > 32) {
$input_errors[] = gettext("The username is longer than 32 characters.");
}
if (!empty($pconfig['passwordfld1']) || !empty($pconfig['passwordfld2'])) {
if ($pconfig['passwordfld1'] != $pconfig['passwordfld2']) {
$input_errors[] = gettext('The passwords do not match.');
} elseif (empty($pconfig['gen_new_password'])) {
// check against local password policy
$authenticator = get_authenticator();
$input_errors = array_merge(
$input_errors,
$authenticator->checkPolicy($pconfig['usernamefld'], null, $pconfig['passwordfld1'])
);
} else {
$input_errors[] = gettext('Cannot set random password due to explicit input.');
}
}
if (!empty($pconfig['disabled']) && $_SESSION['Username'] === $a_user[$id]['name']) {
$input_errors[] = gettext('You cannot disable yourself.');
}
if (isset($id)) {
$oldusername = $a_user[$id]['name'];
} else {
$oldusername = '';
if (empty($pconfig['passwordfld1']) && empty($pconfig['gen_new_password'])) {
$input_errors[] = gettext('A password is required.');
}
}
/* make sure this user name is unique */
if (count($input_errors) == 0) {
foreach ($a_user as $userent) {
if ($userent['name'] == $pconfig['usernamefld'] && $oldusername != $pconfig['usernamefld']) {
$input_errors[] = gettext("Another entry with the same username already exists.");
break;
}
}
}
/* also make sure it is not reserved */
if (count($input_errors) == 0) {
$system_users = explode("\n", file_get_contents("/etc/passwd"));
foreach ($system_users as $s_user) {
$ent = explode(":", $s_user);
if ($ent[0] == $pconfig['usernamefld'] && $oldusername != $pconfig['usernamefld']) {
$input_errors[] = gettext("That username is reserved by the system.");
break;
}
}
}
/*
* Check for a valid expirationdate if one is set at all (valid means,
* DateTime puts out a time stamp so any DateTime compatible time
* format may be used. to keep it simple for the enduser, we only
* claim to accept MM/DD/YYYY as inputs. Advanced users may use inputs
* like "+1 day", which will be converted to MM/DD/YYYY based on "now".
* Otherwise such an entry would lead to an invalid expiration data.
*/
if (!empty($pconfig['expires'])) {
try {
$expdate = new DateTime($pconfig['expires']);
//convert from any DateTime compatible date to MM/DD/YYYY
$pconfig['expires'] = $expdate->format("m/d/Y");
} catch (Exception $ex) {
$input_errors[] = gettext("Invalid expiration date format; use MM/DD/YYYY instead.");
}
}
if (!empty($pconfig['name'])) {
$ca = lookup_ca($pconfig['caref']);
if (!$ca) {
$input_errors[] = gettext("Invalid internal Certificate Authority") . "\n";
}
}
if (!empty($pconfig['shell']) && !in_array($pconfig['shell'], auth_get_shells(isset($id) ? $a_user[$id]['uid'] : $config['system']['nextuid']))) {
$input_errors[] = gettext('Invalid login shell provided.');
}
if (!count($input_errors)) {
$userent = array();
if (isset($id)) {
$userent = $a_user[$id];
/* the user name was modified */
if ($pconfig['usernamefld'] != $pconfig['oldusername']) {
local_user_del($userent);
}
}
/* the user password was modified */
if (!empty($pconfig['passwordfld1'])) {
local_user_set_password($userent, $pconfig['passwordfld1']);
} elseif (!empty($pconfig['gen_new_password'])) {
local_user_set_password($userent);
}
isset($pconfig['scope']) ? $userent['scope'] = $pconfig['scope'] : $userent['scope'] = "system";
$userent['name'] = $pconfig['usernamefld'];
$userent['descr'] = $pconfig['descr'];
$userent['expires'] = $pconfig['expires'];
$userent['authorizedkeys'] = base64_encode(trim($pconfig['authorizedkeys']));
if (!empty($pconfig['gen_otp_seed'])) {
// generate 160bit base32 encoded secret
$userent['otp_seed'] = Base32\Base32::encode(random_bytes(20));
} else {
$userent['otp_seed'] = trim($pconfig['otp_seed']);
}
if (!empty($pconfig['disabled'])) {
$userent['disabled'] = true;
} elseif (isset($userent['disabled'])) {
unset($userent['disabled']);
}
if (!empty($pconfig['email'])) {
$userent['email'] = $pconfig['email'];
} elseif (isset($userent['email'])) {
unset($userent['email']);
}
if (!empty($pconfig['comment'])) {
$userent['comment'] = $pconfig['comment'];
} elseif (isset($userent['comment'])) {
unset($userent['comment']);
}
if (!empty($pconfig['landing_page'])) {
$userent['landing_page'] = $pconfig['landing_page'];
} elseif (isset($userent['landing_page'])) {
unset($userent['landing_page']);
}
if (!empty($pconfig['shell'])) {
$userent['shell'] = $pconfig['shell'];
} elseif (isset($userent['shell'])) {
unset($userent['shell']);
}
if (isset($id)) {
$a_user[$id] = $userent;
} else {
$userent['uid'] = $config['system']['nextuid']++;
$a_user[] = $userent;
}
local_user_set_groups($userent, $pconfig['groups']);
local_user_set($userent);
if (isset($id)) {
$audit_msg = sprintf("user \"%s\" changed", $userent['name']);
} else {
$audit_msg = sprintf("user \"%s\" created", $userent['name']);
}
write_config($audit_msg);
// XXX: signal backend that the user has changed.
configdp_run('auth user changed', [$userent['name']]);
if (!empty($pconfig['chkNewCert'])) {
header(url_safe('Location: /system_certmanager.php?act=new&userid=%d', array(isset($id) ? $id : count($a_user) - 1)));
} elseif (isset($pconfig['save_close'])) {
header(url_safe('Location: /system_usermanager.php?savemsg=%s', array(get_std_save_message(true))));
} else {
header(url_safe('Location: /system_usermanager.php?act=edit&userid=%d&savemsg=%s', array(isset($id) ? $id : count($a_user) - 1, get_std_save_message(true))));
}
exit;
}
} else {
header(url_safe('Location: /system_usermanager.php'));
exit;
}
}
legacy_html_escape_form_data($pconfig);
legacy_html_escape_form_data($a_user);
include("head.inc");
?>
<script src="<?= cache_safe('/ui/js/jquery.qrcode.js') ?>"></script>
<script src="<?= cache_safe('/ui/js/qrcode.js') ?>"></script>
<body>
<?php include("fbegin.inc"); ?>
<script>
$( document ).ready(function() {
// unhide otp QR code if found
$('#otp_unhide').click(function () {
$(this).hide();
$('#otp_qrcode').show();
});
// remove certificate association
$(".act-del-cert").click(function(event){
var certid = $(this).data('certid');
event.preventDefault();
BootstrapDialog.show({
type:BootstrapDialog.TYPE_DANGER,
title: "<?= html_safe(gettext('Certificate')) ?>",
message: "<?= html_safe(gettext('Do you really want to remove this certificate association?')) .'\n'. html_safe(gettext('(Certificate will not be deleted)')) ?>",
buttons: [{
label: "<?= html_safe(gettext('No')) ?>",
action: function(dialogRef) {
dialogRef.close();
}}, {
label: "<?= html_safe(gettext('Yes')) ?>",
action: function(dialogRef) {
$("#certid").val(certid);
$("#act").val("delcert");
$("#iform").submit();
}
}]
});
});
// remove user
$(".act-del-user").click(function(event){
var userid = $(this).data('userid');
var username = $(this).data('username');
event.preventDefault();
BootstrapDialog.show({
type:BootstrapDialog.TYPE_DANGER,
title: "<?= html_safe(gettext('User')) ?>",
message: "<?= html_safe(gettext('Do you really want to delete this user?')) ?>" + "<br/>("+username+")",
buttons: [{
label: "<?= html_safe(gettext('No')) ?>",
action: function(dialogRef) {
dialogRef.close();
}}, {
label: "<?= html_safe(gettext('Yes')) ?>",
action: function(dialogRef) {
$("#userid").val(userid);
$("#act2").val("deluser");
$("#iform2").submit();
}
}]
});
});
// expand ssh key section on click
$("#authorizedkeys").click(function(){
$(this).attr('rows', '10');
});
// import ldap users
$("#import_ldap_users").click(function(event){
event.preventDefault();
const url="system_usermanager_import_ldap.php";
var oWin = window.open(url,"OPNsense","width=620,height=400,top=150,left=150,scrollbars=yes");
if (oWin == null || typeof(oWin) == "undefined") {
alert("<?= html_safe(gettext('Popup blocker detected. Action aborted.')) ?>");
}
});
// generate a new API key for this user
$("#newApiKey").click(function(event){
event.preventDefault();
$.post(window.location, {act: 'newApiKey', userid: $("#userid").val() }, function(data) {
if (data['key'] != undefined) {
// only generate a key file if there's data
const output_data = 'key='+data['key'] +'\n' + 'secret='+data['secret'] +'\n';
// create link, click and send to client
let filename = '<?=html_safe(sprintf('%s.%s_apikey.txt', $config['system']['hostname'], $config['system']['domain']));?>';
$('<a></a>')
.attr('id','downloadFile')
.attr('href','data:text/plain;charset=utf8,' + encodeURIComponent(output_data))
.attr('download', filename)
.appendTo('body');
$('#downloadFile').ready(function() {
$('#downloadFile').get(0).click();
// reload form after download
setTimeout(window.location.reload.bind(window.location), 100);
});
}
},'json');
});
// delete API key
$(".act-del-api-key").click(function(event){
event.preventDefault();
var apiKey = $(this).data('key');
BootstrapDialog.show({
type:BootstrapDialog.TYPE_DANGER,
title: "<?= html_safe(gettext('User')) ?>",
message: '<?= html_safe(gettext('Do you really want to delete this API key?')) ?>' + '<br/><small>('+apiKey.substring(0,40)+"...)</small>",
buttons: [{
label: "<?= html_safe(gettext('No')) ?>",
action: function(dialogRef) {
dialogRef.close();
}}, {
label: "<?= html_safe(gettext('Yes')) ?>",
action: function(dialogRef) {
$("#act").val("delApiKey");
$("#api_delete").val(apiKey);
$("#iform").submit();
}
}]
});
});
$('.datepicker').datepicker();
$("#add_groups").click(function(){
$("#groups").append($("#notgroups option:selected"));
$("#notgroups option:selected").remove();
$("#groups option:selected").prop('selected', false);
});
$("#remove_groups").click(function(){
$("#notgroups").append($("#groups option:selected"));
$("#groups option:selected").remove();
$("#notgroups option:selected").prop('selected', false);
});
$("#save").click(function(){
$("#groups > option").prop('selected', true);
$("#notgroups > option").prop('selected', false);
});
$("#save_close").click(function(){
$("#groups > option").prop('selected', true);
$("#notgroups > option").prop('selected', false);
});
});
</script>
<section class="page-content-main">
<div class="container-fluid">
<div class="row">
<?php if (isset($input_errors) && count($input_errors)) print_input_errors($input_errors); ?>
<?php if (isset($savemsg)) print_info_box($savemsg); ?>
<section class="col-xs-12">
<div class="tab-content content-box col-xs-12 table-responsive">
<?php
if ($act == "new" || $act == "edit" ) :?>
<form method="post" name="iform" id="iform">
<input type="hidden" id="act" name="act" value="<?=$act;?>" />
<input type="hidden" id="userid" name="userid" value="<?=(isset($id) ? $id : '');?>" />
<input type="hidden" id="priv_delete" name="priv_delete" value="" /> <!-- delete priv action -->
<input type="hidden" id="api_delete" name="api_delete" value="" /> <!-- delete api ke action -->
<input type="hidden" id="certid" name="certid" value="" /> <!-- remove cert association action -->
<table class="table table-striped opnsense_standard_table_form">
<tr>
<td style="width:22%"></td>
<td style="width:78%; text-align:right">
<small><?=gettext("full help"); ?> </small>
<i class="fa fa-toggle-off text-danger" style="cursor: pointer;" id="show_all_help_page"></i>
</td>
</tr>
<tr>
<td><?=gettext("Defined by");?></td>
<td>
<strong><?=strtoupper($pconfig['scope']);?></strong>
<input name="scope" type="hidden" value="<?=$pconfig['scope']?>" />
</td>
</tr>
<tr>
<td><i class="fa fa-info-circle text-muted"></i> <?=gettext("Disabled");?></td>
<td>
<input name="disabled" type="checkbox" id="disabled" <?= $pconfig['disabled'] ? "checked=\"checked\"" : "" ?> />
</td>
</tr>
<tr>
<td><i class="fa fa-info-circle text-muted"></i> <?=gettext("Username");?></td>
<td>
<input name="usernamefld" type="text" id="usernamefld" size="20" maxlength="32" value="<?=$pconfig['usernamefld'];?>" <?= $pconfig['scope'] == "system" || !empty($pconfig['user_dn']) ? "readonly=\"readonly\"" : "";?> />
<input name="oldusername" type="hidden" id="oldusername" value="<?=$pconfig['usernamefld'];?>" />
</td>
</tr>
<?php
if (!empty($pconfig['user_dn'])):?>
<tr>
<td><i class="fa fa-info-circle text-muted"></i> <?=gettext("User distinguished name");?></td>
<td>
<input name="user_dn" type="text" id="user_dn" size="20" value="<?=$pconfig['user_dn'];?>" readonly="readonly" />
</td>
</tr>
<?php
endif;?>
<tr>
<td><i class="fa fa-info-circle text-muted"></i> <?=gettext("Password");?></td>
<td>
<input name="passwordfld1" type="password" autocomplete="new-password" id="passwordfld1" size="20" value="" /><br/>
<input name="passwordfld2" type="password" autocomplete="new-password" id="passwordfld2" size="20" value="" />
<small><?= gettext("(confirmation)"); ?></small><br/><br/>
<input type="checkbox" name="gen_new_password" <?= !empty($pconfig['gen_new_password']) ? 'checked="checked"' : '' ?>/>
<small><?=gettext('Generate a scrambled password to prevent local database logins for this user.') ?></small>
</td>
</tr>
<tr>
<td><a id="help_for_fullname" href="#" class="showhelp"><i class="fa fa-info-circle"></i></a> <?=gettext("Full name");?></td>
<td>
<input name="descr" type="text" value="<?=$pconfig['descr'];?>" <?= $pconfig['scope'] == "system" ? "readonly=\"readonly\"" : "";?> />
<div class="hidden" data-for="help_for_fullname">
<?=gettext("User's full name, for your own information only");?>
</div>
</td>
</tr>
<tr>
<td><a id="help_for_email" href="#" class="showhelp"><i class="fa fa-info-circle"></i></a> <?=gettext("E-Mail");?></td>
<td>
<input name="email" type="text" value="<?= $pconfig['email'] ?>" />
<div class="hidden" data-for="help_for_email">
<?= gettext('User\'s e-mail address, for your own information only') ?>
</div>
</td>
</tr>
<tr>
<td><a id="help_for_comment" href="#" class="showhelp"><i class="fa fa-info-circle"></i></a> <?=gettext("Comment");?></td>
<td>
<textarea name="comment" id="comment" class="form-control" cols="65" rows="3"><?= $pconfig['comment'] ?></textarea>
<div class="hidden" data-for="help_for_comment">
<?= gettext('User comment, for your own information only') ?>
</div>
</td>
</tr>
<tr>
<td><a id="help_for_landing_page" href="#" class="showhelp"><i class="fa fa-info-circle"></i></a> <?=gettext("Preferred landing page");?></td>
<td>
<input name="landing_page" type="text" value="<?=$pconfig['landing_page'];?>">
<div class="hidden" data-for="help_for_landing_page">
<?= gettext('Preferred landing page after login or authentication failure') ?>
</div>
</td>
</tr>
<tr>
<td><i class="fa fa-info-circle text-muted"></i> <?=gettext("Language");?></td>
<td>
<input name="language" type="hidden" value="<?= $pconfig['language'] ?>" />
<?= $pconfig['language'] ?>
</td>
</tr>
<tr>
<td><i class="fa fa-info-circle text-muted"></i> <?= gettext('Login shell') ?></td>
<td>
<select name="shell" class="selectpicker" data-style="btn-default">
<?php
foreach (auth_get_shells(isset($id) ? $a_user[$id]['uid'] : $config['system']['nextuid']) as $shell_key => $shell_value) :?>
<option value="<?= html_safe($shell_key) ?>" <?= $pconfig['shell'] == $shell_key ? 'selected="selected"' : '' ?>><?= html_safe($shell_value) ?></option>
<?php
endforeach;?>
</select>
</td>
</tr>
<tr>
<td><a id="help_for_expires" href="#" class="showhelp"><i class="fa fa-info-circle"></i></a> <?=gettext("Expiration date"); ?></td>
<td>
<input name="expires" type="text" id="expires" class="datepicker" data-date-format="mm/dd/yyyy" value="<?=$pconfig['expires'];?>" />
<div class="hidden" data-for="help_for_expires">
<?=gettext("Leave blank if the account shouldn't expire, otherwise enter the expiration date in the following format: mm/dd/yyyy"); ?>
</div>
</td>
</tr>
<tr>
<td><a id="help_for_groups" href="#" class="showhelp"><i class="fa fa-info-circle"></i></a> <?=gettext("Group Memberships");?></td>
<td>
<table class="table" style="width:100%; border:0;">
<thead>
<tr>
<th><?=gettext("Not Member Of"); ?></th>
<th>&nbsp;</th>
<th><?=gettext("Member Of"); ?></th>
</tr>
</thead>
<tbody>
<tr>
<td>
<select size="10" name="notgroups[]" id="notgroups" onchange="clear_selected('groups')" multiple="multiple">
<?php
foreach ($config['system']['group'] as $group) :
if (!empty($pconfig['groups']) && in_array($group['name'], $pconfig['groups'])) {
continue;
}
?>
<option value="<?=$group['name'];?>">
<?=htmlspecialchars($group['name']);?>
</option>
<?php
endforeach;?>
</select>
</td>
<td class="text-center">
<br />
<a id="add_groups" class="btn btn-default btn-xs" data-toggle="tooltip" title="<?=gettext("Add groups"); ?>">
<span class="fa fa-arrow-right fa-fw"></span>
</a>
<br /><br />
<a id="remove_groups" class="btn btn-default btn-xs" data-toggle="tooltip" title="<?=gettext("Remove groups"); ?>">
<span class="fa fa-arrow-left fa-fw"></span>
</a>
</td>
<td>
<select size="10" name="groups[]" id="groups" onchange="clear_selected('notgroups')" multiple="multiple">
<?php
if (!empty($pconfig['groups'])) :
foreach ($config['system']['group'] as $group) :
if (!in_array($group['name'], $pconfig['groups'])) {
continue;
}
?>
<option value="<?=$group['name'];?>">
<?=htmlspecialchars($group['name']);?>
</option>
<?php
endforeach;
endif;
?>
</select>
</td>
</tr>
</table>
<div class="hidden" data-for="help_for_groups">
<?=gettext("Hold down CTRL (pc)/COMMAND (mac) key to select multiple items");?>
</div>
</td>
</tr>
<?php
if ($pconfig['uid'] != "") :?>
<tr>
<td><i class="fa fa-info-circle text-muted"></i> <?=gettext("Effective Privileges");?></td>
<td>
<table class="table table-hover table-condensed">
<tr>
<td><b><?=gettext("Inherited from");?></b></td>
<td><b><?=gettext("Type");?></b></td>
<td><b><?=gettext("Name");?></b></td>
</tr>
<?php
foreach (get_user_privdesc($a_user[$id]) as $priv) :?>
<tr>
<td><?=!empty($priv['group']) ? $priv['group'] : ''?></td>
<td>
<?php
switch (substr($priv['id'], 0, 5)) {
case 'page-':
echo gettext('GUI');
break;
case 'user-':
echo gettext('User');
break;
default:
echo gettext('N/A');
break;
} ?>
</td>
<td><?=$priv['name']?></td>
</tr>
<?php
endforeach;?>
<tr>
<td colspan="3">
<a href="system_usermanager_addprivs.php?userid=<?=$id?>" class="btn btn-xs btn-default"
title="<?=gettext("edit privileges");?>" data-toggle="tooltip">
<span class="fa fa-pencil fa-fw"></span>
</a>
</td>
</tr>
</table>
</td>
</tr>
<tr>
<td><i class="fa fa-info-circle text-muted"></i> <?=gettext("User Certificates");?></td>
<td>
<table class="table table-condensed">
<tr>
<td><strong><?=gettext("Name");?></strong></td>
<td><strong><?=gettext("CA");?></strong></td>
<td><strong><?=gettext("Valid From");?></strong></td>
<td><strong><?=gettext("Valid To");?></strong></td>
<td></td>
</tr>
<?php
$new_cert_link_suffix = "";
if (isset($a_user[$id]['cert']) && is_array($a_user[$id]['cert'])) :
$i = 0;
foreach ($a_user[$id]['cert'] as $certref) :
$cert = lookup_cert($certref);
$ca = lookup_ca($cert['caref']);
list($cert_validfrom, $cert_validto) = cert_get_dates($cert['crt']);
$new_cert_link_suffix = "&amp;method=internal&amp;caref={$cert['caref']}";
?>
<tr>
<td><?=htmlspecialchars($cert['descr']);?>
<?=is_cert_revoked($cert) ? "(<b>".gettext('Revoked')."</b>)" : "";?>
</td>
<td>
<?=htmlspecialchars($ca['descr']);?>
</td>
<td><?=$cert_validfrom;?></td>
<td><?=$cert_validto;?></td>
<td>
<a href="system_usermanager.php?act=expckey&amp;certid=<?=$i?>&amp;userid=<?=$id?>"
class="btn btn-default btn-xs" data-toggle="tooltip" title="<?=gettext("export private key");?>">
<span class="fa fa-arrow-down fa-fw"></span>
</a>
<a href="system_usermanager.php?act=expcert&amp;certid=<?=$i?>&amp;userid=<?=$id?>"
class="btn btn-default btn-xs" data-toggle="tooltip" title="<?=gettext("export certificate");?>">
<span class="fa fa-arrow-down fa-fw"></span>
</a>
<button type="submit" data-certid="<?=$i;?>" class="btn btn-default btn-xs act-del-cert"
title="<?=gettext("unlink certificate");?>" data-toggle="tooltip">
<span class="fa fa-trash fa-fw"></span>
</button>
</td>
</tr>
<?php
$i++;
endforeach;
endif;?>
<tr>
<td colspan="5">
<a href="system_certmanager.php?act=new&amp;userid=<?=$id?><?=$new_cert_link_suffix;?>" class="btn btn-default btn-xs"
title="<?=gettext("create or link user certificate");?>" data-toggle="tooltip">
<span class="fa fa-plus fa-fw"></span>
</a>
</td>
</tr>
</table>
</td>
</tr>
<tr>
<td><a id="help_for_apikeys" href="#" class="showhelp"><i class="fa fa-info-circle"></i></a> <?=gettext("API keys");?> </td>
<td>
<table class="table table-condensed">
<thead>
<tr>
<th>
<?=gettext('key');?>
</th>
<th>
</th>
</tr>
</thead>
<tbody>
<?php
if (isset($a_user[$id]['apikeys']['item'])):
foreach ($a_user[$id]['apikeys']['item'] as $userApiKey):?>
<tr>
<td>
<small>
<?php // listtags always changes our key item to an array.. ?>
<?php // don't want to change "key" to something less sane. ?>
<?=$userApiKey['key'][0];?>
</small>
</td>
<td>
<button data-key="<?=$userApiKey['key'][0];?>" type="button" class="btn btn-default btn-xs act-del-api-key"
title="<?=gettext("delete API key");?>" data-toggle="tooltip">
<span class="fa fa-trash fa-fw"></span>
</button>
</td>
</tr>
<?php
endforeach;
endif;?>
</tbody>
<tfoot>
<tr>
<td colspan="2">
<button type="button" class="btn btn-default btn-xs" id="newApiKey"
title="<?=gettext('Create API key');?>" data-toggle="tooltip">
<span class="fa fa-plus fa-fw"></span>
</button>
</td>
</tr>
</tfoot>
</table>
<div class="hidden" data-for="help_for_apikeys">
<hr/>
<?=gettext('Manage API keys here for machine to machine interaction using this user\'s credentials.');?>
</div>
</td>
</tr>
<?php
else :?>
<tr id="usercertchck">
<td><i class="fa fa-info-circle text-muted"></i> <?=gettext("Certificate");?></td>
<td>
<input type="checkbox" id="chkNewCert" name="chkNewCert" /> <?= gettext('Click to create a user certificate.') ?>
</td>
</tr>
<?php
endif;?>
<tr>
<td><a id="help_for_otp_seed" href="#" class="showhelp"><i class="fa fa-info-circle"></i></a> <?= gettext('OTP seed') ?></td>
<td>
<input name="otp_seed" type="text" value="<?=$pconfig['otp_seed'];?>"/>
<input type="checkbox" name="gen_otp_seed"/>
<small><?= gettext('Generate new secret (160 bit)') ?></small>
<div class="hidden" data-for="help_for_otp_seed">
<?=gettext("OTP (base32) seed to use when a one time password authenticator is used");?><br/>
</div>
</td>
</tr>
<?php
if (!empty($pconfig['otp_seed'])):
// construct google url, using token, username and this machines hostname
$otp_url = "otpauth://totp/";
$otp_url .= $pconfig['usernamefld']."@".htmlspecialchars($config['system']['hostname'])."?secret=";
$otp_url .= $pconfig['otp_seed'];
?>
<tr>
<td><a id="help_for_otp_code" href="#" class="showhelp"><i class="fa fa-info-circle"></i></a> <?= gettext('OTP QR code') ?></td>
<td>
<label class="btn btn-primary" id="otp_unhide"><?= gettext('Click to unhide') ?></label>
<div style="display:none;" id="otp_qrcode"></div>
<script>
$('#otp_qrcode').qrcode('<?= $otp_url ?>');
</script>
<div class="hidden" data-for="help_for_otp_code">
<?= gettext('Scan this QR code for easy setup with external apps.') ?>
</div>
</td>
</tr>
<?php
endif;?>
<tr>
<td><i class="fa fa-info-circle text-muted"></i> <?=gettext("Authorized keys");?></td>
<td>
<textarea name="authorizedkeys" id="authorizedkeys" style="max-width: inherit;" class="form-control" cols="65" rows="1" placeholder="<?=gettext("Paste an authorized keys file here.");?>" wrap='off'><?=$pconfig['authorizedkeys'];?></textarea>
</td>
</tr>
<tr>
<td>&nbsp;</td>
<td>
<button name="save" id="save" type="submit" class="btn btn-primary" value="save" /><?= gettext('Save') ?></button>
<button name="save_close" id="save_close" type="submit" class="btn btn-primary" value="save_close" /><?= gettext('Save and go back') ?></button>
<button name="cancel" id="cancel" type="submit" class="btn btn-default" value="cancel" /><?= gettext('Cancel') ?></button>
<?php
if (isset($id) && !empty($a_user[$id])) :?>
<input name="id" type="hidden" value="<?=htmlspecialchars($id);?>" />
<?php
endif;?>
</td>
</tr>
</table>
</form>
<?php
else :?>
<form method="post" name="iform2" id="iform2">
<input type="hidden" id="act2" name="act" value="" />
<input type="hidden" id="userid" name="userid" value="<?=(isset($id) ? $id : '');?>" />
<input type="hidden" id="username" name="username" value="" />
<table class="table table-striped">
<thead>
<tr>
<th><?=gettext("Username"); ?></th>
<th><?=gettext("Full name"); ?></th>
<th><?=gettext("Groups"); ?></th>
<th class="text-nowrap">
<a href="system_usermanager.php?act=new" class="btn btn-primary btn-xs" data-toggle="tooltip" title="<?= html_safe(gettext('Add')) ?>">
<i class="fa fa-plus fa-fw"></i>
</a>
<?php
$can_import = false;
if (!empty($config['system']['webgui']['authmode'])) {
$servers = explode(',', $config['system']['webgui']['authmode']);
foreach ($servers as $server) {
$authcfg_type = auth_get_authserver($server)['type'];
if ($authcfg_type == 'ldap' || $authcfg_type == 'ldap-totp') {
$can_import = true;
}
}
}
?>
<?php if ($can_import): ?>
<button type="submit" name="import"
id="import_ldap_users"
data-toggle="tooltip"
class="btn btn-primary btn-xs"
title="<?= html_safe(gettext('Import')) ?>">
<i class="fa fa-cloud-download fa-fw"></i>
</button>
<?php endif ?>
</th>
</tr>
</thead>
<tbody>
<?php
/* create a copy for sorting */
$a_user_ro = $a_user;
uasort($a_user_ro, function($a, $b) {
return strnatcasecmp($a['name'], $b['name']);
});
foreach ($a_user_ro as $i => $userent): ?>
<tr>
<td>
<?php
if (isset($userent['disabled'])) {
$usrimg = 'text-muted';
} elseif (userIsAdmin($userent['name'])) {
$usrimg = 'text-danger';
} else {
$usrimg = 'text-info';
}?>
<span class="fa fa-user <?=$usrimg;?>"></span> <?=$userent['name'];?>
</td>
<td><?= $userent['descr'] ?></td>
<td><?= implode(', ', local_user_get_groups($userent)) ?></td>
<td class="text-nowrap">
<a href="system_usermanager.php?act=edit&userid=<?=$i?>"
class="btn btn-default btn-xs" data-toggle="tooltip" title="<?= html_safe(gettext('Edit')) ?>">
<span class="fa fa-pencil fa-fw"></span>
</a>
<?php if ($userent['scope'] != 'system'): ?>
<button type="button" class="btn btn-default btn-xs act-del-user"
data-username="<?=$userent['name'];?>"
data-userid="<?=$i?>" title="<?= html_safe(gettext('Delete')) ?>" data-toggle="tooltip">
<span class="fa fa-trash fa-fw"></span>
</button>
<?php endif ?>
</td>
</tr>
<?php endforeach ?>
<tr>
<td colspan="3">
<table>
<tr>
<td></td>
<td style="width:20px"></td>
<td style="width:20px"><span class="fa fa-user text-danger"></span></td>
<td style="width:200px"><?= gettext('System Administrator') ?></td>
<td style="width:20px"><span class="fa fa-user text-muted"></span></td>
<td style="width:200px"><?= gettext('Disabled User') ?></td>
<td style="width:20px"><span class="fa fa-user text-info"></span></td>
<td style="width:200px"><?= gettext('Normal User') ?></td>
<td></td>
</tr>
</table>
</td>
<td class="text-nowrap"></td>
</tr>
</tbody>
</table>
</form>
<?php
endif;?>
</div>
</section>
</div>
</div>
</section>
<?php include("foot.inc");