sbbscon.c 46.5 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 2004 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
/* Synchronet-specific headers */
48
#undef SBBS	/* this shouldn't be defined unless building sbbs.dll/libsbbs.so */
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
/* XPDEV headers */
#include "conwrap.h"	/* kbhit/getch */
#include "threadwrap.h"	/* pthread_mutex_t */

59
60
61
62
63
#ifdef __unix__

#include <sys/types.h>
#include <unistd.h>
#include <pwd.h>
64
#include <grp.h>
65
66
#include <stdarg.h>
#include <stdlib.h>  /* Is this included from somewhere else? */
67
#include <syslog.h>
68

69
70
#endif

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

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

rswindell's avatar
rswindell committed
80
/* Global variables */
81
82
BOOL				terminated=FALSE;

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

#ifdef __unix__
117
118
char				new_uid_name[32];
char				new_gid_name[32];
119
120
121
122
uid_t				new_uid;
uid_t				old_uid;
gid_t				new_gid;
gid_t				old_gid;
123
BOOL				is_daemon=FALSE;
124
char				daemon_type[2];
125
BOOL				std_facilities=FALSE;
126
FILE *				pidf;
127
#endif
128

129
static const char* prompt;
130

131
static const char* usage  = "\nusage: %s [[setting] [...]] [path/ini_file]\n"
132
							"\n"
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
							"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"
158
159
160
161
162
							"\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"
163
164
165
166
167
							"\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"
168
							"\tt-         disable Telnet/RLogin server\n"
169
							"\n"
170
171
							;
static const char* ftp_usage  = "FTP server settings:\n"
172
173
							"\n"
							"\tfp<port>   set FTP server port\n"
174
							"\tfo<value>  set FTP server options value (advanced)\n"
175
							"\tf-         disable FTP server\n"
176
							"\n"
177
178
							;
static const char* mail_usage  = "Mail server settings:\n"
179
							"\n"
180
181
							"\tms<port>   set SMTP server port\n"
							"\tmp<port>   set POP3 server port\n"
182
183
							"\tmr<addr>   set SMTP relay server (and enable SMTP relay)\n"
							"\tmd<addr>   set DNS server address for MX-record lookups\n"
184
							"\tmo<value>  set Mail server options value (advanced)\n"
185
							"\tma         allow SMTP relays from authenticated users\n"
186
187
188
							"\tm-         disable Mail server (entirely)\n"
							"\tmp-        disable POP3 server\n"
							"\tms-        disable SendMail thread\n"
189
							"\n"
190
191
							;
static const char* services_usage  = "Services settings:\n"
192
193
194
195
							"\n"
							"\tso<value>  set Services option value (advanced)\n"
							"\ts-         disable Services (no services module)\n"
							"\n"
196
197
							;

198
static int lputs(int level, char *str)
199
200
{
	static pthread_mutex_t mutex;
201
	static BOOL mutex_initialized;
202

203
#ifdef __unix__
204

205
	if (is_daemon)  {
206
		if(str!=NULL) {
207
			if (std_facilities)
208
				syslog(level|LOG_AUTH,"%s",str);
209
			else
210
				syslog(level,"%s",str);
211
		}
212
		return(0);
213
	}
214
#endif
215
216
217
218
219
220
221
222
223
224
	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 */
225
226
	if(prompt!=NULL)
		prompt_len = printf(prompt, thread_count, socket_count, client_count, served);
227
228
	fflush(stdout);
	pthread_mutex_unlock(&mutex);
229
230

    return(prompt_len);
231
232
}

233
234
235
236
237
238
239
240
241
242
243
244
static int lprintf(int level, char *fmt, ...)
{
	va_list argptr;
	char sbuf[1024];

    va_start(argptr,fmt);
    vsnprintf(sbuf,sizeof(sbuf),fmt,argptr);
	sbuf[sizeof(sbuf)-1]=0;
    va_end(argptr);
    return(lputs(level,sbuf));
}

