sbbscon.c 39.9 KB
Newer Older
rswindell's avatar
rswindell committed
1
2
3
4
5
6
7
8
9
10
/* sbbscon.c */

/* Synchronet vanilla/console-mode "front-end" */

/* $Id$ */

/****************************************************************************
 * @format.tab-size 4		(Plain Text/Source Code File Header)			*
 * @format.use-tabs true	(see http://www.synchro.net/ptsc_hdr.html)		*
 *																			*
11
 * Copyright 2003 Rob Swindell - http://www.synchro.net/copyright.html		*
rswindell's avatar
rswindell committed
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
 *																			*
 * 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.	*
 ****************************************************************************/

38
/* ANSI headers */
39
#include <stdio.h>
40
41
42
#include <string.h>
#include <signal.h>
#include <ctype.h>
deuce's avatar
deuce committed
43
44
45
#ifdef __QNX__
#include <locale.h>
#endif
46

rswindell's avatar
rswindell committed
47
48
/* Synchronet-specific headers */
#include "conwrap.h"	/* kbhit/getch */
49
50
#include "sbbs.h"		/* load_cfg() */
#include "sbbs_ini.h"	/* sbbs_read_ini() */
rswindell's avatar
rswindell committed
51
52
#include "ftpsrvr.h"	/* ftp_startup_t, ftp_server */
#include "mailsrvr.h"	/* mail_startup_t, mail_server */
53
#include "services.h"	/* services_startup_t, services_thread */
rswindell's avatar
rswindell committed
54

55
56
57
58
59
#ifdef __unix__

#include <sys/types.h>
#include <unistd.h>
#include <pwd.h>
60
#include <grp.h>
61
62
#include <stdarg.h>
#include <stdlib.h>  /* Is this included from somewhere else? */
63
#include <syslog.h>
64

65
66
#endif

67
/* Temporary: Do not include web server in 3.1x-Win32 release build */
68
69
#if defined(_MSC_VER)
	#define NO_WEB_SERVER
70
71
#endif

72
73
74
75
76
/* Services doesn't work without JavaScript support */
#if !defined(JAVASCRIPT)
	#define	NO_SERVICES
#endif

77
78
/* Constants */
#define SBBS_PID_FILE	"/var/run/sbbs.pid"
79
#define SBBS_LOG_NAME	"synchronet"
80

rswindell's avatar
rswindell committed
81
/* Global variables */
82
BOOL				run_bbs=FALSE;
83
BOOL				bbs_running=FALSE;
84
BOOL				bbs_stopped=FALSE;
85
BOOL				has_bbs=FALSE;
86
bbs_startup_t		bbs_startup;
87
BOOL				run_ftp=FALSE;
88
BOOL				ftp_running=FALSE;
89
BOOL				ftp_stopped=FALSE;
90
BOOL				has_ftp=FALSE;
91
ftp_startup_t		ftp_startup;
92
BOOL				run_mail=FALSE;
93
BOOL				mail_running=FALSE;
94
BOOL				mail_stopped=FALSE;
95
BOOL				has_mail=FALSE;
96
mail_startup_t		mail_startup;
97
BOOL				run_services=FALSE;
98
BOOL				services_running=FALSE;
99
BOOL				services_stopped=FALSE;
100
BOOL				has_services=FALSE;
101
services_startup_t	services_startup;
102
BOOL				run_web=FALSE;
rswindell's avatar
rswindell committed
103
104
BOOL				web_running=FALSE;
BOOL				web_stopped=FALSE;
105
BOOL				has_web=FALSE;
rswindell's avatar
rswindell committed
106
web_startup_t		web_startup;
107
108
uint				thread_count=1;
uint				socket_count=0;
109
uint				client_count=0;
110
int					prompt_len=0;
111
112
static scfg_t		scfg;					/* To allow rerun */
static ulong		served=0;
113
114

#ifdef __unix__
115
116
char				new_uid_name[32];
char				new_gid_name[32];
117
118
119
120
uid_t				new_uid;
uid_t				old_uid;
gid_t				new_gid;
gid_t				old_gid;
121
BOOL				is_daemon=FALSE;
122
BOOL				std_facilities=FALSE;
123
#endif
124

125
static const char* prompt;
126

127
static const char* usage  = "\nusage: %s [[setting] [...]] [path/ini_file]\n"
128
							"\n"
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
							"Global settings:\n"
							"\n"
							"\thn[host]   set hostname for this instance\n"
							"\t           if host not specified, uses gethostname\n"
#ifdef __unix__
							"\tun<user>   set username for BBS to run as\n"
							"\tug<group>  set group for BBS to run as\n"
							"\td[x]       run as daemon, log using syslog\n"
							"\t           x is the optional LOCALx facility to use\n"
							"\t           if none is specified, uses USER\n"
							"\t           if 'S' is specified, uses standard facilities\n"
#endif
							"\tgi         get user identity (using IDENT protocol)\n"
							"\tnh         disable hostname lookups\n"
							"\tnj         disable JavaScript support\n"
							"\tne         disable event thread\n"
							"\tni         do not read settings from .ini file\n"
