diff --git a/daemon/inspect.ml b/daemon/inspect.ml index 84571f582..e4530d3a1 100644 --- a/daemon/inspect.ml +++ b/daemon/inspect.ml @@ -450,6 +450,13 @@ and inspect_get_windows_current_control_set root = | None -> failwith "not a Windows guest, or CurrentControlSet could not be determined" +and inspect_get_windows_group_policy root = + let root = search_for_root root in + match root.inspection_data.windows_group_policy with + | Some v -> v + | None -> + failwith "not a Windows guest, or software hive could not be parsed" + and inspect_is_live root = false and inspect_is_netinst root = false diff --git a/daemon/inspect_fs_windows.ml b/daemon/inspect_fs_windows.ml index e69ab3e12..fde051c0d 100644 --- a/daemon/inspect_fs_windows.ml +++ b/daemon/inspect_fs_windows.ml @@ -288,6 +288,54 @@ and check_windows_software_registry software_hive data = with Not_found -> () ); + + (* If the Windows guest appears to be using group policy, since + * group policy might be used to restrict driver injection. + * + * XXX If group policy is present, it may be possible to + * remove the restriction on driver injection. Microsoft has + * an article about this: + * https://support.microsoft.com/uk-ua/help/2773300/stop-0x0000007b-error-after-you-use-a-group-policy-setting-to-prevent + * Nikolay Ivanets pointed out that in addition to that you also + * have to delete: + * HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\DeviceInstall\Restrictions + *) + let has_group_policy = + try + (* NB This is a subtly different path from CurrentVersion path + * we used above. + *) + let path = [ "Microsoft"; "Windows"; "CurrentVersion"; "Group Policy"; "History" ] in + let node = get_node h root path in + let children = Hivex.node_children h node in + let children = Array.to_list children in + let children = + List.map (fun child -> Hivex.node_name h child) children in + eprintf "check_windows_software_registry: \ + found HKLM\\SOFTWARE\\%s node with children: [%s]\n" + (String.concat "\\" path) + (String.concat ", " children); + + (* Just assume any children looking like "{}" mean that + * some GPOs were installed. + * + * In future we might want to look for nodes which match: + * History\{}\ where is a small integer (the order + * in which policy objects were applied. + * + * For an example registry containing GPOs, see RHBZ#1219651. + * See also: https://support.microsoft.com/en-us/kb/201453 + *) + let is_gpo_guid name = + let len = String.length name in + len > 3 && name.[0] = '{' && + Char.isxdigit name.[1] && name.[len-1] = '}' + in + List.exists is_gpo_guid children + with + Not_found -> false in + data.windows_group_policy <- Some has_group_policy; + with | Not_found -> if verbose () then diff --git a/daemon/inspect_types.ml b/daemon/inspect_types.ml index 4c20070b9..f4ee5d0db 100644 --- a/daemon/inspect_types.ml +++ b/daemon/inspect_types.ml @@ -54,6 +54,7 @@ and inspection_data = { mutable windows_software_hive : string option; mutable windows_system_hive : string option; mutable windows_current_control_set : string option; + mutable windows_group_policy : bool option; mutable drive_mappings : drive_mapping list; } and os_type = @@ -188,6 +189,8 @@ and string_of_inspection_data data = data.windows_system_hive; Option.iter (fun v -> bpf " windows_current_control_set: %s\n" v) data.windows_current_control_set; + Option.iter (fun v -> bpf " windows_group_policy: %b\n" v) + data.windows_group_policy; if data.drive_mappings <> [] then ( let v = List.map (fun (a, b) -> sprintf "(%s, %s)" a b) data.drive_mappings in @@ -289,6 +292,7 @@ let null_inspection_data = { windows_software_hive = None; windows_system_hive = None; windows_current_control_set = None; + windows_group_policy = None; drive_mappings = []; } let null_inspection_data () = { null_inspection_data with os_type = None } @@ -316,6 +320,8 @@ let merge_inspection_data child parent = merge child.windows_system_hive parent.windows_system_hive; parent.windows_current_control_set <- merge child.windows_current_control_set parent.windows_current_control_set; + parent.windows_group_policy <- + merge child.windows_group_policy parent.windows_group_policy; (* This is what the old C code did, but I doubt that it's correct. *) parent.drive_mappings <- child.drive_mappings @ parent.drive_mappings diff --git a/daemon/inspect_types.mli b/daemon/inspect_types.mli index e42bf213c..4c6579fba 100644 --- a/daemon/inspect_types.mli +++ b/daemon/inspect_types.mli @@ -57,6 +57,7 @@ and inspection_data = { mutable windows_software_hive : string option; mutable windows_system_hive : string option; mutable windows_current_control_set : string option; + mutable windows_group_policy : bool option; mutable drive_mappings : drive_mapping list; } (** During inspection, this data is collected incrementally for each diff --git a/generator/actions_inspection.ml b/generator/actions_inspection.ml index 27e8dceb6..3cf6f7dc2 100644 --- a/generator/actions_inspection.ml +++ b/generator/actions_inspection.ml @@ -521,6 +521,28 @@ hive is a valid Windows Registry hive. You can use C to read or write to the hive. +Please read L for more details.|} }; + + { defaults with + name = "inspect_get_windows_group_policy"; added = (1, 57, 6); + style = RBool "hasgrouppolicy", [String (Mountable, "root")], []; + impl = OCaml "Inspect.inspect_get_windows_group_policy"; + shortdesc = "return if Windows guest has group policy"; + longdesc = {|This returns true if the Windows guest +has group policy. Group policy can interfere with device +driver installation, preventing libguestfs features like +driver injection from working. + +Note that the presence of group policy is only an indication that +there may be a problem with driver installation. As group policy +is extremely complex and covers many different aspects of Windows +configuration, and we make no attempt to parse it, presence of +group policy should only raise a warning. + +This call assumes that the guest is Windows and that the +Registry could be examined by inspection. If this is not +the case then an error is returned. + Please read L for more details.|} }; { defaults with diff --git a/generator/proc_nr.ml b/generator/proc_nr.ml index bea19c5c7..11e7b9d1b 100644 --- a/generator/proc_nr.ml +++ b/generator/proc_nr.ml @@ -523,6 +523,7 @@ let proc_nr = [ 518, "btrfs_scrub_full"; 519, "setfiles"; 520, "ntfs_chmod"; +521, "inspect_get_windows_group_policy"; ] (* End of list. If adding a new entry, add it at the end of the list diff --git a/lib/MAX_PROC_NR b/lib/MAX_PROC_NR index 2596e4ad8..5a232f264 100644 --- a/lib/MAX_PROC_NR +++ b/lib/MAX_PROC_NR @@ -1 +1 @@ -520 +521