Connecting to a remote shared folder results in "multiple connections not allowed" error, but trying to disconnect causes "connection does not exist"
Asked Answered
M

5

10

I have a shared network folder \\some.domain.net\Shared that contains multiple shared subfolders with different permissions for different users. I wish to open connections to multiple subfolders from the same Windows account, but with different credentials - is this possible without having to disconnect other connections to the same share first?

To be exact: in a C# method, I try to connect to a specific subfolder using WNetUseConnection() (p/invoke) in the manner of:

ConnectToSharedFolder("\\some.domain.net\Shared\Subfolder1", user, password); // calls WNetUseConnection() internally 

This works fine as long as there is no connection already established to the either root folder (i.e. \\some.domain.net\Shared) or another shared subfolder (or, in general, to any folder on \\some.domain.net) at the moment of WNetUseConnection() invocation to connect to a subfolder. I.e., consider that before connecting to a subfolder, net use returns:

Status       Local     Remote
------------------------------------------------
OK                     \\some.domain.net\Shared

Now I want to also connect to a shared subfolder \\some.domain.net\Shared\Subfolder1 as shown at the top of this post. This will result in windows error 1219:

Multiple connections to a server or shared resource by the same user, using more than one user name, are not allowed. Disconnect all previous connections to the server or shared resource and try again. 

So Windows (Server 2008 R2) doesn't seem to recognize a difference between \\some.domain.net\Shared and \\some.domain.net\Shared\Subfolder1, despite different access credentials provided. However, trying to cancel the connection in case of error 1219 by using

WNetCancelConnection2(@"\\some.domain.net\Shared\Subfolder1", 0, true); // error 2250

results in error 2250:

This network connection does not exist.

So it seems that I would first need to manually cancel all open connections to \\some.domain.net\ as it looks like only one can be opened at a time - however, this doesn't seem very robust as another process might be accessing the connected shared folder at the same time.

Are there ways to resolve this and have active connections to multiple shared folders on the same remote machine?

Maricruzmaridel answered 7/1, 2014 at 16:7 Comment(3)
Let me got this straight: you've connected to the root share and you're trying to connect to a sub-folder of that. Are you using different credentials for both connections?Washday
@simonatrcl: correct, yes. I am establishing the connection from the same Windows account in both cases, but the actual credentials specified are different: user1/password1 for the root folder and user2/password2 for the subfolder - these are the same credentials that one would pass to net use.Maricruzmaridel
After researching this a bit more it seems it sure is a "by-design" issue, though it doesn't make any sense to me, looks like a glitch.Maricruzmaridel
A
6

It's an old topic but very actual and problematic. I'll try to put some light on it cos I've been dealing whit such problems for couple of years now.

First of all: Windows doesnt allow you to connect to multiple subfolders in one network share.

Second of all: Windows is identifying connection by remote name. So you can establish more than one connection to the same server whith different names like: www.serverName.com and 123.123.123.123 (by ip) - these will be treated as separate connections with different credentials.

So my solution was to add alias IP to my server. I've created ten aliases of my server and my app was taking first IP from the list then if it was blocked then next etc.

This solution is not very good but it works. problem is when you dont have access to server IP. What then? See next point:

Last of all: Then the only solution is to disconnect user after using specified network share and here begins all other problems... connections are used by many things that are blocking others to log in. For example someone opens Word document from network share - now you cannot disconnect! BUT net.exe will not show any connections! Another BUT when you close Word document after some time (about a minute) connection will by automatically closed and will allow new connections.

My work is now directed to find whitch system elements are blocking connections and notify user: Close Word and you will be able to login. Hopfully it can be done.

PS. I'm working all with WinApi cos net.exe is working much slower and offers less options.

If someone needs source code:

public ServerWinProcessor(string serverAddress)
  : base(serverAddress)
{

}

[DllImport("mpr.dll")]
public static extern int WNetAddConnection2(ref NETRESOURCE netResource, string password, string username, uint flags);

