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.

962 lines
21 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 <crypt.h>
  28. #include <wxlpc.h>
  29. #include <wxlpcp.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 = NULL;
  177. ULONG err=0;
  178. BOOLEAN fResult = FALSE;
  179. err = RegOpenKeyExW( HKEY_LOCAL_MACHINE,
  180. L"System\\CurrentControlSet\\Control\\Lsa",
  181. 0,
  182. KEY_READ | KEY_WRITE,
  183. & LsaKey );
  184. if (0!=err)
  185. {
  186. return FALSE;
  187. }
  188. for (Result = 0 ; Result < 16 ; Result++ )
  189. {
  190. H.Digest[Result] = Hash->Digest[ KeyShuffle[ Result ] ];
  191. }
  192. WxpDeleteLocalKey();
  193. Classes[8] = '\0';
  194. if (!RtlGenRandom( R.Digest, 16 ))
  195. {
  196. goto Cleanup;
  197. }
  198. Class = Classes ;
  199. for ( i = 0 ; i < 4 ; i++ )
  200. {
  201. *Class++ = ToHex( (H.Digest[ i ] >> 4) );
  202. *Class++ = ToHex( H.Digest[ i ] );
  203. }
  204. Result = RegCreateKeyExA( LsaKey,
  205. "JD",
  206. 0,
  207. Classes,
  208. REG_OPTION_NON_VOLATILE,
  209. KEY_WRITE,
  210. NULL,
  211. &Key,
  212. &Disp );
  213. if ( Result == 0 )
  214. {
  215. RegSetValueEx( Key, TEXT("Lookup"), 0,
  216. REG_BINARY, R.Digest, 6 );
  217. RegCloseKey( Key );
  218. }
  219. else
  220. {
  221. goto Cleanup;
  222. }
  223. Class = Classes ;
  224. for ( i = 0 ; i < 4 ; i++ )
  225. {
  226. if (!RtlGenRandom( R.Digest, 16 ))
  227. {
  228. goto Cleanup;
  229. }
  230. *Class++ = ToHex( (H.Digest[ i+4 ] >> 4 ) );
  231. *Class++ = ToHex( H.Digest[ i+4 ] );
  232. }
  233. Result = RegCreateKeyExA( LsaKey,
  234. "Skew1",
  235. 0,
  236. Classes,
  237. REG_OPTION_NON_VOLATILE,
  238. KEY_WRITE,
  239. NULL,
  240. &Key,
  241. &Disp );
  242. if ( Result == 0 )
  243. {
  244. RegSetValueEx( Key, TEXT("SkewMatrix"), 0,
  245. REG_BINARY, R.Digest, 16 );
  246. RegCloseKey( Key );
  247. }
  248. else
  249. {
  250. FailCount++;
  251. }
  252. if (!RtlGenRandom( R.Digest, 16 ))
  253. {
  254. goto Cleanup;
  255. }
  256. for ( i = 0, Class = Classes ; i < 4 ; i++ )
  257. {
  258. *Class++ = ToHex( (H.Digest[ i+8 ] >> 4 ));
  259. *Class++ = ToHex( H.Digest[i+8] );
  260. }
  261. Result = RegCreateKeyExA( LsaKey,
  262. "GBG",
  263. 0,
  264. Classes,
  265. REG_OPTION_NON_VOLATILE,
  266. KEY_WRITE,
  267. NULL,
  268. &Key,
  269. &Disp );
  270. if ( Result == 0 )
  271. {
  272. RegSetValueEx( Key, TEXT("GrafBlumGroup"), 0,
  273. REG_BINARY, R.Digest, 9 );
  274. RegCloseKey( Key );
  275. }
  276. else
  277. {
  278. FailCount++;
  279. }
  280. if (!RtlGenRandom( H.Digest, 8 ))
  281. {
  282. goto Cleanup;
  283. }
  284. Class = Classes ;
  285. if (!RtlGenRandom( R.Digest, 16 ))
  286. {
  287. goto Cleanup;
  288. }
  289. for ( i = 0 ; i < 4 ; i++ )
  290. {
  291. *Class++ = ToHex( (H.Digest[ i+12 ] >> 4 ) );
  292. *Class++ = ToHex( H.Digest[ i+12 ] );
  293. }
  294. Result = RegCreateKeyExA( LsaKey,
  295. "Data",
  296. 0,
  297. Classes,
  298. REG_OPTION_NON_VOLATILE,
  299. KEY_WRITE,
  300. NULL,
  301. &Key,
  302. &Disp );
  303. if ( Result == 0 )
  304. {
  305. if (!RtlGenRandom( H.Digest, 16 ))
  306. {
  307. RegCloseKey( Key );
  308. goto Cleanup;
  309. }
  310. RegSetValueEx( Key, TEXT("Pattern"), 0,
  311. REG_BINARY, R.Digest, 16 );
  312. RegCloseKey( Key );
  313. }
  314. else
  315. {
  316. FailCount++;
  317. }
  318. fResult = TRUE;
  319. Cleanup:
  320. if (LsaKey)
  321. {
  322. RegCloseKey(LsaKey);
  323. }
  324. return fResult ;
  325. }
  326. #define FromHex( c ) ( ( ( c >= '0' ) && ( c <= '9') ) ? c - '0' : \
  327. ( ( c >= 'a' ) && ( c <= 'f') ) ? c - 'a' + 10: \
  328. ( ( c >= 'A' ) && ( c <= 'F' ) ) ? c - 'A' + 10: -1 )
  329. HIDDEN BOOLEAN
  330. WxpDeObfuscateKey(
  331. HKEY Keylocation,
  332. PWXHASH Hash
  333. )
  334. {
  335. WXHASH ProtoHash ;
  336. int Result ;
  337. CHAR Class[ 9 ];
  338. HKEY Key ;
  339. DWORD Size ;
  340. DWORD i ;
  341. PUCHAR j ;
  342. int t;
  343. int t2 ;
  344. HKEY LsaKey;
  345. ULONG err;
  346. if (Keylocation!=NULL) {
  347. DWORD Type=REG_DWORD;
  348. DWORD Data;
  349. DWORD cbData=sizeof(DWORD);
  350. WCHAR Controlset[256];
  351. err = RegOpenKeyExW( Keylocation,
  352. L"Select",
  353. 0,
  354. KEY_READ | KEY_WRITE,
  355. & LsaKey );
  356. if (0!=err)
  357. {
  358. return (FALSE);
  359. }
  360. err = RegQueryValueExW(
  361. LsaKey,
  362. L"Default",
  363. NULL,
  364. &Type,
  365. (LPBYTE)&Data,
  366. &cbData
  367. );
  368. RegCloseKey(LsaKey);
  369. if (0!=err)
  370. {
  371. return (FALSE);
  372. }
  373. if(Data==1){
  374. err = RegOpenKeyExW( Keylocation,
  375. L"ControlSet001\\Control\\Lsa",
  376. 0,
  377. KEY_READ | KEY_WRITE,
  378. & LsaKey );
  379. } else {
  380. err = RegOpenKeyExW( Keylocation,
  381. L"ControlSet002\\Control\\Lsa",
  382. 0,
  383. KEY_READ | KEY_WRITE,
  384. & LsaKey );
  385. }
  386. if (0!=err)
  387. {
  388. RegCloseKey(LsaKey);
  389. return (FALSE);
  390. }
  391. } else {
  392. err = RegOpenKeyExW( HKEY_LOCAL_MACHINE,
  393. L"System\\CurrentControlSet\\Control\\Lsa",
  394. 0,
  395. KEY_READ | KEY_WRITE,
  396. & LsaKey );
  397. if (0!=err)
  398. {
  399. return (FALSE);
  400. }
  401. }
  402. Result = RegOpenKeyEx( LsaKey, TEXT("JD"), 0,
  403. KEY_READ, &Key );
  404. j = ProtoHash.Digest ;
  405. if ( Result == 0 )
  406. {
  407. Size = 9 ;
  408. Result = RegQueryInfoKeyA( Key,
  409. Class,
  410. &Size,
  411. NULL, NULL, NULL,
  412. NULL, NULL, NULL,
  413. NULL, NULL, NULL );
  414. RegCloseKey( Key );
  415. if ( Result == 0 )
  416. {
  417. for ( i = 0 ; i < 8 ; i += 2 )
  418. {
  419. t = FromHex( Class[ i ] );
  420. t2 = FromHex( Class[ i+1 ] );
  421. if ( (t >= 0 ) && ( t2 >= 0 ) )
  422. {
  423. *j++ = (t << 4) + t2 ;
  424. }
  425. else
  426. {
  427. RegCloseKey(LsaKey);
  428. return FALSE ;
  429. }
  430. }
  431. }
  432. }
  433. Result = RegOpenKeyEx( LsaKey, TEXT("Skew1"), 0,
  434. KEY_READ, &Key );
  435. if ( Result == 0 )
  436. {
  437. Size = 9 ;
  438. Result = RegQueryInfoKeyA( Key,
  439. Class,
  440. &Size,
  441. NULL, NULL, NULL,
  442. NULL, NULL, NULL,
  443. NULL, NULL, NULL );
  444. RegCloseKey( Key );
  445. if ( Result == 0 )
  446. {
  447. for ( i = 0 ; i < 8 ; i += 2 )
  448. {
  449. t = FromHex( Class[ i ] );
  450. t2 = FromHex( Class[ i+1 ] );
  451. if ( (t >= 0 ) && ( t2 >= 0 ) )
  452. {
  453. *j++ = (t << 4) + t2 ;
  454. }
  455. else
  456. {
  457. RegCloseKey(LsaKey);
  458. return FALSE ;
  459. }
  460. }
  461. }
  462. }
  463. Result = RegOpenKeyEx( LsaKey, TEXT("GBG"), 0,
  464. KEY_READ, &Key );
  465. if ( Result == 0 )
  466. {
  467. Size = 9 ;
  468. Result = RegQueryInfoKeyA( Key,
  469. Class,
  470. &Size,
  471. NULL, NULL, NULL,
  472. NULL, NULL, NULL,
  473. NULL, NULL, NULL );
  474. RegCloseKey( Key );
  475. if ( Result == 0 )
  476. {
  477. for ( i = 0 ; i < 8 ; i += 2 )
  478. {
  479. t = FromHex( Class[ i ] );
  480. t2 = FromHex( Class[ i+1 ] );
  481. if ( (t >= 0 ) && ( t2 >= 0 ) )
  482. {
  483. *j++ = (t << 4) + t2 ;
  484. }
  485. else
  486. {
  487. RegCloseKey(LsaKey);
  488. return FALSE ;
  489. }
  490. }
  491. }
  492. }
  493. Result = RegOpenKeyEx( LsaKey, TEXT("Data"), 0,
  494. KEY_READ, &Key );
  495. if ( Result == 0 )
  496. {
  497. Size = 9 ;
  498. Result = RegQueryInfoKeyA( Key,
  499. Class,
  500. &Size,
  501. NULL, NULL, NULL,
  502. NULL, NULL, NULL,
  503. NULL, NULL, NULL );
  504. RegCloseKey( Key );
  505. if ( Result == 0 )
  506. {
  507. for ( i = 0 ; i < 8 ; i += 2 )
  508. {
  509. t = FromHex( Class[ i ] );
  510. t2 = FromHex( Class[ i+1 ] );
  511. if ( (t >= 0 ) && ( t2 >= 0 ) )
  512. {
  513. *j++ = (t << 4) + t2 ;
  514. }
  515. else
  516. {
  517. RegCloseKey(LsaKey);
  518. return FALSE ;
  519. }
  520. }
  521. }
  522. }
  523. for ( i = 0 ; i < 16 ; i++ )
  524. {
  525. Hash->Digest[ KeyShuffle[ i ] ] = ProtoHash.Digest[ i ] ;
  526. }
  527. RegCloseKey(LsaKey);
  528. return TRUE ;
  529. }
  530. NTSTATUS
  531. WxSaveSysKey(
  532. IN ULONG Keylen,
  533. IN PVOID Key
  534. )
  535. /*++
  536. Routine Description
  537. This routine is used to store the syskey
  538. in the registry
  539. Paramaeters
  540. Keylen - the length of the key
  541. Key the actual key itself
  542. Return Values
  543. STATUS_SUCCESS
  544. STATUS_UNSUCCESSFUL
  545. --*/
  546. {
  547. WXHASH H;
  548. //
  549. // key should be 128 bits
  550. //
  551. if (Keylen!=sizeof(H.Digest))
  552. return (STATUS_INVALID_PARAMETER);
  553. RtlCopyMemory(&H.Digest,
  554. Key,
  555. Keylen
  556. );
  557. if (WxpObfuscateKey(&H))
  558. {
  559. return(STATUS_SUCCESS);
  560. }
  561. else
  562. {
  563. return(STATUS_UNSUCCESSFUL);
  564. }
  565. }
  566. NTSTATUS
  567. WxReadSysKey(
  568. IN OUT PULONG BufferLength,
  569. OUT PVOID Key
  570. )
  571. /*++
  572. Routine Description
  573. This routine is used to retrieve the syskey from
  574. the registry
  575. Paramaeters
  576. BufferLength is filled in with the length required on output
  577. is used to indicate the size of the buffer
  578. pointed to by Key.
  579. Key Points to a buffer into which the key is recieved
  580. Return Values
  581. STATUS_SUCCESS
  582. STATUS_UNSUCCESSFUL
  583. --*/
  584. {
  585. return WxReadSysKeyEx(
  586. NULL,
  587. BufferLength,
  588. Key
  589. );
  590. }
  591. NTSTATUS
  592. WxReadSysKeyEx(
  593. IN HKEY Handle,
  594. IN OUT PULONG BufferLength,
  595. OUT PVOID Key
  596. )
  597. /*++
  598. Routine Description
  599. This routine is used to retrieve the syskey from
  600. the registry
  601. Paramaeters
  602. Handle Contains a pointer to the syskey in the old registry
  603. BufferLength is filled in with the length required on output
  604. is used to indicate the size of the buffer
  605. pointed to by Key.
  606. Key Points to a buffer into which the key is recieved
  607. Return Values
  608. STATUS_SUCCESS
  609. STATUS_UNSUCCESSFUL
  610. --*/
  611. {
  612. WXHASH H;
  613. if ((NULL==Key) || (*BufferLength <sizeof(H.Digest)))
  614. {
  615. *BufferLength = sizeof(H.Digest);
  616. return(STATUS_BUFFER_OVERFLOW);
  617. }
  618. if (WxpDeObfuscateKey(Handle,&H))
  619. {
  620. *BufferLength = sizeof(H.Digest);
  621. RtlCopyMemory(
  622. Key,
  623. &H.Digest,
  624. *BufferLength
  625. );
  626. return(STATUS_SUCCESS);
  627. }
  628. return (STATUS_UNSUCCESSFUL);
  629. }
  630. NTSTATUS
  631. WxLoadSysKeyFromDisk(OUT PVOID Key,
  632. OUT PULONG BufferLength
  633. )
  634. /*++
  635. Routine Description
  636. This routine is used to read the syskey
  637. from the Disk
  638. Paramaeters
  639. Key - buffer where the key will be read into
  640. BufferLength - size of the returned key
  641. Return Values
  642. STATUS_OBJECT_NAME_NOT_FOUND
  643. STATUS_FILE_CORRUPT_ERROR
  644. STATUS_UNSUCCESSFUL
  645. --*/
  646. {
  647. HANDLE hFile ;
  648. ULONG Actual ;
  649. ULONG ErrorMode ;
  650. LPSTR SysKeyFileName = "A:\\startkey.key";
  651. ErrorMode = SetErrorMode( SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX );
  652. hFile = CreateFileA( SysKeyFileName,
  653. GENERIC_READ,
  654. 0,
  655. NULL,
  656. OPEN_EXISTING,
  657. FILE_ATTRIBUTE_NORMAL,
  658. NULL );
  659. if ( hFile == INVALID_HANDLE_VALUE )
  660. {
  661. SetErrorMode( ErrorMode );
  662. return STATUS_OBJECT_NAME_NOT_FOUND ;
  663. }
  664. if (!ReadFile( hFile, Key, SYSKEY_SIZE, &Actual, NULL ) ||
  665. (Actual != SYSKEY_SIZE ))
  666. {
  667. SetErrorMode( ErrorMode );
  668. CloseHandle( hFile );
  669. return STATUS_FILE_CORRUPT_ERROR ;
  670. }
  671. SetErrorMode( ErrorMode );
  672. CloseHandle( hFile );
  673. *BufferLength = SYSKEY_SIZE;
  674. return STATUS_SUCCESS;
  675. }
  676. NTSTATUS
  677. WxHashKey(
  678. IN OUT LPWSTR key, //will be killed
  679. OUT PVOID SysKey,
  680. IN OUT DWORD cbSysKey
  681. )
  682. /*++
  683. Routine Description
  684. This routine is used to store the boot type
  685. in the registry
  686. Paramaeters
  687. NewType Indicates the new boot type
  688. Return Values
  689. STATUS_SUCCESS
  690. STATUS_UNSUCCESSFUL
  691. --*/
  692. {
  693. MD5_CTX Md5;
  694. if(cbSysKey<SYSKEY_SIZE) {
  695. return STATUS_BUFFER_TOO_SMALL;
  696. }
  697. cbSysKey=wcslen(key)*sizeof(WCHAR);
  698. MD5Init( &Md5 );
  699. MD5Update( &Md5, (PUCHAR) key, cbSysKey );
  700. MD5Final( &Md5 );
  701. ZeroMemory( key, cbSysKey );
  702. cbSysKey=SYSKEY_SIZE;
  703. CopyMemory( SysKey, Md5.digest, cbSysKey );
  704. return STATUS_SUCCESS;
  705. }
  706. NTSTATUS
  707. WxSaveBootOption( WX_AUTH_TYPE NewType )
  708. /*++
  709. Routine Description
  710. This routine is used to store the boot type
  711. in the registry
  712. Paramaeters
  713. NewType Indicates the new boot type
  714. Return Values
  715. STATUS_SUCCESS
  716. STATUS_UNSUCCESSFUL
  717. --*/
  718. {
  719. HKEY LsaKey;
  720. ULONG err;
  721. err = RegOpenKeyExW( HKEY_LOCAL_MACHINE,
  722. L"System\\CurrentControlSet\\Control\\Lsa",
  723. 0,
  724. KEY_READ | KEY_WRITE,
  725. & LsaKey );
  726. if (0!=err)
  727. {
  728. return (STATUS_UNSUCCESSFUL);
  729. }
  730. err = RegSetValueExW(
  731. LsaKey,
  732. SYSTEM_KEY,
  733. 0,
  734. REG_DWORD,
  735. (PUCHAR) &NewType,
  736. sizeof( NewType )
  737. );
  738. if (0!=err)
  739. {
  740. RegCloseKey(LsaKey);
  741. return (STATUS_UNSUCCESSFUL);
  742. }
  743. RegCloseKey(LsaKey);
  744. return ( STATUS_SUCCESS);
  745. }