I have been heavily contemplating adding the Embedded MYSQL Server Library into my application. My software is a layer between a Game Server and a Web Management Panel that provides extra functionality. Many of our customers have been requesting MySQL databases for their servers (since this is what their plugins are developed to use), and being able to run one within my software rather than manually set them up would be fantastic.
Is there a .NET wrapper for this library I am missing?
The software being ran by my application will need to be able to connect to it, but the software is obviously being ran locally. Will this work?
i'm not aware of any .NET wrapper for this library although i remember there was a talk about introducing support for this library in the .NET Connector from version 5. I can't find any information about that right now though.
There is some sample code out there on the web which you can extend your code upon. I quess the most complete would be http://forums.mysql.com/read.php?38,67281,67917 ->
using System;
using System.Runtime.InteropServices;
using System.Diagnostics;
using System.Configuration;
class EntryPoint
{
[DllImport("libmySQL.dll")]
static extern IntPtr mysql_init(IntPtr mysql);
[DllImport("libmySQL.dll")]
static extern IntPtr mysql_fetch_lengths(IntPtr result);
[DllImport("libmySQL.dll")]
static extern IntPtr mysql_store_result(IntPtr mysql);
[DllImport("libmySQL.dll")]
static extern IntPtr mysql_fetch_row(IntPtr result);
[DllImport("libmySQL.dll")]
static extern IntPtr mysql_real_connect(IntPtr mysql, string host, string user, string passwd, string db, uint port, string unix_socket, uint client_flag);
[DllImport("libmySQL.dll")]
static extern uint mysql_field_count(IntPtr mysql);
[DllImport("libmySQL.dll")]
static extern string mysql_error(IntPtr mysql);
[DllImport("libmySQL.dll")]
static extern int mysql_real_query(IntPtr mysql, string query, uint length);
static Array MarshalArray(Type structureType, IntPtr arrayPtr, int length)
{
if (structureType == null)
throw new ArgumentNullException("structureType");
if (!structureType.IsValueType)
throw new ArgumentException("Only struct types are supported.", "structureType");
if (length < 0)
throw new ArgumentOutOfRangeException("length", length, "length must be equal to or greater than zero.");
if (arrayPtr == IntPtr.Zero)
return null;
int size = System.Runtime.InteropServices.Marshal.SizeOf(structureType);
Array array = Array.CreateInstance(structureType, length);
for (int i = 0; i < length; i++)
{
IntPtr offset = new IntPtr((long)arrayPtr + (size * i));
object value = System.Runtime.InteropServices.Marshal.PtrToStructure(offset, structureType);
array.SetValue(value, i);
}
return array;
}
static void mysql_real_query(IntPtr mysql, string query)
{
int result = (query != null) ? mysql_real_query(mysql, query, (uint)query.Length) : mysql_real_query(mysql, null, 0);
if (result == 0)
return;
throw new ApplicationException(mysql_error(mysql));
}
static int Main(string[] args)
{
IntPtr ptr = mysql_init(IntPtr.Zero);
Debug.Assert(ptr != IntPtr.Zero);
IntPtr mysql = mysql_real_connect(ptr, ConfigurationSettings.AppSettings["server"], ConfigurationSettings.AppSettings["username"], ConfigurationSettings.AppSettings["password"], ConfigurationSettings.AppSettings["database"], 0, null, 0);
Debug.Assert(ptr != IntPtr.Zero, mysql_error(ptr));
string query = "SELECT * FROM proxy_servers";
Console.WriteLine("Executing query: {0}", query);
mysql_real_query(mysql, query);
IntPtr result = mysql_store_result(mysql);
Debug.Assert(result != IntPtr.Zero, mysql_error(mysql));
uint fieldCount = mysql_field_count(mysql);
Console.WriteLine("field count: {0}", fieldCount);
for (IntPtr ptrRow = mysql_fetch_row(result); ptrRow != IntPtr.Zero; ptrRow = mysql_fetch_row(result))
{
IntPtr[] mysqlRow = (IntPtr[])MarshalArray(typeof(IntPtr), ptrRow, (int)fieldCount);
IntPtr ptrLengths = mysql_fetch_lengths(result);
uint[] lengths = (uint[])MarshalArray(typeof(uint), ptrLengths, (int)fieldCount);
for (int i = 0; i < (int)fieldCount; i++)
{
string str = Marshal.PtrToStringAnsi(mysqlRow[i], (int)lengths[i]);
Console.Write("{0}, ", str);
}
Console.WriteLine();
}
return 0;
}
}
Related
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Text;
using Microsoft.VisualBasic;
using Microsoft.VisualBasic.CompilerServices;
namespace BaseAddress
{
class Program`enter code here`
{
[DllImport("kernel32.dll")]
public static extern bool WriteProcessMemory(int hProcess, Int64 lpBaseAddress, byte[] lpBuffer,
int nSize, ref int lpNumberOfBytesWritten);
[DllImport("kernel32.dll")]
public static extern IntPtr OpenProcess(int dwDesiredAccess, bool bInheritHandle, int dwProcessId);
[DllImport("kernel32.dll")]
public static extern bool ReadProcessMemory(int hProcess,
Int64 lpBaseAddress, byte[] lpBuffer, int dwSize, ref int lpNumberOfBytesRead);
const int PROCESS_WM_ALL = 0xFFFF;
static void Main(string[] args)
{
Process[] process = Process.GetProcessesByName("Notepad");
Console.WriteLine(GetBase("Notepad"));
Console.WriteLine(GetAdd("Notepad",FromHex("59-00-6F-00-59-00"));
}
public static long GetAdd(string app, byte[] findthis)
{
byte[] buffer = new byte[findthis.Length];
int bytesRead = 0;
long foundAddr = 0;
Process[] processes = Process.GetProcessesByName(app);
Process process = processes[0];
IntPtr procHandle = OpenProcess(PROCESS_WM_ALL, false, process.Id);
long addr = 13188986418;
Console.WriteLine(addr);
Console.WriteLine("Starting address 0x{0}", (addr).ToString("X"));
bool ret2 = ReadProcessMemory((int)procHandle, addr, buffer, buffer.Length, ref bytesRead);
string p = BitConverter.ToString(buffer,0);
string tmp = BitConverter.ToString(findthis, 0);
Console.WriteLine(p);
Console.WriteLine(tmp);
if (p == tmp)
{
foundAddr = addr;
Console.WriteLine("Found it at 0x{0}", foundAddr.ToString("X"));
} else
{
Console.WriteLine("NO");
}
return foundAddr;
}
static long GetBase(string app)
{
long add = 0;
using (Process proc = new Process())
{
Process[] processes = Process.GetProcessesByName(app);
ProcessModule pm;
ProcessModuleCollection pmc = processes[0].Modules;
for (int i = 0; i < pmc.Count; i++)
{
pm = pmc[i];
if(pm.ModuleName.Replace(".exe","") == processes[0].ProcessName)
{
add = pm.BaseAddress.ToInt64();
}
}
}
return add;
}
public static byte[] FromHex(string hex)
{
hex = hex.Replace("-", "");
byte[] raw = new byte[hex.Length / 2];
for (int i = 0; i < raw.Length; i++)
{
raw[i] = Convert.ToByte(hex.Substring(i * 2, 2), 16);
}
return raw;
}
So what I'm trying to do is create a function that I can provide the process name ("Notepad" in this example) and a byte array (in hex) and then the program scans the process in memory, finds the first instance of the matching array, and provides the address of it.
This works for finding a byte array BUT i have to hard code the starting point
what i don't understand is how the base address is 140696861212672 (dec)
yet the address where the code actually is is 13188986418 (dec)
This is the console output:
140696861212672
13188986418
Starting address 0x3121FF632
59-00-6F-00-59-00
59-00-6F-00-59-00
Found it at 0x3121FF632
13188986418
Any idea how i can get this to start at the start of the memory, skip empty zones in memory and loop a chunk of byte array until the array is found?
Hope that makes sense. Any help is welcome.
I am trying to import the GnuTLS library to my C# project and use its APIs. Unfortunately, I cannot find any way on how to do this with the C-based GnuTLS library.
Does anyone know a way on how to use the GnuTLS library in a C# project or even on how to use the Windows build of the GnuTLS library available on their website https://www.gnutls.org/download.html so that I can run it using a C compiler and use the P/Invoke in C# to access the necessary APIs.
(In C#, I tried to import the libraries as reference using MSVS2010 but it says that it is not a valid .NET assembly nor a COM component)
(Also tried the Windows build of this library using a simple C code that calls a function but fails on compilation due to an error "... undefined reference to ...". I put the header files in MinGW directory as well as the DLL and EXE files).
You can use gnutls via P\Invoke. So it's worked on unix platforms.
Example on linux:
namespace GnuTlsExample
{
internal static class NativeMethodsLinux {
internal enum GNUTLS_X509_FMT
{
GNUTLS_X509_FMT_DER = 0,
GNUTLS_X509_FMT_PEM = 1
}
[DllImport("libgnutls.so.30")]
internal static extern int gnutls_x509_crt_list_import(IntPtr certs, ref int cert_max, IntPtr data, GNUTLS_X509_FMT format, uint flags);
[DllImport("libgnutls.so.30")]
internal static extern int gnutls_x509_privkey_init(ref IntPtr key);
[DllImport("libgnutls.so.30")]
internal static extern int gnutls_x509_privkey_import(IntPtr key, IntPtr data, GNUTLS_X509_FMT format);
[DllImport("libgnutls.so.30")]
internal static extern int gnutls_certificate_set_x509_key(IntPtr cred, IntPtr certs, int max, IntPtr key);
[StructLayout(LayoutKind.Sequential)]
internal class gnutls_datum_t
{
public IntPtr data = IntPtr.Zero;
public int size = 0;
}
}
class Program
{
static void Main(string[] args)
{
var buf = ByteArrayToGnuTlsDatum(File.ReadAllBytes(certificateFilePath));
var certs = Marshal.AllocHGlobal(IntPtr.Size);
var max = 6;
var tlsCtx = IntPtr.Zero;
var isServer = 0;
var key = IntPtr.Zero;
var bufKey = MarshalUtils.ByteArrayToGnuTlsDatum(File.ReadAllBytes(keyFilePath));
var res = NativeMethodsLinux.gnutls_x509_privkey_init(ref key);
res = NativeMethodsLinux.gnutls_x509_privkey_import(key, bufKey,
NativeMethodsLinux.GNUTLS_X509_FMT.GNUTLS_X509_FMT_PEM);
res = NativeMethodsLinux.gnutls_x509_crt_list_import(certs, ref max, buf,
NativeMethodsLinux.GNUTLS_X509_FMT.GNUTLS_X509_FMT_PEM, 0);
var cred = Marshal.AllocHGlobal(IntPtr.Size);
res = NativeMethodsLinux.gnutls_certificate_set_x509_key(cred, certs, max, key);
}
internal static IntPtr ByteArrayToGnuTlsDatum(byte[] bytes)
{
var berPtr = Marshal.AllocHGlobal(Marshal.SizeOf<NativeMethodsLinux.gnutls_datum_t>());
var valPtr = Marshal.AllocHGlobal(bytes.Length);
Marshal.Copy(bytes,0,valPtr,bytes.Length);
Marshal.StructureToPtr(new NativeMethodsLinux.gnutls_datum_t
{
data = valPtr,
size = bytes.Length
}, berPtr, true);
return berPtr;
}
}
}
We suddenly have problems with the smart card api on some windows installations.
There seem to be a memory leak while calling the SCardEstablishContext function.
The problem can be reproduced in a console application with the code sample available at
http://www.pinvoke.net/default.aspx/winscard.scardestablishcontext
class Program
{
#region Win32
// WinSCard APIs to be imported.
[DllImport("WinScard.dll")]
static extern int SCardEstablishContext(uint dwScope,
IntPtr notUsed1,
IntPtr notUsed2,
out IntPtr phContext);
[DllImport("WinScard.dll")]
static extern int SCardReleaseContext(IntPtr phContext);
[DllImport("WinScard.dll")]
static extern int SCardConnect(IntPtr hContext,
string cReaderName,
uint dwShareMode,
uint dwPrefProtocol,
ref IntPtr phCard,
ref IntPtr ActiveProtocol);
[DllImport("WinScard.dll")]
static extern int SCardDisconnect(IntPtr hCard, int Disposition);
[DllImport("WinScard.dll", EntryPoint = "SCardListReadersA", CharSet = CharSet.Ansi)]
static extern int SCardListReaders(
IntPtr hContext,
byte[] mszGroups,
byte[] mszReaders,
ref UInt32 pcchReaders);
#endregion
static void Main(string[] args)
{
while (true)
{
SmartCardInserted();
System.Threading.Thread.Sleep(10);
}
}
internal static bool SmartCardInserted()
{
bool cardInserted = false;
IntPtr hContext = IntPtr.Zero;
try
{
List<string> readersList = new List<string>();
int ret = 0;
uint pcchReaders = 0;
int nullindex = -1;
char nullchar = (char)0;
// Establish context.
ret = SCardEstablishContext(2, IntPtr.Zero, IntPtr.Zero, out hContext);
// First call with 3rd parameter set to null gets readers buffer length.
ret = SCardListReaders(hContext, null, null, ref pcchReaders);
byte[] mszReaders = new byte[pcchReaders];
// Fill readers buffer with second call.
ret = SCardListReaders(hContext, null, mszReaders, ref pcchReaders);
// Populate List with readers.
ASCIIEncoding ascii = new ASCIIEncoding();
string currbuff = ascii.GetString(mszReaders);
int len = (int)pcchReaders;
if (len > 0)
{
while (currbuff[0] != nullchar)
{
nullindex = currbuff.IndexOf(nullchar); // Get null end character.
string reader = currbuff.Substring(0, nullindex);
readersList.Add(reader);
len = len - (reader.Length + 1);
currbuff = currbuff.Substring(nullindex + 1, len);
}
}
// We have list of readers, check for cards.
IntPtr phCard = IntPtr.Zero;
IntPtr ActiveProtocol = IntPtr.Zero;
int result = 0;
foreach (string readerName in readersList)
{
try
{
result = SCardConnect(hContext, readerName, 2, 3, ref phCard, ref ActiveProtocol);
if (result == 0)
{
cardInserted = true;
break;
}
}
finally
{
SCardDisconnect(phCard, 0);
}
}
}
finally
{
SCardReleaseContext(hContext);
}
return cardInserted;
}
}
To test, we call the method SmartCardInserted() in an infinite loop with a small delay => the memory grows constantly and new hadles are allocated.
We see this problem on systems runing Windows 10 or Windows Server 2012, but not on Windows Server 2008.
Any ideas are greatly appreciated!
The problem seems to have been released with v1709 of Windows 10. The shortest amount of code to reproduce the bug is
while(true) {
ret = SCardEstablishContext(2, IntPtr.Zero, IntPtr.Zero, out hContext);
SCardReleaseContext(hContext);
}
It leaks ~264 bytes of memory each time a context is established and released.
If you maintain hContext outside of the loop and only create a context if it's IntPtr.Zero you should be able to avoid the leak. Then when you call SCardListReaders, check to see if you get SCARD_E_INVALID_HANDLE back and invalidate your hContext.
class Program
{
#region Win32
// WinSCard APIs to be imported.
[DllImport("WinScard.dll")]
static extern int SCardEstablishContext(uint dwScope,
IntPtr notUsed1,
IntPtr notUsed2,
out IntPtr phContext);
[DllImport("WinScard.dll")]
static extern int SCardReleaseContext(IntPtr phContext);
[DllImport("WinScard.dll")]
static extern int SCardConnect(IntPtr hContext,
string cReaderName,
uint dwShareMode,
uint dwPrefProtocol,
ref IntPtr phCard,
ref IntPtr ActiveProtocol);
[DllImport("WinScard.dll")]
static extern int SCardDisconnect(IntPtr hCard, int Disposition);
[DllImport("WinScard.dll", EntryPoint = "SCardListReadersA", CharSet = CharSet.Ansi)]
static extern int SCardListReaders(
IntPtr hContext,
byte[] mszGroups,
byte[] mszReaders,
ref UInt32 pcchReaders);
#endregion
static void Main(string[] args)
{
IntPtr hContext = IntPtr.Zero;
while (true)
{
SmartCardInserted(hContext);
System.Threading.Thread.Sleep(10);
}
SCardReleaseContext(hContext);
}
internal static bool SmartCardInserted(IntPtr hContext)
{
bool cardInserted = false;
try
{
List<string> readersList = new List<string>();
int ret = 0;
uint pcchReaders = 0;
int nullindex = -1;
char nullchar = (char)0;
// Establish context.
if(hContext == IntPtr.Zero)
ret = SCardEstablishContext(2, IntPtr.Zero, IntPtr.Zero, out hContext);
// First call with 3rd parameter set to null gets readers buffer length.
ret = SCardListReaders(hContext, null, null, ref pcchReaders);
if(ret == 0x80100003) // SCARD_E_INVALID_HANDLE = 0x80100003, // The supplied handle was invalid
{
try
{
SCardReleaseContext(hContext);
}
catch {}
finally
{
hContext = IntPtr.Zero;
}
return false;
}
byte[] mszReaders = new byte[pcchReaders];
// Fill readers buffer with second call.
ret = SCardListReaders(hContext, null, mszReaders, ref pcchReaders);
// Populate List with readers.
ASCIIEncoding ascii = new ASCIIEncoding();
string currbuff = ascii.GetString(mszReaders);
int len = (int)pcchReaders;
if (len > 0)
{
while (currbuff[0] != nullchar)
{
nullindex = currbuff.IndexOf(nullchar); // Get null end character.
string reader = currbuff.Substring(0, nullindex);
readersList.Add(reader);
len = len - (reader.Length + 1);
currbuff = currbuff.Substring(nullindex + 1, len);
}
}
// We have list of readers, check for cards.
IntPtr phCard = IntPtr.Zero;
IntPtr ActiveProtocol = IntPtr.Zero;
int result = 0;
foreach (string readerName in readersList)
{
try
{
result = SCardConnect(hContext, readerName, 2, 3, ref phCard, ref ActiveProtocol);
if (result == 0)
{
cardInserted = true;
break;
}
}
finally
{
SCardDisconnect(phCard, 0);
}
}
}
return cardInserted;
}
}
It's a workaround until the Winscard.dll API is fixed.
I'm trying to get the name of the Windows 8 App that is running with a given ProcessID.
I can get to wwahost, that is the real name of the process that is running, but I want to get the name of the App that WWHOST is actually running.
I saw this thread http://social.msdn.microsoft.com/Forums/en-US/windowsgeneraldevelopmentissues/thread/c9665bf4-00e4-476c-badb-37126efd3f4b/ with that discussion, but there is no specific answer.
any ideas ?
You want to call GetApplicationUserModelId
The sample application provided allows you to pass in a PID and get back the information about the app. For instance:
C:\src\GetAppInfo\Debug>GetAppInfo.exe 7400
Process 7400 (handle=00000044)
Microsoft.BingWeather_8wekyb3d8bbwe!App
To port to C#,
const int QueryLimitedInformation = 0x1000;
const int ERROR_INSUFFICIENT_BUFFER = 0x7a;
const int ERROR_SUCCESS = 0x0;
[DllImport("kernel32.dll")]
internal static extern IntPtr OpenProcess(int dwDesiredAccess, bool bInheritHandle, int dwProcessId);
[DllImport("kernel32.dll")]
static extern bool CloseHandle(IntPtr hHandle);
[DllImport("kernel32.dll")]
internal static extern Int32 GetApplicationUserModelId(
IntPtr hProcess,
ref UInt32 AppModelIDLength,
[MarshalAs(UnmanagedType.LPWStr)] StringBuilder sbAppUserModelID);
Then, your code should look something like this:
if (sProcessName.ToLower().Contains("wwahost")
&& ((Environment.OSVersion.Version.Major == 6) && (Environment.OSVersion.Version.Minor > 1)))
{
IntPtr ptrProcess = OpenProcess(QueryLimitedInformation, false, iPID);
if (IntPtr.Zero != ptrProcess)
{
uint cchLen = 130; // Currently APPLICATION_USER_MODEL_ID_MAX_LENGTH = 130
StringBuilder sbName = new StringBuilder((int)cchLen);
Int32 lResult = GetApplicationUserModelId(ptrProcess, ref cchLen, sbName);
if (ERROR_SUCCESS == lResult)
{
sResult = sbName.ToString();
}
else if (ERROR_INSUFFICIENT_BUFFER == lResult)
{
sbName = new StringBuilder((int)cchLen);
if (ERROR_SUCCESS == GetApplicationUserModelId(ptrProcess, ref cchLen, sbName))
{
sResult = sbName.ToString();
}
}
CloseHandle(ptrProcess);
}
}
Have a look at Get executing assembly name from referenced DLL in C#
You could look around Assembly.GetEntryAssembly() or Assembly.GetExecutingAssembly() e.g.
string exeAssemblyName = Assembly.GetEntryAssembly().GetName().Name;
Here's some C# source code which implements an unmanaged DLL (advapi32).
public void AddPrivileges(string account, string privilege)
{
IntPtr pSid = GetSIDInformation(account);
LSA_UNICODE_STRING[] privileges = new LSA_UNICODE_STRING[1];
privileges[0] = InitLsaString(privilege);
uint ret = Win32Sec.LsaAddAccountRights(lsaHandle, pSid, privileges, 1);
if (ret == 0)
return;
if (ret == STATUS_ACCESS_DENIED)
{
throw new UnauthorizedAccessException();
}
if ((ret == STATUS_INSUFFICIENT_RESOURCES) || (ret == STATUS_NO_MEMORY))
{
throw new OutOfMemoryException();
}
int error = Win32Sec.LsaNtStatusToWinError((int)ret);
throw new Win32Exception(error);
}
The variable values at runtime are as follows:
privilege: "SeServiceLogonRight"
account: "named"
ret: 3221225485 (STATUS_INVALID_PARAMETER)
error: 87
When caught, the message within the Win32Exception is: "The parameter is incorrect"
The code is running on Windows Web Server 2008. I can verify that the account does exist, and this code works fine on another server... I'm not sure if this could have been caused by Windows 2008 SP2. I'm thinking that I've forgotten to install something, but I can't think what...
The code is from: http://weblogs.asp.net/avnerk/archive/2007/05/10/granting-user-rights-in-c.aspx
Following the provided link through to the code at http://www.hightechtalks.com/csharp/lsa-functions-276626.html
IntPtr GetSIDInformation(string account)
{
LSA_UNICODE_STRING[] names = new LSA_UNICODE_STRING[1];
LSA_TRANSLATED_SID2 lts;
IntPtr tsids = IntPtr.Zero;
IntPtr tdom = IntPtr.Zero;
names[0] = InitLsaString(account);
lts.Sid = IntPtr.Zero;
Console.WriteLine("String account: {0}", names[0].Length);
int ret = Win32Sec.LsaLookupNames2(lsaHandle, 0, 1, names, ref tdom, ref tsids);
if (ret != 0)
{
throw new Win32Exception(Win32Sec.LsaNtStatusToWinError(ret));
}
lts = (LSA_TRANSLATED_SID2) Marshal.PtrToStructure(tsids,
typeof(LSA_TRANSLATED_SID2));
Win32Sec.LsaFreeMemory(tsids);
Win32Sec.LsaFreeMemory(tdom);
return lts.Sid;
}
lts (an LSA_TRANSLATED_SID2 struct) contains a pointer that points at memory that is freed by the call to Win32Sec.LsaFreeMemory. Using the pointer after the memory is freed is bad practice and will have unpredictable results -- it might even "work".
Tweaking the code at the link by using the SecurityIdentifier class (.Net 2 and above) along a little cleanup of unneeded code avoids the memory problem.
using System;
namespace Willys.LsaSecurity
{
using System.ComponentModel;
using System.Runtime.InteropServices;
using System.Security;
using System.Security.Principal;
using LSA_HANDLE = IntPtr;
[StructLayout(LayoutKind.Sequential)]
struct LSA_OBJECT_ATTRIBUTES
{
internal int Length;
internal IntPtr RootDirectory;
internal IntPtr ObjectName;
internal int Attributes;
internal IntPtr SecurityDescriptor;
internal IntPtr SecurityQualityOfService;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
struct LSA_UNICODE_STRING
{
internal ushort Length;
internal ushort MaximumLength;
[MarshalAs(UnmanagedType.LPWStr)]
internal string Buffer;
}
sealed class Win32Sec
{
[DllImport("advapi32", CharSet = CharSet.Unicode, SetLastError = true), SuppressUnmanagedCodeSecurityAttribute]
internal static extern uint LsaOpenPolicy(
LSA_UNICODE_STRING[] SystemName,
ref LSA_OBJECT_ATTRIBUTES ObjectAttributes,
int AccessMask,
out IntPtr PolicyHandle
);
[DllImport("advapi32", CharSet = CharSet.Unicode, SetLastError = true), SuppressUnmanagedCodeSecurityAttribute]
internal static extern uint LsaAddAccountRights(
LSA_HANDLE PolicyHandle,
IntPtr pSID,
LSA_UNICODE_STRING[] UserRights,
int CountOfRights
);
[DllImport("advapi32")]
internal static extern int LsaNtStatusToWinError(int NTSTATUS);
[DllImport("advapi32")]
internal static extern int LsaClose(IntPtr PolicyHandle);
}
sealed class Sid : IDisposable
{
public IntPtr pSid = IntPtr.Zero;
public SecurityIdentifier sid = null;
public Sid(string account)
{
sid = (SecurityIdentifier) (new NTAccount(account)).Translate(typeof(SecurityIdentifier));
Byte[] buffer = new Byte[sid.BinaryLength];
sid.GetBinaryForm(buffer, 0);
pSid = Marshal.AllocHGlobal(sid.BinaryLength);
Marshal.Copy(buffer, 0, pSid, sid.BinaryLength);
}
public void Dispose()
{
if (pSid != IntPtr.Zero)
{
Marshal.FreeHGlobal(pSid);
pSid = IntPtr.Zero;
}
GC.SuppressFinalize(this);
}
~Sid()
{
Dispose();
}
}
public sealed class LsaWrapper : IDisposable
{
enum Access : int
{
POLICY_READ = 0x20006,
POLICY_ALL_ACCESS = 0x00F0FFF,
POLICY_EXECUTE = 0X20801,
POLICY_WRITE = 0X207F8
}
const uint STATUS_ACCESS_DENIED = 0xc0000022;
const uint STATUS_INSUFFICIENT_RESOURCES = 0xc000009a;
const uint STATUS_NO_MEMORY = 0xc0000017;
IntPtr lsaHandle;
public LsaWrapper()
: this(null)
{ }
// // local system if systemName is null
public LsaWrapper(string systemName)
{
LSA_OBJECT_ATTRIBUTES lsaAttr;
lsaAttr.RootDirectory = IntPtr.Zero;
lsaAttr.ObjectName = IntPtr.Zero;
lsaAttr.Attributes = 0;
lsaAttr.SecurityDescriptor = IntPtr.Zero;
lsaAttr.SecurityQualityOfService = IntPtr.Zero;
lsaAttr.Length = Marshal.SizeOf(typeof(LSA_OBJECT_ATTRIBUTES));
lsaHandle = IntPtr.Zero;
LSA_UNICODE_STRING[] system = null;
if (systemName != null)
{
system = new LSA_UNICODE_STRING[1];
system[0] = InitLsaString(systemName);
}
uint ret = Win32Sec.LsaOpenPolicy(system, ref lsaAttr,
(int) Access.POLICY_ALL_ACCESS, out lsaHandle);
if (ret == 0)
return;
if (ret == STATUS_ACCESS_DENIED)
{
throw new UnauthorizedAccessException();
}
if ((ret == STATUS_INSUFFICIENT_RESOURCES) || (ret == STATUS_NO_MEMORY))
{
throw new OutOfMemoryException();
}
throw new Win32Exception(Win32Sec.LsaNtStatusToWinError((int) ret));
}
public void AddPrivileges(string account, string privilege)
{
uint ret = 0;
using (Sid sid = new Sid(account))
{
LSA_UNICODE_STRING[] privileges = new LSA_UNICODE_STRING[1];
privileges[0] = InitLsaString(privilege);
ret = Win32Sec.LsaAddAccountRights(lsaHandle, sid.pSid, privileges, 1);
}
if (ret == 0)
return;
if (ret == STATUS_ACCESS_DENIED)
{
throw new UnauthorizedAccessException();
}
if ((ret == STATUS_INSUFFICIENT_RESOURCES) || (ret == STATUS_NO_MEMORY))
{
throw new OutOfMemoryException();
}
throw new Win32Exception(Win32Sec.LsaNtStatusToWinError((int) ret));
}
public void Dispose()
{
if (lsaHandle != IntPtr.Zero)
{
Win32Sec.LsaClose(lsaHandle);
lsaHandle = IntPtr.Zero;
}
GC.SuppressFinalize(this);
}
~LsaWrapper()
{
Dispose();
}
// helper functions
static LSA_UNICODE_STRING InitLsaString(string s)
{
// Unicode strings max. 32KB
if (s.Length > 0x7ffe)
throw new ArgumentException("String too long");
LSA_UNICODE_STRING lus = new LSA_UNICODE_STRING();
lus.Buffer = s;
lus.Length = (ushort) (s.Length * sizeof(char));
lus.MaximumLength = (ushort) (lus.Length + sizeof(char));
return lus;
}
}
}
I couldn't get this to work, so instead I used the source code from the CodeProject project, LSA Functions - Privileges and Impersonation which works nicely.
lts.Sid is freed before returning in GetSIDInformation.
Moving the codes of GetSIDInformation out. It worked fine for .Net 4.5.
public void AddPrivileges(string account, string privilege)
{
LSA_UNICODE_STRING[] names = new LSA_UNICODE_STRING[1];
LSA_TRANSLATED_SID2 lts;
IntPtr tsids = IntPtr.Zero;
IntPtr tdom = IntPtr.Zero;
names[0] = InitLsaString(account);
lts.Sid = IntPtr.Zero;
Console.WriteLine("String account: {0}", names[0].Length);
int ret1 = Win32Sec.LsaLookupNames2(lsaHandle, 0, 1, names, ref tdom, ref tsids);
if (ret1 != 0)
throw new Win32Exception(Win32Sec.LsaNtStatusToWinError(ret1));
lts = (LSA_TRANSLATED_SID2)Marshal.PtrToStructure(tsids, typeof(LSA_TRANSLATED_SID2));
IntPtr pSid = lts.Sid;
//IntPtr pSid = GetSIDInformation(account);
LSA_UNICODE_STRING[] privileges = new LSA_UNICODE_STRING[1];
privileges[0] = InitLsaString(privilege);
uint ret = Win32Sec.LsaAddAccountRights(lsaHandle, pSid, privileges, 1);
Win32Sec.LsaFreeMemory(tsids);
Win32Sec.LsaFreeMemory(tdom);
if (ret == 0)
return;
if (ret == STATUS_ACCESS_DENIED)
{
throw new UnauthorizedAccessException();
}
if ((ret == STATUS_INSUFFICIENT_RESOURCES) || (ret == STATUS_NO_MEMORY))
{
throw new OutOfMemoryException();
}
throw new Win32Exception(Win32Sec.LsaNtStatusToWinError((int)ret));
}
I came across the same error when calling LsaAddAccountRights and I found out I was using sizeof(char) instead of sizeof(wchar) when initializing LSA_UNICODE_STRING.
I checked the code at http://www.codeproject.com/KB/cs/lsadotnet.aspx and found similar issue:
static LSA_UNICODE_STRING InitLsaString(string s)
{
// Unicode strings max. 32KB
if (s.Length > 0x7ffe)
throw new ArgumentException("String too long");
LSA_UNICODE_STRING lus = new LSA_UNICODE_STRING();
lus.Buffer = s;
lus.Length = (ushort)(s.Length * sizeof(char));
lus.MaximumLength = (ushort)(lus.Length + sizeof(char));
return lus;
}
Should be something like:
lus.Length = (ushort)(s.Length * UnicodeEncoding.CharSize);
lus.MaximumLength = (ushort)(lus.Length + UnicodeEncoding.CharSize);
I was able to get this working on one box but then on another box it failed with the error you received:
System.ComponentModel.Win32Exception: The parameter is incorrect
I discovered that the root cause of this issue for me had to do with architecture of the process that was running the code. I was running a msbuild 32-bit process which worked fine, but when I used the 64-bit msbuild.exe to run this it failed with this error.
I hope that helps!
Regards,
Brandon
I found this problem is related to .NET 4.0. Downgrade your project to .NET 3.5 and it will work.