home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 35 Internet / 35-Internet.zip / ircd4652.zip / ircd-df-4.6.5-os2 / src / ircd.c < prev    next >
Text File  |  1998-06-08  |  28KB  |  1,093 lines

  1. /************************************************************************
  2.  *   IRC - Internet Relay Chat, ircd/ircd.c
  3.  *   Copyright (C) 1990 Jarkko Oikarinen and
  4.  *                      University of Oulu, Computing Center
  5.  *
  6.  *   This program is free software; you can redistribute it and/or modify
  7.  *   it under the terms of the GNU General Public License as published by
  8.  *   the Free Software Foundation; either version 1, or (at your option)
  9.  *   any later version.
  10.  *
  11.  *   This program is distributed in the hope that it will be useful,
  12.  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.  *   GNU General Public License for more details.
  15.  *
  16.  *   You should have received a copy of the GNU General Public License
  17.  *   along with this program; if not, write to the Free Software
  18.  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  19.  */
  20.  
  21. #ifndef lint
  22. static    char sccsid[] = "@(#)ircd.c    2.48 3/9/94 (C) 1988 University of Oulu, \
  23. Computing Center and Jarkko Oikarinen";
  24. #endif
  25.  
  26. #include "struct.h"
  27. #include "common.h"
  28. #include "sys.h"
  29. #include "numeric.h"
  30. #include "userload.h"
  31. #include <sys/stat.h>
  32. #include <signal.h>
  33. #include <fcntl.h>
  34. #include <sys/types.h>
  35. #ifndef _WIN32
  36. #include <sys/file.h>
  37. #include <pwd.h>
  38. #include <sys/time.h>
  39. #else
  40. #include <io.h>
  41. #include <direct.h>
  42. #endif
  43. #ifdef HPUX
  44. #define _KERNEL            /* HPUX has the world's worst headers... */
  45. #endif
  46. #ifndef _WIN32
  47. #include <sys/resource.h>
  48. #endif
  49. #ifdef HPUX
  50. #undef _KERNEL
  51. #endif
  52. #include <errno.h>
  53. #include "h.h"
  54.  
  55. #ifdef __FreeBSD__
  56. char *malloc_options="h" MALLOC_FLAGS_EXTRA;
  57. #endif
  58.  
  59. #ifdef SHOWCONNECTINFO
  60. int    R_do_dns, R_fin_dns, R_fin_dnsc, R_fail_dns,
  61.         R_do_id, R_fin_id, R_fail_id;
  62. char    REPORT_DO_DNS[128], REPORT_FIN_DNS[128], REPORT_FIN_DNSC[128],
  63.     REPORT_FAIL_DNS[128], REPORT_DO_ID[128], REPORT_FIN_ID[128],
  64.     REPORT_FAIL_ID[128];
  65. #endif
  66.  
  67. aClient me;            /* That's me */
  68. aClient *client = &me;        /* Pointer to beginning of Client list */
  69.  
  70. void    server_reboot(char *);
  71. void    restart PROTO((char *));
  72. static    void    open_debugfile(), setup_signals();
  73. void    check_lusers(void);
  74.  
  75. char    **myargv;
  76. int    portnum = -1;            /* Server port number, listening this */
  77. char    *configfile = CONFIGFILE;    /* Server configuration file */
  78. int    debuglevel = -1;        /* Server debug level */
  79. int    bootopt = 0;            /* Server boot option flags */
  80. char    *debugmode = "";        /*  -"-    -"-   -"-  */
  81. char    *sbrk0;                /* initial sbrk(0) */
  82. static    int    dorehash = 0;
  83. static    char    *dpath = DPATH;
  84.  
  85. time_t    nextconnect = 1;    /* time for next try_connections call */
  86. time_t    nextping = 1;        /* same as above for check_pings() */
  87. time_t    nextdnscheck = 0;    /* next time to poll dns to force timeouts */
  88. time_t    nextexpire = 1;    /* next expire run on the dns cache */
  89. time_t    lastlucheck = 0;
  90. int    lu_noninv, lu_inv, lu_serv, lu_oper, lu_unknown, lu_channel,
  91.     lu_lu, lu_lulocal, lu_lserv, lu_clu, lu_mlu, lu_cglobalu, lu_mglobalu;
  92.  
  93. #ifdef CLONE_CHECK
  94.         aClone *Clones = NULL;
  95.         char clonekillhost[100];
  96. #endif
  97.  
  98. time_t    NOW;
  99. #if    defined(PROFIL) && !defined(_WIN32)
  100. extern    etext();
  101.  
  102. VOIDSIG    s_monitor()
  103. {
  104.     static    int    mon = 0;
  105. #ifdef    POSIX_SIGNALS
  106.     struct    sigaction act;
  107. #endif
  108.  
  109.     (void)moncontrol(mon);
  110.     mon = 1 - mon;
  111. #ifdef    POSIX_SIGNALS
  112.     act.sa_handler = s_rehash;
  113.     act.sa_flags = 0;
  114.     (void)sigemptyset(&act.sa_mask);
  115.     (void)sigaddset(&act.sa_mask, SIGUSR1);
  116.     (void)sigaction(SIGUSR1, &act, NULL);
  117. #else
  118.     (void)signal(SIGUSR1, s_monitor);
  119. #endif
  120. }
  121. #endif
  122.  
  123. VOIDSIG s_die()
  124. {
  125. #ifdef    USE_SYSLOG
  126.     (void)syslog(LOG_CRIT, "Server Killed By SIGTERM");
  127. #endif
  128.     flush_connections(me.fd);
  129.     exit(-1);
  130. }
  131.  
  132. #ifndef _WIN32
  133. static VOIDSIG s_rehash()
  134. #else
  135. VOIDSIG s_rehash()
  136. #endif
  137. {
  138. #ifdef    POSIX_SIGNALS
  139.     struct    sigaction act;
  140. #endif
  141.     dorehash = 1;
  142. #ifdef    POSIX_SIGNALS
  143.     act.sa_handler = s_rehash;
  144.     act.sa_flags = 0;
  145.     (void)sigemptyset(&act.sa_mask);
  146.     (void)sigaddset(&act.sa_mask, SIGHUP);
  147.     (void)sigaction(SIGHUP, &act, NULL);
  148. #else
  149. # ifndef _WIN32
  150.     (void)signal(SIGHUP, s_rehash);    /* sysV -argv */
  151. # endif
  152. #endif
  153. }
  154.  
  155. void    restart(mesg)
  156. char    *mesg;
  157. {
  158. #ifdef    USE_SYSLOG
  159.     (void)syslog(LOG_WARNING, "Restarting Server because: %s",mesg);
  160. #endif
  161.     server_reboot(mesg);
  162. }
  163.  
  164. VOIDSIG s_restart()
  165. {
  166.     static int restarting = 0;
  167.  
  168. #ifdef    USE_SYSLOG
  169.     (void)syslog(LOG_WARNING, "Server Restarting on SIGINT");
  170. #endif
  171.     if (restarting == 0)
  172.         {
  173.         /* Send (or attempt to) a dying scream to oper if present */
  174.  
  175.         restarting = 1;
  176.         server_reboot("SIGINT");
  177.         }
  178. }
  179.  
  180. void    server_reboot(mesg)
  181. char    *mesg;
  182. {
  183.     Reg1    int    i;
  184.  
  185.     sendto_ops("Aieeeee!!!  Restarting server... %s", mesg);
  186.     Debug((DEBUG_NOTICE,"Restarting server... %s", mesg));
  187.     flush_connections(me.fd);
  188.     /*
  189.     ** fd 0 must be 'preserved' if either the -d or -i options have
  190.     ** been passed to us before restarting.
  191.     */
  192. #ifdef USE_SYSLOG
  193.     (void)closelog();
  194. #endif
  195. #ifndef _WIN32
  196.     for (i = 3; i < MAXCONNECTIONS; i++)
  197.         (void)close(i);
  198.     if (!(bootopt & (BOOT_TTY|BOOT_DEBUG)))
  199.         (void)close(2);
  200.     (void)close(1);
  201.     if ((bootopt & BOOT_CONSOLE) || isatty(0))
  202.         (void)close(0);
  203.     if (!(bootopt & (BOOT_INETD|BOOT_OPER)))
  204.         (void)execv(MYNAME, myargv);
  205. #else
  206.     for (i = 0; i < highest_fd; i++)
  207.         if ( closesocket(i) == -1 ) close(i);
  208.  
  209.     (void)execv(myargv[0], myargv);
  210. #endif
  211. #ifdef USE_SYSLOG
  212.     /* Have to reopen since it has been closed above */
  213.  
  214.     openlog(myargv[0], LOG_PID|LOG_NDELAY, LOG_FACILITY);
  215.     syslog(LOG_CRIT, "execv(%s,%s) failed: %m\n", MYNAME, myargv[0]);
  216.     closelog();
  217. #endif
  218. #ifndef _WIN32
  219.     Debug((DEBUG_FATAL,"Couldn't restart server: %s", strerror(errno)));
  220. #else
  221.     Debug((DEBUG_FATAL,"Couldn't restart server: %s", strerror(GetLastError())));
  222. #endif
  223.     exit(-1);
  224. }
  225.  
  226.  
  227. /*
  228. ** try_connections
  229. **
  230. **    Scan through configuration and try new connections.
  231. **    Returns the calendar time when the next call to this
  232. **    function should be made latest. (No harm done if this
  233. **    is called earlier or later...)
  234. */
  235. static    time_t    try_connections(currenttime)
  236. time_t    currenttime;
  237. {
  238.     Reg1    aConfItem *aconf;
  239.     Reg2    aClient *cptr;
  240.     aConfItem **pconf;
  241.     int    connecting, confrq;
  242.     time_t    next = 0;
  243.     aClass    *cltmp;
  244.     aConfItem *cconf, *con_conf;
  245.     int    con_class = 0;
  246.  
  247.     connecting = FALSE;
  248.     Debug((DEBUG_NOTICE,"Connection check at   : %s",
  249.         myctime(currenttime)));
  250.     for (aconf = conf; aconf; aconf = aconf->next )
  251.         {
  252.         /* Also when already connecting! (update holdtimes) --SRB */
  253.         if (!(aconf->status & CONF_CONNECT_SERVER) || aconf->port <= 0)
  254.             continue;
  255.         cltmp = Class(aconf);
  256.         /*
  257.         ** Skip this entry if the use of it is still on hold until
  258.         ** future. Otherwise handle this entry (and set it on hold
  259.         ** until next time). Will reset only hold times, if already
  260.         ** made one successfull connection... [this algorithm is
  261.         ** a bit fuzzy... -- msa >;) ]
  262.         */
  263.  
  264.         if ((aconf->hold > currenttime))
  265.             {
  266.             if ((next > aconf->hold) || (next == 0))
  267.                 next = aconf->hold;
  268.             continue;
  269.             }
  270.  
  271.         confrq = get_con_freq(cltmp);
  272.         aconf->hold = currenttime + confrq;
  273.         /*
  274.         ** Found a CONNECT config with port specified, scan clients
  275.         ** and see if this server is already connected?
  276.         */
  277.         cptr = find_name(aconf->name, (aClient *)NULL);
  278.  
  279.         if (!cptr && (Links(cltmp) < MaxLinks(cltmp)) &&
  280.             (!connecting || (Class(cltmp) > con_class)))
  281.           {
  282.             /* Check connect rules to see if we're allowed to try */
  283.             for (cconf = conf; cconf; cconf = cconf->next)
  284.               if ((cconf->status & CONF_CRULE) &&
  285.               (match(cconf->host, aconf->name) == 0))
  286.             if (crule_eval (cconf->passwd))
  287.               break;
  288.             if (!cconf)
  289.               {
  290.             con_class = Class(cltmp);
  291.             con_conf = aconf;
  292.             /* We connect only one at time... */
  293.             connecting = TRUE;
  294.               }
  295.           }
  296.         if ((next > aconf->hold) || (next == 0))
  297.             next = aconf->hold;
  298.         }
  299.     if (connecting)
  300.         {
  301.         if (con_conf->next)  /* are we already last? */
  302.             {
  303.             for (pconf = &conf; (aconf = *pconf);
  304.                  pconf = &(aconf->next))
  305.                 /* put the current one at the end and
  306.                  * make sure we try all connections
  307.                  */
  308.                 if (aconf == con_conf)
  309.                     *pconf = aconf->next;
  310.             (*pconf = con_conf)->next = 0;
  311.             }
  312.         if (connect_server(con_conf, (aClient *)NULL,
  313.                    (struct hostent *)NULL) == 0)
  314.             sendto_ops("Connection to %s[%s] activated.",
  315.                    con_conf->name, con_conf->host);
  316.         }
  317.     Debug((DEBUG_NOTICE,"Next connection check : %s", myctime(next)));
  318.     return (next);
  319. }
  320.  
  321. /* Now find_kill is only called when a kline-related command is used:
  322.    AKILL/RAKILL/KLINE/UNKLINE/REHASH.  Very significant CPU usage decrease.
  323.    I made changes to evm_lusers
  324. ery check_pings call to add new parameter.
  325.    -- Barubary */
  326. extern    time_t    check_pings(time_t currenttime, int check_kills)
  327. {        
  328.     Reg1    aClient    *cptr;
  329.     Reg2    int    killflag;
  330.     int    ping = 0, i, rflag = 0;
  331.     time_t    oldest = 0, timeout;
  332.  
  333. #ifdef TIMED_KLINES
  334.     check_kills = 1;
  335. #endif
  336.     for (i = 0; i <= highest_fd; i++)
  337.         {
  338.         if (!(cptr = local[i]) || IsMe(cptr) || IsLog(cptr))
  339.             continue;
  340.  
  341.         /*
  342.         ** Note: No need to notify opers here. It's
  343.         ** already done when "FLAGS_DEADSOCKET" is set.
  344.         */
  345.         if (cptr->flags & FLAGS_DEADSOCKET)
  346.             {
  347.             (void)exit_client(cptr, cptr, &me, "Dead socket");
  348.             continue;
  349.             }
  350.  
  351.         if (check_kills)
  352.             killflag = IsPerson(cptr) ? find_kill(cptr) : 0;
  353.         else
  354.             killflag = 0;
  355.         if (check_kills && !killflag && IsPerson(cptr))
  356.             if (find_zap(cptr, 1))
  357.                 killflag = 1;
  358. #ifdef R_LINES_OFTEN
  359.         rflag = IsPerson(cptr) ? find_restrict(cptr) : 0;
  360. #endif
  361.         ping = IsRegistered(cptr) ? get_client_ping(cptr) :
  362.                         CONNECTTIMEOUT;
  363.         Debug((DEBUG_DEBUG, "c(%s)=%d p %d k %d r %d a %d",
  364.             cptr->name, cptr->status, ping, killflag, rflag,
  365.             currenttime - cptr->lasttime));
  366.         /*
  367.          * Ok, so goto's are ugly and can be avoided here but this code
  368.          * is already indented enough so I think its justified. -avalon
  369.          */
  370.         if (!killflag && !rflag && IsRegistered(cptr) &&
  371.             (ping >= currenttime - cptr->lasttime))
  372.             goto ping_timeout;
  373.         /*
  374.          * If the server hasnt talked to us in 2*ping seconds
  375.          * and it has a ping time, then close its connection.
  376.          * If the client is a user and a KILL line was found
  377.          * to be active, close this connection too.
  378.          */
  379.         if (killflag || rflag ||
  380.             ((currenttime - cptr->lasttime) >= (2 * ping) &&
  381.              (cptr->flags & FLAGS_PINGSENT)) ||
  382.             (!IsRegistered(cptr) &&
  383.              (currenttime - cptr->firsttime) >= ping))
  384.             {
  385.             if (!IsRegistered(cptr) &&
  386.                 (DoingDNS(cptr) || DoingAuth(cptr)))
  387.                 {
  388.                 if (cptr->authfd >= 0)
  389.                     {
  390. #ifndef _WIN32
  391.                     (void)close(cptr->authfd);
  392. #else
  393.                     (void)closesocket(cptr->authfd);
  394. #endif
  395.                     cptr->authfd = -1;
  396.                     cptr->count = 0;
  397.                     *cptr->buffer = '\0';
  398.                     }
  399. #ifdef SHOWCONNECTINFO
  400.                 if (DoingDNS(cptr))
  401.                     write(cptr->fd, REPORT_FAIL_DNS,
  402.                         R_fail_dns);
  403.                 else
  404.                     write(cptr->fd, REPORT_FAIL_ID,
  405.                         R_fail_id);
  406. #endif
  407.                 Debug((DEBUG_NOTICE,
  408.                     "DNS/AUTH timeout %s",
  409.                     get_client_name(cptr,TRUE)));
  410.                 del_queries((char *)cptr);
  411.                 ClearAuth(cptr);
  412.                 ClearDNS(cptr);
  413.                 SetAccess(cptr);
  414.                 cptr->firsttime = currenttime;
  415.                 cptr->lasttime = currenttime;
  416.                 continue;
  417.                 }
  418.             if (IsServer(cptr) || IsConnecting(cptr) ||
  419.                 IsHandshake(cptr)) {
  420.                 sendto_ops("No response from %s, closing link",
  421.                        get_client_name(cptr, FALSE));
  422.                 sendto_serv_butone(&me, ":%s GNOTICE :No response from %s, closing link",
  423.                     me.name, get_client_name(cptr, FALSE));
  424.             }
  425.             /*
  426.              * this is used for KILL lines with time restrictions
  427.              * on them - send a messgae to the user being killed
  428.              * first.
  429.              */
  430.             if (killflag && IsPerson(cptr))
  431.                 sendto_ops("Kill line active for %s",
  432.                        get_client_name(cptr, FALSE));
  433.  
  434. #if defined(R_LINES) && defined(R_LINES_OFTEN)
  435.             if (IsPerson(cptr) && rflag)
  436.                 sendto_ops("Restricting %s, closing link.",
  437.                        get_client_name(cptr,FALSE));
  438. #endif
  439.                          if (killflag)
  440.                                 (void)exit_client(cptr, cptr, &me,
  441.                                   "User has been banned");
  442.                          else
  443.                                 (void)exit_client(cptr, cptr, &me,
  444.                                   "Ping timeout");
  445.             continue;
  446.             }
  447.         else if (IsRegistered(cptr) &&
  448.              (cptr->flags & FLAGS_PINGSENT) == 0)
  449.             {
  450.             /*
  451.              * if we havent PINGed the connection and we havent
  452.              * heard from it in a while, PING it to make sure
  453.              * it is still alive.
  454.              */
  455.             cptr->flags |= FLAGS_PINGSENT;
  456.             /* not nice but does the job */
  457.             cptr->lasttime = currenttime - ping;
  458.             sendto_one(cptr, "PING :%s", me.name);
  459.             }
  460. ping_timeout:
  461.         timeout = cptr->lasttime + ping;
  462.         while (timeout <= currenttime)
  463.             timeout += ping;
  464.         if (timeout < oldest || !oldest)
  465.             oldest = timeout;
  466.         }
  467.     if (!oldest || oldest < currenttime)
  468.         oldest = currenttime + PINGFREQUENCY;
  469.     Debug((DEBUG_NOTICE,"Next check_ping() call at: %s, %d %d %d",
  470.         myctime(oldest), ping, oldest, currenttime));
  471.  
  472.     return (oldest);
  473. }
  474.  
  475. /*
  476. ** bad_command
  477. **    This is called when the commandline is not acceptable.
  478. **    Give error message and exit without starting anything.
  479. */
  480. static    int    bad_command()
  481. {
  482. #ifndef _WIN32
  483.   (void)printf(
  484.      "Usage: ircd %s[-h servername] [-p portnumber] [-x loglevel] [-t]\n",
  485. #ifdef CMDLINE_CONFIG
  486.      "[-f config] "
  487. #else
  488.      ""
  489. #endif
  490.      );
  491.   (void)printf("Server not started\n\n");
  492. #else
  493.   MessageBox(NULL,
  494.          "Usage: wircd [-h servername] [-p portnumber] [-x loglevel]\n",
  495.          "wIRCD", MB_OK);
  496. #endif
  497.   return (-1);
  498. }
  499.  
  500. #ifndef _WIN32
  501. int    main(argc, argv)
  502. #else
  503. int    InitwIRCD(argc, argv)
  504. #endif
  505. int    argc;
  506. char    *argv[];
  507. {
  508. #ifdef _WIN32
  509.     WORD    wVersionRequested = MAKEWORD(1, 1);
  510.     WSADATA wsaData;
  511. #else
  512.     uid_t    uid, euid;
  513.     time_t    delay = 0;
  514. #endif
  515.     int    portarg = 0;
  516. #ifdef  FORCE_CORE
  517.     struct  rlimit corelim;
  518. #endif
  519.  
  520. #ifndef _WIN32
  521.     sbrk0 = (char *)sbrk((size_t)0);
  522.     uid = getuid();
  523.     euid = geteuid();
  524. # ifdef    PROFIL
  525.     (void)monstartup(0, etext);
  526.     (void)moncontrol(1);
  527.     (void)signal(SIGUSR1, s_monitor);
  528. # endif
  529. #endif
  530.  
  531. #ifdef    CHROOTDIR
  532.     if (chdir(dpath))
  533.         {
  534.         perror("chdir");
  535.         exit(-1);
  536.         }
  537.     res_init();
  538.     if (chroot(DPATH))
  539.       {
  540.         (void)fprintf(stderr,"ERROR:  Cannot chdir/chroot\n");
  541.         exit(5);
  542.       }
  543. #endif /*CHROOTDIR*/
  544.  
  545.     myargv = argv;
  546. #ifndef _WIN32
  547.     (void)umask(077);                /* better safe than sorry --SRB */
  548. #else
  549.     WSAStartup(wVersionRequested, &wsaData);
  550. #endif
  551.     bzero((char *)&me, sizeof(me));
  552.  
  553. #ifndef _WIN32
  554.     setup_signals();
  555. #endif
  556.     initload();
  557.  
  558. #ifdef FORCE_CORE
  559.     corelim.rlim_cur = corelim.rlim_max = RLIM_INFINITY;
  560.     if (setrlimit(RLIMIT_CORE, &corelim))
  561.       printf("unlimit core size failed; errno = %d\n", errno);
  562. #endif
  563.  
  564. #ifdef USE_CASETABLES
  565.     /* Set up the case tables */
  566.     setup_match();
  567. #endif
  568.  
  569.     /*
  570.     ** All command line parameters have the syntax "-fstring"
  571.     ** or "-f string" (e.g. the space is optional). String may
  572.     ** be empty. Flag characters cannot be concatenated (like
  573.     ** "-fxyz"), it would conflict with the form "-fstring".
  574.     */
  575.     while (--argc > 0 && (*++argv)[0] == '-')
  576.         {
  577.         char    *p = argv[0]+1;
  578.         int    flag = *p++;
  579.  
  580.         if (flag == '\0' || *p == '\0')
  581.             if (argc > 1 && argv[1][0] != '-')
  582.                 {
  583.                 p = *++argv;
  584.                 argc -= 1;
  585.                 }
  586.             else
  587.                 p = "";
  588.  
  589.         switch (flag)
  590.             {
  591. #if !defined _WIN32 || !defined __EMX__
  592.                     case 'a':
  593.             bootopt |= BOOT_AUTODIE;
  594.             break;
  595.             case 'c':
  596.             bootopt |= BOOT_CONSOLE;
  597.             break;
  598.             case 'q':
  599.             bootopt |= BOOT_QUICK;
  600.             break;
  601.             case 'd' :
  602.                         (void)setuid((uid_t)uid);
  603. #else
  604.             case 'd':
  605. #endif
  606.             dpath = p;
  607.             break;
  608. #if !defined _WIN32 || !defined __EMX__
  609.             case 'o': /* Per user local daemon... */
  610.                         (void)setuid((uid_t)uid);
  611.             bootopt |= BOOT_OPER;
  612.                 break;
  613. #if defined CMDLINE_CONFIG && !defined __EMX__
  614.             case 'f':
  615.                         (void)setuid((uid_t)uid);
  616.             configfile = p;
  617.             break;
  618. #endif
  619.             case 'h':
  620.             strncpyzt(me.name, p, sizeof(me.name));
  621.             break;
  622.             case 'i':
  623.             bootopt |= BOOT_INETD|BOOT_AUTODIE;
  624.                 break;
  625. #endif
  626.             case 'p':
  627.             if ((portarg = atoi(p)) > 0 )
  628.                 portnum = portarg;
  629.             break;
  630. #if !defined _WIN32 || !defined __EMX__
  631.             case 't':
  632.                         (void)setuid((uid_t)uid);
  633.             bootopt |= BOOT_TTY;
  634.             break;
  635.             case 'v':
  636.             (void)printf("ircd %s\n", version);
  637. #else
  638.             case 'v':
  639.             MessageBox(NULL, version, "wIRCD version", MB_OK);
  640. #endif
  641.             exit(0);
  642.             case 'x':
  643. #ifdef    DEBUGMODE
  644. # if !defined _WIN32 || !defined __EMX__
  645.                         (void)setuid((uid_t)uid);
  646. # endif
  647.             debuglevel = atoi(p);
  648.             debugmode = *p ? p : "0";
  649.             bootopt |= BOOT_DEBUG;
  650.             break;
  651. #else
  652. # ifndef _WIN32
  653.             (void)fprintf(stderr,
  654.                 "%s: DEBUGMODE must be defined for -x y\n",
  655.                 myargv[0]);
  656. # else
  657.             MessageBox(NULL,
  658.                 "DEBUGMODE must be defined for -x option",
  659.                 "wIRCD", MB_OK);
  660. # endif
  661.             exit(0);
  662. #endif
  663.             default:
  664.             bad_command();
  665.             break;
  666.             }
  667.         }
  668.  
  669. #ifndef    CHROOT
  670.     if (chdir(dpath))
  671.         {
  672. # ifndef _WIN32
  673.         perror("chdir");
  674. # else
  675.         MessageBox(NULL, strerror(GetLastError()), "wIRCD: chdir()",
  676.             MB_OK);
  677. # endif
  678.         exit(-1);
  679.         }
  680. #endif
  681.  
  682. #if !defined(IRC_UID) && !defined(_WIN32)
  683.     if ((uid != euid) && !euid)
  684.         {
  685.         (void)fprintf(stderr,
  686.             "ERROR: do not run ircd setuid root. Make it setuid a\
  687.  normal user.\n");
  688.         exit(-1);
  689.         }
  690. #endif
  691.  
  692. #if (!defined(CHROOTDIR) || (defined(IRC_UID) && defined(IRC_GID))) \
  693.     && !defined(_WIN32) && !defined __EMX__
  694. # ifndef    AIX
  695.     (void)setuid((uid_t)uid);
  696.     (void)setuid((uid_t)euid);
  697. # endif
  698.  
  699.     if ((int)getuid() == 0)
  700.         {
  701. # if defined(IRC_UID) && defined(IRC_GID) && !defined __EMX__
  702.  
  703.         /* run as a specified user */
  704.         (void)fprintf(stderr,"WARNING: running ircd with uid = %d\n",
  705.             IRC_UID);
  706.         (void)fprintf(stderr,"         changing to gid %d.\n",IRC_GID);
  707.         (void)setuid(IRC_UID);
  708.         (void)setgid(IRC_GID);
  709. #else
  710. #ifndef __EMX__
  711.         /* check for setuid root as usual */
  712.         (void)fprintf(stderr,
  713.             "ERROR: do not run ircd setuid root. Make it setuid a\
  714.  normal user.\n");
  715.         exit(-1);
  716. # endif    
  717. #endif
  718.         } 
  719. #endif /*CHROOTDIR/UID/GID/_WIN32*/
  720.  
  721. #ifndef _WIN32
  722.     /* didn't set debuglevel */
  723.     /* but asked for debugging output to tty */
  724.     if ((debuglevel < 0) &&  (bootopt & BOOT_TTY))
  725.         {
  726.         (void)fprintf(stderr,
  727.             "you specified -t without -x. use -x <n>\n");
  728.         exit(-1);
  729.         }
  730. #endif
  731.  
  732.     if (argc > 0)
  733.         return bad_command(); /* This should exit out */
  734.  
  735.     clear_client_hash_table();
  736.     clear_channel_hash_table();
  737.     clear_notify_hash_table();
  738.     inittoken();
  739.     initlists();
  740.     initclass();
  741.     initwhowas();
  742.     initstats();
  743.     open_debugfile();
  744.     if (portnum < 0)
  745.         portnum = PORTNUM;
  746.     me.port = portnum;
  747.     (void)init_sys();
  748.     me.flags = FLAGS_LISTEN;
  749. #ifndef _WIN32
  750.     if (bootopt & BOOT_INETD)
  751.         {
  752.         me.fd = 0;
  753.         local[0] = &me;
  754.         me.flags = FLAGS_LISTEN;
  755.         }
  756.     else
  757. #endif
  758.         me.fd = -1;
  759.  
  760. #ifdef USE_SYSLOG
  761.     openlog(myargv[0], LOG_PID|LOG_NDELAY, LOG_FACILITY);
  762. #endif
  763.     if (initconf(bootopt) == -1)
  764.         {
  765.         Debug((DEBUG_FATAL, "Failed in reading configuration file %s",
  766.             configfile));
  767. #ifndef _WIN32
  768.         (void)printf("Couldn't open configuration file %s\n",
  769.             configfile);
  770. #else
  771.         MessageBox(NULL, "Couldn't open configuration file "CONFIGFILE,
  772.             "wIRCD", MB_OK);
  773. #endif
  774.         exit(-1);
  775.         }
  776.     if (!(bootopt & BOOT_INETD))
  777.         {
  778.         static    char    star[] = "*";
  779.         aConfItem    *aconf;
  780.  
  781.         if ((aconf = find_me()) && portarg <= 0 && aconf->port > 0)
  782.             portnum = aconf->port;
  783.         Debug((DEBUG_ERROR, "Port = %d", portnum));
  784.         if (inetport(&me, aconf->passwd, portnum))
  785.             exit(1);
  786.         }
  787.     else if (inetport(&me, "*", 0))
  788.         exit(1);
  789.  
  790.     (void)setup_ping();
  791.     (void)get_my_name(&me, me.sockhost, sizeof(me.sockhost)-1);
  792.     if (me.name[0] == '\0')
  793.         strncpyzt(me.name, me.sockhost, sizeof(me.name));
  794.     me.hopcount = 0;
  795.     me.authfd = -1;
  796.     me.confs = NULL;
  797.     me.next = NULL;
  798.     me.user = NULL;
  799.     me.from = &me;
  800.     SetMe(&me);
  801.     make_server(&me);
  802.     (void)strcpy(me.serv->up, me.name);
  803.  
  804.     me.lasttime = me.since = me.firsttime = time(NULL);
  805.     (void)add_to_client_hash_table(me.name, &me);
  806.  
  807. #ifdef SHOWCONNECTINFO
  808.     (void)sprintf(REPORT_DO_DNS, ":%s %s", me.name, BREPORT_DO_DNS);
  809.     (void)sprintf(REPORT_FIN_DNS, ":%s %s", me.name, BREPORT_FIN_DNS);
  810.     (void)sprintf(REPORT_FIN_DNSC, ":%s %s", me.name, BREPORT_FIN_DNSC);
  811.     (void)sprintf(REPORT_FAIL_DNS, ":%s %s", me.name, BREPORT_FAIL_DNS);
  812.     (void)sprintf(REPORT_DO_ID, ":%s %s", me.name, BREPORT_DO_ID);
  813.     (void)sprintf(REPORT_FIN_ID, ":%s %s", me.name, BREPORT_FIN_ID);
  814.     (void)sprintf(REPORT_FAIL_ID, ":%s %s", me.name, BREPORT_FAIL_ID);
  815.  
  816.     R_do_dns = strlen(REPORT_DO_DNS);
  817.     R_fin_dns = strlen(REPORT_FIN_DNS);
  818.     R_fin_dnsc = strlen(REPORT_FIN_DNSC);
  819.     R_fail_dns = strlen(REPORT_FAIL_DNS);
  820.     R_do_id = strlen(REPORT_DO_ID);
  821.     R_fin_id = strlen(REPORT_FIN_ID);
  822.     R_fail_id = strlen(REPORT_FAIL_ID);
  823. #endif
  824.  
  825.     check_class();
  826.     if (bootopt & BOOT_OPER)
  827.         {
  828.         aClient *tmp = add_connection(&me, 0);
  829.  
  830.         if (!tmp)
  831.             exit(1);
  832.         SetMaster(tmp);
  833.         }
  834.     else
  835.         write_pidfile();
  836.  
  837.     Debug((DEBUG_NOTICE,"Server ready..."));
  838. #ifdef USE_SYSLOG
  839.     syslog(LOG_NOTICE, "Server Ready");
  840. #endif
  841.  
  842. #ifdef _WIN32
  843.     return 1;
  844. }
  845.  
  846. void    SocketLoop(void *dummy)
  847. {
  848.     time_t    delay = 0, now;
  849.  
  850.     while (1)
  851. #else
  852.     for (;;)
  853. #endif
  854.         {
  855.         now = time(NULL);
  856.         /*
  857.         ** Run through the hashes and check lusers every
  858.         ** second
  859.         */
  860.         if(lastlucheck < now) {
  861.             check_lusers();
  862.             lastlucheck=now;
  863.         }
  864.         /*
  865.         ** We only want to connect if a connection is due,
  866.         ** not every time through.  Note, if there are no
  867.         ** active C lines, this call to Tryconnections is
  868.         ** made once only; it will return 0. - avalon
  869.         */
  870.         if (nextconnect && now >= nextconnect)
  871.             nextconnect = try_connections(now);
  872.         /*
  873.         ** DNS checks. One to timeout queries, one for cache expiries.
  874.         */
  875.         if (now >= nextdnscheck)
  876.             nextdnscheck = timeout_query_list(now);
  877.         if (now >= nextexpire)
  878.             nextexpire = expire_cache(now);
  879.         /*
  880.         ** take the smaller of the two 'timed' event times as
  881.         ** the time of next event (stops us being late :) - avalon
  882.         ** WARNING - nextconnect can return 0!
  883.         */
  884.         if (nextconnect)
  885.             delay = MIN(nextping, nextconnect);
  886.         else
  887.             delay = nextping;
  888.         delay = MIN(nextdnscheck, delay);
  889.         delay = MIN(nextexpire, delay);
  890.         delay -= now;
  891.         /*
  892.         ** Adjust delay to something reasonable [ad hoc values]
  893.         ** (one might think something more clever here... --msa)
  894.         ** We don't really need to check that often and as long
  895.         ** as we don't delay too long, everything should be ok.
  896.         ** waiting too long can cause things to timeout...
  897.         ** i.e. PINGS -> a disconnection :(
  898.         ** - avalon
  899.         */
  900.         if (delay < 1)
  901.             delay = 1;
  902.         else
  903.             delay = MIN(delay, TIMESEC);
  904.         (void)read_message(delay);
  905.         
  906.         Debug((DEBUG_DEBUG ,"Got message(s)"));
  907.         
  908.         now = time(NULL);
  909.         /*
  910.         ** ...perhaps should not do these loops every time,
  911.         ** but only if there is some chance of something
  912.         ** happening (but, note that conf->hold times may
  913.         ** be changed elsewhere--so precomputed next event
  914.         ** time might be too far away... (similarly with
  915.         ** ping times) --msa
  916.         */
  917.         if (now >= nextping)
  918.             nextping = check_pings(now, 0);
  919.  
  920.         if (dorehash)
  921.             {
  922.             (void)rehash(&me, &me, 1);
  923.             dorehash = 0;
  924.             }
  925.         /*
  926.         ** Flush output buffers on all connections now if they
  927.         ** have data in them (or at least try to flush)
  928.         ** -avalon
  929.         */
  930.         flush_connections(me.fd);
  931.         }
  932.     }
  933.  
  934. /*
  935.  * open_debugfile
  936.  *
  937.  * If the -t option is not given on the command line when the server is
  938.  * started, all debugging output is sent to the file set by LPATH in config.h
  939.  * Here we just open that file and make sure it is opened to fd 2 so that
  940.  * any fprintf's to stderr also goto the logfile.  If the debuglevel is not
  941.  * set from the command line by -x, use /dev/null as the dummy logfile as long
  942.  * as DEBUGMODE has been defined, else dont waste the fd.
  943.  */
  944. static    void    open_debugfile()
  945. {
  946. #ifdef    DEBUGMODE
  947.     int    fd;
  948.     aClient    *cptr;
  949.  
  950.     if (debuglevel >= 0)
  951.         {
  952.         cptr = make_client(NULL, NULL);
  953.         cptr->fd = 2;
  954.         SetLog(cptr);
  955.         cptr->port = debuglevel;
  956.         cptr->flags = 0;
  957.         cptr->acpt = cptr;
  958.         local[2] = cptr;
  959.         (void)strcpy(cptr->sockhost, me.sockhost);
  960. # ifndef _WIN32
  961.         (void)printf("isatty = %d ttyname = %#x\n",
  962.             isatty(2), (u_int)ttyname(2));
  963.         if (!(bootopt & BOOT_TTY)) /* leave debugging output on fd 2 */
  964.             {
  965.             (void)truncate(LOGFILE, 0);
  966.             if ((fd = open(LOGFILE, O_WRONLY | O_CREAT, 0600)) < 0) 
  967.                 if ((fd = open("/dev/null", O_WRONLY)) < 0)
  968.                     exit(-1);
  969.             if (fd != 2)
  970.                 {
  971.                 (void)dup2(fd, 2);
  972.                 (void)close(fd); 
  973.                 }
  974.             strncpyzt(cptr->name, LOGFILE, sizeof(cptr->name));
  975.             }
  976.         else if (isatty(2) && ttyname(2))
  977.             strncpyzt(cptr->name, ttyname(2), sizeof(cptr->name));
  978.         else
  979. # endif
  980.             (void)strcpy(cptr->name, "FD2-Pipe");
  981.         Debug((DEBUG_FATAL, "Debug: File <%s> Level: %d at %s",
  982.             cptr->name, cptr->port, myctime(time(NULL))));
  983.         }
  984.     else
  985.         local[2] = NULL;
  986. #endif
  987.     return;
  988. }
  989.  
  990. #ifndef _WIN32
  991. static    void    setup_signals()
  992. {
  993. #ifdef    POSIX_SIGNALS
  994.     struct    sigaction act;
  995.  
  996.     act.sa_handler = SIG_IGN;
  997.     act.sa_flags = 0;
  998.     (void)sigemptyset(&act.sa_mask);
  999.     (void)sigaddset(&act.sa_mask, SIGPIPE);
  1000.     (void)sigaddset(&act.sa_mask, SIGALRM);
  1001. # ifdef    SIGWINCH
  1002.     (void)sigaddset(&act.sa_mask, SIGWINCH);
  1003.     (void)sigaction(SIGWINCH, &act, NULL);
  1004. # endif
  1005.     (void)sigaction(SIGPIPE, &act, NULL);
  1006.     act.sa_handler = dummy;
  1007.     (void)sigaction(SIGALRM, &act, NULL);
  1008.     act.sa_handler = s_rehash;
  1009.     (void)sigemptyset(&act.sa_mask);
  1010.     (void)sigaddset(&act.sa_mask, SIGHUP);
  1011.     (void)sigaction(SIGHUP, &act, NULL);
  1012.     act.sa_handler = s_restart;
  1013.     (void)sigaddset(&act.sa_mask, SIGINT);
  1014.     (void)sigaction(SIGINT, &act, NULL);
  1015.     act.sa_handler = s_die;
  1016.     (void)sigaddset(&act.sa_mask, SIGTERM);
  1017.     (void)sigaction(SIGTERM, &act, NULL);
  1018.  
  1019. #else
  1020. # ifndef    HAVE_RELIABLE_SIGNALS
  1021.     (void)signal(SIGPIPE, dummy);
  1022. #  ifdef    SIGWINCH
  1023.     (void)signal(SIGWINCH, dummy);
  1024. #  endif
  1025. # else
  1026. #  ifdef    SIGWINCH
  1027.     (void)signal(SIGWINCH, SIG_IGN);
  1028. #  endif
  1029.     (void)signal(SIGPIPE, SIG_IGN);
  1030. # endif
  1031.     (void)signal(SIGALRM, dummy);   
  1032.     (void)signal(SIGHUP, s_rehash);
  1033.     (void)signal(SIGTERM, s_die); 
  1034.     (void)signal(SIGINT, s_restart);
  1035. #endif
  1036.  
  1037. #ifdef RESTARTING_SYSTEMCALLS
  1038.     /*
  1039.     ** At least on Apollo sr10.1 it seems continuing system calls
  1040.     ** after signal is the default. The following 'siginterrupt'
  1041.     ** should change that default to interrupting calls.
  1042.     */
  1043.     (void)siginterrupt(SIGALRM, 1);
  1044. #endif
  1045. }
  1046. #endif /* !_Win32 */
  1047.  
  1048.  
  1049. #define DOMAINNAMEMASK "*" DOMAINNAME
  1050.  
  1051. void check_lusers(void) {
  1052.     aClient *acptr;
  1053.     lu_noninv=lu_inv=lu_serv=lu_oper=lu_unknown=lu_channel=lu_lu=lu_lserv=
  1054.       lu_clu=lu_cglobalu=0;
  1055.     for (acptr = client; acptr; acptr = acptr->next) {
  1056.         switch (acptr->status) {
  1057.          case STAT_SERVER:
  1058.             if (MyConnect(acptr))
  1059.               lu_lserv++;
  1060.          case STAT_ME:
  1061.             lu_serv++;
  1062.             break;
  1063.          case STAT_CLIENT:
  1064.             if (IsOper(acptr))
  1065.               lu_oper++;
  1066.             if (MyConnect(acptr)) {
  1067.                   lu_lu++;
  1068.                 if (match(DOMAINNAMEMASK, acptr->sockhost) == 0)
  1069.                   lu_lulocal++;
  1070.             }
  1071.             if (!IsInvisible(acptr))
  1072.               lu_noninv++;
  1073.             else
  1074.               lu_inv++;
  1075.             break;
  1076.          default:
  1077.             lu_unknown++;
  1078.             break;
  1079.          }
  1080.     }
  1081.     lu_clu=lu_lu;
  1082.     lu_cglobalu=lu_noninv + lu_inv;
  1083.     if (lu_clu > lu_mlu)
  1084.       lu_mlu = lu_lu;
  1085.     lu_cglobalu = lu_noninv + lu_inv;
  1086.     if (lu_cglobalu > lu_mglobalu)
  1087.       lu_mglobalu = lu_cglobalu;
  1088.       
  1089.     lu_channel=count_channels(&me);
  1090. }
  1091.  
  1092.   
  1093.