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

rmmain.c

Go to the documentation of this file.
00001 /*++ 00002 00003 Copyright (c) 1991 Microsoft Corporation 00004 00005 Module Name: 00006 00007 rmmain.c 00008 00009 Abstract: 00010 00011 Security Reference Monitor - Init, Control and State Change 00012 00013 Author: 00014 00015 Scott Birrell (ScottBi) March 12, 1991 00016 00017 Environment: 00018 00019 Revision History: 00020 00021 --*/ 00022 00023 #include <nt.h> 00024 #include <ntlsa.h> 00025 #include "sep.h" 00026 #include <zwapi.h> 00027 #include "rmp.h" 00028 #include "adt.h" 00029 #include "adtp.h" 00030 00031 #ifdef ALLOC_PRAGMA 00032 #pragma alloc_text(INIT,SepRmInitPhase0) 00033 #pragma alloc_text(INIT,SeRmInitPhase1) 00034 #pragma alloc_text(PAGE,SepRmCommandServerThread) 00035 #pragma alloc_text(PAGE,SepRmCommandServerThreadInit) 00036 #pragma alloc_text(PAGE,SepRmComponentTestCommandWrkr) 00037 #pragma alloc_text(PAGE,SepRmSendCommandToLsaWrkr) 00038 #pragma alloc_text(PAGE,SepRmCallLsa) 00039 #endif 00040 00041 // 00042 // Reference Monitor Command Worker Table 00043 // 00044 00045 // 00046 // Keep this in sync with RM_COMMAND_NUMBER in ntrmlsa.h 00047 // 00048 00049 SEP_RM_COMMAND_WORKER SepRmCommandDispatch[] = { 00050 SepRmComponentTestCommandWrkr, 00051 SepRmSetAuditEventWrkr, 00052 SepRmSendCommandToLsaWrkr, 00053 SepRmComponentTestCommandWrkr, 00054 SepRmCreateLogonSessionWrkr, 00055 SepRmDeleteLogonSessionWrkr 00056 }; 00057 00058 00059 BOOLEAN 00060 SeRmInitPhase1( 00061 ) 00062 00063 /*++ 00064 00065 Routine Description: 00066 00067 This function is called by Phase 1 System Initialization to initialize 00068 the Security Reference Monitor. Note that initialization of the 00069 Reference Monitor Global State has already been performed in Phase 0 00070 initialization to allow access validation routines to operate without 00071 having to check that Reference Monitor Initialization is complete. 00072 00073 The steps listed below are performed in this routine. The remainder 00074 of Reference Monitor initialization requires the LSA subsystem to have run, 00075 so that initialization is performed in a separate thread (the RM Command 00076 Server Thread, see below), so that the present thread can create the 00077 Session Manager which execs the LSA. 00078 00079 o Create the Reference Monitor Command LPC port. The LSA subsystem sends 00080 commands (e.g. turn on auditing) which change the Reference Monitor 00081 Global State. 00082 o Create an Event for use in synchronizing with the LSA subsystem. The 00083 LSA will signal the event when the portion of LSA initialization upon 00084 with the Reference Monitor depends is complete. The Reference Monitor 00085 uses another LPC port, called the LSA Command Port to send commands 00086 to the LSA, so the RM must know that this port has been created before 00087 trying to connect to it. 00088 o Create the Reference Monitor Command Server Thread. This thread is 00089 a permanent thread of the System Init process that fields the Reference 00090 Monitor State Change commands described above. 00091 00092 00093 Arguments: 00094 00095 None. 00096 00097 Return Value: 00098 00099 BOOLEAN - TRUE if Rm Initialization (Phase 1) succeeded, else FALSE 00100 00101 --*/ 00102 00103 { 00104 NTSTATUS Status; 00105 STRING RmCommandPortName; 00106 UNICODE_STRING UnicodeRmCommandPortName; 00107 OBJECT_ATTRIBUTES ObjectAttributes; 00108 STRING LsaInitEventName; 00109 UNICODE_STRING UnicodeLsaInitEventName; 00110 OBJECT_ATTRIBUTES LsaInitEventObjectAttributes; 00111 SECURITY_DESCRIPTOR LsaInitEventSecurityDescriptor; 00112 ULONG AclSize; 00113 00114 PAGED_CODE(); 00115 00116 // 00117 // Create an LPC port called the Reference Monitor Command Port. 00118 // This will be used by the LSA to send commands to the Reference 00119 // Monitor to update its state data. 00120 // 00121 00122 RtlInitString( &RmCommandPortName, "\\SeRmCommandPort" ); 00123 Status = RtlAnsiStringToUnicodeString( 00124 &UnicodeRmCommandPortName, 00125 &RmCommandPortName, 00126 TRUE ); ASSERT( NT_SUCCESS(Status) ); 00127 InitializeObjectAttributes( 00128 &ObjectAttributes, 00129 &UnicodeRmCommandPortName, 00130 0, 00131 NULL, 00132 NULL 00133 ); 00134 00135 Status = ZwCreatePort( 00136 &SepRmState.RmCommandPortHandle, 00137 &ObjectAttributes, 00138 sizeof(SEP_RM_CONNECT_INFO), 00139 sizeof(RM_COMMAND_MESSAGE), 00140 sizeof(RM_COMMAND_MESSAGE) * 32 00141 ); 00142 RtlFreeUnicodeString( &UnicodeRmCommandPortName ); 00143 00144 if( !NT_SUCCESS(Status) ) { 00145 00146 KdPrint(("Security: Rm Create Command Port failed 0x%lx\n", Status)); 00147 return FALSE; 00148 } 00149 00150 // 00151 // Prepare to create an event for synchronizing with the LSA. 00152 // First, build the Security Descriptor for the Init Event Object 00153 // 00154 00155 Status = RtlCreateSecurityDescriptor( 00156 &LsaInitEventSecurityDescriptor, 00157 SECURITY_DESCRIPTOR_REVISION 00158 ); 00159 00160 if (!NT_SUCCESS(Status)) { 00161 00162 KdPrint(("Security: Creating Lsa Init Event Desc failed 0x%lx\n", 00163 Status)); 00164 return FALSE; 00165 } 00166 00167 // 00168 // Allocate a temporary buffer from the paged pool. It is a fatal 00169 // system error if the allocation fails since security cannot be 00170 // enabled. 00171 // 00172 00173 AclSize = sizeof(ACL) + 00174 sizeof(ACCESS_ALLOWED_ACE) + 00175 SeLengthSid(SeLocalSystemSid); 00176 LsaInitEventSecurityDescriptor.Dacl = 00177 ExAllocatePoolWithTag(PagedPool, AclSize, 'cAeS'); 00178 00179 if (LsaInitEventSecurityDescriptor.Dacl == NULL) { 00180 00181 KdPrint(("Security LSA: Insufficient resources to initialize\n")); 00182 return FALSE; 00183 } 00184 00185 // 00186 // Now create the Discretionary ACL within the Security Descriptor 00187 // 00188 00189 Status = RtlCreateAcl( 00190 LsaInitEventSecurityDescriptor.Dacl, 00191 AclSize, 00192 ACL_REVISION2 00193 ); 00194 00195 if (!NT_SUCCESS(Status)) { 00196 00197 KdPrint(("Security: Creating Lsa Init Event Dacl failed 0x%lx\n", 00198 Status)); 00199 return FALSE; 00200 } 00201 00202 // 00203 // Now add an ACE giving GENERIC_ALL access to the User ID 00204 // 00205 00206 Status = RtlAddAccessAllowedAce( 00207 LsaInitEventSecurityDescriptor.Dacl, 00208 ACL_REVISION2, 00209 GENERIC_ALL, 00210 SeLocalSystemSid 00211 ); 00212 00213 if (!NT_SUCCESS(Status)) { 00214 00215 KdPrint(("Security: Adding Lsa Init Event ACE failed 0x%lx\n", 00216 Status)); 00217 return FALSE; 00218 } 00219 00220 // 00221 // Set up the Object Attributes for the Lsa Initialization Event 00222 // 00223 00224 RtlInitString( &LsaInitEventName, "\\SeLsaInitEvent" ); 00225 Status = RtlAnsiStringToUnicodeString( 00226 &UnicodeLsaInitEventName, 00227 &LsaInitEventName, 00228 TRUE ); ASSERT( NT_SUCCESS(Status) ); 00229 InitializeObjectAttributes( 00230 &LsaInitEventObjectAttributes, 00231 &UnicodeLsaInitEventName, 00232 0, 00233 NULL, 00234 &LsaInitEventSecurityDescriptor 00235 ); 00236 00237 // 00238 // Create an event for use in synchronizing with the LSA. The LSA will 00239 // signal this event when LSA initialization has reached the point 00240 // where the LSA's Reference Monitor Server Port has been created. 00241 // 00242 00243 Status = ZwCreateEvent( 00244 &(SepRmState.LsaInitEventHandle), 00245 EVENT_MODIFY_STATE, 00246 &LsaInitEventObjectAttributes, 00247 NotificationEvent, 00248 FALSE); 00249 00250 RtlFreeUnicodeString( &UnicodeLsaInitEventName ); 00251 00252 if (!NT_SUCCESS(Status)) { 00253 00254 KdPrint(("Security: LSA init event creation failed.0x%xl\n", 00255 Status)); 00256 return FALSE; 00257 } 00258 00259 // 00260 // Deallocate the pool memory used for the Init Event DACL 00261 // 00262 00263 ExFreePool( LsaInitEventSecurityDescriptor.Dacl ); 00264 00265 // 00266 // Create a permanent thread of the Sysinit Process, called the 00267 // Reference Monitor Server Thread. This thread is dedicated to 00268 // receiving Reference Monitor commands and dispatching them. 00269 // 00270 00271 Status = PsCreateSystemThread( 00272 &SepRmState.SepRmThreadHandle, 00273 THREAD_GET_CONTEXT | 00274 THREAD_SET_CONTEXT | 00275 THREAD_SET_INFORMATION, 00276 NULL, 00277 NULL, 00278 NULL, 00279 SepRmCommandServerThread, 00280 NULL 00281 ); 00282 00283 if (!NT_SUCCESS(Status)) { 00284 00285 KdPrint(("Security: Rm Server Thread creation failed 0x%lx\n", Status)); 00286 return FALSE; 00287 } 00288 00289 // 00290 // Initialize data from the registry. This must go here because all other 00291 // Se initialization takes place before the registry is initialized. 00292 // 00293 00294 SepAdtInitializeCrashOnFail(); 00295 SepAdtInitializePrivilegeAuditing(); 00296 SepAdtInitializeAuditingOptions(); 00297 00298 // 00299 // Reference Monitor initialization is successful if we get to here. 00300 // 00301 00302 ZwClose( SepRmState.SepRmThreadHandle ); 00303 SepRmState.SepRmThreadHandle = NULL; 00304 return TRUE; 00305 } 00306 00307 00308 VOID 00309 SepRmCommandServerThread( 00310 IN PVOID StartContext 00311 ) 00312 00313 /*++ 00314 00315 Routine Description: 00316 00317 This function is executed indefinitely by a dedicated permanent thread 00318 of the Sysinit Process, called the Reference Monitor Server Thread. 00319 This thread updates Reference Monitor Global State Data by dispatching 00320 commands sent from the LSA through the the Reference Monitor LPC Command 00321 Port. The following steps are repeated indefinitely: 00322 00323 o Initialize RM Command receive and reply buffer headers 00324 o Perform remaining Reference Monitor initialization involving LSA 00325 o Wait for RM command sent from LSA, send reply to previous command 00326 (if any) 00327 o Validate command 00328 o Dispatch to command worker routine to execute command. 00329 00330 Arguments: 00331 00332 None. 00333 00334 Return Value: 00335 00336 None. 00337 00338 --*/ 00339 00340 { 00341 NTSTATUS Status; 00342 PRM_REPLY_MESSAGE Reply; 00343 RM_COMMAND_MESSAGE CommandMessage; 00344 RM_REPLY_MESSAGE ReplyMessage; 00345 00346 PAGED_CODE(); 00347 00348 // 00349 // Perform the rest of the Reference Monitor initialization, involving 00350 // synchronization with the LSA or dependency on the LSA having run. 00351 // 00352 00353 if (!SepRmCommandServerThreadInit()) { 00354 00355 KdPrint(("Security: Terminating Rm Command Server Thread\n")); 00356 return; 00357 } 00358 00359 // 00360 // Initialize LPC port message header type and length fields for the 00361 // received command message. 00362 // 00363 00364 CommandMessage.MessageHeader.u2.ZeroInit = 0; 00365 CommandMessage.MessageHeader.u1.s1.TotalLength = 00366 (CSHORT) sizeof(RM_COMMAND_MESSAGE); 00367 CommandMessage.MessageHeader.u1.s1.DataLength = 00368 CommandMessage.MessageHeader.u1.s1.TotalLength - 00369 (CSHORT) sizeof(PORT_MESSAGE); 00370 00371 // 00372 // Initialize the LPC port message header type and data sizes for 00373 // for the reply message. 00374 // 00375 00376 ReplyMessage.MessageHeader.u2.ZeroInit = 0; 00377 ReplyMessage.MessageHeader.u1.s1.TotalLength = 00378 (CSHORT) sizeof(RM_COMMAND_MESSAGE); 00379 ReplyMessage.MessageHeader.u1.s1.DataLength = 00380 ReplyMessage.MessageHeader.u1.s1.TotalLength - 00381 (CSHORT) sizeof(PORT_MESSAGE); 00382 00383 // 00384 // First time through, there is no reply. 00385 // 00386 00387 Reply = NULL; 00388 00389 // 00390 // Now loop indefinitely, processing incoming Rm commands from the LSA. 00391 // 00392 00393 for(;;) { 00394 00395 // 00396 // Wait for Command, send reply to previous command (if any) 00397 // 00398 00399 Status = ZwReplyWaitReceivePort( 00400 SepRmState.RmCommandPortHandle, 00401 NULL, 00402 (PPORT_MESSAGE) Reply, 00403 (PPORT_MESSAGE) &CommandMessage 00404 ); 00405 00406 if (!NT_SUCCESS(Status)) { 00407 00408 // 00409 // malicious user apps can try to connect to this port. We will 00410 // fail later, but if their thread vanishes, we'll get a failure 00411 // here. Ignore it: 00412 // 00413 00414 if ( Status == STATUS_UNSUCCESSFUL ) 00415 { 00416 // 00417 // skip it: 00418 // 00419 00420 Reply = NULL ; 00421 continue; 00422 } 00423 00424 KdPrint(("Security: RM message receive from Lsa failed %lx\n", 00425 Status)); 00426 00427 } 00428 00429 // 00430 // Now dispatch to a routine to handle the command. Allow 00431 // command errors to occur without bringing system down just now. 00432 // 00433 00434 if ( CommandMessage.MessageHeader.u2.s2.Type == LPC_REQUEST ) { 00435 (*(SepRmCommandDispatch[CommandMessage.CommandNumber])) 00436 (&CommandMessage, &ReplyMessage); 00437 00438 // 00439 // Initialize the client thread info and message id for the 00440 // reply message. First time through, the reply message structure 00441 // is not used. 00442 // 00443 00444 ReplyMessage.MessageHeader.ClientId = 00445 CommandMessage.MessageHeader.ClientId; 00446 ReplyMessage.MessageHeader.MessageId = 00447 CommandMessage.MessageHeader.MessageId; 00448 00449 Reply = &ReplyMessage; 00450 00451 } else { 00452 00453 Reply = NULL; 00454 } 00455 } // end_for 00456 00457 // 00458 // Make compiler ferme la bouche 00459 // 00460 00461 StartContext; 00462 } 00463 00464 00465 BOOLEAN 00466 SepRmCommandServerThreadInit( 00467 VOID 00468 ) 00469 00470 /*++ 00471 00472 Routine Description: 00473 00474 This function performs initialization of the Reference Monitor Server 00475 thread. The following steps are performed. 00476 00477 o Wait on the LSA signalling the event. When the event is signalled, 00478 the LSA has already created the LSA Command Server LPC Port 00479 o Close the LSA Init Event Handle. The event is not used again. 00480 o Listen for the LSA to connect to the Port 00481 o Accept the connection. 00482 o Connect to the LSA Command Server LPC Port 00483 00484 Arguments: 00485 00486 None. 00487 00488 Return Value: 00489 00490 --*/ 00491 00492 { 00493 NTSTATUS Status; 00494 UNICODE_STRING LsaCommandPortName; 00495 PORT_MESSAGE ConnectionRequest; 00496 SECURITY_QUALITY_OF_SERVICE DynamicQos; 00497 OBJECT_ATTRIBUTES ObjectAttributes; 00498 PORT_VIEW ClientView; 00499 REMOTE_PORT_VIEW LsaClientView; 00500 BOOLEAN BooleanStatus = TRUE; 00501 00502 PAGED_CODE(); 00503 00504 // 00505 // Save a pointer to our process so we can get back into this process 00506 // to send commands to the LSA (using a handle to an LPC port created 00507 // below). 00508 // 00509 00510 SepRmLsaCallProcess = PsGetCurrentProcess(); 00511 00512 ObReferenceObject(SepRmLsaCallProcess); 00513 00514 // 00515 // Wait on the LSA signalling the event. This means that the LSA 00516 // has created its command port, not that LSA initialization is 00517 // complete. 00518 // 00519 00520 Status = ZwWaitForSingleObject( 00521 SepRmState.LsaInitEventHandle, 00522 FALSE, 00523 NULL); 00524 00525 if ( !NT_SUCCESS(Status) ) { 00526 00527 KdPrint(("Security Rm Init: Waiting for LSA Init Event failed 0x%lx\n", Status)); 00528 goto RmCommandServerThreadInitError; 00529 } 00530 00531 // 00532 // Close the LSA Init Event Handle. The event is not used again. 00533 // 00534 00535 ZwClose(SepRmState.LsaInitEventHandle); 00536 00537 // 00538 // Listen for a connection to be made by the LSA to the Reference Monitor 00539 // Command Port. This connection will be made by the LSA process. 00540 // 00541 00542 ConnectionRequest.u1.s1.TotalLength = sizeof(ConnectionRequest); 00543 ConnectionRequest.u1.s1.DataLength = (CSHORT)0; 00544 Status = ZwListenPort( 00545 SepRmState.RmCommandPortHandle, 00546 &ConnectionRequest 00547 ); 00548 00549 if (!NT_SUCCESS(Status)) { 00550 00551 KdPrint(("Security Rm Init: Listen to Command Port failed 0x%lx\n", 00552 Status)); 00553 goto RmCommandServerThreadInitError; 00554 } 00555 00556 // 00557 // Obtain a handle to the LSA process for use when auditing. 00558 // 00559 00560 InitializeObjectAttributes( &ObjectAttributes, NULL, 0, NULL, NULL ); 00561 00562 Status = ZwOpenProcess( 00563 &SepLsaHandle, 00564 PROCESS_VM_OPERATION | PROCESS_VM_WRITE, 00565 &ObjectAttributes, 00566 &ConnectionRequest.ClientId 00567 ); 00568 00569 if (!NT_SUCCESS(Status)) { 00570 00571 KdPrint(("Security Rm Init: Open Listen to Command Port failed 0x%lx\n", 00572 Status)); 00573 goto RmCommandServerThreadInitError; 00574 } 00575 00576 // 00577 // Accept the connection made by the LSA process. 00578 // 00579 00580 LsaClientView.Length = sizeof(LsaClientView); 00581 00582 Status = ZwAcceptConnectPort( 00583 &SepRmState.RmCommandPortHandle, 00584 NULL, 00585 &ConnectionRequest, 00586 TRUE, 00587 NULL, 00588 &LsaClientView 00589 ); 00590 00591 if (!NT_SUCCESS(Status)) { 00592 00593 KdPrint(("Security Rm Init: Accept Connect to Command Port failed 0x%lx\n", 00594 Status)); 00595 00596 goto RmCommandServerThreadInitError; 00597 } 00598 00599 // 00600 // Complete the connection. 00601 // 00602 00603 Status = ZwCompleteConnectPort(SepRmState.RmCommandPortHandle); 00604 00605 if (!NT_SUCCESS(Status)) { 00606 00607 KdPrint(("Security Rm Init: Complete Connect to Command Port failed 0x%lx\n", 00608 Status)); 00609 goto RmCommandServerThreadInitError; 00610 } 00611 00612 // 00613 // Set up the security quality of service parameters to use over the 00614 // Lsa Command LPC port. Use the most efficient (least overhead) - which 00615 // is dynamic rather than static tracking. 00616 // 00617 00618 DynamicQos.ImpersonationLevel = SecurityImpersonation; 00619 DynamicQos.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING; 00620 DynamicQos.EffectiveOnly = TRUE; 00621 00622 // 00623 // Create the section to be used as unnamed shared memory for 00624 // communication between the RM and LSA. 00625 // 00626 00627 SepRmState.LsaCommandPortSectionSize.LowPart = PAGE_SIZE; 00628 SepRmState.LsaCommandPortSectionSize.HighPart = 0; 00629 00630 Status = ZwCreateSection( 00631 &SepRmState.LsaCommandPortSectionHandle, 00632 SECTION_ALL_ACCESS, 00633 NULL, // ObjectAttributes 00634 &SepRmState.LsaCommandPortSectionSize, 00635 PAGE_READWRITE, 00636 SEC_COMMIT, 00637 NULL // FileHandle 00638 ); 00639 00640 if (!NT_SUCCESS(Status)) { 00641 00642 KdPrint(("Security Rm Init: Create Memory Section for LSA port failed: %X\n", Status)); 00643 goto RmCommandServerThreadInitError; 00644 } 00645 00646 // 00647 // Set up for a call to NtConnectPort and connect to the LSA port. 00648 // This setup includes a description of the port memory section so that 00649 // the LPC connection logic can make the section visible to both the 00650 // client and server processes. 00651 // 00652 00653 ClientView.Length = sizeof(ClientView); 00654 ClientView.SectionHandle = SepRmState.LsaCommandPortSectionHandle; 00655 ClientView.SectionOffset = 0; 00656 ClientView.ViewSize = SepRmState.LsaCommandPortSectionSize.LowPart; 00657 ClientView.ViewBase = 0; 00658 ClientView.ViewRemoteBase = 0; 00659 00660 // 00661 // Set up the security quality of service parameters to use over the 00662 // port. Use dynamic tracking so that XACTSRV will impersonate the 00663 // user that we are impersonating when we call NtRequestWaitReplyPort. 00664 // If we used static tracking, XACTSRV would impersonate the context 00665 // when the connection is made. 00666 // 00667 00668 DynamicQos.ImpersonationLevel = SecurityImpersonation; 00669 DynamicQos.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING; 00670 DynamicQos.EffectiveOnly = TRUE; 00671 00672 // 00673 // Connect to the Lsa Command LPC Port. This port is used to send 00674 // commands from the RM to the LSA. 00675 // 00676 00677 RtlInitUnicodeString( &LsaCommandPortName, L"\\SeLsaCommandPort" ); 00678 00679 Status = ZwConnectPort( 00680 &SepRmState.LsaCommandPortHandle, 00681 &LsaCommandPortName, 00682 &DynamicQos, 00683 &ClientView, 00684 NULL, // ServerView 00685 NULL, // MaxMessageLength 00686 NULL, // ConnectionInformation 00687 NULL // ConnectionInformationLength 00688 ); 00689 00690 if (!NT_SUCCESS(Status)) { 00691 00692 KdPrint(("Security Rm Init: Connect to LSA Port failed 0x%lx\n", Status)); 00693 goto RmCommandServerThreadInitError; 00694 } 00695 00696 // 00697 // Store information about the section so that we can create pointers 00698 // meaningful to LSA. 00699 // 00700 00701 SepRmState.RmViewPortMemory = ClientView.ViewBase; 00702 SepRmState.LsaCommandPortMemoryDelta = 00703 (LONG)((ULONG_PTR)ClientView.ViewRemoteBase - (ULONG_PTR) ClientView.ViewBase ); 00704 SepRmState.LsaViewPortMemory = ClientView.ViewRemoteBase; 00705 00706 /* BugWarning - ScottBi - probably don't need the resource 00707 00708 // 00709 // Create the resource serializing access to the port. This 00710 // resource prevents the port and the shared memory from being 00711 // deleted while worker threads are processing requests. 00712 // 00713 00714 if ( !SepRmState.LsaCommandPortResourceInitialized ) { 00715 00716 ExInitializeResource( &SepRmState.LsaCommandPortResource ); 00717 SepRmState.LsaCommandPortResourceInitialized = TRUE; 00718 } 00719 00720 SepRmState.LsaCommandPortActive = TRUE; 00721 00722 */ 00723 00724 RmCommandServerThreadInitFinish: 00725 00726 // 00727 // Dont need this section handle any more, even if returning 00728 // success. 00729 // 00730 00731 if ( SepRmState.LsaCommandPortSectionHandle != NULL ) { 00732 00733 NtClose( SepRmState.LsaCommandPortSectionHandle ); 00734 SepRmState.LsaCommandPortSectionHandle = NULL; 00735 } 00736 00737 // 00738 // The Reference Monitor Thread has successfully initialized. 00739 // 00740 00741 return BooleanStatus; 00742 00743 RmCommandServerThreadInitError: 00744 00745 if ( SepRmState.LsaCommandPortHandle != NULL ) { 00746 00747 NtClose( SepRmState.LsaCommandPortHandle ); 00748 SepRmState.LsaCommandPortHandle = NULL; 00749 } 00750 00751 BooleanStatus = FALSE; 00752 goto RmCommandServerThreadInitFinish; 00753 } 00754 00755 00756 00757 VOID 00758 SepRmComponentTestCommandWrkr( 00759 IN PRM_COMMAND_MESSAGE CommandMessage, 00760 OUT PRM_REPLY_MESSAGE ReplyMessage 00761 ) 00762 00763 /*++ 00764 00765 Routine Description: 00766 00767 BUGWARNING - Remove this command when other RM commands are implemented. 00768 Until then, this command is the only way a CT can verify that 00769 an RM command with parameters is sent correctly. 00770 00771 This function processes the Component Test RM command. 00772 This is a temporary command that can be used to verify that the link 00773 from RM to LSA is working. This command verifies that the link 00774 is working by receiving a ULONG parameter and verifying that it 00775 has the expected value. 00776 00777 Arguments: 00778 00779 CommandMessage - Pointer to structure containing RM command message 00780 information consisting of an LPC PORT_MESSAGE structure followed 00781 by the command number (RmComponentTestCommand). This command 00782 currently has one parameter, a fixed ulong value. 00783 00784 ReplyMessage - Pointer to structure containing LSA reply message 00785 information consisting of an LPC PORT_MESSAGE structure followed 00786 by the command ReturnedStatus field in which a status code from the 00787 command will be returned. 00788 00789 Return Value: 00790 00791 VOID 00792 00793 --*/ 00794 00795 { 00796 PAGED_CODE(); 00797 00798 ReplyMessage->ReturnedStatus = STATUS_SUCCESS; 00799 00800 // 00801 // Strict check that command is correct. 00802 // 00803 00804 ASSERT( CommandMessage->CommandNumber == RmComponentTestCommand ); 00805 00806 KdPrint(("Security: RM Component Test Command Received\n")); 00807 00808 // 00809 // Verify that the parameter value passed is as expected. 00810 // 00811 00812 if (*((ULONG *) CommandMessage->CommandParams) != 00813 RM_CT_COMMAND_PARAM_VALUE ) { 00814 00815 ReplyMessage->ReturnedStatus = STATUS_INVALID_PARAMETER; 00816 } 00817 00818 return; 00819 } 00820 00821 00822 00823 VOID 00824 SepRmSendCommandToLsaWrkr( 00825 IN PRM_COMMAND_MESSAGE CommandMessage, 00826 OUT PRM_REPLY_MESSAGE ReplyMessage 00827 ) 00828 00829 /*++ 00830 00831 Routine Description: 00832 00833 This function carries out the special Rm Send Command To Lsa Command. This 00834 command is used only by the ctlsarm component test which checks that 00835 LSA to RM and RM to LSA communication via LPC is working. 00836 00837 Arguments: 00838 00839 CommandMessage - Pointer to structure containing RM command message 00840 information consisting of an LPC PORT_MESSAGE structure followed 00841 by the command number (RmDisableAuditCommand), followed by the 00842 command parameters. The parameters of this special command consists 00843 of the Command Number of an LSA command and its parameters (if any). 00844 00845 ReplyMessage - Pointer to structure containing RM reply message 00846 information consisting of an LPC PORT_MESSAGE structure followed 00847 by the command ReturnedStatus field in which a status code from the 00848 command will be returned. 00849 00850 Return Value: 00851 00852 VOID 00853 00854 --*/ 00855 00856 { 00857 // 00858 // Obtain a pointer to the LSA command's params, and the size of the 00859 // params in bytes. If there are no params, set the pointer to NULL. 00860 // 00861 00862 PVOID LsaCommandParams = 00863 ((RM_SEND_COMMAND_TO_LSA_PARAMS *) 00864 (CommandMessage->CommandParams))->LsaCommandParams; 00865 ULONG LsaCommandParamsLength = 00866 ((RM_SEND_COMMAND_TO_LSA_PARAMS *) 00867 (CommandMessage->CommandParams))->LsaCommandParamsLength; 00868 00869 PAGED_CODE(); 00870 00871 if (LsaCommandParamsLength == 0) { 00872 00873 LsaCommandParams = NULL; 00874 00875 } 00876 00877 // 00878 // Strict check that command is correct one for this worker. 00879 // 00880 00881 ASSERT( CommandMessage->CommandNumber == RmSendCommandToLsaCommand ); 00882 00883 KdPrint(("Security: RM Send Command back to LSA Command Received\n")); 00884 00885 ReplyMessage->ReturnedStatus = STATUS_SUCCESS; 00886 00887 // Status = SepRmCallLsa( 00888 // ((RM_SEND_COMMAND_TO_LSA_PARAMS *) 00889 // (CommandMessage->CommandParams))->LsaCommandNumber, 00890 // LsaCommandParams, 00891 // LsaCommandParamsLength, 00892 // NULL, 00893 // 0, 00894 // NULL, 00895 // NULL 00896 // ); 00897 00898 00899 return; 00900 00901 } 00902 00903 00904 00905 00906 NTSTATUS 00907 SepRmCallLsa( 00908 PSEP_WORK_ITEM SepWorkItem 00909 ) 00910 /*++ 00911 00912 Routine Description: 00913 00914 This function sends a command to the LSA via the LSA Reference Monitor 00915 Server Command LPC Port. If the command has parameters, they will be 00916 copied directly into a message structure and sent via LPC, therefore, 00917 the supplied parameters may not contain any absolute pointers. A caller 00918 must remove pointers by "marshalling" them into the buffer CommandParams. 00919 00920 This function will create a queue of requests. This is in order to allow 00921 greater throughput for the majority if its callers. If a thread enters 00922 this routine and finds the queue empty, it is the responsibility of that 00923 thread to service all requests that come in while it is working until the 00924 queue is empty again. Other threads that enter will simply hook their work 00925 item onto the queue and exit. 00926 00927 00928 To implement a new LSA command, do the following: 00929 ================================================ 00930 00931 (1) If the command takes no parameters, just call this routine directly 00932 and provide an LSA worker routine called Lsap<command>Wrkr. See 00933 file lsa\server\lsarm.c for examples 00934 00935 (2) If the command takes parameters, provide a routine called 00936 SepRmSend<command>Command that takes the parameters in unmarshalled 00937 form and calls SepRmCallLsa() with the command id, marshalled 00938 parameters, length of marshalled parameters and pointer to 00939 optional reply message. The marshalled parameters are free format: 00940 the only restriction is that there must be no absolute address 00941 pointers. These parameters are all placed in the passed LsaWorkItem 00942 structure. 00943 00944 (3) In file private\inc\ntrmlsa.h, append a command name to the 00945 enumerated type LSA_COMMAND_NUMBER defined in file 00946 private\inc\ntrmlsa.h. Change the #define for LsapMaximumCommand 00947 to reference the new command. 00948 00949 (4) Add the Lsap<command>Wrkr to the command dispatch table structure 00950 LsapCommandDispatch[] in file lsarm.c. 00951 00952 (5) Add function prototypes to lsap.h and sep.h. 00953 00954 00955 Arguments: 00956 00957 LsaWorkItem - Supplies a pointer to an SE_LSA_WORK_ITEM containing the 00958 information to be passed to LSA. This structure will be freed 00959 asynchronously by some invocation of this routine, not necessarily 00960 in the current context. 00961 00962 !THIS PARAMETER MUST BE ALLOCATED OUT OF NONPAGED POOL! 00963 00964 Return Value: 00965 00966 NTSTATUS - Result Code. This is either a result code returned from 00967 trying to send the command/receive the reply, or a status code 00968 from the command itself. 00969 00970 --*/ 00971 00972 { 00973 NTSTATUS Status = STATUS_SUCCESS; 00974 LSA_COMMAND_MESSAGE CommandMessage; 00975 LSA_REPLY_MESSAGE ReplyMessage; 00976 PSEP_LSA_WORK_ITEM WorkQueueItem; 00977 ULONG LocalListLength = 0; 00978 SIZE_T RegionSize; 00979 PVOID CopiedCommandParams = NULL; 00980 PVOID LsaViewCopiedCommandParams = NULL; 00981 00982 PAGED_CODE(); 00983 00984 #if 0 00985 DbgPrint("Entering SepRmCallLsa\n"); 00986 #endif 00987 00988 WorkQueueItem = SepWorkListHead(); 00989 00990 KeAttachProcess( &SepRmLsaCallProcess->Pcb ); 00991 00992 while ( WorkQueueItem ) { 00993 00994 #if 0 00995 DbgPrint("Got a work item from head of queue, processing\n"); 00996 #endif 00997 00998 // 00999 // Construct a message for LPC. First, fill in the message header 01000 // fields for LPC, specifying the message type and data sizes for 01001 // the outgoing CommandMessage and the incoming ReplyMessage. 01002 // 01003 01004 CommandMessage.MessageHeader.u2.ZeroInit = 0; 01005 CommandMessage.MessageHeader.u1.s1.TotalLength = 01006 ((CSHORT) RM_COMMAND_MESSAGE_HEADER_SIZE + 01007 (CSHORT) WorkQueueItem->CommandParamsLength); 01008 CommandMessage.MessageHeader.u1.s1.DataLength = 01009 CommandMessage.MessageHeader.u1.s1.TotalLength - 01010 (CSHORT) sizeof(PORT_MESSAGE); 01011 01012 ReplyMessage.MessageHeader.u2.ZeroInit = 0; 01013 ReplyMessage.MessageHeader.u1.s1.DataLength = (CSHORT) WorkQueueItem->ReplyBufferLength; 01014 ReplyMessage.MessageHeader.u1.s1.TotalLength = 01015 ReplyMessage.MessageHeader.u1.s1.DataLength + 01016 (CSHORT) sizeof(PORT_MESSAGE); 01017 01018 // 01019 // Next, fill in the header info needed by the LSA. 01020 // 01021 01022 CommandMessage.CommandNumber = WorkQueueItem->CommandNumber; 01023 ReplyMessage.ReturnedStatus = STATUS_SUCCESS; 01024 01025 // 01026 // Set up the Command Parameters either in the LPC Command Message 01027 // itself, in the preallocated Lsa shared memory block, or in a 01028 // specially allocated block. The parameters are either 01029 // immediate (i.e. in the WorkQueueItem itself, or are in a buffer 01030 // pointed to by the address in the WorkQueueItem. 01031 // 01032 01033 switch (WorkQueueItem->CommandParamsMemoryType) { 01034 01035 case SepRmImmediateMemory: 01036 01037 // 01038 // The Command Parameters are in the CommandParams buffer 01039 // in the Work Queue Item. Just copy them to the corresponding 01040 // buffer in the CommandMessage buffer. 01041 // 01042 01043 CommandMessage.CommandParamsMemoryType = SepRmImmediateMemory; 01044 01045 RtlCopyMemory( 01046 CommandMessage.CommandParams, 01047 &WorkQueueItem->CommandParams, 01048 WorkQueueItem->CommandParamsLength 01049 ); 01050 01051 break; 01052 01053 case SepRmPagedPoolMemory: 01054 case SepRmUnspecifiedMemory: 01055 01056 // 01057 // The Command Parameters are contained in paged pool memory. 01058 // Since this memory is is not accessible by the LSA, we must 01059 // copy of them either to the LPC Command Message Block, or 01060 // into LSA shared memory. 01061 // 01062 01063 if (WorkQueueItem->CommandParamsLength <= LSA_MAXIMUM_COMMAND_PARAM_SIZE) { 01064 01065 // 01066 // Parameters will fit into the LPC Command Message block. 01067 // 01068 01069 CopiedCommandParams = CommandMessage.CommandParams; 01070 01071 RtlCopyMemory( 01072 CopiedCommandParams, 01073 WorkQueueItem->CommandParams.BaseAddress, 01074 WorkQueueItem->CommandParamsLength 01075 ); 01076 01077 CommandMessage.CommandParamsMemoryType = SepRmImmediateMemory; 01078 01079 } else { 01080 01081 // 01082 // Parameters too large for LPC Command Message block. 01083 // If possible, copy them to the preallocated Lsa Shared 01084 // Memory block. If they are too large to fit, copy them 01085 // to an individually allocated chunk of Shared Virtual 01086 // Memory. 01087 // 01088 01089 if (WorkQueueItem->CommandParamsLength <= SEP_RM_LSA_SHARED_MEMORY_SIZE) { 01090 01091 RtlCopyMemory( 01092 SepRmState.RmViewPortMemory, 01093 WorkQueueItem->CommandParams.BaseAddress, 01094 WorkQueueItem->CommandParamsLength 01095 ); 01096 01097 LsaViewCopiedCommandParams = SepRmState.LsaViewPortMemory; 01098 CommandMessage.CommandParamsMemoryType = SepRmLsaCommandPortSharedMemory; 01099 01100 } else { 01101 01102 Status = SepAdtCopyToLsaSharedMemory( 01103 SepLsaHandle, 01104 WorkQueueItem->CommandParams.BaseAddress, 01105 WorkQueueItem->CommandParamsLength, 01106 &LsaViewCopiedCommandParams 01107 ); 01108 01109 if (!NT_SUCCESS(Status)) { 01110 01111 // 01112 // An error occurred, most likely in allocating 01113 // shared virtual memory. For now, just ignore 01114 // the error and discard the Audit Record. Later, 01115 // we may consider generating a warning record 01116 // indicating some records lost. 01117 // 01118 01119 break; 01120 01121 } 01122 01123 CommandMessage.CommandParamsMemoryType = SepRmLsaCustomSharedMemory; 01124 } 01125 01126 // 01127 // Buffer has been successfully copied to a shared Lsa 01128 // memory buffer. Place the address of the buffer valid in 01129 // the LSA's process context in the Command Message. 01130 // 01131 01132 *((PVOID *) CommandMessage.CommandParams) = 01133 LsaViewCopiedCommandParams; 01134 01135 CommandMessage.MessageHeader.u1.s1.TotalLength = 01136 ((CSHORT) RM_COMMAND_MESSAGE_HEADER_SIZE + 01137 (CSHORT) sizeof( LsaViewCopiedCommandParams )); 01138 CommandMessage.MessageHeader.u1.s1.DataLength = 01139 CommandMessage.MessageHeader.u1.s1.TotalLength - 01140 (CSHORT) sizeof(PORT_MESSAGE); 01141 } 01142 01143 // 01144 // Free input command params buffer if Paged Pool. 01145 // 01146 01147 if (WorkQueueItem->CommandParamsMemoryType == SepRmPagedPoolMemory) { 01148 01149 ExFreePool( WorkQueueItem->CommandParams.BaseAddress ); 01150 } 01151 01152 break; 01153 01154 default: 01155 01156 Status = STATUS_INVALID_PARAMETER; 01157 break; 01158 } 01159 01160 if (NT_SUCCESS(Status)) { 01161 01162 // 01163 // Send Message to the LSA via the LSA Server Command LPC Port. 01164 // This must be done in the process in which the handle was created. 01165 // 01166 01167 Status = ZwRequestWaitReplyPort( 01168 SepRmState.LsaCommandPortHandle, 01169 (PPORT_MESSAGE) &CommandMessage, 01170 (PPORT_MESSAGE) &ReplyMessage 01171 ); 01172 01173 // 01174 // If the command was successful, copy the data back to the output 01175 // buffer. 01176 // 01177 01178 if (NT_SUCCESS(Status)) { 01179 01180 // 01181 // Move output from command (if any) to buffer. Note that this 01182 // is done even if the command returns status, because some status 01183 // values are not errors. 01184 // 01185 01186 if (ARGUMENT_PRESENT(WorkQueueItem->ReplyBuffer)) { 01187 01188 RtlCopyMemory( 01189 WorkQueueItem->ReplyBuffer, 01190 ReplyMessage.ReplyBuffer, 01191 WorkQueueItem->ReplyBufferLength 01192 ); 01193 } 01194 01195 // 01196 // Return status from command. 01197 // 01198 01199 Status = ReplyMessage.ReturnedStatus; 01200 01201 if (!NT_SUCCESS(Status)) { 01202 KdPrint(("Security: Command sent from RM to LSA returned 0x%lx\n", 01203 Status)); 01204 } 01205 01206 } else { 01207 01208 KdPrint(("Security: Sending Command RM to LSA failed 0x%lx\n", Status)); 01209 } 01210 01211 // 01212 // On return from the LPC call to the LSA, we expect the called 01213 // LSA worker routine to have copied the Command Parameters 01214 // buffer (if any). If a custom shared memory boffer was allocated, 01215 // free it now. 01216 // 01217 01218 if (CommandMessage.CommandParamsMemoryType == SepRmLsaCustomSharedMemory) { 01219 01220 RegionSize = 0; 01221 01222 Status = ZwFreeVirtualMemory( 01223 SepLsaHandle, 01224 (PVOID *) &CommandMessage.CommandParams, 01225 &RegionSize, 01226 MEM_RELEASE 01227 ); 01228 01229 ASSERT(NT_SUCCESS(Status)); 01230 } 01231 01232 } 01233 01234 01235 // 01236 // Clean up. We must call the cleanup functions on its parameter 01237 // and then free the used WorkQueueItem itself. 01238 // 01239 01240 if ( ARGUMENT_PRESENT( WorkQueueItem->CleanupFunction)) { 01241 01242 (WorkQueueItem->CleanupFunction)(WorkQueueItem->CleanupParameter); 01243 } 01244 01245 // 01246 // Determine if there is more work to do on this list 01247 // 01248 01249 WorkQueueItem = SepDequeueWorkItem(); 01250 #if 0 01251 if ( WorkQueueItem ) { 01252 DbgPrint("Got another item from list, going back\n"); 01253 } else { 01254 DbgPrint("List is empty, leaving\n"); 01255 } 01256 #endif 01257 01258 01259 } 01260 01261 KeDetachProcess(); 01262 01263 if ( LocalListLength > SepLsaQueueLength ) { 01264 SepLsaQueueLength = LocalListLength; 01265 } 01266 01267 return Status; 01268 } 01269 01270 01271 01272 01273 01274 BOOLEAN 01275 SepRmInitPhase0( 01276 ) 01277 01278 /*++ 01279 01280 Routine Description: 01281 01282 This function performs Reference Monitor Phase 0 initialization. 01283 This includes initializing the reference monitor database to a state 01284 which allows access validation routines to operate (always granting 01285 access) prior to the main init of the Reference Monitor in Phase 1 01286 initialization, without having to check if the RM is initialized. 01287 01288 01289 Arguments: 01290 01291 None. 01292 01293 Return Value: 01294 01295 BOOLEAN - TRUE if successful, else FALSE 01296 01297 --*/ 01298 01299 { 01300 01301 BOOLEAN CompletionStatus; 01302 01303 PAGED_CODE(); 01304 01305 CompletionStatus = SepRmDbInitialization(); 01306 01307 return CompletionStatus; 01308 }

Generated on Sat May 15 19:41:40 2004 for test by doxygen 1.3.7