/**
 * @file dll/np.c
 *
 * @copyright 2015-2026 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 software
 * in accordance with the commercial license agreement provided in
 * conjunction with the software.  The terms and conditions of any such
 * commercial license agreement shall govern, supersede, and render
 * ineffective any application of the GPLv3 license to this software,
 * notwithstanding of any reference thereto in the software or
 * associated repository.
 */

#include <dll/library.h>
#include <npapi.h>
#include <wincred.h>

#define _NTDEF_
#include <ntsecapi.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

/*
 * Define the following macro to register ourselves as the first network provider.
 * Otherwise we will be registered as the last network provider.
 */
#define FSP_NP_ORDER_FIRST

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 FspNpParseRemoteUserName(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(
    WCHAR Command, ULONG Argc, PWSTR *Argv, ULONG *Argl,
    PWSTR Buffer, PULONG PSize,
    BOOLEAN AllowImpersonation)
{
    NTSTATUS Result;
    ULONG ErrorCode;

    Result = FspLaunchCallLauncherPipeEx(Command, Argc, Argv, Argl, Buffer, PSize, AllowImpersonation,
        &ErrorCode);
    return !NT_SUCCESS(Result) ?
        WN_NO_NETWORK :
        (ERROR_BROKEN_PIPE == ErrorCode ? WN_NO_NETWORK : ErrorCode);
}

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 NTSTATUS FspNpGetAuthPackage(PWSTR AuthPackageName, PULONG PAuthPackage)
{
    HANDLE LsaHandle;
    BOOLEAN LsaHandleValid = FALSE;
    CHAR LsaAuthPackageNameBuf[127]; /* "The package name must not exceed 127 bytes in length." */
    LSA_STRING LsaAuthPackageName;
    ULONG AuthPackage;
    NTSTATUS Result;

    *PAuthPackage = 0;

    Result = LsaConnectUntrusted(&LsaHandle);
    if (!NT_SUCCESS(Result))
        goto exit;
    LsaHandleValid = TRUE;

    LsaAuthPackageName.MaximumLength = sizeof LsaAuthPackageNameBuf;
    LsaAuthPackageName.Buffer = LsaAuthPackageNameBuf;
    LsaAuthPackageName.Length = WideCharToMultiByte(CP_UTF8, 0,
        AuthPackageName, lstrlenW(AuthPackageName),
        LsaAuthPackageNameBuf, sizeof LsaAuthPackageNameBuf,
        0, 0);
    if (0 == LsaAuthPackageName.Length)
    {
        Result = FspNtStatusFromWin32(GetLastError());
        goto exit;
    }

    Result = LsaLookupAuthenticationPackage(LsaHandle, &LsaAuthPackageName, &AuthPackage);
    if (!NT_SUCCESS(Result))
        goto exit;

    *PAuthPackage = AuthPackage;
    Result = STATUS_SUCCESS;

exit:
    if (LsaHandleValid)
        LsaDeregisterLogonProcess(LsaHandle);

    return Result;
}

static DWORD FspNpGetRemoteInfo(PWSTR RemoteName,
    PDWORD PAuthPackage, PDWORD PCredentialsKind, PBOOLEAN PAllowImpersonation)
{
    PWSTR ClassName, InstanceName;
    ULONG ClassNameLen, InstanceNameLen;
    WCHAR ClassNameBuf[sizeof(((FSP_FSCTL_VOLUME_PARAMS *)0)->Prefix) / sizeof(WCHAR)];
    FSP_LAUNCH_REG_RECORD *Record;
    NTSTATUS Result;

    if (0 != PAuthPackage)
        *PAuthPackage = 0;

    if (0 != PCredentialsKind)
        *PCredentialsKind = FSP_NP_CREDENTIALS_NONE;

    if (0 != PAllowImpersonation)
        *PAllowImpersonation = FALSE;

    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';

    Result = FspLaunchRegGetRecord(ClassNameBuf, L"" FSP_NP_NAME, &Record);
    if (!NT_SUCCESS(Result))
        return WN_NO_NETWORK;

    if (0 != PAuthPackage)
    {
        if (0 != Record->AuthPackage)
        {
            ULONG AuthPackage = 0;

            Result = FspNpGetAuthPackage(Record->AuthPackage, &AuthPackage);
            if (!NT_SUCCESS(Result))
                return WN_NO_NETWORK;

            *PAuthPackage = AuthPackage + 1;            /* ensure non-0 (Negotiate AuthPackage == 0) */
        }
        else if (0 != Record->AuthPackageId)
            *PAuthPackage = Record->AuthPackageId + 1;  /* ensure non-0 (Negotiate AuthPackage == 0) */
    }

    if (0 != PCredentialsKind)
        switch (Record->Credentials)
        {
        case FSP_NP_CREDENTIALS_NONE:
        case FSP_NP_CREDENTIALS_PASSWORD:
        case FSP_NP_CREDENTIALS_USERPASS:
            *PCredentialsKind = Record->Credentials;
            break;
        }

    if (0 != PAllowImpersonation)
        *PAllowImpersonation = 0 != Record->RunAs &&
            L'.' == Record->RunAs[0] && L'\0' == Record->RunAs[1];

    FspLaunchRegFreeRecord(Record);

    return WN_SUCCESS;
}

static DWORD FspNpGetCredentials(
    HWND hwndOwner, PWSTR Caption, DWORD PrevNpResult,
    DWORD AuthPackage0, 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 != AuthPackage0 ? AuthPackage0 - 1 : 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,
        (0 != AuthPackage0 ? CREDUIWIN_AUTHPACKAGE_ONLY : 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;
}

static BOOLEAN FspNpCheckRemoteVolume(PWSTR RemoteName)
{
    PWSTR ClassName, InstanceName, P;
    ULONG ClassNameLen, InstanceNameLen;
    WCHAR RemoteNameBuf[9 + sizeof(((FSP_FSCTL_VOLUME_PARAMS *)0)->Prefix) / sizeof(WCHAR)];
    HANDLE Handle;
    DWORD Bytes;
    BOOLEAN Result;

    if (!FspNpParseRemoteName(RemoteName,
        &ClassName, &ClassNameLen, &InstanceName, &InstanceNameLen))
        return FALSE;

    Result = FALSE;

    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';

    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; is it WinFsp? */
        if (DeviceIoControl(Handle, FSP_FSCTL_QUERY_WINFSP, 0, 0, 0, 0, &Bytes, 0))
            Result = TRUE;
        CloseHandle(Handle);
    }

    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 (!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_NOT_CONNECTED;

    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;
    BOOLEAN AllowImpersonation;
    ULONG Argc;
    PWSTR Argv[6];
    ULONG Argl[6];
#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;
    }

    NpResult = FspNpGetRemoteInfo(lpRemoteName, 0, &CredentialsKind, &AllowImpersonation);
    if (WN_SUCCESS != NpResult)
    {
        /*
         * This may still be a WinFsp network file system, but not managed by the Launcher.
         * So if it is already live, one of ours and we do not need to map a drive, then go
         * ahead and report success.
         */
        if (L'\0' == LocalNameBuf[0] && FspNpCheckRemoteVolume(lpRemoteName))
            NpResult = WN_SUCCESS;
        return NpResult;
    }

#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;
        }
    }

    Argc = 0;
    Argv[Argc] = ClassName; Argl[Argc] = ClassNameLen; Argc++;
    Argv[Argc] = InstanceName; Argl[Argc] = InstanceNameLen; Argc++;
    Argv[Argc] = RemoteName; Argl[Argc] = -1; Argc++;
    Argv[Argc] = LocalNameBuf; Argl[Argc] = -1; Argc++;
    if (FSP_NP_CREDENTIALS_USERPASS == CredentialsKind)
    {
        Argv[Argc] = lpUserName; Argl[Argc] = -1; Argc++;
    }
    if (FSP_NP_CREDENTIALS_NONE != CredentialsKind)
    {
        Argv[Argc] = lpPassword; Argl[Argc] = -1; Argc++;
    }

    NpResult = FspNpCallLauncherPipe(
        FSP_NP_CREDENTIALS_NONE != CredentialsKind ? FspLaunchCmdStartWithSecret : FspLaunchCmdStart,
        Argc, Argv, Argl, 0, 0,
        AllowImpersonation);
    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;
                }

                Argc = 0;
                Argv[Argc] = ClassName; Argl[Argc] = ClassNameLen; Argc++;
                Argv[Argc] = InstanceName; Argl[Argc] = InstanceNameLen; Argc++;

                if (WN_SUCCESS != FspNpCallLauncherPipe(
                    FspLaunchCmdGetInfo,
                    Argc, Argv, Argl, 0, 0,
                    FALSE))
                {
                    /* 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;
    case WN_NO_NETWORK:
        /*
         * This may still be a WinFsp network file system, but not managed by the Launcher.
         * So if it is already live, one of ours and we do not need to map a drive, then go
         * ahead and report success.
         */
        if (L'\0' == LocalNameBuf[0] && FspNpCheckRemoteVolume(lpRemoteName))
            NpResult = WN_SUCCESS;
        break;
    default:
        NpResult = WN_NO_NETWORK;
        break;
    }

