mirror of
https://github.com/samba-team/samba.git
synced 2024-12-24 21:34:56 +03:00
ffa1c040c6
winexe from https://sourceforge.net/projects/winexe/ is a project
based on Samba libraries from 2012. According to the winexe git
repository the last Samba commit winexe was updated to is 47bbf9886f
from November 6, 2012. As winexe uses unpublished Samba internal
libraries, it broke over time.
This is a port of the winexe functionality to more modern Samba
versions. It still uses internal APIs, but it being part of the tree
means that it is much easier to keep up to date.
The Windows service files were taken literally from the original
winexe from the sourceforge git. Andrzej Hajda chose GPLv3 only and
not GPLv3+. As GPL evolves very slowly, this should not be a practical
problem for quite some time.
To build it under Linux, you need mingw binaries on your build
system. Under Debian stretch, the package names are gcc-mingw-w64 and
friends.
Signed-off-by: Volker Lendecke <vl@samba.org>
Reviewed-by: Jeremy Allison <jra@samba.org>
Autobuild-User(master): Jeremy Allison <jra@samba.org>
Autobuild-Date(master): Tue Aug 28 02:03:07 CEST 2018 on sn-devel-144
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 commad (%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;
|
|
}
|