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.

2229 lines
67 KiB

  1. /*++
  2. Copyright (c) 1991-1993 Microsoft Corporation
  3. Module Name:
  4. rxuser.c
  5. Abstract:
  6. Routines in this module implement the down-level User and Modals UAS _access
  7. functionality
  8. Contains RxNetUser routines:
  9. RxNetUserAdd
  10. RxNetUserDel
  11. RxNetUserEnum
  12. RxNetUserGetGroups
  13. RxNetUserGetInfo
  14. RxNetUserModalsGet
  15. RxNetUserModalsSet
  16. RxNetUserPasswordSet
  17. RxNetUserSetGroups
  18. RxNetUserSetInfo
  19. RxNetUserValidate2
  20. (GetUserDescriptors)
  21. (GetModalsDescriptors)
  22. GetLanmanSessionKey
  23. Author:
  24. Richard Firth (rfirth) 20-May-1991
  25. Environment:
  26. Win-32/flat address space
  27. Requires ANSI C extensions: slash-slash comments, long external names,
  28. _strupr() function.
  29. Notes:
  30. Routines in this module assume that caller-supplied parameters have
  31. already been verified. No effort is made to further check the veracity
  32. of parms. Any actions causing exceptions must be trapped at a higher
  33. level. This applies to ALL parameters - strings, pointers, buffers, etc.
  34. Revision History:
  35. 20-May-1991 RFirth
  36. Created
  37. 25-Sep-1991 JohnRo
  38. PC-LINT found a bug computing buflen for info level 11.
  39. Fixed UNICODE handling of buflen increments.
  40. Fixed MIPS build.
  41. Changed buflen name to bufsize to reflect NT/LAN naming convention.
  42. Made other changes suggested by PC-LINT.
  43. 21-Nov-1991 JohnRo
  44. Removed NT dependencies to reduce recompiles.
  45. 05-Dec-1991 RFirth
  46. Enum returns in TotalEntries (or EntriesLeft) the number of items to
  47. be enumerated BEFORE this call. Used to be number left after this call
  48. 01-Apr-1992 JohnRo
  49. Use NetApiBufferAllocate() instead of private version.
  50. 06-Apr-1992 JohnRo
  51. RAID 8927: usrmgr.exe: _access violation, memory corruption.
  52. (Fixed RxNetUserSetGroups when it called NetpMoveMemory.)
  53. 02-Apr-1993 JohnRo
  54. RAID 5098: DOS app NetUserPasswordSet to downlevel gets NT return code.
  55. Made some changes suggested by PC-LINT 5.0
  56. --*/
  57. #include <nt.h> // Needed by NetUserPasswordSet
  58. #include <ntrtl.h> // Needed by NetUserPasswordSet
  59. #include <nturtl.h> // RtlConvertUiListToApiList
  60. #include <crypt.h> // Needed by NetUserPasswordSet
  61. #include "downlevl.h"
  62. #include <rxuser.h>
  63. #include <lmaccess.h>
  64. #include <stdlib.h> // wcslen().
  65. #include <ntddnfs.h> // LMR_REQUEST_PACKET
  66. #include <lmuse.h> // USE_IPC
  67. #include <netlibnt.h> // NetpRdrFsControlTree
  68. #include <loghours.h> // NetpRotateLogonHours
  69. #include <accessp.h> // NetpConvertWorkstationList
  70. //
  71. // down-level encryption now on by default!
  72. //
  73. #define DOWN_LEVEL_ENCRYPTION
  74. //
  75. // Maximum size of the Workstation list
  76. //
  77. #define MAX_WORKSTATION_LIST 256
  78. //
  79. // local routine prototypes
  80. //
  81. DBGSTATIC
  82. NET_API_STATUS
  83. GetUserDescriptors(
  84. IN DWORD Level,
  85. IN BOOL Encrypted,
  86. OUT LPDESC* ppDesc16,
  87. OUT LPDESC* ppDesc32,
  88. OUT LPDESC* ppDescSmb
  89. );
  90. DBGSTATIC
  91. VOID
  92. GetModalsDescriptors(
  93. IN DWORD Level,
  94. OUT LPDESC* ppDesc16,
  95. OUT LPDESC* ppDesc32,
  96. OUT LPDESC* ppDescSmb
  97. );
  98. NET_API_STATUS
  99. GetLanmanSessionKey(
  100. IN LPWSTR ServerName,
  101. OUT LPBYTE pSessionKey
  102. );
  103. //
  104. // Down-level remote API worker routines
  105. //
  106. NET_API_STATUS
  107. RxNetUserAdd(
  108. IN LPTSTR ServerName,
  109. IN DWORD Level,
  110. IN LPBYTE Buffer,
  111. OUT LPDWORD ParmError OPTIONAL
  112. )
  113. /*++
  114. Routine Description:
  115. Adds a user to a down-level UAS database.
  116. Assumes
  117. 1. This code assumes that a USER_INFO_1 is a subset of a USER_INFO_2
  118. and that the fields in a USER_INFO_1 map 1-to-1 to a USER_INFO_2
  119. 2. Level has already been range-checked
  120. Arguments:
  121. ServerName - at which down-level server to run the NetUserAdd API
  122. Level - of user info - 1 or 2
  123. Buffer - containing info
  124. ParmError - where to deposit id of failing info level
  125. Return Value:
  126. NET_API_STATUS
  127. Success - NERR_Success
  128. Failure - (return code from down-level API)
  129. --*/
  130. {
  131. LPDESC pDesc16;
  132. LPDESC pDesc32;
  133. LPDESC pDescSmb;
  134. DWORD buflen;
  135. DWORD badparm;
  136. DWORD len;
  137. DWORD pwdlen;
  138. CHAR ansiPassword[LM20_PWLEN+1];
  139. DWORD lmOwfPasswordLen;
  140. LPTSTR cleartext;
  141. NET_API_STATUS NetStatus = NERR_Success;
  142. #ifdef DOWN_LEVEL_ENCRYPTION
  143. LM_OWF_PASSWORD lmOwfPassword;
  144. LM_SESSION_KEY lanmanKey;
  145. ENCRYPTED_LM_OWF_PASSWORD encryptedLmOwfPassword;
  146. NTSTATUS Status;
  147. #endif
  148. BYTE logonHours[21];
  149. PBYTE callersLogonHours = NULL;
  150. WCHAR Workstations[MAX_WORKSTATION_LIST+1];
  151. LPWSTR callersWorkstations = NULL;
  152. if (Level < 1 || Level > 2) {
  153. return ERROR_INVALID_LEVEL;
  154. }
  155. if (ParmError == NULL) {
  156. ParmError = &badparm;
  157. }
  158. *ParmError = PARM_ERROR_NONE;
  159. //
  160. // calculate the size of the data to be transferred on the wire. See
  161. // assumption in rubric. We also allow ourselves the luxury of trapping
  162. // any strings which may break the down-level limits so we can return a
  163. // nice parameter error number. If a string breaks a down-level limit, we
  164. // just get back an ERROR_INVALID_PARAMETER, which is not very helpful
  165. //
  166. buflen = (Level == 1) ? sizeof(USER_INFO_1) : sizeof(USER_INFO_2);
  167. len = POSSIBLE_WCSLEN(((PUSER_INFO_1)Buffer)->usri1_name);
  168. if (len > LM20_UNLEN) {
  169. *ParmError = USER_NAME_PARMNUM;
  170. return ERROR_INVALID_PARAMETER;
  171. }
  172. buflen += len + 1;
  173. if (len = POSSIBLE_WCSLEN(((PUSER_INFO_1)Buffer)->usri1_password)) {
  174. if (len > LM20_PWLEN) {
  175. *ParmError = USER_PASSWORD_PARMNUM;
  176. return ERROR_INVALID_PARAMETER;
  177. }
  178. buflen += len + 1;
  179. }
  180. pwdlen = len;
  181. if (len = POSSIBLE_WCSLEN(((PUSER_INFO_1)Buffer)->usri1_home_dir)) {
  182. if (len > LM20_PATHLEN) {
  183. *ParmError = USER_HOME_DIR_PARMNUM;
  184. return ERROR_INVALID_PARAMETER;
  185. }
  186. buflen += len + 1;
  187. }
  188. if (len = POSSIBLE_WCSLEN(((PUSER_INFO_1)Buffer)->usri1_comment)) {
  189. if (len > LM20_MAXCOMMENTSZ) {
  190. *ParmError = USER_COMMENT_PARMNUM;
  191. return ERROR_INVALID_PARAMETER;
  192. }
  193. buflen += len + 1;
  194. }
  195. if (len = POSSIBLE_WCSLEN(((PUSER_INFO_1)Buffer)->usri1_script_path)) {
  196. if (len > LM20_PATHLEN) {
  197. *ParmError = USER_SCRIPT_PATH_PARMNUM;
  198. return ERROR_INVALID_PARAMETER;
  199. }
  200. buflen += len + 1;
  201. }
  202. if (Level == 2) {
  203. if (len = POSSIBLE_WCSLEN(((PUSER_INFO_2)Buffer)->usri2_full_name)) {
  204. if (len > LM20_MAXCOMMENTSZ) {
  205. *ParmError = USER_FULL_NAME_PARMNUM;
  206. return ERROR_INVALID_PARAMETER;
  207. }
  208. buflen += len + 1;
  209. }
  210. if (len = POSSIBLE_WCSLEN(((PUSER_INFO_2)Buffer)->usri2_usr_comment)) {
  211. if (len > LM20_MAXCOMMENTSZ) {
  212. *ParmError = USER_USR_COMMENT_PARMNUM;
  213. return ERROR_INVALID_PARAMETER;
  214. }
  215. buflen += len + 1;
  216. }
  217. if (len = POSSIBLE_WCSLEN(((PUSER_INFO_2)Buffer)->usri2_parms)) {
  218. if (len > LM20_MAXCOMMENTSZ) {
  219. *ParmError = USER_PARMS_PARMNUM;
  220. return ERROR_INVALID_PARAMETER;
  221. }
  222. buflen += len + 1;
  223. }
  224. if (len = POSSIBLE_WCSLEN(((PUSER_INFO_2)Buffer)->usri2_workstations)) {
  225. if (len > MAX_WORKSTATION_LIST) {
  226. *ParmError = USER_WORKSTATIONS_PARMNUM;
  227. return ERROR_INVALID_PARAMETER;
  228. }
  229. buflen += len + 1;
  230. }
  231. }
  232. if (pwdlen) {
  233. //
  234. // copy the cleartext password out of the buffer - we will replace it with
  235. // the encrypted version, but need to put the cleartext back before
  236. // returning control to the caller
  237. //
  238. cleartext = ((PUSER_INFO_1)Buffer)->usri1_password;
  239. //
  240. // Calculate the one-way function of the password
  241. //
  242. RtlUnicodeToMultiByteN(ansiPassword,
  243. sizeof(ansiPassword),
  244. &lmOwfPasswordLen,
  245. ((PUSER_INFO_1)Buffer)->usri1_password,
  246. pwdlen * sizeof(WCHAR)
  247. );
  248. ansiPassword[lmOwfPasswordLen] = 0;
  249. (VOID) _strupr(ansiPassword);
  250. #ifdef DOWN_LEVEL_ENCRYPTION
  251. NetStatus = NERR_Success;
  252. Status = RtlCalculateLmOwfPassword(ansiPassword, &lmOwfPassword);
  253. if (NT_SUCCESS(Status)) {
  254. NetStatus = GetLanmanSessionKey((LPWSTR)ServerName, (LPBYTE)&lanmanKey);
  255. if (NetStatus == NERR_Success) {
  256. Status = RtlEncryptLmOwfPwdWithLmSesKey(&lmOwfPassword,
  257. &lanmanKey,
  258. &encryptedLmOwfPassword
  259. );
  260. if (NT_SUCCESS(Status)) {
  261. ((PUSER_INFO_1)Buffer)->usri1_password = (LPTSTR)&encryptedLmOwfPassword;
  262. }
  263. }
  264. }
  265. if (NetStatus != NERR_Success)
  266. return NetStatus;
  267. else if (!NT_SUCCESS(Status)) {
  268. return RtlNtStatusToDosError(Status);
  269. }
  270. #else
  271. ((PUSER_INFO_1)Buffer)->usri1_password = (LPTSTR)ansiPassword;
  272. #endif
  273. } else {
  274. lmOwfPasswordLen = 0;
  275. }
  276. //
  277. // we have checked all the parms we can. If any other parameter breaks at
  278. // the down-level server then we just have to be content with an unknown
  279. // parameter error
  280. //
  281. *ParmError = PARM_ERROR_UNKNOWN;
  282. #ifdef DOWN_LEVEL_ENCRYPTION
  283. NetStatus = GetUserDescriptors(Level, TRUE, &pDesc16, &pDesc32, &pDescSmb);
  284. #else
  285. NetStatus = GetUserDescriptors(Level, FALSE, &pDesc16, &pDesc32, &pDescSmb);
  286. #endif
  287. if (NetStatus != NERR_Success)
  288. {
  289. //
  290. // Copy the original password back to the user's buffer
  291. //
  292. if (pwdlen)
  293. {
  294. ((PUSER_INFO_1) Buffer)->usri1_password = cleartext;
  295. }
  296. return NetStatus;
  297. }
  298. //
  299. // if this level supports logon hours, then convert the caller supplied
  300. // logon hours from GMT to local time
  301. //
  302. if (Level == 2 && ((PUSER_INFO_2)Buffer)->usri2_logon_hours) {
  303. callersLogonHours = ((PUSER_INFO_2)Buffer)->usri2_logon_hours;
  304. RtlCopyMemory(logonHours,
  305. ((PUSER_INFO_2)Buffer)->usri2_logon_hours,
  306. sizeof(logonHours)
  307. );
  308. //
  309. // shuffle the bitmap and point the logon_hours field in the structure
  310. // at the shuffled version
  311. //
  312. NetpRotateLogonHours(logonHours, UNITS_PER_WEEK, FALSE);
  313. ((PUSER_INFO_2)Buffer)->usri2_logon_hours = logonHours;
  314. }
  315. //
  316. // Convert the list of workstations from being comma separated
  317. // to being space separated. Ditch workstation names containing
  318. // spaces.
  319. if (Level == 2 && ((PUSER_INFO_2)Buffer)->usri2_workstations) {
  320. UNICODE_STRING WorkstationString;
  321. callersWorkstations = ((PUSER_INFO_2)Buffer)->usri2_workstations;
  322. wcsncpy( Workstations, callersWorkstations, MAX_WORKSTATION_LIST );
  323. RtlInitUnicodeString( &WorkstationString, Workstations );
  324. NetpConvertWorkstationList( &WorkstationString );
  325. ((PUSER_INFO_2)Buffer)->usri2_workstations = Workstations;
  326. }
  327. NetStatus = NERR_Success;
  328. NetStatus = RxRemoteApi(API_WUserAdd2, // which API it is
  329. ServerName, // which server its at
  330. REMSmb_NetUserAdd2_P, // parameter descriptor
  331. pDesc16, pDesc32, pDescSmb, // data descriptors
  332. NULL, NULL, NULL, // no aux descriptors reqd.
  333. FALSE, // need to be logged on
  334. Level, // caller parms
  335. Buffer,
  336. buflen, // and one we created
  337. #ifdef DOWN_LEVEL_ENCRYPTION
  338. 1, // encryption on
  339. lmOwfPasswordLen // length of cleartext
  340. #else
  341. 0,
  342. pwdlen
  343. #endif
  344. );
  345. //
  346. // copy the original password back to the user's buffer
  347. //
  348. if (pwdlen) {
  349. ((PUSER_INFO_1)Buffer)->usri1_password = cleartext;
  350. }
  351. //
  352. // and the original logon hours
  353. //
  354. if (callersLogonHours) {
  355. ((PUSER_INFO_2)Buffer)->usri2_logon_hours = callersLogonHours;
  356. }
  357. //
  358. // and the original workstation list
  359. //
  360. if ( callersWorkstations ) {
  361. ((PUSER_INFO_2)Buffer)->usri2_workstations = callersWorkstations;
  362. }
  363. return NetStatus;
  364. }
  365. NET_API_STATUS
  366. RxNetUserDel(
  367. IN LPTSTR ServerName,
  368. IN LPTSTR UserName
  369. )
  370. /*++
  371. Routine Description:
  372. Removes a user from a down-level server's UAS (User Account Subsystem)
  373. database
  374. Assumes
  375. 1. UserName has been checked for valid pointer to valid string
  376. Arguments:
  377. ServerName - on which (down-level) server to run the API
  378. UserName - which user to delete
  379. Return Value:
  380. NET_API_STATUS
  381. Success - NERR_Success
  382. Failure - ERROR_INVALID_PARAMETER
  383. UserName > LM20_UNLEN
  384. (return code from remoted NetUserDel)
  385. --*/
  386. {
  387. if (STRLEN(UserName) > LM20_UNLEN) {
  388. return ERROR_INVALID_PARAMETER;
  389. }
  390. return RxRemoteApi(API_WUserDel, // api being remoted
  391. ServerName, // where to remote it
  392. REMSmb_NetUserDel_P, // parameter descriptor
  393. NULL, NULL, NULL, // data descriptors
  394. NULL, NULL, NULL, // aux data descriptors
  395. FALSE, // this call needs user logged on
  396. UserName // remote API parms...
  397. );
  398. }
  399. NET_API_STATUS
  400. RxNetUserEnum(
  401. IN LPTSTR ServerName,
  402. IN DWORD Level,
  403. OUT LPBYTE* Buffer,
  404. IN DWORD PrefMaxLen,
  405. OUT LPDWORD EntriesRead,
  406. OUT LPDWORD EntriesLeft,
  407. IN OUT LPDWORD ResumeHandle OPTIONAL
  408. )
  409. /*++
  410. Routine Description:
  411. Returns user information from a down-level server's UAS database
  412. Arguments:
  413. ServerName - where to run the API
  414. Level - of info required - 0, 1, 2, or 10
  415. Buffer - place to return a pointer to an allocated buffer
  416. PrefMaxLen - caller's preferred maximum buffer size
  417. EntriesRead - number of <Level> info entries being returned in the buffer
  418. EntriesLeft - number of entries left after this one
  419. ResumeHandle- used to resume enumeration (Ignored)
  420. Return Value:
  421. NET_API_STATUS
  422. Success - NERR_Success
  423. Failure - ERROR_INVALID_PARAMETER
  424. non-NULL ResumeHandle
  425. ERROR_NOT_ENOUGH_MEMORY
  426. NetApiBufferAllocate failed (?!)
  427. (return code from down-level API)
  428. --*/
  429. {
  430. LPDESC pDesc16;
  431. LPDESC pDesc32;
  432. LPDESC pDescSmb;
  433. NET_API_STATUS rc;
  434. LPBYTE bufptr;
  435. DWORD entries_read, total_avail;
  436. DWORD last_resume_handle, new_resume_handle = 0;
  437. *EntriesRead = *EntriesLeft = 0;
  438. *Buffer = NULL;
  439. rc = GetUserDescriptors(Level, FALSE, &pDesc16, &pDesc32, &pDescSmb);
  440. if (rc != NO_ERROR) {
  441. return(rc);
  442. }
  443. bufptr = NULL;
  444. //
  445. // try NetUserEnum2 (supports resume handle) with the requested amount
  446. // of data. If the down-level server doesn't support this API then try
  447. // NetUserEnum
  448. //
  449. if (ARGUMENT_PRESENT(ResumeHandle)) {
  450. last_resume_handle = *ResumeHandle;
  451. } else {
  452. last_resume_handle = 0;
  453. }
  454. //
  455. // irrespective of whether we can resume the enumeration, down-level
  456. // servers can't generate >64K-1 bytes of data
  457. //
  458. if (PrefMaxLen > 65535) {
  459. PrefMaxLen = 65535;
  460. }
  461. rc = RxRemoteApi(API_WUserEnum2,
  462. ServerName,
  463. REMSmb_NetUserEnum2_P,
  464. pDesc16, pDesc32, pDescSmb,
  465. NULL, NULL, NULL,
  466. ALLOCATE_RESPONSE, // RxRemoteApi allocates buffer
  467. Level,
  468. &bufptr,
  469. PrefMaxLen, // size of caller's buffer
  470. last_resume_handle, // last key returned
  471. &new_resume_handle, // returns this key
  472. &entries_read, // number returned
  473. &total_avail // total available at server
  474. );
  475. //
  476. // WinBall returns ERROR_NOT_SUPPORTED. LM < 2.1 returns NERR_InvalidAPI?
  477. // WinBall returns ERROR_NOT_SUPPORTED because it is share level, so this
  478. // whole API fails. Therefore, no need to account (no pun intended) for
  479. // WinBall
  480. //
  481. //
  482. // RLF 10/01/92. Seemingly, IBM LAN Server returns Internal Error (2140).
  483. // We'll handle that one too....
  484. //
  485. if (rc == NERR_InvalidAPI || rc == NERR_InternalError) {
  486. //
  487. // the down-level server doesn't support NetUserEnum2. Fall-back to
  488. // NetUserEnum & try to get as much data as available
  489. //
  490. rc = RxRemoteApi(API_WUserEnum,
  491. ServerName,
  492. REMSmb_NetUserEnum_P,
  493. pDesc16, pDesc32, pDescSmb,
  494. NULL, NULL, NULL,
  495. ALLOCATE_RESPONSE, // RxRemoteApi allocates buffer
  496. Level,
  497. &bufptr,
  498. 65535, // get as much data as possible
  499. &entries_read,
  500. &total_avail
  501. );
  502. } else if (rc == NERR_Success || rc == ERROR_MORE_DATA) {
  503. //
  504. // return the resume handle if NetUserEnum2 succeeded & the caller
  505. // supplied a ResumeHandle parameter
  506. //
  507. if (ARGUMENT_PRESENT(ResumeHandle)) {
  508. *ResumeHandle = new_resume_handle;
  509. }
  510. }
  511. if (rc && rc != ERROR_MORE_DATA) {
  512. if (bufptr != NULL) {
  513. (void) NetApiBufferFree(bufptr);
  514. }
  515. } else {
  516. //
  517. // if level supports logon hours, convert from local time to GMT. Level
  518. // 2 is the only level of user info handled by this routine that knows
  519. // about logon hours
  520. //
  521. // if level support workstation list, convert from blank separated to
  522. // comma separated list. Level 2 is the only level of user info
  523. // handled by this routine that know about the workstation list.
  524. //
  525. if (Level == 2) {
  526. DWORD numRead;
  527. LPUSER_INFO_2 ptr = (LPUSER_INFO_2)bufptr;
  528. for (numRead = entries_read; numRead; --numRead) {
  529. NetpRotateLogonHours(ptr->usri2_logon_hours, UNITS_PER_WEEK, TRUE);
  530. if ( ptr->usri2_workstations != NULL ) {
  531. UNICODE_STRING BlankSeparated;
  532. UNICODE_STRING CommaSeparated;
  533. NTSTATUS Status;
  534. RtlInitUnicodeString( &BlankSeparated, ptr->usri2_workstations );
  535. Status = RtlConvertUiListToApiList(
  536. &BlankSeparated,
  537. &CommaSeparated,
  538. TRUE ); // Allow Blanks as delimiters
  539. if ( !NT_SUCCESS(Status)) {
  540. return RtlNtStatusToDosError(Status);
  541. }
  542. if ( CommaSeparated.Length > 0 ) {
  543. NetpAssert ( wcslen( ptr->usri2_workstations ) <=
  544. wcslen( CommaSeparated.Buffer ) );
  545. if ( wcslen( ptr->usri2_workstations ) <=
  546. wcslen( CommaSeparated.Buffer ) ) {
  547. wcscpy( ptr->usri2_workstations,
  548. CommaSeparated.Buffer );
  549. }
  550. }
  551. }
  552. ++ptr;
  553. }
  554. }
  555. *Buffer = bufptr;
  556. *EntriesRead = entries_read;
  557. *EntriesLeft = total_avail;
  558. }
  559. return rc;
  560. }
  561. NET_API_STATUS
  562. RxNetUserGetGroups(
  563. IN LPTSTR ServerName,
  564. IN LPTSTR UserName,
  565. IN DWORD Level,
  566. OUT LPBYTE* Buffer,
  567. IN DWORD PrefMaxLen,
  568. OUT LPDWORD EntriesRead,
  569. OUT LPDWORD EntriesLeft
  570. )
  571. /*++
  572. Routine Description:
  573. Get the list of groups in a UAS database to which a particular user belongs
  574. Arguments:
  575. ServerName - where to run the API
  576. UserName - which user to get info for
  577. Level - of info requested - Must Be Zero
  578. Buffer - where to deposit the buffer we allocate containing the info
  579. PrefMaxLen - caller's preferred maximum buffer size
  580. EntriesRead - number of entries being returned in Buffer
  581. EntriesLeft - number of entries left to get
  582. Return Value:
  583. NET_API_STATUS
  584. Success - NERR_Success
  585. Failure - ERROR_INVALID_LEVEL
  586. ERROR_INVALID_PARAMETER
  587. --*/
  588. {
  589. NET_API_STATUS rc;
  590. DWORD entries_read, total_avail;
  591. LPBYTE bufptr;
  592. UNREFERENCED_PARAMETER(Level);
  593. UNREFERENCED_PARAMETER(PrefMaxLen);
  594. *EntriesRead = *EntriesLeft = 0;
  595. *Buffer = NULL;
  596. if (STRLEN(UserName) > LM20_UNLEN) {
  597. return ERROR_INVALID_PARAMETER;
  598. }
  599. bufptr = NULL;
  600. rc = RxRemoteApi(API_WUserGetGroups,
  601. ServerName,
  602. REMSmb_NetUserGetGroups_P,
  603. REM16_user_info_0,
  604. REM32_user_info_0,
  605. REMSmb_user_info_0,
  606. NULL, NULL, NULL,
  607. ALLOCATE_RESPONSE,
  608. UserName, // API parameters
  609. 0, // fixed level
  610. &bufptr,
  611. 65535,
  612. &entries_read,
  613. &total_avail // supplied by us
  614. );
  615. if (rc) {
  616. if (bufptr != NULL) {
  617. (void) NetApiBufferFree(bufptr);
  618. }
  619. } else {
  620. *Buffer = bufptr;
  621. *EntriesRead = entries_read;
  622. *EntriesLeft = total_avail;
  623. }
  624. return rc;
  625. }
  626. NET_API_STATUS
  627. RxNetUserGetInfo(
  628. IN LPTSTR ServerName,
  629. IN LPTSTR UserName,
  630. IN DWORD Level,
  631. OUT LPBYTE* Buffer
  632. )
  633. /*++
  634. Routine Description:
  635. Get information about a particular user from a down-level server
  636. Assumes:
  637. 1. UserName is a valid pointer to a valid string
  638. Arguments:
  639. ServerName - where to run the API
  640. UserName - which user to get info on
  641. Level - what level of info required - 0, 1, 2, 10, 11
  642. Buffer - where to return buffer containing info
  643. Return Value:
  644. NET_API_STATUS
  645. Success - NERR_Success
  646. Failure - ERROR_INVALID_LEVEL
  647. ERROR_INVALID_PARAMETER
  648. --*/
  649. {
  650. LPDESC pDesc16;
  651. LPDESC pDesc32;
  652. LPDESC pDescSmb;
  653. DWORD buflen;
  654. LPBYTE bufptr;
  655. DWORD total_avail;
  656. NET_API_STATUS rc;
  657. *Buffer = NULL;
  658. if (STRLEN(UserName) > LM20_UNLEN) {
  659. return ERROR_INVALID_PARAMETER;
  660. }
  661. //
  662. // work out the anount of buffer space we need to return the down-level
  663. // structure as its 32-bit equivalent
  664. //
  665. switch (Level) {
  666. case 0:
  667. buflen = sizeof(USER_INFO_0) + STRING_SPACE_REQD(UNLEN + 1);
  668. break;
  669. case 1:
  670. buflen = sizeof(USER_INFO_1)
  671. + STRING_SPACE_REQD(UNLEN + 1) // usri1_name
  672. + STRING_SPACE_REQD(ENCRYPTED_PWLEN) // usri1_password
  673. + STRING_SPACE_REQD(LM20_PATHLEN + 1) // usri1_home_dir
  674. + STRING_SPACE_REQD(LM20_MAXCOMMENTSZ + 1) // usri1_comment
  675. + STRING_SPACE_REQD(LM20_PATHLEN + 1); // usri1_script_path
  676. break;
  677. case 2:
  678. buflen = sizeof(USER_INFO_2)
  679. + STRING_SPACE_REQD(UNLEN + 1) // usri2_name
  680. + STRING_SPACE_REQD(ENCRYPTED_PWLEN) // usri2_password
  681. + STRING_SPACE_REQD(LM20_PATHLEN + 1) // usri2_home_dir
  682. + STRING_SPACE_REQD(LM20_MAXCOMMENTSZ + 1) // usri2_comment
  683. + STRING_SPACE_REQD(LM20_PATHLEN + 1) // usri2_script_path
  684. + STRING_SPACE_REQD(LM20_MAXCOMMENTSZ + 1) // usri2_full_name
  685. + STRING_SPACE_REQD(LM20_MAXCOMMENTSZ + 1) // usri2_usr_comment
  686. + STRING_SPACE_REQD(LM20_MAXCOMMENTSZ + 1) // usri2_parms
  687. + STRING_SPACE_REQD(MAX_WORKSTATION_LIST) // usri2_workstations
  688. + STRING_SPACE_REQD(MAX_PATH + 1) // usri2_logon_server
  689. + 21; // usri2_logon_hours
  690. break;
  691. case 10:
  692. buflen = sizeof(USER_INFO_10)
  693. + STRING_SPACE_REQD(UNLEN + 1) // usri10_name
  694. + STRING_SPACE_REQD(LM20_MAXCOMMENTSZ + 1) // usri10_comment
  695. + STRING_SPACE_REQD(LM20_MAXCOMMENTSZ + 1) // usri10_usr_comment
  696. + STRING_SPACE_REQD(LM20_MAXCOMMENTSZ + 1); // usri10_full_name
  697. break;
  698. case 11:
  699. buflen = sizeof(USER_INFO_11)
  700. + STRING_SPACE_REQD(UNLEN + 1) // usri11_name
  701. + STRING_SPACE_REQD(LM20_MAXCOMMENTSZ + 1) // usri11_comment
  702. + STRING_SPACE_REQD(LM20_MAXCOMMENTSZ + 1) // usri11_usr_comment
  703. + STRING_SPACE_REQD(LM20_MAXCOMMENTSZ + 1) // usri11_full_name
  704. + STRING_SPACE_REQD(LM20_PATHLEN + 1) // usri11_home_dir
  705. + STRING_SPACE_REQD(LM20_MAXCOMMENTSZ + 1) // usri11_parms
  706. + STRING_SPACE_REQD(MAX_PATH + 1) // usri11_logon_server
  707. + STRING_SPACE_REQD(MAX_WORKSTATION_LIST) // usri11_workstations
  708. + 21; // usri11_logon_hours
  709. break;
  710. default:
  711. return(ERROR_INVALID_LEVEL);
  712. }
  713. buflen = DWORD_ROUNDUP(buflen);
  714. if (rc = NetApiBufferAllocate(buflen, (LPVOID *) &bufptr)) {
  715. return rc;
  716. }
  717. (void)GetUserDescriptors(Level, FALSE, &pDesc16, &pDesc32, &pDescSmb);
  718. rc = RxRemoteApi(API_WUserGetInfo,
  719. ServerName,
  720. REMSmb_NetUserGetInfo_P,
  721. pDesc16, pDesc32, pDescSmb,
  722. NULL, NULL, NULL,
  723. FALSE,
  724. UserName,
  725. Level,
  726. bufptr,
  727. buflen,
  728. &total_avail
  729. );
  730. if (rc) {
  731. (void) NetApiBufferFree(bufptr);
  732. } else {
  733. //
  734. // Convert the logon hours bitmap to UTC/GMT
  735. // Convert the workstation list from blank separated to comma separated
  736. //
  737. if (Level == 2 || Level == 11) {
  738. PBYTE logonHours;
  739. LPWSTR Workstations;
  740. if (Level == 2) {
  741. logonHours = ((PUSER_INFO_2)bufptr)->usri2_logon_hours;
  742. Workstations = ((PUSER_INFO_2)bufptr)->usri2_workstations;
  743. } else {
  744. logonHours = ((PUSER_INFO_11)bufptr)->usri11_logon_hours;
  745. Workstations = ((PUSER_INFO_11)bufptr)->usri11_workstations;
  746. }
  747. NetpRotateLogonHours(logonHours, UNITS_PER_WEEK, TRUE);
  748. if ( Workstations != NULL ) {
  749. UNICODE_STRING BlankSeparated;
  750. UNICODE_STRING CommaSeparated;
  751. NTSTATUS Status;
  752. RtlInitUnicodeString( &BlankSeparated, Workstations );
  753. Status = RtlConvertUiListToApiList(
  754. &BlankSeparated,
  755. &CommaSeparated,
  756. TRUE ); // Allow Blanks as delimiters
  757. if ( !NT_SUCCESS(Status)) {
  758. return RtlNtStatusToDosError(Status);
  759. }
  760. if ( CommaSeparated.Length > 0 ) {
  761. NetpAssert ( wcslen( Workstations ) <=
  762. wcslen( CommaSeparated.Buffer ) );
  763. if ( wcslen(Workstations) <= wcslen(CommaSeparated.Buffer)){
  764. wcscpy( Workstations, CommaSeparated.Buffer );
  765. }
  766. }
  767. }
  768. }
  769. *Buffer = bufptr;
  770. }
  771. return rc;
  772. }
  773. NET_API_STATUS
  774. RxNetUserModalsGet(
  775. IN LPTSTR ServerName,
  776. IN DWORD Level,
  777. OUT LPBYTE* Buffer
  778. )
  779. /*++
  780. Routine Description:
  781. Returns global information about all users and groups in a down-level UAS
  782. database
  783. Assumes
  784. 1. Level has been validated
  785. Arguments:
  786. ServerName - where to run the API
  787. Level - of info required - 0 or 1
  788. Buffer - where to deposit the returned info
  789. Return Value:
  790. NET_API_STATUS
  791. Success - NERR_Success
  792. Failure - ERROR_INVALID_LEVEL
  793. ERROR_INVALID_PARAMETER
  794. --*/
  795. {
  796. LPDESC pDesc16;
  797. LPDESC pDesc32;
  798. LPDESC pDescSmb;
  799. DWORD buflen;
  800. LPBYTE bufptr;
  801. NET_API_STATUS rc;
  802. DWORD total_avail;
  803. if (Level > 1) {
  804. return ERROR_INVALID_LEVEL;
  805. }
  806. *Buffer = NULL;
  807. buflen = Level ? sizeof(USER_MODALS_INFO_1) : sizeof(USER_MODALS_INFO_0);
  808. buflen += Level ? STRING_SPACE_REQD(MAX_PATH + 1) : 0;
  809. buflen = DWORD_ROUNDUP(buflen);
  810. if (rc = NetApiBufferAllocate(buflen, (LPVOID *) &bufptr)) {
  811. return rc;
  812. }
  813. GetModalsDescriptors(Level, &pDesc16, &pDesc32, &pDescSmb);
  814. rc = RxRemoteApi(API_WUserModalsGet,
  815. ServerName,
  816. REMSmb_NetUserModalsGet_P,
  817. pDesc16, pDesc32, pDescSmb,
  818. NULL, NULL, NULL,
  819. FALSE,
  820. Level,
  821. bufptr,
  822. buflen,
  823. &total_avail
  824. );
  825. if (rc) {
  826. (void) NetApiBufferFree(bufptr);
  827. } else {
  828. *Buffer = bufptr;
  829. }
  830. return rc;
  831. }
  832. NET_API_STATUS
  833. RxNetUserModalsSet(
  834. IN LPTSTR ServerName,
  835. IN DWORD Level,
  836. IN LPBYTE Buffer,
  837. OUT LPDWORD ParmError OPTIONAL
  838. )
  839. /*++
  840. Routine Description:
  841. Sets global information for all users and groups in a down-level UAS
  842. database
  843. Assumes
  844. 1. Level parameter already verified
  845. Arguments:
  846. ServerName - where to run the API
  847. Level - level of information being supplied - 0, 1, 1001-1007
  848. Buffer - pointer to buffer containing input information
  849. ParmError - pointer to place to store index of failing info
  850. Return Value:
  851. NET_API_STATUS
  852. Success - NERR_Success
  853. Failure - ERROR_INVALID_PARAMETER
  854. One of the fields in the input structure was invalid
  855. --*/
  856. {
  857. DWORD parmnum;
  858. DWORD badparm;
  859. DWORD buflen;
  860. LPDESC pDesc16;
  861. LPDESC pDesc32;
  862. LPDESC pDescSmb;
  863. //
  864. // check for bad addresses and set ParmError to a known default
  865. //
  866. if (ParmError == NULL) {
  867. ParmError = &badparm;
  868. }
  869. *ParmError = PARM_ERROR_NONE;
  870. if (Level) {
  871. if (Level == 1) {
  872. parmnum = PARMNUM_ALL;
  873. buflen = sizeof(USER_MODALS_INFO_1)
  874. + POSSIBLE_STRLEN(((PUSER_MODALS_INFO_1)Buffer)->usrmod1_primary);
  875. } else {
  876. //
  877. // Convert info levels 1006, 1007 to corresponding parmnums (1, 2)
  878. // at old info level 1
  879. //
  880. if (Level >= MODALS_ROLE_INFOLEVEL) {
  881. parmnum = Level - (MODALS_ROLE_INFOLEVEL - 1);
  882. Level = 1;
  883. switch (parmnum) {
  884. case 1: // MODALS_ROLE_PARMNUM
  885. buflen = sizeof(DWORD);
  886. break;
  887. case 2: // MODALS_PRIMARY_PARMNUM
  888. buflen = STRLEN( (LPTSTR) Buffer);
  889. if (buflen > MAX_PATH) {
  890. *ParmError = MODALS_PRIMARY_INFOLEVEL;
  891. return ERROR_INVALID_PARAMETER;
  892. }
  893. break;
  894. default:
  895. #if DBG
  896. NetpKdPrint(("error: RxNetUserModalsSet.%d: bad parmnum %d\n",
  897. __LINE__,
  898. parmnum
  899. ));
  900. #endif
  901. return ERROR_INVALID_LEVEL;
  902. }
  903. } else if (Level >= MODALS_MIN_PASSWD_LEN_INFOLEVEL) {
  904. //
  905. // Convert info levels 1001-1005 to equivalent parmnums at
  906. // level 0
  907. //
  908. parmnum = Level - PARMNUM_BASE_INFOLEVEL;
  909. Level = 0;
  910. buflen = sizeof(DWORD);
  911. } else {
  912. #if DBG
  913. NetpKdPrint(("error: RxNetUserModalsSet.%d: bad level %d\n",
  914. __LINE__,
  915. Level
  916. ));
  917. #endif
  918. return ERROR_INVALID_LEVEL;
  919. }
  920. }
  921. } else {
  922. parmnum = PARMNUM_ALL;
  923. buflen = sizeof(USER_MODALS_INFO_0);
  924. }
  925. *ParmError = PARM_ERROR_UNKNOWN;
  926. GetModalsDescriptors(Level, &pDesc16, &pDesc32, &pDescSmb);
  927. return RxRemoteApi(API_WUserModalsSet,
  928. ServerName,
  929. REMSmb_NetUserModalsSet_P,
  930. pDesc16, pDesc32, pDescSmb,
  931. NULL, NULL, NULL,
  932. FALSE,
  933. Level, // API parms
  934. Buffer,
  935. buflen, // supplied by us
  936. MAKE_PARMNUM_PAIR(parmnum, parmnum) // ditto
  937. );
  938. }
  939. NET_API_STATUS
  940. RxNetUserPasswordSet(
  941. IN LPTSTR ServerName,
  942. IN LPTSTR UserName,
  943. IN LPTSTR OldPassword,
  944. IN LPTSTR NewPassword
  945. )
  946. /*++
  947. Routine Description:
  948. Changes the password associated with a user account in a down-level UAS
  949. database
  950. Assumes
  951. 1. The pointer parameters have already been verified
  952. Arguments:
  953. ServerName - where to change the password
  954. UserName - which user account to change it for
  955. OldPassword - the current password
  956. NewPassword - the new password
  957. Return Value:
  958. NET_API_STATUS
  959. Success - NERR_Success
  960. Failure - ERROR_INVALID_PARAMETER
  961. UserName, OldPassword or NewPassword would break down-level
  962. limits
  963. --*/
  964. {
  965. NTSTATUS Status;
  966. NET_API_STATUS NetStatus;
  967. BOOL TryNullSession = TRUE; // Try null session first.
  968. ULONG BytesWritten;
  969. #ifdef DOWN_LEVEL_ENCRYPTION
  970. CHAR OldAnsiPassword[LM20_PWLEN+1];
  971. CHAR NewAnsiPassword[LM20_PWLEN+1];
  972. LM_OWF_PASSWORD OldOwfPassword;
  973. LM_OWF_PASSWORD NewOwfPassword;
  974. ENCRYPTED_LM_OWF_PASSWORD OldEncryptedWithNew;
  975. ENCRYPTED_LM_OWF_PASSWORD NewEncryptedWithOld;
  976. #else
  977. CHAR OldAnsiPassword[ENCRYPTED_PWLEN];
  978. CHAR NewAnsiPassword[ENCRYPTED_PWLEN];
  979. #endif
  980. //
  981. // Reel in some easy errors before they get far.
  982. //
  983. if ((STRLEN(UserName) > LM20_UNLEN)
  984. || (STRLEN(OldPassword) > LM20_PWLEN)
  985. || (STRLEN(NewPassword) > LM20_PWLEN)) {
  986. return ERROR_INVALID_PARAMETER;
  987. }
  988. //
  989. // The passwords are sent in 16-byte ANSI buffers,
  990. // so convert them from Unicode to multibyte.
  991. //
  992. #ifndef DOWN_LEVEL_ENCRYPTION
  993. //
  994. // this required because we always send fixed size char buffers, not strings
  995. //
  996. RtlSecureZeroMemory(OldAnsiPassword, sizeof(OldAnsiPassword));
  997. RtlSecureZeroMemory(NewAnsiPassword, sizeof(NewAnsiPassword));
  998. #endif
  999. RtlUnicodeToMultiByteN(
  1000. OldAnsiPassword,
  1001. sizeof(OldAnsiPassword),
  1002. &BytesWritten,
  1003. OldPassword,
  1004. wcslen(OldPassword) * sizeof(WCHAR)
  1005. );
  1006. OldAnsiPassword[BytesWritten] = 0;
  1007. RtlUnicodeToMultiByteN(
  1008. NewAnsiPassword,
  1009. sizeof(NewAnsiPassword),
  1010. &BytesWritten,
  1011. NewPassword,
  1012. wcslen(NewPassword) * sizeof(WCHAR)
  1013. );
  1014. NewAnsiPassword[BytesWritten] = 0;
  1015. //
  1016. // twould seem that down-level servers require passwords to be in upper
  1017. // case (ie canonicalized) when they are decrypted. Same applies for
  1018. // cleartext
  1019. //
  1020. (VOID) _strupr(OldAnsiPassword);
  1021. (VOID) _strupr(NewAnsiPassword);
  1022. #ifdef DOWN_LEVEL_ENCRYPTION
  1023. //
  1024. // Calculate the one-way functions of the passwords.
  1025. //
  1026. Status = RtlCalculateLmOwfPassword(OldAnsiPassword, &OldOwfPassword);
  1027. if (!NT_SUCCESS(Status)) {
  1028. goto Cleanup;
  1029. }
  1030. Status = RtlCalculateLmOwfPassword(NewAnsiPassword, &NewOwfPassword);
  1031. if (!NT_SUCCESS(Status)) {
  1032. goto Cleanup;
  1033. }
  1034. //
  1035. // Cross-encrypt the passwords.
  1036. //
  1037. Status = RtlEncryptLmOwfPwdWithLmOwfPwd(&OldOwfPassword,
  1038. &NewOwfPassword,
  1039. &OldEncryptedWithNew
  1040. );
  1041. if (!NT_SUCCESS(Status)) {
  1042. goto Cleanup;
  1043. }
  1044. Status = RtlEncryptLmOwfPwdWithLmOwfPwd(&NewOwfPassword,
  1045. &OldOwfPassword,
  1046. &NewEncryptedWithOld
  1047. );
  1048. if (!NT_SUCCESS(Status)) {
  1049. goto Cleanup;
  1050. }
  1051. #else
  1052. //
  1053. // Status hasn't been initialized, but is tested below to determine if we
  1054. // should pick up the NetStatus from Status.
  1055. //
  1056. Status = STATUS_SUCCESS;
  1057. #endif // DOWN_LEVEL_ENCRYPTION
  1058. TryTheEncryptedApi:
  1059. NetStatus = RxRemoteApi(API_WUserPasswordSet2,
  1060. ServerName,
  1061. REMSmb_NetUserPasswordSet2_P,
  1062. NULL, NULL, NULL, // no data - just parms
  1063. NULL, NULL, NULL, // no aux data
  1064. (TryNullSession ? NO_PERMISSION_REQUIRED : 0),
  1065. UserName, // parameters...
  1066. #ifdef DOWN_LEVEL_ENCRYPTION
  1067. &OldEncryptedWithNew,
  1068. &NewEncryptedWithOld,
  1069. TRUE, // data encrypted?
  1070. #else
  1071. OldAnsiPassword,
  1072. NewAnsiPassword,
  1073. FALSE, // passwords not encrypted
  1074. #endif
  1075. strlen(NewAnsiPassword)
  1076. );
  1077. //
  1078. // LarryO says null session might have wrong credentials, so we
  1079. // should retry with non-null session.
  1080. //
  1081. if ( TryNullSession && (Status == ERROR_SESSION_CREDENTIAL_CONFLICT) ) {
  1082. TryNullSession = FALSE;
  1083. goto TryTheEncryptedApi; // retry this one.
  1084. }
  1085. //
  1086. // If the encrypted attempt fails with NERR_InvalidAPI, try plaintext
  1087. //
  1088. if (NetStatus == NERR_InvalidAPI) {
  1089. TryThePlainTextApi:
  1090. TryNullSession = TRUE; // Try null session first.
  1091. NetStatus = RxRemoteApi(API_WUserPasswordSet,
  1092. ServerName,
  1093. REMSmb_NetUserPasswordSet_P,
  1094. NULL, NULL, NULL, // no data - just parms
  1095. NULL, NULL, NULL, // no aux data
  1096. (TryNullSession ? NO_PERMISSION_REQUIRED : 0),
  1097. UserName, // parameters...
  1098. OldAnsiPassword,
  1099. NewAnsiPassword,
  1100. FALSE // data encrypted?
  1101. );
  1102. //
  1103. // LarryO says null session might have wrong credentials, so we
  1104. // should retry with non-null session.
  1105. //
  1106. if ( TryNullSession && (Status == ERROR_SESSION_CREDENTIAL_CONFLICT) ) {
  1107. TryNullSession = FALSE;
  1108. goto TryThePlainTextApi; // retry this one.
  1109. }
  1110. }
  1111. #ifdef DOWN_LEVEL_ENCRYPTION
  1112. Cleanup:
  1113. #endif
  1114. if (!NT_SUCCESS(Status)) {
  1115. NetStatus = RtlNtStatusToDosError(Status);
  1116. }
  1117. return NetStatus;
  1118. }
  1119. NET_API_STATUS
  1120. RxNetUserSetGroups(
  1121. IN LPTSTR ServerName,
  1122. IN LPTSTR UserName,
  1123. IN DWORD Level,
  1124. IN LPBYTE Buffer,
  1125. IN DWORD Entries
  1126. )
  1127. /*++
  1128. Routine Description:
  1129. Makes a user a member of the listed groups. This routine is virtually
  1130. identical to RxNetGroupSetUsers and most of the code was lifted from there
  1131. Arguments:
  1132. ServerName - where to run the API
  1133. UserName - which user to include
  1134. Level - Must Be Zero (MBZ)
  1135. Buffer - pointer to buffer containing a list of GROUP_INFO_0 structures
  1136. Entries - number of GROUP_INFO_0 structures in Buffer
  1137. Return Value:
  1138. NET_API_STATUS
  1139. Success - NERR_Success
  1140. Failure - ERROR_INVALID_LEVEL
  1141. ERROR_INVALID_PARAMETER
  1142. --*/
  1143. {
  1144. NET_API_STATUS rc;
  1145. LPGROUP_INFO_0 group_info;
  1146. DWORD i;
  1147. DWORD buflen;
  1148. LPBYTE newbuf;
  1149. static LPDESC group_0_enumerator_desc16 = "B21BN"; // same as UNLEN
  1150. static LPDESC group_0_enumerator_desc32 = "zQA";
  1151. //
  1152. // This structure is required because the remoting code (particularly down
  1153. // level) can only handle there being >1 auxiliary structure, vs >1
  1154. // primary. Hence we have to convert the caller's supplied buffer of
  1155. // erstwhile primary structures to auxiliaries by forcing the structure
  1156. // below in at the head of the buffer, hence becoming the primary and
  1157. // providing an aux structure count (groan)
  1158. //
  1159. struct group_0_enumerator {
  1160. LPTSTR user_name; // which user to set groups for
  1161. DWORD group_count; // number of GROUP_INFO_0 structures in buffer
  1162. };
  1163. if (Level) {
  1164. return ERROR_INVALID_LEVEL; // MBZ, remember?
  1165. }
  1166. if (STRLEN(UserName) > LM20_UNLEN) {
  1167. return ERROR_INVALID_PARAMETER;
  1168. }
  1169. //
  1170. // iterate through the buffer, checking that each GROUP_INFO_0
  1171. // structure contains a pointer to a valid string which is in the
  1172. // correct range
  1173. //
  1174. group_info = (LPGROUP_INFO_0)Buffer;
  1175. for (i=0; i<Entries; ++i) {
  1176. if (!VALID_STRING(group_info->grpi0_name)) {
  1177. return ERROR_INVALID_PARAMETER;
  1178. }
  1179. if (wcslen(group_info->grpi0_name) > LM20_GNLEN) {
  1180. return ERROR_INVALID_PARAMETER;
  1181. }
  1182. ++group_info;
  1183. }
  1184. //
  1185. // allocate a buffer large enough to fit in <Entries> number of
  1186. // GROUP_INFO_0 structures, and 1 group_0_enumerator structure.
  1187. // Don't worry about string space - unfortunately the Rxp and Rap routines
  1188. // called by RxRemoteApi will allocate yet another buffer, do yet another
  1189. // copy and this time copy in the strings from user space. Hopefully, this
  1190. // routine won't get called too often
  1191. //
  1192. buflen = Entries * sizeof(GROUP_INFO_0) + sizeof(struct group_0_enumerator);
  1193. buflen = DWORD_ROUNDUP(buflen);
  1194. if (rc = NetApiBufferAllocate(buflen, (LPVOID *) &newbuf)) {
  1195. return rc; // aieegh! Failed to allocate memory?
  1196. }
  1197. ((struct group_0_enumerator*)newbuf)->user_name = UserName;
  1198. ((struct group_0_enumerator*)newbuf)->group_count = Entries;
  1199. if (Entries > 0) {
  1200. // Append the group entries to the header we just built.
  1201. NetpMoveMemory(
  1202. newbuf + sizeof(struct group_0_enumerator), // dest
  1203. Buffer, // src
  1204. buflen - sizeof(struct group_0_enumerator)); // byte count
  1205. }
  1206. rc = RxRemoteApi(API_WUserSetGroups,
  1207. ServerName,
  1208. REMSmb_NetUserSetGroups_P,
  1209. group_0_enumerator_desc16, // the "fudged" 16-bit data descriptor
  1210. group_0_enumerator_desc32, // the "fudged" 32-bit data descriptor
  1211. group_0_enumerator_desc16, // SMB desc same as 16-bit
  1212. REM16_group_info_0, // "new" 16-bit aux descriptor
  1213. REM32_group_info_0, // "new" 32-bit aux descriptor
  1214. REMSmb_group_info_0, // SMB aux descriptor
  1215. FALSE, // this API requires user security
  1216. UserName, // parm 1
  1217. 0, // info level must be 0
  1218. newbuf, // "fudged" buffer
  1219. buflen, // length of "fudged" buffer
  1220. Entries // number of GROUP_USERS_INFO_0
  1221. );
  1222. NetpMemoryFree(newbuf);
  1223. return rc;
  1224. }
  1225. NET_API_STATUS
  1226. RxNetUserSetInfo(
  1227. IN LPTSTR ServerName,
  1228. IN LPTSTR UserName,
  1229. IN DWORD Level,
  1230. IN LPBYTE Buffer,
  1231. OUT LPDWORD ParmError OPTIONAL
  1232. )
  1233. /*++
  1234. Routine Description:
  1235. Sets information in a user account in a down-level UAS database
  1236. Assumes:
  1237. 1. UserName is a valid pointer to a valid string,
  1238. Level is in the range below,
  1239. Buffer is a valid pointer
  1240. ParmError is a valid pointer
  1241. Arguments:
  1242. ServerName - where to run the API
  1243. UserName - which user to change info for
  1244. Level - of info supplied - 1-2, 1003, 1005-1014, 1017-1018, 1020, 1023-1025
  1245. Buffer - if PARMNUM_ALL, pointer to buffer containing info,
  1246. else pointer to pointer to buffer containing info
  1247. ParmError - which parameter was bad
  1248. Return Value:
  1249. NET_API_STATUS
  1250. Success - NERR_Success
  1251. Failure - ERROR_INVALID_LEVEL
  1252. ERROR_INVALID_PARAMETER
  1253. --*/
  1254. {
  1255. DWORD parmnum;
  1256. DWORD badparm;
  1257. DWORD buflen;
  1258. DWORD stringlen;
  1259. LPWSTR pointer; // general pointer to string for range checking
  1260. LPDESC pDesc16;
  1261. LPDESC pDesc32;
  1262. LPDESC pDescSmb;
  1263. DWORD passwordEncrypted = FALSE;
  1264. DWORD originalPasswordLength = 0;
  1265. CHAR ansiPassword[LM20_PWLEN+1];
  1266. DWORD lmOwfPasswordLen;
  1267. LPTSTR cleartext;
  1268. LPTSTR* lpClearText;
  1269. NET_API_STATUS NetStatus = NERR_Success;
  1270. #ifdef DOWN_LEVEL_ENCRYPTION
  1271. LM_OWF_PASSWORD lmOwfPassword;
  1272. LM_SESSION_KEY lanmanKey;
  1273. ENCRYPTED_LM_OWF_PASSWORD encryptedLmOwfPassword;
  1274. NTSTATUS Status;
  1275. #endif
  1276. BYTE logonHours[21];
  1277. PBYTE callersLogonHours = NULL;
  1278. PBYTE* lpCallersLogonHours;
  1279. WCHAR Workstations[MAX_WORKSTATION_LIST+1];
  1280. LPWSTR callersWorkstations = NULL;
  1281. LPWSTR *lpCallersWorkstations;
  1282. if (ParmError == NULL) {
  1283. ParmError = &badparm;
  1284. }
  1285. *ParmError = PARM_ERROR_NONE;
  1286. if (STRLEN(UserName) > LM20_UNLEN) {
  1287. NetStatus = ERROR_INVALID_PARAMETER;
  1288. goto Cleanup;
  1289. }
  1290. //
  1291. // throw out invalid level parameter
  1292. //
  1293. if ((Level > 2 && Level < USER_PASSWORD_INFOLEVEL)
  1294. // 2 < Level < 1003
  1295. || (Level > USER_PASSWORD_INFOLEVEL && Level < USER_PRIV_INFOLEVEL)
  1296. // 1003 < Level < 1005 : Check compiler generates == 1004
  1297. || (Level > USER_WORKSTATIONS_INFOLEVEL && Level < USER_ACCT_EXPIRES_INFOLEVEL)
  1298. // 1014 < Level < 1017
  1299. || (Level > USER_MAX_STORAGE_INFOLEVEL && Level < USER_LOGON_HOURS_INFOLEVEL)
  1300. // 1018 < Level < 1020 : Check compiler generates == 1019
  1301. || (Level > USER_LOGON_HOURS_INFOLEVEL && Level < USER_LOGON_SERVER_INFOLEVEL)
  1302. // 1020 < Level < 1023
  1303. || (Level > USER_CODE_PAGE_INFOLEVEL)) {
  1304. // Level < 1025
  1305. NetStatus = ERROR_INVALID_LEVEL;
  1306. goto Cleanup;
  1307. }
  1308. //
  1309. // default to Level 2 for the descriptors (Level 2 works for level 1 also)
  1310. //
  1311. pDesc16 = REM16_user_info_2;
  1312. pDesc32 = REM32_user_info_2;
  1313. pDescSmb = REMSmb_user_info_2;
  1314. if (Level < PARMNUM_BASE_INFOLEVEL) {
  1315. parmnum = PARMNUM_ALL;
  1316. if (Level == 1) {
  1317. pDesc16 = REM16_user_info_1;
  1318. pDesc32 = REM32_user_info_1;
  1319. pDescSmb = REMSmb_user_info_1;
  1320. buflen = sizeof(USER_INFO_1);
  1321. } else {
  1322. buflen = sizeof(USER_INFO_2) + 21;
  1323. }
  1324. } else {
  1325. parmnum = Level - PARMNUM_BASE_INFOLEVEL;
  1326. //
  1327. // Because info level 1 is a subset of info level 2, setting the level
  1328. // to 2 is ok for those parmnums which can be set at level 1 AND 2.
  1329. // Set pointer = Buffer so that in the parmnum != PARMNUM_ALL case, we
  1330. // just check the length of whatever pointer points at
  1331. //
  1332. Level = 2;
  1333. pointer = *(LPWSTR*) Buffer;
  1334. buflen = 0;
  1335. }
  1336. if (parmnum == PARMNUM_ALL) {
  1337. if (pointer = ((PUSER_INFO_1)(LPVOID)Buffer)->usri1_name) {
  1338. if ((stringlen = POSSIBLE_WCSLEN(pointer)) > LM20_UNLEN) {
  1339. *ParmError = USER_NAME_PARMNUM;
  1340. NetStatus = ERROR_INVALID_PARAMETER;
  1341. goto Cleanup;
  1342. }
  1343. buflen += STRING_SPACE_REQD(stringlen + 1);
  1344. }
  1345. }
  1346. if ((parmnum == PARMNUM_ALL) || (parmnum == USER_PASSWORD_PARMNUM)) {
  1347. if (parmnum == PARMNUM_ALL) {
  1348. pointer = ((PUSER_INFO_1)Buffer)->usri1_password;
  1349. }
  1350. if ((stringlen = POSSIBLE_WCSLEN(pointer)) > LM20_PWLEN) {
  1351. *ParmError = USER_PASSWORD_PARMNUM;
  1352. NetStatus = ERROR_INVALID_PARAMETER;
  1353. goto Cleanup;
  1354. }
  1355. buflen += STRING_SPACE_REQD(stringlen + 1);
  1356. //
  1357. // original password length is length of unencrypted string in
  1358. // characters, excluding terminating NUL
  1359. //
  1360. originalPasswordLength = stringlen;
  1361. //
  1362. // lpClearText is address of pointer to cleartext password
  1363. //
  1364. lpClearText = (parmnum == PARMNUM_ALL)
  1365. ? (LPTSTR*)&((PUSER_INFO_1)Buffer)->usri1_password
  1366. : (LPTSTR*)Buffer;
  1367. //
  1368. // copy the cleartext password out of the buffer - we will replace it with
  1369. // the encrypted version, but need to put the cleartext back before
  1370. // returning control to the caller
  1371. //
  1372. cleartext = *lpClearText;
  1373. }
  1374. if ((parmnum == PARMNUM_ALL) || (parmnum == USER_HOME_DIR_PARMNUM)) {
  1375. if (parmnum == PARMNUM_ALL) {
  1376. pointer = ((PUSER_INFO_1)Buffer)->usri1_home_dir;
  1377. }
  1378. if ((stringlen = POSSIBLE_WCSLEN(pointer)) > LM20_PATHLEN) {
  1379. *ParmError = USER_HOME_DIR_PARMNUM;
  1380. NetStatus = ERROR_INVALID_PARAMETER;
  1381. goto Cleanup;
  1382. }
  1383. buflen += STRING_SPACE_REQD(stringlen + 1);
  1384. }
  1385. if ((parmnum == PARMNUM_ALL) || (parmnum == USER_COMMENT_PARMNUM)) {
  1386. if (parmnum == PARMNUM_ALL) {
  1387. pointer = ((PUSER_INFO_1)Buffer)->usri1_comment;
  1388. }
  1389. if ((stringlen = POSSIBLE_WCSLEN(pointer)) > LM20_MAXCOMMENTSZ) {
  1390. *ParmError = USER_COMMENT_PARMNUM;
  1391. NetStatus = ERROR_INVALID_PARAMETER;
  1392. goto Cleanup;
  1393. }
  1394. buflen += STRING_SPACE_REQD(stringlen + 1);
  1395. }
  1396. if ((parmnum == PARMNUM_ALL) || (parmnum == USER_SCRIPT_PATH_PARMNUM)) {
  1397. if (parmnum == PARMNUM_ALL) {
  1398. pointer = ((PUSER_INFO_1)Buffer)->usri1_script_path;
  1399. }
  1400. if ((stringlen = POSSIBLE_WCSLEN(pointer)) > LM20_PATHLEN) {
  1401. *ParmError = USER_SCRIPT_PATH_PARMNUM;
  1402. NetStatus = ERROR_INVALID_PARAMETER;
  1403. goto Cleanup;
  1404. }
  1405. buflen += STRING_SPACE_REQD(stringlen + 1);
  1406. }
  1407. //
  1408. // the next set of checks only need to be done if we are setting PARMNUM_ALL
  1409. // with a Level of 2 or if the parmnum implicitly requires Level 2 (ie parms
  1410. // >= 10)
  1411. //
  1412. if (Level == 2) {
  1413. if ((parmnum == PARMNUM_ALL) || (parmnum == USER_FULL_NAME_PARMNUM)) {
  1414. if (parmnum == PARMNUM_ALL) {
  1415. pointer = ((PUSER_INFO_2)Buffer)->usri2_full_name;
  1416. }
  1417. if ((stringlen = POSSIBLE_WCSLEN(pointer)) > LM20_MAXCOMMENTSZ) {
  1418. *ParmError = USER_FULL_NAME_PARMNUM;
  1419. NetStatus = ERROR_INVALID_PARAMETER;
  1420. goto Cleanup;
  1421. }
  1422. buflen += STRING_SPACE_REQD(stringlen + 1);
  1423. }
  1424. if ((parmnum == PARMNUM_ALL) || (parmnum == USER_USR_COMMENT_PARMNUM)) {
  1425. if (parmnum == PARMNUM_ALL) {
  1426. pointer = ((PUSER_INFO_2)Buffer)->usri2_usr_comment;
  1427. }
  1428. if ((stringlen = POSSIBLE_WCSLEN(pointer)) > LM20_MAXCOMMENTSZ) {
  1429. *ParmError = USER_USR_COMMENT_PARMNUM;
  1430. NetStatus = ERROR_INVALID_PARAMETER;
  1431. goto Cleanup;
  1432. }
  1433. buflen += STRING_SPACE_REQD(stringlen + 1);
  1434. }
  1435. if ((parmnum == PARMNUM_ALL) || (parmnum == USER_PARMS_PARMNUM)) {
  1436. if (parmnum == PARMNUM_ALL) {
  1437. pointer = ((PUSER_INFO_2)Buffer)->usri2_parms;
  1438. }
  1439. if ((stringlen = POSSIBLE_WCSLEN(pointer)) > LM20_MAXCOMMENTSZ) {
  1440. *ParmError = USER_PARMS_PARMNUM;
  1441. NetStatus = ERROR_INVALID_PARAMETER;
  1442. goto Cleanup;
  1443. }
  1444. buflen += STRING_SPACE_REQD(stringlen + 1);
  1445. }
  1446. if ((parmnum == PARMNUM_ALL) || (parmnum == USER_WORKSTATIONS_PARMNUM)) {
  1447. UNICODE_STRING WorkstationString;
  1448. if (parmnum == PARMNUM_ALL) {
  1449. lpCallersWorkstations = &((PUSER_INFO_2)Buffer)->usri2_workstations;
  1450. } else {
  1451. lpCallersWorkstations = &((PUSER_INFO_1014)Buffer)->usri1014_workstations;
  1452. }
  1453. callersWorkstations = *lpCallersWorkstations;
  1454. if ((stringlen = POSSIBLE_WCSLEN(callersWorkstations)) > MAX_WORKSTATION_LIST) {
  1455. *ParmError = USER_WORKSTATIONS_PARMNUM;
  1456. NetStatus = ERROR_INVALID_PARAMETER;
  1457. goto Cleanup;
  1458. }
  1459. buflen += STRING_SPACE_REQD(stringlen + 1);
  1460. //
  1461. // Convert the list of workstations from being comma separated
  1462. // to being space separated. Ditch workstation names containing
  1463. // spaces.
  1464. if ( callersWorkstations != NULL ) {
  1465. wcsncpy( Workstations, callersWorkstations, MAX_WORKSTATION_LIST );
  1466. RtlInitUnicodeString( &WorkstationString, Workstations );
  1467. NetpConvertWorkstationList( &WorkstationString );
  1468. *lpCallersWorkstations = Workstations;
  1469. }
  1470. }
  1471. if ((parmnum == PARMNUM_ALL) || (parmnum == USER_LOGON_SERVER_PARMNUM)) {
  1472. if (parmnum == PARMNUM_ALL) {
  1473. pointer = ((PUSER_INFO_2)Buffer)->usri2_logon_server;
  1474. }
  1475. if ((stringlen = POSSIBLE_WCSLEN(pointer)) > MAX_PATH) {
  1476. *ParmError = USER_LOGON_SERVER_PARMNUM;
  1477. NetStatus = ERROR_INVALID_PARAMETER;
  1478. goto Cleanup;
  1479. }
  1480. buflen += STRING_SPACE_REQD(stringlen + 1);
  1481. }
  1482. //
  1483. // if the caller is setting the logon hours then we need to substitute
  1484. // shuffled bits for the logon hours bitmap
  1485. //
  1486. if ((parmnum == PARMNUM_ALL) || (parmnum == USER_LOGON_HOURS_PARMNUM)) {
  1487. if (parmnum == PARMNUM_ALL) {
  1488. lpCallersLogonHours = (PBYTE*)&((PUSER_INFO_2)Buffer)->usri2_logon_hours;
  1489. } else {
  1490. lpCallersLogonHours = (PBYTE*)&((PUSER_INFO_1020)Buffer)->usri1020_logon_hours;
  1491. }
  1492. callersLogonHours = *lpCallersLogonHours;
  1493. RtlCopyMemory(logonHours, callersLogonHours, sizeof(logonHours));
  1494. //
  1495. // shuffle the bitmap and point the logon_hours field in the structure
  1496. // at the shuffled version
  1497. //
  1498. NetpRotateLogonHours(logonHours, UNITS_PER_WEEK, FALSE);
  1499. *lpCallersLogonHours = logonHours;
  1500. }
  1501. }
  1502. //
  1503. // we have covered all the parameters that we are able to from this end. The
  1504. // down-level APIs don't know about the ParmError concept (it is, after all,
  1505. // a highly developed notion, too highbrow for the LanManDerthals...) so if
  1506. // we get back an ERROR_INVALID_PARAMETER, the caller will just have to be
  1507. // content with PARM_ERROR_UNKNOWN, and try to figure it out from there
  1508. //
  1509. *ParmError = PARM_ERROR_UNKNOWN;
  1510. //
  1511. // if originalPasswordLength is non-zero then we must be supplying a password;
  1512. // perform the encryption machinations
  1513. //
  1514. if (originalPasswordLength) {
  1515. //
  1516. // Calculate the one-way function of the password
  1517. //
  1518. RtlUnicodeToMultiByteN(ansiPassword,
  1519. sizeof(ansiPassword),
  1520. &lmOwfPasswordLen,
  1521. *lpClearText,
  1522. originalPasswordLength * sizeof(WCHAR)
  1523. );
  1524. ansiPassword[lmOwfPasswordLen] = 0;
  1525. (VOID) _strupr(ansiPassword); // down-level wants upper-cased passwords
  1526. #ifdef DOWN_LEVEL_ENCRYPTION
  1527. Status = RtlCalculateLmOwfPassword(ansiPassword, &lmOwfPassword);
  1528. if (NT_SUCCESS(Status)) {
  1529. NetStatus = GetLanmanSessionKey((LPWSTR)ServerName, (LPBYTE)&lanmanKey);
  1530. if (NetStatus == NERR_Success) {
  1531. Status = RtlEncryptLmOwfPwdWithLmSesKey(&lmOwfPassword,
  1532. &lanmanKey,
  1533. &encryptedLmOwfPassword
  1534. );
  1535. if (NT_SUCCESS(Status)) {
  1536. *lpClearText = (LPTSTR)&encryptedLmOwfPassword;
  1537. passwordEncrypted = TRUE;
  1538. if (parmnum == USER_PASSWORD_PARMNUM) {
  1539. buflen = sizeof(encryptedLmOwfPassword);
  1540. }
  1541. }
  1542. }
  1543. }
  1544. if (NetStatus != NERR_Success) {
  1545. goto Cleanup;
  1546. }
  1547. else if (!NT_SUCCESS(Status)) {
  1548. NetStatus = RtlNtStatusToDosError(Status);
  1549. goto Cleanup;
  1550. }
  1551. #else
  1552. *lpClearText = (LPTSTR)ansiPassword;
  1553. #endif
  1554. }
  1555. //
  1556. // New! Improved! Now, even better, RxNetUserSetInfo will use SetInfo2
  1557. // to fix the most stubborn user set info problems (ie password)
  1558. //
  1559. NetStatus = RxRemoteApi(API_WUserSetInfo2,
  1560. ServerName,
  1561. REMSmb_NetUserSetInfo2_P,
  1562. pDesc16, pDesc32, pDescSmb, // data descriptors
  1563. NULL, NULL, NULL, // no aux data
  1564. FALSE, // must be logged on
  1565. UserName, // parameters...
  1566. Level,
  1567. //
  1568. // if we are sending the whole structure, then Buffer
  1569. // points to the structure, else Buffer points to a
  1570. // pointer to the field to set; RxRemoteApi expects
  1571. // a pointer to the data
  1572. //
  1573. parmnum == PARMNUM_ALL || parmnum == USER_PASSWORD_PARMNUM
  1574. ? Buffer
  1575. : *(LPBYTE*)Buffer,
  1576. buflen, // supplied by us
  1577. //
  1578. // in this case, the field index and parm num are the
  1579. // same value
  1580. //
  1581. MAKE_PARMNUM_PAIR(parmnum, parmnum),
  1582. //
  1583. // add those extraneous WWs: whether the data is
  1584. // encrypted and the original password length. (By
  1585. // deduction: password is the only data that is
  1586. // encrypted)
  1587. //
  1588. passwordEncrypted,
  1589. originalPasswordLength
  1590. );
  1591. Cleanup:
  1592. //
  1593. // copy the original password back to the user's buffer if we set a password
  1594. //
  1595. if (originalPasswordLength) {
  1596. *lpClearText = cleartext;
  1597. }
  1598. //
  1599. // restore the original logon hours string
  1600. //
  1601. if (callersLogonHours) {
  1602. *lpCallersLogonHours = callersLogonHours;
  1603. }
  1604. //
  1605. // restore the original workstation list
  1606. //
  1607. if ( callersWorkstations != NULL) {
  1608. *lpCallersWorkstations = callersWorkstations;
  1609. }
  1610. return NetStatus;
  1611. }
  1612. //NET_API_STATUS
  1613. //RxNetUserValidate2
  1614. // /** CANNOT BE REMOTED **/
  1615. //{
  1616. //
  1617. //}
  1618. DBGSTATIC
  1619. NET_API_STATUS
  1620. GetUserDescriptors(
  1621. IN DWORD Level,
  1622. IN BOOL Encrypted,
  1623. OUT LPDESC* ppDesc16,
  1624. OUT LPDESC* ppDesc32,
  1625. OUT LPDESC* ppDescSmb
  1626. )
  1627. /*++
  1628. Routine Description:
  1629. Returns pointers to descriptor strings for user info structures based on
  1630. level of info required for RxNetUser routines
  1631. Arguments:
  1632. Level - of info being requested
  1633. Encrypted - TRUE if info structure contains encrypted password
  1634. ppDesc16 - where to return pointer to 16-bit data descriptor
  1635. ppDesc32 - where to return pointer to 32-bit data descriptor
  1636. ppDescSmb - where to return pointer to SMB data descriptor
  1637. Return Value:
  1638. ERROR_INVALID_LEVEL - If the level was not in the list.
  1639. NO_ERROR - If the operation was successful.
  1640. --*/
  1641. {
  1642. switch (Level) {
  1643. case 0:
  1644. *ppDesc16 = REM16_user_info_0;
  1645. *ppDesc32 = REM32_user_info_0;
  1646. *ppDescSmb = REMSmb_user_info_0;
  1647. break;
  1648. case 1:
  1649. *ppDesc16 = REM16_user_info_1;
  1650. *ppDesc32 = Encrypted ? REM32_user_info_1 : REM32_user_info_1_NOCRYPT;
  1651. *ppDescSmb = REMSmb_user_info_1;
  1652. break;
  1653. case 2:
  1654. *ppDesc16 = REM16_user_info_2;
  1655. *ppDesc32 = Encrypted ? REM32_user_info_2 : REM32_user_info_2_NOCRYPT;
  1656. *ppDescSmb = REMSmb_user_info_2;
  1657. break;
  1658. case 10:
  1659. *ppDesc16 = REM16_user_info_10;
  1660. *ppDesc32 = REM32_user_info_10;
  1661. *ppDescSmb = REMSmb_user_info_10;
  1662. break;
  1663. case 11:
  1664. *ppDesc16 = REM16_user_info_11;
  1665. *ppDesc32 = REM32_user_info_11;
  1666. *ppDescSmb = REMSmb_user_info_11;
  1667. break;
  1668. default:
  1669. return(ERROR_INVALID_LEVEL);
  1670. }
  1671. return(NO_ERROR);
  1672. }
  1673. DBGSTATIC
  1674. VOID
  1675. GetModalsDescriptors(
  1676. IN DWORD Level,
  1677. OUT LPDESC* ppDesc16,
  1678. OUT LPDESC* ppDesc32,
  1679. OUT LPDESC* ppDescSmb
  1680. )
  1681. /*++
  1682. Routine Description:
  1683. Returns pointers to descriptor strings for modals info structures based on
  1684. level of info required for RxNetUserModals routines
  1685. Arguments:
  1686. Level - of info being requested
  1687. ppDesc16 - where to return pointer to 16-bit data descriptor
  1688. ppDesc32 - where to return pointer to 32-bit data descriptor
  1689. ppDescSmb - where to return pointer to SMB data descriptor
  1690. Return Value:
  1691. None.
  1692. --*/
  1693. {
  1694. switch (Level) {
  1695. case 0:
  1696. *ppDesc16 = REM16_user_modals_info_0;
  1697. *ppDesc32 = REM32_user_modals_info_0;
  1698. *ppDescSmb = REMSmb_user_modals_info_0;
  1699. break;
  1700. case 1:
  1701. *ppDesc16 = REM16_user_modals_info_1;
  1702. *ppDesc32 = REM32_user_modals_info_1;
  1703. *ppDescSmb = REMSmb_user_modals_info_1;
  1704. break;
  1705. }
  1706. }
  1707. NET_API_STATUS
  1708. GetLanmanSessionKey(
  1709. IN LPWSTR ServerName,
  1710. OUT LPBYTE pSessionKey
  1711. )
  1712. /*++
  1713. Routine Description:
  1714. Retrieves the LM session key for the connection from the redir FSD
  1715. Arguments:
  1716. ServerName - name of server to get session key for
  1717. pSessionKey - pointer to where session key will be deposited
  1718. Return Value:
  1719. NET_API_STATUS
  1720. Success - NERR_Success
  1721. Failure -
  1722. --*/
  1723. {
  1724. NTSTATUS ntStatus;
  1725. HANDLE hToken;
  1726. TOKEN_STATISTICS stats;
  1727. ULONG length;
  1728. LMR_REQUEST_PACKET request;
  1729. LMR_CONNECTION_INFO_2 connectInfo;
  1730. NET_API_STATUS apiStatus;
  1731. WCHAR connectionName[MAX_PATH];
  1732. ntStatus = NtOpenProcessToken(NtCurrentProcess(), GENERIC_READ, &hToken);
  1733. if (NT_SUCCESS(ntStatus)) {
  1734. //
  1735. // Get the logon id of the current thread
  1736. //
  1737. ntStatus = NtQueryInformationToken(hToken,
  1738. TokenStatistics,
  1739. (PVOID)&stats,
  1740. sizeof(stats),
  1741. &length
  1742. );
  1743. if (NT_SUCCESS(ntStatus)) {
  1744. RtlCopyLuid(&request.LogonId, &stats.AuthenticationId);
  1745. request.Type = GetConnectionInfo;
  1746. request.Version = REQUEST_PACKET_VERSION;
  1747. request.Level = 2;
  1748. wcsncpy(connectionName, ServerName, MAX_PATH-1);
  1749. wcsncat(connectionName, L"\\IPC$", MAX_PATH-1-wcslen(ServerName) );
  1750. apiStatus = NetpRdrFsControlTree(connectionName,
  1751. NULL,
  1752. USE_WILDCARD,
  1753. FSCTL_LMR_GET_CONNECTION_INFO,
  1754. NULL,
  1755. (LPVOID)&request,
  1756. sizeof(request),
  1757. (LPVOID)&connectInfo,
  1758. sizeof(connectInfo),
  1759. FALSE
  1760. );
  1761. if (apiStatus == NERR_Success) {
  1762. RtlMoveMemory(pSessionKey,
  1763. &connectInfo.LanmanSessionKey,
  1764. sizeof(connectInfo.LanmanSessionKey)
  1765. );
  1766. }
  1767. }
  1768. NtClose(hToken);
  1769. }
  1770. if (!NT_SUCCESS(ntStatus)) {
  1771. apiStatus = NetpNtStatusToApiStatus(ntStatus);
  1772. }
  1773. return apiStatus;
  1774. }