Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

4243 lines
107 KiB

/*++
Copyright (c) 1989 Microsoft Corporation
Module Name:
rpcapi2.c
Abstract:
This module contains the routines for the LSA API that use RPC. The
routines in this module are merely wrappers that work as follows:
o Client program calls LsaFoo in this module
o LsaFoo calls RPC client stub interface routine LsapFoo with
similar parameters. Some parameters are translated from types
(e.g structures containing PVOIDs or certain kinds of variable length
parameters such as pointers to SID's) that are not specifiable on an
RPC interface, to specifiable form.
o RPC client stub LsapFoo calls interface specific marshalling routines
and RPC runtime to marshal parameters into a buffer and send them over
to the server side of the LSA.
o Server side calls RPC runtime and interface specific unmarshalling
routines to unmarshal parameters.
o Server side calls worker LsapFoo to perform API function.
o Server side marshals response/output parameters and communicates these
back to client stub LsapFoo
o LsapFoo exits back to LsaFoo which returns to client program.
Author:
Mike Swift (MikeSw) December 7, 1994
Revision History:
--*/
#define UNICODE // required for TEXT() to be defined properly
#include "lsaclip.h"
#include <lmcons.h>
#include <logonmsv.h>
#include <rc4.h>
#include <rpcasync.h>
typedef struct _LSAP_DB_RIGHT_AND_ACCESS {
UNICODE_STRING UserRight;
ULONG SystemAccess;
} LSAP_DB_RIGHT_AND_ACCESS, *PLSAP_DB_RIGHT_AND_ACCESS;
#define LSAP_DB_SYSTEM_ACCESS_TYPES 4
LSAP_DB_RIGHT_AND_ACCESS LsapDbRightAndAccess[LSAP_DB_SYSTEM_ACCESS_TYPES] = {
{{sizeof(SE_INTERACTIVE_LOGON_NAME)-sizeof(WCHAR),
sizeof(SE_INTERACTIVE_LOGON_NAME),
SE_INTERACTIVE_LOGON_NAME},
SECURITY_ACCESS_INTERACTIVE_LOGON},
{{sizeof(SE_NETWORK_LOGON_NAME)-sizeof(WCHAR),
sizeof(SE_NETWORK_LOGON_NAME),
SE_NETWORK_LOGON_NAME},
SECURITY_ACCESS_NETWORK_LOGON},
{{sizeof(SE_BATCH_LOGON_NAME)-sizeof(WCHAR),
sizeof(SE_BATCH_LOGON_NAME),
SE_BATCH_LOGON_NAME},
SECURITY_ACCESS_BATCH_LOGON},
{{sizeof(SE_SERVICE_LOGON_NAME)-sizeof(WCHAR),
sizeof(SE_SERVICE_LOGON_NAME),
SE_SERVICE_LOGON_NAME},
SECURITY_ACCESS_SERVICE_LOGON}
};
//
// Structure to maintain list of enumerated accounts
//
typedef struct _SID_LIST_ENTRY {
struct _SID_LIST_ENTRY * Next;
PSID Sid;
} SID_LIST_ENTRY, *PSID_LIST_ENTRY;
//
// Functions private to this module
//
NTSTATUS
LsapApiReturnResult(
IN ULONG ExceptionCode
);
NTSTATUS
LsapApiConvertRightsToPrivileges(
IN LSA_HANDLE PolicyHandle,
IN PUNICODE_STRING UserRights,
IN ULONG RightCount,
OUT PPRIVILEGE_SET * Privileges,
OUT PULONG SystemAccess
);
NTSTATUS
LsapApiConvertPrivilegesToRights(
IN LSA_HANDLE PolicyHandle,
IN OPTIONAL PPRIVILEGE_SET Privileges,
IN OPTIONAL ULONG SystemAccess,
OUT PUNICODE_STRING * UserRights,
OUT PULONG RightCount
);
//////////////////////////////////////////////////////////////////////
//
// This set of routines implements the same functionality as the APIs
// below but do it with the APIs present through NT 3.5
//
/////////////////////////////////////////////////////////////////////
NTSTATUS
NTAPI
LsapEnumerateAccountsWithUserRight(
IN LSA_HANDLE PolicyHandle,
IN OPTIONAL PUNICODE_STRING UserRights,
OUT PVOID *EnumerationBuffer,
OUT PULONG CountReturned
)
/*++
Routine Description:
The LsaEnumerateAccountsWithUserRight API returns information about
the accounts in the target system's Lsa Database. This call requires
LSA_ENUMERATE_ACCOUNTS access to the Policy object. Since this call
accesses the privileges of an account, you must have ACCOUNT_VIEW access
access to all accounts.
Arguments:
PolicyHandle - Handle from an LsaOpenPolicy call.
UserRight - Name of the right that the account must have.
Buffer - Receives a pointer to a LSA_ENUMERATION_INFORMATION structure
containing the SIDs of all the accounts.
CountReturned - Receives the number of sids returned.
Return Values:
NTSTATUS - Standard Nt Result Code
STATUS_ACCESS_DENIED - Caller does not have the appropriate access
to complete the operation.
STATUS_NO_MORE_ENTRIES - There are no more entries. This warning
is returned if no objects are enumerated because the
EnumerationContext value passed in is too high.
--*/
{
NTSTATUS Status;
PLSA_ENUMERATION_INFORMATION Accounts = NULL;
PPRIVILEGE_SET DesiredPrivilege = NULL;
ULONG DesiredAccess = 0;
PPRIVILEGE_SET Privileges = NULL;
ULONG SystemAccess;
LSA_ENUMERATION_HANDLE EnumContext = 0;
ULONG AccountCount;
ULONG AccountIndex;
LSA_HANDLE AccountHandle = NULL;
PSID_LIST_ENTRY AccountList = NULL;
PSID_LIST_ENTRY NextAccount = NULL;
ULONG AccountSize;
PUCHAR Where;
ULONG PrivilegeIndex;
Status = LsapApiConvertRightsToPrivileges(
PolicyHandle,
UserRights,
(UserRights ? 1 : 0),
&DesiredPrivilege,
&DesiredAccess
);
if (!NT_SUCCESS(Status)) {
goto Cleanup;
}
//
// Enumerate all the accounts.
//
do
{
Status = LsaEnumerateAccounts(
PolicyHandle,
&EnumContext,
&Accounts,
32000,
&AccountCount
);
if (!NT_SUCCESS(Status)) {
break;
}
//
// For each account, check that it has the desired right
//
for (AccountIndex = 0; AccountIndex < AccountCount ; AccountIndex++ ) {
if ((DesiredPrivilege != NULL) || (DesiredAccess != 0)) {
Status = LsaOpenAccount(
PolicyHandle,
Accounts[AccountIndex].Sid,
ACCOUNT_VIEW,
&AccountHandle
);
if (!NT_SUCCESS(Status) ) {
goto Cleanup;
}
//
// If a privilege was requested, get the privilegs
//
if (DesiredPrivilege != NULL) {
Privileges = NULL;
Status = LsaEnumeratePrivilegesOfAccount(
AccountHandle,
&Privileges
);
if (!NT_SUCCESS(Status)) {
goto Cleanup;
}
//
// Search for the desired privilege
//
for (PrivilegeIndex = 0;
PrivilegeIndex < Privileges->PrivilegeCount ;
PrivilegeIndex++) {
if (RtlEqualLuid(&Privileges->Privilege[PrivilegeIndex].Luid,
&DesiredPrivilege->Privilege[0].Luid)) {
break;
}
}
//
// If we found the privilege, add it to the list.
//
if (PrivilegeIndex != Privileges->PrivilegeCount) {
//
// Add this account to the enumeration.
//
NextAccount = MIDL_user_allocate(sizeof(SID_LIST_ENTRY));
if (NextAccount == NULL) {
Status = STATUS_INSUFFICIENT_RESOURCES;
goto Cleanup;
}
NextAccount->Sid = MIDL_user_allocate(RtlLengthSid(Accounts[AccountIndex].Sid));
if (NextAccount->Sid == NULL) {
MIDL_user_free(NextAccount);
Status = STATUS_INSUFFICIENT_RESOURCES;
goto Cleanup;
}
RtlCopyMemory(
NextAccount->Sid,
Accounts[AccountIndex].Sid,
RtlLengthSid(Accounts[AccountIndex].Sid)
);
NextAccount->Next = AccountList;
AccountList = NextAccount;
}
LsaFreeMemory(Privileges);
Privileges = NULL;
} else {
//
// Otherwise get the system access
//
ASSERT(DesiredAccess != 0);
Status = LsaGetSystemAccessAccount(
AccountHandle,
&SystemAccess
);
if (!NT_SUCCESS(Status)) {
goto Cleanup;
}
//
// Check for the desired access
//
if ((SystemAccess & DesiredAccess) != 0) {
//
// Add this account to the enumeration.
//
NextAccount = MIDL_user_allocate(sizeof(SID_LIST_ENTRY));
if (NextAccount == NULL) {
Status = STATUS_INSUFFICIENT_RESOURCES;
goto Cleanup;
}
NextAccount->Sid = MIDL_user_allocate(RtlLengthSid(Accounts[AccountIndex].Sid));
if (NextAccount->Sid == NULL) {
MIDL_user_free(NextAccount);
Status = STATUS_INSUFFICIENT_RESOURCES;
goto Cleanup;
}
RtlCopyMemory(
NextAccount->Sid,
Accounts[AccountIndex].Sid,
RtlLengthSid(Accounts[AccountIndex].Sid)
);
NextAccount->Next = AccountList;
AccountList = NextAccount;
}
}
LsaClose(AccountHandle);
AccountHandle = NULL;
} else {
//
// always add the account if the caller didn't want
// filtering.
//
NextAccount = MIDL_user_allocate(sizeof(SID_LIST_ENTRY));
if (NextAccount == NULL) {
Status = STATUS_INSUFFICIENT_RESOURCES;
goto Cleanup;
}
NextAccount->Sid = MIDL_user_allocate(RtlLengthSid(Accounts[AccountIndex].Sid));
if (NextAccount->Sid == NULL) {
MIDL_user_free(NextAccount);
Status = STATUS_INSUFFICIENT_RESOURCES;
goto Cleanup;
}
RtlCopyMemory(
NextAccount->Sid,
Accounts[AccountIndex].Sid,
RtlLengthSid(Accounts[AccountIndex].Sid)
);
NextAccount->Next = AccountList;
AccountList = NextAccount;
}
}
LsaFreeMemory(Accounts);
Accounts = NULL;
} while ( 1 );
if (Status != STATUS_NO_MORE_ENTRIES) {
goto Cleanup;
}
AccountSize = 0;
AccountCount = 0;
for (NextAccount = AccountList ; NextAccount != NULL; NextAccount = NextAccount->Next) {
AccountSize += sizeof(LSA_ENUMERATION_INFORMATION) +
RtlLengthSid(NextAccount->Sid);
AccountCount++;
}
//
// If there were no accounts return a warning now.
//
if (AccountCount == 0) {
*EnumerationBuffer = NULL;
*CountReturned = 0;
Status = STATUS_NO_MORE_ENTRIES;
goto Cleanup;
}
Accounts = MIDL_user_allocate(AccountSize);
if (Accounts == NULL) {
Status = STATUS_INSUFFICIENT_RESOURCES;
goto Cleanup;
}
//
// Marshall all the sids into the array.
//
Where = (PUCHAR) Accounts + AccountCount * sizeof(LSA_ENUMERATION_INFORMATION);
for ( NextAccount = AccountList,AccountIndex = 0 ;
NextAccount != NULL;
NextAccount = NextAccount->Next, AccountIndex++) {
Accounts[AccountIndex].Sid = (PSID) Where;
RtlCopyMemory(
Where,
NextAccount->Sid,
RtlLengthSid(NextAccount->Sid)
);
Where += RtlLengthSid(NextAccount->Sid);
}
ASSERT(AccountIndex == AccountCount);
ASSERT(Where - (PUCHAR) Accounts == (LONG) AccountSize);
*EnumerationBuffer = Accounts;
Accounts = NULL;
*CountReturned = AccountCount;
Status = STATUS_SUCCESS;
Cleanup:
if (AccountList != NULL) {
while (AccountList != NULL) {
NextAccount = AccountList->Next;
MIDL_user_free(AccountList->Sid);
MIDL_user_free(AccountList);
AccountList = NextAccount;
}
}
if (Accounts != NULL) {
MIDL_user_free(Accounts);
}
if (Privileges != NULL) {
LsaFreeMemory(Privileges);
}
return(Status);
}
NTSTATUS
NTAPI
LsapEnumerateAccountRights(
IN LSA_HANDLE PolicyHandle,
IN PSID AccountSid,
OUT PUNICODE_STRING *UserRights,
OUT PULONG CountOfRights
)
/*++
Routine Description:
Returns all the rights of an account. This is done by gathering the
privileges and system access of an account and translating that into
an array of strings.
Arguments:
PolicyHandle - Handle from an LsaOpenPolicyCall. This API requires
no special access.
AccountSid - Sid of account to open.
UserRights - receives an array of user rights (UNICODE_STRING) for
the account.
CountOfRights - receives the number of rights returned.
Return Value:
STATUS_ACCESS_DENIED - the caller did not have sufficient access to
return the privileges or system access of the account.
STATUS_OBJECT_NAME_NOT_FOUND - the specified account did not exist.
STATUS_INSUFFICIENT_RESOURCES - not enough memory to process the
request.
--*/
{
NTSTATUS Status;
PPRIVILEGE_SET Privileges = NULL;
ULONG SystemAccess = 0;
PUNICODE_STRING Rights = NULL;
ULONG RightCount = 0;
LSA_HANDLE AccountHandle = NULL;
Status = LsaOpenAccount(
PolicyHandle,
AccountSid,
ACCOUNT_VIEW,
&AccountHandle
);
if (!NT_SUCCESS(Status)) {
goto Cleanup;
}
//
// Query the privilegs and system access
//
Status = LsaEnumeratePrivilegesOfAccount(
AccountHandle,
&Privileges
);
if (!NT_SUCCESS(Status)) {
goto Cleanup;
}
Status = LsaGetSystemAccessAccount(
AccountHandle,
&SystemAccess
);
if (!NT_SUCCESS(Status)) {
goto Cleanup;
}
//
// Convert the privileges and access to rights
//
Status = LsapApiConvertPrivilegesToRights(
PolicyHandle,
Privileges,
SystemAccess,
&Rights,
&RightCount
);
if (NT_SUCCESS(Status)) {
*CountOfRights = RightCount;
*UserRights = Rights;
}
Cleanup:
if (Privileges != NULL) {
LsaFreeMemory(Privileges);
}
if (AccountHandle != NULL) {
LsaClose(AccountHandle);
}
return(Status);
}
NTSTATUS
NTAPI
LsapAddAccountRights(
IN LSA_HANDLE PolicyHandle,
IN PSID AccountSid,
IN PUNICODE_STRING UserRights,
IN ULONG CountOfRights
)
/*++
Routine Description:
Adds rights to the account specified by the account sid. If the account
does not exist, it creates the account.
Arguments:
PolicyHandle - Handle from an LsaOpenPolicy call. The handle must have
POLICY_CREATE_ACCOUNT access if this is the first call for this
AccountSid.
AccountSid - Sid of account to add rights to
UserRights - Array of unicode strings naming rights to add to the
account.
Return Value:
STATUS_INSUFFICIENT_RESOURCES - not enough memory to process the request
STATUS_INVALID_PARAMTER - one of the parameters was not present
STATUS_NO_SUCH_PRIVILEGE - One of the user rights was invalid
STATUS_ACCESS_DENIED - the caller does not have sufficient access to the
account to add privileges.
--*/
{
LSA_HANDLE AccountHandle = NULL;
NTSTATUS Status;
PPRIVILEGE_SET Privileges = NULL;
ULONG SystemAccess;
ULONG OldAccess;
//
// Convert the rights into privileges and system access.
//
Status = LsapApiConvertRightsToPrivileges(
PolicyHandle,
UserRights,
CountOfRights,
&Privileges,
&SystemAccess
);
if (!NT_SUCCESS(Status)) {
goto Cleanup;
}
//
// Open the account. If it does not exist ,create the account.
//
Status = LsaOpenAccount(
PolicyHandle,
AccountSid,
ACCOUNT_ADJUST_PRIVILEGES |
ACCOUNT_ADJUST_SYSTEM_ACCESS |
ACCOUNT_VIEW,
&AccountHandle
);
//
// if the account did not exist, try to create it.
//
if (Status == STATUS_OBJECT_NAME_NOT_FOUND) {
Status = LsaCreateAccount(
PolicyHandle,
AccountSid,
ACCOUNT_ADJUST_PRIVILEGES |
ACCOUNT_ADJUST_SYSTEM_ACCESS |
ACCOUNT_VIEW,
&AccountHandle
);
}
if (!NT_SUCCESS(Status)) {
goto Cleanup;
}
Status = LsaGetSystemAccessAccount(
AccountHandle,
&OldAccess
);
if (!NT_SUCCESS(Status)) {
goto Cleanup;
}
Status = LsaSetSystemAccessAccount(
AccountHandle,
OldAccess | SystemAccess
);
if (!NT_SUCCESS(Status)) {
goto Cleanup;
}
Status = LsaAddPrivilegesToAccount(
AccountHandle,
Privileges
);
Cleanup:
if (Privileges != NULL) {
MIDL_user_free(Privileges);
}
if (AccountHandle != NULL) {
LsaClose(AccountHandle);
}
return(Status);
}
NTSTATUS
NTAPI
LsapRemoveAccountRights(
IN LSA_HANDLE PolicyHandle,
IN PSID AccountSid,
IN BOOLEAN AllRights,
IN PUNICODE_STRING UserRights,
IN ULONG CountOfRights
)
/*++
Routine Description:
Removes rights to the account specified by the account sid. If the
AllRights flag is set or if all the rights are removed, the account
is deleted.
Arguments:
PolicyHandle - Handle from an LsaOpenPolicy call
AccountSid - Sid of account to remove rights from
UserRights - Array of unicode strings naming rights to remove from the
account.
Return Value:
STATUS_INSUFFICIENT_RESOURCES - not enough memory to process the request
STATUS_INVALID_PARAMTER - one of the parameters was not present
STATUS_NO_SUCH_PRIVILEGE - One of the user rights was invalid
STATUS_ACCESS_DENIED - the caller does not have sufficient access to the
account to add privileges.
--*/
{
LSA_HANDLE AccountHandle = NULL;
NTSTATUS Status;
PPRIVILEGE_SET Privileges = NULL;
PPRIVILEGE_SET NewPrivileges = NULL;
ULONG SystemAccess = 0 ;
ULONG OldAccess;
ULONG DesiredAccess;
ULONG NewAccess;
//
// Convert the rights into privileges and system access.
//
if (!AllRights) {
Status = LsapApiConvertRightsToPrivileges(
PolicyHandle,
UserRights,
CountOfRights,
&Privileges,
&SystemAccess
);
if (!NT_SUCCESS(Status)) {
goto Cleanup;
}
DesiredAccess = ACCOUNT_ADJUST_PRIVILEGES |
ACCOUNT_ADJUST_SYSTEM_ACCESS |
ACCOUNT_VIEW | DELETE;
} else {
DesiredAccess = DELETE;
}
//
// Open the account.
//
Status = LsaOpenAccount(
PolicyHandle,
AccountSid,
DesiredAccess,
&AccountHandle
);
if (!NT_SUCCESS(Status)) {
goto Cleanup;
}
//
// If we are to remove all rights, just delete the account ,and if that
// succeeds, zero the handle so we don't try to close it later.
//
if (AllRights) {
Status = LsaDelete(
AccountHandle
);
if (NT_SUCCESS(Status)) {
AccountHandle = NULL;
}
goto Cleanup;
}
//
// Get the old system access to adjust
//
Status = LsaGetSystemAccessAccount(
AccountHandle,
&OldAccess
);
if (!NT_SUCCESS(Status)) {
goto Cleanup;
}
NewAccess = OldAccess & ~SystemAccess;
Status = LsaSetSystemAccessAccount(
AccountHandle,
NewAccess
);
if (!NT_SUCCESS(Status)) {
goto Cleanup;
}
Status = LsaRemovePrivilegesFromAccount(
AccountHandle,
FALSE, // don't remove all
Privileges
);
if (!NT_SUCCESS(Status)) {
goto Cleanup;
}
//
// Now query the privilegs to see if they are zero. If so, and
// system access is zero, delete the account.
//
Status = LsaEnumeratePrivilegesOfAccount(
AccountHandle,
&NewPrivileges
);
if (!NT_SUCCESS(Status)) {
goto Cleanup;
}
//
// If the account has no privileges or access, delete it.
//
if ((NewPrivileges->PrivilegeCount == 0) &&
(NewAccess == 0)) {
Status = LsaDelete(
AccountHandle
);
if (NT_SUCCESS(Status)) {
AccountHandle = NULL;
}
}
Status = STATUS_SUCCESS;
Cleanup:
if (Privileges != NULL) {
MIDL_user_free(Privileges);
}
if (AccountHandle != NULL) {
LsaClose(AccountHandle);
}
if (NewPrivileges != NULL) {
LsaFreeMemory(NewPrivileges);
}
return(Status);
}
NTSTATUS
LsapApiBuildSecretName(
PTRUSTED_DOMAIN_NAME_INFO NameInfo,
PUNICODE_STRING OutputSecretName
)
{
UNICODE_STRING SecretName;
//
// The secret name is G$$domain name, where G$ is the global prefix and
// $ is the ssi prefix
//
SecretName.Length = NameInfo->Name.Length +
(SSI_SECRET_PREFIX_LENGTH +
LSA_GLOBAL_SECRET_PREFIX_LENGTH) * sizeof(WCHAR);
SecretName.MaximumLength = SecretName.Length;
SecretName.Buffer = (LPWSTR) MIDL_user_allocate( SecretName.Length );
if (SecretName.Buffer == NULL) {
return(STATUS_INSUFFICIENT_RESOURCES);
}
wcscpy(
SecretName.Buffer,
LSA_GLOBAL_SECRET_PREFIX
);
wcscat(
SecretName.Buffer,
SSI_SECRET_PREFIX
);
RtlCopyMemory(
SecretName.Buffer +
LSA_GLOBAL_SECRET_PREFIX_LENGTH +
SSI_SECRET_PREFIX_LENGTH,
NameInfo->Name.Buffer,
NameInfo->Name.Length
);
*OutputSecretName = SecretName;
return(STATUS_SUCCESS);
}
NTSTATUS
NTAPI
LsapQueryTrustedDomainInfo(
IN LSA_HANDLE PolicyHandle,
IN PSID TrustedDomainSid,
IN TRUSTED_INFORMATION_CLASS InformationClass,
OUT PVOID *Buffer
)
/*++
Routine Description:
The LsaQueryTrustedDomainInfo API obtains information from a
TrustedDomain object. The caller must have access appropriate to the
information being requested (see InformationClass parameter). It also
may query the secret object (for the TrustedDomainPasswordInformation
class).
Arguments:
PolicyHandle - Handle from an LsaOpenPolicy call.
TrustedDomainSid - Sid of domain to query.
InformationClass - Specifies the information to be returned.
Buffer - Receives a pointer to the buffer returned comtaining the
requested information. This buffer is allocated by this service
and must be freed when no longer needed by passing the returned
value to LsaFreeMemory().
Return Value:
NTSTATUS - Standard Nt Result Code
STATUS_ACCESS_DENIED - Caller does not have the appropriate
access to complete the operation.
STATUS_INSUFFICIENT_RESOURCES - Insufficient system resources,
such as memory, to complete the call.
--*/
{
NTSTATUS Status;
LSA_HANDLE DomainHandle = NULL;
LSA_HANDLE SecretHandle = NULL;
PUNICODE_STRING OldPassword = NULL;
PUNICODE_STRING Password = NULL;
PTRUSTED_PASSWORD_INFO PasswordInfo = NULL;
PTRUSTED_DOMAIN_NAME_INFO NameInfo = NULL;
ULONG DesiredAccess;
PVOID LocalBuffer = NULL;
TRUSTED_INFORMATION_CLASS LocalInfoClass;
UNICODE_STRING SecretName;
PUCHAR Where;
ULONG PasswordSize;
SecretName.Buffer = NULL;
//
// Find the desired access type for the info we are
// querying.
//
LocalInfoClass = InformationClass;
switch(InformationClass) {
case TrustedDomainNameInformation:
DesiredAccess = TRUSTED_QUERY_DOMAIN_NAME;
break;
case TrustedPosixOffsetInformation:
DesiredAccess = TRUSTED_QUERY_POSIX;
break;
case TrustedPasswordInformation:
DesiredAccess = TRUSTED_QUERY_DOMAIN_NAME;
LocalInfoClass = TrustedDomainNameInformation;
break;
default:
return(STATUS_INVALID_PARAMETER);
}
//
// Open the domain for the desired access
//
Status = LsaOpenTrustedDomain(
PolicyHandle,
TrustedDomainSid,
DesiredAccess,
&DomainHandle
);
if (!NT_SUCCESS(Status)) {
goto Cleanup;
}
Status = LsaQueryInfoTrustedDomain(
DomainHandle,
LocalInfoClass,
&LocalBuffer
);
if (!NT_SUCCESS(Status)) {
goto Cleanup;
}
//
// If the class wasn't trusted password information, return here.
//
if (InformationClass != TrustedPasswordInformation) {
*Buffer = LocalBuffer;
LocalBuffer = NULL;
goto Cleanup;
}
NameInfo = (PTRUSTED_DOMAIN_NAME_INFO) LocalBuffer;
//
// Get the secret name
//
Status = LsapApiBuildSecretName(
NameInfo,
&SecretName
);
if (!NT_SUCCESS(Status)) {
goto Cleanup;
}
Status = LsaOpenSecret(
PolicyHandle,
&SecretName,
SECRET_QUERY_VALUE,
&SecretHandle
);
if (!NT_SUCCESS(Status)) {
goto Cleanup;
}
//
// Query the secret
//
Status = LsaQuerySecret(
SecretHandle,
&Password,
NULL,
&OldPassword,
NULL
);
if (!NT_SUCCESS(Status)) {
goto Cleanup;
}
//
// Marshall the passwords into the output structure.
//
PasswordSize = sizeof(TRUSTED_PASSWORD_INFO);
if (Password != NULL) {
PasswordSize += Password->MaximumLength;
}
if (OldPassword != NULL) {
PasswordSize += OldPassword->MaximumLength;
}
PasswordInfo = (PTRUSTED_PASSWORD_INFO) MIDL_user_allocate(PasswordSize);
if (PasswordInfo == NULL) {
Status = STATUS_INSUFFICIENT_RESOURCES;
goto Cleanup;
}
RtlZeroMemory(
PasswordInfo,
PasswordSize
);
Where = (PUCHAR) (PasswordInfo+1);
if (Password != NULL) {
PasswordInfo->Password = *Password;
PasswordInfo->Password.Buffer = (LPWSTR) Where;
RtlCopyMemory(
Where,
Password->Buffer,
Password->MaximumLength
);
Where += Password->MaximumLength;
}
if (OldPassword != NULL) {
PasswordInfo->OldPassword = *OldPassword;
PasswordInfo->OldPassword.Buffer = (LPWSTR) Where;
RtlCopyMemory(
Where,
OldPassword->Buffer,
OldPassword->MaximumLength
);
Where += OldPassword->MaximumLength;
}
ASSERT(Where - (PUCHAR) PasswordInfo == (LONG) PasswordSize);
*Buffer = PasswordInfo;
Status = STATUS_SUCCESS;
Cleanup:
if (DomainHandle != NULL) {
LsaClose(DomainHandle);
}
if (SecretHandle != NULL) {
LsaClose(SecretHandle);
}
if (LocalBuffer != NULL) {
LsaFreeMemory(LocalBuffer);
}
if (SecretName.Buffer != NULL) {
MIDL_user_free(SecretName.Buffer);
}
return(Status);
}
NTSTATUS
NTAPI
LsapSetTrustedDomainInformation(
IN LSA_HANDLE PolicyHandle,
IN PSID TrustedDomainSid,
IN TRUSTED_INFORMATION_CLASS InformationClass,
IN PVOID Buffer
)
/*++
Routine Description:
The LsaSetTrustedDomainInformation API modifies information in the Trusted
Domain Object and in the Secret Object. The caller must have access
appropriate to the information to be changed in the Policy Object, see
the InformationClass parameter.
If the domain does not yet exist and the information class is
TrustedDomainNameInformation, then the domain is created. If the
domain exists and the class is TrustedDomainNameInformation, an
error is returned.
Arguments:
PolicyHandle - Handle from an LsaOpenPolicy call.
TrustedDomainSid - Sid of domain to modify.
InformationClass - Specifies the type of information being changed.
The information types and accesses required to change them are as
follows:
TrustedDomainNameInformation POLICY_TRUST_ADMIN
TrustedPosixOffsetInformation none
TrustedPasswordInformation POLICY_CREATE_SECRET
Buffer - Points to a structure containing the information appropriate
to the InformationClass parameter.
Return Value:
NTSTATUS - Standard Nt Result Code
STATUS_ACCESS_DENIED - Caller does not have the appropriate access
to complete the operation.
Others TBS
--*/
{
LSA_HANDLE DomainHandle = NULL;
LSA_HANDLE SecretHandle = NULL;
NTSTATUS Status;
PUNICODE_STRING OldPassword;
PUNICODE_STRING Password;
LSA_TRUST_INFORMATION DomainInformation;
PTRUSTED_DOMAIN_NAME_INFO NameInfo = NULL;
PTRUSTED_PASSWORD_INFO PasswordInfo;
UNICODE_STRING SecretName;
SecretName.Buffer = NULL;
//
// If the information is the domain name, try to create the domain.
//
if (InformationClass == TrustedDomainNameInformation) {
DomainInformation.Sid = TrustedDomainSid;
DomainInformation.Name = ((PTRUSTED_DOMAIN_NAME_INFO) Buffer)->Name;
Status = LsaCreateTrustedDomain(
PolicyHandle,
&DomainInformation,
0, //desired access,
&DomainHandle
);
goto Cleanup;
}
//
// For posix offset, open the domain for SET_POSIX and call the old
// LSA API to set the offset.
//
if (InformationClass == TrustedPosixOffsetInformation) {
Status = LsaOpenTrustedDomain(
PolicyHandle,
TrustedDomainSid,
TRUSTED_SET_POSIX,
&DomainHandle
);
if (!NT_SUCCESS(Status)) {
goto Cleanup;
}
Status = LsaSetInformationTrustedDomain(
DomainHandle,
InformationClass,
Buffer
);
goto Cleanup;
}
//
// The only only remaining allowed class is password information.
//
if (InformationClass != TrustedPasswordInformation) {
Status = STATUS_INVALID_PARAMETER;
goto Cleanup;
}
Status = LsaOpenTrustedDomain(
PolicyHandle,
TrustedDomainSid,
TRUSTED_QUERY_DOMAIN_NAME,
&DomainHandle
);
if (!NT_SUCCESS(Status)) {
goto Cleanup;
}
//
// Get the name so we can find the secret name.
//
Status = LsaQueryInfoTrustedDomain(
DomainHandle,
TrustedDomainNameInformation,
&NameInfo
);
if (!NT_SUCCESS(Status)) {
goto Cleanup;
}
//
// Get the secret name
//
Status = LsapApiBuildSecretName(
NameInfo,
&SecretName
);
if (!NT_SUCCESS(Status)) {
goto Cleanup;
}
Status = LsaOpenSecret(
PolicyHandle,
&SecretName,
SECRET_SET_VALUE,
&SecretHandle
);
//
// If the secret didn't exist, create it now.
//
if (Status == STATUS_OBJECT_NAME_NOT_FOUND) {
Status = LsaCreateSecret(
PolicyHandle,
&SecretName,
SECRET_SET_VALUE,
&SecretHandle
);
}
if (!NT_SUCCESS(Status)) {
goto Cleanup;
}
//
// If the old password wasn't specified, set it to be the new
// password.
//
PasswordInfo = (PTRUSTED_PASSWORD_INFO) Buffer;
Password = &PasswordInfo->Password;
if (PasswordInfo->OldPassword.Buffer == NULL) {
OldPassword = Password;
} else {
OldPassword = &PasswordInfo->OldPassword;
}
Status = LsaSetSecret(
SecretHandle,
Password,
OldPassword
);
Cleanup:
if (SecretName.Buffer != NULL) {
MIDL_user_free(SecretName.Buffer);
}
if (DomainHandle != NULL) {
LsaClose(DomainHandle);
}
if (SecretHandle != NULL) {
LsaClose(SecretHandle);
}
if (NameInfo != NULL) {
LsaFreeMemory(NameInfo);
}
return(Status);
}
NTSTATUS
NTAPI
LsapDeleteTrustedDomain(
IN LSA_HANDLE PolicyHandle,
IN PSID TrustedDomainSid
)
/*++
Routine Description:
This routine deletes a trusted domain and the associated secret.
Arguments:
PolicyHandle - Handle from an LsaOpenPolicy call.
TrustedDomainSid - Sid of domain to delete
Return Value:
STATUS_ACCESS_DENIED - caller has insufficient access to delete
the requested domain.
STATUS_OBJECT_NAME_NOT_FOUND - The requested domain does not exist.
--*/
{
UNICODE_STRING SecretName;
NTSTATUS Status;
PTRUSTED_DOMAIN_NAME_INFO NameInfo = NULL;
LSA_HANDLE DomainHandle = NULL;
LSA_HANDLE SecretHandle = NULL;
SecretName.Buffer = NULL;
//
// Open the domain for query name and delete access. We need query name
// to find the secret name.
//
Status = LsaOpenTrustedDomain(
PolicyHandle,
TrustedDomainSid,
TRUSTED_QUERY_DOMAIN_NAME | DELETE,
&DomainHandle
);
if (!NT_SUCCESS(Status)) {
goto Cleanup;
}
//
// Get the name so we can find the secret name.
//
Status = LsaQueryInfoTrustedDomain(
DomainHandle,
TrustedDomainNameInformation,
&NameInfo
);
if (!NT_SUCCESS(Status)) {
goto Cleanup;
}
Status = LsaDelete(DomainHandle);
if (!NT_SUCCESS(Status)) {
goto Cleanup;
}
//
// Zero the handle so we don't try to free it again.
//
DomainHandle = NULL;
//
// Get the secret name
//
Status = LsapApiBuildSecretName(
NameInfo,
&SecretName
);
if (!NT_SUCCESS(Status)) {
goto Cleanup;
}
Status = LsaOpenSecret(
PolicyHandle,
&SecretName,
DELETE,
&SecretHandle
);
if (!NT_SUCCESS(Status)) {
//
// If the secret does not exist, that is o.k. - it means the password
// was never set.
//
if (Status == STATUS_OBJECT_NAME_NOT_FOUND) {
Status = STATUS_SUCCESS;
}
goto Cleanup;
}
Status = LsaDelete(SecretHandle);
if (NT_SUCCESS(Status)) {
//
// Zero the handle so we don't try to free it again.
//
SecretHandle = NULL;
}
Cleanup:
if (NameInfo != NULL) {
LsaFreeMemory(NameInfo);
}
if (SecretName.Buffer != NULL) {
MIDL_user_free(SecretName.Buffer);
}
if (SecretHandle != NULL) {
LsaClose(SecretHandle);
}
if (DomainHandle != NULL) {
LsaClose(DomainHandle);
}
return(Status);
}
NTSTATUS
NTAPI
LsapStorePrivateData(
IN LSA_HANDLE PolicyHandle,
IN PUNICODE_STRING KeyName,
IN OPTIONAL PUNICODE_STRING PrivateData
)
/*++
Routine Description:
This routine stores private data in a secret named KeyName.
Arguments:
PolicyHandle - Handle from an LsaOpenPolicyCall. If this is the
first call, it requres POLICY_CREATE_SECRET access.
KeyName - Name of secret to store
PrivateData - Private data to store. If this is null, the secret is
deleted.
Return Value:
STATUS_ACCESS_DENIED - caller has insufficient privilege to set
the workstation password.
--*/
{
LSA_HANDLE SecretHandle = NULL;
NTSTATUS Status;
ULONG DesiredAccess;
BOOLEAN DeleteSecret = FALSE;
//
// check whether to delete the secret or not.
//
if (ARGUMENT_PRESENT(PrivateData)) {
DesiredAccess = SECRET_SET_VALUE;
} else {
DesiredAccess = DELETE;
DeleteSecret = TRUE;
}
Status = LsaOpenSecret(
PolicyHandle,
KeyName,
DesiredAccess,
&SecretHandle
);
if ((Status == STATUS_OBJECT_NAME_NOT_FOUND) && !DeleteSecret) {
Status = LsaCreateSecret(
PolicyHandle,
KeyName,
DesiredAccess,
&SecretHandle
);
}
if (!NT_SUCCESS(Status)) {
goto Cleanup;
}
if (DeleteSecret) {
Status = LsaDelete(
SecretHandle
);
if (NT_SUCCESS(Status)) {
SecretHandle = NULL;
}
goto Cleanup;
}
Status = LsaSetSecret(
SecretHandle,
PrivateData,
PrivateData
);
Cleanup:
if (SecretHandle != NULL) {
LsaClose(SecretHandle);
}
return(Status);
}
NTSTATUS
NTAPI
LsapRetrievePrivateData(
IN LSA_HANDLE PolicyHandle,
IN PUNICODE_STRING KeyName,
OUT PUNICODE_STRING * PrivateData
)
/*++
Routine Description:
This routine returns the secret data stored under KeyName.
Arguments:
PolicyHandle - Handle from an LsaOpenPolicyCall
KeyName - Name of secret data to retrieve
PrivateData - Receives a pointer private data
Return Value:
STATUS_ACCESS_DENIED - caller has insufficient access to get the
workstation password.
STATUS_OBJECT_NAME_NOT_FOUND - there is no workstation password.
--*/
{
LSA_HANDLE SecretHandle = NULL;
NTSTATUS Status;
//
// Make the secret name
//
Status = LsaOpenSecret(
PolicyHandle,
KeyName,
SECRET_QUERY_VALUE,
&SecretHandle
);
if (!NT_SUCCESS(Status)) {
goto Cleanup;
}
Status = LsaQuerySecret(
SecretHandle,
PrivateData,
NULL,
NULL,
NULL
);
Cleanup:
if (SecretHandle != NULL) {
LsaClose(SecretHandle);
}
return(Status);
}
/////////////////////////////////////////////////////////////////////////
//
// RPC wrappers for LSA APIs added in nt3.51. This routines call the
// LSA, and if the interface doesn't exist, calls the LsapXXX routine
// to accomplish the same task using the older routines.
//
////////////////////////////////////////////////////////////////////////
NTSTATUS
NTAPI
LsaEnumerateAccountsWithUserRight(
IN LSA_HANDLE PolicyHandle,
IN OPTIONAL PUNICODE_STRING UserRight,
OUT PVOID *Buffer,
OUT PULONG CountReturned
)
/*++
Routine Description:
The LsaEnumerateAccounts API returns information about the accounts
in the target system's Lsa Database. This call requires
LSA_ENUMERATE_ACCOUNTS access to the Policy object. Since this call
accesses the privileges of an account, you must have PRIVILEGE_VIEW
access to the pseudo-privilege object.
Arguments:
PolicyHandle - Handle from an LsaOpenPolicy call.
UserRight - Name of the right that the account must have.
Buffer - Receives a pointer to a LSA_ENUMERATION_INFORMATION structure
containing the SIDs of all the accounts.
CountReturned - Receives the number of sids returned.
Return Values:
NTSTATUS - Standard Nt Result Code
STATUS_ACCESS_DENIED - Caller does not have the appropriate access
to complete the operation.
STATUS_NO_MORE_ENTRIES - There are no more entries. This warning
is returned if no objects are enumerated because the
EnumerationContext value passed in is too high.
--*/
{
NTSTATUS Status;
LSAPR_ACCOUNT_ENUM_BUFFER EnumerationBuffer;
EnumerationBuffer.EntriesRead = 0;
EnumerationBuffer.Information = NULL;
RpcTryExcept {
//
// Enumerate the Accounts. On successful return,
// the Enumeration Buffer structure will receive a count
// of the number of Accounts enumerated this call
// and a pointer to an array of Account Information Entries.
//
// EnumerationBuffer -> EntriesRead
// Information -> Account Info for Domain 0
// Account Info for Domain 1
// ...
// Account Info for Domain
// (EntriesRead - 1)
//
Status = LsarEnumerateAccountsWithUserRight(
(LSAPR_HANDLE) PolicyHandle,
(PLSAPR_UNICODE_STRING) UserRight,
&EnumerationBuffer
);
//
// Return enumeration information or NULL to caller.
//
// NOTE: "Information" is allocated by the called client stub
// as a single block via MIDL_user_allocate, because Information is
// allocated all-nodes. We can therefore pass back the pointer
// directly to the client, who will be able to free the memory after
// use via LsaFreeMemory() [which makes a MIDL_user_free call].
//
*CountReturned = EnumerationBuffer.EntriesRead;
*Buffer = EnumerationBuffer.Information;
} RpcExcept( I_RpcExceptionFilter( RpcExceptionCode()) ) {
//
// If memory was allocated for the Account Information array,
// free it.
//
if (EnumerationBuffer.Information != NULL) {
MIDL_user_free(EnumerationBuffer.Information);
}
Status = LsapApiReturnResult(I_RpcMapWin32Status(RpcExceptionCode()));
} RpcEndExcept;
//
// If the RPC server stub didn't exist, use the old version of the
// API.
//
if ((Status == RPC_NT_UNKNOWN_IF) ||
(Status == RPC_NT_PROCNUM_OUT_OF_RANGE)) {
Status = LsapEnumerateAccountsWithUserRight(
PolicyHandle,
UserRight,
Buffer,
CountReturned
);
}
return Status;
}
NTSTATUS
NTAPI
LsaEnumerateAccountRights(
IN LSA_HANDLE PolicyHandle,
IN PSID AccountSid,
OUT PUNICODE_STRING *UserRights,
OUT PULONG CountOfRights
)
/*++
Routine Description:
Returns all the rights of an account. This is done by gathering the
privileges and system access of an account and translating that into
an array of strings.
Arguments:
PolicyHandle - Handle from an LsaOpenPolicyCall. This API requires
no special access.
AccountSid - Sid of account to open.
UserRights - receives an array of user rights (UNICODE_STRING) for
the account.
CountOfRights - receives the number of rights returned.
Return Value:
STATUS_ACCESS_DENIED - the caller did not have sufficient access to
return the privileges or system access of the account.
STATUS_OBJECT_NAME_NOT_FOUND - the specified account did not exist.
STATUS_INSUFFICIENT_RESOURCES - not enough memory to process the
request.
--*/
{
NTSTATUS Status;
LSAPR_USER_RIGHT_SET UserRightSet;
UserRightSet.Entries = 0;
UserRightSet.UserRights = NULL;
RpcTryExcept {
Status = LsarEnumerateAccountRights(
(LSAPR_HANDLE) PolicyHandle,
(PLSAPR_SID) AccountSid,
&UserRightSet
);
*CountOfRights = UserRightSet.Entries;
*UserRights = (PUNICODE_STRING) UserRightSet.UserRights;
} RpcExcept( I_RpcExceptionFilter( RpcExceptionCode()) ) {
Status = LsapApiReturnResult(I_RpcMapWin32Status(RpcExceptionCode()));
if (UserRightSet.UserRights != NULL) {
MIDL_user_free(UserRightSet.UserRights);
}
} RpcEndExcept;
//
// If the RPC server stub didn't exist, use the old version of the
// API.
//
if ((Status == RPC_NT_UNKNOWN_IF) ||
(Status == RPC_NT_PROCNUM_OUT_OF_RANGE)) {
Status = LsapEnumerateAccountRights(
PolicyHandle,
AccountSid,
UserRights,
CountOfRights
);
}
return Status;
}
NTSTATUS
NTAPI
LsaAddAccountRights(
IN LSA_HANDLE PolicyHandle,
IN PSID AccountSid,
IN PUNICODE_STRING UserRights,
IN ULONG CountOfRights
)
/*++
Routine Description:
Adds rights to the account specified by the account sid. If the account
does not exist, it creates the account.
Arguments:
PolicyHandle - Handle from an LsaOpenPolicy call. The handle must have
POLICY_CREATE_ACCOUNT access if this is the first call for this
AccountSid.
AccountSid - Sid of account to add rights to
UserRights - Array of unicode strings naming rights to add to the
account.
Return Value:
STATUS_INSUFFICIENT_RESOURCES - not enough memory to process the request
STATUS_INVALID_PARAMTER - one of the parameters was not present
STATUS_NO_SUCH_PRIVILEGE - One of the user rights was invalid
STATUS_ACCESS_DENIED - the caller does not have sufficient access to the
account to add privileges.
--*/
{
NTSTATUS Status;
LSAPR_USER_RIGHT_SET UserRightSet;
UserRightSet.Entries = CountOfRights;
UserRightSet.UserRights = (PLSAPR_UNICODE_STRING) UserRights;
RpcTryExcept {
Status = LsarAddAccountRights(
(LSAPR_HANDLE) PolicyHandle,
(PLSAPR_SID) AccountSid,
&UserRightSet
);
} RpcExcept( I_RpcExceptionFilter( RpcExceptionCode()) ) {
Status = LsapApiReturnResult(I_RpcMapWin32Status(RpcExceptionCode()));
} RpcEndExcept;
//
// If the RPC server stub didn't exist, use the old version of the
// API.
//
if ((Status == RPC_NT_UNKNOWN_IF) ||
(Status == RPC_NT_PROCNUM_OUT_OF_RANGE)) {
Status = LsapAddAccountRights(
PolicyHandle,
AccountSid,
UserRights,
CountOfRights
);
}
return Status;
}
NTSTATUS
NTAPI
LsaRemoveAccountRights(
IN LSA_HANDLE PolicyHandle,
IN PSID AccountSid,
IN BOOLEAN AllRights,
IN PUNICODE_STRING UserRights,
IN ULONG CountOfRights
)
/*++
Routine Description:
Removes rights to the account specified by the account sid. If the
AllRights flag is set or if all the rights are removed, the account
is deleted.
Arguments:
PolicyHandle - Handle from an LsaOpenPolicy call
AccountSid - Sid of account to remove rights from
UserRights - Array of unicode strings naming rights to remove from the
account.
Return Value:
STATUS_INSUFFICIENT_RESOURCES - not enough memory to process the request
STATUS_INVALID_PARAMTER - one of the parameters was not present
STATUS_NO_SUCH_PRIVILEGE - One of the user rights was invalid
STATUS_ACCESS_DENIED - the caller does not have sufficient access to the
account to add privileges.
--*/
{
NTSTATUS Status;
LSAPR_USER_RIGHT_SET UserRightSet;
UserRightSet.Entries = CountOfRights;
UserRightSet.UserRights = (PLSAPR_UNICODE_STRING) UserRights;
RpcTryExcept {
Status = LsarRemoveAccountRights(
(LSAPR_HANDLE) PolicyHandle,
(PLSAPR_SID) AccountSid,
AllRights,
&UserRightSet
);
} RpcExcept( I_RpcExceptionFilter( RpcExceptionCode()) ) {
Status = LsapApiReturnResult(I_RpcMapWin32Status(RpcExceptionCode()));
} RpcEndExcept;
if ((Status == RPC_NT_UNKNOWN_IF) ||
(Status == RPC_NT_PROCNUM_OUT_OF_RANGE)) {
Status = LsapRemoveAccountRights(
PolicyHandle,
AccountSid,
AllRights,
UserRights,
CountOfRights
);
}
return Status;
}
NTSTATUS
NTAPI
LsaQueryTrustedDomainInfo(
IN LSA_HANDLE PolicyHandle,
IN PSID TrustedDomainSid,
IN TRUSTED_INFORMATION_CLASS InformationClass,
OUT PVOID *Buffer
)
/*++
Routine Description:
The LsaQueryTrustedDomainInfo API obtains information from a
TrustedDomain object. The caller must have access appropriate to the
information being requested (see InformationClass parameter). It also
may query the secret object (for the TrustedDomainPasswordInformation
class).
Arguments:
PolicyHandle - Handle from an LsaOpenPolicy call.
TrustedDomainSid - Sid of domain to query.
InformationClass - Specifies the information to be returned.
Buffer - Receives a pointer to the buffer returned comtaining the
requested information. This buffer is allocated by this service
and must be freed when no longer needed by passing the returned
value to LsaFreeMemory().
Return Value:
NTSTATUS - Standard Nt Result Code
STATUS_ACCESS_DENIED - Caller does not have the appropriate
access to complete the operation.
STATUS_INSUFFICIENT_RESOURCES - Insufficient system resources,
such as memory, to complete the call.
--*/
{
NTSTATUS Status;
PLSAP_CR_CIPHER_VALUE CipherPassword = NULL;
PLSAP_CR_CIPHER_VALUE CipherOldPassword = NULL;
PLSAP_CR_CLEAR_VALUE ClearPassword = NULL;
PLSAP_CR_CLEAR_VALUE ClearOldPassword = NULL;
PLSAP_CR_CIPHER_KEY SessionKey = NULL;
ULONG DomainInfoSize;
PUCHAR Where = NULL;
PTRUSTED_PASSWORD_INFO PasswordInformation = NULL;
PLSAPR_TRUSTED_DOMAIN_INFO TrustedDomainInformation = NULL;
//
// Avoid the internal info levels that represent the encrypted version on
// the wire.
//
switch ( InformationClass ) {
case TrustedDomainAuthInformationInternal:
case TrustedDomainFullInformationInternal:
return STATUS_INVALID_INFO_CLASS;
}
RpcTryExcept {
//
// Call the Client Stub for LsaQueryInformationTrustedDomain.
//
Status = LsarQueryTrustedDomainInfo(
(LSAPR_HANDLE) PolicyHandle,
(PLSAPR_SID) TrustedDomainSid,
InformationClass,
&TrustedDomainInformation
);
//
// Return pointer to Policy Information for the given class, or NULL.
//
} RpcExcept( I_RpcExceptionFilter( RpcExceptionCode()) ) {
//
// If memory was allocated for the returned Trusted Domain Information,
// free it.
//
if (TrustedDomainInformation != NULL) {
MIDL_user_free(TrustedDomainInformation);
}
Status = LsapApiReturnResult(I_RpcMapWin32Status(RpcExceptionCode()));
} RpcEndExcept;
if (!NT_SUCCESS(Status)) {
goto Cleanup;
}
//
// if we aren't getting passwords, skip out here. Otherwise we need to
// decrypt the passwords.
//
if (InformationClass != TrustedPasswordInformation) {
*Buffer = TrustedDomainInformation;
TrustedDomainInformation = NULL;
goto Cleanup;
}
//
// Obtain the Session Key to be used to two-way encrypt the
// Current Value and/or Old Values.
//
RpcTryExcept {
Status = LsapCrClientGetSessionKey( PolicyHandle, &SessionKey );
} RpcExcept( I_RpcExceptionFilter( RpcExceptionCode()) ) {
Status = LsapApiReturnResult(I_RpcMapWin32Status(RpcExceptionCode()));
} RpcEndExcept;
if (!NT_SUCCESS(Status)) {
goto Cleanup;
}
//
// If the Current Value is requested and a Current Value exists,
// decrypt it using the Session key. Otherwise store NULL for return.
//
if (TrustedDomainInformation->TrustedPasswordInfo.Password != NULL) {
Status = LsapCrDecryptValue(
(PLSAP_CR_CIPHER_VALUE)
TrustedDomainInformation->TrustedPasswordInfo.Password,
SessionKey,
&ClearPassword
);
if (!NT_SUCCESS(Status)) {
goto Cleanup;
}
//
// Convert Clear Current Value to Unicode
//
LsapCrClearValueToUnicode(
ClearPassword,
(PUNICODE_STRING) ClearPassword
);
}
//
// Get the old password
//
if (TrustedDomainInformation->TrustedPasswordInfo.OldPassword != NULL) {
Status = LsapCrDecryptValue(
(PLSAP_CR_CIPHER_VALUE)
TrustedDomainInformation->TrustedPasswordInfo.OldPassword,
SessionKey,
&ClearOldPassword
);
if (!NT_SUCCESS(Status)) {
goto Cleanup;
}
//
// Convert Clear Current Value to Unicode
//
LsapCrClearValueToUnicode(
ClearOldPassword,
(PUNICODE_STRING) ClearOldPassword
);
}
MIDL_user_free(TrustedDomainInformation);
TrustedDomainInformation = NULL;
//
// Allocate a buffer for the two passwords and marshall the
// passwords into the buffer.
//
DomainInfoSize = sizeof(TRUSTED_PASSWORD_INFO);
if (ClearPassword != NULL) {
DomainInfoSize += ((PUNICODE_STRING) ClearPassword)->MaximumLength;
}
if (ClearOldPassword != NULL) {
DomainInfoSize += ((PUNICODE_STRING) ClearOldPassword)->MaximumLength;
}
PasswordInformation = (PTRUSTED_PASSWORD_INFO) MIDL_user_allocate(DomainInfoSize);
if (PasswordInformation == NULL) {
Status = STATUS_INSUFFICIENT_RESOURCES;
goto Cleanup;
}
Where = (PUCHAR) (PasswordInformation+1);
if (ClearPassword != NULL)
{
PasswordInformation->Password = *(PUNICODE_STRING) ClearPassword;
PasswordInformation->Password.Buffer = (LPWSTR) Where;
Where += PasswordInformation->Password.MaximumLength;
RtlCopyUnicodeString(
&PasswordInformation->Password,
(PUNICODE_STRING) ClearPassword
);
}
if (ClearOldPassword != NULL)
{
PasswordInformation->OldPassword = *(PUNICODE_STRING) ClearOldPassword;
PasswordInformation->OldPassword.Buffer = (LPWSTR) Where;
Where += PasswordInformation->OldPassword.MaximumLength;
RtlCopyUnicodeString(
&PasswordInformation->OldPassword,
(PUNICODE_STRING) ClearOldPassword
);
}
ASSERT(Where - (PUCHAR) PasswordInformation == (LONG) DomainInfoSize);
*Buffer = PasswordInformation;
PasswordInformation = NULL;
Status = STATUS_SUCCESS;
Cleanup:
//
// If necessary, free memory allocated for the Session Key.
//
if (SessionKey != NULL) {
MIDL_user_free(SessionKey);
}
//
// If necessary, free memory allocated for the returned Encrypted
// Current Value.
//
if (CipherPassword != NULL) {
LsapCrFreeMemoryValue(CipherPassword);
}
//
// If necessary, free memory allocated for the returned Encrypted
// Old Value.
//
if (CipherOldPassword != NULL) {
LsapCrFreeMemoryValue(CipherOldPassword);
}
if (ClearPassword != NULL) {
LsapCrFreeMemoryValue(ClearPassword);
}
if (ClearOldPassword != NULL) {
LsapCrFreeMemoryValue(ClearOldPassword);
}
if (TrustedDomainInformation != NULL) {
MIDL_user_free(TrustedDomainInformation);
}
if (PasswordInformation != NULL) {
MIDL_user_free(PasswordInformation);
}
//
// If the error was that the server stub didn't exist, call
// the old version of the API.
//
if ((Status == RPC_NT_UNKNOWN_IF) ||
(Status == RPC_NT_PROCNUM_OUT_OF_RANGE)) {
Status = LsapQueryTrustedDomainInfo(
PolicyHandle,
TrustedDomainSid,
InformationClass,
Buffer
);
}
return Status;
}
NTSTATUS
NTAPI
LsaSetTrustedDomainInformation(
IN LSA_HANDLE PolicyHandle,
IN PSID TrustedDomainSid,
IN TRUSTED_INFORMATION_CLASS InformationClass,
IN PVOID Buffer
)
/*++
Routine Description:
The LsaSetTrustedDomainInformation API modifies information in the Trusted
Domain Object and in the Secret Object. The caller must have access
appropriate to the information to be changed in the Policy Object, see
the InformationClass parameter.
If the domain does not yet exist and the information class is
TrustedDomainNameInformation, then the domain is created. If the
domain exists and the class is TrustedDomainNameInformation, an
error is returned.
Arguments:
PolicyHandle - Handle from an LsaOpenPolicy call.
TrustedDomainSid - Sid of domain to modify.
InformationClass - Specifies the type of information being changed.
The information types and accesses required to change them are as
follows:
TrustedDomainNameInformation POLICY_TRUST_ADMIN
TrustedPosixOffsetInformation none
TrustedPasswordInformation POLICY_CREATE_SECRET
Buffer - Points to a structure containing the information appropriate
to the InformationClass parameter.
Return Value:
NTSTATUS - Standard Nt Result Code
STATUS_ACCESS_DENIED - Caller does not have the appropriate access
to complete the operation.
STATUS_INVALID_INFO_CLASS - Setting information for specified information class
is not supported
Others TBS
--*/
{
NTSTATUS Status;
PLSAPR_TRUSTED_DOMAIN_INFO DomainInformation;
LSAPR_TRUSTED_PASSWORD_INFO LsaPasswordInfo;
PTRUSTED_PASSWORD_INFO PasswordInformation;
PLSAP_CR_CIPHER_VALUE CipherPassword = NULL;
LSAP_CR_CLEAR_VALUE ClearPassword;
PLSAP_CR_CIPHER_VALUE CipherOldPassword = NULL;
LSAP_CR_CLEAR_VALUE ClearOldPassword;
PLSAP_CR_CIPHER_KEY SessionKey = NULL;
PUNICODE_STRING OldPassword;
//
// If the infotype is TrustedPasswordInformation, then we need to
// setup a secure channel to transmit the secret passwords.
//
switch ( InformationClass ) {
case TrustedPasswordInformation:
PasswordInformation = (PTRUSTED_PASSWORD_INFO) Buffer;
LsaPasswordInfo.Password = NULL;
LsaPasswordInfo.OldPassword = NULL;
//
// Obtain the Session Key to be used to two-way encrypt the
// Current Value.
//
RpcTryExcept {
Status = LsapCrClientGetSessionKey( PolicyHandle, &SessionKey );
} RpcExcept( I_RpcExceptionFilter( RpcExceptionCode()) ) {
Status = LsapApiReturnResult(I_RpcMapWin32Status(RpcExceptionCode()));
} RpcEndExcept;
if (!NT_SUCCESS(Status)) {
goto Cleanup;
}
//
// The password must be specified, even if it is an empty string.
//
if (PasswordInformation->Password.Buffer != NULL) {
//
// Convert input from Unicode Structures to Clear Value Structures.
//
LsapCrUnicodeToClearValue(
&PasswordInformation->Password,
&ClearPassword
);
//
// Encrypt the Current Value if specified and not too long.
//
Status = LsapCrEncryptValue(
&ClearPassword,
SessionKey,
&CipherPassword
);
if (!NT_SUCCESS(Status)) {
goto Cleanup;
}
LsaPasswordInfo.Password = (PLSAPR_CR_CIPHER_VALUE) CipherPassword;
//
// If the old password wasn't specified, set it to be the
// new password.
//
if (PasswordInformation->OldPassword.Buffer == NULL) {
OldPassword = &PasswordInformation->Password;
} else {
OldPassword = &PasswordInformation->OldPassword;
}
//
// Convert input from Unicode Structures to Clear Value Structures.
//
LsapCrUnicodeToClearValue(
OldPassword,
&ClearOldPassword
);
//
// Encrypt the Current Value if specified and not too long.
//
Status = LsapCrEncryptValue(
&ClearOldPassword,
SessionKey,
&CipherOldPassword
);
if (!NT_SUCCESS(Status)) {
goto Cleanup;
}
LsaPasswordInfo.OldPassword = (PLSAPR_CR_CIPHER_VALUE) CipherOldPassword;
} else {
Status = STATUS_INVALID_PARAMETER;
goto Cleanup;
}
DomainInformation = (PLSAPR_TRUSTED_DOMAIN_INFO) &LsaPasswordInfo;
break;
//
// There are only two other info levels handled
//
case TrustedPosixOffsetInformation:
case TrustedDomainNameInformation:
DomainInformation = (PLSAPR_TRUSTED_DOMAIN_INFO) Buffer;
break;
//
// No other info levels are supported
//
default:
return STATUS_INVALID_INFO_CLASS;
}
RpcTryExcept {
//
// Call the Client Stub for LsaSetInformationTrustedDomain
//
Status = LsarSetTrustedDomainInfo
(
(LSAPR_HANDLE) PolicyHandle,
(PLSAPR_SID) TrustedDomainSid,
InformationClass,
DomainInformation
);
} RpcExcept( I_RpcExceptionFilter( RpcExceptionCode()) ) {
Status = LsapApiReturnResult(I_RpcMapWin32Status(RpcExceptionCode()));
} RpcEndExcept;
Cleanup:
if (SessionKey != NULL) {
MIDL_user_free(SessionKey);
}
if (CipherPassword != NULL) {
LsaFreeMemory(CipherPassword);
}
if (CipherOldPassword != NULL) {
LsaFreeMemory(CipherOldPassword);
}
//
// If the error was that the server stub didn't exist, call
// the old version of the API.
//
if ((Status == RPC_NT_UNKNOWN_IF) ||
(Status == RPC_NT_PROCNUM_OUT_OF_RANGE)) {
Status = LsapSetTrustedDomainInformation(
PolicyHandle,
TrustedDomainSid,
InformationClass,
Buffer
);
}
return Status;
}
NTSTATUS
NTAPI
LsaDeleteTrustedDomain(
IN LSA_HANDLE PolicyHandle,
IN PSID TrustedDomainSid
)
/*++
Routine Description:
This routine deletes a trusted domain and the associated secret.
Arguments:
PolicyHandle - Handle from an LsaOpenPolicy call.
TrustedDomainSid - Sid of domain to delete
Return Value:
STATUS_ACCESS_DENIED - caller has insufficient access to delete
the requested domain.
STATUS_OBJECT_NAME_NOT_FOUND - The requested domain does not exist.
--*/
{
NTSTATUS Status;
RpcTryExcept {
Status = LsarDeleteTrustedDomain(
(LSAPR_HANDLE) PolicyHandle,
(PLSAPR_SID) TrustedDomainSid
);
} RpcExcept( I_RpcExceptionFilter( RpcExceptionCode()) ) {
Status = LsapApiReturnResult(I_RpcMapWin32Status(RpcExceptionCode()));
} RpcEndExcept;
//
// If the error was that the server stub didn't exist, call
// the old version of the API.
//
if ((Status == RPC_NT_UNKNOWN_IF) ||
(Status == RPC_NT_PROCNUM_OUT_OF_RANGE)) {
Status = LsapDeleteTrustedDomain(
PolicyHandle,
TrustedDomainSid
);
}
return(Status);
}
//
// This API sets the workstation password (equivalent of setting/getting
// the SSI_SECRET_NAME secret)
//
NTSTATUS
NTAPI
LsaStorePrivateData(
IN LSA_HANDLE PolicyHandle,
IN PUNICODE_STRING KeyName,
IN OPTIONAL PUNICODE_STRING PrivateData
)
/*++
Routine Description:
This routine stores private data in an LSA secret named KeyName.
Arguments:
PolicyHandle - Handle from an LsaOpenPolicyCall. If this is the
first call, it requres POLICY_CREATE_SECRET access.
KeyName - Name of secret to store.
PrivateData - Data to store. If not present, the secret is deleted.
Return Value:
STATUS_ACCESS_DENIED - caller has insufficient privilege to set
the workstation password.
--*/
{
NTSTATUS Status;
PLSAP_CR_CIPHER_VALUE CipherCurrentValue = NULL;
LSAP_CR_CLEAR_VALUE ClearCurrentValue;
PLSAP_CR_CIPHER_KEY SessionKey = NULL;
if (ARGUMENT_PRESENT(PrivateData)) {
//
// Convert input from Unicode Structures to Clear Value Structures.
//
LsapCrUnicodeToClearValue( PrivateData, &ClearCurrentValue );
//
// Obtain the Session Key to be used to two-way encrypt the
// Current Value.
//
RpcTryExcept {
Status = LsapCrClientGetSessionKey( PolicyHandle, &SessionKey );
} RpcExcept( I_RpcExceptionFilter( RpcExceptionCode()) ) {
Status = LsapApiReturnResult(I_RpcMapWin32Status(RpcExceptionCode()));
} RpcEndExcept;
if (!NT_SUCCESS(Status)) {
goto Cleanup;
}
//
// Encrypt the Current Value if specified and not too long.
//
Status = LsapCrEncryptValue(
&ClearCurrentValue,
SessionKey,
&CipherCurrentValue
);
if (!NT_SUCCESS(Status)) {
goto Cleanup;
}
}
//
// Set the Secret Values.
//
RpcTryExcept {
Status = LsarStorePrivateData(
(LSAPR_HANDLE) PolicyHandle,
(PLSAPR_UNICODE_STRING) KeyName,
(PLSAPR_CR_CIPHER_VALUE) CipherCurrentValue
);
} RpcExcept( I_RpcExceptionFilter( RpcExceptionCode()) ) {
Status = LsapApiReturnResult(I_RpcMapWin32Status(RpcExceptionCode()));
} RpcEndExcept;
if (!NT_SUCCESS(Status)) {
goto Cleanup;
}
Cleanup:
//
// If necessary, free memory allocated for the Encrypted Current Value.
//
if (CipherCurrentValue != NULL) {
LsaFreeMemory(CipherCurrentValue);
}
//
// If necessary, free memory allocated for the Session Key.
//
if (SessionKey != NULL) {
MIDL_user_free(SessionKey);
}
//
// If the error was that the server stub didn't exist, call
// the old version of the API.
//
if ((Status == RPC_NT_UNKNOWN_IF) ||
(Status == RPC_NT_PROCNUM_OUT_OF_RANGE)) {
Status = LsapStorePrivateData(
PolicyHandle,
KeyName,
PrivateData
);
}
return(Status);
}
NTSTATUS
NTAPI
LsaRetrievePrivateData(
IN LSA_HANDLE PolicyHandle,
IN PUNICODE_STRING KeyName,
OUT PUNICODE_STRING *PrivateData
)
/*++
Routine Description:
This routine returns the secret stored in KeyName.
Arguments:
PolicyHandle - Handle from an LsaOpenPolicyCall
KeyName - Name of secret to retrieve
PrivateData - Receives private data, should be freed with LsaFreeMemory.
Return Value:
STATUS_ACCESS_DENIED - caller has insufficient access to get the
private data.
STATUS_OBJECT_NAME_NOT_FOUND - there is no private data stored under
KeyName.
--*/
{
NTSTATUS Status = STATUS_SUCCESS;
PLSAP_CR_CIPHER_VALUE CipherCurrentValue = NULL;
PLSAP_CR_CLEAR_VALUE ClearCurrentValue = NULL;
PLSAP_CR_CIPHER_KEY SessionKey = NULL;
RpcTryExcept {
Status = LsarRetrievePrivateData(
(PLSAPR_HANDLE) PolicyHandle,
(PLSAPR_UNICODE_STRING) KeyName,
(PLSAPR_CR_CIPHER_VALUE *) &CipherCurrentValue
);
} RpcExcept( I_RpcExceptionFilter( RpcExceptionCode()) ) {
Status = LsapApiReturnResult(I_RpcMapWin32Status(RpcExceptionCode()));
} RpcEndExcept;
if (!NT_SUCCESS(Status)) {
goto QuerySecretError;
}
//
// Obtain the Session Key to be used to two-way encrypt the
// Current Value and/or Old Values.
//
RpcTryExcept {
Status = LsapCrClientGetSessionKey( PolicyHandle, &SessionKey );
} RpcExcept( I_RpcExceptionFilter( RpcExceptionCode()) ) {
Status = LsapApiReturnResult(I_RpcMapWin32Status(RpcExceptionCode()));
} RpcEndExcept;
if (!NT_SUCCESS(Status)) {
goto QuerySecretError;
}
//
// If the Current Value is requested and a Current Value exists,
// decrypt it using the Session key. Otherwise store NULL for return.
//
if (CipherCurrentValue != NULL) {
Status = LsapCrDecryptValue(
CipherCurrentValue,
SessionKey,
&ClearCurrentValue
);
if (!NT_SUCCESS(Status)) {
goto QuerySecretError;
}
//
// Convert Clear Current Value to Unicode
//
LsapCrClearValueToUnicode(
ClearCurrentValue,
(PUNICODE_STRING) ClearCurrentValue
);
*PrivateData = (PUNICODE_STRING) ClearCurrentValue;
} else {
*PrivateData = NULL;
}
QuerySecretFinish:
//
// If necessary, free memory allocated for the Session Key.
//
if (SessionKey != NULL) {
MIDL_user_free(SessionKey);
}
//
// If necessary, free memory allocated for the returned Encrypted
// Current Value.
//
if (CipherCurrentValue != NULL) {
LsapCrFreeMemoryValue(CipherCurrentValue);
}
//
// If the error was that the server stub didn't exist, call
// the old version of the API.
//
if ((Status == RPC_NT_UNKNOWN_IF) ||
(Status == RPC_NT_PROCNUM_OUT_OF_RANGE)) {
Status = LsapRetrievePrivateData(
PolicyHandle,
KeyName,
PrivateData
);
}
return(Status);
QuerySecretError:
//
// If necessary, free memory allocated for the Clear Current Value
//
if (ClearCurrentValue != NULL) {
LsapCrFreeMemoryValue(ClearCurrentValue);
}
*PrivateData = NULL;
goto QuerySecretFinish;
}
NTSTATUS
LsapApiConvertRightsToPrivileges(
IN LSA_HANDLE PolicyHandle,
IN PUNICODE_STRING UserRights,
IN ULONG RightCount,
OUT PPRIVILEGE_SET * Privileges,
OUT PULONG SystemAccess
)
/*++
Routine Description:
Converts an array of user rights (unicode strings) into a privilege set
and a system access flag.
Arguments:
PolicyHandle - Handle from an LsaOpenPolicyCall, requires POLICY_LOOKUP_NAME
access.
UserRights - Array of user rights
RightCount - Count of user rights
Privileges - Receives privilege set, should be freed with MIDL_user_free
SystemAccess - Receives system access flags.
Return Value:
--*/
{
ULONG RightIndex;
ULONG PrivilegeIndex;
ULONG AccessIndex;
PPRIVILEGE_SET PrivilegeSet = NULL;
ULONG Access = 0;
ULONG PrivilegeSetSize = 0;
NTSTATUS Status;
LUID PrivilegeValue;
//
// if we weren't passed any privileges, don't allocate anything.
//
if (RightCount == 0) {
*Privileges = NULL;
*SystemAccess = 0;
return(STATUS_SUCCESS);
}
//
// Compute the size of the privilege set. We actually over estimate
// by assuming that all the rights are privileges. We subtract one
// from RightCount to take into account the fact that a PRIVILEGE_SET
// has one LUID_AND_ATTRIBUTE in it.
//
PrivilegeSetSize = sizeof(PRIVILEGE_SET) +
(RightCount-1) * sizeof(LUID_AND_ATTRIBUTES);
PrivilegeSet = (PPRIVILEGE_SET) MIDL_user_allocate(PrivilegeSetSize);
if (PrivilegeSet == NULL) {
Status = STATUS_INSUFFICIENT_RESOURCES;
goto Cleanup;
}
//
// Try looking up every right. If we find it as a privilege,
// add it to the privilege set.
//
PrivilegeIndex = 0;
for (RightIndex = 0; RightIndex < RightCount ; RightIndex++) {
Status = LsaLookupPrivilegeValue(
PolicyHandle,
&UserRights[RightIndex],
&PrivilegeValue
);
if (NT_SUCCESS(Status)) {
PrivilegeSet->Privilege[PrivilegeIndex].Luid = PrivilegeValue;
PrivilegeSet->Privilege[PrivilegeIndex].Attributes = 0;
PrivilegeIndex++;
} else if (Status != STATUS_NO_SUCH_PRIVILEGE) {
//
// This is a more serious error - bail here.
//
goto Cleanup;
} else {
//
// Try looking up the right as a system access type.
//
for (AccessIndex = 0; AccessIndex < LSAP_DB_SYSTEM_ACCESS_TYPES ; AccessIndex++) {
if (RtlCompareUnicodeString(
&UserRights[RightIndex],
&LsapDbRightAndAccess[AccessIndex].UserRight,
FALSE // case sensitive
) == 0) {
Access |= LsapDbRightAndAccess[AccessIndex].SystemAccess;
break;
}
}
//
// If we went through the access types without finding the right,
// it must not be valid so escape here.
//
if (AccessIndex == LSAP_DB_SYSTEM_ACCESS_TYPES) {
Status = STATUS_NO_SUCH_PRIVILEGE;
goto Cleanup;
}
}
}
PrivilegeSet->Control = 0;
PrivilegeSet->PrivilegeCount = PrivilegeIndex;
*Privileges = PrivilegeSet;
*SystemAccess = Access;
Status = STATUS_SUCCESS;
Cleanup:
if (!NT_SUCCESS(Status)) {
if (PrivilegeSet != NULL) {
LsaFreeMemory(PrivilegeSet);
}
}
return(Status);
}
NTSTATUS
LsapApiConvertPrivilegesToRights(
IN LSA_HANDLE PolicyHandle,
IN OPTIONAL PPRIVILEGE_SET Privileges,
IN OPTIONAL ULONG SystemAccess,
OUT PUNICODE_STRING * UserRights,
OUT PULONG RightCount
)
/*++
Routine Description:
Converts a privilege set and a system access flag into an array of
user rights (unicode strings).
Arguments:
PolicyHandle - Handle from an LsaOpenPolicy call, must have
POLICY_LOOKUP_NAMES access.
Privileges - Privilege set to convert
SystemAccess - System access flags to convert
UserRights - Receives an array of user rights (unicode strings). Should
be freed with MIDL_user_free
RightCount - Receives count of rights in UserRights array
Return Value:
--*/
{
NTSTATUS Status;
PUNICODE_STRING OutputRights = NULL;
PUNICODE_STRING * PrivilegeNames = NULL;
UNICODE_STRING AccessNames[LSAP_DB_SYSTEM_ACCESS_TYPES];
ULONG RightSize;
ULONG PrivilegeSize;
ULONG Count;
ULONG PrivilegeIndex;
ULONG AccessIndex;
ULONG RightIndex;
ULONG AccessCount = 0;
PUCHAR Where;
//
// Compute the size of the temporary array. This is just an array of
// pointers to unicode strings to hold the privilege names until
// we reallocate them into one big buffer.
//
RightSize = 0;
Count = 0;
if (ARGUMENT_PRESENT(Privileges)) {
PrivilegeSize = Privileges->PrivilegeCount * sizeof(PUNICODE_STRING);
PrivilegeNames = (PUNICODE_STRING *) MIDL_user_allocate(PrivilegeSize);
if (PrivilegeNames == NULL) {
Status = STATUS_INSUFFICIENT_RESOURCES;
goto Cleanup;
}
RtlZeroMemory(
PrivilegeNames,
PrivilegeSize
);
//
// Lookup the privilge name and store it in the temporary array
//
for (PrivilegeIndex = 0; PrivilegeIndex < Privileges->PrivilegeCount ;PrivilegeIndex++ ) {
Status = LsaLookupPrivilegeName(
PolicyHandle,
&Privileges->Privilege[PrivilegeIndex].Luid,
&PrivilegeNames[PrivilegeIndex]
);
if (!NT_SUCCESS(Status)) {
goto Cleanup;
}
RightSize += sizeof(UNICODE_STRING) + PrivilegeNames[PrivilegeIndex]->MaximumLength;
}
}
//
// Now convert the system access flags to user rights.
//
if (ARGUMENT_PRESENT( (ULONG_PTR)SystemAccess )) {
AccessCount = 0;
for (AccessIndex = 0; AccessIndex < LSAP_DB_SYSTEM_ACCESS_TYPES ; AccessIndex++) {
if ((SystemAccess & LsapDbRightAndAccess[AccessIndex].SystemAccess) != 0) {
AccessNames[AccessCount] = LsapDbRightAndAccess[AccessIndex].UserRight;
RightSize += sizeof(UNICODE_STRING) + AccessNames[AccessCount].MaximumLength;
AccessCount++;
}
}
}
//
// Allocate the output buffer and start copying the strings into the
// buffer.
//
Count = Privileges->PrivilegeCount + AccessCount;
OutputRights = (PUNICODE_STRING) MIDL_user_allocate(RightSize);
if (OutputRights == NULL) {
Status = STATUS_INSUFFICIENT_RESOURCES;
goto Cleanup;
}
Where = (PUCHAR) OutputRights + (Count * sizeof(UNICODE_STRING));
//
// Copy in the privileges first
//
RightIndex = 0;
for (PrivilegeIndex = 0; PrivilegeIndex < Privileges->PrivilegeCount ; PrivilegeIndex ++) {
OutputRights[RightIndex] = *PrivilegeNames[PrivilegeIndex];
OutputRights[RightIndex].Buffer = (LPWSTR) Where;
RtlCopyMemory(
Where,
PrivilegeNames[PrivilegeIndex]->Buffer,
OutputRights[RightIndex].MaximumLength
);
Where += OutputRights[RightIndex].MaximumLength;
RightIndex++;
}
//
// Now copy in the access types
//
for (AccessIndex = 0; AccessIndex < AccessCount; AccessIndex++) {
OutputRights[RightIndex] = AccessNames[AccessIndex];
OutputRights[RightIndex].Buffer = (LPWSTR) Where;
RtlCopyMemory(
Where,
AccessNames[AccessIndex].Buffer,
OutputRights[RightIndex].MaximumLength
);
Where += OutputRights[RightIndex].MaximumLength;
RightIndex++;
}
ASSERT(RightIndex == Count);
*UserRights = OutputRights;
OutputRights = NULL;
*RightCount = Count;
Status = STATUS_SUCCESS;
Cleanup:
if (PrivilegeNames != NULL) {
for (PrivilegeIndex = 0; PrivilegeIndex < Privileges->PrivilegeCount ; PrivilegeIndex++) {
if (PrivilegeNames[PrivilegeIndex] != NULL) {
LsaFreeMemory(PrivilegeNames[PrivilegeIndex]);
}
}
MIDL_user_free(PrivilegeNames);
}
if (OutputRights != NULL) {
MIDL_user_free(OutputRights);
}
return(Status);
}
NTSTATUS
NTAPI
LsaQueryTrustedDomainInfoByName(
IN LSA_HANDLE PolicyHandle,
IN PUNICODE_STRING TrustedDomainName,
IN TRUSTED_INFORMATION_CLASS InformationClass,
OUT PVOID *Buffer
)
{
NTSTATUS Status;
//
// Avoid the internal info levels that represent the encrypted version on
// the wire.
//
switch ( InformationClass ) {
case TrustedDomainAuthInformationInternal:
case TrustedDomainFullInformationInternal:
return STATUS_INVALID_INFO_CLASS;
}
RpcTryExcept {
//
// Call the Client Stub for LsaClearAuditLog.
//
Status = LsarQueryTrustedDomainInfoByName(
(LSAPR_HANDLE) PolicyHandle,
(PLSAPR_UNICODE_STRING) TrustedDomainName,
InformationClass,
(PLSAPR_TRUSTED_DOMAIN_INFO *) Buffer
);
} RpcExcept( I_RpcExceptionFilter( RpcExceptionCode()) ) {
Status = LsapApiReturnResult(I_RpcMapWin32Status(RpcExceptionCode()));
} RpcEndExcept;
return(Status);
}
NTSTATUS
LsapRandomFill(
IN ULONG BufferSize,
IN OUT PUCHAR Buffer
)
/*++
Routine Description:
This routine fills a buffer with random data.
Parameters:
BufferSize - Length of the input buffer, in bytes.
Buffer - Input buffer to be filled with random data.
Return Values:
Errors from NtQuerySystemTime()
--*/
{
ULONG Index;
LARGE_INTEGER Time;
ULONG Seed;
NTSTATUS NtStatus;
NtStatus = NtQuerySystemTime(&Time);
if (!NT_SUCCESS(NtStatus)) {
return(NtStatus);
}
Seed = Time.LowPart ^ Time.HighPart;
for (Index = 0 ; Index < BufferSize ; Index++ )
{
*Buffer++ = (UCHAR) (RtlRandom(&Seed) % 256);
}
return(STATUS_SUCCESS);
}
NTSTATUS
LsapEncryptAuthInfo(
IN LSA_HANDLE PolicyHandle,
IN PLSAPR_TRUSTED_DOMAIN_AUTH_INFORMATION ClearAuthInfo,
IN PLSAPR_TRUSTED_DOMAIN_AUTH_INFORMATION_INTERNAL *EncryptedAuthInfo
)
/*++
Routine Description:
This routine takes a cleartext auth info and returns an encrypted auth info.
Parameters:
PolicyHandle - Handle to the LSA policy.
ClearAuthInfo - Cleartext of the authentication info.
EncryptedAuthInfo - Returns an allocated buffer containing the encrypted form
of the auth info. The caller should free this buffer using LocalFree.
Return Values:
STATUS_SUCCESS - the routine has completed successfully.
--*/
{
NTSTATUS Status;
USER_SESSION_KEY UserSessionKey;
ULONG IncomingAuthInfoSize = 0;
PUCHAR IncomingAuthInfo = NULL;
ULONG OutgoingAuthInfoSize = 0;
PUCHAR OutgoingAuthInfo = NULL;
ULONG EncryptedSize;
PUCHAR EncryptedBuffer;
PUCHAR AllocatedBuffer = NULL;
PUCHAR Where;
struct RC4_KEYSTRUCT Rc4Key;
//
// Get the encryption key
//
Status = RtlGetUserSessionKeyClient(
(RPC_BINDING_HANDLE)PolicyHandle,
&UserSessionKey );
if ( !NT_SUCCESS(Status)) {
goto Cleanup;
}
//
// Marshal the incoming and outgoing auth info halfs into contiguous buffers
//
Status = LsapDsMarshalAuthInfoHalf(
LsapDsAuthHalfFromAuthInfo( ClearAuthInfo, TRUE ),
&IncomingAuthInfoSize,
&IncomingAuthInfo );
if ( !NT_SUCCESS(Status)) {
goto Cleanup;
}
Status = LsapDsMarshalAuthInfoHalf(
LsapDsAuthHalfFromAuthInfo( ClearAuthInfo, FALSE ),
&OutgoingAuthInfoSize,
&OutgoingAuthInfo );
if ( !NT_SUCCESS(Status)) {
goto Cleanup;
}
//
// Build a buffer of:
// 512 random bytes
// The Outgoing auth info buffer.
// The Incoming auth info buffer.
// The length of the outgoing auth info buffer.
// The length of the incoming auth info buffer.
//
// (Notice that a hacker might surmise the length of the auth data by
// observing the length of the encrypted blob. However, the auth data is typically
// fixed length anyway. So the above seems adequate.)
//
EncryptedSize = LSAP_ENCRYPTED_AUTH_DATA_FILL +
OutgoingAuthInfoSize +
IncomingAuthInfoSize +
sizeof(ULONG) +
sizeof(ULONG);
AllocatedBuffer = LocalAlloc( 0, sizeof(LSAPR_TRUSTED_DOMAIN_AUTH_INFORMATION_INTERNAL) + EncryptedSize );
if ( AllocatedBuffer == NULL ) {
Status = STATUS_INSUFFICIENT_RESOURCES;
goto Cleanup;
}
EncryptedBuffer = AllocatedBuffer + sizeof(LSAPR_TRUSTED_DOMAIN_AUTH_INFORMATION_INTERNAL);
Where = EncryptedBuffer;
Status = LsapRandomFill( LSAP_ENCRYPTED_AUTH_DATA_FILL,
Where );
if ( !NT_SUCCESS(Status)) {
goto Cleanup;
}
Where += LSAP_ENCRYPTED_AUTH_DATA_FILL;
RtlCopyMemory( Where, OutgoingAuthInfo, OutgoingAuthInfoSize );
Where += OutgoingAuthInfoSize;
RtlCopyMemory( Where, IncomingAuthInfo, IncomingAuthInfoSize );
Where += IncomingAuthInfoSize;
RtlCopyMemory( Where, &OutgoingAuthInfoSize, sizeof(ULONG) );
Where += sizeof(ULONG);
RtlCopyMemory( Where, &IncomingAuthInfoSize, sizeof(ULONG) );
Where += sizeof(ULONG);
//
// Encrypt the result.
//
rc4_key( &Rc4Key,
sizeof(USER_SESSION_KEY),
(PUCHAR) &UserSessionKey );
rc4( &Rc4Key,
EncryptedSize,
EncryptedBuffer );
//
// Return the result to the caller.
//
*EncryptedAuthInfo =
(PLSAPR_TRUSTED_DOMAIN_AUTH_INFORMATION_INTERNAL) AllocatedBuffer;
(*EncryptedAuthInfo)->AuthBlob.AuthBlob = EncryptedBuffer;
(*EncryptedAuthInfo)->AuthBlob.AuthSize = EncryptedSize;
Status = STATUS_SUCCESS;
Cleanup:
if ( !NT_SUCCESS(Status) ) {
if ( AllocatedBuffer != NULL ) {
LocalFree( AllocatedBuffer );
}
*EncryptedAuthInfo = NULL;
}
if ( IncomingAuthInfo != NULL ) {
MIDL_user_free( IncomingAuthInfo );
}
if ( OutgoingAuthInfo != NULL ) {
MIDL_user_free( OutgoingAuthInfo );
}
return Status;
}
NTSTATUS
NTAPI
LsaSetTrustedDomainInfoByName(
IN LSA_HANDLE PolicyHandle,
IN PUNICODE_STRING TrustedDomainName,
IN TRUSTED_INFORMATION_CLASS InformationClass,
IN PVOID Buffer
)
{
NTSTATUS Status;
PLSAPR_TRUSTED_DOMAIN_AUTH_INFORMATION_INTERNAL InternalAuthBuffer = NULL;
PVOID InternalBuffer;
TRUSTED_INFORMATION_CLASS InternalInformationClass;
LSAPR_TRUSTED_DOMAIN_FULL_INFORMATION_INTERNAL InternalFullBuffer;
//
// Initialization
//
InternalInformationClass = InformationClass;
InternalBuffer = Buffer;
//
// Avoid the internal info levels that represent the encrypted version on
// the wire.
//
switch ( InformationClass ) {
case TrustedPasswordInformation:
case TrustedDomainAuthInformationInternal:
case TrustedDomainFullInformationInternal:
//
// TrustedDomainNameInformation is not allowed, either (RAID #416784)
//
case TrustedDomainNameInformation:
Status = STATUS_INVALID_INFO_CLASS;
goto Cleanup;
//
// Handle the info classes that need to be encrypted on the wire
//
case TrustedDomainAuthInformation: {
//
// Encrypt the data into an internal buffer.
//
Status = LsapEncryptAuthInfo( PolicyHandle,
(PLSAPR_TRUSTED_DOMAIN_AUTH_INFORMATION) Buffer,
&InternalAuthBuffer );
if ( !NT_SUCCESS(Status)) {
goto Cleanup;
}
//
// Use an internal info level to tell the server that the data is
// encrypted.
//
InternalInformationClass = TrustedDomainAuthInformationInternal;
InternalBuffer = InternalAuthBuffer;
break;
}
//
// Handle the info classes that need to be encrypted on the wire
//
case TrustedDomainFullInformation: {
PLSAPR_TRUSTED_DOMAIN_FULL_INFORMATION FullBuffer =
(PLSAPR_TRUSTED_DOMAIN_FULL_INFORMATION) Buffer;
//
// Encrypt the data into an internal buffer.
//
Status = LsapEncryptAuthInfo( PolicyHandle,
&FullBuffer->AuthInformation,
&InternalAuthBuffer );
if ( !NT_SUCCESS(Status)) {
goto Cleanup;
}
//
// Copy all of the information into a single new structure.
//
InternalFullBuffer.Information = FullBuffer->Information;
InternalFullBuffer.PosixOffset = FullBuffer->PosixOffset;
InternalFullBuffer.AuthInformation = *InternalAuthBuffer;
//
// Use an internal info level to tell the server that the data is
// encrypted.
//
InternalInformationClass = TrustedDomainFullInformationInternal;
InternalBuffer = &InternalFullBuffer;
break;
}
}
//
// If the information class was morphed,
// try the morphed class.
//
if ( InternalInformationClass != InformationClass ) {
RpcTryExcept {
//
// Call the Client Stub
//
Status = LsarSetTrustedDomainInfoByName(
(LSAPR_HANDLE) PolicyHandle,
(PLSAPR_UNICODE_STRING) TrustedDomainName,
InternalInformationClass,
(PLSAPR_TRUSTED_DOMAIN_INFO) InternalBuffer
);
} RpcExcept( I_RpcExceptionFilter( RpcExceptionCode()) ) {
Status = LsapApiReturnResult(I_RpcMapWin32Status(RpcExceptionCode()));
} RpcEndExcept;
//
// If the morphed info class is valid,
// we're all done with this call.
// (Otherwise, drop through to try the non-morphed class.)
//
if ( Status != RPC_NT_INVALID_TAG ) {
goto Cleanup;
}
}
//
// Handle non-morphed information classes.
//
RpcTryExcept {
//
// Call the Client Stub
//
Status = LsarSetTrustedDomainInfoByName(
(LSAPR_HANDLE) PolicyHandle,
(PLSAPR_UNICODE_STRING) TrustedDomainName,
InformationClass,
(PLSAPR_TRUSTED_DOMAIN_INFO) Buffer
);
} RpcExcept( I_RpcExceptionFilter( RpcExceptionCode()) ) {
Status = LsapApiReturnResult(I_RpcMapWin32Status(RpcExceptionCode()));
} RpcEndExcept;
Cleanup:
if ( InternalAuthBuffer != NULL ) {
LocalFree( InternalAuthBuffer );
}
return(Status);
}
NTSTATUS
NTAPI
LsaEnumerateTrustedDomainsEx(
IN LSA_HANDLE PolicyHandle,
IN OUT PLSA_ENUMERATION_HANDLE EnumerationContext,
OUT PVOID *Buffer,
IN ULONG PreferedMaximumLength,
OUT PULONG CountReturned
)
{
NTSTATUS Status;
LSAPR_TRUSTED_ENUM_BUFFER_EX EnumerationBuffer;
EnumerationBuffer.EntriesRead = 0;
EnumerationBuffer.EnumerationBuffer = NULL;
//
// Verify that caller has provided a return buffer pointer.
//
if (!ARGUMENT_PRESENT(Buffer)) {
return(STATUS_INVALID_PARAMETER);
}
RpcTryExcept {
//
// Enumerate the Trusted Domains. On successful return,
// the Enumeration Buffer structure will receive a count
// of the number of Trusted Domains enumerated this call
// and a pointer to an array of Trust Information Entries.
//
// EnumerationBuffer -> EntriesRead
// Information -> Trust Info for Domain 0
// Trust Info for Domain 1
// ...
// Trust Info for Domain
// (EntriesRead - 1)
//
//
Status = LsarEnumerateTrustedDomainsEx(
(LSAPR_HANDLE) PolicyHandle,
EnumerationContext,
&EnumerationBuffer,
PreferedMaximumLength
);
//
// Return enumeration information or NULL to caller.
//
// NOTE: "Information" is allocated by the called client stub
// as a single block via MIDL_user_allocate, because Information is
// allocated all-nodes. We can therefore pass back the pointer
// directly to the client, who will be able to free the memory after
// use via LsaFreeMemory() [which makes a MIDL_user_free call].
//
*CountReturned = EnumerationBuffer.EntriesRead;
*Buffer = EnumerationBuffer.EnumerationBuffer;
} RpcExcept( I_RpcExceptionFilter( RpcExceptionCode()) ) {
//
// If memory was allocated for the Trust Information array,
// free it.
//
if (EnumerationBuffer.EnumerationBuffer != NULL) {
MIDL_user_free(EnumerationBuffer.EnumerationBuffer);
}
Status = LsapApiReturnResult(I_RpcMapWin32Status(RpcExceptionCode()));
} RpcEndExcept;
return(Status);
}
NTSTATUS
NTAPI
LsaCreateTrustedDomainEx(
IN LSA_HANDLE PolicyHandle,
IN PTRUSTED_DOMAIN_INFORMATION_EX TrustedDomainInformation,
IN PTRUSTED_DOMAIN_AUTH_INFORMATION AuthenticationInformation,
IN ACCESS_MASK DesiredAccess,
OUT PLSA_HANDLE TrustedDomainHandle
)
{
NTSTATUS Status;
PLSAPR_TRUSTED_DOMAIN_AUTH_INFORMATION_INTERNAL InternalAuthBuffer = NULL;
//
// Encrypt the auth data
//
Status = LsapEncryptAuthInfo( PolicyHandle,
(PLSAPR_TRUSTED_DOMAIN_AUTH_INFORMATION) AuthenticationInformation,
&InternalAuthBuffer );
if ( !NT_SUCCESS(Status)) {
goto Cleanup;
}
//
// Try the version of the API that takes encrypted data
//
RpcTryExcept {
//
// Call the Client Stub
//
Status = LsarCreateTrustedDomainEx2(
(LSAPR_HANDLE) PolicyHandle,
(PLSAPR_TRUSTED_DOMAIN_INFORMATION_EX) TrustedDomainInformation,
InternalAuthBuffer,
DesiredAccess,
(PLSAPR_HANDLE) TrustedDomainHandle
);
} RpcExcept( I_RpcExceptionFilter( RpcExceptionCode()) ) {
Status = LsapApiReturnResult(I_RpcMapWin32Status(RpcExceptionCode()));
} RpcEndExcept;
//
// If the server doesn't accept the new api,
// try the old one.
// (The old API was only supported in beta versions of NT 5.
// After NT 5 ships we no longer need to be able to fall back.)
//
if (Status == RPC_NT_PROCNUM_OUT_OF_RANGE) {
RpcTryExcept {
//
// Call the Client Stub
//
Status = LsarCreateTrustedDomainEx(
(LSAPR_HANDLE) PolicyHandle,
(PLSAPR_TRUSTED_DOMAIN_INFORMATION_EX) TrustedDomainInformation,
(PLSAPR_TRUSTED_DOMAIN_AUTH_INFORMATION) AuthenticationInformation,
DesiredAccess,
(PLSAPR_HANDLE) TrustedDomainHandle
);
} RpcExcept( I_RpcExceptionFilter( RpcExceptionCode()) ) {
Status = LsapApiReturnResult(I_RpcMapWin32Status(RpcExceptionCode()));
} RpcEndExcept;
}
Cleanup:
if ( InternalAuthBuffer != NULL ) {
LocalFree( InternalAuthBuffer );
}
return(Status);
}
NTSTATUS
NTAPI
LsaQueryDomainInformationPolicy(
IN LSA_HANDLE PolicyHandle,
IN POLICY_DOMAIN_INFORMATION_CLASS InformationClass,
OUT PVOID *Buffer
)
{
NTSTATUS Status;
PLSAPR_POLICY_DOMAIN_INFORMATION PolicyDomainInformation = NULL;
RpcTryExcept {
Status = LsarQueryDomainInformationPolicy(
(LSAPR_HANDLE) PolicyHandle,
InformationClass,
&PolicyDomainInformation
);
*Buffer = PolicyDomainInformation;
} RpcExcept( I_RpcExceptionFilter( RpcExceptionCode()) ) {
Status = LsapApiReturnResult(I_RpcMapWin32Status(RpcExceptionCode()));
} RpcEndExcept;
return(Status);
}
NTSTATUS
NTAPI
LsaSetDomainInformationPolicy(
IN LSA_HANDLE PolicyHandle,
IN POLICY_DOMAIN_INFORMATION_CLASS InformationClass,
IN PVOID Buffer
)
{
NTSTATUS Status;
if ( InformationClass == PolicyDomainKerberosTicketInformation &&
Buffer == NULL ) {
return STATUS_INVALID_PARAMETER;
}
RpcTryExcept {
Status = LsarSetDomainInformationPolicy(
(LSAPR_HANDLE) PolicyHandle,
InformationClass,
Buffer
);
} RpcExcept( I_RpcExceptionFilter( RpcExceptionCode()) ) {
Status = LsapApiReturnResult(I_RpcMapWin32Status(RpcExceptionCode()));
} RpcEndExcept;
return(Status);
}
NTSTATUS
LsaOpenTrustedDomainByName(
IN LSA_HANDLE PolicyHandle,
IN PUNICODE_STRING TrustedDomainName,
IN ACCESS_MASK DesiredAccess,
OUT PLSA_HANDLE TrustedDomainHandle
)
/*++
Routine Description:
The LsaOpenTrustedDomain API opens an existing TrustedDomain object
using the Name as the primary key value.
Arguments:
PolicyHandle - An open handle to a Policy object.
TrustedDomainName - Name of the trusted domain
DesiredAccess - This is an access mask indicating accesses being
requested to the target object.
TrustedDomainHandle - Receives a handle to be used in future requests.
Return Values:
NTSTATUS - Standard Nt Result Code
STATUS_ACCESS_DENIED - Caller does not have the appropriate access
to complete the operation.
STATUS_TRUSTED_DOMAIN_NOT_FOUND - There is no TrustedDomain object in the
target system's LSA Database having the specified AccountSid.
--*/
{
NTSTATUS Status;
RpcTryExcept {
Status = LsarOpenTrustedDomainByName(
( LSAPR_HANDLE ) PolicyHandle,
( PLSAPR_UNICODE_STRING )TrustedDomainName,
DesiredAccess,
( PLSAPR_HANDLE )TrustedDomainHandle
);
} RpcExcept( I_RpcExceptionFilter( RpcExceptionCode()) ) {
Status = LsapApiReturnResult(I_RpcMapWin32Status(RpcExceptionCode()));
} RpcEndExcept;
return Status;
}
NTSTATUS
LsaQueryForestTrustInformation(
IN LSA_HANDLE PolicyHandle,
IN PLSA_UNICODE_STRING TrustedDomainName,
OUT PLSA_FOREST_TRUST_INFORMATION * ForestTrustInfo
)
/*++
Routine Description
The LsaQueryForestTrustInformation API returns forest trust information
for the given trusted domain object.
Arguments:
PolicyHandle - An open handle to a Policy object
TrustedDomainName - Name of the trusted domain object
ForestTrustInfo - Used to return forest trust information
Returns:
NTSTATUS - Standard Nt Result Code
STATUS_SUCCESS
STATUS_INVALID_PARAMETER Parameters were somehow invalid
Most likely, the TRUST_ATTRIBUTE_FOREST_TRANSITIVE
trust attribute bit is not set on the TDO
STATUS_NOT_FOUND Forest trust information does not exist for this TDO
STATUS_NO_SUCH_DOMAIN The specified TDO does not exist
STATUS_INSUFFICIENT_RESOURCES Ran out of memory
STATUS_INVALID_DOMAIN_STATE Operation is only legal on domain controllers in root domain
--*/
{
NTSTATUS Status;
RpcTryExcept {
Status = LsarQueryForestTrustInformation(
PolicyHandle,
TrustedDomainName,
ForestTrustRecordTypeLast,
ForestTrustInfo
);
} RpcExcept( I_RpcExceptionFilter( RpcExceptionCode()) ) {
Status = LsapApiReturnResult(I_RpcMapWin32Status(RpcExceptionCode()));
} RpcEndExcept;
return Status;
}
NTSTATUS
LsaSetForestTrustInformation(
IN LSA_HANDLE PolicyHandle,
IN PLSA_UNICODE_STRING TrustedDomainName,
IN PLSA_FOREST_TRUST_INFORMATION ForestTrustInfo,
IN BOOLEAN CheckOnly,
OUT PLSA_FOREST_TRUST_COLLISION_INFORMATION * CollisionInfo
)
/*++
Routine Description
The LsarSetForestTrustInformation API sets forest trust information
on the given trusted domain object.
In case if it fails the operation due to a collision, it will return
the list of entries that conflicted.
Arguments:
PolicyHandle - An open handle to a Policy object
TrustedDomainName - Name of the trusted domain object
ForestTrustInfo - Contains forest trust information to set
CheckOnly - Check for collisions only, do not commit changes to disk
CollisionInfo - In case of collisoin error, used to return collision info
Returns:
STATUS_SUCCESS operation completed successfully
STATUS_INVALID_PARAMETER did not like one of the parameters
STATUS_INSUFFICIENT_RESOURCES out of memory
STATUS_INVALID_DOMAIN_STATE Operation is only legal on domain
controllers in the root domain
STATUS_INVALID_DOMAIN_ROLE Operation is only legal on the primary
domain controller
STATUS_INVALID_SERVER_STATE The server is shutting down and can not
process the request
--*/
{
NTSTATUS Status;
RpcTryExcept {
Status = LsarSetForestTrustInformation(
PolicyHandle,
TrustedDomainName,
ForestTrustRecordTypeLast,
ForestTrustInfo,
CheckOnly,
CollisionInfo
);
} RpcExcept( I_RpcExceptionFilter( RpcExceptionCode()) ) {
Status = LsapApiReturnResult(I_RpcMapWin32Status(RpcExceptionCode()));
} RpcEndExcept;
return Status;
}
#ifdef TESTING_MATCHING_ROUTINE
#include <sddl.h> // ConvertStringSidToSidW
NTSTATUS
NTAPI
LsaForestTrustFindMatch(
IN LSA_HANDLE PolicyHandle,
IN ULONG Type,
IN PLSA_UNICODE_STRING Name,
OUT PLSA_UNICODE_STRING * Match
)
/*++
Routine Description:
A debug-only hook for testing the LsaIForestTrustFindMatch API
Arguments:
Type type of match
Name name to match
Match used to return the name of match
Returns:
STATUS_SUCCESS
--*/
{
NTSTATUS Status;
RpcTryExcept {
Status = LsarForestTrustFindMatch(
PolicyHandle,
Type,
Name,
Match
);
} RpcExcept( I_RpcExceptionFilter( RpcExceptionCode()) ) {
Status = LsapApiReturnResult(I_RpcMapWin32Status(RpcExceptionCode()));
} RpcEndExcept;
return(Status);
} #endif