|
|
/*++
Copyright (c) 1993 Microsoft Corporation
Module Name:
api.c
Abstract:
This module contains misc APIs that are used by the NWC wksta.
Author:
ChuckC 2-Mar-94 Created
Revision History:
--*/
#include <stdlib.h>
#include <nt.h>
#include <ntrtl.h>
#include <nturtl.h>
#include <windows.h>
#include <nwcons.h>
#include <nwmisc.h>
#include <nwapi32.h>
#include "nwstatus.h"
#include "nwevent.h"
DWORD NwMapStatus( IN NTSTATUS NtStatus );
DWORD NwOpenPreferredServer( PHANDLE ServerHandle );
NTSTATUS NwOpenHandle( IN PUNICODE_STRING ObjectName, IN BOOL ValidateFlag, OUT PHANDLE ObjectHandle );
NTSTATUS NwCallNtOpenFile( OUT PHANDLE ObjectHandle, IN ACCESS_MASK DesiredAccess, IN PUNICODE_STRING ObjectName, IN ULONG OpenOptions );
//
// list of error mappings known for E3H calls. we do not have a single list
// because Netware reuses the numbers depending on call.
//
typedef struct _ERROR_MAP_ENTRY { UCHAR NetError; NTSTATUS ResultingStatus; } ERROR_MAP_ENTRY ;
ERROR_MAP_ENTRY Error_Map_Bindery[] = {
//
// NetWare specific error mappings. Specific to E3H.
//
{ 1, STATUS_DISK_FULL }, {128, STATUS_SHARING_VIOLATION }, {129, STATUS_INSUFF_SERVER_RESOURCES }, {130, STATUS_ACCESS_DENIED }, {131, STATUS_DATA_ERROR }, {132, STATUS_ACCESS_DENIED }, {133, STATUS_ACCESS_DENIED }, {134, STATUS_ACCESS_DENIED }, {135, STATUS_OBJECT_NAME_INVALID }, {136, STATUS_INVALID_HANDLE }, {137, STATUS_ACCESS_DENIED }, {138, STATUS_ACCESS_DENIED }, {139, STATUS_ACCESS_DENIED }, {140, STATUS_ACCESS_DENIED }, {141, STATUS_SHARING_VIOLATION }, {142, STATUS_SHARING_VIOLATION }, {143, STATUS_ACCESS_DENIED }, {144, STATUS_ACCESS_DENIED }, {145, STATUS_OBJECT_NAME_COLLISION }, {146, STATUS_OBJECT_NAME_COLLISION }, {147, STATUS_ACCESS_DENIED }, {148, STATUS_ACCESS_DENIED }, {150, STATUS_INSUFF_SERVER_RESOURCES }, {151, STATUS_NO_SPOOL_SPACE }, {152, STATUS_NO_SUCH_DEVICE }, {153, STATUS_DISK_FULL }, {154, STATUS_NOT_SAME_DEVICE }, {155, STATUS_INVALID_HANDLE }, {156, STATUS_OBJECT_PATH_NOT_FOUND }, {157, STATUS_INSUFF_SERVER_RESOURCES }, {158, STATUS_OBJECT_PATH_INVALID }, {159, STATUS_SHARING_VIOLATION }, {160, STATUS_DIRECTORY_NOT_EMPTY }, {161, STATUS_DATA_ERROR }, {162, STATUS_SHARING_VIOLATION }, {192, STATUS_ACCESS_DENIED }, {198, STATUS_ACCESS_DENIED }, {211, STATUS_ACCESS_DENIED }, {212, STATUS_PRINT_QUEUE_FULL }, {213, STATUS_PRINT_CANCELLED }, {214, STATUS_ACCESS_DENIED }, {215, STATUS_PASSWORD_RESTRICTION }, {216, STATUS_PASSWORD_RESTRICTION }, {220, STATUS_ACCOUNT_DISABLED }, {222, STATUS_PASSWORD_EXPIRED }, {223, STATUS_PASSWORD_EXPIRED }, {239, STATUS_OBJECT_NAME_INVALID }, {240, STATUS_OBJECT_NAME_INVALID }, {251, STATUS_INVALID_PARAMETER }, {252, STATUS_NO_MORE_ENTRIES }, {253, STATUS_FILE_LOCK_CONFLICT }, {254, STATUS_FILE_LOCK_CONFLICT }, {255, STATUS_UNSUCCESSFUL} };
ERROR_MAP_ENTRY Error_Map_General[] = { { 1, STATUS_DISK_FULL }, {128, STATUS_SHARING_VIOLATION }, {129, STATUS_INSUFF_SERVER_RESOURCES }, {130, STATUS_ACCESS_DENIED }, {131, STATUS_DATA_ERROR }, {132, STATUS_ACCESS_DENIED }, {133, STATUS_ACCESS_DENIED }, {134, STATUS_ACCESS_DENIED }, {135, STATUS_OBJECT_NAME_INVALID }, {136, STATUS_INVALID_HANDLE }, {137, STATUS_ACCESS_DENIED }, {138, STATUS_ACCESS_DENIED }, {139, STATUS_ACCESS_DENIED }, {140, STATUS_ACCESS_DENIED }, {141, STATUS_SHARING_VIOLATION }, {142, STATUS_SHARING_VIOLATION }, {143, STATUS_ACCESS_DENIED }, {144, STATUS_ACCESS_DENIED }, {145, STATUS_OBJECT_NAME_COLLISION }, {146, STATUS_OBJECT_NAME_COLLISION }, {147, STATUS_ACCESS_DENIED }, {148, STATUS_ACCESS_DENIED }, {150, STATUS_INSUFF_SERVER_RESOURCES }, {151, STATUS_NO_SPOOL_SPACE }, {152, STATUS_NO_SUCH_DEVICE }, {153, STATUS_DISK_FULL }, {154, STATUS_NOT_SAME_DEVICE }, {155, STATUS_INVALID_HANDLE }, {156, STATUS_OBJECT_PATH_NOT_FOUND }, {157, STATUS_INSUFF_SERVER_RESOURCES }, {158, STATUS_OBJECT_PATH_INVALID }, {159, STATUS_SHARING_VIOLATION }, {160, STATUS_DIRECTORY_NOT_EMPTY }, {161, STATUS_DATA_ERROR }, {162, STATUS_SHARING_VIOLATION }, {192, STATUS_ACCESS_DENIED }, {198, STATUS_ACCESS_DENIED }, {211, STATUS_ACCESS_DENIED }, {212, STATUS_PRINT_QUEUE_FULL }, {213, STATUS_PRINT_CANCELLED }, {214, STATUS_ACCESS_DENIED }, {215, STATUS_DEVICE_BUSY }, {216, STATUS_DEVICE_DOES_NOT_EXIST }, {220, STATUS_ACCOUNT_DISABLED }, {222, STATUS_PASSWORD_EXPIRED }, {223, STATUS_PASSWORD_EXPIRED }, {239, STATUS_OBJECT_NAME_INVALID }, {240, STATUS_OBJECT_NAME_INVALID }, {251, STATUS_INVALID_PARAMETER }, {252, STATUS_NO_MORE_ENTRIES }, {253, STATUS_FILE_LOCK_CONFLICT }, {254, STATUS_FILE_LOCK_CONFLICT }, {255, STATUS_UNSUCCESSFUL} };
#define NUM_ERRORS(x) (sizeof(x)/sizeof(x[0]))
DWORD NwMapBinderyCompletionCode( IN NTSTATUS NtStatus ) /*++
Routine Description:
This function takes a bindery completion code embedded in an NT status code and maps it to the appropriate Win32 error code. Used specifically for E3H operations.
Arguments:
NtStatus - Supplies the NT status (that contains the code in low 16 bits)
Return Value:
Returns the appropriate Win32 error.
--*/ { DWORD i; UCHAR code ;
//
// A small optimization for the most common case.
//
if (NtStatus == STATUS_SUCCESS) return NO_ERROR;
//
// Map connection errors specially.
//
if ( ( (NtStatus & 0xFFFF0000) == 0xC0010000) && ( (NtStatus & 0xFF00) != 0 ) ) { return ERROR_UNEXP_NET_ERR; }
//
// if facility code not set, assume it is NT Status
//
if ( (NtStatus & 0xFFFF0000) != 0xC0010000) return RtlNtStatusToDosError(NtStatus);
code = (UCHAR)(NtStatus & 0x000000FF); for (i = 0; i < NUM_ERRORS(Error_Map_Bindery); i++) { if (Error_Map_Bindery[i].NetError == code) return( NwMapStatus(Error_Map_Bindery[i].ResultingStatus)); }
//
// if cannot find let NwMapStatus do its best
//
return NwMapStatus(NtStatus); }
DWORD NwMapStatus( IN NTSTATUS NtStatus ) /*++
Routine Description:
This function takes an NT status code and maps it to the appropriate Win32 error code. If facility code is set, assume it is NW specific
Arguments:
NtStatus - Supplies the NT status.
Return Value:
Returns the appropriate Win32 error.
--*/ { DWORD i; UCHAR code ;
//
// A small optimization for the most common case.
//
if (NtStatus == STATUS_SUCCESS) return NO_ERROR;
//
// Map connection errors specially.
//
if ( ( (NtStatus & 0xFFFF0000) == 0xC0010000) && ( (NtStatus & 0xFF00) != 0 ) ) { return ERROR_UNEXP_NET_ERR; }
//
// if facility code set, assume it is NW Completion code
//
if ( (NtStatus & 0xFFFF0000) == 0xC0010000) { code = (UCHAR)(NtStatus & 0x000000FF); for (i = 0; i < NUM_ERRORS(Error_Map_General); i++) { if (Error_Map_General[i].NetError == code) { //
// map it to NTSTATUS and then drop thru to map to Win32
//
NtStatus = Error_Map_General[i].ResultingStatus ; break ; } } }
switch (NtStatus) { case STATUS_OBJECT_NAME_COLLISION: return ERROR_ALREADY_ASSIGNED;
case STATUS_OBJECT_NAME_NOT_FOUND: return ERROR_NOT_CONNECTED;
case STATUS_IMAGE_ALREADY_LOADED: case STATUS_REDIRECTOR_STARTED: return ERROR_SERVICE_ALREADY_RUNNING;
case STATUS_REDIRECTOR_HAS_OPEN_HANDLES: return ERROR_REDIRECTOR_HAS_OPEN_HANDLES;
case STATUS_NO_MORE_FILES: case STATUS_NO_MORE_ENTRIES: return WN_NO_MORE_ENTRIES;
case STATUS_MORE_ENTRIES: return WN_MORE_DATA;
case STATUS_CONNECTION_IN_USE: return ERROR_DEVICE_IN_USE;
case NWRDR_PASSWORD_HAS_EXPIRED: return NW_PASSWORD_HAS_EXPIRED;
case STATUS_INVALID_DEVICE_REQUEST: return ERROR_CONNECTION_INVALID;
default: return RtlNtStatusToDosError(NtStatus); } }
DWORD NwGetGraceLoginCount( LPWSTR Server, LPWSTR UserName, LPDWORD lpResult ) /*++
Routine Description:
Get the number grace logins for a user.
Arguments:
Server - the server to authenticate against
UserName - the user account
Return Value:
Returns the appropriate Win32 error.
--*/ { DWORD status ; HANDLE hConn ; CHAR UserNameO[NW_MAX_USERNAME_LEN+1] ; BYTE LoginControl[128] ; BYTE MoreFlags, PropFlags ;
//
// skip the backslashes if present
//
if (*Server == L'\\') Server += 2 ;
//
// attach to the NW server
//
if (status = NWAttachToFileServerW(Server, 0, &hConn)) { return status ; }
//
// convert unicode UserName to OEM, and then call the NCP
//
if ( !WideCharToMultiByte(CP_OEMCP, 0, UserName, -1, UserNameO, sizeof(UserNameO), NULL, NULL)) { status = GetLastError() ; } else { status = NWReadPropertyValue( hConn, UserNameO, OT_USER, "LOGIN_CONTROL", 1, LoginControl, &MoreFlags, &PropFlags) ; }
//
// dont need these anymore. if any error, bag out
//
(void) NWDetachFromFileServer(hConn) ;
if (status == NO_ERROR) *lpResult = (DWORD) LoginControl[7] ;
return status ; }
WORD NwParseNdsUncPath( IN OUT LPWSTR * Result, IN LPWSTR ContainerName, IN ULONG flag ) /*++
Routine Description:
This function is used to extract either the tree name, fully distinguished name path to an object, or object name, out of a complete NDS UNC path.
Arguments:
Result - parsed result buffer. ContainerName - Complete NDS UNC path that is to be parsed. flag - Flag indicating operation to be performed:
PARSE_NDS_GET_TREE_NAME PARSE_NDS_GET_PATH_NAME PARSE_NDS_GET_OBJECT_NAME
Return Value:
Length of string in result buffer. If error occured, 0 is returned.
--*/ // NwParseNdsUncPath
{ unsigned short length = 2; unsigned short totalLength = (USHORT) wcslen( ContainerName );
if ( totalLength < 2 ) return 0;
//
// First get length to indicate the character in the string that indicates the
// "\" in between the tree name and the rest of the UNC path.
//
// Example: \\<tree name>\<path to object>[\|.]<object>
// ^
// |
//
while ( length < totalLength && ContainerName[length] != L'\\' ) { length++; }
if ( flag == PARSE_NDS_GET_TREE_NAME ) { *Result = (LPWSTR) ( ContainerName + 2 );
return ( length - 2 ) * sizeof( WCHAR ); // Take off 2 for the two \\'s
}
if ( flag == PARSE_NDS_GET_PATH_NAME && length == totalLength ) { *Result = ContainerName;
return 0; }
if ( flag == PARSE_NDS_GET_PATH_NAME ) { *Result = ContainerName + length + 1;
return ( totalLength - length - 1 ) * sizeof( WCHAR ); }
*Result = ContainerName + totalLength - 1; length = 1;
while ( **Result != L'\\' ) { *Result--; length++; }
*Result++; length--;
return length * sizeof( WCHAR ); }
DWORD NwOpenAServer( PWCHAR pwszServName, PHANDLE ServerHandle, BOOL fVerify ) /*++
Routine Description:
This routine opens a handle to a server.
Arguments:
ServerHandle - Receives an opened handle to the preferred or nearest server.
Return Value:
NO_ERROR or reason for failure.
--*/ { UNICODE_STRING AServer; WCHAR wszName[sizeof(NW_RDR_NAME) + (48 * sizeof(WCHAR))]; DWORD wLen;
if(!pwszServName) { pwszServName = NW_RDR_PREFERRED_SERVER; RtlInitUnicodeString(&AServer, wszName); } else { wLen = wcslen(pwszServName); if(wLen > 47) { return(WSAEFAULT); } wcscpy(wszName, NW_RDR_NAME); wcscat(wszName, pwszServName); RtlInitUnicodeString(&AServer, wszName); }
return RtlNtStatusToDosError( NwOpenHandle(&AServer, fVerify, ServerHandle) );
}
DWORD NwOpenPreferredServer( PHANDLE ServerHandle ) /*++
Routine Description:
This routine opens a handle to the preferred server. If the preferred server has not been specified, a handle to the nearest server is opened instead.
Arguments:
ServerHandle - Receives an opened handle to the preferred or nearest server.
Return Value:
NO_ERROR or reason for failure.
--*/ { UNICODE_STRING PreferredServer;
//
// The NetWare redirector recognizes "*" to mean the preferred
// or nearest server.
//
RtlInitUnicodeString(&PreferredServer, NW_RDR_PREFERRED_SERVER);
return RtlNtStatusToDosError( NwOpenHandle(&PreferredServer, FALSE, ServerHandle) );
}
NTSTATUS NwOpenHandle( IN PUNICODE_STRING ObjectName, IN BOOL ValidateFlag, OUT PHANDLE ObjectHandle ) /*++
Routine Description:
This function opens a handle to \Device\Nwrdr\<ObjectName>.
Arguments:
ObjectName - Supplies the name of the redirector object to open.
ValidateFlag - Supplies a flag which if TRUE, opens the handle to the object by validating the default user account.
ObjectHandle - Receives a pointer to the opened object handle.
Return Value:
STATUS_SUCCESS or reason for failure.
--*/ { ACCESS_MASK DesiredAccess = SYNCHRONIZE;
if (ValidateFlag) {
//
// The redirector only authenticates the default user credential
// if the remote resource is opened with write access.
//
DesiredAccess |= FILE_WRITE_DATA; }
*ObjectHandle = NULL;
return NwCallNtOpenFile( ObjectHandle, DesiredAccess, ObjectName, FILE_SYNCHRONOUS_IO_NONALERT );
}
NTSTATUS NwCallNtOpenFile( OUT PHANDLE ObjectHandle, IN ACCESS_MASK DesiredAccess, IN PUNICODE_STRING ObjectName, IN ULONG OpenOptions ) {
NTSTATUS ntstatus; IO_STATUS_BLOCK IoStatusBlock; OBJECT_ATTRIBUTES ObjectAttributes;
InitializeObjectAttributes( &ObjectAttributes, ObjectName, OBJ_CASE_INSENSITIVE, NULL, NULL );
ntstatus = NtOpenFile( ObjectHandle, DesiredAccess, &ObjectAttributes, &IoStatusBlock, FILE_SHARE_VALID_FLAGS, OpenOptions );
if (!NT_ERROR(ntstatus) && !NT_INFORMATION(ntstatus) && !NT_WARNING(ntstatus)) {
ntstatus = IoStatusBlock.Status;
}
return ntstatus; }
BOOL NwConvertToUnicode( OUT LPWSTR *UnicodeOut, IN LPSTR OemIn ) /*++
Routine Description:
This function converts the given OEM string to a Unicode string. The Unicode string is returned in a buffer allocated by this function and must be freed with LocalFree.
Arguments:
UnicodeOut - Receives a pointer to the Unicode string.
OemIn - This is a pointer to an ansi string that is to be converted.
Return Value:
TRUE - The conversion was successful.
FALSE - The conversion was unsuccessful. In this case a buffer for the unicode string was not allocated.
--*/ { NTSTATUS ntstatus; DWORD BufSize; UNICODE_STRING UnicodeString; OEM_STRING OemString;
//
// Allocate a buffer for the unicode string.
//
BufSize = (strlen(OemIn) + 1) * sizeof(WCHAR);
*UnicodeOut = LocalAlloc(LMEM_ZEROINIT, BufSize);
if (*UnicodeOut == NULL) { KdPrint(("NWWORKSTATION: NwConvertToUnicode:LocalAlloc failed %lu\n", GetLastError())); return FALSE; }
//
// Initialize the string structures
//
RtlInitAnsiString((PANSI_STRING) &OemString, OemIn);
UnicodeString.Buffer = *UnicodeOut; UnicodeString.MaximumLength = (USHORT) BufSize; UnicodeString.Length = 0;
//
// Call the conversion function.
//
ntstatus = RtlOemStringToUnicodeString( &UnicodeString, // Destination
&OemString, // Source
FALSE // Allocate the destination
);
if (ntstatus != STATUS_SUCCESS) {
KdPrint(("NWWORKSTATION: NwConvertToUnicode: RtlOemStringToUnicodeString failure x%08lx\n", ntstatus));
(void) LocalFree((HLOCAL) *UnicodeOut); *UnicodeOut = NULL; return FALSE; }
*UnicodeOut = UnicodeString.Buffer;
return TRUE;
}
|