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.

381 lines
12 KiB

  1. //+-----------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (c) Microsoft Corporation 1991 - 1992
  6. //
  7. // File: scmsvc.cxx
  8. //
  9. // Contents: Initialization for win32 service controller.
  10. //
  11. // History: 14-Jul-92 CarlH Created.
  12. // 31-Dec-93 ErikGav Chicago port
  13. // 25-Aug-99 a-sergiv Fixed ScmCreatedEvent vulnerability
  14. //
  15. //------------------------------------------------------------------------
  16. #include "act.hxx"
  17. #include <sddl.h>
  18. #ifdef DFSACTIVATION
  19. HANDLE ghDfs = 0;
  20. #endif
  21. #define SCM_CREATED_EVENT TEXT("ScmCreatedEvent")
  22. DECLARE_INFOLEVEL(Cairole);
  23. SC_HANDLE g_hServiceController = 0;
  24. PSID psidMySid = NULL;
  25. HANDLE g_hVistaEvent = NULL;
  26. //+-------------------------------------------------------------------------
  27. //
  28. // Function: InitializeVistaEventIfNeeded
  29. //
  30. // Synopsis: Checks to see if vista (vis. studio analyzer) events are
  31. // enabled, and if so creates a named event. Somebody looks at this
  32. // event I presume, but creating the event is the end of our
  33. // responsibility for it. Once created we keep it around forever. Also,
  34. // this is a non-essential operation from our perspective, hence the
  35. // void return value.
  36. //
  37. // Arguments: None.
  38. //
  39. // Returns: void
  40. //
  41. //--------------------------------------------------------------------------
  42. void InitializeVistaEventIfNeeded()
  43. {
  44. // Create a named event for Vista to toggle event logging
  45. ASSERT(!g_hVistaEvent);
  46. LONG lResult;
  47. WCHAR wszValue[128];
  48. LONG lBufSize = sizeof(wszValue);
  49. ZeroMemory(wszValue, sizeof(wszValue));
  50. lResult = RegQueryValue(
  51. HKEY_CLASSES_ROOT,
  52. L"CLSID\\{6C736DB0-BD94-11D0-8A23-00AA00B58E10}\\EnableEvents",
  53. wszValue,
  54. &lBufSize);
  55. if ((lResult != ERROR_SUCCESS) || lstrcmp(wszValue, L"1"))
  56. return;
  57. //
  58. // Create security descriptor that grants the follow privs:
  59. //
  60. // EVENT_QUERY_STATE|EVENT_MODIFY_STATE|SYNCHRONIZE|READ_CONTROL
  61. //
  62. // to Everyone. Dang me if this isn't easier than writing code! :)
  63. //
  64. const WCHAR wszStringSD[] =
  65. SDDL_DACL L":" L"(" SDDL_ACCESS_ALLOWED L";;0x00120003;;;" SDDL_EVERYONE L")";
  66. //
  67. // Turn that into a security descriptor.
  68. //
  69. PSECURITY_DESCRIPTOR psd;
  70. BOOL fRet = ConvertStringSecurityDescriptorToSecurityDescriptor(wszStringSD,
  71. SDDL_REVISION,
  72. &psd,
  73. NULL);
  74. ASSERT(fRet && "ConvertStringSecurityDescriptorToSecurityDescriptor failed!");
  75. if (fRet)
  76. {
  77. SECURITY_ATTRIBUTES sa;
  78. sa.nLength = sizeof(sa);
  79. sa.bInheritHandle = FALSE;
  80. sa.lpSecurityDescriptor = psd;
  81. // The toggle event, which is signaled by LEC and checked by all.
  82. // The handle never closes during the process
  83. g_hVistaEvent = CreateEvent(
  84. &sa, /* Security */
  85. TRUE, /* Manual reset */
  86. FALSE, /* InitialState is non-signaled */
  87. L"MSFT.VSA.IEC.STATUS.6c736db0" /* Name */
  88. );
  89. // do not care if it succeeded or not
  90. LocalFree(psd);
  91. }
  92. return;
  93. }
  94. //+-------------------------------------------------------------------------
  95. //
  96. // Function: InitializeSCMBeforeListen
  97. //
  98. // Synopsis: Initializes OLE side of rpcss. Put things in here that do
  99. // not depend on RPC being initialized, etc.
  100. //
  101. // Arguments: None.
  102. //
  103. // Returns: Status of initialization. Note that this function is a bit
  104. // weak on cleanup in the face of errors, but this is okay since if this
  105. // function fails, RPCSS will not start.
  106. //
  107. //--------------------------------------------------------------------------
  108. DWORD
  109. InitializeSCMBeforeListen( void )
  110. {
  111. LONG Status;
  112. SCODE sc;
  113. RPC_STATUS rs;
  114. SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;
  115. UpdateState(SERVICE_START_PENDING);
  116. Status = RtlInitializeCriticalSection(&gTokenCS);
  117. if (!NT_SUCCESS(Status))
  118. return Status;
  119. // Allocate locks
  120. Status = OR_NOMEM;
  121. gpClientLock = new CSharedLock(Status);
  122. if (OR_OK != Status)
  123. return(Status);
  124. Status = OR_NOMEM;
  125. gpServerLock = new CSharedLock(Status);
  126. if (OR_OK != Status)
  127. return(Status);
  128. Status = OR_NOMEM;
  129. gpIPCheckLock = new CSharedLock(Status);
  130. if (OR_OK != Status)
  131. return(Status);
  132. g_hServiceController = OpenSCManager(NULL, NULL, GENERIC_EXECUTE);
  133. if (!g_hServiceController)
  134. return GetLastError();
  135. // Init random number generator
  136. if (!gRNG.Initialize())
  137. return (OR_NOMEM);
  138. //
  139. // Get my sid
  140. // This is simplified under the assumption that SCM runs as LocalSystem.
  141. // We should remove this code when we incorporate OLE service into the
  142. // Service Control Manager since this becomes duplicated code then.
  143. //
  144. Status = RtlAllocateAndInitializeSid (
  145. &NtAuthority,
  146. 1,
  147. SECURITY_LOCAL_SYSTEM_RID,
  148. 0, 0, 0, 0, 0, 0, 0,
  149. &psidMySid
  150. );
  151. if (!NT_SUCCESS(Status))
  152. return Status;
  153. UpdateState(SERVICE_START_PENDING);
  154. HRESULT hr = S_OK;
  155. hr = InitSCMRegistry();
  156. if (FAILED(hr))
  157. return ERROR_NOT_ENOUGH_MEMORY;
  158. //Initialize runas cache
  159. InitRunAsCache(); // returns void
  160. gpClassLock = new CSharedLock(Status);
  161. if (!gpClassLock)
  162. return ERROR_NOT_ENOUGH_MEMORY;
  163. gpProcessLock = new CSharedLock(Status);
  164. if (!gpProcessLock)
  165. return ERROR_NOT_ENOUGH_MEMORY;
  166. gpProcessListLock = new CSharedLock(Status);
  167. if (!gpProcessListLock)
  168. return ERROR_NOT_ENOUGH_MEMORY;
  169. gpClassTable = new CServerTable(Status, ENTRY_TYPE_CLASS);
  170. if (!gpClassTable)
  171. return ERROR_NOT_ENOUGH_MEMORY;
  172. gpProcessTable = new CServerTable(Status, ENTRY_TYPE_PROCESS);
  173. if (!gpProcessTable)
  174. return ERROR_NOT_ENOUGH_MEMORY;
  175. gpSurrogateList = new CSurrogateList();
  176. if (!gpSurrogateList)
  177. return ERROR_NOT_ENOUGH_MEMORY;
  178. gpRemoteMachineLock = new CSharedLock(Status);
  179. if (!gpRemoteMachineLock)
  180. return ERROR_NOT_ENOUGH_MEMORY;
  181. gpRemoteMachineList = new CRemoteMachineList();
  182. if (!gpRemoteMachineList)
  183. return ERROR_NOT_ENOUGH_MEMORY;
  184. gpNamedObjectTable = new CNamedObjectTable(Status);
  185. if (!gpNamedObjectTable || (Status != OR_OK))
  186. return ERROR_NOT_ENOUGH_MEMORY;
  187. UpdateState(SERVICE_START_PENDING);
  188. #ifdef DFSACTIVATION
  189. DfsOpen( &ghDfs );
  190. #endif
  191. return 0;
  192. }
  193. //+-------------------------------------------------------------------------
  194. //
  195. // Function: InitializeSCM
  196. //
  197. // Synopsis: Initializes OLE side of rpcss.
  198. //
  199. // Arguments: None.
  200. //
  201. // Returns: ERROR_SUCCESS
  202. //
  203. // (REVIEW: should we be returning an error whenever any of
  204. // the stuff in this function fails?)
  205. //
  206. //--------------------------------------------------------------------------
  207. DWORD
  208. InitializeSCM( void )
  209. {
  210. RPC_STATUS status;
  211. HRESULT hr;
  212. // start the RPC service
  213. hr = InitScmRot();
  214. if (FAILED(hr))
  215. return ERROR_NOT_ENOUGH_MEMORY;
  216. //
  217. // Note: some of these calls specify a callback function and some
  218. // don't. The ones that don't must be able to receive unauthenticated
  219. // calls (ie, our remoted interfaces).
  220. //
  221. status = RpcServerRegisterIfEx(ISCM_ServerIfHandle,
  222. NULL,
  223. NULL,
  224. 0,
  225. RPC_C_LISTEN_MAX_CALLS_DEFAULT,
  226. LocalInterfaceOnlySecCallback); // expected to be local only
  227. ASSERT((status == 0) && "RpcServerRegisterIfEx failed!");
  228. status = RpcServerRegisterIfEx(ISCMActivator_ServerIfHandle,
  229. NULL,
  230. NULL,
  231. 0,
  232. RPC_C_LISTEN_MAX_CALLS_DEFAULT,
  233. LocalInterfaceOnlySecCallback); // expected to be local only
  234. ASSERT((status == 0) && "RpcServerRegisterIfEx failed!");
  235. status = RpcServerRegisterIfEx(IMachineActivatorControl_ServerIfHandle,
  236. NULL,
  237. NULL,
  238. 0,
  239. RPC_C_LISTEN_MAX_CALLS_DEFAULT,
  240. LocalInterfaceOnlySecCallback); // expected to be local only
  241. ASSERT((status == 0) && "RpcServerRegisterIfEx failed!");
  242. status = RpcServerRegisterIfEx(_IActivation_ServerIfHandle,
  243. NULL,
  244. NULL,
  245. 0,
  246. RPC_C_LISTEN_MAX_CALLS_DEFAULT,
  247. NULL); // must be able to accept unauthenticated calls
  248. ASSERT((status == 0) && "RpcServerRegisterIf failed!");
  249. status = RpcServerRegisterIfEx(_IRemoteSCMActivator_ServerIfHandle,
  250. NULL,
  251. NULL,
  252. 0,
  253. RPC_C_LISTEN_MAX_CALLS_DEFAULT,
  254. NULL); // must be able to accept unauthenticated calls
  255. ASSERT((status == 0) && "RpcServerRegisterIf failed!");
  256. UpdateState(SERVICE_START_PENDING);
  257. return ERROR_SUCCESS;
  258. }
  259. void
  260. InitializeSCMAfterListen()
  261. {
  262. //
  263. // This is for the OLE apps which start during boot. They must wait for
  264. // rpcss to start before completing OLE calls that talk to rpcss.
  265. //
  266. // Need to do this work to make sure the DACL for the event doesn't have
  267. // WRITE_DAC and WRITE_OWNER on it.
  268. //
  269. // Rights quick reference:
  270. // EVENT_QUERY_STATE 0x00000001
  271. // EVENT_MODIFY_STATE 0x00000002
  272. // READ_CONTROL 0x00020000
  273. // WRITE_DAC 0x00040000
  274. // WRITE_OWNER 0x00080000
  275. // SYNCHRONIZE 0x00100000
  276. //
  277. // So:
  278. // Everyone gets EVENT_QUERY_STATE | READ_CONTROL | SYNCHRONIZE
  279. // I gets EVENT_MODIFY_STATE | WRITE_DAC | WRITE_OWNER
  280. //
  281. // Here we go... (this works because of C++ auto string concatenation)
  282. const WCHAR wszStringSD[] =
  283. SDDL_DACL L":" L"(" SDDL_ACCESS_ALLOWED L";;0x00120001;;;" SDDL_EVERYONE L")"
  284. L"(" SDDL_ACCESS_ALLOWED L";;0x001C0002;;;" SDDL_PERSONAL_SELF L")"
  285. ;
  286. //
  287. // Whew. Make that into a security descriptor.
  288. //
  289. PSECURITY_DESCRIPTOR psd;
  290. BOOL fRet = ConvertStringSecurityDescriptorToSecurityDescriptor(wszStringSD,
  291. SDDL_REVISION,
  292. &psd,
  293. NULL);
  294. ASSERT(fRet && "ConvertStringSecurityDescriptorToSecurityDescriptor failed!");
  295. if (fRet)
  296. {
  297. SECURITY_ATTRIBUTES sa;
  298. sa.nLength = sizeof(sa);
  299. sa.bInheritHandle = FALSE;
  300. sa.lpSecurityDescriptor = psd;
  301. // We leak this handle on purpose, so that other people can still find it by
  302. // name.
  303. HANDLE EventHandle = CreateEventT( &sa, TRUE, FALSE, SCM_CREATED_EVENT );
  304. if ( !EventHandle && GetLastError() == ERROR_ACCESS_DENIED )
  305. EventHandle = OpenEvent(EVENT_MODIFY_STATE, FALSE, SCM_CREATED_EVENT);
  306. if ( EventHandle )
  307. SetEvent( EventHandle );
  308. else
  309. ASSERT(0 && "Unable to get ScmCreatedEvent");
  310. LocalFree(psd);
  311. }
  312. // The vista event was originally being created inline in ServiceMain but
  313. // there is no point in creating it until we are ready for work.
  314. InitializeVistaEventIfNeeded();
  315. // Tell RPC to enable cleanup of idle connections. This function only needs to be
  316. // called one time.
  317. RPC_STATUS rpcstatus = RpcMgmtEnableIdleCleanup();
  318. ASSERT(rpcstatus == RPC_S_OK && "unexpected failure from RpcMgmtEnableIdleCleanup");
  319. // don't fail in free builds, this is an non-essential optimization
  320. return;
  321. }