Access Denied in method SetLocalTime -
07-03-2009
, 09:04 AM
I wrote an application for Windows Embedded with Windows Forms:
In the Application Start I must synchronize the date/time in offline mode so
I ask the date to the user in an input form and then I use the SetLocalTime
API (with the PInvoke) to update the system DateTime.
This call returns an error code 5 (Access Denied)
Since the current user is not a local administrator of the PC I first use
the AdjustTokenPrivileges call to give the proccess the SE_SYSTEMTIME_NAME
permission and then the Impersonation to have administrative rights.
Is there anyone who can help me?
This is the C# Code of my Impersonation class:
-------------------------------------------------------------
class Impersonation
{
// obtains user token
[DllImport("advapi32.dll", SetLastError = true)]
public static extern bool LogonUser(string pszUsername, string
pszDomain, string pszPassword, int dwLogonType, int dwLogonProvider, ref
IntPtr phToken);
// closes open handes returned by LogonUser
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
public extern static bool CloseHandle(IntPtr handle);
// creates duplicate token handle
[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError =
true)]
public extern static bool DuplicateToken(IntPtr ExistingTokenHandle,
int SECURITY_IMPERSONATION_LEVEL, ref IntPtr
DuplicateTokenHandle);
private IntPtr pExistingTokenHandle = new IntPtr(0);
private IntPtr pDuplicateTokenHandle = new IntPtr(0);
public Impersonation()
{
// initialize tokens
pExistingTokenHandle = new IntPtr(0);
pDuplicateTokenHandle = new IntPtr(0);
pExistingTokenHandle = IntPtr.Zero;
pDuplicateTokenHandle = IntPtr.Zero;
}
public WindowsImpersonationContext ImpersonateUser(string sUsername,
string sDomain, string sPassword)
{
if (sDomain == "")
sDomain = System.Environment.MachineName;
string sResult = null;
const int LOGON32_PROVIDER_DEFAULT = 0;
const int LOGON32_LOGON_INTERACTIVE = 2;
// get handle to token
bool bImpersonated = LogonUser(sUsername, sDomain, sPassword,
LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT,
ref pExistingTokenHandle);
// did impersonation fail?
if (false == bImpersonated)
{
int nErrorCode = Marshal.GetLastWin32Error();
throw new Win32Exception(nErrorCode);
}
// Get identity before impersonation
bool bRetVal = DuplicateToken(pExistingTokenHandle,
(int)SECURITY_IMPERSONATION_LEVEL.SecurityImperson ation,
ref pDuplicateTokenHandle);
// did DuplicateToken fail?
if (false == bRetVal)
{
int nErrorCode = Marshal.GetLastWin32Error();
// close existing handle
CloseHandle(pExistingTokenHandle);
// show the reason why DuplicateToken failed
MessageBox.Show(sResult, "Error", MessageBoxButtons.OK,
MessageBoxIcon.Error);
return null;
}
else
{
// create new identity using new primary token
WindowsIdentity newId = new
WindowsIdentity(pDuplicateTokenHandle);
WindowsImpersonationContext impersonatedUser =
newId.Impersonate();
return impersonatedUser;
}
}
public void CloseHandles()
{
if (pExistingTokenHandle != IntPtr.Zero)
CloseHandle(pExistingTokenHandle);
if (pDuplicateTokenHandle != IntPtr.Zero)
CloseHandle(pDuplicateTokenHandle);
}
}
// group type enum
public enum SECURITY_IMPERSONATION_LEVEL : int
{
SecurityAnonymous = 0,
SecurityIdentification = 1,
SecurityImpersonation = 2,
SecurityDelegation = 3
}
-------------------------------------------------------------
This is the code of my SystemDateTimeUtils class:
-------------------------------------------------------------
class SystemDateTimeUtils
{
#region pinvokes
[DllImport("kernel32.dll")]
private static extern bool SetLocalTime(ref SYSTEMTIME time);
[DllImport("kernel32.dll")]
private static extern bool SetSystemTime(ref SYSTEMTIME systime);
[DllImport("kernel32.dll")]
private static extern int GetLastError();
[DllImport("kernel32.dll")]
private static extern void GetLocalTime(out SYSTEMTIME time);
[DllImport("advapi32.dll", CharSet = CharSet.Auto)]
public static extern bool OpenProcessToken(int ProcessHandle,
int DesiredAccess, ref int TokenHandle);
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
public static extern int GetCurrentProcess();
[DllImport("advapi32.dll", CharSet = CharSet.Auto)]
public static extern bool LookupPrivilegeValue(string lpSystemName,
string lpName,
[MarshalAs(UnmanagedType.Struct)] ref LUID lpLuid);
[DllImport("advapi32.dll", CharSet = CharSet.Auto)]
public static extern bool AdjustTokenPrivileges(int TokenHandle, int
DisableAllPrivileges,
[MarshalAs(UnmanagedType.Struct)] ref TOKEN_PRIVILEGES NewState,
int BufferLength,
[MarshalAs(UnmanagedType.Struct)] ref TOKEN_PRIVILEGES
PreviousState, ref int ReturnLength);
#endregion
#region Constants
private const int ANYSIZE_ARRAY = 1;
private const string SE_SYSTEMTIME_NAME = "SeSystemtimePrivilege";
private const int SE_PRIVILEGE_ENABLED = 0x00000002;
private const int TOKEN_QUERY = 0x0008;
private const int TOKEN_ADJUST_PRIVILEGES = 0x0020;
#endregion
#region SetLocalTime
public static bool SetLocalTime(DateTime systemTime, out int
errorCode)
{
AdjustPrivileges();
SYSTEMTIME time = GetSystemTime(ref systemTime);
WindowsImpersonationContext newUser = null;
bool result = false;
Impersonation imp = new Impersonation();
try
{
newUser = imp.ImpersonateUser(<my_username>, ".",
<my_password>);
result = SetLocalTime(ref time);
if (result)
result = SetLocalTime(ref time);
if (!result)
errorCode = GetLastError();
else
errorCode = 0;
}
finally
{
imp.CloseHandles();
if (newUser != null)
newUser.Undo();
}
return result;
}
#endregion
#region GetSystemTime
private static SYSTEMTIME GetSystemTime(ref DateTime systemTime)
{
SYSTEMTIME time = new SYSTEMTIME();
time.wDay = (ushort)systemTime.Day;
time.wDayOfWeek = (ushort)(systemTime.DayOfWeek);
time.wHour = (ushort)systemTime.Hour;
time.wMilliseconds = (ushort)systemTime.Millisecond;
time.wMinute = (ushort)systemTime.Minute;
time.wMonth = (ushort)systemTime.Month;
time.wSecond = (ushort)systemTime.Second;
time.wYear = (ushort)systemTime.Year;
return time;
}
#endregion
public static bool AdjustPrivileges()
{
TOKEN_PRIVILEGES tkNew = new TOKEN_PRIVILEGES();
tkNew.Privileges = new LUID_AND_ATTRIBUTES[ANYSIZE_ARRAY];
TOKEN_PRIVILEGES tkOld = new TOKEN_PRIVILEGES();
tkOld.Privileges = new LUID_AND_ATTRIBUTES[ANYSIZE_ARRAY];
LUID luid = new LUID();
int token = -1;
int oldluidSize = 0;
if (LookupPrivilegeValue(null, SE_SYSTEMTIME_NAME, ref luid))
{
if (OpenProcessToken(GetCurrentProcess(),
TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, ref token))
{
tkNew.PrivilegeCount = 1;
tkNew.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
tkNew.Privileges[0].Luid = luid;
int luidSize = Marshal.SizeOf(typeof(TOKEN_PRIVILEGES));
if (AdjustTokenPrivileges(token, 0, ref tkNew, luidSize,
ref tkOld, ref oldluidSize))
{
return true;
}
}
}
return false;
}
#region Strutture
[StructLayoutAttribute(LayoutKind.Sequential)]
public struct SYSTEMTIME
{
public ushort wYear, wMonth, wDayOfWeek, wDay,
wHour, wMinute, wSecond, wMilliseconds;
}
[StructLayout(LayoutKind.Sequential)]
public struct LUID
{
public int LowPart;
public int HighPart;
}
[StructLayout(LayoutKind.Sequential)]
public struct LUID_AND_ATTRIBUTES
{
public LUID Luid;
public int Attributes;
}
[StructLayout(LayoutKind.Sequential)]
public struct TOKEN_PRIVILEGES
{
public int PrivilegeCount;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = ANYSIZE_ARRAY)]
public LUID_AND_ATTRIBUTES[] Privileges;
}
#endregion
}
-------------------------------------------------------------
and this is my code to call the datetime update
-------------------------------------------------------------
int errorCode = 0;
SystemDateTimeUtils.SetLocalTime(currentDate, out errorCode);
if (errorCode != 0)
MessageBox.Show("Error setting local system time to desired value: " +
"error code " + errorCode, "Error", MessageBoxButtons.OK,
MessageBoxIcon.Error);
------------------------------------------------------------- |