SetSystemTimeAdjustment privileges

Discussions about the Liberty BASIC language, with particular reference to LB Booster
Post Reply
Phineas Freak
Posts: 2
Joined: Thu Jul 04, 2019 7:36 am

SetSystemTimeAdjustment privileges

Post by Phineas Freak » Thu Jul 04, 2019 8:24 am

So, i have the following demo code for fine adjustments of the local clock:

Code: Select all

    struct TOKENPRIVILEGES,      _
        PrivilegeCount as ulong, _
        Luid           as long,  _
        Attributes     as ulong

    hWndProc = GetCurrentProcess()

    if (hWndProc <> 0) then

        hWndToken = OpenProcessToken(hWndProc, _TOKEN_QUERY or _TOKEN_ADJUST_PRIVILEGES)

        if (hWndToken <> 0) then

            lpLuid = LookupPrivilegeValue("", "SeSystemtimePrivilege")

            if (lpLuid <> 0) then

                TOKENPRIVILEGES.PrivilegeCount.struct = 1
                TOKENPRIVILEGES.Luid.struct = lpLuid
                TOKENPRIVILEGES.Attributes.struct = _SE_PRIVILEGE_ENABLED

                bSetPrivileges = AdjustTokenPrivileges(hWndToken, 0)

                if (bSetPrivileges = 1) then

                    bSetTimeAdjust = SetSystemTimeAdjustment(156001, 1)

                    if (bSetTimeAdjust = 1) then

                        print "Time adjustment successful!"

                    else

                        nErrMsg = GetLastError()

                        szErrMsg$ = FormatMessage$(_FORMAT_MESSAGE_FROM_SYSTEM, _NULL, nErrMsg, _NULL, 256, _NULL)

                        print "Error " + str$(nErrMsg) + ": " + szErrMsg$

                    end if

                else

                    print "Error: privileges are not valid for this operation!"

                end if

                TOKENPRIVILEGES.Attributes.struct = _NULL

                bSetPrivileges = AdjustTokenPrivileges(hWndToken, 0)

            else

                print "Error: the lookup of the privilege value could not be completed!"

            end if

        else

            print "Error: the token handle could not be retrieved!"

        end if

        null = CloseHandle(hWndToken)

    else

        print "Error: no current process handle found!"

    end if

    end

'   ====================================================================================================
'   Function AdjustTokenPrivileges()

'   Enables or disables privileges in the specified access token. Enabling or disabling privileges in an
'   access token requires TOKEN_ADJUST_PRIVILEGES access.
'   ====================================================================================================

    function AdjustTokenPrivileges(TokenHandle, DisableAllPrivileges)

        BufferLength = len(TOKENPRIVILEGES.struct)

        calldll #advapi32, "AdjustTokenPrivileges", _
            TokenHandle           as handle,        _
            DisableAllPrivileges  as boolean,       _
            TOKENPRIVILEGES       as struct,        _
            BufferLength          as ulong,         _
            _NULL                 as ulong,         _
            _NULL                 as ulong,         _
            AdjustTokenPrivileges as boolean

    end function

'   ====================================================================================================
'   Function CloseHandle()

'   Closes an open object handle.
'   ====================================================================================================

    function CloseHandle(hWnd)

        calldll #kernel32, "CloseHandle", _
            hWnd        as handle,        _
            CloseHandle as boolean

    end function

'   ====================================================================================================
'   Function FormatMessage()

'   Formats a message string. The function requires a message definition as input. The message
'   definition can come from a buffer passed into the function. It can come from a message table
'   resource in an already-loaded module. Or the caller can ask the function to search the system's
'   message table resource(s) for the message definition. The function finds the message definition
'   in a message table resource based on a message identifier and a language identifier. The function
'   copies the formatted message text to an output buffer, processing any embedded insert sequences
'   if requested.
'   ====================================================================================================

    function FormatMessage$(dwFlags, lpSource, dwMessageId, dwLanguageId, nSize, Arguments)

        lpBuffer$ = space$(nSize)

        calldll #kernel32, "FormatMessageA", _
            dwFlags       as ulong,          _
            lpSource      as long,           _
            dwMessageId   as ulong,          _
            dwLanguageId  as ulong,          _
            lpBuffer$     as ptr,            _
            nSize         as ulong,          _
            Arguments     as long,           _
            FormatMessage as ulong

        if (FormatMessage > 0) then FormatMessage$ = trim$(lpBuffer$)

    end function

'   ====================================================================================================
'   Function GetCurrentProcess()

'   Retrieves a pseudo handle for the current process.
'   ====================================================================================================

    function GetCurrentProcess()

        calldll #kernel32, "GetCurrentProcess", _
            GetCurrentProcess as handle

    end function

'   ====================================================================================================
'   Function GetLastError()

'   Retrieves the calling thread's last-error code value. The last-error code is maintained on a
'   per-thread basis. Multiple threads do not overwrite each other's last-error code.
'   ====================================================================================================

    function GetLastError()

        calldll #kernel32, "GetLastError", _
            GetLastError as ulong

    end function

