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.

1209 lines
38 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 (pBuffer->MachineRole == DsRole_RoleStandaloneWorkstation ||
  188. pBuffer->MachineRole == DsRole_RoleStandaloneServer ||
  189. !*bstrDomain)
  190. {
  191. hr = S_FALSE; // server not in a domain or cannot find an appropriate computer obj.
  192. } else
  193. {
  194. //
  195. // In case the DNS name is in absolute form, remove the ending dot
  196. //
  197. int nlen = _tcslen(bstrDomain);
  198. if ( *(bstrDomain + nlen - 1) == _T('.') )
  199. *(bstrDomain + nlen - 1) = _T('\0');
  200. }
  201. }
  202. DsRoleFreeMemory(pBuffer);
  203. if (S_OK == hr && o_pbstrDomain)
  204. {
  205. *o_pbstrDomain = SysAllocString(bstrDomain);
  206. if (!*o_pbstrDomain)
  207. hr = E_OUTOFMEMORY;
  208. }
  209. if (S_OK == hr &&
  210. (o_pbValidDSObject || o_pbstrDnsName || o_pbstrGuid || o_pbstrFQDN || o_pFRSRootList) )
  211. {
  212. CComBSTR bstrDC;
  213. HANDLE hDS = NULL;
  214. hr = DsBindToDS(bstrDomain, &bstrDC, &hDS);
  215. if (SUCCEEDED(hr))
  216. {
  217. CComBSTR bstrOldName = wki100->wki100_langroup;
  218. bstrOldName += _T("\\");
  219. bstrOldName += wki100->wki100_computername;
  220. bstrOldName += _T("$");
  221. if (o_pbstrGuid)
  222. hr = CrackName(hDS, bstrOldName, DS_NT4_ACCOUNT_NAME, DS_UNIQUE_ID_NAME, o_pbstrGuid);
  223. if (SUCCEEDED(hr) && (o_pbValidDSObject || o_pbstrDnsName || o_pbstrFQDN || o_pFRSRootList))
  224. {
  225. CComBSTR bstrComputerDN;
  226. hr = CrackName(hDS, bstrOldName, DS_NT4_ACCOUNT_NAME, DS_FQDN_1779_NAME, &bstrComputerDN);
  227. if (SUCCEEDED(hr) && o_pbstrFQDN)
  228. {
  229. *o_pbstrFQDN = bstrComputerDN.Copy();
  230. if (!*o_pbstrFQDN)
  231. hr = E_OUTOFMEMORY;
  232. }
  233. if (SUCCEEDED(hr) && (o_pbValidDSObject || o_pbstrDnsName || o_pFRSRootList))
  234. {
  235. PLDAP pldap = NULL;
  236. hr = LdapConnectToDC(bstrDC, &pldap);
  237. if (SUCCEEDED(hr))
  238. {
  239. dwErr = ldap_bind_s(pldap, NULL, NULL, LDAP_AUTH_NEGOTIATE);
  240. if (LDAP_SUCCESS != dwErr)
  241. {
  242. DebugOutLDAPError(pldap, dwErr, _T("ldap_bind_s"));
  243. hr = HRESULT_FROM_WIN32(dwErr);
  244. } else
  245. {
  246. if (o_pbValidDSObject)
  247. {
  248. hr = IsValidObject(pldap, bstrComputerDN);
  249. *o_pbValidDSObject = (S_OK == hr);
  250. }
  251. if (SUCCEEDED(hr) && o_pbstrDnsName)
  252. {
  253. PLDAP_ATTR_VALUE pValues[2] = {0,0};
  254. LDAP_ATTR_VALUE pAttributes[1];
  255. pAttributes[0].bstrAttribute = _T("dNSHostName");
  256. hr = GetValues(
  257. pldap,
  258. bstrComputerDN,
  259. OBJCLASS_SF_COMPUTER,
  260. LDAP_SCOPE_BASE,
  261. 1,
  262. pAttributes,
  263. pValues
  264. );
  265. if (SUCCEEDED(hr))
  266. {
  267. *o_pbstrDnsName = SysAllocString((LPTSTR)(pValues[0]->vpValue));
  268. if (!*o_pbstrDnsName)
  269. hr = E_OUTOFMEMORY;
  270. FreeAttrValList(pValues[0]);
  271. } else
  272. {
  273. hr = S_OK; // ignore failure, since dNSHostName might not be set
  274. }
  275. }
  276. if (SUCCEEDED(hr) && o_pFRSRootList)
  277. {
  278. PCTSTR ppszAttributes[] = {ATTR_FRS_SUBSCRIBER_MEMBERREF, ATTR_FRS_SUBSCRIBER_ROOTPATH, 0};
  279. LListElem* pElem = NULL;
  280. hr = GetValuesEx(pldap,
  281. bstrComputerDN,
  282. LDAP_SCOPE_SUBTREE,
  283. OBJCLASS_SF_NTFRSSUBSCRIBER,
  284. ppszAttributes,
  285. &pElem);
  286. if (SUCCEEDED(hr) && pElem)
  287. {
  288. LListElem* pCurElem = pElem;
  289. while (pCurElem)
  290. {
  291. PTSTR** pppszValues = pCurElem->pppszAttrValues;
  292. if (!pppszValues ||
  293. !pppszValues[0] || !*(pppszValues[0]) ||
  294. !pppszValues[1] || !*(pppszValues[1]))
  295. {
  296. pCurElem = pCurElem->Next;
  297. continue; // corrupted subscriber object, ignore it
  298. }
  299. SUBSCRIBER* pCurrent = new SUBSCRIBER;
  300. BREAK_OUTOFMEMORY_IF_NULL(pCurrent, &hr);
  301. pCurrent->bstrMemberDN = *(pppszValues[0]); // frsMemberReference
  302. pCurrent->bstrRootPath = *(pppszValues[1]); // frsRootPath
  303. if (!(pCurrent->bstrMemberDN) || !(pCurrent->bstrRootPath))
  304. {
  305. delete pCurrent;
  306. hr = E_OUTOFMEMORY;
  307. break;
  308. }
  309. o_pFRSRootList->push_back(pCurrent);
  310. pCurElem = pCurElem->Next;
  311. }
  312. FreeLListElem(pElem);
  313. if (FAILED(hr))
  314. FreeSubscriberList(o_pFRSRootList);
  315. }
  316. }
  317. }
  318. ldap_unbind(pldap);
  319. }
  320. }
  321. }
  322. DsUnBind(&hDS);
  323. }
  324. }
  325. } // DsRoleGetPrimaryDomainInformation
  326. }
  327. NetApiBufferFree((LPBYTE)wki100);
  328. } //NetWkstaGetInfo
  329. return hr;
  330. }
  331. //----------------------------------------------------------------------------------
  332. HRESULT IsServerRunningDfs
  333. (
  334. IN BSTR i_bstrServer
  335. )
  336. /*++
  337. Routine Description:
  338. Contacts the machine and determines if service Dfs is running.
  339. Arguments:
  340. i_bstrServer - The server name.
  341. --*/
  342. {
  343. SC_HANDLE SCMHandle = NULL;
  344. SC_HANDLE DFSHandle = NULL;
  345. SERVICE_STATUS SStatus;
  346. HRESULT hr = S_FALSE;
  347. if ((SCMHandle = OpenSCManager(i_bstrServer, NULL, GENERIC_READ)) &&
  348. (DFSHandle = OpenService(SCMHandle, _T("Dfs"), SERVICE_QUERY_STATUS)) &&
  349. QueryServiceStatus(DFSHandle, &SStatus) &&
  350. (SERVICE_RUNNING == SStatus.dwCurrentState) )
  351. {
  352. hr = S_OK;
  353. }
  354. if (DFSHandle)
  355. CloseServiceHandle(DFSHandle);
  356. if (SCMHandle)
  357. CloseServiceHandle(SCMHandle);
  358. return hr;
  359. }
  360. //
  361. // TRUE: support NTFS 5 reparse point
  362. // FALSE: doesn't support
  363. //
  364. BOOL CheckReparsePoint(IN BSTR i_bstrServer, IN BSTR i_bstrShare)
  365. {
  366. if (!i_bstrServer || !*i_bstrServer || !i_bstrShare || !*i_bstrShare)
  367. return FALSE;
  368. //
  369. // bug#720184
  370. // To work around GetVolumeInfo(\\server\share) adding the share to the SMB cache just before root
  371. // is created, we can replace it with NetShareGetInfo(server, share) and GetVolumeInfo(\\server\c$).
  372. // DFS will be able to hand out referral if \\server\share is not in the SMB cache.
  373. //
  374. // For cases that $ share may not exist or we might have mounted volumes, I'm returning TRUE to let
  375. // DFS API catch the error later. That is, if we failed to get share info or folder path is not in
  376. // C: format, we'll ignore and continue and let DFS API to handle it later.
  377. //
  378. SHARE_INFO_2 *pShareInfo = NULL;
  379. NET_API_STATUS nstatRetVal = NetShareGetInfo(i_bstrServer, i_bstrShare, 2, (LPBYTE *)&pShareInfo);
  380. if (nstatRetVal != NERR_Success)
  381. return TRUE;
  382. if (!pShareInfo->shi2_path || lstrlen(pShareInfo->shi2_path) < 2 || *(pShareInfo->shi2_path + 1) != _T(':'))
  383. {
  384. NetApiBufferFree(pShareInfo);
  385. return TRUE;
  386. }
  387. TCHAR szDriveShare[] = _T("\\C$\\");
  388. szDriveShare[1] = *(pShareInfo->shi2_path);
  389. NetApiBufferFree(pShareInfo);
  390. TCHAR szFileSystemName[MAX_PATH + 1] = {0};
  391. DWORD dwMaxCompLength = 0, dwFileSystemFlags = 0;
  392. CComBSTR bstrRootPath = _T("\\\\");
  393. bstrRootPath += i_bstrServer;
  394. bstrRootPath += szDriveShare;
  395. BOOL bRet = GetVolumeInformation(bstrRootPath, NULL, 0, NULL, &dwMaxCompLength,
  396. &dwFileSystemFlags, szFileSystemName, MAX_PATH);
  397. // If we failed to get volume info, we'll ignore and continue and let DFS API to handle it later
  398. return (!bRet || bRet && CSTR_EQUAL == CompareString(LOCALE_INVARIANT, NORM_IGNORECASE, _T("NTFS"), -1, szFileSystemName, -1) &&
  399. (dwFileSystemFlags & FILE_SUPPORTS_REPARSE_POINTS));
  400. }
  401. //----------------------------------------------------------------------------------
  402. //
  403. // S_OK: o_pbFound is valid
  404. // S_FALSE: share is not eligible to host dfs root
  405. // hr: other errors
  406. //
  407. HRESULT CheckShare
  408. (
  409. IN BSTR i_bstrServer,
  410. IN BSTR i_bstrShare,
  411. OUT BOOL* o_pbFound
  412. )
  413. {
  414. if (!i_bstrServer || !*i_bstrServer || !i_bstrShare || !*i_bstrShare || !o_pbFound)
  415. return E_INVALIDARG;
  416. *o_pbFound = FALSE;
  417. if (CSTR_EQUAL == CompareString(LOCALE_INVARIANT, NORM_IGNORECASE, i_bstrShare, -1, _T("SYSVOL"), -1) ||
  418. CSTR_EQUAL == CompareString(LOCALE_INVARIANT, NORM_IGNORECASE, i_bstrShare, -1, _T("NETLOGON"), -1) ||
  419. _istspace(i_bstrShare[0]) || // exclude share with leading space
  420. _istspace(i_bstrShare[lstrlen(i_bstrShare) - 1]) // exclude share with trailing space
  421. )
  422. return S_FALSE;
  423. LPSHARE_INFO_1 lpBuffer = NULL;
  424. DWORD dwNumEntries = 0;
  425. DWORD dwTotalEntries = 0;
  426. DWORD dwResumehandle = NULL;
  427. NET_API_STATUS nstatRetVal = NetShareEnum(
  428. i_bstrServer,
  429. 1L,
  430. (LPBYTE*) &lpBuffer,
  431. 0xFFFFFFFF,
  432. &dwNumEntries,
  433. &dwTotalEntries,
  434. &dwResumehandle
  435. );
  436. if (NERR_Success != nstatRetVal)
  437. {
  438. if (ERROR_NO_MORE_ITEMS == nstatRetVal)
  439. return S_OK;
  440. else
  441. return HRESULT_FROM_WIN32(nstatRetVal);
  442. }
  443. HRESULT hr = S_OK;
  444. for (DWORD i = 0; i < dwNumEntries; i++)
  445. {
  446. if (!lstrcmpi(lpBuffer[i].shi1_netname, i_bstrShare))
  447. {
  448. if (lpBuffer[i].shi1_type != STYPE_DISKTREE)
  449. hr = S_FALSE;
  450. else
  451. *o_pbFound = TRUE;
  452. break;
  453. }
  454. }
  455. NetApiBufferFree ((LPVOID) lpBuffer);
  456. return hr;
  457. }
  458. HRESULT
  459. BuildSecurityDescriptor(
  460. OUT PSECURITY_DESCRIPTOR *ppSelfRelativeSD // return a security descriptor in self-relative form
  461. )
  462. {
  463. if (*ppSelfRelativeSD)
  464. {
  465. LocalFree((HLOCAL)*ppSelfRelativeSD);
  466. *ppSelfRelativeSD = NULL;
  467. }
  468. HRESULT hr = S_OK;
  469. PSID pSid = NULL;
  470. PSECURITY_DESCRIPTOR pAbsoluteSD = NULL;
  471. PACL pACL = NULL;
  472. do { // false loop
  473. // get PSID of account "everyone"
  474. SID_IDENTIFIER_AUTHORITY SidIdentifierWORLDAuthority = SECURITY_WORLD_SID_AUTHORITY;
  475. DWORD dwRID[8];
  476. ZeroMemory(dwRID, sizeof(dwRID));
  477. dwRID[0] = SECURITY_WORLD_RID;
  478. if ( !AllocateAndInitializeSid(&SidIdentifierWORLDAuthority, 1,
  479. dwRID[0], dwRID[1], dwRID[2], dwRID[3],
  480. dwRID[4], dwRID[5], dwRID[6], dwRID[7], &pSid) )
  481. {
  482. hr = HRESULT_FROM_WIN32(GetLastError());
  483. break;
  484. }
  485. // Initialize a new ACL
  486. DWORD cbACL = sizeof(ACL) + sizeof(ACCESS_ALLOWED_ACE) + GetLengthSid(pSid) - sizeof(DWORD);
  487. if ( !(pACL = (PACL)LocalAlloc(LPTR, cbACL)) ||
  488. !InitializeAcl(pACL, cbACL, ACL_REVISION))
  489. {
  490. hr = HRESULT_FROM_WIN32(GetLastError());
  491. break;
  492. }
  493. // Add Ace
  494. if ( !::AddAccessAllowedAce(pACL, ACL_REVISION, (FILE_GENERIC_READ | FILE_EXECUTE), pSid) )
  495. {
  496. hr = HRESULT_FROM_WIN32(GetLastError());
  497. break;
  498. }
  499. // Note: this is a new object, set Dacl only.
  500. // Initialize a new security descriptor in absolute form and add the new ACL to it
  501. if ( !(pAbsoluteSD = (PSECURITY_DESCRIPTOR)LocalAlloc(LPTR, SECURITY_DESCRIPTOR_MIN_LENGTH)) ||
  502. !InitializeSecurityDescriptor(pAbsoluteSD, SECURITY_DESCRIPTOR_REVISION) ||
  503. !SetSecurityDescriptorDacl(pAbsoluteSD, TRUE, pACL, FALSE) )
  504. {
  505. hr = HRESULT_FROM_WIN32(GetLastError());
  506. break;
  507. }
  508. // transform into a self-relative form
  509. DWORD dwSDSize = 0;
  510. MakeSelfRelativeSD(pAbsoluteSD, *ppSelfRelativeSD, &dwSDSize);
  511. if ( !(*ppSelfRelativeSD = (PSECURITY_DESCRIPTOR)LocalAlloc(LPTR, dwSDSize)) ||
  512. !MakeSelfRelativeSD(pAbsoluteSD, *ppSelfRelativeSD, &dwSDSize) )
  513. {
  514. hr = HRESULT_FROM_WIN32(GetLastError());
  515. break;
  516. }
  517. } while (0);
  518. if (FAILED(hr))
  519. {
  520. if (*ppSelfRelativeSD)
  521. {
  522. LocalFree((HLOCAL)*ppSelfRelativeSD);
  523. *ppSelfRelativeSD = NULL;
  524. }
  525. }
  526. if (pACL)
  527. LocalFree((HLOCAL)pACL);
  528. if (pAbsoluteSD)
  529. LocalFree((HLOCAL)pAbsoluteSD);
  530. if (pSid)
  531. FreeSid(pSid);
  532. return hr;
  533. }
  534. HRESULT CreateShare
  535. (
  536. IN BSTR i_bstrServerName,
  537. IN BSTR i_bstrShareName,
  538. IN BSTR i_bstrComment,
  539. IN BSTR i_bstrPath
  540. )
  541. /*++
  542. Routine Description:
  543. This function creates an share of the specified name on the specified computer.
  544. Arguments:
  545. i_bstrServerName - The machine on which the new share is to be created.
  546. i_bstrShareName - The name of the new share to be created.
  547. i_bstrComment - Comment to be given for the share.
  548. i_bstrPath - The physical path of the share.
  549. --*/
  550. {
  551. RETURN_INVALIDARG_IF_NULL(i_bstrServerName);
  552. RETURN_INVALIDARG_IF_NULL(i_bstrShareName);
  553. RETURN_INVALIDARG_IF_NULL(i_bstrComment);
  554. RETURN_INVALIDARG_IF_NULL(i_bstrPath);
  555. PSECURITY_DESCRIPTOR pSD = NULL;
  556. HRESULT hr = BuildSecurityDescriptor(&pSD);
  557. if (FAILED(hr))
  558. return hr;
  559. SHARE_INFO_502 sInfo;
  560. ZeroMemory(&sInfo, sizeof(sInfo));
  561. sInfo.shi502_netname = i_bstrShareName;
  562. sInfo.shi502_type = STYPE_DISKTREE;
  563. sInfo.shi502_remark = i_bstrComment;
  564. sInfo.shi502_max_uses = (DWORD)-1;
  565. sInfo.shi502_path = i_bstrPath;
  566. sInfo.shi502_security_descriptor = pSD;
  567. DWORD dwError = 0;
  568. NET_API_STATUS nRet = NetShareAdd(i_bstrServerName, 502, (LPBYTE)&sInfo, &dwError);
  569. LocalFree((HLOCAL)pSD);
  570. return HRESULT_FROM_WIN32(nRet);
  571. }
  572. //----------------------------------------------------------------------------------
  573. // Checks if \\<server>\<share>\x\y\z is on a valid disktree share
  574. // and return the path local to the server
  575. HRESULT GetFolderInfo
  576. (
  577. IN BSTR i_bstrServerName, // <server>
  578. IN BSTR i_bstrFolder, // <share>\x\y\z
  579. OUT BSTR *o_bstrPath // return <share path>\x\y\z
  580. )
  581. {
  582. if (!i_bstrServerName || !*i_bstrServerName || !i_bstrFolder || !*i_bstrFolder)
  583. {
  584. return(E_INVALIDARG);
  585. }
  586. //
  587. // first, test if folder \\<server>\<share>\x\y\z can be reached
  588. //
  589. CComBSTR bstrUNC;
  590. if (0 != mylstrncmp(i_bstrServerName, _T("\\\\"), 2))
  591. {
  592. bstrUNC = _T("\\\\");
  593. RETURN_OUTOFMEMORY_IF_NULL((BSTR)bstrUNC);
  594. }
  595. bstrUNC += i_bstrServerName;
  596. RETURN_OUTOFMEMORY_IF_NULL((BSTR)bstrUNC);
  597. bstrUNC += _T("\\");
  598. RETURN_OUTOFMEMORY_IF_NULL((BSTR)bstrUNC);
  599. bstrUNC += i_bstrFolder;
  600. RETURN_OUTOFMEMORY_IF_NULL((BSTR)bstrUNC);
  601. if (-1 == GetFileAttributes(bstrUNC))
  602. return HRESULT_FROM_WIN32(GetLastError());
  603. CComBSTR bstrShareName;
  604. CComBSTR bstrRestOfPath;
  605. TCHAR *p = _tcschr(i_bstrFolder, _T('\\'));
  606. if (p && *(p+1))
  607. {
  608. bstrRestOfPath = p+1;
  609. RETURN_OUTOFMEMORY_IF_NULL((BSTR)bstrRestOfPath);
  610. bstrShareName = CComBSTR(p - i_bstrFolder, i_bstrFolder);
  611. } else
  612. {
  613. bstrShareName = i_bstrFolder;
  614. }
  615. RETURN_OUTOFMEMORY_IF_NULL((BSTR)bstrShareName);
  616. HRESULT hr = S_OK;
  617. SHARE_INFO_2 *pShareInfo = NULL;
  618. NET_API_STATUS nstatRetVal = NetShareGetInfo (i_bstrServerName, bstrShareName, 2, (LPBYTE *)&pShareInfo);
  619. if (nstatRetVal != NERR_Success)
  620. {
  621. hr = HRESULT_FROM_WIN32(nstatRetVal);
  622. }
  623. else
  624. {
  625. if (STYPE_DISKTREE != pShareInfo->shi2_type &&
  626. STYPE_SPECIAL != pShareInfo->shi2_type) // we allow ADMIN$, C$ to be configured in Dfs/Frs
  627. hr = STG_E_NOTFILEBASEDSTORAGE;
  628. while (NULL != o_bstrPath)
  629. {
  630. CComBSTR bstrPath = pShareInfo->shi2_path;
  631. BREAK_OUTOFMEMORY_IF_NULL((BSTR)bstrPath, &hr);
  632. if (!!bstrRestOfPath)
  633. {
  634. if ( _T('\\') != *(bstrPath + _tcslen(bstrPath) - 1) )
  635. {
  636. bstrPath += _T("\\");
  637. BREAK_OUTOFMEMORY_IF_NULL((BSTR)bstrPath, &hr);
  638. }
  639. bstrPath += bstrRestOfPath;
  640. BREAK_OUTOFMEMORY_IF_NULL((BSTR)bstrPath, &hr);
  641. }
  642. *o_bstrPath = bstrPath.Detach();
  643. break;
  644. }
  645. NetApiBufferFree(pShareInfo);
  646. }
  647. return(hr);
  648. }
  649. void FreeNetNameList(NETNAMELIST *pList)
  650. {
  651. if (pList && !pList->empty()) {
  652. for (NETNAMELIST::iterator i = pList->begin(); i != pList->end(); i++)
  653. delete (*i);
  654. pList->clear();
  655. }
  656. }
  657. void FreeRootInfoList(ROOTINFOLIST *pList)
  658. {
  659. if (pList && !pList->empty()) {
  660. for (ROOTINFOLIST::iterator i = pList->begin(); i != pList->end(); i++)
  661. delete (*i);
  662. pList->clear();
  663. }
  664. }
  665. void FreeSubscriberList(SUBSCRIBERLIST *pList)
  666. {
  667. if (pList && !pList->empty()) {
  668. for (SUBSCRIBERLIST::iterator i = pList->begin(); i != pList->end(); i++)
  669. delete (*i);
  670. pList->clear();
  671. }
  672. }
  673. HRESULT GetLocalComputerName(OUT BSTR* o_pbstrComputerName)
  674. {
  675. _ASSERT(o_pbstrComputerName);
  676. DWORD dwErr = 0;
  677. TCHAR szBuffer[DNS_MAX_NAME_BUFFER_LENGTH];
  678. DWORD dwSize = DNS_MAX_NAME_BUFFER_LENGTH;
  679. if ( !GetComputerNameEx(ComputerNameDnsFullyQualified, szBuffer, &dwSize) )
  680. {
  681. dwSize = DNS_MAX_NAME_BUFFER_LENGTH;
  682. if ( !GetComputerNameEx(ComputerNameNetBIOS, szBuffer, &dwSize) )
  683. dwErr = GetLastError();
  684. }
  685. if (0 == dwErr)
  686. {
  687. *o_pbstrComputerName = SysAllocString(szBuffer);
  688. if (!*o_pbstrComputerName)
  689. dwErr = ERROR_OUTOFMEMORY;
  690. }
  691. return HRESULT_FROM_WIN32(dwErr);
  692. }
  693. HRESULT
  694. GetDomainDfsRoots(
  695. OUT NETNAMELIST* o_pDfsRootList,
  696. IN LPCTSTR i_lpszDomainName
  697. )
  698. {
  699. HRESULT hr = S_OK;
  700. FreeNetNameList(o_pDfsRootList);
  701. do {
  702. DFS_INFO_200 *pBuffer = NULL;
  703. DWORD dwEntriesRead = 0;
  704. DWORD dwResumeHandle = 0;
  705. DWORD dwErr = NetDfsEnum(
  706. const_cast<LPTSTR>(i_lpszDomainName),
  707. 200, // Level,
  708. (DWORD)-1, // PrefMaxLen,
  709. (LPBYTE *)&pBuffer,
  710. &dwEntriesRead,
  711. &dwResumeHandle
  712. );
  713. dfsDebugOut((_T("NetDfsEnum domain=%s, level 200 for GetDomainDfsRoots, nRet=%d\n"),
  714. i_lpszDomainName, dwErr));
  715. if (NERR_Success != dwErr)
  716. {
  717. hr = (ERROR_NO_MORE_ITEMS == dwErr || ERROR_NOT_FOUND == dwErr) ? S_FALSE : HRESULT_FROM_WIN32(dwErr);
  718. break;
  719. } else if (0 == dwEntriesRead)
  720. {
  721. if (pBuffer)
  722. NetApiBufferFree(pBuffer);
  723. hr = S_FALSE;
  724. break;
  725. }
  726. NETNAME *pCurrent = NULL;
  727. for (DWORD i = 0; i < dwEntriesRead; i++)
  728. {
  729. pCurrent = new NETNAME;
  730. if (!pCurrent)
  731. {
  732. hr = E_OUTOFMEMORY;
  733. break;
  734. }
  735. pCurrent->bstrNetName = pBuffer[i].FtDfsName;
  736. if (!pCurrent->bstrNetName)
  737. {
  738. delete pCurrent;
  739. hr = E_OUTOFMEMORY;
  740. break;
  741. }
  742. o_pDfsRootList->push_back(pCurrent);
  743. }
  744. NetApiBufferFree(pBuffer);
  745. } while (0);
  746. if (FAILED(hr))
  747. FreeNetNameList(o_pDfsRootList);
  748. return hr;
  749. }
  750. HRESULT
  751. GetMultiDfsRoots(
  752. OUT ROOTINFOLIST* o_pDfsRootList,
  753. IN LPCTSTR i_lpszScope
  754. )
  755. {
  756. if (!i_lpszScope || !*i_lpszScope)
  757. return E_INVALIDARG;
  758. HRESULT hr = S_OK;
  759. FreeRootInfoList(o_pDfsRootList);
  760. do {
  761. DFS_INFO_300 *pBuffer = NULL;
  762. DWORD dwEntriesRead = 0;
  763. DWORD dwResumeHandle = 0;
  764. DWORD dwErr = NetDfsEnum(
  765. const_cast<LPTSTR>(i_lpszScope),
  766. 300, // Level,
  767. (DWORD)-1, // PrefMaxLen,
  768. (LPBYTE *)&pBuffer,
  769. &dwEntriesRead,
  770. &dwResumeHandle
  771. );
  772. dfsDebugOut((_T("NetDfsEnum scope=%s, level 300 for GetMultiDfsRoots, nRet=%d\n"),
  773. i_lpszScope, dwErr));
  774. if (NERR_Success != dwErr)
  775. {
  776. hr = (ERROR_NO_MORE_ITEMS == dwErr || ERROR_NOT_FOUND == dwErr) ? S_FALSE : HRESULT_FROM_WIN32(dwErr);
  777. break;
  778. } else if (0 == dwEntriesRead)
  779. {
  780. if (pBuffer)
  781. NetApiBufferFree(pBuffer);
  782. hr = S_FALSE;
  783. break;
  784. }
  785. ROOTINFO *pCurrent = NULL;
  786. for (DWORD i = 0; i < dwEntriesRead; i++)
  787. {
  788. pCurrent = new ROOTINFO;
  789. if (pCurrent)
  790. {
  791. if ((pBuffer[i].Flags & DFS_VOLUME_FLAVORS) == DFS_VOLUME_FLAVOR_AD_BLOB)
  792. pCurrent->enumRootType = DFS_TYPE_FTDFS;
  793. else
  794. pCurrent->enumRootType = DFS_TYPE_STANDALONE;
  795. pCurrent->bstrRootName = _T("\\");
  796. pCurrent->bstrRootName += pBuffer[i].DfsName;
  797. }
  798. if (!pCurrent)
  799. {
  800. hr = E_OUTOFMEMORY;
  801. break;
  802. }
  803. if (!pCurrent->bstrRootName)
  804. {
  805. delete pCurrent;
  806. hr = E_OUTOFMEMORY;
  807. break;
  808. }
  809. o_pDfsRootList->push_back(pCurrent);
  810. }
  811. NetApiBufferFree(pBuffer);
  812. } while (0);
  813. if (FAILED(hr))
  814. FreeRootInfoList(o_pDfsRootList);
  815. return hr;
  816. }
  817. /*
  818. bool
  819. IsDfsPath
  820. (
  821. LPTSTR i_lpszNetPath
  822. )
  823. {
  824. if ( S_OK != CheckUNCPath(i_lpszNetPath) )
  825. return false;
  826. CComBSTR bstrPath = i_lpszNetPath;
  827. if (!bstrPath)
  828. return false; // out of memory
  829. TCHAR *s = _tcschr(bstrPath + 2, _T('\\')); // points to the 3rd backslash
  830. TCHAR *p = bstrPath + bstrPath.Length(); // points to the ending char '\0'
  831. bool bIsDfsPath = false;
  832. do
  833. {
  834. *p = _T('\0');
  835. PDFS_INFO_1 pDfsInfo1 = NULL;
  836. DWORD dwStatus = NetDfsGetClientInfo (
  837. bstrPath, // dir path as entrypath
  838. NULL, // No server name required
  839. NULL, // No share required
  840. 1, // level 1
  841. (LPBYTE *)&pDfsInfo1 // out buffer.
  842. );
  843. if (NERR_Success == dwStatus)
  844. {
  845. bIsDfsPath = true;
  846. NetApiBufferFree(pDfsInfo1);
  847. break;
  848. }
  849. p--;
  850. while (_T('\\') != *p && p > s)
  851. {
  852. p--;
  853. }
  854. } while (p > s);
  855. return bIsDfsPath;
  856. }
  857. */
  858. HRESULT CheckUNCPath(
  859. IN LPCTSTR i_lpszPath
  860. )
  861. /*++
  862. Routine Description:
  863. Checks if path is of UNC format.
  864. --*/
  865. {
  866. //"someserver\someshare\somedir\.." - Invalid
  867. //"\\Server - Invalid
  868. //"\\someserver\someshare\.. - Valid
  869. //"\\someserver\someshare\Somedir\.. - Valid
  870. RETURN_INVALIDARG_IF_NULL(i_lpszPath);
  871. DWORD dwRetFlags = 0;
  872. NET_API_STATUS nStatus = I_NetPathType(NULL, (LPTSTR)i_lpszPath, &dwRetFlags, 0);
  873. if (NERR_Success != nStatus)
  874. return HRESULT_FROM_WIN32(nStatus);
  875. return (ITYPE_UNC == dwRetFlags) ? S_OK : S_FALSE;
  876. }
  877. HRESULT GetUNCPathComponent(
  878. IN LPCTSTR i_lpszPath,
  879. OUT BSTR* o_pbstrComponent,
  880. IN UINT i_nStartBackslashes, // index starting from 1
  881. IN UINT i_nEndBackslashes // index starting from 1
  882. )
  883. {
  884. RETURN_INVALIDARG_IF_NULL(o_pbstrComponent);
  885. RETURN_INVALIDARG_IF_TRUE(i_nStartBackslashes < 2);
  886. RETURN_INVALIDARG_IF_TRUE(0 != i_nEndBackslashes && i_nEndBackslashes <= i_nStartBackslashes);
  887. *o_pbstrComponent = NULL;
  888. /* bug#587178
  889. HRESULT hr = CheckUNCPath(i_lpszPath);
  890. RETURN_INVALIDARG_IF_TRUE(S_OK != hr);
  891. */
  892. HRESULT hr = S_OK;
  893. UINT nDeltaBackslashes = i_nEndBackslashes ? (i_nEndBackslashes - i_nStartBackslashes) : 0;
  894. TCHAR *p = (LPTSTR)i_lpszPath + 2; // skip the first 2 backslashes
  895. i_nStartBackslashes -= 2;
  896. // locate the starting backslash
  897. while (*p && i_nStartBackslashes)
  898. {
  899. if (_T('\\') == *p)
  900. i_nStartBackslashes--;
  901. p++;
  902. }
  903. if (!*p)
  904. return hr;
  905. // locate the ending backslash
  906. TCHAR *s = p;
  907. if (!nDeltaBackslashes)
  908. {
  909. s += _tcslen(p);
  910. } else
  911. {
  912. while (*s && nDeltaBackslashes)
  913. {
  914. if (_T('\\') == *s)
  915. nDeltaBackslashes--;
  916. s++;
  917. }
  918. if (*s)
  919. s--;
  920. }
  921. // p points at the first char after the starting backslash, and
  922. // s points at the ending backslash or the ending char '\0'
  923. *o_pbstrComponent = SysAllocStringLen(p, s - p);
  924. RETURN_OUTOFMEMORY_IF_NULL(*o_pbstrComponent);
  925. return S_OK;
  926. }
  927. // return TRUE if string matches the filter string, case-insensitive match
  928. BOOL FilterMatch(LPCTSTR lpszString, FILTERDFSLINKS_TYPE lLinkFilterType, LPCTSTR lpszFilter)
  929. {
  930. BOOL bResult = TRUE;
  931. switch (lLinkFilterType)
  932. {
  933. case FILTERDFSLINKS_TYPE_BEGINWITH:
  934. if (!lpszString || !lpszFilter)
  935. return FALSE;
  936. bResult = !mylstrncmpi(lpszString, lpszFilter, lstrlen(lpszFilter));
  937. break;
  938. case FILTERDFSLINKS_TYPE_CONTAIN:
  939. {
  940. if (!lpszString || !lpszFilter)
  941. return FALSE;
  942. TCHAR* pszStringLower = _tcsdup(lpszString);
  943. TCHAR* pszFilterLower = _tcsdup(lpszFilter);
  944. if (!pszStringLower || !pszFilterLower)
  945. bResult = FALSE;
  946. else
  947. bResult = (NULL != _tcsstr(_tcslwr(pszStringLower), _tcslwr(pszFilterLower)));
  948. if (pszStringLower)
  949. free(pszStringLower);
  950. if (pszFilterLower)
  951. free(pszFilterLower);
  952. }
  953. break;
  954. default:
  955. break;
  956. }
  957. return bResult;
  958. }
  959. HRESULT IsHostingDfsRoot(IN BSTR i_bstrServer, OUT BSTR* o_pbstrRootEntryPath)
  960. {
  961. if (o_pbstrRootEntryPath)
  962. *o_pbstrRootEntryPath = NULL;
  963. DWORD dwEntriesRead = 0;
  964. DWORD dwResumeHandle = 0;
  965. DFS_INFO_1* pDfsInfoLevel1 = NULL;
  966. NET_API_STATUS dwRet = NetDfsEnum(
  967. i_bstrServer,
  968. 1,
  969. sizeof(DFS_INFO_1), // get 1 entry
  970. (LPBYTE *)&pDfsInfoLevel1,
  971. &dwEntriesRead,
  972. &dwResumeHandle
  973. );
  974. dfsDebugOut((_T("NetDfsEnum server=%s, level 1 for IsHostingDfsRoot, nRet=%d\n"),
  975. i_bstrServer,dwRet));
  976. if (NERR_Success != dwRet)
  977. {
  978. return (ERROR_NO_MORE_ITEMS == dwRet || ERROR_NOT_FOUND == dwRet) ? S_FALSE : HRESULT_FROM_WIN32(dwRet);
  979. } else if (0 == dwEntriesRead)
  980. {
  981. if (pDfsInfoLevel1)
  982. NetApiBufferFree(pDfsInfoLevel1);
  983. return S_FALSE;
  984. }
  985. HRESULT hr = S_OK;
  986. if (o_pbstrRootEntryPath)
  987. {
  988. *o_pbstrRootEntryPath = SysAllocString(pDfsInfoLevel1->EntryPath);
  989. if (!*o_pbstrRootEntryPath)
  990. hr = E_OUTOFMEMORY;
  991. }
  992. NetApiBufferFree(pDfsInfoLevel1);
  993. return hr;
  994. }
  995. /*
  996. void GetTimeDelta(LPCTSTR str, SYSTEMTIME* ptime0, SYSTEMTIME* ptime1)
  997. {
  998. dfsDebugOut((_T("%s, delta = %d millisec \n"), str,
  999. ((ptime1->wMinute - ptime0->wMinute) * 60 +
  1000. (ptime1->wSecond - ptime0->wSecond)) * 1000 +
  1001. (ptime1->wMilliseconds - ptime0->wMilliseconds)
  1002. ));
  1003. }
  1004. */