Newer
Older
/* Synchronet BBS as a set of Windows NT Services */
/* $Id$ */
/****************************************************************************
* @format.tab-size 4 (Plain Text/Source Code File Header) *
* @format.use-tabs true (see http://www.synchro.net/ptsc_hdr.html) *
* *
* Copyright 2006 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 *
* *
* Anonymous FTP access to the most recent released source is available at *
* ftp://vert.synchro.net, ftp://cvs.synchro.net and ftp://ftp.synchro.net *
* *
* Anonymous CVS access to the development source and modification history *
* is available at cvs.synchro.net:/cvsroot/sbbs, example: *
* cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs login *
* (just hit return, no password is necessary) *
* cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs checkout src *
* *
* For Synchronet coding style and modification guidelines, see *
* http://www.synchro.net/source.html *
* *
* You are encouraged to submit any modifications (preferably in Unix diff *
* format) via e-mail to mods@synchro.net *
* *
* 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;
typedef struct {
char* name;
char* display_name;
char* description;
void* startup;
DWORD* options;
BOOL* recycle_now;
int* log_level;
void DLLCALL (*thread)(void* arg);
void DLLCALL (*terminate)(void);
void (WINAPI *ctrl_handler)(DWORD);
HANDLE log_handle;
BOOL autostart;
BOOL debug;
SERVICE_STATUS status;
SERVICE_STATUS_HANDLE status_handle;
} sbbs_ntsvc_t;
sbbs_ntsvc_t bbs ={
NTSVC_NAME_BBS,
"Synchronet Telnet/RLogin/SSH Server",
"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 */
sbbs_ntsvc_t event ={
NTSVC_NAME_EVENT,
NULL,
NULL,
NULL,
NULL,
&bbs_startup.log_level,
NULL,
NULL,
INVALID_HANDLE_VALUE
};
sbbs_ntsvc_t ftp = {
NTSVC_NAME_FTP,
"Synchronet FTP Server",
"Provides support for FTP clients (including web browsers) 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
};
sbbs_ntsvc_t web = {
NTSVC_NAME_WEB,
"Synchronet Web Server",
"Provides support for Web (HTML/HTTP) clients (browsers).",
&web_startup,
&web_startup.options,
&web_startup.recycle_now,
&web_startup.log_level,
web_server,
web_terminate,
web_ctrl_handler,
INVALID_HANDLE_VALUE
};
sbbs_ntsvc_t mail = {
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",
"Plugin 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)
{
switch(dwCtrlCode) {
case SERVICE_CONTROL_RECYCLE:
*svc->recycle_now=TRUE;
break;
case SERVICE_CONTROL_MUTE:
*svc->options|=BBS_OPT_MUTE;
break;
case SERVICE_CONTROL_UNMUTE:
*svc->options&=~BBS_OPT_MUTE;
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)
{
switch(dwCtrlCode) {
case SERVICE_CONTROL_SYSOP_AVAILABLE:
bbs_startup.options|=BBS_OPT_SYSOP_AVAILABLE;
break;
case SERVICE_CONTROL_SYSOP_UNAVAILABLE:
bbs_startup.options&=~BBS_OPT_SYSOP_AVAILABLE;
break;
default:
svc_ctrl_handler(&bbs, dwCtrlCode);
break;
}
}
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)
{
switch(level) {
case LOG_WARNING:
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;
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);
}
if(svc==NULL)
return(0);
len = strlen(str);
/* Mailslot Logging (for sbbsctrl) */
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) {
sprintf(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) {
if(!WriteFile(svc->log_handle,str,len,&wr,NULL) || wr!=len) {
/* This most likely indicates the server closed the mailslot */
sprintf(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 */
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 */
/****************************************************************************/
/* Event thread local/log print routine */
/****************************************************************************/
static int event_lputs(int level, const char *str)
{
svc_lputs(&event,level,str);
return(0);
}
/************************************/
/* Shared Service Callback Routines */
/************************************/
static void svc_started(void* p)
sbbs_ntsvc_t* svc = (sbbs_ntsvc_t*)p;
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) {
sprintf(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
,NULL /* global_startup */
,NULL ,bbs_startup
,NULL ,ftp_startup
,NULL ,web_startup
,NULL ,mail_startup
,NULL ,services_startup
);
/* close .ini file here */
if(fp!=NULL)
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);
}
sprintf(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) {
sprintf(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 Serivce Install/Uninstall Functions */
/******************************************/
/* ChangeServiceConfig2 is a Win2K+ API function, must call dynamically */
typedef WINADVAPI BOOL (WINAPI *ChangeServiceConfig2_t)(SC_HANDLE, DWORD, LPCVOID);
static void describe_service(HANDLE hSCMlib, SC_HANDLE hService, char* description)
{
ChangeServiceConfig2_t changeServiceConfig2;
static SERVICE_DESCRIPTION service_desc;
if(hSCMlib==NULL)
return;
service_desc.lpDescription=description;
if((changeServiceConfig2 = (ChangeServiceConfig2_t)GetProcAddress(hSCMlib, "ChangeServiceConfig2A"))!=NULL)
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;
sprintf(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);
return(FALSE);
}
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);
return(FALSE);
}
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);
return(FALSE);
}
return(TRUE);
}
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
static const char* start_type_desc(DWORD start_type)
{
static char str[128];
switch(start_type) {
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");
}
sprintf(str,"Start_type: %d", start_type);
return(str);
}
static const char* state_desc(DWORD state)
{
static char str[128];
switch(state) {
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");
}
sprintf(str,"State: %d", state);
return(str);
}
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
static const char* control_desc(DWORD ctrl)
{
static char str[128];
switch(ctrl) {
case SERVICE_CONTROL_STOP:
return("Stopping");
case SERVICE_CONTROL_PAUSE:
return("Pausing");
case SERVICE_CONTROL_CONTINUE:
return("Continuing");
case SERVICE_CONTROL_INTERROGATE:
return("Interrogating");
case SERVICE_CONTROL_SHUTDOWN:
return("Shutting-down");
/* Synchronet-specific */
case SERVICE_CONTROL_RECYCLE:
return("Recycling");
case SERVICE_CONTROL_MUTE:
return("Muting");
case SERVICE_CONTROL_UNMUTE:
return("Un-muting");
case SERVICE_CONTROL_SYSOP_AVAILABLE:
return("Sysop Available");
case SERVICE_CONTROL_SYSOP_UNAVAILABLE:
return("Sysop Unavailable");
}
sprintf(str,"Control: %d", ctrl);
return(str);
}
/****************************************************************************/
/* 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;
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);
return(-1);
}
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());
return(-1);
}
if(state!=NULL && QueryServiceStatus(hService,&status))
*state=status.dwCurrentState;
if((service_config=alloca(size))==NULL) {
printf("\n!ERROR allocating %u bytes of memory\n", size);
return(-1);
}
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());
return(-1);
}
CloseServiceHandle(hService);
return(service_config->dwStartType);
}
/****************************************************************************/
/* Utility function to create a service with description (on Win2K+) */
/****************************************************************************/
static SC_HANDLE create_service(HANDLE hSCMlib, SC_HANDLE hSCManager
,char* name, char* display_name, char* description, char* path
,BOOL autostart)
DWORD err;
DWORD start_type = autostart ? SERVICE_AUTO_START : SERVICE_DEMAND_START;
printf("Installing service: %-*s ... ", STRLEN_MAX_DISPLAY_NAME, display_name);
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);
}
else {
describe_service(hSCMlib, hService,description);
CloseServiceHandle(hService);
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;
HANDLE hSCMlib;
SC_HANDLE hSCManager;
char path[MAX_PATH+1];
printf("Installing Synchronet NT Services...\n");
hSCMlib = LoadLibrary("ADVAPI32.DLL");
if(GetModuleFileName(NULL,path,sizeof(path))==0)
{
fprintf(stderr,"!ERROR %d getting module file name\n",GetLastError());
return(-1);
}
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());
return(-1);
}
for(i=0;ntsvc_list[i]!=NULL;i++)
|| !stricmp(ntsvc_list[i]->name, svc_name)
|| !stricmp(ntsvc_list[i]->name+STRLEN_SYNCHRONET, svc_name))
create_service(hSCMlib
,hSCManager
,ntsvc_list[i]->name
,ntsvc_list[i]->display_name
,ntsvc_list[i]->description
,path
,ntsvc_list[i]->autostart);
if(hSCMlib!=NULL)
FreeLibrary(hSCMlib);
CloseServiceHandle(hSCManager);
return(0);
}
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);
return(NULL);
}
return(hService);
}
/****************************************************************************/
/* 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)
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)
Sleep(1000);
if(status.dwCurrentState == SERVICE_STOPPED)
printf("Stopped, ");
printf("FAILED!, ");
printf("Removed\n");
else
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;
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;
if(!ControlService( hService, SERVICE_CONTROL_STOP, &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 */
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
);
if(hSCManager==NULL) {
fprintf(stderr,"!ERROR %d opening SC manager\n",GetLastError());
return(-1);
}
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);
return(0);
}
/****************************************************************************/
/* 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))