C create and run windows service - c

I am trying to create a service that will be run at system startup and start it immediately. Service is supposed to run my exe file.
GetLastError function return 1053 error code.
int main(void)
{
SC_HANDLE SC_manager_handle;
SC_HANDLE service_handle;
LPCTSTR binary_path = "C:\\Users\\User\\AppData\\file.exe";
LPCTSTR display_name = "ExampleService";
LPCTSTR service_name = "EXAMPLE_SERVICE";
SC_manager_handle = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
puts("-----------------------");
if(SC_manager_handle == NULL)
puts("Open SM Manager: FAILED");
else
puts("SC Manager: SUCCESS");
service_handle = CreateService(SC_manager_handle, service_name, display_name, SERVICE_ALL_ACCESS ,SERVICE_WIN32_OWN_PROCESS, SERVICE_AUTO_START, SERVICE_ERROR_NORMAL, binary_path, NULL, NULL, NULL, NULL, NULL);
if(service_handle == NULL)
puts("Create Service: FAILED");
else
puts("Service Create: SUCCESS");
// running the exe file immediately
if(!StartService(service_handle, 0, NULL))
printf("Start Service: FAILED | ERROR: %d\n", GetLastError());
else
puts("Service Start: SUCCESS");
CloseServiceHandle(SC_manager_handle);
CloseServiceHandle(service_handle);
return 0;
}

I think you miss some important requirements for a windows service.According to the MSDN.
You need a service main function and a control handler function as you can't handle the "start" command if there's no control handler function registered.
So you can refer to the code to know how to wrote a ServiceMain Function and install it.
If you want to open the service, according to Starting a Service:
To start a service, a service control program opens a handle to an
installed database and then specifies the handle in a call to the
StartService function. After starting the service, the program uses
the members of the SERVICE_STATUS_PROCESS structure returned by the
QueryServiceStatusEx function to track the progress of the service.
I recommend you refer to the complete sample of using the service, which will greatly help you use the service.

Related

Sharedmemory between different sessions

I have two applications:
first one: running with SYSTEM Privileges started by a service and the
second one: running still as SYSTEM but with lower privileges (SE_GROUP_INTEGRITY = "S-1-16-4096")
I want both applications to communicate over sharedmemory. Both need to read and write.
In my first application i create the filemapping with specific SECURITY_ATTRIBUTES i learned from this post: How to share memory between services and user processes?
SECURITY_ATTRIBUTES attributes;
ZeroMemory(&attributes, sizeof(attributes));
attributes.nLength = sizeof(attributes);
ConvertStringSecurityDescriptorToSecurityDescriptor(
L"D:P(A;OICI;GA;;;SY)(A;OICI;GA;;;BA)(A;OICI;GWR;;;IU)",
SDDL_REVISION_1,
&attributes.lpSecurityDescriptor,
NULL);
HANDLE test = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, 1024, "Global\\Test");
Everything works as expected, but if i then try to open the file mapping in my second application, it crashes with an access violation at OpenFileMapping.
HANDLE test = OpenFileMapping(FILE_ALL_ACCESS, FALSE, 1024, "Global\\Test");
if you want allow access to object for Low Integrity code you need add Low mandatory level (SDDL_ML_LOW) Integrity label (SDDL_MANDATORY_LABEL) to security descriptor. for example
"D:PNO_ACCESS_CONTROLS:(ML;;NW;;;LW)"
so in general code is next:
ULONG CreateSectionWithLowAccess(PHANDLE SectionHandle, ULONG dwMaximumSize, PCWSTR lpName)
{
SECURITY_ATTRIBUTES sa = { sizeof(sa) };
if (ConvertStringSecurityDescriptorToSecurityDescriptorW(L"D:PNO_ACCESS_CONTROLS:(ML;;NW;;;LW)",
SDDL_REVISION_1, &sa.lpSecurityDescriptor, NULL))
{
*SectionHandle = CreateFileMappingW(INVALID_HANDLE_VALUE, &sa, PAGE_READWRITE, 0, dwMaximumSize, lpName);
LocalFree(sa.lpSecurityDescriptor);
return *SectionHandle ? NOERROR : GetLastError();
}
return GetLastError();
}

