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.

657 lines
17 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. xcv.c
  5. Author:
  6. Steve Wilson (SWilson) March 25, 1997
  7. Revision History:
  8. Ali Naqvi (alinaqvi) October 17, 2001
  9. Changed IniXcv to keep IniMonitor rather than Monitor2. This way we can keep a refcount on
  10. IniMonitor, preventing the monitor to be deleted when in use. We are going to use the
  11. IniMonitor to get the Monitor2.
  12. --*/
  13. #include <precomp.h>
  14. #include <offsets.h>
  15. PINIXCV
  16. CreateXcvEntry(
  17. PCWSTR pszMachine,
  18. PCWSTR pszName,
  19. PINIMONITOR pIniMonitor,
  20. PINISPOOLER pIniSpooler,
  21. HANDLE hXcv
  22. );
  23. VOID
  24. DeleteXcvEntry(
  25. PINIXCV pIniXcv
  26. );
  27. BOOL
  28. SplXcvOpenPort(
  29. PCWSTR pszMachine,
  30. PCWSTR pszObject,
  31. DWORD dwType,
  32. PPRINTER_DEFAULTS pDefault,
  33. PHANDLE phXcv,
  34. PINISPOOLER pIniSpooler
  35. );
  36. INIXCV IniXcvStart;
  37. typedef struct {
  38. PWSTR pszMethod;
  39. BOOL (*pfn)(PINIXCV pIniXcv,
  40. PCWSTR pszDataName,
  41. PBYTE pInputData,
  42. DWORD cbInputData,
  43. PBYTE pOutputData,
  44. DWORD cbOutputData,
  45. PDWORD pcbOutputNeeded,
  46. PDWORD pdwStatus,
  47. PINISPOOLER pIniSpooler
  48. );
  49. } XCV_METHOD, *PXCV_METHOD;
  50. XCV_METHOD gpXcvMethod[] = {
  51. {L"DeletePort", XcvDeletePort},
  52. {L"AddPort", XcvAddPort},
  53. {NULL, NULL}
  54. };
  55. BOOL
  56. LocalXcvData(
  57. HANDLE hXcv,
  58. LPCWSTR pszDataName,
  59. PBYTE pInputData,
  60. DWORD cbInputData,
  61. PBYTE pOutputData,
  62. DWORD cbOutputData,
  63. PDWORD pcbOutputNeeded,
  64. PDWORD pdwStatus
  65. )
  66. {
  67. PINIXCV pIniXcv = ((PSPOOL) hXcv)->pIniXcv;
  68. BOOL bReturn;
  69. if (!ValidateXcvHandle(pIniXcv))
  70. return ROUTER_UNKNOWN;
  71. bReturn = SplXcvData(hXcv,
  72. pszDataName,
  73. pInputData,
  74. cbInputData,
  75. pOutputData,
  76. cbOutputData,
  77. pcbOutputNeeded,
  78. pdwStatus,
  79. pIniXcv->pIniSpooler);
  80. return bReturn;
  81. }
  82. BOOL
  83. SplXcvData(
  84. HANDLE hXcv,
  85. PCWSTR pszDataName,
  86. PBYTE pInputData,
  87. DWORD cbInputData,
  88. PBYTE pOutputData,
  89. DWORD cbOutputData,
  90. PDWORD pcbOutputNeeded,
  91. PDWORD pdwStatus,
  92. PINISPOOLER pIniSpooler
  93. )
  94. {
  95. PINIPORT pIniPort;
  96. BOOL rc = FALSE;
  97. BOOL bCallXcvData = FALSE;
  98. PINIXCV pIniXcv = ((PSPOOL) hXcv)->pIniXcv;
  99. DWORD i;
  100. SPLASSERT(pIniXcv->pIniMonitor->Monitor2.pfnXcvDataPort);
  101. //
  102. // Check to see whether the pointers we use always are not NULL
  103. //
  104. if (pdwStatus && pszDataName && pcbOutputNeeded)
  105. {
  106. rc = TRUE;
  107. }
  108. else
  109. {
  110. SetLastError(ERROR_INVALID_PARAMETER);
  111. }
  112. if (rc)
  113. {
  114. //
  115. // Execute well-known methods
  116. //
  117. for(i = 0 ; gpXcvMethod[i].pszMethod &&
  118. wcscmp(gpXcvMethod[i].pszMethod, pszDataName) ; ++i)
  119. ;
  120. if (gpXcvMethod[i].pszMethod)
  121. {
  122. PINIPORT pIniPort = NULL;
  123. if (!_wcsicmp(gpXcvMethod[i].pszMethod, L"AddPort"))
  124. {
  125. //
  126. // Before we use the pInputData buffer, we need to check if the string
  127. // is NULL terminated somewhere inside it.
  128. //
  129. if (pInputData && cbInputData && IsStringNullTerminatedInBuffer((PWSTR)pInputData, cbInputData / sizeof(WCHAR)))
  130. {
  131. EnterSplSem();
  132. //
  133. // Port name is the first field in the input structure. Keep Refcount on
  134. // IniPort while outside CS.
  135. //
  136. pIniPort = FindPort(pInputData, pIniSpooler);
  137. if ( pIniPort )
  138. {
  139. INCPORTREF(pIniPort);
  140. }
  141. LeaveSplSem();
  142. //
  143. // If this pIniPort doesn't have a monitor associated with it, it is
  144. // a temporary port. We will allow it to be added, if there still is
  145. // no monitor associated with it later, we will simply use this
  146. // structure again.
  147. //
  148. if (pIniPort && !(pIniPort->Status & PP_PLACEHOLDER))
  149. {
  150. rc = TRUE;
  151. *pdwStatus = ERROR_ALREADY_EXISTS;
  152. }
  153. else
  154. {
  155. bCallXcvData = TRUE;
  156. }
  157. }
  158. else
  159. {
  160. SetLastError(ERROR_INVALID_DATA);
  161. rc = FALSE;
  162. }
  163. }
  164. else
  165. {
  166. bCallXcvData = TRUE;
  167. }
  168. //
  169. // Don't make the function call if we do AddPort and the port already exists.
  170. // If it is a placeholder, that's OK.
  171. //
  172. if (bCallXcvData)
  173. {
  174. rc = (*gpXcvMethod[i].pfn)( pIniXcv,
  175. pszDataName,
  176. pInputData,
  177. cbInputData,
  178. pOutputData,
  179. cbOutputData,
  180. pcbOutputNeeded,
  181. pdwStatus,
  182. pIniSpooler);
  183. }
  184. if(pIniPort)
  185. {
  186. EnterSplSem();
  187. DECPORTREF(pIniPort);
  188. LeaveSplSem();
  189. }
  190. }
  191. else
  192. {
  193. *pdwStatus = (*pIniXcv->pIniMonitor->Monitor2.pfnXcvDataPort)( pIniXcv->hXcv,
  194. pszDataName,
  195. pInputData,
  196. cbInputData,
  197. pOutputData,
  198. cbOutputData,
  199. pcbOutputNeeded );
  200. rc = TRUE;
  201. }
  202. }
  203. return rc;
  204. }
  205. DWORD
  206. XcvOpen(
  207. PCWSTR pszServer,
  208. PCWSTR pszObject,
  209. DWORD dwObjectType,
  210. PPRINTER_DEFAULTS pDefault,
  211. PHANDLE phXcv,
  212. PINISPOOLER pIniSpooler
  213. )
  214. {
  215. BOOL bRet;
  216. DWORD dwRet;
  217. DWORD dwLastError;
  218. if (dwObjectType == XCVPORT || dwObjectType == XCVMONITOR) {
  219. bRet = SplXcvOpenPort( pszServer,
  220. pszObject,
  221. dwObjectType,
  222. pDefault,
  223. phXcv,
  224. pIniSpooler);
  225. if (!bRet) {
  226. dwLastError = GetLastError();
  227. if (dwLastError == ERROR_INVALID_NAME)
  228. dwRet = ROUTER_UNKNOWN;
  229. else if (dwLastError == ERROR_UNKNOWN_PORT)
  230. // This is a case where a port exists without an associated port monitor
  231. // (i.e. a masq port), we need to give the partial print provider a chance
  232. // to intercept the XCV call
  233. //
  234. dwRet = ROUTER_UNKNOWN;
  235. else
  236. dwRet = ROUTER_STOP_ROUTING;
  237. }
  238. else {
  239. dwRet = ROUTER_SUCCESS;
  240. }
  241. } else {
  242. dwRet = ROUTER_UNKNOWN;
  243. }
  244. return dwRet;
  245. }
  246. BOOL
  247. SplXcvOpenPort(
  248. PCWSTR pszMachine,
  249. PCWSTR pszObject,
  250. DWORD dwType,
  251. PPRINTER_DEFAULTS pDefault,
  252. PHANDLE phXcv,
  253. PINISPOOLER pIniSpooler
  254. )
  255. {
  256. PINIMONITOR pIniMonitor = NULL;
  257. PINIPORT pIniPort = NULL;
  258. BOOL rc = FALSE;
  259. DWORD dwStatus;
  260. HANDLE hMonitor;
  261. PSPOOL pSpool;
  262. PINIXCV pIniXcv = NULL;
  263. EnterSplSem();
  264. if (dwType == XCVMONITOR) {
  265. pIniMonitor = FindMonitor(pszObject, pIniSpooler);
  266. }
  267. else {
  268. pIniPort = FindPort(pszObject, pIniSpooler);
  269. if(pIniPort && (pIniPort->Status & PP_MONITOR))
  270. pIniMonitor = pIniPort->pIniMonitor;
  271. }
  272. if (pIniMonitor) {
  273. if (!pIniMonitor->Monitor2.pfnXcvOpenPort ||
  274. !pIniMonitor->Monitor2.pfnXcvDataPort ||
  275. !pIniMonitor->Monitor2.pfnXcvClosePort) {
  276. SetLastError(ERROR_INVALID_PRINT_MONITOR);
  277. } else {
  278. //
  279. // Keeping a RefCount on IniMonitor and IniPort while outside CS.
  280. //
  281. INCMONITORREF(pIniMonitor);
  282. LeaveSplSem();
  283. dwStatus = CreateServerHandle( (PWSTR) pszMachine,
  284. phXcv,
  285. pDefault,
  286. pIniSpooler,
  287. PRINTER_HANDLE_XCV_PORT);
  288. EnterSplSem();
  289. if (dwStatus == ROUTER_SUCCESS) { // Create port handle
  290. pSpool = *(PSPOOL *) phXcv; // *phXcv is pSpool
  291. rc = (*pIniMonitor->Monitor2.pfnXcvOpenPort)(
  292. pIniMonitor->hMonitor,
  293. pszObject,
  294. pSpool->GrantedAccess,
  295. &hMonitor);
  296. if (rc) { // Create Spooler XCV entry
  297. pIniXcv = CreateXcvEntry( pszMachine,
  298. pszObject,
  299. pIniMonitor,
  300. pIniSpooler,
  301. hMonitor);
  302. if (pIniXcv) {
  303. pSpool->pIniXcv = pIniXcv;
  304. } else {
  305. (*pIniMonitor->Monitor2.pfnXcvClosePort)(hMonitor);
  306. rc = FALSE;
  307. }
  308. }
  309. }
  310. DECMONITORREF(pIniMonitor);
  311. }
  312. } else {
  313. SetLastError(ERROR_UNKNOWN_PORT);
  314. rc = FALSE;
  315. }
  316. LeaveSplSem();
  317. return rc;
  318. }
  319. PINIXCV
  320. CreateXcvEntry(
  321. PCWSTR pszMachine,
  322. PCWSTR pszName,
  323. PINIMONITOR pIniMonitor,
  324. PINISPOOLER pIniSpooler,
  325. HANDLE hXcv
  326. )
  327. {
  328. PINIXCV pIniXcvPrev = &IniXcvStart;
  329. PINIXCV pIniXcv = IniXcvStart.pNext;
  330. for(; pIniXcv ; pIniXcv = pIniXcv->pNext)
  331. pIniXcvPrev = pIniXcv;
  332. if (!(pIniXcv = (PINIXCV) AllocSplMem(sizeof(INIXCV))))
  333. goto Cleanup;
  334. pIniXcv->hXcv = hXcv;
  335. pIniXcv->signature = XCV_SIGNATURE;
  336. pIniXcv->pIniSpooler = pIniSpooler;
  337. INCSPOOLERREF( pIniSpooler );
  338. if (pszMachine && !(pIniXcv->pszMachineName = AllocSplStr(pszMachine)))
  339. goto Cleanup;
  340. if (pszName && !(pIniXcv->pszName = AllocSplStr(pszName)))
  341. goto Cleanup;
  342. pIniXcv->pIniMonitor = pIniMonitor;
  343. //
  344. // During the lifespan of the IniXcv we keep a Refcount on the IniMonitor
  345. //
  346. INCMONITORREF(pIniXcv->pIniMonitor);
  347. return pIniXcvPrev->pNext = pIniXcv;
  348. Cleanup:
  349. DeleteXcvEntry( pIniXcv );
  350. return NULL;
  351. }
  352. VOID
  353. DeleteXcvEntry(
  354. PINIXCV pIniXcv
  355. )
  356. {
  357. if( pIniXcv ){
  358. if( pIniXcv->pIniSpooler ){
  359. DECSPOOLERREF( pIniXcv->pIniSpooler );
  360. }
  361. //
  362. // Release the IniMonitor
  363. //
  364. if (pIniXcv->pIniMonitor)
  365. {
  366. DECMONITORREF(pIniXcv->pIniMonitor);
  367. }
  368. FreeSplStr(pIniXcv->pszMachineName);
  369. FreeSplStr(pIniXcv->pszName);
  370. FreeSplMem(pIniXcv);
  371. }
  372. }
  373. BOOL
  374. XcvClose(
  375. PINIXCV pIniXcvIn
  376. )
  377. {
  378. PINIXCV pIniXcvPrev = &IniXcvStart;
  379. PINIXCV pIniXcv = IniXcvStart.pNext;
  380. BOOL bRet;
  381. for(; pIniXcv ; pIniXcv = pIniXcv->pNext) {
  382. if (pIniXcv == pIniXcvIn) {
  383. bRet = pIniXcv->pIniMonitor->Monitor2.pfnXcvClosePort(pIniXcv->hXcv);
  384. if (bRet) {
  385. pIniXcvPrev->pNext = pIniXcv->pNext;
  386. DeleteXcvEntry( pIniXcv );
  387. }
  388. return bRet;
  389. }
  390. pIniXcvPrev = pIniXcv;
  391. }
  392. SetLastError(ERROR_INVALID_HANDLE);
  393. return FALSE;
  394. }
  395. BOOL
  396. XcvDeletePort(
  397. PINIXCV pIniXcv,
  398. PCWSTR pszDataName,
  399. PBYTE pInputData,
  400. DWORD cbInputData,
  401. PBYTE pOutputData,
  402. DWORD cbOutputData,
  403. PDWORD pcbOutputNeeded,
  404. PDWORD pdwStatus,
  405. PINISPOOLER pIniSpooler
  406. )
  407. {
  408. PINIPORT pIniPort;
  409. BOOL rc = FALSE;
  410. PWSTR pPortName = (PWSTR) pInputData;
  411. //
  412. // Check to see whether the pInputData is NULL terminated within its buffer
  413. // before going down this path.
  414. //
  415. if (pInputData && cbInputData && IsStringNullTerminatedInBuffer((PWSTR)pInputData, cbInputData / sizeof(WCHAR)))
  416. {
  417. EnterSplSem();
  418. pIniPort = FindPort(pPortName, pIniSpooler);
  419. if ( !pIniPort || !(pIniPort->Status & PP_MONITOR) ) {
  420. SetLastError (*pdwStatus = ERROR_UNKNOWN_PORT);
  421. LeaveSplSem();
  422. return FALSE;
  423. }
  424. rc = DeletePortFromSpoolerStart(pIniPort);
  425. *pdwStatus = GetLastError ();
  426. LeaveSplSem();
  427. if (!rc)
  428. goto Cleanup;
  429. *pdwStatus = (*pIniXcv->pIniMonitor->Monitor2.pfnXcvDataPort)( pIniXcv->hXcv,
  430. pszDataName,
  431. pInputData,
  432. cbInputData,
  433. pOutputData,
  434. cbOutputData,
  435. pcbOutputNeeded);
  436. DeletePortFromSpoolerEnd(pIniPort, pIniSpooler, *pdwStatus == ERROR_SUCCESS);
  437. rc = TRUE;
  438. }
  439. else
  440. {
  441. SetLastError(ERROR_INVALID_PARAMETER);
  442. }
  443. Cleanup:
  444. return rc;
  445. }
  446. BOOL
  447. XcvAddPort(
  448. PINIXCV pIniXcv,
  449. PCWSTR pszDataName,
  450. PBYTE pInputData,
  451. DWORD cbInputData,
  452. PBYTE pOutputData,
  453. DWORD cbOutputData,
  454. PDWORD pcbOutputNeeded,
  455. PDWORD pdwStatus,
  456. PINISPOOLER pIniSpooler
  457. )
  458. {
  459. BOOL rc;
  460. PINIMONITOR pIniMonitor = NULL;
  461. PINIPORT pIniPort = NULL;
  462. pIniMonitor = pIniXcv->pIniMonitor;
  463. if (pIniMonitor) {
  464. *pdwStatus = (*pIniXcv->pIniMonitor->Monitor2.pfnXcvDataPort)( pIniXcv->hXcv,
  465. pszDataName,
  466. pInputData,
  467. cbInputData,
  468. pOutputData,
  469. cbOutputData,
  470. pcbOutputNeeded);
  471. if (*pdwStatus == ERROR_SUCCESS) {
  472. EnterSplSem();
  473. //
  474. // Check to see if we have a placeholder port by the same name. If we
  475. // do this set this as the monitor and revoke its placeholder status.
  476. //
  477. // This pInputData has already been validated by the "Add" method in
  478. // XcvData itself.
  479. //
  480. pIniPort = FindPort(pInputData, pIniSpooler);
  481. if (pIniPort && pIniPort->Status & PP_PLACEHOLDER)
  482. {
  483. pIniPort->pIniMonitor = pIniMonitor;
  484. pIniPort->Status |= PP_MONITOR;
  485. pIniPort->Status &= ~PP_PLACEHOLDER;
  486. }
  487. else
  488. {
  489. CreatePortEntry((PWSTR) pInputData, pIniMonitor, pIniSpooler);
  490. }
  491. LeaveSplSem();
  492. }
  493. rc = TRUE;
  494. } else {
  495. SetLastError(ERROR_INVALID_NAME);
  496. rc = FALSE;
  497. }
  498. return rc;
  499. }
  500. BOOL
  501. ValidateXcvHandle(
  502. PINIXCV pIniXcv
  503. )
  504. {
  505. BOOL ReturnValue;
  506. try {
  507. if (!pIniXcv || pIniXcv->signature != XCV_SIGNATURE) {
  508. ReturnValue = FALSE;
  509. } else {
  510. ReturnValue = TRUE;
  511. }
  512. }except (1) {
  513. ReturnValue = FALSE;
  514. }
  515. if ( !ReturnValue )
  516. SetLastError( ERROR_INVALID_HANDLE );
  517. return ReturnValue;
  518. }