Commit 153afed877

Jakub Konka <kubkon@jakubkonka.com>
2022-11-25 22:26:19
windows: impl some primitives for getting registry keys
1 parent e74b6f0
Changed files (3)
lib
std
lib/std/os/windows/ntdll.zig
@@ -253,3 +253,9 @@ pub extern "ntdll" fn NtUnlockFile(
     Length: *const LARGE_INTEGER,
     Key: ?*ULONG,
 ) callconv(WINAPI) NTSTATUS;
+
+pub extern "ntdll" fn NtOpenKey(
+    KeyHandle: *HANDLE,
+    DesiredAccess: ACCESS_MASK,
+    ObjectAttributes: OBJECT_ATTRIBUTES,
+) callconv(WINAPI) NTSTATUS;
lib/std/os/windows.zig
@@ -2504,6 +2504,7 @@ pub const STANDARD_RIGHTS_READ = READ_CONTROL;
 pub const STANDARD_RIGHTS_WRITE = READ_CONTROL;
 pub const STANDARD_RIGHTS_EXECUTE = READ_CONTROL;
 pub const STANDARD_RIGHTS_REQUIRED = DELETE | READ_CONTROL | WRITE_DAC | WRITE_OWNER;
+pub const MAXIMUM_ALLOWED = 0x02000000;
 
 // disposition for NtCreateFile
 pub const FILE_SUPERSEDE = 0;
@@ -2872,9 +2873,11 @@ pub const PROV_RSA_FULL = 1;
 
 pub const REGSAM = ACCESS_MASK;
 pub const ACCESS_MASK = DWORD;
-pub const HKEY = *opaque {};
 pub const LSTATUS = LONG;
 