#ifdef __unix__
							"\tnd         do not read run as daemon - overrides .ini file\n"
#endif
							"\tlt         use local timezone (do not force UTC/GMT)\n"
							"\tdefaults   show default settings and options\n"
							"\n"
							;
static const char* telnet_usage  = "Telnet server settings:\n\n"
154
155
156
157
158
							"\ttf<node>   set first Telnet node number\n"
							"\ttl<node>   set last Telnet node number\n"
							"\ttp<port>   set Telnet server port\n"
							"\trp<port>   set RLogin server port (and enable RLogin server)\n"
							"\tr2         use second RLogin name in BSD RLogin\n"
159
160
161
162
163
							"\tto<value>  set Telnet server options value (advanced)\n"
							"\tta         enable auto-logon via IP address\n"
							"\ttd         enable Telnet command debug output\n"
							"\ttc         emabble sysop availability for chat\n"
							"\ttq         disable QWK events\n"
164
							"\tt-         disable Telnet/RLogin server\n"
165
							"\n"
166
167
							;
static const char* ftp_usage  = "FTP server settings:\n"
168
169
							"\n"
							"\tfp<port>   set FTP server port\n"
170
							"\tfo<value>  set FTP server options value (advanced)\n"
171
							"\tf-         disable FTP server\n"
172
							"\n"
173
174
							;
static const char* mail_usage  = "Mail server settings:\n"
175
							"\n"
176
177
							"\tms<port>   set SMTP server port\n"
							"\tmp<port>   set POP3 server port\n"
178
179
							"\tmr<addr>   set SMTP relay server (and enable SMTP relay)\n"
							"\tmd<addr>   set DNS server address for MX-record lookups\n"
180
							"\tmo<value>  set Mail server options value (advanced)\n"
181
							"\tma         allow SMTP relays from authenticated users\n"
182
183
184
							"\tm-         disable Mail server (entirely)\n"
							"\tmp-        disable POP3 server\n"
							"\tms-        disable SendMail thread\n"
185
							"\n"
186
187
							;
static const char* services_usage  = "Services settings:\n"
188
189
190
191
							"\n"
							"\tso<value>  set Services option value (advanced)\n"
							"\ts-         disable Services (no services module)\n"
							"\n"
192
193
							;

194
static int lputs(char *str)
195
196
{
	static pthread_mutex_t mutex;
197
	static BOOL mutex_initialized;
198

199
#ifdef __unix__
200

201
	if (is_daemon)  {
202
		if(str!=NULL) {
203
			if (std_facilities)
204
205
				syslog(LOG_INFO|LOG_AUTH,"%s",str);
			else
206
207
				syslog(LOG_INFO,"%s",str);
		}
208
		return(0);
209
	}
210
#endif
211
212
213
214
215
216
217
218
219
220
	if(!mutex_initialized) {
		pthread_mutex_init(&mutex,NULL);
		mutex_initialized=TRUE;
	}
	pthread_mutex_lock(&mutex);
	/* erase prompt */
	printf("\r%*s\r",prompt_len,"");
	if(str!=NULL)
		printf("%s\n",str);
	/* re-display prompt with current stats */
221
222
	if(prompt!=NULL)
		prompt_len = printf(prompt, thread_count, socket_count, client_count, served);
223
224
	fflush(stdout);
	pthread_mutex_unlock(&mutex);
225
226

    return(prompt_len);
227
228
}

229
230
231
232
#ifdef __unix__
/**********************************************************
* Change uid of the calling process to the user if specified
* **********************************************************/
rswindell's avatar
rswindell committed
233
static BOOL do_setuid(void) 
234
235
236
{
	BOOL	result=FALSE;

237
238
239
	setregid(-1,old_gid);
	setreuid(-1,old_uid);
	if(!setregid(new_gid,new_gid) && !setreuid(new_uid,new_uid)) 
240
241
242
243
244
245
246
247
248
249
250
251
252
		result=TRUE;

	if(!result) {
		lputs("!setuid FAILED");
		lputs(strerror(errno));
	}
	return result;
}

/**********************************************************
* Change uid of the calling process to the user if specified
* **********************************************************/
static BOOL do_seteuid(BOOL to_new) 
253
{
254
255
256
	BOOL	result=FALSE;
	static pthread_mutex_t mutex;
	static BOOL mutex_initialized;
257

258
	if(new_uid_name[0]==0)	/* not set? */
259
260
		return(TRUE);		/* do nothing */

261
262
263
264
265
266
	if(!mutex_initialized) {
		pthread_mutex_init(&mutex,NULL);
		mutex_initialized=TRUE;
	}

	pthread_mutex_lock(&mutex);
267

268
	if(to_new)
269
		if(!setregid(-1,new_gid) && !setreuid(-1,new_uid))
270
271
272
273
			result=TRUE;
		else
			result=FALSE;
	else
274
		if(!setregid(-1,old_gid) && !setreuid(-1,old_uid))
275
			result=TRUE;
276
277
278
279
		else
			result=FALSE;

		
280
	pthread_mutex_unlock(&mutex);
281

282
283
284
285
	if(!result) {
		lputs("!seteuid FAILED");
		lputs(strerror(errno));
	}
286
	return result;
287
288
289
}
#endif   /* __unix__ */

