Newer
Older
/* Synchronet BBS as a set of Windows NT Services */
/****************************************************************************
* @format.tab-size 4 (Plain Text/Source Code File Header) *
* @format.use-tabs true (see http://www.synchro.net/ptsc_hdr.html) *
* *
* Copyright Rob Swindell - http://www.synchro.net/copyright.html *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License *
* as published by the Free Software Foundation; either version 2 *
* of the License, or (at your option) any later version. *
* See the GNU General Public License for more details: gpl.txt or *
* http://www.fsf.org/copyleft/gpl.html *
* *
* For Synchronet coding style and modification guidelines, see *
* http://www.synchro.net/source.html *
* *
* Note: If this box doesn't appear square, then you need to fix your tabs. *
****************************************************************************/
/* Synchronet-specific headers */
#include "sbbs.h" /* various */
#include "sbbs_ini.h" /* sbbs_read_ini() */
#include "ftpsrvr.h" /* ftp_startup_t, ftp_server */
#include "websrvr.h" /* web_startup_t, web_server */
#include "mailsrvr.h" /* mail_startup_t, mail_server */
#include "services.h" /* services_startup_t, services_thread */
#include "ntsvcs.h" /* NT service names */
/* Windows-specific headers */
#include <winsvc.h>
#define NTSVC_TIMEOUT_STARTUP 30000 /* Milliseconds */
#define NTSVC_TIMEOUT_TERMINATE 30000 /* Milliseconds */
#define STRLEN_MAX_DISPLAY_NAME 35
#define STRLEN_SYNCHRONET 10 /* this number ain't change'n */
#define SERVICE_NOT_INSTALLED (SERVICE_DISABLED + 1)
static void WINAPI bbs_ctrl_handler(DWORD dwCtrlCode);
static void WINAPI ftp_ctrl_handler(DWORD dwCtrlCode);
static void WINAPI web_ctrl_handler(DWORD dwCtrlCode);
static void WINAPI mail_ctrl_handler(DWORD dwCtrlCode);
static void WINAPI services_ctrl_handler(DWORD dwCtrlCode);
/* Global variables */
char ini_file[MAX_PATH + 1];
bbs_startup_t bbs_startup;
ftp_startup_t ftp_startup;
mail_startup_t mail_startup;
services_startup_t services_startup;
web_startup_t web_startup;
link_list_t login_attempt_list;
typedef struct {
char* name;
char* display_name;
char* description;
void* startup;
DWORD* options;
bool* recycle_now;
int* log_level;
void (*thread)(void* arg);
void (*terminate)(void);
void (WINAPI * ctrl_handler)(DWORD);
HANDLE log_handle;
HANDLE event_handle;
bool autostart;
bool debug;
SERVICE_STATUS status;
SERVICE_STATUS_HANDLE status_handle;
} sbbs_ntsvc_t;
NTSVC_NAME_BBS,
"Provides support for Telnet, RLogin, and SSH clients and executes timed events. " \
"This service provides the critical functions of your Synchronet BBS.",
&bbs_startup,
&bbs_startup.options,
&bbs_startup.recycle_now,
&bbs_startup.log_level,
bbs_thread,
bbs_terminate,
bbs_ctrl_handler,
INVALID_HANDLE_VALUE
};
/* This is not (currently) a separate service, use this for logging only */
NTSVC_NAME_EVENT,
NULL,
NULL,
NULL,
NULL,
&bbs_startup.log_level,
NULL,
NULL,
INVALID_HANDLE_VALUE
};
NTSVC_NAME_FTP,
"Synchronet FTP Server",
"Provides support for FTP and FTPS clients for file transfers.",
&ftp_startup,
&ftp_startup.options,
&ftp_startup.recycle_now,
&ftp_startup.log_level,
ftp_server,
ftp_terminate,
ftp_ctrl_handler,
INVALID_HANDLE_VALUE
};
NTSVC_NAME_WEB,
"Synchronet Web Server",
"Provides support for Web (HTTP/HTTPS) clients (e.g. browsers).",
&web_startup,
&web_startup.options,
&web_startup.recycle_now,
&web_startup.log_level,
web_server,
web_terminate,
web_ctrl_handler,
INVALID_HANDLE_VALUE
};
NTSVC_NAME_MAIL,
"Synchronet SMTP/POP3 Mail Server",
"Sends and receives Internet e-mail (using SMTP) and allows users to remotely " \
"access their e-mail using an Internet mail client (using POP3).",
&mail_startup,
&mail_startup.options,
&mail_startup.recycle_now,
&mail_startup.log_level,
mail_server,
mail_terminate,
mail_ctrl_handler,
INVALID_HANDLE_VALUE
};
sbbs_ntsvc_t services = {
NTSVC_NAME_SERVICES,
"Synchronet Services",
"Plug-in servers (usually in JavaScript) for any TCP/UDP protocol. " \
"Stock services include Finger, Gopher, NNTP, and IRC. Edit your ctrl/services.ini " \
"file for configuration of individual Synchronet Services.",
&services_startup,
&services_startup.options,
&services_startup.recycle_now,
&services_startup.log_level,
services_thread,
services_terminate,
services_ctrl_handler,
INVALID_HANDLE_VALUE
};
/* This list is used for enumerating all services */
sbbs_ntsvc_t* ntsvc_list[] = {
&bbs,
&ftp,
&web,
&mail,
&services,
NULL
};
/****************************************/
/* Service Control Handlers (Callbacks) */
/****************************************/
/* Common control handler for all services */
static void svc_ctrl_handler(sbbs_ntsvc_t* svc, DWORD dwCtrlCode)
{
case SERVICE_CONTROL_RECYCLE:
*svc->recycle_now = TRUE;
break;
case SERVICE_CONTROL_STOP:
case SERVICE_CONTROL_SHUTDOWN:
svc->terminate();
svc->status.dwWaitHint = NTSVC_TIMEOUT_TERMINATE;
svc->status.dwCurrentState = SERVICE_STOP_PENDING;
break;
}
SetServiceStatus(svc->status_handle, &svc->status);
}
/* Service-specific control handler stub functions */
static void WINAPI bbs_ctrl_handler(DWORD dwCtrlCode)
{
svc_ctrl_handler(&bbs, dwCtrlCode);
}
static void WINAPI ftp_ctrl_handler(DWORD dwCtrlCode)
{
svc_ctrl_handler(&ftp, dwCtrlCode);
static void WINAPI web_ctrl_handler(DWORD dwCtrlCode)
svc_ctrl_handler(&web, dwCtrlCode);
static void WINAPI mail_ctrl_handler(DWORD dwCtrlCode)
svc_ctrl_handler(&mail, dwCtrlCode);
static void WINAPI services_ctrl_handler(DWORD dwCtrlCode)
svc_ctrl_handler(&services, dwCtrlCode);
static WORD event_type(int level)
{
return EVENTLOG_WARNING_TYPE;
case LOG_NOTICE:
case LOG_INFO:
case LOG_DEBUG:
return EVENTLOG_INFORMATION_TYPE; /* same as EVENT_LOG_SUCCESS */
}
/*
LOG_EMERG
LOG_ALERT
LOG_CRIT
LOG_ERR
*/
return EVENTLOG_ERROR_TYPE;
/**************************************/
/* Common Service Log Ouptut Function */
/**************************************/
static int svc_lputs(void* p, int level, const char* str)
char debug[1024];
char fname[256];
DWORD len;
DWORD wr;
log_msg_t msg;
sbbs_ntsvc_t* svc = (sbbs_ntsvc_t*)p;
if (svc == NULL || svc->debug) {
snprintf(debug, sizeof(debug), "%s: %s", svc == NULL ? "Synchronet" : svc->name, str);
OutputDebugString(debug);
}
len = strlen(str);
SAFECOPY(msg.buf, str);
msg.level = level;
msg.repeated = 0;
GetLocalTime(&msg.time);
if (svc->log_handle != INVALID_HANDLE_VALUE /* Invalid log handle? */
&& !GetMailslotInfo(svc->log_handle, NULL, NULL, NULL, NULL)) {
/* Close and try to re-open */
CloseHandle(svc->log_handle);
svc->log_handle = INVALID_HANDLE_VALUE;
}
if (svc->log_handle == INVALID_HANDLE_VALUE) {
SAFEPRINTF(fname, "\\\\.\\mailslot\\%s.log", svc->name);
svc->log_handle = CreateFile(
fname, /* pointer to name of the file */
GENERIC_WRITE, /* access (read-write) mode */
FILE_SHARE_READ, /* share mode */
NULL, /* pointer to security attributes */
OPEN_EXISTING, /* how to create */
FILE_ATTRIBUTE_NORMAL, /* file attributes */
NULL /* handle to file with attributes to copy */
if (svc->log_handle != INVALID_HANDLE_VALUE) {
len = sizeof(msg);
if (!WriteFile(svc->log_handle, &msg, len, &wr, NULL) || wr != len) {
/* This most likely indicates the server closed the mailslot */
safe_snprintf(debug, sizeof(debug), "!ERROR %d writing %u bytes to %s pipe (wr=%d)"
, GetLastError(), len, svc->name, wr);
OutputDebugString(debug);
/* So close the handle and attempt re-open next time */
CloseHandle(svc->log_handle);
svc->log_handle = INVALID_HANDLE_VALUE;
if (level <= (*svc->log_level)) {
if (svc->event_handle == NULL)
svc->event_handle = RegisterEventSource(
NULL, /* server name for source (NULL = local computer) */
svc->name /* source name for registered handle */
if (svc->event_handle != NULL)
ReportEvent(svc->event_handle, /* event log handle */
event_type(level), /* event type */
0, /* category zero */
0, /* event identifier */
NULL, /* no user security identifier */
1, /* one string */
0, /* no data */
(LPCSTR*)&str, /* pointer to string array */
NULL); /* pointer to data */
/************************************/
/* Shared Service Callback Routines */
/************************************/
static void svc_set_state(void* p, enum server_state state)
sbbs_ntsvc_t* svc = (sbbs_ntsvc_t*)p;
if (state == SERVER_READY) {
svc->status.dwCurrentState = SERVICE_RUNNING;
svc->status.dwControlsAccepted |= SERVICE_ACCEPT_STOP;
SetServiceStatus(svc->status_handle, &svc->status);
}
static void read_ini(sbbs_ntsvc_t* svc)
{
char str[MAX_PATH * 2];
FILE* fp;
bbs_startup_t* bbs_startup = NULL;
ftp_startup_t* ftp_startup = NULL;
mail_startup_t* mail_startup = NULL;
services_startup_t* services_startup = NULL;
web_startup_t* web_startup = NULL;
if (svc == &bbs)
bbs_startup = svc->startup;
else if (svc == &ftp)
ftp_startup = svc->startup;
else if (svc == &web)
web_startup = svc->startup;
else if (svc == &mail)
mail_startup = svc->startup;
else if (svc == &services)
services_startup = svc->startup;
if ((fp = fopen(ini_file, "r")) != NULL) {
SAFEPRINTF(str, "Reading %s", ini_file);
svc_lputs(NULL, LOG_INFO, str);
/* We call this function to set defaults, even if there's no .ini file */
sbbs_read_ini(fp, ini_file
, NULL /* global_startup */
, NULL, bbs_startup
, NULL, ftp_startup
, NULL, web_startup
, NULL, mail_startup
, NULL, services_startup
);
/* close .ini file here */
fclose(fp);
}
static void svc_recycle(void *p)
{
read_ini((sbbs_ntsvc_t*)p);
}
static void svc_terminated(void* p, int code)
sbbs_ntsvc_t* svc = (sbbs_ntsvc_t*)p;
if (code) {
svc->status.dwWin32ExitCode = ERROR_SERVICE_SPECIFIC_ERROR;
svc->status.dwServiceSpecificExitCode = code;
SetServiceStatus(svc->status_handle, &svc->status);
static void svc_clients(void* p, int active)
{
sbbs_ntsvc_t* svc = (sbbs_ntsvc_t*)p;
}
/***************/
/* ServiceMain */
/***************/
/* Common ServiceMain for all services */
static void WINAPI svc_main(sbbs_ntsvc_t* svc, DWORD argc, LPTSTR *argv)
char str[256];
DWORD i;
char* arg;
for (i = 0; i < argc; i++) {
arg = argv[i];
if (*arg == '-' || *arg == '/')
arg++;
if (!stricmp(arg, "debug"))
svc->debug = TRUE;
if (!stricmp(arg, "loglevel") && i + 1 < argc)
(*svc->log_level) = strtol(argv[++i], NULL, 0);
}
SAFEPRINTF(str, "Starting NT Service: %s", svc->display_name);
svc_lputs(svc, LOG_INFO, str);
if ((svc->status_handle = RegisterServiceCtrlHandler(svc->name, svc->ctrl_handler)) == 0) {
SAFEPRINTF(str, "!ERROR %d registering service control handler", GetLastError());
svc_lputs(NULL, LOG_ERR, str);
memset(&svc->status, 0, sizeof(SERVICE_STATUS));
svc->status.dwServiceType = SERVICE_WIN32_SHARE_PROCESS;
svc->status.dwControlsAccepted = SERVICE_ACCEPT_SHUTDOWN;
svc->status.dwWaitHint = NTSVC_TIMEOUT_STARTUP;
svc->status.dwCurrentState = SERVICE_START_PENDING;
SetServiceStatus(svc->status_handle, &svc->status);
read_ini(svc);
svc->status.dwCurrentState = SERVICE_STOPPED;
SetServiceStatus(svc->status_handle, &svc->status);
if (svc->log_handle != INVALID_HANDLE_VALUE) {
CloseHandle(svc->log_handle);
svc->log_handle = INVALID_HANDLE_VALUE;
if (svc->event_handle != NULL) {
DeregisterEventSource(svc->event_handle);
svc->event_handle = NULL;
/* Service-specific ServiceMain stub functions */
static void WINAPI bbs_start(DWORD dwArgc, LPTSTR *lpszArgv)
svc_main(&bbs, dwArgc, lpszArgv);
/* Events are (currently) part of the BBS service */
if (event.log_handle != INVALID_HANDLE_VALUE) {
CloseHandle(event.log_handle);
event.log_handle = INVALID_HANDLE_VALUE;
}
static void WINAPI ftp_start(DWORD dwArgc, LPTSTR *lpszArgv)
svc_main(&ftp, dwArgc, lpszArgv);
static void WINAPI web_start(DWORD dwArgc, LPTSTR *lpszArgv)
svc_main(&web, dwArgc, lpszArgv);
static void WINAPI mail_start(DWORD dwArgc, LPTSTR *lpszArgv)
svc_main(&mail, dwArgc, lpszArgv);
static void WINAPI services_start(DWORD dwArgc, LPTSTR *lpszArgv)
svc_main(&services, dwArgc, lpszArgv);
}
/******************************************/
/* NT Service Install/Uninstall Functions */
/******************************************/
static void describe_service(SC_HANDLE hService, char* description)
static SERVICE_DESCRIPTION service_desc = {0};
service_desc.lpDescription = description;
ChangeServiceConfig2(hService, SERVICE_CONFIG_DESCRIPTION, &service_desc);
static bool register_event_source(char* name, char* path)
{
char keyname[256];
HKEY hKey;
DWORD type;
DWORD disp;
LONG retval;
char* value;
SAFEPRINTF(keyname, "system\\CurrentControlSet\\services\\eventlog\\application\\%s", name);
retval = RegCreateKeyEx(
HKEY_LOCAL_MACHINE, /* handle to an open key */
keyname, /* address of subkey name */
0, /* reserved */
"", /* address of class string */
0, /* special options flag */
KEY_ALL_ACCESS, /* desired security access */
NULL, /* address of key security structure */
&hKey, /* address of buffer for opened handle */
&disp /* address of disposition value buffer */
);
if (retval != ERROR_SUCCESS) {
fprintf(stderr, "!Error %d creating/opening registry key (HKLM\\%s)\n"
, retval, keyname);
}
value = "EventMessageFile";
retval = RegSetValueEx(
hKey, /* handle to key to set value for */
value, /* name of the value to set */
0, /* reserved */
REG_SZ, /* flag for value type */
path, /* address of value data */
strlen(path) /* size of value data */
);
if (retval != ERROR_SUCCESS) {
RegCloseKey(hKey);
fprintf(stderr, "!Error %d setting registry key value (%s)\n"
, retval, value);
}
value = "TypesSupported";
type = EVENTLOG_ERROR_TYPE | EVENTLOG_WARNING_TYPE | EVENTLOG_INFORMATION_TYPE;
retval = RegSetValueEx(
hKey, /* handle to key to set value for */
value, /* name of the value to set */
0, /* reserved */
REG_DWORD, /* flag for value type */
(BYTE*)&type, /* address of value data */
sizeof(type) /* size of value data */
);
RegCloseKey(hKey);
if (retval != ERROR_SUCCESS) {
fprintf(stderr, "!Error %d setting registry key value (%s)\n"
, retval, value);
}
}
static const char* start_type_desc(DWORD start_type)
{
static char str[128];
case SERVICE_AUTO_START: return "Startup: Automatic";
case SERVICE_DEMAND_START: return "Startup: Manual";
case SERVICE_DISABLED: return "Disabled";
case SERVICE_NOT_INSTALLED: return "Not installed";
}
SAFEPRINTF(str, "Start_type: %d", start_type);
}
static const char* state_desc(DWORD state)
{
static char str[128];
case SERVICE_STOPPED: return "Stopped";
case SERVICE_START_PENDING: return "Start Pending";
case SERVICE_STOP_PENDING: return "Stop Pending";
case SERVICE_RUNNING: return "Running";
case SERVICE_CONTINUE_PENDING: return "Continue Pending";
case SERVICE_PAUSE_PENDING: return "Pause Pending";
case SERVICE_PAUSED: return "Paused";
}
SAFEPRINTF(str, "State: %d", state);
}
static const char* control_desc(DWORD ctrl)
{
static char str[128];
case SERVICE_CONTROL_STOP:
case SERVICE_CONTROL_PAUSE:
case SERVICE_CONTROL_CONTINUE:
case SERVICE_CONTROL_INTERROGATE:
return "Interrogating";
case SERVICE_CONTROL_SHUTDOWN:
return "Shutting-down";
/* Synchronet-specific */
case SERVICE_CONTROL_RECYCLE:
SAFEPRINTF(str, "Control: %d", ctrl);
}
/****************************************************************************/
/* Utility function to detect if a service is currently disabled */
/****************************************************************************/
static DWORD get_service_info(SC_HANDLE hSCManager, char* name, DWORD* state)
{
SC_HANDLE hService;
DWORD size;
DWORD err;
DWORD ret;
SERVICE_STATUS status;
LPQUERY_SERVICE_CONFIG service_config;
if (state != NULL)
*state = SERVICE_STOPPED;
if ((hService = OpenService(hSCManager, name, SERVICE_ALL_ACCESS)) == NULL) {
if ((err = GetLastError()) == ERROR_SERVICE_DOES_NOT_EXIST)
return SERVICE_NOT_INSTALLED;
printf("\n!ERROR %d opening service: %s\n", err, name);
}
if (QueryServiceConfig(
hService, /* handle of service */
NULL, /* address of service config. structure */
0, /* size of service configuration buffer */
&size /* address of variable for bytes needed */
) || GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
printf("\n!Unexpected QueryServiceConfig ERROR %u\n", err = GetLastError());
}
if (state != NULL && QueryServiceStatus(hService, &status))
*state = status.dwCurrentState;
if ((service_config = malloc(size)) == NULL) {
printf("\n!ERROR allocating %u bytes of memory\n", size);
}
if (!QueryServiceConfig(
hService, /* handle of service */
service_config, /* address of service config. structure */
size, /* size of service configuration buffer */
&size /* address of variable for bytes needed */
)) {
printf("\n!QueryServiceConfig ERROR %u\n", GetLastError());
CloseServiceHandle(hService);
ret = service_config->dwStartType;
}
/****************************************************************************/
/* Utility function to create a service with description (on Win2K+) */
/****************************************************************************/
static void create_service(SC_HANDLE hSCManager
, char* name, char* display_name, char* description, char* path
, bool autostart)
SC_HANDLE hService;
DWORD err;
DWORD start_type = autostart ? SERVICE_AUTO_START : SERVICE_DEMAND_START;
printf("Installing service: %-*s ... ", STRLEN_MAX_DISPLAY_NAME, display_name);
hService = CreateService(
hSCManager, /* SCManager database */
name, /* name of service */
display_name, /* name to display */
SERVICE_ALL_ACCESS, /* desired access */
SERVICE_WIN32_SHARE_PROCESS, /* service type */
start_type, /* start type (auto or manual) */
SERVICE_ERROR_NORMAL, /* error control type */
path, /* service's binary */
NULL, /* no load ordering group */
NULL, /* no tag identifier */
"", /* dependencies */
NULL, /* LocalSystem account */
NULL); /* no password */
if (hService == NULL) {
if ((err = GetLastError()) == ERROR_SERVICE_EXISTS)
printf("Already installed\n");
else
printf("!ERROR %d\n", err);
}
describe_service(hService, description);
printf("%s\n", start_type_desc(start_type));
register_event_source(name, path);
register_event_source(NTSVC_NAME_EVENT, path); /* Create SynchronetEvent event source */
/****************************************************************************/
/* Install one or all services */
/****************************************************************************/
int i;
SC_HANDLE hSCManager;
char path[MAX_PATH + 1];
printf("Installing Synchronet NT Services...\n");
if (GetModuleFileName(NULL, path, sizeof(path)) == 0)
{
fprintf(stderr, "!ERROR %d getting module file name\n", GetLastError());
}
hSCManager = OpenSCManager(
NULL, /* machine (NULL == local) */
NULL, /* database (NULL == default) */
SC_MANAGER_ALL_ACCESS /* access required */
);
if (hSCManager == NULL) {
fprintf(stderr, "!ERROR %d opening SC manager\n", GetLastError());
for (i = 0; ntsvc_list[i] != NULL; i++)
if (svc_name == NULL /* All? */
|| !stricmp(ntsvc_list[i]->name, svc_name)
|| !stricmp(ntsvc_list[i]->name + STRLEN_SYNCHRONET, svc_name))
, ntsvc_list[i]->name
, ntsvc_list[i]->display_name
, ntsvc_list[i]->description
, path
, ntsvc_list[i]->autostart);
static SC_HANDLE open_service(SC_HANDLE hSCManager, char* name)
{
SC_HANDLE hService;
DWORD err;
if ((hService = OpenService(hSCManager, name, SERVICE_ALL_ACCESS)) == NULL) {
if ((err = GetLastError()) == ERROR_SERVICE_DOES_NOT_EXIST)
printf("Not installed\n");
else
printf("\n!ERROR %d opening service: %s\n", err, name);
}
}
/****************************************************************************/
/* Utility function to remove a service cleanly (stopping if necessary) */
/****************************************************************************/
static void remove_service(SC_HANDLE hSCManager, char* name, char* disp_name)
SC_HANDLE hService;
SERVICE_STATUS status;
printf("Removing: %-*s ... ", STRLEN_MAX_DISPLAY_NAME, disp_name);
if ((hService = open_service(hSCManager, name)) == NULL)
/* try to stop the service */
if (ControlService( hService, SERVICE_CONTROL_STOP, &status))
{
printf("\nStopping: %-*s ... ", STRLEN_MAX_DISPLAY_NAME, disp_name);
while (QueryServiceStatus(hService, &status) && status.dwCurrentState == SERVICE_STOP_PENDING)
if (status.dwCurrentState == SERVICE_STOPPED)
printf("Stopped, ");
else
printf("FAILED!, ");
}
/* now remove the service */
if (DeleteService(hService))
printf("Removed\n");
printf("!ERROR %d\n", GetLastError());
CloseServiceHandle(hService);
/****************************************************************************/
/* Utility function to stop a service */
/****************************************************************************/
static void stop_service(SC_HANDLE hSCManager, char* name, char* disp_name)
{
SC_HANDLE hService;
SERVICE_STATUS status;
printf("Stopping service: %-*s ... ", STRLEN_MAX_DISPLAY_NAME, disp_name);
if ((hService = open_service(hSCManager, name)) == NULL)
return;
/* try to stop the service */
if (ControlService( hService, SERVICE_CONTROL_STOP, &status))
{
while (QueryServiceStatus(hService, &status) && status.dwCurrentState == SERVICE_STOP_PENDING)
Sleep(1000);
if (status.dwCurrentState == SERVICE_STOPPED)
printf("Stopped\n");
else
printf("FAILED!\n");
} else
printf("Already stopped\n");
CloseServiceHandle(hService);
}
/****************************************************************************/
/* Utility function to stop a service */
/****************************************************************************/
static void control_service(SC_HANDLE hSCManager, char* name, char* disp_name, DWORD ctrl)
{
SC_HANDLE hService;
SERVICE_STATUS status;
DWORD err;
printf("%s service: %-*s ... ", control_desc(ctrl), STRLEN_MAX_DISPLAY_NAME, disp_name);
if ((hService = open_service(hSCManager, name)) == NULL)
return;
/* try to stop the service */
if (!ControlService( hService, ctrl, &status)) {
if ((err = GetLastError()) == ERROR_SERVICE_NOT_ACTIVE)
printf("Not active\n");
else
printf("!ERROR %d\n", err);
} else
printf("Successful\n");
CloseServiceHandle(hService);
}
/****************************************************************************/
/* Control one or all services */
/****************************************************************************/
static int control(const char* svc_name, DWORD ctrl)
{
int i;
SC_HANDLE hSCManager;
hSCManager = OpenSCManager(
NULL, /* machine (NULL == local) */
NULL, /* database (NULL == default) */
SC_MANAGER_ALL_ACCESS /* access required */
);
if (hSCManager == NULL) {
fprintf(stderr, "!ERROR %d opening SC manager\n", GetLastError());
}
for (i = 0; ntsvc_list[i] != NULL; i++) {
#if 0
if (svc_name == NULL
&& get_service_info(hSCManager, ntsvc_list[i]->name, NULL) == SERVICE_DISABLED)
continue;
#endif
if (svc_name == NULL /* All? */
|| !stricmp(ntsvc_list[i]->name, svc_name)
|| !stricmp(ntsvc_list[i]->name + STRLEN_SYNCHRONET, svc_name))
switch (ctrl) {
case SERVICE_CONTROL_STOP:
stop_service(hSCManager
, ntsvc_list[i]->name
, ntsvc_list[i]->display_name);
break;
default:
control_service(hSCManager
, ntsvc_list[i]->name
, ntsvc_list[i]->display_name
, ctrl);
break;
}
CloseServiceHandle(hSCManager);
}
/****************************************************************************/
/* Utility function to start a service */
/****************************************************************************/
static void start_service(SC_HANDLE hSCManager, char* name, char* disp_name
, int argc, char** argv)
{
SC_HANDLE hService;
SERVICE_STATUS status;
printf("Starting service: %-*s ... ", STRLEN_MAX_DISPLAY_NAME, disp_name);
if ((hService = open_service(hSCManager, name)) == NULL)
return;
if (QueryServiceStatus(hService, &status) && status.dwCurrentState == SERVICE_RUNNING)
printf("Already running\n");
else {
if (StartService(hService, argc, (LPCTSTR*)argv))
{
while (QueryServiceStatus(hService, &status) && status.dwCurrentState == SERVICE_START_PENDING)
Sleep(1000);
if (status.dwCurrentState == SERVICE_RUNNING)
printf("Started\n");
else
printf("FAILED!\n");
} else
printf("!ERROR %u\n", GetLastError());
}
CloseServiceHandle(hService);
}
/****************************************************************************/
/* Uninstall one or all services */
/****************************************************************************/
int i;
SC_HANDLE hSCManager;
hSCManager = OpenSCManager(
NULL, /* machine (NULL == local) */
NULL, /* database (NULL == default) */
SC_MANAGER_ALL_ACCESS /* access required */
);
if (hSCManager == NULL) {
fprintf(stderr, "!ERROR %d opening SC manager\n", GetLastError());
for (i = 0; ntsvc_list[i] != NULL; i++)
if (svc_name == NULL /* All? */
|| !stricmp(ntsvc_list[i]->name, svc_name)
|| !stricmp(ntsvc_list[i]->name + STRLEN_SYNCHRONET, svc_name))
, ntsvc_list[i]->name
, ntsvc_list[i]->display_name);
CloseServiceHandle(hSCManager);
/****************************************************************************/
/* Utility function to disable a service */
/****************************************************************************/
static void set_service_start_type(SC_HANDLE hSCManager, char* name
, char* disp_name, DWORD start_type)
{
printf("%s service: %-*s ... "