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.

586 lines
14 KiB

  1. //+--------------------------------------------------------------------------
  2. // File: callback.cpp
  3. // Contents: access check callback
  4. //---------------------------------------------------------------------------
  5. #include <pch.cpp>
  6. #pragma hdrstop
  7. #include "csext.h"
  8. #include "certsd.h"
  9. #include <winldap.h>
  10. #include <limits.h>
  11. #include "csprop.h"
  12. #include "sid.h"
  13. #include <authzi.h>
  14. #define __dwFILE__ __dwFILE_CERTSRV_CALLBACK_CPP__
  15. namespace CertSrv
  16. {
  17. HRESULT GetAccountSid(
  18. IN LPCWSTR pwszName,
  19. PSID *ppSid)
  20. {
  21. HRESULT hr = S_OK;
  22. DWORD cbSid = 0;
  23. DWORD cbDomainName = 0;
  24. SID_NAME_USE use;
  25. LPWSTR pwszDomainName = NULL;
  26. *ppSid = NULL;
  27. if(!pwszName || L'\0'== pwszName[0])
  28. {
  29. hr = GetEveryoneSID(ppSid);
  30. _JumpIfError(hr, error, "GetEveryoneSID");
  31. }
  32. else
  33. {
  34. LookupAccountName(
  35. NULL,
  36. pwszName,
  37. NULL,
  38. &cbSid,
  39. NULL,
  40. &cbDomainName,
  41. &use);
  42. if(ERROR_INSUFFICIENT_BUFFER != GetLastError())
  43. {
  44. hr = myHError(GetLastError());
  45. _JumpError(hr, error, "LookupAccountName");
  46. }
  47. *ppSid = (PSID)LocalAlloc(LMEM_FIXED, cbSid);
  48. if(!*ppSid)
  49. {
  50. hr = E_OUTOFMEMORY;
  51. _JumpError(hr, error, "LocalAlloc");
  52. }
  53. pwszDomainName = (LPWSTR)LocalAlloc(LMEM_FIXED,
  54. cbDomainName*sizeof(WCHAR));
  55. if(!pwszDomainName)
  56. {
  57. hr = E_OUTOFMEMORY;
  58. _JumpError(hr, error, "LocalAlloc");
  59. }
  60. if(!LookupAccountName(
  61. NULL,
  62. pwszName,
  63. *ppSid,
  64. &cbSid,
  65. pwszDomainName,
  66. &cbDomainName,
  67. &use))
  68. {
  69. hr = myHError(GetLastError());
  70. _JumpError(hr, error, "LookupAccountName");
  71. }
  72. }
  73. hr = S_OK;
  74. error:
  75. if(S_OK!=hr)
  76. {
  77. if(*ppSid)
  78. {
  79. LocalFree(*ppSid);
  80. *ppSid = NULL;
  81. }
  82. }
  83. if(pwszDomainName)
  84. {
  85. LocalFree(pwszDomainName);
  86. }
  87. return hr;
  88. }
  89. BOOL
  90. CallbackAccessCheck(
  91. IN AUTHZ_CLIENT_CONTEXT_HANDLE, // pAuthzClientContext
  92. IN PACE_HEADER pAce,
  93. IN PVOID pArgs OPTIONAL,
  94. IN OUT PBOOL pbAceApplicable)
  95. {
  96. HRESULT hr = S_OK;
  97. LPWSTR pwszSamName = (LPWSTR)pArgs;// requester name is passed in to
  98. // AuthzAccessCheck in NT4 style form
  99. // "DomainNetbiosName\RequesterSAMName"
  100. PSID pSid = NULL, pClientSid = NULL, pCallerSid = NULL;
  101. PSID pEveryoneSid = NULL;
  102. PTOKEN_GROUPS pGroups = NULL;
  103. ACCESS_ALLOWED_CALLBACK_ACE* pCallbackAce =
  104. (ACCESS_ALLOWED_CALLBACK_ACE*)pAce;
  105. PSID_LIST pSidList = (PSID_LIST) (((BYTE*)&pCallbackAce->SidStart)+
  106. GetLengthSid(&pCallbackAce->SidStart));
  107. DWORD cSids, cClientSids;
  108. CSASSERT(
  109. ACCESS_ALLOWED_CALLBACK_ACE_TYPE == pAce->AceType ||
  110. ACCESS_DENIED_CALLBACK_ACE_TYPE == pAce->AceType);
  111. CSASSERT(HeapValidate(GetProcessHeap(),0,NULL));
  112. SetLastError(ERROR_SUCCESS);
  113. // get the SID for the requester
  114. hr = GetAccountSid(pwszSamName, &pCallerSid);
  115. CSASSERT(HeapValidate(GetProcessHeap(),0,NULL));
  116. if(EmptyString(pwszSamName) ||
  117. HRESULT_FROM_WIN32(ERROR_NONE_MAPPED)==hr)
  118. {
  119. // if name cannot be resolved, default to Everyone
  120. pGroups = (PTOKEN_GROUPS)LocalAlloc(LMEM_FIXED, sizeof(TOKEN_GROUPS));
  121. if(!pGroups)
  122. {
  123. hr = E_OUTOFMEMORY;
  124. _JumpError(hr, error, "LocalAlloc");
  125. }
  126. hr = GetEveryoneSID(&pEveryoneSid);
  127. _JumpIfError(hr, error, "GetEveryoneSID");
  128. CSASSERT(HeapValidate(GetProcessHeap(),0,NULL));
  129. pGroups->GroupCount=1;
  130. pGroups->Groups[0].Sid = pEveryoneSid;
  131. pGroups->Groups[0].Attributes = 0;
  132. }
  133. else
  134. {
  135. _JumpIfError(hr, error, "GetAccountSid");
  136. // get the list of groups this SID is member of
  137. hr = GetMembership(g_AuthzCertSrvRM, pCallerSid, &pGroups);
  138. _JumpIfError(hr, error, "GetMembership");
  139. CSASSERT(HeapValidate(GetProcessHeap(),0,NULL));
  140. }
  141. CSASSERT(HeapValidate(GetProcessHeap(),0,NULL));
  142. if(pGroups)
  143. {
  144. // traverse the SID list stored in the ACE and compare with the
  145. // client's membership
  146. for(pSid=(PSID)&pSidList->SidListStart, cSids=0; cSids<pSidList->dwSidCount;
  147. cSids++, pSid = (PSID)(((BYTE*)pSid)+GetLengthSid(pSid)))
  148. {
  149. CSASSERT(IsValidSid(pSid));
  150. // group membership doesn't include the user itself, so
  151. // compare with the user first
  152. if(pCallerSid && EqualSid(pSid, pCallerSid))
  153. {
  154. *pbAceApplicable = TRUE;
  155. goto error;
  156. }
  157. for(cClientSids=0; cClientSids<pGroups->GroupCount; cClientSids++)
  158. {
  159. pClientSid = pGroups->Groups[cClientSids].Sid;
  160. CSASSERT(IsValidSid(pClientSid));
  161. if(EqualSid(pSid, pClientSid))
  162. {
  163. *pbAceApplicable = TRUE;
  164. goto error;
  165. }
  166. }
  167. }
  168. }
  169. *pbAceApplicable = FALSE;
  170. error:
  171. CSASSERT(HeapValidate(GetProcessHeap(),0,NULL));
  172. if(pEveryoneSid)
  173. {
  174. LocalFree(pEveryoneSid);
  175. }
  176. if(pCallerSid)
  177. {
  178. LocalFree(pCallerSid);
  179. }
  180. if(pGroups)
  181. {
  182. LocalFree(pGroups);
  183. }
  184. if(S_OK==hr)
  185. {
  186. return TRUE;
  187. }
  188. else
  189. {
  190. SetLastError(HRESULT_CODE(hr));
  191. return FALSE;
  192. }
  193. }
  194. HRESULT GetMembership(
  195. IN AUTHZ_RESOURCE_MANAGER_HANDLE AuthzRM,
  196. IN PSID pSid,
  197. PTOKEN_GROUPS *ppGroups)
  198. {
  199. HRESULT hr = S_OK;
  200. static LUID luid = {0,0};
  201. AUTHZ_CLIENT_CONTEXT_HANDLE AuthzCC = NULL;
  202. DWORD dwSizeRequired;
  203. *ppGroups = NULL;
  204. if(!AuthzInitializeContextFromSid(
  205. 0,
  206. pSid,
  207. AuthzRM,
  208. NULL,
  209. luid, //ignored
  210. NULL,
  211. &AuthzCC))
  212. {
  213. hr = myHError(GetLastError());
  214. _JumpError(hr, error, "AuthzInitializeContextFromSid");
  215. }
  216. if(!AuthzGetInformationFromContext(
  217. AuthzCC,
  218. AuthzContextInfoGroupsSids,
  219. 0,
  220. &dwSizeRequired,
  221. NULL))
  222. {
  223. if(ERROR_INSUFFICIENT_BUFFER!=GetLastError())
  224. {
  225. hr = myHError(GetLastError());
  226. _JumpError(hr, error, "AuthzGetContextInformation");
  227. }
  228. }
  229. *ppGroups = (PTOKEN_GROUPS)LocalAlloc(LMEM_FIXED, dwSizeRequired);
  230. if(!*ppGroups)
  231. {
  232. hr = E_OUTOFMEMORY;
  233. _JumpError(hr, error, "LocalAlloc");
  234. }
  235. if(!AuthzGetInformationFromContext(
  236. AuthzCC,
  237. AuthzContextInfoGroupsSids,
  238. dwSizeRequired,
  239. &dwSizeRequired,
  240. *ppGroups))
  241. {
  242. hr = myHError(GetLastError());
  243. _JumpError(hr, error, "AuthzGetContextInformation");
  244. }
  245. error:
  246. if(AuthzCC)
  247. {
  248. AuthzFreeContext(AuthzCC);
  249. }
  250. if(S_OK!=hr && *ppGroups)
  251. {
  252. LocalFree(*ppGroups);
  253. }
  254. return hr;
  255. }
  256. HRESULT GetRequesterName(DWORD dwRequestId, LPWSTR *ppwszName)
  257. {
  258. HRESULT hr = S_OK;
  259. ICertDBRow *prow = NULL;
  260. hr = g_pCertDB->OpenRow(
  261. PROPOPEN_READONLY | PROPTABLE_REQCERT,
  262. dwRequestId,
  263. NULL,
  264. &prow);
  265. _JumpIfError(hr, error, "OpenRow");
  266. hr = PKCSGetProperty(
  267. prow,
  268. g_wszPropRequesterName,
  269. PROPTYPE_STRING | PROPCALLER_SERVER | PROPTABLE_REQUEST,
  270. NULL,
  271. (BYTE **) ppwszName);
  272. _JumpIfError(hr, error, "PKCSGetProperty");
  273. error:
  274. if(prow)
  275. {
  276. prow->Release();
  277. }
  278. return hr;
  279. }
  280. HRESULT CheckOfficerRights(DWORD dwRequestID, CAuditEvent& event)
  281. {
  282. HRESULT hr = S_OK;
  283. LPWSTR pwszRequesterName = NULL;
  284. // officer rights disabled means every officer is allowed to manage requests
  285. // for everyone, so return ok
  286. if(!g_OfficerRightsSD.IsEnabled())
  287. return S_OK;
  288. hr = GetRequesterName(dwRequestID, &pwszRequesterName);
  289. if(CERTSRV_E_PROPERTY_EMPTY!=hr &&
  290. S_OK != hr)
  291. {
  292. _JumpError(hr, error, "GetRequesterName");
  293. }
  294. hr = CheckOfficerRights(pwszRequesterName, event);
  295. error:
  296. if(pwszRequesterName)
  297. {
  298. LocalFree(pwszRequesterName);
  299. }
  300. return hr;
  301. }
  302. // Verify if impersonated user has the rights over the specified request,
  303. // based on the officer rights defined in the global officer SD and the
  304. // requester name stored in the request
  305. // Return S_OK if allowed or if the officer rights feature is disabled
  306. // E_ACCESSDENIED if not allowed
  307. // E_* if failed to check the rights
  308. HRESULT
  309. CheckOfficerRights(
  310. LPCWSTR pwszRequesterName,
  311. CAuditEvent& event)
  312. {
  313. HRESULT hr;
  314. AUTHZ_CLIENT_CONTEXT_HANDLE hAuthzCC = NULL;
  315. // officer rights disabled means every officer is allowed to manage
  316. // requests for everyone, so return ok
  317. if (!g_OfficerRightsSD.IsEnabled())
  318. {
  319. hr = S_OK;
  320. goto error;
  321. }
  322. hr = GetCallerAuthzContext(&hAuthzCC);
  323. _JumpIfError(hr, error, "GetCallerAuthzContext");
  324. hr = CheckOfficerRightsFromAuthzCC(hAuthzCC, pwszRequesterName);
  325. _JumpIfError(hr, error, "CheckOfficerRightsFromAuthzCC");
  326. error:
  327. if (NULL != hAuthzCC)
  328. {
  329. AuthzFreeContext(hAuthzCC);
  330. }
  331. // generate a failure audit event if restricted officer
  332. if (CERTSRV_E_RESTRICTEDOFFICER == hr)
  333. {
  334. HRESULT hr2 = event.AccessCheck(
  335. CA_ACCESS_DENIED,
  336. event.m_gcNoAuditSuccess);
  337. if (S_OK != hr2 && E_ACCESSDENIED != hr2)
  338. {
  339. hr = hr2;
  340. }
  341. }
  342. return(hr);
  343. }
  344. static LUID s_luid = { 0, 0 };
  345. HRESULT
  346. GetCallerAuthzContext(
  347. OUT AUTHZ_CLIENT_CONTEXT_HANDLE *phAuthzCC)
  348. {
  349. HRESULT hr;
  350. IServerSecurity *pISS = NULL;
  351. HANDLE hThread = NULL;
  352. HANDLE hToken = NULL;
  353. hr = CoGetCallContext(IID_IServerSecurity, (VOID **) &pISS);
  354. _JumpIfError(hr, error, "CoGetCallContext");
  355. if (!pISS->IsImpersonating())
  356. {
  357. hr = pISS->ImpersonateClient();
  358. _JumpIfError(hr, error, "ImpersonateClient");
  359. }
  360. else
  361. {
  362. pISS->Release();
  363. pISS = NULL;
  364. }
  365. hThread = GetCurrentThread();
  366. if (NULL == hThread)
  367. {
  368. hr = myHLastError();
  369. _JumpIfError(hr, error, "GetCurrentThread");
  370. }
  371. if (!OpenThreadToken(
  372. hThread,
  373. TOKEN_QUERY,
  374. FALSE, // client impersonation
  375. &hToken))
  376. {
  377. hr = myHLastError();
  378. _JumpIfError(hr, error, "OpenThreadToken");
  379. }
  380. if (!AuthzInitializeContextFromToken(
  381. 0,
  382. hToken,
  383. g_AuthzCertSrvRM,
  384. NULL,
  385. s_luid,
  386. NULL,
  387. phAuthzCC))
  388. {
  389. hr = myHLastError();
  390. _JumpError(hr, error, "AuthzInitializeContextFromToken");
  391. }
  392. hr = S_OK;
  393. error:
  394. if (NULL != hThread)
  395. {
  396. CloseHandle(hThread);
  397. }
  398. if (NULL != hToken)
  399. {
  400. CloseHandle(hToken);
  401. }
  402. if (NULL != pISS)
  403. {
  404. pISS->RevertToSelf();
  405. pISS->Release();
  406. }
  407. return(hr);
  408. }
  409. // Verify if impersonated user has the rights over the specified request,
  410. // based on the officer rights defined in the global officer SD and the
  411. // requester name retrieved from the request
  412. //
  413. // Return S_OK if allowed or if the officer rights feature is disabled
  414. // E_ACCESSDENIED if not allowed
  415. // E_* if failed to check the rights
  416. HRESULT
  417. CheckOfficerRightsFromAuthzCC(
  418. IN AUTHZ_CLIENT_CONTEXT_HANDLE hAuthzCCOfficer,
  419. IN WCHAR const *pwszRequesterName)
  420. {
  421. HRESULT hr;
  422. PSECURITY_DESCRIPTOR pOfficerSD = NULL;
  423. AUTHZ_ACCESS_REQUEST AuthzRequest;
  424. AUTHZ_ACCESS_REPLY AuthzReply;
  425. ACCESS_MASK GrantedMask;
  426. DWORD dwError = 0;
  427. DWORD dwSaclEval = 0;
  428. AuthzRequest.DesiredAccess = DELETE;
  429. AuthzRequest.PrincipalSelfSid = NULL;
  430. AuthzRequest.ObjectTypeList = NULL;
  431. AuthzRequest.ObjectTypeListLength = 0;
  432. AuthzRequest.OptionalArguments = (VOID *) pwszRequesterName;
  433. AuthzReply.ResultListLength = 1;
  434. AuthzReply.GrantedAccessMask = &GrantedMask;
  435. AuthzReply.Error = &dwError;
  436. AuthzReply.SaclEvaluationResults = &dwSaclEval;
  437. hr = g_OfficerRightsSD.LockGet(&pOfficerSD);
  438. _JumpIfError(hr, error, "CProtectedSecurityDescriptor::LockGet");
  439. CSASSERT(IsValidSecurityDescriptor(pOfficerSD));
  440. if (!AuthzAccessCheck(
  441. 0,
  442. hAuthzCCOfficer,
  443. &AuthzRequest,
  444. NULL, //no audit
  445. pOfficerSD,
  446. NULL,
  447. 0,
  448. &AuthzReply,
  449. NULL))
  450. {
  451. hr = myHLastError();
  452. _JumpError(hr, error, "AuthzAccessCheck");
  453. }
  454. _PrintIfError(AuthzReply.Error[0], "AuthzAccessCheck");
  455. hr = AuthzReply.Error[0] == ERROR_SUCCESS?
  456. S_OK : CERTSRV_E_RESTRICTEDOFFICER;
  457. error:
  458. if (NULL != pOfficerSD)
  459. {
  460. g_OfficerRightsSD.Unlock();
  461. }
  462. return(hr);
  463. }
  464. HRESULT
  465. CheckOfficerRightsFromOfficerName(
  466. IN WCHAR const *pwszOfficerName,
  467. IN WCHAR const *pwszRequesterName)
  468. {
  469. HRESULT hr;
  470. PSID pSid = NULL;
  471. AUTHZ_CLIENT_CONTEXT_HANDLE hAuthzCCOfficer = NULL;
  472. // build authz context based on officer name passed in
  473. hr = GetAccountSid(pwszOfficerName, &pSid);
  474. _JumpIfErrorStr(hr, error, "GetAccountSid", pwszOfficerName);
  475. if (!AuthzInitializeContextFromSid(
  476. 0,
  477. pSid,
  478. g_AuthzCertSrvRM,
  479. NULL,
  480. s_luid, // ignored
  481. NULL,
  482. &hAuthzCCOfficer))
  483. {
  484. hr = myHError(GetLastError());
  485. _JumpError(hr, error, "AuthzInitializeContextFromSid");
  486. }
  487. hr = CheckOfficerRightsFromAuthzCC(hAuthzCCOfficer, pwszRequesterName);
  488. _JumpIfError(hr, error, "CheckOfficerRightsFromAuthzCC");
  489. error:
  490. if (NULL != pSid)
  491. {
  492. LocalFree(pSid);
  493. }
  494. if (NULL != hAuthzCCOfficer)
  495. {
  496. AuthzFreeContext(hAuthzCCOfficer);
  497. }
  498. return(hr);
  499. }
  500. } // namespace CertSrv