ACC SHELL
/**
* File: modules/LdapPopup.ycp
* Package: Configuration of LDAP
* Summary: Additional user interface functions: special edit popups
* Authors: Jiri Suchomel <jsuchome@suse.cz>
*
* $Id: LdapPopup.ycp 51747 2008-10-01 13:35:55Z jsuchome $
*
* Popups for editing the values of LDAP configuration tables.
*/
{
module "LdapPopup";
textdomain "ldap-client";
import "Ldap";
import "Label";
import "Popup";
import "Wizard";
/**
* Popup for browsing LDAP tree and selecting the DN
* WARNING we expect that LDAP connection is already correctly initialized !
* @param root_dn the starting point (root of tree); if empty string is
* given, the search for available bases will be done automatically
* @return DN of selected item, empty string when canceled
*/
global define string BrowseTree (string root_dn) {
// get display mode
map display_info = UI::GetDisplayInfo();
boolean textmode = display_info["TextMode"]:true;
// map of already read subtrees
map<string,boolean> dns = $[];
// selected DN (return value)
string current_dn = "";
term contents = `HBox (`VSpacing (20), `VBox (`HSpacing(70),
`VSpacing (0.2),
`HBox (
`HSpacing (),
`ReplacePoint (`id (`reptree), `Tree (`id(`tree), root_dn, [])),
`HSpacing ()
),
`HBox (
`HSpacing (1.5),
`PushButton (`id (`ok), `opt (`key_F10), Label::OKButton()),
`PushButton(`id (`cancel),`opt (`key_F9),Label::CancelButton()),
// pushbutton label
textmode ?
// button label
`Right (`PushButton (`id (`open), `opt (`key_F6),_("&Open"))):
`Empty (),
`HSpacing (1.5)
),
`VSpacing (0.2)
));
UI::OpenDialog (`opt (`decorated), contents);
list<term> items = [];
list<string> out = (list<string>) SCR::Read (.ldap.search, $[
"base_dn" : root_dn,
"scope" : root_dn != "" ? 0 : 1,
"dn_only" : true,
"not_found_ok" : true ]
);
if (size (out) > 0)
{
items = maplist (string dn, out, {
dns [dn] = false;
return `item (dn, false, []);
});
}
if (size (items) > 0)
{
UI::ReplaceWidget (`id (`reptree), textmode ?
`Tree (`id(`tree), root_dn, items) :
`Tree (`id(`tree), `opt(`notify), root_dn, items));
// no item is selected
UI::ChangeWidget (`tree, `CurrentItem, nil);
}
else if (root_dn == "")
{
list bases = (list) SCR::Read (.ldap.search, $[
"base_dn" : "",
"scope" : 0,
"attrs" : [ "namingContexts" ]
]);
if (size (bases) > 0)
items = maplist (string dn, bases[0,"namingContexts"]:[],
``(`item(dn, false, [])));
if (size (items) > 0)
{
UI::ReplaceWidget (`id (`reptree), textmode ?
`Tree (`id(`tree), root_dn, items) :
`Tree (`id(`tree), `opt(`notify), root_dn, items));
UI::ChangeWidget (`tree, `CurrentItem, nil);
}
}
if (textmode)
UI::SetFocus (`id(`tree));
list<string> subdns = [];
map open_items = $[];
define list<term> update_items (list<term> its) {
return maplist (term it, its, {
string dn = it[0]:"";
if (dn == current_dn)
{
return `item (dn, true, maplist (string k,
subdns, ``(`item (k, false, []))));
}
integer last = size (it) - 1;
if (size (it[last]:[]) == 0)
return it;
// `OpenItems doesn't work in ncurses...
boolean open = haskey (open_items, dn) && !textmode;
return `item (dn, open, update_items (it[last]:[]));
});
}
string retval = root_dn;
while (true)
{
any ret = UI::UserInput ();
if (ret == `tree || ret == `open)
{
current_dn = (string) UI::QueryWidget (`id(`tree),`CurrentItem);
if (! dns[current_dn]:false)
{
subdns = (list<string>) SCR::Read (.ldap.search, $[
"base_dn" : current_dn,
"scope" : 1,
"dn_only" : true,
"not_found_ok" : true,
]);
dns [current_dn] = true;
if (size (subdns) > 0)
{
open_items = (map) UI::QueryWidget (`tree, `OpenItems);
items = update_items (items);
UI::ReplaceWidget (`id (`reptree), textmode ?
`Tree (`id(`tree), root_dn, items) :
`Tree (`id(`tree), `opt(`notify), root_dn, items));
UI::ChangeWidget (`id(`tree), `CurrentItem, current_dn);
open_items = $[];
}
}
if (textmode)
UI::SetFocus (`id(`tree));
}
if (ret == `cancel)
{
retval = "";
break;
}
if (ret == `ok)
{
string dn = (string)UI::QueryWidget (`id(`tree), `CurrentItem);
if (dn != nil)
retval = dn;
else retval = current_dn;
break;
}
}
UI::CloseDialog ();
return retval;
}
/**
* Open the LDAP Browse popup and initialize initialize LDAP connection
* before.
* @param connection init map with information passed to ldap agent
* (see ldap agent '.ldap' Execute call documentation)
* @param root_dn the starting point (root of tree); if empty string is
* given, the search for available bases will be done automatically
* @return DN of selected item, empty string when canceled
*/
global define string InitAndBrowseTree (string root_dn, map connection) {
map args = size (connection) > 0 ? connection : $[
"hostname" : Ldap::GetFirstServer (Ldap::server),
"port" : Ldap::GetFirstPort (Ldap::server),
"version" : Ldap::ldap_v2 ? 2 : 3,
"use_tls" : Ldap::ldap_tls ? "yes" : "no"
];
string error = Ldap::LDAPInitWithTLSCheck (args);
if (error != "")
{
Ldap::LDAPErrorMessage ("init", error);
return root_dn;
}
return BrowseTree (root_dn);
}
/**
* Generic popup for editing attribute's value
* @param map with settings, it could have these keys:
* "attr" attribute name
* "value" current attribute values
* "conflicts" list of forbidden values (e.g. existing 'cn' values)
* "single" if attribute can have only one value
* "offer" list of possible values for current attribute (e.g. existing
* groups for "secondaryGroup" attribute)
* "browse" if Browse LDAP Tree widget should be provided for choosing DN
* @return list of atrtibute values (edited or unchanged)
*/
global define list<string> EditAttribute (map settings)
{
string attr = settings["attr"]:"";
list<string> value = settings["value"]:[];
list conflicts = settings["conflicts"]:[];
list offer = settings["offer"]:[];
boolean single = settings["single"]:false;
boolean browse = settings["browse"]:false;
// help text 1/3
string help_text = _("<p>Set the new value for the current attribute.</p>") +
// help text 2/3
_("<p>If the attribute can have more values, add new entries
with <b>Add Value</b>. Sometimes the button contains the list of
possible values to use for the current attribute.
If the value of the edited attribute should be a distinguished name (DN),
it is possible to choose it from the LDAP tree using <b>Browse</b>.
</p>
");
string desc = Ldap::AttributeDescription (attr);
if (desc != "")
// help text 3/3, %1 is attribute name, description follows.
// The description will be not translated: maybe add a note
// "available only in english" to the sentence for other languages?
// Example:
// "<p>The description of attribute \"%1\"<br>(available only in english):</p>"
// or:
// "<p>The description (only in english) of attribute \"%1\":<br></p>"
help_text = help_text + sformat (_("<p>The description of attribute \"%1\":<br></p>"), attr) +
sformat ("<p><i>%1</i></p>", desc);
list<string> org_value = value;
integer value_size = size (value);
// horizontal size of popup for
integer hsize = size (value[0]:"") + 10;
/**
* Helper for creating items for EditAttribute Popup
*/
define term generate_value_list () ``{
term ret = `VBox();
if (single)
{
ret = add (ret, `InputField (`id (0), `opt (`hstretch),
// textentry label
sformat(_("&Value of \"%1\" Attribute"), attr), value[0]:""));
}
else
{
ret = add (ret, `InputField (`id (0), `opt (`hstretch),
// textentry label
sformat(_("&Values of \"%1\" Attribute"), attr), value[0]:""));
integer i = 1;
while (i < value_size)
{
ret = add (ret, `InputField (`id (i), `opt (`hstretch),
"", value[i]:""));
if (size (value[i]:"" + 10) > hsize)
hsize = size (value[i]:"") + 10;
i = i + 1;
}
}
return ret;
}
term values = generate_value_list ();
// button label
term add_button = `PushButton(`id(`new), `opt (`key_F3), _("&Add Value"));
if (size (offer) > 0 || browse)
{
// menubutton item (default value)
list mb = [ `item(`id(`new), _("&Empty Entry")) ];
if (browse)
mb = add (mb, `item(`id(`browse), _("Bro&wse")));
foreach (string it, (list<string>) offer, ``{
mb = add (mb, `item(`id(it), it));
});
// button label
add_button = `MenuButton(`id(`mb), `opt (`key_F3), _("&Add Value"), mb);
}
UI::OpenDialog( `opt(`decorated), `HBox(
`HSpacing(1),
`VBox(
`HSpacing (hsize > 50 ? hsize : 50),
`ReplacePoint (`id(`rp), values),
`HBox(
`PushButton(`id(`ok),`opt(`default,`key_F10),Label::OKButton()),
`PushButton(`id(`cancel),`opt (`key_F9), Label::CancelButton()),
`PushButton(`id(`help),`opt (`key_F2), Label::HelpButton()),
(single)? `Empty() :
add_button
)
),
`HSpacing(1)
));
any result = nil;
list<string> new_value = [];
if (value_size == 0)
value_size = 1;
UI::SetFocus (`id(value_size-1));
while (true)
{
result = UI::UserInput ();
if (result == `cancel)
{
new_value = org_value;
break;
}
if ( result == `help )
{
Wizard::ShowHelp( help_text );
}
if (result == `new || contains (offer, result) || result == `browse)
{
integer j = 0;
value = [];
while (j < value_size)
{
value = add (value, (string) UI::QueryWidget (`id(j), `Value) );
j = j + 1;
}
if (contains (offer, result) && value[value_size-1]:"" == "")
{
// relace last empty entry
value [value_size-1] = (string) result;
}
else if (result == `browse)
{
value [value_size-1] = BrowseTree ("");
}
else
{
// add new entry
value = add (value, (result == `new)? "" : (string) result);
value_size = value_size + 1;
}
UI::ReplaceWidget (`id(`rp), generate_value_list ());
UI::SetFocus (`id(value_size-1));
}
if (result == `ok)
{
integer j = 0;
boolean duplicate = false;
new_value = [];
while (j < value_size && !duplicate)
{
string v = (string) UI::QueryWidget (`id(j), `Value);
if (!contains (org_value, v) && contains (conflicts, v))
{
//error popup
Popup::Error (sformat (_("The value \'%1\' already exists.
Please select another one."), v));
duplicate = true;
}
if (v != "") new_value = add (new_value, v);
j = j + 1;
}
if (duplicate) continue;
break;
}
}
UI::CloseDialog();
return new_value;
}
/**
* Popup for adding new configuration module
* @param conflicts list of forbidden names ('cn' values)
* @param available list of possible object classes for new module
* @return map of new module (contains its name and object class)
*/
global define map NewModule (list available, list conflicts) ``{
map descriptions = $[
// description of configuration object
"suseuserconfiguration": _("Configuration of user management tools"),
// description of configuration object
"susegroupconfiguration": _("Configuration of group management tools"),
];
// label
term r_buttons = `VBox( `Left(`Label (_("Object Class of New Module"))));
foreach (string class, (list<string>) available, ``{
string desc = class;
if (descriptions [class]:"" != "")
desc = sformat ("%1 (%2)", class, descriptions [class]:"");
r_buttons = add (r_buttons,`Left(`RadioButton (`id(class), desc,true)));
});
UI::OpenDialog( `opt(`decorated), `HBox(
`HSpacing(1),
`VBox(
`HSpacing (50),
`RadioButtonGroup (`id(`rb), r_buttons),
`InputField (`id (`cn), `opt (`hstretch),
// textentry label, do not translate "cn"
_("&Name of New Module (\"cn\" Value)")),
`HBox(
`PushButton(`id(`ok),`opt(`default,`key_F10),Label::OKButton()),
`PushButton(`id(`cancel),`opt (`key_F9), Label::CancelButton())
)
),
`HSpacing(1)
));
any result = nil;
string new_value = "";
string class = "";
UI::SetFocus (`id(`cn));
while (true)
{
result = UI::UserInput ();
if (result == `cancel)
{
new_value = "";
break;
}
if (result == `ok)
{
new_value = (string) UI::QueryWidget (`id(`cn), `Value);
if (contains (conflicts, new_value))
{
//error popup
Popup::Error (_("The entered value already exists.
Select another one.
"));
continue;
}
if (new_value == "")
{
//error popup
Popup::Error (_("Enter the module name."));
continue;
}
class = (string) UI::QueryWidget (`id(`rb), `CurrentButton);
break;
}
}
UI::CloseDialog();
return $[ "class": class, "cn": new_value ];
}
/**
* Popup for adding new default value (default value is template's attribute)
* @param conflicts list of attributes already set
* @param available list of possible attributes
* @return map of new "default value" (contains attribute name and value)
*/
global define map AddDefaultValue (list available, list conflicts) ``{
// help text 1/3
string help_text = _("<p>Here, set the values of attributes belonging
to an object using the current template. Such values are used as defaults when
the new object is created.</p>
") +
/*
// help text 2/3 do not translate "defaultObjectClass"
_("<p>The list of attributes provided in <b>Attribute Name</b> is the
list of allowed attributes for objects described in the \"defaultObjectClass\"
entry of the current template.</p>
") +
*/
// help text 3/3 do not translate "homedirectory"
_("<p>You can use special syntax to create attribute
values from existing ones. The expression <i>%attr_name</i> will be replaced
with the value of attribute \"attr_name\" (for example, use \"/home/%uid\"
as a value of \"homeDirectory\").</p>
");
available = filter (string attr, (list<string>) available, ``(!contains (conflicts,attr)));
UI::OpenDialog( `opt(`decorated), `HBox(
`HSpacing(1),
`VBox(
`HSpacing (50),
`VSpacing(0.5),
// combobox label
`Left(`ComboBox (`id (`attr),`opt(`editable), _("Attribute &Name"),
available)),
`VSpacing(0.5),
// textentry label
`InputField (`id (`val), `opt (`hstretch), _("Attribute &Value")),
`VSpacing(0.5),
`HBox(
`PushButton(`id(`ok),`opt(`default,`key_F10),Label::OKButton()),
`PushButton(`id(`cancel), `opt(`key_F9), Label::CancelButton()),
`PushButton(`id(`help),`opt (`key_F2), Label::HelpButton())
),
`VSpacing(0.5)),
`HSpacing(1)
));
any result = nil;
string new_value = "";
string attr = "";
UI::SetFocus (`id(`attr));
while (true)
{
result = UI::UserInput ();
if (result == `cancel)
{
new_value = "";
break;
}
if ( result == `help )
{
Wizard::ShowHelp( help_text );
}
if (result == `ok)
{
attr = (string) UI::QueryWidget (`id(`attr), `Value);
new_value = (string) UI::QueryWidget (`id(`val), `Value);
break;
}
}
UI::CloseDialog();
return $[ "attr": attr, "value": new_value ];
}
/**
* dialog for Password Policy configuration object
* @param ppolicy data with Password Policy object to be edited (as obtained from LDAP search)
* @return map with modifications of ppolicy object, nil in case of `cancel
*/
global define map PasswordPolicyDialog (map ppolicy) {
// reduce the list values to single ones
ppolicy = mapmap (string a, any val, (map<string,any>)ppolicy, {
if (is (val, list) && (Ldap::SingleValued (a) || size ((list)val) == 1))
val = ((list)val)[0]:nil;
if (val == "TRUE" || val == "FALSE")
val = (val == "TRUE");
return $[ a: val ];
});
map ppolicy_orig = ppolicy;
// help text for Password Policy Dialog
string help_text = _("<p>Select the <b>Password Change Policies</b>, <b>Password Aging Policies</b>, and <b>Lockout Policies</b> tabs to choose LDAP password policy groups of attributes to configure.</p>");
// tab-specific help texts
map tabs_help_text = $[
// help text for pwdInHistory attribute
`pwchange : _("<p>Specify the <b>Maximum Number of Passwords Stored in History</b> to set how many previously used passwords should be saved. Saved passwords may not be used.</p>") +
// help text for pwdMustChange attribute
_("<p>Check <b>User Must Change Password after Reset</b> to force users to change their passwords after the the password is reset or changed by an administrator.</p>") +
// help text for pwdAllowUserChange attribute
_("<p>Check <b>User Can Change Password</b> to allow users to change their passwords.</p>") +
// help text for pwdSafeModify attribute
_("<p>If the existing password must be provided along with the new password, check <b>Old Password Required for Password Change</b>.</p>") +
// help text for pwdCheckQuality attribute
_("<p>Select whether the password quality should be verified while passwords are modified or added. Select <b>No Checking</b> if passwords should not be checked at all. With <b>Accept Uncheckable Passwords</b>, passwords are accepted even if the check cannot be performed, for example, if the user has provided an encrypted password. With <b>Only Accept Checked Passwords</b> passwords are refused if the quality test fails or the password cannot be checked.</p>") +
// help text for pwdMinLength attribute
_("Set the minimum number of characters that must be used in a password in <b>Minimum Password Length</b>.</p>"),
// help text for pwdMinAge attribute
`aging : _("<p><b>Minimum Password Age</b> sets how much time must pass between modifications to the password.</p>") +
// help text for pwdMaxAge attribute
_("<p><b>Maximum Password Age</b> sets how long after modification a password expires.</p>") +
// help text for pwdExpireWarning attribute
_("<p>In <b>Time before Password Expiration to Issue Warning</b> set how long before a password is due to expire that an expiration warning messages should be given to an authenticating user.</p>") +
// help text for pwdGraceAuthNLimit attribute
_("<p>Set the number of times an expired password can be used to authenticate in <b>Allowed Uses of an Expired Password</b>.</p>"),
// help text for pwdLockout attribute
`lockout : _("<p>Check <b>Enable Password Locking</b> to forbid use of a password after a specified number of consecutive failed bind attempts.</p>") +
// help text for pwdMaxFailure attribute
_("<p>Set the number of consecutive failed bind attempts after which the password may not be used to authenticate in <b>Bind Failures to Lock the Password</b>.</p>") +
// help text for pwdLockoutDuration attribute
_("<p>Set how long the password cannot be used in <b>Password Lock Duration</b>.</p>") +
// help text for pwdFailureCountInterval attribute
_("<p><b>Bind Failures Cache Duration</b> sets how long before password failures are purged from the failure counter even though no successful authentication has occurred.</p>"),
];
// map of attribute names for each tab
map attributes = $[
`pwchange : [
"pwdInHistory", "pwdMustChange", "pwdAllowUserChange",
"pwdSafeModify", "pwdCheckQuality", "pwdMinLength"
],
`aging : [
"pwdMinAge", "pwdMaxAge", "pwdExpireWarning", "pwdGraceAuthNLimit"
],
`lockout : [
"pwdLockout", "pwdLockoutDuration", "pwdMaxFailure",
"pwdFailureCountInterval"
],
];
list time_attributes = [
"pwdMinAge", "pwdMaxAge", "pwdExpireWarning", "pwdLockoutDuration",
"pwdFailureCountInterval"
];
map default_values = $[
"pwdMustChange" : false,
"pwdAllowUserChange" : true,
"pwdSafeModify" : false,
"pwdLockout" : false,
];
// maximal value of IntFields
integer max = 99999;
list<term> tabs = [
// tab label
`item(`id(`pwchange), _("&Password Change Policies"), true),
// tab label
`item(`id(`aging), _("Pa&ssword Aging Policies")),
// tab label
`item(`id(`lockout), _("&Lockout Policies")),
];
term tabs_term = `VBox (
`DumbTab (`id(`tabs), tabs,
`ReplacePoint(`id(`tabContents ), `VBox (`Empty ())))
);
boolean has_tabs = true;
if (!UI::HasSpecialWidget (`DumbTab))
{
has_tabs = false;
term tabbar = `HBox ();
foreach (term it, tabs, {
string label = it[1]:"";
tabbar = add (tabbar,`PushButton (it[0]:`id(label), label));
});
tabs_term = `VBox (`Left(tabbar),
`Frame ("", `ReplacePoint(`id(`tabContents), `Empty ()))
);
}
term contents = tabs_term;
// generate the term of password policy tab and update the help text
void set_password_policies_term () {
integer pwdcheckquality = tointeger (ppolicy["pwdCheckQuality"]:"0");
term tab_cont = `Top (`HBox (`HSpacing (0.5), `VBox (
`VSpacing (0.8),
`IntField (`id ("pwdInHistory"),
// IntField label
_("Ma&ximum Number of Passwords Stored in History"),
0, max, tointeger (ppolicy["pwdInHistory"]:"0")),
`VSpacing (0.4),
`Left (`CheckBox (`id ("pwdMustChange"),
// checkbox label
_("U&ser Must Change Password after Reset"),
ppolicy["pwdMustChange"]:true)),
`VSpacing (0.2),
`Left (`CheckBox (`id ("pwdAllowUserChange"),
// checkbox label
_("&User Can Change Password"),
ppolicy["pwdAllowUserChange"]:true)),
`VSpacing (0.2),
`Left (`CheckBox (`id ("pwdSafeModify"),
// checkbox label
_("&Old Password Required for Password Change"),
ppolicy["pwdSafeModify"]:false)),
`VSpacing (0.4),
// frame label
`HBox (`HSpacing (2), `Frame (_("Password Quality Checking"), `VBox(
`VSpacing (0.5),
`RadioButtonGroup (`id("pwdCheckQuality"), `VBox (
`Left (`RadioButton (`id(0), `opt (`notify),
_("&No Checking"), pwdcheckquality == 0)),
`Left (`RadioButton(`id(1), `opt (`notify),
_("Acc&ept Uncheckable Passwords"),
pwdcheckquality == 1)),
`Left (`RadioButton(`id(2), `opt (`notify),
_("&Only Accept Checked Passwords"),
pwdcheckquality == 2))
)),
`VSpacing (0.4),
// IntField label
`IntField (`id ("pwdMinLength"), _("&Minimum Password Length"),
0, max, tointeger (ppolicy["pwdMinLength"]:"0"))
)))
), `HSpacing (0.5)));
UI::ReplaceWidget (`tabContents, tab_cont);
UI::ChangeWidget (`id ("pwdMinLength"), `Enabled, pwdcheckquality > 0);
return;
}
term time_dialog (string id, string label) {
integer value = tointeger (ppolicy[id]:"0");
integer days = value / (24*60*60);
if (days > 0) value = value - (days * 24*60*60);
integer hours = value / (60*60);
if (hours > 0) value = value - (hours * 60*60);
integer minutes = value / 60;
if (minutes > 0) value = value - (minutes * 60);
return `HBox (`HSpacing (0.3), `Frame (label, `HBox (
`IntField (`id (id + "d"), _("Days"), 0, max, days),
`IntField (`id (id + "h"), _("Hours"), 0, 23, hours),
`IntField (`id (id + "m"), _("Minutes"), 0, 59, minutes),
`IntField (`id (id + "s"), _("Seconds"), 0, 59, value)
)), `HSpacing (0.3));
}
integer get_seconds_value (string attr) {
integer days = (integer) UI::QueryWidget (`id (attr + "d"), `Value);
integer hours = (integer) UI::QueryWidget (`id (attr + "h"), `Value);
integer minutes = (integer) UI::QueryWidget (`id (attr + "m"), `Value);
integer seconds = (integer) UI::QueryWidget (`id (attr + "s"), `Value);
return (days * 24*60*60) + (hours * 60*60) + (minutes *60) + seconds;
}
// generate the term of password aging tab
void set_aging_policies_term () {
term tab_cont = `Top (`HBox (`HSpacing (0.5), `VBox (
`VSpacing (0.7),
// frame label
time_dialog ("pwdMinAge", _("Minimum Password Age")),
`VSpacing (0.4),
// frame label
time_dialog ("pwdMaxAge", _("Maximum Password Age")),
`VSpacing (0.4),
time_dialog ("pwdExpireWarning",
// frame label
_("Time before Password Expiration to Issue Warning")),
`VSpacing (0.2),
`IntField (`id ("pwdGraceAuthNLimit"),
// IntField label
_("Allowed Uses of an Expired Password"), 0, max,
tointeger (ppolicy["pwdGraceAuthNLimit"]:"0")
)
), `HSpacing (0.5)));
UI::ReplaceWidget (`tabContents, tab_cont);
return;
}
// generate the term of lockout aging tab
void set_lockout_policies_term () {
boolean pwdlockout = ppolicy["pwdLockout"]:false;
term tab_cont = `Top (`HBox (`HSpacing (0.5), `VBox (
`VSpacing (0.8),
`Left (`CheckBox (`id ("pwdLockout"), `opt (`notify),
// check box label
_("Enable Password Locking"),
pwdlockout)),
`VSpacing (0.4),
`IntField (`id ("pwdMaxFailure"),
// intField label
_("Bind Failures to Lock the Password"),
0, max, tointeger (ppolicy["pwdMaxFailure"]:"0")),
// frame label
time_dialog ("pwdLockoutDuration", _("Password Lock Duration")),
`VSpacing (0.4),
time_dialog ("pwdFailureCountInterval",
// frame label
_("Bind Failures Cache Duration"))
), `HSpacing (0.5)));
UI::ReplaceWidget (`tabContents, tab_cont);
UI::ChangeWidget (`id ("pwdMaxFailure"), `Enabled, pwdlockout);
foreach (string suffix, [ "d", "h", "m", "s" ], {
UI::ChangeWidget (`id ("pwdLockoutDuration" + suffix),
`Enabled, pwdlockout);
UI::ChangeWidget (`id ("pwdFailureCountInterval" + suffix),
`Enabled, pwdlockout);
});
return;
}
symbol current_tab = `pwchange;
any result = nil;
Wizard::OpenNextBackDialog ();
// dialog label
Wizard::SetContentsButtons (_("Password Policy Configuration"), contents,
help_text + tabs_help_text[current_tab]:"",
Label::CancelButton(), Label::OKButton());
Wizard::HideAbortButton();
set_password_policies_term ();
while (true)
{
result = UI::UserInput ();
if (is(result,symbol) &&
contains ([`back, `cancel, `abort], (symbol)result))
break;
// save the values from UI
foreach (string attr, attributes[current_tab]:[], {
if (contains (time_attributes, attr))
{
ppolicy[attr] = sformat ("%1", get_seconds_value (attr));
return;
}
any val = UI::QueryWidget (`id (attr), `Value);
if (is (val, integer))
val = sformat ("%1", val);
ppolicy[attr] = val;
});
if ((result == `pwchange || result == `aging || result == `lockout) &&
result!= current_tab)
{
if (result == `pwchange)
set_password_policies_term ();
else if (result == `aging)
set_aging_policies_term ();
else if (result == `lockout)
set_lockout_policies_term ();
current_tab = (symbol) result;
if (has_tabs)
UI::ChangeWidget (`id (`tabs), `CurrentItem, current_tab);
Wizard::SetHelpText (help_text + tabs_help_text[current_tab]:"");
continue;
}
if (result == `next)
{
boolean cont = false;
// check the template required attributes...
foreach (string oc, ppolicy["objectClass"]:[], ``{
if (cont) return;
foreach (string attr, Ldap::GetRequiredAttributes (oc), ``{
any val = ppolicy[attr]:nil;
if (!cont && val == nil || val == [] || val == "") {
//error popup, %1 is attribute name
Popup::Error (sformat (_("The \"%1\" attribute is mandatory.
Enter a value."), attr));
UI::SetFocus (`id(`table));
cont = true;
}
});
});
if (cont) continue;
break;
}
// now solve events inside the tabs
if (current_tab == `pwchange && is (result, integer))
{
UI::ChangeWidget (`id ("pwdMinLength"), `Enabled, result != 0);
}
if (current_tab == `lockout && result == "pwdLockout")
{
boolean pwdlockout = (boolean) UI::QueryWidget (`id ("pwdLockout"), `Value);
UI::ChangeWidget (`id ("pwdMaxFailure"), `Enabled, pwdlockout);
foreach (string suffix, [ "d", "h", "m", "s" ], {
UI::ChangeWidget (`id ("pwdFailureCountInterval" + suffix),
`Enabled, pwdlockout);
UI::ChangeWidget (`id ("pwdLockoutDuration" + suffix),
`Enabled, pwdlockout);
});
}
}
Wizard::CloseDialog ();
map<string,any> ret = $[];
if (result == `next)
{
foreach (string key, any val, (map<string,any>) ppolicy, {
if (!haskey (ppolicy_orig, key) &&
(val == default_values[key]:nil || val == "0"))
return;
if (val != ppolicy_orig[key]:nil)
{
if (is (val, boolean))
val = (val == true) ? "TRUE" : "FALSE";
ret[key] = val;
}
});
}
return (result == `next) ? ret : nil;
}
}//EOF
ACC SHELL 2018