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.

568 lines
16 KiB

  1. /*****************************************************************************/
  2. /* Copyright (c) 1999-2001 Microsoft Corporation, All Rights Reserved /
  3. /*****************************************************************************/
  4. /*
  5. * SecurityDescriptor.cpp - implementation file for CSecureFile class.
  6. *
  7. * Created: 12-14-1997 by Sanjeev Surati
  8. * (based on classes from Windows NT Security by Nik Okuntseff)
  9. */
  10. #include "precomp.h"
  11. #include "AccessEntry.h" // CAccessEntry class
  12. #include "AccessEntryList.h"
  13. #include "aclapi.h"
  14. #include "DACL.h" // CDACL class
  15. #include "SACL.h" // CSACL class
  16. #include "SecurityDescriptor.h"
  17. #include "securefile.h"
  18. #include "tokenprivilege.h"
  19. #include "ImpLogonUser.h"
  20. #include "AdvApi32Api.h"
  21. ///////////////////////////////////////////////////////////////////
  22. //
  23. // Function: CSecureFile::CSecureFile
  24. //
  25. // Default class constructor.
  26. //
  27. // Inputs:
  28. // None.
  29. //
  30. // Outputs:
  31. // None.
  32. //
  33. // Returns:
  34. // None.
  35. //
  36. // Comments:
  37. //
  38. ///////////////////////////////////////////////////////////////////
  39. CSecureFile::CSecureFile()
  40. : CSecurityDescriptor(),
  41. m_strFileName()
  42. {
  43. }
  44. ///////////////////////////////////////////////////////////////////
  45. //
  46. // Function: CSecureFile::CSecureFile
  47. //
  48. // Alternate Class CTOR
  49. //
  50. // Inputs:
  51. // LPCTSTR pszFileName - The FileName to handle
  52. // security for.
  53. // BOOL fGetSACL - Should we get the SACL?
  54. //
  55. // Outputs:
  56. // None.
  57. //
  58. // Returns:
  59. // None.
  60. //
  61. // Comments:
  62. //
  63. ///////////////////////////////////////////////////////////////////
  64. CSecureFile::CSecureFile( LPCTSTR pszFileName, BOOL fGetSACL /*= TRUE*/ )
  65. : CSecurityDescriptor(),
  66. m_strFileName()
  67. {
  68. SetFileName( pszFileName );
  69. }
  70. ///////////////////////////////////////////////////////////////////
  71. //
  72. // Function: CSecureFile::CSecureFile
  73. //
  74. // Alternate Class CTOR
  75. //
  76. // Inputs:
  77. //
  78. // Outputs:
  79. // None.
  80. //
  81. // Returns:
  82. // None.
  83. //
  84. // Comments:
  85. //
  86. ///////////////////////////////////////////////////////////////////
  87. CSecureFile::CSecureFile
  88. (
  89. LPCTSTR a_pszFileName,
  90. CSid* a_psidOwner,
  91. bool a_fOwnerDefaulted,
  92. CSid* a_psidGroup,
  93. bool a_fGroupDefaulted,
  94. CDACL* a_pDacl,
  95. bool a_fDaclDefaulted,
  96. bool a_fDaclAutoInherited,
  97. CSACL* a_pSacl,
  98. bool a_fSaclDefaulted,
  99. bool a_fSaclAutoInherited
  100. )
  101. : CSecurityDescriptor(a_psidOwner,
  102. a_fOwnerDefaulted,
  103. a_psidGroup,
  104. a_fGroupDefaulted,
  105. a_pDacl,
  106. a_fDaclDefaulted,
  107. a_fDaclAutoInherited,
  108. a_pSacl,
  109. a_fSaclDefaulted,
  110. a_fSaclAutoInherited)
  111. {
  112. m_strFileName = a_pszFileName;
  113. }
  114. ///////////////////////////////////////////////////////////////////
  115. //
  116. // Function: CSecureFile::CSecureFile
  117. //
  118. // Alternate Class CTOR
  119. //
  120. // Inputs:
  121. // LPCTSTR pszFileName - The FileName to handle
  122. // security for.
  123. //
  124. // PSECURITY_DESCRIPTOR pSD - The Security Descriptor to associate with this file
  125. //
  126. // Outputs:
  127. // None.
  128. //
  129. // Returns:
  130. // None.
  131. //
  132. // Comments:
  133. //
  134. ///////////////////////////////////////////////////////////////////
  135. CSecureFile::CSecureFile( LPCTSTR pszFileName, PSECURITY_DESCRIPTOR pSD )
  136. : CSecurityDescriptor(),
  137. m_strFileName()
  138. {
  139. if ( InitSecurity( pSD ) )
  140. {
  141. m_strFileName = pszFileName;
  142. }
  143. }
  144. ///////////////////////////////////////////////////////////////////
  145. //
  146. // Function: CSecureFile::~CSecureFile
  147. //
  148. // Class Destructor.
  149. //
  150. // Inputs:
  151. // None.
  152. //
  153. // Outputs:
  154. // None.
  155. //
  156. // Returns:
  157. // None.
  158. //
  159. // Comments:
  160. //
  161. ///////////////////////////////////////////////////////////////////
  162. CSecureFile::~CSecureFile( void )
  163. {
  164. }
  165. ///////////////////////////////////////////////////////////////////
  166. //
  167. // Function: CSecureFile::SetFileName
  168. //
  169. // Public Entry point to set which file/directory this instance
  170. // of the class is to supply security for.
  171. //
  172. // Inputs:
  173. // LPCTSTR pszFileName - The FileName to handle
  174. // security for.
  175. // BOOL fGetSACL - Should we get the SACL?
  176. //
  177. // Outputs:
  178. // None.
  179. //
  180. // Returns:
  181. // DWORD ERROR_SUCCESS if successful
  182. //
  183. // Comments:
  184. //
  185. // This will clear any previously set filenames and/or security
  186. // information.
  187. //
  188. ///////////////////////////////////////////////////////////////////
  189. DWORD CSecureFile::SetFileName( LPCTSTR pszFileName, BOOL fGetSACL /*= TRUE*/ )
  190. {
  191. DWORD dwError = ERROR_SUCCESS;
  192. SECURITY_INFORMATION siFlags = OWNER_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION;
  193. // GetFileSecurity uses DCOM long logon ids. If we are connected from a remote machine,
  194. // even though we might be the same user as the local logged on user, the long id will be
  195. // different, and GetFileSecurity will give an access denied. Hence the following
  196. // impersonation of the connected user. Note also that this impersonation must be
  197. // done prior to setting the SE_SECURITY_NAME privilage, otherwise we would set that
  198. // privilage for one person, then impersonate another, who probably wouldn't have it!
  199. // This phenomenon can be observed most easily when asking to see an instance of
  200. // win32_logicalfilesecuritysetting of a root directory of a mapped drive, on a machine
  201. // that we have remoted into via wbem.
  202. #ifdef NTONLY
  203. // NOTE: THE FOLLOWING PRESENTS A SECURITY BREACH, AND SHOULD BE REMOVED.
  204. bool fImp = false;
  205. CImpersonateLoggedOnUser icu;
  206. if(icu.Begin())
  207. {
  208. fImp = true;
  209. }
  210. #endif
  211. // We must have the security privilege enabled in order to access the object's SACL
  212. CTokenPrivilege securityPrivilege( SE_SECURITY_NAME );
  213. BOOL fDisablePrivilege = FALSE;
  214. if ( fGetSACL )
  215. {
  216. fDisablePrivilege = ( securityPrivilege.Enable() == ERROR_SUCCESS );
  217. siFlags |= SACL_SECURITY_INFORMATION;
  218. }
  219. // Determine the length needed for self-relative SD
  220. DWORD dwLengthNeeded = 0;
  221. BOOL fSuccess = ::GetFileSecurity( pszFileName,
  222. siFlags,
  223. NULL,
  224. 0,
  225. &dwLengthNeeded );
  226. dwError = ::GetLastError();
  227. // It is possible that the user lacked the permissions required to obtain the SACL,
  228. // even though we set the token's SE_SECURITY_NAME privilege. So if we obtained an
  229. // access denied error, try it again, this time without requesting the SACL.
  230. if(dwError == ERROR_ACCESS_DENIED || dwError == ERROR_PRIVILEGE_NOT_HELD)
  231. {
  232. siFlags = OWNER_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION;
  233. fSuccess = ::GetFileSecurity(pszFileName,
  234. siFlags,
  235. NULL,
  236. 0,
  237. &dwLengthNeeded);
  238. dwError = ::GetLastError();
  239. }
  240. // The only expected error at this point is insuficient buffer
  241. if ( !fSuccess && ERROR_INSUFFICIENT_BUFFER == dwError )
  242. {
  243. PSECURITY_DESCRIPTOR pSD = NULL;
  244. try
  245. {
  246. pSD = malloc( dwLengthNeeded );
  247. if ( NULL != pSD )
  248. {
  249. // Now obtain security descriptor
  250. if ( ::GetFileSecurity( pszFileName,
  251. siFlags,
  252. pSD,
  253. dwLengthNeeded,
  254. &dwLengthNeeded ) )
  255. {
  256. dwError = ERROR_SUCCESS;
  257. if ( InitSecurity( pSD ) )
  258. {
  259. m_strFileName = pszFileName;
  260. }
  261. else
  262. {
  263. dwError = ERROR_INVALID_PARAMETER;
  264. }
  265. }
  266. else
  267. {
  268. dwError = ::GetLastError();
  269. }
  270. // free up the security descriptor
  271. free( pSD );
  272. } // IF NULL != pSD
  273. }
  274. catch(...)
  275. {
  276. if(pSD != NULL)
  277. {
  278. free(pSD);
  279. pSD = NULL;
  280. }
  281. throw;
  282. }
  283. } // IF INSUFFICIENTBUFFER
  284. // Cleanup the Name Privilege as necessary.
  285. if ( fDisablePrivilege )
  286. {
  287. securityPrivilege.Enable(FALSE);
  288. }
  289. #ifdef NTONLY
  290. if(fImp)
  291. {
  292. icu.End();
  293. }
  294. #endif
  295. return dwError;
  296. }
  297. ///////////////////////////////////////////////////////////////////
  298. //
  299. // Function: CSecureFile::WriteAcls
  300. //
  301. // Protected entry point called by CSecurityDescriptor when
  302. // a user Applies Security and wants to apply security for
  303. // the DACL and/or SACL.
  304. //
  305. // Inputs:
  306. // PSECURITY_DESCRIPTOR pAbsoluteSD - Security
  307. // descriptor to apply to
  308. // the file.
  309. // SECURITY_INFORMATION securityinfo - Flags
  310. // indicating which ACL(s)
  311. // to set.
  312. //
  313. // Outputs:
  314. // None.
  315. //
  316. // Returns:
  317. // DWORD ERROR_SUCCESS if successful
  318. //
  319. // Comments:
  320. //
  321. ///////////////////////////////////////////////////////////////////
  322. DWORD CSecureFile::WriteAcls( PSECURITY_DESCRIPTOR pAbsoluteSD, SECURITY_INFORMATION securityinfo )
  323. {
  324. DWORD dwError = ERROR_SUCCESS;
  325. // We must have the security privilege enabled in order to access the object's SACL
  326. CTokenPrivilege securityPrivilege( SE_SECURITY_NAME );
  327. BOOL fDisablePrivilege = FALSE;
  328. if ( securityinfo & SACL_SECURITY_INFORMATION || securityinfo & PROTECTED_SACL_SECURITY_INFORMATION || securityinfo & UNPROTECTED_SACL_SECURITY_INFORMATION)
  329. {
  330. fDisablePrivilege = ( securityPrivilege.Enable() == ERROR_SUCCESS );
  331. }
  332. #if NTONLY >= 5
  333. // CAdvApi32Api *t_pAdvApi32 = NULL;
  334. // CActrl t_actrlAccess;
  335. // CActrl t_actrlAudit;
  336. //
  337. //
  338. // if((dwError = ConfigureActrlAudit(t_actrlAudit, pAbsoluteSD)) == ERROR_SUCCESS && (dwError = ConfigureActrlAccess(t_actrlAccess, pAbsoluteSD)) == ERROR_SUCCESS)
  339. // {
  340. // t_pAdvApi32 = (CAdvApi32Api*) CResourceManager::sm_TheResourceManager.GetResource(g_guidAdvApi32Api, NULL);
  341. // if(t_pAdvApi32 != NULL)
  342. // {
  343. // t_pAdvApi32->SetNamedSecurityInfoEx(m_strFileName,
  344. // SE_FILE_OBJECT,
  345. // securityinfo,
  346. // NULL,
  347. // t_actrlAccess,
  348. // t_actrlAudit,
  349. // NULL, //owner (not specified in securityinfo)
  350. // NULL, //group (not specified in securityinfo)
  351. // NULL, //callback function
  352. // &dwError);
  353. // CResourceManager::sm_TheResourceManager.ReleaseResource(g_guidAdvApi32Api, t_pAdvApi32);
  354. // t_pAdvApi32 = NULL;
  355. // }
  356. // }
  357. // This is new new and improved (hah!) NT5 way. The following is more efficient (although more lines of
  358. // code in *this* module) than making use of our CSecurityDescriptor class to extract all this stuff.
  359. // Need to see if the control flags specify dacl/sacl protection. If so, impacts what we set in the securityinfo structure.
  360. // NEXT FEW LINES AND RELATED LINES NOT REQUIRED AS THE NEW APPROACH, WITH THE NEW PROTECTED_DACL_SECURITY_INFORMATION flag in the SECURITY_INFORMATION
  361. // structure is to not have to, ever, touch or get the control flags (hence, for instance, the call to SetSecurityDescriptorControl in SecurityDescriptor.cpp
  362. // is now superfluous.
  363. //
  364. // SECURITY_DESCRIPTOR_CONTROL Control;
  365. // DWORD dwRevision = 0;
  366. //
  367. // if(GetSecurityDescriptorControl(pAbsoluteSD, &Control, &dwRevision))
  368. // {
  369. // // We got the control structure; now see about dacl/sacl protection, and alter securityinfo accordingly...
  370. // if(Control & SE_DACL_PROTECTED)
  371. // {
  372. // securityinfo |= PROTECTED_DACL_SECURITY_INFORMATION;
  373. // }
  374. // if(Control & SE_SACL_PROTECTED)
  375. // {
  376. // securityinfo |= PROTECTED_SACL_SECURITY_INFORMATION;
  377. // }
  378. PACL pDACL = NULL;
  379. BOOL fDACLPresent = FALSE;
  380. BOOL fDACLDefaulted = FALSE;
  381. // Need to get the PDACL and PSACL if they exist...
  382. if(::GetSecurityDescriptorDacl(pAbsoluteSD, &fDACLPresent, &pDACL, &fDACLDefaulted))
  383. {
  384. PACL pSACL = NULL;
  385. BOOL fSACLPresent = FALSE;
  386. BOOL fSACLDefaulted = FALSE;
  387. if(::GetSecurityDescriptorSacl(pAbsoluteSD, &fSACLPresent, &pSACL, &fSACLDefaulted))
  388. {
  389. // Now need the owner...
  390. PSID psidOwner = NULL;
  391. BOOL bTemp;
  392. if(::GetSecurityDescriptorOwner(pAbsoluteSD, &psidOwner, &bTemp))
  393. {
  394. PSID psidGroup = NULL;
  395. // Now need the group...
  396. if(::GetSecurityDescriptorGroup(pAbsoluteSD, &psidGroup, &bTemp))
  397. {
  398. dwError = ::SetNamedSecurityInfo((LPWSTR)(LPCWSTR)m_strFileName,
  399. SE_FILE_OBJECT,
  400. securityinfo,
  401. psidOwner,
  402. psidGroup,
  403. pDACL,
  404. pSACL);
  405. }
  406. else // couldn't get group
  407. {
  408. dwError = ::GetLastError();
  409. }
  410. }
  411. else // couldn't get owner
  412. {
  413. dwError = ::GetLastError();
  414. }
  415. } // couldn't get sacl
  416. else
  417. {
  418. dwError = ::GetLastError();
  419. }
  420. } // couldn't get dacl
  421. else
  422. {
  423. dwError = ::GetLastError();
  424. }
  425. // } // couldn't get control
  426. // else
  427. // {
  428. // dwError = ::GetLastError();
  429. // }
  430. #else
  431. if(!::SetFileSecurity(TOBSTRT(m_strFileName),
  432. securityinfo,
  433. pAbsoluteSD))
  434. {
  435. dwError = ::GetLastError();
  436. }
  437. #endif
  438. // Cleanup the Name Privilege as necessary.
  439. if ( fDisablePrivilege )
  440. {
  441. securityPrivilege.Enable(FALSE);
  442. }
  443. return dwError;
  444. }
  445. ///////////////////////////////////////////////////////////////////
  446. //
  447. // Function: CSecureFile::WriteOwner
  448. //
  449. // Protected entry point called by CSecurityDescriptor when
  450. // a user Applies Security and wants to apply security for
  451. // the owner.
  452. //
  453. // Inputs:
  454. // PSECURITY_DESCRIPTOR pAbsoluteSD - Security
  455. // descriptor to apply to
  456. // the file.
  457. //
  458. // Outputs:
  459. // None.
  460. //
  461. // Returns:
  462. // DWORD ERROR_SUCCESS if successful
  463. //
  464. // Comments:
  465. //
  466. ///////////////////////////////////////////////////////////////////
  467. DWORD CSecureFile::WriteOwner( PSECURITY_DESCRIPTOR pAbsoluteSD )
  468. {
  469. DWORD dwError = ERROR_SUCCESS;
  470. #if NTONLY >= 5
  471. SECURITY_INFORMATION securityinfo = OWNER_SECURITY_INFORMATION;
  472. PSID psidOwner = NULL;
  473. BOOL bTemp;
  474. if(::GetSecurityDescriptorOwner(pAbsoluteSD, &psidOwner, &bTemp))
  475. {
  476. dwError = ::SetNamedSecurityInfo((LPWSTR)(LPCWSTR)m_strFileName,
  477. SE_FILE_OBJECT,
  478. securityinfo,
  479. psidOwner,
  480. NULL,
  481. NULL,
  482. NULL);
  483. }
  484. else
  485. {
  486. dwError = ::GetLastError();
  487. }
  488. #else
  489. // Open with the appropriate access, set the security and leave
  490. if ( !::SetFileSecurity(TOBSTRT(m_strFileName),
  491. OWNER_SECURITY_INFORMATION,
  492. pAbsoluteSD))
  493. {
  494. dwError = ::GetLastError();
  495. }
  496. #endif
  497. return dwError;
  498. }
  499. DWORD CSecureFile::AllAccessMask( void )
  500. {
  501. // File specific All Access Mask
  502. return FILE_ALL_ACCESS;
  503. }