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.

1501 lines
39 KiB

  1. /*++
  2. Copyright (c) 1990 - 1995 Microsoft Corporation
  3. Module Name:
  4. util.c
  5. Abstract:
  6. This module provides all the utility functions for the Routing Layer and
  7. the local Print Providor
  8. Author:
  9. Dave Snipp (DaveSn) 15-Mar-1991
  10. Revision History:
  11. --*/
  12. #include "precomp.h"
  13. #pragma hdrstop
  14. MODULE_DEBUG_INIT( DBG_ERROR, DBG_ERROR );
  15. // used to break infinite loop in ConvertDevMode
  16. const WCHAR pszCnvrtdmToken[] = L",DEVMODE";
  17. const WCHAR pszDrvConvert[] = L",DrvConvert";
  18. DWORD
  19. Win32IsOlderThan(
  20. DWORD i,
  21. DWORD j
  22. );
  23. VOID
  24. SplInSem(
  25. VOID
  26. )
  27. {
  28. if (SpoolerSection.OwningThread != (HANDLE) ULongToPtr(GetCurrentThreadId())) {
  29. DBGMSG(DBG_ERROR, ("Not in spooler semaphore\n"));
  30. }
  31. }
  32. VOID
  33. SplOutSem(
  34. VOID
  35. )
  36. {
  37. if (SpoolerSection.OwningThread == (HANDLE) ULongToPtr(GetCurrentThreadId())) {
  38. DBGMSG(DBG_ERROR, ("Inside spooler semaphore !!\n"));
  39. }
  40. }
  41. VOID
  42. EnterSplSem(
  43. VOID
  44. )
  45. {
  46. EnterCriticalSection(&SpoolerSection);
  47. }
  48. VOID
  49. LeaveSplSem(
  50. VOID
  51. )
  52. {
  53. SplInSem();
  54. LeaveCriticalSection(&SpoolerSection);
  55. }
  56. PWINIPORT
  57. FindPort(
  58. LPWSTR pName,
  59. PWINIPORT pFirstPort
  60. )
  61. {
  62. PWINIPORT pIniPort;
  63. pIniPort = pFirstPort;
  64. if (pName) {
  65. while (pIniPort) {
  66. if (!lstrcmpi( pIniPort->pName, pName )) {
  67. return pIniPort;
  68. }
  69. pIniPort=pIniPort->pNext;
  70. }
  71. }
  72. return FALSE;
  73. }
  74. BOOL
  75. MyName(
  76. LPWSTR pName
  77. )
  78. {
  79. if (!pName || !*pName)
  80. return TRUE;
  81. if (*pName == L'\\' && *(pName+1) == L'\\')
  82. if (!lstrcmpi(pName, szMachineName))
  83. return TRUE;
  84. return FALSE;
  85. }
  86. BOOL
  87. MyUNCName(
  88. PWSTR pName
  89. )
  90. {
  91. BOOL bRet = VALIDATE_NAME(pName);
  92. if (bRet && !MyName(pName))
  93. {
  94. WCHAR *pcMark;
  95. pcMark = wcschr(pName + 2, L'\\');
  96. DBGMSG(DBG_TRACE, ("WIN32SPL MyUNCName input pName %ws\n", pName));
  97. if (pcMark)
  98. {
  99. *pcMark = 0;
  100. }
  101. bRet = CacheIsNameInNodeList(szMachineName + 2, pName + 2) == S_OK;
  102. DBGMSG(DBG_TRACE, ("WIN32SPL MyUNCName looking for %ws in name cache, result %u\n", pName, bRet));
  103. if (pcMark)
  104. {
  105. *pcMark = L'\\';
  106. }
  107. }
  108. return bRet;
  109. }
  110. #define MAX_CACHE_ENTRIES 20
  111. LMCACHE LMCacheTable[MAX_CACHE_ENTRIES];
  112. DWORD
  113. FindEntryinLMCache(
  114. LPWSTR pServerName,
  115. LPWSTR pShareName
  116. )
  117. {
  118. DWORD i;
  119. DBGMSG(DBG_TRACE, ("FindEntryinLMCache with %ws and %ws\n", pServerName, pShareName));
  120. for (i = 0; i < MAX_CACHE_ENTRIES; i++ ) {
  121. if (LMCacheTable[i].bAvailable) {
  122. if (!_wcsicmp(LMCacheTable[i].szServerName, pServerName)
  123. && !_wcsicmp(LMCacheTable[i].szShareName, pShareName)) {
  124. //
  125. // update the time stamp so that it is current and not old
  126. //
  127. GetSystemTime(&LMCacheTable[i].st);
  128. //
  129. //
  130. //
  131. DBGMSG(DBG_TRACE, ("FindEntryinLMCache returning with %d\n", i));
  132. return(i);
  133. }
  134. }
  135. }
  136. DBGMSG(DBG_TRACE, ("FindEntryinLMCache returning with -1\n"));
  137. return((DWORD)-1);
  138. }
  139. DWORD
  140. AddEntrytoLMCache(
  141. LPWSTR pServerName,
  142. LPWSTR pShareName
  143. )
  144. {
  145. DWORD LRUEntry = (DWORD)-1;
  146. DWORD i;
  147. DBGMSG(DBG_TRACE, ("AddEntrytoLMCache with %ws and %ws\n", pServerName, pShareName));
  148. for (i = 0; i < MAX_CACHE_ENTRIES; i++ ) {
  149. if (!LMCacheTable[i].bAvailable) {
  150. LMCacheTable[i].bAvailable = TRUE;
  151. StringCchCopy(LMCacheTable[i].szServerName, COUNTOF(LMCacheTable[i].szServerName), pServerName);
  152. StringCchCopy(LMCacheTable[i].szShareName, COUNTOF(LMCacheTable[i].szShareName), pShareName);
  153. //
  154. // update the time stamp so that we know when this entry was made
  155. //
  156. GetSystemTime(&LMCacheTable[i].st);
  157. DBGMSG(DBG_TRACE, ("AddEntrytoLMCache returning with %d\n", i));
  158. return(i);
  159. } else {
  160. if ((LRUEntry == (DWORD)-1) ||
  161. (i == IsOlderThan(i, LRUEntry))){
  162. LRUEntry = i;
  163. }
  164. }
  165. }
  166. //
  167. // We have no available entries, replace with the
  168. // LRU Entry
  169. LMCacheTable[LRUEntry].bAvailable = TRUE;
  170. StringCchCopy(LMCacheTable[LRUEntry].szServerName, COUNTOF(LMCacheTable[LRUEntry].szServerName), pServerName);
  171. StringCchCopy(LMCacheTable[LRUEntry].szShareName, COUNTOF(LMCacheTable[LRUEntry].szShareName), pShareName);
  172. DBGMSG(DBG_TRACE, ("AddEntrytoLMCache returning with %d\n", LRUEntry));
  173. return(LRUEntry);
  174. }
  175. VOID
  176. DeleteEntryfromLMCache(
  177. LPWSTR pServerName,
  178. LPWSTR pShareName
  179. )
  180. {
  181. DWORD i;
  182. DBGMSG(DBG_TRACE, ("DeleteEntryFromLMCache with %ws and %ws\n", pServerName, pShareName));
  183. for (i = 0; i < MAX_CACHE_ENTRIES; i++ ) {
  184. if (LMCacheTable[i].bAvailable) {
  185. if (!_wcsicmp(LMCacheTable[i].szServerName, pServerName)
  186. && !_wcsicmp(LMCacheTable[i].szShareName, pShareName)) {
  187. //
  188. // reset the available flag on this node
  189. //
  190. LMCacheTable[i].bAvailable = FALSE;
  191. DBGMSG(DBG_TRACE, ("DeleteEntryFromLMCache returning after deleting the %d th entry\n", i));
  192. return;
  193. }
  194. }
  195. }
  196. DBGMSG(DBG_TRACE, ("DeleteEntryFromLMCache returning after not finding an entry to delete\n"));
  197. }
  198. DWORD
  199. IsOlderThan(
  200. DWORD i,
  201. DWORD j
  202. )
  203. {
  204. SYSTEMTIME *pi, *pj;
  205. DWORD iMs, jMs;
  206. DBGMSG(DBG_TRACE, ("IsOlderThan entering with i %d j %d\n", i, j));
  207. pi = &(LMCacheTable[i].st);
  208. pj = &(LMCacheTable[j].st);
  209. DBGMSG(DBG_TRACE, ("Index i %d - %d:%d:%d:%d:%d:%d:%d\n",
  210. i, pi->wYear, pi->wMonth, pi->wDay, pi->wHour, pi->wMinute, pi->wSecond, pi->wMilliseconds));
  211. DBGMSG(DBG_TRACE,("Index j %d - %d:%d:%d:%d:%d:%d:%d\n",
  212. j, pj->wYear, pj->wMonth, pj->wDay, pj->wHour, pj->wMinute, pj->wSecond, pj->wMilliseconds));
  213. if (pi->wYear < pj->wYear) {
  214. DBGMSG(DBG_TRACE, ("IsOlderThan returns %d\n", i));
  215. return(i);
  216. } else if (pi->wYear > pj->wYear) {
  217. DBGMSG(DBG_TRACE, ("IsOlderThan than returns %d\n", j));
  218. return(j);
  219. } else if (pi->wMonth < pj->wMonth) {
  220. DBGMSG(DBG_TRACE, ("IsOlderThan returns %d\n", i));
  221. return(i);
  222. } else if (pi->wMonth > pj->wMonth) {
  223. DBGMSG(DBG_TRACE, ("IsOlderThan than returns %d\n", j));
  224. return(j);
  225. } else if (pi->wDay < pj->wDay) {
  226. DBGMSG(DBG_TRACE, ("IsOlderThan returns %d\n", i));
  227. return(i);
  228. } else if (pi->wDay > pj->wDay) {
  229. DBGMSG(DBG_TRACE, ("IsOlderThan than returns %d\n", j));
  230. return(j);
  231. } else {
  232. iMs = ((((pi->wHour * 60) + pi->wMinute)*60) + pi->wSecond)* 1000 + pi->wMilliseconds;
  233. jMs = ((((pj->wHour * 60) + pj->wMinute)*60) + pj->wSecond)* 1000 + pj->wMilliseconds;
  234. if (iMs <= jMs) {
  235. DBGMSG(DBG_TRACE, ("IsOlderThan returns %d\n", i));
  236. return(i);
  237. } else {
  238. DBGMSG(DBG_TRACE, ("IsOlderThan than returns %d\n", j));
  239. return(j);
  240. }
  241. }
  242. }
  243. WIN32LMCACHE Win32LMCacheTable[MAX_CACHE_ENTRIES];
  244. DWORD
  245. FindEntryinWin32LMCache(
  246. LPWSTR pServerName
  247. )
  248. {
  249. DWORD i;
  250. DBGMSG(DBG_TRACE, ("FindEntryinWin32LMCache with %ws\n", pServerName));
  251. for (i = 0; i < MAX_CACHE_ENTRIES; i++ ) {
  252. if (Win32LMCacheTable[i].bAvailable) {
  253. if (!_wcsicmp(Win32LMCacheTable[i].szServerName, pServerName)) {
  254. //
  255. // update the time stamp so that it is current and not old
  256. //
  257. GetSystemTime(&Win32LMCacheTable[i].st);
  258. //
  259. //
  260. //
  261. DBGMSG(DBG_TRACE, ("FindEntryinWin32LMCache returning with %d\n", i));
  262. return(i);
  263. }
  264. }
  265. }
  266. DBGMSG(DBG_TRACE, ("FindEntryinWin32LMCache returning with -1\n"));
  267. return((DWORD)-1);
  268. }
  269. DWORD
  270. AddEntrytoWin32LMCache(
  271. LPWSTR pServerName
  272. )
  273. {
  274. DWORD LRUEntry = (DWORD)-1;
  275. DWORD i;
  276. DBGMSG(DBG_TRACE, ("AddEntrytoWin32LMCache with %ws\n", pServerName));
  277. for (i = 0; i < MAX_CACHE_ENTRIES; i++ ) {
  278. if (!Win32LMCacheTable[i].bAvailable) {
  279. Win32LMCacheTable[i].bAvailable = TRUE;
  280. StringCchCopy(Win32LMCacheTable[i].szServerName, COUNTOF(Win32LMCacheTable[i].szServerName), pServerName);
  281. //
  282. // update the time stamp so that we know when this entry was made
  283. //
  284. GetSystemTime(&Win32LMCacheTable[i].st);
  285. DBGMSG(DBG_TRACE, ("AddEntrytoWin32LMCache returning with %d\n", i));
  286. return(i);
  287. } else {
  288. if ((LRUEntry == -1) ||
  289. (i == Win32IsOlderThan(i, LRUEntry))){
  290. LRUEntry = i;
  291. }
  292. }
  293. }
  294. //
  295. // We have no available entries, replace with the
  296. // LRU Entry
  297. Win32LMCacheTable[LRUEntry].bAvailable = TRUE;
  298. StringCchCopy(Win32LMCacheTable[LRUEntry].szServerName, COUNTOF(Win32LMCacheTable[LRUEntry].szServerName), pServerName);
  299. DBGMSG(DBG_TRACE, ("AddEntrytoWin32LMCache returning with %d\n", LRUEntry));
  300. return(LRUEntry);
  301. }
  302. VOID
  303. DeleteEntryfromWin32LMCache(
  304. LPWSTR pServerName
  305. )
  306. {
  307. DWORD i;
  308. DBGMSG(DBG_TRACE, ("DeleteEntryFromWin32LMCache with %ws\n", pServerName));
  309. for (i = 0; i < MAX_CACHE_ENTRIES; i++ ) {
  310. if (Win32LMCacheTable[i].bAvailable) {
  311. if (!_wcsicmp(Win32LMCacheTable[i].szServerName, pServerName)) {
  312. //
  313. // reset the available flag on this node
  314. //
  315. Win32LMCacheTable[i].bAvailable = FALSE;
  316. DBGMSG(DBG_TRACE, ("DeleteEntryFromWin32LMCache returning after deleting the %d th entry\n", i));
  317. return;
  318. }
  319. }
  320. }
  321. DBGMSG(DBG_TRACE, ("DeleteEntryFromWin32LMCache returning after not finding an entry to delete\n"));
  322. }
  323. DWORD
  324. Win32IsOlderThan(
  325. DWORD i,
  326. DWORD j
  327. )
  328. {
  329. SYSTEMTIME *pi, *pj;
  330. DWORD iMs, jMs;
  331. DBGMSG(DBG_TRACE, ("Win32IsOlderThan entering with i %d j %d\n", i, j));
  332. pi = &(Win32LMCacheTable[i].st);
  333. pj = &(Win32LMCacheTable[j].st);
  334. DBGMSG(DBG_TRACE, ("Index i %d - %d:%d:%d:%d:%d:%d:%d\n",
  335. i, pi->wYear, pi->wMonth, pi->wDay, pi->wHour, pi->wMinute, pi->wSecond, pi->wMilliseconds));
  336. DBGMSG(DBG_TRACE,("Index j %d - %d:%d:%d:%d:%d:%d:%d\n",
  337. j, pj->wYear, pj->wMonth, pj->wDay, pj->wHour, pj->wMinute, pj->wSecond, pj->wMilliseconds));
  338. if (pi->wYear < pj->wYear) {
  339. DBGMSG(DBG_TRACE, ("Win32IsOlderThan returns %d\n", i));
  340. return(i);
  341. } else if (pi->wYear > pj->wYear) {
  342. DBGMSG(DBG_TRACE, ("Win32IsOlderThan returns %d\n", j));
  343. return(j);
  344. } else if (pi->wMonth < pj->wMonth) {
  345. DBGMSG(DBG_TRACE, ("Win32IsOlderThan returns %d\n", i));
  346. return(i);
  347. } else if (pi->wMonth > pj->wMonth) {
  348. DBGMSG(DBG_TRACE, ("Win32IsOlderThan returns %d\n", j));
  349. return(j);
  350. } else if (pi->wDay < pj->wDay) {
  351. DBGMSG(DBG_TRACE, ("Win32IsOlderThan returns %d\n", i));
  352. return(i);
  353. } else if (pi->wDay > pj->wDay) {
  354. DBGMSG(DBG_TRACE, ("Win32IsOlderThan returns %d\n", j));
  355. return(j);
  356. } else {
  357. iMs = ((((pi->wHour * 60) + pi->wMinute)*60) + pi->wSecond)* 1000 + pi->wMilliseconds;
  358. jMs = ((((pj->wHour * 60) + pj->wMinute)*60) + pj->wSecond)* 1000 + pj->wMilliseconds;
  359. if (iMs <= jMs) {
  360. DBGMSG(DBG_TRACE, ("Win32IsOlderThan returns %d\n", i));
  361. return(i);
  362. } else {
  363. DBGMSG(DBG_TRACE, ("Win32IsOlderThan returns %d\n", j));
  364. return(j);
  365. }
  366. }
  367. }
  368. BOOL
  369. GetSid(
  370. PHANDLE phToken
  371. )
  372. {
  373. if (!OpenThreadToken( GetCurrentThread(),
  374. TOKEN_IMPERSONATE,
  375. TRUE,
  376. phToken)) {
  377. DBGMSG(DBG_WARNING, ("OpenThreadToken failed: %d\n", GetLastError()));
  378. return FALSE;
  379. } else {
  380. return TRUE;
  381. }
  382. }
  383. BOOL
  384. SetCurrentSid(
  385. HANDLE hToken
  386. )
  387. {
  388. NtSetInformationThread(NtCurrentThread(), ThreadImpersonationToken,
  389. &hToken, sizeof(hToken));
  390. return TRUE;
  391. }
  392. BOOL
  393. ValidateW32SpoolHandle(
  394. PWSPOOL pSpool
  395. )
  396. {
  397. SplOutSem();
  398. try {
  399. if (!pSpool || (pSpool->signature != WSJ_SIGNATURE)) {
  400. DBGMSG( DBG_TRACE, ("ValidateW32SpoolHandle error invalid handle %x\n", pSpool));
  401. SetLastError(ERROR_INVALID_HANDLE);
  402. return(FALSE);
  403. }
  404. return(TRUE);
  405. } except (1) {
  406. DBGMSG( DBG_TRACE, ("ValidateW32SpoolHandle error invalid handle %x\n", pSpool));
  407. return(FALSE);
  408. }
  409. }
  410. BOOL
  411. ValidRawDatatype(
  412. LPCWSTR pszDatatype
  413. )
  414. {
  415. if( !pszDatatype || _wcsnicmp( pszDatatype, pszRaw, 3 )){
  416. return FALSE;
  417. }
  418. return TRUE;
  419. }
  420. HANDLE
  421. LoadDriverFiletoConvertDevmodeFromPSpool(
  422. HANDLE hSplPrinter
  423. )
  424. /*++
  425. Finds out full path to the driver file and creates a DEVMODECHG_INFO
  426. (which does a LoadLibrary)
  427. Arguments:
  428. h : A cache handle
  429. Return Value:
  430. On succes a valid pointer, else NULL
  431. --*/
  432. {
  433. LPBYTE pDriver = NULL;
  434. LPWSTR pConfigFile;
  435. HANDLE hDevModeChgInfo = NULL;
  436. DWORD dwNeeded;
  437. DWORD dwServerMajorVersion = 0, dwServerMinorVersion = 0;
  438. if ( hSplPrinter == INVALID_HANDLE_VALUE ) {
  439. SPLASSERT(hSplPrinter != INVALID_HANDLE_VALUE);
  440. return NULL;
  441. }
  442. SplGetPrinterDriverEx(hSplPrinter,
  443. szEnvironment,
  444. 2,
  445. NULL,
  446. 0,
  447. &dwNeeded,
  448. cThisMajorVersion,
  449. cThisMinorVersion,
  450. &dwServerMajorVersion,
  451. &dwServerMinorVersion);
  452. if ( GetLastError() != ERROR_INSUFFICIENT_BUFFER )
  453. goto Cleanup;
  454. pDriver = AllocSplMem(dwNeeded);
  455. if ( !pDriver ||
  456. !SplGetPrinterDriverEx(hSplPrinter,
  457. szEnvironment,
  458. 2,
  459. (LPBYTE)pDriver,
  460. dwNeeded,
  461. &dwNeeded,
  462. cThisMajorVersion,
  463. cThisMinorVersion,
  464. &dwServerMajorVersion,
  465. &dwServerMinorVersion) )
  466. goto Cleanup;
  467. pConfigFile = ((LPDRIVER_INFO_2)pDriver)->pConfigFile;
  468. hDevModeChgInfo = LoadDriverFiletoConvertDevmode(pConfigFile);
  469. Cleanup:
  470. if ( pDriver )
  471. FreeSplMem(pDriver);
  472. return hDevModeChgInfo;
  473. }
  474. BOOL
  475. DoDevModeConversionAndBuildNewPrinterInfo2(
  476. IN LPPRINTER_INFO_2 pInPrinter2,
  477. IN DWORD dwInSize,
  478. IN OUT LPBYTE pOutBuf,
  479. IN DWORD dwOutSize,
  480. IN OUT LPDWORD pcbNeeded,
  481. IN PWSPOOL pSpool
  482. )
  483. /*++
  484. Calls driver to do a devmode conversion and builds a new printer info 2.
  485. Devmode is put at the end and then strings are packed from there.
  486. Arguments:
  487. pInPrinter2 - Printer Info2 structure with devmode info
  488. dwInSize - Number of characters needed to pack info in pInPrinter
  489. (not necessarily the size of the input buffer)
  490. dwOutSize - buffer size
  491. pOutBuf - Buffer to do the operation
  492. pcbNeeded - Amount of memory copied (in characters)
  493. pSpool - Points to w32 handle
  494. Return Value:
  495. TRUE on success, FALSE on error
  496. --*/
  497. {
  498. BOOL bReturn = FALSE;
  499. LPDEVMODE pNewDevMode = NULL, pCacheDevMode, pInDevMode;
  500. DWORD dwDevModeSize, dwSecuritySize, dwNeeded = 0;
  501. DWORD cchPrinterName;
  502. HANDLE hDevModeChgInfo = NULL;
  503. LPWSTR SourceStrings[sizeof(PRINTER_INFO_2)/sizeof(LPWSTR)];
  504. LPWSTR *pSourceStrings=SourceStrings;
  505. LPDWORD pOffsets;
  506. LPBYTE pEnd;
  507. PWCACHEINIPRINTEREXTRA pExtraData;
  508. LPWSTR pPrinterName = NULL;
  509. VALIDATEW32HANDLE(pSpool);
  510. pInDevMode = pInPrinter2->pDevMode;
  511. if ( !BoolFromHResult(SplIsValidDevmodeNoSizeW(pInDevMode)) ||
  512. pSpool->hSplPrinter == INVALID_HANDLE_VALUE ) {
  513. goto AfterDevModeConversion;
  514. }
  515. if ( !SplGetPrinterExtra(pSpool->hSplPrinter,
  516. &(PBYTE)pExtraData) ) {
  517. DBGMSG(DBG_ERROR,
  518. ("DoDevModeConversionAndBuildNewPrinterInfo2: SplGetPrinterExtra error %d\n",
  519. GetLastError()));
  520. goto AfterDevModeConversion;
  521. }
  522. //
  523. // Only time we do not have to convert devmode is if the server is running
  524. // same version NT and also we have a devmode which matches the server
  525. // devmode in dmSize, dmDriverExtra, dmSpecVersion, and dmDriverVersion
  526. //
  527. pCacheDevMode = pExtraData->pPI2 ? pExtraData->pPI2->pDevMode : NULL;
  528. if ( (pExtraData->dwServerVersion == gdwThisGetVersion ||
  529. (pSpool->Status & WSPOOL_STATUS_CNVRTDEVMODE)) &&
  530. pCacheDevMode &&
  531. pInDevMode->dmSize == pCacheDevMode->dmSize &&
  532. pInDevMode->dmDriverExtra == pCacheDevMode->dmDriverExtra &&
  533. pInDevMode->dmSpecVersion == pCacheDevMode->dmSpecVersion &&
  534. pInDevMode->dmDriverVersion == pCacheDevMode->dmDriverVersion ) {
  535. dwDevModeSize = pInDevMode->dmSize + pInDevMode->dmDriverExtra;
  536. dwNeeded = dwInSize;
  537. if ( dwOutSize < dwNeeded ) {
  538. SetLastError(ERROR_INSUFFICIENT_BUFFER);
  539. goto Cleanup;
  540. }
  541. //
  542. // Put DevMode at the end
  543. //
  544. pNewDevMode = (LPDEVMODE)(pOutBuf + dwOutSize - dwDevModeSize);
  545. CopyMemory((LPBYTE)pNewDevMode,
  546. (LPBYTE)pInDevMode,
  547. dwDevModeSize);
  548. goto AfterDevModeConversion;
  549. }
  550. hDevModeChgInfo = LoadDriverFiletoConvertDevmodeFromPSpool(pSpool->hSplPrinter);
  551. if ( !hDevModeChgInfo )
  552. goto AfterDevModeConversion;
  553. dwDevModeSize = 0;
  554. SPLASSERT( pSpool->pName != NULL );
  555. //
  556. // Append ,DEVMODE to end of pSpool->pName
  557. //
  558. cchPrinterName = lstrlen(pSpool->pName) + lstrlen(pszCnvrtdmToken) + 1;
  559. pPrinterName = AllocSplMem(cchPrinterName * sizeof(WCHAR));
  560. if ( !pPrinterName )
  561. goto Cleanup;
  562. StrNCatBuff(pPrinterName,
  563. cchPrinterName,
  564. pSpool->pName,
  565. pszCnvrtdmToken,
  566. NULL);
  567. //
  568. // Findout size of default devmode
  569. //
  570. if ( ERROR_INSUFFICIENT_BUFFER != CallDrvDevModeConversion(hDevModeChgInfo,
  571. pPrinterName,
  572. NULL,
  573. (LPBYTE *)&pNewDevMode,
  574. &dwDevModeSize,
  575. CDM_DRIVER_DEFAULT,
  576. FALSE) )
  577. goto AfterDevModeConversion;
  578. //
  579. // Findout size needed to have current version devmode
  580. //
  581. dwNeeded = dwInSize + dwDevModeSize - pInDevMode->dmSize
  582. - pInDevMode->dmDriverExtra;
  583. if ( dwOutSize < dwNeeded ) {
  584. SetLastError(ERROR_INSUFFICIENT_BUFFER);
  585. goto Cleanup;
  586. }
  587. //
  588. // Put DevMode at the end
  589. //
  590. pNewDevMode = (LPDEVMODE)(pOutBuf + dwOutSize - dwDevModeSize);
  591. //
  592. // Get default devmode and then convert remote devmode to that format
  593. //
  594. if ( ERROR_SUCCESS != CallDrvDevModeConversion(hDevModeChgInfo,
  595. pPrinterName,
  596. NULL,
  597. (LPBYTE *)&pNewDevMode,
  598. &dwDevModeSize,
  599. CDM_DRIVER_DEFAULT,
  600. FALSE) ||
  601. ERROR_SUCCESS != CallDrvDevModeConversion(hDevModeChgInfo,
  602. pPrinterName,
  603. (LPBYTE)pInDevMode,
  604. (LPBYTE *)&pNewDevMode,
  605. &dwDevModeSize,
  606. CDM_CONVERT,
  607. FALSE) ) {
  608. pNewDevMode = NULL;
  609. goto AfterDevModeConversion;
  610. }
  611. AfterDevModeConversion:
  612. //
  613. // At this point if pNewDevMode != NULL dev mode conversion has been done
  614. // by the driver. If not either we did not get a devmode or conversion failed
  615. // In either case set devmode to NULL
  616. //
  617. if ( !pNewDevMode ) {
  618. dwNeeded = dwInSize;
  619. if ( dwOutSize < dwNeeded ) {
  620. SetLastError(ERROR_INSUFFICIENT_BUFFER);
  621. goto Cleanup;
  622. }
  623. }
  624. bReturn = TRUE;
  625. CopyMemory(pOutBuf, (LPBYTE)pInPrinter2, sizeof(PRINTER_INFO_2));
  626. ((LPPRINTER_INFO_2)pOutBuf)->pDevMode = pNewDevMode;
  627. pEnd = (pNewDevMode ? (LPBYTE) pNewDevMode
  628. : (LPBYTE) (pOutBuf + dwOutSize));
  629. if ( pInPrinter2->pSecurityDescriptor ) {
  630. dwSecuritySize = GetSecurityDescriptorLength(
  631. pInPrinter2->pSecurityDescriptor);
  632. pEnd -= dwSecuritySize;
  633. CopyMemory(pEnd, pInPrinter2->pSecurityDescriptor, dwSecuritySize);
  634. ((LPPRINTER_INFO_2)pOutBuf)->pSecurityDescriptor =
  635. (PSECURITY_DESCRIPTOR) pEnd;
  636. } else {
  637. ((LPPRINTER_INFO_2)pOutBuf)->pSecurityDescriptor = NULL;
  638. }
  639. pOffsets = PrinterInfo2Strings;
  640. *pSourceStrings++ = pInPrinter2->pServerName;
  641. *pSourceStrings++ = pInPrinter2->pPrinterName;
  642. *pSourceStrings++ = pInPrinter2->pShareName;
  643. *pSourceStrings++ = pInPrinter2->pPortName;
  644. *pSourceStrings++ = pInPrinter2->pDriverName;
  645. *pSourceStrings++ = pInPrinter2->pComment;
  646. *pSourceStrings++ = pInPrinter2->pLocation;
  647. *pSourceStrings++ = pInPrinter2->pSepFile;
  648. *pSourceStrings++ = pInPrinter2->pPrintProcessor;
  649. *pSourceStrings++ = pInPrinter2->pDatatype;
  650. *pSourceStrings++ = pInPrinter2->pParameters;
  651. pEnd = PackStrings(SourceStrings, (LPBYTE)pOutBuf, pOffsets, pEnd);
  652. SPLASSERT(pEnd > pOutBuf && pEnd < pOutBuf + dwOutSize);
  653. bReturn = TRUE;
  654. Cleanup:
  655. *pcbNeeded = dwNeeded;
  656. if ( hDevModeChgInfo )
  657. UnloadDriverFile(hDevModeChgInfo);
  658. if (pPrinterName)
  659. FreeSplMem(pPrinterName);
  660. return bReturn;
  661. }
  662. PWSTR
  663. StripString(
  664. PWSTR pszString,
  665. PCWSTR pszStrip,
  666. PCWSTR pszTerminator
  667. )
  668. {
  669. //
  670. // Strips the first occurence of pszStrip from pszString if
  671. // the next character after pszStrip is one of the characters
  672. // in pszTerminator. NULL is an implicit terminator, so if you
  673. // want to strip pszStrip only at the end of pszString, just pass
  674. // in an empty string for pszTerminator.
  675. //
  676. // Returns: Pointer to pszString if pszStrip was found
  677. // NULL is pszStrip was not found
  678. //
  679. PWSTR psz;
  680. DWORD dwStripLength;
  681. if (!pszStrip || !pszString || !pszTerminator)
  682. return NULL;
  683. dwStripLength = wcslen(pszStrip);
  684. for(psz = pszString ; psz ;) {
  685. // find pszStrip in pszString
  686. if ((psz = wcsstr(psz, pszStrip))) {
  687. // check for the terminator & strip pszStrip
  688. if (!*(psz + dwStripLength) || wcschr(pszTerminator, *(psz + dwStripLength))) {
  689. StringCchCopy(psz, 1 + wcslen(psz), psz + dwStripLength);
  690. return pszString;
  691. } else {
  692. ++psz;
  693. }
  694. }
  695. }
  696. return NULL;
  697. }
  698. BOOL
  699. AddDriverFromLocalCab(
  700. LPTSTR pszDriverName,
  701. LPHANDLE pIniSpooler
  702. )
  703. {
  704. DRIVER_INFO_7 DriverInfo7;
  705. if( GetPolicy() & SERVER_INSTALL_ONLY ) {
  706. return FALSE;
  707. }
  708. DriverInfo7.cbSize = sizeof( DriverInfo7 );
  709. DriverInfo7.cVersion = 0;
  710. DriverInfo7.pszDriverName = pszDriverName;
  711. DriverInfo7.pszInfName = NULL;
  712. DriverInfo7.pszInstallSourceRoot = NULL;
  713. return ( SplAddPrinterDriverEx( NULL,
  714. 7,
  715. (LPBYTE)&DriverInfo7,
  716. APD_COPY_NEW_FILES,
  717. pIniSpooler,
  718. DO_NOT_USE_SCRATCH_DIR,
  719. FALSE ) );
  720. }
  721. /*++
  722. Routine Name:
  723. IsAdminAccess
  724. Description:
  725. This returns whether the given printer defaults are asking for admin access,
  726. we consider the request to be admin access if the printer defaults are
  727. non-NULL and have PRINTER_ACCESS_ADMINISTER or WRITE_DAC specified.
  728. Arguments:
  729. pDefaults - The printer defaults, may be NULL.
  730. Return Value:
  731. None.
  732. --*/
  733. BOOL
  734. IsAdminAccess(
  735. IN PRINTER_DEFAULTS *pDefaults
  736. )
  737. {
  738. return pDefaults && (pDefaults->DesiredAccess & (PRINTER_ACCESS_ADMINISTER | WRITE_DAC));
  739. }
  740. /*++
  741. Routine Name:
  742. AreWeOnADomain
  743. Description:
  744. This returns whether this machine is a domain joined machine or not.
  745. Arguments:
  746. pbDomain - If TRUE, we are on a domain.
  747. Return Value:
  748. An HRESULT.
  749. --*/
  750. HRESULT
  751. AreWeOnADomain(
  752. OUT BOOL *pbDomain
  753. )
  754. {
  755. HRESULT hr = pbDomain ? S_OK : HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
  756. PDSROLE_PRIMARY_DOMAIN_INFO_BASIC pRoleInfo = NULL;
  757. BOOL bOnDomain = FALSE;
  758. if (SUCCEEDED(hr))
  759. {
  760. hr = HResultFromWin32(DsRoleGetPrimaryDomainInformation(NULL,
  761. DsRolePrimaryDomainInfoBasic,
  762. (BYTE **)(&pRoleInfo)));
  763. }
  764. if (SUCCEEDED(hr))
  765. {
  766. bOnDomain = pRoleInfo->MachineRole == DsRole_RoleMemberWorkstation ||
  767. pRoleInfo->MachineRole == DsRole_RoleMemberServer ||
  768. pRoleInfo->MachineRole == DsRole_RoleBackupDomainController ||
  769. pRoleInfo->MachineRole == DsRole_RolePrimaryDomainController;
  770. }
  771. if (pRoleInfo)
  772. {
  773. DsRoleFreeMemory((VOID *)pRoleInfo);
  774. }
  775. if (pbDomain)
  776. {
  777. *pbDomain = bOnDomain;
  778. }
  779. return hr;
  780. }
  781. /*++
  782. Routine Name:
  783. GetServerNameFromQueue
  784. Description:
  785. This returns the server name from the given queue name.
  786. Arguments:
  787. pszQueue - The queue name,
  788. ppszServerName - The server name.
  789. Return Value:
  790. An HRESULT.
  791. --*/
  792. HRESULT
  793. GetServerNameFromPrinterName(
  794. IN PCWSTR pszQueue,
  795. OUT PWSTR *ppszServerName
  796. )
  797. {
  798. HRESULT hr = pszQueue && ppszServerName ? S_OK : HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
  799. PWSTR pszServer = NULL;
  800. if (SUCCEEDED(hr))
  801. {
  802. hr = *pszQueue++ == L'\\' && *pszQueue++ == L'\\' ? S_OK : HRESULT_FROM_WIN32(ERROR_INVALID_PRINTER_NAME);
  803. }
  804. if (SUCCEEDED(hr))
  805. {
  806. pszServer = AllocSplStr(pszQueue);
  807. hr = pszServer ? S_OK : HRESULT_FROM_WIN32(ERROR_OUTOFMEMORY);
  808. }
  809. if (SUCCEEDED(hr))
  810. {
  811. PWSTR pszSlash = wcschr(&pszServer[2], L'\\');
  812. //
  813. // If there was no second slash, then what we have is the server name.
  814. //
  815. if (pszSlash)
  816. {
  817. *pszSlash = L'\0';
  818. }
  819. }
  820. if (SUCCEEDED(hr))
  821. {
  822. *ppszServerName = pszServer;
  823. pszServer = NULL;
  824. }
  825. FreeSplMem(pszServer);
  826. return hr;
  827. }
  828. /*++
  829. Routine Name:
  830. GetDNSNameFromServerName
  831. Description:
  832. This returns a fully qualified DNS name from the server name. It is
  833. basically copied from localspl because this is dead-end code. In CSR,
  834. we will fix this properly.
  835. Arguments:
  836. pszServerName - The server name whose fully qualified name we are obtaining.
  837. ppszFullyQualified -
  838. Return Value:
  839. An HRESULT.
  840. --*/
  841. HRESULT
  842. GetDNSNameFromServerName(
  843. IN PCWSTR pszServerName,
  844. OUT PWSTR *ppszFullyQualified
  845. )
  846. {
  847. PSTR pszAnsiMachineName = NULL;
  848. struct hostent *pHostEnt;
  849. WORD wVersion;
  850. WSADATA WSAData;
  851. HRESULT hr = pszServerName && *pszServerName && ppszFullyQualified ? S_OK : HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
  852. PWSTR pszDummy = NULL;
  853. GetFullyQualifiedDomainName(pszServerName, &pszDummy);
  854. if (SUCCEEDED(hr))
  855. {
  856. wVersion = MAKEWORD(1, 1);
  857. hr = HResultFromWin32(WSAStartup(wVersion, &WSAData));
  858. }
  859. if (SUCCEEDED(hr))
  860. {
  861. hr = UnicodeToAnsiString(pszServerName, &pszAnsiMachineName);
  862. if (SUCCEEDED(hr))
  863. {
  864. pHostEnt = gethostbyname(pszAnsiMachineName);
  865. hr = pHostEnt ? S_OK : HResultFromWin32(WSAGetLastError());
  866. }
  867. if (SUCCEEDED(hr))
  868. {
  869. *ppszFullyQualified = AnsiToUnicodeStringWithAlloc(pHostEnt->h_name);
  870. hr = *ppszFullyQualified ? S_OK : HRESULT_FROM_WIN32(ERROR_OUTOFMEMORY);
  871. }
  872. WSACleanup();
  873. }
  874. FreeSplMem(pszAnsiMachineName);
  875. return hr;
  876. }
  877. /*++
  878. Routine Name:
  879. UnicodeToAnsiString
  880. Routine Description:
  881. This allocates an ANSI string and converts it using the thread's codepage.
  882. Arguments:
  883. pszUnicode - The incoming, non-NULL, NULL terminated unicode string.
  884. ppszAnsi - The returned ANSI string.
  885. Return Value:
  886. An HRESULT
  887. --*/
  888. HRESULT
  889. UnicodeToAnsiString(
  890. IN PCWSTR pszUnicode,
  891. OUT PSTR *ppszAnsi
  892. )
  893. {
  894. HRESULT hRetval = E_FAIL;
  895. PSTR pszAnsi = NULL;
  896. INT AnsiStringLength = 0;
  897. hRetval = pszUnicode && ppszAnsi ? S_OK : E_INVALIDARG;
  898. if (ppszAnsi)
  899. {
  900. *ppszAnsi = NULL;
  901. }
  902. if (SUCCEEDED(hRetval))
  903. {
  904. AnsiStringLength = WideCharToMultiByte(CP_THREAD_ACP, 0, pszUnicode, -1, NULL, 0, NULL, NULL);
  905. hRetval = AnsiStringLength != 0 ? S_OK : GetLastErrorAsHResult();
  906. }
  907. if (SUCCEEDED(hRetval))
  908. {
  909. pszAnsi = AllocSplMem(AnsiStringLength);
  910. hRetval = pszAnsi ? S_OK : E_OUTOFMEMORY;
  911. }
  912. if (SUCCEEDED(hRetval))
  913. {
  914. hRetval = WideCharToMultiByte(CP_THREAD_ACP, 0, pszUnicode, -1, pszAnsi, AnsiStringLength, NULL, NULL) != 0 ? S_OK : GetLastErrorAsHResult();
  915. }
  916. if (SUCCEEDED(hRetval))
  917. {
  918. *ppszAnsi = pszAnsi;
  919. pszAnsi = NULL;
  920. }
  921. FreeSplMem(pszAnsi);
  922. return hRetval;
  923. }
  924. /*++
  925. Routine Name:
  926. AnsiToUnicodeStringWithAlloc
  927. Description:
  928. Convert ANSI string to UNICODE. Routine allocates memory from the heap
  929. which should be freed by the caller.
  930. Arguments:
  931. pAnsi - Points to the ANSI string
  932. Return Value:
  933. Pointer to UNICODE string
  934. --*/
  935. LPWSTR
  936. AnsiToUnicodeStringWithAlloc(
  937. LPSTR pAnsi
  938. )
  939. {
  940. LPWSTR pUnicode;
  941. DWORD rc;
  942. rc = MultiByteToWideChar(CP_ACP,
  943. MB_PRECOMPOSED,
  944. pAnsi,
  945. -1,
  946. NULL,
  947. 0);
  948. rc *= sizeof(WCHAR);
  949. if ( !rc || !(pUnicode = (LPWSTR) AllocSplMem(rc)) )
  950. return NULL;
  951. rc = MultiByteToWideChar(CP_ACP,
  952. MB_PRECOMPOSED,
  953. pAnsi,
  954. -1,
  955. pUnicode,
  956. rc);
  957. if ( rc )
  958. return pUnicode;
  959. else {
  960. FreeSplMem(pUnicode);
  961. return NULL;
  962. }
  963. }
  964. /*++
  965. Routine Name:
  966. CheckSamePhysicalAddress
  967. Description:
  968. This checks to see whether two servers share a same network address. What it
  969. does is check to see whether the first physical network address of the first
  970. print server can be found in the list of addresses supported by the second
  971. print server.
  972. Arguments:
  973. pszServer1 - The first server in the list.
  974. pszServer2 - The second server in the list.
  975. pbSameAddress - If TRUE, the first physical address of server1 can be found
  976. in server2.
  977. Return Value:
  978. An HRESULT.
  979. --*/
  980. HRESULT
  981. CheckSamePhysicalAddress(
  982. IN PCWSTR pszServer1,
  983. IN PCWSTR pszServer2,
  984. OUT BOOL *pbSameAddress
  985. )
  986. {
  987. BOOL bSameAddress = FALSE;
  988. PSTR pszAnsiServer1 = NULL;
  989. PSTR pszAnsiServer2 = NULL;
  990. ADDRINFO *pAddrInfo1 = NULL;
  991. ADDRINFO *pAddrInfo2 = NULL;
  992. WSADATA WSAData;
  993. WORD wVersion;
  994. HRESULT hr = pszServer1 && pszServer2 && pbSameAddress ? S_OK : HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
  995. if (SUCCEEDED(hr))
  996. {
  997. wVersion = MAKEWORD(1, 1);
  998. hr = HResultFromWin32(WSAStartup(wVersion, &WSAData));
  999. }
  1000. if (SUCCEEDED(hr))
  1001. {
  1002. ADDRINFO *pAddrInfoScan = NULL;
  1003. hr = UnicodeToAnsiString(pszServer1, &pszAnsiServer1);
  1004. if (SUCCEEDED(hr))
  1005. {
  1006. hr = UnicodeToAnsiString(pszServer2, &pszAnsiServer2);
  1007. }
  1008. if (SUCCEEDED(hr))
  1009. {
  1010. hr = getaddrinfo(pszAnsiServer1, NULL, NULL, &pAddrInfo1) == 0 ? S_OK : HResultFromWin32(WSAGetLastError());
  1011. }
  1012. if (SUCCEEDED(hr))
  1013. {
  1014. hr = getaddrinfo(pszAnsiServer2, NULL, NULL, &pAddrInfo2) == 0 ? S_OK : HResultFromWin32(WSAGetLastError());
  1015. }
  1016. //
  1017. // OK, now for the hokey bit, we check to see whether we can exactly
  1018. // match the first element in pAddrInfo1 anywhere in pAddrInfo2.
  1019. //
  1020. for(pAddrInfoScan = pAddrInfo2; pAddrInfo2 && !bSameAddress; pAddrInfo2 = pAddrInfo2->ai_next)
  1021. {
  1022. //
  1023. // If the lengths of the addresses are the same, then compare the
  1024. // actual addresses.
  1025. //
  1026. if (pAddrInfoScan->ai_addrlen == pAddrInfo1->ai_addrlen &&
  1027. !memcmp(pAddrInfoScan->ai_addr, pAddrInfo1->ai_addr, pAddrInfoScan->ai_addrlen))
  1028. {
  1029. bSameAddress = TRUE;
  1030. }
  1031. }
  1032. freeaddrinfo(pAddrInfo1);
  1033. freeaddrinfo(pAddrInfo2);
  1034. WSACleanup();
  1035. }
  1036. if (pbSameAddress)
  1037. {
  1038. *pbSameAddress = bSameAddress;
  1039. }
  1040. FreeSplMem(pszAnsiServer1);
  1041. FreeSplMem(pszAnsiServer2);
  1042. return hr;
  1043. }
  1044. /*++
  1045. Routine Name:
  1046. CheckUserPrintAdmin
  1047. Description:
  1048. This checks to see whether the given user is a print admin.
  1049. Arguments:
  1050. pbUserAdmin - If TRUE, the user is a print admin.
  1051. Return Value:
  1052. An HRESULT.
  1053. --*/
  1054. HRESULT
  1055. CheckUserPrintAdmin(
  1056. OUT BOOL *pbUserAdmin
  1057. )
  1058. {
  1059. //
  1060. // Check to see whether the caller has access to the local print
  1061. // server, if we do have access, then we allow point and print.
  1062. //
  1063. HANDLE hServer = NULL;
  1064. PRINTER_DEFAULTS Defaults = {NULL, NULL, SERVER_ACCESS_ADMINISTER };
  1065. HRESULT hr = pbUserAdmin ? S_OK : HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
  1066. //
  1067. // This actually calls into the router and not into winspool.drv.
  1068. //
  1069. if (SUCCEEDED(hr))
  1070. {
  1071. }
  1072. hr = OpenPrinterW(NULL, &hServer, &Defaults) ? S_OK : GetLastErrorAsHResultAndFail();
  1073. if (SUCCEEDED(hr))
  1074. {
  1075. *pbUserAdmin = TRUE;
  1076. }
  1077. else if (hr == HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED))
  1078. {
  1079. *pbUserAdmin = FALSE;
  1080. hr = S_OK;
  1081. }
  1082. if (hServer)
  1083. {
  1084. ClosePrinter(hServer);
  1085. }
  1086. return hr;
  1087. }
  1088. /*++
  1089. Routine Name:
  1090. GetFullyQualifiedDomainName
  1091. Description:
  1092. This returns a truly fully qualified name, being the name that the endpoint
  1093. expects to use, or
  1094. Arguments:
  1095. pszServerName - The server name whose fully qualified name we are obtaining.
  1096. ppszFullyQualified - The returned fully qualified name.
  1097. Return Value:
  1098. An HRESULT.
  1099. --*/
  1100. HRESULT
  1101. GetFullyQualifiedDomainName(
  1102. IN PCWSTR pszServerName,
  1103. OUT PWSTR *ppszFullyQualified
  1104. )
  1105. {
  1106. WORD wVersion;
  1107. WSADATA WSAData;
  1108. PSTR pszAnsiMachineName = NULL;
  1109. HRESULT hr = pszServerName && *pszServerName && ppszFullyQualified ? S_OK : HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
  1110. if (SUCCEEDED(hr))
  1111. {
  1112. wVersion = MAKEWORD(1, 1);
  1113. hr = HResultFromWin32(WSAStartup(wVersion, &WSAData));
  1114. }
  1115. if (SUCCEEDED(hr))
  1116. {
  1117. ADDRINFO *pAddrInfo = NULL;
  1118. CHAR HostName[NI_MAXHOST];
  1119. hr = UnicodeToAnsiString(pszServerName, &pszAnsiMachineName);
  1120. if (SUCCEEDED(hr))
  1121. {
  1122. hr = getaddrinfo(pszAnsiMachineName, NULL, NULL, &pAddrInfo) == 0 ? S_OK : HResultFromWin32(WSAGetLastError());
  1123. }
  1124. //
  1125. // Now the we have a socket addr, do a reverse name lookup on the name.
  1126. //
  1127. if (SUCCEEDED(hr))
  1128. {
  1129. hr = HResultFromWin32(getnameinfo(pAddrInfo->ai_addr, pAddrInfo->ai_addrlen, HostName, sizeof(HostName), NULL, 0, NI_NAMEREQD));
  1130. }
  1131. if (SUCCEEDED(hr))
  1132. {
  1133. *ppszFullyQualified = AnsiToUnicodeStringWithAlloc(HostName);
  1134. hr = *ppszFullyQualified ? S_OK : HRESULT_FROM_WIN32(ERROR_OUTOFMEMORY);
  1135. }
  1136. if (pAddrInfo)
  1137. {
  1138. freeaddrinfo(pAddrInfo);
  1139. }
  1140. WSACleanup();
  1141. }
  1142. FreeSplMem(pszAnsiMachineName);
  1143. return hr;
  1144. }