Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

566 lines
17 KiB

/*---------------------------------------------------------------------------
File: PwdSvc.cpp
Comments: entry point functions and other exported functions for ADMT's
password migration Lsa notification package.
REVISION LOG ENTRY
Revision By: Paul Thompson
Revised on 09/06/00
---------------------------------------------------------------------------
*/
#include "Pwd.h"
#include "PwdSvc.h"
#include "PwdSvc_s.c"
// These global variables can be changed if required
#define gsPwdProtoSeq TEXT("ncacn_np")
#define gsPwdEndPoint TEXT("\\pipe\\PwdMigRpc")
DWORD gPwdRpcMinThreads = 1;
DWORD gPwdRpcMaxThreads = RPC_C_LISTEN_MAX_CALLS_DEFAULT;
#ifndef STATUS_SUCCESS
#define STATUS_SUCCESS ((NTSTATUS) 0x00000000L)
#endif
extern "C"
{
BOOL WINAPI _CRT_INIT( HANDLE hInstance, DWORD nReason, LPVOID pReserved );
}
RPC_STATUS RPC_ENTRY SecurityCallback(RPC_IF_HANDLE hInterface, void* pContext);
namespace
{
//
// Timer Class
//
class CTimer
{
public:
CTimer() :
m_hTimer(NULL)
{
}
~CTimer()
{
if (m_hTimer)
{
Close();
}
}
DWORD Create()
{
ASSERT(m_hTimer == NULL);
//
// Create timer. Close timer first if already created.
//
if (m_hTimer)
{
Close();
}
m_hTimer = CreateWaitableTimer(NULL, TRUE, NULL);
return m_hTimer ? ERROR_SUCCESS : GetLastError();
}
DWORD Wait(int nTime)
{
ASSERT(m_hTimer != NULL);
DWORD dwError = ERROR_SUCCESS;
if (m_hTimer)
{
//
// Convert elapsed time parameter from milliseconds
// to relative due time in 100s of nanoseconds.
//
LARGE_INTEGER liDueTime;
liDueTime.QuadPart = nTime * -10000i64;
//
// Set timer and wait for timer to be signaled.
//
if (SetWaitableTimer(m_hTimer, &liDueTime, 0, NULL, NULL, FALSE))
{
if (WaitForSingleObject(m_hTimer, INFINITE) == WAIT_FAILED)
{
dwError = GetLastError();
}
}
else
{
dwError = GetLastError();
}
}
else
{
dwError = ERROR_INVALID_HANDLE;
}
return dwError;
}
void Close()
{
ASSERT(m_hTimer != NULL);
if (m_hTimer)
{
if (CloseHandle(m_hTimer) == FALSE)
{
DWORD dwError = GetLastError();
ASSERT(dwError == ERROR_SUCCESS);
}
m_hTimer = NULL;
}
}
protected:
HANDLE m_hTimer;
};
}
/******************************
* RPC Registration Functions *
******************************/
/*********************************************************************
* *
* Written by: Paul Thompson *
* Date: 11 JUNE 2001 *
* *
* This function is called by a thread spawned from our *
* "InitializeChangeNotify" password filter function to wait until *
* SAM, and therefore RPC, is up and running. *
* *
* 04/17/02 MPO - rewritten to wait for SAM_SERVICE_STARTED event to *
* be created first before waiting for this event to *
* be signaled *
*********************************************************************/
//BEGIN PwdMigWaitForSamService
DWORD __stdcall PwdMigWaitForSamService()
{
DWORD dwError = ERROR_SUCCESS;
//
// Attempt to open the SAM service started event object.
//
// Note that we must use the Nt APIs to open the event object
// as the name begins with a \ character which is not valid
// in the object name space used by the OpenEvent API.
//
HANDLE hEvent = NULL;
UNICODE_STRING usEventName;
RtlInitUnicodeString(&usEventName, L"\\SAM_SERVICE_STARTED");
OBJECT_ATTRIBUTES oaEventAttributes;
InitializeObjectAttributes(&oaEventAttributes, &usEventName, 0, 0, NULL);
NTSTATUS ntStatus = NtOpenEvent(&hEvent, SYNCHRONIZE, &oaEventAttributes);
if (NT_ERROR(ntStatus))
{
//
// If the SAM service started event object has not been
// created yet then wait until it has been created.
//
if (ntStatus == STATUS_OBJECT_NAME_NOT_FOUND)
{
//
// Enter a loop which waits until the open event API returns
// an error other than the event object not found. The loop
// waits 15 sec between attempts to open object.
//
CTimer timer;
dwError = timer.Create();
if (dwError == ERROR_SUCCESS)
{
for (;;)
{
dwError = timer.Wait(15000);
if (dwError != ERROR_SUCCESS)
{
break;
}
ntStatus = NtOpenEvent(&hEvent, SYNCHRONIZE, &oaEventAttributes);
if (NT_SUCCESS(ntStatus))
{
break;
}
if (ntStatus != STATUS_OBJECT_NAME_NOT_FOUND)
{
dwError = LsaNtStatusToWinError(ntStatus);
break;
}
}
}
}
else
{
dwError = LsaNtStatusToWinError(ntStatus);
}
}
//
// If event has been opened then wait for it to be signalled.
//
if (hEvent != NULL)
{
NTSTATUS ntWaitStatus = NtWaitForSingleObject(hEvent, FALSE, NULL);
NTSTATUS ntCloseStatus = NtClose(hEvent);
ASSERT(NT_SUCCESS(ntCloseStatus));
dwError = (ntWaitStatus == STATUS_WAIT_0) ? ERROR_SUCCESS : LsaNtStatusToWinError(ntWaitStatus);
}
return dwError;
}
//END PwdMigWaitForSamService
/*********************************************************************
* *
* Written by: Paul Thompson *
* Date: 11 JUNE 2001 *
* *
* This function is a spawned thread created by the *
* "InitializeChangeNotify" password filter function to wait until *
* SAM, and therefore RPC, is up and running and then register the *
* ADMT Password Migration RPC interface. *
* *
* 04/17/02 MPO - rewritten to wait until critical section is *
* initialized and to use a stronger authentication *
* service when built for Windows 2000 or later *
*********************************************************************/
//BEGIN PwdMigRPCRegProc
DWORD WINAPI PwdMigRPCRegProc(LPVOID lpParameter)
{
RPC_STATUS rc = RPC_S_OK;
//
// Wait for the SAM service to start before registering RPC interface.
//
if (PwdMigWaitForSamService() == ERROR_SUCCESS)
{
//
// Initialize critical section used by PwdRpc interface
// implementation.
// Note that the critical section must be initialized before
// registering RPC interface to prevent a race condition.
//
bool bCriticalSection = false;
try
{
InitializeCriticalSection(&csADMTCriticalSection);
bCriticalSection = true;
}
catch (...)
{
;
}
if (bCriticalSection == false)
{
//
// The initialize critical section API must
// have thrown a STATUS_NO_MEMORY exception.
//
// Enter a loop which waits until the critical
// section is initialized. The loop waits 15 sec
// between attempts to initialize critical section.
//
CTimer timer;
DWORD dwError = timer.Create();
if (dwError == ERROR_SUCCESS)
{
while (bCriticalSection == false)
{
dwError = timer.Wait(15000);
if (dwError != ERROR_SUCCESS)
{
break;
}
try
{
InitializeCriticalSection(&csADMTCriticalSection);
bCriticalSection = true;
}
catch (...)
{
;
}
}
}
if (dwError != ERROR_SUCCESS)
{
return dwError;
}
}
// specify protocol sequence and endpoint
// for receiving remote procedure calls
rc = RpcServerUseProtseqEp(gsPwdProtoSeq, RPC_C_PROTSEQ_MAX_REQS_DEFAULT, gsPwdEndPoint, NULL);
if (rc == RPC_S_OK)
{
//
// Register PwdMigRpc interface with the RPC run-time library.
// Only allow connections with an authorization level higher than
// RPC_C_AUTHN_LEVEL_NONE. Also specifying security callback to
// validate client before allowing access to interface.
//
rc = RpcServerRegisterIfEx(
PwdMigRpc_ServerIfHandle,
NULL,
NULL,
RPC_IF_ALLOW_SECURE_ONLY,
RPC_C_LISTEN_MAX_CALLS_DEFAULT,
SecurityCallback
);
if (rc == RPC_S_OK)
{
#ifdef PWD_W2KORLATER
//
// Register authentication information with RPC specifying
// default principal name and specifying GSS negotiate.
//
PWCHAR pszPrincipalName = NULL;
rc = RpcServerInqDefaultPrincName(RPC_C_AUTHN_GSS_NEGOTIATE, &pszPrincipalName);
if (rc == RPC_S_OK)
{
ASSERT(pszPrincipalName && (wcslen(pszPrincipalName) != 0));
//set the authenification for this RPC interface
rc = RpcServerRegisterAuthInfo(pszPrincipalName, RPC_C_AUTHN_GSS_NEGOTIATE, NULL, NULL);
RpcStringFree(&pszPrincipalName);
}
#else
//set the authenification for this RPC interface
rc = RpcServerRegisterAuthInfo(NULL, RPC_C_AUTHN_WINNT, NULL, NULL);
#endif
}
}//end if set protocal sequence and end point set
}//end if RPC service is ready
return 0;
}
//END PwdMigRPCRegProc
/*********************************************************************
* *
* Written by: Paul Thompson *
* Date: 7 SEPT 2000 *
* *
* This function is called by Lsa when trying to load all *
* registered Lsa password filter notification dlls. Here we will *
* initialize the RPC run-time library to handle our ADMT password *
* migration RPC interface and to begin looking for RPC calls. If we*
* fail to successfully setup our RPC, we will return FALSE from this*
* function which will cause Lsa not to load this password filter *
* Dll. *
* Note that the other two password filter dll functions: *
* PasswordChangeNotify and PasswordFilter do nothing at this point *
* in time. *
* *
*********************************************************************/
//BEGIN InitializeChangeNotify
BOOLEAN __stdcall InitializeChangeNotify()
{
/* local variables */
BOOLEAN bSuccess = FALSE;
/* function body */
//spawn a seperate thread to register our RPC interface once RPC is up and running
HANDLE h = CreateThread(NULL, 0, PwdMigRPCRegProc, NULL, 0, NULL);
if (h != NULL)
bSuccess = TRUE;;
CloseHandle(h);
return bSuccess;
}
//END InitializeChangeNotify
/*********************************************************************
* *
* Written by: Paul Thompson *
* Date: 7 SEPT 2000 *
* *
* This function is called by Lsa for all registered Lsa password*
* filter notification dlls when a password in the domain has been *
* modified. We will simply return STATUS_SUCCESS and do nothing. *
* *
*********************************************************************/
//BEGIN PasswordChangeNotify
NTSTATUS __stdcall PasswordChangeNotify(PUNICODE_STRING UserName, ULONG RelativeId,
PUNICODE_STRING NewPassword)
{
return STATUS_SUCCESS;
}
/*********************************************************************
* *
* Written by: Paul Thompson *
* Date: 7 SEPT 2000 *
* *
* This function is called by Lsa for all registered Lsa password*
* filter notification dlls when a password in the domain is being *
* modified. This function is designed to indicate to Lsa if the new*
* password is acceptable. We will simply return TRUE (indicating it*
* is acceptable) and do nothing. *
* *
*********************************************************************/
//BEGIN PasswordFilter
BOOLEAN __stdcall PasswordFilter(PUNICODE_STRING AccountName, PUNICODE_STRING FullName,
PUNICODE_STRING Password, BOOLEAN SetOperation)
{
return TRUE;
}
//END PasswordFilter
/***************************/
/* Internal DLL functions. */
/***************************/
static BOOL Initialize(void)
{
return TRUE;
}
static BOOL Terminate(BOOL procterm)
{
if (!procterm)
return TRUE;
/* XXX Do stuff here */
return TRUE;
}
BOOL WINAPI
DllMain(HINSTANCE hinst, DWORD reason, VOID *rsvd)
/*++
Routine description:
Dynamic link library entry point. Does nothing meaningful.
Arguments:
hinst = handle for the DLL
reason = code indicating reason for call
rsvd = for process attach: non-NULL => process startup
for process detach: non-NULL => process termination
Return value:
status = success/failure
Side effects:
None
--*/
{
switch (reason) {
case DLL_PROCESS_ATTACH:
{
_CRT_INIT(hinst, reason, rsvd);
DisableThreadLibraryCalls(hinst);
return Initialize();
break;
}
case DLL_PROCESS_DETACH:
{
BOOL bStat = Terminate(rsvd != NULL);
_CRT_INIT(hinst, reason, rsvd);
return bStat;
break;
}
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
return TRUE;
default:
return FALSE;
}
}
///////////////////////////////////////////////////////////////////////////////
// Midl allocate memory
///////////////////////////////////////////////////////////////////////////////
void __RPC_FAR * __RPC_USER
midl_user_allocate(
size_t len )
{
return new char[len];
}
///////////////////////////////////////////////////////////////////////////////
// Midl free memory
///////////////////////////////////////////////////////////////////////////////
void __RPC_USER
midl_user_free(
void __RPC_FAR * ptr )
{
delete [] ptr;
}