You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1010 lines
32 KiB
1010 lines
32 KiB
/*++
|
|
|
|
Copyright (c) 1999 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
utils.c
|
|
|
|
Abstract:
|
|
|
|
Grab bag of functions used by the web dav mini-redir client service.
|
|
|
|
Author:
|
|
|
|
Andy Herron (andyhe) 29-Mar-1999
|
|
|
|
Environment:
|
|
|
|
User Mode - Win32
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "pch.h"
|
|
#pragma hdrstop
|
|
|
|
#include <ntumrefl.h>
|
|
#include <usrmddav.h>
|
|
#include "global.h"
|
|
|
|
//
|
|
// These tables translate wininet codes to the closest ntstatus codes. There are
|
|
// two because there are some errors in wininet which come from ftp and gopher
|
|
// which are not relevant to us.
|
|
//
|
|
typedef struct tagHTTP_TO_NTSTATUS_MAPPING {
|
|
DWORD dwHttpError;
|
|
NTSTATUS Status;
|
|
} HTTP_TO_NTSTATUS_MAPPING;
|
|
|
|
typedef struct tagWIN32_TO_NTSTATUS_MAPPING {
|
|
DWORD dwWin32Error;
|
|
NTSTATUS NtStatus;
|
|
} WIN32_TO_NTSTATUS_MAPPING;
|
|
|
|
HTTP_TO_NTSTATUS_MAPPING rgHttpToNtstatus1[] = {
|
|
ERROR_INTERNET_OUT_OF_HANDLES ,STATUS_INSUFFICIENT_RESOURCES // (INTERNET_ERROR_BASE + 1)
|
|
,ERROR_INTERNET_TIMEOUT ,STATUS_BAD_NETWORK_PATH // (INTERNET_ERROR_BASE + 2)
|
|
,ERROR_INTERNET_EXTENDED_ERROR ,STATUS_UNSUCCESSFUL // (INTERNET_ERROR_BASE + 3)
|
|
,ERROR_INTERNET_INTERNAL_ERROR ,STATUS_INTERNAL_ERROR // (INTERNET_ERROR_BASE + 4)
|
|
,ERROR_INTERNET_INVALID_URL ,STATUS_OBJECT_NAME_INVALID // (INTERNET_ERROR_BASE + 5)
|
|
,ERROR_INTERNET_UNRECOGNIZED_SCHEME ,STATUS_OBJECT_NAME_INVALID // (INTERNET_ERROR_BASE + 6)
|
|
,ERROR_INTERNET_NAME_NOT_RESOLVED ,STATUS_BAD_NETWORK_PATH // (INTERNET_ERROR_BASE + 7)
|
|
,ERROR_INTERNET_PROTOCOL_NOT_FOUND ,STATUS_OBJECT_TYPE_MISMATCH // (INTERNET_ERROR_BASE + 8)
|
|
,ERROR_INTERNET_INVALID_OPTION ,STATUS_INVALID_PARAMETER // (INTERNET_ERROR_BASE + 9)
|
|
,ERROR_INTERNET_BAD_OPTION_LENGTH ,STATUS_INVALID_PARAMETER // (INTERNET_ERROR_BASE + 10)
|
|
,ERROR_INTERNET_OPTION_NOT_SETTABLE ,STATUS_INVALID_PARAMETER // (INTERNET_ERROR_BASE + 11)
|
|
,ERROR_INTERNET_SHUTDOWN ,STATUS_UNSUCCESSFUL // (INTERNET_ERROR_BASE + 12)
|
|
,ERROR_INTERNET_INCORRECT_USER_NAME ,STATUS_LOGON_FAILURE // (INTERNET_ERROR_BASE + 13)
|
|
,ERROR_INTERNET_INCORRECT_PASSWORD ,STATUS_LOGON_FAILURE // (INTERNET_ERROR_BASE + 14)
|
|
,ERROR_INTERNET_LOGIN_FAILURE ,STATUS_LOGON_FAILURE // (INTERNET_ERROR_BASE + 15)
|
|
,ERROR_INTERNET_INVALID_OPERATION ,STATUS_INVALID_DEVICE_REQUEST // (INTERNET_ERROR_BASE + 16)
|
|
,ERROR_INTERNET_OPERATION_CANCELLED ,STATUS_CANCELLED // (INTERNET_ERROR_BASE + 17)
|
|
,ERROR_INTERNET_INCORRECT_HANDLE_TYPE ,STATUS_INVALID_HANDLE // (INTERNET_ERROR_BASE + 18)
|
|
,ERROR_INTERNET_INCORRECT_HANDLE_STATE ,STATUS_INVALID_HANDLE // (INTERNET_ERROR_BASE + 19)
|
|
,ERROR_INTERNET_NOT_PROXY_REQUEST ,STATUS_INVALID_PARAMETER // (INTERNET_ERROR_BASE + 20)
|
|
,ERROR_INTERNET_REGISTRY_VALUE_NOT_FOUND ,STATUS_OBJECT_NAME_NOT_FOUND // (INTERNET_ERROR_BASE + 21)
|
|
,ERROR_INTERNET_BAD_REGISTRY_PARAMETER ,STATUS_INVALID_PARAMETER // (INTERNET_ERROR_BASE + 22)
|
|
,ERROR_INTERNET_NO_DIRECT_ACCESS ,STATUS_UNSUCCESSFUL // (INTERNET_ERROR_BASE + 23)
|
|
,ERROR_INTERNET_NO_CONTEXT ,STATUS_UNSUCCESSFUL // (INTERNET_ERROR_BASE + 24)
|
|
,ERROR_INTERNET_NO_CALLBACK ,STATUS_UNSUCCESSFUL // (INTERNET_ERROR_BASE + 25)
|
|
,ERROR_INTERNET_REQUEST_PENDING ,STATUS_PENDING // (INTERNET_ERROR_BASE + 26)
|
|
,ERROR_INTERNET_INCORRECT_FORMAT ,STATUS_INVALID_NETWORK_RESPONSE // (INTERNET_ERROR_BASE + 27)
|
|
,ERROR_INTERNET_ITEM_NOT_FOUND ,STATUS_OBJECT_PATH_NOT_FOUND // (INTERNET_ERROR_BASE + 28)
|
|
,ERROR_INTERNET_CANNOT_CONNECT ,STATUS_BAD_NETWORK_PATH // (INTERNET_ERROR_BASE + 29)
|
|
,ERROR_INTERNET_CONNECTION_ABORTED ,STATUS_REQUEST_ABORTED // (INTERNET_ERROR_BASE + 30)
|
|
,ERROR_INTERNET_CONNECTION_RESET ,STATUS_CONNECTION_RESET // (INTERNET_ERROR_BASE + 31)
|
|
,ERROR_INTERNET_FORCE_RETRY ,STATUS_RETRY // (INTERNET_ERROR_BASE + 32)
|
|
,ERROR_INTERNET_INVALID_PROXY_REQUEST ,STATUS_INVALID_PARAMETER // (INTERNET_ERROR_BASE + 33)
|
|
,ERROR_INTERNET_NEED_UI ,STATUS_ACCESS_DENIED // (INTERNET_ERROR_BASE + 34)
|
|
};
|
|
|
|
HTTP_TO_NTSTATUS_MAPPING rgHttpToNtstatus2[] = {
|
|
ERROR_HTTP_HEADER_NOT_FOUND ,STATUS_INVALID_NETWORK_RESPONSE // (INTERNET_ERROR_BASE + 150)
|
|
,ERROR_HTTP_DOWNLEVEL_SERVER ,STATUS_INVALID_NETWORK_RESPONSE // (INTERNET_ERROR_BASE + 151)
|
|
,ERROR_HTTP_INVALID_SERVER_RESPONSE ,STATUS_INVALID_NETWORK_RESPONSE // (INTERNET_ERROR_BASE + 152)
|
|
,ERROR_HTTP_INVALID_HEADER ,STATUS_INVALID_NETWORK_RESPONSE // (INTERNET_ERROR_BASE + 153)
|
|
,ERROR_HTTP_INVALID_QUERY_REQUEST ,STATUS_INVALID_PARAMETER // (INTERNET_ERROR_BASE + 154)
|
|
,ERROR_HTTP_HEADER_ALREADY_EXISTS ,STATUS_INVALID_PARAMETER // (INTERNET_ERROR_BASE + 155)
|
|
,ERROR_HTTP_REDIRECT_FAILED ,STATUS_HOST_UNREACHABLE // (INTERNET_ERROR_BASE + 156)
|
|
,ERROR_INTERNET_SECURITY_CHANNEL_ERROR ,STATUS_INTERNAL_ERROR // (INTERNET_ERROR_BASE + 157)
|
|
,ERROR_INTERNET_UNABLE_TO_CACHE_FILE ,STATUS_INTERNAL_ERROR // (INTERNET_ERROR_BASE + 158)
|
|
,ERROR_INTERNET_TCPIP_NOT_INSTALLED ,STATUS_INTERNAL_ERROR // (INTERNET_ERROR_BASE + 159)
|
|
,ERROR_HTTP_NOT_REDIRECTED ,STATUS_INTERNAL_ERROR // (INTERNET_ERROR_BASE + 160)
|
|
,ERROR_HTTP_COOKIE_NEEDS_CONFIRMATION ,STATUS_INTERNAL_ERROR // (INTERNET_ERROR_BASE + 161)
|
|
,ERROR_HTTP_COOKIE_DECLINED ,STATUS_INTERNAL_ERROR // (INTERNET_ERROR_BASE + 162)
|
|
,ERROR_INTERNET_DISCONNECTED ,STATUS_CONNECTION_DISCONNECTED // (INTERNET_ERROR_BASE + 163)
|
|
,ERROR_INTERNET_SERVER_UNREACHABLE ,STATUS_HOST_UNREACHABLE // (INTERNET_ERROR_BASE + 164)
|
|
,ERROR_INTERNET_PROXY_SERVER_UNREACHABLE ,STATUS_HOST_UNREACHABLE // (INTERNET_ERROR_BASE + 165)
|
|
,ERROR_INTERNET_BAD_AUTO_PROXY_SCRIPT ,STATUS_DEVICE_CONFIGURATION_ERROR// (INTERNET_ERROR_BASE + 166)
|
|
,ERROR_INTERNET_UNABLE_TO_DOWNLOAD_SCRIPT ,STATUS_INTERNAL_ERROR // (INTERNET_ERROR_BASE + 167)
|
|
,ERROR_HTTP_REDIRECT_NEEDS_CONFIRMATION ,STATUS_NETWORK_SESSION_EXPIRED // (INTERNET_ERROR_BASE + 168)
|
|
,ERROR_INTERNET_SEC_INVALID_CERT ,STATUS_ACCESS_DENIED // (INTERNET_ERROR_BASE + 169)
|
|
,ERROR_INTERNET_SEC_CERT_REVOKED ,STATUS_ACCESS_DENIED // (INTERNET_ERROR_BASE + 170)
|
|
};
|
|
|
|
WIN32_TO_NTSTATUS_MAPPING rgWin32ToNtStatus [] = {
|
|
|
|
ERROR_SUCCESS, STATUS_SUCCESS // 0L
|
|
|
|
,ERROR_INVALID_FUNCTION, STATUS_NOT_IMPLEMENTED // 1L
|
|
|
|
,ERROR_FILE_NOT_FOUND, STATUS_OBJECT_NAME_NOT_FOUND // 2L
|
|
|
|
,ERROR_PATH_NOT_FOUND, STATUS_OBJECT_PATH_NOT_FOUND // 3L
|
|
|
|
,ERROR_TOO_MANY_OPEN_FILES, STATUS_TOO_MANY_OPENED_FILES // 4L
|
|
|
|
,ERROR_ACCESS_DENIED, STATUS_ACCESS_DENIED // 5L
|
|
|
|
,ERROR_INVALID_HANDLE, STATUS_INVALID_HANDLE // 6L
|
|
|
|
,ERROR_ARENA_TRASHED, STATUS_UNSUCCESSFUL // 7L
|
|
|
|
,ERROR_NOT_ENOUGH_MEMORY, STATUS_INSUFFICIENT_RESOURCES // 8L
|
|
|
|
,ERROR_INVALID_BLOCK, STATUS_UNSUCCESSFUL // 9L
|
|
|
|
,ERROR_BAD_ENVIRONMENT, STATUS_UNSUCCESSFUL // 10L
|
|
|
|
,ERROR_BAD_FORMAT, STATUS_UNSUCCESSFUL // 11L
|
|
|
|
,ERROR_INVALID_ACCESS, STATUS_UNSUCCESSFUL // 12L
|
|
|
|
,ERROR_INVALID_DATA, STATUS_UNSUCCESSFUL // 13L
|
|
|
|
,ERROR_OUTOFMEMORY, STATUS_UNSUCCESSFUL // 14L
|
|
|
|
,ERROR_INVALID_DRIVE, STATUS_UNSUCCESSFUL // 15L
|
|
|
|
,ERROR_CURRENT_DIRECTORY, STATUS_UNSUCCESSFUL // 16L
|
|
|
|
,ERROR_NOT_SAME_DEVICE, STATUS_UNSUCCESSFUL // 17L
|
|
|
|
,ERROR_NO_MORE_FILES, STATUS_UNSUCCESSFUL // 18L
|
|
|
|
,ERROR_WRITE_PROTECT, STATUS_UNSUCCESSFUL // 19L
|
|
|
|
,ERROR_BAD_UNIT, STATUS_UNSUCCESSFUL // 20L
|
|
|
|
,ERROR_NOT_READY, STATUS_UNSUCCESSFUL // 21L
|
|
|
|
,ERROR_BAD_COMMAND, STATUS_UNSUCCESSFUL // 22L
|
|
|
|
,ERROR_CRC, STATUS_UNSUCCESSFUL // 23L
|
|
|
|
,ERROR_BAD_LENGTH, STATUS_UNSUCCESSFUL // 24L
|
|
|
|
,ERROR_SEEK, STATUS_UNSUCCESSFUL // 25L
|
|
|
|
,ERROR_NOT_DOS_DISK, STATUS_UNSUCCESSFUL // 26L
|
|
|
|
,ERROR_SECTOR_NOT_FOUND, STATUS_UNSUCCESSFUL // 27L
|
|
|
|
,ERROR_OUT_OF_PAPER, STATUS_UNSUCCESSFUL // 28L
|
|
|
|
,ERROR_WRITE_FAULT, STATUS_UNSUCCESSFUL // 29L
|
|
|
|
,ERROR_READ_FAULT, STATUS_UNSUCCESSFUL // 30L
|
|
|
|
,ERROR_GEN_FAILURE, STATUS_UNSUCCESSFUL // 31L
|
|
|
|
,ERROR_SHARING_VIOLATION, STATUS_SHARING_VIOLATION // 32L
|
|
|
|
,ERROR_LOCK_VIOLATION, STATUS_LOCK_NOT_GRANTED // 33L
|
|
|
|
,ERROR_WRONG_DISK, STATUS_UNSUCCESSFUL // 34L
|
|
|
|
,0,0 // 35L
|
|
|
|
,ERROR_SHARING_BUFFER_EXCEEDED, STATUS_UNSUCCESSFUL // 36L
|
|
|
|
,0,0 // 37L
|
|
|
|
,ERROR_HANDLE_EOF, STATUS_END_OF_FILE // 38L
|
|
|
|
,ERROR_HANDLE_DISK_FULL, STATUS_UNSUCCESSFUL // 39L
|
|
|
|
};
|
|
|
|
//
|
|
// Implementation of functions begins here.
|
|
//
|
|
|
|
DWORD
|
|
ReadDWord(
|
|
HKEY KeyHandle,
|
|
LPTSTR lpValueName,
|
|
DWORD DefaultValue
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Read a DWORD value from the registry. If there is a problem then
|
|
return the default value.
|
|
|
|
Arguments:
|
|
|
|
KeyHandle - Handle of the key (value) being read.
|
|
|
|
lpValueName - The value name.
|
|
|
|
DefaultValue - The default value to return, if the name does not exists as
|
|
a value of the key handle.
|
|
|
|
Return Value:
|
|
|
|
Win32 error status.
|
|
|
|
--*/
|
|
{
|
|
DWORD Value;
|
|
DWORD ValueSize = sizeof(Value);
|
|
DWORD ValueType;
|
|
|
|
if ((KeyHandle) &&
|
|
(RegQueryValueEx(KeyHandle,
|
|
lpValueName,
|
|
0,
|
|
&ValueType,
|
|
(PUCHAR)&Value,
|
|
&ValueSize ) == ERROR_SUCCESS )) {
|
|
|
|
return Value;
|
|
} else {
|
|
return DefaultValue;
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
UpdateServiceStatus (
|
|
DWORD dwState
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routines updates the service status.
|
|
|
|
Arguments:
|
|
|
|
dwState - The state the service has to be updated to.
|
|
|
|
Return Value:
|
|
|
|
none.
|
|
|
|
--*/
|
|
{
|
|
if (g_registeredService) {
|
|
ASSERT (g_hStatus);
|
|
g_status.dwCurrentState = dwState;
|
|
SetServiceStatus(g_hStatus, &g_status);
|
|
} else {
|
|
g_status.dwCurrentState = dwState;
|
|
}
|
|
}
|
|
|
|
|
|
NET_API_STATUS
|
|
WsLoadRedir(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This loads, starts, and configures the kernel mini-redir. If the redir
|
|
is already loaded or started, it is not a fatal error.
|
|
|
|
Arguments:
|
|
|
|
none.
|
|
|
|
Return Value:
|
|
|
|
Win32 error status.
|
|
|
|
--*/
|
|
{
|
|
NET_API_STATUS err = ERROR_SUCCESS;
|
|
NTSTATUS NtStatus = STATUS_SUCCESS;
|
|
UNICODE_STRING DeviceName;
|
|
IO_STATUS_BLOCK IoStatusBlock;
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
BOOL driverAlreadyLoaded = FALSE;
|
|
|
|
err = WsLoadDriver(DAVCLIENT_DRIVER);
|
|
if (err == ERROR_SERVICE_ALREADY_RUNNING) {
|
|
driverAlreadyLoaded = TRUE;
|
|
err = ERROR_SUCCESS;
|
|
}
|
|
|
|
if (err != ERROR_SUCCESS) {
|
|
DavPrint((DEBUG_ERRORS,
|
|
"WsLoadRedir/WsLoadDriver: Error Val = %08lx.\n", err));
|
|
return err;
|
|
}
|
|
|
|
//
|
|
// Open the redirector device.
|
|
//
|
|
RtlInitUnicodeString(&(DeviceName), DD_DAV_DEVICE_NAME_U);
|
|
|
|
InitializeObjectAttributes(&(ObjectAttributes),
|
|
&(DeviceName),
|
|
OBJ_CASE_INSENSITIVE,
|
|
NULL,
|
|
NULL);
|
|
|
|
NtStatus = NtOpenFile(&(DavRedirDeviceHandle),
|
|
SYNCHRONIZE,
|
|
&(ObjectAttributes),
|
|
&(IoStatusBlock),
|
|
FILE_SHARE_VALID_FLAGS,
|
|
FILE_SYNCHRONOUS_IO_NONALERT);
|
|
if (NtStatus != STATUS_SUCCESS) {
|
|
DavPrint((DEBUG_ERRORS, "WsLoadRedir/NtOpenFile: Error Val = %08lx\n", NtStatus));
|
|
DavRedirDeviceHandle = INVALID_HANDLE_VALUE;
|
|
return RtlNtStatusToDosError(NtStatus);
|
|
}
|
|
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
|
|
NET_API_STATUS
|
|
WsUnloadRedir(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine unloads the DAV driver. Calls the NtUnloadDriver function.
|
|
|
|
Arguments:
|
|
|
|
none.
|
|
|
|
Return Value:
|
|
|
|
Win32 error status.
|
|
|
|
--*/
|
|
{
|
|
LPWSTR DriverRegistryName;
|
|
ULONG Privileges[1], DriverRegistryNameLength;
|
|
UNICODE_STRING DriverRegistryString;
|
|
NET_API_STATUS Status;
|
|
NTSTATUS ntstatus = STATUS_SUCCESS;
|
|
|
|
DriverRegistryNameLength = sizeof(SERVICE_REGISTRY_KEY);
|
|
DriverRegistryNameLength += sizeof(DAVCLIENT_DRIVER);
|
|
|
|
//
|
|
// We need to make the DriverRegistryNameLength a multiple of 8. This is
|
|
// because DavAllocateMemory calls DebugAlloc which does some stuff which
|
|
// requires this. The equation below does this.
|
|
//
|
|
DriverRegistryNameLength = ( ( ( DriverRegistryNameLength + 7 ) / 8 ) * 8 );
|
|
|
|
DriverRegistryName = (LPWSTR) DavAllocateMemory(DriverRegistryNameLength);
|
|
if (DriverRegistryName == NULL) {
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
Privileges[0] = SE_LOAD_DRIVER_PRIVILEGE;
|
|
|
|
Status = NetpGetPrivilege(1, Privileges);
|
|
if (Status != NERR_Success) {
|
|
DavFreeMemory(DriverRegistryName);
|
|
return Status;
|
|
}
|
|
|
|
if (DavRedirDeviceHandle != INVALID_HANDLE_VALUE) {
|
|
NtClose(DavRedirDeviceHandle);
|
|
DavRedirDeviceHandle = INVALID_HANDLE_VALUE;
|
|
}
|
|
|
|
wcscpy(DriverRegistryName, SERVICE_REGISTRY_KEY);
|
|
wcscat(DriverRegistryName, DAVCLIENT_DRIVER);
|
|
|
|
RtlInitUnicodeString(&(DriverRegistryString), DriverRegistryName);
|
|
|
|
// Webclient should not unload the MRxDAV if it does not load it.
|
|
|
|
DavFreeMemory(DriverRegistryName);
|
|
|
|
NetpReleasePrivilege();
|
|
|
|
return(WsMapStatus(ntstatus));
|
|
}
|
|
|
|
|
|
NET_API_STATUS
|
|
WsLoadDriver(
|
|
IN LPWSTR DriverNameString
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine loads the DAV driver. Calls the NtLoadDriver function.
|
|
|
|
Arguments:
|
|
|
|
none.
|
|
|
|
Return Value:
|
|
|
|
Win32 error status.
|
|
|
|
--*/
|
|
{
|
|
LPWSTR DriverRegistryName;
|
|
ULONG Privileges[1], DriverRegistryNameLength;
|
|
UNICODE_STRING DriverRegistryString;
|
|
NET_API_STATUS Status;
|
|
NTSTATUS ntstatus = STATUS_SUCCESS;
|
|
|
|
DriverRegistryNameLength = sizeof(SERVICE_REGISTRY_KEY);
|
|
DriverRegistryNameLength += ( wcslen(DriverNameString) * sizeof(WCHAR) );
|
|
|
|
//
|
|
// We need to make the DriverRegistryNameLength a multiple of 8. This is
|
|
// because DavAllocateMemory calls DebugAlloc which does some stuff which
|
|
// requires this. The equation below does this.
|
|
//
|
|
DriverRegistryNameLength = ( ( ( DriverRegistryNameLength + 7 ) / 8 ) * 8 );
|
|
|
|
DriverRegistryName = (LPWSTR) DavAllocateMemory(DriverRegistryNameLength);
|
|
if (DriverRegistryName == NULL) {
|
|
DavPrint((DEBUG_ERRORS, "WsLoadDriver/DavAllocateMemory.\n"));
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
Privileges[0] = SE_LOAD_DRIVER_PRIVILEGE;
|
|
|
|
Status = NetpGetPrivilege(1, Privileges);
|
|
if (Status != NERR_Success) {
|
|
DavPrint((DEBUG_ERRORS, "WsLoadDriver/NetpGetPrivilege.\n"));
|
|
DavFreeMemory(DriverRegistryName);
|
|
return Status;
|
|
}
|
|
|
|
wcscpy(DriverRegistryName, SERVICE_REGISTRY_KEY);
|
|
wcscat(DriverRegistryName, DriverNameString);
|
|
|
|
RtlInitUnicodeString(&(DriverRegistryString), DriverRegistryName);
|
|
|
|
//
|
|
// Webclient becomes a LocalService and can no longer load the MRxDAV.
|
|
// We make MRxDAV as a depend service of Webclient. Svchost will load it.
|
|
//
|
|
|
|
NetpReleasePrivilege();
|
|
|
|
DavFreeMemory(DriverRegistryName);
|
|
|
|
if (ntstatus != STATUS_SUCCESS && ntstatus != STATUS_IMAGE_ALREADY_LOADED) {
|
|
|
|
LPWSTR subString[1];
|
|
subString[0] = DriverNameString;
|
|
|
|
DavPrint((DEBUG_ERRORS,
|
|
"WsLoadDriver/NtLoadDriver. NtStatus = %08lx\n", ntstatus));
|
|
|
|
#if 0
|
|
DavReportEventW(NELOG_DriverNotLoaded,
|
|
EVENTLOG_ERROR_TYPE,
|
|
1,
|
|
sizeof(NTSTATUS),
|
|
subString,
|
|
&ntstatus);
|
|
#endif
|
|
|
|
}
|
|
|
|
return(WsMapStatus(ntstatus));
|
|
}
|
|
|
|
|
|
NET_API_STATUS
|
|
WsMapStatus(
|
|
IN NTSTATUS NtStatus
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function takes an NT status code and maps it to the appropriate
|
|
error code expected from calling a LAN Man API.
|
|
|
|
Arguments:
|
|
|
|
NtStatus - Supplies the NT status.
|
|
|
|
Return Value:
|
|
|
|
Returns the appropriate LAN Man error code for the NT status.
|
|
|
|
--*/
|
|
{
|
|
//
|
|
// A small optimization for the most common case.
|
|
//
|
|
if (NtStatus == STATUS_SUCCESS) {
|
|
return NERR_Success;
|
|
}
|
|
|
|
switch (NtStatus) {
|
|
|
|
case STATUS_OBJECT_NAME_COLLISION:
|
|
return ERROR_ALREADY_ASSIGNED;
|
|
|
|
case STATUS_ACCESS_DENIED:
|
|
return ERROR_ACCESS_DENIED;
|
|
|
|
case STATUS_OBJECT_NAME_NOT_FOUND:
|
|
return NERR_UseNotFound;
|
|
|
|
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;
|
|
|
|
default:
|
|
return NetpNtStatusToApiStatus(NtStatus);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
DavMapErrorToNtStatus(
|
|
DWORD dwWin32Error
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function takes an errorcode which is either a WinInet error code or
|
|
a or a Win32 error code and converts it into an NTSTATUS value. It does the
|
|
following in the order mentioned below:
|
|
|
|
1. Checks to see if the error code is a WinInet error code and if it is
|
|
maps that to an NTSTATUS value. If not,
|
|
|
|
2. Assumes that this is a Win32 error code and maps that to an NTSTATUS
|
|
value.
|
|
|
|
Arguments:
|
|
|
|
dwWin32Error - The win32 or wininet error code.
|
|
|
|
Return Value:
|
|
|
|
Returns the most appropriate NtStatus value.
|
|
|
|
--*/
|
|
{
|
|
int indexLast;
|
|
|
|
DavPrint((DEBUG_MISC,
|
|
"DavMapErrorToNtstatus. dwWin32Error = %08lx\n", dwWin32Error));
|
|
|
|
//
|
|
// Check if its a WinInet error.
|
|
//
|
|
if (dwWin32Error > INTERNET_ERROR_BASE && dwWin32Error <= INTERNET_ERROR_LAST) {
|
|
|
|
indexLast = ( ( sizeof(rgHttpToNtstatus1) / sizeof(HTTP_TO_NTSTATUS_MAPPING) ) - 1 );
|
|
|
|
if (dwWin32Error >= rgHttpToNtstatus1[0].dwHttpError &&
|
|
dwWin32Error <= rgHttpToNtstatus1[indexLast].dwHttpError) {
|
|
return rgHttpToNtstatus1[dwWin32Error-rgHttpToNtstatus1[0].dwHttpError].Status;
|
|
}
|
|
|
|
indexLast = ( ( sizeof(rgHttpToNtstatus2) / sizeof(HTTP_TO_NTSTATUS_MAPPING) ) - 1 );
|
|
|
|
if (dwWin32Error >= rgHttpToNtstatus2[0].dwHttpError &&
|
|
dwWin32Error <= rgHttpToNtstatus2[indexLast].dwHttpError) {
|
|
return rgHttpToNtstatus2[dwWin32Error-rgHttpToNtstatus2[0].dwHttpError].Status;
|
|
}
|
|
|
|
} else if (dwWin32Error >= (DWORD)HTTP_STATUS_FIRST && dwWin32Error <= (DWORD)HTTP_STATUS_LAST) {
|
|
|
|
#if 0
|
|
|
|
//
|
|
// IMPORTANT!!!
|
|
// We don't check for Http error codes here. This mapping is done in
|
|
// the DavMapHttpErrorToDosError function. The functions expecting a
|
|
// Http response should call DavQueryAndParseResponse function.
|
|
//
|
|
|
|
//
|
|
// Check if its a HTTP error code.
|
|
//
|
|
|
|
switch (dwWin32Error) {
|
|
|
|
case HTTP_STATUS_CONTINUE: // 100 OK to continue with request
|
|
return STATUS_SUCCESS;
|
|
|
|
case HTTP_STATUS_SWITCH_PROTOCOLS: // 101 server has switched protocols in upgrade header
|
|
return STATUS_DEVICE_PROTOCOL_ERROR;
|
|
|
|
case HTTP_STATUS_OK: // 200 // request completed
|
|
case HTTP_STATUS_CREATED: // 201 // object created, reason = new URI
|
|
case HTTP_STATUS_ACCEPTED: // 202 // async completion (TBS)
|
|
case HTTP_STATUS_PARTIAL: // 203 // partial completion
|
|
case HTTP_STATUS_NO_CONTENT: // 204 // no info to return
|
|
case HTTP_STATUS_RESET_CONTENT: // 205 // request completed, but clear form
|
|
case HTTP_STATUS_PARTIAL_CONTENT: // 206 // partial GET furfilled
|
|
case DAV_MULTI_STATUS: // 207 // multi status response
|
|
return STATUS_SUCCESS;
|
|
|
|
|
|
|
|
case HTTP_STATUS_AMBIGUOUS: // 300 // server couldn't decide what to return
|
|
return STATUS_UNSUCCESSFUL;
|
|
|
|
case HTTP_STATUS_MOVED: // 301 // object permanently moved
|
|
return STATUS_OBJECT_NAME_NOT_FOUND;
|
|
|
|
case HTTP_STATUS_REDIRECT:
|
|
return STATUS_OBJECT_NAME_NOT_FOUND; // 302 // object temporarily moved
|
|
|
|
case HTTP_STATUS_REDIRECT_METHOD:
|
|
return STATUS_OBJECT_NAME_NOT_FOUND; // 303 // redirection w/ new access method
|
|
|
|
case HTTP_STATUS_NOT_MODIFIED:
|
|
return STATUS_SUCCESS; // 304 // if-modified-since was not modified
|
|
|
|
case HTTP_STATUS_USE_PROXY:
|
|
return STATUS_HOST_UNREACHABLE; // 305 // redirection to proxy, location header specifies proxy to use
|
|
|
|
case HTTP_STATUS_REDIRECT_KEEP_VERB:
|
|
return STATUS_SUCCESS; // 307 // HTTP/1.1: keep same verb
|
|
|
|
case HTTP_STATUS_BAD_REQUEST: // 400 // invalid syntax
|
|
return STATUS_INVALID_PARAMETER;
|
|
|
|
case HTTP_STATUS_DENIED: // 401 // access denied
|
|
return STATUS_ACCESS_DENIED;
|
|
|
|
case HTTP_STATUS_PAYMENT_REQ: // 402 // payment required
|
|
return STATUS_ACCESS_DENIED;
|
|
|
|
case HTTP_STATUS_FORBIDDEN: // 403 // request forbidden
|
|
return STATUS_ACCESS_DENIED;
|
|
|
|
case HTTP_STATUS_NOT_FOUND: // 404 // object not found
|
|
return STATUS_OBJECT_NAME_NOT_FOUND;
|
|
|
|
case HTTP_STATUS_BAD_METHOD: // 405 // method is not allowed
|
|
return STATUS_ACCESS_DENIED;
|
|
|
|
case HTTP_STATUS_NONE_ACCEPTABLE: // 406 // no response acceptable to client found
|
|
return STATUS_ACCESS_DENIED;
|
|
|
|
case HTTP_STATUS_PROXY_AUTH_REQ: // 407 // proxy authentication required
|
|
return STATUS_ACCESS_DENIED;
|
|
|
|
case HTTP_STATUS_REQUEST_TIMEOUT: // 408 // server timed out waiting for request
|
|
return STATUS_IO_TIMEOUT;
|
|
|
|
case HTTP_STATUS_CONFLICT: // 409 // user should resubmit with more info
|
|
return STATUS_INVALID_PARAMETER;
|
|
|
|
case HTTP_STATUS_GONE: // 410 // the resource is no longer available
|
|
return STATUS_OBJECT_NAME_NOT_FOUND;
|
|
|
|
case HTTP_STATUS_LENGTH_REQUIRED: // 411 // the server refused to accept request w/o a length
|
|
return STATUS_INVALID_PARAMETER;
|
|
|
|
case HTTP_STATUS_PRECOND_FAILED: // 412 // precondition given in request failed
|
|
return STATUS_INVALID_PARAMETER;
|
|
|
|
case HTTP_STATUS_REQUEST_TOO_LARGE: // 413 // request entity was too large
|
|
return STATUS_INVALID_PARAMETER;
|
|
|
|
case HTTP_STATUS_URI_TOO_LONG: // 414 // request URI too long
|
|
return STATUS_INVALID_PARAMETER;
|
|
|
|
case HTTP_STATUS_UNSUPPORTED_MEDIA: // 415 // unsupported media type
|
|
return STATUS_INVALID_PARAMETER;
|
|
|
|
case HTTP_STATUS_RETRY_WITH: // 449 // retry after doing the appropriate action.
|
|
return STATUS_RETRY;
|
|
|
|
case HTTP_STATUS_SERVER_ERROR: // 500 // internal server error
|
|
return STATUS_UNSUCCESSFUL;
|
|
|
|
case HTTP_STATUS_NOT_SUPPORTED: // 501 // required not supported
|
|
return STATUS_NOT_SUPPORTED;
|
|
|
|
case HTTP_STATUS_BAD_GATEWAY: // 502 // error response received from gateway
|
|
return STATUS_HOST_UNREACHABLE;
|
|
|
|
case HTTP_STATUS_SERVICE_UNAVAIL: // 503 // temporarily overloaded
|
|
return STATUS_UNSUCCESSFUL;
|
|
|
|
case HTTP_STATUS_GATEWAY_TIMEOUT: // 504 // timed out waiting for gateway
|
|
return STATUS_HOST_UNREACHABLE;
|
|
|
|
case HTTP_STATUS_VERSION_NOT_SUP: // 505 // HTTP version not supported
|
|
return STATUS_NOT_SUPPORTED;
|
|
|
|
//
|
|
// WebDav specific status codes.
|
|
//
|
|
case DAV_STATUS_INSUFFICIENT_STORAGE: // 507
|
|
return STATUS_DISK_FULL;
|
|
|
|
case DAV_STATUS_UNPROCESSABLE_ENTITY: // 422
|
|
return STATUS_INVALID_PARAMETER;
|
|
|
|
case DAV_STATUS_LOCKED: // 423
|
|
return STATUS_ACCESS_DENIED;
|
|
|
|
case DAV_STATUS_FAILED_DEPENDENCY: // 424
|
|
return STATUS_INVALID_PARAMETER;
|
|
|
|
default:
|
|
break;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
//
|
|
// If none of the above match call this function which takes a Win32 error
|
|
// and maps it to an NTSTATUS value.
|
|
//
|
|
return DavDosErrorToNtStatus(dwWin32Error);
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
DavDosErrorToNtStatus(
|
|
DWORD dwError
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function takes a win32 error code and converts to the closes NTSTATUS.
|
|
As NTSTATUS->Win32Error is many to one mapping, there is a possible loss of
|
|
precision in this method of error reporting.
|
|
|
|
Arguments:
|
|
|
|
dwError - The win32 error code.
|
|
|
|
Return Value:
|
|
|
|
Returns the most appropriate NTSTATUS
|
|
|
|
--*/
|
|
{
|
|
|
|
if (dwError < sizeof(rgWin32ToNtStatus)/sizeof(WIN32_TO_NTSTATUS_MAPPING)) {
|
|
|
|
return rgWin32ToNtStatus[dwError].NtStatus;
|
|
|
|
} else {
|
|
|
|
switch (dwError) {
|
|
|
|
case ERROR_BUFFER_OVERFLOW:
|
|
return STATUS_BUFFER_OVERFLOW;
|
|
|
|
case ERROR_NOT_SUPPORTED:
|
|
return STATUS_NOT_SUPPORTED;
|
|
|
|
case ERROR_DISK_FULL:
|
|
return STATUS_DISK_FULL;
|
|
|
|
case ERROR_FILE_EXISTS:
|
|
return STATUS_OBJECT_NAME_EXISTS;
|
|
|
|
case ERROR_INVALID_PASSWORD:
|
|
return STATUS_WRONG_PASSWORD;
|
|
|
|
case ERROR_INVALID_PARAMETER:
|
|
return STATUS_INVALID_PARAMETER;
|
|
|
|
case ERROR_BAD_NETPATH:
|
|
return STATUS_BAD_NETWORK_PATH;
|
|
|
|
case ERROR_CALL_NOT_IMPLEMENTED:
|
|
return STATUS_NOT_IMPLEMENTED;
|
|
|
|
case ERROR_SEM_TIMEOUT:
|
|
return STATUS_IO_TIMEOUT;
|
|
|
|
case ERROR_INSUFFICIENT_BUFFER:
|
|
return STATUS_BUFFER_TOO_SMALL;
|
|
|
|
case ERROR_INVALID_NAME:
|
|
return STATUS_OBJECT_NAME_INVALID;
|
|
|
|
case ERROR_DIR_NOT_EMPTY:
|
|
return STATUS_DIRECTORY_NOT_EMPTY;
|
|
|
|
case ERROR_BUSY:
|
|
return STATUS_DEVICE_BUSY;
|
|
|
|
case ERROR_ALREADY_EXISTS:
|
|
return STATUS_OBJECT_NAME_COLLISION;
|
|
|
|
case ERROR_DIRECTORY:
|
|
return STATUS_NOT_A_DIRECTORY;
|
|
|
|
case ERROR_OPERATION_ABORTED:
|
|
return STATUS_CANCELLED;
|
|
|
|
case ERROR_IO_PENDING:
|
|
return STATUS_PENDING;
|
|
|
|
case ERROR_NOACCESS:
|
|
return ERROR_ACCESS_DENIED;
|
|
|
|
case ERROR_NOT_FOUND:
|
|
return STATUS_OBJECT_NAME_NOT_FOUND;
|
|
|
|
case ERROR_NO_MATCH:
|
|
return STATUS_OBJECT_NAME_NOT_FOUND;
|
|
|
|
case ERROR_CANCELLED:
|
|
return STATUS_CANCELLED;
|
|
|
|
case ERROR_RETRY:
|
|
return STATUS_RETRY;
|
|
|
|
case STATUS_NOT_A_DIRECTORY:
|
|
return STATUS_NOT_A_DIRECTORY;
|
|
|
|
case STATUS_FILE_IS_A_DIRECTORY:
|
|
return STATUS_FILE_IS_A_DIRECTORY;
|
|
|
|
case ERROR_NOT_ENOUGH_QUOTA:
|
|
return STATUS_QUOTA_EXCEEDED;
|
|
|
|
case ERROR_SESSION_CREDENTIAL_CONFLICT:
|
|
return STATUS_NETWORK_CREDENTIAL_CONFLICT;
|
|
|
|
default:
|
|
DavPrint((DEBUG_ERRORS, "DavDosErrorToNtStatus: dwError = %d\n", dwError));
|
|
return STATUS_UNSUCCESSFUL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// #define FIND_FLAGS_RETRIEVE_ONLY_STRUCT_INFO 0x2
|
|
|
|
DWORD
|
|
DavrGetDiskSpaceUsage(
|
|
IN handle_t dav_binding_h,
|
|
LPWSTR lptzLocation,
|
|
LONG lLenIn,
|
|
LONG *lplReturnLen,
|
|
ULARGE_INTEGER *lpMaxSpace,
|
|
ULARGE_INTEGER *lpUsedSpace
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Finds out the amount of disk being consumed by wininet urlcache due to Webdav
|
|
|
|
Arguments:
|
|
|
|
dav_binding_h - The explicit RPC binding handle.
|
|
|
|
dwSize - Size of the cache location buffer. On return this will contain the actual size of the
|
|
location string.
|
|
|
|
lptzLocation - Buffer to return Cache location string. As much of the location string as can fit
|
|
in the buffer is returned
|
|
|
|
lpdwReturnSize
|
|
|
|
lpMaxSpace - Size of disk Quota set for webdav
|
|
|
|
lpUsedSpace - Size of disk consumed by the urlcache used by webdav
|
|
|
|
Return Value:
|
|
|
|
Win32 error code
|
|
|
|
--*/
|
|
{
|
|
// iterate through the cache to discover the actual size.
|
|
INTERNET_CACHE_CONFIG_INFOW sConfigW;
|
|
DWORD dwSize = sizeof(sConfigW), dwError = ERROR_SUCCESS;
|
|
BOOL fResult = FALSE;
|
|
|
|
// should atleass have enough space for a drive letter
|
|
if (lLenIn < 3)
|
|
{
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
try
|
|
{
|
|
|
|
sConfigW.dwContainer = 0;
|
|
sConfigW.dwStructSize = sizeof(sConfigW);
|
|
|
|
if (GetUrlCacheConfigInfoW(&sConfigW, &dwSize, CACHE_CONFIG_DISK_CACHE_PATHS_FC |
|
|
CACHE_CONFIG_QUOTA_FC |
|
|
CACHE_CONFIG_CONTENT_USAGE_FC |
|
|
CACHE_CONFIG_STICKY_CONTENT_USAGE_FC))
|
|
{
|
|
*(ULONGLONG *)lpMaxSpace = (ULONGLONG)(sConfigW.dwQuota) * 1024;
|
|
*(ULONGLONG *)lpUsedSpace = (ULONGLONG)(sConfigW.dwNormalUsage+sConfigW.dwExemptUsage) * 1024;
|
|
|
|
memset(lptzLocation, 0, lLenIn * sizeof(WCHAR));
|
|
|
|
*lplReturnLen = wcslen(sConfigW.CachePath);
|
|
|
|
if (*lplReturnLen < lLenIn)
|
|
{
|
|
// We have enough buffer
|
|
memcpy(lptzLocation, sConfigW.CachePath, *lplReturnLen * sizeof(WCHAR));
|
|
}
|
|
else
|
|
{
|
|
// We don't have enough buffer, we copy as much as we can
|
|
memcpy(lptzLocation, sConfigW.CachePath, lLenIn * sizeof(WCHAR));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
dwError = GetLastError();
|
|
}
|
|
}
|
|
except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
dwError = ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
return dwError;
|
|
}
|
|
|
|
DWORD
|
|
DavrFreeUsedDiskSpace(
|
|
IN handle_t dav_binding_h,
|
|
DWORD dwPercent
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Frees up dwPercent of the urlcache used by webdav
|
|
|
|
|
|
Arguments:
|
|
|
|
dav_binding_h - The explicit RPC binding handle.
|
|
|
|
dwPercent - % of used space to be freed
|
|
|
|
Return Value:
|
|
|
|
Win32 error code
|
|
|
|
--*/
|
|
{
|
|
DWORD dwError = ERROR_SUCCESS;
|
|
|
|
if (dwPercent <= 100)
|
|
{
|
|
if (!FreeUrlCacheSpaceA(NULL, dwPercent, 0))
|
|
{
|
|
dwError = GetLastError();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
dwError = ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
return dwError;
|
|
}
|
|
|