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.

773 lines
20 KiB

  1. /*++
  2. Copyright (c) 1992 Microsoft Corporation
  3. Module Name:
  4. scopen.cxx
  5. Abstract:
  6. Functions for handling opening and closing of Service and
  7. ServiceController handles.
  8. ROpenSCManagerW
  9. ROpenServiceW
  10. RCloseServiceHandle
  11. SC_RPC_HANDLE_rundown
  12. ScCreateScManagerHandle
  13. ScCreateServiceHandle
  14. ScIsValidScManagerHandle
  15. ScIsValidServiceHandle
  16. ScIsValidScManagerOrServiceHandle
  17. Author:
  18. Dan Lafferty (danl) 20-Jan-1992
  19. Environment:
  20. User Mode - Win32
  21. Revision History:
  22. 20-Jan-1992 danl
  23. Created
  24. 10-Apr-1992 JohnRo
  25. Added ScIsValidServiceHandle().
  26. Export ScCreateServiceHandle() for RCreateService() too.
  27. 14-Apr-1992 JohnRo
  28. Added ScIsValidScManagerHandle().
  29. 22-Feb-1995 AnirudhS
  30. RCloseServiceHandle: Pass the handle, rather than the address of the
  31. handle, to the auditing routine.
  32. --*/
  33. #include "precomp.hxx"
  34. #include <stdlib.h> // wide character c runtimes.
  35. #include <tstr.h> // Unicode string macros
  36. #include "scsec.h" // ScAccessValidate
  37. #include "sclib.h" // ScIsValidServiceName
  38. //-------------------------------------------------------------------//
  39. // //
  40. // Local function prototypes //
  41. // //
  42. //-------------------------------------------------------------------//
  43. DWORD
  44. ScCreateScManagerHandle(
  45. IN LPWSTR DatabaseName,
  46. OUT LPSC_HANDLE_STRUCT *ContextHandle
  47. );
  48. //-------------------------------------------------------------------//
  49. // //
  50. // Functions //
  51. // //
  52. //-------------------------------------------------------------------//
  53. DWORD
  54. ROpenSCManagerW(
  55. IN LPWSTR lpMachineName,
  56. IN LPWSTR lpDatabaseName,
  57. IN DWORD dwDesiredAccess OPTIONAL,
  58. OUT LPSC_RPC_HANDLE lpScHandle
  59. )
  60. /*++
  61. Routine Description:
  62. Arguments:
  63. lpMachineName -
  64. lpDatabaseName -
  65. dwDesiredAccess -
  66. lpScHandle -
  67. Return Value:
  68. NO_ERROR - The operation was successful.
  69. ERROR_INVALID_NAME - lpDatabaseName is invalid
  70. ERROR_DATABASE_DOES_NOT_EXIST - Valid database name but database
  71. does not exist.
  72. ERROR_ACCESS_DENIED - dwDesiredAccess specifies accesses that are
  73. not granted to the client, or contains invalid bits.
  74. ERROR_NOT_ENOUGH_MEMORY - Could not allocated memory for context
  75. handle.
  76. --*/
  77. {
  78. LPSC_HANDLE_STRUCT scManagerHandle;
  79. DWORD error;
  80. LPWSTR RequestedDatabase = SERVICES_ACTIVE_DATABASEW;
  81. if (ScShutdownInProgress) {
  82. return(ERROR_SHUTDOWN_IN_PROGRESS);
  83. }
  84. //
  85. // This parameter got us to the server side and is uninteresting
  86. // once we get here.
  87. //
  88. UNREFERENCED_PARAMETER(lpMachineName);
  89. //
  90. // Validate specified database name
  91. //
  92. if (ARGUMENT_PRESENT(lpDatabaseName)) {
  93. if ((_wcsicmp(lpDatabaseName, SERVICES_ACTIVE_DATABASEW) != 0) &&
  94. (_wcsicmp(lpDatabaseName, SERVICES_FAILED_DATABASEW) != 0)) {
  95. return ERROR_INVALID_NAME;
  96. }
  97. else if ((_wcsicmp(lpDatabaseName, SERVICES_FAILED_DATABASEW) == 0)
  98. &&
  99. (TRUE))
  100. {
  101. //
  102. // CODEWORK: Actually implement a ServicesFailed database
  103. // at some point in the future and check for it
  104. // in place of the (TRUE) above.
  105. //
  106. //
  107. // ServicesFailed database does not exist
  108. //
  109. return ERROR_DATABASE_DOES_NOT_EXIST;
  110. }
  111. else {
  112. RequestedDatabase = lpDatabaseName;
  113. }
  114. }
  115. //
  116. // Allocate context handle structure and save the database name in it
  117. //
  118. if ((error = ScCreateScManagerHandle(
  119. RequestedDatabase,
  120. &scManagerHandle
  121. )) != NO_ERROR) {
  122. return error;
  123. }
  124. //
  125. // Make sure the desired access specified is valid and allowed to
  126. // the client. Save away the desired access in the handle structure.
  127. //
  128. if ((error = ScAccessValidate(
  129. scManagerHandle,
  130. (dwDesiredAccess | SC_MANAGER_CONNECT)
  131. )) != NO_ERROR) {
  132. SC_LOG(ERROR,"ROpenSCManagerW:ScAccessValidate Failed %u\n",
  133. error);
  134. (void) LocalFree(scManagerHandle);
  135. return error;
  136. }
  137. //
  138. // return the pointer to the handle struct as the context handle for
  139. // this open.
  140. //
  141. *lpScHandle = (SC_RPC_HANDLE)scManagerHandle;
  142. SC_LOG(HANDLE,"SC Manager Handle Opened 0x%08lx\n",*lpScHandle);
  143. return(NO_ERROR);
  144. }
  145. DWORD
  146. ROpenServiceW(
  147. IN SC_RPC_HANDLE hSCManager,
  148. IN LPWSTR lpServiceName,
  149. IN DWORD dwDesiredAccess,
  150. OUT LPSC_RPC_HANDLE phService
  151. )
  152. /*++
  153. Routine Description:
  154. Returns a handle to the service. This handle is actually a pointer
  155. to a data structure that contains a pointer to the service record.
  156. Arguments:
  157. hSCManager - This is a handle to this service controller. It is an
  158. RPC context handle, and has allowed the request to get this far.
  159. lpServiceName - This is a pointer to a string containing the name of
  160. the service
  161. dwDesiredAccess - This is an access mask that contains a description
  162. of the access that is desired for this service.
  163. phService - This is a pointer to the location where the handle to the
  164. service is to be placed.
  165. Return Value:
  166. NO_ERROR - The operation was successful.
  167. ERROR_INVALID_HANDLE - The specified ScManager handle is invalid.
  168. ERROR_SERVICE_DOES_NOT_EXIST - The specified service does not exist
  169. in the database.
  170. ERROR_NOT_ENOUGH_MEMORY - The memory allocation for the handle structure
  171. failed.
  172. ERROR_INVALID_NAME - Service name contains invalid character or
  173. name is too long.
  174. Note:
  175. --*/
  176. {
  177. LPSC_HANDLE_STRUCT serviceHandle;
  178. DWORD status;
  179. LPSERVICE_RECORD serviceRecord;
  180. if (ScShutdownInProgress) {
  181. return(ERROR_SHUTDOWN_IN_PROGRESS);
  182. }
  183. //
  184. // Check the handle.
  185. //
  186. if (!ScIsValidScManagerHandle(hSCManager))
  187. {
  188. return ERROR_INVALID_HANDLE;
  189. }
  190. //
  191. // Validate the format of the service name.
  192. //
  193. if (! ScIsValidServiceName(lpServiceName)) {
  194. return(ERROR_INVALID_NAME);
  195. }
  196. //
  197. // Find the service record in the database.
  198. //
  199. CServiceListSharedLock LLock;
  200. CServiceRecordExclusiveLock RLock;
  201. status = ScGetNamedServiceRecord(
  202. lpServiceName,
  203. &serviceRecord);
  204. if (status != NO_ERROR) {
  205. return(status);
  206. }
  207. //
  208. // Allocate context handle structure and save the service record
  209. // pointer in it.
  210. //
  211. if ((status = ScCreateServiceHandle(
  212. serviceRecord,
  213. &serviceHandle
  214. )) != NO_ERROR) {
  215. return(status);
  216. }
  217. //
  218. // Make sure the desired access specified is valid and allowed to
  219. // the client. Save away the desired access in the handle structure.
  220. //
  221. if ((status = ScAccessValidate(
  222. serviceHandle,
  223. dwDesiredAccess
  224. )) != NO_ERROR) {
  225. SC_LOG(ERROR,"ROpenServiceW:ScAccessValidate Failed %u\n",
  226. status);
  227. (void) LocalFree(serviceHandle);
  228. return(status);
  229. }
  230. //
  231. // Additional check is required if the SCManager points to a database
  232. // other than the active one. Execute accesses are not allowed.
  233. //
  234. if (_wcsicmp(
  235. ((LPSC_HANDLE_STRUCT)hSCManager)->Type.ScManagerObject.DatabaseName,
  236. SERVICES_ACTIVE_DATABASEW
  237. ) != 0) {
  238. if (dwDesiredAccess & MAXIMUM_ALLOWED) {
  239. //
  240. // MAXIMUM_ALLOWED is requested. Remove bits for execute accesses.
  241. //
  242. serviceHandle->AccessGranted &= ~(SERVICE_STOP |
  243. SERVICE_START |
  244. SERVICE_PAUSE_CONTINUE |
  245. SERVICE_INTERROGATE |
  246. SERVICE_USER_DEFINED_CONTROL);
  247. }
  248. else if ((serviceHandle->AccessGranted &
  249. (SERVICE_STOP |
  250. SERVICE_START |
  251. SERVICE_PAUSE_CONTINUE |
  252. SERVICE_INTERROGATE |
  253. SERVICE_USER_DEFINED_CONTROL)) != 0) {
  254. //
  255. // Deny access if any execute access is requested.
  256. //
  257. SC_LOG(
  258. SECURITY,
  259. "ROpenServiceW:Non-active database, execute accesses not allowed\n",
  260. 0
  261. );
  262. (void) LocalFree(serviceHandle);
  263. return(ERROR_ACCESS_DENIED);
  264. }
  265. }
  266. //
  267. // Increment the UseCount. The service record cannot be deleted
  268. // as long as the UseCount is greater than zero.
  269. //
  270. serviceRecord->UseCount++;
  271. SC_LOG2(USECOUNT, "ROpenServiceW: " FORMAT_LPWSTR
  272. " increment USECOUNT=%lu\n", serviceRecord->ServiceName, serviceRecord->UseCount);
  273. //
  274. // return the pointer to the handle struct as the handle for this
  275. // open.
  276. //
  277. *phService = (SC_RPC_HANDLE)serviceHandle;
  278. SC_LOG(HANDLE,"Service Handle Opened 0x%lx\n",*phService);
  279. return (NO_ERROR);
  280. }
  281. DWORD
  282. RCloseServiceHandle(
  283. IN OUT SC_RPC_HANDLE *phSCObject
  284. )
  285. /*++
  286. Routine Description:
  287. This function closes a handle to a service or to the service controller
  288. by freeing the data structure that the handle points to.
  289. Arguments:
  290. phSCObject - This is a pointer to a pointer to the context handle
  291. structure.
  292. Return Value:
  293. NO_ERROR - The operation was successful.
  294. ERROR_INVALID_HANDLE - The handle is invalid. It does not point to
  295. a recognizable structure.
  296. Note:
  297. --*/
  298. {
  299. NTSTATUS status;
  300. HLOCAL FreeStatus;
  301. UNICODE_STRING Subsystem;
  302. ULONG privileges[1];
  303. SC_HANDLE_TYPE HandleType;
  304. //
  305. // Check the handle
  306. //
  307. if (!ScIsValidScManagerOrServiceHandle(*phSCObject, &HandleType))
  308. {
  309. return ERROR_INVALID_HANDLE;
  310. }
  311. //
  312. // If it is a service handle being closed, decrement the use count.
  313. // If the count goes to zero, and the service is marked for deletion,
  314. // it will get deleted.
  315. //
  316. if (HandleType == SC_HANDLE_TYPE_SERVICE)
  317. {
  318. RPC_STATUS RpcStatus;
  319. BOOL fImpersonated = TRUE;
  320. {
  321. CServiceRecordExclusiveLock RLock;
  322. ScDecrementUseCountAndDelete(
  323. ((LPSC_HANDLE_STRUCT)*phSCObject)->Type.ScServiceObject.ServiceRecord);
  324. }
  325. //
  326. // Get Audit Privilege
  327. //
  328. privileges[0] = SE_AUDIT_PRIVILEGE;
  329. status = ScGetPrivilege( 1, privileges);
  330. if (status != NO_ERROR)
  331. {
  332. SC_LOG1(ERROR,
  333. "RCloseServiceHandle: ScGetPrivilege (Enable) failed: %d\n",
  334. status);
  335. }
  336. //
  337. // Generate the audit -- must be done as the user as per C2 requirements.
  338. //
  339. RpcStatus = RpcImpersonateClient(NULL);
  340. if (RpcStatus != RPC_S_OK)
  341. {
  342. //
  343. // Can't impersonate the user -- either RCloseServiceHandle was called
  344. // internally by the SCM or the impersonate failed for some other reason.
  345. // Do the audit as System instead.
  346. //
  347. fImpersonated = FALSE;
  348. }
  349. RtlInitUnicodeString(&Subsystem, SC_MANAGER_AUDIT_NAME);
  350. status = NtCloseObjectAuditAlarm(
  351. &Subsystem,
  352. *phSCObject,
  353. (BOOLEAN)((((LPSC_HANDLE_STRUCT)*phSCObject)->Flags
  354. & SC_HANDLE_GENERATE_ON_CLOSE) != 0));
  355. if (!NT_SUCCESS(status))
  356. {
  357. SC_LOG1(ERROR,
  358. "RCloseServiceHandle: NtCloseObjectAuditAlarm failed: %#lx\n",status);
  359. }
  360. if (fImpersonated)
  361. {
  362. RpcStatus = RpcRevertToSelf();
  363. if (RpcStatus != RPC_S_OK)
  364. {
  365. SC_LOG(ERROR,
  366. "RCloseServiceHandle: Fail to revert to self %08lx\n",
  367. RpcStatus);
  368. ScLogEvent(
  369. NEVENT_CALL_TO_FUNCTION_FAILED,
  370. SC_RPC_REVERT,
  371. RpcStatus);
  372. ASSERT(FALSE);
  373. //
  374. // Not much else we can do at this point -- keep on going.
  375. //
  376. }
  377. }
  378. ScReleasePrivilege();
  379. }
  380. //
  381. // Attempt to free the memory that the handle points to.
  382. //
  383. FreeStatus = LocalFree(*phSCObject);
  384. if (FreeStatus != NULL)
  385. {
  386. //
  387. // For some reason, the handle couldn't be freed. Therefore, the
  388. // best we can do to disable it is to remove the signature.
  389. //
  390. SC_LOG(ERROR,"RCloseServiceHandle:LocalFree Failed %d\n",GetLastError());
  391. ((LPSC_HANDLE_STRUCT)*phSCObject)->Signature = 0;
  392. }
  393. //
  394. // Tell RPC we are done with the context handle.
  395. //
  396. SC_LOG(HANDLE,"Handle Closed 0x%08lx\n",*phSCObject);
  397. *phSCObject = NULL;
  398. return(NO_ERROR);
  399. }
  400. VOID
  401. SC_RPC_HANDLE_rundown(
  402. SC_RPC_HANDLE scHandle
  403. )
  404. /*++
  405. Routine Description:
  406. This function is called by RPC when a connection is broken that had
  407. an outstanding context handle. The value of the context handle is
  408. passed in here so that we have an opportunity to clean up.
  409. Arguments:
  410. scHandle - This is the handle value of the context handle that is broken.
  411. Return Value:
  412. none.
  413. --*/
  414. {
  415. //
  416. // Close the handle.
  417. //
  418. RCloseServiceHandle(&scHandle);
  419. }
  420. DWORD
  421. ScCreateScManagerHandle(
  422. IN LPWSTR DatabaseName,
  423. OUT LPSC_HANDLE_STRUCT *ContextHandle
  424. )
  425. /*++
  426. Routine Description:
  427. This function allocates the memory for an SC Manager context handle
  428. structure, and initializes it.
  429. Arguments:
  430. DatabaseName - Supplies the name of the SC Manager database which the
  431. returned structure is a context of.
  432. ContextHandle - Returns a pointer to the context handle structure
  433. created.
  434. Return Value:
  435. NO_ERROR - The operation was successful.
  436. ERROR_NOT_ENOUGH_MEMORY - Memory allocation for the context handle
  437. structure failed.
  438. Note:
  439. The memory allocated by this routine should be freed with LocalFree.
  440. --*/
  441. {
  442. //
  443. // Allocate memory for the context handle structure, and database name.
  444. //
  445. *ContextHandle = (LPSC_HANDLE_STRUCT)LocalAlloc(
  446. LMEM_ZEROINIT,
  447. sizeof(SC_HANDLE_STRUCT) + WCSSIZE(DatabaseName));
  448. if (*ContextHandle == NULL) {
  449. SC_LOG(ERROR,"ScCreateScManagerHandle:LocalAlloc Failed %d\n",
  450. GetLastError());
  451. return ERROR_NOT_ENOUGH_MEMORY;
  452. }
  453. //
  454. // Initialize contents of the context handle structure, except for the
  455. // granted access which is figured out when the desired access is validated
  456. // later.
  457. //
  458. (*ContextHandle)->Signature = SC_SIGNATURE;
  459. (*ContextHandle)->Flags = 0;
  460. (*ContextHandle)->Type.ScManagerObject.DatabaseName =
  461. (LPWSTR) ((DWORD_PTR) *ContextHandle + sizeof(SC_HANDLE_STRUCT));
  462. wcscpy((*ContextHandle)->Type.ScManagerObject.DatabaseName, DatabaseName);
  463. return NO_ERROR;
  464. }
  465. BOOL
  466. ScIsValidScManagerHandle(
  467. IN SC_RPC_HANDLE hScManager
  468. )
  469. {
  470. LPSC_HANDLE_STRUCT serviceHandleStruct = (LPSC_HANDLE_STRUCT) hScManager;
  471. if (serviceHandleStruct == NULL) {
  472. return (FALSE); // Not valid.
  473. }
  474. if (serviceHandleStruct->Signature != SC_SIGNATURE) {
  475. return (FALSE); // Not valid.
  476. }
  477. return (TRUE);
  478. } // ScIsValidScManagerHandle
  479. DWORD
  480. ScCreateServiceHandle(
  481. IN LPSERVICE_RECORD ServiceRecord,
  482. OUT LPSC_HANDLE_STRUCT *ContextHandle
  483. )
  484. /*++
  485. Routine Description:
  486. This function allocates the memory for a service context handle
  487. structure, and initializes it.
  488. Arguments:
  489. ServiceRecord - Supplies a pointer to the service record which the
  490. returned structure is a context of.
  491. ContextHandle - Returns a pointer to the context handle structure
  492. created.
  493. Return Value:
  494. NO_ERROR - The operation was successful.
  495. ERROR_NOT_ENOUGH_MEMORY - Memory allocation for the context handle
  496. structure failed.
  497. Note:
  498. The memory allocated by this routine should be freed with LocalFree.
  499. --*/
  500. {
  501. //
  502. // Allocate memory for the context handle structure.
  503. //
  504. *ContextHandle = (LPSC_HANDLE_STRUCT)LocalAlloc(
  505. LMEM_ZEROINIT,
  506. sizeof(SC_HANDLE_STRUCT)
  507. );
  508. if (*ContextHandle == NULL) {
  509. SC_LOG(ERROR,"ScCreateServiceHandle:LocalAlloc Failed %d\n",
  510. GetLastError());
  511. return ERROR_NOT_ENOUGH_MEMORY;
  512. }
  513. //
  514. // Initialize contents of the context handle structure, except for the
  515. // granted access which is figured out when the desired access is validated
  516. // later.
  517. //
  518. (*ContextHandle)->Signature = SERVICE_SIGNATURE;
  519. (*ContextHandle)->Flags = 0;
  520. (*ContextHandle)->Type.ScServiceObject.ServiceRecord = ServiceRecord;
  521. SC_ASSERT( ScIsValidServiceHandle( *ContextHandle ) );
  522. return NO_ERROR;
  523. }
  524. BOOL
  525. ScIsValidServiceHandle(
  526. IN SC_RPC_HANDLE hService
  527. )
  528. {
  529. LPSC_HANDLE_STRUCT serviceHandleStruct = (LPSC_HANDLE_STRUCT) hService;
  530. if (serviceHandleStruct == NULL) {
  531. return (FALSE); // Not valid.
  532. }
  533. if (serviceHandleStruct->Signature != SERVICE_SIGNATURE) {
  534. return (FALSE); // Not valid.
  535. }
  536. return (TRUE);
  537. } // ScIsValidServiceHandle
  538. BOOL
  539. ScIsValidScManagerOrServiceHandle(
  540. IN SC_RPC_HANDLE ContextHandle,
  541. OUT PSC_HANDLE_TYPE phType
  542. )
  543. /*++
  544. Routine Description:
  545. Function to check a handle that may be either a service handle or
  546. an SC Manager handle without having to check vs. NULL twice by
  547. calling both ScIsValidScManagerHandle and ScIsValidServiceHandle
  548. Arguments:
  549. ContextHandle -- The handle to check
  550. phType -- The type of the handle (SCManager vs. Service) if valid
  551. Return Value:
  552. TRUE -- The handle is valid
  553. FALSE -- The handle is not valid
  554. --*/
  555. {
  556. LPSC_HANDLE_STRUCT pHandle = (LPSC_HANDLE_STRUCT) ContextHandle;
  557. SC_ASSERT(phType != NULL);
  558. if (pHandle == NULL)
  559. {
  560. return FALSE; // Not valid.
  561. }
  562. if (pHandle->Signature == SERVICE_SIGNATURE)
  563. {
  564. *phType = SC_HANDLE_TYPE_SERVICE;
  565. return TRUE;
  566. }
  567. else if (pHandle->Signature == SC_SIGNATURE)
  568. {
  569. *phType = SC_HANDLE_TYPE_MANAGER;
  570. return TRUE;
  571. }
  572. return FALSE;
  573. } // ScIsValidScManagerOrServiceHandle