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.

3513 lines
95 KiB

  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. Module Name:
  4. userp.c
  5. Abstract:
  6. Internal routines for supporting the NetUser API functions
  7. Author:
  8. Cliff Van Dyke (cliffv) 26-Mar-1991
  9. Environment:
  10. User mode only.
  11. Contains NT-specific code.
  12. Requires ANSI C extensions: slash-slash comments, long external names.
  13. Revision History:
  14. 17-Apr-1991 (cliffv)
  15. Incorporated review comments.
  16. 17-Jan-1992 (madana)
  17. Added a new entry in the UserpUasSamTable to support account
  18. rename.
  19. 20-Jan-1992 (madana)
  20. Sundry API changes.
  21. --*/
  22. #include <nt.h>
  23. #include <ntrtl.h>
  24. #include <nturtl.h>
  25. #undef DOMAIN_ALL_ACCESS // defined in both ntsam.h and ntwinapi.h
  26. #include <ntsam.h>
  27. #include <ntsamp.h>
  28. #include <ntlsa.h>
  29. #include <windef.h>
  30. #include <winbase.h>
  31. #include <lmcons.h>
  32. #include <access.h>
  33. #include <accessp.h>
  34. #include <align.h>
  35. #include <limits.h>
  36. #include <lmapibuf.h>
  37. #include <lmaccess.h>
  38. #include <lmerr.h>
  39. #include <netdebug.h>
  40. #include <netlib.h>
  41. #include <netlibnt.h>
  42. #include <secobj.h>
  43. #include <stddef.h>
  44. #include <uasp.h>
  45. /*lint -e614 */ /* Auto aggregate initializers need not be constant */
  46. // Lint complains about casts of one structure type to another.
  47. // That is done frequently in the code below.
  48. /*lint -e740 */ /* don't complain about unusual cast */
  49. ULONG
  50. UserpSizeOfLogonHours(
  51. IN DWORD UnitsPerWeek
  52. )
  53. /*++
  54. Routine Description:
  55. This routine calculates the size in bytes of a logon hours string
  56. given the number of Units per Week.
  57. Parameters:
  58. UnitsPerWeek - The number of bits in the logon hours string.
  59. Return Values:
  60. None.
  61. --*/
  62. {
  63. //
  64. // Calculate the number of bytes in the array, rounding up to the
  65. // nearest number of UCHARs needed to store that many bits.
  66. //
  67. return((UnitsPerWeek + 8 * sizeof(UCHAR) - 1) / (8 * sizeof(UCHAR)));
  68. } // UserpSizeOfLogonHours
  69. NET_API_STATUS
  70. UserpGetUserPriv(
  71. IN SAM_HANDLE BuiltinDomainHandle,
  72. IN SAM_HANDLE UserHandle,
  73. IN ULONG UserRelativeId,
  74. IN PSID DomainId,
  75. OUT LPDWORD Priv,
  76. OUT LPDWORD AuthFlags
  77. )
  78. /*++
  79. Routine Description:
  80. Determines the Priv and AuthFlags for the specified user.
  81. Arguments:
  82. BuiltinDomainHandle - A Handle to the Builtin Domain. This handle
  83. must grant DOMAIN_GET_ALIAS_MEMBERSHIP access.
  84. UserHandle - A handle to the user. This handle must grant
  85. USER_LIST_GROUPS access.
  86. UserRelativeId - Relative ID of the user to query.
  87. DomainId - Domain Sid of the Domain this user belongs to
  88. Priv - Returns the Lanman 2.0 Privilege level for the specified user.
  89. AuthFlags - Returns the Lanman 2.0 Authflags for the specified user.
  90. Return Value:
  91. Status of the operation.
  92. --*/
  93. {
  94. NET_API_STATUS NetStatus;
  95. NTSTATUS Status;
  96. PGROUP_MEMBERSHIP GroupMembership = NULL;
  97. ULONG GroupCount;
  98. ULONG GroupIndex;
  99. PSID *UserSids = NULL;
  100. ULONG UserSidCount = 0;
  101. ULONG AliasCount;
  102. PULONG Aliases = NULL;
  103. //
  104. // Determine all the groups this user is a member of
  105. //
  106. Status = SamGetGroupsForUser( UserHandle,
  107. &GroupMembership,
  108. &GroupCount);
  109. if ( !NT_SUCCESS(Status) ) {
  110. IF_DEBUG( UAS_DEBUG_USER ) {
  111. NetpKdPrint((
  112. "UserpGetUserPriv: SamGetGroupsForUser returns %lX\n",
  113. Status ));
  114. }
  115. NetStatus = NetpNtStatusToApiStatus( Status );
  116. goto Cleanup;
  117. }
  118. //
  119. // Allocate a buffer to point to the SIDs we're interested in
  120. // alias membership for.
  121. //
  122. UserSids = (PSID *) NetpMemoryAllocate( (GroupCount+1) * sizeof(PSID) );
  123. if ( UserSids == NULL ) {
  124. NetStatus = ERROR_NOT_ENOUGH_MEMORY;
  125. goto Cleanup;
  126. }
  127. //
  128. // Add the User's Sid to the Array of Sids.
  129. //
  130. NetStatus = NetpSamRidToSid( UserHandle,
  131. UserRelativeId,
  132. &UserSids[0] );
  133. if ( NetStatus != NERR_Success ) {
  134. goto Cleanup;
  135. }
  136. UserSidCount ++;
  137. //
  138. // Add each group the user is a member of to the array of Sids.
  139. //
  140. for ( GroupIndex = 0; GroupIndex < GroupCount; GroupIndex ++ ) {
  141. NetStatus = NetpSamRidToSid( UserHandle,
  142. GroupMembership[GroupIndex].RelativeId,
  143. &UserSids[GroupIndex+1] );
  144. if ( NetStatus != NERR_Success ) {
  145. goto Cleanup;
  146. }
  147. UserSidCount ++;
  148. }
  149. //
  150. // Find out which aliases in the builtin domain this user is a member of.
  151. //
  152. Status = SamGetAliasMembership( BuiltinDomainHandle,
  153. UserSidCount,
  154. UserSids,
  155. &AliasCount,
  156. &Aliases );
  157. if ( !NT_SUCCESS(Status) ) {
  158. IF_DEBUG( UAS_DEBUG_USER ) {
  159. NetpKdPrint((
  160. "UserpGetUserPriv: SamGetAliasMembership returns %lX\n",
  161. Status ));
  162. }
  163. NetStatus = NetpNtStatusToApiStatus( Status );
  164. goto Cleanup;
  165. }
  166. //
  167. // Convert the alias membership to priv and auth flags
  168. //
  169. NetpAliasMemberToPriv(
  170. AliasCount,
  171. Aliases,
  172. Priv,
  173. AuthFlags );
  174. NetStatus = NERR_Success;
  175. //
  176. // Free Locally used resources.
  177. //
  178. Cleanup:
  179. if ( Aliases != NULL ) {
  180. Status = SamFreeMemory( Aliases );
  181. NetpAssert( NT_SUCCESS(Status) );
  182. }
  183. if ( GroupMembership != NULL ) {
  184. Status = SamFreeMemory( GroupMembership );
  185. NetpAssert( NT_SUCCESS(Status) );
  186. }
  187. if ( UserSids != NULL ) {
  188. for ( GroupIndex = 0; GroupIndex < UserSidCount; GroupIndex ++ ) {
  189. NetpMemoryFree( UserSids[GroupIndex] );
  190. }
  191. NetpMemoryFree( UserSids );
  192. }
  193. return NetStatus;
  194. }
  195. NET_API_STATUS
  196. UserpGetDacl(
  197. IN SAM_HANDLE UserHandle,
  198. OUT PACL *UserDacl,
  199. OUT LPDWORD UserDaclSize OPTIONAL
  200. )
  201. /*++
  202. Routine Description:
  203. Get the DACL for a particular user record in SAM.
  204. Arguments:
  205. UserHandle - A Handle to the particular user.
  206. UserDacl - Returns a pointer to the DACL for the user. The caller
  207. should free this buffer using NetpMemoryFree.
  208. Will return NULL if there is no DACL for this user.
  209. UserDaclSize - Returns the size (in bytes) of the UserDacl.
  210. Return Value:
  211. Status of the operation.
  212. --*/
  213. {
  214. NET_API_STATUS NetStatus;
  215. NTSTATUS Status;
  216. PSECURITY_DESCRIPTOR SecurityDescriptor = NULL;
  217. BOOLEAN DaclPresent;
  218. PACL Dacl;
  219. BOOLEAN DaclDefaulted;
  220. ACL_SIZE_INFORMATION AclSize;
  221. //
  222. // Get the Discretionary ACL (DACL) for the user
  223. //
  224. Status = SamQuerySecurityObject(
  225. UserHandle,
  226. DACL_SECURITY_INFORMATION,
  227. &SecurityDescriptor );
  228. if ( ! NT_SUCCESS( Status ) ) {
  229. IF_DEBUG( UAS_DEBUG_USER ) {
  230. NetpKdPrint((
  231. "UserpGetDacl: SamQuerySecurityObject returns %lX\n",
  232. Status ));
  233. }
  234. NetStatus = NetpNtStatusToApiStatus( Status );
  235. goto Cleanup;
  236. }
  237. Status = RtlGetDaclSecurityDescriptor(
  238. SecurityDescriptor,
  239. &DaclPresent,
  240. &Dacl,
  241. &DaclDefaulted );
  242. if ( ! NT_SUCCESS( Status ) ) {
  243. IF_DEBUG( UAS_DEBUG_USER ) {
  244. NetpKdPrint((
  245. "UserpGetDacl: RtlGetDaclSecurityObject returns %lX\n",
  246. Status ));
  247. }
  248. NetStatus = NERR_InternalError;
  249. goto Cleanup;
  250. }
  251. //
  252. // If there is no DACL, simply tell the caller
  253. //
  254. if ( !DaclPresent || Dacl == NULL ) {
  255. NetStatus = NERR_Success;
  256. *UserDacl = NULL;
  257. if ( UserDaclSize != NULL ) {
  258. *UserDaclSize = 0;
  259. }
  260. goto Cleanup;
  261. }
  262. //
  263. // Determine the size of the DACL so we can copy it
  264. //
  265. Status = RtlQueryInformationAcl(
  266. Dacl,
  267. &AclSize,
  268. sizeof(AclSize),
  269. AclSizeInformation );
  270. if ( ! NT_SUCCESS( Status ) ) {
  271. IF_DEBUG( UAS_DEBUG_USER ) {
  272. NetpKdPrint((
  273. "UserpGetDacl: RtlQueryInformationAcl returns %lX\n",
  274. Status ));
  275. }
  276. NetStatus = NERR_InternalError;
  277. goto Cleanup;
  278. }
  279. //
  280. // Copy the DACL to an allocated buffer.
  281. //
  282. *UserDacl = NetpMemoryAllocate( AclSize.AclBytesInUse );
  283. if ( *UserDacl == NULL ) {
  284. NetStatus = ERROR_NOT_ENOUGH_MEMORY;
  285. goto Cleanup;
  286. }
  287. NetpMoveMemory( *UserDacl, Dacl, AclSize.AclBytesInUse );
  288. if ( UserDaclSize != NULL ) {
  289. *UserDaclSize = AclSize.AclBytesInUse;
  290. }
  291. NetStatus = NERR_Success;
  292. //
  293. // Cleanup
  294. //
  295. Cleanup:
  296. if ( SecurityDescriptor != NULL ) {
  297. Status = SamFreeMemory( SecurityDescriptor );
  298. NetpAssert( NT_SUCCESS(Status) );
  299. }
  300. return NetStatus;
  301. }
  302. NET_API_STATUS
  303. UserpSetDacl(
  304. IN SAM_HANDLE UserHandle,
  305. IN PACL Dacl
  306. )
  307. /*++
  308. Routine Description:
  309. Set the specified Dacl on the specified SAM user record.
  310. Arguments:
  311. UserHandle - A handle to the user to modify.
  312. Dacl - The DACL to set on the user.
  313. Return Value:
  314. Status code.
  315. --*/
  316. {
  317. NTSTATUS Status;
  318. PUCHAR SecurityDescriptor[SECURITY_DESCRIPTOR_MIN_LENGTH];
  319. //
  320. // Initialize a security descriptor to contain a pointer to the
  321. // DACL.
  322. //
  323. Status = RtlCreateSecurityDescriptor(
  324. SecurityDescriptor,
  325. SECURITY_DESCRIPTOR_REVISION );
  326. if (!NT_SUCCESS(Status) ) {
  327. IF_DEBUG( UAS_DEBUG_USER ) {
  328. NetpKdPrint((
  329. "UserpSetDacl: RtlCreateSecurityDescriptor rets %lX\n",
  330. Status ));
  331. }
  332. return NetpNtStatusToApiStatus( Status );
  333. }
  334. Status = RtlSetDaclSecurityDescriptor(
  335. (PSECURITY_DESCRIPTOR) SecurityDescriptor,
  336. (BOOLEAN) TRUE, // Dacl is present
  337. Dacl,
  338. (BOOLEAN) FALSE ); // Dacl wasn't defaulted
  339. if (!NT_SUCCESS(Status) ) {
  340. IF_DEBUG( UAS_DEBUG_USER ) {
  341. NetpKdPrint((
  342. "UserpSetDacl: RtlSetDaclSecurityDescriptor rets %lX\n",
  343. Status ));
  344. }
  345. return NetpNtStatusToApiStatus( Status );
  346. }
  347. //
  348. // Set this new security descriptor on the user
  349. //
  350. Status = SamSetSecurityObject(
  351. UserHandle,
  352. DACL_SECURITY_INFORMATION,
  353. SecurityDescriptor );
  354. if ( !NT_SUCCESS(Status) ) {
  355. IF_DEBUG( UAS_DEBUG_USER ) {
  356. NetpKdPrint(( "NetUserAdd: SamSetSecurityObject rets %lX\n",
  357. Status ));
  358. }
  359. return NetpNtStatusToApiStatus( Status );
  360. }
  361. return NERR_Success;
  362. }
  363. NET_API_STATUS
  364. UserpOpenUser(
  365. IN SAM_HANDLE DomainHandle,
  366. IN ACCESS_MASK DesiredAccess,
  367. IN LPCWSTR UserName,
  368. OUT PSAM_HANDLE UserHandle OPTIONAL,
  369. OUT PULONG RelativeId OPTIONAL
  370. )
  371. /*++
  372. Routine Description:
  373. Open a Sam User by Name
  374. Arguments:
  375. DomainHandle - Supplies the Domain Handle.
  376. DesiredAccess - Supplies access mask indicating desired access to user.
  377. UserName - User name of the user.
  378. UserHandle - Returns a handle to the user. If NULL, user is not
  379. actually opened (merely the relative ID is returned).
  380. RelativeId - Returns the relative ID of the user. If NULL the relative
  381. Id is not returned.
  382. Return Value:
  383. Error code for the operation.
  384. --*/
  385. {
  386. NTSTATUS Status;
  387. NET_API_STATUS NetStatus;
  388. //
  389. // Variables for converting names to relative IDs
  390. //
  391. UNICODE_STRING NameString;
  392. PSID_NAME_USE NameUse = NULL;
  393. PULONG LocalRelativeId = NULL;
  394. //
  395. // Convert user name to relative ID.
  396. //
  397. RtlInitUnicodeString( &NameString, UserName );
  398. Status = SamLookupNamesInDomain( DomainHandle,
  399. 1,
  400. &NameString,
  401. &LocalRelativeId,
  402. &NameUse );
  403. if ( !NT_SUCCESS(Status) ) {
  404. if ( Status == STATUS_NONE_MAPPED ) {
  405. NetStatus = NERR_UserNotFound;
  406. } else {
  407. NetStatus = NetpNtStatusToApiStatus( Status );
  408. }
  409. goto Cleanup;
  410. }
  411. if ( *NameUse != SidTypeUser ) {
  412. NetStatus = NERR_UserNotFound;
  413. goto Cleanup;
  414. }
  415. //
  416. // Open the user
  417. //
  418. if ( UserHandle != NULL ) {
  419. Status = SamOpenUser( DomainHandle,
  420. DesiredAccess,
  421. *LocalRelativeId,
  422. UserHandle);
  423. if ( !NT_SUCCESS(Status) ) {
  424. NetStatus = NetpNtStatusToApiStatus( Status );
  425. goto Cleanup;
  426. }
  427. }
  428. //
  429. // Return the relative Id if it's wanted.
  430. //
  431. if ( RelativeId != NULL ) {
  432. *RelativeId = *LocalRelativeId;
  433. }
  434. NetStatus = NERR_Success;
  435. //
  436. // Cleanup
  437. //
  438. Cleanup:
  439. if ( LocalRelativeId != NULL ) {
  440. Status = SamFreeMemory( LocalRelativeId );
  441. NetpAssert( NT_SUCCESS(Status) );
  442. }
  443. if ( NameUse != NULL ) {
  444. Status = SamFreeMemory( NameUse );
  445. NetpAssert( NT_SUCCESS(Status) );
  446. }
  447. IF_DEBUG( UAS_DEBUG_USER ) {
  448. NetpKdPrint(( "UserpOpenUser: %wZ: returns %ld\n",
  449. &NameString, NetStatus ));
  450. }
  451. return NetStatus;
  452. } // UserpOpenUser
  453. VOID
  454. UserpRelocationRoutine(
  455. IN DWORD Level,
  456. IN OUT PBUFFER_DESCRIPTOR BufferDescriptor,
  457. IN PTRDIFF_T Offset
  458. )
  459. /*++
  460. Routine Description:
  461. Routine to relocate the pointers from the fixed portion of an enumeration
  462. buffer to the string portion of an enumeration buffer. It is called
  463. as a callback routine from NetpAllocateEnumBuffer when it re-allocates
  464. such a buffer. NetpAllocateEnumBuffer copied the fixed portion and
  465. string portion into the new buffer before calling this routine.
  466. Arguments:
  467. Level - Level of information in the buffer.
  468. BufferDescriptor - Description of the new buffer.
  469. Offset - Offset to add to each pointer in the fixed portion.
  470. Return Value:
  471. Returns the error code for the operation.
  472. --*/
  473. {
  474. DWORD EntryCount;
  475. DWORD EntryNumber;
  476. DWORD FixedSize;
  477. IF_DEBUG( UAS_DEBUG_USER ) {
  478. NetpKdPrint(( "UserpRelocationRoutine: entering\n" ));
  479. }
  480. //
  481. // Compute the number of fixed size entries
  482. //
  483. switch (Level) {
  484. case 0:
  485. FixedSize = sizeof(USER_INFO_0);
  486. break;
  487. case 1:
  488. FixedSize = sizeof(USER_INFO_1);
  489. break;
  490. case 2:
  491. FixedSize = sizeof(USER_INFO_2);
  492. break;
  493. case 3:
  494. FixedSize = sizeof(USER_INFO_3);
  495. break;
  496. case 10:
  497. FixedSize = sizeof(USER_INFO_10);
  498. break;
  499. case 11:
  500. FixedSize = sizeof(USER_INFO_11);
  501. break;
  502. case 20:
  503. FixedSize = sizeof(USER_INFO_20);
  504. break;
  505. default:
  506. NetpAssert( FALSE );
  507. return;
  508. }
  509. EntryCount =
  510. (DWORD)((BufferDescriptor->FixedDataEnd - BufferDescriptor->Buffer)) /
  511. FixedSize;
  512. //
  513. // Loop relocating each field in each fixed size structure
  514. //
  515. #define DO_ONE( _type, _fieldname ) \
  516. RELOCATE_ONE( ((_type)TheStruct)->_fieldname, Offset)
  517. for ( EntryNumber=0; EntryNumber<EntryCount; EntryNumber++ ) {
  518. LPBYTE TheStruct = BufferDescriptor->Buffer + FixedSize * EntryNumber;
  519. switch ( Level ) {
  520. case 3:
  521. DO_ONE( PUSER_INFO_3, usri3_profile );
  522. DO_ONE( PUSER_INFO_3, usri3_home_dir_drive );
  523. /* Drop through to case 2 */
  524. case 2:
  525. DO_ONE( PUSER_INFO_2, usri2_full_name );
  526. DO_ONE( PUSER_INFO_2, usri2_usr_comment );
  527. DO_ONE( PUSER_INFO_2, usri2_parms );
  528. DO_ONE( PUSER_INFO_2, usri2_workstations );
  529. DO_ONE( PUSER_INFO_2, usri2_logon_hours );
  530. DO_ONE( PUSER_INFO_2, usri2_logon_server );
  531. /* Drop through to case 1 */
  532. case 1:
  533. DO_ONE( PUSER_INFO_1, usri1_home_dir );
  534. DO_ONE( PUSER_INFO_1, usri1_comment );
  535. DO_ONE( PUSER_INFO_1, usri1_script_path );
  536. /* Drop through to case 0 */
  537. case 0:
  538. DO_ONE( PUSER_INFO_0, usri0_name );
  539. break;
  540. case 11:
  541. DO_ONE( PUSER_INFO_11, usri11_home_dir );
  542. DO_ONE( PUSER_INFO_11, usri11_parms );
  543. DO_ONE( PUSER_INFO_11, usri11_logon_server );
  544. DO_ONE( PUSER_INFO_11, usri11_workstations );
  545. DO_ONE( PUSER_INFO_11, usri11_home_dir );
  546. DO_ONE( PUSER_INFO_11, usri11_logon_hours );
  547. /* Drop through to case 10 */
  548. case 10:
  549. DO_ONE( PUSER_INFO_10, usri10_name );
  550. DO_ONE( PUSER_INFO_10, usri10_comment );
  551. DO_ONE( PUSER_INFO_10, usri10_usr_comment );
  552. DO_ONE( PUSER_INFO_10, usri10_full_name );
  553. break;
  554. case 20:
  555. DO_ONE( PUSER_INFO_20, usri20_name );
  556. DO_ONE( PUSER_INFO_20, usri20_full_name );
  557. DO_ONE( PUSER_INFO_20, usri20_comment );
  558. break;
  559. default:
  560. NetpAssert( FALSE );
  561. return;
  562. }
  563. }
  564. return;
  565. } // UserpRelocationRoutine
  566. NET_API_STATUS
  567. UserpGetInfo(
  568. IN SAM_HANDLE DomainHandle,
  569. IN PSID DomainId,
  570. IN SAM_HANDLE BuiltinDomainHandle OPTIONAL,
  571. IN UNICODE_STRING UserName,
  572. IN ULONG UserRelativeId,
  573. IN DWORD Level,
  574. IN DWORD PrefMaxLen,
  575. IN OUT PBUFFER_DESCRIPTOR BufferDescriptor,
  576. IN BOOL IsGet,
  577. IN DWORD SamFilter
  578. )
  579. /*++
  580. Routine Description:
  581. Get the information on one user and fill that information into an
  582. allocated buffer.
  583. Arguments:
  584. DomainHandle - Domain Handle for the Account domain.
  585. DomainId - Domain Id corresponding to DomainHandle
  586. BuiltinDomainHandle - Domain Handle for the builtin domain. Need only be
  587. specified for info level 1, 2, 3, and 11.
  588. UserName - User name of the user to query.
  589. UserRelativeId - Relative ID of the user to query.
  590. Level - Level of information required. level 0, 1, 2, 3, 10, 11 and 20
  591. are valid.
  592. PrefMaxLen - Callers prefered maximum length
  593. BufferDescriptor - Points to a structure which describes the allocated
  594. buffer. On the first call, pass in BufferDescriptor->Buffer set
  595. to NULL. On subsequent calls (in the 'enum' case), pass in the
  596. structure just as it was passed back on a previous call.
  597. The caller must deallocate the BufferDescriptor->Buffer using
  598. MIDL_user_free if it is non-null.
  599. IsGet - True iff this is a 'get' call and not an 'enum' call.
  600. Return Value:
  601. Error code for the operation.
  602. If this is an Enum call, the status can be ERROR_MORE_DATA implying that
  603. the Buffer has grown to PrefMaxLen and that this much data should
  604. be returned to the caller.
  605. --*/
  606. {
  607. NET_API_STATUS NetStatus;
  608. NTSTATUS Status;
  609. SAM_HANDLE UserHandle = NULL;
  610. USER_ALL_INFORMATION *UserAll = NULL;
  611. UNICODE_STRING LogonServer;
  612. ACCESS_MASK DesiredAccess;
  613. ULONG RequiredFields;
  614. PACL UserDacl = NULL;
  615. ULONG RidToReturn = UserRelativeId;
  616. DWORD Size; // The size of the info returned for this user
  617. DWORD FixedSize; // The size of the info returned for this user
  618. LPBYTE NewStruct; // Pointer to fixed portion of new structure
  619. PSID UserSid = NULL; // sid of the user
  620. DWORD password_expired;
  621. //
  622. // Variables describes membership in the special groups.
  623. //
  624. DWORD Priv;
  625. DWORD AuthFlags;
  626. //
  627. // Validate Level parameter and remember the fixed size of each returned
  628. // array entry.
  629. //
  630. RtlInitUnicodeString( &LogonServer, L"\\\\*" );
  631. switch (Level) {
  632. case 0:
  633. FixedSize = sizeof(USER_INFO_0);
  634. DesiredAccess = 0;
  635. RequiredFields = 0;
  636. break;
  637. case 1:
  638. FixedSize = sizeof(USER_INFO_1);
  639. DesiredAccess = USER_LIST_GROUPS | USER_READ_GENERAL |
  640. USER_READ_LOGON | USER_READ_ACCOUNT | READ_CONTROL;
  641. RequiredFields = USER_ALL_USERNAME |
  642. USER_ALL_PASSWORDLASTSET |
  643. USER_ALL_HOMEDIRECTORY |
  644. USER_ALL_ADMINCOMMENT |
  645. USER_ALL_USERACCOUNTCONTROL |
  646. USER_ALL_SCRIPTPATH ;
  647. break;
  648. case 2:
  649. FixedSize = sizeof(USER_INFO_2);
  650. DesiredAccess = USER_LIST_GROUPS | USER_READ_GENERAL |
  651. USER_READ_LOGON | USER_READ_ACCOUNT | READ_CONTROL |
  652. USER_READ_PREFERENCES;
  653. RequiredFields = USER_ALL_FULLNAME |
  654. USER_ALL_USERCOMMENT |
  655. USER_ALL_PARAMETERS |
  656. USER_ALL_WORKSTATIONS |
  657. USER_ALL_LASTLOGON |
  658. USER_ALL_LASTLOGOFF |
  659. USER_ALL_ACCOUNTEXPIRES |
  660. USER_ALL_LOGONHOURS |
  661. USER_ALL_BADPASSWORDCOUNT |
  662. USER_ALL_LOGONCOUNT |
  663. USER_ALL_COUNTRYCODE |
  664. USER_ALL_CODEPAGE |
  665. USER_ALL_USERNAME |
  666. USER_ALL_PASSWORDLASTSET |
  667. USER_ALL_HOMEDIRECTORY |
  668. USER_ALL_ADMINCOMMENT |
  669. USER_ALL_USERACCOUNTCONTROL |
  670. USER_ALL_SCRIPTPATH ;
  671. break;
  672. case 3:
  673. FixedSize = sizeof(USER_INFO_3);
  674. DesiredAccess = USER_LIST_GROUPS | USER_READ_GENERAL |
  675. USER_READ_LOGON | USER_READ_ACCOUNT | READ_CONTROL |
  676. USER_READ_PREFERENCES;
  677. RequiredFields = USER_ALL_USERID |
  678. USER_ALL_PRIMARYGROUPID |
  679. USER_ALL_PROFILEPATH |
  680. USER_ALL_HOMEDIRECTORYDRIVE |
  681. USER_ALL_PASSWORDMUSTCHANGE |
  682. USER_ALL_FULLNAME |
  683. USER_ALL_USERCOMMENT |
  684. USER_ALL_PARAMETERS |
  685. USER_ALL_WORKSTATIONS |
  686. USER_ALL_LASTLOGON |
  687. USER_ALL_LASTLOGOFF |
  688. USER_ALL_ACCOUNTEXPIRES |
  689. USER_ALL_LOGONHOURS |
  690. USER_ALL_BADPASSWORDCOUNT |
  691. USER_ALL_LOGONCOUNT |
  692. USER_ALL_COUNTRYCODE |
  693. USER_ALL_CODEPAGE |
  694. USER_ALL_USERNAME |
  695. USER_ALL_PASSWORDLASTSET |
  696. USER_ALL_HOMEDIRECTORY |
  697. USER_ALL_ADMINCOMMENT |
  698. USER_ALL_USERACCOUNTCONTROL |
  699. USER_ALL_SCRIPTPATH ;
  700. break;
  701. case 4:
  702. FixedSize = sizeof(USER_INFO_4);
  703. DesiredAccess = USER_LIST_GROUPS | USER_READ_GENERAL |
  704. USER_READ_LOGON | USER_READ_ACCOUNT | READ_CONTROL |
  705. USER_READ_PREFERENCES;
  706. RequiredFields = USER_ALL_USERID |
  707. USER_ALL_PRIMARYGROUPID |
  708. USER_ALL_PROFILEPATH |
  709. USER_ALL_HOMEDIRECTORYDRIVE |
  710. USER_ALL_PASSWORDMUSTCHANGE |
  711. USER_ALL_FULLNAME |
  712. USER_ALL_USERCOMMENT |
  713. USER_ALL_PARAMETERS |
  714. USER_ALL_WORKSTATIONS |
  715. USER_ALL_LASTLOGON |
  716. USER_ALL_LASTLOGOFF |
  717. USER_ALL_ACCOUNTEXPIRES |
  718. USER_ALL_LOGONHOURS |
  719. USER_ALL_BADPASSWORDCOUNT |
  720. USER_ALL_LOGONCOUNT |
  721. USER_ALL_COUNTRYCODE |
  722. USER_ALL_CODEPAGE |
  723. USER_ALL_USERNAME |
  724. USER_ALL_PASSWORDLASTSET |
  725. USER_ALL_HOMEDIRECTORY |
  726. USER_ALL_ADMINCOMMENT |
  727. USER_ALL_USERACCOUNTCONTROL |
  728. USER_ALL_SCRIPTPATH ;
  729. break;
  730. case 10:
  731. FixedSize = sizeof(USER_INFO_10);
  732. DesiredAccess = USER_READ_GENERAL;
  733. RequiredFields = USER_ALL_USERNAME |
  734. USER_ALL_ADMINCOMMENT |
  735. USER_ALL_USERCOMMENT |
  736. USER_ALL_FULLNAME ;
  737. break;
  738. case 11:
  739. FixedSize = sizeof(USER_INFO_11);
  740. DesiredAccess = USER_LIST_GROUPS | USER_READ_GENERAL | USER_READ_LOGON |
  741. USER_READ_ACCOUNT | USER_READ_PREFERENCES;
  742. RequiredFields = USER_ALL_USERNAME |
  743. USER_ALL_ADMINCOMMENT |
  744. USER_ALL_USERCOMMENT |
  745. USER_ALL_FULLNAME |
  746. USER_ALL_PASSWORDLASTSET |
  747. USER_ALL_HOMEDIRECTORY |
  748. USER_ALL_PARAMETERS |
  749. USER_ALL_LASTLOGON |
  750. USER_ALL_LASTLOGOFF |
  751. USER_ALL_BADPASSWORDCOUNT |
  752. USER_ALL_LOGONCOUNT |
  753. USER_ALL_COUNTRYCODE |
  754. USER_ALL_WORKSTATIONS |
  755. USER_ALL_LOGONHOURS |
  756. USER_ALL_CODEPAGE ;
  757. break;
  758. case 20:
  759. FixedSize = sizeof(USER_INFO_20);
  760. DesiredAccess = USER_READ_GENERAL | USER_READ_ACCOUNT | READ_CONTROL;
  761. RequiredFields = USER_ALL_USERNAME |
  762. USER_ALL_FULLNAME |
  763. USER_ALL_ADMINCOMMENT |
  764. USER_ALL_USERACCOUNTCONTROL;
  765. break;
  766. case 23:
  767. FixedSize = sizeof(USER_INFO_23);
  768. DesiredAccess = USER_READ_GENERAL | USER_READ_ACCOUNT | READ_CONTROL;
  769. RequiredFields = USER_ALL_USERNAME |
  770. USER_ALL_FULLNAME |
  771. USER_ALL_ADMINCOMMENT |
  772. USER_ALL_USERACCOUNTCONTROL;
  773. break;
  774. default:
  775. NetStatus = ERROR_INVALID_LEVEL;
  776. goto Cleanup;
  777. }
  778. //
  779. // Validate that the level is supported
  780. //
  781. if ( Level == 3 || Level == 20 ) {
  782. ULONG Mode;
  783. Status = SamGetCompatibilityMode(DomainHandle, &Mode);
  784. if (!NT_SUCCESS(Status)) {
  785. NetStatus = NetpNtStatusToApiStatus( Status );
  786. goto Cleanup;
  787. }
  788. switch (Mode) {
  789. case SAM_SID_COMPATIBILITY_STRICT:
  790. NetStatus = ERROR_NOT_SUPPORTED;
  791. goto Cleanup;
  792. case SAM_SID_COMPATIBILITY_LAX:
  793. RidToReturn = 0;
  794. break;
  795. }
  796. }
  797. //
  798. // if we need to filter this account then query
  799. // USER_ALL_USERACCOUNTCONTROL also.
  800. //
  801. if( SamFilter ) {
  802. DesiredAccess |= USER_READ_ACCOUNT;
  803. RequiredFields |= USER_ALL_USERACCOUNTCONTROL;
  804. }
  805. //
  806. // Open the User account if need be
  807. //
  808. if ( DesiredAccess != 0 ) {
  809. Status = SamOpenUser( DomainHandle,
  810. DesiredAccess,
  811. UserRelativeId,
  812. &UserHandle);
  813. if ( !NT_SUCCESS(Status) ) {
  814. IF_DEBUG( UAS_DEBUG_USER ) {
  815. NetpKdPrint(( "UserpGetInfo: SamOpenUser returns %lX\n",
  816. Status ));
  817. }
  818. NetStatus = NetpNtStatusToApiStatus( Status );
  819. goto Cleanup;
  820. }
  821. }
  822. //
  823. // Get all the information we need about the user
  824. //
  825. if ( RequiredFields != 0 ) {
  826. Status = SamQueryInformationUser( UserHandle,
  827. UserAllInformation,
  828. (PVOID *)&UserAll );
  829. if ( ! NT_SUCCESS( Status ) ) {
  830. IF_DEBUG( UAS_DEBUG_USER ) {
  831. NetpKdPrint((
  832. "UserpGetInfo: SamQueryInformationUser returns %lX\n",
  833. Status ));
  834. }
  835. NetStatus = NetpNtStatusToApiStatus( Status );
  836. goto Cleanup;
  837. }
  838. if ( (UserAll->WhichFields & RequiredFields) != RequiredFields ) {
  839. #if DBG
  840. NetpKdPrint(( "UserpGetInfo: WhichFields: %lX RequireFields: %lX\n",
  841. UserAll->WhichFields,
  842. RequiredFields ));
  843. #endif // DBG
  844. NetStatus = ERROR_ACCESS_DENIED;
  845. goto Cleanup;
  846. }
  847. //
  848. // check the account type to filter this account.
  849. //
  850. if( (SamFilter != 0) &&
  851. ((UserAll->UserAccountControl & SamFilter) == 0)) {
  852. IF_DEBUG( UAS_DEBUG_USER ) {
  853. NetpKdPrint(( "UserpGetInfo: %wZ is skipped \n", &UserName ));
  854. }
  855. NetStatus = NERR_Success ;
  856. goto Cleanup;
  857. }
  858. }
  859. //
  860. // Level 1, 2 and 3 use the User's DACL to figure out the usriX_flags field.
  861. //
  862. if ((Level == 1) ||
  863. (Level == 2) ||
  864. (Level == 3) ||
  865. (Level == 4) ||
  866. (Level == 20) ||
  867. (Level == 23) ) {
  868. //
  869. // Get the DACL for this user.
  870. //
  871. NetStatus = UserpGetDacl( UserHandle, &UserDacl, NULL );
  872. if ( NetStatus != NERR_Success ) {
  873. IF_DEBUG( UAS_DEBUG_USER ) {
  874. NetpKdPrint((
  875. "UserpGetInfo: UserpGetDacl returns %ld\n",
  876. NetStatus ));
  877. }
  878. goto Cleanup;
  879. }
  880. }
  881. //
  882. // Determine the Priv and AuthFlags
  883. //
  884. if (Level == 1 || Level == 2 || Level == 3 || Level == 4 || Level == 11 ) {
  885. //
  886. //
  887. NetStatus = UserpGetUserPriv(
  888. BuiltinDomainHandle,
  889. UserHandle,
  890. UserRelativeId,
  891. DomainId,
  892. &Priv,
  893. &AuthFlags );
  894. if ( NetStatus != NERR_Success ) {
  895. goto Cleanup;
  896. }
  897. }
  898. //
  899. // Construct the user's SID if necessary
  900. //
  901. if ( (Level == 4)
  902. || (Level == 23) ) {
  903. NetStatus = NetpSamRidToSid(UserHandle,
  904. UserRelativeId,
  905. &UserSid);
  906. if ( NetStatus != NERR_Success ) {
  907. goto Cleanup;
  908. }
  909. }
  910. //
  911. // Determine if the account has expired
  912. //
  913. if ( (Level == 3)
  914. || (Level == 4) ) {
  915. //
  916. // If the password is currently expired,
  917. // indicate so.
  918. //
  919. LARGE_INTEGER CurrentTime;
  920. (VOID) NtQuerySystemTime( &CurrentTime );
  921. if ( CurrentTime.QuadPart
  922. >= UserAll->PasswordMustChange.QuadPart ) {
  923. password_expired = TRUE;
  924. } else {
  925. password_expired = FALSE;
  926. }
  927. }
  928. //
  929. // Determine the total size of the return information.
  930. //
  931. Size = FixedSize;
  932. switch (Level) {
  933. case 0:
  934. Size += UserName.Length + sizeof(WCHAR);
  935. break;
  936. case 4:
  937. NetpAssert( NULL != UserSid );
  938. Size += RtlLengthSid(UserSid);
  939. /* Drop through to case 3 */
  940. case 3:
  941. Size += UserAll->ProfilePath.Length + sizeof(WCHAR) +
  942. UserAll->HomeDirectoryDrive.Length + sizeof(WCHAR);
  943. /* Drop through to case 2 */
  944. case 2:
  945. Size += UserAll->FullName.Length + sizeof(WCHAR) +
  946. UserAll->UserComment.Length + sizeof(WCHAR) +
  947. UserAll->Parameters.Length + sizeof(WCHAR) +
  948. UserAll->WorkStations.Length + sizeof(WCHAR) +
  949. LogonServer.Length + sizeof(WCHAR) +
  950. UserpSizeOfLogonHours( UserAll->LogonHours.UnitsPerWeek );
  951. /* Drop through to case 1 */
  952. case 1:
  953. Size += UserAll->UserName.Length + sizeof(WCHAR) +
  954. UserAll->HomeDirectory.Length + sizeof(WCHAR) +
  955. UserAll->AdminComment.Length + sizeof(WCHAR) +
  956. UserAll->ScriptPath.Length + sizeof(WCHAR);
  957. break;
  958. case 10:
  959. Size += UserAll->UserName.Length + sizeof(WCHAR) +
  960. UserAll->AdminComment.Length + sizeof(WCHAR) +
  961. UserAll->UserComment.Length + sizeof(WCHAR) +
  962. UserAll->FullName.Length + sizeof(WCHAR);
  963. break;
  964. case 11:
  965. Size += UserAll->UserName.Length + sizeof(WCHAR) +
  966. UserAll->AdminComment.Length + sizeof(WCHAR) +
  967. UserAll->UserComment.Length + sizeof(WCHAR) +
  968. UserAll->FullName.Length + sizeof(WCHAR) +
  969. UserAll->HomeDirectory.Length + sizeof(WCHAR) +
  970. UserAll->Parameters.Length + sizeof(WCHAR) +
  971. UserAll->WorkStations.Length + sizeof(WCHAR) +
  972. LogonServer.Length + sizeof(WCHAR) +
  973. UserpSizeOfLogonHours( UserAll->LogonHours.UnitsPerWeek );
  974. break;
  975. case 23:
  976. NetpAssert( NULL != UserSid );
  977. Size += RtlLengthSid(UserSid);
  978. /* Drop through to case 20 */
  979. case 20:
  980. Size += UserAll->UserName.Length + sizeof(WCHAR) +
  981. UserAll->FullName.Length + sizeof(WCHAR) +
  982. UserAll->AdminComment.Length + sizeof(WCHAR);
  983. break;
  984. default:
  985. NetStatus = ERROR_INVALID_LEVEL;
  986. goto Cleanup;
  987. }
  988. //
  989. // Ensure there is buffer space for this information.
  990. //
  991. Size = ROUND_UP_COUNT( Size, ALIGN_DWORD );
  992. NetStatus = NetpAllocateEnumBuffer(
  993. BufferDescriptor,
  994. IsGet,
  995. PrefMaxLen,
  996. Size,
  997. UserpRelocationRoutine,
  998. Level );
  999. if (NetStatus != NERR_Success) {
  1000. //
  1001. // NetpAllocateEnumBuffer returns ERROR_MORE_DATA if this
  1002. // entry doesn't fit into the buffer.
  1003. //
  1004. IF_DEBUG( UAS_DEBUG_USER ) {
  1005. NetpKdPrint(( "UserpGetInfo: NetpAllocateEnumBuffer returns %ld\n",
  1006. NetStatus ));
  1007. }
  1008. goto Cleanup;
  1009. }
  1010. //
  1011. // Define macros to make copying bytes and zero terminated strings less
  1012. // repetitive.
  1013. //
  1014. #define COPY_BYTES( _type, _fieldname, _inptr, _length, _align ) \
  1015. if ( !NetpCopyDataToBuffer( \
  1016. (_inptr), \
  1017. (_length), \
  1018. BufferDescriptor->FixedDataEnd, \
  1019. &BufferDescriptor->EndOfVariableData, \
  1020. (LPBYTE*)&((_type)NewStruct)->_fieldname, \
  1021. _align ) ){ \
  1022. \
  1023. NetStatus = NERR_InternalError; \
  1024. IF_DEBUG( UAS_DEBUG_USER ) { \
  1025. NetpKdPrint(( "UserpGetInfo: NetpCopyData returns %ld\n", \
  1026. NetStatus )); \
  1027. } \
  1028. goto Cleanup; \
  1029. }
  1030. #define COPY_STRING( _type, _fieldname, _string ) \
  1031. if ( !NetpCopyStringToBuffer( \
  1032. (_string).Buffer, \
  1033. (_string).Length/sizeof(WCHAR), \
  1034. BufferDescriptor->FixedDataEnd, \
  1035. (LPWSTR *)&BufferDescriptor->EndOfVariableData, \
  1036. &((_type)NewStruct)->_fieldname) ) { \
  1037. \
  1038. NetStatus = NERR_InternalError; \
  1039. IF_DEBUG( UAS_DEBUG_USER ) { \
  1040. NetpKdPrint(( "UserpGetInfo: NetpCopyString returns %ld\n", \
  1041. NetStatus )); \
  1042. } \
  1043. goto Cleanup; \
  1044. }
  1045. //
  1046. // Place this entry into the return buffer.
  1047. //
  1048. // Fill in the information. The array of fixed entries is
  1049. // placed at the beginning of the allocated buffer. The strings
  1050. // pointed to by these fixed entries are allocated starting at
  1051. // the end of the allocate buffer.
  1052. //
  1053. NewStruct = BufferDescriptor->FixedDataEnd;
  1054. BufferDescriptor->FixedDataEnd += FixedSize;
  1055. switch ( Level ) {
  1056. case 4:
  1057. {
  1058. //
  1059. // USER_INFO_2, below, is a subset of USER_INFO_4, so fill in our
  1060. // structures here and then fall through
  1061. //
  1062. PUSER_INFO_4 usri4 = (PUSER_INFO_4) NewStruct;
  1063. NetpAssert( NULL != UserSid );
  1064. COPY_BYTES( PUSER_INFO_4,
  1065. usri4_user_sid,
  1066. UserSid,
  1067. RtlLengthSid(UserSid),
  1068. ALIGN_DWORD );
  1069. usri4->usri4_primary_group_id = UserAll->PrimaryGroupId;
  1070. COPY_STRING( PUSER_INFO_4, usri4_profile, UserAll->ProfilePath );
  1071. COPY_STRING( PUSER_INFO_4,
  1072. usri4_home_dir_drive,
  1073. UserAll->HomeDirectoryDrive );
  1074. NetpAssert( (password_expired == TRUE)
  1075. || (password_expired == FALSE));
  1076. usri4->usri4_password_expired = password_expired;
  1077. //
  1078. // Fall through the level 3
  1079. //
  1080. }
  1081. case 3:
  1082. {
  1083. //
  1084. // since _USER_INFO_2 structure is subset of _USER_INFO_3,
  1085. // full-up the _USER_INFO_3 only fields first and then fall
  1086. // through for the common fields.
  1087. //
  1088. if ( Level == 3 ) {
  1089. PUSER_INFO_3 usri3 = (PUSER_INFO_3) NewStruct;
  1090. NetpAssert( UserRelativeId == UserAll->UserId );
  1091. usri3->usri3_user_id = RidToReturn;
  1092. usri3->usri3_primary_group_id = UserAll->PrimaryGroupId;
  1093. COPY_STRING( PUSER_INFO_3, usri3_profile, UserAll->ProfilePath );
  1094. COPY_STRING( PUSER_INFO_3,
  1095. usri3_home_dir_drive,
  1096. UserAll->HomeDirectoryDrive );
  1097. NetpAssert( (password_expired == TRUE)
  1098. || (password_expired == FALSE));
  1099. usri3->usri3_password_expired = password_expired;
  1100. }
  1101. }
  1102. //
  1103. // FALL THROUGH FOR OTHER _USER_INFO_3 FIELDS
  1104. //
  1105. case 2:
  1106. {
  1107. PUSER_INFO_2 usri2 = (PUSER_INFO_2) NewStruct;
  1108. usri2->usri2_auth_flags = AuthFlags;
  1109. COPY_STRING( PUSER_INFO_2,
  1110. usri2_full_name,
  1111. UserAll->FullName );
  1112. COPY_STRING( PUSER_INFO_2,
  1113. usri2_usr_comment,
  1114. UserAll->UserComment);
  1115. COPY_STRING( PUSER_INFO_2,
  1116. usri2_parms,
  1117. UserAll->Parameters );
  1118. COPY_STRING( PUSER_INFO_2,
  1119. usri2_workstations,
  1120. UserAll->WorkStations);
  1121. if ( !RtlTimeToSecondsSince1970( &UserAll->LastLogon,
  1122. &usri2->usri2_last_logon) ) {
  1123. usri2->usri2_last_logon = 0;
  1124. }
  1125. if ( !RtlTimeToSecondsSince1970( &UserAll->LastLogoff,
  1126. &usri2->usri2_last_logoff) ) {
  1127. usri2->usri2_last_logoff = 0;
  1128. }
  1129. if ( !RtlTimeToSecondsSince1970( &UserAll->AccountExpires,
  1130. &usri2->usri2_acct_expires) ) {
  1131. usri2->usri2_acct_expires = TIMEQ_FOREVER;
  1132. }
  1133. IF_DEBUG( UAS_DEBUG_USER ) {
  1134. NetpKdPrint(( "UserpGetInfo: Account Expries %lx %lx %lx\n",
  1135. UserAll->AccountExpires.HighPart,
  1136. UserAll->AccountExpires.LowPart,
  1137. usri2->usri2_acct_expires));
  1138. }
  1139. usri2->usri2_max_storage = USER_MAXSTORAGE_UNLIMITED;
  1140. usri2->usri2_units_per_week = UserAll->LogonHours.UnitsPerWeek;
  1141. IF_DEBUG( UAS_DEBUG_USER ) {
  1142. DWORD k;
  1143. NetpDbgDisplayDword( "UserpGetInfo: units_per_week",
  1144. usri2->usri2_units_per_week );
  1145. NetpKdPrint(( "UserpGetInfo: LogonHours %lx\n",
  1146. UserAll->LogonHours.LogonHours));
  1147. for ( k=0;
  1148. k<UserpSizeOfLogonHours(
  1149. UserAll->LogonHours.UnitsPerWeek);
  1150. k++ ) {
  1151. NetpKdPrint(( "%d ",
  1152. UserAll->LogonHours.LogonHours[k] ));
  1153. }
  1154. NetpKdPrint(( "\n" ));
  1155. }
  1156. COPY_BYTES( PUSER_INFO_2,
  1157. usri2_logon_hours,
  1158. UserAll->LogonHours.LogonHours,
  1159. UserpSizeOfLogonHours(
  1160. UserAll->LogonHours.UnitsPerWeek ),
  1161. sizeof(UCHAR) );
  1162. BufferDescriptor->EndOfVariableData =
  1163. ROUND_DOWN_POINTER( BufferDescriptor->EndOfVariableData,
  1164. ALIGN_WCHAR );
  1165. usri2->usri2_bad_pw_count = UserAll->BadPasswordCount;
  1166. usri2->usri2_num_logons = UserAll->LogonCount;
  1167. COPY_STRING( PUSER_INFO_2,
  1168. usri2_logon_server,
  1169. LogonServer );
  1170. usri2->usri2_country_code = UserAll->CountryCode;
  1171. usri2->usri2_code_page = UserAll->CodePage;
  1172. /* Drop through to case 1 */
  1173. }
  1174. case 1:
  1175. {
  1176. PUSER_INFO_1 usri1 = (PUSER_INFO_1) NewStruct;
  1177. COPY_STRING( PUSER_INFO_1, usri1_name, UserAll->UserName );
  1178. usri1->usri1_password = NULL;
  1179. usri1->usri1_password_age =
  1180. NetpGetElapsedSeconds( &UserAll->PasswordLastSet );
  1181. usri1->usri1_priv = Priv;
  1182. COPY_STRING( PUSER_INFO_1, usri1_home_dir, UserAll->HomeDirectory );
  1183. COPY_STRING( PUSER_INFO_1, usri1_comment, UserAll->AdminComment);
  1184. usri1->usri1_flags = NetpAccountControlToFlags(
  1185. UserAll->UserAccountControl,
  1186. UserDacl );
  1187. COPY_STRING( PUSER_INFO_1, usri1_script_path, UserAll->ScriptPath);
  1188. break;
  1189. }
  1190. case 0:
  1191. COPY_STRING( PUSER_INFO_0, usri0_name, UserName );
  1192. break;
  1193. case 10:
  1194. COPY_STRING( PUSER_INFO_10, usri10_name, UserAll->UserName );
  1195. COPY_STRING( PUSER_INFO_10, usri10_comment, UserAll->AdminComment );
  1196. COPY_STRING( PUSER_INFO_10, usri10_usr_comment, UserAll->UserComment );
  1197. COPY_STRING( PUSER_INFO_10, usri10_full_name, UserAll->FullName );
  1198. break;
  1199. case 11:
  1200. {
  1201. PUSER_INFO_11 usri11 = (PUSER_INFO_11) NewStruct;
  1202. COPY_STRING( PUSER_INFO_11, usri11_name, UserAll->UserName );
  1203. COPY_STRING( PUSER_INFO_11, usri11_comment, UserAll->AdminComment );
  1204. COPY_STRING(PUSER_INFO_11, usri11_usr_comment,UserAll->UserComment);
  1205. COPY_STRING( PUSER_INFO_11, usri11_full_name, UserAll->FullName );
  1206. usri11->usri11_priv = Priv;
  1207. usri11->usri11_auth_flags = AuthFlags;
  1208. usri11->usri11_password_age =
  1209. NetpGetElapsedSeconds( &UserAll->PasswordLastSet );
  1210. COPY_STRING(PUSER_INFO_11, usri11_home_dir, UserAll->HomeDirectory);
  1211. COPY_STRING( PUSER_INFO_11, usri11_parms, UserAll->Parameters );
  1212. if ( !RtlTimeToSecondsSince1970( &UserAll->LastLogon,
  1213. &usri11->usri11_last_logon) ) {
  1214. usri11->usri11_last_logon = 0;
  1215. }
  1216. if ( !RtlTimeToSecondsSince1970( &UserAll->LastLogoff,
  1217. &usri11->usri11_last_logoff) ) {
  1218. usri11->usri11_last_logoff = 0;
  1219. }
  1220. usri11->usri11_bad_pw_count = UserAll->BadPasswordCount;
  1221. usri11->usri11_num_logons = UserAll->LogonCount;
  1222. COPY_STRING( PUSER_INFO_11, usri11_logon_server, LogonServer );
  1223. usri11->usri11_country_code = UserAll->CountryCode;
  1224. COPY_STRING( PUSER_INFO_11,
  1225. usri11_workstations,
  1226. UserAll->WorkStations );
  1227. usri11->usri11_max_storage = USER_MAXSTORAGE_UNLIMITED;
  1228. usri11->usri11_units_per_week = UserAll->LogonHours.UnitsPerWeek;
  1229. COPY_BYTES( PUSER_INFO_11,
  1230. usri11_logon_hours,
  1231. UserAll->LogonHours.LogonHours,
  1232. UserpSizeOfLogonHours(
  1233. UserAll->LogonHours.UnitsPerWeek ),
  1234. sizeof(UCHAR) );
  1235. BufferDescriptor->EndOfVariableData =
  1236. ROUND_DOWN_POINTER( BufferDescriptor->EndOfVariableData,
  1237. ALIGN_WCHAR );
  1238. usri11->usri11_code_page = UserAll->CodePage;
  1239. break;
  1240. }
  1241. case 23:
  1242. {
  1243. //
  1244. // Since USER_INFO_23 has the same fields as USER_INFO_20 with the
  1245. // exception of the RID and SID fields, copy in the SID here and
  1246. // then fall through for the rest of the fields
  1247. //
  1248. PUSER_INFO_23 usri23 = (PUSER_INFO_23) NewStruct;
  1249. NetpAssert( NULL != UserSid );
  1250. COPY_BYTES( PUSER_INFO_23,
  1251. usri23_user_sid,
  1252. UserSid,
  1253. RtlLengthSid(UserSid),
  1254. ALIGN_DWORD );
  1255. //
  1256. // Fall through the level 20
  1257. //
  1258. }
  1259. case 20:
  1260. {
  1261. PUSER_INFO_20 usri20 = (PUSER_INFO_20) NewStruct;
  1262. COPY_STRING( PUSER_INFO_20, usri20_name, UserAll->UserName );
  1263. COPY_STRING( PUSER_INFO_20, usri20_full_name, UserAll->FullName );
  1264. COPY_STRING( PUSER_INFO_20, usri20_comment, UserAll->AdminComment );
  1265. if ( Level == 20 ) {
  1266. usri20->usri20_user_id = RidToReturn;
  1267. }
  1268. usri20->usri20_flags = NetpAccountControlToFlags(
  1269. UserAll->UserAccountControl,
  1270. UserDacl );
  1271. break;
  1272. }
  1273. default:
  1274. NetStatus = ERROR_INVALID_LEVEL;
  1275. goto Cleanup;
  1276. }
  1277. NetStatus = NERR_Success ;
  1278. //
  1279. // Clean up.
  1280. //
  1281. Cleanup:
  1282. //
  1283. // Free Sam information buffers
  1284. //
  1285. if ( UserAll != NULL ) {
  1286. Status = SamFreeMemory( UserAll );
  1287. NetpAssert( NT_SUCCESS(Status) );
  1288. }
  1289. if ( UserHandle != NULL ) {
  1290. (VOID) SamCloseHandle( UserHandle );
  1291. }
  1292. if ( UserDacl != NULL ) {
  1293. NetpMemoryFree( UserDacl );
  1294. }
  1295. if ( UserSid ) {
  1296. NetpMemoryFree( UserSid );
  1297. }
  1298. IF_DEBUG( UAS_DEBUG_USER ) {
  1299. NetpKdPrint(( "UserpGetInfo: returning %ld\n", NetStatus ));
  1300. }
  1301. return NetStatus;
  1302. } // UserpGetInfo
  1303. //
  1304. // Each field in the SAM USER_ALL_INFORMATION structure (and each pseudo field)
  1305. // is described here.
  1306. struct _SAM_FIELD_DESCRIPTION {
  1307. //
  1308. // Non-zero to indicate which field in the SAM USER_ALL_INFORMATION
  1309. // structure is being set.
  1310. DWORD WhichField;
  1311. //
  1312. // Define the value to return in ParmError if this field is bad.
  1313. //
  1314. DWORD UasParmNum;
  1315. //
  1316. // Describe the byte offset of the field in the SAM USER_ALL_INFORMATION
  1317. // structure.
  1318. //
  1319. DWORD SamOffset;
  1320. //
  1321. // The DesiredAccess mask includes both the access to read and the
  1322. // access to write the appropriate field in the USER_ALL_INFORMATION
  1323. //
  1324. ACCESS_MASK DesiredAccess;
  1325. } SamFieldDescription[] =
  1326. {
  1327. #define SAM_UserNameField 0
  1328. { USER_ALL_USERNAME, USER_NAME_PARMNUM,
  1329. offsetof(USER_ALL_INFORMATION, UserName),
  1330. USER_WRITE_ACCOUNT
  1331. },
  1332. #define SAM_FullNameField 1
  1333. { USER_ALL_FULLNAME, USER_FULL_NAME_PARMNUM,
  1334. offsetof(USER_ALL_INFORMATION, FullName),
  1335. USER_WRITE_ACCOUNT
  1336. },
  1337. #define SAM_PrimaryGroupIdField 2
  1338. { USER_ALL_PRIMARYGROUPID, USER_PRIMARY_GROUP_PARMNUM,
  1339. offsetof(USER_ALL_INFORMATION, PrimaryGroupId),
  1340. USER_LIST_GROUPS | READ_CONTROL | WRITE_DAC |
  1341. USER_WRITE_ACCOUNT
  1342. },
  1343. #define SAM_AdminCommentField 3
  1344. { USER_ALL_ADMINCOMMENT, USER_COMMENT_PARMNUM,
  1345. offsetof(USER_ALL_INFORMATION, AdminComment),
  1346. USER_WRITE_ACCOUNT
  1347. },
  1348. #define SAM_UserCommentField 4
  1349. { USER_ALL_USERCOMMENT, USER_USR_COMMENT_PARMNUM,
  1350. offsetof(USER_ALL_INFORMATION, UserComment),
  1351. USER_WRITE_PREFERENCES
  1352. },
  1353. #define SAM_HomeDirectoryField 5
  1354. { USER_ALL_HOMEDIRECTORY, USER_HOME_DIR_PARMNUM,
  1355. offsetof(USER_ALL_INFORMATION, HomeDirectory),
  1356. USER_WRITE_ACCOUNT
  1357. },
  1358. #define SAM_HomeDirectoryDriveField 6
  1359. { USER_ALL_HOMEDIRECTORYDRIVE, USER_HOME_DIR_DRIVE_PARMNUM,
  1360. offsetof(USER_ALL_INFORMATION, HomeDirectoryDrive),
  1361. USER_WRITE_ACCOUNT
  1362. },
  1363. #define SAM_ScriptPathField 7
  1364. { USER_ALL_SCRIPTPATH, USER_SCRIPT_PATH_PARMNUM,
  1365. offsetof(USER_ALL_INFORMATION, ScriptPath),
  1366. USER_WRITE_ACCOUNT
  1367. },
  1368. #define SAM_ProfilePathField 8
  1369. { USER_ALL_PROFILEPATH, USER_PROFILE_PARMNUM,
  1370. offsetof(USER_ALL_INFORMATION, ProfilePath),
  1371. USER_WRITE_ACCOUNT
  1372. },
  1373. #define SAM_WorkstationsField 9
  1374. { USER_ALL_WORKSTATIONS, USER_WORKSTATIONS_PARMNUM,
  1375. offsetof(USER_ALL_INFORMATION, WorkStations),
  1376. USER_WRITE_ACCOUNT
  1377. },
  1378. #define SAM_LogonHoursField 10
  1379. { USER_ALL_LOGONHOURS, USER_LOGON_HOURS_PARMNUM,
  1380. offsetof(USER_ALL_INFORMATION, LogonHours.LogonHours),
  1381. USER_WRITE_ACCOUNT
  1382. },
  1383. #define SAM_UnitsPerWeekField 11
  1384. { USER_ALL_LOGONHOURS, USER_UNITS_PER_WEEK_PARMNUM,
  1385. offsetof(USER_ALL_INFORMATION, LogonHours.UnitsPerWeek),
  1386. USER_WRITE_ACCOUNT
  1387. },
  1388. #define SAM_AccountExpiresField 12
  1389. { USER_ALL_ACCOUNTEXPIRES, USER_ACCT_EXPIRES_PARMNUM,
  1390. offsetof(USER_ALL_INFORMATION, AccountExpires),
  1391. USER_WRITE_ACCOUNT
  1392. },
  1393. #define SAM_UserAccountControlField 13
  1394. { USER_ALL_USERACCOUNTCONTROL, USER_FLAGS_PARMNUM,
  1395. offsetof(USER_ALL_INFORMATION, UserAccountControl),
  1396. USER_WRITE_ACCOUNT | USER_READ_ACCOUNT | READ_CONTROL | WRITE_DAC
  1397. },
  1398. #define SAM_ParametersField 14
  1399. { USER_ALL_PARAMETERS, USER_PARMS_PARMNUM,
  1400. offsetof(USER_ALL_INFORMATION, Parameters),
  1401. USER_WRITE_ACCOUNT
  1402. },
  1403. #define SAM_CountryCodeField 15
  1404. { USER_ALL_COUNTRYCODE, USER_COUNTRY_CODE_PARMNUM,
  1405. offsetof(USER_ALL_INFORMATION, CountryCode),
  1406. USER_WRITE_PREFERENCES
  1407. },
  1408. #define SAM_CodePageField 16
  1409. { USER_ALL_CODEPAGE, USER_CODE_PAGE_PARMNUM,
  1410. offsetof(USER_ALL_INFORMATION, CodePage),
  1411. USER_WRITE_PREFERENCES
  1412. },
  1413. #define SAM_ClearTextPasswordField 17
  1414. { USER_ALL_NTPASSWORDPRESENT, USER_PASSWORD_PARMNUM,
  1415. offsetof(USER_ALL_INFORMATION, NtPassword),
  1416. USER_FORCE_PASSWORD_CHANGE
  1417. },
  1418. #define SAM_PasswordExpiredField 18
  1419. { USER_ALL_PASSWORDEXPIRED, PARM_ERROR_UNKNOWN,
  1420. offsetof(USER_ALL_INFORMATION, PasswordExpired),
  1421. USER_FORCE_PASSWORD_CHANGE
  1422. },
  1423. #define SAM_OwfPasswordField 19
  1424. { USER_ALL_LMPASSWORDPRESENT | USER_ALL_OWFPASSWORD,
  1425. USER_PASSWORD_PARMNUM,
  1426. offsetof(USER_ALL_INFORMATION, LmPassword),
  1427. USER_FORCE_PASSWORD_CHANGE
  1428. },
  1429. //
  1430. // The following levels are pseudo levels which merely define the
  1431. // access required to set a particuler UAS field.
  1432. #define SAM_AuthFlagsField 20
  1433. { 0, PARM_ERROR_UNKNOWN,
  1434. 0,
  1435. USER_LIST_GROUPS
  1436. },
  1437. #define SAM_MaxStorageField 21
  1438. { 0, USER_MAX_STORAGE_PARMNUM,
  1439. 0,
  1440. USER_READ_GENERAL
  1441. },
  1442. };
  1443. //
  1444. // Relate the NetUser API fields to the SAM API fields.
  1445. //
  1446. // This table contains as much information as possible to describe the
  1447. // relationship between fields in the NetUser API and the SAM API.
  1448. //
  1449. struct _UAS_SAM_TABLE {
  1450. //
  1451. // Describe the field types for UAS and SAM.
  1452. //
  1453. enum {
  1454. UT_STRING, // UAS is LPWSTR. SAM is UNICODE_STRING.
  1455. UT_BOOLEAN, // UAS is DWORD. SAM is BOOLEAN.
  1456. UT_USHORT, // UAS is DWORD. SAM is USHORT.
  1457. UT_ULONG, // UAS is DWORD. SAM is ULONG.
  1458. UT_TIME, // UAS is seconds since 1970. SAM is LARGE_INTEGER.
  1459. UT_PRIV, // Special case
  1460. UT_ACCOUNT_CONTROL, // Special case
  1461. UT_AUTH_FLAGS, // Special case
  1462. UT_MAX_STORAGE, // Special case
  1463. UT_OWF_PASSWORD, // Special case
  1464. UT_LOGON_HOURS, // Special case
  1465. UT_UNITS_PER_WEEK, // Special case
  1466. UT_CREATE_FULLNAME // Special case
  1467. } FieldType;
  1468. //
  1469. // The NetUser API detail level this field is in.
  1470. //
  1471. DWORD UasLevel;
  1472. //
  1473. // Index to the structure describing the Sam Field being changed.
  1474. //
  1475. DWORD SamField;
  1476. //
  1477. // Describe the byte offset of the field in the appropriate UAS
  1478. // and SAM structures.
  1479. //
  1480. DWORD UasOffset;
  1481. } UserpUasSamTable[] =
  1482. {
  1483. // Rename an account at info level 0 only.
  1484. { UT_STRING, 0, SAM_UserNameField,
  1485. offsetof(USER_INFO_1, usri1_name) },
  1486. { UT_STRING, 1, SAM_ClearTextPasswordField,
  1487. offsetof(USER_INFO_1, usri1_password) },
  1488. { UT_STRING, 2, SAM_ClearTextPasswordField,
  1489. offsetof(USER_INFO_2, usri2_password) },
  1490. { UT_STRING, 3, SAM_ClearTextPasswordField,
  1491. offsetof(USER_INFO_3, usri3_password) },
  1492. { UT_STRING, 4, SAM_ClearTextPasswordField,
  1493. offsetof(USER_INFO_4, usri4_password) },
  1494. { UT_STRING, 1003, SAM_ClearTextPasswordField,
  1495. offsetof(USER_INFO_1003, usri1003_password) },
  1496. { UT_OWF_PASSWORD, 21, SAM_OwfPasswordField,
  1497. offsetof(USER_INFO_21, usri21_password[0]) },
  1498. { UT_OWF_PASSWORD, 22, SAM_OwfPasswordField,
  1499. offsetof(USER_INFO_22, usri22_password[0]) },
  1500. { UT_PRIV, 1, SAM_AuthFlagsField,
  1501. offsetof(USER_INFO_1, usri1_priv) },
  1502. { UT_PRIV, 2, SAM_AuthFlagsField,
  1503. offsetof(USER_INFO_2, usri2_priv) },
  1504. { UT_PRIV, 22, SAM_AuthFlagsField,
  1505. offsetof(USER_INFO_22, usri22_priv) },
  1506. #ifdef notdef
  1507. //
  1508. // usri3_priv is totally ignored for info level three. The field is
  1509. // supplied for compatibility with LM 2.x only and LM 2.x never uses
  1510. // info level 3.
  1511. //
  1512. { UT_PRIV, 3, SAM_AuthFlagsField,
  1513. offsetof(USER_INFO_3, usri3_priv) },
  1514. #endif // notdef
  1515. { UT_PRIV, 1005, SAM_AuthFlagsField,
  1516. offsetof(USER_INFO_1005, usri1005_priv) },
  1517. { UT_STRING, 1, SAM_HomeDirectoryField,
  1518. offsetof(USER_INFO_1, usri1_home_dir) },
  1519. { UT_STRING, 2, SAM_HomeDirectoryField,
  1520. offsetof(USER_INFO_2, usri2_home_dir) },
  1521. { UT_STRING, 22, SAM_HomeDirectoryField,
  1522. offsetof(USER_INFO_22, usri22_home_dir) },
  1523. { UT_STRING, 3, SAM_HomeDirectoryField,
  1524. offsetof(USER_INFO_3, usri3_home_dir) },
  1525. { UT_STRING, 4, SAM_HomeDirectoryField,
  1526. offsetof(USER_INFO_4, usri4_home_dir) },
  1527. { UT_STRING, 1006, SAM_HomeDirectoryField,
  1528. offsetof(USER_INFO_1006, usri1006_home_dir) },
  1529. { UT_STRING, 1, SAM_AdminCommentField,
  1530. offsetof(USER_INFO_1, usri1_comment) },
  1531. { UT_STRING, 2, SAM_AdminCommentField,
  1532. offsetof(USER_INFO_2, usri2_comment) },
  1533. { UT_STRING, 22, SAM_AdminCommentField,
  1534. offsetof(USER_INFO_22, usri22_comment) },
  1535. { UT_STRING, 3, SAM_AdminCommentField,
  1536. offsetof(USER_INFO_3, usri3_comment) },
  1537. { UT_STRING, 4, SAM_AdminCommentField,
  1538. offsetof(USER_INFO_4, usri4_comment) },
  1539. { UT_STRING, 1007, SAM_AdminCommentField,
  1540. offsetof(USER_INFO_1007, usri1007_comment) },
  1541. { UT_ACCOUNT_CONTROL, 1, SAM_UserAccountControlField,
  1542. offsetof(USER_INFO_1, usri1_flags) },
  1543. { UT_ACCOUNT_CONTROL, 2, SAM_UserAccountControlField,
  1544. offsetof(USER_INFO_2, usri2_flags) },
  1545. { UT_ACCOUNT_CONTROL, 22, SAM_UserAccountControlField,
  1546. offsetof(USER_INFO_22, usri22_flags) },
  1547. { UT_ACCOUNT_CONTROL, 3, SAM_UserAccountControlField,
  1548. offsetof(USER_INFO_3, usri3_flags) },
  1549. { UT_ACCOUNT_CONTROL, 4, SAM_UserAccountControlField,
  1550. offsetof(USER_INFO_4, usri4_flags) },
  1551. { UT_ACCOUNT_CONTROL, 1008, SAM_UserAccountControlField,
  1552. offsetof(USER_INFO_1008, usri1008_flags) },
  1553. { UT_STRING, 1, SAM_ScriptPathField,
  1554. offsetof(USER_INFO_1, usri1_script_path) },
  1555. { UT_STRING, 2, SAM_ScriptPathField,
  1556. offsetof(USER_INFO_2, usri2_script_path) },
  1557. { UT_STRING, 22, SAM_ScriptPathField,
  1558. offsetof(USER_INFO_22, usri22_script_path) },
  1559. { UT_STRING, 3, SAM_ScriptPathField,
  1560. offsetof(USER_INFO_3, usri3_script_path) },
  1561. { UT_STRING, 4, SAM_ScriptPathField,
  1562. offsetof(USER_INFO_4, usri4_script_path) },
  1563. { UT_STRING, 1009, SAM_ScriptPathField,
  1564. offsetof(USER_INFO_1009, usri1009_script_path) },
  1565. { UT_AUTH_FLAGS, 2, SAM_AuthFlagsField,
  1566. offsetof(USER_INFO_2, usri2_auth_flags) },
  1567. { UT_AUTH_FLAGS, 22, SAM_AuthFlagsField,
  1568. offsetof(USER_INFO_22, usri22_auth_flags) },
  1569. #ifdef notdef
  1570. //
  1571. // usri3_auth_flags is totally ignored for info level three. The field is
  1572. // supplied for compatibility with LM 2.x only and LM 2.x never uses
  1573. // info level 3.
  1574. //
  1575. { UT_AUTH_FLAGS, 3, SAM_AuthFlagsField,
  1576. offsetof(USER_INFO_3, usri3_auth_flags) },
  1577. { UT_AUTH_FLAGS, 4, SAM_AuthFlagsField,
  1578. offsetof(USER_INFO_4, usri4_auth_flags) },
  1579. #endif // notdef
  1580. { UT_AUTH_FLAGS, 1010, SAM_AuthFlagsField,
  1581. offsetof(USER_INFO_1010, usri1010_auth_flags) },
  1582. { UT_CREATE_FULLNAME, 1, SAM_FullNameField,
  1583. offsetof(USER_INFO_1, usri1_name) },
  1584. { UT_STRING, 2, SAM_FullNameField,
  1585. offsetof(USER_INFO_2, usri2_full_name) },
  1586. { UT_STRING, 22, SAM_FullNameField,
  1587. offsetof(USER_INFO_22, usri22_full_name) },
  1588. { UT_STRING, 3, SAM_FullNameField,
  1589. offsetof(USER_INFO_3, usri3_full_name) },
  1590. { UT_STRING, 4, SAM_FullNameField,
  1591. offsetof(USER_INFO_4, usri4_full_name) },
  1592. { UT_STRING, 1011, SAM_FullNameField,
  1593. offsetof(USER_INFO_1011, usri1011_full_name) },
  1594. { UT_STRING, 2, SAM_UserCommentField,
  1595. offsetof(USER_INFO_2, usri2_usr_comment) },
  1596. { UT_STRING, 22, SAM_UserCommentField,
  1597. offsetof(USER_INFO_22, usri22_usr_comment) },
  1598. { UT_STRING, 3, SAM_UserCommentField,
  1599. offsetof(USER_INFO_3, usri3_usr_comment) },
  1600. { UT_STRING, 4, SAM_UserCommentField,
  1601. offsetof(USER_INFO_4, usri4_usr_comment) },
  1602. { UT_STRING, 1012, SAM_UserCommentField,
  1603. offsetof(USER_INFO_1012, usri1012_usr_comment) },
  1604. { UT_STRING, 2, SAM_ParametersField,
  1605. offsetof(USER_INFO_2, usri2_parms) },
  1606. { UT_STRING, 22, SAM_ParametersField,
  1607. offsetof(USER_INFO_22, usri22_parms) },
  1608. { UT_STRING, 3, SAM_ParametersField,
  1609. offsetof(USER_INFO_3, usri3_parms) },
  1610. { UT_STRING, 4, SAM_ParametersField,
  1611. offsetof(USER_INFO_4, usri4_parms) },
  1612. { UT_STRING, 1013, SAM_ParametersField,
  1613. offsetof(USER_INFO_1013, usri1013_parms) },
  1614. { UT_STRING, 2, SAM_WorkstationsField,
  1615. offsetof(USER_INFO_2, usri2_workstations) },
  1616. { UT_STRING, 22, SAM_WorkstationsField,
  1617. offsetof(USER_INFO_22, usri22_workstations) },
  1618. { UT_STRING, 3, SAM_WorkstationsField,
  1619. offsetof(USER_INFO_3, usri3_workstations) },
  1620. { UT_STRING, 4, SAM_WorkstationsField,
  1621. offsetof(USER_INFO_4, usri4_workstations) },
  1622. { UT_STRING, 1014, SAM_WorkstationsField,
  1623. offsetof(USER_INFO_1014, usri1014_workstations) },
  1624. { UT_TIME, 2, SAM_AccountExpiresField,
  1625. offsetof(USER_INFO_2, usri2_acct_expires) },
  1626. { UT_TIME, 22, SAM_AccountExpiresField,
  1627. offsetof(USER_INFO_22, usri22_acct_expires) },
  1628. { UT_TIME, 3, SAM_AccountExpiresField,
  1629. offsetof(USER_INFO_3, usri3_acct_expires) },
  1630. { UT_TIME, 4, SAM_AccountExpiresField,
  1631. offsetof(USER_INFO_4, usri4_acct_expires) },
  1632. { UT_TIME, 1017, SAM_AccountExpiresField,
  1633. offsetof(USER_INFO_1017, usri1017_acct_expires) },
  1634. #ifdef notdef // lm 2.1 gets this wrong when adding BDC accounts
  1635. { UT_MAX_STORAGE, 2, SAM_MaxStorageField,
  1636. offsetof(USER_INFO_2, usri2_max_storage) },
  1637. { UT_MAX_STORAGE, 22, SAM_MaxStorageField,
  1638. offsetof(USER_INFO_22, usri22_max_storage) },
  1639. { UT_MAX_STORAGE, 3, SAM_MaxStorageField,
  1640. offsetof(USER_INFO_3, usri3_max_storage) },
  1641. { UT_MAX_STORAGE, 4, SAM_MaxStorageField,
  1642. offsetof(USER_INFO_4, usri4_max_storage) },
  1643. #endif // notdef
  1644. { UT_MAX_STORAGE, 1018, SAM_MaxStorageField,
  1645. offsetof(USER_INFO_1018, usri1018_max_storage) },
  1646. { UT_UNITS_PER_WEEK, 2, SAM_UnitsPerWeekField,
  1647. offsetof(USER_INFO_2, usri2_units_per_week) },
  1648. { UT_UNITS_PER_WEEK, 22, SAM_UnitsPerWeekField,
  1649. offsetof(USER_INFO_22, usri22_units_per_week) },
  1650. { UT_UNITS_PER_WEEK, 3, SAM_UnitsPerWeekField,
  1651. offsetof(USER_INFO_3, usri3_units_per_week) },
  1652. { UT_UNITS_PER_WEEK, 4, SAM_UnitsPerWeekField,
  1653. offsetof(USER_INFO_4, usri4_units_per_week) },
  1654. { UT_UNITS_PER_WEEK, 1020, SAM_UnitsPerWeekField,
  1655. offsetof(USER_INFO_1020, usri1020_units_per_week) },
  1656. { UT_LOGON_HOURS, 2, SAM_LogonHoursField,
  1657. offsetof(USER_INFO_2, usri2_logon_hours) },
  1658. { UT_LOGON_HOURS, 22, SAM_LogonHoursField,
  1659. offsetof(USER_INFO_22, usri22_logon_hours) },
  1660. { UT_LOGON_HOURS, 3, SAM_LogonHoursField,
  1661. offsetof(USER_INFO_3, usri3_logon_hours) },
  1662. { UT_LOGON_HOURS, 4, SAM_LogonHoursField,
  1663. offsetof(USER_INFO_4, usri4_logon_hours) },
  1664. { UT_LOGON_HOURS, 1020, SAM_LogonHoursField,
  1665. offsetof(USER_INFO_1020, usri1020_logon_hours) },
  1666. { UT_USHORT, 2, SAM_CountryCodeField,
  1667. offsetof(USER_INFO_2, usri2_country_code) },
  1668. { UT_USHORT, 22, SAM_CountryCodeField,
  1669. offsetof(USER_INFO_22, usri22_country_code) },
  1670. { UT_USHORT, 3, SAM_CountryCodeField,
  1671. offsetof(USER_INFO_3, usri3_country_code) },
  1672. { UT_USHORT, 4, SAM_CountryCodeField,
  1673. offsetof(USER_INFO_4, usri4_country_code) },
  1674. { UT_USHORT, 1024, SAM_CountryCodeField,
  1675. offsetof(USER_INFO_1024, usri1024_country_code) },
  1676. { UT_USHORT, 2, SAM_CodePageField,
  1677. offsetof(USER_INFO_2, usri2_code_page) },
  1678. { UT_USHORT, 22, SAM_CodePageField,
  1679. offsetof(USER_INFO_22, usri22_code_page) },
  1680. { UT_USHORT, 3, SAM_CodePageField,
  1681. offsetof(USER_INFO_3, usri3_code_page) },
  1682. { UT_USHORT, 4, SAM_CodePageField,
  1683. offsetof(USER_INFO_4, usri4_code_page) },
  1684. { UT_USHORT, 1025, SAM_CodePageField,
  1685. offsetof(USER_INFO_1025, usri1025_code_page) },
  1686. { UT_ULONG, 3, SAM_PrimaryGroupIdField,
  1687. offsetof(USER_INFO_3, usri3_primary_group_id) },
  1688. { UT_ULONG, 4, SAM_PrimaryGroupIdField,
  1689. offsetof(USER_INFO_4, usri4_primary_group_id) },
  1690. { UT_ULONG, 1051, SAM_PrimaryGroupIdField,
  1691. offsetof(USER_INFO_1051, usri1051_primary_group_id) },
  1692. { UT_STRING, 3, SAM_ProfilePathField,
  1693. offsetof(USER_INFO_3, usri3_profile) },
  1694. { UT_STRING, 4, SAM_ProfilePathField,
  1695. offsetof(USER_INFO_4, usri4_profile) },
  1696. { UT_STRING, 1052, SAM_ProfilePathField,
  1697. offsetof(USER_INFO_1052, usri1052_profile) },
  1698. { UT_STRING, 3, SAM_HomeDirectoryDriveField,
  1699. offsetof(USER_INFO_3, usri3_home_dir_drive) },
  1700. { UT_STRING, 4, SAM_HomeDirectoryDriveField,
  1701. offsetof(USER_INFO_4, usri4_home_dir_drive) },
  1702. { UT_STRING, 1053, SAM_HomeDirectoryDriveField,
  1703. offsetof(USER_INFO_1053, usri1053_home_dir_drive) },
  1704. { UT_BOOLEAN, 3, SAM_PasswordExpiredField,
  1705. offsetof(USER_INFO_3, usri3_password_expired) },
  1706. { UT_BOOLEAN, 4, SAM_PasswordExpiredField,
  1707. offsetof(USER_INFO_4, usri4_password_expired) },
  1708. };
  1709. NET_API_STATUS
  1710. UserpSetInfo(
  1711. IN SAM_HANDLE DomainHandle,
  1712. IN PSID DomainId,
  1713. IN SAM_HANDLE UserHandle OPTIONAL,
  1714. IN SAM_HANDLE BuiltinDomainHandle OPTIONAL,
  1715. IN ULONG UserRelativeId,
  1716. IN LPCWSTR UserName,
  1717. IN DWORD Level,
  1718. IN LPBYTE Buffer,
  1719. IN ULONG WhichFieldsMask,
  1720. OUT LPDWORD ParmError OPTIONAL // Name required by NetpSetParmError
  1721. )
  1722. /*++
  1723. Routine Description:
  1724. Set the parameters on a user account in the user accounts database.
  1725. Arguments:
  1726. DomainHandle - Domain Handle for the domain.
  1727. PSID DomainId - Domain Sid for DomainHandle
  1728. UserHandle - User Handle of the already open group. If one is not
  1729. specified, one will be openned then closed. If one is specified,
  1730. it must be open with adequate access.
  1731. BuiltinDomainHandle - Domain Handle for the builtin domain. Need only be
  1732. specified for info level 1, 2, 3, 22, 1005 and 1010. Need not
  1733. be specified when a user is created.
  1734. UserRelativeId - Relative Id of the user.
  1735. UserName - Name of the user to set.
  1736. Level - Level of information provided.
  1737. Buffer - A pointer to the buffer containing the user information
  1738. structure.
  1739. ParmError - Optional pointer to a DWORD to return the index of the
  1740. first parameter in error when ERROR_INVALID_PARAMETER is returned.
  1741. If NULL, the parameter is not returned on error.
  1742. Return Value:
  1743. Error code for the operation.
  1744. NOTE: LogonServer field that is passed in UAS set structure is never
  1745. used or validated. It is simply ignored.
  1746. --*/
  1747. {
  1748. NET_API_STATUS NetStatus;
  1749. NTSTATUS Status;
  1750. SAM_HANDLE LocalUserHandle = NULL;
  1751. ACCESS_MASK DesiredAccess;
  1752. DWORD UasSamIndex;
  1753. USER_ALL_INFORMATION UserAll;
  1754. //
  1755. // Value of Fields from UAS structure (used for validation)
  1756. //
  1757. DWORD UasUserFlags;
  1758. DWORD NewPriv;
  1759. DWORD NewAuthFlags;
  1760. BOOL ValidatePriv = FALSE;
  1761. BOOL ValidateAuthFlags = FALSE;
  1762. USHORT UasUnitsPerWeek;
  1763. //
  1764. // Variables for changing the DACL on the user.
  1765. //
  1766. PACL OldUserDacl = NULL;
  1767. PACL NewUserDacl = NULL;
  1768. BOOL UserDaclChanged = FALSE;
  1769. BOOL HandleUserDacl = FALSE;
  1770. USHORT AceIndex;
  1771. PSID UserSid = NULL;
  1772. //
  1773. // Define several macros for accessing the various fields of the UAS
  1774. // structure. Each macro takes an index into the UserpUasSamTable
  1775. // array and returns the value.
  1776. //
  1777. #define GET_UAS_STRING_POINTER( _i ) \
  1778. (*((LPWSTR *)(Buffer + UserpUasSamTable[_i].UasOffset)))
  1779. #define GET_UAS_DWORD( _i ) \
  1780. (*((DWORD *)(Buffer + UserpUasSamTable[_i].UasOffset)))
  1781. #define GET_UAS_FIELD_ADDRESS( _i ) \
  1782. (Buffer + UserpUasSamTable[_i].UasOffset)
  1783. //
  1784. // Define a macro which returns a pointer the appropriate
  1785. // SamFieldDescription structure given an index into the UserpUasSamTable.
  1786. //
  1787. #define SAM_FIELD( _i ) \
  1788. SamFieldDescription[ UserpUasSamTable[_i].SamField ]
  1789. //
  1790. // Initialize
  1791. //
  1792. IF_DEBUG( UAS_DEBUG_USER ) {
  1793. NetpKdPrint(( "UserpSetInfo: entered \n" ));
  1794. }
  1795. NetpSetParmError( PARM_ERROR_NONE );
  1796. RtlZeroMemory( &UserAll, sizeof(UserAll) );
  1797. //
  1798. // Go through the list of valid info levels determining if the info level
  1799. // is valid and computing the desired access to the user and copying the
  1800. // UAS information into the SAM structure.
  1801. //
  1802. DesiredAccess = 0;
  1803. for ( UasSamIndex=0 ;
  1804. UasSamIndex<sizeof(UserpUasSamTable)/sizeof(UserpUasSamTable[0]);
  1805. UasSamIndex++ ){
  1806. LPBYTE SamField;
  1807. //
  1808. // If this field isn't one we're changing, just skip to the next one
  1809. //
  1810. if ( Level != UserpUasSamTable[UasSamIndex].UasLevel ) {
  1811. continue;
  1812. }
  1813. //
  1814. // Set up a pointer to the appropriate field in SAM's structure.
  1815. //
  1816. if ( SAM_FIELD(UasSamIndex).WhichField != 0 ) {
  1817. SamField = ((LPBYTE)(&UserAll)) + SAM_FIELD(UasSamIndex).SamOffset;
  1818. } else {
  1819. SamField = NULL;
  1820. }
  1821. //
  1822. // Validate the UAS field based on the field type.
  1823. //
  1824. switch ( UserpUasSamTable[UasSamIndex].FieldType ) {
  1825. //
  1826. // Default the fullname of the account to be the user name when
  1827. // the user is created using level 1.
  1828. //
  1829. // Ignore this entry if not a "create" operation.
  1830. //
  1831. case UT_CREATE_FULLNAME:
  1832. if ( UserHandle == NULL ) {
  1833. continue;
  1834. }
  1835. /* DROP THROUGH to the UT_STRING case */
  1836. //
  1837. // If this is a PARMNUM_ALL and the caller passed in a
  1838. // NULL pointer to a string, he doesn't want to change the string.
  1839. //
  1840. case UT_STRING:
  1841. if ( GET_UAS_STRING_POINTER( UasSamIndex ) == NULL ) {
  1842. continue;
  1843. }
  1844. RtlInitUnicodeString(
  1845. (PUNICODE_STRING) SamField,
  1846. GET_UAS_STRING_POINTER(UasSamIndex) );
  1847. break;
  1848. //
  1849. // Just save the UnitsPerWeek until UT_LOGON_HOURS can handle
  1850. // both fields at once.
  1851. //
  1852. // Sam gets confused if we pass in one field without the other.
  1853. //
  1854. case UT_UNITS_PER_WEEK:
  1855. UasUnitsPerWeek = (USHORT) GET_UAS_DWORD(UasSamIndex);
  1856. //
  1857. // If this is a create at info level 2 (e.g., dowlevel client),
  1858. // assume the caller specified UNITS_PER_WEEK.
  1859. //
  1860. // We don't special case SetInfo at level 2 because we don't
  1861. // want to corrupt the value assuming he did a query followed
  1862. // by a set.
  1863. //
  1864. if ( Level == 2 && UserHandle != NULL ) {
  1865. UasUnitsPerWeek = UNITS_PER_WEEK;
  1866. }
  1867. if ( UasUnitsPerWeek > USHRT_MAX ) {
  1868. NetpSetParmError( SAM_FIELD(UasSamIndex).UasParmNum );
  1869. NetStatus = ERROR_INVALID_PARAMETER;
  1870. IF_DEBUG( UAS_DEBUG_USER ) {
  1871. NetpKdPrint((
  1872. "UserpSetInfo: Ushort too big Index:%ld Value:%ld\n",
  1873. UasSamIndex,
  1874. UasUnitsPerWeek ));
  1875. }
  1876. goto Cleanup;
  1877. }
  1878. //
  1879. // Ignore this field completely for now.
  1880. // Let UT_LOGON_HOURS define the desired access and Whichfields.
  1881. continue;
  1882. //
  1883. // If the caller passed in a NULL pointer to the logon hours
  1884. // he doesn't want to change the logon hours.
  1885. //
  1886. case UT_LOGON_HOURS:
  1887. if ( GET_UAS_STRING_POINTER( UasSamIndex ) == NULL ) {
  1888. continue;
  1889. }
  1890. *((PUCHAR *)SamField) = (PUCHAR)GET_UAS_STRING_POINTER(UasSamIndex);
  1891. UserAll.LogonHours.UnitsPerWeek = UasUnitsPerWeek;
  1892. break;
  1893. //
  1894. // If the user is setting max storage, require him to set
  1895. // it to USER_MAXSTORAGE_UNLIMITED since SAM doesn't support
  1896. // max storage.
  1897. //
  1898. case UT_MAX_STORAGE:
  1899. if ( GET_UAS_DWORD(UasSamIndex) != USER_MAXSTORAGE_UNLIMITED ) {
  1900. NetpSetParmError( USER_MAX_STORAGE_PARMNUM );
  1901. NetStatus = ERROR_INVALID_PARAMETER;
  1902. IF_DEBUG( UAS_DEBUG_USER ) {
  1903. NetpKdPrint(( "UserpSetInfo: Max storage is invalid\n" ));
  1904. }
  1905. goto Cleanup;
  1906. }
  1907. // 'break' to make sure the user exists.
  1908. break;
  1909. //
  1910. // Handle Account control
  1911. //
  1912. // Ensure all the required bits are on and only valid bits
  1913. // are on.
  1914. //
  1915. case UT_ACCOUNT_CONTROL: {
  1916. UasUserFlags = GET_UAS_DWORD(UasSamIndex);
  1917. if ((UasUserFlags & ~UF_SETTABLE_BITS) != 0 ) {
  1918. NetpSetParmError( USER_FLAGS_PARMNUM );
  1919. NetStatus = ERROR_INVALID_PARAMETER;
  1920. IF_DEBUG( UAS_DEBUG_USER ) {
  1921. NetpKdPrint((
  1922. "UserpSetInfo: Invalid account control bits (1) \n" ));
  1923. }
  1924. goto Cleanup;
  1925. }
  1926. //
  1927. // If none of the account type bit is set in the usri_flag,
  1928. // means that the caller does not want to change its account type.
  1929. // break out now, and we will set the appropriate account
  1930. // bit when we set the usri_flag.
  1931. //
  1932. if ( UasUserFlags & UF_ACCOUNT_TYPE_MASK ) {
  1933. //
  1934. // Account Types bits are exclusive, so make sure that
  1935. // precisely one Account Type bit is set.
  1936. //
  1937. if ( !JUST_ONE_BIT( UasUserFlags & UF_ACCOUNT_TYPE_MASK )) {
  1938. NetpSetParmError( USER_FLAGS_PARMNUM );
  1939. NetStatus = ERROR_INVALID_PARAMETER;
  1940. IF_DEBUG( UAS_DEBUG_USER ) {
  1941. NetpKdPrint((
  1942. "UserpSetInfo: Invalid account control bits (2) \n" ));
  1943. }
  1944. goto Cleanup;
  1945. }
  1946. }
  1947. //
  1948. // If this is a 'create' operation,
  1949. // and the user has asked for the SAM defaults.
  1950. // we have no reason to change the DACL
  1951. //
  1952. if ( UserHandle != NULL &&
  1953. (UasUserFlags & UF_PASSWD_CANT_CHANGE) == 0 ) {
  1954. break;
  1955. }
  1956. //
  1957. // In all other cases, update the DACL to match the callers request.
  1958. //
  1959. HandleUserDacl = TRUE;
  1960. break;
  1961. }
  1962. //
  1963. // Copy a boolean to the SAM structure.
  1964. //
  1965. case UT_BOOLEAN:
  1966. *((PBOOLEAN)SamField) = (BOOLEAN)
  1967. (GET_UAS_DWORD(UasSamIndex)) ? TRUE : FALSE;
  1968. break;
  1969. //
  1970. // Ensure unsigned shorts are really in range and
  1971. // copy it to the SAM structure.
  1972. //
  1973. case UT_USHORT:
  1974. if ( GET_UAS_DWORD(UasSamIndex) > USHRT_MAX ) {
  1975. NetpSetParmError( SAM_FIELD(UasSamIndex).UasParmNum );
  1976. NetStatus = ERROR_INVALID_PARAMETER;
  1977. IF_DEBUG( UAS_DEBUG_USER ) {
  1978. NetpKdPrint((
  1979. "UserpSetInfo: Ushort too big Index:%ld Value:%ld\n",
  1980. UasSamIndex,
  1981. GET_UAS_DWORD(UasSamIndex) ));
  1982. }
  1983. goto Cleanup;
  1984. }
  1985. *((PUSHORT)SamField) = (USHORT) GET_UAS_DWORD(UasSamIndex);
  1986. break;
  1987. //
  1988. // Copy the unsigned long to the SAM structure
  1989. //
  1990. case UT_ULONG:
  1991. *((PULONG)SamField) = (ULONG)GET_UAS_DWORD(UasSamIndex);
  1992. break;
  1993. //
  1994. // Convert time to its SAM counterpart
  1995. //
  1996. case UT_TIME:
  1997. //
  1998. // PREFIX: SamField can only be NULL due to a programming error
  1999. // by setting the UserpUasSamTable table incorrectly. This
  2000. // assert catches the problem.
  2001. //
  2002. NetpAssert(NULL != SamField);
  2003. if ( GET_UAS_DWORD(UasSamIndex) == TIMEQ_FOREVER ) {
  2004. ((PLARGE_INTEGER) SamField)->LowPart = 0;
  2005. ((PLARGE_INTEGER) SamField)->HighPart = 0;
  2006. } else {
  2007. RtlSecondsSince1970ToTime(
  2008. GET_UAS_DWORD(UasSamIndex),
  2009. (PLARGE_INTEGER) SamField );
  2010. }
  2011. IF_DEBUG( UAS_DEBUG_USER ) {
  2012. NetpKdPrint(( "UserpSetInfo: Index: %ld Time %lx %lx %lx\n",
  2013. UasSamIndex,
  2014. ((PLARGE_INTEGER) SamField)->HighPart,
  2015. ((PLARGE_INTEGER) SamField)->LowPart,
  2016. GET_UAS_DWORD(UasSamIndex) ));
  2017. }
  2018. break;
  2019. //
  2020. // Copy the OWF password to the SAM structure.
  2021. //
  2022. case UT_OWF_PASSWORD:
  2023. ((PUNICODE_STRING) SamField)->Buffer =
  2024. (LPWSTR) (GET_UAS_FIELD_ADDRESS( UasSamIndex ));
  2025. ((PUNICODE_STRING) SamField)->Length =
  2026. ((PUNICODE_STRING) SamField)->MaximumLength =
  2027. LM_OWF_PASSWORD_LENGTH;
  2028. //
  2029. // set that the LmPasswordField field to TRUE to indicate
  2030. // that we filled LmPassword field.
  2031. //
  2032. UserAll.LmPasswordPresent = TRUE;
  2033. UserAll.NtPasswordPresent = FALSE;
  2034. break;
  2035. //
  2036. // Ensure the specified privilege is valid.
  2037. //
  2038. case UT_PRIV:
  2039. NewPriv = GET_UAS_DWORD(UasSamIndex);
  2040. if ( (NewPriv & ~USER_PRIV_MASK) != 0 ) {
  2041. NetpSetParmError( SAM_FIELD(UasSamIndex).UasParmNum );
  2042. NetStatus = ERROR_INVALID_PARAMETER;
  2043. IF_DEBUG( UAS_DEBUG_USER ) {
  2044. NetpKdPrint(( "UserpSetInfo: Invalid priv %ld\n", NewPriv ));
  2045. }
  2046. goto Cleanup;
  2047. }
  2048. ValidatePriv = TRUE;
  2049. break;
  2050. //
  2051. // Ensure the specified operator flags is valid.
  2052. //
  2053. case UT_AUTH_FLAGS:
  2054. NewAuthFlags = GET_UAS_DWORD(UasSamIndex);
  2055. if ( (NewAuthFlags & ~AF_SETTABLE_BITS) != 0 ) {
  2056. NetpSetParmError( SAM_FIELD(UasSamIndex).UasParmNum );
  2057. NetStatus = ERROR_INVALID_PARAMETER;
  2058. IF_DEBUG( UAS_DEBUG_USER ) {
  2059. NetpKdPrint(( "UserpSetInfo: Invalid auth_flag %lx\n",
  2060. NewAuthFlags ));
  2061. }
  2062. goto Cleanup;
  2063. }
  2064. ValidateAuthFlags = TRUE;
  2065. break;
  2066. //
  2067. // All valid cases were explicitly checked above.
  2068. //
  2069. default:
  2070. IF_DEBUG( UAS_DEBUG_USER ) {
  2071. NetpKdPrint((
  2072. "UserpSetInfo: Invalid field type on initial scan."
  2073. " Index:%ld\n", UasSamIndex ));
  2074. }
  2075. NetStatus = NERR_InternalError;
  2076. goto Cleanup;
  2077. }
  2078. //
  2079. //
  2080. // Accumulate the desired access to do all this functionality.
  2081. DesiredAccess |= SAM_FIELD(UasSamIndex).DesiredAccess;
  2082. //
  2083. // Accumalate which fields are being changed in the
  2084. // USER_ALL_INFORMATION structure.
  2085. UserAll.WhichFields |= SAM_FIELD(UasSamIndex).WhichField;
  2086. }
  2087. //
  2088. // Check to be sure the user specified a valid Level.
  2089. //
  2090. // The search of the UserpUasSamTable should have resulted in
  2091. // at least one match if the arguments are valid.
  2092. //
  2093. if ( DesiredAccess == 0 ) {
  2094. NetpSetParmError( PARM_ERROR_UNKNOWN );
  2095. NetStatus = ERROR_INVALID_PARAMETER;
  2096. IF_DEBUG( UAS_DEBUG_USER ) {
  2097. NetpKdPrint(( "UserpSetInfo: Desired Access == 0\n" ));
  2098. }
  2099. goto Cleanup;
  2100. }
  2101. //
  2102. // Open the user asking for accumulated desired access
  2103. //
  2104. // If a UserHandle was passed in, use it.
  2105. //
  2106. if ( ARGUMENT_PRESENT( UserHandle ) ) {
  2107. LocalUserHandle = UserHandle;
  2108. } else {
  2109. IF_DEBUG( UAS_DEBUG_USER ) {
  2110. NetpKdPrint(( "UserpSetInfo: Desired Access %lX\n", DesiredAccess ));
  2111. }
  2112. NetStatus = UserpOpenUser( DomainHandle,
  2113. DesiredAccess,
  2114. UserName,
  2115. &LocalUserHandle,
  2116. &UserRelativeId );
  2117. if ( NetStatus != NERR_Success ) {
  2118. IF_DEBUG( UAS_DEBUG_USER ) {
  2119. NetpKdPrint(( "UserpSetInfo: UserpOpenUser returns %ld\n",
  2120. NetStatus ));
  2121. }
  2122. goto Cleanup;
  2123. }
  2124. }
  2125. //
  2126. // If an ordinary user created this user (SamCreateUser2InDomain),
  2127. // we must mask off the fields which a user cannot set.
  2128. //
  2129. UserAll.WhichFields &= WhichFieldsMask;
  2130. //
  2131. // Handle Account control
  2132. //
  2133. // Set the individual bits. Notice that I don't change any of
  2134. // the bits which aren't defined by the UAS API.
  2135. //
  2136. if ( UserAll.WhichFields & USER_ALL_USERACCOUNTCONTROL ) {
  2137. USER_CONTROL_INFORMATION *UserControl = NULL;
  2138. //
  2139. // Use the current value of UserAccountControl as the proposed
  2140. // new value of UserAccountControl.
  2141. //
  2142. Status = SamQueryInformationUser( LocalUserHandle,
  2143. UserControlInformation,
  2144. (PVOID *)&UserControl);
  2145. if ( ! NT_SUCCESS( Status ) ) {
  2146. IF_DEBUG( UAS_DEBUG_USER ) {
  2147. NetpKdPrint((
  2148. "UserpGetInfo: SamQueryInformationUser returns %lX\n",
  2149. Status ));
  2150. }
  2151. NetStatus = NetpNtStatusToApiStatus( Status );
  2152. goto Cleanup;
  2153. }
  2154. UserAll.UserAccountControl = UserControl->UserAccountControl;
  2155. Status = SamFreeMemory( UserControl );
  2156. NetpAssert( NT_SUCCESS(Status) );
  2157. //
  2158. // Leave all bits not defined by the UAS API alone,
  2159. // including account type bits.
  2160. //
  2161. UserAll.UserAccountControl &= ~(USER_ACCOUNT_DISABLED |
  2162. USER_HOME_DIRECTORY_REQUIRED |
  2163. USER_PASSWORD_NOT_REQUIRED |
  2164. USER_DONT_EXPIRE_PASSWORD |
  2165. USER_ACCOUNT_AUTO_LOCKED |
  2166. USER_MNS_LOGON_ACCOUNT |
  2167. USER_ENCRYPTED_TEXT_PASSWORD_ALLOWED |
  2168. USER_SMARTCARD_REQUIRED |
  2169. USER_TRUSTED_FOR_DELEGATION |
  2170. USER_NOT_DELEGATED |
  2171. USER_USE_DES_KEY_ONLY |
  2172. USER_DONT_REQUIRE_PREAUTH |
  2173. USER_PASSWORD_EXPIRED
  2174. );
  2175. if (UasUserFlags & UF_ACCOUNTDISABLE) {
  2176. UserAll.UserAccountControl |= USER_ACCOUNT_DISABLED;
  2177. }
  2178. if (UasUserFlags & UF_HOMEDIR_REQUIRED) {
  2179. UserAll.UserAccountControl |= USER_HOME_DIRECTORY_REQUIRED;
  2180. }
  2181. if (UasUserFlags & UF_PASSWD_NOTREQD) {
  2182. UserAll.UserAccountControl |= USER_PASSWORD_NOT_REQUIRED;
  2183. }
  2184. if (UasUserFlags & UF_DONT_EXPIRE_PASSWD) {
  2185. UserAll.UserAccountControl |= USER_DONT_EXPIRE_PASSWORD;
  2186. }
  2187. if (UasUserFlags & UF_LOCKOUT) {
  2188. UserAll.UserAccountControl |= USER_ACCOUNT_AUTO_LOCKED;
  2189. }
  2190. if (UasUserFlags & UF_MNS_LOGON_ACCOUNT) {
  2191. UserAll.UserAccountControl |= USER_MNS_LOGON_ACCOUNT;
  2192. }
  2193. if (UasUserFlags & UF_ENCRYPTED_TEXT_PASSWORD_ALLOWED) {
  2194. (UserAll.UserAccountControl) |= USER_ENCRYPTED_TEXT_PASSWORD_ALLOWED;
  2195. }
  2196. if (UasUserFlags & UF_SMARTCARD_REQUIRED) {
  2197. (UserAll.UserAccountControl) |= USER_SMARTCARD_REQUIRED;
  2198. }
  2199. if (UasUserFlags & UF_TRUSTED_FOR_DELEGATION) {
  2200. (UserAll.UserAccountControl) |= USER_TRUSTED_FOR_DELEGATION;
  2201. }
  2202. if (UasUserFlags & UF_NOT_DELEGATED) {
  2203. (UserAll.UserAccountControl) |= USER_NOT_DELEGATED;
  2204. }
  2205. if (UasUserFlags & UF_USE_DES_KEY_ONLY) {
  2206. (UserAll.UserAccountControl) |= USER_USE_DES_KEY_ONLY;
  2207. }
  2208. if (UasUserFlags & UF_DONT_REQUIRE_PREAUTH) {
  2209. (UserAll.UserAccountControl) |= USER_DONT_REQUIRE_PREAUTH;
  2210. }
  2211. if (UasUserFlags & UF_PASSWORD_EXPIRED) {
  2212. (UserAll.UserAccountControl) |= USER_PASSWORD_EXPIRED;
  2213. }
  2214. if (UasUserFlags & UF_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION) {
  2215. (UserAll.UserAccountControl) |= USER_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION;
  2216. }
  2217. //
  2218. // Set the account type bit.
  2219. //
  2220. // If no account type bit is set in user specified flag,
  2221. // then leave this bit as it is.
  2222. //
  2223. if( UasUserFlags & UF_ACCOUNT_TYPE_MASK ) {
  2224. ULONG NewSamAccountType;
  2225. ULONG OldSamAccountType;
  2226. OldSamAccountType =
  2227. (UserAll.UserAccountControl) & USER_ACCOUNT_TYPE_MASK;
  2228. //
  2229. // Determine what the new account type should be.
  2230. //
  2231. if ( UasUserFlags & UF_TEMP_DUPLICATE_ACCOUNT ) {
  2232. NewSamAccountType = USER_TEMP_DUPLICATE_ACCOUNT;
  2233. } else if ( UasUserFlags & UF_NORMAL_ACCOUNT ) {
  2234. NewSamAccountType = USER_NORMAL_ACCOUNT;
  2235. } else if (UasUserFlags & UF_INTERDOMAIN_TRUST_ACCOUNT){
  2236. NewSamAccountType = USER_INTERDOMAIN_TRUST_ACCOUNT;
  2237. } else if (UasUserFlags & UF_WORKSTATION_TRUST_ACCOUNT){
  2238. NewSamAccountType = USER_WORKSTATION_TRUST_ACCOUNT;
  2239. } else if ( UasUserFlags & UF_SERVER_TRUST_ACCOUNT ) {
  2240. NewSamAccountType = USER_SERVER_TRUST_ACCOUNT;
  2241. } else {
  2242. IF_DEBUG( UAS_DEBUG_USER ) {
  2243. NetpKdPrint((
  2244. "UserpSetInfo: Invalid account type (3)\n"));
  2245. }
  2246. NetStatus = NERR_InternalError;
  2247. goto Cleanup;
  2248. }
  2249. #ifdef notdef
  2250. //
  2251. // If we are not creating this user,
  2252. // and either the old or the new account type is a machine account,
  2253. // don't allow the account type to change.
  2254. //
  2255. // Allow changes between 'normal' and 'temp_duplicate'
  2256. //
  2257. if ( UserHandle == NULL &&
  2258. NewSamAccountType != OldSamAccountType &&
  2259. ((OldSamAccountType & USER_MACHINE_ACCOUNT_MASK) ||
  2260. (NewSamAccountType & USER_MACHINE_ACCOUNT_MASK))) {
  2261. NetpSetParmError( USER_FLAGS_PARMNUM );
  2262. NetStatus = ERROR_INVALID_PARAMETER;
  2263. IF_DEBUG( UAS_DEBUG_USER ) {
  2264. NetpKdPrint((
  2265. "UserpSetInfo: Attempt to change account "
  2266. " type Old: %lx New: %lx\n",
  2267. OldSamAccountType,
  2268. NewSamAccountType ));
  2269. }
  2270. goto Cleanup;
  2271. }
  2272. #endif // notdef
  2273. //
  2274. // Use the new Account Type.
  2275. //
  2276. UserAll.UserAccountControl &= ~USER_ACCOUNT_TYPE_MASK;
  2277. UserAll.UserAccountControl |= NewSamAccountType;
  2278. //
  2279. // If SAM has none of its bits set,
  2280. // set USER_NORMAL_ACCOUNT.
  2281. //
  2282. } else if ((UserAll.UserAccountControl & USER_ACCOUNT_TYPE_MASK) == 0 ){
  2283. UserAll.UserAccountControl |= USER_NORMAL_ACCOUNT;
  2284. }
  2285. }
  2286. //
  2287. // Validate the usriX_priv and usrix_auth_flags fields
  2288. //
  2289. if ( ValidatePriv || ValidateAuthFlags ) {
  2290. DWORD OldPriv, OldAuthFlags;
  2291. //
  2292. // If this is a 'create' operation, just mandate that
  2293. // the values be reasonable. These reasonable values
  2294. // are what UserpGetUserPriv probably would return, unless
  2295. // of course someone puts the 'user' group in one of the
  2296. // aliases.
  2297. //
  2298. if ( UserHandle != NULL ) {
  2299. OldPriv = USER_PRIV_USER;
  2300. OldAuthFlags = 0;
  2301. //
  2302. // On a 'set' operation, just get the previous values.
  2303. //
  2304. } else {
  2305. NetStatus = UserpGetUserPriv(
  2306. BuiltinDomainHandle,
  2307. LocalUserHandle,
  2308. UserRelativeId,
  2309. DomainId,
  2310. &OldPriv,
  2311. &OldAuthFlags
  2312. );
  2313. if ( NetStatus != NERR_Success ) {
  2314. goto Cleanup;
  2315. }
  2316. }
  2317. //
  2318. // Ensure AUTH_FLAGS isn't being changed.
  2319. //
  2320. if ( ValidateAuthFlags ) {
  2321. if ( NewAuthFlags != OldAuthFlags ) {
  2322. NetpSetParmError( USER_AUTH_FLAGS_PARMNUM );
  2323. NetStatus = ERROR_INVALID_PARAMETER;
  2324. IF_DEBUG( UAS_DEBUG_USER ) {
  2325. NetpKdPrint((
  2326. "UserpSetInfo: Old AuthFlag %ld New AuthFlag %ld\n",
  2327. OldAuthFlags,
  2328. NewAuthFlags ));
  2329. }
  2330. goto Cleanup;
  2331. }
  2332. }
  2333. //
  2334. // Ensure PRIV isn't being changed.
  2335. //
  2336. if ( ValidatePriv ) {
  2337. if ( NewPriv != OldPriv ) {
  2338. NetpSetParmError( USER_PRIV_PARMNUM );
  2339. NetStatus = ERROR_INVALID_PARAMETER;
  2340. IF_DEBUG( UAS_DEBUG_USER ) {
  2341. NetpKdPrint((
  2342. "UserpSetInfo: Old Priv %ld New Priv %ld\n",
  2343. OldPriv,
  2344. NewPriv ));
  2345. }
  2346. goto Cleanup;
  2347. }
  2348. }
  2349. }
  2350. //
  2351. // Handle changes to the User Dacl
  2352. //
  2353. if ( HandleUserDacl ) {
  2354. DWORD DaclSize;
  2355. PACCESS_ALLOWED_ACE Ace;
  2356. SID_IDENTIFIER_AUTHORITY WorldAuthority = SECURITY_WORLD_SID_AUTHORITY;
  2357. //
  2358. // Build the sid for the user
  2359. //
  2360. NetStatus = NetpSamRidToSid(
  2361. LocalUserHandle,
  2362. UserRelativeId,
  2363. &UserSid
  2364. );
  2365. if (NetStatus != NERR_Success) {
  2366. goto Cleanup;
  2367. }
  2368. //
  2369. // Get the DACL for the user record.
  2370. //
  2371. NetStatus = UserpGetDacl( LocalUserHandle,
  2372. &OldUserDacl,
  2373. &DaclSize );
  2374. if ( NetStatus != NERR_Success ) {
  2375. goto Cleanup;
  2376. }
  2377. //
  2378. // If there is no DACL, just ignore that fact.
  2379. //
  2380. if ( OldUserDacl != NULL ) {
  2381. SID_IDENTIFIER_AUTHORITY WorldSidAuthority = SECURITY_WORLD_SID_AUTHORITY;
  2382. DWORD WorldSid[sizeof(SID)/sizeof(DWORD) + SID_MAX_SUB_AUTHORITIES ];
  2383. //
  2384. // Build a copy of the world SID for later comparison.
  2385. //
  2386. RtlInitializeSid( (PSID) WorldSid, &WorldSidAuthority, 1 );
  2387. *(RtlSubAuthoritySid( (PSID)WorldSid, 0 )) = SECURITY_WORLD_RID;
  2388. //
  2389. // Make a copy of the DACL that reflect the new UAS field.
  2390. //
  2391. NewUserDacl = NetpMemoryAllocate( DaclSize );
  2392. if ( NewUserDacl == NULL ) {
  2393. IF_DEBUG( UAS_DEBUG_USER ) {
  2394. NetpKdPrint(( "UserpSetInfo: no DACL memory %ld\n",
  2395. DaclSize ));
  2396. }
  2397. NetStatus = ERROR_NOT_ENOUGH_MEMORY;
  2398. goto Cleanup;
  2399. }
  2400. NetpMoveMemory( NewUserDacl, OldUserDacl, DaclSize );
  2401. //
  2402. // The UF_PASSWD_CANT_CHANGE bit is implemented by the
  2403. // ACL on the user object in SAM. When
  2404. // UF_PASSWD_CANT_CHANGE is on, the ACL doesn't allow
  2405. // World or the user himself USER_CHANGE_PASSWORD access.
  2406. // We set/clear the USER_CHANGE_PASSWORD access
  2407. // bit in the ACEs for the user and for World. This leaves
  2408. // Administrators and Account Operators with
  2409. // USER_ALL_ACCESS access.
  2410. //
  2411. // If the DACL for the user has been set by anyone
  2412. // other than the NetUser APIs, this action may
  2413. // not accurately reflect whether the password can
  2414. // be changed. We silently ignore ACLs we don't
  2415. // recognize.
  2416. //
  2417. //
  2418. // Point Ace to the first ACE.
  2419. //
  2420. for ( AceIndex = 0;
  2421. AceIndex < NewUserDacl->AceCount;
  2422. AceIndex++ ) {
  2423. Status = RtlGetAce(
  2424. NewUserDacl,
  2425. AceIndex,
  2426. (PVOID) &Ace
  2427. );
  2428. if ( !NT_SUCCESS(Status) ) {
  2429. break;
  2430. }
  2431. //
  2432. // If the sid in the ACE matches either the world SID
  2433. // or the User's SID, modify the access mask.
  2434. //
  2435. if ( RtlEqualSid(
  2436. &Ace->SidStart,
  2437. (PSID)WorldSid) ||
  2438. RtlEqualSid(
  2439. &Ace->SidStart,
  2440. UserSid) ) {
  2441. //
  2442. // Twiddle the USER_CHANGE_PASSWORD access bit.
  2443. //
  2444. if ( Ace->Mask & USER_CHANGE_PASSWORD ) {
  2445. if ( UasUserFlags & UF_PASSWD_CANT_CHANGE ) {
  2446. Ace->Mask &= ~USER_CHANGE_PASSWORD;
  2447. UserDaclChanged = TRUE;
  2448. }
  2449. } else {
  2450. if ( (UasUserFlags & UF_PASSWD_CANT_CHANGE) == 0 ) {
  2451. Ace->Mask |= USER_CHANGE_PASSWORD;
  2452. UserDaclChanged = TRUE;
  2453. }
  2454. }
  2455. }
  2456. }
  2457. //
  2458. // Set the DACL if it needs to be.
  2459. //
  2460. if ( UserDaclChanged ) {
  2461. NetStatus = UserpSetDacl( LocalUserHandle, NewUserDacl );
  2462. if ( NetStatus != NERR_Success ) {
  2463. goto Cleanup;
  2464. }
  2465. }
  2466. }
  2467. }
  2468. //
  2469. // If there is anything changed in the 'UserAll' structure,
  2470. // tell SAM about the changes.
  2471. //
  2472. //
  2473. // N.B. Because some of the NET fields are not treated as SAM fields
  2474. // (UT_PRIV and UT_MAX_STORAGE), there may be nothing to change. However,
  2475. // for app compat, continue to call SamSetInformationUser
  2476. //
  2477. Status = SamSetInformationUser(
  2478. LocalUserHandle,
  2479. UserAllInformation,
  2480. &UserAll );
  2481. if ( !NT_SUCCESS(Status) ) {
  2482. IF_DEBUG( UAS_DEBUG_USER ) {
  2483. NetpKdPrint((
  2484. "UserpSetInfo: SamSetInformationUser returns %lX\n",
  2485. Status ));
  2486. }
  2487. NetpSetParmError( PARM_ERROR_UNKNOWN );
  2488. NetStatus = NetpNtStatusToApiStatus( Status );
  2489. goto Cleanup;
  2490. }
  2491. NetStatus = NERR_Success;
  2492. //
  2493. // Clean up.
  2494. //
  2495. Cleanup:
  2496. //
  2497. // If we've changed the DACL on the user and we've not been able
  2498. // to change everything, put the DACL back as we found it.
  2499. //
  2500. if ( NetStatus != NERR_Success && UserDaclChanged ) {
  2501. NET_API_STATUS NetStatus2;
  2502. NetStatus2 = UserpSetDacl( LocalUserHandle, OldUserDacl );
  2503. ASSERT( NetStatus2 == NERR_Success );
  2504. }
  2505. //
  2506. // If a handle to the user was opened by this routine,
  2507. // close it.
  2508. //
  2509. if (!ARGUMENT_PRESENT( UserHandle ) && LocalUserHandle != NULL) {
  2510. (VOID) SamCloseHandle( LocalUserHandle );
  2511. }
  2512. //
  2513. // Free any locally used recources.
  2514. //
  2515. if ( NewUserDacl != NULL ) {
  2516. NetpMemoryFree( NewUserDacl );
  2517. }
  2518. if ( OldUserDacl != NULL ) {
  2519. NetpMemoryFree( OldUserDacl );
  2520. }
  2521. if ( UserSid != NULL ) {
  2522. NetpMemoryFree( UserSid );
  2523. }
  2524. IF_DEBUG( UAS_DEBUG_USER ) {
  2525. NetpKdPrint(( "UserpSetInfo: returning %ld\n", NetStatus ));
  2526. }
  2527. return NetStatus;
  2528. } // UserpSetInfo
  2529. NET_API_STATUS
  2530. NetpSamRidToSid(
  2531. IN SAM_HANDLE SamHandle,
  2532. IN ULONG RelativeId,
  2533. OUT PSID *Sid
  2534. )
  2535. /*++
  2536. Routine Description:
  2537. Given a Rid returned from a Sam Handle, return the SID for that account.
  2538. Arguments:
  2539. SamHandle - a valid SAM handle
  2540. RelativeId - a RID obtained from a SAM call that used SamHandle
  2541. Sid - Returns a pointer to an allocated buffer containing the resultant
  2542. Sid. Free this buffer using NetpMemoryFree.
  2543. Return Value:
  2544. 0 - if successful
  2545. NERR_UserNotFound if the Rid could not be mapped to a SID
  2546. a resource error, otherwise
  2547. --*/
  2548. {
  2549. NTSTATUS NtStatus = STATUS_SUCCESS;
  2550. PSID SamSid;
  2551. DWORD err = 0;
  2552. NtStatus = SamRidToSid(SamHandle,
  2553. RelativeId,
  2554. &SamSid);
  2555. if (NT_SUCCESS(NtStatus)) {
  2556. ULONG Length = RtlLengthSid(SamSid);
  2557. (*Sid) = NetpMemoryAllocate(Length);
  2558. if ((*Sid)) {
  2559. RtlCopySid(Length, (*Sid), SamSid);
  2560. } else {
  2561. err = ERROR_NOT_ENOUGH_MEMORY;
  2562. }
  2563. SamFreeMemory(SamSid);
  2564. } else if ( STATUS_NOT_FOUND == NtStatus ) {
  2565. // This is unexpected -- the user RID could not be
  2566. // found
  2567. err = NERR_UserNotFound;
  2568. } else {
  2569. // a resource error occurred
  2570. err = RtlNtStatusToDosError(NtStatus);
  2571. }
  2572. return err;
  2573. }
  2574. /*lint +e614 */
  2575. /*lint +e740 */