ACC SHELL
/**
* File: clients/inst_user_first.ycp
* Package: Configuration of users and groups
* Summary: Dialog for creating the first user during installation
* Authors: Jiri Suchomel <jsuchome@suse.cz>
*
* $Id: inst_user_first.ycp 61042 2010-02-26 13:48:03Z jsuchome $
*/
{
import "Directory";
import "GetInstArgs";
import "Label";
import "Mode";
import "Popup";
import "Stage";
import "Package";
import "ProductControl";
import "ProductFeatures";
import "Progress";
import "Report";
import "String";
import "UsersSimple";
import "Wizard";
textdomain "users";
map display_info = UI::GetDisplayInfo ();
boolean text_mode = display_info["TextMode"]:false;
boolean check_CA_constraints =
(ProductFeatures::GetBooleanFeature ("globals","root_password_ca_check") == true);
// minimal pw length for CA-management (F#300438)
integer pw_min_CA = 4;
// full info about imported users
map<string,map> imported_users = $[];
// user names of imported users
list<string> user_names = [];
// names of imported users selected for writing
list<string> to_import = [];
// if importing users from different partition is possible
boolean import_available = UsersSimple::ImportAvailable ();
if (!GetInstArgs::going_back() && import_available)
{
imported_users = (map<string,map>)
UsersSimple::GetImportedUsers ("local");
user_names = maplist (string name, map u, imported_users,``(name));
if (size (user_names) < 1)
{
y2milestone ("No users to import");
import_available = false;
}
}
// check if LDAP/Kerberos are available
UsersSimple::CheckNetworkMethodsAvailability ();
// do not open package progress wizard window
boolean progress_orig = Progress::set (false);
string auth_method = UsersSimple::AfterAuth ();
string encryption_method = UsersSimple::EncryptionMethod ();
boolean use_kerberos = UsersSimple::KerberosConfiguration ();
map button_labels = $[
// radiobutton to select ldap user auth.
"ldap": _("&LDAP"),
// radiobutton to select nis user auth.
"nis": _("N&IS"),
// radiobutton to select samba user auth.
"samba": _("&Windows Domain"),
// radiobutton to select local user auth.
"users": _("L&ocal (/etc/passwd)"),
// radiobutton to select local user auth.
"edir_ldap": _("&eDirectory LDAP"),
// radiobutton to select local user auth.
"users": _("L&ocal (/etc/passwd)"),
];
map auth2label = $[
// authentication type
"ldap": _("LDAP"),
// authentication type
"nis": _("NIS"),
// authentication type
"samba": _("Samba (Windows Domain)"),
// authentication type
"edir_ldap": _("eDirectory LDAP"),
];
map<string,string> encoding2label = $[
// encryption type
"des" : _("DES"),
// encryption type
"md5" : _("MD5"),
// encryption type
"blowfish" : _("Blowfish"),
];
term import_checkbox = `Left (`CheckBox (`id (`import_ch),
// check box label
_("&Read User Data from a Previous Installation")
));
// button label
term import_button = `PushButton (`id(`import), _("&Choose"));
term buttons = `VBox (`VSpacing(0.5));
list<string> available_clients = filter (string client,
[ "ldap", "nis", "samba", "edir_ldap" ], {
string package = sformat ("yast2-%1-client", client);
if (client == "edir_ldap")
package = "yast2-linux-user-mgmt";
return Mode::normal () || Package::Available (package) == true ||
// during Mode::live_installation, available = installed
(Mode::live_installation () && Package::Installed (package));
});
available_clients = prepend (available_clients, "users");
foreach (string client, available_clients, {
if (client == "users" && import_available)
buttons = add (buttons, `VBox (
`Left (`RadioButton (
`id(client), `opt (`notify), button_labels[client]:""
)),
`HBox (
`HSpacing (3),
text_mode ?
`VBox (import_checkbox, `Left (import_button)) :
`HBox (import_checkbox, import_button)
)
));
else
buttons = add (buttons, `Left (`RadioButton (
`id(client), `opt (`notify), button_labels[client]:"")
));
});
buttons = add (buttons, `VSpacing(0.5));
term auth_term = `VBox (
`Frame (_("Authentication Method"),
`RadioButtonGroup (`id (`auth_method), buttons)
),
`VSpacing (),
// check box label
`Left (`CheckBox (`id(`krb), _("Set Up &Kerberos Authentication")))
);
// frame label
term encryption_term = `Frame (_("Password Encryption Type"),
`RadioButtonGroup (`id (`encryption_method), `VBox (
`VSpacing (0.5),
// Radio button label: password encryption type
`Left (`RadioButton (`id ("des"), _("&DES (Linux default)"))),
// Radio button label: password encryption type
`Left (`RadioButton (`id ("md5"), _("&MD5"))),
// Radio button label: password encryption type
`Left (`RadioButton (`id ("blowfish"), _("&Blowfish"))),
`VSpacing (0.5)
))
);
// help text for dialog "User Authentication Method" 1/3
string auth_help = _("<p>
<b>Authentication</b><br>
Select the authentication method to use for users on your system.
</p>") +
// helptext 2/3
_("<p>Select <b>Local</b> to authenticate users only by using the local files <i>/etc/passwd</i> and <i>/etc/shadow</i>.</p>");
auth_help = auth_help +
// helptext 3/3 -- nis & samba & ldap avialable
_("<p>If you are using a NIS or LDAP server to store user data or if you want
to authenticate users against an NT server, choose the appropriate value.</p>") +
// helptext: additional kerberos support
_("<p>Check <b>Set Up Kerberos Authentication</b> to configure Kerberos after configuring the user data source.</p>");
// Help text for password expert dialog
string encryption_help = _("<p>
Choose a password encryption method for local and system users.
<b>DES</b>, the Linux default method, works in all network environments, but it
restricts passwords to eight characters or less.
</p>
") +
// Help text for password expert dialog
_("<p>
<b>MD5</b> allows longer passwords, so provides more security, but some
network protocols do not support this and you may have problems with NIS.
</p>") +
// Help text for password expert dialog
_("<p>
<b>Blowfish</b> is similar to MD5, but uses a different algorithm
to encrypt passwords.
</P>");
// help text for main add user dialog
string main_help () {
// help text for main add user dialog
string help = _("<p>
Enter the <b>User's Full Name</b>, <b>Username</b>, and <b>Password</b> to
assign to this user account.
</p>
") +
// help text for main add user dialog
_("<p>
When entering a password, distinguish between uppercase and
lowercase. Passwords should not contain any accented characters or umlauts.
</p>
") +
// help text %1 is encryption type, %2,%3 numbers
sformat (_("<p>
With the current password encryption (%1), the password length should be between
%2 and %3 characters.
</p>"),
encoding2label[encryption_method]:encryption_method,
UsersSimple::GetMinPasswordLength ("local"),
UsersSimple::GetMaxPasswordLength ("local")
) +
UsersSimple::ValidPasswordHelptext ();
if (check_CA_constraints)
help = help + sformat (
// additional help text about password
_("<p>If you intend to use this password for creating certificates,
it has to be at least %1 characters long.</p>"), pw_min_CA);
help = help +
// help text for main add user dialog
_("<p>
To ensure that the password was entered correctly,
repeat it exactly in a second field. Do not forget your password.
</p>
") +
// help text for main add user dialog
_("<p>
For the <b>Username</b> use only letters (no accented characters), digits, and <tt>._-</tt>.
Do not use uppercase letters in this entry unless you know what you are doing.
Usernames have stricter restrictions than passwords. You can redefine the
restrictions in the /etc/login.defs file. Read its man page for information.
</p>
") +
// help text for main add user dialog
_("<p>Check <b>Use this password for system administrator</b> if the same password as entered for the first user should be used for root.</p>") +
// help text for main add user dialog
_("<p>
The username and password created here are needed to log in and work with your Linux system. With <b>Automatic Login</b> enabled, the login procedure is skipped. This user is logged in automatically.</p>
") +
// help text for main add user dialog
_("<p>
Have mail for root forwarded to this user by checking <b>Receive System Mail</b>.</p>
");
return help;
}
/**
* Helper function: ask user which users to import
*/
list<string> choose_to_import (list<string> all, list<string> selected) {
list items = maplist (string u, all, ``(
`item (`id (u), u, contains (selected, u))
));
boolean all_checked = (size (all) == size (selected)) && size (all) > 0;
integer vsize = size (all) + 3;
if (vsize > 15) vsize = 15;
UI::OpenDialog (`opt(`decorated), `HBox(`VSpacing (vsize), `VBox (
`HSpacing(50),
`MultiSelectionBox (`id(`userlist),
// selection box label
_("&Select Users to Read"), items),
`Left (`CheckBox (`id(`all), `opt(`notify),
// check box label
_("Select or Deselect &All"), all_checked
)),
`HBox (
`PushButton (`id(`ok), `opt(`default), Label::OKButton()),
`PushButton (`id(`cancel), Label::CancelButton())
)
)));
any ret = nil;
while (true)
{
ret = UI::UserInput ();
if (ret == `all)
{
boolean ch = (boolean)UI::QueryWidget (`id(`all),`Value);
if (ch != all_checked)
{
UI::ChangeWidget (`id(`userlist), `Items,
maplist (string u, all, ``(`item (`id (u), u, ch)))
);
all_checked = ch;
}
}
if (ret == `ok || ret == `cancel)
break;
}
if (ret == `ok)
{
selected = (list<string>)
UI::QueryWidget(`id(`userlist),`SelectedItems);
}
UI::CloseDialog ();
return ret == `ok ? selected : nil;
}
/**
* Dialog for expert user settings: authentication method as well
* as password encryption (see fate 302980)
* @return true if user accepted expert settings
*/
boolean ExpertDialog () {
term contents = `HBox (
`HWeight (1, `HBox ()),
`HWeight (9, `HBox (`VBox (
`VStretch (),
auth_term,
`VSpacing (),
encryption_term,
`VStretch ()
))),
`HWeight (1, `HBox ())
);
Wizard::OpenAcceptDialog ();
Wizard::SetContents (_("Expert Settings"), contents,
auth_help + encryption_help, true, true
);
UI::ChangeWidget (`id (`auth_method), `CurrentButton, auth_method);
UI::ChangeWidget (`id (`encryption_method), `CurrentButton,
encryption_method);
UI::ChangeWidget (`id (`krb), `Value, use_kerberos);
UI::ChangeWidget (`id (`krb), `Enabled,
auth_method != "users" && auth_method != "samba");
foreach (string enc, string l, encoding2label, {
UI::ChangeWidget (`id(enc),`Enabled, auth_method == "users");
});
if (size (to_import) > 0)
UI::ChangeWidget (`id (`import_ch), `Value,
auth_method == "users" && size (to_import) > 0);
any retval = `cancel;
while (true)
{
retval = UI::UserInput ();
if (retval == `import)
{
list<string> selected = choose_to_import (user_names,to_import);
if (selected != nil)
to_import = selected;
UI::ChangeWidget (`id (`import_ch), `Value, size(to_import)> 0);
}
if (is (retval, string) && haskey (button_labels, (string)retval))
{
UI::ChangeWidget (`id(`krb),`Enabled,
retval != "users" && retval != "samba");
foreach (string enc, string l, encoding2label, {
UI::ChangeWidget (`id(enc),`Enabled, retval == "users");
});
UI::ChangeWidget (`id (`import_ch), `Enabled, retval== "users");
UI::ChangeWidget (`id (`import), `Enabled, retval == "users");
}
if (retval == `accept && import_available && to_import == [] &&
UI::QueryWidget (`id(`import_ch), `Value) == true)
{
// force selecting when only checkbox is checked
list<string> selected = choose_to_import (user_names,to_import);
if (selected != nil)
to_import = selected;
else
{
retval = `notnext;
continue;
}
}
if (retval == `cancel || retval == `accept || retval == `back)
break;
}
if (retval == `accept)
{
auth_method = (string)
UI::QueryWidget (`id (`auth_method), `CurrentButton);
encryption_method = (string)
UI::QueryWidget (`id(`encryption_method), `CurrentButton);
UsersSimple::SetEncryptionMethod (encryption_method);
if (auth_method == "users" || auth_method == "samba")
use_kerberos = false;
else
use_kerberos = (boolean) UI::QueryWidget (`id(`krb), `Value);
if (auth_method != "users" ||
UI::QueryWidget (`id (`import_ch), `Value) == false)
to_import = [];
}
Wizard::CloseDialog ();
return (retval == `accept);
}
// build the term with current user configuration status
term get_status_term () {
// summary label
string auth_line = _("The authentication method is local /etc/passwd.");
// summary label
string details_line =sformat(_("The password encryption method is %1."),
encoding2label[encryption_method]:encryption_method);
term imported_term = `Empty ();
if (auth_method != "users")
{
// summary line: %1 is LDAP/NIS etc.
auth_line = sformat (_("The authentication method is %1."),
auth2label[auth_method]:auth_method);
if (use_kerberos)
// summary line: %1 is LDAP/NIS etc.
auth_line = sformat (_("The authentication method is %1 and Kerberos."), auth2label[auth_method]:auth_method);
// // summary label
details_line = _("The configuration will be available later during the installation.");
}
else if (to_import != [])
{
// summary label, %1 are user names (comma separated)
string imported = sformat (_("Users %1 will be imported."),
mergestring (to_import, ","));
if (size (to_import) == 1)
// summary label, %1 is user name
imported = sformat (_("User %1 will be imported."),
to_import[0]:"");
if (text_mode)
auth_line = auth_line + "<br>" + imported;
else
imported_term = `Left (`Label (imported));
}
term status = text_mode ?
`RichText (auth_line + "<br>" + details_line) :
`VBox (
`Left (`Label (auth_line)),
imported_term,
`Left (`Label (details_line))
);
term button = `HBox (
// pushbutton label
`Right (`PushButton (`id(`change),_("&Change..."))));
return text_mode ?
`VBox (
status,
button
) :
// frame label
`Frame (_("Summary"), `HBox (`HSpacing (0.2), `VBox (
status,
button,
`VSpacing (0.2)
)));
}
list<map> users = (list<map>) UsersSimple::GetUsers ();
map<string,any>user = $[];
if (size (users) > 1)
{
to_import = maplist (map u, users, ``(u["uid"]:""));
}
if (size (users) == 1)
{
if (users[0,"__imported"]:nil != nil)
to_import = [ users[0,"uid"]:"" ];
else
user = (map<string,any>) users[0]:$[];
}
string user_type = user["type"]:"local";
string username = user["uid"]:"";
string cn = user["cn"]:"";
string password = (string)user["userPassword"]:nil;
boolean autologin = UsersSimple::AutologinUsed ();
// set the initial default value for autologin
if (user == $[] && !autologin)
{
if (ProductFeatures::GetBooleanFeature ("globals", "enable_autologin") == true)
autologin = true;
y2debug ("autologin default value: %1", autologin);
}
boolean root_pw = (UsersSimple::GetRootPassword () == password);
// set the initial default value for root pw checkbox
if (user == $[] && !root_pw)
{
if (ProductFeatures::GetBooleanFeature ("globals", "root_password_as_first_user") == true)
root_pw = true;
y2debug ("root_pw default value: %1", root_pw);
}
map args = GetInstArgs::argmap ();
// indication that client was called directly from proposal
boolean root_dialog_follows = args["root_dialog_follows"]:true;
// this user gets root's mail
boolean root_mail =
(username != "" && UsersSimple::GetRootAlias () == username);
term fields = `VBox (
`InputField (`id (`cn), `opt (`notify, `hstretch),
// text entry
_("User's &Full Name"), cn),
`InputField (`id (`username), `opt (`notify, `hstretch),
// input field for login name
_("&Username"),username),
`Password (`id (`pw1), `opt (`hstretch), Label::Password(),
password == nil ? "" : password),
`Password (`id (`pw2), `opt (`hstretch), Label::ConfirmPassword(),
password == nil ? "" : password)
);
term optionbox = `VBox (
`Left (`CheckBox (`id (`root_pw),
// checkbox label
_("U&se this password for system administrator"), root_pw)
),
`Left (
// checkbox label
`CheckBox (`id (`root_mail), _("Receive S&ystem Mail"), root_mail)
),
// checkbox label
`Left (`CheckBox (`id (`autologin), _("&Automatic Login"), autologin))
);
term contents = `HBox (
`HCenter (`HSquash (`VBox (
`VStretch (),
fields,
`VSpacing (0.2),
optionbox,
`VSpacing (),
`ReplacePoint (`id (`rp_status), get_status_term ()),
`VStretch ()
)))
);
if (Mode::normal ()) Wizard::CreateDialog (); // for testing only
Wizard::SetTitleIcon("yast-users");
// dialog caption
Wizard::SetContents (_("Create New User"), contents,
main_help (),
GetInstArgs::enable_back(), GetInstArgs::enable_next() || Mode::normal()
);
foreach (symbol w, [`cn, `username, `pw1, `pw2, `root_pw, `root_mail,
`autologin ], {
UI::ChangeWidget (`id (w), `Enabled,
auth_method == "users" && to_import == []);
});
if (auth_method == "users")
UI::SetFocus (`id (`cn));
else
UI::SetFocus (`id (`change));
boolean login_modified = false;
symbol ret = `back;
while (true)
{
ret = (symbol) UI::UserInput ();
if (ret == `change)
{
if (ExpertDialog ())
{
// show correct values now
UI::ReplaceWidget (`id (`rp_status), get_status_term ());
foreach (symbol w, [`cn, `username, `pw1, `pw2, `root_pw,
`root_mail, `autologin ], {
UI::ChangeWidget (`id (w), `Enabled,
auth_method == "users" && to_import == []);
});
Wizard::RestoreHelp (main_help ());
}
}
if (ret == `cn)
{
string uname = (string)UI::QueryWidget (`id (`username), `Value);
if (login_modified && uname == "")
login_modified = false; // reenable suggestion
if (!login_modified)
{
string full = (string)UI::QueryWidget (`id (`cn), `Value);
full = splitstring (full, " ")[0]:"";
full = UsersSimple::Transliterate (full);
UI::ChangeWidget (`id (`username), `Value, tolower (
filterchars (full, UsersSimple::ValidLognameChars ()))
);
}
}
if (ret == `username)
{
login_modified = true;
}
if (ret == `accept) // from proposal
ret = `next;
if (ret == `next)
{
string error = "";
// map returned from Check*UI functions
map error_map = $[];
// map with id's of confirmed questions
map<string,any> ui_map = $[];
// --------------------------------- username checks
username = (string) UI::QueryWidget (`id (`username), `Value);
if (auth_method != "users" || to_import != [])
{
break;
}
if (username == "")
{
// when 2nd stage is enabled, there will be inst_auth anyway
if (
(!Mode::live_installation () && ProductControl::GetUseAutomaticConfiguration () == false) ||
// yes-no popup headline
Popup::YesNoHeadline(_("Empty User Login"),
// yes-no popup contents
_("Leaving the user name empty only makes sense
in a network environment with an authentication server.
Leave it empty?")))
{
break;
}
else
continue;
}
error = UsersSimple::CheckUsernameLength (username);
if (error != "")
{
Report::Error (error);
UI::SetFocus (`id (`username));
continue;
}
error = UsersSimple::CheckUsernameContents (username, "");
if (error != "")
{
Report::Error (error);
UI::SetFocus (`id (`username));
continue;
}
error = UsersSimple::CheckUsernameConflicts (username);
if (error != "")
{
Report::Error (error);
UI::SetFocus (`id (`username));
continue;
}
// --------------------------------- full name checks
cn = (string) UI::QueryWidget(`id(`cn), `Value);
error = UsersSimple::CheckFullname (cn);
if (error != "")
{
Report::Error (error);
UI::SetFocus (`id (`cn));
continue;
}
// --------------------------------- password checks
string pw1 = (string) UI::QueryWidget(`id(`pw1), `Value);
string pw2 = (string) UI::QueryWidget(`id(`pw2),`Value);
root_pw = (boolean) UI::QueryWidget (`id (`root_pw),`Value);
if (pw1 != pw2)
{
// The two group password information do not match
// error popup
Report::Error(_("The passwords do not match.
Try again.")) ;
UI::SetFocus (`id (`pw1));
continue;
}
error = UsersSimple::CheckPassword (pw1, "local");
if (error != "")
{
Report::Error (error);
UI::SetFocus (`id (`pw1));
continue;
}
if (!UsersSimple::LoadCracklib ())
{
y2error ("loading cracklib failed, not used for pw check");
UsersSimple::UseCrackLib (false);
}
list<string> errors = UsersSimple::CheckPasswordUI ($[
"uid" : username,
"userPassword" : pw1,
"type" : "local",
]);
if (root_pw && check_CA_constraints && (size (pw1) < pw_min_CA))
{
errors = add (errors, sformat (
// yes/no popup question, %1 is a number
_("If you intend to create certificates,
the password should have at least %1 characters."), pw_min_CA));
}
if (errors != [])
{
string message = mergestring (errors, "\n\n") +
// last part of message popup
"\n\n" + _("Really use this password?");
if (!Popup::YesNo (message))
{
ret = `notnext;
UI::SetFocus (`id (`pw1));
continue;
}
}
// set UID if home directory is found on future home partition
password = pw1;
}
if (contains ([`back, `abort, `cancel, `next], ret))
break;
}
if (ret == `next)
{
UsersSimple::SetAfterAuth (auth_method);
UsersSimple::SetKerberosConfiguration (use_kerberos);
if (auth_method == "users" && to_import != [])
{
list create_users = [];
foreach (string name, to_import, {
map u = imported_users[name]:$[];
u["__imported"] = true;
create_users = add (create_users, u);
});
UsersSimple::SetUsers (create_users);
UsersSimple::SkipRootPasswordDialog (false);
if (root_dialog_follows)
UsersSimple::SetRootPassword ("");
UsersSimple::SetAutologinUser ("");
UsersSimple::SetRootAlias ("");
}
else if (auth_method == "users" && username != "")
{
// save the first user data
map<string,any> user_map = $[
"uid" : username,
"userPassword" : password,
"cn" : cn
];
UsersSimple::SetUsers ([user_map]);
UsersSimple::SkipRootPasswordDialog (root_pw);
if (root_dialog_follows || root_pw)
UsersSimple::SetRootPassword (root_pw ? password : "");
UsersSimple::SetAutologinUser (
(UI::QueryWidget(`id (`autologin),`Value)==true) ? username : ""
);
UsersSimple::SetRootAlias (
(UI::QueryWidget (`id (`root_mail), `Value) == true) ?
username : ""
);
}
else if (auth_method != "users")
{
// preselect the required packages for installation
y2milestone ("preselect required packages for installation");
map<string,list<string> > required_packages = $[
"ldap" : [ "yast2-ldap-client", "pam_ldap", "nss_ldap"],
"nis" : [ "yast2-nis-client", "ypbind" ],
"samba" : [
"yast2-samba-client", "krb5", "samba-client",
"samba-winbind"
],
];
foreach (string package, required_packages[auth_method]:[], {
Pkg::ResolvableInstall (package, `package);
});
}
if (use_kerberos)
{
foreach (string package, ["pam_krb5", "krb5", "krb5-client"], {
Pkg::ResolvableInstall (package, `package);
});
}
if (root_pw)
{
UsersSimple::UnLoadCracklib ();
}
}
else if (ret == `back)
{
// reset to defaults
UsersSimple::SetAutologinUser ("");
UsersSimple::SetRootAlias ("");
UsersSimple::SetRootPassword ("");
UsersSimple::SetUsers ([]);
}
if (Mode::normal ()) Wizard::CloseDialog ();
Progress::set (progress_orig);
return ret;
}
ACC SHELL 2018