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

1934 lines
48 KiB

  1. #include "setupp.h"
  2. #pragma hdrstop
  3. //
  4. // Safe boot strings
  5. //
  6. #define SAFEBOOT_OPTION_KEY TEXT("System\\CurrentControlSet\\Control\\SafeBoot\\Option")
  7. #define OPTION_VALUE TEXT("OptionValue")
  8. VOID
  9. SetUpProductTypeName(
  10. OUT PWSTR ProductTypeString,
  11. IN UINT BufferSizeChars
  12. )
  13. {
  14. switch(ProductType) {
  15. case PRODUCT_WORKSTATION:
  16. lstrcpyn(ProductTypeString,L"WinNT",BufferSizeChars);
  17. break;
  18. case PRODUCT_SERVER_PRIMARY:
  19. lstrcpyn(ProductTypeString,L"LanmanNT",BufferSizeChars);
  20. break;
  21. case PRODUCT_SERVER_STANDALONE:
  22. lstrcpyn(ProductTypeString,L"ServerNT",BufferSizeChars);
  23. break;
  24. default:
  25. LoadString(MyModuleHandle,IDS_UNKNOWN,ProductTypeString,BufferSizeChars);
  26. break;
  27. }
  28. }
  29. HMODULE
  30. MyLoadLibraryWithSignatureCheck(
  31. IN PWSTR ModuleName
  32. )
  33. /*++
  34. Routine Description:
  35. verifies the signature for a dll and if it's ok, then load the dll
  36. Arguments:
  37. ModuleName - filename to be loaded.
  38. Return Value:
  39. an HMODULE on success, else NULL
  40. --*/
  41. {
  42. WCHAR FullModuleName[MAX_PATH];
  43. PWSTR p;
  44. DWORD error;
  45. if (!GetFullPathName(ModuleName,MAX_PATH,FullModuleName,&p)) {
  46. //
  47. // couldn't get full path to file
  48. //
  49. SetupDebugPrint1( L"Setup: MyLoadLibraryWithSignatureCheck failed GetFullPathName, le = %d\n",
  50. GetLastError() );
  51. return NULL;
  52. }
  53. error = pSetupVerifyFile(
  54. NULL,
  55. NULL,
  56. NULL,
  57. 0,
  58. pSetupGetFileTitle(FullModuleName),
  59. FullModuleName,
  60. NULL,
  61. NULL,
  62. FALSE,
  63. NULL,
  64. NULL,
  65. NULL );
  66. if (NO_ERROR != error) {
  67. //
  68. // signing problem
  69. //
  70. SetupDebugPrint1( L"Setup: MyLoadLibraryWithSignatureCheck failed pSetupVerifyFile, le = %x\n",
  71. error );
  72. SetLastError(error);
  73. return NULL;
  74. }
  75. return (LoadLibrary(FullModuleName));
  76. }
  77. UINT
  78. MyGetDriveType(
  79. IN WCHAR Drive
  80. )
  81. {
  82. WCHAR DriveNameNt[] = L"\\\\.\\?:";
  83. WCHAR DriveName[] = L"?:\\";
  84. HANDLE hDisk;
  85. BOOL b;
  86. UINT rc;
  87. DWORD DataSize;
  88. DISK_GEOMETRY MediaInfo;
  89. //
  90. // First, get the win32 drive type. If it tells us DRIVE_REMOVABLE,
  91. // then we need to see whether it's a floppy or hard disk. Otherwise
  92. // just believe the api.
  93. //
  94. DriveName[0] = Drive;
  95. if((rc = GetDriveType(DriveName)) == DRIVE_REMOVABLE) {
  96. DriveNameNt[4] = Drive;
  97. hDisk = CreateFile(
  98. DriveNameNt,
  99. FILE_READ_ATTRIBUTES,
  100. FILE_SHARE_READ | FILE_SHARE_WRITE,
  101. NULL,
  102. OPEN_EXISTING,
  103. 0,
  104. NULL
  105. );
  106. if(hDisk != INVALID_HANDLE_VALUE) {
  107. b = DeviceIoControl(
  108. hDisk,
  109. IOCTL_DISK_GET_DRIVE_GEOMETRY,
  110. NULL,
  111. 0,
  112. &MediaInfo,
  113. sizeof(MediaInfo),
  114. &DataSize,
  115. NULL
  116. );
  117. //
  118. // It's really a hard disk if the media type is removable.
  119. //
  120. if(b && (MediaInfo.MediaType == RemovableMedia)) {
  121. rc = DRIVE_FIXED;
  122. }
  123. CloseHandle(hDisk);
  124. }
  125. }
  126. return(rc);
  127. }
  128. BOOL
  129. GetPartitionInfo(
  130. IN WCHAR Drive,
  131. OUT PPARTITION_INFORMATION PartitionInfo
  132. )
  133. {
  134. WCHAR DriveName[] = L"\\\\.\\?:";
  135. HANDLE hDisk;
  136. BOOL b;
  137. DWORD DataSize;
  138. DriveName[4] = Drive;
  139. hDisk = CreateFile(
  140. DriveName,
  141. GENERIC_READ,
  142. FILE_SHARE_READ | FILE_SHARE_WRITE,
  143. NULL,
  144. OPEN_EXISTING,
  145. 0,
  146. NULL
  147. );
  148. if(hDisk == INVALID_HANDLE_VALUE) {
  149. return(FALSE);
  150. }
  151. b = DeviceIoControl(
  152. hDisk,
  153. IOCTL_DISK_GET_PARTITION_INFO,
  154. NULL,
  155. 0,
  156. PartitionInfo,
  157. sizeof(PARTITION_INFORMATION),
  158. &DataSize,
  159. NULL
  160. );
  161. CloseHandle(hDisk);
  162. return(b);
  163. }
  164. BOOL
  165. IsErrorLogEmpty (
  166. VOID
  167. )
  168. /*++
  169. Routine Description:
  170. Checks to see if the error log is empty.
  171. Arguments:
  172. None.
  173. Returns:
  174. TRUE if the error log size is zero.
  175. --*/
  176. {
  177. HANDLE ErrorLog;
  178. WCHAR LogName[MAX_PATH];
  179. DWORD Size = 0;
  180. if( GetWindowsDirectory (LogName, MAX_PATH) ) {
  181. pSetupConcatenatePaths (LogName, SETUPLOG_ERROR_FILENAME, MAX_PATH, NULL);
  182. ErrorLog = CreateFile (
  183. LogName,
  184. GENERIC_READ,
  185. FILE_SHARE_READ | FILE_SHARE_WRITE,
  186. NULL,
  187. OPEN_EXISTING,
  188. FILE_ATTRIBUTE_NORMAL,
  189. NULL
  190. );
  191. if (ErrorLog != INVALID_HANDLE_VALUE) {
  192. Size = GetFileSize (ErrorLog, NULL);
  193. CloseHandle (ErrorLog);
  194. }
  195. }
  196. return Size == 0;
  197. }
  198. VOID
  199. PumpMessageQueue(
  200. VOID
  201. )
  202. {
  203. MSG msg;
  204. while(PeekMessage(&msg,NULL,0,0,PM_REMOVE)) {
  205. DispatchMessage(&msg);
  206. }
  207. }
  208. PVOID
  209. InitSysSetupQueueCallbackEx(
  210. IN HWND OwnerWindow,
  211. IN HWND AlternateProgressWindow, OPTIONAL
  212. IN UINT ProgressMessage,
  213. IN DWORD Reserved1,
  214. IN PVOID Reserved2
  215. )
  216. {
  217. PSYSSETUP_QUEUE_CONTEXT SysSetupContext;
  218. SysSetupContext = MyMalloc(sizeof(SYSSETUP_QUEUE_CONTEXT));
  219. if(SysSetupContext) {
  220. SysSetupContext->Skipped = FALSE;
  221. SysSetupContext->DefaultContext = SetupInitDefaultQueueCallbackEx(
  222. OwnerWindow,
  223. AlternateProgressWindow,
  224. ProgressMessage,
  225. Reserved1,
  226. Reserved2
  227. );
  228. }
  229. return SysSetupContext;
  230. }
  231. PVOID
  232. InitSysSetupQueueCallback(
  233. IN HWND OwnerWindow
  234. )
  235. {
  236. return(InitSysSetupQueueCallbackEx(OwnerWindow,NULL,0,0,NULL));
  237. }
  238. VOID
  239. TermSysSetupQueueCallback(
  240. IN PVOID SysSetupContext
  241. )
  242. {
  243. PSYSSETUP_QUEUE_CONTEXT Context = SysSetupContext;
  244. try {
  245. if(Context->DefaultContext) {
  246. SetupTermDefaultQueueCallback(Context->DefaultContext);
  247. }
  248. MyFree(Context);
  249. } except(EXCEPTION_EXECUTE_HANDLER) {
  250. ;
  251. }
  252. }
  253. #if 0
  254. UINT
  255. VersionCheckQueueCallback(
  256. IN PVOID Context,
  257. IN UINT Notification,
  258. IN UINT_PTR Param1,
  259. IN UINT_PTR Param2
  260. )
  261. {
  262. PFILEPATHS FilePaths = (PFILEPATHS)Param1;
  263. //
  264. // If we're being notified that a version mismatch was found,
  265. // indicate that the file shouldn't be copied. Otherwise,
  266. // pass the notification on.
  267. //
  268. if((Notification & (SPFILENOTIFY_LANGMISMATCH |
  269. SPFILENOTIFY_TARGETNEWER |
  270. SPFILENOTIFY_TARGETEXISTS)) != 0) {
  271. SetuplogError(
  272. LogSevInformation,
  273. SETUPLOG_USE_MESSAGEID,
  274. , // MSG_LOG_VERSION_MISMATCH, This message is no longer appropriate.
  275. FilePaths->Source,
  276. FilePaths->Target,
  277. NULL,NULL);
  278. return(0);
  279. }
  280. //
  281. // Want default processing.
  282. //
  283. return(SysSetupQueueCallback(Context,Notification,Param1,Param2));
  284. }
  285. #endif
  286. UINT
  287. SysSetupQueueCallback(
  288. IN PVOID Context,
  289. IN UINT Notification,
  290. IN UINT_PTR Param1,
  291. IN UINT_PTR Param2
  292. )
  293. {
  294. UINT Status;
  295. PSYSSETUP_QUEUE_CONTEXT SysSetupContext = Context;
  296. PFILEPATHS FilePaths = (PFILEPATHS)Param1;
  297. PSOURCE_MEDIA SourceMedia = (PSOURCE_MEDIA)Param1;
  298. REGISTRATION_CONTEXT RegistrationContext;
  299. //
  300. // If we're being notified that a file is missing and we're supposed
  301. // to skip missing files, then return skip. Otherwise pass it on
  302. // to the default callback routine.
  303. //
  304. if(( (Notification == SPFILENOTIFY_COPYERROR) || (Notification == SPFILENOTIFY_NEEDMEDIA) ) && SkipMissingFiles) {
  305. if((FilePaths->Win32Error == ERROR_FILE_NOT_FOUND)
  306. || (FilePaths->Win32Error == ERROR_PATH_NOT_FOUND)) {
  307. if(Notification == SPFILENOTIFY_COPYERROR)
  308. SetuplogError(
  309. LogSevWarning,
  310. SETUPLOG_USE_MESSAGEID,
  311. MSG_LOG_FILE_COPY_ERROR,
  312. FilePaths->Source,
  313. FilePaths->Target, NULL,
  314. SETUPLOG_USE_MESSAGEID,
  315. FilePaths->Win32Error,
  316. NULL,NULL);
  317. else
  318. SetuplogError(
  319. LogSevError,
  320. SETUPLOG_USE_MESSAGEID,
  321. MSG_LOG_NEEDMEDIA_SKIP,
  322. SourceMedia->SourceFile,
  323. SourceMedia->SourcePath,
  324. NULL,NULL);
  325. return(FILEOP_SKIP);
  326. }
  327. }
  328. if ((Notification == SPFILENOTIFY_COPYERROR
  329. || Notification == SPFILENOTIFY_RENAMEERROR
  330. || Notification == SPFILENOTIFY_DELETEERROR) &&
  331. (FilePaths->Win32Error == ERROR_DIRECTORY)) {
  332. WCHAR Buffer[MAX_PATH];
  333. PWSTR p;
  334. //
  335. // The target directory has been converted into a file by autochk.
  336. // just delete it -- we might be in trouble if the target directory was
  337. // really important, but it's worth trying
  338. //
  339. wcscpy( Buffer,FilePaths->Target);
  340. p = wcsrchr(Buffer,L'\\');
  341. if (p) {
  342. *p = (WCHAR)NULL;
  343. }
  344. if (FileExists(Buffer,NULL)) {
  345. DeleteFile( Buffer );
  346. SetupDebugPrint1(L"autochk turned directory %s into file, delete file and retry\n", Buffer);
  347. return(FILEOP_RETRY);
  348. }
  349. }
  350. //
  351. // If we're being notified that a version mismatch was found,
  352. // silently overwrite the file. Otherwise, pass the notification on.
  353. //
  354. if((Notification & (SPFILENOTIFY_LANGMISMATCH |
  355. SPFILENOTIFY_TARGETNEWER |
  356. SPFILENOTIFY_TARGETEXISTS)) != 0) {
  357. SetuplogError(
  358. LogSevInformation,
  359. SETUPLOG_USE_MESSAGEID,
  360. MSG_LOG_VERSION_MISMATCH,
  361. FilePaths->Source,
  362. FilePaths->Target,
  363. NULL,NULL);
  364. return(FILEOP_DOIT);
  365. }
  366. //
  367. // Use default processing, then check for errors.
  368. //
  369. Status = SetupDefaultQueueCallback(
  370. SysSetupContext->DefaultContext,Notification,Param1,Param2);
  371. switch(Notification) {
  372. case SPFILENOTIFY_STARTQUEUE:
  373. case SPFILENOTIFY_STARTSUBQUEUE:
  374. case SPFILENOTIFY_ENDSUBQUEUE:
  375. //
  376. // Nothing is logged in this case.
  377. //
  378. break;
  379. case SPFILENOTIFY_ENDQUEUE:
  380. if(!Param1) {
  381. SetuplogError(
  382. LogSevInformation,
  383. SETUPLOG_USE_MESSAGEID,
  384. MSG_LOG_QUEUE_ABORT, NULL,
  385. SETUPLOG_USE_MESSAGEID,
  386. GetLastError(),
  387. NULL,NULL);
  388. }
  389. break;
  390. case SPFILENOTIFY_STARTRENAME:
  391. if(Status == FILEOP_SKIP) {
  392. SysSetupContext->Skipped = TRUE;
  393. } else {
  394. SysSetupContext->Skipped = FALSE;
  395. }
  396. break;
  397. case SPFILENOTIFY_ENDRENAME:
  398. if(FilePaths->Win32Error == NO_ERROR &&
  399. !SysSetupContext->Skipped) {
  400. SetuplogError(
  401. LogSevInformation,
  402. SETUPLOG_USE_MESSAGEID,
  403. MSG_LOG_FILE_RENAMED,
  404. FilePaths->Source,
  405. FilePaths->Target,
  406. NULL,NULL);
  407. } else {
  408. SetuplogError(
  409. LogSevError,
  410. SETUPLOG_USE_MESSAGEID,
  411. MSG_LOG_FILE_RENAME_ERROR,
  412. FilePaths->Source,
  413. FilePaths->Target, NULL,
  414. SETUPLOG_USE_MESSAGEID,
  415. FilePaths->Win32Error == NO_ERROR ?
  416. MSG_LOG_USER_SKIP :
  417. FilePaths->Win32Error,
  418. NULL,NULL);
  419. }
  420. break;
  421. case SPFILENOTIFY_RENAMEERROR:
  422. if(Status == FILEOP_SKIP) {
  423. SysSetupContext->Skipped = TRUE;
  424. }
  425. break;
  426. case SPFILENOTIFY_STARTDELETE:
  427. if(Status == FILEOP_SKIP) {
  428. SysSetupContext->Skipped = TRUE;
  429. } else {
  430. SysSetupContext->Skipped = FALSE;
  431. }
  432. break;
  433. case SPFILENOTIFY_ENDDELETE:
  434. if(FilePaths->Win32Error == NO_ERROR &&
  435. !SysSetupContext->Skipped) {
  436. SetuplogError(
  437. LogSevInformation,
  438. SETUPLOG_USE_MESSAGEID,
  439. MSG_LOG_FILE_DELETED,
  440. FilePaths->Target,
  441. NULL,NULL);
  442. } else if(FilePaths->Win32Error == ERROR_FILE_NOT_FOUND ||
  443. FilePaths->Win32Error == ERROR_PATH_NOT_FOUND) {
  444. //
  445. // This failure is not important.
  446. //
  447. SetuplogError(
  448. LogSevInformation,
  449. SETUPLOG_USE_MESSAGEID,
  450. MSG_LOG_FILE_DELETE_ERROR,
  451. FilePaths->Target, NULL,
  452. SETUPLOG_USE_MESSAGEID,
  453. FilePaths->Win32Error,
  454. NULL,NULL);
  455. } else {
  456. //
  457. // Here we have an actual error.
  458. //
  459. SetuplogError(
  460. LogSevError,
  461. SETUPLOG_USE_MESSAGEID,
  462. MSG_LOG_FILE_DELETE_ERROR,
  463. FilePaths->Target, NULL,
  464. SETUPLOG_USE_MESSAGEID,
  465. FilePaths->Win32Error == NO_ERROR ?
  466. MSG_LOG_USER_SKIP :
  467. FilePaths->Win32Error,
  468. NULL,NULL);
  469. }
  470. break;
  471. case SPFILENOTIFY_DELETEERROR:
  472. if(Status == FILEOP_SKIP) {
  473. SysSetupContext->Skipped = TRUE;
  474. }
  475. break;
  476. case SPFILENOTIFY_STARTCOPY:
  477. if(Status == FILEOP_SKIP) {
  478. SysSetupContext->Skipped = TRUE;
  479. } else {
  480. SysSetupContext->Skipped = FALSE;
  481. }
  482. break;
  483. case SPFILENOTIFY_ENDCOPY:
  484. if(FilePaths->Win32Error == NO_ERROR &&
  485. !SysSetupContext->Skipped) {
  486. LogRepairInfo(
  487. FilePaths->Source,
  488. FilePaths->Target
  489. );
  490. SetuplogError(
  491. LogSevInformation,
  492. SETUPLOG_USE_MESSAGEID,
  493. MSG_LOG_FILE_COPIED,
  494. FilePaths->Source,
  495. FilePaths->Target,
  496. NULL,NULL);
  497. //
  498. // clear the file's readonly attribute that it may have gotten
  499. // from the cdrom.
  500. //
  501. SetFileAttributes(
  502. FilePaths->Target,
  503. GetFileAttributes(FilePaths->Target) & ~FILE_ATTRIBUTE_READONLY );
  504. } else {
  505. SetuplogError(
  506. LogSevError,
  507. SETUPLOG_USE_MESSAGEID,
  508. MSG_LOG_FILE_COPY_ERROR,
  509. FilePaths->Source,
  510. FilePaths->Target, NULL,
  511. SETUPLOG_USE_MESSAGEID,
  512. FilePaths->Win32Error == NO_ERROR ?
  513. MSG_LOG_USER_SKIP :
  514. FilePaths->Win32Error,
  515. NULL,NULL);
  516. }
  517. break;
  518. case SPFILENOTIFY_COPYERROR:
  519. if(Status == FILEOP_SKIP) {
  520. SysSetupContext->Skipped = TRUE;
  521. }
  522. break;
  523. case SPFILENOTIFY_NEEDMEDIA:
  524. if(Status == FILEOP_SKIP) {
  525. SetuplogError(
  526. LogSevError,
  527. SETUPLOG_USE_MESSAGEID,
  528. MSG_LOG_NEEDMEDIA_SKIP,
  529. SourceMedia->SourceFile,
  530. SourceMedia->SourcePath,
  531. NULL,NULL);
  532. SysSetupContext->Skipped = TRUE;
  533. }
  534. break;
  535. case SPFILENOTIFY_STARTREGISTRATION:
  536. case SPFILENOTIFY_ENDREGISTRATION:
  537. RtlZeroMemory(&RegistrationContext,sizeof(RegistrationContext));
  538. RegistrationQueueCallback(
  539. &RegistrationContext,
  540. Notification,
  541. Param1,
  542. Param2);
  543. break;
  544. default:
  545. break;
  546. }
  547. return Status;
  548. }
  549. PSID
  550. GetAdminAccountSid(
  551. )
  552. /*++
  553. ===============================================================================
  554. Routine Description:
  555. This routine gets the Adminstrator's SID
  556. Arguments:
  557. None.
  558. Return Value:
  559. TRUE - success.
  560. FALSE - failed.
  561. ===============================================================================
  562. --*/
  563. {
  564. BOOL b = TRUE;
  565. LSA_HANDLE hPolicy;
  566. NTSTATUS ntStatus;
  567. OBJECT_ATTRIBUTES ObjectAttributes;
  568. PPOLICY_ACCOUNT_DOMAIN_INFO AccountDomainInfo = NULL;
  569. UCHAR SubAuthCount;
  570. DWORD sidlen;
  571. PSID psid = NULL;
  572. InitializeObjectAttributes( &ObjectAttributes,
  573. NULL,
  574. 0L,
  575. NULL,
  576. NULL );
  577. ntStatus = LsaOpenPolicy( NULL,
  578. &ObjectAttributes,
  579. POLICY_ALL_ACCESS,
  580. &hPolicy );
  581. if (!NT_SUCCESS(ntStatus)) {
  582. LsaClose(hPolicy);
  583. b = FALSE;
  584. }
  585. if( b ) {
  586. ntStatus = LsaQueryInformationPolicy( hPolicy,
  587. PolicyAccountDomainInformation,
  588. (PVOID *) &AccountDomainInfo );
  589. LsaClose( hPolicy );
  590. if (!NT_SUCCESS(ntStatus)) {
  591. if ( AccountDomainInfo != NULL ) {
  592. (VOID) LsaFreeMemory( AccountDomainInfo );
  593. }
  594. b = FALSE;
  595. }
  596. }
  597. if( b ) {
  598. //
  599. // calculate the size of a new sid with one more SubAuthority
  600. //
  601. SubAuthCount = *(GetSidSubAuthorityCount ( AccountDomainInfo->DomainSid ));
  602. SubAuthCount++; // for admin
  603. sidlen = GetSidLengthRequired ( SubAuthCount );
  604. //
  605. // allocate and copy the new new sid from the Domain SID
  606. //
  607. psid = (PSID)malloc(sidlen);
  608. if( psid ) {
  609. memcpy(psid, AccountDomainInfo->DomainSid, GetLengthSid(AccountDomainInfo->DomainSid) );
  610. //
  611. // increment SubAuthority count and add Domain Admin RID
  612. //
  613. *(GetSidSubAuthorityCount( psid )) = SubAuthCount;
  614. *(GetSidSubAuthority( psid, SubAuthCount-1 )) = DOMAIN_USER_RID_ADMIN;
  615. if ( AccountDomainInfo != NULL ) {
  616. (VOID) LsaFreeMemory( AccountDomainInfo );
  617. }
  618. }
  619. }
  620. return psid;
  621. }
  622. VOID
  623. GetAdminAccountName(
  624. PWSTR AccountName
  625. )
  626. /*++
  627. ===============================================================================
  628. Routine Description:
  629. This routine sets the Adminstrator Password
  630. Arguments:
  631. None.
  632. Return Value:
  633. TRUE - success.
  634. FALSE - failed.
  635. ===============================================================================
  636. --*/
  637. {
  638. BOOL b = TRUE;
  639. LSA_HANDLE hPolicy;
  640. NTSTATUS ntStatus;
  641. OBJECT_ATTRIBUTES ObjectAttributes;
  642. PPOLICY_ACCOUNT_DOMAIN_INFO AccountDomainInfo = NULL;
  643. UCHAR SubAuthCount;
  644. DWORD sidlen;
  645. PSID psid;
  646. WCHAR adminname[512];
  647. WCHAR domainname[512];
  648. DWORD adminlen=512; // address of size account string
  649. DWORD domlen=512; // address of size account string
  650. SID_NAME_USE sidtype;
  651. //
  652. // Initialize the administrator's account name.
  653. //
  654. LoadString(MyModuleHandle,IDS_ADMINISTRATOR,adminname,MAX_USERNAME+1);
  655. InitializeObjectAttributes( &ObjectAttributes,
  656. NULL,
  657. 0L,
  658. NULL,
  659. NULL );
  660. ntStatus = LsaOpenPolicy( NULL,
  661. &ObjectAttributes,
  662. POLICY_ALL_ACCESS,
  663. &hPolicy );
  664. if (!NT_SUCCESS(ntStatus)) {
  665. LsaClose(hPolicy);
  666. b = FALSE;
  667. }
  668. if( b ) {
  669. ntStatus = LsaQueryInformationPolicy( hPolicy,
  670. PolicyAccountDomainInformation,
  671. (PVOID *) &AccountDomainInfo );
  672. LsaClose( hPolicy );
  673. if (!NT_SUCCESS(ntStatus)) {
  674. if ( AccountDomainInfo != NULL ) {
  675. (VOID) LsaFreeMemory( AccountDomainInfo );
  676. }
  677. b = FALSE;
  678. }
  679. }
  680. if( b ) {
  681. //
  682. // calculate the size of a new sid with one more SubAuthority
  683. //
  684. SubAuthCount = *(GetSidSubAuthorityCount ( AccountDomainInfo->DomainSid ));
  685. SubAuthCount++; // for admin
  686. sidlen = GetSidLengthRequired ( SubAuthCount );
  687. //
  688. // allocate and copy the new new sid from the Domain SID
  689. //
  690. psid = (PSID)malloc(sidlen);
  691. if (psid) {
  692. memcpy(psid, AccountDomainInfo->DomainSid, GetLengthSid(AccountDomainInfo->DomainSid) );
  693. //
  694. // increment SubAuthority count and add Domain Admin RID
  695. //
  696. *(GetSidSubAuthorityCount( psid )) = SubAuthCount;
  697. *(GetSidSubAuthority( psid, SubAuthCount-1 )) = DOMAIN_USER_RID_ADMIN;
  698. if ( AccountDomainInfo != NULL ) {
  699. (VOID) LsaFreeMemory( AccountDomainInfo );
  700. }
  701. //
  702. // get the admin account name from the new SID
  703. //
  704. LookupAccountSid( NULL,
  705. psid,
  706. adminname,
  707. &adminlen,
  708. domainname,
  709. &domlen,
  710. &sidtype );
  711. }
  712. }
  713. lstrcpy( AccountName, adminname );
  714. if (psid) {
  715. free(psid);
  716. }
  717. }
  718. ULONG
  719. GetBatteryTag (HANDLE DriverHandle)
  720. {
  721. NTSTATUS Status;
  722. IO_STATUS_BLOCK IOSB;
  723. ULONG BatteryTag;
  724. Status = NtDeviceIoControlFile(
  725. DriverHandle,
  726. (HANDLE) NULL, // event
  727. (PIO_APC_ROUTINE) NULL,
  728. (PVOID) NULL,
  729. &IOSB,
  730. IOCTL_BATTERY_QUERY_TAG,
  731. NULL, // input buffer
  732. 0,
  733. &BatteryTag, // output buffer
  734. sizeof (BatteryTag)
  735. );
  736. if (!NT_SUCCESS(Status)) {
  737. BatteryTag = BATTERY_TAG_INVALID;
  738. if (Status == STATUS_NO_SUCH_DEVICE) {
  739. SetupDebugPrint(L"(Battery is not physically present or is not connected)\n");
  740. } else {
  741. SetupDebugPrint1(L"Query Battery tag failed: Status = %x\n", Status);
  742. }
  743. }
  744. return BatteryTag;
  745. }
  746. BOOLEAN
  747. GetBatteryInfo (
  748. HANDLE DriverHandle,
  749. ULONG BatteryTag,
  750. IN BATTERY_QUERY_INFORMATION_LEVEL Level,
  751. OUT PVOID Buffer,
  752. IN ULONG BufferLength
  753. )
  754. {
  755. NTSTATUS Status;
  756. IO_STATUS_BLOCK IOSB;
  757. BATTERY_QUERY_INFORMATION BInfo;
  758. memset (Buffer, 0, BufferLength);
  759. BInfo.BatteryTag = BatteryTag;
  760. BInfo.InformationLevel = Level;
  761. BInfo.AtRate = 0; // This is needed for reading estimated time correctly.
  762. Status = NtDeviceIoControlFile(
  763. DriverHandle,
  764. (HANDLE) NULL, // event
  765. (PIO_APC_ROUTINE) NULL,
  766. (PVOID) NULL,
  767. &IOSB,
  768. IOCTL_BATTERY_QUERY_INFORMATION,
  769. &BInfo, // input buffer
  770. sizeof (BInfo),
  771. Buffer, // output buffer
  772. BufferLength
  773. );
  774. if (!NT_SUCCESS(Status)) {
  775. if ((Status == STATUS_INVALID_PARAMETER) ||
  776. (Status == STATUS_INVALID_DEVICE_REQUEST) ||
  777. (Status == STATUS_NOT_SUPPORTED)) {
  778. SetupDebugPrint2(L"Not Supported by Battery, Level %x, Status: %x\n", Level, Status);
  779. } else {
  780. SetupDebugPrint2(L"Query failed: Level %x, Status = %x\n", Level, Status);
  781. }
  782. return FALSE;
  783. }
  784. return TRUE;
  785. }
  786. BOOLEAN
  787. IsLongTermBattery(
  788. PCWSTR BatteryName
  789. )
  790. {
  791. HANDLE driverHandle;
  792. ULONG batteryTag;
  793. BATTERY_INFORMATION BInfo;
  794. BOOLEAN Ret;
  795. driverHandle = CreateFile (BatteryName,
  796. GENERIC_READ | GENERIC_WRITE,
  797. FILE_SHARE_READ | FILE_SHARE_WRITE,
  798. NULL,
  799. OPEN_EXISTING,
  800. FILE_ATTRIBUTE_NORMAL,
  801. NULL);
  802. if (INVALID_HANDLE_VALUE == driverHandle) {
  803. SetupDebugPrint2(L"Error opening %ws: GetLastError = 0x%08lx \n",
  804. BatteryName, GetLastError());
  805. return FALSE;
  806. }
  807. batteryTag = GetBatteryTag (driverHandle);
  808. if (batteryTag == BATTERY_TAG_INVALID) {
  809. NtClose(driverHandle);
  810. return FALSE;
  811. }
  812. if (GetBatteryInfo (driverHandle, batteryTag, BatteryInformation, &BInfo, sizeof(BInfo))) {
  813. Ret = !(BInfo.Capabilities & BATTERY_IS_SHORT_TERM);
  814. } else {
  815. Ret = FALSE;
  816. }
  817. NtClose(driverHandle);
  818. return(Ret);
  819. }
  820. BOOLEAN
  821. IsLaptop(
  822. VOID
  823. )
  824. {
  825. HDEVINFO devInfo;
  826. SP_INTERFACE_DEVICE_DATA interfaceDevData;
  827. PSP_INTERFACE_DEVICE_DETAIL_DATA funcClassDevData;
  828. UCHAR index;
  829. DWORD reqSize;
  830. BOOLEAN b = FALSE;
  831. devInfo = SetupDiGetClassDevs((LPGUID)&GUID_DEVICE_BATTERY, NULL, NULL,
  832. DIGCF_PRESENT | DIGCF_INTERFACEDEVICE);
  833. if (devInfo == INVALID_HANDLE_VALUE) {
  834. SetupDebugPrint1(L"SetupDiGetClassDevs on GUID_DEVICE_BATTERY, failed: %d\n", GetLastError());
  835. return FALSE;
  836. }
  837. interfaceDevData.cbSize = sizeof(SP_DEVINFO_DATA);
  838. index = 0;
  839. while(1) {
  840. if (SetupDiEnumInterfaceDevice(devInfo,
  841. 0,
  842. (LPGUID)&GUID_DEVICE_BATTERY,
  843. index,
  844. &interfaceDevData)) {
  845. // Get the required size of the function class device data.
  846. SetupDiGetInterfaceDeviceDetail(devInfo,
  847. &interfaceDevData,
  848. NULL,
  849. 0,
  850. &reqSize,
  851. NULL);
  852. funcClassDevData = MyMalloc(reqSize);
  853. if (funcClassDevData != NULL) {
  854. funcClassDevData->cbSize =
  855. sizeof(SP_INTERFACE_DEVICE_DETAIL_DATA);
  856. if (SetupDiGetInterfaceDeviceDetail(devInfo,
  857. &interfaceDevData,
  858. funcClassDevData,
  859. reqSize,
  860. &reqSize,
  861. NULL)) {
  862. b = IsLongTermBattery(funcClassDevData->DevicePath);
  863. }
  864. else {
  865. SetupDebugPrint1(L"SetupDiGetInterfaceDeviceDetail, failed: %d\n", GetLastError());
  866. }
  867. MyFree(funcClassDevData);
  868. if (b) {
  869. break;
  870. }
  871. }
  872. } else {
  873. if (ERROR_NO_MORE_ITEMS == GetLastError()) {
  874. break;
  875. }
  876. else {
  877. SetupDebugPrint1(L"SetupDiEnumInterfaceDevice, failed: %d\n", GetLastError());
  878. }
  879. }
  880. index++;
  881. }
  882. SetupDiDestroyDeviceInfoList(devInfo);
  883. return b;
  884. }
  885. VOID
  886. SaveInstallInfoIntoEventLog(
  887. VOID
  888. )
  889. /*++
  890. Routine Description:
  891. This routine will store information into the event log regarding
  892. - if we upgraded or cleaninstall
  893. - what build did the install originate from
  894. - what build are we?
  895. - were there errors during Setup
  896. Arguments:
  897. None.
  898. Return Value:
  899. None.
  900. --*/
  901. {
  902. #define AnswerBufLen (64)
  903. WCHAR AnswerFile[MAX_PATH];
  904. WCHAR Answer[AnswerBufLen];
  905. WCHAR OrigVersion[AnswerBufLen];
  906. WCHAR NewVersion[AnswerBufLen];
  907. HANDLE hEventSrc;
  908. PCWSTR MyArgs[2];
  909. PCWSTR ErrorArgs[1];
  910. DWORD MessageID;
  911. WORD MyArgCount;
  912. //
  913. // Go get the starting information out of $winnt$.sif
  914. //
  915. OrigVersion[0] = L'0';
  916. OrigVersion[1] = L'\0';
  917. GetSystemDirectory(AnswerFile,MAX_PATH);
  918. pSetupConcatenatePaths(AnswerFile,WINNT_GUI_FILE,MAX_PATH,NULL);
  919. if( GetPrivateProfileString( WINNT_DATA,
  920. WINNT_D_WIN32_VER,
  921. pwNull,
  922. Answer,
  923. AnswerBufLen,
  924. AnswerFile ) ) {
  925. if( lstrcmp( pwNull, Answer ) ) {
  926. wsprintf( OrigVersion, L"%d", HIWORD(wcstoul( Answer, NULL, 16 )) );
  927. }
  928. }
  929. MyArgs[1] = OrigVersion;
  930. //
  931. // Get the new version information.
  932. //
  933. wsprintf( NewVersion, L"%d", HIWORD(GetVersion()) );
  934. MyArgs[0] = NewVersion;
  935. //
  936. // See if we're an NT upgrade?
  937. //
  938. MessageID = 0;
  939. if( GetPrivateProfileString( WINNT_DATA,
  940. WINNT_D_NTUPGRADE,
  941. pwNo,
  942. Answer,
  943. AnswerBufLen,
  944. AnswerFile ) ) {
  945. if( !lstrcmp( pwYes, Answer ) ) {
  946. MessageID = MSG_NTUPGRADE_SUCCESS;
  947. MyArgCount = 2;
  948. }
  949. }
  950. //
  951. // See if we're a Win9X upgrade.
  952. //
  953. if( (!MessageID) &&
  954. GetPrivateProfileString( WINNT_DATA,
  955. WINNT_D_WIN95UPGRADE,
  956. pwNo,
  957. Answer,
  958. AnswerBufLen,
  959. AnswerFile ) ) {
  960. if( !lstrcmp( pwYes, Answer ) ) {
  961. MessageID = MSG_WIN9XUPGRADE_SUCCESS;
  962. MyArgCount = 2;
  963. }
  964. }
  965. //
  966. // Clean install.
  967. //
  968. if( (!MessageID) ) {
  969. MessageID = MSG_CLEANINSTALL_SUCCESS;
  970. MyArgCount = 1;
  971. }
  972. //
  973. // If this is anything but an NT upgrade, then
  974. // we need to go try and manually start the eventlog
  975. // service.
  976. //
  977. if( MessageID != MSG_NTUPGRADE_SUCCESS ) {
  978. SetupStartService( L"Eventlog", TRUE );
  979. }
  980. //
  981. // Get a handle to the eventlog.
  982. //
  983. hEventSrc = RegisterEventSource( NULL, L"Setup" );
  984. if( (hEventSrc == NULL) ||
  985. (hEventSrc == INVALID_HANDLE_VALUE) ) {
  986. //
  987. // Fail quietly.
  988. //
  989. return;
  990. }
  991. //
  992. // Log event message for failure of SceSetupRootSecurity
  993. //
  994. if( !bSceSetupRootSecurityComplete) {
  995. ErrorArgs[0] = L"%windir%";
  996. ReportEvent( hEventSrc,
  997. EVENTLOG_WARNING_TYPE,
  998. 0,
  999. MSG_LOG_SCE_SETUPROOT_ERROR,
  1000. NULL,
  1001. 1,
  1002. 0,
  1003. ErrorArgs,
  1004. NULL );
  1005. }
  1006. //
  1007. // Log event if there were errors during Setup.
  1008. //
  1009. if ( !IsErrorLogEmpty() ) {
  1010. ReportEvent( hEventSrc,
  1011. EVENTLOG_ERROR_TYPE,
  1012. 0,
  1013. MSG_NONFATAL_ERRORS,
  1014. NULL,
  1015. 0,
  1016. 0,
  1017. NULL,
  1018. NULL );
  1019. }
  1020. //
  1021. // Build the event log message.
  1022. //
  1023. ReportEvent( hEventSrc,
  1024. EVENTLOG_INFORMATION_TYPE,
  1025. 0,
  1026. MessageID,
  1027. NULL,
  1028. MyArgCount,
  1029. 0,
  1030. MyArgs,
  1031. NULL );
  1032. DeregisterEventSource( hEventSrc );
  1033. }
  1034. BOOL
  1035. IsEncryptedAdminPasswordPresent( VOID )
  1036. {
  1037. #define MD4HASHLEN ((2*(LM_OWF_PASSWORD_LENGTH + NT_OWF_PASSWORD_LENGTH))+2)
  1038. WCHAR AnswerFile[MAX_PATH+2];
  1039. WCHAR Answer[MD4HASHLEN];
  1040. //
  1041. // Get EncryptedAdminPassword from the Answer file
  1042. //
  1043. GetSystemDirectory(AnswerFile,MAX_PATH);
  1044. pSetupConcatenatePaths(AnswerFile,WINNT_GUI_FILE,MAX_PATH,NULL);
  1045. if( GetPrivateProfileString( WINNT_GUIUNATTENDED,
  1046. WINNT_US_ENCRYPTEDADMINPASS,
  1047. pwNull,
  1048. Answer,
  1049. MD4HASHLEN,
  1050. AnswerFile ) ) {
  1051. //
  1052. // See if we have an encrypted password. Now interpret the Admin Password differently
  1053. //
  1054. if( !lstrcmpi( WINNT_A_YES, Answer ) )
  1055. return TRUE;
  1056. }
  1057. return FALSE;
  1058. }
  1059. BOOL
  1060. ProcessEncryptedAdminPassword( PCWSTR AdminAccountName )
  1061. /*++
  1062. Routine Description:
  1063. This routine looks in the unattend file to see if there is an encrypted password and if present
  1064. sets the admin password to that.
  1065. Arguments:
  1066. AdminAccountName - Name of the administrator account whose password you want to set.
  1067. Returns:
  1068. Returns TRUE if it succeeds, FALSE on failure
  1069. --*/
  1070. {
  1071. #define MD4HASHLEN ((2*(LM_OWF_PASSWORD_LENGTH + NT_OWF_PASSWORD_LENGTH))+2)
  1072. WCHAR AnswerFile[MAX_PATH+2];
  1073. WCHAR Answer[MD4HASHLEN];
  1074. DWORD Err = NO_ERROR;
  1075. WCHAR adminName[MAX_USERNAME+1];
  1076. BOOLEAN ret = FALSE;
  1077. //
  1078. // Pickup the answer file.
  1079. //
  1080. GetSystemDirectory(AnswerFile,MAX_PATH);
  1081. pSetupConcatenatePaths(AnswerFile,WINNT_GUI_FILE,MAX_PATH,NULL);
  1082. //
  1083. // we look for the following keys in the [GUIUnattended] section:
  1084. //
  1085. //
  1086. // EncryptedAdminPassword = Yes | No
  1087. // AdminPassword = <MD4 Hash value>
  1088. //
  1089. if( IsEncryptedAdminPasswordPresent() ) {
  1090. //Fetch the Encrypted Admin Password
  1091. if( GetPrivateProfileString( WINNT_GUIUNATTENDED,
  1092. WINNT_US_ADMINPASS,
  1093. pwNull,
  1094. Answer,
  1095. MD4HASHLEN,
  1096. AnswerFile ) == (MD4HASHLEN-2) ) {
  1097. Err = SetLocalUserEncryptedPassword( AdminAccountName, L"", FALSE, Answer, TRUE );
  1098. if( Err == ERROR_SUCCESS) {
  1099. ret = TRUE;
  1100. }else{
  1101. //Log the error - MSG_LOG_CHANGING_ENCRYPT_PW_FAIL
  1102. SetuplogError(
  1103. LogSevWarning,
  1104. SETUPLOG_USE_MESSAGEID,
  1105. MSG_LOG_CHANGING_ENCRYPT_PW_FAIL,
  1106. AdminAccountName, NULL,
  1107. SETUPLOG_USE_MESSAGEID,
  1108. MSG_LOG_X_PARAM_RETURNED_WINERR,
  1109. L"SetLocalUserEncryptedPassword",
  1110. Err,
  1111. AdminAccountName,
  1112. NULL,NULL);
  1113. }
  1114. }else{
  1115. //Log that we had a bad encrypted password
  1116. SetuplogError(
  1117. LogSevError,
  1118. SETUPLOG_USE_MESSAGEID,
  1119. MSG_LOG_BAD_UNATTEND_PARAM,
  1120. WINNT_US_ADMINPASS,
  1121. WINNT_GUIUNATTENDED,
  1122. NULL,NULL);
  1123. }
  1124. }
  1125. return ret;
  1126. }
  1127. BOOL
  1128. FileExists(
  1129. IN PCTSTR FileName,
  1130. OUT PWIN32_FIND_DATA FindData OPTIONAL
  1131. )
  1132. /*++
  1133. Routine Description:
  1134. Determine if a file exists and is accessible.
  1135. Errormode is set (and then restored) so the user will not see
  1136. any pop-ups.
  1137. Arguments:
  1138. FileName - supplies full path of file to check for existance.
  1139. FindData - if specified, receives find data for the file.
  1140. Return Value:
  1141. TRUE if the file exists and is accessible.
  1142. FALSE if not. GetLastError() returns extended error info.
  1143. --*/
  1144. {
  1145. WIN32_FIND_DATA findData;
  1146. HANDLE FindHandle;
  1147. UINT OldMode;
  1148. DWORD Error;
  1149. OldMode = SetErrorMode(SEM_FAILCRITICALERRORS);
  1150. FindHandle = FindFirstFile(FileName,&findData);
  1151. if(FindHandle == INVALID_HANDLE_VALUE) {
  1152. Error = GetLastError();
  1153. } else {
  1154. FindClose(FindHandle);
  1155. if(FindData) {
  1156. *FindData = findData;
  1157. }
  1158. Error = NO_ERROR;
  1159. }
  1160. SetErrorMode(OldMode);
  1161. SetLastError(Error);
  1162. return (Error == NO_ERROR);
  1163. }
  1164. BOOL IsSafeMode(
  1165. VOID
  1166. )
  1167. {
  1168. LONG lStatus;
  1169. HKEY hk;
  1170. DWORD dwVal;
  1171. DWORD dwType;
  1172. DWORD dwSize;
  1173. lStatus = RegOpenKeyExW(HKEY_LOCAL_MACHINE, SAFEBOOT_OPTION_KEY, 0, KEY_QUERY_VALUE, &hk);
  1174. if(lStatus != ERROR_SUCCESS)
  1175. return FALSE;
  1176. dwSize = sizeof(dwVal);
  1177. lStatus = RegQueryValueExW(hk, OPTION_VALUE, NULL, &dwType, (LPBYTE) &dwVal, &dwSize);
  1178. RegCloseKey(hk);
  1179. return ERROR_SUCCESS == lStatus && REG_DWORD == dwType && dwVal != 0;
  1180. }
  1181. void
  1182. SetupCrashRecovery(
  1183. VOID
  1184. )
  1185. /*
  1186. Setup the Crash Recovery stuff. This is implemented as RTL APIS
  1187. This call sets up the tracking file etc. Crash Recovery tracks boot and
  1188. shutdown and in the event of failures in either it will by default pick the
  1189. right advanced boot option.
  1190. */
  1191. {
  1192. HANDLE BootStatusData;
  1193. NTSTATUS Status;
  1194. BOOLEAN Enabled;
  1195. UCHAR Timeout = 30; //default = 30 sec
  1196. WCHAR Buffer[10];
  1197. PSTR AnsiBuffer;
  1198. int p = 0;
  1199. //
  1200. // We enable the feature for Pro and Per. On Server SKUs
  1201. // we create the file but don't enable the feature by default.
  1202. //
  1203. if( ProductType == PRODUCT_WORKSTATION ){
  1204. Enabled = TRUE;
  1205. }else{
  1206. Enabled = FALSE;
  1207. }
  1208. //
  1209. // For the fresh install case create the boot status data file
  1210. // and setup the default settings. In the case of an upgrade
  1211. // we will set the previous values if we find them in $winnt$.inf
  1212. // as textmode setup would have stored this away for us. If not we
  1213. // proceed as if we were fresh.
  1214. //
  1215. if( Upgrade ){
  1216. //Look for settings in $winnt$.inf
  1217. if( SpSetupLoadParameter( WINNT_D_CRASHRECOVERYENABLED, Buffer, sizeof(Buffer)/sizeof(WCHAR))){
  1218. if (_wcsicmp(Buffer, L"NO") == 0) {
  1219. Enabled = FALSE;
  1220. }
  1221. //
  1222. //We do the below check also as we might have to migrate settings on server SKUs
  1223. //that have this enabled. By default they are disabled.
  1224. //
  1225. if (_wcsicmp(Buffer, L"YES") == 0) {
  1226. Enabled = TRUE;
  1227. }
  1228. }
  1229. }
  1230. Status = RtlLockBootStatusData( &BootStatusData );
  1231. // This is the first time or there was no file. Create it
  1232. if( !NT_SUCCESS( Status )){
  1233. Status = RtlCreateBootStatusDataFile();
  1234. if( !NT_SUCCESS( Status )){
  1235. SetuplogError(
  1236. LogSevWarning,
  1237. L"Setup: (non-critical error) Could not lock the Crash Recovery status file - (%1!x!)\n",
  1238. 0,Status,NULL,NULL);
  1239. return;
  1240. }
  1241. //Lock the file
  1242. Status = RtlLockBootStatusData( &BootStatusData );
  1243. if( !NT_SUCCESS( Status )){
  1244. SetupDebugPrint1( L"Setup: (non-critical error) Could not lock the Crash Recovery status file - (%x)\n", Status );
  1245. return;
  1246. }
  1247. Status = RtlGetSetBootStatusData(
  1248. BootStatusData,
  1249. FALSE,
  1250. RtlBsdItemAabTimeout,
  1251. &Timeout,
  1252. sizeof(UCHAR),
  1253. NULL
  1254. );
  1255. if( !NT_SUCCESS( Status )){
  1256. SetupDebugPrint1( L"Setup: (non-critical error) Could not set the Crash Recovery timeout - (%x)\n", Status );
  1257. goto SCR_done;
  1258. }
  1259. }
  1260. Status = RtlGetSetBootStatusData(
  1261. BootStatusData,
  1262. FALSE,
  1263. RtlBsdItemAabEnabled,
  1264. &Enabled,
  1265. sizeof(BOOLEAN),
  1266. NULL
  1267. );
  1268. if( !NT_SUCCESS( Status )){
  1269. SetupDebugPrint1( L"Setup: (non-critical error) Could not enable Crash Recovery - (%x)\n", Status );
  1270. }
  1271. SCR_done:
  1272. RtlUnlockBootStatusData( BootStatusData );
  1273. return;
  1274. }
  1275. DWORD
  1276. BuildFileListFromDir(
  1277. IN PCTSTR PathBase,
  1278. IN PCTSTR Directory OPTIONAL,
  1279. IN DWORD MustHaveAttrs OPTIONAL,
  1280. IN DWORD MustNotHaveAttrs OPTIONAL,
  1281. IN PFN_BUILD_FILE_LIST_CALLBACK Callback OPTIONAL,
  1282. OUT PLIST_ENTRY ListHead
  1283. )
  1284. /*++
  1285. Routine Description:
  1286. Builds a linked list containing the names (without path) of files present in a specified directory.
  1287. The files must meed a set of conditions as specified by the arguments.
  1288. Arguments:
  1289. PathBase - The path to the directory to enumerate files in.
  1290. Directory - If not NULL or empty, it is appended to PathBase to form a complete path to the directory.
  1291. MustHaveAttrs - A set of attributes a file must have to be included on the list.
  1292. MustNotHaveAttrs - A set of attributes a file must not have to be included on the list.
  1293. Callback - If not NULL, this function will be called and the file will be included on the list only
  1294. if it returns TRUE.
  1295. ListHead - Pointer to the head of the list to be filled in.
  1296. Return value:
  1297. ERROR_SUCCESS on success, otherwise a Win32 error code. The list may not be empty even if the function fails; the caller
  1298. must always empty the list.
  1299. --*/
  1300. {
  1301. DWORD Error = ERROR_SUCCESS;
  1302. HANDLE hFind = INVALID_HANDLE_VALUE;
  1303. PTSTR szPath = NULL;
  1304. WIN32_FIND_DATA fd;
  1305. if(ListHead != NULL) {
  1306. InitializeListHead(ListHead);
  1307. }
  1308. if(NULL == PathBase || 0 == PathBase[0] || NULL == ListHead) {
  1309. Error = ERROR_INVALID_PARAMETER;
  1310. goto exit;
  1311. }
  1312. szPath = (PTSTR) MyMalloc(MAX_PATH * sizeof(TCHAR));
  1313. if(NULL == szPath) {
  1314. Error = ERROR_NOT_ENOUGH_MEMORY;
  1315. goto exit;
  1316. }
  1317. _tcsncpy(szPath, PathBase, MAX_PATH - 1);
  1318. szPath[MAX_PATH - 1] = 0;
  1319. if(Directory != NULL && Directory[0] != 0) {
  1320. pSetupConcatenatePaths(szPath, Directory, MAX_PATH, NULL);
  1321. }
  1322. if(!pSetupConcatenatePaths(szPath, TEXT("\\*"), MAX_PATH, NULL)) {
  1323. Error = ERROR_BAD_PATHNAME;
  1324. goto exit;
  1325. }
  1326. hFind = FindFirstFile(szPath, &fd);
  1327. if(INVALID_HANDLE_VALUE == hFind) {
  1328. Error = GetLastError();
  1329. if(ERROR_FILE_NOT_FOUND == Error || ERROR_PATH_NOT_FOUND == Error) {
  1330. Error = ERROR_SUCCESS;
  1331. }
  1332. goto exit;
  1333. }
  1334. //
  1335. // We might need the dir later
  1336. //
  1337. (_tcsrchr(szPath, L'\\'))[0] = 0;
  1338. do {
  1339. if(_tcscmp(fd.cFileName, _T(".")) != 0 &&
  1340. _tcscmp(fd.cFileName, _T("..")) != 0 &&
  1341. (MustHaveAttrs & fd.dwFileAttributes) == MustHaveAttrs &&
  1342. 0 == (MustNotHaveAttrs & fd.dwFileAttributes) &&
  1343. (NULL == Callback || Callback(szPath, fd.cFileName))) {
  1344. ULONG uLen;
  1345. PSTRING_LIST_ENTRY pElem = (PSTRING_LIST_ENTRY) MyMalloc(sizeof(STRING_LIST_ENTRY));
  1346. if(NULL == pElem) {
  1347. Error = ERROR_NOT_ENOUGH_MEMORY;
  1348. goto exit;
  1349. }
  1350. uLen = (_tcslen(fd.cFileName) + 1) * sizeof(TCHAR);
  1351. pElem->String = (PTSTR) MyMalloc(uLen);
  1352. if(NULL == pElem->String) {
  1353. MyFree(pElem);
  1354. Error = ERROR_NOT_ENOUGH_MEMORY;
  1355. goto exit;
  1356. }
  1357. RtlCopyMemory(pElem->String, fd.cFileName, uLen);
  1358. InsertTailList(ListHead, &pElem->Entry);
  1359. }
  1360. }
  1361. while(FindNextFile(hFind, &fd));
  1362. Error = GetLastError();
  1363. if(ERROR_NO_MORE_FILES == Error) {
  1364. Error = ERROR_SUCCESS;
  1365. }
  1366. exit:
  1367. if(hFind != INVALID_HANDLE_VALUE) {
  1368. FindClose(hFind);
  1369. }
  1370. if(szPath != NULL) {
  1371. MyFree(szPath);
  1372. }
  1373. return Error;
  1374. }
  1375. PSTRING_LIST_ENTRY
  1376. SearchStringInList(
  1377. IN PLIST_ENTRY ListHead,
  1378. IN PCTSTR String,
  1379. BOOL CaseSensitive
  1380. )
  1381. /*++
  1382. Routine Description:
  1383. This routine searches for a string in a string list. The string can be NULL or empty, in which
  1384. case the function returns the first entry in the list with a NULL or empty string.
  1385. Arguments:
  1386. ListHead - Pointer to the head of the list to be searched.
  1387. String - Specifies the string to search for.
  1388. CaseSensitive - If TRUE, the search will be case sensitive.
  1389. Return value:
  1390. A pointer to the first entry containing the string, if found, or NULL otherwise.
  1391. --*/
  1392. {
  1393. if(ListHead != NULL)
  1394. {
  1395. PLIST_ENTRY pEntry;
  1396. ULONG uLen1 = (String != NULL ? _tcslen(String) : 0);
  1397. for(pEntry = ListHead->Flink; pEntry != ListHead; pEntry = pEntry->Flink) {
  1398. PSTRING_LIST_ENTRY pStringEntry;
  1399. ULONG uLen2;
  1400. pStringEntry = CONTAINING_RECORD(pEntry, STRING_LIST_ENTRY, Entry);
  1401. uLen2 = (pStringEntry->String != NULL ? _tcslen(pStringEntry->String) : 0);
  1402. if(uLen1 == uLen2) {
  1403. if(0 == uLen1 || 0 == (CaseSensitive ? _tcscmp : _tcsicmp)(String, pStringEntry->String)) {
  1404. return pStringEntry;
  1405. }
  1406. }
  1407. }
  1408. }
  1409. return NULL;
  1410. }
  1411. DWORD
  1412. LookupCatalogAttribute(
  1413. IN PCWSTR CatalogName,
  1414. IN PCWSTR Directory OPTIONAL,
  1415. IN PCWSTR AttributeName OPTIONAL,
  1416. IN PCWSTR AttributeValue OPTIONAL,
  1417. PBOOL Found
  1418. )
  1419. /*++
  1420. Routine Description:
  1421. This function searches if a catalog has the specified attribute with the specified value.
  1422. Arguments:
  1423. CatalogName - Name of the catalog to search. A path can be specified.
  1424. Directory - If specified, it is prepended to CatalogName to form the path to the catalog.
  1425. AttributeName - See AttributeValue.
  1426. AttributeValue - If AttributeName and AttributeValue are not specified, the catalog meets the condition.
  1427. If AttributeName is specified and AttributeValue isn't, the catalog meets the condition if
  1428. it contains an attribute with AttributeName name and any value. If AttributeName is not
  1429. specified and AttributeValue is, the catalog meets the condition if it contains an attribute
  1430. with AttributeValue value and any name. If both AttributeName and AttributeValue are
  1431. specified, the catalog meets the condition if it contains an attribute with AttributeName name
  1432. and AttributeValue value.
  1433. Found - Pointer to a variable that receives TRUE if the catalog meets the condition, or FALSE otherwise.
  1434. Return value:
  1435. ERROR_SUCCESS if successful, otherwise a Win32 error code.
  1436. --*/
  1437. {
  1438. DWORD Error = ERROR_SUCCESS;
  1439. HANDLE hCat = INVALID_HANDLE_VALUE;
  1440. PWSTR szCatPath = NULL;
  1441. CRYPTCATATTRIBUTE* pAttr;
  1442. if(Found != NULL) {
  1443. *Found = FALSE;
  1444. }
  1445. if(NULL == CatalogName || 0 == CatalogName[0] || NULL == Found) {
  1446. Error = ERROR_INVALID_PARAMETER;
  1447. goto exit;
  1448. }
  1449. if(Directory != NULL && Directory[0] != 0) {
  1450. szCatPath = MyMalloc(MAX_PATH * sizeof(WCHAR));
  1451. if(NULL == szCatPath) {
  1452. Error = ERROR_NOT_ENOUGH_MEMORY;
  1453. goto exit;
  1454. }
  1455. _tcsncpy(szCatPath, Directory, MAX_PATH - 1);
  1456. szCatPath[MAX_PATH - 1] = 0;
  1457. pSetupConcatenatePaths(szCatPath, CatalogName, MAX_PATH, NULL);
  1458. CatalogName = szCatPath;
  1459. }
  1460. //
  1461. // This is easier to test
  1462. //
  1463. if(AttributeName != NULL && 0 == AttributeName[0]) {
  1464. AttributeName = NULL;
  1465. }
  1466. if(AttributeValue != NULL && 0 == AttributeValue[0]) {
  1467. AttributeValue = NULL;
  1468. }
  1469. if(NULL == AttributeName && NULL == AttributeValue) {
  1470. //
  1471. // If attribute name and value are not specified, any catalog is a match
  1472. //
  1473. *Found = TRUE;
  1474. goto exit;
  1475. }
  1476. hCat = CryptCATOpen((PWSTR) CatalogName, CRYPTCAT_OPEN_EXISTING, 0, 0, 0);
  1477. if(INVALID_HANDLE_VALUE == hCat) {
  1478. Error = GetLastError();
  1479. goto exit;
  1480. }
  1481. pAttr = CryptCATEnumerateCatAttr(hCat, NULL);
  1482. while(pAttr != NULL) {
  1483. *Found = (NULL == AttributeName || 0 == _wcsicmp(AttributeName, pAttr->pwszReferenceTag)) &&
  1484. (NULL == AttributeValue || 0 == _wcsicmp(AttributeName, (PCWSTR) pAttr->pbValue));
  1485. if(*Found) {
  1486. goto exit;
  1487. }
  1488. pAttr = CryptCATEnumerateCatAttr(hCat, pAttr);
  1489. }
  1490. Error = GetLastError();
  1491. if(CRYPT_E_NOT_FOUND == Error) {
  1492. Error = ERROR_SUCCESS;
  1493. }
  1494. exit:
  1495. if(szCatPath != NULL) {
  1496. MyFree(szCatPath);
  1497. }
  1498. if(hCat != INVALID_HANDLE_VALUE) {
  1499. CryptCATClose(hCat);
  1500. }
  1501. return Error;
  1502. }