|
|
1.1 root 1: /* ntsrvcs.c */
2:
3: /* Synchronet BBS as a set of Windows NT Services */
4:
5: /* $Id: ntsvcs.c,v 1.24 2004/12/04 16:45:30 rswindell Exp $ */
6:
7: /****************************************************************************
8: * @format.tab-size 4 (Plain Text/Source Code File Header) *
9: * @format.use-tabs true (see http://www.synchro.net/ptsc_hdr.html) *
10: * *
11: * Copyright 2004 Rob Swindell - http://www.synchro.net/copyright.html *
12: * *
13: * This program is free software; you can redistribute it and/or *
14: * modify it under the terms of the GNU General Public License *
15: * as published by the Free Software Foundation; either version 2 *
16: * of the License, or (at your option) any later version. *
17: * See the GNU General Public License for more details: gpl.txt or *
18: * http://www.fsf.org/copyleft/gpl.html *
19: * *
20: * Anonymous FTP access to the most recent released source is available at *
21: * ftp://vert.synchro.net, ftp://cvs.synchro.net and ftp://ftp.synchro.net *
22: * *
23: * Anonymous CVS access to the development source and modification history *
24: * is available at cvs.synchro.net:/cvsroot/sbbs, example: *
25: * cvs -d :pserver:[email protected]:/cvsroot/sbbs login *
26: * (just hit return, no password is necessary) *
27: * cvs -d :pserver:[email protected]:/cvsroot/sbbs checkout src *
28: * *
29: * For Synchronet coding style and modification guidelines, see *
30: * http://www.synchro.net/source.html *
31: * *
32: * You are encouraged to submit any modifications (preferably in Unix diff *
33: * format) via e-mail to [email protected] *
34: * *
35: * Note: If this box doesn't appear square, then you need to fix your tabs. *
36: ****************************************************************************/
37:
38: /* Synchronet-specific headers */
39: #include "sbbs.h" /* various */
40: #include "sbbs_ini.h" /* sbbs_read_ini() */
41: #include "ftpsrvr.h" /* ftp_startup_t, ftp_server */
42: #include "websrvr.h" /* web_startup_t, web_server */
43: #include "mailsrvr.h" /* mail_startup_t, mail_server */
44: #include "services.h" /* services_startup_t, services_thread */
45: #include "ntsvcs.h" /* NT service names */
46:
47: /* Windows-specific headers */
48: #include <winsvc.h>
49:
50: #define NTSVC_TIMEOUT_STARTUP 30000 /* Milliseconds */
51: #define NTSVC_TIMEOUT_TERMINATE 30000 /* Milliseconds */
52:
53:
54: static void WINAPI bbs_ctrl_handler(DWORD dwCtrlCode);
55: static void WINAPI ftp_ctrl_handler(DWORD dwCtrlCode);
56: static void WINAPI web_ctrl_handler(DWORD dwCtrlCode);
57: static void WINAPI mail_ctrl_handler(DWORD dwCtrlCode);
58: static void WINAPI services_ctrl_handler(DWORD dwCtrlCode);
59:
60: /* Global variables */
61:
62: char ini_file[MAX_PATH+1];
63: bbs_startup_t bbs_startup;
64: ftp_startup_t ftp_startup;
65: mail_startup_t mail_startup;
66: services_startup_t services_startup;
67: web_startup_t web_startup;
68:
69: typedef struct {
70: char* name;
71: char* display_name;
72: char* description;
73: void* startup;
74: DWORD* options;
75: BOOL* recycle_now;
76: DWORD* log_mask;
77: void (*thread)(void* arg);
78: void (*terminate)(void);
79: void (WINAPI *ctrl_handler)(DWORD);
80: HANDLE log_handle;
81: HANDLE event_handle;
82: BOOL autostart;
83: BOOL debug;
84: SERVICE_STATUS status;
85: SERVICE_STATUS_HANDLE status_handle;
86: } sbbs_ntsvc_t;
87:
88: sbbs_ntsvc_t bbs ={
89: NTSVC_NAME_BBS,
90: "Synchronet Telnet/RLogin Server",
91: "Provides support for Telnet and RLogin clients and executes timed events. " \
92: "This service provides the critical functions of your Synchronet BBS.",
93: &bbs_startup,
94: &bbs_startup.options,
95: &bbs_startup.recycle_now,
96: &bbs_startup.log_mask,
97: bbs_thread,
98: bbs_terminate,
99: bbs_ctrl_handler,
100: INVALID_HANDLE_VALUE
101: };
102:
103: /* This is not (currently) a separate service, use this for logging only */
104: sbbs_ntsvc_t event ={
105: NTSVC_NAME_EVENT,
106: NULL,
107: NULL,
108: NULL,
109: NULL,
110: NULL,
111: &bbs_startup.log_mask,
112: NULL,
113: NULL,
114: NULL,
115: INVALID_HANDLE_VALUE
116: };
117:
118: sbbs_ntsvc_t ftp = {
119: NTSVC_NAME_FTP,
120: "Synchronet FTP Server",
121: "Provides support for FTP clients (including web browsers) for file transfers.",
122: &ftp_startup,
123: &ftp_startup.options,
124: &ftp_startup.recycle_now,
125: &ftp_startup.log_mask,
126: ftp_server,
127: ftp_terminate,
128: ftp_ctrl_handler,
129: INVALID_HANDLE_VALUE
130: };
131:
132: sbbs_ntsvc_t web = {
133: NTSVC_NAME_WEB,
134: "Synchronet Web Server",
135: "Provides support for Web (HTML/HTTP) clients (browsers).",
136: &web_startup,
137: &web_startup.options,
138: &web_startup.recycle_now,
139: &web_startup.log_mask,
140: web_server,
141: web_terminate,
142: web_ctrl_handler,
143: INVALID_HANDLE_VALUE
144: };
145:
146: sbbs_ntsvc_t mail = {
147: NTSVC_NAME_MAIL,
148: "Synchronet SMTP/POP3 Mail Server",
149: "Sends and receives Internet e-mail (using SMTP) and allows users to remotely " \
150: "access their e-mail using an Internet mail client (using POP3).",
151: &mail_startup,
152: &mail_startup.options,
153: &mail_startup.recycle_now,
154: &mail_startup.log_mask,
155: mail_server,
156: mail_terminate,
157: mail_ctrl_handler,
158: INVALID_HANDLE_VALUE
159: };
160:
161: sbbs_ntsvc_t services = {
162: NTSVC_NAME_SERVICES,
163: "Synchronet Services",
164: "Plugin servers (usually in JavaScript) for any TCP/UDP protocol. " \
165: "Stock services include Finger, Gopher, NNTP, and IRC. Edit your ctrl/services.ini " \
166: "file for configuration of individual Synchronet Services.",
167: &services_startup,
168: &services_startup.options,
169: &services_startup.recycle_now,
170: &services_startup.log_mask,
171: services_thread,
172: services_terminate,
173: services_ctrl_handler,
174: INVALID_HANDLE_VALUE
175: };
176:
177: /* This list is used for enumerating all services */
178: sbbs_ntsvc_t* ntsvc_list[] = {
179: &bbs,
180: &ftp,
181: &web,
182: &mail,
183: &services,
184: NULL
185: };
186:
187: /****************************************/
188: /* Service Control Handlers (Callbacks) */
189: /****************************************/
190:
191: /* Common control handler for all services */
192: static void svc_ctrl_handler(sbbs_ntsvc_t* svc, DWORD dwCtrlCode)
193: {
194: switch(dwCtrlCode) {
195: case SERVICE_CONTROL_RECYCLE:
196: *svc->recycle_now=TRUE;
197: break;
198: case SERVICE_CONTROL_MUTE:
199: *svc->options|=BBS_OPT_MUTE;
200: break;
201: case SERVICE_CONTROL_UNMUTE:
202: *svc->options&=~BBS_OPT_MUTE;
203: break;
204: case SERVICE_CONTROL_STOP:
205: case SERVICE_CONTROL_SHUTDOWN:
206: svc->terminate();
207: svc->status.dwWaitHint=NTSVC_TIMEOUT_TERMINATE;
208: svc->status.dwCurrentState=SERVICE_STOP_PENDING;
209: break;
210: }
211: SetServiceStatus(svc->status_handle, &svc->status);
212: }
213:
214: /* Service-specific control handler stub functions */
215: static void WINAPI bbs_ctrl_handler(DWORD dwCtrlCode)
216: {
217: switch(dwCtrlCode) {
218: case SERVICE_CONTROL_SYSOP_AVAILABLE:
219: bbs_startup.options|=BBS_OPT_SYSOP_AVAILABLE;
220: break;
221: case SERVICE_CONTROL_SYSOP_UNAVAILABLE:
222: bbs_startup.options&=~BBS_OPT_SYSOP_AVAILABLE;
223: break;
224: default:
225: svc_ctrl_handler(&bbs, dwCtrlCode);
226: break;
227: }
228: }
229:
230: static void WINAPI ftp_ctrl_handler(DWORD dwCtrlCode)
231: {
232: svc_ctrl_handler(&ftp, dwCtrlCode);
233: }
234:
235: static void WINAPI web_ctrl_handler(DWORD dwCtrlCode)
236: {
237: svc_ctrl_handler(&web, dwCtrlCode);
238: }
239:
240: static void WINAPI mail_ctrl_handler(DWORD dwCtrlCode)
241: {
242: svc_ctrl_handler(&mail, dwCtrlCode);
243: }
244:
245: static void WINAPI services_ctrl_handler(DWORD dwCtrlCode)
246: {
247: svc_ctrl_handler(&services, dwCtrlCode);
248: }
249:
250: static WORD event_type(int level)
251: {
252: switch(level) {
253: case LOG_WARNING:
254: return(EVENTLOG_WARNING_TYPE);
255: case LOG_NOTICE:
256: case LOG_INFO:
257: case LOG_DEBUG:
258: return(EVENTLOG_INFORMATION_TYPE); /* same as EVENT_LOG_SUCCESS */
259: }
260: /*
261: LOG_EMERG
262: LOG_ALERT
263: LOG_CRIT
264: LOG_ERR
265: */
266: return(EVENTLOG_ERROR_TYPE);
267: }
268:
269: /**************************************/
270: /* Common Service Log Ouptut Function */
271: /**************************************/
272: static int svc_lputs(void* p, int level, char* str)
273: {
274: char debug[1024];
275: char fname[256];
276: DWORD len;
277: DWORD wr;
278: sbbs_ntsvc_t* svc = (sbbs_ntsvc_t*)p;
279:
280: /* Debug Logging */
281: if(svc==NULL || svc->debug) {
282: snprintf(debug,sizeof(debug),"%s: %s",svc==NULL ? "Synchronet" : svc->name, str);
283: OutputDebugString(debug);
284: }
285: if(svc==NULL)
286: return(0);
287:
288: len = strlen(str);
289:
290: /* Mailslot Logging (for sbbsctrl) */
291: if(svc->log_handle != INVALID_HANDLE_VALUE /* Invalid log handle? */
292: && !GetMailslotInfo(svc->log_handle, NULL, NULL, NULL, NULL)) {
293: /* Close and try to re-open */
294: CloseHandle(svc->log_handle);
295: svc->log_handle=INVALID_HANDLE_VALUE;
296: }
297:
298: if(svc->log_handle == INVALID_HANDLE_VALUE) {
299: sprintf(fname,"\\\\.\\mailslot\\%s.log",svc->name);
300: svc->log_handle = CreateFile(
301: fname, // pointer to name of the file
302: GENERIC_WRITE, // access (read-write) mode
303: FILE_SHARE_READ, // share mode
304: NULL, // pointer to security attributes
305: OPEN_EXISTING, // how to create
306: FILE_ATTRIBUTE_NORMAL, // file attributes
307: NULL // handle to file with attributes to copy
308: );
309: }
310: if(svc->log_handle != INVALID_HANDLE_VALUE) {
311: if(!WriteFile(svc->log_handle,str,len,&wr,NULL) || wr!=len) {
312: /* This most likely indicates the server closed the mailslot */
313: sprintf(debug,"!ERROR %d writing %u bytes to %s pipe (wr=%d)"
314: ,GetLastError(),len,svc->name,wr);
315: OutputDebugString(debug);
316: /* So close the handle and attempt re-open next time */
317: CloseHandle(svc->log_handle);
318: svc->log_handle=INVALID_HANDLE_VALUE;
319: }
320: }
321:
322: /* Event Logging */
323: if((*svc->log_mask)&(1<<level)) {
324: if(svc->event_handle == NULL)
325: svc->event_handle = RegisterEventSource(
326: NULL, // server name for source (NULL = local computer)
327: svc->name // source name for registered handle
328: );
329: if(svc->event_handle != NULL)
330: ReportEvent(svc->event_handle, // event log handle
331: event_type(level), // event type
332: 0, // category zero
333: 0, // event identifier
334: NULL, // no user security identifier
335: 1, // one string
336: 0, // no data
337: &str, // pointer to string array
338: NULL); // pointer to data
339: }
340:
341: return(0);
342: }
343:
344: /****************************************************************************/
345: /* Event thread local/log print routine */
346: /****************************************************************************/
347: static int event_lputs(int level, char *str)
348: {
349: svc_lputs(&event,level,str);
350: return(0);
351: }
352:
353: /************************************/
354: /* Shared Service Callback Routines */
355: /************************************/
356:
357: static void svc_started(void* p)
358: {
359: sbbs_ntsvc_t* svc = (sbbs_ntsvc_t*)p;
360:
361: svc->status.dwCurrentState=SERVICE_RUNNING;
362: svc->status.dwControlsAccepted|=SERVICE_ACCEPT_STOP;
363: SetServiceStatus(svc->status_handle, &svc->status);
364: }
365:
366: static void svc_recycle(void *p)
367: {
368: char str[MAX_PATH*2];
369: FILE* fp;
370: sbbs_ntsvc_t* svc = (sbbs_ntsvc_t*)p;
371: bbs_startup_t* bbs_startup=NULL;
372: ftp_startup_t* ftp_startup=NULL;
373: mail_startup_t* mail_startup=NULL;
374: services_startup_t* services_startup=NULL;
375: web_startup_t* web_startup=NULL;
376:
377: if(svc==&bbs)
378: bbs_startup=svc->startup;
379: else if(svc==&ftp)
380: ftp_startup=svc->startup;
381: else if(svc==&web)
382: web_startup=svc->startup;
383: else if(svc==&mail)
384: mail_startup=svc->startup;
385: else if(svc==&services)
386: services_startup=svc->startup;
387:
388: SAFEPRINTF(str,"Reading %s",ini_file);
389: svc_lputs(svc,LOG_INFO,str);
390:
391: /* Read .ini file here */
392: fp=fopen(ini_file,"r");
393:
394: /* We call this function to set defaults, even if there's no .ini file */
395: sbbs_read_ini(fp
396: ,NULL /* global_startup */
397: ,NULL ,bbs_startup
398: ,NULL ,ftp_startup
399: ,NULL ,web_startup
400: ,NULL ,mail_startup
401: ,NULL ,services_startup
402: );
403:
404: /* close .ini file here */
405: if(fp!=NULL)
406: fclose(fp);
407: }
408:
409: static void svc_terminated(void* p, int code)
410: {
411: sbbs_ntsvc_t* svc = (sbbs_ntsvc_t*)p;
412:
413: if(code) {
414: svc->status.dwWin32ExitCode=ERROR_SERVICE_SPECIFIC_ERROR;
415: svc->status.dwServiceSpecificExitCode=code;
416: SetServiceStatus(svc->status_handle, &svc->status);
417: }
418: }
419:
420: static void svc_clients(void* p, int active)
421: {
422: sbbs_ntsvc_t* svc = (sbbs_ntsvc_t*)p;
423: }
424:
425: /***************/
426: /* ServiceMain */
427: /***************/
428:
429: /* Common ServiceMain for all services */
430: static void WINAPI svc_main(sbbs_ntsvc_t* svc, DWORD argc, LPTSTR *argv)
431: {
432: char str[256];
433: DWORD i;
434: char* arg;
435:
436: for(i=0;i<argc;i++) {
437: arg=argv[i];
438: if(*arg=='-' || *arg=='/')
439: arg++;
440: if(!stricmp(arg,"debug"))
441: svc->debug=TRUE;
442: if(!stricmp(arg,"logmask") && i+1<argc)
443: (*svc->log_mask)=strtol(argv[++i],NULL,0);
444: }
445:
446: sprintf(str,"Starting NT Service: %s",svc->display_name);
447: svc_lputs(svc,LOG_INFO,str);
448:
449: if((svc->status_handle = RegisterServiceCtrlHandler(svc->name, svc->ctrl_handler))==0) {
450: sprintf(str,"!ERROR %d registering service control handler",GetLastError());
451: svc_lputs(NULL,LOG_ERR,str);
452: return;
453: }
454:
455: memset(&svc->status,0,sizeof(SERVICE_STATUS));
456: svc->status.dwServiceType=SERVICE_WIN32_SHARE_PROCESS;
457: svc->status.dwControlsAccepted=SERVICE_ACCEPT_SHUTDOWN;
458: svc->status.dwWaitHint=NTSVC_TIMEOUT_STARTUP;
459:
460: svc->status.dwCurrentState=SERVICE_START_PENDING;
461: SetServiceStatus(svc->status_handle, &svc->status);
462:
463: svc->thread(svc->startup);
464:
465: svc->status.dwCurrentState=SERVICE_STOPPED;
466: SetServiceStatus(svc->status_handle, &svc->status);
467:
468: if(svc->log_handle!=INVALID_HANDLE_VALUE) {
469: CloseHandle(svc->log_handle);
470: svc->log_handle=INVALID_HANDLE_VALUE;
471: }
472:
473: if(svc->event_handle!=NULL) {
474: DeregisterEventSource(svc->event_handle);
475: svc->event_handle=NULL;
476: }
477: }
478:
479: /* Service-specific ServiceMain stub functions */
480:
481: static void WINAPI bbs_start(DWORD dwArgc, LPTSTR *lpszArgv)
482: {
483: svc_main(&bbs, dwArgc, lpszArgv);
484:
485: /* Events are (currently) part of the BBS service */
486: if(event.log_handle!=INVALID_HANDLE_VALUE) {
487: CloseHandle(event.log_handle);
488: event.log_handle=INVALID_HANDLE_VALUE;
489: }
490: }
491:
492: static void WINAPI ftp_start(DWORD dwArgc, LPTSTR *lpszArgv)
493: {
494: svc_main(&ftp, dwArgc, lpszArgv);
495: }
496:
497: static void WINAPI web_start(DWORD dwArgc, LPTSTR *lpszArgv)
498: {
499: svc_main(&web, dwArgc, lpszArgv);
500: }
501:
502: static void WINAPI mail_start(DWORD dwArgc, LPTSTR *lpszArgv)
503: {
504: svc_main(&mail, dwArgc, lpszArgv);
505: }
506:
507: static void WINAPI services_start(DWORD dwArgc, LPTSTR *lpszArgv)
508: {
509: svc_main(&services, dwArgc, lpszArgv);
510: }
511:
512: /******************************************/
513: /* NT Serivce Install/Uninstall Functions */
514: /******************************************/
515:
516: /* ChangeServiceConfig2 is a Win2K+ API function, must call dynamically */
517: typedef WINADVAPI BOOL (WINAPI *ChangeServiceConfig2_t)(SC_HANDLE, DWORD, LPCVOID);
518:
519: static void describe_service(HANDLE hSCMlib, SC_HANDLE hService, char* description)
520: {
521: ChangeServiceConfig2_t changeServiceConfig2;
522: static SERVICE_DESCRIPTION service_desc;
523:
524: if(hSCMlib==NULL)
525: return;
526:
527: service_desc.lpDescription=description;
528:
529: if((changeServiceConfig2 = (ChangeServiceConfig2_t)GetProcAddress(hSCMlib, "ChangeServiceConfig2A"))!=NULL)
530: changeServiceConfig2(hService, SERVICE_CONFIG_DESCRIPTION, &service_desc);
531: }
532:
533: static BOOL register_event_source(char* name, char* path)
534: {
535: char keyname[256];
536: HKEY hKey;
537: DWORD type;
538: DWORD disp;
539: LONG retval;
540: char* value;
541:
542: sprintf(keyname,"system\\CurrentControlSet\\services\\eventlog\\application\\%s",name);
543:
544: retval=RegCreateKeyEx(
545: HKEY_LOCAL_MACHINE, // handle to an open key
546: keyname, // address of subkey name
547: 0, // reserved
548: "", // address of class string
549: 0, // special options flag
550: KEY_ALL_ACCESS, // desired security access
551: NULL, // address of key security structure
552: &hKey, // address of buffer for opened handle
553: &disp // address of disposition value buffer
554: );
555:
556: if(retval!=ERROR_SUCCESS) {
557: fprintf(stderr,"!Error %d creating/opening registry key (HKLM\\%s)\n"
558: ,retval,keyname);
559: return(FALSE);
560: }
561:
562: value="EventMessageFile";
563: retval=RegSetValueEx(
564: hKey, // handle to key to set value for
565: value, // name of the value to set
566: 0, // reserved
567: REG_SZ, // flag for value type
568: path, // address of value data
569: strlen(path) // size of value data
570: );
571:
572: if(retval!=ERROR_SUCCESS) {
573: RegCloseKey(hKey);
574: fprintf(stderr,"!Error %d setting registry key value (%s)\n"
575: ,retval,value);
576: return(FALSE);
577: }
578:
579: value="TypesSupported";
580: type=EVENTLOG_ERROR_TYPE | EVENTLOG_WARNING_TYPE | EVENTLOG_INFORMATION_TYPE;
581: retval=RegSetValueEx(
582: hKey, // handle to key to set value for
583: value, // name of the value to set
584: 0, // reserved
585: REG_DWORD, // flag for value type
586: (BYTE*)&type, // address of value data
587: sizeof(type) // size of value data
588: );
589:
590: RegCloseKey(hKey);
591:
592: if(retval!=ERROR_SUCCESS) {
593: fprintf(stderr,"!Error %d setting registry key value (%s)\n"
594: ,retval,value);
595: return(FALSE);
596: }
597:
598: return(TRUE);
599: }
600:
601: /****************************************************************************/
602: /* Utility function to create a service with description (on Win2K+) */
603: /****************************************************************************/
604: static SC_HANDLE create_service(HANDLE hSCMlib, SC_HANDLE hSCManager
605: ,char* name, char* display_name, char* description, char* path
606: ,BOOL autostart)
607: {
608: SC_HANDLE hService;
609:
610: printf("Installing service: %-40s ... ", display_name);
611:
612: hService = CreateService(
613: hSCManager, // SCManager database
614: name, // name of service
615: display_name, // name to display
616: SERVICE_ALL_ACCESS, // desired access
617: SERVICE_WIN32_SHARE_PROCESS, // service type
618: autostart // start type (auto or manual)
619: ? SERVICE_AUTO_START : SERVICE_DEMAND_START,
620: SERVICE_ERROR_NORMAL, // error control type
621: path, // service's binary
622: NULL, // no load ordering group
623: NULL, // no tag identifier
624: "", // dependencies
625: NULL, // LocalSystem account
626: NULL); // no password
627:
628: if(hService==NULL)
629: printf("!ERROR %d\n",GetLastError());
630: else {
631: describe_service(hSCMlib, hService,description);
632: CloseServiceHandle(hService);
633: printf("Successful\n");
634:
635: register_event_source(name,path);
636: }
637:
638: return(hService);
639: }
640:
641: /****************************************************************************/
642: /* Install one or all services */
643: /****************************************************************************/
644: static int install(const char* svc_name)
645: {
646: int i;
647: HANDLE hSCMlib;
648: SC_HANDLE hSCManager;
649: char path[MAX_PATH+1];
650:
651: printf("Installing Synchronet NT Services...\n");
652:
653: hSCMlib = LoadLibrary("ADVAPI32.DLL");
654:
655: if(GetModuleFileName(NULL,path,sizeof(path))==0)
656: {
657: fprintf(stderr,"!ERROR %d getting module file name\n",GetLastError());
658: return(-1);
659: }
660:
661: hSCManager = OpenSCManager(
662: NULL, // machine (NULL == local)
663: NULL, // database (NULL == default)
664: SC_MANAGER_ALL_ACCESS // access required
665: );
666: if(hSCManager==NULL) {
667: fprintf(stderr,"!ERROR %d opening SC manager\n",GetLastError());
668: return(-1);
669: }
670:
671: for(i=0;ntsvc_list[i]!=NULL;i++)
672: if(svc_name==NULL /* All? */
673: || !stricmp(ntsvc_list[i]->name, svc_name))
674: create_service(hSCMlib
675: ,hSCManager
676: ,ntsvc_list[i]->name
677: ,ntsvc_list[i]->display_name
678: ,ntsvc_list[i]->description
679: ,path
680: ,ntsvc_list[i]->autostart);
681:
682: if(hSCMlib!=NULL)
683: FreeLibrary(hSCMlib);
684:
685: CloseServiceHandle(hSCManager);
686:
687: return(0);
688: }
689:
690: /****************************************************************************/
691: /* Utility function to remove a service cleanly (stopping if necessary) */
692: /****************************************************************************/
693: static void remove_service(SC_HANDLE hSCManager, char* name, char* disp_name)
694: {
695: SC_HANDLE hService;
696: SERVICE_STATUS status;
697:
698: printf("Removing service: %-40s ... ", disp_name);
699:
700: hService = OpenService(hSCManager, name, SERVICE_ALL_ACCESS);
701:
702: if(hService==NULL) {
703: printf("\n!ERROR %d opening service: %s\n",GetLastError(),name);
704: return;
705: }
706:
707: // try to stop the service
708: if(ControlService( hService, SERVICE_CONTROL_STOP, &status))
709: {
710: printf("\nStopping: %s ... ",name);
711:
712: while(QueryServiceStatus(hService, &status) && status.dwCurrentState == SERVICE_STOP_PENDING)
713: Sleep(1000);
714:
715: if(status.dwCurrentState == SERVICE_STOPPED)
716: printf("Stopped.\n");
717: else
718: printf("FAILED!\n");
719: }
720:
721: // now remove the service
722: if(DeleteService(hService))
723: printf("Successful\n");
724: else
725: printf("!ERROR %d\n",GetLastError());
726: CloseServiceHandle(hService);
727: }
728:
729: /****************************************************************************/
730: /* Uninstall one or all services */
731: /****************************************************************************/
732: static int uninstall(const char* svc_name)
733: {
734: int i;
735: SC_HANDLE hSCManager;
736:
737: hSCManager = OpenSCManager(
738: NULL, // machine (NULL == local)
739: NULL, // database (NULL == default)
740: SC_MANAGER_ALL_ACCESS // access required
741: );
742: if(hSCManager==NULL) {
743: fprintf(stderr,"!ERROR %d opening SC manager\n",GetLastError());
744: return(-1);
745: }
746:
747: for(i=0;ntsvc_list[i]!=NULL;i++)
748: if(svc_name==NULL /* All? */
749: || !stricmp(ntsvc_list[i]->name, svc_name))
750: remove_service(hSCManager
751: ,ntsvc_list[i]->name
752: ,ntsvc_list[i]->display_name);
753:
754: CloseServiceHandle(hSCManager);
755:
756: return(0);
757: }
758:
759: /****************************************************************************/
760: /* Utility function to disable a service */
761: /****************************************************************************/
762: static void set_service_start_type(SC_HANDLE hSCManager, char* name
763: ,char* disp_name, DWORD start_type)
764: {
765: SC_HANDLE hService;
766:
767: printf("%s service: %-40s ... "
768: ,start_type==SERVICE_DISABLED ? "Disabling" : "Enabling", disp_name);
769:
770: hService = OpenService(hSCManager, name, SERVICE_ALL_ACCESS);
771:
772: if(hService==NULL) {
773: printf("\n!ERROR %d opening service: %s\n",GetLastError(),name);
774: return;
775: }
776:
777: if(!ChangeServiceConfig(
778: hService, // handle to service
779: SERVICE_NO_CHANGE, // type of service
780: start_type, // when to start service
781: SERVICE_NO_CHANGE, // severity if service fails to start
782: NULL, // pointer to service binary file name
783: NULL, // pointer to load ordering group name
784: NULL, // pointer to variable to get tag identifier
785: NULL, // pointer to array of dependency names
786: NULL, // pointer to account name of service
787: NULL, // pointer to password for service account
788: NULL // pointer to display name
789: ))
790: printf("\n!ERROR %d changing service config for: %s\n",GetLastError(),name);
791: else
792: printf("Successful\n");
793:
794: CloseServiceHandle(hService);
795: }
796:
797: /****************************************************************************/
798: /* Enable (set to auto-start) or disable one or all services */
799: /****************************************************************************/
800: static int enable(const char* svc_name, BOOL enabled)
801: {
802: int i;
803: SC_HANDLE hSCManager;
804:
805: hSCManager = OpenSCManager(
806: NULL, // machine (NULL == local)
807: NULL, // database (NULL == default)
808: SC_MANAGER_ALL_ACCESS // access required
809: );
810: if(hSCManager==NULL) {
811: fprintf(stderr,"!ERROR %d opening SC manager\n",GetLastError());
812: return(-1);
813: }
814:
815: for(i=0;ntsvc_list[i]!=NULL;i++)
816: if(svc_name==NULL /* All? */
817: || !stricmp(ntsvc_list[i]->name, svc_name))
818: set_service_start_type(hSCManager
819: ,ntsvc_list[i]->name
820: ,ntsvc_list[i]->display_name
821: ,enabled ? SERVICE_AUTO_START : SERVICE_DISABLED);
822:
823: CloseServiceHandle(hSCManager);
824:
825: return(0);
826: }
827:
828:
829: /****************************************************************************/
830: /* Main Entry Point */
831: /****************************************************************************/
832: int main(int argc, char** argv)
833: {
834: char* ctrl_dir;
835: char* arg;
836: char* p;
837: char str[MAX_PATH+1];
838: int i;
839: FILE* fp=NULL;
840:
841: SERVICE_TABLE_ENTRY ServiceDispatchTable[] =
842: {
843: { bbs.name, bbs_start },
844: { ftp.name, ftp_start },
845: { web.name, web_start },
846: { mail.name, mail_start },
847: { services.name, services_start },
848: { NULL, NULL } /* Terminator */
849: };
850:
851: printf("\nSynchronet NT Services Version %s%c %s\n\n"
852: ,VERSION,REVISION,COPYRIGHT_NOTICE);
853:
854: ctrl_dir=getenv("SBBSCTRL"); /* read from environment variable */
855: if(ctrl_dir==NULL || ctrl_dir[0]==0) {
856: ctrl_dir="\\sbbs\\ctrl"; /* Not set? Use default */
857: printf("!SBBSCTRL environment variable not set, using default value: %s\n\n"
858: ,ctrl_dir);
859: }
860:
861: sbbs_get_ini_fname(ini_file, ctrl_dir, NULL /* auto-host_name */);
862:
863: /* Initialize BBS startup structure */
864: memset(&bbs_startup,0,sizeof(bbs_startup));
865: bbs_startup.size=sizeof(bbs_startup);
866: bbs_startup.cbdata=&bbs;
867: bbs_startup.lputs=svc_lputs;
868: bbs_startup.event_lputs=event_lputs;
869: bbs_startup.started=svc_started;
870: bbs_startup.recycle=svc_recycle;
871: bbs_startup.terminated=svc_terminated;
872: bbs_startup.clients=svc_clients;
873: strcpy(bbs_startup.ctrl_dir,ctrl_dir);
874:
875: /* Initialize FTP startup structure */
876: memset(&ftp_startup,0,sizeof(ftp_startup));
877: ftp_startup.cbdata=&ftp;
878: ftp_startup.size=sizeof(ftp_startup);
879: ftp_startup.lputs=svc_lputs;
880: ftp_startup.started=svc_started;
881: ftp_startup.recycle=svc_recycle;
882: ftp_startup.terminated=svc_terminated;
883: ftp_startup.clients=svc_clients;
884: strcpy(ftp_startup.ctrl_dir,ctrl_dir);
885:
886: /* Initialize Web Server startup structure */
887: memset(&web_startup,0,sizeof(web_startup));
888: web_startup.cbdata=&web;
889: web_startup.size=sizeof(web_startup);
890: web_startup.lputs=svc_lputs;
891: web_startup.started=svc_started;
892: web_startup.recycle=svc_recycle;
893: web_startup.terminated=svc_terminated;
894: web_startup.clients=svc_clients;
895: strcpy(web_startup.ctrl_dir,ctrl_dir);
896:
897: /* Initialize Mail Server startup structure */
898: memset(&mail_startup,0,sizeof(mail_startup));
899: mail_startup.cbdata=&mail;
900: mail_startup.size=sizeof(mail_startup);
901: mail_startup.lputs=svc_lputs;
902: mail_startup.started=svc_started;
903: mail_startup.recycle=svc_recycle;
904: mail_startup.terminated=svc_terminated;
905: mail_startup.clients=svc_clients;
906: strcpy(mail_startup.ctrl_dir,ctrl_dir);
907:
908: /* Initialize Services startup structure */
909: memset(&services_startup,0,sizeof(services_startup));
910: services_startup.cbdata=&services;
911: services_startup.size=sizeof(services_startup);
912: services_startup.lputs=svc_lputs;
913: services_startup.started=svc_started;
914: services_startup.recycle=svc_recycle;
915: services_startup.terminated=svc_terminated;
916: services_startup.clients=svc_clients;
917: strcpy(services_startup.ctrl_dir,ctrl_dir);
918:
919: /* Read .ini file here */
920: if((fp=fopen(ini_file,"r"))!=NULL) {
921: sprintf(str,"Reading %s",ini_file);
922: svc_lputs(NULL,LOG_INFO,str);
923: }
924:
925: /* We call this function to set defaults, even if there's no .ini file */
926: sbbs_read_ini(fp
927: ,NULL /* global_startup */
928: ,&bbs.autostart ,&bbs_startup
929: ,&ftp.autostart ,&ftp_startup
930: ,&web.autostart ,&web_startup
931: ,&mail.autostart ,&mail_startup
932: ,&services.autostart ,&services_startup
933: );
934:
935: /* close .ini file here */
936: if(fp!=NULL)
937: fclose(fp);
938:
939: ctrl_dir = bbs_startup.ctrl_dir;
940: if(chdir(ctrl_dir)!=0) {
941: sprintf(str,"!ERROR %d changing directory to: %s", errno, ctrl_dir);
942: svc_lputs(NULL,LOG_ERR,str);
943: }
944:
945: for(i=1;i<argc;i++) {
946: arg=argv[i];
947: while(*arg=='-')
948: arg++;
949: if(!stricmp(arg,"install"))
950: return install(argv[i+1]);
951:
952: if(!stricmp(arg,"remove"))
953: return uninstall(argv[i+1]);
954:
955: if(!stricmp(arg,"disable"))
956: return enable(argv[i+1], FALSE);
957:
958: if(!stricmp(arg,"enable"))
959: return enable(argv[i+1], TRUE);
960: }
961:
962: printf("Available Services:\n\n");
963: printf("%-20s %s\n","Name","Description");
964: printf("%-20s %s\n","----","-----------");
965: for(i=0;ntsvc_list[i]!=NULL;i++)
966: printf("%-20s %s\n",ntsvc_list[i]->name,ntsvc_list[i]->display_name);
967:
968: SAFECOPY(str,getfname(argv[0]));
969: if((p=getfext(str))!=NULL)
970: *p=0;
971:
972: printf("\nUsage: %s [command] [service]\n", str);
973:
974: printf("\nCommands:\n");
975: printf("\tinstall\t to install a service by name (default: ALL services)\n");
976: printf("\tremove\t to remove a service by name (default: ALL services)\n");
977: printf("\tdisable\t to disable a service by name (default: ALL services)\n");
978: printf("\tenable\t to re-enable a disabled service (default: ALL services)\n");
979:
980: printf("\nStartServiceCtrlDispatcher being called.\n" );
981: printf("This may take several seconds. Please wait.\n" );
982:
983: if(!StartServiceCtrlDispatcher(ServiceDispatchTable))
984: {
985: sprintf(str,"!StartServiceCtrlDispatcher ERROR %d",GetLastError());
986: printf("%s\n",str);
987: OutputDebugString(str);
988: }
989:
990: return(0);
991: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.