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.

1241 lines
36 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (C) Microsoft Corporation, 1996 - 1999
  6. //
  7. // File: util.cpp
  8. //
  9. // This file contains misc functions.
  10. //
  11. //--------------------------------------------------------------------------
  12. #include "rshx32.h"
  13. #include <shlobjp.h> // SHFree
  14. #include <shlwapip.h> // IsOS
  15. #include <safeboot.h> // SAFEBOOT_* flags
  16. STDMETHODIMP
  17. IDA_BindToFolder(LPIDA pIDA, LPSHELLFOLDER *ppsf)
  18. {
  19. HRESULT hr;
  20. LPSHELLFOLDER psfDesktop;
  21. TraceEnter(TRACE_UTIL, "IDA_BindToFolder");
  22. TraceAssert(pIDA != NULL);
  23. TraceAssert(ppsf != NULL);
  24. *ppsf = NULL;
  25. hr = SHGetDesktopFolder(&psfDesktop);
  26. if (SUCCEEDED(hr))
  27. {
  28. LPCITEMIDLIST pidlFolder = (LPCITEMIDLIST)ByteOffset(pIDA, pIDA->aoffset[0]);
  29. if (ILIsEmpty(pidlFolder))
  30. {
  31. // We're binding to the desktop
  32. *ppsf = psfDesktop;
  33. }
  34. else
  35. {
  36. hr = psfDesktop->BindToObject(pidlFolder,
  37. NULL,
  38. IID_IShellFolder,
  39. (PVOID*)ppsf);
  40. psfDesktop->Release();
  41. }
  42. }
  43. TraceLeaveResult(hr);
  44. }
  45. STDMETHODIMP
  46. IDA_GetItemName(LPSHELLFOLDER psf,
  47. LPCITEMIDLIST pidl,
  48. LPTSTR pszName,
  49. UINT cchName,
  50. SHGNO uFlags)
  51. {
  52. STRRET str;
  53. HRESULT hr;
  54. hr = psf->GetDisplayNameOf(pidl, uFlags, &str);
  55. if (SUCCEEDED(hr))
  56. {
  57. DWORD dwErr;
  58. LPSTR psz;
  59. switch (str.uType)
  60. {
  61. case STRRET_WSTR:
  62. lstrcpyn(pszName, str.pOleStr, cchName);
  63. //
  64. // Since this string was alocated from the shell's IMalloc heap,
  65. // we must free it to the same place.
  66. //
  67. SHFree(str.pOleStr);
  68. break;
  69. case STRRET_OFFSET:
  70. psz = (LPSTR)ByteOffset(pidl, str.uOffset);
  71. goto GetItemName_ANSI;
  72. case STRRET_CSTR:
  73. psz = str.cStr;
  74. GetItemName_ANSI:
  75. if (!MultiByteToWideChar(CP_ACP,
  76. 0,
  77. psz,
  78. -1,
  79. pszName,
  80. cchName))
  81. {
  82. dwErr = GetLastError();
  83. hr = HRESULT_FROM_WIN32(dwErr);
  84. }
  85. break;
  86. default:
  87. hr = E_UNEXPECTED;
  88. break;
  89. }
  90. }
  91. return hr;
  92. }
  93. STDMETHODIMP
  94. IDA_GetItemName(LPSHELLFOLDER psf,
  95. LPCITEMIDLIST pidl,
  96. LPTSTR *ppszName,
  97. SHGNO uFlags)
  98. {
  99. TCHAR szName[MAX_PATH];
  100. HRESULT hr = IDA_GetItemName(psf, pidl, szName, ARRAYSIZE(szName));
  101. if (SUCCEEDED(hr))
  102. hr = LocalAllocString(ppszName, szName);
  103. else
  104. *ppszName = NULL;
  105. return hr;
  106. }
  107. //
  108. // Helper functions used by DPA_CompareSecurityIntersection
  109. //
  110. BOOL
  111. IsEqualSID(PSID pSid1, PSID pSid2)
  112. {
  113. //
  114. // Are they both NULL?
  115. //
  116. if (pSid1 || pSid2)
  117. {
  118. //
  119. // At least one is non-NULL, so if one is NULL then they can't
  120. // be equal.
  121. //
  122. if (pSid1 == NULL || pSid2 == NULL)
  123. return FALSE;
  124. //
  125. // Both are non-NULL. Check the SIDs.
  126. //
  127. if (!EqualSid(pSid1, pSid2))
  128. return FALSE;
  129. }
  130. return TRUE;
  131. }
  132. BOOL
  133. IsEqualACL(PACL pA1, PACL pA2)
  134. {
  135. //
  136. // Are they both NULL?
  137. //
  138. if (pA1 || pA2)
  139. {
  140. //
  141. // At least one is non-NULL, so if one is NULL then they can't
  142. // be equal.
  143. //
  144. if (pA1 == NULL || pA2 == NULL)
  145. return FALSE;
  146. //
  147. // At this point we know that both are non-NULL. Check the
  148. // sizes and contents.
  149. //
  150. // could do a lot more here
  151. if (pA1->AclSize != pA2->AclSize || memcmp(pA1, pA2, pA1->AclSize))
  152. return FALSE;
  153. }
  154. return TRUE;
  155. }
  156. //+---------------------------------------------------------------------------
  157. //
  158. // Function: CompareSecurityDescriptors
  159. //
  160. // Synopsis: Determines if 2 security descriptors are identical. It does
  161. // this by comparing control fields, owner/group, and acls.
  162. //
  163. // Arguments: [IN] pSD1 - 1st SD to compare
  164. // [IN] pSD2 - 2nd SD to compare
  165. // [OUT] pfOwnerConflict - (optional) Set to TRUE if the Owner SIDs are not equal
  166. // [OUT] pfGroupConflict - (optional) Set to TRUE if the Group SIDs are not equal
  167. // [OUT] pfDACLConflict - (optional) Set to TRUE if the DACLs are not equal
  168. // [OUT] pfSACLConflict - (optional) Set to TRUE if the SACLs are not equal
  169. //
  170. // Returns: nothing
  171. //
  172. //
  173. //----------------------------------------------------------------------------
  174. #define DACL_CONTROL_MASK (SE_DACL_PRESENT | SE_DACL_DEFAULTED | SE_DACL_AUTO_INHERITED | SE_DACL_PROTECTED)
  175. #define SACL_CONTROL_MASK (SE_SACL_PRESENT | SE_SACL_DEFAULTED | SE_SACL_AUTO_INHERITED | SE_SACL_PROTECTED)
  176. void
  177. CompareSecurityDescriptors(PSECURITY_DESCRIPTOR pSD1,
  178. PSECURITY_DESCRIPTOR pSD2,
  179. BOOL *pfOwnerConflict,
  180. BOOL *pfGroupConflict,
  181. BOOL *pfSACLConflict,
  182. BOOL *pfDACLConflict)
  183. {
  184. PISECURITY_DESCRIPTOR pS1 = (PISECURITY_DESCRIPTOR)pSD1;
  185. PISECURITY_DESCRIPTOR pS2 = (PISECURITY_DESCRIPTOR)pSD2;
  186. //
  187. // Are the pointers identical?
  188. // This includes the case where both are NULL.
  189. //
  190. if (pS1 == pS2)
  191. {
  192. if (pfOwnerConflict)
  193. *pfOwnerConflict = FALSE;
  194. if (pfGroupConflict)
  195. *pfGroupConflict = FALSE;
  196. if (pfSACLConflict)
  197. *pfSACLConflict = FALSE;
  198. if (pfDACLConflict)
  199. *pfDACLConflict = FALSE;
  200. return;
  201. }
  202. //
  203. // Is (only) one of them NULL? If so, then we can't compare so
  204. // assume that nothing matches.
  205. //
  206. if (!pS1 || !pS2)
  207. {
  208. if (pfOwnerConflict)
  209. *pfOwnerConflict = TRUE;
  210. if (pfGroupConflict)
  211. *pfGroupConflict = TRUE;
  212. if (pfSACLConflict)
  213. *pfSACLConflict = TRUE;
  214. if (pfDACLConflict)
  215. *pfDACLConflict = TRUE;
  216. return;
  217. }
  218. //
  219. // Owner
  220. //
  221. if (pfOwnerConflict)
  222. {
  223. if ((pS1->Control & SE_OWNER_DEFAULTED) != (pS2->Control & SE_OWNER_DEFAULTED))
  224. {
  225. *pfOwnerConflict = TRUE;
  226. }
  227. else
  228. {
  229. *pfOwnerConflict = !IsEqualSID(RtlpOwnerAddrSecurityDescriptor(pS1),
  230. RtlpOwnerAddrSecurityDescriptor(pS2));
  231. }
  232. }
  233. //
  234. // Group
  235. //
  236. if (pfGroupConflict)
  237. {
  238. if ((pS1->Control & SE_GROUP_DEFAULTED) != (pS2->Control & SE_GROUP_DEFAULTED))
  239. {
  240. *pfGroupConflict = TRUE;
  241. }
  242. else
  243. {
  244. *pfGroupConflict = !IsEqualSID(RtlpGroupAddrSecurityDescriptor(pS1),
  245. RtlpGroupAddrSecurityDescriptor(pS2));
  246. }
  247. }
  248. //
  249. // Sacl
  250. //
  251. if (pfSACLConflict)
  252. {
  253. if ((pS1->Control & SACL_CONTROL_MASK) != (pS2->Control & SACL_CONTROL_MASK))
  254. {
  255. *pfSACLConflict = TRUE;
  256. }
  257. else
  258. {
  259. *pfSACLConflict = !IsEqualACL(RtlpSaclAddrSecurityDescriptor(pS1),
  260. RtlpSaclAddrSecurityDescriptor(pS2));
  261. }
  262. }
  263. //
  264. // Dacl
  265. //
  266. if (pfDACLConflict)
  267. {
  268. if ((pS1->Control & DACL_CONTROL_MASK) != (pS2->Control & DACL_CONTROL_MASK))
  269. {
  270. *pfDACLConflict = TRUE;
  271. }
  272. else
  273. {
  274. *pfDACLConflict = !IsEqualACL(RtlpDaclAddrSecurityDescriptor(pS1),
  275. RtlpDaclAddrSecurityDescriptor(pS2));
  276. }
  277. }
  278. }
  279. /*******************************************************************
  280. NAME: DPA_CompareSecurityIntersection
  281. SYNOPSIS: Determines if the selected objects have
  282. equivalent security descriptors
  283. ENTRY: hItemList - DPA containing item names
  284. pfnReadSD - callback function to read the Security Descriptor
  285. for a single item.
  286. pfOwnerConflict - (optional) Set to TRUE if not all Owner SIDs are equal
  287. pfGroupConflict - (optional) Set to TRUE if not all Group SIDs are equal
  288. pfDACLConflict - (optional) Set to TRUE if not all DACLs are equal
  289. pfSACLConflict - (optional) Set to TRUE if not all SACLs are equal
  290. ppszOwnerConflict - (optional) The name of the first item
  291. with a different Owner is returned here.
  292. Free with LocalFreeString.
  293. ppszGroupConflict - (optional) similar to ppszOwnerConflict
  294. ppszDaclConflict - (optional) similar to ppszOwnerConflict
  295. ppszSaclConflict - (optional) similar to ppszOwnerConflict
  296. ppszFailureMsg - Message to display in case of failure.
  297. RETURNS: S_OK if successful, HRESULT error code otherwise
  298. NOTES: The function may exit without checking all objects if all of
  299. the requested flags become FALSE. All out parameters are
  300. valid if the function succeeds, and undetermined otherwise.
  301. HISTORY:
  302. JeffreyS 18-Feb-1997 Created
  303. ********************************************************************/
  304. STDMETHODIMP
  305. DPA_CompareSecurityIntersection(HDPA hItemList,
  306. PFN_READ_SD pfnReadSD,
  307. BOOL *pfOwnerConflict,
  308. BOOL *pfGroupConflict,
  309. BOOL *pfSACLConflict,
  310. BOOL *pfDACLConflict,
  311. LPTSTR *ppszOwnerConflict,
  312. LPTSTR *ppszGroupConflict,
  313. LPTSTR *ppszSaclConflict,
  314. LPTSTR *ppszDaclConflict,
  315. LPTSTR *ppszFailureMsg,
  316. LPBOOL pbCancel)
  317. {
  318. HRESULT hr = S_OK;
  319. DWORD dwErr;
  320. SECURITY_INFORMATION si = 0;
  321. DWORD dwPriv = SE_SECURITY_PRIVILEGE;
  322. HANDLE hToken = INVALID_HANDLE_VALUE;
  323. LPTSTR pszItem;
  324. LPTSTR pszFile;
  325. PSECURITY_DESCRIPTOR pSD1 = NULL;
  326. PSECURITY_DESCRIPTOR pSD2 = NULL;
  327. int i;
  328. #if DBG
  329. DWORD dwTimeStart = GetTickCount();
  330. #endif
  331. TraceEnter(TRACE_UTIL, "DPA_CompareSecurityIntersection");
  332. TraceAssert(hItemList != NULL);
  333. TraceAssert(pfnReadSD != NULL);
  334. if (pfOwnerConflict)
  335. {
  336. *pfOwnerConflict = FALSE;
  337. si |= OWNER_SECURITY_INFORMATION;
  338. }
  339. if (pfGroupConflict)
  340. {
  341. *pfGroupConflict = FALSE;
  342. si |= GROUP_SECURITY_INFORMATION;
  343. }
  344. if (pfSACLConflict)
  345. {
  346. *pfSACLConflict = FALSE;
  347. // SeAuditPrivilege must be enabled to read the SACL.
  348. hToken = EnablePrivileges(&dwPriv, 1);
  349. if (INVALID_HANDLE_VALUE != hToken)
  350. {
  351. si |= SACL_SECURITY_INFORMATION;
  352. }
  353. else
  354. {
  355. // Leave *pfSACLConflict set to FALSE
  356. pfSACLConflict = NULL;
  357. TraceMsg("Security privilege not enabled -- not checking SACL");
  358. }
  359. }
  360. if (pfDACLConflict)
  361. {
  362. *pfDACLConflict = FALSE;
  363. si |= DACL_SECURITY_INFORMATION;
  364. }
  365. if (ppszOwnerConflict != NULL)
  366. *ppszOwnerConflict = NULL;
  367. if (ppszGroupConflict != NULL)
  368. *ppszGroupConflict = NULL;
  369. if (ppszSaclConflict != NULL)
  370. *ppszSaclConflict = NULL;
  371. if (ppszDaclConflict != NULL)
  372. *ppszDaclConflict = NULL;
  373. if (si == 0 || DPA_GetPtrCount(hItemList) < 2)
  374. ExitGracefully(hr, S_OK, "Nothing requested or list contains only one item");
  375. if (pbCancel && *pbCancel)
  376. ExitGracefully(hr, S_OK, "DPA_CompareSecurityIntersection cancelled");
  377. //
  378. // Get the first item name and load its security descriptor.
  379. //
  380. pszItem = (LPTSTR)DPA_FastGetPtr(hItemList, 0);
  381. if (NULL == pszItem)
  382. ExitGracefully(hr, E_UNEXPECTED, "Item list is empty");
  383. dwErr = (*pfnReadSD)(pszItem, si, &pSD1);
  384. if (dwErr)
  385. {
  386. //Incase of multiple of selection, if we fail to read the security descriptor
  387. //of single item, security page should be disabled.
  388. LPTSTR pszSystemError = NULL;
  389. LPTSTR pszFailureMsg = NULL;
  390. if (GetSystemErrorText(&pszSystemError, dwErr))
  391. {
  392. //often last two chars are \r\n sequence which break our formatting.
  393. DWORD dwLen = wcslen(pszSystemError);
  394. if(dwLen >= 2 && pszSystemError[dwLen-2] == 0x0d && pszSystemError[dwLen-1] ==0x0a)
  395. {
  396. pszSystemError[dwLen-2] = 0;
  397. }
  398. FormatStringID(&pszFailureMsg, g_hInstance, IDS_MULTIPLE_SELECTION_READ_ERROR, pszItem, pszSystemError);
  399. }
  400. else
  401. {
  402. FormatStringID(&pszFailureMsg, g_hInstance, IDS_MULTIPLE_SELECTION_READ_ERROR_1, pszItem);
  403. }
  404. *ppszFailureMsg = pszFailureMsg;
  405. ExitGracefully(hr, HRESULT_FROM_WIN32(dwErr), "Unable to read Security Descriptor");
  406. }
  407. //
  408. // Go through the rest of the list and compare their security
  409. // descriptors to the first one.
  410. //
  411. for (i = 1; i < DPA_GetPtrCount(hItemList) && si != 0; i++)
  412. {
  413. if (pbCancel && *pbCancel)
  414. ExitGracefully(hr, S_OK, "DPA_CompareSecurityIntersection cancelled");
  415. pszItem = (LPTSTR)DPA_FastGetPtr(hItemList, i);
  416. if (NULL == pszItem)
  417. ExitGracefully(hr, E_UNEXPECTED, "Unable to retrieve item name from list");
  418. dwErr = (*pfnReadSD)(pszItem, si, &pSD2);
  419. if (dwErr)
  420. {
  421. //Incase of multiple of selection, if we fail to read the security descriptor
  422. //of single item, security page should be disabled.
  423. LPTSTR pszSystemError = NULL;
  424. LPTSTR pszFailureMsg = NULL;
  425. if (GetSystemErrorText(&pszSystemError, dwErr))
  426. {
  427. //often last two chars are \r\n sequence which break our formatting.
  428. DWORD dwLen = wcslen(pszSystemError);
  429. if(dwLen >= 2 && pszSystemError[dwLen-2] == 0x0d && pszSystemError[dwLen-1] ==0x0a)
  430. {
  431. pszSystemError[dwLen-2] = 0;
  432. }
  433. FormatStringID(&pszFailureMsg, g_hInstance, IDS_MULTIPLE_SELECTION_READ_ERROR, pszItem, pszSystemError);
  434. }
  435. else
  436. {
  437. FormatStringID(&pszFailureMsg, g_hInstance, IDS_MULTIPLE_SELECTION_READ_ERROR_1, pszItem);
  438. }
  439. *ppszFailureMsg = pszFailureMsg;
  440. ExitGracefully(hr, HRESULT_FROM_WIN32(dwErr), "Unable to read Security Descriptor");
  441. }
  442. CompareSecurityDescriptors(pSD1,
  443. pSD2,
  444. pfOwnerConflict,
  445. pfGroupConflict,
  446. pfSACLConflict,
  447. pfDACLConflict);
  448. if (pSD2 != NULL)
  449. {
  450. LocalFree(pSD2);
  451. pSD2 = NULL;
  452. }
  453. //
  454. // Get the leaf name of the item to return as the conflict name
  455. //
  456. pszFile = PathFindFileName(pszItem);
  457. if (!pszFile)
  458. pszFile = pszItem;
  459. // If we find an owner that doesn't match, we can stop checking owners
  460. if (pfOwnerConflict && *pfOwnerConflict)
  461. {
  462. pfOwnerConflict = NULL;
  463. si &= ~OWNER_SECURITY_INFORMATION;
  464. if (ppszOwnerConflict)
  465. LocalAllocString(ppszOwnerConflict, pszFile);
  466. }
  467. // Ditto for the group
  468. if (pfGroupConflict && *pfGroupConflict)
  469. {
  470. pfGroupConflict = NULL;
  471. si &= ~GROUP_SECURITY_INFORMATION;
  472. if (ppszGroupConflict)
  473. LocalAllocString(ppszGroupConflict, pszFile);
  474. }
  475. // Same for SACLs
  476. if (pfSACLConflict && *pfSACLConflict)
  477. {
  478. pfSACLConflict = NULL;
  479. si &= ~SACL_SECURITY_INFORMATION;
  480. if (ppszSaclConflict)
  481. LocalAllocString(ppszSaclConflict, pszFile);
  482. }
  483. // Same for DACLs
  484. if (pfDACLConflict && *pfDACLConflict)
  485. {
  486. pfDACLConflict = NULL;
  487. si &= ~DACL_SECURITY_INFORMATION;
  488. if (ppszDaclConflict)
  489. LocalAllocString(ppszDaclConflict, pszFile);
  490. }
  491. }
  492. exit_gracefully:
  493. // Release any privileges we enabled
  494. ReleasePrivileges(hToken);
  495. if (FAILED(hr))
  496. {
  497. LocalFreeString(ppszOwnerConflict);
  498. LocalFreeString(ppszGroupConflict);
  499. LocalFreeString(ppszSaclConflict);
  500. LocalFreeString(ppszDaclConflict);
  501. }
  502. if (pSD1 != NULL)
  503. LocalFree(pSD1);
  504. #if DBG
  505. Trace((TEXT("DPA_CompareSecurityIntersection done: %d"), GetTickCount() - dwTimeStart));
  506. #endif
  507. TraceLeaveResult(hr);
  508. }
  509. //*************************************************************
  510. //
  511. // GetRemotePath
  512. //
  513. // Purpose: Return UNC version of a path
  514. //
  515. // Parameters: pszInName - initial path
  516. // ppszOutName - UNC path returned here
  517. //
  518. //
  519. // Return: HRESULT
  520. // S_OK - UNC path returned
  521. // S_FALSE - drive not connected (UNC not returned)
  522. // or failure code
  523. //
  524. // Notes: The function fails is the path is not a valid
  525. // network path. If the path is already UNC,
  526. // a copy is made without validating the path.
  527. // *ppszOutName must be LocalFree'd by the caller.
  528. //
  529. //*************************************************************
  530. DWORD _WNetGetConnection(LPCTSTR pszLocal, LPTSTR pszRemote, LPDWORD pdwLen)
  531. {
  532. DWORD dwErr = ERROR_PROC_NOT_FOUND;
  533. // This is the only function we call in mpr.dll, and it's delay-loaded
  534. // so wrap it with SEH.
  535. __try
  536. {
  537. dwErr = WNetGetConnection(pszLocal, pszRemote, pdwLen);
  538. }
  539. __finally
  540. {
  541. }
  542. return dwErr;
  543. }
  544. STDMETHODIMP
  545. GetRemotePath(LPCTSTR pszInName, LPTSTR *ppszOutName)
  546. {
  547. HRESULT hr = HRESULT_FROM_WIN32(ERROR_BAD_PATHNAME);
  548. TraceEnter(TRACE_UTIL, "GetRemotePath");
  549. TraceAssert(pszInName);
  550. TraceAssert(ppszOutName);
  551. *ppszOutName = NULL;
  552. if (pszInName[1] == TEXT(':'))
  553. {
  554. DWORD dwErr;
  555. TCHAR szLocalName[3];
  556. TCHAR szRemoteName[MAX_PATH];
  557. DWORD dwLen = ARRAYSIZE(szRemoteName);
  558. szLocalName[0] = pszInName[0];
  559. szLocalName[1] = pszInName[1];
  560. szLocalName[2] = TEXT('\0');
  561. dwErr = _WNetGetConnection(szLocalName, szRemoteName, &dwLen);
  562. if (NO_ERROR == dwErr)
  563. {
  564. hr = S_OK;
  565. dwLen = lstrlen(szRemoteName);
  566. }
  567. else if (ERROR_NOT_CONNECTED == dwErr)
  568. {
  569. ExitGracefully(hr, S_FALSE, "Drive not connected");
  570. }
  571. else if (ERROR_MORE_DATA != dwErr)
  572. ExitGracefully(hr, HRESULT_FROM_WIN32(dwErr), "WNetGetConnection failed");
  573. // if dwErr == ERROR_MORE_DATA, dwLen already has the correct value
  574. // Skip the drive letter and add the length of the rest of the path
  575. // (including NULL)
  576. pszInName += 2;
  577. DWORD dwOutputLen = dwLen + lstrlen(pszInName) + 1;
  578. // We should never get incomplete paths, so we should always
  579. // see a backslash after the "X:". If this isn't true, then
  580. // we should call GetFullPathName above.
  581. TraceAssert(TEXT('\\') == *pszInName);
  582. // Allocate the return buffer
  583. *ppszOutName = (LPTSTR)LocalAlloc(LPTR, dwOutputLen * SIZEOF(TCHAR));
  584. if (!*ppszOutName)
  585. ExitGracefully(hr, E_OUTOFMEMORY, "LocalAlloc failed");
  586. if (ERROR_MORE_DATA == dwErr)
  587. {
  588. // Try again with the bigger buffer
  589. dwErr = _WNetGetConnection(szLocalName, *ppszOutName, &dwLen);
  590. hr = HRESULT_FROM_WIN32(dwErr);
  591. FailGracefully(hr, "WNetGetConnection failed");
  592. }
  593. else
  594. {
  595. // WNetGetConnection succeeded. Copy the result
  596. lstrcpy(*ppszOutName, szRemoteName);
  597. }
  598. // Copy the rest of the path
  599. hr = StringCchCat(*ppszOutName,dwOutputLen,pszInName);
  600. }
  601. else if (PathIsUNC(pszInName))
  602. {
  603. // Just copy the path without validating it
  604. hr = LocalAllocString(ppszOutName, pszInName);
  605. }
  606. exit_gracefully:
  607. if (FAILED(hr))
  608. {
  609. LocalFreeString(ppszOutName);
  610. }
  611. else
  612. {
  613. if(*ppszOutName)
  614. {
  615. //Trailing backshash causes IsShareRoot to fail.
  616. //NTRAID#NTBUG9-533576-2002/05/06-hiteshr
  617. PathRemoveBackslash(*ppszOutName);
  618. }
  619. }
  620. TraceLeaveResult(hr);
  621. }
  622. /*******************************************************************
  623. NAME: LocalFreeDPA
  624. SYNOPSIS: LocalFree's all pointers in a Dynamic Pointer
  625. Array and then frees the DPA.
  626. ENTRY: hList - handle of list to destroy
  627. RETURNS: nothing
  628. ********************************************************************/
  629. int CALLBACK
  630. _LocalFreeCB(LPVOID pVoid, LPVOID /*pData*/)
  631. {
  632. if (pVoid)
  633. LocalFree(pVoid);
  634. return 1;
  635. }
  636. void
  637. LocalFreeDPA(HDPA hList)
  638. {
  639. if (hList != NULL)
  640. DPA_DestroyCallback(hList, _LocalFreeCB, 0);
  641. }
  642. //+---------------------------------------------------------------------------
  643. //
  644. // Function: IsSafeMode
  645. //
  646. // Synopsis: Checks the registry to see if the system is in safe mode.
  647. //
  648. // History: 06-Oct-00 JeffreyS Created
  649. //
  650. //----------------------------------------------------------------------------
  651. BOOL
  652. IsSafeMode(void)
  653. {
  654. BOOL fIsSafeMode = FALSE;
  655. LONG ec;
  656. HKEY hkey;
  657. ec = RegOpenKeyEx(
  658. HKEY_LOCAL_MACHINE,
  659. TEXT("SYSTEM\\CurrentControlSet\\Control\\SafeBoot\\Option"),
  660. 0,
  661. KEY_QUERY_VALUE,
  662. &hkey
  663. );
  664. if (ec == NO_ERROR)
  665. {
  666. DWORD dwValue;
  667. DWORD dwValueSize = sizeof(dwValue);
  668. ec = RegQueryValueEx(hkey,
  669. TEXT("OptionValue"),
  670. NULL,
  671. NULL,
  672. (LPBYTE)&dwValue,
  673. &dwValueSize);
  674. if (ec == NO_ERROR)
  675. {
  676. fIsSafeMode = (dwValue == SAFEBOOT_MINIMAL || dwValue == SAFEBOOT_NETWORK);
  677. }
  678. RegCloseKey(hkey);
  679. }
  680. return fIsSafeMode;
  681. }
  682. //+---------------------------------------------------------------------------
  683. //
  684. // Function: IsGuestAccessMode
  685. //
  686. // Synopsis: Checks the registry to see if the system is using the
  687. // Guest-only network access mode.
  688. //
  689. // History: 06-Oct-00 JeffreyS Created
  690. // 19-Apr-00 GPease Modified and changed name
  691. //
  692. //----------------------------------------------------------------------------
  693. BOOL
  694. IsForcedGuestModeOn(void)
  695. {
  696. BOOL fIsForcedGuestModeOn = FALSE;
  697. if (IsOS(OS_PERSONAL))
  698. {
  699. // Guest mode is always on for Personal
  700. fIsForcedGuestModeOn = TRUE;
  701. }
  702. else if (IsOS(OS_PROFESSIONAL) && !IsOS(OS_DOMAINMEMBER))
  703. {
  704. LONG ec;
  705. HKEY hkey;
  706. // Professional, not in a domain. Check the ForceGuest value.
  707. ec = RegOpenKeyEx(
  708. HKEY_LOCAL_MACHINE,
  709. TEXT("SYSTEM\\CurrentControlSet\\Control\\LSA"),
  710. 0,
  711. KEY_QUERY_VALUE,
  712. &hkey
  713. );
  714. if (ec == NO_ERROR)
  715. {
  716. DWORD dwValue;
  717. DWORD dwValueSize = sizeof(dwValue);
  718. ec = RegQueryValueEx(hkey,
  719. TEXT("ForceGuest"),
  720. NULL,
  721. NULL,
  722. (LPBYTE)&dwValue,
  723. &dwValueSize);
  724. if (ec == NO_ERROR && 1 == dwValue)
  725. {
  726. fIsForcedGuestModeOn = TRUE;
  727. }
  728. RegCloseKey(hkey);
  729. }
  730. }
  731. return fIsForcedGuestModeOn;
  732. }
  733. //+---------------------------------------------------------------------------
  734. //
  735. // Function: IsSimpleUI
  736. //
  737. // Synopsis: Checks whether to show the simple version of the UI.
  738. //
  739. // History: 06-Oct-00 JeffreyS Created
  740. // 19-Apr-00 GPease Removed CTRL key check
  741. //
  742. //----------------------------------------------------------------------------
  743. BOOL
  744. IsSimpleUI(void)
  745. {
  746. // Show old UI in safe mode and anytime network access involves
  747. // true user identity (server, pro with GuestMode off).
  748. // Show simple UI anytime network access is done using the Guest
  749. // account (personal, pro with GuestMode on) except in safe mode.
  750. return (!IsSafeMode() && IsForcedGuestModeOn());
  751. }
  752. HRESULT BindToObjectEx(IShellFolder *psf, LPCITEMIDLIST pidl, LPBC pbc, REFIID riid, void **ppv)
  753. {
  754. HRESULT hr;
  755. IShellFolder *psfRelease = NULL;
  756. if (!psf)
  757. {
  758. hr = SHGetDesktopFolder(&psf);
  759. if(SUCCEEDED(hr))
  760. {
  761. psfRelease = psf;
  762. }
  763. }
  764. if (psf)
  765. {
  766. if (!pidl || ILIsEmpty(pidl))
  767. {
  768. hr = psf->QueryInterface(riid, ppv);
  769. }
  770. else
  771. {
  772. hr = psf->BindToObject(pidl, pbc, riid, ppv);
  773. }
  774. }
  775. else
  776. {
  777. *ppv = NULL;
  778. hr = E_FAIL;
  779. }
  780. if (psfRelease)
  781. {
  782. psfRelease->Release();
  783. }
  784. if (SUCCEEDED(hr) && (*ppv == NULL))
  785. {
  786. // Some shell extensions (eg WS_FTP) will return success and a null out pointer
  787. hr = E_FAIL;
  788. }
  789. return hr;
  790. }
  791. LPITEMIDLIST ILCloneParent(LPCITEMIDLIST pidl)
  792. {
  793. LPITEMIDLIST pidlParent = ILClone(pidl);
  794. if (pidlParent)
  795. ILRemoveLastID(pidlParent);
  796. return pidlParent;
  797. }
  798. // psfRoot is the base of the bind. If NULL, then we use the shell desktop.
  799. // If you want to bind relative to the explorer root (e.g., CabView, MSN),
  800. // then use SHBindToIDListParent.
  801. HRESULT BindToFolderIDListParent(IShellFolder *psfRoot, LPCITEMIDLIST pidl, REFIID riid, void **ppv, LPCITEMIDLIST *ppidlLast)
  802. {
  803. HRESULT hr;
  804. // Old shell32 code in some cases simply whacked the pidl,
  805. // but this is unsafe. Do what shdocvw does and clone/remove:
  806. //
  807. LPITEMIDLIST pidlParent = ILCloneParent(pidl);
  808. if (pidlParent)
  809. {
  810. hr = BindToObjectEx(psfRoot, pidlParent, NULL, riid, ppv);
  811. ILFree(pidlParent);
  812. }
  813. else
  814. hr = E_OUTOFMEMORY;
  815. if (ppidlLast)
  816. *ppidlLast = ILFindLastID(pidl);
  817. return hr;
  818. }
  819. //+---------------------------------------------------------------------------
  820. //
  821. // Function: IsUIHiddenByPrivacyPolicy
  822. //
  823. // Synopsis: Checks if Security Tab is hidden by privacy policy
  824. // NTRAID#NTBUG9-223899-2001/03/06-hiteshr
  825. // History: 06-March-01 hiteshr Created
  826. //
  827. //----------------------------------------------------------------------------
  828. BOOL
  829. IsUIHiddenByPrivacyPolicy(void)
  830. {
  831. BOOL fIsUIHiddenByPrivacyPolicy = FALSE;
  832. LONG ec;
  833. HKEY hkey = NULL;
  834. ec = RegOpenKeyEx(HKEY_CURRENT_USER,
  835. TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\Explorer"),
  836. 0,
  837. KEY_QUERY_VALUE,
  838. &hkey
  839. );
  840. if (ec == NO_ERROR)
  841. {
  842. DWORD dwValue = 0;
  843. DWORD dwValueSize = sizeof(dwValue);
  844. ec = RegQueryValueEx(hkey,
  845. TEXT("NoSecurityTab"),
  846. NULL,
  847. NULL,
  848. (LPBYTE)&dwValue,
  849. &dwValueSize);
  850. if (ec == NO_ERROR && 1 == dwValue)
  851. {
  852. fIsUIHiddenByPrivacyPolicy = TRUE;
  853. }
  854. RegCloseKey(hkey);
  855. }
  856. return fIsUIHiddenByPrivacyPolicy;
  857. }
  858. //+----------------------------------------------------------------------------
  859. // Function:SetAclOnRemoteNetworkDrive
  860. // Synopsis: If Z: is a mapped drive( mapped to \\machineA\share), when
  861. // we set DACL/SACL on Z:, Security API's cannot determine
  862. // the parent of "share" on machineA and so we lose all the
  863. // inherited aces. All UI can do is to detect such cases and
  864. // show a warning. Thats what this function does.
  865. // Arguments:hItemList List of items on which security is going to be set
  866. // si: SECURITY_INFORMATION
  867. // pSD: Security Descriptor to be set
  868. // hWndPopupOwner: Owner window for message box
  869. // Returns:
  870. //-----------------------------------------------------------------------------
  871. BOOL SetAclOnRemoteNetworkDrive(HDPA hItemList,
  872. SECURITY_INFORMATION si,
  873. PSECURITY_DESCRIPTOR pSD,
  874. HWND hWndPopupOwner)
  875. {
  876. if(!hItemList || !pSD)
  877. {
  878. ASSERT(hItemList);
  879. ASSERT(pSD);
  880. return FALSE;
  881. }
  882. //We care only about DACL and SACL
  883. if(!(si & (DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION)))
  884. {
  885. return TRUE;
  886. }
  887. SECURITY_DESCRIPTOR_CONTROL Control = 0;
  888. DWORD dwRevision = 0;
  889. //Check if DACL or SACL is protected
  890. if(!GetSecurityDescriptorControl(pSD,&Control,&dwRevision))
  891. {
  892. return FALSE;
  893. }
  894. //If inheritance is prevented for this object,there is no loss of inheritance
  895. //so we are fine
  896. if( ((si & DACL_SECURITY_INFORMATION) && (Control & SE_DACL_PROTECTED)) ||
  897. ((si & SACL_SECURITY_INFORMATION) && (Control & SE_SACL_PROTECTED)))
  898. {
  899. return TRUE;
  900. }
  901. LPTSTR pszPath = (LPTSTR)DPA_FastGetPtr(hItemList, 0);
  902. int nMsgId = (si & DACL_SECURITY_INFORMATION) ? IDS_SET_PERM_ON_NETWORK_DRIVE : IDS_SET_SACL_ON_NETWORK_DRIVE;
  903. //Ok, this is a remote network drive, display Warning.
  904. //We display only one warning per list
  905. if (IDNO == MsgPopup(hWndPopupOwner,
  906. MAKEINTRESOURCE(nMsgId),
  907. MAKEINTRESOURCE(IDS_PROPPAGE_TITLE),
  908. MB_YESNO|MB_DEFBUTTON2| MB_ICONWARNING | MB_SETFOREGROUND,
  909. g_hInstance,
  910. pszPath))
  911. {
  912. return FALSE;
  913. }
  914. return TRUE;
  915. }
  916. //+----------------------------------------------------------------------------
  917. // Function:GetSystemPaths
  918. // Synopsis:Extract the value for environment variables SystemDrive
  919. // and SystemRoot
  920. //-----------------------------------------------------------------------------
  921. void
  922. GetSystemPaths(LPWSTR * ppszSystemDrive,
  923. LPWSTR * ppszSystemRoot)
  924. {
  925. static WCHAR szSystemDrive[] = L"%SystemDrive%";
  926. static WCHAR szSystemRoot[] = L"%SystemRoot%";
  927. do
  928. {
  929. //Get SystemDrive
  930. DWORD dwLen = ExpandEnvironmentStrings(szSystemDrive,
  931. NULL,
  932. 0);
  933. if(dwLen)
  934. {
  935. //dwLen contains space for NULL char. 1 is added for "\".
  936. //SystemDrive is in format C:, while we want in the format C:"\"
  937. DWORD dwArrayLen = dwLen + 1;
  938. *ppszSystemDrive = (LPWSTR)LocalAlloc(LPTR,dwArrayLen*sizeof(WCHAR));
  939. if(!*ppszSystemDrive)
  940. break;
  941. dwLen = ExpandEnvironmentStrings(szSystemDrive,
  942. *ppszSystemDrive,
  943. dwArrayLen);
  944. if(!dwLen)
  945. {
  946. LocalFree(*ppszSystemDrive);
  947. *ppszSystemDrive = NULL;
  948. }
  949. else
  950. {
  951. HRESULT hr = StringCchCat(*ppszSystemDrive,
  952. dwArrayLen,
  953. L"\\");
  954. if(FAILED(hr))
  955. {
  956. ASSERT(SUCCEEDED(hr));
  957. LocalFree(*ppszSystemDrive);
  958. *ppszSystemDrive = NULL;
  959. }
  960. }
  961. }
  962. //Get SystemRoot
  963. dwLen = ExpandEnvironmentStrings(szSystemRoot,
  964. NULL,
  965. 0);
  966. if(dwLen)
  967. {
  968. *ppszSystemRoot = (LPWSTR)LocalAlloc(LPTR,dwLen*sizeof(WCHAR));
  969. if(!*ppszSystemRoot)
  970. break;
  971. dwLen = ExpandEnvironmentStrings(szSystemRoot,
  972. *ppszSystemRoot,
  973. dwLen);
  974. if(!dwLen)
  975. {
  976. ASSERT(dwLen);
  977. LocalFree(*ppszSystemRoot);
  978. *ppszSystemRoot = NULL;
  979. }
  980. }
  981. }while(0);
  982. }
  983. //+----------------------------------------------------------------------------
  984. // Function:SetAclOnSystemPaths
  985. // Synopsis:changing acl of SystemDrive or on or under SystemRoot results in
  986. // problem. This function detects if user is changing acl on these
  987. // system folder and shows appropriate warning.
  988. // Returns: TRUE if its fine to set ACL , FALSE if not.
  989. //-----------------------------------------------------------------------------
  990. BOOL SetAclOnSystemPaths(HDPA hItemList,
  991. LPCWSTR pszSystemDrive,
  992. LPCWSTR pszSystemRoot,
  993. SECURITY_INFORMATION si,
  994. HWND hWndPopupOwner)
  995. {
  996. if(!hItemList)
  997. {
  998. ASSERT(hItemList);
  999. return FALSE;
  1000. }
  1001. //We care only about DACL
  1002. if(!(si & DACL_SECURITY_INFORMATION))
  1003. {
  1004. return TRUE;
  1005. }
  1006. DWORD dwLenSystemRoot = 0;
  1007. if(pszSystemRoot)
  1008. {
  1009. dwLenSystemRoot = (DWORD)wcslen(pszSystemRoot);
  1010. }
  1011. //Now Check each item in hItemList
  1012. for (int i = 0; i < DPA_GetPtrCount(hItemList); i++)
  1013. {
  1014. LPTSTR pszPath = (LPTSTR)DPA_FastGetPtr(hItemList, i);
  1015. if(!pszPath)
  1016. continue;
  1017. //Check for system drive
  1018. if(pszSystemDrive &&
  1019. CSTR_EQUAL == CompareString(LOCALE_USER_DEFAULT,
  1020. 0,
  1021. pszSystemDrive,
  1022. -1,
  1023. pszPath,
  1024. -1))
  1025. {
  1026. if (IDNO == MsgPopup(hWndPopupOwner,
  1027. MAKEINTRESOURCE(IDS_ACL_ON_SYSTEMROOT),
  1028. MAKEINTRESOURCE(IDS_PROPPAGE_TITLE),
  1029. MB_YESNO|MB_DEFBUTTON2| MB_ICONWARNING | MB_SETFOREGROUND,
  1030. g_hInstance))
  1031. {
  1032. return FALSE;
  1033. }
  1034. break;
  1035. }
  1036. //Check if its under systemroot
  1037. DWORD dwlenPath = wcslen(pszPath);
  1038. if(dwLenSystemRoot && (dwlenPath >= dwLenSystemRoot) &&
  1039. (CSTR_EQUAL == CompareString(LOCALE_USER_DEFAULT,
  1040. NORM_IGNORECASE,
  1041. pszSystemRoot,
  1042. dwLenSystemRoot,
  1043. pszPath,
  1044. dwLenSystemRoot)))
  1045. {
  1046. if (IDNO == MsgPopup(hWndPopupOwner,
  1047. MAKEINTRESOURCE(IDS_ACL_ON_UNDER_SYSTEM_DRIVE),
  1048. MAKEINTRESOURCE(IDS_PROPPAGE_TITLE),
  1049. MB_YESNO|MB_DEFBUTTON2| MB_ICONWARNING | MB_SETFOREGROUND,
  1050. g_hInstance))
  1051. {
  1052. return FALSE;
  1053. }
  1054. break;
  1055. }
  1056. }
  1057. return TRUE;
  1058. }