|
I have faced the issue what Jecho mentioned. When this code is called from a WIX custom action, LsaAddAccountRights returns some random number. To solve it, the return type was changed to UInt32.
|
|
|
|
|
Corrina,
Great article, it has helped me out a lot, now if I could just resolve my current error, it would help even more!
My journey started with http://weblogs.asp.net/avnerk/archive/2007/05/08/setting-windows-service-account-c-and-wmi.aspx and I later ran across this follow-up posting http://weblogs.asp.net/avnerk/archive/2007/05/10/granting-user-rights-in-c.aspx which led me to http://www.hightechtalks.com/csharp/lsa-functions-276626.html.
I did some more searching and ran across http://blog.deploymentengineering.com/2008/09/different-year-same-problem.html which pointed me to your article. I then started cleaning up the example that was available and have ran into my current problem "1734 (The array bounds are invalid.)" when calling LsaAddAccountRights() to add "Log On As A Service" right to a user account.
During my various searches, I found the following link which lists available logon user rights http://support.microsoft.com/?id=279664 and http://support.microsoft.com/default.aspx?scid=kb;en-us;132958 provides additional information abour managing user privileges programmatically.
I have followed the following websites with no luck...all appear to be doing essentially the same thing that I am and implementing the differences yields the same result.
http://social.msdn.microsoft.com/forums/en-US/vbgeneral/thread/2d7d8115-a2ea-4d02-927b-667b20c047db/
http://social.msdn.microsoft.com/Forums/en-US/clr/thread/fd055d60-e030-4edc-b7a9-1962d6f7339e
http://www.pinvoke.net/default.aspx/advapi32/LsaAddAccountRights.html
http://pinvoke.net/default.aspx/advapi32/LsaOpenPolicy.html
Please help!
Here is the cleaned up code:
if (LSAUtility.SetRight(accountName, "SeServiceLogonRight", out errorMessage) == 0)
{
System.Windows.Forms.MessageBox.Show("The account " + accountName + " has been granted the Log On As A Service right.", "Information", MessageBoxButtons.OK, MessageBoxIcon.Information);
} // end if
else
{
System.Windows.Forms.MessageBox.Show("The Log On As A Service right was not added due to the following error: " + errorMessage, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
} // end else
----------------------------------------------
using System;
using System.Runtime.InteropServices; // DllImport
using System.Text;
namespace MyUtils
{
/// <summary>
/// The Local Security Authority (LSA) Utility
/// </summary>
public class LSAUtility
{
#region Import the LSA functions
[DllImport("advapi32.dll", PreserveSig = true)]
private static extern Int32 LsaOpenPolicy(ref LSA_UNICODE_STRING SystemName, ref LSA_OBJECT_ATTRIBUTES ObjectAttributes, Int32 DesiredAccess, out IntPtr PolicyHandle);
[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true, PreserveSig = true)]
private static extern bool LookupAccountName(string lpSystemName, string lpAccountName, IntPtr psid, ref int cbsid, StringBuilder domainName, ref int cbdomainLength, ref int use);
[DllImport("advapi32.dll", SetLastError = true, PreserveSig = true)]
private static extern Int32 LsaAddAccountRights(IntPtr PolicyHandle, IntPtr AccountSid, LSA_UNICODE_STRING UserRights, int CountOfRights);
[DllImport("advapi32.dll")]
private static extern bool IsValidSid(IntPtr pSid);
[DllImport("advapi32")]
public static extern void FreeSid(IntPtr pSid);
[DllImport("advapi32.dll")]
private static extern Int32 LsaClose(IntPtr ObjectHandle);
[DllImport("advapi32.dll")]
private static extern Int32 LsaNtStatusToWinError(Int32 status);
[DllImport("kernel32.dll")]
private static extern int GetLastError();
#endregion Import the LSA functions
#region Structures
#region LSA_OBJECT_ATTRIBUTES
[StructLayout(LayoutKind.Sequential)]
private struct LSA_OBJECT_ATTRIBUTES
{
public IntPtr RootDirectory;
public IntPtr SecurityDescriptor;
public IntPtr SecurityQualityOfService;
public LSA_UNICODE_STRING ObjectName;
public UInt32 Attributes;
public UInt32 Length;
} // LSA_OBJECT_ATTRIBUTES
#endregion LSA_OBJECT_ATTRIBUTES
#region LSA_UNICODE_STRING
[StructLayout(LayoutKind.Sequential)]
private struct LSA_UNICODE_STRING
{
public IntPtr Buffer;
public UInt16 Length;
public UInt16 MaximumLength;
} // LSA_UNICODE_STRING
#endregion LSA_UNICODE_STRING
#endregion Structures
#region Enumeration
#region LSA_AccessPolicy
private enum LSA_AccessPolicy : long
{
POLICY_AUDIT_LOG_ADMIN = 0x00000200L,
POLICY_CREATE_ACCOUNT = 0x00000010L,
POLICY_CREATE_PRIVILEGE = 0x00000040L,
POLICY_CREATE_SECRET = 0x00000020L,
POLICY_GET_PRIVATE_INFORMATION = 0x00000004L,
POLICY_LOOKUP_NAMES = 0x00000800L,
POLICY_NOTIFICATION = 0x00001000L,
POLICY_SERVER_ADMIN = 0x00000400L,
POLICY_SET_AUDIT_REQUIREMENTS = 0x00000100L,
POLICY_SET_DEFAULT_QUOTA_LIMITS = 0x00000080L,
POLICY_TRUST_ADMIN = 0x00000008L,
POLICY_VIEW_AUDIT_INFORMATION = 0x00000002L,
POLICY_VIEW_LOCAL_INFORMATION = 0x00000001L
} // LSA_AccessPolicy
#endregion LSA_AccessPolicy
#endregion Enumeration
#region Methods
/// <summary>Adds a privilege to an account</summary>
/// <param name="accountName">Name of an account - "domain\account" or only "account"</param>
/// <param name="privilegeName">Name of the privilege</param>
/// <returns>The windows error code returned by LsaAddAccountRights</returns>
public static Int32 SetRight(string accountName, string privilegeName, out string errorMessage)
{
int accountType = 0; // account-type variable for lookup
int nameSize = 0; // size of the domain name
int sidSize = 0; // size of the SID
IntPtr sid = IntPtr.Zero; // pointer for the SID
Int32 winErrorCode = 0; // contains the last error
StringBuilder domainName = null; // StringBuilder for the domain name
errorMessage = "";
// get required buffer size
LookupAccountName(null, accountName, sid, ref sidSize, domainName, ref nameSize, ref accountType);
// allocate buffers
domainName = new StringBuilder(nameSize);
sid = Marshal.AllocHGlobal(sidSize);
// lookup the SID for the account
if (!LookupAccountName(null, accountName, sid, ref sidSize, domainName, ref nameSize, ref accountType))
{
winErrorCode = GetLastError();
errorMessage = "An error occurred while Looking up the Account Name, Error Code: " + winErrorCode;
} // end if
else
{
// combine all policies
int access = (int) (LSA_AccessPolicy.POLICY_AUDIT_LOG_ADMIN |
LSA_AccessPolicy.POLICY_CREATE_ACCOUNT |
LSA_AccessPolicy.POLICY_CREATE_PRIVILEGE |
LSA_AccessPolicy.POLICY_CREATE_SECRET |
LSA_AccessPolicy.POLICY_GET_PRIVATE_INFORMATION |
LSA_AccessPolicy.POLICY_LOOKUP_NAMES |
LSA_AccessPolicy.POLICY_NOTIFICATION |
LSA_AccessPolicy.POLICY_SERVER_ADMIN |
LSA_AccessPolicy.POLICY_SET_AUDIT_REQUIREMENTS |
LSA_AccessPolicy.POLICY_SET_DEFAULT_QUOTA_LIMITS |
LSA_AccessPolicy.POLICY_TRUST_ADMIN |
LSA_AccessPolicy.POLICY_VIEW_AUDIT_INFORMATION |
LSA_AccessPolicy.POLICY_VIEW_LOCAL_INFORMATION);
// Operation result
Int32 result;
// initialize a pointer for the policy handle
IntPtr policyHandle = IntPtr.Zero;
// initialize an empty unicode-string
LSA_UNICODE_STRING systemName = new LSA_UNICODE_STRING();
// this variable and it's attributes are not used, but LsaOpenPolicy wants them to exists
LSA_OBJECT_ATTRIBUTES ObjectAttributes = new LSA_OBJECT_ATTRIBUTES();
// get a policy handle
result = LsaOpenPolicy(ref systemName, ref ObjectAttributes, access, out policyHandle);
winErrorCode = LsaNtStatusToWinError(result);
if (winErrorCode != 0)
{
errorMessage = "An error occurred while opening the policy, Error Code: " + winErrorCode;
} // end if
else // Now that we have the SID and the policy, we can add the right to the account.
{
// initialize a unicode-string for the privilege name
LSA_UNICODE_STRING userRight = new LSA_UNICODE_STRING();
userRight.Buffer = Marshal.StringToHGlobalUni(privilegeName);
userRight.Length = (UInt16) (privilegeName.Length * UnicodeEncoding.CharSize);
userRight.MaximumLength = (UInt16) ((privilegeName.Length + 1) * UnicodeEncoding.CharSize);
// add the right to the account
result = LsaAddAccountRights(policyHandle, sid, userRight, 1);
winErrorCode = LsaNtStatusToWinError(result);
if (winErrorCode != 0)
{
errorMessage = "An error occurred while adding the account right, Error Code: " + winErrorCode;
} // end if
Marshal.FreeHGlobal(userRight.Buffer);
LsaClose(policyHandle);
} // end else
FreeSid(sid);
} // end else
return winErrorCode;
} // SetRight()
#endregion Methods
} // class LSAUtility
} // namespace MyUtils
|
|
|
|
|
Ok, ok, ok.....be prepared for the stupidest fix ever.....in the LSA_UNICODE_STRING structure, public IntPtr Buffer has to be declared after Length and MaximumLength! Don't ask me why, because I don't know and I really don't care...actually I do care, but just don't know why.
In the posted code above I had changed userRight from an array to a variable; however, apparently the websites that I visited which stated that it did not have to be an array are wrong as I did have to change back to an array in order to get it to work.
The updated code is listed below so that others hopefully don't have to waste as much time as I have searching for a simple solution to the problem at hand.
using System;
using System.Runtime.InteropServices; // DllImport
using System.Text;
namespace myUtils
{
/// <summary>
/// The Local Security Authority (LSA) Utility
/// </summary>
public class LSAUtility
{
#region Import the LSA functions
[DllImport("advapi32.dll", PreserveSig = true)]
private static extern Int32 LsaOpenPolicy(ref LSA_UNICODE_STRING SystemName, ref LSA_OBJECT_ATTRIBUTES ObjectAttributes, Int32 DesiredAccess, out IntPtr PolicyHandle);
[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true, PreserveSig = true)]
private static extern bool LookupAccountName(string lpSystemName, string lpAccountName, IntPtr psid, ref int cbsid, StringBuilder domainName, ref int cbdomainLength, ref int use);
[DllImport("advapi32.dll", SetLastError = true, PreserveSig = true)]
private static extern Int32 LsaAddAccountRights(IntPtr PolicyHandle, IntPtr AccountSid, LSA_UNICODE_STRING[] UserRights, int CountOfRights);
[DllImport("advapi32.dll")]
private static extern bool IsValidSid(IntPtr pSid);
[DllImport("advapi32")]
public static extern void FreeSid(IntPtr pSid);
[DllImport("advapi32.dll")]
private static extern Int32 LsaClose(IntPtr ObjectHandle);
[DllImport("advapi32.dll")]
private static extern Int32 LsaNtStatusToWinError(Int32 status);
[DllImport("kernel32.dll")]
private static extern int GetLastError();
#endregion Import the LSA functions
#region Structures
#region LSA_OBJECT_ATTRIBUTES
[StructLayout(LayoutKind.Sequential)]
private struct LSA_OBJECT_ATTRIBUTES
{
public int Attributes;
public int Length;
public IntPtr RootDirectory;
public IntPtr SecurityDescriptor;
public IntPtr SecurityQualityOfService;
public LSA_UNICODE_STRING ObjectName;
} // LSA_OBJECT_ATTRIBUTES
#endregion LSA_OBJECT_ATTRIBUTES
#region LSA_UNICODE_STRING
[StructLayout(LayoutKind.Sequential)]
private struct LSA_UNICODE_STRING
{
public UInt16 Length;
public UInt16 MaximumLength;
// NOTE: Buffer has to be declared after Length and MaximumLength;
// otherwise, you will get winErrorCode: 1734 (The array bounds are invalid.)
// and waste lots of time trying to track down what causes the error!
public IntPtr Buffer;
} // LSA_UNICODE_STRING
#endregion LSA_UNICODE_STRING
#endregion Structures
#region Enumeration
#region LSA_AccessPolicy
private enum LSA_AccessPolicy : long
{
POLICY_VIEW_LOCAL_INFORMATION = 0x00000001L,
POLICY_VIEW_AUDIT_INFORMATION = 0x00000002L,
POLICY_GET_PRIVATE_INFORMATION = 0x00000004L,
POLICY_TRUST_ADMIN = 0x00000008L,
POLICY_CREATE_ACCOUNT = 0x00000010L,
POLICY_CREATE_SECRET = 0x00000020L,
POLICY_CREATE_PRIVILEGE = 0x00000040L,
POLICY_SET_DEFAULT_QUOTA_LIMITS = 0x00000080L,
POLICY_SET_AUDIT_REQUIREMENTS = 0x00000100L,
POLICY_AUDIT_LOG_ADMIN = 0x00000200L,
POLICY_SERVER_ADMIN = 0x00000400L,
POLICY_LOOKUP_NAMES = 0x00000800L,
POLICY_NOTIFICATION = 0x00001000L
} // LSA_AccessPolicy
#endregion LSA_AccessPolicy
#endregion Enumeration
#region Methods
/// <summary>Adds a privilege to an account</summary>
/// <param name="accountName">Name of an account - "domain\account" or only "account"</param>
/// <param name="privilegeName">Name of the privilege</param>
/// <returns>The windows error code returned by LsaAddAccountRights</returns>
public static Int32 SetRight(string accountName, string privilegeName, out string errorMessage)
{
int accountType = 0; // account-type variable for lookup
int nameSize = 0; // size of the domain name
int sidSize = 0; // size of the SID
IntPtr sid = IntPtr.Zero; // pointer for the SID
Int32 winErrorCode = 0; // contains the last error
StringBuilder domainName = null; // StringBuilder for the domain name
errorMessage = "";
// get required buffer size
LookupAccountName(null, accountName, sid, ref sidSize, domainName, ref nameSize, ref accountType);
// allocate buffers
domainName = new StringBuilder(nameSize);
sid = Marshal.AllocHGlobal(sidSize);
// lookup the SID for the account
if (!LookupAccountName(null, accountName, sid, ref sidSize, domainName, ref nameSize, ref accountType))
{
winErrorCode = GetLastError();
errorMessage = "An error occurred while Looking up the Account Name, Error Code: " + winErrorCode;
} // end if
else
{
// combine all policies
int access = (int) (LSA_AccessPolicy.POLICY_AUDIT_LOG_ADMIN |
LSA_AccessPolicy.POLICY_CREATE_ACCOUNT |
LSA_AccessPolicy.POLICY_CREATE_PRIVILEGE |
LSA_AccessPolicy.POLICY_CREATE_SECRET |
LSA_AccessPolicy.POLICY_GET_PRIVATE_INFORMATION |
LSA_AccessPolicy.POLICY_LOOKUP_NAMES |
LSA_AccessPolicy.POLICY_NOTIFICATION |
LSA_AccessPolicy.POLICY_SERVER_ADMIN |
LSA_AccessPolicy.POLICY_SET_AUDIT_REQUIREMENTS |
LSA_AccessPolicy.POLICY_SET_DEFAULT_QUOTA_LIMITS |
LSA_AccessPolicy.POLICY_TRUST_ADMIN |
LSA_AccessPolicy.POLICY_VIEW_AUDIT_INFORMATION |
LSA_AccessPolicy.POLICY_VIEW_LOCAL_INFORMATION);
Int32 result; // Operation result
IntPtr policyHandle = IntPtr.Zero; // initialize a pointer for the policy handle
LSA_UNICODE_STRING systemName = new LSA_UNICODE_STRING(); // initialize an empty unicode-string
// this variable and it's attributes are not used, but LsaOpenPolicy wants them to exists
LSA_OBJECT_ATTRIBUTES ObjectAttributes = new LSA_OBJECT_ATTRIBUTES();
// get a policy handle
result = LsaOpenPolicy(ref systemName, ref ObjectAttributes, access, out policyHandle);
winErrorCode = LsaNtStatusToWinError(result);
if (winErrorCode != 0)
{
errorMessage = "An error occurred while opening the policy, Error Code: " + winErrorCode;
} // end if
else // Now that we have the SID and the policy, we can add the right to the account.
{
// initialize a unicode-string for the privilege name
LSA_UNICODE_STRING[] userRights = new LSA_UNICODE_STRING[1];
userRights[0] = new LSA_UNICODE_STRING();
userRights[0].Buffer = Marshal.StringToHGlobalUni(privilegeName);
userRights[0].Length = (UInt16) (privilegeName.Length * UnicodeEncoding.CharSize);
userRights[0].MaximumLength = (UInt16) ((privilegeName.Length + 1) * UnicodeEncoding.CharSize);
// add the right to the account
result = LsaAddAccountRights(policyHandle, sid, userRights, 1);
winErrorCode = LsaNtStatusToWinError(result);
if (winErrorCode != 0)
{
errorMessage = "An error occurred while adding the account right, Error Code: " + winErrorCode;
} // end if
Marshal.FreeHGlobal(userRights[0].Buffer);
LsaClose(policyHandle);
} // end else
FreeSid(sid);
} // end else
return winErrorCode;
} // SetRight()
#endregion Methods
} // class LSAUtility
} // namespace myUtils
|
|
|
|
|
Hi,
that's because of the unmanaged structure layout. You have to declare unmanaged types exactly as the Windows SDK headers do. They will be marshalled byte-by-byte.
This statement is false.
|
|
|
|
|
If that is the case, why isn't there a problem with the LSA_OBJECT_ATTRIBUTES structure? I changed Attributes to an int and put it on top for alphabetical purposes and then pulled the ObjectName variable to the bottom so that all of the IntPtr variables would be together?
|
|
|
|
|
I cannot see where you fill the LSA_OBJECT_ATTRIBUTES structure yourself. You only pass it by ref to a function that expects a certain the unmanaged layout (and behaves as if it were so). All variables in the structure are initialized to the same value '0', so the external function doesn't notice that something is wrong. And you never read the structure's values, so you don't notice that there's something wrong.
Yes, there would be a bad problem, if you actually used the structure as you declared it. It didn't yet happen, because you only pass on a row of zeros.
This statement is false.
|
|
|
|
|
Good deal...you just confirmed what a fellow employee was explaining to me. He was saying that it probably isn't causing a problem now but somewhere down the road it might start causing random errors b/c when implementing structures, etc. from API's, the code is expected to exist in a specific order and if things have been moved / types have been changed various problems can arise.
That got me to thinking that probably the reason why I am not currently getting an error message is due to the fact that I don't really ever use that structure. I am going to change the LSA_OBJECT_ATTRIBUTES structure back to what you originally had in order to prevent any future problems that might occur. I guess this is a case where being a bit anal / OCD can cause unforseen problems! :-P
[StructLayout(LayoutKind.Sequential)]
private struct LSA_OBJECT_ATTRIBUTES
{
public int Length;
public IntPtr RootDirectory;
public LSA_UNICODE_STRING ObjectName;
public UInt32 Attributes;
public IntPtr SecurityDescriptor;
public IntPtr SecurityQualityOfService;
} // LSA_OBJECT_ATTRIBUTES
Thanks,
Ryan
|
|
|
|
|
Hii..
Try the exe run as administrator..
|
|
|
|
|
hello,
how to give to a programm the privilege of an user ?
I'am using remore server (ipcchannel).
1)the remote server is launch by windows service :
when user insert usb device (a key) the server cannot eject this device.
2)I launch the serveur myself directly( with user account )
when user insert usb device (a key) the server can eject this device.
how to give privilege to the server ?
An idea ?
thanks
Vincent
|
|
|
|
|
I'm programming with C#, program run under windows 2000
thanks again
Vincent
|
|
|
|
|
LsaNtStatusToWinError work incorect.
Need next change:
[DllImport("advapi32.dll")]
private static extern uint LsaNtStatusToWinError(uint status);
[DllImport("advapi32.dll", SetLastError=true, PreserveSig=true)]
private static extern uint LsaAddAccountRights(
IntPtr PolicyHandle,
IntPtr AccountSid,
LSA_UNICODE_STRING[] UserRights,
long CountOfRights);
Sorry, bad english.
|
|
|
|
|
Corinna,
Its nice to run across articles that remain relevant long after they were written ... good one!
I am attempting to update an existing VB6 application that automates a very involved installation of a server product. It creates user accounts, groups, files, file shares, DCOM components, and COM+ applications and proxies, etc.
It works just fine in work groups and in Win2k domains, but in a Windows 2003 domain the server only runs for a little while after installation.
I determined that it is because during the installation of the COM+ application, the account used as it's identity is implicitly set into the local security policy with the "Log on as batch job" privilege. But in the W2003 domain the overriding global policy proceeds to write over that change to local policy. Seems to do it periodically even without the system restarting.
Anyway, I wanted to know if I could use these calls to give the server's identity account the "Log on a batch job" privilege in the domains Global Policy for Local Security Settings? And it so, what would the calls look like parameter wise? I shouldn't have any trouble porting sample code to VB6 even though I'm a C/C++/C# guy.
Ciao,
Scott
|
|
|
|
|
Nice Article!!
But I've a bit different query & after reading this article i guess you can very well guide me!
Problem: I want to impersoante a user & the only information that i have for the purpose is his SID. How can I do that?
Description: I know that i can easily impersonate a user using LogonUser() & then fire ImpersonateLoggedOnUser() on the access token that i get from LogonUser() . But I don't have the user's User Name & Password (which LogonUser() takes as input. I only have his SID.
>>> Please assume i've tried most of the impersonation approaches.
Please HELP!!
Thanks in advance.
TJ
|
|
|
|
|
TJ,
You can't do it with just a SID otherwise every virus out there would impersonate Administrator using its well known SID!
If you also had the password, you could lookup the account name matching the SID to do the logon.
The only other way I can think of off hand is complicated...
* Must be using Kerberos for authentication
* Your process's identity (logged on user?) has to have delegation privilege
* The user you want to impersonate has to be logged on
* A process they are running must pass a kerberos authentication token to your process that includes the delegation information
* Your process must receive the kerberos info set it into the thread
* The thread must then enable impersonation
Good luck if you go this route because as I said above, it is complicated ... I attempted it in the past in C# over remoting and had it working "most of the time" ... sometimes it just failed and I was never able to determine why.
The question is: "When is Microsoft going to add optional security to the .NET remoting framework classes to automate authentication and impersonation?"
Ciao,
Scott S
|
|
|
|
|
I reviewed the thread below regarding the LsaOpenPolicyError...I received the same "error":
I added a bit of code to check the error code returned (4294967296) from OpenPolicy:
if(winErrorCode != 0){<br />
Console.WriteLine("OpenPolicy failed: "+ winErrorCode);<br />
System.ComponentModel.Win32Exception ex = new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error());<br />
Console.WriteLine("1 " + ex.Message + " (" + Marshal.GetLastWin32Error().ToString() + ") ");<br />
System.ComponentModel.Win32Exception ex2 = new System.ComponentModel.Win32Exception((int)winErrorCode);<br />
Console.WriteLine("2 " + ex2.Message + " (" + winErrorCode.ToString() + ") ");<br />
}<br />
else<br />
{<br />
...<br />
The spit-out from win2k is:
1 Overlapped I/O operation is in progress (127)
2 The operation completed successfully (4294967296)
The code works on an XP machine, but I receive the "error" on Win2k machines. I found the "completed successfully" interesting, so I allowed the next block (LsaAddAccount) to execute, and received the same "error".
I checked the security policy, and was happy to see that it worked!
So, this "error" (4294967296) seems to actually be a success code. So I modified the check's to look like this:
if(winErrorCode != 0 && winErrorCode != 4294967296){<br />
I've also found that in
winErrorCode = LsaNtStatusToWinError(resultPolicy);
on XP, winErrorCode will be 0. On Win2k, winErrorCode will be 4294967296. Don't know exactly why...
Just thought you'd all like to know.
shoe
-- modified at 18:22 Monday 20th March, 2006
|
|
|
|
|
Hi,
See this post[^] for a solution to your problem.
Regards,
Jecho
|
|
|
|
|
Hallo Corinna,
Ihr Code hat mich auf den richtigen Weg gebracht für das, was ich tun will.
Das einzige, was mir abgegangen ist, "RemoveRight" (Recht löschen) und "HasRight" (Abfrage, ob ein Account ein bestimmtes Recht besitzt) sowie eine öffentliche Enumeration von Rechten.
Ich habe diese Dinge in meiner Version von "LsaUtilities.cs" ergänzt und würde Ihnen das Resultat gerne zum Test zur Verfügung stellen. Derzeit habe ich nur die Logon-Features überprüft.
Ich hoffe, Sie können aus dieser Nachricht meine Email-Adresse ermitteln, sonst senden Sie mir bitte bei Interesse einfach eine SMS mit Ihrer Email an 004369912197955.
Liebe Grüße aus Österreich
Peter Pranter
|
|
|
|
|
Hi,
I have banging my head against the wall for about 2 weeks trying to figure this out.
My goal is to write a file to a SAMBA share in a C# console app. I have an account set up in SAMBA and also set up in windows with identical username and password. I have read that this is the way to do it.
I have found that i am impersonating the user correctly but when i go to write the file an error is raised telling me that it is a bad username and/or password. According to the SAMBA logs the impersonated users credentials are not being sent, instead MY login credentials are being sent. Do you have any ideas? It would be greatly appreciated.
Cheers,
Lucas.
Lucas
|
|
|
|
|
Hi,
I've built these LSA functions into a VB command line app so that I can call it from within an InstallShield setup project. The primary purpose was so that I can call SetRight with SeServiceLogonRight to make sure the user has the "Logon as a Service" right, before I try to set a username/password on the service I'm installing.
On WinXP this has worked like a charm, but when I tested it on Win2k I got an error from LsaOpenPolicy. From my application the error is reported as "OpenPolicy failed: 4294967296". At first I thought it must have been an error that crept in when I converted the code to VB, but on further investigation it appears this isn't a valid error number at all. As far as I can tell this is just the max value for an integer. So I tried the original test app from this article and it returns the error "Privilege not added: +winErrorCode".
(Note: In both of these cases I was trying to give the privilege to the Administrator of the local PC, but I get the same error no matter what user I use)
As far as I can tell this is still necessary on Win2k because after the error occurs my service is left with LocalSystem as the logon user.
Is there some good reason why this isn't working on Win2k or am I missing something obvious?
|
|
|
|
|
i have this exact problem, did you ever resolve this issue?
|
|
|
|
|
I don't think I ever did get that working. In the end I found a pre-compiled version of ssplogon.exe like what is described here.
http://support.microsoft.com/default.aspx?scid=kb;en-us;Q180548
The one I have takes a command line like...
ssplogon.exe <domain> <user> <password>
...and returns a value in the ERRORLEVEL indicating if the logon wass sucessful or not.
If this will suit you purpose, let me know and I can send u a copy of the exe.
|
|
|
|
|
i've had a read through that article.
could you post some sample c# code as i am not quite sure what to do.
basically the bit i am interested in is more enabling privileges for different accounts (specifically log on as service)
cheers
|
|
|
|
|
Sorry bout that, I went off on completely the wrong track there. The code for the class I ended up using is below. I converted Corinna's class to VB.NET (since that's my language of choice) and if I recall correctly the problem went away somewhere during the conversion. If there was something specific I fixed it's too long ago for me to recall what it was now. Hopefully if you compare the 2 you might be able to spot what's different, or maybe you could just compile this into a dll that you can use from your C# projects.
To grant the Logon As A Service right you'd call the SetRight function like this...
Dim lsaResult As Long = LsaFunctions.SetRight("domain\account", "SeServiceLogonRight")
...and a 0 result means it was sucessful.
Here's my VB.NET class, which is basically equivilent to Corinna's LsaUtility class.
(BTW... sorry for the long post everyone, but I can't see any other way to attach this.)
<br />
Imports System.Text<br />
Imports System.Runtime.InteropServices<br />
<br />
Public Class LsaFunctions<br />
<br />
' Import the LSA functions<br />
<DllImport("advapi32.dll", PreserveSig:=True)> _<br />
Private Shared Function LsaOpenPolicy(ByRef SystemName As LSA_UNICODE_STRING, ByRef ObjectAttributes As LSA_OBJECT_ATTRIBUTES, ByVal DesiredAccess As Int32, ByRef PolicyHandle As IntPtr) As UInt32<br />
End Function<br />
<br />
<DllImport("advapi32.dll", SetLastError:=True, PreserveSig:=True)> _<br />
Private Shared Function LsaAddAccountRights(ByVal PolicyHandle As IntPtr, ByVal AccountSid As IntPtr, ByVal UserRights As LSA_UNICODE_STRING(), ByVal CountOfRights As Long) As UInt32<br />
End Function<br />
<br />
<DllImport("advapi32")> _<br />
Public Shared Sub FreeSid(ByVal pSid As IntPtr)<br />
End Sub<br />
<br />
<DllImport("advapi32.dll", CharSet:=CharSet.Auto, SetLastError:=True, PreserveSig:=True)> _<br />
Private Shared Function LookupAccountName(ByVal lpSystemName As String, ByVal lpAccountName As String, ByVal psid As IntPtr, ByRef cbsid As Int32, ByVal domainName As StringBuilder, ByRef cbdomainLength As Int32, ByRef use As Int32) As Boolean<br />
End Function<br />
<br />
<DllImport("advapi32.dll")> _<br />
Private Shared Function IsValidSid(ByVal pSid As IntPtr) As Boolean<br />
End Function<br />
<br />
<DllImport("advapi32.dll")> _<br />
Private Shared Function LsaClose(ByVal ObjectHandle As IntPtr) As Long<br />
End Function<br />
<br />
<DllImport("kernel32.dll")> _<br />
Private Shared Function GetLastError() As Long<br />
End Function<br />
<br />
' Define the structures<br />
<StructLayout(LayoutKind.Sequential)> _<br />
Private Structure LSA_UNICODE_STRING<br />
Public Length As UInt16<br />
Public MaximumLength As UInt16<br />
Public Buffer As IntPtr<br />
End Structure<br />
<br />
<StructLayout(LayoutKind.Sequential)> _<br />
Private Structure LSA_OBJECT_ATTRIBUTES<br />
Public Length As Int32<br />
Public RootDirectory As IntPtr<br />
Public ObjectName As LSA_UNICODE_STRING<br />
Public Attributes As UInt32<br />
Public SecurityDescriptor As IntPtr<br />
Public SecurityQualityOfService As IntPtr<br />
End Structure<br />
<br />
' Enum all policies<br />
Private Enum LSA_AccessPolicy As Long<br />
POLICY_VIEW_LOCAL_INFORMATION = &H1L<br />
POLICY_VIEW_AUDIT_INFORMATION = &H2L<br />
POLICY_GET_PRIVATE_INFORMATION = &H4L<br />
POLICY_TRUST_ADMIN = &H8L<br />
POLICY_CREATE_ACCOUNT = &H10L<br />
POLICY_CREATE_SECRET = &H20L<br />
POLICY_CREATE_PRIVILEGE = &H40L<br />
POLICY_SET_DEFAULT_QUOTA_LIMITS = &H80L<br />
POLICY_SET_AUDIT_REQUIREMENTS = &H100L<br />
POLICY_AUDIT_LOG_ADMIN = &H200L<br />
POLICY_SERVER_ADMIN = &H400L<br />
POLICY_LOOKUP_NAMES = &H800L<br />
POLICY_NOTIFICATION = &H1000L<br />
End Enum<br />
<br />
' <summary>Adds a privilege to an account</summary><br />
' <param name="accountName">Name of an account - "domain\account" or only "account"</param><br />
' <param name="privilegeName">Name ofthe privilege</param><br />
' <returns>The windows error code returned by LsaAddAccountRights</returns><br />
Public Shared Function SetRight(ByVal accountName As String, ByVal privilegeName As String) As Long<br />
Dim winErrorCode As Long = 0 ' contains the last error<br />
<br />
' pointer an size for the SID<br />
Dim sid As IntPtr = IntPtr.Zero<br />
Dim sidSize As Int32 = 0<br />
<br />
' StringBuilder and size for the domain name<br />
Dim domainName As StringBuilder = New StringBuilder<br />
Dim nameSize As Int32 = 0<br />
<br />
' account-type variable for lookup<br />
Dim accountType As Int32 = 0<br />
<br />
' get required buffer size<br />
LookupAccountName(String.Empty, accountName, sid, sidSize, domainName, nameSize, accountType)<br />
<br />
' allocate buffers<br />
domainName = New StringBuilder(nameSize)<br />
sid = Marshal.AllocHGlobal(sidSize)<br />
<br />
' lookup the SID for the account<br />
Dim result As Boolean = LookupAccountName(String.Empty, accountName, sid, sidSize, domainName, nameSize, accountType)<br />
<br />
' say what you're doing<br />
'Dim msg As String<br />
'msg &= "LookupAccountName result = " & result & vbCrLf<br />
'msg &= "IsValidSid: " & IsValidSid(sid) & vbCrLf<br />
'msg &= "LookupAccountName domainName: " & domainName.ToString()<br />
'MessageBox.Show(msg)<br />
<br />
If Not result Then<br />
winErrorCode = GetLastError()<br />
MessageBox.Show("LookupAccountName failed: " & winErrorCode, "ServiceUtils")<br />
Else<br />
' initialize an empty unicode-string<br />
Dim systemName As LSA_UNICODE_STRING = New LSA_UNICODE_STRING<br />
<br />
' Combine policies required to grant/deny privileges<br />
Dim access As Int32 = CInt( _<br />
LSA_AccessPolicy.POLICY_CREATE_ACCOUNT Or _<br />
LSA_AccessPolicy.POLICY_LOOKUP_NAMES)<br />
<br />
' initialize a pointer for the policy handle<br />
Dim policyHandle As IntPtr = IntPtr.Zero<br />
<br />
' these attributes are not used, but LsaOpenPolicy wants them to exists<br />
Dim ObjectAttributes As LSA_OBJECT_ATTRIBUTES = New LSA_OBJECT_ATTRIBUTES<br />
ObjectAttributes.Length = 0<br />
ObjectAttributes.RootDirectory = IntPtr.Zero<br />
ObjectAttributes.Attributes = UInt32.Parse("0")<br />
ObjectAttributes.SecurityDescriptor = IntPtr.Zero<br />
ObjectAttributes.SecurityQualityOfService = IntPtr.Zero<br />
<br />
' get a policy handle<br />
Dim resultPolicy As UInt32 = LsaOpenPolicy(systemName, ObjectAttributes, access, policyHandle)<br />
<br />
If Not resultPolicy.ToString = "0" Then<br />
MessageBox.Show("OpenPolicy failed: " & resultPolicy.ToString, "ServiceUtils")<br />
Else<br />
' Now that we have the SID an the policy,<br />
' we can add rights to the account.<br />
<br />
' initialize an unicode-string for the privilege name<br />
Dim userRights(1) As LSA_UNICODE_STRING<br />
userRights(0) = New LSA_UNICODE_STRING<br />
userRights(0).Buffer = Marshal.StringToHGlobalUni(privilegeName)<br />
userRights(0).Length = UInt16.Parse(privilegeName.Length * UnicodeEncoding.CharSize)<br />
userRights(0).MaximumLength = UInt16.Parse((privilegeName.Length + 1) * UnicodeEncoding.CharSize)<br />
<br />
' add the right to the account<br />
Dim resultRights As UInt32 = LsaAddAccountRights(policyHandle, sid, userRights, 1)<br />
If Not resultRights.ToString = "0" Then<br />
MessageBox.Show("LsaAddAccountRights failed: " & resultRights.ToString, "ServiceUtils")<br />
End If<br />
<br />
LsaClose(policyHandle)<br />
End If<br />
FreeSid(sid)<br />
End If<br />
<br />
Return winErrorCode<br />
End Function<br />
End Class<br />
|
|
|
|
|
fixed the errors:
private static extern long LsaAddAccountRights(
IntPtr PolicyHandle, IntPtr AccountSid,
LSA_UNICODE_STRING[] UserRights,
UInt32 CountOfRights );
private static extern long LsaNtStatusToWinError(UInt32 status);
|
|
|
|
|
I know this is an old thread, but I am just reading it now. I am interested in a compiled version of SSPLOGIN.EXE. I don't seem to be able to find it anywhere.
Thanks
Neo
Kermittt wrote: The one I have takes a command line like...
ssplogon.exe <domain> <user> <password>
...and returns a value in the ERRORLEVEL indicating if the logon wass sucessful or not.
|
|
|
|
|