exit:
#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 AuthPackage, CredentialsKind;
    WCHAR UserName[CREDUI_MAX_USERNAME_LENGTH + 1], Password[CREDUI_MAX_PASSWORD_LENGTH + 1];
#if defined(FSP_NP_CREDENTIAL_MANAGER)
    BOOL Save = FALSE;
#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;
    }

    NpResult = FspNpGetRemoteInfo(RemoteName, &AuthPackage, &CredentialsKind, 0);
    if (WN_SUCCESS != NpResult)
        return NpResult;
    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)
        FspNpParseRemoteUserName(RemoteName, UserName, sizeof UserName / sizeof UserName[0]);
    do
    {
        NpResult = FspNpGetCredentials(
            hwndOwner, RemoteName, NpResult,
            AuthPackage, 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;
    ULONG ClassNameLen, InstanceNameLen;
    ULONG Argc;
    PWSTR Argv[2];
    ULONG Argl[2];

    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;

    Argc = 0;
    Argv[Argc] = ClassName; Argl[Argc] = ClassNameLen; Argc++;
    Argv[Argc] = InstanceName; Argl[Argc] = InstanceNameLen; Argc++;

    NpResult = FspNpCallLauncherPipe(
        FspLaunchCmdStop,
        Argc, Argv, Argl, 0, 0,
        FALSE);
    switch (NpResult)
    {
    case WN_SUCCESS:
        break;
    case ERROR_FILE_NOT_FOUND:
        NpResult = WN_NOT_CONNECTED;
        break;
    default:
        NpResult = WN_NO_NETWORK;
        break;
    }

    return NpResult;
}

DWORD APIENTRY NPGetUniversalName(
    LPCWSTR lpLocalPath,
    DWORD dwInfoLevel,
    LPVOID lpBuffer,
    LPDWORD lpBufferSize)
{
    DWORD NpResult;
    WCHAR LocalNameBuf[3];
    PCWSTR RemainLocalPath;
    WCHAR RemoteNameBuf[sizeof(((FSP_FSCTL_VOLUME_PARAMS *)0)->Prefix) / sizeof(WCHAR)];
    DWORD RemoteNameSize, RemainLocalPathSize, RequiredBufferSize;

    if (UNIVERSAL_NAME_INFO_LEVEL != dwInfoLevel &&
        REMOTE_NAME_INFO_LEVEL != dwInfoLevel)
        return WN_BAD_LEVEL;

    if (0 == lpLocalPath ||
        L'\0' == lpLocalPath[0] ||
        L':' != lpLocalPath[1] ||
        (L'\0' != lpLocalPath[2] && L'\\' != lpLocalPath[2]))
        return WN_BAD_LOCALNAME;

    LocalNameBuf[0] = lpLocalPath[0];
    LocalNameBuf[1] = L':';
    LocalNameBuf[2] = L'\0';
    RemainLocalPath = lpLocalPath + 2;

    RemoteNameSize = sizeof RemoteNameBuf / sizeof(WCHAR);
    NpResult = NPGetConnection(LocalNameBuf, RemoteNameBuf, &RemoteNameSize);
    if (WN_SUCCESS != NpResult)
        return NpResult;

    RemoteNameSize = lstrlenW(RemoteNameBuf) * sizeof(WCHAR);
    RemainLocalPathSize = lstrlenW(RemainLocalPath) * sizeof(WCHAR) + sizeof(WCHAR)/* term-0 */;

    if (UNIVERSAL_NAME_INFO_LEVEL == dwInfoLevel)
    {
        RequiredBufferSize = sizeof(UNIVERSAL_NAME_INFOW) +
            /* UniversalName */ RemoteNameSize + RemainLocalPathSize;

        if (RequiredBufferSize > *lpBufferSize)
        {
            *lpBufferSize = RequiredBufferSize;
            NpResult = WN_MORE_DATA;
            goto exit;
        }

        LPUNIVERSAL_NAME_INFOW Info = lpBuffer;
        memset(Info, 0, sizeof *Info);
        Info->lpUniversalName = (PVOID)(Info + 1);
        memcpy(Info->lpUniversalName, RemoteNameBuf, RemoteNameSize);
        memcpy((PUINT8)Info->lpUniversalName + RemoteNameSize, RemainLocalPath,
            RemainLocalPathSize);

        NpResult = WN_SUCCESS;
    }
    else if (REMOTE_NAME_INFO_LEVEL == dwInfoLevel)
    {
        RequiredBufferSize = sizeof(REMOTE_NAME_INFOW) +
            /* UniversalName */ RemoteNameSize + RemainLocalPathSize +
            /* ConnectionName */RemoteNameSize + sizeof(WCHAR) +
            /* RemainingPath */ RemainLocalPathSize;

        if (RequiredBufferSize > *lpBufferSize)
        {
            *lpBufferSize = RequiredBufferSize;
            NpResult = WN_MORE_DATA;
            goto exit;
        }

        LPREMOTE_NAME_INFOW Info = lpBuffer;
        memset(Info, 0, sizeof *Info);
        Info->lpUniversalName = (PVOID)(Info + 1);
        Info->lpConnectionName = (PVOID)((PUINT8)Info->lpUniversalName +
            RemoteNameSize + RemainLocalPathSize);
        Info->lpRemainingPath = (PVOID)((PUINT8)Info->lpConnectionName +
            RemoteNameSize + sizeof(WCHAR));
        memcpy(Info->lpUniversalName, RemoteNameBuf, RemoteNameSize);
        memcpy((PUINT8)Info->lpUniversalName + RemoteNameSize, RemainLocalPath,
            RemainLocalPathSize);
        memcpy(Info->lpConnectionName, RemoteNameBuf, RemoteNameSize + sizeof(WCHAR));
        memcpy(Info->lpRemainingPath, RemainLocalPath, RemainLocalPathSize);

        NpResult = WN_SUCCESS;
    }
    else
        /* should not happen! */
        NpResult = WN_BAD_LEVEL;

exit:
    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 DllPath[MAX_PATH], ProviderPath[MAX_PATH];
    PWSTR VersionInfoPath;
    BOOLEAN HasPercent;
    WCHAR RegBuffer[1024];
    PWSTR P, Part;
    DWORD RegResult, RegType, RegBufferSize, RegBufferOffset;
    HKEY RegKey;
    BOOLEAN FoundProvider;
    NTSTATUS Result;

    VersionInfoPath = ProviderPath;
    HasPercent = FALSE;
    for (P = L"" MyNpRegisterPath; *P; P++)
        if ('%' == *P)
        {
            HasPercent = TRUE;
            break;
        }
    if (HasPercent)
    {
        VersionInfoPath = DllPath;
        if (0 == GetModuleFileNameW(DllInstance, DllPath, MAX_PATH))
            return FspNtStatusFromWin32(GetLastError());
    }

    Result = FspGetModuleFileName(DllInstance, ProviderPath, MAX_PATH, L"" MyNpRegisterPath);
    if (!NT_SUCCESS(Result))
        return Result;

    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(VersionInfoPath, &Size/*dummy*/);
        if (0 < Size)
        {
            VersionInfo = MemAlloc(Size);
            if (0 != VersionInfo &&
                GetFileVersionInfoW(VersionInfoPath, 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, HasPercent ? REG_EXPAND_SZ : REG_SZ,
        (PVOID)ProviderPath, (lstrlenW(ProviderPath) + 1) * sizeof(WCHAR));
    if (ERROR_SUCCESS != RegResult)
        goto close_and_exit;

    RegResult = RegSetValueExW(RegKey,
        L"DeviceName", 0, REG_SZ,
        (PVOID)L"\\Device\\" FSP_FSCTL_MUP_DEVICE_NAME,
        sizeof L"\\Device\\" FSP_FSCTL_MUP_DEVICE_NAME);
    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;
#ifdef FSP_NP_ORDER_FIRST
    RegBufferOffset = sizeof "" FSP_NP_NAME;
#else
    RegBufferOffset = 0;
#endif
    RegResult = RegQueryValueExW(RegKey,
        L"ProviderOrder", 0, &RegType, (PVOID)&RegBuffer[RegBufferOffset], &RegBufferSize);
    if (ERROR_SUCCESS != RegResult)
        goto close_and_exit;
    RegBufferSize /= sizeof(WCHAR);

    FoundProvider = FALSE;
    RegBuffer[RegBufferSize + RegBufferOffset] = L'\0';
    P = &RegBuffer[RegBufferOffset], 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)
    {
#ifdef FSP_NP_ORDER_FIRST
        memcpy((PWSTR)RegBuffer, L"" FSP_NP_NAME ",", sizeof L"" FSP_NP_NAME);
#else
        memcpy(--P, L"," FSP_NP_NAME, sizeof L"," FSP_NP_NAME);
#endif

        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);
}
