NetUserSetInfo and SecureString

B

Brian Stoop

Hi,

[DllImport("Netapi32.dll")]
extern public static int NetUserSetInfo(
[MarshalAs(UnmanagedType.LPWStr)] string servername,
[MarshalAs(UnmanagedType.LPWStr)] string username,
int level,
ref USER_INFO_1003 buf,
int error);

public struct USER_INFO_1003
{
public string usri1003_password;
}

I currently use strings to pass passwords into USER_INFO_1003 passwords, and
call NetSetInfo to set the password for an account somewhere, e.g:

string newpassword="SomePassword";

USER_INFO_1003 UserInfo1003 = new USER_INFO_1003();
UserInfo1003.usri1003_password = newpassword;


Now I store passwords in SecureStrings. How set passwords in NetUserSetInfo
calls without converting them to a string?



thanks, B
 
S

Stanimir Stoyanov \(C# MVP\)

Hi Brian,

You can use the Marshal.SecureStringToGlobalAllocUnicode [1] method to
allocate a Unicode representation of your SecureString. To avoid any further
processing of the password, I would recommend changing the definition of
USER_INFO_1003: change the string field to an IntPtr (a pointer to a block
of memory).

After you have finished using the password, you have to release the block of
memory by calling Marshal.ZeroFreeGlobalAllocUnicode [2].

SecureString password; // Initialize the password SecureString object

IntPtr pPassword = Marshal.SecureStringToGlobalAllocUnicode(password);

if (pPassword != IntPtr.Zero)
{
// Perform this check if reading memory at pPassword because if the
original password value is null, SecureStringToGlobalAllocUnicode will
return 0, resulting in an AccessViolationException.

// Sanity test
string passwordTest = Marshal.PtrToStringUni(pPassword);

// ...

Marshal.ZeroFreeGlobalAllocUnicode(pPassword)
}

[1]
http://msdn.microsoft.com/en-us/lib...marshal.securestringtoglobalallocunicode.aspx
[2]
http://msdn.microsoft.com/en-us/lib...vices.marshal.zerofreeglobalallocunicode.aspx

Regards,
Stanimir Stoyanov
Visual C# MVP
http://stoyanoff.info
 
B

Brian Stoop

Mnogo blagodarya. You have answered my question 100%.

B.


Stanimir Stoyanov (C# MVP) said:
Hi Brian,

You can use the Marshal.SecureStringToGlobalAllocUnicode [1] method to
allocate a Unicode representation of your SecureString. To avoid any
further processing of the password, I would recommend changing the
definition of USER_INFO_1003: change the string field to an IntPtr (a
pointer to a block of memory).

After you have finished using the password, you have to release the block
of memory by calling Marshal.ZeroFreeGlobalAllocUnicode [2].

SecureString password; // Initialize the password SecureString object

IntPtr pPassword = Marshal.SecureStringToGlobalAllocUnicode(password);

if (pPassword != IntPtr.Zero)
{
// Perform this check if reading memory at pPassword because if the
original password value is null, SecureStringToGlobalAllocUnicode will
return 0, resulting in an AccessViolationException.

// Sanity test
string passwordTest = Marshal.PtrToStringUni(pPassword);

// ...

Marshal.ZeroFreeGlobalAllocUnicode(pPassword)
}

[1]
http://msdn.microsoft.com/en-us/lib...marshal.securestringtoglobalallocunicode.aspx
[2]
http://msdn.microsoft.com/en-us/lib...vices.marshal.zerofreeglobalallocunicode.aspx

Regards,
Stanimir Stoyanov
Visual C# MVP
http://stoyanoff.info

Brian Stoop said:
Hi,

[DllImport("Netapi32.dll")]
extern public static int NetUserSetInfo(
[MarshalAs(UnmanagedType.LPWStr)] string servername,
[MarshalAs(UnmanagedType.LPWStr)] string username,
int level,
ref USER_INFO_1003 buf,
int error);

public struct USER_INFO_1003
{
public string usri1003_password;
}

I currently use strings to pass passwords into USER_INFO_1003 passwords,
and call NetSetInfo to set the password for an account somewhere, e.g:

string newpassword="SomePassword";

USER_INFO_1003 UserInfo1003 = new USER_INFO_1003();
UserInfo1003.usri1003_password = newpassword;


Now I store passwords in SecureStrings. How set passwords in
NetUserSetInfo calls without converting them to a string?



thanks, B
 
B

Brian Stoop

Hi Stanimir,

Your suggestion:- IntPtr pPassword =
Marshal.SecureStringToGlobalAllocUnicode(password)
worked with NetUserSetInfo thanks.

But I tried using this pointer in the following circumstances.

1. de.Invoke("SetPassword", pPassword);

- The Invoke was successful, but the password did'nt work.


2. [DllImport("Netapi32.dll")]
extern public static unsafe int NetUserChangePassword(
[MarshalAs(UnmanagedType.LPWStr)] string domain,
[MarshalAs(UnmanagedType.LPWStr)] string username,
[MarshalAs(UnmanagedType.LPWStr)] IntPtr oldpassword,
[MarshalAs(UnmanagedType.LPWStr)] IntPtr newpassword);
NetUserSetPassword(domain, user, pPassword, pPassword);

- NetUserSetPassword failed, with a casting exception.


Do you know how SecureStrings used with DirectoryEntry SetPassword Invoke,
and NetUserSetPassword ?


Thanks, B



Stanimir Stoyanov (C# MVP) said:
Hi Brian,

You can use the Marshal.SecureStringToGlobalAllocUnicode [1] method to
allocate a Unicode representation of your SecureString. To avoid any
further processing of the password, I would recommend changing the
definition of USER_INFO_1003: change the string field to an IntPtr (a
pointer to a block of memory).

After you have finished using the password, you have to release the block
of memory by calling Marshal.ZeroFreeGlobalAllocUnicode [2].

SecureString password; // Initialize the password SecureString object

IntPtr pPassword = Marshal.SecureStringToGlobalAllocUnicode(password);

if (pPassword != IntPtr.Zero)
{
// Perform this check if reading memory at pPassword because if the
original password value is null, SecureStringToGlobalAllocUnicode will
return 0, resulting in an AccessViolationException.

// Sanity test
string passwordTest = Marshal.PtrToStringUni(pPassword);

// ...

Marshal.ZeroFreeGlobalAllocUnicode(pPassword)
}

[1]
http://msdn.microsoft.com/en-us/lib...marshal.securestringtoglobalallocunicode.aspx
[2]
http://msdn.microsoft.com/en-us/lib...vices.marshal.zerofreeglobalallocunicode.aspx

Regards,
Stanimir Stoyanov
Visual C# MVP
http://stoyanoff.info

Brian Stoop said:
Hi,

[DllImport("Netapi32.dll")]
extern public static int NetUserSetInfo(
[MarshalAs(UnmanagedType.LPWStr)] string servername,
[MarshalAs(UnmanagedType.LPWStr)] string username,
int level,
ref USER_INFO_1003 buf,
int error);

public struct USER_INFO_1003
{
public string usri1003_password;
}

I currently use strings to pass passwords into USER_INFO_1003 passwords,
and call NetSetInfo to set the password for an account somewhere, e.g:

string newpassword="SomePassword";

USER_INFO_1003 UserInfo1003 = new USER_INFO_1003();
UserInfo1003.usri1003_password = newpassword;


Now I store passwords in SecureStrings. How set passwords in
NetUserSetInfo calls without converting them to a string?



thanks, B
 
S

Stanimir Stoyanov \(C# MVP\)

Hi Brian,

The DirectoryEntry SetPassword method [1] appears to expect the password as
a BSTR, which is different than the pPassword pointer we already have (an
LPWSTR). In this case, you will have to reuse the original code with a
couple of changes when calling Marshal's methods: SecureStringToBSTR and
ZeroFreeBSTR.

Regarding the NetUserChangePassword casting issue, remove the MarshalAs
attributes from the two IntPtr parameters. This attribute is not necessary
(actually should not be there) for this data type.

It is important that the expected data types match the ones you pass to the
native API. MSDN has most, if not all, of these covered.

[1] http://msdn.microsoft.com/en-us/library/aa746344(VS.85).aspx

HTH,
--
Stanimir Stoyanov
Visual C# MVP
http://stoyanoff.info

Brian Stoop said:
Hi Stanimir,

Your suggestion:- IntPtr pPassword =
Marshal.SecureStringToGlobalAllocUnicode(password)
worked with NetUserSetInfo thanks.

But I tried using this pointer in the following circumstances.

1. de.Invoke("SetPassword", pPassword);

- The Invoke was successful, but the password did'nt work.


2. [DllImport("Netapi32.dll")]
extern public static unsafe int NetUserChangePassword(
[MarshalAs(UnmanagedType.LPWStr)] string domain,
[MarshalAs(UnmanagedType.LPWStr)] string username,
[MarshalAs(UnmanagedType.LPWStr)] IntPtr oldpassword,
[MarshalAs(UnmanagedType.LPWStr)] IntPtr
newpassword);
NetUserSetPassword(domain, user, pPassword, pPassword);

- NetUserSetPassword failed, with a casting exception.


Do you know how SecureStrings used with DirectoryEntry SetPassword Invoke,
and NetUserSetPassword ?


Thanks, B



Stanimir Stoyanov (C# MVP) said:
Hi Brian,

You can use the Marshal.SecureStringToGlobalAllocUnicode [1] method to
allocate a Unicode representation of your SecureString. To avoid any
further processing of the password, I would recommend changing the
definition of USER_INFO_1003: change the string field to an IntPtr (a
pointer to a block of memory).

After you have finished using the password, you have to release the block
of memory by calling Marshal.ZeroFreeGlobalAllocUnicode [2].

SecureString password; // Initialize the password SecureString object

IntPtr pPassword = Marshal.SecureStringToGlobalAllocUnicode(password);

if (pPassword != IntPtr.Zero)
{
// Perform this check if reading memory at pPassword because if
the original password value is null, SecureStringToGlobalAllocUnicode
will return 0, resulting in an AccessViolationException.

// Sanity test
string passwordTest = Marshal.PtrToStringUni(pPassword);

// ...

Marshal.ZeroFreeGlobalAllocUnicode(pPassword)
}

[1]
http://msdn.microsoft.com/en-us/lib...marshal.securestringtoglobalallocunicode.aspx
[2]
http://msdn.microsoft.com/en-us/lib...vices.marshal.zerofreeglobalallocunicode.aspx

Regards,
Stanimir Stoyanov
Visual C# MVP
http://stoyanoff.info

Brian Stoop said:
Hi,

[DllImport("Netapi32.dll")]
extern public static int NetUserSetInfo(
[MarshalAs(UnmanagedType.LPWStr)] string servername,
[MarshalAs(UnmanagedType.LPWStr)] string username,
int level,
ref USER_INFO_1003 buf,
int error);

public struct USER_INFO_1003
{
public string usri1003_password;
}

I currently use strings to pass passwords into USER_INFO_1003 passwords,
and call NetSetInfo to set the password for an account somewhere, e.g:

string newpassword="SomePassword";

USER_INFO_1003 UserInfo1003 = new USER_INFO_1003();
UserInfo1003.usri1003_password = newpassword;


Now I store passwords in SecureStrings. How set passwords in
NetUserSetInfo calls without converting them to a string?



thanks, B
 
B

Brian Stoop

Thanks again for yoir help.

Brian

Stanimir Stoyanov (C# MVP) said:
Hi Brian,

The DirectoryEntry SetPassword method [1] appears to expect the password
as a BSTR, which is different than the pPassword pointer we already have
(an LPWSTR). In this case, you will have to reuse the original code with a
couple of changes when calling Marshal's methods: SecureStringToBSTR and
ZeroFreeBSTR.

Regarding the NetUserChangePassword casting issue, remove the MarshalAs
attributes from the two IntPtr parameters. This attribute is not necessary
(actually should not be there) for this data type.

It is important that the expected data types match the ones you pass to
the native API. MSDN has most, if not all, of these covered.

[1] http://msdn.microsoft.com/en-us/library/aa746344(VS.85).aspx

HTH,
--
Stanimir Stoyanov
Visual C# MVP
http://stoyanoff.info

Brian Stoop said:
Hi Stanimir,

Your suggestion:- IntPtr pPassword =
Marshal.SecureStringToGlobalAllocUnicode(password)
worked with NetUserSetInfo thanks.

But I tried using this pointer in the following circumstances.

1. de.Invoke("SetPassword", pPassword);

- The Invoke was successful, but the password did'nt work.


2. [DllImport("Netapi32.dll")]
extern public static unsafe int NetUserChangePassword(
[MarshalAs(UnmanagedType.LPWStr)] string domain,
[MarshalAs(UnmanagedType.LPWStr)] string username,
[MarshalAs(UnmanagedType.LPWStr)] IntPtr
oldpassword,
[MarshalAs(UnmanagedType.LPWStr)] IntPtr
newpassword);
NetUserSetPassword(domain, user, pPassword, pPassword);

- NetUserSetPassword failed, with a casting exception.


Do you know how SecureStrings used with DirectoryEntry SetPassword
Invoke, and NetUserSetPassword ?


Thanks, B



Stanimir Stoyanov (C# MVP) said:
Hi Brian,

You can use the Marshal.SecureStringToGlobalAllocUnicode [1] method to
allocate a Unicode representation of your SecureString. To avoid any
further processing of the password, I would recommend changing the
definition of USER_INFO_1003: change the string field to an IntPtr (a
pointer to a block of memory).

After you have finished using the password, you have to release the
block of memory by calling Marshal.ZeroFreeGlobalAllocUnicode [2].

SecureString password; // Initialize the password SecureString object

IntPtr pPassword = Marshal.SecureStringToGlobalAllocUnicode(password);

if (pPassword != IntPtr.Zero)
{
// Perform this check if reading memory at pPassword because if
the original password value is null, SecureStringToGlobalAllocUnicode
will return 0, resulting in an AccessViolationException.

// Sanity test
string passwordTest = Marshal.PtrToStringUni(pPassword);

// ...

Marshal.ZeroFreeGlobalAllocUnicode(pPassword)
}

[1]
http://msdn.microsoft.com/en-us/lib...marshal.securestringtoglobalallocunicode.aspx
[2]
http://msdn.microsoft.com/en-us/lib...vices.marshal.zerofreeglobalallocunicode.aspx

Regards,
Stanimir Stoyanov
Visual C# MVP
http://stoyanoff.info

Hi,

[DllImport("Netapi32.dll")]
extern public static int NetUserSetInfo(
[MarshalAs(UnmanagedType.LPWStr)] string servername,
[MarshalAs(UnmanagedType.LPWStr)] string username,
int level,
ref USER_INFO_1003 buf,
int error);

public struct USER_INFO_1003
{
public string usri1003_password;
}

I currently use strings to pass passwords into USER_INFO_1003
passwords, and call NetSetInfo to set the password for an account
somewhere, e.g:

string newpassword="SomePassword";

USER_INFO_1003 UserInfo1003 = new USER_INFO_1003();
UserInfo1003.usri1003_password = newpassword;


Now I store passwords in SecureStrings. How set passwords in
NetUserSetInfo calls without converting them to a string?



thanks, B
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top