How to get token of logged-in user from within windows service with C++?

我是研究僧i 提交于 2021-02-20 03:55:30

问题


on windows vista & above,

currently, I am enumerating all windows sessions, then once I find an active session, WTSQueryUserToken() is called which gives me the token of current user.

This token is used to launch a process with his privileges / inside his desktop.

Problem I am facing is that there is not reliable way to get the active session / interactive session. I have to wait (check its presence every few millsecs) until explorer.exe is spawned.

I am not preferring notifications like those from SENS (system notification service) that user has logged on.


Edit

On receiving SERVICE_CONTROL_SESSIONCHANGE / logon event I call WTSGetActiveConsoleSessionId() to get the current session then I use this session ID with WTSQueryUserToken() to get token.

WTSGetActiveConsoleSessionId() sometimes returns me session 0. Thus I end up with token of session 0 when I want token from session of currently logged-in user.

It depends on timing of WTSGetActiveConsoleSessionId() call.

By experimenting I came up with idea to wait for explorer.exe and only after it comes up call WTSGetActiveConsoleSessionId(), this seems to guarantee that I always get session 1 or above and thus corresponding token.

Seeking a cleaner approach.


回答1:


On receiving SERVICE_CONTROL_SESSIONCHANGE / logon event I call WTSGetActiveConsoleSessionId() to get the current session then I use this session ID with WTSQueryUserToken() to get token.

You should be using the session ID that is reported by SERVICE_CONTROL_SESSIONCHANGE itself. The lpEventData parameter will be a pointer to a WTSSESSION_NOTIFICATION structure, which contains a dwSessionId field.

WTSGetActiveConsoleSessionId() sometimes returns me session 0.

WTSGetActiveConsoleSessionId() returns the session that is attached to the physical console (mouse/keyboard/monitor) of the local machine. It can NEVER report session 0 in Vista and later (due to session 0 isolation), but it can in XP (where the first interactive user to login uses session 0). However, even if it could report session 0, that is not guaranteed to be the correct session that is associated with the user who logged in. There are other ways to log in to a computer than through its physical console. Remote Desktop, for example.

Thus I end up with token of session 0 when I want token from session of currently logged-in user.

You need to query the session that the user actually logged into. SERVICE_CONTROL_SESSIONCHANGE tells you the actual session ID, which will never be 0 on Vista and later (due to Session 0 isolation).

By experimenting I came up with idea to wait for explorer.exe and only after it comes up call WTSGetActiveConsoleSessionId(), this seems to guarantee that I always get session 1 or above and thus corresponding token.

But that is not a guarantee that that active console session is the correct session to query.

Seeking a cleaner approach.

Use the session ID that the notification explicitly tells you. Don't hunt for it.




回答2:


I know this is an old question, but just for future reference, and to clarify Remy Lebeau's answer...

If we assume your Service Control Handler is called ServiceControlHandler then you want to do the following:

DWORD ServiceControlHandler(DWORD dwControl, DWORD dwEventType, LPVOID lpEventData, LPVOID lpContext)
{
    DWORD retval = ERROR_CALL_NOT_IMPLEMENTED; 

    switch (dwControl)
    {
        case SERVICE_CONTROL_INTERROGATE: // All services should handle this message
            retval = NO_ERROR;
            break;

        case SERVICE_CONTROL_SESSIONCHANGE: // Assumes you registered for these when you created the service
        {
            auto data = reinterpret_cast<WTSSESSION_NOTIFICATION*>(lpEventData);
            if (data)
            {
                DWORD sessionId = data->dwSessionId; // Now you have the actual session ID

                retval = NO_ERROR; // indicates we handled the message.

                switch (dwEventType)
                {
                    case WTS_CONSOLE_CONNECT:
                        // TODO: Do what you wish
                        break;
                    case WTS_CONSOLE_DISCONNECT:
                        // TODO: Do what you wish
                        break;
                    case WTS_REMOTE_CONNECT:
                        // TODO: Do what you wish
                        break;
                    case WTS_REMOTE_DISCONNECT:
                        // TODO: Do what you wish
                        break;
                    case WTS_SESSION_LOGON:
                        // TODO: Do what you wish
                        break;
                    case WTS_SESSION_LOGOFF:
                        // TODO: Do what you wish
                        break;
                    case WTS_SESSION_LOCK:
                        // TODO: Do what you wish
                        break;
                    case WTS_SESSION_UNLOCK:
                        // TODO: Do what you wish
                        break;
                    case WTS_SESSION_REMOTE_CONTROL:
                        // TODO: Do what you wish
                        break;

                    case WTS_SESSION_CREATE:    // (0xA) Reserved for future use.
                    case WTS_SESSION_TERMINATE: // (0xB) Reserved for future use.
                    default:
                        break; // do nothing
                }
            }
            else
            {
                // NOTE: should never happen
            }
        }
        break;

        // TODO: Handle other control types here

        default:
            retval = ERROR_CALL_NOT_IMPLEMENTED; // must always return this if not handled
            break;

    };

    return retval;
}

As Remy says, this way you use the session ID that the notification explicitly tells you, rather than going looking for it and getting the wrong one.



来源:https://stackoverflow.com/questions/33069138/how-to-get-token-of-logged-in-user-from-within-windows-service-with-c

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!