mirror of
https://github.com/samba-team/samba.git
synced 2024-12-23 17:34:34 +03:00
1ba146dda3
Signed-off-by: Andreas Schneider <asn@samba.org> Reviewed-by: Rowland Penny <rpenny@samba.org>
746 lines
20 KiB
C
746 lines
20 KiB
C
/*
|
|
* Copyright (C) Andrzej Hajda 2009-2013
|
|
* Contact: andrzej.hajda@wp.pl
|
|
*
|
|
* Source of this file: https://git.code.sf.net/p/winexe/winexe-waf
|
|
* commit b787d2a2c4b1abc3653bad10aec943b8efcd7aab.
|
|
*
|
|
* ** NOTE! The following "GPLv3 only" license applies to the winexe
|
|
* ** service files. This does NOT imply that all of Samba is released
|
|
* ** under the "GPLv3 only" license.
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License
|
|
* version 3 as published by the Free Software Foundation.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include <windows.h>
|
|
#include <aclapi.h>
|
|
#include <userenv.h>
|
|
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <stdarg.h>
|
|
#include <stdlib.h>
|
|
|
|
#include "winexesvc.h"
|
|
|
|
#define BUFSIZE 256
|
|
|
|
#if 0
|
|
#define dbg(arg...) \
|
|
({\
|
|
FILE *f = fopen("C:\\" SERVICE_NAME ".log", "at");\
|
|
if (f) {\
|
|
fprintf(f, arg);\
|
|
fclose(f);\
|
|
}\
|
|
})
|
|
#else
|
|
#define dbg(arg...)
|
|
#endif
|
|
|
|
static SECURITY_ATTRIBUTES sa;
|
|
|
|
/* Creates SECURITY_ATTRIBUTES sa with full access for BUILTIN\Administrators */
|
|
static int CreatePipesSA()
|
|
{
|
|
DWORD dwRes;
|
|
PSID pAdminSID = NULL;
|
|
PACL pACL = NULL;
|
|
PSECURITY_DESCRIPTOR pSD = NULL;
|
|
EXPLICIT_ACCESS ea;
|
|
SID_IDENTIFIER_AUTHORITY SIDAuthNT = {SECURITY_NT_AUTHORITY};
|
|
|
|
/* Create a SID for the BUILTIN\Administrators group. */
|
|
if (
|
|
!AllocateAndInitializeSid(
|
|
&SIDAuthNT, 2,
|
|
SECURITY_BUILTIN_DOMAIN_RID,
|
|
DOMAIN_ALIAS_RID_ADMINS,
|
|
0, 0, 0, 0, 0, 0, &pAdminSID
|
|
)
|
|
) {
|
|
dbg("AllocateAndInitializeSid Error %lu\n", GetLastError());
|
|
return 0;
|
|
}
|
|
/* Initialize an EXPLICIT_ACCESS structure for an ACE.
|
|
The ACE will allow the Administrators group full access to the key.
|
|
*/
|
|
ea.grfAccessPermissions = FILE_ALL_ACCESS;
|
|
ea.grfAccessMode = SET_ACCESS;
|
|
ea.grfInheritance = NO_INHERITANCE;
|
|
ea.Trustee.TrusteeForm = TRUSTEE_IS_SID;
|
|
ea.Trustee.TrusteeType = TRUSTEE_IS_GROUP;
|
|
ea.Trustee.ptstrName = (LPTSTR) pAdminSID;
|
|
|
|
/* Create a new ACL that contains the new ACEs */
|
|
dwRes = SetEntriesInAcl(1, &ea, NULL, &pACL);
|
|
if (ERROR_SUCCESS != dwRes) {
|
|
dbg("SetEntriesInAcl Error %lu\n", GetLastError());
|
|
return 0;
|
|
}
|
|
/* Initialize a security descriptor */
|
|
pSD = (PSECURITY_DESCRIPTOR) LocalAlloc(LPTR, SECURITY_DESCRIPTOR_MIN_LENGTH);
|
|
if (NULL == pSD) {
|
|
dbg("LocalAlloc Error %lu\n", GetLastError());
|
|
return 0;
|
|
}
|
|
|
|
if (!InitializeSecurityDescriptor(pSD, SECURITY_DESCRIPTOR_REVISION))
|
|
{
|
|
dbg("InitializeSecurityDescriptor Error %lu\n", GetLastError());
|
|
return 0;
|
|
}
|
|
/* Add the ACL to the security descriptor */
|
|
if (
|
|
!SetSecurityDescriptorDacl(
|
|
pSD, TRUE, /* bDaclPresent flag */
|
|
pACL, FALSE /* not a default DACL */
|
|
)
|
|
) {
|
|
dbg("SetSecurityDescriptorDacl Error %lu\n", GetLastError());
|
|
return 0;
|
|
}
|
|
/* Initialize a security attributes structure */
|
|
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
|
|
sa.lpSecurityDescriptor = pSD;
|
|
sa.bInheritHandle = FALSE;
|
|
return 1;
|
|
}
|
|
|
|
typedef struct {
|
|
HANDLE h;
|
|
OVERLAPPED o;
|
|
} OV_HANDLE;
|
|
|
|
static int hgets(char *str, int n, OV_HANDLE *pipe)
|
|
{
|
|
DWORD res;
|
|
DWORD count = 0;
|
|
--n;
|
|
while (--n >= 0) {
|
|
if (!ReadFile(pipe->h, str, 1, NULL, &pipe->o) && GetLastError() != ERROR_IO_PENDING)
|
|
goto finish;
|
|
if (!GetOverlappedResult(pipe->h, &pipe->o, &res, TRUE) || !res)
|
|
goto finish;
|
|
if (*str == '\n')
|
|
goto finish;
|
|
++count;
|
|
++str;
|
|
}
|
|
finish:
|
|
*str = 0;
|
|
return count;
|
|
}
|
|
|
|
static int hprintf(OV_HANDLE *pipe, const char *fmt, ...)
|
|
{
|
|
int res;
|
|
char buf[1024];
|
|
va_list ap;
|
|
va_start(ap, fmt);
|
|
vsnprintf(buf, sizeof(buf), fmt, ap);
|
|
va_end(ap);
|
|
if (!WriteFile(pipe->h, buf, strlen(buf), NULL, &pipe->o) && GetLastError() == ERROR_IO_PENDING)
|
|
GetOverlappedResult(pipe->h, &pipe->o, (LPDWORD)&res, TRUE);
|
|
FlushFileBuffers(pipe->h);
|
|
return res;
|
|
}
|
|
|
|
typedef struct {
|
|
OV_HANDLE *pipe;
|
|
const char *cmd;
|
|
HANDLE pin;
|
|
HANDLE pout;
|
|
HANDLE perr;
|
|
HANDLE token;
|
|
int implevel;
|
|
int system;
|
|
int profile;
|
|
char *runas;
|
|
int conn_number;
|
|
} connection_context;
|
|
|
|
typedef int CMD_FUNC(connection_context *);
|
|
|
|
typedef struct {
|
|
const char *name;
|
|
CMD_FUNC *func;
|
|
} CMD_ITEM;
|
|
|
|
static int cmd_set(connection_context *c)
|
|
{
|
|
static const char* var_system = "system";
|
|
static const char* var_implevel = "implevel";
|
|
static const char* var_runas = "runas";
|
|
static const char* var_profile = "profile";
|
|
char *cmdline;
|
|
int res = 0;
|
|
|
|
cmdline = strchr(c->cmd, ' ');
|
|
if (!cmdline) {
|
|
goto finish;
|
|
}
|
|
++cmdline;
|
|
int l;
|
|
if ((strstr(cmdline, var_system) == cmdline) && (cmdline[l = strlen(var_system)] == ' ')) {
|
|
c->system = atoi(cmdline + l + 1);
|
|
} else if ((strstr(cmdline, var_implevel) == cmdline) && (cmdline[l = strlen(var_implevel)] == ' ')) {
|
|
c->implevel = atoi(cmdline + l + 1);
|
|
} else if ((strstr(cmdline, var_profile) == cmdline) && (cmdline[l = strlen(var_profile)] == ' ')) {
|
|
c->profile = atoi(cmdline + l + 1);
|
|
} else if ((strstr(cmdline, var_runas) == cmdline) && (cmdline[l = strlen(var_runas)] == ' ')) {
|
|
c->runas = strdup(cmdline + l + 1);
|
|
} else {
|
|
hprintf(c->pipe, "error Unknown command (%s)\n", c->cmd);
|
|
goto finish;
|
|
}
|
|
res = 1;
|
|
finish:
|
|
return res;
|
|
}
|
|
|
|
static int cmd_get(connection_context *c)
|
|
{
|
|
static const char* var_version = "version";
|
|
static const char* var_codepage = "codepage";
|
|
char *cmdline;
|
|
int res = 0;
|
|
|
|
cmdline = strchr(c->cmd, ' ');
|
|
if (!cmdline) {
|
|
goto finish;
|
|
}
|
|
++cmdline;
|
|
int l;
|
|
if ((strstr(cmdline, var_version) == cmdline)
|
|
&& (cmdline[l = strlen(var_version)] == 0)) {
|
|
hprintf(c->pipe, "version 0x%04X\n", VERSION);
|
|
} else if ((strstr(cmdline, var_codepage) == cmdline)
|
|
&& (cmdline[l = strlen(var_codepage)] == 0)) {
|
|
hprintf(c->pipe, "codepage %d\n", GetOEMCP());
|
|
} else {
|
|
hprintf(c->pipe, "error Unknown argument (%s)\n", c->cmd);
|
|
goto finish;
|
|
}
|
|
res = 1;
|
|
finish:
|
|
return res;
|
|
}
|
|
|
|
typedef struct {
|
|
char *user;
|
|
char *domain;
|
|
char *password;
|
|
} credentials;
|
|
|
|
static int prepare_credentials(char *str, credentials *crd)
|
|
{
|
|
char *p;
|
|
p = strchr(str, '/');
|
|
if (!p) p = strchr(str, '\\');
|
|
if (p) {
|
|
*p++ = 0;
|
|
crd->domain = str;
|
|
} else {
|
|
p = str;
|
|
crd->domain = ".";
|
|
}
|
|
crd->user = p;
|
|
p = strchr(p, '%');
|
|
if (p)
|
|
*p++ = 0;
|
|
crd->password = p;
|
|
return 1;
|
|
}
|
|
|
|
static int get_token(connection_context *c)
|
|
{
|
|
int res = 0;
|
|
int wres;
|
|
HANDLE token;
|
|
|
|
if (c->runas) {
|
|
credentials crd;
|
|
if (!prepare_credentials(c->runas, &crd)) {
|
|
hprintf(c->pipe, "error Incorrect runas credentials\n");
|
|
goto finish;
|
|
}
|
|
wres = LogonUser(crd.user, crd.domain, crd.password, LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, &c->token);
|
|
if (!wres) {
|
|
hprintf(c->pipe, "error Cannot LogonUser(%s,%s,%s) %d\n",
|
|
crd.user, crd.domain, crd.password, GetLastError());
|
|
goto finish;
|
|
}
|
|
res = 1;
|
|
goto finish;
|
|
} else if (c->system) {
|
|
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &token)) {
|
|
hprintf(c->pipe, "error Cannot OpenProcessToken %d\n", GetLastError());
|
|
goto finish;
|
|
}
|
|
} else {
|
|
if (!ImpersonateNamedPipeClient(c->pipe->h)) {
|
|
hprintf(c->pipe, "error Cannot ImpersonateNamedPipeClient %d\n", GetLastError());
|
|
goto finish;
|
|
}
|
|
if (!OpenThreadToken(GetCurrentThread(), TOKEN_ALL_ACCESS, FALSE, &token)) {
|
|
hprintf(c->pipe, "error Cannot OpenThreadToken %d\n", GetLastError());
|
|
goto finishRevertToSelf;
|
|
}
|
|
}
|
|
if (!DuplicateTokenEx(token, MAXIMUM_ALLOWED, 0, c->implevel, TokenPrimary, &c->token)) {
|
|
hprintf(c->pipe, "error Cannot Duplicate Token %d\n", GetLastError());
|
|
goto finishCloseToken;
|
|
}
|
|
res = 1;
|
|
finishCloseToken:
|
|
CloseHandle(token);
|
|
finishRevertToSelf:
|
|
if (!c->system) {
|
|
if (!RevertToSelf()) {
|
|
hprintf(c->pipe, "error Cannot RevertToSelf %d\n", GetLastError());
|
|
res = 0;
|
|
}
|
|
}
|
|
finish:
|
|
return res;
|
|
}
|
|
|
|
static int load_user_profile(connection_context *c)
|
|
{
|
|
PROFILEINFO pi = { .dwSize = sizeof(PROFILEINFO) };
|
|
DWORD ulen = 256;
|
|
TCHAR username[ulen];
|
|
|
|
GetUserName(username, &ulen);
|
|
pi.lpUserName = username;
|
|
|
|
return LoadUserProfile(c->token, &pi);
|
|
}
|
|
|
|
static int cmd_run(connection_context *c)
|
|
{
|
|
char buf[256];
|
|
int res = 0;
|
|
char *cmdline;
|
|
DWORD pipe_nr;
|
|
|
|
cmdline = strchr(c->cmd, ' ');
|
|
if (!cmdline) {
|
|
goto finish;
|
|
}
|
|
++cmdline;
|
|
|
|
if (!get_token(c))
|
|
return 0;
|
|
|
|
pipe_nr = (GetCurrentProcessId() << 16) + (DWORD) c->conn_number;
|
|
|
|
sprintf(buf, "\\\\.\\pipe\\" PIPE_NAME_IN, (unsigned int) pipe_nr);
|
|
c->pin = CreateNamedPipe(buf,
|
|
PIPE_ACCESS_DUPLEX,
|
|
PIPE_WAIT,
|
|
1,
|
|
BUFSIZE,
|
|
BUFSIZE,
|
|
NMPWAIT_USE_DEFAULT_WAIT,
|
|
&sa);
|
|
if (c->pin == INVALID_HANDLE_VALUE) {
|
|
hprintf(c->pipe, "error Cannot create in pipe(%s), error 0x%08X\n", buf, GetLastError());
|
|
goto finishCloseToken;
|
|
}
|
|
|
|
sprintf(buf, "\\\\.\\pipe\\" PIPE_NAME_OUT, (unsigned int) pipe_nr);
|
|
c->pout = CreateNamedPipe(buf,
|
|
PIPE_ACCESS_DUPLEX,
|
|
PIPE_WAIT,
|
|
1,
|
|
BUFSIZE,
|
|
BUFSIZE,
|
|
NMPWAIT_USE_DEFAULT_WAIT,
|
|
&sa);
|
|
if (c->pout == INVALID_HANDLE_VALUE) {
|
|
hprintf(c->pipe, "error Cannot create out pipe(%s), error 0x%08X\n", buf, GetLastError());
|
|
goto finishClosePin;
|
|
}
|
|
|
|
sprintf(buf, "\\\\.\\pipe\\" PIPE_NAME_ERR, (unsigned int) pipe_nr);
|
|
c->perr = CreateNamedPipe(buf,
|
|
PIPE_ACCESS_DUPLEX,
|
|
PIPE_WAIT,
|
|
1,
|
|
BUFSIZE,
|
|
BUFSIZE,
|
|
NMPWAIT_USE_DEFAULT_WAIT,
|
|
&sa);
|
|
if (c->perr == INVALID_HANDLE_VALUE) {
|
|
hprintf(c->pipe, "error Cannot create err pipe(%s), error 0x%08x\n", buf, GetLastError());
|
|
goto finishClosePout;
|
|
}
|
|
|
|
/* Send handle to client (it will use it to connect pipes) */
|
|
hprintf(c->pipe, CMD_STD_IO_ERR " %08X\n", pipe_nr);
|
|
|
|
HANDLE ph[] = { c->pin, c->pout, c->perr };
|
|
int i;
|
|
|
|
for (i = 0; i < 3; ++i) {
|
|
if (ConnectNamedPipe(ph[i], NULL))
|
|
continue;
|
|
int err = GetLastError();
|
|
if (err != ERROR_PIPE_CONNECTED) {
|
|
hprintf(c->pipe, "error ConnectNamedPipe(pin) %d\n", err);
|
|
while (--i >= 0)
|
|
DisconnectNamedPipe(ph[i]);
|
|
goto finishClosePerr;
|
|
}
|
|
}
|
|
|
|
SetHandleInformation(c->pin, HANDLE_FLAG_INHERIT, 1);
|
|
SetHandleInformation(c->pout, HANDLE_FLAG_INHERIT, 1);
|
|
SetHandleInformation(c->perr, HANDLE_FLAG_INHERIT, 1);
|
|
|
|
if (c->profile)
|
|
load_user_profile(c);
|
|
|
|
PROCESS_INFORMATION pi;
|
|
ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
|
|
|
|
STARTUPINFO si;
|
|
ZeroMemory(&si, sizeof(STARTUPINFO));
|
|
si.cb = sizeof(STARTUPINFO);
|
|
si.hStdInput = c->pin;
|
|
si.hStdOutput = c->pout;
|
|
si.hStdError = c->perr;
|
|
si.dwFlags |= STARTF_USESTDHANDLES;
|
|
|
|
if (CreateProcessAsUser(
|
|
c->token,
|
|
NULL,
|
|
cmdline, /* command line */
|
|
NULL, /* process security attributes */
|
|
NULL, /* primary thread security attributes */
|
|
TRUE, /* handles are inherited */
|
|
0, /* creation flags */
|
|
NULL, /* use parent's environment */
|
|
NULL, /* use parent's current directory */
|
|
&si, /* STARTUPINFO pointer */
|
|
&pi) /* receives PROCESS_INFORMATION */
|
|
) {
|
|
HANDLE hlist[2] = {c->pipe->o.hEvent, pi.hProcess};
|
|
DWORD ec;
|
|
char str[1];
|
|
|
|
if (!ResetEvent(c->pipe->o.hEvent))
|
|
dbg("ResetEvent error - %lu\n", GetLastError());
|
|
if (!ReadFile(c->pipe->h, str, 1, NULL, &c->pipe->o) && GetLastError() != ERROR_IO_PENDING)
|
|
dbg("ReadFile(control_pipe) error - %lu\n", GetLastError());
|
|
ec = WaitForMultipleObjects(2, hlist, FALSE, INFINITE);
|
|
dbg("WaitForMultipleObjects=%lu\n", ec - WAIT_OBJECT_0);
|
|
if (ec != WAIT_OBJECT_0)
|
|
GetExitCodeProcess(pi.hProcess, &ec);
|
|
else
|
|
TerminateProcess(pi.hProcess, ec = 0x1234);
|
|
FlushFileBuffers(c->pout);
|
|
FlushFileBuffers(c->perr);
|
|
CloseHandle(pi.hProcess);
|
|
CloseHandle(pi.hThread);
|
|
hprintf(c->pipe, CMD_RETURN_CODE " %08X\n", ec);
|
|
} else {
|
|
hprintf(c->pipe, "error Creating process(%s) %d\n", cmdline, GetLastError());
|
|
}
|
|
|
|
DisconnectNamedPipe(c->perr);
|
|
DisconnectNamedPipe(c->pout);
|
|
DisconnectNamedPipe(c->pin);
|
|
finishClosePerr:
|
|
CloseHandle(c->perr);
|
|
finishClosePout:
|
|
CloseHandle(c->pout);
|
|
finishClosePin:
|
|
CloseHandle(c->pin);
|
|
finishCloseToken:
|
|
CloseHandle(c->token);
|
|
finish:
|
|
return res;
|
|
}
|
|
|
|
static CMD_ITEM cmd_table[] = {
|
|
{"run", cmd_run},
|
|
{"set", cmd_set},
|
|
{"get", cmd_get},
|
|
{NULL, NULL}
|
|
};
|
|
|
|
typedef struct {
|
|
OV_HANDLE *pipe;
|
|
int conn_number;
|
|
} connection_data;
|
|
|
|
#define MAX_COMMAND_LENGTH (32768)
|
|
|
|
static VOID handle_connection(connection_data *data)
|
|
{
|
|
char *cmd = 0;
|
|
int res;
|
|
connection_context _c, *c = &_c;
|
|
cmd = malloc(MAX_COMMAND_LENGTH);
|
|
if (!cmd) {
|
|
hprintf(data->pipe,
|
|
"error: unable to allocate buffer for command\n");
|
|
return;
|
|
}
|
|
ZeroMemory(cmd, MAX_COMMAND_LENGTH);
|
|
ZeroMemory(c, sizeof(connection_context));
|
|
c->pipe = data->pipe;
|
|
c->cmd = cmd;
|
|
c->conn_number = data->conn_number;
|
|
free(data);
|
|
/* FIXME make wait for end of process or ctrl_pipe input */
|
|
while (1) {
|
|
res = hgets(cmd, MAX_COMMAND_LENGTH, c->pipe);
|
|
if (res <= 0) {
|
|
dbg("Error reading from pipe(%p)\n", c->pipe->h);
|
|
goto finish;
|
|
}
|
|
dbg("Retrieved line: \"%s\"\n", cmd);
|
|
CMD_ITEM *ci;
|
|
for (ci = cmd_table; ci->name; ++ci) {
|
|
if (strstr(cmd, ci->name) != cmd)
|
|
continue;
|
|
char c = cmd[strlen(ci->name)];
|
|
if (!c || (c == ' '))
|
|
break;
|
|
}
|
|
if (ci->name) {
|
|
if (!ci->func(c))
|
|
goto finish;
|
|
} else {
|
|
hprintf(c->pipe, "error Ignoring unknown command (%s)\n", cmd);
|
|
}
|
|
}
|
|
finish:
|
|
FlushFileBuffers(c->pipe->h);
|
|
DisconnectNamedPipe(c->pipe->h);
|
|
CloseHandle(c->pipe->h);
|
|
CloseHandle(c->pipe->o.hEvent);
|
|
free(c->pipe);
|
|
free(cmd);
|
|
}
|
|
|
|
static int conn_number = 0;
|
|
|
|
DWORD WINAPI winexesvc_loop(LPVOID lpParameter)
|
|
{
|
|
BOOL res;
|
|
|
|
dbg("server_loop: alive\n");
|
|
if (!CreatePipesSA()) {
|
|
dbg("CreatePipesSA failed (%08lX)\n", GetLastError());
|
|
return -1;
|
|
}
|
|
dbg("server_loop: CreatePipesSA done\n");
|
|
for (;;) {
|
|
dbg("server_loop: Create Pipe\n");
|
|
OV_HANDLE *pipe;
|
|
pipe = (OV_HANDLE *)malloc(sizeof(OV_HANDLE));
|
|
ZeroMemory(&pipe->o, sizeof(OVERLAPPED));
|
|
pipe->o.hEvent = CreateEvent(NULL, TRUE, TRUE, NULL);
|
|
pipe->h = CreateNamedPipe("\\\\.\\pipe\\" PIPE_NAME,
|
|
PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
|
|
PIPE_WAIT,
|
|
PIPE_UNLIMITED_INSTANCES,
|
|
BUFSIZE,
|
|
BUFSIZE,
|
|
NMPWAIT_USE_DEFAULT_WAIT,
|
|
&sa);
|
|
if (pipe->h == INVALID_HANDLE_VALUE) {
|
|
dbg("CreatePipe failed(%08lX)\n",
|
|
GetLastError());
|
|
CloseHandle(pipe->o.hEvent);
|
|
free(pipe);
|
|
return 0;
|
|
}
|
|
|
|
dbg("server_loop: Connect Pipe\n");
|
|
if (ConnectNamedPipe(pipe->h, &pipe->o)) {
|
|
dbg("server_loop: Connect Pipe err %08lX\n", GetLastError());
|
|
res = FALSE;
|
|
} else {
|
|
switch (GetLastError()) {
|
|
case ERROR_IO_PENDING:
|
|
dbg("server_loop: Connect Pipe(0) pending\n");
|
|
DWORD t;
|
|
res = GetOverlappedResult(pipe->h, &pipe->o, &t, TRUE);
|
|
break;
|
|
case ERROR_PIPE_CONNECTED:
|
|
dbg("server_loop: Connect Pipe(0) connected\n");
|
|
res = TRUE;
|
|
break;
|
|
default:
|
|
dbg("server_loop: Connect Pipe(0) err %08lX\n", GetLastError());
|
|
res = FALSE;
|
|
}
|
|
}
|
|
|
|
if (res) {
|
|
connection_data *cd = malloc(sizeof(connection_data));
|
|
cd->pipe = pipe;
|
|
cd->conn_number = ++conn_number;
|
|
dbg("server_loop: CreateThread\n");
|
|
HANDLE th = CreateThread(NULL, /* no security attribute */
|
|
0, /* default stack size */
|
|
(LPTHREAD_START_ROUTINE)
|
|
handle_connection,
|
|
(LPVOID) cd, /* thread parameter */
|
|
0, /* not suspended */
|
|
NULL); /* returns thread ID */
|
|
if (!th) {
|
|
dbg("Cannot create thread\n");
|
|
CloseHandle(pipe->h);
|
|
CloseHandle(pipe->o.hEvent);
|
|
free(pipe);
|
|
} else {
|
|
CloseHandle(th);
|
|
dbg("server_loop: Thread created\n");
|
|
}
|
|
} else {
|
|
dbg("server_loop: Pipe not connected\n");
|
|
CloseHandle(pipe->h);
|
|
CloseHandle(pipe->o.hEvent);
|
|
free(pipe);
|
|
}
|
|
}
|
|
dbg("server_loop: STH wrong\n");
|
|
return 0;
|
|
}
|
|
|
|
static SERVICE_STATUS winexesvcStatus;
|
|
static SERVICE_STATUS_HANDLE winexesvcStatusHandle;
|
|
|
|
static VOID WINAPI winexesvcCtrlHandler(DWORD Opcode)
|
|
{
|
|
switch (Opcode) {
|
|
case SERVICE_CONTROL_PAUSE:
|
|
dbg(SERVICE_NAME ": winexesvcCtrlHandler: pause\n", 0);
|
|
winexesvcStatus.dwCurrentState = SERVICE_PAUSED;
|
|
break;
|
|
|
|
case SERVICE_CONTROL_CONTINUE:
|
|
dbg(SERVICE_NAME ": winexesvcCtrlHandler: continue\n", 0);
|
|
winexesvcStatus.dwCurrentState = SERVICE_RUNNING;
|
|
break;
|
|
|
|
case SERVICE_CONTROL_STOP:
|
|
dbg(SERVICE_NAME ": winexesvcCtrlHandler: stop\n", 0);
|
|
winexesvcStatus.dwWin32ExitCode = 0;
|
|
winexesvcStatus.dwCurrentState = SERVICE_STOPPED;
|
|
winexesvcStatus.dwCheckPoint = 0;
|
|
winexesvcStatus.dwWaitHint = 0;
|
|
|
|
if (!SetServiceStatus (winexesvcStatusHandle, &winexesvcStatus))
|
|
dbg(SERVICE_NAME ": SetServiceStatus error %ld\n", GetLastError());
|
|
|
|
dbg(SERVICE_NAME ": Leaving winexesvc\n", 0);
|
|
return;
|
|
|
|
case SERVICE_CONTROL_INTERROGATE:
|
|
dbg(SERVICE_NAME ": winexesvcCtrlHandler: interrogate\n", 0);
|
|
break;
|
|
|
|
default:
|
|
dbg(SERVICE_NAME ": Unrecognized opcode %ld\n", Opcode);
|
|
}
|
|
|
|
if (!SetServiceStatus(winexesvcStatusHandle, &winexesvcStatus))
|
|
dbg(SERVICE_NAME ": SetServiceStatus error 0x%08X\n", GetLastError());
|
|
|
|
return;
|
|
}
|
|
|
|
static DWORD winexesvcInitialization(DWORD argc, LPTSTR * argv, DWORD * specificError)
|
|
{
|
|
HANDLE th = CreateThread(NULL, 0, winexesvc_loop, NULL, 0, NULL);
|
|
if (th) {
|
|
CloseHandle(th);
|
|
return NO_ERROR;
|
|
}
|
|
return !NO_ERROR;
|
|
}
|
|
|
|
static void WINAPI winexesvcStart(DWORD argc, LPTSTR * argv)
|
|
{
|
|
DWORD status;
|
|
DWORD specificError;
|
|
|
|
winexesvcStatus.dwServiceType = SERVICE_WIN32;
|
|
winexesvcStatus.dwCurrentState = SERVICE_START_PENDING;
|
|
winexesvcStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_PAUSE_CONTINUE;
|
|
winexesvcStatus.dwWin32ExitCode = 0;
|
|
winexesvcStatus.dwServiceSpecificExitCode = 0;
|
|
winexesvcStatus.dwCheckPoint = 0;
|
|
winexesvcStatus.dwWaitHint = 0;
|
|
|
|
dbg(SERVICE_NAME ": RegisterServiceCtrlHandler\n", 0);
|
|
|
|
winexesvcStatusHandle = RegisterServiceCtrlHandler(SERVICE_NAME, winexesvcCtrlHandler);
|
|
|
|
if (winexesvcStatusHandle == (SERVICE_STATUS_HANDLE) 0) {
|
|
dbg(SERVICE_NAME
|
|
": RegisterServiceCtrlHandler failed %d\n",
|
|
GetLastError());
|
|
return;
|
|
}
|
|
status = winexesvcInitialization(argc, argv, &specificError);
|
|
|
|
if (status != NO_ERROR) {
|
|
winexesvcStatus.dwCurrentState = SERVICE_STOPPED;
|
|
winexesvcStatus.dwCheckPoint = 0;
|
|
winexesvcStatus.dwWaitHint = 0;
|
|
winexesvcStatus.dwWin32ExitCode = status;
|
|
winexesvcStatus.dwServiceSpecificExitCode = specificError;
|
|
|
|
SetServiceStatus(winexesvcStatusHandle, &winexesvcStatus);
|
|
return;
|
|
}
|
|
|
|
winexesvcStatus.dwCurrentState = SERVICE_RUNNING;
|
|
winexesvcStatus.dwCheckPoint = 0;
|
|
winexesvcStatus.dwWaitHint = 0;
|
|
|
|
if (!SetServiceStatus(winexesvcStatusHandle, &winexesvcStatus)) {
|
|
status = GetLastError();
|
|
dbg(SERVICE_NAME ": SetServiceStatus error %ld\n", status);
|
|
}
|
|
|
|
dbg(SERVICE_NAME ": Returning the Main Thread \n", 0);
|
|
|
|
return;
|
|
}
|
|
|
|
int main(int argc, char *argv[])
|
|
{
|
|
SERVICE_TABLE_ENTRY DispatchTable[] = {
|
|
{SERVICE_NAME, winexesvcStart},
|
|
{NULL, NULL}
|
|
};
|
|
|
|
dbg(SERVICE_NAME ": StartServiceCtrlDispatcher %d\n", GetLastError());
|
|
if (!StartServiceCtrlDispatcher(DispatchTable)) {
|
|
dbg(SERVICE_NAME
|
|
": StartServiceCtrlDispatcher (%d)\n",
|
|
GetLastError());
|
|
}
|
|
return 0;
|
|
}
|