290
291
#ifdef _WINSOCKAPI_

292
static WSADATA WSAData;
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320

static BOOL winsock_startup(void)
{
	int		status;             /* Status Code */

    if((status = WSAStartup(MAKEWORD(1,1), &WSAData))==0)
		return(TRUE);

    fprintf(stderr,"!WinSock startup ERROR %d\n", status);
	return(FALSE);
}

static BOOL winsock_cleanup(void)	
{
	if(WSACleanup()==0)
		return(TRUE);

	fprintf(stderr,"!WinSock cleanup ERROR %d\n",ERROR_VALUE);
	return(FALSE);
}

#else /* No WINSOCK */

#define winsock_startup()	(TRUE)	
#define winsock_cleanup()	(TRUE)

#endif

321
static void thread_up(BOOL up, BOOL setuid)
322
{
323
324
325
   	static pthread_mutex_t mutex;
	static BOOL mutex_initialized;

326
327
328
329
330
331
332
#ifdef _THREAD_SUID_BROKEN
	if(up && setuid) {
		do_seteuid(FALSE);
		do_setuid();
	}
#endif

333
334
335
336
337
338
	if(!mutex_initialized) {
		pthread_mutex_init(&mutex,NULL);
		mutex_initialized=TRUE;
	}

	pthread_mutex_lock(&mutex);
339
	if(up)
340
341
342
343
	    thread_count++;
    else if(thread_count>0)
    	thread_count--;
	pthread_mutex_unlock(&mutex);
344
	lputs(NULL); /* update displayed stats */
345
346
347
348
349
350
351
352
353
354
}

static void socket_open(BOOL open)
{
   	static pthread_mutex_t mutex;
	static BOOL mutex_initialized;

	if(!mutex_initialized) {
		pthread_mutex_init(&mutex,NULL);
		mutex_initialized=TRUE;
355
	}
356
357
358
359
360
361
362

	pthread_mutex_lock(&mutex);
	if(open)
	    socket_count++;
    else if(socket_count>0)
    	socket_count--;
	pthread_mutex_unlock(&mutex);
363
	lputs(NULL); /* update displayed stats */
364
365
}

366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
static void client_on(BOOL on, int sock, client_t* client, BOOL update)
{
   	static pthread_mutex_t mutex;
	static BOOL mutex_initialized;

	if(!mutex_initialized) {
		pthread_mutex_init(&mutex,NULL);
		mutex_initialized=TRUE;
	}

	pthread_mutex_lock(&mutex);
	if(on && !update) {
		client_count++;
	    served++;
	} else if(!on && client_count>0)
		client_count--;
	pthread_mutex_unlock(&mutex);
	lputs(NULL); /* update displayed stats */
}

rswindell's avatar
rswindell committed
386
387
388
389
390
391
392
393
/****************************************************************************/
/* BBS local/log print routine												*/
/****************************************************************************/
static int bbs_lputs(char *str)
{
	char		logline[512];
	char		tstr[64];
	time_t		t;
394
	struct tm	tm;
rswindell's avatar
rswindell committed
395

396
397
398
399
#ifdef __unix__
	if (is_daemon)  {
		if(str==NULL)
			return(0);
400
		if (std_facilities)
401
402
			syslog(LOG_INFO|LOG_AUTH,"%s",str);
		else
403
			syslog(LOG_INFO,"     %s",str);
404
405
406
407
		return(strlen(str));
	}
#endif

408
	t=time(NULL);
409
	if(localtime_r(&t,&tm)==NULL)
410
411
412
		tstr[0]=0;
	else
		sprintf(tstr,"%d/%d %02d:%02d:%02d "
413
414
			,tm.tm_mon+1,tm.tm_mday
			,tm.tm_hour,tm.tm_min,tm.tm_sec);
rswindell's avatar
rswindell committed
415

416
	sprintf(logline,"%s     %.*s",tstr,(int)sizeof(logline)-32,str);
rswindell's avatar
rswindell committed
417
	truncsp(logline);
418
	lputs(logline);
rswindell's avatar
rswindell committed
419
420
421
422
423
424
425
	
    return(strlen(logline)+1);
}

static void bbs_started(void)
{
	bbs_running=TRUE;
426
	bbs_stopped=FALSE;
427
428
429
430
	#ifdef _THREAD_SUID_BROKEN
	    do_seteuid(FALSE);
	    do_setuid();
	#endif
rswindell's avatar
rswindell committed
431
432
433
434
435
}

static void bbs_terminated(int code)
{
	bbs_running=FALSE;
436
	bbs_stopped=TRUE;
rswindell's avatar
rswindell committed
437
438
439
440
441
442
443
444
445
446
}

