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.

939 lines
20 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1992 - 1997.
  5. //
  6. // File: wxcli.c
  7. //
  8. // Contents:
  9. //
  10. // Classes:
  11. //
  12. // Functions:
  13. //
  14. // History: 4-18-97 RichardW Created
  15. //
  16. //----------------------------------------------------------------------------
  17. #include <nt.h>
  18. #include <ntrtl.h>
  19. #include <nturtl.h>
  20. #include <ntsam.h>
  21. #include <ntsamp.h>
  22. #include <ntlsa.h>
  23. #include <caiseapi.h>
  24. #include <windows.h>
  25. #include <windef.h>
  26. #include <md5.h>
  27. #include <wxlpc.h>
  28. #include <wxlpcp.h>
  29. #include "rng.h"
  30. #define safe_min(x,y) ( x < y ? x : y )
  31. NTSTATUS
  32. WxConnect(
  33. PHANDLE Handle
  34. )
  35. {
  36. NTSTATUS Status ;
  37. UNICODE_STRING PortName ;
  38. SECURITY_QUALITY_OF_SERVICE DynamicQos;
  39. //
  40. // Set up the security quality of service parameters to use over the
  41. // port. Use the most efficient (least overhead) - which is dynamic
  42. // rather than static tracking.
  43. //
  44. DynamicQos.ImpersonationLevel = SecurityImpersonation;
  45. DynamicQos.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING;
  46. DynamicQos.EffectiveOnly = TRUE;
  47. //
  48. // Connect to the Winlogon server thread
  49. //
  50. RtlInitUnicodeString(&PortName, WX_PORT_NAME );
  51. Status = NtConnectPort(
  52. Handle,
  53. &PortName,
  54. &DynamicQos,
  55. NULL,
  56. NULL,
  57. NULL,
  58. NULL,
  59. 0
  60. );
  61. if ( !NT_SUCCESS(Status) )
  62. {
  63. // DbgPrint("WX: Connection failed %lx\n",Status);
  64. }
  65. return Status;
  66. }
  67. NTSTATUS
  68. WxGetKeyData(
  69. IN HANDLE Handle,
  70. IN WX_AUTH_TYPE ExpectedAuthSource,
  71. IN ULONG BufferSize,
  72. OUT PUCHAR Buffer,
  73. OUT PULONG BufferData
  74. )
  75. {
  76. WXLPC_MESSAGE Message ;
  77. NTSTATUS Status ;
  78. WXLPC_GETKEYDATA * Parameters ;
  79. PREPARE_MESSAGE( Message, WxGetKeyDataApi );
  80. Parameters = &Message.Parameters.GetKeyData ;
  81. Parameters->ExpectedAuth = ExpectedAuthSource ;
  82. Parameters->BufferSize = BufferSize ;
  83. Status = NtRequestWaitReplyPort(
  84. Handle,
  85. &Message.Message,
  86. &Message.Message );
  87. if ( !NT_SUCCESS( Status ) )
  88. {
  89. return Status ;
  90. }
  91. if ( NT_SUCCESS( Message.Status ) )
  92. {
  93. RtlCopyMemory( Buffer,
  94. Parameters->Buffer,
  95. safe_min( Parameters->BufferData, BufferSize ) );
  96. }
  97. return Message.Status ;
  98. }
  99. NTSTATUS
  100. WxReportResults(
  101. IN HANDLE Handle,
  102. IN NTSTATUS ResultStatus
  103. )
  104. {
  105. WXLPC_MESSAGE Message ;
  106. NTSTATUS Status ;
  107. WXLPC_REPORTRESULTS * Parameters ;
  108. PREPARE_MESSAGE( Message, WxReportResultsApi );
  109. Parameters = &Message.Parameters.ReportResults ;
  110. Parameters->Status = ResultStatus ;
  111. Status = NtRequestWaitReplyPort(
  112. Handle,
  113. &Message.Message,
  114. &Message.Message );
  115. if ( !NT_SUCCESS( Status ) )
  116. {
  117. return Status ;
  118. }
  119. return Message.Status ;
  120. }
  121. /*++
  122. The following code was moved from syskey to wxcli so as to commonalize this code
  123. between syskey and samsrv.dll
  124. --*/
  125. #if DBG
  126. #define HIDDEN
  127. #else
  128. #define HIDDEN static
  129. #endif
  130. HIDDEN
  131. UCHAR KeyShuffle[ 16 ] = { 8, 10, 3, 7, 2, 1, 9, 15, 0, 5, 13, 4, 11, 6, 12, 14 };
  132. HIDDEN
  133. CHAR HexKey[ 17 ] = "0123456789abcdef" ;
  134. #define ToHex( f ) (HexKey[f & 0xF])
  135. #define SYSTEM_KEY L"SecureBoot"
  136. HIDDEN BOOLEAN
  137. WxpDeleteLocalKey(VOID)
  138. /*++
  139. Routine Description
  140. Deletes the syskey stored on the local machine
  141. --*/
  142. {
  143. HKEY LsaKey;
  144. ULONG err;
  145. err = RegOpenKeyExW( HKEY_LOCAL_MACHINE,
  146. L"System\\CurrentControlSet\\Control\\Lsa",
  147. 0,
  148. KEY_READ | KEY_WRITE,
  149. & LsaKey );
  150. if (0!=err)
  151. {
  152. return (FALSE);
  153. }
  154. (void) RegDeleteKey( LsaKey, TEXT("Data") );
  155. (void) RegDeleteKey( LsaKey, TEXT("Skew1") );
  156. (void) RegDeleteKey( LsaKey, TEXT("GBG") );
  157. (void) RegDeleteKey( LsaKey, TEXT("JD") );
  158. RegCloseKey(LsaKey);
  159. return STATUS_SUCCESS ;
  160. }
  161. HIDDEN BOOLEAN
  162. WxpObfuscateKey(
  163. PWXHASH Hash
  164. )
  165. {
  166. HKEY Key ;
  167. HKEY Key2 ;
  168. int Result ;
  169. WXHASH H ;
  170. CHAR Classes[ 9 ];
  171. int i ;
  172. WXHASH R ;
  173. PCHAR Class ;
  174. DWORD Disp ;
  175. DWORD FailCount = 0;
  176. HKEY LsaKey;
  177. ULONG err=0;
  178. err = RegOpenKeyExW( HKEY_LOCAL_MACHINE,
  179. L"System\\CurrentControlSet\\Control\\Lsa",
  180. 0,
  181. KEY_READ | KEY_WRITE,
  182. & LsaKey );
  183. if (0!=err)
  184. {
  185. return (FALSE);
  186. }
  187. for (Result = 0 ; Result < 16 ; Result++ )
  188. {
  189. H.Digest[Result] = Hash->Digest[ KeyShuffle[ Result ] ];
  190. }
  191. WxpDeleteLocalKey();
  192. Classes[8] = '\0';
  193. STGenerateRandomBits( R.Digest, 16 );
  194. Class = Classes ;
  195. for ( i = 0 ; i < 4 ; i++ )
  196. {
  197. *Class++ = ToHex( (H.Digest[ i ] >> 4) );
  198. *Class++ = ToHex( H.Digest[ i ] );
  199. }
  200. Result = RegCreateKeyExA( LsaKey,
  201. "JD",
  202. 0,
  203. Classes,
  204. REG_OPTION_NON_VOLATILE,
  205. KEY_WRITE,
  206. NULL,
  207. &Key,
  208. &Disp );
  209. if ( Result == 0 )
  210. {
  211. RegSetValueEx( Key, TEXT("Lookup"), 0,
  212. REG_BINARY, R.Digest, 6 );
  213. RegCloseKey( Key );
  214. }
  215. else
  216. {
  217. RegCloseKey(LsaKey);
  218. return FALSE ;
  219. }
  220. Class = Classes ;
  221. for ( i = 0 ; i < 4 ; i++ )
  222. {
  223. STGenerateRandomBits( R.Digest, 16 );
  224. *Class++ = ToHex( (H.Digest[ i+4 ] >> 4 ) );
  225. *Class++ = ToHex( H.Digest[ i+4 ] );
  226. }
  227. Result = RegCreateKeyExA( LsaKey,
  228. "Skew1",
  229. 0,
  230. Classes,
  231. REG_OPTION_NON_VOLATILE,
  232. KEY_WRITE,
  233. NULL,
  234. &Key,
  235. &Disp );
  236. if ( Result == 0 )
  237. {
  238. RegSetValueEx( Key, TEXT("SkewMatrix"), 0,
  239. REG_BINARY, R.Digest, 16 );
  240. RegCloseKey( Key );
  241. }
  242. else
  243. {
  244. FailCount++;
  245. }
  246. STGenerateRandomBits( R.Digest, 16 );
  247. for ( i = 0, Class = Classes ; i < 4 ; i++ )
  248. {
  249. *Class++ = ToHex( (H.Digest[ i+8 ] >> 4 ));
  250. *Class++ = ToHex( H.Digest[i+8] );
  251. }
  252. Result = RegCreateKeyExA( LsaKey,
  253. "GBG",
  254. 0,
  255. Classes,
  256. REG_OPTION_NON_VOLATILE,
  257. KEY_WRITE,
  258. NULL,
  259. &Key,
  260. &Disp );
  261. if ( Result == 0 )
  262. {
  263. RegSetValueEx( Key, TEXT("GrafBlumGroup"), 0,
  264. REG_BINARY, R.Digest, 9 );
  265. RegCloseKey( Key );
  266. }
  267. else
  268. {
  269. FailCount++;
  270. }
  271. STGenerateRandomBits( H.Digest, 8 );
  272. Class = Classes ;
  273. STGenerateRandomBits( R.Digest, 16 );
  274. for ( i = 0 ; i < 4 ; i++ )
  275. {
  276. *Class++ = ToHex( (H.Digest[ i+12 ] >> 4 ) );
  277. *Class++ = ToHex( H.Digest[ i+12 ] );
  278. }
  279. Result = RegCreateKeyExA( LsaKey,
  280. "Data",
  281. 0,
  282. Classes,
  283. REG_OPTION_NON_VOLATILE,
  284. KEY_WRITE,
  285. NULL,
  286. &Key,
  287. &Disp );
  288. if ( Result == 0 )
  289. {
  290. STGenerateRandomBits( H.Digest, 16 );
  291. RegSetValueEx( Key, TEXT("Pattern"), 0,
  292. REG_BINARY, R.Digest, 64 );
  293. RegCloseKey( Key );
  294. }
  295. else
  296. {
  297. FailCount++;
  298. }
  299. RegCloseKey(LsaKey);
  300. return TRUE ;
  301. }
  302. #define FromHex( c ) ( ( ( c >= '0' ) && ( c <= '9') ) ? c - '0' : \
  303. ( ( c >= 'a' ) && ( c <= 'f') ) ? c - 'a' + 10: \
  304. ( ( c >= 'A' ) && ( c <= 'F' ) ) ? c - 'A' + 10: -1 )
  305. HIDDEN BOOLEAN
  306. WxpDeObfuscateKey(
  307. HKEY Keylocation,
  308. PWXHASH Hash
  309. )
  310. {
  311. WXHASH ProtoHash ;
  312. int Result ;
  313. CHAR Class[ 9 ];
  314. HKEY Key ;
  315. DWORD Size ;
  316. DWORD i ;
  317. PUCHAR j ;
  318. int t;
  319. int t2 ;
  320. HKEY LsaKey;
  321. ULONG err;
  322. if (Keylocation!=NULL) {
  323. DWORD Type=REG_DWORD;
  324. DWORD Data;
  325. DWORD cbData=sizeof(DWORD);
  326. WCHAR Controlset[256];
  327. err = RegOpenKeyExW( Keylocation,
  328. L"Select",
  329. 0,
  330. KEY_READ | KEY_WRITE,
  331. & LsaKey );
  332. if (0!=err)
  333. {
  334. return (FALSE);
  335. }
  336. err = RegQueryValueExW(
  337. LsaKey,
  338. L"Default",
  339. NULL,
  340. &Type,
  341. (LPBYTE)&Data,
  342. &cbData
  343. );
  344. RegCloseKey(LsaKey);
  345. if (0!=err)
  346. {
  347. return (FALSE);
  348. }
  349. if(Data==1){
  350. err = RegOpenKeyExW( Keylocation,
  351. L"ControlSet001\\Control\\Lsa",
  352. 0,
  353. KEY_READ | KEY_WRITE,
  354. & LsaKey );
  355. } else {
  356. err = RegOpenKeyExW( Keylocation,
  357. L"ControlSet002\\Control\\Lsa",
  358. 0,
  359. KEY_READ | KEY_WRITE,
  360. & LsaKey );
  361. }
  362. if (0!=err)
  363. {
  364. RegCloseKey(LsaKey);
  365. return (FALSE);
  366. }
  367. } else {
  368. err = RegOpenKeyExW( HKEY_LOCAL_MACHINE,
  369. L"System\\CurrentControlSet\\Control\\Lsa",
  370. 0,
  371. KEY_READ | KEY_WRITE,
  372. & LsaKey );
  373. if (0!=err)
  374. {
  375. return (FALSE);
  376. }
  377. }
  378. Result = RegOpenKeyEx( LsaKey, TEXT("JD"), 0,
  379. KEY_READ, &Key );
  380. j = ProtoHash.Digest ;
  381. if ( Result == 0 )
  382. {
  383. Size = 9 ;
  384. Result = RegQueryInfoKeyA( Key,
  385. Class,
  386. &Size,
  387. NULL, NULL, NULL,
  388. NULL, NULL, NULL,
  389. NULL, NULL, NULL );
  390. RegCloseKey( Key );
  391. if ( Result == 0 )
  392. {
  393. for ( i = 0 ; i < 8 ; i += 2 )
  394. {
  395. t = FromHex( Class[ i ] );
  396. t2 = FromHex( Class[ i+1 ] );
  397. if ( (t >= 0 ) && ( t2 >= 0 ) )
  398. {
  399. *j++ = (t << 4) + t2 ;
  400. }
  401. else
  402. {
  403. RegCloseKey(LsaKey);
  404. return FALSE ;
  405. }
  406. }
  407. }
  408. }
  409. Result = RegOpenKeyEx( LsaKey, TEXT("Skew1"), 0,
  410. KEY_READ, &Key );
  411. if ( Result == 0 )
  412. {
  413. Size = 9 ;
  414. Result = RegQueryInfoKeyA( Key,
  415. Class,
  416. &Size,
  417. NULL, NULL, NULL,
  418. NULL, NULL, NULL,
  419. NULL, NULL, NULL );
  420. RegCloseKey( Key );
  421. if ( Result == 0 )
  422. {
  423. for ( i = 0 ; i < 8 ; i += 2 )
  424. {
  425. t = FromHex( Class[ i ] );
  426. t2 = FromHex( Class[ i+1 ] );
  427. if ( (t >= 0 ) && ( t2 >= 0 ) )
  428. {
  429. *j++ = (t << 4) + t2 ;
  430. }
  431. else
  432. {
  433. RegCloseKey(LsaKey);
  434. return FALSE ;
  435. }
  436. }
  437. }
  438. }
  439. Result = RegOpenKeyEx( LsaKey, TEXT("GBG"), 0,
  440. KEY_READ, &Key );
  441. if ( Result == 0 )
  442. {
  443. Size = 9 ;
  444. Result = RegQueryInfoKeyA( Key,
  445. Class,
  446. &Size,
  447. NULL, NULL, NULL,
  448. NULL, NULL, NULL,
  449. NULL, NULL, NULL );
  450. RegCloseKey( Key );
  451. if ( Result == 0 )
  452. {
  453. for ( i = 0 ; i < 8 ; i += 2 )
  454. {
  455. t = FromHex( Class[ i ] );
  456. t2 = FromHex( Class[ i+1 ] );
  457. if ( (t >= 0 ) && ( t2 >= 0 ) )
  458. {
  459. *j++ = (t << 4) + t2 ;
  460. }
  461. else
  462. {
  463. RegCloseKey(LsaKey);
  464. return FALSE ;
  465. }
  466. }
  467. }
  468. }
  469. Result = RegOpenKeyEx( LsaKey, TEXT("Data"), 0,
  470. KEY_READ, &Key );
  471. if ( Result == 0 )
  472. {
  473. Size = 9 ;
  474. Result = RegQueryInfoKeyA( Key,
  475. Class,
  476. &Size,
  477. NULL, NULL, NULL,
  478. NULL, NULL, NULL,
  479. NULL, NULL, NULL );
  480. RegCloseKey( Key );
  481. if ( Result == 0 )
  482. {
  483. for ( i = 0 ; i < 8 ; i += 2 )
  484. {
  485. t = FromHex( Class[ i ] );
  486. t2 = FromHex( Class[ i+1 ] );
  487. if ( (t >= 0 ) && ( t2 >= 0 ) )
  488. {
  489. *j++ = (t << 4) + t2 ;
  490. }
  491. else
  492. {
  493. RegCloseKey(LsaKey);
  494. return FALSE ;
  495. }
  496. }
  497. }
  498. }
  499. for ( i = 0 ; i < 16 ; i++ )
  500. {
  501. Hash->Digest[ KeyShuffle[ i ] ] = ProtoHash.Digest[ i ] ;
  502. }
  503. RegCloseKey(LsaKey);
  504. return TRUE ;
  505. }
  506. NTSTATUS
  507. WxSaveSysKey(
  508. IN ULONG Keylen,
  509. IN PVOID Key
  510. )
  511. /*++
  512. Routine Description
  513. This routine is used to store the syskey
  514. in the registry
  515. Paramaeters
  516. Keylen - the length of the key
  517. Key the actual key itself
  518. Return Values
  519. STATUS_SUCCESS
  520. STATUS_UNSUCCESSFUL
  521. --*/
  522. {
  523. WXHASH H;
  524. //
  525. // key should be 128 bits
  526. //
  527. if (Keylen!=sizeof(H.Digest))
  528. return (STATUS_INVALID_PARAMETER);
  529. RtlCopyMemory(&H.Digest,
  530. Key,
  531. Keylen
  532. );
  533. if (WxpObfuscateKey(&H))
  534. {
  535. return(STATUS_SUCCESS);
  536. }
  537. else
  538. {
  539. return(STATUS_UNSUCCESSFUL);
  540. }
  541. }
  542. NTSTATUS
  543. WxReadSysKey(
  544. IN OUT PULONG BufferLength,
  545. OUT PVOID Key
  546. )
  547. /*++
  548. Routine Description
  549. This routine is used to retrieve the syskey from
  550. the registry
  551. Paramaeters
  552. BufferLength is filled in with the length required on output
  553. is used to indicate the size of the buffer
  554. pointed to by Key.
  555. Key Points to a buffer into which the key is recieved
  556. Return Values
  557. STATUS_SUCCESS
  558. STATUS_UNSUCCESSFUL
  559. --*/
  560. {
  561. return WxReadSysKeyEx(
  562. NULL,
  563. BufferLength,
  564. Key
  565. );
  566. }
  567. NTSTATUS
  568. WxReadSysKeyEx(
  569. IN HKEY Handle,
  570. IN OUT PULONG BufferLength,
  571. OUT PVOID Key
  572. )
  573. /*++
  574. Routine Description
  575. This routine is used to retrieve the syskey from
  576. the registry
  577. Paramaeters
  578. Handle Contains a pointer to the syskey in the old registry
  579. BufferLength is filled in with the length required on output
  580. is used to indicate the size of the buffer
  581. pointed to by Key.
  582. Key Points to a buffer into which the key is recieved
  583. Return Values
  584. STATUS_SUCCESS
  585. STATUS_UNSUCCESSFUL
  586. --*/
  587. {
  588. WXHASH H;
  589. if ((NULL==Key) || (*BufferLength <sizeof(H.Digest)))
  590. {
  591. *BufferLength = sizeof(H.Digest);
  592. return(STATUS_BUFFER_OVERFLOW);
  593. }
  594. if (WxpDeObfuscateKey(Handle,&H))
  595. {
  596. *BufferLength = sizeof(H.Digest);
  597. RtlCopyMemory(
  598. Key,
  599. &H.Digest,
  600. *BufferLength
  601. );
  602. return(STATUS_SUCCESS);
  603. }
  604. return (STATUS_UNSUCCESSFUL);
  605. }
  606. NTSTATUS
  607. WxLoadSysKeyFromDisk(OUT PVOID Key,
  608. OUT PULONG BufferLength
  609. )
  610. /*++
  611. Routine Description
  612. This routine is used to read the syskey
  613. from the Disk
  614. Paramaeters
  615. Key - buffer where the key will be read into
  616. BufferLength - size of the returned key
  617. Return Values
  618. STATUS_OBJECT_NAME_NOT_FOUND
  619. STATUS_FILE_CORRUPT_ERROR
  620. STATUS_UNSUCCESSFUL
  621. --*/
  622. {
  623. HANDLE hFile ;
  624. ULONG Actual ;
  625. ULONG ErrorMode ;
  626. LPSTR SysKeyFileName = "A:\\startkey.key";
  627. ErrorMode = SetErrorMode( SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX );
  628. hFile = CreateFileA( SysKeyFileName,
  629. GENERIC_READ,
  630. 0,
  631. NULL,
  632. OPEN_EXISTING,
  633. FILE_ATTRIBUTE_NORMAL,
  634. NULL );
  635. if ( hFile == INVALID_HANDLE_VALUE )
  636. {
  637. SetErrorMode( ErrorMode );
  638. return STATUS_OBJECT_NAME_NOT_FOUND ;
  639. }
  640. if (!ReadFile( hFile, Key, SYSKEY_SIZE, &Actual, NULL ) ||
  641. (Actual != SYSKEY_SIZE ))
  642. {
  643. SetErrorMode( ErrorMode );
  644. CloseHandle( hFile );
  645. return STATUS_FILE_CORRUPT_ERROR ;
  646. }
  647. SetErrorMode( ErrorMode );
  648. CloseHandle( hFile );
  649. *BufferLength = SYSKEY_SIZE;
  650. return STATUS_SUCCESS;
  651. }
  652. NTSTATUS
  653. WxHashKey(
  654. IN OUT LPWSTR key, //will be killed
  655. OUT PVOID SysKey,
  656. IN OUT DWORD cbSysKey
  657. )
  658. /*++
  659. Routine Description
  660. This routine is used to store the boot type
  661. in the registry
  662. Paramaeters
  663. NewType Indicates the new boot type
  664. Return Values
  665. STATUS_SUCCESS
  666. STATUS_UNSUCCESSFUL
  667. --*/
  668. {
  669. MD5_CTX Md5;
  670. if(cbSysKey<SYSKEY_SIZE) {
  671. return STATUS_BUFFER_TOO_SMALL;
  672. }
  673. cbSysKey=wcslen(key)*sizeof(WCHAR);
  674. MD5Init( &Md5 );
  675. MD5Update( &Md5, (PUCHAR) key, cbSysKey );
  676. MD5Final( &Md5 );
  677. ZeroMemory( key, cbSysKey );
  678. cbSysKey=SYSKEY_SIZE;
  679. CopyMemory( SysKey, Md5.digest, cbSysKey );
  680. return STATUS_SUCCESS;
  681. }
  682. NTSTATUS
  683. WxSaveBootOption( WX_AUTH_TYPE NewType )
  684. /*++
  685. Routine Description
  686. This routine is used to store the boot type
  687. in the registry
  688. Paramaeters
  689. NewType Indicates the new boot type
  690. Return Values
  691. STATUS_SUCCESS
  692. STATUS_UNSUCCESSFUL
  693. --*/
  694. {
  695. HKEY LsaKey;
  696. ULONG err;
  697. err = RegOpenKeyExW( HKEY_LOCAL_MACHINE,
  698. L"System\\CurrentControlSet\\Control\\Lsa",
  699. 0,
  700. KEY_READ | KEY_WRITE,
  701. & LsaKey );
  702. if (0!=err)
  703. {
  704. return (STATUS_UNSUCCESSFUL);
  705. }
  706. err = RegSetValueExW(
  707. LsaKey,
  708. SYSTEM_KEY,
  709. 0,
  710. REG_DWORD,
  711. (PUCHAR) &NewType,
  712. sizeof( NewType )
  713. );
  714. if (0!=err)
  715. {
  716. RegCloseKey(LsaKey);
  717. return (STATUS_UNSUCCESSFUL);
  718. }
  719. RegCloseKey(LsaKey);
  720. return ( STATUS_SUCCESS);
  721. }