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.

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