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 / child.c < prev    next >
C/C++ Source or Header  |  2012-02-07  |  27KB  |  1,187 lines

  1. /*
  2.  * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 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: child.c 806 2012-02-08 03:40:06Z leres $ (LBL)";
  25. #endif
  26.  
  27. #include <sys/types.h>
  28. #include <sys/time.h>
  29.  
  30. #include <errno.h>
  31. #include <signal.h>
  32. #include <stdio.h>
  33. #include <stdlib.h>
  34. #include <string.h>
  35. #include <sysexits.h>
  36. #include <syslog.h>
  37. #include <unistd.h>
  38.  
  39. #include "acld.h"
  40. #include "cf.h"
  41. #include "child.h"
  42.  
  43. /* Forwards */
  44. static void childaclcleanup(struct state *sp, struct req *rp);
  45. static int childresponse(char **, struct state *);
  46. static int failed(const char *, const char *);
  47.  
  48. /* Fix up things if updating the router failed */
  49. static void
  50. childaclcleanup(struct state *sp, struct req *rp)
  51. {
  52.     struct acllist *ap;
  53.  
  54.     switch (rp->type) {
  55.  
  56.     case REQ_DROP:
  57.     case REQ_BLOCKHOSTHOST:
  58.         /* Need to delete ACL entry since we failed */
  59.         ap = aclfindlistbyaddr(sp->cf, &rp->acl.addr1);
  60.         if (ap == NULL) {
  61.             lg(LOG_ERR, "childinput: NULL %s", rp->cmd);
  62.             exit(EX_SOFTWARE);
  63.         }
  64.         if (!acldeleteacl(ap, &rp->acl))
  65.             lg(LOG_ERR, "childinput: acldeleteacl failed");
  66.         break;
  67.  
  68.     case REQ_PERMITUDPDSTHOSTPORT:
  69.     case REQ_PERMITTCPDSTHOSTPORT:
  70.     case REQ_DROPTCPDSTHOSTPORT:
  71.         /* Need to delete ACL entry since we failed */
  72.         ap = aclfindlistdefault(sp->cf, &rp->acl.addr1);
  73.         if (ap == NULL) {
  74.             lg(LOG_ERR, "childinput: NULL %s", rp->cmd);
  75.             exit(EX_SOFTWARE);
  76.         }
  77.         if (!acldeleteacl(ap, &rp->acl))
  78.             lg(LOG_ERR, "childinput: acldeleteacl failed");
  79.         break;
  80.  
  81.     case REQ_RESTORE:
  82.     case REQ_RESTOREHOSTHOST:
  83.         /* Need to restore ACL entry since we failed */
  84.         ap = aclfindlistbyaddr(sp->cf, &rp->acl.addr1);
  85.         if (ap == NULL) {
  86.             lg(LOG_ERR, "childinput: NULL %s", rp->cmd);
  87.             exit(EX_SOFTWARE);
  88.         }
  89.         acladdacl(ap, &rp->acl);
  90.         break;
  91.  
  92.     case REQ_UNPERMITUDPDSTHOSTPORT:
  93.     case REQ_UNPERMITTCPDSTHOSTPORT:
  94.     case REQ_RESTORETCPDSTHOSTPORT:
  95.         /* Need to restore ACL entry since we failed */
  96.         ap = aclfindlistdefault(sp->cf, &rp->acl.addr1);
  97.         if (ap == NULL) {
  98.             lg(LOG_ERR, "childinput: NULL %s", rp->cmd);
  99.             exit(EX_SOFTWARE);
  100.         }
  101.         acladdacl(ap, &rp->acl);
  102.         break;
  103.  
  104.     case REQ_DROPUDPPORT:
  105.     case REQ_DROPTCPPORT:
  106.         /* Need to delete/restore ACL entry since we failed */
  107.         ap = aclfindlistbyname(sp->cf, rp->aclname);
  108.         if (ap == NULL) {
  109.             lg(LOG_ERR, "childinput: NULL %s", rp->cmd);
  110.             exit(EX_SOFTWARE);
  111.         }
  112.         if (!acldeleteacl(ap, &rp->acl))
  113.             lg(LOG_ERR, "childinput: acldeleteacl failed");
  114.         break;
  115.  
  116.     case REQ_RESTOREUDPPORT:
  117.     case REQ_RESTORETCPPORT:
  118.         /* Need to delete/restore ACL entry since we failed */
  119.         ap = aclfindlistbyname(sp->cf, rp->aclname);
  120.         if (ap == NULL) {
  121.             lg(LOG_ERR, "childinput: NULL %s", rp->cmd);
  122.             exit(EX_SOFTWARE);
  123.         }
  124.         acladdacl(ap, &rp->acl);
  125.         break;
  126.  
  127.     case REQ_NULLZERO:
  128.         /* Need to delete nullzero route since we failed */
  129.         if (!routedelete(sp, &rp->nullzero))
  130.             lg(LOG_ERR, "childinput: routedelete failed");
  131.         break;
  132.  
  133.     case REQ_NONULLZERO:
  134.         /* Need to restore nullzero route since we failed */
  135.         routeadd(sp, &rp->nullzero);
  136.         break;
  137.  
  138.     default:
  139.         break;
  140.     }
  141. }
  142.  
  143. /* Process input from the child */
  144. int
  145. childinput(struct state *sp, struct client *cl)
  146. {
  147.     int an, flags, i, haveline;
  148.     char *cp;
  149.     struct acllist *ap, *ap2;
  150.     struct req *rp;
  151.     struct iobuf *ip;
  152.     char **av;
  153.     static char *p1, *p2;
  154.     static char prompt[] = "expect>";
  155.  
  156.     if (cl != NULL)
  157.         rp = cl->req;
  158.     else
  159.         rp = sp->req;
  160.  
  161.     ip = &sp->rbuf;
  162.     switch (sp->state) {
  163.  
  164.     case ASTATE_READRESPONSE:
  165.         if (childresponse(&p1, sp)) {
  166.             if (sp->state == ASTATE_READRESPONSE) {
  167.                 sp->state = ASTATE_LOGGEDIN;
  168.                 sp->cmd = NULL;
  169.             } else {
  170.                 sp->state = ASTATE_CONNECTED;
  171.                 sp->cmd = NULL;
  172.             }
  173.             if (p1 != NULL) {
  174.                 trimws(p1, strlen(p1));
  175.                 lg(LOG_DEBUG, "childinput response: \"%s\"",
  176.                     pretty(p1));
  177.                 free(p1);
  178.                 p1 = NULL;
  179.             }
  180.         }
  181.         return (0);
  182.  
  183.     case ASTATE_READERROR:
  184.         if (childresponse(&p2, sp)) {
  185.             if (sp->state == ASTATE_READRESPONSE) {
  186.                 sp->state = ASTATE_LOGGEDIN;
  187.                 sp->cmd = NULL;
  188.             } else {
  189.                 sp->state = ASTATE_CONNECTED;
  190.                 sp->cmd = NULL;
  191.                 /* Wait a bit before trying again */
  192.                 timerset(&sp->t_login, sp->cf->c_login_secs);
  193.             }
  194.             if (p2 != NULL) {
  195.                 trimws(p2, strlen(p2));
  196.                 lg(LOG_DEBUG, "childinput error: \"%s\"",
  197.                     pretty(p2));
  198.                 free(p2);
  199.                 p2 = NULL;
  200.             }
  201.         }
  202.         return (0);
  203.  
  204.     case ASTATE_READACL:
  205.         while ((haveline = iohaveline(ip)) &&
  206.             (cp = iogetstr(ip)) != NULL) {
  207.             /* Find the last ACL list that hasn't been updated */
  208.             ap2 = sp->cf->c_acllist;
  209.             ap = NULL;
  210.             for (i = 0; i < sp->cf->c_acllistlen; ++i) {
  211.                 if (!ap2->sentlistacl)
  212.                     break;
  213.                 ap = ap2++;
  214.             }
  215.             if (ap == NULL) {
  216.                 lg(LOG_ERR, "childinput: can't happen");
  217.                 exit(EX_SOFTWARE);
  218.             }
  219.  
  220.             /* Remove trailing newline for possible error message */
  221.             trimws(cp, strlen(cp));
  222.             if (aclstraddacl(sp->cf, ap, cp)) {
  223.                 sp->state = ASTATE_LOGGEDIN;
  224.                 sp->cmd = NULL;
  225.                 break;
  226.             }
  227.         }
  228.         /* We're not done if there wasn't a newline in the buffer */
  229.         return (!haveline);
  230.  
  231.     case ASTATE_READROUTE:
  232.         while ((haveline = iohaveline(ip)) &&
  233.             (cp = iogetstr(ip)) != NULL) {
  234.             /* Remove trailing newline for possible error message */
  235.             trimws(cp, strlen(cp));
  236.             if (routestradd(sp, cp)) {
  237.                 sp->state = ASTATE_LOGGEDIN;
  238.                 sp->cmd = NULL;
  239.                 break;
  240.             }
  241.         }
  242.         /* We're not done if there wasn't a newline in the buffer */
  243.         return (!haveline);
  244.  
  245.     default:
  246.         if (rp != NULL && rp->state == RSTATE_READRESPONSE) {
  247.             while ((cp = iogetstr(ip)) != NULL) {
  248.                 /* Strip trailing "\r\n" */
  249.                 trimws(cp, strlen(cp));
  250.                 if (strcmp(cp, ".") != 0) {
  251.                     lg(LOG_DEBUG,
  252.                         "childinput response: \"%s\"",
  253.                         pretty(cp));
  254.                     if (cl != NULL)
  255.                         ioappendline(&rp->payload,
  256.                             cp, strlen(cp));
  257.                     continue;
  258.                 }
  259.                 if (cl != NULL)
  260.                     clientsend(cl, rp);
  261.                 else {
  262.                     rp->state = RSTATE_DONE;
  263.                     getts(&rp->cts);
  264.                 }
  265.  
  266.                 /* Log for NETS */
  267.                 if (cl != NULL)
  268.                     nets_log(sp, rp);
  269.  
  270.                 /* Fix up things if the router command failed */
  271.                 if ((rp->flags & RFLAG_FAILED) != 0)
  272.                     childaclcleanup(sp, rp);
  273.                 break;
  274.             }
  275.             return (0);
  276.         }
  277.         break;
  278.     }
  279.  
  280.     /* Get input */
  281.     cp = iogetstr(ip);
  282.     if (strncmp(cp, prompt, sizeof(prompt) - 1) == 0) {
  283.         if (sp->state == ASTATE_NOTCONNECTED) {
  284.             sp->state = ASTATE_CONNECTED;
  285.             sp->cmd = NULL;
  286.         }
  287.         if (debug)
  288.             fprintf(lf, "%s childinput: (ready)\n", tsstr());
  289.         cp += sizeof(prompt) - 1;
  290.         if (*cp == '\0')
  291.             return (0);
  292.     }
  293.  
  294.     /* Break into arguments */
  295.     av = NULL;
  296.     an = makeargv(cp, &av);
  297.     if (an <= 0) {
  298.         freeargv(av);
  299.         return (0);
  300.     }
  301.  
  302.     if (debug) {
  303.         fprintf(lf, "%s childinput:", tsstr());
  304.         for (i = 0; i < an; ++i)
  305.             fprintf(lf, " %s", av[i]);
  306.         putc('\n', lf);
  307.     }
  308.  
  309.     switch (sp->state) {
  310.  
  311.     case ASTATE_SENTLISTACL:
  312.     case ASTATE_SENTLISTROUTE:
  313.     case ASTATE_SENTLOGIN:
  314.     case ASTATE_SENTATTR:
  315.         flags = 0;
  316.         if (failed(sp->cmd, av[0]))
  317.             flags |= RFLAG_FAILED;
  318.         else if (strcmp(sp->cmd, av[0]) != 0) {
  319.             lg(LOG_ERR,
  320.                 "childinput: unexpected response %s waiting for %s",
  321.                 av[0], sp->cmd);
  322.             freeargv(av);
  323.             return (0);
  324.         }
  325.         if (an > 1 && strcmp(av[1], "-") == 0)
  326.             flags |= RFLAG_CONTINUE;
  327.  
  328.         switch (sp->state) {
  329.  
  330.         case ASTATE_SENTLOGIN:
  331.         case ASTATE_SENTATTR:
  332.             if ((flags & RFLAG_FAILED) == 0) {
  333.                 if ((flags & RFLAG_CONTINUE) == 0)
  334.                     sp->state = ASTATE_LOGGEDIN;
  335.                 else
  336.                     sp->state = ASTATE_READRESPONSE;
  337.             } else {
  338.                 if ((flags & RFLAG_CONTINUE) == 0) {
  339.                     sp->state = ASTATE_CONNECTED;
  340.                     /* Wait a bit before trying again */
  341.                     timerset(&sp->t_login,
  342.                         sp->cf->c_login_secs);
  343.                 } else
  344.                     sp->state = ASTATE_READERROR;
  345.             }
  346.             break;
  347.  
  348.         case ASTATE_SENTLISTACL:
  349.             if ((flags & RFLAG_FAILED) == 0) {
  350.                 if ((flags & RFLAG_CONTINUE) == 0)
  351.                     sp->state = ASTATE_LOGGEDIN;
  352.                 else
  353.                     sp->state = ASTATE_READACL;
  354.             } else {
  355.                 if ((flags & RFLAG_CONTINUE) == 0) {
  356.                     sp->state = ASTATE_LOGGEDIN;
  357.                     childkill(sp);
  358.                 } else
  359.                     sp->state = ASTATE_READERROR;
  360.             }
  361.             break;
  362.  
  363.         case ASTATE_SENTLISTROUTE:
  364.             if ((flags & RFLAG_FAILED) == 0) {
  365.                 if ((flags & RFLAG_CONTINUE) == 0)
  366.                     sp->state = ASTATE_LOGGEDIN;
  367.                 else
  368.                     sp->state = ASTATE_READROUTE;
  369.             } else {
  370.                 if ((flags & RFLAG_CONTINUE) == 0) {
  371.                     sp->state = ASTATE_LOGGEDIN;
  372.                     childkill(sp);
  373.                 } else
  374.                     sp->state = ASTATE_READERROR;
  375.             }
  376.             break;
  377.  
  378.         default:
  379.             break;
  380.         }
  381.  
  382.         freeargv(av);
  383.         return (0);
  384.  
  385.     default:
  386.         break;
  387.     }
  388.  
  389.     if (rp == NULL) {
  390.         lg(LOG_ERR, "childinput: no server/client request to process");
  391.         freeargv(av);
  392.         return (0);
  393.     }
  394.  
  395.     if (rp->state != RSTATE_CHILD) {
  396.         lg(LOG_ERR, "childinput: not waiting for child to talk!");
  397.         freeargv(av);
  398.         return (0);
  399.     }
  400.  
  401.     rp->flags = 0;
  402.     if (failed(rp->cmd, av[0]))
  403.         rp->flags = RFLAG_FAILED;
  404.     else if (strcmp(rp->cmd, av[0]) != 0) {
  405.         lg(LOG_ERR, "childinput: unexpected response %s waiting for %s",
  406.             av[0], rp->cmd);
  407.         freeargv(av);
  408.         return (0);
  409.     }
  410.  
  411.     if (an > 1 && strcmp(av[1], "-") == 0) {
  412.         rp->flags |= RFLAG_CONTINUE;
  413.         rp->state = RSTATE_READRESPONSE;
  414.         freeargv(av);
  415.         /* Need to collect response before we're done */
  416.         return (0);
  417.     } else {
  418.         rp->state = RSTATE_DONE;
  419.         getts(&rp->cts);
  420.  
  421.         /* Log for NETS */
  422.         if (cl != NULL)
  423.             nets_log(sp, rp);
  424.     }
  425.  
  426.     /* Done with cracked arguments */
  427.     freeargv(av);
  428.  
  429.     if (cl != NULL)
  430.         clientsend(cl, rp);
  431.  
  432.     /* Fix up things if the router command failed */
  433.     if ((rp->flags & RFLAG_FAILED) != 0)
  434.         childaclcleanup(sp, rp);
  435.  
  436.     return (0);
  437. }
  438.  
  439. /* XXX unfortunately, this duplicates a lot of serverdroprestore() */
  440. void
  441. childdroprestore(struct state *sp, struct client *cl, struct req *rp)
  442. {
  443.     const char *p;
  444.     struct acllist *ap;
  445.     struct acl *al;
  446.     struct addr *wp, *tp;
  447.     struct cf *cf;
  448.     char buf[132];
  449.  
  450.     /* Find ACL list */
  451.     cf = sp->cf;
  452.     switch (rp->acl.type) {
  453.  
  454.     case ATYPE_PERMITHOST:
  455.     case ATYPE_BLOCKHOST:
  456.     case ATYPE_PERMITNET:
  457.     case ATYPE_BLOCKNET:
  458.     case ATYPE_BLOCKHOSTHOST:
  459.     case ATYPE_BLOCKTCPDSTHOSTPORT:
  460.         /* By address */
  461.         ap = aclfindlistbyaddr(cf, &rp->acl.addr1);
  462.         if (ap == NULL) {
  463.             clientsenderr(cl, rp, "can't find acllist for %s"
  464.                 " (is the default ACL missing?)",
  465.                 addr2str(&rp->acl.addr1));
  466.             return;
  467.         }
  468.         rp->acllist = ap;
  469.         break;
  470.  
  471.     case ATYPE_BLOCKUDPPORT:
  472.     case ATYPE_BLOCKTCPPORT:
  473.         /* By ACL name */
  474.         ap = aclfindlistbyname(cf, rp->aclname);
  475.         if (ap == NULL) {
  476.             clientsenderr(cl, rp, "can't find ACL %s", rp->aclname);
  477.             return;
  478.         }
  479.         rp->acllist = ap;
  480.         break;
  481.  
  482.     case ATYPE_PERMITUDPDSTHOSTPORT:
  483.     case ATYPE_PERMITTCPDSTHOSTPORT:
  484.         /* Use default ACL list for permit guys */
  485.         ap = aclfindlistdefault(cf, &rp->acl.addr1);
  486.         if (ap == NULL) {
  487.             clientsenderr(cl, rp,
  488.                 "can't find acllist for %s (is the default ACL"
  489.                 " for its address type missing?)",
  490.                 addr2str(&rp->acl.addr1));
  491.             return;
  492.         }
  493.         rp->acllist = ap;
  494.         break;
  495.  
  496.     default:
  497.         clientsenderr(cl, rp, "ACL type %d not implemented",
  498.             rp->acl.type);
  499.         return;
  500.     }
  501.  
  502.     /* Check if ACL should or should not already exist */
  503.     al = aclfindacl(ap, &rp->acl, 0);
  504.     switch (rp->type) {
  505.  
  506.     case REQ_DROP:
  507.         stats_setrate(&ap->stats);
  508.         tp = &rp->acl.addr1;
  509.         wp = whitelist(cf, tp);
  510.         if (wp != NULL) {
  511.             snprintf(buf, sizeof(buf), "%s", addr2str(tp));
  512.             clientsenderr(cl, rp, "%s is on the whitelist (%s)",
  513.                 buf, addr2str(wp));
  514.             return;
  515.         }
  516.  
  517.         if (al != NULL) {
  518.             rp->flags |= RFLAG_IGNORE;
  519.             clientsendfmt(cl, rp,
  520.                 "Note: %s is already blocked in ACL %s",
  521.                 addr2str(tp), ap->name);
  522.  
  523.             /* Log for NETS */
  524.             nets_log(sp, rp);
  525.             return;
  526.         }
  527.         break;
  528.  
  529.     case REQ_BLOCKHOSTHOST:
  530.         stats_setrate(&ap->stats);
  531.         tp = &rp->acl.addr1;
  532.         wp = whitelist(cf, tp);
  533.         if (wp == NULL) {
  534.             /* Check second address too */
  535.             tp = &rp->acl.addr2;
  536.             wp = whitelist(cf, tp);
  537.         }
  538.         if (wp != NULL) {
  539.             snprintf(buf, sizeof(buf), "%s", addr2str(tp));
  540.             clientsenderr(cl, rp, "%s is on the whitelist (%s)",
  541.                 buf, addr2str(wp));
  542.             return;
  543.         }
  544.  
  545.         if (al != NULL) {
  546.             rp->flags |= RFLAG_IGNORE;
  547.             snprintf(buf, sizeof(buf), "%s", addr2str(tp));
  548.             clientsendfmt(cl, rp,
  549.                 "Note: %s/%s is already blocked in ACL %s",
  550.                 buf, addr2str(&rp->acl.addr2), ap->name);
  551.  
  552.             /* Log for NETS */
  553.             nets_log(sp, rp);
  554.             return;
  555.         }
  556.         break;
  557.  
  558.     case REQ_DROPUDPPORT:
  559.     case REQ_DROPTCPPORT:
  560.         stats_setrate(&ap->stats);
  561.         if (al != NULL) {
  562.             rp->flags |= RFLAG_IGNORE;
  563.             clientsendfmt(cl, rp,
  564.                 "Note: %s/%s is already blocked in ACL %s",
  565.                 tcporudpreqstr(rp->type), rp->acl.port1, ap->name);
  566.  
  567.             /* Log for NETS */
  568.             nets_log(sp, rp);
  569.             return;
  570.         }
  571.         break;
  572.  
  573.     case REQ_PERMITUDPDSTHOSTPORT:
  574.     case REQ_PERMITTCPDSTHOSTPORT:
  575.         if (al != NULL) {
  576.             rp->flags |= RFLAG_IGNORE;
  577.             clientsendfmt(cl, rp,
  578.                 "Note: %s %s/%s is already permitted in ACL %s",
  579.                 addr2str(&rp->acl.addr1), tcporudpreqstr(rp->type),
  580.                 rp->acl.port1, ap->name);
  581.  
  582.             /* Log for NETS */
  583.             nets_log(sp, rp);
  584.             return;
  585.         }
  586.         break;
  587.  
  588.     case REQ_DROPTCPDSTHOSTPORT:
  589.         if (al != NULL) {
  590.             rp->flags |= RFLAG_IGNORE;
  591.             clientsendfmt(cl, rp,
  592.                 "Note: %s %s/%s is already blocked in ACL %s",
  593.                 addr2str(&rp->acl.addr1), tcporudpreqstr(rp->type),
  594.                 rp->acl.port1, ap->name);
  595.  
  596.             /* Log for NETS */
  597.             nets_log(sp, rp);
  598.             return;
  599.         }
  600.         break;
  601.  
  602.     case REQ_RESTORE:
  603.     case REQ_RESTOREHOSTHOST:
  604.         if (al == NULL) {
  605.             clientsenderr(cl, rp, "%s not found in ACL %s",
  606.                 addr2str(&rp->acl.addr1), ap->name);
  607.  
  608.             /* Log for NETS */
  609.             rp->flags |= RFLAG_IGNORE;
  610.             nets_log(sp, rp);
  611.             return;
  612.         }
  613.         break;
  614.  
  615.     case REQ_RESTOREUDPPORT:
  616.     case REQ_RESTORETCPPORT:
  617.         if (al == NULL) {
  618.             clientsenderr(cl, rp, "%s/%s not found in ACL %s",
  619.                 tcporudpreqstr(rp->type), rp->acl.port1, ap->name);
  620.  
  621.             /* Log for NETS */
  622.             rp->flags |= RFLAG_IGNORE;
  623.             nets_log(sp, rp);
  624.             return;
  625.         }
  626.         break;
  627.  
  628.     case REQ_UNPERMITUDPDSTHOSTPORT:
  629.     case REQ_UNPERMITTCPDSTHOSTPORT:
  630.     case REQ_RESTORETCPDSTHOSTPORT:
  631.         if (al == NULL) {
  632.             clientsenderr(cl, rp, "%s:%s/%s not found in ACL %s",
  633.                 addr2str(&rp->acl.addr1), tcporudpreqstr(rp->type),
  634.                 rp->acl.port1, ap->name);
  635.  
  636.             /* Log for NETS */
  637.             rp->flags |= RFLAG_IGNORE;
  638.             nets_log(sp, rp);
  639.             return;
  640.         }
  641.         break;
  642.  
  643.     default:
  644.         lg(LOG_ERR, "childdroprestore: bad type %d (1)", rp->type);
  645.         exit(EX_SOFTWARE);
  646.     }
  647.  
  648.     /* If removing an ACL, check that its seq number is in the range */
  649.     switch (rp->type) {
  650.  
  651.     case REQ_RESTORE:
  652.     case REQ_RESTOREHOSTHOST:
  653.         /* Host sequence range */
  654.         if (al->seq < cf->c_lowseq || al->seq > cf->c_highseq) {
  655.             clientsenderr(cl, rp,
  656.                 "seq %d in ACL %s not in host seq range (%d-%d)",
  657.                 al->seq, ap->name, cf->c_lowseq, cf->c_highseq);
  658.  
  659.             /* Log for NETS */
  660.             rp->flags |= RFLAG_IGNORE;
  661.             nets_log(sp, rp);
  662.             return;
  663.         }
  664.         break;
  665.  
  666.     case REQ_RESTOREUDPPORT:
  667.     case REQ_RESTORETCPPORT:
  668.         /* Port sequence range */
  669.         if (al->seq < cf->c_lowportseq || al->seq > cf->c_highportseq) {
  670.             clientsenderr(cl, rp,
  671.                 "seq %d in ACL %s not in port seq range (%d-%d)",
  672.                 al->seq, ap->name,
  673.                 cf->c_lowportseq, cf->c_highportseq);
  674.  
  675.             /* Log for NETS */
  676.             rp->flags |= RFLAG_IGNORE;
  677.             nets_log(sp, rp);
  678.             return;
  679.         }
  680.         break;
  681.  
  682.     case REQ_UNPERMITUDPDSTHOSTPORT:
  683.     case REQ_UNPERMITTCPDSTHOSTPORT:
  684.     case REQ_RESTORETCPDSTHOSTPORT:
  685.         /* Permit host/port sequence range */
  686.         if (al->seq < cf->c_lowpermithostportseq ||
  687.             al->seq > cf->c_highpermithostportseq) {
  688.             clientsenderr(cl, rp,
  689.                 "seq %d in ACL %s not in port seq range (%d-%d)",
  690.                 al->seq, ap->name,
  691.                 cf->c_lowpermithostportseq,
  692.                 cf->c_highpermithostportseq);
  693.  
  694.             /* Log for NETS */
  695.             rp->flags |= RFLAG_IGNORE;
  696.             nets_log(sp, rp);
  697.             return;
  698.         }
  699.         break;
  700.  
  701.     default:
  702.         break;
  703.     }
  704.  
  705.     /* Add or remove the ACL */
  706.     switch (rp->type) {
  707.  
  708.     case REQ_DROP:
  709.     case REQ_BLOCKHOSTHOST:
  710.         /* Are we moving up or down? */
  711.         if (cf->c_incrseq) {
  712.             if (cf->c_highseq >= 0 &&
  713.                 ap->lastseq >= cf->c_highseq) {
  714.                 (void)snprintf(buf, sizeof(buf),
  715.                     "Last sequence number in ACL %s"
  716.                     " already in use (%d)",
  717.                     ap->name, cf->c_highseq);
  718.                 clientsenderr(cl, rp, "%s", buf);
  719.                 syslog(LOG_INFO, "%s", buf);
  720.                 return;
  721.             }
  722.         } else {
  723.             if (cf->c_lowseq >= 0 &&
  724.                 ap->lastseq <= cf->c_lowseq) {
  725.                 (void)snprintf(buf, sizeof(buf),
  726.                     "First sequence number in ACL %s"
  727.                     " already in use (%d)",
  728.                     ap->name, cf->c_lowseq);
  729.                 clientsenderr(cl, rp, "%s", buf);
  730.                 syslog(LOG_INFO, "%s", buf);
  731.                 return;
  732.             }
  733.         }
  734.  
  735.         /* Check cap and limits */
  736.         p = checklimits(cf, ap);
  737.         if (p != NULL) {
  738.             clientsenderr(cl, rp, "%s", p);
  739.             syslog(LOG_INFO, "%s", p);
  740.             return;
  741.         }
  742.  
  743.         if (cf->c_incrseq)
  744.             rp->acl.seq = ++ap->lastseq;
  745.         else
  746.             rp->acl.seq = --ap->lastseq;
  747.  
  748.         /* Add here to avoid the race (remove later if it fails) */
  749.         acladdacl(ap, &rp->acl);
  750.         break;
  751.  
  752.     case REQ_DROPUDPPORT:
  753.     case REQ_DROPTCPPORT:
  754.         if (cf->c_highportseq >= 0 &&
  755.             ap->lastportseq >= cf->c_highportseq) {
  756.             clientsenderr(cl, rp,
  757.                 "Last port sequence number in ACL %s"
  758.                 " already in use (%d)",
  759.                 ap->name, cf->c_highportseq);
  760.             return;
  761.         }
  762.  
  763.         /* Check cap and limits */
  764.         p = checklimits(cf, ap);
  765.         if (p != NULL) {
  766.             clientsenderr(cl, rp, "%s", p);
  767.             syslog(LOG_INFO, "%s", p);
  768.             return;
  769.         }
  770.  
  771.         rp->acl.seq = ++ap->lastportseq;
  772.  
  773.         /* Add here to avoid the race (remove later if it fails) */
  774.         acladdacl(ap, &rp->acl);
  775.         break;
  776.  
  777.     case REQ_PERMITUDPDSTHOSTPORT:
  778.     case REQ_PERMITTCPDSTHOSTPORT:
  779.     case REQ_DROPTCPDSTHOSTPORT:
  780.         if (cf->c_highpermithostportseq >= 0 &&
  781.             ap->lastpermithostportseq >=
  782.             cf->c_highpermithostportseq) {
  783.             clientsenderr(cl, rp,
  784.                 "Last permit host/port sequence number in ACL %s"
  785.                 " already in use (%d)",
  786.                 ap->name, cf->c_highpermithostportseq);
  787.             return;
  788.         }
  789.  
  790.         /* Check cap and limits */
  791.         p = checklimits(cf, ap);
  792.         if (p != NULL) {
  793.             clientsenderr(cl, rp, "%s", p);
  794.             syslog(LOG_INFO, "%s", p);
  795.             return;
  796.         }
  797.  
  798.         rp->acl.seq = ++ap->lastpermithostportseq;
  799.  
  800.         /* Add here to avoid the race (remove later if it fails) */
  801.         acladdacl(ap, &rp->acl);
  802.         break;
  803.  
  804.     case REQ_RESTORE:
  805.     case REQ_RESTOREHOSTHOST:
  806.     case REQ_RESTOREUDPPORT:
  807.     case REQ_RESTORETCPPORT:
  808.     case REQ_UNPERMITUDPDSTHOSTPORT:
  809.     case REQ_UNPERMITTCPDSTHOSTPORT:
  810.     case REQ_RESTORETCPDSTHOSTPORT:
  811.         rp->acl.seq = al->seq;
  812.  
  813.         /* Remove here to avoid the race (restore later if it fails) */
  814.         if (!acldeleteacl(ap, &rp->acl)) {
  815.             lg(LOG_ERR, "childdroprestore: acldeleteacl failed");
  816.             exit(EX_SOFTWARE);
  817.         }
  818.         break;
  819.  
  820.     default:
  821.         lg(LOG_ERR, "childdroprestore: bad type %d (2)", rp->type);
  822.         exit(EX_SOFTWARE);
  823.     }
  824.  
  825.     /* Send the request to the child */
  826.     switch (rp->acl.type) {
  827.  
  828.     case ATYPE_BLOCKHOST:
  829.         childsend(sp, "%s %s %s %d",
  830.             rp->cmd, addr2str(&rp->acl.addr1), ap->name, rp->acl.seq);
  831.         break;
  832.  
  833.     case ATYPE_BLOCKNET:
  834.         childsend(sp, "%s %s %s %d",
  835.             rp->cmd, addr2str(&rp->acl.addr1), ap->name, rp->acl.seq);
  836.         break;
  837.  
  838.     case ATYPE_BLOCKHOSTHOST:
  839.         (void)snprintf(buf, sizeof(buf), "%s",
  840.             addr2str(&rp->acl.addr2));
  841.         childsend(sp, "%s %s %s %s %d",
  842.             rp->cmd, addr2str(&rp->acl.addr1), buf,
  843.             ap->name, rp->acl.seq);
  844.         break;
  845.  
  846.     case ATYPE_BLOCKUDPPORT:
  847.     case ATYPE_BLOCKTCPPORT:
  848.         childsend(sp, "%s %s %s %d",
  849.             rp->cmd, rp->acl.port1, ap->name, rp->acl.seq);
  850.         break;
  851.  
  852.     case ATYPE_PERMITUDPDSTHOSTPORT:
  853.     case ATYPE_PERMITTCPDSTHOSTPORT:
  854.     case ATYPE_BLOCKTCPDSTHOSTPORT:
  855.         childsend(sp, "%s %s %s %s %d",
  856.             rp->cmd, addr2str(&rp->acl.addr1), rp->acl.port1,
  857.             ap->name, rp->acl.seq);
  858.         break;
  859.  
  860.     default:
  861.         lg(LOG_ERR, "childdroprestore: bad atype %d", rp->acl.type);
  862.         exit(EX_SOFTWARE);
  863.     }
  864.  
  865.     /* Update request state */
  866.     rp->state = RSTATE_CHILD;
  867.  
  868.     /* Schedule a sync */
  869.     if (cf->c_sync_secs > 0 && timercheck(&sp->t_sync) < 0)
  870.         timerset(&sp->t_sync, cf->c_sync_secs);
  871. }
  872.  
  873. void
  874. childkill(struct state *sp)
  875. {
  876.  
  877.     if (sp->wfd >= 0 && sp->state == ASTATE_LOGGEDIN)
  878.         childsend(sp, "logout");
  879.     sp->state = ASTATE_NOTCONNECTED;
  880.     sp->cmd = NULL;
  881.  
  882.     errno = 0;
  883.     if (sp->pid > 0 && kill(sp->pid, SIGTERM) < 0 && errno != ESRCH)
  884.         lg(LOG_ERR, "childkill: kill %d: %s",
  885.             (int)sp->pid, strerror(errno));
  886.  
  887.     sp->pid = -1;
  888.     if (sp->rfd >= 0)
  889.         close(sp->rfd);
  890.     sp->rfd = -1;
  891.  
  892.     if (sp->wfd >= 0)
  893.         close(sp->wfd);
  894.     sp->wfd = -1;
  895.  
  896.     iofree(&sp->rbuf);
  897.  
  898.     timerset(&sp->t_ayt, 0);
  899.     timerset(&sp->t_login, 0);
  900.     timerset(&sp->t_sync, 0);
  901. }
  902.  
  903. void
  904. childlistacl(struct state *sp)
  905. {
  906.     int i;
  907.     struct acllist *ap;
  908.     struct cf *cf;
  909.  
  910.     cf = sp->cf;
  911.     for (i = 0, ap = cf->c_acllist; i < cf->c_acllistlen; ++i, ++ap)
  912.         if (!ap->sentlistacl) {
  913.             sp->state = ASTATE_SENTLISTACL;
  914.             sp->cmd = "listacl";
  915.             childsend(sp, "%s %s {%s}",
  916.                 sp->cmd, ap->name, ap->intlist->i_name);
  917.             ++ap->sentlistacl;
  918.             return;
  919.         }
  920.  
  921.     /* If we got here, we've listed all the ACLs; sort 'em */
  922.     ++sp->listedallacls;
  923.     aclsortacls(cf);
  924. }
  925.  
  926. /* XXX Should we only do this if nullzero routes if enabled? */
  927. void
  928. childlistroute(struct state *sp)
  929. {
  930.  
  931.     routelistsfree(sp);
  932.     sp->state = ASTATE_SENTLISTROUTE;
  933.     sp->cmd = "listroute";
  934.     childsend(sp, "%s", sp->cmd);
  935.     ++sp->listedroutes;
  936. }
  937.  
  938. void
  939. childlogin(struct state *sp)
  940. {
  941.     int odebug;
  942.     struct cf *cf;
  943.  
  944.     cf = sp->cf;
  945.  
  946.     /* Free ACL lists so we'll re-aquire them from the router */
  947.     acllistsfree(sp);
  948.  
  949.     /* Zero out attr status */
  950.     attrclear(sp);
  951.  
  952.     /* Free routes so we'll re-aquire them from the router */
  953.     routelistsfree(sp);
  954.  
  955.     sp->state = ASTATE_SENTLOGIN;
  956.     sp->cmd = "login";
  957.     odebug = debug;
  958.     if (odebug) {
  959.         /* Avoid exposing router passwords in debugging output */
  960.         debug = 0;
  961.         fprintf(lf, "%s childsend: \"%s %s %s %s %s %s %s %s\"\n",
  962.             tsstr(),
  963.             sp->cmd,
  964.             cf->c_router,
  965.             cf->c_cuser,
  966.             "?",
  967.             "?",
  968.             cf->c_euser,
  969.             "?",
  970.             "?");
  971.     }
  972.     childsend(sp, "%s %s %s %s %s %s %s %s",
  973.         sp->cmd,
  974.         cf->c_router,
  975.         cf->c_cuser,
  976.         cf->c_cpass1,
  977.         cf->c_cpass2,
  978.         cf->c_euser,
  979.         cf->c_epass1,
  980.         cf->c_epass2);
  981.     debug = odebug;
  982.     timerreset(&sp->t_ayt);
  983.     timerreset(&sp->t_sync);
  984. }
  985.  
  986. void
  987. childnullzero(struct state *sp, struct client *cl, struct req *rp)
  988. {
  989.     struct cf *cf;
  990.     struct route *rtp;
  991.     struct addr *wp;
  992.     const char *p;
  993.     char buf[64];
  994.  
  995.     if (rp->nullzero.type != ROUTE_NULLZERO) {
  996.         lg(LOG_ERR, "childnullzero: bad routetype %d",
  997.             rp->nullzero.type);
  998.         exit(EX_SOFTWARE);
  999.     }
  1000.  
  1001.     cf = sp->cf;
  1002.     /*
  1003.      * Everything is ok (subject to whitelist check) if no
  1004.      * configured nullzero nets
  1005.      */
  1006.     if (cf->c_nullzeronets != NULL &&
  1007.         !goodnullzero(cf, &rp->nullzero.dst)) {
  1008.         clientsenderr(cl, rp, "%s not part of a configured nullzeronet",
  1009.             addr2str(&rp->nullzero.dst));
  1010.         return;
  1011.     }
  1012.  
  1013.     rtp = routefind(sp, &rp->nullzero);
  1014.  
  1015.     switch (rp->type) {
  1016.  
  1017.     case REQ_NULLZERO:
  1018.         stats_setrate(&sp->nullzerostats);
  1019.         wp = whitelist(cf, &rp->nullzero.dst);
  1020.         if (wp != NULL) {
  1021.             snprintf(buf, sizeof(buf), "%s",
  1022.                 addr2str(&rp->nullzero.dst));
  1023.             clientsenderr(cl, rp, "%s is on the whitelist (%s)",
  1024.                 buf, addr2str(wp));
  1025.             return;
  1026.         }
  1027.         if (rtp != NULL) {
  1028.             rp->flags |= RFLAG_IGNORE;
  1029.             clientsendfmt(cl, rp,
  1030.                 "Note: %s is already nullzero routed",
  1031.                 addr2str(&rp->nullzero.dst));
  1032.  
  1033.             /* Log for NETS */
  1034.             nets_log(sp, rp);
  1035.             return;
  1036.         }
  1037.  
  1038.         p = checkmaskwidth(cf, &rp->nullzero.dst);
  1039.         if (p != NULL) {
  1040.             clientsenderr(cl, rp, "%s", p);
  1041.             return;
  1042.         }
  1043.  
  1044.         if (cf->c_nullzeromax != 0 &&
  1045.             sp->nullzerolen >= cf->c_nullzeromax) {
  1046.             rp->flags |= RFLAG_IGNORE;
  1047.             clientsenderr(cl, rp,
  1048.                 "Too many nullzero routes (%d in use, %d allowed)",
  1049.                 sp->nullzerolen, cf->c_nullzeromax);
  1050.  
  1051.             /* Log for NETS */
  1052.             nets_log(sp, rp);
  1053.             return;
  1054.         }
  1055.  
  1056.         /* Add here to avoid the race (remove later if it fails) */
  1057.         routeadd(sp, &rp->nullzero);
  1058.  
  1059.         /* Queue up the command */
  1060.         childsend(sp, "%s %s", rp->cmd, addr2str(&rp->nullzero.dst));
  1061.         break;
  1062.  
  1063.     case REQ_NONULLZERO:
  1064.         if (rtp == NULL) {
  1065.             rp->flags |= RFLAG_IGNORE;
  1066.             clientsenderr(cl, rp, "%s not found",
  1067.                 addr2str(&rp->nullzero.dst));
  1068.             return;
  1069.         }
  1070.  
  1071.         p = checkmaskwidth(cf, &rp->nullzero.dst);
  1072.         if (p != NULL) {
  1073.             clientsenderr(cl, rp, "%s", p);
  1074.             return;
  1075.         }
  1076.  
  1077.         /* Remove here to avoid the race (restore later if it fails) */
  1078.         if (!routedelete(sp, &rp->nullzero)) {
  1079.             lg(LOG_ERR, "childnullzero: deleteroute failed");
  1080.             exit(EX_SOFTWARE);
  1081.         }
  1082.  
  1083.         /* Queue up the command */
  1084.         childsend(sp, "%s %s", rp->cmd, addr2str(&rp->nullzero.dst));
  1085.         break;
  1086.  
  1087.     default:
  1088.         lg(LOG_ERR, "childnullzero: bad type %d (1)", rp->type);
  1089.         exit(EX_SOFTWARE);
  1090.     }
  1091.  
  1092.     /* Update request state */
  1093.     rp->state = RSTATE_CHILD;
  1094.  
  1095.     /* Schedule a sync */
  1096.     if (cf->c_sync_secs > 0 && timercheck(&sp->t_sync) < 0)
  1097.         timerset(&sp->t_sync, cf->c_sync_secs);
  1098. }
  1099.  
  1100. static int
  1101. childresponse(char **pp, struct state *sp)
  1102. {
  1103.     char *cp;
  1104.     struct iobuf *ip;
  1105.  
  1106.     /* Look for end of message (and strip leading dots) */
  1107.     ip = &sp->rbuf;
  1108.     while ((cp = iogetstr(ip)) != NULL) {
  1109.         if (*cp == '.') {
  1110.             ++cp;
  1111.             if (*cp == '\0' || *cp == '\n')
  1112.                 return (1);
  1113.         }
  1114.         strappend(pp, cp);
  1115.     }
  1116.     return(0);
  1117. }
  1118.  
  1119. void
  1120. childsend(struct state *sp, const char *fmt, ...)
  1121. {
  1122.     char *cp;
  1123.     size_t n;
  1124.     ssize_t cc;
  1125.     char buf[1024];
  1126.     va_list ap;
  1127.  
  1128.     va_start(ap, fmt);
  1129.     (void)vsnprintf(buf, sizeof(buf) - 1, fmt, ap);
  1130.     va_end(ap);
  1131.     n = strlen(buf);
  1132.     cp = buf + n - 1;
  1133.  
  1134.     if (debug)
  1135.         fprintf(lf, "%s childsend: \"%s\"\n", tsstr(), buf);
  1136.  
  1137.     if (cp >= buf) {
  1138.         *++cp = '\n';
  1139.         *++cp = '\0';
  1140.         ++n;
  1141.     }
  1142.     cc = write(sp->wfd, buf, n);
  1143.     if (cc < 0) {
  1144.         /* XXX close off child here? */
  1145.         lg(LOG_ERR, "childsend: write: %s", strerror(errno));
  1146.         return;
  1147.     }
  1148.     if (cc != n) {
  1149.         lg(LOG_ERR, "childsend: short write (%d != %d)",
  1150.             (int)cc, (int)n);
  1151.         return;
  1152.     }
  1153. }
  1154.  
  1155. void
  1156. childsendattr(struct state *sp)
  1157. {
  1158.     int i, didany;
  1159.     struct cf *cf;
  1160.     struct attrlist *atp;
  1161.  
  1162.     cf = sp->cf;
  1163.     didany = 0;
  1164.     for (i = 0, atp = cf->c_attrlist; i < cf->c_attrlistlen; ++i, ++atp)
  1165.         if (!atp->a_sentattr) {
  1166.             sp->state = ASTATE_SENTATTR;
  1167.             sp->cmd = "attr";
  1168.             childsend(sp, "%s", attrfmt(atp));
  1169.             ++atp->a_sentattr;
  1170.             ++didany;
  1171.             break;
  1172.         }
  1173.     if (!didany)
  1174.         ++sp->sentattrs;
  1175. }
  1176.  
  1177. static int
  1178. failed(const char *what, const char *str)
  1179. {
  1180.     size_t len;
  1181.  
  1182.     len = strlen(what);
  1183.     if (strncmp(what, str, len) == 0 && strcmp(str + len, "-failed") == 0)
  1184.         return (1);
  1185.     return (0);
  1186. }
  1187.