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.

697 lines
19 KiB

  1. /*****************************************************************************\
  2. * MODULE: inetpp.c
  3. *
  4. * The module contains routines for handling the INETPP functionality. Use
  5. * of these routines require the locking/unlocking of a critical-section
  6. * to maninpulate the INIMONPORT list. All internal routines assume the
  7. * crit-sect is locked prior to executing. CheckMonCrit() is a debugging
  8. * call to verify the monitor-crit-sect is locked.
  9. *
  10. * NOTE: Each of the Inetmon* calls must be protected by the global-crit-sect.
  11. * If a new routine is added to this module which is to be called from
  12. * another module, be sure to include the call to (semCheckCrit), so
  13. * that the debug-code can catch unprotected access.
  14. *
  15. * Copyright (C) 1996-1997 Microsoft Corporation
  16. * Copyright (C) 1996-1997 Hewlett Packard
  17. *
  18. * History:
  19. * 07-Oct-1996 HWP-Guys Initiated port from win95 to winNT
  20. * 14-Nov-1997 ChrisWil Added local-spooling functionality.
  21. * 10-Jul-1998 WeihaiC Change Authentication Dialog Code
  22. *
  23. \*****************************************************************************/
  24. #include "precomp.h"
  25. #include "priv.h"
  26. CInetMon::CInetMon ()
  27. {
  28. // Initialize the monitor-port-list.
  29. //
  30. m_pPortList = (PINIMONPORTLIST)memAlloc(sizeof(INIMONPORTLIST));
  31. m_bValid = (m_pPortList != NULL);
  32. }
  33. CInetMon::~CInetMon ()
  34. {
  35. }
  36. /*****************************************************************************\
  37. * _inet_validate_portname (Local Routine)
  38. *
  39. * Validate the portname.
  40. *
  41. * NOTE: If this check becomes more rigorous, it must account for the (%)
  42. * character (escape).
  43. *
  44. \*****************************************************************************/
  45. BOOL
  46. CInetMon::_inet_validate_portname(
  47. LPCTSTR lpszPortName)
  48. {
  49. if (lpszPortName && (*lpszPortName))
  50. return TRUE;
  51. DBG_MSG(DBG_LEV_ERROR, (TEXT("Err : _inet_validate_portname : Invalid Name")));
  52. SetLastError(ERROR_INVALID_NAME);
  53. return FALSE;
  54. }
  55. /*****************************************************************************\
  56. * _inet_find_port (Local Routine)
  57. *
  58. * Locates the entry in the list where the port-name resides. Return the
  59. * full entry-type (INIMONPORT) for the location.
  60. *
  61. \*****************************************************************************/
  62. PCINETMONPORT
  63. CInetMon::_inet_find_port(
  64. LPCTSTR lpszPortName)
  65. {
  66. PCINETMONPORT pIniPort;
  67. pIniPort = m_pPortList->pIniFirstPort;
  68. while (pIniPort && lstrcmpi(lpszPortName, pIniPort->m_lpszName))
  69. pIniPort = pIniPort->m_pNext;
  70. return pIniPort;
  71. }
  72. /*****************************************************************************\
  73. * _inet_create_port (Local Routine)
  74. *
  75. * Create a new port data structure and link into the list. This routine
  76. * assumes that the Crit is held.
  77. *
  78. * This routine also assumes the pszPortName is a valid http:// format.
  79. *
  80. \*****************************************************************************/
  81. PCINETMONPORT
  82. CInetMon::_inet_create_port(
  83. LPCTSTR lpszPortName,
  84. PCPORTMGR pPortMgr)
  85. {
  86. PCINETMONPORT pIniPort;
  87. PCINETMONPORT pPort;
  88. BOOL bRet = FALSE;
  89. if ((pIniPort = new CInetMonPort (lpszPortName, g_szLocalPort, pPortMgr)) &&
  90. pIniPort->bValid ()) {
  91. // Set the link. If this is the first port added, the
  92. // we set the global variable.
  93. //
  94. if (pPort = m_pPortList->pIniFirstPort) {
  95. while (pPort->GetNext())
  96. pPort = pPort->GetNext();
  97. pPort->SetNext (pIniPort);
  98. } else {
  99. m_pPortList->pIniFirstPort = pIniPort;
  100. }
  101. bRet = TRUE;
  102. }
  103. if (!bRet) {
  104. if (pIniPort) {
  105. delete pIniPort;
  106. pIniPort = NULL;
  107. }
  108. }
  109. return pIniPort;
  110. }
  111. /*****************************************************************************\
  112. * _inet_delete_port (Local Routine)
  113. *
  114. * Free a port data structure that is no longer needed.
  115. *
  116. \*****************************************************************************/
  117. BOOL
  118. CInetMon::_inet_delete_port(
  119. LPCTSTR lpszPortName)
  120. {
  121. PCINETMONPORT pIniPort;
  122. PCINETMONPORT pPrvPort;
  123. BOOL bRet = FALSE;
  124. // Keep track of our previous/current entries, so that
  125. // we can remove the specified port.
  126. //
  127. pIniPort = m_pPortList->pIniFirstPort;
  128. while (pIniPort && lstrcmpi(pIniPort->m_lpszName, lpszPortName)) {
  129. pPrvPort = pIniPort;
  130. pIniPort = pIniPort->GetNext ();
  131. }
  132. // If the PortName is found, then delete it.
  133. //
  134. if (pIniPort) {
  135. if (pIniPort->m_cRef > 0 && pIniPort->m_hTerminateEvent) {
  136. // To tell spooling thread to terminate
  137. //
  138. SetEvent (pIniPort->m_hTerminateEvent);
  139. semSafeLeaveCrit(pIniPort);
  140. //
  141. // Leave the critical section so that the spooling thread can decrease the ref count
  142. //
  143. Sleep (250);
  144. semSafeEnterCrit (pIniPort);
  145. }
  146. // Only allow this port to be deleted if the reference count
  147. // is at zero.
  148. //
  149. if (pIniPort->m_cRef == 0) {
  150. pIniPort->m_bDeletePending = TRUE;
  151. //
  152. // Remove the pointer from the list
  153. //
  154. // If this is our first-port then we need to handle
  155. // differently as we keep a global-pointer to this.
  156. //
  157. if (pIniPort == m_pPortList->pIniFirstPort) {
  158. m_pPortList->pIniFirstPort = pIniPort->GetNext();
  159. } else {
  160. pPrvPort->SetNext(pIniPort->GetNext());
  161. }
  162. // We only free the memeory if there are no open handles
  163. //
  164. if (pIniPort->m_cPrinterRef == 0) {
  165. DBG_MSG(DBG_LEV_INFO, (TEXT("Info: pIniPort Freed %p."), pIniPort));
  166. delete pIniPort;
  167. }
  168. bRet = TRUE;
  169. } else {
  170. DBG_MSG(DBG_LEV_WARN, (TEXT("Warn: _inet_delete_port: Port in use: Name(%s)"), lpszPortName));
  171. SetLastError(ERROR_BUSY);
  172. }
  173. } else {
  174. DBG_MSG(DBG_LEV_WARN, (TEXT("Warn: _inet_delete_port: Unrecognized PortName: Name(%s)"), lpszPortName));
  175. SetLastError(ERROR_UNKNOWN_PORT);
  176. }
  177. return bRet;
  178. }
  179. /*****************************************************************************\
  180. * _inet_is_xcv_open
  181. *
  182. * Check whether it is a XCV Open
  183. *
  184. \*****************************************************************************/
  185. BOOL
  186. CInetMon::_inet_is_xcv_open (
  187. LPCTSTR lpszPortName,
  188. LPTSTR *ppszServerName,
  189. LPTSTR *ppszRealPortName,
  190. LPBOOL pbXcv)
  191. {
  192. static CONST TCHAR cchSlash = _T ('\\');
  193. static CONST TCHAR cszXcvPort[] = _T (",XcvPort ");
  194. static CONST DWORD cdwXcvPortLen = (sizeof (cszXcvPort) / sizeof (TCHAR)) - 1;
  195. BOOL bRet = TRUE;
  196. LPCTSTR pServerStart = NULL;
  197. LPTSTR pServerEnd = NULL;
  198. LPTSTR pszServerName = NULL;
  199. LPTSTR pszRealPortName = NULL;
  200. // "\\Server\,XcvPort Object_" */
  201. DWORD dwLen = lstrlen (lpszPortName);
  202. *pbXcv = FALSE;
  203. if (dwLen > cdwXcvPortLen + 1) {
  204. if (lpszPortName[0] == _T (',')) {
  205. // No Server
  206. pServerEnd = (LPTSTR) lpszPortName;
  207. }
  208. else if (lpszPortName[0] == cchSlash && lpszPortName[1] == cchSlash) {
  209. pServerStart = lpszPortName + 2;
  210. if (pServerEnd = _tcschr (pServerStart, cchSlash))
  211. pServerEnd ++;
  212. }
  213. else {
  214. return bRet;
  215. }
  216. if (pServerEnd && ! _tcsncmp (pServerEnd, cszXcvPort, cdwXcvPortLen)) {
  217. LPCTSTR pPortStart = pServerEnd + cdwXcvPortLen;
  218. if (pServerStart) {
  219. pszServerName = new TCHAR [(pServerEnd - 1) - pServerStart + 1];
  220. if (!pszServerName) {
  221. bRet = FALSE;
  222. }
  223. else {
  224. StringCchCopy(pszServerName, pServerEnd - 1 - pServerStart, pServerStart);
  225. pszServerName[pServerEnd - 1 - pServerStart] = 0;
  226. }
  227. }
  228. if (bRet) {
  229. size_t uSize = lstrlen (pPortStart) + 1;
  230. pszRealPortName = new TCHAR [uSize];
  231. if (!pszRealPortName)
  232. bRet = FALSE;
  233. else {
  234. if (SUCCEEDED(StringCchCopy(pszRealPortName, uSize, pPortStart)))
  235. *pbXcv = TRUE;
  236. else
  237. bRet = FALSE;
  238. }
  239. }
  240. if (!bRet) {
  241. if (pszServerName) {
  242. delete [] pszServerName;
  243. pszServerName = NULL;
  244. }
  245. if (pszRealPortName) {
  246. delete [] pszRealPortName;
  247. pszRealPortName = NULL;
  248. }
  249. }
  250. *ppszServerName = pszServerName;
  251. *ppszRealPortName = pszRealPortName;
  252. }
  253. }
  254. return bRet;
  255. }
  256. PCINETMONPORT
  257. CInetMon::InetmonOpenPort(
  258. LPCTSTR lpszPortName,
  259. PBOOL pbXcv)
  260. {
  261. PCINETMONPORT pIniPort = NULL;
  262. PCPORTMGR pPortMgr = NULL;
  263. DWORD dwLE;
  264. *pbXcv = FALSE;
  265. semCheckCrit();
  266. if (_inet_validate_portname(lpszPortName)) {
  267. // Let's first look to see if it is a XCV call
  268. LPTSTR pszServerName = NULL;
  269. LPTSTR pszRealPortName = NULL;
  270. BOOL bXcv;
  271. if (_inet_is_xcv_open (lpszPortName, &pszServerName, &pszRealPortName, &bXcv) && bXcv) {
  272. if (pIniPort = _inet_find_port(pszRealPortName)) {
  273. if (!pIniPort->m_bDeletePending) {
  274. // The refrernce to the iniport is not changed, since the client may open a XCV handle
  275. // to delete the port
  276. //
  277. *pbXcv = TRUE;
  278. }
  279. else {
  280. DBG_MSG(DBG_LEV_ERROR, (TEXT("Err : InetmonOpenPort (XCV) : Open deleted port: Port(%s)"), lpszPortName));
  281. SetLastError(ERROR_INVALID_NAME);
  282. }
  283. }
  284. // This is a valid XcvOpen
  285. if (pszServerName) {
  286. delete [] pszServerName;
  287. }
  288. if (pszRealPortName) {
  289. delete [] pszRealPortName;
  290. }
  291. if (pIniPort)
  292. {
  293. return pIniPort;
  294. }
  295. }
  296. // Let's first look to see if this port is already in the
  297. // list. If not, then add it to the list and continue with
  298. // the open.
  299. //
  300. if ((pIniPort = _inet_find_port(lpszPortName)) == NULL) {
  301. semLeaveCrit();
  302. // Leave the critical section becuase the following call will hit the network
  303. pPortMgr = new CPortMgr;
  304. if (pPortMgr != NULL) {
  305. if (! pPortMgr->Create (lpszPortName)) {
  306. delete (pPortMgr);
  307. pPortMgr = NULL;
  308. }
  309. }
  310. dwLE = GetLastError ();
  311. semEnterCrit();
  312. if (! (pPortMgr)) {
  313. // The connection is invalid
  314. DBG_MSG(DBG_LEV_ERROR, (TEXT("Err: InetmonOpenPort : PortMgrCreate Failed: LastError(%d)"), GetLastError()));
  315. if (dwLE != ERROR_ACCESS_DENIED &&
  316. dwLE != ERROR_INVALID_PRINTER_NAME &&
  317. dwLE != ERROR_INVALID_NAME) {
  318. dwLE = ERROR_PRINTER_NOT_FOUND;
  319. }
  320. SetLastError ( dwLE );
  321. goto exit_openport;
  322. }
  323. if (_inet_create_port(lpszPortName, pPortMgr) == FALSE) {
  324. DBG_MSG(DBG_LEV_ERROR, (TEXT("Err: InetmonOpenPort : Add Port Failed: LastError(%d)"), GetLastError()));
  325. SetLastError(ERROR_INVALID_NAME);
  326. goto exit_openport;
  327. }
  328. }
  329. if (pIniPort || (pIniPort = _inet_find_port(lpszPortName))) {
  330. if (!pIniPort->m_bDeletePending) {
  331. //
  332. // We stop increasing the ref count since the open handles
  333. // won't have affect on the port deletion, i.e. the port
  334. // may be deleted even when there are open handles.
  335. //
  336. // pIniPort->m_cRef ++;
  337. //
  338. // Increase the printer open handle ref count. This
  339. // count is used to manage the life time of the PCINETMONPORT
  340. // data structure. i.e. if the port is deleted when there are
  341. // open handles, PCINETMONPORT is not freed until
  342. //
  343. // pIniPort->m_cPrinterRef == 0
  344. //
  345. pIniPort->IncPrinterRef ();
  346. }
  347. else {
  348. DBG_MSG(DBG_LEV_ERROR, (TEXT("Err : InetmonOpenPort : Open deleted port: Port(%s)"), lpszPortName));
  349. SetLastError(ERROR_INVALID_NAME);
  350. }
  351. } else {
  352. DBG_MSG(DBG_LEV_ERROR, (TEXT("Err : InetmonOpenPort : Invalid Name: Port(%s)"), lpszPortName));
  353. SetLastError(ERROR_INVALID_NAME);
  354. }
  355. }
  356. exit_openport:
  357. return pIniPort;
  358. }
  359. BOOL
  360. CInetMon::InetmonReleasePort(
  361. PCINETMONPORT pIniPort)
  362. {
  363. DBG_MSG(DBG_LEV_CALLTREE, (TEXT("Call: InetmonReleasePort: pIniPort(%08lX)"), pIniPort));
  364. semCheckCrit();
  365. // Validate the port and proceed to close the port.
  366. //
  367. pIniPort->DecPrinterRef ();
  368. if (pIniPort->m_bDeletePending && pIniPort->m_cPrinterRef == 0) {
  369. //
  370. // There is no open handles, free PCINETMONPORT
  371. //
  372. DBG_MSG(DBG_LEV_INFO, (TEXT("Info: InetmonReleasePort free pIniPort %p."), pIniPort));
  373. delete pIniPort;
  374. }
  375. return TRUE;
  376. }
  377. /*****************************************************************************\
  378. * InetmonClosePort
  379. *
  380. * Close the internet connection.
  381. *
  382. \*****************************************************************************/
  383. BOOL
  384. CInetMon::InetmonClosePort(
  385. PCINETMONPORT pIniPort,
  386. HANDLE hPrinter)
  387. {
  388. DBG_MSG(DBG_LEV_CALLTREE, (TEXT("Call: InetmonClosePort: pIniPort(%08lX)"), pIniPort));
  389. semCheckCrit();
  390. pIniPort->ClosePort (hPrinter);
  391. if (pIniPort->m_bDeletePending && pIniPort->m_cPrinterRef == 0) {
  392. //
  393. // There is no open handles, free PCINETMONPORT
  394. //
  395. DBG_MSG(DBG_LEV_INFO, (TEXT("Info: pIniPort Freed %p."), pIniPort));
  396. delete pIniPort;
  397. }
  398. return TRUE;
  399. }
  400. /*****************************************************************************\
  401. * InetmonEnumPorts
  402. *
  403. * Enumerate the ports registered in our list.
  404. *
  405. \*****************************************************************************/
  406. BOOL
  407. CInetMon::InetmonEnumPorts(
  408. LPTSTR lpszServerName,
  409. DWORD dwLevel,
  410. LPBYTE pPorts,
  411. DWORD cbBuf,
  412. LPDWORD pcbNeeded,
  413. LPDWORD pcReturned)
  414. {
  415. PCINETMONPORT pIniPort;
  416. DWORD cb;
  417. LPBYTE pEnd;
  418. DWORD dwError = ERROR_SUCCESS;
  419. semCheckCrit();
  420. // Traverse the list to build the size of the entire list.
  421. //
  422. cb = 0;
  423. pIniPort = m_pPortList->pIniFirstPort;
  424. while (pIniPort) {
  425. cb += pIniPort->_inet_size_entry(dwLevel);
  426. pIniPort = pIniPort->m_pNext;
  427. }
  428. // Store the size of the list (This is the size needed).
  429. //
  430. *pcbNeeded = cb;
  431. // If the size of the list is capable of being stored in the buffer
  432. // passed in, then we can return the entries.
  433. //
  434. if (cb <= cbBuf) {
  435. pEnd = pPorts + cbBuf;
  436. *pcReturned = 0;
  437. pIniPort = m_pPortList->pIniFirstPort;
  438. while (pIniPort) {
  439. pEnd = pIniPort->_inet_copy_entry(dwLevel, pPorts, pEnd);
  440. switch (dwLevel) {
  441. case PRINT_LEVEL_1:
  442. pPorts += sizeof(PORT_INFO_1);
  443. break;
  444. case PRINT_LEVEL_2:
  445. pPorts += sizeof(PORT_INFO_2);
  446. break;
  447. }
  448. pIniPort = pIniPort->m_pNext;
  449. (*pcReturned)++;
  450. }
  451. } else {
  452. dwError = ERROR_INSUFFICIENT_BUFFER;
  453. }
  454. if (dwError != ERROR_SUCCESS) {
  455. SetLastError(dwError);
  456. return FALSE;
  457. }
  458. return TRUE;
  459. }
  460. /*****************************************************************************\
  461. * InetmonDeletePort
  462. *
  463. * Deletes a port from the INIMONPORT list.
  464. *
  465. \*****************************************************************************/
  466. BOOL
  467. CInetMon::InetmonDeletePort(
  468. LPCTSTR lpszPortName,
  469. HWND hWnd,
  470. LPCTSTR lpszMonitorName)
  471. {
  472. BOOL bRet = FALSE;
  473. semCheckCrit();
  474. if (_inet_validate_portname(lpszPortName))
  475. bRet = _inet_delete_port(lpszPortName);
  476. return bRet;
  477. }
  478. /*****************************************************************************\
  479. * InetmonAddPort
  480. *
  481. * Adds a port to the INIMONPORT list.
  482. *
  483. \*****************************************************************************/
  484. BOOL
  485. CInetMon::InetmonAddPort(
  486. LPCTSTR lpszPortName,
  487. LPCTSTR lpszMonitorName)
  488. {
  489. BOOL bRet = FALSE;
  490. PCPORTMGR pPortMgr = NULL;
  491. semCheckCrit();
  492. // If the port is not-found, then we can add it. Otherwise,
  493. // the port already exists.
  494. //
  495. if (_inet_validate_portname(lpszPortName)) {
  496. if (_inet_find_port(lpszPortName) == NULL) {
  497. pPortMgr = new CPortMgr;
  498. if (pPortMgr != NULL) {
  499. if (!pPortMgr->Init (lpszPortName)) {
  500. delete pPortMgr;
  501. pPortMgr = NULL;
  502. }
  503. if (pPortMgr) {
  504. bRet = (_inet_create_port(lpszPortName, pPortMgr) != NULL);
  505. }
  506. }
  507. }
  508. }
  509. return bRet;
  510. }
  511. /*****************************************************************************\
  512. * InetmonFindPort
  513. *
  514. * Looks for port in INIMONPORT list.
  515. *
  516. \*****************************************************************************/
  517. PCINETMONPORT
  518. CInetMon::InetmonFindPort(
  519. LPCTSTR lpszPortName)
  520. {
  521. PCINETMONPORT hPort = NULL;
  522. semCheckCrit();
  523. if (_inet_validate_portname(lpszPortName))
  524. hPort = _inet_find_port(lpszPortName) ;
  525. return hPort;
  526. }
  527. /********************************************************************************
  528. ** End of FIle (inetpp.c)
  529. ********************************************************************************/