1680 lines
46 KiB
C++
1680 lines
46 KiB
C++
/*++
|
||
|
||
Copyright (c) 1996 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
logon32.cxx
|
||
|
||
Abstract:
|
||
|
||
Provide a replacement for LogonUser to login a user
|
||
as a net logon. Also support sub-authentication DLL IDs
|
||
|
||
Author:
|
||
|
||
Philippe Choquier (phillich) 10-january-1996
|
||
Created from base\advapi\logon32.c
|
||
|
||
--*/
|
||
|
||
|
||
#include "lonsint.hxx"
|
||
|
||
#pragma hdrstop
|
||
|
||
extern "C" {
|
||
|
||
#include <ntsam.h>
|
||
#include <ntlsa.h>
|
||
#include <ntmsv1_0.h>
|
||
#include <crypt.h>
|
||
#include <logonmsv.h>
|
||
#include <inetsec.h>
|
||
#define SECURITY_WIN32
|
||
#include <sspi.h> // Security Support Provider APIs
|
||
#include <issperr.h>
|
||
}
|
||
#include <svcloc.h>
|
||
#include <lonsi.hxx>
|
||
#include <tslogon.hxx>
|
||
|
||
#if !defined(MSV1_0_RETURN_PASSWORD_EXPIRY)
|
||
#define MSV1_0_RETURN_PASSWORD_EXPIRY 0x40
|
||
#endif
|
||
|
||
|
||
//
|
||
// We dynamically load mpr.dll (no big surprise there), in order to call
|
||
// WNetLogonNotify, as defined in private\inc\mpr.h. This prototype matches
|
||
// it -- consult the header file for all the parameters.
|
||
//
|
||
typedef (* LOGONNOTIFYFN)(LPCWSTR, PLUID, LPCWSTR, LPVOID,
|
||
LPCWSTR, LPVOID, LPWSTR, LPVOID, LPWSTR *);
|
||
|
||
#define LEN_ALIGN(a,b) (((a)+b-1)&~(b-1))
|
||
|
||
ULONG
|
||
BaseSetLastNTError(
|
||
IN NTSTATUS Status
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This API sets the "last error value" and the "last error string"
|
||
based on the value of Status. For status codes that don't have
|
||
a corresponding error string, the string is set to null.
|
||
|
||
Arguments:
|
||
|
||
Status - Supplies the status value to store as the last error value.
|
||
|
||
Return Value:
|
||
|
||
The corresponding Win32 error code that was stored in the
|
||
"last error value" thread variable.
|
||
|
||
--*/
|
||
|
||
{
|
||
ULONG dwErrorCode;
|
||
|
||
dwErrorCode = RtlNtStatusToDosError( Status );
|
||
SetLastError( dwErrorCode );
|
||
return( dwErrorCode );
|
||
}
|
||
|
||
//
|
||
// The QuotaLimits are global, because the defaults
|
||
// are always used for accounts, based on server/wksta, and no one ever
|
||
// calls lsasetaccountquota
|
||
//
|
||
|
||
HANDLE Logon32LsaHandle = NULL;
|
||
ULONG Logon32MsvHandle = 0xFFFFFFFF;
|
||
WCHAR Logon32DomainName[16] = L""; // NOTE: This should be DNLEN from
|
||
// lmcons.h, but that would be a
|
||
// lot of including
|
||
QUOTA_LIMITS Logon32QuotaLimits;
|
||
LOGONNOTIFYFN Logon32LogonNotify = NULL;
|
||
HINSTANCE Logon32MprHandle = NULL;
|
||
|
||
CRITICAL_SECTION Logon32Lock;
|
||
|
||
#define LockLogon() EnterCriticalSection( &Logon32Lock )
|
||
#define UnlockLogon() LeaveCriticalSection( &Logon32Lock )
|
||
|
||
SID_IDENTIFIER_AUTHORITY L32SystemSidAuthority = SECURITY_NT_AUTHORITY;
|
||
SID_IDENTIFIER_AUTHORITY L32LocalSidAuthority = SECURITY_LOCAL_SID_AUTHORITY;
|
||
|
||
|
||
#define COMMON_CREATE_SUSPENDED 0x00000001 // Suspended, do not Resume()
|
||
#define COMMON_CREATE_PROCESSSD 0x00000002 // Whack the process SD
|
||
#define COMMON_CREATE_THREADSD 0x00000004 // Whack the thread SD
|
||
|
||
BOOL
|
||
IISLogon32Initialize(
|
||
IN PVOID hMod,
|
||
IN ULONG Reason,
|
||
IN PCONTEXT Context)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Initializes the critical section
|
||
|
||
Arguments:
|
||
|
||
hMod -- reserved, must be NULL
|
||
Reason -- DLL_PROCESS_ATTACH or DLL_PROCESS_DETACH
|
||
Context -- reserved, must be NULL
|
||
|
||
Returns:
|
||
|
||
TRUE if initialization success, else FALSE
|
||
|
||
--*/
|
||
{
|
||
return( TRUE );
|
||
}
|
||
|
||
|
||
PSID
|
||
L32CreateLogonSid(
|
||
PLUID LogonId OPTIONAL
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Creates a logon sid for a new logon.
|
||
|
||
Arguments:
|
||
|
||
LogonId -- If non NULL, on return the LUID that is part of the logon
|
||
sid is returned here.
|
||
|
||
Returns:
|
||
|
||
Logon SID or NULL if error
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS Status;
|
||
ULONG Length;
|
||
PSID Sid;
|
||
LUID Luid;
|
||
|
||
//
|
||
// Generate a locally unique id to include in the logon sid
|
||
//
|
||
|
||
Status = NtAllocateLocallyUniqueId(&Luid);
|
||
if (!NT_SUCCESS(Status)) {
|
||
return(NULL);
|
||
}
|
||
|
||
|
||
//
|
||
// Allocate space for the sid and fill it in.
|
||
//
|
||
|
||
Length = RtlLengthRequiredSid(SECURITY_LOGON_IDS_RID_COUNT);
|
||
|
||
Sid = (PSID)LocalAlloc(LMEM_FIXED, Length);
|
||
|
||
if (Sid != NULL) {
|
||
|
||
RtlInitializeSid(Sid, &L32SystemSidAuthority, SECURITY_LOGON_IDS_RID_COUNT);
|
||
|
||
ASSERT(SECURITY_LOGON_IDS_RID_COUNT == 3);
|
||
|
||
*(RtlSubAuthoritySid(Sid, 0)) = SECURITY_LOGON_IDS_RID;
|
||
*(RtlSubAuthoritySid(Sid, 1 )) = Luid.HighPart;
|
||
*(RtlSubAuthoritySid(Sid, 2 )) = Luid.LowPart;
|
||
}
|
||
|
||
|
||
//
|
||
// Return the logon LUID if required.
|
||
//
|
||
|
||
if (LogonId != NULL) {
|
||
*LogonId = Luid;
|
||
}
|
||
|
||
return(Sid);
|
||
}
|
||
|
||
|
||
BOOL
|
||
L32pInitLsa(
|
||
void
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Initialize connection with LSA
|
||
|
||
Arguments:
|
||
|
||
None
|
||
|
||
Returns:
|
||
|
||
TRUE if success, FALSE if error
|
||
|
||
--*/
|
||
{
|
||
char MyName[MAX_PATH];
|
||
char * ModuleName;
|
||
STRING LogonProcessName;
|
||
STRING PackageName;
|
||
ULONG dummy;
|
||
NTSTATUS Status;
|
||
BOOLEAN WasEnabled;
|
||
|
||
Status = RtlAdjustPrivilege(SE_TCB_PRIVILEGE, TRUE, FALSE, &WasEnabled);
|
||
if (!NT_SUCCESS(Status))
|
||
{
|
||
BaseSetLastNTError(Status);
|
||
return(FALSE);
|
||
}
|
||
|
||
if (GetModuleFileNameA(NULL, MyName, MAX_PATH))
|
||
{
|
||
ModuleName = strrchr(MyName, '\\');
|
||
if (!ModuleName)
|
||
{
|
||
ModuleName = MyName;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
BaseSetLastNTError(STATUS_OBJECT_NAME_NOT_FOUND);
|
||
return(FALSE);
|
||
}
|
||
|
||
|
||
//
|
||
// Hookup to the LSA and locate our authentication package.
|
||
//
|
||
|
||
RtlInitString(&LogonProcessName, ModuleName);
|
||
Status = LsaRegisterLogonProcess(
|
||
&LogonProcessName,
|
||
&Logon32LsaHandle,
|
||
&dummy
|
||
);
|
||
|
||
|
||
//
|
||
// Turn off the privilege now.
|
||
//
|
||
if (!WasEnabled)
|
||
{
|
||
(VOID) RtlAdjustPrivilege(SE_TCB_PRIVILEGE, FALSE, FALSE, &WasEnabled);
|
||
}
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
BaseSetLastNTError(Status);
|
||
return(FALSE);
|
||
}
|
||
|
||
|
||
//
|
||
// Connect with the MSV1_0 authentication package
|
||
//
|
||
RtlInitString(&PackageName, "MICROSOFT_AUTHENTICATION_PACKAGE_V1_0");
|
||
Status = LsaLookupAuthenticationPackage (
|
||
Logon32LsaHandle,
|
||
&PackageName,
|
||
&Logon32MsvHandle
|
||
);
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
BaseSetLastNTError(Status);
|
||
(VOID) LsaDeregisterLogonProcess( Logon32LsaHandle );
|
||
Logon32LsaHandle = NULL;
|
||
return(FALSE);
|
||
}
|
||
|
||
return(TRUE);
|
||
}
|
||
|
||
//+---------------------------------------------------------------------------
|
||
//
|
||
// Function: L32pNotifyMpr
|
||
//
|
||
// Synopsis: Loads the MPR DLL and notifies the network providers (like
|
||
// csnw) so they know about this logon session and the credentials
|
||
//
|
||
// Arguments: [NewLogon] -- New logon information
|
||
// [LogonId] -- Logon ID
|
||
//
|
||
// History: 4-24-95 RichardW Created
|
||
//
|
||
// Notes:
|
||
//
|
||
//----------------------------------------------------------------------------
|
||
BOOL
|
||
L32pNotifyMpr(
|
||
PMSV1_0_INTERACTIVE_LOGON NewLogon,
|
||
PLUID LogonId
|
||
)
|
||
{
|
||
MSV1_0_INTERACTIVE_LOGON OldLogon;
|
||
LPWSTR LogonScripts;
|
||
DWORD status;
|
||
|
||
if ( Logon32MprHandle == NULL )
|
||
{
|
||
LockLogon();
|
||
|
||
if ( Logon32MprHandle == NULL)
|
||
{
|
||
Logon32MprHandle = LoadLibrary("mpr.dll");
|
||
if (Logon32MprHandle != NULL) {
|
||
|
||
Logon32LogonNotify = (LOGONNOTIFYFN) GetProcAddress(
|
||
Logon32MprHandle,
|
||
"WNetLogonNotify");
|
||
|
||
}
|
||
}
|
||
|
||
UnlockLogon();
|
||
|
||
}
|
||
|
||
if ( Logon32LogonNotify != NULL )
|
||
{
|
||
|
||
|
||
CopyMemory(&OldLogon, NewLogon, sizeof(OldLogon));
|
||
|
||
status = Logon32LogonNotify(
|
||
L"Windows NT Network Provider",
|
||
LogonId,
|
||
L"MSV1_0:Interactive",
|
||
(LPVOID)NewLogon,
|
||
L"MSV1_0:Interactive",
|
||
(LPVOID)&OldLogon,
|
||
L"SvcCtl", // StationName
|
||
NULL, // StationHandle
|
||
&LogonScripts); // LogonScripts
|
||
|
||
if (status == NO_ERROR) {
|
||
if (LogonScripts != NULL ) {
|
||
(void) LocalFree(LogonScripts);
|
||
}
|
||
}
|
||
|
||
return( TRUE );
|
||
}
|
||
|
||
return( FALSE );
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
L32pLogonNetUser(
|
||
IN HANDLE LsaHandle,
|
||
IN ULONG AuthenticationPackage,
|
||
IN SECURITY_LOGON_TYPE LogonType,
|
||
IN PUNICODE_STRING UserName,
|
||
IN PUNICODE_STRING Domain,
|
||
IN PSTRING Password,
|
||
IN PUNICODE_STRING Workstation,
|
||
IN DWORD dwSubAuth,
|
||
IN PSID LogonSid,
|
||
OUT PLUID LogonId,
|
||
OUT PHANDLE LogonToken,
|
||
OUT PQUOTA_LIMITS Quotas,
|
||
OUT PVOID *pProfileBuffer,
|
||
OUT PULONG pProfileBufferLength,
|
||
OUT PNTSTATUS pSubStatus
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Wraps up the call to LsaLogonUser
|
||
|
||
Arguments:
|
||
|
||
LsaHandle -- handle to LSA package
|
||
AuthenticationPackage -- ID of authentication package to use
|
||
LogonType -- Interactive, network, ...
|
||
UserName -- User Name
|
||
Domain -- Domain validating the user name
|
||
Password -- clear text password, can be empty if a sub-auth package is used
|
||
Workstation -- workstation where the login take place, can be NULL
|
||
if local login
|
||
dwSubAuth -- Sub-authentication DLL ID
|
||
LogonSid -- Logon SID for this session
|
||
LogonId -- created logon ID
|
||
LogonToken -- created logon token
|
||
Quotas -- quota info
|
||
pProfileBuffer -- account profile
|
||
pProfileBufferLength -- account profile length
|
||
pSubStatus -- substatus for authentication failure
|
||
|
||
Returns:
|
||
|
||
0 if success, else NT status
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS Status;
|
||
STRING OriginName;
|
||
TOKEN_SOURCE SourceContext;
|
||
PMSV1_0_LM20_LOGON MsvAuthInfo;
|
||
PMSV1_0_LM20_LOGON MsvNetAuthInfo;
|
||
PMSV1_0_INTERACTIVE_LOGON MsvInterAuthInfo;
|
||
PMSV1_0_SUBAUTH_LOGON MsvSubAuthInfo;
|
||
PVOID AuthInfoBuf;
|
||
ULONG AuthInfoSize;
|
||
PTOKEN_GROUPS TokenGroups;
|
||
PSID LocalSid;
|
||
UNICODE_STRING UnicodePassword;
|
||
//WCHAR ComputerName[ MAX_COMPUTERNAME_LENGTH + 1 ];
|
||
DWORD ComputerNameLength;
|
||
|
||
NT_RESPONSE NtResponse;
|
||
LM_RESPONSE LmResponse;
|
||
|
||
union {
|
||
LUID Luid;
|
||
NT_CHALLENGE NtChallenge;
|
||
} Challenge;
|
||
|
||
NT_OWF_PASSWORD PasswordHash;
|
||
OEM_STRING LmPassword;
|
||
UCHAR LmPasswordBuf[ LM20_PWLEN + 1 ];
|
||
LM_OWF_PASSWORD LmPasswordHash;
|
||
|
||
|
||
#if DBG
|
||
if (!RtlValidSid(LogonSid))
|
||
{
|
||
return(STATUS_INVALID_PARAMETER);
|
||
}
|
||
#endif
|
||
|
||
//
|
||
// Initialize source context structure
|
||
//
|
||
|
||
strncpy(SourceContext.SourceName, "IIS ", sizeof(SourceContext.SourceName)); // LATER from res file
|
||
|
||
Status = NtAllocateLocallyUniqueId(&SourceContext.SourceIdentifier);
|
||
|
||
if (!NT_SUCCESS(Status))
|
||
{
|
||
return(Status);
|
||
}
|
||
|
||
UnicodePassword.Buffer = NULL;
|
||
|
||
//
|
||
// Set logon origin
|
||
//
|
||
|
||
RtlInitString(&OriginName, "IIS security API");
|
||
|
||
//
|
||
// For network logons, do the magic.
|
||
//
|
||
|
||
if ( LogonType == Network )
|
||
{
|
||
#if 0
|
||
ComputerNameLength = MAX_COMPUTERNAME_LENGTH + 1;
|
||
|
||
if (!GetComputerNameW( ComputerName, &ComputerNameLength ) )
|
||
{
|
||
return( STATUS_INVALID_PARAMETER );
|
||
}
|
||
#else
|
||
ComputerNameLength = wcslen( Workstation->Buffer );
|
||
#endif
|
||
|
||
if (!RtlCreateUnicodeStringFromAsciiz( &UnicodePassword, Password->Buffer ))
|
||
{
|
||
return STATUS_NO_MEMORY;
|
||
}
|
||
|
||
AuthInfoSize = sizeof( MSV1_0_LM20_LOGON ) +
|
||
sizeof( WCHAR ) * ( wcslen( UserName->Buffer ) + 1 +
|
||
wcslen( Domain->Buffer ) + 1 +
|
||
ComputerNameLength + 1) +
|
||
NT_RESPONSE_LENGTH +
|
||
LM_RESPONSE_LENGTH ;
|
||
|
||
MsvNetAuthInfo = (PMSV1_0_LM20_LOGON)
|
||
(AuthInfoBuf = RtlAllocateHeap( RtlProcessHeap(),
|
||
HEAP_ZERO_MEMORY,
|
||
AuthInfoSize ));
|
||
|
||
if ( !MsvNetAuthInfo )
|
||
{
|
||
return( STATUS_NO_MEMORY );
|
||
}
|
||
|
||
//
|
||
// Start packing in the string
|
||
//
|
||
|
||
MsvNetAuthInfo->MessageType = MsV1_0NetworkLogon;
|
||
|
||
//
|
||
// Copy the user name into the authentication buffer
|
||
//
|
||
|
||
MsvNetAuthInfo->UserName.Length =
|
||
(USHORT)sizeof(WCHAR)*wcslen(UserName->Buffer);
|
||
MsvNetAuthInfo->UserName.MaximumLength =
|
||
MsvNetAuthInfo->UserName.Length + sizeof(WCHAR);
|
||
|
||
MsvNetAuthInfo->UserName.Buffer = (PWSTR)(MsvNetAuthInfo+1);
|
||
wcscpy(MsvNetAuthInfo->UserName.Buffer, UserName->Buffer);
|
||
|
||
|
||
//
|
||
// Copy the domain name into the authentication buffer
|
||
//
|
||
|
||
MsvNetAuthInfo->LogonDomainName.Length =
|
||
(USHORT)sizeof(WCHAR)*wcslen(Domain->Buffer);
|
||
MsvNetAuthInfo->LogonDomainName.MaximumLength =
|
||
MsvNetAuthInfo->LogonDomainName.Length + sizeof(WCHAR);
|
||
|
||
MsvNetAuthInfo->LogonDomainName.Buffer = (PWSTR)
|
||
((PBYTE)(MsvNetAuthInfo->UserName.Buffer) +
|
||
MsvNetAuthInfo->UserName.MaximumLength);
|
||
|
||
wcscpy(MsvNetAuthInfo->LogonDomainName.Buffer, Domain->Buffer);
|
||
|
||
//
|
||
// Copy the workstation name into the buffer
|
||
//
|
||
|
||
MsvNetAuthInfo->Workstation.Length = (USHORT)
|
||
(sizeof(WCHAR) * ComputerNameLength);
|
||
|
||
MsvNetAuthInfo->Workstation.MaximumLength =
|
||
MsvNetAuthInfo->Workstation.Length + sizeof(WCHAR);
|
||
|
||
MsvNetAuthInfo->Workstation.Buffer = (PWSTR)
|
||
((PBYTE) (MsvNetAuthInfo->LogonDomainName.Buffer) +
|
||
MsvNetAuthInfo->LogonDomainName.MaximumLength );
|
||
|
||
wcscpy( MsvNetAuthInfo->Workstation.Buffer, Workstation->Buffer );
|
||
|
||
//
|
||
// Now, generate the bits for the challenge
|
||
//
|
||
|
||
Status = NtAllocateLocallyUniqueId( &Challenge.Luid );
|
||
|
||
if ( !NT_SUCCESS(Status) )
|
||
{
|
||
RtlFreeHeap( RtlProcessHeap(), 0, MsvNetAuthInfo );
|
||
|
||
return( Status );
|
||
}
|
||
|
||
RtlCopyMemory( MsvNetAuthInfo->ChallengeToClient,
|
||
& Challenge,
|
||
MSV1_0_CHALLENGE_LENGTH );
|
||
|
||
//
|
||
// Set up space for response
|
||
//
|
||
|
||
MsvNetAuthInfo->CaseSensitiveChallengeResponse.Buffer = (PCHAR)
|
||
((PBYTE) (MsvNetAuthInfo->Workstation.Buffer) +
|
||
MsvNetAuthInfo->Workstation.MaximumLength );
|
||
|
||
MsvNetAuthInfo->CaseSensitiveChallengeResponse.Length =
|
||
NT_RESPONSE_LENGTH;
|
||
|
||
MsvNetAuthInfo->CaseSensitiveChallengeResponse.MaximumLength =
|
||
NT_RESPONSE_LENGTH;
|
||
|
||
RtlCalculateNtOwfPassword(
|
||
& UnicodePassword,
|
||
& PasswordHash );
|
||
|
||
RtlCalculateNtResponse(
|
||
& Challenge.NtChallenge,
|
||
& PasswordHash,
|
||
& NtResponse );
|
||
|
||
RtlCopyMemory( MsvNetAuthInfo->CaseSensitiveChallengeResponse.Buffer,
|
||
& NtResponse,
|
||
NT_RESPONSE_LENGTH );
|
||
|
||
//
|
||
// Now do the painful LM compatible hash, so anyone who is maintaining
|
||
// their account from a WfW machine will still have a password.
|
||
//
|
||
|
||
LmPassword.Buffer = (CHAR*)LmPasswordBuf;
|
||
LmPassword.Length = LmPassword.MaximumLength = LM20_PWLEN + 1;
|
||
|
||
Status = RtlUpcaseUnicodeStringToOemString(
|
||
& LmPassword,
|
||
& UnicodePassword,
|
||
FALSE );
|
||
|
||
if ( NT_SUCCESS(Status) )
|
||
{
|
||
|
||
MsvNetAuthInfo->CaseInsensitiveChallengeResponse.Buffer = (PCHAR)
|
||
((PBYTE) (MsvNetAuthInfo->CaseSensitiveChallengeResponse.Buffer) +
|
||
MsvNetAuthInfo->CaseSensitiveChallengeResponse.MaximumLength );
|
||
|
||
MsvNetAuthInfo->CaseInsensitiveChallengeResponse.Length =
|
||
LM_RESPONSE_LENGTH;
|
||
|
||
MsvNetAuthInfo->CaseInsensitiveChallengeResponse.MaximumLength =
|
||
LM_RESPONSE_LENGTH;
|
||
|
||
|
||
RtlCalculateLmOwfPassword(
|
||
LmPassword.Buffer,
|
||
& LmPasswordHash );
|
||
|
||
ZeroMemory( LmPassword.Buffer, LmPassword.Length );
|
||
|
||
RtlCalculateLmResponse(
|
||
& Challenge.NtChallenge,
|
||
& LmPasswordHash,
|
||
& LmResponse );
|
||
|
||
RtlCopyMemory( MsvNetAuthInfo->CaseInsensitiveChallengeResponse.Buffer,
|
||
& LmResponse,
|
||
LM_RESPONSE_LENGTH );
|
||
}
|
||
else
|
||
{
|
||
//
|
||
// If we're here, the NT (supplied) password is longer than the
|
||
// limit allowed for LM passwords. NULL out the field, so that
|
||
// MSV knows not to worry about it.
|
||
//
|
||
|
||
RtlZeroMemory( &MsvNetAuthInfo->CaseInsensitiveChallengeResponse,
|
||
sizeof( STRING ) );
|
||
}
|
||
|
||
MsvNetAuthInfo->ParameterControl = MSV1_0_RETURN_PASSWORD_EXPIRY;
|
||
}
|
||
else if ( LogonType == (SECURITY_LOGON_TYPE)IIS_Network )
|
||
{
|
||
if (!RtlCreateUnicodeStringFromAsciiz( &UnicodePassword, Password->Buffer ))
|
||
{
|
||
return STATUS_NO_MEMORY;
|
||
}
|
||
|
||
//
|
||
// Build logon structure for IIS network logons. We'll be using the subauth DLL
|
||
// in this case
|
||
//
|
||
|
||
AuthInfoSize = sizeof(MSV1_0_SUBAUTH_LOGON) +
|
||
sizeof(WCHAR)*(wcslen(UserName->Buffer) + 1 +
|
||
wcslen(Domain->Buffer) + 1 +
|
||
wcslen(Workstation->Buffer) + 1 ) +
|
||
sizeof(WCHAR)*wcslen(UnicodePassword.Buffer) +
|
||
LEN_ALIGN(strlen(Password->Buffer),sizeof(WCHAR));
|
||
|
||
AuthInfoBuf = RtlAllocateHeap( RtlProcessHeap(),
|
||
HEAP_ZERO_MEMORY,
|
||
AuthInfoSize);
|
||
MsvSubAuthInfo = (PMSV1_0_SUBAUTH_LOGON)AuthInfoBuf;
|
||
|
||
if (MsvSubAuthInfo == NULL) {
|
||
return(STATUS_NO_MEMORY);
|
||
}
|
||
|
||
//
|
||
// This authentication buffer will be used for a logon attempt
|
||
//
|
||
|
||
MsvSubAuthInfo->MessageType = MsV1_0SubAuthLogon;
|
||
|
||
MsvSubAuthInfo->SubAuthPackageId = dwSubAuth;
|
||
|
||
//
|
||
// Copy the domain name into the authentication buffer
|
||
//
|
||
|
||
MsvSubAuthInfo->LogonDomainName.Length =
|
||
(USHORT)sizeof(WCHAR)*wcslen(Domain->Buffer);
|
||
MsvSubAuthInfo->LogonDomainName.MaximumLength =
|
||
MsvSubAuthInfo->LogonDomainName.Length + sizeof(WCHAR);
|
||
MsvSubAuthInfo->LogonDomainName.Buffer = (PWSTR)(MsvSubAuthInfo+1);
|
||
|
||
wcscpy(MsvSubAuthInfo->LogonDomainName.Buffer, Domain->Buffer);
|
||
|
||
|
||
//
|
||
// Copy the user name into the authentication buffer
|
||
//
|
||
|
||
MsvSubAuthInfo->UserName.Length =
|
||
(USHORT)sizeof(WCHAR)*wcslen(UserName->Buffer);
|
||
MsvSubAuthInfo->UserName.MaximumLength =
|
||
MsvSubAuthInfo->UserName.Length + sizeof(WCHAR);
|
||
MsvSubAuthInfo->UserName.Buffer = (PWSTR)
|
||
((PBYTE)(MsvSubAuthInfo->LogonDomainName.Buffer) +
|
||
MsvSubAuthInfo->LogonDomainName.MaximumLength);
|
||
wcscpy(MsvSubAuthInfo->UserName.Buffer, UserName->Buffer);
|
||
|
||
|
||
//
|
||
// Copy the workstation
|
||
//
|
||
|
||
MsvSubAuthInfo->Workstation.Length =
|
||
(USHORT)sizeof(WCHAR)*wcslen(Workstation->Buffer);
|
||
MsvSubAuthInfo->Workstation.MaximumLength =
|
||
MsvSubAuthInfo->Workstation.Length + sizeof(WCHAR);
|
||
|
||
MsvSubAuthInfo->Workstation.Buffer = (PWSTR)
|
||
((PBYTE)(MsvSubAuthInfo->UserName.Buffer) +
|
||
MsvSubAuthInfo->UserName.MaximumLength);
|
||
wcscpy(MsvSubAuthInfo->Workstation.Buffer, Workstation->Buffer);
|
||
|
||
|
||
memset( MsvSubAuthInfo->ChallengeToClient,
|
||
'\0',
|
||
sizeof(MsvSubAuthInfo->ChallengeToClient) );
|
||
|
||
MsvSubAuthInfo->AuthenticationInfo1.Buffer =
|
||
((PCHAR)(MsvSubAuthInfo->Workstation.Buffer) +
|
||
MsvSubAuthInfo->Workstation.MaximumLength);
|
||
MsvSubAuthInfo->AuthenticationInfo1.Length = (USHORT)sizeof(WCHAR)*wcslen(UnicodePassword.Buffer);
|
||
|
||
MsvSubAuthInfo->AuthenticationInfo1.MaximumLength
|
||
= MsvSubAuthInfo->AuthenticationInfo1.Length;
|
||
|
||
memcpy( MsvSubAuthInfo->AuthenticationInfo1.Buffer,
|
||
UnicodePassword.Buffer,
|
||
MsvSubAuthInfo->AuthenticationInfo1.Length );
|
||
|
||
MsvSubAuthInfo->AuthenticationInfo2.Buffer =
|
||
((PCHAR)(MsvSubAuthInfo->AuthenticationInfo1.Buffer) +
|
||
MsvSubAuthInfo->AuthenticationInfo1.MaximumLength);
|
||
|
||
MsvSubAuthInfo->AuthenticationInfo2.Length = (USHORT)strlen(Password->Buffer);
|
||
|
||
MsvSubAuthInfo->AuthenticationInfo2.MaximumLength
|
||
= LEN_ALIGN(MsvSubAuthInfo->AuthenticationInfo2.Length,sizeof(WCHAR));
|
||
|
||
memcpy( MsvSubAuthInfo->AuthenticationInfo2.Buffer,
|
||
Password->Buffer,
|
||
MsvSubAuthInfo->AuthenticationInfo2.Length );
|
||
|
||
MsvSubAuthInfo->ParameterControl = (dwSubAuth << MSV1_0_SUBAUTHENTICATION_DLL_SHIFT)
|
||
| MSV1_0_UPDATE_LOGON_STATISTICS
|
||
| MSV1_0_DONT_TRY_GUEST_ACCOUNT
|
||
| MSV1_0_CLEARTEXT_PASSWORD_ALLOWED
|
||
| MSV1_0_RETURN_PASSWORD_EXPIRY
|
||
| MSV1_0_SUBAUTHENTICATION_DLL_EX
|
||
| MSV1_0_DISABLE_PERSONAL_FALLBACK
|
||
;
|
||
|
||
LogonType = Network;
|
||
}
|
||
else
|
||
{
|
||
//
|
||
// Build logon structure for non-network logons - service,
|
||
// batch, interactive
|
||
//
|
||
|
||
if (!RtlCreateUnicodeStringFromAsciiz( &UnicodePassword, Password->Buffer ))
|
||
{
|
||
return STATUS_NO_MEMORY;
|
||
}
|
||
|
||
AuthInfoSize = sizeof(MSV1_0_INTERACTIVE_LOGON) +
|
||
sizeof(WCHAR)*(wcslen(UserName->Buffer) + 1 +
|
||
wcslen(Domain->Buffer) + 1 +
|
||
wcslen(UnicodePassword.Buffer) + 1 );
|
||
|
||
AuthInfoBuf = RtlAllocateHeap( RtlProcessHeap(),
|
||
HEAP_ZERO_MEMORY,
|
||
AuthInfoSize);
|
||
MsvInterAuthInfo = (PMSV1_0_INTERACTIVE_LOGON)AuthInfoBuf;
|
||
|
||
if (MsvInterAuthInfo == NULL)
|
||
{
|
||
return STATUS_NO_MEMORY;
|
||
}
|
||
|
||
//
|
||
// This authentication buffer will be used for a logon attempt
|
||
//
|
||
|
||
MsvInterAuthInfo->MessageType = MsV1_0InteractiveLogon;
|
||
|
||
|
||
//
|
||
// Copy the user name into the authentication buffer
|
||
//
|
||
|
||
MsvInterAuthInfo->UserName.Length =
|
||
(USHORT)sizeof(WCHAR)*wcslen(UserName->Buffer);
|
||
MsvInterAuthInfo->UserName.MaximumLength =
|
||
MsvInterAuthInfo->UserName.Length + sizeof(WCHAR);
|
||
|
||
MsvInterAuthInfo->UserName.Buffer = (PWSTR)(MsvInterAuthInfo+1);
|
||
wcscpy(MsvInterAuthInfo->UserName.Buffer, UserName->Buffer);
|
||
|
||
|
||
//
|
||
// Copy the domain name into the authentication buffer
|
||
//
|
||
|
||
MsvInterAuthInfo->LogonDomainName.Length =
|
||
(USHORT)sizeof(WCHAR)*wcslen(Domain->Buffer);
|
||
MsvInterAuthInfo->LogonDomainName.MaximumLength =
|
||
MsvInterAuthInfo->LogonDomainName.Length + sizeof(WCHAR);
|
||
|
||
MsvInterAuthInfo->LogonDomainName.Buffer = (PWSTR)
|
||
((PBYTE)(MsvInterAuthInfo->UserName.Buffer) +
|
||
MsvInterAuthInfo->UserName.MaximumLength);
|
||
|
||
wcscpy(MsvInterAuthInfo->LogonDomainName.Buffer, Domain->Buffer);
|
||
|
||
//
|
||
// Copy the password into the authentication buffer
|
||
// Hide it once we have copied it. Use the same seed value
|
||
// that we used for the original password in pGlobals.
|
||
//
|
||
|
||
|
||
MsvInterAuthInfo->Password.Length =
|
||
(USHORT)sizeof(WCHAR)*wcslen(UnicodePassword.Buffer);
|
||
MsvInterAuthInfo->Password.MaximumLength =
|
||
MsvInterAuthInfo->Password.Length + sizeof(WCHAR);
|
||
|
||
MsvInterAuthInfo->Password.Buffer = (PWSTR)
|
||
((PBYTE)(MsvInterAuthInfo->LogonDomainName.Buffer) +
|
||
MsvInterAuthInfo->LogonDomainName.MaximumLength);
|
||
|
||
wcscpy(MsvInterAuthInfo->Password.Buffer, UnicodePassword.Buffer);
|
||
}
|
||
|
||
//
|
||
// Create logon token groups
|
||
//
|
||
|
||
#define TOKEN_GROUP_COUNT 2 // We'll add the local SID and the logon SID
|
||
|
||
TokenGroups = (PTOKEN_GROUPS) RtlAllocateHeap(RtlProcessHeap(), 0,
|
||
sizeof(TOKEN_GROUPS) +
|
||
(TOKEN_GROUP_COUNT - ANYSIZE_ARRAY) * sizeof(SID_AND_ATTRIBUTES));
|
||
|
||
if (TokenGroups == NULL) {
|
||
RtlFreeHeap(RtlProcessHeap(), 0, AuthInfoBuf);
|
||
return(STATUS_NO_MEMORY);
|
||
}
|
||
|
||
//
|
||
// Fill in the logon token group list
|
||
//
|
||
|
||
Status = RtlAllocateAndInitializeSid(
|
||
&L32LocalSidAuthority,
|
||
1,
|
||
SECURITY_LOCAL_RID,
|
||
0, 0, 0, 0, 0, 0, 0,
|
||
&LocalSid
|
||
);
|
||
|
||
|
||
TokenGroups->GroupCount = TOKEN_GROUP_COUNT;
|
||
TokenGroups->Groups[0].Sid = LogonSid;
|
||
TokenGroups->Groups[0].Attributes =
|
||
SE_GROUP_MANDATORY | SE_GROUP_ENABLED |
|
||
SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_LOGON_ID;
|
||
TokenGroups->Groups[1].Sid = LocalSid;
|
||
TokenGroups->Groups[1].Attributes =
|
||
SE_GROUP_MANDATORY | SE_GROUP_ENABLED |
|
||
SE_GROUP_ENABLED_BY_DEFAULT;
|
||
|
||
//
|
||
// Now try to log this one on
|
||
//
|
||
|
||
Status = LsaLogonUser (
|
||
LsaHandle,
|
||
&OriginName,
|
||
LogonType,
|
||
AuthenticationPackage,
|
||
AuthInfoBuf,
|
||
AuthInfoSize,
|
||
TokenGroups,
|
||
&SourceContext,
|
||
pProfileBuffer,
|
||
pProfileBufferLength,
|
||
LogonId,
|
||
LogonToken,
|
||
Quotas,
|
||
pSubStatus
|
||
);
|
||
|
||
//
|
||
// Discard token group list
|
||
//
|
||
|
||
RtlFreeHeap(RtlProcessHeap(), 0, TokenGroups);
|
||
|
||
//
|
||
// Notify all the network providers, if this is a NON network logon
|
||
//
|
||
|
||
if ( NT_SUCCESS( Status ) &&
|
||
LogonType != Network &&
|
||
LogonType != IIS_Network )
|
||
{
|
||
L32pNotifyMpr( (PMSV1_0_INTERACTIVE_LOGON)AuthInfoBuf, LogonId );
|
||
}
|
||
|
||
//
|
||
// Discard authentication buffer
|
||
//
|
||
|
||
RtlFreeHeap(RtlProcessHeap(), 0, AuthInfoBuf);
|
||
|
||
if ( UnicodePassword.Buffer != NULL )
|
||
{
|
||
RtlFreeUnicodeString(&UnicodePassword);
|
||
}
|
||
|
||
RtlFreeSid(LocalSid);
|
||
|
||
return(Status);
|
||
}
|
||
|
||
|
||
BOOL
|
||
WINAPI
|
||
IISLogonNetUserW(
|
||
PWSTR lpszUsername,
|
||
PWSTR lpszDomain,
|
||
PSTR lpszPassword,
|
||
PWSTR lpszWorkstation,
|
||
DWORD dwSubAuth,
|
||
DWORD dwLogonType,
|
||
DWORD dwLogonProvider,
|
||
HANDLE * phToken,
|
||
LARGE_INTEGER * pExpiry
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Logs a user on via username and domain
|
||
name via the LSA.
|
||
|
||
Arguments:
|
||
|
||
lpszUsername -- user name
|
||
lpszDomain -- domain validating the user name
|
||
lpszPassword -- clear text password, can be empty if a sub-auth DLL
|
||
is used
|
||
lpszWorkstation -- workstation requesting the login, can be NULL
|
||
for local workstation
|
||
dwSubAuth -- sub-auth DLL ID
|
||
dwLogonType -- one of LOGON32_LOGON_NETWORK, LOGON32_LOGON_IIS_NETWORK
|
||
dwLogonProvider -- must be LOGON32_PROVIDER_DEFAULT
|
||
phToken -- created access token
|
||
pExpiry -- ptr to pwd expiration time
|
||
|
||
Returns:
|
||
|
||
TRUE if success, FALSE if error
|
||
|
||
--*/
|
||
{
|
||
|
||
NTSTATUS Status;
|
||
ULONG PackageId;
|
||
UNICODE_STRING Username;
|
||
UNICODE_STRING Domain;
|
||
STRING Password;
|
||
UNICODE_STRING Workstation;
|
||
LUID LogonId;
|
||
PSID pLogonSid;
|
||
PVOID Profile;
|
||
ULONG ProfileLength;
|
||
NTSTATUS SubStatus;
|
||
SECURITY_LOGON_TYPE LogonType;
|
||
WCHAR achComputerName[MAX_COMPUTERNAME_LENGTH+1];
|
||
|
||
//
|
||
// Validate the provider
|
||
//
|
||
if (dwLogonProvider == LOGON32_PROVIDER_DEFAULT)
|
||
{
|
||
dwLogonProvider = LOGON32_PROVIDER_WINNT35;
|
||
}
|
||
|
||
if (dwLogonProvider != LOGON32_PROVIDER_WINNT35)
|
||
{
|
||
BaseSetLastNTError(STATUS_INVALID_PARAMETER);
|
||
return(FALSE);
|
||
}
|
||
|
||
switch (dwLogonType)
|
||
{
|
||
case LOGON32_LOGON_IIS_NETWORK:
|
||
LogonType = (SECURITY_LOGON_TYPE)IIS_Network;
|
||
break;
|
||
|
||
case LOGON32_LOGON_NETWORK:
|
||
LogonType = Network;
|
||
break;
|
||
|
||
case LOGON32_LOGON_INTERACTIVE:
|
||
LogonType = Interactive;
|
||
break;
|
||
|
||
case LOGON32_LOGON_BATCH:
|
||
LogonType = Batch;
|
||
break;
|
||
|
||
case LOGON32_LOGON_SERVICE:
|
||
LogonType = Service;
|
||
break;
|
||
|
||
case LOGON32_LOGON_NETWORK_CLEARTEXT:
|
||
LogonType = NetworkCleartext;
|
||
break;
|
||
|
||
default:
|
||
BaseSetLastNTError(STATUS_INVALID_PARAMETER);
|
||
return(FALSE);
|
||
break;
|
||
}
|
||
|
||
if ( lpszWorkstation == NULL )
|
||
{
|
||
DWORD dwL = MAX_COMPUTERNAME_LENGTH+1;
|
||
if ( !GetComputerNameW( achComputerName, &dwL ) )
|
||
{
|
||
return(FALSE);
|
||
}
|
||
lpszWorkstation = achComputerName;
|
||
}
|
||
|
||
//
|
||
// If the MSV handle is -1, grab the lock, and try again:
|
||
//
|
||
|
||
if (Logon32MsvHandle == 0xFFFFFFFF)
|
||
{
|
||
LockLogon();
|
||
|
||
//
|
||
// If the MSV handle is still -1, init our connection to lsa. We
|
||
// have the lock, so no other threads can be trying this right now.
|
||
//
|
||
if (Logon32MsvHandle == 0xFFFFFFFF)
|
||
{
|
||
if (!L32pInitLsa())
|
||
{
|
||
UnlockLogon();
|
||
return( FALSE );
|
||
}
|
||
}
|
||
|
||
UnlockLogon();
|
||
}
|
||
|
||
//
|
||
// Validate the parameters. NULL or empty domain or NULL or empty
|
||
// user name is invalid.
|
||
//
|
||
|
||
RtlInitUnicodeString(&Username, lpszUsername);
|
||
if (Username.Length == 0)
|
||
{
|
||
BaseSetLastNTError(STATUS_INVALID_PARAMETER);
|
||
return(FALSE);
|
||
}
|
||
|
||
RtlInitUnicodeString(&Domain, lpszDomain);
|
||
RtlInitString(&Password, lpszPassword);
|
||
|
||
//
|
||
// Finally, init the workstation
|
||
//
|
||
RtlInitUnicodeString(&Workstation, lpszWorkstation);
|
||
|
||
|
||
//
|
||
// Get a logon sid to refer to this guy (not that anyone will be able to
|
||
// use it...
|
||
//
|
||
pLogonSid = L32CreateLogonSid(NULL);
|
||
if (!pLogonSid)
|
||
{
|
||
BaseSetLastNTError(STATUS_NO_MEMORY);
|
||
return(FALSE);
|
||
}
|
||
|
||
|
||
//
|
||
// Attempt the logon
|
||
//
|
||
Status = L32pLogonNetUser(
|
||
Logon32LsaHandle,
|
||
Logon32MsvHandle,
|
||
LogonType,
|
||
&Username,
|
||
&Domain,
|
||
&Password,
|
||
&Workstation,
|
||
dwSubAuth,
|
||
pLogonSid,
|
||
&LogonId,
|
||
phToken,
|
||
&Logon32QuotaLimits,
|
||
&Profile,
|
||
&ProfileLength,
|
||
&SubStatus);
|
||
|
||
//
|
||
// Done with logon sid, regardless of result:
|
||
//
|
||
|
||
LocalFree( pLogonSid );
|
||
|
||
if (!NT_SUCCESS(Status))
|
||
{
|
||
if (Status == STATUS_ACCOUNT_RESTRICTION)
|
||
{
|
||
BaseSetLastNTError(SubStatus);
|
||
}
|
||
else
|
||
{
|
||
BaseSetLastNTError(Status);
|
||
}
|
||
|
||
return(FALSE);
|
||
}
|
||
|
||
if (Profile != NULL)
|
||
{
|
||
if ( pExpiry != NULL )
|
||
{
|
||
switch ( dwLogonType )
|
||
{
|
||
case LOGON32_LOGON_IIS_NETWORK:
|
||
case LOGON32_LOGON_NETWORK:
|
||
memcpy( pExpiry,
|
||
&(((PMSV1_0_LM20_LOGON_PROFILE)Profile)
|
||
->LogoffTime),
|
||
sizeof(LARGE_INTEGER) );
|
||
break;
|
||
|
||
default:
|
||
//
|
||
// if pwd never expire, MustChange.HighPart == 0x7fffffff
|
||
// if user cannot change pwd, CanChange == LastSet
|
||
//
|
||
|
||
if ( ((PMSV1_0_INTERACTIVE_PROFILE)Profile)
|
||
->PasswordMustChange.HighPart
|
||
!= 0x7fffffff )
|
||
{
|
||
memcpy( pExpiry,
|
||
&(((PMSV1_0_INTERACTIVE_PROFILE)Profile)
|
||
->PasswordMustChange),
|
||
sizeof(LARGE_INTEGER) );
|
||
}
|
||
else
|
||
{
|
||
((PMSV1_0_INTERACTIVE_PROFILE)Profile)
|
||
->PasswordMustChange.LowPart = 0xffffffff;
|
||
((PMSV1_0_INTERACTIVE_PROFILE)Profile)
|
||
->PasswordMustChange.HighPart = 0x7fffffff;
|
||
}
|
||
break;
|
||
}
|
||
}
|
||
|
||
LsaFreeReturnBuffer(Profile);
|
||
}
|
||
|
||
return(TRUE);
|
||
}
|
||
|
||
|
||
BOOL
|
||
WINAPI
|
||
IISLogonNetUserA(
|
||
PSTR lpszUsername,
|
||
PSTR lpszDomain,
|
||
PSTR lpszPassword,
|
||
PSTR lpszWorkstation,
|
||
DWORD dwSubAuth,
|
||
DWORD dwLogonType,
|
||
DWORD dwLogonProvider,
|
||
HANDLE * phToken,
|
||
LARGE_INTEGER * pExpiry
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Logs a user on via username and domain
|
||
name via the LSA.
|
||
|
||
Arguments:
|
||
|
||
lpszUsername -- user name
|
||
lpszDomain -- domain validating the user name
|
||
lpszPassword -- clear text password, can be empty if a sub-auth DLL
|
||
is used
|
||
lpszWorkstation -- workstation requesting the login, can be NULL
|
||
for local workstation
|
||
dwSubAuth -- sub-auth DLL ID
|
||
dwLogonType -- one of LOGON32_LOGON_NETWORK, LOGON32_LOGON_IIS_NETWORK
|
||
dwLogonProvider -- must be LOGON32_PROVIDER_DEFAULT
|
||
phToken -- created access token
|
||
pExpiry -- ptr to pwd expiration time
|
||
|
||
Returns:
|
||
|
||
TRUE if success, FALSE if error
|
||
|
||
--*/
|
||
{
|
||
UNICODE_STRING Username;
|
||
UNICODE_STRING Domain;
|
||
UNICODE_STRING Workstation;
|
||
NTSTATUS Status;
|
||
BOOL bRet;
|
||
|
||
Username.Buffer = NULL;
|
||
Domain.Buffer = NULL;
|
||
Workstation.Buffer = NULL;
|
||
|
||
if ( !RtlCreateUnicodeStringFromAsciiz(&Username, lpszUsername) )
|
||
{
|
||
bRet = FALSE;
|
||
goto Cleanup;
|
||
}
|
||
|
||
if (!RtlCreateUnicodeStringFromAsciiz(&Domain, lpszDomain))
|
||
{
|
||
bRet = FALSE;
|
||
goto Cleanup;
|
||
}
|
||
|
||
if ( lpszWorkstation )
|
||
{
|
||
if (!RtlCreateUnicodeStringFromAsciiz(&Workstation, lpszWorkstation))
|
||
{
|
||
bRet = FALSE;
|
||
goto Cleanup;
|
||
}
|
||
}
|
||
|
||
bRet = IISLogonNetUserW(
|
||
Username.Buffer,
|
||
Domain.Buffer,
|
||
lpszPassword,
|
||
Workstation.Buffer,
|
||
dwSubAuth,
|
||
dwLogonType,
|
||
dwLogonProvider,
|
||
phToken,
|
||
pExpiry
|
||
) ;
|
||
|
||
Cleanup:
|
||
|
||
if (Username.Buffer)
|
||
{
|
||
RtlFreeUnicodeString(&Username);
|
||
}
|
||
|
||
if (Domain.Buffer)
|
||
{
|
||
RtlFreeUnicodeString(&Domain);
|
||
}
|
||
|
||
if (Workstation.Buffer)
|
||
{
|
||
RtlFreeUnicodeString(&Workstation);
|
||
}
|
||
|
||
return bRet;
|
||
}
|
||
|
||
|
||
BOOL
|
||
WINAPI
|
||
IISNetUserCookieA(
|
||
LPSTR lpszUsername,
|
||
DWORD dwSeed,
|
||
LPSTR lpszCookieBuff,
|
||
DWORD dwBuffSize
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Compute logon validator ( to be used as password )
|
||
for IISSuba
|
||
|
||
Arguments:
|
||
|
||
lpszUsername -- user name
|
||
dwSeed -- start value of cookie
|
||
|
||
Returns:
|
||
|
||
TRUE if success, FALSE if error
|
||
|
||
--*/
|
||
{
|
||
UNICODE_STRING Username;
|
||
LPWSTR lpwszUserName;
|
||
NTSTATUS Status;
|
||
#define TOHEX(a) ((a)>=10 ? 'a'+(a)-10 : '0'+(a))
|
||
|
||
if ( dwBuffSize < sizeof(dwSeed)*2 + 1 )
|
||
{
|
||
SetLastError( ERROR_INSUFFICIENT_BUFFER );
|
||
return FALSE;
|
||
}
|
||
|
||
if ( !RtlCreateUnicodeStringFromAsciiz(&Username, lpszUsername) )
|
||
{
|
||
return FALSE;
|
||
}
|
||
|
||
lpwszUserName = Username.Buffer;
|
||
while ( *lpwszUserName )
|
||
{
|
||
dwSeed = ((dwSeed << 5) | ( dwSeed >> 27 )) ^ ((*lpwszUserName++)&0xff);
|
||
}
|
||
|
||
RtlFreeUnicodeString(&Username);
|
||
|
||
lpszCookieBuff[0] = '0' + IISSUBA_COOKIE;
|
||
lpszCookieBuff[1] = '"';
|
||
|
||
for ( UINT x = 0, y = 2 ; x < sizeof(dwSeed) ; ++x )
|
||
{
|
||
UINT v;
|
||
v = ((LPBYTE)&dwSeed)[x]>>4;
|
||
lpszCookieBuff[y++] = TOHEX( v );
|
||
v = ((LPBYTE)&dwSeed)[x]&0x0f;
|
||
lpszCookieBuff[y++] = TOHEX( v );
|
||
}
|
||
lpszCookieBuff[y] = '\0';
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
|
||
BOOL
|
||
WINAPI
|
||
IISLogonDigestUserA(
|
||
PDIGEST_LOGON_INFO pDigestLogonInfo,
|
||
DWORD dwAlgo,
|
||
HANDLE * phToken
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Logs a user on via username and domain
|
||
name via the LSA using Digest authentication
|
||
|
||
Arguments:
|
||
|
||
pDigestLogonInfo - Digest parameters for use in logon
|
||
dwAlgo - type of logon
|
||
phToken -- created access token
|
||
|
||
Returns:
|
||
|
||
TRUE if success, FALSE if error
|
||
|
||
--*/
|
||
{
|
||
UNICODE_STRING Username;
|
||
UNICODE_STRING Domain;
|
||
STRING Password;
|
||
NTSTATUS Status;
|
||
BOOL bRet;
|
||
char achA[3];
|
||
int l;
|
||
|
||
Username.Buffer = NULL;
|
||
Domain.Buffer = NULL;
|
||
Password.Buffer = NULL;
|
||
|
||
if (!RtlCreateUnicodeStringFromAsciiz(&Username,
|
||
pDigestLogonInfo->pszNtUser))
|
||
{
|
||
bRet = FALSE;
|
||
goto Cleanup;
|
||
}
|
||
|
||
if (!RtlCreateUnicodeStringFromAsciiz(&Domain,
|
||
pDigestLogonInfo->pszDomain))
|
||
{
|
||
bRet = FALSE;
|
||
goto Cleanup;
|
||
}
|
||
|
||
achA[0] = (int)dwAlgo + '0';
|
||
achA[1] = '"';
|
||
achA[2] = '\0';
|
||
|
||
l = strlen(achA) +
|
||
strlen(pDigestLogonInfo->pszRealm) +
|
||
strlen(pDigestLogonInfo->pszURI) +
|
||
strlen(pDigestLogonInfo->pszMethod) +
|
||
strlen(pDigestLogonInfo->pszNonce) +
|
||
strlen(pDigestLogonInfo->pszCurrentNonce) +
|
||
strlen(pDigestLogonInfo->pszResponse) +
|
||
strlen(pDigestLogonInfo->pszUser) +
|
||
strlen(pDigestLogonInfo->pszQOP) +
|
||
strlen(pDigestLogonInfo->pszCNonce) +
|
||
strlen(pDigestLogonInfo->pszNC) +
|
||
32;
|
||
|
||
if ( Password.Buffer = (CHAR*)RtlAllocateHeap( RtlProcessHeap(), HEAP_ZERO_MEMORY, l) )
|
||
{
|
||
Password.MaximumLength = (USHORT)l;
|
||
}
|
||
else
|
||
{
|
||
Password.MaximumLength = 0;
|
||
}
|
||
Password.Length = 0;
|
||
|
||
if( !NT_SUCCESS( Status = RtlAppendAsciizToString( &Password, achA)) ||
|
||
!NT_SUCCESS( Status = RtlAppendAsciizToString( &Password, pDigestLogonInfo->pszRealm)) ||
|
||
!NT_SUCCESS( Status = RtlAppendAsciizToString( &Password, "\"")) ||
|
||
!NT_SUCCESS( Status = RtlAppendAsciizToString( &Password, pDigestLogonInfo->pszURI)) ||
|
||
!NT_SUCCESS( Status = RtlAppendAsciizToString( &Password, "\"")) ||
|
||
!NT_SUCCESS( Status = RtlAppendAsciizToString( &Password, pDigestLogonInfo->pszMethod)) ||
|
||
!NT_SUCCESS( Status = RtlAppendAsciizToString( &Password, "\"")) ||
|
||
!NT_SUCCESS( Status = RtlAppendAsciizToString( &Password, pDigestLogonInfo->pszNonce)) ||
|
||
!NT_SUCCESS( Status = RtlAppendAsciizToString( &Password, "\"")) ||
|
||
!NT_SUCCESS( Status = RtlAppendAsciizToString( &Password, pDigestLogonInfo->pszCurrentNonce)) ||
|
||
!NT_SUCCESS( Status = RtlAppendAsciizToString( &Password, "\"")) ||
|
||
!NT_SUCCESS( Status = RtlAppendAsciizToString( &Password, pDigestLogonInfo->pszResponse)) ||
|
||
!NT_SUCCESS( Status = RtlAppendAsciizToString( &Password, "\"")) ||
|
||
!NT_SUCCESS( Status = RtlAppendAsciizToString( &Password, pDigestLogonInfo->pszUser)) ||
|
||
!NT_SUCCESS( Status = RtlAppendAsciizToString( &Password, "\"")) ||
|
||
!NT_SUCCESS( Status = RtlAppendAsciizToString( &Password, pDigestLogonInfo->pszQOP)) ||
|
||
!NT_SUCCESS( Status = RtlAppendAsciizToString( &Password, "\"")) ||
|
||
!NT_SUCCESS( Status = RtlAppendAsciizToString( &Password, pDigestLogonInfo->pszCNonce)) ||
|
||
!NT_SUCCESS( Status = RtlAppendAsciizToString( &Password, "\"")) ||
|
||
!NT_SUCCESS( Status = RtlAppendAsciizToString( &Password, pDigestLogonInfo->pszNC)) ||
|
||
!NT_SUCCESS( Status = RtlAppendAsciizToString( &Password, "\"")) )
|
||
{
|
||
BaseSetLastNTError(Status);
|
||
bRet = FALSE;
|
||
goto Cleanup;
|
||
}
|
||
|
||
bRet = IISLogonNetUserW(
|
||
Username.Buffer,
|
||
Domain.Buffer,
|
||
Password.Buffer,
|
||
NULL,
|
||
IIS_SUBAUTH_ID,
|
||
LOGON32_LOGON_IIS_NETWORK,
|
||
LOGON32_PROVIDER_DEFAULT,
|
||
phToken,
|
||
NULL
|
||
) ;
|
||
|
||
Cleanup:
|
||
|
||
if (Username.Buffer)
|
||
{
|
||
RtlFreeUnicodeString(&Username);
|
||
}
|
||
|
||
if (Domain.Buffer)
|
||
{
|
||
RtlFreeUnicodeString(&Domain);
|
||
}
|
||
|
||
if ( Password.Buffer )
|
||
{
|
||
RtlFreeHeap(RtlProcessHeap(), 0, Password.Buffer );
|
||
}
|
||
|
||
return bRet;
|
||
}
|
||
|
||
|
||
|
||
/*******************************************************************
|
||
|
||
NAME: GetDefaultDomainName
|
||
|
||
SYNOPSIS: Fills in the given array with the name of the default
|
||
domain to use for logon validation.
|
||
|
||
ENTRY: pszDomainName - Pointer to a buffer that will receive
|
||
the default domain name.
|
||
|
||
cchDomainName - The size (in charactesr) of the domain
|
||
name buffer.
|
||
|
||
RETURNS: TRUE if successful, FALSE if not.
|
||
|
||
HISTORY:
|
||
KeithMo 05-Dec-1994 Created.
|
||
|
||
********************************************************************/
|
||
BOOL
|
||
IISGetDefaultDomainName(
|
||
CHAR * pszDomainName,
|
||
DWORD cchDomainName
|
||
)
|
||
{
|
||
OBJECT_ATTRIBUTES ObjectAttributes;
|
||
NTSTATUS NtStatus;
|
||
INT Result;
|
||
DWORD err = 0;
|
||
LSA_HANDLE LsaPolicyHandle = NULL;
|
||
PPOLICY_ACCOUNT_DOMAIN_INFO DomainInfo = NULL;
|
||
|
||
//
|
||
// Open a handle to the local machine's LSA policy object.
|
||
//
|
||
|
||
InitializeObjectAttributes( &ObjectAttributes, // object attributes
|
||
NULL, // name
|
||
0L, // attributes
|
||
NULL, // root directory
|
||
NULL ); // security descriptor
|
||
|
||
NtStatus = LsaOpenPolicy( NULL, // system name
|
||
&ObjectAttributes, // object attributes
|
||
POLICY_EXECUTE, // access mask
|
||
&LsaPolicyHandle ); // policy handle
|
||
|
||
if( !NT_SUCCESS( NtStatus ) )
|
||
{
|
||
DBGPRINTF(( DBG_CONTEXT,
|
||
"cannot open lsa policy, error %08lX\n",
|
||
NtStatus ));
|
||
|
||
err = LsaNtStatusToWinError( NtStatus );
|
||
|
||
// Failure LsaOpenPolicy() does not guarantee that
|
||
// LsaPolicyHandle was not touched.
|
||
|
||
LsaPolicyHandle = NULL;
|
||
|
||
goto Cleanup;
|
||
}
|
||
|
||
//
|
||
// Query the domain information from the policy object.
|
||
//
|
||
|
||
NtStatus = LsaQueryInformationPolicy( LsaPolicyHandle,
|
||
PolicyAccountDomainInformation,
|
||
(PVOID *)&DomainInfo );
|
||
|
||
if( !NT_SUCCESS( NtStatus ) )
|
||
{
|
||
|
||
DBGPRINTF(( DBG_CONTEXT,
|
||
"cannot query lsa policy info, error %08lX\n",
|
||
NtStatus ));
|
||
|
||
err = LsaNtStatusToWinError( NtStatus );
|
||
goto Cleanup;
|
||
}
|
||
|
||
//
|
||
// Convert the name from UNICODE to ANSI.
|
||
//
|
||
|
||
Result = WideCharToMultiByte( CP_ACP,
|
||
0, // flags
|
||
(LPCWSTR)DomainInfo->DomainName.Buffer,
|
||
DomainInfo->DomainName.Length / sizeof(WCHAR),
|
||
pszDomainName,
|
||
cchDomainName - 1, // save room for '\0'
|
||
NULL,
|
||
NULL );
|
||
|
||
if( Result <= 0 )
|
||
{
|
||
err = GetLastError();
|
||
|
||
DBGPRINTF(( DBG_CONTEXT,
|
||
"cannot convert domain name to ANSI, error %d\n",
|
||
err ));
|
||
|
||
goto Cleanup;
|
||
}
|
||
|
||
//
|
||
// Ensure the ANSI string is zero terminated.
|
||
//
|
||
|
||
|
||
DBG_ASSERT( (DWORD)Result < cchDomainName );
|
||
|
||
pszDomainName[Result] = '\0';
|
||
|
||
//
|
||
// Success!
|
||
//
|
||
|
||
|
||
DBG_ASSERT( err == 0 );
|
||
|
||
Cleanup:
|
||
|
||
if( DomainInfo != NULL )
|
||
{
|
||
LsaFreeMemory( (PVOID)DomainInfo );
|
||
}
|
||
|
||
if( LsaPolicyHandle != NULL )
|
||
{
|
||
LsaClose( LsaPolicyHandle );
|
||
}
|
||
|
||
if ( err )
|
||
{
|
||
SetLastError( err );
|
||
return FALSE;
|
||
}
|
||
|
||
return TRUE;
|
||
|
||
} // IISGetDefaultDomainName
|
||
|