/****************************************************************************/
/* FTP local/log print routine												*/
/****************************************************************************/
static int ftp_lputs(char *str)
{
	char		logline[512];
	char		tstr[64];
	time_t		t;
447
	struct tm	tm;
rswindell's avatar
rswindell committed
448

449
450
451
452
#ifdef __unix__
	if (is_daemon)  {
		if(str==NULL)
			return(0);
453
		if (std_facilities)
454
455
456
#ifdef __solaris__
			syslog(LOG_INFO|LOG_DAEMON,"%s",str);
#else
457
			syslog(LOG_INFO|LOG_FTP,"%s",str);
458
#endif
459
		else
460
			syslog(LOG_INFO,"ftp  %s",str);
461
462
463
464
		return(strlen(str));
	}
#endif

465
	t=time(NULL);
466
	if(localtime_r(&t,&tm)==NULL)
467
468
469
		tstr[0]=0;
	else
		sprintf(tstr,"%d/%d %02d:%02d:%02d "
470
471
			,tm.tm_mon+1,tm.tm_mday
			,tm.tm_hour,tm.tm_min,tm.tm_sec);
rswindell's avatar
rswindell committed
472

473
	sprintf(logline,"%sftp  %.*s",tstr,(int)sizeof(logline)-32,str);
rswindell's avatar
rswindell committed
474
	truncsp(logline);
475
	lputs(logline);
rswindell's avatar
rswindell committed
476
477
478
479
480
481
482
	
    return(strlen(logline)+1);
}

static void ftp_started(void)
{
	ftp_running=TRUE;
483
	ftp_stopped=FALSE;
484
485
486
487
	#ifdef _THREAD_SUID_BROKEN
	    do_seteuid(FALSE);
	    do_setuid();
	#endif
rswindell's avatar
rswindell committed
488
489
490
491
492
}

static void ftp_terminated(int code)
{
	ftp_running=FALSE;
493
	ftp_stopped=TRUE;
rswindell's avatar
rswindell committed
494
495
496
497
498
499
500
501
502
503
}

/****************************************************************************/
/* Mail Server local/log print routine										*/
/****************************************************************************/
static int mail_lputs(char *str)
{
	char		logline[512];
	char		tstr[64];
	time_t		t;
504
	struct tm	tm;
rswindell's avatar
rswindell committed
505

506
507
508
509
#ifdef __unix__
	if (is_daemon)  {
		if(str==NULL)
			return(0);
510
		if (std_facilities)
511
512
			syslog(LOG_INFO|LOG_MAIL,"%s",str);
		else
513
			syslog(LOG_INFO,"mail %s",str);
514
515
516
517
		return(strlen(str));
	}
#endif

518
	t=time(NULL);
519
	if(localtime_r(&t,&tm)==NULL)
520
521
522
		tstr[0]=0;
	else
		sprintf(tstr,"%d/%d %02d:%02d:%02d "
523
524
			,tm.tm_mon+1,tm.tm_mday
			,tm.tm_hour,tm.tm_min,tm.tm_sec);
rswindell's avatar
rswindell committed
525

526
	sprintf(logline,"%smail %.*s",tstr,(int)sizeof(logline)-32,str);
rswindell's avatar
rswindell committed
527
	truncsp(logline);
528
	lputs(logline);
rswindell's avatar
rswindell committed
529
530
531
532
533
534
535
	
    return(strlen(logline)+1);
}

static void mail_started(void)
{
	mail_running=TRUE;
536
	mail_stopped=FALSE;
537
538
539
540
	#ifdef _THREAD_SUID_BROKEN
	    do_seteuid(FALSE);
	    do_setuid();
	#endif
rswindell's avatar
rswindell committed
541
542
543
544
545
}

static void mail_terminated(int code)
{
	mail_running=FALSE;
546
	mail_stopped=TRUE;
rswindell's avatar
rswindell committed
547
548
}

549
550
551
552
553
554
555
556
/****************************************************************************/
/* Services local/log print routine											*/
/****************************************************************************/
static int services_lputs(char *str)
{
	char		logline[512];
	char		tstr[64];
	time_t		t;
557
	struct tm	tm;
558

559
560
561
562
#ifdef __unix__
	if (is_daemon)  {
		if(str==NULL)
			return(0);
563
		if (std_facilities)
564
565
			syslog(LOG_INFO|LOG_DAEMON,"%s",str);
		else
566
			syslog(LOG_INFO,"srvc %s",str);
567
568
569
570
		return(strlen(str));
	}
#endif

571
	t=time(NULL);
572
	if(localtime_r(&t,&tm)==NULL)
573
574
575
		tstr[0]=0;
	else
		sprintf(tstr,"%d/%d %02d:%02d:%02d "
576
577
			,tm.tm_mon+1,tm.tm_mday
			,tm.tm_hour,tm.tm_min,tm.tm_sec);
578

579
	sprintf(logline,"%ssrvc %.*s",tstr,(int)sizeof(logline)-32,str);
580
581
582
583
584
585
586
587
588
	truncsp(logline);
	lputs(logline);
	
    return(strlen(logline)+1);
}

