Link to home
Start Free TrialLog in
Avatar of Bryon Czaja
Bryon CzajaFlag for United States of America

asked on

The client connected to another applications mailslot returns access denied when attempting to write.

The problem I am encountering is with the Mailslot write function of the client. The purpose of this is to build a compatible code base in C#, that will be used with older applications built in C++. The C# code client to server works fine, using either separate (local) applications or internal communication. I can also talk to the server spun up in C++ code. So, everything seems to be working...to a point.


But the thing is, I cannot write from the C++ client to the C# server. The code returned is 5, which is access denied. 

This seems to be a security/permission problem with the C# code base. Any thoughts?



https://docs.microsoft.com/en-us/windows/win32/debug/system-error-codes--0-499-


The basic ideas for the mailslot is this:


//Server  - C# 
CreateMailslot(mailBoxPath, 
      1024, 
      2000, 
      IntPtr.Zero);


ReadFile(serverHandle,
     buffer,
     msgSize,
     out numBytesReadm
     Intptr.Zero);


//Client  - C++
CreatFile(mailBoxPath, 
      GENERIC_WRITE, 
      FILE_SHARE_READ | FILE_SHARE_WRITE,
      NULL,
      OPEN_EXISTING,
      NULL);


WriteFile(clientHandle,
     mailMsg,
     numBytesToWrite,
     numBytesWritten,
     NULL);

Open in new window

Here is some information on the topic.

Avatar of Bryon Czaja
Bryon Czaja
Flag of United States of America image

ASKER

Thanks Gerwin!
Avatar of ste5an
Without testing: The client can only write to the slot. Thus FILE_SHARE_READ is probably the issue.
Hello ste5an,
That is an idea I can try. I will remove the FILE_SHARE_READ attribute and see if that does the job. Thanks for the suggestion.
Ok. it seems that ommitting FILE_SHARE_READ does not correct the problem.
Not sure if this would make a difference, but I am running on Windows Server 2019. My thought on this is that this may be a security or permission problem. 
Never used that tool, but I would give it a shot: https://ioninja.com/plugins/mailslot-monitor.html
I tried this out on a Win 10 machine, and it does not exhibit the problem. It really does seem like a permission problem.
Thanks for the tool ste5an. I was able to see it send data from the C# client to the C++ server. However sending from the C++ client to the C# server showed no activity when sending the message. It did validate that the client did connect, so that is a positive!
As you have limited the message size, Is it maybe too large?

To test permissions: Do you have a test domain? Then I would run the C# server and C++ client as full domain admin with full access on both machines. When this works, then it is for sure an permission issue.

How do you run your C# server? I would try also a STA console application.
Hello ste5an. The messages are about 16 bytes in length. I run the server on the local machine, both the C++ and C# machines, but different paths obviously.

One thing to note is that the mailslot uses a virtual path and 'file'.So the file is just hanging out in memory. I think that the server running the C# code has permissions issue that does not allow the C++ MFC client to access when it goes to write.


https://docs.microsoft.com/en-us/windows/win32/ipc/mailslots

