windows-nt/Source/XPSP1/NT/ds/nw/svcdlls/nwwks/lib/misc.c
2020-09-26 16:20:57 +08:00

786 lines
18 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
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;
}