static void services_started(void)
{
	services_running=TRUE;
589
	services_stopped=FALSE;
590
591
592
593
	#ifdef _THREAD_SUID_BROKEN
	    do_seteuid(FALSE);
	    do_setuid();
	#endif
594
595
596
597
598
}

static void services_terminated(int code)
{
	services_running=FALSE;
599
	services_stopped=TRUE;
600
601
}

602
603
604
605
606
607
608
609
/****************************************************************************/
/* Event thread local/log print routine										*/
/****************************************************************************/
static int event_lputs(char *str)
{
	char		logline[512];
	char		tstr[64];
	time_t		t;
610
	struct tm	tm;
611

612
613
614
615
#ifdef __unix__
	if (is_daemon)  {
		if(str==NULL)
			return(0);
616
		if (std_facilities)
617
618
			syslog(LOG_INFO|LOG_CRON,"%s",str);
		else
619
			syslog(LOG_INFO,"evnt %s",str);
620
621
622
623
		return(strlen(str));
	}
#endif

624
	t=time(NULL);
625
	if(localtime_r(&t,&tm)==NULL)
626
627
628
		tstr[0]=0;
	else
		sprintf(tstr,"%d/%d %02d:%02d:%02d "
629
630
			,tm.tm_mon+1,tm.tm_mday
			,tm.tm_hour,tm.tm_min,tm.tm_sec);
631

632
	sprintf(logline,"%sevnt %.*s",tstr,(int)sizeof(logline)-32,str);
633
634
635
636
637
638
	truncsp(logline);
	lputs(logline);
	
    return(strlen(logline)+1);
}

rswindell's avatar
rswindell committed
639
640
641
642
643
644
645
646
/****************************************************************************/
/* web local/log print routine											*/
/****************************************************************************/
static int web_lputs(char *str)
{
	char		logline[512];
	char		tstr[64];
	time_t		t;
647
	struct tm	tm;
rswindell's avatar
rswindell committed
648
649
650
651
652
653
654
655

#ifdef __unix__
	if (is_daemon)  {
		if(str==NULL)
			return(0);
		if (std_facilities)
			syslog(LOG_INFO|LOG_DAEMON,"%s",str);
		else
rswindell's avatar
rswindell committed
656
			syslog(LOG_INFO,"web  %s",str);
rswindell's avatar
rswindell committed
657
658
659
660
661
		return(strlen(str));
	}
#endif

	t=time(NULL);
662
	if(localtime_r(&t,&tm)==NULL)
rswindell's avatar
rswindell committed
663
664
665
		tstr[0]=0;
	else
		sprintf(tstr,"%d/%d %02d:%02d:%02d "
666
667
			,tm.tm_mon+1,tm.tm_mday
			,tm.tm_hour,tm.tm_min,tm.tm_sec);
rswindell's avatar
rswindell committed
668

rswindell's avatar
rswindell committed
669
	sprintf(logline,"%sweb  %.*s",tstr,(int)sizeof(logline)-32,str);
rswindell's avatar
rswindell committed
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
	truncsp(logline);
	lputs(logline);
	
    return(strlen(logline)+1);
}

static void web_started(void)
{
	web_running=TRUE;
	web_stopped=FALSE;
	#ifdef _THREAD_SUID_BROKEN
	    do_seteuid(FALSE);
	    do_setuid();
	#endif
}

static void web_terminated(int code)
{
	web_running=FALSE;
	web_stopped=TRUE;
}

692
static void terminate(void)
693
{
694
695
	ulong count=0;

696
697
	bbs_terminate();
	ftp_terminate();
698
#ifndef NO_WEB_SERVER
699
	web_terminate();
700
#endif
701
	mail_terminate();
702
#ifndef NO_SERVICES
703
704
	services_terminate();
#endif
705

706
	while(bbs_running || ftp_running || web_running || mail_running || services_running)  {
707
708
		if(count && (count%10)==0) {
			if(bbs_running)
709
				bbs_lputs("BBS System thread still running");
710
711
712
713
714
715
716
717
718
719
720
			if(ftp_running)
				ftp_lputs("FTP Server thread still running");
			if(web_running)
				web_lputs("Web Server thread still running");
			if(mail_running)
				mail_lputs("Mail Server thread still running");
			if(services_running)
				services_lputs("Services thread still running");
		}
		count++;
		SLEEP(1000);
721
	}
722
}
723

rswindell's avatar
rswindell committed
724
725
726
#ifdef __unix__
void _sighandler_quit(int sig)
{
727
728
729
730
731
732
733
734
735
736
737
738
739
	char	str[1024];
	static pthread_mutex_t mutex;
	static BOOL mutex_initialized;

	if(!mutex_initialized) {
		pthread_mutex_init(&mutex,NULL);
		mutex_initialized=TRUE;
	}
	pthread_mutex_lock(&mutex);
	/* Can I get away with leaving this locked till exit? */

	sprintf(str,"     Got quit signal (%d)",sig);
	lputs(str);
740
741
	terminate();

742
	if(is_daemon)
743
		unlink(SBBS_PID_FILE);
744
745

    exit(0);
rswindell's avatar
rswindell committed
746
}
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786

