NTSTATUS NTAPI RtlInitializeRXact( HANDLE RootDirectory, BOOLEAN Commit, PRXACT_CONTEXT *OutContext) { NTSTATUS Status, TmpStatus; PRXACT_CONTEXT Context; PKEY_VALUE_FULL_INFORMATION KeyValueInformation; KEY_VALUE_BASIC_INFORMATION KeyValueBasicInfo; UNICODE_STRING ValueName; UNICODE_STRING KeyName; OBJECT_ATTRIBUTES ObjectAttributes; RXACT_INFO TransactionInfo; ULONG Disposition; ULONG ValueType; ULONG ValueDataLength; ULONG Length; HANDLE KeyHandle; /* Open or create the 'RXACT' key in the root directory */ RtlInitUnicodeString(&KeyName, L"RXACT"); InitializeObjectAttributes(&ObjectAttributes, &KeyName, OBJ_CASE_INSENSITIVE | OBJ_OPENIF, RootDirectory, NULL); Status = ZwCreateKey(&KeyHandle, KEY_READ | KEY_WRITE | DELETE, &ObjectAttributes, 0, NULL, 0, &Disposition); if (!NT_SUCCESS(Status)) { return Status; } /* Allocate a new context */ Context = RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(*Context)); *OutContext = Context; if (Context == NULL) { TmpStatus = ZwDeleteKey(KeyHandle); ASSERT(NT_SUCCESS(TmpStatus)); TmpStatus = NtClose(KeyHandle); ASSERT(NT_SUCCESS(TmpStatus)); return STATUS_NO_MEMORY; } /* Initialize the context */ RXactInitializeContext(Context, RootDirectory, KeyHandle); /* Check if we created a new key */ if (Disposition == REG_CREATED_NEW_KEY) { /* The key is new, set the default value */ TransactionInfo.Revision = 1; RtlInitUnicodeString(&ValueName, NULL); Status = ZwSetValueKey(KeyHandle, &ValueName, 0, REG_NONE, &TransactionInfo, sizeof(TransactionInfo)); if (!NT_SUCCESS(Status)) { TmpStatus = ZwDeleteKey(KeyHandle); ASSERT(NT_SUCCESS(TmpStatus)); TmpStatus = NtClose(KeyHandle); ASSERT(NT_SUCCESS(TmpStatus)); RtlFreeHeap(RtlGetProcessHeap(), 0, *OutContext); return Status; } return STATUS_RXACT_STATE_CREATED; } else { /* The key exited, get the default key value */ ValueDataLength = sizeof(TransactionInfo); Status = RtlpNtQueryValueKey(KeyHandle, &ValueType, &TransactionInfo, &ValueDataLength, 0); if (!NT_SUCCESS(Status)) { TmpStatus = NtClose(KeyHandle); ASSERT(NT_SUCCESS(TmpStatus)); RtlFreeHeap(RtlGetProcessHeap(), 0, Context); return Status; } /* Check if the value date is valid */ if ((ValueDataLength != sizeof(TransactionInfo)) || (TransactionInfo.Revision != 1)) { TmpStatus = NtClose(KeyHandle); ASSERT(NT_SUCCESS(TmpStatus)); RtlFreeHeap(RtlGetProcessHeap(), 0, Context); return STATUS_UNKNOWN_REVISION; } /* Query the 'Log' key value */ RtlInitUnicodeString(&ValueName, L"Log"); Status = ZwQueryValueKey(KeyHandle, &ValueName, KeyValueBasicInformation, &KeyValueBasicInfo, sizeof(KeyValueBasicInfo), &Length); if (!NT_SUCCESS(Status)) { /* There is no 'Log', so we are done */ return STATUS_SUCCESS; } /* Check if the caller asked to commit the current state */ if (!Commit) { /* We have a log, that must be committed first! */ return STATUS_RXACT_COMMIT_NECESSARY; } /* Query the size of the 'Log' key value */ Status = ZwQueryValueKey(KeyHandle, &ValueName, KeyValueFullInformation, NULL, 0, &Length); if (Status != STATUS_BUFFER_TOO_SMALL) { return Status; } /* Allocate a buffer for the key value information */ KeyValueInformation = RtlAllocateHeap(RtlGetProcessHeap(), 0, Length); if (KeyValueInformation == NULL) { return STATUS_NO_MEMORY; } /* Query the 'Log' key value */ Status = ZwQueryValueKey(KeyHandle, &ValueName, KeyValueFullInformation, KeyValueInformation, Length, &Length); if (!NT_SUCCESS(Status)) { RtlFreeHeap(RtlGetProcessHeap(), 0, KeyValueInformation); RtlFreeHeap(RtlGetProcessHeap(), 0, Context); return Status; } /* Set the Data pointer to the key value data */ Context->Data = (PRXACT_DATA)((PUCHAR)KeyValueInformation + KeyValueInformation->DataOffset); /* This is an old log, don't use handles when committing! */ Context->CanUseHandles = FALSE; /* Commit the data */ Status = RXactpCommit(Context); if (!NT_SUCCESS(Status)) { RtlFreeHeap(RtlGetProcessHeap(), 0, KeyValueInformation); RtlFreeHeap(RtlGetProcessHeap(), 0, Context); return Status; } /* Delete the old key */ Status = NtDeleteValueKey(KeyHandle, &ValueName); ASSERT(NT_SUCCESS(Status)); /* Set the data member to the allocated buffer, so it will get freed */ Context->Data = (PRXACT_DATA)KeyValueInformation; /* Abort the old transaction */ Status = RtlAbortRXact(Context); ASSERT(NT_SUCCESS(Status)); return Status; } }
NTSTATUS LsapGetObjectAttribute(PLSA_DB_OBJECT DbObject, LPWSTR AttributeName, LPVOID AttributeData, PULONG AttributeSize) { OBJECT_ATTRIBUTES ObjectAttributes; UNICODE_STRING KeyName; HANDLE AttributeKey; ULONG ValueSize; NTSTATUS Status; RtlInitUnicodeString(&KeyName, AttributeName); InitializeObjectAttributes(&ObjectAttributes, &KeyName, OBJ_CASE_INSENSITIVE, DbObject->KeyHandle, NULL); Status = NtOpenKey(&AttributeKey, KEY_QUERY_VALUE, &ObjectAttributes); if (!NT_SUCCESS(Status)) { return Status; } ValueSize = *AttributeSize; Status = RtlpNtQueryValueKey(AttributeKey, NULL, NULL, &ValueSize, 0); if (!NT_SUCCESS(Status) && Status != STATUS_BUFFER_OVERFLOW) { goto Done; } if (AttributeData == NULL || *AttributeSize == 0) { *AttributeSize = ValueSize; Status = STATUS_SUCCESS; goto Done; } else if (*AttributeSize < ValueSize) { *AttributeSize = ValueSize; Status = STATUS_BUFFER_OVERFLOW; goto Done; } Status = RtlpNtQueryValueKey(AttributeKey, NULL, AttributeData, &ValueSize, 0); if (NT_SUCCESS(Status)) { *AttributeSize = ValueSize; } Done: NtClose(AttributeKey); return Status; }