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.

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