How to launch an Universal App as another user with WinAPI?

How can I launch an Universal App as another user using CreateProcessWithLogonW()? I cannot get it to launch using C:\\Windows\\System32\\cmd.exe /c start skype: even though start skype: does launch in the terminal.
#include <stdio.h>
#include <windows.h>
#include <lmcons.h>
int main(void)
{
PROCESS_INFORMATION pi = { 0 };
STARTUPINFOW si = { 0 };
si.cb = sizeof(STARTUPINFOW);
/*
not working:
L"C:\\Windows\\System32\\cmd.exe /c start skype" error: "The filename, directory name, or volume label syntax is incorrect."
L"C:\\Windows\\System32\\cmd.exe /c start skype:" no error but a pop-up with text: "You'll need a new app to open this"
*/
wchar_t lpCommandLine[] = L"C:\\Windows\\System32\\cmd.exe /c start skype:"; // lpCommandLine must be writable memory
if (!CreateProcessWithLogonW(L"username", L".", L"password", LOGON_WITH_PROFILE, NULL, lpCommandLine, 0, NULL, NULL, &si, &pi))
{
printf("GetLastError(): %i\n", GetLastError());
char buf[UNLEN + 1] = { 0 };
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&buf, sizeof(buf), NULL);
puts(buf);
return 1;
}
else
{
// do stuff only while skype is running
puts("skype is running.");
if (WaitForSingleObject(pi.hProcess, INFINITE) == WAIT_FAILED)
puts("WaitForSingleObject() failed");
// do stuff only after skype exits
puts("skype is NOT running.");
}
return 0;
}
This is impossible. No matter what user the UWP app is run under, it will always run under a sandboxed AppContainer user that is different for every user session. You can't run a UWP app as another user using the Win32 api.
This is possible depending on what you mean by different user. For example, in our product we have a windows service which runs under 'Local System' account and from this we are able to launch a UWP app in the currently logged on user account. For this, we have used CreateProcessAsUser to launch a process in the logged on user account with command to open the protocol supported by the UWP app. Sample code :
string uwpAppLaunchCmdLine = string.Format("/c start {0}", PROTOCOL_SUPPORTED_BY_UWP_APP);
int processId;
IntPtr hErrorReadOut = IntPtr.Zero;
ProcessMetadata processMetadata;
if (!StartAsCurrentUser("cmd.exe", false, out processId,out processMetadata, coreAppLaunchCmdLine))
{
//Failed to launch
}
else
{
//success!
}

How to retrieve system proxy settings in Win 7 for windows service in C

