home *** CD-ROM | disk | FTP | other *** search
/ The Net: Ultimate Internet Guide / WWLCD1.ISO / pc / java / in4wjcxu / other / irc / ircd / s_conf.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-08-14  |  29.2 KB  |  1,244 lines

  1. /************************************************************************
  2.  *   IRC - Internet Relay Chat, ircd/s_conf.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. /* -- avalon -- 20 Feb 1992
  22.  * Reversed the order of the params for attach_conf().
  23.  * detach_conf() and attach_conf() are now the same:
  24.  * function_conf(aClient *, aConfItem *)
  25.  */
  26.  
  27. /* -- Jto -- 20 Jun 1990
  28.  * Added gruner's overnight fix..
  29.  */
  30.  
  31. /* -- Jto -- 16 Jun 1990
  32.  * Moved matches to ../common/match.c
  33.  */
  34.  
  35. /* -- Jto -- 03 Jun 1990
  36.  * Added Kill fixes from gruner@lan.informatik.tu-muenchen.de
  37.  * Added jarlek's msgbase fix (I still don't understand it... -- Jto)
  38.  */
  39.  
  40. /* -- Jto -- 13 May 1990
  41.  * Added fixes from msa:
  42.  * Comments and return value to init_conf()
  43.  */
  44.  
  45. /*
  46.  * -- Jto -- 12 May 1990
  47.  *  Added close() into configuration file (was forgotten...)
  48.  */
  49.  
  50. #ifndef lint
  51. static  char sccsid[] = "@(#)s_conf.c    2.56 02 Apr 1994 (C) 1988 University of Oulu, \
  52. Computing Center and Jarkko Oikarinen";
  53. #endif
  54.  
  55. #include "struct.h"
  56. #include "common.h"
  57. #include "sys.h"
  58. #include "numeric.h"
  59. #include <sys/socket.h>
  60. #include <fcntl.h>
  61. #include <sys/wait.h>
  62. #ifdef __hpux
  63. #include "inet.h"
  64. #endif
  65. #if defined(PCS) || defined(AIX) || defined(DYNIXPTX) || defined(SVR3)
  66. #include <time.h>
  67. #endif
  68. #ifdef    R_LINES
  69. #include <signal.h>
  70. #endif
  71.  
  72. #include "h.h"
  73.  
  74. static    int    check_time_interval PROTO((char *, char *));
  75. static    int    lookup_confhost PROTO((aConfItem *));
  76.  
  77. aConfItem    *conf = NULL;
  78.  
  79. /*
  80.  * remove all conf entries from the client except those which match
  81.  * the status field mask.
  82.  */
  83. void    det_confs_butmask(cptr, mask)
  84. aClient    *cptr;
  85. int    mask;
  86. {
  87.     Reg1 Link *tmp, *tmp2;
  88.  
  89.     for (tmp = cptr->confs; tmp; tmp = tmp2)
  90.         {
  91.         tmp2 = tmp->next;
  92.         if ((tmp->value.aconf->status & mask) == 0)
  93.             (void)detach_conf(cptr, tmp->value.aconf);
  94.         }
  95. }
  96.  
  97. /*
  98.  * find the first (best) I line to attach.
  99.  */
  100. int    attach_Iline(cptr, hp, sockhost)
  101. aClient *cptr;
  102. Reg2    struct    hostent    *hp;
  103. char    *sockhost;
  104. {
  105.     Reg1    aConfItem    *aconf;
  106.     Reg3    char    *hname;
  107.     Reg4    int    i;
  108.     static    char    uhost[HOSTLEN+USERLEN+3];
  109.     static    char    fullname[HOSTLEN+1];
  110.  
  111.     for (aconf = conf; aconf; aconf = aconf->next)
  112.         {
  113.         if (aconf->status != CONF_CLIENT)
  114.             continue;
  115.         if (aconf->port && aconf->port != cptr->acpt->port)
  116.             continue;
  117.         if (!aconf->host || !aconf->name)
  118.             goto attach_iline;
  119.         if (hp)
  120.             for (i = 0, hname = hp->h_name; hname;
  121.                  hname = hp->h_aliases[i++])
  122.                 {
  123.                 (void)strncpy(fullname, hname,
  124.                     sizeof(fullname)-1);
  125.                 add_local_domain(fullname,
  126.                          HOSTLEN - strlen(fullname));
  127.                 Debug((DEBUG_DNS, "a_il: %s->%s",
  128.                       sockhost, fullname));
  129.                 if (index(aconf->name, '@'))
  130.                     {
  131.                     (void)strcpy(uhost, cptr->username);
  132.                     (void)strcat(uhost, "@");
  133.                     }
  134.                 else
  135.                     *uhost = '\0';
  136.                 (void)strncat(uhost, fullname,
  137.                     sizeof(uhost) - strlen(uhost));
  138.                 if (!match(aconf->name, uhost))
  139.                     goto attach_iline;
  140.                 }
  141.  
  142.         if (index(aconf->host, '@'))
  143.             {
  144.             strncpyzt(uhost, cptr->username, sizeof(uhost));
  145.             (void)strcat(uhost, "@");
  146.             }
  147.         else
  148.             *uhost = '\0';
  149.         (void)strncat(uhost, sockhost, sizeof(uhost) - strlen(uhost));
  150.         if (!match(aconf->host, uhost))
  151.             goto attach_iline;
  152.         continue;
  153. attach_iline:
  154.         if (index(uhost, '@'))
  155.             cptr->flags |= FLAGS_DOID;
  156.         get_sockhost(cptr, uhost);
  157.         return attach_conf(cptr, aconf);
  158.         }
  159.     return -1;
  160. }
  161.  
  162. /*
  163.  * Find the single N line and return pointer to it (from list).
  164.  * If more than one then return NULL pointer.
  165.  */
  166. aConfItem    *count_cnlines(lp)
  167. Reg1    Link    *lp;
  168. {
  169.     Reg1    aConfItem    *aconf, *cline = NULL, *nline = NULL;
  170.  
  171.     for (; lp; lp = lp->next)
  172.         {
  173.         aconf = lp->value.aconf;
  174.         if (!(aconf->status & CONF_SERVER_MASK))
  175.             continue;
  176.         if (aconf->status == CONF_CONNECT_SERVER && !cline)
  177.             cline = aconf;
  178.         else if (aconf->status == CONF_NOCONNECT_SERVER && !nline)
  179.             nline = aconf;
  180.         }
  181.     return nline;
  182. }
  183.  
  184. /*
  185. ** detach_conf
  186. **    Disassociate configuration from the client.
  187. **      Also removes a class from the list if marked for deleting.
  188. */
  189. int    detach_conf(cptr, aconf)
  190. aClient *cptr;
  191. aConfItem *aconf;
  192. {
  193.     Reg1    Link    **lp, *tmp;
  194.  
  195.     lp = &(cptr->confs);
  196.  
  197.     while (*lp)
  198.         {
  199.         if ((*lp)->value.aconf == aconf)
  200.             {
  201.             if ((aconf) && (Class(aconf)))
  202.                 {
  203.                 if (aconf->status & CONF_CLIENT_MASK)
  204.                     if (ConfLinks(aconf) > 0)
  205.                         --ConfLinks(aconf);
  206.                        if (ConfMaxLinks(aconf) == -1 &&
  207.                     ConfLinks(aconf) == 0)
  208.                      {
  209.                     free_class(Class(aconf));
  210.                     Class(aconf) = NULL;
  211.                     }
  212.                  }
  213.             if (aconf && !--aconf->clients && IsIllegal(aconf))
  214.                 free_conf(aconf);
  215.             tmp = *lp;
  216.             *lp = tmp->next;
  217.             free_link(tmp);
  218.             return 0;
  219.             }
  220.         else
  221.             lp = &((*lp)->next);
  222.         }
  223.     return -1;
  224. }
  225.  
  226. static    int    is_attached(aconf, cptr)
  227. aConfItem *aconf;
  228. aClient *cptr;
  229. {
  230.     Reg1    Link    *lp;
  231.  
  232.     for (lp = cptr->confs; lp; lp = lp->next)
  233.         if (lp->value.aconf == aconf)
  234.             break;
  235.  
  236.     return (lp) ? 1 : 0;
  237. }
  238.  
  239. /*
  240. ** attach_conf
  241. **    Associate a specific configuration entry to a *local*
  242. **    client (this is the one which used in accepting the
  243. **    connection). Note, that this automaticly changes the
  244. **    attachment if there was an old one...
  245. */
  246. int    attach_conf(cptr, aconf)
  247. aConfItem *aconf;
  248. aClient *cptr;
  249. {
  250.     Reg1 Link *lp;
  251.  
  252.     if (is_attached(aconf, cptr))
  253.         return 1;
  254.     if (IsIllegal(aconf))
  255.         return -1;
  256.     if ((aconf->status & (CONF_LOCOP | CONF_OPERATOR | CONF_CLIENT)) &&
  257.         aconf->clients >= ConfMaxLinks(aconf) && ConfMaxLinks(aconf) > 0)
  258.         return -3;    /* Use this for printing error message */
  259.     lp = make_link();
  260.     lp->next = cptr->confs;
  261.     lp->value.aconf = aconf;
  262.     cptr->confs = lp;
  263.     aconf->clients++;
  264.     if (aconf->status & CONF_CLIENT_MASK)
  265.         ConfLinks(aconf)++;
  266.     return 0;
  267. }
  268.  
  269.  
  270. aConfItem *find_admin()
  271.     {
  272.     Reg1 aConfItem *aconf;
  273.  
  274.     for (aconf = conf; aconf; aconf = aconf->next)
  275.         if (aconf->status & CONF_ADMIN)
  276.             break;
  277.     
  278.     return (aconf);
  279.     }
  280.  
  281. aConfItem *find_me()
  282.     {
  283.     Reg1 aConfItem *aconf;
  284.     for (aconf = conf; aconf; aconf = aconf->next)
  285.         if (aconf->status & CONF_ME)
  286.             break;
  287.     
  288.     return (aconf);
  289.     }
  290.  
  291. /*
  292.  * attach_confs
  293.  *  Attach a CONF line to a client if the name passed matches that for
  294.  * the conf file (for non-C/N lines) or is an exact match (C/N lines
  295.  * only).  The difference in behaviour is to stop C:*::* and N:*::*.
  296.  */
  297. aConfItem *attach_confs(cptr, name, statmask)
  298. aClient    *cptr;
  299. char    *name;
  300. int    statmask;
  301. {
  302.     Reg1 aConfItem *tmp;
  303.     aConfItem *first = NULL;
  304.     int len = strlen(name);
  305.   
  306.     if (!name || len > HOSTLEN)
  307.         return NULL;
  308.     for (tmp = conf; tmp; tmp = tmp->next)
  309.         {
  310.         if ((tmp->status & statmask) && !IsIllegal(tmp) &&
  311.             ((tmp->status & (CONF_SERVER_MASK|CONF_HUB)) == 0) &&
  312.             tmp->name && !match(tmp->name, name))
  313.             {
  314.             if (!attach_conf(cptr, tmp) && !first)
  315.                 first = tmp;
  316.             }
  317.         else if ((tmp->status & statmask) && !IsIllegal(tmp) &&
  318.              (tmp->status & (CONF_SERVER_MASK|CONF_HUB)) &&
  319.              tmp->name && !mycmp(tmp->name, name))
  320.             {
  321.             if (!attach_conf(cptr, tmp) && !first)
  322.                 first = tmp;
  323.             }
  324.         }
  325.     return (first);
  326. }
  327.  
  328. /*
  329.  * Added for new access check    meLazy
  330.  */
  331. aConfItem *attach_confs_host(cptr, host, statmask)
  332. aClient *cptr;
  333. char    *host;
  334. int    statmask;
  335. {
  336.     Reg1    aConfItem *tmp;
  337.     aConfItem *first = NULL;
  338.     int    len = strlen(host);
  339.   
  340.     if (!host || len > HOSTLEN)
  341.         return NULL;
  342.  
  343.     for (tmp = conf; tmp; tmp = tmp->next)
  344.         {
  345.         if ((tmp->status & statmask) && !IsIllegal(tmp) &&
  346.             (tmp->status & CONF_SERVER_MASK) == 0 &&
  347.             (!tmp->host || match(tmp->host, host) == 0))
  348.             {
  349.             if (!attach_conf(cptr, tmp) && !first)
  350.                 first = tmp;
  351.             }
  352.         else if ((tmp->status & statmask) && !IsIllegal(tmp) &&
  353.                    (tmp->status & CONF_SERVER_MASK) &&
  354.                    (tmp->host && mycmp(tmp->host, host) == 0))
  355.             {
  356.             if (!attach_conf(cptr, tmp) && !first)
  357.                 first = tmp;
  358.             }
  359.         }
  360.     return (first);
  361. }
  362.  
  363. /*
  364.  * find a conf entry which matches the hostname and has the same name.
  365.  */
  366. aConfItem *find_conf_exact(name, user, host, statmask)
  367. char    *name, *host, *user;
  368. int    statmask;
  369. {
  370.     Reg1    aConfItem *tmp;
  371.     char    userhost[USERLEN+HOSTLEN+3];
  372.  
  373.     (void)sprintf(userhost, "%s@%s", user, host);
  374.  
  375.     for (tmp = conf; tmp; tmp = tmp->next)
  376.         {
  377.         if (!(tmp->status & statmask) || !tmp->name || !tmp->host ||
  378.             mycmp(tmp->name, name))
  379.             continue;
  380.         /*
  381.         ** Accept if the *real* hostname (usually sockecthost)
  382.         ** socket host) matches *either* host or name field
  383.         ** of the configuration.
  384.         */
  385.         if (match(tmp->host, userhost))
  386.             continue;
  387.         if (tmp->status & (CONF_OPERATOR|CONF_LOCOP))
  388.             {
  389.             if (tmp->clients < MaxLinks(Class(tmp)))
  390.                 return tmp;
  391.             else
  392.                 continue;
  393.             }
  394.         else
  395.             return tmp;
  396.         }
  397.     return NULL;
  398. }
  399.  
  400. aConfItem *find_conf_name(name, statmask)
  401. char    *name;
  402. int    statmask;
  403. {
  404.     Reg1    aConfItem *tmp;
  405.  
  406.     for (tmp = conf; tmp; tmp = tmp->next)
  407.         {
  408.         /*
  409.         ** Accept if the *real* hostname (usually sockecthost)
  410.         ** matches *either* host or name field of the configuration.
  411.         */
  412.         if ((tmp->status & statmask) &&
  413.             (!tmp->name || match(tmp->name, name) == 0))
  414.             return tmp;
  415.         }
  416.     return NULL;
  417. }
  418.  
  419. aConfItem *find_conf(lp, name, statmask)
  420. char    *name;
  421. Link    *lp;
  422. int    statmask;
  423. {
  424.     Reg1    aConfItem *tmp;
  425.     int    namelen = name ? strlen(name) : 0;
  426.   
  427.     if (namelen > HOSTLEN)
  428.         return (aConfItem *) 0;
  429.  
  430.     for (; lp; lp = lp->next)
  431.         {
  432.         tmp = lp->value.aconf;
  433.         if ((tmp->status & statmask) &&
  434.             (((tmp->status & (CONF_SERVER_MASK|CONF_HUB)) &&
  435.               tmp->name && !mycmp(tmp->name, name)) ||
  436.              ((tmp->status & (CONF_SERVER_MASK|CONF_HUB)) == 0 &&
  437.              tmp->name && !match(tmp->name, name))))
  438.             return tmp;
  439.         }
  440.     return NULL;
  441. }
  442.  
  443. /*
  444.  * Added for new access check    meLazy
  445.  */
  446. aConfItem *find_conf_host(lp, host, statmask)
  447. Reg2    Link    *lp;
  448. char    *host;
  449. Reg3    int    statmask;
  450. {
  451.     Reg1    aConfItem *tmp;
  452.     int    hostlen = host ? strlen(host) : 0;
  453.   
  454.     if (hostlen > HOSTLEN || BadPtr(host))
  455.         return (aConfItem *)NULL;
  456.     for (; lp; lp = lp->next)
  457.         {
  458.         tmp = lp->value.aconf;
  459.         if (tmp->status & statmask &&
  460.             (!(tmp->status & CONF_SERVER_MASK || tmp->host) ||
  461.               (tmp->host && !match(tmp->host, host))))
  462.             return tmp;
  463.         }
  464.     return NULL;
  465. }
  466.  
  467. /*
  468.  * find_conf_ip
  469.  *
  470.  * Find a conf line using the IP# stored in it to search upon.
  471.  * Added 1/8/92 by Avalon.
  472.  */
  473. aConfItem *find_conf_ip(lp, ip, user, statmask)
  474. char    *ip, *user;
  475. Link    *lp;
  476. int    statmask;
  477. {
  478.     Reg1    aConfItem *tmp;
  479.     Reg2    char    *s;
  480.   
  481.     for (; lp; lp = lp->next)
  482.         {
  483.         tmp = lp->value.aconf;
  484.         if (!(tmp->status & statmask))
  485.             continue;
  486.         s = index(tmp->host, '@');
  487.         *s = '\0';
  488.         if (match(tmp->host, user))
  489.             {
  490.             *s = '@';
  491.             continue;
  492.             }
  493.         *s = '@';
  494.         if (!bcmp((char *)&tmp->ipnum, ip, sizeof(struct in_addr)))
  495.             return tmp;
  496.         }
  497.     return NULL;
  498. }
  499.  
  500. /*
  501.  * find_conf_entry
  502.  *
  503.  * - looks for a match on all given fields.
  504.  */
  505. aConfItem *find_conf_entry(aconf, mask)
  506. aConfItem *aconf;
  507. u_int    mask;
  508. {
  509.     Reg1    aConfItem *bconf;
  510.  
  511.     for (bconf = conf, mask &= ~CONF_ILLEGAL; bconf; bconf = bconf->next)
  512.         {
  513.         if (!(bconf->status & mask) || (bconf->port != aconf->port))
  514.             continue;
  515.  
  516.         if ((BadPtr(bconf->host) && !BadPtr(aconf->host)) ||
  517.             (BadPtr(aconf->host) && !BadPtr(bconf->host)))
  518.             continue;
  519.         if (!BadPtr(bconf->host) && mycmp(bconf->host, aconf->host))
  520.             continue;
  521.  
  522.         if ((BadPtr(bconf->passwd) && !BadPtr(aconf->passwd)) ||
  523.             (BadPtr(aconf->passwd) && !BadPtr(bconf->passwd)))
  524.             continue;
  525.         if (!BadPtr(bconf->passwd) &&
  526.             mycmp(bconf->passwd, aconf->passwd))
  527.             continue;
  528.  
  529.         if ((BadPtr(bconf->name) && !BadPtr(aconf->name)) ||
  530.             (BadPtr(aconf->name) && !BadPtr(bconf->name)))
  531.             continue;
  532.         if (!BadPtr(bconf->name) && mycmp(bconf->name, aconf->name))
  533.             continue;
  534.         break;
  535.         }
  536.     return bconf;
  537. }
  538.  
  539. /*
  540.  * rehash
  541.  *
  542.  * Actual REHASH service routine. Called with sig == 0 if it has been called
  543.  * as a result of an operator issuing this command, else assume it has been
  544.  * called as a result of the server receiving a HUP signal.
  545.  */
  546. int    rehash(cptr, sptr, sig)
  547. aClient    *cptr, *sptr;
  548. int    sig;
  549. {
  550.     Reg1    aConfItem **tmp = &conf, *tmp2;
  551.     Reg2    aClass    *cltmp;
  552.     Reg1    aClient    *acptr;
  553.     Reg2    int    i;
  554.     int    ret = 0;
  555.  
  556.     if (sig == 1)
  557.         {
  558.         sendto_ops("Got signal SIGHUP, reloading ircd conf. file");
  559. #ifdef    ULTRIX
  560.         if (fork() > 0)
  561.             exit(0);
  562.         write_pidfile();
  563. #endif
  564.         }
  565.  
  566.     for (i = 0; i <= highest_fd; i++)
  567.         if ((acptr = local[i]) && !IsMe(acptr))
  568.             {
  569.             /*
  570.              * Nullify any references from client structures to
  571.              * this host structure which is about to be freed.
  572.              * Could always keep reference counts instead of
  573.              * this....-avalon
  574.              */
  575.             acptr->hostp = NULL;
  576. #if defined(R_LINES_REHASH) && !defined(R_LINES_OFTEN)
  577.             if (find_restrict(acptr))
  578.                 {
  579.                 sendto_ops("Restricting %s, closing lp",
  580.                        get_client_name(acptr,FALSE));
  581.                 if (exit_client(cptr,acptr,sptr,"R-lined") ==
  582.                     FLUSH_BUFFER)
  583.                     ret = FLUSH_BUFFER;
  584.                 }
  585. #endif
  586.             }
  587.  
  588.     while ((tmp2 = *tmp))
  589.         if (tmp2->clients || tmp2->status & CONF_LISTEN_PORT)
  590.             {
  591.             /*
  592.             ** Configuration entry is still in use by some
  593.             ** local clients, cannot delete it--mark it so
  594.             ** that it will be deleted when the last client
  595.             ** exits...
  596.             */
  597.             if (!(tmp2->status & (CONF_LISTEN_PORT|CONF_CLIENT)))
  598.                 {
  599.                 *tmp = tmp2->next;
  600.                 tmp2->next = NULL;
  601.                 }
  602.             else
  603.                 tmp = &tmp2->next;
  604.             tmp2->status |= CONF_ILLEGAL;
  605.             }
  606.         else
  607.             {
  608.             *tmp = tmp2->next;
  609.             free_conf(tmp2);
  610.                 }
  611.  
  612.     /*
  613.      * We don't delete the class table, rather mark all entries
  614.      * for deletion. The table is cleaned up by check_class. - avalon
  615.      */
  616.     for (cltmp = NextClass(FirstClass()); cltmp; cltmp = NextClass(cltmp))
  617.         MaxLinks(cltmp) = -1;
  618.  
  619.     if (sig != 2)
  620.         flush_cache();
  621.     (void) initconf(0);
  622.     close_listeners();
  623.  
  624.     /*
  625.      * flush out deleted I and P lines although still in use.
  626.      */
  627.     for (tmp = &conf; (tmp2 = *tmp); )
  628.         if (!(tmp2->status & CONF_ILLEGAL))
  629.             tmp = &tmp2->next;
  630.         else
  631.             {
  632.             *tmp = tmp2->next;
  633.             tmp2->next = NULL;
  634.             if (!tmp2->clients)
  635.                 free_conf(tmp2);
  636.             }
  637.     return ret;
  638. }
  639.  
  640. /*
  641.  * openconf
  642.  *
  643.  * returns -1 on any error or else the fd opened from which to read the
  644.  * configuration file from.  This may either be th4 file direct or one end
  645.  * of a pipe from m4.
  646.  */
  647. int    openconf()
  648. {
  649. #ifdef    M4_PREPROC
  650.     int    pi[2], i;
  651.  
  652.     if (pipe(pi) == -1)
  653.         return -1;
  654.     switch(fork())
  655.     {
  656.     case -1 :
  657.         return -1;
  658.     case 0 :
  659.         (void)close(pi[0]);
  660.         if (pi[1] != 1)
  661.             {
  662.             (void)dup2(pi[1], 1);
  663.             (void)close(pi[1]);
  664.             }
  665.         (void)dup2(1,2);
  666.         for (i = 3; i < MAXCONNECTIONS; i++)
  667.             if (local[i])
  668.                 (void) close(i);
  669.         /*
  670.          * m4 maybe anywhere, use execvp to find it.  Any error
  671.          * goes out with report_error.  Could be dangerous,
  672.          * two servers running with the same fd's >:-) -avalon
  673.          */
  674.         (void)execlp("m4", "m4", "ircd.m4", configfile, 0);
  675.         report_error("Error executing m4 %s:%s", &me);
  676.         exit(-1);
  677.     default :
  678.         (void)close(pi[1]);
  679.         return pi[0];
  680.     }
  681. #else
  682.     return open(configfile, O_RDONLY);
  683. #endif
  684. }
  685. extern char *getfield();
  686.  
  687. /*
  688. ** initconf() 
  689. **    Read configuration file.
  690. **
  691. **    returns -1, if file cannot be opened
  692. **             0, if file opened
  693. */
  694.  
  695. #define MAXCONFLINKS 150
  696.  
  697. int     initconf(opt)
  698. int    opt;
  699. {
  700.     static    char    quotes[9][2] = {{'b', '\b'}, {'f', '\f'}, {'n', '\n'},
  701.                     {'r', '\r'}, {'t', '\t'}, {'v', '\v'},
  702.                     {'\\', '\\'}, { 0, 0}};
  703.     Reg1    char    *tmp, *s;
  704.     int    fd, i;
  705.     char    line[512], c[80];
  706.     int    ccount = 0, ncount = 0;
  707.     aConfItem *aconf = NULL;
  708.  
  709.     Debug((DEBUG_DEBUG, "initconf(): ircd.conf = %s", configfile));
  710.     if ((fd = openconf()) == -1)
  711.         {
  712. #ifdef    M4_PREPROC
  713.         (void)wait(0);
  714. #endif
  715.         return -1;
  716.         }
  717.     (void)dgets(-1, NULL, 0); /* make sure buffer is at empty pos */
  718.     while ((i = dgets(fd, line, sizeof(line) - 1)) > 0)
  719.         {
  720.         line[i] = '\0';
  721.         if ((tmp = (char *)index(line, '\n')))
  722.             *tmp = 0;
  723.         else while(dgets(fd, c, sizeof(c) - 1) > 0)
  724.             if ((tmp = (char *)index(c, '\n')))
  725.                 {
  726.                 *tmp = 0;
  727.                 break;
  728.                 }
  729.         /*
  730.          * Do quoting of characters and # detection.
  731.          */
  732.         for (tmp = line; *tmp; tmp++)
  733.             {
  734.             if (*tmp == '\\')
  735.                 {
  736.                 for (i = 0; quotes[i][0]; i++)
  737.                     if (quotes[i][0] == *(tmp+1))
  738.                         {
  739.                         *tmp = quotes[i][1];
  740.                         break;
  741.                         }
  742.                 if (!quotes[i][0])
  743.                     *tmp = *(tmp+1);
  744.                 if (!*(tmp+1))
  745.                     break;
  746.                 else
  747.                     for (s = tmp; *s = *(s+1); s++)
  748.                         ;
  749.                 }
  750.             else if (*tmp == '#')
  751.                 *tmp = '\0';
  752.             }
  753.         if (!*line || line[0] == '#' || line[0] == '\n' ||
  754.             line[0] == ' ' || line[0] == '\t')
  755.             continue;
  756.         /* Could we test if it's conf line at all?    -Vesa */
  757.         if (line[1] != ':')
  758.             {
  759.                         Debug((DEBUG_ERROR, "Bad config line: %s", line));
  760.                         continue;
  761.                     }
  762.         if (aconf)
  763.             free_conf(aconf);
  764.         aconf = make_conf();
  765.  
  766.         tmp = getfield(line);
  767.         if (!tmp)
  768.             continue;
  769.         switch (*tmp)
  770.         {
  771.             case 'A': /* Name, e-mail address of administrator */
  772.             case 'a': /* of this server. */
  773.                 aconf->status = CONF_ADMIN;
  774.                 break;
  775.             case 'C': /* Server where I should try to connect */
  776.             case 'c': /* in case of lp failures             */
  777.                 ccount++;
  778.                 aconf->status = CONF_CONNECT_SERVER;
  779.                 break;
  780.             case 'H': /* Hub server line */
  781.             case 'h':
  782.                 aconf->status = CONF_HUB;
  783.                 break;
  784.             case 'I': /* Just plain normal irc client trying  */
  785.             case 'i': /* to connect me */
  786.                 aconf->status = CONF_CLIENT;
  787.                 break;
  788.             case 'K': /* Kill user line on irc.conf           */
  789.             case 'k':
  790.                 aconf->status = CONF_KILL;
  791.                 break;
  792.             /* Operator. Line should contain at least */
  793.             /* password and host where connection is  */
  794.             case 'L': /* guaranteed leaf server */
  795.             case 'l':
  796.                 aconf->status = CONF_LEAF;
  797.                 break;
  798.             /* Me. Host field is name used for this host */
  799.             /* and port number is the number of the port */
  800.             case 'M':
  801.             case 'm':
  802.                 aconf->status = CONF_ME;
  803.                 break;
  804.             case 'N': /* Server where I should NOT try to     */
  805.             case 'n': /* connect in case of lp failures     */
  806.                   /* but which tries to connect ME        */
  807.                 ++ncount;
  808.                 aconf->status = CONF_NOCONNECT_SERVER;
  809.                 break;
  810.             case 'O':
  811.                 aconf->status = CONF_OPERATOR;
  812.                 break;
  813.             /* Local Operator, (limited privs --SRB) */
  814.             case 'o':
  815.                 aconf->status = CONF_LOCOP;
  816.                 break;
  817.             case 'P': /* listen port line */
  818.             case 'p':
  819.                 aconf->status = CONF_LISTEN_PORT;
  820.                 break;
  821.             case 'Q': /* a server that you don't want in your */
  822.             case 'q': /* network. USE WITH CAUTION! */
  823.                 aconf->status = CONF_QUARANTINED_SERVER;
  824.                 break;
  825. #ifdef R_LINES
  826.             case 'R': /* extended K line */
  827.             case 'r': /* Offers more options of how to restrict */
  828.                 aconf->status = CONF_RESTRICT;
  829.                 break;
  830. #endif
  831.             case 'S': /* Service. Same semantics as   */
  832.             case 's': /* CONF_OPERATOR                */
  833.                 aconf->status = CONF_SERVICE;
  834.                 break;
  835.             case 'U': /* Uphost, ie. host where client reading */
  836.             case 'u': /* this should connect.                  */
  837.             /* This is for client only, I must ignore this */
  838.             /* ...U-line should be removed... --msa */
  839.                 break;
  840.             case 'Y':
  841.             case 'y':
  842.                     aconf->status = CONF_CLASS;
  843.                     break;
  844.             default:
  845.             Debug((DEBUG_ERROR, "Error in config file: %s", line));
  846.             break;
  847.             }
  848.         if (IsIllegal(aconf))
  849.             continue;
  850.  
  851.         for (;;) /* Fake loop, that I can use break here --msa */
  852.             {
  853.             if ((tmp = getfield(NULL)) == NULL)
  854.                 break;
  855.             DupString(aconf->host, tmp);
  856.             if ((tmp = getfield(NULL)) == NULL)
  857.                 break;
  858.             DupString(aconf->passwd, tmp);
  859.             if ((tmp = getfield(NULL)) == NULL)
  860.                 break;
  861.             DupString(aconf->name, tmp);
  862.             if ((tmp = getfield(NULL)) == NULL)
  863.                 break;
  864.             aconf->port = atoi(tmp);
  865.             if ((tmp = getfield(NULL)) == NULL)
  866.                 break;
  867.             Class(aconf) = find_class(atoi(tmp));
  868.             break;
  869.             }
  870.         /*
  871.                 ** If conf line is a class definition, create a class entry
  872.                 ** for it and make the conf_line illegal and delete it.
  873.                 */
  874.         if (aconf->status & CONF_CLASS)
  875.             {
  876.             add_class(atoi(aconf->host), atoi(aconf->passwd),
  877.                   atoi(aconf->name), aconf->port,
  878.                   tmp ? atoi(tmp) : 0);
  879.             continue;
  880.             }
  881.         /*
  882.                 ** associate each conf line with a class by using a pointer
  883.                 ** to the correct class record. -avalon
  884.                 */
  885.         if (aconf->status & (CONF_CLIENT_MASK|CONF_LISTEN_PORT))
  886.             {
  887.             if (Class(aconf) == 0)
  888.                 Class(aconf) = find_class(0);
  889.             if (MaxLinks(Class(aconf)) < 0)
  890.                 Class(aconf) = find_class(0);
  891.             }
  892.         if (aconf->status & (CONF_LISTEN_PORT|CONF_CLIENT))
  893.             {
  894.             aConfItem *bconf;
  895.  
  896.             if (bconf = find_conf_entry(aconf, aconf->status))
  897.                 {
  898.                 delist_conf(bconf);
  899.                 bconf->status &= ~CONF_ILLEGAL;
  900.                 if (aconf->status == CONF_CLIENT)
  901.                     {
  902.                     bconf->class->links -= bconf->clients;
  903.                     bconf->class = aconf->class;
  904.                     bconf->class->links += bconf->clients;
  905.                     }
  906.                 free_conf(aconf);
  907.                 aconf = bconf;
  908.                 }
  909.             else if (aconf->host &&
  910.                  aconf->status == CONF_LISTEN_PORT)
  911.                 (void)add_listener(aconf);
  912.             }
  913.         if (aconf->status & CONF_SERVER_MASK)
  914.             if (ncount > MAXCONFLINKS || ccount > MAXCONFLINKS ||
  915.                 !aconf->host || index(aconf->host, '*') ||
  916.                  index(aconf->host,'?') || !aconf->name)
  917.                 continue;
  918.  
  919.         if (aconf->status &
  920.             (CONF_SERVER_MASK|CONF_LOCOP|CONF_OPERATOR))
  921.             if (!index(aconf->host, '@') && *aconf->host != '/')
  922.                 {
  923.                 char    *newhost;
  924.                 int    len = 3;    /* *@\0 = 3 */
  925.  
  926.                 len += strlen(aconf->host);
  927.                 newhost = (char *)MyMalloc(len);
  928.                 (void)sprintf(newhost, "*@%s", aconf->host);
  929.                 MyFree(aconf->host);
  930.                 aconf->host = newhost;
  931.                 }
  932.         if (aconf->status & CONF_SERVER_MASK)
  933.             {
  934.             if (BadPtr(aconf->passwd))
  935.                 continue;
  936.             else if (!(opt & BOOT_QUICK))
  937.                 (void)lookup_confhost(aconf);
  938.             }
  939.         /*
  940.         ** Own port and name cannot be changed after the startup.
  941.         ** (or could be allowed, but only if all links are closed
  942.         ** first).
  943.         ** Configuration info does not override the name and port
  944.         ** if previously defined. Note, that "info"-field can be
  945.         ** changed by "/rehash".
  946.         */
  947.         if (aconf->status == CONF_ME)
  948.             {
  949.             strncpyzt(me.info, aconf->name, sizeof(me.info));
  950.             if (me.name[0] == '\0' && aconf->host[0])
  951.                 strncpyzt(me.name, aconf->host,
  952.                       sizeof(me.name));
  953.             if (portnum < 0 && aconf->port >= 0)
  954.                 portnum = aconf->port;
  955.             }
  956.         (void)collapse(aconf->host);
  957.         (void)collapse(aconf->name);
  958.         Debug((DEBUG_NOTICE,
  959.               "Read Init: (%d) (%s) (%s) (%s) (%d) (%d)",
  960.               aconf->status, aconf->host, aconf->passwd,
  961.               aconf->name, aconf->port, Class(aconf)));
  962.         aconf->next = conf;
  963.         conf = aconf;
  964.         aconf = NULL;
  965.         }
  966.     if (aconf)
  967.         free_conf(aconf);
  968.     (void)dgets(-1, NULL, 0); /* make sure buffer is at empty pos */
  969.     (void)close(fd);
  970. #ifdef    M4_PREPROC
  971.     (void)wait(0);
  972. #endif
  973.     check_class();
  974.     nextping = nextconnect = time(NULL);
  975.     return 0;
  976.     }
  977.  
  978. /*
  979.  * lookup_confhost
  980.  *   Do (start) DNS lookups of all hostnames in the conf line and convert
  981.  * an IP addresses in a.b.c.d number for to IP#s.
  982.  */
  983. static    int    lookup_confhost(aconf)
  984. Reg1    aConfItem    *aconf;
  985. {
  986.     Reg2    char    *s;
  987.     Reg3    struct    hostent *hp;
  988.     Link    ln;
  989.  
  990.     if (BadPtr(aconf->host) || BadPtr(aconf->name))
  991.         goto badlookup;
  992.     if ((s = index(aconf->host, '@')))
  993.         s++;
  994.     else
  995.         s = aconf->host;
  996.     /*
  997.     ** Do name lookup now on hostnames given and store the
  998.     ** ip numbers in conf structure.
  999.     */
  1000.     if (!isalpha(*s) && !isdigit(*s))
  1001.         goto badlookup;
  1002.  
  1003.     /*
  1004.     ** Prepare structure in case we have to wait for a
  1005.     ** reply which we get later and store away.
  1006.     */
  1007.     ln.value.aconf = aconf;
  1008.     ln.flags = ASYNC_CONF;
  1009.  
  1010.     if (isdigit(*s))
  1011.         aconf->ipnum.s_addr = inet_addr(s);
  1012.     else if ((hp = gethost_byname(s, &ln)))
  1013.         bcopy(hp->h_addr, (char *)&(aconf->ipnum),
  1014.             sizeof(struct in_addr));
  1015.  
  1016.     if (aconf->ipnum.s_addr == -1)
  1017.         goto badlookup;
  1018.     return 0;
  1019. badlookup:
  1020.     if (aconf->ipnum.s_addr == -1)
  1021.         bzero((char *)&aconf->ipnum, sizeof(struct in_addr));
  1022.     Debug((DEBUG_ERROR,"Host/server name error: (%s) (%s)",
  1023.         aconf->host, aconf->name));
  1024.     return -1;
  1025. }
  1026.  
  1027. int    find_kill(cptr)
  1028. aClient    *cptr;
  1029. {
  1030.     char    reply[256], *host, *name;
  1031.     aConfItem *tmp;
  1032.  
  1033.     if (!cptr->user)
  1034.         return 0;
  1035.  
  1036.     host = cptr->sockhost;
  1037.     name = cptr->user->username;
  1038.  
  1039.     if (strlen(host)  > (size_t) HOSTLEN ||
  1040.             (name ? strlen(name) : 0) > (size_t) HOSTLEN)
  1041.         return (0);
  1042.  
  1043.     reply[0] = '\0';
  1044.  
  1045.     for (tmp = conf; tmp; tmp = tmp->next)
  1046.          if ((tmp->status == CONF_KILL) && tmp->host && tmp->name &&
  1047.             (match(tmp->host, host) == 0) &&
  1048.              (!name || match(tmp->name, name) == 0) &&
  1049.             (!tmp->port || (tmp->port == cptr->acpt->port)))
  1050.              if (BadPtr(tmp->passwd) ||
  1051.                  check_time_interval(tmp->passwd, reply))
  1052.              break;
  1053.  
  1054.     if (reply[0])
  1055.         sendto_one(cptr, reply,
  1056.                me.name, ERR_YOUREBANNEDCREEP, cptr->name);
  1057.     else if (tmp)
  1058.         sendto_one(cptr, err_str(ERR_YOUREBANNEDCREEP), me.name,
  1059.                cptr->name);
  1060.  
  1061.      return (tmp ? -1 : 0);
  1062.  }
  1063.  
  1064. #ifdef R_LINES
  1065. /* find_restrict works against host/name and calls an outside program 
  1066.  * to determine whether a client is allowed to connect.  This allows 
  1067.  * more freedom to determine who is legal and who isn't, for example
  1068.  * machine load considerations.  The outside program is expected to 
  1069.  * return a reply line where the first word is either 'Y' or 'N' meaning 
  1070.  * "Yes Let them in" or "No don't let them in."  If the first word 
  1071.  * begins with neither 'Y' or 'N' the default is to let the person on.
  1072.  * It returns a value of 0 if the user is to be let through -Hoppie
  1073.  */
  1074. int    find_restrict(cptr)
  1075. aClient    *cptr;
  1076. {
  1077.     aConfItem *tmp;
  1078.     char    reply[80], temprpl[80];
  1079.     char    *rplhold = reply, *host, *name, *s;
  1080.     char    rplchar = 'Y';
  1081.     int    pi[2], rc = 0, n;
  1082.  
  1083.     if (!cptr->user)
  1084.         return 0;
  1085.     name = cptr->user->username;
  1086.     host = cptr->sockhost;
  1087.     Debug((DEBUG_INFO, "R-line check for %s[%s]", name, host));
  1088.  
  1089.     for (tmp = conf; tmp; tmp = tmp->next)
  1090.         {
  1091.         if (tmp->status != CONF_RESTRICT ||
  1092.             (tmp->host && host && match(tmp->host, host)) ||
  1093.             (tmp->name && name && match(tmp->name, name)))
  1094.             continue;
  1095.  
  1096.         if (BadPtr(tmp->passwd))
  1097.             {
  1098.             sendto_ops("Program missing on R-line %s/%s, ignoring",
  1099.                    name, host);
  1100.             continue;
  1101.             }
  1102.  
  1103.         if (pipe(pi) == -1)
  1104.             {
  1105.             report_error("Error creating pipe for R-line %s:%s",
  1106.                      &me);
  1107.             return 0;
  1108.             }
  1109.         switch (rc = fork())
  1110.         {
  1111.         case -1 :
  1112.             report_error("Error forking for R-line %s:%s", &me);
  1113.             return 0;
  1114.         case 0 :
  1115.             {
  1116.             Reg1    int    i;
  1117.  
  1118.             (void)close(pi[0]);
  1119.             for (i = 2; i < MAXCONNECTIONS; i++)
  1120.                 if (i != pi[1])
  1121.                     (void)close(i);
  1122.             if (pi[1] != 2)
  1123.                 (void)dup2(pi[1], 2);
  1124.             (void)dup2(2, 1);
  1125.             if (pi[1] != 2 && pi[1] != 1)
  1126.                 (void)close(pi[1]);
  1127.             (void)execlp(tmp->passwd, tmp->passwd, name, host, 0);
  1128.             exit(-1);
  1129.             }
  1130.         default :
  1131.             (void)close(pi[1]);
  1132.             break;
  1133.         }
  1134.         *reply = '\0';
  1135.         (void)dgets(-1, NULL, 0); /* make sure buffer marked empty */
  1136.         while ((n = dgets(pi[0], temprpl, sizeof(temprpl)-1)) > 0)
  1137.             {
  1138.             temprpl[n] = '\0';
  1139.             if ((s = (char *)index(temprpl, '\n')))
  1140.                   *s = '\0';
  1141.             if (strlen(temprpl) + strlen(reply) < sizeof(reply)-2)
  1142.                 (void)sprintf(rplhold, "%s %s", rplhold,
  1143.                     temprpl);
  1144.             else
  1145.                 {
  1146.                 sendto_ops("R-line %s/%s: reply too long!",
  1147.                        name, host);
  1148.                 break;
  1149.                 }
  1150.             }
  1151.         (void)dgets(-1, NULL, 0); /* make sure buffer marked empty */
  1152.         (void)close(pi[0]);
  1153.         (void)kill(rc, SIGKILL); /* cleanup time */
  1154.         (void)wait(0);
  1155.  
  1156.         rc = 0;
  1157.         while (*rplhold == ' ')
  1158.             rplhold++;
  1159.         rplchar = *rplhold; /* Pull out the yes or no */
  1160.         while (*rplhold != ' ')
  1161.             rplhold++;
  1162.         while (*rplhold == ' ')
  1163.             rplhold++;
  1164.         (void)strcpy(reply,rplhold);
  1165.         rplhold = reply;
  1166.  
  1167.         if ((rc = (rplchar == 'n' || rplchar == 'N')))
  1168.             break;
  1169.         }
  1170.     if (rc)
  1171.         {
  1172.         sendto_one(cptr, ":%s %d %s :Restriction: %s",
  1173.                me.name, ERR_YOUREBANNEDCREEP, cptr->name,
  1174.                reply);
  1175.         return -1;
  1176.         }
  1177.     return 0;
  1178. }
  1179. #endif
  1180.  
  1181.  
  1182. /*
  1183. ** check against a set of time intervals
  1184. */
  1185.  
  1186. static    int    check_time_interval(interval, reply)
  1187. char    *interval, *reply;
  1188. {
  1189.     struct tm *tptr;
  1190.      time_t    tick;
  1191.      char    *p;
  1192.      int    perm_min_hours, perm_min_minutes,
  1193.          perm_max_hours, perm_max_minutes;
  1194.      int    now, perm_min, perm_max;
  1195.  
  1196.      tick = time(NULL);
  1197.     tptr = localtime(&tick);
  1198.      now = tptr->tm_hour * 60 + tptr->tm_min;
  1199.  
  1200.     while (interval)
  1201.         {
  1202.         p = (char *)index(interval, ',');
  1203.         if (p)
  1204.             *p = '\0';
  1205.         if (sscanf(interval, "%2d%2d-%2d%2d",
  1206.                &perm_min_hours, &perm_min_minutes,
  1207.                &perm_max_hours, &perm_max_minutes) != 4)
  1208.             {
  1209.             if (p)
  1210.                 *p = ',';
  1211.             return(0);
  1212.             }
  1213.         if (p)
  1214.             *(p++) = ',';
  1215.         perm_min = 60 * perm_min_hours + perm_min_minutes;
  1216.         perm_max = 60 * perm_max_hours + perm_max_minutes;
  1217.                /*
  1218.                ** The following check allows intervals over midnight ...
  1219.                */
  1220.         if ((perm_min < perm_max)
  1221.             ? (perm_min <= now && now <= perm_max)
  1222.             : (perm_min <= now || now <= perm_max))
  1223.             {
  1224.             (void)sprintf(reply,
  1225.                 ":%%s %%d %%s :%s %d:%02d to %d:%02d.",
  1226.                 "You are not allowed to connect from",
  1227.                 perm_min_hours, perm_min_minutes,
  1228.                 perm_max_hours, perm_max_minutes);
  1229.             return(ERR_YOUREBANNEDCREEP);
  1230.             }
  1231.         if ((perm_min < perm_max)
  1232.             ? (perm_min <= now + 5 && now + 5 <= perm_max)
  1233.             : (perm_min <= now + 5 || now + 5 <= perm_max))
  1234.             {
  1235.             (void)sprintf(reply, ":%%s %%d %%s :%d minute%s%s",
  1236.                 perm_min-now,(perm_min-now)>1?"s ":" ",
  1237.                 "and you will be denied for further access");
  1238.             return(ERR_YOUWILLBEBANNED);
  1239.             }
  1240.         interval = p;
  1241.         }
  1242.     return(0);
  1243. }
  1244.