245
#ifdef __unix__
246
247
248
249
/**********************************************************
* Change uid of the calling process to the user if specified
* **********************************************************/
static BOOL do_seteuid(BOOL to_new) 
250
{
251
252
253
	BOOL	result=FALSE;
	static pthread_mutex_t mutex;
	static BOOL mutex_initialized;
254

255
	if(new_uid_name[0]==0)	/* not set? */
256
257
		return(TRUE);		/* do nothing */

258
259
260
261
262
263
	if(!mutex_initialized) {
		pthread_mutex_init(&mutex,NULL);
		mutex_initialized=TRUE;
	}

	pthread_mutex_lock(&mutex);
264

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

		
277
	pthread_mutex_unlock(&mutex);
278

279
	if(!result) {
280
281
		lputs(LOG_ERR,"!seteuid FAILED");
		lputs(LOG_ERR,strerror(errno));
282
	}
283
	return result;
284
}
285
286
287
288

/**********************************************************
* Change uid of the calling process to the user if specified
* **********************************************************/
289
BOOL do_setuid(BOOL force)
290
{
291
292
293
294
295
	BOOL result=TRUE;
#if defined(DONT_BLAME_SYNCHRONET) || defined(_THREAD_SUID_BROKEN)
	if(!force)
		return(do_seteuid(TRUE));
#endif
296
297
	setregid(-1,old_gid);
	setreuid(-1,old_uid);
298
299
	if(setregid(new_gid,new_gid))
	{
300
301
		lputs(LOG_ERR,"!setgid FAILED");
		lputs(LOG_ERR,strerror(errno));
302
303
		result=FALSE;
	}
304

305
306
	if(setreuid(new_uid,new_uid))
	{
307
308
		lputs(LOG_ERR,"!setuid FAILED");
		lputs(LOG_ERR,strerror(errno));
309
		result=FALSE;
310
	}
311
312
313
314
	if(force && (!result))
		exit(1);

	return(result);
315
}
316
317
#endif   /* __unix__ */

318
319
#ifdef _WINSOCKAPI_

320
static WSADATA WSAData;
321
322
323
324
325
326
327
328

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

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

329
    lprintf(LOG_ERR,"!WinSock startup ERROR %d", status);
330
331
332
333
334
335
336
337
	return(FALSE);
}

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

338
	lprintf(LOG_ERR,"!WinSock cleanup ERROR %d",ERROR_VALUE);
339
340
341
342
343
344
345
346
347
348
	return(FALSE);
}

#else /* No WINSOCK */

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

#endif

349
static void thread_up(void* p, BOOL up, BOOL setuid)
350
{
351
352
353
   	static pthread_mutex_t mutex;
	static BOOL mutex_initialized;

354
355
356
#ifdef _THREAD_SUID_BROKEN
	if(up && setuid) {
		do_seteuid(FALSE);
357
		do_setuid(FALSE);
358
359
360
	}
#endif

361
362
363
364
365
366
	if(!mutex_initialized) {
		pthread_mutex_init(&mutex,NULL);
		mutex_initialized=TRUE;
	}

	pthread_mutex_lock(&mutex);
367
	if(up)
368
369
370
371
	    thread_count++;
    else if(thread_count>0)
    	thread_count--;
	pthread_mutex_unlock(&mutex);
372
	lputs(LOG_INFO,NULL); /* update displayed stats */
373
374
}

375
static void socket_open(void* p, BOOL open)
376
377
378
379
380
381
382
{
   	static pthread_mutex_t mutex;
	static BOOL mutex_initialized;

	if(!mutex_initialized) {
		pthread_mutex_init(&mutex,NULL);
		mutex_initialized=TRUE;
383
	}
384
385
386
387
388
389
390

	pthread_mutex_lock(&mutex);
	if(open)
	    socket_count++;
    else if(socket_count>0)
    	socket_count--;
	pthread_mutex_unlock(&mutex);
391
	lputs(LOG_INFO,NULL); /* update displayed stats */
392
393
}

