NTSTATUS NtAllocateLocallyUniqueId ( __out PLUID Luid ) /*++ Routine Description: This function returns an LUID value that is unique since the system was last rebooted. It is unique on the system it is generated on only (not network wide). There are no restrictions on who can allocate LUIDs. The LUID space is large enough that this will never present a problem. If one LUID is allocated every 100ns, they will not be exhausted for roughly 15,000 years (100ns * 2^63). Arguments: Luid - Supplies the address of a variable that will receive the new LUID. Return Value: STATUS_SUCCESS is returned if the service is successfully executed. STATUS_ACCESS_VIOLATION is returned if the output parameter for the LUID cannot be written. --*/ { KPROCESSOR_MODE PreviousMode; // // Get previous processor mode and probe argument if necessary. // try { PreviousMode = KeGetPreviousMode(); if (PreviousMode != KernelMode) { ProbeForWriteSmallStructure((PVOID)Luid, sizeof(LUID), sizeof(ULONG)); } // // Allocate and store a locally unique Id. // ExAllocateLocallyUniqueId(Luid); } except (ExSystemExceptionFilter()) { return GetExceptionCode(); } return STATUS_SUCCESS; }
NTSTATUS NtQueryFullAttributesFile ( __in POBJECT_ATTRIBUTES ObjectAttributes, __out PFILE_NETWORK_OPEN_INFORMATION FileInformation ) /*++ Routine Description: This service queries the network attributes information for a specified file. Arguments: ObjectAttributes - Supplies the attributes to be used for file object (name, SECURITY_DESCRIPTOR, etc.) FileInformation - Supplies an output buffer to receive the returned file attributes information. Return Value: The status returned is the final completion status of the operation. --*/ { KPROCESSOR_MODE requestorMode; NTSTATUS status; OPEN_PACKET openPacket; DUMMY_FILE_OBJECT localFileObject; FILE_NETWORK_OPEN_INFORMATION networkInformation; HANDLE handle; PAGED_CODE(); // // Get the previous mode; i.e., the mode of the caller. // requestorMode = KeGetPreviousMode(); if (requestorMode != KernelMode) { try { // // The caller's mode is not kernel, so probe the output buffer. // ProbeForWriteSmallStructure( FileInformation, sizeof( FILE_NETWORK_OPEN_INFORMATION ), #if defined(_X86_) sizeof( LONG )); #else sizeof( LONGLONG )); #endif // defined(_X86_) } except(EXCEPTION_EXECUTE_HANDLER) { // // An exception was incurred while probing the caller's parameters. // Simply return an appropriate error status code. // return GetExceptionCode(); } } // // Build a parse open packet that tells the parse method to open the file, // query the file's full attributes, and close the file. // RtlZeroMemory( &openPacket, sizeof( OPEN_PACKET ) ); openPacket.Type = IO_TYPE_OPEN_PACKET; openPacket.Size = sizeof( OPEN_PACKET ); openPacket.ShareAccess = (USHORT) FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE; openPacket.Disposition = FILE_OPEN; openPacket.CreateOptions = FILE_OPEN_REPARSE_POINT|FILE_OPEN_FOR_BACKUP_INTENT; openPacket.QueryOnly = TRUE; openPacket.FullAttributes = TRUE; openPacket.TraversedMountPoint = FALSE; openPacket.LocalFileObject = &localFileObject; if (requestorMode != KernelMode) { openPacket.NetworkInformation = &networkInformation; } else { openPacket.NetworkInformation = FileInformation; } // // Update the open count for this process. // IopUpdateOtherOperationCount(); // // Open the object by its name. Because of the special QueryOnly flag set // in the open packet, the parse routine will open the file, and then // realize that it is only performing a query. It will therefore perform // the query, and immediately close the file. // status = ObOpenObjectByName( ObjectAttributes, (POBJECT_TYPE) NULL, requestorMode, NULL, FILE_READ_ATTRIBUTES, &openPacket, &handle ); // // The operation is successful if the parse check field of the open packet // indicates that the parse routine was actually invoked, and the final // status field of the packet is set to success. // if (openPacket.ParseCheck != OPEN_PACKET_PATTERN) { if (NT_SUCCESS(status)) { ZwClose(handle); status = STATUS_OBJECT_TYPE_MISMATCH; } return status; } else { status = openPacket.FinalStatus; } if (NT_SUCCESS( status )) { if (requestorMode != KernelMode) { try { // // The query worked, so copy the returned information to the // caller's output buffer. // RtlCopyMemory( FileInformation, &networkInformation, sizeof( FILE_NETWORK_OPEN_INFORMATION ) ); } except(EXCEPTION_EXECUTE_HANDLER) { status = GetExceptionCode(); } } } return status; }
NTSTATUS NtPrivilegeCheck( __in HANDLE ClientToken, __inout PPRIVILEGE_SET RequiredPrivileges, __out PBOOLEAN Result ) /*++ Routine Description: This routine tests the caller's client's security context to see if it contains the specified privileges. Arguments: ClientToken - A handle to a token object representing a client attempting access. This handle must be obtained from a communication session layer, such as from an LPC Port or Local Named Pipe, to prevent possible security policy violations. RequiredPrivileges - Points to a set of privileges. The client's security context is to be checked to see which of the specified privileges are present. The results will be indicated in the attributes associated with each privilege. Note that flags in this parameter indicate whether all the privileges listed are needed, or any of the privileges. Result - Receives a boolean flag indicating whether the client has all the specified privileges or not. A value of TRUE indicates the client has all the specified privileges. Otherwise a value of FALSE is returned. Return Value: STATUS_SUCCESS - Indicates the call completed successfully. STATUS_PRIVILEGE_NOT_HELD - Indicates the caller does not have sufficient privilege to use this privileged system service. --*/ { BOOLEAN BStatus; KPROCESSOR_MODE PreviousMode; NTSTATUS Status; PLUID_AND_ATTRIBUTES CapturedPrivileges = NULL; PTOKEN Token = NULL; ULONG CapturedPrivilegeCount = 0; ULONG CapturedPrivilegesLength = 0; ULONG ParameterLength = 0; ULONG PrivilegeSetControl = 0; PAGED_CODE(); PreviousMode = KeGetPreviousMode(); Status = ObReferenceObjectByHandle( ClientToken, // Handle TOKEN_QUERY, // DesiredAccess SeTokenObjectType, // ObjectType PreviousMode, // AccessMode (PVOID *)&Token, // Object NULL // GrantedAccess ); if ( !NT_SUCCESS(Status) ) { return Status; } // // If the passed token is an impersonation token, make sure // it is at SecurityIdentification or above. // if (Token->TokenType == TokenImpersonation) { if (Token->ImpersonationLevel < SecurityIdentification) { ObDereferenceObject( (PVOID)Token ); return( STATUS_BAD_IMPERSONATION_LEVEL ); } } try { // // Capture passed Privilege Set // ProbeForWriteSmallStructure( RequiredPrivileges, sizeof(PRIVILEGE_SET), sizeof(ULONG) ); CapturedPrivilegeCount = RequiredPrivileges->PrivilegeCount; if (!IsValidElementCount(CapturedPrivilegeCount, LUID_AND_ATTRIBUTES)) { Status = STATUS_INVALID_PARAMETER; leave; } ParameterLength = (ULONG)sizeof(PRIVILEGE_SET) + ((CapturedPrivilegeCount - ANYSIZE_ARRAY) * (ULONG)sizeof(LUID_AND_ATTRIBUTES) ); ProbeForWrite( RequiredPrivileges, ParameterLength, sizeof(ULONG) ); ProbeForWriteBoolean(Result); PrivilegeSetControl = RequiredPrivileges->Control; } except(EXCEPTION_EXECUTE_HANDLER) { Status = GetExceptionCode(); } if (!NT_SUCCESS(Status)) { ObDereferenceObject( (PVOID)Token ); return Status; } Status = SeCaptureLuidAndAttributesArray( (RequiredPrivileges->Privilege), CapturedPrivilegeCount, UserMode, NULL, 0, PagedPool, TRUE, &CapturedPrivileges, &CapturedPrivilegesLength ); if (!NT_SUCCESS(Status)) { ObDereferenceObject( (PVOID)Token ); return Status; } BStatus = SepPrivilegeCheck( Token, // Token, CapturedPrivileges, // RequiredPrivileges, CapturedPrivilegeCount, // RequiredPrivilegeCount, PrivilegeSetControl, // PrivilegeSetControl PreviousMode // PreviousMode ); ObDereferenceObject( Token ); try { // // copy the modified privileges buffer back to user // RtlCopyMemory( RequiredPrivileges->Privilege, CapturedPrivileges, CapturedPrivilegesLength ); *Result = BStatus; } except (EXCEPTION_EXECUTE_HANDLER) { SeReleaseLuidAndAttributesArray( CapturedPrivileges, PreviousMode, TRUE ); return(GetExceptionCode()); } SeReleaseLuidAndAttributesArray( CapturedPrivileges, PreviousMode, TRUE ); return( STATUS_SUCCESS ); }
NTSTATUS KiContinueEx ( IN PCONTEXT ContextRecord, IN BOOLEAN TestAlert, IN PKEXCEPTION_FRAME ExceptionFrame, IN PKTRAP_FRAME TrapFrame ) /*++ Routine Description: This function is called to copy the specified context frame to the specified exception and trap frames for the continue system service. N.B. If the previous mode is user mode, alerts are being tested, a user APC is available to execute, and the specified context record was previously placed on the stack by the user APC initialization routine, then bypass context record copy to the kernel frames and back again. Arguments: ContextRecord - Supplies a pointer to a context record. TestAlert - Supplies a boolean value that determines whether a test alert is to be performed. ExceptionFrame - Supplies a pointer to an exception frame. TrapFrame - Supplies a pointer to a trap frame. Return Value: STATUS_ACCESS_VIOLATION is returned if the context record is not readable from user mode. STATUS_DATATYPE_MISALIGNMENT is returned if the context record is not properly aligned. STATUS_SUCCESS + 1 is returned if the context frame is copied successfully to the specified exception and trap frames. STATUS_SUCCESS is returned if the context record copy was bypassed and another user APC is ready to be delivered. --*/ { KIRQL OldIrql; NTSTATUS Status; PKTHREAD Thread; ULONG64 UserStack; // // Synchronize with other context operations. // // If the current IRQL is less than APC_LEVEL, then raise IRQL to APC level. // OldIrql = KeGetCurrentIrql(); if (OldIrql < APC_LEVEL) { KfRaiseIrql(APC_LEVEL); } // // If the previous mode was not kernel mode, then attempt to bypass // the copy of the context record. Otherwise, copy context to kernel // frames directly. // Status = STATUS_SUCCESS + 1; Thread = KeGetCurrentThread(); if (Thread->PreviousMode != KernelMode) { try { if (TestAlert != FALSE) { ProbeForWriteSmallStructure(ContextRecord, sizeof(CONTEXT), CONTEXT_ALIGN); KeTestAlertThread(UserMode); UserStack = (ContextRecord->Rsp - sizeof(MACHINE_FRAME)) & ~STACK_ROUND; if (((UserStack - sizeof(CONTEXT)) == (ULONG64)ContextRecord) && (Thread->ApcState.UserApcPending != FALSE)) { // // Save the context record and exception frame addresses // in the trap frame and deliver the user APC bypassing // the context copy. // TrapFrame->ContextRecord = (ULONG64)ContextRecord; TrapFrame->ExceptionFrame = (ULONG64)ExceptionFrame; KiDeliverApc(UserMode, NULL, TrapFrame); Status = STATUS_SUCCESS; leave; } } else { ProbeForReadSmallStructure(ContextRecord, sizeof(CONTEXT), CONTEXT_ALIGN); } KiContinuePreviousModeUser(ContextRecord, ExceptionFrame, TrapFrame); } except(EXCEPTION_EXECUTE_HANDLER) { Status = GetExceptionCode(); } } else {
NTSTATUS NtReplyWaitReceivePortEx( __in HANDLE PortHandle, __out_opt PVOID *PortContext, __in_opt PPORT_MESSAGE ReplyMessage, __out PPORT_MESSAGE ReceiveMessage, __in_opt PLARGE_INTEGER Timeout ) /*++ Routine Description: See NtReplyWaitReceivePort. Arguments: See NtReplyWaitReceivePort. Timeout - Supplies an optional timeout value to use when waiting for a receive. Return Value: See NtReplyWaitReceivePort. --*/ { PLPCP_PORT_OBJECT PortObject; PLPCP_PORT_OBJECT ReceivePort; PORT_MESSAGE CapturedReplyMessage; KPROCESSOR_MODE PreviousMode; KPROCESSOR_MODE WaitMode; NTSTATUS Status; PLPCP_MESSAGE Msg; PETHREAD CurrentThread; PETHREAD WakeupThread; LARGE_INTEGER TimeoutValue ; PLPCP_PORT_OBJECT ConnectionPort = NULL; PAGED_CODE(); CurrentThread = PsGetCurrentThread(); TimeoutValue.QuadPart = 0 ; // // Get previous processor mode // PreviousMode = KeGetPreviousMode(); WaitMode = PreviousMode; if (PreviousMode != KernelMode) { try { if (ARGUMENT_PRESENT( PortContext )) { ProbeForWriteUlong( (PULONG)PortContext ); } if (ARGUMENT_PRESENT( ReplyMessage)) { ProbeForReadSmallStructure( ReplyMessage, sizeof( *ReplyMessage ), sizeof( ULONG )); CapturedReplyMessage = *ReplyMessage; } if (ARGUMENT_PRESENT( Timeout )) { TimeoutValue = ProbeAndReadLargeInteger( Timeout ); Timeout = &TimeoutValue ; } ProbeForWriteSmallStructure( ReceiveMessage, sizeof( *ReceiveMessage ), sizeof( ULONG )); } except( EXCEPTION_EXECUTE_HANDLER ) { return GetExceptionCode(); } } else { // // Kernel mode threads call with wait mode of user so that their // kernel // stacks are swappable. Main consumer of this is // SepRmCommandThread // if ( IS_SYSTEM_THREAD(CurrentThread) ) {
NTSTATUS NtAcceptConnectPort ( __out PHANDLE PortHandle, __in_opt PVOID PortContext, __in PPORT_MESSAGE ConnectionRequest, __in BOOLEAN AcceptConnection, __inout_opt PPORT_VIEW ServerView, __out_opt PREMOTE_PORT_VIEW ClientView ) /*++ Routine Description: A server process can accept or reject a client connection request using the NtAcceptConnectPort service. The ConnectionRequest parameter must specify a connection request returned by a previous call to the NtListenPort service. This service will either complete the connection if the AcceptConnection parameter is TRUE, or reject the connection request if the AcceptConnection parameter is FALSE. In either case, the contents of the data portion of the connection request is the data to return to the caller of NtConnectPort. If the connection request is accepted, then two communication port objects will be created and connected together. One will be inserted in the client process' handle table and returned to the client via the PortHandle parameter it specified on the NtConnectPort service. The other will be inserted in the server process' handle table and returned via the PortHandle parameter specified on the NtCompleteConnectPort service. In addition the two communication ports (client and server) will be linked together. If the connection request is accepted, and the ServerView parameter was specified, then the section handle is examined. If it is valid, then the portion of the section described by the SectionOffset and ViewSize fields will be mapped into both the client and server process address spaces. The address in server's address space will be returned in the ViewBase field. The address in the client's address space will be returned in the ViewRemoteBase field. The actual offset and size used to map the section will be returned in the SectionOffset and ViewSize fields. Communication port objects are temporary objects that have no names and cannot be inherited. When either the client or server process calls the !f NtClose service for a communication port, the port will be deleted since there can never be more than one outstanding handle for each communication port. The port object type specific delete procedure will then be invoked. This delete procedure will examine the communication port, and if it is connected to another communication port, it will queue an LPC_PORT_CLOSED datagram to that port's message queue. This will allow both the client and server processes to notice when a port becomes disconnected, either because of an explicit call to NtClose or an implicit call due to process termination. In addition, the delete procedure will scan the message queue of the port being closed and for each message still in the queue, it will return an ERROR_PORT_CLOSED status to any thread that is waiting for a reply to the message. Arguments: PortHandle - A pointer to a variable that will receive the server communication port object handle value. PortContext - An uninterpreted pointer that is stored in the server communication port. This pointer is returned whenever a message is received for this port. ConnectionRequest - A pointer to a structure that describes the connection request being accepted or rejected: The ConnectionRequest structure ULONG Length - Specifies the size of this data structure in bytes. CLIENT_ID ClientId - Specifies a structure that contains the client identifier (CLIENT_ID) of the thread that sent the request. The ClientId Structure ULONG UniqueProcessId - A unique value for each process in the system. ULONG UniqueThreadId - A unique value for each thread in the system. ULONG MessageId - A unique value that identifies the connection request being completed. ULONG PortAttributes - This field has no meaning for this service. ULONG ClientViewSize - This field has no meaning for this service. AcceptConnection - Specifies a boolean value which indicates where the connection request is being accepted or rejected. A value of TRUE means that the connection request is accepted and a server communication port handle will be created and connected to the client's communication port handle. A value of FALSE means that the connection request is not accepted. ServerView - A pointer to a structure that specifies the section that the server process will use to send messages back to the client process connected to this port. The ServerView Structure ULONG Length - Specifies the size of this data structure in bytes. HANDLE SectionHandle - Specifies an open handle to a section object. ULONG SectionOffset - Specifies a field that will receive the actual offset, in bytes, from the start of the section. The initial value of this parameter specifies the byte offset within the section that the client's view is based. The value is rounded down to the next host page size boundary. ULONG ViewSize - Specifies the size of the view, in bytes. PVOID ViewBase - Specifies a field that will receive the base address of the port memory in the server's address space. PVOID ViewRemoteBase - Specifies a field that will receive the base address of the server port's memory in the client's address space. Used to generate pointers that are meaningful to the client. ClientView - An optional pointer to a structure that will receive information about the client process' view in the server's address space. The server process can use this information to validate pointers it receives from the client process. The ClientView Structure ULONG Length - Specifies the size of this data structure in bytes. PVOID ViewBase - Specifies a field that will receive the base address of the client port's memory in the server's address space. ULONG ViewSize - Specifies a field that will receive the size, in bytes, of the client's view in the server's address space. If this field is zero, then client has no view in the server's address space. Return Value: NTSTATUS - An appropriate status value. --*/ { PLPCP_PORT_OBJECT ConnectionPort; PLPCP_PORT_OBJECT ServerPort; PLPCP_PORT_OBJECT ClientPort; PVOID ClientSectionToMap; HANDLE Handle; KPROCESSOR_MODE PreviousMode; NTSTATUS Status; ULONG ConnectionInfoLength; PLPCP_MESSAGE Msg; PLPCP_CONNECTION_MESSAGE ConnectMsg; PORT_MESSAGE CapturedReplyMessage; PVOID SectionToMap; LARGE_INTEGER SectionOffset; SIZE_T ViewSize; PEPROCESS ClientProcess; PETHREAD ClientThread; PORT_VIEW CapturedServerView; PAGED_CODE(); // // Get previous processor mode and probe output arguments if necessary. // PreviousMode = KeGetPreviousMode(); if (PreviousMode != KernelMode) { try { ProbeForWriteHandle( PortHandle ); ProbeForReadSmallStructure( ConnectionRequest, sizeof( *ConnectionRequest ), sizeof( ULONG )); CapturedReplyMessage = *ConnectionRequest; if (ARGUMENT_PRESENT( ServerView )) { CapturedServerView = ProbeAndReadStructure( ServerView, PORT_VIEW ); if (CapturedServerView.Length != sizeof( *ServerView )) { return STATUS_INVALID_PARAMETER; } ProbeForWriteSmallStructure( ServerView, sizeof( *ServerView ), sizeof( ULONG )); } if (ARGUMENT_PRESENT( ClientView )) { if (ProbeAndReadUlong( &ClientView->Length ) != sizeof( *ClientView )) { return STATUS_INVALID_PARAMETER; } ProbeForWriteSmallStructure( ClientView, sizeof( *ClientView ), sizeof( ULONG )); } } except( EXCEPTION_EXECUTE_HANDLER ) { return GetExceptionCode(); } } else {