I am writing an application that will run as a service and will pick system proxy settings for communication with the outside world .I tried WinHttpGetIEProxyConfigForCurrentUser but it fails to retrieve proxy settings for current user which is obvious since service is running under the domain of Local System. To realize the same I have to made the user to logon to the service which I don't want application user to do. I read about SERVICE_USER_OWN_PROCESS parameter which can be passed to CreateService() but neither I found its declaration in WinNT.h nor I am sure if it will work. Development of application is stuck because of this issue. Can anybody please help.
I had similar situation with running a program in the context of the current user.
First of all - somewhere in a global scope - define following variables:
HANDLE hUsrToken;
HANDLE hDupToken;
int sessionId;
You need to get the session Id of the current user:
int getInteractiveSessinoId()
{
PWTS_SESSION_INFO pSessInfo;
ulong count; // Number of current user sessions
int result = -1;
if (!WTSEnumerateSessions(WTS_CURRENT_SERVER, 0, 1, &pSessInfo, &count))
{
printf("Getting session information failed with error %d\n", << GetLastError());
WTSFreeMemory(pSessInfo);
return -2;
}
for (ulong loop = 0; loop < count; loop++)
{
if (pSessInfo[loop].State == WTSActive)
{
printf("Session %d is currently active\n", pSessInfo[loop].SessionId);
result = pSessInfo[loop].SessionId;
break;
}
}
WTSFreeMemory(pSessInfo);
return result;
}
Next you need to impersonate the current user (I called it "attach to the session"):
bool attachToSession(int sessionId)
{
// We need to duplicate the token of the session's user
if (!WTSQueryUserToken(sessionId, &hUsrToken))
{
pritnf("Query the user token failed with error %d\n", GetLastError());
return false;
}
if (!DuplicateTokenEx(hUsrToken, TOKEN_ALL_ACCESS, NULL, SecurityImpersonation, TokenImpersonation , &hDupToken))
{
printf("Duplicating a token failed with error %d\n", GetLastError());
return false;
}
if (!ImpersonateLoggedOnUser(hDupToken))
{
printf("Impersonating the user failed with error %d\n", GetLastError();
return false;
}
return true;
}
Now do whatever you want to do want to do within the current user's context, when done, revert (or "detach") from the user's context:
bool detachFromSession()
{
if (!RevertToSelf())
{
printf("Reverting the token failed with error %d\n", GetLastError());
return false;
}
(void)CloseHandle(hDupToken);
(void)CloseHandle(hUsrToken);
return true;
}
I'm not sure if it is good idea to apply the token to the current (service) thread. I think it is a better idea to create a new thread which executes whatever you want to do in the user's context and apply the impersonated token to it. So your code part may look like this:
HANDLE hUsrToken;
HANDLE hDupToken;
HANDLE hThread;
int sessionId;
DWORD threadId;
DWORD WINAPI MyThreadFunction(LPVOID lpParam)
{
// WinHttpGetIEProxyConfigForCurrentUser(...
}
sessionId = getInterActiveSessionId();
if (attachToSession(int sessionId) == false)
{
// Error handling
return;
}
hThread = CreateThread(NULL, // default security attributes
0, // use default stack size
MyThreadFunction, // thread function name
NULL, // argument to thread function
CREATE_SUSPENDED, // Delay execution
&threadId);
if (SetThreadToken(hThread, hDupToken) == false)
{
// Error handling
return;
}
ResumeThread(hThread);
I cannot garantee that this will resolve your problem, but I hope it does. Good luck!

Get the process handle of a process by image name

I need the simplest way from C using Win32 to get the process handle of another process by its executable file name.
The process I am looking for does not have any registered window classes. I also know that if it is running there will be only one instance of it running.
Use CreateToolhelp32Snapshot, Process32First, and Process32Next to enumerate all of the processes.
Inside the PROCESSENTRY32 you can find a szExeFile member.
You can get the process handle by calling OpenProcess with the process ID th32ProcessID within the same struct.
Once you find a process matching your exe name, you can break out of your loop and obtain the handle.
Note: If you need to enumerate EVERY process no matter what the session is, you should acquire the SE_DEBUG privilege.
At the top of your main call this:
acquirePrivilegeByName(SE_DEBUG_NAME);// SeDebugPrivilege
And here is the definition of acquirePrivilegeByName:
BOOL acquirePrivilegeByName(
const TCHAR *szPrivilegeName)
{
HANDLE htoken;
TOKEN_PRIVILEGES tkp;
DWORD dwerr;
if (szPrivilegeName == NULL)
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
if (!LookupPrivilegeValue(NULL, szPrivilegeName, &(tkp.Privileges[0].Luid)))
return FALSE;
tkp.PrivilegeCount = 1;
tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &htoken))
return FALSE;
if (!AdjustTokenPrivileges(htoken, FALSE, &tkp, 0, NULL, NULL) ||
GetLastError() != ERROR_SUCCESS) // may equal ERROR_NOT_ALL_ASSIGNED
{
dwerr = GetLastError();
CloseHandle(htoken);
SetLastError(dwerr);
return FALSE;
}
CloseHandle(htoken);
SetLastError(ERROR_SUCCESS);
return TRUE;
} //acquirePrivilegeByName()
In addition to what I said above, there is an example on how to use the above Win32 API here.

