/*++ Copyright (c) 1993 Microsoft Corporation Module Name: api.c Abstract: This module contains exposed APIs that is used by the NetWare Control Panel Applet. Author: Yi-Hsin Sung 15-Jul-1993 Revision History: ChuckC 23-Jul-93 Completed the stubs --*/ #include #include #include #include #include #include #include //Multi-User code merge DWORD NwpCitrixGetUserInfo( LPWSTR *ppszUserSid ); // // forward declare // DWORD NwpGetCurrentUserRegKey( IN DWORD DesiredAccess, OUT HKEY *phKeyCurrentUser ); DWORD NwQueryInfo( OUT PDWORD pnPrintOptions, OUT LPWSTR *ppszPreferredSrv ) /*++ Routine Description: This routine gets the user's preferred server and print options from the registry. Arguments: pnPrintOptions - Receives the user's print option ppszPreferredSrv - Receives the user's preferred server Return Value: Returns the appropriate Win32 error. --*/ { HKEY hKeyCurrentUser = NULL; DWORD BufferSize; DWORD BytesNeeded; DWORD PrintOption; DWORD ValueType; LPWSTR PreferredServer ; DWORD err ; // // get to right place in registry and allocate dthe buffer // if (err = NwpGetCurrentUserRegKey( KEY_READ, &hKeyCurrentUser)) { // // If somebody mess around with the registry and we can't find // the registry, just use the defaults. // *ppszPreferredSrv = NULL; *pnPrintOptions = NW_PRINT_OPTION_DEFAULT; return NO_ERROR; } BufferSize = sizeof(WCHAR) * (MAX_PATH + 2) ; PreferredServer = (LPWSTR) LocalAlloc(LPTR, BufferSize) ; if (!PreferredServer) return (GetLastError()) ; // // Read PreferredServer value into Buffer. // BytesNeeded = BufferSize ; err = RegQueryValueExW( hKeyCurrentUser, NW_SERVER_VALUENAME, NULL, &ValueType, (LPBYTE) PreferredServer, &BytesNeeded ); if (err != NO_ERROR) { // // set to empty and carry on // PreferredServer[0] = 0; } // // Read PrintOption value into PrintOption. // BytesNeeded = sizeof(PrintOption); err = RegQueryValueExW( hKeyCurrentUser, NW_PRINTOPTION_VALUENAME, NULL, &ValueType, (LPBYTE) &PrintOption, &BytesNeeded ); if (err != NO_ERROR) { // // set to default and carry on // PrintOption = NW_PRINT_OPTION_DEFAULT; } if (hKeyCurrentUser != NULL) (void) RegCloseKey(hKeyCurrentUser) ; *ppszPreferredSrv = PreferredServer ; *pnPrintOptions = PrintOption ; return NO_ERROR ; } DWORD NwSetInfoInRegistry( IN DWORD nPrintOptions, IN LPWSTR pszPreferredSrv ) /*++ Routine Description: This routine set the user's print option and preferred server into the registry. Arguments: nPrintOptions - Supplies the print option. pszPreferredSrv - Supplies the preferred server. Return Value: Returns the appropriate Win32 error. --*/ { HKEY hKeyCurrentUser = NULL; DWORD err = NwpGetCurrentUserRegKey( KEY_SET_VALUE, &hKeyCurrentUser ); if (err != NO_ERROR) return err; err = RegSetValueEx(hKeyCurrentUser, NW_SERVER_VALUENAME, 0, REG_SZ, (CONST BYTE *)pszPreferredSrv, (wcslen(pszPreferredSrv)+1) * sizeof(WCHAR)) ; if (err != NO_ERROR) { if (hKeyCurrentUser != NULL) (void) RegCloseKey(hKeyCurrentUser) ; return err; } err = RegSetValueEx(hKeyCurrentUser, NW_PRINTOPTION_VALUENAME, 0, REG_DWORD, (CONST BYTE *)&nPrintOptions, sizeof(nPrintOptions)) ; if (hKeyCurrentUser != NULL) (void) RegCloseKey(hKeyCurrentUser) ; return err; } DWORD NwQueryLogonOptions( OUT PDWORD pnLogonScriptOptions ) /*++ Routine Description: This routine gets the user's Logon script options from the registry. Arguments: pnLogonScriptOptions - Receives the user's Logon script options Return Value: Returns the appropriate Win32 error. --*/ { HKEY hKeyCurrentUser; DWORD BytesNeeded; DWORD LogonScriptOption; DWORD ValueType; DWORD err ; // // get to right place in registry and allocate the buffer // if (err = NwpGetCurrentUserRegKey( KEY_READ, &hKeyCurrentUser)) { // // If somebody mess around with the registry and we can't find // the registry, assume no. // *pnLogonScriptOptions = NW_LOGONSCRIPT_DEFAULT ; return NO_ERROR; } // // Read LogonScriptOption value into LogonScriptOption. // BytesNeeded = sizeof(LogonScriptOption); err = RegQueryValueExW( hKeyCurrentUser, NW_LOGONSCRIPT_VALUENAME, NULL, &ValueType, (LPBYTE) &LogonScriptOption, &BytesNeeded ); if (err != NO_ERROR) { // // default to nothing and carry on // LogonScriptOption = NW_LOGONSCRIPT_DEFAULT; } *pnLogonScriptOptions = LogonScriptOption ; return NO_ERROR ; } DWORD NwSetLogonOptionsInRegistry( IN DWORD nLogonScriptOptions ) /*++ Routine Description: This routine set the logon script options in the registry. Arguments: nLogonScriptOptions - Supplies the logon options Return Value: Returns the appropriate Win32 error. --*/ { HKEY hKeyCurrentUser; DWORD err = NwpGetCurrentUserRegKey( KEY_SET_VALUE, &hKeyCurrentUser ); if (err != NO_ERROR) return err; err = RegSetValueEx(hKeyCurrentUser, NW_LOGONSCRIPT_VALUENAME, 0, REG_DWORD, (CONST BYTE *)&nLogonScriptOptions, sizeof(nLogonScriptOptions)) ; (void) RegCloseKey( hKeyCurrentUser ); return err; } DWORD NwSetInfoInWksta( IN DWORD nPrintOption, IN LPWSTR pszPreferredSrv ) /*++ Routine Description: This routine notifies the workstation service and the redirector about the user's new print option and preferred server. Arguments: nPrintOptions - Supplies the print option. pszPreferredSrv - Supplies the preferred server. Return Value: Returns the appropriate Win32 error. --*/ { DWORD err; RpcTryExcept { err = NwrSetInfo( NULL, nPrintOption, pszPreferredSrv ); } RpcExcept(1) { err = NwpMapRpcError(RpcExceptionCode()); } RpcEndExcept return err; } DWORD NwSetLogonScript( IN DWORD ScriptOptions ) /*++ Routine Description: This routine notifies the workstation service of login script options. Arguments: ScriptOptions - Supplies the options. Return Value: Returns the appropriate Win32 error. --*/ { DWORD err; RpcTryExcept { err = NwrSetLogonScript( NULL, ScriptOptions ); } RpcExcept(1) { err = NwpMapRpcError(RpcExceptionCode()); } RpcEndExcept return err; } DWORD NwValidateUser( IN LPWSTR pszPreferredSrv ) /*++ Routine Description: This routine checks to see if the user can be authenticated on the chosen preferred server. Arguments: pszPreferredSrv - Supplies the preferred server name. Return Value: Returns the appropriate Win32 error. --*/ { DWORD err; // // Don't need to validate if the preferred server is NULL or empty string // if ( ( pszPreferredSrv == NULL ) || ( *pszPreferredSrv == 0 ) ) { return NO_ERROR; } // // See if the name contains any invalid characters // if ( !IS_VALID_SERVER_TOKEN( pszPreferredSrv, wcslen( pszPreferredSrv ))) return ERROR_INVALID_NAME; RpcTryExcept { err = NwrValidateUser( NULL, pszPreferredSrv ); } RpcExcept(1) { err = NwpMapRpcError( RpcExceptionCode() ); } RpcEndExcept return err; } DWORD NwpGetCurrentUserRegKey( IN DWORD DesiredAccess, OUT HKEY *phKeyCurrentUser ) /*++ Routine Description: This routine opens the current user's registry key under \HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\NWCWorkstation\Parameters Arguments: DesiredAccess - The access mask to open the key with phKeyCurrentUser - Receives the opened key handle Return Value: Returns the appropriate Win32 error. --*/ { DWORD err; HKEY hkeyWksta; LPWSTR CurrentUser; // // Open HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services // \NWCWorkstation\Parameters // err = RegOpenKeyExW( HKEY_LOCAL_MACHINE, NW_WORKSTATION_REGKEY, REG_OPTION_NON_VOLATILE, KEY_READ, &hkeyWksta ); if ( err ) { KdPrint(("NWPROVAU: NwGetCurrentUserRegKey open Parameters key unexpected error %lu!\n", err)); return err; } // -- MultiUser code merge ---- // Get the current user's SID string // DON'T look in the registry. This thread should be owned by the // user. // CurrentUser = NULL; err = NwpCitrixGetUserInfo( &CurrentUser ); if ( err ) { KdPrint(("NWPROVAU: NwGetCurrentUserRegKey get CurrentUser SID unexpected error %lu!\n", err)); (void) RegCloseKey( hkeyWksta ); return err; } // // Get the current user's SID string. // //err = NwReadRegValue( // hkeyWksta, // NW_CURRENTUSER_VALUENAME, // &CurrentUser // ); if ( err ) { KdPrint(("NWPROVAU: NwGetCurrentUserRegKey read CurrentUser value unexpected error %lu!\n", err)); (void) RegCloseKey( hkeyWksta ); return err; } (void) RegCloseKey( hkeyWksta ); // // Open HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services // \NWCWorkstation\Parameters\Option // err = RegOpenKeyExW( HKEY_LOCAL_MACHINE, NW_WORKSTATION_OPTION_REGKEY, REG_OPTION_NON_VOLATILE, KEY_READ, &hkeyWksta ); if ( err ) { KdPrint(("NWPROVAU: NwGetCurrentUserRegKey open Parameters\\Option key unexpected error %lu!\n", err)); return err; } // // Open current user's key // err = RegOpenKeyExW( hkeyWksta, CurrentUser, REG_OPTION_NON_VOLATILE, DesiredAccess, phKeyCurrentUser ); if ( err == ERROR_FILE_NOT_FOUND) { DWORD Disposition; // // Create key under NWCWorkstation\Parameters\Option // err = RegCreateKeyExW( hkeyWksta, CurrentUser, 0, WIN31_CLASS, REG_OPTION_NON_VOLATILE, DesiredAccess, NULL, // security attr phKeyCurrentUser, &Disposition ); if ( err == NO_ERROR ) { err = NwLibSetEverybodyPermission( *phKeyCurrentUser, KEY_SET_VALUE ); if ( err != NO_ERROR ) { KdPrint(("NWPROVAU: NwpSaveLogonCredential set security on Option\\%ws key unexpected error %lu!\n", CurrentUser, err)); } } } if ( err ) { KdPrint(("NWPROVAU: NwGetCurrentUserRegKey open or create of Parameters\\Option\\%ws key failed %lu\n", CurrentUser, err)); } (void) RegCloseKey( hkeyWksta ); (void) LocalFree((HLOCAL)CurrentUser) ; return err; } DWORD NwEnumGWDevices( LPDWORD Index, LPBYTE Buffer, DWORD BufferSize, LPDWORD BytesNeeded, LPDWORD EntriesRead ) /*++ Routine Description: This routine enumerates the special gateway devices (redirections) that are cureently in use. Arguments: Index - Point to start enumeration. Should be zero for first call. Buffer - buffer for return data BufferSize - size of buffer in bytes BytesNeeded - number of bytes needed to return all the data EntriesRead - number of entries read Return Value: Returns the appropriate Win32 error. --*/ { DWORD i, err ; LPNETRESOURCE lpNetRes = (LPNETRESOURCE) Buffer ; // // call the implementing routine on server side // RpcTryExcept { err = NwrEnumGWDevices( NULL, Index, Buffer, BufferSize, BytesNeeded, EntriesRead) ; if ( err == NO_ERROR) { // // the change the offsets into real pointers // for (i = 0; i < *EntriesRead; i++) { lpNetRes->lpLocalName = (LPWSTR) (Buffer+(DWORD_PTR)lpNetRes->lpLocalName) ; lpNetRes->lpRemoteName = (LPWSTR) (Buffer+(DWORD_PTR)lpNetRes->lpRemoteName) ; lpNetRes->lpProvider = (LPWSTR) (Buffer+(DWORD_PTR)lpNetRes->lpProvider) ; lpNetRes++ ; } } } RpcExcept(1) { err = NwpMapRpcError( RpcExceptionCode() ); } RpcEndExcept return err ; } DWORD NwAddGWDevice( LPWSTR DeviceName, LPWSTR RemoteName, LPWSTR AccountName, LPWSTR Password, DWORD Flags ) /*++ Routine Description: This routine adds a gateway redirection. Arguments: DeviceName - the drive to redirect RemoteName - the remote network resource to redirect to Flags - supplies the options (eg. UpdateRegistry & make this sticky) Return Value: Returns the appropriate Win32 error. --*/ { DWORD err; RpcTryExcept { err = NwrAddGWDevice( NULL, DeviceName, RemoteName, AccountName, Password, Flags) ; } RpcExcept(1) { err = NwpMapRpcError( RpcExceptionCode() ); } RpcEndExcept return err; } DWORD NwDeleteGWDevice( LPWSTR DeviceName, DWORD Flags ) /*++ Routine Description: This routine deletes a gateway redirection. Arguments: DeviceName - the drive to delete Flags - supplies the options (eg. UpdateRegistry & make this sticky) Return Value: Returns the appropriate Win32 error. --*/ { DWORD err; RpcTryExcept { err = NwrDeleteGWDevice(NULL, DeviceName, Flags) ; } RpcExcept(1) { err = NwpMapRpcError( RpcExceptionCode() ); } RpcEndExcept return err; } DWORD NwQueryGatewayAccount( LPWSTR AccountName, DWORD AccountNameLen, LPDWORD AccountCharsNeeded, LPWSTR Password, DWORD PasswordLen, LPDWORD PasswordCharsNeeded ) /*++ Routine Description: Query the gateway account info. specifically, the Account name and the passeord stored as an LSA secret. Arguments: AccountName - buffer used to return account name AccountNameLen - length of buffer Password - buffer used to return account name PasswordLen - length of buffer Return Value: Returns the appropriate Win32 error. --*/ { DWORD err; RpcTryExcept { if (AccountName && AccountNameLen) *AccountName = 0 ; if (Password && PasswordLen) *Password = 0 ; err = NwrQueryGatewayAccount(NULL, AccountName, AccountNameLen, AccountCharsNeeded, Password, PasswordLen, PasswordCharsNeeded) ; } RpcExcept(1) { err = NwpMapRpcError( RpcExceptionCode() ); } RpcEndExcept return err; } DWORD NwSetGatewayAccount( LPWSTR AccountName, LPWSTR Password ) /*++ Routine Description: Set the account and password to be used for gateway access. Arguments: AccountName - the account (NULL terminated) Password - the password string (NULL terminated) Return Value: Returns the appropriate Win32 error. --*/ { DWORD err; RpcTryExcept { err = NwrSetGatewayAccount( NULL, AccountName, Password); } RpcExcept(1) { err = NwpMapRpcError( RpcExceptionCode() ); } RpcEndExcept return err; } DWORD NwLogonGatewayAccount( LPWSTR AccountName, LPWSTR Password, LPWSTR Server ) /*++ Routine Description: Logon the SYSTEM process with the specified account/password. Arguments: AccountName - the account (NULL terminated) Password - the password string (NULL terminated) Server - the server to authenticate against Return Value: Returns the appropriate Win32 error. --*/ { DWORD err ; LUID SystemId = SYSTEM_LUID ; RpcTryExcept { (void) NwrLogoffUser(NULL, &SystemId); err = NwrLogonUser( NULL, &SystemId, AccountName, Password, Server, NULL, NULL, 0, NW_GATEWAY_PRINT_OPTION_DEFAULT ); } RpcExcept(1) { err = NwpMapRpcError( RpcExceptionCode() ); } RpcEndExcept return err ; } NTSTATUS NwGetUserNameForServer( PUNICODE_STRING ServerName, PUNICODE_STRING UserName ) /*++ Routine Description: Calls the redir to get the User Name used to connect to the server in question. Arguments: ServerName - the server in question UserName - used to return the user name Return Value: Returns the appropriate NTSTATUS --*/ { NTSTATUS Status; WCHAR LocalUserName[NW_MAX_USERNAME_LEN]; ULONG UserNameLen = sizeof(LocalUserName); OBJECT_ATTRIBUTES ObjectAttributes; UNICODE_STRING DriverName; HANDLE RdrHandle = NULL; IO_STATUS_BLOCK IoStatus; // // Initialize variables // RtlInitUnicodeString( &DriverName, DD_NWFS_DEVICE_NAME_U ); InitializeObjectAttributes( &ObjectAttributes, &DriverName, 0, NULL, NULL ); // // open handle to the redir // Status = NtOpenFile( &RdrHandle, FILE_LIST_DIRECTORY | SYNCHRONIZE, &ObjectAttributes, &IoStatus, FILE_SHARE_READ, 0 // open options ); if (!NT_SUCCESS(Status) || !NT_SUCCESS(IoStatus.Status) ) { return( Status ); } // // Call the driver to get use the user name // Status = NtFsControlFile( RdrHandle, NULL, NULL, NULL, &IoStatus, FSCTL_NWR_GET_USERNAME, ServerName->Buffer, ServerName->Length, LocalUserName, UserNameLen ); NtClose(RdrHandle); if (!NT_SUCCESS(Status)) { return(Status); } // // copy the info if it fits. set size required and fail otherwise. // if (UserName->MaximumLength >= IoStatus.Information) { UserName->Length = (USHORT) IoStatus.Information; RtlCopyMemory( UserName->Buffer, LocalUserName, UserNameLen ); Status = STATUS_SUCCESS; } else { UserName->Length = (USHORT) IoStatus.Information; Status = STATUS_BUFFER_TOO_SMALL; } return(Status); } NTSTATUS NwEncryptChallenge( IN PUCHAR Challenge, IN ULONG ObjectId, IN OPTIONAL PUNICODE_STRING ServerName, IN OPTIONAL PUNICODE_STRING Password, OUT PUCHAR ChallengeResponse, OUT OPTIONAL PUCHAR SessionKey ) /*++ Routine Description: Calls the redir to encrypt a challenge Arguments: Challenge - Challenge key ObjectId - User's object ID ServerName - The server to authenticate against Password - Password supplied ChallengeResponse - Used to return the challenge response SessionKey - Used to return the session key Return Value: Returns the appropriate NTSTATUS --*/ { NTSTATUS Status; OBJECT_ATTRIBUTES ObjectAttributes; UNICODE_STRING DriverName; HANDLE RdrHandle = NULL; IO_STATUS_BLOCK IoStatus; PNWR_GET_CHALLENGE_REQUEST ChallengeRequest = NULL; NWR_GET_CHALLENGE_REPLY ChallengeReply; ULONG ChallengeRequestSize; // // Initialize variables // RtlInitUnicodeString( &DriverName, DD_NWFS_DEVICE_NAME_U ); InitializeObjectAttributes( &ObjectAttributes, &DriverName, 0, NULL, NULL ); // // open handle to redirector // Status = NtOpenFile( &RdrHandle, FILE_LIST_DIRECTORY | SYNCHRONIZE, &ObjectAttributes, &IoStatus, FILE_SHARE_READ, 0 // open options ); if (!NT_SUCCESS(Status) || !NT_SUCCESS(IoStatus.Status) ) { return( Status ); } ChallengeRequestSize = sizeof(NWR_GET_CHALLENGE_REQUEST) + ((Password != NULL) ? Password->Length : 0) + ((ServerName != NULL) ? ServerName->Length : 0); ChallengeRequest = (PNWR_GET_CHALLENGE_REQUEST) RtlAllocateHeap( RtlProcessHeap(), 0, ChallengeRequestSize ); if (ChallengeRequest == NULL ) { Status = STATUS_INSUFFICIENT_RESOURCES; goto Cleanup; } // // Marshall the challenge request structure. Only send servername if // password has not been specified. // ChallengeRequest->ObjectId = ObjectId; ChallengeRequest->Flags = 0; // // If both password and servername are present, use the password. // if ((Password != NULL) && (Password->Length != 0)) { ChallengeRequest->ServerNameorPasswordLength = Password->Length; RtlCopyMemory( ChallengeRequest->ServerNameorPassword, Password->Buffer, Password->Length ); ChallengeRequest->Flags = CHALLENGE_FLAGS_PASSWORD; } else if ((ServerName != NULL) && (ServerName->Length != 0)) { ChallengeRequest->ServerNameorPasswordLength = ServerName->Length; RtlCopyMemory( ChallengeRequest->ServerNameorPassword, ServerName->Buffer, ServerName->Length ); ChallengeRequest->Flags = CHALLENGE_FLAGS_SERVERNAME; } RtlCopyMemory( ChallengeRequest->Challenge, Challenge, 8 ); // // Issue FS control to redir to get challenge response // Status = NtFsControlFile( RdrHandle, NULL, NULL, NULL, &IoStatus, FSCTL_NWR_CHALLENGE, ChallengeRequest, ChallengeRequestSize, &ChallengeReply, sizeof(ChallengeReply) ); if (!NT_SUCCESS(Status) || !NT_SUCCESS(IoStatus.Status)) { goto Cleanup; } RtlCopyMemory( ChallengeResponse, ChallengeReply.Challenge, 8 ); if (SessionKey != NULL) { RtlCopyMemory( ChallengeResponse, ChallengeReply.Challenge, 8 ); } Cleanup: if (RdrHandle != NULL) { NtClose(RdrHandle); } if (ChallengeRequest != NULL) { RtlFreeHeap( RtlProcessHeap(), 0, ChallengeRequest ); } return(Status); }