get current Logged in user name from within a C++ windows service - c++

I have a service (written in C++), running under Windows 10. I need to get the name of the currently logged in user, but most Windows APIs I have found return the username of the calling thread, which when run as a system, is always "SYSTEM".
My use case is below:
Install the service with Administrator account
Log off from administrator
Login as a Non-Admin user
Query the service to get the current logged user name

You need to enumerate all sessions and identify the active session using WTSEnumerateSessions. Then you can query username of the active session using WTSQuerySessionInformation and query class WTSUsername.
WTS_SESSION_INFO *SessionInfo;
unsigned long SessionCount;
unsigned long ActiveSessionId = -1;
std::cout<<"Active Console Session Id : "<<WTSGetActiveConsoleSessionId()<<"\n";
if(WTSEnumerateSessions(WTS_CURRENT_SERVER_HANDLE, 0, 1, &SessionInfo, &SessionCount))
{
for (auto i = 0; i < SessionCount; i++)
{
if (SessionInfo[i].State == WTSActive)
{
ActiveSessionId = SessionInfo[i].SessionId;
break;
}
}
char *UserName;
if (ActiveSessionId != -1)
{
unsigned long BytesReturned;
if (WTSQuerySessionInformation(WTS_CURRENT_SERVER_HANDLE, ActiveSessionId, WTSUserName, &UserName, &BytesReturned))
{
std::cout<<UserName;
WTSFreeMemory(UserName);
}
}
WTSFreeMemory(SessionInfo);
}
Note that this will only work if there is only one active session (unlike terminal servers)

in addition to answer above, the following line
if (SessionInfo[i].State == WTSActive)
should be changed to
if (SessionInfo[i].State == WTSActive || SessionInfo[i].State == WTSConnected)
to include remote session too

Related

WTS_CONNECTSTATE_CLASS enumeration class

I have to determine what state the user session is in. i.e if the the user is logged on and active or if the user is not logged on. To do this im using the function WTSEnumerateSessions and then I am checking the WTS_SESSION_INFOwhich is return from this function which has a state member.
According to the online documentation.
WTSActive A user is logged on to the WinStation
WTSDisconnected
The WinStation is active but the client is disconnected.
The problem is that im currently logged onto my system but the state returned for my current session is WTSDisconnected im expecting the state to be WTSActive is there any reason as to why this is happening?
Code below
PWTS_SESSION_INFO pSessionInfo(nullptr);
DWORD countOfSessions(0);
DWORD sessionIndex(0);
if (WTSEnumerateSessions(WTS_CURRENT_SERVER_HANDLE, // local machine
0, // reserved, must be zero
1, // Version, must be one
&pSessionInfo,
&countOfSessions) == FALSE)
{
return false;
}
if (countOfSessions == 0 || !pSessionInfo)
{
return false;
}
const DWORD currentSession = GetRealSessionID(CurrentSession); //This case we are in session 0
for (; sessionIndex < countOfSessions; ++sessionIndex)
{
WTS_SESSION_INFO& sessionInfo = pSessionInfo[sessionIndex];
if (currentSession == sessionInfo.SessionId)
{
if (sessionInfo.State == WTSActive)
{
return true;
}
}
}
return false;
Thanks
This doesn't make much sense. The most likely explanation is that currentSession is being assigned a value of 0, which is the session ID for the non-interactive isolated session in which services run.

Query cached ACL of a directory for a disconnected Windows domain user via Authz API

I would like to explore the effective rights of a local directory for the currently logged on domain user. This link has given me a good starting point and works as expected.
Unfortunately, querying the ACL fails when I disconnect from the domain controller and log on with my cached domain user profile. When being confronted with this environment, the AuthzInitializeContextFromSid function in the example code returns FALSE and sets 1355 (ERROR_NO_SUCH_DOMAIN) as the last error code:
...
PSID pSid = NULL;
BOOL bResult = FALSE;
LUID unusedId = { 0 };
AUTHZ_CLIENT_CONTEXT_HANDLE hAuthzClientContext = NULL;
pSid = ConvertNameToBinarySid(lpszUserName);
if (pSid != NULL)
{
bResult = AuthzInitializeContextFromSid(0,
pSid,
hManager,
NULL,
unusedId,
NULL,
&hAuthzClientContext);
if (bResult)
{
GetAccess(hAuthzClientContext, psd);
AuthzFreeContext(hAuthzClientContext);
}
else
{
//prints 1355 as last error code
wprintf_s(_T("AuthzInitializeContextFromSid failed with %d\n"), GetLastError());
}
...
}
Is it possible to query the (cached) ACL nonetheless? Surely they must be accessible some way or another, even if the domain controller is unreachable.

