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.

2808 lines
97 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1994 - 1996.
  5. //
  6. // File: file.cxx
  7. //
  8. // Contents: Local file support functions
  9. //
  10. // History: 8/94 davemont Created
  11. //
  12. //----------------------------------------------------------------------------
  13. #include <aclpch.hxx>
  14. #pragma hdrstop
  15. #include <ntprov.hxx>
  16. #include <alsup.hxx>
  17. #include <martaevt.h>
  18. extern "C"
  19. {
  20. #include <lmdfs.h>
  21. #include <stdio.h>
  22. #include <seopaque.h>
  23. #include <sertlp.h>
  24. }
  25. #define LMRDR L"\\Device\\LanmanRedirector"
  26. #define WINDFS L"\\Device\\WinDfs"
  27. GENERIC_MAPPING gFileGenMap = {FILE_GENERIC_READ,
  28. FILE_GENERIC_WRITE,
  29. FILE_GENERIC_EXECUTE,
  30. FILE_ALL_ACCESS};
  31. //+---------------------------------------------------------------------------
  32. //
  33. // Function: ConvertFileHandleToName
  34. //
  35. // Synopsis: Determines the file name for a handle. Issues an
  36. // NtQueryInformationFile to determine the file name
  37. //
  38. // Arguments: [IN hFile] -- The (open) handle of the file
  39. // object
  40. // [OUT ppwszName] -- Where the name is returned
  41. //
  42. // Returns: ERROR_SUCCESS -- Succcess
  43. // ERROR_NOT_ENOUGH_MEMORY -- A memory allocation failed
  44. //
  45. // Notes: The returned memory must be freed with AccFree
  46. //
  47. //----------------------------------------------------------------------------
  48. DWORD
  49. ConvertFileHandleToName(IN HANDLE hFile,
  50. OUT PWSTR *ppwszName)
  51. {
  52. DWORD dwErr = ERROR_SUCCESS;
  53. CHECK_HEAP
  54. //
  55. // First, determine the size of the buffer we need...
  56. //
  57. HANDLE hRootDir = NULL;
  58. BYTE pBuff[512];
  59. ULONG cLen = 0;
  60. POBJECT_NAME_INFORMATION pNI = NULL;
  61. PWSTR pwszPath = NULL;
  62. NTSTATUS Status = NtQueryObject(hFile,
  63. ObjectNameInformation,
  64. (POBJECT_NAME_INFORMATION)pBuff,
  65. 512,
  66. &cLen);
  67. if(!NT_SUCCESS(Status))
  68. {
  69. if(Status == STATUS_BUFFER_TOO_SMALL ||
  70. Status == STATUS_INFO_LENGTH_MISMATCH)
  71. {
  72. //
  73. // Fine.. Allocate a big enough buffer
  74. //
  75. pNI = (POBJECT_NAME_INFORMATION)AccAlloc(cLen);
  76. if(pNI != NULL)
  77. {
  78. Status = NtQueryObject(hFile,
  79. ObjectNameInformation,
  80. pNI,
  81. cLen,
  82. NULL);
  83. if(NT_SUCCESS(Status))
  84. {
  85. pwszPath = pNI->Name.Buffer;
  86. acDebugOut((DEB_TRACE_HANDLE, "Path for handle 0x%lx: %ws\n",
  87. hFile, pwszPath));
  88. }
  89. AccFree(pNI);
  90. }
  91. else
  92. {
  93. Status = STATUS_NO_MEMORY;
  94. }
  95. }
  96. dwErr = RtlNtStatusToDosError(Status);
  97. if(dwErr == ERROR_SUCCESS && pwszPath == NULL)
  98. {
  99. dwErr = ERROR_INVALID_HANDLE;
  100. }
  101. if (dwErr != ERROR_SUCCESS)
  102. {
  103. acDebugOut(( DEB_ERROR,
  104. "Failed to get path for handle 0x%lx: %lu\n",
  105. hFile, dwErr ));
  106. ASSERT( dwErr == ERROR_SUCCESS );
  107. }
  108. }
  109. else
  110. {
  111. pwszPath =((POBJECT_NAME_INFORMATION)pBuff)->Name.Buffer;
  112. acDebugOut((DEB_TRACE_HANDLE, "Path for handle 0x%lx: %ws\n", hFile, pwszPath));
  113. }
  114. if(dwErr == ERROR_SUCCESS &&
  115. _wcsnicmp(pwszPath,
  116. LMRDR,
  117. sizeof(LMRDR) / sizeof(WCHAR) - 1) == 0)
  118. {
  119. *ppwszName = (PWSTR)AccAlloc(sizeof(WCHAR) *
  120. (wcslen(pwszPath + ((sizeof(LMRDR) - 1) / sizeof(WCHAR))) + 2));
  121. if(*ppwszName == NULL)
  122. {
  123. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  124. }
  125. else
  126. {
  127. swprintf(*ppwszName,
  128. L"\\%ws",
  129. pwszPath + (sizeof(LMRDR) / sizeof(WCHAR) - 1));
  130. }
  131. acDebugOut((DEB_TRACE_HANDLE, "returning path %ws as LM Rdr path\n",
  132. *ppwszName ));
  133. return(dwErr);
  134. }
  135. if(dwErr != ERROR_SUCCESS)
  136. {
  137. acDebugOut((DEB_ERROR,
  138. "ConvertFileHandleToPath on 0x%lx failed with %lu\n",
  139. hFile,
  140. dwErr));
  141. return(dwErr);
  142. }
  143. UNICODE_STRING UnicodeString;
  144. OBJECT_ATTRIBUTES Attributes;
  145. UCHAR Buffer[1024];
  146. BOOL fFound = FALSE;
  147. ULONG Context = 0;
  148. POBJECT_DIRECTORY_INFORMATION DirInfo = NULL;
  149. //
  150. // Get a handle to the directory and iterate through that directory
  151. // to find the object name.
  152. //
  153. RtlInitUnicodeString(&UnicodeString,
  154. L"\\??");
  155. InitializeObjectAttributes(&Attributes,
  156. &UnicodeString,
  157. OBJ_CASE_INSENSITIVE,
  158. NULL,
  159. NULL);
  160. Status = NtOpenDirectoryObject(&hRootDir,
  161. DIRECTORY_QUERY,
  162. &Attributes);
  163. if (!NT_SUCCESS(Status))
  164. {
  165. return(RtlNtStatusToDosError(Status));
  166. }
  167. //
  168. // Get the entries in batches that will fit in a buffer of size
  169. // BUFFERSIZE until we find the entry that we want
  170. //
  171. while (NT_SUCCESS(Status) && !fFound )
  172. {
  173. RtlZeroMemory(Buffer,
  174. 1024);
  175. Status = NtQueryDirectoryObject(hRootDir,
  176. (PVOID)&Buffer,
  177. 1024,
  178. FALSE,
  179. FALSE,
  180. &Context,
  181. NULL);
  182. if(NT_SUCCESS(Status))
  183. {
  184. //
  185. // Keep looking until we've examined all the entries in this
  186. // batch or we find what we're looking for.
  187. //
  188. DirInfo = (POBJECT_DIRECTORY_INFORMATION)&Buffer[0];
  189. while(!fFound && DirInfo->Name.Length != 0)
  190. {
  191. HANDLE LinkHandle;
  192. UNICODE_STRING LinkTarget;
  193. ASSERT( DirInfo != NULL );
  194. ASSERT( DirInfo->Name.Length != 0 );
  195. ASSERT( DirInfo->TypeName.Length != 0 );
  196. acDebugOut((DEB_TRACE_HANDLE, "Checking dir entry %wZ\n",
  197. &DirInfo->Name));
  198. RtlInitUnicodeString(&UnicodeString,
  199. DirInfo->Name.Buffer);
  200. InitializeObjectAttributes(&Attributes,
  201. &UnicodeString,
  202. OBJ_CASE_INSENSITIVE,
  203. hRootDir,
  204. NULL);
  205. Status = NtOpenSymbolicLinkObject(&LinkHandle,
  206. SYMBOLIC_LINK_QUERY,
  207. &Attributes);
  208. if(NT_SUCCESS(Status))
  209. {
  210. WCHAR LinkTargetBuffer[1024];
  211. memset(LinkTargetBuffer,0,1024 * sizeof(WCHAR));
  212. LinkTarget.Buffer = LinkTargetBuffer;
  213. LinkTarget.Length = 0;
  214. LinkTarget.MaximumLength = sizeof(LinkTargetBuffer);
  215. Status = NtQuerySymbolicLinkObject(LinkHandle,
  216. &LinkTarget,
  217. NULL);
  218. if(NT_SUCCESS(Status))
  219. {
  220. acDebugOut((DEB_TRACE_HANDLE, "Symbolic link for %wZ: %wZ\n",
  221. &DirInfo->Name, &LinkTarget));
  222. if(_wcsnicmp(pwszPath,
  223. LinkTargetBuffer,
  224. LinkTarget.Length / sizeof(WCHAR)) == 0 &&
  225. IS_FILE_PATH( DirInfo->Name.Buffer,
  226. DirInfo->Name.Length / sizeof(WCHAR) ) )
  227. {
  228. fFound = TRUE;
  229. *ppwszName = (PWSTR)AccAlloc((wcslen(DirInfo->Name.Buffer) +
  230. wcslen(pwszPath + (LinkTarget.Length / sizeof(WCHAR))) +
  231. 1) * sizeof(WCHAR));
  232. if(*ppwszName == NULL)
  233. {
  234. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  235. }
  236. else
  237. {
  238. swprintf(*ppwszName,
  239. L"%ws%ws",
  240. DirInfo->Name.Buffer,
  241. pwszPath + (LinkTarget.Length / sizeof(WCHAR)));
  242. acDebugOut((DEB_TRACE_HANDLE, "Returning path %ws\n", *ppwszName ));
  243. }
  244. }
  245. }
  246. NtClose(LinkHandle);
  247. }
  248. DirInfo++;
  249. }
  250. }
  251. }
  252. if (!fFound)
  253. {
  254. if(Status != STATUS_NO_MORE_ENTRIES)
  255. {
  256. dwErr = RtlNtStatusToDosError(Status);
  257. }
  258. else
  259. {
  260. dwErr = ERROR_RESOURCE_NAME_NOT_FOUND;
  261. }
  262. }
  263. if(hRootDir != NULL)
  264. {
  265. NtClose(hRootDir);
  266. }
  267. return(dwErr);
  268. }
  269. //+---------------------------------------------------------------------------
  270. //
  271. // Function: ReadFileSD
  272. //
  273. // Synopsis: Reads the file descriptor off of the given file handle
  274. //
  275. // Arguments: [IN hFile] -- The (open) handle of the file
  276. // object
  277. // [IN SeInfo] -- The security information to
  278. // read
  279. // [IN cKnownSize] -- If non-0, this is the size
  280. // of the buffer to allocate
  281. // for the SD. If 0, the buffer
  282. // size is determined
  283. // [OUT ppSD] -- Where the security descriptor
  284. // is returned
  285. //
  286. // Returns: ERROR_SUCCESS -- Succcess
  287. // ERROR_NOT_ENOUGH_MEMORY -- A memory allocation failed
  288. //
  289. // Notes: The returned memory must be freed with AccFree
  290. //
  291. //----------------------------------------------------------------------------
  292. DWORD
  293. ReadFileSD(IN HANDLE hFile,
  294. IN SECURITY_INFORMATION SeInfo,
  295. IN ULONG cKnownSize,
  296. OUT PSECURITY_DESCRIPTOR *ppSD)
  297. {
  298. DWORD dwErr = ERROR_SUCCESS;
  299. CHECK_HEAP
  300. NTSTATUS Status;
  301. ULONG cNeeded;
  302. //
  303. // If we don't know the size of the object, go ahead and determine it
  304. //
  305. if(cKnownSize == 0)
  306. {
  307. Status = NtQuerySecurityObject(hFile,
  308. SeInfo,
  309. *ppSD,
  310. 0,
  311. &cNeeded);
  312. if(!NT_SUCCESS(Status))
  313. {
  314. if(Status == STATUS_BUFFER_TOO_SMALL)
  315. {
  316. cKnownSize = cNeeded;
  317. Status = STATUS_SUCCESS;
  318. }
  319. }
  320. dwErr = RtlNtStatusToDosError(Status);
  321. }
  322. //
  323. // Now, the actual read
  324. //
  325. if(dwErr == ERROR_SUCCESS)
  326. {
  327. *ppSD = (PISECURITY_DESCRIPTOR)AccAlloc(cKnownSize);
  328. if(*ppSD == NULL)
  329. {
  330. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  331. }
  332. else
  333. {
  334. Status = NtQuerySecurityObject(hFile,
  335. SeInfo,
  336. *ppSD,
  337. cKnownSize,
  338. &cNeeded);
  339. }
  340. }
  341. return(dwErr);
  342. }
  343. //+---------------------------------------------------------------------------
  344. //
  345. // Function: IsFileContainer
  346. //
  347. // Synopsis: Determines if the file is a container (directory)
  348. //
  349. // Arguments: [IN Handle] -- the (open) handle of the file
  350. // object
  351. // [OUT pfIsContainer] -- flag indicating if the object
  352. // is a container
  353. //
  354. // Returns: ERROR_SUCCESS -- Succcess
  355. //
  356. //----------------------------------------------------------------------------
  357. DWORD
  358. IsFileContainer(HANDLE Handle,
  359. PBOOL pfIsContainer)
  360. {
  361. NTSTATUS ntstatus;
  362. IO_STATUS_BLOCK iosb;
  363. FILE_BASIC_INFORMATION basicfileinfo;
  364. *pfIsContainer = FALSE;
  365. //
  366. // call NtQueryInformationFile to get basic file information
  367. //
  368. if (NT_SUCCESS(ntstatus = NtQueryInformationFile(Handle,
  369. &iosb,
  370. &basicfileinfo,
  371. sizeof(FILE_BASIC_INFORMATION),
  372. FileBasicInformation)))
  373. {
  374. *pfIsContainer =
  375. (basicfileinfo.FileAttributes & FILE_ATTRIBUTE_DIRECTORY) ?
  376. TRUE :
  377. FALSE;
  378. return(ERROR_SUCCESS);
  379. }
  380. else
  381. {
  382. return(RtlNtStatusToDosError(ntstatus));
  383. }
  384. }
  385. //+---------------------------------------------------------------------------
  386. //
  387. // Function: IsFilePathLocalOrLM
  388. //
  389. // Synopsis: Determines if the path is that of a local object or a remote
  390. // (network) object
  391. //
  392. // Arguments: [IN pwszFile] -- The file to check
  393. //
  394. // Returns: ERROR_SUCCESS -- Succcess
  395. // ERROR_PATH_NOT_FOUND -- No such path exists
  396. //
  397. //----------------------------------------------------------------------------
  398. DWORD
  399. IsFilePathLocalOrLM(IN LPWSTR pwszFile)
  400. {
  401. DWORD dwErr = ERROR_SUCCESS;
  402. BOOL fIsDfs = FALSE;
  403. NTSTATUS Status;
  404. if (pwszFile && wcsncmp(pwszFile, L"\\\\?\\", 4) == 0)
  405. {
  406. pwszFile += 4;
  407. }
  408. //
  409. // First, try the simply case of it not being accessible...
  410. //
  411. if(GetFileAttributes(pwszFile) == 0xFFFFFFFF)
  412. {
  413. dwErr = GetLastError();
  414. if(dwErr == ERROR_PATH_NOT_FOUND || dwErr == ERROR_FILE_NOT_FOUND)
  415. {
  416. return(ERROR_PATH_NOT_FOUND);
  417. }
  418. }
  419. //
  420. // Otherwise, we need to find out whether it's a path that only we have
  421. // access to or not
  422. //
  423. #if 0
  424. // for some reason, the full path name built is never used - waste time
  425. // First, we'll see if it's a relative path. If so, we'll have to
  426. // build a full path...
  427. //
  428. PWSTR pwszFullPath = pwszFile;
  429. DWORD dwSize;
  430. if(wcslen(pwszFile) < 2 || (pwszFile[1] != L':' && pwszFile[1] != L'\\'))
  431. {
  432. //
  433. // It's a relative path...
  434. //
  435. dwSize = GetFullPathName(pwszFile,
  436. 0,
  437. NULL,
  438. NULL);
  439. if(dwSize == 0)
  440. {
  441. dwErr = GetLastError();
  442. }
  443. else
  444. {
  445. pwszFullPath = (PWSTR)AccAlloc((dwSize + 1) * sizeof(WCHAR));
  446. if(pwszFullPath == NULL)
  447. {
  448. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  449. }
  450. else
  451. {
  452. PWSTR pwszFilePart;
  453. if(GetFullPathName(pwszFile,
  454. dwSize,
  455. pwszFullPath,
  456. &pwszFilePart) == 0)
  457. {
  458. dwErr = GetLastError();
  459. }
  460. }
  461. }
  462. }
  463. #endif
  464. if(pwszFile[1] == L':')
  465. {
  466. if(GetDriveType(pwszFile) == DRIVE_REMOTE)
  467. {
  468. //
  469. // Have to figure out what it is...
  470. //
  471. #define BUFFERSIZE 1024
  472. HANDLE hRootDir;
  473. UNICODE_STRING ObjDir;
  474. OBJECT_ATTRIBUTES Attributes;
  475. UCHAR Buffer[BUFFERSIZE];
  476. ULONG Context = 0;
  477. POBJECT_DIRECTORY_INFORMATION pDirInfo = NULL;
  478. RtlInitUnicodeString(&ObjDir,
  479. L"\\??");
  480. InitializeObjectAttributes(&Attributes,
  481. &ObjDir,
  482. OBJ_CASE_INSENSITIVE,
  483. NULL,
  484. NULL);
  485. Status = NtOpenDirectoryObject(&hRootDir,
  486. DIRECTORY_QUERY,
  487. &Attributes);
  488. //
  489. // Get the entries in batches that will fit in a buffer of size
  490. // BUFFERSIZE until we find the entry that we want
  491. //
  492. BOOL fFound = FALSE;
  493. while (NT_SUCCESS(Status) && !fFound )
  494. {
  495. RtlZeroMemory(Buffer,
  496. BUFFERSIZE);
  497. Status = NtQueryDirectoryObject(hRootDir,
  498. (PVOID)&Buffer,
  499. BUFFERSIZE,
  500. FALSE,
  501. FALSE,
  502. &Context,
  503. NULL);
  504. if(NT_SUCCESS(Status))
  505. {
  506. //
  507. // Keep looking until we've examined all the entries in this
  508. // batch or we find what we're looking for.
  509. //
  510. pDirInfo = (POBJECT_DIRECTORY_INFORMATION)&Buffer[0];
  511. while(pDirInfo->Name.Length != 0)
  512. {
  513. ULONG cChar;
  514. cChar = pDirInfo->Name.Length/sizeof(WCHAR);
  515. if(_wcsnicmp(pDirInfo->Name.Buffer,
  516. pwszFile,
  517. 2) == 0)
  518. {
  519. fFound = TRUE;
  520. break;
  521. }
  522. else
  523. {
  524. pDirInfo++;
  525. }
  526. }
  527. }
  528. }
  529. NtClose(hRootDir);
  530. if(fFound != TRUE)
  531. {
  532. dwErr = RtlNtStatusToDosError(Status);
  533. if(dwErr == ERROR_SUCCESS)
  534. {
  535. dwErr = ERROR_PATH_NOT_FOUND;
  536. }
  537. }
  538. else
  539. {
  540. //
  541. // Now, figure out what type of path I have
  542. //
  543. if(wcscmp(pDirInfo->TypeName.Buffer,
  544. L"SymbolicLink") == 0)
  545. {
  546. HANDLE hLink;
  547. RtlInitUnicodeString(&ObjDir,
  548. pDirInfo->Name.Buffer);
  549. InitializeObjectAttributes(&Attributes,
  550. &ObjDir,
  551. OBJ_CASE_INSENSITIVE,
  552. NULL,
  553. NULL);
  554. Status = NtOpenSymbolicLinkObject(&hLink,
  555. SYMBOLIC_LINK_QUERY,
  556. &Attributes);
  557. if(NT_SUCCESS(Status))
  558. {
  559. UNICODE_STRING Link;
  560. Link.Buffer = (PWSTR)Buffer;
  561. Link.Length = 0;
  562. Link.MaximumLength = sizeof(Buffer);
  563. Status = NtQuerySymbolicLinkObject(hLink,
  564. &Link,
  565. NULL);
  566. NtClose(hLink);
  567. if(NT_SUCCESS(Status))
  568. {
  569. //
  570. // See if this is part of the lanman redir set
  571. //
  572. if(_wcsnicmp(Link.Buffer,
  573. LMRDR,
  574. sizeof(LMRDR) / sizeof(WCHAR)) != 0)
  575. {
  576. //
  577. // See if it's a DFS path before passing
  578. // judgement
  579. //
  580. if(_wcsnicmp(Link.Buffer,
  581. WINDFS,
  582. sizeof(WINDFS) / sizeof(WCHAR)) == 0)
  583. {
  584. // fIsDfs = TRUE;
  585. }
  586. else
  587. {
  588. dwErr = ERROR_PATH_NOT_FOUND;
  589. }
  590. }
  591. }
  592. }
  593. }
  594. }
  595. }
  596. }
  597. if(fIsDfs == TRUE || IS_UNC_PATH(pwszFile, wcslen(pwszFile)))
  598. {
  599. //
  600. // Try and open it...
  601. //
  602. /*
  603. //
  604. // First, see if it's a DFS path...
  605. //
  606. if(fIsDfs || IsThisADfsPath((LPCWSTR)pwszFile, 0) == TRUE)
  607. {
  608. ULONG cLocals = 0;
  609. dwErr = GetLMDfsPaths(pwszFile,
  610. &cLocals,
  611. NULL);
  612. if(dwErr == ERROR_SUCCESS && cLocals == 0)
  613. {
  614. dwErr = ERROR_PATH_NOT_FOUND;
  615. }
  616. }
  617. else
  618. {
  619. */
  620. //
  621. // We'll try to open it...
  622. //
  623. UNICODE_STRING FileName;
  624. if ( RtlDosPathNameToNtPathName_U(pwszFile,
  625. &FileName,
  626. NULL,
  627. NULL) ) {
  628. /*
  629. WCHAR wszPath[MAX_PATH + 1 + sizeof(LMRDR) / sizeof(WCHAR) + 1];
  630. //
  631. // Build the path...
  632. //
  633. ASSERT(wcslen(pwszFile) < MAX_PATH + 1);
  634. swprintf(wszPath,
  635. L"%ws%ws",
  636. LMRDR,
  637. pwszFile + 1);
  638. */
  639. // UNICODE_STRING Path;
  640. OBJECT_ATTRIBUTES ObjAttribs;
  641. IO_STATUS_BLOCK IOSb;
  642. HANDLE hRmt;
  643. // RtlInitUnicodeString(&Path, wszPath);
  644. InitializeObjectAttributes(&ObjAttribs,
  645. &FileName, // &Path,
  646. OBJ_CASE_INSENSITIVE,
  647. NULL,
  648. NULL);
  649. Status = NtCreateFile(&hRmt,
  650. SYNCHRONIZE,
  651. &ObjAttribs,
  652. &IOSb,
  653. NULL,
  654. FILE_ATTRIBUTE_NORMAL,
  655. FILE_SHARE_READ,
  656. FILE_OPEN_IF,
  657. FILE_SYNCHRONOUS_IO_NONALERT,
  658. NULL,
  659. 0);
  660. if(!NT_SUCCESS(Status))
  661. {
  662. dwErr = RtlNtStatusToDosError(Status);
  663. }
  664. else
  665. {
  666. NtClose(hRmt);
  667. }
  668. RtlFreeHeap(RtlProcessHeap(), 0, FileName.Buffer );
  669. } else {
  670. dwErr = ERROR_INVALID_NAME;
  671. }
  672. }
  673. #if 0
  674. //
  675. // never used!!! Free our memory
  676. //
  677. if(pwszFullPath != pwszFile)
  678. {
  679. AccFree(pwszFullPath);
  680. }
  681. #endif
  682. return(dwErr);
  683. }
  684. //+---------------------------------------------------------------------------
  685. //
  686. // Function : OpenFileObject
  687. //
  688. // Synopsis : opens the specified file (or directory) object
  689. //
  690. // Arguments: [IN pObjectName] -- The name of the file object
  691. // [IN AccessMask] -- How to open the file
  692. // [OUT Handle] -- Where to return the file
  693. // handle
  694. // [IN fOpenRoot] -- Open the path as the root of a drive
  695. //
  696. // Returns: ERROR_SUCCESS -- Success
  697. //
  698. //----------------------------------------------------------------------------
  699. DWORD
  700. OpenFileObject(IN LPWSTR pObjectName,
  701. IN ACCESS_MASK AccessMask,
  702. OUT PHANDLE Handle,
  703. IN BOOL fOpenRoot)
  704. {
  705. acDebugOut((DEB_TRACE, "in OpenFileObject\n"));
  706. NTSTATUS ntstatus;
  707. DWORD status = ERROR_SUCCESS;
  708. WCHAR PathBuff[ 7 ];
  709. OBJECT_ATTRIBUTES oa;
  710. IO_STATUS_BLOCK isb;
  711. UNICODE_STRING FileName;
  712. RTL_RELATIVE_NAME_U RelativeName;
  713. IO_STATUS_BLOCK IoStatusBlock;
  714. PVOID FreeBuffer = NULL;
  715. BOOL ReleaseRelativeName = FALSE;
  716. //
  717. // cut and paste code from windows\base\advapi\security.c SetFileSecurityW
  718. //
  719. if(fOpenRoot == TRUE && wcslen(pObjectName) == 2)
  720. {
  721. wcscpy(PathBuff, L"\\??\\");
  722. wcscat(PathBuff, pObjectName);
  723. RtlInitUnicodeString(&FileName, PathBuff);
  724. RtlZeroMemory(&RelativeName, sizeof(RelativeName));
  725. } else {
  726. if(RtlDosPathNameToRelativeNtPathName_U(pObjectName, &FileName, NULL, &RelativeName))
  727. {
  728. ReleaseRelativeName = TRUE;
  729. FreeBuffer = FileName.Buffer;
  730. if ( RelativeName.RelativeName.Length )
  731. {
  732. FileName = RelativeName.RelativeName;
  733. }
  734. else
  735. {
  736. RelativeName.ContainingDirectory = NULL;
  737. }
  738. }
  739. else
  740. {
  741. status = ERROR_INVALID_NAME;
  742. }
  743. }
  744. if(status == ERROR_SUCCESS)
  745. {
  746. InitializeObjectAttributes(&oa,
  747. &FileName,
  748. OBJ_CASE_INSENSITIVE,
  749. RelativeName.ContainingDirectory,
  750. NULL);
  751. ntstatus = NtOpenFile( Handle,
  752. AccessMask,
  753. &oa,
  754. &isb,
  755. FILE_SHARE_READ |
  756. FILE_SHARE_WRITE |
  757. FILE_SHARE_DELETE,
  758. 0);
  759. if (!NT_SUCCESS(ntstatus))
  760. {
  761. status = RtlNtStatusToDosError(ntstatus);
  762. }
  763. if (ReleaseRelativeName) {
  764. RtlReleaseRelativeName(&RelativeName);
  765. }
  766. RtlFreeHeap(RtlProcessHeap(), 0,FreeBuffer);
  767. }
  768. else
  769. {
  770. status = ERROR_INVALID_NAME;
  771. }
  772. acDebugOut((DEB_TRACE, "OutOpenFileObject: %lu\n", status));
  773. return(status);
  774. }
  775. //+---------------------------------------------------------------------------
  776. //
  777. // Function: ReadFilePropertyRights
  778. //
  779. // Synopsis: Reads the access rights from the specified properties on the
  780. // specified file
  781. //
  782. // Arguments: [IN pwszFile] -- The file to get the rights for
  783. // [IN pRightsList] -- SecurityInfo to read based
  784. // on properties
  785. // [IN cRights] -- Number of items in rights list
  786. // [IN AccessList] -- Access List to fill in
  787. //
  788. // Returns: ERROR_SUCCESS -- Success
  789. // ERROR_INVALID_PARAMETER -- A bad property was encountered
  790. //
  791. //----------------------------------------------------------------------------
  792. DWORD
  793. ReadFilePropertyRights(IN PWSTR pwszFile,
  794. IN PACTRL_RIGHTS_INFO pRightsList,
  795. IN ULONG cRights,
  796. IN CAccessList& AccessList)
  797. {
  798. acDebugOut((DEB_TRACE,
  799. "in ReadFilePropertyRights\n"));
  800. DWORD dwErr = ERROR_SUCCESS;
  801. PWSTR pwszPath;
  802. CHECK_HEAP
  803. //
  804. // For the moment, there is only file properties itself...
  805. //
  806. ASSERT(cRights == 1 && pRightsList[0].pwszProperty == NULL);
  807. if(cRights != 1 || pRightsList[0].pwszProperty != NULL)
  808. {
  809. return(ERROR_INVALID_PARAMETER);
  810. }
  811. //
  812. // Set the server name to lookup accounts on
  813. //
  814. dwErr = SetAccessListLookupServer( pwszFile,
  815. AccessList );
  816. //
  817. // Always open with READ_CONTROL..
  818. //
  819. HANDLE hFile;
  820. if(dwErr == ERROR_SUCCESS)
  821. {
  822. dwErr = OpenFileObject(pwszFile,
  823. GetDesiredAccess(READ_ACCESS_RIGHTS,
  824. pRightsList[0].SeInfo) |
  825. FILE_READ_ATTRIBUTES |
  826. READ_CONTROL,
  827. &hFile,
  828. FALSE);
  829. }
  830. if(dwErr == ERROR_SUCCESS && IS_FILE_PATH(pwszFile,wcslen(pwszFile)))
  831. {
  832. //
  833. // See if there is a server associated with this path
  834. //
  835. dwErr = ConvertFileHandleToName(hFile,
  836. &pwszPath );
  837. if(dwErr == ERROR_SUCCESS)
  838. {
  839. dwErr = SetAccessListLookupServer( pwszPath,
  840. AccessList );
  841. AccFree(pwszPath);
  842. }
  843. //
  844. // jinhuang: do not care if it finds the remote server or not
  845. //
  846. dwErr = ERROR_SUCCESS;
  847. }
  848. if(dwErr == ERROR_SUCCESS)
  849. {
  850. PSECURITY_DESCRIPTOR pSD = NULL;
  851. dwErr = GetKernelSecurityInfo(hFile,
  852. pRightsList[0].SeInfo,
  853. NULL,
  854. NULL,
  855. &pSD);
  856. if(dwErr == ERROR_SUCCESS && pSD == NULL)
  857. {
  858. dwErr = ERROR_ACCESS_DENIED;
  859. }
  860. //
  861. // If that worked, we'll have to get the parent SD, if it exists,
  862. // and see if we can determine the inheritance on our current object.
  863. // We only have to do this if we are reading the DACL or SACL
  864. //
  865. if(dwErr == ERROR_SUCCESS)
  866. {
  867. if((FLAG_ON(pRightsList[0].SeInfo, DACL_SECURITY_INFORMATION) &&
  868. !FLAG_ON(((PISECURITY_DESCRIPTOR)pSD)->Control,
  869. SE_DACL_AUTO_INHERITED | SE_DACL_PROTECTED)) ||
  870. (FLAG_ON(pRightsList[0].SeInfo, SACL_SECURITY_INFORMATION) &&
  871. !FLAG_ON(((PISECURITY_DESCRIPTOR)pSD)->Control,
  872. SE_SACL_AUTO_INHERITED | SE_SACL_PROTECTED)))
  873. {
  874. //
  875. // Ok, it's downlevel, so get the parent SD...
  876. //
  877. PSECURITY_DESCRIPTOR pParentSD;
  878. dwErr = GetFileParentRights(pwszFile,
  879. pRightsList,
  880. cRights,
  881. NULL,
  882. NULL,
  883. &pParentSD);
  884. //
  885. // gross hack for the NTFS people, who don't allow opens on the $Extend directory
  886. //
  887. if ( dwErr == ERROR_ACCESS_DENIED &&
  888. _wcsnicmp( pwszFile + 1, L":\\$Extend", 9 ) == 0 ) {
  889. pParentSD = NULL;
  890. dwErr = ERROR_SUCCESS;
  891. }
  892. //
  893. // Also, the routine to convert from nt4 to nt5 security
  894. // descriptor requires that we have the owner and group,
  895. // so we may have to reread the child SD if we don't have
  896. // that info
  897. //
  898. if(dwErr == ERROR_SUCCESS && (!FLAG_ON(pRightsList[0].SeInfo,
  899. OWNER_SECURITY_INFORMATION) ||
  900. !FLAG_ON(pRightsList[0].SeInfo,
  901. GROUP_SECURITY_INFORMATION)))
  902. {
  903. AccFree(pSD);
  904. pSD = NULL;
  905. dwErr = GetKernelSecurityInfo(hFile,
  906. pRightsList[0].SeInfo |
  907. OWNER_SECURITY_INFORMATION |
  908. GROUP_SECURITY_INFORMATION,
  909. NULL,
  910. NULL,
  911. &pSD);
  912. }
  913. //
  914. // A NULL parent SD means this object has no parent!
  915. //
  916. if(dwErr == ERROR_SUCCESS)
  917. {
  918. if(pParentSD != NULL)
  919. {
  920. BOOL fIsContainer;
  921. dwErr = IsFileContainer(hFile,
  922. &fIsContainer);
  923. if(dwErr == ERROR_SUCCESS)
  924. {
  925. PSECURITY_DESCRIPTOR pNewSD;
  926. dwErr = ConvertToAutoInheritSD(pParentSD,
  927. pSD,
  928. fIsContainer,
  929. &gFileGenMap,
  930. &pNewSD);
  931. if(dwErr == ERROR_SUCCESS)
  932. {
  933. dwErr = AccessList.AddSD(pNewSD,
  934. pRightsList[0].SeInfo,
  935. pRightsList[0].pwszProperty);
  936. DestroyPrivateObjectSecurity(&pNewSD);
  937. }
  938. }
  939. AccFree(pParentSD);
  940. }
  941. else
  942. {
  943. dwErr = AccessList.AddSD(pSD,
  944. pRightsList[0].SeInfo,
  945. pRightsList[0].pwszProperty);
  946. }
  947. }
  948. }
  949. else
  950. {
  951. //
  952. // Simply add the SD to our list
  953. //
  954. dwErr = AccessList.AddSD(pSD,
  955. pRightsList[0].SeInfo,
  956. pRightsList[0].pwszProperty);
  957. }
  958. //
  959. // Make sure to free the security descriptor...
  960. //
  961. AccFree(pSD);
  962. }
  963. NtClose(hFile);
  964. }
  965. acDebugOut((DEB_TRACE,
  966. "Out ReadFilePropertyRights %lu\n",
  967. dwErr));
  968. return(dwErr);
  969. }
  970. //+---------------------------------------------------------------------------
  971. //
  972. // Function: ReadFileRights
  973. //
  974. // Synopsis: Reads the access rights from the specified properties on the
  975. // open file
  976. //
  977. // Arguments: [IN pwszFile] -- The file to get the rights for
  978. // [IN pRightsList] -- SecurityInfo to read based
  979. // on properties
  980. // [IN cRights] -- Number of items in rights list
  981. // [IN AccessList] -- Access List to fill in
  982. //
  983. // Returns: ERROR_SUCCESS -- Success
  984. // ERROR_INVALID_PARAMETER -- A bad property was encountered
  985. //
  986. //----------------------------------------------------------------------------
  987. DWORD
  988. ReadFileRights(IN HANDLE hObject,
  989. IN PACTRL_RIGHTS_INFO pRightsList,
  990. IN ULONG cRights,
  991. IN CAccessList& AccessList)
  992. {
  993. acDebugOut((DEB_TRACE,
  994. "in ReadFileRights\n"));
  995. DWORD dwErr = ERROR_SUCCESS;
  996. PACL pDAcl, pSAcl;
  997. PSECURITY_DESCRIPTOR pSD;
  998. PWSTR pwszPath = NULL;
  999. CHECK_HEAP
  1000. //
  1001. // See if there is a server associated with this path
  1002. //
  1003. dwErr = ConvertFileHandleToName(hObject,
  1004. &pwszPath );
  1005. if(dwErr == ERROR_SUCCESS)
  1006. {
  1007. dwErr = SetAccessListLookupServer( pwszPath,
  1008. AccessList );
  1009. AccFree(pwszPath);
  1010. }
  1011. if(dwErr == ERROR_SUCCESS)
  1012. {
  1013. dwErr = GetKernelSecurityInfo(hObject,
  1014. pRightsList[0].SeInfo,
  1015. &pDAcl,
  1016. &pSAcl,
  1017. &pSD);
  1018. }
  1019. //
  1020. // If that worked, we'll have to get the parent SD, if it exists,
  1021. // and see if we can determine the inheritance on our current object
  1022. //
  1023. if(dwErr == ERROR_SUCCESS && !FLAG_ON(pRightsList[0].SeInfo,
  1024. DACL_SECURITY_INFORMATION |
  1025. SACL_SECURITY_INFORMATION))
  1026. {
  1027. //
  1028. // Just insert it and continue
  1029. //
  1030. dwErr = AccessList.AddSD(pSD,
  1031. pRightsList[0].SeInfo,
  1032. pRightsList[0].pwszProperty);
  1033. AccFree(pSD);
  1034. }
  1035. else if(dwErr == ERROR_SUCCESS)
  1036. {
  1037. if(!FLAG_ON(((PISECURITY_DESCRIPTOR)pSD)->Control,
  1038. SE_SACL_AUTO_INHERITED |
  1039. SE_DACL_AUTO_INHERITED))
  1040. {
  1041. //
  1042. // Ok, it's downlevel, so get the parent SD... In order to
  1043. // do this, we'll have to determine who the parent is (path wise)
  1044. //
  1045. PWSTR pwszName = NULL;
  1046. dwErr = ConvertFileHandleToName(hObject,
  1047. &pwszName);
  1048. if(dwErr == ERROR_SUCCESS)
  1049. {
  1050. PSECURITY_DESCRIPTOR pParentSD;
  1051. PACL pParentDAcl, pParentSAcl;
  1052. dwErr = GetFileParentRights(pwszName,
  1053. pRightsList,
  1054. cRights,
  1055. &pParentDAcl,
  1056. &pParentSAcl,
  1057. &pParentSD);
  1058. if(dwErr == ERROR_SUCCESS && (!FLAG_ON(pRightsList[0].SeInfo,
  1059. OWNER_SECURITY_INFORMATION) ||
  1060. !FLAG_ON(pRightsList[0].SeInfo,
  1061. GROUP_SECURITY_INFORMATION)))
  1062. {
  1063. AccFree(pSD);
  1064. pSD = NULL;
  1065. dwErr = GetKernelSecurityInfo(hObject,
  1066. pRightsList[0].SeInfo |
  1067. OWNER_SECURITY_INFORMATION |
  1068. GROUP_SECURITY_INFORMATION,
  1069. NULL,
  1070. NULL,
  1071. &pSD);
  1072. }
  1073. //
  1074. // A NULL parent SD means this object has no parent!
  1075. //
  1076. if(dwErr == ERROR_SUCCESS && pParentSD != NULL)
  1077. {
  1078. BOOL fIsContainer;
  1079. dwErr = IsFileContainer(hObject,
  1080. &fIsContainer);
  1081. if(dwErr == ERROR_SUCCESS)
  1082. {
  1083. PSECURITY_DESCRIPTOR pNewSD;
  1084. dwErr = ConvertToAutoInheritSD(pParentSD,
  1085. pSD,
  1086. fIsContainer,
  1087. &gFileGenMap,
  1088. &pNewSD);
  1089. if(dwErr == ERROR_SUCCESS)
  1090. {
  1091. dwErr = AccessList.AddSD(pNewSD,
  1092. pRightsList[0].SeInfo,
  1093. pRightsList[0].pwszProperty);
  1094. DestroyPrivateObjectSecurity(&pNewSD);
  1095. }
  1096. }
  1097. AccFree(pParentSD);
  1098. }
  1099. AccFree(pwszName);
  1100. }
  1101. }
  1102. else
  1103. {
  1104. //
  1105. // Simply add the SD to our list
  1106. //
  1107. dwErr = AccessList.AddSD(pSD,
  1108. pRightsList[0].SeInfo,
  1109. pRightsList[0].pwszProperty);
  1110. }
  1111. //
  1112. // Make sure to free the security descriptor...
  1113. //
  1114. AccFree(pSD);
  1115. }
  1116. acDebugOut((DEB_TRACE,
  1117. "Out ReadFileRights %lu\n",
  1118. dwErr));
  1119. return(dwErr);
  1120. }
  1121. //+---------------------------------------------------------------------------
  1122. //
  1123. // Function: GetFileParentRights
  1124. //
  1125. // Synopsis: Determines who the parent is, and gets the access rights
  1126. // for it. It is used to aid in determining what the approriate
  1127. // inheritance bits are.
  1128. //
  1129. // Arguments: [IN pwszFile] -- The file/directory to get the
  1130. // parent for
  1131. // [IN pRightsList] -- The properties to get the
  1132. // rights for
  1133. // [IN cRights] -- Number of items in rights list
  1134. // [OUT ppDAcl] -- Where the DACL is returned
  1135. // [OUT ppSAcl] -- Where the SACL is returned
  1136. // [OUT ppSD] -- Where the Security Descriptor
  1137. // is returned
  1138. //
  1139. // Returns: ERROR_SUCCESS -- Success
  1140. //
  1141. //----------------------------------------------------------------------------
  1142. DWORD
  1143. GetFileParentRights(IN LPWSTR pwszFile,
  1144. IN PACTRL_RIGHTS_INFO pRightsList,
  1145. IN ULONG cRights,
  1146. OUT PACL *ppDAcl,
  1147. OUT PACL *ppSAcl,
  1148. OUT PSECURITY_DESCRIPTOR *ppSD)
  1149. {
  1150. acDebugOut((DEB_TRACE, "in GetFileParentRights\n"));
  1151. DWORD dwErr = ERROR_SUCCESS;
  1152. BOOL fNoParent = FALSE;
  1153. WCHAR pwszLocalFileNameBuffer[MAX_PATH+1];
  1154. PWSTR pwszLocalFileName = (PWSTR) pwszLocalFileNameBuffer;
  1155. ULONG filesize;
  1156. PWSTR pwszLastComp;
  1157. CHECK_HEAP
  1158. if (0 == (filesize = RtlGetFullPathName_U(pwszFile, sizeof(WCHAR)*MAX_PATH, pwszLocalFileName, NULL)))
  1159. {
  1160. dwErr = ERROR_FILE_NOT_FOUND;
  1161. goto FileCleanup;
  1162. }
  1163. if (filesize > sizeof(WCHAR)*MAX_PATH)
  1164. {
  1165. //
  1166. // The buffer is too small. We have to allocate more.
  1167. //
  1168. if (NULL == (pwszLocalFileName = (PWSTR) AccAlloc(sizeof(WCHAR)+filesize)))
  1169. {
  1170. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  1171. goto FileCleanup;
  1172. }
  1173. //
  1174. // Try to get the full pathname again. This time the buffer is big enough to hold the full pathname.
  1175. //
  1176. if (0 == (RtlGetFullPathName_U(pwszFile, filesize, pwszLocalFileName, NULL)))
  1177. {
  1178. dwErr = ERROR_FILE_NOT_FOUND;
  1179. goto FileCleanup;
  1180. }
  1181. }
  1182. //
  1183. // First, we have to figure out who are parent is. For now, since there
  1184. // are no supported properties, we'll simply open the parent object
  1185. //
  1186. pwszLastComp = wcsrchr(pwszLocalFileName, L'\\');
  1187. if(pwszLastComp == NULL)
  1188. {
  1189. //
  1190. // Ok, we must be at the root, so we won't have any inheritance
  1191. //
  1192. //
  1193. // Return success after nulling out SD.
  1194. //
  1195. *ppSD = NULL;
  1196. }
  1197. else
  1198. {
  1199. //
  1200. // We'll shorten our path, and then get the info
  1201. //
  1202. WCHAR wcLast;
  1203. // Leave the trailing \, it doesn't hurt to have them on directories.
  1204. // Plus, we don't end up querying security on the Device (x:) instead
  1205. // of the intended root (x:\)
  1206. //
  1207. // We restore
  1208. pwszLastComp ++;
  1209. wcLast = *pwszLastComp;
  1210. *pwszLastComp = L'\0';
  1211. //
  1212. // Make sure if we were looking at the root of a share, that we don't try and go to far
  1213. //
  1214. if (IS_UNC_PATH(pwszLocalFileName, wcslen(pwszLocalFileName)))
  1215. {
  1216. //
  1217. //
  1218. // Have to pass "\\server" if the original string was "\\server\share"
  1219. //
  1220. *(pwszLastComp-1) = L'\0';
  1221. if(wcsrchr(pwszLocalFileName+2, L'\\') == NULL)
  1222. {
  1223. //
  1224. // It's impossible for us to have a parent, so return
  1225. //
  1226. *ppSD = NULL;
  1227. fNoParent = TRUE;
  1228. }
  1229. //
  1230. // Restore the '\'
  1231. //
  1232. *(pwszLastComp-1) = L'\\';
  1233. }
  1234. if(fNoParent == FALSE)
  1235. {
  1236. HANDLE hFile;
  1237. SECURITY_INFORMATION SeInfo = pRightsList[0].SeInfo;
  1238. //
  1239. // Don't want owner or group
  1240. //
  1241. SeInfo &= ~(OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION);
  1242. dwErr = OpenFileObject(pwszLocalFileName,
  1243. GetDesiredAccess(READ_ACCESS_RIGHTS,SeInfo),
  1244. &hFile,
  1245. TRUE);
  1246. if(dwErr == ERROR_SUCCESS)
  1247. {
  1248. dwErr = GetKernelSecurityInfo(hFile,
  1249. SeInfo,
  1250. NULL,
  1251. NULL,
  1252. ppSD);
  1253. if(dwErr == ERROR_SUCCESS)
  1254. {
  1255. //
  1256. // Convert it to self relative
  1257. //
  1258. PSECURITY_DESCRIPTOR pNewSD;
  1259. dwErr = MakeSDSelfRelative(*ppSD,
  1260. &pNewSD,
  1261. ppDAcl,
  1262. ppSAcl);
  1263. if(dwErr == ERROR_SUCCESS)
  1264. {
  1265. *ppSD = pNewSD;
  1266. }
  1267. else
  1268. {
  1269. AccFree(*ppSD);
  1270. }
  1271. }
  1272. NtClose(hFile);
  1273. }
  1274. }
  1275. *pwszLastComp = wcLast;
  1276. }
  1277. FileCleanup:
  1278. if ((pwszLocalFileName != (PWSTR) pwszLocalFileNameBuffer) && (NULL != pwszLocalFileName))
  1279. {
  1280. AccFree(pwszLocalFileName);
  1281. }
  1282. acDebugOut((DEB_TRACE, "Out GetFileParentRights: %lu\n", dwErr));
  1283. return(dwErr);
  1284. }
  1285. //+---------------------------------------------------------------------------
  1286. //
  1287. // Function: SetFilePropertyRights
  1288. //
  1289. // Synopsis: Sets the specified security info on the specified file object
  1290. // property
  1291. //
  1292. // Arguments: [IN hFile] -- The handle to the open object
  1293. // [IN SeInfo] -- Flag indicating what security
  1294. // info to set
  1295. // [IN pwszProperty] -- Property to set it on
  1296. // [IN pSD] -- The security desciptor to set
  1297. //
  1298. // Returns: ERROR_SUCCESS -- Success
  1299. // ERROR_INVALID_PARAMETER -- A bad paramter was given
  1300. //
  1301. //----------------------------------------------------------------------------
  1302. DWORD
  1303. SetFilePropertyRights(IN HANDLE hFile,
  1304. IN SECURITY_INFORMATION SeInfo,
  1305. IN PWSTR pwszProperty,
  1306. IN PSECURITY_DESCRIPTOR pSD)
  1307. {
  1308. acDebugOut((DEB_TRACE, "in SetFilePropertyRights\n"));
  1309. DWORD dwErr = ERROR_SUCCESS;
  1310. //
  1311. // Filesystems don't support properties yet...
  1312. //
  1313. ASSERT(pwszProperty == NULL);
  1314. if(pwszProperty != NULL)
  1315. {
  1316. return(ERROR_INVALID_PARAMETER);
  1317. }
  1318. //
  1319. // Marta only writes uplevel security descriptors.
  1320. //
  1321. // The caller of SetFilePropertyRights will call with SE_xACL_AUTO_INHERITED off in those
  1322. // cases that it wants the underlying file system to do auto inheritance.
  1323. // The caller of SetFilePropertyRights will call with SE_xACL_AUTO_INHERITED on in those
  1324. // cases that it wants the underlying file system to simply store the bits.
  1325. //
  1326. // In the later case, the OS uses the SE_xACL_AUTO_INHERIT_REQ bit as a flag indicating
  1327. // that it is OK to preserve SE_xACL_AUTO_INHERITED bit.
  1328. //
  1329. if(FLAG_ON(SeInfo, DACL_SECURITY_INFORMATION)) {
  1330. ((PISECURITY_DESCRIPTOR)pSD)->Control |= SE_DACL_AUTO_INHERIT_REQ;
  1331. }
  1332. if(FLAG_ON(SeInfo, SACL_SECURITY_INFORMATION)) {
  1333. ((PISECURITY_DESCRIPTOR)pSD)->Control |= SE_SACL_AUTO_INHERIT_REQ;
  1334. }
  1335. //
  1336. // Otherwise, do the set
  1337. //
  1338. NTSTATUS Status = NtSetSecurityObject(hFile,
  1339. SeInfo,
  1340. pSD);
  1341. dwErr = RtlNtStatusToDosError(Status);
  1342. acDebugOut((DEB_TRACE,
  1343. "Out SetFilePropertyRights: %ld\n",
  1344. dwErr));
  1345. return(dwErr);
  1346. }
  1347. #define CLEANUP_ON_INTERRUPT(pstopflag) \
  1348. if(*pstopflag != 0) \
  1349. { \
  1350. goto FileCleanup; \
  1351. }
  1352. //+---------------------------------------------------------------------------
  1353. //
  1354. // Function: SetAndPropagateFilePropertyRights
  1355. //
  1356. // Synopsis: Sets the speecified access on the object and, if appropriate,
  1357. // propagates the access to the apporpriate child objects
  1358. //
  1359. // Arguments: [IN pwszFile] -- The path to set and propagate
  1360. // [IN pwszProperty] -- Property to set it on
  1361. // [IN RootAccList] -- CAccessList that indicates
  1362. // what access is to be set on
  1363. // the object
  1364. // [IN pfStopFlag] -- Address of the stop flag
  1365. // to be monitored
  1366. // [IN pcProcessed] -- Count of processed items
  1367. // [IN hOpenObject] -- OPTIONAL handle to the file object
  1368. // if it's already open
  1369. //
  1370. // Returns: ERROR_SUCCESS -- Success
  1371. // ERROR_INVALID_PARAMETER -- A bad paramter was given
  1372. //
  1373. //----------------------------------------------------------------------------
  1374. DWORD
  1375. SetAndPropagateFilePropertyRights(IN PWSTR pwszFile,
  1376. IN PWSTR pwszProperty,
  1377. IN CAccessList& RootAccList,
  1378. IN PULONG pfStopFlag,
  1379. IN PULONG pcProcessed,
  1380. IN HANDLE hOpenObject OPTIONAL)
  1381. {
  1382. acDebugOut((DEB_TRACE, "in SetAndPropagateFilePropertyRights\n"));
  1383. DWORD dwErr = ERROR_SUCCESS;
  1384. PSECURITY_DESCRIPTOR pReadSD = NULL;
  1385. HANDLE hObject = NULL;
  1386. BOOL fManualProp = FALSE;
  1387. NTSTATUS Status;
  1388. ULONG cNeeded = 0;
  1389. BOOL fIsCont = FALSE;
  1390. ULONG fProtected = 0;
  1391. HANDLE hProcessToken;
  1392. PSECURITY_DESCRIPTOR pSD = NULL;
  1393. SECURITY_INFORMATION SeInfo = 0;
  1394. PSECURITY_DESCRIPTOR pUpdateSD = NULL;
  1395. CSList FailureLogList(FreePropagationFailureListEntry);
  1396. //
  1397. // First, get the security descriptor
  1398. //
  1399. dwErr = RootAccList.BuildSDForAccessList(&pSD,
  1400. &SeInfo,
  1401. ACCLIST_SD_ABSOK);
  1402. if(dwErr == ERROR_SUCCESS &&
  1403. FLAG_ON(SeInfo, DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION))
  1404. {
  1405. //
  1406. // Next, open it
  1407. //
  1408. if(hOpenObject == NULL)
  1409. {
  1410. dwErr = OpenFileObject(pwszFile,
  1411. GetDesiredAccess(MODIFY_ACCESS_RIGHTS,
  1412. SeInfo) | FILE_READ_ATTRIBUTES | READ_CONTROL,
  1413. &hObject,
  1414. FALSE);
  1415. }
  1416. else
  1417. {
  1418. hObject = hOpenObject;
  1419. }
  1420. if(dwErr == ERROR_SUCCESS)
  1421. {
  1422. dwErr = IsFileContainer(hObject,
  1423. &fIsCont);
  1424. }
  1425. if(dwErr != ERROR_SUCCESS || *pfStopFlag != 0)
  1426. {
  1427. goto FileCleanup;
  1428. }
  1429. //
  1430. // Ok, first, we have to read the SD off the object. We do this
  1431. // so that we can determine what the potential inheritance is for
  1432. // our children following the object getting an updated security
  1433. // descriptor.
  1434. //
  1435. if(dwErr == ERROR_SUCCESS && fIsCont == TRUE)
  1436. {
  1437. dwErr = ReadFileSD(hObject,
  1438. SeInfo,
  1439. 0,
  1440. &pReadSD);
  1441. }
  1442. //
  1443. // Now, write the current SD out to the object. Note that it's being
  1444. // written out as an uplevel acl
  1445. //
  1446. if(dwErr == ERROR_SUCCESS)
  1447. {
  1448. CLEANUP_ON_INTERRUPT(pfStopFlag);
  1449. dwErr = SetFilePropertyRights(hObject,
  1450. SeInfo,
  1451. pwszProperty,
  1452. pSD);
  1453. if(dwErr == ERROR_SUCCESS)
  1454. {
  1455. PSECURITY_DESCRIPTOR pVerifySD;
  1456. (*pcProcessed)++;
  1457. CLEANUP_ON_INTERRUPT(pfStopFlag);
  1458. //
  1459. // Now, we have to reread the new SD, to see if we need
  1460. // to do manual propagation
  1461. //
  1462. dwErr = ReadFileSD(hObject,
  1463. SeInfo,
  1464. RootAccList.QuerySDSize(),
  1465. &pVerifySD);
  1466. //
  1467. // Get our process token
  1468. //
  1469. if(dwErr == ERROR_SUCCESS)
  1470. {
  1471. dwErr = GetCurrentToken(&hProcessToken);
  1472. }
  1473. if(dwErr == ERROR_SUCCESS)
  1474. {
  1475. //
  1476. // Check to see if this was done uplevel...
  1477. //
  1478. PISECURITY_DESCRIPTOR pISD = (PISECURITY_DESCRIPTOR)pVerifySD;
  1479. if(!(FLAG_ON(SeInfo, DACL_SECURITY_INFORMATION) &&
  1480. FLAG_ON(pISD->Control, SE_DACL_AUTO_INHERITED) &&
  1481. !FLAG_ON(pISD->Control, SE_DACL_PROTECTED)) &&
  1482. !(FLAG_ON(SeInfo, SACL_SECURITY_INFORMATION) &&
  1483. FLAG_ON(pISD->Control, SE_SACL_AUTO_INHERITED &&
  1484. !FLAG_ON(pISD->Control, SE_SACL_PROTECTED))))
  1485. {
  1486. //
  1487. // It's not uplevel, so we'll turn the AutoInherit
  1488. // flags on, rewrite it, and do our own propagation,
  1489. // only if this is a container and we're setting the
  1490. // dacl or sacl
  1491. //
  1492. if(FLAG_ON(SeInfo,
  1493. (DACL_SECURITY_INFORMATION |
  1494. SACL_SECURITY_INFORMATION)) &&
  1495. fIsCont == TRUE)
  1496. {
  1497. fManualProp = TRUE;
  1498. }
  1499. //
  1500. // Upgrade it...
  1501. //
  1502. dwErr = UpdateFileSDByPath(pSD,
  1503. pwszFile,
  1504. hObject,
  1505. hProcessToken,
  1506. SeInfo,
  1507. fIsCont,
  1508. &pUpdateSD);
  1509. //
  1510. // Now, if we're going to do manual propagation,
  1511. // we'll write out the old SD until we get everyone
  1512. // else updated
  1513. //
  1514. PSECURITY_DESCRIPTOR pWriteSD = pUpdateSD;
  1515. if(fManualProp == TRUE)
  1516. {
  1517. pWriteSD = pReadSD;
  1518. }
  1519. //
  1520. // Reset it...
  1521. //
  1522. if(dwErr == ERROR_SUCCESS)
  1523. {
  1524. dwErr = SetFilePropertyRights(hObject,
  1525. SeInfo,
  1526. pwszProperty,
  1527. pWriteSD);
  1528. }
  1529. }
  1530. AccFree(pVerifySD);
  1531. }
  1532. CLEANUP_ON_INTERRUPT(pfStopFlag);
  1533. }
  1534. }
  1535. //
  1536. // Ok, now we'll do the right thing
  1537. //
  1538. if(dwErr == ERROR_SUCCESS && fManualProp == TRUE)
  1539. {
  1540. //
  1541. // We'll have to do our own propagation...
  1542. //
  1543. PSECURITY_DESCRIPTOR pUpdateParentSD = NULL;
  1544. if(!FLAG_ON(SeInfo, OWNER_SECURITY_INFORMATION) ||
  1545. !FLAG_ON(SeInfo, GROUP_SECURITY_INFORMATION))
  1546. {
  1547. dwErr = GetKernelSecurityInfo(hObject,
  1548. SeInfo |
  1549. OWNER_SECURITY_INFORMATION |
  1550. GROUP_SECURITY_INFORMATION,
  1551. NULL,
  1552. NULL,
  1553. &pUpdateParentSD);
  1554. }
  1555. //
  1556. // Ok, go ahead and do deep. This will possibly save us
  1557. // some storage space in the long run...
  1558. //
  1559. if(dwErr == ERROR_SUCCESS)
  1560. {
  1561. //
  1562. // Set our protected flags. If we aren't messing with a particular acl, we'll
  1563. // pretend it's protected
  1564. //
  1565. fProtected = ((SECURITY_DESCRIPTOR *)pUpdateSD)->Control &
  1566. ~(SE_DACL_PROTECTED | SE_SACL_PROTECTED);
  1567. if(!FLAG_ON(SeInfo, DACL_SECURITY_INFORMATION))
  1568. {
  1569. fProtected |= SE_DACL_PROTECTED;
  1570. }
  1571. if(!FLAG_ON(SeInfo, SACL_SECURITY_INFORMATION))
  1572. {
  1573. fProtected |= SE_SACL_PROTECTED;
  1574. }
  1575. dwErr = PropagateFileRightsDeep(pUpdateSD,
  1576. pUpdateParentSD,
  1577. SeInfo,
  1578. pwszFile,
  1579. pwszProperty,
  1580. pcProcessed,
  1581. pfStopFlag,
  1582. fProtected,
  1583. hProcessToken,
  1584. FailureLogList);
  1585. }
  1586. //
  1587. // If that worked, write out our updated root security descriptor
  1588. //
  1589. if(dwErr == ERROR_SUCCESS)
  1590. {
  1591. dwErr = SetFilePropertyRights(hObject,
  1592. SeInfo,
  1593. pwszProperty,
  1594. pUpdateSD );
  1595. }
  1596. AccFree(pUpdateParentSD);
  1597. }
  1598. if(pUpdateSD != NULL)
  1599. {
  1600. DestroyPrivateObjectSecurity(&pUpdateSD);
  1601. }
  1602. }
  1603. else
  1604. {
  1605. if(dwErr == ERROR_SUCCESS &&
  1606. FLAG_ON(SeInfo, OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION))
  1607. {
  1608. if(hOpenObject == NULL)
  1609. {
  1610. dwErr = OpenFileObject(pwszFile,
  1611. GetDesiredAccess(WRITE_ACCESS_RIGHTS,
  1612. SeInfo),
  1613. &hObject,
  1614. FALSE);
  1615. }
  1616. else
  1617. {
  1618. hObject = hOpenObject;
  1619. }
  1620. if(dwErr == ERROR_SUCCESS)
  1621. {
  1622. dwErr = SetFilePropertyRights(hObject,
  1623. SeInfo,
  1624. pwszProperty,
  1625. pSD);
  1626. }
  1627. }
  1628. }
  1629. if(dwErr == ERROR_SUCCESS)
  1630. {
  1631. dwErr = WritePropagationFailureList(MARTAEVT_DIRECTORY_PROPAGATION_FAILED,
  1632. FailureLogList,
  1633. hProcessToken);
  1634. //
  1635. // Temporary hack. The failure list should be written to the eventlog rather
  1636. // than to a registry key.
  1637. //
  1638. // Remember to change this in future.
  1639. // KedarD
  1640. //
  1641. dwErr = ERROR_SUCCESS;
  1642. }
  1643. FileCleanup:
  1644. if(hObject != hOpenObject)
  1645. {
  1646. NtClose(hObject);
  1647. }
  1648. AccFree(pReadSD);
  1649. acDebugOut((DEB_TRACE,
  1650. "Out SetAndPropagateFilePropertyRights: %ld\n",
  1651. dwErr));
  1652. return(dwErr);
  1653. }
  1654. //+---------------------------------------------------------------------------
  1655. //
  1656. // Function: SetAndPropagateFilePropertyRightsByHandle
  1657. //
  1658. // Synopsis: Same as above, but deals with a handle to the open object
  1659. // as opposed to a file name.
  1660. //
  1661. // Arguments: [IN hObject] -- File handle
  1662. // [IN pwszProperty] -- Property to set it on
  1663. // [IN RootAccList] -- CAccessList that indicates
  1664. // what access is to be set on
  1665. // the object
  1666. // [IN pfStopFlag] -- Address of the stop flag
  1667. // to be monitored
  1668. // [IN pcProcessed] -- Count of processed items
  1669. //
  1670. // Returns: ERROR_SUCCESS -- Success
  1671. // ERROR_INVALID_PARAMETER -- A bad paramter was given
  1672. //
  1673. //----------------------------------------------------------------------------
  1674. DWORD
  1675. SetAndPropagateFilePropertyRightsByHandle(IN HANDLE hObject,
  1676. IN PWSTR pwszProperty,
  1677. IN CAccessList& RootAccList,
  1678. IN PULONG pfStopFlag,
  1679. IN PULONG pcProcessed)
  1680. {
  1681. acDebugOut((DEB_TRACE, "in SetAndPropagateFilePropertyRightsByHandle\n"));
  1682. CHECK_HEAP
  1683. //
  1684. // We'll do this the easy way... convert it to a path, and call on up
  1685. //
  1686. PWSTR pwszPath = NULL;
  1687. DWORD dwErr = ConvertFileHandleToName(hObject,
  1688. &pwszPath);
  1689. if(dwErr == ERROR_SUCCESS)
  1690. {
  1691. dwErr = SetAndPropagateFilePropertyRights(pwszPath,
  1692. pwszProperty,
  1693. RootAccList,
  1694. pfStopFlag,
  1695. pcProcessed,
  1696. hObject);
  1697. AccFree(pwszPath);
  1698. }
  1699. acDebugOut((DEB_TRACE,
  1700. "Out SetAndPropagateFilePropertyRightsByHandle: %ld\n",
  1701. dwErr));
  1702. return(dwErr);
  1703. }
  1704. //+---------------------------------------------------------------------------
  1705. //
  1706. // Function: GetLMDfsPaths
  1707. //
  1708. // Synopsis: Given a DFS path, this function will return a list of the
  1709. // LANMAN shares supporting this path. If any non-LM paths are
  1710. // found, they are ignored.
  1711. //
  1712. // Arguments: [IN pwszPath] -- Path to check
  1713. // [OUT pcItems] -- Where the count of the
  1714. // number of items in the list
  1715. // is returned
  1716. // [OUT pppwszLocalList] -- OPTIONAL. If present, the
  1717. // list of LM paths is returned
  1718. // here.
  1719. //
  1720. // Returns: ERROR_SUCCESS -- Success
  1721. // ERROR_NOT_ENOUGH_MEMORY -- A memory allocation failed
  1722. //
  1723. //----------------------------------------------------------------------------
  1724. DWORD
  1725. GetLMDfsPaths(IN PWSTR pwszPath,
  1726. OUT PULONG pcItems,
  1727. OUT PWSTR **pppwszLocalList OPTIONAL)
  1728. {
  1729. DWORD dwErr = ERROR_SUCCESS;
  1730. CHECK_HEAP
  1731. PDFS_INFO_3 pDI3;
  1732. dwErr = LoadDLLFuncTable();
  1733. if(dwErr != ERROR_SUCCESS)
  1734. {
  1735. return(dwErr);
  1736. }
  1737. dwErr = (*DLLFuncs.PNetDfsGetInfo)(pwszPath,
  1738. NULL,
  1739. NULL,
  1740. 3,
  1741. (PBYTE *)&pDI3);
  1742. //
  1743. // Now, build the list of information to return.
  1744. //
  1745. if(dwErr == ERROR_SUCCESS)
  1746. {
  1747. //
  1748. // Go through and size our list
  1749. //
  1750. *pcItems = 0;
  1751. DWORD dwSize = sizeof(PWSTR) * pDI3->NumberOfStorages;
  1752. for(ULONG iIndex = 0; iIndex < pDI3->NumberOfStorages; iIndex++)
  1753. {
  1754. WCHAR wszUNCPath[MAX_PATH + 1];
  1755. swprintf(wszUNCPath,
  1756. L"\\\\%ws\\%ws",
  1757. pDI3->Storage[iIndex].ServerName,
  1758. pDI3->Storage[iIndex].ShareName);
  1759. dwErr = IsFilePathLocalOrLM(wszUNCPath);
  1760. if(dwErr != ERROR_SUCCESS)
  1761. {
  1762. if(dwErr == ERROR_PATH_NOT_FOUND)
  1763. {
  1764. dwErr = ERROR_SUCCESS;
  1765. continue;
  1766. }
  1767. else
  1768. {
  1769. break;
  1770. }
  1771. }
  1772. (*pcItems)++;
  1773. if(pppwszLocalList != NULL)
  1774. {
  1775. //
  1776. // Set a flag in the information so we can look up the
  1777. // valid names quicker below, when we copy them
  1778. //
  1779. pDI3->Storage[iIndex].State = 0xFFFFFFFF;
  1780. dwSize += SIZE_PWSTR(pDI3->Storage[iIndex].ServerName);
  1781. dwSize += SIZE_PWSTR(pDI3->Storage[iIndex].ShareName);
  1782. dwSize += 2 * sizeof(WCHAR); // Room for leading \\'s. The
  1783. // NULL of the server name
  1784. // gives the seperator
  1785. }
  1786. }
  1787. if(dwErr == ERROR_SUCCESS && pppwszLocalList != NULL)
  1788. {
  1789. //
  1790. // Now, allocate, and we'll fill
  1791. //
  1792. *pppwszLocalList = (PWSTR *)AccAlloc(dwSize);
  1793. if(*pppwszLocalList == NULL)
  1794. {
  1795. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  1796. }
  1797. else
  1798. {
  1799. PWSTR pwszStrStart = (PWSTR)(*pppwszLocalList +
  1800. (sizeof(PWSTR) * pDI3->NumberOfStorages));
  1801. for(iIndex = 0; iIndex < pDI3->NumberOfStorages; iIndex++)
  1802. {
  1803. if(pDI3->Storage[iIndex].State == 0xFFFFFFFF)
  1804. {
  1805. (*pppwszLocalList)[iIndex] = pwszStrStart;
  1806. swprintf(pwszStrStart,
  1807. L"\\\\%ws\\%ws",
  1808. pDI3->Storage[iIndex].ServerName,
  1809. pDI3->Storage[iIndex].ShareName);
  1810. pwszStrStart += wcslen(pwszStrStart) + 1;
  1811. }
  1812. }
  1813. }
  1814. }
  1815. //
  1816. // Make sure to free our buffer
  1817. //
  1818. (*DLLFuncs.PNetApiBufferFree)(pDI3);
  1819. }
  1820. return(dwErr);
  1821. }
  1822. //+---------------------------------------------------------------------------
  1823. //
  1824. // Function: PropagateFileRightsDeep, recursive
  1825. //
  1826. // Synopsis: Does a deep propagation of the access. At the same time, it
  1827. // will update NT4 acls to NT5 acls. This function is only
  1828. // called on downlevel file systems, so the update will always
  1829. // happen (where appropriate). The algorithm is:
  1830. // - Read the current security descriptor from the object
  1831. // - If it's a downlevel acl, update it using the OLD
  1832. // parent security descriptor (to set any inheritied aces)
  1833. // - Update the security descriptor using the NEW parent
  1834. // security descriptor.
  1835. // - Repeat for its children. (This is necessar, since there
  1836. // could have been unmarked inheritance off of the old
  1837. // security descriptor)
  1838. //
  1839. // Arguments: [IN pParentSD] -- The current parent sd
  1840. // [IN pOldParentSD] -- The previous parent SD (before
  1841. // the current parent SD was
  1842. // stamped on the object)
  1843. // [IN SeInfo] -- What is being written
  1844. // [IN pwszFile] -- Parent file path
  1845. // [IN pwszProperty] -- What property is being
  1846. // written
  1847. // [IN pcProcessed] -- Where the number processed is
  1848. // returned.
  1849. // [IN pfStopFlag] -- Stop flag to monitor
  1850. // [IN fProtectedFlag] -- Indicates whether acls are protected or not
  1851. // [IN hToken] -- Handle to the process token
  1852. //
  1853. // Returns: ERROR_SUCCESS -- Success
  1854. // ERROR_NOT_ENOUGH_MEMORY -- A memory allocation failed
  1855. //
  1856. //----------------------------------------------------------------------------
  1857. #define ALL_STR L"\\*.*"
  1858. DWORD
  1859. PropagateFileRightsDeep(IN PSECURITY_DESCRIPTOR pParentSD,
  1860. IN PSECURITY_DESCRIPTOR pOldParentSD,
  1861. IN SECURITY_INFORMATION SeInfo,
  1862. IN PWSTR pwszFile,
  1863. IN PWSTR pwszProperty,
  1864. IN PULONG pcProcessed,
  1865. IN PULONG pfStopFlag,
  1866. IN ULONG fProtectedFlag,
  1867. IN HANDLE hToken,
  1868. IN OUT CSList& LogList)
  1869. {
  1870. acDebugOut((DEB_TRACE, "in PropagateFileRightsDeep\n"));
  1871. DWORD dwErr = ERROR_SUCCESS;
  1872. WIN32_FIND_DATA FindData;
  1873. HANDLE hFind = NULL;
  1874. HANDLE hChild = NULL;
  1875. ULONG cRootLen = SIZE_PWSTR(pwszFile), Protected = 0;
  1876. SECURITY_DESCRIPTOR *pChildSD = NULL;
  1877. PSECURITY_DESCRIPTOR pNewSD = NULL;
  1878. PWSTR pwszFull = NULL;
  1879. BOOL fUpdateChild = FALSE; // Write out the child?
  1880. BOOL fAccFreeChild = TRUE; // How to free the child
  1881. BOOL fNoPropagate = FALSE;
  1882. BOOL fLoggedFailure = FALSE;
  1883. acDebugOut((DEB_TRACE_PROP, " Path: %ws\n", pwszFile));
  1884. acDebugOut((DEB_TRACE_PROP, " ParentSD: 0x%lx, OldParentSD: 0x%lx\n",
  1885. pParentSD, pOldParentSD));
  1886. //
  1887. // If the any part of the node is going be ingnored because of protection, log it
  1888. //
  1889. if(FLAG_ON(SeInfo, DACL_SECURITY_INFORMATION) && FLAG_ON(fProtectedFlag, SE_DACL_PROTECTED))
  1890. {
  1891. Protected |= SE_DACL_PROTECTED;
  1892. }
  1893. if(FLAG_ON(SeInfo, SACL_SECURITY_INFORMATION) && FLAG_ON(fProtectedFlag, SE_SACL_PROTECTED))
  1894. {
  1895. Protected |= SE_SACL_PROTECTED;
  1896. }
  1897. if( Protected != 0)
  1898. {
  1899. dwErr = InsertPropagationFailureEntry(LogList,
  1900. 0,
  1901. Protected,
  1902. pwszFile);
  1903. if(dwErr != ERROR_SUCCESS)
  1904. {
  1905. return(dwErr);
  1906. }
  1907. }
  1908. //
  1909. // Check to see if we've reached full protection saturation
  1910. //
  1911. if(fProtectedFlag == (SE_DACL_PROTECTED | SE_SACL_PROTECTED))
  1912. {
  1913. acDebugOut((DEB_TRACE_PROP, "Parent of %ws is fully or effectively protected\n",
  1914. pwszFile));
  1915. return(ERROR_SUCCESS);
  1916. }
  1917. //
  1918. // Build the full path name
  1919. //
  1920. PWSTR pwszFindRoot = (PWSTR)AccAlloc(cRootLen + sizeof(ALL_STR));
  1921. if(pwszFindRoot == NULL)
  1922. {
  1923. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  1924. }
  1925. else
  1926. {
  1927. swprintf(pwszFindRoot,
  1928. L"%ws%ws",
  1929. pwszFile,
  1930. ALL_STR);
  1931. hFind = FindFirstFile(pwszFindRoot,
  1932. &FindData);
  1933. if(hFind == INVALID_HANDLE_VALUE)
  1934. {
  1935. dwErr = InsertPropagationFailureEntry(LogList,
  1936. GetLastError(),
  1937. 0,
  1938. pwszFile);
  1939. fNoPropagate = TRUE;
  1940. }
  1941. }
  1942. //
  1943. // Start processing all the files
  1944. //
  1945. while(dwErr == ERROR_SUCCESS && fNoPropagate == FALSE)
  1946. {
  1947. //
  1948. // Ignore the . and ..
  1949. //
  1950. if(_wcsicmp(FindData.cFileName, L".") != 0 &&
  1951. wcscmp(FindData.cFileName, L"..") != 0)
  1952. {
  1953. //
  1954. // Now, build the full path...
  1955. //
  1956. pwszFull = (PWSTR)AccAlloc(cRootLen + SIZE_PWSTR(FindData.cFileName));
  1957. if(pwszFull == NULL)
  1958. {
  1959. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  1960. break;
  1961. }
  1962. wcscpy(pwszFull,
  1963. pwszFile);
  1964. if(pwszFull[(cRootLen / sizeof(WCHAR)) - 2] != L'\\')
  1965. {
  1966. wcscat(pwszFull,
  1967. L"\\");
  1968. }
  1969. wcscat(pwszFull,
  1970. FindData.cFileName);
  1971. acDebugOut((DEB_TRACE_PROP,
  1972. "Processing %ws\n",
  1973. pwszFull));
  1974. //
  1975. // Open the object
  1976. //
  1977. if(hChild != NULL)
  1978. {
  1979. NtClose(hChild);
  1980. hChild = NULL;
  1981. }
  1982. dwErr = OpenFileObject(pwszFull,
  1983. GetDesiredAccess(MODIFY_ACCESS_RIGHTS,
  1984. SeInfo) | FILE_READ_ATTRIBUTES | READ_CONTROL,
  1985. &hChild,
  1986. FALSE);
  1987. if(dwErr == ERROR_SUCCESS)
  1988. {
  1989. //
  1990. // Ok, is it a file or directory
  1991. //
  1992. BOOL fIsCont;
  1993. dwErr = IsFileContainer(hChild,
  1994. &fIsCont);
  1995. //
  1996. // First, we have to read the current security descriptor
  1997. // on the object
  1998. //
  1999. if(dwErr == ERROR_SUCCESS)
  2000. {
  2001. //
  2002. // Get the owner and the group if we have to
  2003. //
  2004. if(pChildSD == NULL ||
  2005. !FLAG_ON(SeInfo, OWNER_SECURITY_INFORMATION) ||
  2006. !FLAG_ON(SeInfo, GROUP_SECURITY_INFORMATION))
  2007. {
  2008. AccFree(pChildSD);
  2009. pChildSD = NULL;
  2010. dwErr = ReadFileSD(hChild,
  2011. SeInfo |
  2012. OWNER_SECURITY_INFORMATION |
  2013. GROUP_SECURITY_INFORMATION,
  2014. 0,
  2015. (PSECURITY_DESCRIPTOR *)&pChildSD);
  2016. }
  2017. if(dwErr == ERROR_SUCCESS)
  2018. {
  2019. //
  2020. // If we don't have an uplevel SecurityDescriptor,
  2021. // we'll need to update it with our old parent sd
  2022. //
  2023. if(!FLAG_ON(pChildSD->Control,
  2024. SE_DACL_AUTO_INHERITED |
  2025. SE_SACL_AUTO_INHERITED))
  2026. {
  2027. dwErr = ConvertToAutoInheritSD(pOldParentSD,
  2028. pChildSD,
  2029. fIsCont,
  2030. &gFileGenMap,
  2031. &pNewSD);
  2032. if(dwErr == ERROR_SUCCESS)
  2033. {
  2034. if(fAccFreeChild == TRUE)
  2035. {
  2036. AccFree(pChildSD);
  2037. }
  2038. else
  2039. {
  2040. DestroyPrivateObjectSecurity((PSECURITY_DESCRIPTOR *)&pChildSD);
  2041. }
  2042. pChildSD = (SECURITY_DESCRIPTOR *)pNewSD;
  2043. fAccFreeChild = FALSE;
  2044. pNewSD = NULL;
  2045. }
  2046. }
  2047. }
  2048. //
  2049. // Now, compute the new security descriptor
  2050. //
  2051. if(dwErr == ERROR_SUCCESS)
  2052. {
  2053. DebugDumpSD("CPOS ParentSD", pParentSD);
  2054. DebugDumpSD("CPOS ChildSD", pChildSD);
  2055. if(CreatePrivateObjectSecurityEx(
  2056. pParentSD,
  2057. pChildSD,
  2058. &pNewSD,
  2059. NULL,
  2060. fIsCont,
  2061. SEF_DACL_AUTO_INHERIT |
  2062. SEF_SACL_AUTO_INHERIT |
  2063. SEF_AVOID_OWNER_CHECK |
  2064. SEF_AVOID_PRIVILEGE_CHECK,
  2065. hToken,
  2066. &gFileGenMap) == FALSE)
  2067. {
  2068. dwErr = GetLastError();
  2069. }
  2070. #ifdef DBG
  2071. if(dwErr == ERROR_SUCCESS)
  2072. {
  2073. DebugDumpSD("CPOS NewChild", pNewSD);
  2074. }
  2075. #endif
  2076. if(dwErr == ERROR_SUCCESS)
  2077. {
  2078. //
  2079. // If the resultant child is protected, don't bother propagating
  2080. // down.
  2081. //
  2082. if(FLAG_ON(SeInfo, DACL_SECURITY_INFORMATION))
  2083. {
  2084. if(DACL_PROTECTED(pNewSD))
  2085. {
  2086. fProtectedFlag |= SE_DACL_PROTECTED;
  2087. }
  2088. }
  2089. if(FLAG_ON(SeInfo, SACL_SECURITY_INFORMATION))
  2090. {
  2091. if(SACL_PROTECTED(pNewSD))
  2092. {
  2093. fProtectedFlag |= SE_SACL_PROTECTED;
  2094. }
  2095. }
  2096. if(fProtectedFlag == (SE_DACL_PROTECTED | SE_SACL_PROTECTED))
  2097. {
  2098. fIsCont = FALSE;
  2099. }
  2100. //
  2101. // If we haven't changed the acl, security descriptor, then
  2102. // we can also quit
  2103. //
  2104. if(EqualSecurityDescriptors(pNewSD, pChildSD))
  2105. {
  2106. fIsCont = FALSE;
  2107. }
  2108. }
  2109. }
  2110. //
  2111. // Now, if it's a directory, call ourselves
  2112. //
  2113. if(dwErr == ERROR_SUCCESS && fIsCont == TRUE)
  2114. {
  2115. dwErr = PropagateFileRightsDeep(pNewSD,
  2116. pChildSD,
  2117. SeInfo,
  2118. pwszFull,
  2119. pwszProperty,
  2120. pcProcessed,
  2121. pfStopFlag,
  2122. fProtectedFlag,
  2123. hToken,
  2124. LogList);
  2125. }
  2126. //
  2127. // Free the old child, since we won't need it anymore
  2128. //
  2129. if(fAccFreeChild == TRUE)
  2130. {
  2131. AccFree(pChildSD);
  2132. }
  2133. else
  2134. {
  2135. DestroyPrivateObjectSecurity((PSECURITY_DESCRIPTOR *)
  2136. &pChildSD);
  2137. }
  2138. pChildSD = NULL;
  2139. }
  2140. }
  2141. else
  2142. {
  2143. dwErr = InsertPropagationFailureEntry(LogList,
  2144. dwErr,
  2145. 0,
  2146. pwszFull);
  2147. fLoggedFailure = TRUE;
  2148. }
  2149. acDebugOut((DEB_TRACE_PROP,
  2150. "Processed %ws: %lu\n",
  2151. pwszFull,
  2152. dwErr));
  2153. //
  2154. // Finally, set the new security
  2155. //
  2156. if(dwErr == ERROR_SUCCESS && fLoggedFailure == FALSE)
  2157. {
  2158. //
  2159. // Now, we'll simply stamp it on the object
  2160. //
  2161. dwErr = SetFilePropertyRights(hChild,
  2162. SeInfo,
  2163. pwszProperty,
  2164. pNewSD);
  2165. (*pcProcessed)++;
  2166. }
  2167. DestroyPrivateObjectSecurity(&pNewSD);
  2168. pNewSD = NULL;
  2169. AccFree(pwszFull);
  2170. pwszFull = NULL;
  2171. fLoggedFailure = FALSE;
  2172. }
  2173. CLEANUP_ON_INTERRUPT(pfStopFlag);
  2174. if(dwErr != ERROR_SUCCESS)
  2175. {
  2176. break;
  2177. }
  2178. if(FindNextFile(hFind,
  2179. &FindData) == FALSE)
  2180. {
  2181. dwErr = GetLastError();
  2182. }
  2183. }
  2184. if(dwErr == ERROR_NO_MORE_FILES)
  2185. {
  2186. dwErr = ERROR_SUCCESS;
  2187. }
  2188. FileCleanup:
  2189. if(hChild != NULL)
  2190. {
  2191. NtClose(hChild);
  2192. }
  2193. if(hFind != NULL)
  2194. {
  2195. FindClose(hFind);
  2196. }
  2197. AccFree(pwszFull);
  2198. AccFree(pwszFindRoot);
  2199. if(pNewSD != NULL)
  2200. {
  2201. DestroyPrivateObjectSecurity(&pNewSD);
  2202. }
  2203. acDebugOut((DEB_TRACE, "Out PropagateFileRightsDeep: %ld\n", dwErr));
  2204. return(dwErr);
  2205. }
  2206. //+---------------------------------------------------------------------------
  2207. //
  2208. // Function: MakeSDSelfRelative
  2209. //
  2210. // Synopsis: Makes the indicated security descriptor self relative,
  2211. // if it isn't already.
  2212. //
  2213. // Arguments: [IN pOldSD] -- The security descriptor to
  2214. // convert
  2215. // [OUT ppNewSD] -- Where the new SD is returned
  2216. // [OUT ppDAcl] -- If non-NULL, the DACL pointer
  2217. // is returned here
  2218. // [OUT ppSAcl] -- If non-NULL, the SACL pointer
  2219. // is returned here
  2220. // [IN fFreeOldSD] -- If true, AccFree is called
  2221. // on the old SD.
  2222. // [IN fRtlAlloc] -- If true, use the RtlAllocation
  2223. // routines instead of AccAlloc
  2224. //
  2225. // Returns: ERROR_SUCCESS -- Success
  2226. // ERROR_NOT_ENOUGH_MEMORY -- A memory allocation failed
  2227. //
  2228. //----------------------------------------------------------------------------
  2229. DWORD
  2230. MakeSDSelfRelative(IN PSECURITY_DESCRIPTOR pOldSD,
  2231. OUT PSECURITY_DESCRIPTOR *ppNewSD,
  2232. OUT PACL *ppDAcl,
  2233. OUT PACL *ppSAcl,
  2234. IN BOOL fFreeOldSD,
  2235. IN BOOL fRtlAlloc)
  2236. {
  2237. DWORD dwErr = ERROR_SUCCESS;
  2238. CHECK_HEAP
  2239. if(pOldSD == NULL)
  2240. {
  2241. *ppNewSD = NULL;
  2242. return(dwErr);
  2243. }
  2244. //
  2245. // If it's already self relative and we don't need it to be allocated via
  2246. // RtlAllocateHead, simply return what we have
  2247. //
  2248. if(FLAG_ON(((SECURITY_DESCRIPTOR *)pOldSD)->Control,
  2249. SE_SELF_RELATIVE) && fRtlAlloc == FALSE)
  2250. {
  2251. *ppNewSD = pOldSD;
  2252. }
  2253. else
  2254. {
  2255. DWORD dwSize = RtlLengthSecurityDescriptor(pOldSD);
  2256. if(fRtlAlloc == FALSE)
  2257. {
  2258. *ppNewSD = (PSECURITY_DESCRIPTOR)AccAlloc(dwSize);
  2259. }
  2260. else
  2261. {
  2262. *ppNewSD = (PSECURITY_DESCRIPTOR)RtlAllocateHeap(RtlProcessHeap(),
  2263. 0, dwSize);
  2264. }
  2265. if(*ppNewSD == NULL)
  2266. {
  2267. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  2268. }
  2269. else
  2270. {
  2271. if(FLAG_ON(((SECURITY_DESCRIPTOR *)pOldSD)->Control, SE_SELF_RELATIVE))
  2272. {
  2273. RtlCopyMemory(*ppNewSD, pOldSD, dwSize);
  2274. }
  2275. else
  2276. {
  2277. if(MakeSelfRelativeSD(pOldSD,
  2278. *ppNewSD,
  2279. &dwSize) == FALSE)
  2280. {
  2281. dwErr = GetLastError();
  2282. if(fRtlAlloc == FALSE)
  2283. {
  2284. AccFree(*ppNewSD);
  2285. *ppNewSD = NULL;
  2286. }
  2287. else
  2288. {
  2289. RtlFreeHeap(RtlProcessHeap(), 0, *ppNewSD);
  2290. }
  2291. }
  2292. }
  2293. }
  2294. }
  2295. if(dwErr == ERROR_SUCCESS)
  2296. {
  2297. if(ppDAcl != NULL)
  2298. {
  2299. *ppDAcl =
  2300. RtlpDaclAddrSecurityDescriptor((SECURITY_DESCRIPTOR *)*ppNewSD);
  2301. }
  2302. if(ppSAcl != NULL)
  2303. {
  2304. *ppSAcl =
  2305. RtlpSaclAddrSecurityDescriptor((SECURITY_DESCRIPTOR *)*ppNewSD);
  2306. }
  2307. //
  2308. // Don't release it if we're returning it...
  2309. //
  2310. if(fFreeOldSD == TRUE && *ppNewSD != pOldSD)
  2311. {
  2312. AccFree(pOldSD);
  2313. }
  2314. }
  2315. return(dwErr);
  2316. }
  2317. //+---------------------------------------------------------------------------
  2318. //
  2319. // Function: UpdateFileSDByPath
  2320. //
  2321. // Synopsis: Determines the inheritance necessary for the current security
  2322. // descriptor given the path to the object
  2323. //
  2324. // Arguments: [IN pCurrentSD] -- The security descriptor to
  2325. // update
  2326. // [IN pwszPath] -- The path to th object
  2327. // [IN hFile] -- Handle to the open file
  2328. // [IN SeInfo] -- The security information of
  2329. // the current SD.
  2330. // [IN fIsContainer] -- Does the Sec. Desc. refer to
  2331. // a container?
  2332. // [OUT ppNewSD] -- Where the new SD is returned
  2333. //
  2334. // Returns: ERROR_SUCCESS -- Success
  2335. //
  2336. // Notes: The returned security descriptor must be freed via a call to
  2337. // DestroyPrivateObjectSecurity
  2338. //
  2339. //----------------------------------------------------------------------------
  2340. DWORD
  2341. UpdateFileSDByPath(IN PSECURITY_DESCRIPTOR pCurrentSD,
  2342. IN PWSTR pwszPath,
  2343. IN HANDLE hFile,
  2344. IN HANDLE hProcessToken,
  2345. IN SECURITY_INFORMATION SeInfo,
  2346. IN BOOL fIsContainer,
  2347. OUT PSECURITY_DESCRIPTOR *ppNewSD)
  2348. {
  2349. DWORD dwErr = ERROR_SUCCESS;
  2350. CHECK_HEAP
  2351. acDebugOut((DEB_TRACE, "In UpdateFileSDByPath\n"));
  2352. PSECURITY_DESCRIPTOR pSD = pCurrentSD;
  2353. PSECURITY_DESCRIPTOR pParentSD = NULL;
  2354. if(!FLAG_ON(SeInfo, OWNER_SECURITY_INFORMATION) ||
  2355. !FLAG_ON(SeInfo, GROUP_SECURITY_INFORMATION))
  2356. {
  2357. //
  2358. // We'll have to reopen by path to get this to work properly, since we're
  2359. // now reading the owner/group
  2360. //
  2361. HANDLE hLocalFile;
  2362. dwErr = OpenFileObject(pwszPath,
  2363. GetDesiredAccess(READ_ACCESS_RIGHTS,
  2364. SeInfo |
  2365. OWNER_SECURITY_INFORMATION |
  2366. GROUP_SECURITY_INFORMATION) |
  2367. FILE_READ_ATTRIBUTES,
  2368. &hLocalFile,
  2369. FALSE);
  2370. //
  2371. // If we get back an access denied from the open request, try it with the
  2372. // handle we were given on input
  2373. //
  2374. if(dwErr == ERROR_ACCESS_DENIED)
  2375. {
  2376. hLocalFile = hFile;
  2377. dwErr = ERROR_SUCCESS;
  2378. }
  2379. if(dwErr == ERROR_SUCCESS)
  2380. {
  2381. dwErr = GetKernelSecurityInfo(hLocalFile,
  2382. SeInfo |
  2383. OWNER_SECURITY_INFORMATION |
  2384. GROUP_SECURITY_INFORMATION,
  2385. NULL,
  2386. NULL,
  2387. &pSD);
  2388. if(hLocalFile != hFile)
  2389. {
  2390. NtClose(hLocalFile);
  2391. }
  2392. }
  2393. }
  2394. if(dwErr == ERROR_SUCCESS)
  2395. {
  2396. //
  2397. // Get the parent security descriptor
  2398. //
  2399. ACTRL_RIGHTS_INFO RightsInfo;
  2400. RightsInfo.SeInfo = SeInfo;
  2401. RightsInfo.pwszProperty = 0;
  2402. dwErr = GetFileParentRights(pwszPath,
  2403. &RightsInfo,
  2404. 1,
  2405. NULL,
  2406. NULL,
  2407. &pParentSD);
  2408. }
  2409. //
  2410. // Finally, do the update
  2411. //
  2412. if(dwErr == ERROR_SUCCESS)
  2413. {
  2414. acDebugOut((DEB_TRACE_PROP,"Update being called: Parent info: 0x%lx\n",
  2415. pParentSD));
  2416. acDebugOut((DEB_TRACE_PROP,"Child: path %ws, 0x%lx\n",
  2417. pwszPath, pSD));
  2418. if(CreatePrivateObjectSecurityEx(pParentSD,
  2419. pSD,
  2420. ppNewSD,
  2421. NULL,
  2422. fIsContainer,
  2423. SEF_DACL_AUTO_INHERIT |
  2424. SEF_SACL_AUTO_INHERIT |
  2425. SEF_AVOID_OWNER_CHECK |
  2426. SEF_AVOID_PRIVILEGE_CHECK,
  2427. hProcessToken,
  2428. &gFileGenMap) == FALSE)
  2429. {
  2430. dwErr = GetLastError();
  2431. }
  2432. AccFree(pParentSD);
  2433. }
  2434. //
  2435. // See if we had to read a new security descriptor for the object. If so,
  2436. // we'll need to release that memory as well
  2437. //
  2438. if(pSD != pCurrentSD)
  2439. {
  2440. AccFree(pSD);
  2441. }
  2442. acDebugOut((DEB_TRACE, "Out UpdateFileSDByPath: %ld\n", dwErr));
  2443. return(dwErr);
  2444. }