/*-- Copyright (c) 1987-1993 Microsoft Corporation Module Name: ssptest.c Abstract: Test program for the NtLmSsp service. Author: 28-Jun-1993 (cliffv) Environment: User mode only. Contains NT-specific code. Requires ANSI C extensions: slash-slash comments, long external names. Revision History: --*/ #ifndef UNICODE #define UNICODE #endif // UNICODE #include #include #include #ifndef SECURITY_WIN32 #define SECURITY_WIN32 #endif // SECURITY_WIN32 #define SECURITY_KERNEL #define SECURITY_PACKAGE #define SECURITY_KERBEROS #include #include BOOLEAN QuietMode = FALSE; ULONG DoTests = FALSE; VOID DumpBuffer( PVOID Buffer, DWORD BufferSize ) /*++ Routine Description: Dumps the buffer content on to the debugger output. Arguments: Buffer: buffer pointer. BufferSize: size of the buffer. Return Value: none --*/ { #define NUM_CHARS 16 DWORD i, limit; CHAR TextBuffer[NUM_CHARS + 1]; PUCHAR BufferPtr = Buffer; DbgPrint("------------------------------------\n"); // // Hex dump of the bytes // limit = ((BufferSize - 1) / NUM_CHARS + 1) * NUM_CHARS; for (i = 0; i < limit; i++) { if (i < BufferSize) { DbgPrint("%02x ", BufferPtr[i]); if (BufferPtr[i] < 31 ) { TextBuffer[i % NUM_CHARS] = '.'; } else if (BufferPtr[i] == '\0') { TextBuffer[i % NUM_CHARS] = ' '; } else { TextBuffer[i % NUM_CHARS] = (CHAR) BufferPtr[i]; } } else { DbgPrint(" "); TextBuffer[i % NUM_CHARS] = ' '; } if ((i + 1) % NUM_CHARS == 0) { TextBuffer[NUM_CHARS] = 0; DbgPrint(" %s\n", TextBuffer); } } DbgPrint("------------------------------------\n"); } VOID PrintTime( LPSTR Comment, TimeStamp ConvertTime ) /*++ Routine Description: Print the specified time Arguments: Comment - Comment to print in front of the time Time - Local time to print Return Value: None --*/ { LARGE_INTEGER LocalTime; LocalTime.HighPart = ConvertTime.HighPart; LocalTime.LowPart = ConvertTime.LowPart; DbgPrint( "%s", Comment ); // // If the time is infinite, // just say so. // if ( LocalTime.HighPart == 0x7FFFFFFF && LocalTime.LowPart == 0xFFFFFFFF ) { DbgPrint( "Infinite\n" ); // // Otherwise print it more clearly // } else { TIME_FIELDS TimeFields; RtlTimeToTimeFields( &LocalTime, &TimeFields ); DbgPrint( "%ld/%ld/%ld %ld:%2.2ld:%2.2ld\n", TimeFields.Month, TimeFields.Day, TimeFields.Year, TimeFields.Hour, TimeFields.Minute, TimeFields.Second ); } } VOID PrintStatus( ULONG NetStatus ) /*++ Routine Description: Print a net status code. Arguments: NetStatus - The net status code to print. Return Value: None --*/ { DbgPrint( "Status = %lu 0x%lx", NetStatus, NetStatus ); switch (NetStatus) { case SEC_E_NO_SPM: DbgPrint( " SEC_E_NO_SPM" ); break; case SEC_E_BAD_PKGID: DbgPrint( " SEC_E_BAD_PKGID" ); break; case SEC_E_NOT_OWNER: DbgPrint( " SEC_E_NOT_OWNER" ); break; case SEC_E_CANNOT_INSTALL: DbgPrint( " SEC_E_CANNOT_INSTALL" ); break; case SEC_E_INVALID_TOKEN: DbgPrint( " SEC_E_INVALID_TOKEN" ); break; case SEC_E_CANNOT_PACK: DbgPrint( " SEC_E_CANNOT_PACK" ); break; case SEC_E_QOP_NOT_SUPPORTED: DbgPrint( " SEC_E_QOP_NOT_SUPPORTED" ); break; case SEC_E_NO_IMPERSONATION: DbgPrint( " SEC_E_NO_IMPERSONATION" ); break; case SEC_E_LOGON_DENIED: DbgPrint( " SEC_E_LOGON_DENIED" ); break; case SEC_E_UNKNOWN_CREDENTIALS: DbgPrint( " SEC_E_UNKNOWN_CREDENTIALS" ); break; case SEC_E_NO_CREDENTIALS: DbgPrint( " SEC_E_NO_CREDENTIALS" ); break; case SEC_E_MESSAGE_ALTERED: DbgPrint( " SEC_E_MESSAGE_ALTERED" ); break; case SEC_E_OUT_OF_SEQUENCE: DbgPrint( " SEC_E_OUT_OF_SEQUENCE" ); break; case SEC_E_INSUFFICIENT_MEMORY: DbgPrint( " SEC_E_INSUFFICIENT_MEMORY" ); break; case SEC_E_INVALID_HANDLE: DbgPrint( " SEC_E_INVALID_HANDLE" ); break; case SEC_E_NOT_SUPPORTED: DbgPrint( " SEC_E_NOT_SUPPORTED" ); break; } DbgPrint( "\n" ); } //+------------------------------------------------------------------------- // // Function: SecAllocate // // Synopsis: // // Effects: // // Arguments: // // Requires: // // Returns: // // Notes: // // //-------------------------------------------------------------------------- VOID * SEC_ENTRY SspAlloc(ULONG Flags, ULONG cbMemory) { NTSTATUS scRet; PVOID Buffer = NULL; scRet = ZwAllocateVirtualMemory( NtCurrentProcess(), &Buffer, 0L, &cbMemory, MEM_COMMIT, PAGE_READWRITE ); if (!NT_SUCCESS(scRet)) { return(NULL); } return(Buffer); UNREFERENCED_PARAMETER(Flags); } //+------------------------------------------------------------------------- // // Function: SecFree // // Synopsis: // // Effects: // // Arguments: // // Requires: // // Returns: // // Notes: // // //-------------------------------------------------------------------------- void SEC_ENTRY SspFree(PVOID pvMemory) { ULONG Length = 0; (VOID) ZwFreeVirtualMemory( NtCurrentProcess(), &pvMemory, &Length, MEM_RELEASE ); } VOID TestSspRoutine( ) /*++ Routine Description: Test base SSP functionality Arguments: None Return Value: None --*/ { SECURITY_STATUS SecStatus; SECURITY_STATUS AcceptStatus; SECURITY_STATUS InitStatus; CredHandle ServerCredHandle; CredHandle ClientCredentialHandle; CtxtHandle ClientContextHandle; CtxtHandle ServerContextHandle; TimeStamp Lifetime; ULONG ContextAttributes; ULONG PackageCount, Index; PSecPkgInfo PackageInfo = NULL; HANDLE Token = NULL; static int Calls; ULONG ClientFlags; ULONG ServerFlags; LPWSTR DomainName = NULL; LPWSTR UserName = NULL; LPWSTR TargetName = NULL; UNICODE_STRING TargetString; UNICODE_STRING PackageName; SecBufferDesc NegotiateDesc; SecBuffer NegotiateBuffer; SecBufferDesc ChallengeDesc; SecBuffer ChallengeBuffer; SecBufferDesc AuthenticateDesc; SecBuffer AuthenticateBuffer; SecPkgContext_Sizes ContextSizes; SecPkgContext_Names ContextNames; SecPkgContext_Lifespan ContextLifespan; PSecPkgCredentials_Names CredNames; SecBufferDesc SignMessage; SecBuffer SigBuffers[2]; UCHAR bDataBuffer[20]; UCHAR bSigBuffer[100]; // // Allow tests to be disabled // if (!DoTests) { return; } NegotiateBuffer.pvBuffer = NULL; ChallengeBuffer.pvBuffer = NULL; AuthenticateBuffer.pvBuffer = NULL; SigBuffers[1].pvBuffer = bSigBuffer; SigBuffers[1].cbBuffer = sizeof(bSigBuffer); SigBuffers[1].BufferType = SECBUFFER_TOKEN; SigBuffers[0].pvBuffer = bDataBuffer; SigBuffers[0].cbBuffer = sizeof(bDataBuffer); SigBuffers[0].BufferType = SECBUFFER_DATA; memset(bDataBuffer,0xeb,sizeof(bDataBuffer)); SignMessage.pBuffers = SigBuffers; SignMessage.cBuffers = 2; SignMessage.ulVersion = 0; DomainName = L"makalu"; UserName = L"mikesw"; PackageName.Buffer = (LPWSTR) SspAlloc(0,100); if (PackageName.Buffer == NULL) { return; } wcscpy( PackageName.Buffer, L"Kerberos" ); RtlInitUnicodeString( &PackageName, PackageName.Buffer ); // // Get info about the security packages. // SecStatus = EnumerateSecurityPackages( &PackageCount, &PackageInfo ); if ( SecStatus != STATUS_SUCCESS ) { DbgPrint( "EnumerateSecurityPackages failed:" ); PrintStatus( SecStatus ); return; } DbgPrint( "PackageCount: %ld\n", PackageCount ); for (Index = 0; Index < PackageCount ; Index++ ) { DbgPrint( "Package %d:\n",Index); DbgPrint( "Name: %ws Comment: %ws\n", PackageInfo[Index].Name, PackageInfo[Index].Comment ); DbgPrint( "Cap: %ld Version: %ld RPCid: %ld MaxToken: %ld\n\n", PackageInfo[Index].fCapabilities, PackageInfo[Index].wVersion, PackageInfo[Index].wRPCID, PackageInfo[Index].cbMaxToken ); } #ifdef notdef // // Get info about the security packages. // SecStatus = QuerySecurityPackageInfo( &PackageName, &PackageInfo ); if ( SecStatus != STATUS_SUCCESS ) { DbgPrint( "QuerySecurityPackageInfo failed:" ); PrintStatus( SecStatus ); return; } if ( !QuietMode ) { DbgPrint( "Name: %ws Comment: %ws\n", PackageInfo->Name, PackageInfo->Comment ); DbgPrint( "Cap: %ld Version: %ld RPCid: %ld MaxToken: %ld\n\n", PackageInfo->fCapabilities, PackageInfo->wVersion, PackageInfo->wRPCID, PackageInfo->cbMaxToken ); } FreeContextBuffer(PackageInfo); #endif // // Acquire a credential handle for the server side // SecStatus = AcquireCredentialsHandle( NULL, // New principal &PackageName, // Package Name SECPKG_CRED_INBOUND, NULL, NULL, NULL, NULL, &ServerCredHandle, &Lifetime ); if ( SecStatus != STATUS_SUCCESS ) { DbgPrint( "AcquireCredentialsHandle failed: "); PrintStatus( SecStatus ); return; } if ( !QuietMode ) { DbgPrint( "ServerCredHandle: 0x%lx 0x%lx ", ServerCredHandle.dwLower, ServerCredHandle.dwUpper ); PrintTime( "Lifetime: ", Lifetime ); } // // Acquire a credential handle for the client side // SecStatus = AcquireCredentialsHandle( NULL, // New principal &PackageName, // Package Name SECPKG_CRED_OUTBOUND, NULL, NULL, NULL, NULL, &ClientCredentialHandle, &Lifetime ); if ( SecStatus != STATUS_SUCCESS ) { DbgPrint( "AcquireCredentialsHandle failed: " ); PrintStatus( SecStatus ); return; } if ( !QuietMode ) { DbgPrint( "ClientCredentialHandle: 0x%lx 0x%lx ", ClientCredentialHandle.dwLower, ClientCredentialHandle.dwUpper ); PrintTime( "Lifetime: ", Lifetime ); } // // Query some cred attributes // CredNames = SspAlloc(0, sizeof(*CredNames)); if (CredNames == NULL) { DbgPrint("Failed to allocate CredNames\n"); return; } SecStatus = QueryCredentialsAttributes( &ClientCredentialHandle, SECPKG_CRED_ATTR_NAMES, CredNames ); if ( SecStatus != STATUS_SUCCESS ) { DbgPrint( "QueryCredentialsAttributes (Client) (names): " ); PrintStatus( SecStatus ); if ( !NT_SUCCESS(SecStatus) ) { return; } } DbgPrint("Client credential names: %ws\n",CredNames->sUserName); FreeContextBuffer(CredNames->sUserName); // // Do the same for the client // SecStatus = QueryCredentialsAttributes( &ServerCredHandle, SECPKG_CRED_ATTR_NAMES, CredNames ); if ( SecStatus != STATUS_SUCCESS ) { DbgPrint( "QueryCredentialsAttributes (Server) (names): " ); PrintStatus( SecStatus ); if ( !NT_SUCCESS(SecStatus) ) { return; } } DbgPrint("Server credential names: %ws\n",CredNames->sUserName); FreeContextBuffer(CredNames->sUserName); SspFree(CredNames); // // Get the NegotiateMessage (ClientSide) // NegotiateDesc.ulVersion = 0; NegotiateDesc.cBuffers = 1; NegotiateDesc.pBuffers = &NegotiateBuffer; NegotiateBuffer.cbBuffer = PackageInfo->cbMaxToken; NegotiateBuffer.BufferType = SECBUFFER_TOKEN; NegotiateBuffer.pvBuffer = SspAlloc( 0, NegotiateBuffer.cbBuffer ); if ( NegotiateBuffer.pvBuffer == NULL ) { DbgPrint( "Allocate NegotiateMessage failed\n" ); return; } ClientFlags = ISC_REQ_SEQUENCE_DETECT | ISC_REQ_MUTUAL_AUTH; // | ISC_REQ_USE_DCE_STYLE | ISC_REQ_DATAGRAM; // | ISC_REQ_DELEGATE; TargetName = (LPWSTR) SspAlloc(0,100); if (TargetName == NULL) { return; } wcscpy( TargetName, DomainName ); wcscat( TargetName, L"\\" ); wcscat( TargetName, UserName ); RtlInitUnicodeString( &TargetString, TargetName ); InitStatus = InitializeSecurityContext( &ClientCredentialHandle, NULL, // No Client context yet &TargetString, // Faked target name ClientFlags, 0, // Reserved 1 SECURITY_NATIVE_DREP, NULL, // No initial input token 0, // Reserved 2 &ClientContextHandle, &NegotiateDesc, &ContextAttributes, &Lifetime ); if ( InitStatus != STATUS_SUCCESS ) { if ( !QuietMode || !NT_SUCCESS(InitStatus) ) { DbgPrint( "InitializeSecurityContext (negotiate): " ); PrintStatus( InitStatus ); } if ( !NT_SUCCESS(InitStatus) ) { return; } } if ( !QuietMode ) { DbgPrint( "\n\nNegotiate Message:\n" ); DbgPrint( "ClientContextHandle: 0x%lx 0x%lx Attributes: 0x%lx ", ClientContextHandle.dwLower, ClientContextHandle.dwUpper, ContextAttributes ); PrintTime( "Lifetime: ", Lifetime ); // DumpBuffer( NegotiateBuffer.pvBuffer, NegotiateBuffer.cbBuffer ); } // // Get the ChallengeMessage (ServerSide) // NegotiateBuffer.BufferType |= SECBUFFER_READONLY; ChallengeDesc.ulVersion = 0; ChallengeDesc.cBuffers = 1; ChallengeDesc.pBuffers = &ChallengeBuffer; ChallengeBuffer.cbBuffer = PackageInfo->cbMaxToken; ChallengeBuffer.BufferType = SECBUFFER_TOKEN; ChallengeBuffer.pvBuffer = SspAlloc( 0, ChallengeBuffer.cbBuffer ); if ( ChallengeBuffer.pvBuffer == NULL ) { DbgPrint( "Allocate ChallengeMessage failed\n"); return; } ServerFlags = 0; AcceptStatus = AcceptSecurityContext( &ServerCredHandle, NULL, // No Server context yet &NegotiateDesc, ServerFlags, SECURITY_NATIVE_DREP, &ServerContextHandle, &ChallengeDesc, &ContextAttributes, &Lifetime ); if ( AcceptStatus != STATUS_SUCCESS ) { if ( !QuietMode || !NT_SUCCESS(AcceptStatus) ) { DbgPrint( "AcceptSecurityContext (Challenge): " ); PrintStatus( AcceptStatus ); } if ( !NT_SUCCESS(AcceptStatus) ) { return; } } if ( !QuietMode ) { DbgPrint( "\n\nChallenge Message:\n" ); DbgPrint( "ServerContextHandle: 0x%lx 0x%lx Attributes: 0x%lx ", ServerContextHandle.dwLower, ServerContextHandle.dwUpper, ContextAttributes ); PrintTime( "Lifetime: ", Lifetime ); // DumpBuffer( ChallengeBuffer.pvBuffer, ChallengeBuffer.cbBuffer ); } if (InitStatus != STATUS_SUCCESS) { // // Get the AuthenticateMessage (ClientSide) // ChallengeBuffer.BufferType |= SECBUFFER_READONLY; AuthenticateDesc.ulVersion = 0; AuthenticateDesc.cBuffers = 1; AuthenticateDesc.pBuffers = &AuthenticateBuffer; AuthenticateBuffer.cbBuffer = PackageInfo->cbMaxToken; AuthenticateBuffer.BufferType = SECBUFFER_TOKEN; AuthenticateBuffer.pvBuffer = SspAlloc( 0, AuthenticateBuffer.cbBuffer ); if ( AuthenticateBuffer.pvBuffer == NULL ) { DbgPrint( "Allocate AuthenticateMessage failed: \n" ); return; } SecStatus = InitializeSecurityContext( NULL, &ClientContextHandle, NULL, 0, 0, // Reserved 1 SECURITY_NATIVE_DREP, &ChallengeDesc, 0, // Reserved 2 &ClientContextHandle, &AuthenticateDesc, &ContextAttributes, &Lifetime ); if ( SecStatus != STATUS_SUCCESS ) { DbgPrint( "InitializeSecurityContext (Authenticate): " ); PrintStatus( SecStatus ); if ( !NT_SUCCESS(SecStatus) ) { return; } } if ( !QuietMode ) { DbgPrint( "\n\nAuthenticate Message:\n" ); DbgPrint( "ClientContextHandle: 0x%lx 0x%lx Attributes: 0x%lx ", ClientContextHandle.dwLower, ClientContextHandle.dwUpper, ContextAttributes ); PrintTime( "Lifetime: ", Lifetime ); // DumpBuffer( AuthenticateBuffer.pvBuffer, AuthenticateBuffer.cbBuffer ); } if (AcceptStatus != STATUS_SUCCESS) { // // Finally authenticate the user (ServerSide) // AuthenticateBuffer.BufferType |= SECBUFFER_READONLY; SecStatus = AcceptSecurityContext( NULL, &ServerContextHandle, &AuthenticateDesc, 0, SECURITY_NATIVE_DREP, &ServerContextHandle, NULL, &ContextAttributes, &Lifetime ); if ( SecStatus != STATUS_SUCCESS ) { DbgPrint( "AcceptSecurityContext (Challenge): " ); PrintStatus( SecStatus ); if ( !NT_SUCCESS(SecStatus) ) { return; } } if ( !QuietMode ) { DbgPrint( "\n\nFinal Authentication:\n" ); DbgPrint( "ServerContextHandle: 0x%lx 0x%lx Attributes: 0x%lx ", ServerContextHandle.dwLower, ServerContextHandle.dwUpper, ContextAttributes ); PrintTime( "Lifetime: ", Lifetime ); DbgPrint(" \n" ); } } } SecStatus = QueryContextAttributes( &ServerContextHandle, SECPKG_ATTR_NAMES, &ContextNames ); if ( SecStatus != STATUS_SUCCESS ) { DbgPrint( "QueryContextAttributes (Server) (names): " ); PrintStatus( SecStatus ); if ( !NT_SUCCESS(SecStatus) ) { return; } } DbgPrint("Server Context names: %ws\n",ContextNames.sUserName); FreeContextBuffer(ContextNames.sUserName); // // Impersonate the client (ServerSide) // SecStatus = ImpersonateSecurityContext( &ServerContextHandle ); if ( SecStatus != STATUS_SUCCESS ) { DbgPrint( "ImpersonateSecurityContext: " ); PrintStatus( SecStatus ); if ( !NT_SUCCESS(SecStatus) ) { return; } } SecStatus = RevertSecurityContext( &ServerContextHandle ); if ( SecStatus != STATUS_SUCCESS ) { DbgPrint( "RevertSecurityContext: " ); PrintStatus( SecStatus ); if ( !NT_SUCCESS(SecStatus) ) { return; } } #ifdef notdef // // Impersonate the client manually // SecStatus = QuerySecurityContextToken( &ServerContextHandle,&Token ); if ( SecStatus != STATUS_SUCCESS ) { DbgPrint( "ImpersonateSecurityContext: " ); PrintStatus( SecStatus ); if ( !NT_SUCCESS(SecStatus) ) { return; } } NtClose(Token); #endif #ifdef notdef // // Sign a message // SecStatus = MakeSignature( &ClientContextHandle, 0, &SignMessage, 0 ); if ( SecStatus != STATUS_SUCCESS ) { DbgPrint( "MakeSignature: " ); PrintStatus( SecStatus ); if ( !NT_SUCCESS(SecStatus) ) { return; } } if ( !QuietMode ) { DbgPrint("\n Signature: \n"); // DumpBuffer(SigBuffers[1].pvBuffer,SigBuffers[1].cbBuffer); } // // Verify the signature // SecStatus = VerifySignature( &ServerContextHandle, &SignMessage, 0, 0 ); if ( SecStatus != STATUS_SUCCESS ) { DbgPrint( "VerifySignature: " ); PrintStatus( SecStatus ); if ( !NT_SUCCESS(SecStatus) ) { return; } } // // Sign a message, this time to check if it can detect a change in the // message // SecStatus = MakeSignature( &ClientContextHandle, 0, &SignMessage, 0 ); if ( SecStatus != STATUS_SUCCESS ) { DbgPrint( "MakeSignature: " ); PrintStatus( SecStatus ); if ( !NT_SUCCESS(SecStatus) ) { return; } } if ( !QuietMode ) { DbgPrint("\n Signature: \n"); // DumpBuffer(SigBuffers[1].pvBuffer,SigBuffers[1].cbBuffer); } // // Mess up the message to see if VerifySignature works // bDataBuffer[10] = 0xec; // // Verify the signature // SecStatus = VerifySignature( &ServerContextHandle, &SignMessage, 0, 0 ); if ( SecStatus != SEC_E_MESSAGE_ALTERED ) { DbgPrint( "VerifySignature: " ); PrintStatus( SecStatus ); if ( !NT_SUCCESS(SecStatus) ) { return; } } #endif // // Delete both contexts. // SecStatus = DeleteSecurityContext( &ClientContextHandle ); if ( SecStatus != STATUS_SUCCESS ) { DbgPrint( "DeleteSecurityContext failed: " ); PrintStatus( SecStatus ); return; } SecStatus = DeleteSecurityContext( &ServerContextHandle ); if ( SecStatus != STATUS_SUCCESS ) { DbgPrint( "DeleteSecurityContext failed: " ); PrintStatus( SecStatus ); return; } // // Free both credential handles // SecStatus = FreeCredentialsHandle( &ServerCredHandle ); if ( SecStatus != STATUS_SUCCESS ) { DbgPrint( "FreeCredentialsHandle failed: " ); PrintStatus( SecStatus ); return; } SecStatus = FreeCredentialsHandle( &ClientCredentialHandle ); if ( SecStatus != STATUS_SUCCESS ) { DbgPrint( "FreeCredentialsHandle failed: " ); PrintStatus( SecStatus ); return; } // // Final Cleanup // if (PackageInfo != NULL) { FreeContextBuffer(PackageInfo); } if (PackageName.Buffer != NULL) { SspFree(PackageName.Buffer); } if ( NegotiateBuffer.pvBuffer != NULL ) { (VOID) SspFree( NegotiateBuffer.pvBuffer ); } if ( ChallengeBuffer.pvBuffer != NULL ) { (VOID) SspFree( ChallengeBuffer.pvBuffer ); } if ( AuthenticateBuffer.pvBuffer != NULL ) { (VOID) SspFree( AuthenticateBuffer.pvBuffer ); } if (TargetName != NULL) { SspFree(TargetName); } }