SetSystemTimeAdjustment privileges

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

SetSystemTimeAdjustment privileges

Post by Phineas Freak »

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: 197
Joined: Tue Apr 03, 2018 1:34 pm

Re: SetSystemTimeAdjustment privileges

Post by guest »

Phineas Freak wrote: Thu Jul 04, 2019 8:24 amHow 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 »

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!