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.
 
 
 
 
 
 

428 lines
11 KiB

/*++
Copyright (c) 1997 Microsoft Corporation
Module Name:
rpcsvr.c
Abstract:
This file contains routines for starting and stopping RPC servers.
StartRpcServerListen
StopRpcServerListen
Author:
Vlad Sadovsky (vlads) 10-Jan-1997
Environment:
User Mode - Win32
Revision History:
26-Jan-1997 VladS created
--*/
#include "precomp.h"
//#define NOMINMAX
#include "stiexe.h"
#include <apiutil.h>
#include <stirpc.h>
#ifndef stirpc_ServerIfHandle
#define stirpc_ServerIfHandle stirpc_v2_0_s_ifspec
#endif
HANDLE g_hWiaServiceStarted = NULL;
RPC_STATUS RPC_ENTRY StiRpcSecurityCallBack(
RPC_IF_HANDLE hIF,
void *Context)
{
RPC_STATUS rpcStatus = RPC_S_ACCESS_DENIED;
WCHAR *pBinding = NULL;
WCHAR *pProtSeq = NULL;
RPC_AUTHZ_HANDLE hPrivs;
DWORD dwAuthenticationLevel;
rpcStatus = RpcBindingInqAuthClient(Context,
&hPrivs,
NULL,
&dwAuthenticationLevel,
NULL,
NULL);
if (rpcStatus != RPC_S_OK)
{
DBG_ERR(("STI Security: Error calling RpcBindingInqAuthClient"));
goto CleanUp;
}
//
// We require at least packet-level authentication with integrity checking
//
if (dwAuthenticationLevel < RPC_C_AUTHN_LEVEL_PKT_INTEGRITY)
{
DBG_ERR(("STI Security: Error, client attempting to use weak authentication."));
rpcStatus = RPC_S_ACCESS_DENIED;
goto CleanUp;
}
//
// Also, we only accept LRPC requests i.e. we only process requests from this machine,
// and we disallow any remote calls to us.
//
rpcStatus = RpcBindingToStringBindingW(Context, &pBinding);
if (rpcStatus == RPC_S_OK)
{
rpcStatus = RpcStringBindingParseW(pBinding,
NULL,
&pProtSeq,
NULL,
NULL,
NULL);
if (rpcStatus == RPC_S_OK)
{
if (lstrcmpiW(pProtSeq, L"ncalrpc") == 0)
{
DBG_TRC(("STI Security: We have a local client"));
rpcStatus = RPC_S_OK;
}
else
{
DBG_ERR(("STI Security: Error, remote client attempting to connect to STI RPC server"));
rpcStatus = RPC_S_ACCESS_DENIED;
}
}
else
{
DBG_ERR(("STI Security: Error 0x%08X calling RpcStringBindingParse", rpcStatus));
goto CleanUp;
}
}
else
{
DBG_ERR(("STI Security: Error 0x%08X calling RpcBindingToStringBinding", rpcStatus));
goto CleanUp;
}
CleanUp:
if (pBinding)
{
RpcStringFree(&pBinding);
pBinding = NULL;
}
if (pProtSeq)
{
RpcStringFree(&pProtSeq);
pProtSeq = NULL;
}
return rpcStatus;
}
RPC_STATUS
PrepareStiAcl(
ACL **ppAcl)
/*++
Routine Description:
This function prepares appropriate ACL for our RPC endpoint
Arguments:
ppAcl - points to ACL pointer we allocate and fill in.
The ACL is allocated from the process heap and stays allocated for the
lifetime of the process
Return Value:
NOERROR, or any GetLastError() codes.
--*/
{
RPC_STATUS RpcStatus = NOERROR;
SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;
PSID AuthenticatedUsers = NULL;
PSID BuiltinAdministrators = NULL;
ULONG AclSize;
if(!AllocateAndInitializeSid(&NtAuthority,
2,
SECURITY_BUILTIN_DOMAIN_RID,
DOMAIN_ALIAS_RID_ADMINS,
0,0,0,0,0,0,
&BuiltinAdministrators))
{
RpcStatus = GetLastError();
DBG_ERR(("PrepareStiAcl: failed to allocate SID for BuiltinAdministrators, RpcStatus = %d",
RpcStatus));
goto Cleanup;
}
if(!AllocateAndInitializeSid(&NtAuthority,
1,
SECURITY_AUTHENTICATED_USER_RID,
0,0,0,0,0,0, 0,
&AuthenticatedUsers))
{
RpcStatus = GetLastError();
DBG_ERR(("PrepareStiAcl: failed to allocate SID for AuthenticatedUsers, RpcStatus = %d",
RpcStatus));
goto Cleanup;
}
AclSize = sizeof(ACL) +
2 * (sizeof(ACCESS_ALLOWED_ACE) - sizeof(ULONG)) +
GetLengthSid(AuthenticatedUsers) +
GetLengthSid(BuiltinAdministrators);
*ppAcl = (ACL *)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, AclSize);
if(*ppAcl == NULL)
{
RpcStatus = GetLastError();
DBG_ERR(("PrepareStiAcl: failed to allocate ACL (LastError = %d)",
RpcStatus));
goto Cleanup;
}
if(!InitializeAcl(*ppAcl, AclSize, ACL_REVISION))
{
RpcStatus = GetLastError();
DBG_ERR(("PrepareStiAcl: failed to initialize ACL (LastError = %d)",
RpcStatus));
goto Cleanup;
}
if(!AddAccessAllowedAce(*ppAcl, ACL_REVISION,
SYNCHRONIZE | GENERIC_READ | GENERIC_WRITE,
AuthenticatedUsers))
{
RpcStatus = GetLastError();
DBG_ERR(("PrepareStiAcl: failed to allow AuthenticatedUsers (LastError = %d)",
RpcStatus));
goto Cleanup;
}
if(!AddAccessAllowedAce(*ppAcl, ACL_REVISION,
GENERIC_ALL,
BuiltinAdministrators))
{
RpcStatus = GetLastError();
DBG_ERR(("PrepareStiAcl: failed to allow BuiltinAdministrators (LastError = %d)",
RpcStatus));
goto Cleanup;
}
Cleanup:
if(RpcStatus != NOERROR)
{
if(AuthenticatedUsers)
{
FreeSid(AuthenticatedUsers);
}
if(BuiltinAdministrators)
{
FreeSid(BuiltinAdministrators);
}
if(*ppAcl)
{
HeapFree(GetProcessHeap(), 0, *ppAcl);
*ppAcl = NULL;
}
}
return RpcStatus;
}
RPC_STATUS
StartRpcServerListen(
VOID)
/*++
Routine Description:
This function starts RpcServerListen for this process.
RPC server only binds to LRPC transport , if STI becomes remotable
it will need to bind to named pipe and/or tcp/ip ( or netbios) transports
Shouldn't happen though, since WIA will be the remotable part, while STI will
be local to the machine.
Arguments:
Return Value:
NERR_Success, or any RPC error codes that can be returned from
RpcServerUnregisterIf.
--*/
{
DBG_FN(StartRpcServerListen);
RPC_STATUS RpcStatus;
SECURITY_DESCRIPTOR SecurityDescriptor;
ACL *pAcl = NULL;
// prepare our ACL
RpcStatus = PrepareStiAcl(&pAcl);
if(pAcl == NULL) {
DBG_ERR(("StartRpcServerListen: PrepareStiAcl() returned RpcStatus=0x%X", RpcStatus));
return RpcStatus;
}
// Give access to everybody
InitializeSecurityDescriptor(&SecurityDescriptor, SECURITY_DESCRIPTOR_REVISION);
SetSecurityDescriptorDacl(&SecurityDescriptor, TRUE, pAcl, FALSE);
//
// For now, ignore the second argument.
//
RpcStatus = RpcServerUseProtseqEp((RPC_STRING)STI_LRPC_SEQ,
STI_LRPC_MAX_REQS,
(RPC_STRING)STI_LRPC_ENDPOINT,
&SecurityDescriptor);
if ( NOERROR != RpcStatus) {
DBG_ERR(("StartRpcServerListen: RpcServerUseProtseqEp returned RpcStatus=0x%X",RpcStatus));
return RpcStatus;
}
//
// Add interface by using implicit handle, generated by MIDL
//
RpcStatus = RpcServerRegisterIfEx(stirpc_ServerIfHandle, //RpcInterface
0, //MgrUuid
0, //MgrEpv
RPC_IF_ALLOW_SECURE_ONLY,
RPC_C_LISTEN_MAX_CALLS_DEFAULT,
StiRpcSecurityCallBack);
if ( NOERROR != RpcStatus) {
DBG_ERR(("StartRpcServerListen: RpcServerRegisterIf returned RpcStatus=0x%X",RpcStatus));
return RpcStatus;
}
//
// Now initiate servicing
//
RpcStatus = RpcServerListen(STI_LRPC_THREADS, // Minimum # of listen threads
STI_LRPC_MAX_REQS, // Concurrency
TRUE); // Immediate return
if ( NOERROR != RpcStatus) {
DBG_ERR(("StartRpcServerListen: RpcServerListen returned RpcStatus=0x%X",RpcStatus));
return RpcStatus;
}
//
//
//
SECURITY_ATTRIBUTES sa = { sizeof(sa), FALSE, NULL };
// allocate appropriate security attributes for the named event we
// use to learn about WIA service startup
if(!ConvertStringSecurityDescriptorToSecurityDescriptor(TEXT("D:(A;;0x1f0003;;;SY)(A;;0x1f0003;;;LS)(A;;0x1f0003;;;LA)"),
SDDL_REVISION_1, &(sa.lpSecurityDescriptor), NULL))
{
DBG_ERR(("StartRpcServerListen failed to produce event security descriptor (Error %d)", GetLastError()));
return GetLastError();
}
g_hWiaServiceStarted = CreateEvent(&sa, FALSE, FALSE, TEXT("Global\\WiaServiceStarted"));
if(!g_hWiaServiceStarted) {
DBG_ERR(("StartRpcServerListen failed to produce event security descriptor (Error %d)", GetLastError()));
if(sa.lpSecurityDescriptor) LocalFree(sa.lpSecurityDescriptor);
return GetLastError();
}
if(!SetEvent(g_hWiaServiceStarted)) {
DBG_ERR(("StartRpcServerListen failed to set event (Error %d)", GetLastError()));
}
return (RpcStatus);
}
RPC_STATUS
StopRpcServerListen(
VOID
)
/*++
Routine Description:
Deletes the interface.
Arguments:
Return Value:
RPC_S_OK or any RPC error codes that can be returned from
RpcServerUnregisterIf.
--*/
{
RPC_STATUS RpcStatus;
EnterCriticalSection(&g_RpcEvent.cs);
if(g_RpcEvent.pAsync) {
RPC_STATUS status;
status = RpcAsyncAbortCall(g_RpcEvent.pAsync, RPC_S_CALL_CANCELLED);
if(status) {
DBG_ERR(("RpcAsyncAbortCall failed with error 0x%x", status));
}
g_RpcEvent.pAsync = NULL;
}
LeaveCriticalSection(&g_RpcEvent.cs);
RpcStatus = RpcServerUnregisterIf(stirpc_ServerIfHandle,
NULL, // MgrUuid
TRUE); // wait for calls to complete
// BUGBUG RPC server should stop only after all interfaces are unregistered. For now we
// only have one, so this is non-issue. When adding new interfaces to this RPC server, keep
// ref count on register/unregister
RpcStatus = RpcMgmtStopServerListening(0);
//
// wait for all RPC threads to go away.
//
if( RpcStatus == RPC_S_OK) {
RpcStatus = RpcMgmtWaitServerListen();
}
return (RpcStatus);
}