'   ====================================================================================================
'   Function LookupPrivilegeValue()

'   Retrieves the locally unique identifier (LUID) used on a specified system to locally represent the
'   specified privilege name.
'   ====================================================================================================

    function LookupPrivilegeValue(lpSystemName$, lpName$)

        struct PRIVILEGELPLUID, _
            lpLuid as long

        lpSystemName$ = lpSystemName$ + chr$(0)
        lpName$ = lpName$ + chr$(0)

        calldll #advapi32, "LookupPrivilegeValueA", _
            lpSystemName$        as ptr,            _
            lpName$              as ptr,            _
            PRIVILEGELPLUID      as struct,         _
            LookupPrivilegeValue as boolean

        if (LookupPrivilegeValue = 1) then LookupPrivilegeValue = PRIVILEGELPLUID.lpLuid.struct

    end function

'   ====================================================================================================
'   Function OpenProcessToken()

'   Opens the access token associated with a process.
'   ====================================================================================================

    function OpenProcessToken(ProcessHandle, DesiredAccess)

        struct TOKENHANDLE, _
            TokenHandle as handle

        calldll #advapi32, "OpenProcessToken", _
            ProcessHandle    as handle,        _
            DesiredAccess    as ulong,         _
            TOKENHANDLE      as struct,        _
            OpenProcessToken as boolean

        if (OpenProcessToken = 1) then OpenProcessToken = TOKENHANDLE.TokenHandle.struct

    end function

'   ====================================================================================================
'   Function SetSystemTimeAdjustment()

'   Enables or disables periodic time adjustments to the system's time-of-day clock. When enabled, such
'   time adjustments can be used to synchronize the time of day with some other source of time
'   information.
'   ====================================================================================================

    function SetSystemTimeAdjustment(dwTimeAdjustment, bTimeAdjustmentDisabled)

        calldll #kernel32, "SetSystemTimeAdjustment", _
            dwTimeAdjustment        as ulong,         _
            bTimeAdjustmentDisabled as boolean,       _
            SetSystemTimeAdjustment as boolean

    end function
As expected, it requires administrative access rights (which i have). Upon running the above snippet i get a standard access error 1314 ("A required privilege is not held by the client"). "Weird, i followed the standard steps that Microsoft recommends for that kind of operation". I then checked the return error codes of all preceding functions and all returned 0, as expected.

The quirk: i tested various things (checking the code itself, the LBB executable user rights, running the code in different computer systems) but i always got back the same error code. For some reason in one of the tests i added some random comments after the SetSystemTimeAdjustment call (just below the "Time Adjustment Successful" print call). Running the same exact code with just some additional REMs resulted in a "Time Adjustment Successful" message. Further testing revealed that different computer systems required different comment lengths (!?!?!).

TL;DR: How the hell simple comments after the critical system calls affect their proper execution? Or am i missing something really simple and the fact that the snippet works is because of sheer luck?

guest
Site Admin
Posts: 74
Joined: Tue Apr 03, 2018 1:34 pm

Re: SetSystemTimeAdjustment privileges

Post by guest » Thu Jul 04, 2019 11:51 am

Phineas Freak wrote:
Thu Jul 04, 2019 8:24 am
How the hell simple comments after the critical system calls affect their proper execution?
My suspicion is that it is a structure size issue. You have declared the TOKENPRIVILEGES structure as follows:

Code: Select all

struct TOKENPRIVILEGES,      _
PrivilegeCount as ulong, _
Luid           as long,  _
Attributes     as ulong
but Microsoft declare it differently:

Code: Select all

typedef struct _LUID_AND_ATTRIBUTES {
  LUID  Luid;
  DWORD Attributes;
} LUID_AND_ATTRIBUTES, *PLUID_AND_ATTRIBUTES;

typedef struct _TOKEN_PRIVILEGES {
  DWORD               PrivilegeCount;
  LUID_AND_ATTRIBUTES Privileges[ANYSIZE_ARRAY];
} TOKEN_PRIVILEGES, *PTOKEN_PRIVILEGES;
In your declaration there are three members, each consisting of 4 bytes. In Microsoft's there are two members, the first consisting of 4 bytes and the second of 12 bytes (LUID is a 64-bit value).

Try changing your structure declaration as follows:

Code: Select all

struct TOKENPRIVILEGES,  _
PrivilegeCount as ulong, _
LuidLo         as long,  _
LuidHi         as long,  _
Attributes     as ulong
Does that make a difference?

Phineas Freak
Posts: 2
Joined: Thu Jul 04, 2019 7:36 am

Re: SetSystemTimeAdjustment privileges

Post by Phineas Freak » Mon Jul 08, 2019 7:21 am

Heh, so much for claiming that i "followed the standard steps that Microsoft recommends for that kind of operation"... :oops:

You are correct, setting the proper LUID members fixed all these weird errors. Now the code runs just fine in all systems!

Thank you very much for your time!

Post Reply