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.

499 lines
13 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. scbsm.cxx
  5. Abstract:
  6. This module implements a simplistic scheme to have a trusted system
  7. component issue a BroadcastSystemMessage when a network drive is added
  8. or deleted through the WNet APIs. This scheme guarantees that a spurious
  9. message is never sent; however, there are some situations in which a
  10. bona fide message can get lost or delayed. The real solution requires
  11. Plug and Play support from network providers.
  12. The following functions are in this file:
  13. ScInitBSM
  14. ScHandleBSMRequest
  15. ScGetNetworkDrives
  16. ScCreateBSMEventSD
  17. Author:
  18. Anirudh Sahni (anirudhs) 05-Jun-1996
  19. Environment:
  20. User Mode - Win32
  21. Notes:
  22. There is no architectural reason for this to be in the service controller.
  23. A more appropriate place would be the Plug and Play service.
  24. Revision History:
  25. 22-Oct-1998 jschwart
  26. Converted SCM to use NT thread pool APIs
  27. 05-Jun-1996 AnirudhS
  28. Created.
  29. --*/
  30. #include "precomp.hxx"
  31. #include <dbt.h> // BroadcastSystemMessage structures
  32. #include <winsvcp.h> // SC_BSM_EVENT_NAME
  33. #include <scseclib.h> // well-known SIDs
  34. #include "scbsm.h"
  35. //-------------------------------------------------------------------//
  36. // //
  37. // Constants and Macros //
  38. // //
  39. //-------------------------------------------------------------------//
  40. //-------------------------------------------------------------------//
  41. // //
  42. // Static global variables //
  43. // //
  44. //-------------------------------------------------------------------//
  45. //
  46. // Event that will be pulsed by the WNet APIs when they want a message
  47. // broadcast
  48. //
  49. HANDLE hBSMEvent;
  50. //
  51. // What the net drive bitmask was when we last broadcast (initially 0)
  52. //
  53. DWORD LastNetDrives;
  54. //
  55. // Work item handle
  56. //
  57. HANDLE g_hWorkitem;
  58. //-------------------------------------------------------------------//
  59. // //
  60. // Local function prototypes //
  61. // //
  62. //-------------------------------------------------------------------//
  63. BOOL
  64. ScCreateBSMEventSD(
  65. PSECURITY_DESCRIPTOR * SecurityDescriptor
  66. );
  67. VOID
  68. ScHandleBSMRequest(
  69. PVOID pContext,
  70. BOOLEAN dwWaitStatus
  71. );
  72. DWORD
  73. ScGetNetworkDrives(
  74. );
  75. //-------------------------------------------------------------------//
  76. // //
  77. // Functions //
  78. // //
  79. //-------------------------------------------------------------------//
  80. VOID
  81. ScInitBSM(
  82. )
  83. /*++
  84. Routine Description:
  85. This function performs initialization related to network drive arrival
  86. broadcasts.
  87. CODEWORK Should we fail service controller initialization if this fails?
  88. Event log the cause?
  89. Arguments:
  90. None
  91. Return Value:
  92. None
  93. --*/
  94. {
  95. NTSTATUS ntStatus;
  96. SECURITY_ATTRIBUTES EventAttrs = { sizeof(SECURITY_ATTRIBUTES), NULL, FALSE };
  97. //
  98. // Create the security descriptor for the event.
  99. // No-one else can wait for the event, but anyone can set it.
  100. //
  101. if (! ScCreateBSMEventSD(&EventAttrs.lpSecurityDescriptor))
  102. {
  103. SC_LOG(ERROR, "Couldn't create BSM event security descriptor, %lu\n",
  104. GetLastError());
  105. return;
  106. }
  107. //
  108. // Create the event that will be pulsed by the WNet APIs when they
  109. // want a message broadcast.
  110. //
  111. hBSMEvent = CreateEvent(
  112. &EventAttrs, // security attrs
  113. FALSE, // make this an auto-reset event
  114. FALSE, // initial state is nonsignaled
  115. SC_BSM_EVENT_NAME // name
  116. );
  117. if (hBSMEvent == NULL)
  118. {
  119. SC_LOG(ERROR, "Couldn't create BSM event, %lu\n", GetLastError());
  120. }
  121. LocalFree(EventAttrs.lpSecurityDescriptor);
  122. if (hBSMEvent == NULL)
  123. {
  124. return;
  125. }
  126. //
  127. // Add the work item that will be executed when this event is signaled.
  128. //
  129. ntStatus = RtlRegisterWait(&g_hWorkitem, // work item handle
  130. hBSMEvent, // waitable object handle
  131. ScHandleBSMRequest, // callback function
  132. 0, // parameter for callback function
  133. INFINITE, // infinite wait
  134. WT_EXECUTEONLYONCE); // one-time work item
  135. if (!NT_SUCCESS(ntStatus))
  136. {
  137. SC_LOG1(ERROR, "ScInitBSM: RtlRegisterWait failed 0x%x\n", ntStatus);
  138. CloseHandle(hBSMEvent);
  139. hBSMEvent = NULL;
  140. }
  141. }
  142. VOID
  143. ScHandleBSMRequest(
  144. PVOID pContext,
  145. BOOLEAN fWaitStatus
  146. )
  147. /*++
  148. Routine Description:
  149. This is the callback function executed when some process sets the BSM
  150. Request event.
  151. Arguments:
  152. Return Value:
  153. --*/
  154. {
  155. DWORD NetDrives;
  156. NTSTATUS ntStatus;
  157. DEV_BROADCAST_VOLUME dbv;
  158. LONG status;
  159. //
  160. // If fWaitStatus if TRUE, we're being signalled because of a timeout.
  161. // Since we registered with an infinite wait, this should NEVER happen
  162. //
  163. ASSERT(fWaitStatus == FALSE);
  164. SC_LOG0(BSM, "Handling a BSM request\n");
  165. //
  166. // Deregister the work item (we have to do this even if the
  167. // WT_EXECUTEONLYONCE flag is specified)
  168. //
  169. ntStatus = RtlDeregisterWait(g_hWorkitem);
  170. if (!NT_SUCCESS(ntStatus)) {
  171. SC_LOG1(ERROR,
  172. "ScHandleBSMRequest: RtlDeregisterWait FAILED %#x\n",
  173. ntStatus);
  174. }
  175. //
  176. // Keep broadcasting until the set of net drives stops changing
  177. //
  178. for (;;)
  179. {
  180. //
  181. // If we're shutting down, do nothing
  182. //
  183. if (ScShutdownInProgress)
  184. {
  185. return;
  186. }
  187. //
  188. // Get the current net drive bitmask and compare against the net
  189. // drive bitmask when we last broadcast
  190. //
  191. NetDrives = ScGetNetworkDrives();
  192. SC_LOG2(BSM, "Previous net drives: %#lx Now: %#lx\n",
  193. LastNetDrives, NetDrives);
  194. if (NetDrives == LastNetDrives)
  195. {
  196. break;
  197. }
  198. //
  199. // Broadcast about deleted volumes
  200. //
  201. dbv.dbcv_size = sizeof(dbv);
  202. dbv.dbcv_devicetype = DBT_DEVTYP_VOLUME;
  203. dbv.dbcv_reserved = 0;
  204. dbv.dbcv_unitmask = LastNetDrives & ~NetDrives;
  205. dbv.dbcv_flags = DBTF_NET;
  206. if (dbv.dbcv_unitmask != 0)
  207. {
  208. DWORD dwRec = BSM_APPLICATIONS | BSM_ALLDESKTOPS;
  209. SC_LOG0(BSM, "Calling BroadcastSystemMessage...\n");
  210. status = BroadcastSystemMessage(
  211. BSF_FORCEIFHUNG | BSF_NOHANG | BSF_NOTIMEOUTIFNOTHUNG,
  212. &dwRec,
  213. WM_DEVICECHANGE,
  214. (WPARAM) DBT_DEVICEREMOVECOMPLETE,
  215. (LPARAM)(DEV_BROADCAST_HDR*)(&dbv)
  216. );
  217. SC_LOG0(BSM, "... returned\n");
  218. if (status <= 0)
  219. {
  220. SC_LOG2(ERROR, "BSM for deleted volumes %#lx FAILED, returned %ld\n",
  221. dbv.dbcv_unitmask, status);
  222. }
  223. }
  224. //
  225. // Broadcast about added volumes
  226. //
  227. dbv.dbcv_unitmask = NetDrives & ~LastNetDrives;
  228. if (dbv.dbcv_unitmask != 0)
  229. {
  230. DWORD dwRec = BSM_APPLICATIONS | BSM_ALLDESKTOPS;
  231. SC_LOG0(BSM, "Calling BroadcastSystemMessage...\n");
  232. status = BroadcastSystemMessage(
  233. BSF_FORCEIFHUNG | BSF_NOHANG | BSF_NOTIMEOUTIFNOTHUNG,
  234. &dwRec,
  235. WM_DEVICECHANGE,
  236. (WPARAM) DBT_DEVICEARRIVAL,
  237. (LPARAM)(DEV_BROADCAST_HDR*)(&dbv)
  238. );
  239. SC_LOG0(BSM, "... returned\n");
  240. if (status <= 0)
  241. {
  242. SC_LOG2(ERROR, "BSM for added volumes %#lx FAILED, returned %ld\n",
  243. dbv.dbcv_unitmask, status);
  244. }
  245. }
  246. //
  247. // Remember the drive set that we last broadcast about
  248. //
  249. LastNetDrives = NetDrives;
  250. //
  251. // Go around the loop again to detect changes that may have occurred
  252. // while we were broadcasting
  253. //
  254. }
  255. //
  256. // Add this work item back to the queue
  257. //
  258. SC_LOG0(BSM, "Re-waiting on BSM event\n");
  259. ntStatus = RtlRegisterWait(&g_hWorkitem, // work item handle
  260. hBSMEvent, // waitable object handle
  261. ScHandleBSMRequest, // callback function
  262. 0, // parameter for callback function
  263. INFINITE, // infinite wait
  264. WT_EXECUTEONLYONCE); // one-time work item
  265. if (!NT_SUCCESS(ntStatus))
  266. {
  267. SC_LOG1(ERROR, "ScInitBSM: RtlRegisterWait failed 0x%x\n", ntStatus);
  268. // CloseHandle(hBSMRequest);
  269. // hBSMRequest = NULL;
  270. // BUGBUG No more events will be processed. Event log this?
  271. }
  272. return;
  273. }
  274. DWORD
  275. ScGetNetworkDrives(
  276. )
  277. /*++
  278. Routine Description:
  279. Returns a drive bitmask similar to GetLogicalDrives, but including
  280. only the network drives.
  281. Arguments:
  282. Return Value:
  283. --*/
  284. {
  285. WCHAR wszDrive[] = L" :\\";
  286. DWORD dwMask = 0;
  287. DWORD dwCurrDrive = 1;
  288. // For all the drives
  289. for (wszDrive[0] = L'A'; wszDrive[0] <= L'Z'; wszDrive[0]++, dwCurrDrive <<= 1)
  290. {
  291. if (GetDriveType(wszDrive) == DRIVE_REMOTE)
  292. {
  293. dwMask |= dwCurrDrive;
  294. }
  295. }
  296. return dwMask;
  297. }
  298. BOOL
  299. ScCreateBSMEventSD(
  300. PSECURITY_DESCRIPTOR * SecurityDescriptor
  301. )
  302. /*++
  303. Routine Description:
  304. This function creates a security descriptor for the BSM request event.
  305. It grants EVENT_ALL_ACCESS to local system and EVENT_MODIFY_STATE access
  306. to the rest of the world. This prevents principals other than local
  307. system from waiting for the event.
  308. Arguments:
  309. SecurityDescriptor - Receives a pointer to the new security descriptor.
  310. Should be freed with LocalFree.
  311. Return Value:
  312. TRUE - success
  313. FALSE - failure, use GetLastError
  314. History:
  315. AnirudhS 06-Jun-1996 Adapted from LsapAuCreatePortSD in auloop.c
  316. --*/
  317. {
  318. NTSTATUS Status;
  319. ULONG AclLength;
  320. PACL EventDacl;
  321. //
  322. // Allocate a buffer to contain the SD followed by the DACL
  323. // Note, the well-known SIDs are expected to have been created
  324. // by this time
  325. //
  326. AclLength = (ULONG) sizeof(ACL) +
  327. (2 * ((ULONG)sizeof(ACCESS_ALLOWED_ACE) - sizeof(ULONG))) +
  328. RtlLengthSid( LocalSystemSid ) +
  329. RtlLengthSid( WorldSid );
  330. *SecurityDescriptor = (PSECURITY_DESCRIPTOR)
  331. LocalAlloc( 0, SECURITY_DESCRIPTOR_MIN_LENGTH + AclLength );
  332. if (*SecurityDescriptor == NULL) {
  333. return FALSE;
  334. }
  335. EventDacl = (PACL) ((BYTE*)(*SecurityDescriptor) + SECURITY_DESCRIPTOR_MIN_LENGTH);
  336. //
  337. // Set up a default ACL
  338. //
  339. // Public: WORLD:EVENT_MODIFY_STATE, SYSTEM:all
  340. Status = RtlCreateAcl( EventDacl, AclLength, ACL_REVISION2);
  341. //
  342. // WORLD access
  343. //
  344. Status = RtlAddAccessAllowedAce (
  345. EventDacl,
  346. ACL_REVISION2,
  347. EVENT_MODIFY_STATE,
  348. WorldSid
  349. );
  350. SC_ASSERT( NT_SUCCESS(Status) );
  351. //
  352. // SYSTEM access
  353. //
  354. Status = RtlAddAccessAllowedAce (
  355. EventDacl,
  356. ACL_REVISION2,
  357. EVENT_ALL_ACCESS,
  358. LocalSystemSid
  359. );
  360. SC_ASSERT( NT_SUCCESS(Status) );
  361. //
  362. // Now initialize security descriptors
  363. // that export this protection
  364. //
  365. Status = RtlCreateSecurityDescriptor(
  366. *SecurityDescriptor,
  367. SECURITY_DESCRIPTOR_REVISION1
  368. );
  369. SC_ASSERT( NT_SUCCESS(Status) );
  370. Status = RtlSetDaclSecurityDescriptor(
  371. *SecurityDescriptor,
  372. TRUE, // DaclPresent
  373. EventDacl,
  374. FALSE // DaclDefaulted
  375. );
  376. SC_ASSERT( NT_SUCCESS(Status) );
  377. return TRUE;
  378. }