[DllImport("mpr.dll")]
public static extern int WNetCancelConnection2(string lpName, int dwFlags, bool fForce);

[DllImport("mpr.dll")]
public static extern int WNetOpenEnum(int dwScope, int dwType, int dwUsage, NETRESOURCE2 lpNetResource, out IntPtr lphEnum);

[DllImport("Mpr.dll", EntryPoint = "WNetCloseEnum", CallingConvention = CallingConvention.Winapi)]
private static extern int WNetCloseEnum(IntPtr hEnum);

[DllImport("mpr.dll")]
private static extern int WNetEnumResource(IntPtr hEnum, ref uint lpcCount, IntPtr buffer, ref uint lpBufferSize);

public OperationResult LoginToNetworkShare(string userName, string password, string shareName)
{
  return LoginToNetworkShare(userName, password, shareName, null);
}

public OperationResult LoginToNetworkShare(string userName, string password, string shareName, string shareDrive)
{
  NETRESOURCE nr = new NETRESOURCE();
  nr.dwType = RESOURCETYPE_DISK;
  nr.lpLocalName = shareDrive;
  nr.lpRemoteName = @"\\" + ServerAddress + @"\" + shareName;

  int result = WNetAddConnection2(ref nr, password, userName, CONNECT_TEMPORARY);
  return new OperationResult(result);
}

public Task<OperationResult> LoginToNetworkShareAsync(string userName, string password, string shareName, string shareDrive)
{
  return Task.Factory.StartNew(() =>
  {
    return LoginToNetworkShare(userName, password, shareName, shareDrive);
  });
}

public OperationResult LogoutFromNetworkSharePath(string sharePath)
{
  int result = WNetCancelConnection2(sharePath, CONNECT_UPDATE_PROFILE, true);
  return new OperationResult(result);
}

public OperationResult LogoutFromNetworkShare(string shareName)
{
  int result = WNetCancelConnection2(@"\\" + ServerAddress + @"\" + shareName, CONNECT_UPDATE_PROFILE, true);
  return new OperationResult(result);
}

public OperationResult LogoutFromNetworkShareDrive(string driveLetter)
{
  int result = WNetCancelConnection2(driveLetter, CONNECT_UPDATE_PROFILE, true);
  return new OperationResult(result);
}

private ArrayList EnumerateServers(NETRESOURCE2 pRsrc, int scope, int type, int usage, ResourceDisplayType displayType)
{
  ArrayList netData = new ArrayList();
  ArrayList aData = new ArrayList();
  uint bufferSize = 16384;
  IntPtr buffer = Marshal.AllocHGlobal((int)bufferSize);
  IntPtr handle = IntPtr.Zero;
  int result;
  uint cEntries = 1;

  result = WNetOpenEnum(scope, type, usage, pRsrc, out handle);

  if (result == NO_ERROR)
  {
    do
    {
      result = WNetEnumResource(handle, ref cEntries, buffer, ref bufferSize);

      if (result == NO_ERROR)
      {
        Marshal.PtrToStructure(buffer, pRsrc);

        if (string.IsNullOrWhiteSpace(pRsrc.lpLocalName) == false && pRsrc.lpRemoteName.Contains(ServerAddress))
          if (aData.Contains(pRsrc.lpLocalName) == false)
          {
            aData.Add(pRsrc.lpLocalName);
            netData.Add(new NetworkConnectionInfo(null, pRsrc.lpLocalName));
          }

        if (aData.Contains(pRsrc.lpRemoteName) == false && pRsrc.lpRemoteName.Contains(ServerAddress))
        {
          aData.Add(pRsrc.lpRemoteName);
          netData.Add(new NetworkConnectionInfo(pRsrc.lpRemoteName, null));
        }

        if ((pRsrc.dwUsage & RESOURCEUSAGE_CONTAINER) == RESOURCEUSAGE_CONTAINER)
          netData.AddRange(EnumerateServers(pRsrc, scope, type, usage, displayType));
      }
      else if (result != ERROR_NO_MORE_ITEMS)
        break;
    } while (result != ERROR_NO_MORE_ITEMS);

    WNetCloseEnum(handle);
  }

  Marshal.FreeHGlobal(buffer);
  return netData;
}

public void CloseAllConnections()
{
  NETRESOURCE2 res = new NETRESOURCE2();
  ArrayList aData = EnumerateServers(res, RESOURCE_CONNECTED, 0, 0, ResourceDisplayType.RESOURCEDISPLAYTYPE_NETWORK);

  foreach (NetworkConnectionInfo item in aData)
  {
    if (item.IsRemoteOnly)
      LogoutFromNetworkSharePath(item.RemoteName);
    else
      LogoutFromNetworkShareDrive(item.LocalName);
  }
}
}

