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.

649 lines
17 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. secure.c
  5. Abstract:
  6. Security related routines
  7. Author:
  8. Colin Brace (ColinBr)
  9. Environment:
  10. User Mode
  11. Revision History:
  12. --*/
  13. #include <setpch.h>
  14. #include <dssetp.h>
  15. #include "secure.h"
  16. #include <ntsam.h>
  17. #include <samrpc.h>
  18. #include <samisrv.h>
  19. //
  20. // Data global to this module only
  21. //
  22. SECURITY_DESCRIPTOR DsRolepPromoteSD;
  23. SECURITY_DESCRIPTOR DsRolepDemoteSD;
  24. SECURITY_DESCRIPTOR DsRolepCallDsRoleInterfaceSD;
  25. //
  26. // Unlocalized string descriptors for promotion/demotion audits to use
  27. // when unable to load localized resources for some reason.
  28. //
  29. #define DSROLE_AUDIT_PROMOTE_DESC L"Domain Controller Promotion"
  30. #define DSROLE_AUDIT_DEMOTE_DESC L"Domain Controller Demotion"
  31. #define DSROLE_AUDIT_INTERFACE_DESC L"DsRole Interface"
  32. //
  33. // Used to audit anyone attempting server role change operations
  34. //
  35. SID WORLD_SID = {SID_REVISION,
  36. 1,
  37. SECURITY_WORLD_SID_AUTHORITY,
  38. SECURITY_WORLD_RID};
  39. //
  40. // DsRole related access masks
  41. //
  42. #define DSROLE_ROLE_CHANGE_ACCESS 0x00000001
  43. #define DSROLE_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | \
  44. DSROLE_ROLE_CHANGE_ACCESS )
  45. GENERIC_MAPPING DsRolepInfoMapping =
  46. {
  47. STANDARD_RIGHTS_READ, // Generic read
  48. STANDARD_RIGHTS_WRITE, // Generic write
  49. STANDARD_RIGHTS_EXECUTE, // Generic execute
  50. DSROLE_ALL_ACCESS // Generic all
  51. };
  52. //
  53. // Function definitions
  54. //
  55. BOOLEAN
  56. DsRolepMakeSecurityDescriptor(
  57. PSECURITY_DESCRIPTOR psd,
  58. PSID psid,
  59. PACL pacl,
  60. PACL psacl
  61. )
  62. /*++
  63. Routine Description:
  64. This routine creates the Security Descriptor
  65. Arguments:
  66. PSECURITY_DESCRIPTOR psd - a pointer to a SECURITY_DESCRIPTOR which will be constucted
  67. PSID psid - The Sid for the SECURITY_DESCRIPTOR
  68. PACL pacl - The Acl to place on the security Descriptor
  69. Returns:
  70. TRUE if successful; FALSE otherwise
  71. --*/
  72. {
  73. BOOLEAN fSuccess = TRUE;
  74. if ( !InitializeSecurityDescriptor( psd,
  75. SECURITY_DESCRIPTOR_REVISION ) ) {
  76. fSuccess = FALSE;
  77. goto Cleanup;
  78. }
  79. if ( !SetSecurityDescriptorOwner( psd,
  80. psid,
  81. FALSE ) ) { // not defaulted
  82. fSuccess = FALSE;
  83. goto Cleanup;
  84. }
  85. if ( !SetSecurityDescriptorGroup( psd,
  86. psid,
  87. FALSE ) ) { // not defaulted
  88. fSuccess = FALSE;
  89. goto Cleanup;
  90. }
  91. if ( !SetSecurityDescriptorDacl( psd,
  92. TRUE, // DACL is present
  93. pacl,
  94. FALSE ) ) { // not defaulted
  95. fSuccess = FALSE;
  96. goto Cleanup;
  97. }
  98. if ( !SetSecurityDescriptorSacl( psd,
  99. psacl != NULL ? TRUE : FALSE,
  100. psacl,
  101. FALSE ) ) { // not defaulted
  102. fSuccess = FALSE;
  103. goto Cleanup;
  104. }
  105. Cleanup:
  106. return fSuccess;
  107. }
  108. BOOLEAN
  109. DsRolepCreateInterfaceSDs(
  110. VOID
  111. )
  112. /*++
  113. Routine Description:
  114. This routine creates the in memory access control lists that
  115. are used to perform security checks on callers of the DsRoler
  116. API's.
  117. The model is as follows:
  118. Promote: the caller must have the builtin admin SID
  119. Demote: the caller must have the builtin admin SID
  120. CalltheDsRoleInterface: the caller must have the builtin admin SID
  121. Arguments:
  122. None.
  123. Returns:
  124. TRUE if successful; FALSE otherwise
  125. --*/
  126. {
  127. NTSTATUS Status;
  128. BOOLEAN fSuccess = TRUE;
  129. SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;
  130. ULONG AclLength = 0;
  131. ULONG SaclLength = 0;
  132. PSID BuiltinAdminsSid = NULL;
  133. PSID *AllowedSids [] =
  134. {
  135. &BuiltinAdminsSid
  136. };
  137. ULONG cAllowedSids = sizeof(AllowedSids) / sizeof(AllowedSids[0]);
  138. ULONG i;
  139. PACL DsRolepPromoteAcl = NULL;
  140. PACL DsRolepDemoteAcl = NULL;
  141. PACL DsRolepCallDsRoleInterfaceAcl = NULL;
  142. PACL DsRolepSacl = NULL;
  143. //
  144. // Build the builtin administrators sid
  145. //
  146. Status = RtlAllocateAndInitializeSid(
  147. &NtAuthority,
  148. 2,
  149. SECURITY_BUILTIN_DOMAIN_RID,
  150. DOMAIN_ALIAS_RID_ADMINS,
  151. 0, 0, 0, 0, 0, 0,
  152. &BuiltinAdminsSid
  153. );
  154. if ( !NT_SUCCESS( Status ) ) {
  155. fSuccess = FALSE;
  156. goto Cleanup;
  157. }
  158. //
  159. // Determine the required size of the SACL
  160. //
  161. SaclLength = sizeof( ACL ) +
  162. sizeof( SYSTEM_AUDIT_ACE ) +
  163. GetLengthSid( &WORLD_SID );
  164. //
  165. // Make the SACL for auditing role change operation attempts
  166. //
  167. DsRolepSacl = LocalAlloc( 0, SaclLength );
  168. if ( !DsRolepSacl ) {
  169. fSuccess = FALSE;
  170. goto Cleanup;
  171. }
  172. if ( !InitializeAcl( DsRolepSacl, SaclLength, ACL_REVISION ) ) {
  173. fSuccess = FALSE;
  174. goto Cleanup;
  175. }
  176. Status = AddAuditAccessAce(
  177. DsRolepSacl,
  178. ACL_REVISION,
  179. DSROLE_ROLE_CHANGE_ACCESS,
  180. &WORLD_SID,
  181. TRUE,
  182. TRUE
  183. );
  184. if ( !NT_SUCCESS(Status) ) {
  185. fSuccess = FALSE;
  186. goto Cleanup;
  187. }
  188. //
  189. // Calculate how much space we'll need for the ACL
  190. //
  191. AclLength = sizeof( ACL );
  192. for ( i = 0; i < cAllowedSids; i++ ) {
  193. AclLength += (sizeof( ACCESS_ALLOWED_ACE )
  194. - sizeof(DWORD)
  195. + GetLengthSid((*AllowedSids[i])) );
  196. }
  197. DsRolepPromoteAcl = LocalAlloc( 0, AclLength );
  198. if ( !DsRolepPromoteAcl ) {
  199. fSuccess = FALSE;
  200. goto Cleanup;
  201. }
  202. if ( !InitializeAcl( DsRolepPromoteAcl, AclLength, ACL_REVISION ) ) {
  203. fSuccess = FALSE;
  204. goto Cleanup;
  205. }
  206. for ( i = 0; i < cAllowedSids; i++ ) {
  207. if ( !AddAccessAllowedAce( DsRolepPromoteAcl,
  208. ACL_REVISION,
  209. DSROLE_ALL_ACCESS,
  210. *(AllowedSids[i]) ) ) {
  211. fSuccess = FALSE;
  212. goto Cleanup;
  213. }
  214. }
  215. //
  216. // Now make the security descriptor
  217. //
  218. fSuccess = DsRolepMakeSecurityDescriptor(&DsRolepPromoteSD,
  219. BuiltinAdminsSid,
  220. DsRolepPromoteAcl,
  221. DsRolepSacl);
  222. if (!fSuccess) {
  223. goto Cleanup;
  224. }
  225. //
  226. // Make the demote access check the same
  227. //
  228. DsRolepDemoteAcl = LocalAlloc( 0, AclLength );
  229. if ( !DsRolepDemoteAcl ) {
  230. fSuccess = FALSE;
  231. goto Cleanup;
  232. }
  233. RtlCopyMemory( DsRolepDemoteAcl, DsRolepPromoteAcl, AclLength );
  234. //
  235. // Now make the security descriptor
  236. //
  237. fSuccess = DsRolepMakeSecurityDescriptor(&DsRolepDemoteSD,
  238. BuiltinAdminsSid,
  239. DsRolepDemoteAcl,
  240. DsRolepSacl);
  241. if (!fSuccess) {
  242. goto Cleanup;
  243. }
  244. //
  245. // Make the Call interface access check the same
  246. //
  247. DsRolepCallDsRoleInterfaceAcl = LocalAlloc( 0, AclLength );
  248. if ( !DsRolepCallDsRoleInterfaceAcl ) {
  249. fSuccess = FALSE;
  250. goto Cleanup;
  251. }
  252. RtlCopyMemory( DsRolepCallDsRoleInterfaceAcl, DsRolepPromoteAcl, AclLength );
  253. //
  254. // Now make the security descriptor
  255. //
  256. fSuccess = DsRolepMakeSecurityDescriptor(&DsRolepCallDsRoleInterfaceSD,
  257. BuiltinAdminsSid,
  258. DsRolepCallDsRoleInterfaceAcl,
  259. NULL);
  260. if (!fSuccess) {
  261. goto Cleanup;
  262. }
  263. Cleanup:
  264. if ( !fSuccess ) {
  265. for ( i = 0; i < cAllowedSids; i++ ) {
  266. if ( *(AllowedSids[i]) ) {
  267. RtlFreeHeap( RtlProcessHeap(), 0, *(AllowedSids[i]) );
  268. }
  269. }
  270. if ( DsRolepPromoteAcl ) {
  271. LocalFree( DsRolepPromoteAcl );
  272. }
  273. if ( DsRolepDemoteAcl ) {
  274. LocalFree( DsRolepDemoteAcl );
  275. }
  276. if ( DsRolepCallDsRoleInterfaceAcl ) {
  277. LocalFree( DsRolepCallDsRoleInterfaceAcl );
  278. }
  279. if ( DsRolepSacl ) {
  280. LocalFree( DsRolepSacl );
  281. }
  282. }
  283. return fSuccess;
  284. }
  285. DWORD
  286. DsRolepCheckClientAccess(
  287. PSECURITY_DESCRIPTOR pSD,
  288. DWORD DesiredAccess,
  289. BOOLEAN PerformAudit
  290. )
  291. /*++
  292. Routine Description:
  293. This routine grabs a copy of the client's token and then performs
  294. an access to make the client has the privlege found in pSD
  295. Arguments:
  296. pSD: a valid security descriptor
  297. DesiredAccess: the access mask the client is asking for
  298. PerformAudit: Indicates if system object access audits should occur. If
  299. TRUE then DnsDomainName must point to a null terminated
  300. string.
  301. Returns:
  302. ERROR_SUCCESS, ERROR_ACCESS_DENIED, or system error
  303. --*/
  304. {
  305. DWORD WinError = ERROR_SUCCESS;
  306. BOOL fStatus = FALSE;
  307. BOOL fAccessAllowed = FALSE;
  308. HANDLE ClientToken = 0;
  309. DWORD AccessGranted = 0;
  310. BYTE Buffer[500];
  311. PRIVILEGE_SET *PrivilegeSet = (PRIVILEGE_SET*)Buffer;
  312. DWORD PrivilegeSetSize = sizeof(Buffer);
  313. BOOL fGenerateOnClose = FALSE;
  314. RPC_STATUS rpcStatus = RPC_S_OK;
  315. DWORD MessageId;
  316. PWSTR ObjectNameString = NULL;
  317. PWSTR ObjectTypeString = NULL;
  318. ULONG len = 0;
  319. WinError = DsRolepGetImpersonationToken( &ClientToken );
  320. if ( ERROR_SUCCESS == WinError ) {
  321. //
  322. // For promotion/demote we must perform an object access audit
  323. //
  324. if (PerformAudit) {
  325. //
  326. // Load the ObjectName string
  327. //
  328. WinError = DsRolepFormatOperationString(
  329. DSROLEEVT_AUDIT_INTERFACE_DESC,
  330. &ObjectTypeString
  331. );
  332. if ( ERROR_SUCCESS != WinError ) {
  333. //
  334. // Fallback to an unlocalized string on error.
  335. //
  336. ObjectTypeString = DSROLE_AUDIT_INTERFACE_DESC;
  337. } else {
  338. //
  339. // Strip the \r\n DsRolepFormatOperationString adds.
  340. //
  341. ObjectTypeString[wcslen(ObjectTypeString) -2] = '\0';
  342. }
  343. //
  344. // Load the ObjectType string for this operation
  345. //
  346. MessageId = (pSD == &DsRolepPromoteSD) ?
  347. DSROLEEVT_AUDIT_PROMOTE_DESC :
  348. DSROLEEVT_AUDIT_DEMOTE_DESC;
  349. WinError = DsRolepFormatOperationString(
  350. MessageId,
  351. &ObjectNameString
  352. );
  353. if ( ERROR_SUCCESS != WinError ) {
  354. //
  355. // Fallback to an unlocalized string on error.
  356. //
  357. ObjectNameString = (pSD == &DsRolepPromoteSD) ?
  358. DSROLE_AUDIT_PROMOTE_DESC :
  359. DSROLE_AUDIT_DEMOTE_DESC;
  360. } else {
  361. //
  362. // Strip the \r\n DsRolepFormatOperationString adds.
  363. //
  364. ObjectNameString[wcslen(ObjectNameString) -2] = '\0';
  365. }
  366. //
  367. // Impersonate the caller as required by AccessCheckAndAuditAlarmW
  368. //
  369. WinError = RpcImpersonateClient( 0 );
  370. if ( WinError == ERROR_SUCCESS ) {
  371. fStatus = AccessCheckAndAuditAlarmW(
  372. SAMP_SAM_COMPONENT_NAME,
  373. NULL,
  374. ObjectTypeString,
  375. ObjectNameString,
  376. pSD,
  377. DesiredAccess,
  378. &DsRolepInfoMapping,
  379. FALSE,
  380. &AccessGranted,
  381. &fAccessAllowed,
  382. &fGenerateOnClose );
  383. rpcStatus = RpcRevertToSelf( );
  384. ASSERT(!rpcStatus);
  385. }
  386. } else {
  387. fStatus = AccessCheck(
  388. pSD,
  389. ClientToken,
  390. DesiredAccess,
  391. &DsRolepInfoMapping,
  392. PrivilegeSet,
  393. &PrivilegeSetSize,
  394. &AccessGranted,
  395. &fAccessAllowed );
  396. }
  397. if ( !fStatus ) {
  398. WinError = GetLastError();
  399. } else {
  400. if ( !fAccessAllowed ) {
  401. WinError = ERROR_ACCESS_DENIED;
  402. }
  403. }
  404. }
  405. if ( ClientToken ) {
  406. NtClose( ClientToken );
  407. }
  408. //
  409. // Free resource strings
  410. //
  411. if ( ObjectNameString ) {
  412. MIDL_user_free( ObjectNameString );
  413. }
  414. if ( ObjectTypeString ) {
  415. MIDL_user_free( ObjectTypeString );
  416. }
  417. return WinError;
  418. }
  419. DWORD
  420. DsRolepCheckPromoteAccess(
  421. BOOLEAN PerformAudit
  422. )
  423. {
  424. return DsRolepCheckClientAccess( &DsRolepPromoteSD,
  425. DSROLE_ROLE_CHANGE_ACCESS,
  426. PerformAudit );
  427. }
  428. DWORD
  429. DsRolepCheckDemoteAccess(
  430. BOOLEAN PerformAudit
  431. )
  432. {
  433. return DsRolepCheckClientAccess( &DsRolepDemoteSD,
  434. DSROLE_ROLE_CHANGE_ACCESS,
  435. PerformAudit );
  436. }
  437. DWORD
  438. DsRolepCheckCallDsRoleInterfaceAccess(
  439. VOID
  440. )
  441. {
  442. return DsRolepCheckClientAccess( &DsRolepCallDsRoleInterfaceSD,
  443. DSROLE_ROLE_CHANGE_ACCESS,
  444. FALSE );
  445. }
  446. DWORD
  447. DsRolepGetImpersonationToken(
  448. OUT HANDLE *ImpersonationToken
  449. )
  450. /*++
  451. Routine Description:
  452. This function will impersonate the invoker of this call and then duplicate their token
  453. Arguments:
  454. ImpersonationToken - Where the duplicated token is returned
  455. Returns:
  456. ERROR_SUCCESS - Success
  457. --*/
  458. {
  459. DWORD Win32Err = ERROR_SUCCESS;
  460. NTSTATUS Status;
  461. OBJECT_ATTRIBUTES ObjAttrs;
  462. SECURITY_QUALITY_OF_SERVICE SecurityQofS;
  463. HANDLE ClientToken;
  464. RPC_STATUS rpcStatus = RPC_S_OK;
  465. //
  466. // Impersonate the caller
  467. //
  468. Win32Err = RpcImpersonateClient( 0 );
  469. if ( Win32Err == ERROR_SUCCESS ) {
  470. Status = NtOpenThreadToken( NtCurrentThread(),
  471. TOKEN_QUERY | TOKEN_DUPLICATE,
  472. TRUE,
  473. &ClientToken );
  474. rpcStatus = RpcRevertToSelf( );
  475. ASSERT(!rpcStatus);
  476. if ( NT_SUCCESS( Status ) ) {
  477. //
  478. // Duplicate the token
  479. //
  480. InitializeObjectAttributes( &ObjAttrs, NULL, 0L, NULL, NULL );
  481. SecurityQofS.Length = sizeof(SECURITY_QUALITY_OF_SERVICE);
  482. SecurityQofS.ImpersonationLevel = SecurityImpersonation;
  483. SecurityQofS.ContextTrackingMode = FALSE; // Snapshot client context
  484. SecurityQofS.EffectiveOnly = FALSE;
  485. ObjAttrs.SecurityQualityOfService = &SecurityQofS;
  486. Status = NtDuplicateToken( ClientToken,
  487. TOKEN_QUERY | TOKEN_IMPERSONATE | TOKEN_ADJUST_PRIVILEGES | TOKEN_DUPLICATE,
  488. &ObjAttrs,
  489. FALSE,
  490. TokenImpersonation,
  491. ImpersonationToken );
  492. NtClose( ClientToken );
  493. }
  494. if ( !NT_SUCCESS( Status ) ) {
  495. Win32Err = RtlNtStatusToDosError( Status );
  496. }
  497. }
  498. return( Win32Err );
  499. }