+pub const HKEY = HANDLE;
+pub const HKEY_LOCAL_MACHINE: HKEY = @intToPtr(HKEY, 0x80000002);
+
 pub const FILE_NOTIFY_INFORMATION = extern struct {
     NextEntryOffset: DWORD,
     Action: DWORD,
@@ -4017,3 +4020,187 @@ pub fn IsProcessorFeaturePresent(feature: PF) bool {
     if (@enumToInt(feature) >= PROCESSOR_FEATURE_MAX) return false;
     return SharedUserData.ProcessorFeatures[@enumToInt(feature)] == 1;
 }
+
+pub const KEY_QUERY_VALUE = 0x0001;
+
+/// Open symbolic link.
+pub const REG_OPTION_OPEN_LINK: DWORD = 0x8;
+
+inline fn IsPredefKey(hkey: HKEY) bool {
+    return @ptrToInt(hkey) & 0xF0000000 == 0x80000000;
+}
+
+inline fn GetPredefKeyIndex(hkey: HKEY) usize {
+    return @ptrToInt(hkey) & 0x0FFFFFFF;
+}
+
+inline fn ClosePredefKey(hkey: HKEY) void {
+    if (@ptrToInt(hkey) & 0x1 != 0) {
+        assert(ntdll.NtClose(hkey) == .SUCCESS);
+    }
+}
+
+const MAX_DEFAULT_HANDLES = 6;
+pub const REG_MAX_NAME_SIZE = 256;
+
+pub const RegOpenKeyOpts = struct {
+    ulOptions: DWORD = 0,
+    samDesired: ACCESS_MASK = KEY_QUERY_VALUE,
+};
+
+/// Pulls existing key from the registry.
+pub fn RegOpenKey(hkey: HKEY, lpSubKey: []const u16, opts: RegOpenKeyOpts) !HKEY {
+    if (IsPredefKey(hkey) and lpSubKey.len == 0) {
+        return hkey;
+    }
+
+    const key_handle = try MapDefaultKey(hkey);
+    defer ClosePredefKey(key_handle);
+
+    var subkey_string: UNICODE_STRING = undefined;
+    if (lpSubKey.len == 0 or mem.eql(u16, &[_]u16{'\\'}, lpSubKey)) {
+        subkey_string = .{
+            .Length = 0,
+            .MaximumLength = 0,
+            .Buffer = @intToPtr([*]u16, @ptrToInt(&[0]u16{})),
+        };
+    } else {
+        const len_bytes = math.cast(u16, lpSubKey.len * 2) orelse return error.NameTooLong;
+        subkey_string = .{
+            .Length = len_bytes,
+            .MaximumLength = len_bytes,
+            .Buffer = @intToPtr([*]u16, @ptrToInt(lpSubKey.ptr)),
+        };
+    }
+
+    var attributes: ULONG = OBJ_CASE_INSENSITIVE;
+    if (opts.ulOptions & REG_OPTION_OPEN_LINK != 0) {
+        attributes |= OBJ_OPENLINK;
+    }
+
+    var attr = OBJECT_ATTRIBUTES{
+        .Length = @sizeOf(OBJECT_ATTRIBUTES),
+        .RootDirectory = key_handle,
+        .Attributes = attributes,
+        .ObjectName = &subkey_string,
+        .SecurityDescriptor = null,
+        .SecurityQualityOfService = null,
+    };
+
+    var result: HKEY = undefined;
+    const rc = ntdll.NtOpenKey(
+        &result,
+        opts.samDesired,
+        attr,
+    );
+    switch (rc) {
+        .SUCCESS => return result,
+        else => return unexpectedStatus(rc),
+    }
+}
+
+pub fn RegCloseKey(hkey: HKEY) void {
+    if (IsPredefKey(hkey)) return;
+    assert(ntdll.NtClose(hkey) == .SUCCESS);
+}
+
+extern var DefaultHandleHKUDisabled: BOOLEAN;
+extern var DefaultHandlesDisabled: BOOLEAN;
+extern var DefaultHandleTable: [MAX_DEFAULT_HANDLES]?HANDLE;
+
+fn MapDefaultKey(key: HKEY) !HANDLE {
+    if (!IsPredefKey(key)) return @intToPtr(HANDLE, @ptrToInt(key) & ~@as(usize, 0x1));
+
+    const index = GetPredefKeyIndex(key);
+    if (index >= MAX_DEFAULT_HANDLES) {
+        return error.InvalidParameter;
+    }
+
+    const def_disabled = if (key == HKEY_LOCAL_MACHINE) DefaultHandleHKUDisabled else DefaultHandlesDisabled;
+
+    var handle: HANDLE = undefined;
+    var do_open: bool = true;
+
+    if (def_disabled != 0) {
+        const tmp = DefaultHandleTable[index];
+        if (tmp) |h| {
+            do_open = false;
+            handle = h;
+        }
+    }
+
+    if (do_open) {
+        handle = try OpenPredefinedKey(index);
+    }
+
+    if (def_disabled == 0) {
+        handle = @intToPtr(HANDLE, @ptrToInt(handle) | 0x1);
+    }
+
+    return handle;
+}
+
+fn OpenPredefinedKey(index: usize) !HANDLE {
+    switch (index) {
+        0 => {
+            // HKEY_CLASSES_ROOT
+            return error.Unimplemented;
+        },
+        1 => {
+            // HKEY_CURRENT_USER
+            return error.Unimplemented;
+        },
+        2 => {
+            // HKEY_LOCAL_MACHINE
+            return OpenLocalMachineKey();
+        },
+        3 => {
+            // HKEY_USERS
+            return error.Unimplemented;
+        },
+        5 => {
+            // HKEY_CURRENT_CONFIG
+            return error.Unimplemented;
+        },
+        6 => {
+            // HKEY_DYN_DATA
+            return error.Unimplemented;
+        },
+        else => {
+            return error.InvalidParameter;
+        },
+    }
+}
+
+fn OpenLocalMachineKey() !HANDLE {
+    const path = "\\Registry\\Machine";
+    var path_u16: [REG_MAX_NAME_SIZE]u16 = undefined;
+    const path_len_u16 = try std.unicode.utf8ToUtf16Le(&path_u16, path);
+    const path_len_bytes = @intCast(u16, path_len_u16 * 2);
+
+    var key_name = UNICODE_STRING{
+        .Length = path_len_bytes,
+        .MaximumLength = path_len_bytes,
+        .Buffer = @intToPtr([*]u16, @ptrToInt(&path_u16)),
+    };
+
+    var attr = OBJECT_ATTRIBUTES{
+        .Length = @sizeOf(OBJECT_ATTRIBUTES),
+        .RootDirectory = null,
+        .Attributes = OBJ_CASE_INSENSITIVE,
+        .ObjectName = &key_name,
+        .SecurityDescriptor = null,
+        .SecurityQualityOfService = null,
+    };
+
+    var result: HKEY = undefined;
+    const rc = ntdll.NtOpenKey(
+        &result,
+        MAXIMUM_ALLOWED,
+        attr,
+    );
+    switch (rc) {
+        .SUCCESS => return result,
+        else => return unexpectedStatus(rc),
+    }
+}
lib/std/target/aarch64.zig
@@ -2252,4 +2252,19 @@ pub const cpu = struct {
             .v8a,
         }),
     };
+
+    pub const microsoft_sq3 = CpuModel{
+        .name = "microsoft_sq3",
+        .llvm_name = "generic",
+        .features = featureSet(&[_]Feature{
+            .aes,
+            .crc,
+            .crypto,
+            .dotprod,
+            .fp_armv8,
+            .lse,
+            .neon,
+            .sha2,
+        }),
+    };
 };