void _sighandler_rerun(int sig)
{
	int		i;
	node_t	node;

	lputs("     Got HUP (rerun) signal");
	
	for(i=1;i<=scfg.sys_nodes;i++) {
		getnodedat(&scfg,i,&node,NULL /* file */);
		node.misc|=NODE_RRUN;
		printnodedat(&scfg,i,&node);
	}
}

#ifdef NEEDS_DAEMON
/****************************************************************************/
/* Daemonizes the process                                                   */
/****************************************************************************/
int
daemon(nochdir, noclose)
    int nochdir, noclose;
{
    int fd;

    switch (fork()) {
    case -1:
        return (-1);
    case 0:
        break;
    default:
        _exit(0);
    }

    if (setsid() == -1)
        return (-1);

    if (!nochdir)
        (void)chdir("/");

787
    if (!noclose && (fd = open(_PATH_DEVNULL, O_RDWR, 0)) != -1) {
788
789
790
791
792
793
794
795
796
797
798
799
800
801
        (void)dup2(fd, STDIN_FILENO);
        (void)dup2(fd, STDOUT_FILENO);
        (void)dup2(fd, STDERR_FILENO);
        if (fd > 2)
            (void)close(fd);
    }
    return (0);
}
#endif /* NEEDS_DAEMON */

static void handle_sigs(void)  {
	int		sig;
	sigset_t			sigs;
	char		str[1024];
802
803
804
805
806
807
808
809
810
811
812
813
814
	FILE*	pidfile;

	thread_up(TRUE,TRUE);

	/* Write the standard .pid file if running as a daemon */
	/* Must be here so signals are sent to the correct thread */
	if(is_daemon)  {
		pidfile=fopen(SBBS_PID_FILE,"w");
		if(pidfile!=NULL) {
			fprintf(pidfile,"%d",getpid());
			fclose(pidfile);
		}
	}
815

816
817
818
819
820
821
822
823
824
	/* Set up blocked signals */
	sigemptyset(&sigs);
	sigaddset(&sigs,SIGINT);
	sigaddset(&sigs,SIGQUIT);
	sigaddset(&sigs,SIGABRT);
	sigaddset(&sigs,SIGTERM);
	sigaddset(&sigs,SIGHUP);
	sigaddset(&sigs,SIGALRM);
	sigaddset(&sigs,SIGPIPE);
825
826
827
	pthread_sigmask(SIG_BLOCK,&sigs,NULL);
	while(1)  {
		sigwait(&sigs,&sig);    /* wait here until signaled */
828
829
		sprintf(str,"     Got signal (%d)",sig);
		lputs(str);
830
831
832
833
834
835
836
837
838
839
840
841
		switch(sig)  {
			/* QUIT-type signals */
			case SIGINT:
			case SIGQUIT:
			case SIGABRT:
			case SIGTERM:
				_sighandler_quit(sig);
				break;
			case SIGHUP:    /* rerun */
				_sighandler_rerun(sig);
				break;
			default:
deuce's avatar
deuce committed
842
				sprintf(str,"     Signal has no handler (unexpected)");
843
				lputs(str);
844
845
846
		}
	}
}
847
#endif	/* __unix__ */
rswindell's avatar
rswindell committed
848

849
850
851
/****************************************************************************/
/* Displays appropriate usage info											*/
/****************************************************************************/
852
static void show_usage(char *cmd)
853
854
855
856
857
858
859
860
861
862
863
864
{
	printf(usage,cmd);
	if(has_bbs)
		printf(telnet_usage);
	if(has_ftp)
		printf(ftp_usage);
	if(has_mail)
		printf(mail_usage);
	if(has_services)
		printf(services_usage);
}

865
static int command_is(char *cmdline, char *cmd)
866
{
867
	return(strnicmp(getfname(cmdline),cmd,strlen(cmd))==0);
868
869
}

