|
|
1.1 root 1: /* sbbscon.c */
2:
3: /* Synchronet vanilla/console-mode "front-end" */
4:
5: /* $Id: sbbscon.c,v 1.217 2006/09/20 21:30:56 deuce 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 2006 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: /* ANSI headers */
39: #include <stdio.h>
40: #include <string.h>
41: #include <signal.h>
42: #include <ctype.h>
43: #ifdef __QNX__
44: #include <locale.h>
45: #endif
46:
47: /* Synchronet-specific headers */
48: #undef SBBS /* this shouldn't be defined unless building sbbs.dll/libsbbs.so */
49: #include "sbbs.h" /* load_cfg() */
50: #include "sbbs_ini.h" /* sbbs_read_ini() */
51: #include "ftpsrvr.h" /* ftp_startup_t, ftp_server */
52: #include "mailsrvr.h" /* mail_startup_t, mail_server */
53: #include "services.h" /* services_startup_t, services_thread */
54:
55: /* XPDEV headers */
56: #include "conwrap.h" /* kbhit/getch */
57: #include "threadwrap.h" /* pthread_mutex_t */
58:
59: #ifdef __unix__
60:
61: #include <sys/types.h>
62: #include <unistd.h>
63: #include <pwd.h>
64: #include <grp.h>
65: #include <stdarg.h>
66: #include <stdlib.h> /* Is this included from somewhere else? */
67: #include <syslog.h>
68:
69: #endif
70:
71: /* Services doesn't work without JavaScript support */
72: #if !defined(JAVASCRIPT)
73: #define NO_SERVICES
74: #endif
75:
76: /* Global variables */
77: BOOL terminated=FALSE;
78:
79: BOOL run_bbs=FALSE;
80: BOOL bbs_running=FALSE;
81: BOOL bbs_stopped=FALSE;
82: BOOL has_bbs=FALSE;
83: bbs_startup_t bbs_startup;
84: BOOL run_ftp=FALSE;
85: BOOL ftp_running=FALSE;
86: BOOL ftp_stopped=FALSE;
87: BOOL has_ftp=FALSE;
88: ftp_startup_t ftp_startup;
89: BOOL run_mail=FALSE;
90: BOOL mail_running=FALSE;
91: BOOL mail_stopped=FALSE;
92: BOOL has_mail=FALSE;
93: mail_startup_t mail_startup;
94: BOOL run_services=FALSE;
95: BOOL services_running=FALSE;
96: BOOL services_stopped=FALSE;
97: BOOL has_services=FALSE;
98: services_startup_t services_startup;
99: BOOL run_web=FALSE;
100: BOOL web_running=FALSE;
101: BOOL web_stopped=FALSE;
102: BOOL has_web=FALSE;
103: web_startup_t web_startup;
104: uint thread_count=1;
105: uint socket_count=0;
106: uint client_count=0;
107: int prompt_len=0;
108: static scfg_t scfg; /* To allow rerun */
109: static ulong served=0;
110: char ini_file[MAX_PATH+1];
111:
112: #ifdef __unix__
113: char new_uid_name[32];
114: char new_gid_name[32];
115: uid_t new_uid;
116: uid_t old_uid;
117: gid_t new_gid;
118: gid_t old_gid;
119: BOOL is_daemon=FALSE;
120: char log_facility[2];
121: char log_ident[128];
122: BOOL std_facilities=FALSE;
123: FILE * pidf;
124: char pid_fname[MAX_PATH+1];
125: #endif
126:
127: static const char* prompt;
128:
129: static const char* usage = "\nusage: %s [[setting] [...]] [path/ini_file]\n"
130: "\n"
131: "Global settings:\n"
132: "\n"
133: "\thn[host] set hostname for this instance\n"
134: "\t if host not specified, uses gethostname\n"
135: #ifdef __unix__
136: "\tun<user> set username for BBS to run as\n"
137: "\tug<group> set group for BBS to run as\n"
138: "\td[x] run as daemon, log using syslog\n"
139: "\t x is the optional LOCALx facility to use\n"
140: "\t if none is specified, uses USER\n"
141: "\t if 'S' is specified, uses standard facilities\n"
142: #endif
143: "\tgi get user identity (using IDENT protocol)\n"
144: "\tnh disable hostname lookups\n"
145: "\tnj disable JavaScript support\n"
146: "\tne disable event thread\n"
147: "\tni do not read settings from .ini file\n"
148: #ifdef __unix__
149: "\tnd do not read run as daemon - overrides .ini file\n"
150: #endif
151: "\tlt use local timezone (do not force UTC/GMT)\n"
152: "\tdefaults show default settings and options\n"
153: "\n"
154: ;
155: static const char* telnet_usage = "Telnet server settings:\n\n"
156: "\ttf<node> set first Telnet node number\n"
157: "\ttl<node> set last Telnet node number\n"
158: "\ttp<port> set Telnet server port\n"
159: "\trp<port> set RLogin server port (and enable RLogin server)\n"
160: "\tr2 use second RLogin name in BSD RLogin\n"
161: "\tto<value> set Telnet server options value (advanced)\n"
162: "\tta enable auto-logon via IP address\n"
163: "\ttd enable Telnet command debug output\n"
164: "\ttc emabble sysop availability for chat\n"
165: "\ttq disable QWK events\n"
166: "\tt- disable Telnet/RLogin server\n"
167: "\n"
168: ;
169: static const char* ftp_usage = "FTP server settings:\n"
170: "\n"
171: "\tfp<port> set FTP server port\n"
172: "\tfo<value> set FTP server options value (advanced)\n"
173: "\tf- disable FTP server\n"
174: "\n"
175: ;
176: static const char* mail_usage = "Mail server settings:\n"
177: "\n"
178: "\tms<port> set SMTP server port\n"
179: "\tmp<port> set POP3 server port\n"
180: "\tmr<addr> set SMTP relay server (and enable SMTP relay)\n"
181: "\tmd<addr> set DNS server address for MX-record lookups\n"
182: "\tmo<value> set Mail server options value (advanced)\n"
183: "\tma allow SMTP relays from authenticated users\n"
184: "\tm- disable Mail server (entirely)\n"
185: "\tmp- disable POP3 server\n"
186: "\tms- disable SendMail thread\n"
187: "\n"
188: ;
189: static const char* services_usage = "Services settings:\n"
190: "\n"
191: "\tso<value> set Services option value (advanced)\n"
192: "\ts- disable Services (no services module)\n"
193: "\n"
194: ;
195: static const char* web_usage = "Web server settings:\n"
196: "\n"
197: "\twp<port> set HTTP server port\n"
198: "\two<value> set Web server option value (advanced)\n"
199: "\tw- disable Web server (no services module)\n"
200: "\n"
201: ;
202: static int lputs(int level, char *str)
203: {
204: static pthread_mutex_t mutex;
205: static BOOL mutex_initialized;
206: char *p;
207:
208: #ifdef __unix__
209:
210: if (is_daemon) {
211: if(str!=NULL) {
212: if (std_facilities)
213: syslog(level|LOG_AUTH,"%s",str);
214: else
215: syslog(level,"%s",str);
216: }
217: return(0);
218: }
219: #endif
220: if(!mutex_initialized) {
221: pthread_mutex_init(&mutex,NULL);
222: mutex_initialized=TRUE;
223: }
224: pthread_mutex_lock(&mutex);
225: /* erase prompt */
226: printf("\r%*s\r",prompt_len,"");
227: if(str!=NULL) {
228: for(p=str; *p; p++) {
229: if(iscntrl(*p))
230: printf("^%c",'@'+*p);
231: else
232: printf("%c",*p);
233: }
234: puts("");
235: }
236: /* re-display prompt with current stats */
237: if(prompt!=NULL)
238: prompt_len = printf(prompt, thread_count, socket_count, client_count, served);
239: fflush(stdout);
240: pthread_mutex_unlock(&mutex);
241:
242: return(prompt_len);
243: }
244:
245: static int lprintf(int level, char *fmt, ...)
246: {
247: va_list argptr;
248: char sbuf[1024];
249:
250: va_start(argptr,fmt);
251: vsnprintf(sbuf,sizeof(sbuf),fmt,argptr);
252: sbuf[sizeof(sbuf)-1]=0;
253: va_end(argptr);
254: return(lputs(level,sbuf));
255: }
256:
257: #ifdef __unix__
258: static pthread_mutex_t setid_mutex;
259: static BOOL setid_mutex_initialized=0;
260: /**********************************************************
261: * Change uid of the calling process to the user if specified
262: * **********************************************************/
263: static BOOL do_seteuid(BOOL to_new)
264: {
265: BOOL result=FALSE;
266:
267: if(new_uid_name[0]==0) /* not set? */
268: return(TRUE); /* do nothing */
269:
270: if(old_uid==new_uid && old_gid==new_gid)
271: return(TRUE); /* do nothing */
272:
273: if(!setid_mutex_initialized) {
274: pthread_mutex_init(&setid_mutex,NULL);
275: setid_mutex_initialized=TRUE;
276: }
277:
278: pthread_mutex_lock(&setid_mutex);
279:
280: if(to_new) {
281: if((new_gid==getegid() || setregid(-1,new_gid)==0)
282: && (new_uid==geteuid() || setreuid(-1,new_uid)==0))
283: result=TRUE;
284: else
285: result=FALSE;
286: }
287: else {
288: if((old_gid==getegid() || setregid(-1,old_gid)==0)
289: && (old_uid==geteuid() || setreuid(-1,old_uid)==0))
290: result=TRUE;
291: else
292: result=FALSE;
293: }
294:
295: pthread_mutex_unlock(&setid_mutex);
296:
297: if(!result) {
298: lputs(LOG_ERR,"!seteuid FAILED");
299: lputs(LOG_ERR,strerror(errno));
300: }
301: return result;
302: }
303:
304: /**********************************************************
305: * Change uid of the calling process to the user if specified
306: * **********************************************************/
307: BOOL do_setuid(BOOL force)
308: {
309: BOOL result=TRUE;
310: #if defined(DONT_BLAME_SYNCHRONET)
311: if(!force)
312: return(do_seteuid(TRUE));
313: #endif
314:
315: #if defined(_THREAD_SUID_BROKEN)
316: if(thread_suid_broken && (!force))
317: return(do_seteuid(TRUE));
318: #endif
319:
320: if(old_uid==new_uid && old_gid==new_gid)
321: return(TRUE); /* do nothing */
322:
323: if(!setid_mutex_initialized) {
324: pthread_mutex_init(&setid_mutex,NULL);
325: setid_mutex_initialized=TRUE;
326: }
327:
328: pthread_mutex_lock(&setid_mutex);
329:
330: if(getegid()!=old_gid)
331: setregid(-1,old_gid);
332: if(geteuid()!=old_gid)
333: setreuid(-1,old_uid);
334: if(getgid() != new_gid || getegid() != new_gid) {
335: if(setregid(new_gid,new_gid))
336: {
337: lputs(LOG_ERR,"!setgid FAILED");
338: lputs(LOG_ERR,strerror(errno));
339: result=FALSE;
340: }
341: }
342:
343: if(getuid() != new_uid || geteuid() != new_uid) {
344: if(setreuid(new_uid,new_uid))
345: {
346: lputs(LOG_ERR,"!setuid FAILED");
347: lputs(LOG_ERR,strerror(errno));
348: result=FALSE;
349: }
350: }
351:
352: pthread_mutex_unlock(&setid_mutex);
353:
354: if(force && (!result))
355: exit(1);
356:
357: return(result);
358: }
359: #endif /* __unix__ */
360:
361: #ifdef _WINSOCKAPI_
362:
363: static WSADATA WSAData;
364:
365: static BOOL winsock_startup(void)
366: {
367: int status; /* Status Code */
368:
369: if((status = WSAStartup(MAKEWORD(1,1), &WSAData))==0)
370: return(TRUE);
371:
372: lprintf(LOG_ERR,"!WinSock startup ERROR %d", status);
373: return(FALSE);
374: }
375:
376: static BOOL winsock_cleanup(void)
377: {
378: if(WSACleanup()==0)
379: return(TRUE);
380:
381: lprintf(LOG_ERR,"!WinSock cleanup ERROR %d",ERROR_VALUE);
382: return(FALSE);
383: }
384:
385: #else /* No WINSOCK */
386:
387: #define winsock_startup() (TRUE)
388: #define winsock_cleanup() (TRUE)
389:
390: #endif
391:
392: static void thread_up(void* p, BOOL up, BOOL setuid)
393: {
394: static pthread_mutex_t mutex;
395: static BOOL mutex_initialized;
396:
397: #ifdef _THREAD_SUID_BROKEN
398: if(thread_suid_broken && up && setuid) {
399: do_seteuid(FALSE);
400: do_setuid(FALSE);
401: }
402: #endif
403:
404: if(!mutex_initialized) {
405: pthread_mutex_init(&mutex,NULL);
406: mutex_initialized=TRUE;
407: }
408:
409: pthread_mutex_lock(&mutex);
410:
411: if(up)
412: thread_count++;
413: else if(thread_count>0)
414: thread_count--;
415: pthread_mutex_unlock(&mutex);
416: lputs(LOG_INFO,NULL); /* update displayed stats */
417: }
418:
419: static void socket_open(void* p, BOOL open)
420: {
421: static pthread_mutex_t mutex;
422: static BOOL mutex_initialized;
423:
424: if(!mutex_initialized) {
425: pthread_mutex_init(&mutex,NULL);
426: mutex_initialized=TRUE;
427: }
428:
429: pthread_mutex_lock(&mutex);
430: if(open)
431: socket_count++;
432: else if(socket_count>0)
433: socket_count--;
434: pthread_mutex_unlock(&mutex);
435: lputs(LOG_INFO,NULL); /* update displayed stats */
436: }
437:
438: static void client_on(void* p, BOOL on, int sock, client_t* client, BOOL update)
439: {
440: static pthread_mutex_t mutex;
441: static BOOL mutex_initialized;
442:
443: if(!mutex_initialized) {
444: pthread_mutex_init(&mutex,NULL);
445: mutex_initialized=TRUE;
446: }
447:
448: pthread_mutex_lock(&mutex);
449: if(on && !update) {
450: client_count++;
451: served++;
452: } else if(!on && client_count>0)
453: client_count--;
454: pthread_mutex_unlock(&mutex);
455: lputs(LOG_INFO,NULL); /* update displayed stats */
456: }
457:
458: /****************************************************************************/
459: /* BBS local/log print routine */
460: /****************************************************************************/
461: static int bbs_lputs(void* p, int level, char *str)
462: {
463: char logline[512];
464: char tstr[64];
465: time_t t;
466: struct tm tm;
467:
468: if(level > bbs_startup.log_level)
469: return(0);
470:
471: #ifdef __unix__
472: if (is_daemon) {
473: if(str==NULL)
474: return(0);
475: if (std_facilities)
476: syslog(level|LOG_AUTH,"%s",str);
477: else
478: syslog(level," %s",str);
479: return(strlen(str));
480: }
481: #endif
482:
483: t=time(NULL);
484: if(localtime_r(&t,&tm)==NULL)
485: tstr[0]=0;
486: else
487: sprintf(tstr,"%d/%d %02d:%02d:%02d "
488: ,tm.tm_mon+1,tm.tm_mday
489: ,tm.tm_hour,tm.tm_min,tm.tm_sec);
490:
491: sprintf(logline,"%s %.*s",tstr,(int)sizeof(logline)-32,str);
492: truncsp(logline);
493: lputs(level,logline);
494:
495: return(strlen(logline)+1);
496: }
497:
498: static void bbs_started(void* p)
499: {
500: bbs_running=TRUE;
501: bbs_stopped=FALSE;
502: #ifdef _THREAD_SUID_BROKEN
503: if(thread_suid_broken) {
504: do_seteuid(FALSE);
505: do_setuid(FALSE);
506: }
507: #endif
508: }
509:
510: static void bbs_terminated(void* p, int code)
511: {
512: bbs_running=FALSE;
513: bbs_stopped=TRUE;
514: }
515:
516: /****************************************************************************/
517: /* FTP local/log print routine */
518: /****************************************************************************/
519: static int ftp_lputs(void* p, int level, char *str)
520: {
521: char logline[512];
522: char tstr[64];
523: time_t t;
524: struct tm tm;
525:
526: if(level > ftp_startup.log_level)
527: return(0);
528:
529: #ifdef __unix__
530: if (is_daemon) {
531: if(str==NULL)
532: return(0);
533: if (std_facilities)
534: #ifdef __solaris__
535: syslog(level|LOG_DAEMON,"%s",str);
536: #else
537: syslog(level|LOG_FTP,"%s",str);
538: #endif
539: else
540: syslog(level,"ftp %s",str);
541: return(strlen(str));
542: }
543: #endif
544:
545: t=time(NULL);
546: if(localtime_r(&t,&tm)==NULL)
547: tstr[0]=0;
548: else
549: sprintf(tstr,"%d/%d %02d:%02d:%02d "
550: ,tm.tm_mon+1,tm.tm_mday
551: ,tm.tm_hour,tm.tm_min,tm.tm_sec);
552:
553: sprintf(logline,"%sftp %.*s",tstr,(int)sizeof(logline)-32,str);
554: truncsp(logline);
555: lputs(level,logline);
556:
557: return(strlen(logline)+1);
558: }
559:
560: static void ftp_started(void* p)
561: {
562: ftp_running=TRUE;
563: ftp_stopped=FALSE;
564: #ifdef _THREAD_SUID_BROKEN
565: if(thread_suid_broken) {
566: do_seteuid(FALSE);
567: do_setuid(FALSE);
568: }
569: #endif
570: }
571:
572: static void ftp_terminated(void* p, int code)
573: {
574: ftp_running=FALSE;
575: ftp_stopped=TRUE;
576: }
577:
578: /****************************************************************************/
579: /* Mail Server local/log print routine */
580: /****************************************************************************/
581: static int mail_lputs(void* p, int level, char *str)
582: {
583: char logline[512];
584: char tstr[64];
585: time_t t;
586: struct tm tm;
587:
588: if(level > mail_startup.log_level)
589: return(0);
590:
591: #ifdef __unix__
592: if (is_daemon) {
593: if(str==NULL)
594: return(0);
595: if (std_facilities)
596: syslog(level|LOG_MAIL,"%s",str);
597: else
598: syslog(level,"mail %s",str);
599: return(strlen(str));
600: }
601: #endif
602:
603: t=time(NULL);
604: if(localtime_r(&t,&tm)==NULL)
605: tstr[0]=0;
606: else
607: sprintf(tstr,"%d/%d %02d:%02d:%02d "
608: ,tm.tm_mon+1,tm.tm_mday
609: ,tm.tm_hour,tm.tm_min,tm.tm_sec);
610:
611: sprintf(logline,"%smail %.*s",tstr,(int)sizeof(logline)-32,str);
612: truncsp(logline);
613: lputs(level,logline);
614:
615: return(strlen(logline)+1);
616: }
617:
618: static void mail_started(void* p)
619: {
620: mail_running=TRUE;
621: mail_stopped=FALSE;
622: #ifdef _THREAD_SUID_BROKEN
623: if(thread_suid_broken) {
624: do_seteuid(FALSE);
625: do_setuid(FALSE);
626: }
627: #endif
628: }
629:
630: static void mail_terminated(void* p, int code)
631: {
632: mail_running=FALSE;
633: mail_stopped=TRUE;
634: }
635:
636: /****************************************************************************/
637: /* Services local/log print routine */
638: /****************************************************************************/
639: static int services_lputs(void* p, int level, char *str)
640: {
641: char logline[512];
642: char tstr[64];
643: time_t t;
644: struct tm tm;
645:
646: if(level > services_startup.log_level)
647: return(0);
648:
649: #ifdef __unix__
650: if (is_daemon) {
651: if(str==NULL)
652: return(0);
653: if (std_facilities)
654: syslog(level|LOG_DAEMON,"%s",str);
655: else
656: syslog(level,"srvc %s",str);
657: return(strlen(str));
658: }
659: #endif
660:
661: t=time(NULL);
662: if(localtime_r(&t,&tm)==NULL)
663: tstr[0]=0;
664: else
665: sprintf(tstr,"%d/%d %02d:%02d:%02d "
666: ,tm.tm_mon+1,tm.tm_mday
667: ,tm.tm_hour,tm.tm_min,tm.tm_sec);
668:
669: sprintf(logline,"%ssrvc %.*s",tstr,(int)sizeof(logline)-32,str);
670: truncsp(logline);
671: lputs(level,logline);
672:
673: return(strlen(logline)+1);
674: }
675:
676: static void services_started(void* p)
677: {
678: services_running=TRUE;
679: services_stopped=FALSE;
680: #ifdef _THREAD_SUID_BROKEN
681: if(thread_suid_broken) {
682: do_seteuid(FALSE);
683: do_setuid(FALSE);
684: }
685: #endif
686: }
687:
688: static void services_terminated(void* p, int code)
689: {
690: services_running=FALSE;
691: services_stopped=TRUE;
692: }
693:
694: /****************************************************************************/
695: /* Event thread local/log print routine */
696: /****************************************************************************/
697: static int event_lputs(int level, char *str)
698: {
699: char logline[512];
700: char tstr[64];
701: time_t t;
702: struct tm tm;
703:
704: if(level > bbs_startup.log_level)
705: return(0);
706:
707: #ifdef __unix__
708: if (is_daemon) {
709: if(str==NULL)
710: return(0);
711: if (std_facilities)
712: syslog(level|LOG_CRON,"%s",str);
713: else
714: syslog(level,"evnt %s",str);
715: return(strlen(str));
716: }
717: #endif
718:
719: t=time(NULL);
720: if(localtime_r(&t,&tm)==NULL)
721: tstr[0]=0;
722: else
723: sprintf(tstr,"%d/%d %02d:%02d:%02d "
724: ,tm.tm_mon+1,tm.tm_mday
725: ,tm.tm_hour,tm.tm_min,tm.tm_sec);
726:
727: sprintf(logline,"%sevnt %.*s",tstr,(int)sizeof(logline)-32,str);
728: truncsp(logline);
729: lputs(level,logline);
730:
731: return(strlen(logline)+1);
732: }
733:
734: /****************************************************************************/
735: /* web local/log print routine */
736: /****************************************************************************/
737: static int web_lputs(void* p, int level, char *str)
738: {
739: char logline[512];
740: char tstr[64];
741: time_t t;
742: struct tm tm;
743:
744: if(level > web_startup.log_level)
745: return(0);
746:
747: #ifdef __unix__
748: if (is_daemon) {
749: if(str==NULL)
750: return(0);
751: if (std_facilities)
752: syslog(level|LOG_DAEMON,"%s",str);
753: else
754: syslog(level,"web %s",str);
755: return(strlen(str));
756: }
757: #endif
758:
759: t=time(NULL);
760: if(localtime_r(&t,&tm)==NULL)
761: tstr[0]=0;
762: else
763: sprintf(tstr,"%d/%d %02d:%02d:%02d "
764: ,tm.tm_mon+1,tm.tm_mday
765: ,tm.tm_hour,tm.tm_min,tm.tm_sec);
766:
767: sprintf(logline,"%sweb %.*s",tstr,(int)sizeof(logline)-32,str);
768: truncsp(logline);
769: lputs(level,logline);
770:
771: return(strlen(logline)+1);
772: }
773:
774: static void web_started(void* p)
775: {
776: web_running=TRUE;
777: web_stopped=FALSE;
778: #ifdef _THREAD_SUID_BROKEN
779: if(thread_suid_broken) {
780: do_seteuid(FALSE);
781: do_setuid(FALSE);
782: }
783: #endif
784: }
785:
786: static void web_terminated(void* p, int code)
787: {
788: web_running=FALSE;
789: web_stopped=TRUE;
790: }
791:
792: static void terminate(void)
793: {
794: ulong count=0;
795:
796: if(bbs_running)
797: bbs_terminate();
798: if(ftp_running)
799: ftp_terminate();
800: #ifndef NO_WEB_SERVER
801: if(web_running)
802: web_terminate();
803: #endif
804: if(mail_running)
805: mail_terminate();
806: #ifndef NO_SERVICES
807: if(services_running)
808: services_terminate();
809: #endif
810:
811: while(bbs_running || ftp_running || web_running || mail_running || services_running) {
812: if(count && (count%10)==0) {
813: if(bbs_running)
814: lputs(LOG_INFO,"BBS System thread still running");
815: if(ftp_running)
816: lputs(LOG_INFO,"FTP Server thread still running");
817: if(web_running)
818: lputs(LOG_INFO,"Web Server thread still running");
819: if(mail_running)
820: lputs(LOG_INFO,"Mail Server thread still running");
821: if(services_running)
822: lputs(LOG_INFO,"Services thread still running");
823: }
824: count++;
825: SLEEP(1000);
826: }
827: }
828:
829: static void read_startup_ini(BOOL recycle
830: ,bbs_startup_t* bbs, ftp_startup_t* ftp, web_startup_t* web
831: ,mail_startup_t* mail, services_startup_t* services)
832: {
833: FILE* fp=NULL;
834:
835: /* Read .ini file here */
836: if(ini_file[0]!=0) {
837: if((fp=fopen(ini_file,"r"))==NULL) {
838: lprintf(LOG_ERR,"!ERROR %d (%s) opening %s",errno,strerror(errno),ini_file);
839: } else {
840: lprintf(LOG_INFO,"Reading %s",ini_file);
841: }
842: }
843: if(fp==NULL)
844: lputs(LOG_WARNING,"Using default initialization values");
845:
846: /* We call this function to set defaults, even if there's no .ini file */
847: sbbs_read_ini(fp,
848: NULL, /* global_startup */
849: &run_bbs, bbs,
850: &run_ftp, ftp,
851: &run_web, web,
852: &run_mail, mail,
853: &run_services, services);
854:
855: /* read/default any sbbscon-specific .ini keys here */
856: #if defined(__unix__)
857: {
858: char value[INI_MAX_VALUE_LEN];
859: char* section="UNIX";
860: SAFECOPY(new_uid_name,iniReadString(fp,section,"User","",value));
861: SAFECOPY(new_gid_name,iniReadString(fp,section,"Group","",value));
862: if(!recycle)
863: is_daemon=iniReadBool(fp,section,"Daemonize",FALSE);
864: SAFECOPY(log_facility,iniReadString(fp,section,"LogFacility","U",value));
865: SAFECOPY(log_ident,iniReadString(fp,section,"LogIdent","synchronet",value));
866: SAFECOPY(pid_fname,iniReadString(fp,section,"PidFile","/var/run/sbbs.pid",value));
867: umask(iniReadInteger(fp,section,"umask",077));
868: }
869: #endif
870: /* close .ini file here */
871: if(fp!=NULL)
872: fclose(fp);
873: }
874:
875: /* Server recycle callback (read relevant startup .ini file section) */
876: void recycle(void* cbdata)
877: {
878: bbs_startup_t* bbs=NULL;
879: ftp_startup_t* ftp=NULL;
880: web_startup_t* web=NULL;
881: mail_startup_t* mail=NULL;
882: services_startup_t* services=NULL;
883:
884: if(cbdata==&bbs_startup)
885: bbs=cbdata;
886: else if(cbdata==&ftp_startup)
887: ftp=cbdata;
888: else if(cbdata==&web_startup)
889: web=cbdata;
890: else if(cbdata==&mail_startup)
891: mail=cbdata;
892: else if(cbdata==&services_startup)
893: services=cbdata;
894:
895: read_startup_ini(/* recycle? */TRUE,bbs,ftp,web,mail,services);
896: }
897:
898: void cleanup(void)
899: {
900: #ifdef __unix__
901: unlink(pid_fname);
902: #endif
903: }
904:
905: #if defined(_WIN32)
906: BOOL WINAPI ControlHandler(DWORD CtrlType)
907: {
908: terminated=TRUE;
909: return TRUE;
910: }
911: #endif
912:
913:
914: #ifdef __unix__
915: void _sighandler_quit(int sig)
916: {
917: char str[1024];
918: static pthread_mutex_t mutex;
919: static BOOL mutex_initialized;
920:
921: if(!mutex_initialized) {
922: pthread_mutex_init(&mutex,NULL);
923: mutex_initialized=TRUE;
924: }
925: pthread_mutex_lock(&mutex);
926: /* Can I get away with leaving this locked till exit? */
927:
928: lprintf(LOG_NOTICE," Got quit signal (%d)",sig);
929: terminate();
930:
931: exit(0);
932: }
933:
934: void _sighandler_rerun(int sig)
935: {
936:
937: lputs(LOG_NOTICE," Got HUP (rerun) signal");
938:
939: bbs_startup.recycle_now=TRUE;
940: ftp_startup.recycle_now=TRUE;
941: web_startup.recycle_now=TRUE;
942: mail_startup.recycle_now=TRUE;
943: services_startup.recycle_now=TRUE;
944: }
945:
946: static void handle_sigs(void)
947: {
948: int i;
949: int sig=0;
950: sigset_t sigs;
951:
952: thread_up(NULL,TRUE,TRUE);
953:
954: if (is_daemon) {
955: /* Write the standard .pid file if running as a daemon */
956: /* Must be here so signals are sent to the correct thread */
957:
958: if(pidf!=NULL) {
959: fprintf(pidf,"%d",getpid());
960: fclose(pidf);
961: pidf=NULL;
962: }
963: }
964:
965: /* Set up blocked signals */
966: sigemptyset(&sigs);
967: sigaddset(&sigs,SIGINT);
968: sigaddset(&sigs,SIGQUIT);
969: sigaddset(&sigs,SIGABRT);
970: sigaddset(&sigs,SIGTERM);
971: sigaddset(&sigs,SIGHUP);
972: sigaddset(&sigs,SIGALRM);
973: /* sigaddset(&sigs,SIGPIPE); */
974: pthread_sigmask(SIG_BLOCK,&sigs,NULL);
975: while(1) {
976: if((i=sigwait(&sigs,&sig))!=0) { /* wait here until signaled */
977: lprintf(LOG_ERR," !sigwait FAILURE (%d)", i);
978: continue;
979: }
980: lprintf(LOG_NOTICE," Got signal (%d)", sig);
981: switch(sig) {
982: /* QUIT-type signals */
983: case SIGINT:
984: case SIGQUIT:
985: case SIGABRT:
986: case SIGTERM:
987: _sighandler_quit(sig);
988: break;
989: case SIGHUP: /* rerun */
990: _sighandler_rerun(sig);
991: break;
992: default:
993: lputs(LOG_NOTICE," Signal has no handler (unexpected)");
994: }
995: }
996: }
997: #endif /* __unix__ */
998:
999: /****************************************************************************/
1000: /* Displays appropriate usage info */
1001: /****************************************************************************/
1002: static void show_usage(char *cmd)
1003: {
1004: printf(usage,cmd);
1005: if(has_bbs)
1006: printf(telnet_usage);
1007: if(has_ftp)
1008: printf(ftp_usage);
1009: if(has_mail)
1010: printf(mail_usage);
1011: if(has_services)
1012: printf(services_usage);
1013: if(has_web)
1014: printf(web_usage);
1015: }
1016:
1017: #if SBBS_MAGIC_FILENAMES
1018: static int command_is(char *cmdline, char *cmd)
1019: {
1020: return(strnicmp(getfname(cmdline),cmd,strlen(cmd))==0);
1021: }
1022: #endif
1023:
1024: /****************************************************************************/
1025: /* Main Entry Point */
1026: /****************************************************************************/
1027: int main(int argc, char** argv)
1028: {
1029: int i;
1030: int n;
1031: int file;
1032: char ch;
1033: char* p;
1034: char* arg;
1035: char* ctrl_dir;
1036: char str[MAX_PATH+1];
1037: char error[256];
1038: char host_name[128]="";
1039: node_t node;
1040: #ifdef __unix__
1041: struct passwd* pw_entry;
1042: struct group* gr_entry;
1043: sigset_t sigs;
1044: #endif
1045: #ifdef _THREAD_SUID_BROKEN
1046: size_t conflen;
1047: #endif
1048:
1049: #ifdef __QNX__
1050: setlocale( LC_ALL, "C-TRADITIONAL" );
1051: #endif
1052: #ifdef __unix__
1053: setsid(); /* Disassociate from controlling terminal */
1054: umask(077);
1055: #endif
1056: printf("\nSynchronet Console for %s Version %s%c %s\n\n"
1057: ,PLATFORM_DESC,VERSION,REVISION,COPYRIGHT_NOTICE);
1058:
1059: atexit(cleanup);
1060:
1061: ctrl_dir=getenv("SBBSCTRL"); /* read from environment variable */
1062: if(ctrl_dir==NULL || ctrl_dir[0]==0) {
1063: ctrl_dir="/sbbs/ctrl"; /* Not set? Use default */
1064: printf("!SBBSCTRL environment variable not set, using default value: %s\n\n"
1065: ,ctrl_dir);
1066: }
1067:
1068: if(!winsock_startup())
1069: return(-1);
1070:
1071: gethostname(host_name,sizeof(host_name)-1);
1072:
1073: if(!winsock_cleanup())
1074: return(-1);
1075:
1076: sbbs_get_ini_fname(ini_file, ctrl_dir, host_name);
1077:
1078: /* Initialize BBS startup structure */
1079: memset(&bbs_startup,0,sizeof(bbs_startup));
1080: bbs_startup.size=sizeof(bbs_startup);
1081: bbs_startup.cbdata=&bbs_startup;
1082: bbs_startup.log_level = LOG_DEBUG;
1083: bbs_startup.lputs=bbs_lputs;
1084: bbs_startup.event_lputs=event_lputs;
1085: bbs_startup.started=bbs_started;
1086: bbs_startup.recycle=recycle;
1087: bbs_startup.terminated=bbs_terminated;
1088: bbs_startup.thread_up=thread_up;
1089: bbs_startup.socket_open=socket_open;
1090: bbs_startup.client_on=client_on;
1091: #ifdef __unix__
1092: bbs_startup.seteuid=do_seteuid;
1093: bbs_startup.setuid=do_setuid;
1094: #endif
1095: /* These callbacks haven't been created yet
1096: bbs_startup.status=bbs_status;
1097: bbs_startup.clients=bbs_clients;
1098: */
1099: strcpy(bbs_startup.ctrl_dir,ctrl_dir);
1100:
1101: /* Initialize FTP startup structure */
1102: memset(&ftp_startup,0,sizeof(ftp_startup));
1103: ftp_startup.size=sizeof(ftp_startup);
1104: ftp_startup.cbdata=&ftp_startup;
1105: ftp_startup.log_level = LOG_DEBUG;
1106: ftp_startup.lputs=ftp_lputs;
1107: ftp_startup.started=ftp_started;
1108: ftp_startup.recycle=recycle;
1109: ftp_startup.terminated=ftp_terminated;
1110: ftp_startup.thread_up=thread_up;
1111: ftp_startup.socket_open=socket_open;
1112: ftp_startup.client_on=client_on;
1113: #ifdef __unix__
1114: ftp_startup.seteuid=do_seteuid;
1115: ftp_startup.setuid=do_setuid;
1116: #endif
1117: strcpy(ftp_startup.index_file_name,"00index");
1118: strcpy(ftp_startup.ctrl_dir,ctrl_dir);
1119:
1120: /* Initialize Web Server startup structure */
1121: memset(&web_startup,0,sizeof(web_startup));
1122: web_startup.size=sizeof(web_startup);
1123: web_startup.cbdata=&web_startup;
1124: web_startup.log_level = LOG_DEBUG;
1125: web_startup.lputs=web_lputs;
1126: web_startup.started=web_started;
1127: web_startup.recycle=recycle;
1128: web_startup.terminated=web_terminated;
1129: web_startup.thread_up=thread_up;
1130: web_startup.socket_open=socket_open;
1131: web_startup.client_on=client_on;
1132: #ifdef __unix__
1133: web_startup.seteuid=do_seteuid;
1134: web_startup.setuid=do_setuid;
1135: #endif
1136: strcpy(web_startup.ctrl_dir,ctrl_dir);
1137:
1138: /* Initialize Mail Server startup structure */
1139: memset(&mail_startup,0,sizeof(mail_startup));
1140: mail_startup.size=sizeof(mail_startup);
1141: mail_startup.cbdata=&mail_startup;
1142: mail_startup.log_level = LOG_DEBUG;
1143: mail_startup.lputs=mail_lputs;
1144: mail_startup.started=mail_started;
1145: mail_startup.recycle=recycle;
1146: mail_startup.terminated=mail_terminated;
1147: mail_startup.thread_up=thread_up;
1148: mail_startup.socket_open=socket_open;
1149: mail_startup.client_on=client_on;
1150: #ifdef __unix__
1151: mail_startup.seteuid=do_seteuid;
1152: mail_startup.setuid=do_setuid;
1153: #endif
1154: strcpy(mail_startup.ctrl_dir,ctrl_dir);
1155:
1156: /* Initialize Services startup structure */
1157: memset(&services_startup,0,sizeof(services_startup));
1158: services_startup.size=sizeof(services_startup);
1159: services_startup.cbdata=&services_startup;
1160: services_startup.log_level = LOG_DEBUG;
1161: services_startup.lputs=services_lputs;
1162: services_startup.started=services_started;
1163: services_startup.recycle=recycle;
1164: services_startup.terminated=services_terminated;
1165: services_startup.thread_up=thread_up;
1166: services_startup.socket_open=socket_open;
1167: services_startup.client_on=client_on;
1168: #ifdef __unix__
1169: services_startup.seteuid=do_seteuid;
1170: services_startup.setuid=do_setuid;
1171: #endif
1172: strcpy(services_startup.ctrl_dir,ctrl_dir);
1173:
1174: /* Pre-INI command-line switches */
1175: for(i=1;i<argc;i++) {
1176: arg=argv[i];
1177: while(*arg=='-')
1178: arg++;
1179: if(strcspn(arg,"\\/")!=strlen(arg)) {
1180: strcpy(ini_file,arg);
1181: continue;
1182: }
1183: if(!stricmp(arg,"ni")) {
1184: ini_file[0]=0;
1185: break;
1186: }
1187: }
1188:
1189: read_startup_ini(/* recycle? */FALSE
1190: ,&bbs_startup, &ftp_startup, &web_startup, &mail_startup, &services_startup);
1191:
1192: #if SBBS_MAGIC_FILENAMES /* This stuff is just broken */
1193:
1194: if(!command_is(argv[0],"sbbs")) {
1195: run_bbs=has_bbs=FALSE;
1196: run_ftp=has_ftp=FALSE;
1197: run_mail=has_mail=FALSE;
1198: run_services=has_services=FALSE;
1199: run_web=has_web=FALSE;
1200: }
1201: if(command_is(argv[0],"sbbs_ftp"))
1202: run_ftp=has_ftp=TRUE;
1203: else if(command_is(argv[0],"sbbs_mail"))
1204: run_mail=has_mail=TRUE;
1205: else if(command_is(argv[0],"sbbs_bbs"))
1206: run_bbs=has_bbs=TRUE;
1207: #ifndef NO_SERVICES
1208: else if(command_is(argv[0],"sbbs_srvc"))
1209: run_services=has_services=TRUE;
1210: #endif
1211: #ifndef NO_WEB_SERVER
1212: else if(command_is(argv[0],"sbbs_web"))
1213: run_web=has_web=TRUE;
1214: #endif
1215: else {
1216: run_bbs=has_bbs=TRUE;
1217: run_ftp=has_ftp=TRUE;
1218: run_mail=has_mail=TRUE;
1219: #ifndef NO_SERVICES
1220: run_services=has_services=TRUE;
1221: #endif
1222: #ifndef NO_WEB_SERVER
1223: run_web=has_web=TRUE;
1224: #endif
1225: }
1226: #else
1227: has_web=has_bbs=has_ftp=has_mail=has_services=TRUE;
1228: #endif /* Removed broken stuff */
1229:
1230: /* Post-INI command-line switches */
1231: for(i=1;i<argc;i++) {
1232: arg=argv[i];
1233: while(*arg=='-')
1234: arg++;
1235: if(strcspn(arg,"\\/")!=strlen(arg)) /* ini_file name */
1236: continue;
1237: if(!stricmp(arg,"defaults")) {
1238: printf("Default settings:\n");
1239: printf("\n");
1240: printf("Telnet server port:\t%u\n",bbs_startup.telnet_port);
1241: printf("Telnet first node:\t%u\n",bbs_startup.first_node);
1242: printf("Telnet last node:\t%u\n",bbs_startup.last_node);
1243: printf("Telnet server options:\t0x%08lX\n",bbs_startup.options);
1244: printf("FTP server port:\t%u\n",ftp_startup.port);
1245: printf("FTP server options:\t0x%08lX\n",ftp_startup.options);
1246: printf("Mail SMTP server port:\t%u\n",mail_startup.smtp_port);
1247: printf("Mail SMTP relay port:\t%u\n",mail_startup.relay_port);
1248: printf("Mail POP3 server port:\t%u\n",mail_startup.pop3_port);
1249: printf("Mail server options:\t0x%08lX\n",mail_startup.options);
1250: printf("Services options:\t0x%08lX\n",services_startup.options);
1251: printf("Web server port:\t%u\n",web_startup.port);
1252: printf("Web server options:\t0x%08lX\n",web_startup.options);
1253: return(0);
1254: }
1255: switch(toupper(*(arg++))) {
1256: #ifdef __unix__
1257: case 'D': /* Run as daemon */
1258: is_daemon=TRUE;
1259: if(*arg)
1260: SAFECOPY(log_facility,arg++);
1261: break;
1262: #endif
1263: case 'T': /* Telnet settings */
1264: switch(toupper(*(arg++))) {
1265: case '-':
1266: run_bbs=FALSE;
1267: break;
1268: case 'D': /* debug output */
1269: bbs_startup.options|=BBS_OPT_DEBUG_TELNET;
1270: break;
1271: case 'A': /* Auto-logon via IP */
1272: bbs_startup.options|=BBS_OPT_AUTO_LOGON;
1273: break;
1274: case 'Q': /* No QWK events */
1275: bbs_startup.options|=BBS_OPT_NO_QWK_EVENTS;
1276: break;
1277: case 'C': /* Sysop available for chat */
1278: bbs_startup.options|=BBS_OPT_SYSOP_AVAILABLE;
1279: break;
1280: case 'O': /* Set options */
1281: bbs_startup.options=strtoul(arg,NULL,0);
1282: break;
1283: case 'P':
1284: bbs_startup.telnet_port=atoi(arg);
1285: break;
1286: case 'F':
1287: bbs_startup.first_node=atoi(arg);
1288: break;
1289: case 'L':
1290: bbs_startup.last_node=atoi(arg);
1291: break;
1292: default:
1293: show_usage(argv[0]);
1294: return(1);
1295: }
1296: break;
1297: case 'R': /* RLogin */
1298: bbs_startup.options|=BBS_OPT_ALLOW_RLOGIN;
1299: switch(toupper(*(arg++))) {
1300: case 'P':
1301: bbs_startup.rlogin_port=atoi(arg);
1302: break;
1303: case '2':
1304: bbs_startup.options|=BBS_OPT_USE_2ND_RLOGIN;
1305: break;
1306: default:
1307: show_usage(argv[0]);
1308: return(1);
1309: }
1310: break;
1311: case 'F': /* FTP */
1312: switch(toupper(*(arg++))) {
1313: case '-':
1314: run_ftp=FALSE;
1315: break;
1316: case 'P':
1317: ftp_startup.port=atoi(arg);
1318: break;
1319: case 'O': /* Set options */
1320: ftp_startup.options=strtoul(arg,NULL,0);
1321: break;
1322: default:
1323: show_usage(argv[0]);
1324: return(1);
1325: }
1326: break;
1327: case 'M': /* Mail */
1328: switch(toupper(*(arg++))) {
1329: case '-':
1330: run_mail=FALSE;
1331: break;
1332: case 'O': /* Set options */
1333: mail_startup.options=strtoul(arg,NULL,0);
1334: break;
1335: case 'S': /* SMTP/SendMail */
1336: if(isdigit(*arg)) {
1337: mail_startup.smtp_port=atoi(arg);
1338: break;
1339: }
1340: switch(toupper(*(arg++))) {
1341: case '-':
1342: mail_startup.options|=MAIL_OPT_NO_SENDMAIL;
1343: break;
1344: default:
1345: show_usage(argv[0]);
1346: return(1);
1347: }
1348: break;
1349: case 'P': /* POP3 */
1350: if(isdigit(*arg)) {
1351: mail_startup.pop3_port=atoi(arg);
1352: break;
1353: }
1354: switch(toupper(*(arg++))) {
1355: case '-':
1356: mail_startup.options&=~MAIL_OPT_ALLOW_POP3;
1357: break;
1358: default:
1359: show_usage(argv[0]);
1360: return(1);
1361: }
1362: break;
1363: case 'R': /* Relay */
1364: mail_startup.options|=MAIL_OPT_RELAY_TX;
1365: p=strchr(arg,':'); /* port specified */
1366: if(p!=NULL) {
1367: *p=0;
1368: mail_startup.relay_port=atoi(p+1);
1369: }
1370: SAFECOPY(mail_startup.relay_server,arg);
1371: break;
1372: case 'D': /* DNS Server */
1373: SAFECOPY(mail_startup.dns_server,arg);
1374: break;
1375: case 'A':
1376: mail_startup.options|=MAIL_OPT_ALLOW_RELAY;
1377: break;
1378: default:
1379: show_usage(argv[0]);
1380: return(1);
1381: }
1382: break;
1383: case 'S': /* Services */
1384: switch(toupper(*(arg++))) {
1385: case '-':
1386: run_services=FALSE;
1387: break;
1388: case 'O': /* Set options */
1389: services_startup.options=strtoul(arg,NULL,0);
1390: break;
1391: default:
1392: show_usage(argv[0]);
1393: return(1);
1394: }
1395: break;
1396: case 'W': /* Web server */
1397: switch(toupper(*(arg++))) {
1398: case '-':
1399: run_web=FALSE;
1400: break;
1401: case 'P':
1402: web_startup.port=atoi(arg);
1403: break;
1404: case 'O': /* Set options */
1405: web_startup.options=strtoul(arg,NULL,0);
1406: break;
1407: default:
1408: show_usage(argv[0]);
1409: return(1);
1410: }
1411: break;
1412: break;
1413: case 'G': /* GET */
1414: switch(toupper(*(arg++))) {
1415: case 'I': /* Identity */
1416: bbs_startup.options|=BBS_OPT_GET_IDENT;
1417: ftp_startup.options|=BBS_OPT_GET_IDENT;
1418: mail_startup.options|=BBS_OPT_GET_IDENT;
1419: services_startup.options|=BBS_OPT_GET_IDENT;
1420: web_startup.options|=BBS_OPT_GET_IDENT;
1421: break;
1422: default:
1423: show_usage(argv[0]);
1424: return(1);
1425: }
1426: break;
1427: case 'H': /* Host */
1428: switch(toupper(*(arg++))) {
1429: case 'N': /* Name */
1430: if(*arg) {
1431: SAFECOPY(bbs_startup.host_name,arg);
1432: SAFECOPY(ftp_startup.host_name,arg);
1433: SAFECOPY(mail_startup.host_name,arg);
1434: SAFECOPY(services_startup.host_name,arg);
1435: SAFECOPY(web_startup.host_name,arg);
1436: } else {
1437: SAFECOPY(bbs_startup.host_name,host_name);
1438: SAFECOPY(ftp_startup.host_name,host_name);
1439: SAFECOPY(mail_startup.host_name,host_name);
1440: SAFECOPY(services_startup.host_name,host_name);
1441: SAFECOPY(web_startup.host_name,host_name);
1442: }
1443: printf("Setting hostname: %s\n",bbs_startup.host_name);
1444: break;
1445: default:
1446: show_usage(argv[0]);
1447: return(1);
1448: }
1449: break;
1450: case 'U': /* runtime UID */
1451: switch(toupper(*(arg++))) {
1452: case 'N': /* username */
1453: #ifdef __unix__
1454: if(strlen(arg) > 1)
1455: {
1456: SAFECOPY(new_uid_name,arg);
1457: }
1458: #endif
1459: break;
1460: case 'G': /* groupname */
1461: #ifdef __unix__
1462: if(strlen(arg) > 1)
1463: {
1464: SAFECOPY(new_gid_name,arg);
1465: }
1466: #endif
1467: break;
1468: default:
1469: show_usage(argv[0]);
1470: return(1);
1471: }
1472: break;
1473: case 'N': /* No */
1474: switch(toupper(*(arg++))) {
1475: case 'F': /* FTP Server */
1476: run_ftp=FALSE;
1477: break;
1478: case 'M': /* Mail Server */
1479: run_mail=FALSE;
1480: break;
1481: case 'S': /* Services */
1482: run_services=FALSE;
1483: break;
1484: case 'T': /* Telnet */
1485: run_bbs=FALSE;
1486: break;
1487: case 'E': /* No Events */
1488: bbs_startup.options |=BBS_OPT_NO_EVENTS;
1489: break;
1490: case 'Q': /* No QWK events */
1491: bbs_startup.options |=BBS_OPT_NO_QWK_EVENTS;
1492: break;
1493: case 'H': /* Hostname lookup */
1494: bbs_startup.options |=BBS_OPT_NO_HOST_LOOKUP;
1495: ftp_startup.options |=BBS_OPT_NO_HOST_LOOKUP;
1496: mail_startup.options |=BBS_OPT_NO_HOST_LOOKUP;
1497: services_startup.options|=BBS_OPT_NO_HOST_LOOKUP;
1498: break;
1499: case 'J': /* JavaScript */
1500: bbs_startup.options |=BBS_OPT_NO_JAVASCRIPT;
1501: ftp_startup.options |=BBS_OPT_NO_JAVASCRIPT;
1502: mail_startup.options |=BBS_OPT_NO_JAVASCRIPT;
1503: services_startup.options|=BBS_OPT_NO_JAVASCRIPT;
1504: break;
1505: case 'I': /* no .ini file */
1506: break;
1507: case 'D':
1508: #if defined(__unix__)
1509: is_daemon=FALSE;
1510: #endif
1511: break;
1512: case 'W': /* no web server */
1513: run_web=FALSE;
1514: break;
1515: default:
1516: show_usage(argv[0]);
1517: return(1);
1518: }
1519: break;
1520: case 'L': /* Local */
1521: switch(toupper(*(arg++))) {
1522: case 'T': /* timezone */
1523: bbs_startup.options |=BBS_OPT_LOCAL_TIMEZONE;
1524: ftp_startup.options |=BBS_OPT_LOCAL_TIMEZONE;
1525: mail_startup.options |=BBS_OPT_LOCAL_TIMEZONE;
1526: services_startup.options|=BBS_OPT_LOCAL_TIMEZONE;
1527: break;
1528: default:
1529: show_usage(argv[0]);
1530: return(1);
1531: }
1532: break;
1533:
1534: default:
1535: show_usage(argv[0]);
1536: return(1);
1537: }
1538: }
1539:
1540: /* Read in configuration files */
1541: memset(&scfg,0,sizeof(scfg));
1542: SAFECOPY(scfg.ctrl_dir,bbs_startup.ctrl_dir);
1543:
1544: if(chdir(scfg.ctrl_dir)!=0)
1545: lprintf(LOG_ERR,"!ERROR %d changing directory to: %s", errno, scfg.ctrl_dir);
1546:
1547: scfg.size=sizeof(scfg);
1548: SAFECOPY(error,UNKNOWN_LOAD_ERROR);
1549: lprintf(LOG_INFO,"Loading configuration files from %s", scfg.ctrl_dir);
1550: if(!load_cfg(&scfg, NULL /* text.dat */, TRUE /* prep */, error)) {
1551: lprintf(LOG_ERR,"!ERROR Loading Configuration Files: %s", error);
1552: return(-1);
1553: }
1554:
1555: /* Daemonize / Set uid/gid */
1556: #ifdef __unix__
1557:
1558: switch(toupper(log_facility[0])) {
1559: case '0':
1560: openlog(log_ident,LOG_CONS,LOG_LOCAL0);
1561: break;
1562: case '1':
1563: openlog(log_ident,LOG_CONS,LOG_LOCAL1);
1564: break;
1565: case '2':
1566: openlog(log_ident,LOG_CONS,LOG_LOCAL2);
1567: break;
1568: case '3':
1569: openlog(log_ident,LOG_CONS,LOG_LOCAL3);
1570: break;
1571: case '4':
1572: openlog(log_ident,LOG_CONS,LOG_LOCAL4);
1573: break;
1574: case '5':
1575: openlog(log_ident,LOG_CONS,LOG_LOCAL5);
1576: break;
1577: case '6':
1578: openlog(log_ident,LOG_CONS,LOG_LOCAL6);
1579: break;
1580: case '7':
1581: openlog(log_ident,LOG_CONS,LOG_LOCAL7);
1582: break;
1583: case 'F': /* this is legacy */
1584: case 'S':
1585: /* Use standard facilities */
1586: openlog(log_ident,LOG_CONS,LOG_USER);
1587: std_facilities = TRUE;
1588: break;
1589: default:
1590: openlog(log_ident,LOG_CONS,LOG_USER);
1591: }
1592: if(is_daemon) {
1593:
1594: lprintf(LOG_INFO,"Running as daemon");
1595: if(daemon(TRUE,FALSE)) { /* Daemonize, DON'T switch to / and DO close descriptors */
1596: lprintf(LOG_ERR,"!ERROR %d running as daemon",errno);
1597: is_daemon=FALSE;
1598: }
1599:
1600: /* Open here to use startup permissions to create the file */
1601: pidf=fopen(pid_fname,"w");
1602: }
1603: old_uid = getuid();
1604: if((pw_entry=getpwnam(new_uid_name))!=0)
1605: {
1606: new_uid=pw_entry->pw_uid;
1607: new_gid=pw_entry->pw_gid;
1608: }
1609: else {
1610: new_uid=getuid();
1611: new_gid=getgid();
1612: }
1613: old_gid = getgid();
1614: if((gr_entry=getgrnam(new_gid_name))!=0)
1615: new_gid=gr_entry->gr_gid;
1616:
1617: do_seteuid(TRUE);
1618: #endif
1619:
1620: #ifdef _THREAD_SUID_BROKEN
1621: /* check if we're using NPTL */
1622: /* Old (2.2) systems don't have this. */
1623: #ifdef _CS_GNU_LIBPTHREAD_VERSION
1624: conflen=confstr (_CS_GNU_LIBPTHREAD_VERSION, NULL, 0);
1625: if (conflen > 0) {
1626: char *buf = alloca (conflen);
1627: confstr (_CS_GNU_LIBPTHREAD_VERSION, buf, conflen);
1628: if (strstr (buf, "NPTL"))
1629: thread_suid_broken=FALSE;
1630: }
1631: #endif
1632: #endif
1633:
1634: /* Install Ctrl-C/Break signal handler here */
1635: #if defined(_WIN32)
1636: SetConsoleCtrlHandler(ControlHandler, TRUE /* Add */);
1637: #elif defined(__unix__)
1638: /* Set up blocked signals */
1639: sigemptyset(&sigs);
1640: sigaddset(&sigs,SIGINT);
1641: sigaddset(&sigs,SIGQUIT);
1642: sigaddset(&sigs,SIGABRT);
1643: sigaddset(&sigs,SIGTERM);
1644: sigaddset(&sigs,SIGHUP);
1645: sigaddset(&sigs,SIGALRM);
1646: /* sigaddset(&sigs,SIGPIPE); */
1647: pthread_sigmask(SIG_BLOCK,&sigs,NULL);
1648: signal(SIGPIPE, SIG_IGN); /* Ignore "Broken Pipe" signal (Also used for broken socket etc.) */
1649: signal(SIGALRM, SIG_IGN); /* Ignore "Alarm" signal */
1650: _beginthread((void(*)(void*))handle_sigs,0,NULL);
1651: if(new_uid_name[0]!=0) { /* check the user arg, if we have uid 0 */
1652: /* Can't recycle servers (re-bind ports) as non-root user */
1653: /* If DONT_BLAME_SYNCHRONET is set, keeps root credentials laying around */
1654: #if !defined(DONT_BLAME_SYNCHRONET)
1655: if(!thread_suid_broken) {
1656: if(bbs_startup.telnet_port < IPPORT_RESERVED
1657: || (bbs_startup.options & BBS_OPT_ALLOW_RLOGIN
1658: && bbs_startup.rlogin_port < IPPORT_RESERVED)
1659: #ifdef USE_CRYPTLIB
1660: || (bbs_startup.options & BBS_OPT_ALLOW_SSH
1661: && bbs_startup.ssh_port < IPPORT_RESERVED)
1662: #endif
1663: )
1664: bbs_startup.options|=BBS_OPT_NO_RECYCLE;
1665: if(ftp_startup.port < IPPORT_RESERVED)
1666: ftp_startup.options|=FTP_OPT_NO_RECYCLE;
1667: if(web_startup.port < IPPORT_RESERVED)
1668: web_startup.options|=BBS_OPT_NO_RECYCLE;
1669: if((mail_startup.options & MAIL_OPT_ALLOW_POP3
1670: && mail_startup.pop3_port < IPPORT_RESERVED)
1671: || mail_startup.smtp_port < IPPORT_RESERVED)
1672: mail_startup.options|=MAIL_OPT_NO_RECYCLE;
1673: /* Perhaps a BBS_OPT_NO_RECYCLE_LOW option? */
1674: services_startup.options|=BBS_OPT_NO_RECYCLE;
1675: }
1676: #endif
1677: }
1678: #endif
1679:
1680: if(run_bbs)
1681: _beginthread((void(*)(void*))bbs_thread,0,&bbs_startup);
1682: if(run_ftp)
1683: _beginthread((void(*)(void*))ftp_server,0,&ftp_startup);
1684: if(run_mail)
1685: _beginthread((void(*)(void*))mail_server,0,&mail_startup);
1686: #ifdef NO_SERVICES
1687: run_services=FALSE;
1688: #else
1689: if(run_services)
1690: _beginthread((void(*)(void*))services_thread,0,&services_startup);
1691: #endif
1692: #ifdef NO_WEB_SERVER
1693: run_web=FALSE;
1694: #else
1695: if(run_web)
1696: _beginthread((void(*)(void*))web_server,0,&web_startup);
1697: #endif
1698:
1699: #ifdef __unix__
1700: if(getuid()) { /* are we running as a normal user? */
1701: lprintf(LOG_WARNING
1702: ,"!Started as non-root user. Cannot bind() to ports below %u.", IPPORT_RESERVED);
1703: }
1704:
1705: else if(new_uid_name[0]==0) /* check the user arg, if we have uid 0 */
1706: lputs(LOG_WARNING,"WARNING: No user account specified, running as root.");
1707:
1708: else
1709: {
1710: lputs(LOG_INFO,"Waiting for child threads to bind ports...");
1711: while((run_bbs && !(bbs_running || bbs_stopped))
1712: || (run_ftp && !(ftp_running || ftp_stopped))
1713: || (run_web && !(web_running || web_stopped))
1714: || (run_mail && !(mail_running || mail_stopped))
1715: || (run_services && !(services_running || services_stopped))) {
1716: mswait(1000);
1717: if(run_bbs && !(bbs_running || bbs_stopped))
1718: lputs(LOG_INFO,"Waiting for BBS thread");
1719: if(run_web && !(web_running || web_stopped))
1720: lputs(LOG_INFO,"Waiting for Web thread");
1721: if(run_ftp && !(ftp_running || ftp_stopped))
1722: lputs(LOG_INFO,"Waiting for FTP thread");
1723: if(run_mail && !(mail_running || mail_stopped))
1724: lputs(LOG_INFO,"Waiting for Mail thread");
1725: if(run_services && !(services_running || services_stopped))
1726: lputs(LOG_INFO,"Waiting for Services thread");
1727: }
1728:
1729: if(!do_setuid(FALSE))
1730: /* actually try to change the uid of this process */
1731: lputs(LOG_ERR,"!Setting new user_id failed! (Does the user exist?)");
1732:
1733: else {
1734: char str[256];
1735: struct passwd *pwent;
1736:
1737: pwent=getpwnam(new_uid_name);
1738: if(pwent != NULL) {
1739: char uenv[128];
1740: char henv[MAX_PATH+6];
1741: sprintf(uenv,"USER=%s",pwent->pw_name);
1742: putenv(uenv);
1743: sprintf(henv,"HOME=%s",pwent->pw_dir);
1744: putenv(henv);
1745: }
1746: if(new_gid_name[0]) {
1747: char genv[128];
1748: sprintf(genv,"GROUP=%s",new_gid_name);
1749: putenv(genv);
1750: }
1751: lprintf(LOG_INFO,"Successfully changed user_id to %s", new_uid_name);
1752: }
1753: }
1754:
1755: if(!isatty(fileno(stdin))) /* redirected */
1756: while(1)
1757: select(0,NULL,NULL,NULL,NULL); /* Sleep forever - Should this just exit the thread? */
1758: else /* interactive */
1759: #endif
1760: {
1761: prompt = "[Threads: %d Sockets: %d Clients: %d Served: %lu] (?=Help): ";
1762: lputs(LOG_INFO,NULL); /* display prompt */
1763:
1764: while(!terminated) {
1765: #ifdef __unix__
1766: if(!isatty(STDIN_FILENO)) { /* Controlling terminal has left us *sniff* */
1767: int fd;
1768: openlog(log_ident,LOG_CONS,LOG_USER);
1769: if ((fd = open(_PATH_DEVNULL, O_RDWR, 0)) != -1) {
1770: (void)dup2(fd, STDIN_FILENO);
1771: (void)dup2(fd, STDOUT_FILENO);
1772: (void)dup2(fd, STDERR_FILENO);
1773: if (fd > 2)
1774: (void)close(fd);
1775: }
1776: is_daemon=TRUE;
1777: lputs(LOG_WARNING, "STDIN is not a tty anymore... switching to syslog logging");
1778: select(0,NULL,NULL,NULL,NULL); /* Sleep forever - Should this just exit the thread? */
1779: }
1780: #endif
1781:
1782: if(!kbhit()) {
1783: YIELD();
1784: continue;
1785: }
1786: ch=getch();
1787: printf("%c\n",ch);
1788: switch(ch) {
1789: case 'q':
1790: terminated=TRUE;
1791: break;
1792: case 'w': /* who's online */
1793: printf("\nNodes in use:\n");
1794: case 'n': /* nodelist */
1795: printf("\n");
1796: for(i=1;i<=scfg.sys_nodes;i++) {
1797: getnodedat(&scfg,i,&node,NULL /* file */);
1798: if(ch=='w' && node.status!=NODE_INUSE && node.status!=NODE_QUIET)
1799: continue;
1800: printnodedat(&scfg, i,&node);
1801: }
1802: break;
1803: case 'l': /* lock node */
1804: case 'd': /* down node */
1805: case 'i': /* interrupt node */
1806: printf("\nNode number: ");
1807: if((n=atoi(fgets(str,sizeof(str),stdin)))<1)
1808: break;
1809: fflush(stdin);
1810: printf("\n");
1811: if((i=getnodedat(&scfg,n,&node,&file))!=0) {
1812: printf("!Error %d getting node %d data\n",i,n);
1813: break;
1814: }
1815: switch(ch) {
1816: case 'l':
1817: node.misc^=NODE_LOCK;
1818: break;
1819: case 'd':
1820: node.misc^=NODE_DOWN;
1821: break;
1822: case 'i':
1823: node.misc^=NODE_INTR;
1824: break;
1825: }
1826: putnodedat(&scfg,n,&node,file);
1827: printnodedat(&scfg,n,&node);
1828: break;
1829: case 'r': /* recycle */
1830: case 's': /* shutdown */
1831: case 't': /* terminate */
1832: printf("BBS, FTP, Web, Mail, Services, or [All] ? ");
1833: switch(toupper(getch())) {
1834: case 'B':
1835: printf("BBS\n");
1836: if(ch=='t')
1837: bbs_terminate();
1838: else if(ch=='s')
1839: bbs_startup.shutdown_now=TRUE;
1840: else
1841: bbs_startup.recycle_now=TRUE;
1842: break;
1843: case 'F':
1844: printf("FTP\n");
1845: if(ch=='t')
1846: ftp_terminate();
1847: else if(ch=='s')
1848: ftp_startup.shutdown_now=TRUE;
1849: else
1850: ftp_startup.recycle_now=TRUE;
1851: break;
1852: case 'W':
1853: printf("Web\n");
1854: if(ch=='t')
1855: web_terminate();
1856: else if(ch=='s')
1857: web_startup.shutdown_now=TRUE;
1858: else
1859: web_startup.recycle_now=TRUE;
1860: break;
1861: case 'M':
1862: printf("Mail\n");
1863: if(ch=='t')
1864: mail_terminate();
1865: else if(ch=='s')
1866: mail_startup.shutdown_now=TRUE;
1867: else
1868: mail_startup.recycle_now=TRUE;
1869: break;
1870: case 'S':
1871: printf("Services\n");
1872: if(ch=='t')
1873: services_terminate();
1874: else if(ch=='s')
1875: services_startup.shutdown_now=TRUE;
1876: else
1877: services_startup.recycle_now=TRUE;
1878: break;
1879: default:
1880: printf("All\n");
1881: if(ch=='t')
1882: terminate();
1883: else if(ch=='s') {
1884: bbs_startup.shutdown_now=TRUE;
1885: ftp_startup.shutdown_now=TRUE;
1886: web_startup.shutdown_now=TRUE;
1887: mail_startup.shutdown_now=TRUE;
1888: services_startup.shutdown_now=TRUE;
1889: }
1890: else {
1891: bbs_startup.recycle_now=TRUE;
1892: ftp_startup.recycle_now=TRUE;
1893: web_startup.recycle_now=TRUE;
1894: mail_startup.recycle_now=TRUE;
1895: services_startup.recycle_now=TRUE;
1896: }
1897: break;
1898: }
1899: break;
1900: case '!': /* execute */
1901: printf("Command line: ");
1902: fgets(str,sizeof(str),stdin);
1903: system(str);
1904: break;
1905: default:
1906: printf("\nSynchronet Console Version %s%c Help\n\n",VERSION,REVISION);
1907: printf("q = quit\n");
1908: printf("n = node list\n");
1909: printf("w = who's online\n");
1910: printf("l = lock node (toggle)\n");
1911: printf("d = down node (toggle)\n");
1912: printf("i = interrupt node (toggle)\n");
1913: printf("r = recycle servers (when not in use)\n");
1914: printf("s = shutdown servers (when not in use)\n");
1915: printf("t = terminate servers (immediately)\n");
1916: printf("! = execute external command\n");
1917: #if 0 /* to do */
1918: printf("c# = chat with node #\n");
1919: printf("s# = spy on node #\n");
1920: #endif
1921: break;
1922: }
1923: lputs(LOG_INFO,""); /* redisplay prompt */
1924: }
1925: }
1926:
1927: terminate();
1928:
1929: /* erase the prompt */
1930: printf("\r%*s\r",prompt_len,"");
1931:
1932: return(0);
1933: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.