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.

1355 lines
32 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Abstract:
  4. This module provides utilities useful for Directory Service interactions
  5. Author:
  6. Steve Wilson (NT) November 1997
  7. Revision History:
  8. --*/
  9. #define INC_OLE2
  10. #include "precomp.h"
  11. #pragma hdrstop
  12. #include "client.h"
  13. #include "pubprn.hxx"
  14. #include "varconv.hxx"
  15. #include "property.hxx"
  16. #include "dsutil.hxx"
  17. #include "winsprlp.h"
  18. #include "dnsapi.h"
  19. #define DN_SPECIAL_CHARS L",=\r\n+<>#;\"\\"
  20. #define DN_SPECIAL_FILTER_CHARS L"\\*()"
  21. PWSTR
  22. GetUNCName(
  23. HANDLE hPrinter
  24. )
  25. {
  26. PPRINTER_INFO_2 pInfo2 = NULL;
  27. DWORD cbNeeded;
  28. PWSTR pszUNCName = NULL;
  29. if (!GetPrinter(hPrinter, 2, (PBYTE) pInfo2, 0, &cbNeeded)) {
  30. if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
  31. goto error;
  32. }
  33. if (!(pInfo2 = (PPRINTER_INFO_2) AllocSplMem(cbNeeded)))
  34. goto error;
  35. if (!GetPrinter(hPrinter, 2, (PBYTE) pInfo2, cbNeeded, &cbNeeded))
  36. goto error;
  37. // pPrinterName is already in correct UNC format since we
  38. // opened handle with UNC name: just copy it
  39. cbNeeded = wcslen(pInfo2->pPrinterName) + 1;
  40. cbNeeded *= sizeof(WCHAR);
  41. if (!(pszUNCName = (PWSTR) AllocSplMem(cbNeeded)))
  42. goto error;
  43. wcscpy(pszUNCName, pInfo2->pPrinterName);
  44. error:
  45. if (pInfo2)
  46. FreeSplMem(pInfo2);
  47. return pszUNCName;
  48. }
  49. PWSTR
  50. CreateEscapedDN(
  51. PCWSTR pszIn
  52. )
  53. {
  54. PWSTR psz, pszO;
  55. PWSTR pszOut = NULL;
  56. DWORD cb;
  57. // Count special characters
  58. for (cb = 0, psz = (PWSTR) pszIn ; psz = wcspbrk(psz, DN_SPECIAL_FILTER_CHARS) ; ++cb, ++psz)
  59. ;
  60. // Add in length of input string
  61. // 2 = (\5c) - '\'
  62. cb = (wcslen(pszIn) + cb*2 + 1)*sizeof *pszIn;
  63. // Allocate output buffer and replace special chars with \HexEquivalent
  64. // Ex: replace \ with \5c , ( with \28
  65. if (pszOut = (PWSTR) AllocSplMem(cb)) {
  66. for(psz = (PWSTR) pszIn, pszO = pszOut ; *psz ; ++psz) {
  67. if (wcschr(DN_SPECIAL_FILTER_CHARS, *psz)) {
  68. pszO += wsprintf(pszO, L"\\%x", *psz);
  69. } else {
  70. *pszO++ = *psz;
  71. }
  72. }
  73. *pszO = L'\0';
  74. }
  75. return pszOut;
  76. }
  77. DWORD
  78. PrintQueueExists(
  79. HWND hwnd,
  80. HANDLE hPrinter,
  81. PWSTR pszUNCName,
  82. DWORD dwAction,
  83. PWSTR pszTargetDN,
  84. PWSTR *ppszObjectDN
  85. )
  86. {
  87. HRESULT hr = S_OK;
  88. DWORD dwRet = ERROR_SUCCESS;
  89. WCHAR szSearchPattern[MAX_UNC_PRINTER_NAME + 50];
  90. WCHAR szFullUNCName[MAX_UNC_PRINTER_NAME];
  91. PWSTR pNames[2];
  92. WCHAR szName[MAX_PATH + 1];
  93. WCHAR szDuplicateFormat[1024];
  94. PWSTR pszSearchRoot = NULL;
  95. PWSTR pszDuplicate = NULL;
  96. PWSTR pszUNCNameSearch = NULL;
  97. IDirectorySearch *pDSSearch = NULL;
  98. DS_NAME_RESULT *pDNR = NULL;
  99. DOMAIN_CONTROLLER_INFO *pDCI = NULL;
  100. HANDLE hDS = NULL;
  101. ADS_SEARCH_HANDLE hSearchHandle = NULL;
  102. ADS_SEARCH_COLUMN ADsPath;
  103. ADS_SEARCH_COLUMN UNCName;
  104. PWSTR pszAttributes[] = {L"ADsPath", L"UNCName"};
  105. DWORD nSize;
  106. BOOL bRet = FALSE;
  107. BOOL bDeleteDuplicate;
  108. PDSROLE_PRIMARY_DOMAIN_INFO_BASIC pDsRole = NULL;
  109. dwRet = DsRoleGetPrimaryDomainInformation(NULL, DsRolePrimaryDomainInfoBasic, (PBYTE *) &pDsRole);
  110. if (dwRet != ERROR_SUCCESS)
  111. goto error;
  112. wsprintf(szName, L"%ws\\", pDsRole->DomainNameFlat);
  113. pNames[0] = szName;
  114. pNames[1] = NULL;
  115. dwRet = Bind2DS(&hDS, &pDCI, DS_GC_SERVER_REQUIRED);
  116. if (dwRet != ERROR_SUCCESS)
  117. goto error;
  118. if (!(DsCrackNames(
  119. hDS,
  120. DS_NAME_NO_FLAGS,
  121. DS_UNKNOWN_NAME,
  122. DS_FQDN_1779_NAME,
  123. 1,
  124. &pNames[0],
  125. &pDNR) == ERROR_SUCCESS)) {
  126. dwRet = GetLastError();
  127. goto error;
  128. }
  129. if (pDNR->rItems[0].status != DS_NAME_NO_ERROR) {
  130. if (pDNR->rItems[0].status == DS_NAME_ERROR_RESOLVING)
  131. dwRet = ERROR_PATH_NOT_FOUND;
  132. else
  133. dwRet = pDNR->rItems[0].status;
  134. goto error;
  135. }
  136. // GC:// + pDCName + 1
  137. nSize = (wcslen(pDNR->rItems[0].pName) + 6)*sizeof(WCHAR);
  138. if (!(pszSearchRoot = (PWSTR) AllocSplMem(nSize))) {
  139. dwRet = GetLastError();
  140. goto error;
  141. }
  142. wsprintf(pszSearchRoot, L"GC://%ws", pDNR->rItems[0].pName);
  143. hr = ADsGetObject( pszSearchRoot,
  144. IID_IDirectorySearch,
  145. (void **)&pDSSearch);
  146. BAIL_ON_FAILURE(hr);
  147. if (!(pszUNCNameSearch = CreateEscapedDN(pszUNCName))) {
  148. dwRet = GetLastError();
  149. goto error;
  150. }
  151. wsprintf(szSearchPattern, L"(&(objectClass=printQueue)(uNCName=%ws))", pszUNCNameSearch);
  152. hr = pDSSearch->ExecuteSearch(
  153. szSearchPattern,
  154. pszAttributes,
  155. sizeof(pszAttributes)/sizeof *pszAttributes,
  156. &hSearchHandle);
  157. BAIL_ON_FAILURE(hr);
  158. hr = pDSSearch->GetNextRow(hSearchHandle);
  159. BAIL_ON_FAILURE(hr);
  160. while (hr != S_ADS_NOMORE_ROWS) {
  161. hr = pDSSearch->GetColumn(
  162. hSearchHandle,
  163. L"ADsPath",
  164. &ADsPath
  165. );
  166. if (hr == S_OK) {
  167. hr = pDSSearch->GetColumn(
  168. hSearchHandle,
  169. L"UNCName",
  170. &UNCName
  171. );
  172. if (hr == S_OK) {
  173. switch (dwAction) {
  174. case PUBLISHPRINTER_QUERY:
  175. if (!LoadString(hInst, IDS_DUPLICATE_PRINTQUEUE, szDuplicateFormat, COUNTOF(szDuplicateFormat))) {
  176. dwRet = GetLastError();
  177. goto error;
  178. }
  179. nSize = wcslen(szDuplicateFormat);
  180. nSize += wcslen(ADsPath.pADsValues->DNString);
  181. nSize += wcslen(pszTargetDN);
  182. nSize = (nSize + 1)*sizeof(WCHAR);
  183. if (!(pszDuplicate = (PWSTR) AllocSplMem(nSize))) {
  184. dwRet = GetLastError();
  185. goto error;
  186. }
  187. PWSTR pszCanonicalSource;
  188. PWSTR pszCanonicalTarget;
  189. pszCanonicalSource = pszCanonicalTarget = NULL;
  190. FQDN2Canonical(ADsPath.pADsValues->DNString, &pszCanonicalSource);
  191. FQDN2Canonical(pszTargetDN, &pszCanonicalTarget);
  192. if (!pszCanonicalSource || !pszCanonicalTarget) {
  193. wsprintf(pszDuplicate, szDuplicateFormat, ADsPath.pADsValues->DNString, pszTargetDN);
  194. } else {
  195. wsprintf(pszDuplicate, szDuplicateFormat, pszCanonicalSource, pszCanonicalTarget);
  196. }
  197. FreeSplStr(pszCanonicalSource);
  198. FreeSplStr(pszCanonicalTarget);
  199. if (!LoadString(hInst, IDS_DUPLICATE_PRINTQUEUE_TITLE, szDuplicateFormat, COUNTOF(szDuplicateFormat)))
  200. goto error;
  201. dwRet = MessageBox( hwnd,
  202. pszDuplicate,
  203. szDuplicateFormat,
  204. MB_YESNO);
  205. bDeleteDuplicate = (dwRet == IDYES);
  206. dwRet = (dwRet == IDYES) ? ERROR_SUCCESS : ERROR_CANCELLED;
  207. pszDuplicate = NULL;
  208. break;
  209. case PUBLISHPRINTER_DELETE_DUPLICATES:
  210. bDeleteDuplicate = TRUE;
  211. break;
  212. case PUBLISHPRINTER_FAIL_ON_DUPLICATE:
  213. bDeleteDuplicate = FALSE;
  214. if (ppszObjectDN) {
  215. if (!(*ppszObjectDN = AllocGlobalStr(ADsPath.pADsValues->DNString))) {
  216. dwRet = GetLastError();
  217. goto error;
  218. }
  219. }
  220. dwRet = ERROR_FILE_EXISTS;
  221. break;
  222. case PUBLISHPRINTER_IGNORE_DUPLICATES:
  223. bDeleteDuplicate = FALSE;
  224. break;
  225. default:
  226. bDeleteDuplicate = FALSE;
  227. dwRet = ERROR_INVALID_PARAMETER;
  228. break;
  229. }
  230. if (bDeleteDuplicate) {
  231. hr = DeleteDSObject(ADsPath.pADsValues->DNString);
  232. if ( hr == ERROR_DS_NO_SUCH_OBJECT ) {
  233. hr = S_OK;
  234. }
  235. }
  236. pDSSearch->FreeColumn(&UNCName);
  237. }
  238. pDSSearch->FreeColumn(&ADsPath);
  239. }
  240. if (dwRet != ERROR_SUCCESS || hr != S_OK)
  241. goto error;
  242. hr = pDSSearch->GetNextRow(hSearchHandle);
  243. BAIL_ON_FAILURE(hr);
  244. }
  245. hr = S_OK;
  246. error:
  247. if (hr != S_OK)
  248. dwRet = ERROR_DS_UNAVAILABLE;
  249. if (pDsRole)
  250. DsRoleFreeMemory((PVOID) pDsRole);
  251. if (pDNR)
  252. DsFreeNameResult(pDNR);
  253. if (hDS)
  254. DsUnBind(&hDS);
  255. if (pDCI)
  256. NetApiBufferFree(pDCI);
  257. if (hSearchHandle)
  258. pDSSearch->CloseSearchHandle(hSearchHandle);
  259. if (pszUNCNameSearch)
  260. FreeSplMem(pszUNCNameSearch);
  261. if (pDSSearch)
  262. pDSSearch->Release();
  263. if (pszSearchRoot)
  264. FreeSplMem(pszSearchRoot);
  265. if(pszDuplicate)
  266. FreeSplMem(pszDuplicate);
  267. return dwRet;
  268. }
  269. DWORD
  270. MovePrintQueue(
  271. PCWSTR pszObjectGUID,
  272. PCWSTR pszNewContainer, // Container path
  273. PCWSTR pszNewCN // Object CN
  274. )
  275. {
  276. PWSTR pszCurrentContainer = NULL;
  277. PWSTR pszCurrentCN = NULL;
  278. HRESULT hr;
  279. IADsContainer *pADsContainer = NULL;
  280. IDispatch *pNewObject = NULL;
  281. // Get PublishPoint from GUID
  282. hr = GetPublishPointFromGUID(pszObjectGUID, &pszCurrentContainer, &pszCurrentCN);
  283. BAIL_ON_FAILURE(hr);
  284. if (pszCurrentContainer) {
  285. // Get container
  286. hr = ADsGetObject( pszCurrentContainer, IID_IADsContainer, (void **) &pADsContainer);
  287. BAIL_ON_FAILURE(hr);
  288. // Move PrintQueue
  289. if (wcscmp(pszCurrentContainer, pszNewContainer)) {
  290. hr = pADsContainer->MoveHere((PWSTR) pszNewContainer, (PWSTR) pszNewCN, &pNewObject);
  291. BAIL_ON_FAILURE(hr);
  292. }
  293. }
  294. error:
  295. if (pszCurrentContainer)
  296. FreeSplMem(pszCurrentContainer);
  297. if (pszCurrentCN)
  298. FreeSplMem(pszCurrentCN);
  299. if (pADsContainer)
  300. pADsContainer->Release();
  301. if (pNewObject)
  302. pNewObject->Release();
  303. return hr;
  304. }
  305. HRESULT
  306. GetPublishPointFromGUID(
  307. PCWSTR pszObjectGUID,
  308. PWSTR *ppszDN,
  309. PWSTR *ppszCN
  310. )
  311. {
  312. DWORD dwRet, nBytes, nChars;
  313. PWSTR pNames[2];
  314. DS_NAME_RESULT *pDNR = NULL;
  315. DOMAIN_CONTROLLER_INFO *pDCI = NULL;
  316. HANDLE hDS = NULL;
  317. PWSTR psz;
  318. HRESULT hr = S_OK;
  319. dwRet = Bind2DS(&hDS, &pDCI, DS_DIRECTORY_SERVICE_PREFERRED);
  320. if (dwRet != ERROR_SUCCESS)
  321. goto error;
  322. // Get Publish Point
  323. if (ppszDN) {
  324. pNames[0] = (PWSTR) pszObjectGUID;
  325. pNames[1] = NULL;
  326. if (!(DsCrackNames(
  327. hDS,
  328. DS_NAME_NO_FLAGS,
  329. DS_UNKNOWN_NAME,
  330. DS_FQDN_1779_NAME,
  331. 1,
  332. &pNames[0],
  333. &pDNR) == ERROR_SUCCESS)) {
  334. dwRet = GetLastError();
  335. goto error;
  336. }
  337. if (pDNR->rItems[0].status != DS_NAME_NO_ERROR) {
  338. if (pDNR->rItems[0].status == DS_NAME_ERROR_RESOLVING)
  339. dwRet = ERROR_PATH_NOT_FOUND;
  340. else
  341. dwRet = pDNR->rItems[0].status;
  342. goto error;
  343. }
  344. // Separate DN into CN & PublishPoint
  345. // pDNR has form: CN=CommonName,DN...
  346. hr = FQDN2CNDN(pDCI->DomainControllerName + 2, pDNR->rItems[0].pName, ppszCN, ppszDN);
  347. BAIL_ON_FAILURE(hr);
  348. }
  349. error:
  350. if (pDNR)
  351. DsFreeNameResult(pDNR);
  352. if (hDS)
  353. DsUnBind(&hDS);
  354. if (pDCI)
  355. NetApiBufferFree(pDCI);
  356. if (dwRet != ERROR_SUCCESS) {
  357. hr = MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, dwRet);
  358. }
  359. if (FAILED(hr)) {
  360. FreeSplMem(*ppszCN);
  361. FreeSplMem(*ppszDN);
  362. *ppszCN = *ppszDN = NULL;
  363. }
  364. return hr;
  365. }
  366. DWORD
  367. Bind2DS(
  368. HANDLE *phDS,
  369. DOMAIN_CONTROLLER_INFO **ppDCI,
  370. ULONG Flags
  371. )
  372. {
  373. DWORD dwRet;
  374. dwRet = DsGetDcName(NULL, NULL, NULL, NULL, Flags, ppDCI);
  375. if (dwRet == ERROR_SUCCESS) {
  376. if ((*ppDCI)->Flags & DS_DS_FLAG) {
  377. dwRet = DsBind (NULL, (*ppDCI)->DomainName, phDS);
  378. if (dwRet != ERROR_SUCCESS) {
  379. NetApiBufferFree(*ppDCI);
  380. *ppDCI = NULL;
  381. if (!(Flags & DS_FORCE_REDISCOVERY)) {
  382. dwRet = Bind2DS(phDS, ppDCI, DS_FORCE_REDISCOVERY | Flags);
  383. }
  384. }
  385. } else {
  386. NetApiBufferFree(*ppDCI);
  387. *ppDCI = NULL;
  388. dwRet = ERROR_CANT_ACCESS_DOMAIN_INFO;
  389. }
  390. }
  391. return dwRet;
  392. }
  393. HRESULT
  394. FQDN2CNDN(
  395. PWSTR pszDCName,
  396. PWSTR pszFQDN,
  397. PWSTR *ppszCN,
  398. PWSTR *ppszDN
  399. )
  400. {
  401. IADs *pADs = NULL;
  402. PWSTR pszCN = NULL;
  403. PWSTR pszDN = NULL;
  404. PWSTR pszLDAPPath = NULL;
  405. HRESULT hr;
  406. // Get LDAP path to object
  407. hr = BuildLDAPPath(pszDCName, pszFQDN, &pszLDAPPath);
  408. BAIL_ON_FAILURE(hr);
  409. // Get DN
  410. hr = ADsGetObject(pszLDAPPath, IID_IADs, (void **) &pADs);
  411. BAIL_ON_FAILURE(hr);
  412. hr = pADs->get_Parent(&pszDN);
  413. BAIL_ON_FAILURE(hr);
  414. if (!(*ppszDN = AllocSplStr(pszDN))) {
  415. hr = MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, GetLastError());
  416. BAIL_ON_FAILURE(hr);
  417. }
  418. // Get CN
  419. hr = pADs->get_Name(&pszCN);
  420. BAIL_ON_FAILURE(hr);
  421. if (!(*ppszCN = AllocSplStr(pszCN))) {
  422. hr = MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, GetLastError());
  423. BAIL_ON_FAILURE(hr);
  424. }
  425. error:
  426. if (pADs)
  427. pADs->Release();
  428. if (pszCN)
  429. SysFreeString(pszCN);
  430. if (pszDN)
  431. SysFreeString(pszDN);
  432. FreeSplStr(pszLDAPPath);
  433. if (FAILED(hr)) {
  434. FreeSplStr(*ppszCN);
  435. FreeSplStr(*ppszDN);
  436. }
  437. return hr;
  438. }
  439. HRESULT
  440. BuildLDAPPath(
  441. PWSTR pszDC,
  442. PWSTR pszFQDN,
  443. PWSTR *ppszLDAPPath
  444. )
  445. {
  446. DWORD nBytes;
  447. HRESULT hr;
  448. // LDAP:// + pDCName + / + pName + 1
  449. nBytes = (wcslen(pszDC) + wcslen(pszFQDN) + 9)*sizeof(WCHAR);
  450. if (!(*ppszLDAPPath = (PWSTR) AllocSplMem(nBytes))) {
  451. hr = MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, GetLastError());
  452. BAIL_ON_FAILURE(hr);
  453. }
  454. wsprintf(*ppszLDAPPath, L"LDAP://%ws/%ws", pszDC,pszFQDN);
  455. error:
  456. return hr;
  457. }
  458. DWORD
  459. UNC2Printer(
  460. PCWSTR pszUNC,
  461. PWSTR *ppszPrinter
  462. )
  463. {
  464. PWSTR psz;
  465. if (!pszUNC || pszUNC[0] != L'\\' || pszUNC[1] != L'\\')
  466. return ERROR_INVALID_PARAMETER;
  467. if(!(psz = wcsrchr(pszUNC + 2, L'\\')))
  468. return ERROR_INVALID_PARAMETER;
  469. if (!(*ppszPrinter = (PWSTR) AllocSplStr(psz + 1)))
  470. return GetLastError();
  471. return ERROR_SUCCESS;
  472. }
  473. DWORD
  474. UNC2Server(
  475. PCWSTR pszUNC,
  476. PWSTR *ppszServer
  477. )
  478. {
  479. PWSTR psz;
  480. DWORD cb;
  481. DWORD nChars;
  482. if (!pszUNC || pszUNC[0] != L'\\' || pszUNC[1] != L'\\')
  483. return ERROR_INVALID_PARAMETER;
  484. if(!(psz = wcschr(pszUNC + 2, L'\\')))
  485. return ERROR_INVALID_PARAMETER;
  486. cb = (DWORD) ((ULONG_PTR) psz - (ULONG_PTR) pszUNC + sizeof *psz);
  487. if (!(*ppszServer = (PWSTR) AllocSplMem(cb)))
  488. return GetLastError();
  489. nChars = (DWORD) (psz - pszUNC);
  490. wcsncpy(*ppszServer, pszUNC, nChars);
  491. (*ppszServer)[nChars] = L'\0';
  492. return ERROR_SUCCESS;
  493. }
  494. // Utility routine to report if a printer is color or monochrome
  495. BOOL
  496. ThisIsAColorPrinter(
  497. LPCTSTR lpstrName
  498. )
  499. {
  500. HANDLE hPrinter = NULL;
  501. LPTSTR lpstrMe = const_cast <LPTSTR> (lpstrName);
  502. BOOL bReturn = FALSE;
  503. LPDEVMODE lpdm = NULL;
  504. long lcbNeeded;
  505. if (!OpenPrinter(lpstrMe, &hPrinter, NULL)) {
  506. goto error;
  507. }
  508. // First, use DocumentProperties to find the correct DEVMODE size- we
  509. // must use the DEVMODE to force color on, in case the user's defaults
  510. // have turned it off...
  511. lcbNeeded = DocumentProperties(NULL, hPrinter, lpstrMe, NULL, NULL, 0);
  512. if (lcbNeeded <= 0) {
  513. goto error;
  514. }
  515. lpdm = (LPDEVMODE) AllocSplMem(lcbNeeded);
  516. if (lpdm) {
  517. lpdm->dmSize = sizeof(DEVMODE);
  518. lpdm->dmFields = DM_COLOR;
  519. lpdm->dmColor = DMCOLOR_COLOR;
  520. if (IDOK == DocumentProperties(NULL, hPrinter, lpstrMe, lpdm, lpdm,
  521. DM_IN_BUFFER | DM_OUT_BUFFER)) {
  522. // Finally, we can create the DC!
  523. HDC hdcThis = CreateDC(NULL, lpstrName, NULL, lpdm);
  524. if (hdcThis) {
  525. bReturn = 2 < (unsigned) GetDeviceCaps(hdcThis, NUMCOLORS);
  526. DeleteDC(hdcThis);
  527. }
  528. }
  529. }
  530. error:
  531. FreeSplMem(lpdm);
  532. if (hPrinter)
  533. ClosePrinter(hPrinter);
  534. return bReturn;
  535. }
  536. HRESULT
  537. DeleteDSObject(
  538. PWSTR pszADsPath
  539. )
  540. {
  541. BSTR bstrCommonName = NULL;
  542. PWSTR pszParent = NULL;
  543. PWSTR pszCN = NULL;
  544. PWSTR pszLDAPPath = NULL;
  545. IADs *pADs = NULL;
  546. IADsContainer *pContainer = NULL;
  547. DWORD cb;
  548. HRESULT hr;
  549. DWORD nSize;
  550. if(pszADsPath && !_wcsnicmp(pszADsPath , L"GC://" , 5)){
  551. //
  552. // Build LDAP://..... path from GC://.... path
  553. // 3 comes from len(LDAP) - len(GC) + len(string_terminator)
  554. //
  555. nSize = (wcslen(pszADsPath) + 3)* sizeof(WCHAR);
  556. if (!(pszLDAPPath = (PWSTR) AllocSplMem(nSize))) {
  557. hr = MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, GetLastError());
  558. goto error;
  559. }
  560. wsprintf(pszLDAPPath, L"LDAP%ws", pszADsPath + 2);
  561. }
  562. // Get PrintQueue object
  563. hr = ADsGetObject(pszLDAPPath, IID_IADs, (void **) &pADs);
  564. BAIL_ON_FAILURE(hr);
  565. // Get the CommonName & don't forget the "CN="
  566. hr = get_BSTR_Property(pADs, L"cn", &bstrCommonName);
  567. BAIL_ON_FAILURE(hr);
  568. cb = (SysStringLen(bstrCommonName) + 4)*sizeof(WCHAR);
  569. if (!(pszCN = (PWSTR) AllocSplMem(cb))) {
  570. hr = dw2hr(GetLastError());
  571. BAIL_ON_FAILURE(hr);
  572. }
  573. wcscpy(pszCN, L"CN=");
  574. wcscat(pszCN, bstrCommonName);
  575. // Get the Parent ADsPath
  576. hr = pADs->get_Parent(&pszParent);
  577. BAIL_ON_FAILURE(hr);
  578. // Get the Parent object
  579. hr = ADsGetObject( pszParent,
  580. IID_IADsContainer,
  581. (void **) &pContainer);
  582. BAIL_ON_FAILURE(hr);
  583. // Delete the printqueue
  584. hr = pContainer->Delete(SPLDS_PRINTER_CLASS, pszCN);
  585. error:
  586. if (pADs)
  587. pADs->Release();
  588. if (pContainer)
  589. pContainer->Release();
  590. if (bstrCommonName)
  591. SysFreeString(bstrCommonName);
  592. if (pszParent)
  593. SysFreeString(pszParent);
  594. if (pszCN)
  595. FreeSplMem(pszCN);
  596. if(pszLDAPPath)
  597. FreeSplMem(pszLDAPPath);
  598. return hr;
  599. }
  600. DWORD
  601. GetCommonName(
  602. HANDLE hPrinter,
  603. PWSTR *ppszCommonName
  604. )
  605. {
  606. DWORD nBytes;
  607. PWSTR psz;
  608. PPRINTER_INFO_2 pInfo2 = NULL;
  609. DWORD cbNeeded;
  610. DWORD dwRet;
  611. PWSTR pszServerName, pszPrinterName;
  612. // Get Server & Share names
  613. if (!GetPrinter(hPrinter, 2, (PBYTE) pInfo2, 0, &cbNeeded)) {
  614. if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
  615. dwRet = GetLastError();
  616. goto error;
  617. }
  618. if (!(pInfo2 = (PPRINTER_INFO_2) AllocSplMem(cbNeeded))) {
  619. dwRet = GetLastError();
  620. goto error;
  621. }
  622. if (!GetPrinter(hPrinter, 2, (PBYTE) pInfo2, cbNeeded, &cbNeeded)) {
  623. dwRet = GetLastError();
  624. goto error;
  625. }
  626. pszServerName = pInfo2->pServerName;
  627. if (!pszServerName) {
  628. DBGMSG(DBG_ERROR,("GetPrinter returned NULL ServerName"));
  629. dwRet = ERROR_INVALID_DATA;
  630. goto error;
  631. }
  632. pszPrinterName = pInfo2->pShareName ? pInfo2->pShareName : pInfo2->pPrinterName;
  633. } else {
  634. // We should never get here. If we do, something is wrong
  635. // with the server and we have no meaningful error to report,
  636. // so just claim invalid data.
  637. DBGMSG(DBG_ERROR,("INVALID GetPrinter return"));
  638. dwRet = ERROR_INVALID_DATA;
  639. goto error;
  640. }
  641. // "CN=Server-Printer"
  642. nBytes = (wcslen(pszPrinterName) + wcslen(pszServerName) + 5)*sizeof(WCHAR);
  643. if (!(*ppszCommonName = psz = (PWSTR) AllocSplMem(nBytes))) {
  644. dwRet = GetLastError();
  645. goto error;
  646. }
  647. // CN=
  648. wcscpy(psz, L"CN=");
  649. // Server
  650. for(psz += 3, pszServerName += 2 ; *pszServerName ; ++psz, ++pszServerName) {
  651. *psz = wcschr(DN_SPECIAL_CHARS, *pszServerName) ? TEXT('_') : *pszServerName;
  652. }
  653. *psz = L'-';
  654. // Printer
  655. for(++psz; *pszPrinterName ; ++psz, ++pszPrinterName) {
  656. *psz = wcschr(DN_SPECIAL_CHARS, *pszPrinterName) ? TEXT('_') : *pszPrinterName;
  657. }
  658. // NULL
  659. *psz = *pszPrinterName;
  660. // DS only allows 64 characters in CN attribute, so shorten this if needed
  661. if (wcslen(pszPrinterName) > 62)
  662. pszPrinterName[63] = NULL;
  663. error:
  664. FreeSplMem(pInfo2);
  665. return ERROR_SUCCESS;
  666. }
  667. PWSTR
  668. AllocGlobalStr(
  669. PWSTR pszIn
  670. )
  671. {
  672. DWORD cb;
  673. PWSTR pszOut = NULL;
  674. if (!pszIn)
  675. return NULL;
  676. cb = (wcslen(pszIn) + 1)*sizeof *pszIn;
  677. if (pszOut = (PWSTR) GlobalAlloc(GMEM_FIXED, cb))
  678. wcscpy(pszOut, pszIn);
  679. return pszOut;
  680. }
  681. VOID
  682. FreeGlobalStr(
  683. PWSTR pszIn
  684. )
  685. {
  686. if (pszIn)
  687. GlobalFree(pszIn);
  688. }
  689. DWORD
  690. GetADsPathFromGUID(
  691. PCWSTR pszObjectGUID,
  692. PWSTR *ppszDN
  693. )
  694. {
  695. DWORD dwRet, nBytes, nChars;
  696. PWSTR pNames[2];
  697. DS_NAME_RESULT *pDNR = NULL;
  698. DOMAIN_CONTROLLER_INFO *pDCI = NULL;
  699. HANDLE hDS = NULL;
  700. PWSTR psz;
  701. dwRet = Bind2DS(&hDS, &pDCI, DS_DIRECTORY_SERVICE_PREFERRED);
  702. if (dwRet != ERROR_SUCCESS)
  703. goto error;
  704. // Get Publish Point
  705. if (ppszDN) {
  706. pNames[0] = (PWSTR) pszObjectGUID;
  707. pNames[1] = NULL;
  708. if (!(DsCrackNames(
  709. hDS,
  710. DS_NAME_NO_FLAGS,
  711. DS_UNKNOWN_NAME,
  712. DS_FQDN_1779_NAME,
  713. 1,
  714. &pNames[0],
  715. &pDNR) == ERROR_SUCCESS)) {
  716. dwRet = GetLastError();
  717. goto error;
  718. }
  719. if (pDNR->rItems[0].status != DS_NAME_NO_ERROR) {
  720. if (pDNR->rItems[0].status == DS_NAME_ERROR_RESOLVING)
  721. dwRet = ERROR_PATH_NOT_FOUND;
  722. else
  723. dwRet = pDNR->rItems[0].status;
  724. goto error;
  725. }
  726. // LDAP:// + pDCName + / + pName + 1
  727. nBytes = (wcslen(pDCI->DomainControllerName + 2) +
  728. wcslen(pDNR->rItems[0].pName) + 9)*sizeof(WCHAR);
  729. if (!(*ppszDN = (PWSTR) AllocSplMem(nBytes))) {
  730. dwRet = GetLastError();
  731. goto error;
  732. }
  733. wsprintf(*ppszDN, L"LDAP://%ws/%ws", pDCI->DomainControllerName + 2,pDNR->rItems[0].pName);
  734. }
  735. error:
  736. if (pDNR)
  737. DsFreeNameResult(pDNR);
  738. if (hDS)
  739. DsUnBind(&hDS);
  740. if (pDCI)
  741. NetApiBufferFree(pDCI);
  742. if (dwRet != ERROR_SUCCESS) {
  743. FreeSplMem(*ppszDN);
  744. *ppszDN = NULL;
  745. }
  746. return dwRet;
  747. }
  748. PWSTR
  749. GetDNWithServer(
  750. PCWSTR pszDNIn
  751. )
  752. {
  753. DOMAIN_CONTROLLER_INFO *pDCI = NULL;
  754. DWORD nBytes;
  755. PWSTR pszDNOut = NULL;
  756. DWORD dwRet;
  757. // Convert pszDNIn into a DN with the DC name, if it isn't already there
  758. // Check for existing DC name or badly formed name
  759. if (wcsncmp(pszDNIn, L"LDAP://", 7) || wcschr(pszDNIn + 7, L'/'))
  760. goto error;
  761. // Get DC name
  762. dwRet = DsGetDcName(NULL, NULL, NULL, NULL, 0, &pDCI);
  763. if (dwRet != ERROR_SUCCESS) {
  764. goto error;
  765. }
  766. // Build name
  767. // LDAP:// + pDCName + / + pName + 1
  768. nBytes = (wcslen(pDCI->DomainControllerName + 2) +
  769. wcslen(pszDNIn + 7) + 9)*sizeof(WCHAR);
  770. if (!(pszDNOut = (PWSTR) AllocSplMem(nBytes)))
  771. goto error;
  772. wsprintf(pszDNOut, L"LDAP://%ws/%ws", pDCI->DomainControllerName + 2,pszDNIn + 7);
  773. error:
  774. if (pDCI)
  775. NetApiBufferFree(pDCI);
  776. return pszDNOut;
  777. }
  778. DWORD
  779. hr2dw(
  780. HRESULT hr
  781. )
  782. {
  783. if (SUCCEEDED(hr))
  784. return ERROR_SUCCESS;
  785. if (HRESULT_FACILITY(hr) == FACILITY_WIN32)
  786. return HRESULT_CODE(hr);
  787. if (hr != HRESULT_FROM_WIN32(ERROR_OBJECT_ALREADY_EXISTS))
  788. return ERROR_DS_UNAVAILABLE;
  789. return hr;
  790. }
  791. PWSTR
  792. DelimString2MultiSz(
  793. PWSTR pszIn,
  794. WCHAR wcDelim
  795. )
  796. {
  797. DWORD cb;
  798. PWSTR pszOut = NULL;
  799. // pszIn looks like L"xxx,xxxx,xxx,xxx"
  800. // the output looks like L"xxx0xxxx0xxx0xxx00"
  801. // Replace all wcDelim characters with NULLs & add a NULL
  802. if (!pszIn || !*pszIn)
  803. return NULL;
  804. cb = (wcslen(pszIn) + 2)*sizeof *pszIn;
  805. pszOut = (PWSTR) AllocSplMem(cb);
  806. if (pszOut) {
  807. DWORD i;
  808. for (i = 0 ; pszIn[i] ; ++i) {
  809. pszOut[i] = (pszIn[i] == wcDelim) ? L'\0' : pszIn[i];
  810. }
  811. pszOut[i] = pszOut[i + 1] = L'\0';
  812. }
  813. return pszOut;
  814. }
  815. HRESULT
  816. GetPrinterInfo2(
  817. HANDLE hPrinter,
  818. PPRINTER_INFO_2 *ppInfo2
  819. )
  820. {
  821. HRESULT hr = S_OK;
  822. DWORD cbNeeded;
  823. // Get PRINTER_INFO_2 properties
  824. if (!GetPrinter(hPrinter, 2, (PBYTE) *ppInfo2, 0, &cbNeeded)) {
  825. if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
  826. hr = dw2hr(GetLastError());
  827. goto error;
  828. }
  829. if (!(*ppInfo2 = (PPRINTER_INFO_2) AllocSplMem(cbNeeded))) {
  830. hr = dw2hr(GetLastError());
  831. goto error;
  832. }
  833. if (!GetPrinter(hPrinter, 2, (PBYTE) *ppInfo2, cbNeeded, &cbNeeded)) {
  834. hr = dw2hr(GetLastError());
  835. goto error;
  836. }
  837. }
  838. error:
  839. return hr;
  840. }
  841. DWORD
  842. FQDN2Canonical(
  843. PWSTR pszIn,
  844. PWSTR *ppszOut
  845. )
  846. {
  847. DWORD dwRet = ERROR_SUCCESS;
  848. DS_NAME_RESULT *pDNR = NULL;
  849. PWSTR pNames[2];
  850. *ppszOut = NULL;
  851. if (wcslen(pszIn) < 8) {
  852. dwRet = ERROR_INVALID_PARAMETER;
  853. goto error;
  854. }
  855. pNames[0] = pszIn + 7; // Input string is LDAP://CN=... Strip off the LDAP:// portion
  856. pNames[1] = NULL;
  857. if (!(DsCrackNames(
  858. INVALID_HANDLE_VALUE,
  859. DS_NAME_FLAG_SYNTACTICAL_ONLY,
  860. DS_FQDN_1779_NAME,
  861. DS_CANONICAL_NAME,
  862. 1,
  863. &pNames[0],
  864. &pDNR) == ERROR_SUCCESS)) {
  865. dwRet = GetLastError();
  866. goto error;
  867. }
  868. if (pDNR->rItems[0].status != DS_NAME_NO_ERROR) {
  869. if (pDNR->rItems[0].status == DS_NAME_ERROR_RESOLVING)
  870. dwRet = ERROR_PATH_NOT_FOUND;
  871. else
  872. dwRet = pDNR->rItems[0].status;
  873. goto error;
  874. }
  875. *ppszOut = AllocSplStr(pDNR->rItems[0].pName);
  876. error:
  877. if (pDNR)
  878. DsFreeNameResult(pDNR);
  879. return dwRet;
  880. }
  881. BOOL
  882. DevCapMultiSz(
  883. PWSTR pszUNCName,
  884. IADs *pPrintQueue,
  885. WORD fwCapability,
  886. DWORD dwElementBytes,
  887. PWSTR pszAttributeName
  888. )
  889. {
  890. DWORD dwResult, cbBytes;
  891. PWSTR pszDevCapBuffer = NULL;
  892. PWSTR pszRegData = NULL;
  893. HRESULT hr;
  894. _try {
  895. dwResult = DeviceCapabilities( pszUNCName,
  896. NULL,
  897. fwCapability,
  898. NULL,
  899. NULL);
  900. if (dwResult != GDI_ERROR) {
  901. pszDevCapBuffer = (PWSTR) AllocSplMem(dwResult*dwElementBytes*sizeof(WCHAR));
  902. if (pszDevCapBuffer) {
  903. dwResult = DeviceCapabilities( pszUNCName,
  904. NULL,
  905. fwCapability,
  906. pszDevCapBuffer,
  907. NULL);
  908. if (dwResult != GDI_ERROR) {
  909. if (!(pszRegData = DevCapStrings2MultiSz(pszDevCapBuffer, dwResult, dwElementBytes, &cbBytes))) {
  910. dwResult = GDI_ERROR;
  911. }
  912. }
  913. } else {
  914. dwResult = GDI_ERROR;
  915. }
  916. }
  917. } _except(1) {
  918. SetLastError(GetExceptionCode());
  919. dwResult = GDI_ERROR;
  920. }
  921. if (dwResult != GDI_ERROR) {
  922. hr = PublishDsData( pPrintQueue,
  923. pszAttributeName,
  924. REG_MULTI_SZ,
  925. (PBYTE) pszRegData);
  926. if (FAILED(hr)) {
  927. SetLastError(HRESULT_CODE(hr));
  928. dwResult = GDI_ERROR;
  929. }
  930. }
  931. FreeSplStr(pszDevCapBuffer);
  932. FreeSplStr(pszRegData);
  933. return dwResult != GDI_ERROR;
  934. }
  935. PWSTR
  936. DevCapStrings2MultiSz(
  937. PWSTR pszDevCapString,
  938. DWORD nDevCapStrings,
  939. DWORD dwDevCapStringLength,
  940. DWORD *pcbBytes
  941. )
  942. {
  943. DWORD i, cbBytes, cbSize;
  944. PWSTR pszMultiSz = NULL;
  945. PWSTR pStr;
  946. if (!pszDevCapString || !pcbBytes)
  947. return NULL;
  948. *pcbBytes = 0;
  949. //
  950. // Devcap buffers may not be NULL terminated
  951. //
  952. cbBytes = (nDevCapStrings*(dwDevCapStringLength + 1) + 1)*sizeof(WCHAR);
  953. //
  954. // Allocate and copy
  955. //
  956. if (pszMultiSz = (PWSTR) AllocSplMem(cbBytes)) {
  957. for(i = 0, pStr = pszMultiSz, cbBytes = 0 ; i < nDevCapStrings ; ++i, pStr += cbSize, cbBytes +=cbSize ) {
  958. wcsncpy(pStr, pszDevCapString + i*dwDevCapStringLength, dwDevCapStringLength);
  959. cbSize = *pStr ? wcslen(pStr) + 1 : 0;
  960. }
  961. *pStr = L'\0';
  962. *pcbBytes = (cbBytes + 1) * sizeof(WCHAR);
  963. }
  964. return pszMultiSz;
  965. }
  966. HRESULT
  967. MachineIsInMyForest(
  968. PWSTR pszMachineName
  969. )
  970. {
  971. DWORD dwRet;
  972. HRESULT hr;
  973. PDSROLE_PRIMARY_DOMAIN_INFO_BASIC pMachineRole = NULL;
  974. PDSROLE_PRIMARY_DOMAIN_INFO_BASIC pMyRole = NULL;
  975. dwRet = DsRoleGetPrimaryDomainInformation( pszMachineName,
  976. DsRolePrimaryDomainInfoBasic,
  977. (PBYTE *) &pMachineRole);
  978. if (dwRet != ERROR_SUCCESS) {
  979. hr = MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, dwRet);
  980. goto error;
  981. }
  982. dwRet = DsRoleGetPrimaryDomainInformation( NULL,
  983. DsRolePrimaryDomainInfoBasic,
  984. (PBYTE *) &pMyRole);
  985. if (dwRet != ERROR_SUCCESS) {
  986. hr = MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, dwRet);
  987. goto error;
  988. }
  989. dwRet = DnsNameCompare_W(pMachineRole->DomainForestName, pMyRole->DomainForestName);
  990. hr = MAKE_HRESULT(SEVERITY_SUCCESS, FACILITY_WIN32, dwRet);
  991. error:
  992. if (pMachineRole)
  993. DsRoleFreeMemory((PVOID) pMachineRole);
  994. if (pMyRole)
  995. DsRoleFreeMemory((PVOID) pMyRole);
  996. return hr;
  997. }