Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

lpcconn.c File Reference

#include "lpcp.h"

Go to the source code of this file.

Functions

PVOID LpcpFreeConMsg (IN PLPCP_MESSAGE *Msg, PLPCP_CONNECTION_MESSAGE *ConnectMsg, IN PETHREAD CurrentThread)
NTSYSAPI NTSTATUS NTAPI NtConnectPort (OUT PHANDLE PortHandle, IN PUNICODE_STRING PortName, IN PSECURITY_QUALITY_OF_SERVICE SecurityQos, IN OUT PPORT_VIEW ClientView OPTIONAL, IN OUT PREMOTE_PORT_VIEW ServerView OPTIONAL, OUT PULONG MaxMessageLength OPTIONAL, IN OUT PVOID ConnectionInformation OPTIONAL, IN OUT PULONG ConnectionInformationLength OPTIONAL)
NTSTATUS NtSecureConnectPort (OUT PHANDLE PortHandle, IN PUNICODE_STRING PortName, IN PSECURITY_QUALITY_OF_SERVICE SecurityQos, IN OUT PPORT_VIEW ClientView OPTIONAL, IN PSID RequiredServerSid, IN OUT PREMOTE_PORT_VIEW ServerView OPTIONAL, OUT PULONG MaxMessageLength OPTIONAL, IN OUT PVOID ConnectionInformation OPTIONAL, IN OUT PULONG ConnectionInformationLength OPTIONAL)


Function Documentation

PVOID LpcpFreeConMsg IN PLPCP_MESSAGE Msg,
PLPCP_CONNECTION_MESSAGE ConnectMsg,
IN PETHREAD  CurrentThread
 

Definition at line 1131 of file lpcconn.c.

References LpcpAcquireLpcpLock, LpcpReleaseLpcpLock, NULL, and _LPCP_CONNECTION_MESSAGE::SectionToMap.

Referenced by NtSecureConnectPort().

01139 : 01140 01141 This routine returns a connection reply message for the specified thread 01142 01143 Arguments: 01144 01145 Msg - Receives a pointer to the LPCP message if there is a reply 01146 01147 ConnectMsg - Receives a pointer to the LPCP connection message if there 01148 is a reply 01149 01150 CurrentThread - Specifies the thread we're to be examining 01151 01152 Return Value: 01153 01154 PVOID - Returns a pointer to the section to map in the connection message 01155 01156 --*/ 01157 01158 { 01159 PVOID SectionToMap; 01160 01161 // 01162 // Acquire the LPC mutex, remove the connection request message 01163 // from the received queue and free the message back to the connection 01164 // port's zone. 01165 // 01166 01167 LpcpAcquireLpcpLock(); 01168 01169 // 01170 // Remove the thread from the reply rundown list in case we did not wakeup due to 01171 // a reply 01172 // 01173 01174 if (!IsListEmpty( &CurrentThread->LpcReplyChain )) { 01175 01176 RemoveEntryList( &CurrentThread->LpcReplyChain ); 01177 01178 InitializeListHead( &CurrentThread->LpcReplyChain ); 01179 } 01180 01181 // 01182 // Check if the thread has an LPC reply message waiting to be handled 01183 // 01184 01185 if (CurrentThread->LpcReplyMessage != NULL) { 01186 01187 // 01188 // Take the message off the threads list 01189 // 01190 01191 *Msg = CurrentThread->LpcReplyMessage; 01192 01193 CurrentThread->LpcReplyMessageId = 0; 01194 CurrentThread->LpcReplyMessage = NULL; 01195 01196 // 01197 // Set the connection message pointer, and copy over the section 01198 // to map location before zeroing it out 01199 // 01200 01201 *ConnectMsg = (PLPCP_CONNECTION_MESSAGE)(*Msg + 1); 01202 01203 SectionToMap = (*ConnectMsg)->SectionToMap; 01204 (*ConnectMsg)->SectionToMap = NULL; 01205 01206 } else { 01207 01208 // 01209 // Otherwise there is no LPC message to be handle so we'll return 01210 // null's to our caller 01211 // 01212 01213 *Msg = NULL; 01214 SectionToMap = NULL; 01215 } 01216 01217 // 01218 // Release the global lock and return to our caller 01219 // 01220 01221 LpcpReleaseLpcpLock(); 01222 01223 return SectionToMap; 01224 } }

NTSYSAPI NTSTATUS NTAPI NtConnectPort OUT PHANDLE  PortHandle,
IN PUNICODE_STRING  PortName,
IN PSECURITY_QUALITY_OF_SERVICE  SecurityQos,
IN OUT PPORT_VIEW ClientView  OPTIONAL,
IN OUT PREMOTE_PORT_VIEW ServerView  OPTIONAL,
OUT PULONG MaxMessageLength  OPTIONAL,
IN OUT PVOID ConnectionInformation  OPTIONAL,
IN OUT PULONG ConnectionInformationLength  OPTIONAL
 

Definition at line 43 of file lpcconn.c.

References NtSecureConnectPort(), NULL, PortHandle, PortName, and SecurityQos.

Referenced by ConnectToTerminalServer(), DbgSspConnectToDbg(), DbgUiConnectToDbg(), IopConnectLinkTrackingPort(), IopErrorLogConnectPort(), main(), and TerminalServerRequestThread().

