Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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