| ... | @@ -2504,6 +2504,7 @@ pub const STANDARD_RIGHTS_READ = READ_CONTROL; | ... | @@ -2504,6 +2504,7 @@ pub const STANDARD_RIGHTS_READ = READ_CONTROL; |
| 2504 | pub const STANDARD_RIGHTS_WRITE = READ_CONTROL; | 2504 | pub const STANDARD_RIGHTS_WRITE = READ_CONTROL; |
| 2505 | pub const STANDARD_RIGHTS_EXECUTE = READ_CONTROL; | 2505 | pub const STANDARD_RIGHTS_EXECUTE = READ_CONTROL; |
| 2506 | pub const STANDARD_RIGHTS_REQUIRED = DELETE | READ_CONTROL | WRITE_DAC | WRITE_OWNER; | 2506 | pub const STANDARD_RIGHTS_REQUIRED = DELETE | READ_CONTROL | WRITE_DAC | WRITE_OWNER; |
| | 2507 | pub const MAXIMUM_ALLOWED = 0x02000000; |
| 2507 | | 2508 | |
| 2508 | // disposition for NtCreateFile | 2509 | // disposition for NtCreateFile |
| 2509 | pub const FILE_SUPERSEDE = 0; | 2510 | pub const FILE_SUPERSEDE = 0; |
| ... | @@ -2872,9 +2873,11 @@ pub const PROV_RSA_FULL = 1; | ... | @@ -2872,9 +2873,11 @@ pub const PROV_RSA_FULL = 1; |
| 2872 | | 2873 | |
| 2873 | pub const REGSAM = ACCESS_MASK; | 2874 | pub const REGSAM = ACCESS_MASK; |
| 2874 | pub const ACCESS_MASK = DWORD; | 2875 | pub const ACCESS_MASK = DWORD; |
| 2875 | pub const HKEY = *opaque {}; | | |
| 2876 | pub const LSTATUS = LONG; | 2876 | pub const LSTATUS = LONG; |
| 2877 | | 2877 | |
| | 2878 | pub const HKEY = HANDLE; |
| | 2879 | pub const HKEY_LOCAL_MACHINE: HKEY = @intToPtr(HKEY, 0x80000002); |
| | 2880 | |
| 2878 | pub const FILE_NOTIFY_INFORMATION = extern struct { | 2881 | pub const FILE_NOTIFY_INFORMATION = extern struct { |
| 2879 | NextEntryOffset: DWORD, | 2882 | NextEntryOffset: DWORD, |
| 2880 | Action: DWORD, | 2883 | Action: DWORD, |
| ... | @@ -4017,3 +4020,187 @@ pub fn IsProcessorFeaturePresent(feature: PF) bool { | ... | @@ -4017,3 +4020,187 @@ pub fn IsProcessorFeaturePresent(feature: PF) bool { |
| 4017 | if (@enumToInt(feature) >= PROCESSOR_FEATURE_MAX) return false; | 4020 | if (@enumToInt(feature) >= PROCESSOR_FEATURE_MAX) return false; |
| 4018 | return SharedUserData.ProcessorFeatures[@enumToInt(feature)] == 1; | 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 | } |