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 / s_conf.c < prev    next >
C/C++ Source or Header  |  1998-01-19  |  63KB  |  2,488 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. /* Changed all calls of check_pings so that only when a kline-related command
  22.    is used will a kline check occur -- Barubary */
  23.  
  24. #define KLINE_RET_AKILL 3
  25. #define KLINE_RET_PERM 2
  26. #define KLINE_RET_DELOK 1
  27. #define KLINE_DEL_ERR 0
  28.  
  29.  
  30. #ifndef lint
  31. static  char sccsid[] = "@(#)s_conf.c    2.56 02 Apr 1994 (C) 1988 University of Oulu, \
  32. Computing Center and Jarkko Oikarinen";
  33. #endif
  34.  
  35. #include "struct.h"
  36. #include "common.h"
  37. #include "sys.h"
  38. #include "numeric.h"
  39. #include "channel.h"
  40. #include <fcntl.h>
  41. #ifndef _WIN32
  42. #include <sys/socket.h>
  43. #include <sys/wait.h>
  44. #else
  45. #include <io.h>
  46. #endif
  47. #include <sys/stat.h>
  48. #ifdef __hpux
  49. #include "inet.h"
  50. #endif
  51. #if defined(PCS) || defined(AIX) || defined(DYNIXPTX) || defined(SVR3)
  52. #include <time.h>
  53. #endif
  54. #ifdef    R_LINES
  55. #include <signal.h>
  56. #endif
  57.  
  58. #include "h.h"
  59.  
  60. static    int    check_time_interval PROTO((char *, char *));
  61. static    int    lookup_confhost PROTO((aConfItem *));
  62. static    int    is_comment PROTO((char *));
  63. static  int     advanced_check(char *, int);
  64.  
  65. aSqlineItem    *sqline = NULL;
  66. aConfItem    *conf = NULL;
  67. extern char    zlinebuf[];
  68.  
  69. /*
  70.  * remove all conf entries from the client except those which match
  71.  * the status field mask.
  72.  */
  73. void    det_confs_butmask(cptr, mask)
  74. aClient    *cptr;
  75. int    mask;
  76. {
  77.     Reg1 Link *tmp, *tmp2;
  78.  
  79.     for (tmp = cptr->confs; tmp; tmp = tmp2)
  80.         {
  81.         tmp2 = tmp->next;
  82.         if ((tmp->value.aconf->status & mask) == 0)
  83.             (void)detach_conf(cptr, tmp->value.aconf);
  84.         }
  85. }
  86.  
  87. /*
  88.  * Add a temporary line to the configuration
  89.  */
  90. void    add_temp_conf(status, host, passwd, name, port, class, temp)
  91. unsigned int    status;
  92. char    *host;
  93. char    *passwd;
  94. char    *name;
  95. int    port, class, temp;    /* temp: 0 = perm 1 = temp 2 = akill */
  96. {
  97.     Reg1 aConfItem *aconf;
  98.  
  99.     aconf = make_conf();
  100.  
  101.     aconf->tmpconf = temp;
  102.     aconf->status = status;
  103.     if (host)
  104.       DupString(aconf->host, host);
  105.     if (passwd)
  106.       DupString(aconf->passwd, passwd);
  107.     if (name)
  108.       DupString(aconf->name, name);
  109.     aconf->port = port;
  110.     if (class)
  111.         Class(aconf) = find_class(class);
  112.     if (!find_temp_conf_entry(aconf, status)) {
  113.         aconf->next = conf;
  114.         conf = aconf;
  115.         aconf = NULL;
  116.     }
  117.  
  118.     if (aconf)
  119.       free_conf(aconf);
  120. }
  121.  
  122. /*
  123.  * delete a temporary conf line.  *only* temporary conf lines may be deleted.
  124.  */
  125. int    del_temp_conf(status, host, passwd, name, port, class, akill)
  126. unsigned int    status, akill;
  127. char    *host;
  128. char    *passwd;
  129. char    *name;
  130. int     port, class;
  131. {
  132.     Reg1    aConfItem    *aconf;
  133.     Reg3    aConfItem    *bconf;
  134.     u_int    mask;
  135.     u_int    result=KLINE_DEL_ERR;
  136.  
  137.     aconf = make_conf();
  138.     
  139.     aconf->status=status;
  140.     if(host)
  141.         DupString(aconf->host, host);
  142.     if(passwd)
  143.         DupString(aconf->passwd, passwd);
  144.     if(name)
  145.         DupString(aconf->name, name);
  146.     aconf->port = port;
  147.     if(class)
  148.         Class(aconf) = find_class(class);
  149.     mask = status;
  150.     if (bconf=find_temp_conf_entry(aconf,mask)) /* only if non-null ptr */
  151.     {
  152. /* Completely skirt the akill error messages if akill is set to 1
  153.  * this allows RAKILL to do its thing without having to go through the
  154.  * error checkers.  If it had to it would go kaplooey. --Russell
  155.  */
  156.         if (bconf->tmpconf == KLINE_PERM && (akill != 3))
  157.             result = KLINE_RET_PERM;/* Kline permanent */
  158.         else if (!akill && (bconf->tmpconf == KLINE_AKILL))
  159.             result = KLINE_RET_AKILL;  /* Akill */
  160.         else if (akill && (bconf->tmpconf != KLINE_AKILL))
  161.             result = KLINE_RET_PERM;
  162.         else
  163.         {
  164.             bconf->status |= CONF_ILLEGAL; /* just mark illegal */
  165.             result = KLINE_RET_DELOK;      /* same as deletion */
  166.         }    
  167.  
  168.     }
  169.     if (aconf)
  170.         free_conf(aconf);
  171.     return result; /* if it gets to here, it doesn't exist */
  172. }
  173.  
  174. /*
  175.  * find the first (best) I line to attach.
  176.  */
  177. int    attach_Iline(cptr, hp, sockhost)
  178. aClient *cptr;
  179. Reg2    struct    hostent    *hp;
  180. char    *sockhost;
  181. {
  182.     Reg1    aConfItem    *aconf;
  183.     Reg3    char    *hname;
  184.     Reg4    int    i;
  185.     static    char    uhost[HOSTLEN+USERLEN+3];
  186.     static    char    fullname[HOSTLEN+1];
  187.  
  188.     for (aconf = conf; aconf; aconf = aconf->next)
  189.         {
  190.         if (aconf->status != CONF_CLIENT)
  191.             continue;
  192.         if (aconf->port && aconf->port != cptr->acpt->port)
  193.             continue;
  194.         if (!aconf->host || !aconf->name)
  195.             goto attach_iline;
  196.         if (hp)
  197.             for (i = 0, hname = hp->h_name; hname;
  198.                  hname = hp->h_aliases[i++])
  199.                 {
  200.                 (void)strncpy(fullname, hname,
  201.                     sizeof(fullname)-1);
  202.                 add_local_domain(fullname,
  203.                          HOSTLEN - strlen(fullname));
  204.                 Debug((DEBUG_DNS, "a_il: %s->%s",
  205.                       sockhost, fullname));
  206.                 if (index(aconf->name, '@'))
  207.                     {
  208.                     (void)strcpy(uhost, cptr->username);
  209.                     (void)strcat(uhost, "@");
  210.                     }
  211.                 else
  212.                     *uhost = '\0';
  213.                 (void)strncat(uhost, fullname,
  214.                     sizeof(uhost) - strlen(uhost));
  215.                 if (!match(aconf->name, uhost))
  216.                     goto attach_iline;
  217.                 }
  218.  
  219.         if (index(aconf->host, '@'))
  220.             {
  221.             strncpyzt(uhost, cptr->username, sizeof(uhost));
  222.             (void)strcat(uhost, "@");
  223.             }
  224.         else
  225.             *uhost = '\0';
  226.         (void)strncat(uhost, sockhost, sizeof(uhost) - strlen(uhost));
  227.         if (!match(aconf->host, uhost))
  228.             goto attach_iline;
  229.         continue;
  230. attach_iline:
  231.         if (index(uhost, '@'))
  232.             cptr->flags |= FLAGS_DOID;
  233.         get_sockhost(cptr, uhost);
  234.         return attach_conf(cptr, aconf);
  235.         }
  236.     return -1;
  237. }
  238.  
  239. /*
  240.  * Find the single N line and return pointer to it (from list).
  241.  * If more than one then return NULL pointer.
  242.  */
  243. aConfItem    *count_cnlines(lp)
  244. Reg1    Link    *lp;
  245. {
  246.     Reg1    aConfItem    *aconf, *cline = NULL, *nline = NULL;
  247.  
  248.     for (; lp; lp = lp->next)
  249.         {
  250.         aconf = lp->value.aconf;
  251.         if (!(aconf->status & CONF_SERVER_MASK))
  252.             continue;
  253.         if (aconf->status == CONF_CONNECT_SERVER && !cline)
  254.             cline = aconf;
  255.         else if (aconf->status == CONF_NOCONNECT_SERVER && !nline)
  256.             nline = aconf;
  257.         }
  258.     return nline;
  259. }
  260.  
  261. /*
  262. ** detach_conf
  263. **    Disassociate configuration from the client.
  264. **      Also removes a class from the list if marked for deleting.
  265. */
  266. int    detach_conf(cptr, aconf)
  267. aClient *cptr;
  268. aConfItem *aconf;
  269. {
  270.     Reg1    Link    **lp, *tmp;
  271.  
  272.     lp = &(cptr->confs);
  273.  
  274.     while (*lp)
  275.         {
  276.         if ((*lp)->value.aconf == aconf)
  277.             {
  278.             if ((aconf) && (Class(aconf)))
  279.                 {
  280.                 if (aconf->status & CONF_CLIENT_MASK)
  281.                     if (ConfLinks(aconf) > 0)
  282.                         --ConfLinks(aconf);
  283.                        if (ConfMaxLinks(aconf) == -1 &&
  284.                     ConfLinks(aconf) == 0)
  285.                      {
  286.                     free_class(Class(aconf));
  287.                     Class(aconf) = NULL;
  288.                     }
  289.                  }
  290.             if (aconf && !--aconf->clients && IsIllegal(aconf))
  291.                 free_conf(aconf);
  292.             tmp = *lp;
  293.             *lp = tmp->next;
  294.             free_link(tmp);
  295.             return 0;
  296.             }
  297.         else
  298.             lp = &((*lp)->next);
  299.         }
  300.     return -1;
  301. }
  302.  
  303. static    int    is_attached(aconf, cptr)
  304. aConfItem *aconf;
  305. aClient *cptr;
  306. {
  307.     Reg1    Link    *lp;
  308.  
  309.     for (lp = cptr->confs; lp; lp = lp->next)
  310.         if (lp->value.aconf == aconf)
  311.             break;
  312.  
  313.     return (lp) ? 1 : 0;
  314. }
  315.  
  316. /*
  317. ** attach_conf
  318. **    Associate a specific configuration entry to a *local*
  319. **    client (this is the one which used in accepting the
  320. **    connection). Note, that this automaticly changes the
  321. **    attachment if there was an old one...
  322. */
  323. int    attach_conf(cptr, aconf)
  324. aConfItem *aconf;
  325. aClient *cptr;
  326. {
  327.     Reg1 Link *lp;
  328.  
  329.     if (is_attached(aconf, cptr))
  330.         return 1;
  331.     if (IsIllegal(aconf))
  332.         return -1;
  333.     if ((aconf->status & (CONF_LOCOP | CONF_OPERATOR | CONF_CLIENT)) &&
  334.         aconf->clients >= ConfMaxLinks(aconf) && ConfMaxLinks(aconf) > 0)
  335.         return -3;    /* Use this for printing error message */
  336.     lp = make_link();
  337.     lp->next = cptr->confs;
  338.     lp->value.aconf = aconf;
  339.     cptr->confs = lp;
  340.     aconf->clients++;
  341.     if (aconf->status & CONF_CLIENT_MASK)
  342.         ConfLinks(aconf)++;
  343.     return 0;
  344. }
  345.  
  346.  
  347. aConfItem *find_admin()
  348.     {
  349.     Reg1 aConfItem *aconf;
  350.  
  351.     for (aconf = conf; aconf; aconf = aconf->next)
  352.         if (aconf->status & CONF_ADMIN)
  353.             break;
  354.     
  355.     return (aconf);
  356.     }
  357.  
  358. /* Find a DR_PASS line for the /DIE or /RESTART command
  359.  * Instead of returning the whole structure we return a
  360.  * char* which is the pass. 
  361.  * Added December 28 1997 -- NikB 
  362.  */
  363. char *find_diepass() 
  364.     {
  365.     Reg1 aConfItem *aconf;
  366.     
  367.     for (aconf = conf; aconf; aconf = aconf->next)
  368.         if (aconf->status & CONF_DRPASS)
  369.             return (aconf->host);
  370.             
  371.     return NULL;    /* Return NULL (We did not find any) */
  372.     }
  373.     
  374. char *find_restartpass() 
  375.     {
  376.     Reg1 aConfItem *aconf;
  377.     
  378.     for (aconf = conf; aconf; aconf = aconf->next)
  379.         if (aconf->status & CONF_DRPASS)
  380.             return (aconf->passwd);
  381.                 
  382.     return NULL;    /* Return NULL (We did not find any) */
  383.     }
  384.    
  385. aConfItem *find_me()
  386.     {
  387.     Reg1 aConfItem *aconf;
  388.     for (aconf = conf; aconf; aconf = aconf->next)
  389.         if (aconf->status & CONF_ME)
  390.             break;
  391.     
  392.     return (aconf);
  393.     }
  394.  
  395. /*
  396.  * attach_confs
  397.  *  Attach a CONF line to a client if the name passed matches that for
  398.  * the conf file (for non-C/N lines) or is an exact match (C/N lines
  399.  * only).  The difference in behaviour is to stop C:*::* and N:*::*.
  400.  */
  401. aConfItem *attach_confs(cptr, name, statmask)
  402. aClient    *cptr;
  403. char    *name;
  404. int    statmask;
  405. {
  406.     Reg1 aConfItem *tmp;
  407.     aConfItem *first = NULL;
  408.     int len = strlen(name);
  409.   
  410.     if (!name || len > HOSTLEN)
  411.         return NULL;
  412.     for (tmp = conf; tmp; tmp = tmp->next)
  413.         {
  414.         if ((tmp->status & statmask) && !IsIllegal(tmp) &&
  415.             ((tmp->status & (CONF_SERVER_MASK|CONF_HUB)) == 0) &&
  416.             tmp->name && !match(tmp->name, name))
  417.             {
  418.             if (!attach_conf(cptr, tmp) && !first)
  419.                 first = tmp;
  420.             }
  421.         else if ((tmp->status & statmask) && !IsIllegal(tmp) &&
  422.              (tmp->status & (CONF_SERVER_MASK|CONF_HUB)) &&
  423.              tmp->name && !mycmp(tmp->name, name))
  424.             {
  425.             if (!attach_conf(cptr, tmp) && !first)
  426.                 first = tmp;
  427.             }
  428.         }
  429.     return (first);
  430. }
  431.  
  432. /*
  433.  * Added for new access check    meLazy
  434.  */
  435. aConfItem *attach_confs_host(cptr, host, statmask)
  436. aClient *cptr;
  437. char    *host;
  438. int    statmask;
  439. {
  440.     Reg1    aConfItem *tmp;
  441.     aConfItem *first = NULL;
  442.     int    len = strlen(host);
  443.   
  444.     if (!host || len > HOSTLEN)
  445.         return NULL;
  446.  
  447.     for (tmp = conf; tmp; tmp = tmp->next)
  448.         {
  449.         if ((tmp->status & statmask) && !IsIllegal(tmp) &&
  450.             (tmp->status & CONF_SERVER_MASK) == 0 &&
  451.             (!tmp->host || match(tmp->host, host) == 0))
  452.             {
  453.             if (!attach_conf(cptr, tmp) && !first)
  454.                 first = tmp;
  455.             }
  456.         else if ((tmp->status & statmask) && !IsIllegal(tmp) &&
  457.                    (tmp->status & CONF_SERVER_MASK) &&
  458.                    (tmp->host && mycmp(tmp->host, host) == 0))
  459.             {
  460.             if (!attach_conf(cptr, tmp) && !first)
  461.                 first = tmp;
  462.             }
  463.         }
  464.     return (first);
  465. }
  466.  
  467. /*
  468.  * find a conf entry which matches the hostname and has the same name.
  469.  */
  470. aConfItem *find_conf_exact(name, user, host, statmask)
  471. char    *name, *host, *user;
  472. int    statmask;
  473. {
  474.     Reg1    aConfItem *tmp;
  475.     char    userhost[USERLEN+HOSTLEN+3];
  476.  
  477.     (void)sprintf(userhost, "%s@%s", user, host);
  478.  
  479.     for (tmp = conf; tmp; tmp = tmp->next)
  480.         {
  481.         if (!(tmp->status & statmask) || !tmp->name || !tmp->host ||
  482.             mycmp(tmp->name, name))
  483.             continue;
  484.         /*
  485.         ** Accept if the *real* hostname (usually sockecthost)
  486.         ** socket host) matches *either* host or name field
  487.         ** of the configuration.
  488.         */
  489.         if (match(tmp->host, userhost))
  490.             continue;
  491.         if (tmp->status & (CONF_OPERATOR|CONF_LOCOP))
  492.             {
  493.             if (tmp->clients < MaxLinks(Class(tmp)))
  494.                 return tmp;
  495.             else
  496.                 continue;
  497.             }
  498.         else
  499.             return tmp;
  500.         }
  501.     return NULL;
  502. }
  503.  
  504. aConfItem *find_conf_name(name, statmask)
  505. char    *name;
  506. int    statmask;
  507. {
  508.     Reg1    aConfItem *tmp;
  509.  
  510.     for (tmp = conf; tmp; tmp = tmp->next)
  511.         {
  512.         /*
  513.         ** Accept if the *real* hostname (usually sockecthost)
  514.         ** matches *either* host or name field of the configuration.
  515.         */
  516.         if ((tmp->status & statmask) &&
  517.             (!tmp->name || match(tmp->name, name) == 0))
  518.             return tmp;
  519.         }
  520.     return NULL;
  521. }
  522.  
  523. aConfItem *find_conf_servern(name)
  524. char    *name;
  525. {
  526.     Reg1    aConfItem *tmp;
  527.  
  528.     for (tmp = conf; tmp; tmp = tmp->next)
  529.         {
  530.         /*
  531.         ** Accept if the *real* hostname (usually sockecthost)
  532.         ** matches *either* host or name field of the configuration.
  533.         */
  534.         if ((tmp->status & CONF_NOCONNECT_SERVER) &&
  535.             (!tmp->name || match(tmp->name, name) == 0))
  536.             return tmp;
  537.         }
  538.     return NULL;
  539. }
  540.  
  541. aConfItem *find_conf(lp, name, statmask)
  542. char    *name;
  543. Link    *lp;
  544. int    statmask;
  545. {
  546.     Reg1    aConfItem *tmp;
  547.     int    namelen = name ? strlen(name) : 0;
  548.   
  549.     if (namelen > HOSTLEN)
  550.         return (aConfItem *) 0;
  551.  
  552.     for (; lp; lp = lp->next)
  553.         {
  554.         tmp = lp->value.aconf;
  555.         if ((tmp->status & statmask) &&
  556.             (((tmp->status & (CONF_SERVER_MASK|CONF_HUB)) &&
  557.               tmp->name && !mycmp(tmp->name, name)) ||
  558.              ((tmp->status & (CONF_SERVER_MASK|CONF_HUB)) == 0 &&
  559.              tmp->name && !match(tmp->name, name))))
  560.             return tmp;
  561.         }
  562.     return NULL;
  563. }
  564.  
  565. /*
  566.  * Added for new access check    meLazy
  567.  */
  568. aConfItem *find_conf_host(lp, host, statmask)
  569. Reg2    Link    *lp;
  570. char    *host;
  571. Reg3    int    statmask;
  572. {
  573.     Reg1    aConfItem *tmp;
  574.     int    hostlen = host ? strlen(host) : 0;
  575.   
  576.     if (hostlen > HOSTLEN || BadPtr(host))
  577.         return (aConfItem *)NULL;
  578.     for (; lp; lp = lp->next)
  579.         {
  580.         tmp = lp->value.aconf;
  581.         if (tmp->status & statmask &&
  582.             (!(tmp->status & CONF_SERVER_MASK || tmp->host) ||
  583.               (tmp->host && !match(tmp->host, host))))
  584.             return tmp;
  585.         }
  586.     return NULL;
  587. }
  588.  
  589. /*
  590.  * find_conf_ip
  591.  *
  592.  * Find a conf line using the IP# stored in it to search upon.
  593.  * Added 1/8/92 by Avalon.
  594.  */
  595. aConfItem *find_conf_ip(lp, ip, user, statmask)
  596. char    *ip, *user;
  597. Link    *lp;
  598. int    statmask;
  599. {
  600.     Reg1    aConfItem *tmp;
  601.     Reg2    char    *s;
  602.   
  603.     for (; lp; lp = lp->next)
  604.         {
  605.         tmp = lp->value.aconf;
  606.         if (!(tmp->status & statmask))
  607.             continue;
  608.         s = index(tmp->host, '@');
  609.         *s = '\0';
  610.         if (match(tmp->host, user))
  611.             {
  612.             *s = '@';
  613.             continue;
  614.             }
  615.         *s = '@';
  616.         if (!bcmp((char *)&tmp->ipnum, ip, sizeof(struct in_addr)))
  617.             return tmp;
  618.         }
  619.     return NULL;
  620. }
  621.  
  622. /*
  623.  * find_conf_entry
  624.  *
  625.  * - looks for a match on all given fields.
  626.  */
  627. aConfItem *find_conf_entry(aconf, mask)
  628. aConfItem *aconf;
  629. u_int    mask;
  630. {
  631.     Reg1    aConfItem *bconf;
  632.  
  633.     for (bconf = conf, mask &= ~CONF_ILLEGAL; bconf; bconf = bconf->next)
  634.         {
  635.         if (!(bconf->status & mask) || (bconf->port != aconf->port))
  636.             continue;
  637.  
  638.         if ((BadPtr(bconf->host) && !BadPtr(aconf->host)) ||
  639.             (BadPtr(aconf->host) && !BadPtr(bconf->host)))
  640.             continue;
  641.         if (!BadPtr(bconf->host) && mycmp(bconf->host, aconf->host))
  642.             continue;
  643.  
  644.         if ((BadPtr(bconf->passwd) && !BadPtr(aconf->passwd)) ||
  645.             (BadPtr(aconf->passwd) && !BadPtr(bconf->passwd)))
  646.             continue;
  647.         if (!BadPtr(bconf->passwd) &&
  648.             mycmp(bconf->passwd, aconf->passwd))
  649.             continue;
  650.  
  651.         if ((BadPtr(bconf->name) && !BadPtr(aconf->name)) ||
  652.             (BadPtr(aconf->name) && !BadPtr(bconf->name)))
  653.             continue;
  654.         if (!BadPtr(bconf->name) && mycmp(bconf->name, aconf->name))
  655.             continue;
  656.         break;
  657.         }
  658.     return bconf;
  659. }
  660.  
  661. /*
  662.  * find_temp_conf_entry
  663.  *
  664.  * - looks for a match on all given fields for a TEMP conf line.
  665.  *  Right now the passwd,port, and class fields are ignored, because it's
  666.  *  only useful for k:lines anyway.  -Russell   11/22/95
  667.  *  1/21/95 Now looks for any conf line.  I'm leaving this routine and its
  668.  *  call in because this routine has potential in future upgrades. -Russell
  669.  */
  670. aConfItem *find_temp_conf_entry(aconf, mask)
  671. aConfItem *aconf;
  672. u_int   mask;
  673. {
  674.         Reg1    aConfItem *bconf;
  675.  
  676.         for (bconf = conf, mask &= ~CONF_ILLEGAL; bconf; bconf = bconf->next)
  677.             {
  678.         /* kline/unkline/kline fix -- Barubary */
  679.         if (bconf->status & CONF_ILLEGAL) continue;
  680.                 if (!(bconf->status & mask) || (bconf->port != aconf->port))
  681.                         continue;
  682. /*                if (!bconf->tempconf) continue;*/
  683.                 if ((BadPtr(bconf->host) && !BadPtr(aconf->host)) ||
  684.                     (BadPtr(aconf->host) && !BadPtr(bconf->host)))
  685.                        continue;
  686.                 if (!BadPtr(bconf->host) && mycmp(bconf->host, aconf->host))
  687.                         continue;
  688.  
  689. /*                if ((BadPtr(bconf->passwd) && !BadPtr(aconf->passwd)) ||
  690.                     (BadPtr(aconf->passwd) && !BadPtr(bconf->passwd)))
  691.                         continue;
  692.                 if (!BadPtr(bconf->passwd) &&
  693.                     mycmp(bconf->passwd, aconf->passwd))
  694.                         continue;*/
  695.  
  696.                 if ((BadPtr(bconf->name) && !BadPtr(aconf->name)) ||
  697.                     (BadPtr(aconf->name) && !BadPtr(bconf->name)))
  698.             continue;
  699.                 if (!BadPtr(bconf->name) && mycmp(bconf->name, aconf->name))
  700.                         continue;
  701.                 break;
  702.             }
  703.         return bconf;
  704. }
  705.  
  706. aSqlineItem *find_sqline_nick(nickmask)
  707. char *nickmask;
  708. {
  709.     Reg1     aSqlineItem *asqline;
  710.  
  711.     for(asqline = sqline; asqline; asqline = asqline->next) {
  712.         if(!BadPtr(asqline->sqline) && (asqline->status !=
  713.             CONF_ILLEGAL) && !mycmp(asqline->sqline, nickmask))
  714.         return asqline;
  715.     }
  716.     return NULL;
  717. }
  718.  
  719. aSqlineItem *find_sqline_match(nickname)
  720. char *nickname;
  721. {
  722.         Reg1    aSqlineItem *asqline;
  723.  
  724.     for(asqline = sqline; asqline; asqline = asqline->next) {
  725.         if(!BadPtr(asqline->sqline) && (asqline->status != 
  726.             CONF_ILLEGAL) && !match(asqline->sqline,nickname))
  727.             return asqline;
  728.     }
  729.     return NULL;
  730. }
  731.  
  732. /*
  733. **      parv[0] = sender prefix
  734. **      parv[1] = server
  735. **      parv[2] = +/-
  736. **
  737. */
  738. int     m_svsnoop(cptr, sptr, parc, parv)
  739. aClient *cptr, *sptr;
  740. int     parc;
  741. char    *parv[];
  742.     {
  743.     Reg1    aConfItem *aconf;
  744.  
  745.         if (!(check_registered(sptr) && IsULine(cptr, sptr) && parc > 2))
  746.                 return 0;
  747.  
  748.     if (!hunt_server(cptr, sptr, ":%s SVSNOOP %s :%s", 1, parc, parv) != HUNTED_ISME) {
  749.         if (parv[2][0] == '+')
  750.             for(aconf=conf;aconf;aconf=aconf->next) {
  751.                if (aconf->status & CONF_OPERATOR || aconf->status & CONF_LOCOP)
  752.                     aconf->status = CONF_ILLEGAL;
  753.             }
  754.         else
  755.             (void)rehash(&me, &me, 2);
  756.     }    
  757. }
  758.  
  759. /*
  760.  * rehash
  761.  *
  762.  * Actual REHASH service routine. Called with sig == 0 if it has been called
  763.  * as a result of an operator issuing this command, else assume it has been
  764.  * called as a result of the server receiving a HUP signal.
  765.  */
  766. int    rehash(cptr, sptr, sig)
  767. aClient    *cptr, *sptr;
  768. int    sig;
  769. {
  770.     Reg1    aConfItem **tmp = &conf, *tmp2;
  771.     Reg2    aClass    *cltmp;
  772.     Reg1    aClient    *acptr;
  773.     Reg2    int    i;
  774.       int    ret = 0;
  775.  
  776.     if (sig == 1)
  777.         {
  778.         sendto_ops("Got signal SIGHUP, reloading ircd conf. file");
  779. #ifdef    ULTRIX
  780.         if (fork() > 0)
  781.             exit(0);
  782.         write_pidfile();
  783. #endif
  784.         }
  785.  
  786.     for (i = 0; i <= highest_fd; i++)
  787.         if ((acptr = local[i]) && !IsMe(acptr))
  788.             {
  789.             /*
  790.              * Nullify any references from client structures to
  791.              * this host structure which is about to be freed.
  792.              * Could always keep reference counts instead of
  793.              * this....-avalon
  794.              */
  795.             acptr->hostp = NULL;
  796. #if defined(R_LINES_REHASH) && !defined(R_LINES_OFTEN)
  797.             if (find_restrict(acptr))
  798.                 {
  799.                 sendto_ops("Restricting %s, closing lp",
  800.                        get_client_name(acptr,FALSE));
  801.                 if (exit_client(cptr,acptr,sptr,"R-lined") ==
  802.                     FLUSH_BUFFER)
  803.                     ret = FLUSH_BUFFER;
  804.                 }
  805. #endif
  806.             }
  807.  
  808.     while ((tmp2 = *tmp))
  809.         if (tmp2->clients || tmp2->status & CONF_LISTEN_PORT)
  810.             {
  811.             /*
  812.             ** Configuration entry is still in use by some
  813.             ** local clients, cannot delete it--mark it so
  814.             ** that it will be deleted when the last client
  815.             ** exits...
  816.             */
  817.             if (!(tmp2->status & (CONF_LISTEN_PORT|CONF_CLIENT)))
  818.                 {
  819.                 *tmp = tmp2->next;
  820.                 tmp2->next = NULL;
  821.                 }
  822.             else
  823.                 tmp = &tmp2->next;
  824.             tmp2->status |= CONF_ILLEGAL;
  825.             }
  826.         else
  827.             {
  828.             *tmp = tmp2->next;
  829.             /* free expression trees of connect rules */
  830.             if ((tmp2->status & (CONF_CRULEALL|CONF_CRULEAUTO))
  831.                 && (tmp2->passwd != NULL))
  832.               crule_free (&(tmp2->passwd));
  833.             free_conf(tmp2);
  834.                 }
  835.  
  836.     /*
  837.      * We don't delete the class table, rather mark all entries
  838.      * for deletion. The table is cleaned up by check_class. - avalon
  839.      */
  840.     for (cltmp = NextClass(FirstClass()); cltmp; cltmp = NextClass(cltmp))
  841.         MaxLinks(cltmp) = -1;
  842.  
  843.     if (sig != 2)
  844.         flush_cache();
  845.     (void) initconf(0);
  846.     close_listeners();
  847.  
  848.     /*
  849.      * flush out deleted I and P lines although still in use.
  850.      */
  851.     for (tmp = &conf; (tmp2 = *tmp); )
  852.         if (!(tmp2->status & CONF_ILLEGAL))
  853.             tmp = &tmp2->next;
  854.         else
  855.             {
  856.             *tmp = tmp2->next;
  857.             tmp2->next = NULL;
  858.             if (!tmp2->clients)
  859.                 free_conf(tmp2);
  860.             }
  861.     /* Added to make sure K-lines are checked -- Barubary */
  862.     check_pings(time(NULL), 1);
  863.  
  864.     /* Recheck all U-lines -- Barubary */
  865.     for (i = 0; i < highest_fd; i++)
  866.         if ((acptr = local[i]) && !IsMe(acptr))
  867.         {
  868.             if (find_conf_host(acptr->from->confs, acptr->name,
  869.                 CONF_UWORLD) || (acptr->user && find_conf_host(
  870.                 acptr->from->confs, acptr->user->server,
  871.                 CONF_UWORLD)))
  872.                 acptr->flags |= FLAGS_ULINE;
  873.             else
  874.                 acptr->flags &= ~FLAGS_ULINE;
  875.         }
  876.  
  877.     reset_help(); /* Reinitialize help-system. -Donwulff */
  878.  
  879.     return ret;
  880. }
  881.  
  882. /*
  883.  * openconf
  884.  *
  885.  * returns -1 on any error or else the fd opened from which to read the
  886.  * configuration file from.  This may either be th4 file direct or one end
  887.  * of a pipe from m4.
  888.  */
  889. int    openconf()
  890. {
  891. #ifdef    M4_PREPROC
  892.     int    pi[2], i;
  893.  
  894.     if (pipe(pi) == -1)
  895.         return -1;
  896.     switch(fork())
  897.     {
  898.     case -1 :
  899.         return -1;
  900.     case 0 :
  901.         (void)close(pi[0]);
  902.         if (pi[1] != 1)
  903.             {
  904.             (void)dup2(pi[1], 1);
  905.             (void)close(pi[1]);
  906.             }
  907.         (void)dup2(1,2);
  908.         for (i = 3; i < MAXCONNECTIONS; i++)
  909.             if (local[i])
  910.                 (void) close(i);
  911.         /*
  912.          * m4 maybe anywhere, use execvp to find it.  Any error
  913.          * goes out with report_error.  Could be dangerous,
  914.          * two servers running with the same fd's >:-) -avalon
  915.          */
  916.         (void)execlp("m4", "m4", "ircd.m4", configfile, 0);
  917.         report_error("Error executing m4 %s:%s", &me);
  918.         exit(-1);
  919.     default :
  920.         (void)close(pi[1]);
  921.         return pi[0];
  922.     }
  923. #else
  924.     return open(configfile, O_RDONLY);
  925. #endif
  926. }
  927. extern char *getfield();
  928.  
  929. static int oper_access[] = {
  930.     ~(OFLAG_ADMIN|OFLAG_SADMIN|OFLAG_ZLINE),    '*',
  931.     OFLAG_LOCAL,    'o',
  932.     OFLAG_GLOBAL,    'O',
  933.     OFLAG_REHASH,    'r',
  934.     OFLAG_DIE,    'D',
  935.     OFLAG_RESTART,    'R',
  936.     OFLAG_HELPOP,    'h',
  937.     OFLAG_GLOBOP,    'g',
  938.     OFLAG_WALLOP,    'w',
  939.     OFLAG_LOCOP,    'l',
  940.     OFLAG_LROUTE,    'c',
  941.     OFLAG_GROUTE,    'C',
  942.     OFLAG_LKILL,    'k',
  943.     OFLAG_GKILL,    'K',
  944.     OFLAG_KLINE,    'b',
  945.     OFLAG_UNKLINE,    'B',
  946.     OFLAG_LNOTICE,    'n',
  947.     OFLAG_GNOTICE,    'N',
  948.     OFLAG_ADMIN,    'A',
  949.     OFLAG_SADMIN,    'a',
  950.     OFLAG_UMODEC,    'u',
  951.     OFLAG_UMODEF,    'f',
  952.     OFLAG_ZLINE,    'z',
  953.     0, 0 };
  954.  
  955. /*
  956. ** initconf() 
  957. **    Read configuration file.
  958. **
  959. **    returns -1, if file cannot be opened
  960. **             0, if file opened
  961. */
  962.  
  963. #define MAXCONFLINKS 150
  964.  
  965. int     initconf(opt)
  966. int    opt;
  967. {
  968.     static    char    quotes[9][2] = {{'b', '\b'}, {'f', '\f'}, {'n', '\n'},
  969.                     {'r', '\r'}, {'t', '\t'}, {'v', '\v'},
  970.                     {'\\', '\\'}, { 0, 0}};
  971.     Reg1    char    *tmp, *s;
  972.     int    fd, i;
  973.     char    line[512], c[80];
  974.     int    ccount = 0, ncount = 0;
  975.     aConfItem *aconf = NULL;
  976.  
  977.     Debug((DEBUG_DEBUG, "initconf(): ircd.conf = %s", configfile));
  978.     if ((fd = openconf()) == -1)
  979.         {
  980. #ifdef    M4_PREPROC
  981.         (void)wait(0);
  982. #endif
  983.         return -1;
  984.         }
  985.     (void)dgets(-1, NULL, 0); /* make sure buffer is at empty pos */
  986.     while ((i = dgets(fd, line, sizeof(line) - 1)) > 0)
  987.         {
  988.         line[i] = '\0';
  989.         if ((tmp = (char *)index(line, '\n')))
  990.             *tmp = 0;
  991.         else while(dgets(fd, c, sizeof(c) - 1) > 0)
  992.             if ((tmp = (char *)index(c, '\n')))
  993.                 {
  994.                 *tmp = 0;
  995.                 break;
  996.                 }
  997.         /*
  998.          * Do quoting of characters and # detection.
  999.          */
  1000.         for (tmp = line; *tmp; tmp++)
  1001.             {
  1002.             if (*tmp == '\\')
  1003.                 {
  1004.                 for (i = 0; quotes[i][0]; i++)
  1005.                     if (quotes[i][0] == *(tmp+1))
  1006.                         {
  1007.                         *tmp = quotes[i][1];
  1008.                         break;
  1009.                         }
  1010.                 if (!quotes[i][0])
  1011.                     *tmp = *(tmp+1);
  1012.                 if (!*(tmp+1))
  1013.                     break;
  1014.                 else
  1015.                     for (s = tmp; *s = *(s+1); s++)
  1016.                         ;
  1017.                 }
  1018.             else if (*tmp == '#')
  1019.                 *tmp = '\0';
  1020.             }
  1021.         if (!*line || line[0] == '#' || line[0] == '\n' ||
  1022.             line[0] == ' ' || line[0] == '\t')
  1023.             continue;
  1024.         /* Could we test if it's conf line at all?    -Vesa */
  1025.         if (line[1] != ':')
  1026.             {
  1027.                         Debug((DEBUG_ERROR, "Bad config line: %s", line));
  1028.                         continue;
  1029.                     }
  1030.         if (aconf)
  1031.             free_conf(aconf);
  1032.         aconf = make_conf();
  1033.  
  1034.         tmp = getfield(line);
  1035.         if (!tmp)
  1036.             continue;
  1037.         switch (*tmp)
  1038.         {
  1039.             case 'A': /* Name, e-mail address of administrator */
  1040.                 aconf->status = CONF_ADMIN;
  1041.                 break;
  1042.             case 'a': /* of this server. */
  1043.                 aconf->status = CONF_SADMIN;
  1044.                 break;
  1045.             case 'C': /* Server where I should try to connect */
  1046.             case 'c': /* in case of lp failures             */
  1047.                 ccount++;
  1048.                 aconf->status = CONF_CONNECT_SERVER;
  1049.                 break;
  1050.             /* Connect rule */
  1051.             case 'D':
  1052.                 aconf->status = CONF_CRULEALL;
  1053.                 break;
  1054.             /* Connect rule - autos only */
  1055.             case 'd':
  1056.                 aconf->status = CONF_CRULEAUTO;
  1057.                 break;
  1058.                 case 'G':
  1059.             case 'g':
  1060.               /* General config options */
  1061.               aconf->status = CONF_CONFIG;
  1062.               break;
  1063.                 case 'H': /* Hub server line */
  1064.             case 'h':
  1065.                 aconf->status = CONF_HUB;
  1066.                 break;
  1067.             case 'I': /* Just plain normal irc client trying  */
  1068.             case 'i': /* to connect me */
  1069.                 aconf->status = CONF_CLIENT;
  1070.                 break;
  1071.             case 'K': /* Kill user line on irc.conf           */
  1072.             case 'k':
  1073.                 aconf->status = CONF_KILL;
  1074.                 break;
  1075.             /* Operator. Line should contain at least */
  1076.             /* password and host where connection is  */
  1077.             case 'L': /* guaranteed leaf server */
  1078.             case 'l':
  1079.                 aconf->status = CONF_LEAF;
  1080.                 break;
  1081.             /* Me. Host field is name used for this host */
  1082.             /* and port number is the number of the port */
  1083.             case 'M':
  1084.             case 'm':
  1085.                 aconf->status = CONF_ME;
  1086.                 break;
  1087.             case 'N': /* Server where I should NOT try to     */
  1088.             case 'n': /* connect in case of lp failures     */
  1089.                   /* but which tries to connect ME        */
  1090.                 ++ncount;
  1091.                 aconf->status = CONF_NOCONNECT_SERVER;
  1092.                 break;
  1093.             case 'O':
  1094.                 aconf->status = CONF_OPERATOR;
  1095.                 break;
  1096.             /* Local Operator, (limited privs --SRB)
  1097.              * Not anymore, OperFlag access levels. -Cabal95 */
  1098.             case 'o':
  1099.                 aconf->status = CONF_OPERATOR;
  1100.                 break;
  1101.             case 'P': /* listen port line */
  1102.             case 'p':
  1103.                 aconf->status = CONF_LISTEN_PORT;
  1104.                 break;
  1105.             case 'Q': /* reserved nicks */
  1106.                 aconf->status = CONF_QUARANTINED_NICK;
  1107.                 break;
  1108.             case 'q': /* a server that you don't want in your */
  1109.                   /* network. USE WITH CAUTION! */
  1110.                 aconf->status = CONF_QUARANTINED_SERVER;
  1111.                 break;
  1112. #ifdef R_LINES
  1113.             case 'R': /* extended K line */
  1114.             case 'r': /* Offers more options of how to restrict */
  1115.                 aconf->status = CONF_RESTRICT;
  1116.                 break;
  1117. #endif
  1118.             case 'S': /* Service. Same semantics as   */
  1119.             case 's': /* CONF_OPERATOR                */
  1120.                 aconf->status = CONF_SERVICE;
  1121.                 break;
  1122.             case 'U': /* Underworld server, allowed to hack modes */
  1123.             case 'u': /* *Every* server on the net must define the same !!! */
  1124.                 aconf->status = CONF_UWORLD;
  1125.                 break;
  1126.             case 'Y':
  1127.             case 'y':
  1128.                     aconf->status = CONF_CLASS;
  1129.                     break;
  1130.             case 'Z':
  1131.             case 'z':
  1132.                 aconf->status = CONF_ZAP;
  1133.                 break;
  1134.             case 'X':
  1135.             case 'x':
  1136.                 aconf->status = CONF_DRPASS;
  1137.                 break;
  1138.             default:
  1139.             Debug((DEBUG_ERROR, "Error in config file: %s", line));
  1140.             break;
  1141.             }
  1142.         if (IsIllegal(aconf))
  1143.             continue;
  1144.  
  1145.         for (;;) /* Fake loop, that I can use break here --msa */
  1146.             {
  1147.             /* Yes I know this could be much cleaner, but I did not
  1148.              * want to put it into its own separate function, but  
  1149.              * I believe the X:should be like this:
  1150.              * X:restartpass:diepass
  1151.              * which leaves this code untouched. This is already indented
  1152.              * enough to justify that...
  1153.              */
  1154.             if ((tmp = getfield(NULL)) == NULL)
  1155.                 break;
  1156.             DupString(aconf->host, tmp);
  1157.             if ((tmp = getfield(NULL)) == NULL)
  1158.                 break;
  1159.             DupString(aconf->passwd, tmp);
  1160.             if ((tmp = getfield(NULL)) == NULL)
  1161.                 break;
  1162.             DupString(aconf->name, tmp);
  1163.             if ((tmp = getfield(NULL)) == NULL)
  1164.                 break;
  1165.             if (aconf->status & CONF_OPS) {
  1166.               int   *i, flag;
  1167.               char  *m = "*";
  1168.               /*
  1169.                * Now we use access flags to define
  1170.                * what an operator can do with their O.
  1171.                */
  1172.               for (m = (*tmp) ? tmp : m; *m; m++) {
  1173.                 for (i = oper_access; (flag = *i); i += 2)
  1174.                   if (*m == (char)(*(i+1))) {
  1175.                 aconf->port |= flag;
  1176.                 break;
  1177.                   }
  1178.               }
  1179.               if (!(aconf->port&OFLAG_ISGLOBAL))
  1180.                 aconf->status = CONF_LOCOP;
  1181.             }
  1182.             else
  1183.                 aconf->port = atoi(tmp);
  1184.             if ((tmp = getfield(NULL)) == NULL)
  1185.                 break;
  1186.             Class(aconf) = find_class(atoi(tmp));
  1187.             break;
  1188.             }
  1189.         /*
  1190.         ** If conf line is a general config, just
  1191.         ** see if we recognize the keyword, and set
  1192.         ** the appropriate global.  We don't use a "standard"
  1193.         ** config link here, because these are things which need
  1194.         ** to be tested SO often that a simple global test
  1195.         ** is much better!  -Aeto
  1196.         */
  1197.         if ((aconf->status & CONF_CONFIG) == CONF_CONFIG) {
  1198. #ifdef USE_CASETABLES
  1199.           if (mycmp(aconf->host,"casetable") == 0) {
  1200.             if (atoi(aconf->passwd) == 1)
  1201.                     {
  1202.                        casetable = 1;
  1203.                       touppertab = touppertab2;
  1204.                       tolowertab = tolowertab2;
  1205.                     }
  1206.             else if (casetable == 1)
  1207.               sendto_ops ("WARNING -- rehash tried to reduce casetable value, which is illegal.  Restart to reduce it.");
  1208.  
  1209.           }
  1210. #endif
  1211.           continue;
  1212.         }
  1213.  
  1214.         /* Check for bad Z-lines masks as they are *very* dangerous
  1215.            if not correct!!! */
  1216.         if (aconf->status == CONF_ZAP)
  1217.         {
  1218.             char *tempc = aconf->host;
  1219.             if (!tempc)
  1220.             {
  1221.                 free_conf(aconf);
  1222.                 aconf = NULL;
  1223.                 continue;
  1224.             }
  1225.             for (; *tempc; tempc++)
  1226.                 if ((*tempc >= '0') && (*tempc <= '9'))
  1227.                     goto zap_safe;
  1228.             free_conf(aconf);
  1229.             aconf = NULL;
  1230.             continue;
  1231.             zap_safe:;
  1232.         }
  1233.         /*
  1234.                 ** If conf line is a class definition, create a class entry
  1235.                 ** for it and make the conf_line illegal and delete it.
  1236.                 */
  1237.         if (aconf->status & CONF_CLASS)
  1238.             {
  1239.             add_class(atoi(aconf->host), atoi(aconf->passwd),
  1240.                   atoi(aconf->name), aconf->port,
  1241.                   tmp ? atoi(tmp) : 0);
  1242.             continue;
  1243.             }
  1244.         /*
  1245.                 ** associate each conf line with a class by using a pointer
  1246.                 ** to the correct class record. -avalon
  1247.                 */
  1248.         if (aconf->status & (CONF_CLIENT_MASK|CONF_LISTEN_PORT))
  1249.             {
  1250.             if (Class(aconf) == 0)
  1251.                 Class(aconf) = find_class(0);
  1252.             if (MaxLinks(Class(aconf)) < 0)
  1253.                 Class(aconf) = find_class(0);
  1254.             }
  1255.         if (aconf->status & (CONF_LISTEN_PORT|CONF_CLIENT))
  1256.             {
  1257.             aConfItem *bconf;
  1258.  
  1259.             if (bconf = find_conf_entry(aconf, aconf->status))
  1260.                 {
  1261.                 delist_conf(bconf);
  1262.                 bconf->status &= ~CONF_ILLEGAL;
  1263.                 if (aconf->status == CONF_CLIENT)
  1264.                     {
  1265.                     bconf->class->links -= bconf->clients;
  1266.                     bconf->class = aconf->class;
  1267.                                         if (bconf->class)
  1268.                      bconf->class->links += bconf->clients;
  1269.                     }
  1270.                 free_conf(aconf);
  1271.                 aconf = bconf;
  1272.                 }
  1273.             else if (aconf->host &&
  1274.                  aconf->status == CONF_LISTEN_PORT)
  1275.                 (void)add_listener(aconf);
  1276.             }
  1277.         if (aconf->status & CONF_SERVER_MASK)
  1278.             if (ncount > MAXCONFLINKS || ccount > MAXCONFLINKS ||
  1279.                 !aconf->host || index(aconf->host, '*') ||
  1280.                  index(aconf->host,'?') || !aconf->name)
  1281.                 continue;
  1282.  
  1283.         if (aconf->status &
  1284.             (CONF_SERVER_MASK|CONF_LOCOP|CONF_OPERATOR))
  1285.             if (!index(aconf->host, '@') && *aconf->host != '/')
  1286.                 {
  1287.                 char    *newhost;
  1288.                 int    len = 3;    /* *@\0 = 3 */
  1289.  
  1290.                 len += strlen(aconf->host);
  1291.                 newhost = (char *)MyMalloc(len);
  1292.                 (void)sprintf(newhost, "*@%s", aconf->host);
  1293.                 MyFree(aconf->host);
  1294.                 aconf->host = newhost;
  1295.                 }
  1296.         if (aconf->status & CONF_SERVER_MASK)
  1297.             {
  1298.             if (BadPtr(aconf->passwd))
  1299.                 continue;
  1300.             else if (!(opt & BOOT_QUICK))
  1301.                 (void)lookup_confhost(aconf);
  1302.             }
  1303.  
  1304.                 /* Create expression tree from connect rule...
  1305.                 ** If there's a parsing error, nuke the conf structure */
  1306.                 if (aconf->status & (CONF_CRULEALL | CONF_CRULEAUTO))
  1307.           {
  1308.             MyFree (aconf->passwd);
  1309.             if ((aconf->passwd =
  1310.              (char *) crule_parse (aconf->name)) == NULL)
  1311.               {
  1312.             free_conf (aconf);
  1313.             aconf = NULL;
  1314.             continue;
  1315.               }
  1316.           }
  1317.  
  1318.         /*
  1319.         ** Own port and name cannot be changed after the startup.
  1320.         ** (or could be allowed, but only if all links are closed
  1321.         ** first).
  1322.         ** Configuration info does not override the name and port
  1323.         ** if previously defined. Note, that "info"-field can be
  1324.         ** changed by "/rehash".
  1325.         */
  1326.         if (aconf->status == CONF_ME)
  1327.             {
  1328.             strncpyzt(me.info, aconf->name, sizeof(me.info));
  1329.             if (me.name[0] == '\0' && aconf->host[0])
  1330.                 strncpyzt(me.name, aconf->host,
  1331.                       sizeof(me.name));
  1332.             if (aconf->passwd[0] && (aconf->passwd[0] != '*'))
  1333.                 me.ip.s_addr = inet_addr(aconf->passwd);
  1334.             else
  1335.                 me.ip.s_addr = INADDR_ANY;
  1336.             if (portnum < 0 && aconf->port >= 0)
  1337.                 portnum = aconf->port;
  1338.             }
  1339.         if (aconf->status == CONF_KILL)
  1340.             aconf->tmpconf = KLINE_PERM;
  1341.         (void)collapse(aconf->host);
  1342.         (void)collapse(aconf->name);
  1343.         Debug((DEBUG_NOTICE,
  1344.               "Read Init: (%d) (%s) (%s) (%s) (%d) (%d)",
  1345.               aconf->status, aconf->host, aconf->passwd,
  1346.               aconf->name, aconf->port, Class(aconf)));
  1347.         aconf->next = conf;
  1348.         conf = aconf;
  1349.         aconf = NULL;
  1350.         }
  1351.     if (aconf)
  1352.         free_conf(aconf);
  1353.     (void)dgets(-1, NULL, 0); /* make sure buffer is at empty pos */
  1354.     (void)close(fd);
  1355. #ifdef    M4_PREPROC
  1356.     (void)wait(0);
  1357. #endif
  1358.     check_class();
  1359.     nextping = nextconnect = time(NULL);
  1360.     return 0;
  1361.     }
  1362.  
  1363. /*
  1364.  * lookup_confhost
  1365.  *   Do (start) DNS lookups of all hostnames in the conf line and convert
  1366.  * an IP addresses in a.b.c.d number for to IP#s.
  1367.  */
  1368. static    int    lookup_confhost(aconf)
  1369. Reg1    aConfItem    *aconf;
  1370. {
  1371.     Reg2    char    *s;
  1372.     Reg3    struct    hostent *hp;
  1373.     Link    ln;
  1374.  
  1375.     if (BadPtr(aconf->host) || BadPtr(aconf->name))
  1376.         goto badlookup;
  1377.     if ((s = index(aconf->host, '@')))
  1378.         s++;
  1379.     else
  1380.         s = aconf->host;
  1381.     /*
  1382.     ** Do name lookup now on hostnames given and store the
  1383.     ** ip numbers in conf structure.
  1384.     */
  1385.     if (!isalpha(*s) && !isdigit(*s))
  1386.         goto badlookup;
  1387.  
  1388.     /*
  1389.     ** Prepare structure in case we have to wait for a
  1390.     ** reply which we get later and store away.
  1391.     */
  1392.     ln.value.aconf = aconf;
  1393.     ln.flags = ASYNC_CONF;
  1394.  
  1395.     if (isdigit(*s))
  1396.         aconf->ipnum.s_addr = inet_addr(s);
  1397.     else if ((hp = gethost_byname(s, &ln)))
  1398.         bcopy(hp->h_addr, (char *)&(aconf->ipnum),
  1399.             sizeof(struct in_addr));
  1400.  
  1401.     if (aconf->ipnum.s_addr == -1)
  1402.         goto badlookup;
  1403.     return 0;
  1404. badlookup:
  1405.     if (aconf->ipnum.s_addr == -1)
  1406.         bzero((char *)&aconf->ipnum, sizeof(struct in_addr));
  1407.     Debug((DEBUG_ERROR,"Host/server name error: (%s) (%s)",
  1408.         aconf->host, aconf->name));
  1409.     return -1;
  1410. }
  1411.  
  1412. int    find_kill(cptr)
  1413. aClient    *cptr;
  1414. {
  1415.     char    reply[256], *host, *name;
  1416.     aConfItem *tmp;
  1417.  
  1418.     if (!cptr->user)
  1419.         return 0;
  1420.  
  1421.     host = cptr->sockhost;
  1422.     name = cptr->user->username;
  1423.  
  1424.     if (strlen(host)  > (size_t) HOSTLEN ||
  1425.             (name ? strlen(name) : 0) > (size_t) HOSTLEN)
  1426.         return (0);
  1427.  
  1428.     reply[0] = '\0';
  1429.  
  1430.     for (tmp = conf; tmp; tmp = tmp->next)
  1431.          if ((tmp->status == CONF_KILL) && tmp->host && tmp->name &&
  1432.             (match(tmp->host, host) == 0) &&
  1433.              (!name || match(tmp->name, name) == 0) &&
  1434.             (!tmp->port || (tmp->port == cptr->acpt->port)))
  1435.                        /* can short-circuit evaluation - not taking chances
  1436.                            cos check_time_interval destroys tmp->passwd
  1437.                                                                 - Mmmm
  1438.                          */
  1439.                         if (BadPtr(tmp->passwd))
  1440.                                 break;
  1441.                         else if (is_comment(tmp->passwd))
  1442.                                 break;
  1443.                         else if (check_time_interval(tmp->passwd, reply))
  1444.                                 break;
  1445.  
  1446.  
  1447.     if (reply[0])
  1448.         sendto_one(cptr, reply,
  1449.                me.name, ERR_YOUREBANNEDCREEP, cptr->name);
  1450.     else if (tmp)
  1451.             if (BadPtr(tmp->passwd))
  1452.         sendto_one(cptr,
  1453.                ":%s %d %s :*** You are not welcome on this server."
  1454.                "  Email " KLINE_ADDRESS " for more information.",
  1455.                me.name, ERR_YOUREBANNEDCREEP, cptr->name);
  1456.              else
  1457. #ifdef COMMENT_IS_FILE
  1458.                    m_killcomment(cptr,cptr->name, tmp->passwd);
  1459. #else
  1460.          {
  1461.           if (tmp->tmpconf == KLINE_AKILL)
  1462.               sendto_one(cptr,
  1463.                          ":%s %d %s :*** %s",
  1464.                          me.name, ERR_YOUREBANNEDCREEP, cptr->name,
  1465.                          tmp->passwd);
  1466.           else
  1467.               sendto_one(cptr,
  1468.                          ":%s %d %s :*** You are not welcome on this server: "
  1469.              "%s.  Email " KLINE_ADDRESS " for more information.",
  1470.                          me.name, ERR_YOUREBANNEDCREEP, cptr->name,
  1471.                          tmp->passwd);
  1472.          }
  1473. #endif  /* COMMENT_IS_FILE */
  1474.  
  1475.      return (tmp ? -1 : 0);
  1476. }
  1477.  
  1478. char *find_zap(aClient *cptr, int dokillmsg)  
  1479. {
  1480.     aConfItem *tmp;
  1481.     char *retval = NULL;
  1482.     for (tmp = conf; tmp; tmp = tmp->next)
  1483.         if ((tmp->status == CONF_ZAP) && tmp->host &&
  1484.             !match(tmp->host, inetntoa((char *) &cptr->ip)))
  1485.             {
  1486.                 retval = (tmp->passwd) ? tmp->passwd :
  1487.                     "Reason unspecified";
  1488.                 break;
  1489.             }
  1490.     if (dokillmsg && retval)
  1491.         sendto_one(cptr,
  1492.             ":%s %d %s :*** You are not welcome on this server: "
  1493.             "%s.  Email " KLINE_ADDRESS " for more information.",
  1494.             me.name, ERR_YOUREBANNEDCREEP, cptr->name,
  1495.             retval);
  1496.     if (!dokillmsg && retval)
  1497.     {
  1498.         sprintf(zlinebuf,
  1499.             "ERROR :Closing Link: [%s] (You are not welcome on "
  1500.             "this server: %s.  Email " KLINE_ADDRESS " for more"
  1501.             " information.)\r\n", inetntoa((char *) &cptr->ip),
  1502.             retval);
  1503.         retval = zlinebuf;
  1504.     }
  1505.     return retval;
  1506. }
  1507.  
  1508. int    find_kill_byname(host, name)
  1509. char *host, *name;
  1510. {
  1511.     aConfItem *tmp;
  1512.  
  1513.     for (tmp = conf; tmp; tmp = tmp->next) {
  1514.          if ((tmp->status == CONF_KILL) && tmp->host && tmp->name &&
  1515.             (match(tmp->host, host) == 0) &&
  1516.              (!name || match(tmp->name, name) == 0))
  1517.         return 1;
  1518.     }
  1519.  
  1520.      return 0;
  1521.  }
  1522.  
  1523. #ifdef R_LINES
  1524. /* find_restrict works against host/name and calls an outside program 
  1525.  * to determine whether a client is allowed to connect.  This allows 
  1526.  * more freedom to determine who is legal and who isn't, for example
  1527.  * machine load considerations.  The outside program is expected to 
  1528.  * return a reply line where the first word is either 'Y' or 'N' meaning 
  1529.  * "Yes Let them in" or "No don't let them in."  If the first word 
  1530.  * begins with neither 'Y' or 'N' the default is to let the person on.
  1531.  * It returns a value of 0 if the user is to be let through -Hoppie
  1532.  */
  1533. int    find_restrict(cptr)
  1534. aClient    *cptr;
  1535. {
  1536.     aConfItem *tmp;
  1537.     char    reply[80], temprpl[80];
  1538.     char    *rplhold = reply, *host, *name, *s;
  1539.     char    rplchar = 'Y';
  1540.     int    pi[2], rc = 0, n;
  1541.  
  1542.     if (!cptr->user)
  1543.         return 0;
  1544.     name = cptr->user->username;
  1545.     host = cptr->sockhost;
  1546.     Debug((DEBUG_INFO, "R-line check for %s[%s]", name, host));
  1547.  
  1548.     for (tmp = conf; tmp; tmp = tmp->next)
  1549.         {
  1550.         if (tmp->status != CONF_RESTRICT ||
  1551.             (tmp->host && host && match(tmp->host, host)) ||
  1552.             (tmp->name && name && match(tmp->name, name)))
  1553.             continue;
  1554.  
  1555.         if (BadPtr(tmp->passwd))
  1556.             {
  1557.             sendto_ops("Program missing on R-line %s/%s, ignoring",
  1558.                    name, host);
  1559.             continue;
  1560.             }
  1561.  
  1562.         if (pipe(pi) == -1)
  1563.             {
  1564.             report_error("Error creating pipe for R-line %s:%s",
  1565.                      &me);
  1566.             return 0;
  1567.             }
  1568.         switch (rc = fork())
  1569.         {
  1570.         case -1 :
  1571.             report_error("Error forking for R-line %s:%s", &me);
  1572.             return 0;
  1573.         case 0 :
  1574.             {
  1575.             Reg1    int    i;
  1576.  
  1577.             (void)close(pi[0]);
  1578.             for (i = 2; i < MAXCONNECTIONS; i++)
  1579.                 if (i != pi[1])
  1580.                     (void)close(i);
  1581.             if (pi[1] != 2)
  1582.                 (void)dup2(pi[1], 2);
  1583.             (void)dup2(2, 1);
  1584.             if (pi[1] != 2 && pi[1] != 1)
  1585.                 (void)close(pi[1]);
  1586.             (void)execlp(tmp->passwd, tmp->passwd, name, host, 0);
  1587.             exit(-1);
  1588.             }
  1589.         default :
  1590.             (void)close(pi[1]);
  1591.             break;
  1592.         }
  1593.         *reply = '\0';
  1594.         (void)dgets(-1, NULL, 0); /* make sure buffer marked empty */
  1595.         while ((n = dgets(pi[0], temprpl, sizeof(temprpl)-1)) > 0)
  1596.             {
  1597.             temprpl[n] = '\0';
  1598.             if ((s = (char *)index(temprpl, '\n')))
  1599.                   *s = '\0';
  1600.             if (strlen(temprpl) + strlen(reply) < sizeof(reply)-2)
  1601.                 (void)sprintf(rplhold, "%s %s", rplhold,
  1602.                     temprpl);
  1603.             else
  1604.                 {
  1605.                 sendto_ops("R-line %s/%s: reply too long!",
  1606.                        name, host);
  1607.                 break;
  1608.                 }
  1609.             }
  1610.         (void)dgets(-1, NULL, 0); /* make sure buffer marked empty */
  1611.         (void)close(pi[0]);
  1612.         (void)kill(rc, SIGKILL); /* cleanup time */
  1613.         (void)wait(0);
  1614.  
  1615.         rc = 0;
  1616.         while (*rplhold == ' ')
  1617.             rplhold++;
  1618.         rplchar = *rplhold; /* Pull out the yes or no */
  1619.         while (*rplhold != ' ')
  1620.             rplhold++;
  1621.         while (*rplhold == ' ')
  1622.             rplhold++;
  1623.         (void)strcpy(reply,rplhold);
  1624.         rplhold = reply;
  1625.  
  1626.         if ((rc = (rplchar == 'n' || rplchar == 'N')))
  1627.             break;
  1628.         }
  1629.     if (rc)
  1630.         {
  1631.         sendto_one(cptr, ":%s %d %s :Restriction: %s",
  1632.                me.name, ERR_YOUREBANNEDCREEP, cptr->name,
  1633.                reply);
  1634.         return -1;
  1635.         }
  1636.     return 0;
  1637. }
  1638. #endif
  1639.  
  1640. /*
  1641. **  output the reason for being k lined from a file  - Mmmm
  1642. ** sptr is server    
  1643. ** parv is the sender prefix
  1644. ** filename is the file that is to be output to the K lined client
  1645. */
  1646. int     m_killcomment(sptr, parv, filename)
  1647. aClient *sptr;
  1648. char    *parv, *filename;
  1649. {
  1650.       int     fd;
  1651.       char    line[80];
  1652.       Reg1    char     *tmp;
  1653.       struct  stat    sb;
  1654.       struct  tm      *tm;
  1655.  
  1656.       /*
  1657.        * stop NFS hangs...most systems should be able to open a file in
  1658.        * 3 seconds. -avalon (curtesy of wumpus)
  1659.        */
  1660.       fd = open(filename, O_RDONLY);
  1661.       if (fd == -1)
  1662.           {
  1663.               sendto_one(sptr, err_str(ERR_NOMOTD), me.name, parv);
  1664.               sendto_one(sptr,
  1665.                          ":%s %d %s :*** You are not welcome to this server.",
  1666.                          me.name, ERR_YOUREBANNEDCREEP, parv);
  1667.               return 0;
  1668.           }
  1669.       (void)fstat(fd, &sb);
  1670.       tm = localtime(&sb.st_mtime);
  1671.       (void)dgets(-1, NULL, 0); /* make sure buffer is at empty pos */
  1672.       while (dgets(fd, line, sizeof(line)-1) > 0)
  1673.           {
  1674.               if ((tmp = (char *)index(line,'\n')))
  1675.                       *tmp = '\0';
  1676.               if ((tmp = (char *)index(line,'\r')))
  1677.                       *tmp = '\0';
  1678.               /* sendto_one(sptr,
  1679.                          ":%s %d %s : %s.",
  1680.                          me.name, ERR_YOUREBANNEDCREEP, parv,line); */
  1681.               sendto_one(sptr, rpl_str(RPL_MOTD), me.name, parv, line); 
  1682.           }
  1683.        sendto_one(sptr,
  1684.                   ":%s %d %s :*** You are not welcome to this server.",
  1685.                    me.name, ERR_YOUREBANNEDCREEP, parv);
  1686.       (void)dgets(-1, NULL, 0); /* make sure buffer is at empty pos */
  1687.       (void)close(fd);
  1688.       return 0;
  1689.   }
  1690.  
  1691.  
  1692. /*
  1693. ** is the K line field an interval or a comment? - Mmmm
  1694. */
  1695.  
  1696. static int is_comment(comment)
  1697. char     *comment;
  1698. {
  1699.     int i;
  1700.         for (i=0; i<strlen(comment); i++)
  1701.           if ( (comment[i] != ' ') && (comment[i] != '-')
  1702.                                      && (comment[i] != ',') 
  1703.                   &&  ( (comment[i] < '0') || (comment[i] > '9') ) )
  1704.                    return(1);
  1705.  
  1706.     return(0);
  1707. }
  1708.  
  1709.  
  1710. /*
  1711. ** check against a set of time intervals
  1712. */
  1713.  
  1714. static    int    check_time_interval(interval, reply)
  1715. char    *interval, *reply;
  1716. {
  1717.     struct tm *tptr;
  1718.      time_t    tick;
  1719.      char    *p;
  1720.      int    perm_min_hours, perm_min_minutes,
  1721.          perm_max_hours, perm_max_minutes;
  1722.      int    now, perm_min, perm_max;
  1723.  
  1724.      tick = time(NULL);
  1725.     tptr = localtime(&tick);
  1726.      now = tptr->tm_hour * 60 + tptr->tm_min;
  1727.  
  1728.     while (interval)
  1729.         {
  1730.         p = (char *)index(interval, ',');
  1731.         if (p)
  1732.             *p = '\0';
  1733.         if (sscanf(interval, "%2d%2d-%2d%2d",
  1734.                &perm_min_hours, &perm_min_minutes,
  1735.                &perm_max_hours, &perm_max_minutes) != 4)
  1736.             {
  1737.             if (p)
  1738.                 *p = ',';
  1739.             return(0);
  1740.             }
  1741.         if (p)
  1742.             *(p++) = ',';
  1743.         perm_min = 60 * perm_min_hours + perm_min_minutes;
  1744.         perm_max = 60 * perm_max_hours + perm_max_minutes;
  1745.                /*
  1746.                ** The following check allows intervals over midnight ...
  1747.                */
  1748.         if ((perm_min < perm_max)
  1749.             ? (perm_min <= now && now <= perm_max)
  1750.             : (perm_min <= now || now <= perm_max))
  1751.             {
  1752.             (void)sprintf(reply,
  1753.                 ":%%s %%d %%s :%s %d:%02d to %d:%02d.",
  1754.                 "You are not allowed to connect from",
  1755.                 perm_min_hours, perm_min_minutes,
  1756.                 perm_max_hours, perm_max_minutes);
  1757.             return(ERR_YOUREBANNEDCREEP);
  1758.             }
  1759.         if ((perm_min < perm_max)
  1760.             ? (perm_min <= now + 5 && now + 5 <= perm_max)
  1761.             : (perm_min <= now + 5 || now + 5 <= perm_max))
  1762.             {
  1763.             (void)sprintf(reply, ":%%s %%d %%s :%d minute%s%s",
  1764.                 perm_min-now,(perm_min-now)>1?"s ":" ",
  1765.                 "and you will be denied for further access");
  1766.             return(ERR_YOUWILLBEBANNED);
  1767.             }
  1768.         interval = p;
  1769.         }
  1770.     return(0);
  1771. }
  1772.  
  1773. /*
  1774. ** m_rakill;
  1775. **      parv[0] = sender prefix
  1776. **      parv[1] = hostmask
  1777. **      parv[2] = username
  1778. **      parv[3] = comment
  1779. */
  1780. int     m_rakill(cptr, sptr, parc, parv)
  1781. aClient *cptr, *sptr;
  1782. int     parc;
  1783. char    *parv[];
  1784.     {
  1785.         if (check_registered(sptr))
  1786.                 return 0;
  1787.  
  1788.         if (parc < 3)
  1789.             {
  1790.                 sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS),
  1791.                            me.name, parv[0], "RAKILL");
  1792.                 return 0;
  1793.             }
  1794.  
  1795.         if (IsServer(cptr) &&
  1796.             find_conf_host(cptr->confs, sptr->name, CONF_UWORLD))
  1797.         {
  1798.                 if (find_kill_byname(parv[1], parv[2]))
  1799.         {
  1800. #ifndef COMMENT_IS_FILE
  1801.                     del_temp_conf(CONF_KILL, parv[1], parv[3], 
  1802.                 parv[2], 0, 0, 1); 
  1803. #else
  1804.                     del_temp_conf(CONF_KILL, parv[1], NULL,
  1805.                 parv[2], 0, 0, 1);
  1806. #endif
  1807.         }
  1808.                 if(parv[3])
  1809.                         sendto_serv_butone(cptr, ":%s RAKILL %s %s :%s", 
  1810.                 parv[0], parv[1], parv[2], parv[3]);
  1811.                 else
  1812.                         sendto_serv_butone(cptr, ":%s RAKILL %s %s", 
  1813.                 parv[0], parv[1], parv[2]);
  1814.                 check_pings(time(NULL), 1);
  1815.         }
  1816.  
  1817.     }
  1818.  
  1819. /* ** m_akill;
  1820. **    parv[0] = sender prefix
  1821. **    parv[1] = hostmask
  1822. **    parv[2] = username
  1823. **    parv[3] = comment
  1824. */
  1825. int    m_akill(cptr, sptr, parc, parv)
  1826. aClient *cptr, *sptr;
  1827. int    parc;
  1828. char    *parv[];
  1829.     {
  1830.     if (check_registered(sptr))
  1831.         return 0;
  1832.  
  1833.     if (parc < 3)
  1834.         {
  1835.         sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS),
  1836.                me.name, parv[0], "AKILL");
  1837.         return 0;
  1838.         }
  1839.  
  1840.     if (IsServer(cptr) &&
  1841.         find_conf_host(cptr->confs, sptr->name, CONF_UWORLD))
  1842.     {
  1843.         if (!find_kill_byname(parv[1], parv[2]))
  1844.         {
  1845.  
  1846. #ifndef COMMENT_IS_FILE
  1847.              add_temp_conf(CONF_KILL, parv[1], parv[3], parv[2], 0, 0, 2); 
  1848. #else
  1849.             add_temp_conf(CONF_KILL, parv[1], NULL, parv[2], 0, 0, 2); 
  1850. #endif
  1851.         }
  1852.         if(parv[3])
  1853.             sendto_serv_butone(cptr, ":%s AKILL %s %s :%s", parv[0],
  1854.                      parv[1], parv[2], parv[3]);
  1855.         else
  1856.             sendto_serv_butone(cptr, ":%s AKILL %s %s", parv[0],
  1857.                      parv[1], parv[2]);
  1858.         check_pings(time(NULL), 1);
  1859.     }
  1860.  
  1861.     }
  1862.  
  1863. /*    m_sqline
  1864. **    parv[0] = sender
  1865. **    parv[1] = nickmask
  1866. **    parv[2] = reason
  1867. */
  1868. int    m_sqline(cptr, sptr, parc, parv)
  1869. aClient *cptr, *sptr;
  1870. int    parc;
  1871. char    *parv[];
  1872. {
  1873.     Reg1 aSqlineItem *asqline;
  1874.  
  1875.     if (!IsServer(sptr) || parc < 2)
  1876.         return 0;
  1877.  
  1878.     if(parv[2])
  1879.         sendto_serv_butone(cptr, ":%s SQLINE %s :%s", parv[0],
  1880.                  parv[1], parv[2]);
  1881.     else
  1882.         sendto_serv_butone(cptr, ":%s SQLINE %s", parv[0],
  1883.                  parv[1]);
  1884.  
  1885.     asqline = make_sqline();
  1886.  
  1887.     if (parv[2])
  1888.       DupString(asqline->reason, parv[2]);
  1889.     if (parv[1])
  1890.       DupString(asqline->sqline, parv[1]);
  1891.  
  1892.     if (!find_sqline_nick(parv[1])) {
  1893.         asqline->next = sqline;
  1894.         sqline = asqline;
  1895.         asqline = NULL;
  1896.     }
  1897.  
  1898.     if (asqline)
  1899.       free_sqline(asqline);
  1900. }
  1901.  
  1902. /*    m_unsqline
  1903. **    parv[0] = sender
  1904. **    parv[1] = nickmask
  1905. */
  1906. int    m_unsqline(cptr, sptr, parc, parv)
  1907. aClient *cptr, *sptr;
  1908. int    parc;
  1909. char    *parv[];
  1910. {
  1911.     Reg1 aSqlineItem *asqline;
  1912.  
  1913.     if (!IsServer(sptr) || parc < 1)
  1914.         return 0;
  1915.  
  1916.     sendto_serv_butone(cptr, ":%s UNSQLINE %s", parv[0],
  1917.              parv[1]);
  1918.  
  1919.     if(!(asqline = find_sqline_nick(parv[1])))
  1920.         return;
  1921.  
  1922.     asqline->status = CONF_ILLEGAL;
  1923.  
  1924. }
  1925.  
  1926. /*
  1927. ** m_kline;
  1928. **    parv[0] = sender prefix
  1929. **    parv[1] = nickname
  1930. **    parv[2] = comment or filename
  1931. */
  1932. int    m_kline(cptr, sptr, parc, parv)
  1933. aClient *cptr, *sptr;
  1934. int    parc;
  1935. char    *parv[];
  1936.     {
  1937.     char *host, *tmp, *hosttemp;
  1938.     char uhost[80], name[80];
  1939.     int ip1, ip2, ip3, temp;
  1940.     aClient *acptr;
  1941.  
  1942.         if (!MyClient(sptr) || !OPCanKline(sptr))
  1943.             {
  1944.                 sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
  1945.                 return 0;
  1946.             }
  1947.  
  1948.     if (check_registered(sptr))
  1949.         return 0;
  1950.  
  1951.     if (parc < 2)
  1952.         {
  1953.         sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS),
  1954.                me.name, parv[0], "KLINE");
  1955.         return 0;
  1956.         }
  1957.  
  1958.  
  1959. /* This patch allows opers to quote kline by address as well as nick
  1960.  * --Russell
  1961.  */
  1962.     if (hosttemp = strchr(parv[1], '@'))
  1963.     {
  1964.         temp = 0;
  1965.         while (temp <= 20)
  1966.             name[temp++] = 0;
  1967.         strcpy(uhost, ++hosttemp);
  1968.         strncpy(name, parv[1], hosttemp-1-parv[1]);
  1969.         if (name[0] == '\0' || uhost[0] == '\0')
  1970.         {
  1971.             Debug((DEBUG_INFO, "KLINE: Bad field!"));
  1972.             sendto_one (sptr, "NOTICE %s :If you're going to add a userhost, at LEAST specify both fields", parv[0]);    
  1973.             return 0;
  1974.         }
  1975.         if (!strcmp(uhost, "*") || !strchr(uhost, '.'))
  1976.         {
  1977.             sendto_one (sptr, "NOTICE %s :What a sweeping K:Line.  If only your admin knew you tried that..", parv[0]);
  1978.             return 0;
  1979.         }
  1980.     }    
  1981.  
  1982. /* by nick */
  1983.     else
  1984.     {
  1985.         if (!(acptr = find_client(parv[1], NULL))) {
  1986.             if (!(acptr = get_history(parv[1], (long)KILLCHASETIMELIMIT))) {
  1987.                 sendto_one(sptr, "NOTICE %s :Can't find user %s to add KLINE",
  1988.                        parv[0], parv[1]);
  1989.                 return 0;
  1990.             }
  1991.         }
  1992.  
  1993.         if (!acptr->user)
  1994.             return 0;
  1995.  
  1996.         strcpy(name, acptr->user->username);
  1997.         if (MyClient(acptr))
  1998.             host = acptr->sockhost;
  1999.         else
  2000.             host = acptr->user->host;
  2001.  
  2002.         /* Sanity checks */
  2003.  
  2004.         if (name == '\0' || host == '\0')
  2005.         {
  2006.             Debug((DEBUG_INFO, "KLINE: Bad field"));
  2007.             sendto_one(sptr, "NOTICE %s :Bad field!", parv[0]);
  2008.             return 0;
  2009.         }
  2010.  
  2011.         /* Add some wildcards */
  2012.  
  2013.  
  2014.         strcpy(uhost, host);
  2015.         if (isdigit(host[strlen(host)-1])) {
  2016.             if (sscanf(host, "%d.%d.%d.%*d", &ip1, &ip2, &ip3))
  2017.                 sprintf(uhost, "%d.%d.%d.*", ip1, ip2, ip3);
  2018.         }
  2019.         else if (sscanf(host, "%*[^.].%*[^.].%s", uhost)) { /* Not really... */
  2020.             tmp = (char*)strchr(host, '.');
  2021.             sprintf(uhost, "*%s", tmp);
  2022.         }
  2023.     }
  2024.  
  2025.     sendto_ops("%s added a temp k:line for %s@%s %s", parv[0], name, uhost, parv[2] ? parv[2] : "");
  2026.      add_temp_conf(CONF_KILL, uhost, parv[2], name, 0, 0, 1);
  2027.     check_pings(time(NULL), 1);
  2028.     }
  2029.     
  2030.  
  2031. /*
  2032.  *  m_unkline
  2033.  *    parv[0] = sender prefix
  2034.  *    parv[1] = userhost
  2035.  */
  2036.  
  2037. int m_unkline(cptr, sptr, parc, parv)
  2038. aClient *cptr, *sptr;
  2039. int     parc;
  2040. char    *parv[];
  2041. {
  2042.  
  2043.     int    result, temp;
  2044.     char    *hosttemp=parv[1], host[80], name[80];
  2045.  
  2046.     if (!MyClient(sptr) || !OPCanUnKline(sptr))
  2047.     {
  2048.                 sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
  2049.                 return 0;
  2050.     }
  2051.     if (parc<2)
  2052.     {
  2053.         sendto_one(sptr,"NOTICE %s :Not enough parameters", parv[0]);
  2054.         return 0;
  2055.     }
  2056.         if (hosttemp = strchr(parv[1], '@'))
  2057.         {
  2058.                 temp = 0;
  2059.                 while (temp <= 20)
  2060.                         name[temp++] = 0;
  2061.                 strcpy(host, ++hosttemp);
  2062.                 strncpy(name, parv[1], hosttemp-1-parv[1]);
  2063.                 if (name[0] == '\0' || host[0] == '\0')
  2064.                 {
  2065.                         Debug((DEBUG_INFO, "UNKLINE: Bad field"));
  2066.             sendto_one(sptr, "NOTICE %s : Both user and host fields must be non-null", parv[0]);
  2067.             return 0;
  2068.         }
  2069.         result = del_temp_conf(CONF_KILL, host, NULL, name, 
  2070.             NULL, NULL, 0);
  2071.         if (result == KLINE_RET_AKILL) {    /* akill - result = 3 */
  2072.             sendto_one(sptr, "NOTICE %s :You may not remove autokills.  Only U:lined clients may.", parv[0]);
  2073.             return 0;
  2074.         }
  2075.         if (result ==  KLINE_RET_PERM) {    /* Not a temporary line - result =2 */
  2076.             sendto_one(sptr,"NOTICE %s :You may not remove permanent K:Lines - talk to the admin", parv[0]);
  2077.             return 0;
  2078.         }
  2079.         if (result ==  KLINE_RET_DELOK)  {    /* Successful result = 1*/
  2080.             sendto_one(sptr,"NOTICE %s :Temp K:Line %s@%s is now removed.", parv[0],name,host);
  2081.             sendto_ops("%s removed temp k:line %s@%s", parv[0], name, host);
  2082.             return 0;
  2083.         }
  2084.         if (result == KLINE_DEL_ERR) {    /* Unsuccessful result = 0*/
  2085.             sendto_one(sptr,"NOTICE %s :Temporary K:Line %s@%s not found", parv[0],name,host);
  2086.             return 0;
  2087.         }
  2088.     }
  2089.     /* This wasn't here before -- Barubary */
  2090.     check_pings(time(NULL), 1);
  2091. }
  2092.  
  2093. /*
  2094.  *  m_zline                       add a temporary zap line
  2095.  *    parv[0] = sender prefix
  2096.  *    parv[1] = host
  2097.  *    parv[2] = reason
  2098.  */
  2099.  
  2100. int m_zline(cptr, sptr, parc, parv)
  2101. aClient *cptr, *sptr;
  2102. int     parc;
  2103. char    *parv[];
  2104. {
  2105.     char userhost[512+2]="", *in;
  2106.     int result=0, uline=0, i=0, propo=0;
  2107.     char *reason, *mask, *server, *person;
  2108.     aClient *acptr;
  2109.     
  2110.     reason=mask=server=person=NULL;
  2111.     
  2112.     reason = ((parc>=3) ? parv[parc-1] : "Reason unspecified");
  2113.     mask   = ((parc>=2) ? parv[parc-2] : NULL);
  2114.     server   = ((parc>=4) ? parv[parc-1] : NULL);
  2115.  
  2116.     if (parc == 4)
  2117.     {
  2118.           mask = parv[parc-3];
  2119.           server = parv[parc-2];
  2120.           reason = parv[parc-1];
  2121.     }
  2122.  
  2123.     uline = IsULine(cptr, sptr) ? 1 : 0;
  2124.  
  2125.     if (!uline && (!MyConnect(sptr) || !OPCanZline(sptr) || !IsOper(sptr)))
  2126.     {
  2127.       sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
  2128.       return -1;
  2129.     }
  2130.  
  2131.     if (uline)
  2132.     {
  2133.       if (parc>=4 && server)
  2134.       {
  2135.         if (hunt_server(cptr, sptr, ":%s ZLINE %s %s :%s", 2, parc, parv)
  2136.                 != HUNTED_ISME)
  2137.           return 0;
  2138.         else    ;
  2139.       }
  2140.       else propo=1;
  2141.     }
  2142.  
  2143.     if (parc < 2)
  2144.     {
  2145.       sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS),
  2146.                  me.name, parv[0], "ZLINE");
  2147.       return -1;
  2148.     }
  2149.  
  2150.     if (acptr = find_client(parv[1], NULL))
  2151.     {
  2152.       strcpy(userhost, inetntoa((char *) &acptr->ip));
  2153.       person = &acptr->name[0];
  2154.       acptr = NULL;
  2155.     }
  2156.      /* z-lines don't support user@host format, they only 
  2157.         work with ip addresses and nicks */
  2158.     else
  2159.     if ((in = index(parv[1], '@')) && (*(in+1)!='\0'))
  2160.     {
  2161.       strcpy(userhost, in+1);
  2162.       in = &userhost[0];
  2163.       while(*in) 
  2164.       { 
  2165.         if (!isdigit(*in) && !ispunct(*in)) 
  2166.         {
  2167.           sendto_one(sptr, ":%s NOTICE %s :z:lines work only with ip addresses (you cannot specify ident either)", me.name, sptr->name);
  2168.           return;
  2169.         }
  2170.         in++;
  2171.         }
  2172.       } else if (in && !(*(in+1))) /* sheesh not only specifying a ident@, but
  2173.                                    omitting the ip...?*/
  2174.       {
  2175.         sendto_one(sptr, ":%s NOTICE %s :Hey! z:lines need an ip address...",
  2176.                        me.name, sptr->name);
  2177.         return -1;
  2178.       }
  2179.     else
  2180.     {
  2181.       strcpy(userhost, parv[1]);
  2182.       in = &userhost[0];
  2183.       while(*in) 
  2184.       { 
  2185.         if (!isdigit(*in) && !ispunct(*in)) 
  2186.         {
  2187.            sendto_one(sptr, ":%s NOTICE %s :z:lines work only with ip addresses (you cannot specify ident either)", me.name, sptr->name);
  2188.            return;
  2189.         }
  2190.         in++;
  2191.       }
  2192.     }
  2193.     
  2194.        /* this'll protect against z-lining *.* or something */
  2195.     if (advanced_check(userhost, TRUE) == FALSE)
  2196.     { 
  2197.       sendto_ops("Bad z:line mask from %s *@%s [%s]", parv[0], userhost, reason?reason:"");
  2198.       if (MyClient(sptr))
  2199.       sendto_one(sptr, ":%s NOTICE %s :*@%s is a bad z:line mask...", me.name, sptr->name, userhost);
  2200.       return;
  2201.         }
  2202.  
  2203.     if (uline == 0)
  2204.     {
  2205.       if (person)
  2206.         sendto_ops("%s added a temp z:line for %s (*@%s) [%s]", parv[0], person, userhost, reason?reason:"");
  2207.       else
  2208.         sendto_ops("%s added a temp z:line *@%s [%s]", parv[0], userhost, reason?reason:"");
  2209.       (void) add_temp_conf(CONF_ZAP, userhost,  reason, NULL, 0, 0, KLINE_TEMP); 
  2210.         }
  2211.     else
  2212.      {
  2213.      if (person)
  2214.        sendto_ops("%s z:lined %s (*@%s) on %s [%s]", parv[0], person, userhost, server?server:"DALnet" , reason?reason:"");
  2215.      else
  2216.        sendto_ops("%s z:lined *@%s on %s [%s]", parv[0], userhost, server?server:"DALnet" , reason?reason:"");
  2217.       (void) add_temp_conf(CONF_ZAP, userhost,  reason, NULL, 0, 0, KLINE_AKILL); 
  2218.         }
  2219.  
  2220.                                            /* something's wrong if i'm
  2221.                                               zapping the command source... */
  2222.        if (find_zap(cptr, 0)||find_zap(sptr, 0))
  2223.        {
  2224.              sendto_failops_whoare_opers("z:line error: mask=%s parsed=%s I tried to zap cptr", mask, userhost);
  2225.              sendto_serv_butone(NULL,":%s GLOBOPS :z:line error: mask=%s parsed=%s I tried to zap cptr", me.name, mask, userhost);
  2226.              flush_connections(me.fd);
  2227.              (void)rehash(&me, &me, 0);
  2228.              return;
  2229.        }
  2230.  
  2231.     for (i=highest_fd;i>0;i--)
  2232.     {
  2233.       if (!(acptr = local[i]) || IsLog(acptr) || IsMe(acptr));
  2234.          continue;
  2235.       if (  find_zap(acptr, 1) )
  2236.           {
  2237.         if (!IsServer(acptr))
  2238.         {
  2239.                sendto_one(sptr,":%s NOTICE %s :*** %s %s",
  2240.                           me.name, sptr->name, 
  2241.                       IsPerson(acptr)?"exiting":"closing", 
  2242.                       acptr->name[0]?acptr->name:"<unknown>");
  2243.                exit_client(acptr, acptr, acptr, "z-lined");
  2244.         }
  2245.         else
  2246.         {
  2247.           sendto_one(sptr, ":%s NOTICE %s :*** exiting %s",
  2248.                      me.name, sptr->name, acptr->name);
  2249.           sendto_ops("dropping server %s (z-lined)", acptr->name);
  2250.           sendto_serv_butone(cptr, "GNOTICE :dropping server %s (z-lined)",
  2251.                              acptr->name);
  2252.           exit_client(acptr, acptr, acptr, "z-lined");
  2253.  
  2254.         }
  2255.       }
  2256.     }
  2257.  
  2258.        if (propo==1)      /* propo is if a ulined server is propagating a z-line
  2259.                              this should go after the above check */
  2260.             sendto_serv_butone(cptr, ":%s ZLINE %s :%s", parv[0], parv[1], reason?reason:"");
  2261.  
  2262.         check_pings(time(NULL), 1);
  2263.  
  2264. }
  2265.  
  2266.  
  2267. /*
  2268.  *  m_unzline                        remove a temporary zap line
  2269.  *    parv[0] = sender prefix
  2270.  *    parv[1] = host
  2271.  */
  2272.  
  2273. int m_unzline(cptr, sptr, parc, parv)
  2274. aClient *cptr, *sptr;
  2275. int     parc;
  2276. char    *parv[];
  2277. {
  2278. char userhost[512+2]="", *in;
  2279. int result=0, uline=0, akill=0;
  2280. aConfItem *aconf, *tmp;
  2281. aConfItem dummy;
  2282. char *mask, *server;
  2283.  
  2284. uline = IsULine(cptr, sptr)? 1 : 0;
  2285.  
  2286.    if (parc < 2)
  2287.    {
  2288.    sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS),
  2289.               me.name, parv[0], "UNZLINE");
  2290.       return -1;
  2291.    }
  2292.  
  2293.  
  2294.  if (parc < 3 || !uline)
  2295.  {
  2296.      mask   = parv[parc-1];
  2297.      server = NULL;
  2298.  }
  2299.  else if (parc == 3)
  2300.  {
  2301.      mask   = parv[parc-2];
  2302.      server = parv[parc-1];
  2303.  }
  2304.  
  2305.    if (!uline && (!MyConnect(sptr) || !OPCanZline(sptr) || !IsOper(sptr)))
  2306.    {
  2307.        sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
  2308.        return -1;
  2309.    }
  2310.  
  2311.    /* before we even check ourselves we need to do the uline checks
  2312.       because we aren't supposed to add a z:line if the message is
  2313.       destined to be passed on...*/
  2314.  
  2315.    if (uline)
  2316.    {
  2317.      if (parc == 3 && server)
  2318.      {
  2319.         if (hunt_server(cptr, sptr, ":%s UNZLINE %s %s", 2, parc, parv) != HUNTED_ISME)
  2320.                    return 0;
  2321.         else    ;
  2322.      }
  2323.       else
  2324.             sendto_serv_butone(cptr, ":%s UNZLINE %s", parv[0], parv[1]);
  2325.  
  2326.    }
  2327.  
  2328.  
  2329.    /* parse the removal mask the same way so an oper can just use
  2330.       the same thing to remove it if they specified *@ or something... */
  2331.    if ((in = index(parv[1], '@')))
  2332.    {
  2333.        strcpy(userhost, in+1);
  2334.        in = &userhost[0];
  2335.        while(*in) 
  2336.        { 
  2337.            if (!isdigit(*in) && !ispunct(*in)) 
  2338.            {
  2339.               sendto_one(sptr, ":%s NOTICE %s :it's not possible to have a z:line that's not an ip addresss...", me.name, sptr->name);
  2340.               return;
  2341.            }
  2342.             in++;
  2343.        }
  2344.    }
  2345.    else
  2346.    {
  2347.        strcpy(userhost, parv[1]);
  2348.        in = &userhost[0];
  2349.        while(*in) 
  2350.        { 
  2351.            if (!isdigit(*in) && !ispunct(*in)) 
  2352.            {
  2353.               sendto_one(sptr, ":%s NOTICE %s :it's not possible to have a z:line that's not an ip addresss...", me.name, sptr->name);
  2354.               return;
  2355.            }
  2356.             in++;
  2357.        }
  2358.    }
  2359.  
  2360.        akill = 0;
  2361. retry_unzline:
  2362.  
  2363.         if (uline == 0)
  2364.         {
  2365.            result = del_temp_conf(CONF_ZAP, userhost,  NULL, NULL, 0, 0, akill);
  2366.       if ((result) == KLINE_RET_DELOK)
  2367.           {
  2368.              sendto_one(sptr,":%s NOTICE %s :temp z:line *@%s removed", me.name, parv[0], userhost);
  2369.              sendto_ops("%s removed temp z:line *@%s", parv[0], userhost);
  2370.           }
  2371.           else if (result == KLINE_RET_PERM)
  2372.               sendto_one(sptr, ":%s NOTICE %s :You may not remove permanent z:lines talk to your admin...", me.name, sptr->name);
  2373.  
  2374.           else if (result == KLINE_RET_AKILL && !(sptr->umodes & UMODE_SADMIN))
  2375.           {
  2376.               sendto_one(sptr, ":%s NOTICE %s :You may not remove z:lines placed by services...", me.name, sptr->name);
  2377.           }
  2378.           else if (result == KLINE_RET_AKILL && !akill)
  2379.           {
  2380.              akill=1;
  2381.              goto retry_unzline;
  2382.           }
  2383.           else
  2384.               sendto_one(sptr, ":%s NOTICE %s :Couldn't find/remove zline for *@%s", me.name, sptr->name, userhost);
  2385.  
  2386.         }
  2387.         else    
  2388.         {      /* services did it, services should be able to remove
  2389.                   both types...;> */
  2390.       if (del_temp_conf(CONF_ZAP, userhost,  NULL, NULL, 0, 0, 1) == KLINE_RET_DELOK||
  2391.               del_temp_conf(CONF_ZAP, userhost,  NULL, NULL, 0, 0, 0) == KLINE_RET_DELOK)
  2392.           {
  2393.               if (MyClient(sptr))
  2394.              sendto_one(sptr,"NOTICE %s :temp z:line *@%s removed", parv[0], userhost);
  2395.              sendto_ops("%s removed temp z:line *@%s", parv[0], userhost);
  2396.           }
  2397.           else
  2398.               sendto_one(sptr, ":%s NOTICE %s :ERROR Removing z:line", me.name, sptr->name);
  2399.        }
  2400.  
  2401. }
  2402.  
  2403.  
  2404. /* ok, given a mask, our job is to determine
  2405.  * wether or not it's a safe mask to banish...
  2406.  *
  2407.  * userhost= mask to verify
  2408.  * ipstat= TRUE  == it's an ip
  2409.  *         FALSE == it's a hostname
  2410.  *         UNSURE == we need to find out
  2411.  * return value
  2412.  *         TRUE  == mask is ok
  2413.  *         FALSE == mask is not ok
  2414.  *        UNSURE == [unused] something went wrong
  2415.  */
  2416.  
  2417. advanced_check(char *userhost, int ipstat)
  2418. {
  2419.   register int    retval = TRUE;
  2420.   char    *up, *p, *thisseg;
  2421.   int    numdots=0, segno=0, numseg, i=0;
  2422.   char    *ipseg[10+2];
  2423.   char    safebuffer[512]=""; /* buffer strtoken() can mess up to its heart's content...;>*/
  2424.  
  2425.   strcpy(safebuffer, userhost);
  2426.  
  2427. #define userhost safebuffer
  2428. #define IP_WILDS_OK(x) ((x)<2? 0 : 1)
  2429.  
  2430.    if (ipstat == UNSURE)
  2431.    {
  2432.         ipstat=TRUE;
  2433.         for (;*up;up++) 
  2434.         {
  2435.            if (*up=='.') numdots++;
  2436.            if (!isdigit(*up) && !ispunct(*up)) {ipstat=FALSE; continue;}
  2437.         }
  2438.         if (numdots != 3) ipstat=FALSE;
  2439.         if (numdots < 1 || numdots > 9)  return(0);
  2440.    }
  2441.  
  2442.      /* fill in the segment set */
  2443.   {
  2444.      int l = 0;
  2445.         for (segno = 0, i = 0, thisseg = strtoken(&p, userhost, "."); thisseg;
  2446.              thisseg = strtoken(&p, NULL, "."), i++)
  2447.         {
  2448.             
  2449.             l = strlen(thisseg)+2;
  2450.             ipseg[segno] = calloc(1, l);
  2451.             strncpy(ipseg[segno++], thisseg, l);
  2452.         }
  2453.   }
  2454.      if (segno < 2 && ipstat==TRUE) retval = FALSE;  
  2455.      numseg = segno;
  2456.      if (ipstat==TRUE)
  2457.       for(i=0;i<numseg;i++)
  2458.       {
  2459.             if (!IP_WILDS_OK(i) && index(ipseg[i], '*')||index(ipseg[i], '?'))
  2460.                retval=FALSE;            
  2461.             MyFree(ipseg[i]);
  2462.       }
  2463.      else
  2464.      {
  2465.       int wildsok=0;
  2466.  
  2467.       for(i=0;i<numseg;i++)
  2468.       {
  2469.              /* for hosts, let the mask extent all the way to 
  2470.                 the second-level domain... */
  2471.            wildsok=1;
  2472.            if (i==numseg||(i+1)==numseg) wildsok=0;
  2473.            if (wildsok == 0 && (index(ipseg[i], '*')||index(ipseg[i], '?')))
  2474.            {
  2475.              retval=FALSE;
  2476.            }
  2477.             MyFree(ipseg[i]);
  2478.       }
  2479.  
  2480.  
  2481.      }
  2482.  
  2483.            return(retval);
  2484. #undef userhost
  2485. #undef IP_WILDS_OK
  2486.  
  2487. }
  2488.