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.

1307 lines
33 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. mailrm.cpp
  5. Abstract:
  6. The implementation of the Mail resource manager
  7. Author:
  8. t-eugenz - August 2000
  9. Environment:
  10. User mode only.
  11. Revision History:
  12. Created - August 2000
  13. --*/
  14. #include "pch.h"
  15. #include "mailrm.h"
  16. #include "mailrmp.h"
  17. #include <time.h>
  18. MailRM::MailRM()
  19. /*++
  20. Routine Description
  21. The constructor for the Mail resource manager.
  22. It initializes an instance of an Authz Resource Manager, providing it
  23. with the appropriate callback functions.
  24. It also creates a security descriptor for the mail RM, with a
  25. SACL and DACL.
  26. Arguments
  27. None.
  28. Return Value
  29. None.
  30. --*/
  31. {
  32. //
  33. // Initialize the audit information
  34. //
  35. AUTHZ_RM_AUDIT_INFO_HANDLE hRMAuditInfo;
  36. if( FALSE == AuthzInitializeRMAuditInfo(&hRMAuditInfo,
  37. 0,
  38. 0,
  39. 0,
  40. L"MailRM") )
  41. {
  42. throw (DWORD)ERROR_INTERNAL_ERROR;
  43. }
  44. if( FALSE == AuthzInitializeResourceManager(
  45. MailRM::AccessCheck,
  46. MailRM::ComputeDynamicGroups,
  47. MailRM::FreeDynamicGroups,
  48. hRMAuditInfo,
  49. 0, // no flags
  50. &_hRM
  51. ) )
  52. {
  53. AuthzFreeRMAuditInfo(hRMAuditInfo);
  54. throw (DWORD)ERROR_INTERNAL_ERROR;
  55. }
  56. //
  57. // Create the security descriptor
  58. //
  59. try {
  60. InitializeMailSecurityDescriptor();
  61. }
  62. catch(...)
  63. {
  64. AuthzFreeRMAuditInfo(hRMAuditInfo);
  65. AuthzFreeResourceManager(_hRM);
  66. throw;
  67. }
  68. }
  69. MailRM::~MailRM()
  70. /*++
  71. Routine Description
  72. The destructor for the Mail resource manager.
  73. Frees any dynamically allocated memory used, including
  74. deleting any registered mailboxes.
  75. Arguments
  76. None.
  77. Return Value
  78. None.
  79. --*/
  80. {
  81. //
  82. // Deallocate the DACL and SACL in the security descriptor
  83. //
  84. PACL pAclMail = NULL;
  85. BOOL fPresent;
  86. BOOL fDefaulted;
  87. DWORD dwTmp;
  88. AUTHZ_RM_AUDIT_INFO_HANDLE hAuditInfo;
  89. if( FALSE != AuthzGetInformationFromResourceManager(
  90. _hRM,
  91. AuthzRMInfoRMAuditInfo,
  92. &hAuditInfo,
  93. sizeof(AUTHZ_RM_AUDIT_INFO_HANDLE),
  94. &dwTmp
  95. ) )
  96. {
  97. AuthzFreeRMAuditInfo(hAuditInfo);
  98. }
  99. GetSecurityDescriptorDacl(&_sd,
  100. &fPresent,
  101. &pAclMail,
  102. &fDefaulted);
  103. if( pAclMail != NULL )
  104. {
  105. delete[] (PBYTE)pAclMail;
  106. pAclMail = NULL;
  107. }
  108. GetSecurityDescriptorSacl(&_sd,
  109. &fPresent,
  110. &pAclMail,
  111. &fDefaulted);
  112. if( pAclMail != NULL )
  113. {
  114. delete[] (PBYTE)pAclMail;
  115. }
  116. //
  117. // Deallocate the resource manager
  118. //
  119. AuthzFreeResourceManager(_hRM);
  120. //
  121. // Delete the mailboxes
  122. //
  123. while( ! _mapSidMailbox.empty() )
  124. {
  125. delete (*(_mapSidMailbox.begin())).second;
  126. _mapSidMailbox.erase(_mapSidMailbox.begin());
  127. }
  128. //
  129. // Free the AuthZ client contexts
  130. //
  131. while( ! _mapSidContext.empty() )
  132. {
  133. AuthzFreeContext((*(_mapSidContext.begin())).second);
  134. _mapSidContext.erase(_mapSidContext.begin());
  135. }
  136. }
  137. void MailRM::InitializeMailSecurityDescriptor()
  138. /*++
  139. Routine Description
  140. This private method initializes the MailRM's security descriptor.
  141. It should be called exactly once, and only by the constructor.
  142. It creates a security descriptor with the following DACL:
  143. CallbackDeny READ Insecure 11pm-5am OR Sensitive
  144. Allow READ, WRITE PrincipalSelf
  145. Allow READ, WRITE, ADMIN MailAdmins
  146. And the following SACL
  147. CallbackAudit READ Insecure 11pm-5am OR Sensitive
  148. (audit on both success and failure)
  149. Arguments
  150. None.
  151. Return Value
  152. None.
  153. --*/
  154. {
  155. DWORD dwAclSize = sizeof(ACL);
  156. DWORD dwAceSize = 0;
  157. PMAILRM_OPTIONAL_DATA pOptionalData = NULL;
  158. //
  159. // Initialize the security descriptor
  160. // No need for owner or group
  161. //
  162. InitializeSecurityDescriptor(&_sd, SECURITY_DESCRIPTOR_REVISION);
  163. SetSecurityDescriptorGroup(&_sd, NULL, FALSE);
  164. SetSecurityDescriptorOwner(&_sd, MailAdminsSid, FALSE);
  165. //
  166. // Callback deny ace RWA for Insecure group SID
  167. // Optional data: Sensitive mailbox OR 11pm-5am
  168. // Any users coming in over an insecure connection between 11pm and 5am
  169. // should be denied read access.
  170. // Also any users coming in over insecure connections to sensitive mailboxes
  171. // should be denied read access.
  172. //
  173. PACCESS_DENIED_CALLBACK_ACE pDenyAce = NULL;
  174. //
  175. // This audit ACE has the same conditions as the above deny ACE. It audits
  176. // any successful (should not happen with the above deny) or failed
  177. // authentications which fit the callback parameters.
  178. //
  179. PSYSTEM_AUDIT_CALLBACK_ACE pAuditAce = NULL;
  180. //
  181. // DACL for the security descriptor
  182. //
  183. PACL pDacl = NULL;
  184. //
  185. // SACL for the security descriptor
  186. //
  187. PACL pSacl = NULL;
  188. //
  189. // We allocate and initialize the callback deny ACE
  190. //
  191. //
  192. // Size of the callback access denied ACE with the optional data
  193. //
  194. dwAceSize = sizeof(ACCESS_DENIED_CALLBACK_ACE) // ACE and 1 DWORD of SID
  195. - sizeof(DWORD) // minus the dword
  196. + GetLengthSid(InsecureSid) // length of the SID
  197. + sizeof(MAILRM_OPTIONAL_DATA); // size of optional data
  198. pDenyAce = (PACCESS_DENIED_CALLBACK_ACE)new BYTE[dwAceSize];
  199. if( pDenyAce == NULL )
  200. {
  201. throw (DWORD)ERROR_OUTOFMEMORY;
  202. }
  203. //
  204. // Manually initialize the ACE structure
  205. //
  206. pDenyAce->Header.AceFlags = 0;
  207. pDenyAce->Header.AceSize = dwAceSize;
  208. pDenyAce->Header.AceType = ACCESS_DENIED_CALLBACK_ACE_TYPE;
  209. pDenyAce->Mask = ACCESS_MAIL_READ;
  210. //
  211. // Copy the Insecure SID into the ACE
  212. //
  213. memcpy(&(pDenyAce->SidStart), InsecureSid, GetLengthSid(InsecureSid));
  214. //
  215. // Our optional data is at the end of the ACE
  216. //
  217. pOptionalData = (PMAILRM_OPTIONAL_DATA)( (PBYTE)pDenyAce
  218. + dwAceSize
  219. - sizeof(MAILRM_OPTIONAL_DATA) );
  220. //
  221. // Initialize the optional data as described above
  222. //
  223. pOptionalData->bIsSensitive = MAILRM_SENSITIVE;
  224. pOptionalData->bLogicType = MAILRM_USE_OR;
  225. pOptionalData->bStartHour = MAILRM_DEFAULT_START_TIME;
  226. pOptionalData->bEndHour = MAILRM_DEFAULT_END_TIME;
  227. //
  228. // Add the size of the callback ACE to the expected ACL size
  229. //
  230. dwAclSize += dwAceSize;
  231. //
  232. // We also need to add non-callback ACEs
  233. //
  234. dwAclSize += ( sizeof(ACCESS_ALLOWED_ACE)
  235. - sizeof(DWORD)
  236. + GetLengthSid(PrincipalSelfSid) );
  237. dwAclSize += ( sizeof(ACCESS_ALLOWED_ACE)
  238. - sizeof(DWORD)
  239. + GetLengthSid(MailAdminsSid) );
  240. //
  241. // Now we can allocate the DACL
  242. //
  243. pDacl = (PACL) (new BYTE[dwAclSize]);
  244. if( pDacl == NULL )
  245. {
  246. delete[] (PBYTE)pDenyAce;
  247. throw (DWORD)ERROR_OUTOFMEMORY;
  248. }
  249. //
  250. // Finally, initialize the ACL and copy the ACEs into it
  251. //
  252. InitializeAcl(pDacl, dwAclSize, ACL_REVISION_DS);
  253. //
  254. // Copy the ACE into the ACL
  255. //
  256. AddAce(pDacl,
  257. ACL_REVISION_DS,
  258. 0xFFFFFFFF, // Add to end
  259. pDenyAce,
  260. dwAceSize);
  261. delete[] (PBYTE)pDenyAce;
  262. //
  263. // Add a PRINCIPAL_SELF_SID allow read and write ace
  264. //
  265. AddAccessAllowedAce(pDacl,
  266. ACL_REVISION_DS,
  267. ACCESS_MAIL_READ | ACCESS_MAIL_WRITE,
  268. PrincipalSelfSid);
  269. //
  270. // Add an allow mail administrators group full access
  271. //
  272. AddAccessAllowedAce(pDacl,
  273. ACL_REVISION_DS,
  274. ACCESS_MAIL_READ | ACCESS_MAIL_WRITE | ACCESS_MAIL_ADMIN,
  275. MailAdminsSid);
  276. //
  277. // Now create the SACL, which will onlye have a single callback ACE
  278. //
  279. dwAclSize = sizeof(ACL);
  280. dwAceSize = sizeof(SYSTEM_AUDIT_CALLBACK_ACE) // ACE and 1 DWORD of SID
  281. - sizeof(DWORD) // minus the dword
  282. + GetLengthSid(InsecureSid) // length of the SID
  283. + sizeof(MAILRM_OPTIONAL_DATA); // size of optional data
  284. //
  285. // Allocate the callback audit ACE
  286. //
  287. pAuditAce = (PSYSTEM_AUDIT_CALLBACK_ACE)new BYTE[dwAceSize];
  288. if( pAuditAce == NULL )
  289. {
  290. delete[] (PBYTE)pDacl;
  291. throw (DWORD)ERROR_OUTOFMEMORY;
  292. }
  293. //
  294. // Initialize the ACE structure
  295. //
  296. pAuditAce->Header.AceFlags = FAILED_ACCESS_ACE_FLAG
  297. | SUCCESSFUL_ACCESS_ACE_FLAG;
  298. pAuditAce->Header.AceSize = dwAceSize;
  299. pAuditAce->Header.AceType = SYSTEM_AUDIT_CALLBACK_ACE_TYPE;
  300. pAuditAce->Mask = ACCESS_MAIL_READ;
  301. //
  302. // Copy the Insecure SID into the ACE
  303. //
  304. memcpy(&(pAuditAce->SidStart), InsecureSid, GetLengthSid(InsecureSid));
  305. pOptionalData = (PMAILRM_OPTIONAL_DATA)( (PBYTE)pAuditAce
  306. + dwAceSize
  307. - sizeof(MAILRM_OPTIONAL_DATA) );
  308. //
  309. // Initialize the optional data as described above
  310. //
  311. pOptionalData->bIsSensitive = MAILRM_SENSITIVE;
  312. pOptionalData->bLogicType = MAILRM_USE_OR;
  313. pOptionalData->bStartHour = MAILRM_DEFAULT_START_TIME;
  314. pOptionalData->bEndHour = MAILRM_DEFAULT_END_TIME;
  315. dwAclSize += dwAceSize;
  316. //
  317. // Allocate the SACL
  318. //
  319. pSacl = (PACL)new BYTE[dwAclSize];
  320. if( pSacl == NULL )
  321. {
  322. delete[] (PBYTE)pDacl;
  323. throw (DWORD)ERROR_OUTOFMEMORY;
  324. }
  325. InitializeAcl(pSacl, dwAclSize, ACL_REVISION_DS);
  326. //
  327. // Now add the audit ACE to the SACL
  328. //
  329. AddAce(pSacl,
  330. ACL_REVISION_DS,
  331. 0xFFFFFFFF, // Add to end
  332. pAuditAce,
  333. dwAceSize);
  334. delete[] (PBYTE)pAuditAce;
  335. //
  336. // We now have the DACL and the SACL, set them
  337. // in the security descriptor
  338. //
  339. SetSecurityDescriptorDacl(&_sd, TRUE, pDacl, FALSE);
  340. SetSecurityDescriptorSacl(&_sd, TRUE, pSacl, FALSE);
  341. }
  342. void MailRM::AddMailbox(Mailbox *pMailbox)
  343. /*++
  344. Routine Description
  345. Registers a mailbox (and its user) with the resource manager.
  346. Arguments
  347. pMailbox - Pointer to an allocated and initialized mailbox
  348. Return Value
  349. None.
  350. --*/
  351. {
  352. _mapSidMailbox[pMailbox->GetOwnerSid()] = pMailbox;
  353. }
  354. Mailbox * MailRM::GetMailboxAccess(
  355. const PSID psMailbox,
  356. const PSID psUser,
  357. DWORD dwIncomingIp,
  358. ACCESS_MASK amAccessRequested
  359. )
  360. /*++
  361. Routine Description
  362. This routine checks whether the user with SID psUser should
  363. be allowed access to the mailbox of user psMailbox. psUser
  364. is coming from dwIncomingIp, and desires amAccessRequested
  365. access mask.
  366. Arguments
  367. psMailbox - PSID of the user whose mailbox will be accessed
  368. psUser - PSID of the user accessing the mailbox
  369. dwIncomingIp- IP address of the user accessing the mailbox
  370. amAccessRequested - Requested access type to the mailbox
  371. Return Value
  372. Non-NULL Mailbox * if access is granted.
  373. NULL if mailbox does not exist or access is denied.
  374. --*/
  375. {
  376. AUTHZ_CLIENT_CONTEXT_HANDLE hAuthzClient;
  377. AUTHZ_ACCESS_REQUEST AuthzAccessRequest;
  378. AUTHZ_ACCESS_REPLY AuthzAccessReply;
  379. AUTHZ_AUDIT_INFO_HANDLE hAuthzAuditInfo = NULL;
  380. PAUDIT_EVENT_INFO pAuditEventInfo = NULL;
  381. wstring wsAccessType;
  382. DWORD dwErr = ERROR_SUCCESS;
  383. ACCESS_MASK amAccessGranted = 0;
  384. WCHAR szIP[20];
  385. //
  386. // Find the correct mailbox
  387. //
  388. Mailbox *pMbx = _mapSidMailbox[psMailbox];
  389. //
  390. // Initialize the auditing info for a Generic object
  391. //
  392. if( FALSE == AuthzInitializeAuditEvent( &pAuditEventInfo,
  393. AUTHZ_INIT_GENERIC_AUDIT_EVENT,
  394. 0,
  395. 0,
  396. 0) )
  397. {
  398. throw (DWORD)ERROR_INTERNAL_ERROR;
  399. }
  400. try {
  401. if( amAccessRequested & ACCESS_MAIL_READ )
  402. {
  403. wsAccessType.append(L"Read ");
  404. }
  405. if( amAccessRequested & ACCESS_MAIL_WRITE )
  406. {
  407. wsAccessType.append(L"Write ");
  408. }
  409. if( amAccessRequested & ACCESS_MAIL_ADMIN )
  410. {
  411. wsAccessType.append(L"Administer");
  412. }
  413. }
  414. catch(...)
  415. {
  416. throw (DWORD)ERROR_INTERNAL_ERROR;
  417. }
  418. wsprintf(szIP, L"IP: %d.%d.%d.%d", (dwIncomingIp >> 24) & 0x000000FF,
  419. (dwIncomingIp >> 16) & 0x000000FF,
  420. (dwIncomingIp >> 8 ) & 0x000000FF,
  421. (dwIncomingIp ) & 0x000000FF );
  422. if( NULL == AuthzInitializeAuditInfo(
  423. &hAuthzAuditInfo,
  424. 0,
  425. pAuditEventInfo,
  426. NULL,
  427. INFINITE,
  428. wsAccessType.c_str(),
  429. L"Mailbox",
  430. pMbx->GetOwnerName(),
  431. szIP) )
  432. {
  433. AuthzFreeAuditEvent(pAuditEventInfo);
  434. throw (DWORD)ERROR_INTERNAL_ERROR;
  435. }
  436. //
  437. // The audit event info is only needed for the above call, we can
  438. // deallocate it immediately after
  439. //
  440. AuthzFreeAuditEvent(pAuditEventInfo);
  441. //
  442. // Set up the Authz access request
  443. //
  444. AuthzAccessRequest.DesiredAccess = amAccessRequested;
  445. AuthzAccessRequest.ObjectTypeList = NULL;
  446. AuthzAccessRequest.ObjectTypeListLength = 0;
  447. AuthzAccessRequest.OptionalArguments = pMbx;
  448. //
  449. // The PrincipalSelf SID is the SID of the mailbox owner
  450. // This way, the PRINCIPAL_SELF_SID allow ACE grants access
  451. // only to the owner. PrincipalSelfSid in the ACE will be replaced
  452. // by this value for access check purposes. The owner of this mailbox
  453. // will have the same SID in his context. Therefore, the two SIDs will
  454. // match if there is a PrincipalSelfSid ACE in the ACL.
  455. //
  456. AuthzAccessRequest.PrincipalSelfSid = pMbx->GetOwnerSid();
  457. //
  458. // Prepare the reply structure
  459. //
  460. AuthzAccessReply.Error = &dwErr;
  461. AuthzAccessReply.GrantedAccessMask = &amAccessGranted;
  462. AuthzAccessReply.ResultListLength = 1;
  463. //
  464. // Create or retrieve the client context
  465. //
  466. if( _mapSidContext.find(pair<PSID, DWORD>(psUser, dwIncomingIp))
  467. == _mapSidContext.end())
  468. {
  469. //
  470. // No context available, initialize
  471. //
  472. LUID lIdentifier = {0L, 0L};
  473. //
  474. // Since we are using SIDs which are not generated by NT,
  475. // it would be pointless to resolve group memberships, since
  476. // the SIDs will not be recognized by any machine in the domain,
  477. // and none of our ACLs use actual NT account SIDs. Therefore,
  478. // we use the SKIP_LOCAL_GROUPS and SKIP_TOKEN_GROUPS flags,
  479. // the LOCAL prevents a check for groups on the local machine,
  480. // and TOKEN prevents a search on the domain
  481. //
  482. if( FALSE == AuthzInitializeContextFromSid(
  483. psUser,
  484. NULL,
  485. _hRM,
  486. NULL,
  487. lIdentifier,
  488. AUTHZ_SKIP_LOCAL_GROUPS | AUTHZ_SKIP_TOKEN_GROUPS,
  489. &dwIncomingIp,
  490. &hAuthzClient) )
  491. {
  492. AuthzFreeAuditInfo(hAuthzAuditInfo, _hRM);
  493. throw (DWORD)ERROR_INTERNAL_ERROR;
  494. }
  495. _mapSidContext[pair<PSID, DWORD>(psUser, dwIncomingIp)] =
  496. hAuthzClient;
  497. }
  498. else
  499. {
  500. //
  501. // Use existing context
  502. //
  503. hAuthzClient = _mapSidContext[pair<PSID, DWORD>(psUser, dwIncomingIp)];
  504. }
  505. BOOL bTmp;
  506. //
  507. // Perform the access check
  508. //
  509. bTmp = AuthzAccessCheck(
  510. hAuthzClient,
  511. &AuthzAccessRequest,
  512. hAuthzAuditInfo,
  513. &_sd,
  514. NULL,
  515. 0,
  516. &AuthzAccessReply,
  517. NULL
  518. );
  519. AuthzFreeAuditInfo(hAuthzAuditInfo, _hRM);
  520. //
  521. // Determine whether to grant access
  522. // On AccessCheck error, deny access
  523. //
  524. if( dwErr == ERROR_SUCCESS && bTmp != FALSE)
  525. {
  526. return pMbx;
  527. }
  528. else
  529. {
  530. return NULL;
  531. }
  532. }
  533. BOOL MailRM::GetMultipleMailboxAccess(
  534. IN const PMAILRM_MULTI_REQUEST pRequest,
  535. IN OUT PMAILRM_MULTI_REPLY pReply
  536. )
  537. /*++
  538. Routine Description
  539. This routine performs a set of cached access checks in order to request
  540. access to a set of mailboxes for a single user (for example, mail admin
  541. sending out a message to all users).
  542. No need to audit, since this type of access would be only done by an
  543. administrator, and multiple audits would most likely flood the mailbox.
  544. Something like this would be use, for example, to send out a message
  545. to all users.
  546. The cached access check first assumes all callback deny ACEs which match
  547. SIDs in the user's context apply, and no allow callback ACEs apply.
  548. Therefore, the cached access check may initially deny access when it
  549. should be granted. If a cached access check results
  550. in access denied, a regular access check is performed automatically
  551. by AuthZ. As a result, the cached access check is guaranteed to have
  552. the same results as a normal access check, though it will take
  553. significantly more time if many denies are encountered than if most
  554. access requests succeed.
  555. Arguments
  556. pRequest - Request structure describing the user and the mailboxes
  557. pReply - Reply structure returning mailbox pointers and granted
  558. access masks. If the access check fails, a NULL pointer
  559. is returned for the given mailbox. This is allocated
  560. by the caller, and should have the same number of
  561. elements as the request.
  562. Return Value
  563. TRUE on success
  564. FALSE on failure. If failure, pReply may not be completely filled
  565. --*/
  566. {
  567. AUTHZ_CLIENT_CONTEXT_HANDLE hAuthzClient;
  568. AUTHZ_ACCESS_REQUEST AuthzAccessRequest;
  569. AUTHZ_ACCESS_REPLY AuthzAccessReply;
  570. DWORD dwErr = ERROR_SUCCESS;
  571. ACCESS_MASK amAccessGranted = 0;
  572. AUTHZ_HANDLE hAuthzCached;
  573. //
  574. // Set up the Authz access request
  575. // Only the DesiredAccess and PrincipalSelfSid parameters will change
  576. // per mailbox. Initial access check is MAXIMUM_ALLOWED.
  577. //
  578. AuthzAccessRequest.ObjectTypeList = NULL;
  579. AuthzAccessRequest.ObjectTypeListLength = 0;
  580. //
  581. // Initial access check will be caching, therefore optional parameters
  582. // will not be used
  583. //
  584. AuthzAccessRequest.OptionalArguments = NULL;
  585. //
  586. // The PrincipalSelf SID is the SID of the mailbox owner
  587. // This way, the PRINCIPAL_SELF_SID allow ACE grants access
  588. // only to the owner
  589. //
  590. AuthzAccessRequest.PrincipalSelfSid = NULL;
  591. //
  592. // Initially ask for MAXIMUM_ALLOWED access
  593. //
  594. AuthzAccessRequest.DesiredAccess = MAXIMUM_ALLOWED;
  595. //
  596. // Prepare the reply structure
  597. //
  598. AuthzAccessReply.Error = &dwErr;
  599. AuthzAccessReply.GrantedAccessMask = &amAccessGranted;
  600. AuthzAccessReply.ResultListLength = 1;
  601. //
  602. // Create or retrieve the client context
  603. //
  604. if( _mapSidContext.find(
  605. pair<PSID, DWORD>(pRequest->psUser , pRequest->dwIp))
  606. == _mapSidContext.end())
  607. {
  608. //
  609. // No context available, initialize
  610. //
  611. LUID lIdentifier = {0L, 0L};
  612. //
  613. // The SIDs are not real, therefore do not attempt to resolve
  614. // local or domain group memberships for the token
  615. //
  616. AuthzInitializeContextFromSid(
  617. pRequest->psUser,
  618. NULL,
  619. _hRM,
  620. NULL,
  621. lIdentifier,
  622. AUTHZ_SKIP_LOCAL_GROUPS | AUTHZ_SKIP_TOKEN_GROUPS,
  623. &(pRequest->dwIp),
  624. &hAuthzClient);
  625. _mapSidContext[pair<PSID, DWORD>(pRequest->psUser,
  626. pRequest->dwIp)] = hAuthzClient;
  627. }
  628. else
  629. {
  630. //
  631. // Use existing context
  632. //
  633. hAuthzClient = _mapSidContext[pair<PSID, DWORD>(pRequest->psUser,
  634. pRequest->dwIp)];
  635. }
  636. //
  637. // Perform a single AuthZ access check to get the cached handle
  638. //
  639. if( FALSE == AuthzAccessCheck(
  640. hAuthzClient,
  641. &AuthzAccessRequest,
  642. NULL,
  643. &_sd,
  644. NULL,
  645. 0,
  646. &AuthzAccessReply,
  647. &hAuthzCached
  648. ))
  649. {
  650. return FALSE;
  651. }
  652. //
  653. // Now use the cached access check for all of the access requests
  654. //
  655. DWORD i;
  656. Mailbox * mbx;
  657. for( i = 0; i < pRequest->dwNumElems; i++ )
  658. {
  659. mbx = _mapSidMailbox[pRequest->pRequestElem[i].psMailbox];
  660. AuthzAccessRequest.DesiredAccess =
  661. pRequest->pRequestElem[i].amAccessRequested;
  662. AuthzAccessRequest.PrincipalSelfSid = mbx->GetOwnerSid();
  663. AuthzAccessRequest.OptionalArguments = mbx;
  664. if( FALSE == AuthzCachedAccessCheck(
  665. hAuthzCached,
  666. &AuthzAccessRequest,
  667. NULL,
  668. &AuthzAccessReply
  669. ))
  670. {
  671. return FALSE;
  672. }
  673. //
  674. // Access check done, now fill in the access array element
  675. //
  676. if( dwErr == ERROR_SUCCESS )
  677. {
  678. pReply[i].pMailbox = mbx;
  679. pReply[i].amAccessGranted = amAccessGranted;
  680. }
  681. else
  682. {
  683. pReply[i].pMailbox = NULL;
  684. pReply[i].amAccessGranted = 0;
  685. }
  686. }
  687. return TRUE;
  688. }
  689. BOOL CALLBACK MailRM::AccessCheck(
  690. IN AUTHZ_CLIENT_CONTEXT_HANDLE pAuthzClientContext,
  691. IN PACE_HEADER pAce,
  692. IN PVOID pArgs OPTIONAL,
  693. IN OUT PBOOL pbAceApplicable
  694. )
  695. /*++
  696. Routine Description
  697. This is the Authz callback access check for the mail resource manager.
  698. It determines whether the given callback ACE applies based on whether
  699. the mailbox contains sensitive information and the current time.
  700. Arguments
  701. pAuthzClientContext - the AuthZ client context of the user accessing
  702. the mailbox, with dynamic groups already
  703. computed
  704. pAce - Pointer to the start of the callback ACE
  705. The optional ACE data is in the last 4
  706. bytes of the ACE
  707. pArgs - The optional argument passed to the
  708. AuthzAccessCheck, pointer to the Mailbox
  709. being accessed
  710. pbAceApplicable - Set to TRUE iff the ACE should be used in the
  711. access check.
  712. Return Value
  713. TRUE on success
  714. FALSE on failure
  715. --*/
  716. {
  717. BOOL bTimeApplies;
  718. BOOL bSensitiveApplies;
  719. //
  720. // If pArgs are not present, ACE is never applicable
  721. //
  722. if( pArgs == NULL )
  723. {
  724. *pbAceApplicable = FALSE;
  725. return TRUE;
  726. }
  727. //
  728. // Offset of the optional data, last 4 bytes of the callback ACE
  729. //
  730. PMAILRM_OPTIONAL_DATA pOptData = (PMAILRM_OPTIONAL_DATA) (
  731. (PBYTE)pAce
  732. + pAce->AceSize
  733. - sizeof(MAILRM_OPTIONAL_DATA));
  734. //
  735. // Get current time and check if the ACE time restriction applies
  736. //
  737. time_t tTime;
  738. struct tm * tStruct;
  739. time(&tTime);
  740. tStruct = localtime(&tTime);
  741. if( WITHIN_TIMERANGE(tStruct->tm_hour,
  742. pOptData->bStartHour,
  743. pOptData->bEndHour) )
  744. {
  745. bTimeApplies = TRUE;
  746. }
  747. else
  748. {
  749. bTimeApplies = FALSE;
  750. }
  751. //
  752. // Check whether the mailbox is sensitive and the ACE applies to sensitive
  753. // mailboxes
  754. //
  755. if( ((Mailbox *)pArgs)->IsSensitive()
  756. && pOptData->bIsSensitive == MAILRM_SENSITIVE )
  757. {
  758. bSensitiveApplies = TRUE;
  759. }
  760. else
  761. {
  762. bSensitiveApplies = FALSE;
  763. }
  764. //
  765. // Make the final decision based on whether the optional argument
  766. // calls for an AND or OR condition
  767. //
  768. if( pOptData->bLogicType == MAILRM_USE_AND )
  769. {
  770. *pbAceApplicable = bSensitiveApplies && bTimeApplies;
  771. }
  772. else
  773. {
  774. *pbAceApplicable = bSensitiveApplies || bTimeApplies;
  775. }
  776. //
  777. // AccessCheck succeeded
  778. //
  779. return TRUE;
  780. }
  781. BOOL CALLBACK MailRM::ComputeDynamicGroups(
  782. IN AUTHZ_CLIENT_CONTEXT_HANDLE pAuthzClientContext,
  783. IN PVOID Args,
  784. OUT PSID_AND_ATTRIBUTES *pSidAttrArray,
  785. OUT PDWORD pSidCount,
  786. OUT PSID_AND_ATTRIBUTES *pRestrictedSidAttrArray,
  787. OUT PDWORD pRestrictedSidCount
  788. )
  789. /*++
  790. Routine Description
  791. This is the Authz callback which computes additional dynamic groups
  792. for the user context.
  793. If the user is originating at an IP address outside the company lan
  794. (company lan assumed to be 192.*), the InsecureSid SID is added
  795. to the client's context, signifying that the connection is not
  796. secure. This enables callback ACEs which prohibit sensitive
  797. information from being sent over insecure connections.
  798. Arguments
  799. pAuthzClientContext - the AuthZ client context of the user
  800. pArgs - The optional argument passed to the
  801. AuthzCreateContext, pointer to a DWORD
  802. containing the user's IP address
  803. pSidAttrArray * - The additional SIDs, if any are assigned,
  804. are returned here.
  805. pSidCount - Number of entries in pSidAttrArray
  806. pRestrictedSidAttrArray * - The additional restricted SIDs, if any
  807. are assigned, are returned here.
  808. pRestrictedSidCount - Number of entries in pSidAttrArray
  809. Return Value
  810. TRUE on success
  811. FALSE on failure
  812. --*/
  813. {
  814. //
  815. // No restrict-only groups used
  816. //
  817. *pRestrictedSidCount = 0;
  818. *pRestrictedSidAttrArray = NULL;
  819. //
  820. // Internal company network (secure) is 192.*, anything else is insecure
  821. //
  822. if( *( (DWORD *) Args) >= 0xC0000000 && *( (DWORD *) Args) < 0xC1000000 )
  823. {
  824. //
  825. // Secure, within the company IP range, no restricted groups
  826. //
  827. *pSidCount = 0;
  828. *pSidAttrArray = NULL;
  829. }
  830. else
  831. {
  832. //
  833. // Insecure external connection, add the Insecure group SID
  834. //
  835. *pSidCount = 1;
  836. *pSidAttrArray =
  837. (PSID_AND_ATTRIBUTES)malloc( sizeof(SID_AND_ATTRIBUTES) );
  838. if( pSidAttrArray == NULL )
  839. {
  840. SetLastError(ERROR_OUTOFMEMORY);
  841. return FALSE;
  842. }
  843. (*pSidAttrArray)[0].Attributes = SE_GROUP_ENABLED;
  844. (*pSidAttrArray)[0].Sid = InsecureSid;
  845. }
  846. return TRUE;
  847. }
  848. VOID CALLBACK MailRM::FreeDynamicGroups (
  849. IN PSID_AND_ATTRIBUTES pSidAttrArray
  850. )
  851. /*++
  852. Routine Description
  853. This routine frees any memory allocated by ComputeDynamicGroups
  854. Arguments
  855. pSidAttrArray - Pointer to the memory to be freed
  856. Return Value
  857. None
  858. --*/
  859. {
  860. free(pSidAttrArray);
  861. }
  862. bool CompareSidStruct::operator()(const PSID pSid1, const PSID pSid2) const
  863. /*++
  864. Routine Description
  865. This is a less-than function which places a complete ordering on
  866. a set of PSIDs by value, NULL PSIDs are valid. This is used by the
  867. STL map.
  868. Since the number of subauthorities appears before the subauthorities
  869. themselves, that difference will be noticed for two SIDs of different
  870. size before the memcmp tries to access the nonexistant subauthority
  871. in the shorter SID, therefore an access violation will not occur.
  872. Arguments
  873. pSid1 - The first PSID
  874. pSid2 - The second PSID
  875. Return Value
  876. true IFF pSid1 < pSid2
  877. --*/
  878. {
  879. //
  880. // If both are NULL, false should be returned for complete ordering
  881. //
  882. if(pSid2 == NULL)
  883. {
  884. return false;
  885. }
  886. if(pSid1 == NULL)
  887. {
  888. return true;
  889. }
  890. if( memcmp(pSid1, pSid2, GetLengthSid(pSid1)) < 0 )
  891. {
  892. return true;
  893. }
  894. else
  895. {
  896. return false;
  897. }
  898. }
  899. bool CompareSidPairStruct::operator()(const pair<PSID, DWORD > pair1,
  900. const pair<PSID, DWORD > pair2) const
  901. /*++
  902. Routine Description
  903. This is a less-than function which places a complete ordering on
  904. a set of <PSID, DWORD> pairs by value, NULL PSIDs are valid. This
  905. is used by the STL map
  906. Arguments
  907. pair1 - The first pair
  908. pair2 - The second pair
  909. Return Value
  910. true IFF pSid1 < pSid2 OR (pSid1 = pSid2 AND DWORD1 < DWORD2)
  911. --*/
  912. {
  913. CompareSidStruct SidComp;
  914. if( pair1.second < pair2.second )
  915. {
  916. return true;
  917. }
  918. if( pair1.second > pair2.second )
  919. {
  920. return false;
  921. }
  922. return SidComp.operator()(pair1.first, pair2.first);
  923. }