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.

193 lines
6.4 KiB

  1. //+----------------------------------------------------------------------------
  2. //
  3. // Job Scheduler
  4. //
  5. // Microsoft Windows
  6. // Copyright (C) Microsoft Corporation, 2002.
  7. //
  8. // File: FolderSecurity.cpp
  9. //
  10. // Contents: Class to read folder security and perform access checks against it
  11. //
  12. // History: 5-April-02 HHance created
  13. //
  14. //-----------------------------------------------------------------------------
  15. #include <Windows.h>
  16. #include <FolderSecurity.h>
  17. // disable cilly warning about bools (we'll put it back, later...)
  18. #pragma warning( push )
  19. #pragma warning( disable: 4800)
  20. // returns S_OK if the folder's DACL allows the requested access
  21. // E_ACCESSDENIED if not
  22. // E_NOTFOUND if file/folder cannot be found
  23. // other error on other error
  24. // HANDLE clientToken // handle to client access token
  25. // DWORD desiredAccess // requested access rights
  26. //
  27. // NOTE: Do not use the GENERIC_XXX rights, they must already have been mapped
  28. //
  29. // Suggested rights:
  30. // FILE_READ_DATA
  31. // FILE_WRITE_DATA
  32. // FILE_EXECUTE
  33. // FILE_DELETE_CHILD
  34. //
  35. HRESULT FolderAccessCheck(const WCHAR* pFolderName, HANDLE clientToken, DWORD desiredAccess)
  36. {
  37. if ((desiredAccess == 0) ||
  38. (pFolderName == NULL))
  39. return false;
  40. HRESULT hr = E_ACCESSDENIED;
  41. DWORD dSize = 0;
  42. // call once to see how big a buffer we need
  43. if (!GetFileSecurityW(pFolderName, DACL_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | OWNER_SECURITY_INFORMATION, NULL, 0, &dSize))
  44. {
  45. DWORD dwErr = GetLastError();
  46. if (dwErr != ERROR_INSUFFICIENT_BUFFER)
  47. return HRESULT_FROM_WIN32(dwErr);
  48. }
  49. PSECURITY_DESCRIPTOR pSD = NULL;
  50. if ((dSize > 0) && (pSD = new BYTE[dSize + 1]))
  51. {
  52. // get it for real (hopefully)
  53. if (GetFileSecurityW(pFolderName, DACL_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | OWNER_SECURITY_INFORMATION, pSD, dSize, &dSize))
  54. {
  55. // all the args access check could ever want
  56. GENERIC_MAPPING gm;
  57. gm.GenericRead = FILE_GENERIC_READ;
  58. gm.GenericWrite = FILE_GENERIC_WRITE;
  59. gm.GenericExecute = FILE_GENERIC_EXECUTE;
  60. gm.GenericAll = FILE_ALL_ACCESS;
  61. PRIVILEGE_SET ps;
  62. DWORD psLength = sizeof(PRIVILEGE_SET);
  63. // guilty until proven innocent
  64. BOOL accessStatus = FALSE;
  65. DWORD grantedAccess = 0;
  66. if (AccessCheck(pSD, clientToken, desiredAccess, &gm, &ps, &psLength, &grantedAccess, &accessStatus))
  67. if (accessStatus && ((grantedAccess & desiredAccess) == desiredAccess))
  68. hr = S_OK;
  69. }
  70. else
  71. hr = HRESULT_FROM_WIN32(GetLastError());
  72. delete[] pSD;
  73. }
  74. return hr;
  75. }
  76. // helper function - uses current thread/process token
  77. // to call AccessCheck
  78. HRESULT FolderAccessCheckOnThreadToken(const WCHAR* pFolderName, DWORD desiredAccess)
  79. {
  80. HANDLE hToken = INVALID_HANDLE_VALUE;
  81. // Use the thread's own token if he's got one.
  82. HRESULT hr = E_ACCESSDENIED;
  83. if (OpenThreadToken(GetCurrentThread(), TOKEN_QUERY, TRUE, &hToken))
  84. hr = FolderAccessCheck(pFolderName, hToken, desiredAccess);
  85. else
  86. // that didn't work, let's see if we can get the process token
  87. {
  88. if (ImpersonateSelf(SecurityImpersonation))
  89. {
  90. if (OpenThreadToken(GetCurrentThread(), TOKEN_QUERY, TRUE, &hToken))
  91. hr = FolderAccessCheck(pFolderName, hToken, desiredAccess);
  92. RevertToSelf();
  93. }
  94. }
  95. if (hToken != INVALID_HANDLE_VALUE)
  96. CloseHandle(hToken);
  97. return hr;
  98. }
  99. // helper function - makes use of RPC Impersonation capabilities
  100. // intended to be called from the task scheduler service process
  101. // if bHandleImpersonation is true, this function calls RPCImpersonateClient and RPCRevertToSelf
  102. HRESULT RPCFolderAccessCheck(const WCHAR* pFolderName, DWORD desiredAccess, bool bHandleImpersonation)
  103. {
  104. HRESULT hr = E_ACCESSDENIED;
  105. bool bRet = true;
  106. if (bHandleImpersonation)
  107. bRet = (RPC_S_OK == RpcImpersonateClient(NULL));
  108. if (bRet)
  109. {
  110. HANDLE hToken = INVALID_HANDLE_VALUE;
  111. bRet = OpenThreadToken(GetCurrentThread(), TOKEN_QUERY, TRUE, &hToken);
  112. if (bHandleImpersonation)
  113. RpcRevertToSelf();
  114. if (bRet)
  115. hr = FolderAccessCheck(pFolderName, hToken, desiredAccess);
  116. if (hToken != INVALID_HANDLE_VALUE)
  117. CloseHandle(hToken);
  118. }
  119. return hr;
  120. };
  121. // helper function - makes use of COM impersonation capabilities
  122. // ** Will Fail if COM hasn't been initialized **
  123. // ** Or we can't imperonate the client **
  124. HRESULT CoFolderAccessCheck(const WCHAR* pFolderName, DWORD desiredAccess)
  125. {
  126. bool bAlreadyImpersonated = false;
  127. IServerSecurity* iSecurity = NULL;
  128. HRESULT hr = E_ACCESSDENIED;
  129. if (SUCCEEDED(hr = CoGetCallContext(IID_IServerSecurity, (void**)&iSecurity)))
  130. {
  131. // We were impersonating when we got here?
  132. // if not - try to impersonate the client now.
  133. bool bWeImpersonating = false;
  134. if (bAlreadyImpersonated = iSecurity->IsImpersonating())
  135. bWeImpersonating = true;
  136. else
  137. bWeImpersonating = SUCCEEDED(iSecurity->ImpersonateClient());
  138. // if we've got a thread token, let the helper's helper help out
  139. if (bWeImpersonating)
  140. {
  141. HANDLE hToken = INVALID_HANDLE_VALUE;
  142. if (OpenThreadToken(GetCurrentThread(), TOKEN_QUERY, TRUE, &hToken))
  143. {
  144. if (!bAlreadyImpersonated)
  145. iSecurity->RevertToSelf();
  146. hr = FolderAccessCheck(pFolderName, hToken, desiredAccess);
  147. CloseHandle(hToken);
  148. }
  149. else if (!bAlreadyImpersonated)
  150. iSecurity->RevertToSelf();
  151. }
  152. iSecurity->Release();
  153. }
  154. else if ((hr == RPC_E_CALL_COMPLETE) || (hr == CO_E_NOTINITIALIZED))
  155. hr = FolderAccessCheckOnThreadToken(pFolderName, desiredAccess);
  156. return hr;
  157. }
  158. #pragma warning(pop)