CreateDesktop() with vista and UAC on (C, windows)

I asked this in CreateDesktop() with Vista UAC (C Windows)
I set a bounty but in trying to vote down the only answer the "accept" was pressed by mistake (i've been awake for more than 48 hs). so I am asking it again.
I'm using CreateDesktop() to create a temporary desktop where an application will run, perform a cleanup action (while remaining out of the way) and terminate. I'm closing that desktop once the application is gone. Everything is fine when using Windows XP and even Vista. The problem arises when you enable the (annoying) UAC.
Everything is OK when you create a desktop, but when you call CreateProcess() to open a program on that desktop it causes the opened application to crash with an exception on User32.dll.
I've been reading a lot about the different desktops and layers on Windows and the restrictions of memory. However, most of the programs I open (as test scenarios) are OK, but a few (like IE, Notepad, Calc and my own application) cause the crash.
Anyone has any idea why this happen on Vista with UAC, or more specifically for those specific programs? and how to fix this?
Anyone has a good solid example on how to create a desktop and open an application there without switching to it under Vista with UAC on?
Code is appreciated.
Thanks
The code used is
SECURITY_ATTRIBUTES sa;
HDESK dOld;
HDESK dNew;
BOOL switchdesk, switchdesk2, closedesk;
int AppPid;
sa.bInheritHandle = TRUE;
sa.lpSecurityDescriptor = NULL;
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
//Get handle to current desktop
dOld = OpenDesktopA("default", 0, TRUE, DESKTOP_SWITCHDESKTOP|
DESKTOP_WRITEOBJECTS|
DESKTOP_READOBJECTS|
DESKTOP_ENUMERATE|
DESKTOP_CREATEWINDOW|
DESKTOP_CREATEMENU);
if(!dOld)
{
printf("Failed to get current desktop handle !!\n\n");
return 0;
}
//Make a new desktop
dNew = CreateDesktopA("kaka", 0, 0, 0, DESKTOP_SWITCHDESKTOP|
DESKTOP_WRITEOBJECTS|
DESKTOP_READOBJECTS|
DESKTOP_ENUMERATE|
DESKTOP_CREATEWINDOW|
DESKTOP_CREATEMENU, &sa);
if(!dNew)
{
printf("Failed to create new desktop !!\n\n");
return 0;
}
AppPid = PerformOpenApp(SomeAppPath);
if(AppPid == 0)
{
printf("failed to open app, err = %d\n", GetLastError());
}
else
{
printf("App pid = %d\n", AppPid);
}
closedesk = CloseDesktop(dNew);
if(!closedesk)
{
printf("Failed to close new desktop !!\n\n");
return 0;
}
return 0;
The correct solution is given as a short comment by ChristianWimmer above:
The desktop must have a security descriptor that allows access to lower integrity level like IE has. Otherwise the GUI cannot access the desktop. – ChristianWimmer Jul 22 '10 at 17:00
Since the answer is a little bit hidden and there's no source code example, let me state it clearly here:
If IE runs in protected mode then the browser tabs are created as low integrity processes. The low integrity tab process will fail to initialize if the desktop does not have a low integrity mandatory label.
As a consequence, the main IE process terminates, too. An interesting observation is that if you start IE providing a command line URL from the secure zone, then IE will succeed to start, because protected mode is disabled by default for the secure zone.
I checked the integrity level of the default desktop, and indeed I was able to verify that the default desktop has a low integrity level! So the easiest solution to the problem is to (1) create the new desktop, (2) get the mandatory label from the default desktop, and (3) copy it into the new desktop. For (2) and (3), you can use the following code
PACL pSacl;
PSECURITY_DESCRIPTOR pSecurityDescriptor;
DWORD dwResult;
dwResult = GetSecurityInfo(hDefaultDesktop, SE_WINDOW_OBJECT, LABEL_SECURITY_INFORMATION, NULL, NULL, NULL, &pSacl, &pSecurityDescriptor);
if (dwResult == ERROR_SUCCESS) {
if (pSacl != NULL) {
dwResult = SetSecurityInfo(hNewDesktop, SE_WINDOW_OBJECT, LABEL_SECURITY_INFORMATION, NULL, NULL, NULL, pSacl);
if (dwResult != ERROR_SUCCESS)
_tprintf(_T("SetSecurityInfo(hNewDesktop) failed, error = %d"), dwResult);
}
LocalFree(pSecurityDescriptor);
} else {
_tprintf(_T("GetSecurityInfo(hDefaultDesktop) failed, error = %d"), dwResult);
}
#CristianWimmer: Thanks for providing the hint to the correct solution. This saved my a lot of time!!
You appear to have come across a bug in IE as it interacts with UAC. If protected mode is set to on you cannot run IE as an ordinary user in any desktop except the default one. In order to run IE in an alternate desktop you must be running as administrator or have protected mode set to off. This is true for Vista, W2K8 and Win7.
As to the other programs that you cannot run, unfortunately I can't confirm anything. I tried upwards of thirty different programs including notepad, calc, all the office apps, visual studio 2005, 2008 and 2010, MSDN help and a number of others and all worked as expected with the noted exception of IE. Is there something truly unusual about your app that might make it behave in an unexpected manner?
One note - if you attempt to run an application like this that needs elevation (such as regedit, etc.) it will fail in CreateProcess with the last error set to ERROR_ELEVATION_REQUIRED.
For your reference, in case I'm doing something different from you, the code I used is:
#ifndef _WIN32_WINNT // Specifies that the minimum required platform is Windows Vista.
#define _WIN32_WINNT 0x0600 // Change this to the appropriate value to target other versions of Windows.
#endif
#include <stdio.h>
#include <tchar.h>
#include "windows.h"
HANDLE PerformOpenApp(TCHAR* appPath);
int _tmain(int argc, _TCHAR* argv[])
{
HDESK dNew;
BOOL closedesk;
HANDLE hApp;
//Make a new desktop
dNew = CreateDesktop(_T("kaka"), 0, 0, 0, DESKTOP_SWITCHDESKTOP|
DESKTOP_WRITEOBJECTS|
DESKTOP_READOBJECTS|
DESKTOP_ENUMERATE|
DESKTOP_CREATEWINDOW|
DESKTOP_CREATEMENU, NULL);
if(!dNew)
{
_tprintf(_T("Failed to create new desktop !!\n\n"));
return 0;
}
TCHAR path[MAX_PATH];
_putts(_T("Enter the path of a program to run in the new desktop:\n"));
_getts(path);
while(_tcslen(path) > 0)
{
hApp = PerformOpenApp(path);
if(hApp == 0)
{
_tprintf(_T("Failed to open app, err = %d\n"), GetLastError());
}
else
{
_tprintf(_T("App pid = %d\n"), GetProcessId(hApp));
_putts(_T("Press any key to close the app.\n"));
_gettchar();
TerminateProcess(hApp, 0);
CloseHandle(hApp);
}
_putts(_T("Enter the path of a program to run in the new desktop:\n"));
_getts(path);
}
closedesk = CloseDesktop(dNew);
if(!closedesk)
{
_tprintf(_T("Failed to close new desktop !!\n\n"));
return 0;
}
return 0;
}
HANDLE PerformOpenApp(TCHAR* appPath)
{
STARTUPINFO si = {0};
PROCESS_INFORMATION pi;
si.cb = sizeof(si);
si.lpDesktop = _T("kaka");
BOOL retVal = CreateProcess(NULL, appPath, NULL, NULL, FALSE, CREATE_NEW_CONSOLE, NULL,
NULL, &si, &pi);
if (retVal)
{
CloseHandle(pi.hThread);
}
return pi.hProcess;
}

Resources