394
static void client_on(void* p, BOOL on, int sock, client_t* client, BOOL update)
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
{
   	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);
411
	lputs(LOG_INFO,NULL); /* update displayed stats */
412
413
}

rswindell's avatar
rswindell committed
414
415
416
/****************************************************************************/
/* BBS local/log print routine												*/
/****************************************************************************/
417
static int bbs_lputs(void* p, int level, char *str)
rswindell's avatar
rswindell committed
418
419
420
421
{
	char		logline[512];
	char		tstr[64];
	time_t		t;
422
	struct tm	tm;
rswindell's avatar
rswindell committed
423

424
425
426
	if(!(bbs_startup.log_mask&(1<<level)))
		return(0);

427
428
429
430
#ifdef __unix__
	if (is_daemon)  {
		if(str==NULL)
			return(0);
431
		if (std_facilities)
432
			syslog(level|LOG_AUTH,"%s",str);
433
		else
434
			syslog(level,"     %s",str);
435
436
437
438
		return(strlen(str));
	}
#endif

439
	t=time(NULL);
440
	if(localtime_r(&t,&tm)==NULL)
441
442
443
		tstr[0]=0;
	else
		sprintf(tstr,"%d/%d %02d:%02d:%02d "
444
445
			,tm.tm_mon+1,tm.tm_mday
			,tm.tm_hour,tm.tm_min,tm.tm_sec);
rswindell's avatar
rswindell committed
446

447
	sprintf(logline,"%s     %.*s",tstr,(int)sizeof(logline)-32,str);
rswindell's avatar
rswindell committed
448
	truncsp(logline);
449
	lputs(level,logline);
rswindell's avatar
rswindell committed
450
451
452
453
	
    return(strlen(logline)+1);
}

454
static void bbs_started(void* p)
rswindell's avatar
rswindell committed
455
456
{
	bbs_running=TRUE;
457
	bbs_stopped=FALSE;
458
459
	#ifdef _THREAD_SUID_BROKEN
	    do_seteuid(FALSE);
460
	    do_setuid(FALSE);
461
	#endif
rswindell's avatar
rswindell committed
462
463
}

464
static void bbs_terminated(void* p, int code)
rswindell's avatar
rswindell committed
465
466
{
	bbs_running=FALSE;
467
	bbs_stopped=TRUE;
rswindell's avatar
rswindell committed
468
469
470
471
472
}

/****************************************************************************/
/* FTP local/log print routine												*/
/****************************************************************************/
473
static int ftp_lputs(void* p, int level, char *str)
rswindell's avatar
rswindell committed
474
475
476
477
{
	char		logline[512];
	char		tstr[64];
	time_t		t;
478
	struct tm	tm;
rswindell's avatar
rswindell committed
479

480
481
482
	if(!(ftp_startup.log_mask&(1<<level)))
		return(0);

483
484
485
486
#ifdef __unix__
	if (is_daemon)  {
		if(str==NULL)
			return(0);
487
		if (std_facilities)
488
#ifdef __solaris__
489
			syslog(level|LOG_DAEMON,"%s",str);
490
#else
491
			syslog(level|LOG_FTP,"%s",str);
492
#endif
493
		else
494
			syslog(level,"ftp  %s",str);
495
496
497
498
		return(strlen(str));
	}
#endif

499
	t=time(NULL);
500
	if(localtime_r(&t,&tm)==NULL)
501
502
503
		tstr[0]=0;
	else
		sprintf(tstr,"%d/%d %02d:%02d:%02d "
504
505
			,tm.tm_mon+1,tm.tm_mday
			,tm.tm_hour,tm.tm_min,tm.tm_sec);
rswindell's avatar
rswindell committed
506

507
	sprintf(logline,"%sftp  %.*s",tstr,(int)sizeof(logline)-32,str);
rswindell's avatar
rswindell committed
508
	truncsp(logline);
509
	lputs(level,logline);
rswindell's avatar
rswindell committed
510
511
512
513
	
    return(strlen(logline)+1);
}

