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.

5214 lines
125 KiB

  1. /*++
  2. Copyright (c) 1991-92 Microsoft Corporation
  3. Module Name:
  4. scconfig.cxx
  5. Abstract:
  6. This module contains routines for manipulating configuration
  7. information.
  8. Configuration information is kept in the registry.
  9. This file contains the following functions:
  10. ScGetImageFileName
  11. ScInitSecurityProcess
  12. ScCreateLoadOrderGroupList
  13. ScGenerateServiceDB
  14. ScOpenServiceConfigKey
  15. ScReadServiceType
  16. ScReadStartName
  17. ScReadFailureActions
  18. ScWriteDependencies
  19. ScWriteErrorControl
  20. ScWriteGroupForThisService
  21. ScWriteImageFileName
  22. ScWriteServiceType
  23. ScWriteStartType
  24. ScWriteStartName
  25. ScWriteFailureActions
  26. ScWriteCurrentServiceValue
  27. ScReadServiceType
  28. ScReadStartType
  29. ScReadErrorControl
  30. ScReadServiceConfig
  31. ScAllocateAndReadConfigValue
  32. ScReadNoInteractiveFlag
  33. ScReadOptionalString
  34. ScWriteOptionalString
  35. ScGetToken
  36. ScOpenServicesKey
  37. ScRegCreateKeyExW
  38. ScRegOpenKeyExW
  39. ScRegQueryValueExW
  40. ScRegSetValueExW
  41. ScRegEnumKeyW
  42. ScRegDeleteKeyW
  43. ScRegQueryInfoKeyW
  44. ScRegGetKeySecurity
  45. ScRegSetKeySecurity
  46. ScRegEnumValueW
  47. ScHandleProviderChange
  48. ScMarkForDelete
  49. ScTakeOwnership
  50. Author:
  51. Dan Lafferty (danl) 01-Apr-1991
  52. Environment:
  53. User Mode -Win32
  54. Revision History:
  55. 04-Apr-1991 danl
  56. created
  57. 21-Apr-1992 JohnRo
  58. Export ScAllocateAndReadConfigValue(). Added ScOpenServiceConfigKey().
  59. Added ScWriteServiceType() and other ScWrite routines.
  60. Use SC_LOG0(), etc. Use FORMAT_ equates.
  61. 24-Apr-1992 JohnRo
  62. Make ScWriteStartType() write a DWORD, not a string, for consistency.
  63. Call ScWriteStartType() from ScTransferServiceToRegistry().
  64. Must call RegSetValueExW (not RegSetValueW) for non-strings.
  65. 29-Apr-1992 JohnRo
  66. Move registry stuff from System\Services to
  67. System\Services\CurrentControlSet.
  68. Undo all group operations (ifdef USE_GROUPS).
  69. Undo reading from nt.cfg (we've got real registry) (ifdef
  70. USE_OLDCONFIG).
  71. They changed winreg APIs so REG_SZ is now UNICODE, so avoid REG_USZ.
  72. 08-Aug-1992 Danl
  73. Added ScMarkForDelete & ScDeleteFlagIsSet. ScReadServiceConfig is
  74. called for each service when generating the service database. At the
  75. end of this routine, we check to see if the delete flag is set in
  76. the registry entry. If it is, the delete flag is set in the service
  77. record so it can be deleted later. After the list of service records
  78. is complete - and before the dependencies are generated, we call
  79. ScDeleteMarkedServices which walks through the list and deletes any
  80. service (in both the registry and linked list) that is marked for
  81. deletion.
  82. 03-Nov-1992 Danl
  83. ScReadServiceConfig: If the ScAddCOnfigInfoServiceRecord call fails,
  84. we just want to skip the database entry - rather than fail the
  85. ScReadServiceConfig fuction. Failing ScReadServiceConfig is a fatal
  86. error for the service controller.
  87. 05-Nov-1992 Danl
  88. Added ScWriteDisplayName and ScReadDisplayName. Modified
  89. ReadServiceConfig to read in the display name.
  90. 29-Mar-1993 Danl
  91. Added SERVICE_RECOGNIZER_DRIVER as a type that is ignored when reading
  92. in the Service Database.
  93. 01-Apr-1993 Danl
  94. Added ScTakeOwnership. It is called when opening a key that
  95. complains about access denied.
  96. 30-Apr-1993 Danl
  97. Put security descriptor in a separate key that only allows read
  98. access to LocalSystem and Administrators. Also, we now delete the
  99. dependencies values from the registry when asked to write an empty
  100. string of dependencies.
  101. 05-Aug-1993 Danl
  102. ScRegQueryValueExW: It there is no pointer to a buffer for the data
  103. to be returned in, then we always want to return
  104. STATUS_BUFFER_OVERFLOW, even if we successfully read the data into
  105. the functions internal buffer.
  106. 20-Oct-1993 Danl
  107. InitSecurityProcess: Use a global NetLogon service name, and set
  108. the ScConnectedToSecProc flag when we succeed in connecting to the
  109. SecurityProcess.
  110. 16-Mar-1994 Danl
  111. ScRegOpenKeyExW: Fixed Memory Leak. KeyPath was not being free'd.
  112. ScRegEnumKeyW: Fixed Memory Leak. KeyInformation was not being free'd.
  113. 12-Apr-1995 AnirudhS
  114. Added AccountName field to image record.
  115. 04-Aug-1995 AnirudhS
  116. Close Lsa Event handle after use.
  117. 05-Feb-1996 AnirudhS
  118. ScWriteSd: Don't close registry handle twice. Don't close it at all
  119. if it's invalid.
  120. 18-Nov-1998 jschwart
  121. Added ScValidateMultiSZ, since the SCM was assuming all MULTI_SZ
  122. values were properly double-NUL terminated and AVing when this
  123. was not the case.
  124. --*/
  125. #include "precomp.hxx"
  126. #include <stdlib.h> // wide character c runtimes.
  127. #include <string.h> // ansi character c runtimes.
  128. #include <tstr.h> // Unicode string macros
  129. #include <sclib.h> // ScConvertToAnsi
  130. #include <control.h> // ScWaitForConnect
  131. #include "scconfig.h" // ScGetToken
  132. #include <valid.h> // SERVICE_TYPE_INVALID().
  133. #include <strarray.h> // ScDisplayWStrArray
  134. #include <scseclib.h> // ScCreateAndSetSD
  135. #include <regrpc.h> // RPC_SECURITY_DESCRIPTOR
  136. #include "depend.h" // ScInHardwareProfile
  137. #define ScWinRegErrorToApiStatus( regError ) \
  138. ( (DWORD) RegError )
  139. //
  140. // Constants
  141. //
  142. #define SECURITY_SERVICES_STARTED TEXT("SECURITY_SERVICES_STARTED")
  143. #define LSA_RPC_SERVER_ACTIVE L"LSA_RPC_SERVER_ACTIVE"
  144. #define REG_DELETE_FLAG L"DeleteFlag"
  145. //
  146. // Registry keys/values
  147. //
  148. #define SERVICES_TREE L"System\\CurrentControlSet\\Services"
  149. #define CONTROL_TREE L"System\\CurrentControlSet\\Control"
  150. #define CURRENT_KEY L"ServiceCurrent"
  151. #define DEFAULT_SERVICE_TYPE SERVICE_DRIVER
  152. //
  153. // Used for the Nt Registry API.
  154. //
  155. #define SC_HKEY_LOCAL_MACHINE L"\\REGISTRY\\MACHINE\\"
  156. //
  157. // Average Number of Bytes in a service record (including name).
  158. //
  159. #define AVE_SR_SIZE 260
  160. //
  161. // Static Global Variables
  162. //
  163. STATIC HKEY ScSGOKey = NULL;
  164. STATIC DWORD Buffer;
  165. //
  166. // Local Function Prototypes
  167. //
  168. DWORD
  169. ScReadServiceConfig(
  170. IN HKEY ServiceNameKey,
  171. IN LPWSTR ServiceName
  172. );
  173. BOOL
  174. ScDeleteFlagIsSet(
  175. HKEY ServiceKeyHandle
  176. );
  177. DWORD
  178. ScTakeOwnership(
  179. POBJECT_ATTRIBUTES pObja
  180. );
  181. DWORD
  182. ScOpenSecurityKey(
  183. IN HKEY ServiceNameKey,
  184. IN DWORD DesiredAccess,
  185. IN BOOL CreateIfMissing,
  186. OUT PHKEY pSecurityKey
  187. );
  188. VOID
  189. ScWaitForLsa(
  190. );
  191. DWORD
  192. ScGetEnvironment (
  193. IN LPWSTR ServiceName,
  194. OUT LPVOID *Environment
  195. )
  196. /*++
  197. Routine Description:
  198. Retrieves the environment block for the service. This is stored
  199. in the registry under the Environment value. The cluster service
  200. uses this to pass an environment block to services under control
  201. of the cluster software.
  202. This routine allocates storage for the environment block and the
  203. caller is responsible for freeing this with LocalFree.
  204. Arguments:
  205. ServiceName - This is a pointer to a service name. This identifies
  206. the service for which we desire an environment
  207. Environment - Returns a pointer to a location where the environment
  208. is to be placed. This memory should be freed with LocalFree.
  209. Return Value:
  210. NO_ERROR - The operation was successful.
  211. ERROR_PATH_NOT_FOUND - The environment could not be found
  212. or there was a registry error.
  213. --*/
  214. {
  215. DWORD ApiStatus;
  216. HKEY ServiceKey;
  217. DWORD EnvironmentSize;
  218. SC_ASSERT( ServiceName != NULL );
  219. //
  220. // Open the service key.
  221. //
  222. ApiStatus = ScOpenServiceConfigKey(
  223. ServiceName,
  224. KEY_READ, // desired access
  225. FALSE, // don't create if missing.
  226. &ServiceKey
  227. );
  228. if (ApiStatus != NO_ERROR) {
  229. return ERROR_PATH_NOT_FOUND;
  230. }
  231. //
  232. // Read the binary path name
  233. //
  234. ApiStatus = ScAllocateAndReadConfigValue(ServiceKey,
  235. ENVIRONMENT_VALUENAME_W,
  236. (LPWSTR *)Environment,
  237. &EnvironmentSize);
  238. ScRegCloseKey(ServiceKey);
  239. if (ApiStatus != NO_ERROR) {
  240. return ERROR_PATH_NOT_FOUND;
  241. }
  242. ApiStatus = ScValidateMultiSZ((LPWSTR) *Environment,
  243. EnvironmentSize);
  244. if (ApiStatus != NO_ERROR) {
  245. LocalFree(*Environment);
  246. *Environment = NULL;
  247. }
  248. return ApiStatus;
  249. }
  250. DWORD
  251. ScGetImageFileName (
  252. IN LPWSTR ServiceName,
  253. OUT LPWSTR *ImageNamePtr
  254. )
  255. /*++
  256. Routine Description:
  257. Retreives the Name of the Image File in which the specified service
  258. can be found. This routine allocates storage for the name so that
  259. a pointer to that name can be returned.
  260. Arguments:
  261. ServiceName - This is a pointer to a service name. This identifies
  262. the service for which we desire an image file name.
  263. ImageNamePtr - Returns a pointer to a location where the Image Name
  264. pointer is to be placed. This memory should be freed with
  265. LocalFree.
  266. Return Value:
  267. NO_ERROR - The operation was successful.
  268. ERROR_PATH_NOT_FOUND - The configuration component could not be found
  269. or there was a registry error.
  270. --*/
  271. {
  272. DWORD ApiStatus;
  273. HKEY ServiceKey;
  274. SC_ASSERT( ServiceName != NULL );
  275. //
  276. // Open the service key.
  277. //
  278. ApiStatus = ScOpenServiceConfigKey(
  279. ServiceName,
  280. KEY_READ, // desired access
  281. FALSE, // don't create if missing.
  282. &ServiceKey
  283. );
  284. if (ApiStatus != NO_ERROR) {
  285. return ERROR_PATH_NOT_FOUND;
  286. }
  287. //
  288. // Read the binary path name
  289. //
  290. if (ScAllocateAndReadConfigValue(
  291. ServiceKey,
  292. IMAGE_VALUENAME_W,
  293. ImageNamePtr,
  294. NULL
  295. ) != NO_ERROR) {
  296. (void) ScRegCloseKey(ServiceKey);
  297. return ERROR_PATH_NOT_FOUND;
  298. }
  299. (void) ScRegCloseKey(ServiceKey);
  300. SC_LOG1(CONFIG, "ScGetImageFileName got " FORMAT_LPWSTR " from registry\n",
  301. *ImageNamePtr);
  302. return NO_ERROR;
  303. }
  304. #ifndef _CAIRO_
  305. BOOL
  306. ScInitSecurityProcess(
  307. LPSERVICE_RECORD ServiceRecord
  308. )
  309. /*++
  310. Routine Description:
  311. This function determines the name of the security process, and then
  312. initializes a control pipe for it. A global named event is then
  313. set. This causes the security process to start its control dispatcher.
  314. The control dispatcher should then open the other end of the pipe and
  315. send its process id. The processId and the name of the image file
  316. are stored in an image record for the security process. The service
  317. instance count is incremented in this image record so that the
  318. record will never be deleted and the security process is never
  319. terminated.
  320. QUESTION:
  321. What is the proper behavior if this fails?
  322. Arguments:
  323. ServiceRecord -- The service record of the service being started.
  324. Note that as per the check in ScStartService, this
  325. service runs in the security process (and is the
  326. first service in that process being started)
  327. Return Value:
  328. TRUE - The initialization was successful.
  329. FALSE - The initialization failed. This indicates means that the
  330. service controller shouldn't continue with its initialization.
  331. If FALSE is returned, the service's service record has been
  332. marked (in the START_TYPE field) as disabled.
  333. --*/
  334. {
  335. DWORD status;
  336. HANDLE pipeHandle;
  337. LPIMAGE_RECORD imageRecord;
  338. HANDLE eventHandle;
  339. DWORD processId;
  340. //
  341. // Create an instance of the control pipe. Use an ID of 0 for lsass.exe
  342. // since it's possible for it to create its end of the pipe before we
  343. // ever get to this function.
  344. //
  345. status = ScCreateControlInstance (&pipeHandle, 0, LocalSystemSid);
  346. if (status != NO_ERROR) {
  347. SC_LOG1(ERROR,
  348. "ScInitSecurityProcess: ScCreateControlInstance Failure "
  349. FORMAT_DWORD "\n",
  350. status);
  351. ServiceRecord->StartType = SERVICE_DISABLED;
  352. return FALSE;
  353. }
  354. //
  355. // Set the event that will cause the Control dispatcher in the
  356. // Security Process to be started.
  357. //
  358. eventHandle = CreateEvent( NULL, // No special security
  359. TRUE, // Must be manually reset
  360. FALSE, // The event is initially not signalled
  361. SECURITY_SERVICES_STARTED );
  362. if (eventHandle == NULL){
  363. status = GetLastError();
  364. //
  365. // If the event already exists, the security process beat us to
  366. // creating it. Just open it.
  367. //
  368. if ( status == ERROR_ALREADY_EXISTS ) {
  369. eventHandle = OpenEvent( GENERIC_WRITE,
  370. FALSE,
  371. SECURITY_SERVICES_STARTED );
  372. }
  373. if (eventHandle == NULL ) {
  374. SC_LOG1(ERROR,"ScInitSecurityProcess: OpenEvent Failed "
  375. FORMAT_DWORD "\n", status);
  376. CloseHandle(pipeHandle);
  377. ServiceRecord->StartType = SERVICE_DISABLED;
  378. return FALSE;
  379. }
  380. }
  381. if (!SetEvent(eventHandle)) {
  382. SC_LOG1(ERROR,"ScInitSecurityProcess: SetEvent Failed " FORMAT_DWORD
  383. "\n", GetLastError());
  384. CloseHandle(pipeHandle);
  385. CloseHandle(eventHandle);
  386. ServiceRecord->StartType = SERVICE_DISABLED;
  387. return FALSE;
  388. }
  389. //
  390. // Wait for the Security Process to attach to the pipe and get its PID
  391. //
  392. status = ScWaitForConnect(pipeHandle,
  393. NULL,
  394. ServiceRecord->DisplayName,
  395. &processId);
  396. if (status != NO_ERROR) {
  397. SC_LOG1(ERROR,"ScInitSecurityProcess:"
  398. "SecurityProcess did not attach to pipe " FORMAT_DWORD "\n",
  399. status);
  400. CloseHandle(pipeHandle);
  401. CloseHandle(eventHandle);
  402. ServiceRecord->StartType = SERVICE_DISABLED;
  403. return FALSE;
  404. }
  405. //
  406. // Don't close the event handle until we know the security process has
  407. // seen the event.
  408. //
  409. CloseHandle(eventHandle);
  410. //
  411. // NOTE: The image record does not have a valid processHandle.
  412. // Therefore, we will never be able to terminate it. This is desired
  413. // behavior though. We should never terminate the security process.
  414. //
  415. status = ScCreateImageRecord (
  416. &imageRecord,
  417. ScGlobalSecurityExePath,
  418. NULL, // Account name is LocalSystem
  419. processId,
  420. pipeHandle,
  421. NULL, // The process handle is NULL.
  422. NULL, // Token handle is also NULL -- LocalSystem
  423. NULL, // No user profile loaded -- LocalSystem
  424. CANSHARE_FLAG |
  425. IS_SYSTEM_SERVICE);
  426. if (status != NO_ERROR) {
  427. SC_LOG0(ERROR,"Failed to create ImageRecord for Security Process\n");
  428. ServiceRecord->StartType = SERVICE_DISABLED;
  429. return FALSE;
  430. }
  431. imageRecord->ServiceCount = 1;
  432. ScConnectedToSecProc = TRUE;
  433. return TRUE;
  434. }
  435. #endif // _CAIRO_
  436. BOOL
  437. ScCreateLoadOrderGroupList(
  438. VOID
  439. )
  440. /*++
  441. Routine Description:
  442. This function creates the load order group list from the group
  443. order information found in HKEY_LOCAL_SYSTEM\Service_Group_Order
  444. Arguments:
  445. None
  446. Return Value:
  447. TRUE - The operation was completely successful.
  448. FALSE - An error occurred.
  449. Note:
  450. The GroupListLock must be held exclusively prior to calling this routine.
  451. --*/
  452. {
  453. DWORD status;
  454. DWORD dwGroupBytes;
  455. LONG RegError;
  456. LPWSTR Groups;
  457. LPWSTR GroupPtr;
  458. LPWSTR GroupName;
  459. SC_ASSERT(ScGroupListLock.HaveExclusive());
  460. //
  461. // Open the HKEY_LOCAL_MACHINE
  462. // System\CurrentControlSet\Control\ServiceGroupOrder key.
  463. //
  464. RegError = ScRegOpenKeyExW(
  465. HKEY_LOCAL_MACHINE,
  466. LOAD_ORDER_GROUP_LIST_KEY,
  467. REG_OPTION_NON_VOLATILE, // options
  468. KEY_READ, // desired access
  469. &ScSGOKey
  470. );
  471. if (RegError != ERROR_SUCCESS) {
  472. SC_LOG1(ERROR,
  473. "ScCreateLoadOrderGroupList: "
  474. "ScRegOpenKeyExW of HKEY_LOCAL_MACHINE\\System failed "
  475. FORMAT_LONG "\n", RegError);
  476. return FALSE;
  477. }
  478. //
  479. // Read the List value
  480. //
  481. if (ScAllocateAndReadConfigValue(
  482. ScSGOKey,
  483. GROUPLIST_VALUENAME_W,
  484. &Groups,
  485. &dwGroupBytes
  486. ) != NO_ERROR) {
  487. ScRegCloseKey(ScSGOKey);
  488. ScSGOKey = NULL;
  489. return FALSE;
  490. }
  491. if (ScValidateMultiSZ(
  492. Groups,
  493. dwGroupBytes
  494. ) != NO_ERROR) {
  495. LocalFree(Groups);
  496. ScRegCloseKey(ScSGOKey);
  497. ScSGOKey = NULL;
  498. return FALSE;
  499. }
  500. //
  501. // Leave the ServiceGroupOrder key open for change notify later
  502. //
  503. SC_LOG0(DEPEND_DUMP, "ScCreateLoadOrderGroupList: ServiceGroupOrder:\n");
  504. ScDisplayWStrArray(Groups);
  505. GroupPtr = Groups;
  506. while (*GroupPtr != 0) {
  507. if (ScGetToken(&GroupPtr, &GroupName)) {
  508. //
  509. // Add the group to the end of the load order group list
  510. //
  511. status = ScCreateOrderGroupEntry(
  512. GroupName
  513. );
  514. if (status != NO_ERROR) {
  515. //
  516. // Fatal error
  517. //
  518. LocalFree(Groups);
  519. return FALSE;
  520. }
  521. }
  522. }
  523. LocalFree(Groups);
  524. return TRUE;
  525. }
  526. BOOL
  527. ScGenerateServiceDB(
  528. VOID
  529. )
  530. /*++
  531. Routine Description:
  532. This function creates the service record list from the information
  533. which resides in the registry.
  534. Arguments:
  535. None
  536. Return Value:
  537. TRUE - The operation was completely successful.
  538. FALSE - An error occurred.
  539. NOTE:
  540. This function holds the GroupListLock.
  541. --*/
  542. {
  543. #define MAX_SERVICE_NAME_LENGTH 256
  544. WCHAR ServiceName[MAX_SERVICE_NAME_LENGTH];
  545. DWORD Index = 0;
  546. LONG RegError;
  547. LONG lTempError; // Used for debug messages only
  548. HKEY ServicesKey;
  549. HKEY ServiceNameKey;
  550. WCHAR ClassName[ MAX_PATH ];
  551. DWORD ClassNameLength = MAX_PATH;
  552. DWORD NumberOfSubKeys;
  553. DWORD MaxSubKeyLength;
  554. DWORD MaxClassLength;
  555. DWORD NumberOfValues;
  556. DWORD MaxValueNameLength;
  557. DWORD MaxValueDataLength;
  558. DWORD SecurityDescriptorLength;
  559. FILETIME LastWriteTime;
  560. DWORD HeapSize;
  561. //
  562. // Since there is only one thread at the time this function is called,
  563. // these locks are not really needed, but they are included to quell
  564. // assertions in the routines called herein.
  565. //
  566. CGroupListExclusiveLock GLock;
  567. CServiceListExclusiveLock LLock;
  568. CServiceRecordExclusiveLock RLock;
  569. //
  570. // Read in the group order list from the registry
  571. //
  572. if (! ScCreateLoadOrderGroupList()) {
  573. return FALSE;
  574. }
  575. //
  576. // Read in all the services entries from the registry
  577. //
  578. //
  579. // Open the key to the Services tree.
  580. //
  581. RegError = ScRegOpenKeyExW(
  582. HKEY_LOCAL_MACHINE,
  583. SERVICES_TREE,
  584. REG_OPTION_NON_VOLATILE, // options
  585. KEY_READ, // desired access
  586. &ServicesKey
  587. );
  588. if (RegError != ERROR_SUCCESS) {
  589. SC_LOG1(ERROR,
  590. "ScGenerateServiceDB: ScRegOpenKeyExW of Services tree failed "
  591. FORMAT_LONG "\n", RegError);
  592. return FALSE;
  593. }
  594. //
  595. // Find out how many service keys there are, and allocate a heap
  596. // that is twice as large.
  597. //
  598. RegError = ScRegQueryInfoKeyW(
  599. ServicesKey,
  600. ClassName,
  601. &ClassNameLength,
  602. NULL,
  603. &NumberOfSubKeys,
  604. &MaxSubKeyLength,
  605. &MaxClassLength,
  606. &NumberOfValues,
  607. &MaxValueNameLength,
  608. &MaxValueDataLength,
  609. &SecurityDescriptorLength,
  610. &LastWriteTime);
  611. if (RegError != NO_ERROR) {
  612. SC_LOG1(ERROR,"ScGenerateServiceDatabase: RegQueryInfoKey failed %d\n",
  613. RegError);
  614. HeapSize = 0x8000;
  615. }
  616. else {
  617. SC_LOG1(INFO,"ScGenerateServiceDatabase: %d SubKeys\n",NumberOfSubKeys);
  618. HeapSize = NumberOfSubKeys*2*AVE_SR_SIZE;
  619. }
  620. if (!ScAllocateSRHeap(HeapSize)) {
  621. return(FALSE);
  622. }
  623. //
  624. // Enumerate all the service name keys
  625. //
  626. do {
  627. RegError = ScRegEnumKeyW(
  628. ServicesKey,
  629. Index,
  630. ServiceName,
  631. MAX_SERVICE_NAME_LENGTH * sizeof(WCHAR)
  632. );
  633. if (RegError != ERROR_SUCCESS) {
  634. if (RegError == ERROR_NO_MORE_ITEMS) {
  635. //
  636. // No more entries
  637. //
  638. SC_LOG1(CONFIG,
  639. "ScGenerateServiceDB: ScRegEnumKeyW returns ERROR_NO_MORE_ITEMS"
  640. "(no more entries) for index " FORMAT_DWORD "\n",
  641. Index);
  642. }
  643. else {
  644. //
  645. // Error trying to enumerate next service name key
  646. //
  647. SC_LOG1(ERROR,
  648. "ScGenerateServiceDB: ScRegEnumKeyW of services tree failed "
  649. FORMAT_LONG "\n", RegError );
  650. ScRegCloseKey(ServicesKey);
  651. return FALSE;
  652. }
  653. }
  654. else {
  655. //
  656. // Got the name of a new service key. Open a handle to it.
  657. //
  658. SC_LOG1(CONFIG, "Service name key " FORMAT_LPWSTR "\n",
  659. ServiceName);
  660. lTempError = ScRegOpenKeyExW(
  661. ServicesKey,
  662. ServiceName,
  663. REG_OPTION_NON_VOLATILE, // options
  664. KEY_READ, // desired access
  665. &ServiceNameKey);
  666. if (lTempError == ERROR_SUCCESS)
  667. {
  668. //
  669. // Read service config info from the registry and build the
  670. // service record.
  671. //
  672. lTempError = ScReadServiceConfig(
  673. ServiceNameKey,
  674. ServiceName);
  675. ScRegCloseKey(ServiceNameKey);
  676. if (lTempError != NO_ERROR)
  677. {
  678. //
  679. // Skip this key
  680. //
  681. SC_LOG2(ERROR,
  682. "ScGenerateServiceDB: ScReadServiceConfig of "
  683. FORMAT_LPWSTR " failed " FORMAT_LONG "\n",
  684. ServiceName,
  685. lTempError);
  686. }
  687. }
  688. else
  689. {
  690. //
  691. // Skip this key
  692. //
  693. SC_LOG2(ERROR,
  694. "ScGenerateServiceDB: ScRegOpenKeyExW of "
  695. FORMAT_LPWSTR " failed " FORMAT_LONG "\n",
  696. ServiceName,
  697. lTempError);
  698. }
  699. }
  700. Index++;
  701. } while (RegError == ERROR_SUCCESS);
  702. ScRegCloseKey(ServicesKey);
  703. //
  704. // Wait for LSA to start since we are about to make our first call to
  705. // LSA and it typically is not already started yet.
  706. //
  707. ScWaitForLsa();
  708. //
  709. // Go through entire service record list and remove any services marked
  710. // for deletion.
  711. //
  712. ScDeleteMarkedServices();
  713. //
  714. // Go through entire service record list and resolve dependencies chain
  715. //
  716. ScGenerateDependencies();
  717. #if DBG
  718. ScDumpGroups();
  719. ScDumpServiceDependencies();
  720. #endif // DBG
  721. return TRUE;
  722. }
  723. VOID
  724. ScWaitForLsa(
  725. )
  726. /*++
  727. Routine Description:
  728. This routine either creates or opens the event called LSA_RPC_SERVER_ACTIVE
  729. event and waits on it indefinitely until LSA signals it. We need
  730. to know when LSA is available so that we can call LSA APIs.
  731. Arguments:
  732. None.
  733. Return Value:
  734. None.
  735. --*/
  736. {
  737. DWORD Status;
  738. HANDLE EventHandle;
  739. //
  740. // Create the named event LSA will set.
  741. //
  742. EventHandle = CreateEventW(
  743. NULL, // No special security
  744. TRUE, // Must be manually reset
  745. FALSE, // The event is initially not signalled
  746. LSA_RPC_SERVER_ACTIVE
  747. );
  748. if ( EventHandle == NULL ) {
  749. Status = GetLastError();
  750. //
  751. // If the event already exists, LSA has already created it.
  752. // Just open.
  753. //
  754. if ( Status == ERROR_ALREADY_EXISTS ) {
  755. EventHandle = OpenEventW(
  756. SYNCHRONIZE,
  757. FALSE,
  758. LSA_RPC_SERVER_ACTIVE
  759. );
  760. }
  761. if ( EventHandle == NULL ) {
  762. SC_LOG1(ERROR, "ScWaitForLsa: OpenEvent of LSA_RPC_SERVER_ACTIVE failed %d\n",
  763. GetLastError());
  764. return;
  765. }
  766. }
  767. //
  768. // Wait for LSA to come up.
  769. //
  770. (VOID) WaitForSingleObject( EventHandle, INFINITE );
  771. CloseHandle( EventHandle );
  772. }
  773. DWORD
  774. ScOpenServiceConfigKey(
  775. IN LPWSTR ServiceName,
  776. IN DWORD DesiredAccess,
  777. IN BOOL CreateIfMissing,
  778. OUT PHKEY ServiceKey
  779. )
  780. /*++
  781. Routine Description:
  782. Arguments:
  783. Return Value:
  784. --*/
  785. {
  786. HKEY ServicesKey;
  787. HKEY ServiceNameKey;
  788. DWORD ServicesAccess = KEY_READ;
  789. LONG RegError;
  790. SC_ASSERT( ServiceName != NULL );
  791. if (CreateIfMissing) {
  792. ServicesAccess |= KEY_CREATE_SUB_KEY;
  793. }
  794. //
  795. // Open the key to the Services tree.
  796. //
  797. RegError = ScRegOpenKeyExW(
  798. HKEY_LOCAL_MACHINE,
  799. SERVICES_TREE,
  800. REG_OPTION_NON_VOLATILE, // options
  801. ServicesAccess, // desired access (this level)
  802. &ServicesKey
  803. );
  804. if (RegError != ERROR_SUCCESS) {
  805. SC_LOG1(ERROR, "ScOpenServiceConfigKey: "
  806. "ScRegOpenKeyExW of Services tree failed, reg error "
  807. FORMAT_LONG "\n", RegError);
  808. return ((DWORD) RegError);
  809. }
  810. if ( !CreateIfMissing ) {
  811. //
  812. // Open the existing service key.
  813. //
  814. RegError = ScRegOpenKeyExW(
  815. ServicesKey,
  816. ServiceName,
  817. REG_OPTION_NON_VOLATILE, // options
  818. DesiredAccess, // desired access
  819. & ServiceNameKey );
  820. if (RegError != ERROR_SUCCESS) {
  821. SC_LOG2(ERROR, "ScOpenServiceConfigKey: "
  822. "ScRegOpenKeyExW of " FORMAT_LPWSTR " failed "
  823. FORMAT_LONG "\n", ServiceName, RegError);
  824. (void) ScRegCloseKey(ServicesKey);
  825. return ((DWORD) RegError);
  826. }
  827. } else {
  828. DWORD Disposition;
  829. //
  830. // Create a new service key (or open existing one).
  831. //
  832. RegError = ScRegCreateKeyExW(
  833. ServicesKey,
  834. ServiceName,
  835. 0,
  836. 0,
  837. REG_OPTION_NON_VOLATILE, // options
  838. DesiredAccess, // desired access
  839. NULL,
  840. &ServiceNameKey,
  841. &Disposition);
  842. if (RegError != ERROR_SUCCESS) {
  843. SC_LOG2(ERROR, "ScOpenServiceConfigKey: "
  844. "ScRegCreateKeyExW of " FORMAT_LPWSTR " failed "
  845. FORMAT_LONG "\n", ServiceName, RegError);
  846. ScRegCloseKey(ServicesKey);
  847. return ((DWORD) RegError);
  848. }
  849. }
  850. (void) ScRegCloseKey(ServicesKey);
  851. //
  852. // Give the service key back to caller.
  853. //
  854. *ServiceKey = ServiceNameKey;
  855. return NO_ERROR;
  856. } // ScOpenServiceConfigKey
  857. DWORD
  858. ScWriteCurrentServiceValue(
  859. OUT LPDWORD lpdwID
  860. )
  861. /*++
  862. Routine Description:
  863. Writes the value to be used in the next service's pipe name to the registry
  864. Arguments:
  865. Return Value:
  866. --*/
  867. {
  868. LONG RegError;
  869. NTSTATUS ntstatus;
  870. SECURITY_ATTRIBUTES SecurityAttr;
  871. PSECURITY_DESCRIPTOR SecurityDescriptor;
  872. DWORD Disposition;
  873. //
  874. // Unique ID for the service to be started. Start
  875. // at 1 since ID 0 is reserved for lsass.exe
  876. //
  877. static DWORD s_dwCurrentService = 1;
  878. static HKEY s_hCurrentKey = NULL;
  879. SC_ASSERT(lpdwID != NULL);
  880. if (s_hCurrentKey == NULL)
  881. {
  882. HKEY hKey;
  883. //
  884. // Open the key to the Services tree.
  885. //
  886. RegError = ScRegOpenKeyExW(
  887. HKEY_LOCAL_MACHINE,
  888. CONTROL_TREE,
  889. 0, // options (ignored)
  890. KEY_WRITE, // KEY_SET_VALUE | KEY_CREATE_SUB_KEY
  891. &hKey
  892. );
  893. if (RegError != ERROR_SUCCESS)
  894. {
  895. SC_LOG1(ERROR,
  896. "ScWriteCurrentServiceValue: ScRegOpenKeyExW of Control tree failed, reg error "
  897. FORMAT_LONG "\n",
  898. RegError);
  899. return ((DWORD) RegError);
  900. }
  901. #define SC_KEY_ACE_COUNT 2
  902. SC_ACE_DATA AceData[SC_KEY_ACE_COUNT] = {
  903. {ACCESS_ALLOWED_ACE_TYPE, CONTAINER_INHERIT_ACE, 0,
  904. GENERIC_ALL, &LocalSystemSid},
  905. {ACCESS_ALLOWED_ACE_TYPE, CONTAINER_INHERIT_ACE, 0,
  906. GENERIC_READ, &WorldSid}
  907. };
  908. //
  909. // Create a security descriptor for the registry key we are about
  910. // to create. This gives everyone read access, and all access to
  911. // ourselves only.
  912. //
  913. ntstatus = ScCreateAndSetSD(
  914. AceData,
  915. SC_KEY_ACE_COUNT,
  916. LocalSystemSid,
  917. LocalSystemSid,
  918. &SecurityDescriptor
  919. );
  920. #undef SC_KEY_ACE_COUNT
  921. if (! NT_SUCCESS(ntstatus)) {
  922. SC_LOG1(ERROR, "ScCreateAndSetSD failed " FORMAT_NTSTATUS
  923. "\n", ntstatus);
  924. ScRegCloseKey(hKey);
  925. return(RtlNtStatusToDosError(ntstatus));
  926. }
  927. SecurityAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
  928. SecurityAttr.lpSecurityDescriptor = SecurityDescriptor;
  929. SecurityAttr.bInheritHandle = FALSE;
  930. //
  931. // Create a new key (or open existing one).
  932. //
  933. RegError = ScRegCreateKeyExW(
  934. hKey,
  935. CURRENT_KEY,
  936. 0,
  937. 0,
  938. REG_OPTION_VOLATILE, // options
  939. KEY_SET_VALUE, // desired access
  940. &SecurityAttr,
  941. &s_hCurrentKey,
  942. &Disposition);
  943. RtlDeleteSecurityObject(&SecurityDescriptor);
  944. ScRegCloseKey(hKey);
  945. if (RegError != ERROR_SUCCESS)
  946. {
  947. SC_LOG1(ERROR,
  948. "ScWriteCurrentServiceValue: ScRegCreateKeyExW of "
  949. "CURRENT_KEY failed " FORMAT_LONG "\n",
  950. RegError);
  951. return ((DWORD) RegError);
  952. }
  953. }
  954. //
  955. // Write the value in the key
  956. //
  957. RegError = ScRegSetValueExW(
  958. s_hCurrentKey,
  959. NULL, // Use key's unnamed value
  960. 0,
  961. REG_DWORD,
  962. (LPBYTE) &s_dwCurrentService,
  963. sizeof(DWORD));
  964. if (RegError != ERROR_SUCCESS)
  965. {
  966. SC_LOG1(ERROR,
  967. "ScWriteCurrentServiceValue: ScRegCreateKeyExW of "
  968. "CURRENT_KEY failed " FORMAT_LONG "\n",
  969. RegError);
  970. return ((DWORD) RegError);
  971. }
  972. *lpdwID = s_dwCurrentService;
  973. s_dwCurrentService++;
  974. return NO_ERROR;
  975. } // ScWriteCurrentServiceValue
  976. DWORD
  977. ScReadServiceType(
  978. IN HKEY ServiceNameKey,
  979. OUT LPDWORD ServiceTypePtr
  980. )
  981. /*++
  982. Routine Description:
  983. Arguments:
  984. Return Value:
  985. --*/
  986. {
  987. DWORD BytesRequired = sizeof(DWORD);
  988. LONG RegError;
  989. SC_ASSERT( ServiceNameKey != NULL );
  990. SC_ASSERT( ServiceTypePtr != NULL );
  991. *ServiceTypePtr = 0;
  992. RegError = ScRegQueryValueExW(
  993. ServiceNameKey,
  994. SERVICETYPE_VALUENAME_W,
  995. NULL,
  996. NULL,
  997. (LPBYTE) ServiceTypePtr,
  998. &BytesRequired
  999. );
  1000. if (RegError != ERROR_SUCCESS) {
  1001. SC_LOG3(TRACE, "ScReadServiceType: ScRegQueryValueExW of " FORMAT_LPWSTR
  1002. " failed "
  1003. FORMAT_LONG ", BytesRequired " FORMAT_DWORD "\n",
  1004. SERVICETYPE_VALUENAME_W, RegError, BytesRequired);
  1005. }
  1006. return (ScWinRegErrorToApiStatus( RegError ) );
  1007. } // ScReadServiceType
  1008. DWORD
  1009. ScReadNoInteractiveFlag(
  1010. IN HKEY ServiceNameKey,
  1011. OUT LPDWORD NoInteractivePtr
  1012. )
  1013. /*++
  1014. Routine Description:
  1015. Arguments:
  1016. Return Value:
  1017. --*/
  1018. {
  1019. DWORD BytesRequired = sizeof(DWORD);
  1020. LONG RegError;
  1021. SC_ASSERT( ServiceNameKey != NULL );
  1022. SC_ASSERT( NoInteractivePtr != NULL );
  1023. *NoInteractivePtr = 0;
  1024. RegError = ScRegQueryValueExW(
  1025. ServiceNameKey,
  1026. NOINTERACTIVE_VALUENAME_W,
  1027. NULL,
  1028. NULL,
  1029. (LPBYTE) NoInteractivePtr,
  1030. &BytesRequired
  1031. );
  1032. if (RegError != ERROR_SUCCESS) {
  1033. SC_LOG3(ERROR, "ScReadNoInteractiveFlag: ScRegQueryValueExW of " FORMAT_LPWSTR
  1034. " failed "
  1035. FORMAT_LONG ", BytesRequired " FORMAT_DWORD "\n",
  1036. NOINTERACTIVE_VALUENAME_W, RegError, BytesRequired);
  1037. }
  1038. return (ScWinRegErrorToApiStatus( RegError ) );
  1039. } // ScReadServiceType
  1040. DWORD
  1041. ScReadStartType(
  1042. IN HKEY ServiceNameKey,
  1043. OUT LPDWORD StartTypePtr
  1044. )
  1045. /*++
  1046. Routine Description:
  1047. Arguments:
  1048. Return Value:
  1049. --*/
  1050. {
  1051. DWORD BytesRequired = sizeof(DWORD);
  1052. LONG RegError;
  1053. SC_ASSERT( ServiceNameKey != NULL );
  1054. SC_ASSERT( StartTypePtr != NULL );
  1055. *StartTypePtr = 0;
  1056. RegError = ScRegQueryValueExW(
  1057. ServiceNameKey,
  1058. START_VALUENAME_W,
  1059. NULL,
  1060. NULL,
  1061. (LPBYTE) StartTypePtr,
  1062. &BytesRequired
  1063. );
  1064. if (RegError != ERROR_SUCCESS) {
  1065. SC_LOG3(ERROR, "ScReadStartType: ScRegQueryValueExW of " FORMAT_LPWSTR
  1066. " failed "
  1067. FORMAT_LONG ", BytesRequired " FORMAT_DWORD "\n",
  1068. START_VALUENAME_W, RegError, BytesRequired);
  1069. }
  1070. return (ScWinRegErrorToApiStatus( RegError ));
  1071. } // ScReadStartType
  1072. DWORD
  1073. ScReadTag(
  1074. IN HKEY ServiceNameKey,
  1075. OUT LPDWORD TagPtr
  1076. )
  1077. /*++
  1078. Routine Description:
  1079. Arguments:
  1080. Return Value:
  1081. --*/
  1082. {
  1083. DWORD BytesRequired = sizeof(DWORD);
  1084. LONG RegError;
  1085. SC_ASSERT( ServiceNameKey != NULL );
  1086. SC_ASSERT( TagPtr != NULL );
  1087. *TagPtr = 0;
  1088. RegError = ScRegQueryValueExW(
  1089. ServiceNameKey,
  1090. TAG_VALUENAME_W,
  1091. NULL,
  1092. NULL,
  1093. (LPBYTE) TagPtr,
  1094. &BytesRequired
  1095. );
  1096. if (RegError != ERROR_SUCCESS) {
  1097. SC_LOG3(CONFIG, "ScReadTag: ScRegQueryValueExW of " FORMAT_LPWSTR
  1098. " failed "
  1099. FORMAT_LONG ", BytesRequired " FORMAT_DWORD "\n",
  1100. START_VALUENAME_W, RegError, BytesRequired);
  1101. }
  1102. return (ScWinRegErrorToApiStatus( RegError ));
  1103. } // ScReadTag
  1104. DWORD
  1105. ScReadErrorControl(
  1106. IN HKEY ServiceNameKey,
  1107. OUT LPDWORD ErrorControlPtr
  1108. )
  1109. /*++
  1110. Routine Description:
  1111. Arguments:
  1112. Return Value:
  1113. --*/
  1114. {
  1115. DWORD BytesRequired = sizeof(DWORD);
  1116. LONG RegError;
  1117. SC_ASSERT( ServiceNameKey != NULL );
  1118. SC_ASSERT( ErrorControlPtr != NULL );
  1119. *ErrorControlPtr = 0;
  1120. RegError = ScRegQueryValueExW(
  1121. ServiceNameKey,
  1122. ERRORCONTROL_VALUENAME_W,
  1123. NULL,
  1124. NULL,
  1125. (LPBYTE) ErrorControlPtr,
  1126. &BytesRequired
  1127. );
  1128. if (RegError != ERROR_SUCCESS) {
  1129. SC_LOG3(ERROR, "ScReadErrorControl: ScRegQueryValueExW of " FORMAT_LPWSTR
  1130. " failed "
  1131. FORMAT_LONG ", BytesRequired " FORMAT_DWORD "\n",
  1132. ERRORCONTROL_VALUENAME_W, RegError, BytesRequired);
  1133. }
  1134. return (ScWinRegErrorToApiStatus( RegError ));
  1135. } // ScReadErrorControl
  1136. DWORD
  1137. ScReadFailureActions(
  1138. IN HKEY ServiceNameKey,
  1139. OUT LPSERVICE_FAILURE_ACTIONS_WOW64 * FailActPtr,
  1140. IN OUT LPDWORD TotalBytes OPTIONAL
  1141. )
  1142. /*++
  1143. Routine Description:
  1144. This function attempts to read the value for the non-string portion
  1145. of the service's failure actions configuration from the registry.
  1146. If the value does not exist, or is invalid, this function sets the
  1147. pointer to the value to NULL and returns NO_ERROR. If any other error
  1148. occurs, the error is returned.
  1149. NOTE: On return from this function, a buffer with the value will be
  1150. allocated, or the pointer will be NULL. If a buffer is allocated,
  1151. it contains both the fixed-size structure and the array of actions.
  1152. Arguments:
  1153. ServiceNameKey - This is the Service's Key handle.
  1154. FailActPtr - This is a pointer to a location where the pointer to
  1155. the failure actions information is to be placed.
  1156. TotalBytes - If present, this DWORD is INCREMENTED by the number of bytes
  1157. needed to store the string.
  1158. Return Value:
  1159. --*/
  1160. {
  1161. DWORD BytesReturned;
  1162. LONG RegError = ScAllocateAndReadConfigValue(
  1163. ServiceNameKey,
  1164. FAILUREACTIONS_VALUENAME_W,
  1165. (LPWSTR *) FailActPtr,
  1166. &BytesReturned
  1167. );
  1168. if (RegError != ERROR_SUCCESS)
  1169. {
  1170. if (RegError == ERROR_FILE_NOT_FOUND)
  1171. {
  1172. RegError = NO_ERROR;
  1173. }
  1174. *FailActPtr = NULL;
  1175. return RegError;
  1176. }
  1177. //
  1178. // Validate the value read. Treat a bogus value as no value.
  1179. //
  1180. if ((BytesReturned < sizeof(SERVICE_FAILURE_ACTIONS_WOW64)) ||
  1181. (BytesReturned != sizeof(SERVICE_FAILURE_ACTIONS_WOW64) +
  1182. (*FailActPtr)->cActions * sizeof(SC_ACTION)))
  1183. {
  1184. LocalFree(*FailActPtr);
  1185. *FailActPtr = NULL;
  1186. return NO_ERROR;
  1187. }
  1188. //
  1189. // Fix up the pointer to the array.
  1190. //
  1191. (*FailActPtr)->dwsaActionsOffset = sizeof(SERVICE_FAILURE_ACTIONS_WOW64);
  1192. //
  1193. // Increment the total number of bytes used.
  1194. //
  1195. if (ARGUMENT_PRESENT(TotalBytes))
  1196. {
  1197. *TotalBytes += BytesReturned;
  1198. }
  1199. return NO_ERROR;
  1200. } // ScReadFailureActions
  1201. DWORD
  1202. ScReadOptionalString(
  1203. IN HKEY ServiceNameKey,
  1204. IN LPCWSTR ValueName,
  1205. OUT LPWSTR *Value,
  1206. IN OUT LPDWORD TotalBytes OPTIONAL
  1207. )
  1208. /*++
  1209. Routine Description:
  1210. This function attempts to read the value for the optional string
  1211. configuration parameter from the registry. If this read fails because
  1212. the value does no exist, then this function sets the pointer to the
  1213. value string to NULL, and returns NO_ERROR. If any other error occurs,
  1214. the error is returned.
  1215. NOTE: On successful return from this function, a buffer with the
  1216. string value will be allocated, or the pointer will be NULL.
  1217. If a string is returned, it is guaranteed to be non-empty and
  1218. null-terminated (if the registry value was not null-terminated,
  1219. its last character will be overwritten).
  1220. Arguments:
  1221. ServiceNameKey - This is the Service's Key handle.
  1222. ValueName - Name of the registry value from which to read.
  1223. Value - This is a pointer to a location where the pointer to the
  1224. string is to be placed.
  1225. TotalBytes - If present, this DWORD is INCREMENTED by the number of bytes
  1226. needed to store the string.
  1227. Return Value:
  1228. --*/
  1229. {
  1230. DWORD BytesReturned;
  1231. LONG RegError = ScAllocateAndReadConfigValue(
  1232. ServiceNameKey,
  1233. ValueName,
  1234. Value,
  1235. &BytesReturned
  1236. );
  1237. if (RegError != ERROR_SUCCESS)
  1238. {
  1239. // Nothing read from the registry.
  1240. if (RegError == ERROR_FILE_NOT_FOUND)
  1241. {
  1242. RegError = NO_ERROR;
  1243. }
  1244. *Value = NULL;
  1245. BytesReturned = 0;
  1246. }
  1247. else
  1248. {
  1249. // We read something from the registry. Make sure it's
  1250. // null-terminated.
  1251. if (BytesReturned < sizeof(L" "))
  1252. {
  1253. LocalFree(*Value);
  1254. *Value = NULL;
  1255. BytesReturned = 0;
  1256. }
  1257. else
  1258. {
  1259. (*Value)[BytesReturned/sizeof(WCHAR) - 1] = L'\0';
  1260. }
  1261. }
  1262. //
  1263. // Increment the total number of bytes used.
  1264. //
  1265. if (ARGUMENT_PRESENT(TotalBytes))
  1266. {
  1267. *TotalBytes += (BytesReturned/sizeof(WCHAR)) * sizeof(WCHAR);
  1268. }
  1269. return RegError;
  1270. } // ScReadOptionalString
  1271. DWORD
  1272. ScReadStartName(
  1273. IN HKEY ServiceNameKey,
  1274. OUT LPWSTR *AccountName
  1275. )
  1276. /*++
  1277. Routine Description:
  1278. Arguments:
  1279. Return Value:
  1280. --*/
  1281. {
  1282. return ScAllocateAndReadConfigValue(
  1283. ServiceNameKey,
  1284. STARTNAME_VALUENAME_W,
  1285. AccountName,
  1286. NULL
  1287. );
  1288. } // ScReadStartName
  1289. DWORD
  1290. ScReadSd(
  1291. IN HKEY ServiceNameKey,
  1292. OUT PSECURITY_DESCRIPTOR *Sd
  1293. )
  1294. /*++
  1295. Routine Description:
  1296. This function reads the security descriptor for the service
  1297. Arguments:
  1298. Return Value:
  1299. --*/
  1300. {
  1301. LONG RegError;
  1302. HKEY SecurityKey;
  1303. DWORD status;
  1304. //
  1305. // Open the Security Sub-key (under the services key).
  1306. // NOTE: This key may not exist, and that is ok.
  1307. //
  1308. RegError = ScOpenSecurityKey(
  1309. ServiceNameKey,
  1310. KEY_READ,
  1311. FALSE, // Do not create if missing.
  1312. &SecurityKey);
  1313. if (RegError != NO_ERROR) {
  1314. SC_LOG1(TRACE,"ScReadSd:ScOpenSecurityKey Failed %d\n",RegError);
  1315. return(ScWinRegErrorToApiStatus(RegError));
  1316. }
  1317. //
  1318. // Read the Security Descriptor value stored under the security key.
  1319. //
  1320. status = ScAllocateAndReadConfigValue(
  1321. SecurityKey,
  1322. SD_VALUENAME_W,
  1323. (LPWSTR *) Sd,
  1324. NULL);
  1325. if (status == NO_ERROR)
  1326. {
  1327. if (RtlValidSecurityDescriptor(*Sd))
  1328. {
  1329. status = NO_ERROR;
  1330. }
  1331. else
  1332. {
  1333. LocalFree(*Sd);
  1334. *Sd = NULL;
  1335. status = ERROR_FILE_NOT_FOUND;
  1336. }
  1337. }
  1338. RegCloseKey(SecurityKey);
  1339. return status;
  1340. } // ScReadSd
  1341. DWORD
  1342. ScWriteDependencies(
  1343. IN HKEY ServiceNameKey,
  1344. IN LPWSTR Dependencies,
  1345. IN DWORD DependSize
  1346. )
  1347. /*++
  1348. Routine Description:
  1349. Arguments:
  1350. Return Value:
  1351. --*/
  1352. {
  1353. LONG RegError;
  1354. LPWSTR DependOnService;
  1355. LPWSTR DependOnGroup;
  1356. LPWSTR DestService;
  1357. LPWSTR DestGroup;
  1358. DWORD DependencyLength;
  1359. SC_ASSERT( ServiceNameKey != NULL );
  1360. SC_ASSERT( Dependencies != NULL );
  1361. //
  1362. // If the dependencies string is empty, then delete the dependency
  1363. // values from the registry and return. If errors occur during the
  1364. // delete, we ignore them. It could be that there aren't any existing
  1365. // dependencies, so that the depend values don't exist to begin with.
  1366. // Also, it the delete fails, we can't do anything about it anyway.
  1367. //
  1368. if (*Dependencies == L'\0') {
  1369. RegError = ScRegDeleteValue(ServiceNameKey,DEPENDONSERVICE_VALUENAME_W);
  1370. if ((RegError != ERROR_SUCCESS) && (RegError != ERROR_FILE_NOT_FOUND)) {
  1371. SC_LOG1(ERROR, "Failed to delete DependOnService Value "
  1372. "" FORMAT_LONG "\n",RegError);
  1373. }
  1374. RegError = ScRegDeleteValue(ServiceNameKey,DEPENDONGROUP_VALUENAME_W);
  1375. if ((RegError != ERROR_SUCCESS) && (RegError != ERROR_FILE_NOT_FOUND)) {
  1376. SC_LOG1(ERROR, "Failed to delete DependOnGroup Value "
  1377. "" FORMAT_LONG "\n",RegError);
  1378. }
  1379. return(NO_ERROR);
  1380. }
  1381. //
  1382. // Allocate a buffer which is twice the size of DependSize so that
  1383. // we can split the Dependencies array string into a DependOnService,
  1384. // and a DependOnGroup array strings.
  1385. //
  1386. if ((DependOnService = (LPWSTR)LocalAlloc(
  1387. LMEM_ZEROINIT,
  1388. (UINT) (2 * DependSize)
  1389. )) == NULL) {
  1390. SC_LOG1(ERROR, "ScWriteDependencies: LocalAlloc failed " FORMAT_DWORD "\n",
  1391. GetLastError());
  1392. return ERROR_NOT_ENOUGH_MEMORY;
  1393. }
  1394. DependOnGroup = (LPWSTR) ((DWORD_PTR) DependOnService + DependSize);
  1395. DestService = DependOnService;
  1396. DestGroup = DependOnGroup;
  1397. while ((*Dependencies) != 0) {
  1398. if (*Dependencies == SC_GROUP_IDENTIFIERW) {
  1399. Dependencies++;
  1400. DependencyLength = (DWORD) wcslen(Dependencies) + 1;
  1401. wcscpy(DestGroup, Dependencies);
  1402. DestGroup += DependencyLength;
  1403. }
  1404. else {
  1405. DependencyLength = (DWORD) wcslen(Dependencies) + 1;
  1406. wcscpy(DestService, Dependencies);
  1407. DestService += DependencyLength;
  1408. }
  1409. Dependencies += DependencyLength;
  1410. }
  1411. //
  1412. // Write the DependOnService array string
  1413. //
  1414. RegError = ScRegSetValueExW(
  1415. ServiceNameKey, // open handle (to section)
  1416. DEPENDONSERVICE_VALUENAME_W,
  1417. 0,
  1418. REG_MULTI_SZ, // type (NULL-NULL UNICODE string)
  1419. (LPBYTE) DependOnService, // data
  1420. ScWStrArraySize(DependOnService) // byte count for data
  1421. );
  1422. if (RegError != ERROR_SUCCESS) {
  1423. #if DBG
  1424. SC_LOG1(ERROR, "ScWriteDependOnService: ScRegSetValueExW returned "
  1425. FORMAT_LONG "\n", RegError);
  1426. ScDisplayWStrArray(DependOnService);
  1427. #endif
  1428. goto CleanExit;
  1429. }
  1430. //
  1431. // Write the DependOnGroup array string
  1432. //
  1433. RegError = ScRegSetValueExW(
  1434. ServiceNameKey, // open handle (to section)
  1435. DEPENDONGROUP_VALUENAME_W,
  1436. 0,
  1437. REG_MULTI_SZ, // type (NULL-NULL UNICODE string)
  1438. (LPBYTE) DependOnGroup, // data
  1439. ScWStrArraySize(DependOnGroup) // byte count for data
  1440. );
  1441. if (RegError != ERROR_SUCCESS) {
  1442. #if DBG
  1443. SC_LOG1(ERROR, "ScWriteDependOnGroup: ScRegSetValueExW returned "
  1444. FORMAT_LONG "\n", RegError);
  1445. ScDisplayWStrArray(DependOnGroup);
  1446. #endif
  1447. goto CleanExit;
  1448. }
  1449. CleanExit:
  1450. LocalFree(DependOnService);
  1451. if (RegError != NO_ERROR) {
  1452. SC_LOG2(ERROR, "ScWriteDependencies (%ws) Error %d \n",
  1453. Dependencies,RegError);
  1454. }
  1455. return (ScWinRegErrorToApiStatus( RegError ));
  1456. } // ScWriteDependencies
  1457. DWORD
  1458. ScWriteOptionalString(
  1459. IN HKEY ServiceNameKey,
  1460. IN LPCWSTR ValueName,
  1461. IN LPCWSTR Value
  1462. )
  1463. /*++
  1464. Routine Description:
  1465. This function writes the specified string value to the registry for the
  1466. particular key. If the value is a NULL pointer, we don't do anything. If
  1467. the value is an empty string, we delete the registry value.
  1468. Arguments:
  1469. Return Value:
  1470. --*/
  1471. {
  1472. LONG RegError;
  1473. SC_ASSERT( ServiceNameKey != NULL );
  1474. SC_ASSERT( ValueName != NULL && ValueName[0] != L'\0' );
  1475. //
  1476. // A NULL value means no change.
  1477. //
  1478. if (Value == NULL)
  1479. {
  1480. return NO_ERROR;
  1481. }
  1482. if (Value[0] != L'\0')
  1483. {
  1484. //
  1485. // Write the Value
  1486. //
  1487. RegError = ScRegSetValueExW(
  1488. ServiceNameKey, // open key handle
  1489. ValueName, // value name
  1490. 0,
  1491. REG_SZ, // type (zero-terminated UNICODE)
  1492. (LPBYTE) Value, // data
  1493. (DWORD) WCSSIZE(Value)); // byte count for data
  1494. if (RegError != ERROR_SUCCESS)
  1495. {
  1496. SC_LOG3(ERROR, "ScWriteStringParm: ScRegSetValueExW of \"%ws\" "
  1497. "to reg value %ws failed %ld\n",
  1498. Value, ValueName, RegError);
  1499. }
  1500. return RegError;
  1501. }
  1502. else
  1503. {
  1504. //
  1505. // The value is specifically being cleared. So we
  1506. // want to delete the registry value.
  1507. //
  1508. RegError = ScRegDeleteValue(ServiceNameKey, ValueName);
  1509. if (RegError != ERROR_SUCCESS)
  1510. {
  1511. if (RegError == ERROR_FILE_NOT_FOUND)
  1512. {
  1513. RegError = ERROR_SUCCESS;
  1514. }
  1515. else
  1516. {
  1517. SC_LOG2(ERROR, "ScWriteStringParm: ScRegDeleteValue of "
  1518. "reg value %ws failed %ld\n", ValueName, RegError);
  1519. }
  1520. }
  1521. return RegError;
  1522. }
  1523. } // ScWriteOptionalString
  1524. DWORD
  1525. ScWriteFailureActions(
  1526. IN HKEY ServiceNameKey,
  1527. IN LPSERVICE_FAILURE_ACTIONSW psfa
  1528. )
  1529. /*++
  1530. Routine Description:
  1531. This function writes ONLY the non-string fields of the
  1532. SERVICE_FAILURE_ACTIONS structure to the registry for the specified
  1533. key. If the structure is a NULL pointer, we don't do anything. If
  1534. the structure contains no failure actions, we delete the registry value.
  1535. Arguments:
  1536. Return Value:
  1537. --*/
  1538. {
  1539. SC_ASSERT( ServiceNameKey != NULL );
  1540. //
  1541. // A NULL structure or NULL array means no change.
  1542. //
  1543. if (psfa == NULL || psfa->lpsaActions == NULL)
  1544. {
  1545. return NO_ERROR;
  1546. }
  1547. if (psfa->cActions != 0)
  1548. {
  1549. //
  1550. // Write the Value
  1551. //
  1552. //
  1553. // Combine the SERVICE_FAILURE_ACTIONSW structure and the
  1554. // array of SC_ACTION into a contiguous block.
  1555. // The structure includes the string pointers, though we don't
  1556. // actually use them when reading the structure back.
  1557. //
  1558. // Always write this structure out with 32-bit "pointers" since
  1559. // that's the format we expect when we read it in (required for
  1560. // backwards compatibility).
  1561. //
  1562. DWORD cbValueLen = sizeof(SERVICE_FAILURE_ACTIONS_WOW64) +
  1563. psfa->cActions * sizeof(SC_ACTION);
  1564. LPSERVICE_FAILURE_ACTIONS_WOW64 psfaValue =
  1565. (LPSERVICE_FAILURE_ACTIONS_WOW64) LocalAlloc(0, cbValueLen);
  1566. if (psfaValue == NULL)
  1567. {
  1568. return (GetLastError());
  1569. }
  1570. psfaValue->dwResetPeriod = psfa->dwResetPeriod;
  1571. psfaValue->dwRebootMsgOffset = psfa->lpRebootMsg ? 1 : 0;
  1572. psfaValue->dwCommandOffset = psfa->lpCommand ? 1 : 0;
  1573. psfaValue->cActions = psfa->cActions;
  1574. RtlCopyMemory(psfaValue + 1,
  1575. psfa->lpsaActions,
  1576. psfa->cActions * sizeof(SC_ACTION));
  1577. //
  1578. // Write the block to the registry
  1579. //
  1580. LONG RegError = ScRegSetValueExW(
  1581. ServiceNameKey,
  1582. FAILUREACTIONS_VALUENAME_W,
  1583. 0,
  1584. REG_BINARY,
  1585. psfaValue,
  1586. cbValueLen
  1587. );
  1588. if (RegError != ERROR_SUCCESS)
  1589. {
  1590. SC_LOG(ERROR, "ScWriteFailureActions: ScRegSetValueExW failed %ld\n",
  1591. RegError);
  1592. }
  1593. LocalFree(psfaValue);
  1594. return RegError;
  1595. }
  1596. else
  1597. {
  1598. //
  1599. // There are no failure actions to store. So we
  1600. // want to delete the registry value.
  1601. //
  1602. LONG RegError = ScRegDeleteValue(
  1603. ServiceNameKey,
  1604. FAILUREACTIONS_VALUENAME_W
  1605. );
  1606. if (RegError != ERROR_SUCCESS)
  1607. {
  1608. if (RegError == ERROR_FILE_NOT_FOUND)
  1609. {
  1610. RegError = ERROR_SUCCESS;
  1611. }
  1612. else
  1613. {
  1614. SC_LOG(ERROR, "ScWriteFailureActions: ScRegDeleteValue failed %ld\n",
  1615. RegError);
  1616. }
  1617. }
  1618. return RegError;
  1619. }
  1620. } // ScWriteFailureActions
  1621. DWORD
  1622. ScWriteErrorControl(
  1623. IN HKEY ServiceNameKey,
  1624. IN DWORD ErrorControl
  1625. )
  1626. /*++
  1627. Routine Description:
  1628. Arguments:
  1629. Return Value:
  1630. --*/
  1631. {
  1632. LONG RegError;
  1633. SC_ASSERT( ServiceNameKey != NULL );
  1634. SC_ASSERT( !ERROR_CONTROL_INVALID( ErrorControl ) );
  1635. RegError = ScRegSetValueExW(
  1636. ServiceNameKey, // key
  1637. ERRORCONTROL_VALUENAME_W, // value name
  1638. 0,
  1639. REG_DWORD, // data type
  1640. (LPBYTE) & ErrorControl, // data
  1641. sizeof(DWORD) ); // byte count
  1642. SC_ASSERT( RegError == ERROR_SUCCESS );
  1643. return (ScWinRegErrorToApiStatus( RegError ) );
  1644. } // ScWriteErrorControl
  1645. DWORD
  1646. ScWriteSd(
  1647. IN HKEY ServiceNameKey,
  1648. IN PSECURITY_DESCRIPTOR Security
  1649. )
  1650. /*++
  1651. Routine Description:
  1652. This routine write the specified security descriptor to the registry.
  1653. Arguments:
  1654. Return Value:
  1655. --*/
  1656. {
  1657. LONG RegError;
  1658. HKEY SecurityKey;
  1659. ULONG SdLength;
  1660. SC_ASSERT( ServiceNameKey != NULL );
  1661. if (Security == NULL) {
  1662. return NO_ERROR;
  1663. }
  1664. SdLength = RtlLengthSecurityDescriptor(Security);
  1665. if (SdLength == 0) {
  1666. return(NO_ERROR);
  1667. }
  1668. SC_LOG1(SECURITY, "ScWriteSd: Size of security descriptor %lu\n", SdLength);
  1669. //
  1670. // Open the Security Sub-key (under the service key).
  1671. //
  1672. RegError = ScOpenSecurityKey(
  1673. ServiceNameKey,
  1674. KEY_READ | KEY_WRITE,
  1675. TRUE, // CreateIfMissing
  1676. &SecurityKey);
  1677. if (RegError != NO_ERROR) {
  1678. SC_LOG1(ERROR,"ScWriteSd:ScOpenSecurityKey Failed %d\n",RegError);
  1679. }
  1680. else
  1681. {
  1682. //
  1683. // Write the Security Descriptor to the Security Value in the Security
  1684. // Key.
  1685. //
  1686. RegError = ScRegSetValueExW(
  1687. SecurityKey, // key
  1688. SD_VALUENAME_W, // value name
  1689. 0, // reserved
  1690. REG_BINARY, // data type
  1691. (LPBYTE) Security, // data
  1692. SdLength // byte count
  1693. );
  1694. if (RegError != NO_ERROR) {
  1695. SC_LOG1(ERROR,"ScWriteSd:ScRegSetValueExW Failed %d\n",RegError);
  1696. }
  1697. RegCloseKey(SecurityKey);
  1698. }
  1699. return (ScWinRegErrorToApiStatus( RegError ) );
  1700. } // ScWriteSd
  1701. #ifdef USE_GROUPS
  1702. DWORD
  1703. ScWriteGroupForThisService(
  1704. IN HKEY ServiceNameKey,
  1705. IN LPWSTR Group
  1706. )
  1707. /*++
  1708. Routine Description:
  1709. Arguments:
  1710. Return Value:
  1711. --*/
  1712. {
  1713. LONG RegError;
  1714. SC_ASSERT( ServiceNameKey != NULL );
  1715. SC_ASSERT( Group != NULL );
  1716. //
  1717. // Write the group
  1718. //
  1719. RegError = ScRegSetValueExW(
  1720. ServiceNameKey, // open handle (to section)
  1721. GROUP_VALUENAME_W, // value name
  1722. 0,
  1723. REG_SZ, // type (zero-terminated UNICODE)
  1724. (LPBYTE) Group, // data
  1725. (DWORD) WCSSIZE(Group)); // byte count for data
  1726. if (RegError != ERROR_SUCCESS) {
  1727. SC_LOG2(ERROR, "ScWriteGroupForThisService: ScRegSetValueExW of "
  1728. FORMAT_LPWSTR " failed " FORMAT_LONG "\n",
  1729. Group, RegError);
  1730. }
  1731. return (ScWinRegErrorToApiStatus( RegError ) );
  1732. } // ScWriteGroupForThisService
  1733. #endif // USE_GROUPS
  1734. DWORD
  1735. ScWriteImageFileName(
  1736. IN HKEY hServiceKey,
  1737. IN LPWSTR ImageFileName
  1738. )
  1739. /*++
  1740. Routine Description:
  1741. Arguments:
  1742. Return Value:
  1743. --*/
  1744. {
  1745. LONG RegError;
  1746. SC_ASSERT( hServiceKey != NULL );
  1747. SC_ASSERT( ImageFileName != NULL );
  1748. //
  1749. // Write the binary path name
  1750. //
  1751. RegError = ScRegSetValueExW(
  1752. hServiceKey, // open handle (to section)
  1753. IMAGE_VALUENAME_W, // value name
  1754. 0,
  1755. REG_EXPAND_SZ, // type (zero-terminated UNICODE)
  1756. (LPBYTE) ImageFileName, // data
  1757. (DWORD) WCSSIZE(ImageFileName)); // byte count for data
  1758. if (RegError != ERROR_SUCCESS) {
  1759. SC_LOG2(ERROR, "ScWriteImageFileName: ScRegSetValueExW of "
  1760. FORMAT_LPWSTR " failed " FORMAT_LONG "\n",
  1761. ImageFileName, RegError);
  1762. }
  1763. SC_ASSERT( RegError == ERROR_SUCCESS );
  1764. return ( (DWORD) RegError );
  1765. } // ScWriteImageFileName
  1766. DWORD
  1767. ScWriteServiceType(
  1768. IN HKEY hServiceKey,
  1769. IN DWORD dwServiceType
  1770. )
  1771. /*++
  1772. Routine Description:
  1773. Arguments:
  1774. Return Value:
  1775. --*/
  1776. {
  1777. LONG RegError;
  1778. SC_ASSERT( hServiceKey != NULL );
  1779. SC_ASSERT( !SERVICE_TYPE_INVALID( dwServiceType ) );
  1780. SC_ASSERT( dwServiceType != SERVICE_WIN32 ); // Don't write ambig info.
  1781. RegError = ScRegSetValueExW(
  1782. hServiceKey, // key
  1783. SERVICETYPE_VALUENAME_W, // value name
  1784. 0,
  1785. REG_DWORD, // data type
  1786. (LPBYTE) & dwServiceType, // data
  1787. sizeof(DWORD) ); // byte count
  1788. SC_ASSERT( RegError == ERROR_SUCCESS );
  1789. return (ScWinRegErrorToApiStatus( RegError ) );
  1790. } // ScWriteServiceType
  1791. DWORD
  1792. ScWriteStartType(
  1793. IN HKEY hServiceKey,
  1794. IN DWORD dwStartType
  1795. )
  1796. /*++
  1797. Routine Description:
  1798. Arguments:
  1799. Return Value:
  1800. --*/
  1801. {
  1802. LONG RegError;
  1803. SC_ASSERT( hServiceKey != NULL );
  1804. SC_ASSERT( !START_TYPE_INVALID( dwStartType ) );
  1805. RegError = ScRegSetValueExW(
  1806. hServiceKey, // key
  1807. START_VALUENAME_W, // value name
  1808. 0,
  1809. REG_DWORD, // data type
  1810. (LPBYTE) &dwStartType, // data
  1811. sizeof( DWORD ) ); // byte count
  1812. SC_ASSERT( RegError == ERROR_SUCCESS );
  1813. return (ScWinRegErrorToApiStatus( RegError ) );
  1814. } // ScWriteStartType
  1815. DWORD
  1816. ScWriteTag(
  1817. IN HKEY hServiceKey,
  1818. IN DWORD dwTag
  1819. )
  1820. /*++
  1821. Routine Description:
  1822. Arguments:
  1823. Return Value:
  1824. --*/
  1825. {
  1826. LONG RegError;
  1827. SC_ASSERT( hServiceKey != NULL );
  1828. RegError = ScRegSetValueExW(
  1829. hServiceKey, // key
  1830. TAG_VALUENAME_W, // value name
  1831. 0,
  1832. REG_DWORD, // data type
  1833. (LPBYTE) &dwTag, // data
  1834. sizeof( DWORD ) ); // byte count
  1835. SC_ASSERT( RegError == ERROR_SUCCESS );
  1836. return (ScWinRegErrorToApiStatus( RegError ) );
  1837. } // ScWriteTag
  1838. VOID
  1839. ScDeleteTag(
  1840. IN HKEY hServiceKey
  1841. )
  1842. /*++
  1843. Routine Description:
  1844. Arguments:
  1845. Return Value:
  1846. --*/
  1847. {
  1848. LONG RegError;
  1849. SC_ASSERT( hServiceKey != NULL );
  1850. RegError = ScRegDeleteValue(
  1851. hServiceKey, // key
  1852. TAG_VALUENAME_W); // value name
  1853. SC_LOG1(DEPEND, "ScRegDeleteValue of Tag returns %ld\n", RegError);
  1854. } // ScDeleteTag
  1855. DWORD
  1856. ScWriteStartName(
  1857. IN HKEY ServiceNameKey,
  1858. IN LPWSTR StartName
  1859. )
  1860. /*++
  1861. Routine Description:
  1862. Arguments:
  1863. Return Value:
  1864. --*/
  1865. {
  1866. LONG RegError;
  1867. SC_ASSERT( ServiceNameKey != NULL );
  1868. SC_ASSERT( StartName != NULL );
  1869. //
  1870. // Write the StartName
  1871. //
  1872. RegError = ScRegSetValueExW(
  1873. ServiceNameKey, // open handle (to section)
  1874. STARTNAME_VALUENAME_W, // value name
  1875. 0,
  1876. REG_SZ, // type (zero-terminated UNICODE)
  1877. (LPBYTE) StartName, // data
  1878. (DWORD) WCSSIZE(StartName)); // byte count for data
  1879. if (RegError != ERROR_SUCCESS) {
  1880. SC_LOG2(ERROR, "ScWriteStartName: ScRegSetValueExW of " FORMAT_LPWSTR
  1881. " failed " FORMAT_LONG "\n",
  1882. StartName, RegError);
  1883. }
  1884. SC_ASSERT( RegError == ERROR_SUCCESS );
  1885. return (ScWinRegErrorToApiStatus( RegError ) );
  1886. } // ScWriteStartName
  1887. DWORD
  1888. ScReadServiceConfig(
  1889. IN HKEY ServiceNameKey,
  1890. IN LPWSTR ServiceName
  1891. )
  1892. /*++
  1893. Routine Description:
  1894. This function reads the service configuration information and
  1895. creates a service record in memory with the information.
  1896. Arguments:
  1897. ServiceNameKey - Supplies opened handle to the service key to read
  1898. from.
  1899. ServiceName - Supplies name of the service.
  1900. Return Value:
  1901. TRUE - Service record is created successfully.
  1902. FALSE - Error in creating the service record. If an error occurs here,
  1903. it is generally considered a fatal error which will cause the
  1904. service controller to fail to start.
  1905. Note:
  1906. The GroupListLock must be held exclusively prior to calling this routine.
  1907. --*/
  1908. {
  1909. DWORD status;
  1910. DWORD StartType;
  1911. DWORD ServiceType;
  1912. DWORD ErrorControl;
  1913. DWORD Tag;
  1914. LPWSTR Group = NULL;
  1915. LPWSTR Dependencies = NULL;
  1916. LPWSTR DisplayName=NULL;
  1917. PSECURITY_DESCRIPTOR Sd = NULL;
  1918. LPSERVICE_RECORD ServiceRecord;
  1919. SC_ASSERT(ScGroupListLock.HaveExclusive());
  1920. //
  1921. // Get the Service Type information from the registry
  1922. //
  1923. status = ScReadServiceType(ServiceNameKey, &ServiceType);
  1924. if (status != NO_ERROR) {
  1925. SC_LOG1(TRACE, "Ignored " FORMAT_LPWSTR ". No ServiceType\n",
  1926. ServiceName);
  1927. return NO_ERROR; // Skip service entry and ignore error.
  1928. }
  1929. //
  1930. // If service type is not one of type SERVICE_WIN32 or SERVICE_DRIVER,
  1931. // do not bother saving it in a service record because it's data
  1932. // for services.
  1933. //
  1934. if (SERVICE_TYPE_INVALID(ServiceType)) {
  1935. if ((ServiceType != SERVICE_ADAPTER) &&
  1936. (ServiceType != SERVICE_RECOGNIZER_DRIVER)) {
  1937. SC_LOG2(ERROR, "Ignored " FORMAT_LPWSTR ". Invalid ServiceType "
  1938. FORMAT_HEX_DWORD "\n", ServiceName, ServiceType);
  1939. }
  1940. return NO_ERROR;
  1941. }
  1942. SC_LOG1(CONFIG, " ServiceType " FORMAT_HEX_DWORD "\n", ServiceType);
  1943. //
  1944. // Read the StartType value
  1945. //
  1946. status = ScReadStartType(ServiceNameKey, &StartType);
  1947. if (status != NO_ERROR) {
  1948. SC_LOG1(ERROR, "Ignored " FORMAT_LPWSTR ". No StartType\n",
  1949. ServiceName);
  1950. return NO_ERROR; // Skip service entry and ignore error.
  1951. }
  1952. SC_LOG1(CONFIG, " StartType " FORMAT_HEX_DWORD "\n", StartType);
  1953. //
  1954. // Read the ErrorControl value
  1955. //
  1956. status = ScReadErrorControl(ServiceNameKey, &ErrorControl);
  1957. if (status != NO_ERROR) {
  1958. SC_LOG1(ERROR, "Ignored " FORMAT_LPWSTR ". No ErrorControl\n",
  1959. ServiceName);
  1960. return NO_ERROR; // Skip service entry and ignore error.
  1961. }
  1962. SC_LOG1(CONFIG, " ErrorControl " FORMAT_HEX_DWORD "\n", ErrorControl);
  1963. //
  1964. // Read the optional Tag value. 0 means no tag.
  1965. //
  1966. status = ScReadTag(ServiceNameKey, &Tag);
  1967. if (status != NO_ERROR) {
  1968. Tag = 0;
  1969. }
  1970. //
  1971. // Read the Group value
  1972. //
  1973. if (ScAllocateAndReadConfigValue(
  1974. ServiceNameKey,
  1975. GROUP_VALUENAME_W,
  1976. &Group,
  1977. NULL
  1978. ) != NO_ERROR) {
  1979. Group = NULL;
  1980. }
  1981. else {
  1982. SC_LOG1(CONFIG, " Belongs to group " FORMAT_LPWSTR "\n", Group);
  1983. }
  1984. //
  1985. // Read the Dependencies
  1986. //
  1987. status = ScReadDependencies(ServiceNameKey, &Dependencies, ServiceName);
  1988. if (status != NO_ERROR) {
  1989. Dependencies = NULL;
  1990. }
  1991. //
  1992. // Read the security descriptor
  1993. //
  1994. if (ScReadSd(
  1995. ServiceNameKey,
  1996. &Sd
  1997. ) != NO_ERROR) {
  1998. Sd = NULL;
  1999. }
  2000. //
  2001. // Read the Display Name
  2002. // NOTE: If an error occurs, or the name doesn't exist, then a NULL
  2003. // pointer is returned from this call.
  2004. //
  2005. ScReadDisplayName(ServiceNameKey, &DisplayName);
  2006. //
  2007. // Get an exclusive lock on the database so we can read and
  2008. // make modifications.
  2009. //
  2010. SC_ASSERT(ScServiceListLock.HaveExclusive());
  2011. SC_ASSERT(ScServiceRecordLock.HaveExclusive());
  2012. //
  2013. // See if the service record already exists
  2014. //
  2015. status = ScGetNamedServiceRecord(
  2016. ServiceName,
  2017. &ServiceRecord
  2018. );
  2019. if (status == ERROR_SERVICE_DOES_NOT_EXIST) {
  2020. //
  2021. // Create a service record for this service
  2022. //
  2023. status = ScCreateServiceRecord(
  2024. ServiceName,
  2025. &ServiceRecord
  2026. );
  2027. }
  2028. if (status != NO_ERROR) {
  2029. goto CleanExit;
  2030. }
  2031. //
  2032. // Insert the config information into the service record
  2033. //
  2034. status = ScAddConfigInfoServiceRecord(
  2035. ServiceRecord,
  2036. ServiceType,
  2037. StartType,
  2038. ErrorControl,
  2039. Group,
  2040. Tag,
  2041. Dependencies,
  2042. DisplayName,
  2043. Sd
  2044. );
  2045. if (status != NO_ERROR) {
  2046. //
  2047. // Fail to set meaningful data into service record. Remove the service
  2048. // record from the service record list and delete it. This is not
  2049. // a fatal error. Instead, we just leave this entry out of the
  2050. // database.
  2051. //
  2052. REMOVE_FROM_LIST(ServiceRecord);
  2053. ScFreeServiceRecord(ServiceRecord);
  2054. status = NO_ERROR;
  2055. }
  2056. else {
  2057. //
  2058. // Should the service be deleted?
  2059. // The service entry in the registry cannot be deleted while we
  2060. // are enumerating services, therefore we must mark it and delete it
  2061. // later.
  2062. //
  2063. if (ScDeleteFlagIsSet(ServiceNameKey)) {
  2064. SC_LOG(TRACE,"ScReadServiceConfig: %ws service marked for delete\n",
  2065. ServiceRecord->ServiceName);
  2066. SET_DELETE_FLAG(ServiceRecord);
  2067. }
  2068. }
  2069. CleanExit:
  2070. LocalFree(Group);
  2071. LocalFree(Dependencies);
  2072. LocalFree(DisplayName);
  2073. return status;
  2074. }
  2075. DWORD
  2076. ScAllocateAndReadConfigValue(
  2077. IN HKEY Key,
  2078. IN LPCWSTR ValueName,
  2079. OUT LPWSTR *Value,
  2080. OUT LPDWORD BytesReturned OPTIONAL
  2081. )
  2082. /*++
  2083. Routine Description:
  2084. This function allocates the output buffer and reads the requested
  2085. value from the registry into it. It is useful for reading string
  2086. data of undeterministic length.
  2087. Arguments:
  2088. Key - Supplies opened handle to the key to read from.
  2089. ValueName - Supplies name of the value to retrieve data.
  2090. Value - Returns a pointer to the output buffer which points to
  2091. the memory allocated and contains the data read in from the
  2092. registry.
  2093. Return Value:
  2094. ERROR_NOT_ENOUGH_MEMORY - Failed to create buffer to read value into.
  2095. Error from registry call.
  2096. --*/
  2097. {
  2098. LONG RegError;
  2099. DWORD NumRequired = 0;
  2100. WCHAR Temp[1];
  2101. LPWSTR TempValue = NULL;
  2102. DWORD ValueType;
  2103. DWORD CharsReturned;
  2104. //
  2105. // Set returned buffer pointer to NULL.
  2106. //
  2107. *Value = NULL;
  2108. RegError = ScRegQueryValueExW(
  2109. Key,
  2110. ValueName,
  2111. NULL,
  2112. &ValueType,
  2113. (LPBYTE) NULL,
  2114. &NumRequired
  2115. );
  2116. if (RegError != ERROR_SUCCESS && NumRequired > 0) {
  2117. SC_LOG3(CONFIG, "ScAllocateAndReadConfig: ScRegQueryKeyExW of "
  2118. FORMAT_LPWSTR " failed " FORMAT_LONG ", NumRequired "
  2119. FORMAT_DWORD "\n",
  2120. ValueName, RegError, NumRequired);
  2121. if ((TempValue = (LPWSTR)LocalAlloc(
  2122. LMEM_ZEROINIT,
  2123. (UINT) NumRequired
  2124. )) == NULL) {
  2125. SC_LOG2(ERROR, "ScAllocateAndReadConfig: LocalAlloc of size "
  2126. FORMAT_DWORD " failed " FORMAT_DWORD "\n",
  2127. NumRequired, GetLastError());
  2128. return ERROR_NOT_ENOUGH_MEMORY;
  2129. }
  2130. RegError = ScRegQueryValueExW(
  2131. Key,
  2132. ValueName,
  2133. NULL,
  2134. &ValueType,
  2135. (LPBYTE) TempValue,
  2136. &NumRequired
  2137. );
  2138. }
  2139. if (RegError != ERROR_SUCCESS) {
  2140. if (RegError != ERROR_FILE_NOT_FOUND) {
  2141. SC_LOG3(ERROR, "ScAllocateAndReadConfig: ScRegQueryKeyExW of "
  2142. FORMAT_LPWSTR " failed " FORMAT_LONG ", NumRequired "
  2143. FORMAT_DWORD "\n",
  2144. ValueName, RegError, NumRequired);
  2145. }
  2146. LocalFree(TempValue);
  2147. return (DWORD) RegError;
  2148. }
  2149. if (ValueType != REG_EXPAND_SZ || TempValue == NULL) {
  2150. *Value = TempValue;
  2151. if (BytesReturned != NULL) {
  2152. *BytesReturned = NumRequired;
  2153. }
  2154. return(NO_ERROR);
  2155. }
  2156. //
  2157. // If the ValueType is REG_EXPAND_SZ, then we must call the
  2158. // function to expand environment variables.
  2159. //
  2160. SC_LOG1(CONFIG,"ScAllocateAndReadConfig: Must expand the string for "
  2161. FORMAT_LPWSTR "\n", ValueName);
  2162. //
  2163. // Make the first call just to get the number of characters that
  2164. // will be returned.
  2165. //
  2166. NumRequired = ExpandEnvironmentStringsW (TempValue,Temp, 1);
  2167. if (NumRequired > 1) {
  2168. *Value = (LPWSTR)LocalAlloc(LMEM_ZEROINIT, (UINT) (NumRequired * sizeof(WCHAR)));
  2169. if (*Value == NULL) {
  2170. SC_LOG2(ERROR, "ScAllocateAndReadConfig: LocalAlloc of numChar= "
  2171. FORMAT_DWORD " failed " FORMAT_DWORD "\n",
  2172. NumRequired, GetLastError());
  2173. LocalFree(TempValue);
  2174. return(ERROR_NOT_ENOUGH_MEMORY);
  2175. }
  2176. CharsReturned = ExpandEnvironmentStringsW (
  2177. TempValue,
  2178. *Value,
  2179. NumRequired);
  2180. if (CharsReturned > NumRequired) {
  2181. SC_LOG1(ERROR, "ScAllocAndReadConfig: ExpandEnvironmentStrings "
  2182. " failed for " FORMAT_LPWSTR " \n", ValueName);
  2183. LocalFree(*Value);
  2184. *Value = NULL;
  2185. LocalFree(TempValue);
  2186. return(ERROR_NOT_ENOUGH_MEMORY);
  2187. }
  2188. LocalFree(TempValue);
  2189. if (BytesReturned != NULL) {
  2190. *BytesReturned = CharsReturned * sizeof(WCHAR);
  2191. }
  2192. return(NO_ERROR);
  2193. }
  2194. else {
  2195. //
  2196. // This call should have failed because of our ridiculously small
  2197. // buffer size.
  2198. //
  2199. SC_LOG0(ERROR, "ScAllocAndReadConfig: ExpandEnvironmentStrings "
  2200. " Should have failed because we gave it a BufferSize=1\n");
  2201. //
  2202. // This could happen if the string was a single byte long and
  2203. // didn't really have any environment values to expand. In this
  2204. // case, we return the TempValue buffer pointer.
  2205. //
  2206. *Value = TempValue;
  2207. if (BytesReturned != NULL) {
  2208. *BytesReturned = sizeof(WCHAR);
  2209. }
  2210. return(NO_ERROR);
  2211. }
  2212. }
  2213. DWORD
  2214. ScGetGroupVector(
  2215. IN LPWSTR Group,
  2216. OUT LPBYTE *Buffer,
  2217. OUT LPDWORD BufferSize
  2218. )
  2219. {
  2220. DWORD status;
  2221. LONG RegError;
  2222. HKEY VectorsKey;
  2223. //
  2224. // Open the HKEY_LOCAL_MACHINE
  2225. // System\CurrentControlSet\Control\GroupOrderList key.
  2226. //
  2227. RegError = ScRegOpenKeyExW(
  2228. HKEY_LOCAL_MACHINE,
  2229. GROUP_VECTORS_KEY,
  2230. REG_OPTION_NON_VOLATILE, // options
  2231. KEY_READ, // desired access
  2232. &VectorsKey
  2233. );
  2234. if (RegError != ERROR_SUCCESS) {
  2235. SC_LOG(ERROR, "ScGetGroupVector: Open of GroupOrderList key failed "
  2236. FORMAT_LONG "\n", RegError);
  2237. return (DWORD) RegError;
  2238. }
  2239. //
  2240. // Read the value with the valuename of the specified group
  2241. //
  2242. status = ScAllocateAndReadConfigValue(
  2243. VectorsKey,
  2244. Group,
  2245. (LPWSTR *)Buffer,
  2246. BufferSize
  2247. );
  2248. (void) ScRegCloseKey(VectorsKey);
  2249. return status;
  2250. }
  2251. BOOL
  2252. ScGetToken(
  2253. IN OUT LPWSTR *CurrentPtr,
  2254. OUT LPWSTR *TokenPtr
  2255. )
  2256. /*++
  2257. Routine Description:
  2258. This function takes a pointer into a given NULL-NULL-terminated buffer
  2259. and isolates the next string token in it. The CurrentPtr is incremented
  2260. past the NULL byte of the token found if it is not the end of the buffer.
  2261. The TokenPtr returned points to the token in the buffer and is NULL-
  2262. terminated.
  2263. Arguments:
  2264. CurrentPtr - Supplies a pointer to the buffer to extract the next token.
  2265. On output, this pointer is set past the token found.
  2266. TokenPtr - Supplies the pointer to the token found.
  2267. Return Value:
  2268. TRUE - If a token is found.
  2269. FALSE - No token is found.
  2270. --*/
  2271. {
  2272. if (*(*CurrentPtr) == 0) {
  2273. return FALSE;
  2274. }
  2275. *TokenPtr = *CurrentPtr;
  2276. *CurrentPtr = ScNextWStrArrayEntry((*CurrentPtr));
  2277. return TRUE;
  2278. }
  2279. DWORD
  2280. ScOpenServicesKey(
  2281. OUT PHKEY ServicesKey
  2282. )
  2283. {
  2284. LONG RegError;
  2285. RegError = ScRegOpenKeyExW(
  2286. HKEY_LOCAL_MACHINE,
  2287. SERVICES_TREE,
  2288. REG_OPTION_NON_VOLATILE, // options
  2289. KEY_READ | DELETE, // desired access
  2290. ServicesKey
  2291. );
  2292. return (ScWinRegErrorToApiStatus( RegError ));
  2293. }
  2294. DWORD
  2295. ScRegCreateKeyExW(
  2296. IN HKEY hKey,
  2297. IN LPWSTR lpSubKey,
  2298. IN DWORD dwReserved,
  2299. IN LPWSTR lpClass,
  2300. IN DWORD dwOptions,
  2301. IN REGSAM samDesired,
  2302. IN LPSECURITY_ATTRIBUTES lpSecurityAttributes,
  2303. OUT PHKEY phKeyResult,
  2304. OUT LPDWORD lpdwDisposition
  2305. )
  2306. /*++
  2307. Routine Description:
  2308. NOTE: This routine only creates one key at a time. If the lpSubKey
  2309. parameter includes keys that don't exist, an error will result.
  2310. For instance, if "\\new\\key\\here" is passed in, "new" and "key"
  2311. are expected to exist. They will not be created by this call.
  2312. Arguments:
  2313. Return Value:
  2314. Note:
  2315. --*/
  2316. {
  2317. NTSTATUS ntStatus;
  2318. OBJECT_ATTRIBUTES Obja;
  2319. UNICODE_STRING KeyName;
  2320. UNICODE_STRING ClassString;
  2321. UNREFERENCED_PARAMETER(dwReserved);
  2322. RtlInitUnicodeString(&KeyName,lpSubKey);
  2323. RtlInitUnicodeString(&ClassString,lpClass);
  2324. InitializeObjectAttributes(
  2325. &Obja,
  2326. &KeyName,
  2327. OBJ_CASE_INSENSITIVE,
  2328. hKey,
  2329. ARGUMENT_PRESENT(lpSecurityAttributes) ?
  2330. lpSecurityAttributes->lpSecurityDescriptor :
  2331. NULL);
  2332. ntStatus = NtCreateKey(
  2333. (PHANDLE)phKeyResult,
  2334. (ACCESS_MASK)samDesired,
  2335. &Obja,
  2336. 0,
  2337. &ClassString,
  2338. (ULONG)dwOptions,
  2339. (PULONG)lpdwDisposition);
  2340. return(RtlNtStatusToDosError(ntStatus));
  2341. }
  2342. DWORD
  2343. ScRegOpenKeyExW(
  2344. IN HKEY hKey,
  2345. IN LPWSTR lpSubKey,
  2346. IN DWORD dwOptions,
  2347. IN REGSAM samDesired,
  2348. OUT PHKEY phKeyResult
  2349. )
  2350. /*++
  2351. Routine Description:
  2352. NOTE: This function will only accept one of the WinReg Pre-defined
  2353. handles - HKEY_LOCAL_MACHINE. Passing any other type of Pre-defined
  2354. handle will cause an error.
  2355. Arguments:
  2356. Return Value:
  2357. Note:
  2358. --*/
  2359. {
  2360. NTSTATUS ntStatus;
  2361. DWORD status;
  2362. OBJECT_ATTRIBUTES Obja;
  2363. UNICODE_STRING KeyNameString;
  2364. LPWSTR KeyPath;
  2365. DWORD stringSize;
  2366. LPWSTR HKeyLocalMachine = SC_HKEY_LOCAL_MACHINE;
  2367. HKEY tempHKey;
  2368. BOOL KeyPathIsAllocated=FALSE;
  2369. UNREFERENCED_PARAMETER(dwOptions);
  2370. //
  2371. // If we are opening the Pre-Defined Key (HKEY_LOCAL_MACHINE), then
  2372. // pre-pend "\\REGISTRY\\MACHINE\\" to the subKey string.
  2373. //
  2374. if (hKey == HKEY_LOCAL_MACHINE) {
  2375. stringSize = (DWORD) WCSSIZE(HKeyLocalMachine) + (DWORD) WCSSIZE(lpSubKey);
  2376. KeyPath = (LPWSTR)LocalAlloc(LMEM_ZEROINIT, (UINT) stringSize);
  2377. if (KeyPath == NULL) {
  2378. SC_LOG0(ERROR,"ScRegOpenKeyExW: Local Alloc Failed\n");
  2379. return(GetLastError());
  2380. }
  2381. KeyPathIsAllocated=TRUE;
  2382. wcscpy(KeyPath,HKeyLocalMachine);
  2383. wcscat(KeyPath,lpSubKey);
  2384. tempHKey = NULL;
  2385. }
  2386. else {
  2387. KeyPath = lpSubKey;
  2388. tempHKey = hKey;
  2389. }
  2390. RtlInitUnicodeString(&KeyNameString,KeyPath);
  2391. InitializeObjectAttributes(
  2392. &Obja,
  2393. &KeyNameString,
  2394. OBJ_CASE_INSENSITIVE,
  2395. tempHKey,
  2396. NULL);
  2397. ntStatus = NtOpenKey(
  2398. (PHANDLE)phKeyResult,
  2399. (ACCESS_MASK)samDesired,
  2400. &Obja);
  2401. if (ntStatus == STATUS_ACCESS_DENIED) {
  2402. SC_LOG0(ERROR,"ScOpenKeyExW: NtOpenKey ACCESS_DENIED try to Take Ownership\n");
  2403. status = ScTakeOwnership(&Obja);
  2404. if (status != NO_ERROR) {
  2405. if (KeyPathIsAllocated) {
  2406. LocalFree(KeyPath);
  2407. }
  2408. return(status);
  2409. }
  2410. //
  2411. // Now try to open the key with the desired access.
  2412. //
  2413. ntStatus = NtOpenKey(
  2414. (PHANDLE)phKeyResult,
  2415. (ACCESS_MASK)samDesired,
  2416. &Obja);
  2417. if (!NT_SUCCESS(ntStatus)) {
  2418. SC_LOG(ERROR, "ScRegOpenKeyExW: NtOpenKey(final try) failed %x\n",
  2419. ntStatus);
  2420. }
  2421. }
  2422. if (KeyPathIsAllocated) {
  2423. LocalFree(KeyPath);
  2424. }
  2425. return(RtlNtStatusToDosError(ntStatus));
  2426. }
  2427. DWORD
  2428. ScRegQueryValueExW(
  2429. IN HKEY hKey,
  2430. IN LPCWSTR lpValueName,
  2431. OUT LPDWORD lpReserved,
  2432. OUT LPDWORD lpType,
  2433. OUT LPBYTE lpData,
  2434. IN OUT LPDWORD lpcbData
  2435. )
  2436. /*++
  2437. Routine Description:
  2438. Arguments:
  2439. Return Value:
  2440. Note:
  2441. --*/
  2442. {
  2443. NTSTATUS ntStatus;
  2444. UNICODE_STRING ValueName;
  2445. PKEY_VALUE_PARTIAL_INFORMATION KeyValueInfo;
  2446. DWORD bufSize;
  2447. UNREFERENCED_PARAMETER(lpReserved);
  2448. //
  2449. // Make sure we have a buffer size if the buffer is present.
  2450. //
  2451. if ((ARGUMENT_PRESENT(lpData)) && (!ARGUMENT_PRESENT(lpcbData))) {
  2452. return(ERROR_INVALID_PARAMETER);
  2453. }
  2454. RtlInitUnicodeString(&ValueName, lpValueName);
  2455. //
  2456. // Compute size of value information and allocate buffer.
  2457. //
  2458. bufSize = 0;
  2459. if (ARGUMENT_PRESENT(lpcbData)) {
  2460. bufSize = *lpcbData;
  2461. }
  2462. bufSize += FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data);
  2463. KeyValueInfo =
  2464. (PKEY_VALUE_PARTIAL_INFORMATION)LocalAlloc(LMEM_ZEROINIT, bufSize);
  2465. if (KeyValueInfo == NULL) {
  2466. SC_LOG0(ERROR,"ScRegQueryValueExW: LocalAlloc Failed");
  2467. return ERROR_NOT_ENOUGH_MEMORY;
  2468. }
  2469. ntStatus = NtQueryValueKey(
  2470. hKey,
  2471. &ValueName,
  2472. KeyValuePartialInformation,
  2473. KeyValueInfo,
  2474. bufSize,
  2475. &bufSize);
  2476. if (NT_SUCCESS(ntStatus) || (ntStatus == STATUS_BUFFER_OVERFLOW)) {
  2477. if (ARGUMENT_PRESENT(lpcbData)) {
  2478. *lpcbData = KeyValueInfo->DataLength;
  2479. }
  2480. if (ARGUMENT_PRESENT(lpType)) {
  2481. *lpType = KeyValueInfo->Type;
  2482. }
  2483. }
  2484. if (NT_SUCCESS(ntStatus) && ARGUMENT_PRESENT(lpData)) {
  2485. RtlCopyMemory(lpData, &KeyValueInfo->Data[0], KeyValueInfo->DataLength);
  2486. }
  2487. LocalFree(KeyValueInfo);
  2488. return RtlNtStatusToDosError(ntStatus);
  2489. }
  2490. DWORD
  2491. ScRegSetValueExW(
  2492. IN HKEY hKey,
  2493. IN LPCWSTR lpValueName,
  2494. IN DWORD lpReserved,
  2495. IN DWORD dwType,
  2496. IN LPVOID lpData,
  2497. IN DWORD cbData
  2498. )
  2499. /*++
  2500. Routine Description:
  2501. Arguments:
  2502. Return Value:
  2503. Note:
  2504. --*/
  2505. {
  2506. DWORD status;
  2507. NTSTATUS ntStatus;
  2508. UNICODE_STRING ValueName;
  2509. UNREFERENCED_PARAMETER(lpReserved);
  2510. RtlInitUnicodeString(&ValueName,lpValueName);
  2511. ntStatus = NtSetValueKey(
  2512. hKey,
  2513. &ValueName,
  2514. 0,
  2515. (ULONG)dwType,
  2516. (PVOID)lpData,
  2517. (ULONG)cbData);
  2518. status = RtlNtStatusToDosError(ntStatus);
  2519. if (status != NO_ERROR)
  2520. {
  2521. ScLogEvent(
  2522. NEVENT_CALL_TO_FUNCTION_FAILED_II,
  2523. L"ScRegSetValueExW",
  2524. lpValueName,
  2525. status
  2526. );
  2527. }
  2528. return(status);
  2529. }
  2530. DWORD
  2531. ScRegDeleteValue(
  2532. IN HKEY hKey,
  2533. IN LPCWSTR lpValueName
  2534. )
  2535. /*++
  2536. Routine Description:
  2537. Arguments:
  2538. Return Value:
  2539. Note:
  2540. --*/
  2541. {
  2542. NTSTATUS ntStatus;
  2543. UNICODE_STRING ValueName;
  2544. RtlInitUnicodeString(&ValueName,lpValueName);
  2545. ntStatus = NtDeleteValueKey(
  2546. hKey,
  2547. &ValueName);
  2548. return(RtlNtStatusToDosError(ntStatus));
  2549. }
  2550. DWORD
  2551. ScRegEnumKeyW(
  2552. HKEY hKey,
  2553. DWORD dwIndex,
  2554. LPWSTR lpName,
  2555. DWORD cbName
  2556. )
  2557. /*++
  2558. Routine Description:
  2559. Arguments:
  2560. Return Value:
  2561. --*/
  2562. {
  2563. NTSTATUS ntStatus;
  2564. PKEY_BASIC_INFORMATION KeyInformation;
  2565. ULONG resultLength;
  2566. DWORD bufSize;
  2567. //
  2568. // Allocate a buffer for the Key Information.
  2569. //
  2570. bufSize = sizeof(KEY_BASIC_INFORMATION) + cbName;
  2571. KeyInformation = (PKEY_BASIC_INFORMATION)LocalAlloc(LMEM_ZEROINIT, (UINT) bufSize);
  2572. if (KeyInformation == NULL){
  2573. SC_LOG0(ERROR,"ScRegEnumKey: LocalAlloc Failed\n");
  2574. return(ERROR_NOT_ENOUGH_MEMORY);
  2575. }
  2576. ntStatus = NtEnumerateKey(
  2577. (HANDLE)hKey,
  2578. (ULONG)dwIndex,
  2579. KeyBasicInformation,
  2580. (PVOID)KeyInformation,
  2581. (ULONG)bufSize,
  2582. (PULONG)&resultLength);
  2583. if (!NT_SUCCESS(ntStatus)) {
  2584. LocalFree(KeyInformation);
  2585. return(RtlNtStatusToDosError(ntStatus));
  2586. }
  2587. if (cbName < (KeyInformation->NameLength + sizeof(WCHAR))) {
  2588. LocalFree(KeyInformation);
  2589. return(ERROR_MORE_DATA);
  2590. }
  2591. RtlCopyMemory(lpName, KeyInformation->Name, KeyInformation->NameLength);
  2592. *(lpName + (KeyInformation->NameLength/sizeof(WCHAR))) = L'\0';
  2593. LocalFree(KeyInformation);
  2594. return(NO_ERROR);
  2595. }
  2596. DWORD
  2597. ScRegDeleteKeyW (
  2598. HKEY hKey,
  2599. LPWSTR lpSubKey
  2600. )
  2601. /*++
  2602. Routine Description:
  2603. Arguments:
  2604. Return Value:
  2605. --*/
  2606. {
  2607. DWORD status;
  2608. NTSTATUS ntStatus;
  2609. HKEY keyToDelete;
  2610. status = ScRegOpenKeyExW(
  2611. hKey,
  2612. lpSubKey,
  2613. 0,
  2614. KEY_READ | READ_CONTROL | DELETE,
  2615. &keyToDelete);
  2616. if (status != NO_ERROR) {
  2617. SC_LOG2(ERROR, "ScRegDeleteKeyW: ScRegOpenKeyExW (%ws) Failed %d\n",
  2618. lpSubKey,
  2619. status);
  2620. return(status);
  2621. }
  2622. ntStatus = NtDeleteKey(keyToDelete);
  2623. NtClose(keyToDelete);
  2624. return(RtlNtStatusToDosError(ntStatus));
  2625. }
  2626. DWORD
  2627. ScRegQueryInfoKeyW (
  2628. HKEY hKey,
  2629. LPWSTR lpClass,
  2630. LPDWORD lpcbClass,
  2631. LPDWORD lpReserved,
  2632. LPDWORD lpcSubKeys,
  2633. LPDWORD lpcbMaxSubKeyLen,
  2634. LPDWORD lpcbMaxClassLen,
  2635. LPDWORD lpcValues,
  2636. LPDWORD lpcbMaxValueNameLen,
  2637. LPDWORD lpcbMaxValueLen,
  2638. LPDWORD lpcbSecurityDescriptor,
  2639. PFILETIME lpftLastWriteTime
  2640. )
  2641. /*++
  2642. Routine Description:
  2643. Arguments:
  2644. Return Value:
  2645. --*/
  2646. {
  2647. DWORD status;
  2648. NTSTATUS ntStatus;
  2649. NTSTATUS ntStatus2;
  2650. PSECURITY_DESCRIPTOR SecurityDescriptor=NULL;
  2651. ULONG SecurityDescriptorLength;
  2652. PKEY_FULL_INFORMATION KeyInfo;
  2653. DWORD bufSize;
  2654. DWORD bytesReturned;
  2655. DWORD classBufSize;
  2656. UNREFERENCED_PARAMETER(lpReserved);
  2657. classBufSize = *lpcbClass;
  2658. bufSize = sizeof(KEY_FULL_INFORMATION) + *lpcbClass;
  2659. KeyInfo = (PKEY_FULL_INFORMATION)LocalAlloc(LMEM_ZEROINIT, bufSize);
  2660. if (KeyInfo == NULL) {
  2661. SC_LOG0(ERROR,"RegQueryInfoKeyW: LocalAlloc failed\n");
  2662. return(ERROR_NOT_ENOUGH_MEMORY);
  2663. }
  2664. ntStatus = NtQueryKey(
  2665. hKey,
  2666. KeyFullInformation,
  2667. (PVOID)KeyInfo,
  2668. bufSize,
  2669. &bytesReturned);
  2670. status = RtlNtStatusToDosError(ntStatus);
  2671. if (ntStatus == STATUS_SUCCESS) {
  2672. ntStatus2 = NtQuerySecurityObject(
  2673. hKey,
  2674. OWNER_SECURITY_INFORMATION
  2675. | GROUP_SECURITY_INFORMATION
  2676. | DACL_SECURITY_INFORMATION,
  2677. SecurityDescriptor,
  2678. 0,
  2679. lpcbSecurityDescriptor
  2680. );
  2681. //
  2682. // If getting the size of the SECURITY_DESCRIPTOR failed (probably
  2683. // due to the lack of READ_CONTROL access) return zero.
  2684. //
  2685. if( ntStatus2 != STATUS_BUFFER_TOO_SMALL ) {
  2686. *lpcbSecurityDescriptor = 0;
  2687. } else {
  2688. //
  2689. // Try again to get the size of the key's SECURITY_DESCRIPTOR,
  2690. // this time asking for SACL as well. This should normally
  2691. // fail but may succeed if the caller has SACL access.
  2692. //
  2693. ntStatus2 = NtQuerySecurityObject(
  2694. hKey,
  2695. OWNER_SECURITY_INFORMATION
  2696. | GROUP_SECURITY_INFORMATION
  2697. | DACL_SECURITY_INFORMATION
  2698. | SACL_SECURITY_INFORMATION,
  2699. SecurityDescriptor,
  2700. 0,
  2701. &SecurityDescriptorLength
  2702. );
  2703. if( ntStatus2 == STATUS_BUFFER_TOO_SMALL ) {
  2704. //
  2705. // The caller had SACL access so update the returned
  2706. // length.
  2707. //
  2708. *lpcbSecurityDescriptor = SecurityDescriptorLength;
  2709. }
  2710. }
  2711. *lpcbClass = KeyInfo->ClassLength;
  2712. *lpcSubKeys = KeyInfo->SubKeys;
  2713. *lpcbMaxSubKeyLen = KeyInfo->MaxNameLen;
  2714. *lpcbMaxClassLen = KeyInfo->MaxClassLen;
  2715. *lpcValues = KeyInfo->Values;
  2716. *lpcbMaxValueNameLen = KeyInfo->MaxValueNameLen;
  2717. *lpcbMaxValueLen = KeyInfo->MaxValueDataLen;
  2718. *lpftLastWriteTime = *(PFILETIME) &KeyInfo->LastWriteTime;
  2719. if (KeyInfo->ClassLength > classBufSize) {
  2720. LocalFree(KeyInfo);
  2721. return(RtlNtStatusToDosError(STATUS_BUFFER_TOO_SMALL));
  2722. }
  2723. RtlCopyMemory(
  2724. lpClass,
  2725. (LPBYTE)KeyInfo->Class,
  2726. KeyInfo->ClassLength);
  2727. //
  2728. // NUL terminate the class name.
  2729. //
  2730. *(lpClass + (KeyInfo->ClassLength/sizeof(WCHAR))) = UNICODE_NULL;
  2731. }
  2732. else
  2733. {
  2734. //
  2735. // NtQueryKey failed
  2736. //
  2737. ScLogEvent(
  2738. NEVENT_CALL_TO_FUNCTION_FAILED,
  2739. L"ScRegQueryInfoKeyW",
  2740. status
  2741. );
  2742. }
  2743. LocalFree(KeyInfo);
  2744. return(status);
  2745. }
  2746. DWORD
  2747. ScRegGetKeySecurity (
  2748. HKEY hKey,
  2749. SECURITY_INFORMATION SecurityInformation,
  2750. PSECURITY_DESCRIPTOR pSecurityDescriptor,
  2751. LPDWORD lpcbSecurityDescriptor
  2752. )
  2753. /*++
  2754. Routine Description:
  2755. Arguments:
  2756. Return Value:
  2757. --*/
  2758. {
  2759. RPC_SECURITY_DESCRIPTOR RpcSD;
  2760. DWORD status;
  2761. //
  2762. // Convert the supplied SECURITY_DESCRIPTOR to a RPCable version.
  2763. //
  2764. RpcSD.lpSecurityDescriptor = (PBYTE) pSecurityDescriptor;
  2765. RpcSD.cbInSecurityDescriptor = *lpcbSecurityDescriptor;
  2766. RpcSD.cbOutSecurityDescriptor = 0;
  2767. status = (DWORD)BaseRegGetKeySecurity(
  2768. hKey,
  2769. SecurityInformation,
  2770. &RpcSD
  2771. );
  2772. //
  2773. // Extract the size of the SECURITY_DESCRIPTOR from the RPCable version.
  2774. //
  2775. *lpcbSecurityDescriptor = RpcSD.cbInSecurityDescriptor;
  2776. return(status);
  2777. }
  2778. DWORD
  2779. ScRegSetKeySecurity (
  2780. HKEY hKey,
  2781. SECURITY_INFORMATION SecurityInformation,
  2782. PSECURITY_DESCRIPTOR pSecurityDescriptor
  2783. )
  2784. /*++
  2785. Routine Description:
  2786. Arguments:
  2787. Return Value:
  2788. --*/
  2789. {
  2790. RPC_SECURITY_DESCRIPTOR RpcSD;
  2791. DWORD status;
  2792. //
  2793. // Convert the supplied SECURITY_DESCRIPTOR to a RPCable version.
  2794. //
  2795. RpcSD.lpSecurityDescriptor = NULL;
  2796. status = MapSDToRpcSD(
  2797. pSecurityDescriptor,
  2798. &RpcSD
  2799. );
  2800. if( status != ERROR_SUCCESS )
  2801. {
  2802. SC_LOG1(ERROR,"ScRegSetKeySecurity: MapSDToRpcSD failed %lu\n",
  2803. status);
  2804. ScLogEvent(
  2805. NEVENT_CALL_TO_FUNCTION_FAILED,
  2806. L"MapSDToRpcSD",
  2807. status
  2808. );
  2809. return (status);
  2810. }
  2811. status = (DWORD)BaseRegSetKeySecurity (
  2812. hKey,
  2813. SecurityInformation,
  2814. &RpcSD
  2815. );
  2816. //
  2817. // Free the buffer allocated by MapSDToRpcSD.
  2818. //
  2819. RtlFreeHeap(
  2820. RtlProcessHeap( ), 0,
  2821. RpcSD.lpSecurityDescriptor
  2822. );
  2823. return (status);
  2824. }
  2825. DWORD
  2826. ScRegEnumValueW (
  2827. HKEY hKey,
  2828. DWORD dwIndex,
  2829. LPWSTR lpValueName,
  2830. LPDWORD lpcbValueName,
  2831. LPDWORD lpReserved,
  2832. LPDWORD lpType,
  2833. LPBYTE lpData,
  2834. LPDWORD lpcbData
  2835. )
  2836. /*++
  2837. Routine Description:
  2838. Arguments:
  2839. Return Value:
  2840. --*/
  2841. {
  2842. NTSTATUS ntStatus;
  2843. PKEY_VALUE_FULL_INFORMATION KeyValueInfo;
  2844. DWORD bufSize;
  2845. DWORD resultSize;
  2846. DWORD totalSize; // size of string including NUL
  2847. BOOL stringData = FALSE;
  2848. UNREFERENCED_PARAMETER(lpReserved);
  2849. //
  2850. // Make sure we have a buffer size if the buffer is present.
  2851. //
  2852. if ((ARGUMENT_PRESENT(lpData)) && (!ARGUMENT_PRESENT(lpcbData))) {
  2853. return(ERROR_INVALID_PARAMETER);
  2854. }
  2855. //
  2856. // Compute size of KeyValueInfo, round to pointer size, and allocate
  2857. // buffer.
  2858. //
  2859. bufSize = FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION, Name) + (MAX_PATH * sizeof(WCHAR));
  2860. bufSize = (bufSize + sizeof(PVOID) - 1) & ~(sizeof(PVOID) - 1);
  2861. bufSize += *lpcbData;
  2862. KeyValueInfo = (PKEY_VALUE_FULL_INFORMATION)LocalAlloc(
  2863. LMEM_ZEROINIT,
  2864. (UINT) bufSize);
  2865. if (KeyValueInfo == NULL) {
  2866. SC_LOG0(ERROR,"ScRegEnumValueW: LocalAlloc Failed\n");
  2867. return(ERROR_NOT_ENOUGH_MEMORY);
  2868. }
  2869. ntStatus = NtEnumerateValueKey(
  2870. (HANDLE)hKey,
  2871. (ULONG)dwIndex,
  2872. KeyValueFullInformation,
  2873. (PVOID)KeyValueInfo,
  2874. (ULONG)bufSize,
  2875. (PULONG)&resultSize);
  2876. if (ntStatus == STATUS_BUFFER_OVERFLOW) {
  2877. LocalFree(KeyValueInfo);
  2878. KeyValueInfo = (PKEY_VALUE_FULL_INFORMATION)LocalAlloc(
  2879. LMEM_ZEROINIT,
  2880. (UINT) resultSize);
  2881. if (KeyValueInfo == NULL) {
  2882. SC_LOG0(ERROR,"ScRegEnumValueW: LocalAlloc (2nd try) Failed\n");
  2883. return(ERROR_NOT_ENOUGH_MEMORY);
  2884. }
  2885. ntStatus = NtEnumerateValueKey(
  2886. hKey,
  2887. (ULONG)dwIndex,
  2888. KeyValueFullInformation,
  2889. (PVOID)KeyValueInfo,
  2890. (ULONG)bufSize,
  2891. (PULONG)&resultSize);
  2892. if (ntStatus != STATUS_SUCCESS) {
  2893. LocalFree(KeyValueInfo);
  2894. return(RtlNtStatusToDosError(ntStatus));
  2895. }
  2896. }
  2897. else if (ntStatus != STATUS_SUCCESS) {
  2898. LocalFree(KeyValueInfo);
  2899. return(RtlNtStatusToDosError(ntStatus));
  2900. }
  2901. //
  2902. // The API was successful (from our point of view. Now see if the
  2903. // callers buffers were large enough.
  2904. //
  2905. totalSize = KeyValueInfo->NameLength+sizeof(WCHAR); // add 1 for the NUL terminator.
  2906. if (*lpcbValueName < totalSize) {
  2907. *lpcbValueName = totalSize;
  2908. *lpcbData = KeyValueInfo->DataLength;
  2909. LocalFree(KeyValueInfo);
  2910. return(ERROR_INSUFFICIENT_BUFFER);
  2911. }
  2912. else {
  2913. RtlCopyMemory(
  2914. lpValueName,
  2915. (LPBYTE)KeyValueInfo->Name,
  2916. KeyValueInfo->NameLength);
  2917. *lpcbValueName = totalSize;
  2918. //
  2919. // NUL terminate the Value name.
  2920. //
  2921. *(lpValueName + (KeyValueInfo->NameLength/sizeof(WCHAR))) = UNICODE_NULL;
  2922. }
  2923. if (ARGUMENT_PRESENT(lpData)) {
  2924. totalSize = KeyValueInfo->DataLength;
  2925. #ifdef REMOVE
  2926. //
  2927. // I believe I can remove this because data strings will be
  2928. // stored with NULL terminators.
  2929. //
  2930. if((KeyValueInfo->Type == REG_SZ) ||
  2931. (KeyValueInfo->Type == REG_EXPAND_SZ) ||
  2932. (KeyValueInfo->Type == REG_MULTI_SZ)) {
  2933. totalSize += sizeof(WCHAR);
  2934. stringData = TRUE;
  2935. }
  2936. #endif // REMOVE
  2937. if (*lpcbData < totalSize) {
  2938. *lpcbData = totalSize;
  2939. LocalFree(KeyValueInfo);
  2940. return(ERROR_INSUFFICIENT_BUFFER);
  2941. }
  2942. else {
  2943. RtlCopyMemory(
  2944. lpData,
  2945. (LPBYTE)KeyValueInfo + KeyValueInfo->DataOffset,
  2946. KeyValueInfo->DataLength);
  2947. *lpcbData = KeyValueInfo->DataLength;
  2948. if (stringData) {
  2949. *lpcbData += sizeof(WCHAR);
  2950. //
  2951. // NUL terminate the string Data.
  2952. //
  2953. *((LPWSTR)lpData + (KeyValueInfo->DataLength/sizeof(WCHAR))) = UNICODE_NULL;
  2954. }
  2955. }
  2956. }
  2957. if (ARGUMENT_PRESENT(lpType)) {
  2958. *lpType = KeyValueInfo->Type;
  2959. }
  2960. LocalFree(KeyValueInfo);
  2961. return(NO_ERROR);
  2962. }
  2963. VOID
  2964. ScHandleProviderChange(
  2965. PVOID pContext,
  2966. BOOLEAN fWaitStatus
  2967. )
  2968. /*++
  2969. Routine Description:
  2970. Processes changes to the list of network providers in the registry
  2971. and publishes a list of those that are currently active in the HW
  2972. profile for mpr.dll to use.
  2973. Arguments:
  2974. Return Value:
  2975. --*/
  2976. {
  2977. DWORD dwStatus;
  2978. LPWSTR lpProviderList = NULL;
  2979. DWORD dwLength;
  2980. DWORD dwTempLength;
  2981. UINT i;
  2982. DWORD dwCurrentChar;
  2983. DWORD dwNameStart;
  2984. BOOL fWriteList = TRUE;
  2985. LPWSTR lpList = NULL;
  2986. HKEY hProviderHwKey;
  2987. HKEY hProviderKey;
  2988. DWORD dwDisposition;
  2989. SECURITY_ATTRIBUTES SecurityAttr;
  2990. PSECURITY_DESCRIPTOR SecurityDescriptor;
  2991. static HANDLE s_hWorkItem;
  2992. #define SC_KEY_ACE_COUNT 2
  2993. SC_ACE_DATA AceData[SC_KEY_ACE_COUNT] = {
  2994. {ACCESS_ALLOWED_ACE_TYPE, CONTAINER_INHERIT_ACE, 0,
  2995. GENERIC_ALL, &LocalSystemSid},
  2996. {ACCESS_ALLOWED_ACE_TYPE, CONTAINER_INHERIT_ACE, 0,
  2997. GENERIC_READ, &WorldSid}
  2998. };
  2999. SC_ASSERT(fWaitStatus == FALSE);
  3000. SC_ASSERT(g_hProviderKey != NULL);
  3001. if (ScShutdownInProgress)
  3002. {
  3003. return;
  3004. }
  3005. if (s_hWorkItem != NULL)
  3006. {
  3007. dwStatus = RtlDeregisterWait(s_hWorkItem);
  3008. if (!NT_SUCCESS(dwStatus))
  3009. {
  3010. SC_LOG(ERROR,
  3011. "ScHandleProviderChange: RtlDeregisterWait FAILED %#x\n",
  3012. dwStatus);
  3013. }
  3014. }
  3015. //
  3016. // Reset the event
  3017. //
  3018. ResetEvent((HANDLE)pContext);
  3019. SC_LOG0(TRACE, "ScHandleProviderChange: ProviderOrder key changed\n");
  3020. //
  3021. // Reregister for registry change notifications in case the key
  3022. // changes while we're in this routine. Note that there's no
  3023. // race condition since the work item is a one-shot -- only one
  3024. // thread can be in this routine at a time.
  3025. //
  3026. dwStatus = RegNotifyChangeKeyValue(
  3027. g_hProviderKey,
  3028. FALSE, // Don't watch subkeys
  3029. REG_NOTIFY_CHANGE_LAST_SET, // Watch for value changes
  3030. (HANDLE)pContext, // Event to signal
  3031. TRUE); // Asynchronous
  3032. if (dwStatus != NO_ERROR)
  3033. {
  3034. //
  3035. // We won't pick up any further changes to the provider list.
  3036. // Keep going so we at least pick up this one.
  3037. //
  3038. SC_LOG(ERROR,
  3039. "ScHandleProviderChange: RegNotifyChangeKeyValue FAILED %d\n",
  3040. dwStatus);
  3041. }
  3042. dwStatus = ScAllocateAndReadConfigValue(g_hProviderKey,
  3043. PROVIDER_VALUE,
  3044. &lpProviderList,
  3045. &dwLength);
  3046. if (dwStatus != NO_ERROR)
  3047. {
  3048. SC_LOG(ERROR,
  3049. "ScHandleProviderChange: Unable to read ProviderOrder %d\n",
  3050. dwStatus);
  3051. goto Reregister;
  3052. }
  3053. //
  3054. // This should be a REG_SZ -- check the basics
  3055. //
  3056. if ((dwLength % 2 != 0)
  3057. ||
  3058. (dwLength < sizeof(UNICODE_NULL))
  3059. ||
  3060. (lpProviderList[dwLength / sizeof(WCHAR) - 1] != UNICODE_NULL))
  3061. {
  3062. SC_LOG0(ERROR,
  3063. "ScHandleProviderChange: Invalid REG_SZ for ProviderOrder\n");
  3064. goto Reregister;
  3065. }
  3066. dwTempLength = dwLength;
  3067. dwCurrentChar = 0;
  3068. dwNameStart = 0;
  3069. //
  3070. // For each character in the original string
  3071. //
  3072. for (i = 0; i < dwTempLength; i += sizeof(WCHAR))
  3073. {
  3074. WCHAR wcTemp = lpProviderList[dwCurrentChar];
  3075. //
  3076. // The provider list is comma-delimited
  3077. //
  3078. if (wcTemp == L',' || wcTemp == UNICODE_NULL)
  3079. {
  3080. lpProviderList[dwCurrentChar] = UNICODE_NULL;
  3081. if (!ScInHardwareProfile(&lpProviderList[dwNameStart], 0))
  3082. {
  3083. //
  3084. // The string plus the trailing UNICODE_NULL
  3085. //
  3086. DWORD dwBytes = (dwCurrentChar - dwNameStart + 1) * sizeof(WCHAR);
  3087. //
  3088. // Service is disabled in the HW profile
  3089. //
  3090. SC_LOG(TRACE,
  3091. "ScHandleProviderChange: Service %ws is disabled\n",
  3092. &lpProviderList[dwNameStart]);
  3093. //
  3094. // Shift over the remaining characters in the buffer.
  3095. //
  3096. RtlMoveMemory(&lpProviderList[dwNameStart],
  3097. &lpProviderList[dwCurrentChar + 1],
  3098. dwLength - (dwCurrentChar + 1) * sizeof(WCHAR));
  3099. //
  3100. // This may cause dwCurrentChar to underflow to
  3101. // 0xffffffff (if the first provider was deleted).
  3102. // This is OK -- it'll be incremented (to 0) below.
  3103. //
  3104. dwLength -= dwBytes;
  3105. dwCurrentChar = dwNameStart - 1;
  3106. }
  3107. else
  3108. {
  3109. //
  3110. // Restore the temp character and move
  3111. // to the start of the next provider name.
  3112. //
  3113. lpProviderList[dwCurrentChar] = wcTemp;
  3114. dwNameStart = dwCurrentChar + 1;
  3115. }
  3116. }
  3117. dwCurrentChar++;
  3118. }
  3119. //
  3120. // If the last provider name was deleted, the string will
  3121. // end with a ',' instead of a '\0'. Note that if all the
  3122. // provider names were deleted, dwCurrentChar will be 0 --
  3123. // we increment it to empty out the provider list.
  3124. //
  3125. if (dwCurrentChar == 0)
  3126. {
  3127. dwCurrentChar++;
  3128. }
  3129. lpProviderList[dwCurrentChar - 1] = UNICODE_NULL;
  3130. SC_LOG(TRACE,
  3131. "ScHandleProviderChange: Provider list is now %ws\n",
  3132. lpProviderList);
  3133. dwStatus = ScRegOpenKeyExW(HKEY_LOCAL_MACHINE,
  3134. PROVIDER_KEY_BASE,
  3135. REG_OPTION_NON_VOLATILE,
  3136. KEY_WRITE | KEY_READ,
  3137. &hProviderKey);
  3138. if (dwStatus != NO_ERROR)
  3139. {
  3140. SC_LOG(ERROR,
  3141. "ScHandleProviderChange: Unable to open provider key %d\n",
  3142. dwStatus);
  3143. goto Reregister;
  3144. }
  3145. //
  3146. // Create a security descriptor for the registry key we are about
  3147. // to create. This gives everyone read access, and all access to
  3148. // ourselves only.
  3149. //
  3150. dwStatus = ScCreateAndSetSD(AceData,
  3151. SC_KEY_ACE_COUNT,
  3152. LocalSystemSid,
  3153. LocalSystemSid,
  3154. &SecurityDescriptor);
  3155. #undef SC_KEY_ACE_COUNT
  3156. if (!NT_SUCCESS(dwStatus))
  3157. {
  3158. SC_LOG1(ERROR,
  3159. "ScHandleProviderChange: ScCreateAndSetSD failed %#x\n",
  3160. dwStatus);
  3161. ScRegCloseKey(hProviderKey);
  3162. goto Reregister;
  3163. }
  3164. SecurityAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
  3165. SecurityAttr.lpSecurityDescriptor = SecurityDescriptor;
  3166. SecurityAttr.bInheritHandle = FALSE;
  3167. //
  3168. // Create a new HW provider subkey (or open existing one).
  3169. //
  3170. dwStatus = ScRegCreateKeyExW(hProviderKey,
  3171. PROVIDER_KEY_HW,
  3172. 0,
  3173. 0,
  3174. REG_OPTION_VOLATILE,
  3175. KEY_SET_VALUE | KEY_QUERY_VALUE,
  3176. &SecurityAttr,
  3177. &hProviderHwKey,
  3178. &dwDisposition);
  3179. RtlDeleteSecurityObject(&SecurityDescriptor);
  3180. ScRegCloseKey(hProviderKey);
  3181. if (dwStatus != NO_ERROR)
  3182. {
  3183. SC_LOG(ERROR,
  3184. "ScHandleProviderChange: Unable to open HW subkey %d\n",
  3185. dwStatus);
  3186. goto Reregister;
  3187. }
  3188. //
  3189. // Write the modified list to the registry, but only if it is
  3190. // different from the list already there. This will prevent
  3191. // mpr.dll from getting hyperactive on spurious (or repeated)
  3192. // registry change notifications.
  3193. //
  3194. dwStatus = ScAllocateAndReadConfigValue(hProviderHwKey,
  3195. PROVIDER_VALUE,
  3196. &lpList,
  3197. &dwTempLength);
  3198. if (dwStatus == NO_ERROR)
  3199. {
  3200. //
  3201. // If the string lengths are different, there's
  3202. // definitely been a provider change.
  3203. //
  3204. if (dwTempLength == dwLength)
  3205. {
  3206. fWriteList = (_wcsnicmp(lpList,
  3207. lpProviderList,
  3208. dwTempLength / sizeof(WCHAR)) != 0);
  3209. }
  3210. LocalFree(lpList);
  3211. }
  3212. if (fWriteList)
  3213. {
  3214. SC_LOG0(TRACE,
  3215. "Active provider list is different -- writing new list\n");
  3216. dwStatus = ScRegSetValueExW(hProviderHwKey,
  3217. PROVIDER_VALUE,
  3218. 0,
  3219. REG_SZ,
  3220. (LPBYTE) lpProviderList,
  3221. dwLength);
  3222. if (dwStatus != NO_ERROR)
  3223. {
  3224. SC_LOG(ERROR,
  3225. "ScHandleProviderChange: Unable to write HW-aware list %d\n",
  3226. dwStatus);
  3227. }
  3228. }
  3229. else
  3230. {
  3231. SC_LOG0(TRACE,
  3232. "Active provider list is the same -- not writing\n");
  3233. }
  3234. ScRegCloseKey(hProviderHwKey);
  3235. Reregister:
  3236. LocalFree(lpProviderList);
  3237. dwStatus = RtlRegisterWait(&s_hWorkItem, // work item handle
  3238. (HANDLE) pContext, // watiable handle
  3239. ScHandleProviderChange, // callback
  3240. (HANDLE) pContext, // callback arg
  3241. INFINITE,
  3242. WT_EXECUTEINPERSISTENTIOTHREAD |
  3243. WT_EXECUTEONLYONCE);
  3244. if (!NT_SUCCESS(dwStatus))
  3245. {
  3246. SC_LOG(ERROR,
  3247. "ScHandleProviderChange: RtlRegisterWait FAILED %#x\n",
  3248. dwStatus);
  3249. }
  3250. }
  3251. VOID
  3252. ScMarkForDelete(
  3253. LPSERVICE_RECORD ServiceRecord
  3254. )
  3255. /*++
  3256. Routine Description:
  3257. This function adds a DeleteFlag value to a service key in the registry.
  3258. Arguments:
  3259. ServiceName - This is a pointer to the service name string.
  3260. Return Value:
  3261. none.
  3262. --*/
  3263. {
  3264. DWORD status;
  3265. HKEY hServiceKey;
  3266. DWORD deleteFlag=1;
  3267. status = ScOpenServiceConfigKey(
  3268. ServiceRecord->ServiceName,
  3269. KEY_WRITE, // desired access
  3270. FALSE, // don't create if missing
  3271. &hServiceKey);
  3272. if (status != NO_ERROR) {
  3273. SC_LOG1(TRACE,"ScMarkForDelete:ScOpenServiceConfigKey failed %d\n",status);
  3274. return;
  3275. }
  3276. status = ScRegSetValueExW(
  3277. hServiceKey,
  3278. REG_DELETE_FLAG,
  3279. 0,
  3280. REG_DWORD,
  3281. (LPBYTE)&deleteFlag,
  3282. sizeof(DWORD));
  3283. if (status != NO_ERROR) {
  3284. SC_LOG1(TRACE,"ScMarkForDelete:ScRegSetValueExW failed %d\n",status);
  3285. (void) ScRegCloseKey(hServiceKey);
  3286. return;
  3287. }
  3288. //
  3289. // Make sure we're disabling the service in case it's a driver started by the
  3290. // kernel before we get a chance to delete the key on the next boot
  3291. //
  3292. ASSERT(ServiceRecord->StartType == SERVICE_DISABLED);
  3293. status = ScWriteStartType(hServiceKey, ServiceRecord->StartType);
  3294. if (status != NO_ERROR) {
  3295. SC_LOG1(TRACE,"ScMarkForDelete:ScRegSetValueExW failed %d\n",status);
  3296. }
  3297. (void) ScRegCloseKey(hServiceKey);
  3298. return;
  3299. }
  3300. BOOL
  3301. ScDeleteFlagIsSet(
  3302. HKEY ServiceKeyHandle
  3303. )
  3304. /*++
  3305. Routine Description:
  3306. This function looks for a delete flag value stored in the registry for
  3307. this service.
  3308. Arguments:
  3309. ServiceKeyHandle - This is a handle to the service key.
  3310. Return Value:
  3311. TRUE - if the delete flag exists.
  3312. FALSE - otherwise.
  3313. --*/
  3314. {
  3315. DWORD status;
  3316. DWORD value;
  3317. DWORD valueSize = sizeof(DWORD);
  3318. DWORD type;
  3319. status = ScRegQueryValueExW(
  3320. ServiceKeyHandle,
  3321. REG_DELETE_FLAG,
  3322. NULL,
  3323. &type,
  3324. (LPBYTE)&value,
  3325. &valueSize);
  3326. if (status == NO_ERROR) {
  3327. return(TRUE);
  3328. }
  3329. return(FALSE);
  3330. }
  3331. DWORD
  3332. ScReadDependencies(
  3333. HKEY ServiceNameKey,
  3334. LPWSTR *Dependencies,
  3335. LPWSTR ServiceName
  3336. )
  3337. /*++
  3338. Routine Description:
  3339. Arguments:
  3340. Return Value:
  3341. Note:
  3342. --*/
  3343. {
  3344. LPWSTR DependOnService = NULL;
  3345. LPWSTR DependOnGroup = NULL;
  3346. DWORD DependOnServiceSize = 0;
  3347. DWORD DependOnGroupSize = 0;
  3348. DWORD status = NO_ERROR;
  3349. //
  3350. // Read the DependOnService value
  3351. //
  3352. if (ScAllocateAndReadConfigValue(
  3353. ServiceNameKey,
  3354. DEPENDONSERVICE_VALUENAME_W,
  3355. &DependOnService,
  3356. &DependOnServiceSize
  3357. ) != NO_ERROR)
  3358. {
  3359. DependOnService = NULL;
  3360. DependOnServiceSize = 0;
  3361. }
  3362. //
  3363. // We write a length of 2 bytes into the
  3364. // registry for an empty REG_MULTI_SZ.
  3365. //
  3366. else if ((DependOnServiceSize >= sizeof(WCHAR)) && (*DependOnService != L'\0'))
  3367. {
  3368. //
  3369. // Make sure we got a valid MULTI_SZ
  3370. //
  3371. status = ScValidateMultiSZ(DependOnService,
  3372. DependOnServiceSize);
  3373. if (status != NO_ERROR) {
  3374. SC_LOG2(CONFIG,
  3375. "ScReadDependencies: ScValidateMultiSZ failed %d for service %ws\n",
  3376. status,
  3377. ServiceName);
  3378. //
  3379. // Set this to NULL since we'll LocalFree it in CleanExit below
  3380. //
  3381. LocalFree(DependOnService);
  3382. DependOnService = NULL;
  3383. DependOnServiceSize = 0;
  3384. }
  3385. #if DBG
  3386. SC_LOG1(CONFIG, " " FORMAT_LPWSTR " DependOnService\n", ServiceName);
  3387. ScDisplayWStrArray(DependOnService);
  3388. #endif
  3389. }
  3390. //
  3391. // Read the DependOnGroup value
  3392. //
  3393. if (ScAllocateAndReadConfigValue(
  3394. ServiceNameKey,
  3395. DEPENDONGROUP_VALUENAME_W,
  3396. &DependOnGroup,
  3397. &DependOnGroupSize
  3398. ) != NO_ERROR)
  3399. {
  3400. DependOnGroup = NULL;
  3401. DependOnGroupSize = 0;
  3402. }
  3403. //
  3404. // We write a length of 2 bytes into the
  3405. // registry for an empty REG_MULTI_SZ.
  3406. //
  3407. else if ((DependOnGroupSize >= sizeof(WCHAR)) && (*DependOnGroup != L'\0'))
  3408. {
  3409. //
  3410. // Make sure we got a valid MULTI_SZ
  3411. //
  3412. status = ScValidateMultiSZ(DependOnGroup,
  3413. DependOnGroupSize);
  3414. if (status != NO_ERROR) {
  3415. SC_LOG2(CONFIG,
  3416. "ScReadDependencies: ScValidateMultiSZ failed %d for service %ws\n",
  3417. status,
  3418. ServiceName);
  3419. //
  3420. // Set this to NULL since we'll LocalFree it in CleanExit below
  3421. //
  3422. LocalFree(DependOnGroup);
  3423. DependOnGroup = NULL;
  3424. DependOnGroupSize = 0;
  3425. }
  3426. #if DBG
  3427. SC_LOG1(CONFIG, " " FORMAT_LPWSTR " DependOnGroup\n", ServiceName);
  3428. ScDisplayWStrArray(DependOnGroup);
  3429. #endif
  3430. }
  3431. //
  3432. // Concatenate the DependOnService and DependOnGroup string arrays
  3433. // to make the Dependencies array string.
  3434. //
  3435. if (DependOnService == NULL && DependOnGroup == NULL) {
  3436. *Dependencies = NULL;
  3437. }
  3438. else {
  3439. LPWSTR Entry;
  3440. LPWSTR DestPtr;
  3441. if (DependOnService != NULL) {
  3442. DependOnServiceSize -= sizeof(WCHAR); // subtract the NULL terminator
  3443. }
  3444. if (DependOnGroup != NULL) {
  3445. Entry = DependOnGroup;
  3446. while (*Entry != 0) {
  3447. //
  3448. // Add extra space for the group name to be prefixed
  3449. // by SC_GROUP_IDENTIFIERW.
  3450. //
  3451. DependOnGroupSize += sizeof(WCHAR);
  3452. Entry = (LPWSTR) ((DWORD_PTR) Entry + WCSSIZE(Entry));
  3453. }
  3454. }
  3455. //
  3456. // Allocate the total amount of memory needed for DependOnService
  3457. // and DependOnGroup strings.
  3458. //
  3459. *Dependencies = (LPWSTR) LocalAlloc(LMEM_ZEROINIT,
  3460. DependOnServiceSize +
  3461. DependOnGroupSize +
  3462. sizeof(WCHAR)); // NULL terminator
  3463. if (*Dependencies == NULL) {
  3464. SC_LOG1(ERROR,
  3465. "ScReadDependencies: LocalAlloc failed " FORMAT_DWORD "\n",
  3466. GetLastError());
  3467. status = ERROR_NOT_ENOUGH_MEMORY;
  3468. goto CleanExit;
  3469. }
  3470. if (DependOnService != NULL) {
  3471. RtlCopyMemory(*Dependencies, DependOnService, DependOnServiceSize);
  3472. }
  3473. if (DependOnGroup != NULL) {
  3474. DWORD EntrySize;
  3475. DestPtr = (LPWSTR) ((DWORD_PTR) *Dependencies + DependOnServiceSize);
  3476. Entry = DependOnGroup;
  3477. while (*Entry != 0) {
  3478. EntrySize = (DWORD) wcslen(Entry) + 1;
  3479. *DestPtr = SC_GROUP_IDENTIFIERW;
  3480. DestPtr++;
  3481. wcscpy(DestPtr, Entry);
  3482. DestPtr += EntrySize;
  3483. Entry += EntrySize;
  3484. }
  3485. }
  3486. #if DBG
  3487. SC_LOG0(CONFIG, " Dependencies\n");
  3488. ScDisplayWStrArray(*Dependencies);
  3489. #endif
  3490. }
  3491. CleanExit:
  3492. LocalFree(DependOnService);
  3493. LocalFree(DependOnGroup);
  3494. return(status);
  3495. }
  3496. DWORD
  3497. ScReadConfigFromReg(
  3498. LPSERVICE_RECORD ServiceRecord,
  3499. LPDWORD lpdwServiceType,
  3500. LPDWORD lpdwStartType,
  3501. LPDWORD lpdwErrorControl,
  3502. LPDWORD lpdwTagId,
  3503. LPWSTR *Dependencies,
  3504. LPWSTR *LoadOrderGroup,
  3505. LPWSTR *DisplayName
  3506. )
  3507. /*++
  3508. Routine Description:
  3509. This function obtains some basic information about a service from
  3510. the registry.
  3511. If dependencies or load order group information are not present for
  3512. the service in question, then NULL pointers will be returned for
  3513. these parameters.
  3514. Arguments:
  3515. Return Value:
  3516. --*/
  3517. {
  3518. DWORD ApiStatus = NO_ERROR;
  3519. HKEY ServiceNameKey;
  3520. ApiStatus = ScOpenServiceConfigKey(
  3521. ServiceRecord->ServiceName,
  3522. KEY_READ,
  3523. FALSE, // don't create if missing
  3524. & ServiceNameKey );
  3525. if (ApiStatus != NO_ERROR) {
  3526. return(ApiStatus);
  3527. }
  3528. //---------------------
  3529. // Service Type
  3530. //---------------------
  3531. ApiStatus = ScReadServiceType( ServiceNameKey, lpdwServiceType);
  3532. if (ApiStatus != NO_ERROR) {
  3533. ScRegCloseKey(ServiceNameKey);
  3534. return(ApiStatus);
  3535. }
  3536. //---------------------
  3537. // Start Type
  3538. //---------------------
  3539. ApiStatus = ScReadStartType( ServiceNameKey, lpdwStartType);
  3540. if (ApiStatus != NO_ERROR) {
  3541. ScRegCloseKey(ServiceNameKey);
  3542. return(ApiStatus);
  3543. }
  3544. //---------------------
  3545. // ErrorControl
  3546. //---------------------
  3547. ApiStatus = ScReadErrorControl( ServiceNameKey, lpdwErrorControl);
  3548. if (ApiStatus != NO_ERROR) {
  3549. ScRegCloseKey(ServiceNameKey);
  3550. return(ApiStatus);
  3551. }
  3552. //---------------------
  3553. // TagId
  3554. //---------------------
  3555. if (ScReadTag( ServiceNameKey, lpdwTagId) != NO_ERROR) {
  3556. *lpdwTagId = 0;
  3557. }
  3558. //---------------------
  3559. // Dependencies
  3560. //---------------------
  3561. if (Dependencies != NULL) {
  3562. if (ScReadDependencies(
  3563. ServiceNameKey,
  3564. Dependencies,
  3565. ServiceRecord->ServiceName) != NO_ERROR) {
  3566. *Dependencies = NULL;
  3567. }
  3568. }
  3569. //---------------------
  3570. // LoadGroupOrder
  3571. //---------------------
  3572. if (ScAllocateAndReadConfigValue(
  3573. ServiceNameKey,
  3574. GROUP_VALUENAME_W,
  3575. LoadOrderGroup,
  3576. NULL
  3577. ) != NO_ERROR) {
  3578. *LoadOrderGroup = NULL;
  3579. }
  3580. //---------------------
  3581. // DisplayName
  3582. //---------------------
  3583. if (DisplayName != NULL) {
  3584. ApiStatus = ScReadDisplayName(
  3585. ServiceNameKey,
  3586. DisplayName);
  3587. }
  3588. ScRegCloseKey(ServiceNameKey);
  3589. return(ApiStatus);
  3590. }
  3591. DWORD
  3592. ScTakeOwnership(
  3593. POBJECT_ATTRIBUTES pObja
  3594. )
  3595. /*++
  3596. Routine Description:
  3597. This function attempts to take ownership of the key described by the
  3598. Object Attributes. If successful, it will modify the security descriptor
  3599. to give LocalSystem full control over the key in question.
  3600. Arguments:
  3601. pObja - Pointer to object attributes that describe the key.
  3602. Return Value:
  3603. --*/
  3604. {
  3605. DWORD status = NO_ERROR;
  3606. NTSTATUS ntStatus;
  3607. HKEY hKey;
  3608. DWORD SdBufSize=0;
  3609. SECURITY_DESCRIPTOR tempSD;
  3610. BOOL DaclFlag;
  3611. PACL pDacl;
  3612. BOOL DaclDefaulted;
  3613. PACL pNewDacl=NULL;
  3614. PACCESS_ALLOWED_ACE pMyAce=NULL;
  3615. DWORD bufSize;
  3616. PISECURITY_DESCRIPTOR pSecurityDescriptor = NULL;
  3617. //
  3618. // An event should be logged whenever we must resort to using this
  3619. // routine.
  3620. //
  3621. ScLogEvent(
  3622. NEVENT_TAKE_OWNERSHIP,
  3623. pObja->ObjectName->Buffer
  3624. );
  3625. //
  3626. // If we were denied access, then assume we have the privilege
  3627. // to get WRITE_OWNER access, so that we can modify the Security
  3628. // Descriptor.
  3629. //
  3630. ntStatus = NtOpenKey(
  3631. (PHANDLE)&hKey,
  3632. (ACCESS_MASK)WRITE_OWNER,
  3633. pObja);
  3634. if (!NT_SUCCESS(ntStatus)) {
  3635. // MAKE THIS A TRACE
  3636. SC_LOG(ERROR, "ScTakeOwnership: NtOpenKey(WRITE_OWNER) failed %x\n",ntStatus);
  3637. return(RtlNtStatusToDosError(ntStatus));
  3638. }
  3639. //
  3640. // Set the owner to be local system
  3641. //
  3642. if (!InitializeSecurityDescriptor(&tempSD,SECURITY_DESCRIPTOR_REVISION)) {
  3643. status = GetLastError();
  3644. SC_LOG(ERROR, "ScTakeOwnership: InitializeSD(1) failed %d\n",status);
  3645. NtClose(hKey);
  3646. return(status);
  3647. }
  3648. if (!SetSecurityDescriptorOwner(&tempSD, LocalSystemSid,0)) {
  3649. status = GetLastError();
  3650. SC_LOG(ERROR, "ScTakeOwnership: SetSDOwner failed %d\n",status);
  3651. NtClose(hKey);
  3652. return(status);
  3653. }
  3654. status = ScRegSetKeySecurity(
  3655. hKey,
  3656. OWNER_SECURITY_INFORMATION,
  3657. &tempSD);
  3658. if (status != NO_ERROR) {
  3659. SC_LOG(ERROR, "ScRegOpenKeyExW: ScRegSetKeySecurity (take ownership)"
  3660. " failed %d\n",status);
  3661. }
  3662. NtClose(hKey);
  3663. //
  3664. // Now open the handle again so that the DACL can be modified to
  3665. // allow LocalSystem Full Access.
  3666. //
  3667. ntStatus = NtOpenKey(
  3668. (PHANDLE)&hKey,
  3669. (ACCESS_MASK)READ_CONTROL | WRITE_DAC,
  3670. pObja);
  3671. if (!NT_SUCCESS(ntStatus)) {
  3672. // MAKE THIS A TRACE
  3673. SC_LOG(ERROR, "ScTakeOwnership: NtOpenKey(WRITE_DAC) failed %x\n",ntStatus);
  3674. return(RtlNtStatusToDosError(ntStatus));
  3675. }
  3676. status = ScRegGetKeySecurity(
  3677. hKey,
  3678. DACL_SECURITY_INFORMATION,
  3679. pSecurityDescriptor,
  3680. &SdBufSize);
  3681. if (status != ERROR_INSUFFICIENT_BUFFER) {
  3682. SC_LOG(ERROR, "ScTakeOwnership: ScRegGetKeySecurity(1) failed %d\n",
  3683. status);
  3684. NtClose(hKey);
  3685. return(status);
  3686. }
  3687. pSecurityDescriptor = (PISECURITY_DESCRIPTOR) LocalAlloc(LMEM_FIXED,SdBufSize);
  3688. if (pSecurityDescriptor == NULL) {
  3689. status = GetLastError();
  3690. SC_LOG(ERROR, "ScTakeOwnership: LocalAlloc failed %d\n",status);
  3691. NtClose(hKey);
  3692. return(status);
  3693. }
  3694. status = ScRegGetKeySecurity(
  3695. hKey,
  3696. DACL_SECURITY_INFORMATION,
  3697. pSecurityDescriptor,
  3698. &SdBufSize);
  3699. if (status != NO_ERROR) {
  3700. SC_LOG(ERROR, "ScTakeOwnership: ScRegGetKeySecurity(2) failed %d\n",
  3701. status);
  3702. goto CleanExit;
  3703. }
  3704. //
  3705. // Modify the DACL to allow LocalSystem to have all access.
  3706. //
  3707. // Get size of DACL
  3708. if (!GetSecurityDescriptorDacl (
  3709. pSecurityDescriptor,
  3710. &DaclFlag,
  3711. &pDacl,
  3712. &DaclDefaulted)) {
  3713. status = GetLastError();
  3714. SC_LOG(ERROR, "ScTakeOwnership: GetSecurityDescriptorDacl "
  3715. " failed %d\n",status);
  3716. goto CleanExit;
  3717. }
  3718. //
  3719. // Create new ACE.
  3720. //
  3721. bufSize = sizeof(ACE_HEADER) +
  3722. sizeof(ACCESS_MASK) +
  3723. GetLengthSid(LocalSystemSid);
  3724. pMyAce = (PACCESS_ALLOWED_ACE) LocalAlloc(LMEM_ZEROINIT, bufSize);
  3725. if (pMyAce == NULL) {
  3726. status = GetLastError();
  3727. SC_LOG(ERROR, "ScTakeOwnership: LocalAlloc(Ace) failed %d\n",status);
  3728. goto CleanExit;
  3729. }
  3730. pMyAce->Header.AceType = ACCESS_ALLOWED_ACE_TYPE;
  3731. pMyAce->Header.AceFlags = CONTAINER_INHERIT_ACE;
  3732. pMyAce->Header.AceSize = (WORD)bufSize;
  3733. pMyAce->Mask = GENERIC_ALL;
  3734. if (!CopySid(
  3735. GetLengthSid(LocalSystemSid),
  3736. &(pMyAce->SidStart),
  3737. LocalSystemSid)) {
  3738. status = GetLastError();
  3739. SC_LOG(ERROR, "ScTakeOwnership: CopySid failed %d\n",status);
  3740. goto CleanExit;
  3741. }
  3742. //
  3743. // Allocate buffer for DACL and new ACE.
  3744. //
  3745. bufSize += pDacl->AclSize;
  3746. pNewDacl = (PACL) LocalAlloc(LMEM_ZEROINIT, bufSize);
  3747. if (pNewDacl == NULL) {
  3748. status = GetLastError();
  3749. SC_LOG(ERROR, "ScTakeOwnership: LocalAlloc (DACL) "
  3750. " failed %d\n",status);
  3751. goto CleanExit;
  3752. }
  3753. if (!InitializeAcl(pNewDacl, bufSize, ACL_REVISION)) {
  3754. status = GetLastError();
  3755. SC_LOG(ERROR, "ScTakeOwnership: InitializeAcl failed %d\n",status);
  3756. goto CleanExit;
  3757. }
  3758. //
  3759. // Add the ACE to the DACL
  3760. //
  3761. if (!AddAce(
  3762. pNewDacl, // pACL
  3763. pDacl->AclRevision, // dwACLRevision
  3764. 0, // dwStartingAceIndex
  3765. pMyAce, // pAceList
  3766. (DWORD)pMyAce->Header.AceSize)) { // cbAceList
  3767. status = GetLastError();
  3768. SC_LOG(ERROR, "ScTakeOwnership: AddAce failed %d\n",status);
  3769. goto CleanExit;
  3770. }
  3771. //
  3772. // Initialize a new SD.
  3773. //
  3774. if (!InitializeSecurityDescriptor(&tempSD,SECURITY_DESCRIPTOR_REVISION)) {
  3775. status = GetLastError();
  3776. SC_LOG(ERROR, "ScTakeOwnership: InitializeSD failed %d\n",status);
  3777. goto CleanExit;
  3778. }
  3779. //
  3780. // Add the new DACL to the SD
  3781. //
  3782. if (!SetSecurityDescriptorDacl(&tempSD,TRUE,pNewDacl,FALSE)) {
  3783. status = GetLastError();
  3784. SC_LOG(ERROR, "ScTakeOwnership: SetSecurityDescriptorDacl failed %d\n",status);
  3785. goto CleanExit;
  3786. }
  3787. //
  3788. // Set DACL on the key's security descriptor.
  3789. //
  3790. status = ScRegSetKeySecurity(
  3791. hKey,
  3792. DACL_SECURITY_INFORMATION,
  3793. &tempSD);
  3794. if (status != NO_ERROR) {
  3795. SC_LOG(ERROR, "ScTakeOwnership: ScRegSetKeySecurity(new DACL) failed %d\n",
  3796. status);
  3797. }
  3798. SC_LOG0(CONFIG, "ScTakeOwnership: Changed SD, now try to open with "
  3799. "Desired Access\n");
  3800. CleanExit:
  3801. LocalFree(pNewDacl);
  3802. LocalFree(pMyAce);
  3803. LocalFree (pSecurityDescriptor);
  3804. NtClose(hKey);
  3805. return(status);
  3806. } // ScTakeOwnership
  3807. DWORD
  3808. ScOpenSecurityKey(
  3809. IN HKEY ServiceNameKey,
  3810. IN DWORD DesiredAccess,
  3811. IN BOOL CreateIfMissing,
  3812. OUT PHKEY pSecurityKey
  3813. )
  3814. /*++
  3815. Routine Description:
  3816. This function opens, or creates (if it doesn't exist), the Security Key
  3817. that is a sub-key of the service's key. This key is created such that
  3818. only LocalSystem and Administrators have access.
  3819. Arguments:
  3820. ServiceNameKey - This is a key to the service key that will contain
  3821. the security key.
  3822. DesiredAccess - This is the access that is desired with the SecurityKey
  3823. that will be returned on a successful call.
  3824. pSecurityKey - A pointer to a location where the security key is to
  3825. be placed.
  3826. Return Value:
  3827. NO_ERROR - if the operation is successful.
  3828. otherwise, a registry error code is returned.
  3829. --*/
  3830. {
  3831. LONG RegError;
  3832. LPWSTR SecurityKeyName = SD_VALUENAME_W;
  3833. DWORD Disposition;
  3834. NTSTATUS ntstatus;
  3835. SECURITY_ATTRIBUTES SecurityAttr;
  3836. PSECURITY_DESCRIPTOR SecurityDescriptor;
  3837. #define SEC_KEY_ACE_COUNT 2
  3838. SC_ACE_DATA AceData[SEC_KEY_ACE_COUNT] = {
  3839. {ACCESS_ALLOWED_ACE_TYPE, CONTAINER_INHERIT_ACE, 0,
  3840. GENERIC_ALL, &LocalSystemSid},
  3841. {ACCESS_ALLOWED_ACE_TYPE, CONTAINER_INHERIT_ACE, 0,
  3842. GENERIC_ALL, &AliasAdminsSid}
  3843. };
  3844. if (!CreateIfMissing) {
  3845. //
  3846. // Open the existing security key.
  3847. //
  3848. RegError = ScRegOpenKeyExW(
  3849. ServiceNameKey,
  3850. SecurityKeyName,
  3851. REG_OPTION_NON_VOLATILE,
  3852. DesiredAccess,
  3853. pSecurityKey);
  3854. if (RegError != ERROR_SUCCESS) {
  3855. SC_LOG2(TRACE, "ScOpenSecurityKey: "
  3856. "ScRegOpenKeyExW of " FORMAT_LPWSTR " failed "
  3857. FORMAT_LONG "\n", SecurityKeyName, RegError);
  3858. }
  3859. return((DWORD)RegError);
  3860. }
  3861. //
  3862. // Create a security descriptor for the registry key we are about
  3863. // to create. This gives everyone read access, and all access to
  3864. // ourselves and the admins.
  3865. //
  3866. ntstatus = ScCreateAndSetSD(
  3867. AceData,
  3868. SEC_KEY_ACE_COUNT,
  3869. LocalSystemSid,
  3870. LocalSystemSid,
  3871. &SecurityDescriptor
  3872. );
  3873. if (! NT_SUCCESS(ntstatus)) {
  3874. SC_LOG1(ERROR, "ScCreateAndSetSD failed " FORMAT_NTSTATUS
  3875. "\n", ntstatus);
  3876. return(RtlNtStatusToDosError(ntstatus));
  3877. }
  3878. //
  3879. // Protect the DACL on the SD so it can't be overridden by DACL inheritance
  3880. // from parent keys. Since this key can contain a SACL, we want to make
  3881. // sure access to it is always what we expect.
  3882. //
  3883. ntstatus = RtlSetControlSecurityDescriptor(SecurityDescriptor,
  3884. SE_DACL_PROTECTED,
  3885. SE_DACL_PROTECTED);
  3886. if (!NT_SUCCESS(ntstatus))
  3887. {
  3888. SC_LOG1(ERROR,
  3889. "ScOpenSecurityKey: RtlSetControlSecurityDescriptor failed %x\n",
  3890. ntstatus);
  3891. RtlDeleteSecurityObject(&SecurityDescriptor);
  3892. return RtlNtStatusToDosError(ntstatus);
  3893. }
  3894. SecurityAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
  3895. SecurityAttr.lpSecurityDescriptor = SecurityDescriptor;
  3896. SecurityAttr.bInheritHandle = FALSE;
  3897. //
  3898. // Create a new service key (or open existing one).
  3899. //
  3900. RegError = ScRegCreateKeyExW(
  3901. ServiceNameKey,
  3902. SecurityKeyName,
  3903. 0,
  3904. 0,
  3905. REG_OPTION_NON_VOLATILE, // options
  3906. DesiredAccess, // desired access
  3907. &SecurityAttr,
  3908. pSecurityKey,
  3909. &Disposition);
  3910. RtlDeleteSecurityObject(&SecurityDescriptor);
  3911. if (RegError != ERROR_SUCCESS) {
  3912. SC_LOG2(ERROR, "ScOpenSecurityKey: "
  3913. "ScRegCreateKeyExW of " FORMAT_LPWSTR " failed "
  3914. FORMAT_LONG "\n", SecurityKeyName, RegError);
  3915. return ((DWORD) RegError);
  3916. }
  3917. return NO_ERROR;
  3918. } // ScOpenSecurityKey