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.

747 lines
22 KiB

  1. //--------------------------------------------------------------------------
  2. //
  3. // Copyright (C) 1999, Microsoft Corporation
  4. //
  5. // File: misc.cxx
  6. //
  7. //--------------------------------------------------------------------------
  8. #define UNICODE 1
  9. extern "C" {
  10. #include <nt.h>
  11. #include <ntrtl.h>
  12. #include <nturtl.h>
  13. #include <windows.h>
  14. #include <stdio.h>
  15. #include <stdlib.h>
  16. #include <stddef.h>
  17. #include <shellapi.h>
  18. #include <dfsprefix.h>
  19. #include <winldap.h>
  20. #include <dsgetdc.h>
  21. #include <lm.h>
  22. #include <lmdfs.h>
  23. #include <dfsfsctl.h>
  24. }
  25. #include <DfsServerLibrary.hxx>
  26. #include <DfsRegStrings.hxx>
  27. #include "struct.hxx"
  28. #include "flush.hxx"
  29. #include "misc.hxx"
  30. #include "messages.h"
  31. #include <strsafe.h>
  32. #include <dfsutil.hxx>
  33. #include <DfsBlobInfo.hxx>
  34. #include "dfspathname.hxx"
  35. DFSSTATUS
  36. GetWin2kStandaloneMetadata (
  37. IN HKEY DfsMetadataKey,
  38. IN LPWSTR RelativeName,
  39. IN LPWSTR RegistryValueNameString,
  40. OUT PDFS_NAME_INFORMATION pNameInfo);
  41. DFSSTATUS
  42. SetWin2kStandaloneMetadata (
  43. IN HKEY DfsMetadataKey,
  44. IN LPWSTR RelativeName,
  45. IN LPWSTR RegistryValueNameString,
  46. IN PVOID pData,
  47. IN ULONG DataSize );
  48. DFSSTATUS
  49. GetDfsRegistryKey( IN LPWSTR MachineName,
  50. IN LPWSTR LocationString,
  51. BOOLEAN WritePermission,
  52. OUT BOOLEAN *pMachineContacted,
  53. OUT PHKEY pDfsRegKey );
  54. DFSSTATUS
  55. GetRootPhysicalShare(
  56. HKEY RootKey,
  57. PUNICODE_STRING pRootPhysicalShare );
  58. DFSSTATUS
  59. GetRootPhysicalShare(
  60. HKEY RootKey,
  61. PUNICODE_STRING pRootPhysicalShare )
  62. {
  63. DFSSTATUS Status;
  64. ULONG DataSize, DataType;
  65. LPWSTR DfsRootShare = NULL;
  66. Status = RegQueryInfoKey( RootKey, // Key
  67. NULL, // Class string
  68. NULL, // Size of class string
  69. NULL, // Reserved
  70. NULL, // # of subkeys
  71. NULL, // max size of subkey name
  72. NULL, // max size of class name
  73. NULL, // # of values
  74. NULL, // max size of value name
  75. &DataSize, // max size of value data,
  76. NULL, // security descriptor
  77. NULL ); // Last write time
  78. if (Status == ERROR_SUCCESS)
  79. {
  80. DfsRootShare = (LPWSTR) new BYTE [DataSize];
  81. if ( DfsRootShare == NULL )
  82. {
  83. Status = ERROR_NOT_ENOUGH_MEMORY;
  84. } else
  85. {
  86. Status = RegQueryValueEx( RootKey,
  87. DFS_REG_ROOT_SHARE_VALUE,
  88. NULL,
  89. &DataType,
  90. (LPBYTE)DfsRootShare,
  91. &DataSize );
  92. }
  93. }
  94. if (Status == ERROR_SUCCESS)
  95. {
  96. if (DataType == REG_SZ)
  97. {
  98. RtlInitUnicodeString( pRootPhysicalShare, DfsRootShare );
  99. }
  100. else {
  101. Status = STATUS_INVALID_PARAMETER;
  102. }
  103. }
  104. if (Status != ERROR_SUCCESS)
  105. {
  106. if (DfsRootShare != NULL)
  107. {
  108. delete [] DfsRootShare;
  109. }
  110. }
  111. return Status;
  112. }
  113. DFSSTATUS
  114. GetDfsRegistryKey( IN LPWSTR MachineName,
  115. IN LPWSTR LocationString,
  116. BOOLEAN WritePermission,
  117. OUT BOOLEAN *pMachineContacted,
  118. OUT PHKEY pDfsRegKey )
  119. {
  120. DFSSTATUS Status;
  121. HKEY RootKey;
  122. BOOLEAN Contacted = FALSE;
  123. LPWSTR UseMachineName = NULL;
  124. REGSAM DesiredAccess = KEY_READ;
  125. if (WritePermission == TRUE)
  126. {
  127. DesiredAccess |= KEY_WRITE;
  128. }
  129. if (IsEmptyString(MachineName) == FALSE) {
  130. UseMachineName = MachineName;
  131. }
  132. Status = RegConnectRegistry( UseMachineName,
  133. HKEY_LOCAL_MACHINE,
  134. &RootKey );
  135. if ( Status == ERROR_SUCCESS )
  136. {
  137. Contacted = TRUE;
  138. Status = RegOpenKeyEx( RootKey,
  139. LocationString,
  140. 0,
  141. DesiredAccess,
  142. pDfsRegKey );
  143. //
  144. // There appears to be a bug in the registry code. When
  145. // we connect to the local machine, the key that is returned
  146. // in the RegConnectRegistry is HKEY_LOCAL_MACHINE. If we
  147. // then attempt to close it here, it affects other threads
  148. // that are using this code: they get STATUS_INVALID_HANDLE
  149. // in some cases. So, dont close the key if it is
  150. // HKEY_LOCAL_MACHINE.
  151. //
  152. if (RootKey != HKEY_LOCAL_MACHINE)
  153. {
  154. RegCloseKey( RootKey );
  155. }
  156. }
  157. if (pMachineContacted != NULL)
  158. {
  159. *pMachineContacted = Contacted;
  160. }
  161. return Status;
  162. }
  163. DFSSTATUS
  164. CreateNameInformationBlob(
  165. IN PDFS_NAME_INFORMATION pDfsNameInfo,
  166. OUT PVOID *ppBlob,
  167. OUT PULONG pDataSize )
  168. {
  169. PVOID pBlob = NULL;
  170. PVOID pUseBlob = NULL;
  171. ULONG BlobSize = 0;
  172. ULONG UseBlobSize = 0;
  173. DFSSTATUS Status = ERROR_SUCCESS;
  174. BlobSize = PackSizeNameInformation( pDfsNameInfo );
  175. pBlob = (PVOID) new BYTE[BlobSize];
  176. if (pBlob == NULL)
  177. {
  178. return ERROR_NOT_ENOUGH_MEMORY;
  179. }
  180. pUseBlob = pBlob;
  181. UseBlobSize = BlobSize;
  182. // Pack the name information into the binary stream allocated.
  183. //
  184. Status = PackSetStandaloneNameInformation( pDfsNameInfo,
  185. &pUseBlob,
  186. &UseBlobSize );
  187. if (Status != ERROR_SUCCESS)
  188. {
  189. delete [] pBlob;
  190. pBlob = NULL;
  191. }
  192. if (Status == ERROR_SUCCESS)
  193. {
  194. *ppBlob = pBlob;
  195. *pDataSize = BlobSize - UseBlobSize;
  196. }
  197. return Status;
  198. }
  199. DFSSTATUS
  200. DfsSetWin2kStdNameInfo(
  201. HKEY DomainRootKey,
  202. LPWSTR LinkName,
  203. PDFS_NAME_INFORMATION pNameInfo)
  204. {
  205. DFSSTATUS Status = ERROR_SUCCESS;
  206. PVOID pBlob = NULL;
  207. ULONG BlobSize = 0;
  208. Status = CreateNameInformationBlob( pNameInfo,
  209. &pBlob,
  210. &BlobSize );
  211. if (Status != ERROR_SUCCESS)
  212. {
  213. DebugInformation((L"Error 0x%x creating registry blob with NameInfo\n", Status));
  214. return Status;
  215. }
  216. if (Status == ERROR_SUCCESS)
  217. {
  218. Status = SetWin2kStandaloneMetadata( DomainRootKey,
  219. LinkName, // Can be NULL for roots
  220. L"ID",
  221. pBlob,
  222. BlobSize );
  223. if (Status == ERROR_SUCCESS)
  224. {
  225. DebugInformation((L"Successfully wrote changes to the Windows2000 standalone root\n"));
  226. }
  227. else
  228. {
  229. DebugInformation((L"Error 0x%x writing changes to the Windows2000 standalone root\n", Status));
  230. }
  231. }
  232. delete [] pBlob;
  233. return Status;
  234. }
  235. #if 0
  236. DFSSTATUS
  237. DfsGetWin2kStdReplicaInfo(
  238. LPWSTR MachineName,
  239. PDFS_REPLICA_LIST_INFORMATION pReplicaInfo)
  240. {
  241. DFSSTATUS Status = ERROR_SUCCESS;
  242. HKEY VolumesKey = NULL;
  243. BOOLEAN MachineContacted = FALSE;
  244. PVOID pBlob = NULL;
  245. ULONG BlobSize = 0;
  246. Status = GetDfsRegistryKey (MachineName,
  247. DFS_REG_OLD_HOST_LOCATION,
  248. FALSE,
  249. &MachineContacted,
  250. &VolumesKey );
  251. if (Status != ERROR_SUCCESS)
  252. {
  253. return Status;
  254. }
  255. Status = GetWin2kStandaloneMetadata( VolumesKey,
  256. DFS_REG_OLD_STANDALONE_CHILD,
  257. L"Svc",
  258. &pBlob,
  259. &BlobSize );
  260. RegCloseKey( VolumesKey );
  261. RtlZeroMemory (pReplicaInfo, sizeof(DFS_REPLICA_LIST_INFORMATION));
  262. Status = PackGetULong( &pReplicaInfo->ReplicaCount,
  263. &pBlob,
  264. &BlobSize );
  265. if (Status == ERROR_SUCCESS)
  266. {
  267. pReplicaInfo->pReplicas = new DFS_REPLICA_INFORMATION[ pReplicaInfo->ReplicaCount];
  268. if ( pReplicaInfo->pReplicas != NULL )
  269. {
  270. Status = PackGetReplicaInformation( pReplicaInfo,
  271. &pBlob,
  272. &BlobSize );
  273. }
  274. else
  275. {
  276. Status = ERROR_NOT_ENOUGH_MEMORY;
  277. }
  278. }
  279. if (Status == ERROR_SUCCESS)
  280. {
  281. DumpReplicaInformation( pReplicaInfo );
  282. delete [] pReplicaInfo->pReplicas;
  283. }
  284. return Status;
  285. }
  286. #endif
  287. DFSSTATUS
  288. DfsGetWin2kStdLinkNameInfo(
  289. HKEY DomainRootKey,
  290. PUNICODE_STRING pLinkName,
  291. PBOOLEAN pLinkFound,
  292. LPWSTR *pChildGuidName,
  293. PDFS_NAME_INFORMATION pNameInfo)
  294. {
  295. DFSSTATUS Status = ERROR_SUCCESS;
  296. ULONG ChildNum = 0;
  297. DWORD CchMaxName = 0;
  298. DWORD CchChildName = 0;
  299. LPWSTR ChildName = NULL;
  300. *pLinkFound = FALSE;
  301. //
  302. // First find the length of the longest subkey
  303. // and allocate a buffer big enough for it.
  304. //
  305. Status = RegQueryInfoKey( DomainRootKey, // Key
  306. NULL, // Class string
  307. NULL, // Size of class string
  308. NULL, // Reserved
  309. NULL, // # of subkeys
  310. &CchMaxName, // max size of subkey name in TCHARs
  311. NULL, // max size of class name
  312. NULL, // # of values
  313. NULL, // max size of value name
  314. NULL, // max size of value data,
  315. NULL, // security descriptor
  316. NULL ); // Last write time
  317. if (Status == ERROR_SUCCESS)
  318. {
  319. // Space for the NULL terminator.
  320. CchMaxName++;
  321. ChildName = (LPWSTR) new WCHAR [CchMaxName];
  322. if (ChildName == NULL)
  323. {
  324. Status = ERROR_NOT_ENOUGH_MEMORY;
  325. }
  326. }
  327. do
  328. {
  329. //
  330. // For each child, get the child name.
  331. //
  332. CchChildName = CchMaxName;
  333. Status = RegEnumKeyEx( DomainRootKey,
  334. ChildNum,
  335. ChildName,
  336. &CchChildName,
  337. NULL,
  338. NULL,
  339. NULL,
  340. NULL );
  341. ChildNum++;
  342. //
  343. // Read in the child link and see if that's the link we need.
  344. //
  345. if ( Status == ERROR_SUCCESS )
  346. {
  347. UNICODE_STRING PrefixName;
  348. Status = GetWin2kStandaloneMetadata( DomainRootKey,
  349. ChildName,
  350. L"ID",
  351. pNameInfo);
  352. if (Status == ERROR_SUCCESS)
  353. {
  354. DumpNameInformation( pNameInfo );
  355. // Skip the leading '\'s if any.
  356. PrefixName = pNameInfo->Prefix;
  357. while (PrefixName.Buffer[0] == UNICODE_PATH_SEP)
  358. {
  359. PrefixName.Buffer++;
  360. PrefixName.Length -= sizeof(WCHAR);
  361. }
  362. if (RtlCompareUnicodeString( &PrefixName, pLinkName, TRUE ) == 0)
  363. {
  364. *pLinkFound = TRUE;
  365. *pChildGuidName = ChildName;
  366. Status = ERROR_SUCCESS;
  367. break;
  368. }
  369. else
  370. {
  371. // Go on to the next link
  372. DebugInformation((L"Found W2k Link %wZ, doesn't match %wZ\n", &PrefixName, pLinkName));
  373. }
  374. }
  375. }
  376. } while ( Status == ERROR_SUCCESS );
  377. if (*pLinkFound == FALSE)
  378. {
  379. delete [] ChildName;
  380. Status = ERROR_PATH_NOT_FOUND;
  381. }
  382. return Status;
  383. }
  384. DFSSTATUS
  385. DfsGetWin2kStdNameInfo(
  386. HKEY VolumesKey,
  387. HKEY DomainRootKey,
  388. PUNICODE_STRING pShareName,
  389. PDFS_NAME_INFORMATION pNameInfo)
  390. {
  391. DFSSTATUS Status = ERROR_SUCCESS;
  392. UNICODE_STRING W2kRootName;
  393. // Look at DfsHost\volumes-> RootShare key to get at the root name.
  394. Status = GetRootPhysicalShare( VolumesKey, &W2kRootName );
  395. if (Status == ERROR_SUCCESS)
  396. {
  397. // We need to find a matching share. Win2k has only one root.
  398. if (RtlCompareUnicodeString( &W2kRootName, pShareName, TRUE ) == 0)
  399. {
  400. Status = GetWin2kStandaloneMetadata( DomainRootKey,
  401. NULL,
  402. L"ID",
  403. pNameInfo);
  404. }
  405. else
  406. {
  407. Status = ERROR_PATH_NOT_FOUND;
  408. DebugInformation((L"Found W2k root %wZ, doesn't match %wZ\n", &W2kRootName, pShareName));
  409. }
  410. delete [] W2kRootName.Buffer;
  411. }
  412. return Status;
  413. }
  414. DFSSTATUS
  415. GetWin2kStandaloneMetadata (
  416. IN HKEY DfsMetadataKey,
  417. IN LPWSTR RelativeName,
  418. IN LPWSTR RegistryValueNameString,
  419. OUT PDFS_NAME_INFORMATION pNameInfo)
  420. {
  421. HKEY NewKey = NULL;
  422. HKEY UseKey = NULL;
  423. PVOID pDataBuffer = NULL;
  424. ULONG DataSize, DataType;
  425. DFSSTATUS Status = ERROR_SUCCESS;
  426. //
  427. // If a relative name was passed in, we need to open a subkey under the
  428. // passed in key. Otherwise, we already have a key open to the information
  429. // of interest.
  430. //
  431. if ( RelativeName != NULL )
  432. {
  433. Status = RegOpenKeyEx( DfsMetadataKey,
  434. RelativeName,
  435. 0,
  436. KEY_READ,
  437. &NewKey );
  438. if ( Status == ERROR_SUCCESS )
  439. {
  440. UseKey = NewKey;
  441. }
  442. else
  443. {
  444. //DFS_TRACE_HIGH( REFERRAL_SERVER, "registry store, GetMetadata-RegOpenKeyEx %ws status=%d\n", RelativeName, Status);
  445. }
  446. } else
  447. {
  448. UseKey = DfsMetadataKey;
  449. }
  450. //
  451. // Get the largest size of any value under the key of interest, so we know
  452. // how much we need to allocate in the worst case.
  453. // (If a subkey has 3 values, this returns the maximum memory size required
  454. // to read any one of the values.)
  455. //
  456. if ( Status == ERROR_SUCCESS )
  457. {
  458. Status = RegQueryInfoKey( UseKey, // Key
  459. NULL, // Class string
  460. NULL, // Size of class string
  461. NULL, // Reserved
  462. NULL, // # of subkeys
  463. NULL, // max size of subkey name
  464. NULL, // max size of class name
  465. NULL, // # of values
  466. NULL, // max size of value name
  467. &DataSize, // max size of value data,
  468. NULL, // security descriptor
  469. NULL ); // Last write time
  470. }
  471. //
  472. // We have the required size now: allocate a buffer for that size and
  473. // read the value we are interested in.
  474. //
  475. if ( Status == ERROR_SUCCESS )
  476. {
  477. pDataBuffer = new BYTE [DataSize];
  478. if ( pDataBuffer == NULL )
  479. {
  480. Status = ERROR_NOT_ENOUGH_MEMORY;
  481. }
  482. else
  483. {
  484. Status = RegQueryValueEx( UseKey,
  485. RegistryValueNameString, // eg. "ID"
  486. NULL,
  487. &DataType,
  488. (LPBYTE)pDataBuffer,
  489. &DataSize );
  490. //
  491. // If the format of data is not a certain type (usually binary type for DFS)
  492. // we have bogus data.
  493. //
  494. if ( (Status == ERROR_SUCCESS) && (DataType != DFS_REGISTRY_DATA_TYPE) )
  495. {
  496. Status = ERROR_INVALID_DATA;
  497. }
  498. }
  499. }
  500. //
  501. // If we are successful in reading the value, pass the allcoated buffer and
  502. // size back to caller. Otherwise, free up the allocate buffer and return
  503. // error status to the caller.
  504. //
  505. if ( Status == ERROR_SUCCESS )
  506. {
  507. Status = PackGetStandaloneNameInformation( pNameInfo, &pDataBuffer, &DataSize );
  508. }
  509. if ( pDataBuffer != NULL )
  510. {
  511. delete [] pDataBuffer;
  512. pDataBuffer = NULL;
  513. }
  514. //
  515. // If we did open a new key, it is time to close it now.
  516. //
  517. if ( NewKey != NULL )
  518. RegCloseKey(NewKey);
  519. return Status;
  520. }
  521. DFSSTATUS
  522. SetWin2kStandaloneMetadata (
  523. IN HKEY DomainRootKey,
  524. IN LPWSTR RelativeName,
  525. IN LPWSTR RegistryValueNameString,
  526. IN PVOID pData,
  527. IN ULONG DataSize )
  528. {
  529. HKEY UseKey = DomainRootKey;
  530. DFSSTATUS Status = ERROR_SUCCESS;
  531. //
  532. // If a relative name was passed in, we need to open a subkey under the
  533. // passed in key. Otherwise, we already have a key open to the information
  534. // of interest.
  535. //
  536. if (RelativeName)
  537. {
  538. Status = RegOpenKeyEx( DomainRootKey,
  539. RelativeName,
  540. 0,
  541. KEY_READ | KEY_WRITE,
  542. &UseKey );
  543. }
  544. //
  545. // Store the value against the passed in value string
  546. //
  547. if (Status == ERROR_SUCCESS)
  548. {
  549. Status = RegSetValueEx( UseKey,
  550. RegistryValueNameString,
  551. NULL,
  552. DFS_REGISTRY_DATA_TYPE,
  553. (LPBYTE)pData,
  554. DataSize );
  555. if (UseKey != DomainRootKey)
  556. RegCloseKey(UseKey);
  557. }
  558. return Status;
  559. }
  560. //
  561. // Look at the Win2k standalone location on the remote
  562. // machine to see if it has a matching root. If this is a
  563. // set operation, the Type info will be changed. Else this
  564. // returns existing Type attribute in NameInformation.
  565. //
  566. DFSSTATUS
  567. DfsExtendedWin2kRootAttributes(
  568. DfsPathName *Namespace,
  569. PULONG pAttr,
  570. BOOLEAN Set)
  571. {
  572. DFSSTATUS Status = ERROR_SUCCESS;
  573. DFS_NAME_INFORMATION NameInfo;
  574. BOOLEAN PathFound = FALSE;
  575. LPWSTR ChildGuidName = NULL;
  576. HKEY VolumesKey = NULL;
  577. HKEY DomainRootKey = NULL;
  578. // Open DfsHost\volumes
  579. Status = GetDfsRegistryKey (Namespace->GetServerString(),
  580. DFS_REG_OLD_HOST_LOCATION,
  581. TRUE, // RW
  582. NULL,
  583. &VolumesKey );
  584. if (Status != ERROR_SUCCESS)
  585. {
  586. Status = ERROR_PATH_NOT_FOUND;
  587. return Status;
  588. }
  589. Status = RegOpenKeyEx( VolumesKey,
  590. DFS_REG_OLD_STANDALONE_CHILD, // 'domainroot',
  591. 0,
  592. KEY_READ|KEY_WRITE,
  593. &DomainRootKey );
  594. if (Status != ERROR_SUCCESS)
  595. {
  596. RegCloseKey( VolumesKey );
  597. Status = ERROR_PATH_NOT_FOUND;
  598. return Status;
  599. }
  600. do {
  601. DebugInformation((L"Attempting to get Windows2000 standalone root information for %wZ\n",
  602. Namespace->GetPathCountedString()));
  603. Status = DfsGetWin2kStdNameInfo( VolumesKey,
  604. DomainRootKey,
  605. Namespace->GetShareCountedString(),
  606. &NameInfo );
  607. if (Status != ERROR_SUCCESS)
  608. {
  609. Status = ERROR_PATH_NOT_FOUND;
  610. break;
  611. }
  612. //DumpNameInformation( &NameInfo );
  613. // We've matched the root name so far. See if we need to find the link component.
  614. if (!IsEmptyUnicodeString( Namespace->GetRemainingCountedString() ))
  615. {
  616. Status = DfsGetWin2kStdLinkNameInfo( DomainRootKey,
  617. Namespace->GetFolderCountedString(),
  618. &PathFound,
  619. &ChildGuidName,
  620. &NameInfo );
  621. if (!PathFound)
  622. {
  623. Status = ERROR_PATH_NOT_FOUND;
  624. break;
  625. }
  626. }
  627. if (!Set)
  628. {
  629. *pAttr = NameInfo.Type & PKT_ENTRY_TYPE_EXTENDED_ATTRIBUTES;
  630. }
  631. else
  632. {
  633. NameInfo.Type &= ~PKT_ENTRY_TYPE_EXTENDED_ATTRIBUTES;
  634. NameInfo.Type |= *pAttr;
  635. //DebugInformation((L"New name information type flags will be 0x%x\n", NameInfo.Type));
  636. Status = DfsSetWin2kStdNameInfo( DomainRootKey,
  637. ChildGuidName, // NULL for roots
  638. &NameInfo );
  639. }
  640. } while (FALSE);
  641. RegCloseKey( DomainRootKey );
  642. RegCloseKey( VolumesKey );
  643. return Status;
  644. }