mirror of
https://github.com/winfsp/winfsp.git
synced 2025-04-26 02:12:45 -05:00
383 lines
11 KiB
C
383 lines
11 KiB
C
/**
|
|
* @file dll/np.c
|
|
*
|
|
* @copyright 2015-2016 Bill Zissimopoulos
|
|
*/
|
|
/*
|
|
* This file is part of WinFsp.
|
|
*
|
|
* You can redistribute it and/or modify it under the terms of the
|
|
* GNU Affero General Public License version 3 as published by the
|
|
* Free Software Foundation.
|
|
*
|
|
* Licensees holding a valid commercial license may use this file in
|
|
* accordance with the commercial license agreement provided with the
|
|
* software.
|
|
*/
|
|
|
|
#include <dll/library.h>
|
|
#include <npapi.h>
|
|
|
|
#define FSP_NP_NAME LIBRARY_NAME ".Np"
|
|
#define FSP_NP_TYPE ' spF' /* pick a value hopefully not in use */
|
|
|
|
DWORD APIENTRY NPGetCaps(DWORD Index)
|
|
{
|
|
switch (Index)
|
|
{
|
|
case WNNC_ADMIN:
|
|
/*
|
|
* WNNC_ADM_DIRECTORYNOTIFY
|
|
* WNNC_ADM_GETDIRECTORYTYPE
|
|
*/
|
|
return 0;
|
|
case WNNC_CONNECTION:
|
|
/*
|
|
* WNNC_CON_ADDCONECTION
|
|
* WNNC_CON_CANCELCONNECTION
|
|
* WNNC_CON_GETCONNECTIONS
|
|
* WNNC_CON_ADDCONECTION3
|
|
* WNNC_CON_GETPERFORMANCE
|
|
* WNNC_CON_DEFER
|
|
*/
|
|
return WNNC_CON_GETCONNECTIONS;
|
|
case WNNC_DIALOG:
|
|
/*
|
|
* WNNC_DLG_DEVICEMODE
|
|
* WNNC_DLG_FORMATNETNAME
|
|
* WNNC_DLG_GETRESOURCEINFORMATION
|
|
* WNNC_DLG_GETRESOURCEPARENT
|
|
* WNNC_DLG_PERMISSIONEDITOR
|
|
* WNNC_DLG_PROPERTYDIALOG
|
|
* WNNC_DLG_SEARCHDIALOG
|
|
*/
|
|
return 0;
|
|
case WNNC_ENUMERATION:
|
|
/*
|
|
* WNNC_ENUM_GLOBAL
|
|
* WNNC_ENUM_LOCAL
|
|
* WNNC_ENUM_CONTEXT
|
|
*/
|
|
return 0;
|
|
case WNNC_NET_TYPE:
|
|
return FSP_NP_TYPE;
|
|
case WNNC_SPEC_VERSION:
|
|
return WNNC_SPEC_VERSION51;
|
|
case WNNC_START:
|
|
return 1;
|
|
case WNNC_USER:
|
|
/*
|
|
* WNNC_USR_GETUSER
|
|
*/
|
|
return 0;
|
|
default:
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
static NTSTATUS FspNpGetVolumeList(
|
|
PWCHAR *PVolumeListBuf, PSIZE_T PVolumeListSize)
|
|
{
|
|
NTSTATUS Result;
|
|
PWCHAR VolumeListBuf;
|
|
SIZE_T VolumeListSize;
|
|
|
|
*PVolumeListBuf = 0;
|
|
*PVolumeListSize = 0;
|
|
|
|
for (VolumeListSize = 1024;; VolumeListSize *= 2)
|
|
{
|
|
VolumeListBuf = MemAlloc(VolumeListSize);
|
|
if (0 == VolumeListBuf)
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
Result = FspFsctlGetVolumeList(L"" FSP_FSCTL_NET_DEVICE_NAME,
|
|
VolumeListBuf, &VolumeListSize);
|
|
if (NT_SUCCESS(Result))
|
|
{
|
|
*PVolumeListBuf = VolumeListBuf;
|
|
*PVolumeListSize = VolumeListSize;
|
|
return Result;
|
|
}
|
|
|
|
MemFree(VolumeListBuf);
|
|
|
|
if (STATUS_BUFFER_TOO_SMALL != Result)
|
|
return Result;
|
|
}
|
|
}
|
|
|
|
DWORD APIENTRY NPGetConnection(LPWSTR lpLocalName, LPWSTR lpRemoteName, LPDWORD lpnBufferLen)
|
|
{
|
|
DWORD NpResult;
|
|
NTSTATUS Result;
|
|
WCHAR LocalNameBuf[3];
|
|
WCHAR VolumeNameBuf[FSP_FSCTL_VOLUME_NAME_SIZEMAX / sizeof(WCHAR)];
|
|
PWCHAR VolumeListBuf = 0, VolumeListBufEnd, VolumeName, P;
|
|
SIZE_T VolumeListSize, VolumeNameSize;
|
|
ULONG Backslashes;
|
|
|
|
if (0 == lpLocalName ||
|
|
!(
|
|
(L'A' <= lpLocalName[0] && lpLocalName[0] <= L'Z') ||
|
|
(L'a' <= lpLocalName[0] && lpLocalName[0] <= L'z')
|
|
) ||
|
|
L':' != lpLocalName[1])
|
|
return WN_BAD_LOCALNAME;
|
|
|
|
LocalNameBuf[0] = lpLocalName[0];
|
|
LocalNameBuf[1] = L':';
|
|
LocalNameBuf[2] = L'\0';
|
|
|
|
if (0 == QueryDosDeviceW(LocalNameBuf, VolumeNameBuf, sizeof VolumeNameBuf))
|
|
return WN_NOT_CONNECTED;
|
|
|
|
Result = FspNpGetVolumeList(&VolumeListBuf, &VolumeListSize);
|
|
if (!NT_SUCCESS(Result))
|
|
return WN_OUT_OF_MEMORY;
|
|
|
|
NpResult = WN_NOT_CONNECTED;
|
|
for (P = VolumeListBuf, VolumeListBufEnd = (PVOID)((PUINT8)P + VolumeListSize), VolumeName = P;
|
|
VolumeListBufEnd > P; P++)
|
|
{
|
|
if (L'\0' == *P)
|
|
{
|
|
if (0 == lstrcmpW(VolumeNameBuf, VolumeName))
|
|
{
|
|
/*
|
|
* Looks like this is a WinFsp device. Extract the VolumePrefix from the VolumeName.
|
|
*
|
|
* The VolumeName will have the following syntax:
|
|
* \Device\Volume{GUID}\Server\Share
|
|
*
|
|
* We want to extract the \Server\Share part. We will simply count backslashes and
|
|
* stop at the third one. Since we are about to break this loop, it is ok to mess
|
|
* with the loop variables.
|
|
*/
|
|
|
|
for (Backslashes = 0; VolumeName < P; VolumeName++)
|
|
if (L'\\' == *VolumeName)
|
|
if (3 == ++Backslashes)
|
|
break;
|
|
|
|
if (3 == Backslashes)
|
|
{
|
|
VolumeNameSize = lstrlenW(VolumeName) + 1/* term-0 */;
|
|
if (*lpnBufferLen >= 1/* lead-\ */ + VolumeNameSize)
|
|
{
|
|
*lpRemoteName = L'\\';
|
|
memcpy(lpRemoteName + 1, VolumeName, VolumeNameSize * sizeof(WCHAR));
|
|
NpResult = WN_SUCCESS;
|
|
}
|
|
else
|
|
{
|
|
*lpnBufferLen = (DWORD)(1/* lead-\ */ + VolumeNameSize);
|
|
NpResult = WN_MORE_DATA;
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
else
|
|
VolumeName = P + 1;
|
|
}
|
|
}
|
|
|
|
MemFree(VolumeListBuf);
|
|
|
|
return NpResult;
|
|
}
|
|
|
|
NTSTATUS FspNpRegister(VOID)
|
|
{
|
|
extern HINSTANCE DllInstance;
|
|
WCHAR ProviderPath[MAX_PATH];
|
|
WCHAR RegBuffer[1024];
|
|
PWSTR P, Part;
|
|
DWORD RegResult, RegType, RegBufferSize;
|
|
HKEY RegKey;
|
|
BOOLEAN FoundProvider;
|
|
|
|
if (0 == GetModuleFileNameW(DllInstance, ProviderPath, MAX_PATH))
|
|
return FspNtStatusFromWin32(GetLastError());
|
|
|
|
RegResult = RegCreateKeyExW(
|
|
HKEY_LOCAL_MACHINE, L"SYSTEM\\CurrentControlSet\\Services\\" FSP_NP_NAME,
|
|
0, 0, 0, KEY_ALL_ACCESS, 0, &RegKey, 0);
|
|
if (ERROR_SUCCESS != RegResult)
|
|
return FspNtStatusFromWin32(RegResult);
|
|
|
|
RegResult = RegSetValueExW(RegKey,
|
|
L"Group", 0, REG_SZ, (PVOID) L"NetworkProvider", sizeof L"NetworkProvider");
|
|
if (ERROR_SUCCESS != RegResult)
|
|
goto close_and_exit;
|
|
|
|
RegCloseKey(RegKey);
|
|
|
|
RegResult = RegCreateKeyExW(
|
|
HKEY_LOCAL_MACHINE, L"SYSTEM\\CurrentControlSet\\Services\\" FSP_NP_NAME "\\NetworkProvider",
|
|
0, 0, 0, KEY_ALL_ACCESS, 0, &RegKey, 0);
|
|
if (ERROR_SUCCESS != RegResult)
|
|
return FspNtStatusFromWin32(RegResult);
|
|
|
|
RegResult = ERROR_RESOURCE_NAME_NOT_FOUND; /* not a real resource error! */
|
|
{
|
|
PVOID VersionInfo = 0;
|
|
DWORD Size;
|
|
PWSTR Description;
|
|
|
|
Size = GetFileVersionInfoSizeW(ProviderPath, &Size/*dummy*/);
|
|
if (0 < Size)
|
|
{
|
|
VersionInfo = MemAlloc(Size);
|
|
if (0 != VersionInfo &&
|
|
GetFileVersionInfoW(ProviderPath, 0, Size, VersionInfo) &&
|
|
VerQueryValueW(VersionInfo, L"\\StringFileInfo\\040904b0\\FileDescription",
|
|
&Description, &Size))
|
|
{
|
|
Size = Size * 2 + sizeof(WCHAR);
|
|
RegResult = RegSetValueExW(RegKey,
|
|
L"Name", 0, REG_SZ, (PVOID)Description, Size);
|
|
}
|
|
|
|
MemFree(VersionInfo);
|
|
}
|
|
}
|
|
if (ERROR_SUCCESS != RegResult)
|
|
goto close_and_exit;
|
|
|
|
RegResult = RegSetValueExW(RegKey,
|
|
L"ProviderPath", 0, REG_SZ, (PVOID)ProviderPath, (lstrlenW(ProviderPath) + 1) * sizeof(WCHAR));
|
|
if (ERROR_SUCCESS != RegResult)
|
|
goto close_and_exit;
|
|
|
|
RegCloseKey(RegKey);
|
|
|
|
RegResult = RegOpenKeyExW(
|
|
HKEY_LOCAL_MACHINE, L"SYSTEM\\CurrentControlSet\\Control\\NetworkProvider\\Order",
|
|
0, KEY_ALL_ACCESS, &RegKey);
|
|
if (ERROR_SUCCESS != RegResult)
|
|
return FspNtStatusFromWin32(RegResult);
|
|
|
|
RegBufferSize = sizeof RegBuffer - sizeof L"," FSP_NP_NAME;
|
|
RegResult = RegQueryValueExW(RegKey,
|
|
L"ProviderOrder", 0, &RegType, (PVOID)RegBuffer, &RegBufferSize);
|
|
if (ERROR_SUCCESS != RegResult)
|
|
goto close_and_exit;
|
|
RegBufferSize /= sizeof(WCHAR);
|
|
|
|
FoundProvider = FALSE;
|
|
RegBuffer[RegBufferSize] = L'\0';
|
|
P = RegBuffer, Part = P;
|
|
do
|
|
{
|
|
if (L',' == *P || '\0' == *P)
|
|
{
|
|
if (CSTR_EQUAL == CompareStringW(LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE,
|
|
Part, (int)(P - Part),
|
|
L"" FSP_NP_NAME, (int)(sizeof L"" FSP_NP_NAME - sizeof(WCHAR)) / sizeof(WCHAR)))
|
|
{
|
|
FoundProvider = TRUE;
|
|
break;
|
|
}
|
|
else
|
|
Part = P + 1;
|
|
}
|
|
} while (L'\0' != *P++);
|
|
|
|
if (!FoundProvider)
|
|
{
|
|
P--;
|
|
memcpy(P, L"," FSP_NP_NAME, sizeof L"," FSP_NP_NAME);
|
|
|
|
RegBufferSize = lstrlenW(RegBuffer);
|
|
RegBufferSize++;
|
|
|
|
RegResult = RegSetValueExW(RegKey,
|
|
L"ProviderOrder", 0, REG_SZ, (PVOID)RegBuffer, RegBufferSize * sizeof(WCHAR));
|
|
if (ERROR_SUCCESS != RegResult)
|
|
goto close_and_exit;
|
|
}
|
|
|
|
RegCloseKey(RegKey);
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
close_and_exit:
|
|
RegCloseKey(RegKey);
|
|
return FspNtStatusFromWin32(RegResult);
|
|
}
|
|
|
|
NTSTATUS FspNpUnregister(VOID)
|
|
{
|
|
WCHAR RegBuffer[1024];
|
|
PWSTR P, Part;
|
|
DWORD RegResult, RegType, RegBufferSize;
|
|
HKEY RegKey;
|
|
BOOLEAN FoundProvider;
|
|
|
|
RegResult = RegOpenKeyExW(
|
|
HKEY_LOCAL_MACHINE, L"SYSTEM\\CurrentControlSet\\Control\\NetworkProvider\\Order",
|
|
0, KEY_ALL_ACCESS, &RegKey);
|
|
if (ERROR_SUCCESS != RegResult)
|
|
return FspNtStatusFromWin32(RegResult);
|
|
|
|
RegBufferSize = sizeof RegBuffer - sizeof L"," FSP_NP_NAME;
|
|
RegResult = RegQueryValueExW(RegKey,
|
|
L"ProviderOrder", 0, &RegType, (PVOID)RegBuffer, &RegBufferSize);
|
|
if (ERROR_SUCCESS != RegResult)
|
|
goto close_and_exit;
|
|
RegBufferSize /= sizeof(WCHAR);
|
|
|
|
FoundProvider = FALSE;
|
|
RegBuffer[RegBufferSize] = L'\0';
|
|
P = RegBuffer, Part = P;
|
|
do
|
|
{
|
|
if (L',' == *P || '\0' == *P)
|
|
{
|
|
if (CSTR_EQUAL == CompareStringW(LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE,
|
|
Part, (int)(P - Part),
|
|
L"" FSP_NP_NAME, (int)(sizeof L"" FSP_NP_NAME - sizeof(WCHAR)) / sizeof(WCHAR)))
|
|
{
|
|
FoundProvider = TRUE;
|
|
break;
|
|
}
|
|
else
|
|
Part = P + 1;
|
|
}
|
|
} while (L'\0' != *P++);
|
|
|
|
if (FoundProvider)
|
|
{
|
|
if (L',' == *P)
|
|
P++;
|
|
|
|
RtlMoveMemory(Part, P, (lstrlenW(P) + 1) * sizeof(WCHAR));
|
|
|
|
RegBufferSize = lstrlenW(RegBuffer);
|
|
while (0 < RegBufferSize && ',' == RegBuffer[RegBufferSize - 1])
|
|
RegBufferSize--;
|
|
RegBuffer[RegBufferSize] = L'\0';
|
|
RegBufferSize++;
|
|
|
|
RegResult = RegSetValueExW(RegKey,
|
|
L"ProviderOrder", 0, REG_SZ, (PVOID)RegBuffer, RegBufferSize * sizeof(WCHAR));
|
|
if (ERROR_SUCCESS != RegResult)
|
|
goto close_and_exit;
|
|
}
|
|
|
|
RegCloseKey(RegKey);
|
|
|
|
RegResult = RegDeleteTreeW(
|
|
HKEY_LOCAL_MACHINE, L"SYSTEM\\CurrentControlSet\\Services\\" FSP_NP_NAME);
|
|
if (ERROR_SUCCESS != RegResult && ERROR_FILE_NOT_FOUND != RegResult)
|
|
return FspNtStatusFromWin32(RegResult);
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
close_and_exit:
|
|
RegCloseKey(RegKey);
|
|
return FspNtStatusFromWin32(RegResult);
|
|
}
|