Annotation of sbbs/src/sbbs3/sbbscon.c, revision 1.1.1.2

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: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.