SetLocalTime/SetSystemTime P/Invoke call fails under Vista (even witha requireAdministrator manifest)

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • rdilipk@gmail.com

    SetLocalTime/SetSystemTime P/Invoke call fails under Vista (even witha requireAdministrator manifest)


    I am posting at the end of this post some code that P/Invoke's
    SetSystemTime to set the local system time. This call fails -- i.e
    the time is not set and the API returns false. However calling
    Marshal.GetLast Win32Error immediately afterwards returns an errorcode
    of 0 indicating that the operation somehow executed successfully.

    This is a plain vanilla console app written in C#. It runs on vista
    and has a manifest embedded in it that has 'requireAdminis trator'
    privilege level on it. The logged on user belongs to the
    administrator group and the UAC is set at "prompt for consent".

    What am I missing? (FWIW, I didn't write the P/Invoke signatures
    myself. I just lifted them out of various postings on the internet --
    is there a mistake in that somewhere)?

    It seems similar to what was reported here:


    /********** CODE *************** *****/
    using System;
    using System.Collecti ons.Generic;
    using System.Text;
    using System.Runtime. InteropServices ;
    using System.Componen tModel;

    namespace VistaUACTest
    {
    class Program
    {
    [StructLayoutAtt ribute(LayoutKi nd.Sequential)]
    public struct SystemTime
    {
    public short year;
    public short month;
    public short dayOfWeek;
    public short day;
    public short hour;
    public short minute;
    public short second;
    public short milliseconds;
    }

    [DllImport("kern el32.dll")]
    private static extern bool SetLocalTime(re f SystemTime
    systime);

    [DllImport("kern el32.dll")]
    private static extern bool SetSystemTime(r ef SystemTime
    systime);

    private const int ANYSIZE_ARRAY = 1;
    private const string SE_SYSTEMTIME_N AME =
    "SeSystemtimePr ivilege";
    private const int SE_PRIVILEGE_EN ABLED = 0x00000002;
    private const int TOKEN_QUERY = 0x0008;
    private const int TOKEN_ADJUST_PR IVILEGES = 0x0020;

    [StructLayout(La youtKind.Sequen tial)]
    public struct LUID
    {
    public int LowPart;
    public int HighPart;
    }

    [StructLayout(La youtKind.Sequen tial)]
    public struct LUID_AND_ATTRIB UTES
    {
    public LUID Luid;
    public int Attributes;
    }

    [StructLayout(La youtKind.Sequen tial)]
    public struct TOKEN_PRIVILEGE S
    {
    public int PrivilegeCount;
    [MarshalAs(Unman agedType.ByValA rray, SizeConst =
    ANYSIZE_ARRAY)]
    public LUID_AND_ATTRIB UTES[] Privileges;
    }

    [DllImport("adva pi32.dll", CharSet = CharSet.Auto)]
    public static extern bool OpenProcessToke n(int ProcessHandle,
    int DesiredAccess, ref int TokenHandle);

    [DllImport("kern el32.dll", CharSet = CharSet.Auto)]
    public static extern int GetCurrentProce ss();

    [DllImport("adva pi32.dll", CharSet = CharSet.Auto)]
    public static extern bool LookupPrivilege Value(string
    lpSystemName, string lpName,

    [MarshalAs(Unman agedType.Struct )] ref LUID lpLuid);

    [DllImport("adva pi32.dll", CharSet = CharSet.Auto)]
    public static extern bool AdjustTokenPriv ileges(int
    TokenHandle,
    int
    DisableAllPrivi leges,

    [MarshalAs(Unman agedType.Struct )] ref TOKEN_PRIVILEGE S NewState,
    int
    BufferLength,

    [MarshalAs(Unman agedType.Struct )] ref TOKEN_PRIVILEGE S PreviousState,
    ref
    int ReturnLength);

    static void Main(string[] args)
    {
    try
    {
    // because the docs for SetSystemTime says that the
    SE_SYSTEMTIME_N AME privilege is disabled by default
    // this call doesn't really help though
    AdjustPrivilege s();
    SystemTime st = new SystemTime();
    st.hour = 10;
    if (!SetSystemTime (ref st))
    {
    // the return value says the call failed, however
    Marshal.GetLast Win32Error() says the previous P/Invoke operation
    // completed successfully (the default ctor of
    Win32Exception calls GetLastWin32Err or)
    throw new Win32Exception( );
    }
    }
    catch (Exception ex)
    {
    Console.WriteLi ne(ex);
    }
    Console.Read();
    }

    public static bool AdjustPrivilege s()
    {
    TOKEN_PRIVILEGE S tkNew = new TOKEN_PRIVILEGE S();
    tkNew.Privilege s = new LUID_AND_ATTRIB UTES[ANYSIZE_ARRAY];
    TOKEN_PRIVILEGE S tkOld = new TOKEN_PRIVILEGE S();
    tkOld.Privilege s = new LUID_AND_ATTRIB UTES[ANYSIZE_ARRAY];

    LUID luid = new LUID();
    int token = -1;
    int oldluidSize = 0;

    if (LookupPrivileg eValue(null, SE_SYSTEMTIME_N AME, ref
    luid))
    {
    if (OpenProcessTok en(GetCurrentPr ocess(),
    TOKEN_ADJUST_PR IVILEGES | TOKEN_QUERY, ref token))
    {
    tkNew.Privilege Count = 1;
    tkNew.Privilege s[0].Attributes =
    SE_PRIVILEGE_EN ABLED;
    tkNew.Privilege s[0].Luid = luid;
    int luidSize =
    Marshal.SizeOf( typeof(TOKEN_PR IVILEGES));
    if (AdjustTokenPri vileges(token, 0, ref tkNew,
    luidSize, ref tkOld, ref oldluidSize))
    {
    return true;
    }
    }
    }
    return false;
    }
    }
    }
    /************ CODE *************** *********/
  • Jeff Winn

    #2
    Re: SetLocalTime/SetSystemTime P/Invoke call fails under Vista (even with a requireAdminist rator manifest)

    Well, the signatures for the time APIs are correct (mostly) along with your
    SystemTime struct. Win32 BOOL is actually an int. Yes I know the marshalling
    will happen automatically, I'm just picky. Might want to turn off the UAC
    and try it again to see if that's causing the problem, I had no problem on
    my machine with UAC off. If so, there's a problem with how you're elevating
    the privileges of the current user.


    <rdilipk@gmail. comwrote in message
    news:d536c31b-34e9-4b75-80ca-57fa5779619f@l4 2g2000hsc.googl egroups.com...
    >
    I am posting at the end of this post some code that P/Invoke's
    SetSystemTime to set the local system time. This call fails -- i.e
    the time is not set and the API returns false. However calling
    Marshal.GetLast Win32Error immediately afterwards returns an errorcode
    of 0 indicating that the operation somehow executed successfully.
    >
    This is a plain vanilla console app written in C#. It runs on vista
    and has a manifest embedded in it that has 'requireAdminis trator'
    privilege level on it. The logged on user belongs to the
    administrator group and the UAC is set at "prompt for consent".
    >
    What am I missing? (FWIW, I didn't write the P/Invoke signatures
    myself. I just lifted them out of various postings on the internet --
    is there a mistake in that somewhere)?
    >
    It seems similar to what was reported here:

    >
    /********** CODE *************** *****/
    using System;
    using System.Collecti ons.Generic;
    using System.Text;
    using System.Runtime. InteropServices ;
    using System.Componen tModel;
    >
    namespace VistaUACTest
    {
    class Program
    {
    [StructLayoutAtt ribute(LayoutKi nd.Sequential)]
    public struct SystemTime
    {
    public short year;
    public short month;
    public short dayOfWeek;
    public short day;
    public short hour;
    public short minute;
    public short second;
    public short milliseconds;
    }
    >
    [DllImport("kern el32.dll")]
    private static extern bool SetLocalTime(re f SystemTime
    systime);
    >
    [DllImport("kern el32.dll")]
    private static extern bool SetSystemTime(r ef SystemTime
    systime);
    >
    private const int ANYSIZE_ARRAY = 1;
    private const string SE_SYSTEMTIME_N AME =
    "SeSystemtimePr ivilege";
    private const int SE_PRIVILEGE_EN ABLED = 0x00000002;
    private const int TOKEN_QUERY = 0x0008;
    private const int TOKEN_ADJUST_PR IVILEGES = 0x0020;
    >
    [StructLayout(La youtKind.Sequen tial)]
    public struct LUID
    {
    public int LowPart;
    public int HighPart;
    }
    >
    [StructLayout(La youtKind.Sequen tial)]
    public struct LUID_AND_ATTRIB UTES
    {
    public LUID Luid;
    public int Attributes;
    }
    >
    [StructLayout(La youtKind.Sequen tial)]
    public struct TOKEN_PRIVILEGE S
    {
    public int PrivilegeCount;
    [MarshalAs(Unman agedType.ByValA rray, SizeConst =
    ANYSIZE_ARRAY)]
    public LUID_AND_ATTRIB UTES[] Privileges;
    }
    >
    [DllImport("adva pi32.dll", CharSet = CharSet.Auto)]
    public static extern bool OpenProcessToke n(int ProcessHandle,
    int DesiredAccess, ref int TokenHandle);
    >
    [DllImport("kern el32.dll", CharSet = CharSet.Auto)]
    public static extern int GetCurrentProce ss();
    >
    [DllImport("adva pi32.dll", CharSet = CharSet.Auto)]
    public static extern bool LookupPrivilege Value(string
    lpSystemName, string lpName,
    >
    [MarshalAs(Unman agedType.Struct )] ref LUID lpLuid);
    >
    [DllImport("adva pi32.dll", CharSet = CharSet.Auto)]
    public static extern bool AdjustTokenPriv ileges(int
    TokenHandle,
    int
    DisableAllPrivi leges,
    >
    [MarshalAs(Unman agedType.Struct )] ref TOKEN_PRIVILEGE S NewState,
    int
    BufferLength,
    >
    [MarshalAs(Unman agedType.Struct )] ref TOKEN_PRIVILEGE S PreviousState,
    ref
    int ReturnLength);
    >
    static void Main(string[] args)
    {
    try
    {
    // because the docs for SetSystemTime says that the
    SE_SYSTEMTIME_N AME privilege is disabled by default
    // this call doesn't really help though
    AdjustPrivilege s();
    SystemTime st = new SystemTime();
    st.hour = 10;
    if (!SetSystemTime (ref st))
    {
    // the return value says the call failed, however
    Marshal.GetLast Win32Error() says the previous P/Invoke operation
    // completed successfully (the default ctor of
    Win32Exception calls GetLastWin32Err or)
    throw new Win32Exception( );
    }
    }
    catch (Exception ex)
    {
    Console.WriteLi ne(ex);
    }
    Console.Read();
    }
    >
    public static bool AdjustPrivilege s()
    {
    TOKEN_PRIVILEGE S tkNew = new TOKEN_PRIVILEGE S();
    tkNew.Privilege s = new LUID_AND_ATTRIB UTES[ANYSIZE_ARRAY];
    TOKEN_PRIVILEGE S tkOld = new TOKEN_PRIVILEGE S();
    tkOld.Privilege s = new LUID_AND_ATTRIB UTES[ANYSIZE_ARRAY];
    >
    LUID luid = new LUID();
    int token = -1;
    int oldluidSize = 0;
    >
    if (LookupPrivileg eValue(null, SE_SYSTEMTIME_N AME, ref
    luid))
    {
    if (OpenProcessTok en(GetCurrentPr ocess(),
    TOKEN_ADJUST_PR IVILEGES | TOKEN_QUERY, ref token))
    {
    tkNew.Privilege Count = 1;
    tkNew.Privilege s[0].Attributes =
    SE_PRIVILEGE_EN ABLED;
    tkNew.Privilege s[0].Luid = luid;
    int luidSize =
    Marshal.SizeOf( typeof(TOKEN_PR IVILEGES));
    if (AdjustTokenPri vileges(token, 0, ref tkNew,
    luidSize, ref tkOld, ref oldluidSize))
    {
    return true;
    }
    }
    }
    return false;
    }
    }
    }
    /************ CODE *************** *********/

    Comment

    • Dilip

      #3
      Re: SetLocalTime/SetSystemTime P/Invoke call fails under Vista (evenwith a requireAdminist rator manifest)

      On May 16, 8:30 pm, "Jeff Winn" <jw...@nospam.c omwrote:
      Well, the signatures for the time APIs are correct (mostly) along with your
      SystemTime struct. Win32 BOOL is actually an int. Yes I know the marshalling
      will happen automatically, I'm just picky. Might want to turn off the UAC
      and try it again to see if that's causing the problem, I had no problem on
      my machine with UAC off. If so, there's a problem with how you're elevating
      the privileges of the current user.
      Jeff
      Thanks for responding. The privilege adjusting code is there for no
      particular reason. I believe the admin privileges already include
      SE_SYSTEMTIME_N AME (which is enabled).

      In any case, the funny thing is I can't get it to work even:

      * if I run this application from a elevated command prompt
      * if I mark the manifest as 'requireAdminis trator' and grant consent
      to the UAC dialog that pops up.

      I thought the latter option was at least morally the same as turning
      off UAC? I will turn off UAC and see how that goes.

      There is another weird thing going on here. SetSystemTime seems to
      return false indicating the call failed (and the time obviously isn't
      set), however if I call Marshal.GetLast Win32Error() immediately after,
      it returns 0 saying "the operation completed successfully".

      Does that make sense to you?

      Comment

      Working...