00051 :
00052
00053
A server process can accept or reject a client connection request
00054
using the NtAcceptConnectPort service.
00055
00056 The ConnectionRequest parameter must specify a connection request
00057 returned by a previous call to
the NtListenPort service. This
00058 service will either complete
the connection
if the AcceptConnection
00059 parameter
is TRUE, or reject
the connection request
if the
00060 AcceptConnection parameter
is FALSE.
00061
00062 In either
case,
the contents of
the data portion of
the connection
00063 request
is the data to
return to
the caller of
NtConnectPort.
00064
00065 If
the connection request
is accepted, then two communication port
00066 objects will be created and connected together. One will be
00067 inserted in
the client process' handle table and returned to
the
00068 client via
the PortHandle parameter
it specified on
the
00069
NtConnectPort service. The other will be inserted in
the server
00070 process' handle table and returned via
the PortHandle parameter
00071 specified on
the NtCompleteConnectPort service. In addition
the
00072 two communication ports (client and server) will be linked together.
00073
00074 If
the connection request
is accepted, and
the ServerView parameter
00075 was specified, then
the section handle
is examined. If
it is valid,
00076 then
the portion of
the section described by
the SectionOffset and
00077 ViewSize fields will be mapped into both
the client and server
00078 process address spaces. The address in server's address space will
00079 be returned in
the ViewBase field. The address in
the client's
00080 address space will be returned in
the ViewRemoteBase field. The
00081 actual offset and size used to map
the section will be returned in
00082
the SectionOffset and ViewSize fields.
00083
00084 Communication port objects are temporary objects that have no names
00085 and cannot be inherited. When either
the client or server process
00086 calls
the !f
NtClose service
for a communication port,
the port will
00087 be deleted since there can never be more than one outstanding handle
00088
for each communication port. The port object
type specific
delete
00089
procedure will then be invoked. This
delete procedure will examine
00090
the communication port, and
if it is connected to another
00091 communication port,
it will queue an LPC_PORT_CLOSED datagram to
00092 that port's message queue. This will allow both
the client and
00093 server processes to notice when a port becomes disconnected, either
00094 because of an
explicit call to
NtClose or an implicit call due to
00095 process termination. In addition,
the delete procedure will scan
00096
the message queue of
the port being closed and
for each message
00097 still in
the queue,
it will
return an ERROR_PORT_CLOSED status to
00098 any thread that
is waiting
for a reply to
the message.
00099
00100 Arguments:
00101
00102
PortHandle -
A pointer to a variable that will receive
the server
00103 communication port object handle value.
00104
00105 PortContext - An uninterpreted pointer that
is stored in
the
00106 server communication port. This pointer
is returned whenever
00107 a message
is received
for this port.
00108
00109 ConnectionRequest -
A pointer to a structure that describes
the
00110 connection request being accepted or rejected:
00111
00112 The ConnectionRequest structure
00113
00114 ULONG Length - Specifies
the size of
this data structure in
00115 bytes.
00116
00117 CLIENT_ID ClientId - Specifies a structure that contains
the
00118 client identifier (CLIENT_ID) of the thread that sent the
00119 request.
00120
00121 The ClientId Structure
00122
00123 ULONG UniqueProcessId - A unique value for each process
00124 in the system.
00125
00126 ULONG UniqueThreadId - A unique value for each thread in the
00127 system.
00128
00129 ULONG MessageId - A unique value that identifies the connection
00130 request being completed.
00131
00132 ULONG PortAttributes - This field has no meaning for this service.
00133
00134 ULONG ClientViewSize - This field has no meaning for this service.
00135
00136 AcceptConnection - Specifies a
boolean value which indicates where
00137 the connection request is being accepted or rejected. A value
00138 of TRUE means that the connection request is accepted and a
00139 server communication port handle will be created and connected
00140 to the client's communication port handle. A value of FALSE
00141 means that the connection request is not accepted.
00142
00143 ServerView - A pointer to a structure that specifies the section that
00144 the server process will use to send messages back to the client
00145 process connected to this port.
00146
00147 The ServerView Structure
00148
00149 ULONG Length - Specifies the size of this data structure in
00150 bytes.
00151
00152 HANDLE SectionHandle - Specifies an open handle to a section
00153 object.
00154
00155 ULONG SectionOffset - Specifies a field that will receive the
00156 actual offset, in bytes, from the start of the section. The
00157 initial value of this parameter specifies the byte offset
00158 within the section that the client's view is based. The
00159 value is rounded down to the next host page size boundary.
00160
00161 ULONG ViewSize - Specifies the size of the view, in bytes.
00162
00163 PVOID ViewBase - Specifies a field that will receive the base
00164 address of the port memory in the server's address space.
00165
00166 PVOID ViewRemoteBase - Specifies a field that will receive
00167 the base address of the server port's memory in the client's
00168 address space. Used to generate pointers that are
00169 meaningful to the client.
00170
00171 ClientView - An optional pointer to a structure that will receive
00172 information about the client process' view in the server's
00173 address space. The server process can use this information
00174 to validate pointers it receives from the client process.
00175
00176 The ClientView Structure
00177
00178 ULONG Length - Specifies the size of this data structure in
00179 bytes.
00180
00181 PVOID ViewBase - Specifies a field that will receive the base
00182 address of the client port's memory in the server's address
00183 space.
00184
00185 ULONG ViewSize - Specifies a field that will receive the
00186 size, in bytes, of the client's view in the server's address
00187 space. If this field is zero, then client has no view in
00188 the server's address space.
00189
00190 Return Value:
00191
00192 NTSTATUS - An appropriate status value.
00193
00194 --*/
00195
00196 {
00197
PLPCP_PORT_OBJECT ConnectionPort;
00198
PLPCP_PORT_OBJECT ServerPort;
00199
PLPCP_PORT_OBJECT ClientPort;
00200 PVOID ClientSectionToMap;
00201 HANDLE
Handle;
00202
KPROCESSOR_MODE PreviousMode;
00203
NTSTATUS Status;
00204 ULONG ConnectionInfoLength;
00205
PLPCP_MESSAGE Msg;
00206
PLPCP_CONNECTION_MESSAGE ConnectMsg;
00207 PORT_MESSAGE CapturedReplyMessage;
00208 PVOID SectionToMap;
00209 LARGE_INTEGER SectionOffset;
00210 SIZE_T ViewSize;
00211
PEPROCESS ClientProcess;
00212
PETHREAD ClientThread;
00213 PORT_VIEW CapturedServerView;
00214
00215
PAGED_CODE();
00216
00217
00218
00219
00220
00221 PreviousMode = KeGetPreviousMode();
00222
00223
if (PreviousMode !=
KernelMode) {
00224
00225
try {
00226
00227
ProbeForWriteHandle( PortHandle );
00228
00229
ProbeForRead( ConnectionRequest,
00230
sizeof( *ConnectionRequest ),
00231
sizeof( ULONG ));
00232
00233 CapturedReplyMessage = *ConnectionRequest;
00234
00235
if (ARGUMENT_PRESENT( ServerView )) {
00236
00237 CapturedServerView =
ProbeAndReadStructure( ServerView, PORT_VIEW );
00238
00239
if (CapturedServerView.Length !=
sizeof( *ServerView )) {
00240
00241
return STATUS_INVALID_PARAMETER;
00242 }
00243
00244
ProbeForWrite( ServerView,
00245
sizeof( *ServerView ),
00246
sizeof( ULONG ));
00247 }
00248
00249
if (ARGUMENT_PRESENT( ClientView )) {
00250
00251
if (
ProbeAndReadUlong( &ClientView->Length ) !=
sizeof( *ClientView )) {
00252
00253
return STATUS_INVALID_PARAMETER;
00254 }
00255
00256
ProbeForWrite( ClientView,
00257
sizeof( *ClientView ),
00258
sizeof( ULONG ));
00259 }
00260
00261 } except( EXCEPTION_EXECUTE_HANDLER ) {
00262
00263
return GetExceptionCode();
00264 }
00265
00266 }
else {
00267
00268
00269
00270
00271
00272 CapturedReplyMessage = *ConnectionRequest;
00273
00274
if (ARGUMENT_PRESENT( ServerView )) {
00275
00276
if (ServerView->Length !=
sizeof( *ServerView )) {
00277
00278
return STATUS_INVALID_PARAMETER;
00279 }
00280
00281 CapturedServerView = *ServerView;
00282 }
00283
00284
if (ARGUMENT_PRESENT( ClientView )) {
00285
00286
if (ClientView->Length !=
sizeof( *ClientView )) {
00287
00288
return STATUS_INVALID_PARAMETER;
00289 }
00290 }
00291 }
00292
00293
00294
00295
00296
00297
00298
00299
Status =
PsLookupProcessThreadByCid( &CapturedReplyMessage.ClientId,
00300 &ClientProcess,
00301 &ClientThread );
00302
00303
if (!
NT_SUCCESS( Status )) {
00304
00305
return Status;
00306 }
00307
00308
00309
00310
00311
00312
00313
00314
LpcpAcquireLpcpLock();
00315
00316
00317
00318
00319
00320
00321
00322
00323
00324
00325
00326
if ((
ClientThread->LpcReplyMessage ==
NULL) ||
00327 (CapturedReplyMessage.MessageId == 0) ||
00328 (
ClientThread->LpcReplyMessageId != CapturedReplyMessage.MessageId) ||
00329 ((((
PLPCP_MESSAGE)
ClientThread->LpcReplyMessage)->Request.u2.s2.Type & ~LPC_KERNELMODE_MESSAGE) != LPC_CONNECTION_REQUEST)) {
00330
00331 Msg =
NULL;
00332
00333 }
else {
00334
00335
00336
00337
00338
00339 Msg =
ClientThread->LpcReplyMessage;
00340
00341
00342
00343
00344
00345 ConnectMsg = (
PLPCP_CONNECTION_MESSAGE)(Msg + 1);
00346
00347
00348
00349
00350
00351 ClientPort = ConnectMsg->
ClientPort;
00352
00353
00354
00355
00356
00357 ConnectionPort = ClientPort->
ConnectionPort;
00358
00359
00360
00361
00362
00363
if ( ConnectionPort->
ServerProcess !=
PsGetCurrentProcess() ) {
00364
00365
00366
00367
00368
00369
LpcpReleaseLpcpLock();
00370
00371
ObDereferenceObject( ClientProcess );
00372
ObDereferenceObject( ClientThread );
00373
00374
return (STATUS_REPLY_MESSAGE_MISMATCH);
00375 }
00376
00377
00378
00379
00380
00381
ClientThread->LpcReplyMessage =
NULL;
00382
00383
00384
00385
00386
00387 ConnectMsg->
ClientPort =
NULL;
00388
00389
00390
00391
00392
00393
00394
00395
00396
ClientThread->LpcReplyMessageId = 0;
00397 }
00398
00399
00400
00401
00402
00403
LpcpReleaseLpcpLock();
00404
00405
00406
00407
00408
00409
00410
00411
if ( !Msg ) {
00412
00413
LpcpPrint((
"%s Attempted AcceptConnectPort to Thread %lx (%s)\n",
00414
PsGetCurrentProcess()->ImageFileName,
00415 ClientThread,
00416
THREAD_TO_PROCESS( ClientThread )->ImageFileName ));
00417
LpcpPrint((
"failed. MessageId == %u\n", CapturedReplyMessage.MessageId ));
00418
LpcpPrint((
" Thread MessageId == %u\n",
ClientThread->LpcReplyMessageId ));
00419
LpcpPrint((
" Thread Msg == %x\n",
ClientThread->LpcReplyMessage ));
00420
00421
ObDereferenceObject( ClientProcess );
00422
ObDereferenceObject( ClientThread );
00423
00424
return (STATUS_REPLY_MESSAGE_MISMATCH);
00425 }
00426
00427
00428
00429
00430
00431
00432
LpcpTrace((
"Replying to Connect Msg %lx to Port %lx\n",
00433 Msg, ClientPort->
ConnectionPort ));
00434
00435
00436
00437
00438
00439
00440 ConnectionInfoLength = CapturedReplyMessage.u1.s1.DataLength;
00441
00442
if (ConnectionInfoLength > ConnectionPort->
MaxConnectionInfoLength) {
00443
00444 ConnectionInfoLength = ConnectionPort->
MaxConnectionInfoLength;
00445 }
00446
00447 Msg->
Request.u1.s1.DataLength = (CSHORT)(
sizeof( *ConnectMsg ) +
00448 ConnectionInfoLength);
00449
00450 Msg->
Request.u1.s1.TotalLength = (CSHORT)(
sizeof( *Msg ) +
00451 Msg->
Request.u1.s1.DataLength);
00452
00453 Msg->
Request.u2.s2.Type = LPC_REPLY;
00454 Msg->
Request.u2.s2.DataInfoOffset = 0;
00455 Msg->
Request.ClientId = CapturedReplyMessage.ClientId;
00456 Msg->
Request.MessageId = CapturedReplyMessage.MessageId;
00457 Msg->
Request.ClientViewSize = 0;
00458
00459
try {
00460
00461 RtlMoveMemory( ConnectMsg + 1,
00462 (PCHAR)(ConnectionRequest + 1),
00463 ConnectionInfoLength );
00464
00465 } except( EXCEPTION_EXECUTE_HANDLER ) {
00466
00467
Status = GetExceptionCode();
00468 }
00469
00470
00471
00472
00473
00474 ClientSectionToMap =
NULL;
00475
00476
if (AcceptConnection) {
00477
00478
00479
00480
00481
00482
00483
00484
Status =
ObCreateObject( PreviousMode,
00485 LpcPortObjectType,
00486 NULL,
00487 PreviousMode,
00488 NULL,
00489
sizeof(
LPCP_PORT_OBJECT ),
00490 0,
00491 0,
00492 (PVOID *)&ServerPort );
00493
00494
if (!
NT_SUCCESS( Status )) {
00495
00496
goto bailout;
00497 }
00498
00499 RtlZeroMemory( ServerPort,
sizeof( LPCP_PORT_OBJECT ));
00500
00501 ServerPort->
Length =
sizeof(
LPCP_PORT_OBJECT );
00502 ServerPort->
PortContext = PortContext;
00503 ServerPort->
Flags =
SERVER_COMMUNICATION_PORT;
00504
00505 InitializeListHead( &ServerPort->
LpcReplyChainHead );
00506 InitializeListHead( &ServerPort->
LpcDataInfoChainHead );
00507
00508
00509
00510
00511
00512
00513
00514
00515
ObReferenceObject( ConnectionPort );
00516
00517 ServerPort->
ConnectionPort = ConnectionPort;
00518 ServerPort->
MaxMessageLength = ConnectionPort->
MaxMessageLength;
00519
00520
00521
00522
00523
00524
00525
00526
00527
00528
00529 ServerPort->
ConnectedPort = ClientPort;
00530 ClientPort->
ConnectedPort = ServerPort;
00531
00532 ServerPort->
Creator =
PsGetCurrentThread()->Cid;
00533 ClientPort->
Creator = Msg->
Request.ClientId;
00534
00535
00536
00537
00538
00539
00540
00541
LpcpAcquireLpcpLock();
00542
00543 ClientSectionToMap = ConnectMsg->
SectionToMap;
00544 ConnectMsg->
SectionToMap =
NULL;
00545
00546
LpcpReleaseLpcpLock();
00547
00548
if (ClientSectionToMap) {
00549
00550 LARGE_INTEGER LargeSectionOffset;
00551
00552 LargeSectionOffset.LowPart = ConnectMsg->
ClientView.SectionOffset;
00553 LargeSectionOffset.HighPart = 0;
00554
00555
Status =
MmMapViewOfSection( ClientSectionToMap,
00556
PsGetCurrentProcess(),
00557 &ServerPort->
ClientSectionBase,
00558 0,
00559 0,
00560 &LargeSectionOffset,
00561 &ConnectMsg->
ClientView.ViewSize,
00562 ViewUnmap,
00563 0,
00564 PAGE_READWRITE );
00565
00566 ConnectMsg->
ClientView.SectionOffset = LargeSectionOffset.LowPart;
00567
00568
if (
NT_SUCCESS( Status )) {
00569
00570 ConnectMsg->
ClientView.ViewRemoteBase = ServerPort->
ClientSectionBase;
00571
00572 }
else {
00573
00574
00575
00576
00577
00578
00579
00580
00581
ObDereferenceObject( ServerPort );
00582 }
00583 }
00584
00585
00586
00587
00588
00589
00590
00591
00592
00593
00594
00595
if (
NT_SUCCESS( Status ) && ARGUMENT_PRESENT( ServerView )) {
00596
00597 LARGE_INTEGER LargeSectionOffset;
00598
00599 LargeSectionOffset.LowPart = CapturedServerView.SectionOffset;
00600 LargeSectionOffset.HighPart = 0;
00601
00602
00603
00604
00605
00606
00607
00608
00609
00610
00611
Status =
ObReferenceObjectByHandle( CapturedServerView.SectionHandle,
00612 SECTION_MAP_READ |
00613 SECTION_MAP_WRITE,
00614 MmSectionObjectType,
00615 PreviousMode,
00616 (PVOID *)&SectionToMap,
00617 NULL );
00618
00619
if (
NT_SUCCESS( Status )) {
00620
00621
Status =
MmMapViewOfSection( SectionToMap,
00622
PsGetCurrentProcess(),
00623 &ServerPort->
ServerSectionBase,
00624 0,
00625 0,
00626 &LargeSectionOffset,
00627 &CapturedServerView.ViewSize,
00628 ViewUnmap,
00629 0,
00630 PAGE_READWRITE );
00631
00632
if (
NT_SUCCESS( Status )) {
00633
00634 CapturedServerView.SectionOffset = LargeSectionOffset.LowPart;
00635
00636 CapturedServerView.ViewBase = ServerPort->
ServerSectionBase;
00637
00638
00639 SectionOffset.LowPart = CapturedServerView.SectionOffset;
00640 SectionOffset.HighPart = 0;
00641
00642 ViewSize = CapturedServerView.ViewSize;
00643
00644
Status =
MmMapViewOfSection( SectionToMap,
00645 ClientProcess,
00646 &ClientPort->
ServerSectionBase,
00647 0,
00648 0,
00649 &SectionOffset,
00650 &ViewSize,
00651 ViewUnmap,
00652 0,
00653 PAGE_READWRITE );
00654
00655
if (
NT_SUCCESS( Status )) {
00656
00657
00658
00659
00660
00661
00662 CapturedServerView.ViewRemoteBase = ClientPort->
ServerSectionBase;
00663
00664
00665
00666
00667
00668
00669 ConnectMsg->
ServerView.ViewBase = ClientPort->
ServerSectionBase;
00670 ConnectMsg->
ServerView.ViewSize = ViewSize;
00671
00672 }
else {
00673
00674
ObDereferenceObject( ServerPort );
00675 }
00676
00677 }
else {
00678
00679
ObDereferenceObject( ServerPort );
00680 }
00681
00682
ObDereferenceObject( SectionToMap );
00683
00684 }
else {
00685
00686
ObDereferenceObject( ServerPort );
00687 }
00688 }
00689
00690
00691
00692
00693
00694
00695
00696
00697
00698
00699
if (
NT_SUCCESS( Status )) {
00700
00701
00702
00703
00704
00705
00706
00707
ObReferenceObject( ServerPort );
00708
00709
00710
00711
00712
00713
Status =
ObInsertObject( ServerPort,
00714 NULL,
00715 PORT_ALL_ACCESS,
00716 0,
00717 (PVOID *)NULL,
00718 &Handle );
00719
00720
if (
NT_SUCCESS( Status )) {
00721
00722
try {
00723
00724
if (ARGUMENT_PRESENT( ServerView )) {
00725
00726 *ServerView = CapturedServerView;
00727 }
00728
00729
if (ARGUMENT_PRESENT( ClientView )) {
00730
00731 ClientView->ViewBase = ConnectMsg->
ClientView.ViewRemoteBase;
00732 ClientView->ViewSize = ConnectMsg->
ClientView.ViewSize;
00733 }
00734
00735 *
PortHandle =
Handle;
00736
00737
if (!ARGUMENT_PRESENT( PortContext )) {
00738
00739 ServerPort->
PortContext =
Handle;
00740 }
00741
00742 ServerPort->
ClientThread =
ClientThread;
00743
00744
LpcpAcquireLpcpLock();
00745
ClientThread->LpcReplyMessage = Msg;
00746
LpcpReleaseLpcpLock();
00747
00748
ClientThread =
NULL;
00749
00750 } except( EXCEPTION_EXECUTE_HANDLER ) {
00751
00752
NtClose( Handle );
00753
Status = GetExceptionCode();
00754 }
00755 }
00756
00757
00758
00759
00760
00761
ObDereferenceObject( ServerPort );
00762 }
00763
00764 }
else {
00765
00766
00767
00768
00769
00770
LpcpPrint((
"Refusing connection from %x.%x\n",
00771 Msg->
Request.ClientId.UniqueProcess,
00772 Msg->
Request.ClientId.UniqueThread ));
00773 }
00774
00775 bailout:
00776
00777
if ( ClientSectionToMap ) {
00778
00779
ObDereferenceObject( ClientSectionToMap );
00780 }
00781
00782
00783
00784
00785
00786
00787
00788
if (
ClientThread !=
NULL) {
00789
00790
LpcpAcquireLpcpLock();
00791
00792
ClientThread->LpcReplyMessage = Msg;
00793
00794
if (AcceptConnection) {
00795
00796
LpcpPrint((
"LPC: Failing AcceptConnection with Status == %x\n", Status ));
00797 }
00798
00799
LpcpPrepareToWakeClient( ClientThread );
00800
00801
LpcpReleaseLpcpLock();
00802
00803
00804
00805
00806
00807
00808
KeReleaseSemaphore( &
ClientThread->LpcReplySemaphore,
00809 0,
00810 1L,
00811 FALSE );
00812
00813
00814
00815
00816
00817
ObDereferenceObject( ClientThread );
00818 }
00819
00820
if (ClientPort) {
00821
00822
ObDereferenceObject( ClientPort );
00823 }
00824
00825
ObDereferenceObject( ClientProcess );
00826
00827
00828
00829
00830
00831
return Status;
00832 }