514
static void ftp_started(void* p)
rswindell's avatar
rswindell committed
515
516
{
	ftp_running=TRUE;
517
	ftp_stopped=FALSE;
518
519
	#ifdef _THREAD_SUID_BROKEN
	    do_seteuid(FALSE);
520
	    do_setuid(FALSE);
521
	#endif
rswindell's avatar
rswindell committed
522
523
}

524
static void ftp_terminated(void* p, int code)
rswindell's avatar
rswindell committed
525
526
{
	ftp_running=FALSE;
527
	ftp_stopped=TRUE;
rswindell's avatar
rswindell committed
528
529
530
531
532
}

/****************************************************************************/
/* Mail Server local/log print routine										*/
/****************************************************************************/
533
static int mail_lputs(void* p, int level, char *str)
rswindell's avatar
rswindell committed
534
535
536
537
{
	char		logline[512];
	char		tstr[64];
	time_t		t;
538
	struct tm	tm;
rswindell's avatar
rswindell committed
539

540
541
542
	if(!(mail_startup.log_mask&(1<<level)))
		return(0);

543
544
545
546
#ifdef __unix__
	if (is_daemon)  {
		if(str==NULL)
			return(0);
547
		if (std_facilities)
548
			syslog(level|LOG_MAIL,"%s",str);
549
		else
550
			syslog(level,"mail %s",str);
551
552
553
554
		return(strlen(str));
	}
#endif

555
	t=time(NULL);
556
	if(localtime_r(&t,&tm)==NULL)
557
558
559
		tstr[0]=0;
	else
		sprintf(tstr,"%d/%d %02d:%02d:%02d "
560
561
			,tm.tm_mon+1,tm.tm_mday
			,tm.tm_hour,tm.tm_min,tm.tm_sec);
rswindell's avatar
rswindell committed
562

563
	sprintf(logline,"%smail %.*s",tstr,(int)sizeof(logline)-32,str);
rswindell's avatar
rswindell committed
564
	truncsp(logline);
565
	lputs(level,logline);
rswindell's avatar
rswindell committed
566
567
568
569
	
    return(strlen(logline)+1);
}

570
static void mail_started(void* p)
rswindell's avatar
rswindell committed
571
572
{
	mail_running=TRUE;
573
	mail_stopped=FALSE;
574
575
	#ifdef _THREAD_SUID_BROKEN
	    do_seteuid(FALSE);
576
	    do_setuid(FALSE);
577
	#endif
rswindell's avatar
rswindell committed
578
579
}

580
static void mail_terminated(void* p, int code)
rswindell's avatar
rswindell committed
581
582
{
	mail_running=FALSE;
583
	mail_stopped=TRUE;
rswindell's avatar
rswindell committed
584
585
}

586
587
588
/****************************************************************************/
/* Services local/log print routine											*/
/****************************************************************************/
589
static int services_lputs(void* p, int level, char *str)
590
591
592
593
{
	char		logline[512];
	char		tstr[64];
	time_t		t;
594
	struct tm	tm;
595

596
597
598
	if(!(services_startup.log_mask&(1<<level)))
		return(0);

599
600
601
602
#ifdef __unix__
	if (is_daemon)  {
		if(str==NULL)
			return(0);
603
		if (std_facilities)
604
			syslog(level|LOG_DAEMON,"%s",str);
605
		else
606
			syslog(level,"srvc %s",str);
607
608
609
610
		return(strlen(str));
	}
#endif

611
	t=time(NULL);
612
	if(localtime_r(&t,&tm)==NULL)
613
614
615
		tstr[0]=0;
	else
		sprintf(tstr,"%d/%d %02d:%02d:%02d "
616
617
			,tm.tm_mon+1,tm.tm_mday
			,tm.tm_hour,tm.tm_min,tm.tm_sec);
618

619
	sprintf(logline,"%ssrvc %.*s",tstr,(int)sizeof(logline)-32,str);
620
	truncsp(logline);
621
	lputs(level,logline);
622
623
624
625
	
    return(strlen(logline)+1);
}

