Source code of Windows XP (NT5)
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.

1471 lines
43 KiB

  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. Module Name:
  4. start.cxx
  5. Abstract:
  6. Contains functions that are required for starting a service.
  7. RStartServiceW
  8. StartImage
  9. InitStartImage
  10. ScInitStartupInfo
  11. EndStartImage
  12. ScAllowInteractiveServices
  13. Author:
  14. Dan Lafferty (danl) 20-Jan-1992
  15. Environment:
  16. User Mode - Calls Win32 and NT native APIs.
  17. Revision History:
  18. 13-Mar-199 jschwart
  19. Use CreateProcessAsUserW for non-LocalSystem services
  20. 06-Apr-1998 jschwart
  21. Change check for Security Process connection -- check to see if
  22. the service being started runs in the process, not if it's NetLogon.
  23. Also clean up WesW from 12-Dec-1997
  24. 10-Mar-1998 jschwart
  25. Allow services to receive control messages for Plug-and-Play events
  26. 12-Dec-1997 WesW
  27. Added support for safe boot
  28. 22-Oct-1997 jschwart
  29. Enable 12-Apr-1995 change for non-_CAIRO_.
  30. 08-Jan-1997 AnirudhS
  31. Fixed miscellaneous synchronization bugs found by new locking
  32. scheme.
  33. 09-Dec-1996 AnirudhS
  34. Added ScInitStartupInfo and ScAllowInteractiveServices, also used
  35. by crash.cxx
  36. 01-Mar-1996 AnirudhS
  37. ScStartImage: Notify the PNP manager when a service is started.
  38. 12-Apr-1995 AnirudhS
  39. Allow services that run under accounts other than LocalSystem to
  40. share processes too.
  41. (_CAIRO_ only)
  42. 21-Feb-1995 AnirudhS
  43. Since CreateProcess now handles quoted exe pathnames, removed the
  44. (buggy) code that had been added to parse them, including
  45. ScParseImagePath.
  46. 08-Sep-1994 Danl
  47. ScLogonAndStartImage: Close the Duplicate token when we are done
  48. with it. This allows logoff notification when the service process
  49. exits.
  50. 30-Aug-1994 Danl
  51. ScParseImagePath: Added this function to look for quotes around the
  52. pathname. The Quotes may be necessary if the path contains a space
  53. character.
  54. 18-Mar-1994 Danl
  55. ScLogonAndStartImage: When starting a service in an account, we now
  56. Impersonate using a duplicate of the token for the service, prior
  57. to calling CreateProcess. This allows us to load executables
  58. whose binaries reside on a remote server.
  59. 20-Oct-1993 Danl
  60. ScStartService: If the NetLogon Service isn't in our database yet,
  61. then we want to check to see if the service to be started is
  62. NetLogon. If it is then we need to init our connection with the
  63. Security Process.
  64. 17-Feb-1993 danl
  65. Must release the database lock around the CreateProcess call so
  66. that dll init routines can call OpenService.
  67. 12-Feb-1993 danl
  68. Move the incrementing of the Service UseCount to
  69. ScActivateServiceRecord. This is because if we fail beyond this
  70. point, we call ScRemoveService to cleanup - but that assumes the
  71. UseCount has already been incremented one for the service itself.
  72. 25-Apr-1992 ritaw
  73. Changed ScStartImage to ScLogonAndStartImage
  74. 20-Jan-1992 danl
  75. created
  76. --*/
  77. //
  78. // Includes
  79. //
  80. #include "precomp.hxx"
  81. extern "C" {
  82. #include <winuserp.h> // STARTF_DESKTOPINHERIT
  83. #include <cfgmgr32.h> // PNP manager functions
  84. #include <pnp.h> // PNP manager functions, server side
  85. #include <cfgmgrp.h> // PNP manager functions, server side, internal
  86. #include <userenv.h> // UnloadUserProfile
  87. }
  88. #include <stdlib.h> // wide character c runtimes.
  89. #include <tstr.h> // Unicode string macros
  90. #include <scconfig.h> // ScGetImageFileName
  91. #include <control.h>
  92. #include <scseclib.h> // ScCreateAndSetSD
  93. #include <svcslib.h> // SvcStartLocalDispatcher
  94. #include "depend.h" // ScStartMarkedServices
  95. #include "driver.h" // ScLoadDeviceDriver
  96. #include "account.h" // ScLogonService
  97. #include "start.h" // ScStartService
  98. //
  99. // STATIC DATA
  100. //
  101. CRITICAL_SECTION ScStartImageCriticalSection;
  102. const LPWSTR pszInteractiveDesktop=L"WinSta0\\Default";
  103. //
  104. // LOCAL FUNCTIONS
  105. //
  106. DWORD
  107. ScLogonAndStartImage(
  108. IN LPSERVICE_RECORD ServiceRecord,
  109. IN LPWSTR ImageName,
  110. OUT LPIMAGE_RECORD *ImageRecordPtr,
  111. IN OPTIONAL LPVOID Environment
  112. );
  113. VOID
  114. ScProcessHandleIsSignaled(
  115. PVOID pContext,
  116. BOOLEAN fWaitStatus
  117. );
  118. BOOL
  119. ScEqualAccountName(
  120. IN LPWSTR Account1,
  121. IN LPWSTR Account2
  122. );
  123. DWORD
  124. RStartServiceW(
  125. IN SC_RPC_HANDLE hService,
  126. IN DWORD NumArgs,
  127. IN LPSTRING_PTRSW CmdArgs
  128. )
  129. /*++
  130. Routine Description:
  131. This function begins the execution of a service.
  132. Arguments:
  133. hService - A handle which is a pointer to a service handle structure.
  134. dwNumServiceArgs - This indicates the number of argument vectors.
  135. lpServiceArgVectors - This is a pointer to an array of string pointers.
  136. Return Value:
  137. NO_ERROR - The operation was completely successful.
  138. ERROR_ACCESS_DENIED - The specified handle was not opened with
  139. SERVICE_START access.
  140. ERROR_INVALID_HANDLE - The specified handle was invalid.
  141. ERROR_SERVICE_WAS_STARTED - An instance of the service is already running.
  142. ERROR_SERVICE_REQUEST_TIMEOUT - The service did not respond to the start
  143. request in a timely fashion.
  144. ERROR_SERVICE_NO_THREAD - A thread could not be created for the Win32
  145. service.
  146. ERROR_PATH_NOT_FOUND - The image file name could not be found in
  147. the configuration database (registry), or the image file name
  148. failed in a unicode/ansi conversion.
  149. --*/
  150. {
  151. DWORD status;
  152. LPSERVICE_RECORD serviceRecord;
  153. if (ScShutdownInProgress) {
  154. return(ERROR_SHUTDOWN_IN_PROGRESS);
  155. }
  156. //
  157. // Check the handle.
  158. //
  159. if (!ScIsValidServiceHandle(hService))
  160. {
  161. return ERROR_INVALID_HANDLE;
  162. }
  163. //
  164. // Was the handle opened with SERVICE_START access?
  165. //
  166. if (! RtlAreAllAccessesGranted(
  167. ((LPSC_HANDLE_STRUCT)hService)->AccessGranted,
  168. SERVICE_START
  169. )) {
  170. return(ERROR_ACCESS_DENIED);
  171. }
  172. //
  173. // A word about Locks....
  174. // We don't bother to get locks here because (1) We know the service
  175. // record cannot go away because we have an open handle to it,
  176. // (2) For these checks, we don't care if state changes after we
  177. // check them.
  178. //
  179. // (ScStartServiceAndDependencies also performs these checks; they are
  180. // repeated here so we can fail quickly in these 2 cases.)
  181. //
  182. serviceRecord =
  183. ((LPSC_HANDLE_STRUCT)hService)->Type.ScServiceObject.ServiceRecord;
  184. //
  185. // We can never start a disabled service
  186. //
  187. if (serviceRecord->StartType == SERVICE_DISABLED) {
  188. return ERROR_SERVICE_DISABLED;
  189. }
  190. //
  191. // Cannot start a deleted service.
  192. //
  193. if (DELETE_FLAG_IS_SET(serviceRecord)) {
  194. return ERROR_SERVICE_MARKED_FOR_DELETE;
  195. }
  196. status = ScStartServiceAndDependencies(serviceRecord, NumArgs, CmdArgs, FALSE);
  197. if (status == NO_ERROR)
  198. {
  199. if (serviceRecord->StartError == NO_ERROR)
  200. {
  201. //
  202. // Log successful service start. 0 is for a start "control"
  203. // since there's actually no such SERVICE_CONTROL_* constant.
  204. //
  205. ScLogControlEvent(NEVENT_SERVICE_CONTROL_SUCCESS,
  206. serviceRecord->DisplayName,
  207. 0);
  208. }
  209. return serviceRecord->StartError;
  210. }
  211. else
  212. {
  213. //
  214. // Start failure was logged by ScStartServiceAndDependencies
  215. //
  216. return status;
  217. }
  218. }
  219. DWORD
  220. ScStartService(
  221. IN LPSERVICE_RECORD ServiceRecord,
  222. IN DWORD NumArgs,
  223. IN LPSTRING_PTRSW CmdArgs
  224. )
  225. /*++
  226. Routine Description:
  227. This function starts a service. This code is split from the RStartServiceW
  228. so that the service controller internal code can bypass RPC and security
  229. checking when auto-starting services and their dependencies.
  230. Arguments:
  231. ServiceRecord - This is a pointer to the service record.
  232. NumArgs - This indicates the number of argument vectors.
  233. CmdArgs - This is a pointer to an array of string pointers.
  234. Return Value:
  235. NO_ERROR - The operation was completely successful.
  236. ERROR_ACCESS_DENIED - The specified handle was not opened with
  237. SERVICE_START access.
  238. ERROR_INVALID_HANDLE - The specified handle was invalid.
  239. ERROR_SERVICE_WAS_STARTED - An instance of the service is already running.
  240. ERROR_SERVICE_REQUEST_TIMEOUT - The service did not respond to the start
  241. request in a timely fashion.
  242. ERROR_SERVICE_NO_THREAD - A thread could not be created for the Win32
  243. service.
  244. ERROR_PATH_NOT_FOUND - The image file name could not be found in
  245. the configuration database (registry), or the image file name
  246. failed in a Unicode/Ansi conversion.
  247. ERROR_NOT_SAFEBOOT_SERVICE - This service isn't startable during Safeboot.
  248. --*/
  249. {
  250. DWORD status;
  251. LPWSTR ImageName = NULL;
  252. LPIMAGE_RECORD ImageRecord = NULL;
  253. LPWSTR serviceName;
  254. LPWSTR displayName;
  255. HANDLE pipeHandle;
  256. DWORD startControl;
  257. //
  258. // Check for Safeboot
  259. //
  260. if (g_dwSafebootLen != 0 && g_SafeBootEnabled != SAFEBOOT_DSREPAIR) {
  261. HKEY hKeySafeBoot;
  262. //
  263. // If this ever fails, SAFEBOOT_BUFFER_LENGTH must be made larger
  264. //
  265. SC_ASSERT(g_dwSafebootLen + wcslen(ServiceRecord->ServiceName)
  266. < SAFEBOOT_BUFFER_LENGTH);
  267. wcscpy(g_szSafebootKey + g_dwSafebootLen, ServiceRecord->ServiceName);
  268. status = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  269. g_szSafebootKey,
  270. 0,
  271. KEY_READ,
  272. &hKeySafeBoot);
  273. if (status != NO_ERROR) {
  274. SC_LOG1(ERROR, "SAFEBOOT: service skipped = %ws\n",
  275. ServiceRecord->ServiceName);
  276. return ERROR_NOT_SAFEBOOT_SERVICE;
  277. }
  278. RegCloseKey(hKeySafeBoot);
  279. }
  280. // NOTE: Only one thread at a time should be in this part of the code.
  281. // This prevents two images from getting started as could happen if
  282. // two threads get the Image Record at virtually the same time. In
  283. // this case, they might both decide to start the same image.
  284. //
  285. // We need to do this before the check for the CurrentState. Otherwise,
  286. // two threads could race down to start the same service, and they
  287. // would both attempt to start it. We would end up with either
  288. // two service images running, or two threads of the same service
  289. // running in a single image.
  290. //
  291. EnterCriticalSection(&ScStartImageCriticalSection);
  292. SC_LOG(LOCKS,"RStartServiceW: Entering StartImage Critical Section.....\n",0);
  293. //
  294. // We need to gain exclusive access to the database so that we may
  295. // Read the database and make decisions based on its content.
  296. //
  297. {
  298. CServiceRecordExclusiveLock RLock;
  299. #ifdef TIMING_TEST
  300. DbgPrint("[SC_TIMING] Start Next Service TickCount for\t%ws\t%d\n",
  301. ServiceRecord->ServiceName, GetTickCount());
  302. #endif // TIMING_TEST
  303. //
  304. // Check to see if the service is already running.
  305. //
  306. if (ServiceRecord->ServiceStatus.dwCurrentState != SERVICE_STOPPED){
  307. SC_LOG(LOCKS,"RStartServiceW: Leaving StartImage Critical Section....\n",0);
  308. LeaveCriticalSection(&ScStartImageCriticalSection);
  309. return(ERROR_SERVICE_ALREADY_RUNNING);
  310. }
  311. //
  312. // If we are loading a driver, load it and return.
  313. // WARNING: ScLoadDeviceDriver releases and reacquires the RecordLock.
  314. //
  315. if (ServiceRecord->ServiceStatus.dwServiceType & SERVICE_DRIVER) {
  316. status = ScLoadDeviceDriver(ServiceRecord);
  317. LeaveCriticalSection(&ScStartImageCriticalSection);
  318. return(status);
  319. }
  320. //
  321. // Get the image record information out of the configuration database.
  322. //
  323. status = ScGetImageFileName(ServiceRecord->ServiceName, &ImageName);
  324. if (status != NO_ERROR) {
  325. SC_LOG(ERROR,"GetImageFileName failed rc = %d\n",status);
  326. SC_LOG(LOCKS,"RStartServiceW: Leaving StartImage Critical Section....\n",0);
  327. LeaveCriticalSection(&ScStartImageCriticalSection);
  328. return status;
  329. }
  330. if (ImageName == NULL) {
  331. SC_LOG0(ERROR,"GetImageFileName returned a NULL pointer\n");
  332. SC_LOG(LOCKS,"RStartServiceW: Leaving StartImage Critical Section....\n",0);
  333. LeaveCriticalSection(&ScStartImageCriticalSection);
  334. return ERROR_PATH_NOT_FOUND;
  335. }
  336. #ifndef _CAIRO_
  337. //
  338. // If the security process hasn't been started yet, see if this
  339. // service runs in the security process and if so, initialize it.
  340. // Even if ScInitSecurityProcess fails, we will set the global
  341. // flag since we will not attempt to connect again.
  342. //
  343. if (!ScConnectedToSecProc) {
  344. if (_wcsicmp(ScGlobalSecurityExePath, ImageName) == 0) {
  345. if (!ScInitSecurityProcess(ServiceRecord)) {
  346. SC_LOG0(ERROR, "ScInitSecurityProcess Failed\n");
  347. }
  348. ScConnectedToSecProc = TRUE;
  349. }
  350. }
  351. #endif // _CAIRO_
  352. //
  353. // Make the service record active.
  354. // Because the service effectively has a handle to itself, the
  355. // UseCount gets incremented inside ScActivateServiceRecord() when
  356. // called with a NULL ImageRecord pointer.
  357. //
  358. // We need to do this here because when we get to ScLogonAndStartImage,
  359. // we have to release the database lock around the CreateProcess call.
  360. // Since we open ourselves up to DeleteService and Control Service calls,
  361. // We need to increment the use count, and set the START_PENDING status
  362. // here.
  363. //
  364. ScActivateServiceRecord(ServiceRecord, NULL);
  365. //
  366. // Is the image file for that service already running?
  367. // If not, call StartImage.
  368. //
  369. // If the Image Record was NOT found in the database OR if the service
  370. // wants to share a process and there is no shareable version of the
  371. // Image Record, then start the image file.
  372. //
  373. if (ServiceRecord->ServiceStatus.dwServiceType & SERVICE_WIN32_SHARE_PROCESS) {
  374. ScGetNamedImageRecord(ImageName,&ImageRecord);
  375. }
  376. // CODEWORK - may not need to release the lock here in all cases.
  377. } // Release RLock
  378. if (ImageRecord != NULL) {
  379. //
  380. // The service is configured to share its process with other services,
  381. // and the image for the service is already running. So we don't need
  382. // to start a new instance of the image.
  383. //
  384. // We do need to check that the account for the service is the same
  385. // as the one that the image was started under, and that the password
  386. // is valid.
  387. //
  388. LPWSTR AccountName = NULL;
  389. status = ScLookupServiceAccount(
  390. ServiceRecord->ServiceName,
  391. &AccountName
  392. );
  393. if (status == NO_ERROR) {
  394. if (!ScEqualAccountName(AccountName, ImageRecord->AccountName)) {
  395. status = ERROR_DIFFERENT_SERVICE_ACCOUNT;
  396. SC_LOG3(ERROR,
  397. "Can't start %ws service in account %ws because "
  398. "image is already running under account %ws\n",
  399. ServiceRecord->ServiceName,
  400. AccountName,
  401. ImageRecord->AccountName
  402. );
  403. }
  404. }
  405. //
  406. // If the account is not LocalSystem, validate the password by
  407. // logging on the service
  408. //
  409. if (status == NO_ERROR && AccountName != NULL) {
  410. HANDLE ServiceToken = NULL;
  411. PSID ServiceSid = NULL;
  412. status = ScLogonService(
  413. ServiceRecord->ServiceName,
  414. AccountName,
  415. &ServiceToken,
  416. NULL, // Don't need to load the user profile again
  417. &ServiceSid
  418. );
  419. if (status == NO_ERROR) {
  420. CloseHandle(ServiceToken);
  421. LocalFree(ServiceSid);
  422. }
  423. }
  424. LocalFree(AccountName);
  425. }
  426. else {
  427. //
  428. // Start a new instance of the image
  429. //
  430. // See if the service has a supplied environment.
  431. //
  432. LPVOID Environment;
  433. status = ScGetEnvironment(ServiceRecord->ServiceName, &Environment);
  434. if (status != NO_ERROR) {
  435. Environment = NULL;
  436. }
  437. SC_LOG(TRACE,"Start: calling StartImage\n",0);
  438. status = ScLogonAndStartImage(
  439. ServiceRecord,
  440. ImageName,
  441. &ImageRecord,
  442. Environment
  443. );
  444. if (status != NO_ERROR) {
  445. SC_LOG(TRACE,"Start: StartImage failed!\n",0);
  446. }
  447. LocalFree(Environment);
  448. }
  449. LocalFree( ImageName );
  450. if (status != NO_ERROR) {
  451. //
  452. // Deactivate the service record.
  453. //
  454. CServiceRecordExclusiveLock RLock;
  455. (void)ScDeactivateServiceRecord(ServiceRecord);
  456. SC_LOG(LOCKS,"RStartServiceW: Leaving StartImage Critical Section........\n",0);
  457. LeaveCriticalSection(&ScStartImageCriticalSection);
  458. return(status);
  459. }
  460. //
  461. // Before leaving the StartImage critical section, we need to gain
  462. // exclusive access to the database so that we may add the image record
  463. // pointer to the service record. (ActivateServiceRecord).
  464. //
  465. {
  466. CServiceRecordExclusiveLock RLock;
  467. //
  468. // By the time we get here, the Service Process will already be
  469. // running and ready to accept its first control request.
  470. //
  471. //
  472. // Add the ImageRecord Information to the active service record.
  473. //
  474. // Note that, as soon as we activate the service record and release
  475. // the lock, we open ourselves up to receiving control requests.
  476. // However, ScActivateServiceRecord sets the ControlsAccepted field
  477. // to 0, so that the service cannot accept any controls. Thus, until
  478. // the service actually sends its own status, the service controller
  479. // will reject any controls other than INTERROGATE.
  480. //
  481. // Because the service effectively has a handle to itself, the
  482. // UseCount gets incremented inside ScActivateServiceRecord().
  483. //
  484. ScActivateServiceRecord(ServiceRecord,ImageRecord);
  485. pipeHandle = ServiceRecord->ImageRecord->PipeHandle;
  486. serviceName = ServiceRecord->ServiceName;
  487. displayName = ServiceRecord->DisplayName;
  488. }
  489. SC_LOG(LOCKS,"RStartServiceW: Leaving StartImage Critical Section........\n",0);
  490. LeaveCriticalSection(&ScStartImageCriticalSection);
  491. //
  492. // Start the Service
  493. //
  494. if (ServiceRecord->ServiceStatus.dwServiceType & SERVICE_WIN32_OWN_PROCESS) {
  495. startControl = SERVICE_CONTROL_START_OWN;
  496. }
  497. else {
  498. startControl = SERVICE_CONTROL_START_SHARE;
  499. }
  500. CONTROL_ARGS ControlArgs;
  501. ControlArgs.CmdArgs = (LPWSTR *)CmdArgs;
  502. status = ScSendControl (
  503. serviceName, // ServiceName
  504. displayName, // DisplayName
  505. pipeHandle, // pipeHandle
  506. startControl, // Opcode
  507. &ControlArgs, // Union holding command-line args
  508. NumArgs, // NumArgs
  509. NULL); // Ignore handler return value
  510. if (status != NO_ERROR) {
  511. //
  512. // If an error occured, remove the service by de-activating the
  513. // service record and terminating the service process if it is
  514. // the only one running in the process.
  515. //
  516. SC_LOG2(ERROR,"Start: SendControl to %ws service failed! status=%ld\n",
  517. serviceName, status);
  518. //
  519. // NOTE: Because ScRemoveService will expect the use count
  520. // to already be incremented (for the service's own handle),
  521. // it is necessary to increment that use count prior to
  522. // removing it.
  523. //
  524. ScRemoveService(ServiceRecord);
  525. }
  526. else
  527. {
  528. //
  529. // Notify the PNP manager that the service was started.
  530. // The PNP manager uses this information to resolve ambiguities in
  531. // reconfiguration scenarios where there could temporarily be more
  532. // than one controlling service for a device. It remembers the last
  533. // service started for each device, and marks it as the "active"
  534. // service for the device in the registry.
  535. // We don't need to do this for drivers, because NtLoadDriver itself
  536. // notifies the PNP manager.
  537. //
  538. CONFIGRET PnpStatus = PNP_SetActiveService(
  539. NULL, // hBinding
  540. serviceName, // pszService
  541. PNP_SERVICE_STARTED // ulFlags
  542. );
  543. if (PnpStatus != CR_SUCCESS)
  544. {
  545. SC_LOG2(ERROR, "PNP_SetActiveService failed %#lx for service %ws\n",
  546. PnpStatus, serviceName);
  547. }
  548. }
  549. return(status);
  550. }
  551. /****************************************************************************/
  552. DWORD
  553. ScLogonAndStartImage(
  554. IN LPSERVICE_RECORD ServiceRecord,
  555. IN LPWSTR ImageName,
  556. OUT LPIMAGE_RECORD *ImageRecordPtr,
  557. IN OPTIONAL LPVOID Environment
  558. )
  559. /*++
  560. Routine Description:
  561. This function is called when the first service in an instance of an
  562. image needs to be started.
  563. This function creates a pipe instance for control messages and invokes
  564. the executable image. It then waits for the new process to connect
  565. to the control data pipe. An image Record is created with the
  566. above information by calling CreateImageRecord.
  567. Arguments:
  568. ImageName - This is the name of the image file that is to be started.
  569. This is expected to be a fully qualified path name.
  570. ImageRecordPtr - This is a location where the pointer to the new
  571. Image Record is returned.
  572. Environment - If present, supplies the environment block to be passed
  573. to CreateProcess
  574. Return Value:
  575. NO_ERROR - The operation was successful. It any other return value
  576. is returned, a pipe instance will not be created, a process will
  577. not be started, and an image record will not be created.
  578. ERROR_NOT_ENOUGH_MEMORY - Unable to allocate buffer for the image record.
  579. other - Any error returned by the following could be returned:
  580. CreateNamedPipe
  581. ConnectNamedPipe
  582. CreateProcess
  583. ScCreateControlInstance
  584. ScLogonService
  585. Note:
  586. LOCKS:
  587. The Database Lock is not held when this function is called.
  588. CODEWORK: This function badly needs to use C++ destructors for safe
  589. cleanup in error conditions.
  590. --*/
  591. {
  592. PROCESS_INFORMATION processInfo = { 0, 0, 0, 0 };
  593. DWORD servicePID;
  594. DWORD dwServiceID;
  595. HANDLE pipeHandle = NULL;
  596. DWORD status;
  597. BOOL runningInThisProcess = FALSE;
  598. HANDLE ServiceToken = NULL;
  599. HANDLE ProfileHandle = NULL;
  600. LPWSTR AccountName = NULL;
  601. DWORD ImageFlags = 0;
  602. PSID ServiceSid = LocalSystemSid;
  603. SC_ASSERT(! ScServiceRecordLock.Have());
  604. //
  605. // IMPORTANT:
  606. // Only one thread at a time should be allowed to execute this
  607. // code.
  608. //
  609. //
  610. // Lookup the account that the service is to be started under.
  611. // An AccountName of NULL means the LocalSystem account.
  612. //
  613. status = ScLookupServiceAccount(
  614. ServiceRecord->ServiceName,
  615. &AccountName
  616. );
  617. if (status != NO_ERROR) {
  618. return status;
  619. }
  620. if (AccountName != NULL) {
  621. //*******************************************************************
  622. // Start Service in an Account
  623. //*******************************************************************
  624. //
  625. // A token can be created via service logon, if the service
  626. // account name is not LocalSystem. Assign this token into
  627. // the service process.
  628. //
  629. NTSTATUS ntstatus;
  630. SECURITY_ATTRIBUTES SaProcess;
  631. BOOL fLoadedEnv = FALSE;
  632. PSECURITY_DESCRIPTOR SecurityDescriptor;
  633. #define SC_PROCESSSD_ACECOUNT 2
  634. SC_ACE_DATA AceData[SC_PROCESSSD_ACECOUNT] = {
  635. {ACCESS_ALLOWED_ACE_TYPE, 0, 0,
  636. PROCESS_ALL_ACCESS,
  637. 0},
  638. {ACCESS_ALLOWED_ACE_TYPE, 0, 0,
  639. PROCESS_SET_INFORMATION |
  640. PROCESS_TERMINATE |
  641. SYNCHRONIZE,
  642. &LocalSystemSid}
  643. };
  644. //
  645. // Get service token, to be assigned into the service process,
  646. // by logging on the service
  647. //
  648. status = ScLogonService(
  649. ServiceRecord->ServiceName,
  650. AccountName,
  651. &ServiceToken,
  652. &ProfileHandle,
  653. &ServiceSid
  654. );
  655. if (status != NO_ERROR) {
  656. LocalFree(AccountName);
  657. return status;
  658. }
  659. //
  660. // If there was no environment specified in the registry for
  661. // this service and successfully read by ScGetEnvironment,
  662. // give it this user account's environment block
  663. //
  664. if (Environment == NULL) {
  665. fLoadedEnv = CreateEnvironmentBlock(
  666. &Environment,
  667. ServiceToken,
  668. FALSE);
  669. if (!fLoadedEnv) {
  670. SC_LOG(ERROR,
  671. "ScLogonAndStartImage: CreateEnvironmentBlock FAILED %d\n",
  672. GetLastError());
  673. Environment = NULL;
  674. }
  675. }
  676. //
  677. // Fill pointer in AceData structure with ServiceSid we just
  678. // got back.
  679. //
  680. AceData[0].Sid = &ServiceSid;
  681. //
  682. // Create a security descriptor for the process we are about
  683. // to create
  684. //
  685. ntstatus = ScCreateAndSetSD(
  686. AceData, // AceData
  687. SC_PROCESSSD_ACECOUNT, // AceCount
  688. NULL, // OwnerSid (optional)
  689. NULL, // GroupSid (optional)
  690. &SecurityDescriptor // pNewDescriptor
  691. );
  692. #undef SC_PROCESSSD_ACECOUNT
  693. if (! NT_SUCCESS(ntstatus)) {
  694. SC_LOG1(ERROR, "ScCreateAndSetSD failed " FORMAT_NTSTATUS
  695. "\n", ntstatus);
  696. if (fLoadedEnv) {
  697. DestroyEnvironmentBlock(Environment);
  698. }
  699. status = RtlNtStatusToDosError(ntstatus);
  700. goto ExitAccountError;
  701. }
  702. //
  703. // Initialize process security info
  704. //
  705. SaProcess.nLength = sizeof(SECURITY_ATTRIBUTES);
  706. SaProcess.lpSecurityDescriptor = SecurityDescriptor;
  707. SaProcess.bInheritHandle = FALSE;
  708. //
  709. // Set the flags that prevent the service from interacting
  710. // with the desktop
  711. //
  712. STARTUPINFOW StartupInfo;
  713. ScInitStartupInfo(&StartupInfo, FALSE);
  714. //
  715. // Impersonate the user so we don't give access to
  716. // EXEs that have been locked down for the account.
  717. //
  718. if (!ImpersonateLoggedOnUser(ServiceToken))
  719. {
  720. status = GetLastError();
  721. SC_LOG1(ERROR,
  722. "ScLogonAndStartImage: ImpersonateLoggedOnUser failed %d\n",
  723. status);
  724. if (fLoadedEnv) {
  725. DestroyEnvironmentBlock(Environment);
  726. }
  727. RtlDeleteSecurityObject(&SecurityDescriptor);
  728. goto ExitAccountError;
  729. }
  730. //
  731. // Create the process in suspended mode to set the token
  732. // into the process.
  733. //
  734. // Note: If someone tries to start a service in a user account
  735. // with an image name of services.exe, a second instance of
  736. // services.exe will start, but will exit because it won't be
  737. // able to open the start event with write access (see
  738. // ScGetStartEvent).
  739. //
  740. if (!CreateProcessAsUserW (
  741. ServiceToken, // Token representing logged-on user
  742. NULL, // Fully qualified image name
  743. ImageName, // Command Line
  744. &SaProcess, // Process Attributes
  745. NULL, // Thread Attributes
  746. FALSE, // Inherit Handles
  747. DETACHED_PROCESS |
  748. CREATE_UNICODE_ENVIRONMENT |
  749. CREATE_SUSPENDED, // Creation Flags
  750. Environment, // Pointer to Environment block
  751. NULL, // Pointer to Current Directory
  752. &StartupInfo, // Startup Info
  753. &processInfo)) // ProcessInformation
  754. {
  755. status = GetLastError();
  756. }
  757. //
  758. // Stop impersonating
  759. //
  760. RevertToSelf();
  761. if (fLoadedEnv) {
  762. DestroyEnvironmentBlock(Environment);
  763. }
  764. RtlDeleteSecurityObject(&SecurityDescriptor);
  765. if (status != NO_ERROR) {
  766. SC_LOG2(ERROR,
  767. "LogonAndStartImage: CreateProcessAsUser %ws failed " FORMAT_DWORD "\n",
  768. ImageName, status);
  769. goto ExitAccountError;
  770. }
  771. SC_LOG1(ACCOUNT, "LogonAndStartImage: Service " FORMAT_LPWSTR
  772. " was spawned to run in an account\n", ServiceRecord->ServiceName);
  773. //*******************************************************************
  774. // End of Service In Account Stuff.
  775. //*******************************************************************
  776. }
  777. else
  778. {
  779. //-----------------------------------------------
  780. // Service to run with the LocalSystem account.
  781. //-----------------------------------------------
  782. BOOL bInteractive = FALSE;
  783. if (_wcsicmp(ImageName,ScGlobalThisExePath) == 0)
  784. {
  785. processInfo.hProcess = NULL;
  786. processInfo.dwProcessId = GetCurrentProcessId();
  787. runningInThisProcess = TRUE;
  788. }
  789. else
  790. {
  791. //
  792. // The service is to run in some other image.
  793. //
  794. // If the service is to run interactively, check the flag in the
  795. // registry to see if this system is to allow interactive services.
  796. //
  797. if (ServiceRecord->ServiceStatus.dwServiceType & SERVICE_INTERACTIVE_PROCESS) {
  798. bInteractive = ScAllowInteractiveServices();
  799. if (!bInteractive)
  800. {
  801. //
  802. // Write an event to indicate that an interactive service
  803. // was started, but the system is configured to not allow
  804. // services to be interactive.
  805. //
  806. ScLogEvent(NEVENT_SERVICE_NOT_INTERACTIVE,
  807. ServiceRecord->DisplayName);
  808. }
  809. }
  810. //
  811. // If the process is to be interactive, set the appropriate flags.
  812. //
  813. STARTUPINFOW StartupInfo;
  814. ScInitStartupInfo(&StartupInfo, bInteractive);
  815. //
  816. // Spawn the Image Process
  817. //
  818. SC_LOG0(TRACE,"LogonAndStartImage: about to spawn a Service Process\n");
  819. if (!CreateProcessW (
  820. NULL, // Fully qualified image name
  821. ImageName, // Command Line
  822. NULL, // Process Attributes
  823. NULL, // Thread Attributes
  824. FALSE, // Inherit Handles
  825. DETACHED_PROCESS |
  826. CREATE_UNICODE_ENVIRONMENT |
  827. CREATE_SUSPENDED, // Creation Flags
  828. Environment, // Pointer to Environment block
  829. NULL, // Pointer to Current Directory
  830. &StartupInfo, // Startup Info
  831. &processInfo) // ProcessInformation
  832. ) {
  833. status = GetLastError();
  834. SC_LOG2(ERROR,
  835. "LogonAndStartImage: CreateProcess %ws failed %d \n",
  836. ImageName,
  837. status);
  838. goto ExitAccountError;
  839. }
  840. SC_LOG1(ACCOUNT, "LogonAndStartImage: Service " FORMAT_LPWSTR
  841. " was spawned to run as LocalSystem\n", ServiceRecord->ServiceName);
  842. }
  843. //-----------------------------------------------
  844. // End of LocalSystem account stuff
  845. //-----------------------------------------------
  846. }
  847. //
  848. // Create an instance of the control pipe. If a malicious process
  849. // has already created a pipe by this name, the CreateNamedPipe
  850. // call in ScCreateControlInstance will return ERROR_ACCESS_DENIED.
  851. // Since that error should never come back otherwise, keep trying
  852. // new pipe names until we stop getting that error.
  853. //
  854. do
  855. {
  856. //
  857. // Write the service's ID to the registry
  858. //
  859. status = ScWriteCurrentServiceValue(&dwServiceID);
  860. if (status != NO_ERROR)
  861. {
  862. goto ExitAccountError;
  863. }
  864. status = ScCreateControlInstance(&pipeHandle,
  865. dwServiceID,
  866. ServiceSid);
  867. }
  868. while (status == ERROR_ACCESS_DENIED);
  869. if (status != NO_ERROR)
  870. {
  871. SC_LOG(ERROR,"LogonAndStartImage: CreateControlInstance Failure\n",0);
  872. goto ExitAccountError;
  873. }
  874. if (runningInThisProcess) {
  875. //
  876. // The service is to run in this image (services.exe).
  877. // Since this is the first service to be started in this image,
  878. // we need to start the local dispatcher.
  879. //
  880. status = SvcStartLocalDispatcher();
  881. if (status != NO_ERROR) {
  882. SC_LOG1(ERROR,"LogonAndStartImage: SvcStartLocalDispatcher "
  883. " failed %d",status);
  884. goto ExitAccountError;
  885. }
  886. }
  887. else {
  888. //
  889. // Let the suspended process run.
  890. //
  891. ResumeThread(processInfo.hThread);
  892. }
  893. status = ScWaitForConnect(pipeHandle,
  894. processInfo.hProcess,
  895. ServiceRecord->DisplayName,
  896. &servicePID);
  897. if (status != NO_ERROR) {
  898. SC_LOG0(ERROR,
  899. "LogonAndStartImage: Failed to connect to pipe - Terminating the Process...\n");
  900. goto ExitAccountError;
  901. }
  902. //
  903. // The client managed to connect on the correct PID-named pipe, so
  904. // the PID it's reporting should be the same as what we think it is.
  905. // Note that a mismatch is OK if the service is being run under the debugger.
  906. //
  907. if (processInfo.dwProcessId != servicePID) {
  908. SC_LOG2(ERROR,
  909. "LogonAndStartImage: PID mismatch - started process %d, process %d connected\n",
  910. processInfo.dwProcessId,
  911. servicePID);
  912. }
  913. //
  914. // If it's a shared-process service, put this information into the Image Record
  915. //
  916. if (ServiceRecord->ServiceStatus.dwServiceType & SERVICE_WIN32_SHARE_PROCESS) {
  917. ImageFlags |= CANSHARE_FLAG;
  918. }
  919. status = ScCreateImageRecord (
  920. ImageRecordPtr,
  921. ImageName,
  922. AccountName,
  923. processInfo.dwProcessId,
  924. pipeHandle,
  925. processInfo.hProcess,
  926. ServiceToken,
  927. ProfileHandle,
  928. ImageFlags);
  929. if (status != NO_ERROR) {
  930. SC_LOG0(ERROR,
  931. "LogonAndStartImage: Failed to create imageRecord - Terminating the Process...\n",);
  932. goto ExitAccountError;
  933. }
  934. //
  935. // If the dispatcher is running in this process, then we want to
  936. // increment the service count an extra time so that the dispatcher
  937. // never goes away. Also, we don't really have a process handle for
  938. // the watcher to wait on.
  939. // It could wait on the ThreadHandle, but handling that when it becomes
  940. // signaled becomes a special case. So we won't try that.
  941. //
  942. if (runningInThisProcess) {
  943. (*ImageRecordPtr)->ServiceCount = 1;
  944. (*ImageRecordPtr)->ImageFlags |= IS_SYSTEM_SERVICE;
  945. }
  946. else {
  947. HANDLE hWaitObject = NULL;
  948. NTSTATUS ntStatus;
  949. CloseHandle(processInfo.hThread);
  950. //
  951. // Add the process handle to the ObjectWatcher list of waitable
  952. // objects.
  953. //
  954. //
  955. // Add the process handle as a handle to wait on.
  956. // Retain the WaitObject handle for when we need shutdown the
  957. // process because all the services stopped.
  958. //
  959. ntStatus = RtlRegisterWait(&hWaitObject,
  960. processInfo.hProcess,
  961. ScProcessHandleIsSignaled,
  962. processInfo.hProcess,
  963. INFINITE, // Infinite
  964. WT_EXECUTEONLYONCE);
  965. if (!NT_SUCCESS(ntStatus)) {
  966. //
  967. // Work item registration failed
  968. //
  969. SC_LOG1(ERROR,
  970. "ScLogonAndStartImage: RtlRegisterWait failed 0x%x\n",
  971. ntStatus);
  972. }
  973. (*ImageRecordPtr)->ObjectWaitHandle = hWaitObject;
  974. }
  975. if (ServiceSid != LocalSystemSid) {
  976. LocalFree(ServiceSid);
  977. }
  978. LocalFree(AccountName);
  979. return(NO_ERROR);
  980. ExitAccountError:
  981. if (pipeHandle != NULL) {
  982. CloseHandle(pipeHandle);
  983. }
  984. if (ServiceSid != LocalSystemSid) {
  985. LocalFree(ServiceSid);
  986. }
  987. UnloadUserProfile(ServiceToken, ProfileHandle);
  988. if (ServiceToken != NULL) {
  989. CloseHandle(ServiceToken);
  990. }
  991. if (processInfo.hProcess) {
  992. TerminateProcess(processInfo.hProcess,0);
  993. CloseHandle(processInfo.hProcess);
  994. CloseHandle(processInfo.hThread);
  995. }
  996. LocalFree(AccountName);
  997. return status;
  998. }
  999. BOOL
  1000. ScEqualAccountName(
  1001. IN LPWSTR Account1,
  1002. IN LPWSTR Account2
  1003. )
  1004. /*++
  1005. Routine Description:
  1006. This function compares two account names, either of which may be NULL,
  1007. for equality.
  1008. Arguments:
  1009. Account1, Account2 - account names to be compared
  1010. Return Value:
  1011. TRUE - names are equal
  1012. FALSE - names are not equal
  1013. --*/
  1014. {
  1015. if (Account1 == NULL && Account2 == NULL)
  1016. {
  1017. return TRUE;
  1018. }
  1019. if (Account1 == NULL || Account2 == NULL)
  1020. {
  1021. return FALSE;
  1022. }
  1023. return (_wcsicmp(Account1, Account2) == 0);
  1024. }
  1025. VOID
  1026. ScInitStartImage(
  1027. VOID
  1028. )
  1029. /*++
  1030. Routine Description:
  1031. This function initializes the Critical Section that protects
  1032. entry into the ScStartImage Routine.
  1033. Arguments:
  1034. none
  1035. Return Value:
  1036. none
  1037. --*/
  1038. {
  1039. InitializeCriticalSection(&ScStartImageCriticalSection);
  1040. }
  1041. VOID
  1042. ScInitStartupInfo(
  1043. OUT LPSTARTUPINFOW StartupInfo,
  1044. IN BOOL bInteractive
  1045. )
  1046. /*++
  1047. Routine Description:
  1048. Arguments:
  1049. none
  1050. Return Value:
  1051. none
  1052. --*/
  1053. {
  1054. static const STARTUPINFOW ScStartupInfo =
  1055. {
  1056. sizeof(STARTUPINFOW), // size
  1057. NULL, // lpReserved
  1058. NULL, // DeskTop
  1059. NULL, // Title
  1060. 0, // X (position)
  1061. 0, // Y (position)
  1062. 0, // XSize (dimension)
  1063. 0, // YSize (dimension)
  1064. 0, // XCountChars
  1065. 0, // YCountChars
  1066. 0, // FillAttributes
  1067. STARTF_FORCEOFFFEEDBACK,
  1068. // Flags - should be STARTF_TASKNOTCLOSABLE
  1069. SW_HIDE, // ShowWindow
  1070. 0L, // cbReserved
  1071. NULL, // lpReserved
  1072. NULL, // hStdInput
  1073. NULL, // hStdOutput
  1074. NULL // hStdError
  1075. };
  1076. RtlCopyMemory(StartupInfo, &ScStartupInfo, sizeof(ScStartupInfo));
  1077. if (bInteractive)
  1078. {
  1079. StartupInfo->dwFlags |= STARTF_DESKTOPINHERIT;
  1080. StartupInfo->lpDesktop = pszInteractiveDesktop;
  1081. }
  1082. }
  1083. VOID
  1084. ScProcessHandleIsSignaled(
  1085. PVOID pContext,
  1086. BOOLEAN fWaitStatus
  1087. )
  1088. /*++
  1089. Routine Description:
  1090. Arguments:
  1091. pContext - This is the process handle.
  1092. fWaitStatus - This is the status from the wait on the process handle.
  1093. TRUE means the wait timed out, FALSE means it was signaled
  1094. Return Value:
  1095. --*/
  1096. {
  1097. if (fWaitStatus == TRUE) {
  1098. //
  1099. // This should never happen -- it indicates a bug in the thread pool code
  1100. // since we registered an infinite wait and are getting called on a timeout
  1101. //
  1102. SC_LOG0(ERROR,
  1103. "ScProcessCleanup received bad WaitStatus\n");
  1104. SC_ASSERT(FALSE);
  1105. return;
  1106. }
  1107. SC_ASSERT(fWaitStatus == FALSE);
  1108. SC_LOG1(THREADS, "Process Handle is signaled 0x%lx\n", pContext);
  1109. ScNotifyChangeState();
  1110. ScProcessCleanup((HANDLE)pContext);
  1111. }
  1112. BOOL
  1113. ScAllowInteractiveServices(
  1114. VOID
  1115. )
  1116. /*++
  1117. Routine Description:
  1118. Check the flag in the registry to see if this system is to allow
  1119. interactive services.
  1120. REG KEY = HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\-
  1121. Windows\NoInteractiveServices.
  1122. Arguments:
  1123. Return Value:
  1124. --*/
  1125. {
  1126. HKEY WindowsKey=NULL;
  1127. DWORD NoInteractiveFlag=0;
  1128. BOOL bServicesInteractive = TRUE;
  1129. DWORD status = ScRegOpenKeyExW(
  1130. HKEY_LOCAL_MACHINE,
  1131. CONTROL_WINDOWS_KEY_W,
  1132. REG_OPTION_NON_VOLATILE, // options
  1133. KEY_READ, // desired access
  1134. &WindowsKey
  1135. );
  1136. if (status != ERROR_SUCCESS) {
  1137. SC_LOG1(TRACE,
  1138. "ScAllowInteractiveServices: ScRegOpenKeyExW of Control\\Windows failed "
  1139. FORMAT_LONG "\n", status);
  1140. }
  1141. else {
  1142. status = ScReadNoInteractiveFlag(WindowsKey,&NoInteractiveFlag);
  1143. if ((status == ERROR_SUCCESS) && (NoInteractiveFlag != 0)) {
  1144. bServicesInteractive = FALSE;
  1145. }
  1146. ScRegCloseKey(WindowsKey);
  1147. }
  1148. return bServicesInteractive;
  1149. }