Hi all,

 

The following C# sample shows how to create a memory mapped file and use private namespaces to allow access to specific groups of users:

 

FORM1.CS

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Security.Principal;
using System.IO;

namespace Alejacma
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}

private void button1_Click(object sender, EventArgs e)
{
bool bResult = false;
IntPtr hBoundary = IntPtr.Zero;
IntPtr pSid = IntPtr.Zero;
int cbSid = Win32.SECURITY_MAX_SID_SIZE;
IntPtr hNamespace = IntPtr.Zero;
Win32.SECURITY_ATTRIBUTES securityAttributes = new Win32.SECURITY_ATTRIBUTES();
IntPtr hFile = IntPtr.Zero;
IntPtr pView = IntPtr.Zero;
IntPtr pData = IntPtr.Zero;

try
{
// Create boundary
hBoundary = Win32.CreateBoundaryDescriptor(
"AlejacmaBoundaryDescriptor",
0
);
if (hBoundary == IntPtr.Zero) { throw new Exception("CreateBoundaryDescriptor", new Win32Exception(Marshal.GetLastWin32Error())); }

pSid = Marshal.AllocHGlobal(cbSid);
bResult = Win32.CreateWellKnownSid(
WellKnownSidType.BuiltinAdministratorsSid,
IntPtr.Zero,
pSid,
ref cbSid
);
if (!bResult) { throw new Exception("CreateWellKnownSid", new Win32Exception(Marshal.GetLastWin32Error())); }

bResult = Win32.AddSIDToBoundaryDescriptor(
ref hBoundary,
pSid
);
if (!bResult) { throw new Exception("AddSIDToBoundaryDescriptor", new Win32Exception(Marshal.GetLastWin32Error())); }

// Create namespace and give access to some groups of users:
// - Remote Desktop Users (needed for remote users to access the mapped file)
// - Administrators (needed to create the mapped file within this program)
// - Interactive users (needed for local users to access mapped file)
bResult = Win32.ConvertStringSecurityDescriptorToSecurityDescriptor(
"D:(A;;GA;;;RD)(A;;GA;;;S-1-5-32-544)(A;;GA;;;S-1-5-4)",
Win32.SDDL_REVISION_1,
out securityAttributes.lpSecurityDescriptor,
IntPtr.Zero
);
if (!bResult) { throw new Exception("ConvertStringSecurityDescriptorToSecurityDescriptor", new Win32Exception(Marshal.GetLastWin32Error())); }

securityAttributes.nLength = Marshal.SizeOf(securityAttributes);
securityAttributes.bInheritHandle = false;
hNamespace = Win32.CreatePrivateNamespace(
ref securityAttributes,
hBoundary,
"Alejacma"
);
if (hNamespace == IntPtr.Zero) { throw new Exception("CreatePrivateNamespace", new Win32Exception(Marshal.GetLastWin32Error())); }

// Create file mapping, and give access to all users with access to the namespace
hFile = Win32.CreateFileMapping(
Win32.INVALID_HANDLE_VALUE,
ref securityAttributes,
Win32.PAGE_READWRITE,
0,
20971520,
"Alejacma\\TestFileMapping"
);
if (hFile == IntPtr.Zero) { throw new Exception("CreateFileMapping", new Win32Exception(Marshal.GetLastWin32Error())); }

// Map file and write something to it
pView = Win32.MapViewOfFile(
hFile,
Win32.FILE_MAP_WRITE,
0,
0,
11
);
if (pView == IntPtr.Zero) { throw new Exception("MapViewOfFile", new Win32Exception(Marshal.GetLastWin32Error())); }

pData = Marshal.StringToHGlobalAnsi("Hello World");
Win32.MemCopy(pView, pData, 11);

// We are done. Now a reader app can access the data
MessageBox.Show("Run the reader app now!");
}
catch (Exception ex)
{
// Any error?
MessageBox.Show(ex.Message + " failed with '" + ex.InnerException.Message + "' error");
}
finally
{
// Clean up memory
if (pSid != IntPtr.Zero)
{
Marshal.FreeHGlobal(pSid);
}

if (securityAttributes.lpSecurityDescriptor != IntPtr.Zero)
{
Win32.LocalFree(securityAttributes.lpSecurityDescriptor);
}

if (pData != IntPtr.Zero)
{
Marshal.FreeHGlobal(pData);
}

// We must also close hBoundary, hNamespace, hFile and pView when we don't need them anymore.
// Check MSDN's description of the APIs we used to create them to figure out how to close them.
}
}
}
}

 

WIN32.CS

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using System.Security.Principal;

namespace Alejacma
{
class Win32
{
public const int SECURITY_MAX_SID_SIZE = 68;
public const int SDDL_REVISION_1 = 1;
public const uint INVALID_HANDLE_VALUE = 0xffffffff;
public const int PAGE_READWRITE = 0x04;
public const int FILE_MAP_WRITE = 0X02;

[StructLayout(LayoutKind.Sequential)]
public struct SECURITY_ATTRIBUTES
{
public int nLength;
public IntPtr lpSecurityDescriptor;
public bool bInheritHandle;
}

[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern IntPtr CreateBoundaryDescriptor
(
[In] string Name,
[In] int Flags
);

[DllImport("advapi32.dll", SetLastError = true)]
public static extern bool CreateWellKnownSid
(
[In] WellKnownSidType WellKnownSidType,
[In] [Optional] IntPtr DomainSid,
[In] IntPtr pSid,
[In][Out]ref int cbSid
);

[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool AddSIDToBoundaryDescriptor
(
[In][Out] ref IntPtr BoundaryDescriptor,
[In] IntPtr RequiredSid
);

[DllImport("advapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
public static extern bool ConvertStringSecurityDescriptorToSecurityDescriptor
(
[In] string StringSecurityDescriptor,
[In] int StringSDRevision,
[Out] out IntPtr SecurityDescriptor,
[Out] IntPtr SecurityDescriptorSize
);

[DllImport("kernel32.dll", SetLastError = true)]
public static extern IntPtr LocalFree([In] IntPtr hMem);

[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern IntPtr CreatePrivateNamespace(
[In][Optional] ref SECURITY_ATTRIBUTES lpPrivateNamespaceAttributes,
[In] IntPtr lpBoundaryDescriptor,
[In] string lpAliasPrefix
);

[DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern IntPtr CreateFileMapping(
[In] uint hFile,
[In][Optional] ref SECURITY_ATTRIBUTES lpAttributes,
[In] int flProtect,
[In] int dwMaximumSizeHigh,
[In] int dwMaximumSizeLow,
[In][Optional] string lpName
);

[DllImport("Kernel32.dll", SetLastError = true)]
public static extern IntPtr MapViewOfFile(
[In] IntPtr hFileMappingObject,
[In] int dwDesiredAccess,
[In] int dwFileOffsetHigh,
[In] int dwFileOffsetLow,
[In] int dwNumberOfBytesToMap
);

[DllImport("msvcrt.dll", EntryPoint = "memcpy", CallingConvention = CallingConvention.Cdecl, SetLastError = false)]
public static extern IntPtr MemCopy(IntPtr dest, IntPtr src, uint count);
}
}

 

I hope this helps.

Regards,

 

Alex (Alejandro Campos Magencio)