626
static void services_started(void* p)
627
628
{
	services_running=TRUE;
629
	services_stopped=FALSE;
630
631
	#ifdef _THREAD_SUID_BROKEN
	    do_seteuid(FALSE);
632
	    do_setuid(FALSE);
633
	#endif
634
635
}

636
static void services_terminated(void* p, int code)
637
638
{
	services_running=FALSE;
639
	services_stopped=TRUE;
640
641
}

642
643
644
/****************************************************************************/
/* Event thread local/log print routine										*/
/****************************************************************************/
645
static int event_lputs(int level, char *str)
646
647
648
649
{
	char		logline[512];
	char		tstr[64];
	time_t		t;
650
	struct tm	tm;
651

652
653
654
	if(!(bbs_startup.log_mask&(1<<level)))
		return(0);

655
656
657
658
#ifdef __unix__
	if (is_daemon)  {
		if(str==NULL)
			return(0);
659
		if (std_facilities)
660
			syslog(level|LOG_CRON,"%s",str);
661
		else
662
			syslog(level,"evnt %s",str);
663
664
665
666
		return(strlen(str));
	}
#endif

667
	t=time(NULL);
668
	if(localtime_r(&t,&tm)==NULL)
669
670
671
		tstr[0]=0;
	else
		sprintf(tstr,"%d/%d %02d:%02d:%02d "
672
673
			,tm.tm_mon+1,tm.tm_mday
			,tm.tm_hour,tm.tm_min,tm.tm_sec);
674

675
	sprintf(logline,"%sevnt %.*s",tstr,(int)sizeof(logline)-32,str);
676
	truncsp(logline);
677
	lputs(level,logline);
678
679
680
681
	
    return(strlen(logline)+1);
}

rswindell's avatar
rswindell committed
682
683
684
/****************************************************************************/
/* web local/log print routine											*/
/****************************************************************************/
685
static int web_lputs(void* p, int level, char *str)
rswindell's avatar
rswindell committed
686
687
688
689
{
	char		logline[512];
	char		tstr[64];
	time_t		t;
690
	struct tm	tm;
rswindell's avatar
rswindell committed
691

692
693
694
	if(!(web_startup.log_mask&(1<<level)))
		return(0);

rswindell's avatar
rswindell committed
695
696
697
698
699
#ifdef __unix__
	if (is_daemon)  {
		if(str==NULL)
			return(0);
		if (std_facilities)
700
			syslog(level|LOG_DAEMON,"%s",str);
rswindell's avatar
rswindell committed
701
		else
702
			syslog(level,"web  %s",str);
rswindell's avatar
rswindell committed
703
704
705
706
707
		return(strlen(str));
	}
#endif

	t=time(NULL);
708
	if(localtime_r(&t,&tm)==NULL)
rswindell's avatar
rswindell committed
709
710
711
		tstr[0]=0;
	else
		sprintf(tstr,"%d/%d %02d:%02d:%02d "
712
713
			,tm.tm_mon+1,tm.tm_mday
			,tm.tm_hour,tm.tm_min,tm.tm_sec);
rswindell's avatar
rswindell committed
714

rswindell's avatar
rswindell committed
715
	sprintf(logline,"%sweb  %.*s",tstr,(int)sizeof(logline)-32,str);
rswindell's avatar
rswindell committed
716
	truncsp(logline);
717
	lputs(level,logline);
rswindell's avatar
rswindell committed
718
719
720
721
	
    return(strlen(logline)+1);
}

722
static void web_started(void* p)
rswindell's avatar
rswindell committed
723
724
725
726
727
{
	web_running=TRUE;
	web_stopped=FALSE;
	#ifdef _THREAD_SUID_BROKEN
	    do_seteuid(FALSE);
728
	    do_setuid(FALSE);
rswindell's avatar
rswindell committed
729
730
731
	#endif
}

