Source code of Windows XP (NT5)
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.

1753 lines
43 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. setup.c
  5. Abstract:
  6. Implements "Majority Node Set" setup and configuration in cluster
  7. Author:
  8. Ahmed Mohamed (ahmedm) 1-Feb-2000
  9. Revision History:
  10. --*/
  11. #define UNICODE 1
  12. #include <nt.h>
  13. #include <ntrtl.h>
  14. #include <nturtl.h>
  15. #include <windows.h>
  16. #include <winsock2.h>
  17. #include <string.h>
  18. #include <ctype.h>
  19. #include <stdlib.h>
  20. #include <tchar.h>
  21. #include <clusapi.h>
  22. #include <resapi.h>
  23. #include <aclapi.h>
  24. #include <accctrl.h>
  25. #include <lm.h>
  26. #include <lmshare.h>
  27. #include <sddl.h>
  28. // These may be included in any order:
  29. #include <ntddnfs.h> // DD_NFS_DEVICE_NAME, EA_NAME_ equates, etc.
  30. #include <ntioapi.h> // NtFsControlFile().
  31. #include <ntrtl.h> // Rtl APIs.
  32. //#include <prefix.h> // PREFIX_ equates.
  33. #include <tstr.h> // STRCAT(), STRCPY(), STRLEN().
  34. #include <lmuse.h> // USE_IPC...
  35. #include <align.h> // ALIGN_xxx
  36. #include "fsutil.h"
  37. #include <Iphlpapi.h>
  38. #include <clusudef.h>
  39. #include <clusrtl.h>
  40. #define MAX_NAME_SIZE 256
  41. #define PROTECTED_DACL_SECURITY_INFORMATION (0x80000000L)
  42. #define SETUP_DIRECTORY_PREFIX L"\\cluster\\" MAJORITY_NODE_SET_DIRECTORY_PREFIX
  43. extern void WINAPI debug_log(char *, ...);
  44. #define SetupLog(x) debug_log x
  45. #define SetupLogError(x) debug_log x
  46. DWORD
  47. FindTransport(LPWSTR TransportId, LPWSTR *Transport);
  48. // node section
  49. #define MAX_CLUSTER_SIZE 16
  50. #define MAX_NAME_SIZE 256
  51. typedef struct _VCD_NODE_ {
  52. struct _VCD_NODE_ *next;
  53. DWORD id;
  54. LPWSTR name;
  55. }VCD_NODE;
  56. typedef struct {
  57. ULONG lid;
  58. DWORD Nic;
  59. DWORD ArbTime;
  60. LPWSTR Transport;
  61. DWORD ClusterSize;
  62. VCD_NODE *ClusterList;
  63. }VCD_INFO, *PVCD_INFO;
  64. DWORD
  65. FindTransport(LPWSTR TransportId, LPWSTR *Transport)
  66. {
  67. LPSERVER_TRANSPORT_INFO_0 pBuf = NULL;
  68. LPSERVER_TRANSPORT_INFO_0 pTmpBuf;
  69. DWORD dwLevel = 0;
  70. DWORD dwPrefMaxLen = 256;//-1
  71. DWORD dwEntriesRead = 0;
  72. DWORD dwTotalEntries = 0;
  73. DWORD dwResumeHandle = 0;
  74. NET_API_STATUS nStatus;
  75. DWORD i;
  76. *Transport = NULL;
  77. //
  78. // Call the NetServerTransportEnum function; specify level 0.
  79. //
  80. do // begin do
  81. {
  82. nStatus = NetServerTransportEnum(NULL,
  83. dwLevel,
  84. (LPBYTE *) &pBuf,
  85. dwPrefMaxLen,
  86. &dwEntriesRead,
  87. &dwTotalEntries,
  88. &dwResumeHandle);
  89. //
  90. // If the call succeeds,
  91. //
  92. if ((nStatus != NERR_Success) && (nStatus != ERROR_MORE_DATA)) {
  93. break;
  94. }
  95. if ((pTmpBuf = pBuf) == NULL) {
  96. nStatus = ERROR_NOT_FOUND;
  97. break;
  98. }
  99. //
  100. // Loop through the entries;
  101. //
  102. for (i = 0; i < dwEntriesRead; i++) {
  103. SetupLog(("\tTransport: %S address %S\n",
  104. pTmpBuf->svti0_transportname,
  105. pTmpBuf->svti0_networkaddress));
  106. if (wcsstr(pTmpBuf->svti0_transportname, TransportId)) {
  107. // found it, we are done
  108. LPWSTR p;
  109. DWORD sz;
  110. sz = wcslen(pTmpBuf->svti0_transportname) + 1;
  111. p = (LPWSTR) LocalAlloc(LMEM_FIXED, sz * sizeof(WCHAR));
  112. if (p != NULL) {
  113. wcscpy(p, pTmpBuf->svti0_transportname);
  114. *Transport = p;
  115. nStatus = ERROR_SUCCESS;
  116. break;
  117. }
  118. }
  119. pTmpBuf++;
  120. }
  121. //
  122. // Free the allocated buffer.
  123. //
  124. if (pBuf != NULL) {
  125. NetApiBufferFree(pBuf);
  126. pBuf = NULL;
  127. }
  128. } while (nStatus == ERROR_MORE_DATA);
  129. // Check again for an allocated buffer.
  130. //
  131. if (pBuf != NULL)
  132. NetApiBufferFree(pBuf);
  133. return nStatus;
  134. }
  135. DWORD
  136. NetInterfaceProp( IN HNETINTERFACE hNet,IN LPCWSTR name, WCHAR *buf)
  137. {
  138. DWORD dwError = ERROR_SUCCESS; // for return values
  139. DWORD cbAllocated = 1024; // allocated size of output buffer
  140. DWORD cbReturned = 0; // adjusted size of output buffer
  141. WCHAR *value;
  142. //
  143. // Allocate output buffer
  144. //
  145. PVOID pPropList = LocalAlloc( LPTR, cbAllocated );
  146. if ( pPropList == NULL )
  147. {
  148. dwError = GetLastError();
  149. goto EndFunction;
  150. }
  151. //
  152. // Verify valid handle
  153. //
  154. if ( hNet == NULL )
  155. {
  156. dwError = ERROR_BAD_ARGUMENTS;
  157. goto EndFunction;
  158. }
  159. //
  160. // Retrieve common group properties.
  161. // cbReturned will be set to the size of the property list.
  162. //
  163. dwError = ClusterNetInterfaceControl(hNet,
  164. NULL,
  165. CLUSCTL_NETINTERFACE_GET_RO_COMMON_PROPERTIES,
  166. NULL,
  167. 0,
  168. pPropList,
  169. cbAllocated,
  170. &cbReturned );
  171. //
  172. // If the output buffer was not big enough, reallocate it
  173. // according to cbReturned.
  174. //
  175. if ( dwError == ERROR_MORE_DATA )
  176. {
  177. cbAllocated = cbReturned;
  178. LocalFree( pPropList );
  179. pPropList = LocalAlloc( LPTR, cbAllocated );
  180. if ( pPropList == NULL )
  181. {
  182. dwError = GetLastError();
  183. goto EndFunction;
  184. }
  185. dwError = ClusterNetInterfaceControl(hNet,
  186. NULL,
  187. CLUSCTL_NETINTERFACE_GET_RO_COMMON_PROPERTIES,
  188. NULL,
  189. 0,
  190. pPropList,
  191. cbAllocated,
  192. &cbReturned );
  193. }
  194. if ( dwError != ERROR_SUCCESS ) goto EndFunction;
  195. dwError = ResUtilFindSzProperty( pPropList,
  196. cbReturned,
  197. name,
  198. &value);
  199. if (dwError == ERROR_SUCCESS) {
  200. wcscpy(buf, value);
  201. }
  202. EndFunction:
  203. if (pPropList)
  204. LocalFree( pPropList );
  205. return dwError;
  206. } //
  207. int
  208. strcmpwcs(char *s, WCHAR *p)
  209. {
  210. char c;
  211. for (wctomb(&c,*p); (c == *s) && *s != '\0'; s++) {
  212. p++;
  213. wctomb(&c,*p);
  214. }
  215. if (*s == '\0' && c == *s)
  216. return 0;
  217. return 1;
  218. }
  219. DWORD
  220. NetworkIsPrivate(HCLUSTER chdl, LPWSTR netname)
  221. {
  222. HCLUSENUM ehdl;
  223. DWORD err, index;
  224. // Open enum handle
  225. ehdl = ClusterOpenEnum(chdl, CLUSTER_ENUM_INTERNAL_NETWORK);
  226. if (!ehdl) {
  227. err = GetLastError();
  228. return err;
  229. }
  230. for (index = 0; TRUE; index++) {
  231. DWORD type;
  232. DWORD sz;
  233. WCHAR name[MAX_NAME_SIZE];
  234. sz = sizeof(name) / sizeof(WCHAR);
  235. err = ClusterEnum(ehdl, index, &type, name, &sz);
  236. if (err == ERROR_NO_MORE_ITEMS)
  237. break;
  238. if (err != ERROR_SUCCESS) {
  239. break;
  240. }
  241. ASSERT(type == CLUSTER_ENUM_INTERNAL_NETWORK);
  242. if (wcscmp(name, netname) == 0) {
  243. break;
  244. }
  245. err = ERROR_NOT_FOUND;
  246. // always return first one only, since I changed from a mask to a single number
  247. break;
  248. }
  249. ClusterCloseEnum(ehdl);
  250. return err;
  251. }
  252. DWORD
  253. NodeNetworkAdapterMask(HCLUSTER chdl, HNODE nhdl, ULONG *nic, LPWSTR *transport)
  254. {
  255. HNODEENUM nehdl = NULL;
  256. int index, done;
  257. DWORD err, type;
  258. DWORD sz = MAX_NAME_SIZE;
  259. WCHAR buf[MAX_NAME_SIZE];
  260. LPWSTR id = (LPWSTR) buf;
  261. *nic = 0;
  262. *transport = NULL;
  263. // Open node enum handle
  264. nehdl = ClusterNodeOpenEnum(nhdl, CLUSTER_NODE_ENUM_NETINTERFACES);
  265. if (!nehdl) {
  266. err = GetLastError();
  267. return err;
  268. }
  269. // Get node properties
  270. done = 0;
  271. for (index = 0; !done; index++) {
  272. HNETINTERFACE nethdl;
  273. sz = MAX_NAME_SIZE;
  274. err = ClusterNodeEnum(nehdl, index, &type, id, &sz);
  275. if (err == ERROR_NO_MORE_ITEMS)
  276. break;
  277. if (err != ERROR_SUCCESS) {
  278. break;
  279. }
  280. nethdl = OpenClusterNetInterface(chdl, id);
  281. if (!nethdl) {
  282. continue;
  283. }
  284. err = NetInterfaceProp(nethdl, L"Network", id);
  285. if (err != ERROR_SUCCESS) {
  286. continue;
  287. }
  288. // check if this network can be used by cluster service
  289. err = NetworkIsPrivate(chdl, id);
  290. if (err != ERROR_SUCCESS) {
  291. continue;
  292. }
  293. err = NetInterfaceProp(nethdl, L"AdapterId", id);
  294. if (err == ERROR_SUCCESS) {
  295. // find nic
  296. PIP_INTERFACE_INFO ilist;
  297. LONG num;
  298. sz = 0;
  299. GetInterfaceInfo(NULL, &sz);
  300. ilist = (PIP_INTERFACE_INFO) malloc(sz);
  301. if (ilist != NULL) {
  302. err = GetInterfaceInfo(ilist, &sz);
  303. if (err == NO_ERROR) {
  304. for (num = 0; num < ilist->NumAdapters; num++) {
  305. if (wcsstr(ilist->Adapter[num].Name, id)) {
  306. *nic = (ULONG) (ilist->Adapter[num].Index % ilist->NumAdapters);
  307. SetupLog(("Adapter %d '%S'\n", *nic, id));
  308. break;
  309. }
  310. }
  311. } else {
  312. SetupLog(("GetInterfaceInfo failed %d\n", err));
  313. }
  314. free(ilist);
  315. }
  316. // find transport name
  317. err = FindTransport(id, transport);
  318. if (err == ERROR_SUCCESS) {
  319. SetupLog(("NetBT: %S\n", *transport));
  320. }
  321. }
  322. CloseClusterNetInterface(nethdl);
  323. }
  324. if (*transport == NULL) {
  325. SetupLog(("No transport is found\n"));
  326. }
  327. if (nehdl)
  328. ClusterNodeCloseEnum(nehdl);
  329. return err;
  330. }
  331. DWORD
  332. NodeGetId(HNODE nhdl, ULONG *nid)
  333. {
  334. DWORD sz = MAX_NAME_SIZE;
  335. WCHAR buf[MAX_NAME_SIZE], *stopstring;
  336. LPWSTR id = (LPWSTR) buf;
  337. DWORD err;
  338. err = GetClusterNodeId(nhdl, id, &sz);
  339. if (err == ERROR_SUCCESS) {
  340. *nid = wcstol(id, &stopstring,10);
  341. }
  342. return err;
  343. }
  344. void
  345. NodeAddNode(PVCD_INFO info, WCHAR *name, DWORD id)
  346. {
  347. WCHAR *p;
  348. VCD_NODE *n, **last;
  349. n = (VCD_NODE *) LocalAlloc(LMEM_FIXED, ((wcslen(name)+1) * sizeof(WCHAR)) + sizeof(*n));
  350. if (n == NULL) {
  351. return;
  352. }
  353. p = (WCHAR *) (n+1);
  354. wcscpy(p, name);
  355. n->name = p;
  356. n->id = id;
  357. // insert into list in proper order, ascending
  358. last = &info->ClusterList;
  359. while (*last && (*last)->id < id) {
  360. last = &(*last)->next;
  361. }
  362. n->next = *last;
  363. *last = n;
  364. info->ClusterSize++;
  365. }
  366. NodeInit(PVCD_INFO info, HCLUSTER chdl)
  367. {
  368. HCLUSENUM ehdl;
  369. DWORD err, index;
  370. // Open enum handle
  371. ehdl = ClusterOpenEnum(chdl, CLUSTER_ENUM_NODE);
  372. if (!ehdl) {
  373. err = GetLastError();
  374. SetupLogError(("Unable to open enum_node %d\n", err));
  375. return err;
  376. }
  377. for (index = 0; TRUE; index++) {
  378. DWORD type;
  379. DWORD sz, id;
  380. WCHAR name[128];
  381. HNODE nhdl = NULL;
  382. sz = sizeof(name) / sizeof(WCHAR);
  383. err = ClusterEnum(ehdl, index, &type, name, &sz);
  384. if (err == ERROR_NO_MORE_ITEMS) {
  385. err = ERROR_SUCCESS;
  386. break;
  387. }
  388. if (err != ERROR_SUCCESS) {
  389. SetupLogError(("Unable to enum %d node %d\n", index, err));
  390. break;
  391. }
  392. ASSERT(type == CLUSTER_ENUM_NODE);
  393. nhdl = OpenClusterNode(chdl, name);
  394. if (!nhdl) {
  395. err = GetLastError();
  396. SetupLogError(("Unable to open node %S err %d\n", name, err));
  397. continue;
  398. }
  399. err = NodeGetId(nhdl, &id);
  400. if (err == ERROR_SUCCESS) {
  401. NodeAddNode(info, name, id);
  402. if (id == info->lid) {
  403. NodeNetworkAdapterMask(chdl, nhdl, &info->Nic, &info->Transport);
  404. }
  405. } else {
  406. SetupLogError(("Unable to get node id %S %d\n", name, err));
  407. }
  408. CloseClusterNode(nhdl);
  409. }
  410. if (ehdl)
  411. ClusterCloseEnum(ehdl);
  412. return err;
  413. }
  414. // In order to deal with auto-setup:
  415. // we need to create a directory mscs.<resource name>.
  416. // we then create a share with guid:.....\mscs.<resource name>.
  417. // set security on both directory and share for cluster service account only
  418. DWORD
  419. SetupShare(LPWSTR name, LPWSTR *lpath)
  420. {
  421. DWORD err, len;
  422. WCHAR path[MAX_PATH];
  423. if (name == NULL || wcslen(name) > MAX_PATH)
  424. return ERROR_INVALID_PARAMETER;
  425. *lpath = NULL;
  426. len = GetWindowsDirectoryW(path, MAX_PATH);
  427. if (len > 0) {
  428. SECURITY_ATTRIBUTES sec;
  429. HANDLE hDir;
  430. path[len] = L'\0';
  431. lstrcatW(path, SETUP_DIRECTORY_PREFIX);
  432. lstrcatW(path, name);
  433. memset((PVOID) &sec, 0, sizeof(sec));
  434. if (!CreateDirectoryW(path, NULL)) {
  435. err = GetLastError();
  436. if (err != ERROR_ALREADY_EXISTS) {
  437. SetupLogError(("Failed to create %s %d\n", path, err));
  438. return 0;
  439. }
  440. }
  441. hDir = CreateFileW(path,
  442. GENERIC_READ|WRITE_DAC|READ_CONTROL,
  443. FILE_SHARE_READ | FILE_SHARE_WRITE,
  444. NULL,
  445. OPEN_ALWAYS,
  446. FILE_FLAG_BACKUP_SEMANTICS,
  447. NULL);
  448. if (hDir != INVALID_HANDLE_VALUE) {
  449. // set the security attributes for the file.
  450. err = ClRtlSetObjSecurityInfo(hDir, SE_FILE_OBJECT,
  451. GENERIC_ALL, GENERIC_ALL, 0);
  452. // close directory handle
  453. CloseHandle(hDir);
  454. // duplicate path
  455. *lpath = (LPWSTR) LocalAlloc(LMEM_FIXED, (wcslen(path)+1)*sizeof(WCHAR));
  456. if (*lpath != NULL) {
  457. wcscpy(*lpath, path);
  458. SetupLog(("Local path %S\n", lpath));
  459. } else {
  460. err = GetLastError();
  461. }
  462. } else {
  463. err = GetLastError();
  464. SetupLogError(("Unable to open directory %d\n", err));
  465. }
  466. if (err == ERROR_SUCCESS) {
  467. // check if share doesn't exist already
  468. SHARE_INFO_502 shareInfo;
  469. PBYTE BufPtr;
  470. err = NetShareGetInfo(NULL, name, 502, (PBYTE *)&BufPtr);
  471. if (err == ERROR_SUCCESS) {
  472. NetApiBufferFree(BufPtr);
  473. }
  474. if (err != ERROR_SUCCESS) {
  475. PSECURITY_DESCRIPTOR secDesc;
  476. err = ConvertStringSecurityDescriptorToSecurityDescriptor(
  477. L"D:P(A;;GA;;;BA)(A;;GA;;;CO)",
  478. SDDL_REVISION_1,
  479. &secDesc,
  480. NULL);
  481. if (!err) {
  482. secDesc = NULL;
  483. err = GetLastError();
  484. SetupLogError(("Unable to get security desc %d\n", err));
  485. }
  486. // create a net share now
  487. ZeroMemory( &shareInfo, sizeof( shareInfo ) );
  488. shareInfo.shi502_netname = name;
  489. shareInfo.shi502_type = STYPE_DISKTREE;
  490. shareInfo.shi502_remark = L"Cluster Quorum Share";
  491. shareInfo.shi502_max_uses = -1;
  492. shareInfo.shi502_path = path;
  493. shareInfo.shi502_passwd = NULL;
  494. shareInfo.shi502_permissions = ACCESS_ALL;
  495. // set security stuff
  496. shareInfo.shi502_security_descriptor = secDesc;
  497. err = NetShareAdd( NULL, 502, (PBYTE)&shareInfo, NULL );
  498. if (secDesc)
  499. LocalFree(secDesc);
  500. } else {
  501. SetupLogError(("Netshare '%S' already exists\n", name));
  502. }
  503. }
  504. } else {
  505. err = GetLastError();
  506. }
  507. return err;
  508. }
  509. DWORD
  510. GetDwParameter(
  511. IN HKEY ClusterKey,
  512. IN LPCWSTR ValueName
  513. )
  514. {
  515. DWORD Value = 0;
  516. DWORD ValueLength;
  517. DWORD ValueType;
  518. DWORD Status;
  519. ValueLength = sizeof(Value);
  520. Status = ClusterRegQueryValue(ClusterKey,
  521. ValueName,
  522. &ValueType,
  523. (LPBYTE) &Value,
  524. &ValueLength);
  525. if ( (Status != ERROR_SUCCESS) &&
  526. (Status != ERROR_MORE_DATA) ) {
  527. SetLastError(Status);
  528. }
  529. return(Value);
  530. }
  531. LPWSTR
  532. GetParameter(
  533. IN HKEY ClusterKey,
  534. IN LPCWSTR ValueName
  535. )
  536. /*++
  537. Routine Description:
  538. Queries a REG_SZ parameter out of the registry and allocates the
  539. necessary storage for it.
  540. Arguments:
  541. ClusterKey - Supplies the cluster key where the parameter is stored
  542. ValueName - Supplies the name of the value.
  543. Return Value:
  544. A pointer to a buffer containing the parameter if successful.
  545. NULL if unsuccessful.
  546. --*/
  547. {
  548. LPWSTR Value;
  549. DWORD ValueLength;
  550. DWORD ValueType;
  551. DWORD Status;
  552. ValueLength = 0;
  553. Status = ClusterRegQueryValue(ClusterKey,
  554. ValueName,
  555. &ValueType,
  556. NULL,
  557. &ValueLength);
  558. if ( (Status != ERROR_SUCCESS) &&
  559. (Status != ERROR_MORE_DATA) ) {
  560. SetLastError(Status);
  561. return(NULL);
  562. }
  563. if ( ValueType == REG_SZ ) {
  564. ValueLength += sizeof(UNICODE_NULL);
  565. }
  566. Value = LocalAlloc(LMEM_FIXED, ValueLength);
  567. if (Value == NULL) {
  568. return(NULL);
  569. }
  570. Status = ClusterRegQueryValue(ClusterKey,
  571. ValueName,
  572. &ValueType,
  573. (LPBYTE)Value,
  574. &ValueLength);
  575. if (Status != ERROR_SUCCESS) {
  576. LocalFree(Value);
  577. SetLastError(Status);
  578. Value = NULL;
  579. }
  580. return(Value);
  581. } // GetParameter
  582. DWORD
  583. SetupNetworkInterfaceFromRegistry(HKEY hkey, LPWSTR netname, VCD_INFO *info)
  584. {
  585. HKEY rkey;
  586. DWORD err, index;
  587. // get network key
  588. err = ClusterRegOpenKey(hkey, CLUSREG_KEYNAME_NETINTERFACES, KEY_READ, &rkey);
  589. if (err != ERROR_SUCCESS) {
  590. return err;
  591. }
  592. for (index = 0; TRUE; index++) {
  593. WCHAR name[256];
  594. DWORD sz;
  595. FILETIME mtime;
  596. HKEY tkey;
  597. LPWSTR tname;
  598. DWORD id;
  599. sz = sizeof(name) / sizeof(WCHAR);
  600. err = ClusterRegEnumKey(rkey, index, name, &sz, &mtime);
  601. if (err != ERROR_SUCCESS)
  602. break;
  603. err = ClusterRegOpenKey(rkey, name, KEY_READ, &tkey);
  604. if (err != ERROR_SUCCESS)
  605. break;
  606. // get the name and compare it against our name
  607. tname = GetParameter(tkey, CLUSREG_NAME_NETIFACE_NODE);
  608. if (tname == NULL)
  609. continue;
  610. id = wcstol(tname, NULL, 10);
  611. LocalFree(tname);
  612. if (id != info->lid)
  613. continue;
  614. tname = GetParameter(tkey, CLUSREG_NAME_NETIFACE_NETWORK);
  615. SetupLog(("Found adapter %d %S\n", id, tname));
  616. if (wcscmp(tname, netname) == 0) {
  617. // get adapter id
  618. LocalFree(tname);
  619. tname = GetParameter(tkey, CLUSREG_NAME_NETIFACE_ADAPTER_ID);
  620. if (tname) {
  621. SetupLog(("Find transport %S\n", tname));
  622. err = FindTransport(tname, &info->Transport);
  623. }
  624. LocalFree(tname);
  625. ClusterRegCloseKey(tkey);
  626. break;
  627. }
  628. LocalFree(tname);
  629. ClusterRegCloseKey(tkey);
  630. }
  631. ClusterRegCloseKey(rkey);
  632. if (err == ERROR_NO_MORE_ITEMS)
  633. err = ERROR_SUCCESS;
  634. return err;
  635. }
  636. DWORD
  637. SetupNetworkFromRegistry(HKEY hkey, VCD_INFO *info)
  638. {
  639. HKEY rkey;
  640. DWORD err, index;
  641. // get network key
  642. err = ClusterRegOpenKey(hkey, CLUSREG_KEYNAME_NETWORKS, KEY_READ, &rkey);
  643. if (err != ERROR_SUCCESS) {
  644. return err;
  645. }
  646. for (index = 0; TRUE; index++) {
  647. WCHAR name[256];
  648. DWORD sz;
  649. FILETIME mtime;
  650. HKEY tkey;
  651. DWORD id;
  652. sz = sizeof(name) / sizeof(WCHAR);
  653. err = ClusterRegEnumKey(rkey, index, name, &sz, &mtime);
  654. if (err != ERROR_SUCCESS)
  655. break;
  656. err = ClusterRegOpenKey(rkey, name, KEY_READ, &tkey);
  657. if (err != ERROR_SUCCESS)
  658. break;
  659. // get the name and compare it against our name
  660. id = GetDwParameter(tkey, CLUSREG_NAME_NET_PRIORITY);
  661. SetupLog(("Found network %d %S\n", id, name));
  662. if (id == 1) {
  663. // find which nic belongs to this transport
  664. err = SetupNetworkInterfaceFromRegistry(hkey, name, info);
  665. ClusterRegCloseKey(tkey);
  666. break;
  667. }
  668. ClusterRegCloseKey(tkey);
  669. }
  670. ClusterRegCloseKey(rkey);
  671. if (err == ERROR_NO_MORE_ITEMS)
  672. err = ERROR_SUCCESS;
  673. return err;
  674. }
  675. DWORD
  676. SetupNodesFromRegistry(HCLUSTER hCluster, VCD_INFO *info)
  677. {
  678. HKEY hkey, rkey;
  679. DWORD err, index;
  680. WCHAR localname[MAX_COMPUTERNAME_LENGTH + 1];
  681. memset(info, 0, sizeof(*info));
  682. index = sizeof(localname) / sizeof(WCHAR);
  683. if (GetComputerName(localname, &index) == FALSE) {
  684. return GetLastError();
  685. }
  686. hkey = GetClusterKey(hCluster, KEY_READ);
  687. if (hkey == NULL)
  688. return GetLastError();
  689. // get resource key
  690. err = ClusterRegOpenKey(hkey, CLUSREG_KEYNAME_NODES, KEY_READ, &rkey);
  691. if (err != ERROR_SUCCESS) {
  692. ClusterRegCloseKey(hkey);
  693. return err;
  694. }
  695. for (index = 0; TRUE; index++) {
  696. WCHAR name[256];
  697. DWORD sz;
  698. FILETIME mtime;
  699. HKEY tkey;
  700. LPWSTR tname;
  701. DWORD id;
  702. sz = sizeof(name) / sizeof(WCHAR);
  703. err = ClusterRegEnumKey(rkey, index, name, &sz, &mtime);
  704. if (err != ERROR_SUCCESS)
  705. break;
  706. err = ClusterRegOpenKey(rkey, name, KEY_READ, &tkey);
  707. if (err != ERROR_SUCCESS)
  708. break;
  709. // get the name and compare it against our name
  710. tname = GetParameter(tkey, CLUSREG_NAME_NODE_NAME);
  711. if (tname == NULL) {
  712. err = GetLastError();
  713. ClusterRegCloseKey(tkey);
  714. break;
  715. }
  716. ClusterRegCloseKey(tkey);
  717. id = wcstol(name, NULL, 10);
  718. SetupLog(("Found node %d %S\n", id, tname));
  719. NodeAddNode(info, tname, id);
  720. if (wcscmp(localname, tname) == 0) {
  721. // set our local id
  722. info->lid = id;
  723. // find which nic and transport to use
  724. SetupNetworkFromRegistry(hkey, info);
  725. }
  726. LocalFree(tname);
  727. }
  728. ClusterRegCloseKey(rkey);
  729. ClusterRegCloseKey(hkey);
  730. if (err == ERROR_NO_MORE_ITEMS)
  731. err = ERROR_SUCCESS;
  732. return err;
  733. }
  734. DWORD
  735. SetupNodes(HCLUSTER chdl, VCD_INFO *info)
  736. {
  737. DWORD err;
  738. memset(info, 0, sizeof(*info));
  739. err = NodeGetId(NULL, &info->lid);
  740. if (err != ERROR_SUCCESS) {
  741. SetupLogError(("Unable to get local id %d\n", err));
  742. return err;
  743. }
  744. SetupLog(("Local node id %d\n", info->lid));
  745. err = NodeInit(info, chdl);
  746. return err;
  747. }
  748. DWORD
  749. GetIDFromRegistry(IN HCLUSTER hCluster, IN LPWSTR resname, OUT LPWSTR *id)
  750. {
  751. HKEY hkey, rkey;
  752. DWORD err, index;
  753. *id = NULL;
  754. hkey = GetClusterKey(hCluster, KEY_READ);
  755. if (hkey == NULL)
  756. return GetLastError();
  757. // get resource key
  758. err = ClusterRegOpenKey(hkey, CLUSREG_KEYNAME_RESOURCES, KEY_READ, &rkey);
  759. if (err != ERROR_SUCCESS) {
  760. ClusterRegCloseKey(hkey);
  761. return err;
  762. }
  763. for (index = 0; TRUE; index++) {
  764. WCHAR name[256];
  765. DWORD sz;
  766. FILETIME mtime;
  767. HKEY tkey;
  768. LPWSTR tname;
  769. sz = sizeof(name) / sizeof(WCHAR);
  770. err = ClusterRegEnumKey(rkey, index, name, &sz, &mtime);
  771. if (err != ERROR_SUCCESS)
  772. break;
  773. SetupLog(("Found name %S\n", name));
  774. err = ClusterRegOpenKey(rkey, name, KEY_READ, &tkey);
  775. if (err != ERROR_SUCCESS)
  776. break;
  777. // get the name and compare it against our name
  778. tname = GetParameter(tkey, CLUSREG_NAME_RES_NAME);
  779. if (tname == NULL) {
  780. err = GetLastError();
  781. ClusterRegCloseKey(tkey);
  782. break;
  783. }
  784. ClusterRegCloseKey(tkey);
  785. if (wcscmp(tname, resname) == 0) {
  786. SetupLog(("Guid %S\n", name));
  787. // found it
  788. *id = LocalAlloc(LMEM_FIXED, 80 * sizeof(WCHAR));
  789. if (*id != NULL) {
  790. wcscpy(*id, name);
  791. } else {
  792. err = GetLastError();
  793. }
  794. LocalFree(tname);
  795. break;
  796. }
  797. LocalFree(tname);
  798. }
  799. ClusterRegCloseKey(rkey);
  800. ClusterRegCloseKey(hkey);
  801. return err;
  802. }
  803. DWORD
  804. GetIDFromName(
  805. IN HRESOURCE hResource,
  806. OUT LPWSTR *ppszID
  807. )
  808. {
  809. DWORD dwError = ERROR_INVALID_PARAMETER;
  810. if (hResource && ppszID)
  811. {
  812. //
  813. // Should be able to hold the string representation of a guid
  814. //
  815. DWORD cbBuf = 80;
  816. //
  817. // Set the out parameter to something known
  818. //
  819. *ppszID = NULL;
  820. if (*ppszID = (LPWSTR)LocalAlloc(LMEM_FIXED, cbBuf))
  821. {
  822. if ((dwError = ClusterResourceControl(hResource,
  823. NULL,
  824. CLUSCTL_RESOURCE_GET_ID,
  825. NULL,
  826. 0,
  827. *ppszID,
  828. cbBuf,
  829. &cbBuf)) == ERROR_MORE_DATA)
  830. {
  831. LocalFree(*ppszID);
  832. if (*ppszID = (LPWSTR)LocalAlloc(LMEM_FIXED, cbBuf))
  833. {
  834. dwError = ClusterResourceControl(hResource,
  835. NULL,
  836. CLUSCTL_RESOURCE_GET_ID,
  837. NULL,
  838. 0,
  839. *ppszID,
  840. cbBuf,
  841. &cbBuf);
  842. }
  843. else
  844. {
  845. dwError = GetLastError();
  846. }
  847. }
  848. //
  849. // Free the memory if getting the ID failed
  850. //
  851. if (dwError != ERROR_SUCCESS && *ppszID)
  852. {
  853. LocalFree(*ppszID);
  854. *ppszID = NULL;
  855. }
  856. }
  857. else
  858. {
  859. dwError = GetLastError();
  860. }
  861. }
  862. return dwError;
  863. }
  864. DWORD
  865. SetupIoctlQuorumResource(LPWSTR ResType, DWORD ControlCode)
  866. {
  867. HRESOURCE hres;
  868. HCLUSTER chdl;
  869. HKEY hkey, rkey, qkey;
  870. DWORD err, index;
  871. LPWSTR tname, resname;
  872. chdl = OpenCluster(NULL);
  873. if (chdl == NULL) {
  874. SetupLogError(("Unable to open cluster\n"));
  875. return GetLastError();
  876. }
  877. hkey = GetClusterKey(chdl, KEY_READ);
  878. if (hkey == NULL) {
  879. CloseCluster(chdl);
  880. return GetLastError();
  881. }
  882. // get quorum key
  883. err = ClusterRegOpenKey(hkey, CLUSREG_KEYNAME_QUORUM, KEY_READ, &rkey);
  884. if (err != ERROR_SUCCESS) {
  885. ClusterRegCloseKey(hkey);
  886. CloseCluster(chdl);
  887. return err;
  888. }
  889. // read guid of current quorum
  890. tname = GetParameter(rkey, CLUSREG_NAME_QUORUM_RESOURCE);
  891. if (tname == NULL) {
  892. err = GetLastError();
  893. ClusterRegCloseKey(rkey);
  894. ClusterRegCloseKey(hkey);
  895. CloseCluster(chdl);
  896. return err;
  897. }
  898. // close rkey
  899. ClusterRegCloseKey(rkey);
  900. // get resources key
  901. err = ClusterRegOpenKey(hkey, CLUSREG_KEYNAME_RESOURCES, KEY_READ, &rkey);
  902. if (err != ERROR_SUCCESS) {
  903. ClusterRegCloseKey(hkey);
  904. CloseCluster(chdl);
  905. LocalFree(tname);
  906. return err;
  907. }
  908. // get resource key
  909. err = ClusterRegOpenKey(rkey, tname, KEY_READ, &qkey);
  910. LocalFree(tname);
  911. if (err != ERROR_SUCCESS) {
  912. ClusterRegCloseKey(rkey);
  913. ClusterRegCloseKey(hkey);
  914. CloseCluster(chdl);
  915. return err;
  916. }
  917. // read resource type of current quorum
  918. tname = GetParameter(qkey, CLUSREG_NAME_RES_TYPE);
  919. if (tname == NULL)
  920. err = GetLastError();
  921. if (tname != NULL && wcscmp(tname, ResType) == 0) {
  922. resname = GetParameter(qkey, CLUSREG_NAME_RES_NAME);
  923. if (resname != NULL) {
  924. err = ERROR_SUCCESS;
  925. // open this resource and drop ioctl now
  926. hres = OpenClusterResource(chdl, resname);
  927. if (hres != NULL) {
  928. err = ClusterResourceControl(hres, NULL, ControlCode, NULL, 0, NULL,
  929. 0, NULL);
  930. CloseClusterResource(hres);
  931. }
  932. LocalFree(resname);
  933. } else {
  934. err = GetLastError();
  935. }
  936. }
  937. if (tname)
  938. LocalFree(tname);
  939. ClusterRegCloseKey(qkey);
  940. ClusterRegCloseKey(rkey);
  941. ClusterRegCloseKey(hkey);
  942. CloseCluster(chdl);
  943. return err;
  944. }
  945. // This not is not efficient, some day someone can do this better. For now, I just
  946. // need this stuff.
  947. DWORD
  948. SetupIsQuorum(LPWSTR ResourceName)
  949. {
  950. HRESOURCE hres;
  951. HCLUSTER chdl;
  952. DWORD status;
  953. LPWSTR Guid = NULL;
  954. chdl = OpenCluster(NULL);
  955. if (chdl == NULL) {
  956. SetupLogError(("Unable to open cluster\n"));
  957. return GetLastError();
  958. }
  959. hres = OpenClusterResource(chdl, ResourceName);
  960. if (hres == NULL) {
  961. status = GetLastError();
  962. SetupLogError(("Unable to open resource\n"));
  963. CloseCluster(chdl);
  964. return status;
  965. }
  966. status = GetIDFromName(hres, &Guid);
  967. if (status != ERROR_SUCCESS) {
  968. SetupLogError(("Unable to get guid %d\n", status));
  969. // we need to walk the registry and find the guid ourself.
  970. status = GetIDFromRegistry(chdl, ResourceName, &Guid);
  971. }
  972. CloseClusterResource(hres);
  973. if (status == ERROR_SUCCESS) {
  974. HKEY hkey, rkey;
  975. LPWSTR tname;
  976. // ok we have guid of resource, we now get the current quorum resource
  977. // and compare guids
  978. hkey = GetClusterKey(chdl, KEY_READ);
  979. if (hkey == NULL) {
  980. status = GetLastError();
  981. goto exit;
  982. }
  983. // get quorum key
  984. status = ClusterRegOpenKey(hkey, CLUSREG_KEYNAME_QUORUM, KEY_READ, &rkey);
  985. if (status != ERROR_SUCCESS) {
  986. ClusterRegCloseKey(hkey);
  987. goto exit;
  988. }
  989. // read guid of current quorum
  990. tname = GetParameter(rkey, CLUSREG_NAME_QUORUM_RESOURCE);
  991. if (tname != NULL) {
  992. if (wcscmp(tname, Guid) == 0)
  993. status = ERROR_SUCCESS;
  994. else
  995. status = ERROR_CLUSTER_INSTANCE_ID_MISMATCH;
  996. LocalFree(tname);
  997. }
  998. ClusterRegCloseKey(rkey);
  999. ClusterRegCloseKey(hkey);
  1000. }
  1001. exit:
  1002. if (Guid)
  1003. LocalFree(Guid);
  1004. CloseCluster(chdl);
  1005. return status;
  1006. }
  1007. DWORD
  1008. SetupStart(LPWSTR ResourceName, LPWSTR *SrvPath,
  1009. LPWSTR *DiskList, DWORD *DiskListSize,
  1010. DWORD *NicId, LPWSTR *Transport, DWORD *ArbTime)
  1011. {
  1012. HRESOURCE hres;
  1013. HCLUSTER chdl;
  1014. DWORD status;
  1015. LPWSTR Guid = NULL, nbtName = NULL, lpath = NULL;
  1016. VCD_INFO Info;
  1017. chdl = OpenCluster(NULL);
  1018. if (chdl == NULL) {
  1019. SetupLogError(("Unable to open cluster\n"));
  1020. return GetLastError();
  1021. }
  1022. // read quorum arb. timeout
  1023. if (ArbTime != NULL) {
  1024. HKEY hkey;
  1025. *ArbTime = 60; // default is 60 seconds
  1026. hkey = GetClusterKey(chdl, KEY_READ);
  1027. if (hkey != NULL) {
  1028. DWORD tmp;
  1029. tmp = GetDwParameter(hkey, CLUSREG_NAME_QUORUM_ARBITRATION_TIMEOUT);
  1030. if (tmp > 0)
  1031. *ArbTime = tmp;
  1032. ClusterRegCloseKey(hkey);
  1033. }
  1034. // convert to msec and normalize
  1035. *ArbTime = ((*ArbTime) * 7 * 1000) / 8; // use 7/8 of the actual timeout
  1036. SetupLog(("Max. arbitration time %d msec\n", *ArbTime));
  1037. }
  1038. hres = OpenClusterResource(chdl, ResourceName);
  1039. if (hres == NULL) {
  1040. status = GetLastError();
  1041. SetupLogError(("Unable to open resource\n"));
  1042. CloseCluster(chdl);
  1043. return status;
  1044. }
  1045. status = GetIDFromName(hres, &Guid);
  1046. if (status != ERROR_SUCCESS) {
  1047. SetupLogError(("Unable to get guid %d\n", status));
  1048. // we need to walk the registry and find the guid ourself.
  1049. status = GetIDFromRegistry(chdl, ResourceName, &Guid);
  1050. }
  1051. if (status == ERROR_SUCCESS) {
  1052. int sz;
  1053. // we add a $ onto the guid
  1054. wcscat(Guid, L"$");
  1055. sz = wcslen(Guid);
  1056. // netbios name are 16 bytes, 3 back-slashs, 1 null and few extra pads
  1057. sz += 32;
  1058. nbtName = (LPWSTR) LocalAlloc(LMEM_FIXED, sizeof(WCHAR) * sz);
  1059. if (nbtName == NULL) {
  1060. status = ERROR_NOT_ENOUGH_MEMORY;
  1061. goto done;
  1062. }
  1063. nbtName[0] = L'\\';
  1064. nbtName[1] = L'\\';
  1065. // netbios name are 15 bytes + 1 byte for type. So, we use first 15 bytes
  1066. wcsncpy(&nbtName[2], Guid, 15);
  1067. nbtName[17] = L'\0';
  1068. wcscat(nbtName, L"\\");
  1069. wcscat(nbtName, Guid);
  1070. // guid for everything to do with shares and directory name
  1071. status = SetupShare(Guid, &lpath);
  1072. if (status != ERROR_SUCCESS) {
  1073. SetupLogError(("Unable to setup share %d\n", status));
  1074. goto done;
  1075. }
  1076. // get list of nodes.
  1077. // make a path with \\guid\guid
  1078. // make disklist with UNC\nodename\guid, for local node we can use the
  1079. // raw ntfs path directly
  1080. status = SetupNodes(chdl, &Info);
  1081. if (status != ERROR_SUCCESS) {
  1082. status = SetupNodesFromRegistry(chdl, &Info);
  1083. }
  1084. if (status == ERROR_SUCCESS) {
  1085. // build an array of disk shares, \\hostname\guid
  1086. int i;
  1087. VCD_NODE *cur;
  1088. // we start @ slot 1 and not zero, store local path in zero
  1089. DiskList[0] = lpath;
  1090. for (cur = Info.ClusterList; cur != NULL; cur=cur->next){
  1091. // build a unc\hostname\guid path
  1092. sz = wcslen(L"UNC\\");
  1093. sz += wcslen(cur->name);
  1094. sz += wcslen(L"\\");
  1095. sz += wcslen(Guid);
  1096. sz += 1;
  1097. i = cur->id;
  1098. DiskList[i] = (LPWSTR) LocalAlloc(LMEM_FIXED, sz * sizeof(WCHAR));
  1099. if (DiskList[i] == NULL) {
  1100. status = ERROR_NOT_ENOUGH_MEMORY;
  1101. break;
  1102. }
  1103. wcscpy(DiskList[i], L"UNC\\");
  1104. wcscat(DiskList[i], cur->name);
  1105. wcscat(DiskList[i], L"\\");
  1106. wcscat(DiskList[i], Guid);
  1107. }
  1108. if (status == ERROR_SUCCESS) {
  1109. *DiskListSize = Info.ClusterSize;
  1110. *NicId = Info.Nic;
  1111. *Transport = Info.Transport;
  1112. *SrvPath = nbtName;
  1113. }
  1114. while(cur = Info.ClusterList) {
  1115. cur = cur->next;
  1116. LocalFree((PVOID)Info.ClusterList);
  1117. Info.ClusterList = cur;
  1118. }
  1119. Info.ClusterSize = 0;
  1120. } else {
  1121. status = ERROR_NOT_ENOUGH_MEMORY;
  1122. }
  1123. }
  1124. done:
  1125. // free guid buffer
  1126. if (Guid) {
  1127. LocalFree(Guid);
  1128. }
  1129. if (status != ERROR_SUCCESS) {
  1130. if (nbtName) {
  1131. LocalFree(nbtName);
  1132. }
  1133. if (lpath) {
  1134. LocalFree(lpath);
  1135. }
  1136. }
  1137. CloseClusterResource(hres);
  1138. CloseCluster(chdl);
  1139. return status;
  1140. }
  1141. DWORD
  1142. SetupDelete(IN LPWSTR Path)
  1143. {
  1144. LPWSTR name;
  1145. DWORD err = ERROR_INVALID_PARAMETER;
  1146. HANDLE vfd;
  1147. WCHAR tmp[MAX_PATH];
  1148. if (Path == NULL)
  1149. return err;
  1150. // We need to do couple of things here. First we remove the
  1151. // network share and then delete the tree structure.
  1152. SetupLog(("Delete path %S\n", Path));
  1153. name = wcsstr(Path, SETUP_DIRECTORY_PREFIX);
  1154. if (name != NULL) {
  1155. name += wcslen(SETUP_DIRECTORY_PREFIX);
  1156. err = NetShareDel(NULL, name, 0);
  1157. SetupLog(("Delete share %S err %d\n", name, err));
  1158. }
  1159. // Open path with delete on close and delete whole tree
  1160. ASSERT(wcslen(Path) < sizeof(tmp));
  1161. swprintf(tmp,L"\\??\\%s", Path);
  1162. err = xFsOpen(&vfd, NULL, tmp, wcslen(tmp),
  1163. FILE_GENERIC_READ | FILE_GENERIC_WRITE,
  1164. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  1165. FILE_DIRECTORY_FILE);
  1166. if (err == STATUS_SUCCESS) {
  1167. err = xFsDeleteTree(vfd);
  1168. xFsClose(vfd);
  1169. SetupLog(("Delete tree %S err %x\n", tmp, err));
  1170. // now delete root
  1171. if (err == STATUS_SUCCESS)
  1172. err = xFsDelete(NULL, tmp, wcslen(tmp));
  1173. SetupLog(("Delete tree %S err %x\n", tmp, err));
  1174. }
  1175. return RtlNtStatusToDosError(err);
  1176. }
  1177. DWORD
  1178. SetupTree(
  1179. IN LPTSTR TreeName,
  1180. IN LPTSTR DlBuf,
  1181. IN OUT DWORD *DlBufSz,
  1182. IN LPTSTR TransportName OPTIONAL,
  1183. IN LPVOID SecurityDescriptor OPTIONAL
  1184. )
  1185. {
  1186. DWORD ApiStatus;
  1187. DWORD ConnectionType = USE_WILDCARD; // use_chardev
  1188. IO_STATUS_BLOCK iosb;
  1189. NTSTATUS ntstatus; // Status from NT operations.
  1190. OBJECT_ATTRIBUTES objattrTreeConn; // Attrs for tree conn.
  1191. LPTSTR pszTreeConn = NULL; // See strTreeConn below.
  1192. UNICODE_STRING ucTreeConn;
  1193. HANDLE TreeConnHandle = NULL;
  1194. PFILE_FULL_EA_INFORMATION EaBuffer = NULL;
  1195. PFILE_FULL_EA_INFORMATION Ea;
  1196. USHORT TransportNameSize = 0;
  1197. ULONG EaBufferSize = 0;
  1198. PWSTR UnicodeTransportName = NULL;
  1199. UCHAR EaNameDomainNameSize = (UCHAR) (ROUND_UP_COUNT(
  1200. strlen(EA_NAME_DOMAIN) + sizeof(CHAR),
  1201. ALIGN_WCHAR
  1202. ) - sizeof(CHAR));
  1203. UCHAR EaNamePasswordSize = (UCHAR) (ROUND_UP_COUNT(
  1204. strlen(EA_NAME_PASSWORD) + sizeof(CHAR),
  1205. ALIGN_WCHAR
  1206. ) - sizeof(CHAR));
  1207. UCHAR EaNameTransportNameSize = (UCHAR) (ROUND_UP_COUNT(
  1208. strlen(EA_NAME_TRANSPORT) + sizeof(CHAR),
  1209. ALIGN_WCHAR
  1210. ) - sizeof(CHAR));
  1211. UCHAR EaNameTypeSize = (UCHAR) (ROUND_UP_COUNT(
  1212. strlen(EA_NAME_TYPE) + sizeof(CHAR),
  1213. ALIGN_DWORD
  1214. ) - sizeof(CHAR));
  1215. UCHAR EaNameUserNameSize = (UCHAR) (ROUND_UP_COUNT(
  1216. strlen(EA_NAME_USERNAME) + sizeof(CHAR),
  1217. ALIGN_WCHAR
  1218. ) - sizeof(CHAR));
  1219. USHORT TypeSize = sizeof(ULONG);
  1220. if ((TreeName == NULL) || (TreeName[0] == 0)) {
  1221. ApiStatus = ERROR_INVALID_PARAMETER;
  1222. goto Cleanup;
  1223. }
  1224. //
  1225. // Build NT-style name for what we're connecting to. Note that there is
  1226. // NOT a pair of backslashes anywhere in this name.
  1227. //
  1228. {
  1229. DWORD NameSize =
  1230. // /Device/LanManRedirector / server/share \0
  1231. ( ( STRLEN((LPTSTR)DD_NFS_DEVICE_NAME_U) + 1 + STRLEN(TreeName) + 1 ) )
  1232. * sizeof(TCHAR);
  1233. pszTreeConn = (LPTSTR)LocalAlloc(LMEM_FIXED, NameSize );
  1234. }
  1235. if (pszTreeConn == NULL) {
  1236. ApiStatus = ERROR_NOT_ENOUGH_MEMORY;
  1237. goto Cleanup;
  1238. }
  1239. //
  1240. // Build the tree connect name.
  1241. //
  1242. (void) STRCPY(pszTreeConn, (LPTSTR) DD_NFS_DEVICE_NAME_U);
  1243. //
  1244. // NOTE: We add 1, (not sizeof(TCHAR)) because pointer arithmetic is done
  1245. // in terms of multiples of sizeof(*pointer), not bytes
  1246. //
  1247. {
  1248. LPWSTR p = wcschr(TreeName+2, L'\\');
  1249. if (p != NULL) {
  1250. *p = L'\0';
  1251. }
  1252. (void) STRCAT(pszTreeConn, TreeName+1); // \server\share
  1253. if (p != NULL) {
  1254. *p = L'\\';
  1255. (void) STRCAT(pszTreeConn, L"\\IPC$"); // \server\IPC$
  1256. }
  1257. }
  1258. RtlInitUnicodeString(&ucTreeConn, pszTreeConn);
  1259. //
  1260. // Calculate the number of bytes needed for the EA buffer.
  1261. // This may have the transport name. For regular sessions, the user
  1262. // name, password, and domain name are implicit. For null sessions, we
  1263. // must give 0-len user name, 0-len password, and 0-len domain name.
  1264. //
  1265. if (ARGUMENT_PRESENT(TransportName)) {
  1266. UnicodeTransportName = TransportName;
  1267. TransportNameSize = (USHORT) (wcslen(UnicodeTransportName) * sizeof(WCHAR));
  1268. EaBufferSize += ROUND_UP_COUNT(
  1269. FIELD_OFFSET(FILE_FULL_EA_INFORMATION, EaName[0]) +
  1270. EaNameTransportNameSize + sizeof(CHAR) +
  1271. TransportNameSize,
  1272. ALIGN_DWORD
  1273. );
  1274. }
  1275. EaBufferSize += ((ULONG)FIELD_OFFSET( FILE_FULL_EA_INFORMATION, EaName[0]))+
  1276. EaNameTypeSize + sizeof(CHAR) +
  1277. TypeSize;
  1278. //
  1279. // Allocate the EA buffer
  1280. //
  1281. if ((EaBuffer = LocalAlloc(LMEM_FIXED, EaBufferSize )) == NULL) {
  1282. ApiStatus = ERROR_NOT_ENOUGH_MEMORY;
  1283. goto Cleanup;
  1284. }
  1285. //
  1286. // Fill-in the EA buffer.
  1287. //
  1288. RtlZeroMemory(EaBuffer, EaBufferSize);
  1289. Ea = EaBuffer;
  1290. if (ARGUMENT_PRESENT(TransportName)) {
  1291. //
  1292. // Copy the EA name into EA buffer. EA name length does not
  1293. // include the zero terminator.
  1294. //
  1295. strcpy(Ea->EaName, EA_NAME_TRANSPORT);
  1296. Ea->EaNameLength = EaNameTransportNameSize;
  1297. //
  1298. // Copy the EA value into EA buffer. EA value length does not
  1299. // include the zero terminator.
  1300. //
  1301. (VOID) wcscpy(
  1302. (LPWSTR) &(Ea->EaName[EaNameTransportNameSize + sizeof(CHAR)]),
  1303. UnicodeTransportName
  1304. );
  1305. Ea->EaValueLength = TransportNameSize;
  1306. Ea->NextEntryOffset = ROUND_UP_COUNT(
  1307. FIELD_OFFSET( FILE_FULL_EA_INFORMATION, EaName[0]) +
  1308. EaNameTransportNameSize + sizeof(CHAR) +
  1309. TransportNameSize,
  1310. ALIGN_DWORD
  1311. );
  1312. Ea->Flags = 0;
  1313. (ULONG_PTR) Ea += Ea->NextEntryOffset;
  1314. }
  1315. //
  1316. // Copy the EA for the connection type name into EA buffer. EA name length
  1317. // does not include the zero terminator.
  1318. //
  1319. strcpy(Ea->EaName, EA_NAME_TYPE);
  1320. Ea->EaNameLength = EaNameTypeSize;
  1321. *((PULONG) &(Ea->EaName[EaNameTypeSize + sizeof(CHAR)])) = ConnectionType;
  1322. Ea->EaValueLength = TypeSize;
  1323. Ea->NextEntryOffset = 0;
  1324. Ea->Flags = 0;
  1325. // Set object attributes for the tree conn.
  1326. InitializeObjectAttributes(
  1327. & objattrTreeConn, // obj attr to init
  1328. (LPVOID) & ucTreeConn, // string to use
  1329. OBJ_CASE_INSENSITIVE, // Attributes
  1330. NULL, // Root directory
  1331. SecurityDescriptor); // Security Descriptor
  1332. //
  1333. // Open a tree connection to the remote server.
  1334. //
  1335. ntstatus = NtCreateFile(
  1336. &TreeConnHandle, // ptr to handle
  1337. SYNCHRONIZE // desired...
  1338. | GENERIC_READ | GENERIC_WRITE, // ...access
  1339. & objattrTreeConn, // name & attributes
  1340. & iosb, // I/O status block.
  1341. NULL, // alloc size.
  1342. FILE_ATTRIBUTE_NORMAL, // (ignored)
  1343. FILE_SHARE_READ | FILE_SHARE_WRITE, // ...access
  1344. FILE_OPEN_IF, // create disposition
  1345. FILE_CREATE_TREE_CONNECTION // create...
  1346. | FILE_SYNCHRONOUS_IO_NONALERT, // ...options
  1347. EaBuffer, // EA buffer
  1348. EaBufferSize ); // Ea buffer size
  1349. ApiStatus = RtlNtStatusToDosError(ntstatus);
  1350. if (ntstatus == STATUS_SUCCESS) {
  1351. // create drive letter
  1352. NETRESOURCE nr;
  1353. DWORD result;
  1354. nr.dwType = RESOURCETYPE_DISK;
  1355. nr.lpLocalName = NULL; //drive;
  1356. nr.lpRemoteName = TreeName;
  1357. nr.lpProvider = NULL;
  1358. if (DlBufSz != NULL)
  1359. ApiStatus = WNetUseConnection(NULL, &nr, NULL, NULL, CONNECT_REDIRECT,
  1360. DlBuf, DlBufSz, &result);
  1361. else
  1362. ApiStatus = WNetUseConnection(NULL, &nr, NULL, NULL, 0, NULL, 0, NULL);
  1363. }
  1364. Cleanup:
  1365. // Clean up.
  1366. if ( TreeConnHandle != NULL ) {
  1367. ntstatus = NtClose(TreeConnHandle);
  1368. }
  1369. if ( pszTreeConn != NULL ) {
  1370. LocalFree(pszTreeConn);
  1371. }
  1372. if (EaBuffer != NULL) {
  1373. LocalFree(EaBuffer);
  1374. }
  1375. return ApiStatus;
  1376. }
  1377. #ifdef STANDALONE
  1378. __cdecl
  1379. main()
  1380. {
  1381. DWORD err;
  1382. WCHAR Drive[10];
  1383. DWORD DriveSz;
  1384. LPWSTR DiskList[FsMaxNodes];
  1385. DWORD DiskListSz, Nic;
  1386. LPWSTR Path, Share, Transport;
  1387. LPWSTR ResName = L"Node Quorum";
  1388. err = SetupStart(ResName, &Path, DiskList, &DiskListSz, &Nic, &Transport);
  1389. if (err == ERROR_SUCCESS) {
  1390. DWORD i;
  1391. Share = wcschr(Path+2, L'\\');
  1392. wprintf(L"Path is '%s'\n", Path);
  1393. wprintf(L"Share is '%s'\n", Share);
  1394. wprintf(L"Nic %d\n", Nic);
  1395. wprintf(L"Transport '%s'\n", Transport);
  1396. for (i = 1; i < FsMaxNodes; i++) {
  1397. if (DiskList[i])
  1398. wprintf(L"Disk%d: %s\n", i, DiskList[i]);
  1399. }
  1400. DriveSz = sizeof(Drive);
  1401. err = SetupTree(Path, Drive, &DriveSz, Transport, NULL);
  1402. if (err == ERROR_SUCCESS)
  1403. wprintf(L"Drive %s\n", Drive);
  1404. }
  1405. printf("Err is %d\n",err);
  1406. return err;
  1407. }
  1408. #endif