Alternatives to LsaLogonUser with KERB_S4U_LOGON have Network access? - c++

Are there any alternatives to LsaLogonUser for impersonating given account in order to access network resources? I'm looking for the method of impersonation which would let me call a remote machine via UNC in the same domain.
For initial data I have: domain\username.
I have no password, because this I am using LsaRegisterLogonProcess and LsaLogonUser with Kerberos package. Locally everything is working and I can impersonate and call applications using a different username, however, when trying to access a remote machine using.. \\remotemachine\shared\somefile.bat I have Access Denied.
Basically I call cmd.exe as command.. and then a Console opens with a new user impersonated, but if a Try to call the UNC path, Access Denied.
If I open a basic console with my own user, I execute this UNC path successfully. Is not Folder permissions because is a public Share.
This is a part of my working code:
...
NTSTATUS Status = STATUS_SUCCESS;
LSA_OPERATIONAL_MODE unused;
LSA_STRING lsaString;
lsaString.Buffer = "User Impersonated LogonProcess";
lsaString.Length = strlen(lsaString.Buffer);
lsaString.MaximumLength = lsaString.Length + 1;
Status = LsaRegisterLogonProcess(&lsaString, &lsa, &unused);
if (Status != STATUS_SUCCESS) {
printf("LsaRegisterLogonProcess failed: %x\n", Status);
}
...
NTSTATUS status = LsaLogonUser(
lsa,
&origin,
Network,
packageId,
authInfo,
authInfoSize,
0,
&source,
&profileBuffer,
&profileBufLen,
&luid,
&token,
&qlimits,
&subStatus
);
if (status != ERROR_SUCCESS)
{
ULONG err = LsaNtStatusToWinError(status);
printf("LsaLogonUser failed: %x\n", status);
return 1;
}
...
DuplicateTokenEx(token, MAXIMUM_ALLOWED, NULL, SecurityImpersonation, TokenPrimary, &tokenDuplicate);
if (CreateProcessWithTokenW(
tokenDuplicate,
LOGON_WITH_PROFILE,
command,
command_arguments,
CREATE_NEW_CONSOLE,
NULL,
NULL,
&si,
&pi))
{
pi.hThread = NULL;
pi.hProcess = NULL;
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
}

Related

Windows Login from C++ service

I am trying to create a Windows Service that is able to log on my user programatically into my local windows 10 pc the same as if i was typing directly in front of my keyboard. (I want to be able to initialize my session remotely)
I am using LogonUser and it returns properly but i will never see the user to appear as loged in in the Task Manager for example.
This is what i have tried now:
BSINFO(L"Login User...");
HANDLE sessToken = nullptr;
BOOL bRes = LogonUserW(
L"TestUser",
L".",
L"1234",
LOGON32_LOGON_INTERACTIVE,
LOGON32_PROVIDER_DEFAULT,
&sessToken);
if (bRes)
{
PROFILEINFO profInfo;
ZeroMemory(&profInfo,sizeof(PROFILEINFO));
profInfo.dwSize = sizeof(PROFILEINFO);
profInfo.lpUserName = L"TestUser";
profInfo.lpServerName = L"";
bRes = LoadUserProfileW(sessToken,&profInfo);
if (!bRes)
{
DWORD dwError = GetLastError();
BSERROR(L"Error LoadUserProfileW. %d '%ls'", dwError, GetLastErrorW(dwError).c_str());
}
}
else
{
DWORD dwError = GetLastError();
BSERROR(L"Error login user. %d '%ls'", dwError, GetLastErrorW(dwError).c_str());
}
Is it something possible to do?

Winapi OpenService Returning Acces Denied [duplicate]

