/*++ Copyright (c) 1989 Microsoft Corporation Module Name: austub.c Abstract: Local Security Authority AUTHENTICATION service client stubs. Author: Jim Kelly (JimK) 20-Feb-1991 Environment: Kernel or User Modes Revision History: --*/ #include "lsadllp.h" #include #include #ifdef _NTSYSTEM_ // // Unfortunately the security header files are just not at all constructed // in a manner compatible with kernelmode. For some reason they are totally // reliant on usermode header definitions. Just assume the text and const // pragma's will work. If they don't work on an architecture, they can be // fixed. // #pragma alloc_text(PAGE,LsaFreeReturnBuffer) #pragma alloc_text(PAGE,LsaRegisterLogonProcess) #pragma alloc_text(PAGE,LsaConnectUntrusted) #pragma alloc_text(PAGE,LsaLookupAuthenticationPackage) #pragma alloc_text(PAGE,LsaLogonUser) #pragma alloc_text(PAGE,LsaCallAuthenticationPackage) #pragma alloc_text(PAGE,LsaDeregisterLogonProcess) //#pragma const_seg("PAGECONST") #endif //_NTSYSTEM_ const WCHAR LsapEvent[] = L"\\SECURITY\\LSA_AUTHENTICATION_INITIALIZED"; const WCHAR LsapPort[] = L"\\LsaAuthenticationPort"; NTSTATUS LsaFreeReturnBuffer ( IN PVOID Buffer ) /*++ Routine Description: Some of the LSA authentication services allocate memory buffers to hold returned information. This service is used to free those buffers when no longer needed. Arguments: Buffer - Supplies a pointer to the return buffer to be freed. Return Status: STATUS_SUCCESS - Indicates the service completed successfully. Others - returned by NtFreeVirtualMemory(). --*/ { NTSTATUS Status; ULONG_PTR Length; Length = 0; Status = ZwFreeVirtualMemory( NtCurrentProcess(), &Buffer, &Length, MEM_RELEASE ); return Status; } NTSTATUS LsaRegisterLogonProcess( IN PSTRING LogonProcessName, OUT PHANDLE LsaHandle, OUT PLSA_OPERATIONAL_MODE SecurityMode ) /*++ Routine Description: This service connects to the LSA server and verifies that the caller is a legitimate logon process. this is done by ensuring the caller has the SeTcbPrivilege privilege. It also opens the caller's process for PROCESS_DUP_HANDLE access in anticipation of future LSA authentication calls. Arguments: LogonProcessName - Provides a name string that identifies the logon process. This should be a printable name suitable for display to administrators. For example, "User32LogonProces" might be used for the windows logon process name. No check is made to determine whether the name is already in use. This name must NOT be longer than 127 bytes long. LsaHandle - Receives a handle which must be provided in future authenticaiton services. SecurityMode - The security mode the system is running under. This value typically influences the logon user interface. For example, a system running with password control will prompt for username and passwords before bringing up the UI shell. One running without password control would typically automatically bring up the UI shell at system initialization. Return Value: STATUS_SUCCESS - The call completed successfully. STATUS_PRIVILEGE_NOT_HELD - Indicates the caller does not have the privilege necessary to act as a logon process. The SeTcbPrivilege privilege is needed. STATUS_NAME_TOO_LONG - The logon process name provided is too long. --*/ { NTSTATUS Status, IgnoreStatus; UNICODE_STRING PortName, EventName; LSAP_AU_REGISTER_CONNECT_INFO ConnectInfo; ULONG ConnectInfoLength; SECURITY_QUALITY_OF_SERVICE DynamicQos; OBJECT_ATTRIBUTES ObjectAttributes; HANDLE EventHandle; // // Validate input parameters // if (LogonProcessName->Length > LSAP_MAX_LOGON_PROC_NAME_LENGTH) { return STATUS_NAME_TOO_LONG; } // // Wait for LSA to initialize... // RtlInitUnicodeString( &EventName, LsapEvent ); InitializeObjectAttributes( &ObjectAttributes, &EventName, OBJ_CASE_INSENSITIVE, 0, NULL ); Status = NtOpenEvent( &EventHandle, SYNCHRONIZE, &ObjectAttributes ); if (!NT_SUCCESS(Status)) { return(Status); } Status = NtWaitForSingleObject( EventHandle, TRUE, NULL); IgnoreStatus = NtClose( EventHandle ); if (!NT_SUCCESS(Status)) { return(Status); } // // Set up the security quality of service parameters to use over the // port. Use the most efficient (least overhead) - which is dynamic // rather than static tracking. // DynamicQos.Length = sizeof( DynamicQos ); DynamicQos.ImpersonationLevel = SecurityImpersonation; DynamicQos.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING; DynamicQos.EffectiveOnly = TRUE; // // Set up the connection information to contain the logon process // name. // ConnectInfoLength = sizeof(LSAP_AU_REGISTER_CONNECT_INFO); strncpy( ConnectInfo.LogonProcessName, LogonProcessName->Buffer, LogonProcessName->Length ); ConnectInfo.LogonProcessNameLength = LogonProcessName->Length; ConnectInfo.LogonProcessName[ConnectInfo.LogonProcessNameLength] = '\0'; // // Connect to the LSA server // *LsaHandle = NULL; RtlInitUnicodeString(&PortName,LsapPort); Status = ZwConnectPort( LsaHandle, &PortName, &DynamicQos, NULL, NULL, NULL, &ConnectInfo, &ConnectInfoLength ); if ( !NT_SUCCESS(Status) ) { //DbgPrint("LSA AU: Logon Process Register failed %lx\n",Status); return Status; } if ( !NT_SUCCESS(ConnectInfo.CompletionStatus) ) { //DbgPrint("LSA AU: Logon Process Register rejected %lx\n",ConnectInfo.CompletionStatus); if ( LsaHandle && *LsaHandle != NULL ) { ZwClose( *LsaHandle ); *LsaHandle = NULL; } } (*SecurityMode) = ConnectInfo.SecurityMode; return ConnectInfo.CompletionStatus; } NTSTATUS LsaConnectUntrusted( OUT PHANDLE LsaHandle ) /*++ Routine Description: This service connects to the LSA server and sets up an untrusted connection. It does not check anything about the caller. Arguments: LsaHandle - Receives a handle which must be provided in future authenticaiton services. Return Value: STATUS_SUCCESS - The call completed successfully. --*/ { NTSTATUS Status, IgnoreStatus; UNICODE_STRING PortName, EventName; LSAP_AU_REGISTER_CONNECT_INFO ConnectInfo; ULONG ConnectInfoLength; SECURITY_QUALITY_OF_SERVICE DynamicQos; OBJECT_ATTRIBUTES ObjectAttributes; HANDLE EventHandle; // // Wait for LSA to initialize... // RtlInitUnicodeString( &EventName, LsapEvent ); InitializeObjectAttributes( &ObjectAttributes, &EventName, OBJ_CASE_INSENSITIVE, 0, NULL ); Status = NtOpenEvent( &EventHandle, SYNCHRONIZE, &ObjectAttributes ); if (!NT_SUCCESS(Status)) { return(Status); } Status = NtWaitForSingleObject( EventHandle, TRUE, NULL); IgnoreStatus = NtClose( EventHandle ); if (!NT_SUCCESS(Status)) { return(Status); } // // Set up the security quality of service parameters to use over the // port. Use the most efficient (least overhead) - which is dynamic // rather than static tracking. // DynamicQos.ImpersonationLevel = SecurityImpersonation; DynamicQos.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING; DynamicQos.EffectiveOnly = TRUE; // // Set up the connection information to contain the logon process // name. // ConnectInfoLength = sizeof(LSAP_AU_REGISTER_CONNECT_INFO); RtlZeroMemory( &ConnectInfo, ConnectInfoLength ); // // Connect to the LSA server // RtlInitUnicodeString(&PortName,LsapPort); Status = ZwConnectPort( LsaHandle, &PortName, &DynamicQos, NULL, NULL, NULL, &ConnectInfo, &ConnectInfoLength ); if ( !NT_SUCCESS(Status) ) { //DbgPrint("LSA AU: Logon Process Register failed %lx\n",Status); return Status; } if ( !NT_SUCCESS(ConnectInfo.CompletionStatus) ) { //DbgPrint("LSA AU: Logon Process Register rejected %lx\n",ConnectInfo.CompletionStatus); ; } return ConnectInfo.CompletionStatus; } NTSTATUS LsaLookupAuthenticationPackage ( IN HANDLE LsaHandle, IN PSTRING PackageName, OUT PULONG AuthenticationPackage ) /*++ Arguments: LsaHandle - Supplies a handle obtained in a previous call to LsaRegisterLogonProcess. PackageName - Supplies a string which identifies the Authentication Package. "MSV1.0" is the standard NT authentication package name. The package name must not exceed 127 bytes in length. AuthenticationPackage - Receives an ID used to reference the authentication package in subsequent authentication services. Return Status: STATUS_SUCCESS - Indicates the service completed successfully. STATUS_NO_SUCH_PACKAGE - The specified authentication package is unknown to the LSA. STATUS_NAME_TOO_LONG - The authentication package name provided is too long. Routine Description: This service is used to obtain the ID of an authentication package. This ID may then be used in subsequent authentication services. --*/ { NTSTATUS Status; LSAP_AU_API_MESSAGE Message = {0}; PLSAP_LOOKUP_PACKAGE_ARGS Arguments; // // Validate input parameters // if (PackageName->Length > LSAP_MAX_PACKAGE_NAME_LENGTH) { return STATUS_NAME_TOO_LONG; } Arguments = &Message.Arguments.LookupPackage; // // Set arguments // strncpy(Arguments->PackageName, PackageName->Buffer, PackageName->Length); Arguments->PackageNameLength = PackageName->Length; Arguments->PackageName[Arguments->PackageNameLength] = '\0'; // // Call the Local Security Authority Server. // Message.ApiNumber = LsapAuLookupPackageApi; Message.PortMessage.u1.s1.DataLength = sizeof(*Arguments) + 8; Message.PortMessage.u1.s1.TotalLength = sizeof(Message); Message.PortMessage.u2.ZeroInit = 0L; Status = ZwRequestWaitReplyPort( LsaHandle, (PPORT_MESSAGE) &Message, (PPORT_MESSAGE) &Message ); // // Return the authentication package ID. // If the call failed for any reason, this will be garbage, // but who cares. // (*AuthenticationPackage) = Arguments->AuthenticationPackage; if ( NT_SUCCESS(Status) ) { Status = Message.ReturnedStatus; if ( !NT_SUCCESS(Status) ) { //DbgPrint("LSA AU: Package Lookup Failed %lx\n",Status); ; } } else { #if DBG DbgPrint("LSA AU: Package Lookup NtRequestWaitReply Failed %lx\n",Status); #else ; #endif } return Status; } NTSTATUS LsaLogonUser ( IN HANDLE LsaHandle, IN PSTRING OriginName, IN SECURITY_LOGON_TYPE LogonType, IN ULONG AuthenticationPackage, IN PVOID AuthenticationInformation, IN ULONG AuthenticationInformationLength, IN PTOKEN_GROUPS LocalGroups OPTIONAL, IN PTOKEN_SOURCE SourceContext, OUT PVOID *ProfileBuffer, OUT PULONG ProfileBufferLength, OUT PLUID LogonId, OUT PHANDLE Token, OUT PQUOTA_LIMITS Quotas, OUT PNTSTATUS SubStatus ) /*++ Arguments: LsaHandle - Supplies a handle obtained in a previous call to LsaRegisterLogonProcess. OriginName - Supplies a string which identifies the origin of the logon attempt. For example, "TTY1" specify terminal 1, or "LAN Manager - remote node JAZZ" might indicate a network logon attempt via LAN Manager from a remote node called "JAZZ". LogonType - Identifies the type of logon being attempted. If the type is Interactive or Batch then a PrimaryToken will be generated to represent this new user. If the type is Network then an impersonation token will be generated. AuthenticationPackage - Supplies the ID of the authentication package to use for the logon attempt. The standard authentication package name for NT is called "MSV1.0". AuthenticationInformation - Supplies the authentication information specific to the authentication package. It is expected to include identification and authentication information such as user name and password. AuthenticationInformationLength - Indicates the length of the authentication information buffer. LocalGroups - Optionally supplies a list of additional group identifiers to add to the authenticated user's token. The WORLD group will always be included in the token. A group identifying the logon type (INTERACTIVE, NETWORK, BATCH) will also automatically be included in the token. SourceContext - Supplies information identifying the source component (e.g., session manager) and context that may be useful to that component. This information will be included in the token and may later be retrieved. ProfileBuffer - Receives a pointer to any returned profile and accounting information about the logged on user's account. This information is authentication package specific and provides such information as the logon shell, home directory and so forth. For an authentication package value of "MSV1.0", a MSV1_0_PROFILE_DATA data structure is returned. This buffer is allocated by this service and must be freed using LsaFreeReturnBuffer() when no longer needed. ProfileBufferLength - Receives the length (in bytes) of the returned profile buffer. LogonId - Points to a buffer which receives a LUID that uniquely identifies this logon session. This LUID was assigned by the domain controller which authenticated the logon information. Token - Receives a handle to the new token created for this authentication. Quotas - When a primary token is returned, this parameter will be filled in with process quota limits that are to be assigned to the newly logged on user's initial process. SubStatus - If the logon failed due to account restrictions, this out parameter will receive an indication as to why the logon failed. This value will only be set to a meaningful value if the user has a legitimate account, but may not currently logon for some reason. The substatus values for authentication package "MSV1.0" are: STATUS_INVALID_LOGON_HOURS STATUS_INVALID_WORKSTATION STATUS_PASSWORD_EXPIRED STATUS_ACCOUNT_DISABLED Return Status: STATUS_SUCCESS - Indicates the service completed successfully. STATUS_QUOTA_EXCEEDED - Indicates the caller does not have enough quota to allocate the profile data being returned by the authentication package. STATUS_NO_LOGON_SERVERS - Indicates that no domain controllers are currently able to service the authentication request. STATUS_LOGON_FAILURE - Indicates the logon attempt failed. No indication as to the reason for failure is given, but typical reasons include mispelled usernames, mispelled passwords. STATUS_ACCOUNT_RESTRICTION - Indicates the user account and password were legitimate, but that the user account has some restriction preventing successful logon at this time. STATUS_NO_SUCH_PACKAGE - The specified authentication package is unknown to the LSA. STATUS_BAD_VALIDATION_CLASS - The authentication information provided is not a validation class known to the specified authentication package. Routine Description: This routine is used to authenticate a user logon attempt. This is used only for user's initial logon, necessary to gain access to NT OS/2. Subsequent (supplementary) authentication requests must be done using LsaCallAuthenticationPackage(). This service will cause a logon session to be created to represent the new logon. It will also return a token representing the newly logged on user. --*/ { NTSTATUS Status; LSAP_AU_API_MESSAGE Message = {0}; PLSAP_LOGON_USER_ARGS Arguments; Arguments = &Message.Arguments.LogonUser; // // Set arguments // Arguments->AuthenticationPackage = AuthenticationPackage; Arguments->AuthenticationInformation = AuthenticationInformation; Arguments->AuthenticationInformationLength = AuthenticationInformationLength; Arguments->OriginName = (*OriginName); Arguments->LogonType = LogonType; Arguments->SourceContext = (*SourceContext); Arguments->LocalGroups = LocalGroups; if ( ARGUMENT_PRESENT(LocalGroups) ) { Arguments->LocalGroupsCount = LocalGroups->GroupCount; } else { Arguments->LocalGroupsCount = 0; } // // Call the Local Security Authority Server. // Message.ApiNumber = LsapAuLogonUserApi; Message.PortMessage.u1.s1.DataLength = sizeof(*Arguments) + 8; Message.PortMessage.u1.s1.TotalLength = sizeof(Message); Message.PortMessage.u2.ZeroInit = 0L; Status = ZwRequestWaitReplyPort( LsaHandle, (PPORT_MESSAGE) &Message, (PPORT_MESSAGE) &Message ); // // We may be returning bogus return values here, but it doesn't // matter. They will just be ignored if an error occured. // (*SubStatus) = Arguments->SubStatus; if ( NT_SUCCESS( Status ) ) { Status = Message.ReturnedStatus ; // Don't not clear the ProfileBuffer even in case of error, cause // subauth packages need the ProfileBuffer. *ProfileBuffer = Arguments->ProfileBuffer ; *ProfileBufferLength = Arguments->ProfileBufferLength ; if ( NT_SUCCESS( Status ) ) { *LogonId = Arguments->LogonId ; *Token = Arguments->Token ; *Quotas = Arguments->Quotas ; } else { *Token = NULL; } } else { *ProfileBuffer = NULL ; *Token = NULL ; } return Status; } NTSTATUS LsaCallAuthenticationPackage ( IN HANDLE LsaHandle, IN ULONG AuthenticationPackage, IN PVOID ProtocolSubmitBuffer, IN ULONG SubmitBufferLength, OUT PVOID *ProtocolReturnBuffer OPTIONAL, OUT PULONG ReturnBufferLength OPTIONAL, OUT PNTSTATUS ProtocolStatus OPTIONAL ) /*++ Arguments: LsaHandle - Supplies a handle obtained in a previous call to LsaRegisterLogonProcess. AuthenticationPackage - Supplies the ID of the authentication package to use for the logon attempt. The standard authentication package name for NT is called "MSV1.0". ProtocolSubmitBuffer - Supplies a protocol message specific to the authentication package. SubmitBufferLength - Indicates the length of the submitted protocol message buffer. ProtocolReturnBuffer - Receives a pointer to a returned protocol message whose format and semantics are specific to the authentication package. This buffer is allocated by this service and must be freed using LsaFreeReturnBuffer() when no longer needed. ReturnBufferLength - Receives the length (in bytes) of the returned profile buffer. ProtocolStatus - Assuming the services completion is STATUS_SUCCESS, this parameter will receive completion status returned by the specified authentication package. The list of status values that may be returned are authentication package specific. Return Status: STATUS_SUCCESS - The call was made to the authentication package. The ProtocolStatus parameter must be checked to see what the completion status from the authentication package is. STATUS_QUOTA_EXCEEDED - This error indicates that the call could not be completed because the client does not have sufficient quota to allocate the return buffer. STATUS_NO_SUCH_PACKAGE - The specified authentication package is unknown to the LSA. Routine Description: This routine is used when a logon process needs to communicate with an authentication package. There are several reasons why a logon process may want to do this. Some examples are: o To implement multi-message authentication protocols (such as the LAN Manager Challenge-response protocol. o To notify the authentication package of interesting state change information, such as LAN Manager notifying the MSV1.0 package that a previously unreachable domain controller is now reachable. In this example, the authentication package would re-logon any users logged on to that domain controller. --*/ { NTSTATUS Status; LSAP_AU_API_MESSAGE Message = {0}; PLSAP_CALL_PACKAGE_ARGS Arguments; Arguments = &Message.Arguments.CallPackage; // // Set arguments // Arguments->AuthenticationPackage = AuthenticationPackage; Arguments->ProtocolSubmitBuffer = ProtocolSubmitBuffer; Arguments->SubmitBufferLength = SubmitBufferLength; // // Call the Local Security Authority Server. // Message.ApiNumber = LsapAuCallPackageApi; Message.PortMessage.u1.s1.DataLength = sizeof(*Arguments) + 8; Message.PortMessage.u1.s1.TotalLength = sizeof(Message); Message.PortMessage.u2.ZeroInit = 0L; Status = ZwRequestWaitReplyPort( LsaHandle, (PPORT_MESSAGE) &Message, (PPORT_MESSAGE) &Message ); // // We may be returning bogus return values here, but it doesn't // matter. They will just be ignored if an error occured. // if ( ProtocolReturnBuffer ) { (*ProtocolReturnBuffer) = Arguments->ProtocolReturnBuffer; } if ( ReturnBufferLength ) { (*ReturnBufferLength) = Arguments->ReturnBufferLength; } if ( ProtocolStatus ) { (*ProtocolStatus) = Arguments->ProtocolStatus; } if ( NT_SUCCESS(Status) ) { Status = Message.ReturnedStatus; #if DBG if ( !NT_SUCCESS(Status) ) { DbgPrint("LSA AU: Call Package Failed %lx\n",Status); } } else { DbgPrint("LSA AU: Call Package Failed %lx\n",Status); #endif //DBG } return Status; } NTSTATUS LsaDeregisterLogonProcess ( IN HANDLE LsaHandle ) /*++ This function deletes the caller's logon process context. --- WARNING --- Logon Processes are part of the Trusted Computer Base, and, as such, are expected to be debugged to a high degree. If a logon process deregisters, we will believe it. This allows us to re-use the old Logon Process context value. If the Logon process accidently uses its context value after freeing it, strange things may happen. LIkewise, if a client calls to release a context that has already been released, then LSA may grind to a halt. Arguments: LsaHandle - Supplies a handle obtained in a previous call to LsaRegisterLogonProcess. Return Status: STATUS_SUCCESS - Indicates the service completed successfully. --*/ { NTSTATUS Status; LSAP_AU_API_MESSAGE Message = {0}; NTSTATUS TempStatus; // // Call the Local Security Authority Server. // Message.ApiNumber = LsapAuDeregisterLogonProcessApi; Message.PortMessage.u1.s1.DataLength = 8; Message.PortMessage.u1.s1.TotalLength = sizeof(Message); Message.PortMessage.u2.ZeroInit = 0L; Status = ZwRequestWaitReplyPort( LsaHandle, (PPORT_MESSAGE) &Message, (PPORT_MESSAGE) &Message ); TempStatus = ZwClose(LsaHandle); ASSERT(NT_SUCCESS(TempStatus)); if ( NT_SUCCESS(Status) ) { Status = Message.ReturnedStatus; #if DBG if ( !NT_SUCCESS(Status) ) { DbgPrint("LSA AU: DeRregisterLogonProcess Failed 0x%lx\n",Status); } } else { DbgPrint("LSA AU: Package Lookup NtRequestWaitReply Failed 0x%lx\n",Status); #endif } return Status; }