test: lpcconn.c Source File

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

# lpcconn.c

Go to the documentation of this file.

    00001 /*++
    00002
    00003 Copyright (c) 1989  Microsoft Corporation
    00004
    00005 Module Name:
    00006
    00007     lpcconn.c
    00008
    00009 Abstract:
    00010
    00011     Local Inter-Process Communication (LPC) connection system services.
    00012
    00013 Author:
    00014
    00015     Steve Wood (stevewo) 15-May-1989
    00016
    00017 Revision History:
    00018
    00019 --*/
    00020
    00021 #include "lpcp.h"
    00022
    00023 //
    00024 //  Local procedure prototypes
    00025 //
    00026
    00027 PVOID
    00028 LpcpFreeConMsg(
    00029     IN PLPCP_MESSAGE *Msg,
    00030     PLPCP_CONNECTION_MESSAGE *ConnectMsg,
    00031     IN PETHREAD CurrentThread
    00032     );
    00033
    00034 #ifdef ALLOC_PRAGMA
    00035 #pragma alloc_text(PAGE,NtConnectPort)
    00036 #pragma alloc_text(PAGE,LpcpFreeConMsg)
    00037 #endif
    00038
    00039
    00040 NTSYSAPI
    00041 NTSTATUS
    00042 NTAPI
    00043 NtConnectPort (
    00044     OUT PHANDLE PortHandle,
    00045     IN PUNICODE_STRING PortName,
    00046     IN PSECURITY_QUALITY_OF_SERVICE SecurityQos,
    00047     IN OUT PPORT_VIEW ClientView OPTIONAL,
    00048     IN OUT PREMOTE_PORT_VIEW ServerView OPTIONAL,
    00049     OUT PULONG MaxMessageLength OPTIONAL,
    00050     IN OUT PVOID ConnectionInformation OPTIONAL,
    00051     IN OUT PULONG ConnectionInformationLength OPTIONAL
    00052     )
    00053
    00054 /*++
    00055
    00056 Routine Description:
    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 }
    00081
    00082
    00083 NTSTATUS
    00084 NtSecureConnectPort (
    00085     OUT PHANDLE PortHandle,
    00086     IN PUNICODE_STRING PortName,
    00087     IN PSECURITY_QUALITY_OF_SERVICE SecurityQos,
    00088     IN OUT PPORT_VIEW ClientView OPTIONAL,
    00089     IN PSID RequiredServerSid,
    00090     IN OUT PREMOTE_PORT_VIEW ServerView OPTIONAL,
    00091     OUT PULONG MaxMessageLength OPTIONAL,
    00092     IN OUT PVOID ConnectionInformation OPTIONAL,
    00093     IN OUT PULONG ConnectionInformationLength OPTIONAL
    00094     )
    00095
    00096 /*++
    00097
    00098 Routine Description:
    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 }
    01124
    01125
    01126 //
    01127 //  Local support routine
    01128 //
    01129
    01130 PVOID
    01131 LpcpFreeConMsg (
    01132     IN PLPCP_MESSAGE *Msg,
    01133     PLPCP_CONNECTION_MESSAGE *ConnectMsg,
    01134     IN PETHREAD CurrentThread
    01135     )
    01136
    01137 /*++
    01138
    01139 Routine Description:
    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 }