// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF // ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A // PARTICULAR PURPOSE. // // Copyright (c) Microsoft Corporation. All rights reserved. /* File Replication Sample Server System Service FILE: FileRepServerProc.cpp PURPOSE: Remote procedures for server system service FUNCTIONS: COMMENTS: */ #include "common.h" #include #include #include #include #include #include // header file generated by MIDL compiler #include "FileRepServer.h" // Declarations for service routines. #include "Service.h" #ifdef DEBUG2 #include "DbgMsg.h" #endif extern HANDLE ServerCompletionPort; extern LONG nThreadsAtServerCompletionPort; #define ServerCompletionPortTimeout (20*1000) typedef enum tSReqState { StateArrived, StateQueued, StateActive } SReqState; typedef enum { IoFileRep, IoPipe, IoFile } IoCompletionType; typedef enum { Activate, Read, Push, Wait, } ActionType; #ifdef DEBUG1 unsigned nServerReqs = 0; #endif // // Packages up the variables to be passed // to the processing thread. // typedef struct tSReq{ handle_t hFileRepClient; HANDLE hTokenHandle; HANDLE hLocalFile; LPTSTR LocalFileName; // Set when we are impersonating the client. BOOL bImpersonating; // Priority of this request. UINT Pri; // User SID. PSID pSID; SReqState State; // The out-pipe we use to pull data from the server. ASYNC_CHAR_PIPE_TYPE *OutPipe; // The async handle for the call to RemoteOpen. RPC_ASYNC_STATE *Async; BYTE pbReadBuf[PULL_BUFSIZE]; LONG FileReadPos; ULONG PushSize; OVERLAPPED FileOl; ActionType Action; CRITICAL_SECTION Lock; BOOL bPushOutstanding; BOOL bReadOutstanding; BOOL bBuf; ULONG cbRead; // Set when all the non-null pushes have been dispatched. // This happens after reading the last segment of the file // and calling a push for it. What remains to be done // is waiting for notification for the last data push and issuing a // NULL push. BOOL bLastDataPushIssued; // Set when all of the file reads have completed. BOOL bReadsDone; // Set when issuing the last push of 0 length. BOOL bNullPush; // Set when a pull fails and RPC runtime cleans up the call. // There is no need to call Cancel after that. BOOL fCallInvalidated; // We use this wariable to set an error code so that // ServerShutdownRequest can know whether an error has occurred. // If no error occurred, the async call will be completed. // Otherwise it will be cancelled. DWORD Status; } SReq; // // Handles the requests placed on req queue and active req queue // and returns when no requests are available. // SReq* FindSReq(void) { SReq *pReq = NULL; #ifdef DEBUG2 TCHAR Msg[MSG_SIZE]; ULONG bufSize = MSG_SIZE; // Keeps track of remaining size of buffer for _stprintf_s int nCharWritten; #endif // // We will now go and check if the request or the active request sets of queues have anything that we // can service. If they do not, then this thread can terminate. // // Check if the request queues have anything on them. If they do, // pick a request off the highest priority queue and handle it, but only if we // are not handling enough of those requests already. for (UINT pri = NumPriGroups; pri > 0; pri--) { pReq = (SReq *) QueueRemove(ServerReqQueues[pri-1]); if (pReq != NULL) { break; } } if (pReq != NULL) { #ifdef DEBUG2 nCharWritten = _stprintf_s(Msg, bufSize, TEXT("RequestFile: Took req %p off Req queue %p\n"), pReq, ServerReqQueues[pReq->Pri]); bufSize -= nCharWritten; DbgMsgRecord(Msg); #endif if (CounterIncrement(pServerActiveReqCounters[pReq->Pri])) { if (QueueHashIncrementCounter(ServerActiveReqHashCounters[pReq->Pri], pReq->pSID)) { #ifdef DEBUG2 nCharWritten = _stprintf_s(Msg, bufSize, TEXT("Incremented ServerActiveReqCounters[%d] and ServerActiveReqHashCounters[%d]\n"), pReq->Pri, pReq->Pri); bufSize -= nCharWritten; DbgMsgRecord(Msg); #endif // The request now resides on a new queue. CounterDecrement(pServerReqCounters[pReq->Pri]); #ifdef DEBUG2 nCharWritten = _stprintf_s(Msg, bufSize, TEXT("Decremented ServerReqCounters[%d]\n"), pReq->Pri); bufSize -= nCharWritten; DbgMsgRecord(Msg); #endif pReq->State = StateActive; #ifdef DEBUG2 nCharWritten = _stprintf_s(Msg, bufSize, TEXT("RequestFile: Handling active req %p\n"), pReq); bufSize -= nCharWritten; DbgMsgRecord(Msg); #endif return pReq; } else { // There were too many requests for a given SID, place the request back // onto the queue. // Don't forget to decrement the counter for the group! CounterDecrement(pServerActiveReqCounters[pReq->Pri]); QueueAdd(ServerReqQueues[pReq->Pri], pReq, TRUE); #ifdef DEBUG2 nCharWritten = _stprintf_s(Msg, bufSize, TEXT("Too many active requests for a SID\n")); bufSize -= nCharWritten; DbgMsgRecord(Msg); nCharWritten = _stprintf_s(Msg, bufSize, TEXT("RequestFile: Put req %p onto Req queue %p\n"), pReq, ServerReqQueues[pReq->Pri]); bufSize -= nCharWritten; DbgMsgRecord(Msg); #endif } } else { // There were too many active requests for the user group, place the request back // onto the queue. QueueAdd(ServerReqQueues[pReq->Pri], pReq, TRUE); #ifdef DEBUG2 nCharWritten = _stprintf_s(Msg, bufSize, TEXT("Too many active requests for priority %d\n"), pReq->Pri); bufSize -= nCharWritten; DbgMsgRecord(Msg); nCharWritten = _stprintf_s(Msg, bufSize, TEXT("RequestFile: Put req %p onto Req queue %p\n"), pReq, ServerReqQueues[pReq->Pri]); bufSize -= nCharWritten; DbgMsgRecord(Msg); #endif } } return NULL; } VOID FindAndActivateSReq(VOID) { DWORD status; tSReq *pReq = FindSReq(); if (pReq) { #ifdef DEBUG1 QueueAdd(ServerActiveReqQueue, pReq, TRUE); #endif // All that is requeired to activate the request is to queue a completion // packet with Activate key and the Req as Overlapped. status = PostQueuedCompletionStatus(ServerCompletionPort, 0, IoFileRep, (LPOVERLAPPED)pReq); ASSERT(status); } } // // Closes the file handle and frees all thread data if an error occured // in one of the following functions. // VOID ServerShutdownRequest(SReq *pReq) { DWORD status; RPC_STATUS rpcstatus; #ifdef DEBUG2 TCHAR Msg[MSG_SIZE]; ULONG bufSize = MSG_SIZE; // Keeps track of remaining size of buffer for _stprintf_s int nCharWritten; DbgMsgRecord(TEXT("-> ServerShutdownRequest\n")); #endif ASSERT(pReq != NULL); #ifdef DEBUG1 nServerReqs--; #endif // We are actually deleting a request, pick a new one from the queue. FindAndActivateSReq(); // Stop impersonating if we are. // The first thing we do in handling a request is impersonating the client. if (pReq->bImpersonating) { rpcstatus = RpcRevertToSelf(); if (rpcstatus != RPC_S_OK) { AddToMessageLogProcFailureEEInfo(TEXT("ServerShutdownRequest: RpcRevertToSelf"), rpcstatus); } } // Complete or cancel the async call, depending on whether an error // has occurred. if (pReq->Status && !pReq->fCallInvalidated) { RpcAsyncAbortCall(pReq->Async, TRUE); } else { RpcAsyncCompleteCall(pReq->Async, &status); } // Check that hLocalFile has been initialized and that initialization // was successful. if (pReq->hLocalFile != NULL && pReq->hLocalFile != INVALID_HANDLE_VALUE) { status = CloseHandle(pReq->hLocalFile); ASSERT(status != 0); } if (pReq->LocalFileName != NULL) { AutoHeapFree(pReq->LocalFileName); } // Check if any of the counters need to be decremented // since we are removing the request. if (pReq->State == StateQueued) { CounterDecrement(pServerReqCounters[pReq->Pri]); #ifdef DEBUG2 nCharWritten = _stprintf_s(Msg, bufSize, TEXT("Decremented ServerReqCounters[%d]\n"), pReq->Pri); bufSize -= nCharWritten; DbgMsgRecord(Msg); #endif } if (pReq->State == StateActive) { CounterDecrement(pServerActiveReqCounters[pReq->Pri]); QueueHashDecrementCounter(ServerActiveReqHashCounters[pReq->Pri], pReq->pSID); #ifdef DEBUG2 nCharWritten = _stprintf_s(Msg, bufSize, TEXT("Decremented ServerActiveReqCounters[%d] and ServerActiveReqHashCounters[%d]\n"), pReq->Pri, pReq->Pri); bufSize -= nCharWritten; DbgMsgRecord(Msg); #endif #ifdef DEBUG1 QueueRemoveData(ServerActiveReqQueue, pReq); #endif } if (pReq->hTokenHandle != NULL) { status = CloseHandle(pReq->hTokenHandle); ASSERT(status != NULL); } if (pReq->pSID != NULL) { AutoHeapFree(pReq->pSID); } if (pReq->Lock.DebugInfo) { DeleteCriticalSection(&pReq->Lock); } AutoHeapFree(pReq); #ifdef DEBUG2 DbgMsgRecord(TEXT("<- ServerShutdownRequest\n")); #endif } // // Handles a request taken off req queue. // Returns TRUE on sucess. // BOOL HandleSReq(tSReq *pReq) { #ifndef NO_SEC // We need to impersonate the user that has issued the // remote call. // We want to impersonate as soon as possible to minimise // the amount of resources that can be consumed by an attack. if (ImpersonateLoggedOnUser(pReq->hTokenHandle) == 0) { pReq->Status = GetLastError(); ServerShutdownRequest(pReq); AddToMessageLogProcFailure(TEXT("HandleReq: ImpersonateLoggedOnUser"), GetLastError()); return FALSE; } pReq->bImpersonating = TRUE; #endif // Attempt to open the local file. if ((pReq->hLocalFile = CreateFile(pReq->LocalFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL)) == INVALID_HANDLE_VALUE) { pReq->Status = GetLastError(); ServerShutdownRequest(pReq); AddToMessageLogProcFailure(TEXT("HandleReq: CreateFile"), GetLastError()); return FALSE; } #ifndef NO_SEC // We need to stop impersonating before putting this request back into // a queue or quitting. if (RevertToSelf() == 0) { AddToMessageLogProcFailure(TEXT("HandleReq: RevertToSelf"), GetLastError()); } pReq->bImpersonating = FALSE; #endif // Initialize the request fileds for throtteling the IO pReq->FileOl.Offset = 0; pReq->FileOl.OffsetHigh = 0; pReq->FileOl.hEvent = NULL; pReq->Async->u.IOC.dwCompletionKey = IoPipe; pReq->Async->u.IOC.lpOverlapped = (LPOVERLAPPED) pReq; pReq->bLastDataPushIssued = FALSE; pReq->bReadsDone = FALSE; pReq->bNullPush = FALSE; pReq->Async->Flags = RPC_C_NOTIFY_ON_SEND_COMPLETE; pReq->Async->UserInfo = pReq; pReq->Async->NotificationType = RpcNotificationTypeIoc; pReq->Async->u.IOC.hIOPort = ServerCompletionPort; // Link this file to the client requests's IO completion port: if ((ServerCompletionPort = CreateIoCompletionPort (pReq->hLocalFile, ServerCompletionPort, IoFile, 0)) == NULL) { AddToMessageLogProcFailure(TEXT("HandleActiveReq: CreateIoCompletionPort"), GetLastError()); return FALSE; } pReq->bReadOutstanding = FALSE; pReq->bPushOutstanding = FALSE; pReq->bBuf = FALSE; // Init the critsec. if (InitializeCriticalSectionAndSpinCount(&pReq->Lock, 10) == 0) { AddToMessageLogProcFailure(TEXT("HandleActiveReq: InitializeCriticalSectionAndSpinCount"), GetLastError()); return FALSE; } return TRUE; } // // Handles a request taken off active req queue // VOID SServiceRequests(VOID) { tSReq *pReq; #ifdef DEBUG2 TCHAR Msg[MSG_SIZE]; ULONG bufSize = MSG_SIZE; // Keeps track of remaining size of buffer for _stprintf_s int nCharWritten; #endif DWORD dwNumberOfBytesTransferred; DWORD dwCompletionKey; OVERLAPPED *lpOverlapped; ActionType Action = Wait; while(TRUE) { // // Read data from file. // if (Action == Read) { EnterCriticalSection(&pReq->Lock); ASSERT(!pReq->bBuf); ASSERT(!pReq->bReadOutstanding); // We did not read anything yet. pReq->cbRead = 0; pReq->bReadOutstanding = TRUE; #ifdef DEBUG2 nCharWritten = _stprintf_s(Msg, bufSize, TEXT("THREAD %d: SServiceRequests: reading file for req %p\n"), GetCurrentThreadId(), pReq); bufSize -= nCharWritten; DbgMsgRecord(Msg); #endif if(!ReadFile(pReq->hLocalFile, pReq->pbReadBuf, PUSH_BUFSIZE, &pReq->cbRead, &pReq->FileOl)) { if (GetLastError() != ERROR_IO_PENDING) { AddToMessageLogProcFailure(TEXT("HandleActiveSReq: WriteFile"), GetLastError()); pReq->Status = GetLastError(); LeaveCriticalSection(&pReq->Lock); ServerShutdownRequest(pReq); Action = Wait; } } Action = Wait; LeaveCriticalSection(&pReq->Lock); } // // Push the data to the client. // else if (Action == Push) { EnterCriticalSection(&pReq->Lock); #ifdef DEBUG2 nCharWritten = _stprintf_s(Msg, bufSize, TEXT("THREAD %d: SServiceRequests: pushing a buffer for req %p\n"), GetCurrentThreadId(), pReq); bufSize -= nCharWritten; DbgMsgRecord(Msg); #endif // Doing a regular Push for the data read from the file. if (!pReq->bNullPush) { ASSERT(!pReq->bReadOutstanding); ASSERT(!pReq->bPushOutstanding); ASSERT(pReq->bBuf); pReq->bPushOutstanding = TRUE; pReq->Status = ((WINAPI_MY_PIPE_PUSH) pReq->OutPipe->push)(pReq->OutPipe->state, (char *)pReq->pbReadBuf, pReq->cbRead); pReq->bBuf = FALSE; if(pReq->Status != RPC_S_OK) { pReq->bReadsDone = TRUE; pReq->bPushOutstanding = FALSE; pReq->fCallInvalidated = TRUE; if (pReq->bReadOutstanding == FALSE) { LeaveCriticalSection(&pReq->Lock); ServerShutdownRequest(pReq); Action = Wait; } else LeaveCriticalSection(&pReq->Lock); } else { if (!pReq->bReadsDone) Action = Read; else { Action = Wait; pReq->bLastDataPushIssued = TRUE; } LeaveCriticalSection(&pReq->Lock); } } // Doing a "NULL" push to signal the end of the pipe out-stream. else { ASSERT(!pReq->bReadOutstanding); ASSERT(!pReq->bPushOutstanding); ASSERT(!pReq->bBuf); pReq->bPushOutstanding = TRUE; WINAPI_MY_PIPE_PUSH pPush = (WINAPI_MY_PIPE_PUSH) pReq->OutPipe->push; pReq->Status = pPush(pReq->OutPipe->state, NULL, 0); if(pReq->Status != RPC_S_OK) { pReq->fCallInvalidated = TRUE; LeaveCriticalSection(&pReq->Lock); ServerShutdownRequest(pReq); Action = Wait; } else { Action = Wait; LeaveCriticalSection(&pReq->Lock); } } } // // Wait on the completion port. // else if (Action == Wait) { InterlockedIncrement(&nThreadsAtServerCompletionPort); ASSERT(nThreadsAtServerCompletionPort >= 0); #ifdef DEBUG2 nCharWritten = _stprintf_s(Msg, bufSize, TEXT("THREAD %d: SServiceRequests: waiting on a completion port\n"), GetCurrentThreadId()); bufSize -= nCharWritten; DbgMsgRecord(Msg); #endif if (!GetQueuedCompletionStatus(ServerCompletionPort, &dwNumberOfBytesTransferred, (PULONG_PTR)&dwCompletionKey, &lpOverlapped, ServerCompletionPortTimeout)) { LONG nThreads = InterlockedDecrement(&nThreadsAtServerCompletionPort); if (GetLastError() == WAIT_TIMEOUT) { #ifdef DEBUG2 nCharWritten = _stprintf_s(Msg, bufSize, TEXT("THREAD %d: SServiceRequests: timed out waiting on a completion port\n"), GetCurrentThreadId()); bufSize -= nCharWritten; DbgMsgRecord(Msg); #endif if (nThreads != 0) { return; } else { continue; } } else { AddToMessageLogProcFailure(TEXT("SServiceRequests: GetQueuedCompletionStatus"), GetLastError()); Action = Wait; } } else { // If this is the last thread to come off a completion port, // spin up an extra worker thread. if (InterlockedDecrement(&nThreadsAtServerCompletionPort) == 0) { HANDLE hThread; ULONG ThreadIdentifier; DWORD status; if ((hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SServiceRequests, NULL, 0, &ThreadIdentifier)) == NULL) { // If creating a thread fails there is really nothing that we // we can do. Just continue. AddToMessageLogProcFailure(TEXT("SServiceRequests: CreateThread"), GetLastError()); } else { // Unless we close a handle to the thread, it will remain in the // system even after its execution has terminated. status = CloseHandle(hThread); ASSERT(status != 0); } } ASSERT(nThreadsAtServerCompletionPort >= 0); // // Received file IO completion. // if (dwCompletionKey == IoFile) { pReq = (SReq *) ((size_t)lpOverlapped - offsetof(SReq, FileOl)); #ifdef DEBUG2 nCharWritten = _stprintf_s(Msg, bufSize, TEXT("THREAD %d: SServiceRequests: completed File IO for req %p\n"), GetCurrentThreadId(), pReq); bufSize -= nCharWritten; DbgMsgRecord(Msg); #endif EnterCriticalSection(&pReq->Lock); pReq->cbRead = dwNumberOfBytesTransferred; ASSERT(pReq->bReadOutstanding); ASSERT(!pReq->bBuf); pReq->bReadOutstanding = FALSE; pReq->bBuf = TRUE; ASSERT(!pReq->bLastDataPushIssued); if(pReq->Status != RPC_S_OK) { LeaveCriticalSection(&pReq->Lock); ServerShutdownRequest(pReq); Action = Wait; } else { // If we read less then we asked, then EOF has been reached. if (pReq->cbRead != PUSH_BUFSIZE) { pReq->bReadsDone = TRUE; // If we read 0 bytes, then the previous data push has been // the last one. So the last data push has already been issued. if (pReq->cbRead == 0) { pReq->bLastDataPushIssued = TRUE; // If there are no outstanding pushes, we can do a NULL push. if (pReq->bPushOutstanding == FALSE) { pReq->bNullPush = TRUE; } } } pReq->FileOl.Offset += pReq->cbRead; // We have at most one outstanding push, since RPC runtime // guarantees proper notification if there are no more then // one push outstanding. if (pReq->bPushOutstanding == TRUE) Action = Wait; else Action = Push; LeaveCriticalSection(&pReq->Lock); } } // // Received pipe IO completion. // else if(dwCompletionKey == IoPipe) { #ifdef DEBUG2 nCharWritten = _stprintf_s(Msg, bufSize, TEXT("THREAD %d: SServiceRequests: completed Pipe IO for req %p\n"), GetCurrentThreadId(), pReq); bufSize -= nCharWritten; DbgMsgRecord(Msg); #endif pReq = (SReq *) lpOverlapped; EnterCriticalSection(&pReq->Lock); if (pReq->Async->Event != RpcSendComplete) { ASSERT(0); } ASSERT(pReq->bPushOutstanding); pReq->bPushOutstanding = FALSE; // The completion of the NULL push terminates the request. // The reuest is now handled. if (pReq->bNullPush) { LeaveCriticalSection(&pReq->Lock); ServerShutdownRequest(pReq); Action = Wait; } // This is a regular data push. else { // If there is a read outstanding, wait for it to complete // since we do not have any other data to push at present. if (pReq->bReadOutstanding) Action = Wait; // If there is a buffer to send, push it. else if (pReq->bBuf) Action = Push; // If the this is the completion of the last data push, then // we just need to do the NULL push. else if (pReq->bLastDataPushIssued) { Action = Push; pReq->bNullPush = TRUE; } else { /*ASSERT(0);*/Action = Wait; } LeaveCriticalSection(&pReq->Lock); } } // // Received an internal FileRep IO completion. // else if(dwCompletionKey == IoFileRep) { pReq = (SReq *) lpOverlapped; #ifdef DEBUG2 nCharWritten = _stprintf_s(Msg, bufSize, TEXT("THREAD %d: SServiceRequests: completed FileRep internal IO for req %p\n"), GetCurrentThreadId(), pReq); bufSize -= nCharWritten; DbgMsgRecord(Msg); #endif // This is a signal to handle a new request. // If the request can be activated, then handle it. if(HandleSReq(pReq)) { Action = Read; } // Otherwise, do event. else { Action = Wait; } } else { ASSERT(0); } } } else { ASSERT(0); } } } void s_RemoteReadAsyncPipe(PRPC_ASYNC_STATE pAsync, handle_t hFileRepClient, TCHAR FileName[128], ASYNC_CHAR_PIPE_TYPE *OutPipe) { int nReply = 1; unsigned long ecount = 0; SReq *pReq = NULL; #ifdef DEBUG2 TCHAR Msg[MSG_SIZE]; ULONG bufSize = MSG_SIZE; // Keeps track of remaining size of buffer for _stprintf_s int nCharWritten; DbgMsgRecord(TEXT("-> s_RemoteReadAsyncPipe\n")); #endif if((pReq = (SReq *) AutoHeapAlloc(sizeof(SReq))) == NULL) { AddRpcEEInfoAndRaiseException(ERROR_OUTOFMEMORY, TEXT("RequestFile: AutoHeapAlloc failed")); return; } // Set pReq' fields to NULL so that we will know // in ServerShutdownRequest which ones have been initialized. pReq->hFileRepClient = hFileRepClient; pReq->hTokenHandle = NULL; pReq->hLocalFile = NULL; pReq->bImpersonating = FALSE; pReq->Pri = 0; pReq->State = StateArrived; pReq->pSID = NULL; pReq->Status = 0; pReq->Lock.DebugInfo = NULL; // The out-pipe we use to pull data from the server. pReq->OutPipe = OutPipe; // The async handle for the call to RemoteOpen. pReq->Async = pAsync; pReq->fCallInvalidated = FALSE; #ifdef DEBUG1 nServerReqs++; #endif if ((pReq->LocalFileName = (LPTSTR) AutoHeapAlloc((_tcslen(FileName)+1) * sizeof(TCHAR))) == NULL) { pReq->Status = GetLastError(); ServerShutdownRequest(pReq); AddRpcEEInfoAndRaiseException(ERROR_OUTOFMEMORY, TEXT("RequestFile: AutoHeapAlloc failed")); return; } CopyMemory(pReq->LocalFileName, FileName, (_tcslen(FileName)+1) * sizeof(TCHAR)); // // Check that we are not exceeding the bound on the number // of concurrent requests for this user's priority group. // And update the number of such requests. // #ifndef NO_SEC RPC_STATUS rpcstatus; // Impersonate the caller so that we can get the caller's SID if ((rpcstatus = RpcImpersonateClient(pReq->hFileRepClient)) != RPC_S_OK) { pReq->Status = GetLastError(); ServerShutdownRequest(pReq); AddRpcEEInfoAndRaiseException(rpcstatus, TEXT("RequestFile: RpcImpersonateClient failed")); return; } pReq->bImpersonating = TRUE; // We need to write down the access token for the user so that // we can use it for impersonation later when the client binding handle // gets deallocated. if (OpenThreadToken(GetCurrentThread(), TOKEN_QUERY | TOKEN_IMPERSONATE, TRUE, &pReq->hTokenHandle) == 0) { pReq->Status = GetLastError(); ServerShutdownRequest(pReq); AddRpcEEInfoAndRaiseException(GetLastError(), TEXT("RequestFile: OpenThreadToken failed")); return; } // Determine current user's priority level. This corresponds to the // priority level of the callee, since we are impersonating. pReq->Pri = GetCurrentUserPriority(); // Write down the SID for the user. pReq->pSID = GetUserSID(); // Stop impersonating. We got what we wanted. if ((rpcstatus = RpcRevertToSelf()) != RPC_S_OK) { pReq->bImpersonating = FALSE; pReq->Status = GetLastError(); ServerShutdownRequest(pReq); AddRpcEEInfoAndRaiseException(rpcstatus, TEXT("RequestFile: RpcRevertToSelf failed")); return; } pReq->bImpersonating = FALSE; #else pReq->Pri = 1; unsigned SidLength = GetLengthSid(pAnonSID); if ((pReq->pSID = AutoHeapAlloc(SidLength)) == NULL) { pReq->Status = GetLastError(); ServerShutdownRequest(pReq); AddRpcEEInfoAndRaiseException(GetLastError(), TEXT("RequestFile: AutoHeapAlloc failed")); return; } if (CopySid(SidLength, pReq->pSID, pAnonSID) == 0) { pReq->Status = GetLastError(); ServerShutdownRequest(pReq); AddRpcEEInfoAndRaiseException(GetLastError(), TEXT("RequestFile: CopySID failed")); return; } #endif #ifdef DEBUG2 nCharWritten = _stprintf_s(Msg, bufSize, TEXT("RequestFile: Pri=%d for req %p\n"), pReq->Pri, pReq); bufSize -= nCharWritten; DbgMsgRecord(Msg); #endif // If there are no workers ot handle the request, create one. HANDLE hThread; ULONG ThreadIdentifier; DWORD status; if (nThreadsAtServerCompletionPort < 1) { // Go service some requests, remember that you are // an RPC thread. if ((hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SServiceRequests, NULL, 0, &ThreadIdentifier)) == NULL) { pReq->Status = GetLastError(); ServerShutdownRequest(pReq); AddToMessageLogProcFailure(TEXT("SServiceRequests: CreateThread"), GetLastError()); return; } // Unless we close a handle to the thread, it will remain in the // system even after its execution has terminated. status = CloseHandle(hThread); ASSERT(status != 0); } // We need to place request onto the queue only after we know that there is someone // who will actually be able to pick it up. Thus, we need to create the thread first. // Increment the counter for the number of concurrent requests. if (!CounterIncrement(pServerReqCounters[pReq->Pri])) { pReq->Status = GetLastError(); ServerShutdownRequest(pReq); // We have to raise exception after deallocating the data // since there is a possibility that a client thread // will retry and will attempt to open this local file // while it's previous request is still holding a lock. // This has been actually hit on an overloaded system. AddRpcEEInfoAndRaiseException(RPC_S_SERVER_TOO_BUSY, TEXT("RequestFile: CounterIncrement failed")); return; } #ifdef DEBUG2 nCharWritten = _stprintf_s(Msg, bufSize, TEXT("Incremented ServerReqCounters[%d]\n"), pReq->Pri); bufSize -= nCharWritten; DbgMsgRecord(Msg); #endif pReq->State = StateQueued; #ifdef DEBUG2 nCharWritten = _stprintf_s(Msg, bufSize, TEXT("RequestFile: Put req %p onto Req queue %p\n"), pReq, ServerReqQueues[pReq->Pri]); bufSize -= nCharWritten; DbgMsgRecord(Msg); #endif // Place the request onto the queue. QueueAdd(ServerReqQueues[pReq->Pri], pReq, TRUE); // After this point the request can be deleted. Do not touch it. // Now if we can, find a queued request and activate it. FindAndActivateSReq(); #ifdef DEBUG2 DbgMsgRecord(TEXT("<- RequestFile\n")); #endif return; } // end FileRepServerProc.cpp