I wrote a windows service (and it runs fine). Now i have a separate app where I want to start this service from, but it seems this is not possible without administrator rights.
How would a proper solution look like that a user can start/stop the service (e.g. from a tray or application)
IMHO its bad that the application must always be started with administrator rights.
You just need to change the permissions on the service object, preferably at the same time you install it.
wchar_t sddl[] = L"D:"
L"(A;;CCLCSWRPWPDTLOCRRC;;;SY)" // default permissions for local system
L"(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;BA)" // default permissions for administrators
L"(A;;CCLCSWLOCRRC;;;AU)" // default permissions for authenticated users
L"(A;;CCLCSWRPWPDTLOCRRC;;;PU)" // default permissions for power users
L"(A;;RP;;;IU)" // added permission: start service for interactive users
;
PSECURITY_DESCRIPTOR sd;
if (!ConvertStringSecurityDescriptorToSecurityDescriptor(sddl, SDDL_REVISION_1, &sd, NULL))
{
fail();
}
if (!SetServiceObjectSecurity(service, DACL_SECURITY_INFORMATION, sd))
{
fail();
}
I'm assuming here you've already opened the service handle. You need WRITE_DAC permission.
If you also want non-admin users to be able to stop the service, add the WP right, i.e.,
L"(A;;RPWP;;;IU)"
// added permissions: start service, stop service for interactive users
SDDL codes for service rights can be found in Wayne Martin's blog entry, Service Control Manager Security for non-admins.
#Harry Johnston, in addition to response.
Here is c++ builder example.
void __fastcall TService1::ServiceAfterInstall(TService *Sender)
{
wchar_t lpBuffer[256];
long errorCode;
SC_HANDLE hSCManager,hService;
hSCManager = OpenSCManager(0, 0, SC_MANAGER_CONNECT);
if (hSCManager == NULL)
{
errorCode = GetLastError();
FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM, NULL, errorCode,MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), lpBuffer, 256, NULL);
LogMessage("OpenSCManager Error "+AnsiString(lpBuffer), EVENTLOG_ERROR_TYPE);
return;
}
hService = OpenService(hSCManager, this->Name.c_str(), READ_CONTROL | WRITE_DAC);
if (hService == NULL)
{
errorCode = GetLastError();
FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM, NULL, errorCode,MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), lpBuffer, 256, NULL);
LogMessage("OpenService Error "+AnsiString(lpBuffer), EVENTLOG_ERROR_TYPE);
CloseServiceHandle(hSCManager);
}
wchar_t sddl[] = L"D:"
L"(A;;CCLCSWRPWPDTLOCRRC;;;SY)" // default permissions for local system
L"(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;BA)" // default permissions for administrators
L"(A;;CCLCSWLOCRRC;;;AU)" // default permissions for authenticated users
L"(A;;CCLCSWRPWPDTLOCRRC;;;PU)" // default permissions for power users
L"(A;;RP;;;IU)" // added permission: start service for interactive users
;
PSECURITY_DESCRIPTOR sd;
if (!ConvertStringSecurityDescriptorToSecurityDescriptor(AnsiString(sddl).c_str(), SDDL_REVISION_1, &sd, NULL))
{
errorCode = GetLastError();
FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM, NULL, errorCode,MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), lpBuffer, 256, NULL);
LogMessage("ConvertStringSecurityDescriptorToSecurityDescriptor Error "+AnsiString(lpBuffer), EVENTLOG_ERROR_TYPE);
}
if (!SetServiceObjectSecurity(hService, DACL_SECURITY_INFORMATION, sd))
{
errorCode = GetLastError();
FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM, NULL, errorCode,MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), lpBuffer, 256, NULL);
LogMessage("SetServiceObjectSecurity Error "+AnsiString(lpBuffer), EVENTLOG_ERROR_TYPE);
}
CloseServiceHandle(hService);
CloseServiceHandle(hSCManager);
}
Starting a service programmatically is done with the StartService function. There is a comprehensive usage example also given under the title starting a service, which also shows how to:
detect that the service is for some reason shutting down
wait until the service is in a stable state (started/stopped)
start the service programmatically
As for administrator rights, this is necessary because if just about any application could shut services down (or, more importantly, install and start new services) there would be very real and very serious security issues.
#Harry Johnston 's worked fine for me, in case someone wants to do this in C#:
[DllImport("advapi32.dll", SetLastError = true)]
static extern bool SetServiceObjectSecurity(SafeHandle serviceHandle,
UInt32 secInfos,
IntPtr lpSecDesrBuf);
[DllImport("advapi32.dll", EntryPoint = "ConvertStringSecurityDescriptorToSecurityDescriptorW", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern Boolean ConvertStringSecurityDescriptorToSecurityDescriptor(
[MarshalAs(UnmanagedType.LPWStr)] String strSecurityDescriptor,
UInt32 sDRevision,
ref IntPtr securityDescriptor,
ref UInt32 securityDescriptorSize);
public static void SetServicePermissions(string service)
{
System.ServiceProcess.ServiceController sc = new System.ServiceProcess.ServiceController(service);
bool ok;
IntPtr pSD = IntPtr.Zero;
uint securityDescriptorSize = 0;
string secDesc = "D:(A;;CCLCSWRPWPDTLOCRRC;;;SY)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;BA)(A;;CCLCSWLOCRRC;;;AU)(A;;CCLCSWRPWPDTLOCRRC;;;PU)(A;;RPWP;;;IU)";
ok = ConvertStringSecurityDescriptorToSecurityDescriptor(secDesc, 1, ref pSD, ref securityDescriptorSize);
if (!ok)
{
throw new ApplicationException("error calling ConvertStringSecurityDescriptorToSecurityDescriptor(): error code=" + Marshal.GetLastWin32Error());
}
ok = SetServiceObjectSecurity(sc.ServiceHandle, 4 , pSD);
if (!ok)
{
throw new ApplicationException("error calling SetServiceObjectSecurity(); error code=" + Marshal.GetLastWin32Error());
}
}

After ImpersonateLoggedOnUser(), why failed to call Windows API SetDisplayConfig()?

This is a System service. After ImpersonateLoggedOnUser(), I can call CreateProcessAsUser() successfully. But it fails to call one Windows API SetDisplayConfig(). The error is 5 (ERROR_ACCESS_DENIED). Please see the code below.
// This function is called in a System service.
void SetDisplayToExtendMode()
{
DWORD dwSessionId = WTSGetActiveConsoleSessionId();
if (dwSessionId == 0xFFFFFFFF)
{
qCritical() << "Failed to get active console session Id when setting extend mode for display!";
}
HANDLE hUserToken = NULL;
if (WTSQueryUserToken(dwSessionId, &hUserToken) == FALSE)
{
qCritical() << "Failed to query user token when setting extend mode for display!";
}
HANDLE hTheToken = NULL;
if (DuplicateTokenEx(hUserToken, TOKEN_ASSIGN_PRIMARY | TOKEN_ALL_ACCESS, 0, SecurityImpersonation, TokenPrimary, &hTheToken) == TRUE)
{
if (ImpersonateLoggedOnUser(hTheToken) == TRUE)
{
DWORD dwCreationFlags = HIGH_PRIORITY_CLASS | CREATE_NEW_CONSOLE;
LPVOID pEnv = NULL;
if (CreateEnvironmentBlock(&pEnv, hTheToken, TRUE) == TRUE)
{
dwCreationFlags |= CREATE_UNICODE_ENVIRONMENT;
}
// Way 1: Call Windows API directly.
// Fail. Error code is ERROR_ACCESS_DENIED
LONG errCode = SetDisplayConfig(0, NULL, 0, NULL, SDC_TOPOLOGY_EXTEND | SDC_APPLY);
if (errCode != ERROR_SUCCESS)
{
qCritical() << "Failed to set Windows Display to Extended mode! Error is " << errCode;
if (errCode == ERROR_ACCESS_DENIED)
{
qCritical() << "ACCESS denied!";
}
}
STARTUPINFO si = { sizeof(si) };
PROCESS_INFORMATION pi;
SECURITY_ATTRIBUTES Security1 = { sizeof(Security1) };
SECURITY_ATTRIBUTES Security2 = { sizeof(Security2) };
std::wstring command = L"C:\\Users\\SomeUser\\Desktop\\QT_Projects\\build\\release\\TestSetDisplay.exe";
TCHAR commandLine[MAX_PATH];
_tcscpy_s(commandLine, MAX_PATH, command.c_str());
// Way 2: This way can be successful.
BOOL bResult = CreateProcessAsUser(
hTheToken,
NULL, // (LPWSTR)(path),
(LPWSTR)(commandLine),
&Security1,
&Security2,
FALSE,
dwCreationFlags,
pEnv,
NULL,
&si,
&pi
);
if (!bResult)
{
qCritical() << "Failed to CreateProcessAsUser()";
}
RevertToSelf();
if (pEnv)
{
DestroyEnvironmentBlock(pEnv);
}
}
CloseHandle(hTheToken);
}
CloseHandle(hUserToken);
}
So, after ImpersonateLoggedOnUser(), how to call Windows API SetDisplayConfig() successfully?
Alternatively, in one System service, how to call one Windows API as a user? (For this case, the purpose of calling SetDisplayConfig() is to set the display mode to Extend mode. This display mode is set per user. So, as a system service, it may need to impersonateLoggedOnUser() first.)
from SetDisplayConfig documentation
ERROR_ACCESS_DENIED The caller does not have access to the console
session. This error occurs if the calling process does not have access
to the current desktop or is running on a remote session.
and you wrote
This is a System service.
but System service have no access to interactive desktop. so you need call it from interactive session

Get a process Owner (Citrix/Provisioning)

I'm using OpenProcessToken, GetTokenInformation and then LookupAccountSid to determine the owner of a certain process.
On a local machine (Win 7 and Win 8.1), on a RD Services session (Server 2012) it works fine. I do get the correct user name. The user name displayed in the task manager next to the process.
When I execute the same code in a Provisioning (ex Citrix) environment I only get the username "Administrator" although there is a different name displayed in the task manager.
Does anybody have an idea how to conquer this within a Provisioning environment?
Thanks a lot for any help
Martin
Here is the C++ Code I'm using:
BOOL DDEWinWord::processStartedFromLocalUser(DWORD procId)
{
#define MAX_NAME 256
DWORD dwSize = 0, dwResult = 0;
HANDLE hToken;
SID_NAME_USE SidType;
char lpName[MAX_NAME];
char lpDomain[MAX_NAME];
PTOKEN_OWNER tp;
// Open a handle to the access token for the calling process.
HANDLE processHandle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, procId);
if (!OpenProcessToken(processHandle, TOKEN_QUERY, &hToken)) {
AfxMessageBox("processStartedFromLocalUser - OpenProcessToken fehlschlag.");
return FALSE;
}
// Call GetTokenInformation to get the buffer size.
if(!GetTokenInformation(hToken, TokenOwner, NULL, dwSize, &dwSize))
{
dwResult = GetLastError();
if (dwResult != ERROR_INSUFFICIENT_BUFFER)
{
AfxMessageBox("processStartedFromLocalUser - GetTokenInformation fehlschlag.");
return FALSE;
}
}
// Allocate the buffer.
tp = (PTOKEN_OWNER)GlobalAlloc(GPTR, dwSize);
// Call GetTokenInformation again to get the group information.
if (!GetTokenInformation(hToken, TokenOwner, tp, dwSize, &dwSize))
{
AfxMessageBox("processStartedFromLocalUser - GetTokenInformation mit tp fehlschlag.");
return FALSE;
}
if (!LookupAccountSid(NULL, tp->Owner, lpName, &dwSize, lpDomain, &dwSize, &SidType))
{
AfxMessageBox("processStartedFromLocalUser - LookupAccountSid fehlschlag.");
return FALSE;
}
else
{
AfxMessageBox(lpName);
}
return (m_stUserId.CompareNoCase(lpName) == 0);
}
You should be using TokenUser rather than TokenOwner.

Start Windows Service From Application without Admin right(c++)

I wrote a windows service (and it runs fine). Now i have a separate app where I want to start this service from, but it seems this is not possible without administrator rights.
How would a proper solution look like that a user can start/stop the service (e.g. from a tray or application)
IMHO its bad that the application must always be started with administrator rights.
You just need to change the permissions on the service object, preferably at the same time you install it.
wchar_t sddl[] = L"D:"
L"(A;;CCLCSWRPWPDTLOCRRC;;;SY)" // default permissions for local system
L"(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;BA)" // default permissions for administrators
L"(A;;CCLCSWLOCRRC;;;AU)" // default permissions for authenticated users
L"(A;;CCLCSWRPWPDTLOCRRC;;;PU)" // default permissions for power users
L"(A;;RP;;;IU)" // added permission: start service for interactive users
;
PSECURITY_DESCRIPTOR sd;
if (!ConvertStringSecurityDescriptorToSecurityDescriptor(sddl, SDDL_REVISION_1, &sd, NULL))
{
fail();
}
if (!SetServiceObjectSecurity(service, DACL_SECURITY_INFORMATION, sd))
{
fail();
}
I'm assuming here you've already opened the service handle. You need WRITE_DAC permission.
If you also want non-admin users to be able to stop the service, add the WP right, i.e.,
L"(A;;RPWP;;;IU)"
// added permissions: start service, stop service for interactive users
SDDL codes for service rights can be found in Wayne Martin's blog entry, Service Control Manager Security for non-admins.
#Harry Johnston, in addition to response.
Here is c++ builder example.
void __fastcall TService1::ServiceAfterInstall(TService *Sender)
{
wchar_t lpBuffer[256];
long errorCode;
SC_HANDLE hSCManager,hService;
hSCManager = OpenSCManager(0, 0, SC_MANAGER_CONNECT);
if (hSCManager == NULL)
{
errorCode = GetLastError();
FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM, NULL, errorCode,MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), lpBuffer, 256, NULL);
LogMessage("OpenSCManager Error "+AnsiString(lpBuffer), EVENTLOG_ERROR_TYPE);
return;
}
hService = OpenService(hSCManager, this->Name.c_str(), READ_CONTROL | WRITE_DAC);
if (hService == NULL)
{
errorCode = GetLastError();
FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM, NULL, errorCode,MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), lpBuffer, 256, NULL);
LogMessage("OpenService Error "+AnsiString(lpBuffer), EVENTLOG_ERROR_TYPE);
CloseServiceHandle(hSCManager);
}
wchar_t sddl[] = L"D:"
L"(A;;CCLCSWRPWPDTLOCRRC;;;SY)" // default permissions for local system
L"(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;BA)" // default permissions for administrators
L"(A;;CCLCSWLOCRRC;;;AU)" // default permissions for authenticated users
L"(A;;CCLCSWRPWPDTLOCRRC;;;PU)" // default permissions for power users
L"(A;;RP;;;IU)" // added permission: start service for interactive users
;
PSECURITY_DESCRIPTOR sd;
if (!ConvertStringSecurityDescriptorToSecurityDescriptor(AnsiString(sddl).c_str(), SDDL_REVISION_1, &sd, NULL))
{
errorCode = GetLastError();
FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM, NULL, errorCode,MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), lpBuffer, 256, NULL);
LogMessage("ConvertStringSecurityDescriptorToSecurityDescriptor Error "+AnsiString(lpBuffer), EVENTLOG_ERROR_TYPE);
}
if (!SetServiceObjectSecurity(hService, DACL_SECURITY_INFORMATION, sd))
{
errorCode = GetLastError();
FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM, NULL, errorCode,MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), lpBuffer, 256, NULL);
LogMessage("SetServiceObjectSecurity Error "+AnsiString(lpBuffer), EVENTLOG_ERROR_TYPE);
}
CloseServiceHandle(hService);
CloseServiceHandle(hSCManager);
}
Starting a service programmatically is done with the StartService function. There is a comprehensive usage example also given under the title starting a service, which also shows how to:
detect that the service is for some reason shutting down
wait until the service is in a stable state (started/stopped)
start the service programmatically
As for administrator rights, this is necessary because if just about any application could shut services down (or, more importantly, install and start new services) there would be very real and very serious security issues.
#Harry Johnston 's worked fine for me, in case someone wants to do this in C#:
[DllImport("advapi32.dll", SetLastError = true)]
static extern bool SetServiceObjectSecurity(SafeHandle serviceHandle,
UInt32 secInfos,
IntPtr lpSecDesrBuf);
[DllImport("advapi32.dll", EntryPoint = "ConvertStringSecurityDescriptorToSecurityDescriptorW", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern Boolean ConvertStringSecurityDescriptorToSecurityDescriptor(
[MarshalAs(UnmanagedType.LPWStr)] String strSecurityDescriptor,
UInt32 sDRevision,
ref IntPtr securityDescriptor,
ref UInt32 securityDescriptorSize);
public static void SetServicePermissions(string service)
{
System.ServiceProcess.ServiceController sc = new System.ServiceProcess.ServiceController(service);
bool ok;
IntPtr pSD = IntPtr.Zero;
uint securityDescriptorSize = 0;
string secDesc = "D:(A;;CCLCSWRPWPDTLOCRRC;;;SY)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;BA)(A;;CCLCSWLOCRRC;;;AU)(A;;CCLCSWRPWPDTLOCRRC;;;PU)(A;;RPWP;;;IU)";
ok = ConvertStringSecurityDescriptorToSecurityDescriptor(secDesc, 1, ref pSD, ref securityDescriptorSize);
if (!ok)
{
throw new ApplicationException("error calling ConvertStringSecurityDescriptorToSecurityDescriptor(): error code=" + Marshal.GetLastWin32Error());
}
ok = SetServiceObjectSecurity(sc.ServiceHandle, 4 , pSD);
if (!ok)
{
throw new ApplicationException("error calling SetServiceObjectSecurity(); error code=" + Marshal.GetLastWin32Error());
}
}