//+----------------------------------------------------------------------- // // Microsoft Windows // // Copyright (c) Microsoft Corporation 2000 // // File: common.cxx // // Contents: Shared SSPI code // // // History: 11-March-2000 Created Todds // //------------------------------------------------------------------------ //+------------------------------------------------------------------------- // // Function: SspAllocate // // Synopsis: Copies a string from the client and if necessary converts // from ansi to unicode // // Effects: allocates output with either KerbAllocate (unicode) // or RtlAnsiStringToUnicodeString // // Arguments: StringPointer - address of string in client process // StringLength - Lenght (in characters) of string // AnsiString - if TRUE, string is ansi // LocalString - receives allocated string // // Requires: // // Returns: // // Notes: // // //-------------------------------------------------------------------------- PVOID SspAllocate( IN ULONG BufferSize ) { PVOID pBuffer = NULL; if (*pSspState == SspLsaMode) { pBuffer = LsaFunctions->AllocateLsaHeap(BufferSize); if (pBuffer != NULL) { RtlZeroMemory(Buffer, BufferSize); } } else { ASSERT((*pSspState) == SspUserMode); pBuffer = LocalAlloc(LPTR, BufferSize); } return pBuffer; } //+------------------------------------------------------------------------- // // Function: SspFree // // Synopsis: Copies a string from the client and if necessary converts // from ansi to unicode // // Effects: allocates output with either KerbAllocate (unicode) // or RtlAnsiStringToUnicodeString // // Arguments: StringPointer - address of string in client process // StringLength - Lenght (in characters) of string // AnsiString - if TRUE, string is ansi // LocalString - receives allocated string // // Requires: // // Returns: // // Notes: // // //-------------------------------------------------------------------------- VOID SspFree( IN PVOID pBuffer ) { if (ARGUMENT_PRESENT(Buffer)) { if ((*pSspState) == SspLsaMode) { LsaFunctions->FreeLsaHeap(Buffer); } else { ASSERT((*pSspState) == SspUserMode); LocalFree(Buffer); } } } //+------------------------------------------------------------------------- // // Function: SspCopyClientString // // Synopsis: Copies a string from the client and if necessary converts // from ansi to unicode // // Effects: allocates output with SspAllocate, free w/ SspFree // // Arguments: StringPointer - address of string in client process // StringLength - Lenght (in characters) of string // UnicodeString - if TRUE, string is ansi // MaxLength - Maximum length of string (useful for pwds) // LocalString - receives allocated string // // Requires: // // Returns: // // Notes: // // //-------------------------------------------------------------------------- NTSTATUS SspCopyClientString( IN PVOID StringPointer, IN ULONG StringLength, IN BOOLEAN UnicodeString, OUT PUNICODE_STRING LocalString, IN ULONG MaxLength = 0xFFFF ) { NTSTATUS Status = STATUS_SUCCESS; STRING TempString = {0}; ULONG SourceSize = 0; ULONG CharacterSize = (DoUnicode ? sizeof(WCHAR) : sizeof(CHAR)); // init outputs LocalString->Length = LocalString->MaximumLength = 0; LocalString->Buffer = NULL; if (NULL != StringPointer) { // For 0 length strings, allocate 2 bytes if (StringLength == 0) { LocalString->Buffer = (LPWSTR) SspAllocate(sizeof(WCHAR)); if (NULL == LocalString->Buffer) { DebugLog((DEB_ERROR,"SspCopyClientString allocation failure!\n"); Status = STATUS_NO_MEMORY; goto Cleanup; } LocalString->MaximumLength = sizeof(WCHAR); *LocalString->Buffer = L"\0"; } else { // // Ensure no overflow against UNICODE_STRING, or desired string // SourceSize = (StringLength + 1) * CharacterSize; if ((StringLength > MaxLength) || (SourceSize > 0xFFFF)) { Status = STATUS_INVALID_PARAMETER; DebugLog((DEB_WARN, "SspCopyClientString, String is too big for UNICODE_STRING\n")); goto Cleanup; } TempString.Buffer = (LPSTR) SspAllocate(SourceSize); if (NULL == TempString.Buffer) { DebugLog((DEB_ERROR,"SspCopyClientString allocation failure!\n"); Status = STATUS_NO_MEMORY; goto Cleanup; } TempString.Length = (USHORT) (SourceSize - CharacterSize); TempString.MaximumLength = (USHORT) SourceSize; Status = LsaFunctions->CopyFromClientBuffer( NULL, SourceSize - CharacterSize, TempString.Buffer, StringPointer ); if (!NT_SUCCESS(Status)) { DebugLog(( DEB_ERROR, "SspCopyClientString:LsaFn->CopyFromClientBuffer Failed - 0x%x\n", Status)); goto Cleanup; } // We've put info into a STRING structure. Now do // translation to UNICODE_STRING. if (UnicodeString) { LocalString->Buffer = (LPWSTR) TemporaryString.Buffer; LocalString->Length = TempString.Length; LocalString->MaximumLength = TempString.MaximumLength; } else { NTSTATUS Status1; Status1 = RtlOemStringToUnicodeString( LocalString, &TemporaryString, TRUE ); // allocate destination if (!NT_SUCCESS(Status1)) { Status = STATUS_NO_MEMORY; DebugLog(( DEB_ERROR, "SspCopyClientString, Error from RtlOemStringToUnicodeString is 0x%lx\n", Status )); goto Cleanup; } } } } Cleanup: if (TempString.Buffer != NULL) { // // Free this if we failed and were doing unicode or if we weren't // doing unicode // if ((UnicodeString && !NT_SUCCESS(Status)) || !UnicodeString) { NtLmFree(TemporaryString.Buffer); } } return Status; } //+------------------------------------------------------------------------- // // Function: SspAllocate // // Synopsis: Copies a string from the client and if necessary converts // from ansi to unicode // // Effects: allocates output with either KerbAllocate (unicode) // or RtlAnsiStringToUnicodeString // // Arguments: StringPointer - address of string in client process // StringLength - Lenght (in characters) of string // AnsiString - if TRUE, string is ansi // LocalString - receives allocated string // // Requires: // // Returns: // // Notes: // // //-------------------------------------------------------------------------- NTSTATUS SspCopyAuthorizationData(IN PVOID AuthorizationData, IN OUT PBOOLEAN NullSession) { PSEC_WINNT_AUTH_IDENTITY_EXW pAuthIdentityEx = NULL; BOOLEAN UnicodeString = TRUE; // Init out parameters *NullSession = FALSE; if (NULL == AuthorizationData) { return STATUS_SUCCESS; } pAuthIdentity = (PSEC_WINNT_AUTH_IDENTITY_EXW) SspAllocate(sizeof(SEC_WINNT_AUTH_IDENTITY_EXW)); if (NULL != pAuthIdentity) { Status = LsaFunctions->CopyFromClientBuffer( NULL, sizeof(SEC_WINNT_AUTH_IDENTITY), pAuthIdentityEx, AuthorizationData ); if (!NT_SUCCESS(Status)) { DebugLog((DEB_ERROR,"Fail: LsaFunctions->CopyFromClientBuffer is 0x%lx\n", Status)); goto Cleanup; } } else { Status = STATUS_NO_MEMORY; DebugLog((DEB_ERROR, "Fail: Alloc in SspCopyAuthData\n"); goto Cleanup; } // // Do we have an EX version? // if (pAuthIdentityEx->Version == SEC_WINNT_AUTH_IDENTITY_VERSION) { Status = LsaFunctions->CopyFromClientBuffer( NULL, sizeof(SEC_WINNT_AUTH_IDENTITY_EXW), pAuthIdentityEx, AuthorizationData ); if (!NT_SUCCESS(Status)) { DebugLog((DEB_ERROR,"Fail: Error from LsaFunctions->CopyFromClientBuffer 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; 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; } // // For NTLM, we've got to verify that this is indeed a NULL session // if ((pAuthIdentity->UserLength == 0) && (pAuthIdentity->DomainLength == 0) && (pAuthIdentity->PasswordLength == 0) && (pAuthIdentity->User != NULL) && (pAuthIdentity->Domain != NULL) && (pAuthIdentity->Password != NULL)) { *NullSession = TRUE; } // // Copy over marshalled data // if((pAuthIdentity->Flags & SEC_WINNT_AUTH_IDENTITY_MARSHALLED) != 0 ) { ULONG TmpCredentialSize; ULONG_PTR EndOfCreds; ULONG_PTR TmpUser; ULONG_PTR TmpDomain; ULONG_PTR TmpPassword; if( pAuthIdentity->UserLength > UNLEN || pAuthIdentity->PasswordLength > PWLEN || pAuthIdentity->DomainLength > DNS_MAX_NAME_LENGTH ) { SspPrint((SSP_CRITICAL,"Supplied credentials illegal length.\n")); Status = STATUS_INVALID_PARAMETER; goto Cleanup; } // // 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)) ) * 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 ); } } // // Data was *not* marshalled, copy strings individually // else { if (pAuthIdentity->Password != NULL) { Status = SspCopyClientString( pAuthIdentity->Password, pAuthIdentity->PasswordLength, UnicodeString, &Password ); if (!NT_SUCCESS(Status)) { DebugLog((DEB_ERROR,"SpAcquireCredentialsHandle, Error from CopyClientString is 0x%lx\n", Status)); goto Cleanup; } } if (pAuthIdentity->User != NULL) { Status = SspCopyClientString( pAuthIdentity->User, pAuthIdentity->UserLength, UnicodeString, &UserName ); if (!NT_SUCCESS(Status)) { DebugLog((DEB_ERROR, "SpAcquireCredentialsHandle, Error from CopyClientString is 0x%lx\n", Status)); goto Cleanup; } } if (pAuthIdentity->Domain != NULL) { Status = SspCopyClientString( pAuthIdentity->Domain, pAuthIdentity->DomainLength, UnicodeString, &DomainName ); if (!NT_SUCCESS(Status)) { DebugLog((DEB_ERROR, "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)) { DebugLog((DEB_ERROR, "SpAcquireCredentialsHandle: Invalid supplied domain name %wZ\n", &DomainName )); Status = SEC_E_UNKNOWN_CREDENTIALS; goto Cleanup; } } } } }