/*++ Copyright (c) 1993 Microsoft Corporation Module Name: authpkg.c Abstract: This module is the NetWare authentication package. It saves credentials in LSA, and notifies the workstation of a logoff. Author: Jim Kelly (jimk) 11-Mar-1991 Cliff Van Dyke (cliffv) 25-Apr-1991 Revision History: Rita Wong (ritaw) 1-Apr-1993 Cloned for NetWare --*/ #include #include #include #include #include #include // // Netware authentication manager credential // #define NW_CREDENTIAL_KEY "NWCS_Credential" //-------------------------------------------------------------------// // // // Local functions // // // //-------------------------------------------------------------------// NTSTATUS AuthpSetCredential( IN PLUID LogonId, IN LPWSTR UserName, IN LPWSTR Password ); NTSTATUS AuthpGetCredential( IN PLUID LogonId, OUT PNWAUTH_GET_CREDENTIAL_RESPONSE CredBuf ); NTSTATUS NwAuthGetCredential( IN PLSA_CLIENT_REQUEST ClientRequest, IN PVOID ProtocolSubmitBuffer, IN PVOID ClientBufferBase, IN ULONG SubmitBufferSize, OUT PVOID *ProtocolReturnBuffer, OUT PULONG ReturnBufferSize, OUT PNTSTATUS ProtocolStatus ); NTSTATUS NwAuthSetCredential( IN PLSA_CLIENT_REQUEST ClientRequest, IN PVOID ProtocolSubmitBuffer, IN PVOID ClientBufferBase, IN ULONG SubmitBufferSize, OUT PVOID *ProtocolReturnBuffer, OUT PULONG ReturnBufferSize, OUT PNTSTATUS ProtocolStatus ); PVOID NwAuthHeap; ULONG NwAuthPackageId; LSA_DISPATCH_TABLE Lsa; // // LsaApCallPackage() function dispatch table // PLSA_AP_CALL_PACKAGE NwCallPackageDispatch[] = { NwAuthGetCredential, NwAuthSetCredential }; // // Structure of the credential saved in LSA. // typedef struct _NWCREDENTIAL { LPWSTR UserName; LPWSTR Password; } NWCREDENTIAL, *PNWCREDENTIAL; //-------------------------------------------------------------------// // // // Authentication package dispatch routines. // // // //-------------------------------------------------------------------// NTSTATUS LsaApInitializePackage ( IN ULONG AuthenticationPackageId, IN PLSA_DISPATCH_TABLE LsaDispatchTable, IN PSTRING Database OPTIONAL, IN PSTRING Confidentiality OPTIONAL, OUT PSTRING *AuthenticationPackageName ) /*++ Routine Description: This service is called once by the LSA during system initialization to provide the DLL a chance to initialize itself. Arguments: AuthenticationPackageId - The ID assigned to the authentication package. LsaDispatchTable - Provides the address of a table of LSA services available to authentication packages. The services of this table are ordered according to the enumerated type LSA_DISPATCH_TABLE_API. Database - This parameter is not used by this authentication package. Confidentiality - This parameter is not used by this authentication package. AuthenticationPackageName - Receives the name of the authentication package. The authentication package is responsible for allocating the buffer that the string is in (using the AllocateLsaHeap() service) and returning its address here. The buffer will be deallocated by LSA when it is no longer needed. Return Value: STATUS_SUCCESS - Indicates the service completed successfully. --*/ { PSTRING NameString; PCHAR NameBuffer; UNREFERENCED_PARAMETER(Database); UNREFERENCED_PARAMETER(Confidentiality); // // Use the process heap for memory allocations. // NwAuthHeap = RtlProcessHeap(); NwAuthPackageId = AuthenticationPackageId; // // Copy the LSA service dispatch table // Lsa.CreateLogonSession = LsaDispatchTable->CreateLogonSession; Lsa.DeleteLogonSession = LsaDispatchTable->DeleteLogonSession; Lsa.AddCredential = LsaDispatchTable->AddCredential; Lsa.GetCredentials = LsaDispatchTable->GetCredentials; Lsa.DeleteCredential = LsaDispatchTable->DeleteCredential; Lsa.AllocateLsaHeap = LsaDispatchTable->AllocateLsaHeap; Lsa.FreeLsaHeap = LsaDispatchTable->FreeLsaHeap; Lsa.AllocateClientBuffer = LsaDispatchTable->AllocateClientBuffer; Lsa.FreeClientBuffer = LsaDispatchTable->FreeClientBuffer; Lsa.CopyToClientBuffer = LsaDispatchTable->CopyToClientBuffer; Lsa.CopyFromClientBuffer = LsaDispatchTable->CopyFromClientBuffer; // // Allocate and return our package name // NameBuffer = (*Lsa.AllocateLsaHeap)(sizeof(NW_AUTH_PACKAGE_NAME)); strcpy(NameBuffer, NW_AUTH_PACKAGE_NAME); NameString = (*Lsa.AllocateLsaHeap)(sizeof(STRING)); RtlInitString(NameString, NameBuffer); (*AuthenticationPackageName) = NameString; // // Delete outdated credential information in the registry // NwDeleteCurrentUser(); (void) NwDeleteServiceLogon(NULL); return STATUS_SUCCESS; } NTSTATUS LsaApLogonUser ( IN PLSA_CLIENT_REQUEST ClientRequest, IN SECURITY_LOGON_TYPE LogonType, IN PVOID ProtocolSubmitBuffer, IN PVOID ClientBufferBase, IN ULONG SubmitBufferSize, OUT PVOID *ProfileBuffer, OUT PULONG ProfileBufferSize, OUT PLUID LogonId, OUT PNTSTATUS SubStatus, OUT PLSA_TOKEN_INFORMATION_TYPE TokenInformationType, OUT PVOID *TokenInformation, OUT PUNICODE_STRING *AccountName, OUT PUNICODE_STRING *AuthenticatingAuthority ) /*++ Routine Description: This routine is used to authenticate a user logon attempt. This may be the user's initial logon, necessary to gain access to NT, or may be a subsequent logon attempt. If the logon is the user's initial logon, then a new LSA logon session will be established for the user and a PrimaryToken will be returned. Otherwise, the authentication package will associated appropriate credentials with the already logged on user's existing LSA logon session. Arguments: ClientRequest - Is a pointer to an opaque data structure representing the client's request. LogonType - Identifies the type of logon being attempted. ProtocolSubmitBuffer - Supplies the authentication information specific to the authentication package. ClientBufferBase - Provides the address within the client process at which the authentication information was resident. This may be necessary to fix-up any pointers within the authentication information buffer. SubmitBufferSize - Indicates the Size, in bytes, of the authentication information buffer. ProfileBuffer - Is used to return the address of the profile buffer in the client process. The authentication package is responsible for allocating and returning the profile buffer within the client process. However, if the LSA subsequently encounters an error which prevents a successful logon, then the LSA will take care of deallocating that buffer. This buffer is expected to have been allocated with the AllocateClientBuffer() service. The format and semantics of this buffer are specific to the authentication package. ProfileBufferSize - Receives the size (in bytes) of the returned profile buffer. LogonId - Points to a buffer into which the authentication package must return a logon ID that uniquely identifies this logon session. SubStatus - If the logon failed due to account restrictions, the reason for the failure should be returned via this parameter. The reason is authentication-package specific. The substatus values for authentication package "MSV1.0" are: STATUS_INVALID_LOGON_HOURS STATUS_INVALID_WORKSTATION STATUS_PASSWORD_EXPIRED STATUS_ACCOUNT_DISABLED TokenInformationType - If the logon is successful, this field is used to indicate what level of information is being returned for inclusion in the Token to be created. This information is returned via the TokenInformation parameter. TokenInformation - If the logon is successful, this parameter is used by the authentication package to return information to be included in the token. The format and content of the buffer returned is indicated by the TokenInformationLevel return value. AccountName - A Unicode string describing the account name being logged on to. This parameter must always be returned regardless of the success or failure of the operation. AuthenticatingAuthority - A Unicode string describing the Authenticating Authority for the logon. This string may optionally be omitted. Return Value: STATUS_NOT_IMPLEMENTED - NetWare authentication package does not support login. --*/ { UNREFERENCED_PARAMETER(ClientRequest); UNREFERENCED_PARAMETER(LogonType); UNREFERENCED_PARAMETER(ProtocolSubmitBuffer); UNREFERENCED_PARAMETER(ClientBufferBase); UNREFERENCED_PARAMETER(SubmitBufferSize); UNREFERENCED_PARAMETER(ProfileBuffer); UNREFERENCED_PARAMETER(ProfileBufferSize); UNREFERENCED_PARAMETER(LogonId); UNREFERENCED_PARAMETER(SubStatus); UNREFERENCED_PARAMETER(TokenInformationType); UNREFERENCED_PARAMETER(TokenInformation); UNREFERENCED_PARAMETER(AccountName); UNREFERENCED_PARAMETER(AuthenticatingAuthority); return STATUS_NOT_IMPLEMENTED; } NTSTATUS LsaApCallPackage ( IN PLSA_CLIENT_REQUEST ClientRequest, IN PVOID ProtocolSubmitBuffer, IN PVOID ClientBufferBase, IN ULONG SubmitBufferLength, OUT PVOID *ProtocolReturnBuffer, OUT PULONG ReturnBufferLength, OUT PNTSTATUS ProtocolStatus ) /*++ Routine Description: This routine is the dispatch routine for LsaCallAuthenticationPackage(). Arguments: ClientRequest - Is a pointer to an opaque data structure representing the client's request. ProtocolSubmitBuffer - Supplies a protocol message specific to the authentication package. ClientSubmitBufferBase - Supplies the client address of the submitted protocol message. SubmitBufferLength - Indicates the length of the submitted protocol message buffer. ProtocolReturnBuffer - Is used to return the address of the protocol buffer in the client process. The authentication package is responsible for allocating and returning the protocol buffer within the client process. This buffer is expected to have been allocated with the AllocateClientBuffer() service. The format and semantics of this buffer are specific to the authentication package. ReturnBufferLength - Receives the length (in bytes) of the returned protocol 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: --*/ { ULONG MessageType; // // Get the messsage type from the protocol submit buffer. // if ( SubmitBufferLength < sizeof(NWAUTH_MESSAGE_TYPE) ) { return STATUS_INVALID_PARAMETER; } MessageType = (ULONG) *((PNWAUTH_MESSAGE_TYPE)(ProtocolSubmitBuffer)); if ( MessageType >= (sizeof(NwCallPackageDispatch)/sizeof(NwCallPackageDispatch[0])) ) { return STATUS_INVALID_PARAMETER; } // // Allow the dispatch routines to only set the return buffer information // on success conditions. // *ProtocolReturnBuffer = NULL; *ReturnBufferLength = 0; // // Call the appropriate routine for this message. // return (*(NwCallPackageDispatch[MessageType]))( ClientRequest, ProtocolSubmitBuffer, ClientBufferBase, SubmitBufferLength, ProtocolReturnBuffer, ReturnBufferLength, ProtocolStatus ) ; } VOID LsaApLogonTerminated ( IN PLUID LogonId ) /*++ Routine Description: This routine is used to notify each authentication package when a logon session terminates. A logon session terminates when the last token referencing the logon session is deleted. Arguments: LogonId - Is the logon ID that just logged off. Return Status: None. --*/ { DWORD status; LONG RegError; HKEY WkstaKey = NULL; HKEY WkstaLogonKey = NULL; HKEY CurrentUserKey = NULL; LPWSTR CurrentUser = NULL; PLUID CurrentLogonId = NULL; #if DBG IF_DEBUG(LOGON) { KdPrint(("\nNWPROVAU: LsaApLogonTerminated\n")); } #endif RpcTryExcept { // // The logon ID may be for a service login // if (NwDeleteServiceLogon(LogonId) == NO_ERROR) { // // Tell workstation to log off the service. // (void) NwrLogoffUser(NULL, LogonId); goto Done; } // // Open HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services // \NWCWorkstation\Parameters to delete the CurrentUser // value to indicate that there is currently no interactively // logged on user. // RegError = RegOpenKeyExW( HKEY_LOCAL_MACHINE, NW_WORKSTATION_REGKEY, REG_OPTION_NON_VOLATILE, KEY_READ | KEY_WRITE | DELETE, &WkstaKey ); if (RegError == NO_ERROR) { // // Read the current user SID string so that we // know which key is the current user key to open. // status = NwReadRegValue( WkstaKey, NW_CURRENTUSER_VALUENAME, &CurrentUser ); if (status == NO_ERROR) { // // Open the Logon key // RegError = RegOpenKeyExW( HKEY_LOCAL_MACHINE, NW_WORKSTATION_LOGON_REGKEY, REG_OPTION_NON_VOLATILE, KEY_READ, &WkstaLogonKey ); // // Open the key under Logon // if ( RegError == NO_ERROR ) { RegError = RegOpenKeyExW( WkstaLogonKey, CurrentUser, REG_OPTION_NON_VOLATILE, KEY_READ, &CurrentUserKey ); } if (RegError == NO_ERROR) { // // Read the logon ID // status = NwReadRegValue( CurrentUserKey, NW_LOGONID_VALUENAME, (LPWSTR *) &CurrentLogonId ); if (status == NO_ERROR) { if (RtlEqualLuid(CurrentLogonId, LogonId)) { // // Only delete the current user value if the // logon ID of the logging off user is the same // as the current user's logon ID. // (void) RegDeleteValueW( WkstaKey, NW_CURRENTUSER_VALUENAME ); } // // Tell workstation to log off the // interactive user. // (void) NwrLogoffUser(NULL, LogonId); } } } } Done: ; } RpcExcept(1) { //status = NwpMapRpcError(RpcExceptionCode()); } RpcEndExcept // // free up before returning in case of premature exit (eg. RPC exceptions). // if (WkstaKey != NULL) (void) RegCloseKey(WkstaKey); if (WkstaLogonKey != NULL) (void) RegCloseKey(WkstaLogonKey); if (CurrentUserKey != NULL) (void) RegCloseKey(CurrentUserKey); if (CurrentLogonId != NULL) (void) LocalFree((HLOCAL) CurrentLogonId); if (CurrentUser != NULL) (void) LocalFree((HLOCAL) CurrentUser); } NTSTATUS NwAuthGetCredential( IN PLSA_CLIENT_REQUEST ClientRequest, IN PVOID ProtocolSubmitBuffer, IN PVOID ClientBufferBase, IN ULONG SubmitBufferSize, OUT PVOID *ProtocolReturnBuffer, OUT PULONG ReturnBufferSize, OUT PNTSTATUS ProtocolStatus ) /*++ Routine Description: This routine is the dispatch routine for LsaCallAuthenticationPackage() with a message type of NwAuth_GetCredential. It is called by the NetWare workstation service to get the username and password associated with a logon ID. Arguments: The arguments to this routine are identical to those of LsaApCallPackage. Only the special attributes of these parameters as they apply to this routine are mentioned here. Return Value: STATUS_SUCCESS - Indicates the service completed successfully. --*/ { NTSTATUS Status; PNWAUTH_GET_CREDENTIAL_RESPONSE LocalBuf; UNREFERENCED_PARAMETER(ClientBufferBase); // // Ensure the specified Submit Buffer is of reasonable size. // if (SubmitBufferSize < sizeof(NWAUTH_GET_CREDENTIAL_REQUEST)) { return STATUS_INVALID_PARAMETER; } // // Allocate a local buffer and a buffer in client's address space. // *ReturnBufferSize = sizeof(NWAUTH_GET_CREDENTIAL_RESPONSE); LocalBuf = RtlAllocateHeap(NwAuthHeap, 0, *ReturnBufferSize); if (LocalBuf == NULL) { return STATUS_NO_MEMORY; } Status = (*Lsa.AllocateClientBuffer)( ClientRequest, *ReturnBufferSize, (PVOID *) ProtocolReturnBuffer ); if (! NT_SUCCESS( Status )) { RtlFreeHeap(NwAuthHeap, 0, LocalBuf); return Status; } // // Get the credential from LSA // Status = AuthpGetCredential( &(((PNWAUTH_GET_CREDENTIAL_REQUEST) ProtocolSubmitBuffer)->LogonId), LocalBuf ); if (! NT_SUCCESS(Status)) { goto Cleanup; } // // Copy the data to the client's address space. // Status = (*Lsa.CopyToClientBuffer)( ClientRequest, *ReturnBufferSize, (PVOID) *ProtocolReturnBuffer, (PVOID) LocalBuf ); Cleanup: RtlFreeHeap(NwAuthHeap, 0, LocalBuf); // // If we weren't successful, free the buffer in the clients address space. // Otherwise, the client will free the memory when done. // if (! NT_SUCCESS(Status)) { (VOID) (*Lsa.FreeClientBuffer)( ClientRequest, *ProtocolReturnBuffer ); *ProtocolReturnBuffer = NULL; } // // Return status to the caller. // *ProtocolStatus = Status; return STATUS_SUCCESS; } NTSTATUS NwAuthSetCredential( IN PLSA_CLIENT_REQUEST ClientRequest, IN PVOID ProtocolSubmitBuffer, IN PVOID ClientBufferBase, IN ULONG SubmitBufferSize, OUT PVOID *ProtocolReturnBuffer, OUT PULONG ReturnBufferSize, OUT PNTSTATUS ProtocolStatus ) /*++ Routine Description: This routine is the dispatch routine for LsaCallAuthenticationPackage() with a message type of NwAuth_SetCredential. It is called by the NetWare credential manager DLL on user logon to save the username and password of the logon session. Arguments: The arguments to this routine are identical to those of LsaApCallPackage. Only the special attributes of these parameters as they apply to this routine are mentioned here. Return Value: STATUS_SUCCESS - Indicates the service completed successfully. --*/ { NTSTATUS Status; UNREFERENCED_PARAMETER(ClientBufferBase); // // Ensure the specified Submit Buffer is of reasonable size. // if (SubmitBufferSize < sizeof(NWAUTH_SET_CREDENTIAL_REQUEST)) { return STATUS_INVALID_PARAMETER; } #if DBG IF_DEBUG(LOGON) { KdPrint(("NwAuthSetCredential: LogonId %08lx%08lx Username %ws\n", ((PNWAUTH_SET_CREDENTIAL_REQUEST) ProtocolSubmitBuffer)->LogonId.HighPart, ((PNWAUTH_SET_CREDENTIAL_REQUEST) ProtocolSubmitBuffer)->LogonId.LowPart, ((PNWAUTH_SET_CREDENTIAL_REQUEST) ProtocolSubmitBuffer)->UserName )); } #endif // // Set the credential in LSA // Status = AuthpSetCredential( &(((PNWAUTH_SET_CREDENTIAL_REQUEST) ProtocolSubmitBuffer)->LogonId), ((PNWAUTH_SET_CREDENTIAL_REQUEST) ProtocolSubmitBuffer)->UserName, ((PNWAUTH_SET_CREDENTIAL_REQUEST) ProtocolSubmitBuffer)->Password ); *ProtocolStatus = Status; return STATUS_SUCCESS; } NTSTATUS AuthpGetCredential( IN PLUID LogonId, OUT PNWAUTH_GET_CREDENTIAL_RESPONSE CredBuf ) /*++ Routine Description: This routine retrieves the credential saved in LSA given the logon ID. Arguments: LogonId - Supplies the logon ID for the logon session. CredBuf - Buffer to receive the credential. Return Value: --*/ { NTSTATUS Status; STRING KeyString; STRING CredString; ULONG QueryContext = 0; ULONG KeyLength; PNWCREDENTIAL Credential; RtlInitString(&KeyString, NW_CREDENTIAL_KEY); Status = (*Lsa.GetCredentials)( LogonId, NwAuthPackageId, &QueryContext, (BOOLEAN) FALSE, // Just retrieve matching key &KeyString, &KeyLength, &CredString ); if (! NT_SUCCESS(Status)) { return Status; } Credential = (PNWCREDENTIAL) CredString.Buffer; #if DBG IF_DEBUG(LOGON) { KdPrint(("AuthpGetCredential: Got CredentialSize %lu\n", CredString.Length)); } #endif // // Make the pointers absolute. // Credential->UserName = (LPWSTR) ((DWORD) Credential->UserName + (DWORD) Credential); Credential->Password = (LPWSTR) ((DWORD) Credential->Password + (DWORD) Credential); wcscpy(CredBuf->UserName, Credential->UserName); wcscpy(CredBuf->Password, Credential->Password); return STATUS_SUCCESS; } NTSTATUS AuthpSetCredential( IN PLUID LogonId, IN LPWSTR UserName, IN LPWSTR Password ) /*++ Routine Description: This routine saves the credential in LSA. Arguments: LogonId - Supplies the logon ID for the logon session. UserName, Password - Credential for the logon session. Return Value: --*/ { NTSTATUS Status; PNWCREDENTIAL Credential; DWORD CredentialSize; STRING CredString; STRING KeyString; // // Allocate memory to package the credential. // CredentialSize = sizeof(NWCREDENTIAL) + (wcslen(UserName) + wcslen(Password) + 2) * sizeof(WCHAR); #if DBG IF_DEBUG(LOGON) { KdPrint(("AuthpSetCredential: CredentialSize is %lu\n", CredentialSize)); } #endif Credential = RtlAllocateHeap(NwAuthHeap, 0, CredentialSize); if (Credential == NULL) { return STATUS_NO_MEMORY; } RtlZeroMemory(Credential, CredentialSize); // // Pack the credential // Credential->UserName = (LPWSTR) (((DWORD) Credential) + sizeof(NWCREDENTIAL)); wcscpy(Credential->UserName, UserName); Credential->Password = (LPWSTR) ((DWORD) Credential->UserName + (wcslen(UserName) + 1) * sizeof(WCHAR)); wcscpy(Credential->Password, Password); // // Make the pointers self-relative. // Credential->UserName = (LPWSTR) ((DWORD) Credential->UserName - (DWORD) Credential); Credential->Password = (LPWSTR) ((DWORD) Credential->Password - (DWORD) Credential); // // Add credential to logon session // RtlInitString(&KeyString, NW_CREDENTIAL_KEY); CredString.Buffer = (PCHAR) Credential; CredString.Length = (USHORT) CredentialSize; CredString.MaximumLength = (USHORT) CredentialSize; Status = (*Lsa.AddCredential)( LogonId, NwAuthPackageId, &KeyString, &CredString ); if (! NT_SUCCESS(Status)) { KdPrint(( "NWPROVAU: AuthpSetCredential: error from AddCredential %lX\n", Status)); } return Status; }