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.

778 lines
17 KiB

  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. Module Name:
  4. accessp.c
  5. Abstract:
  6. Internal routines shared by NetUser API and Netlogon service. These
  7. routines convert from SAM specific data formats to UAS specific data
  8. formats.
  9. Author:
  10. Cliff Van Dyke (cliffv) 29-Aug-1991
  11. Environment:
  12. User mode only.
  13. Contains NT-specific code.
  14. Requires ANSI C extensions: slash-slash comments, long external names.
  15. Revision History:
  16. 22-Oct-1991 JohnRo
  17. Made changes suggested by PC-LINT.
  18. 04-Dec-1991 JohnRo
  19. Trying to get around a weird MIPS compiler bug.
  20. --*/
  21. #include <nt.h>
  22. #include <ntrtl.h>
  23. #include <nturtl.h>
  24. #undef DOMAIN_ALL_ACCESS // defined in both ntsam.h and ntwinapi.h
  25. #include <ntsam.h>
  26. #include <windef.h>
  27. #include <lmcons.h>
  28. #include <accessp.h>
  29. #include <debuglib.h>
  30. #include <lmaccess.h>
  31. #include <netdebug.h>
  32. #include <netsetp.h>
  33. #if(_WIN32_WINNT >= 0x0500)
  34. NET_API_STATUS
  35. NET_API_FUNCTION
  36. NetpSetDnsComputerNameAsRequired(
  37. IN PWSTR DnsDomainName
  38. )
  39. /*++
  40. Routine Description:
  41. Determines if the machine is set to update the machine Dns computer name based on changes
  42. to the Dns domain name. If so, the new value is set. Otherwise, no action is taken.
  43. Arguments:
  44. DnsDomainName - New Dns domain name of this machine
  45. Return Value:
  46. NERR_Success -- Success
  47. --*/
  48. {
  49. NET_API_STATUS NetStatus = NERR_Success;
  50. HKEY SyncKey;
  51. DWORD ValueType, Value, Length;
  52. BOOLEAN SetName = FALSE;
  53. PWCHAR AbsoluteSignifier = NULL;
  54. if ( DnsDomainName == NULL ) {
  55. return ERROR_INVALID_PARAMETER;
  56. }
  57. //
  58. // See if we should be doing the name change
  59. //
  60. NetStatus = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  61. L"System\\CurrentControlSet\\Services\\Tcpip\\Parameters",
  62. 0,
  63. KEY_QUERY_VALUE,
  64. &SyncKey );
  65. if ( NetStatus == NERR_Success ) {
  66. Length = sizeof( ULONG );
  67. NetStatus = RegQueryValueEx( SyncKey,
  68. L"SyncDomainWithMembership",
  69. NULL,
  70. &ValueType,
  71. ( LPBYTE )&Value,
  72. &Length );
  73. if ( NetStatus == NERR_Success) {
  74. if ( Value == 1 ) {
  75. SetName = TRUE;
  76. }
  77. } else if ( NetStatus == ERROR_FILE_NOT_FOUND ) {
  78. NetStatus = NERR_Success;
  79. SetName = TRUE;
  80. }
  81. RegCloseKey( SyncKey );
  82. }
  83. if ( NetStatus == NERR_Success && SetName == TRUE ) {
  84. //
  85. // If we've got an absolute Dns domain name, shorten it up...
  86. //
  87. if ( wcslen(DnsDomainName) > 0 ) {
  88. AbsoluteSignifier = &DnsDomainName[ wcslen( DnsDomainName ) - 1 ];
  89. if ( *AbsoluteSignifier == L'.' ) {
  90. *AbsoluteSignifier = UNICODE_NULL;
  91. } else {
  92. AbsoluteSignifier = NULL;
  93. }
  94. }
  95. if ( !SetComputerNameEx( ComputerNamePhysicalDnsDomain, DnsDomainName ) ) {
  96. NetStatus = GetLastError();
  97. }
  98. if ( AbsoluteSignifier ) {
  99. *AbsoluteSignifier = L'.';
  100. }
  101. }
  102. return( NetStatus );
  103. }
  104. #endif
  105. VOID
  106. NetpGetAllowedAce(
  107. IN PACL Dacl,
  108. IN PSID Sid,
  109. OUT PVOID *Ace
  110. )
  111. /*++
  112. Routine Description:
  113. Given a DACL, find an AccessAllowed ACE containing a particuar SID.
  114. Arguments:
  115. Dacl - A pointer to the ACL to search.
  116. Sid - A pointer to the Sid to search for.
  117. Ace - Returns a pointer to the specified ACE. Returns NULL if there
  118. is no such ACE
  119. Return Value:
  120. None.
  121. --*/
  122. {
  123. NTSTATUS Status;
  124. ACL_SIZE_INFORMATION AclSize;
  125. DWORD AceIndex;
  126. //
  127. // Determine the size of the DACL so we can copy it
  128. //
  129. Status = RtlQueryInformationAcl(
  130. Dacl,
  131. &AclSize,
  132. sizeof(AclSize),
  133. AclSizeInformation );
  134. if ( ! NT_SUCCESS( Status ) ) {
  135. IF_DEBUG( ACCESSP ) {
  136. NetpKdPrint((
  137. "NetpGetDacl: RtlQueryInformationAcl returns %lX\n",
  138. Status ));
  139. }
  140. *Ace = NULL;
  141. return;
  142. }
  143. //
  144. // Loop through the ACEs looking for an ACCESS_ALLOWED ACE with the
  145. // right SID.
  146. //
  147. for ( AceIndex=0; AceIndex<AclSize.AceCount; AceIndex++ ) {
  148. Status = RtlGetAce( Dacl, AceIndex, (PVOID *)Ace );
  149. if ( ! NT_SUCCESS( Status ) ) {
  150. *Ace = NULL;
  151. return;
  152. }
  153. if ( ((PACE_HEADER)*Ace)->AceType != ACCESS_ALLOWED_ACE_TYPE ) {
  154. continue;
  155. }
  156. if ( RtlEqualSid( Sid,
  157. (PSID)&((PACCESS_ALLOWED_ACE)(*Ace))->SidStart )
  158. ){
  159. return;
  160. }
  161. }
  162. //
  163. // Couldn't find any such ACE.
  164. //
  165. *Ace = NULL;
  166. return;
  167. }
  168. DWORD
  169. NetpAccountControlToFlags(
  170. IN DWORD UserAccountControl,
  171. IN PACL UserDacl
  172. )
  173. /*++
  174. Routine Description:
  175. Convert a SAM UserAccountControl field and the Discretionary ACL for
  176. the user into the NetUser API usriX_flags field.
  177. Arguments:
  178. UserAccountControl - The SAM UserAccountControl field for the user.
  179. UserDacl - The Discretionary ACL for the user.
  180. Return Value:
  181. Returns the usriX_flags field for the user.
  182. --*/
  183. {
  184. SID_IDENTIFIER_AUTHORITY WorldSidAuthority = SECURITY_WORLD_SID_AUTHORITY;
  185. DWORD WorldSid[sizeof(SID)/sizeof(DWORD) + SID_MAX_SUB_AUTHORITIES ];
  186. PACCESS_ALLOWED_ACE Ace;
  187. DWORD Flags = UF_SCRIPT;
  188. //
  189. // Build a copy of the world SID for later comparison.
  190. //
  191. RtlInitializeSid( (PSID) WorldSid, &WorldSidAuthority, 1 );
  192. *(RtlSubAuthoritySid( (PSID)WorldSid, 0 )) = SECURITY_WORLD_RID;
  193. //
  194. // Determine if the UF_PASSWD_CANT_CHANGE bit should be returned
  195. //
  196. // Return UF_PASSWD_CANT_CHANGE unless the world can change the
  197. // password.
  198. //
  199. //
  200. // If the user has no DACL, the password can change
  201. //
  202. if ( UserDacl != NULL ) {
  203. //
  204. // Find the WORLD grant ACE
  205. //
  206. NetpGetAllowedAce( UserDacl, (PSID) WorldSid, (PVOID *)&Ace );
  207. if ( Ace == NULL ) {
  208. Flags |= UF_PASSWD_CANT_CHANGE;
  209. } else {
  210. if ( (Ace->Mask & USER_CHANGE_PASSWORD) == 0 ) {
  211. Flags |= UF_PASSWD_CANT_CHANGE;
  212. }
  213. }
  214. }
  215. //
  216. // Set all other bits as a function of the SAM UserAccountControl
  217. //
  218. if ( UserAccountControl & USER_ACCOUNT_DISABLED ) {
  219. Flags |= UF_ACCOUNTDISABLE;
  220. }
  221. if ( UserAccountControl & USER_HOME_DIRECTORY_REQUIRED ){
  222. Flags |= UF_HOMEDIR_REQUIRED;
  223. }
  224. if ( UserAccountControl & USER_PASSWORD_NOT_REQUIRED ){
  225. Flags |= UF_PASSWD_NOTREQD;
  226. }
  227. if ( UserAccountControl & USER_DONT_EXPIRE_PASSWORD ){
  228. Flags |= UF_DONT_EXPIRE_PASSWD;
  229. }
  230. if ( UserAccountControl & USER_ACCOUNT_AUTO_LOCKED ){
  231. Flags |= UF_LOCKOUT;
  232. }
  233. if ( UserAccountControl & USER_MNS_LOGON_ACCOUNT ){
  234. Flags |= UF_MNS_LOGON_ACCOUNT;
  235. }
  236. if ( UserAccountControl & USER_ENCRYPTED_TEXT_PASSWORD_ALLOWED ){
  237. Flags |= UF_ENCRYPTED_TEXT_PASSWORD_ALLOWED;
  238. }
  239. if ( UserAccountControl & USER_SMARTCARD_REQUIRED ){
  240. Flags |= UF_SMARTCARD_REQUIRED;
  241. }
  242. if ( UserAccountControl & USER_TRUSTED_FOR_DELEGATION ){
  243. Flags |= UF_TRUSTED_FOR_DELEGATION;
  244. }
  245. if ( UserAccountControl & USER_NOT_DELEGATED ){
  246. Flags |= UF_NOT_DELEGATED;
  247. }
  248. if ( UserAccountControl & USER_USE_DES_KEY_ONLY ){
  249. Flags |= UF_USE_DES_KEY_ONLY;
  250. }
  251. if ( UserAccountControl & USER_DONT_REQUIRE_PREAUTH) {
  252. Flags |= UF_DONT_REQUIRE_PREAUTH;
  253. }
  254. if ( UserAccountControl & USER_PASSWORD_EXPIRED) {
  255. Flags |= UF_PASSWORD_EXPIRED;
  256. }
  257. if ( UserAccountControl & USER_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION) {
  258. Flags |= UF_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION;
  259. }
  260. //
  261. // set account type bit.
  262. //
  263. //
  264. // account type bit are exculsive and precisely only one
  265. // account type bit is set. So, as soon as an account type bit is set
  266. // in the following if sequence we can return.
  267. //
  268. if( UserAccountControl & USER_TEMP_DUPLICATE_ACCOUNT ) {
  269. Flags |= UF_TEMP_DUPLICATE_ACCOUNT;
  270. } else if( UserAccountControl & USER_NORMAL_ACCOUNT ) {
  271. Flags |= UF_NORMAL_ACCOUNT;
  272. } else if( UserAccountControl & USER_INTERDOMAIN_TRUST_ACCOUNT ) {
  273. Flags |= UF_INTERDOMAIN_TRUST_ACCOUNT;
  274. } else if( UserAccountControl & USER_WORKSTATION_TRUST_ACCOUNT ) {
  275. Flags |= UF_WORKSTATION_TRUST_ACCOUNT;
  276. } else if( UserAccountControl & USER_SERVER_TRUST_ACCOUNT ) {
  277. Flags |= UF_SERVER_TRUST_ACCOUNT;
  278. } else {
  279. //
  280. // There is no known account type bit set in UserAccountControl.
  281. // ?? Flags |= UF_NORMAL_ACCOUNT;
  282. // NetpAssert( FALSE );
  283. }
  284. return Flags;
  285. }
  286. ULONG
  287. NetpDeltaTimeToSeconds(
  288. IN LARGE_INTEGER DeltaTime
  289. )
  290. /*++
  291. Routine Description:
  292. Convert an NT delta time specification to seconds
  293. Arguments:
  294. DeltaTime - Specifies the NT Delta time to convert. NT delta time is
  295. a negative number of 100ns units.
  296. Return Value:
  297. Returns the number of seconds. Any invalid or too large input
  298. returns TIMEQ_FOREVER.
  299. --*/
  300. {
  301. LARGE_INTEGER LargeSeconds;
  302. //
  303. // These are the magic numbers needed to do our extended division by
  304. // 10,000,000 = convert 100ns tics to one second tics
  305. //
  306. LARGE_INTEGER Magic10000000 = { (ULONG) 0xe57a42bd, (LONG) 0xd6bf94d5};
  307. #define SHIFT10000000 23
  308. //
  309. // Special case zero.
  310. //
  311. if ( DeltaTime.HighPart == 0 && DeltaTime.LowPart == 0 ) {
  312. return( 0 );
  313. }
  314. //
  315. // Convert the Delta time to a Large integer seconds.
  316. //
  317. LargeSeconds = RtlExtendedMagicDivide(
  318. DeltaTime,
  319. Magic10000000,
  320. SHIFT10000000 );
  321. #ifdef notdef
  322. NetpKdPrint(( "NetpDeltaTimeToSeconds: %lx %lx %lx %lx\n",
  323. DeltaTime.HighPart,
  324. DeltaTime.LowPart,
  325. LargeSeconds.HighPart,
  326. LargeSeconds.LowPart ));
  327. #endif // notdef
  328. //
  329. // Return too large a number or a positive number as TIMEQ_FOREVER
  330. //
  331. if ( LargeSeconds.HighPart != -1 ) {
  332. return TIMEQ_FOREVER;
  333. }
  334. return ( (ULONG)(- ((LONG)(LargeSeconds.LowPart))) );
  335. } // NetpDeltaTimeToSeconds
  336. LARGE_INTEGER
  337. NetpSecondsToDeltaTime(
  338. IN ULONG Seconds
  339. )
  340. /*++
  341. Routine Description:
  342. Convert a number of seconds to an NT delta time specification
  343. Arguments:
  344. Seconds - a positive number of seconds
  345. Return Value:
  346. Returns the NT Delta time. NT delta time is a negative number
  347. of 100ns units.
  348. --*/
  349. {
  350. LARGE_INTEGER DeltaTime;
  351. LARGE_INTEGER LargeSeconds;
  352. LARGE_INTEGER Answer;
  353. //
  354. // Special case TIMEQ_FOREVER (return a full scale negative)
  355. //
  356. if ( Seconds == TIMEQ_FOREVER ) {
  357. DeltaTime.LowPart = 0;
  358. DeltaTime.HighPart = (LONG) 0x80000000;
  359. //
  360. // Convert seconds to 100ns units simply by multiplying by 10000000.
  361. //
  362. // Convert to delta time by negating.
  363. //
  364. } else {
  365. LargeSeconds = RtlConvertUlongToLargeInteger( Seconds );
  366. Answer = RtlExtendedIntegerMultiply( LargeSeconds, 10000000 );
  367. if ( Answer.QuadPart < 0 ) {
  368. DeltaTime.LowPart = 0;
  369. DeltaTime.HighPart = (LONG) 0x80000000;
  370. } else {
  371. DeltaTime.QuadPart = -Answer.QuadPart;
  372. }
  373. }
  374. return DeltaTime;
  375. } // NetpSecondsToDeltaTime
  376. VOID
  377. NetpAliasMemberToPriv(
  378. IN ULONG AliasCount,
  379. IN PULONG AliasMembership,
  380. OUT LPDWORD Priv,
  381. OUT LPDWORD AuthFlags
  382. )
  383. /*++
  384. Routine Description:
  385. Converts membership in Aliases to LANMAN 2.0 style Priv and AuthFlags.
  386. Arguments:
  387. AliasCount - Specifies the number of Aliases in the AliasMembership array.
  388. AliasMembership - Specifies the Aliases that are to be converted to Priv
  389. and AuthFlags. Each element in the array specifies the RID of an
  390. alias in the BuiltIn domain.
  391. Priv - Returns the Lanman 2.0 Privilege level for the specified aliases.
  392. AuthFlags - Returns the Lanman 2.0 Authflags for the specified aliases.
  393. Return Value:
  394. None.
  395. --*/
  396. {
  397. DWORD j;
  398. BOOLEAN IsAdmin = FALSE;
  399. BOOLEAN IsUser = FALSE;
  400. //
  401. // Loop through the aliases finding any special aliases.
  402. //
  403. // If this user is the member of multiple operator aliases,
  404. // just "or" the appropriate bits in.
  405. //
  406. // If this user is the member of multiple "privilege" aliases,
  407. // just report the one with the highest privilege.
  408. // Report the user is a member of the Guest aliases by default.
  409. //
  410. *AuthFlags = 0;
  411. for ( j=0; j < AliasCount; j++ ) {
  412. switch ( AliasMembership[j] ) {
  413. case DOMAIN_ALIAS_RID_ADMINS:
  414. IsAdmin = TRUE;
  415. break;
  416. case DOMAIN_ALIAS_RID_USERS:
  417. IsUser = TRUE;
  418. break;
  419. case DOMAIN_ALIAS_RID_ACCOUNT_OPS:
  420. *AuthFlags |= AF_OP_ACCOUNTS;
  421. break;
  422. case DOMAIN_ALIAS_RID_SYSTEM_OPS:
  423. *AuthFlags |= AF_OP_SERVER;
  424. break;
  425. case DOMAIN_ALIAS_RID_PRINT_OPS:
  426. *AuthFlags |= AF_OP_PRINT;
  427. break;
  428. }
  429. }
  430. if ( IsAdmin ) {
  431. *Priv = USER_PRIV_ADMIN;
  432. } else if ( IsUser ) {
  433. *Priv = USER_PRIV_USER;
  434. } else {
  435. *Priv = USER_PRIV_GUEST;
  436. }
  437. }
  438. DWORD
  439. NetpGetElapsedSeconds(
  440. IN PLARGE_INTEGER Time
  441. )
  442. /*++
  443. Routine Description:
  444. Computes the elapsed time in seconds since the time specified.
  445. Returns 0 on error.
  446. Arguments:
  447. Time - Time (typically in the past) to compute the elapsed time from.
  448. Return Value:
  449. 0: on error.
  450. Number of seconds.
  451. --*/
  452. {
  453. LARGE_INTEGER CurrentTime;
  454. DWORD Current1980Time;
  455. DWORD Prior1980Time;
  456. NTSTATUS Status;
  457. //
  458. // Compute the age of the password
  459. //
  460. Status = NtQuerySystemTime( &CurrentTime );
  461. if( !NT_SUCCESS(Status) ) {
  462. return 0;
  463. }
  464. if ( !RtlTimeToSecondsSince1980( &CurrentTime, &Current1980Time) ) {
  465. return 0;
  466. }
  467. if ( !RtlTimeToSecondsSince1980( Time, &Prior1980Time ) ) {
  468. return 0;
  469. }
  470. if ( Current1980Time <= Prior1980Time ) {
  471. return 0;
  472. }
  473. return Current1980Time - Prior1980Time;
  474. }
  475. VOID
  476. NetpConvertWorkstationList(
  477. IN OUT PUNICODE_STRING WorkstationList
  478. )
  479. /*++
  480. Routine Description:
  481. Convert the list of workstations from a comma separated list to
  482. a blank separated list. Any workstation name containing a blank is
  483. silently removed.
  484. Arguments:
  485. WorkstationList - List of workstations to convert
  486. Return Value:
  487. None
  488. --*/
  489. {
  490. LPWSTR Source;
  491. LPWSTR Destination;
  492. LPWSTR EndOfBuffer;
  493. LPWSTR BeginningOfName;
  494. BOOLEAN SkippingName;
  495. ULONG NumberOfCharacters;
  496. //
  497. // Handle the trivial case.
  498. //
  499. if ( WorkstationList->Length == 0 ) {
  500. return;
  501. }
  502. //
  503. // Initialization.
  504. //
  505. Destination = Source = WorkstationList->Buffer;
  506. EndOfBuffer = Source + WorkstationList->Length/sizeof(WCHAR);
  507. //
  508. // Loop handling special characters
  509. //
  510. SkippingName = FALSE;
  511. BeginningOfName = Destination;
  512. while ( Source < EndOfBuffer ) {
  513. switch ( *Source ) {
  514. case ',':
  515. if ( !SkippingName ) {
  516. *Destination = ' ';
  517. Destination++;
  518. }
  519. SkippingName = FALSE;
  520. BeginningOfName = Destination;
  521. break;
  522. case ' ':
  523. SkippingName = TRUE;
  524. Destination = BeginningOfName;
  525. break;
  526. default:
  527. if ( !SkippingName ) {
  528. *Destination = *Source;
  529. Destination ++;
  530. }
  531. break;
  532. }
  533. Source ++;
  534. }
  535. //
  536. // Remove any trailing delimiter
  537. //
  538. NumberOfCharacters = (ULONG)(Destination - WorkstationList->Buffer);
  539. if ( NumberOfCharacters > 0 &&
  540. WorkstationList->Buffer[NumberOfCharacters-1] == ' ' ) {
  541. NumberOfCharacters--;
  542. }
  543. WorkstationList->Length = (USHORT) (NumberOfCharacters * sizeof(WCHAR));
  544. }