rswindell's avatar
rswindell committed
870
871
872
873
874
/****************************************************************************/
/* Main Entry Point															*/
/****************************************************************************/
int main(int argc, char** argv)
{
875
	int		i;
876
877
	int		n;
	int		file;
878
	char	ch;
rswindell's avatar
rswindell committed
879
	char*	p;
880
	char*	arg;
rswindell's avatar
rswindell committed
881
	char*	ctrl_dir;
882
	char	str[MAX_PATH+1];
883
    char	error[256];
884
	char	ini_file[MAX_PATH+1];
885
	char	host_name[128]="";
886
	BOOL	quit=FALSE;
887
	FILE*	fp=NULL;
888
	node_t	node;
889
#ifdef __unix__
890
	char	daemon_type[2];
rswindell's avatar
rswindell committed
891
	char	value[MAX_VALUE_LEN];
892
893
	struct passwd* pw_entry;
	struct group*  gr_entry;
894
	sigset_t			sigs;
895
#endif
rswindell's avatar
rswindell committed
896

897
898
	if(command_is(argv[0],"sbbs_ftp"))
		run_ftp=has_ftp=TRUE;
899
	else if(command_is(argv[0],"sbbs_mail"))
900
		run_mail=has_mail=TRUE;
901
	else if(command_is(argv[0],"sbbs_bbs"))
902
		run_bbs=has_bbs=TRUE;
903
	else if(command_is(argv[0],"sbbs_srvc"))
904
		run_services=has_services=TRUE;
905
	else if(command_is(argv[0],"sbbs_web"))
906
907
908
909
910
911
912
913
914
		run_web=has_web=TRUE;
	else {
		run_bbs=has_bbs=TRUE;
		run_ftp=has_ftp=TRUE;
		run_mail=has_mail=TRUE;
		run_services=has_services=TRUE;
		run_web=has_web=TRUE;
	}

deuce's avatar
deuce committed
915
916
#ifdef __QNX__
	setlocale( LC_ALL, "C-TRADITIONAL" );
917
918
919
#endif
#ifdef __unix__
	umask(077);
deuce's avatar
deuce committed
920
#endif
rswindell's avatar
rswindell committed
921
922
	printf("\nSynchronet Console for %s  Version %s%c  %s\n\n"
		,PLATFORM_DESC,VERSION,REVISION,COPYRIGHT_NOTICE);
rswindell's avatar
rswindell committed
923
924

	ctrl_dir=getenv("SBBSCTRL");	/* read from environment variable */
925
	if(ctrl_dir==NULL || ctrl_dir[0]==0) {
926
		ctrl_dir="/sbbs/ctrl";		/* Not set? Use default */
927
928
929
		printf("!SBBSCTRL environment variable not set, using default value: %s\n\n"
			,ctrl_dir);
	}
930

931
932
933
	if(!winsock_startup())
		return(-1);

934
935
	gethostname(host_name,sizeof(host_name)-1);

936
937
938
	if(!winsock_cleanup())
		return(-1);

939
	sprintf(ini_file,"%s%c%s.ini",ctrl_dir,PATH_DELIM,host_name);
940
#if defined(__unix__) && defined(PREFIX)
941
	if(!fexistcase(ini_file))
942
943
		sprintf(ini_file,"%s/etc/sbbs.ini",PREFIX);
#endif
944
	if(!fexistcase(ini_file))
945
		sprintf(ini_file,"%s%csbbs.ini",ctrl_dir,PATH_DELIM);
rswindell's avatar
rswindell committed
946
947
948
949
950
951

	/* Initialize BBS startup structure */
    memset(&bbs_startup,0,sizeof(bbs_startup));
    bbs_startup.size=sizeof(bbs_startup);

	bbs_startup.lputs=bbs_lputs;
952
	bbs_startup.event_log=event_lputs;
rswindell's avatar
rswindell committed
953
954
    bbs_startup.started=bbs_started;
    bbs_startup.terminated=bbs_terminated;
955
    bbs_startup.thread_up=thread_up;
956
    bbs_startup.socket_open=socket_open;
957
    bbs_startup.client_on=client_on;
958
#ifdef __unix__
959
	bbs_startup.seteuid=do_seteuid;
960
#endif
rswindell's avatar
rswindell committed
961
962
/*	These callbacks haven't been created yet
    bbs_startup.status=bbs_status;
963
    bbs_startup.clients=bbs_clients;
rswindell's avatar
rswindell committed
964
965
966
967
968
969
970
*/
    strcpy(bbs_startup.ctrl_dir,ctrl_dir);

	/* Initialize FTP startup structure */
    memset(&ftp_startup,0,sizeof(ftp_startup));
    ftp_startup.size=sizeof(ftp_startup);
	ftp_startup.lputs=ftp_lputs;
971
972
    ftp_startup.started=ftp_started;
    ftp_startup.terminated=ftp_terminated;
973
	ftp_startup.thread_up=thread_up;
974
    ftp_startup.socket_open=socket_open;
975
    ftp_startup.client_on=client_on;
976
#ifdef __unix__
977
	ftp_startup.seteuid=do_seteuid;
978
#endif
979
    strcpy(ftp_startup.index_file_name,"00index");
rswindell's avatar
rswindell committed
980
981
    strcpy(ftp_startup.ctrl_dir,ctrl_dir);

rswindell's avatar
rswindell committed
982
983
984
985
986
987
988
989
990
991
992
993
994
	/* Initialize Web Server startup structure */
    memset(&web_startup,0,sizeof(web_startup));
    web_startup.size=sizeof(web_startup);
	web_startup.lputs=web_lputs;
    web_startup.started=web_started;
    web_startup.terminated=web_terminated;
	web_startup.thread_up=thread_up;
    web_startup.socket_open=socket_open;
#ifdef __unix__
	web_startup.seteuid=do_seteuid;
#endif
    strcpy(web_startup.ctrl_dir,ctrl_dir);

rswindell's avatar
rswindell committed
995
996
997
998
	/* Initialize Mail Server startup structure */
    memset(&mail_startup,0,sizeof(mail_startup));
    mail_startup.size=sizeof(mail_startup);
	mail_startup.lputs=mail_lputs;
999
1000
    mail_startup.started=mail_started;
    mail_startup.terminated=mail_terminated;
1001
	mail_startup.thread_up=thread_up;
1002
    mail_startup.socket_open=socket_open;
1003
    mail_startup.client_on=client_on;
1004
#ifdef __unix__
1005
	mail_startup.seteuid=do_seteuid;
1006
#endif
rswindell's avatar
rswindell committed
1007
1008
    strcpy(mail_startup.ctrl_dir,ctrl_dir);

1009
1010
1011
1012
1013
1014
#ifdef __unix__	/* Look up DNS server address */
	{
		FILE*	fp;
		char*	p;
		char	str[128];

1015
		if((fp=fopen("/etc/resolv.conf","r"))!=NULL) {
1016
			while(!feof(fp)) {
1017
				if(fgets(str,sizeof(str),fp)==NULL)
1018
1019
1020
1021
1022
1023
1024
1025
					break;
				truncsp(str);
				p=str;
				while(*p && *p<=' ') p++;	/* skip white-space */
				if(strnicmp(p,"nameserver",10)!=0) /* no match */
					continue;
				p+=10;	/* skip "nameserver" */
				while(*p && *p<=' ') p++;	/* skip more white-space */
1026
				SAFECOPY(mail_startup.dns_server,p);
1027
1028
1029
1030
1031
1032
1033
				break;
			}
			fclose(fp);
		}
	}
#endif /* __unix__ */

1034
1035
1036
1037
1038
1039
	/* Initialize Services startup structure */
    memset(&services_startup,0,sizeof(services_startup));
    services_startup.size=sizeof(services_startup);
	services_startup.lputs=services_lputs;
    services_startup.started=services_started;
    services_startup.terminated=services_terminated;
1040
	services_startup.thread_up=thread_up;
1041
    services_startup.socket_open=socket_open;
1042
    services_startup.client_on=client_on;
1043
#ifdef __unix__
1044
	services_startup.seteuid=do_seteuid;
1045
#endif
1046
1047
    strcpy(services_startup.ctrl_dir,ctrl_dir);

1048
	/* Pre-INI command-line switches */
1049
1050
	for(i=1;i<argc;i++) {
		arg=argv[i];
1051
		while(*arg=='-')
1052
			arg++;
1053
		if(strcspn(arg,"\\/")!=strlen(arg)) {
1054
1055
1056
			strcpy(ini_file,arg);
			continue;
		}
1057
1058
1059
1060
1061
1062
1063
1064
1065
		if(!stricmp(arg,"ni")) {
			ini_file[0]=0;
			break;
		}
	}

	/* Read .ini file here */
	if(ini_file[0]!=0 && (fp=fopen(ini_file,"r"))!=NULL) {
		sprintf(str,"Reading %s",ini_file);
1066
		bbs_lputs(str);
1067
1068
	}

1069
1070
	prompt = "[Threads: %d  Sockets: %d  Clients: %d  Served: %lu] (?=Help): ";

1071
1072
1073
1074
	/* We call this function to set defaults, even if there's no .ini file */
	sbbs_read_ini(fp, 
		&run_bbs,		&bbs_startup,
		&run_ftp,		&ftp_startup, 
rswindell's avatar
rswindell committed
1075
		&run_web,		&web_startup,
1076
1077
1078
		&run_mail,		&mail_startup, 
		&run_services,	&services_startup);

1079
	/* read/default any sbbscon-specific .ini keys here */
1080
#if defined(__unix__)
rswindell's avatar
rswindell committed
1081
1082
	SAFECOPY(new_uid_name,iniGetString(fp,"UNIX","User","",value));
	SAFECOPY(new_gid_name,iniGetString(fp,"UNIX","Group","",value));
1083
	is_daemon=iniGetBool(fp,"UNIX","Daemonize",FALSE);
rswindell's avatar
rswindell committed
1084
	SAFECOPY(daemon_type,iniGetString(fp,"UNIX","LogFacility","U",value));
1085
1086
	umask(iniGetInteger(fp,"UNIX","umask",077));
#endif
1087
	/* close .ini file here */
1088
1089
1090
1091
1092
1093
1094
1095
	if(fp!=NULL)
		fclose(fp);

	/* Post-INI command-line switches */
	for(i=1;i<argc;i++) {
		arg=argv[i];
		while(*arg=='-')
			arg++;
1096
		if(strcspn(arg,"\\/")!=strlen(arg))	/* ini_file name */
1097
			continue;
1098
		if(!stricmp(arg,"defaults")) {
1099
			printf("Default settings:\n");
1100
			printf("\n");
1101
			printf("Telnet server port:\t%u\n",bbs_startup.telnet_port);
1102
1103
			printf("Telnet first node:\t%u\n",bbs_startup.first_node);
			printf("Telnet last node:\t%u\n",bbs_startup.last_node);
1104
			printf("Telnet server options:\t0x%08lX\n",bbs_startup