home *** CD-ROM | disk | FTP | other *** search
/ ftp.ee.lbl.gov / 2014.05.ftp.ee.lbl.gov.tar / ftp.ee.lbl.gov / acld-1.11.tar.gz / acld-1.11.tar / acld-1.11 / cf.c < prev    next >
C/C++ Source or Header  |  2012-02-07  |  21KB  |  863 lines

  1. /*
  2.  * Copyright (c) 2002, 2003, 2004, 2006, 2008, 2009, 2010, 2011, 2012
  3.  *    The Regents of the University of California.  All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that: (1) source code distributions
  7.  * retain the above copyright notice and this paragraph in its entirety, (2)
  8.  * distributions including binary code include the above copyright notice and
  9.  * this paragraph in its entirety in the documentation or other materials
  10.  * provided with the distribution, and (3) all advertising materials mentioning
  11.  * features or use of this software display the following acknowledgement:
  12.  * ``This product includes software developed by the University of California,
  13.  * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
  14.  * the University nor the names of its contributors may be used to endorse
  15.  * or promote products derived from this software without specific prior
  16.  * written permission.
  17.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
  18.  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
  19.  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  20.  */
  21.  
  22. #ifndef lint
  23. static const char rcsid[] =
  24.     "@(#) $Id: cf.c 806 2012-02-08 03:40:06Z leres $ (LBL)";
  25. #endif
  26.  
  27. #include <sys/types.h>
  28. #include <sys/time.h>
  29. #include <sys/stat.h>
  30.  
  31. #include <netinet/in.h>
  32.  
  33. #include <arpa/inet.h>
  34.  
  35. #include <ctype.h>
  36. #include <errno.h>
  37. #include <stdio.h>
  38. #include <stdlib.h>
  39. #include <string.h>
  40. #include <sysexits.h>
  41. #include <syslog.h>
  42.  
  43. #include "acld.h"
  44. #include "cf.h"
  45.  
  46. /* Locals */
  47. static int errors;
  48.  
  49. /* Forwards */
  50. static void acllimitadd(struct cf *, const char *);
  51. static void acllimitfree(struct acllimit *);
  52. static void attrlistadd(struct cf *, const char *);
  53. static void attrlistfree(struct attrlist *);
  54. static void intlistadd(struct cf *, const char *);
  55. static void intlistfree(struct intlist *);
  56. static int readcf(const char *, struct cf *, int);
  57.  
  58. /* Open, read and parse one config file */
  59. static int
  60. readcf(const char *fn, struct cf *cf, int mustexist)
  61. {
  62.     int n, errs, *ip, *ip2;
  63.     struct addr *a;
  64.     char *cp, *cp2, **pp;
  65.     const char *p;
  66.     time_t t;
  67.     FILE *f;
  68.     struct stat sbuf;
  69.     char buf[1024];
  70.     char at[1024];
  71.  
  72.     errs = 0;
  73.     f = fopen(fn, "r");
  74.     if (f == NULL) {
  75.         if (mustexist) {
  76.             lg(LOG_ERR, "readcf: fopen %s: %s",
  77.                 fn, strerror(errno));
  78.             ++errs;
  79.         }
  80.         return (errs);
  81.     }
  82.  
  83.     /* Get the config file mod time */
  84.     if (fstat(fileno(f), &sbuf) >= 0) {
  85.         t = (sbuf.st_mtime > sbuf.st_ctime) ?
  86.             sbuf.st_mtime : sbuf.st_ctime;
  87.         if (cf->c_time < t)
  88.             cf->c_time = t;
  89.     } else {
  90.         lg(LOG_ERR, "readcf: fstat %s: %s", fn, strerror(errno));
  91.         ++errs;
  92.     }
  93.  
  94.     n = 0;
  95.     while (fgets(buf, sizeof(buf), f) != NULL) {
  96.         ++n;
  97.  
  98.         /* Eat comments */
  99.         cp = strchr(buf, '#');
  100.         if (cp)
  101.             *cp = '\0';
  102.  
  103.         /* Eat trailing whitesapce */
  104.         cp = buf + strlen(buf) - 1;
  105.         while (cp >= buf && isspace((int)*cp))
  106.             *cp-- = '\0';
  107.         cp = buf;
  108.  
  109.         /* Skip blank lines */
  110.         if (*cp == '\n' || *cp == '\0')
  111.             continue;
  112.  
  113.         /* Get command */
  114.         cp2 = cp;
  115.         while (!isspace((int)*cp) && *cp != '\0')
  116.             ++cp;
  117.         *cp++ = '\0';
  118.  
  119.         (void)sprintf(at, "%s:%d", fn, n);
  120.  
  121.         /* Find start of next keyword */
  122.         while (isspace((int)*cp))
  123.             ++cp;
  124.  
  125.         /* Quoted one line commands */
  126.         if ((pp = &cf->c_cuser, strcasecmp(cp2, "cuser") == 0) ||
  127. #ifdef HAVE_CFORCE
  128.             (pp = &cf->c_cforceaddr,
  129.             strcasecmp(cp2, "cforceaddr") == 0) ||
  130.             (pp = &cf->c_cforcedata,
  131.             strcasecmp(cp2, "cforcedata") == 0) ||
  132. #endif
  133.             (pp = &cf->c_cpass1, strcasecmp(cp2, "cpass1") == 0) ||
  134.             (pp = &cf->c_cpass2, strcasecmp(cp2, "cpass2") == 0) ||
  135.             (pp = &cf->c_epass1, strcasecmp(cp2, "epass1") == 0) ||
  136.             (pp = &cf->c_epass2, strcasecmp(cp2, "epass2") == 0) ||
  137.             (pp = &cf->c_euser, strcasecmp(cp2, "euser") == 0) ||
  138.             (pp = &cf->c_expect, strcasecmp(cp2, "expect") == 0) ||
  139.             (pp = &cf->c_id, strcasecmp(cp2, "id") == 0) ||
  140.             (pp = &cf->c_router, strcasecmp(cp2, "router") == 0) ||
  141.             (pp = &cf->c_script, strcasecmp(cp2, "script") == 0) ||
  142.             (pp = &cf->c_whitelistfn,
  143.             strcasecmp(cp2, "whitelist") == 0)) {
  144.             if (*cp++ != '"') {
  145.                 lg(LOG_ERR, "%s missing leading double quote",
  146.                     at);
  147.                 ++errors;
  148.                 continue;
  149.             }
  150.             if (*pp != NULL)  {
  151.                 lg(LOG_ERR, "%s only one \"%s\" is allowed",
  152.                     at, cp2);
  153.                 ++errors;
  154.                 continue;
  155.             }
  156.             *pp = strsave(cp);
  157.             cp = *pp;
  158.             cp2 = cp + strlen(cp) - 1;
  159.             if (cp > cp2 || *cp2 != '"') {
  160.                 lg(LOG_ERR, "%s missing trailing double quote",
  161.                     at);
  162.                 ++errors;
  163.                 free(*pp);
  164.                 *pp = NULL;
  165.                 continue;
  166.             }
  167.             *cp2 = '\0';
  168.             continue;
  169.         }
  170.  
  171.         /* Commands with numeric arguments */
  172.         if ((ip = &cf->c_ayt_secs, strcasecmp(cp2, "ayt_secs") == 0) ||
  173.             (ip = &cf->c_incrseq, strcasecmp(cp2, "incrseq") == 0) ||
  174.             (ip = &cf->c_ipv4_maxwidth,
  175.             strcasecmp(cp2, "ipv4_maxwidth") == 0) ||
  176.             (ip = &cf->c_ipv6_maxwidth,
  177.             strcasecmp(cp2, "ipv6_maxwidth") == 0) ||
  178.             (ip = &cf->c_login_secs,
  179.             strcasecmp(cp2, "login_secs") == 0) ||
  180.             (ip = &cf->c_nullzeromax,
  181.             strcasecmp(cp2, "nullzeromax") == 0) ||
  182.             (ip = &cf->c_maxseq, strcasecmp(cp2, "maxseq") == 0) ||
  183.             (ip = &cf->c_port, strcasecmp(cp2, "port") == 0) ||
  184. #ifdef HAVE_BROCCOLI
  185.             (ip = &cf->c_portbro, strcasecmp(cp2, "portbro") == 0) ||
  186. #endif
  187. #ifdef HAVE_CFORCE
  188.             (ip = &cf->c_portcforce,
  189.             strcasecmp(cp2, "portcforce") == 0) ||
  190. #endif
  191.             (ip = &cf->c_portro, strcasecmp(cp2, "portro") == 0) ||
  192.             (ip = &cf->c_portweb, strcasecmp(cp2, "portweb") == 0) ||
  193.             (ip = &cf->c_select_secs,
  194.             strcasecmp(cp2, "select_secs") == 0) ||
  195.             (ip = &cf->c_sync_secs,
  196.             strcasecmp(cp2, "sync_secs") == 0)) {
  197.             *ip = atoi(cp);
  198.             if (*cp == '-' || *cp == '+')
  199.                 ++cp;
  200.             while (isdigit((int)*cp))
  201.                 ++cp;
  202.             while (isspace((int)*cp))
  203.                 ++cp;
  204.             if (*cp != '\0') {
  205.                 lg(LOG_ERR, "%s trailing garbage (%s)", at, cp);
  206.                 ++errors;
  207.             }
  208.             continue;
  209.         }
  210.  
  211.         /* Commands with two numeric arguments */
  212.         if ((ip = &cf->c_lowseq, ip2 = &cf->c_highseq,
  213.             strcasecmp(cp2, "seqrange") == 0) ||
  214.             (ip = &cf->c_lowportseq, ip2 = &cf->c_highportseq,
  215.             strcasecmp(cp2, "portseqrange") == 0) ||
  216.             (ip = &cf->c_lowpermithostportseq,
  217.             ip2 = &cf->c_highpermithostportseq,
  218.             strcasecmp(cp2, "permithostportseqrange") == 0)) {
  219.             /* Low value */
  220.             *ip = atoi(cp);
  221.             if (*cp == '-' || *cp == '+')
  222.                 ++cp;
  223.             if (!isdigit((int)*cp)) {
  224.                 lg(LOG_ERR, "%s missing low %s", at, cp2);
  225.                 ++errors;
  226.             }
  227.             while (isdigit((int)*cp))
  228.                 ++cp;
  229.             if (!isspace((int)*cp)) {
  230.                 lg(LOG_ERR, "%s missing %s whitespace",
  231.                     at, cp2);
  232.                 ++errors;
  233.             }
  234.             while (isspace((int)*cp))
  235.                 ++cp;
  236.  
  237.             /* High value */
  238.             *ip2 = atoi(cp);
  239.             if (*cp == '-' || *cp == '+')
  240.                 ++cp;
  241.             if (!isdigit((int)*cp)) {
  242.                 lg(LOG_ERR, "%s missing high %s", at, cp2);
  243.                 ++errors;
  244.             }
  245.             while (isdigit((int)*cp))
  246.                 ++cp;
  247.             while (isspace((int)*cp))
  248.                 ++cp;
  249.             if (*cp != '\0') {
  250.                 lg(LOG_ERR, "%s %s trailing garbage", at, cp2);
  251.                 ++errors;
  252.             }
  253.             continue;
  254.         }
  255.  
  256.         /* Commands with ip address arguments */
  257.         if ((a = &cf->c_bindaddr, strcasecmp(cp2, "bindaddr") == 0)
  258. #ifdef HAVE_BROCCOLI
  259.             || (a = &cf->c_broaddr, strcasecmp(cp2, "broaddr") == 0)
  260. #endif
  261.             ) {
  262.             p = extractaddr(cp, NULL, a);
  263.             if (p != NULL) {
  264.                 lg(LOG_ERR, "%s bogus ip address: %s", at, p);
  265.                 ++errors;
  266.             }
  267.             continue;
  268.         }
  269.  
  270.         /* ACL limits */
  271.         if (strcasecmp(cp2, "limit") == 0) {
  272.             acllimitadd(cf, cp);
  273.             continue;
  274.         }
  275.  
  276.         /* ACLs */
  277.         if (strcasecmp(cp2, "acl") == 0) {
  278.             acladdacllist(cf, cp);
  279.             continue;
  280.         }
  281.  
  282.         /* Attributes */
  283.         if (strcasecmp(cp2, "attr") == 0) {
  284.             attrlistadd(cf, cp);
  285.             continue;
  286.         }
  287.  
  288.         /* Interfaces */
  289.         if (strcasecmp(cp2, "interface") == 0) {
  290.             intlistadd(cf, cp);
  291.             continue;
  292.         }
  293.  
  294.         /* Null zero nets */
  295.         if (strcasecmp(cp2, "nullzeronet") == 0) {
  296.             if (!nullzeronetadd(cf, cp))
  297.                 ++errors;
  298.             continue;
  299.         }
  300.  
  301.         /* nets_log() syslog facility */
  302.         if (strcasecmp(cp2, "netsfac") == 0) {
  303.             cf->c_netsfac = str2val(syslog2str, cp);
  304.             if (cf->c_netsfac < 0) {
  305.                 lg(LOG_ERR, "error: bogus netpri value \"%s\"",
  306.                     cp);
  307.                 ++errors;
  308.             }
  309.             continue;
  310.         }
  311.  
  312.         /* Bad commands */
  313.         lg(LOG_ERR, "%s unknown command \"%s\"", at, cp2);
  314.         ++errors;
  315.     }
  316.     (void)fclose(f);
  317.  
  318.     return (errs);
  319. }
  320.  
  321. static void
  322. acllimitadd(struct cf *cf, const char *str)
  323. {
  324.     long v;
  325.     int an;
  326.     char **av;
  327.     char *cp;
  328.     struct acllimit *alp;
  329.  
  330.     v = strtol(str, &cp, 10);
  331.     if (!isspace(*cp)) {
  332.         lg(LOG_ERR, "acllimitadd: trailing garbage (%s)", str);
  333.         ++errors;
  334.     }
  335.     if (v <= 0) {
  336.         lg(LOG_ERR, "acllimitadd: bad value (%ld)", v);
  337.         ++errors;
  338.     }
  339.  
  340.     ++cp;
  341.     while (isspace(*cp))
  342.         ++cp;
  343.  
  344.     /* Make a list of ACL names */
  345.     an = makeargv(cp, &av);
  346.     if (an <= 0) {
  347.         lg(LOG_ERR, "acllimitadd: missing ACL name(s) \"%s\"", str);
  348.         return;
  349.     }
  350.  
  351.     DYNARRAY(cf->c_acllimit, cf->c_acllimitlen, &cf->c_acllimitsize,
  352.         sizeof(*cf->c_acllimit), 8, 8, "cf acllimit");
  353.     alp = cf->c_acllimit + cf->c_acllimitlen;
  354.     ++cf->c_acllimitlen;
  355.  
  356.     alp->a_maxseq = v;
  357.     alp->a_nacls = an;
  358.     alp->a_acls = av;
  359. }
  360.  
  361. static void
  362. acllimitfree(struct acllimit *alp)
  363. {
  364.  
  365.     if (alp->a_acls != NULL) {
  366.         freeargv(alp->a_acls);
  367.         alp->a_acls = NULL;
  368.         alp->a_nacls = 0;
  369.     }
  370. }
  371.  
  372. static void
  373. attrlistadd(struct cf *cf, const char *str)
  374. {
  375.     struct attrlist *atp, *atp2;
  376.     int an, i;
  377.     char **av;
  378.  
  379.     an = makeargv(str, &av);
  380.     if (an < 2) {
  381.         lg(LOG_ERR, "attrlistadd: wrong number of args: \"%s\"", str);
  382.         freeargv(av);
  383.         return;
  384.     }
  385.  
  386.     /* Find access list */
  387.     atp = NULL;
  388.     for (i = 0, atp2 = cf->c_attrlist; i < cf->c_attrlistlen; ++i, ++atp2)
  389.         if (strcmp(av[0], atp2->a_acl) == 0) {
  390.             atp = atp2;
  391.             break;
  392.         }
  393.  
  394.     if (atp == NULL) {
  395.         /* New entry */
  396.         DYNARRAY(cf->c_attrlist, cf->c_attrlistlen, &cf->c_attrlistsize,
  397.             sizeof(*cf->c_attrlist), 8, 8, "cf attrlist");
  398.         atp = cf->c_attrlist + cf->c_attrlistlen;
  399.         ++cf->c_attrlistlen;
  400.         atp->a_acl = strsave(av[0]);
  401.     }
  402.  
  403.     for (i = 1; i < an; ++i) {
  404.         if (strcmp(av[i], "ipv6") == 0) {
  405.             atp->a_attr |= ATTR_IPV6;
  406.             continue;
  407.         }
  408.         lg(LOG_ERR, "attrlistadd: unknown attr \"%s\"", av[i]);
  409.         ++errors;
  410.     }
  411.  
  412.     freeargv(av);
  413. }
  414.  
  415. static void
  416. attrlistfree(struct attrlist *atp)
  417. {
  418.  
  419.     if (atp->a_acl != NULL) {
  420.         free(atp->a_acl);
  421.         atp->a_acl = NULL;
  422.     }
  423. }
  424.  
  425. struct cf *
  426. parsecf(const char *fn)
  427. {
  428.     int i, j, seqrange, portseqrange, permithostportseqrange;
  429.     char *cp;
  430.     const char *p;
  431.     struct cf *cf;
  432.     struct acllimit *alp;
  433.     struct attrlist *atp;
  434.     struct acllist *ap;
  435.     struct intlist *ip;
  436.  
  437.     cf = (struct cf *)new(1, sizeof(*cf), "parsecf cf");
  438.  
  439.     /* Defaults */
  440.     cf->c_ayt_secs = AYT_SECS;
  441.     cf->c_login_secs = LOGIN_SECS;
  442.     cf->c_select_secs = SELECT_SECS;
  443.     cf->c_sync_secs = SYNC_SECS;
  444.     cf->c_incrseq = 1;
  445.  
  446.     cf->c_lowseq = -1;
  447.     cf->c_highseq = -1;
  448.     cf->c_lowportseq = -1;
  449.     cf->c_highportseq = -1;
  450.     cf->c_lowpermithostportseq = -1;
  451.     cf->c_highpermithostportseq = -1;
  452.  
  453.     cf->c_ipv4_maxwidth = DEFAULT_IPV4_WIDTH;
  454.     cf->c_ipv6_maxwidth = DEFAULT_IPV6_WIDTH;
  455.  
  456. #ifdef HAVE_CFORCE
  457.     cf->c_cforcedata = "/var/run/cforce.data";
  458. #endif
  459.  
  460.     p = extractaddr("127.0.0.1", NULL, &cf->c_bindaddr);
  461.     if (p != NULL)
  462.         abort();
  463.  
  464.     errors += readcf(fn, cf, 1);
  465.  
  466.     if ((cp = "acl", cf->c_acllist == NULL) ||
  467.         (cp = "interface", cf->c_intlist == NULL)) {
  468.         lg(LOG_ERR, "error: \"%s\" missing but required", cp);
  469.         ++errors;
  470.     }
  471.  
  472. #ifdef HAVE_CFORCE
  473.     if (cf->c_router != NULL) {
  474. #endif
  475.         /*
  476.          * Without cForce:
  477.          * Need expect+router+script
  478.          */
  479.         if ((cp = "expect", cf->c_expect == NULL) ||
  480.             (cp = "script", cf->c_script == NULL) ||
  481.             (cp = "router", cf->c_router == NULL)) {
  482.             lg(LOG_ERR, "error: \"%s\" missing but required", cp);
  483.             ++errors;
  484.         }
  485. #ifdef HAVE_CFORCE
  486.     } else {
  487.         /*
  488.          * With cForce:
  489.          * Need either expect+router+script or cforceaddr+portcforce
  490.          */
  491.         i = 0;
  492.         if (cf->c_cforceaddr != NULL)
  493.             ++i;
  494.         if (cf->c_portcforce > 0)
  495.             ++i;
  496.         j = 0;
  497.         if (cf->c_expect != NULL)
  498.             ++j;
  499.         if (cf->c_script != NULL)
  500.             ++j;
  501.         if (cf->c_script != NULL)
  502.             ++j;
  503.         if (!((i == 2 && j == 0) || (i == 0 && j == 3))) {
  504.             lg(LOG_ERR,
  505.                 "error: Only \"expect\", \"router\" and \"script\""
  506.                 " or \"cforceaddr\" and \"portcforce\" allowed");
  507.             ++errors;
  508.         }
  509.  
  510.         /* cForce: sequence numbers are assigned by the appliance */
  511.         if (cf->c_lowseq >= 0 || cf->c_highseq >= 0) {
  512.             lg(LOG_ERR, "error: cForce does not use seqrange");
  513.             ++errors;
  514.         }
  515.  
  516.         /* cForce: nullzero routes are not support */
  517.         if (cf->c_nullzeronets != NULL || cf->c_nullzeromax != 0) {
  518.             lg(LOG_ERR,
  519.                 "error: cForce does not support nullzero routes");
  520.             ++errors;
  521.         }
  522.         if (!cf->c_incrseq) {
  523.             lg(LOG_ERR, "error: cForce does not use incrseq");
  524.             ++errors;
  525.         }
  526.         if (!cf->c_sync_secs > 0) {
  527.             lg(LOG_ERR, "error: cForce does not use sync_secs");
  528.             ++errors;
  529.         }
  530.     }
  531. #endif
  532.  
  533.     if (cf->c_ipv4_maxwidth < MAX_IPV4_WIDTH) {
  534.         lg(LOG_ERR, "error: \"ipv4_maxwidth\" must > %d",
  535.             MAX_IPV4_WIDTH);
  536.         ++errors;
  537.     } else if (cf->c_ipv4_maxwidth > 32) {
  538.         lg(LOG_ERR, "error: \"ipv4_maxwidth\" must <= 32");
  539.         ++errors;
  540.     }
  541.  
  542.     if (cf->c_ipv6_maxwidth < MAX_IPV6_WIDTH) {
  543.         lg(LOG_ERR, "error: \"ipv6_maxwidth\" must > %d",
  544.             MAX_IPV6_WIDTH);
  545.         ++errors;
  546.     } else if (cf->c_ipv6_maxwidth > 128) {
  547.         lg(LOG_ERR, "error: \"ipv6_maxwidth\" must <= 128");
  548.         ++errors;
  549.     }
  550.  
  551.     if ((cp = "login_secs", cf->c_login_secs <= 0) ||
  552.         (cp = "port", cf->c_port <= 0) ||
  553.         (cp = "select_secs", cf->c_select_secs <= 0)) {
  554.         lg(LOG_ERR, "error: \"%s\" must be non-zero", cp);
  555.         ++errors;
  556.     }
  557.  
  558.     if ((cp = "port", !VALID_PORT(cf->c_port)) ||
  559.         (cp = "portro", !VALID_PORT(cf->c_portro) && cf->c_portro != 0) ||
  560.         (cp = "portweb", !VALID_PORT(cf->c_portweb) &&
  561.         cf->c_portweb != 0)) {
  562.         lg(LOG_ERR, "error: \"%s\" is out of range", cp);
  563.         ++errors;
  564.     }
  565.  
  566.     if ((cf->c_portro > 0 && (cp = "portro", cf->c_portro == cf->c_port)) ||
  567.         (cf->c_portweb > 0 && (cp = "portweb",
  568.         cf->c_portweb == cf->c_port))) {
  569.         lg(LOG_ERR, "error: \"%s\" can't be the same as \"port\"", cp);
  570.         ++errors;
  571.     }
  572.     if (cf->c_portro > 0 && cf->c_portweb > 0 &&
  573.         cf->c_portro == cf->c_portweb) {
  574.         lg(LOG_ERR,
  575.             "error: \"portro\" can't be the same as \"portweb\"");
  576.         ++errors;
  577.     }
  578.  
  579.     seqrange = (cf->c_lowseq >= 0 || cf->c_highseq >= 0);
  580.     portseqrange = (cf->c_lowportseq > 0 || cf->c_highportseq > 0);
  581.     permithostportseqrange = (cf->c_lowpermithostportseq >= 0 ||
  582.         cf->c_highpermithostportseq >= 0);
  583.  
  584. #define IN_SEQRANGE(n) ((n) >= cf->c_lowseq && (n) <= cf->c_highseq)
  585. #define IN_PORTSEQRANGE(n) ((n) >= cf->c_lowportseq && (n) <= cf->c_highportseq)
  586. #define IN_PERMITHOSTPORTSEQRANGE(n) \
  587.     ((n) >= cf->c_lowpermithostportseq && (n) <= cf->c_highpermithostportseq)
  588.  
  589.     if (seqrange) {
  590.         if (cf->c_lowseq >= cf->c_highseq) {
  591.             lg(LOG_ERR, "error: \"seqrange\" must be increasing");
  592.             ++errors;
  593.         }
  594.         if (portseqrange && (IN_SEQRANGE(cf->c_lowportseq) ||
  595.             IN_SEQRANGE(cf->c_highportseq))) {
  596.             lg(LOG_ERR,
  597.                 "error: \"seqrange\" and \"portseqrange\" overlap");
  598.             ++errors;
  599.         }
  600.     }
  601.  
  602.     if (portseqrange) {
  603.         if (cf->c_lowportseq >= cf->c_highportseq) {
  604.             lg(LOG_ERR,
  605.                 "error: \"portseqrange\" must be increasing");
  606.             ++errors;
  607.         }
  608.         if (permithostportseqrange &&
  609.             (IN_PERMITHOSTPORTSEQRANGE(cf->c_lowseq) ||
  610.             IN_PERMITHOSTPORTSEQRANGE(cf->c_highseq))) {
  611.             lg(LOG_ERR, "error: \"portseqrange\" and"
  612.                 " \"permithostportseqrange\" overlap");
  613.             ++errors;
  614.         }
  615.     }
  616.  
  617.     if (permithostportseqrange) {
  618.         if (cf->c_lowpermithostportseq >= cf->c_highpermithostportseq) {
  619.             lg(LOG_ERR, "error: \"permithostportseqrange\" must"
  620.             " be increasing");
  621.             ++errors;
  622.         }
  623.         if (seqrange &&
  624.             (IN_SEQRANGE(cf->c_lowpermithostportseq) ||
  625.             IN_SEQRANGE(cf->c_highpermithostportseq))) {
  626.             lg(LOG_ERR, "error: \"seqrange\" and"
  627.                 " \"permithostportseqrange\" overlap");
  628.             ++errors;
  629.         }
  630.     }
  631. #define GOOD_PORT(p) ((p) > 0 && (p) <= 2 << 16)
  632.     if (cf->c_port != 0 && !GOOD_PORT(cf->c_port)) {
  633.         lg(LOG_ERR, "error: bad \"port\" port value");
  634.         ++errors;
  635.     }
  636.     if (cf->c_portro != 0 && !GOOD_PORT(cf->c_portro)) {
  637.         lg(LOG_ERR, "error: bad \"portro\" port value");
  638.         ++errors;
  639.     }
  640.     if (cf->c_portweb != 0 && !GOOD_PORT(cf->c_portweb)) {
  641.         lg(LOG_ERR, "error: bad \"portweb\" port value");
  642.         ++errors;
  643.     }
  644. #ifdef HAVE_BROCCOLI
  645.     if (cf->c_portbro != 0 && !GOOD_PORT(cf->c_portbro)) {
  646.         lg(LOG_ERR, "error: bad \"portbro\" port value");
  647.         ++errors;
  648.     }
  649. #endif
  650.  
  651. #define ESCAPESTR(str) { \
  652.     cp = str; \
  653.     str = strsave(escapestr(cp)); \
  654.     if (cp != NULL) \
  655.         free(cp); \
  656.     }
  657.  
  658.     ESCAPESTR(cf->c_cuser);
  659.     ESCAPESTR(cf->c_cpass1);
  660.     ESCAPESTR(cf->c_cpass2);
  661.     ESCAPESTR(cf->c_euser);
  662.     ESCAPESTR(cf->c_epass1);
  663.     ESCAPESTR(cf->c_epass2);
  664.  
  665.     /* Hook interfaces into acls */
  666.     for (i = 0, ap = cf->c_acllist; i < cf->c_acllistlen; ++i, ++ap)
  667.         for (j = 0, ip = cf->c_intlist; j < cf->c_intlistlen; ++j, ++ip)
  668.             if (strcmp(ap->name, ip->i_acl) == 0) {
  669.                 ap->intlist = ip;
  670.                 break;
  671.             }
  672.     for (i = 0, ap = cf->c_acllist; i < cf->c_acllistlen; ++i, ++ap)
  673.         if (ap->intlist == NULL) {
  674.             lg(LOG_ERR, "error: ACL %s missing interface",
  675.                 ap->name);
  676.             ++errors;
  677.         }
  678.  
  679.     /* Hook ACL limits into ACLs */
  680.     for (i = 0, alp = cf->c_acllimit; i < cf->c_acllimitlen; ++i, ++alp)
  681.         for (j = 0; j < alp->a_nacls; ++j) {
  682.             ap = aclfindlistbyname(cf, alp->a_acls[j]);
  683.             if (ap == NULL) {
  684.                 lg(LOG_ERR, "error: ACL %s not defined",
  685.                     alp->a_acls[j]);
  686.                 ++errors;
  687.                 continue;
  688.             }
  689.             if (ap->limitp != NULL) {
  690.                 lg(LOG_ERR, "error: ACL %s already limited",
  691.                     ap->name);
  692.                 ++errors;
  693.                 continue;
  694.             }
  695.             ap->limitp = alp;
  696.         }
  697.  
  698.     /* Check for limits on undefined ACLs */
  699.     for (i = 0, atp = cf->c_attrlist; i < cf->c_attrlistlen; ++i, ++atp) {
  700.         ap = aclfindlistbyname(cf, atp->a_acl);
  701.         if (ap == NULL) {
  702.             lg(LOG_ERR, "error: ACL %s not defined", atp->a_acl);
  703.             ++errors;
  704.         }
  705.     }
  706.  
  707.     /* If any ACLs are limited, check for unlimited */
  708.     if (cf->c_acllimitlen > 0) {
  709.         for (i = 0, ap = cf->c_acllist; i < cf->c_acllistlen; ++i, ++ap)
  710.             if (ap->limitp == NULL) {
  711.                 lg(LOG_ERR, "error: ACL %s is unlimited",
  712.                     ap->name);
  713.                 ++errors;
  714.             }
  715.     }
  716.  
  717.     /* Whitelist */
  718.     whitelistread(cf);
  719.  
  720. #ifdef HAVE_BROCCOLI
  721.     /* Default broaddr to bindaddr */
  722.     if (cf->c_portbro != 0 && cf->c_broaddr.family == 0)
  723.         cf->c_broaddr = cf->c_bindaddr;
  724. #endif
  725.  
  726.     if (errors > 0)
  727.         exit(EX_CONFIG);
  728.  
  729.     return (cf);
  730. }
  731.  
  732. static void
  733. freeone(void *p)
  734. {
  735.  
  736.     if (p != NULL)
  737.         free(p);
  738. }
  739.  
  740. void
  741. freecf(struct cf *cf)
  742. {
  743.     int i;
  744.     struct acllist *ap;
  745.     struct acllimit *alp;
  746.     struct attrlist *atp;
  747.     struct intlist *ip;
  748.  
  749.     /* Single line options */
  750. #ifdef HAVE_CFORCE
  751.     freeone(cf->c_cforceaddr);
  752. #endif
  753.     freeone(cf->c_cpass1);
  754.     freeone(cf->c_cpass2);
  755.     freeone(cf->c_epass1);
  756.     freeone(cf->c_epass2);
  757.     freeone(cf->c_expect);
  758.     freeone(cf->c_router);
  759.     freeone(cf->c_script);
  760.  
  761.     /* ACL limits */
  762.     for (i = 0, alp = cf->c_acllimit; i < cf->c_acllimitlen; ++i, ++alp)
  763.         acllimitfree(alp);
  764.     cf->c_acllimit = NULL;
  765.     cf->c_acllimitlen = 0;
  766.     cf->c_acllimitsize = 0;
  767.  
  768.     /* ACLs */
  769.     for (i = 0, ap = cf->c_acllist; i < cf->c_acllistlen; ++i, ++ap)
  770.         aclfree(ap);
  771.     cf->c_acllist = NULL;
  772.     cf->c_acllistlen = 0;
  773.     cf->c_acllistsize = 0;
  774.  
  775.     /* Attributes */
  776.     for (i = 0, atp = cf->c_attrlist; i < cf->c_attrlistlen; ++i, ++atp)
  777.         attrlistfree(atp);
  778.     cf->c_attrlist = NULL;
  779.     cf->c_attrlistlen = 0;
  780.     cf->c_attrlistsize = 0;
  781.  
  782.     /* Interfaces */
  783.     for (i = 0, ip = cf->c_intlist; i < cf->c_intlistlen; ++i, ++ip)
  784.         intlistfree(ip);
  785.     cf->c_intlist = NULL;
  786.     cf->c_intlistlen = 0;
  787.     cf->c_intlistsize = 0;
  788.  
  789.     /* Null zero routes */
  790.     if (cf->c_nullzeronets != NULL) {
  791.         free(cf->c_nullzeronets);
  792.         cf->c_nullzeronets = NULL;
  793.         cf->c_nullzeronetslen = 0;
  794.         cf->c_nullzeronetssize = 0;
  795.     }
  796.  
  797.     /* Whitelist */
  798.     if (cf->c_whitelist != NULL) {
  799.         free(cf->c_whitelist);
  800.         cf->c_whitelist = NULL;
  801.         cf->c_whitelistlen = 0;
  802.         cf->c_whitelistsize = 0;
  803.     }
  804.     if (cf->c_whitelistfn != NULL) {
  805.         free(cf->c_whitelistfn);
  806.         cf->c_whitelistfn = NULL;
  807.     }
  808.  
  809.     free(cf);
  810. }
  811.  
  812. static void
  813. intlistadd(struct cf *cf, const char *str)
  814. {
  815.     struct intlist *ip;
  816.     int an, i;
  817.     char **av;
  818.     char buf[1024];
  819.     char *cp;
  820.     size_t size, len;
  821.  
  822.     an = makeargv(str, &av);
  823.     if (an < 2) {
  824.         lg(LOG_ERR, "intlistadd: wrong number of args: \"%s\"", str);
  825.         freeargv(av);
  826.         return;
  827.     }
  828.  
  829.     DYNARRAY(cf->c_intlist, cf->c_intlistlen, &cf->c_intlistsize,
  830.         sizeof(*cf->c_intlist), 8, 8, "cf intlist");
  831.     ip = cf->c_intlist + cf->c_intlistlen;
  832.     ++cf->c_intlistlen;
  833.  
  834.     ip->i_acl = strsave(av[an - 1]);
  835.  
  836.     size = sizeof(buf);
  837.     cp = buf;
  838.     for (i = 0; i < an - 1; ++i) {
  839.         (void)snprintf(cp, size, " %s", av[i]);
  840.         len = strlen(cp);
  841.         cp += len;
  842.         size -= len;
  843.     }
  844.     cp = buf + 1;
  845.     ip->i_name = strsave(cp);
  846.  
  847.     freeargv(av);
  848. }
  849.  
  850. static void
  851. intlistfree(struct intlist *ip)
  852. {
  853.  
  854.     if (ip->i_acl != NULL) {
  855.         free(ip->i_acl);
  856.         ip->i_acl = NULL;
  857.     }
  858.     if (ip->i_name != NULL) {
  859.         free(ip->i_name);
  860.         ip->i_name = NULL;
  861.     }
  862. }
  863.