732
static void web_terminated(void* p, int code)
rswindell's avatar
rswindell committed
733
734
735
736
737
{
	web_running=FALSE;
	web_stopped=TRUE;
}

738
static void terminate(void)
739
{
740
741
	ulong count=0;

742
743
744
745
	if(bbs_running)
		bbs_terminate();
	if(ftp_running)
		ftp_terminate();
746
#ifndef NO_WEB_SERVER
747
748
	if(web_running)
		web_terminate();
749
#endif
750
751
	if(mail_running)
		mail_terminate();
752
#ifndef NO_SERVICES
753
754
	if(services_running)
		services_terminate();
755
#endif
756

757
	while(bbs_running || ftp_running || web_running || mail_running || services_running)  {
758
759
		if(count && (count%10)==0) {
			if(bbs_running)
760
				lputs(LOG_INFO,"BBS System thread still running");
761
			if(ftp_running)
762
				lputs(LOG_INFO,"FTP Server thread still running");
763
			if(web_running)
764
				lputs(LOG_INFO,"Web Server thread still running");
765
			if(mail_running)
766
				lputs(LOG_INFO,"Mail Server thread still running");
767
			if(services_running)
768
				lputs(LOG_INFO,"Services thread still running");
769
770
771
		}
		count++;
		SLEEP(1000);
772
	}
773
}
774

775
776
static void read_startup_ini(BOOL recycle
							 ,bbs_startup_t* bbs, ftp_startup_t* ftp, web_startup_t* web
777
							 ,mail_startup_t* mail, services_startup_t* services)
778
779
780
781
{
	FILE*	fp=NULL;

	/* Read .ini file here */
782
783
	if(ini_file[0]!=0) { 
		if((fp=fopen(ini_file,"r"))==NULL) {
784
			lprintf(LOG_ERR,"!ERROR %d (%s) opening %s",errno,strerror(errno),ini_file);
785
		} else {
786
			lprintf(LOG_INFO,"Reading %s",ini_file);
787
		}
788
	}
789
	if(fp==NULL)
790
		lputs(LOG_WARNING,"Using default initialization values");
791
792
793

	/* We call this function to set defaults, even if there's no .ini file */
	sbbs_read_ini(fp, 
794
		NULL,			/* global_startup */
795
796
797
798
799
		&run_bbs,		bbs,
		&run_ftp,		ftp, 
		&run_web,		web,
		&run_mail,		mail, 
		&run_services,	services);
800
801
802
803
804

	/* read/default any sbbscon-specific .ini keys here */
#if defined(__unix__)
	{
		char	value[INI_MAX_VALUE_LEN];
805
806
		SAFECOPY(new_uid_name,iniReadString(fp,"UNIX","User","",value));
		SAFECOPY(new_gid_name,iniReadString(fp,"UNIX","Group","",value));
807
808
		if(!recycle)
			is_daemon=iniReadBool(fp,"UNIX","Daemonize",FALSE);
809
810
		SAFECOPY(daemon_type,iniReadString(fp,"UNIX","LogFacility","U",value));
		umask(iniReadInteger(fp,"UNIX","umask",077));
811
812
813
814
815
816
817
	}
#endif
	/* close .ini file here */
	if(fp!=NULL)
		fclose(fp);
}

818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
/* Server recycle callback (read relevant startup .ini file section)		*/
void recycle(void* cbdata)
{
	bbs_startup_t* bbs=NULL;
	ftp_startup_t* ftp=NULL;
	web_startup_t* web=NULL;
	mail_startup_t* mail=NULL;
	services_startup_t* services=NULL;

	if(cbdata==&bbs_startup)
		bbs=cbdata;
	else if(cbdata==&ftp_startup)
		ftp=cbdata;
	else if(cbdata==&web_startup)
		web=cbdata;
	else if(cbdata==&mail_startup)
		mail=cbdata;
	else if(cbdata==&services_startup)
		services=cbdata;

838
	read_startup_ini(/* recycle? */TRUE,bbs,ftp,web,mail,services);
839
}
840

