mirror of
https://github.com/winfsp/winfsp.git
synced 2025-04-25 09:52:23 -05:00
1201 lines
36 KiB
C
1201 lines
36 KiB
C
/**
|
|
* @file dll/np.c
|
|
*
|
|
* @copyright 2015-2017 Bill Zissimopoulos
|
|
*/
|
|
/*
|
|
* This file is part of WinFsp.
|
|
*
|
|
* You can redistribute it and/or modify it under the terms of the GNU
|
|
* 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 <launcher/launcher.h>
|
|
#include <npapi.h>
|
|
#include <wincred.h>
|
|
|
|
#define FSP_NP_NAME LIBRARY_NAME ".Np"
|
|
#define FSP_NP_TYPE ' spF' /* pick a value hopefully not in use */
|
|
#define FSP_NP_ADDCONNECTION_TIMEOUT 15000
|
|
|
|
/*
|
|
* Define the following macro to use CredUIPromptForWindowsCredentials.
|
|
* Otherwise CredUIPromptForCredentials will be used.
|
|
*/
|
|
#define FSP_NP_CREDUI_PROMPT_NEW
|
|
|
|
/*
|
|
* Define the following macro to include support for the credential manager.
|
|
*/
|
|
#define FSP_NP_CREDENTIAL_MANAGER
|
|
|
|
enum
|
|
{
|
|
FSP_NP_CREDENTIALS_NONE = 0,
|
|
FSP_NP_CREDENTIALS_PASSWORD = 1,
|
|
FSP_NP_CREDENTIALS_USERPASS = 3,
|
|
};
|
|
|
|
DWORD APIENTRY NPGetCaps(DWORD Index)
|
|
{
|
|
switch (Index)
|
|
{
|
|
case WNNC_ADMIN:
|
|
/*
|
|
* WNNC_ADM_DIRECTORYNOTIFY
|
|
* WNNC_ADM_GETDIRECTORYTYPE
|
|
*/
|
|
return 0;
|
|
case WNNC_CONNECTION:
|
|
/*
|
|
* WNNC_CON_ADDCONNECTION
|
|
* WNNC_CON_CANCELCONNECTION
|
|
* WNNC_CON_GETCONNECTIONS
|
|
* WNNC_CON_ADDCONNECTION3
|
|
* WNNC_CON_GETPERFORMANCE
|
|
* WNNC_CON_DEFER
|
|
*/
|
|
return
|
|
WNNC_CON_GETCONNECTIONS |
|
|
WNNC_CON_ADDCONNECTION | WNNC_CON_ADDCONNECTION3 |
|
|
WNNC_CON_CANCELCONNECTION;
|
|
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 WNNC_ENUM_LOCAL | WNNC_ENUM_CONTEXT;
|
|
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 inline BOOLEAN FspNpCheckLocalName(PWSTR LocalName)
|
|
{
|
|
return 0 != LocalName && FspPathIsDrive(LocalName);
|
|
}
|
|
|
|
static inline BOOLEAN FspNpCheckRemoteName(PWSTR RemoteName)
|
|
{
|
|
return 0 != RemoteName && L'\\' == RemoteName[0] && L'\\' == RemoteName[1] &&
|
|
sizeof(((FSP_FSCTL_VOLUME_PARAMS *)0)->Prefix) / sizeof(WCHAR) >= lstrlenW(RemoteName);
|
|
}
|
|
|
|
static inline BOOLEAN FspNpParseRemoteName(PWSTR RemoteName,
|
|
PWSTR *PClassName, PULONG PClassNameLen,
|
|
PWSTR *PInstanceName, PULONG PInstanceNameLen)
|
|
{
|
|
PWSTR ClassName, InstanceName, P;
|
|
ULONG ClassNameLen, InstanceNameLen;
|
|
|
|
if (!FspNpCheckRemoteName(RemoteName))
|
|
return FALSE;
|
|
|
|
ClassName = RemoteName + 2; /* skip \\ */
|
|
for (P = ClassName; *P; P++)
|
|
if (L'\\' == *P)
|
|
break;
|
|
if (ClassName == P || L'\\' != *P)
|
|
return FALSE;
|
|
ClassNameLen = (ULONG)(P - ClassName);
|
|
|
|
InstanceName = P + 1;
|
|
for (P = InstanceName; *P; P++)
|
|
;
|
|
for (;;)
|
|
{
|
|
if (InstanceName == P)
|
|
return FALSE;
|
|
if (L'\\' != P[-1])
|
|
break;
|
|
P--;
|
|
}
|
|
InstanceNameLen = (ULONG)(P - InstanceName);
|
|
|
|
*PClassName = ClassName; *PClassNameLen = ClassNameLen;
|
|
*PInstanceName = InstanceName; *PInstanceNameLen = InstanceNameLen;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static inline BOOLEAN FspNpParseUserName(PWSTR RemoteName,
|
|
PWSTR UserName, ULONG UserNameSize/* in chars */)
|
|
{
|
|
PWSTR ClassName, InstanceName, P;
|
|
ULONG ClassNameLen, InstanceNameLen;
|
|
|
|
if (FspNpParseRemoteName(RemoteName,
|
|
&ClassName, &ClassNameLen, &InstanceName, &InstanceNameLen))
|
|
{
|
|
for (P = InstanceName; *P; P++)
|
|
if ('@' == *P && (ULONG)(P - InstanceName) < UserNameSize)
|
|
{
|
|
memcpy(UserName, InstanceName, (P - InstanceName) * sizeof(WCHAR));
|
|
UserName[P - InstanceName] = L'\0';
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static inline DWORD FspNpCallLauncherPipe(PWSTR PipeBuf, ULONG SendSize, ULONG RecvSize)
|
|
{
|
|
DWORD NpResult;
|
|
NTSTATUS Result;
|
|
DWORD BytesTransferred;
|
|
|
|
Result = FspCallNamedPipeSecurely(L"" LAUNCHER_PIPE_NAME, PipeBuf, SendSize, PipeBuf, RecvSize,
|
|
&BytesTransferred, NMPWAIT_USE_DEFAULT_WAIT, LAUNCHER_PIPE_OWNER);
|
|
|
|
if (!NT_SUCCESS(Result))
|
|
NpResult = WN_NO_NETWORK;
|
|
else if (sizeof(WCHAR) > BytesTransferred)
|
|
NpResult = WN_NO_NETWORK;
|
|
else if (LauncherSuccess == PipeBuf[0])
|
|
NpResult = WN_SUCCESS;
|
|
else if (LauncherFailure == PipeBuf[0])
|
|
{
|
|
NpResult = 0;
|
|
for (PWSTR P = PipeBuf + 1, EndP = PipeBuf + BytesTransferred / sizeof(WCHAR); EndP > P; P++)
|
|
{
|
|
if (L'0' > *P || *P > L'9')
|
|
break;
|
|
|
|
NpResult = 10 * NpResult + (*P - L'0');
|
|
}
|
|
|
|
if (0 == NpResult)
|
|
NpResult = WN_NO_NETWORK;
|
|
}
|
|
else
|
|
NpResult = WN_NO_NETWORK;
|
|
|
|
return NpResult;
|
|
}
|
|
|
|
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;
|
|
}
|
|
}
|
|
|
|
static WCHAR FspNpGetDriveLetter(PDWORD PLogicalDrives, PWSTR VolumeName)
|
|
{
|
|
WCHAR VolumeNameBuf[MAX_PATH];
|
|
WCHAR LocalNameBuf[3];
|
|
WCHAR Drive;
|
|
|
|
if (0 == *PLogicalDrives)
|
|
return 0;
|
|
|
|
LocalNameBuf[1] = L':';
|
|
LocalNameBuf[2] = L'\0';
|
|
|
|
for (Drive = 'Z'; 'A' <= Drive; Drive--)
|
|
if (0 != (*PLogicalDrives & (1 << (Drive - 'A'))))
|
|
{
|
|
LocalNameBuf[0] = Drive;
|
|
if (QueryDosDeviceW(LocalNameBuf, VolumeNameBuf, sizeof VolumeNameBuf / sizeof(WCHAR)))
|
|
{
|
|
if (0 == invariant_wcscmp(VolumeNameBuf, VolumeName))
|
|
{
|
|
*PLogicalDrives &= ~(1 << (Drive - 'A'));
|
|
return Drive;
|
|
}
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static DWORD FspNpGetCredentialsKind(PWSTR RemoteName, PDWORD PCredentialsKind)
|
|
{
|
|
HKEY RegKey = 0;
|
|
DWORD NpResult, RegSize;
|
|
DWORD Credentials;
|
|
PWSTR ClassName, InstanceName;
|
|
ULONG ClassNameLen, InstanceNameLen;
|
|
WCHAR ClassNameBuf[sizeof(((FSP_FSCTL_VOLUME_PARAMS *)0)->Prefix) / sizeof(WCHAR)];
|
|
|
|
*PCredentialsKind = FSP_NP_CREDENTIALS_NONE;
|
|
|
|
if (!FspNpParseRemoteName(RemoteName,
|
|
&ClassName, &ClassNameLen, &InstanceName, &InstanceNameLen))
|
|
return WN_BAD_NETNAME;
|
|
|
|
if (ClassNameLen > sizeof ClassNameBuf / sizeof ClassNameBuf[0] - 1)
|
|
ClassNameLen = sizeof ClassNameBuf / sizeof ClassNameBuf[0] - 1;
|
|
memcpy(ClassNameBuf, ClassName, ClassNameLen * sizeof(WCHAR));
|
|
ClassNameBuf[ClassNameLen] = '\0';
|
|
|
|
NpResult = RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"" LAUNCHER_REGKEY,
|
|
0, LAUNCHER_REGKEY_WOW64 | KEY_READ, &RegKey);
|
|
if (ERROR_SUCCESS != NpResult)
|
|
goto exit;
|
|
|
|
RegSize = sizeof Credentials;
|
|
Credentials = 0; /* default is NO credentials */
|
|
NpResult = RegGetValueW(RegKey, ClassNameBuf, L"Credentials", RRF_RT_REG_DWORD, 0,
|
|
&Credentials, &RegSize);
|
|
if (ERROR_SUCCESS != NpResult && ERROR_FILE_NOT_FOUND != NpResult)
|
|
goto exit;
|
|
|
|
switch (Credentials)
|
|
{
|
|
case FSP_NP_CREDENTIALS_NONE:
|
|
case FSP_NP_CREDENTIALS_PASSWORD:
|
|
case FSP_NP_CREDENTIALS_USERPASS:
|
|
*PCredentialsKind = Credentials;
|
|
break;
|
|
}
|
|
|
|
NpResult = ERROR_SUCCESS;
|
|
|
|
exit:
|
|
if (0 != RegKey)
|
|
RegCloseKey(RegKey);
|
|
|
|
return NpResult;
|
|
}
|
|
|
|
static DWORD FspNpGetCredentials(
|
|
HWND hwndOwner, PWSTR Caption, DWORD PrevNpResult,
|
|
DWORD CredentialsKind,
|
|
PBOOL PSave,
|
|
PWSTR UserName, ULONG UserNameSize/* in chars */,
|
|
PWSTR Password, ULONG PasswordSize/* in chars */)
|
|
{
|
|
DWORD NpResult;
|
|
CREDUI_INFOW UiInfo;
|
|
|
|
memset(&UiInfo, 0, sizeof UiInfo);
|
|
UiInfo.cbSize = sizeof UiInfo;
|
|
UiInfo.hwndParent = hwndOwner;
|
|
UiInfo.pszCaptionText = Caption;
|
|
UiInfo.pszMessageText = L"Enter credentials to unlock this file system.";
|
|
|
|
#if !defined(FSP_NP_CREDUI_PROMPT_NEW)
|
|
NpResult = CredUIPromptForCredentialsW(&UiInfo, L"NONE", 0, 0,
|
|
UserName, UserNameSize,
|
|
Password, PasswordSize,
|
|
PSave,
|
|
CREDUI_FLAGS_GENERIC_CREDENTIALS |
|
|
CREDUI_FLAGS_DO_NOT_PERSIST |
|
|
CREDUI_FLAGS_ALWAYS_SHOW_UI |
|
|
(0 != PrevNpResult ? CREDUI_FLAGS_INCORRECT_PASSWORD : 0) |
|
|
(0 != PSave ? CREDUI_FLAGS_SHOW_SAVE_CHECK_BOX : 0) |
|
|
(FSP_NP_CREDENTIALS_PASSWORD == CredentialsKind ? 0/*CREDUI_FLAGS_KEEP_USERNAME*/ : 0));
|
|
#else
|
|
WCHAR Domain[CREDUI_MAX_DOMAIN_TARGET_LENGTH + 1];
|
|
ULONG AuthPackage = 0;
|
|
PVOID InAuthBuf = 0, OutAuthBuf = 0;
|
|
ULONG InAuthSize, OutAuthSize, DomainSize;
|
|
|
|
InAuthSize = 0;
|
|
if (!CredPackAuthenticationBufferW(
|
|
CRED_PACK_GENERIC_CREDENTIALS, UserName, Password, 0, &InAuthSize) &&
|
|
ERROR_INSUFFICIENT_BUFFER != GetLastError())
|
|
{
|
|
NpResult = GetLastError();
|
|
goto exit;
|
|
}
|
|
|
|
InAuthBuf = MemAlloc(InAuthSize);
|
|
if (0 == InAuthBuf)
|
|
{
|
|
NpResult = ERROR_NO_SYSTEM_RESOURCES;
|
|
goto exit;
|
|
}
|
|
|
|
if (!CredPackAuthenticationBufferW(
|
|
CRED_PACK_GENERIC_CREDENTIALS, UserName, Password, InAuthBuf, &InAuthSize))
|
|
{
|
|
NpResult = GetLastError();
|
|
goto exit;
|
|
}
|
|
|
|
NpResult = CredUIPromptForWindowsCredentialsW(&UiInfo, PrevNpResult,
|
|
&AuthPackage, InAuthBuf, InAuthSize, &OutAuthBuf, &OutAuthSize, PSave,
|
|
CREDUIWIN_GENERIC | (0 != PSave ? CREDUIWIN_CHECKBOX : 0));
|
|
if (ERROR_SUCCESS != NpResult)
|
|
goto exit;
|
|
|
|
DomainSize = sizeof Domain / sizeof Domain[0];
|
|
if (!CredUnPackAuthenticationBufferW(0, OutAuthBuf, OutAuthSize,
|
|
UserName, &UserNameSize, Domain, &DomainSize, Password, &PasswordSize))
|
|
{
|
|
NpResult = GetLastError();
|
|
goto exit;
|
|
}
|
|
|
|
NpResult = ERROR_SUCCESS;
|
|
|
|
exit:
|
|
if (0 != OutAuthBuf)
|
|
{
|
|
SecureZeroMemory(OutAuthBuf, OutAuthSize);
|
|
CoTaskMemFree(OutAuthBuf);
|
|
}
|
|
|
|
if (0 != InAuthBuf)
|
|
{
|
|
SecureZeroMemory(InAuthBuf, InAuthSize);
|
|
MemFree(InAuthBuf);
|
|
}
|
|
#endif
|
|
|
|
return NpResult;
|
|
}
|
|
|
|
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 (!FspNpCheckLocalName(lpLocalName))
|
|
return WN_BAD_LOCALNAME;
|
|
|
|
LocalNameBuf[0] = lpLocalName[0] & ~0x20; /* convert to uppercase */
|
|
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 == invariant_wcscmp(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;
|
|
}
|
|
|
|
DWORD APIENTRY NPAddConnection(LPNETRESOURCEW lpNetResource, LPWSTR lpPassword, LPWSTR lpUserName)
|
|
{
|
|
DWORD NpResult;
|
|
DWORD dwType = lpNetResource->dwType;
|
|
LPWSTR lpRemoteName = lpNetResource->lpRemoteName;
|
|
LPWSTR lpLocalName = lpNetResource->lpLocalName;
|
|
WCHAR LocalNameBuf[3];
|
|
PWSTR ClassName, InstanceName, RemoteName, P;
|
|
ULONG ClassNameLen, InstanceNameLen;
|
|
DWORD CredentialsKind;
|
|
PWSTR PipeBuf = 0;
|
|
#if defined(FSP_NP_CREDENTIAL_MANAGER)
|
|
PCREDENTIALW Credential = 0;
|
|
#endif
|
|
|
|
if (dwType & RESOURCETYPE_PRINT)
|
|
return WN_BAD_VALUE;
|
|
|
|
if (!FspNpParseRemoteName(lpRemoteName,
|
|
&ClassName, &ClassNameLen, &InstanceName, &InstanceNameLen))
|
|
return WN_BAD_NETNAME;
|
|
RemoteName = lpRemoteName + 1;
|
|
|
|
LocalNameBuf[0] = L'\0';
|
|
if (0 != lpLocalName && L'\0' != lpLocalName[0])
|
|
{
|
|
if (!FspNpCheckLocalName(lpLocalName))
|
|
return WN_BAD_LOCALNAME;
|
|
|
|
LocalNameBuf[0] = lpLocalName[0] & ~0x20; /* convert to uppercase */
|
|
LocalNameBuf[1] = L':';
|
|
LocalNameBuf[2] = L'\0';
|
|
|
|
if (GetLogicalDrives() & (1 << (LocalNameBuf[0] - 'A')))
|
|
return WN_ALREADY_CONNECTED;
|
|
}
|
|
|
|
FspNpGetCredentialsKind(lpRemoteName, &CredentialsKind);
|
|
|
|
#if defined(FSP_NP_CREDENTIAL_MANAGER)
|
|
/* if we need credentials and none were passed check with the credential manager */
|
|
if (FSP_NP_CREDENTIALS_NONE != CredentialsKind && 0 == lpPassword &&
|
|
CredReadW(lpRemoteName, CRED_TYPE_GENERIC, 0, &Credential))
|
|
{
|
|
if (sizeof(WCHAR) <= Credential->CredentialBlobSize &&
|
|
L'\0' == ((PWSTR)(Credential->CredentialBlob))
|
|
[(Credential->CredentialBlobSize / sizeof(WCHAR)) - 1])
|
|
{
|
|
lpUserName = Credential->UserName;
|
|
lpPassword = (PVOID)Credential->CredentialBlob;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
/* if we need credentials and we don't have any return ACCESS DENIED */
|
|
if (FSP_NP_CREDENTIALS_NONE != CredentialsKind)
|
|
{
|
|
int Length;
|
|
if (0 == lpPassword ||
|
|
(0 == (Length = lstrlenW(lpPassword))) || CREDUI_MAX_PASSWORD_LENGTH < Length)
|
|
{
|
|
NpResult = WN_ACCESS_DENIED;
|
|
goto exit;
|
|
}
|
|
}
|
|
if (FSP_NP_CREDENTIALS_USERPASS == CredentialsKind)
|
|
{
|
|
int Length;
|
|
if (0 == lpUserName ||
|
|
(0 == (Length = lstrlenW(lpUserName))) || CREDUI_MAX_USERNAME_LENGTH < Length)
|
|
{
|
|
NpResult = WN_ACCESS_DENIED;
|
|
goto exit;
|
|
}
|
|
}
|
|
|
|
PipeBuf = MemAlloc(LAUNCHER_PIPE_BUFFER_SIZE);
|
|
if (0 == PipeBuf)
|
|
{
|
|
NpResult = WN_OUT_OF_MEMORY;
|
|
goto exit;
|
|
}
|
|
|
|
/* we do not explicitly check, but assumption is it all fits in LAUNCHER_PIPE_BUFFER_SIZE */
|
|
P = PipeBuf;
|
|
*P++ = FSP_NP_CREDENTIALS_NONE != CredentialsKind ?
|
|
LauncherSvcInstanceStartWithSecret : LauncherSvcInstanceStart;
|
|
memcpy(P, ClassName, ClassNameLen * sizeof(WCHAR)); P += ClassNameLen; *P++ = L'\0';
|
|
memcpy(P, InstanceName, InstanceNameLen * sizeof(WCHAR)); P += InstanceNameLen; *P++ = L'\0';
|
|
lstrcpyW(P, RemoteName); P += lstrlenW(RemoteName) + 1;
|
|
lstrcpyW(P, LocalNameBuf); P += lstrlenW(LocalNameBuf) + 1;
|
|
if (FSP_NP_CREDENTIALS_USERPASS == CredentialsKind)
|
|
{
|
|
lstrcpyW(P, lpUserName); P += lstrlenW(lpUserName) + 1;
|
|
}
|
|
if (FSP_NP_CREDENTIALS_NONE != CredentialsKind)
|
|
{
|
|
lstrcpyW(P, lpPassword); P += lstrlenW(lpPassword) + 1;
|
|
}
|
|
|
|
NpResult = FspNpCallLauncherPipe(
|
|
PipeBuf, (ULONG)(P - PipeBuf) * sizeof(WCHAR), LAUNCHER_PIPE_BUFFER_SIZE);
|
|
switch (NpResult)
|
|
{
|
|
case WN_SUCCESS:
|
|
/*
|
|
* The Launcher is reporting success. Wait until we can access the new volume
|
|
* root directory. If we see it report success, otherwise report error.
|
|
*/
|
|
{
|
|
WCHAR RemoteNameBuf[9 + sizeof(((FSP_FSCTL_VOLUME_PARAMS *)0)->Prefix) / sizeof(WCHAR)];
|
|
HANDLE Handle;
|
|
|
|
if (L'\0' != LocalNameBuf[0])
|
|
{
|
|
P = RemoteNameBuf;
|
|
*P++ = L'\\'; *P++ = L'\\'; *P++ = L'?'; *P++ = L'\\';
|
|
*P++ = LocalNameBuf[0]; *P++ = L':'; *P++ = L'\\';
|
|
*P++ = L'\0';
|
|
}
|
|
else
|
|
{
|
|
P = RemoteNameBuf;
|
|
*P++ = L'\\'; *P++ = L'\\'; *P++ = L'?'; *P++ = L'\\';
|
|
*P++ = L'U'; *P++ = L'N'; *P++ = L'C'; *P++ = L'\\';
|
|
memcpy(P, ClassName, ClassNameLen * sizeof(WCHAR)); P += ClassNameLen; *P++ = L'\\';
|
|
memcpy(P, InstanceName, InstanceNameLen * sizeof(WCHAR)); P += InstanceNameLen; *P++ = L'\\';
|
|
*P++ = L'\0';
|
|
}
|
|
|
|
NpResult = WN_NO_NETWORK; /* timeout error */
|
|
|
|
for (ULONG I = 0, N = 1 + FSP_NP_ADDCONNECTION_TIMEOUT / 500; N > I; I++)
|
|
{
|
|
if (0 != I)
|
|
Sleep(500);
|
|
|
|
Handle = CreateFileW(RemoteNameBuf,
|
|
FILE_READ_ATTRIBUTES, 0, 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
|
|
if (INVALID_HANDLE_VALUE != Handle)
|
|
{
|
|
/* the file system is up and running */
|
|
CloseHandle(Handle);
|
|
NpResult = WN_SUCCESS;
|
|
break;
|
|
}
|
|
|
|
P = PipeBuf;
|
|
*P++ = LauncherSvcInstanceInfo;
|
|
memcpy(P, ClassName, ClassNameLen * sizeof(WCHAR)); P += ClassNameLen; *P++ = L'\0';
|
|
memcpy(P, InstanceName, InstanceNameLen * sizeof(WCHAR)); P += InstanceNameLen; *P++ = L'\0';
|
|
|
|
if (WN_SUCCESS != FspNpCallLauncherPipe(
|
|
PipeBuf, (ULONG)(P - PipeBuf) * sizeof(WCHAR), LAUNCHER_PIPE_BUFFER_SIZE))
|
|
{
|
|
/* looks like the file system is gone! */
|
|
NpResult = WN_NO_NETWORK;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case WN_ACCESS_DENIED:
|
|
break;
|
|
case ERROR_ALREADY_EXISTS:
|
|
/*
|
|
* The file system is already running! If we are being asked for a drive mapping,
|
|
* see if it is the one we already have to decide on the error code to return.
|
|
*/
|
|
if (L'\0' != LocalNameBuf[0])
|
|
{
|
|
WCHAR ExpectRemoteNameBuf[sizeof(((FSP_FSCTL_VOLUME_PARAMS *)0)->Prefix) / sizeof(WCHAR)];
|
|
WCHAR RemoteNameBuf[sizeof(((FSP_FSCTL_VOLUME_PARAMS *)0)->Prefix) / sizeof(WCHAR)];
|
|
DWORD RemoteNameSize;
|
|
|
|
P = ExpectRemoteNameBuf;
|
|
*P++ = L'\\'; *P++ = L'\\';
|
|
memcpy(P, ClassName, ClassNameLen * sizeof(WCHAR)); P += ClassNameLen; *P++ = L'\\';
|
|
memcpy(P, InstanceName, InstanceNameLen * sizeof(WCHAR)); P += InstanceNameLen; *P++ = L'\0';
|
|
|
|
RemoteNameSize = sizeof RemoteNameBuf / sizeof(WCHAR);
|
|
NpResult = NPGetConnection(LocalNameBuf, RemoteNameBuf, &RemoteNameSize);
|
|
if (WN_SUCCESS == NpResult)
|
|
NpResult = 0 == invariant_wcscmp(ExpectRemoteNameBuf, RemoteNameBuf) ? WN_SUCCESS : WN_NO_NETWORK;
|
|
else
|
|
NpResult = WN_NO_NETWORK;
|
|
}
|
|
else
|
|
/* we are not being asked for a drive mapping, so whatever we have is good! */
|
|
NpResult = WN_SUCCESS;
|
|
break;
|
|
default:
|
|
NpResult = WN_NO_NETWORK;
|
|
break;
|
|
}
|
|
|
|
exit:
|
|
MemFree(PipeBuf);
|
|
|
|
#if defined(FSP_NP_CREDENTIAL_MANAGER)
|
|
if (0 != Credential)
|
|
CredFree(Credential);
|
|
#endif
|
|
|
|
return NpResult;
|
|
}
|
|
|
|
DWORD APIENTRY NPAddConnection3(HWND hwndOwner,
|
|
LPNETRESOURCEW lpNetResource, LPWSTR lpPassword, LPWSTR lpUserName, DWORD dwFlags)
|
|
{
|
|
DWORD NpResult;
|
|
PWSTR RemoteName = lpNetResource->lpRemoteName;
|
|
DWORD CredentialsKind;
|
|
WCHAR UserName[CREDUI_MAX_USERNAME_LENGTH + 1], Password[CREDUI_MAX_PASSWORD_LENGTH + 1];
|
|
#if defined(FSP_NP_CREDENTIAL_MANAGER)
|
|
BOOL Save = TRUE;
|
|
#endif
|
|
|
|
//dwFlags |= CONNECT_INTERACTIVE | CONNECT_PROMPT; /* TESTING ONLY! */
|
|
|
|
/* CONNECT_PROMPT is only valid if CONNECT_INTERACTIVE is also set */
|
|
if (CONNECT_PROMPT == (dwFlags & (CONNECT_INTERACTIVE | CONNECT_PROMPT)))
|
|
return WN_BAD_VALUE;
|
|
|
|
/* if not CONNECT_PROMPT go ahead and attempt to NPAddConnection once */
|
|
if (0 == (dwFlags & CONNECT_PROMPT))
|
|
{
|
|
NpResult = NPAddConnection(lpNetResource, lpPassword, lpUserName);
|
|
if (WN_ACCESS_DENIED != NpResult || 0 == (dwFlags & CONNECT_INTERACTIVE))
|
|
return NpResult;
|
|
}
|
|
|
|
FspNpGetCredentialsKind(RemoteName, &CredentialsKind);
|
|
if (FSP_NP_CREDENTIALS_NONE == CredentialsKind)
|
|
return WN_CANCEL;
|
|
|
|
/* if CONNECT_INTERACTIVE keep asking the user for valid credentials or cancel */
|
|
NpResult = WN_SUCCESS;
|
|
lstrcpyW(UserName, L"UNSPECIFIED");
|
|
Password[0] = L'\0';
|
|
if (FSP_NP_CREDENTIALS_PASSWORD == CredentialsKind)
|
|
FspNpParseUserName(RemoteName, UserName, sizeof UserName / sizeof UserName[0]);
|
|
do
|
|
{
|
|
NpResult = FspNpGetCredentials(
|
|
hwndOwner, RemoteName, NpResult,
|
|
CredentialsKind,
|
|
#if defined(FSP_NP_CREDENTIAL_MANAGER)
|
|
&Save,
|
|
#else
|
|
0,
|
|
#endif
|
|
UserName, sizeof UserName / sizeof UserName[0],
|
|
Password, sizeof Password / sizeof Password[0]);
|
|
if (WN_SUCCESS != NpResult)
|
|
break;
|
|
|
|
NpResult = NPAddConnection(lpNetResource, Password, UserName);
|
|
} while (WN_ACCESS_DENIED == NpResult);
|
|
|
|
#if defined(FSP_NP_CREDENTIAL_MANAGER)
|
|
if (WN_SUCCESS == NpResult && Save)
|
|
{
|
|
CREDENTIALW Credential;
|
|
|
|
memset(&Credential, 0, sizeof Credential);
|
|
Credential.Type = CRED_TYPE_GENERIC;
|
|
Credential.Persist = CRED_PERSIST_LOCAL_MACHINE;
|
|
Credential.TargetName = RemoteName;
|
|
Credential.UserName = UserName;
|
|
Credential.CredentialBlobSize = (lstrlenW(Password) + 1) * sizeof(WCHAR);
|
|
Credential.CredentialBlob = (PVOID)Password;
|
|
|
|
CredWriteW(&Credential, 0);
|
|
}
|
|
#endif
|
|
|
|
SecureZeroMemory(Password, sizeof Password);
|
|
|
|
return NpResult;
|
|
}
|
|
|
|
DWORD APIENTRY NPCancelConnection(LPWSTR lpName, BOOL fForce)
|
|
{
|
|
DWORD NpResult;
|
|
WCHAR RemoteNameBuf[sizeof(((FSP_FSCTL_VOLUME_PARAMS *)0)->Prefix) / sizeof(WCHAR)];
|
|
DWORD RemoteNameSize;
|
|
PWSTR ClassName, InstanceName, RemoteName, P;
|
|
ULONG ClassNameLen, InstanceNameLen;
|
|
PWSTR PipeBuf = 0;
|
|
|
|
if (FspNpCheckLocalName(lpName))
|
|
{
|
|
RemoteNameSize = sizeof RemoteNameBuf / sizeof(WCHAR);
|
|
NpResult = NPGetConnection(lpName, RemoteNameBuf, &RemoteNameSize);
|
|
if (WN_SUCCESS != NpResult)
|
|
return NpResult;
|
|
|
|
RemoteName = RemoteNameBuf;
|
|
}
|
|
else if (FspNpCheckRemoteName(lpName))
|
|
RemoteName = lpName;
|
|
else
|
|
return WN_BAD_NETNAME;
|
|
|
|
if (!FspNpParseRemoteName(RemoteName,
|
|
&ClassName, &ClassNameLen, &InstanceName, &InstanceNameLen))
|
|
return WN_BAD_NETNAME;
|
|
|
|
PipeBuf = MemAlloc(LAUNCHER_PIPE_BUFFER_SIZE);
|
|
if (0 == PipeBuf)
|
|
return WN_OUT_OF_MEMORY;
|
|
|
|
P = PipeBuf;
|
|
*P++ = LauncherSvcInstanceStop;
|
|
memcpy(P, ClassName, ClassNameLen * sizeof(WCHAR)); P += ClassNameLen; *P++ = L'\0';
|
|
memcpy(P, InstanceName, InstanceNameLen * sizeof(WCHAR)); P += InstanceNameLen; *P++ = L'\0';
|
|
|
|
NpResult = FspNpCallLauncherPipe(
|
|
PipeBuf, (ULONG)(P - PipeBuf) * sizeof(WCHAR), LAUNCHER_PIPE_BUFFER_SIZE);
|
|
switch (NpResult)
|
|
{
|
|
case WN_SUCCESS:
|
|
break;
|
|
case ERROR_FILE_NOT_FOUND:
|
|
NpResult = WN_NOT_CONNECTED;
|
|
break;
|
|
default:
|
|
NpResult = WN_NO_NETWORK;
|
|
break;
|
|
}
|
|
|
|
MemFree(PipeBuf);
|
|
|
|
return NpResult;
|
|
}
|
|
|
|
typedef struct
|
|
{
|
|
DWORD Signature; /* cheap and cheerful! */
|
|
DWORD dwScope;
|
|
PWCHAR VolumeListBuf, VolumeListBufEnd, VolumeName;
|
|
DWORD LogicalDrives;
|
|
} FSP_NP_ENUM;
|
|
|
|
static inline BOOLEAN FspNpValidateEnum(FSP_NP_ENUM *Enum)
|
|
{
|
|
#if 0
|
|
return
|
|
0 != Enum &&
|
|
HeapValidate(GetProcessHeap(), 0, Enum) &&
|
|
'munE' == Enum->Signature;
|
|
#else
|
|
return
|
|
0 != Enum &&
|
|
'munE' == Enum->Signature;
|
|
#endif
|
|
}
|
|
|
|
DWORD APIENTRY NPOpenEnum(
|
|
DWORD dwScope, DWORD dwType, DWORD dwUsage, LPNETRESOURCEW lpNetResource, LPHANDLE lphEnum)
|
|
{
|
|
NTSTATUS Result;
|
|
FSP_NP_ENUM *Enum = 0;
|
|
SIZE_T VolumeListSize;
|
|
|
|
switch (dwScope)
|
|
{
|
|
case RESOURCE_CONNECTED:
|
|
case RESOURCE_CONTEXT:
|
|
/* ignore lpNetResource; according to documentation it should be NULL */
|
|
break;
|
|
default:
|
|
return WN_NOT_SUPPORTED;
|
|
}
|
|
|
|
if (dwType & RESOURCETYPE_PRINT)
|
|
return WN_BAD_VALUE;
|
|
|
|
Enum = MemAlloc(sizeof *Enum);
|
|
if (0 == Enum)
|
|
return WN_OUT_OF_MEMORY;
|
|
|
|
Result = FspNpGetVolumeList(&Enum->VolumeListBuf, &VolumeListSize);
|
|
if (!NT_SUCCESS(Result))
|
|
{
|
|
MemFree(Enum);
|
|
return WN_OUT_OF_MEMORY;
|
|
}
|
|
|
|
Enum->Signature = 'munE';
|
|
Enum->dwScope = dwScope;
|
|
Enum->VolumeListBufEnd = (PVOID)((PUINT8)Enum->VolumeListBuf + VolumeListSize);
|
|
Enum->VolumeName = Enum->VolumeListBuf;
|
|
Enum->LogicalDrives = GetLogicalDrives();
|
|
|
|
*lphEnum = Enum;
|
|
|
|
return WN_SUCCESS;
|
|
}
|
|
|
|
DWORD APIENTRY NPEnumResource(
|
|
HANDLE hEnum, LPDWORD lpcCount, LPVOID lpBuffer, LPDWORD lpBufferSize)
|
|
{
|
|
FSP_NP_ENUM *Enum = hEnum;
|
|
DWORD NpResult;
|
|
LPNETRESOURCEW Resource; /* grows upwards */
|
|
PWCHAR Strings; /* grows downwards */
|
|
PWCHAR ProviderName = 0;
|
|
DWORD Count;
|
|
PWCHAR P, VolumePrefix;
|
|
ULONG Backslashes;
|
|
WCHAR Drive;
|
|
|
|
if (!FspNpValidateEnum(Enum))
|
|
return WN_BAD_HANDLE;
|
|
|
|
if (0 == lpcCount || 0 == lpBuffer || 0 == lpBufferSize)
|
|
return WN_BAD_VALUE;
|
|
|
|
Resource = lpBuffer;
|
|
Strings = (PVOID)((PUINT8)lpBuffer + (*lpBufferSize & ~1/* WCHAR alignment */));
|
|
Count = 0;
|
|
for (P = Enum->VolumeName; *lpcCount > Count && Enum->VolumeListBufEnd > P; P++)
|
|
{
|
|
if (L'\0' == *P)
|
|
{
|
|
/*
|
|
* 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.
|
|
*/
|
|
|
|
for (Backslashes = 0, VolumePrefix = Enum->VolumeName; VolumePrefix < P; VolumePrefix++)
|
|
if (L'\\' == *VolumePrefix)
|
|
if (3 == ++Backslashes)
|
|
break;
|
|
|
|
if (3 == Backslashes)
|
|
{
|
|
Drive = FspNpGetDriveLetter(&Enum->LogicalDrives, Enum->VolumeName);
|
|
|
|
Strings -= (Drive ? 3 : 0) + 2/* backslash + term-0 */ + lstrlenW(VolumePrefix) +
|
|
(0 == ProviderName ? lstrlenW(L"" FSP_NP_NAME) + 1 : 0);
|
|
|
|
if ((PVOID)(Resource + 1) > (PVOID)Strings)
|
|
{
|
|
if (0 == Count)
|
|
{
|
|
*lpBufferSize =
|
|
(DWORD)((PUINT8)(Resource + 1) - (PUINT8)lpBuffer) +
|
|
(DWORD)((PUINT8)lpBuffer + *lpBufferSize - (PUINT8)Strings);
|
|
NpResult = WN_MORE_DATA;
|
|
}
|
|
else
|
|
{
|
|
*lpcCount = Count;
|
|
NpResult = WN_SUCCESS;
|
|
}
|
|
|
|
goto exit;
|
|
}
|
|
|
|
if (0 == ProviderName)
|
|
{
|
|
ProviderName = Strings + (Drive ? 3 : 0) + 2/* backslash + term-0 */ + lstrlenW(VolumePrefix);
|
|
lstrcpyW(ProviderName, L"" FSP_NP_NAME);
|
|
}
|
|
|
|
if (Drive)
|
|
{
|
|
Strings[0] = Drive;
|
|
Strings[1] = L':';
|
|
Strings[2] = L'\0';
|
|
|
|
Strings[3] = L'\\';
|
|
lstrcpyW(Strings + 4, VolumePrefix);
|
|
}
|
|
else
|
|
{
|
|
Strings[0] = L'\\';
|
|
lstrcpyW(Strings + 1, VolumePrefix);
|
|
}
|
|
|
|
Resource->dwScope = Enum->dwScope;
|
|
Resource->dwType = RESOURCETYPE_DISK;
|
|
Resource->dwDisplayType = RESOURCEDISPLAYTYPE_SHARE;
|
|
Resource->dwUsage = RESOURCEUSAGE_CONNECTABLE;
|
|
Resource->lpLocalName = Drive ? Strings : 0;
|
|
Resource->lpRemoteName = Drive ? Strings + 3 : Strings;
|
|
Resource->lpComment = 0;
|
|
Resource->lpProvider = ProviderName;
|
|
Resource++;
|
|
|
|
Count++;
|
|
}
|
|
|
|
Enum->VolumeName = P + 1;
|
|
}
|
|
}
|
|
|
|
if (0 == Count)
|
|
NpResult = WN_NO_MORE_ENTRIES;
|
|
else
|
|
{
|
|
*lpcCount = Count;
|
|
NpResult = WN_SUCCESS;
|
|
}
|
|
|
|
exit:
|
|
return NpResult;
|
|
}
|
|
|
|
DWORD APIENTRY NPCloseEnum(HANDLE hEnum)
|
|
{
|
|
FSP_NP_ENUM *Enum = hEnum;
|
|
|
|
if (!FspNpValidateEnum(Enum))
|
|
return WN_BAD_HANDLE;
|
|
|
|
MemFree(Enum->VolumeListBuf);
|
|
MemFree(Enum);
|
|
|
|
return WN_SUCCESS;
|
|
}
|
|
|
|
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 (0 == invariant_wcsncmp(Part, L"" FSP_NP_NAME, P - Part))
|
|
{
|
|
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 (0 == invariant_wcsncmp(Part, L"" FSP_NP_NAME, P - Part))
|
|
{
|
|
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);
|
|
}
|