Source code of Windows XP (NT5)
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.

518 lines
16 KiB

  1. /*************************************************************************
  2. *
  3. * connect.c
  4. *
  5. * This module contains routines for managing TerminalServer connections.
  6. *
  7. * Copyright 1998, Microsoft.
  8. *
  9. *************************************************************************/
  10. /*
  11. * Includes
  12. */
  13. #include <precomp.h>
  14. #pragma hdrstop
  15. NTSTATUS
  16. _IcaCallStack(
  17. IN PICA_STACK pStack,
  18. IN ULONG ProcIndex,
  19. IN OUT PVOID pParms
  20. );
  21. NTSTATUS
  22. IcaDeviceControlConnection (
  23. IN PICA_CONNECTION pConnect,
  24. IN PIRP Irp,
  25. IN PIO_STACK_LOCATION IrpSp
  26. );
  27. NTSTATUS
  28. IcaCleanupConnection (
  29. IN PICA_CONNECTION pConnect,
  30. IN PIRP Irp,
  31. IN PIO_STACK_LOCATION IrpSp
  32. );
  33. NTSTATUS
  34. IcaCloseConnection (
  35. IN PICA_CONNECTION pConnect,
  36. IN PIRP Irp,
  37. IN PIO_STACK_LOCATION IrpSp
  38. );
  39. NTSTATUS
  40. IcaStartStopTrace(
  41. IN PICA_TRACE_INFO pTraceInfo,
  42. IN PICA_TRACE pTrace
  43. );
  44. NTSTATUS
  45. IcaUnbindVirtualChannel(
  46. IN PICA_CONNECTION pConnect,
  47. IN PVIRTUALCHANNELNAME pVirtualName
  48. );
  49. /*
  50. * Local procedure prototypes
  51. */
  52. PICA_CONNECTION _IcaAllocateConnection( VOID );
  53. VOID _IcaFreeConnection( PICA_CONNECTION );
  54. /*
  55. * Dispatch table for ICA connection objects
  56. */
  57. PICA_DISPATCH IcaConnectionDispatchTable[IRP_MJ_MAXIMUM_FUNCTION+1] = {
  58. NULL, // IRP_MJ_CREATE
  59. NULL, // IRP_MJ_CREATE_NAMED_PIPE
  60. IcaCloseConnection, // IRP_MJ_CLOSE
  61. NULL, // IRP_MJ_READ
  62. NULL, // IRP_MJ_WRITE
  63. NULL, // IRP_MJ_QUERY_INFORMATION
  64. NULL, // IRP_MJ_SET_INFORMATION
  65. NULL, // IRP_MJ_QUERY_EA
  66. NULL, // IRP_MJ_SET_EA
  67. NULL, // IRP_MJ_FLUSH_BUFFERS
  68. NULL, // IRP_MJ_QUERY_VOLUME_INFORMATION
  69. NULL, // IRP_MJ_SET_VOLUME_INFORMATION
  70. NULL, // IRP_MJ_DIRECTORY_CONTROL
  71. NULL, // IRP_MJ_FILE_SYSTEM_CONTROL
  72. IcaDeviceControlConnection, // IRP_MJ_DEVICE_CONTROL
  73. NULL, // IRP_MJ_INTERNAL_DEVICE_CONTROL
  74. NULL, // IRP_MJ_SHUTDOWN
  75. NULL, // IRP_MJ_LOCK_CONTROL
  76. IcaCleanupConnection, // IRP_MJ_CLEANUP
  77. NULL, // IRP_MJ_CREATE_MAILSLOT
  78. NULL, // IRP_MJ_QUERY_SECURITY
  79. NULL, // IRP_MJ_SET_SECURITY
  80. NULL, // IRP_MJ_SET_POWER
  81. NULL, // IRP_MJ_QUERY_POWER
  82. };
  83. extern PERESOURCE IcaTraceResource;
  84. // resource used to protect access to the code that start/stops the keep alive thread
  85. PERESOURCE g_pKeepAliveResource;
  86. extern NTSTATUS _IcaKeepAlive(
  87. IN BOOLEAN startKeepAliveThread,
  88. IN ULONG interval );
  89. NTSTATUS
  90. IcaCreateConnection (
  91. IN PIRP Irp,
  92. IN PIO_STACK_LOCATION IrpSp
  93. )
  94. /*++
  95. Routine Description:
  96. This routine is called to create a new ICA_CONNECTION object.
  97. Arguments:
  98. Irp - Pointer to I/O request packet
  99. IrpSp - pointer to the stack location to use for this request.
  100. Return Value:
  101. NTSTATUS -- Indicates whether the request was successfully queued.
  102. --*/
  103. {
  104. PICA_CONNECTION pConnect;
  105. /*
  106. * Allocate a new ICA connect object
  107. */
  108. pConnect = _IcaAllocateConnection();
  109. if ( pConnect == NULL )
  110. return( STATUS_INSUFFICIENT_RESOURCES );
  111. /*
  112. * Save a pointer to the connection in the file object
  113. * so that we can find it in future calls.
  114. */
  115. IrpSp->FileObject->FsContext = pConnect;
  116. IcaDereferenceConnection( pConnect );
  117. return( STATUS_SUCCESS );
  118. }
  119. NTSTATUS
  120. IcaDeviceControlConnection(
  121. IN PICA_CONNECTION pConnect,
  122. IN PIRP Irp,
  123. IN PIO_STACK_LOCATION IrpSp
  124. )
  125. {
  126. ICA_TRACE LocalTrace;
  127. PICA_TRACE_BUFFER pTraceBuffer;
  128. ULONG code;
  129. SD_IOCTL SdIoctl;
  130. NTSTATUS Status;
  131. BOOLEAN bConnectionLocked = FALSE;
  132. BYTE *Buffer = NULL;
  133. PICA_KEEP_ALIVE pKeepAlive;
  134. /*
  135. * Extract the IOCTL control code and process the request.
  136. */
  137. code = IrpSp->Parameters.DeviceIoControl.IoControlCode;
  138. #if DBG
  139. if ( code != IOCTL_ICA_SYSTEM_TRACE && code != IOCTL_ICA_TRACE ) {
  140. TRACE(( pConnect, TC_ICADD, TT_API1, "ICADD: IcaDeviceControlConnection, fc %d (enter)\n",
  141. (code & 0x3fff) >> 2 ));
  142. }
  143. #endif
  144. try {
  145. switch ( code ) {
  146. case IOCTL_ICA_SET_SYSTEM_TRACE :
  147. // This IOCTL should only be invoked if we are called from system process
  148. // If not, we deny the request
  149. if (!((BOOLEAN)IrpSp->FileObject->FsContext2)) {
  150. return (STATUS_ACCESS_DENIED);
  151. }
  152. if ( IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(ICA_TRACE) )
  153. return( STATUS_BUFFER_TOO_SMALL );
  154. if ( Irp->RequestorMode != KernelMode ) {
  155. ProbeForRead(IrpSp->Parameters.DeviceIoControl.Type3InputBuffer, sizeof(ICA_TRACE), sizeof(BYTE) );
  156. }
  157. LocalTrace = *(PICA_TRACE)(IrpSp->Parameters.DeviceIoControl.Type3InputBuffer);
  158. KeEnterCriticalRegion();
  159. ExAcquireResourceExclusiveLite( IcaTraceResource, TRUE );
  160. try {
  161. Status = IcaStartStopTrace( &G_TraceInfo, &LocalTrace );
  162. } finally {
  163. ExReleaseResourceLite( IcaTraceResource );
  164. KeLeaveCriticalRegion();
  165. }
  166. break;
  167. case IOCTL_ICA_SET_TRACE :
  168. // This IOCTL should only be invoked if we are called from system process
  169. // If not, we deny the request
  170. if (!((BOOLEAN)IrpSp->FileObject->FsContext2)) {
  171. return (STATUS_ACCESS_DENIED);
  172. }
  173. if ( IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(ICA_TRACE) )
  174. return( STATUS_BUFFER_TOO_SMALL );
  175. if ( Irp->RequestorMode != KernelMode ) {
  176. ProbeForRead(IrpSp->Parameters.DeviceIoControl.Type3InputBuffer, IrpSp->Parameters.DeviceIoControl.InputBufferLength, sizeof(BYTE) );
  177. }
  178. LocalTrace = *(PICA_TRACE)(IrpSp->Parameters.DeviceIoControl.Type3InputBuffer);
  179. IcaLockConnection( pConnect );
  180. bConnectionLocked = TRUE;
  181. Status = IcaStartStopTrace( &pConnect->TraceInfo, &LocalTrace );
  182. if ( !IsListEmpty(&pConnect->StackHead)) {
  183. PICA_STACK pStack;
  184. pStack = CONTAINING_RECORD( pConnect->StackHead.Flink,
  185. ICA_STACK, StackEntry );
  186. SdIoctl.IoControlCode = code;
  187. SdIoctl.InputBuffer = IrpSp->Parameters.DeviceIoControl.Type3InputBuffer;
  188. SdIoctl.InputBufferLength = IrpSp->Parameters.DeviceIoControl.InputBufferLength;
  189. SdIoctl.OutputBuffer = NULL;
  190. SdIoctl.OutputBufferLength = 0;
  191. _IcaCallStack(pStack, SD$IOCTL, &SdIoctl);
  192. }
  193. IcaUnlockConnection( pConnect );
  194. break;
  195. case IOCTL_ICA_SYSTEM_TRACE :
  196. if ( IrpSp->Parameters.DeviceIoControl.InputBufferLength < (ULONG)(FIELD_OFFSET(ICA_TRACE_BUFFER,Data[0])) )
  197. return( STATUS_BUFFER_TOO_SMALL );
  198. if ( IrpSp->Parameters.DeviceIoControl.InputBufferLength > sizeof(ICA_TRACE_BUFFER) )
  199. return( STATUS_INVALID_BUFFER_SIZE );
  200. if ( Irp->RequestorMode != KernelMode ) {
  201. ProbeForRead(IrpSp->Parameters.DeviceIoControl.Type3InputBuffer, IrpSp->Parameters.DeviceIoControl.InputBufferLength, sizeof(BYTE) );
  202. }
  203. pTraceBuffer = IrpSp->Parameters.DeviceIoControl.Type3InputBuffer;
  204. KeEnterCriticalRegion();
  205. ExAcquireResourceExclusiveLite( IcaTraceResource, TRUE );
  206. try {
  207. IcaTraceFormat( &G_TraceInfo,
  208. pTraceBuffer->TraceClass,
  209. pTraceBuffer->TraceEnable,
  210. pTraceBuffer->Data );
  211. } finally {
  212. ExReleaseResourceLite( IcaTraceResource );
  213. KeLeaveCriticalRegion();
  214. }
  215. Status = STATUS_SUCCESS;
  216. break;
  217. case IOCTL_ICA_TRACE :
  218. if ( IrpSp->Parameters.DeviceIoControl.InputBufferLength < (ULONG)(FIELD_OFFSET(ICA_TRACE_BUFFER,Data[0])) )
  219. return( STATUS_BUFFER_TOO_SMALL );
  220. if ( IrpSp->Parameters.DeviceIoControl.InputBufferLength > sizeof(ICA_TRACE_BUFFER) )
  221. return( STATUS_INVALID_BUFFER_SIZE );
  222. if ( Irp->RequestorMode != KernelMode ) {
  223. ProbeForRead(IrpSp->Parameters.DeviceIoControl.Type3InputBuffer, IrpSp->Parameters.DeviceIoControl.InputBufferLength, sizeof(BYTE) );
  224. }
  225. pTraceBuffer = IrpSp->Parameters.DeviceIoControl.Type3InputBuffer;
  226. IcaLockConnection( pConnect );
  227. bConnectionLocked=TRUE;
  228. IcaTraceFormat( &pConnect->TraceInfo,
  229. pTraceBuffer->TraceClass,
  230. pTraceBuffer->TraceEnable,
  231. pTraceBuffer->Data );
  232. IcaUnlockConnection( pConnect );
  233. Status = STATUS_SUCCESS;
  234. break;
  235. case IOCTL_ICA_UNBIND_VIRTUAL_CHANNEL :
  236. if ( IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(VIRTUALCHANNELNAME) )
  237. return( STATUS_BUFFER_TOO_SMALL );
  238. if ( Irp->RequestorMode != KernelMode ) {
  239. ProbeForRead(IrpSp->Parameters.DeviceIoControl.Type3InputBuffer, sizeof(VIRTUALCHANNELNAME), sizeof(BYTE) );
  240. }
  241. if (IrpSp->Parameters.DeviceIoControl.InputBufferLength) {
  242. Buffer = ICA_ALLOCATE_POOL( NonPagedPool,
  243. IrpSp->Parameters.DeviceIoControl.InputBufferLength);
  244. if (Buffer) {
  245. memcpy(Buffer, IrpSp->Parameters.DeviceIoControl.Type3InputBuffer,
  246. IrpSp->Parameters.DeviceIoControl.InputBufferLength);
  247. }
  248. else {
  249. Status = STATUS_NO_MEMORY;
  250. break;
  251. }
  252. }
  253. IcaLockConnection( pConnect );
  254. bConnectionLocked = TRUE;
  255. Status = IcaUnbindVirtualChannel( pConnect, (PVIRTUALCHANNELNAME)Buffer );
  256. IcaUnlockConnection( pConnect );
  257. break;
  258. case IOCTL_ICA_SET_SYSTEM_PARAMETERS:
  259. // Settings coming from TermSrv, copy to global variable.
  260. if (IrpSp->Parameters.DeviceIoControl.InputBufferLength <
  261. sizeof(TERMSRV_SYSTEM_PARAMS))
  262. return(STATUS_BUFFER_TOO_SMALL);
  263. if (Irp->RequestorMode != KernelMode)
  264. ProbeForRead(IrpSp->Parameters.DeviceIoControl.
  265. Type3InputBuffer, sizeof(TERMSRV_SYSTEM_PARAMS),
  266. sizeof(BYTE));
  267. SysParams = *(PTERMSRV_SYSTEM_PARAMS)(IrpSp->Parameters.
  268. DeviceIoControl.Type3InputBuffer);
  269. Status = STATUS_SUCCESS;
  270. break;
  271. case IOCTL_ICA_SYSTEM_KEEP_ALIVE:
  272. // This should only be invoked if we are called from system process
  273. // If not, we deny the request
  274. if (!((BOOLEAN)IrpSp->FileObject->FsContext2)) {
  275. return (STATUS_ACCESS_DENIED);
  276. }
  277. if ( IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(ICA_KEEP_ALIVE ) )
  278. return( STATUS_BUFFER_TOO_SMALL );
  279. if ( Irp->RequestorMode != KernelMode ) {
  280. ProbeForRead(IrpSp->Parameters.DeviceIoControl.Type3InputBuffer, sizeof(ICA_KEEP_ALIVE ), sizeof(BYTE) );
  281. }
  282. pKeepAlive = (PICA_KEEP_ALIVE)(IrpSp->Parameters.DeviceIoControl.Type3InputBuffer);
  283. KeEnterCriticalRegion();
  284. ExAcquireResourceExclusive( g_pKeepAliveResource, TRUE );
  285. try {
  286. Status = _IcaKeepAlive( pKeepAlive->start, pKeepAlive->interval );
  287. } finally {
  288. ExReleaseResource( g_pKeepAliveResource );
  289. KeLeaveCriticalRegion();
  290. }
  291. break;
  292. default:
  293. Status = STATUS_INVALID_DEVICE_REQUEST;
  294. break;
  295. }
  296. } except(EXCEPTION_EXECUTE_HANDLER){
  297. Status = GetExceptionCode();
  298. if (bConnectionLocked) {
  299. IcaUnlockConnection( pConnect );
  300. }
  301. }
  302. if (Buffer) {
  303. ICA_FREE_POOL(Buffer);
  304. Buffer = NULL;
  305. }
  306. #if DBG
  307. if ( code != IOCTL_ICA_SYSTEM_TRACE && code != IOCTL_ICA_TRACE ) {
  308. TRACE(( pConnect, TC_ICADD, TT_API1, "ICADD: IcaDeviceControlConnection, fc %d, 0x%x\n",
  309. (code & 0x3fff) >> 2, Status ));
  310. }
  311. #endif
  312. return( Status );
  313. }
  314. NTSTATUS
  315. IcaCleanupConnection(
  316. IN PICA_CONNECTION pConnect,
  317. IN PIRP Irp,
  318. IN PIO_STACK_LOCATION IrpSp
  319. )
  320. {
  321. return( STATUS_SUCCESS );
  322. }
  323. NTSTATUS
  324. IcaCloseConnection(
  325. IN PICA_CONNECTION pConnect,
  326. IN PIRP Irp,
  327. IN PIO_STACK_LOCATION IrpSp
  328. )
  329. {
  330. /*
  331. * Remove the file object reference for this connection.
  332. * This will cause the connection to be deleted when all other
  333. * references (including stack/channel references) are gone.
  334. */
  335. IcaDereferenceConnection( pConnect );
  336. return( STATUS_SUCCESS );
  337. }
  338. VOID
  339. IcaReferenceConnection(
  340. IN PICA_CONNECTION pConnect
  341. )
  342. {
  343. ASSERT( pConnect->RefCount >= 0 );
  344. /*
  345. * Increment the reference count
  346. */
  347. if ( InterlockedIncrement(&pConnect->RefCount) <= 0 ) {
  348. ASSERT( FALSE );
  349. }
  350. }
  351. VOID
  352. IcaDereferenceConnection(
  353. IN PICA_CONNECTION pConnect
  354. )
  355. {
  356. ASSERT( pConnect->RefCount > 0 );
  357. /*
  358. * Decrement the reference count; if it is 0, free the connection.
  359. */
  360. if ( InterlockedDecrement( &pConnect->RefCount) == 0 ) {
  361. _IcaFreeConnection( pConnect );
  362. }
  363. }
  364. PICA_CONNECTION
  365. _IcaAllocateConnection( VOID )
  366. {
  367. PICA_CONNECTION pConnect;
  368. NTSTATUS Status;
  369. pConnect = ICA_ALLOCATE_POOL( NonPagedPool, sizeof(*pConnect) );
  370. if ( pConnect == NULL )
  371. return NULL;
  372. RtlZeroMemory( pConnect, sizeof(*pConnect) );
  373. /*
  374. * Initialize the reference count to 2,
  375. * one for the caller's reference, one for the file object reference.
  376. */
  377. pConnect->RefCount = 2;
  378. /*
  379. * Initialize the rest of the connect object
  380. */
  381. pConnect->Header.Type = IcaType_Connection;
  382. pConnect->Header.pDispatchTable = IcaConnectionDispatchTable;
  383. ExInitializeResourceLite( &pConnect->Resource );
  384. ExInitializeResourceLite( &pConnect->ChannelTableLock );
  385. InitializeListHead( &pConnect->StackHead );
  386. InitializeListHead( &pConnect->ChannelHead );
  387. InitializeListHead( &pConnect->VcBindHead );
  388. return( pConnect );
  389. }
  390. VOID
  391. _IcaFreeConnection( PICA_CONNECTION pConnect )
  392. {
  393. ICA_TRACE TraceControl;
  394. PICA_CHANNEL pChannel;
  395. PLIST_ENTRY Head;
  396. ASSERT( pConnect->RefCount == 0 );
  397. ASSERT( IsListEmpty( &pConnect->StackHead ) );
  398. ASSERT( IsListEmpty( &pConnect->ChannelHead ) );
  399. ASSERT( IsListEmpty( &pConnect->VcBindHead ) );
  400. ASSERT( !ExIsResourceAcquiredExclusiveLite( &pConnect->Resource ) );
  401. TRACE(( pConnect, TC_ICADD, TT_API2, "ICADD: _IcaFreeConnection: %x\n", pConnect ));
  402. /*
  403. * Close trace file, if any
  404. */
  405. RtlZeroMemory( &TraceControl, sizeof(TraceControl) );
  406. (void) IcaStartStopTrace( &pConnect->TraceInfo, &TraceControl );
  407. ExDeleteResourceLite( &pConnect->Resource );
  408. ExDeleteResourceLite( &pConnect->ChannelTableLock );
  409. ICA_FREE_POOL( pConnect );
  410. }