Windows Networking (WNet API / mpr.dll) WNetAddConnection2 fails with NotAuthenticated

2.1k views Asked by At

I am writing a program to map a network drive (WebDAV) from a graphical UI (Windows Forms).

I am using the Windows Networking API that lives in the mpr.dll.

Now, when the user enters a wrong password WNetAddConnection2 returns the NotAuthenticated result. So far so good. I throw a custom exception in my wrapper in this case. When the user then goes ahead and enters a correct password I still get a NotAuthenticated. Why is this?

Edit: Also interesting: If I set a breakpoint to the second try statement and let the debugger sit there for about 30 seconds the mapping works after I continue execution.

Edit 2: The problem only occurs under Windows 7 and 10

Here is some code to illustrate what I am doing


using System;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Text;

namespace WNetStackOverflow
{
    class Program
    {
        static void Main(string[] args)
        {
            char driveLetter = 'Z';
            string userName = "user";
            string password = "passwor";

            try
            {
                Console.WriteLine("First attempt (wrong pass)");
                WNetWrapper.CreateNewNetDrive(driveLetter, userName, password);
            }
            catch (WNetException e)
            {
                Console.WriteLine($"First attempt failed: {e.Error}");
                Console.WriteLine(e);
            }

            try
            {
                Console.WriteLine("Second attempt (correct pass)");
                WNetWrapper.CreateNewNetDrive(driveLetter, userName, password + "d");
                Console.WriteLine("Success!");
            }
            catch (WNetException e)
            {
                Console.WriteLine($"Second attempt failed: {e.Error}");
                Console.WriteLine(e);
            }

            Console.ReadKey();
        }
    }

    internal static class WNetWrapper
    {
        [DllImport("mpr.dll")]
        private static extern WNetError WNetAddConnection2(
            NetResource netResource,
            string password,
            string username,
            uint flags);

        [DllImport("mpr.dll")]
        public static extern int WNetGetLastError(
            ref int lpError,
            StringBuilder lpErrorBuf,
            int nErrorBufSize,
            StringBuilder lpNameBuf,
            int nNameBufSize);

        const string WebDavUri = "yourDomain.com";
        public static void CreateNewNetDrive(char driveLetter, string userName, string password)
        {
            var netResource = new NetResource
            {
                dwScope = ResourceScope.Globalnet,
                dwDisplayType = ResourceDisplayType.Share,
                dwType = ResourceType.Disk,
                lpRemoteName = $"https://{userName}.{WebDavUri}",
                lpLocalName = driveLetter + ":"
            };

            var returnCode = WNetAddConnection2(netResource, password, userName, 1);

            if (returnCode != WNetError.NoError)
            {
                var errorInformation = GetErrorInformation(returnCode);
                errorInformation.Add("DriveLetter", driveLetter.ToString());
                errorInformation.Add("UserName", userName);
                throw new WNetException("Failed to create net drive", returnCode, errorInformation);
            }
        }

        private static IDictionary GetErrorInformation(WNetError wNetError)
        {
            var data = new Dictionary<string, object>
            {
                {"ErrorCode", $"{wNetError} (ErrorCode {(int) wNetError})"}
            };

            var sbErrorBuf = new StringBuilder(500);
            var sbNameBuf = new StringBuilder(500);

            var errorNumber = 0;
            WNetGetLastError(ref errorNumber, sbErrorBuf, sbErrorBuf.Capacity, sbNameBuf, sbNameBuf.Capacity);

            if (errorNumber != 0)
            {
                data.Add("WNetLastErrorNumber", errorNumber);
                data.Add("WNetLastErrorMessage", sbErrorBuf);
            }

            Console.WriteLine($"ErrorNumber {errorNumber}, ErrorMessage {sbErrorBuf}");

            return data;
        }
    }

    internal enum WNetError
    {
        NoError = 0,
        BadNetName = 67,
        AlreadyAssigned = 85,
        NoMoreItems = 259,
        BadDevice = 1200,
        NotAuthenticated = 1244
    }

    internal class WNetException : Exception
    {
        public WNetError Error { get; }

        public WNetException(string message, WNetError error, IDictionary data) : base(message)
        {
            Error = error;

            foreach (var key in data.Keys)
            {
                Data[key] = data[key];
            }
        }
    }
    internal enum ResourceScope
    {
        Connected = 1,
        Globalnet,
        Remembered,
        Recent,
        Context
    }
    internal enum ResourceType
    {
        Any,
        Disk,
        Print,
        Reserved
    }

    [StructLayout(LayoutKind.Sequential)]
    internal class NetResource
    {
        public ResourceScope dwScope = 0;
        public ResourceType dwType = 0;
        public ResourceDisplayType dwDisplayType = 0;
        public ResourceUsage dwUsage = 0;
        public string lpLocalName;
        public string lpRemoteName;
        public string lpComment;
        public string lpProvider;
    }

    public enum ResourceDisplayType
    {
        Generic,
        Domain,
        Server,
        Share,
        File,
        Group,
        Network,
        Root,
        Shareadmin,
        Directory,
        Tree,
        Ndscontainer
    }

    [Flags]
    public enum ResourceUsage
    {
        Connectable = 0x00000001,
        Container = 0x00000002,
        Nolocaldevice = 0x00000004,
        Sibling = 0x00000008,
        Attached = 0x00000010,
        All = Connectable | Container | Attached
    }

}
0

There are 0 answers