1 /* 2 * COPYRIGHT: See COPYING in the top level directory 3 * PROJECT: Security Account Manager (SAM) Server 4 * FILE: reactos/dll/win32/samsrv/registry.c 5 * PURPOSE: Registry helper functions 6 * 7 * PROGRAMMERS: Eric Kohl 8 */ 9 10 #include "lsasrv.h" 11 12 /* FUNCTIONS ***************************************************************/ 13 14 static 15 BOOLEAN 16 IsStringType(ULONG Type) 17 { 18 return (Type == REG_SZ) || (Type == REG_EXPAND_SZ) || (Type == REG_MULTI_SZ); 19 } 20 21 22 NTSTATUS 23 LsapRegCloseKey(IN HANDLE KeyHandle) 24 { 25 return NtClose(KeyHandle); 26 } 27 28 29 NTSTATUS 30 LsapRegCreateKey(IN HANDLE ParentKeyHandle, 31 IN LPCWSTR KeyName, 32 IN ACCESS_MASK DesiredAccess, 33 OUT HANDLE KeyHandle) 34 { 35 OBJECT_ATTRIBUTES ObjectAttributes; 36 UNICODE_STRING Name; 37 ULONG Disposition; 38 39 RtlInitUnicodeString(&Name, KeyName); 40 41 InitializeObjectAttributes(&ObjectAttributes, 42 &Name, 43 OBJ_CASE_INSENSITIVE | OBJ_OPENIF, 44 ParentKeyHandle, 45 NULL); 46 47 /* Create the key */ 48 return ZwCreateKey(KeyHandle, 49 DesiredAccess, 50 &ObjectAttributes, 51 0, 52 NULL, 53 0, 54 &Disposition); 55 } 56 57 58 NTSTATUS 59 LsapRegDeleteSubKey(IN HANDLE ParentKeyHandle, 60 IN LPCWSTR KeyName) 61 { 62 OBJECT_ATTRIBUTES ObjectAttributes; 63 UNICODE_STRING SubKeyName; 64 HANDLE TargetKey; 65 NTSTATUS Status; 66 67 RtlInitUnicodeString(&SubKeyName, 68 (LPWSTR)KeyName); 69 InitializeObjectAttributes(&ObjectAttributes, 70 &SubKeyName, 71 OBJ_CASE_INSENSITIVE, 72 ParentKeyHandle, 73 NULL); 74 Status = NtOpenKey(&TargetKey, 75 DELETE, 76 &ObjectAttributes); 77 if (!NT_SUCCESS(Status)) 78 return Status; 79 80 Status = NtDeleteKey(TargetKey); 81 82 NtClose(TargetKey); 83 84 return Status; 85 } 86 87 88 NTSTATUS 89 LsapRegDeleteKey(IN HANDLE KeyHandle) 90 { 91 return NtDeleteKey(KeyHandle); 92 } 93 94 95 NTSTATUS 96 LsapRegEnumerateSubKey(IN HANDLE KeyHandle, 97 IN ULONG Index, 98 IN ULONG Length, 99 OUT LPWSTR Buffer) 100 { 101 PKEY_BASIC_INFORMATION KeyInfo = NULL; 102 ULONG BufferLength = 0; 103 ULONG ReturnedLength; 104 NTSTATUS Status; 105 106 /* Check if we have a name */ 107 if (Length) 108 { 109 /* Allocate a buffer for it */ 110 BufferLength = sizeof(KEY_BASIC_INFORMATION) + Length * sizeof(WCHAR); 111 112 KeyInfo = RtlAllocateHeap(RtlGetProcessHeap(), 0, BufferLength); 113 if (KeyInfo == NULL) 114 return STATUS_NO_MEMORY; 115 } 116 117 /* Enumerate the key */ 118 Status = ZwEnumerateKey(KeyHandle, 119 Index, 120 KeyBasicInformation, 121 KeyInfo, 122 BufferLength, 123 &ReturnedLength); 124 if (NT_SUCCESS(Status)) 125 { 126 /* Check if the name fits */ 127 if (KeyInfo->NameLength < (Length * sizeof(WCHAR))) 128 { 129 /* Copy it */ 130 RtlMoveMemory(Buffer, 131 KeyInfo->Name, 132 KeyInfo->NameLength); 133 134 /* Terminate the string */ 135 Buffer[KeyInfo->NameLength / sizeof(WCHAR)] = UNICODE_NULL; 136 } 137 else 138 { 139 /* Otherwise, we ran out of buffer space */ 140 Status = STATUS_BUFFER_OVERFLOW; 141 } 142 } 143 144 /* Free the buffer and return status */ 145 if (KeyInfo) 146 RtlFreeHeap(RtlGetProcessHeap(), 0, KeyInfo); 147 148 return Status; 149 } 150 151 152 NTSTATUS 153 LsapRegOpenKey(IN HANDLE ParentKeyHandle, 154 IN LPCWSTR KeyName, 155 IN ACCESS_MASK DesiredAccess, 156 OUT HANDLE KeyHandle) 157 { 158 OBJECT_ATTRIBUTES ObjectAttributes; 159 UNICODE_STRING Name; 160 161 RtlInitUnicodeString(&Name, KeyName); 162 163 InitializeObjectAttributes(&ObjectAttributes, 164 &Name, 165 OBJ_CASE_INSENSITIVE, 166 ParentKeyHandle, 167 NULL); 168 169 return NtOpenKey(KeyHandle, 170 DesiredAccess, 171 &ObjectAttributes); 172 } 173 174 175 NTSTATUS 176 LsapRegQueryKeyInfo(IN HANDLE KeyHandle, 177 OUT PULONG SubKeyCount, 178 OUT PULONG MaxSubKeyNameLength, 179 OUT PULONG ValueCount) 180 { 181 KEY_FULL_INFORMATION FullInfoBuffer; 182 ULONG Length; 183 NTSTATUS Status; 184 185 FullInfoBuffer.ClassLength = 0; 186 FullInfoBuffer.ClassOffset = FIELD_OFFSET(KEY_FULL_INFORMATION, Class); 187 188 Status = NtQueryKey(KeyHandle, 189 KeyFullInformation, 190 &FullInfoBuffer, 191 sizeof(KEY_FULL_INFORMATION), 192 &Length); 193 TRACE("NtQueryKey() returned status 0x%08lX\n", Status); 194 if (!NT_SUCCESS(Status)) 195 return Status; 196 197 if (SubKeyCount != NULL) 198 *SubKeyCount = FullInfoBuffer.SubKeys; 199 200 if (MaxSubKeyNameLength != NULL) 201 *MaxSubKeyNameLength = FullInfoBuffer.MaxNameLen; 202 203 if (ValueCount != NULL) 204 *ValueCount = FullInfoBuffer.Values; 205 206 return Status; 207 } 208 209 210 NTSTATUS 211 LsapRegDeleteValue(IN HANDLE KeyHandle, 212 IN LPWSTR ValueName) 213 { 214 UNICODE_STRING Name; 215 216 RtlInitUnicodeString(&Name, 217 ValueName); 218 219 return NtDeleteValueKey(KeyHandle, 220 &Name); 221 } 222 223 224 NTSTATUS 225 LsapRegEnumerateValue(IN HANDLE KeyHandle, 226 IN ULONG Index, 227 OUT LPWSTR Name, 228 IN OUT PULONG NameLength, 229 OUT PULONG Type OPTIONAL, 230 OUT PVOID Data OPTIONAL, 231 IN OUT PULONG DataLength OPTIONAL) 232 { 233 PKEY_VALUE_FULL_INFORMATION ValueInfo = NULL; 234 ULONG BufferLength = 0; 235 ULONG ReturnedLength; 236 NTSTATUS Status; 237 238 TRACE("Index: %lu\n", Index); 239 240 /* Calculate the required buffer length */ 241 BufferLength = FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION, Name); 242 BufferLength += (MAX_PATH + 1) * sizeof(WCHAR); 243 if (Data != NULL) 244 BufferLength += *DataLength; 245 246 /* Allocate the value buffer */ 247 ValueInfo = RtlAllocateHeap(RtlGetProcessHeap(), 0, BufferLength); 248 if (ValueInfo == NULL) 249 return STATUS_NO_MEMORY; 250 251 /* Enumerate the value*/ 252 Status = ZwEnumerateValueKey(KeyHandle, 253 Index, 254 KeyValueFullInformation, 255 ValueInfo, 256 BufferLength, 257 &ReturnedLength); 258 if (NT_SUCCESS(Status)) 259 { 260 if (Name != NULL) 261 { 262 /* Check if the name fits */ 263 if (ValueInfo->NameLength < (*NameLength * sizeof(WCHAR))) 264 { 265 /* Copy it */ 266 RtlMoveMemory(Name, 267 ValueInfo->Name, 268 ValueInfo->NameLength); 269 270 /* Terminate the string */ 271 Name[ValueInfo->NameLength / sizeof(WCHAR)] = UNICODE_NULL; 272 } 273 else 274 { 275 /* Otherwise, we ran out of buffer space */ 276 Status = STATUS_BUFFER_OVERFLOW; 277 goto done; 278 } 279 } 280 281 if (Data != NULL) 282 { 283 /* Check if the data fits */ 284 if (ValueInfo->DataLength <= *DataLength) 285 { 286 /* Copy it */ 287 RtlMoveMemory(Data, 288 (PVOID)((ULONG_PTR)ValueInfo + ValueInfo->DataOffset), 289 ValueInfo->DataLength); 290 291 /* if the type is REG_SZ and data is not 0-terminated 292 * and there is enough space in the buffer NT appends a \0 */ 293 if (IsStringType(ValueInfo->Type) && 294 ValueInfo->DataLength <= *DataLength - sizeof(WCHAR)) 295 { 296 WCHAR *ptr = (WCHAR *)((ULONG_PTR)Data + ValueInfo->DataLength); 297 if ((ptr > (WCHAR *)Data) && ptr[-1]) 298 *ptr = UNICODE_NULL; 299 } 300 } 301 else 302 { 303 Status = STATUS_BUFFER_OVERFLOW; 304 goto done; 305 } 306 } 307 } 308 309 done: 310 if ((NT_SUCCESS(Status)) || (Status == STATUS_BUFFER_OVERFLOW)) 311 { 312 if (Type != NULL) 313 *Type = ValueInfo->Type; 314 315 if (NameLength != NULL) 316 *NameLength = ValueInfo->NameLength; 317 318 if (DataLength != NULL) 319 *DataLength = ValueInfo->DataLength; 320 } 321 322 /* Free the buffer and return status */ 323 if (ValueInfo) 324 RtlFreeHeap(RtlGetProcessHeap(), 0, ValueInfo); 325 326 return Status; 327 } 328 329 330 NTSTATUS 331 LsapRegQueryValue(IN HANDLE KeyHandle, 332 IN LPWSTR ValueName, 333 OUT PULONG Type OPTIONAL, 334 OUT PVOID Data OPTIONAL, 335 IN OUT PULONG DataLength OPTIONAL) 336 { 337 PKEY_VALUE_PARTIAL_INFORMATION ValueInfo; 338 UNICODE_STRING Name; 339 ULONG BufferLength = 0; 340 NTSTATUS Status; 341 342 RtlInitUnicodeString(&Name, 343 ValueName); 344 345 if (DataLength != NULL) 346 BufferLength = *DataLength; 347 348 BufferLength += FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data); 349 350 /* Allocate memory for the value */ 351 ValueInfo = RtlAllocateHeap(RtlGetProcessHeap(), 0, BufferLength); 352 if (ValueInfo == NULL) 353 return STATUS_NO_MEMORY; 354 355 /* Query the value */ 356 Status = ZwQueryValueKey(KeyHandle, 357 &Name, 358 KeyValuePartialInformation, 359 ValueInfo, 360 BufferLength, 361 &BufferLength); 362 if ((NT_SUCCESS(Status)) || (Status == STATUS_BUFFER_OVERFLOW)) 363 { 364 if (Type != NULL) 365 *Type = ValueInfo->Type; 366 367 if (DataLength != NULL) 368 *DataLength = ValueInfo->DataLength; 369 } 370 371 /* Check if the caller wanted data back, and we got it */ 372 if ((NT_SUCCESS(Status)) && (Data != NULL)) 373 { 374 /* Copy it */ 375 RtlMoveMemory(Data, 376 ValueInfo->Data, 377 ValueInfo->DataLength); 378 379 /* if the type is REG_SZ and data is not 0-terminated 380 * and there is enough space in the buffer NT appends a \0 */ 381 if (IsStringType(ValueInfo->Type) && 382 ValueInfo->DataLength <= *DataLength - sizeof(WCHAR)) 383 { 384 WCHAR *ptr = (WCHAR *)((ULONG_PTR)Data + ValueInfo->DataLength); 385 if ((ptr > (WCHAR *)Data) && ptr[-1]) 386 *ptr = UNICODE_NULL; 387 } 388 } 389 390 /* Free the memory and return status */ 391 RtlFreeHeap(RtlGetProcessHeap(), 0, ValueInfo); 392 393 if ((Data == NULL) && (Status == STATUS_BUFFER_OVERFLOW)) 394 Status = STATUS_SUCCESS; 395 396 return Status; 397 } 398 399 400 NTSTATUS 401 LsapRegSetValue(HANDLE KeyHandle, 402 LPWSTR ValueName, 403 ULONG Type, 404 LPVOID Data, 405 ULONG DataLength) 406 { 407 UNICODE_STRING Name; 408 409 RtlInitUnicodeString(&Name, 410 ValueName); 411 412 return ZwSetValueKey(KeyHandle, 413 &Name, 414 0, 415 Type, 416 Data, 417 DataLength); 418 } 419