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.

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