Form load:
    public partial class Form1 : Form
    {
        private  string serverPath = "Server";
        private MailslotServer server;

        public Form1()
        {
            InitializeComponent();

            try
            {
                server = new MailslotServer(serverPath);
                textBox2.Text = @"//.mailslot/" + serverPath;
            }
            catch(Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

Open in new window


Server code:

using System;
using System.Text;
using System.Runtime.InteropServices;
using System.Security;
using System.Security.Permissions;
using System.Runtime.ConstrainedExecution;
using Microsoft.Win32.SafeHandles;
using System.ComponentModel;

[SuppressUnmanagedCodeSecurity]
public static class Mailslot
{
    public const int MailslotNoMessage = -1;

    [Flags]
    public enum FileDesiredAccess : uint
    {
        GenericRead = 0x80000000,
        GenericWrite = 0x40000000,
        GenericExecute = 0x20000000,
        GenericAll = 0x10000000
    }

    [Flags]
    public enum FileShareMode : uint
    {
        Zero = 0x00000000,
        FileShareDelete = 0x00000004,
        FileShareRead = 0x00000001,
        FileShareWrite = 0x00000002
    }

    public enum FileCreationDisposition : uint
    {
        CreateNew = 1,
        CreateAlways = 2,
        OpenExisting = 3,
        OpenAlways = 4,
        TruncateExisting = 5
    }

    [SecurityCritical(SecurityCriticalScope.Everything)]
    [HostProtection(SecurityAction.LinkDemand, MayLeakOnAbort = true)]
    [SecurityPermission(SecurityAction.LinkDemand, UnmanagedCode = true)]
    public sealed class SafeMailslotHandle : SafeHandleZeroOrMinusOneIsInvalid
    {
        private SafeMailslotHandle() : base(true) { }
        public SafeMailslotHandle(IntPtr preexistingHandle, bool ownsHandle) : base(ownsHandle)
        {
            base.SetHandle(preexistingHandle);
        }

        [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
        [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        private static extern bool CloseHandle(IntPtr handle);

        protected override bool ReleaseHandle()
        {
            return CloseHandle(base.handle);
        }
    }

    [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    public static extern SafeMailslotHandle CreateMailslot(string mailslotName,
                                                uint nMaxMessageSize, int lReadTimeout,
                                                IntPtr securityAttributes);


    [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    [return: MarshalAs(UnmanagedType.Bool)]
    public static extern bool GetMailslotInfo(SafeMailslotHandle hMailslot,
                                                IntPtr lpMaxMessageSize,
                                                out int lpNextSize, out int lpMessageCount,
                                                IntPtr lpReadTimeout);


    [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    [return: MarshalAs(UnmanagedType.Bool)]
    public static extern bool ReadFile(SafeMailslotHandle handle,
                                        byte[] bytes, int numBytesToRead,
                                        out int numBytesRead,
                                        IntPtr overlapped);

    [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    [return: MarshalAs(UnmanagedType.Bool)]
    public static extern bool WriteFile(SafeMailslotHandle handle,
                                        byte[] bytes, int numBytesToWrite,
                                        out int numBytesWritten,
                                        IntPtr overlapped);

    [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    public static extern SafeMailslotHandle CreateFile(string fileName,
                                        FileDesiredAccess desiredAccess,
                                        FileShareMode shareMode,
                                        IntPtr securityAttributes,
                                        FileCreationDisposition creationDisposition,
                                        int flagsAndAttributes, IntPtr hTemplateFile);
}

public class MailslotServer : IDisposable
{
    private Mailslot.SafeMailslotHandle _handle;

    public MailslotServer(string name)
    {
        _handle = Mailslot.CreateMailslot(@"\\.\mailslot\" + name, 0, 0, IntPtr.Zero);
        if (_handle.IsInvalid) throw new Win32Exception();
    }

    public string GetNextMessage()
    {
        int messageBytes;
        int bytesRead;
        int messages;

        if (!Mailslot.GetMailslotInfo(_handle, IntPtr.Zero, out messageBytes,
                     out messages, IntPtr.Zero)) throw new Win32Exception();

        if (messageBytes == Mailslot.MailslotNoMessage) return null;

        var bBuffer = new byte[messageBytes];

        if (!Mailslot.ReadFile(_handle, bBuffer, messageBytes, out bytesRead,
             IntPtr.Zero) || bytesRead == 0) throw new Win32Exception();

        return Encoding.Unicode.GetString(bBuffer);
    }

    public void Dispose()
    {
        if (_handle != null)
        {
            _handle.Close();
            _handle = null;
        }
    }
}

public class MailslotClient : IDisposable
{
    private Mailslot.SafeMailslotHandle _handle;
    private readonly string _name;
    private readonly string _machine;

    public MailslotClient(string name) : this(name, ".") { }
    public MailslotClient(string name, string machine)
    {
        _name = name;
        _machine = machine;
    }

    public void SendMessage(string msg)
    {
        if (_handle == null) CreateHandle();

        int bytesWritten;

        byte[] bMessage = Encoding.Unicode.GetBytes(msg);

        bool succeeded = Mailslot.WriteFile(_handle, bMessage,
             bMessage.Length, out bytesWritten, IntPtr.Zero);

        if (!succeeded || bMessage.Length != bytesWritten)
        {
            if (_handle != null) _handle.Close();
            _handle = null;

            throw new Win32Exception();
        }
    }
    public void Dispose()
    {
        if (_handle != null)
        {
            _handle.Close();
            _handle = null;
        }
    }

    private void CreateHandle()
    {
        _handle = Mailslot.CreateFile(
            @"\\" + _machine + @"\mailslot\" + _name,
            Mailslot.FileDesiredAccess.GenericWrite,
            Mailslot.FileShareMode.FileShareRead,
            IntPtr.Zero,
            Mailslot.FileCreationDisposition.OpenExisting,
            0,
            IntPtr.Zero);

        if (_handle.IsInvalid) throw new Win32Exception();

    }
}

Open in new window

ASKER CERTIFIED SOLUTION
Avatar of ste5an
ste5an
Flag of Germany image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Hello ste5an,
That was the problem. I cannot believe that was it. Now, I can communicate between applications, and verified it with the old code base.
Thank you for the help!