//+----------------------------------------------------------------------- // // Microsoft Windows // // Copyright (c) Microsoft Corporation 1992 - 1996 // // File: credapi.cxx // // Contents: Code for credentials APIs for the NtLm package // Main entry points into this dll: // SpAcceptCredentials // SpAcquireCredentialsHandle // SpFreeCredentialsHandle // SpQueryCredentialsAttributes // SpSaveCredentials // SpGetCredentials // SpDeleteCredentials // // Helper functions: // CopyClientString // // History: ChandanS 26-Jul-1996 Stolen from kerberos\client2\credapi.cxx // //------------------------------------------------------------------------ #define NTLM_CREDAPI #include extern "C" { #include } //+------------------------------------------------------------------------- // // Function: CopyClientString // // Synopsis: copies a client string to local memory, including // allocating space for it locally. // // Arguments: // SourceString - Could be Oem or Wchar in client process // SourceLength - bytes // DoUnicode - whether the string is Wchar // // Returns: // DestinationString - Unicode String in Lsa Process // // Notes: // //-------------------------------------------------------------------------- HRESULT CopyClientString( IN PWSTR SourceString, IN ULONG SourceLength, IN BOOLEAN DoUnicode, OUT PUNICODE_STRING DestinationString ) { SspPrint((SSP_API_MORE,"Entering CopyClientString\n")); NTSTATUS Status = STATUS_SUCCESS; STRING TemporaryString; ULONG SourceSize = 0; ULONG CharacterSize = sizeof(CHAR); // // First initialize the string to zero, in case the source is a null // string // DestinationString->Length = DestinationString->MaximumLength = 0; DestinationString->Buffer = NULL; TemporaryString.Buffer = NULL; if (SourceString != NULL) { // // If the length is zero, allocate one byte for a "\0" terminator // if (SourceLength == 0) { DestinationString->Buffer = (LPWSTR) NtLmAllocate(sizeof(WCHAR)); if (DestinationString->Buffer == NULL) { SspPrint((SSP_CRITICAL,"CopyClientString, Error from NtLmAllocate is 0x%lx\n", Status)); Status = STATUS_NO_MEMORY; goto Cleanup; } DestinationString->MaximumLength = sizeof(WCHAR); *DestinationString->Buffer = L'\0'; } else { // // Allocate a temporary buffer to hold the client string. We may // then create a buffer for the unicode version. The length // is the length in characters, so possible expand to hold unicode // characters and a null terminator. // if (DoUnicode) { CharacterSize = sizeof(WCHAR); } SourceSize = (SourceLength + 1) * CharacterSize; // // insure no overflow aggainst UNICODE_STRING // if ( (SourceSize > 0xFFFF) || ((SourceSize - CharacterSize) > 0xFFFF) ) { Status = STATUS_INVALID_PARAMETER; SspPrint((SSP_CRITICAL,"CopyClientString, SourceSize is too large\n")); goto Cleanup; } TemporaryString.Buffer = (LPSTR) NtLmAllocate(SourceSize); if (TemporaryString.Buffer == NULL) { Status = STATUS_NO_MEMORY; SspPrint((SSP_CRITICAL,"CopyClientString, Error from NtLmAllocate is 0x%lx\n", Status)); goto Cleanup; } TemporaryString.Length = (USHORT) (SourceSize - CharacterSize); TemporaryString.MaximumLength = (USHORT) SourceSize; // // Finally copy the string from the client // Status = LsaFunctions->CopyFromClientBuffer( NULL, SourceSize - CharacterSize, TemporaryString.Buffer, SourceString ); if (!NT_SUCCESS(Status)) { SspPrint((SSP_CRITICAL,"CopyClientString, Error from LsaFunctions->CopyFromClientBuffer is 0x%lx\n", Status)); goto Cleanup; } // // If we are doing unicode, finish up now // if (DoUnicode) { DestinationString->Buffer = (LPWSTR) TemporaryString.Buffer; DestinationString->Length = (USHORT) (SourceSize - CharacterSize); DestinationString->MaximumLength = (USHORT) SourceSize; TemporaryString.Buffer = NULL; } else { // // allocate enough space based on the size of the original Unicode input. // required so that we can use our own allocation scheme. // DestinationString->Buffer = (LPWSTR)NtLmAllocate( SourceSize*sizeof(WCHAR) ); if( DestinationString->Buffer == NULL ) { Status = STATUS_NO_MEMORY; SspPrint((SSP_CRITICAL,"Error from NtLmAllocate\n")); goto Cleanup; } DestinationString->Length = (USHORT)(SourceSize - CharacterSize); DestinationString->MaximumLength = (USHORT)SourceSize * sizeof(WCHAR); Status = RtlOemStringToUnicodeString( DestinationString, &TemporaryString, FALSE ); if (!NT_SUCCESS(Status)) { SspPrint((SSP_CRITICAL,"CopyClientString, Error from RtlOemStringToUnicodeString is 0x%lx\n", Status)); // set to STATUS_NO_MEMORY, as it's unlikely that locale error code would be useful. Status = STATUS_NO_MEMORY; goto Cleanup; } } } } Cleanup: if (TemporaryString.Buffer != NULL) { NtLmFree(TemporaryString.Buffer); } SspPrint((SSP_API_MORE,"Leaving CopyClientString\n")); return(Status); } //+------------------------------------------------------------------------- // // Function: SpAcceptCredentials // // Synopsis: This routine is called after another package has logged // a user on. The other package provides a user name and // password and the NtLm package will create a logon // session for this user. // // Effects: Creates a logon session // // Arguments: LogonType - Type of logon, such as network or interactive // Accountname - Name of the account that logged on // PrimaryCredentials - Primary credentials for the account, // containing a domain name, password, SID, etc. // SupplementalCredentials - NtLm -Specific blob of // supplemental credentials. // // Returns: None // // Notes: // //-------------------------------------------------------------------------- NTSTATUS NTAPI SpAcceptCredentials( IN SECURITY_LOGON_TYPE LogonType, IN PUNICODE_STRING AccountName, IN PSECPKG_PRIMARY_CRED PrimaryCredentials, IN PSECPKG_SUPPLEMENTAL_CRED SupplementalCredentials ) { NTSTATUS Status = S_OK; SspPrint((SSP_API,"Entering SpAcceptCredentials\n")); Status = SspAcceptCredentials( LogonType, PrimaryCredentials, SupplementalCredentials ); SspPrint((SSP_API,"Leaving SpAcceptCredentials\n")); return(SspNtStatusToSecStatus(Status, SEC_E_INTERNAL_ERROR)); UNREFERENCED_PARAMETER( AccountName ); } //+------------------------------------------------------------------------- // // Function: SpAcquireCredentialsHandle // // Synopsis: Contains NtLm Code for AcquireCredentialsHandle which // creates a Credential associated with a logon session. // // Effects: Creates a SSP_CREDENTIAL // // Arguments: PrincipalName - Name of logon session for which to create credential // CredentialUseFlags - Flags indicating whether the credentials // is for inbound or outbound use. // LogonId - The logon ID of logon session for which to create // a credential. // AuthorizationData - Unused blob of NtLm-specific data // GetKeyFunction - Unused function to retrieve a session key // GetKeyArgument - Argument for GetKeyFunction // CredentialHandle - Receives handle to new credential // ExpirationTime - Receives expiration time for credential // // Returns: // STATUS_SUCCESS -- Call completed successfully // SEC_E_NO_SPM -- Security Support Provider is not running // SEC_E_PACKAGE_UNKNOWN -- Package being queried is not this package // SEC_E_PRINCIPAL_UNKNOWN -- No such principal // SEC_E_NOT_OWNER -- caller does not own the specified credentials // SEC_E_INSUFFICIENT_MEMORY -- Not enough memory // // Notes: // //-------------------------------------------------------------------------- NTSTATUS NTAPI SpAcquireCredentialsHandle( IN OPTIONAL PUNICODE_STRING PrincipalName, IN ULONG CredentialUseFlags, IN OPTIONAL PLUID LogonId, IN PVOID AuthorizationData, IN PVOID GetKeyFunction, IN PVOID GetKeyArgument, OUT PULONG_PTR CredentialHandle, OUT PTimeStamp ExpirationTime ) { SspPrint((SSP_API,"Entering SpAcquireCredentialsHandle\n")); NTSTATUS Status = STATUS_SUCCESS; UNICODE_STRING UserName; UNICODE_STRING DomainName; UNICODE_STRING Password; ULONG NewCredentialUseFlags = CredentialUseFlags; PSEC_WINNT_AUTH_IDENTITY pAuthIdentity = NULL; BOOLEAN DoUnicode = TRUE; PSEC_WINNT_AUTH_IDENTITY_EXW pAuthIdentityEx = NULL; PSEC_WINNT_AUTH_IDENTITY_W TmpCredentials = NULL; ULONG CredSize = 0; ULONG Offset = 0; // // Initialization // RtlInitUnicodeString( &UserName, NULL); RtlInitUnicodeString( &DomainName, NULL); RtlInitUnicodeString( &Password, NULL); // // Validate the arguments // if ( (CredentialUseFlags & (SECPKG_CRED_OUTBOUND |SECPKG_CRED_INBOUND)) == 0) { Status = SEC_E_INVALID_CREDENTIAL_USE; goto Cleanup; } if ( ARGUMENT_PRESENT(GetKeyFunction) ) { Status = SEC_E_UNSUPPORTED_FUNCTION; SspPrint((SSP_CRITICAL,"Error from SpAquireCredentialsHandle is 0x%lx\n", Status)); goto Cleanup; } // RDR2 passes in a 1 while talking to down level clients if ( ARGUMENT_PRESENT(GetKeyArgument) && (GetKeyArgument != (PVOID) 1)) { Status = SEC_E_UNSUPPORTED_FUNCTION; SspPrint((SSP_CRITICAL,"Error from SpAquireCredentialsHandle is 0x%lx\n", Status)); goto Cleanup; } // // First get information about the caller. // SECPKG_CLIENT_INFO ClientInfo; PLUID LogonIdToUse; Status = LsaFunctions->GetClientInfo(&ClientInfo); if (!NT_SUCCESS(Status)) { SspPrint((SSP_CRITICAL,"SpAcquireCredentialsHandle, Error from LsaFunctions->GetClientInfo is 0x%lx\n", Status)); goto Cleanup; } // // If the caller supplied a logon ID, and it doesn't match the caller, // they must have the TCB privilege // if (ARGUMENT_PRESENT(LogonId) && ((LogonId->LowPart != 0) || (LogonId->HighPart != 0)) && !RtlEqualLuid( LogonId, &ClientInfo.LogonId) ) { if (!ClientInfo.HasTcbPrivilege) { Status = STATUS_PRIVILEGE_NOT_HELD; SspPrint((SSP_CRITICAL,"SpAcquireCredentialsHandle, Error from ClientInfo.HasTcbPrivilege is 0x%lx\n", Status)); goto Cleanup; } LogonIdToUse = LogonId; // note: there is a special case where the LogonIdToUse specifies // the SYSTEM token, and there may not be a credential (and access token) // for that Luid yet. This special case is handled in SsprAcquireCredentialsHandle() } else { // // Use the callers logon id. // LogonIdToUse = &ClientInfo.LogonId; } // // Got to have an impersonation level token in order to call ACH. // This check used to be in lsa, but moved here to enable // some S4Uproxy scenarios to work w/o tcb. // if (ClientInfo.ImpersonationLevel <= SecurityIdentification) { SspPrint((SSP_CRITICAL, "Trying to acquire credentials with an token no better than SecurityIdentification\n")); Status = SEC_E_NO_CREDENTIALS; goto Cleanup; } // // Copy over the authorization data into out address // space and make a local copy of the strings. // if (AuthorizationData != NULL) { SECPKG_CALL_INFO CallInfo ; SEC_WINNT_AUTH_IDENTITY32 Cred32 = {0}; SEC_WINNT_AUTH_IDENTITY_EX32 CredEx32 ; if(!LsaFunctions->GetCallInfo( &CallInfo )) { Status = STATUS_INTERNAL_ERROR; SspPrint((SSP_CRITICAL,"SpAcquireCredentialsHandle, Error from LsaFunctions->GetCallInfo is 0x%lx\n", Status)); goto Cleanup; } pAuthIdentityEx = (PSEC_WINNT_AUTH_IDENTITY_EXW) NtLmAllocate(sizeof(SEC_WINNT_AUTH_IDENTITY_EXW)); if (pAuthIdentityEx != NULL) { if ( CallInfo.Attributes & SECPKG_CALL_WOWCLIENT ) { Status = LsaFunctions->CopyFromClientBuffer( NULL, sizeof( Cred32 ), pAuthIdentityEx, AuthorizationData ); if ( NT_SUCCESS( Status ) ) { RtlCopyMemory( &Cred32, pAuthIdentityEx, sizeof( Cred32 ) ); } } else { Status = LsaFunctions->CopyFromClientBuffer( NULL, sizeof(SEC_WINNT_AUTH_IDENTITY), pAuthIdentityEx, AuthorizationData); } if (!NT_SUCCESS(Status)) { SspPrint((SSP_CRITICAL,"SpAcquireCredentialsHandle, Error from LsaFunctions->CopyFromClientBuffer is 0x%lx\n", Status)); goto Cleanup; } } else { Status = STATUS_INSUFFICIENT_RESOURCES; SspPrint((SSP_CRITICAL,"SpAcquireCredentialsHandle, Error from NtLmAllocate is 0x%lx\n", Status)); goto Cleanup; } // // Check for the ex version // if (pAuthIdentityEx->Version == SEC_WINNT_AUTH_IDENTITY_VERSION) { // // It's an EX structure. // if ( CallInfo.Attributes & SECPKG_CALL_WOWCLIENT ) { Status = LsaFunctions->CopyFromClientBuffer( NULL, sizeof( CredEx32 ), &CredEx32, AuthorizationData ); if ( NT_SUCCESS( Status ) ) { pAuthIdentityEx->Version = CredEx32.Version ; pAuthIdentityEx->Length = (CredEx32.Length < sizeof( SEC_WINNT_AUTH_IDENTITY_EX ) ? (ULONG) sizeof( SEC_WINNT_AUTH_IDENTITY_EX ) : CredEx32.Length ); pAuthIdentityEx->User = (PWSTR) UlongToPtr( CredEx32.User ); pAuthIdentityEx->UserLength = CredEx32.UserLength ; pAuthIdentityEx->Domain = (PWSTR) UlongToPtr( CredEx32.Domain ); pAuthIdentityEx->DomainLength = CredEx32.DomainLength ; pAuthIdentityEx->Password = (PWSTR) UlongToPtr( CredEx32.Password ); pAuthIdentityEx->PasswordLength = CredEx32.PasswordLength ; pAuthIdentityEx->Flags = CredEx32.Flags ; pAuthIdentityEx->PackageList = (PWSTR) UlongToPtr( CredEx32.PackageList ); pAuthIdentityEx->PackageListLength = CredEx32.PackageListLength ; } } else { Status = LsaFunctions->CopyFromClientBuffer( NULL, sizeof(SEC_WINNT_AUTH_IDENTITY_EXW), pAuthIdentityEx, AuthorizationData); } if (!NT_SUCCESS(Status)) { SspPrint((SSP_CRITICAL,"SpAcquireCredentialsHandle, Error from LsaFunctions->CopyFromClientBuffer is 0x%lx\n", Status)); goto Cleanup; } pAuthIdentity = (PSEC_WINNT_AUTH_IDENTITY) &pAuthIdentityEx->User; CredSize = pAuthIdentityEx->Length; Offset = FIELD_OFFSET(SEC_WINNT_AUTH_IDENTITY_EXW, User); } else { pAuthIdentity = (PSEC_WINNT_AUTH_IDENTITY_W) pAuthIdentityEx; if ( CallInfo.Attributes & SECPKG_CALL_WOWCLIENT ) { pAuthIdentity->User = (PWSTR) UlongToPtr( Cred32.User ); pAuthIdentity->UserLength = Cred32.UserLength ; pAuthIdentity->Domain = (PWSTR) UlongToPtr( Cred32.Domain ); pAuthIdentity->DomainLength = Cred32.DomainLength ; pAuthIdentity->Password = (PWSTR) UlongToPtr( Cred32.Password ); pAuthIdentity->PasswordLength = Cred32.PasswordLength ; pAuthIdentity->Flags = Cred32.Flags ; } CredSize = sizeof(SEC_WINNT_AUTH_IDENTITY_W); } if ((pAuthIdentity->Flags & SEC_WINNT_AUTH_IDENTITY_ANSI) != 0) { DoUnicode = FALSE; // // Turn off the marshalled flag because we don't support marshalling // with ansi. // pAuthIdentity->Flags &= ~SEC_WINNT_AUTH_IDENTITY_MARSHALLED; } else if ((pAuthIdentity->Flags & SEC_WINNT_AUTH_IDENTITY_UNICODE) == 0) { Status = SEC_E_INVALID_TOKEN; SspPrint((SSP_CRITICAL,"SpAcquireCredentialsHandle, Error from pAuthIdentity->Flags is 0x%lx\n", pAuthIdentity->Flags)); goto Cleanup; } // This is the only place where we can figure out whether null // session was requested if ((pAuthIdentity->UserLength == 0) && (pAuthIdentity->DomainLength == 0) && (pAuthIdentity->PasswordLength == 0) && (pAuthIdentity->User != NULL) && (pAuthIdentity->Domain != NULL) && (pAuthIdentity->Password != NULL)) { NewCredentialUseFlags |= NTLM_CRED_NULLSESSION; } if( // UserName may include a marshalled credential > UNLEN pAuthIdentity->UserLength > 0xFFFC || // MAX_USHORT - NULL pAuthIdentity->PasswordLength > PWLEN || pAuthIdentity->DomainLength > DNS_MAX_NAME_LENGTH ) { SspPrint((SSP_CRITICAL,"Supplied credentials illegal length.\n")); Status = STATUS_INVALID_PARAMETER; goto Cleanup; } // // Copy over the strings // if( (pAuthIdentity->Flags & SEC_WINNT_AUTH_IDENTITY_MARSHALLED) != 0 ) { ULONG TmpCredentialSize; ULONG_PTR EndOfCreds; ULONG_PTR TmpUser; ULONG_PTR TmpDomain; ULONG_PTR TmpPassword; // // The callers can set the length of field to n chars, but they // will really occupy n+1 chars (null-terminator). // TmpCredentialSize = CredSize + ( pAuthIdentity->UserLength + pAuthIdentity->DomainLength + pAuthIdentity->PasswordLength + (((pAuthIdentity->User != NULL) ? 1 : 0) + ((pAuthIdentity->Domain != NULL) ? 1 : 0) + ((pAuthIdentity->Password != NULL) ? 1 : 0)) ) * (ULONG) sizeof(WCHAR); EndOfCreds = (ULONG_PTR) AuthorizationData + TmpCredentialSize; // // Verify that all the offsets are valid and no overflow will happen // TmpUser = (ULONG_PTR) pAuthIdentity->User; if ((TmpUser != NULL) && ( (TmpUser < (ULONG_PTR) AuthorizationData) || (TmpUser > EndOfCreds) || ((TmpUser + (pAuthIdentity->UserLength) * sizeof(WCHAR)) > EndOfCreds ) || ((TmpUser + (pAuthIdentity->UserLength * sizeof(WCHAR))) < TmpUser))) { SspPrint((SSP_CRITICAL,"Username in supplied credentials has invalid pointer or length.\n")); Status = STATUS_INVALID_PARAMETER; goto Cleanup; } TmpDomain = (ULONG_PTR) pAuthIdentity->Domain; if ((TmpDomain != NULL) && ( (TmpDomain < (ULONG_PTR) AuthorizationData) || (TmpDomain > EndOfCreds) || ((TmpDomain + (pAuthIdentity->DomainLength) * sizeof(WCHAR)) > EndOfCreds ) || ((TmpDomain + (pAuthIdentity->DomainLength * sizeof(WCHAR))) < TmpDomain))) { SspPrint((SSP_CRITICAL,"Domainname in supplied credentials has invalid pointer or length.\n")); Status = STATUS_INVALID_PARAMETER; goto Cleanup; } TmpPassword = (ULONG_PTR) pAuthIdentity->Password; if ((TmpPassword != NULL) && ( (TmpPassword < (ULONG_PTR) AuthorizationData) || (TmpPassword > EndOfCreds) || ((TmpPassword + (pAuthIdentity->PasswordLength) * sizeof(WCHAR)) > EndOfCreds ) || ((TmpPassword + (pAuthIdentity->PasswordLength * sizeof(WCHAR))) < TmpPassword))) { SspPrint((SSP_CRITICAL,"Password in supplied credentials has invalid pointer or length.\n")); Status = STATUS_INVALID_PARAMETER; goto Cleanup; } // // Allocate a chunk of memory for the credentials // TmpCredentials = (PSEC_WINNT_AUTH_IDENTITY_W) NtLmAllocate(TmpCredentialSize - Offset); if (TmpCredentials == NULL) { Status = STATUS_INSUFFICIENT_RESOURCES; goto Cleanup; } // // Copy the credentials from the client // Status = LsaFunctions->CopyFromClientBuffer( NULL, TmpCredentialSize - Offset, TmpCredentials, (PUCHAR) AuthorizationData + Offset ); if (!NT_SUCCESS(Status)) { SspPrint((SSP_CRITICAL,"Failed to copy whole auth identity\n")); goto Cleanup; } // // Now convert all the offsets to pointers. // if (TmpCredentials->User != NULL) { USHORT cbUser; TmpCredentials->User = (LPWSTR) RtlOffsetToPointer( TmpCredentials->User, (PUCHAR) TmpCredentials - (PUCHAR) AuthorizationData - Offset ); ASSERT( (TmpCredentials->UserLength*sizeof(WCHAR)) <= 0xFFFF ); cbUser = (USHORT)(TmpCredentials->UserLength * sizeof(WCHAR)); UserName.Buffer = (PWSTR)NtLmAllocate( cbUser ); if (UserName.Buffer == NULL ) { Status = STATUS_INSUFFICIENT_RESOURCES; goto Cleanup; } CopyMemory( UserName.Buffer, TmpCredentials->User, cbUser ); UserName.Length = cbUser; UserName.MaximumLength = cbUser; } if (TmpCredentials->Domain != NULL) { USHORT cbDomain; TmpCredentials->Domain = (LPWSTR) RtlOffsetToPointer( TmpCredentials->Domain, (PUCHAR) TmpCredentials - (PUCHAR) AuthorizationData - Offset ); ASSERT( (TmpCredentials->DomainLength*sizeof(WCHAR)) <= 0xFFFF ); cbDomain = (USHORT)(TmpCredentials->DomainLength * sizeof(WCHAR)); DomainName.Buffer = (PWSTR)NtLmAllocate( cbDomain ); if (DomainName.Buffer == NULL ) { Status = STATUS_INSUFFICIENT_RESOURCES; goto Cleanup; } CopyMemory( DomainName.Buffer, TmpCredentials->Domain, cbDomain ); DomainName.Length = cbDomain; DomainName.MaximumLength = cbDomain; } if (TmpCredentials->Password != NULL) { USHORT cbPassword; TmpCredentials->Password = (LPWSTR) RtlOffsetToPointer( TmpCredentials->Password, (PUCHAR) TmpCredentials - (PUCHAR) AuthorizationData - Offset ); ASSERT( (TmpCredentials->PasswordLength*sizeof(WCHAR)) <= 0xFFFF ); cbPassword = (USHORT)(TmpCredentials->PasswordLength * sizeof(WCHAR)); Password.Buffer = (PWSTR)NtLmAllocate( cbPassword ); if (Password.Buffer == NULL ) { ZeroMemory( TmpCredentials->Password, cbPassword ); Status = STATUS_INSUFFICIENT_RESOURCES; goto Cleanup; } CopyMemory( Password.Buffer, TmpCredentials->Password, cbPassword ); Password.Length = cbPassword; Password.MaximumLength = cbPassword; ZeroMemory( TmpCredentials->Password, cbPassword ); } } else { if (pAuthIdentity->Password != NULL) { Status = CopyClientString( pAuthIdentity->Password, pAuthIdentity->PasswordLength, DoUnicode, &Password ); if (!NT_SUCCESS(Status)) { SspPrint((SSP_CRITICAL,"SpAcquireCredentialsHandle, Error from CopyClientString is 0x%lx\n", Status)); goto Cleanup; } } if (pAuthIdentity->User != NULL) { Status = CopyClientString( pAuthIdentity->User, pAuthIdentity->UserLength, DoUnicode, &UserName ); if (!NT_SUCCESS(Status)) { SspPrint((SSP_CRITICAL, "SpAcquireCredentialsHandle, Error from CopyClientString is 0x%lx\n", Status)); goto Cleanup; } } if (pAuthIdentity->Domain != NULL) { Status = CopyClientString( pAuthIdentity->Domain, pAuthIdentity->DomainLength, DoUnicode, &DomainName ); if (!NT_SUCCESS(Status)) { SspPrint((SSP_CRITICAL, "SpAcquireCredentialsHandle, Error from CopyClientString is 0x%lx\n", Status)); goto Cleanup; } // // Make sure that the domain name length is not greater // than the allowed dns domain name // if (DomainName.Length > DNS_MAX_NAME_LENGTH * sizeof(WCHAR)) { SspPrint((SSP_CRITICAL, "SpAcquireCredentialsHandle: Invalid supplied domain name %wZ\n", &DomainName )); Status = SEC_E_UNKNOWN_CREDENTIALS; goto Cleanup; } } } } // AuthorizationData != NULL #if 0 // // Handle UPN and composite NETBIOS syntax // { UNICODE_STRING User = UserName; UNICODE_STRING Domain = DomainName; Status = NtLmParseName( &User, &Domain, TRUE); // If successful, this will allocate and free buffers if(NT_SUCCESS(Status)){ UserName = User; DomainName = Domain; } } #endif if( Password.Length != 0 ) { UNICODE_STRING OldPassword = Password; Status = NtLmDuplicatePassword( &Password, &OldPassword ); if(!NT_SUCCESS(Status)) { goto Cleanup; } ZeroMemory( OldPassword.Buffer, OldPassword.Length ); NtLmFree( OldPassword.Buffer ); } Status = SsprAcquireCredentialHandle( LogonIdToUse, &ClientInfo, NewCredentialUseFlags, CredentialHandle, ExpirationTime, &DomainName, &UserName, &Password ); if (!NT_SUCCESS(Status)) { SspPrint((SSP_CRITICAL, "SpAcquireCredentialsHandle, Error from SsprAcquireCredentialsHandle is 0x%lx\n", Status)); goto Cleanup; } // These will be kept in the Credential structure and freed // when the Credential structure is freed if (DomainName.Buffer != NULL) { DomainName.Buffer = NULL; } if (UserName.Buffer != NULL) { UserName.Buffer = NULL; } if (Password.Buffer != NULL) { Password.Buffer = NULL; } Cleanup: if (TmpCredentials != NULL) { NtLmFree(TmpCredentials); } if (DomainName.Buffer != NULL) { NtLmFree(DomainName.Buffer); } if (UserName.Buffer != NULL) { NtLmFree(UserName.Buffer); } if (Password.Buffer != NULL) { ZeroMemory(Password.Buffer, Password.Length); NtLmFree(Password.Buffer); } if (pAuthIdentityEx != NULL) { NtLmFree(pAuthIdentityEx); } SspPrint((SSP_API, "Leaving SpAcquireCredentialsHandle, Status is %d\n", Status)); return(SspNtStatusToSecStatus(Status, SEC_E_INTERNAL_ERROR)); } //+------------------------------------------------------------------------- // // Function: SpFreeCredentialsHandle // // Synopsis: Frees a credential created by AcquireCredentialsHandle. // // Effects: Unlinks the credential from the global list and the list // for this client. // // Arguments: CredentialHandle - Handle to the credential to free // (acquired through AcquireCredentialsHandle) // // Requires: // // Returns: STATUS_SUCCESS on success, // SEC_E_INVALID_HANDLE if the handle is not valid // // Notes: // // //-------------------------------------------------------------------------- NTSTATUS NTAPI SpFreeCredentialsHandle( IN ULONG_PTR CredentialHandle ) { SspPrint((SSP_API, "Entering SpFreeCredentialsHandle\n")); NTSTATUS Status = STATUS_SUCCESS; PSSP_CREDENTIAL Credential; // // Find the referenced credential and delink it. // Status = SspCredentialReferenceCredential( CredentialHandle, TRUE, // remove the instance of the credential &Credential ); if ( !NT_SUCCESS( Status ) ) { SspPrint((SSP_CRITICAL, "SpFreeCredentialsHandle, Error from SspCredentialReferenceCredential is 0x%lx\n", Status)); goto Cleanup; } // // Dereferencing the Credential will remove the client's reference // to it, causing it to be rundown if nobody else is using it. // SspCredentialDereferenceCredential( Credential ); Cleanup: // // Catch spurious INVALID_HANDLE being returned to RPC. // ASSERT( NT_SUCCESS(Status) ); SspPrint((SSP_API, "Leaving SpFreeCredentialsHandle\n")); return(SspNtStatusToSecStatus(Status, SEC_E_INTERNAL_ERROR)); } NTSTATUS NTAPI SpQueryCredentialsAttributes( IN LSA_SEC_HANDLE CredentialHandle, IN ULONG CredentialAttribute, IN OUT PVOID Buffer ) { PSSP_CREDENTIAL pCredential = NULL; SecPkgCredentials_NamesW Names; LUID LogonId; BOOLEAN bActiveLogonsAreLocked = FALSE; LPWSTR pszContextNames = NULL; LPWSTR pWhere; LPWSTR pszUserName = NULL; LPWSTR pszDomainName = NULL; DWORD cchUserName = 0; DWORD cchDomainName = 0; ULONG Length; BOOLEAN CalledLsaLookup = FALSE; PLSAPR_REFERENCED_DOMAIN_LIST ReferencedDomain = NULL; LSAPR_TRANSLATED_NAMES ReferencedUser; #if _WIN64 SECPKG_CALL_INFO CallInfo; #endif NTSTATUS Status = STATUS_SUCCESS; SspPrint((SSP_API,"In SpQueryCredentialsAttributes\n")); Names.sUserName = NULL; if (CredentialAttribute != SECPKG_CRED_ATTR_NAMES) { SspPrint((SSP_MISC, "Asked for illegal info level in QueryCredAttr: %d\n", CredentialAttribute)); Status = STATUS_INVALID_PARAMETER; goto Cleanup; } Status = SspCredentialReferenceCredential( CredentialHandle, FALSE, &pCredential ); if ( !NT_SUCCESS( Status ) ) { SspPrint((SSP_CRITICAL, "SpQueryCredentialsAttributes, Error from SspCredentialReferenceCredential is 0x%lx\n", Status)); goto Cleanup; } #if _WIN64 if(!LsaFunctions->GetCallInfo( &CallInfo )) { Status = STATUS_INTERNAL_ERROR; SspPrint((SSP_CRITICAL, "SpQueryCredentialsAttributes, failed to get callinfo 0x%lx\n", Status)); goto Cleanup; } #endif // // The logon id of the credential is constant, so it is o.k. // to use it without locking the credential // LogonId = pCredential->LogonId; // // credentials were either specified when cred built, or, they were defaulted. // if ( pCredential->UserName.Buffer == NULL && pCredential->DomainName.Buffer == NULL ) { PACTIVE_LOGON pActiveLogon = NULL; // // defaulted creds: pickup info from active logon table. // NlpLockActiveLogonsRead(); bActiveLogonsAreLocked = TRUE; pActiveLogon = NlpFindActiveLogon(&LogonId); if (pActiveLogon) { // // found an active logon entry. // pszUserName = pActiveLogon->UserName.Buffer; cchUserName = pActiveLogon->UserName.Length / sizeof(WCHAR); pszDomainName = pActiveLogon->LogonDomainName.Buffer; cchDomainName = pActiveLogon->LogonDomainName.Length / sizeof(WCHAR); } else { PTOKEN_USER pTokenInfo; BYTE FastBuffer[ 256 ]; DWORD cbTokenInfo; HANDLE ClientTokenHandle; BOOL fSuccess = FALSE; NlpUnlockActiveLogons(); bActiveLogonsAreLocked = FALSE; // // get a token associated with the logon session. // Status = LsaFunctions->OpenTokenByLogonId( &LogonId, &ClientTokenHandle ); if (!NT_SUCCESS(Status)) { SspPrint(( SSP_CRITICAL, "SpQueryCredentialsAttributes: " "Could not open client token 0x%lx\n", Status )); goto Cleanup; } // // get Sid associated with credential. // cbTokenInfo = sizeof(FastBuffer); pTokenInfo = (PTOKEN_USER)FastBuffer; fSuccess = GetTokenInformation( ClientTokenHandle, TokenUser, pTokenInfo, cbTokenInfo, &cbTokenInfo ); CloseHandle( ClientTokenHandle ); if ( fSuccess ) { LSAPR_SID_ENUM_BUFFER SidEnumBuffer; LSAPR_SID_INFORMATION SidInfo; ULONG MappedCount; SidEnumBuffer.Entries = 1; SidEnumBuffer.SidInfo = &SidInfo; SidInfo.Sid = (LSAPR_SID*)pTokenInfo->User.Sid; ZeroMemory( &ReferencedUser, sizeof(ReferencedUser) ); CalledLsaLookup = TRUE; Status = LsarLookupSids( NtLmGlobalPolicyHandle, &SidEnumBuffer, &ReferencedDomain, &ReferencedUser, LsapLookupWksta, &MappedCount ); if ( !NT_SUCCESS( Status ) || (MappedCount == 0) || (ReferencedUser.Entries == 0) || (ReferencedDomain == NULL) || (ReferencedDomain->Entries == 0) ) { fSuccess = FALSE; } else { LONG Index = ReferencedUser.Names->DomainIndex; pszUserName = ReferencedUser.Names->Name.Buffer; cchUserName = ReferencedUser.Names->Name.Length / sizeof(WCHAR); pszDomainName = ReferencedDomain->Domains[Index].Name.Buffer; cchDomainName = ReferencedDomain->Domains[Index].Name.Length / sizeof(WCHAR); } } if ( !fSuccess ) { Status = STATUS_NO_SUCH_LOGON_SESSION; SspPrint(( SSP_CRITICAL, "SpQueryCredentialsAtributes, NlpFindActiveLogon returns FALSE\n")); goto Cleanup; } } } else { // // specified creds. // pszUserName = pCredential->UserName.Buffer; cchUserName = pCredential->UserName.Length / sizeof(WCHAR); pszDomainName = pCredential->DomainName.Buffer; cchDomainName = pCredential->DomainName.Length / sizeof(WCHAR); } Length = (cchUserName + 1 + cchDomainName + 1) * sizeof(WCHAR); pszContextNames = (LPWSTR)NtLmAllocate( Length ); if ( pszContextNames == NULL ) { goto Cleanup; } pWhere = pszContextNames; if ( pszDomainName) { RtlCopyMemory( pszContextNames, pszDomainName, cchDomainName * sizeof(WCHAR) ); pszContextNames[ cchDomainName ] = L'\\'; pWhere += (cchDomainName+1); } if ( pszUserName ) { RtlCopyMemory( pWhere, pszUserName, cchUserName * sizeof(WCHAR) ); } pWhere[ cchUserName ] = L'\0'; if (bActiveLogonsAreLocked) { NlpUnlockActiveLogons(); bActiveLogonsAreLocked = FALSE; } // // Allocate memory in the client's address space // Status = LsaFunctions->AllocateClientBuffer( NULL, Length, (PVOID *) &Names.sUserName ); if (!NT_SUCCESS(Status)) { goto Cleanup; } // // Copy the string there // Status = LsaFunctions->CopyToClientBuffer( NULL, Length, Names.sUserName, pszContextNames ); if (!NT_SUCCESS(Status)) { goto Cleanup; } // // Now copy the address of the string there // #if _WIN64 if ( CallInfo.Attributes & SECPKG_CALL_WOWCLIENT ) { Status = LsaFunctions->CopyToClientBuffer( NULL, sizeof(ULONG), Buffer, &Names ); } else { Status = LsaFunctions->CopyToClientBuffer( NULL, sizeof(Names), Buffer, &Names ); } #else Status = LsaFunctions->CopyToClientBuffer( NULL, sizeof(Names), Buffer, &Names ); #endif if (!NT_SUCCESS(Status)) { goto Cleanup; } Cleanup: if (bActiveLogonsAreLocked) { NlpUnlockActiveLogons(); } if ( pCredential != NULL ) { SspCredentialDereferenceCredential( pCredential ); } if ( CalledLsaLookup ) { if ( ReferencedDomain ) { LsaIFree_LSAPR_REFERENCED_DOMAIN_LIST( ReferencedDomain ); } LsaIFree_LSAPR_TRANSLATED_NAMES( &ReferencedUser ); } if (!NT_SUCCESS(Status)) { if (Names.sUserName != NULL) { (VOID) LsaFunctions->FreeClientBuffer( NULL, Names.sUserName ); } } if ( pszContextNames ) { NtLmFree( pszContextNames ); } SspPrint((SSP_API, "Leaving SpQueryCredentialsAttributes\n")); return (SspNtStatusToSecStatus(Status, SEC_E_INTERNAL_ERROR)); } NTSTATUS NTAPI SpSaveCredentials( IN ULONG_PTR CredentialHandle, IN PSecBuffer Credentials ) { UNREFERENCED_PARAMETER(CredentialHandle); UNREFERENCED_PARAMETER(Credentials); SspPrint((SSP_API,"In SpSaveCredentials\n")); return(SEC_E_UNSUPPORTED_FUNCTION); } NTSTATUS NTAPI SpGetCredentials( IN ULONG_PTR CredentialHandle, IN OUT PSecBuffer Credentials ) { UNREFERENCED_PARAMETER(CredentialHandle); UNREFERENCED_PARAMETER(Credentials); SspPrint((SSP_API,"In SpGetCredentials\n")); return(SEC_E_UNSUPPORTED_FUNCTION); } NTSTATUS NTAPI SpDeleteCredentials( IN ULONG_PTR CredentialHandle, IN PSecBuffer Key ) { UNREFERENCED_PARAMETER(CredentialHandle); UNREFERENCED_PARAMETER(Key); SspPrint((SSP_API,"In SpDeleteCredentials\n")); return(SEC_E_UNSUPPORTED_FUNCTION); }