How do I get the Service Display name in C++?

I am trying to get the display name of the running service using c++. I was trying to use the GetServiceDisplayName function but it does not seem to be working, not sure why.
TTServiceBegin( const char *svcName, PFNSERVICE pfnService, bool *svc, PFNTERMINATE pfnTerm,
int flags, int argc, char *argv[], DWORD dynamiteThreadWaitTime )
{
SC_HANDLE serviceStatusHandle;
DWORD dwSizeNeeded = 0 ;
TCHAR* szKeyName = NULL ;
serviceStatusHandle=OpenSCManager(NULL, SERVICES_ACTIVE_DATABASE ,SC_MANAGER_ALL_ACCESS);
GetServiceDisplayName(serviceStatusHandle,svcName, NULL, &dwSizeNeeded);
if(dwSizeNeeded)
{
szKeyName = new char[dwSizeNeeded+1];
ZeroMemory(szKeyName,dwSizeNeeded+1);
if(GetServiceDisplayName(serviceStatusHandle ,svcName,szKeyName,&dwSizeNeeded)!=0)
{
MessageBox(0,szKeyName,"Got the key name",0);
}
}
When i run this code, i can never see the value of szKeyName in my debugger and it goes into the if block for the message box but never displays the message box. Not sure why?
Anyway to get this to work to get the display name of the service or any other/easier way to accomplish that task?
You need to use the WTSSendMessage instead of the MessageBox to interact with the active session.
WTS_SESSION_INFO* pSessionInfo = NULL;
DWORD dwSessionsCount = 0;
if(WTSEnumerateSessions(WTS_CURRENT_SERVER_HANDLE, 0, 1, &pSessionInfo, &dwSessionsCount))
{
for(int i=0; i<(int)dwSessionsCount; i++)
{
WTS_SESSION_INFO &si = pSessionInfo[i];
if(si.State == WTSActive)
{
DWORD dwIdCurrentSession = si.SessionId;
std::string strTitle = "Hello";
std::string strMessage = "This is a message from the service";
DWORD dwMsgBoxRetValue = 0;
if(WTSSendMessage(
WTS_CURRENT_SERVER_HANDLE,
dwIdCurrentSession,
(char*)strTitle.c_str(),
strTitle.size(),
(char*)strMessage.c_str(),
strMessage.size(),
MB_RETRYCANCEL | MB_ICONINFORMATION | MB_TOPMOST,
60000,
&dwMsgBoxRetValue,
TRUE))
{
switch(dwMsgBoxRetValue)
{
case IDTIMEOUT:
// Deal with TimeOut...
break;
case IDCANCEL:
// Deal With Cancel....
break;
}
}
else
{
// Deal With Error
}
break;
}
}
WTSFreeMemory(pSessionInfo);
}
The message box will not be visible on Windows Vista and later due to a change that has services running in a separate session (Session 0 Isolation) that does not have access to a desktop so the message box would not be visible to you, the logged on user.
On Window XP and earlier, you need to tick the Allow service to interact with desktop checkbox under the Log On tab in the service's properties dialog for your service to make message box appear.
Instead, you could write the service name out to a file or run a user application that accepts the name of the service to query and have it query and display the service name (I just tried with the posted code and it works correctly, displaying the message box).

Use of getlogin function in Linux

When I login in Linux Suse10 machine and check for getlogin_r() through a C++ program, i get a proper result as my login name.
int main()
{
char szUserName[64] = {0};
int nGet = getlogin_r(szUserName, sizeof(szUserName)-1);
if(0 != nGet)
{
printerr();
}
printf("%s\n", szUserName);
char * szHome = getlogin();
printf("%s\n", szHome);
return 0;
}
But after using the su - name2
i have changed the login now.
But getlogin_r() still shows the older usename.
One solution is the use of geteuid(). But what is the reason of above problem
"after using su - name2 I have changed the login" - No, you haven't. You've changed the user id, not the login.
The man page for su says this about the - option: "Provide an environment similar to what the user would expect had the user logged in directly." Apparently "similar" is different than "identical to". Specifically, su - does not store a login record in /var/run/utmp.

WMI Remote connection

I have an issue regarding WMI connection through asp.net from Computer A (windows 2003 server) to Computer B (Windows XP)..
The error is as follows:
RPC server is unavailable..
There are a few steps that you must take in order to successfully leverage WMI connectivity. The basics are you must allow remote management on the target box of course. If you can’t RDP into it, chances are, you can’t remote manage anything else. This can also include Windows firewall issues too. Make sure your request can even get in at all.
Next, start simple. Can you even poll for the running processes on that box? Try to output all the running processes on the target box with System.Diagnostics.Process currentProcess = System.Diagnostics.Process.GetProcesses("machine-name"). If you can at least get some information on the box then the RPC message you are getting has to do with incorrect arguments being passed in, perhaps?
Anyways, I recently wrote a web application that allowed the users to find a server on the LAN and kill a target process there or start a new one. I did it in C# so the code snippet below is just what I used. It's not the best but its working in production right now:
public static class RemoteProcessAccess
{
public static void KillProcessByProcessID(string NameOfServer, string DomainName, string LogIn, string Password, int processID)
{
//#1 The vars for this static method
#region /// <variables> ...
string userName;
string password;
string machineName;
string myDomain;
Hashtable hs = new Hashtable();
ManagementScope mScope;
ConnectionOptions cnOptions;
ManagementObjectSearcher objSearcher;
ManagementOperationObserver opsObserver;
ManagementClass manageClass;
DirectoryEntry entry;
DirectorySearcher searcher;
DirectorySearcher userSearcher;
#endregion
//#2 Set the basics sent into the method
machineName = NameOfServer;
myDomain = DomainName;
userName = LogIn;
password = Password;
cnOptions = new ConnectionOptions();
cnOptions.Impersonation = ImpersonationLevel.Impersonate;
cnOptions.EnablePrivileges = true;
cnOptions.Username = myDomain + "\\" + userName;
cnOptions.Password = password;
mScope = new ManagementScope(#"\\" + machineName + #"\ROOT\CIMV2", cnOptions);
//#3 Begin Connection to Remote Box
mScope.Connect();
objSearcher = new ManagementObjectSearcher(String.Format("Select * from Win32_Process Where ProcessID = {0}", processID));
opsObserver = new ManagementOperationObserver();
objSearcher.Scope = mScope;
string[] sep = { "\n", "\t" };
//#4 Loop through
foreach (ManagementObject obj in objSearcher.Get())
{
string caption = obj.GetText(TextFormat.Mof);
string[] split = caption.Split(sep, StringSplitOptions.RemoveEmptyEntries);
// Iterate through the splitter
for (int i = 0; i < split.Length; i++)
{
if (split[i].Split('=').Length > 1)
{
string[] procDetails = split[i].Split('=');
procDetails[1] = procDetails[1].Replace(#"""", "");
procDetails[1] = procDetails[1].Replace(';', ' ');
switch (procDetails[0].Trim().ToLower())
{
//You could look for any of the properties here and do something else,
case "processid":
int tmpProc = Convert.ToInt32(procDetails[1].ToString());
//if the process id equals the one passed in....
//(this is redundant since we should have limited the return
//by the query where above, but we're paranoid here
if (tmpProc.Equals(processID))
{
obj.InvokeMethod(opsObserver, "Terminate", null);
}
break;
}//end process ID switch...
}//end our if statement...
}//end our for loop...
}//end our for each loop...
}//end static method
}
Look at KB875605 ("How to troubleshoot WMI-related issues in Windows XP SP2")
You could enable the RPC server on any target machine by running this on the target's command prompt:
[/code]
netsh firewall set service RemoteAdmin
[/code]
Worked for me at least. :)
Try to use wmic command line to get information from the remote computer, also you can install the code of Services+ and try to connect and debug your connection to the server, most likely it is firewall problem or RPC services is down or disabled.