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.

1042 lines
36 KiB

  1. /*******************************************************************************
  2. * config.c
  3. *
  4. * Published Terminal Server APIs
  5. *
  6. * - user configuration routines
  7. *
  8. * Copyright 1998, Citrix Systems Inc.
  9. * Copyright (C) 1997-1999 Microsoft Corp.
  10. /******************************************************************************/
  11. #include <nt.h>
  12. #include <ntrtl.h>
  13. #include <nturtl.h>
  14. #include <ntddkbd.h>
  15. #include <ntddmou.h>
  16. #include <windows.h>
  17. #include <ntsecapi.h>
  18. #include <lm.h>
  19. #include <winbase.h>
  20. #include <winerror.h>
  21. #if(WINVER >= 0x0500)
  22. #include <ntstatus.h>
  23. #include <winsta.h>
  24. #else
  25. #include <citrix\cxstatus.h>
  26. #include <citrix\winsta.h>
  27. #endif
  28. #include <utildll.h>
  29. #include <stdio.h>
  30. #include <stdarg.h>
  31. #include <lmaccess.h> // for NetGet[Any]DCName KLB 10-07-97
  32. #include <lmerr.h> // for NERR_Success KLB 10-07-97
  33. #include <lmapibuf.h> // for NetApiBufferFree KLB 10-07-97
  34. #include <wtsapi32.h>
  35. /*=============================================================================
  36. == External procedures defined
  37. =============================================================================*/
  38. BOOL WINAPI WTSQueryUserConfigW( LPWSTR, LPWSTR, WTS_CONFIG_CLASS, LPWSTR *, DWORD *);
  39. BOOL WINAPI WTSQueryUserConfigA( LPSTR, LPSTR, WTS_CONFIG_CLASS, LPSTR *, DWORD *);
  40. BOOL WINAPI WTSSetUserConfigW( LPWSTR, LPWSTR, WTS_CONFIG_CLASS, LPWSTR, DWORD);
  41. BOOL WINAPI WTSSetUserConfigA( LPSTR, LPSTR, WTS_CONFIG_CLASS, LPSTR, DWORD);
  42. /*=============================================================================
  43. == Internal procedures defined
  44. =============================================================================*/
  45. #ifdef NETWARE
  46. //This should be defined in the wtsapi32.h
  47. typedef struct _WTS_USER_CONFIG_SET_NWSERVERW {
  48. LPWSTR pNWServerName;
  49. LPWSTR pNWDomainAdminName;
  50. LPWSTR pNWDomainAdminPassword;
  51. } WTS_USER_CONFIG_SET_NWSERVERW, * PWTS_USER_CONFIG_SET_NWSERVERW;
  52. BOOL
  53. SetNWAuthenticationServer(PWTS_USER_CONFIG_SET_NWSERVERW pInput,
  54. LPWSTR pServerNameW,
  55. LPWSTR pUserNameW,
  56. PUSERCONFIGW pUserConfigW
  57. );
  58. #endif
  59. /*=============================================================================
  60. == Procedures used
  61. =============================================================================*/
  62. BOOL _CopyData( PVOID, ULONG, LPWSTR *, DWORD * );
  63. BOOL _CopyStringW( LPWSTR, LPWSTR *, DWORD * );
  64. BOOL _CopyStringA( LPSTR, LPWSTR *, DWORD * );
  65. BOOL _CopyStringWtoA( LPWSTR, LPSTR *, DWORD * );
  66. BOOL ValidateCopyAnsiToUnicode(LPSTR, DWORD, LPWSTR);
  67. BOOL ValidateCopyUnicodeToUnicode(LPWSTR, DWORD, LPWSTR);
  68. VOID UnicodeToAnsi( CHAR *, ULONG, WCHAR * );
  69. VOID AnsiToUnicode( WCHAR *, ULONG, CHAR * );
  70. /*=============================================================================
  71. == Local Data
  72. =============================================================================*/
  73. /****************************************************************************
  74. *
  75. * WTSQueryUserConfigW (UNICODE)
  76. *
  77. * Query information from the SAM for the specified user
  78. *
  79. * ENTRY:
  80. * pServerName (input)
  81. * Name of server to access (NULL for current machine).
  82. * pUserName (input)
  83. * User name to query
  84. * WTSConfigClass (input)
  85. * Specifies the type of information to retrieve about the specified user
  86. * ppBuffer (output)
  87. * Points to the address of a variable to receive information about
  88. * the specified session. The format and contents of the data
  89. * depend on the specified information class being queried. The
  90. * buffer is allocated within this API and is disposed of using
  91. * WTSFreeMemory.
  92. * pBytesReturned (output)
  93. * An optional parameter that if specified, receives the number of
  94. * bytes returned.
  95. *
  96. * EXIT:
  97. *
  98. * TRUE -- The query operation succeeded.
  99. *
  100. * FALSE -- The operation failed. Extended error status is available
  101. * using GetLastError.
  102. *
  103. * HISTORY:
  104. * Created KLB 10-06-97
  105. *
  106. ****************************************************************************/
  107. BOOL
  108. WINAPI
  109. WTSQueryUserConfigW(
  110. IN LPWSTR pServerName,
  111. IN LPWSTR pUserName,
  112. IN WTS_CONFIG_CLASS WTSConfigClass,
  113. OUT LPWSTR * ppBuffer,
  114. OUT DWORD * pBytesReturned
  115. )
  116. {
  117. USERCONFIGW UserConfigW;
  118. ULONG ulReturnLength;
  119. LONG rc;
  120. BOOL fSuccess = FALSE;
  121. DWORD dwfInheritInitialProgram;
  122. DWORD dwReturnValue;
  123. PUSER_INFO_0 pUserInfo = NULL;
  124. WCHAR netServerName[DOMAIN_LENGTH + 3];
  125. /*
  126. * Check the null buffer
  127. */
  128. if (!ppBuffer || !pBytesReturned) {
  129. SetLastError (ERROR_INVALID_PARAMETER);
  130. fSuccess = FALSE;
  131. goto done;
  132. }
  133. /*
  134. * First, we want to make sure the user actually exists on the specified
  135. * machine.
  136. */
  137. rc = NetUserGetInfo( pServerName, // server name (can be NULL)
  138. pUserName, // user name
  139. 0, // level to query (0 = just name)
  140. (LPBYTE *)&pUserInfo );// buffer to return data to (they alloc, we free)
  141. /*
  142. * append the "\\" in front of server name to check the user name existence again
  143. */
  144. if ( rc != NERR_Success && pServerName) {
  145. lstrcpyW(netServerName, L"\\\\");
  146. lstrcatW(netServerName, pServerName);
  147. rc = NetUserGetInfo( netServerName, // server name (can be NULL)
  148. pUserName, // user name
  149. 0, // level to query (0 = user name)
  150. (LPBYTE *)&pUserInfo );// buffer to return data to (they alloc, we free)
  151. if ( rc != NERR_Success ) {
  152. SetLastError( ERROR_NO_SUCH_USER );
  153. goto done; // exit with fSuccess = FALSE
  154. }
  155. }
  156. /*
  157. * Query the user. If the user config doesn't exist for the user, then
  158. * we query the default values.
  159. */
  160. rc = RegUserConfigQuery( pServerName, // server name
  161. pUserName, // user name
  162. &UserConfigW, // returned user config
  163. (ULONG)sizeof(UserConfigW),// user config length
  164. &ulReturnLength ); // #bytes returned
  165. if ( rc != ERROR_SUCCESS ) {
  166. rc = RegDefaultUserConfigQuery( pServerName, // server name
  167. &UserConfigW, // returned user config
  168. (ULONG)sizeof(UserConfigW),// user config length
  169. &ulReturnLength ); // #bytes returned
  170. }
  171. /*
  172. * Now, process the results. Note that in each case, we're allocating a
  173. * new buffer which the caller must free
  174. * (WTSUserConfigfInheritInitialProgram is just a boolean, but we allocate
  175. * a DWORD to send it back).
  176. */
  177. if ( rc == ERROR_SUCCESS ) {
  178. switch ( WTSConfigClass ) {
  179. case WTSUserConfigInitialProgram:
  180. fSuccess = _CopyStringW( UserConfigW.InitialProgram,
  181. ppBuffer,
  182. pBytesReturned );
  183. break;
  184. case WTSUserConfigWorkingDirectory:
  185. fSuccess = _CopyStringW( UserConfigW.WorkDirectory,
  186. ppBuffer,
  187. pBytesReturned );
  188. break;
  189. case WTSUserConfigfInheritInitialProgram:
  190. dwReturnValue = UserConfigW.fInheritInitialProgram;
  191. fSuccess = _CopyData( &dwReturnValue,
  192. sizeof(DWORD),
  193. ppBuffer,
  194. pBytesReturned );
  195. break;
  196. case WTSUserConfigfAllowLogonTerminalServer: //DWORD returned/expected
  197. dwReturnValue = !(UserConfigW.fLogonDisabled);
  198. fSuccess = _CopyData( &dwReturnValue,
  199. sizeof(DWORD),
  200. ppBuffer,
  201. pBytesReturned );
  202. break;
  203. //Timeout settings
  204. case WTSUserConfigTimeoutSettingsConnections:
  205. dwReturnValue = UserConfigW.MaxConnectionTime;
  206. fSuccess = _CopyData( &dwReturnValue,
  207. sizeof(DWORD),
  208. ppBuffer,
  209. pBytesReturned );
  210. break;
  211. case WTSUserConfigTimeoutSettingsDisconnections: //DWORD
  212. dwReturnValue = UserConfigW.MaxDisconnectionTime;
  213. fSuccess = _CopyData( &dwReturnValue,
  214. sizeof(DWORD),
  215. ppBuffer,
  216. pBytesReturned );
  217. break;
  218. case WTSUserConfigTimeoutSettingsIdle: //DWORD
  219. dwReturnValue = UserConfigW.MaxIdleTime;
  220. fSuccess = _CopyData( &dwReturnValue,
  221. sizeof(DWORD),
  222. ppBuffer,
  223. pBytesReturned );
  224. break;
  225. case WTSUserConfigfDeviceClientDrives: //DWORD
  226. dwReturnValue = UserConfigW.fAutoClientDrives;
  227. fSuccess = _CopyData( &dwReturnValue,
  228. sizeof(DWORD),
  229. ppBuffer,
  230. pBytesReturned );
  231. break;
  232. case WTSUserConfigfDeviceClientPrinters: //DWORD
  233. dwReturnValue = UserConfigW.fAutoClientLpts;
  234. fSuccess = _CopyData( &dwReturnValue,
  235. sizeof(DWORD),
  236. ppBuffer,
  237. pBytesReturned );
  238. break;
  239. case WTSUserConfigfDeviceClientDefaultPrinter: //DWORD
  240. dwReturnValue = UserConfigW.fForceClientLptDef;
  241. fSuccess = _CopyData( &dwReturnValue,
  242. sizeof(DWORD),
  243. ppBuffer,
  244. pBytesReturned );
  245. break;
  246. //Connection settings
  247. case WTSUserConfigBrokenTimeoutSettings: //DWORD
  248. dwReturnValue = UserConfigW.fResetBroken;
  249. fSuccess = _CopyData( &dwReturnValue,
  250. sizeof(DWORD),
  251. ppBuffer,
  252. pBytesReturned );
  253. break;
  254. case WTSUserConfigReconnectSettings:
  255. dwReturnValue = UserConfigW.fReconnectSame;
  256. fSuccess = _CopyData( &dwReturnValue,
  257. sizeof(DWORD),
  258. ppBuffer,
  259. pBytesReturned );
  260. break;
  261. //Modem settings
  262. case WTSUserConfigModemCallbackSettings: //DWORD
  263. dwReturnValue = UserConfigW.Callback;
  264. fSuccess = _CopyData( &dwReturnValue,
  265. sizeof(DWORD),
  266. ppBuffer,
  267. pBytesReturned );
  268. break;
  269. case WTSUserConfigModemCallbackPhoneNumber:
  270. fSuccess = _CopyStringW(UserConfigW.CallbackNumber,
  271. ppBuffer,
  272. pBytesReturned );
  273. break;
  274. case WTSUserConfigShadowingSettings: //DWORD
  275. dwReturnValue = UserConfigW.Shadow;
  276. fSuccess = _CopyData( &dwReturnValue,
  277. sizeof(DWORD),
  278. ppBuffer,
  279. pBytesReturned );
  280. break;
  281. #ifdef NETWARE
  282. case WTSUserConfigNWServerName: // string
  283. fSuccess = _CopyStringW(UserConfigW.NWLogonServer,
  284. ppBuffer,
  285. pBytesReturned );
  286. break;
  287. #endif
  288. case WTSUserConfigTerminalServerProfilePath: // string
  289. fSuccess = _CopyStringW(UserConfigW.WFProfilePath,
  290. ppBuffer,
  291. pBytesReturned );
  292. break;
  293. case WTSUserConfigTerminalServerHomeDir: // string
  294. fSuccess = _CopyStringW(UserConfigW.WFHomeDir,
  295. ppBuffer,
  296. pBytesReturned );
  297. break;
  298. case WTSUserConfigTerminalServerHomeDirDrive: // string
  299. fSuccess = _CopyStringW(UserConfigW.WFHomeDirDrive,
  300. ppBuffer,
  301. pBytesReturned );
  302. break;
  303. case WTSUserConfigfTerminalServerRemoteHomeDir: // DWORD 0:LOCAL 1:REMOTE
  304. if (wcslen(UserConfigW.WFHomeDirDrive) > 0 ) {
  305. dwReturnValue = 1;
  306. } else {
  307. dwReturnValue = 0;
  308. }
  309. fSuccess = _CopyData( &dwReturnValue,
  310. sizeof(DWORD),
  311. ppBuffer,
  312. pBytesReturned );
  313. break;
  314. #ifdef NETWARE
  315. case WTSUserConfigfNWMapRoot:
  316. dwReturnValue = UserConfigW.fHomeDirectoryMapRoot;
  317. fSuccess = _CopyData( &dwReturnValue,
  318. sizeof(DWORD),
  319. ppBuffer,
  320. pBytesReturned );
  321. break;
  322. #endif
  323. } // switch()
  324. } //if (rc == ERROR_SUCCESS)
  325. done:
  326. if ( pUserInfo ) {
  327. NetApiBufferFree( pUserInfo );
  328. }
  329. return( fSuccess );
  330. }
  331. /****************************************************************************
  332. *
  333. * WTSQueryUserConfigA (ANSI)
  334. *
  335. * Query information from the SAM for the specified user
  336. *
  337. * ENTRY:
  338. *
  339. * see WTSQueryUserConfigW
  340. *
  341. * EXIT:
  342. *
  343. * TRUE -- The query operation succeeded.
  344. *
  345. * FALSE -- The operation failed. Extended error status is available
  346. * using GetLastError.
  347. *
  348. * HISTORY:
  349. * Created KLB 10-06-97
  350. *
  351. ****************************************************************************/
  352. BOOL
  353. WINAPI
  354. WTSQueryUserConfigA(
  355. IN LPSTR pServerName,
  356. IN LPSTR pUserName,
  357. IN WTS_CONFIG_CLASS WTSConfigClass,
  358. OUT LPSTR * ppBuffer,
  359. OUT DWORD * pBytesReturned
  360. )
  361. {
  362. LPWSTR lpBufferW = NULL;
  363. BOOL fSuccess;
  364. LONG rc;
  365. LPWSTR pUserNameW = NULL;
  366. LPWSTR pServerNameW = NULL;
  367. if (!ppBuffer || !pBytesReturned) {
  368. SetLastError (ERROR_INVALID_PARAMETER);
  369. fSuccess = FALSE;
  370. goto done;
  371. }
  372. fSuccess = _CopyStringA( pUserName, &pUserNameW, NULL );
  373. if ( fSuccess ) {
  374. fSuccess = _CopyStringA( pServerName, &pServerNameW, NULL );
  375. }
  376. if ( fSuccess ) {
  377. fSuccess = WTSQueryUserConfigW( pServerNameW,
  378. pUserNameW,
  379. WTSConfigClass,
  380. &lpBufferW,
  381. pBytesReturned );
  382. LocalFree( pUserNameW );
  383. }
  384. // Now, process the results.
  385. if ( fSuccess ) switch ( WTSConfigClass ) {
  386. case WTSUserConfigInitialProgram:
  387. case WTSUserConfigWorkingDirectory:
  388. case WTSUserConfigModemCallbackPhoneNumber:
  389. #ifdef NETWARE
  390. case WTSUserConfigNWServerName: // string returned/expected
  391. #endif
  392. case WTSUserConfigTerminalServerProfilePath: // string returned/expected
  393. case WTSUserConfigTerminalServerHomeDir: // string returned/expected
  394. case WTSUserConfigTerminalServerHomeDirDrive: // string returned/expected
  395. /*
  396. * String Data - Convert to ANSI
  397. */
  398. fSuccess = _CopyStringWtoA( lpBufferW, ppBuffer, pBytesReturned );
  399. LocalFree( lpBufferW );
  400. break;
  401. default:
  402. /*
  403. * Just a DWORD, point buffer at the one returned (caller is
  404. * responsible for freeing, so this is cool).
  405. */
  406. *ppBuffer = (LPSTR)lpBufferW;
  407. break;
  408. } // switch()
  409. done:
  410. return( fSuccess );
  411. }
  412. /****************************************************************************
  413. *
  414. * WTSSetUserConfigW (UNICODE)
  415. *
  416. * Set information in the SAM for the specified user
  417. *
  418. * ENTRY:
  419. * pServerName (input)
  420. * Name of server to access (NULL for current machine).
  421. * pUserName (input)
  422. * User name to query
  423. * WTSConfigClass (input)
  424. * Specifies the type of information to change for the specified user
  425. * pBuffer (input)
  426. * Pointer to the data used to modify the specified user's information.
  427. * DataLength (input)
  428. * The length of the data provided.
  429. *
  430. * EXIT:
  431. *
  432. * TRUE -- The query operation succeeded.
  433. *
  434. * FALSE -- The operation failed. Extended error status is available
  435. * using GetLastError.
  436. *
  437. * HISTORY:
  438. * Created KLB 10-06-97
  439. *
  440. ****************************************************************************/
  441. BOOL
  442. WINAPI
  443. WTSSetUserConfigW(
  444. IN LPWSTR pServerName,
  445. IN LPWSTR pUserName,
  446. IN WTS_CONFIG_CLASS WTSConfigClass,
  447. IN LPWSTR pBuffer,
  448. IN DWORD DataLength
  449. )
  450. {
  451. USERCONFIGW UserConfigW;
  452. ULONG ulReturnLength;
  453. LONG rc;
  454. BOOL fSuccess = FALSE;
  455. BOOL fUserConfig = TRUE; //TRUE - We use RegUserConfigSet
  456. //FALSE - Use NetUserSetInfo
  457. DWORD dwfInheritInitialProgram;
  458. PDWORD pdwValue = (DWORD *) pBuffer;
  459. PUSER_INFO_0 pUserInfo = NULL;
  460. DWORD dwParam = 0;
  461. WCHAR netServerName[DOMAIN_LENGTH + 3];
  462. if (!pBuffer || DataLength == 0) {
  463. SetLastError (ERROR_INVALID_PARAMETER);
  464. goto done; // exit with fSuccess = FALSE
  465. }
  466. /*
  467. * First, we want to make sure the user actually exists on the specified
  468. * machine.
  469. */
  470. rc = NetUserGetInfo( pServerName, // server name (can be NULL)
  471. pUserName, // user name
  472. 0, // level to query (0 = just name)
  473. (LPBYTE *)&pUserInfo );// buffer to return data to (they alloc, we free)
  474. if ( rc != NERR_Success ) {
  475. if (pServerName != NULL) {
  476. lstrcpyW(netServerName, L"\\\\");
  477. lstrcatW(netServerName, pServerName);
  478. rc = NetUserGetInfo( netServerName, // server name (can be NULL)
  479. pUserName, // user name
  480. 3, // level to query (3 = ust name)
  481. (LPBYTE *)&pUserInfo );// buffer to return data to (they alloc, we free)
  482. }
  483. else {
  484. rc = NetUserGetInfo( NULL, // server name is NULL
  485. pUserName, // user name
  486. 3, // level to query (3 = ust name)
  487. (LPBYTE *)&pUserInfo );// buffer to return data to (they alloc, we free)
  488. }
  489. if ( rc != NERR_Success ) {
  490. SetLastError( ERROR_NO_SUCH_USER );
  491. goto done; // exit with fSuccess = FALSE
  492. }
  493. }
  494. /*
  495. * Query the user. If the user config doesn't exist for the user, then
  496. * we query the default values.
  497. */
  498. rc = RegUserConfigQuery( pServerName, // server name
  499. pUserName, // user name
  500. &UserConfigW, // returned user config
  501. (ULONG)sizeof(UserConfigW),// user config length
  502. &ulReturnLength ); // #bytes returned
  503. if ( rc != ERROR_SUCCESS ) {
  504. rc = RegDefaultUserConfigQuery( pServerName, // server name
  505. &UserConfigW, // returned user config
  506. (ULONG)sizeof(UserConfigW),// user config length
  507. &ulReturnLength ); // #bytes returned
  508. }
  509. if ( rc != ERROR_SUCCESS ) {
  510. goto done;
  511. }
  512. /*
  513. * Now, we plug in the part we want to change.
  514. */
  515. switch ( WTSConfigClass ) {
  516. case WTSUserConfigInitialProgram:
  517. if (!(fSuccess = ValidateCopyUnicodeToUnicode((LPWSTR)pBuffer,
  518. INITIALPROGRAM_LENGTH,
  519. UserConfigW.InitialProgram)) ) {
  520. SetLastError(ERROR_INVALID_DATA);
  521. goto done;
  522. }
  523. break;
  524. case WTSUserConfigWorkingDirectory:
  525. if (!(fSuccess = ValidateCopyUnicodeToUnicode((LPWSTR)pBuffer,
  526. DIRECTORY_LENGTH,
  527. UserConfigW.WorkDirectory)) ) {
  528. SetLastError(ERROR_INVALID_DATA);
  529. goto done;
  530. }
  531. break;
  532. case WTSUserConfigfInheritInitialProgram:
  533. /*
  534. * We have to point a DWORD pointer at the data, then assign it
  535. * from the DWORD, as that's how it's defined (and this will
  536. * ensure that it works okay on non-Intel architectures).
  537. */
  538. UserConfigW.fInheritInitialProgram = *pdwValue;
  539. fSuccess = TRUE;
  540. break;
  541. case WTSUserConfigfAllowLogonTerminalServer:
  542. if (*pdwValue) {
  543. UserConfigW.fLogonDisabled = FALSE;
  544. } else {
  545. UserConfigW.fLogonDisabled = TRUE;
  546. }
  547. fSuccess = TRUE;
  548. break;
  549. case WTSUserConfigTimeoutSettingsConnections:
  550. UserConfigW.MaxConnectionTime = *pdwValue;
  551. fSuccess = TRUE;
  552. break;
  553. case WTSUserConfigTimeoutSettingsDisconnections: //DWORD
  554. UserConfigW.MaxDisconnectionTime = *pdwValue;
  555. fSuccess = TRUE;
  556. break;
  557. case WTSUserConfigTimeoutSettingsIdle: //DWORD
  558. UserConfigW.MaxIdleTime = *pdwValue;
  559. fSuccess = TRUE;
  560. break;
  561. case WTSUserConfigfDeviceClientDrives: //DWORD
  562. UserConfigW.fAutoClientDrives = *pdwValue;
  563. fSuccess = TRUE;
  564. break;
  565. case WTSUserConfigfDeviceClientPrinters: //DWORD
  566. UserConfigW.fAutoClientLpts = *pdwValue;
  567. fSuccess = TRUE;
  568. break;
  569. case WTSUserConfigfDeviceClientDefaultPrinter: //DWORD
  570. UserConfigW.fForceClientLptDef = *pdwValue;
  571. fSuccess = TRUE;
  572. break;
  573. case WTSUserConfigBrokenTimeoutSettings: //DWORD
  574. UserConfigW.fResetBroken= *pdwValue;
  575. fSuccess = TRUE;
  576. break;
  577. case WTSUserConfigReconnectSettings:
  578. UserConfigW.fReconnectSame = *pdwValue;
  579. fSuccess = TRUE;
  580. break;
  581. //Modem settings
  582. case WTSUserConfigModemCallbackSettings: //DWORD
  583. UserConfigW.Callback = *pdwValue;
  584. fSuccess = TRUE;
  585. break;
  586. case WTSUserConfigModemCallbackPhoneNumber:
  587. if (!(fSuccess = ValidateCopyUnicodeToUnicode((LPWSTR)pBuffer,
  588. sizeof(UserConfigW.CallbackNumber) - 1,
  589. UserConfigW.CallbackNumber)) ) {
  590. SetLastError(ERROR_INVALID_DATA);
  591. goto done;
  592. }
  593. break;
  594. case WTSUserConfigShadowingSettings: //DWORD
  595. UserConfigW.Shadow = *pdwValue;
  596. fSuccess = TRUE;
  597. break;
  598. #ifdef NETWARE
  599. case WTSUserConfigNWServerName: // WTS_USER_CONFIG_SET_NWSERVERW
  600. // Make sure the data structure is correct
  601. //
  602. if (DataLength < sizeof (WTS_USER_CONFIG_SET_NWSERVERW)) {
  603. fSuccess = FALSE;
  604. SetLastError(ERROR_INVALID_PARAMETER);
  605. goto done;
  606. }
  607. fSuccess = SetNWAuthenticationServer((PWTS_USER_CONFIG_SET_NWSERVERW)pBuffer,
  608. pServerName,
  609. pUserName,
  610. pBuffer,
  611. &UserConfigW);
  612. goto done;
  613. break;
  614. #endif
  615. case WTSUserConfigTerminalServerProfilePath: // string
  616. if (!(fSuccess = ValidateCopyUnicodeToUnicode((LPWSTR)pBuffer,
  617. sizeof(UserConfigW.WFProfilePath) - 1,
  618. UserConfigW.WFProfilePath)) ) {
  619. SetLastError(ERROR_INVALID_DATA);
  620. goto done;
  621. }
  622. break;
  623. case WTSUserConfigTerminalServerHomeDir: // string
  624. if (!(fSuccess = ValidateCopyUnicodeToUnicode((LPWSTR)pBuffer,
  625. sizeof(UserConfigW.WFHomeDir) - 1,
  626. UserConfigW.WFHomeDir)) ) {
  627. SetLastError(ERROR_INVALID_DATA);
  628. goto done;
  629. }
  630. break;
  631. case WTSUserConfigTerminalServerHomeDirDrive: // string
  632. if (!(fSuccess = ValidateCopyUnicodeToUnicode((LPWSTR)pBuffer,
  633. sizeof(UserConfigW.WFHomeDirDrive) - 1,
  634. UserConfigW.WFHomeDirDrive)) ) {
  635. SetLastError(ERROR_INVALID_DATA);
  636. goto done;
  637. }
  638. break;
  639. case WTSUserConfigfTerminalServerRemoteHomeDir: // DWORD 0:LOCAL 1:REMOTE
  640. fSuccess = FALSE;
  641. SetLastError (ERROR_INVALID_PARAMETER); // We don't set this parameter
  642. goto done;
  643. break;
  644. #ifdef NETWARE
  645. case WTSUserConfigfNWMapRoot:
  646. UserConfigW.fHomeDirectoryMapRoot = *pdwValue;
  647. fSuccess = TRUE;
  648. break;
  649. #endif
  650. default:
  651. fSuccess = FALSE;
  652. SetLastError (ERROR_INVALID_PARAMETER);
  653. goto done;
  654. }
  655. if ( fSuccess ) {
  656. if (fUserConfig) {
  657. /*
  658. * Only in here if we successfully changed the data in UserConfigW.
  659. * So, we can now write it out to the SAM.
  660. */
  661. rc = RegUserConfigSet( pServerName, // server name
  662. pUserName, // user name
  663. &UserConfigW, // returned user config
  664. (ULONG)sizeof(UserConfigW));// user config length
  665. }
  666. fSuccess = (ERROR_SUCCESS == rc);
  667. if ( !fSuccess ) {
  668. SetLastError( rc );
  669. }
  670. }
  671. done:
  672. if ( pUserInfo ) {
  673. NetApiBufferFree( pUserInfo );
  674. }
  675. return(fSuccess);
  676. }
  677. /****************************************************************************
  678. *
  679. * WTSSetUserConfigA (ANSI)
  680. *
  681. * Set information in the SAM for the specified user
  682. *
  683. * ENTRY:
  684. *
  685. * see WTSSetUserConfigW
  686. *
  687. * EXIT:
  688. *
  689. * TRUE -- The query operation succeeded.
  690. *
  691. * FALSE -- The operation failed. Extended error status is available
  692. * using GetLastError.
  693. *
  694. * HISTORY:
  695. * Created KLB 10-06-97
  696. *
  697. ****************************************************************************/
  698. BOOL
  699. WINAPI
  700. WTSSetUserConfigA(
  701. IN LPSTR pServerName,
  702. IN LPSTR pUserName,
  703. IN WTS_CONFIG_CLASS WTSConfigClass,
  704. IN LPSTR pBuffer,
  705. IN DWORD DataLength
  706. )
  707. {
  708. BOOL fSuccess = FALSE;
  709. BOOL fFreepBufferW = TRUE;
  710. LPWSTR pUserNameW = NULL;
  711. LPWSTR pServerNameW = NULL;
  712. LPWSTR pBufferW = NULL;
  713. DWORD dwDataLength;
  714. if (!pBuffer || DataLength == 0) {
  715. SetLastError (ERROR_INVALID_PARAMETER);
  716. goto done; // exit with fSuccess = FALSE
  717. }
  718. /*
  719. * We're going to call WTSSetUserConfigW() to do the actual work. We need
  720. * to convert all ANSI strings to Unicode before calling. These are the
  721. * user name, and the pBuffer data if it's the initial program or the
  722. * working directory; if it's the flag for inherit initial program, it'll
  723. * be a DWORD in either case, so no conversion is necessary.
  724. */
  725. fSuccess = _CopyStringA( pUserName, &pUserNameW, NULL );
  726. if ( fSuccess ) {
  727. fSuccess = _CopyStringA( pServerName, &pServerNameW, NULL );
  728. }
  729. if ( fSuccess ) switch ( WTSConfigClass ) {
  730. case WTSUserConfigInitialProgram:
  731. case WTSUserConfigWorkingDirectory:
  732. case WTSUserConfigModemCallbackPhoneNumber:
  733. case WTSUserConfigTerminalServerProfilePath: // string returned/expected
  734. case WTSUserConfigTerminalServerHomeDir: // string returned/expected
  735. case WTSUserConfigTerminalServerHomeDirDrive: // string returned/expected
  736. /*
  737. * String Data - Convert to Unicode (_CopyStringA() allocates
  738. * pBufferW for us)
  739. */
  740. fSuccess = _CopyStringA( pBuffer, &pBufferW, &dwDataLength );
  741. break;
  742. #ifdef NETWARE
  743. case WTSUserConfigNWServerName: // string returned/expected
  744. {
  745. //Need to convert the data structure from ASCII to UNICODE
  746. PWTS_USER_CONFIG_SET_NWSERVERW pSetNWServerParamW = LocalAlloc(LPTR, sizeof(WTS_USER_CONFIG_SET_NWSERVERW));
  747. PWTS_USER_CONFIG_SET_NWSERVERA pSetNWServerParamA = (PWTS_USER_CONFIG_SET_NWSERVERA)pBuffer;
  748. DWORD dwLen = 0;
  749. if (pSetNWServerParamW == NULL) {
  750. fSuccess = FALSE;
  751. break;
  752. }
  753. pBufferW = pSetNWServerParamW;
  754. //----------------------------------------//
  755. // Allocate the buffer to hold the //
  756. // required unicode string //
  757. //----------------------------------------//
  758. dwLen = strlen(pSetNWServerParamA -> pNWServerName);
  759. if (fSuccess = _CopyStringA(pSetNWServerParamA -> pNWServerName,
  760. &pSetNWServerParamW -> pNWServerName,
  761. &dwLen)) {
  762. dwLen = strlen(pSetNWServerParamA -> pNWDomainAdminName);
  763. if (fSuccess = _CopyStringA(pSetNWServerParamA -> pNWDomainAdminName,
  764. &pSetNWServerParamW -> pNWDomainAdminName,
  765. &dwLen)) {
  766. dwLen = strlen(pSetNWServerParamA -> pNWDomainAdminPassword);
  767. fSuccess = _CopyStringA(pSetNWServerParamA -> pNWDomainAdminPassword,
  768. &pSetNWServerParamW -> pNWDomainAdminPassword,
  769. &dwLen);
  770. }
  771. }
  772. //-----------------------------------------//
  773. // Call the UNICODE function //
  774. //-----------------------------------------//
  775. if (fSuccess) {
  776. fSuccess = WTSSetUserConfigW( pServerNameW,
  777. pUserNameW,
  778. WTSConfigClass,
  779. pBufferW,
  780. dwDataLength );
  781. }
  782. //----------------------------------------------//
  783. // Free the storage for the specific function //
  784. //----------------------------------------------//
  785. if (pSetNWServerParamW -> pNWServerName) {
  786. LocalFree( pSetNWServerParamW -> pNWServerName );
  787. }
  788. if (pSetNWServerParamW -> pNWDomainAdminName) {
  789. LocalFree( pSetNWServerParamW -> pNWDomainAdminName );
  790. }
  791. if (pSetNWServerParamW -> pNWDomainAdminPassword) {
  792. LocalFree( pSetNWServerParamW -> pNWDomainAdminPassword );
  793. }
  794. goto done;
  795. break;
  796. }
  797. #endif
  798. default:
  799. /*
  800. * Just a DWORD, point our wide buffer at the narrow buffer passed
  801. * in to us and set the data length variable we'll pass down.
  802. * NOTE: WE DON'T WANT TO FREE THE BUFFER, since we're re-using
  803. * the buffer sent in and the caller expects to free it. We'll
  804. * use a BOOL to decide, rather than allocating an extra buffer
  805. * here (performance, memory fragmentation, etc.). KLB 10-08-97
  806. */
  807. pBufferW = (LPWSTR) pBuffer;
  808. dwDataLength = sizeof(DWORD);
  809. fFreepBufferW = FALSE;
  810. break;
  811. } // switch()
  812. /*
  813. * Now, if fSuccess is TRUE, we've copied all the strings we need. So, we
  814. * can now call WTSSetUserConfigW().
  815. */
  816. if ( fSuccess ) {
  817. fSuccess = WTSSetUserConfigW( pServerNameW,
  818. pUserNameW,
  819. WTSConfigClass,
  820. pBufferW,
  821. dwDataLength );
  822. }
  823. done:
  824. if ( pUserNameW ) {
  825. LocalFree( pUserNameW );
  826. }
  827. if ( fFreepBufferW && pBufferW ) {
  828. LocalFree( pBufferW );
  829. }
  830. return(fSuccess);
  831. }
  832. #ifdef NETWARE
  833. BOOL
  834. SetNWAuthenticationServer(PWTS_USER_CONFIG_SET_NWSERVERW pInput,
  835. LPWSTR pServerNameW,
  836. LPWSTR pUserNameW,
  837. PUSERCONFIGW pUserConfigW
  838. )
  839. {
  840. BOOL bStatus = TRUE;
  841. PWKSTA_INFO_100 pWkstaInfo = NULL;
  842. NWLOGONADMIN nwLogonAdmin;
  843. HANDLE hServer;
  844. DWORD dwStatus;
  845. //----------------------------------//
  846. // Get a Server handle
  847. //----------------------------------//
  848. hServer = RegOpenServer(pServerNameW);
  849. if (!hServer) {
  850. SetLastError(GetLastError());
  851. bStatus = FALSE;
  852. goto done;
  853. }
  854. //----------------------------------
  855. //find the domain name
  856. //------------------------------------
  857. dwStatus = NetWkstaGetInfo(
  858. pServerNameW,
  859. 100,
  860. &pWkstaInfo
  861. );
  862. if (dwStatus != ERROR_SUCCESS) {
  863. SetLastError(dwStatus);
  864. goto done;
  865. }
  866. //-----------------------------------------------------
  867. //Copy the parameter to the NWLOGONADMIN structure
  868. //-----------------------------------------------------
  869. bStatus = ValidateCopyUnicodeToUnicode(pInput -> pNWDomainAdminName,
  870. sizeof(nwLogonAdmin.Username)-1,
  871. nwLogonAdmin.Username);
  872. if (!bStatus) {
  873. goto done;
  874. }
  875. bStatus = ValidateCopyUnicodeToUnicode(pInput -> pNWDomainAdminPassword,
  876. sizeof(nwLogonAdmin.Password)-1,
  877. nwLogonAdmin.Password);
  878. if (!bStatus) {
  879. goto done;
  880. }
  881. bStatus = ValidateCopyUnicodeToUnicode(pWkstaInfo -> wki100_langroup,
  882. sizeof(nwLogonAdmin.Domain)-1,
  883. nwLogonAdmin.Domain);
  884. if (!bStatus) {
  885. goto done;
  886. }
  887. //------------------------------------------//
  888. // Set the admin //
  889. //-----------------------------------------//
  890. bStatus = _NWLogonSetAdmin(hServer,
  891. &nwLogonAdmin,
  892. sizeof(nwLogonAdmin));
  893. if (!bStatus) {
  894. SetLastError(GetLastError());
  895. goto done;
  896. }
  897. done:
  898. if (pWkstaInfo) {
  899. NetApiBufferFree(pWkstaInfo);
  900. }
  901. return bStatus;
  902. }
  903. #endif