And other classes:

public static class Consts
  {
    public const int RESOURCETYPE_DISK = 0x1;
    public const int CONNECT_TEMPORARY = 0x00000004;
    public const int CONNECT_UPDATE_PROFILE = 0x00000001;
    public const int RESOURCE_GLOBALNET = 0x00000002;
    public const int RESOURCE_CONNECTED = 0x00000001;
    public const int RESOURCEDISPLAYTYPE_SERVER = 0x00000002;
    public const int RESOURCEUSAGE_CONTAINER = 0x00000002;

    public const int NO_ERROR = 0x000;
    public const int ERROR_NOT_CONNECTED = 0x8CA;
    public const int ERROR_LOGON_FAILURE = 0x52E;
    public const int ERROR_SESSION_CREDENTIAL_CONFLICT = 0x4C3;
    public const int ERROR_ALREADY_ASSIGNED = 0x55;
    public const int ERROR_INVALID_PASSWORD = 0x56;
    public const int ERROR_INVALID_PARAMETER = 0x57;
    public const int ERROR_NO_MORE_ITEMS = 0x103;
    //public const int ERROR_BAD_PROFILE = 0x4B6;
    //public const int ERROR_CANNOT_OPEN_PROFILE = 0x4B5;
    //public const int ERROR_DEVICE_IN_USE = 0x964;
    //public const int ERROR_EXTENDED_ERROR = 0x4B8;
    //public const int ERROR_OPEN_FILES = 0x961;

    public enum ResourceDisplayType
    {
      RESOURCEDISPLAYTYPE_GENERIC,
      RESOURCEDISPLAYTYPE_DOMAIN,
      RESOURCEDISPLAYTYPE_SERVER,
      RESOURCEDISPLAYTYPE_SHARE,
      RESOURCEDISPLAYTYPE_FILE,
      RESOURCEDISPLAYTYPE_GROUP,
      RESOURCEDISPLAYTYPE_NETWORK,
      RESOURCEDISPLAYTYPE_ROOT,
      RESOURCEDISPLAYTYPE_SHAREADMIN,
      RESOURCEDISPLAYTYPE_DIRECTORY,
      RESOURCEDISPLAYTYPE_TREE,
      RESOURCEDISPLAYTYPE_NDSCONTAINER
    };

    [StructLayout(LayoutKind.Sequential)]
    public struct NETRESOURCE
    {
      public int dwScope;
      public int dwType;
      public int dwDisplayType;
      public int dwUsage;
      public string lpLocalName;
      public string lpRemoteName;
      public string Comment;
      public string lpProvider;
    }

    [StructLayout(LayoutKind.Sequential)]
    public class NETRESOURCE2
    {
      public int dwScope = 0;
      public int dwType = 0;
      public ResourceDisplayType dwDisplayType = 0;
      public int dwUsage = 0;
      public string lpLocalName = null;
      public string lpRemoteName = null;
      public string lpComment = null;
      public string lpProvider = null;
    };
  }

And the las one:

public class NetworkConnectionInfo
  {
    public string RemoteName { get; set; }
    public string LocalName { get; set; }

    public bool IsRemoteOnly { get; set; }

    public NetworkConnectionInfo(string remoteName, string localName)
    {
      RemoteName = remoteName;
      LocalName = localName;

      if (string.IsNullOrWhiteSpace(localName))
        IsRemoteOnly = true;
    }
  }