00056 : 00057 00058 See NtSecureConnectPort 00059 00060 Arguments: 00061 00062 See NtSecureConnectPort 00063 00064 Return Value: 00065 00066 NTSTATUS - An appropriate status value 00067 00068 --*/ 00069 00070 { 00071 return NtSecureConnectPort( PortHandle, 00072 PortName, 00073 SecurityQos, 00074 ClientView, 00075 NULL, 00076 ServerView, 00077 MaxMessageLength, 00078 ConnectionInformation, 00079 ConnectionInformationLength ); 00080 }

NTSTATUS NtSecureConnectPort OUT PHANDLE  PortHandle,
IN PUNICODE_STRING  PortName,
IN PSECURITY_QUALITY_OF_SERVICE  SecurityQos,
IN OUT PPORT_VIEW ClientView  OPTIONAL,
IN PSID  RequiredServerSid,
IN OUT PREMOTE_PORT_VIEW ServerView  OPTIONAL,
OUT PULONG MaxMessageLength  OPTIONAL,
IN OUT PVOID ConnectionInformation  OPTIONAL,
IN OUT PULONG ConnectionInformationLength  OPTIONAL
 

Definition at line 84 of file lpcconn.c.

References _ETHREAD::Cid, CLIENT_COMMUNICATION_PORT, EXCEPTION_EXECUTE_HANDLER, Executive, ExFreePool(), FALSE, Handle, KeReadStateSemaphore(), KeReleaseSemaphore(), KernelMode, KeSetEvent(), KeWaitForSingleObject(), KPROCESSOR_MODE, LPCP_PORT_OBJECT, LpcpAcquireLpcpLock, LpcpAllocateFromPortZone(), LpcpFreeConMsg(), LpcpFreeToPortZone(), LpcpGenerateMessageId, LpcpInitializePortQueue(), LpcPortObjectType, LpcpReleaseLpcpLock, LpcpTrace, _ETHREAD::LpcReplyChain, _ETHREAD::LpcReplyMessage, _ETHREAD::LpcReplyMessageId, _ETHREAD::LpcReplySemaphore, LpcWaitablePortObjectType, MmMapViewOfSection(), MmSectionObjectType, NT_SUCCESS, NtClose(), NTSTATUS(), NULL, ObCreateObject(), ObDereferenceObject, ObInsertObject(), ObReferenceObject, ObReferenceObjectByHandle(), ObReferenceObjectByName(), PAGED_CODE, PagedPool, PORT_DYNAMIC_SECURITY, PORT_NAME_DELETED, PORT_TYPE, PORT_WAITABLE, PortHandle, PortName, ProbeAndReadStructure, ProbeAndReadUlong, ProbeForWrite(), ProbeForWriteHandle, ProbeForWriteUlong, PsDereferencePrimaryToken, PsGetCurrentProcess, PsGetCurrentThread, PsReferencePrimaryToken(), RtlEqualSid(), SeCaptureSid(), SeCreateClientSecurity(), SecurityQos, SeQueryInformationToken(), SeReleaseSid(), SERVER_CONNECTION_PORT, Status, Token, TRUE, and WrExecutive.

Referenced by CsrpConnectToServer(), and NtConnectPort().

