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.

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