/*++ Copyright (c) 1991-92 Microsoft Corporation Module Name: logonapi.c Abstract: This module contains the Netlogon API RPC client stubs. Author: Cliff Van Dyke (CliffV) 27-Jun-1991 [Environment:] User Mode - Win32 Revision History: 27-Jun-1991 CliffV Created --*/ // // INCLUDES // #include #include #include #include // needed by rpcasync.h #include // I_RpcExceptionFilter #include // includes lmcons.h, lmaccess.h, netlogon.h, ssi.h, windef.h #include // Encryption routines. #include // IF_DEBUG() #include // NERR_ and ERROR_ equates. #include // NetpKdPrint NET_API_STATUS NET_API_FUNCTION I_NetLogonUasLogon ( IN LPWSTR UserName, IN LPWSTR Workstation, OUT PNETLOGON_VALIDATION_UAS_INFO *ValidationInformation ) /*++ Routine Description: This function is called by the XACT server when processing a I_NetWkstaUserLogon XACT SMB. This feature allows a UAS client to logon to a SAM domain controller. Arguments: UserName -- Account name of the user logging on. Workstation -- The workstation from which the user is logging on. ValidationInformation -- Returns the requested validation information. Return Value: NERR_SUCCESS if there was no error. Otherwise, the error code is returned. --*/ { NET_API_STATUS NetStatus; LPWSTR ServerName = NULL; // Not supported remotely // // Do the RPC call with an exception handler since RPC will raise an // exception if anything fails. It is up to us to figure out what // to do once the exception is raised. // RpcTryExcept { *ValidationInformation = NULL; // Force RPC to allocate // // Call RPC version of the API. // NetStatus = NetrLogonUasLogon( (LPWSTR) ServerName, UserName, Workstation, ValidationInformation ); } RpcExcept( I_RpcExceptionFilter(RpcExceptionCode()) ) { NetStatus = RpcExceptionCode(); } RpcEndExcept; IF_DEBUG( LOGON ) { NetpKdPrint(("NetrLogonUasLogon rc = %lu 0x%lx\n", NetStatus, NetStatus)); } return NetStatus; } NET_API_STATUS I_NetLogonUasLogoff ( IN LPWSTR UserName, IN LPWSTR Workstation, OUT PNETLOGON_LOGOFF_UAS_INFO LogoffInformation ) /*++ Routine Description: This function is called by the XACT server when processing a I_NetWkstaUserLogoff XACT SMB. This feature allows a UAS client to logoff from a SAM domain controller. The request is authenticated, the entry is removed for this user from the logon session table maintained by the Netlogon service for NetLogonEnum, and logoff information is returned to the caller. The server portion of I_NetLogonUasLogoff (in the Netlogon service) compares the user name and workstation name specified in the LogonInformation with the user name and workstation name from the impersonation token. If they don't match, I_NetLogonUasLogoff fails indicating the access is denied. Group SECURITY_LOCAL is refused access to this function. Membership in SECURITY_LOCAL implies that this call was made locally and not through the XACT server. The Netlogon service cannot be sure that this function was called by the XACT server. Therefore, the Netlogon service will not simply delete the entry from the logon session table. Rather, the logon session table entry will be marked invisible outside of the Netlogon service (i.e., it will not be returned by NetLogonEnum) until a valid LOGON_WKSTINFO_RESPONSE is received for the entry. The Netlogon service will immediately interrogate the client (as described above for LOGON_WKSTINFO_RESPONSE) and temporarily increase the interrogation frequency to at least once a minute. The logon session table entry will reappear as soon as a function of interrogation if this isn't a true logoff request. Arguments: UserName -- Account name of the user logging off. Workstation -- The workstation from which the user is logging off. LogoffInformation -- Returns the requested logoff information. Return Value: The Net status code. --*/ { NET_API_STATUS NetStatus; LPWSTR ServerName = NULL; // Not supported remotely // // Do the RPC call with an exception handler since RPC will raise an // exception if anything fails. It is up to us to figure out what // to do once the exception is raised. // RpcTryExcept { // // Call RPC version of the API. // NetStatus = NetrLogonUasLogoff( (LPWSTR) ServerName, UserName, Workstation, LogoffInformation ); } RpcExcept( I_RpcExceptionFilter(RpcExceptionCode()) ) { NetStatus = RpcExceptionCode(); } RpcEndExcept; IF_DEBUG( LOGON ) { NetpKdPrint(("NetrLogonUasLogoff rc = %lu 0x%lx\n", NetStatus, NetStatus)); } return NetStatus; } NTSTATUS I_NetLogonSamLogon ( IN LPWSTR LogonServer OPTIONAL, IN LPWSTR ComputerName OPTIONAL, IN PNETLOGON_AUTHENTICATOR Authenticator OPTIONAL, OUT PNETLOGON_AUTHENTICATOR ReturnAuthenticator OPTIONAL, IN NETLOGON_LOGON_INFO_CLASS LogonLevel, IN LPBYTE LogonInformation, IN NETLOGON_VALIDATION_INFO_CLASS ValidationLevel, OUT LPBYTE * ValidationInformation, OUT PBOOLEAN Authoritative ) /*++ Routine Description: This function is called by an NT client to process an interactive or network logon. This function passes a domain name, user name and credentials to the Netlogon service and returns information needed to build a token. It is called in three instances: * It is called by the LSA's MSV1_0 authentication package for any NT system that has LanMan installed. The MSV1_0 authentication package calls SAM directly if LanMan is not installed. In this case, this function is a local function and requires the caller to have SE_TCB privilege. The local Netlogon service will either handle this request directly (validating the request with the local SAM database) or will forward this request to the appropriate domain controller as documented in sections 2.4 and 2.5. * It is called by a Netlogon service on a workstation to a DC in the Primary Domain of the workstation as documented in section 2.4. In this case, this function uses a secure channel set up between the two Netlogon services. * It is called by a Netlogon service on a DC to a DC in a trusted domain as documented in section 2.5. In this case, this function uses a secure channel set up between the two Netlogon services. The Netlogon service validates the specified credentials. If they are valid, adds an entry for this LogonId, UserName, and Workstation into the logon session table. The entry is added to the logon session table only in the domain defining the specified user's account. This service is also used to process a re-logon request. Arguments: LogonServer -- Supplies the name of the logon server to process this logon request. This field should be null to indicate this is a call from the MSV1_0 authentication package to the local Netlogon service. ComputerName -- Name of the machine making the call. This field should be null to indicate this is a call from the MSV1_0 authentication package to the local Netlogon service. Authenticator -- supplied by the client. This field should be null to indicate this is a call from the MSV1_0 authentication package to the local Netlogon service. ReturnAuthenticator -- Receives an authenticator returned by the server. This field should be null to indicate this is a call from the MSV1_0 authentication package to the local Netlogon service. LogonLevel -- Specifies the level of information given in LogonInformation. LogonInformation -- Specifies the description for the user logging on. ValidationLevel -- Specifies the level of information returned in ValidationInformation. Must be NetlogonValidationSamInformation. ValidationInformation -- Returns the requested validation information. Authoritative -- Returns whether the status returned is an authoritative status which should be returned to the original caller. If not, this logon request may be tried again on another domain controller. This parameter is returned regardless of the status code. Return Value: STATUS_SUCCESS: if there was no error. STATUS_NO_LOGON_SERVERS -- Either Pass-thru authentication or Trusted Domain Authentication could not contact the requested Domain Controller. STATUS_INVALID_INFO_CLASS -- Either LogonLevel or ValidationLevel is invalid. STATUS_INVALID_PARAMETER -- Another Parameter is invalid. STATUS_ACCESS_DENIED -- The caller does not have access to call this API. STATUS_NO_SUCH_USER -- Indicates that the user specified in LogonInformation does not exist. This status should not be returned to the originally caller. It should be mapped to STATUS_LOGON_FAILURE. STATUS_WRONG_PASSWORD -- Indicates that the password information in LogonInformation was incorrect. This status should not be returned to the originally caller. It should be mapped to STATUS_LOGON_FAILURE. STATUS_INVALID_LOGON_HOURES -- The user is not authorized to logon at this time. STATUS_INVALID_WORKSTATION -- The user is not authorized to logon from the specified workstation. STATUS_PASSWORD_EXPIRED -- The password for the user has expired. STATUS_ACCOUNT_DISABLED -- The user's account has been disabled. . . . --*/ { NTSTATUS Status = STATUS_SUCCESS; NETLOGON_LEVEL RpcLogonInformation; NETLOGON_VALIDATION RpcValidationInformation; // // Do the RPC call with an exception handler since RPC will raise an // exception if anything fails. It is up to us to figure out what // to do once the exception is raised. // RpcTryExcept { // // Call RPC version of the API. // RpcLogonInformation.LogonInteractive = (PNETLOGON_INTERACTIVE_INFO) LogonInformation; RpcValidationInformation.ValidationSam = NULL; Status = NetrLogonSamLogon( LogonServer, ComputerName, Authenticator, ReturnAuthenticator, LogonLevel, &RpcLogonInformation, ValidationLevel, &RpcValidationInformation, Authoritative ); *ValidationInformation = (LPBYTE) RpcValidationInformation.ValidationSam; } RpcExcept( I_RpcExceptionFilter(RpcExceptionCode()) ) { *Authoritative = TRUE; Status = I_RpcMapWin32Status(RpcExceptionCode()); } RpcEndExcept; IF_DEBUG( LOGON ) { NetpKdPrint(("I_NetLogonSamLogon rc = %lu 0x%lx\n", Status, Status)); } return Status; } NTSTATUS I_NetLogonSamLogonWithFlags ( IN LPWSTR LogonServer OPTIONAL, IN LPWSTR ComputerName OPTIONAL, IN PNETLOGON_AUTHENTICATOR Authenticator OPTIONAL, OUT PNETLOGON_AUTHENTICATOR ReturnAuthenticator OPTIONAL, IN NETLOGON_LOGON_INFO_CLASS LogonLevel, IN LPBYTE LogonInformation, IN NETLOGON_VALIDATION_INFO_CLASS ValidationLevel, OUT LPBYTE * ValidationInformation, OUT PBOOLEAN Authoritative, IN OUT PULONG ExtraFlags ) /*++ Routine Description: Flag version of I_NetLogonSamLogon. Arguments: Same as I_NetLogonSamLogon except: * ExtraFlags - Passes and returns a DWORD. For later expansion. Return Value: Same as I_NetLogonSamLogon. --*/ { NTSTATUS Status = STATUS_SUCCESS; NETLOGON_LEVEL RpcLogonInformation; NETLOGON_VALIDATION RpcValidationInformation; // // Do the RPC call with an exception handler since RPC will raise an // exception if anything fails. It is up to us to figure out what // to do once the exception is raised. // RpcTryExcept { // // Call RPC version of the API. // RpcLogonInformation.LogonInteractive = (PNETLOGON_INTERACTIVE_INFO) LogonInformation; RpcValidationInformation.ValidationSam = NULL; Status = NetrLogonSamLogonWithFlags( LogonServer, ComputerName, Authenticator, ReturnAuthenticator, LogonLevel, &RpcLogonInformation, ValidationLevel, &RpcValidationInformation, Authoritative, ExtraFlags ); *ValidationInformation = (LPBYTE) RpcValidationInformation.ValidationSam; } RpcExcept( I_RpcExceptionFilter(RpcExceptionCode()) ) { *Authoritative = TRUE; Status = I_RpcMapWin32Status(RpcExceptionCode()); } RpcEndExcept; IF_DEBUG( LOGON ) { NetpKdPrint(("I_NetLogonSamLogonWithFlags rc = %lu 0x%lx\n", Status, Status)); } return Status; } NTSTATUS I_NetLogonSamLogonEx ( IN PVOID ContextHandle, IN LPWSTR LogonServer OPTIONAL, IN LPWSTR ComputerName OPTIONAL, IN NETLOGON_LOGON_INFO_CLASS LogonLevel, IN LPBYTE LogonInformation, IN NETLOGON_VALIDATION_INFO_CLASS ValidationLevel, OUT LPBYTE * ValidationInformation, OUT PBOOLEAN Authoritative, IN OUT PULONG ExtraFlags, OUT PBOOLEAN RpcFailed ) /*++ Routine Description: Concurrent API version of I_NetLogonSamLogon. Arguments: Same as I_NetLogonSamLogon except: * No authenticator parameters. * Context Handle parameter * ExtraFlags - Passes and returns a DWORD. For later expansion. Return Value: Same as I_NetLogonSamLogon. --*/ { NTSTATUS Status = STATUS_SUCCESS; NETLOGON_LEVEL RpcLogonInformation; NETLOGON_VALIDATION RpcValidationInformation; *RpcFailed = FALSE; // // Do the RPC call with an exception handler since RPC will raise an // exception if anything fails. It is up to us to figure out what // to do once the exception is raised. // RpcTryExcept { // // Call RPC version of the API. // RpcLogonInformation.LogonInteractive = (PNETLOGON_INTERACTIVE_INFO) LogonInformation; RpcValidationInformation.ValidationSam = NULL; Status = NetrLogonSamLogonEx( ContextHandle, LogonServer, ComputerName, LogonLevel, &RpcLogonInformation, ValidationLevel, &RpcValidationInformation, Authoritative, ExtraFlags ); *ValidationInformation = (LPBYTE) RpcValidationInformation.ValidationSam; } RpcExcept( I_RpcExceptionFilter(RpcExceptionCode()) ) { *Authoritative = TRUE; *RpcFailed = TRUE; Status = I_RpcMapWin32Status(RpcExceptionCode()); } RpcEndExcept; IF_DEBUG( LOGON ) { NetpKdPrint(("I_NetLogonSamLogonEx rc = %lu 0x%lx\n", Status, Status)); } return Status; } NTSTATUS NET_API_FUNCTION I_NetLogonSamLogoff ( IN LPWSTR LogonServer OPTIONAL, IN LPWSTR ComputerName OPTIONAL, IN PNETLOGON_AUTHENTICATOR Authenticator OPTIONAL, OUT PNETLOGON_AUTHENTICATOR ReturnAuthenticator OPTIONAL, IN NETLOGON_LOGON_INFO_CLASS LogonLevel, IN LPBYTE LogonInformation ) /*++ Routine Description: This function is called by an NT client to process an interactive logoff. It is not called for the network logoff case since the Netlogon service does not maintain any context for network logons. This function does the following. It authenticates the request. It updates the logon statistics in the SAM database on whichever machine or domain defines this user account. It updates the logon session table in the primary domain of the machine making the request. And it returns logoff information to the caller. This function is called in same scenarios that I_NetLogonSamLogon is called: * It is called by the LSA's MSV1_0 authentication package to support LsaApLogonTerminated. In this case, this function is a local function and requires the caller to have SE_TCB privilege. The local Netlogon service will either handle this request directly (if LogonDomainName indicates this request was validated locally) or will forward this request to the appropriate domain controller as documented in sections 2.4 and 2.5. * It is called by a Netlogon service on a workstation to a DC in the Primary Domain of the workstation as documented in section 2.4. In this case, this function uses a secure channel set up between the two Netlogon services. * It is called by a Netlogon service on a DC to a DC in a trusted domain as documented in section 2.5. In this case, this function uses a secure channel set up between the two Netlogon services. When this function is a remote function, it is sent to the DC over a NULL session. Arguments: LogonServer -- Supplies the name of the logon server which logged this user on. This field should be null to indicate this is a call from the MSV1_0 authentication package to the local Netlogon service. ComputerName -- Name of the machine making the call. This field should be null to indicate this is a call from the MSV1_0 authentication package to the local Netlogon service. Authenticator -- supplied by the client. This field should be null to indicate this is a call from the MSV1_0 authentication package to the local Netlogon service. ReturnAuthenticator -- Receives an authenticator returned by the server. This field should be null to indicate this is a call from the MSV1_0 authentication package to the local Netlogon service. LogonLevel -- Specifies the level of information given in LogonInformation. LogonInformation -- Specifies the logon domain name, logon Id, user name and workstation name of the user logging off. Return Value: --*/ { NTSTATUS Status = STATUS_SUCCESS; NETLOGON_LEVEL RpcLogonInformation; // // Do the RPC call with an exception handler since RPC will raise an // exception if anything fails. It is up to us to figure out what // to do once the exception is raised. // RpcTryExcept { // // Call RPC version of the API. // RpcLogonInformation.LogonInteractive = (PNETLOGON_INTERACTIVE_INFO) LogonInformation; Status = NetrLogonSamLogoff( LogonServer, ComputerName, Authenticator, ReturnAuthenticator, LogonLevel, &RpcLogonInformation ); } RpcExcept( I_RpcExceptionFilter(RpcExceptionCode()) ) { Status = I_RpcMapWin32Status(RpcExceptionCode()); } RpcEndExcept; IF_DEBUG( LOGON ) { NetpKdPrint(("I_NetLogonSamLogoff rc = %lu 0x%lx\n", Status, Status)); } return Status; } NTSTATUS NET_API_FUNCTION I_NetLogonSendToSam ( IN LPWSTR PrimaryName OPTIONAL, IN LPWSTR ComputerName, IN PNETLOGON_AUTHENTICATOR Authenticator, OUT PNETLOGON_AUTHENTICATOR ReturnAuthenticator, IN LPBYTE OpaqueBuffer, IN ULONG OpaqueBufferSize ) /*++ Routine Description: This function sends an opaque buffer from SAM on a BDC to SAM on the PDC. The original use of this routine will be to allow the BDC to forward user account password changes to the PDC. Arguments: PrimaryName -- Computer name of the PDC to remote the call to. ComputerName -- Name of the machine making the call. Authenticator -- supplied by the client. ReturnAuthenticator -- Receives an authenticator returned by the server. OpaqueBuffer - Buffer to be passed to the SAM service on the PDC. The buffer will be encrypted on the wire. OpaqueBufferSize - Size (in bytes) of OpaqueBuffer. Return Value: STATUS_SUCCESS: Message successfully sent to PDC STATUS_NO_MEMORY: There is not enough memory to complete the operation STATUS_NO_SUCH_DOMAIN: DomainName does not correspond to a hosted domain STATUS_NO_LOGON_SERVERS: PDC is not currently available STATUS_NOT_SUPPORTED: PDC does not support this operation --*/ { NTSTATUS Status = STATUS_SUCCESS; // // Do the RPC call with an exception handler since RPC will raise an // exception if anything fails. It is up to us to figure out what // to do once the exception is raised. // RpcTryExcept { // // Call RPC version of the API. // Status = NetrLogonSendToSam( PrimaryName, ComputerName, Authenticator, ReturnAuthenticator, OpaqueBuffer, OpaqueBufferSize ); } RpcExcept( I_RpcExceptionFilter(RpcExceptionCode()) ) { Status = I_RpcMapWin32Status(RpcExceptionCode()); } RpcEndExcept; IF_DEBUG( LOGON ) { NetpKdPrint(("I_NetLogonSendToSam rc = %lu 0x%lx\n", Status, Status)); } return Status; }