From 1766c2ef9f6fe7b87d0d6c12c80c11445d6addb7 Mon Sep 17 00:00:00 2001 From: "Richard W.M. Jones" Date: Thu, 21 Nov 2013 17:13:22 +0000 Subject: [PATCH] builder/sysprep: Allow accounts to be locked (RHBZ#1028660). This allows you to select both locked accounts and disabled passwords. The two are subtly different concepts. A locked account [cf. passwd -l] puts "!!" at the beginning of the shadow password field. Locking is reversible, because the "!!" can be removed, restoring the original password. Therefore "locked" acts as a flag in front of an existing selector. A disabled account has "*" in the password field. Therefore it has no password. Note that an account may be both locked and disabled, although this is probably not useful. The shadow password field will contain "!!*". (cherry picked from commit 3712249f9659121277a0d2ca0549e02bc38e0cad) --- builder/builder.ml | 2 +- builder/virt-builder.pod | 21 +++++++++++++++ mllib/password.ml | 49 ++++++++++++++++++++++++++--------- mllib/password.mli | 11 +++++--- sysprep/sysprep_operation_password.ml | 33 +++++++++++++++++++++++ 5 files changed, 100 insertions(+), 16 deletions(-) diff --git a/builder/builder.ml b/builder/builder.ml index 541eb60..2710f10 100644 --- a/builder/builder.ml +++ b/builder/builder.ml @@ -458,7 +458,7 @@ let main () = pw | None -> msg (f_"Setting random root password [did you mean to use --root-password?]"); - Password.Set_random_password in + parse_selector ~prog "random" in Hashtbl.replace password_map "root" pw; set_linux_passwords ~prog ?password_crypto g root password_map | _ -> diff --git a/builder/virt-builder.pod b/builder/virt-builder.pod index 7b74bdb..4bb9f64 100644 --- a/builder/virt-builder.pod +++ b/builder/virt-builder.pod @@ -712,6 +712,27 @@ has approximately 120 bits of randomness. This is the default. +=item B<--root-password> disabled + +The root account password is disabled. This is like putting C<*> +in the password field. + +=item B<--root-password> locked:file:FILENAME + +=item B<--root-password> locked:password:PASSWORD + +=item B<--root-password> locked:random + +The root account is locked, but a password is placed on the +account. If first unlocked (using C) then logins will +use the given password. + +=item B<--root-password> locked + +=item B<--root-password> locked:disabled + +The root account is locked I password is disabled. + =back =head3 Creating user accounts diff --git a/mllib/password.ml b/mllib/password.ml index 99923d7..6527138 100644 --- a/mllib/password.ml +++ b/mllib/password.ml @@ -22,9 +22,14 @@ open Printf type password_crypto = [`MD5 | `SHA256 | `SHA512 ] -type password_selector = -| Set_password of string -| Set_random_password +type password_selector = { + pw_password : password; + pw_locked : bool; +} +and password = +| Password of string +| Random_password +| Disabled_password type password_map = (string, password_selector) Hashtbl.t @@ -45,12 +50,26 @@ let password_crypto_of_string ~prog = function exit 1 let rec parse_selector ~prog arg = - match string_nsplit ":" arg with - | [ "file"; filename ] -> Set_password (read_password_from_file filename) - | "password" :: password -> Set_password (String.concat ":" password) - | [ "random" ] -> Set_random_password + parse_selector_list ~prog arg (string_nsplit ":" arg) + +and parse_selector_list ~prog orig_arg = function + | [ "lock"|"locked" ] -> + { pw_locked = true; pw_password = Disabled_password } + | ("lock"|"locked") :: rest -> + let pw = parse_selector_list ~prog orig_arg rest in + { pw with pw_locked = true } + | [ "file"; filename ] -> + { pw_password = Password (read_password_from_file filename); + pw_locked = false } + | "password" :: password -> + { pw_password = Password (String.concat ":" password); pw_locked = false } + | [ "random" ] -> + { pw_password = Random_password; pw_locked = false } + | [ "disable"|"disabled" ] -> + { pw_password = Disabled_password; pw_locked = false } | _ -> - eprintf (f_"%s: invalid password selector '%s'; see the man page.\n") prog arg; + eprintf (f_"%s: invalid password selector '%s'; see the man page.\n") + prog orig_arg; exit 1 and read_password_from_file filename = @@ -77,7 +96,8 @@ let rec set_linux_passwords ~prog ?password_crypto g root passwords = List.map ( fun line -> try - (* Each line is: "user:password:..." + (* Each line is: "user:[!!]password:..." + * !! at the front of the password field means the account is locked. * 'i' points to the first colon, 'j' to the second colon. *) let i = String.index line ':' in @@ -87,12 +107,17 @@ let rec set_linux_passwords ~prog ?password_crypto g root passwords = let rest = String.sub line j (String.length line - j) in let pwfield = match selector with - | Set_password password -> encrypt password crypto - | Set_random_password -> + | { pw_locked = locked; + pw_password = Password password } -> + if locked then "!!" else "" ^ encrypt password crypto + | { pw_locked = locked; + pw_password = Random_password } -> let password = make_random_password () in printf (f_"Setting random password of %s to %s\n%!") user password; - encrypt password crypto in + if locked then "!!" else "" ^ encrypt password crypto + | { pw_locked = true; pw_password = Disabled_password } -> "!!*" + | { pw_locked = false; pw_password = Disabled_password } -> "*" in user ^ ":" ^ pwfield ^ rest with Not_found -> line ) shadow in diff --git a/mllib/password.mli b/mllib/password.mli index dce9486..c662b1b 100644 --- a/mllib/password.mli +++ b/mllib/password.mli @@ -21,9 +21,14 @@ type password_crypto = [ `MD5 | `SHA256 | `SHA512 ] val password_crypto_of_string : prog:string -> string -> password_crypto (** Parse --password-crypto parameter on command line. *) -type password_selector = -| Set_password of string -| Set_random_password +type password_selector = { + pw_password : password; (** The password. *) + pw_locked : bool; (** If the account should be locked. *) +} +and password = +| Password of string (** Password (literal string). *) +| Random_password (** Choose a random password. *) +| Disabled_password (** [*] in the password field. *) val parse_selector : prog:string -> string -> password_selector (** Parse the selector field in --password/--root-password. Note this diff --git a/sysprep/sysprep_operation_password.ml b/sysprep/sysprep_operation_password.ml index 0cd834a..ef0e985 100644 --- a/sysprep/sysprep_operation_password.ml +++ b/sysprep/sysprep_operation_password.ml @@ -143,6 +143,39 @@ can see the cleartext password using L. Choose a random password, which is printed on stdout. The password has approximately 120 bits of randomness. +=item B<--password> USERNAME:disabled + +=item B<--root-password> disabled + +The account password is disabled. This is like putting C<*> +in the password field. + +=item B<--password> USERNAME:locked:file:FILENAME + +=item B<--password> USERNAME:locked:password:PASSWORD + +=item B<--password> USERNAME:locked:random + +=item B<--root-password> locked:file:FILENAME + +=item B<--root-password> locked:password:PASSWORD + +=item B<--root-password> locked:random + +The account is locked, but a password is placed on the +account. If first unlocked (using C) then logins will +use the given password. + +=item B<--password> USERNAME:locked + +=item B<--password> USERNAME:locked:disabled + +=item B<--root-password> locked + +=item B<--root-password> locked:disabled + +The account is locked I password is disabled. + =back" }; -- 1.8.4.2