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.

3234 lines
89 KiB

  1. /*++
  2. Copyright (c) 1991-1993 Microsoft Corporation
  3. Module Name:
  4. ApiUser.c
  5. Abstract:
  6. This module contains individual API handlers for the NetUser APIs.
  7. SUPPORTED : NetUserAdd2, NetUserDel, NetUserEnum, NetUserEnum2,
  8. NetUserGetGroups, NetUserGetInfo, NetUserModalsGet,
  9. NetUserModalsSet, NetUserSetGroups, NetUserSetInfo2,
  10. NetUserSetInfo, NetUserPasswordSet2
  11. UNSUPPORTED : NetUserValidate2.
  12. Author:
  13. Shanku Niyogi (w-shanku) 11-Feb-1991
  14. Revision History:
  15. --*/
  16. //
  17. // NetUser APIs are UNICODE only.
  18. //
  19. #ifndef UNICODE
  20. #define UNICODE
  21. #endif
  22. #include "xactsrvp.h"
  23. #include <crypt.h>
  24. #include "changepw.h"
  25. #include <loghours.h>
  26. #include <netlibnt.h>
  27. #include <names.h>
  28. #include <prefix.h> // PREFIX_ equates.
  29. //
  30. // Declaration of descriptor strings.
  31. //
  32. STATIC const LPDESC Desc16_user_info_0 = REM16_user_info_0;
  33. STATIC const LPDESC Desc32_user_info_0 = REM32_user_info_0;
  34. STATIC const LPDESC Desc16_user_info_1 = REM16_user_info_1;
  35. STATIC const LPDESC Desc32_user_info_1 = REM32_user_info_1;
  36. STATIC const LPDESC Desc32_user_info_1_NC = REM32_user_info_1_NOCRYPT;
  37. STATIC const LPDESC Desc32_user_info_1_OWF = REM32_user_info_1_OWF;
  38. STATIC const LPDESC Desc16_user_info_1_setinfo = REM16_user_info_1_setinfo;
  39. STATIC const LPDESC Desc32_user_info_1_setinfo = REM32_user_info_1_setinfo;
  40. STATIC const LPDESC Desc32_user_info_1_setinfo_NC = REM32_user_info_1_setinfo_NOCRYPT;
  41. STATIC const LPDESC Desc16_user_info_2 = REM16_user_info_2;
  42. STATIC const LPDESC Desc32_user_info_2 = REM32_user_info_2;
  43. STATIC const LPDESC Desc32_user_info_2_NC = REM32_user_info_2_NOCRYPT;
  44. STATIC const LPDESC Desc16_user_info_2_setinfo = REM16_user_info_2_setinfo;
  45. STATIC const LPDESC Desc32_user_info_2_setinfo = REM32_user_info_2_setinfo;
  46. STATIC const LPDESC Desc32_user_info_2_setinfo_NC = REM32_user_info_2_setinfo_NOCRYPT;
  47. STATIC const LPDESC Desc16_user_info_10 = REM16_user_info_10;
  48. STATIC const LPDESC Desc32_user_info_10 = REM32_user_info_10;
  49. STATIC const LPDESC Desc16_user_info_11 = REM16_user_info_11;
  50. STATIC const LPDESC Desc32_user_info_11 = REM32_user_info_11;
  51. STATIC const LPDESC Desc32_user_info_22 = REM32_user_info_22;
  52. STATIC const LPDESC Desc16_user_group_info_0 = REM16_group_info_0;
  53. STATIC const LPDESC Desc32_user_group_info_0 = REM32_group_info_0;
  54. STATIC const LPDESC Desc16_user_group_info_0_set
  55. = REM16_group_users_info_0_set;
  56. STATIC const LPDESC Desc32_user_group_info_0_set
  57. = REM32_group_users_info_0_set;
  58. STATIC const LPDESC Desc16_user_modals_info_0 = REM16_user_modals_info_0;
  59. STATIC const LPDESC Desc32_user_modals_info_0 = REM32_user_modals_info_0;
  60. STATIC const LPDESC Desc16_user_modals_info_0_setinfo
  61. = REM16_user_modals_info_0_setinfo;
  62. STATIC const LPDESC Desc32_user_modals_info_0_setinfo
  63. = REM32_user_modals_info_0_setinfo;
  64. STATIC const LPDESC Desc16_user_modals_info_1 = REM16_user_modals_info_1;
  65. STATIC const LPDESC Desc32_user_modals_info_1 = REM32_user_modals_info_1;
  66. STATIC const LPDESC Desc16_user_modals_info_1_setinfo
  67. = REM16_user_modals_info_1_setinfo;
  68. STATIC const LPDESC Desc32_user_modals_info_1_setinfo
  69. = REM32_user_modals_info_1_setinfo;
  70. STATIC NET_API_STATUS
  71. XsGetMinPasswordLength(
  72. LPDWORD minPasswordLength
  73. )
  74. {
  75. NET_API_STATUS apiStatus;
  76. LPUSER_MODALS_INFO_0 modals = NULL;
  77. HANDLE OpenedToken;
  78. NetpAssert( minPasswordLength != NULL );
  79. //
  80. // Revert to Local System
  81. //
  82. (VOID)NtOpenThreadToken(
  83. NtCurrentThread(),
  84. MAXIMUM_ALLOWED,
  85. TRUE,
  86. &OpenedToken
  87. );
  88. RevertToSelf();
  89. //
  90. // Find out how long the password has to be.
  91. //
  92. apiStatus = NetUserModalsGet(
  93. NULL, // local (no server name)
  94. 0, // level
  95. (LPBYTE *)&modals ); // alloc and set ptr
  96. //
  97. // Re-impersonate the client
  98. //
  99. (VOID)NtSetInformationThread(
  100. NtCurrentThread(),
  101. ThreadImpersonationToken,
  102. &OpenedToken,
  103. sizeof( OpenedToken )
  104. );
  105. if ( apiStatus != NO_ERROR ) {
  106. NetpKdPrint(( PREFIX_XACTSRV
  107. "XsGetMinPasswordLength: Problems getting modals: "
  108. FORMAT_API_STATUS ".\n", apiStatus ));
  109. return (apiStatus);
  110. }
  111. NetpAssert( modals != NULL );
  112. *minPasswordLength = modals->usrmod0_min_passwd_len;
  113. (VOID) NetApiBufferFree( (LPVOID)modals );
  114. return (NO_ERROR);
  115. } // XsGetMinPasswordLength
  116. STATIC NET_API_STATUS
  117. XsCheckAndReplacePassword (
  118. IN DWORD Length
  119. )
  120. /*++
  121. Routine Description
  122. This routine checks the current password's real length to make sure
  123. it is valid, and then generates a reasonably random replacement password
  124. long enough to satisfy the system's modal for minimum password length.
  125. This routine is used by Add and SetInfo handlers below.
  126. Arguments:
  127. Length - Real length of the current password.
  128. Seed - A seed number.
  129. TempPassword - Receives a pointer to a new temporary password. If
  130. this is not specified, the new password is not generated.
  131. Return Value:
  132. NET_API_STATUS - NERR_Success on successful completion, or some other
  133. error status.
  134. --*/
  135. {
  136. NET_API_STATUS status;
  137. DWORD minPasswordLength;
  138. //
  139. // Find out how long the password has to be.
  140. //
  141. status = XsGetMinPasswordLength( &minPasswordLength );
  142. if ( status != NERR_Success ) {
  143. NetpKdPrint(( PREFIX_XACTSRV
  144. "XsCheckAndReplacePassword: Problems getting min PW len: "
  145. FORMAT_API_STATUS ".\n", status ));
  146. return status;
  147. }
  148. //
  149. // Check length of current password.
  150. //
  151. if ( Length < minPasswordLength ) {
  152. return NERR_PasswordTooShort;
  153. }
  154. return NERR_Success;
  155. }
  156. NET_API_STATUS
  157. XsNameToRid(
  158. IN LPCTSTR Name, // may be user or group name.
  159. IN SID_NAME_USE ExpectedType,
  160. OUT PULONG UserRid
  161. )
  162. {
  163. NET_API_STATUS status;
  164. PSID_NAME_USE nameUse;
  165. NTSTATUS ntstatus;
  166. UNICODE_STRING unicodeName;
  167. PULONG tempRid;
  168. PSID accountsDomainId;
  169. SAM_HANDLE samConnectHandle;
  170. SAM_HANDLE samAccountsDomainHandle;
  171. if( ARGUMENT_PRESENT( UserRid ) ) {
  172. *UserRid = 0;
  173. }
  174. //
  175. // Get a connection to SAM.
  176. //
  177. ntstatus = SamConnect(
  178. NULL, // no server name (local)
  179. &samConnectHandle, // resulting SAM handle
  180. SAM_SERVER_LOOKUP_DOMAIN, // desired access
  181. NULL // no object attributes
  182. );
  183. if ( !NT_SUCCESS( ntstatus ) ) {
  184. status = NetpNtStatusToApiStatus( ntstatus );
  185. return status;
  186. }
  187. //
  188. // To open the accounts domain, we'll need the domain ID.
  189. //
  190. status = NetpGetLocalDomainId (
  191. LOCAL_DOMAIN_TYPE_ACCOUNTS, // type we want.
  192. &accountsDomainId
  193. );
  194. if ( status != NO_ERROR ) {
  195. SamCloseHandle( samConnectHandle );
  196. return status;
  197. }
  198. //
  199. // Open the accounts domain.
  200. //
  201. ntstatus = SamOpenDomain(
  202. samConnectHandle,
  203. DOMAIN_LOOKUP,
  204. accountsDomainId,
  205. &samAccountsDomainHandle
  206. );
  207. if ( !NT_SUCCESS( ntstatus ) ) {
  208. LocalFree( accountsDomainId );
  209. SamCloseHandle( samConnectHandle );
  210. status = NetpNtStatusToApiStatus( ntstatus );
  211. return status;
  212. }
  213. //
  214. // Get a RID for this user name.
  215. //
  216. RtlInitUnicodeString(
  217. &unicodeName, // dest (NT struct)
  218. Name ); // src (null-terminated)
  219. ntstatus = SamLookupNamesInDomain(
  220. samAccountsDomainHandle, // users live in accounts domain
  221. (ULONG)1, // only want one name.
  222. &unicodeName, // name (in NT struct)
  223. &tempRid, // alloc and set RIDs.
  224. &nameUse // alloc and set name types.
  225. );
  226. if ( !NT_SUCCESS( ntstatus ) ) {
  227. status = NetpNtStatusToApiStatus( ntstatus );
  228. goto cleanup;
  229. }
  230. *UserRid = *tempRid;
  231. //
  232. // Did type user wanted match the actual one?
  233. //
  234. if ( ExpectedType != *nameUse ) {
  235. status = ERROR_INVALID_PARAMETER;
  236. } else {
  237. status = NO_ERROR;
  238. }
  239. //
  240. // Free memory which SAM allocated for us.
  241. //
  242. ntstatus = SamFreeMemory( nameUse );
  243. if ( !NT_SUCCESS( ntstatus ) ) {
  244. status = NetpNtStatusToApiStatus( ntstatus );
  245. }
  246. ntstatus = SamFreeMemory( tempRid );
  247. if ( !NT_SUCCESS( ntstatus ) ) {
  248. status = NetpNtStatusToApiStatus( ntstatus );
  249. }
  250. cleanup:
  251. LocalFree( accountsDomainId );
  252. SamCloseHandle( samAccountsDomainHandle );
  253. SamCloseHandle( samConnectHandle );
  254. return status;
  255. } // XsNameToRid
  256. NET_API_STATUS
  257. XsSetMacPrimaryGroup(
  258. IN LPCTSTR UserName,
  259. IN LPCTSTR MacPrimaryField // field in "mGroup:junk" format.
  260. )
  261. {
  262. NET_API_STATUS status;
  263. LPTSTR groupName = NULL;
  264. ULONG groupRid;
  265. USER_INFO_1051 userInfo;
  266. //
  267. // Extract the primary group name from the Mac field.
  268. //
  269. status = NetpGetPrimaryGroupFromMacField(
  270. MacPrimaryField, // name in "mGroup:" format.
  271. &groupName // alloc and set ptr.
  272. );
  273. if ( status != NO_ERROR ) {
  274. goto cleanup;
  275. }
  276. //
  277. // Make sure this user is a member of the group (add to group if needed).
  278. // This will also check if the group and user exist.
  279. //
  280. status = NetGroupAddUser(
  281. NULL, // local (no server name)
  282. groupName, // group to update
  283. (LPTSTR)UserName // user name to add to group
  284. );
  285. if ( (status != NO_ERROR) && (status != NERR_UserInGroup) ) {
  286. goto cleanup;
  287. }
  288. //
  289. // Convert the group name to a RID.
  290. //
  291. status = XsNameToRid(
  292. (LPCWSTR)groupName,
  293. SidTypeGroup, // expected type
  294. &groupRid
  295. );
  296. if ( status != NO_ERROR ) {
  297. goto cleanup;
  298. }
  299. //
  300. // Call NetUserSetInfo to set the primary group ID using the RID.
  301. //
  302. userInfo.usri1051_primary_group_id = (DWORD)groupRid;
  303. status = NetUserSetInfo (
  304. NULL, // local (no server name)
  305. (LPTSTR)UserName,
  306. PARMNUM_BASE_INFOLEVEL + USER_PRIMARY_GROUP_PARMNUM,
  307. (LPVOID)&userInfo,
  308. NULL // don't care about parmnum
  309. );
  310. cleanup:
  311. if ( groupName != NULL ) {
  312. NetpMemoryFree( groupName );
  313. }
  314. return status;
  315. } // XsSetMacPrimaryGroup
  316. NTSTATUS
  317. XsNetUserAdd2 (
  318. API_HANDLER_PARAMETERS
  319. )
  320. /*++
  321. Routine Description:
  322. This routine handles a call to NetUserAdd. A remote NetUserAdd call
  323. from a 16-bit machine will translate to a NetUserAdd2 call, with
  324. a doubly encrypted password. We will call a special level of
  325. NetUserSetInfo to set this later, after the user has been added.
  326. Arguments:
  327. API_HANDLER_PARAMETERS - information about the API call. See
  328. XsTypes.h for details.
  329. Return Value:
  330. NTSTATUS - STATUS_SUCCESS or reason for failure.
  331. --*/
  332. {
  333. NET_API_STATUS status;
  334. PXS_NET_USER_ADD_2 parameters = Parameters;
  335. LPVOID buffer = NULL; // Native parameters
  336. LPBYTE stringLocation = NULL; // Conversion variables
  337. DWORD bytesRequired = 0;
  338. DWORD bufferSize;
  339. LPBYTE nativeStructureDesc;
  340. LPUSER_INFO_1 user = NULL;
  341. DWORD parmError;
  342. DWORD level;
  343. BOOLEAN encryptionSupported = TRUE;
  344. PUSER_INFO_22 usri22;
  345. BYTE tempPwdBuffer[ENCRYPTED_PWLEN];
  346. API_HANDLER_PARAMETERS_REFERENCE; // Avoid warnings
  347. IF_DEBUG(USER) {
  348. NetpKdPrint(( "XsNetUserAdd2: header at %lx, params at %lx, "
  349. "level %ld\n",
  350. Header, parameters,
  351. SmbGetUshort( &parameters->Level ) ));
  352. }
  353. try {
  354. //
  355. // Check if password is encrypted. We know for a fact that dos redirs
  356. // don't support encryption
  357. //
  358. encryptionSupported = (BOOLEAN)
  359. ( SmbGetUshort( &parameters->DataEncryption ) == TRUE );
  360. level = SmbGetUshort( &parameters->Level );
  361. //
  362. // Check for password length
  363. //
  364. status = XsCheckAndReplacePassword( (DWORD)( SmbGetUshort( &parameters->PasswordLength )) );
  365. if ( status != NERR_Success ) {
  366. IF_DEBUG(ERRORS) {
  367. NetpKdPrint(( "XsNetUserAdd2: XsCheckAndReplacePassword failed: "
  368. "%X\n", status ));
  369. }
  370. goto cleanup;
  371. }
  372. //
  373. // Use the requested level to determine the format of the 32-bit
  374. // we need to pass to NetUserAdd. The format of the
  375. // 16-bit structure is stored in the transaction block, and we
  376. // got a pointer to it as a parameter.
  377. //
  378. switch ( level ) {
  379. case 1:
  380. StructureDesc = Desc16_user_info_1;
  381. nativeStructureDesc = Desc32_user_info_1_OWF;
  382. break;
  383. case 2:
  384. StructureDesc = Desc16_user_info_2;
  385. nativeStructureDesc = Desc32_user_info_22;
  386. break;
  387. default:
  388. status = ERROR_INVALID_LEVEL;
  389. goto cleanup;
  390. }
  391. //
  392. // Figure out if there is enough room in the buffer for all the
  393. // data required. If not, return NERR_BufTooSmall.
  394. //
  395. if ( !XsCheckBufferSize(
  396. SmbGetUshort( &parameters->BufLen ),
  397. StructureDesc,
  398. FALSE // not in native format
  399. )) {
  400. IF_DEBUG(ERRORS) {
  401. NetpKdPrint(( "XsNetUserAdd2: Buffer too small.\n" ));
  402. }
  403. status = NERR_BufTooSmall;
  404. goto cleanup;
  405. }
  406. //
  407. // Find out how big a buffer we need to allocate to hold the native
  408. // 32-bit version of the input data structure. Always allocate
  409. // a level 22 buffer since we will always be making a level 22
  410. // call to netuseradd.
  411. //
  412. bufferSize = XsBytesForConvertedStructure(
  413. (LPBYTE)XsSmbGetPointer( &parameters->Buffer ),
  414. StructureDesc,
  415. Desc32_user_info_22,
  416. RapToNative,
  417. TRUE
  418. );
  419. //
  420. // Allocate enough memory to hold the converted native buffer.
  421. //
  422. buffer = NetpMemoryAllocate( bufferSize );
  423. if ( buffer == NULL ) {
  424. IF_DEBUG(ERRORS) {
  425. NetpKdPrint(( "XsNetUserAdd2: failed to create buffer" ));
  426. }
  427. status = NERR_NoRoom;
  428. goto cleanup;
  429. }
  430. IF_DEBUG(USER) {
  431. NetpKdPrint(( "XsNetUserAdd2: buffer of %ld bytes at %lx\n",
  432. bufferSize, buffer ));
  433. }
  434. //
  435. // Convert the buffer from 16-bit to 32-bit.
  436. //
  437. stringLocation = (LPBYTE)buffer + bufferSize;
  438. bytesRequired = 0;
  439. status = RapConvertSingleEntry(
  440. (LPBYTE)XsSmbGetPointer( &parameters->Buffer ),
  441. StructureDesc,
  442. TRUE,
  443. buffer,
  444. buffer,
  445. nativeStructureDesc,
  446. FALSE,
  447. &stringLocation,
  448. &bytesRequired,
  449. Response,
  450. RapToNative
  451. );
  452. if ( status != NERR_Success ) {
  453. IF_DEBUG(ERRORS) {
  454. NetpKdPrint(( "XsNetUserAdd: RapConvertSingleEntry failed: "
  455. "%X\n", status ));
  456. }
  457. status = NERR_InternalError;
  458. goto cleanup;
  459. }
  460. usri22 = buffer;
  461. //
  462. // If this is a level 1 call, then we did not fill up all the
  463. // entries required for a level 22 call. Put the default values
  464. // here.
  465. //
  466. if ( level == 1 ) {
  467. //
  468. // These are not used in a NetUserAdd.
  469. //
  470. // usri22->usri22_last_logon
  471. // usri22->usri22_last_logoff
  472. // usri22->usri22_units_per_week
  473. // usri22->usri22_bad_pw_count
  474. // usri22->usri22_num_logons
  475. //
  476. usri22->usri22_auth_flags = 0;
  477. usri22->usri22_full_name = NULL;
  478. usri22->usri22_usr_comment = NULL;
  479. usri22->usri22_parms = NULL;
  480. usri22->usri22_workstations = NULL;
  481. usri22->usri22_acct_expires = TIMEQ_FOREVER;
  482. usri22->usri22_max_storage = USER_MAXSTORAGE_UNLIMITED;
  483. usri22->usri22_logon_hours = NULL;
  484. usri22->usri22_logon_server = NULL;
  485. usri22->usri22_country_code = 0;
  486. usri22->usri22_code_page = 0;
  487. } else if ( usri22->usri22_logon_hours != NULL ) {
  488. //
  489. // Call NetpRotateLogonHours to make sure we behave properly
  490. // during DST.
  491. //
  492. if ( !NetpRotateLogonHours(
  493. usri22->usri22_logon_hours,
  494. usri22->usri22_units_per_week,
  495. TRUE
  496. ) ) {
  497. status = ERROR_INVALID_PARAMETER;
  498. goto cleanup;
  499. }
  500. }
  501. //
  502. // If the password is clear text, we need to convert it to an OWF
  503. // password. This is to fix a LMUNIX bug which forgets to upper
  504. // case the password it sends across. Converting it to OWF
  505. // tells sam not to do upcasing.
  506. //
  507. // If the password is encrypted, then we get the owf by decrypting
  508. // it with the session key.
  509. //
  510. RtlCopyMemory(
  511. tempPwdBuffer,
  512. usri22->usri22_password,
  513. ENCRYPTED_PWLEN
  514. );
  515. if ( !encryptionSupported ) {
  516. (VOID) RtlCalculateLmOwfPassword(
  517. (PLM_PASSWORD) tempPwdBuffer,
  518. (PLM_OWF_PASSWORD) usri22->usri22_password
  519. );
  520. } else {
  521. (VOID) RtlDecryptLmOwfPwdWithLmSesKey(
  522. (PENCRYPTED_LM_OWF_PASSWORD) tempPwdBuffer,
  523. (PLM_SESSION_KEY) Header->EncryptionKey,
  524. (PLM_OWF_PASSWORD) usri22->usri22_password
  525. );
  526. }
  527. //
  528. // Make the local call.
  529. //
  530. status = NetUserAdd(
  531. NULL,
  532. 22,
  533. (LPBYTE) usri22,
  534. &parmError
  535. );
  536. if ( !XsApiSuccess( status )) {
  537. IF_DEBUG(ERRORS) {
  538. NetpKdPrint(( "XsNetUserAdd2: NetUserAdd failed: %X\n", status ));
  539. if ( status == ERROR_INVALID_PARAMETER ) {
  540. NetpKdPrint(( "XsNetUserAdd2: ParmError: %ld\n",
  541. parmError ));
  542. }
  543. }
  544. goto cleanup;
  545. }
  546. //
  547. // If there was a Macintosh primary group field for this user, then
  548. // set the primary group.
  549. //
  550. if ( NetpIsMacPrimaryGroupFieldValid( (LPCTSTR)usri22->usri22_parms ) ) {
  551. NET_API_STATUS status1;
  552. status1 = XsSetMacPrimaryGroup(
  553. (LPCTSTR)usri22->usri22_name,
  554. (LPCTSTR)usri22->usri22_parms
  555. );
  556. if ( !XsApiSuccess( status1 )) {
  557. IF_DEBUG(ERRORS) {
  558. NetpKdPrint(( "XsNetUserAdd2: SetMacPrimaryGroup failed: %X\n",
  559. status1 ));
  560. }
  561. }
  562. }
  563. //
  564. // There is no real return information for this API.
  565. //
  566. cleanup:
  567. ;
  568. } except( EXCEPTION_EXECUTE_HANDLER ) {
  569. status = (WORD)RtlNtStatusToDosError( GetExceptionCode() );
  570. }
  571. Header->Status = (WORD)status;
  572. NetpMemoryFree( buffer );
  573. return STATUS_SUCCESS;
  574. } // XsNetUserAdd2
  575. NTSTATUS
  576. XsNetUserDel (
  577. API_HANDLER_PARAMETERS
  578. )
  579. /*++
  580. Routine Description:
  581. This routine handles a call to NetUserDel.
  582. Arguments:
  583. API_HANDLER_PARAMETERS - information about the API call. See
  584. XsTypes.h for details.
  585. Return Value:
  586. NTSTATUS - STATUS_SUCCESS or reason for failure.
  587. --*/
  588. {
  589. NET_API_STATUS status;
  590. PXS_NET_USER_DEL parameters = Parameters;
  591. LPTSTR nativeUserName = NULL; // Native parameters
  592. API_HANDLER_PARAMETERS_REFERENCE; // Avoid warnings
  593. IF_DEBUG(USER) {
  594. NetpKdPrint(( "XsNetUserDel: header at %lx, params at %lx, name %s\n",
  595. Header, parameters, SmbGetUlong( &parameters->UserName )));
  596. }
  597. try {
  598. //
  599. // Translate parameters, check for errors.
  600. //
  601. XsConvertTextParameter(
  602. nativeUserName,
  603. (LPSTR)XsSmbGetPointer( &parameters->UserName )
  604. );
  605. //
  606. // Make the local call.
  607. //
  608. status = NetUserDel(
  609. NULL,
  610. nativeUserName
  611. );
  612. if ( !XsApiSuccess( status )) {
  613. IF_DEBUG(ERRORS) {
  614. NetpKdPrint(( "XsNetUserDel: NetUserDel failed: %X\n", status ));
  615. }
  616. }
  617. cleanup:
  618. ;
  619. } except( EXCEPTION_EXECUTE_HANDLER ) {
  620. Header->Status = (WORD)RtlNtStatusToDosError( GetExceptionCode() );
  621. }
  622. NetpMemoryFree( nativeUserName );
  623. //
  624. // Nothing to return.
  625. //
  626. Header->Status = (WORD)status;
  627. return STATUS_SUCCESS;
  628. }
  629. NTSTATUS
  630. XsNetUserEnum (
  631. API_HANDLER_PARAMETERS
  632. )
  633. /*++
  634. Routine Description
  635. This routine handles a call to NetUserEnum.
  636. Arguments:
  637. API_HANDLER_PARAMETERS - information about the API call. See
  638. XsTypes.h for details.
  639. Return Value:
  640. NTSTATUS - STATUS_SUCCESS or reason for failure.
  641. --*/
  642. {
  643. NET_API_STATUS status;
  644. PXS_NET_USER_ENUM parameters = Parameters;
  645. LPVOID outBuffer = NULL; // Native parameters
  646. DWORD entriesRead;
  647. DWORD totalEntries;
  648. DWORD entriesFilled = 0; // Conversion variables
  649. DWORD bytesRequired = 0;
  650. LPBYTE nativeStructureDesc;
  651. API_HANDLER_PARAMETERS_REFERENCE; // Avoid parameters
  652. IF_DEBUG(USER) {
  653. NetpKdPrint(( "XsNetUserEnum: header at %lx, params at %lx, "
  654. "level %ld, buf size %ld\n",
  655. Header, parameters, SmbGetUshort( &parameters->Level ),
  656. SmbGetUshort( &parameters->BufLen )));
  657. }
  658. try {
  659. //
  660. // Check for errors.
  661. //
  662. if (( XsWordParamOutOfRange( parameters->Level, 0, 2 ))
  663. && SmbGetUshort( &parameters->Level ) != 10 ) {
  664. Header->Status = ERROR_INVALID_LEVEL;
  665. goto cleanup;
  666. }
  667. //
  668. // Make the local call.
  669. //
  670. status = NetUserEnum(
  671. NULL,
  672. (DWORD)SmbGetUshort( &parameters->Level ),
  673. FILTER_NORMAL_ACCOUNT,
  674. (LPBYTE *)&outBuffer,
  675. XsNativeBufferSize( SmbGetUshort( &parameters->BufLen )),
  676. &entriesRead,
  677. &totalEntries,
  678. NULL
  679. );
  680. if ( !XsApiSuccess( status )) {
  681. IF_DEBUG(API_ERRORS) {
  682. NetpKdPrint(( "XsNetUserEnum: NetUserEnum failed: %X\n", status ));
  683. }
  684. Header->Status = (WORD)status;
  685. goto cleanup;
  686. }
  687. IF_DEBUG(USER) {
  688. NetpKdPrint(( "XsNetUserEnum: received %ld entries at %lx\n",
  689. entriesRead, outBuffer ));
  690. }
  691. //
  692. // Use the requested level to determine the format of the
  693. // data structure.
  694. //
  695. switch ( SmbGetUshort( &parameters->Level ) ) {
  696. case 0:
  697. nativeStructureDesc = Desc32_user_info_0;
  698. StructureDesc = Desc16_user_info_0;
  699. break;
  700. case 1:
  701. nativeStructureDesc = Desc32_user_info_1;
  702. StructureDesc = Desc16_user_info_1;
  703. break;
  704. case 2:
  705. nativeStructureDesc = Desc32_user_info_2;
  706. StructureDesc = Desc16_user_info_2;
  707. break;
  708. case 10:
  709. nativeStructureDesc = Desc32_user_info_10;
  710. StructureDesc = Desc16_user_info_10;
  711. break;
  712. }
  713. //
  714. // Do the actual conversion from the 32-bit structures to 16-bit
  715. // structures.
  716. //
  717. XsFillEnumBuffer(
  718. outBuffer,
  719. entriesRead,
  720. nativeStructureDesc,
  721. (LPVOID)XsSmbGetPointer( &parameters->Buffer ),
  722. (LPVOID)XsSmbGetPointer( &parameters->Buffer ),
  723. SmbGetUshort( &parameters->BufLen ),
  724. StructureDesc,
  725. NULL, // verify function
  726. &bytesRequired,
  727. &entriesFilled,
  728. NULL
  729. );
  730. IF_DEBUG(USER) {
  731. NetpKdPrint(( "32-bit data at %lx, 16-bit data at %lx, %ld BR,"
  732. " Entries %ld of %ld\n",
  733. outBuffer, SmbGetUlong( &parameters->Buffer ),
  734. bytesRequired, entriesFilled, totalEntries ));
  735. }
  736. //
  737. // If all the entries could not be filled, return ERROR_MORE_DATA,
  738. // and return the buffer as is. Otherwise, the data needs to be
  739. // packed so that we don't send too much useless data.
  740. //
  741. if ( entriesFilled < totalEntries ) {
  742. Header->Status = ERROR_MORE_DATA;
  743. } else {
  744. Header->Converter = XsPackReturnData(
  745. (LPVOID)XsSmbGetPointer( &parameters->Buffer ),
  746. SmbGetUshort( &parameters->BufLen ),
  747. StructureDesc,
  748. entriesFilled
  749. );
  750. }
  751. //
  752. // Set up the response parameters.
  753. //
  754. SmbPutUshort( &parameters->EntriesRead, (WORD)entriesFilled );
  755. SmbPutUshort( &parameters->TotalAvail, (WORD)totalEntries );
  756. cleanup:
  757. ;
  758. } except( EXCEPTION_EXECUTE_HANDLER ) {
  759. Header->Status = (WORD)RtlNtStatusToDosError( GetExceptionCode() );
  760. }
  761. NetApiBufferFree( outBuffer );
  762. //
  763. // Determine return buffer size.
  764. //
  765. XsSetDataCount(
  766. &parameters->BufLen,
  767. StructureDesc,
  768. Header->Converter,
  769. entriesFilled,
  770. Header->Status
  771. );
  772. return STATUS_SUCCESS;
  773. } // XsNetUserEnum
  774. NTSTATUS
  775. XsNetUserEnum2 (
  776. API_HANDLER_PARAMETERS
  777. )
  778. /*++
  779. Routine Description:
  780. This routine handles a call to NetUserEnum. This version supports a
  781. resumable handle.
  782. Arguments:
  783. API_HANDLER_PARAMETERS - information about the API call. See
  784. XsTypes.h for details.
  785. Return Value:
  786. NTSTATUS - STATUS_SUCCESS or reason for failure.
  787. --*/
  788. {
  789. NET_API_STATUS status;
  790. PXS_NET_USER_ENUM_2 parameters = Parameters;
  791. LPVOID outBuffer = NULL; // Native parameters
  792. DWORD TotalEntriesToReturn = 0;
  793. LPDESC nativeStructureDesc;
  794. DWORD nativeBufferSize = 0xFFFFFFFF;
  795. DWORD entriesRead = 0;
  796. DWORD PreviousEntriesRead;
  797. DWORD totalEntries;
  798. DWORD entriesFilled = 0; // Conversion variables
  799. DWORD bytesRequired;
  800. LPBYTE bufferBegin;
  801. DWORD bufferSize;
  802. DWORD totalEntriesRead= 0;
  803. DWORD resumeKey;
  804. LPBYTE SavedBufferBegin;
  805. DWORD SavedBufferSize;
  806. DWORD SavedTotalEntriesRead;
  807. DWORD SavedResumeKey;
  808. API_HANDLER_PARAMETERS_REFERENCE; // Avoid warnings
  809. try {
  810. IF_DEBUG(USER) {
  811. NetpKdPrint(( "XsNetUserEnum2: header at %lx, params at %lx, "
  812. "level %ld, buf size %ld\n",
  813. Header, parameters, SmbGetUshort( &parameters->Level ),
  814. SmbGetUshort( &parameters->BufLen )));
  815. }
  816. //
  817. // Copy input resume handle to output resume handle, and get a copy of it.
  818. //
  819. resumeKey = SmbGetUlong( &parameters->ResumeIn );
  820. SmbPutUlong( &parameters->ResumeOut, resumeKey );
  821. IF_DEBUG(USER) {
  822. NetpKdPrint(( "XsNetUserEnum2: resume key is %ld\n", resumeKey ));
  823. }
  824. //
  825. // Use the level to determine the descriptor string.
  826. //
  827. switch ( SmbGetUshort( &parameters->Level ) ) {
  828. case 0:
  829. nativeStructureDesc = Desc32_user_info_0;
  830. StructureDesc = Desc16_user_info_0;
  831. break;
  832. case 1:
  833. nativeStructureDesc = Desc32_user_info_1;
  834. StructureDesc = Desc16_user_info_1;
  835. break;
  836. case 2:
  837. nativeStructureDesc = Desc32_user_info_2;
  838. StructureDesc = Desc16_user_info_2;
  839. break;
  840. case 10:
  841. nativeStructureDesc = Desc32_user_info_10;
  842. StructureDesc = Desc16_user_info_10;
  843. break;
  844. default:
  845. //
  846. // Unsupported levels, abort before any work.
  847. //
  848. Header->Status = ERROR_INVALID_LEVEL;
  849. goto cleanup;
  850. }
  851. //
  852. // NetUserEnum2 is a resumable API, so we cannot get more information
  853. // from the native call than we can send back. The most efficient way
  854. // to do this is in a loop...we use the 16-bit buffer size to determine
  855. // a safe native buffer size, make the call, fill the entries, then
  856. // take the amount of space remaining and determine a safe size again,
  857. // and so on, until NetUserEnum returns either no entries or all entries
  858. // read.
  859. //
  860. //
  861. // Initialize important variables for loop.
  862. //
  863. bufferBegin = (LPBYTE)XsSmbGetPointer( &parameters->Buffer );
  864. bufferSize = (DWORD)SmbGetUshort( &parameters->BufLen );
  865. totalEntriesRead = 0;
  866. for ( ; ; ) {
  867. //
  868. // Compute a safe size for the native buffer.
  869. //
  870. // It is better to underguess than overguess. NetUserEnum is relatively
  871. // efficient (especially in the local case) at resuming an enumeration.
  872. // It is relatively inefficient at returning detailed information about
  873. // the enumerated users.
  874. //
  875. // If nativeBufferSize reaches 1 (or 0),
  876. // NetUserEnum will typically enumerate a single user.
  877. //
  878. if ( nativeBufferSize > bufferSize/2 ) {
  879. nativeBufferSize = bufferSize/2;
  880. }
  881. //
  882. // Remember how many we read last time to ensure we make progress.
  883. //
  884. PreviousEntriesRead = entriesRead;
  885. //
  886. // Save away a copy of all the important variables.
  887. //
  888. // The NetUserEnum API can actually overshoot its PrefMaxLen. The
  889. // values being saved are values known to not already have been overshot.
  890. // We can restore these values later if needed.
  891. //
  892. SavedBufferBegin = bufferBegin;
  893. SavedBufferSize = bufferSize;
  894. SavedTotalEntriesRead = totalEntriesRead;
  895. SavedResumeKey = resumeKey;
  896. //
  897. // Make the local call.
  898. //
  899. status = NetUserEnum(
  900. NULL,
  901. (DWORD)SmbGetUshort( &parameters->Level ),
  902. FILTER_NORMAL_ACCOUNT,
  903. (LPBYTE *)&outBuffer,
  904. nativeBufferSize,
  905. &entriesRead,
  906. &totalEntries,
  907. &resumeKey
  908. );
  909. if ( !XsApiSuccess( status )) {
  910. IF_DEBUG(API_ERRORS) {
  911. NetpKdPrint(( "XsNetUserEnum2: NetUserEnum failed: %X\n",
  912. status ));
  913. }
  914. Header->Status = (WORD)status;
  915. goto cleanup;
  916. }
  917. IF_DEBUG(USER) {
  918. NetpKdPrint(( "XsNetUserEnum2: received %ld entries out of %ld at %lx asking for %ld bytes.\n",
  919. entriesRead, totalEntries, outBuffer, nativeBufferSize ));
  920. NetpKdPrint(( "XsNetUserEnum2: resume key is now %ld\n",
  921. resumeKey ));
  922. }
  923. //
  924. // Keep track of the total entries available.
  925. //
  926. if ( totalEntries > TotalEntriesToReturn ) {
  927. TotalEntriesToReturn = totalEntries;
  928. }
  929. //
  930. // Was NetUserEnum able to read at least one complete entry?
  931. //
  932. if ( entriesRead == 0 ) {
  933. break;
  934. }
  935. //
  936. // Do the actual conversion from the 32-bit structures to 16-bit
  937. // structures.
  938. //
  939. XsFillEnumBuffer(
  940. outBuffer,
  941. entriesRead,
  942. nativeStructureDesc,
  943. bufferBegin,
  944. (LPBYTE)XsSmbGetPointer( &parameters->Buffer ),
  945. bufferSize,
  946. StructureDesc,
  947. NULL, // verify function
  948. &bytesRequired,
  949. &entriesFilled,
  950. NULL
  951. );
  952. IF_DEBUG(USER) {
  953. NetpKdPrint(( "XsNetUserEnum2: 32-bit data at %lx, 16-bit data at %lx, %ld BR,"
  954. " Entries %ld of %ld\n",
  955. outBuffer, SmbGetUlong( &parameters->Buffer ),
  956. bytesRequired, entriesFilled, entriesRead ));
  957. }
  958. //
  959. // If NetUserEnum overshot PrefMaxLen,
  960. // we can't simply return the collected data since we wouldn't
  961. // know what to use as a ResumeHandle.
  962. //
  963. if ( entriesRead != entriesFilled ) {
  964. //
  965. // Restore the saved values.
  966. //
  967. bufferBegin = SavedBufferBegin;
  968. bufferSize = SavedBufferSize;
  969. totalEntriesRead = SavedTotalEntriesRead;
  970. resumeKey = SavedResumeKey;
  971. //
  972. // If we have ANY data to return to the caller,
  973. // return the short list now rather than trying to outguess NetUserEnum
  974. //
  975. if ( totalEntriesRead != 0 ) {
  976. IF_DEBUG(USER) {
  977. NetpKdPrint(( "XsNetUserEnum2: couldn't pack data: return previous data\n" ));
  978. }
  979. break;
  980. }
  981. //
  982. // If we've already asked NetUserEnum for the smallest amount,
  983. // just give up.
  984. //
  985. if ( nativeBufferSize == 1 || entriesRead == 1 ) {
  986. status = NERR_BufTooSmall;
  987. IF_DEBUG(API_ERRORS) {
  988. NetpKdPrint(( "XsNetUserEnum2: NetUserEnum buffer too small: %X\n",
  989. status ));
  990. }
  991. Header->Status = (WORD)status;
  992. goto cleanup;
  993. }
  994. //
  995. // Otherwise, trim it down and try again.
  996. // If we've tried twice and gotten the same result,
  997. // be really agressive.
  998. //
  999. if ( entriesRead == PreviousEntriesRead || entriesRead < 10 ) {
  1000. nativeBufferSize = 1;
  1001. } else {
  1002. nativeBufferSize /= 2;
  1003. }
  1004. //
  1005. // If NetUserEnum returned useful data,
  1006. // account for it.
  1007. //
  1008. } else {
  1009. //
  1010. // Update count of entries read.
  1011. //
  1012. totalEntriesRead += entriesRead;
  1013. //
  1014. // Are there any more entries to read?
  1015. //
  1016. if ( entriesRead == totalEntries ) {
  1017. break;
  1018. }
  1019. //
  1020. // If we've made the nativeBufferSize so small we're barely making
  1021. // progress,
  1022. // just return what we have to the caller.
  1023. //
  1024. if ( entriesRead == 1 ) {
  1025. break;
  1026. }
  1027. //
  1028. // Calculate new buffer beginning and size.
  1029. //
  1030. bufferBegin += entriesRead *
  1031. RapStructureSize( StructureDesc, Response, FALSE );
  1032. bufferSize -= bytesRequired;
  1033. //
  1034. // Don't hassle the last few bytes,
  1035. // we'll just overshoot anyway.
  1036. //
  1037. if ( bufferSize < 50 ) {
  1038. break;
  1039. }
  1040. }
  1041. //
  1042. // Free last native buffer.
  1043. //
  1044. NetApiBufferFree( outBuffer );
  1045. outBuffer = NULL;
  1046. }
  1047. //
  1048. // Upon exit from the loop, totalEntriesRead has the number of entries
  1049. // read, TotalEntriesToReturn has the number available from NetUserEnum.
  1050. // Formulate return codes, etc. from these values.
  1051. //
  1052. if ( totalEntriesRead < TotalEntriesToReturn ) {
  1053. Header->Status = ERROR_MORE_DATA;
  1054. } else {
  1055. Header->Converter = XsPackReturnData(
  1056. (LPVOID)XsSmbGetPointer( &parameters->Buffer ),
  1057. SmbGetUshort( &parameters->BufLen ),
  1058. StructureDesc,
  1059. totalEntriesRead
  1060. );
  1061. }
  1062. IF_DEBUG(USER) {
  1063. NetpKdPrint(( "XsNetUserEnum2: returning %ld entries of %ld. Resume key is now %ld\n",
  1064. totalEntriesRead,
  1065. TotalEntriesToReturn,
  1066. resumeKey ));
  1067. }
  1068. //
  1069. // Set up the response parameters.
  1070. //
  1071. SmbPutUshort( &parameters->EntriesRead, (WORD)totalEntriesRead );
  1072. SmbPutUshort( &parameters->TotalAvail,
  1073. (WORD)( TotalEntriesToReturn ));
  1074. SmbPutUlong( &parameters->ResumeOut, resumeKey );
  1075. cleanup:
  1076. ;
  1077. } except( EXCEPTION_EXECUTE_HANDLER ) {
  1078. Header->Status = (WORD)RtlNtStatusToDosError( GetExceptionCode() );
  1079. }
  1080. NetApiBufferFree( outBuffer );
  1081. //
  1082. // Determine return buffer size.
  1083. //
  1084. XsSetDataCount(
  1085. &parameters->BufLen,
  1086. StructureDesc,
  1087. Header->Converter,
  1088. totalEntriesRead,
  1089. Header->Status
  1090. );
  1091. return STATUS_SUCCESS;
  1092. } // XsNetUserEnum2
  1093. NTSTATUS
  1094. XsNetUserGetGroups (
  1095. API_HANDLER_PARAMETERS
  1096. )
  1097. /*++
  1098. Routine Description:
  1099. This routine handles a call to NetUserGetGroups.
  1100. Arguments:
  1101. API_HANDLER_PARAMETERS - information about the API call. See
  1102. XsTypes.h for details.
  1103. Return Value:
  1104. NTSTATUS - STATUS_SUCCESS or reason for failure.
  1105. --*/
  1106. {
  1107. NET_API_STATUS status;
  1108. PXS_NET_USER_GET_GROUPS parameters = Parameters;
  1109. LPTSTR nativeUserName = NULL; // Native parameters
  1110. LPVOID outBuffer= NULL;
  1111. DWORD entriesRead;
  1112. DWORD totalEntries;
  1113. DWORD entriesFilled = 0; // Conversion variables
  1114. DWORD bytesRequired = 0;
  1115. API_HANDLER_PARAMETERS_REFERENCE; // Avoid warnings
  1116. try {
  1117. IF_DEBUG(USER) {
  1118. NetpKdPrint(( "XsNetUserGetGroups: header at %lx, params at %lx, "
  1119. "level %ld, buf size %ld\n",
  1120. Header, parameters, SmbGetUshort( &parameters->Level ),
  1121. SmbGetUshort( &parameters->BufLen )));
  1122. }
  1123. //
  1124. // Translate parameters, check for errors.
  1125. //
  1126. if ( SmbGetUshort( &parameters->Level ) != 0 ) {
  1127. Header->Status = ERROR_INVALID_LEVEL;
  1128. goto cleanup;
  1129. }
  1130. XsConvertTextParameter(
  1131. nativeUserName,
  1132. (LPSTR)XsSmbGetPointer( &parameters->UserName )
  1133. );
  1134. //
  1135. // Get the actual information from the local 32-bit call.
  1136. //
  1137. status = NetUserGetGroups(
  1138. NULL,
  1139. nativeUserName,
  1140. (DWORD)SmbGetUshort( &parameters->Level ),
  1141. (LPBYTE *)&outBuffer,
  1142. XsNativeBufferSize( SmbGetUshort( &parameters->BufLen )),
  1143. &entriesRead,
  1144. &totalEntries
  1145. );
  1146. if ( !XsApiSuccess( status )) {
  1147. IF_DEBUG(API_ERRORS) {
  1148. NetpKdPrint(( "XsNetUserGetGroups: NetUserGetGroups failed: %X\n",
  1149. status ));
  1150. }
  1151. Header->Status = (WORD)status;
  1152. goto cleanup;
  1153. }
  1154. IF_DEBUG(USER) {
  1155. NetpKdPrint(( "XsNetUserGetGroups: received %ld entries at %lx\n",
  1156. entriesRead, outBuffer ));
  1157. }
  1158. //
  1159. // Do the conversion from 32- to 16-bit data.
  1160. //
  1161. XsFillEnumBuffer(
  1162. outBuffer,
  1163. entriesRead,
  1164. Desc32_user_group_info_0,
  1165. (LPVOID)XsSmbGetPointer( &parameters->Buffer ),
  1166. (LPVOID)XsSmbGetPointer( &parameters->Buffer ),
  1167. SmbGetUshort( &parameters->BufLen ),
  1168. Desc16_user_group_info_0,
  1169. NULL, // verify function
  1170. &bytesRequired,
  1171. &entriesFilled,
  1172. NULL
  1173. );
  1174. IF_DEBUG(USER) {
  1175. NetpKdPrint(( "32-bit data at %lx, 16-bit data at %lx, %ld BR,"
  1176. " Entries %ld of %ld\n",
  1177. outBuffer, SmbGetUlong( &parameters->Buffer ),
  1178. bytesRequired, entriesFilled, totalEntries ));
  1179. }
  1180. //
  1181. // If there is no room for one fixed structure, return NERR_BufTooSmall.
  1182. // If all the entries could not be filled, return ERROR_MORE_DATA,
  1183. // and return the buffer as is. GROUP_INFO_0 structures don't
  1184. // need to be packed, because they have no variable data.
  1185. //
  1186. if ( !XsCheckBufferSize(
  1187. SmbGetUshort( &parameters->BufLen ),
  1188. Desc16_user_group_info_0,
  1189. FALSE // not in native format
  1190. )) {
  1191. Header->Status = NERR_BufTooSmall;
  1192. } else if ( entriesFilled < totalEntries ) {
  1193. Header->Status = ERROR_MORE_DATA;
  1194. }
  1195. //
  1196. // Set up the response parameters.
  1197. //
  1198. SmbPutUshort( &parameters->EntriesRead, (WORD)entriesFilled );
  1199. SmbPutUshort( &parameters->TotalAvail, (WORD)totalEntries );
  1200. cleanup:
  1201. ;
  1202. } except( EXCEPTION_EXECUTE_HANDLER ) {
  1203. Header->Status = (WORD)RtlNtStatusToDosError( GetExceptionCode() );
  1204. }
  1205. NetApiBufferFree( outBuffer );
  1206. NetpMemoryFree( nativeUserName );
  1207. //
  1208. // Determine return buffer size.
  1209. //
  1210. XsSetDataCount(
  1211. &parameters->BufLen,
  1212. Desc16_user_group_info_0,
  1213. Header->Converter,
  1214. entriesFilled,
  1215. Header->Status
  1216. );
  1217. return STATUS_SUCCESS;
  1218. } // XsNetUserGetGroups
  1219. NTSTATUS
  1220. XsNetUserGetInfo (
  1221. API_HANDLER_PARAMETERS
  1222. )
  1223. /*++
  1224. Routine Description:
  1225. This routine handles a call to NetUserGetInfo.
  1226. Arguments:
  1227. API_HANDLER_PARAMETERS - information about the API call. See
  1228. XsTypes.h for details.
  1229. Return Value:
  1230. NTSTATUS - STATUS_SUCCESS or reason for failure.
  1231. --*/
  1232. {
  1233. NET_API_STATUS status;
  1234. PXS_NET_USER_GET_INFO parameters = Parameters;
  1235. LPTSTR nativeUserName = NULL; // Native parameters
  1236. LPVOID outBuffer = NULL;
  1237. LPBYTE stringLocation = NULL; // Conversion variables
  1238. DWORD bytesRequired = 0;
  1239. LPBYTE nativeStructureDesc;
  1240. DWORD level;
  1241. API_HANDLER_PARAMETERS_REFERENCE; // Avoid warnings
  1242. try {
  1243. IF_DEBUG(USER) {
  1244. NetpKdPrint(( "XsNetUserGetInfo: header at %lx, "
  1245. "params at %lx, level %ld\n",
  1246. Header, parameters, SmbGetUshort( &parameters->Level ) ));
  1247. }
  1248. //
  1249. // Translate parameters, check for errors.
  1250. //
  1251. level = SmbGetUshort( &parameters->Level );
  1252. if ( XsWordParamOutOfRange( level, 0, 2 )
  1253. && XsWordParamOutOfRange( level, 10, 11 )) {
  1254. Header->Status = ERROR_INVALID_LEVEL;
  1255. goto cleanup;
  1256. }
  1257. XsConvertTextParameter(
  1258. nativeUserName,
  1259. (LPSTR)XsSmbGetPointer( &parameters->UserName )
  1260. );
  1261. //
  1262. // Make the local call.
  1263. //
  1264. status = NetUserGetInfo(
  1265. NULL,
  1266. nativeUserName,
  1267. level,
  1268. (LPBYTE *)&outBuffer
  1269. );
  1270. if ( !XsApiSuccess( status )) {
  1271. IF_DEBUG(API_ERRORS) {
  1272. NetpKdPrint(( "XsNetUserGetInfo: NetUserGetInfo failed: "
  1273. "%X\n", status ));
  1274. }
  1275. Header->Status = (WORD)status;
  1276. goto cleanup;
  1277. }
  1278. //
  1279. // Use the requested level to determine the format of the
  1280. // data structure.
  1281. //
  1282. switch ( level ) {
  1283. case 0:
  1284. nativeStructureDesc = Desc32_user_info_0;
  1285. StructureDesc = Desc16_user_info_0;
  1286. break;
  1287. case 1:
  1288. nativeStructureDesc = Desc32_user_info_1;
  1289. StructureDesc = Desc16_user_info_1;
  1290. break;
  1291. case 2:
  1292. {
  1293. PUSER_INFO_2 usri2 = outBuffer;
  1294. //
  1295. // Call NetpRotateLogonHours to make sure we behave properly
  1296. // during DST.
  1297. //
  1298. if ( usri2->usri2_logon_hours != NULL ) {
  1299. if ( !NetpRotateLogonHours(
  1300. usri2->usri2_logon_hours,
  1301. usri2->usri2_units_per_week,
  1302. FALSE
  1303. ) ) {
  1304. Header->Status = NERR_InternalError;
  1305. goto cleanup;
  1306. }
  1307. }
  1308. //
  1309. // Truncate UserParms to 48 bytes
  1310. //
  1311. if (( usri2->usri2_parms != NULL ) &&
  1312. (wcslen(usri2->usri2_parms) > LM20_MAXCOMMENTSZ))
  1313. {
  1314. *(usri2->usri2_parms + LM20_MAXCOMMENTSZ) = UNICODE_NULL;
  1315. }
  1316. nativeStructureDesc = Desc32_user_info_2;
  1317. StructureDesc = Desc16_user_info_2;
  1318. }
  1319. break;
  1320. case 10:
  1321. nativeStructureDesc = Desc32_user_info_10;
  1322. StructureDesc = Desc16_user_info_10;
  1323. break;
  1324. case 11:
  1325. {
  1326. PUSER_INFO_11 usri11 = outBuffer;
  1327. //
  1328. // Call NetpRotateLogonHours to make sure we behave properly
  1329. // during DST.
  1330. //
  1331. if ( usri11->usri11_logon_hours != NULL ) {
  1332. if ( !NetpRotateLogonHours(
  1333. usri11->usri11_logon_hours,
  1334. usri11->usri11_units_per_week,
  1335. FALSE
  1336. ) ) {
  1337. Header->Status = NERR_InternalError;
  1338. goto cleanup;
  1339. }
  1340. }
  1341. //
  1342. // Truncate UserParms to 48 bytes
  1343. //
  1344. if (( usri11->usri11_parms != NULL ) &&
  1345. (wcslen(usri11->usri11_parms) > LM20_MAXCOMMENTSZ))
  1346. {
  1347. *(usri11->usri11_parms + LM20_MAXCOMMENTSZ) = UNICODE_NULL;
  1348. }
  1349. nativeStructureDesc = Desc32_user_info_11;
  1350. StructureDesc = Desc16_user_info_11;
  1351. }
  1352. break;
  1353. }
  1354. //
  1355. // Convert the structure returned by the 32-bit call to a 16-bit
  1356. // structure. The last possible location for variable data is
  1357. // calculated from buffer location and length.
  1358. //
  1359. stringLocation = (LPBYTE)( XsSmbGetPointer( &parameters->Buffer )
  1360. + SmbGetUshort( &parameters->BufLen ) );
  1361. status = RapConvertSingleEntry(
  1362. outBuffer,
  1363. nativeStructureDesc,
  1364. FALSE,
  1365. (LPBYTE)XsSmbGetPointer( &parameters->Buffer ),
  1366. (LPBYTE)XsSmbGetPointer( &parameters->Buffer ),
  1367. StructureDesc,
  1368. TRUE,
  1369. &stringLocation,
  1370. &bytesRequired,
  1371. Response,
  1372. NativeToRap
  1373. );
  1374. if ( status != NERR_Success ) {
  1375. IF_DEBUG(ERRORS) {
  1376. NetpKdPrint(( "XsNetUserGetInfo: RapConvertSingleEntry failed: "
  1377. "%X\n", status ));
  1378. }
  1379. Header->Status = NERR_InternalError;
  1380. goto cleanup;
  1381. }
  1382. IF_DEBUG(USER) {
  1383. NetpKdPrint(( "32-bit data at %lx, 16-bit data at %lx, %ld BR\n",
  1384. outBuffer, SmbGetUlong( &parameters->Buffer ),
  1385. bytesRequired ));
  1386. }
  1387. //
  1388. // Determine return code based on the size of the buffer.
  1389. //
  1390. if ( !XsCheckBufferSize(
  1391. SmbGetUshort( &parameters->BufLen ),
  1392. StructureDesc,
  1393. FALSE // not in native format
  1394. )) {
  1395. IF_DEBUG(ERRORS) {
  1396. NetpKdPrint(( "XsNetUserGetInfo: Buffer too small %ld s.b. %ld.\n",
  1397. SmbGetUshort( &parameters->BufLen ),
  1398. RapStructureSize(
  1399. StructureDesc,
  1400. Response,
  1401. FALSE ) ));
  1402. }
  1403. Header->Status = NERR_BufTooSmall;
  1404. } else if ( bytesRequired > (DWORD)SmbGetUshort( &parameters-> BufLen )) {
  1405. IF_DEBUG(ERRORS) {
  1406. NetpKdPrint(( "NetUserGetInfo: More data available.\n" ));
  1407. }
  1408. Header->Status = ERROR_MORE_DATA;
  1409. } else {
  1410. //
  1411. // Pack the response data.
  1412. //
  1413. Header->Converter = XsPackReturnData(
  1414. (LPVOID)XsSmbGetPointer( &parameters->Buffer ),
  1415. SmbGetUshort( &parameters->BufLen ),
  1416. StructureDesc,
  1417. 1
  1418. );
  1419. }
  1420. //
  1421. // Set up the response parameters.
  1422. //
  1423. SmbPutUshort( &parameters->TotalAvail, (WORD)bytesRequired );
  1424. cleanup:
  1425. ;
  1426. } except( EXCEPTION_EXECUTE_HANDLER ) {
  1427. Header->Status = (WORD)RtlNtStatusToDosError( GetExceptionCode() );
  1428. }
  1429. NetApiBufferFree( outBuffer );
  1430. NetpMemoryFree( nativeUserName );
  1431. //
  1432. // Determine return buffer size.
  1433. //
  1434. XsSetDataCount(
  1435. &parameters->BufLen,
  1436. StructureDesc,
  1437. Header->Converter,
  1438. 1,
  1439. Header->Status
  1440. );
  1441. return STATUS_SUCCESS;
  1442. } // XsNetUserGetInfo
  1443. NTSTATUS
  1444. XsNetUserModalsGet (
  1445. API_HANDLER_PARAMETERS
  1446. )
  1447. /*++
  1448. Routine Description:
  1449. This routine handles a call to NetUserModalsGet.
  1450. Arguments:
  1451. API_HANDLER_PARAMETERS - information about the API call. See
  1452. XsTypes.h for details.
  1453. Return Value:
  1454. NTSTATUS - STATUS_SUCCESS or reason for failure.
  1455. --*/
  1456. {
  1457. NET_API_STATUS status;
  1458. PXS_NET_USER_MODALS_GET parameters = Parameters;
  1459. LPVOID outBuffer = NULL; // Native parameters
  1460. LPBYTE stringLocation = NULL; // Conversion variables
  1461. DWORD bytesRequired = 0;
  1462. LPBYTE nativeStructureDesc;
  1463. API_HANDLER_PARAMETERS_REFERENCE; // Avoid warnings
  1464. try {
  1465. IF_DEBUG(USER) {
  1466. NetpKdPrint(( "XsNetUserModalsGet: header at %lx, "
  1467. "params at %lx, level %ld\n",
  1468. Header, parameters, SmbGetUshort( &parameters->Level ) ));
  1469. }
  1470. //
  1471. // Check for errors.
  1472. //
  1473. if ( XsWordParamOutOfRange( parameters->Level, 0, 1 )) {
  1474. Header->Status = ERROR_INVALID_LEVEL;
  1475. goto cleanup;
  1476. }
  1477. //
  1478. // Make the local call.
  1479. //
  1480. status = NetUserModalsGet(
  1481. NULL,
  1482. (DWORD)SmbGetUshort( &parameters->Level ),
  1483. (LPBYTE *)&outBuffer
  1484. );
  1485. if ( !XsApiSuccess( status )) {
  1486. IF_DEBUG(API_ERRORS) {
  1487. NetpKdPrint(( "XsNetUserModalsGet: NetUserModalsGet failed: "
  1488. "%X\n", status ));
  1489. }
  1490. Header->Status = (WORD)status;
  1491. goto cleanup;
  1492. }
  1493. //
  1494. // Use the requested level to determine the format of the
  1495. // data structure.
  1496. //
  1497. switch ( SmbGetUshort( &parameters->Level ) ) {
  1498. case 0:
  1499. nativeStructureDesc = Desc32_user_modals_info_0;
  1500. StructureDesc = Desc16_user_modals_info_0;
  1501. break;
  1502. case 1:
  1503. nativeStructureDesc = Desc32_user_modals_info_1;
  1504. StructureDesc = Desc16_user_modals_info_1;
  1505. break;
  1506. }
  1507. //
  1508. // Convert the structure returned by the 32-bit call to a 16-bit
  1509. // structure. The last possible location for variable data is
  1510. // calculated from buffer location and length.
  1511. //
  1512. stringLocation = (LPBYTE)( XsSmbGetPointer( &parameters->Buffer )
  1513. + SmbGetUshort( &parameters->BufLen ) );
  1514. status = RapConvertSingleEntry(
  1515. outBuffer,
  1516. nativeStructureDesc,
  1517. FALSE,
  1518. (LPBYTE)XsSmbGetPointer( &parameters->Buffer ),
  1519. (LPBYTE)XsSmbGetPointer( &parameters->Buffer ),
  1520. StructureDesc,
  1521. TRUE,
  1522. &stringLocation,
  1523. &bytesRequired,
  1524. Response,
  1525. NativeToRap
  1526. );
  1527. if ( status != NERR_Success ) {
  1528. IF_DEBUG(ERRORS) {
  1529. NetpKdPrint(( "XsNetUserModalsGet: RapConvertSingleEntry failed: "
  1530. "%X\n", status ));
  1531. }
  1532. Header->Status = NERR_InternalError;
  1533. goto cleanup;
  1534. }
  1535. IF_DEBUG(USER) {
  1536. NetpKdPrint(( "32-bit data at %lx, 16-bit data at %lx, %ld BR\n",
  1537. outBuffer, SmbGetUlong( &parameters->Buffer ),
  1538. bytesRequired ));
  1539. }
  1540. //
  1541. // Determine return code based on the size of the buffer.
  1542. //
  1543. if ( !XsCheckBufferSize(
  1544. SmbGetUshort( &parameters->BufLen ),
  1545. StructureDesc,
  1546. FALSE // not in native format
  1547. )) {
  1548. IF_DEBUG(ERRORS) {
  1549. NetpKdPrint(( "XsNetUserModalsGet: Buffer too small.\n" ));
  1550. }
  1551. Header->Status = NERR_BufTooSmall;
  1552. } else if ( bytesRequired > (DWORD)SmbGetUshort( &parameters-> BufLen )) {
  1553. IF_DEBUG(ERRORS) {
  1554. NetpKdPrint(( "NetUserModalsGet: More data available.\n" ));
  1555. }
  1556. Header->Status = ERROR_MORE_DATA;
  1557. } else {
  1558. //
  1559. // Pack the response data.
  1560. //
  1561. Header->Converter = XsPackReturnData(
  1562. (LPVOID)XsSmbGetPointer( &parameters->Buffer ),
  1563. SmbGetUshort( &parameters->BufLen ),
  1564. StructureDesc,
  1565. 1
  1566. );
  1567. }
  1568. //
  1569. // Set up the response parameters.
  1570. //
  1571. SmbPutUshort( &parameters->TotalAvail, (WORD)bytesRequired );
  1572. cleanup:
  1573. ;
  1574. } except( EXCEPTION_EXECUTE_HANDLER ) {
  1575. Header->Status = (WORD)RtlNtStatusToDosError( GetExceptionCode() );
  1576. }
  1577. NetApiBufferFree( outBuffer );
  1578. //
  1579. // Determine return buffer size.
  1580. //
  1581. XsSetDataCount(
  1582. &parameters->BufLen,
  1583. StructureDesc,
  1584. Header->Converter,
  1585. 1,
  1586. Header->Status
  1587. );
  1588. return STATUS_SUCCESS;
  1589. } // XsNetUserModalsGet
  1590. NTSTATUS
  1591. XsNetUserModalsSet (
  1592. API_HANDLER_PARAMETERS
  1593. )
  1594. /*++
  1595. Routine Description:
  1596. This routine handles a call to NetUserModalsSet.
  1597. Arguments:
  1598. API_HANDLER_PARAMETERS - information about the API call. See
  1599. XsTypes.h for details.
  1600. Return Value:
  1601. NTSTATUS - STATUS_SUCCESS or reason for failure.
  1602. --*/
  1603. {
  1604. NET_API_STATUS status;
  1605. PXS_NET_USER_MODALS_SET parameters = Parameters;
  1606. DWORD nativeLevel; // Native parameters
  1607. LPVOID buffer = NULL;
  1608. LPDESC setInfoDesc; // Conversion variables
  1609. LPDESC nativeSetInfoDesc;
  1610. LPDESC nativeStructureDesc;
  1611. API_HANDLER_PARAMETERS_REFERENCE; // Avoid warnings
  1612. try {
  1613. //
  1614. // Check for errors.
  1615. //
  1616. if ( XsWordParamOutOfRange( parameters->Level, 0, 1 )) {
  1617. Header->Status = ERROR_INVALID_LEVEL;
  1618. goto cleanup;
  1619. }
  1620. //
  1621. // First of all, the 32-bit parmnum is a bit messed up. If the level
  1622. // is 2, the new parmnum is 5 plus the old parmnum.
  1623. //
  1624. nativeLevel = XsLevelFromParmNum( SmbGetUshort( &parameters->Level ),
  1625. SmbGetUshort( &parameters->ParmNum ));
  1626. switch ( SmbGetUshort( &parameters->Level )) {
  1627. case 0:
  1628. StructureDesc = Desc16_user_modals_info_0;
  1629. nativeStructureDesc = Desc32_user_modals_info_0;
  1630. setInfoDesc = Desc16_user_modals_info_0_setinfo;
  1631. nativeSetInfoDesc = Desc32_user_modals_info_0_setinfo;
  1632. break;
  1633. case 1:
  1634. StructureDesc = Desc16_user_modals_info_1;
  1635. nativeStructureDesc = Desc32_user_modals_info_1;
  1636. setInfoDesc = Desc16_user_modals_info_1_setinfo;
  1637. nativeSetInfoDesc = Desc32_user_modals_info_1_setinfo;
  1638. if ( nativeLevel != (DWORD)SmbGetUshort( &parameters->Level )) {
  1639. nativeLevel += 5;
  1640. }
  1641. break;
  1642. }
  1643. status = XsConvertSetInfoBuffer(
  1644. (LPBYTE)XsSmbGetPointer( &parameters->Buffer ),
  1645. SmbGetUshort( &parameters->BufLen ),
  1646. SmbGetUshort( &parameters->ParmNum ),
  1647. TRUE,
  1648. TRUE,
  1649. StructureDesc,
  1650. nativeStructureDesc,
  1651. setInfoDesc,
  1652. nativeSetInfoDesc,
  1653. (LPBYTE *)&buffer,
  1654. NULL
  1655. );
  1656. if ( status != NERR_Success ) {
  1657. IF_DEBUG(ERRORS) {
  1658. NetpKdPrint(( "XsNetUserModalsSet: Problem with conversion: %X\n",
  1659. status ));
  1660. }
  1661. Header->Status = (WORD)status;
  1662. goto cleanup;
  1663. }
  1664. //
  1665. // Make the local call.
  1666. //
  1667. status = NetUserModalsSet(
  1668. NULL,
  1669. nativeLevel,
  1670. buffer,
  1671. NULL
  1672. );
  1673. if ( !XsApiSuccess( status )) {
  1674. IF_DEBUG(ERRORS) {
  1675. NetpKdPrint(( "XsNetUserModalsSet: NetUserModalsSet failed: %X\n",
  1676. status ));
  1677. }
  1678. Header->Status = (WORD)status;
  1679. goto cleanup;
  1680. }
  1681. //
  1682. // No return information for this API.
  1683. //
  1684. cleanup:
  1685. ;
  1686. } except( EXCEPTION_EXECUTE_HANDLER ) {
  1687. Header->Status = (WORD)RtlNtStatusToDosError( GetExceptionCode() );
  1688. }
  1689. //
  1690. // If there is a native 32-bit buffer, free it.
  1691. //
  1692. NetpMemoryFree( buffer );
  1693. return STATUS_SUCCESS;
  1694. } // XsNetUserModalsSet
  1695. NTSTATUS
  1696. XsNetUserPasswordSet2 (
  1697. API_HANDLER_PARAMETERS
  1698. )
  1699. /*++
  1700. Routine Description:
  1701. This routine handles a call to NetUserPasswordSet. This call is
  1702. translated to NetUserPasswordSet2 when remotely called from a
  1703. 16-bit machine.
  1704. Arguments:
  1705. API_HANDLER_PARAMETERS - information about the API call. See
  1706. XsTypes.h for details.
  1707. Return Value:
  1708. NTSTATUS - STATUS_SUCCESS or reason for failure.
  1709. --*/
  1710. {
  1711. NET_API_STATUS status;
  1712. PXS_NET_USER_PASSWORD_SET_2 parameters = Parameters;
  1713. LPTSTR nativeUserName = NULL; // Native parameters
  1714. UNICODE_STRING UserName;
  1715. API_HANDLER_PARAMETERS_REFERENCE; // Avoid warnings
  1716. try {
  1717. //
  1718. // Convert the username.
  1719. //
  1720. XsConvertTextParameter(
  1721. nativeUserName,
  1722. (LPSTR)XsSmbGetPointer( &parameters->UserName )
  1723. );
  1724. RtlInitUnicodeString(
  1725. &UserName,
  1726. nativeUserName
  1727. );
  1728. //
  1729. // Check the password length.
  1730. //
  1731. status = XsCheckAndReplacePassword( (DWORD)( SmbGetUshort( &parameters->PasswordLength )) );
  1732. if ( status != NERR_Success ) {
  1733. IF_DEBUG(ERRORS) {
  1734. NetpKdPrint(( "XsNetUserPasswordSet2: XsCheckAndReplacePassword "
  1735. "failed: %X\n", status ));
  1736. }
  1737. goto cleanup;
  1738. }
  1739. status = XsChangePasswordSam(
  1740. &UserName,
  1741. parameters->OldPassword,
  1742. parameters->NewPassword,
  1743. (BOOLEAN)SmbGetUshort( &parameters->DataEncryption )
  1744. );
  1745. //
  1746. // No return data.
  1747. //
  1748. cleanup:
  1749. ;
  1750. } except( EXCEPTION_EXECUTE_HANDLER ) {
  1751. Header->Status = (WORD)RtlNtStatusToDosError( GetExceptionCode() );
  1752. }
  1753. NetpMemoryFree( nativeUserName );
  1754. Header->Status = (WORD)status;
  1755. return STATUS_SUCCESS;
  1756. } // XsNetUserPasswordSet2
  1757. NTSTATUS
  1758. XsNetUserSetGroups (
  1759. API_HANDLER_PARAMETERS
  1760. )
  1761. /*++
  1762. Routine Description:
  1763. This routine handles a call to NetUserSetGroups.
  1764. Arguments:
  1765. API_HANDLER_PARAMETERS - information about the API call. See
  1766. XsTypes.h for details.
  1767. Return Value:
  1768. NTSTATUS - STATUS_SUCCESS or reason for failure.
  1769. --*/
  1770. {
  1771. NET_API_STATUS status;
  1772. PXS_NET_USER_SET_GROUPS parameters = Parameters;
  1773. LPTSTR nativeUserName = NULL; // Native parameters
  1774. LPBYTE actualBuffer = NULL;
  1775. DWORD groupCount;
  1776. LPBYTE stringLocation = NULL; // Conversion variables
  1777. LPVOID buffer = NULL;
  1778. DWORD bytesRequired = 0;
  1779. LPDESC longDescriptor = NULL;
  1780. LPDESC longNativeDescriptor = NULL;
  1781. DWORD bufferSize;
  1782. DWORD i;
  1783. API_HANDLER_PARAMETERS_REFERENCE; // Avoid warnings
  1784. try {
  1785. IF_DEBUG(USER) {
  1786. NetpKdPrint(( "XsNetUserSetGroups: header at %lx, params at %lx,"
  1787. "level %ld\n",
  1788. Header, parameters, SmbGetUshort( &parameters->Level ) ));
  1789. }
  1790. //
  1791. // Translate parameters, check for errors.
  1792. //
  1793. if ( SmbGetUshort( &parameters->Level ) != 0 ) {
  1794. Header->Status = ERROR_INVALID_LEVEL;
  1795. goto cleanup;
  1796. }
  1797. StructureDesc = Desc16_user_group_info_0_set;
  1798. AuxStructureDesc = Desc16_user_group_info_0;
  1799. XsConvertTextParameter(
  1800. nativeUserName,
  1801. (LPSTR)XsSmbGetPointer( &parameters->UserName )
  1802. );
  1803. //
  1804. // Use the count of group_info_0 structures to form a long
  1805. // descriptor string which can be used to do all the conversion
  1806. // in one pass.
  1807. //
  1808. groupCount = (DWORD)SmbGetUshort( &parameters->Entries );
  1809. longDescriptor = NetpMemoryAllocate(
  1810. strlen( StructureDesc )
  1811. + strlen( AuxStructureDesc ) * groupCount
  1812. + 1 );
  1813. longNativeDescriptor = NetpMemoryAllocate(
  1814. strlen( Desc32_user_group_info_0_set )
  1815. + strlen( Desc32_user_group_info_0 )
  1816. * groupCount
  1817. + 1 );
  1818. if (( longDescriptor == NULL ) || ( longNativeDescriptor == NULL )) {
  1819. IF_DEBUG(ERRORS) {
  1820. NetpKdPrint(( "XsNetUserSetGroups: failed to allocate memory" ));
  1821. }
  1822. Header->Status = NERR_NoRoom;
  1823. goto cleanup;
  1824. }
  1825. strcpy( longDescriptor, StructureDesc );
  1826. strcpy( longNativeDescriptor, Desc32_user_group_info_0_set );
  1827. for ( i = 0; i < groupCount; i++ ) {
  1828. strcat( longDescriptor, AuxStructureDesc );
  1829. strcat( longNativeDescriptor, Desc32_user_group_info_0 );
  1830. }
  1831. //
  1832. // Figure out if there is enough room in the buffer for all this
  1833. // data. If not, return NERR_BufTooSmall.
  1834. //
  1835. if ( !XsCheckBufferSize(
  1836. SmbGetUshort( &parameters->BufLen ),
  1837. longDescriptor,
  1838. FALSE // not in native format
  1839. )) {
  1840. IF_DEBUG(ERRORS) {
  1841. NetpKdPrint(( "XsNetUserSetGroups: Buffer too small.\n" ));
  1842. }
  1843. Header->Status = NERR_BufTooSmall;
  1844. goto cleanup;
  1845. }
  1846. //
  1847. // Find out how big a buffer we need to allocate to hold the native
  1848. // 32-bit version of the input data structure.
  1849. //
  1850. bufferSize = XsBytesForConvertedStructure(
  1851. (LPBYTE)XsSmbGetPointer( &parameters->Buffer ),
  1852. longDescriptor,
  1853. longNativeDescriptor,
  1854. RapToNative,
  1855. TRUE
  1856. );
  1857. //
  1858. // Allocate enough memory to hold the converted native buffer.
  1859. //
  1860. buffer = NetpMemoryAllocate( bufferSize );
  1861. if ( buffer == NULL ) {
  1862. IF_DEBUG(ERRORS) {
  1863. NetpKdPrint(( "XsNetUserSetGroups: failed to create buffer" ));
  1864. }
  1865. Header->Status = NERR_NoRoom;
  1866. goto cleanup;
  1867. }
  1868. IF_DEBUG(USER) {
  1869. NetpKdPrint(( "XsNetUserSetGroups: buffer of %ld bytes at %lx\n",
  1870. bufferSize, buffer ));
  1871. }
  1872. //
  1873. // Convert the buffer from 16-bit to 32-bit.
  1874. //
  1875. stringLocation = (LPBYTE)buffer + bufferSize;
  1876. bytesRequired = 0;
  1877. status = RapConvertSingleEntry(
  1878. (LPBYTE)XsSmbGetPointer( &parameters->Buffer ),
  1879. longDescriptor,
  1880. TRUE,
  1881. buffer,
  1882. buffer,
  1883. longNativeDescriptor,
  1884. FALSE,
  1885. &stringLocation,
  1886. &bytesRequired,
  1887. Response,
  1888. RapToNative
  1889. );
  1890. if ( status != NERR_Success ) {
  1891. IF_DEBUG(ERRORS) {
  1892. NetpKdPrint(( "XsNetUserSetGroups: RapConvertSingleEntry failed: "
  1893. "%X\n", status ));
  1894. }
  1895. Header->Status = NERR_InternalError;
  1896. goto cleanup;
  1897. }
  1898. //
  1899. // Check if we got all the entries. If not, we'll quit.
  1900. //
  1901. if ( RapAuxDataCount( buffer, Desc32_user_group_info_0_set, Both, TRUE )
  1902. != groupCount ) {
  1903. Header->Status = NERR_BufTooSmall;
  1904. goto cleanup;
  1905. }
  1906. //
  1907. // If there are no entries, there's no data. Otherwise, the data comes
  1908. // after an initial header structure.
  1909. //
  1910. if ( groupCount > 0 ) {
  1911. actualBuffer = (LPBYTE)buffer + RapStructureSize(
  1912. Desc32_user_group_info_0_set,
  1913. Both,
  1914. TRUE
  1915. );
  1916. } else {
  1917. actualBuffer = NULL;
  1918. }
  1919. //
  1920. // Make the local call.
  1921. //
  1922. status = NetUserSetGroups(
  1923. NULL,
  1924. nativeUserName,
  1925. (DWORD)SmbGetUshort( &parameters->Level ),
  1926. actualBuffer,
  1927. (DWORD)groupCount
  1928. );
  1929. if ( !XsApiSuccess( status )) {
  1930. IF_DEBUG(ERRORS) {
  1931. NetpKdPrint(( "XsNetUserSetGroups: NetUserSetGroups failed: %X\n",
  1932. status ));
  1933. }
  1934. Header->Status = (WORD)status;
  1935. goto cleanup;
  1936. }
  1937. //
  1938. // There is no real return information for this API.
  1939. //
  1940. cleanup:
  1941. ;
  1942. } except( EXCEPTION_EXECUTE_HANDLER ) {
  1943. Header->Status = (WORD)RtlNtStatusToDosError( GetExceptionCode() );
  1944. }
  1945. NetpMemoryFree( buffer );
  1946. NetpMemoryFree( longDescriptor );
  1947. NetpMemoryFree( longNativeDescriptor );
  1948. NetpMemoryFree( nativeUserName );
  1949. return STATUS_SUCCESS;
  1950. } // XsNetUserSetGroups
  1951. NTSTATUS
  1952. XsNetUserSetInfo2 (
  1953. API_HANDLER_PARAMETERS
  1954. )
  1955. /*++
  1956. Routine Description:
  1957. This routine handles a call to NetUserSetInfo2. A remote NetUserGetInfo2
  1958. call from a 16-bit machine is translated to NetUserGetInfo2, with
  1959. an encrypted password. This routine has to check for a password set
  1960. and handle it properly, by using level 21 to set the password.
  1961. Arguments:
  1962. API_HANDLER_PARAMETERS - information about the API call. See
  1963. XsTypes.h for details.
  1964. Return Value:
  1965. NTSTATUS - STATUS_SUCCESS or reason for failure.
  1966. --*/
  1967. {
  1968. NET_API_STATUS status = NO_ERROR;
  1969. PXS_NET_USER_SET_INFO_2 parameters = Parameters;
  1970. LPTSTR nativeUserName = NULL; // Native parameters
  1971. LPVOID buffer = NULL;
  1972. WORD bufLen;
  1973. DWORD level;
  1974. BYTE newPassword[ENCRYPTED_PWLEN];
  1975. LPDESC setInfoDesc; // Conversion variables
  1976. LPVOID nativePasswordArea = NULL; // Points to Unicode or encrypted.
  1977. LPDESC nativeSetInfoDesc;
  1978. LPDESC nativeStructureDesc;
  1979. LPUSER_INFO_2 user = NULL;
  1980. PUSER_16_INFO_1 user16 = NULL;
  1981. USER_INFO_1020 usri1020;
  1982. BOOLEAN changePassword = FALSE;
  1983. BOOLEAN changeUserInfo = FALSE;
  1984. BOOLEAN encryptionSupported = TRUE;
  1985. WORD parmNum;
  1986. PUSER_INFO_2 Susri2 = NULL;
  1987. //
  1988. // avoid warnings;
  1989. //
  1990. API_HANDLER_PARAMETERS_REFERENCE;
  1991. try {
  1992. bufLen = SmbGetUshort( &parameters->BufLen );
  1993. level = SmbGetUshort( &parameters->Level );
  1994. parmNum = SmbGetUshort( &parameters->ParmNum );
  1995. IF_DEBUG(USER) {
  1996. NetpKdPrint((
  1997. "XsNetUserSetInfo2: header at " FORMAT_LPVOID ", "
  1998. "params at " FORMAT_LPVOID ",\n "
  1999. "level " FORMAT_DWORD ", parmnum " FORMAT_DWORD ", "
  2000. "buflen " FORMAT_WORD_ONLY "\n",
  2001. Header, parameters,
  2002. level, parmNum, bufLen ));
  2003. }
  2004. //
  2005. // Translate parameters
  2006. //
  2007. XsConvertTextParameter(
  2008. nativeUserName,
  2009. (LPSTR)XsSmbGetPointer( &parameters->UserName )
  2010. );
  2011. //
  2012. // Check if password is encrypted. We know for a fact that dos redirs
  2013. // don't support encryption
  2014. //
  2015. encryptionSupported = (BOOLEAN)
  2016. ( SmbGetUshort( &parameters->DataEncryption ) == TRUE );
  2017. //
  2018. // Determine descriptor strings based on level.
  2019. //
  2020. switch ( level ) {
  2021. case 1:
  2022. StructureDesc = Desc16_user_info_1;
  2023. setInfoDesc = Desc16_user_info_1_setinfo;
  2024. if ( encryptionSupported ) {
  2025. nativeStructureDesc = Desc32_user_info_1;
  2026. nativeSetInfoDesc = Desc32_user_info_1_setinfo;
  2027. } else {
  2028. nativeStructureDesc = Desc32_user_info_1_NC;
  2029. nativeSetInfoDesc = Desc32_user_info_1_setinfo_NC;
  2030. }
  2031. break;
  2032. case 2:
  2033. StructureDesc = Desc16_user_info_2;
  2034. setInfoDesc = Desc16_user_info_2_setinfo;
  2035. if ( encryptionSupported ) {
  2036. nativeStructureDesc = Desc32_user_info_2;
  2037. nativeSetInfoDesc = Desc32_user_info_2_setinfo;
  2038. } else {
  2039. nativeStructureDesc = Desc32_user_info_2_NC;
  2040. nativeSetInfoDesc = Desc32_user_info_2_setinfo_NC;
  2041. }
  2042. break;
  2043. default:
  2044. status = ERROR_INVALID_LEVEL;
  2045. goto cleanup;
  2046. }
  2047. if (parmNum != USER_PASSWORD_PARMNUM) {
  2048. status = XsConvertSetInfoBuffer(
  2049. (LPBYTE)XsSmbGetPointer( &parameters->Buffer ),
  2050. bufLen,
  2051. parmNum,
  2052. TRUE, // yes, convert strings
  2053. TRUE, // yes, meaningless input pointers
  2054. StructureDesc,
  2055. nativeStructureDesc,
  2056. setInfoDesc,
  2057. nativeSetInfoDesc,
  2058. (LPBYTE *)&buffer,
  2059. NULL // don't need output buffer size
  2060. );
  2061. if ( status != NERR_Success ) {
  2062. IF_DEBUG(ERRORS) {
  2063. NetpKdPrint((
  2064. "XsNetUserSetInfo2: Problem with conversion: "
  2065. FORMAT_API_STATUS "\n",
  2066. status ));
  2067. }
  2068. goto cleanup;
  2069. }
  2070. } else {
  2071. XsConvertTextParameter(
  2072. buffer,
  2073. (LPSTR)XsSmbGetPointer( &parameters->Buffer ) );
  2074. }
  2075. NetpAssert( buffer != NULL );
  2076. //
  2077. // Check the password length. A value of -1 means caller wants us
  2078. // to compute the length; see XsNetUserSetInfo below.
  2079. //
  2080. if ( parmNum == PARMNUM_ALL || parmNum == USER_PASSWORD_PARMNUM) {
  2081. WORD passwordLength = SmbGetUshort( &parameters->PasswordLength );
  2082. if (parmNum == PARMNUM_ALL) {
  2083. LPUSER_INFO_2 userInfo = (LPVOID) buffer; // Native structure.
  2084. nativePasswordArea = userInfo->usri2_password; // May be NULL.
  2085. } else {
  2086. nativePasswordArea = buffer; // Entire native buffer.
  2087. if (nativePasswordArea == NULL) {
  2088. status = ERROR_INVALID_PARAMETER;
  2089. goto cleanup;
  2090. }
  2091. }
  2092. if (passwordLength == (WORD)(-1)) {
  2093. if (parameters->DataEncryption) {
  2094. parameters->PasswordLength = ENCRYPTED_PWLEN;
  2095. } else if (nativePasswordArea != NULL) {
  2096. // Unencrypted, count is number of chars, w/o null char.
  2097. parameters->PasswordLength = (USHORT)wcslen( nativePasswordArea );
  2098. } else {
  2099. parameters->PasswordLength = 0;
  2100. }
  2101. }
  2102. status = XsCheckAndReplacePassword( (DWORD)( SmbGetUshort( &parameters->PasswordLength )) );
  2103. if ( status != NERR_Success ) {
  2104. IF_DEBUG(ERRORS) {
  2105. NetpKdPrint(( "XsNetUserSetInfo2: XsCheckAndReplacePassword "
  2106. "failed: " FORMAT_API_STATUS "\n", status ));
  2107. }
  2108. goto cleanup;
  2109. }
  2110. }
  2111. //
  2112. // If necessary, do work with passwords. Also, translate the parmnum to
  2113. // an info level.
  2114. //
  2115. switch( parmNum ) {
  2116. case PARMNUM_ALL:
  2117. //
  2118. // Get the encrypted password.
  2119. //
  2120. user16 = (PUSER_16_INFO_1)XsSmbGetPointer( &parameters->Buffer );
  2121. RtlCopyMemory(
  2122. newPassword,
  2123. user16->usri1_password,
  2124. ENCRYPTED_PWLEN
  2125. );
  2126. user = (LPUSER_INFO_2)buffer;
  2127. user->usri2_password = NULL;
  2128. if ( level == 2 && user->usri2_logon_hours != NULL ) {
  2129. //
  2130. // Call NetpRotateLogonHours to make sure we behave properly
  2131. // during DST.
  2132. //
  2133. if ( !NetpRotateLogonHours(
  2134. user->usri2_logon_hours,
  2135. user->usri2_units_per_week,
  2136. TRUE
  2137. ) ) {
  2138. status = ERROR_INVALID_PARAMETER;
  2139. goto cleanup;
  2140. }
  2141. }
  2142. changePassword = TRUE;
  2143. changeUserInfo = TRUE;
  2144. break;
  2145. case USER_PASSWORD_PARMNUM:
  2146. //
  2147. // We will use level 21 for changing passwords.
  2148. //
  2149. //
  2150. // Get the encrypted password.
  2151. //
  2152. RtlCopyMemory(
  2153. newPassword,
  2154. (PVOID)XsSmbGetPointer( &parameters->Buffer ),
  2155. ENCRYPTED_PWLEN
  2156. );
  2157. changePassword = TRUE;
  2158. break;
  2159. case USER_LOGON_HOURS_PARMNUM:
  2160. usri1020.usri1020_units_per_week = UNITS_PER_WEEK;
  2161. usri1020.usri1020_logon_hours =
  2162. (LPBYTE)XsSmbGetPointer( &parameters->Buffer );
  2163. //
  2164. // Call NetpRotateLogonHours to make sure we behave properly
  2165. // during DST.
  2166. //
  2167. if ( !NetpRotateLogonHours(
  2168. usri1020.usri1020_logon_hours,
  2169. usri1020.usri1020_units_per_week,
  2170. TRUE
  2171. ) ) {
  2172. status = ERROR_INVALID_PARAMETER;
  2173. goto cleanup;
  2174. }
  2175. //
  2176. // Lack of break is intentional
  2177. //
  2178. default:
  2179. changeUserInfo = TRUE;
  2180. level = PARMNUM_BASE_INFOLEVEL + parmNum;
  2181. break;
  2182. }
  2183. //
  2184. // Bug 114883
  2185. // Downlevel clients cannot set more than 48 wchars and if the server
  2186. // did have more than 48 wchars, we were truncating it! We merge the
  2187. // data that the client sent with what exists on the server
  2188. //
  2189. if ((buffer != NULL) &&
  2190. (changeUserInfo) &&
  2191. ((level == 2) || (parmNum == USER_PARMS_PARMNUM)))
  2192. {
  2193. PUSER_INFO_2 Cusri2 = NULL;
  2194. PUSER_INFO_1013 Cusri1013 = NULL;
  2195. LPWSTR UserParms = NULL;
  2196. // Get the pointer to the client's userparms
  2197. if (level == 2)
  2198. {
  2199. Cusri2 = buffer;
  2200. UserParms = Cusri2->usri2_parms;
  2201. }
  2202. else
  2203. {
  2204. Cusri1013 = buffer;
  2205. UserParms = Cusri1013->usri1013_parms;
  2206. }
  2207. //
  2208. // Make the local call.
  2209. //
  2210. status = NetUserGetInfo(
  2211. NULL,
  2212. nativeUserName,
  2213. level,
  2214. (LPBYTE *)&Susri2
  2215. );
  2216. if ( !XsApiSuccess( status )) {
  2217. IF_DEBUG(API_ERRORS) {
  2218. NetpKdPrint(( "XsNetUserGetInfo: NetUserGetInfo failed: "
  2219. "%X\n", status ));
  2220. }
  2221. goto cleanup;
  2222. }
  2223. // If the server userparms field is > 48, we want to do something special
  2224. if (( Susri2->usri2_parms != NULL ) &&
  2225. (wcslen(Susri2->usri2_parms) > LM20_MAXCOMMENTSZ))
  2226. {
  2227. //
  2228. // We need to merge the returned bytes with the local ones
  2229. //
  2230. UINT Length = 0;
  2231. if ( UserParms != NULL )
  2232. {
  2233. //
  2234. // Just to be safe, we never over-write more than 48 wchars.
  2235. //
  2236. Length = wcslen(UserParms);
  2237. if (Length > LM20_MAXCOMMENTSZ)
  2238. {
  2239. Length = LM20_MAXCOMMENTSZ;
  2240. }
  2241. }
  2242. // we copy the bytes that the client sent, but only upto
  2243. // 48 wchars.
  2244. RtlCopyMemory( Susri2->usri2_parms,
  2245. UserParms,
  2246. Length * sizeof(WCHAR));
  2247. // From Length to LM20_MAXCOMMENTSZ, we pad with blanks
  2248. while (Length < LM20_MAXCOMMENTSZ)
  2249. {
  2250. Susri2->usri2_parms[Length++] = L' ';
  2251. }
  2252. // Save the merged user parms
  2253. if (level == 2 )
  2254. {
  2255. Cusri2->usri2_parms = Susri2->usri2_parms;
  2256. }
  2257. else
  2258. {
  2259. Cusri1013->usri1013_parms = Susri2->usri2_parms;
  2260. }
  2261. }
  2262. }
  2263. //
  2264. // Change user infos other than the password
  2265. //
  2266. if ( changeUserInfo ) {
  2267. status = NetUserSetInfo(
  2268. NULL,
  2269. nativeUserName,
  2270. level,
  2271. buffer,
  2272. NULL
  2273. );
  2274. if ( !XsApiSuccess( status )) {
  2275. IF_DEBUG(ERRORS) {
  2276. NetpKdPrint(( "XsNetUserSetInfo2: NetUserSetInfo failed: %X\n",
  2277. status ));
  2278. }
  2279. goto cleanup;
  2280. }
  2281. //
  2282. // If there was a Macintosh primary group field for this user, then
  2283. // set the primary group.
  2284. //
  2285. if ( (level == 2) &&
  2286. NetpIsMacPrimaryGroupFieldValid( (LPCTSTR)user->usri2_parms ) ) {
  2287. NET_API_STATUS status1;
  2288. status1 = XsSetMacPrimaryGroup(
  2289. (LPCTSTR)nativeUserName,
  2290. (LPCTSTR)user->usri2_parms
  2291. );
  2292. if ( !XsApiSuccess( status1 )) {
  2293. IF_DEBUG(ERRORS) {
  2294. NetpKdPrint(( "XsNetUserSetInfo2: SetMacPrimaryGroup "
  2295. "failed: %X\n", status1 ));
  2296. }
  2297. }
  2298. } else if ( (level == USER_PARMS_INFOLEVEL) &&
  2299. NetpIsMacPrimaryGroupFieldValid(
  2300. (LPCTSTR)((LPUSER_INFO_1013)buffer)->usri1013_parms ) ) {
  2301. NET_API_STATUS status1;
  2302. status1 = XsSetMacPrimaryGroup(
  2303. (LPCTSTR)nativeUserName,
  2304. (LPCTSTR)((LPUSER_INFO_1013)buffer)->usri1013_parms
  2305. );
  2306. if ( !XsApiSuccess( status1 )) {
  2307. IF_DEBUG(ERRORS) {
  2308. NetpKdPrint(( "XsNetUserSetInfo2: SetMacPrimaryGroup "
  2309. "failed: %X\n", status1 ));
  2310. }
  2311. }
  2312. }
  2313. }
  2314. //
  2315. // If there is a pending password change, do it now.
  2316. //
  2317. if ( changePassword ) {
  2318. USER_INFO_21 user21;
  2319. if ( !encryptionSupported ) {
  2320. //
  2321. // Do not change password if user sent all blanks. Clear text
  2322. // passwords are only 14 bytes (LM20_PWLEN) long.
  2323. //
  2324. if ( RtlCompareMemory(
  2325. newPassword,
  2326. NULL_USERSETINFO_PASSWD,
  2327. LM20_PWLEN
  2328. ) == LM20_PWLEN ) {
  2329. status = NERR_Success;
  2330. goto cleanup;
  2331. }
  2332. //
  2333. // Change clear text password to OWF
  2334. //
  2335. (VOID) RtlCalculateLmOwfPassword(
  2336. (PLM_PASSWORD) newPassword,
  2337. (PLM_OWF_PASSWORD) user21.usri21_password
  2338. );
  2339. } else {
  2340. BYTE NullOwfPassword[ENCRYPTED_PWLEN];
  2341. //
  2342. // Decrypt doubly encrypted password with the encryption key
  2343. // provided creating an OWF encrypted password.
  2344. //
  2345. (VOID) RtlDecryptLmOwfPwdWithLmSesKey(
  2346. (PENCRYPTED_LM_OWF_PASSWORD) newPassword,
  2347. (PLM_SESSION_KEY) Header->EncryptionKey,
  2348. (PLM_OWF_PASSWORD) user21.usri21_password
  2349. );
  2350. //
  2351. // Generate the NULL Owf Password.
  2352. //
  2353. (VOID) RtlCalculateLmOwfPassword(
  2354. (PLM_PASSWORD) NULL_USERSETINFO_PASSWD,
  2355. (PLM_OWF_PASSWORD) NullOwfPassword
  2356. );
  2357. //
  2358. // Compare the Owf password the client sent and the Owf password
  2359. // for the NULL password. Do not change the password if this is
  2360. // the case.
  2361. //
  2362. if ( RtlCompareMemory(
  2363. user21.usri21_password,
  2364. NullOwfPassword,
  2365. ENCRYPTED_PWLEN
  2366. ) == ENCRYPTED_PWLEN ) {
  2367. status = NERR_Success;
  2368. goto cleanup;
  2369. }
  2370. }
  2371. status = NetUserSetInfo(
  2372. NULL,
  2373. nativeUserName,
  2374. 21,
  2375. (LPBYTE)&user21,
  2376. NULL
  2377. );
  2378. if ( !XsApiSuccess( status )) {
  2379. IF_DEBUG(ERRORS) {
  2380. NetpKdPrint(( "XsNetUserSetInfo2: NetUserSetInfo failed: "
  2381. "%X\n", status ));
  2382. }
  2383. goto cleanup;
  2384. }
  2385. }
  2386. //
  2387. // No return information for this API.
  2388. //
  2389. cleanup:
  2390. ;
  2391. } except( EXCEPTION_EXECUTE_HANDLER ) {
  2392. status = (WORD)RtlNtStatusToDosError( GetExceptionCode() );
  2393. }
  2394. //
  2395. // If there is a native 32-bit buffer, free it.
  2396. //
  2397. if (Susri2)
  2398. NetApiBufferFree( Susri2);
  2399. Header->Status = (WORD)status;
  2400. NetpMemoryFree( buffer );
  2401. NetpMemoryFree( nativeUserName );
  2402. return STATUS_SUCCESS;
  2403. } // XsNetUserSetInfo2
  2404. NTSTATUS
  2405. XsNetUserSetInfo (
  2406. API_HANDLER_PARAMETERS
  2407. )
  2408. /*++
  2409. Routine Description:
  2410. This routine handles a call to NetUserSetInfo. Since this is a subset
  2411. of the newer NetUserSetInfo2, we just convert into a call to that.
  2412. Arguments:
  2413. API_HANDLER_PARAMETERS - information about the API call. See
  2414. XsTypes.h for details.
  2415. Return Value:
  2416. NTSTATUS - STATUS_SUCCESS or reason for failure.
  2417. --*/
  2418. {
  2419. WORD dataEncryption;
  2420. WORD bufLen;
  2421. WORD level;
  2422. NTSTATUS ntStatus;
  2423. WORD parmNum;
  2424. PXS_NET_USER_SET_INFO subsetParameters = Parameters;
  2425. XS_NET_USER_SET_INFO_2 supersetParameters;
  2426. bufLen = SmbGetUshort( &subsetParameters->BufLen );
  2427. dataEncryption = SmbGetUshort( &subsetParameters->DataEncryption );
  2428. level = SmbGetUshort( &subsetParameters->Level );
  2429. parmNum = SmbGetUshort( &subsetParameters->ParmNum );
  2430. try {
  2431. IF_DEBUG(USER) {
  2432. NetpKdPrint((
  2433. "XsNetUserSetInfo: header at " FORMAT_LPVOID ", "
  2434. "params at " FORMAT_LPVOID ",\n level " FORMAT_DWORD ", "
  2435. "parmnum " FORMAT_DWORD ", buflen " FORMAT_LONG "\n",
  2436. Header, subsetParameters,
  2437. (DWORD) level, (DWORD) parmNum, (LONG) bufLen ));
  2438. }
  2439. //
  2440. // Create parms for XsNetUserSetInfo2()...
  2441. //
  2442. supersetParameters.Buffer = subsetParameters->Buffer;
  2443. supersetParameters.UserName = subsetParameters->UserName;
  2444. SmbPutUshort( &supersetParameters.Level, level );
  2445. SmbPutUshort( &supersetParameters.BufLen, bufLen );
  2446. SmbPutUshort( &supersetParameters.ParmNum, parmNum );
  2447. SmbPutUshort( &supersetParameters.DataEncryption, dataEncryption );
  2448. //
  2449. // Set info 2 will calc password length for us if we give it -1.
  2450. //
  2451. SmbPutUshort( &supersetParameters.PasswordLength, (WORD)(-1) );
  2452. //
  2453. // Invoke new version of API.
  2454. //
  2455. ntStatus = XsNetUserSetInfo2(
  2456. Header,
  2457. &supersetParameters,
  2458. StructureDesc,
  2459. AuxStructureDesc );
  2460. } except( EXCEPTION_EXECUTE_HANDLER ) {
  2461. ntStatus = GetExceptionCode();
  2462. }
  2463. return (ntStatus);
  2464. } // XsNetUserSetInfo