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.
 
 
 
 
 
 

686 lines
18 KiB

//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1992 - 1996.
//
// File: secmisc.cxx
//
// Contents: Code to retrieve security-related information from the job
// object. Function names partially describe the intended
// function - we don't want to give too much away.
//
// Classes: None.
//
// Functions: CloseFile
// GetFileInformation
//
// History: 15-May-96 MarkBl Created
//
//----------------------------------------------------------------------------
#include "..\pch\headers.hxx"
#pragma hdrstop
#include <ntsecapi.h>
#include <mstask.h>
#include <msterr.h>
#include "debug.hxx"
#include "lsa.hxx"
#include "globals.hxx"
#include "misc.hxx"
BOOL WaitForMUP (DWORD dwMaxWait);
BOOL WaitForServiceToStart (LPTSTR lpServiceName, DWORD dwMaxWait);
//
// Defined in globals.cxx
//
extern CStaticCritSec gcsSSCritSection;
//
// Defined in security.cxx.
//
extern DWORD gdwKeyElement;
extern POLICY_ACCOUNT_DOMAIN_INFO * gpDomainInfo;
extern WCHAR gwszComputerName[MAX_COMPUTERNAME_LENGTH + 2];
//+---------------------------------------------------------------------------
//
// Function: CloseFile
//
// Synopsis:
//
// Arguments: [hFile] --
// [ccApplication] --
// [wszApplication] --
// [hrPrevious] --
//
// Returns: S_OK
// SCHED_E_INVALID_TASK
// E_UNEXPECTED
// HRESULT argument, if it is an error.
//
// Notes: None.
//
//----------------------------------------------------------------------------
HRESULT
CloseFile(
HANDLE hFile,
WORD ccApplication,
WCHAR wszApplication[],
HRESULT hrPrevious)
{
HRESULT hr = S_OK;
DWORD dwBytesRead;
WCHAR * pwsz;
WORD wAppOffset;
WORD cch;
//
// If the previous operation failed, skip the application read.
//
if (FAILED(hrPrevious))
{
hr = hrPrevious;
goto ErrorExit;
}
//
// Read the offset to the application name.
//
if (!ReadFile(hFile, &wAppOffset, sizeof(wAppOffset), &dwBytesRead, NULL))
{
CHECK_HRESULT(HRESULT_FROM_WIN32(GetLastError()));
hr = SCHED_E_INVALID_TASK;
goto ErrorExit;
}
//
// Move to read the application name.
//
if (SetFilePointer(hFile, wAppOffset, NULL, FILE_BEGIN) != -1)
{
//
// Read the application size, allocate sufficient buffer space
// and read the application string.
//
if (!ReadFile(hFile, &cch, sizeof(cch), &dwBytesRead, NULL) ||
dwBytesRead != sizeof(cch))
{
CHECK_HRESULT(HRESULT_FROM_WIN32(GetLastError()));
hr = SCHED_E_INVALID_TASK;
goto ErrorExit;
}
if (!cch)
{
wszApplication[0] = L'\0';
}
else if (cch > ccApplication)
{
hr = E_UNEXPECTED;
CHECK_HRESULT(hr);
goto ErrorExit;
}
else
{
if (!ReadFile(hFile,
wszApplication,
cch * sizeof(WCHAR),
&dwBytesRead,
NULL))
{
CHECK_HRESULT(HRESULT_FROM_WIN32(GetLastError()));
hr = SCHED_E_INVALID_TASK;
goto ErrorExit;
}
if (dwBytesRead != (cch * sizeof(WCHAR)))
{
hr = SCHED_E_INVALID_TASK;
CHECK_HRESULT(hr);
goto ErrorExit;
}
if (wszApplication[cch - 1] != L'\0')
{
hr = SCHED_E_INVALID_TASK;
CHECK_HRESULT(hr);
goto ErrorExit;
}
}
}
else
{
CHECK_HRESULT(HRESULT_FROM_WIN32(GetLastError()));
hr = SCHED_E_INVALID_TASK;
}
ErrorExit:
if (hFile != NULL) CloseHandle(hFile);
return(hr);
}
//+---------------------------------------------------------------------------
//
// Function: GetFileInformation
//
// Synopsis:
//
// Arguments: [pwszFileName] --
// [hFile] --
// [pcbOwnerSid] --
// [ppOwnerSid] --
// [ppOwnerSecDescr] --
// [ccOwnerName] --
// [ccOwnerDomain] --
// [ccApplication] --
// [wszOwnerName] --
// [wszOwnerDomain] --
// [wszApplication] --
// [pftCreationTime] --
// [pdwVolumeSerialNo] --
//
// Returns: HRESULT
//
// Notes: None.
//
//----------------------------------------------------------------------------
HRESULT
GetFileInformation(
LPCWSTR pwszFileName,
DWORD * pcbOwnerSid,
PSID * ppOwnerSid,
PSECURITY_DESCRIPTOR * ppOwnerSecDescr,
UUID * pJobID,
DWORD ccOwnerName,
DWORD ccOwnerDomain,
DWORD ccApplication,
WCHAR wszOwnerName[],
WCHAR wszOwnerDomain[],
WCHAR wszApplication[],
FILETIME * pftCreationTime,
DWORD * pdwVolumeSerialNo)
{
BY_HANDLE_FILE_INFORMATION hinfo;
HANDLE hFile;
SECURITY_DESCRIPTOR * pOwnerSecDescr = NULL;
PSID pOwnerSid = NULL;
DWORD cbOwnerSid = 0;
DWORD cbSizeNeeded;
BOOL fRet, fOwnerDefaulted;
static s_bWaitForWorkStation = TRUE;
HRESULT hr = OpenFileWithRetry(pwszFileName, GENERIC_READ, FILE_SHARE_READ, &hFile);
if (FAILED(hr))
{
return hr;
}
else
{
//
// Read the UUID from the job indicated.
//
BYTE pbBuffer[sizeof(DWORD) + sizeof(UUID)];
DWORD dwBytesRead;
if (!ReadFile(hFile, pbBuffer, sizeof(pbBuffer), &dwBytesRead, NULL))
{
CHECK_HRESULT(HRESULT_FROM_WIN32(GetLastError()));
CloseHandle(hFile);
return SCHED_E_INVALID_TASK;
}
if (dwBytesRead != sizeof(pbBuffer))
{
CHECK_HRESULT(SCHED_E_INVALID_TASK);
CloseHandle(hFile);
return SCHED_E_INVALID_TASK;
}
CopyMemory(pJobID, pbBuffer + sizeof(DWORD), sizeof(*pJobID));
}
//
// Retrieve file creation time and the volume serial number.
//
if (!GetFileInformationByHandle(hFile, &hinfo))
{
hr = HRESULT_FROM_WIN32(GetLastError());
CHECK_HRESULT(hr);
goto ErrorExit;
}
//
// Retrieve the file owner. Call GetFileSecurity twice - first to get
// the buffer size, then the actual information retrieval.
//
if (GetFileSecurity(pwszFileName,
OWNER_SECURITY_INFORMATION,
NULL,
0,
&cbSizeNeeded))
{
//
// Didn't expect this to succeed!
//
hr = E_UNEXPECTED;
CHECK_HRESULT(hr);
goto ErrorExit;
}
if ((GetLastError() == ERROR_INSUFFICIENT_BUFFER) && (cbSizeNeeded > 0))
{
//
// Allocate the buffer space necessary and retrieve the info.
//
pOwnerSecDescr = (SECURITY_DESCRIPTOR *)new BYTE[cbSizeNeeded];
if (pOwnerSecDescr == NULL)
{
hr = E_OUTOFMEMORY;
CHECK_HRESULT(hr);
goto ErrorExit;
}
if (!GetFileSecurity(pwszFileName,
OWNER_SECURITY_INFORMATION,
pOwnerSecDescr,
cbSizeNeeded,
&cbSizeNeeded))
{
hr = HRESULT_FROM_WIN32(GetLastError());
CHECK_HRESULT(hr);
goto ErrorExit;
}
}
else
{
hr = HRESULT_FROM_WIN32(GetLastError());
CHECK_HRESULT(hr);
goto ErrorExit;
}
//
// Retrieve & validate the owner sid.
//
// NB : After this, pOwnerSid will point into the security descriptor,
// pOwnerSecDescr; hence, the descriptor must exist for the
// lifetime of pOwnerSid.
//
fRet = GetSecurityDescriptorOwner(pOwnerSecDescr,
&pOwnerSid,
&fOwnerDefaulted);
if (fRet)
{
if (fRet = IsValidSid(pOwnerSid))
{
cbOwnerSid = GetLengthSid(pOwnerSid);
}
else
{
hr = HRESULT_FROM_WIN32(GetLastError());
CHECK_HRESULT(hr);
}
}
else
{
hr = HRESULT_FROM_WIN32(GetLastError());
CHECK_HRESULT(hr);
}
if (!fRet)
{
goto ErrorExit;
}
//
// Retrieve the account name & domain name from the file owner sid.
//
SID_NAME_USE snu;
BOOL bDoLookupAgain;
//
//Startup jobs for domain users will fail if workstation is not initialized
//If LookupAccountSid fails and we are booting then force the service to
// wait until workstation is fully initialized and then try again
//
do
{
bDoLookupAgain = FALSE;
schDebugOut((DEB_TRACE, "GetFileInformation: Calling LookupAccountSid\n"));
if (!LookupAccountSid(NULL,
pOwnerSid,
wszOwnerName,
&ccOwnerName,
wszOwnerDomain,
&ccOwnerDomain,
&snu))
{
hr = HRESULT_FROM_WIN32(GetLastError());
CHECK_HRESULT(hr);
if( s_bWaitForWorkStation )
{
schDebugOut((DEB_TRACE, "GetFileInformation: Delaying LookupAccountSid for boot\n"));
WaitForMUP(120000);
WaitForServiceToStart(L"workstation",120000);
WaitForServiceToStart(L"netlogon",120000);
bDoLookupAgain = TRUE;
s_bWaitForWorkStation = FALSE;
//Reset since CloseFile returns this value if failure
hr = ERROR_SUCCESS;
} else {
goto ErrorExit;
}
}
} while(bDoLookupAgain);
ErrorExit:
//
// Being a little sneaky here and reading the job application whilst
// closing the file handle. That is, if all succeeded above.
//
hr = CloseFile(hFile, (WORD)ccApplication, wszApplication, hr);
if (SUCCEEDED(hr))
{
*pftCreationTime = hinfo.ftCreationTime;
*pdwVolumeSerialNo = hinfo.dwVolumeSerialNumber;
*pcbOwnerSid = cbOwnerSid;
*ppOwnerSid = pOwnerSid;
*ppOwnerSecDescr = pOwnerSecDescr;
//
// If not already done so, set the 'mystery' global DWORD.
// This DWORD, in addition to other data, is used to generate
// the encryption key for the SAC/SAI database.
//
// The reason why this is done here is to spread the key generation
// code around a bit.
//
if (!gdwKeyElement)
{
SetMysteryDWORDValue();
}
}
else
{
delete pOwnerSecDescr;
}
return(hr);
}
//+---------------------------------------------------------------------------
//
// Function: SetMysteryDWORDValue
//
// Synopsis: Initialize a global DWORD to be used as a data element in
// generation of the SAC/SAI database encryption key.
//
// Arguments: None.
//
// Returns: None.
//
// Notes: None.
//
//----------------------------------------------------------------------------
void
SetMysteryDWORDValue(void)
{
//
// Set the global mystery dword to the first dword of the job or queue
// class ids, depending on the value of the machine sid.
//
EnterCriticalSection(&gcsSSCritSection);
if (!gdwKeyElement)
{
DWORD dwTmp;
//
// The last (3) subauthorities of the machine SID are unique per
// machine. Test LSB of the 2nd from the last subauthority.
//
PUCHAR pSidSubAuthorityCount = GetSidSubAuthorityCount(
gpDomainInfo->DomainSid);
schAssert(pSidSubAuthorityCount != NULL);
DWORD nSubAuthority = (pSidSubAuthorityCount != NULL ?
max(*pSidSubAuthorityCount, 2) : 2);
DWORD * pSubAuthority = GetSidSubAuthority(
gpDomainInfo->DomainSid,
nSubAuthority - 2);
schAssert(pSubAuthority != NULL);
if (pSubAuthority != NULL && *pSubAuthority & 0x00000001)
{
dwTmp = 0x255b3f60; // CLSID_CQueue.Data1
}
else
{
dwTmp = CLSID_CTask.Data1;
}
//
// Apply a mask to the mystery value to further disguise it.
//
if (gwszComputerName[0] & 0x0100)
{
dwTmp &= 0xC03F71C3;
}
else
{
dwTmp &= 0xE3507233;
}
gdwKeyElement = dwTmp;
}
LeaveCriticalSection(&gcsSSCritSection);
}
//*************************************************************
//
// WaitForServiceToStart()
//
// Purpose: Waits for the specified service to start
//
// Parameters: dwMaxWait - Max wait time
//
//
// Return: TRUE if the network is started
// FALSE if not
//
//*************************************************************
BOOL WaitForServiceToStart (LPTSTR lpServiceName, DWORD dwMaxWait)
{
BOOL bStarted = FALSE;
DWORD dwSize = 512;
SC_HANDLE hScManager = NULL;
SC_HANDLE hService = NULL;
LPQUERY_SERVICE_CONFIG lpServiceConfig = NULL;
DWORD dwPoleWait = 1000;
DWORD StartTickCount;
SERVICE_STATUS ServiceStatus;
//
// OpenSCManager and the rpcss service
//
hScManager = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
if (!hScManager) {
goto Exit;
}
hService = OpenService(hScManager, lpServiceName,
SERVICE_QUERY_CONFIG | SERVICE_QUERY_STATUS);
if (!hService) {
goto Exit;
}
//
// Query if the service is going to start
//
lpServiceConfig = (LPQUERY_SERVICE_CONFIG)LocalAlloc (LPTR, dwSize);
if (!lpServiceConfig) {
goto Exit;
}
if (!QueryServiceConfig (hService, lpServiceConfig, dwSize, &dwSize)) {
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
goto Exit;
}
LocalFree (lpServiceConfig);
lpServiceConfig = (LPQUERY_SERVICE_CONFIG)LocalAlloc (LPTR, dwSize);
if (!lpServiceConfig) {
goto Exit;
}
if (!QueryServiceConfig (hService, lpServiceConfig, dwSize, &dwSize)) {
goto Exit;
}
}
if (lpServiceConfig->dwStartType != SERVICE_AUTO_START) {
goto Exit;
}
//
// Loop until the service starts or we think it never will start
// or we've exceeded our maximum time delay.
//
StartTickCount = GetTickCount();
while (!bStarted) {
if ((GetTickCount() - StartTickCount) > dwMaxWait) {
break;
}
if (!QueryServiceStatus(hService, &ServiceStatus )) {
break;
}
if (ServiceStatus.dwCurrentState == SERVICE_STOPPED) {
if (ServiceStatus.dwWin32ExitCode == ERROR_SERVICE_NEVER_STARTED) {
Sleep(dwPoleWait);
} else {
break;
}
} else if ( (ServiceStatus.dwCurrentState == SERVICE_RUNNING) ||
(ServiceStatus.dwCurrentState == SERVICE_CONTINUE_PENDING) ||
(ServiceStatus.dwCurrentState == SERVICE_PAUSE_PENDING) ||
(ServiceStatus.dwCurrentState == SERVICE_PAUSED) ) {
bStarted = TRUE;
} else if (ServiceStatus.dwCurrentState == SERVICE_START_PENDING) {
Sleep(dwPoleWait);
} else {
Sleep(dwPoleWait);
}
}
Exit:
if (lpServiceConfig) {
LocalFree (lpServiceConfig);
}
if (hService) {
CloseServiceHandle(hService);
}
if (hScManager) {
CloseServiceHandle(hScManager);
}
return bStarted;
}
//*************************************************************
//
// WaitForMUP()
//
// Purpose: Waits for the MUP to finish initializing
//
// Parameters: dwMaxWait - Max wait time
//
// Return: TRUE if successful
// FALSE if an error occurs
//
//*************************************************************
BOOL WaitForMUP (DWORD dwMaxWait)
{
HANDLE hEvent = NULL;
BOOL bResult;
INT i = 0;
//
// Try to open the event
//
do {
hEvent = OpenEvent (SYNCHRONIZE, FALSE,
TEXT("wkssvc: MUP finished initializing event"));
if (hEvent) {
break;
}
if (GetLastError() != ERROR_FILE_NOT_FOUND) {
break;
}
Sleep(500);
i++;
} while (i < 20);
if (!hEvent) {
return FALSE;
}
//
// Wait for the event to be signalled
//
bResult = (WaitForSingleObject (hEvent, dwMaxWait) == WAIT_OBJECT_0);
//
// Clean up
//
CloseHandle (hEvent);
return bResult;
}