Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenconnect.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
1.7.6.1
|