00098 : 00099 00100 A client process can connect to a server process by name using the 00101 NtConnectPort service. 00102 00103 The PortName parameter specifies the name of the server port to 00104 connect to. It must correspond to an object name specified on a 00105 call to NtCreatePort. The service sends a connection request to the 00106 server thread that is listening for them with the NtListenPort 00107 service. The client thread then blocks until a server thread 00108 receives the connection request and responds with a call to the 00109 NtCompleteConnectPort service. The server thread receives the ID of 00110 the client thread, along with any information passed via the 00111 ConnectionInformation parameter. The server thread then decides to 00112 either accept or reject the connection request. 00113 00114 The server communicates the acceptance or rejection with the 00115 NtCompleteConnectPort service. The server can pass back data to the 00116 client about the acceptance or rejection via the 00117 ConnectionInformation data block. 00118 00119 If the server accepts the connection request, then the client 00120 receives a communication port object in the location pointed to by 00121 the PortHandle parameter. This object handle has no name associated 00122 with it and is private to the client process (i.e. it cannot be 00123 inherited by a child process). The client uses the handle to send 00124 and receive messages to/from the server process using the 00125 NtRequestWaitReplyPort service. 00126 00127 If the ClientView parameter was specified, then the section handle 00128 is examined. If it is a valid section handle, then the portion of 00129 the section described by the SectionOffset and ViewSize fields will 00130 be mapped into both the client and server process' address spaces. 00131 The address in client address space will be returned in the ViewBase 00132 field. The address in the server address space will be returned in 00133 the ViewRemoteBase field. The actual offset and size used to map 00134 the section will be returned in the SectionOffset and ViewSize 00135 fields. 00136 00137 If the server rejects the connection request, then no communication 00138 port object handle is returned, and the return status indicates an 00139 error occurred. The server may optionally return information in the 00140 ConnectionInformation data block giving the reason the connection 00141 requests was rejected. 00142 00143 If the PortName does not exist, or the client process does not have 00144 sufficient access rights then the returned status will indicate that 00145 the port was not found. 00146 00147 Arguments: 00148 00149 PortHandle - A pointer to a variable that will receive the client 00150 communication port object handle value. 00151 00152 PortName - A pointer to a port name string. The form of the name 00153 is [\name...\name]\port_name. 00154 00155 SecurityQos - A pointer to security quality of service information 00156 to be applied to the server on the client's behalf. 00157 00158 ClientView - An optional pointer to a structure that specifies the 00159 section that all client threads will use to send messages to the 00160 server. 00161 00162 ClientView Structure 00163 00164 ULONG Length - Specifies the size of this data structure in 00165 bytes. 00166 00167 HANDLE SectionHandle - Specifies an open handle to a section 00168 object. 00169 00170 ULONG SectionOffset - Specifies a field that will receive the 00171 actual offset, in bytes, from the start of the section. The 00172 initial value of this parameter specifies the byte offset 00173 within the section that the client's view is based. The 00174 value is rounded down to the next host page size boundary. 00175 00176 ULONG ViewSize - Specifies a field that will receive the 00177 actual size, in bytes, of the view. If the value of this 00178 parameter is zero, then the client's view of the section 00179 will be mapped starting at the specified section offset and 00180 continuing to the end of the section. Otherwise, the 00181 initial value of this parameter specifies the size, in 00182 bytes, of the client's view and is rounded up to the next 00183 host page size boundary. 00184 00185 PVOID ViewBase - Specifies a field that will receive the base 00186 address of the section in the client's address space. 00187 00188 PVOID ViewRemoteBase - Specifies a field that will receive 00189 the base address of the client's section in the server's 00190 address space. Used to generate pointers that are 00191 meaningful to the server. 00192 00193 RequiredServerSid - Optionally specifies the SID that we expect the 00194 server side of the port to possess. If not specified then we'll 00195 connect to any server SID. 00196 00197 ServerView - An optional pointer to a structure that will receive 00198 information about the server process' view in the client's 00199 address space. The client process can use this information 00200 to validate pointers it receives from the server process. 00201 00202 ServerView Structure 00203 00204 ULONG Length - Specifies the size of this data structure in 00205 bytes. 00206 00207 PVOID ViewBase - Specifies a field that will receive the base 00208 address of the server's section in the client's address 00209 space. 00210 00211 ULONG ViewSize - Specifies a field that will receive the 00212 size, in bytes, of the server's view in the client's address 00213 space. If this field is zero, then server has no view in 00214 the client's address space. 00215 00216 MaxMessageLength - An optional pointer to a variable that will 00217 receive maximum length of messages that can be sent to the 00218 server. The value of this parameter will not exceed 00219 MAX_PORTMSG_LENGTH bytes. 00220 00221 ConnectionInformation - An optional pointer to uninterpreted data. 00222 This data is intended for clients to pass package, version and 00223 protocol identification information to the server to allow the 00224 server to determine if it can satisify the client before 00225 accepting the connection. Upon return to the client, the 00226 ConnectionInformation data block contains any information passed 00227 back from the server by its call to the NtCompleteConnectPort 00228 service. The output data overwrites the input data. 00229 00230 ConnectionInformationLength - Pointer to the length of the 00231 ConnectionInformation data block. The output value is the 00232 length of the data stored in the ConnectionInformation data 00233 block by the server's call to the NtCompleteConnectPort 00234 service. This parameter is OPTIONAL only if the 00235 ConnectionInformation parameter is null, otherwise it is 00236 required. 00237 00238 Return Value: 00239 00240 NTSTATUS - An appropriate status value. 00241 00242 --*/ 00243 00244 { 00245 PLPCP_PORT_OBJECT ConnectionPort; 00246 PLPCP_PORT_OBJECT ClientPort; 00247 HANDLE Handle; 00248 KPROCESSOR_MODE PreviousMode; 00249 NTSTATUS Status; 00250 ULONG ConnectionInfoLength; 00251 PVOID SectionToMap; 00252 PLPCP_MESSAGE Msg; 00253 PLPCP_CONNECTION_MESSAGE ConnectMsg; 00254 PETHREAD CurrentThread = PsGetCurrentThread(); 00255 LARGE_INTEGER SectionOffset; 00256 PORT_VIEW CapturedClientView; 00257 SECURITY_QUALITY_OF_SERVICE CapturedQos; 00258 PSID CapturedRequiredServerSid; 00259 00260 PAGED_CODE(); 00261 00262 // 00263 // Get previous processor mode and probe input and output arguments if 00264 // necessary. 00265 // 00266 00267 PreviousMode = KeGetPreviousMode(); 00268 ConnectionInfoLength = 0; 00269 00270 if (PreviousMode != KernelMode) { 00271 00272 try { 00273 00274 ProbeForWriteHandle( PortHandle ); 00275 00276 if (ARGUMENT_PRESENT( ClientView )) { 00277 00278 CapturedClientView = ProbeAndReadStructure( ClientView, PORT_VIEW ); 00279 00280 if (CapturedClientView.Length != sizeof( *ClientView )) { 00281 00282 return( STATUS_INVALID_PARAMETER ); 00283 } 00284 00285 ProbeForWrite( ClientView, 00286 sizeof( *ClientView ), 00287 sizeof( ULONG )); 00288 } 00289 00290 if (ARGUMENT_PRESENT( ServerView )) { 00291 00292 if (ProbeAndReadUlong( &ServerView->Length ) != sizeof( *ServerView )) { 00293 00294 return( STATUS_INVALID_PARAMETER ); 00295 } 00296 00297 ProbeForWrite( ServerView, 00298 sizeof( *ServerView ), 00299 sizeof( ULONG )); 00300 } 00301 00302 if (ARGUMENT_PRESENT( MaxMessageLength )) { 00303 00304 ProbeForWriteUlong( MaxMessageLength ); 00305 } 00306 00307 if (ARGUMENT_PRESENT( ConnectionInformationLength )) { 00308 00309 ConnectionInfoLength = ProbeAndReadUlong( ConnectionInformationLength ); 00310 ProbeForWriteUlong( ConnectionInformationLength ); 00311 } 00312 00313 if (ARGUMENT_PRESENT( ConnectionInformation )) { 00314 00315 ProbeForWrite( ConnectionInformation, 00316 ConnectionInfoLength, 00317 sizeof( UCHAR )); 00318 } 00319 00320 CapturedQos = ProbeAndReadStructure( SecurityQos, SECURITY_QUALITY_OF_SERVICE ); 00321 00322 CapturedRequiredServerSid = RequiredServerSid; 00323 00324 if (ARGUMENT_PRESENT( RequiredServerSid )) { 00325 00326 Status = SeCaptureSid( RequiredServerSid, 00327 PreviousMode, 00328 NULL, 00329 0, 00330 PagedPool, 00331 TRUE, 00332 &CapturedRequiredServerSid ); 00333 00334 if (!NT_SUCCESS(Status)) { 00335 00336 return Status; 00337 } 00338 } 00339 00340 } except( EXCEPTION_EXECUTE_HANDLER ) { 00341 00342 return( GetExceptionCode() ); 00343 } 00344 00345 // 00346 // Otherwise this is a kernel mode operation 00347 // 00348 00349 } else { 00350 00351 if (ARGUMENT_PRESENT( ClientView )) { 00352 00353 if (ClientView->Length != sizeof( *ClientView )) { 00354 00355 return( STATUS_INVALID_PARAMETER ); 00356 } 00357 00358 CapturedClientView = *ClientView; 00359 } 00360 00361 if (ARGUMENT_PRESENT( ServerView )) { 00362 00363 if (ServerView->Length != sizeof( *ServerView )) { 00364 00365 return( STATUS_INVALID_PARAMETER ); 00366 } 00367 } 00368 00369 if (ARGUMENT_PRESENT( ConnectionInformationLength )) { 00370 00371 ConnectionInfoLength = *ConnectionInformationLength; 00372 } 00373 00374 CapturedQos = *SecurityQos; 00375 CapturedRequiredServerSid = RequiredServerSid; 00376 } 00377 00378 // 00379 // Reference the connection port object by name. Return status if 00380 // unsuccessful. 00381 // 00382 00383 Status = ObReferenceObjectByName( PortName, 00384 0, 00385 NULL, 00386 PORT_CONNECT, 00387 LpcPortObjectType, 00388 PreviousMode, 00389 NULL, 00390 (PVOID *)&ConnectionPort ); 00391 00392 // 00393 // If the port type object didn't work then try for a waitable port type 00394 // object 00395 // 00396 00397 if ( Status == STATUS_OBJECT_TYPE_MISMATCH ) { 00398 00399 Status = ObReferenceObjectByName( PortName, 00400 0, 00401 NULL, 00402 PORT_CONNECT, 00403 LpcWaitablePortObjectType, 00404 PreviousMode, 00405 NULL, 00406 (PVOID *)&ConnectionPort ); 00407 } 00408 00409 // 00410 // We can't locate the name so release the sid if we captured one and 00411 // return error status back to our caller 00412 // 00413 00414 if (!NT_SUCCESS( Status )) { 00415 00416 if (CapturedRequiredServerSid != RequiredServerSid) { 00417 00418 SeReleaseSid( CapturedRequiredServerSid, PreviousMode, TRUE); 00419 } 00420 00421 return Status; 00422 } 00423 00424 LpcpTrace(("Connecting to port %wZ\n", PortName )); 00425 00426 // 00427 // Error if user didn't give us a server communication port 00428 // 00429 00430 if ((ConnectionPort->Flags & PORT_TYPE) != SERVER_CONNECTION_PORT) { 00431 00432 ObDereferenceObject( ConnectionPort ); 00433 00434 if (CapturedRequiredServerSid != RequiredServerSid) { 00435 00436 SeReleaseSid( CapturedRequiredServerSid, PreviousMode, TRUE); 00437 } 00438 00439 return STATUS_INVALID_PORT_HANDLE; 00440 } 00441 00442 // 00443 // If this is NtSecureConnectPort, validated the required SID against 00444 // the SID of the server process. Fail if not equal. 00445 // 00446 00447 if (ARGUMENT_PRESENT( RequiredServerSid )) { 00448 00449 PTOKEN_USER TokenInfo; 00450 00451 if (ConnectionPort->ServerProcess != NULL) { 00452 00453 PACCESS_TOKEN Token ; 00454 00455 Token = PsReferencePrimaryToken( ConnectionPort->ServerProcess ); 00456 00457 00458 Status = SeQueryInformationToken( Token, 00459 TokenUser, 00460 &TokenInfo ); 00461 00462 PsDereferencePrimaryToken( Token ); 00463 00464 if (NT_SUCCESS( Status )) { 00465 00466 if (!RtlEqualSid( CapturedRequiredServerSid, TokenInfo->User.Sid )) { 00467 00468 Status = STATUS_SERVER_SID_MISMATCH; 00469 } 00470 00471 ExFreePool( TokenInfo ); 00472 } 00473 00474 } else { 00475 00476 Status = STATUS_SERVER_SID_MISMATCH; 00477 } 00478 00479 // 00480 // We are all done with the required server sid if specified so 00481 // now release one if we had to capture it 00482 // 00483 00484 if (CapturedRequiredServerSid != RequiredServerSid) { 00485 00486 SeReleaseSid( CapturedRequiredServerSid, PreviousMode, TRUE); 00487 } 00488 00489 // 00490 // If the se information token query didn't work then return the 00491 // error to our caller 00492 // 00493 00494 if (!NT_SUCCESS( Status )) { 00495 00496 ObDereferenceObject( ConnectionPort ); 00497 00498 return Status; 00499 } 00500 } 00501 00502 // 00503 // Allocate and initialize a client communication port object. Give 00504 // the port a request message queue for lost reply datagrams. If 00505 // unable to initialize the port, then deference the port object which 00506 // will cause it to be deleted and return the system service status. 00507 // 00508 00509 Status = ObCreateObject( PreviousMode, 00510 LpcPortObjectType, 00511 NULL, 00512 PreviousMode, 00513 NULL, 00514 sizeof( LPCP_PORT_OBJECT ), 00515 0, 00516 0, 00517 (PVOID *)&ClientPort ); 00518 00519 if (!NT_SUCCESS( Status )) { 00520 00521 ObDereferenceObject( ConnectionPort ); 00522 00523 return Status; 00524 } 00525 00526 // 00527 // Note, that from here on, none of the error paths dereference the 00528 // connection port pointer, just the newly created client port pointer. 00529 // The port delete routine will get called when the client port is 00530 // deleted and it will dereference the connection port pointer stored 00531 // in the client port object. 00532 // 00533 00534 // 00535 // Initialize the client port object to zeros and then fill in the 00536 // fields. 00537 // 00538 00539 RtlZeroMemory( ClientPort, sizeof( LPCP_PORT_OBJECT )); 00540 00541 ClientPort->Length = sizeof( LPCP_PORT_OBJECT ); 00542 ClientPort->Flags = CLIENT_COMMUNICATION_PORT; 00543 ClientPort->ConnectionPort = ConnectionPort; 00544 ClientPort->MaxMessageLength = ConnectionPort->MaxMessageLength; 00545 ClientPort->SecurityQos = CapturedQos; 00546 00547 InitializeListHead( &ClientPort->LpcReplyChainHead ); 00548 InitializeListHead( &ClientPort->LpcDataInfoChainHead ); 00549 00550 // 00551 // Set the security tracking mode, and initialize the client security 00552 // context if it is static tracking. 00553 // 00554 00555 if (CapturedQos.ContextTrackingMode == SECURITY_DYNAMIC_TRACKING) { 00556 00557 ClientPort->Flags |= PORT_DYNAMIC_SECURITY; 00558 00559 } else { 00560 00561 Status = SeCreateClientSecurity( CurrentThread, 00562 &CapturedQos, 00563 FALSE, 00564 &ClientPort->StaticSecurity ); 00565 00566 if (!NT_SUCCESS( Status )) { 00567 00568 ObDereferenceObject( ClientPort ); 00569 00570 return Status; 00571 } 00572 } 00573 00574 // 00575 // Client communication ports get a request message queue for lost 00576 // replies. 00577 // 00578 00579 Status = LpcpInitializePortQueue( ClientPort ); 00580 00581 if (!NT_SUCCESS( Status )) { 00582 00583 ObDereferenceObject( ClientPort ); 00584 00585 return Status; 00586 } 00587 00588 // 00589 // If client has allocated a port memory section, then map a view of 00590 // that section into the client's address space. Also reference the 00591 // section object so we can pass a pointer to the section object in 00592 // connection request message. If the server accepts the connection, 00593 // then it will map a corresponding view of the section in the server's 00594 // address space, using the referenced pointer passed in the connection 00595 // request message. 00596 // 00597 00598 if (ARGUMENT_PRESENT( ClientView )) { 00599 00600 Status = ObReferenceObjectByHandle( CapturedClientView.SectionHandle, 00601 SECTION_MAP_READ | 00602 SECTION_MAP_WRITE, 00603 MmSectionObjectType, 00604 PreviousMode, 00605 (PVOID *)&SectionToMap, 00606 NULL ); 00607 00608 if (!NT_SUCCESS( Status )) { 00609 00610 ObDereferenceObject( ClientPort ); 00611 00612 return Status; 00613 } 00614 00615 SectionOffset.LowPart = CapturedClientView.SectionOffset, 00616 SectionOffset.HighPart = 0; 00617 00618 // 00619 // Now map a view of the section using the reference we just captured 00620 // and not the section handle itself, because the handle may have changed 00621 // 00622 00623 Status = MmMapViewOfSection( SectionToMap, 00624 PsGetCurrentProcess(), 00625 &ClientPort->ClientSectionBase, 00626 0, 00627 0, 00628 &SectionOffset, 00629 &CapturedClientView.ViewSize, 00630 ViewUnmap, 00631 0, 00632 PAGE_READWRITE ); 00633 00634 CapturedClientView.SectionOffset = SectionOffset.LowPart; 00635 00636 if (!NT_SUCCESS( Status )) { 00637 00638 ObDereferenceObject( SectionToMap ); 00639 ObDereferenceObject( ClientPort ); 00640 00641 return Status; 00642 } 00643 00644 CapturedClientView.ViewBase = ClientPort->ClientSectionBase; 00645 00646 } else { 00647 00648 SectionToMap = NULL; 00649 } 00650 00651 // 00652 // Adjust the size of the connection info length that the client supplied 00653 // to be the no longer than one the connection port will accept 00654 // 00655 00656 if (ConnectionInfoLength > ConnectionPort->MaxConnectionInfoLength) { 00657 00658 ConnectionInfoLength = ConnectionPort->MaxConnectionInfoLength; 00659 } 00660 00661 // 00662 // At this point the client port is all setup and now we have to 00663 // allocate a request connection message for the server and send it off 00664 // 00665 // Lock, allocate and then unlock the zone. We are allocation a 00666 // connection request message. It holds the LPCP message, the LPCP 00667 // connection message, and the user supplied connection information 00668 // 00669 00670 LpcpAcquireLpcpLock(); 00671 00672 Msg = LpcpAllocateFromPortZone( sizeof( *Msg ) + 00673 sizeof( *ConnectMsg ) + 00674 ConnectionInfoLength ); 00675 00676 LpcpReleaseLpcpLock(); 00677 00678 // 00679 // If we didn't get memory for the message then tell our caller we failed 00680 // 00681 00682 if (Msg == NULL) { 00683 00684 if (SectionToMap != NULL) { 00685 00686 ObDereferenceObject( SectionToMap ); 00687 } 00688 00689 ObDereferenceObject( ClientPort ); 00690 00691 return STATUS_NO_MEMORY; 00692 } 00693 00694 // 00695 // Msg points to the LPCP message, followed by ConnectMsg which points to 00696 // the LPCP connection message, followed by client specified information. 00697 // We'll now fill it all in. 00698 // 00699 00700 ConnectMsg = (PLPCP_CONNECTION_MESSAGE)(Msg + 1); 00701 00702 // 00703 // This thread originated the message 00704 // 00705 00706 Msg->Request.ClientId = CurrentThread->Cid; 00707 00708 // 00709 // If we have a client view then copy over the client view information 00710 // otherwise we'll zero out all of the view information 00711 // 00712 00713 if (ARGUMENT_PRESENT( ClientView )) { 00714 00715 Msg->Request.ClientViewSize = CapturedClientView.ViewSize; 00716 00717 RtlMoveMemory( &ConnectMsg->ClientView, 00718 &CapturedClientView, 00719 sizeof( CapturedClientView )); 00720 00721 RtlZeroMemory( &ConnectMsg->ServerView, sizeof( ConnectMsg->ServerView )); 00722 00723 } else { 00724 00725 Msg->Request.ClientViewSize = 0; 00726 RtlZeroMemory( ConnectMsg, sizeof( *ConnectMsg )); 00727 } 00728 00729 ConnectMsg->ClientPort = NULL; // Set below 00730 ConnectMsg->SectionToMap = SectionToMap; 00731 00732 // 00733 // The data length is everything after the port message within the lpcp 00734 // message. In other words the connection message and the user supplied 00735 // information 00736 // 00737 00738 Msg->Request.u1.s1.DataLength = (CSHORT)(sizeof( *ConnectMsg ) + 00739 ConnectionInfoLength); 00740 00741 // 00742 // The total length add on the LPCP message 00743 // 00744 // **** should this just add on the size of a port message instead? 00745 // 00746 00747 Msg->Request.u1.s1.TotalLength = (CSHORT)(sizeof( *Msg ) + 00748 Msg->Request.u1.s1.DataLength); 00749 00750 // 00751 // This will be a connection request message 00752 // 00753 00754 Msg->Request.u2.s2.Type = LPC_CONNECTION_REQUEST; 00755 00756 // 00757 // If the caller supplied some connection information then copy 00758 // that into place right now 00759 // 00760 00761 if (ARGUMENT_PRESENT( ConnectionInformation )) { 00762 00763 try { 00764 00765 RtlMoveMemory( ConnectMsg + 1, 00766 ConnectionInformation, 00767 ConnectionInfoLength ); 00768 00769 } except( EXCEPTION_EXECUTE_HANDLER ) { 00770 00771 // 00772 // If we fail then cleanup after ourselves and return the 00773 // error to our caller 00774 // 00775 00776 LpcpFreeToPortZone( Msg, FALSE ); 00777 00778 if (SectionToMap != NULL) { 00779 00780 ObDereferenceObject( SectionToMap ); 00781 } 00782 00783 ObDereferenceObject( ClientPort ); 00784 00785 return GetExceptionCode(); 00786 } 00787 } 00788 00789 // 00790 // The message is mostly ready to go now put it on the servers queue. 00791 // 00792 // Acquire the mutex that guards the LpcReplyMessage field of the 00793 // thread. Also acquire the semaphore that guards the connection 00794 // request message queue. Stamp the connection request message with 00795 // a serial number, insert the message at the tail of the connection 00796 // request message queue and remember the address of the message in 00797 // the LpcReplyMessage field for the current thread. 00798 // 00799 00800 LpcpAcquireLpcpLock(); 00801 00802 // 00803 // See if the port name has been deleted from under us. If so, then 00804 // don't queue the message and don't wait for a reply 00805 // 00806 00807 if (ConnectionPort->Flags & PORT_NAME_DELETED) { 00808 00809 Status = STATUS_OBJECT_NAME_NOT_FOUND; 00810 00811 } else { 00812 00813 Status = STATUS_SUCCESS; 00814 00815 LpcpTrace(( "Send Connect Msg %lx to Port %wZ (%lx)\n", Msg, PortName, ConnectionPort )); 00816 00817 // 00818 // Stamp the request message with a serial number, insert the message 00819 // at the tail of the request message queue 00820 // 00821 00822 Msg->RepliedToThread = NULL; 00823 Msg->Request.MessageId = LpcpGenerateMessageId(); 00824 00825 CurrentThread->LpcReplyMessageId = Msg->Request.MessageId; 00826 00827 InsertTailList( &ConnectionPort->MsgQueue.ReceiveHead, &Msg->Entry ); 00828 InsertTailList( &ConnectionPort->LpcReplyChainHead, &CurrentThread->LpcReplyChain ); 00829 00830 CurrentThread->LpcReplyMessage = Msg; 00831 00832 // 00833 // Reference the port we are passing in the connect msg so if we die 00834 // it will still be valid for the server in NtAcceptConnectPort. The 00835 // reference will be release when the message is freed. 00836 // 00837 00838 ObReferenceObject( ClientPort ); 00839 00840 ConnectMsg->ClientPort = ClientPort; 00841 } 00842 00843 LpcpReleaseLpcpLock(); 00844 00845 // 00846 // At this point the client's communcation port is all set up and the 00847 // connection request message is in the server's queue. So now we have 00848 // to single the server and wait for a reply 00849 // 00850 00851 if (NT_SUCCESS( Status )) { 00852 00853 // 00854 // If this is a waitable port then set the event that they might be 00855 // waiting on 00856 // 00857 00858 if ( ConnectionPort->Flags & PORT_WAITABLE ) { 00859 00860 KeSetEvent( &ConnectionPort->WaitEvent, 1, FALSE ); 00861 } 00862 00863 // 00864 // Increment the connection request message queue semaphore by one for 00865 // the newly inserted connection request message. Release the spin 00866 // locks, while remaining at the dispatcher IRQL. Then wait for the 00867 // reply to this connection request by waiting on the LpcReplySemaphore 00868 // for the current thread. 00869 // 00870 00871 KeReleaseSemaphore( ConnectionPort->MsgQueue.Semaphore, 00872 1, 00873 1, 00874 FALSE ); 00875 00876 Status = KeWaitForSingleObject( &CurrentThread->LpcReplySemaphore, 00877 Executive, 00878 PreviousMode, 00879 FALSE, 00880 NULL ); 00881 } 00882 00883 if (Status == STATUS_USER_APC) { 00884 00885 // 00886 // if the semaphore is signaled, then clear it 00887 // 00888 00889 if (KeReadStateSemaphore( &CurrentThread->LpcReplySemaphore )) { 00890 00891 KeWaitForSingleObject( &CurrentThread->LpcReplySemaphore, 00892 WrExecutive, 00893 KernelMode, 00894 FALSE, 00895 NULL ); 00896 00897 Status = STATUS_SUCCESS; 00898 } 00899 } 00900 00901 // 00902 // A connection request is accepted if the ConnectedPort of the client's 00903 // communication port has been filled in. 00904 // 00905 00906 if (Status == STATUS_SUCCESS) { 00907 00908 SectionToMap = LpcpFreeConMsg( &Msg, &ConnectMsg, CurrentThread ); 00909 00910 // 00911 // Check that we got a reply message 00912 // 00913 00914 if (Msg != NULL) { 00915 00916 // 00917 // Copy any connection information back to the caller, but first 00918 // calculate the new connection data length for the reply and 00919 // don't let it grow beyond what we probed originally 00920 // 00921 00922 if ((Msg->Request.u1.s1.DataLength - sizeof( *ConnectMsg )) < ConnectionInfoLength) { 00923 00924 ConnectionInfoLength = Msg->Request.u1.s1.DataLength - sizeof( *ConnectMsg ); 00925 } 00926 00927 if (ARGUMENT_PRESENT( ConnectionInformation )) { 00928 00929 try { 00930 00931 if (ARGUMENT_PRESENT( ConnectionInformationLength )) { 00932 00933 *ConnectionInformationLength = ConnectionInfoLength; 00934 } 00935 00936 RtlMoveMemory( ConnectionInformation, 00937 ConnectMsg + 1, 00938 ConnectionInfoLength ); 00939 00940 } except( EXCEPTION_EXECUTE_HANDLER ) { 00941 00942 Status = GetExceptionCode(); 00943 } 00944 } 00945 00946 // 00947 // Insert client communication port object in specified object 00948 // table. Set port handle value if successful. If not 00949 // successful, then the port will have been dereferenced, which 00950 // will cause it to be freed, after our delete procedure is 00951 // called. The delete procedure will undo the work done to 00952 // initialize the port. 00953 // 00954 00955 if (ClientPort->ConnectedPort != NULL) { 00956 00957 ULONG CapturedMaxMessageLength; 00958 00959 // 00960 // Before we do the object insert we need to get the max 00961 // message length because right after the call the object 00962 // could be dereferenced and gone away 00963 // 00964 00965 CapturedMaxMessageLength = ConnectionPort->MaxMessageLength; 00966 00967 // 00968 // Now create a handle for the new client port object. 00969 // 00970 00971 Status = ObInsertObject( ClientPort, 00972 NULL, 00973 PORT_ALL_ACCESS, 00974 0, 00975 (PVOID *)NULL, 00976 &Handle ); 00977 00978 if (NT_SUCCESS( Status )) { 00979 00980 // 00981 // This is the only successful path through this routine. 00982 // Set the output variables, later we'll free the msg 00983 // back to the port zone and return to our caller 00984 // 00985 00986 try { 00987 00988 *PortHandle = Handle; 00989 00990 if (ARGUMENT_PRESENT( MaxMessageLength )) { 00991 00992 *MaxMessageLength = CapturedMaxMessageLength; 00993 } 00994 00995 if (ARGUMENT_PRESENT( ClientView )) { 00996 00997 RtlMoveMemory( ClientView, 00998 &ConnectMsg->ClientView, 00999 sizeof( *ClientView )); 01000 } 01001 01002 if (ARGUMENT_PRESENT( ServerView )) { 01003 01004 RtlMoveMemory( ServerView, 01005 &ConnectMsg->ServerView, 01006 sizeof( *ServerView )); 01007 } 01008 01009 } except( EXCEPTION_EXECUTE_HANDLER ) { 01010 01011 Status = GetExceptionCode(); 01012 NtClose( Handle ); 01013 } 01014 } 01015 01016 } else { 01017 01018 // 01019 // Otherwise we did not get a connect port from the server so 01020 // the connection was refused 01021 // 01022 01023 LpcpTrace(( "Connection request refused.\n" )); 01024 01025 if ( SectionToMap != NULL ) { 01026 01027 ObDereferenceObject( SectionToMap ); 01028 } 01029 01030 if (ConnectionPort->Flags & PORT_NAME_DELETED) { 01031 01032 Status = STATUS_OBJECT_NAME_NOT_FOUND; 01033 01034 } else { 01035 01036 Status = STATUS_PORT_CONNECTION_REFUSED; 01037 } 01038 01039 ObDereferenceObject( ClientPort ); 01040 } 01041 01042 // 01043 // Free the reply message back to the port zone 01044 // 01045 01046 LpcpFreeToPortZone( Msg, FALSE ); 01047 01048 } else { 01049 01050 // 01051 // We did not get a reply message so the connection must have 01052 // been refused 01053 // 01054 01055 if (SectionToMap != NULL) { 01056 01057 ObDereferenceObject( SectionToMap ); 01058 } 01059 01060 ObDereferenceObject( ClientPort ); 01061 01062 Status = STATUS_PORT_CONNECTION_REFUSED; 01063 } 01064 01065 } else { 01066 01067 // 01068 // Our wait was not successful 01069 // 01070 01071 // 01072 // Remove the connection request message from the received 01073 // queue and free the message back to the connection 01074 // port's zone. 01075 // 01076 01077 SectionToMap = LpcpFreeConMsg( &Msg, &ConnectMsg, CurrentThread ); 01078 01079 // 01080 // The wait was not successful, but in the meantime the server could 01081 // replied, so it signaled the lpc semaphore. We have to clear the 01082 // semaphore state right now. 01083 // 01084 01085 if (KeReadStateSemaphore( &CurrentThread->LpcReplySemaphore )) { 01086 01087 KeWaitForSingleObject( &CurrentThread->LpcReplySemaphore, 01088 WrExecutive, 01089 KernelMode, 01090 FALSE, 01091 NULL ); 01092 } 01093 01094 if (Msg != NULL) { 01095 01096 LpcpFreeToPortZone( Msg, FALSE ); 01097 } 01098 01099 // 01100 // If a client section was specified, then dereference the section 01101 // object. 01102 // 01103 01104 if ( SectionToMap != NULL ) { 01105 01106 ObDereferenceObject( SectionToMap ); 01107 } 01108 01109 // 01110 // If the connection was rejected or the wait failed, then 01111 // dereference the client port object, which will cause it to 01112 // be deleted. 01113 // 01114 01115 ObDereferenceObject( ClientPort ); 01116 } 01117 01118 // 01119 // And return to our caller 01120 // 01121 01122 return Status; 01123 }


Generated on Sat May 15 19:44:33 2004 for test by doxygen 1.3.7