ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

connect.c
Go to the documentation of this file.
00001 /*
00002  * PROJECT:         ReactOS Kernel
00003  * LICENSE:         GPL - See COPYING in the top level directory
00004  * FILE:            ntoskrnl/lpc/connect.c
00005  * PURPOSE:         Local Procedure Call: Connection Management
00006  * PROGRAMMERS:     Alex Ionescu (alex.ionescu@reactos.org)
00007  */
00008 
00009 /* INCLUDES ******************************************************************/
00010 
00011 #include <ntoskrnl.h>
00012 #define NDEBUG
00013 #include <debug.h>
00014 
00015 /* PRIVATE FUNCTIONS *********************************************************/
00016 
00017 PVOID
00018 NTAPI
00019 LpcpFreeConMsg(IN OUT PLPCP_MESSAGE *Message,
00020                IN OUT PLPCP_CONNECTION_MESSAGE *ConnectMessage,
00021                IN PETHREAD CurrentThread)
00022 {
00023     PVOID SectionToMap;
00024     PLPCP_MESSAGE ReplyMessage;
00025 
00026     /* Acquire the LPC lock */
00027     KeAcquireGuardedMutex(&LpcpLock);
00028 
00029     /* Check if the reply chain is not empty */
00030     if (!IsListEmpty(&CurrentThread->LpcReplyChain))
00031     {
00032         /* Remove this entry and re-initialize it */
00033         RemoveEntryList(&CurrentThread->LpcReplyChain);
00034         InitializeListHead(&CurrentThread->LpcReplyChain);
00035     }
00036 
00037     /* Check if there's a reply message */
00038     ReplyMessage = LpcpGetMessageFromThread(CurrentThread);
00039     if (ReplyMessage)
00040     {
00041         /* Get the message */
00042         *Message = ReplyMessage;
00043 
00044         /* Check if it's got messages */
00045         if (!IsListEmpty(&ReplyMessage->Entry))
00046         {
00047             /* Clear the list */
00048             RemoveEntryList(&ReplyMessage->Entry);
00049             InitializeListHead(&ReplyMessage->Entry);
00050         }
00051 
00052         /* Clear message data */
00053         CurrentThread->LpcReceivedMessageId = 0;
00054         CurrentThread->LpcReplyMessage = NULL;
00055 
00056         /* Get the connection message and clear the section */
00057         *ConnectMessage = (PLPCP_CONNECTION_MESSAGE)(ReplyMessage + 1);
00058         SectionToMap = (*ConnectMessage)->SectionToMap;
00059         (*ConnectMessage)->SectionToMap = NULL;
00060     }
00061     else
00062     {
00063         /* No message to return */
00064         *Message = NULL;
00065         SectionToMap = NULL;
00066     }
00067 
00068     /* Release the lock and return the section */
00069     KeReleaseGuardedMutex(&LpcpLock);
00070     return SectionToMap;
00071 }
00072 
00073 /* PUBLIC FUNCTIONS **********************************************************/
00074 
00075 /*
00076  * @implemented
00077  */
00078 NTSTATUS
00079 NTAPI
00080 NtSecureConnectPort(OUT PHANDLE PortHandle,
00081                     IN PUNICODE_STRING PortName,
00082                     IN PSECURITY_QUALITY_OF_SERVICE Qos,
00083                     IN OUT PPORT_VIEW ClientView OPTIONAL,
00084                     IN PSID ServerSid OPTIONAL,
00085                     IN OUT PREMOTE_PORT_VIEW ServerView OPTIONAL,
00086                     OUT PULONG MaxMessageLength OPTIONAL,
00087                     IN OUT PVOID ConnectionInformation OPTIONAL,
00088                     IN OUT PULONG ConnectionInformationLength OPTIONAL)
00089 {
00090     ULONG ConnectionInfoLength = 0;
00091     PLPCP_PORT_OBJECT Port, ClientPort;
00092     KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
00093     NTSTATUS Status = STATUS_SUCCESS;
00094     HANDLE Handle;
00095     PVOID SectionToMap;
00096     PLPCP_MESSAGE Message;
00097     PLPCP_CONNECTION_MESSAGE ConnectMessage;
00098     PETHREAD Thread = PsGetCurrentThread();
00099     ULONG PortMessageLength;
00100     LARGE_INTEGER SectionOffset;
00101     PTOKEN Token;
00102     PTOKEN_USER TokenUserInfo;
00103     PAGED_CODE();
00104     LPCTRACE(LPC_CONNECT_DEBUG,
00105              "Name: %wZ. Qos: %p. Views: %p/%p. Sid: %p\n",
00106              PortName,
00107              Qos,
00108              ClientView,
00109              ServerView,
00110              ServerSid);
00111 
00112     /* Validate client view */
00113     if ((ClientView) && (ClientView->Length != sizeof(PORT_VIEW)))
00114     {
00115         /* Fail */
00116         return STATUS_INVALID_PARAMETER;
00117     }
00118 
00119     /* Validate server view */
00120     if ((ServerView) && (ServerView->Length != sizeof(REMOTE_PORT_VIEW)))
00121     {
00122         /* Fail */
00123         return STATUS_INVALID_PARAMETER;
00124     }
00125 
00126     /* Check if caller sent connection information length */
00127     if (ConnectionInformationLength)
00128     {
00129         /* Retrieve the input length */
00130         ConnectionInfoLength = *ConnectionInformationLength;
00131     }
00132 
00133     /* Get the port */
00134     Status = ObReferenceObjectByName(PortName,
00135                                      0,
00136                                      NULL,
00137                                      PORT_CONNECT,
00138                                      LpcPortObjectType,
00139                                      PreviousMode,
00140                                      NULL,
00141                                      (PVOID *)&Port);
00142     if (!NT_SUCCESS(Status)) return Status;
00143 
00144     /* This has to be a connection port */
00145     if ((Port->Flags & LPCP_PORT_TYPE_MASK) != LPCP_CONNECTION_PORT)
00146     {
00147         /* It isn't, so fail */
00148         ObDereferenceObject(Port);
00149         return STATUS_INVALID_PORT_HANDLE;
00150     }
00151 
00152     /* Check if we have a SID */
00153     if (ServerSid)
00154     {
00155         /* Make sure that we have a server */
00156         if (Port->ServerProcess)
00157         {
00158             /* Get its token and query user information */
00159             Token = PsReferencePrimaryToken(Port->ServerProcess);
00160             //Status = SeQueryInformationToken(Token, TokenUser, (PVOID*)&TokenUserInfo);
00161             // FIXME: Need SeQueryInformationToken
00162             Status = STATUS_SUCCESS;
00163             TokenUserInfo = ExAllocatePool(PagedPool, sizeof(TOKEN_USER));
00164             TokenUserInfo->User.Sid = ServerSid;
00165             PsDereferencePrimaryToken(Token);
00166 
00167             /* Check for success */
00168             if (NT_SUCCESS(Status))
00169             {
00170                 /* Compare the SIDs */
00171                 if (!RtlEqualSid(ServerSid, TokenUserInfo->User.Sid))
00172                 {
00173                     /* Fail */
00174                     Status = STATUS_SERVER_SID_MISMATCH;
00175                 }
00176 
00177                 /* Free token information */
00178                 ExFreePool(TokenUserInfo);
00179             }
00180         }
00181         else
00182         {
00183             /* Invalid SID */
00184             Status = STATUS_SERVER_SID_MISMATCH;
00185         }
00186 
00187         /* Check if SID failed */
00188         if (!NT_SUCCESS(Status))
00189         {
00190             /* Quit */
00191             ObDereferenceObject(Port);
00192             return Status;
00193         }
00194     }
00195 
00196     /* Create the client port */
00197     Status = ObCreateObject(PreviousMode,
00198                             LpcPortObjectType,
00199                             NULL,
00200                             PreviousMode,
00201                             NULL,
00202                             sizeof(LPCP_PORT_OBJECT),
00203                             0,
00204                             0,
00205                             (PVOID *)&ClientPort);
00206     if (!NT_SUCCESS(Status))
00207     {
00208         /* Failed, dereference the server port and return */
00209         ObDereferenceObject(Port);
00210         return Status;
00211     }
00212 
00213     /* Setup the client port */
00214     RtlZeroMemory(ClientPort, sizeof(LPCP_PORT_OBJECT));
00215     ClientPort->Flags = LPCP_CLIENT_PORT;
00216     ClientPort->ConnectionPort = Port;
00217     ClientPort->MaxMessageLength = Port->MaxMessageLength;
00218     ClientPort->SecurityQos = *Qos;
00219     InitializeListHead(&ClientPort->LpcReplyChainHead);
00220     InitializeListHead(&ClientPort->LpcDataInfoChainHead);
00221 
00222     /* Check if we have dynamic security */
00223     if (Qos->ContextTrackingMode == SECURITY_DYNAMIC_TRACKING)
00224     {
00225         /* Remember that */
00226         ClientPort->Flags |= LPCP_SECURITY_DYNAMIC;
00227     }
00228     else
00229     {
00230         /* Create our own client security */
00231         Status = SeCreateClientSecurity(Thread,
00232                                         Qos,
00233                                         FALSE,
00234                                         &ClientPort->StaticSecurity);
00235         if (!NT_SUCCESS(Status))
00236         {
00237             /* Security failed, dereference and return */
00238             ObDereferenceObject(ClientPort);
00239             return Status;
00240         }
00241     }
00242 
00243     /* Initialize the port queue */
00244     Status = LpcpInitializePortQueue(ClientPort);
00245     if (!NT_SUCCESS(Status))
00246     {
00247         /* Failed */
00248         ObDereferenceObject(ClientPort);
00249         return Status;
00250     }
00251 
00252     /* Check if we have a client view */
00253     if (ClientView)
00254     {
00255         /* Get the section handle */
00256         Status = ObReferenceObjectByHandle(ClientView->SectionHandle,
00257                                            SECTION_MAP_READ |
00258                                            SECTION_MAP_WRITE,
00259                                            MmSectionObjectType,
00260                                            PreviousMode,
00261                                            (PVOID*)&SectionToMap,
00262                                            NULL);
00263         if (!NT_SUCCESS(Status))
00264         {
00265             /* Fail */
00266             ObDereferenceObject(Port);
00267             return Status;
00268         }
00269 
00270         /* Set the section offset */
00271         SectionOffset.QuadPart = ClientView->SectionOffset;
00272 
00273         /* Map it */
00274         Status = MmMapViewOfSection(SectionToMap,
00275                                     PsGetCurrentProcess(),
00276                                     &ClientPort->ClientSectionBase,
00277                                     0,
00278                                     0,
00279                                     &SectionOffset,
00280                                     &ClientView->ViewSize,
00281                                     ViewUnmap,
00282                                     0,
00283                                     PAGE_READWRITE);
00284 
00285         /* Update the offset */
00286         ClientView->SectionOffset = SectionOffset.LowPart;
00287 
00288         /* Check for failure */
00289         if (!NT_SUCCESS(Status))
00290         {
00291             /* Fail */
00292             ObDereferenceObject(SectionToMap);
00293             ObDereferenceObject(Port);
00294             return Status;
00295         }
00296 
00297         /* Update the base */
00298         ClientView->ViewBase = ClientPort->ClientSectionBase;
00299 
00300         /* Reference and remember the process */
00301         ClientPort->MappingProcess = PsGetCurrentProcess();
00302         ObReferenceObject(ClientPort->MappingProcess);
00303     }
00304     else
00305     {
00306         /* No section */
00307         SectionToMap = NULL;
00308     }
00309 
00310     /* Normalize connection information */
00311     if (ConnectionInfoLength > Port->MaxConnectionInfoLength)
00312     {
00313         /* Use the port's maximum allowed value */
00314         ConnectionInfoLength = Port->MaxConnectionInfoLength;
00315     }
00316 
00317     /* Allocate a message from the port zone */
00318     Message = LpcpAllocateFromPortZone();
00319     if (!Message)
00320     {
00321         /* Fail if we couldn't allocate a message */
00322         if (SectionToMap) ObDereferenceObject(SectionToMap);
00323         ObDereferenceObject(ClientPort);
00324         return STATUS_NO_MEMORY;
00325     }
00326 
00327     /* Set pointer to the connection message and fill in the CID */
00328     ConnectMessage = (PLPCP_CONNECTION_MESSAGE)(Message + 1);
00329     Message->Request.ClientId = Thread->Cid;
00330 
00331     /* Check if we have a client view */
00332     if (ClientView)
00333     {
00334         /* Set the view size */
00335         Message->Request.ClientViewSize = ClientView->ViewSize;
00336 
00337         /* Copy the client view and clear the server view */
00338         RtlCopyMemory(&ConnectMessage->ClientView,
00339                       ClientView,
00340                       sizeof(PORT_VIEW));
00341         RtlZeroMemory(&ConnectMessage->ServerView, sizeof(REMOTE_PORT_VIEW));
00342     }
00343     else
00344     {
00345         /* Set the size to 0 and clear the connect message */
00346         Message->Request.ClientViewSize = 0;
00347         RtlZeroMemory(ConnectMessage, sizeof(LPCP_CONNECTION_MESSAGE));
00348     }
00349 
00350     /* Set the section and client port. Port is NULL for now */
00351     ConnectMessage->ClientPort = NULL;
00352     ConnectMessage->SectionToMap = SectionToMap;
00353 
00354     /* Set the data for the connection request message */
00355     Message->Request.u1.s1.DataLength = (CSHORT)ConnectionInfoLength + 
00356                                          sizeof(LPCP_CONNECTION_MESSAGE);
00357     Message->Request.u1.s1.TotalLength = sizeof(LPCP_MESSAGE) +
00358                                          Message->Request.u1.s1.DataLength;
00359     Message->Request.u2.s2.Type = LPC_CONNECTION_REQUEST;
00360 
00361     /* Check if we have connection information */
00362     if (ConnectionInformation)
00363     {
00364         /* Copy it in */
00365         RtlCopyMemory(ConnectMessage + 1,
00366                       ConnectionInformation,
00367                       ConnectionInfoLength);
00368     }
00369 
00370     /* Acquire the port lock */
00371     KeAcquireGuardedMutex(&LpcpLock);
00372 
00373     /* Check if someone already deleted the port name */
00374     if (Port->Flags & LPCP_NAME_DELETED)
00375     {
00376         /* Fail the request */
00377         Status = STATUS_OBJECT_NAME_NOT_FOUND;
00378     }
00379     else
00380     {
00381         /* Associate no thread yet */
00382         Message->RepliedToThread = NULL;
00383 
00384         /* Generate the Message ID and set it */
00385         Message->Request.MessageId =  LpcpNextMessageId++;
00386         if (!LpcpNextMessageId) LpcpNextMessageId = 1;
00387         Thread->LpcReplyMessageId = Message->Request.MessageId;
00388 
00389         /* Insert the message into the queue and thread chain */
00390         InsertTailList(&Port->MsgQueue.ReceiveHead, &Message->Entry);
00391         InsertTailList(&Port->LpcReplyChainHead, &Thread->LpcReplyChain);
00392         Thread->LpcReplyMessage = Message;
00393 
00394         /* Now we can finally reference the client port and link it*/
00395         ObReferenceObject(ClientPort);
00396         ConnectMessage->ClientPort = ClientPort;
00397 
00398         /* Enter a critical region */
00399         KeEnterCriticalRegion();
00400     }
00401 
00402     /* Add another reference to the port */
00403     ObReferenceObject(Port);
00404 
00405     /* Release the lock */
00406     KeReleaseGuardedMutex(&LpcpLock);
00407 
00408     /* Check for success */
00409     if (NT_SUCCESS(Status))
00410     {
00411         LPCTRACE(LPC_CONNECT_DEBUG,
00412                  "Messages: %p/%p. Ports: %p/%p. Status: %lx\n",
00413                  Message,
00414                  ConnectMessage,
00415                  Port,
00416                  ClientPort,
00417                  Status);
00418 
00419         /* If this is a waitable port, set the event */
00420         if (Port->Flags & LPCP_WAITABLE_PORT) KeSetEvent(&Port->WaitEvent,
00421                                                          1,
00422                                                          FALSE);
00423 
00424         /* Release the queue semaphore and leave the critical region */
00425         LpcpCompleteWait(Port->MsgQueue.Semaphore);
00426         KeLeaveCriticalRegion();
00427 
00428         /* Now wait for a reply */
00429         LpcpConnectWait(&Thread->LpcReplySemaphore, PreviousMode);
00430     }
00431 
00432     /* Check for failure */
00433     if (!NT_SUCCESS(Status)) goto Cleanup;
00434 
00435     /* Free the connection message */
00436     SectionToMap = LpcpFreeConMsg(&Message, &ConnectMessage, Thread);
00437 
00438     /* Check if we got a message back */
00439     if (Message)
00440     {
00441         /* Check for new return length */
00442         if ((Message->Request.u1.s1.DataLength -
00443              sizeof(LPCP_CONNECTION_MESSAGE)) < ConnectionInfoLength)
00444         {
00445             /* Set new normalized connection length */
00446             ConnectionInfoLength = Message->Request.u1.s1.DataLength -
00447                                    sizeof(LPCP_CONNECTION_MESSAGE);
00448         }
00449 
00450         /* Check if we had connection information */
00451         if (ConnectionInformation)
00452         {
00453             /* Check if we had a length pointer */
00454             if (ConnectionInformationLength)
00455             {
00456                 /* Return the length */
00457                 *ConnectionInformationLength = ConnectionInfoLength;
00458             }
00459 
00460             /* Return the connection information */
00461             RtlCopyMemory(ConnectionInformation,
00462                           ConnectMessage + 1,
00463                           ConnectionInfoLength );
00464         }
00465 
00466         /* Make sure we had a connected port */
00467         if (ClientPort->ConnectedPort)
00468         {
00469             /* Get the message length before the port might get killed */
00470             PortMessageLength = Port->MaxMessageLength;
00471 
00472             /* Insert the client port */
00473             Status = ObInsertObject(ClientPort,
00474                                     NULL,
00475                                     PORT_ALL_ACCESS,
00476                                     0,
00477                                     (PVOID *)NULL,
00478                                     &Handle);
00479             if (NT_SUCCESS(Status))
00480             {
00481                 /* Return the handle */
00482                 *PortHandle = Handle;
00483                 LPCTRACE(LPC_CONNECT_DEBUG,
00484                          "Handle: %lx. Length: %lx\n",
00485                          Handle,
00486                          PortMessageLength);
00487 
00488                 /* Check if maximum length was requested */
00489                 if (MaxMessageLength) *MaxMessageLength = PortMessageLength;
00490 
00491                 /* Check if we had a client view */
00492                 if (ClientView)
00493                 {
00494                     /* Copy it back */
00495                     RtlCopyMemory(ClientView,
00496                                   &ConnectMessage->ClientView,
00497                                   sizeof(PORT_VIEW));
00498                 }
00499 
00500                 /* Check if we had a server view */
00501                 if (ServerView)
00502                 {
00503                     /* Copy it back */
00504                     RtlCopyMemory(ServerView,
00505                                   &ConnectMessage->ServerView,
00506                                   sizeof(REMOTE_PORT_VIEW));
00507                 }
00508             }
00509         }
00510         else
00511         {
00512             /* No connection port, we failed */
00513             if (SectionToMap) ObDereferenceObject(SectionToMap);
00514 
00515             /* Acquire the lock */
00516             KeAcquireGuardedMutex(&LpcpLock);
00517 
00518             /* Check if it's because the name got deleted */
00519             if (!(ClientPort->ConnectionPort) ||
00520                 (Port->Flags & LPCP_NAME_DELETED))
00521             {
00522                 /* Set the correct status */
00523                 Status = STATUS_OBJECT_NAME_NOT_FOUND;
00524             }
00525             else
00526             {
00527                 /* Otherwise, the caller refused us */
00528                 Status = STATUS_PORT_CONNECTION_REFUSED;
00529             }
00530 
00531             /* Release the lock */
00532             KeReleaseGuardedMutex(&LpcpLock);
00533 
00534             /* Kill the port */
00535             ObDereferenceObject(ClientPort);
00536         }
00537 
00538         /* Free the message */
00539         LpcpFreeToPortZone(Message, 0);
00540     }
00541     else
00542     {
00543         /* No reply message, fail */
00544         if (SectionToMap) ObDereferenceObject(SectionToMap);
00545         ObDereferenceObject(ClientPort);
00546         Status = STATUS_PORT_CONNECTION_REFUSED;
00547     }
00548 
00549     /* Return status */
00550     ObDereferenceObject(Port);
00551     return Status;
00552 
00553 Cleanup:
00554     /* We failed, free the message */
00555     SectionToMap = LpcpFreeConMsg(&Message, &ConnectMessage, Thread);
00556 
00557     /* Check if the semaphore got signaled */
00558     if (KeReadStateSemaphore(&Thread->LpcReplySemaphore))
00559     {
00560         /* Wait on it */
00561         KeWaitForSingleObject(&Thread->LpcReplySemaphore,
00562                               WrExecutive,
00563                               KernelMode,
00564                               FALSE,
00565                               NULL);
00566     }
00567 
00568     /* Check if we had a message and free it */
00569     if (Message) LpcpFreeToPortZone(Message, 0);
00570 
00571     /* Dereference other objects */
00572     if (SectionToMap) ObDereferenceObject(SectionToMap);
00573     ObDereferenceObject(ClientPort);
00574 
00575     /* Return status */
00576     ObDereferenceObject(Port);
00577     return Status;
00578 }
00579 
00580 /*
00581  * @implemented
00582  */
00583 NTSTATUS
00584 NTAPI
00585 NtConnectPort(OUT PHANDLE PortHandle,
00586               IN PUNICODE_STRING PortName,
00587               IN PSECURITY_QUALITY_OF_SERVICE Qos,
00588               IN PPORT_VIEW ClientView,
00589               IN PREMOTE_PORT_VIEW ServerView,
00590               OUT PULONG MaxMessageLength,
00591               IN PVOID ConnectionInformation,
00592               OUT PULONG ConnectionInformationLength)
00593 {
00594     /* Call the newer API */
00595     return NtSecureConnectPort(PortHandle,
00596                                PortName,
00597                                Qos,
00598                                ClientView,
00599                                NULL,
00600                                ServerView,
00601                                MaxMessageLength,
00602                                ConnectionInformation,
00603                                ConnectionInformationLength);
00604 }
00605 
00606 /* EOF */

Generated on Sat May 26 2012 04:21:03 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.