You dont need OperationResult it is just simple error container, not needed. Base class ServerProcessorBase contains only one field serverAddress.

IMPORTANT: This is a problem maker when you wont set it up properly: CONNECT_TEMPORARY option. If not set then windows will remember mounted drives and will try to connect them after computer restart ofcource causing error: can not connect some drives :) anoying :)

Algeciras answered 30/1, 2016 at 13:35 Comment(1)
Hi, have you add this aliases in the HOSTS file, or have you add the aliases with the app?Klos
W
2

OK - this is the problem. It gives a couple of suggested solutions; both sound a bit manky to me, but might be OK for you. It sounds like this behavior is by design (probably a security consideration).

Cheers -

Washday answered 7/1, 2014 at 17:3 Comment(3)
Thank you, but unfortunately method 1 doesn't resolve the situation, and method 2 is unacceptable for me.Maricruzmaridel
Microsoft: "this behavior is by design". Thank you Microsoft for that BAD design. I agree that proposed methods 1 or 2 are both dirty.Gingerich
While this link may answer the question, it is better to include the essential parts of the answer here and provide the link for reference. Link-only answers can become invalid if the linked page changes. - From ReviewStamm
S
0

I want to share the solution I used for error code 1219 while mapping a drive with a shared path using WNetCancelConnection2() even though this a different function call, I feel this approach may resolve.

First of all, you need to make sure how your computers are organized in a network.

If it is in Domain:

Your username should be [DomainName]\[UserName], sometimes you can simply use [UserName].

var userName = string.IsNullOrEmpty(credentials.Domain) ? credentials.UserName : string.Format(@"{0}\{1}", credentials.Domain, credentials.UserName);

If it is in Workgroup:

Your username should be [ServerName]\[UserName], never use [UserName].

Here ServerName is the hostname of your shared path.

var userName = string.Format(@"{0}\{1}", serverMachineName, credentials.UserName);

Note: Workgroup solution works only if the passed username is the current login username. If you are using Windows Service then just change the log on as with the specific user credentials

Samarskite answered 19/1, 2017 at 9:27 Comment(0)
E
0

This is indeed very annoying, and something which Microsoft should have fixed long ago.

However, this bad feature does not always turn up. I have been able to map three different subdirectories in the same server, using different remote credentials from the same Windows user (Windows 10/64-bit Pro), and it worked for years, coming up at every bootup. I used the device mapping facility of File Explorer. When it works then it will work, but as soon as a change occurs, e.g. the password of one of the remote users are changed, then this problem might occur, too. It also appears, when Windows cannot map a specific drive, because the password was incorrect, then it grabs the next remote user credentials and attempt the device mapping. If this user is acknowledged by the server, it appears Windows will fail to map the device for which this next remote user's credentials was intended for. The observation that it is sometimes possible to map server subdirectories by the same Windows user, using both different and even identical remote user credentials indicates this behaviour is not tightly controlled by Windows.

Sorry to say, this makes Windows less usable than necessary.

Ephraim answered 7/10, 2019 at 17:30 Comment(1)
One way to avoid this problem will work in specific cases: When you need to map several server based resources in the same server, create or ask for a user with the server, which offers the required rights in the server for the collection of resources to map. Then, map all these resources for the Windows user, using this server based credential. Also resources, which do not require a login, must be mapped using the same server based credential. This works at least with Buffalo TeraStation 5400.Ephraim
U
0

Problem: I had an exception saying "error code 1219" when I tried to connect to a shared folder on a remote server windows.

Solution: In my C# code, I add the name of the domainName\myUsername and it works. Before I put only myUsername to the variable networkUsername.

Ulrika answered 5/9, 2024 at 3:26 Comment(1)
As it’s currently written, your answer is unclear. Please edit to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers in the help center.Lewls

© 2022 - 2025 — McMap. All rights reserved.