|
|
|
|
@ -30,6 +30,102 @@
|
|
|
|
|
#include "win32-service.h"
|
|
|
|
|
#include "util-debug.h"
|
|
|
|
|
|
|
|
|
|
/** Append a character, leaving room for the terminating NUL. */
|
|
|
|
|
static bool SCServiceAppendChar(char *path, size_t size, size_t *len, char c)
|
|
|
|
|
{
|
|
|
|
|
if (size == 0 || *len >= size - 1) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
path[(*len)++] = c;
|
|
|
|
|
path[*len] = '\0';
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Quote an argument for the Windows C runtime. Backslashes are literal except
|
|
|
|
|
* before a double quote: emit 2n+1 backslashes before an embedded quote, and
|
|
|
|
|
* 2n before the closing quote. Always quote, including empty arguments.
|
|
|
|
|
*/
|
|
|
|
|
static bool SCServiceAppendArgument(char *path, size_t size, size_t *len, const char *arg)
|
|
|
|
|
{
|
|
|
|
|
if (!SCServiceAppendChar(path, size, len, '"')) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
while (*arg != '\0') {
|
|
|
|
|
size_t backslashes = 0;
|
|
|
|
|
while (*arg == '\\') {
|
|
|
|
|
backslashes++;
|
|
|
|
|
arg++;
|
|
|
|
|
}
|
|
|
|
|
for (size_t i = 0; i < backslashes; i++) {
|
|
|
|
|
if (!SCServiceAppendChar(path, size, len, '\\')) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
if ((*arg == '"' || *arg == '\0') && !SCServiceAppendChar(path, size, len, '\\')) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (*arg == '\0') {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if (*arg == '"' && !SCServiceAppendChar(path, size, len, '\\')) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
if (!SCServiceAppendChar(path, size, len, *arg++)) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return SCServiceAppendChar(path, size, len, '"');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** Build the service command line without accessing SCM. */
|
|
|
|
|
static bool SCServiceBuildCommandLine(char *path, size_t size, const char *module, int argc,
|
|
|
|
|
const char *const *argv, const char *service_option)
|
|
|
|
|
{
|
|
|
|
|
if (size == 0) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
path[0] = '\0';
|
|
|
|
|
size_t len = 0;
|
|
|
|
|
if (!SCServiceAppendArgument(path, size, &len, module)) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
for (int i = 1; i < argc; i++) {
|
|
|
|
|
/* Preserve the existing service-option prefix matching. */
|
|
|
|
|
if (strlen(argv[i]) <= strlen(service_option) &&
|
|
|
|
|
strncmp(service_option, argv[i], strlen(argv[i])) == 0) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
if (!SCServiceAppendChar(path, size, &len, ' ') ||
|
|
|
|
|
!SCServiceAppendArgument(path, size, &len, argv[i])) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** Resolve the executable and reject truncation before making any SCM calls. */
|
|
|
|
|
static bool SCServiceGetCommandLine(
|
|
|
|
|
char *path, size_t size, int argc, char **argv, const char *service_option)
|
|
|
|
|
{
|
|
|
|
|
char module[2048];
|
|
|
|
|
DWORD len = GetModuleFileName(NULL, module, sizeof(module));
|
|
|
|
|
if (len == 0) {
|
|
|
|
|
SCLogError("Can't get path to service binary: %d", (int)GetLastError());
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
if (len >= sizeof(module)) {
|
|
|
|
|
SCLogError("failed to construct service path string: binary path truncated");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
if (!SCServiceBuildCommandLine(
|
|
|
|
|
path, size, module, argc, (const char *const *)argv, service_option)) {
|
|
|
|
|
SCLogError("failed to construct service path string: invalid or truncated command line");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static SERVICE_STATUS_HANDLE service_status_handle = 0;
|
|
|
|
|
|
|
|
|
|
static int service_argc = 0;
|
|
|
|
|
@ -214,35 +310,11 @@ int SCServiceInstall(int argc, char **argv)
|
|
|
|
|
SC_HANDLE service = NULL;
|
|
|
|
|
SC_HANDLE scm = NULL;
|
|
|
|
|
int ret = -1;
|
|
|
|
|
int i = 0;
|
|
|
|
|
|
|
|
|
|
do {
|
|
|
|
|
memset(path, 0, sizeof(path));
|
|
|
|
|
|
|
|
|
|
path[0] = '"';
|
|
|
|
|
if (GetModuleFileName(NULL, path + 1, sizeof(path) - 1) == 0) {
|
|
|
|
|
SCLogError("Can't get path to service binary: %d", (int)GetLastError());
|
|
|
|
|
if (!SCServiceGetCommandLine(path, sizeof(path), argc, argv, "--service-install")) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if (strlcat(path, "\"", sizeof(path)) >= sizeof(path)) {
|
|
|
|
|
SCLogError("failed to construct service path string: path truncated: %s", path);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* skip name of binary itself */
|
|
|
|
|
for (i = 1; i < argc; i++) {
|
|
|
|
|
if ((strlen(argv[i]) <= strlen("--service-install")) && (strncmp("--service-install", argv[i], strlen(argv[i])) == 0)) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
if (strlcat(path, " ", sizeof(path)) >= sizeof(path)) {
|
|
|
|
|
SCLogError("failed to construct service path string: path truncated: %s", path);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
if (strlcat(path, argv[i], sizeof(path)) >= sizeof(path)) {
|
|
|
|
|
SCLogError("failed to construct service path string: path truncated: %s", path);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ((scm = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS)) == NULL) {
|
|
|
|
|
SCLogError("Can't open SCM: %d", (int)GetLastError());
|
|
|
|
|
@ -350,36 +422,12 @@ int SCServiceChangeParams(int argc, char **argv)
|
|
|
|
|
SC_HANDLE service = NULL;
|
|
|
|
|
SC_HANDLE scm = NULL;
|
|
|
|
|
int ret = -1;
|
|
|
|
|
int i = 0;
|
|
|
|
|
|
|
|
|
|
do {
|
|
|
|
|
memset(path, 0, sizeof(path));
|
|
|
|
|
|
|
|
|
|
path[0] = '"';
|
|
|
|
|
if (GetModuleFileName(NULL, path + 1, sizeof(path) - 1) == 0) {
|
|
|
|
|
SCLogError("Can't get path to service binary: %d", (int)GetLastError());
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if (strlcat(path, "\"", sizeof(path)) >= sizeof(path)) {
|
|
|
|
|
SCLogError("failed to construct service path string: path truncated: %s", path);
|
|
|
|
|
if (!SCServiceGetCommandLine(path, sizeof(path), argc, argv, "--service-change-params")) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* skip name of binary itself */
|
|
|
|
|
for (i = 1; i < argc; i++) {
|
|
|
|
|
if ((strlen(argv[i]) <= strlen("--service-change-params")) && (strncmp("--service-change-params", argv[i], strlen(argv[i])) == 0)) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
if (strlcat(path, " ", sizeof(path)) >= sizeof(path)) {
|
|
|
|
|
SCLogError("failed to construct service path string: path truncated: %s", path);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
if (strlcat(path, argv[i], sizeof(path)) >= sizeof(path)) {
|
|
|
|
|
SCLogError("failed to construct service path string: path truncated: %s", path);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ((scm = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS)) == NULL) {
|
|
|
|
|
SCLogError("Can't open SCM: %d", (int)GetLastError());
|
|
|
|
|
break;
|
|
|
|
|
|