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.

1076 lines
32 KiB

  1. /**
  2. Module Name:
  3. NetUtils.cpp
  4. Abstract:
  5. This is the implementation file for the utility functions for Network APIs.
  6. */
  7. #include "NetUtils.h"
  8. #include <winsock2.h>
  9. #include <stack>
  10. #include <ntdsapi.h>
  11. #include <ldaputils.h>
  12. #include <lmdfs.h>
  13. #include <dsrole.h>
  14. #include <dns.h> //DNS_MAX_NAME_BUFFER_LENGTH
  15. //----------------------------------------------------------------------------------
  16. HRESULT FlatAdd
  17. (
  18. DOMAIN_DESC* i_pDomDesc, // Pointer to the Domain Description Structure returned by IBrowserDomainTree::GetDomains()
  19. OUT NETNAMELIST* o_pDomainList // Pointer to the list of NETNAME is returned here.
  20. )
  21. /*++
  22. Routine Description:
  23. This function flattens the domain tree returned by GetDomains() method
  24. of IBrowserDomainTree into a NETNAME list.
  25. This code produces a preorder traversal method.
  26. Arguments:
  27. i_pDomDesc - Pointer to the Domain Description Structure returned by IBrowserDomainTree::GetDomains()
  28. o_pDomainList - Pointer to the list of NETNAME is returned here.
  29. --*/
  30. {
  31. RETURN_INVALIDARG_IF_NULL(i_pDomDesc);
  32. RETURN_INVALIDARG_IF_NULL(o_pDomainList);
  33. HRESULT hr = S_OK;
  34. stack<DOMAIN_DESC*> Stack;
  35. Stack.push(i_pDomDesc);
  36. while (!Stack.empty())
  37. {
  38. DOMAIN_DESC* pDomDesc = Stack.top();
  39. Stack.pop();
  40. NETNAME* pCurrent = new NETNAME;
  41. BREAK_OUTOFMEMORY_IF_NULL(pCurrent, &hr);
  42. pCurrent->bstrNetName = pDomDesc->pszName;
  43. if (!(pCurrent->bstrNetName))
  44. {
  45. delete pCurrent;
  46. hr = E_OUTOFMEMORY;
  47. break;
  48. }
  49. // Add to the output list.
  50. o_pDomainList->push_back(pCurrent);
  51. if (pDomDesc->pdNextSibling)
  52. Stack.push(pDomDesc->pdNextSibling);
  53. if (pDomDesc->pdChildList)
  54. Stack.push(pDomDesc->pdChildList);
  55. }
  56. if (FAILED(hr))
  57. FreeNetNameList(o_pDomainList);
  58. return hr;
  59. }
  60. HRESULT Get50Domains
  61. (
  62. OUT NETNAMELIST* o_pDomains // List of NETNAME structures.
  63. )
  64. /*++
  65. Routine Description:
  66. Returns a list of all NT 5.0 domains in a list of NETNAME structures
  67. Arguments:
  68. o_pDomains - Pointer to list of NETNAME structures is returned.
  69. --*/
  70. // This method uses the DsDomainTreeBrowser COM Object to get the list
  71. // of domain names from the DS. The Domain tree returned is then flatened out
  72. // by using preorder traversal algorithm.
  73. {
  74. RETURN_INVALIDARG_IF_NULL(o_pDomains);
  75. FreeNetNameList(o_pDomains);
  76. CComPtr<IDsBrowseDomainTree> pDsDomTree;
  77. HRESULT hr = CoCreateInstance(
  78. CLSID_DsDomainTreeBrowser,
  79. NULL,
  80. CLSCTX_INPROC_SERVER,
  81. IID_IDsBrowseDomainTree,
  82. (void **)&pDsDomTree
  83. );
  84. RETURN_IF_FAILED(hr);
  85. PDOMAIN_TREE pDomTree = NULL;
  86. hr = pDsDomTree->GetDomains(&pDomTree, DBDTF_RETURNEXTERNAL | DBDTF_RETURNINBOUND);
  87. RETURN_IF_FAILED(hr);
  88. // Flaten the tree in to a list.
  89. hr = FlatAdd(&(pDomTree->aDomains[0]), o_pDomains);
  90. pDsDomTree->FreeDomains(&pDomTree);
  91. return hr;
  92. }
  93. //----------------------------------------------------------------------------------
  94. HRESULT Is50Domain
  95. (
  96. IN BSTR i_bstrDomain,
  97. OUT BSTR* o_pbstrDnsDomainName
  98. )
  99. {
  100. return GetDomainInfo(i_bstrDomain, NULL, o_pbstrDnsDomainName);
  101. }
  102. //----------------------------------------------------------------------------------
  103. HRESULT GetServerInfo
  104. (
  105. IN BSTR i_bstrServer,
  106. OUT BSTR *o_pbstrDomain, // = NULL
  107. OUT BSTR *o_pbstrNetbiosName, // = NULL
  108. OUT BOOL *o_pbValidDSObject, // = NULL
  109. OUT BSTR *o_pbstrDnsName, // = NULL
  110. OUT BSTR *o_pbstrGuid, // = NULL
  111. OUT BSTR *o_pbstrFQDN, // = NULL
  112. OUT SUBSCRIBERLIST *o_pFRSRootList, // NULL
  113. OUT long *o_lMajorNo, // = NULL
  114. OUT long *o_lMinorNo // = NULL
  115. )
  116. {
  117. // This function uses NetWkstaGetInfo to get the server informaiton.
  118. if (!o_pbstrDomain &&
  119. !o_pbstrNetbiosName &&
  120. !o_pbValidDSObject &&
  121. !o_pbstrDnsName &&
  122. !o_pbstrGuid &&
  123. !o_pbstrFQDN &&
  124. !o_pFRSRootList &&
  125. !o_lMajorNo &&
  126. !o_lMinorNo
  127. )
  128. return(E_INVALIDARG);
  129. if (o_pbstrDomain) *o_pbstrDomain = NULL;
  130. if (o_pbstrNetbiosName) *o_pbstrNetbiosName = NULL;
  131. if (o_pbValidDSObject) *o_pbValidDSObject = FALSE;
  132. if (o_pbstrDnsName) *o_pbstrDnsName = NULL;
  133. if (o_pbstrGuid) *o_pbstrGuid = NULL;
  134. if (o_pbstrFQDN) *o_pbstrFQDN = NULL;
  135. if (o_pFRSRootList) FreeSubscriberList(o_pFRSRootList);
  136. if (o_lMajorNo) *o_lMajorNo = 0;
  137. if (o_lMinorNo) *o_lMinorNo = 0;
  138. HRESULT hr = S_OK;
  139. PWKSTA_INFO_100 wki100 = NULL;
  140. NET_API_STATUS NetStatus = NetWkstaGetInfo(i_bstrServer, 100, (LPBYTE *) &wki100 );
  141. if (ERROR_SUCCESS != NetStatus)
  142. hr = HRESULT_FROM_WIN32(NetStatus);
  143. else
  144. {
  145. if (o_lMajorNo)
  146. *o_lMajorNo = wki100->wki100_ver_major;
  147. if (o_lMinorNo)
  148. *o_lMinorNo = wki100->wki100_ver_minor;
  149. if (SUCCEEDED(hr) && o_pbstrNetbiosName && wki100->wki100_computername)
  150. {
  151. *o_pbstrNetbiosName = SysAllocString(wki100->wki100_computername);
  152. if (!*o_pbstrNetbiosName)
  153. hr = E_OUTOFMEMORY;
  154. }
  155. if (SUCCEEDED(hr) &&
  156. (o_pbstrDomain || o_pbValidDSObject || o_pbstrDnsName || o_pbstrGuid || o_pbstrFQDN || o_pFRSRootList) &&
  157. wki100->wki100_langroup &&
  158. wki100->wki100_computername)
  159. {
  160. PDSROLE_PRIMARY_DOMAIN_INFO_BASIC pBuffer = NULL;
  161. DWORD dwErr = DsRoleGetPrimaryDomainInformation(
  162. i_bstrServer,
  163. DsRolePrimaryDomainInfoBasic,
  164. (PBYTE *)&pBuffer);
  165. if (ERROR_SUCCESS != dwErr)
  166. hr = HRESULT_FROM_WIN32(dwErr);
  167. else
  168. {
  169. CComBSTR bstrDomain;
  170. //
  171. // Verify if this is really a server name.
  172. // NetWkstaGetInfo and DsRoleGetPrimaryDomainInformation work with domain name,
  173. // they return info of a DC.
  174. //
  175. if (i_bstrServer && *i_bstrServer &&
  176. (pBuffer->DomainNameFlat && !lstrcmpi(i_bstrServer, pBuffer->DomainNameFlat) ||
  177. pBuffer->DomainNameDns && !lstrcmpi(i_bstrServer, pBuffer->DomainNameDns)))
  178. {
  179. // we're seeing a domain name, not what we expect, return S_FALSE.
  180. hr = S_FALSE; // server not in a domain or cannot find an appropriate computer obj.
  181. } else
  182. {
  183. bstrDomain = (pBuffer->DomainNameDns ? pBuffer->DomainNameDns : pBuffer->DomainNameFlat);
  184. if (!bstrDomain)
  185. {
  186. hr = E_OUTOFMEMORY;
  187. } else if (!*bstrDomain)
  188. {
  189. hr = S_FALSE; // server not in a domain or cannot find an appropriate computer obj.
  190. } else
  191. {
  192. //
  193. // In case the DNS name is in absolute form, remove the ending dot
  194. //
  195. int nlen = _tcslen(bstrDomain);
  196. if ( *(bstrDomain + nlen - 1) == _T('.') )
  197. *(bstrDomain + nlen - 1) = _T('\0');
  198. }
  199. }
  200. DsRoleFreeMemory(pBuffer);
  201. if (S_OK == hr && o_pbstrDomain)
  202. {
  203. *o_pbstrDomain = SysAllocString(bstrDomain);
  204. if (!*o_pbstrDomain)
  205. hr = E_OUTOFMEMORY;
  206. }
  207. if (S_OK == hr &&
  208. (o_pbValidDSObject || o_pbstrDnsName || o_pbstrGuid || o_pbstrFQDN || o_pFRSRootList) )
  209. {
  210. CComBSTR bstrDC;
  211. HANDLE hDS = NULL;
  212. hr = DsBindToDS(bstrDomain, &bstrDC, &hDS);
  213. if (SUCCEEDED(hr))
  214. {
  215. CComBSTR bstrOldName = wki100->wki100_langroup;
  216. bstrOldName += _T("\\");
  217. bstrOldName += wki100->wki100_computername;
  218. bstrOldName += _T("$");
  219. if (o_pbstrGuid)
  220. hr = CrackName(hDS, bstrOldName, DS_NT4_ACCOUNT_NAME, DS_UNIQUE_ID_NAME, o_pbstrGuid);
  221. if (SUCCEEDED(hr) && (o_pbValidDSObject || o_pbstrDnsName || o_pbstrFQDN || o_pFRSRootList))
  222. {
  223. CComBSTR bstrComputerDN;
  224. hr = CrackName(hDS, bstrOldName, DS_NT4_ACCOUNT_NAME, DS_FQDN_1779_NAME, &bstrComputerDN);
  225. if (SUCCEEDED(hr) && o_pbstrFQDN)
  226. {
  227. *o_pbstrFQDN = bstrComputerDN.Copy();
  228. if (!*o_pbstrFQDN)
  229. hr = E_OUTOFMEMORY;
  230. }
  231. if (SUCCEEDED(hr) && (o_pbValidDSObject || o_pbstrDnsName || o_pFRSRootList))
  232. {
  233. PLDAP pldap = NULL;
  234. hr = LdapConnectToDC(bstrDC, &pldap);
  235. if (SUCCEEDED(hr))
  236. {
  237. dwErr = ldap_bind_s(pldap, NULL, NULL, LDAP_AUTH_NEGOTIATE);
  238. if (LDAP_SUCCESS != dwErr)
  239. {
  240. DebugOutLDAPError(pldap, dwErr, _T("ldap_bind_s"));
  241. hr = HRESULT_FROM_WIN32(dwErr);
  242. } else
  243. {
  244. if (o_pbValidDSObject)
  245. {
  246. hr = IsValidObject(pldap, bstrComputerDN);
  247. *o_pbValidDSObject = (S_OK == hr);
  248. }
  249. if (SUCCEEDED(hr) && o_pbstrDnsName)
  250. {
  251. PLDAP_ATTR_VALUE pValues[2] = {0,0};
  252. LDAP_ATTR_VALUE pAttributes[1];
  253. pAttributes[0].bstrAttribute = _T("dNSHostName");
  254. hr = GetValues(
  255. pldap,
  256. bstrComputerDN,
  257. OBJCLASS_SF_COMPUTER,
  258. LDAP_SCOPE_BASE,
  259. 1,
  260. pAttributes,
  261. pValues
  262. );
  263. if (SUCCEEDED(hr))
  264. {
  265. *o_pbstrDnsName = SysAllocString((LPTSTR)(pValues[0]->vpValue));
  266. if (!*o_pbstrDnsName)
  267. hr = E_OUTOFMEMORY;
  268. FreeAttrValList(pValues[0]);
  269. } else
  270. {
  271. hr = S_OK; // ignore failure, since dNSHostName might not be set
  272. }
  273. }
  274. if (SUCCEEDED(hr) && o_pFRSRootList)
  275. {
  276. PCTSTR ppszAttributes[] = {ATTR_FRS_SUBSCRIBER_MEMBERREF, ATTR_FRS_SUBSCRIBER_ROOTPATH, 0};
  277. LListElem* pElem = NULL;
  278. hr = GetValuesEx(pldap,
  279. bstrComputerDN,
  280. LDAP_SCOPE_SUBTREE,
  281. OBJCLASS_SF_NTFRSSUBSCRIBER,
  282. ppszAttributes,
  283. &pElem);
  284. if (SUCCEEDED(hr) && pElem)
  285. {
  286. LListElem* pCurElem = pElem;
  287. while (pCurElem)
  288. {
  289. PTSTR** pppszValues = pCurElem->pppszAttrValues;
  290. if (!pppszValues ||
  291. !pppszValues[0] || !*(pppszValues[0]) ||
  292. !pppszValues[1] || !*(pppszValues[1]))
  293. {
  294. pCurElem = pCurElem->Next;
  295. continue; // corrupted subscriber object, ignore it
  296. }
  297. SUBSCRIBER* pCurrent = new SUBSCRIBER;
  298. BREAK_OUTOFMEMORY_IF_NULL(pCurrent, &hr);
  299. pCurrent->bstrMemberDN = *(pppszValues[0]); // frsMemberReference
  300. pCurrent->bstrRootPath = *(pppszValues[1]); // frsRootPath
  301. if (!(pCurrent->bstrMemberDN) || !(pCurrent->bstrRootPath))
  302. {
  303. delete pCurrent;
  304. hr = E_OUTOFMEMORY;
  305. break;
  306. }
  307. o_pFRSRootList->push_back(pCurrent);
  308. pCurElem = pCurElem->Next;
  309. }
  310. FreeLListElem(pElem);
  311. if (FAILED(hr))
  312. FreeSubscriberList(o_pFRSRootList);
  313. }
  314. }
  315. }
  316. ldap_unbind(pldap);
  317. }
  318. }
  319. }
  320. DsUnBind(&hDS);
  321. }
  322. }
  323. } // DsRoleGetPrimaryDomainInformation
  324. }
  325. NetApiBufferFree((LPBYTE)wki100);
  326. } //NetWkstaGetInfo
  327. return hr;
  328. }
  329. //----------------------------------------------------------------------------------
  330. HRESULT IsServerRunningDfs
  331. (
  332. IN BSTR i_bstrServer
  333. )
  334. /*++
  335. Routine Description:
  336. Contacts the machine and determines if service Dfs is running.
  337. Arguments:
  338. i_bstrServer - The server name.
  339. --*/
  340. {
  341. SC_HANDLE SCMHandle = NULL;
  342. SC_HANDLE DFSHandle = NULL;
  343. SERVICE_STATUS SStatus;
  344. HRESULT hr = S_FALSE;
  345. if ((SCMHandle = OpenSCManager(i_bstrServer, NULL, GENERIC_READ)) &&
  346. (DFSHandle = OpenService(SCMHandle, _T("Dfs"), SERVICE_QUERY_STATUS)) &&
  347. QueryServiceStatus(DFSHandle, &SStatus) &&
  348. (SERVICE_RUNNING == SStatus.dwCurrentState) )
  349. {
  350. hr = S_OK;
  351. }
  352. if (DFSHandle)
  353. CloseServiceHandle(DFSHandle);
  354. if (SCMHandle)
  355. CloseServiceHandle(SCMHandle);
  356. return hr;
  357. }
  358. //
  359. // TRUE: support NTFS 5 reparse point
  360. // FALSE: doesn't support
  361. //
  362. BOOL CheckReparsePoint(IN BSTR i_bstrServer, IN BSTR i_bstrShare)
  363. {
  364. if (!i_bstrServer || !*i_bstrServer || !i_bstrShare || !*i_bstrShare)
  365. return FALSE;
  366. TCHAR szFileSystemName[MAX_PATH + 1] = {0};
  367. DWORD dwMaxCompLength = 0, dwFileSystemFlags = 0;
  368. CComBSTR bstrRootPath = _T("\\\\");
  369. bstrRootPath += i_bstrServer;
  370. bstrRootPath += _T("\\");
  371. bstrRootPath += i_bstrShare;
  372. bstrRootPath += _T("\\"); // a trailing backslash is required
  373. BOOL bRet = GetVolumeInformation(bstrRootPath, NULL, 0, NULL, &dwMaxCompLength,
  374. &dwFileSystemFlags, szFileSystemName, MAX_PATH);
  375. return (bRet && !lstrcmpi(_T("NTFS"), szFileSystemName) &&
  376. (dwFileSystemFlags & FILE_SUPPORTS_REPARSE_POINTS));
  377. }
  378. //----------------------------------------------------------------------------------
  379. //
  380. // S_OK: o_pbFound is valid
  381. // S_FALSE: share is not eligible to host dfs root
  382. // hr: other errors
  383. //
  384. HRESULT CheckShare
  385. (
  386. IN BSTR i_bstrServer,
  387. IN BSTR i_bstrShare,
  388. OUT BOOL* o_pbFound
  389. )
  390. {
  391. if (!i_bstrServer || !*i_bstrServer || !i_bstrShare || !*i_bstrShare || !o_pbFound)
  392. return E_INVALIDARG;
  393. *o_pbFound = FALSE;
  394. if (!lstrcmpi(i_bstrShare, _T("SYSVOL")) ||
  395. !lstrcmpi(i_bstrShare, _T("NETLOGON")) ||
  396. _istspace(i_bstrShare[0]) || // exclude share with leading space
  397. _istspace(i_bstrShare[lstrlen(i_bstrShare) - 1]) // exclude share with trailing space
  398. )
  399. return S_FALSE;
  400. LPSHARE_INFO_1 lpBuffer = NULL;
  401. DWORD dwNumEntries = 0;
  402. DWORD dwTotalEntries = 0;
  403. DWORD dwResumehandle = NULL;
  404. NET_API_STATUS nstatRetVal = NetShareEnum(
  405. i_bstrServer,
  406. 1L,
  407. (LPBYTE*) &lpBuffer,
  408. 0xFFFFFFFF,
  409. &dwNumEntries,
  410. &dwTotalEntries,
  411. &dwResumehandle
  412. );
  413. if (NERR_Success != nstatRetVal)
  414. {
  415. if (ERROR_NO_MORE_ITEMS == nstatRetVal)
  416. return S_OK;
  417. else
  418. return HRESULT_FROM_WIN32(nstatRetVal);
  419. }
  420. HRESULT hr = S_OK;
  421. for (DWORD i = 0; i < dwNumEntries; i++)
  422. {
  423. if (!lstrcmpi(lpBuffer[i].shi1_netname, i_bstrShare))
  424. {
  425. if (lpBuffer[i].shi1_type != STYPE_DISKTREE)
  426. hr = S_FALSE;
  427. else
  428. *o_pbFound = TRUE;
  429. break;
  430. }
  431. }
  432. NetApiBufferFree ((LPVOID) lpBuffer);
  433. return hr;
  434. }
  435. HRESULT CreateShare
  436. (
  437. IN BSTR i_bstrServerName,
  438. IN BSTR i_bstrShareName,
  439. IN BSTR i_bstrComment,
  440. IN BSTR i_bstrPath
  441. )
  442. /*++
  443. Routine Description:
  444. This function creates an share of the specified name on the specified computer.
  445. Arguments:
  446. i_bstrServerName - The machine on which the new share is to be created.
  447. i_bstrShareName - The name of the new share to be created.
  448. i_bstrComment - Comment to be given for the share.
  449. i_bstrPath - The physical path of the share.
  450. --*/
  451. {
  452. RETURN_INVALIDARG_IF_NULL(i_bstrServerName);
  453. RETURN_INVALIDARG_IF_NULL(i_bstrShareName);
  454. RETURN_INVALIDARG_IF_NULL(i_bstrComment);
  455. RETURN_INVALIDARG_IF_NULL(i_bstrPath);
  456. SHARE_INFO_2 NewShareInfo;
  457. NewShareInfo.shi2_netname = i_bstrShareName;
  458. NewShareInfo.shi2_type = STYPE_DISKTREE;
  459. NewShareInfo.shi2_remark = i_bstrComment;
  460. NewShareInfo.shi2_permissions = ACCESS_ALL;
  461. NewShareInfo.shi2_max_uses = (DWORD)-1;
  462. NewShareInfo.shi2_current_uses = 0;
  463. NewShareInfo.shi2_path = i_bstrPath;
  464. NewShareInfo.shi2_passwd = NULL;
  465. DWORD dwError = 0;
  466. NET_API_STATUS nstatRetVal = NetShareAdd(i_bstrServerName, 2, (LPBYTE) &NewShareInfo, &dwError);
  467. return HRESULT_FROM_WIN32(nstatRetVal);
  468. }
  469. //----------------------------------------------------------------------------------
  470. // Checks if \\<server>\<share>\x\y\z is on a valid disktree share
  471. // and return the path local to the server
  472. HRESULT GetFolderInfo
  473. (
  474. IN BSTR i_bstrServerName, // <server>
  475. IN BSTR i_bstrFolder, // <share>\x\y\z
  476. OUT BSTR *o_bstrPath // return <share path>\x\y\z
  477. )
  478. {
  479. if (!i_bstrServerName || !*i_bstrServerName || !i_bstrFolder || !*i_bstrFolder)
  480. {
  481. return(E_INVALIDARG);
  482. }
  483. //
  484. // first, test if folder \\<server>\<share>\x\y\z can be reached
  485. //
  486. CComBSTR bstrUNC;
  487. if (0 != mylstrncmp(i_bstrServerName, _T("\\\\"), 2))
  488. {
  489. bstrUNC = _T("\\\\");
  490. RETURN_OUTOFMEMORY_IF_NULL((BSTR)bstrUNC);
  491. }
  492. bstrUNC += i_bstrServerName;
  493. RETURN_OUTOFMEMORY_IF_NULL((BSTR)bstrUNC);
  494. bstrUNC += _T("\\");
  495. RETURN_OUTOFMEMORY_IF_NULL((BSTR)bstrUNC);
  496. bstrUNC += i_bstrFolder;
  497. RETURN_OUTOFMEMORY_IF_NULL((BSTR)bstrUNC);
  498. if (-1 == GetFileAttributes(bstrUNC))
  499. return HRESULT_FROM_WIN32(GetLastError());
  500. CComBSTR bstrShareName;
  501. CComBSTR bstrRestOfPath;
  502. TCHAR *p = _tcschr(i_bstrFolder, _T('\\'));
  503. if (p && *(p+1))
  504. {
  505. bstrRestOfPath = p+1;
  506. RETURN_OUTOFMEMORY_IF_NULL((BSTR)bstrRestOfPath);
  507. bstrShareName = CComBSTR(p - i_bstrFolder, i_bstrFolder);
  508. } else
  509. {
  510. bstrShareName = i_bstrFolder;
  511. }
  512. RETURN_OUTOFMEMORY_IF_NULL((BSTR)bstrShareName);
  513. HRESULT hr = S_OK;
  514. SHARE_INFO_2 *pShareInfo = NULL;
  515. NET_API_STATUS nstatRetVal = NetShareGetInfo (i_bstrServerName, bstrShareName, 2, (LPBYTE *)&pShareInfo);
  516. if (nstatRetVal != NERR_Success)
  517. {
  518. hr = HRESULT_FROM_WIN32(nstatRetVal);
  519. }
  520. else
  521. {
  522. if (STYPE_DISKTREE != pShareInfo->shi2_type &&
  523. STYPE_SPECIAL != pShareInfo->shi2_type) // we allow ADMIN$, C$ to be configured in Dfs/Frs
  524. hr = STG_E_NOTFILEBASEDSTORAGE;
  525. while (NULL != o_bstrPath)
  526. {
  527. CComBSTR bstrPath = pShareInfo->shi2_path;
  528. BREAK_OUTOFMEMORY_IF_NULL((BSTR)bstrPath, &hr);
  529. if (!!bstrRestOfPath)
  530. {
  531. if ( _T('\\') != *(bstrPath + _tcslen(bstrPath) - 1) )
  532. {
  533. bstrPath += _T("\\");
  534. BREAK_OUTOFMEMORY_IF_NULL((BSTR)bstrPath, &hr);
  535. }
  536. bstrPath += bstrRestOfPath;
  537. BREAK_OUTOFMEMORY_IF_NULL((BSTR)bstrPath, &hr);
  538. }
  539. *o_bstrPath = bstrPath.Detach();
  540. break;
  541. }
  542. NetApiBufferFree(pShareInfo);
  543. }
  544. return(hr);
  545. }
  546. void FreeNetNameList(NETNAMELIST *pList)
  547. {
  548. if (pList && !pList->empty()) {
  549. for (NETNAMELIST::iterator i = pList->begin(); i != pList->end(); i++)
  550. delete (*i);
  551. pList->clear();
  552. }
  553. }
  554. void FreeRootInfoList(ROOTINFOLIST *pList)
  555. {
  556. if (pList && !pList->empty()) {
  557. for (ROOTINFOLIST::iterator i = pList->begin(); i != pList->end(); i++)
  558. delete (*i);
  559. pList->clear();
  560. }
  561. }
  562. void FreeSubscriberList(SUBSCRIBERLIST *pList)
  563. {
  564. if (pList && !pList->empty()) {
  565. for (SUBSCRIBERLIST::iterator i = pList->begin(); i != pList->end(); i++)
  566. delete (*i);
  567. pList->clear();
  568. }
  569. }
  570. HRESULT GetLocalComputerName(OUT BSTR* o_pbstrComputerName)
  571. {
  572. _ASSERT(o_pbstrComputerName);
  573. DWORD dwErr = 0;
  574. TCHAR szBuffer[DNS_MAX_NAME_BUFFER_LENGTH];
  575. DWORD dwSize = DNS_MAX_NAME_BUFFER_LENGTH;
  576. if ( !GetComputerNameEx(ComputerNameDnsFullyQualified, szBuffer, &dwSize) )
  577. {
  578. dwSize = DNS_MAX_NAME_BUFFER_LENGTH;
  579. if ( !GetComputerNameEx(ComputerNameNetBIOS, szBuffer, &dwSize) )
  580. dwErr = GetLastError();
  581. }
  582. if (0 == dwErr)
  583. {
  584. *o_pbstrComputerName = SysAllocString(szBuffer);
  585. if (!*o_pbstrComputerName)
  586. dwErr = ERROR_OUTOFMEMORY;
  587. }
  588. return HRESULT_FROM_WIN32(dwErr);
  589. }
  590. HRESULT
  591. GetDomainDfsRoots(
  592. OUT NETNAMELIST* o_pDfsRootList,
  593. IN LPCTSTR i_lpszDomainName
  594. )
  595. {
  596. HRESULT hr = S_OK;
  597. FreeNetNameList(o_pDfsRootList);
  598. do {
  599. DFS_INFO_200 *pBuffer = NULL;
  600. DWORD dwEntriesRead = 0;
  601. DWORD dwResumeHandle = 0;
  602. DWORD dwErr = NetDfsEnum(
  603. const_cast<LPTSTR>(i_lpszDomainName),
  604. 200, // Level,
  605. (DWORD)-1, // PrefMaxLen,
  606. (LPBYTE *)&pBuffer,
  607. &dwEntriesRead,
  608. &dwResumeHandle
  609. );
  610. if (NERR_Success != dwErr)
  611. {
  612. hr = (ERROR_NO_MORE_ITEMS == dwErr || ERROR_NOT_FOUND == dwErr) ? S_FALSE : HRESULT_FROM_WIN32(dwErr);
  613. break;
  614. }
  615. NETNAME *pCurrent = NULL;
  616. for (DWORD i = 0; i < dwEntriesRead; i++)
  617. {
  618. pCurrent = new NETNAME;
  619. if (!pCurrent)
  620. {
  621. hr = E_OUTOFMEMORY;
  622. break;
  623. }
  624. pCurrent->bstrNetName = pBuffer[i].FtDfsName;
  625. if (!pCurrent->bstrNetName)
  626. {
  627. delete pCurrent;
  628. hr = E_OUTOFMEMORY;
  629. break;
  630. }
  631. o_pDfsRootList->push_back(pCurrent);
  632. }
  633. NetApiBufferFree(pBuffer);
  634. } while (0);
  635. if (FAILED(hr))
  636. FreeNetNameList(o_pDfsRootList);
  637. return hr;
  638. }
  639. HRESULT
  640. GetMultiDfsRoots(
  641. OUT ROOTINFOLIST* o_pDfsRootList,
  642. IN LPCTSTR i_lpszScope
  643. )
  644. {
  645. if (!i_lpszScope || !*i_lpszScope)
  646. return E_INVALIDARG;
  647. HRESULT hr = S_OK;
  648. FreeRootInfoList(o_pDfsRootList);
  649. do {
  650. DFS_INFO_200 *pBuffer = NULL;
  651. DWORD dwEntriesRead = 0;
  652. DWORD dwResumeHandle = 0;
  653. DWORD dwErr = NetDfsEnum(
  654. const_cast<LPTSTR>(i_lpszScope),
  655. 200, // Level,
  656. (DWORD)-1, // PrefMaxLen,
  657. (LPBYTE *)&pBuffer,
  658. &dwEntriesRead,
  659. &dwResumeHandle
  660. );
  661. if (NERR_Success != dwErr)
  662. {
  663. hr = (ERROR_NO_MORE_ITEMS == dwErr || ERROR_NOT_FOUND == dwErr) ? S_FALSE : HRESULT_FROM_WIN32(dwErr);
  664. break;
  665. }
  666. ROOTINFO *pCurrent = NULL;
  667. for (DWORD i = 0; i < dwEntriesRead; i++)
  668. {
  669. CComBSTR bstrEntryPath = _T("\\\\");
  670. bstrEntryPath += i_lpszScope;
  671. bstrEntryPath += _T("\\");
  672. bstrEntryPath += pBuffer[i].FtDfsName;
  673. PDFS_INFO_2 pDfsInfo = NULL;
  674. NET_API_STATUS nRet = NetDfsGetInfo(
  675. bstrEntryPath,
  676. NULL,
  677. NULL,
  678. 2,
  679. (LPBYTE*) &pDfsInfo
  680. );
  681. if (NERR_Success != nRet)
  682. continue;
  683. pCurrent = new ROOTINFO;
  684. if (pCurrent)
  685. {
  686. if ((pDfsInfo->State & DFS_VOLUME_FLAVORS) == DFS_VOLUME_FLAVOR_AD_BLOB)
  687. pCurrent->enumRootType = DFS_TYPE_FTDFS;
  688. else
  689. pCurrent->enumRootType = DFS_TYPE_STANDALONE;
  690. pCurrent->bstrRootName = pBuffer[i].FtDfsName;
  691. }
  692. NetApiBufferFree(pDfsInfo);
  693. if (!pCurrent)
  694. {
  695. hr = E_OUTOFMEMORY;
  696. break;
  697. }
  698. if (!pCurrent->bstrRootName)
  699. {
  700. delete pCurrent;
  701. hr = E_OUTOFMEMORY;
  702. break;
  703. }
  704. o_pDfsRootList->push_back(pCurrent);
  705. }
  706. NetApiBufferFree(pBuffer);
  707. } while (0);
  708. if (FAILED(hr))
  709. FreeRootInfoList(o_pDfsRootList);
  710. return hr;
  711. }
  712. /*
  713. bool
  714. IsDfsPath
  715. (
  716. LPTSTR i_lpszNetPath
  717. )
  718. {
  719. if ( S_OK != CheckUNCPath(i_lpszNetPath) )
  720. return false;
  721. CComBSTR bstrPath = i_lpszNetPath;
  722. if (!bstrPath)
  723. return false; // out of memory
  724. TCHAR *s = _tcschr(bstrPath + 2, _T('\\')); // points to the 3rd backslash
  725. TCHAR *p = bstrPath + bstrPath.Length(); // points to the ending char '\0'
  726. bool bIsDfsPath = false;
  727. do
  728. {
  729. *p = _T('\0');
  730. PDFS_INFO_1 pDfsInfo1 = NULL;
  731. DWORD dwStatus = NetDfsGetClientInfo (
  732. bstrPath, // dir path as entrypath
  733. NULL, // No server name required
  734. NULL, // No share required
  735. 1, // level 1
  736. (LPBYTE *)&pDfsInfo1 // out buffer.
  737. );
  738. if (NERR_Success == dwStatus)
  739. {
  740. bIsDfsPath = true;
  741. NetApiBufferFree(pDfsInfo1);
  742. break;
  743. }
  744. p--;
  745. while (_T('\\') != *p && p > s)
  746. {
  747. p--;
  748. }
  749. } while (p > s);
  750. return bIsDfsPath;
  751. }
  752. */
  753. HRESULT CheckUNCPath(
  754. IN LPCTSTR i_lpszPath
  755. )
  756. /*++
  757. Routine Description:
  758. Checks if path is of UNC format.
  759. --*/
  760. {
  761. //"someserver\someshare\somedir\.." - Invalid
  762. //"\\Server - Invalid
  763. //"\\someserver\someshare\.. - Valid
  764. //"\\someserver\someshare\Somedir\.. - Valid
  765. RETURN_INVALIDARG_IF_NULL(i_lpszPath);
  766. DWORD dwRetFlags = 0;
  767. NET_API_STATUS nStatus = I_NetPathType(NULL, (LPTSTR)i_lpszPath, &dwRetFlags, 0);
  768. if (NERR_Success != nStatus)
  769. return HRESULT_FROM_WIN32(nStatus);
  770. return (ITYPE_UNC == dwRetFlags) ? S_OK : S_FALSE;
  771. }
  772. HRESULT GetUNCPathComponent(
  773. IN LPCTSTR i_lpszPath,
  774. OUT BSTR* o_pbstrComponent,
  775. IN UINT i_nStartBackslashes, // index starting from 1
  776. IN UINT i_nEndBackslashes // index starting from 1
  777. )
  778. {
  779. RETURN_INVALIDARG_IF_NULL(o_pbstrComponent);
  780. RETURN_INVALIDARG_IF_TRUE(i_nStartBackslashes < 2);
  781. RETURN_INVALIDARG_IF_TRUE(0 != i_nEndBackslashes && i_nEndBackslashes <= i_nStartBackslashes);
  782. *o_pbstrComponent = NULL;
  783. HRESULT hr = CheckUNCPath(i_lpszPath);
  784. RETURN_INVALIDARG_IF_TRUE(S_OK != hr);
  785. UINT nDeltaBackslashes = i_nEndBackslashes ? (i_nEndBackslashes - i_nStartBackslashes) : 0;
  786. TCHAR *p = (LPTSTR)i_lpszPath + 2; // skip the first 2 backslashes
  787. i_nStartBackslashes -= 2;
  788. // locate the starting backslash
  789. while (*p && i_nStartBackslashes)
  790. {
  791. if (_T('\\') == *p)
  792. i_nStartBackslashes--;
  793. p++;
  794. }
  795. if (!*p)
  796. return hr;
  797. // locate the ending backslash
  798. TCHAR *s = p;
  799. if (!nDeltaBackslashes)
  800. {
  801. s += _tcslen(p);
  802. } else
  803. {
  804. while (*s && nDeltaBackslashes)
  805. {
  806. if (_T('\\') == *s)
  807. nDeltaBackslashes--;
  808. s++;
  809. }
  810. if (*s)
  811. s--;
  812. }
  813. // p points at the first char after the starting backslash, and
  814. // s points at the ending backslash or the ending char '\0'
  815. *o_pbstrComponent = SysAllocStringLen(p, s - p);
  816. RETURN_OUTOFMEMORY_IF_NULL(*o_pbstrComponent);
  817. return S_OK;
  818. }
  819. // return TRUE if string matches the filter string, case-insensitive match
  820. BOOL FilterMatch(LPCTSTR lpszString, FILTERDFSLINKS_TYPE lLinkFilterType, LPCTSTR lpszFilter)
  821. {
  822. BOOL bResult = TRUE;
  823. switch (lLinkFilterType)
  824. {
  825. case FILTERDFSLINKS_TYPE_BEGINWITH:
  826. if (!lpszString || !lpszFilter)
  827. return FALSE;
  828. bResult = !mylstrncmpi(lpszString, lpszFilter, lstrlen(lpszFilter));
  829. break;
  830. case FILTERDFSLINKS_TYPE_CONTAIN:
  831. {
  832. if (!lpszString || !lpszFilter)
  833. return FALSE;
  834. TCHAR* pszStringLower = _tcsdup(lpszString);
  835. TCHAR* pszFilterLower = _tcsdup(lpszFilter);
  836. if (!pszStringLower || !pszFilterLower)
  837. bResult = FALSE;
  838. else
  839. bResult = (NULL != _tcsstr(_tcslwr(pszStringLower), _tcslwr(pszFilterLower)));
  840. if (pszStringLower)
  841. free(pszStringLower);
  842. if (pszFilterLower)
  843. free(pszFilterLower);
  844. }
  845. break;
  846. default:
  847. break;
  848. }
  849. return bResult;
  850. }
  851. HRESULT IsHostingDfsRoot(IN BSTR i_bstrServer, OUT BSTR* o_pbstrRootEntryPath)
  852. {
  853. if (o_pbstrRootEntryPath)
  854. *o_pbstrRootEntryPath = NULL;
  855. DWORD dwEntriesRead = 0;
  856. DWORD dwResumeHandle = 0;
  857. DFS_INFO_1* pDfsInfoLevel1 = NULL;
  858. NET_API_STATUS dwRet = NetDfsEnum(
  859. i_bstrServer,
  860. 1,
  861. sizeof(DFS_INFO_1), // get 1 entry
  862. (LPBYTE *)&pDfsInfoLevel1,
  863. &dwEntriesRead,
  864. &dwResumeHandle
  865. );
  866. if (ERROR_NO_MORE_ITEMS == dwRet || ERROR_NOT_FOUND == dwRet)
  867. return S_FALSE;
  868. HRESULT hr = S_OK;
  869. if (NERR_Success == dwRet)
  870. {
  871. if (o_pbstrRootEntryPath)
  872. {
  873. *o_pbstrRootEntryPath = SysAllocString(pDfsInfoLevel1->EntryPath);
  874. if (!*o_pbstrRootEntryPath)
  875. hr = E_OUTOFMEMORY;
  876. }
  877. NetApiBufferFree(pDfsInfoLevel1);
  878. } else
  879. {
  880. hr = HRESULT_FROM_WIN32(dwRet);
  881. }
  882. return hr;
  883. }
  884. /*
  885. void GetTimeDelta(LPCTSTR str, SYSTEMTIME* ptime0, SYSTEMTIME* ptime1)
  886. {
  887. dfsDebugOut((_T("%s, delta = %d millisec \n"), str,
  888. ((ptime1->wMinute - ptime0->wMinute) * 60 +
  889. (ptime1->wSecond - ptime0->wSecond)) * 1000 +
  890. (ptime1->wMilliseconds - ptime0->wMilliseconds)
  891. ));
  892. }
  893. */