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