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.

1775 lines
55 KiB

  1. /*************************************************************************
  2. *
  3. * reguc.c
  4. *
  5. * Registry APIs for SAM-based user configuration data
  6. *
  7. * Copyright (c) 1998 Microsoft Corporation
  8. *
  9. *
  10. *
  11. *************************************************************************/
  12. /*
  13. * Includes
  14. */
  15. #include <nt.h>
  16. #include <ntrtl.h>
  17. #include <nturtl.h>
  18. #include <ntlsa.h>
  19. #include <ntsam.h>
  20. #include <stdio.h>
  21. #include <string.h>
  22. #include <windows.h>
  23. #include <lm.h>
  24. #include <ntddkbd.h>
  25. #include <ntddmou.h>
  26. #include <winstaw.h>
  27. #include <regapi.h>
  28. #include <regsam.h>
  29. #include <rpc.h>
  30. #include <rpcdce.h>
  31. #include <ntdsapi.h>
  32. // For more info, check out \\index1\src\nt\private\security\tools\delegate\ldap.c
  33. #include "usrprop.h"
  34. /*
  35. * !!! WARNING !!! WARNING !!!
  36. *
  37. * A lot of time could be spent on making this calculation accurate and
  38. * automatic, but time is of the essence. So a brute force
  39. * approach is used. The size of the User Configuration section that
  40. * Citrix is going to add to the User Parameters is based on NOT
  41. * ONLY the size of the USERCONFIG structure, but must account for the
  42. * Value names and the buffer management pointers as well, since the
  43. * User Parameters section is a linear buffer that holds CITRIX data
  44. * and Microsoft Services for Netware data.
  45. *
  46. * It is assumed that the overhead of the value name strings and
  47. * the buffer management pointers will NOT be greater than twice the
  48. * maximum data size. If this assumption is false, buffer overruns
  49. * will occur.
  50. *
  51. * Bruce Fortune. 1/31/97.
  52. */
  53. #define CTX_USER_PARAM_MAX_SIZE (3 * sizeof(USERCONFIG))
  54. /*
  55. * CTXPREFIX is the prefix for all value names placed in the User
  56. * Parameters section of the SAM. This is a defensive measure since
  57. * this section of the SAM is shared with MS Services for Netware.
  58. */
  59. #define CTXPREFIX L"Ctx"
  60. /*
  61. * WIN_FLAGS1 is the name of the Flags value that is used to hold
  62. * all of the F1MSK_... flags defined below. This is done in order to
  63. * reduce the amount of space required in the User Parameters section
  64. * of the SAM, since the value name of each flag is eliminated.
  65. */
  66. #define WIN_FLAGS1 L"CfgFlags1"
  67. /*
  68. * WIN_CFGPRESENT is used to indicate that the Citrix configuration
  69. * information is present in the User Parameters section of the user's
  70. * SAM record.
  71. */
  72. #define WIN_CFGPRESENT L"CfgPresent"
  73. #define CFGPRESENT_VALUE 0xB00B1E55
  74. #define F1MSK_INHERITAUTOLOGON 0x80000000
  75. #define F1MSK_INHERITRESETBROKEN 0x40000000
  76. #define F1MSK_INHERITRECONNECTSAME 0x20000000
  77. #define F1MSK_INHERITINITIALPROGRAM 0x10000000
  78. #define F1MSK_INHERITCALLBACK 0x08000000
  79. #define F1MSK_INHERITCALLBACKNUMBER 0x04000000
  80. #define F1MSK_INHERITSHADOW 0x02000000
  81. #define F1MSK_INHERITMAXSESSIONTIME 0x01000000
  82. #define F1MSK_INHERITMAXDISCONNECTIONTIME 0x00800000
  83. #define F1MSK_INHERITMAXIDLETIME 0x00400000
  84. #define F1MSK_INHERITAUTOCLIENT 0x00200000
  85. #define F1MSK_INHERITSECURITY 0x00100000
  86. #define F1MSK_PROMPTFORPASSWORD 0x00080000
  87. #define F1MSK_RESETBROKEN 0x00040000
  88. #define F1MSK_RECONNECTSAME 0x00020000
  89. #define F1MSK_LOGONDISABLED 0x00010000
  90. #define F1MSK_AUTOCLIENTDRIVES 0x00008000
  91. #define F1MSK_AUTOCLIENTLPTS 0x00004000
  92. #define F1MSK_FORCECLIENTLPTDEF 0x00002000
  93. #define F1MSK_DISABLEENCRYPTION 0x00001000
  94. #define F1MSK_HOMEDIRECTORYMAPROOT 0x00000800
  95. #define F1MSK_USEDEFAULTGINA 0x00000400
  96. #define F1MSK_DISABLECPM 0x00000200
  97. #define F1MSK_DISABLECDM 0x00000100
  98. #define F1MSK_DISABLECCM 0x00000080
  99. #define F1MSK_DISABLELPT 0x00000040
  100. #define F1MSK_DISABLECLIP 0x00000020
  101. #define F1MSK_DISABLEEXE 0x00000010
  102. #define F1MSK_WALLPAPERDISABLED 0x00000008
  103. #define F1MSK_DISABLECAM 0x00000004
  104. //#define F1MSK_unused 0x00000002
  105. //#define F1MSK_unused 0x00000001
  106. VOID AnsiToUnicode( WCHAR *, ULONG, CHAR * );
  107. NTSTATUS GetDomainName ( PWCHAR, PWCHAR * );
  108. ULONG GetFlagMask( PUSERCONFIG );
  109. VOID QueryUserConfig( HKEY, PUSERCONFIG );
  110. /*******************************************************************************
  111. *
  112. * UsrPropSetValue (UNICODE)
  113. *
  114. * Sets a 1-, 2-, or 4-byte value into the supplied User Parameters buffer
  115. *
  116. * ENTRY:
  117. * pValueName (input)
  118. * Points to the Value Name string
  119. * pValue (input)
  120. * Points to value
  121. * ValueLength (input)
  122. * Number of bytes in the Value
  123. * pUserParms (input)
  124. * Points to the specially formatted User Parameters buffer
  125. * UserParmsLength (input)
  126. * Length in bytes of the pUserParms buffer
  127. *
  128. * EXIT:
  129. * STATUS_SUCCESS - no error
  130. *
  131. ******************************************************************************/
  132. NTSTATUS
  133. UsrPropSetValue(
  134. WCHAR * pValueName,
  135. PVOID pValue,
  136. USHORT ValueLength,
  137. BOOL fDefaultValue,
  138. WCHAR * pUserParms,
  139. ULONG UserParmsLength
  140. )
  141. {
  142. NTSTATUS Status = STATUS_SUCCESS;
  143. UNICODE_STRING uniValue;
  144. LPWSTR lpNewUserParms = NULL;
  145. BOOL fUpdate;
  146. PWCHAR pNameBuf;
  147. ULONG NBLen;
  148. /*
  149. * Prefix the name with a unique string so that other users of
  150. * the user parameters section of the SAM won't collide with our
  151. * value names.
  152. */
  153. NBLen = sizeof(CTXPREFIX) + ((wcslen(pValueName) + 1) * sizeof(WCHAR));
  154. pNameBuf = (PWCHAR) LocalAlloc( LPTR, NBLen );
  155. if ( !pNameBuf ) {
  156. return( STATUS_INSUFFICIENT_RESOURCES );
  157. }
  158. wcscpy( pNameBuf, CTXPREFIX );
  159. wcscat( pNameBuf, pValueName );
  160. uniValue.Buffer = (PWCHAR) pValue;
  161. uniValue.Length = ValueLength;
  162. uniValue.MaximumLength = uniValue.Length;
  163. Status = SetUserProperty( pUserParms,
  164. pNameBuf,
  165. uniValue,
  166. USER_PROPERTY_TYPE_ITEM,
  167. fDefaultValue,
  168. &lpNewUserParms,
  169. &fUpdate );
  170. LocalFree( pNameBuf );
  171. if ((Status == STATUS_SUCCESS) && (lpNewUserParms != NULL)) {
  172. if (fUpdate) {
  173. if ( (wcslen( lpNewUserParms ) * sizeof(WCHAR)) > UserParmsLength ) {
  174. return( STATUS_BUFFER_TOO_SMALL );
  175. }
  176. lstrcpyW( pUserParms, lpNewUserParms);
  177. }
  178. LocalFree( lpNewUserParms );
  179. }
  180. return( Status );
  181. }
  182. /*******************************************************************************
  183. *
  184. * UsrPropGetValue (UNICODE)
  185. *
  186. * Gets a value from the supplied User Parameters buffer
  187. *
  188. * ENTRY:
  189. * pValuegName (input)
  190. * Points to the Value Name string
  191. * pValue (output)
  192. * Points to the buffer to receive the value
  193. * ValueLength (input)
  194. * Number of bytes in the buffer pointer to by pValue
  195. * pUserParms (input)
  196. * Points to the specially formatted User Parameters buffer
  197. *
  198. * EXIT:
  199. * STATUS_SUCCESS - no error
  200. *
  201. ******************************************************************************/
  202. NTSTATUS
  203. UsrPropGetValue(
  204. TCHAR * pValueName,
  205. PVOID pValue,
  206. ULONG ValueLength,
  207. WCHAR * pUserParms
  208. )
  209. {
  210. NTSTATUS Status = STATUS_SUCCESS;
  211. UNICODE_STRING uniValue;
  212. WCHAR Flag;
  213. PWCHAR pNameBuf;
  214. ULONG NBLen;
  215. /*
  216. * Prefix the name with a unique string so that other users of
  217. * the user parameters section of the SAM won't collide with our
  218. * usage.
  219. */
  220. NBLen = sizeof(CTXPREFIX) + ((wcslen(pValueName) + 1) * sizeof(WCHAR));
  221. pNameBuf = (PWCHAR) LocalAlloc( LPTR, NBLen );
  222. if ( !pNameBuf ) {
  223. return( STATUS_INSUFFICIENT_RESOURCES );
  224. }
  225. wcscpy( pNameBuf, CTXPREFIX );
  226. wcscat( pNameBuf, pValueName );
  227. Status = QueryUserProperty( pUserParms, pNameBuf, &Flag, &uniValue );
  228. LocalFree( pNameBuf );
  229. if ( Status != STATUS_SUCCESS ) {
  230. return( Status );
  231. }
  232. if ( !uniValue.Buffer ) {
  233. memset( pValue, 0, ValueLength );
  234. } else {
  235. memcpy( pValue, uniValue.Buffer, ValueLength );
  236. LocalFree( uniValue.Buffer );
  237. }
  238. return( Status );
  239. }
  240. /*******************************************************************************
  241. *
  242. * UsrPropSetString (UNICODE)
  243. *
  244. * Sets a variable length string into the supplied User Parameters buffer
  245. *
  246. * ENTRY:
  247. * pStringName (input)
  248. * Points to the String Name string
  249. * pStringValue (input)
  250. * Points to the string
  251. * pUserParms (input)
  252. * Points to the specially formatted User Parameters buffer
  253. * UserParmsLength (input)
  254. * Length in bytes of the pUserParms buffer
  255. * fDefaultValue
  256. * Indicates that this value is a default value and should not be saved
  257. *
  258. * EXIT:
  259. * STATUS_SUCCESS - no error
  260. *
  261. ******************************************************************************/
  262. NTSTATUS
  263. UsrPropSetString(
  264. WCHAR * pStringName,
  265. WCHAR * pStringValue,
  266. WCHAR * pUserParms,
  267. ULONG UserParmsLength,
  268. BOOL fDefaultValue
  269. )
  270. {
  271. NTSTATUS Status = STATUS_SUCCESS;
  272. UNICODE_STRING uniString;
  273. CHAR * pchTemp = NULL;
  274. LPWSTR lpNewUserParms = NULL;
  275. BOOL fUpdate;
  276. PWCHAR pNameBuf;
  277. ULONG NBLen;
  278. INT nMBLen;
  279. if (pStringValue == NULL) {
  280. uniString.Buffer = NULL;
  281. uniString.Length = 0;
  282. uniString.MaximumLength = 0;
  283. }
  284. else
  285. {
  286. BOOL fDummy;
  287. INT nStringLength = lstrlen(pStringValue) + 1;
  288. // Determine the length of the mulitbyte string
  289. // allocate it and convert to
  290. // this fixes bug 264907
  291. // Next release we'll need to change from ansi code page to
  292. // UTF8.
  293. nMBLen = WideCharToMultiByte(CP_ACP,
  294. 0,
  295. pStringValue,
  296. nStringLength,
  297. pchTemp,
  298. 0,
  299. NULL,
  300. NULL );
  301. pchTemp = ( CHAR * )LocalAlloc( LPTR , nMBLen );
  302. if ( pchTemp == NULL )
  303. {
  304. #ifdef DBG
  305. OutputDebugString( L"REGAPI : UsrPropSetString - STATUS_INSUFFICIENT_RESOURCES\n" );
  306. #endif
  307. Status = STATUS_INSUFFICIENT_RESOURCES;
  308. }
  309. else if( !WideCharToMultiByte( CP_ACP,
  310. 0 ,
  311. pStringValue ,
  312. nStringLength ,
  313. pchTemp ,
  314. nMBLen ,
  315. NULL ,
  316. NULL ) )
  317. {
  318. #ifdef DBG
  319. // OutputDebugString( L"REGAPI : UsrPropSetString - STATUS_UNSUCCESSFUL wctomb failed.\n" );
  320. DbgPrint( "REGAPI : UsrPropSetString - STATUS_UNSUCCESSFUL wctomb failed with 0x%x.\n" , GetLastError( ) );
  321. #endif
  322. Status = STATUS_UNSUCCESSFUL;
  323. }
  324. if( Status == STATUS_SUCCESS )
  325. {
  326. uniString.Buffer = (WCHAR *) pchTemp;
  327. uniString.Length = (USHORT)nMBLen;
  328. uniString.MaximumLength = (USHORT)nMBLen;
  329. }
  330. }
  331. /*
  332. * Prefix the name with a unique string so that other users of
  333. * the user parameters section of the SAM won't collide with our
  334. * usage.
  335. */
  336. NBLen = sizeof(CTXPREFIX) + ((wcslen(pStringName) + 1) * sizeof(WCHAR));
  337. pNameBuf = (PWCHAR) LocalAlloc( LPTR, NBLen );
  338. if ( !pNameBuf ) {
  339. return( STATUS_INSUFFICIENT_RESOURCES );
  340. }
  341. wcscpy( pNameBuf, CTXPREFIX );
  342. wcscat( pNameBuf, pStringName );
  343. Status = Status ? Status : SetUserProperty( pUserParms,
  344. pNameBuf,
  345. uniString,
  346. USER_PROPERTY_TYPE_ITEM,
  347. fDefaultValue,
  348. &lpNewUserParms,
  349. &fUpdate );
  350. LocalFree( pNameBuf );
  351. if ( (Status == STATUS_SUCCESS) && (lpNewUserParms != NULL))
  352. {
  353. if ( fUpdate )
  354. {
  355. if ( (wcslen( lpNewUserParms ) * sizeof(WCHAR)) > UserParmsLength )
  356. {
  357. return( STATUS_BUFFER_TOO_SMALL );
  358. }
  359. lstrcpyW( pUserParms, lpNewUserParms);
  360. }
  361. LocalFree( lpNewUserParms );
  362. }
  363. if ( pchTemp != NULL )
  364. {
  365. LocalFree( pchTemp );
  366. }
  367. return( Status );
  368. }
  369. /*******************************************************************************
  370. *
  371. * UsrPropGetString (UNICODE)
  372. *
  373. * Gets a variable length string from the supplied User Parameters buffer
  374. *
  375. * ENTRY:
  376. * pStringName (input)
  377. * Points to the String Name string
  378. * pStringValue (output)
  379. * Points to the string
  380. * StringValueLength (input)
  381. * Number of bytes in the buffer pointer to by pStringValue
  382. * pUserParms (input)
  383. * Points to the specially formatted User Parameters buffer
  384. *
  385. * EXIT:
  386. * STATUS_SUCCESS - no error
  387. *
  388. ******************************************************************************/
  389. NTSTATUS
  390. UsrPropGetString(
  391. TCHAR * pStringName,
  392. TCHAR * pStringValue,
  393. ULONG StringValueLength,
  394. WCHAR * pUserParms
  395. )
  396. {
  397. NTSTATUS Status = STATUS_SUCCESS;
  398. UNICODE_STRING uniString;
  399. WCHAR Flag;
  400. PWCHAR pNameBuf;
  401. ULONG NBLen;
  402. /*
  403. * Prefix the name with a unique string so that other users of
  404. * the user parameters section of the SAM won't collide with our
  405. * usage.
  406. */
  407. NBLen = sizeof(CTXPREFIX) + ((wcslen(pStringName) + 1) * sizeof(WCHAR));
  408. pNameBuf = (PWCHAR) LocalAlloc( LPTR, NBLen );
  409. if ( !pNameBuf ) {
  410. return( STATUS_INSUFFICIENT_RESOURCES );
  411. }
  412. wcscpy( pNameBuf, CTXPREFIX );
  413. wcscat( pNameBuf, pStringName );
  414. pStringValue[0] = L'\0';
  415. Status = QueryUserProperty( pUserParms, pNameBuf, &Flag, &uniString );
  416. LocalFree( pNameBuf );
  417. if ( !( Status == STATUS_SUCCESS && uniString.Length && uniString.Buffer) ) {
  418. pStringValue[0] = L'\0';
  419. } else {
  420. if ( !MultiByteToWideChar( CP_ACP,
  421. 0,
  422. (CHAR *)uniString.Buffer,
  423. uniString.Length,
  424. pStringValue,
  425. StringValueLength ) ) {
  426. Status = STATUS_UNSUCCESSFUL;
  427. }
  428. }
  429. if ( uniString.Buffer ) {
  430. LocalFree( uniString.Buffer );
  431. }
  432. return( Status );
  433. }
  434. /*******************************************************************************
  435. *
  436. * ConnectToSAM (UNICODE)
  437. *
  438. * Given a Server name and a Domain name, connect to the SAM
  439. *
  440. * ENTRY:
  441. * pServerName (input)
  442. * Points to the Server name
  443. * pDomainValue (input)
  444. * Points to the Domain name
  445. * pSAMHandle (output)
  446. * Pointer to the Handle to the SAM
  447. * pDomainHandle (output)
  448. * Pointer to the Handle to the Domain
  449. * pDomainID (ouptut)
  450. * Pointer to the Domain SID
  451. *
  452. * EXIT:
  453. * STATUS_SUCCESS - no error
  454. *
  455. ******************************************************************************/
  456. NTSTATUS
  457. ConnectToSam(
  458. BOOLEAN fReadOnly,
  459. LPTSTR pServerName,
  460. LPTSTR pDomainName,
  461. SAM_HANDLE * pSAMHandle,
  462. SAM_HANDLE * pDomainHandle,
  463. PSID * pDomainID
  464. )
  465. {
  466. NTSTATUS status;
  467. OBJECT_ATTRIBUTES object_attrib;
  468. UNICODE_STRING UniDomainName;
  469. UNICODE_STRING UniServerName;
  470. *pSAMHandle = NULL;
  471. *pDomainHandle = NULL;
  472. *pDomainID = NULL;
  473. //
  474. // connect to SAM (Security Account Manager)
  475. //
  476. #ifdef DEBUG
  477. DbgPrint( "ConnectToSam: pServerName %ws, pDomainName %ws\n", pServerName, pDomainName );
  478. #endif // DEBUG
  479. RtlInitUnicodeString(&UniServerName, pServerName);
  480. RtlInitUnicodeString(&UniDomainName, pDomainName);
  481. InitializeObjectAttributes(&object_attrib, NULL, 0, NULL, NULL);
  482. status = SamConnect( &UniServerName,
  483. pSAMHandle,
  484. fReadOnly
  485. ? SAM_SERVER_READ |
  486. SAM_SERVER_EXECUTE
  487. : STANDARD_RIGHTS_WRITE |
  488. SAM_SERVER_EXECUTE,
  489. &object_attrib );
  490. #ifdef DEBUG
  491. DbgPrint( "ConnectToSam: SamConnect returned NTSTATUS = 0x%x\n", status );
  492. #endif // DEBUG
  493. if ( status != STATUS_SUCCESS ) {
  494. goto exit;
  495. }
  496. status = SamLookupDomainInSamServer( *pSAMHandle,
  497. &UniDomainName,
  498. pDomainID);
  499. #ifdef DEBUG
  500. DbgPrint( "ConnectToSam: SamLookupDomainInSamServer returned NTSTATUS = 0x%x\n", status );
  501. #endif // DEBUG
  502. if ( status != STATUS_SUCCESS ) {
  503. goto cleanupconnect;
  504. }
  505. status = SamOpenDomain( *pSAMHandle,
  506. fReadOnly
  507. ? DOMAIN_READ |
  508. DOMAIN_LOOKUP |
  509. DOMAIN_READ_PASSWORD_PARAMETERS
  510. : DOMAIN_READ |
  511. DOMAIN_CREATE_ALIAS |
  512. DOMAIN_LOOKUP |
  513. DOMAIN_CREATE_USER |
  514. DOMAIN_READ_PASSWORD_PARAMETERS,
  515. *pDomainID,
  516. pDomainHandle );
  517. #ifdef DEBUG
  518. DbgPrint( "ConnectToSam: SamOpenDomain returned NTSTATUS = 0x%x\n", status );
  519. #endif // DEBUG
  520. if ( status != STATUS_SUCCESS ) {
  521. goto cleanuplookup;
  522. }
  523. return( STATUS_SUCCESS );
  524. /*
  525. * Error returns
  526. */
  527. cleanuplookup:
  528. SamFreeMemory( *pDomainID );
  529. *pDomainID = NULL;
  530. cleanupconnect:
  531. SamCloseHandle( *pSAMHandle );
  532. *pSAMHandle = NULL;
  533. exit:
  534. return( status );
  535. }
  536. /*******************************************************************************
  537. *
  538. * UsrPropQueryUserConfig
  539. *
  540. * Query USERCONFIG info from SAM's User Parameters
  541. *
  542. * ENTRY:
  543. * pUserParms (input)
  544. * pointer to a wide char buffer containing the SAM's User Parameters
  545. * UPlength (input )
  546. * length of the pUserParms buffer
  547. * pUser (output)
  548. * pointer to USERCONFIG structure
  549. *
  550. * EXIT:
  551. * STATUS_SUCCESS - no error
  552. *
  553. ******************************************************************************/
  554. NTSTATUS
  555. UsrPropQueryUserConfig(
  556. WCHAR *pUserParms,
  557. ULONG UPLength,
  558. PUSERCONFIG pUser )
  559. {
  560. ULONG Flags1;
  561. NTSTATUS Status;
  562. ULONG CfgPresent;
  563. USERCONFIG ucDefault;
  564. QueryUserConfig( HKEY_LOCAL_MACHINE , &ucDefault );
  565. /*
  566. * Check if the configuration exits in the User Parameters
  567. */
  568. if( ( ( Status = UsrPropGetValue( WIN_CFGPRESENT,
  569. &CfgPresent,
  570. sizeof(CfgPresent),
  571. pUserParms ) ) != NO_ERROR ) )
  572. {
  573. KdPrint( ( "UsrPropQueryUserConfig: UsrPropGetValue returned NTSTATUS = 0x%x\n", Status ) );
  574. return( Status );
  575. }
  576. else
  577. {
  578. if( CfgPresent != CFGPRESENT_VALUE )
  579. {
  580. KdPrint( ( "UsrPropQueryUserConfig: UsrPropGetValue returned NTSTATUS = 0x%x but TS-signature was not present\n", Status ) );
  581. return( STATUS_OBJECT_NAME_NOT_FOUND );
  582. }
  583. }
  584. Status = UsrPropGetValue( WIN_FLAGS1,
  585. &Flags1,
  586. sizeof(Flags1),
  587. pUserParms );
  588. if( NT_SUCCESS( Status ) )
  589. {
  590. Status = UsrPropGetValue( WIN_CALLBACK,
  591. &pUser->Callback,
  592. sizeof(pUser->Callback),
  593. pUserParms );
  594. if( Status == STATUS_OBJECT_NAME_NOT_FOUND )
  595. {
  596. pUser->Callback = ucDefault.Callback;
  597. Status = STATUS_SUCCESS;
  598. }
  599. }
  600. if( NT_SUCCESS( Status ) )
  601. {
  602. Status = UsrPropGetValue( WIN_SHADOW,
  603. &pUser->Shadow,
  604. sizeof(pUser->Shadow),
  605. pUserParms );
  606. if( Status == STATUS_OBJECT_NAME_NOT_FOUND )
  607. {
  608. pUser->Shadow = ucDefault.Shadow;
  609. Status = STATUS_SUCCESS;
  610. }
  611. }
  612. if( NT_SUCCESS( Status ) )
  613. {
  614. Status = UsrPropGetValue( WIN_MAXCONNECTIONTIME,
  615. &pUser->MaxConnectionTime,
  616. sizeof(pUser->MaxConnectionTime),
  617. pUserParms );
  618. if( Status == STATUS_OBJECT_NAME_NOT_FOUND )
  619. {
  620. pUser->MaxConnectionTime = ucDefault.MaxConnectionTime;
  621. Status = STATUS_SUCCESS;
  622. }
  623. }
  624. if( NT_SUCCESS( Status ) )
  625. {
  626. Status = UsrPropGetValue( WIN_MAXDISCONNECTIONTIME,
  627. &pUser->MaxDisconnectionTime,
  628. sizeof(pUser->MaxDisconnectionTime),
  629. pUserParms );
  630. if( Status == STATUS_OBJECT_NAME_NOT_FOUND )
  631. {
  632. pUser->MaxDisconnectionTime = ucDefault.MaxDisconnectionTime;
  633. Status = STATUS_SUCCESS;
  634. }
  635. }
  636. if( NT_SUCCESS( Status ) )
  637. {
  638. Status = UsrPropGetValue( WIN_MAXIDLETIME,
  639. &pUser->MaxIdleTime,
  640. sizeof(pUser->MaxIdleTime),
  641. pUserParms );
  642. if( Status == STATUS_OBJECT_NAME_NOT_FOUND )
  643. {
  644. pUser->MaxIdleTime = ucDefault.MaxIdleTime;
  645. Status = STATUS_SUCCESS;
  646. }
  647. }
  648. if( NT_SUCCESS( Status ) )
  649. {
  650. Status = UsrPropGetValue( WIN_KEYBOARDLAYOUT,
  651. &pUser->KeyboardLayout,
  652. sizeof(pUser->KeyboardLayout),
  653. pUserParms );
  654. if( Status == STATUS_OBJECT_NAME_NOT_FOUND )
  655. {
  656. pUser->KeyboardLayout = ucDefault.KeyboardLayout;
  657. Status = STATUS_SUCCESS;
  658. }
  659. }
  660. if( NT_SUCCESS( Status ) )
  661. {
  662. Status = UsrPropGetValue( WIN_MINENCRYPTIONLEVEL,
  663. &pUser->MinEncryptionLevel,
  664. sizeof(pUser->MinEncryptionLevel),
  665. pUserParms );
  666. if( Status == STATUS_OBJECT_NAME_NOT_FOUND )
  667. {
  668. pUser->MinEncryptionLevel = ucDefault.MinEncryptionLevel;
  669. Status = STATUS_SUCCESS;
  670. }
  671. }
  672. // String properties that do not exist are init to NULL
  673. // default values are null so need to fix if ret status is a failure.
  674. if( NT_SUCCESS( Status ) )
  675. {
  676. Status = UsrPropGetString( WIN_WORKDIRECTORY,
  677. pUser->WorkDirectory,
  678. sizeof(pUser->WorkDirectory),
  679. pUserParms );
  680. if( Status == STATUS_OBJECT_NAME_NOT_FOUND )
  681. {
  682. Status = STATUS_SUCCESS;
  683. }
  684. }
  685. if( NT_SUCCESS( Status ) )
  686. {
  687. Status = UsrPropGetString( WIN_NWLOGONSERVER,
  688. pUser->NWLogonServer,
  689. sizeof(pUser->NWLogonServer),
  690. pUserParms );
  691. if( Status == STATUS_OBJECT_NAME_NOT_FOUND )
  692. {
  693. Status = STATUS_SUCCESS;
  694. }
  695. }
  696. if( NT_SUCCESS( Status ) )
  697. {
  698. Status = UsrPropGetString( WIN_WFHOMEDIR,
  699. pUser->WFHomeDir,
  700. sizeof(pUser->WFHomeDir),
  701. pUserParms );
  702. if( Status == STATUS_OBJECT_NAME_NOT_FOUND )
  703. {
  704. Status = STATUS_SUCCESS;
  705. }
  706. }
  707. if( NT_SUCCESS( Status ) )
  708. {
  709. Status = UsrPropGetString( WIN_WFHOMEDIRDRIVE,
  710. pUser->WFHomeDirDrive,
  711. sizeof(pUser->WFHomeDir),
  712. pUserParms );
  713. if( Status == STATUS_OBJECT_NAME_NOT_FOUND )
  714. {
  715. Status = STATUS_SUCCESS;
  716. }
  717. }
  718. if( NT_SUCCESS( Status ) )
  719. {
  720. Status = UsrPropGetString( WIN_WFPROFILEPATH,
  721. pUser->WFProfilePath,
  722. sizeof(pUser->WFProfilePath),
  723. pUserParms );
  724. if( Status == STATUS_OBJECT_NAME_NOT_FOUND )
  725. {
  726. Status = STATUS_SUCCESS;
  727. }
  728. }
  729. if( NT_SUCCESS( Status ) )
  730. {
  731. Status = UsrPropGetString( WIN_INITIALPROGRAM,
  732. pUser->InitialProgram,
  733. sizeof(pUser->InitialProgram),
  734. pUserParms );
  735. if( Status == STATUS_OBJECT_NAME_NOT_FOUND )
  736. {
  737. Status = STATUS_SUCCESS;
  738. }
  739. }
  740. if( NT_SUCCESS( Status ) )
  741. {
  742. Status = UsrPropGetString( WIN_CALLBACKNUMBER,
  743. pUser->CallbackNumber,
  744. sizeof(pUser->CallbackNumber),
  745. pUserParms );
  746. if( Status == STATUS_OBJECT_NAME_NOT_FOUND )
  747. {
  748. Status = STATUS_SUCCESS;
  749. }
  750. }
  751. if( !( NT_SUCCESS( Status ) ) )
  752. {
  753. return( Status );
  754. }
  755. pUser->fInheritAutoLogon =
  756. Flags1 & F1MSK_INHERITAUTOLOGON ? TRUE : FALSE;
  757. pUser->fInheritResetBroken =
  758. Flags1 & F1MSK_INHERITRESETBROKEN ? TRUE : FALSE;
  759. pUser->fInheritReconnectSame =
  760. Flags1 & F1MSK_INHERITRECONNECTSAME ? TRUE : FALSE;
  761. pUser->fInheritInitialProgram =
  762. Flags1 & F1MSK_INHERITINITIALPROGRAM ? TRUE : FALSE;
  763. pUser->fInheritCallback =
  764. Flags1 & F1MSK_INHERITCALLBACK ? TRUE : FALSE;
  765. pUser->fInheritCallbackNumber =
  766. Flags1 & F1MSK_INHERITCALLBACKNUMBER ? TRUE : FALSE;
  767. pUser->fInheritShadow =
  768. Flags1 & F1MSK_INHERITSHADOW ? TRUE : FALSE;
  769. pUser->fInheritMaxSessionTime =
  770. Flags1 & F1MSK_INHERITMAXSESSIONTIME ? TRUE : FALSE;
  771. pUser->fInheritMaxDisconnectionTime =
  772. Flags1 & F1MSK_INHERITMAXDISCONNECTIONTIME ? TRUE : FALSE;
  773. pUser->fInheritMaxIdleTime =
  774. Flags1 & F1MSK_INHERITMAXIDLETIME ? TRUE : FALSE;
  775. pUser->fInheritAutoClient =
  776. Flags1 & F1MSK_INHERITAUTOCLIENT ? TRUE : FALSE;
  777. pUser->fInheritSecurity =
  778. Flags1 & F1MSK_INHERITSECURITY ? TRUE : FALSE;
  779. pUser->fPromptForPassword =
  780. Flags1 & F1MSK_PROMPTFORPASSWORD ? TRUE : FALSE;
  781. pUser->fResetBroken =
  782. Flags1 & F1MSK_RESETBROKEN ? TRUE : FALSE;
  783. pUser->fReconnectSame =
  784. Flags1 & F1MSK_RECONNECTSAME ? TRUE : FALSE;
  785. pUser->fLogonDisabled =
  786. Flags1 & F1MSK_LOGONDISABLED ? TRUE : FALSE;
  787. pUser->fAutoClientDrives =
  788. Flags1 & F1MSK_AUTOCLIENTDRIVES ? TRUE : FALSE;
  789. pUser->fAutoClientLpts =
  790. Flags1 & F1MSK_AUTOCLIENTLPTS ? TRUE : FALSE;
  791. pUser->fForceClientLptDef =
  792. Flags1 & F1MSK_FORCECLIENTLPTDEF ? TRUE : FALSE;
  793. pUser->fDisableEncryption =
  794. Flags1 & F1MSK_DISABLEENCRYPTION ? TRUE : FALSE;
  795. pUser->fHomeDirectoryMapRoot =
  796. Flags1 & F1MSK_HOMEDIRECTORYMAPROOT ? TRUE : FALSE;
  797. pUser->fUseDefaultGina =
  798. Flags1 & F1MSK_USEDEFAULTGINA ? TRUE : FALSE;
  799. pUser->fDisableCpm =
  800. Flags1 & F1MSK_DISABLECPM ? TRUE : FALSE;
  801. pUser->fDisableCdm =
  802. Flags1 & F1MSK_DISABLECDM ? TRUE : FALSE;
  803. pUser->fDisableCcm =
  804. Flags1 & F1MSK_DISABLECCM ? TRUE : FALSE;
  805. pUser->fDisableLPT =
  806. Flags1 & F1MSK_DISABLELPT ? TRUE : FALSE;
  807. pUser->fDisableClip =
  808. Flags1 & F1MSK_DISABLECLIP ? TRUE : FALSE;
  809. pUser->fDisableExe =
  810. Flags1 & F1MSK_DISABLEEXE ? TRUE : FALSE;
  811. pUser->fWallPaperDisabled =
  812. Flags1 & F1MSK_WALLPAPERDISABLED ? TRUE : FALSE;
  813. pUser->fDisableCam =
  814. Flags1 & F1MSK_DISABLECAM ? TRUE : FALSE;
  815. return( STATUS_SUCCESS );
  816. }
  817. /*******************************************************************************
  818. *
  819. * UsrPropMergeUserConfig
  820. *
  821. * Merge USERCONFIG structure into User Properties section of SAM
  822. *
  823. * ENTRY:
  824. * pUserParms (input/output)
  825. * pointer to a wide char buffer containing the SAM's User Parameters
  826. * UPlength (input )
  827. * length of the pUserParms buffer
  828. * pUser (input)
  829. * pointer to USERCONFIG structure
  830. *
  831. * EXIT:
  832. * STATUS_SUCCESS - no error
  833. *
  834. * NOTES:
  835. * Certain properties have to be stored regardless if they're default or not
  836. * this is done to maintain compatibility for TSE4.0 and W2K servers
  837. ******************************************************************************/
  838. NTSTATUS
  839. UsrPropMergeUserConfig(
  840. WCHAR *pUserParms,
  841. ULONG UPLength,
  842. PUSERCONFIG pUser )
  843. {
  844. ULONG Flags1;
  845. NTSTATUS Status;
  846. USERCONFIG ucDefault;
  847. ULONG CfgPresent = CFGPRESENT_VALUE;
  848. BOOL fDefaultValue = FALSE;
  849. // 1st parameter forces default values to be placed in ucDefault
  850. QueryUserConfig( HKEY_LOCAL_MACHINE , &ucDefault );
  851. Flags1 = GetFlagMask( pUser );
  852. // this value needs to be written out
  853. Status = UsrPropSetValue( WIN_CFGPRESENT,
  854. &CfgPresent,
  855. sizeof(CfgPresent),
  856. FALSE,
  857. pUserParms,
  858. UPLength );
  859. if( NT_SUCCESS( Status ) )
  860. {
  861. // these values must be written out for TS4 & TS5.0
  862. Status = UsrPropSetValue( WIN_FLAGS1,
  863. &Flags1,
  864. sizeof(Flags1),
  865. FALSE,
  866. pUserParms,
  867. UPLength );
  868. }
  869. if( NT_SUCCESS( Status ) )
  870. {
  871. fDefaultValue = ( pUser->Callback == ucDefault.Callback );
  872. Status = UsrPropSetValue( WIN_CALLBACK,
  873. &pUser->Callback,
  874. sizeof(pUser->Callback),
  875. fDefaultValue,
  876. pUserParms,
  877. UPLength );
  878. }
  879. if( NT_SUCCESS( Status ) )
  880. {
  881. // this value must be written out for backcompat servers
  882. Status = UsrPropSetValue( WIN_SHADOW,
  883. &pUser->Shadow,
  884. sizeof(pUser->Shadow),
  885. FALSE,
  886. pUserParms,
  887. UPLength );
  888. }
  889. if( NT_SUCCESS( Status ) )
  890. {
  891. fDefaultValue = ( pUser->MaxConnectionTime == ucDefault.MaxConnectionTime );
  892. Status = UsrPropSetValue( WIN_MAXCONNECTIONTIME,
  893. &pUser->MaxConnectionTime,
  894. sizeof(pUser->MaxConnectionTime),
  895. fDefaultValue,
  896. pUserParms,
  897. UPLength );
  898. }
  899. if( NT_SUCCESS( Status ) )
  900. {
  901. fDefaultValue = ( pUser->MaxDisconnectionTime == ucDefault.MaxDisconnectionTime );
  902. Status = UsrPropSetValue( WIN_MAXDISCONNECTIONTIME,
  903. &pUser->MaxDisconnectionTime,
  904. sizeof(pUser->MaxDisconnectionTime),
  905. fDefaultValue,
  906. pUserParms,
  907. UPLength );
  908. }
  909. if( NT_SUCCESS( Status ) )
  910. {
  911. fDefaultValue = ( pUser->MaxIdleTime == ucDefault.MaxIdleTime );
  912. Status = UsrPropSetValue( WIN_MAXIDLETIME,
  913. &pUser->MaxIdleTime,
  914. sizeof(pUser->MaxIdleTime),
  915. fDefaultValue,
  916. pUserParms,
  917. UPLength );
  918. }
  919. if( NT_SUCCESS( Status ) )
  920. {
  921. fDefaultValue = ( pUser->KeyboardLayout == ucDefault.KeyboardLayout );
  922. Status = UsrPropSetValue( WIN_KEYBOARDLAYOUT,
  923. &pUser->KeyboardLayout,
  924. sizeof(pUser->KeyboardLayout),
  925. fDefaultValue,
  926. pUserParms,
  927. UPLength );
  928. }
  929. if( NT_SUCCESS( Status ) )
  930. {
  931. // always store minencryption level for backwards compatibilty purposes
  932. Status = UsrPropSetValue( WIN_MINENCRYPTIONLEVEL,
  933. &pUser->MinEncryptionLevel,
  934. sizeof(pUser->MinEncryptionLevel),
  935. FALSE,
  936. pUserParms,
  937. UPLength );
  938. }
  939. if( NT_SUCCESS( Status ) )
  940. {
  941. fDefaultValue = ( pUser->WorkDirectory[0] == 0 );
  942. Status = UsrPropSetString( WIN_WORKDIRECTORY,
  943. pUser->WorkDirectory,
  944. pUserParms,
  945. UPLength,
  946. fDefaultValue );
  947. }
  948. if( NT_SUCCESS( Status ) )
  949. {
  950. fDefaultValue = ( pUser->NWLogonServer[0] == 0 );
  951. Status = UsrPropSetString( WIN_NWLOGONSERVER,
  952. pUser->NWLogonServer,
  953. pUserParms,
  954. UPLength,
  955. fDefaultValue );
  956. }
  957. if( NT_SUCCESS( Status ) )
  958. {
  959. fDefaultValue = ( pUser->WFHomeDir[0] == 0 );
  960. Status = UsrPropSetString( WIN_WFHOMEDIR,
  961. pUser->WFHomeDir,
  962. pUserParms,
  963. UPLength,
  964. fDefaultValue );
  965. }
  966. if( NT_SUCCESS( Status ) )
  967. {
  968. fDefaultValue = ( pUser->WFHomeDirDrive[0] == 0 );
  969. Status = UsrPropSetString( WIN_WFHOMEDIRDRIVE,
  970. pUser->WFHomeDirDrive,
  971. pUserParms,
  972. UPLength,
  973. fDefaultValue );
  974. }
  975. if( NT_SUCCESS( Status ) )
  976. {
  977. fDefaultValue = ( pUser->WFProfilePath[0] == 0 );
  978. Status = UsrPropSetString( WIN_WFPROFILEPATH,
  979. pUser->WFProfilePath,
  980. pUserParms,
  981. UPLength,
  982. fDefaultValue );
  983. }
  984. if( NT_SUCCESS( Status ) )
  985. {
  986. fDefaultValue = ( pUser->InitialProgram[0] == 0 );
  987. Status = UsrPropSetString( WIN_INITIALPROGRAM,
  988. pUser->InitialProgram,
  989. pUserParms,
  990. UPLength,
  991. fDefaultValue );
  992. }
  993. if( NT_SUCCESS( Status ) )
  994. {
  995. fDefaultValue = ( pUser->CallbackNumber[0] == 0 );
  996. Status = UsrPropSetString( WIN_CALLBACKNUMBER,
  997. pUser->CallbackNumber,
  998. pUserParms,
  999. UPLength,
  1000. fDefaultValue );
  1001. }
  1002. return( Status );
  1003. }
  1004. /*******************************************************************************
  1005. GetFlagMask
  1006. Assembles a bitmask of flags set in pUser
  1007. *******************************************************************************/
  1008. ULONG GetFlagMask( PUSERCONFIG pUser )
  1009. {
  1010. ULONG Flags1 = 0;
  1011. if ( pUser->fInheritAutoLogon ) {
  1012. Flags1 |= F1MSK_INHERITAUTOLOGON;
  1013. }
  1014. if ( pUser->fInheritResetBroken ) {
  1015. Flags1 |= F1MSK_INHERITRESETBROKEN;
  1016. }
  1017. if ( pUser->fInheritReconnectSame ) {
  1018. Flags1 |= F1MSK_INHERITRECONNECTSAME;
  1019. }
  1020. if ( pUser->fInheritInitialProgram ) {
  1021. Flags1 |= F1MSK_INHERITINITIALPROGRAM;
  1022. }
  1023. if ( pUser->fInheritCallback ) {
  1024. Flags1 |= F1MSK_INHERITCALLBACK;
  1025. }
  1026. if ( pUser->fInheritCallbackNumber ) {
  1027. Flags1 |= F1MSK_INHERITCALLBACKNUMBER;
  1028. }
  1029. if ( pUser->fInheritShadow ) {
  1030. Flags1 |= F1MSK_INHERITSHADOW;
  1031. }
  1032. if ( pUser->fInheritMaxSessionTime ) {
  1033. Flags1 |= F1MSK_INHERITMAXSESSIONTIME;
  1034. }
  1035. if ( pUser->fInheritMaxDisconnectionTime ) {
  1036. Flags1 |= F1MSK_INHERITMAXDISCONNECTIONTIME;
  1037. }
  1038. if ( pUser->fInheritMaxIdleTime ) {
  1039. Flags1 |= F1MSK_INHERITMAXIDLETIME;
  1040. }
  1041. if ( pUser->fInheritAutoClient ) {
  1042. Flags1 |= F1MSK_INHERITAUTOCLIENT;
  1043. }
  1044. if ( pUser->fInheritSecurity ) {
  1045. Flags1 |= F1MSK_INHERITSECURITY;
  1046. }
  1047. if ( pUser->fPromptForPassword ) {
  1048. Flags1 |= F1MSK_PROMPTFORPASSWORD;
  1049. }
  1050. if ( pUser->fResetBroken ) {
  1051. Flags1 |= F1MSK_RESETBROKEN;
  1052. }
  1053. if ( pUser->fReconnectSame ) {
  1054. Flags1 |= F1MSK_RECONNECTSAME;
  1055. }
  1056. if ( pUser->fLogonDisabled ) {
  1057. Flags1 |= F1MSK_LOGONDISABLED;
  1058. }
  1059. if ( pUser->fAutoClientDrives ) {
  1060. Flags1 |= F1MSK_AUTOCLIENTDRIVES;
  1061. }
  1062. if ( pUser->fAutoClientLpts ) {
  1063. Flags1 |= F1MSK_AUTOCLIENTLPTS;
  1064. }
  1065. if ( pUser->fForceClientLptDef ) {
  1066. Flags1 |= F1MSK_FORCECLIENTLPTDEF;
  1067. }
  1068. if ( pUser->fDisableEncryption ) {
  1069. Flags1 |= F1MSK_DISABLEENCRYPTION;
  1070. }
  1071. if ( pUser->fHomeDirectoryMapRoot ) {
  1072. Flags1 |= F1MSK_HOMEDIRECTORYMAPROOT;
  1073. }
  1074. if ( pUser->fUseDefaultGina ) {
  1075. Flags1 |= F1MSK_USEDEFAULTGINA;
  1076. }
  1077. if ( pUser->fDisableCpm ) {
  1078. Flags1 |= F1MSK_DISABLECPM;
  1079. }
  1080. if ( pUser->fDisableCdm ) {
  1081. Flags1 |= F1MSK_DISABLECDM;
  1082. }
  1083. if ( pUser->fDisableCcm ) {
  1084. Flags1 |= F1MSK_DISABLECCM;
  1085. }
  1086. if ( pUser->fDisableLPT ) {
  1087. Flags1 |= F1MSK_DISABLELPT;
  1088. }
  1089. if ( pUser->fDisableClip ) {
  1090. Flags1 |= F1MSK_DISABLECLIP;
  1091. }
  1092. if ( pUser->fDisableExe ) {
  1093. Flags1 |= F1MSK_DISABLEEXE;
  1094. }
  1095. if ( pUser->fWallPaperDisabled ) {
  1096. Flags1 |= F1MSK_WALLPAPERDISABLED;
  1097. }
  1098. if ( pUser->fDisableCam ) {
  1099. Flags1 |= F1MSK_DISABLECAM;
  1100. }
  1101. return Flags1;
  1102. }
  1103. /*******************************************************************************
  1104. *
  1105. * RegMergeUserConfigWithUserParameters
  1106. *
  1107. * Merge the User Configuration with the supplied SAM's User
  1108. * Parameters buffer.
  1109. *
  1110. * ENTRY:
  1111. * pUserParms (input/output)
  1112. * pointer to a wide char buffer containing the SAM's User Parameters
  1113. * UPlength (input)
  1114. * length of the pUserParms buffer
  1115. * pUser (input)
  1116. * pointer to USERCONFIG structure
  1117. *
  1118. * EXIT:
  1119. * STATUS_SUCCESS - no error
  1120. *
  1121. ******************************************************************************/
  1122. NTSTATUS
  1123. RegMergeUserConfigWithUserParameters(
  1124. PUSER_PARAMETERS_INFORMATION pUserParmInfo,
  1125. PUSERCONFIGW pUser,
  1126. PUSER_PARAMETERS_INFORMATION pNewUserParmInfo
  1127. )
  1128. {
  1129. NTSTATUS status;
  1130. ULONG ObjectID;
  1131. PWCHAR lpNewUserParms = NULL;
  1132. ULONG UPLength;
  1133. WCHAR *pUserParms;
  1134. /*
  1135. * Compute the size the user parameter buffer must be
  1136. * in order to accommodate the CITRIX data plus the existing
  1137. * User Parameters data.
  1138. */
  1139. KdPrint( ("TSUSEREX: User parameter length is %d\n", pUserParmInfo->Parameters.Length ) );
  1140. UPLength = (pUserParmInfo->Parameters.Length +
  1141. CTX_USER_PARAM_MAX_SIZE) *
  1142. sizeof(WCHAR);
  1143. pUserParms = (WCHAR *) LocalAlloc( LPTR, UPLength );
  1144. if ( pUserParms == NULL ) {
  1145. status = STATUS_INSUFFICIENT_RESOURCES;
  1146. goto exit;
  1147. }
  1148. /*
  1149. * Copy SAM data to the local buffer.
  1150. * Let the Set/Get operation terminate the buffer.
  1151. */
  1152. memcpy( pUserParms,
  1153. pUserParmInfo->Parameters.Buffer,
  1154. pUserParmInfo->Parameters.Length );
  1155. /*
  1156. * Zero fill the unused portion of the pUserParms buffer.
  1157. */
  1158. memset( &pUserParms[ pUserParmInfo->Parameters.Length / sizeof(WCHAR) ],
  1159. 0,
  1160. UPLength - pUserParmInfo->Parameters.Length );
  1161. status = UsrPropMergeUserConfig( pUserParms, UPLength, pUser );
  1162. if ( status != NO_ERROR ) {
  1163. goto cleanupoperation;
  1164. }
  1165. RtlInitUnicodeString( &pNewUserParmInfo->Parameters, pUserParms );
  1166. return( STATUS_SUCCESS );
  1167. /*
  1168. * Error returns
  1169. */
  1170. cleanupoperation:
  1171. LocalFree( pUserParms );
  1172. exit:
  1173. return( status );
  1174. }
  1175. /*******************************************************************************
  1176. *
  1177. * RegGetUserConfigFromUserParameters
  1178. *
  1179. * Get the User Configuration from the supplied SAM's
  1180. * User Parameters buffer.
  1181. *
  1182. * ENTRY:
  1183. * pUserParmInfo (input)
  1184. * pointer to a USER_PARAMETERS_INFORMATION structure obtained from
  1185. * a user's SAM entry
  1186. * pUser (input)
  1187. * pointer to USERCONFIG structure
  1188. *
  1189. * EXIT:
  1190. * STATUS_SUCCESS - no error
  1191. *
  1192. ******************************************************************************/
  1193. NTSTATUS
  1194. RegGetUserConfigFromUserParameters(
  1195. PUSER_PARAMETERS_INFORMATION pUserParmInfo,
  1196. PUSERCONFIGW pUser
  1197. )
  1198. {
  1199. NTSTATUS status;
  1200. ULONG ObjectID;
  1201. PWCHAR lpNewUserParms = NULL;
  1202. ULONG UPLength;
  1203. WCHAR *pUserParms;
  1204. /*
  1205. * Compute the size the user parameter buffer must be
  1206. * in order to accommodate the existing User Parameters.
  1207. */
  1208. UPLength = pUserParmInfo->Parameters.Length + sizeof(WCHAR);
  1209. pUserParms = (WCHAR *) LocalAlloc( LPTR, UPLength );
  1210. if ( pUserParms == NULL ) {
  1211. status = STATUS_INSUFFICIENT_RESOURCES;
  1212. goto exit;
  1213. }
  1214. /*
  1215. * Copy SAM data to the local buffer and terminate the buffer.
  1216. */
  1217. memcpy( pUserParms,
  1218. pUserParmInfo->Parameters.Buffer,
  1219. pUserParmInfo->Parameters.Length );
  1220. pUserParms[ pUserParmInfo->Parameters.Length / sizeof(WCHAR) ] = L'\0';
  1221. /*
  1222. * Extract the User Configuration from the SAM's User
  1223. * Parameters.
  1224. */
  1225. status = UsrPropQueryUserConfig( pUserParms, UPLength, pUser );
  1226. LocalFree( pUserParms );
  1227. if ( status != NO_ERROR ) {
  1228. goto exit;
  1229. }
  1230. return( STATUS_SUCCESS );
  1231. /*
  1232. * Error returns
  1233. */
  1234. exit:
  1235. #ifdef DEBUG
  1236. DbgPrint( "RegGetUserConfigFromUserParameters: status = 0x%x\n", status );
  1237. #endif // DEBUG
  1238. return( status );
  1239. }
  1240. /*******************************************************************************
  1241. *
  1242. * RegSAMUserConfig
  1243. *
  1244. * Set or Get the User Configuration for a user from the Domain whose
  1245. * PDC is server is given.
  1246. *
  1247. * ENTRY:
  1248. * fGetConfig (input)
  1249. * TRUE for Get config, FALSE for Set configuration
  1250. * pUsername (input)
  1251. * points to the user name
  1252. * pServerName (input)
  1253. * points to the name of the server. UNC names permitted.
  1254. * pUser (input/output)
  1255. * pointer to USERCONFIG structure
  1256. *
  1257. * EXIT:
  1258. * STATUS_SUCCESS - no error
  1259. *
  1260. ******************************************************************************/
  1261. DWORD
  1262. RegSAMUserConfig(
  1263. BOOLEAN fGetConfig,
  1264. PWCHAR pUserName,
  1265. PWCHAR pServerName,
  1266. PUSERCONFIGW pUser
  1267. )
  1268. {
  1269. NTSTATUS status;
  1270. UNICODE_STRING UniUserName;
  1271. PULONG pRids = NULL;
  1272. PSID_NAME_USE pSidNameUse = NULL;
  1273. ULONG ObjectID;
  1274. SID_NAME_USE SidNameUse;
  1275. SAM_HANDLE Handle = (SAM_HANDLE) 0;
  1276. PUSER_PARAMETERS_INFORMATION UserParmInfo = NULL;
  1277. ULONG UPLength;
  1278. SAM_HANDLE SAMHandle = NULL;
  1279. SAM_HANDLE DomainHandle = NULL;
  1280. PWCHAR ServerName = NULL;
  1281. PSID DomainID = NULL;
  1282. PWCHAR pUserParms;
  1283. PWCHAR pDomainName = NULL;
  1284. WCHAR wCompName[MAX_COMPUTERNAME_LENGTH+1];
  1285. ULONG openFlag;
  1286. DWORD dwErr = ERROR_SUCCESS;
  1287. ULONG cValues;
  1288. HANDLE hDS = NULL;
  1289. PDS_NAME_RESULTW pDsResult = NULL;
  1290. typedef DWORD (WINAPI *PFNDSCRACKNAMES) ( HANDLE, DS_NAME_FLAGS, DS_NAME_FORMAT, \
  1291. DS_NAME_FORMAT, DWORD, LPTSTR *, PDS_NAME_RESULT *);
  1292. typedef void (WINAPI *PFNDSFREENAMERESULT) (DS_NAME_RESULT *);
  1293. typedef DWORD (WINAPI *PFNDSBIND) (TCHAR *, TCHAR *, HANDLE *);
  1294. typedef DWORD (WINAPI *PFNDSUNBIND) (HANDLE *);
  1295. PFNDSCRACKNAMES pfnDsCrackNamesW;
  1296. PFNDSFREENAMERESULT pfnDsFreeNameResultW;
  1297. PFNDSBIND pfnDsBindW;
  1298. PFNDSUNBIND pfnDsUnBindW;
  1299. // vars used for handling UPN anmes
  1300. WCHAR tmpUserName[MAX_PATH];
  1301. WCHAR *pUserAlias;
  1302. HINSTANCE hNtdsApi = NULL;
  1303. // We dont' care about the domain since we get it otherwise.
  1304. // WCHAR tmpDomainName[ MAX_PATH];
  1305. // tmpDomainName[0]=NULL;
  1306. tmpUserName[0]=0;
  1307. pUserAlias=NULL;
  1308. #ifdef DEBUG
  1309. DbgPrint( "RegSAMUserConfig %s, User %ws, Server %ws\n", fGetConfig ? "GET" : "SET", pUserName, pServerName ? pServerName : L"-NULL-" );
  1310. #endif // DEBUG
  1311. if (pServerName == NULL) {
  1312. UPLength = MAX_COMPUTERNAME_LENGTH + 1;
  1313. if (!GetComputerName(wCompName, &UPLength)) {
  1314. status = STATUS_INSUFFICIENT_RESOURCES;
  1315. goto exit;
  1316. }
  1317. }
  1318. // init this to the name passed in, if it is not a UPN name, we will continue to use
  1319. // the names passed into this function.
  1320. pUserAlias = pUserName;
  1321. //
  1322. //
  1323. // NEW code to handle UPN if the name passed in contains a '@' in the name.
  1324. // The call to CrackName is to seperate the UPN name into the user alias by
  1325. // contacting the DS and looking in the Gloabl-Catalog.
  1326. //
  1327. //
  1328. if ( wcschr(pUserName,L'@') != NULL )
  1329. {
  1330. hNtdsApi = LoadLibrary(TEXT("ntdsapi.dll"));
  1331. if ( hNtdsApi )
  1332. {
  1333. pfnDsCrackNamesW = (PFNDSCRACKNAMES)GetProcAddress(hNtdsApi, "DsCrackNamesW");
  1334. pfnDsFreeNameResultW = (PFNDSFREENAMERESULT)GetProcAddress(hNtdsApi, "DsFreeNameResultW");
  1335. pfnDsBindW = (PFNDSBIND)GetProcAddress(hNtdsApi, "DsBindW");
  1336. pfnDsUnBindW = (PFNDSUNBIND)GetProcAddress(hNtdsApi, "DsUnBindW");
  1337. if (pfnDsBindW && pfnDsCrackNamesW )
  1338. {
  1339. dwErr = pfnDsBindW(NULL, NULL, &hDS);
  1340. }
  1341. else
  1342. {
  1343. dwErr = ERROR_INVALID_FUNCTION;
  1344. }
  1345. if(dwErr == ERROR_SUCCESS)
  1346. {
  1347. dwErr = pfnDsCrackNamesW(hDS,
  1348. DS_NAME_NO_FLAGS,
  1349. DS_UNKNOWN_NAME,
  1350. DS_NT4_ACCOUNT_NAME,
  1351. 1,
  1352. &pUserName,
  1353. &pDsResult);
  1354. if(dwErr == ERROR_SUCCESS)
  1355. {
  1356. if(pDsResult)
  1357. {
  1358. if( pDsResult->rItems )
  1359. {
  1360. if (pDsResult->rItems[0].pName )
  1361. {
  1362. // no error
  1363. status = STATUS_SUCCESS;
  1364. wcscpy(tmpUserName, pDsResult->rItems[0].pName);
  1365. KdPrint(("RegSAMUserConfig: tmpUserName=%ws\n",tmpUserName));
  1366. // do we have a non-null name?
  1367. if ( tmpUserName[0] ) {
  1368. pUserAlias = wcschr(tmpUserName,L'\\');
  1369. pUserAlias++; //move pass the wack.
  1370. // we are not using the domain name, we already have this
  1371. // wcscpy(tmpDomainName, pDsResult->rItems[0].pDomain);
  1372. }
  1373. }
  1374. else
  1375. {
  1376. KdPrint(("RegSAMUserConfig: pDsResult->rItems[0].pName is NULL\n"));
  1377. }
  1378. }
  1379. else
  1380. {
  1381. KdPrint(("RegSAMUserConfig: pDsResult->rItems=0x%lx\n",pDsResult->rItems));
  1382. }
  1383. }
  1384. else
  1385. {
  1386. KdPrint(("RegSAMUserConfig: pDsResult=0x%lx\n",pDsResult));
  1387. }
  1388. }
  1389. else
  1390. {
  1391. switch( dwErr )
  1392. {
  1393. case ERROR_INVALID_PARAMETER:
  1394. status = STATUS_INVALID_PARAMETER;
  1395. break;
  1396. case ERROR_NOT_ENOUGH_MEMORY:
  1397. status = STATUS_NO_MEMORY;
  1398. break;
  1399. default:
  1400. status = STATUS_UNSUCCESSFUL;
  1401. break;
  1402. }
  1403. // have decided to continue using the passed-in pUserName instead of what
  1404. // would have been returned from CrackName. Hence, no need to exit.
  1405. // goto exit;
  1406. }
  1407. }
  1408. else
  1409. {
  1410. status = STATUS_UNSUCCESSFUL; // DsBindW doesn't have a clean set of errors.
  1411. // have decided to continue using the passed-in pUserName instead of what
  1412. // would have been returned from DsBind/CrackName. Hence, no need to exit.
  1413. // goto exit;
  1414. }
  1415. }
  1416. else
  1417. {
  1418. status = STATUS_DLL_NOT_FOUND;
  1419. // have decided to continue using the passed-in pUserName instead of what
  1420. // would have been returned from DsBind/CrackName. Hence, no need to exit.
  1421. // goto exit;
  1422. }
  1423. }
  1424. #ifdef DEBUG
  1425. DbgPrint( "RegSAMUserConfig: pUserAlias=%ws\n", pUserAlias);
  1426. #endif // DEBUG
  1427. status = GetDomainName( pServerName, &pDomainName );
  1428. #ifdef DEBUG
  1429. DbgPrint( "RegSAMUserConfig: GetDomainName returned NTSTATUS = 0x%x\n", status );
  1430. #endif // DEBUG
  1431. if ( status != STATUS_SUCCESS ) {
  1432. goto exit;
  1433. }
  1434. /*
  1435. * With the PDC Server name and the Domain Name,
  1436. * connect to the SAM
  1437. */
  1438. status = ConnectToSam( fGetConfig,
  1439. pServerName,
  1440. pDomainName,
  1441. &SAMHandle,
  1442. &DomainHandle,
  1443. &DomainID );
  1444. #ifdef DEBUG
  1445. DbgPrint( "RegSAMUserConfig: ConnectToSam returned NTSTATUS = 0x%x\n", status );
  1446. #endif // DEBUG
  1447. if ( status != STATUS_SUCCESS ) {
  1448. goto cleanupconnect;
  1449. }
  1450. RtlInitUnicodeString( &UniUserName, pUserAlias );
  1451. status = SamLookupNamesInDomain( DomainHandle,
  1452. 1,
  1453. &UniUserName,
  1454. &pRids,
  1455. &pSidNameUse );
  1456. #ifdef DEBUG
  1457. DbgPrint( "RegSAMUserConfig: SamLookupNamesInDomain returned NTSTATUS = 0x%x\n", status );
  1458. #endif // DEBUG
  1459. if ((status != STATUS_SUCCESS) ||
  1460. (pRids == NULL) ||
  1461. (pSidNameUse == NULL)) {
  1462. goto cleanuplookup;
  1463. }
  1464. /*
  1465. * Found the user name in the SAM, copy and free SAM info
  1466. */
  1467. ObjectID = pRids[ 0 ];
  1468. SidNameUse = pSidNameUse[ 0 ];
  1469. SamFreeMemory( pRids );
  1470. SamFreeMemory( pSidNameUse );
  1471. /*
  1472. * Open the SAM entry for this user
  1473. */
  1474. openFlag = fGetConfig ? USER_READ
  1475. : USER_WRITE_ACCOUNT| USER_READ;
  1476. #ifdef DEBUG
  1477. DbgPrint("calling SamOpenUSer with flag = 0x%x\n", openFlag);
  1478. #endif
  1479. status = SamOpenUser( DomainHandle,
  1480. openFlag,
  1481. ObjectID,
  1482. &Handle );
  1483. // For getting config parametesr...
  1484. // The call will fail if it goes to the DC, for that case, change
  1485. // flag, since DC does allow access to read user-parameters (for
  1486. // legacy compat reasons).
  1487. if (!NT_SUCCESS( status ) && fGetConfig )
  1488. {
  1489. openFlag = 0;
  1490. #ifdef DEBUG
  1491. DbgPrint("calling SamOpenUSer with flag = 0x%x\n", openFlag);
  1492. #endif
  1493. status = SamOpenUser( DomainHandle,
  1494. openFlag,
  1495. ObjectID,
  1496. &Handle );
  1497. }
  1498. #ifdef DEBUG
  1499. DbgPrint( "RegSAMUserConfig: SamOpenUser returned NTSTATUS = 0x%x\n", status );
  1500. #endif // DEBUG
  1501. if ( status != STATUS_SUCCESS ) {
  1502. goto cleanupsamopen;
  1503. }
  1504. /*
  1505. * Get the user parameters from the SAM
  1506. */
  1507. status = SamQueryInformationUser( Handle,
  1508. UserParametersInformation,
  1509. (PVOID *) &UserParmInfo );
  1510. KdPrint( ( "RegSAMUserConfig: SamQueryInformationUser returned NTSTATUS = 0x%x\n", status ) );
  1511. if ( status != STATUS_SUCCESS || UserParmInfo == NULL ) {
  1512. goto cleanupsamquery;
  1513. }
  1514. if( fGetConfig )
  1515. {
  1516. /*
  1517. * Extract the User Configuration from the SAM's User
  1518. * Parameters.
  1519. *
  1520. * For Whistler builds and higher we assume that not every field
  1521. * has been stored in the SAM we'll need to retrieve the default
  1522. * values first
  1523. */
  1524. KdPrint( ( "RegSAMUserConfig: UserParmInfo %d\n", UserParmInfo->Parameters.Length ) );
  1525. status = RegGetUserConfigFromUserParameters( UserParmInfo, pUser );
  1526. KdPrint( ( "RegSAMUserConfig: RegGetUserConfigFromUserParameters returned NTSTATUS = 0x%x\n", status ) );
  1527. SamFreeMemory( UserParmInfo );
  1528. UserParmInfo = NULL;
  1529. if ( status != NO_ERROR )
  1530. {
  1531. goto cleanupoperation;
  1532. }
  1533. }
  1534. else
  1535. {
  1536. USER_PARAMETERS_INFORMATION NewUserParmInfo;
  1537. /*
  1538. * Set the SAM based on the supplied User Configuration.
  1539. */
  1540. status = RegMergeUserConfigWithUserParameters( UserParmInfo,
  1541. pUser,
  1542. &NewUserParmInfo );
  1543. KdPrint( ( "RegSAMUserConfig: RegMergeUserConfigWithUserParameters returned NTSTATUS = 0x%x\n", status ) );
  1544. SamFreeMemory( UserParmInfo );
  1545. UserParmInfo = NULL;
  1546. if( status != NO_ERROR )
  1547. {
  1548. goto cleanupoperation;
  1549. }
  1550. status = SamSetInformationUser( Handle,
  1551. UserParametersInformation,
  1552. (PVOID) &NewUserParmInfo );
  1553. KdPrint( ( "RegSAMUserConfig: NewUserParmInfo.Parameters.Length = %d\n" , NewUserParmInfo.Parameters.Length ) );
  1554. KdPrint( ( "RegSAMUserConfig: SamSetInformationUser returned NTSTATUS = 0x%x\n", status ) );
  1555. LocalFree( NewUserParmInfo.Parameters.Buffer );
  1556. if ( status != STATUS_SUCCESS )
  1557. {
  1558. goto cleanupoperation;
  1559. }
  1560. }
  1561. cleanupoperation:
  1562. if ( UserParmInfo ) {
  1563. SamFreeMemory( UserParmInfo );
  1564. }
  1565. cleanupsamquery:
  1566. if ( Handle != (SAM_HANDLE) 0 ) {
  1567. SamCloseHandle( Handle );
  1568. }
  1569. cleanupsamopen:
  1570. cleanuplookup:
  1571. if ( SAMHandle != (SAM_HANDLE) 0 ) {
  1572. SamCloseHandle( SAMHandle );
  1573. }
  1574. if ( DomainHandle != (SAM_HANDLE) 0 ) {
  1575. SamCloseHandle( DomainHandle );
  1576. }
  1577. if ( DomainID != (PSID) 0 ) {
  1578. SamFreeMemory( DomainID );
  1579. }
  1580. cleanupconnect:
  1581. if ( pDomainName ) {
  1582. NetApiBufferFree( pDomainName );
  1583. }
  1584. exit:
  1585. if (hNtdsApi)
  1586. {
  1587. if (hDS)
  1588. {
  1589. if ( pfnDsUnBindW ) // it should never be otherwise.
  1590. pfnDsUnBindW( & hDS );
  1591. }
  1592. if (pDsResult)
  1593. {
  1594. if (pfnDsFreeNameResultW ) // it should never be otherwise.
  1595. pfnDsFreeNameResultW( pDsResult );
  1596. }
  1597. FreeLibrary(hNtdsApi);
  1598. }
  1599. #ifdef DEBUG
  1600. DbgPrint( "RegSAMUserConfig %s NTSTATUS = 0x%x\n", fGetConfig ? "GET" : "SET", status );
  1601. #endif // DEBUG
  1602. return( RtlNtStatusToDosError( status ) );
  1603. }
  1604.