Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

3147 lines
92 KiB

  1. /*++
  2. Copyright (c) 1992 Microsoft Corporation
  3. Module Name:
  4. CfgAPI.cxx
  5. Abstract:
  6. This file contains the Service Controller's Config API.
  7. RChangeServiceConfigW
  8. RCreateServiceW
  9. RDeleteService
  10. RQueryServiceConfigW
  11. ScCanonDriverImagePath
  12. Author:
  13. John Rogers (JohnRo) 10-Apr-1992
  14. Environment:
  15. User Mode - Win32
  16. Revision History:
  17. 26-Mar-1992 danl
  18. Created the stubbed out version for RPC.
  19. 22-Apr-1992 JohnRo
  20. Use SC_LOG0(), FORMAT_ equates, etc
  21. Wrote real code for these APIs.
  22. Split lock APIs into server/lockapi.c.
  23. Added some assertion checks here and there. Added handle checks too.
  24. 28-Apr-1992 JohnRo
  25. Undo all group operations (ifdef USE_GROUPS).
  26. 28-May-1992 JohnRo
  27. Put back load order group in APIs.
  28. Avoid compiler warnings.
  29. 02-Jun-1992 JohnRo
  30. RAID 10709: QueryServiceConfig() has bad length check.
  31. 08-Aug-1992 Danl
  32. RDeleteService: Add call to ScMarkForDelete so the registry entry
  33. is marked for deletion.
  34. 25-Aug-1992 Danl
  35. RQueryServiceConfig: Fix problem where it failed if it couldn't
  36. read the StartName from the registry. (This should be optional).
  37. 21-Jan-1994 Danl
  38. RChangeServiceConfigW: Fixed BUG where a unicode DisplayName was
  39. being copied into a buffer whose size assumed ansi characters.
  40. Also changed so that displayname is not allocated unless it is
  41. different from the ServiceName.
  42. 24-Mar-1994 Danl
  43. RQueryServiceConfigW: Add worse case number of bytes (3) for RPC
  44. alignment. I removed the exact calculation because it assumed
  45. that strings went into the buffer in a particular order. Since RPC
  46. picks the order for unmarshalling into the users buffer, the order
  47. may be random.
  48. 06-Jun-1994 Danl
  49. We were allocating memory for the display name in the service record only
  50. when it was the same. It should have been doing this only when different.
  51. The behaviour was such that if you changed the display name to something
  52. other than the KeyName, the new name was placed in the registry, but not
  53. in the service record. So GetKeyName on the new name would fail.
  54. 20-Jun-1994 Danl
  55. Added SERVICE_WIN32_INTERACTIVE support to service type.
  56. 21-Jan-1995 AnirudhS
  57. RCreateServiceW: This was calling ScAccessValidate to check if the caller
  58. had the desired access to the object on creation of a new service object.
  59. Fixed this to just grant the desired access instead.
  60. 26-Feb-1996 AnirudhS
  61. RChangeServiceConfigW: Would generate a tag only if the group name
  62. changed. Fixed it to always generate and return a tag if one is
  63. requested, just like RCreateServiceW.
  64. 09-Dec-1996 AnirudhS
  65. Added SC_LOG printouts to help diagnose the annoying
  66. ERROR_INVALID_PARAMETER and ERROR_INVALID_SERVICE_ACCOUNT return codes.
  67. 22-Oct-1997 JSchwart (after AnirudhS in _CAIRO_ 12-Apr-1995)
  68. RChangeServiceConfigW and RCreateServiceW: Allow services that run under
  69. accounts other than LocalSystem to share processes too.
  70. --*/
  71. //
  72. // INCLUDES
  73. //
  74. #include "precomp.hxx"
  75. #include <scconfig.h> // ScGetImageFileName().
  76. #include <sclib.h> // ScImagePathsMatch(), ScIsValidImagePath(), etc.
  77. #include <scsec.h> // ScAccessValidate().
  78. #include <valid.h> // SERVICE_TYPE_INVALID(), etc.
  79. #include <sccrypt.h> // ScDecryptPassword
  80. #include "account.h" // ScValidateAndSaveAccount
  81. #include <strarray.h> // ScWStrArraySize
  82. #include <align.h> // ROUND_UP_COUNT
  83. #include "smartp.h" // CHeapPtr
  84. #include "resource.h" // IDS_SC_CONFIG_* constants
  85. #define SC_NT_SYSTEM_ROOT L"\\SystemRoot\\"
  86. #define SC_DOS_SYSTEM_ROOT L"%SystemRoot%\\"
  87. #define SERVICE_TYPE_CHANGED 0x00000001
  88. #define START_TYPE_CHANGED 0x00000002
  89. #define ERROR_CONTROL_CHANGED 0x00000004
  90. #define BINARY_PATH_CHANGED 0x00000008
  91. #define REG_GROUP_CHANGED 0x00000010
  92. #define TAG_ID_CHANGED 0x00000020
  93. #define DEPENDENCIES_CHANGED_SR 0x00000040 // Not in NT4
  94. #define DEPENDENCIES_CHANGED_REG 0x00000080 // Not in NT4
  95. #define START_NAME_CHANGED 0x00000100
  96. #define SR_GROUP_CHANGED 0x00000200
  97. #define DISPLAY_NAME_CHANGED_SR 0x00000400
  98. #define DISPLAY_NAME_CHANGED_REG 0x00000800
  99. DWORD
  100. ScCanonDriverImagePath(
  101. IN DWORD DriverStartType,
  102. IN LPWSTR DriverPath,
  103. OUT LPWSTR *CanonDriverPath
  104. );
  105. DWORD
  106. ScConvertToBootPathName(
  107. LPWSTR FullQualPathName,
  108. LPWSTR * RelativePathName
  109. );
  110. DWORD
  111. ScValidateDisplayName(
  112. LPWSTR lpDisplayName,
  113. LPSERVICE_RECORD lpServiceRecord
  114. );
  115. BOOLEAN
  116. ScIsArcName(
  117. LPWSTR PathName
  118. );
  119. DWORD
  120. RChangeServiceConfigW(
  121. IN SC_RPC_HANDLE hService,
  122. IN DWORD dwServiceType,
  123. IN DWORD dwStartType,
  124. IN DWORD dwErrorControl,
  125. IN LPWSTR lpBinaryPathName,
  126. IN LPWSTR lpLoadOrderGroup,
  127. OUT LPDWORD lpdwTagId,
  128. IN LPBYTE lpDependencies,
  129. IN DWORD dwDependSize,
  130. IN LPWSTR lpServiceStartName,
  131. IN LPBYTE EncryptedPassword,
  132. IN DWORD PasswordSize,
  133. IN LPWSTR lpDisplayName
  134. )
  135. /*++
  136. Routine Description:
  137. Arguments:
  138. Return Value:
  139. --*/
  140. {
  141. DWORD ApiStatus;
  142. DWORD backoutStatus;
  143. DWORD newServiceType;
  144. LPSC_HANDLE_STRUCT serviceHandleStruct = (LPSC_HANDLE_STRUCT) hService;
  145. HKEY ServiceNameKey = NULL;
  146. LPSERVICE_RECORD serviceRecord;
  147. LPWSTR CanonBinaryPath = NULL;
  148. LPWSTR NewBinaryPath = NULL;
  149. LPWSTR OldAccountName = NULL;
  150. LPWSTR CanonAccountName = NULL;
  151. DWORD CurrentServiceType = 0;
  152. DWORD CurrentStartType = 0;
  153. DWORD CurrentErrorControl = 0;
  154. LPWSTR CurrentImageName = NULL;
  155. LPWSTR CurrentDependencies = NULL;
  156. LPWSTR CurrentDisplayName = NULL;
  157. LPWSTR CurrentGroup = NULL;
  158. LPWSTR CurrentStartName = NULL;
  159. DWORD CurrentTag = 0;
  160. DWORD Tag = 0;
  161. DWORD Progress = 0;
  162. LPWSTR Password = NULL;
  163. LPWSTR OldSRDisplayName = NULL;
  164. LPWSTR NewDisplayName = NULL;
  165. if (ScShutdownInProgress) {
  166. return(ERROR_SHUTDOWN_IN_PROGRESS);
  167. }
  168. //
  169. // Check the handle.
  170. //
  171. if ( !ScIsValidServiceHandle( hService ) ) {
  172. return(ERROR_INVALID_HANDLE);
  173. }
  174. SC_LOG(CONFIG_API, "RChangeServiceConfigW(%ws)\n",
  175. serviceHandleStruct->Type.ScServiceObject.ServiceRecord->ServiceName);
  176. //
  177. // Do we have permission to do this?
  178. //
  179. if ( !RtlAreAllAccessesGranted(
  180. serviceHandleStruct->AccessGranted,
  181. SERVICE_CHANGE_CONFIG
  182. )) {
  183. return(ERROR_ACCESS_DENIED);
  184. }
  185. if (lpdwTagId != NULL) {
  186. //
  187. // Asking for new tag value but didn't specify group
  188. //
  189. if ((lpLoadOrderGroup == NULL) || (*lpLoadOrderGroup == 0)) {
  190. SC_LOG0(ERROR, "Asking for new tag value but didn't specify group\n");
  191. return(ERROR_INVALID_PARAMETER);
  192. }
  193. }
  194. //
  195. // Lock database, as we want to add stuff without other threads tripping
  196. // on our feet. NOTE: since we may need the group list lock, we
  197. // must get that lock first.
  198. //
  199. CGroupListExclusiveLock GLock;
  200. CServiceListSharedLock LLock;
  201. CServiceRecordExclusiveLock RLock;
  202. //
  203. // Find the service record for this handle.
  204. //
  205. serviceRecord =
  206. serviceHandleStruct->Type.ScServiceObject.ServiceRecord;
  207. SC_ASSERT( serviceRecord != NULL );
  208. SC_ASSERT( serviceRecord->Signature == SERVICE_SIGNATURE );
  209. //
  210. // Disallow this call if record is marked for delete.
  211. //
  212. if (DELETE_FLAG_IS_SET(serviceRecord)) {
  213. return(ERROR_SERVICE_MARKED_FOR_DELETE);
  214. }
  215. //
  216. // If there is a DisplayName specified, check to see if it already
  217. // exists.
  218. //
  219. ApiStatus = ScValidateDisplayName(lpDisplayName,serviceRecord);
  220. if (ApiStatus != NO_ERROR) {
  221. SC_LOG0(ERROR, "DisplayName invalid\n");
  222. return(ApiStatus);
  223. }
  224. //
  225. // Figure-out what the resulting service type will be.
  226. // (Some other stuff below depends on this.)
  227. //
  228. if (dwServiceType != SERVICE_NO_CHANGE) {
  229. if ( SERVICE_TYPE_INVALID( dwServiceType ) ) {
  230. SC_LOG0(ERROR, "ServiceType invalid\n");
  231. return(ERROR_INVALID_PARAMETER);
  232. }
  233. newServiceType = dwServiceType;
  234. }
  235. else {
  236. newServiceType = serviceRecord->ServiceStatus.dwServiceType;
  237. }
  238. SC_ASSERT( newServiceType != SERVICE_NO_CHANGE );
  239. //
  240. // Validate other parameters.
  241. //
  242. ApiStatus = ScCheckServiceConfigParms(
  243. TRUE, // This is a change operation
  244. serviceRecord->ServiceName,
  245. serviceRecord->ServiceStatus.dwServiceType, // new actual type
  246. dwServiceType,
  247. dwStartType,
  248. dwErrorControl,
  249. lpBinaryPathName,
  250. lpLoadOrderGroup,
  251. (LPWSTR)lpDependencies,
  252. dwDependSize);
  253. if (ApiStatus != NO_ERROR) {
  254. return(ApiStatus);
  255. }
  256. //-----------------------------
  257. //
  258. // Begin Updating the Registry
  259. //
  260. //-----------------------------
  261. ApiStatus = ScOpenServiceConfigKey(
  262. serviceRecord->ServiceName,
  263. KEY_WRITE | KEY_READ,
  264. FALSE, // don't create if missing
  265. & ServiceNameKey );
  266. if (ApiStatus != NO_ERROR) {
  267. return(ApiStatus);
  268. }
  269. //--------------------------------------
  270. // (from here on we need to use Cleanup)
  271. //
  272. // Service Type
  273. //--------------------------------------
  274. if (dwServiceType != SERVICE_NO_CHANGE) {
  275. //
  276. // If this service is supposed to be interactive, make sure
  277. // the service account is LocalSystem. Otherwise, it should
  278. // fail with ERROR_INVALID_PARAMETER.
  279. //
  280. if (dwServiceType & SERVICE_INTERACTIVE_PROCESS) {
  281. if (ARGUMENT_PRESENT(lpServiceStartName)) {
  282. ApiStatus = ScCanonAccountName(lpServiceStartName, &CanonAccountName);
  283. if (ApiStatus != NO_ERROR) {
  284. goto Cleanup;
  285. }
  286. if (_wcsicmp(CanonAccountName,SC_LOCAL_SYSTEM_USER_NAME) != 0) {
  287. SC_LOG0(ERROR, "Service must run in LocalSystem account to be interactive\n");
  288. ApiStatus = ERROR_INVALID_PARAMETER;
  289. goto Cleanup;
  290. }
  291. }
  292. else {
  293. //
  294. // Get old account name
  295. //
  296. ApiStatus = ScReadStartName(ServiceNameKey, &OldAccountName);
  297. if (ApiStatus != NO_ERROR) {
  298. goto Cleanup;
  299. }
  300. if (_wcsicmp(OldAccountName, SC_LOCAL_SYSTEM_USER_NAME) != 0) {
  301. SC_LOG0(ERROR, "Service must run in LocalSystem account to be interactive\n");
  302. ApiStatus = ERROR_INVALID_PARAMETER;
  303. goto Cleanup;
  304. }
  305. }
  306. }
  307. ApiStatus = ScReadServiceType( ServiceNameKey, &CurrentServiceType);
  308. if (ApiStatus != NO_ERROR) {
  309. goto Cleanup;
  310. }
  311. ApiStatus = ScWriteServiceType( ServiceNameKey, dwServiceType);
  312. if (ApiStatus != NO_ERROR) {
  313. goto Cleanup;
  314. }
  315. Progress |= SERVICE_TYPE_CHANGED;
  316. }
  317. else {
  318. //
  319. // ServiceType is not being changed.
  320. //
  321. CurrentServiceType = serviceRecord->ServiceStatus.dwServiceType;
  322. //
  323. // if the current service type contains the interactive bit, and the
  324. // account type is being changed to something other than LocalSystem,
  325. // then we should fail the call with ERROR_INVALID_PARAMETER.
  326. //
  327. if (ARGUMENT_PRESENT(lpServiceStartName)) {
  328. if ((CurrentServiceType & SERVICE_INTERACTIVE_PROCESS) &&
  329. (_wcsicmp(lpServiceStartName,SC_LOCAL_SYSTEM_USER_NAME) != 0)) {
  330. SC_LOG0(ERROR, "Service must run in LocalSystem account to be interactive\n");
  331. ApiStatus = ERROR_INVALID_PARAMETER;
  332. goto Cleanup;
  333. }
  334. }
  335. }
  336. //---------------------
  337. // Start Type
  338. //---------------------
  339. if (dwStartType != SERVICE_NO_CHANGE) {
  340. ApiStatus = ScReadStartType( ServiceNameKey, &CurrentStartType);
  341. if (ApiStatus != NO_ERROR) {
  342. goto Cleanup;
  343. }
  344. ApiStatus = ScWriteStartType( ServiceNameKey, dwStartType);
  345. if (ApiStatus != NO_ERROR) {
  346. goto Cleanup;
  347. }
  348. Progress |= START_TYPE_CHANGED;
  349. //
  350. // If they're supplying a new binary name, making it correct for the
  351. // Start type will happen automatically. If they're keeping the
  352. // same imagepath, we need to make sure it of the correct format,
  353. // and if not, fix it.
  354. //
  355. if (lpBinaryPathName == NULL) {
  356. //
  357. // If the start type is changing from SERVICE_BOOT_START we need
  358. // to turn the start path into a fully qualified NT name (BOOT
  359. // drivers have paths relative to systemroot)
  360. //
  361. if (CurrentStartType == SERVICE_BOOT_START &&
  362. dwStartType != SERVICE_BOOT_START) {
  363. //
  364. // Note: The following call allocates storage for the
  365. // CurrentImageName
  366. //
  367. ApiStatus = ScGetImageFileName (
  368. serviceRecord->ServiceName,
  369. &CurrentImageName );
  370. if (ApiStatus != NO_ERROR && ApiStatus != ERROR_PATH_NOT_FOUND) {
  371. SC_LOG(ERROR,"RChangeServiceConfigW: ScGetImageFileName failed %d\n",
  372. ApiStatus);
  373. goto Cleanup;
  374. }
  375. //
  376. // If there's an existing path, we need to fix
  377. // If it is an ARC name, leave it alone
  378. //
  379. //
  380. if (ApiStatus != ERROR_PATH_NOT_FOUND &&
  381. !ScIsArcName(CurrentImageName)) {
  382. //
  383. // Prepend \systemroot\ to the beginning of the path
  384. //
  385. NewBinaryPath = (LPWSTR)LocalAlloc(LMEM_ZEROINIT,
  386. (UINT) ((wcslen(CurrentImageName) +
  387. wcslen(SC_NT_SYSTEM_ROOT) + 1) * sizeof(WCHAR)));
  388. if (!NewBinaryPath) {
  389. SC_LOG(ERROR,"RChangeServiceConfigW: LocalAlloc failed %d\n",
  390. GetLastError());
  391. ApiStatus = ERROR_NOT_ENOUGH_MEMORY;
  392. goto Cleanup;
  393. }
  394. wcscpy(NewBinaryPath, SC_NT_SYSTEM_ROOT);
  395. wcscat(NewBinaryPath, CurrentImageName);
  396. lpBinaryPathName = NewBinaryPath;
  397. }
  398. ApiStatus = NO_ERROR;
  399. LocalFree(CurrentImageName);
  400. }
  401. //
  402. // If the start type is changing to SERVICE_BOOT_START, we need
  403. // to make sure the ImagePath gets canonicalized
  404. //
  405. else if (dwStartType == SERVICE_BOOT_START &&
  406. CurrentStartType != SERVICE_BOOT_START) {
  407. //
  408. // Note: The following call allocates storage for the
  409. // CurrentImageName
  410. //
  411. ApiStatus = ScGetImageFileName (
  412. serviceRecord->ServiceName,
  413. &CurrentImageName );
  414. if (ApiStatus != NO_ERROR && ApiStatus != ERROR_PATH_NOT_FOUND) {
  415. SC_LOG(ERROR,"RChangeServiceConfigW: ScGetImageFileName failed %d\n",
  416. ApiStatus);
  417. goto Cleanup;
  418. }
  419. //
  420. // If there's an existing path and it's not an ARC name, we
  421. // need to fix
  422. //
  423. if (ApiStatus != ERROR_PATH_NOT_FOUND &&
  424. !ScIsArcName(CurrentImageName)) {
  425. //
  426. // Now make sure it's in the proper canonical form for a
  427. // boot driver.
  428. //
  429. ApiStatus = ScConvertToBootPathName(
  430. CurrentImageName,
  431. &NewBinaryPath
  432. );
  433. if (ApiStatus != NO_ERROR) {
  434. SC_LOG(ERROR, "ScConvertToBootPathName error %lu\n", ApiStatus);
  435. goto Cleanup;
  436. }
  437. lpBinaryPathName = NewBinaryPath;
  438. LocalFree(CurrentImageName);
  439. }
  440. ApiStatus = NO_ERROR;
  441. }
  442. }
  443. }
  444. //---------------------
  445. // ErrorControl
  446. //---------------------
  447. if (dwErrorControl != SERVICE_NO_CHANGE) {
  448. ApiStatus = ScReadErrorControl( ServiceNameKey, &CurrentErrorControl);
  449. if (ApiStatus != NO_ERROR) {
  450. goto Cleanup;
  451. }
  452. ApiStatus = ScWriteErrorControl( ServiceNameKey, dwErrorControl );
  453. if (ApiStatus != NO_ERROR) {
  454. goto Cleanup;
  455. }
  456. Progress |= ERROR_CONTROL_CHANGED;
  457. }
  458. //---------------------
  459. // DisplayName
  460. //---------------------
  461. if (lpDisplayName != NULL) {
  462. //
  463. // UPDATE SERVICE RECORD
  464. //
  465. // We always update the display name in the service record - even
  466. // if we delay in updating the rest of the config. If we don't
  467. // do this, then we leave an opening where two services can end
  468. // up with the same display name.
  469. // The following scenerio can take place if we don't update
  470. // the service record until the service is stopped:
  471. //
  472. // Until serviceA is stopped, the new display name only exists
  473. // in the registry. In the mean time, another service (serviceB)
  474. // can be given the same name. Name validation only looks in
  475. // the service records for duplicate names. Then when serviceA is
  476. // stopped, it takes on the new name which is the same as the
  477. // display name for serviceB.
  478. //
  479. OldSRDisplayName = serviceRecord->DisplayName;
  480. //
  481. // If the display name is the same as the service name,
  482. // then set the display name pointer to point to
  483. // the service name.
  484. //
  485. if ((*lpDisplayName != L'\0') &&
  486. (_wcsicmp(lpDisplayName,serviceRecord->ServiceName) != 0)) {
  487. NewDisplayName = (LPWSTR)LocalAlloc(
  488. LMEM_FIXED,
  489. WCSSIZE(lpDisplayName));
  490. if (NewDisplayName == NULL) {
  491. SC_LOG0(ERROR,"RChangeServiceConfigW: LocalAlloc failed\n");
  492. ApiStatus = ERROR_NOT_ENOUGH_MEMORY;
  493. serviceRecord->DisplayName = OldSRDisplayName;
  494. goto Cleanup;
  495. }
  496. //
  497. // Copy the display name into new buffer, and free up memory
  498. // for old name if necessary.
  499. //
  500. wcscpy(NewDisplayName, lpDisplayName);
  501. }
  502. else {
  503. NewDisplayName = serviceRecord->ServiceName;
  504. }
  505. serviceRecord->DisplayName = NewDisplayName;
  506. Progress |= DISPLAY_NAME_CHANGED_SR;
  507. //
  508. // UPDATE REGISTRY
  509. //
  510. ApiStatus = ScReadDisplayName(ServiceNameKey, &CurrentDisplayName);
  511. if (ApiStatus != NO_ERROR) {
  512. goto Cleanup;
  513. }
  514. ApiStatus = ScWriteDisplayName( ServiceNameKey, lpDisplayName);
  515. if (ApiStatus != NO_ERROR) {
  516. goto Cleanup;
  517. }
  518. Progress |= DISPLAY_NAME_CHANGED_REG;
  519. }
  520. //---------------------
  521. // BinaryPathName
  522. //---------------------
  523. if (lpBinaryPathName != NULL) {
  524. //
  525. // Note: The following call allocates storage for the CurrentImageName
  526. //
  527. ApiStatus = ScGetImageFileName (
  528. serviceRecord->ServiceName,
  529. &CurrentImageName );
  530. if (ApiStatus != NO_ERROR && ApiStatus != ERROR_PATH_NOT_FOUND) {
  531. SC_LOG(ERROR,"RChangeServiceConfigW: ScGetImageFileName failed %d\n",
  532. ApiStatus);
  533. goto Cleanup;
  534. }
  535. if (CurrentServiceType & SERVICE_DRIVER) {
  536. //
  537. // Driver service
  538. //
  539. ApiStatus = ScCanonDriverImagePath(
  540. dwStartType,
  541. lpBinaryPathName,
  542. &CanonBinaryPath
  543. );
  544. if (ApiStatus != NO_ERROR) {
  545. SC_LOG(ERROR, "ScCanonDriverImagePath error %lu\n", ApiStatus);
  546. goto Cleanup;
  547. }
  548. if (CurrentImageName == NULL ||
  549. !ScImagePathsMatch(CanonBinaryPath, CurrentImageName)) {
  550. ApiStatus = ScWriteImageFileName( ServiceNameKey, CanonBinaryPath);
  551. if (ApiStatus != NO_ERROR) {
  552. SC_LOG(ERROR,"RChangeServiceConfigW: ScWriteImageFileName "
  553. "failed %d\n",ApiStatus);
  554. goto Cleanup;
  555. }
  556. Progress |= BINARY_PATH_CHANGED;
  557. }
  558. }
  559. else {
  560. //
  561. // Win32 service
  562. //
  563. if (CurrentImageName == NULL ||
  564. !ScImagePathsMatch(lpBinaryPathName, CurrentImageName)) {
  565. ApiStatus = ScWriteImageFileName( ServiceNameKey, lpBinaryPathName);
  566. if (ApiStatus != NO_ERROR) {
  567. SC_LOG(ERROR,"RChangeServiceConfigW: ScWriteImageFileName "
  568. "failed %d\n",ApiStatus);
  569. goto Cleanup;
  570. }
  571. Progress |= BINARY_PATH_CHANGED;
  572. }
  573. }
  574. }
  575. //---------------------
  576. // Dependencies
  577. //---------------------
  578. if (lpDependencies != NULL) {
  579. //
  580. // Read the existing dependencies from registry so
  581. // that we can restore it in case of failure later.
  582. // We don't check for error here. We assume a failure means
  583. // that there are no current dependencies.
  584. //
  585. ScReadDependencies(
  586. ServiceNameKey,
  587. &CurrentDependencies,
  588. serviceRecord->ServiceName);
  589. //
  590. // Dynamically update the dependencies and check to make sure
  591. // updating was error-free
  592. //
  593. ApiStatus = ScUpdateServiceRecordConfig(
  594. serviceRecord,
  595. SERVICE_NO_CHANGE,
  596. SERVICE_NO_CHANGE,
  597. SERVICE_NO_CHANGE,
  598. NULL,
  599. (LPBYTE)lpDependencies);
  600. if (ApiStatus != NO_ERROR) {
  601. goto Cleanup;
  602. }
  603. Progress |= DEPENDENCIES_CHANGED_SR;
  604. //
  605. // Update the dependencies in the registry
  606. //
  607. ApiStatus = ScWriteDependencies(
  608. ServiceNameKey,
  609. (LPWSTR) lpDependencies,
  610. dwDependSize
  611. );
  612. if (ApiStatus != NO_ERROR) {
  613. goto Cleanup;
  614. }
  615. Progress |= DEPENDENCIES_CHANGED_REG;
  616. }
  617. //---------------------
  618. // Load order group
  619. //---------------------
  620. if (lpLoadOrderGroup != NULL) {
  621. //
  622. // Save existing group membership info so that we can restore
  623. // it in case of error.
  624. // Read the Current LoadOrderGroup value from Registry
  625. //
  626. if (ScAllocateAndReadConfigValue(
  627. ServiceNameKey,
  628. GROUP_VALUENAME_W,
  629. &CurrentGroup,
  630. NULL
  631. ) != NO_ERROR) {
  632. CurrentGroup = NULL;
  633. }
  634. //
  635. // Read current Tag Id to save in case of error.
  636. //
  637. CurrentTag = serviceRecord->Tag;
  638. if ((CurrentGroup != NULL) &&
  639. (_wcsicmp(lpLoadOrderGroup, CurrentGroup) == 0)) {
  640. //
  641. // The new load order group is the same as what is currently
  642. // in the registry. This means that no group change is occuring.
  643. //
  644. if (lpdwTagId != NULL) {
  645. //
  646. // The caller requested a tag. If there isn't one, generate
  647. // one and write it to the registry.
  648. //
  649. Tag = CurrentTag;
  650. if (CurrentTag == 0) {
  651. ScGetUniqueTag(
  652. lpLoadOrderGroup,
  653. &Tag
  654. );
  655. ApiStatus = ScWriteTag(ServiceNameKey, Tag);
  656. if (ApiStatus != NO_ERROR) {
  657. goto Cleanup;
  658. }
  659. //
  660. // Update the service record with the tag id.
  661. //
  662. serviceRecord->Tag = Tag;
  663. Progress |= TAG_ID_CHANGED;
  664. }
  665. }
  666. }
  667. else {
  668. //
  669. // The new load order group is different from what is currently
  670. // stored in the registry. Save the new one in the registry.
  671. //
  672. ApiStatus = ScWriteGroupForThisService(
  673. ServiceNameKey,
  674. lpLoadOrderGroup);
  675. if (ApiStatus != NO_ERROR) {
  676. goto Cleanup;
  677. }
  678. //
  679. // Also save it in the service controller database.
  680. //
  681. Progress |= REG_GROUP_CHANGED;
  682. ScDeleteRegistryGroupPointer( serviceRecord);
  683. ApiStatus = ScCreateRegistryGroupPointer(
  684. serviceRecord,
  685. lpLoadOrderGroup);
  686. if (ApiStatus != NO_ERROR) {
  687. goto Cleanup;
  688. }
  689. Progress |= SR_GROUP_CHANGED;
  690. //
  691. // Check to see if the LoadOrderGroup is being cleared
  692. // (0 length string) or set to a new string. If there
  693. // is a new string, we need to get a new unique Tag for it.
  694. //
  695. if (*lpLoadOrderGroup != 0) {
  696. //
  697. // We have a new LoadOrderGroup information. Get a unique
  698. // Tag value.
  699. //
  700. if (lpdwTagId != NULL) {
  701. ScGetUniqueTag(
  702. lpLoadOrderGroup,
  703. &Tag
  704. );
  705. }
  706. }
  707. //
  708. // Write tag entry to registry if not 0. If 0, we delete the tag
  709. // value from the registry.
  710. //
  711. if (Tag == 0) {
  712. ScDeleteTag(ServiceNameKey);
  713. }
  714. else {
  715. ApiStatus = ScWriteTag(ServiceNameKey, Tag);
  716. }
  717. if (ApiStatus != NO_ERROR) {
  718. goto Cleanup;
  719. }
  720. //
  721. // Update the service record with the tag id.
  722. //
  723. serviceRecord->Tag = Tag;
  724. Progress |= TAG_ID_CHANGED;
  725. }
  726. }
  727. //---------------------
  728. // ServiceStartName
  729. //---------------------
  730. //
  731. // If the service type is a DRIVER then we must interpret the
  732. // lpServiceStartName as an NT driver object name and add it to
  733. // the registry. If the type is WIN32, then lpServiceStartName
  734. // must be an account name. This will be handled by
  735. // ScUpdateServiceRecordConfig.
  736. //
  737. if ((newServiceType & SERVICE_DRIVER) &&
  738. (ARGUMENT_PRESENT(lpServiceStartName))) {
  739. //
  740. // Read StartName to save in case of error.
  741. //
  742. ApiStatus = ScReadStartName( ServiceNameKey, &CurrentStartName);
  743. if (ApiStatus != NO_ERROR) {
  744. goto Cleanup;
  745. }
  746. //
  747. // Write the driver objectname to the registry.
  748. //
  749. ApiStatus = ScWriteStartName(
  750. ServiceNameKey,
  751. lpServiceStartName
  752. );
  753. if (ApiStatus != NO_ERROR) {
  754. goto Cleanup;
  755. }
  756. Progress |= START_NAME_CHANGED;
  757. }
  758. //==============================
  759. // UPDATE Account Information
  760. //==============================
  761. if ((newServiceType & SERVICE_WIN32) &&
  762. (ARGUMENT_PRESENT(lpServiceStartName) ||
  763. ARGUMENT_PRESENT(EncryptedPassword))) {
  764. //
  765. // Changing the account.
  766. //
  767. //
  768. // Get old account name.
  769. // It may have already been retreived when we were handling
  770. // ServiceType (above).
  771. //
  772. if (OldAccountName == NULL) {
  773. ApiStatus = ScReadStartName(ServiceNameKey, &OldAccountName);
  774. if (ApiStatus != NO_ERROR) {
  775. goto Cleanup;
  776. }
  777. }
  778. if (! ARGUMENT_PRESENT(lpServiceStartName)) {
  779. //
  780. // Account name is specified as the one saved in the registry
  781. //
  782. CanonAccountName = OldAccountName;
  783. }
  784. else {
  785. //
  786. // NOTE: We may have already obtained a CanonAccountName when we
  787. // checked the INTERACTIVE service type.
  788. //
  789. if (CanonAccountName == NULL) {
  790. ApiStatus = ScCanonAccountName(lpServiceStartName, &CanonAccountName);
  791. if (ApiStatus != NO_ERROR) {
  792. goto Cleanup;
  793. }
  794. }
  795. }
  796. //
  797. // Decrypt the password. This function returns a pointer to
  798. // the decrypted password that must be freed later.
  799. //
  800. if (ARGUMENT_PRESENT(EncryptedPassword)) {
  801. ApiStatus = ScDecryptPassword(
  802. hService,
  803. EncryptedPassword,
  804. PasswordSize,
  805. &Password
  806. );
  807. if (ApiStatus != NO_ERROR) {
  808. SC_LOG0(ERROR, "RChangeServiceConfigW: ScDecryptPassword failed\n");
  809. goto Cleanup;
  810. }
  811. }
  812. //
  813. // NOTE: The following needs to be the last operation in the
  814. // function. This is because there is no way to back out of this
  815. // if something after it fails.
  816. //
  817. //
  818. // Validate and update internal data structures for the new
  819. // account, as well as write the new AccountName back to the
  820. // registry if appropriate.
  821. //
  822. ApiStatus = ScValidateAndChangeAccount(
  823. serviceRecord,
  824. ServiceNameKey,
  825. OldAccountName,
  826. CanonAccountName,
  827. Password
  828. );
  829. if (ApiStatus != NO_ERROR) {
  830. SC_LOG(ERROR, "ScValidateAndChangeAccount error %lu\n", ApiStatus);
  831. goto Cleanup;
  832. }
  833. }
  834. //
  835. // Update the service record with the new configuration if the
  836. // service is stopped. If it is running, then set a flag to
  837. // remind us to do it later. We don't update the dependencies
  838. // here since it is done dynamically in RChangeServiceConfigW
  839. //
  840. if (serviceRecord->ServiceStatus.dwCurrentState == SERVICE_STOPPED) {
  841. //
  842. // Dependencies are NULL since they're updated dynamically
  843. //
  844. ApiStatus = ScUpdateServiceRecordConfig(
  845. serviceRecord,
  846. dwServiceType,
  847. dwStartType,
  848. dwErrorControl,
  849. lpLoadOrderGroup,
  850. NULL);
  851. if (ApiStatus != NO_ERROR) {
  852. goto Cleanup;
  853. }
  854. }
  855. else {
  856. //
  857. // The service is running. Mark is so that we update the status
  858. // when it stops.
  859. //
  860. SET_UPDATE_FLAG(serviceRecord);
  861. }
  862. Cleanup:
  863. if (ApiStatus == NO_ERROR)
  864. {
  865. if (lpdwTagId != NULL)
  866. {
  867. *lpdwTagId = Tag;
  868. }
  869. if (Progress & DISPLAY_NAME_CHANGED_SR)
  870. {
  871. if (OldSRDisplayName != serviceRecord->ServiceName)
  872. {
  873. LocalFree(OldSRDisplayName);
  874. }
  875. }
  876. }
  877. else
  878. {
  879. //
  880. // An error occured. Backout any changes that may have occured.
  881. //
  882. if (Progress & SERVICE_TYPE_CHANGED) {
  883. backoutStatus = ScWriteServiceType( ServiceNameKey, CurrentServiceType);
  884. if (backoutStatus != NO_ERROR)
  885. {
  886. ScLogControlEvent(NEVENT_SERVICE_CONFIG_BACKOUT_FAILED,
  887. OldSRDisplayName ? OldSRDisplayName :
  888. serviceRecord->DisplayName,
  889. IDS_SC_CONFIG_SERVICE_TYPE);
  890. }
  891. }
  892. if (Progress & START_TYPE_CHANGED) {
  893. backoutStatus = ScWriteStartType( ServiceNameKey, CurrentStartType);
  894. if (backoutStatus != NO_ERROR)
  895. {
  896. ScLogControlEvent(NEVENT_SERVICE_CONFIG_BACKOUT_FAILED,
  897. OldSRDisplayName ? OldSRDisplayName :
  898. serviceRecord->DisplayName,
  899. IDS_SC_CONFIG_START_TYPE);
  900. }
  901. }
  902. if (Progress & ERROR_CONTROL_CHANGED) {
  903. backoutStatus = ScWriteErrorControl( ServiceNameKey, CurrentErrorControl);
  904. if (backoutStatus != NO_ERROR)
  905. {
  906. ScLogControlEvent(NEVENT_SERVICE_CONFIG_BACKOUT_FAILED,
  907. OldSRDisplayName ? OldSRDisplayName :
  908. serviceRecord->DisplayName,
  909. IDS_SC_CONFIG_ERROR_CONTROL);
  910. }
  911. }
  912. if (Progress & DISPLAY_NAME_CHANGED_REG) {
  913. if (CurrentDisplayName == NULL) {
  914. backoutStatus = ScWriteDisplayName(
  915. ServiceNameKey,
  916. L"");
  917. }
  918. else {
  919. backoutStatus = ScWriteDisplayName(
  920. ServiceNameKey,
  921. CurrentDisplayName);
  922. }
  923. if (backoutStatus != NO_ERROR)
  924. {
  925. ScLogControlEvent(NEVENT_SERVICE_CONFIG_BACKOUT_FAILED,
  926. OldSRDisplayName ? OldSRDisplayName :
  927. serviceRecord->DisplayName,
  928. IDS_SC_CONFIG_DISPLAY_NAME);
  929. }
  930. }
  931. if (Progress & DISPLAY_NAME_CHANGED_SR) {
  932. if (serviceRecord->DisplayName != serviceRecord->ServiceName) {
  933. LocalFree(serviceRecord->DisplayName);
  934. serviceRecord->DisplayName = OldSRDisplayName;
  935. }
  936. }
  937. if (Progress & BINARY_PATH_CHANGED) {
  938. if (CurrentImageName == NULL) {
  939. ScRegDeleteValue(ServiceNameKey, IMAGE_VALUENAME_W);
  940. }
  941. else {
  942. backoutStatus = ScWriteImageFileName( ServiceNameKey, CurrentImageName);
  943. if (backoutStatus != NO_ERROR)
  944. {
  945. ScLogControlEvent(NEVENT_SERVICE_CONFIG_BACKOUT_FAILED,
  946. OldSRDisplayName ? OldSRDisplayName :
  947. serviceRecord->DisplayName,
  948. IDS_SC_CONFIG_BINARY_PATH);
  949. }
  950. }
  951. }
  952. if (Progress & DEPENDENCIES_CHANGED_REG) {
  953. //
  954. // ScWriteDependencies doesn't like NULL dependencies
  955. //
  956. LPWSTR lpTempDepend;
  957. lpTempDepend = (CurrentDependencies ? CurrentDependencies : L"\0");
  958. backoutStatus = ScWriteDependencies(
  959. ServiceNameKey,
  960. lpTempDepend,
  961. ScWStrArraySize(lpTempDepend));
  962. if (backoutStatus != NO_ERROR)
  963. {
  964. ScLogControlEvent(NEVENT_SERVICE_CONFIG_BACKOUT_FAILED,
  965. OldSRDisplayName ? OldSRDisplayName :
  966. serviceRecord->DisplayName,
  967. IDS_SC_CONFIG_DEPENDENCIES);
  968. }
  969. }
  970. if (Progress & DEPENDENCIES_CHANGED_SR) {
  971. backoutStatus = ScUpdateServiceRecordConfig(
  972. serviceRecord,
  973. SERVICE_NO_CHANGE,
  974. SERVICE_NO_CHANGE,
  975. SERVICE_NO_CHANGE,
  976. NULL,
  977. (LPBYTE)CurrentDependencies);
  978. if (backoutStatus != NO_ERROR)
  979. {
  980. ScLogControlEvent(NEVENT_SERVICE_CONFIG_BACKOUT_FAILED,
  981. OldSRDisplayName ? OldSRDisplayName :
  982. serviceRecord->DisplayName,
  983. IDS_SC_CONFIG_DEPENDENCIES);
  984. }
  985. }
  986. if (Progress & REG_GROUP_CHANGED) {
  987. if (CurrentGroup != NULL) {
  988. backoutStatus = ScWriteGroupForThisService(
  989. ServiceNameKey, CurrentGroup);
  990. if (backoutStatus != NO_ERROR)
  991. {
  992. ScLogControlEvent(NEVENT_SERVICE_CONFIG_BACKOUT_FAILED,
  993. OldSRDisplayName ? OldSRDisplayName :
  994. serviceRecord->DisplayName,
  995. IDS_SC_CONFIG_GROUP);
  996. }
  997. }
  998. else {
  999. ScRegDeleteValue(ServiceNameKey, GROUP_VALUENAME_W);
  1000. }
  1001. }
  1002. if (Progress & SR_GROUP_CHANGED) {
  1003. ScDeleteRegistryGroupPointer( serviceRecord);
  1004. backoutStatus = ScCreateRegistryGroupPointer( serviceRecord, CurrentGroup);
  1005. if (backoutStatus != NO_ERROR)
  1006. {
  1007. ScLogControlEvent(NEVENT_SERVICE_CONFIG_BACKOUT_FAILED,
  1008. OldSRDisplayName ? OldSRDisplayName :
  1009. serviceRecord->DisplayName,
  1010. IDS_SC_CONFIG_GROUP);
  1011. }
  1012. }
  1013. if (Progress & TAG_ID_CHANGED)
  1014. {
  1015. if (CurrentTag == 0)
  1016. {
  1017. ScDeleteTag(ServiceNameKey);
  1018. }
  1019. else
  1020. {
  1021. backoutStatus = ScWriteTag( ServiceNameKey, CurrentTag);
  1022. if (backoutStatus != NO_ERROR)
  1023. {
  1024. ScLogControlEvent(NEVENT_SERVICE_CONFIG_BACKOUT_FAILED,
  1025. OldSRDisplayName ? OldSRDisplayName :
  1026. serviceRecord->DisplayName,
  1027. IDS_SC_CONFIG_TAG);
  1028. }
  1029. }
  1030. serviceRecord->Tag = CurrentTag;
  1031. }
  1032. if (Progress & START_NAME_CHANGED)
  1033. {
  1034. backoutStatus = ScWriteStartName( ServiceNameKey, CurrentStartName);
  1035. if (backoutStatus != NO_ERROR)
  1036. {
  1037. ScLogControlEvent(NEVENT_SERVICE_CONFIG_BACKOUT_FAILED,
  1038. OldSRDisplayName ? OldSRDisplayName :
  1039. serviceRecord->DisplayName,
  1040. IDS_SC_CONFIG_ACCOUNT);
  1041. }
  1042. }
  1043. }
  1044. if (CanonAccountName == OldAccountName) {
  1045. LocalFree(OldAccountName);
  1046. }
  1047. else {
  1048. LocalFree(OldAccountName);
  1049. LocalFree(CanonAccountName);
  1050. }
  1051. //
  1052. // Free memory resources
  1053. //
  1054. LocalFree(CurrentDisplayName);
  1055. LocalFree(CurrentImageName);
  1056. LocalFree(CurrentDependencies);
  1057. LocalFree(CurrentGroup);
  1058. LocalFree(CurrentStartName);
  1059. LocalFree(CanonBinaryPath);
  1060. LocalFree(NewBinaryPath);
  1061. LocalFree(Password);
  1062. if (ServiceNameKey != NULL) {
  1063. (VOID) ScRegFlushKey(ServiceNameKey);
  1064. (VOID) ScRegCloseKey( ServiceNameKey );
  1065. }
  1066. SC_LOG1( CONFIG_API, "RChangeServiceConfigW returning status " FORMAT_DWORD
  1067. ".\n", ApiStatus );
  1068. return (ApiStatus);
  1069. }
  1070. DWORD
  1071. RCreateServiceW(
  1072. IN SC_RPC_HANDLE hSCManager,
  1073. IN LPWSTR lpServiceName,
  1074. IN LPWSTR lpDisplayName,
  1075. IN DWORD dwDesiredAccess,
  1076. IN DWORD dwServiceType,
  1077. IN DWORD dwStartType,
  1078. IN DWORD dwErrorControl,
  1079. IN LPWSTR lpBinaryPathName,
  1080. IN LPWSTR lpLoadOrderGroup,
  1081. OUT LPDWORD lpdwTagId OPTIONAL,
  1082. IN LPBYTE lpDependencies OPTIONAL,
  1083. IN DWORD dwDependSize,
  1084. IN LPWSTR lpServiceStartName OPTIONAL,
  1085. IN LPBYTE EncryptedPassword OPTIONAL,
  1086. IN DWORD PasswordSize,
  1087. IN OUT LPSC_RPC_HANDLE lpServiceHandle
  1088. )
  1089. /*++
  1090. Routine Description:
  1091. Arguments:
  1092. Return Value:
  1093. --*/
  1094. {
  1095. DWORD ApiStatus;
  1096. LPSERVICE_RECORD newServiceRecord = NULL;
  1097. LPSERVICE_RECORD oldServiceRecord;
  1098. LPSC_HANDLE_STRUCT serviceHandleStruct = NULL;
  1099. HKEY serviceKey = NULL;
  1100. CHeapPtr<LPWSTR> Password;
  1101. CHeapPtr<LPWSTR> CanonAccountName;
  1102. CHeapPtr<LPWSTR> CanonBinaryPath;
  1103. DWORD Tag = 0;
  1104. SC_LOG1( CONFIG_API, "In RCreateServiceW - creating %ws\n",lpServiceName);
  1105. if (ScShutdownInProgress) {
  1106. return(ERROR_SHUTDOWN_IN_PROGRESS);
  1107. }
  1108. if ( !ScIsValidScManagerHandle( hSCManager ) ) {
  1109. ApiStatus = ERROR_INVALID_HANDLE;
  1110. return(ApiStatus);
  1111. }
  1112. if ( !RtlAreAllAccessesGranted(
  1113. ((LPSC_HANDLE_STRUCT)hSCManager)->AccessGranted,
  1114. SC_MANAGER_CREATE_SERVICE
  1115. )) {
  1116. ApiStatus = ERROR_ACCESS_DENIED;
  1117. return(ApiStatus);
  1118. }
  1119. if ( !ScIsValidServiceName( lpServiceName ) ) {
  1120. ApiStatus = ERROR_INVALID_NAME;
  1121. return(ApiStatus);
  1122. }
  1123. //
  1124. // Validate other parameters.
  1125. //
  1126. ApiStatus = ScCheckServiceConfigParms(
  1127. FALSE, // no, this is not a change operation
  1128. lpServiceName,
  1129. dwServiceType, // new actual type = same one app gave us.
  1130. dwServiceType,
  1131. dwStartType,
  1132. dwErrorControl,
  1133. lpBinaryPathName,
  1134. lpLoadOrderGroup,
  1135. (LPWSTR)lpDependencies,
  1136. dwDependSize);
  1137. if (ApiStatus != NO_ERROR) {
  1138. return(ApiStatus);
  1139. }
  1140. if (lpdwTagId != NULL) {
  1141. //
  1142. // Asking for tag value but didn't specify group
  1143. //
  1144. if ((lpLoadOrderGroup == NULL) ||
  1145. ((lpLoadOrderGroup != NULL) && (*lpLoadOrderGroup == 0))){
  1146. SC_LOG0(ERROR, "Asking for tag value but didn't specify group\n");
  1147. ApiStatus = ERROR_INVALID_PARAMETER;
  1148. return(ApiStatus);
  1149. }
  1150. }
  1151. if (dwServiceType & SERVICE_WIN32) {
  1152. //
  1153. // Canonicalize the StartName if it is an account name.
  1154. //
  1155. LPWSTR AccountName = SC_LOCAL_SYSTEM_USER_NAME; // Default
  1156. if (ARGUMENT_PRESENT(lpServiceStartName)) {
  1157. AccountName = lpServiceStartName;
  1158. }
  1159. ApiStatus = ScCanonAccountName(
  1160. AccountName,
  1161. &CanonAccountName
  1162. );
  1163. if (ApiStatus != NO_ERROR) {
  1164. return(ApiStatus);
  1165. }
  1166. //
  1167. // The services that are expected to be interactive MUST
  1168. // run in the LocalSystem account only.
  1169. //
  1170. if ((dwServiceType & SERVICE_INTERACTIVE_PROCESS) &&
  1171. (_wcsicmp(CanonAccountName,SC_LOCAL_SYSTEM_USER_NAME) != 0)) {
  1172. SC_LOG0(ERROR, "Service must run in LocalSystem account to be interactive\n");
  1173. ApiStatus = ERROR_INVALID_PARAMETER;
  1174. return(ApiStatus);
  1175. }
  1176. }
  1177. else if (dwServiceType & SERVICE_DRIVER) {
  1178. //
  1179. // Canonicalize the path name for drivers
  1180. //
  1181. ApiStatus = ScCanonDriverImagePath(
  1182. dwStartType,
  1183. lpBinaryPathName,
  1184. &CanonBinaryPath
  1185. );
  1186. if (ApiStatus != NO_ERROR) {
  1187. SC_LOG(ERROR, "ScCanonDriverImagePath error %lu\n", ApiStatus);
  1188. return(ApiStatus);
  1189. }
  1190. }
  1191. if (lpServiceHandle == NULL) {
  1192. SC_LOG0(ERROR, "Null lpServiceHandle\n");
  1193. ApiStatus = ERROR_INVALID_PARAMETER;
  1194. return(ApiStatus);
  1195. }
  1196. //
  1197. // Lock database, as we want to add stuff without other threads tripping
  1198. // on our feet. NOTE: since we may need the group list lock, we must
  1199. // get that lock first.
  1200. //
  1201. CGroupListExclusiveLock GLock;
  1202. CServiceListExclusiveLock LLock;
  1203. CServiceRecordExclusiveLock RLock;
  1204. //
  1205. // Look for unique tag
  1206. //
  1207. if (lpdwTagId != NULL) {
  1208. ScGetUniqueTag(
  1209. lpLoadOrderGroup,
  1210. &Tag
  1211. );
  1212. }
  1213. //
  1214. // Look for an existing service.
  1215. //
  1216. SC_LOG0( CONFIG_API, "RCreateServiceW: See if Service already exists\n");
  1217. ApiStatus = ScGetNamedServiceRecord (
  1218. lpServiceName,
  1219. & oldServiceRecord );
  1220. if (ApiStatus == NO_ERROR) {
  1221. if (DELETE_FLAG_IS_SET(oldServiceRecord)) {
  1222. ApiStatus = ERROR_SERVICE_MARKED_FOR_DELETE;
  1223. }
  1224. else {
  1225. ApiStatus = ERROR_SERVICE_EXISTS;
  1226. }
  1227. goto Cleanup;
  1228. } else if (ApiStatus != ERROR_SERVICE_DOES_NOT_EXIST) {
  1229. goto Cleanup;
  1230. }
  1231. //
  1232. // If there is a DisplayName specified, check to see if it already
  1233. // exists.
  1234. //
  1235. ApiStatus = ScValidateDisplayName(lpDisplayName,NULL);
  1236. if (ApiStatus != NO_ERROR) {
  1237. goto Cleanup;
  1238. }
  1239. //
  1240. // Allocate new service record. Put the service name in the record too.
  1241. //
  1242. SC_LOG0( CONFIG_API, "RCreateServiceW: Create a new service record\n");
  1243. ApiStatus = ScCreateServiceRecord(
  1244. lpServiceName,
  1245. & newServiceRecord );
  1246. if (ApiStatus != NO_ERROR) {
  1247. goto Cleanup;
  1248. }
  1249. SC_LOG0( CONFIG_API, "RCreateServiceW: Add Config Info to Service Record\n");
  1250. ApiStatus = ScAddConfigInfoServiceRecord(
  1251. newServiceRecord,
  1252. dwServiceType,
  1253. dwStartType,
  1254. dwErrorControl,
  1255. lpLoadOrderGroup,
  1256. Tag,
  1257. (LPWSTR) lpDependencies,
  1258. lpDisplayName,
  1259. NULL // Create new security descriptor
  1260. );
  1261. if (ApiStatus != NO_ERROR) {
  1262. SC_LOG(ERROR, "ScAddConfigInfoServiceRecord error %lu\n", ApiStatus);
  1263. goto Cleanup;
  1264. }
  1265. SC_LOG0( CONFIG_API, "RCreateServiceW: Set dependency pointers\n");
  1266. ApiStatus = ScSetDependencyPointers(
  1267. newServiceRecord
  1268. );
  1269. if (ApiStatus != NO_ERROR) {
  1270. goto Cleanup;
  1271. }
  1272. //--------------------------------------------
  1273. // Create a key in registry for this service.
  1274. //--------------------------------------------
  1275. SC_LOG0( CONFIG_API, "RCreateServiceW: Open Registry Key for service\n");
  1276. ApiStatus = ScOpenServiceConfigKey(
  1277. lpServiceName,
  1278. KEY_READ | KEY_WRITE, // desired access
  1279. TRUE, // create if it doesn't exist
  1280. & serviceKey );
  1281. if (ApiStatus != NO_ERROR) {
  1282. SC_LOG1( CONFIG_API, "RCreateServiceW: ScOpenServiceConfigKey failed %d\n",
  1283. ApiStatus);
  1284. goto Cleanup;
  1285. }
  1286. //
  1287. // Write stuff to the registry (except user name and password).
  1288. //
  1289. SC_LOG0( CONFIG_API, "RCreateServiceW: Write RegistryInfo\n");
  1290. ApiStatus = ScWriteServiceType( serviceKey, dwServiceType );
  1291. if (ApiStatus != NO_ERROR) {
  1292. goto Cleanup;
  1293. }
  1294. ApiStatus = ScWriteStartType( serviceKey, dwStartType );
  1295. if (ApiStatus != NO_ERROR) {
  1296. goto Cleanup;
  1297. }
  1298. ApiStatus = ScWriteErrorControl( serviceKey, dwErrorControl );
  1299. if (ApiStatus != NO_ERROR) {
  1300. goto Cleanup;
  1301. }
  1302. if (lpdwTagId != NULL) {
  1303. ApiStatus = ScWriteTag( serviceKey, Tag );
  1304. if (ApiStatus != NO_ERROR) {
  1305. goto Cleanup;
  1306. }
  1307. }
  1308. if (dwServiceType & SERVICE_WIN32) {
  1309. ApiStatus = ScWriteImageFileName( serviceKey, lpBinaryPathName );
  1310. }
  1311. else if (dwServiceType & SERVICE_DRIVER) {
  1312. ApiStatus = ScWriteImageFileName( serviceKey, CanonBinaryPath );
  1313. }
  1314. if (ApiStatus != NO_ERROR) {
  1315. goto Cleanup;
  1316. }
  1317. ScWriteDisplayName(serviceKey, lpDisplayName);
  1318. if ( (lpLoadOrderGroup != NULL) && ( (*lpLoadOrderGroup) != L'\0' ) ) {
  1319. ApiStatus = ScWriteGroupForThisService( serviceKey, lpLoadOrderGroup );
  1320. if (ApiStatus != NO_ERROR) {
  1321. goto Cleanup;
  1322. }
  1323. }
  1324. if ( (lpDependencies != NULL) && ( (*lpDependencies) != L'\0' ) ) {
  1325. ApiStatus = ScWriteDependencies(
  1326. serviceKey,
  1327. (LPWSTR) lpDependencies,
  1328. dwDependSize );
  1329. if (ApiStatus != NO_ERROR) {
  1330. goto Cleanup;
  1331. }
  1332. }
  1333. if (newServiceRecord != NULL && newServiceRecord->ServiceSd != NULL) {
  1334. ApiStatus = ScWriteSd(
  1335. serviceKey,
  1336. newServiceRecord->ServiceSd
  1337. );
  1338. if (ApiStatus != NO_ERROR) {
  1339. goto Cleanup;
  1340. }
  1341. }
  1342. //
  1343. // Create a handle which caller can use.
  1344. //
  1345. SC_LOG0( CONFIG_API, "RCreateServiceW: Create Service Handle\n");
  1346. ApiStatus = ScCreateServiceHandle( newServiceRecord,
  1347. & serviceHandleStruct );
  1348. if (ApiStatus != NO_ERROR) {
  1349. goto Cleanup;
  1350. }
  1351. //
  1352. // Give the handle the access that the caller requested.
  1353. //
  1354. ApiStatus = ScGrantAccess(
  1355. serviceHandleStruct,
  1356. dwDesiredAccess);
  1357. if (ApiStatus != NO_ERROR) {
  1358. goto Cleanup;
  1359. }
  1360. //
  1361. // Resolve outstanding dependency to this service.
  1362. //
  1363. SC_LOG0( CONFIG_API, "RCreateServiceW: Resolve Dependencies\n");
  1364. ApiStatus = ScResolveDependencyToService(newServiceRecord);
  1365. if (ApiStatus != NO_ERROR) {
  1366. goto Cleanup;
  1367. }
  1368. //
  1369. // Decrypt the password. This function returns a pointer to
  1370. // the decrypted password that must be freed later.
  1371. //
  1372. if (ARGUMENT_PRESENT(EncryptedPassword)) {
  1373. ApiStatus = ScDecryptPassword(
  1374. hSCManager,
  1375. EncryptedPassword,
  1376. PasswordSize,
  1377. &Password
  1378. );
  1379. if (ApiStatus != NO_ERROR) {
  1380. SC_LOG0(ERROR, "RCreateServiceW: ScDecryptPassword failed\n");
  1381. goto Cleanup;
  1382. }
  1383. }
  1384. //
  1385. // The LAST thing we must do (which might fail) is call
  1386. // ScValidateAndSaveAccount(). This must be last because there is no
  1387. // way to undo this routine's actions.
  1388. //
  1389. if (dwServiceType & SERVICE_WIN32) {
  1390. SC_LOG0( CONFIG_API, "RCreateServiceW: Validate and save account\n");
  1391. ApiStatus = ScValidateAndSaveAccount(
  1392. lpServiceName,
  1393. serviceKey,
  1394. CanonAccountName,
  1395. Password
  1396. );
  1397. if (ApiStatus != NO_ERROR) {
  1398. SC_LOG(ERROR, "ScValidateAndSaveAccount error %lu\n", ApiStatus);
  1399. goto Cleanup;
  1400. }
  1401. }
  1402. else if ((dwServiceType & SERVICE_DRIVER) &&
  1403. (ARGUMENT_PRESENT(lpServiceStartName))) {
  1404. SC_LOG0( CONFIG_API, "RCreateServiceW: Write Driver ObjectName to "
  1405. "registry\n");
  1406. //
  1407. // Write the driver objectname to the registry.
  1408. //
  1409. ApiStatus = ScWriteStartName(
  1410. serviceKey,
  1411. lpServiceStartName
  1412. );
  1413. if (ApiStatus != NO_ERROR) {
  1414. goto Cleanup;
  1415. }
  1416. }
  1417. SC_LOG0( CONFIG_API, "RCreateServiceW: Done - No Errors\n");
  1418. ApiStatus = NO_ERROR;
  1419. Cleanup:
  1420. if (serviceKey != NULL) {
  1421. (VOID) ScRegFlushKey( serviceKey);
  1422. (VOID) ScRegCloseKey( serviceKey );
  1423. }
  1424. if (ApiStatus == NO_ERROR) {
  1425. newServiceRecord->UseCount = 1;
  1426. *lpServiceHandle = (SC_RPC_HANDLE) serviceHandleStruct;
  1427. SC_LOG2(USECOUNT, "CreateService: " FORMAT_LPWSTR
  1428. " increment USECOUNT=%lu\n", newServiceRecord->ServiceName, newServiceRecord->UseCount);
  1429. if (lpdwTagId != NULL) {
  1430. *lpdwTagId = Tag;
  1431. }
  1432. }
  1433. else {
  1434. if (newServiceRecord != NULL) {
  1435. //
  1436. // Delete partially created service record.
  1437. //
  1438. SET_DELETE_FLAG(newServiceRecord);
  1439. newServiceRecord->UseCount = 1;
  1440. SC_LOG2(USECOUNT, "CreateService: " FORMAT_LPWSTR
  1441. " increment USECOUNT=%lu\n", newServiceRecord->ServiceName, newServiceRecord->UseCount);
  1442. //
  1443. // ScDecrementUseCountAndDelete deletes the service record
  1444. // and the registry entry for that service.
  1445. //
  1446. ScDecrementUseCountAndDelete(newServiceRecord);
  1447. newServiceRecord = NULL;
  1448. }
  1449. LocalFree(serviceHandleStruct);
  1450. if (lpServiceHandle != NULL) {
  1451. *lpServiceHandle = NULL;
  1452. }
  1453. }
  1454. SC_LOG2( CONFIG_API, "RCreateServiceW returning status " FORMAT_DWORD
  1455. " and handle " FORMAT_LPVOID ".\n", ApiStatus,
  1456. (LPVOID) serviceHandleStruct );
  1457. return(ApiStatus);
  1458. }
  1459. DWORD
  1460. RDeleteService(
  1461. IN SC_RPC_HANDLE hService
  1462. )
  1463. /*++
  1464. Routine Description:
  1465. Arguments:
  1466. Return Value:
  1467. --*/
  1468. {
  1469. NTSTATUS status;
  1470. UNICODE_STRING Subsystem;
  1471. ULONG privileges[1];
  1472. DWORD ApiStatus;
  1473. LPSC_HANDLE_STRUCT serviceHandleStruct = (LPSC_HANDLE_STRUCT) hService;
  1474. LPSERVICE_RECORD serviceRecord;
  1475. if (ScShutdownInProgress) {
  1476. return(ERROR_SHUTDOWN_IN_PROGRESS);
  1477. }
  1478. //
  1479. // Check the handle.
  1480. //
  1481. if ( !ScIsValidServiceHandle( hService ) ) {
  1482. return(ERROR_INVALID_HANDLE);
  1483. }
  1484. //
  1485. // Do we have permission to do this?
  1486. //
  1487. if ( !RtlAreAllAccessesGranted(
  1488. serviceHandleStruct->AccessGranted,
  1489. DELETE
  1490. )) {
  1491. return(ERROR_ACCESS_DENIED);
  1492. }
  1493. //
  1494. // Lock database, as we want to change stuff without other threads tripping
  1495. // on our feet.
  1496. //
  1497. CServiceRecordExclusiveLock RLock;
  1498. //
  1499. // Find the service record
  1500. //
  1501. serviceRecord = serviceHandleStruct->Type.ScServiceObject.ServiceRecord;
  1502. SC_ASSERT( serviceRecord != NULL );
  1503. SC_ASSERT( serviceRecord->Signature == SERVICE_SIGNATURE );
  1504. //
  1505. // Check if marked for deletion (by another call to this API).
  1506. //
  1507. if (DELETE_FLAG_IS_SET(serviceRecord)) {
  1508. ApiStatus = ERROR_SERVICE_MARKED_FOR_DELETE;
  1509. goto Cleanup;
  1510. }
  1511. //
  1512. // Mark the service for deletion.
  1513. // It will actually be deleted when the last handle to it is closed.
  1514. // NOTE: Since the service itself owns a handle, the deletion is
  1515. // not complete until the service has stopped.
  1516. //
  1517. SET_DELETE_FLAG(serviceRecord);
  1518. //
  1519. // Set the start type to disabled. If we're deleting a driver that's
  1520. // started by the system, we don't want the system to start it on the
  1521. // next boot since we're going to remove the key from the registry
  1522. //
  1523. serviceRecord->StartType = SERVICE_DISABLED;
  1524. //
  1525. // Mark the registry entry for this service for deletion. If we notice
  1526. // this as being present when we go throught our initialization routine
  1527. // (during boot), the service entry in the registry will be deleted.
  1528. //
  1529. ScMarkForDelete(serviceRecord);
  1530. //
  1531. // Get Audit Privilege
  1532. //
  1533. privileges[0] = SE_AUDIT_PRIVILEGE;
  1534. status = ScGetPrivilege( 1, privileges);
  1535. if (!NT_SUCCESS(status)) {
  1536. SC_LOG1(ERROR, "RDeleteService: ScGetPrivilege (Enable) failed %#lx\n",
  1537. status);
  1538. }
  1539. //
  1540. // Generate the Audit.
  1541. //
  1542. RtlInitUnicodeString(&Subsystem, SC_MANAGER_AUDIT_NAME);
  1543. status = NtDeleteObjectAuditAlarm(
  1544. &Subsystem,
  1545. hService,
  1546. (BOOLEAN)((serviceHandleStruct->Flags
  1547. & SC_HANDLE_GENERATE_ON_CLOSE) != 0));
  1548. if (!NT_SUCCESS(status)) {
  1549. SC_LOG1(ERROR, "RDeleteService: NtDeleteObjectAuditAlarm failed %#lx\n",
  1550. status);
  1551. }
  1552. ScReleasePrivilege();
  1553. ApiStatus = NO_ERROR;
  1554. Cleanup:
  1555. SC_LOG2( CONFIG_API, "RDeleteService(%ws) returning status " FORMAT_DWORD
  1556. ".\n", serviceRecord->ServiceName, ApiStatus );
  1557. return (ApiStatus);
  1558. }
  1559. DWORD
  1560. RQueryServiceConfigW(
  1561. IN SC_RPC_HANDLE hService,
  1562. OUT LPQUERY_SERVICE_CONFIGW lpServiceConfig,
  1563. IN DWORD cbBufSize,
  1564. OUT LPDWORD pcbBytesNeeded
  1565. )
  1566. /*++
  1567. Routine Description:
  1568. This function returns the service configuration information that
  1569. is currently stored in the registry.
  1570. NOTE:
  1571. When a service is running and its configuration is changed, the
  1572. change only affects the registry information as long as the service
  1573. is running. During this period (while the service is running), it is
  1574. not possible to obtain the configuration of the running service.
  1575. All that can be obtained is the configuration stored in the registry.
  1576. This is the configuration that the service will have the next time
  1577. it is run. Stopping a service causes it to get its configuration
  1578. information refreshed from the registry.
  1579. Arguments:
  1580. Return Value:
  1581. --*/
  1582. {
  1583. DWORD ApiStatus;
  1584. DWORD bytesNeeded = sizeof(QUERY_SERVICE_CONFIG); // (initial)
  1585. LPWSTR endOfVariableData;
  1586. LPWSTR fixedDataEnd;
  1587. LPSC_HANDLE_STRUCT serviceHandleStruct = (LPSC_HANDLE_STRUCT) hService;
  1588. LPSERVICE_RECORD serviceRecord = NULL;
  1589. HKEY ServiceNameKey = (HKEY) NULL;
  1590. DWORD bufSize;
  1591. DWORD dependSize=0;
  1592. LPWSTR CurrentImagePathName = NULL;
  1593. LPWSTR CurrentDependencies = NULL;
  1594. LPWSTR CurrentGroup = NULL;
  1595. LPWSTR CurrentStartName = NULL;
  1596. LPWSTR pDependString;
  1597. LPWSTR CurrentDisplayName = NULL;
  1598. LPWSTR ConvertImageName;
  1599. if (ScShutdownInProgress) {
  1600. return(ERROR_SHUTDOWN_IN_PROGRESS);
  1601. }
  1602. //
  1603. // Check the handle.
  1604. //
  1605. if ( !ScIsValidServiceHandle( hService ) ) {
  1606. return(ERROR_INVALID_HANDLE);
  1607. }
  1608. //
  1609. // Check other caller parms (except buffer too small, we need more info).
  1610. //
  1611. if (lpServiceConfig == NULL) {
  1612. return(ERROR_INVALID_PARAMETER);
  1613. } else if (pcbBytesNeeded == NULL) {
  1614. return(ERROR_INVALID_PARAMETER);
  1615. }
  1616. //
  1617. // Do we have permission to do this?
  1618. //
  1619. if ( !RtlAreAllAccessesGranted(
  1620. serviceHandleStruct->AccessGranted,
  1621. SERVICE_QUERY_CONFIG
  1622. )) {
  1623. return(ERROR_ACCESS_DENIED);
  1624. }
  1625. //
  1626. // Lock database, as we want to look at stuff without other threads changing
  1627. // fields at the same time.
  1628. //
  1629. CServiceRecordSharedLock RLock;
  1630. serviceRecord = serviceHandleStruct->Type.ScServiceObject.ServiceRecord;
  1631. SC_ASSERT( serviceRecord != NULL );
  1632. //
  1633. // Open the service name key.
  1634. //
  1635. ApiStatus = ScOpenServiceConfigKey(
  1636. serviceRecord->ServiceName,
  1637. KEY_READ,
  1638. FALSE, // Create if missing
  1639. &ServiceNameKey
  1640. );
  1641. if (ApiStatus != NO_ERROR) {
  1642. goto Cleanup;
  1643. }
  1644. //--------------------------------
  1645. // Get the BinaryPathName
  1646. //--------------------------------
  1647. SC_ASSERT( serviceRecord->ServiceName != NULL );
  1648. ApiStatus = ScGetImageFileName (
  1649. serviceRecord->ServiceName,
  1650. & CurrentImagePathName ); // alloc and set ptr.
  1651. if (ApiStatus != NO_ERROR) {
  1652. CurrentImagePathName = NULL;
  1653. }
  1654. ApiStatus = ScReadConfigFromReg(
  1655. serviceRecord,
  1656. &lpServiceConfig->dwServiceType,
  1657. &lpServiceConfig->dwStartType,
  1658. &lpServiceConfig->dwErrorControl,
  1659. &lpServiceConfig->dwTagId,
  1660. &CurrentDependencies,
  1661. &CurrentGroup,
  1662. &CurrentDisplayName);
  1663. if (ApiStatus != NO_ERROR) {
  1664. goto Cleanup;
  1665. }
  1666. //
  1667. // If the starttype is SERVICE_BOOT_START the name is a relative path
  1668. // from \SystemRoot. Fix it to be a fully qualified name, unless it is
  1669. // an ARC name, then leave it alone.
  1670. //
  1671. if (CurrentImagePathName &&
  1672. lpServiceConfig->dwStartType == SERVICE_BOOT_START &&
  1673. !ScIsArcName(CurrentImagePathName)) {
  1674. ConvertImageName = (LPWSTR) LocalAlloc(LMEM_ZEROINIT,
  1675. (UINT) ((wcslen(CurrentImagePathName) +
  1676. wcslen(SC_NT_SYSTEM_ROOT) + 1) * sizeof(WCHAR)));
  1677. if (ConvertImageName == NULL) {
  1678. SC_LOG1(ERROR, "RQueryServiceConfigW: LocalAlloc failed %lu\n",
  1679. GetLastError());
  1680. ApiStatus = ERROR_NOT_ENOUGH_MEMORY;
  1681. goto Cleanup;
  1682. }
  1683. wcscpy(ConvertImageName, SC_NT_SYSTEM_ROOT);
  1684. wcscat(ConvertImageName, CurrentImagePathName);
  1685. LocalFree(CurrentImagePathName);
  1686. CurrentImagePathName = ConvertImageName;
  1687. }
  1688. //--------------------------------
  1689. // Get StartName
  1690. //--------------------------------
  1691. ApiStatus = ScReadStartName( ServiceNameKey, &CurrentStartName);
  1692. if (ApiStatus != NO_ERROR) {
  1693. SC_LOG1(TRACE,"StartName for %ws service does not exist\n",
  1694. serviceRecord->ServiceName);
  1695. CurrentStartName = NULL;
  1696. }
  1697. //
  1698. // Figure-out how much space we'll need for the record.
  1699. // We've already got the initial (fixed) size in bytesNeeded...
  1700. //
  1701. SC_ASSERT( bytesNeeded == sizeof(QUERY_SERVICE_CONFIG) );
  1702. //
  1703. // Add on some extra for RPC byte count alignment.
  1704. // NOTE: We don't try and solve any exact alignment problem because
  1705. // RPC will choose a random order in which to load strings into
  1706. // the buffer.
  1707. //
  1708. bytesNeeded += sizeof(ULONG_PTR) - 1; // extra for RPC alignment
  1709. if (CurrentImagePathName != NULL)
  1710. {
  1711. bytesNeeded += (DWORD) WCSSIZE(CurrentImagePathName);
  1712. }
  1713. else {
  1714. bytesNeeded += sizeof(WCHAR);
  1715. }
  1716. bytesNeeded += sizeof(ULONG_PTR) - 1; // extra for RPC alignment
  1717. //
  1718. // If the display name is not stored in the registry, the
  1719. // Service Name is returned instead.
  1720. //
  1721. if (CurrentDisplayName == NULL) {
  1722. CurrentDisplayName = serviceRecord->ServiceName;
  1723. }
  1724. bytesNeeded += (DWORD) WCSSIZE(CurrentDisplayName);
  1725. //
  1726. // Add on some extra for RPC byte count alignment.
  1727. //
  1728. bytesNeeded += sizeof(ULONG_PTR) - 1; // extra for RPC alignment
  1729. if (CurrentGroup != NULL) {
  1730. bytesNeeded += (DWORD) WCSSIZE(CurrentGroup);
  1731. }
  1732. else {
  1733. bytesNeeded += sizeof(WCHAR);
  1734. }
  1735. bytesNeeded += sizeof(ULONG_PTR) - 1; // extra for RPC alignment
  1736. if (CurrentDependencies != NULL) {
  1737. dependSize = ScWStrArraySize(CurrentDependencies);
  1738. bytesNeeded += dependSize;
  1739. }
  1740. else {
  1741. bytesNeeded += (2 * sizeof(WCHAR));
  1742. }
  1743. bytesNeeded += sizeof(ULONG_PTR) - 1; // extra for RPC alignment
  1744. if (CurrentStartName != NULL) {
  1745. bytesNeeded += (DWORD) WCSSIZE(CurrentStartName);
  1746. }
  1747. else {
  1748. bytesNeeded += sizeof(WCHAR);
  1749. }
  1750. bytesNeeded = ROUND_UP_COUNT(bytesNeeded, ALIGN_WCHAR);
  1751. //
  1752. // Make sure app gave us enough space.
  1753. //
  1754. if (bytesNeeded > cbBufSize) {
  1755. *pcbBytesNeeded = bytesNeeded;
  1756. ApiStatus = ERROR_INSUFFICIENT_BUFFER;
  1757. goto Cleanup;
  1758. }
  1759. //========================
  1760. // Fill in the strings.
  1761. //========================
  1762. fixedDataEnd = (LPWSTR) (lpServiceConfig + 1);
  1763. endOfVariableData = (LPWSTR) ((LPBYTE)lpServiceConfig + bytesNeeded);
  1764. bufSize = 0;
  1765. if (CurrentImagePathName != NULL) {
  1766. bufSize = (DWORD) wcslen( CurrentImagePathName );
  1767. }
  1768. if ( !ScCopyStringToBufferW (
  1769. CurrentImagePathName,
  1770. bufSize,
  1771. fixedDataEnd,
  1772. & endOfVariableData,
  1773. & lpServiceConfig->lpBinaryPathName,
  1774. NULL
  1775. ) ) {
  1776. SC_LOG0(ERROR,
  1777. "RQueryServiceConfigW:ScCopyStringtoBufferW "
  1778. "(BinaryPathName)Failed\n");
  1779. SC_ASSERT( FALSE );
  1780. ApiStatus = ERROR_INSUFFICIENT_BUFFER;
  1781. goto Cleanup;
  1782. }
  1783. bufSize = 0;
  1784. if (CurrentGroup != NULL) {
  1785. bufSize = (DWORD) wcslen( CurrentGroup );
  1786. }
  1787. if ( !ScCopyStringToBufferW (
  1788. CurrentGroup,
  1789. bufSize,
  1790. fixedDataEnd,
  1791. &endOfVariableData,
  1792. &lpServiceConfig->lpLoadOrderGroup,
  1793. NULL
  1794. ) ) {
  1795. SC_LOG0(ERROR,
  1796. "RQueryServiceConfigW:ScCopyStringtoBufferW "
  1797. "(LoadOrderGroup)Failed\n");
  1798. SC_ASSERT( FALSE );
  1799. ApiStatus = ERROR_INSUFFICIENT_BUFFER;
  1800. goto Cleanup;
  1801. }
  1802. //
  1803. // Dependencies
  1804. //
  1805. if ((CurrentDependencies == NULL) || (dependSize == 0)) {
  1806. //
  1807. // There are no dependencies so put in a double null terminated
  1808. // null string.
  1809. //
  1810. // NOTE: The seperator character '/' is inserted to allow the
  1811. // double NULL terminated string to make it across RPC.
  1812. // This is removed by the client side.
  1813. //
  1814. lpServiceConfig->lpDependencies = endOfVariableData - 2;
  1815. endOfVariableData = lpServiceConfig->lpDependencies;
  1816. lpServiceConfig->lpDependencies[0] = L'/';
  1817. lpServiceConfig->lpDependencies[1] = L'\0';
  1818. }
  1819. else {
  1820. lpServiceConfig->lpDependencies = (LPWSTR)((LPBYTE)endOfVariableData - dependSize);
  1821. pDependString = lpServiceConfig->lpDependencies;
  1822. endOfVariableData = pDependString;
  1823. RtlCopyMemory(lpServiceConfig->lpDependencies, CurrentDependencies, dependSize);
  1824. //
  1825. // Add seperator characters.
  1826. //
  1827. while ((bufSize = (DWORD) wcslen(pDependString)) != 0) {
  1828. pDependString += bufSize;
  1829. *pDependString = L'/';
  1830. pDependString++;
  1831. }
  1832. }
  1833. //
  1834. // StartName
  1835. //
  1836. bufSize = 0;
  1837. if (CurrentStartName != NULL) {
  1838. bufSize = (DWORD) wcslen(CurrentStartName);
  1839. }
  1840. if ( !ScCopyStringToBufferW (
  1841. CurrentStartName,
  1842. bufSize,
  1843. fixedDataEnd,
  1844. & endOfVariableData,
  1845. & lpServiceConfig->lpServiceStartName,
  1846. NULL
  1847. ) ) {
  1848. SC_LOG0(ERROR,
  1849. "RQueryServiceConfigW:ScCopyStringtoBufferW (StartName)Failed\n");
  1850. SC_ASSERT( FALSE );
  1851. ApiStatus = ERROR_INSUFFICIENT_BUFFER;
  1852. goto Cleanup;
  1853. }
  1854. //
  1855. // DisplayName
  1856. //
  1857. bufSize = 0;
  1858. SC_ASSERT(CurrentDisplayName);
  1859. bufSize = (DWORD) wcslen(CurrentDisplayName);
  1860. if ( !ScCopyStringToBufferW (
  1861. CurrentDisplayName,
  1862. bufSize,
  1863. fixedDataEnd,
  1864. & endOfVariableData,
  1865. & lpServiceConfig->lpDisplayName,
  1866. NULL
  1867. ) ) {
  1868. SC_LOG0(ERROR,
  1869. "RQueryServiceConfigW:ScCopyStringtoBufferW (DisplayName)Failed\n");
  1870. SC_ASSERT( FALSE );
  1871. ApiStatus = ERROR_INSUFFICIENT_BUFFER;
  1872. goto Cleanup;
  1873. }
  1874. //
  1875. // That's all, folks! --JR
  1876. //
  1877. ApiStatus = NO_ERROR;
  1878. Cleanup:
  1879. if (ServiceNameKey != (HKEY) NULL) {
  1880. ScRegCloseKey(ServiceNameKey);
  1881. }
  1882. LocalFree(CurrentStartName);
  1883. LocalFree(CurrentImagePathName);
  1884. if (serviceRecord != NULL &&
  1885. CurrentDisplayName != serviceRecord->DisplayName) {
  1886. (VOID) LocalFree( CurrentDisplayName );
  1887. }
  1888. LocalFree( CurrentGroup );
  1889. LocalFree( CurrentDependencies );
  1890. if (pcbBytesNeeded != NULL) {
  1891. *pcbBytesNeeded = bytesNeeded;
  1892. }
  1893. SC_LOG2( CONFIG_API, "RQueryServiceConfigW returning status " FORMAT_DWORD
  1894. " and size needed " FORMAT_DWORD ".\n", ApiStatus, bytesNeeded );
  1895. //
  1896. // If an error occurs, we set the pointers in the structure to NULL.
  1897. // This is for RPC. Since we are using the byte_count feature, the
  1898. // server marshalling code must look at the pointers. Otherwise, it
  1899. // doesn't know how to marshall the strings.
  1900. //
  1901. if (ApiStatus != NO_ERROR) {
  1902. lpServiceConfig->lpBinaryPathName = NULL;
  1903. lpServiceConfig->lpLoadOrderGroup = NULL;
  1904. lpServiceConfig->lpDependencies = NULL;
  1905. lpServiceConfig->lpServiceStartName = NULL;
  1906. lpServiceConfig->lpDisplayName = NULL;
  1907. }
  1908. return (ApiStatus);
  1909. }
  1910. DWORD
  1911. ScCanonDriverImagePath(
  1912. IN DWORD DriverStartType,
  1913. IN LPWSTR DriverPath,
  1914. OUT LPWSTR *CanonDriverPath
  1915. )
  1916. /*++
  1917. Routine Description:
  1918. This function converts the user specified DOS path name to the driver
  1919. binary file into an NT path format understood by NtLoadDriver.
  1920. Examples:
  1921. C:\nt\system32\file.sys -> \DosDevices\c:\nt\system323\file.sys
  1922. %SystemRoot%\system32\drivers\file.sys -> \SystemRoot\system32\driver\file.sys
  1923. Arguments:
  1924. DriverPath - User specified DOS path name to driver .SYS file.
  1925. CanonDriverPath - Receives a pointer to a buffer which contains the
  1926. NT path to the driver .SYS file. This buffer should be freed
  1927. with LocalFree.
  1928. Return Value:
  1929. NO_ERROR - successful.
  1930. ERROR_NOT_ENOUGH_MEMORY - no memory to allocate output buffer.
  1931. ERROR_INVALID_PARAMETER - RtlDosPathNameToNtPath_U failure.
  1932. --*/
  1933. {
  1934. UNICODE_STRING NewPath;
  1935. DWORD DriverPathLength;
  1936. DWORD NTSystemRootLength;
  1937. DWORD DOSSystemRootLength;
  1938. LPWSTR RelativeCanonPath;
  1939. DWORD Status;
  1940. SC_LOG1(DEPEND, "ScCanonDriverImagePath: Input path "
  1941. FORMAT_LPWSTR "\n", DriverPath);
  1942. DriverPathLength = (DWORD) wcslen(DriverPath);
  1943. NTSystemRootLength = (DWORD) wcslen(SC_NT_SYSTEM_ROOT);
  1944. if (DriverPathLength > NTSystemRootLength &&
  1945. (_wcsnicmp(SC_NT_SYSTEM_ROOT, DriverPath,
  1946. NTSystemRootLength) == 0)) {
  1947. //
  1948. // Path is already in NT form with \SystemRoot\ prefix.
  1949. // Just return a buffer that contains the same path as input.
  1950. //
  1951. *CanonDriverPath = (LPWSTR) LocalAlloc(LMEM_ZEROINIT,
  1952. (UINT) ((DriverPathLength + 1) * sizeof(WCHAR)));
  1953. if (*CanonDriverPath == NULL) {
  1954. SC_LOG1(ERROR, "ScCanonDriverPathName: LocalAlloc failed %lu\n",
  1955. GetLastError());
  1956. return ERROR_NOT_ENOUGH_MEMORY;
  1957. }
  1958. //
  1959. // Boot drivers need relative path names
  1960. //
  1961. if (DriverStartType == SERVICE_BOOT_START) {
  1962. wcscpy(*CanonDriverPath, DriverPath + NTSystemRootLength);
  1963. }
  1964. else {
  1965. wcscpy(*CanonDriverPath, DriverPath);
  1966. }
  1967. SC_LOG1(DEPEND, "ScCanonDriverImagePath: Canonicalized path "
  1968. FORMAT_LPWSTR "\n", *CanonDriverPath);
  1969. return NO_ERROR;
  1970. }
  1971. DOSSystemRootLength = (DWORD) wcslen(SC_DOS_SYSTEM_ROOT);
  1972. if (DriverPathLength > DOSSystemRootLength &&
  1973. (_wcsnicmp(SC_DOS_SYSTEM_ROOT, DriverPath, DOSSystemRootLength) == 0)) {
  1974. //
  1975. // DOS path has %SystemRoot%\ prefix
  1976. //
  1977. *CanonDriverPath = (LPWSTR) LocalAlloc(LMEM_ZEROINIT,
  1978. (UINT) ((DriverPathLength + 1) * sizeof(WCHAR)));
  1979. if (*CanonDriverPath == NULL) {
  1980. SC_LOG1(ERROR, "ScCanonDriverPathName: LocalAlloc failed %lu\n",
  1981. GetLastError());
  1982. return ERROR_NOT_ENOUGH_MEMORY;
  1983. }
  1984. if (DriverStartType != SERVICE_BOOT_START) {
  1985. wcscpy(*CanonDriverPath, SC_NT_SYSTEM_ROOT);
  1986. }
  1987. else {
  1988. *CanonDriverPath[0] = '\0';
  1989. }
  1990. wcscat(*CanonDriverPath, DriverPath + DOSSystemRootLength);
  1991. SC_LOG1(DEPEND, "ScCanonDriverImagePath: Canonicalized path "
  1992. FORMAT_LPWSTR "\n", *CanonDriverPath);
  1993. return NO_ERROR;
  1994. }
  1995. //
  1996. // If it's already a relative path name, leave it alone
  1997. //
  1998. if (DriverPath[0] != L'\\' && DriverPath[1] != L':') {
  1999. *CanonDriverPath = (LPWSTR) LocalAlloc(LMEM_ZEROINIT,
  2000. (UINT) ((DriverPathLength + 1) * sizeof(WCHAR)));
  2001. if (*CanonDriverPath == NULL) {
  2002. SC_LOG1(ERROR, "ScCanonDriverPathName: LocalAlloc failed %lu\n",
  2003. GetLastError());
  2004. return ERROR_NOT_ENOUGH_MEMORY;
  2005. }
  2006. wcscpy(*CanonDriverPath, DriverPath);
  2007. return(NO_ERROR);
  2008. }
  2009. //
  2010. // Convert DOS path to NT path using Rtl routine which allocates
  2011. // the Unicode string buffer.
  2012. //
  2013. if (! RtlDosPathNameToNtPathName_U(
  2014. (PCWSTR) DriverPath,
  2015. &NewPath,
  2016. NULL,
  2017. NULL
  2018. )) {
  2019. return ERROR_INVALID_PARAMETER;
  2020. }
  2021. *CanonDriverPath = (LPWSTR) LocalAlloc(
  2022. LMEM_ZEROINIT,
  2023. (UINT) NewPath.Length + sizeof(WCHAR)
  2024. );
  2025. if (*CanonDriverPath == NULL) {
  2026. SC_LOG1(ERROR, "ScCanonDriverPathName: LocalAlloc failed %lu\n",
  2027. GetLastError());
  2028. RtlFreeUnicodeString(&NewPath);
  2029. return ERROR_NOT_ENOUGH_MEMORY;
  2030. }
  2031. wcsncpy(*CanonDriverPath, NewPath.Buffer, NewPath.Length / sizeof(WCHAR));
  2032. RtlFreeUnicodeString(&NewPath);
  2033. //
  2034. // Boot drivers' imagepath must be relative to \systemroot
  2035. //
  2036. if (DriverStartType == SERVICE_BOOT_START)
  2037. {
  2038. Status = ScConvertToBootPathName(*CanonDriverPath, &RelativeCanonPath);
  2039. if (Status == NO_ERROR)
  2040. {
  2041. SC_ASSERT(RelativeCanonPath != NULL);
  2042. wcscpy(*CanonDriverPath, RelativeCanonPath + NTSystemRootLength);
  2043. LocalFree(RelativeCanonPath);
  2044. }
  2045. else
  2046. {
  2047. LocalFree(*CanonDriverPath);
  2048. *CanonDriverPath = NULL;
  2049. }
  2050. return Status;
  2051. }
  2052. SC_LOG1(DEPEND, "ScCanonDriverImagePath: Canonicalized path "
  2053. FORMAT_LPWSTR "\n", *CanonDriverPath);
  2054. return NO_ERROR;
  2055. }
  2056. DWORD
  2057. RGetServiceDisplayNameW(
  2058. SC_RPC_HANDLE hSCManager,
  2059. LPWSTR lpServiceName,
  2060. LPWSTR lpDisplayName,
  2061. LPDWORD lpcchBuffer
  2062. )
  2063. /*++
  2064. Routine Description:
  2065. This function returns the DisplayName that is associated with a
  2066. particular ServiceName. If the buffer that is to receive the
  2067. DisplayName is too small, no data is returned in the buffer. Instead,
  2068. the actual string size (in characters - not including NUL terminator)
  2069. is returned in *lpcchBuffer.
  2070. Arguments:
  2071. hSCManager - Handle to the Service Control Manager. This parameter
  2072. is the RPC handle that was used to get us to this point.
  2073. lpServiceName - This is a pointer to the service name string. This
  2074. name is the same as the registry key name for that service.
  2075. lpDisplayName - This is a pointer to the buffer where the display name
  2076. is to be placed. If this function fails, this buffer will contain
  2077. an empty string.
  2078. lpcchBuffer - This is a pointer to a DWORD that contains the size of
  2079. the buffer (in characters) upon input. On return, this DWORD
  2080. indicates how many characters (excluding the NUL terminator) are
  2081. in the DisplayName.
  2082. Return Value:
  2083. NO_ERROR - If the operation was successful.
  2084. ERROR_INSUFFICIENT_BUFFER - if the buffer is too small to contain the
  2085. whole string.
  2086. ERROR_SERVICE_DOES_NOT_EXIST - If there is no record of a service
  2087. by this name in the database.
  2088. ERROR_INVALID_NAME - if the ServiceName is invalid (NULL);
  2089. --*/
  2090. {
  2091. DWORD status;
  2092. DWORD reqSize;
  2093. LPSERVICE_RECORD ServiceRecord;
  2094. UNREFERENCED_PARAMETER(hSCManager);
  2095. //
  2096. // Find the proper service record.
  2097. //
  2098. CServiceListSharedLock LLock;
  2099. CServiceRecordSharedLock RLock;
  2100. status = ScGetNamedServiceRecord(lpServiceName, &ServiceRecord);
  2101. if (status != NO_ERROR) {
  2102. return(status);
  2103. }
  2104. //
  2105. // Get the display name and determine if it will fit in the buffer.
  2106. //
  2107. reqSize = (DWORD) wcslen(ServiceRecord->DisplayName);
  2108. if (*lpcchBuffer < (reqSize + 1))
  2109. {
  2110. *lpcchBuffer = reqSize;
  2111. return(ERROR_INSUFFICIENT_BUFFER);
  2112. }
  2113. wcscpy(lpDisplayName, ServiceRecord->DisplayName);
  2114. *lpcchBuffer = reqSize;
  2115. return(NO_ERROR);
  2116. }
  2117. DWORD
  2118. RGetServiceKeyNameW(
  2119. SC_RPC_HANDLE hSCManager,
  2120. LPWSTR lpDisplayName,
  2121. LPWSTR lpServiceName,
  2122. LPDWORD lpcchBuffer
  2123. )
  2124. /*++
  2125. Routine Description:
  2126. This function returns the ServiceName that is associated with a
  2127. particular DisplayName. If the buffer that is to receive the
  2128. ServiceName is too small, no data is returned in the buffer. Instead,
  2129. the actual string size (in characters - not including NUL terminator)
  2130. is returned in *lpcchBuffer.
  2131. Arguments:
  2132. hSCManager - Handle to the Service Control Manager. This parameter
  2133. is the RPC handle that was used to get us to this point.
  2134. lpDisplayName - This is a pointer to the service display name string.
  2135. lpServiceName - This is a pointer to the buffer where the service name
  2136. string is to be placed. If this function fails, this buffer will
  2137. contain an empty string.
  2138. lpcchBuffer - This is a pointer to a DWORD that contains the size of
  2139. the buffer (in characters) upon input. On return, this DWORD
  2140. indicates how many characters (excluding the NUL terminator) are
  2141. in the DisplayName.
  2142. Return Value:
  2143. --*/
  2144. {
  2145. DWORD status;
  2146. DWORD reqSize;
  2147. LPSERVICE_RECORD ServiceRecord;
  2148. UNREFERENCED_PARAMETER(hSCManager);
  2149. //
  2150. // Find the proper service record.
  2151. //
  2152. CServiceListSharedLock LLock;
  2153. CServiceRecordSharedLock RLock;
  2154. status = ScGetDisplayNamedServiceRecord(lpDisplayName, &ServiceRecord);
  2155. if (status != NO_ERROR)
  2156. {
  2157. return(status);
  2158. }
  2159. //
  2160. // Get the service key name and determine if it will fit in the buffer.
  2161. //
  2162. reqSize = (DWORD) wcslen(ServiceRecord->ServiceName);
  2163. if (*lpcchBuffer < (reqSize + 1)) {
  2164. *lpcchBuffer = reqSize;
  2165. return(ERROR_INSUFFICIENT_BUFFER);
  2166. }
  2167. wcscpy(lpServiceName, ServiceRecord->ServiceName);
  2168. *lpcchBuffer = reqSize;
  2169. return(NO_ERROR);
  2170. }
  2171. DWORD
  2172. ScValidateDisplayName(
  2173. LPWSTR lpDisplayName,
  2174. LPSERVICE_RECORD lpServiceRecord
  2175. )
  2176. /*++
  2177. Routine Description:
  2178. This function validates display names by checking to see if the name
  2179. string already exists in the database. The display name must not match
  2180. any other display name or another service name. The display name can
  2181. match the service name if it they both refer to the same service.
  2182. Arguments:
  2183. lpDisplayName - A pointer to the proposed DisplayName.
  2184. lpServiceRecord - A pointer to the service record to which the display
  2185. name is to be added. If this function is called from CreateService,
  2186. the lpServiceRecord pointer will be NULL.
  2187. Return Value:
  2188. NO_ERROR - If the DisplayName doesn't conflict with any other names
  2189. in the database.
  2190. ERROR_DUPLICATE_SERVICE_NAME - If the DisplayName conflicts with another name.
  2191. --*/
  2192. {
  2193. DWORD status = NO_ERROR;
  2194. LPSERVICE_RECORD displayServiceRecord;
  2195. if (lpDisplayName != NULL) {
  2196. if (wcslen(lpDisplayName) > MAX_SERVICE_NAME_LENGTH) {
  2197. return(ERROR_INVALID_NAME);
  2198. }
  2199. status = ScGetDisplayNamedServiceRecord(
  2200. lpDisplayName,
  2201. &displayServiceRecord);
  2202. if (status == NO_ERROR) {
  2203. if (displayServiceRecord != lpServiceRecord) {
  2204. //
  2205. // The display name already exists for a different
  2206. // service. Therefore we must reject it.
  2207. //
  2208. return(ERROR_DUPLICATE_SERVICE_NAME);
  2209. }
  2210. }
  2211. status = ScGetNamedServiceRecord(
  2212. lpDisplayName,
  2213. &displayServiceRecord);
  2214. if (status == NO_ERROR) {
  2215. if (displayServiceRecord != lpServiceRecord) {
  2216. //
  2217. // The display name is already used as a service name.
  2218. // Therefore we must reject it.
  2219. //
  2220. return(ERROR_DUPLICATE_SERVICE_NAME);
  2221. }
  2222. }
  2223. }
  2224. return(NO_ERROR);
  2225. }
  2226. DWORD
  2227. ScConvertToBootPathName(
  2228. LPWSTR FullQualPathName,
  2229. LPWSTR * RelativePathName
  2230. )
  2231. /*++
  2232. Routine Description:
  2233. This function takes an NT style image path name and turns it into an
  2234. NT style path name that is accessed via \systemroot. This is required
  2235. for drivers that are loaded by the boot loader.
  2236. Arguments:
  2237. FullQualPathName - The fully qualified name
  2238. RelativePathName - A pointer to the pointer for the new buffer which
  2239. contains the fully qualified path name using
  2240. \systemroot\. The caller must free this buffer using
  2241. LocalFree.
  2242. Return Value:
  2243. NO_ERROR - If the name can be converted.
  2244. ERROR_INVALID_PARAMETER - If the Name is not relative to \systemroot
  2245. --*/
  2246. {
  2247. WCHAR Dummy;
  2248. LPWSTR Prefix = &Dummy;
  2249. DWORD PrefixLength;
  2250. UNICODE_STRING NewPrefix;
  2251. DWORD NTSystemRootLength;
  2252. DWORD PathLength;
  2253. DWORD NumRequired;
  2254. DWORD CharsReturned;
  2255. OBJECT_ATTRIBUTES ObjectAttributes;
  2256. HANDLE Handle = NULL;
  2257. UNICODE_STRING FileName;
  2258. UNICODE_STRING LinkTarget = { 0, 0, NULL };
  2259. NTSTATUS Status;
  2260. DWORD dwError = NO_ERROR;
  2261. DWORD BytesRequired;
  2262. PrefixLength = (DWORD) wcslen(SC_NT_SYSTEM_ROOT);
  2263. NTSystemRootLength = PrefixLength;
  2264. PathLength = (DWORD) wcslen(FullQualPathName);
  2265. if ((PathLength > PrefixLength) &&
  2266. (_wcsnicmp(SC_NT_SYSTEM_ROOT, FullQualPathName, PrefixLength) == 0)) {
  2267. //
  2268. // Path is already in NT form with \SystemRoot\ prefix.
  2269. // Just return it
  2270. //
  2271. *RelativePathName = (LPWSTR) LocalAlloc(LMEM_ZEROINIT,
  2272. (UINT) (PathLength + 1) * sizeof(WCHAR));
  2273. if (*RelativePathName == NULL)
  2274. {
  2275. SC_LOG1(ERROR, "ScConvertToBootName: LocalAlloc failed %d\n",
  2276. GetLastError());
  2277. return(ERROR_NOT_ENOUGH_MEMORY);
  2278. }
  2279. wcscpy(*RelativePathName, FullQualPathName);
  2280. return(ERROR_SUCCESS);
  2281. }
  2282. PrefixLength = (DWORD) wcslen(SC_DOS_SYSTEM_ROOT);
  2283. if (PathLength > PrefixLength &&
  2284. (_wcsnicmp(SC_DOS_SYSTEM_ROOT, FullQualPathName, PrefixLength) == 0)) {
  2285. //
  2286. // Path is in DOS form with %SystemRoot% prefix.
  2287. // Just return it after replacing the %SystemRoot%\ prefix with
  2288. // \SystemRoot
  2289. //
  2290. *RelativePathName = (LPWSTR) LocalAlloc(LMEM_ZEROINIT,
  2291. (UINT) (PathLength - PrefixLength + NTSystemRootLength + 1)
  2292. * sizeof(WCHAR));
  2293. if (*RelativePathName == NULL) {
  2294. SC_LOG1(ERROR, "ScConvertToBootName: LocalAlloc failed %d\n",
  2295. GetLastError());
  2296. return(ERROR_NOT_ENOUGH_MEMORY);
  2297. }
  2298. wcscpy(*RelativePathName, SC_NT_SYSTEM_ROOT);
  2299. wcscat(*RelativePathName, FullQualPathName + PrefixLength);
  2300. return(ERROR_SUCCESS);
  2301. }
  2302. //
  2303. // Create a string that represents the path to systemroot that you
  2304. // would get if you started with a Dos style name
  2305. //
  2306. //
  2307. // Make the first call just to get the number of characters that
  2308. // will be returned.
  2309. //
  2310. NumRequired = ExpandEnvironmentStringsW (SC_DOS_SYSTEM_ROOT, Prefix, 1);
  2311. if (NumRequired > 1) {
  2312. Prefix = (LPWSTR)LocalAlloc(LMEM_ZEROINIT,
  2313. (UINT) ((NumRequired + 1) * sizeof(WCHAR)));
  2314. if (Prefix == NULL) {
  2315. SC_LOG2(ERROR, "ScConvertToBootName: LocalAlloc of numChar= "
  2316. FORMAT_DWORD " failed " FORMAT_DWORD "\n",
  2317. NumRequired + 1, GetLastError());
  2318. return(ERROR_NOT_ENOUGH_MEMORY);
  2319. }
  2320. //
  2321. // Now expand the string into a dos type path
  2322. //
  2323. CharsReturned = ExpandEnvironmentStringsW (
  2324. SC_DOS_SYSTEM_ROOT,
  2325. Prefix,
  2326. NumRequired);
  2327. if (CharsReturned > NumRequired) {
  2328. SC_LOG1(ERROR, "ScConvertToBootName: ExpandEnvironmentStrings "
  2329. " failed for " FORMAT_LPWSTR " \n", SC_DOS_SYSTEM_ROOT);
  2330. LocalFree(Prefix);
  2331. return(ERROR_NOT_ENOUGH_MEMORY);
  2332. }
  2333. }
  2334. else {
  2335. //
  2336. // This shouldn't ever happen
  2337. //
  2338. ASSERT(FALSE);
  2339. return ERROR_INVALID_ENVIRONMENT;
  2340. }
  2341. //
  2342. // Now convert the DOS path to an NT path
  2343. //
  2344. if (! RtlDosPathNameToNtPathName_U(
  2345. (PCWSTR) Prefix,
  2346. &NewPrefix,
  2347. NULL,
  2348. NULL
  2349. )) {
  2350. //
  2351. // This shouldn't ever happen
  2352. //
  2353. ASSERT(FALSE);
  2354. LocalFree(Prefix);
  2355. return ERROR_INVALID_ENVIRONMENT;
  2356. }
  2357. LocalFree(Prefix);
  2358. PrefixLength = NewPrefix.Length / sizeof(WCHAR);
  2359. Prefix = (LPWSTR)LocalAlloc(LMEM_ZEROINIT,
  2360. (UINT) (NewPrefix.Length + sizeof(WCHAR)));
  2361. if (Prefix == NULL)
  2362. {
  2363. SC_LOG2(ERROR, "ScConvertToBootName: LocalAlloc of numChar= "
  2364. FORMAT_DWORD " failed " FORMAT_DWORD "\n",
  2365. NewPrefix.Length + sizeof(WCHAR), GetLastError());
  2366. dwError = ERROR_NOT_ENOUGH_MEMORY;
  2367. goto ErrorExit;
  2368. }
  2369. wcsncpy(Prefix, NewPrefix.Buffer, PrefixLength);
  2370. if (PathLength > PrefixLength &&
  2371. (_wcsnicmp(Prefix, FullQualPathName, PrefixLength) == 0)) {
  2372. //
  2373. // Path is in DOS form without using %systemroot%
  2374. // Convert to \SystemRoot format
  2375. //
  2376. *RelativePathName = (LPWSTR) LocalAlloc(LMEM_ZEROINIT,
  2377. (UINT) (PathLength - PrefixLength + NTSystemRootLength + 1)
  2378. * sizeof(WCHAR));
  2379. if (*RelativePathName == NULL)
  2380. {
  2381. SC_LOG2(ERROR, "ScConvertToBootName: LocalAlloc of numChar= "
  2382. FORMAT_DWORD " failed " FORMAT_DWORD "\n",
  2383. (PathLength - PrefixLength + NTSystemRootLength + 1) *
  2384. sizeof(WCHAR), GetLastError());
  2385. dwError = ERROR_NOT_ENOUGH_MEMORY;
  2386. goto ErrorExit;
  2387. }
  2388. wcscpy(*RelativePathName, SC_NT_SYSTEM_ROOT);
  2389. wcscat(*RelativePathName, FullQualPathName + PrefixLength);
  2390. dwError = NO_ERROR;
  2391. goto CleanExit;
  2392. }
  2393. //
  2394. // Create a string that represents the path to systemroot that you
  2395. // would get if you started with a NT style name
  2396. //
  2397. //
  2398. // Make the first call just to get the number of characters that
  2399. // will be returned.
  2400. //
  2401. RtlInitUnicodeString(&FileName,L"\\SystemRoot");
  2402. InitializeObjectAttributes(
  2403. &ObjectAttributes,
  2404. &FileName,
  2405. OBJ_CASE_INSENSITIVE,
  2406. NULL,
  2407. NULL
  2408. );
  2409. Status = NtOpenSymbolicLinkObject(&Handle, SYMBOLIC_LINK_QUERY,
  2410. &ObjectAttributes);
  2411. if (!NT_SUCCESS(Status))
  2412. {
  2413. //
  2414. // This should never happen
  2415. //
  2416. ASSERT(FALSE);
  2417. dwError = ERROR_INVALID_ENVIRONMENT;
  2418. goto ErrorExit;
  2419. }
  2420. Status = NtQuerySymbolicLinkObject(Handle, &LinkTarget, &BytesRequired);
  2421. if (!NT_SUCCESS(Status) && Status != STATUS_BUFFER_TOO_SMALL)
  2422. {
  2423. //
  2424. // This should never happen
  2425. //
  2426. ASSERT(FALSE);
  2427. dwError = ERROR_INVALID_ENVIRONMENT;
  2428. goto ErrorExit;
  2429. }
  2430. LinkTarget.Buffer = (LPWSTR) LocalAlloc(LMEM_ZEROINIT,
  2431. BytesRequired + sizeof(WCHAR));
  2432. if (LinkTarget.Buffer == NULL)
  2433. {
  2434. SC_LOG2(ERROR, "ScConvertToBootName: LocalAlloc of numChar= "
  2435. FORMAT_DWORD " failed " FORMAT_DWORD "\n",
  2436. BytesRequired, GetLastError());
  2437. dwError = ERROR_NOT_ENOUGH_MEMORY;
  2438. goto ErrorExit;
  2439. }
  2440. LinkTarget.Length = (USHORT) BytesRequired;
  2441. LinkTarget.MaximumLength = (USHORT) (BytesRequired + sizeof(WCHAR));
  2442. Status = NtQuerySymbolicLinkObject(Handle, &LinkTarget, &BytesRequired);
  2443. if (!NT_SUCCESS(Status))
  2444. {
  2445. //
  2446. // This should never happen
  2447. //
  2448. ASSERT(FALSE);
  2449. dwError = ERROR_INVALID_ENVIRONMENT;
  2450. goto ErrorExit;
  2451. }
  2452. PrefixLength = LinkTarget.Length / sizeof(WCHAR);
  2453. if (PathLength > PrefixLength &&
  2454. (_wcsnicmp(LinkTarget.Buffer, FullQualPathName, PrefixLength) == 0)) {
  2455. //
  2456. // Path is in NT form without using \systemroot
  2457. // Convert to \SystemRoot format
  2458. //
  2459. *RelativePathName = (LPWSTR) LocalAlloc(LMEM_ZEROINIT,
  2460. (UINT) (PathLength - PrefixLength + NTSystemRootLength + 1)
  2461. * sizeof(WCHAR));
  2462. if (*RelativePathName == NULL)
  2463. {
  2464. SC_LOG2(ERROR, "ScConvertToBootName: LocalAlloc of numChar= "
  2465. FORMAT_DWORD " failed " FORMAT_DWORD "\n",
  2466. (PathLength - PrefixLength + NTSystemRootLength + 1) *
  2467. sizeof(WCHAR), GetLastError());
  2468. dwError = ERROR_NOT_ENOUGH_MEMORY;
  2469. goto ErrorExit;
  2470. }
  2471. wcscpy(*RelativePathName, SC_NT_SYSTEM_ROOT);
  2472. // Skip the \ between \SystemRoot and the relative name
  2473. wcscat(*RelativePathName, FullQualPathName + PrefixLength + 1);
  2474. dwError = NO_ERROR;
  2475. goto CleanExit;
  2476. }
  2477. //
  2478. // If we get this far, the imagepath is not relative to the systemroot.
  2479. //
  2480. dwError = ERROR_INVALID_PARAMETER;
  2481. ErrorExit:
  2482. //
  2483. // Return an error and a NULL pointer.
  2484. //
  2485. *RelativePathName = NULL;
  2486. CleanExit:
  2487. if (Handle)
  2488. {
  2489. NtClose(Handle);
  2490. }
  2491. LocalFree(LinkTarget.Buffer);
  2492. RtlFreeUnicodeString(&NewPrefix);
  2493. LocalFree(Prefix);
  2494. return dwError;
  2495. }
  2496. BOOLEAN
  2497. ScIsArcName(
  2498. LPWSTR PathName
  2499. )
  2500. /*++
  2501. Routine Description:
  2502. This function takes a driver's path name and determines if it is an
  2503. ARC style name. This is done by trying to open the file with \Arcname
  2504. prepended. There are symbolic links of this form for every valid arcname.
  2505. Arguments:
  2506. PathName - The image path
  2507. Return Value:
  2508. TRUE - If it is an arcname
  2509. FALSE - If it's not an arcname
  2510. --*/
  2511. {
  2512. #define ARC_PREFIX L"\\Arcname"
  2513. OBJECT_ATTRIBUTES ObjectAttributes;
  2514. HANDLE Handle;
  2515. IO_STATUS_BLOCK IoStatusBlock;
  2516. UNICODE_STRING FileName;
  2517. NTSTATUS Status;
  2518. LPWSTR NewString;
  2519. UINT BufferSize;
  2520. //
  2521. // Allocate the buffer for the composite string
  2522. //
  2523. BufferSize = ((DWORD) wcslen(PathName)
  2524. + (DWORD) wcslen(ARC_PREFIX) + 1) * sizeof(WCHAR);
  2525. NewString = (LPWSTR) LocalAlloc(LMEM_ZEROINIT, BufferSize);
  2526. if (NewString == NULL)
  2527. {
  2528. SC_LOG2(ERROR, "ScIsArcName: LocalAlloc of numChar= "
  2529. FORMAT_DWORD " failed " FORMAT_DWORD "\n", BufferSize, GetLastError());
  2530. return FALSE;
  2531. }
  2532. //
  2533. // Create the composite string
  2534. //
  2535. wcscpy(NewString, ARC_PREFIX);
  2536. wcscat(NewString, PathName);
  2537. RtlInitUnicodeString(&FileName, NewString);
  2538. //
  2539. // Try to open it
  2540. //
  2541. InitializeObjectAttributes(
  2542. &ObjectAttributes,
  2543. &FileName,
  2544. OBJ_CASE_INSENSITIVE,
  2545. NULL,
  2546. NULL);
  2547. Status = NtOpenFile(&Handle,
  2548. FILE_GENERIC_READ,
  2549. &ObjectAttributes,
  2550. &IoStatusBlock,
  2551. FILE_SHARE_READ,
  2552. FILE_SYNCHRONOUS_IO_NONALERT);
  2553. LocalFree(NewString);
  2554. //
  2555. // If you could open it, it's an arcname
  2556. //
  2557. if (NT_SUCCESS(Status))
  2558. {
  2559. //
  2560. // Close it, we just need the status
  2561. //
  2562. NtClose(Handle);
  2563. return TRUE;
  2564. }
  2565. else
  2566. {
  2567. return FALSE;
  2568. }
  2569. }