Newer
Older
/* ntsrvcs.c */
/* 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 2005 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;
void (*thread)(void* arg);
void (*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 Server",
"Provides support for Telnet and RLogin 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_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_mask,
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_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_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_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_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, 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;
/* Event Logging */
if((*svc->log_mask)&(1<<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
&str, // pointer to string array
NULL); // pointer to data
}
/****************************************************************************/
/* Event thread local/log print routine */
/****************************************************************************/
static int event_lputs(int level, 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,"logmask") && i+1<argc)
(*svc->log_mask)=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);
}
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
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
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
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);
/****************************************************************************/
/* 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)
return;
// 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)
Sleep(1000);
if(status.dwCurrentState == SERVICE_STOPPED)
printf("Stopped, ");
printf("FAILED!, ");
}
// now remove the service
if(DeleteService(hService))
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;
// 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);
}
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
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
/****************************************************************************/
/* 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, 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
);
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 {
// Start the service
if(StartService( hService, argc, argv))
{
while(QueryServiceStatus(hService, &status) && status.dwCurrentState == SERVICE_START_PENDING)
Sleep(1000);
if(status.dwCurrentState == SERVICE_RUNNING)
printf("Started\n");