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.

705 lines
15 KiB

  1. /********************************************************************/
  2. /** Copyright(c) 1989 Microsoft Corporation. **/
  3. /********************************************************************/
  4. //***
  5. //
  6. // Filename: port.c
  7. //
  8. // Description: This module contains the entry points for the AppleTalk
  9. // monitor that manipulate ports.
  10. //
  11. // The following are the functions contained in this module.
  12. // All these functions are exported.
  13. //
  14. // OpenPort
  15. // ClosePort
  16. // EnumPortsW
  17. // AddPortW
  18. // ConfigurePortW
  19. // DeletePortW
  20. //
  21. // History:
  22. //
  23. // Aug 26,1992 frankb Initial version
  24. // June 11,1993. NarenG Bug fixes/clean up
  25. //
  26. #include <windows.h>
  27. #include <winspool.h>
  28. #include <winsplp.h>
  29. #include <winsock.h>
  30. #include <atalkwsh.h>
  31. #include <stdlib.h>
  32. #include <stdio.h>
  33. #include <string.h>
  34. #include <lmcons.h>
  35. #include <prtdefs.h>
  36. #include "atalkmon.h"
  37. #include "atmonmsg.h"
  38. #include <bltrc.h>
  39. #include "dialogs.h"
  40. //**
  41. //
  42. // Call: AddPort
  43. //
  44. // Returns: TRUE - Success
  45. // FALSE - False
  46. //
  47. // Description:
  48. // This routine is called when the user selects 'other...'
  49. // from the port list of the print manager. It presents a browse
  50. // dialog to the user to allow the user to locate a LaserWriter
  51. // on the AppleTalk network.
  52. //
  53. BOOL
  54. AddPort(
  55. IN LPWSTR pName,
  56. IN HWND hwnd,
  57. IN LPWSTR pMonitorName
  58. ){
  59. PATALKPORT pNewPort;
  60. PATALKPORT pWalker;
  61. HANDLE hToken;
  62. DWORD dwRetCode;
  63. INT i=0;
  64. DBGPRINT(("Entering AddPort\n")) ;
  65. //
  66. // Allocate an initialized port
  67. //
  68. if ( ( pNewPort = AllocAndInitializePort()) == NULL )
  69. {
  70. SetLastError( ERROR_NOT_ENOUGH_MEMORY );
  71. return( FALSE );
  72. }
  73. //
  74. // Set up the query socket. If this fails we assume that it is because
  75. // the stack is not started and we let the Add Port dialogs bring
  76. // up the error
  77. //
  78. if ( OpenAndBindAppleTalkSocket( &(pNewPort->sockQuery) ) != NO_ERROR )
  79. pNewPort->sockQuery = INVALID_SOCKET;
  80. if ( !AddPortDialog( hwnd, pNewPort ) )
  81. {
  82. //
  83. // If the dialog failed for some reason then we just return. The
  84. // dialog has taken care of displaying an error popup.
  85. //
  86. if ( pNewPort->sockQuery != INVALID_SOCKET )
  87. {
  88. closesocket( pNewPort->sockQuery );
  89. pNewPort->sockQuery = INVALID_SOCKET;
  90. }
  91. FreeAppleTalkPort( pNewPort );
  92. DBGPRINT(("AddPortDialog returns not OK\n")) ;
  93. return( TRUE );
  94. }
  95. //
  96. // Clean up the query socket
  97. //
  98. closesocket( pNewPort->sockQuery );
  99. pNewPort->sockQuery = INVALID_SOCKET;
  100. WaitForSingleObject( hmutexPortList, INFINITE );
  101. do {
  102. //
  103. // walk the list and make sure we are not a duplicate
  104. //
  105. dwRetCode = NO_ERROR;
  106. for( pWalker = pPortList; pWalker != NULL; pWalker = pWalker->pNext )
  107. {
  108. if ( _wcsicmp( pWalker->pPortName, pNewPort->pPortName ) == 0 )
  109. {
  110. dwRetCode = ERROR_ALREADY_EXISTS;
  111. break;
  112. }
  113. }
  114. //
  115. // check if the key name does not contain "\", else the
  116. // key name will be broken up over various levels
  117. // Reject such a name
  118. //
  119. i=0;
  120. while (pNewPort->pPortName[i] != L'\0')
  121. {
  122. if (pNewPort->pPortName[i] == L'\\')
  123. {
  124. dwRetCode = ERROR_INVALID_PRINTER_NAME;
  125. DBGPRINT(("sfmmon: AddPort: Detected invalid character in port %ws to be added, rejecting port addition\n", pNewPort->pPortName));
  126. break;
  127. }
  128. i++;
  129. }
  130. if ( dwRetCode != NO_ERROR )
  131. {
  132. break;
  133. }
  134. //
  135. // add port to registry
  136. //
  137. hToken = RevertToPrinterSelf();
  138. dwRetCode = CreateRegistryPort( pNewPort );
  139. if (hToken)
  140. {
  141. if (!ImpersonatePrinterClient( hToken ))
  142. {
  143. dwRetCode = ERROR_CANNOT_IMPERSONATE;
  144. }
  145. }
  146. if ( dwRetCode != NO_ERROR )
  147. {
  148. break;
  149. }
  150. //
  151. // Add port to our list
  152. //
  153. pNewPort->pNext = pPortList;
  154. pPortList = pNewPort;
  155. } while ( FALSE );
  156. ReleaseMutex( hmutexPortList );
  157. if ( dwRetCode != NO_ERROR )
  158. {
  159. SetLastError( dwRetCode );
  160. FreeAppleTalkPort( pNewPort );
  161. return( FALSE );
  162. }
  163. SetEvent( hevConfigChange );
  164. return( TRUE );
  165. }
  166. //**
  167. //
  168. // Call: DeletePort
  169. //
  170. // Returns: TRUE - Success
  171. // FALSE - Failure
  172. //
  173. // Description:
  174. // This routine is called by the print manager to remove
  175. // a port from our configuration. Need to verify that it can only
  176. // be called when the port is not active, or we need to resolve
  177. // the issue of deleting an active port. DeletePort will release
  178. // the printer if it is captured.
  179. BOOL
  180. DeletePort(
  181. IN LPWSTR pName,
  182. IN HWND hwnd,
  183. IN LPWSTR pPortName
  184. ){
  185. PATALKPORT pPrevious;
  186. PATALKPORT pWalker;
  187. HANDLE hToken;
  188. DWORD dwRetCode = ERROR_UNKNOWN_PORT;
  189. DBGPRINT(("Entering DeletePort\n")) ;
  190. WaitForSingleObject( hmutexPortList, INFINITE );
  191. for ( pWalker = pPortList, pPrevious = pPortList;
  192. pWalker != NULL;
  193. pPrevious = pWalker,
  194. pWalker = pWalker->pNext )
  195. {
  196. if ( _wcsicmp( pPortName, pWalker->pPortName ) == 0 )
  197. {
  198. if ( pWalker->fPortFlags & SFM_PORT_IN_USE )
  199. {
  200. dwRetCode = ERROR_DEVICE_IN_USE;
  201. break;
  202. }
  203. //
  204. // remove from registry
  205. //
  206. hToken = RevertToPrinterSelf();
  207. dwRetCode = RegDeleteKey( hkeyPorts, pPortName );
  208. if (hToken)
  209. {
  210. if (!ImpersonatePrinterClient( hToken ))
  211. {
  212. dwRetCode = ERROR_CANNOT_IMPERSONATE;
  213. }
  214. }
  215. if ( dwRetCode != ERROR_SUCCESS )
  216. {
  217. break;
  218. }
  219. //
  220. // Remove from active list
  221. //
  222. if ( pWalker == pPortList )
  223. pPortList = pPortList->pNext;
  224. else
  225. pPrevious->pNext = pWalker->pNext;
  226. //
  227. // Put it in the delete list
  228. //
  229. WaitForSingleObject( hmutexDeleteList, INFINITE );
  230. pWalker->pNext = pDeleteList;
  231. pDeleteList = pWalker;
  232. ReleaseMutex( hmutexDeleteList );
  233. break;
  234. }
  235. }
  236. ReleaseMutex( hmutexPortList );
  237. if ( dwRetCode != NO_ERROR )
  238. {
  239. SetLastError( dwRetCode );
  240. return( FALSE );
  241. }
  242. SetEvent( hevConfigChange );
  243. return( TRUE );
  244. }
  245. //**
  246. //
  247. // Call: EnumPorts
  248. //
  249. // Returns: TRUE - Success
  250. // FALSE - Failure
  251. //
  252. // Description:
  253. // EnumPorts is called by the print manager to get
  254. // information about all configured ports for the monitor.
  255. BOOL
  256. EnumPorts(
  257. IN LPWSTR pName,
  258. IN DWORD dwLevel,
  259. IN LPBYTE pPorts,
  260. IN DWORD cbBuf,
  261. OUT LPDWORD pcbNeeded,
  262. OUT PDWORD pcReturned
  263. )
  264. {
  265. PATALKPORT pWalker;
  266. LPWSTR pNames;
  267. *pcReturned = 0;
  268. *pcbNeeded = 0;
  269. //
  270. // validate parameters
  271. //
  272. if ( dwLevel != 1 && dwLevel != 2 )
  273. {
  274. SetLastError( ERROR_INVALID_LEVEL );
  275. return( FALSE );
  276. }
  277. //
  278. // get size needed
  279. //
  280. WaitForSingleObject( hmutexPortList, INFINITE );
  281. for ( pWalker = pPortList; pWalker != NULL; pWalker = pWalker->pNext )
  282. {
  283. if ( dwLevel == 1 )
  284. {
  285. *pcbNeeded += ((sizeof(WCHAR) * (wcslen(pWalker->pPortName) + 1))
  286. + sizeof(PORT_INFO_1));
  287. }
  288. else // if ( dwLevel == 2 )
  289. {
  290. *pcbNeeded += ((sizeof(WCHAR) * (wcslen(pWalker->pPortName) + 1))
  291. + sizeof(WCHAR) * (wcslen (wchPortDescription) + 1)+
  292. + sizeof(WCHAR) * (wcslen (wchDllName) + 1) +
  293. + sizeof (PORT_INFO_2));
  294. }
  295. }
  296. DBGPRINT(("buffer size needed=%d\n", *pcbNeeded)) ;
  297. //
  298. // if buffer too small, return error
  299. //
  300. if ( ( *pcbNeeded > cbBuf ) || ( pPorts == NULL ))
  301. {
  302. SetLastError( ERROR_INSUFFICIENT_BUFFER );
  303. DBGPRINT(("insufficient buffer\n"));
  304. ReleaseMutex( hmutexPortList );
  305. return( FALSE );
  306. }
  307. //
  308. // fill the buffer
  309. //
  310. DBGPRINT(("attempting to copy to buffer\n")) ;
  311. for ( pWalker = pPortList, pNames = (LPWSTR)(pPorts+cbBuf);
  312. pWalker != NULL;
  313. pWalker = pWalker->pNext )
  314. {
  315. if ( dwLevel == 1)
  316. {
  317. DWORD dwLen;
  318. PPORT_INFO_1 pPortInfo1 = (PPORT_INFO_1)pPorts;
  319. DBGPRINT(("copying %ws\n", pWalker->pPortName)) ;
  320. #if 0
  321. pNames -= ( wcslen( pWalker->pPortName ) + 1 );
  322. wcscpy( (LPWSTR)pNames, pWalker->pPortName );
  323. pPortInfo->pName = pNames;
  324. pPorts += sizeof (PORT_INFO_1);
  325. #endif
  326. dwLen = wcslen (pWalker->pPortName) + 1;
  327. pNames -= dwLen;
  328. pPortInfo1->pName = pNames;
  329. wcscpy (pPortInfo1->pName, pWalker->pPortName);
  330. pPorts += sizeof (PORT_INFO_1);
  331. }
  332. else // if dwLevel == 2
  333. {
  334. DWORD dwLen;
  335. PPORT_INFO_1 pPortInfo1 = (LPPORT_INFO_1)pPorts;
  336. PPORT_INFO_2 pPortInfo2 = (LPPORT_INFO_2)pPorts;
  337. dwLen = wcslen (wchDllName) + 1;
  338. pNames -= dwLen;
  339. pPortInfo2->pMonitorName = (LPWSTR)pNames;
  340. wcscpy (pPortInfo2->pMonitorName, (LPWSTR)wchDllName);
  341. dwLen = wcslen (wchPortDescription) + 1;
  342. pNames -= dwLen;
  343. pPortInfo2->pDescription = (LPWSTR)pNames;
  344. wcscpy (pPortInfo2->pDescription, (LPWSTR)wchPortDescription);
  345. dwLen = wcslen (pWalker->pPortName) + 1;
  346. pNames -= dwLen;
  347. pPortInfo1->pName = (LPWSTR)pNames;
  348. wcscpy(pPortInfo1->pName, pWalker->pPortName);
  349. pPorts += sizeof (PORT_INFO_2);
  350. }
  351. (*pcReturned)++;
  352. }
  353. ReleaseMutex( hmutexPortList );
  354. return( TRUE );
  355. }
  356. //**
  357. //
  358. // Call: OpenPort
  359. //
  360. // Returns: TRUE - Success
  361. // FALSE - Failure
  362. //
  363. // Description:
  364. // This routine is called by the print manager to
  365. // get a handle for a port to be used in subsequent calls
  366. // to read and write data to the port. It opens an AppleTalk
  367. // Address on the server for use in establishing connections
  368. // when a job is sent to print. It looks like the NT Print
  369. // Spooler only calls OpenPort once.
  370. //
  371. // NOTE: In order to allow for the AppleTalk stack to be turned off
  372. // while printing is not happening, OpenPort will not go to the
  373. // stack. Instead, it will just validate the parameters and
  374. // return a handle. The stack will be accessed on StartDocPort.
  375. //
  376. // OpenPort is called whenever a port becomes configured to
  377. // be used by one or more NT Printers. We use this fact to recognize
  378. // when we need to start capturing the printer. This routine sets
  379. // the port state to open and then kicks off a config event to
  380. // capture or release it.
  381. //
  382. BOOL
  383. OpenPort(
  384. IN LPWSTR pName,
  385. IN PHANDLE pHandle
  386. ){
  387. PATALKPORT pWalker;
  388. DBGPRINT(("Entering OpenPort\n")) ;
  389. //
  390. // find the printer in our list
  391. //
  392. WaitForSingleObject( hmutexPortList, INFINITE );
  393. for ( pWalker = pPortList; pWalker != NULL; pWalker = pWalker->pNext )
  394. {
  395. if ( _wcsicmp( pWalker->pPortName, pName ) == 0 )
  396. {
  397. pWalker->fPortFlags |= SFM_PORT_OPEN;
  398. pWalker->fPortFlags &= ~SFM_PORT_CLOSE_PENDING;
  399. break;
  400. }
  401. }
  402. ReleaseMutex( hmutexPortList );
  403. if ( pWalker == NULL )
  404. {
  405. SetLastError( ERROR_UNKNOWN_PORT );
  406. DBGPRINT(("ERROR: Could not find printer %ws\n", pName)) ;
  407. return( FALSE );
  408. }
  409. SetEvent( hevConfigChange );
  410. *pHandle = pWalker;
  411. return( TRUE );
  412. }
  413. //**
  414. //
  415. // Call: ClosePort
  416. //
  417. // Returns: TRUE - Success
  418. // FALSE - Failure
  419. //
  420. // Description:
  421. // This routine is called to release the handle to
  422. // the open port. It looks like the spooler only calls
  423. // ClosePort prior to deleting a port (maybe). Otherwise,
  424. // ports are never closed by the spooler.
  425. //
  426. // This routine simply cleans up the handle and returns.
  427. //
  428. // When the NT spooler recognizes that no printers are configured
  429. // to use a port, it calls ClosePort(). We mark the port status as
  430. // closed, and release the printer if it is captured.
  431. //
  432. BOOL
  433. ClosePort(
  434. IN HANDLE hPort
  435. ){
  436. PATALKPORT pPort = (PATALKPORT)hPort;
  437. PATALKPORT pWalker;
  438. DWORD dwRetCode = ERROR_UNKNOWN_PORT;
  439. DBGPRINT(("Entering ClosePort\n"));
  440. if ( pPort == NULL )
  441. {
  442. SetLastError( ERROR_INVALID_HANDLE );
  443. DBGPRINT(("ERROR: ClosePort on closed handle\n")) ;
  444. return( FALSE );
  445. }
  446. //
  447. // find the printer in our list
  448. //
  449. WaitForSingleObject( hmutexPortList, INFINITE );
  450. for ( pWalker = pPortList; pWalker != NULL; pWalker = pWalker->pNext )
  451. {
  452. if ( _wcsicmp( pWalker->pPortName, pPort->pPortName ) == 0 )
  453. {
  454. if ( pWalker->fPortFlags & SFM_PORT_IN_USE )
  455. dwRetCode = ERROR_BUSY;
  456. else
  457. {
  458. pWalker->fPortFlags &= ~SFM_PORT_OPEN;
  459. pWalker->fPortFlags |= SFM_PORT_CLOSE_PENDING;
  460. pWalker->fPortFlags &= ~SFM_PORT_CAPTURED;
  461. dwRetCode = NO_ERROR;
  462. }
  463. break;
  464. }
  465. }
  466. ReleaseMutex( hmutexPortList );
  467. if ( dwRetCode != NO_ERROR )
  468. {
  469. SetLastError( dwRetCode );
  470. return( FALSE );
  471. }
  472. SetEvent( hevConfigChange );
  473. return( TRUE );
  474. }
  475. //**
  476. //
  477. // Call: ConfigurePort
  478. //
  479. // Returns: TRUE - Success
  480. // FALSE - Failure
  481. //
  482. // Description:
  483. //
  484. BOOL
  485. ConfigurePort(
  486. IN LPWSTR pName,
  487. IN HWND hwnd,
  488. IN LPWSTR pPortName
  489. ){
  490. DWORD dwRetCode;
  491. HANDLE hToken;
  492. BOOL fCapture;
  493. BOOL fIsSpooler;
  494. PATALKPORT pWalker;
  495. DBGPRINT(("Entering ConfigurePort\n")) ;
  496. //
  497. // find the port structure
  498. //
  499. WaitForSingleObject( hmutexPortList, INFINITE );
  500. for ( pWalker = pPortList; pWalker != NULL; pWalker = pWalker->pNext )
  501. {
  502. if ( _wcsicmp( pPortName, pWalker->pPortName ) == 0 )
  503. {
  504. fCapture = pWalker->fPortFlags & SFM_PORT_CAPTURED;
  505. fIsSpooler = pWalker->fPortFlags & SFM_PORT_IS_SPOOLER;
  506. break;
  507. }
  508. }
  509. ReleaseMutex( hmutexPortList );
  510. if ( pWalker == NULL )
  511. {
  512. DBGPRINT(("ERROR: port not found\n")) ;
  513. SetLastError( ERROR_UNKNOWN_PORT );
  514. return( FALSE );
  515. }
  516. //
  517. // configure the port. If there was any error in the dialog, it would
  518. // have been displayed already.
  519. //
  520. if ( !ConfigPortDialog( hwnd, fIsSpooler, &fCapture ) )
  521. return( TRUE );
  522. WaitForSingleObject( hmutexPortList, INFINITE );
  523. do {
  524. for ( pWalker = pPortList; pWalker != NULL; pWalker = pWalker->pNext )
  525. {
  526. if ( _wcsicmp( pPortName, pWalker->pPortName ) == 0 )
  527. break;
  528. }
  529. if ( pWalker == NULL )
  530. {
  531. dwRetCode = ERROR_UNKNOWN_PORT;
  532. break;
  533. }
  534. if ( fCapture )
  535. pWalker->fPortFlags |= SFM_PORT_CAPTURED;
  536. else
  537. pWalker->fPortFlags &= ~SFM_PORT_CAPTURED;
  538. //
  539. // save changes to registry
  540. //
  541. hToken = RevertToPrinterSelf();
  542. dwRetCode = SetRegistryInfo( pWalker );
  543. if (hToken)
  544. {
  545. if (!ImpersonatePrinterClient( hToken ))
  546. {
  547. dwRetCode = ERROR_CANNOT_IMPERSONATE;
  548. }
  549. }
  550. } while( FALSE );
  551. ReleaseMutex( hmutexPortList );
  552. if ( dwRetCode != NO_ERROR )
  553. {
  554. SetLastError( dwRetCode );
  555. return( FALSE );
  556. }
  557. SetEvent( hevConfigChange );
  558. return( TRUE );
  559. }