smbdotconf: finally remove unused "client use spnego principal" option
[Samba.git] / examples / winexe / winexesvc.c
blob3d2ebcce149379e22143cb1295ee3812ae337c21
1 /*
2 * Copyright (C) Andrzej Hajda 2009-2013
3 * Contact: andrzej.hajda@wp.pl
5 * Source of this file: https://git.code.sf.net/p/winexe/winexe-waf
6 * commit b787d2a2c4b1abc3653bad10aec943b8efcd7aab.
8 * ** NOTE! The following "GPLv3 only" license applies to the winexe
9 * ** service files. This does NOT imply that all of Samba is released
10 * ** under the "GPLv3 only" license.
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * version 3 as published by the Free Software Foundation.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, see <http://www.gnu.org/licenses/>.
25 #include <windows.h>
26 #include <aclapi.h>
27 #include <userenv.h>
29 #include <stdio.h>
30 #include <string.h>
31 #include <stdarg.h>
32 #include <stdlib.h>
34 #include "winexesvc.h"
36 #define BUFSIZE 256
38 #if 0
39 #define dbg(arg...) \
40 ({\
41 FILE *f = fopen("C:\\" SERVICE_NAME ".log", "at");\
42 if (f) {\
43 fprintf(f, arg);\
44 fclose(f);\
47 #else
48 #define dbg(arg...)
49 #endif
51 static SECURITY_ATTRIBUTES sa;
53 /* Creates SECURITY_ATTRIBUTES sa with full access for BUILTIN\Administrators */
54 static int CreatePipesSA()
56 DWORD dwRes;
57 PSID pAdminSID = NULL;
58 PACL pACL = NULL;
59 PSECURITY_DESCRIPTOR pSD = NULL;
60 EXPLICIT_ACCESS ea;
61 SID_IDENTIFIER_AUTHORITY SIDAuthNT = {SECURITY_NT_AUTHORITY};
63 /* Create a SID for the BUILTIN\Administrators group. */
64 if (
65 !AllocateAndInitializeSid(
66 &SIDAuthNT, 2,
67 SECURITY_BUILTIN_DOMAIN_RID,
68 DOMAIN_ALIAS_RID_ADMINS,
69 0, 0, 0, 0, 0, 0, &pAdminSID
71 ) {
72 dbg("AllocateAndInitializeSid Error %lu\n", GetLastError());
73 return 0;
75 /* Initialize an EXPLICIT_ACCESS structure for an ACE.
76 The ACE will allow the Administrators group full access to the key.
78 ea.grfAccessPermissions = FILE_ALL_ACCESS;
79 ea.grfAccessMode = SET_ACCESS;
80 ea.grfInheritance = NO_INHERITANCE;
81 ea.Trustee.TrusteeForm = TRUSTEE_IS_SID;
82 ea.Trustee.TrusteeType = TRUSTEE_IS_GROUP;
83 ea.Trustee.ptstrName = (LPTSTR) pAdminSID;
85 /* Create a new ACL that contains the new ACEs */
86 dwRes = SetEntriesInAcl(1, &ea, NULL, &pACL);
87 if (ERROR_SUCCESS != dwRes) {
88 dbg("SetEntriesInAcl Error %lu\n", GetLastError());
89 return 0;
91 /* Initialize a security descriptor */
92 pSD = (PSECURITY_DESCRIPTOR) LocalAlloc(LPTR, SECURITY_DESCRIPTOR_MIN_LENGTH);
93 if (NULL == pSD) {
94 dbg("LocalAlloc Error %lu\n", GetLastError());
95 return 0;
98 if (!InitializeSecurityDescriptor(pSD, SECURITY_DESCRIPTOR_REVISION))
100 dbg("InitializeSecurityDescriptor Error %lu\n", GetLastError());
101 return 0;
103 /* Add the ACL to the security descriptor */
104 if (
105 !SetSecurityDescriptorDacl(
106 pSD, TRUE, /* bDaclPresent flag */
107 pACL, FALSE /* not a default DACL */
110 dbg("SetSecurityDescriptorDacl Error %lu\n", GetLastError());
111 return 0;
113 /* Initialize a security attributes structure */
114 sa.nLength = sizeof(SECURITY_ATTRIBUTES);
115 sa.lpSecurityDescriptor = pSD;
116 sa.bInheritHandle = FALSE;
117 return 1;
120 typedef struct {
121 HANDLE h;
122 OVERLAPPED o;
123 } OV_HANDLE;
125 static int hgets(char *str, int n, OV_HANDLE *pipe)
127 DWORD res;
128 DWORD count = 0;
129 --n;
130 while (--n >= 0) {
131 if (!ReadFile(pipe->h, str, 1, NULL, &pipe->o) && GetLastError() != ERROR_IO_PENDING)
132 goto finish;
133 if (!GetOverlappedResult(pipe->h, &pipe->o, &res, TRUE) || !res)
134 goto finish;
135 if (*str == '\n')
136 goto finish;
137 ++count;
138 ++str;
140 finish:
141 *str = 0;
142 return count;
145 static int hprintf(OV_HANDLE *pipe, const char *fmt, ...)
147 int res;
148 char buf[1024];
149 va_list ap;
150 va_start(ap, fmt);
151 vsnprintf(buf, sizeof(buf), fmt, ap);
152 va_end(ap);
153 if (!WriteFile(pipe->h, buf, strlen(buf), NULL, &pipe->o) && GetLastError() == ERROR_IO_PENDING)
154 GetOverlappedResult(pipe->h, &pipe->o, (LPDWORD)&res, TRUE);
155 FlushFileBuffers(pipe->h);
156 return res;
159 typedef struct {
160 OV_HANDLE *pipe;
161 const char *cmd;
162 HANDLE pin;
163 HANDLE pout;
164 HANDLE perr;
165 HANDLE token;
166 int implevel;
167 int system;
168 int profile;
169 char *runas;
170 int conn_number;
171 } connection_context;
173 typedef int CMD_FUNC(connection_context *);
175 typedef struct {
176 const char *name;
177 CMD_FUNC *func;
178 } CMD_ITEM;
180 static int cmd_set(connection_context *c)
182 static const char* var_system = "system";
183 static const char* var_implevel = "implevel";
184 static const char* var_runas = "runas";
185 static const char* var_profile = "profile";
186 char *cmdline;
187 int res = 0;
189 cmdline = strchr(c->cmd, ' ');
190 if (!cmdline) {
191 goto finish;
193 ++cmdline;
194 int l;
195 if ((strstr(cmdline, var_system) == cmdline) && (cmdline[l = strlen(var_system)] == ' ')) {
196 c->system = atoi(cmdline + l + 1);
197 } else if ((strstr(cmdline, var_implevel) == cmdline) && (cmdline[l = strlen(var_implevel)] == ' ')) {
198 c->implevel = atoi(cmdline + l + 1);
199 } else if ((strstr(cmdline, var_profile) == cmdline) && (cmdline[l = strlen(var_profile)] == ' ')) {
200 c->profile = atoi(cmdline + l + 1);
201 } else if ((strstr(cmdline, var_runas) == cmdline) && (cmdline[l = strlen(var_runas)] == ' ')) {
202 c->runas = strdup(cmdline + l + 1);
203 } else {
204 hprintf(c->pipe, "error Unknown command (%s)\n", c->cmd);
205 goto finish;
207 res = 1;
208 finish:
209 return res;
212 static int cmd_get(connection_context *c)
214 static const char* var_version = "version";
215 static const char* var_codepage = "codepage";
216 char *cmdline;
217 int res = 0;
219 cmdline = strchr(c->cmd, ' ');
220 if (!cmdline) {
221 goto finish;
223 ++cmdline;
224 int l;
225 if ((strstr(cmdline, var_version) == cmdline)
226 && (cmdline[l = strlen(var_version)] == 0)) {
227 hprintf(c->pipe, "version 0x%04X\n", VERSION);
228 } else if ((strstr(cmdline, var_codepage) == cmdline)
229 && (cmdline[l = strlen(var_codepage)] == 0)) {
230 hprintf(c->pipe, "codepage %d\n", GetOEMCP());
231 } else {
232 hprintf(c->pipe, "error Unknown argument (%s)\n", c->cmd);
233 goto finish;
235 res = 1;
236 finish:
237 return res;
240 typedef struct {
241 char *user;
242 char *domain;
243 char *password;
244 } credentials;
246 static int prepare_credentials(char *str, credentials *crd)
248 char *p;
249 p = strchr(str, '/');
250 if (!p) p = strchr(str, '\\');
251 if (p) {
252 *p++ = 0;
253 crd->domain = str;
254 } else {
255 p = str;
256 crd->domain = ".";
258 crd->user = p;
259 p = strchr(p, '%');
260 if (p)
261 *p++ = 0;
262 crd->password = p;
263 return 1;
266 static int get_token(connection_context *c)
268 int res = 0;
269 int wres;
270 HANDLE token;
272 if (c->runas) {
273 credentials crd;
274 if (!prepare_credentials(c->runas, &crd)) {
275 hprintf(c->pipe, "error Incorrect runas credentials\n");
276 goto finish;
278 wres = LogonUser(crd.user, crd.domain, crd.password, LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, &c->token);
279 if (!wres) {
280 hprintf(c->pipe, "error Cannot LogonUser(%s,%s,%s) %d\n",
281 crd.user, crd.domain, crd.password, GetLastError());
282 goto finish;
284 res = 1;
285 goto finish;
286 } else if (c->system) {
287 if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &token)) {
288 hprintf(c->pipe, "error Cannot OpenProcessToken %d\n", GetLastError());
289 goto finish;
291 } else {
292 if (!ImpersonateNamedPipeClient(c->pipe->h)) {
293 hprintf(c->pipe, "error Cannot ImpersonateNamedPipeClient %d\n", GetLastError());
294 goto finish;
296 if (!OpenThreadToken(GetCurrentThread(), TOKEN_ALL_ACCESS, FALSE, &token)) {
297 hprintf(c->pipe, "error Cannot OpenThreadToken %d\n", GetLastError());
298 goto finishRevertToSelf;
301 if (!DuplicateTokenEx(token, MAXIMUM_ALLOWED, 0, c->implevel, TokenPrimary, &c->token)) {
302 hprintf(c->pipe, "error Cannot Duplicate Token %d\n", GetLastError());
303 goto finishCloseToken;
305 res = 1;
306 finishCloseToken:
307 CloseHandle(token);
308 finishRevertToSelf:
309 if (!c->system) {
310 if (!RevertToSelf()) {
311 hprintf(c->pipe, "error Cannot RevertToSelf %d\n", GetLastError());
312 res = 0;
315 finish:
316 return res;
319 static int load_user_profile(connection_context *c)
321 PROFILEINFO pi = { .dwSize = sizeof(PROFILEINFO) };
322 DWORD ulen = 256;
323 TCHAR username[ulen];
325 GetUserName(username, &ulen);
326 pi.lpUserName = username;
328 return LoadUserProfile(c->token, &pi);
331 static int cmd_run(connection_context *c)
333 char buf[256];
334 int res = 0;
335 char *cmdline;
336 DWORD pipe_nr;
338 cmdline = strchr(c->cmd, ' ');
339 if (!cmdline) {
340 goto finish;
342 ++cmdline;
344 if (!get_token(c))
345 return 0;
347 pipe_nr = (GetCurrentProcessId() << 16) + (DWORD) c->conn_number;
349 sprintf(buf, "\\\\.\\pipe\\" PIPE_NAME_IN, (unsigned int) pipe_nr);
350 c->pin = CreateNamedPipe(buf,
351 PIPE_ACCESS_DUPLEX,
352 PIPE_WAIT,
354 BUFSIZE,
355 BUFSIZE,
356 NMPWAIT_USE_DEFAULT_WAIT,
357 &sa);
358 if (c->pin == INVALID_HANDLE_VALUE) {
359 hprintf(c->pipe, "error Cannot create in pipe(%s), error 0x%08X\n", buf, GetLastError());
360 goto finishCloseToken;
363 sprintf(buf, "\\\\.\\pipe\\" PIPE_NAME_OUT, (unsigned int) pipe_nr);
364 c->pout = CreateNamedPipe(buf,
365 PIPE_ACCESS_DUPLEX,
366 PIPE_WAIT,
368 BUFSIZE,
369 BUFSIZE,
370 NMPWAIT_USE_DEFAULT_WAIT,
371 &sa);
372 if (c->pout == INVALID_HANDLE_VALUE) {
373 hprintf(c->pipe, "error Cannot create out pipe(%s), error 0x%08X\n", buf, GetLastError());
374 goto finishClosePin;
377 sprintf(buf, "\\\\.\\pipe\\" PIPE_NAME_ERR, (unsigned int) pipe_nr);
378 c->perr = CreateNamedPipe(buf,
379 PIPE_ACCESS_DUPLEX,
380 PIPE_WAIT,
382 BUFSIZE,
383 BUFSIZE,
384 NMPWAIT_USE_DEFAULT_WAIT,
385 &sa);
386 if (c->perr == INVALID_HANDLE_VALUE) {
387 hprintf(c->pipe, "error Cannot create err pipe(%s), error 0x%08x\n", buf, GetLastError());
388 goto finishClosePout;
391 /* Send handle to client (it will use it to connect pipes) */
392 hprintf(c->pipe, CMD_STD_IO_ERR " %08X\n", pipe_nr);
394 HANDLE ph[] = { c->pin, c->pout, c->perr };
395 int i;
397 for (i = 0; i < 3; ++i) {
398 if (ConnectNamedPipe(ph[i], NULL))
399 continue;
400 int err = GetLastError();
401 if (err != ERROR_PIPE_CONNECTED) {
402 hprintf(c->pipe, "error ConnectNamedPipe(pin) %d\n", err);
403 while (--i >= 0)
404 DisconnectNamedPipe(ph[i]);
405 goto finishClosePerr;
409 SetHandleInformation(c->pin, HANDLE_FLAG_INHERIT, 1);
410 SetHandleInformation(c->pout, HANDLE_FLAG_INHERIT, 1);
411 SetHandleInformation(c->perr, HANDLE_FLAG_INHERIT, 1);
413 if (c->profile)
414 load_user_profile(c);
416 PROCESS_INFORMATION pi;
417 ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
419 STARTUPINFO si;
420 ZeroMemory(&si, sizeof(STARTUPINFO));
421 si.cb = sizeof(STARTUPINFO);
422 si.hStdInput = c->pin;
423 si.hStdOutput = c->pout;
424 si.hStdError = c->perr;
425 si.dwFlags |= STARTF_USESTDHANDLES;
427 if (CreateProcessAsUser(
428 c->token,
429 NULL,
430 cmdline, /* command line */
431 NULL, /* process security attributes */
432 NULL, /* primary thread security attributes */
433 TRUE, /* handles are inherited */
434 0, /* creation flags */
435 NULL, /* use parent's environment */
436 NULL, /* use parent's current directory */
437 &si, /* STARTUPINFO pointer */
438 &pi) /* receives PROCESS_INFORMATION */
440 HANDLE hlist[2] = {c->pipe->o.hEvent, pi.hProcess};
441 DWORD ec;
442 char str[1];
444 if (!ResetEvent(c->pipe->o.hEvent))
445 dbg("ResetEvent error - %lu\n", GetLastError());
446 if (!ReadFile(c->pipe->h, str, 1, NULL, &c->pipe->o) && GetLastError() != ERROR_IO_PENDING)
447 dbg("ReadFile(control_pipe) error - %lu\n", GetLastError());
448 ec = WaitForMultipleObjects(2, hlist, FALSE, INFINITE);
449 dbg("WaitForMultipleObjects=%lu\n", ec - WAIT_OBJECT_0);
450 if (ec != WAIT_OBJECT_0)
451 GetExitCodeProcess(pi.hProcess, &ec);
452 else
453 TerminateProcess(pi.hProcess, ec = 0x1234);
454 FlushFileBuffers(c->pout);
455 FlushFileBuffers(c->perr);
456 CloseHandle(pi.hProcess);
457 CloseHandle(pi.hThread);
458 hprintf(c->pipe, CMD_RETURN_CODE " %08X\n", ec);
459 } else {
460 hprintf(c->pipe, "error Creating process(%s) %d\n", cmdline, GetLastError());
463 DisconnectNamedPipe(c->perr);
464 DisconnectNamedPipe(c->pout);
465 DisconnectNamedPipe(c->pin);
466 finishClosePerr:
467 CloseHandle(c->perr);
468 finishClosePout:
469 CloseHandle(c->pout);
470 finishClosePin:
471 CloseHandle(c->pin);
472 finishCloseToken:
473 CloseHandle(c->token);
474 finish:
475 return res;
478 static CMD_ITEM cmd_table[] = {
479 {"run", cmd_run},
480 {"set", cmd_set},
481 {"get", cmd_get},
482 {NULL, NULL}
485 typedef struct {
486 OV_HANDLE *pipe;
487 int conn_number;
488 } connection_data;
490 #define MAX_COMMAND_LENGTH (32768)
492 static VOID handle_connection(connection_data *data)
494 char *cmd = 0;
495 int res;
496 connection_context _c, *c = &_c;
497 cmd = malloc(MAX_COMMAND_LENGTH);
498 if (!cmd) {
499 hprintf(data->pipe,
500 "error: unable to allocate buffer for command\n");
501 return;
503 ZeroMemory(cmd, MAX_COMMAND_LENGTH);
504 ZeroMemory(c, sizeof(connection_context));
505 c->pipe = data->pipe;
506 c->cmd = cmd;
507 c->conn_number = data->conn_number;
508 free(data);
509 /* FIXME make wait for end of process or ctrl_pipe input */
510 while (1) {
511 res = hgets(cmd, MAX_COMMAND_LENGTH, c->pipe);
512 if (res <= 0) {
513 dbg("Error reading from pipe(%p)\n", c->pipe->h);
514 goto finish;
516 dbg("Retrieved line: \"%s\"\n", cmd);
517 CMD_ITEM *ci;
518 for (ci = cmd_table; ci->name; ++ci) {
519 if (strstr(cmd, ci->name) != cmd)
520 continue;
521 char c = cmd[strlen(ci->name)];
522 if (!c || (c == ' '))
523 break;
525 if (ci->name) {
526 if (!ci->func(c))
527 goto finish;
528 } else {
529 hprintf(c->pipe, "error Ignoring unknown command (%s)\n", cmd);
532 finish:
533 FlushFileBuffers(c->pipe->h);
534 DisconnectNamedPipe(c->pipe->h);
535 CloseHandle(c->pipe->h);
536 CloseHandle(c->pipe->o.hEvent);
537 free(c->pipe);
538 free(cmd);
541 static int conn_number = 0;
543 DWORD WINAPI winexesvc_loop(LPVOID lpParameter)
545 BOOL res;
547 dbg("server_loop: alive\n");
548 if (!CreatePipesSA()) {
549 dbg("CreatePipesSA failed (%08lX)\n", GetLastError());
550 return -1;
552 dbg("server_loop: CreatePipesSA done\n");
553 for (;;) {
554 dbg("server_loop: Create Pipe\n");
555 OV_HANDLE *pipe;
556 pipe = (OV_HANDLE *)malloc(sizeof(OV_HANDLE));
557 ZeroMemory(&pipe->o, sizeof(OVERLAPPED));
558 pipe->o.hEvent = CreateEvent(NULL, TRUE, TRUE, NULL);
559 pipe->h = CreateNamedPipe("\\\\.\\pipe\\" PIPE_NAME,
560 PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
561 PIPE_WAIT,
562 PIPE_UNLIMITED_INSTANCES,
563 BUFSIZE,
564 BUFSIZE,
565 NMPWAIT_USE_DEFAULT_WAIT,
566 &sa);
567 if (pipe->h == INVALID_HANDLE_VALUE) {
568 dbg("CreatePipe failed(%08lX)\n",
569 GetLastError());
570 CloseHandle(pipe->o.hEvent);
571 free(pipe);
572 return 0;
575 dbg("server_loop: Connect Pipe\n");
576 if (ConnectNamedPipe(pipe->h, &pipe->o)) {
577 dbg("server_loop: Connect Pipe err %08lX\n", GetLastError());
578 res = FALSE;
579 } else {
580 switch (GetLastError()) {
581 case ERROR_IO_PENDING:
582 dbg("server_loop: Connect Pipe(0) pending\n");
583 DWORD t;
584 res = GetOverlappedResult(pipe->h, &pipe->o, &t, TRUE);
585 break;
586 case ERROR_PIPE_CONNECTED:
587 dbg("server_loop: Connect Pipe(0) connected\n");
588 res = TRUE;
589 break;
590 default:
591 dbg("server_loop: Connect Pipe(0) err %08lX\n", GetLastError());
592 res = FALSE;
596 if (res) {
597 connection_data *cd = malloc(sizeof(connection_data));
598 cd->pipe = pipe;
599 cd->conn_number = ++conn_number;
600 dbg("server_loop: CreateThread\n");
601 HANDLE th = CreateThread(NULL, /* no security attribute */
602 0, /* default stack size */
603 (LPTHREAD_START_ROUTINE)
604 handle_connection,
605 (LPVOID) cd, /* thread parameter */
606 0, /* not suspended */
607 NULL); /* returns thread ID */
608 if (!th) {
609 dbg("Cannot create thread\n");
610 CloseHandle(pipe->h);
611 CloseHandle(pipe->o.hEvent);
612 free(pipe);
613 } else {
614 CloseHandle(th);
615 dbg("server_loop: Thread created\n");
617 } else {
618 dbg("server_loop: Pipe not connected\n");
619 CloseHandle(pipe->h);
620 CloseHandle(pipe->o.hEvent);
621 free(pipe);
624 dbg("server_loop: STH wrong\n");
625 return 0;
628 static SERVICE_STATUS winexesvcStatus;
629 static SERVICE_STATUS_HANDLE winexesvcStatusHandle;
631 static VOID WINAPI winexesvcCtrlHandler(DWORD Opcode)
633 switch (Opcode) {
634 case SERVICE_CONTROL_PAUSE:
635 dbg(SERVICE_NAME ": winexesvcCtrlHandler: pause\n", 0);
636 winexesvcStatus.dwCurrentState = SERVICE_PAUSED;
637 break;
639 case SERVICE_CONTROL_CONTINUE:
640 dbg(SERVICE_NAME ": winexesvcCtrlHandler: continue\n", 0);
641 winexesvcStatus.dwCurrentState = SERVICE_RUNNING;
642 break;
644 case SERVICE_CONTROL_STOP:
645 dbg(SERVICE_NAME ": winexesvcCtrlHandler: stop\n", 0);
646 winexesvcStatus.dwWin32ExitCode = 0;
647 winexesvcStatus.dwCurrentState = SERVICE_STOPPED;
648 winexesvcStatus.dwCheckPoint = 0;
649 winexesvcStatus.dwWaitHint = 0;
651 if (!SetServiceStatus (winexesvcStatusHandle, &winexesvcStatus))
652 dbg(SERVICE_NAME ": SetServiceStatus error %ld\n", GetLastError());
654 dbg(SERVICE_NAME ": Leaving winexesvc\n", 0);
655 return;
657 case SERVICE_CONTROL_INTERROGATE:
658 dbg(SERVICE_NAME ": winexesvcCtrlHandler: interrogate\n", 0);
659 break;
661 default:
662 dbg(SERVICE_NAME ": Unrecognized opcode %ld\n", Opcode);
665 if (!SetServiceStatus(winexesvcStatusHandle, &winexesvcStatus))
666 dbg(SERVICE_NAME ": SetServiceStatus error 0x%08X\n", GetLastError());
668 return;
671 static DWORD winexesvcInitialization(DWORD argc, LPTSTR * argv, DWORD * specificError)
673 HANDLE th = CreateThread(NULL, 0, winexesvc_loop, NULL, 0, NULL);
674 if (th) {
675 CloseHandle(th);
676 return NO_ERROR;
678 return !NO_ERROR;
681 static void WINAPI winexesvcStart(DWORD argc, LPTSTR * argv)
683 DWORD status;
684 DWORD specificError;
686 winexesvcStatus.dwServiceType = SERVICE_WIN32;
687 winexesvcStatus.dwCurrentState = SERVICE_START_PENDING;
688 winexesvcStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_PAUSE_CONTINUE;
689 winexesvcStatus.dwWin32ExitCode = 0;
690 winexesvcStatus.dwServiceSpecificExitCode = 0;
691 winexesvcStatus.dwCheckPoint = 0;
692 winexesvcStatus.dwWaitHint = 0;
694 dbg(SERVICE_NAME ": RegisterServiceCtrlHandler\n", 0);
696 winexesvcStatusHandle = RegisterServiceCtrlHandler(SERVICE_NAME, winexesvcCtrlHandler);
698 if (winexesvcStatusHandle == (SERVICE_STATUS_HANDLE) 0) {
699 dbg(SERVICE_NAME
700 ": RegisterServiceCtrlHandler failed %d\n",
701 GetLastError());
702 return;
704 status = winexesvcInitialization(argc, argv, &specificError);
706 if (status != NO_ERROR) {
707 winexesvcStatus.dwCurrentState = SERVICE_STOPPED;
708 winexesvcStatus.dwCheckPoint = 0;
709 winexesvcStatus.dwWaitHint = 0;
710 winexesvcStatus.dwWin32ExitCode = status;
711 winexesvcStatus.dwServiceSpecificExitCode = specificError;
713 SetServiceStatus(winexesvcStatusHandle, &winexesvcStatus);
714 return;
717 winexesvcStatus.dwCurrentState = SERVICE_RUNNING;
718 winexesvcStatus.dwCheckPoint = 0;
719 winexesvcStatus.dwWaitHint = 0;
721 if (!SetServiceStatus(winexesvcStatusHandle, &winexesvcStatus)) {
722 status = GetLastError();
723 dbg(SERVICE_NAME ": SetServiceStatus error %ld\n", status);
726 dbg(SERVICE_NAME ": Returning the Main Thread \n", 0);
728 return;
731 int main(int argc, char *argv[])
733 SERVICE_TABLE_ENTRY DispatchTable[] = {
734 {SERVICE_NAME, winexesvcStart},
735 {NULL, NULL}
738 dbg(SERVICE_NAME ": StartServiceCtrlDispatcher %d\n", GetLastError());
739 if (!StartServiceCtrlDispatcher(DispatchTable)) {
740 dbg(SERVICE_NAME
741 ": StartServiceCtrlDispatcher (%d)\n",
742 GetLastError());
744 return 0;