841
842
843
844
845
846
847
void cleanup(void)
{
#ifdef __unix__
	unlink(SBBS_PID_FILE);
#endif
}

848
849
850
851
852
853
854
855
856
#if defined(_WIN32)
BOOL WINAPI ControlHandler(DWORD CtrlType)
{
	terminated=TRUE;
	return TRUE;
}
#endif


rswindell's avatar
rswindell committed
857
858
859
#ifdef __unix__
void _sighandler_quit(int sig)
{
860
861
862
863
864
865
866
867
868
869
870
	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? */

871
	lprintf(LOG_NOTICE,"     Got quit signal (%d)",sig);
872
873
	terminate();

874
    exit(0);
rswindell's avatar
rswindell committed
875
}
876
877
878
879

void _sighandler_rerun(int sig)
{

880
	lputs(LOG_NOTICE,"     Got HUP (rerun) signal");
881

882
883
884
885
886
	bbs_startup.recycle_now=TRUE;
	ftp_startup.recycle_now=TRUE;
	web_startup.recycle_now=TRUE;
	mail_startup.recycle_now=TRUE;
	services_startup.recycle_now=TRUE;
887
888
}

889
890
static void handle_sigs(void)
{
891
892
	int			i;
	int			sig=0;
893
	sigset_t	sigs;
894

895
	thread_up(NULL,TRUE,TRUE);
896

897
	if (is_daemon) {
898
899
900
		/* Write the standard .pid file if running as a daemon */
		/* Must be here so signals are sent to the correct thread */

901
902
903
		if(pidf!=NULL) {
			fprintf(pidf,"%d",getpid());
			fclose(pidf);
904
905
		}
	}
906

907
908
909
910
911
912
913
914
	/* Set up blocked signals */
	sigemptyset(&sigs);
	sigaddset(&sigs,SIGINT);
	sigaddset(&sigs,SIGQUIT);
	sigaddset(&sigs,SIGABRT);
	sigaddset(&sigs,SIGTERM);
	sigaddset(&sigs,SIGHUP);
	sigaddset(&sigs,SIGALRM);
915
	/* sigaddset(&sigs,SIGPIPE); */
916
917
	pthread_sigmask(SIG_BLOCK,&sigs,NULL);
	while(1)  {
918
		if((i=sigwait(&sigs,&sig))!=0) {   /* wait here until signaled */
rswindell's avatar
rswindell committed
919
			lprintf(LOG_ERR,"     !sigwait FAILURE (%d)", i);
920
921
922
			continue;
		}
		lprintf(LOG_NOTICE,"     Got signal (%d)", sig);
923
924
925
926
927
928
929
930
931
932
933
934
		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:
935
				lputs(LOG_NOTICE,"     Signal has no handler (unexpected)");
936
937
938
		}
	}
}
939
#endif	/* __unix__ */
rswindell's avatar
rswindell committed
940

941
942
943
/****************************************************************************/
/* Displays appropriate usage info											*/
/****************************************************************************/
944
static void show_usage(char *cmd)
945
946
947
948
949
950
951
952
953
954
955
956
{
	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);
}

957
#if SBBS_MAGIC_FILENAMES
958
static int command_is(char *cmdline, char *cmd)
959
{
960
	return(strnicmp(getfname(cmdline),cmd,strlen(cmd))==0);
961
}
962
#endif
963

rswindell's avatar
rswindell committed
964
965
966
967
968
/****************************************************************************/
/* Main Entry Point															*/
/****************************************************************************/
int main(int argc, char** argv)
{
969
	int		i;
970
971
	int		n;
	int		file;
972
	char	ch;
rswindell's avatar
rswindell committed
973
	char*	p;
974
	char*	arg;
rswindell's avatar
rswindell committed
975
	char*	ctrl_dir;
976
	char	str[MAX_PATH+1];
977
    char	error[256];