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.

1662 lines
40 KiB

  1. /*++
  2. Copyright (c) 1999 Microsoft Corporation
  3. Module Name:
  4. sisSetup.c
  5. Abstract:
  6. This module is used to install the SIS and GROVELER services.
  7. Environment:
  8. User Mode Only
  9. Revision History:
  10. --*/
  11. #include <windows.h>
  12. #include <stdio.h>
  13. #include <conio.h>
  14. #include <stdlib.h>
  15. #include <winioctl.h>
  16. #include <aclapi.h>
  17. //#include <winldap.h>
  18. //
  19. // Global variables
  20. //
  21. SC_HANDLE scm = NULL;
  22. BOOL MakeCommonStoreDirHidden = TRUE;
  23. BOOL UseSystemACL = TRUE;
  24. BOOL IsWhistlerOrLater = FALSE;
  25. BOOL ForceGrovelAllPaths = FALSE;
  26. BOOL ForceGrovelRISOnly = FALSE;
  27. BOOL SetRISPath = FALSE;
  28. const wchar_t CommonStoreDirName[] = L"\\SIS Common Store";
  29. const wchar_t MaxIndexName[] = L"\\MaxIndex";
  30. const wchar_t BackupExludeList[] = L"\\SIS Common Store\\*.* /s" L"\000";
  31. const wchar_t GrovelerParameters[] = L"software\\Microsoft\\Windows NT\\CurrentVersion\\Groveler\\Parameters";
  32. const wchar_t GrovelAllPaths[] = L"GrovelAllPaths";
  33. const wchar_t OneStr[] = L"1";
  34. const wchar_t ZeroStr[] = L"0";
  35. const wchar_t TftpdServiceParameters[] = L"system\\CurrentControlSet\\Services\\tftpd\\parameters";
  36. const wchar_t DirectoryStr[] = L"directory";
  37. const wchar_t SISService[] = L"system\\CurrentControlSet\\Services\\SIS";
  38. const wchar_t GrovelerService[] = L"system\\CurrentControlSet\\Services\\Groveler";
  39. const wchar_t ImagePathStr[] = L"ImagePath";
  40. const wchar_t StartStr[] = L"Start";
  41. const wchar_t DisplayNameStr[] = L"DisplayName";
  42. const wchar_t TypeStr[] = L"Type";
  43. wchar_t RISPath[128] = {0}; //Holds RIS path to set
  44. //
  45. // Functions
  46. //
  47. VOID
  48. DisplayUsage (
  49. void
  50. )
  51. /*++
  52. Routine Description:
  53. This routine will display an error message based off of the Win32 error
  54. code that is passed in. This allows the user to see an understandable
  55. error message instead of just the code.
  56. Arguments:
  57. None
  58. Return Value:
  59. None.
  60. --*/
  61. {
  62. printf( "\nUsage: sisSetup [/?] [/h] [/s] [/i] [/u] [/n] [/a] [/g] [/r] [/p path] [drive: [...]]\n"
  63. " /? /h Display usage information.\n"
  64. " /s Display current groveler state (default if no operation specified).\n"
  65. "\n"
  66. " /i Create the SIS and GROVELER services. (if not already defined)\n"
  67. " /u Delete the SIS and GROVELER services.\n"
  68. " /g Have the groveler monitor all directories on all configured volumes.\n"
  69. " /r Have the groveler monitor only RIS directories on the RIS volume.\n"
  70. " /p path Specify the RIS volume and path to monitor.\n"
  71. "\n"
  72. " /n Do NOT make the \"SIS Common Store\" directory \"Hidden|System\".\n"
  73. " Will unhide the directory if it already exists and is hidden.\n"
  74. " /a Do NOT set SYSTEM ACL on \"SIS Common Store \" directory, instead\n"
  75. " set ADMINISTRATORS group ACL.\n"
  76. " This will change the ACL setting for existing directories.\n"
  77. "\n"
  78. " drive: A list of NTFS volumes you would like initialized for SIS.\n"
  79. " If no drives are specified, only the services will be installed.\n"
  80. " This will only initialize local hard drives with NTFS on them.\n"
  81. " The BOOT volume is never initialized.\n"
  82. "\n"
  83. " You must reboot for the changes to take affect.\n"
  84. "\n"
  85. "Example: sisSetup /i /g f: g:\n"
  86. " This will create the SIS and GROVELER services and initialize the\n"
  87. " \"SIS Common Store\" directory on the specified volumes.\n"
  88. );
  89. }
  90. void
  91. DisplayError (
  92. DWORD Code,
  93. LPSTR Msg,
  94. ...
  95. )
  96. /*++
  97. Routine Description:
  98. This routine will display an error message based off of the Win32 error
  99. code that is passed in. This allows the user to see an understandable
  100. error message instead of just the code.
  101. Arguments:
  102. Msg - The error message to display
  103. Code - The error code to be translated.
  104. Return Value:
  105. None.
  106. --*/
  107. {
  108. wchar_t errmsg[128];
  109. DWORD count;
  110. va_list ap;
  111. //printf("\n");
  112. va_start( ap, Msg );
  113. vprintf( Msg, ap );
  114. va_end( ap );
  115. //
  116. // Translate the Win32 error code into a useful message.
  117. //
  118. count = FormatMessage(
  119. FORMAT_MESSAGE_FROM_SYSTEM,
  120. NULL,
  121. Code,
  122. 0,
  123. errmsg,
  124. sizeof(errmsg),
  125. NULL );
  126. //
  127. // Make sure that the message could be translated.
  128. //
  129. if (count == 0) {
  130. printf( "(%d) Could not translate Error\n", Code );
  131. } else {
  132. //
  133. // Display the translated error.
  134. //
  135. printf( "(%d) %S", Code, errmsg );
  136. }
  137. }
  138. DWORD
  139. SetRegistryValue(
  140. IN LPCTSTR RegistryKey,
  141. IN LPCTSTR DataName,
  142. IN DWORD DataType,
  143. IN CONST void *Data,
  144. IN DWORD DataSize
  145. )
  146. {
  147. HKEY regHandle = NULL;
  148. DWORD status;
  149. //
  150. // Get a handle to the services registry key.
  151. //
  152. status = RegCreateKeyEx( HKEY_LOCAL_MACHINE,
  153. RegistryKey,
  154. 0,
  155. NULL,
  156. REG_OPTION_NON_VOLATILE,
  157. KEY_ALL_ACCESS,
  158. NULL,
  159. &regHandle,
  160. NULL );
  161. if (ERROR_SUCCESS != status) {
  162. DisplayError( status,
  163. "\nError creating registry key \"%S\", ",
  164. RegistryKey );
  165. return status;
  166. }
  167. try {
  168. //
  169. // Set the data value
  170. //
  171. status = RegSetValueEx( regHandle,
  172. DataName,
  173. 0,
  174. DataType,
  175. Data,
  176. DataSize );
  177. if (ERROR_SUCCESS != status) {
  178. DisplayError( status,
  179. "\nError setting registry data in the key \"%S\" and data \"%S\"",
  180. RegistryKey,
  181. DataName );
  182. leave;
  183. }
  184. } finally {
  185. //
  186. // Close the registry key
  187. //
  188. RegCloseKey( regHandle );
  189. }
  190. return status;
  191. }
  192. DWORD
  193. GetRegistryValue(
  194. IN LPCTSTR RegistryKey,
  195. IN LPCTSTR DataName,
  196. OUT DWORD *RetDataType,
  197. OUT void *Data,
  198. IN CONST DWORD DataSize,
  199. OUT DWORD *RetSize
  200. )
  201. {
  202. HKEY regHandle = NULL;
  203. DWORD status;
  204. //
  205. // Get a handle to the services registry key.
  206. //
  207. status = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  208. RegistryKey,
  209. 0,
  210. KEY_ALL_ACCESS,
  211. &regHandle );
  212. if (ERROR_SUCCESS != status) {
  213. // DisplayError( status,
  214. // "\nError opening registry key \"%S\", ",
  215. // RegistryKey );
  216. return status;
  217. }
  218. try {
  219. //
  220. // Set the data value
  221. //
  222. *RetSize = DataSize;
  223. status = RegQueryValueEx( regHandle,
  224. DataName,
  225. 0,
  226. RetDataType,
  227. Data,
  228. RetSize );
  229. if (ERROR_SUCCESS != status) {
  230. // DisplayError( status,
  231. // "\nError getting registry data in the key \"%S\" and data \"%S\"",
  232. // RegistryKey,
  233. // DataName );
  234. leave;
  235. }
  236. } finally {
  237. //
  238. // Close the registry key
  239. //
  240. RegCloseKey( regHandle );
  241. }
  242. return status;
  243. }
  244. DWORD
  245. SetupService(
  246. LPCTSTR Name,
  247. LPCTSTR DisplayName,
  248. LPCTSTR DriverPath,
  249. LPCTSTR LoadOrderGroup,
  250. LPCTSTR Dependencies,
  251. DWORD ServiceType,
  252. DWORD StartType,
  253. LPCTSTR RegistryKey,
  254. LPCTSTR RegDescription
  255. )
  256. /*++
  257. Routine Description:
  258. This routine will initialize the given service.
  259. Arguments:
  260. Return Value:
  261. Status of operation
  262. --*/
  263. {
  264. DWORD status;
  265. ULONG tag;
  266. SC_HANDLE srvHandle = NULL;
  267. HKEY regHandle = NULL;
  268. static CONST wchar_t DescriptionRegValue[] = L"Description";
  269. try {
  270. //
  271. // Create the given service
  272. //
  273. srvHandle = CreateService(
  274. scm,
  275. Name,
  276. DisplayName,
  277. STANDARD_RIGHTS_REQUIRED | SERVICE_START,
  278. ServiceType,
  279. StartType,
  280. SERVICE_ERROR_NORMAL,
  281. DriverPath,
  282. LoadOrderGroup,
  283. ((ServiceType == SERVICE_FILE_SYSTEM_DRIVER) ? &tag : NULL),
  284. Dependencies,
  285. NULL,
  286. NULL );
  287. if ( !srvHandle ) {
  288. status = GetLastError();
  289. if (ERROR_SERVICE_EXISTS != status) {
  290. DisplayError( status,
  291. "Creating the service \"%S\", ",
  292. Name);
  293. return status;
  294. }
  295. printf( "The \"%S\" service already exists.\n", Name );
  296. return ERROR_SUCCESS;
  297. }
  298. //
  299. // Get a handle to the services registry key.
  300. //
  301. status = RegOpenKeyEx (
  302. HKEY_LOCAL_MACHINE,
  303. RegistryKey,
  304. 0,
  305. KEY_ALL_ACCESS,
  306. &regHandle);
  307. if (ERROR_SUCCESS != status) {
  308. DisplayError( status,
  309. "Opening the registry key \"%S\", ",
  310. RegistryKey);
  311. return status;
  312. }
  313. //
  314. // Add the DESCRIPTION to the service
  315. //
  316. status = RegSetValueEx(
  317. regHandle,
  318. DescriptionRegValue,
  319. 0,
  320. REG_SZ,
  321. (CONST BYTE *)RegDescription,
  322. (wcslen(RegDescription) * sizeof(wchar_t)));
  323. if (ERROR_SUCCESS != status) {
  324. DisplayError( status,
  325. "Adding \"%S\" value to the \"%S\" registry key, ",
  326. DescriptionRegValue,
  327. RegistryKey);
  328. return status;
  329. }
  330. } finally {
  331. if (regHandle) {
  332. RegCloseKey( regHandle );
  333. }
  334. if (srvHandle) {
  335. CloseServiceHandle( srvHandle );
  336. }
  337. }
  338. printf( "The \"%S\" service was successfully added.\n", Name );
  339. return ERROR_SUCCESS;
  340. }
  341. DWORD
  342. CreateServices (
  343. void
  344. )
  345. /*++
  346. Routine Description:
  347. This will create the SIS and GROVELER service.
  348. Arguments:
  349. None
  350. Return Value:
  351. None.
  352. --*/
  353. {
  354. DWORD status;
  355. //
  356. // Create SIS service
  357. //
  358. status = SetupService(
  359. L"Sis",
  360. L"Single Instance Storage",
  361. L"%SystemRoot%\\system32\\drivers\\sis.sys",
  362. (IsWhistlerOrLater) ? L"FSFilter System" :
  363. L"filter",
  364. NULL,
  365. SERVICE_FILE_SYSTEM_DRIVER,
  366. SERVICE_BOOT_START,
  367. L"SYSTEM\\CurrentControlSet\\Services\\Sis",
  368. L"A File System Filter that manages duplicate copies of files on hard-disk volumes. It copies one instance of the duplicate file into a central directory, and the duplicates are replaced with a link to the central copy in order to improve disk usage. This service can not be stopped. If this service is disabled, all linked files will no longer be accessible. If the central directory is deleted, all linked files will become permanently inaccessible." );
  369. if (ERROR_SUCCESS != status) {
  370. return status;
  371. }
  372. //
  373. // Create GROVELER service
  374. //
  375. status = SetupService(
  376. L"Groveler",
  377. L"Single Instance Storage Groveler",
  378. L"%SystemRoot%\\system32\\grovel.exe",
  379. NULL,
  380. L"SIS\0",
  381. SERVICE_WIN32_OWN_PROCESS,
  382. SERVICE_AUTO_START,
  383. L"SYSTEM\\CurrentControlSet\\Services\\Groveler",
  384. L"Scans the hard-disk volumes on a Remote Installation Services (RIS) server for duplicate copies of files. If found, one instance of the duplicate file is stored in a central directory, and the duplicates are replaced with a link to the central copy in order to improve disk usage. If this service is stopped, files will no longer be automatically linked in this manner, but the existing linked files will still be accessible." );
  385. if (ERROR_SUCCESS != status) {
  386. return status;
  387. }
  388. return ERROR_SUCCESS;
  389. }
  390. DWORD
  391. RemoveService(
  392. LPCTSTR Name
  393. )
  394. /*++
  395. Routine Description:
  396. This will delete the given service. This will make sure the given
  397. service is stopped first.
  398. Arguments:
  399. None
  400. Return Value:
  401. Status of operation
  402. --*/
  403. {
  404. DWORD status;
  405. SC_HANDLE srvHandle = NULL;
  406. BOOL state;
  407. SERVICE_STATUS servStatus;
  408. int retryLimit;
  409. # define RETRY_TIMEOUT 500 //1/2 second
  410. # define RETRY_COUNT (6*2) //try for a few seconds
  411. try {
  412. //
  413. // Open the service
  414. //
  415. srvHandle = OpenService(
  416. scm,
  417. Name,
  418. SERVICE_ALL_ACCESS );
  419. if ( !srvHandle ) {
  420. status = GetLastError();
  421. if (ERROR_SERVICE_DOES_NOT_EXIST != status) {
  422. DisplayError( status,
  423. "Opening the service \"%S\", ",
  424. Name);
  425. return status;
  426. }
  427. printf( "The \"%S\" service does not exist.\n", Name );
  428. return ERROR_SUCCESS;
  429. }
  430. //
  431. // Stop the service
  432. //
  433. state = ControlService(
  434. srvHandle,
  435. SERVICE_CONTROL_STOP,
  436. &servStatus );
  437. if ( !state ) {
  438. status = GetLastError();
  439. if ((ERROR_SERVICE_NOT_ACTIVE != status) &&
  440. (ERROR_INVALID_SERVICE_CONTROL != status) ) {
  441. DisplayError( status,
  442. "Stoping the \"%S\" service, ",
  443. Name);
  444. return status;
  445. }
  446. }
  447. //
  448. // Wait a few seconds for the service to stop.
  449. //
  450. for (retryLimit=0;
  451. (SERVICE_STOPPED != servStatus.dwCurrentState);
  452. ) {
  453. Sleep( RETRY_TIMEOUT ); //wait for 1/4 second
  454. state = QueryServiceStatus(
  455. srvHandle,
  456. &servStatus );
  457. if ( !state ) {
  458. status = GetLastError();
  459. DisplayError( status,
  460. "Querrying service status for the \"%S\" service, ",
  461. Name);
  462. return status;
  463. }
  464. if (++retryLimit >= RETRY_COUNT) {
  465. printf("The \"%S\" service could not be stopped.\n",Name);
  466. break;
  467. }
  468. }
  469. //
  470. // Delete the service
  471. //
  472. state = DeleteService( srvHandle );
  473. if ( !state ) {
  474. status = GetLastError();
  475. DisplayError( status,
  476. "Deleting the \"%S\" service, ",
  477. Name);
  478. return status;
  479. }
  480. } finally {
  481. if (srvHandle) {
  482. CloseServiceHandle( srvHandle );
  483. }
  484. }
  485. printf( "The \"%S\" service was successfully deleted.\n", Name );
  486. return ERROR_SUCCESS;
  487. }
  488. DWORD
  489. DeleteServices(
  490. void
  491. )
  492. /*++
  493. Routine Description:
  494. This will delete the SIS and GROVELER services from the system
  495. Arguments:
  496. None
  497. Return Value:
  498. Status of operation
  499. --*/
  500. {
  501. DWORD status;
  502. status = RemoveService( L"Groveler" );
  503. if (ERROR_SUCCESS != status) {
  504. return status;
  505. }
  506. status = RemoveService( L"Sis" );
  507. if (ERROR_SUCCESS != status) {
  508. return status;
  509. }
  510. return ERROR_SUCCESS;
  511. }
  512. DWORD
  513. InitVolume(
  514. wchar_t *DevName
  515. )
  516. /*++
  517. Routine Description:
  518. This routine will initialize SIS on the given volume. This will verify
  519. that the volume is an NTFS volume and that it is not the BOOT volume.
  520. Arguments:
  521. DevName - The name of the volume to init
  522. Return Value:
  523. Status of operation
  524. --*/
  525. {
  526. HANDLE hVolume;
  527. HANDLE hCSDir;
  528. HANDLE hMaxIndex = INVALID_HANDLE_VALUE;
  529. DWORD status;
  530. DWORD transferCount;
  531. LONGLONG maxIndex;
  532. PSID pSid = NULL;
  533. PACL pAcl = NULL;
  534. EXPLICIT_ACCESS ExplicitEntries;
  535. SECURITY_ATTRIBUTES sa;
  536. SID_IDENTIFIER_AUTHORITY ntSidAuthority = SECURITY_NT_AUTHORITY;
  537. SECURITY_DESCRIPTOR SecDescriptor;
  538. BOOL state;
  539. USHORT compressionMode = COMPRESSION_FORMAT_DEFAULT;
  540. wchar_t name[MAX_PATH];
  541. wchar_t dirName[MAX_PATH];
  542. wchar_t fileSystemType[MAX_PATH];
  543. try {
  544. //
  545. // Get the "SystemDrive" environemnt variable
  546. //
  547. status = GetEnvironmentVariable(
  548. L"SystemDrive",
  549. name,
  550. (sizeof(name) / sizeof(wchar_t)));
  551. if (status <= 0) {
  552. printf( "Unable to retrieve the environment variable \"SystemDrive\"." );
  553. return ERROR_INVALID_FUNCTION;
  554. }
  555. //
  556. // See if they have requested the SYSTEM drive. If so return an error
  557. //
  558. if (_wcsicmp(name,DevName) == 0) {
  559. printf( "The volume \"%s\" is the BOOT volume, SIS not initialized on it.\n", DevName );
  560. return ERROR_SUCCESS;
  561. }
  562. //
  563. // Get the TYPE of the drive, see if it is a local HARDDISK (fixed
  564. // or removable). If not return now.
  565. //
  566. wsprintf(name,L"%s\\",DevName); //generate ROOTDIR name
  567. status = GetDriveType( name );
  568. if ((status == DRIVE_UNKNOWN) ||
  569. (status == DRIVE_NO_ROOT_DIR)) {
  570. printf("The volume \"%s\" does not exist.\n",DevName);
  571. return ERROR_SUCCESS;
  572. } else if ((status != DRIVE_FIXED) &&
  573. (status != DRIVE_REMOVABLE)) {
  574. printf("The volume \"%s\" is not a local hard drive, SIS not initialized on it.\n",DevName);
  575. return ERROR_SUCCESS;
  576. }
  577. //
  578. // Get the type of the file system on the volume. If not NTFS
  579. // return now.
  580. //
  581. state = GetVolumeInformation(
  582. name,
  583. NULL,
  584. 0,
  585. NULL,
  586. NULL,
  587. NULL,
  588. fileSystemType,
  589. sizeof(fileSystemType));
  590. if ( !state ) {
  591. status = GetLastError();
  592. if (ERROR_PATH_NOT_FOUND != status) {
  593. DisplayError( status,
  594. "Opening volume \"%s\", ",
  595. DevName );
  596. return status;
  597. }
  598. printf("The volume \"%s\" does not exist.\n",DevName);
  599. return ERROR_SUCCESS;
  600. }
  601. if (_wcsnicmp(fileSystemType, L"NTFS", 4 ) != 0) {
  602. printf("The volume \"%s\" is not an NTFS volume, SIS not initialized on it.\n",DevName);
  603. return ERROR_SUCCESS;
  604. }
  605. //
  606. // Create the Common Store Directory. Keep going if the directory
  607. // already exits.
  608. //
  609. wsprintf( dirName, L"%s%s", DevName, CommonStoreDirName );
  610. state = CreateDirectory(dirName, NULL);
  611. if ( !state ) {
  612. status = GetLastError();
  613. if (ERROR_ALREADY_EXISTS != status) {
  614. DisplayError( status,
  615. "Creating directory \"%S\", ",
  616. dirName);
  617. return status;
  618. }
  619. }
  620. //
  621. // Mark the directory as SYSTEM and HIDDEN if requested.
  622. //
  623. state = SetFileAttributes( dirName,
  624. ((MakeCommonStoreDirHidden) ?
  625. FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM :
  626. FILE_ATTRIBUTE_NORMAL) );
  627. if ( !state ) {
  628. status = GetLastError();
  629. DisplayError(
  630. status,
  631. "Setting attributes on directory \"%S\", ",
  632. dirName);
  633. }
  634. //
  635. // Set compression on the "SIS Common Store" directory
  636. // Don't do it for now.
  637. //
  638. // //
  639. // // Open the directory
  640. // //
  641. //
  642. // hCSDir = CreateFile(
  643. // dirName,
  644. // GENERIC_READ|GENERIC_WRITE,
  645. // FILE_SHARE_READ | FILE_SHARE_WRITE,
  646. // NULL,
  647. // OPEN_EXISTING,
  648. // FILE_FLAG_BACKUP_SEMANTICS,
  649. // NULL);
  650. //
  651. // if (INVALID_HANDLE_VALUE == hCSDir) {
  652. //
  653. // DisplayError(
  654. // status,
  655. // "Opening directory \"%S\" to update compression, ",
  656. // dirName);
  657. //
  658. // } else {
  659. //
  660. // //
  661. // // Enable compression
  662. // //
  663. //
  664. // state = DeviceIoControl(
  665. // hCSDir,
  666. // FSCTL_SET_COMPRESSION,
  667. // &compressionMode,
  668. // sizeof(compressionMode),
  669. // NULL,
  670. // 0,
  671. // &transferCount,
  672. // NULL);
  673. //
  674. // if ( !state ) {
  675. //
  676. // status = GetLastError();
  677. // DisplayError(
  678. // status,
  679. // "Enabling compression on \"%S\", ",
  680. // dirName);
  681. // }
  682. //
  683. // //
  684. // // Close directory handle
  685. // //
  686. //
  687. // CloseHandle( hCSDir );
  688. // }
  689. //
  690. // Create the MaxIndex file
  691. //
  692. wsprintf( name, L"%s%s", dirName, MaxIndexName );
  693. hMaxIndex = CreateFile(
  694. name,
  695. GENERIC_READ | GENERIC_WRITE,
  696. 0,
  697. NULL,
  698. CREATE_NEW,
  699. FILE_ATTRIBUTE_NORMAL,
  700. NULL);
  701. if (INVALID_HANDLE_VALUE == hMaxIndex) {
  702. status = GetLastError();
  703. if (ERROR_FILE_EXISTS != status) {
  704. DisplayError( status,
  705. "Creating file \"%S\", ",
  706. name);
  707. return status;
  708. }
  709. } else {
  710. //
  711. // The MaxIndex file did not exist, init it.
  712. //
  713. maxIndex = 1;
  714. state = WriteFile(
  715. hMaxIndex,
  716. &maxIndex,
  717. sizeof(maxIndex),
  718. &transferCount,
  719. NULL);
  720. if ( !state || (transferCount < sizeof(maxIndex)) ) {
  721. status = GetLastError();
  722. DisplayError( status,
  723. "Writing file \"%S\", ",
  724. name);
  725. return status;
  726. }
  727. //
  728. // Close the file
  729. //
  730. CloseHandle( hMaxIndex );
  731. hMaxIndex = INVALID_HANDLE_VALUE;
  732. }
  733. //
  734. // Set security information on the common store directory
  735. //
  736. //
  737. // build AccessEntry structure
  738. //
  739. ZeroMemory( &ExplicitEntries, sizeof(ExplicitEntries) );
  740. if (UseSystemACL) {
  741. state = AllocateAndInitializeSid(
  742. &ntSidAuthority,
  743. 1,
  744. SECURITY_LOCAL_SYSTEM_RID,
  745. 0, 0, 0, 0, 0, 0, 0,
  746. &pSid );
  747. } else {
  748. state = AllocateAndInitializeSid(
  749. &ntSidAuthority,
  750. 2,
  751. SECURITY_BUILTIN_DOMAIN_RID,
  752. DOMAIN_ALIAS_RID_ADMINS,
  753. 0, 0, 0, 0, 0, 0,
  754. &pSid );
  755. }
  756. if ( !state || (pSid == NULL) ) {
  757. status = GetLastError();
  758. DisplayError( status,
  759. "Creating SID, ");
  760. return status;
  761. }
  762. BuildTrusteeWithSid( &ExplicitEntries.Trustee, pSid );
  763. ExplicitEntries.grfInheritance = SUB_CONTAINERS_AND_OBJECTS_INHERIT;
  764. ExplicitEntries.grfAccessMode = SET_ACCESS;
  765. ExplicitEntries.grfAccessPermissions = FILE_ALL_ACCESS;
  766. //
  767. // Set the Acl with the ExplicitEntry rights
  768. //
  769. status = SetEntriesInAcl( 1,
  770. &ExplicitEntries,
  771. NULL,
  772. &pAcl );
  773. if ( status != ERROR_SUCCESS ) {
  774. DisplayError( status, "Creating ACL, ");
  775. return status;
  776. }
  777. //
  778. // Create the Security Descriptor
  779. //
  780. InitializeSecurityDescriptor( &SecDescriptor, SECURITY_DESCRIPTOR_REVISION );
  781. state = SetSecurityDescriptorDacl( &SecDescriptor, TRUE, pAcl, FALSE );
  782. if ( !state ) {
  783. status = GetLastError();
  784. DisplayError( status, "Setting Security DACL, ");
  785. return status;
  786. }
  787. //
  788. // SET security on the Directory
  789. //
  790. state = SetFileSecurity(dirName,
  791. DACL_SECURITY_INFORMATION,
  792. &SecDescriptor);
  793. if ( !state ) {
  794. status = GetLastError();
  795. DisplayError( status, "Setting File Security, ");
  796. return status;
  797. }
  798. } finally {
  799. //
  800. // Cleanup
  801. //
  802. if (hMaxIndex != INVALID_HANDLE_VALUE) {
  803. CloseHandle( hMaxIndex );
  804. }
  805. if ( pSid ) {
  806. FreeSid( pSid );
  807. }
  808. if ( pAcl ) {
  809. LocalFree( pAcl );
  810. }
  811. }
  812. printf( "The volume \"%s\" was successfully initialized.\n", DevName );
  813. return ERROR_SUCCESS;
  814. }
  815. void
  816. SetRegistryValues()
  817. {
  818. DWORD status;
  819. status = SetRegistryValue(
  820. L"SYSTEM\\CurrentControlSet\\Control\\BackupRestore\\FilesNotToBackup",
  821. L"Single Instance Storage",
  822. REG_MULTI_SZ,
  823. BackupExludeList,
  824. sizeof(BackupExludeList) );
  825. //
  826. // Set the apropriate "GrovelAllPaths" state
  827. //
  828. if (ForceGrovelAllPaths) {
  829. status = SetRegistryValue(
  830. GrovelerParameters,
  831. GrovelAllPaths,
  832. REG_SZ,
  833. OneStr,
  834. sizeof(OneStr) );
  835. } else if (ForceGrovelRISOnly) {
  836. status = SetRegistryValue(
  837. GrovelerParameters,
  838. GrovelAllPaths,
  839. REG_SZ,
  840. ZeroStr,
  841. sizeof(ZeroStr) );
  842. }
  843. if (SetRISPath) {
  844. status = SetRegistryValue(
  845. TftpdServiceParameters,
  846. DirectoryStr,
  847. REG_SZ,
  848. RISPath,
  849. (wcslen(RISPath) * sizeof(wchar_t)) );
  850. }
  851. }
  852. void
  853. DisplayGrovelerRISState()
  854. {
  855. DWORD status;
  856. DWORD dataType;
  857. DWORD dataSize;
  858. wchar_t data[128];
  859. wchar_t *endptr;
  860. BOOL doAllPaths = FALSE;
  861. BOOL hasPath = FALSE;
  862. BOOL sisConfigured = FALSE;
  863. BOOL grovelerConfigured = FALSE;
  864. printf("\n");
  865. //
  866. // See if SIS service is configured
  867. //
  868. try {
  869. status = GetRegistryValue( SISService,
  870. ImagePathStr,
  871. &dataType,
  872. data,
  873. sizeof(data),
  874. &dataSize );
  875. if (ERROR_SUCCESS != status) {
  876. leave;
  877. }
  878. status = GetRegistryValue( SISService,
  879. StartStr,
  880. &dataType,
  881. data,
  882. sizeof(data),
  883. &dataSize );
  884. if (ERROR_SUCCESS != status) {
  885. leave;
  886. }
  887. status = GetRegistryValue( SISService,
  888. DisplayNameStr,
  889. &dataType,
  890. data,
  891. sizeof(data),
  892. &dataSize );
  893. if (ERROR_SUCCESS != status) {
  894. leave;
  895. }
  896. status = GetRegistryValue( SISService,
  897. TypeStr,
  898. &dataType,
  899. data,
  900. sizeof(data),
  901. &dataSize );
  902. if (ERROR_SUCCESS != status) {
  903. leave;
  904. }
  905. sisConfigured = TRUE;
  906. } finally {
  907. printf( (sisConfigured) ?
  908. "The SIS Service is properly configured\n" :
  909. "The SIS Service is NOT properly configured\n" );
  910. }
  911. //
  912. // See if GROVELER service is configured
  913. //
  914. try {
  915. status = GetRegistryValue( GrovelerService,
  916. ImagePathStr,
  917. &dataType,
  918. data,
  919. sizeof(data),
  920. &dataSize );
  921. if (ERROR_SUCCESS != status) {
  922. leave;
  923. }
  924. status = GetRegistryValue( GrovelerService,
  925. StartStr,
  926. &dataType,
  927. data,
  928. sizeof(data),
  929. &dataSize );
  930. if (ERROR_SUCCESS != status) {
  931. leave;
  932. }
  933. status = GetRegistryValue( GrovelerService,
  934. DisplayNameStr,
  935. &dataType,
  936. data,
  937. sizeof(data),
  938. &dataSize );
  939. if (ERROR_SUCCESS != status) {
  940. leave;
  941. }
  942. status = GetRegistryValue( GrovelerService,
  943. TypeStr,
  944. &dataType,
  945. data,
  946. sizeof(data),
  947. &dataSize );
  948. if (ERROR_SUCCESS != status) {
  949. leave;
  950. }
  951. grovelerConfigured = TRUE;
  952. } finally {
  953. printf( (grovelerConfigured) ?
  954. "The GROVELER Service is properly configured\n" :
  955. "The GROVELER Service is NOT properly configured\n" );
  956. }
  957. //
  958. // Get GrovelAllPaths value
  959. //
  960. try {
  961. status = GetRegistryValue( GrovelerParameters,
  962. GrovelAllPaths,
  963. &dataType,
  964. data,
  965. sizeof(data),
  966. &dataSize );
  967. if (ERROR_SUCCESS != status) {
  968. leave;
  969. }
  970. //
  971. // See if correct type of data, if not, assume NOT doing all paths
  972. //
  973. if (dataType != REG_SZ) {
  974. leave;
  975. }
  976. //
  977. // Set appropriate state based on value
  978. doAllPaths = (wcstol( data, &endptr, 10 ) != 0);
  979. } finally {
  980. printf( (doAllPaths) ?
  981. "The \"Groveler\" will monitor all directories on all SIS configured volumes.\n" :
  982. "The \"Groveler\" will only monitor the RIS directory tree on the RIS volume.\n" );
  983. }
  984. //
  985. // Get RIS Path value
  986. //
  987. try {
  988. //
  989. // Get the path to grovel
  990. //
  991. status = GetRegistryValue( TftpdServiceParameters,
  992. DirectoryStr,
  993. &dataType,
  994. data,
  995. sizeof(data),
  996. &dataSize );
  997. if (ERROR_SUCCESS != status) {
  998. leave;
  999. }
  1000. //
  1001. // See if correct type of data, if not, assume NOT doing all paths
  1002. //
  1003. if (dataType != REG_SZ) {
  1004. leave;
  1005. }
  1006. if (dataSize > 0) {
  1007. hasPath = TRUE;
  1008. }
  1009. } finally {
  1010. printf( "The RIS volume and directory to monitor is: \"%S\"\n",
  1011. (hasPath) ? data : L"<Unknown>" );
  1012. }
  1013. //
  1014. // Display correct message
  1015. //
  1016. }
  1017. void
  1018. SetupOsVersion(
  1019. void
  1020. )
  1021. {
  1022. OSVERSIONINFOEX versionInfo;
  1023. ULONGLONG conditionMask = 0;
  1024. versionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
  1025. versionInfo.dwMajorVersion = 5;
  1026. versionInfo.dwMinorVersion = 1; //testing to see if Whistler or later
  1027. VER_SET_CONDITION( conditionMask, VER_MAJORVERSION, VER_GREATER_EQUAL );
  1028. VER_SET_CONDITION( conditionMask, VER_MINORVERSION, VER_GREATER_EQUAL );
  1029. if (VerifyVersionInfo( &versionInfo,
  1030. (VER_MAJORVERSION | VER_MINORVERSION),
  1031. conditionMask ))
  1032. {
  1033. printf("Running on Windows XP or later\n");
  1034. IsWhistlerOrLater = TRUE;
  1035. }
  1036. }
  1037. //
  1038. // Main FUNCTION
  1039. //
  1040. void __cdecl
  1041. wmain(
  1042. int argc,
  1043. wchar_t *argv[])
  1044. /*++
  1045. Routine Description:
  1046. This is the program entry point and main processing routine for the
  1047. installation console mode application.
  1048. Arguments:
  1049. argc - The count of arguments passed into the command line.
  1050. argv - Array of arguments passed into the command line.
  1051. Return Value:
  1052. None.
  1053. --*/
  1054. {
  1055. wchar_t *param;
  1056. # define OP_UNKNOWN 0
  1057. # define OP_CREATE 1
  1058. # define OP_DELETE 2
  1059. int operation = OP_UNKNOWN;
  1060. int servicesState = OP_UNKNOWN;
  1061. int i;
  1062. DWORD status;
  1063. BOOL getRISPath = FALSE;
  1064. //
  1065. // Handle different OS versions
  1066. //
  1067. SetupOsVersion();
  1068. //
  1069. // Obtain a handle to the service control manager requesting all access
  1070. //
  1071. scm = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
  1072. //
  1073. // Verify that a handle could be obtained.
  1074. //
  1075. if (!scm) {
  1076. //
  1077. // A handle could not be obtained, report error.
  1078. //
  1079. DisplayError(GetLastError(),
  1080. "The Service Control Manager could not be opened, ");
  1081. return;
  1082. }
  1083. try {
  1084. //
  1085. // Parase parameters then perform the operations that we can
  1086. //
  1087. for (i=1; i < argc; i++) {
  1088. param = argv[i];
  1089. //
  1090. // See if a SWITCH
  1091. //
  1092. if ((param[0] == '-') || (param[0] == '/')) {
  1093. //
  1094. // We have a switch header, make sure it is 1 character long
  1095. //
  1096. if (param[2] != 0) {
  1097. DisplayError(ERROR_INVALID_PARAMETER,
  1098. "Parsing \"%S\", ",
  1099. param);
  1100. DisplayUsage();
  1101. leave;
  1102. }
  1103. //
  1104. // Figure out the switch
  1105. //
  1106. switch (param[1]) {
  1107. case L'?':
  1108. case L'h':
  1109. case L'H':
  1110. DisplayUsage();
  1111. leave;
  1112. case L'i':
  1113. case L'I':
  1114. operation = OP_CREATE;
  1115. break;
  1116. case L'u':
  1117. case L'U':
  1118. operation = OP_DELETE;
  1119. break;
  1120. case L'n':
  1121. case L'N':
  1122. MakeCommonStoreDirHidden = FALSE;
  1123. break;
  1124. case L'a':
  1125. case L'A':
  1126. UseSystemACL = FALSE;
  1127. break;
  1128. case L'g':
  1129. case L'G':
  1130. ForceGrovelAllPaths = TRUE;
  1131. break;
  1132. case L'r':
  1133. case L'R':
  1134. ForceGrovelRISOnly = TRUE;
  1135. break;
  1136. case L'p':
  1137. case L'P':
  1138. SetRISPath = TRUE;
  1139. getRISPath = TRUE; //the path is the next parameter
  1140. break;
  1141. case L's':
  1142. case L'S':
  1143. DisplayGrovelerRISState();
  1144. leave;
  1145. default:
  1146. DisplayError( ERROR_INVALID_PARAMETER,
  1147. "Parsing \"%S\", ",
  1148. param);
  1149. DisplayUsage();
  1150. leave;
  1151. }
  1152. } else if (getRISPath) {
  1153. printf("param=\"%S\", #chars=%d\n",param,wcslen(param));
  1154. wcscpy( RISPath, param );
  1155. getRISPath = FALSE;
  1156. } else {
  1157. //
  1158. // Execute the given operation
  1159. //
  1160. switch (operation) {
  1161. case OP_CREATE:
  1162. if (servicesState != OP_CREATE) {
  1163. status = CreateServices();
  1164. if (ERROR_SUCCESS != status) {
  1165. goto Cleanup;
  1166. }
  1167. servicesState = OP_CREATE;
  1168. }
  1169. status = InitVolume(param);
  1170. if (ERROR_SUCCESS != status) {
  1171. goto Cleanup;
  1172. }
  1173. SetRegistryValues();
  1174. DisplayGrovelerRISState();
  1175. break;
  1176. case OP_DELETE:
  1177. if (servicesState != OP_DELETE) {
  1178. status = DeleteServices();
  1179. if (ERROR_SUCCESS != status) {
  1180. goto Cleanup;
  1181. }
  1182. servicesState = OP_DELETE;
  1183. }
  1184. // status = CleanupVolume(param);
  1185. // if (ERROR_SUCCESS != status) {
  1186. //
  1187. // goto Cleanup;
  1188. // }
  1189. break;
  1190. }
  1191. }
  1192. }
  1193. if (getRISPath) {
  1194. DisplayError( ERROR_INVALID_PARAMETER,
  1195. "Parsing \"%S\", ",
  1196. argv[i-1]);
  1197. DisplayUsage();
  1198. leave;
  1199. }
  1200. //
  1201. // See if any operation was performed. If not then no drive letter
  1202. // was specified, so do what ever operation they said without a
  1203. // drive letter.
  1204. //
  1205. if (servicesState == OP_UNKNOWN) {
  1206. switch (operation) {
  1207. case OP_UNKNOWN:
  1208. SetRegistryValues();
  1209. DisplayGrovelerRISState();
  1210. break;
  1211. case OP_CREATE:
  1212. CreateServices();
  1213. SetRegistryValues();
  1214. DisplayGrovelerRISState();
  1215. break;
  1216. case OP_DELETE:
  1217. DeleteServices();
  1218. break;
  1219. }
  1220. }
  1221. Cleanup: ;
  1222. } finally {
  1223. CloseServiceHandle(scm);
  1224. }
  1225. }