| ... | ... | @@ -2504,6 +2504,7 @@ pub const STANDARD_RIGHTS_READ = READ_CONTROL; |
| 2504 | 2504 | pub const STANDARD_RIGHTS_WRITE = READ_CONTROL; |
| 2505 | 2505 | pub const STANDARD_RIGHTS_EXECUTE = READ_CONTROL; |
| 2506 | 2506 | pub const STANDARD_RIGHTS_REQUIRED = DELETE | READ_CONTROL | WRITE_DAC | WRITE_OWNER; |
| 2507 | pub const MAXIMUM_ALLOWED = 0x02000000; |
| 2507 | 2508 | |
| 2508 | 2509 | // disposition for NtCreateFile |
| 2509 | 2510 | pub const FILE_SUPERSEDE = 0; |
| ... | ... | @@ -2872,9 +2873,11 @@ pub const PROV_RSA_FULL = 1; |
| 2872 | 2873 | |
| 2873 | 2874 | pub const REGSAM = ACCESS_MASK; |
| 2874 | 2875 | pub const ACCESS_MASK = DWORD; |
| 2875 | | pub const HKEY = *opaque {}; |
| 2876 | 2876 | pub const LSTATUS = LONG; |
| 2877 | 2877 | |
| 2878 | pub const HKEY = HANDLE; |
| 2879 | pub const HKEY_LOCAL_MACHINE: HKEY = @intToPtr(HKEY, 0x80000002); |
| 2880 | |
| 2878 | 2881 | pub const FILE_NOTIFY_INFORMATION = extern struct { |
| 2879 | 2882 | NextEntryOffset: DWORD, |
| 2880 | 2883 | Action: DWORD, |
| ... | ... | @@ -4017,3 +4020,187 @@ pub fn IsProcessorFeaturePresent(feature: PF) bool { |
| 4017 | 4020 | if (@enumToInt(feature) >= PROCESSOR_FEATURE_MAX) return false; |
| 4018 | 4021 | return SharedUserData.ProcessorFeatures[@enumToInt(feature)] == 1; |
| 4019 | 4022 | } |
| 4023 | |
| 4024 | pub const KEY_QUERY_VALUE = 0x0001; |
| 4025 | |
| 4026 | /// Open symbolic link. |
| 4027 | pub const REG_OPTION_OPEN_LINK: DWORD = 0x8; |
| 4028 | |
| 4029 | inline fn IsPredefKey(hkey: HKEY) bool { |
| 4030 | return @ptrToInt(hkey) & 0xF0000000 == 0x80000000; |
| 4031 | } |
| 4032 | |
| 4033 | inline fn GetPredefKeyIndex(hkey: HKEY) usize { |
| 4034 | return @ptrToInt(hkey) & 0x0FFFFFFF; |
| 4035 | } |
| 4036 | |
| 4037 | inline fn ClosePredefKey(hkey: HKEY) void { |
| 4038 | if (@ptrToInt(hkey) & 0x1 != 0) { |
| 4039 | assert(ntdll.NtClose(hkey) == .SUCCESS); |
| 4040 | } |
| 4041 | } |
| 4042 | |
| 4043 | const MAX_DEFAULT_HANDLES = 6; |
| 4044 | pub const REG_MAX_NAME_SIZE = 256; |
| 4045 | |
| 4046 | pub const RegOpenKeyOpts = struct { |
| 4047 | ulOptions: DWORD = 0, |
| 4048 | samDesired: ACCESS_MASK = KEY_QUERY_VALUE, |
| 4049 | }; |
| 4050 | |
| 4051 | /// Pulls existing key from the registry. |
| 4052 | pub fn RegOpenKey(hkey: HKEY, lpSubKey: []const u16, opts: RegOpenKeyOpts) !HKEY { |
| 4053 | if (IsPredefKey(hkey) and lpSubKey.len == 0) { |
| 4054 | return hkey; |
| 4055 | } |
| 4056 | |
| 4057 | const key_handle = try MapDefaultKey(hkey); |
| 4058 | defer ClosePredefKey(key_handle); |
| 4059 | |
| 4060 | var subkey_string: UNICODE_STRING = undefined; |
| 4061 | if (lpSubKey.len == 0 or mem.eql(u16, &[_]u16{'\\'}, lpSubKey)) { |
| 4062 | subkey_string = .{ |
| 4063 | .Length = 0, |
| 4064 | .MaximumLength = 0, |
| 4065 | .Buffer = @intToPtr([*]u16, @ptrToInt(&[0]u16{})), |
| 4066 | }; |
| 4067 | } else { |
| 4068 | const len_bytes = math.cast(u16, lpSubKey.len * 2) orelse return error.NameTooLong; |
| 4069 | subkey_string = .{ |
| 4070 | .Length = len_bytes, |
| 4071 | .MaximumLength = len_bytes, |
| 4072 | .Buffer = @intToPtr([*]u16, @ptrToInt(lpSubKey.ptr)), |
| 4073 | }; |
| 4074 | } |
| 4075 | |
| 4076 | var attributes: ULONG = OBJ_CASE_INSENSITIVE; |
| 4077 | if (opts.ulOptions & REG_OPTION_OPEN_LINK != 0) { |
| 4078 | attributes |= OBJ_OPENLINK; |
| 4079 | } |
| 4080 | |
| 4081 | var attr = OBJECT_ATTRIBUTES{ |
| 4082 | .Length = @sizeOf(OBJECT_ATTRIBUTES), |
| 4083 | .RootDirectory = key_handle, |
| 4084 | .Attributes = attributes, |
| 4085 | .ObjectName = &subkey_string, |
| 4086 | .SecurityDescriptor = null, |
| 4087 | .SecurityQualityOfService = null, |
| 4088 | }; |
| 4089 | |
| 4090 | var result: HKEY = undefined; |
| 4091 | const rc = ntdll.NtOpenKey( |
| 4092 | &result, |
| 4093 | opts.samDesired, |
| 4094 | attr, |
| 4095 | ); |
| 4096 | switch (rc) { |
| 4097 | .SUCCESS => return result, |
| 4098 | else => return unexpectedStatus(rc), |
| 4099 | } |
| 4100 | } |
| 4101 | |
| 4102 | pub fn RegCloseKey(hkey: HKEY) void { |
| 4103 | if (IsPredefKey(hkey)) return; |
| 4104 | assert(ntdll.NtClose(hkey) == .SUCCESS); |
| 4105 | } |
| 4106 | |
| 4107 | extern var DefaultHandleHKUDisabled: BOOLEAN; |
| 4108 | extern var DefaultHandlesDisabled: BOOLEAN; |
| 4109 | extern var DefaultHandleTable: [MAX_DEFAULT_HANDLES]?HANDLE; |
| 4110 | |
| 4111 | fn MapDefaultKey(key: HKEY) !HANDLE { |
| 4112 | if (!IsPredefKey(key)) return @intToPtr(HANDLE, @ptrToInt(key) & ~@as(usize, 0x1)); |
| 4113 | |
| 4114 | const index = GetPredefKeyIndex(key); |
| 4115 | if (index >= MAX_DEFAULT_HANDLES) { |
| 4116 | return error.InvalidParameter; |
| 4117 | } |
| 4118 | |
| 4119 | const def_disabled = if (key == HKEY_LOCAL_MACHINE) DefaultHandleHKUDisabled else DefaultHandlesDisabled; |
| 4120 | |
| 4121 | var handle: HANDLE = undefined; |
| 4122 | var do_open: bool = true; |
| 4123 | |
| 4124 | if (def_disabled != 0) { |
| 4125 | const tmp = DefaultHandleTable[index]; |
| 4126 | if (tmp) |h| { |
| 4127 | do_open = false; |
| 4128 | handle = h; |
| 4129 | } |
| 4130 | } |
| 4131 | |
| 4132 | if (do_open) { |
| 4133 | handle = try OpenPredefinedKey(index); |
| 4134 | } |
| 4135 | |
| 4136 | if (def_disabled == 0) { |
| 4137 | handle = @intToPtr(HANDLE, @ptrToInt(handle) | 0x1); |
| 4138 | } |
| 4139 | |
| 4140 | return handle; |
| 4141 | } |
| 4142 | |
| 4143 | fn OpenPredefinedKey(index: usize) !HANDLE { |
| 4144 | switch (index) { |
| 4145 | 0 => { |
| 4146 | // HKEY_CLASSES_ROOT |
| 4147 | return error.Unimplemented; |
| 4148 | }, |
| 4149 | 1 => { |
| 4150 | // HKEY_CURRENT_USER |
| 4151 | return error.Unimplemented; |
| 4152 | }, |
| 4153 | 2 => { |
| 4154 | // HKEY_LOCAL_MACHINE |
| 4155 | return OpenLocalMachineKey(); |
| 4156 | }, |
| 4157 | 3 => { |
| 4158 | // HKEY_USERS |
| 4159 | return error.Unimplemented; |
| 4160 | }, |
| 4161 | 5 => { |
| 4162 | // HKEY_CURRENT_CONFIG |
| 4163 | return error.Unimplemented; |
| 4164 | }, |
| 4165 | 6 => { |
| 4166 | // HKEY_DYN_DATA |
| 4167 | return error.Unimplemented; |
| 4168 | }, |
| 4169 | else => { |
| 4170 | return error.InvalidParameter; |
| 4171 | }, |
| 4172 | } |
| 4173 | } |
| 4174 | |
| 4175 | fn OpenLocalMachineKey() !HANDLE { |
| 4176 | const path = "\\Registry\\Machine"; |
| 4177 | var path_u16: [REG_MAX_NAME_SIZE]u16 = undefined; |
| 4178 | const path_len_u16 = try std.unicode.utf8ToUtf16Le(&path_u16, path); |
| 4179 | const path_len_bytes = @intCast(u16, path_len_u16 * 2); |
| 4180 | |
| 4181 | var key_name = UNICODE_STRING{ |
| 4182 | .Length = path_len_bytes, |
| 4183 | .MaximumLength = path_len_bytes, |
| 4184 | .Buffer = @intToPtr([*]u16, @ptrToInt(&path_u16)), |
| 4185 | }; |
| 4186 | |
| 4187 | var attr = OBJECT_ATTRIBUTES{ |
| 4188 | .Length = @sizeOf(OBJECT_ATTRIBUTES), |
| 4189 | .RootDirectory = null, |
| 4190 | .Attributes = OBJ_CASE_INSENSITIVE, |
| 4191 | .ObjectName = &key_name, |
| 4192 | .SecurityDescriptor = null, |
| 4193 | .SecurityQualityOfService = null, |
| 4194 | }; |
| 4195 | |
| 4196 | var result: HKEY = undefined; |
| 4197 | const rc = ntdll.NtOpenKey( |
| 4198 | &result, |
| 4199 | MAXIMUM_ALLOWED, |
| 4200 | attr, |
| 4201 | ); |
| 4202 | switch (rc) { |
| 4203 | .SUCCESS => return result, |
| 4204 | else => return unexpectedStatus(rc), |
| 4205 | } |
| 4206 | } |