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 / cforce.c < prev    next >
C/C++ Source or Header  |  2012-02-08  |  16KB  |  692 lines

  1. /*
  2.  * Copyright (c) 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: cforce.c 807 2012-02-09 00:57:40Z leres $ (LBL)";
  25. #endif
  26.  
  27. #include <sys/types.h>
  28. #include <sys/mman.h>
  29. #include <sys/stat.h>
  30. #include <sys/time.h>
  31.  
  32. #include <netinet/in.h>
  33.  
  34. #include <arpa/inet.h>
  35.  
  36. #include <ctype.h>
  37. #include <errno.h>
  38. #include <fcntl.h>
  39. #include <stdio.h>
  40. #include <stdlib.h>
  41. #include <string.h>
  42. #include <sysexits.h>
  43. #include <syslog.h>
  44. #include <unistd.h>
  45.  
  46. #include <cforce.h>
  47.  
  48. #include "acld.h"
  49. #include "cforcep.h"
  50. #include "util.h"
  51.  
  52. /* Locals */
  53. struct s2v cforceerr2str[] = {
  54.     { "GENERAL",            ERROR_GENERAL },
  55.     { "COMMUNICATION",        ERROR_COMMUNICATION },
  56.     { "INVALID_IP_ADDRESS",        ERROR_INVALID_IP_ADDRESS },
  57.     { "ADDRESS_ALREADY_PROVISIONED", ERROR_ADDRESS_ALREADY_PROVISIONED },
  58.     { "HOST_ALREADY_BLOCKED",    ERROR_HOST_ALREADY_BLOCKED },
  59.     { "INVALID_ID",            ERROR_INVALID_ID },
  60.     { "CAPACITY_EXCEEDED",        ERROR_CAPACITY_EXCEEDED },
  61.     { "INVALID_RULE",        ERROR_INVALID_RULE },
  62.     { "BOTH_NOT_SUPPORTED",        ERROR_BOTH_NOT_SUPPORTED },
  63.     { "CONVERSATION_ALREADY_BLOCKED", ERROR_CONVERSATION_ALREADY_BLOCKED },
  64.     { "NOT_INITIALIZED",        ERROR_NOT_INITIALIZED },
  65.     { "INVALID_ARGUMENTS",        ERROR_INVALID_ARGUMENTS },
  66.     { "INVALID_CONNECTION_PARAMETERS",
  67.                     ERROR_INVALID_CONNECTION_PARAMETERS },
  68.     { "ALL_RULE_PROVISIONED",    ERROR_ALL_RULE_PROVISIONED },
  69.     { "RULE_CONFLICT",        ERROR_RULE_CONFLICT },
  70.     { "INVALID_COMBINATION",    ERROR_INVALID_COMBINATION },
  71.     { "COULD_NOT_OPEN_FILE",    ERROR_COULD_NOT_OPEN_FILE },
  72.     { "COULD_NOT_WRITE_TO_FD",    ERROR_COULD_NOT_WRITE_TO_FD },
  73.     { "DATA_STRUCTURE_INCONSISTENCY", ERROR_DATA_STRUCTURE_INCONSISTENCY },
  74. };
  75.  
  76. struct cforceseq {
  77.     enum acltype type;
  78.     int dir;
  79.     struct addr addr1;
  80.     struct addr addr2;
  81. };
  82.  
  83. static int md = -1;
  84. struct cforceseq *cforceseq;
  85.  
  86. /* XXX doesn't include hosthost or IPv6 rules */
  87. #define NUMRULES 64000
  88. size_t cforceseqsize = sizeof(*cforceseq) * NUMRULES;
  89.  
  90. /* Forwards */
  91. static int acl2dir(struct acllist *);
  92. static int cforce_drophost(int, struct addr *);
  93. static int cforce_drophosthost(int, struct addr *, struct addr *);
  94. static void cforcemapfile(const char *fn);
  95. static void cforcemsync(void);
  96. static void cforceunmapfile(void);
  97.  
  98. static int
  99. acl2dir(struct acllist *ap)
  100. {
  101.     const char *interface;
  102.  
  103.     interface = ap->intlist->i_name;
  104.     if (strcasecmp(interface, "outside") == 0)
  105.         return (OUTSIDE);
  106.     if (strcasecmp(interface, "inside") == 0)
  107.         return (INSIDE);
  108.     return (-1);
  109. }
  110.  
  111. static int
  112. cforce_drophost(int dir, struct addr *addr)
  113. {
  114.     int (*drop_host_func)(block_direction_enum_t, char *);
  115.  
  116.     if (addr->family == AF_INET)
  117.         drop_host_func = drop_host;
  118.     else
  119.         drop_host_func = drop_ipv6_host;
  120.     return ((drop_host_func)(dir, (char *)addr2str(addr)));
  121. }
  122.  
  123. static int
  124. cforce_drophosthost(int dir, struct addr *addr1, struct addr *addr2)
  125. {
  126.     char saddr1[128];
  127.  
  128.     int (*drop_hosthost_func)(rule_port_enum_t, char *, char *);
  129.  
  130.     if (addr1->family == AF_INET)
  131.         drop_hosthost_func = drop_conversation;
  132.     else
  133.         drop_hosthost_func = drop_ipv6_conversation;
  134.     strncpy(saddr1, addr2str(addr1), sizeof(saddr1));
  135.     saddr1[sizeof(saddr1) - 1] = '\0';
  136.     return ((drop_hosthost_func)(dir, saddr1, (char *)addr2str(addr2)));
  137. }
  138.  
  139. /* Assume if we can get the appliance counters that it's alive */
  140. void
  141. cforceayt(struct state *sp)
  142. {
  143.     int rc;
  144.     cforce_counters_t counters;
  145.  
  146.     rc = get_counters(&counters);
  147.     if (rc < 0) {
  148.         if (sp->state != ASTATE_NOTCONNECTED) {
  149.             lg(LOG_DEBUG, "cforceayt: not connected");
  150.             sp->state = ASTATE_NOTCONNECTED;
  151.         }
  152.     }
  153. }
  154.  
  155. void
  156. cforcecompact(struct state *sp)
  157. {
  158.     lg(LOG_DEBUG, "cforcecompact: noop");
  159. }
  160.  
  161. void
  162. cforcedroprestore(struct state *sp, struct client *cl, struct req *rp)
  163. {
  164.     int rc, dir, seq;
  165.     const char *p, *what;
  166.     struct acllist *ap;
  167.     struct acl *al;
  168.     struct addr *wp, *tp;
  169.     struct cf *cf;
  170.     struct cforceseq *cs;
  171.     char buf[132];
  172.  
  173.     /* Find ACL list */
  174.     cf = sp->cf;
  175.     switch (rp->acl.type) {
  176.  
  177.     case ATYPE_BLOCKHOST:
  178.     case ATYPE_BLOCKHOSTHOST:
  179.         /* By address */
  180.         ap = aclfindlistbyaddr(cf, &rp->acl.addr1);
  181.         if (ap == NULL) {
  182.             clientsenderr(cl, rp, "can't find acllist for %s"
  183.                 " (is the default ACL missing?)",
  184.                 addr2str(&rp->acl.addr1));
  185.             return;
  186.         }
  187.         rp->acllist = ap;
  188.         break;
  189.  
  190.     default:
  191.         clientsenderr(cl, rp, "ATYPE %s not implemented",
  192.             val2str(str2acl, rp->acl.type));
  193.         return;
  194.     }
  195.  
  196.     /* Check if ACL should or should not already exist */
  197.     al = aclfindacl(ap, &rp->acl, 0);
  198.     switch (rp->type) {
  199.  
  200.     case REQ_DROP:
  201.         stats_setrate(&ap->stats);
  202.         tp = &rp->acl.addr1;
  203.         wp = whitelist(cf, tp);
  204.         if (wp != NULL) {
  205.             snprintf(buf, sizeof(buf), "%s", addr2str(tp));
  206.             clientsenderr(cl, rp, "%s is on the whitelist (%s)",
  207.                 buf, addr2str(wp));
  208.             return;
  209.         }
  210.  
  211.         if (al != NULL) {
  212.             rp->flags |= RFLAG_IGNORE;
  213.             clientsendfmt(cl, rp,
  214.                 "Note: %s is already blocked in ACL %s",
  215.                 addr2str(tp), ap->name);
  216.  
  217.             /* Log for NETS */
  218.             nets_log(sp, rp);
  219.             return;
  220.         }
  221.         break;
  222.  
  223.     case REQ_BLOCKHOSTHOST:
  224.         stats_setrate(&ap->stats);
  225.         tp = &rp->acl.addr1;
  226.         wp = whitelist(cf, tp);
  227.         if (wp == NULL) {
  228.             /* Check second address too */
  229.             tp = &rp->acl.addr2;
  230.             wp = whitelist(cf, tp);
  231.         }
  232.         if (wp != NULL) {
  233.             snprintf(buf, sizeof(buf), "%s", addr2str(tp));
  234.             clientsenderr(cl, rp, "%s is on the whitelist (%s)",
  235.                 buf, addr2str(wp));
  236.             return;
  237.         }
  238.  
  239.         if (al != NULL) {
  240.             rp->flags |= RFLAG_IGNORE;
  241.             snprintf(buf, sizeof(buf), "%s", addr2str(tp));
  242.             clientsendfmt(cl, rp,
  243.                 "Note: %s/%s is already blocked in ACL %s",
  244.                 buf, addr2str(&rp->acl.addr2), ap->name);
  245.  
  246.             /* Log for NETS */
  247.             nets_log(sp, rp);
  248.             return;
  249.         }
  250.         break;
  251.  
  252.     case REQ_RESTORE:
  253.     case REQ_RESTOREHOSTHOST:
  254.         if (al == NULL) {
  255.             rp->flags |= RFLAG_IGNORE;
  256.             clientsenderr(cl, rp, "%s not found in ACL %s",
  257.                 addr2str(&rp->acl.addr1), ap->name);
  258.  
  259.             /* Log for NETS */
  260.             nets_log(sp, rp);
  261.             return;
  262.         }
  263.         break;
  264.  
  265.     default:
  266.         lg(LOG_ERR, "cforcedroprestore: bad type %d (1)", rp->type);
  267.         exit(EX_SOFTWARE);
  268.     }
  269.  
  270.     /* Add or remove the ACL */
  271.     switch (rp->type) {
  272.  
  273.     case REQ_DROP:
  274.     case REQ_BLOCKHOSTHOST:
  275.         /* Check cap and limits */
  276.         p = checklimits(cf, ap);
  277.         if (p != NULL) {
  278.             clientsenderr(cl, rp, "%s", p);
  279.             syslog(LOG_INFO, "%s", p);
  280.             return;
  281.         }
  282.  
  283.         /* Add the rule */
  284.         if (rp->type == REQ_DROP) {
  285.             /* Determine cForce direction */
  286.             dir = acl2dir(ap);
  287.             if (dir < 0) {
  288.                 (void)snprintf(buf, sizeof(buf),
  289.                     "Direction for ACL %s undefined", ap->name);
  290.                 clientsenderr(cl, rp, "%s", buf);
  291.                 syslog(LOG_INFO, "%s", buf);
  292.                 return;
  293.             }
  294.             rc = cforce_drophost(dir, &rp->acl.addr1);
  295.             what = "cforce_drophost";
  296.         } else {
  297.             dir = CFORCE_BOTH_PORTS;
  298.             rc = cforce_drophosthost(dir, &rp->acl.addr1,
  299.                 &rp->acl.addr2);
  300.             what = "cforce_drophosthost";
  301.         }
  302.         if (rc < 0) {
  303.             (void)snprintf(buf, sizeof(buf), "%s failed: %s",
  304.                 what, val2str(cforceerr2str, rc));
  305.             lg(LOG_ERR, "cforcedroprestore: %s", buf);
  306.             if (rc == ERROR_CAPACITY_EXCEEDED) {
  307.                 clientsenderr(cl, rp, "%s", buf);
  308.                 return;
  309.             }
  310.             exit(EX_SOFTWARE);
  311.         }
  312.  
  313.         /* Assign sequence number */
  314.         rp->acl.seq = rc;
  315.  
  316.         /* Sanity */
  317.         cs = cforceseq + rp->acl.seq;
  318.         if (cs->type != ATYPE_UNKNOWN) {
  319.             lg(LOG_ERR, "cforcedroprestore: %s failed:"
  320.                 " cforceseq slot %d already in use",
  321.                 what, rp->acl.seq);
  322.             exit(EX_SOFTWARE);
  323.         }
  324.  
  325.         /* Update our data structure */
  326.         acladdacl(ap, &rp->acl);
  327.  
  328.         /* Update mmap file */
  329.         cs->dir = dir;
  330.         if (rp->type == REQ_DROP) {
  331.             cs->type = ATYPE_BLOCKHOST;
  332.             cs->addr1 = rp->acl.addr1;
  333.         } else {
  334.             cs->type = ATYPE_BLOCKHOSTHOST;
  335.             cs->addr1 = rp->acl.addr1;
  336.             cs->addr2 = rp->acl.addr2;
  337.         }
  338.  
  339.         /* Always sort after assigning new sequence numbers */
  340.         aclsortacls(cf);
  341.         break;
  342.  
  343.     case REQ_RESTORE:
  344.     case REQ_RESTOREHOSTHOST:
  345.         /* Save a copy of the sequence number before it gets zeroed */
  346.         seq = al->seq;
  347.  
  348.         /* Delete the rule */
  349.         rc = delete_rule(seq);
  350.         if (rc < 0) {
  351.             lg(LOG_ERR,
  352.                 "cforcedroprestore: delete_rule(%d) failed: %s",
  353.                 seq, val2str(cforceerr2str, rc));
  354.             exit(EX_SOFTWARE);
  355.         }
  356.  
  357.         /* Remove from our data structure */
  358.         if (!acldeleteacl(ap, &rp->acl)) {
  359.             lg(LOG_ERR, "cforcedroprestore: acldeleteacl failed");
  360.             exit(EX_SOFTWARE);
  361.         }
  362.  
  363.         /* Update mmap file */
  364.         cs = cforceseq + seq;
  365.         memset(cs, 0, sizeof(*cs));
  366.         break;
  367.  
  368.     default:
  369.         lg(LOG_ERR, "cforcedroprestore: bad type %d (2)", rp->type);
  370.         exit(EX_SOFTWARE);
  371.     }
  372.  
  373.     /* Update mmap file */
  374.     cforcemsync();
  375.  
  376.     /* Log for NETS */
  377.     nets_log(sp, rp);
  378.  
  379.     clientsend(cl, rp);
  380. }
  381.  
  382. void
  383. cforceinit(struct state *sp)
  384. {
  385.     sp->f_ayt = cforceayt;
  386.     sp->f_compact = cforcecompact;
  387.     sp->f_droprestore = cforcedroprestore;
  388.     sp->f_kill = cforcekill;
  389.     sp->f_listacl = cforcelistacl;
  390.     sp->f_listroute = cforcelistroute;
  391.     sp->f_login = cforcelogin;
  392.     sp->f_nullzero = cforcenullzero;
  393.     sp->f_send = cforcesend;
  394.     sp->f_sendattr = cforcesendattr;
  395.     sp->f_sync = cforcesync;
  396. }
  397.  
  398. int
  399. cforceinput(struct state *sp, struct client *cl)
  400. {
  401.     /* XXX Shouldn't be able to get here */
  402.     abort();
  403. }
  404.  
  405. void
  406. cforcekill(struct state *sp)
  407. {
  408.     sp->state = ASTATE_NOTCONNECTED;
  409.     timerset(&sp->t_ayt, 0);
  410.     timerset(&sp->t_login, 0);
  411.     timerset(&sp->t_sync, 0);
  412. }
  413.  
  414. void
  415. cforcelistacl(struct state *sp)
  416. {
  417.     aclsortacls(sp->cf);
  418.     ++sp->listedallacls;
  419. }
  420.  
  421. void
  422. cforcelistroute(struct state *sp)
  423. {
  424.     ++sp->listedroutes;
  425. }
  426.  
  427. void
  428. cforcelogin(struct state *sp)
  429. {
  430.     int rc, i;
  431.     struct cf *cf;
  432.     const char *what;
  433.     struct acllist *ap;
  434.     struct cforceseq *cforceseq2, *cs, *cs2;
  435.     struct acl acl;
  436.     static int init = 0;
  437.  
  438.     cf = sp->cf;
  439.     if (!init) {
  440.         rc = cforce_initialize(sp->cf->c_cforceaddr,
  441.             sp->cf->c_portcforce);
  442.         if (rc < 0) {
  443.             lg(LOG_ERR, "cforcelogin: cforce_initialize failed: %s",
  444.                 val2str(cforceerr2str, rc));
  445.             sp->state = ASTATE_NOTCONNECTED;
  446.             return;
  447.         }
  448.         ++init;
  449.     } else {
  450.         lg(LOG_INFO, "cforcelogin: unmapping cforce data file");
  451.         cforceunmapfile();
  452.     }
  453.  
  454.     /* Zero rules in appliance */
  455.     rc = clear_rules();
  456.     if (rc < 0) {
  457.         lg(LOG_ERR, "cforcelogin: clear_rules failed: %s",
  458.             val2str(cforceerr2str, rc));
  459.         return;
  460.     }
  461.  
  462.  
  463.     /* Reinstall saved rules */
  464.     cforcemapfile(cf->c_cforcedata);
  465.  
  466.     /* Reblock hosts */
  467.     cs = cforceseq;
  468.     cforceseq2 = malloc(cforceseqsize);
  469.     if (cforceseq2 == NULL) {
  470.         lg(LOG_ERR, "cforcelogin: malloc");
  471.         exit(EX_OSERR);
  472.     }
  473.     memmove(cforceseq2, cforceseq, cforceseqsize);
  474.     memset(cforceseq, 0, cforceseqsize);
  475.  
  476.     for (i = 0, cs2 = cforceseq2; i < NUMRULES; ++i, ++cs2) {
  477.         switch (cs2->type) {
  478.  
  479.         case ATYPE_UNKNOWN:
  480.             /* Unused slot */
  481.             break;
  482.  
  483.         case ATYPE_BLOCKHOST:
  484.             /* Install rule in appliance */
  485.             what = "cforce_drophost";
  486.             rc = cforce_drophost(cs2->dir, &cs2->addr1);
  487.             if (rc < 0) {
  488.                 lg(LOG_ERR, "cforcelogin: drop_host failed: %s",
  489.                     val2str(cforceerr2str, rc));
  490.                 exit(EX_SOFTWARE);
  491.             }
  492.  
  493.             /* Sanity */
  494.             if (rc >= NUMRULES) {
  495.                 lg(LOG_ERR, "cforcelogin: drop_host"
  496.                     " seq number too boku %d", rc);
  497.                 exit(EX_SOFTWARE);
  498.             }
  499.             cs = cforceseq + rc;
  500.             if (cs->type != ATYPE_UNKNOWN) {
  501.                 lg(LOG_ERR, "cforcelogin: %s failed:"
  502.                     " cforceseq seq %d already in use",
  503.                     what, rc);
  504.                 exit(EX_SOFTWARE);
  505.             }
  506.  
  507.             /* Update our data structure */
  508.             ap = aclfindlistbyaddr(cf, &cs2->addr1);
  509.             if (ap == NULL) {
  510.                 lg(LOG_ERR, "can't find acllist for %s",
  511.                     addr2str(&cs2->addr1));
  512.                 exit(EX_SOFTWARE);
  513.             }
  514.             memset(&acl, 0, sizeof(acl));
  515.             acl.seq = rc;
  516.             acl.type = cs2->type;
  517.             memmove(&acl.addr1, &cs2->addr1, sizeof(acl.addr1));
  518.             acladdacl(ap, &acl);
  519.  
  520.             /* Copy rule */
  521.             *cs = *cs2;
  522.             ++cs;
  523.             break;
  524.  
  525.         case ATYPE_BLOCKHOSTHOST:
  526.             /* Install rule in appliance */
  527.             what = "cforce_drophosthost";
  528.             rc = cforce_drophosthost(cs2->dir, &cs2->addr1,
  529.                 &cs2->addr2);
  530.             if (rc < 0) {
  531.                 lg(LOG_ERR, "cforcelogin: cforce_drophosthost"
  532.                     " failed: %s", val2str(cforceerr2str, rc));
  533.                 exit(EX_SOFTWARE);
  534.             }
  535.  
  536.             /* Sanity */
  537.             if (rc >= NUMRULES) {
  538.                 lg(LOG_ERR, "cforcelogin: drop_hosthosthost"
  539.                     " seq number too boku %d", rc);
  540.                 exit(EX_SOFTWARE);
  541.             }
  542.             cs = cforceseq + rc;
  543.             if (cs->type != ATYPE_UNKNOWN) {
  544.                 lg(LOG_ERR, "cforcelogin: %s failed:"
  545.                     " cforceseq seq %d already in use",
  546.                     what, rc);
  547.                 exit(EX_SOFTWARE);
  548.             }
  549.  
  550.             /* Update our data structure */
  551.             ap = aclfindlistbyaddr(cf, &cs2->addr1);
  552.             if (ap == NULL) {
  553.                 lg(LOG_ERR, "can't find acllist for %s",
  554.                     addr2str(&cs2->addr1));
  555.                 exit(EX_SOFTWARE);
  556.             }
  557.             memset(&acl, 0, sizeof(acl));
  558.             acl.seq = rc;
  559.             acl.type = cs2->type;
  560.             memmove(&acl.addr1, &cs2->addr1, sizeof(acl.addr1));
  561.             memmove(&acl.addr2, &cs2->addr2, sizeof(acl.addr2));
  562.             acladdacl(ap, &acl);
  563.  
  564.             /* Copy rule */
  565.             *cs = *cs2;
  566.             ++cs;
  567.             break;
  568.  
  569.         default:
  570.             lg(LOG_ERR, "unhandled type #%d", cs2->type);
  571.             break;
  572.         }
  573.     }
  574.     free(cforceseq2);
  575.  
  576.     /* Need to sort since the cForce appliance picks the sequence numbers */
  577.     aclsortacls(sp->cf);
  578.  
  579.     sp->state = ASTATE_LOGGEDIN;
  580. }
  581.  
  582. static void
  583. cforcemapfile(const char *fn)
  584. {
  585.     char ch;
  586.     struct stat sbuf;
  587.  
  588.     if (fn == NULL) {
  589.         lg(LOG_ERR, "cforcemapfile: missing cforce filename");
  590.         exit(EX_SOFTWARE);
  591.     }
  592.  
  593.     md = open(fn, O_RDWR | O_CREAT, 0600);
  594.     if (md < 0) {
  595.         lg(LOG_ERR, "cforcemapfile(%s): open: %s",
  596.             fn, strerror(errno));
  597.         exit(EX_SOFTWARE);
  598.     }
  599.  
  600.     memset(&sbuf, 0, sizeof(sbuf));
  601.     if (fstat(md, &sbuf) < 0) {
  602.         lg(LOG_ERR, "cforcemapfile(%s): fstat: %s",
  603.             fn, strerror(errno));
  604.         exit(EX_SOFTWARE);
  605.     }
  606.  
  607.     if (sbuf.st_size == 0) {
  608.         lg(LOG_ERR,
  609.             "cforcemapfile(%s): initialize empty mmap file", fn);
  610.         if (lseek(md, cforceseqsize - 1, SEEK_SET) < 0) {
  611.             lg(LOG_ERR, "cforcemapfile(%s): lseek: %s",
  612.                 fn, strerror(errno));
  613.             exit(EX_SOFTWARE);
  614.         }
  615.         ch = 0;
  616.         if (write(md, &ch, 1) < 0) {
  617.             lg(LOG_ERR, "cforcemapfile(%s): write: %s",
  618.                 fn, strerror(errno));
  619.             exit(EX_OSERR);
  620.         }
  621.         if (fsync(md) < 0) {
  622.             lg(LOG_ERR, "cforcemapfile(%s): fsync: %s",
  623.                 fn, strerror(errno));
  624.             exit(EX_OSERR);
  625.         }
  626.     } else if (sbuf.st_size != cforceseqsize) {
  627.         lg(LOG_ERR, "cforcemapfile(%s): bad size: %ld != %ld",
  628.             fn, (u_long)sbuf.st_size, (u_long)cforceseqsize);
  629.         exit(EX_SOFTWARE);
  630.     }
  631.  
  632.     cforceseq = mmap(0, cforceseqsize, PROT_READ | PROT_WRITE, MAP_SHARED,
  633.         md, 0);
  634.     if ((int)cforceseq == -1) {
  635.         lg(LOG_ERR, "cforcemapfile(%s): mmap: %s",
  636.             fn, strerror(errno));
  637.         exit(EX_OSERR);
  638.     }
  639.     if (close(md) < 0) {
  640.         lg(LOG_ERR, "cforcemapfile(%s): close: %s",
  641.             fn, strerror(errno));
  642.         exit(EX_OSERR);
  643.     }
  644.     cforcemsync();
  645. }
  646.  
  647. static void
  648. cforcemsync()
  649. {
  650.     if (msync(cforceseq, cforceseqsize, MS_SYNC) < 0) {
  651.         lg(LOG_ERR, "cforcemsync(): msync: %s", strerror(errno));
  652.         exit(EX_OSERR);
  653.     }
  654. }
  655.  
  656. void
  657. cforcenullzero(struct state *sp, struct client *cl, struct req *rp)
  658. {
  659.  
  660.     clientsenderr(cl, rp, "cForce doesn't support null zero routes");
  661. }
  662.  
  663. void
  664. cforcesend(struct state *sp, const char *fmt, ...)
  665. {
  666.     abort();
  667. }
  668.  
  669. void
  670. cforcesendattr(struct state *sp)
  671. {
  672.     ++sp->sentattrs;
  673. }
  674.  
  675. void
  676. cforcesync(struct state *sp)
  677. {
  678.     lg(LOG_DEBUG, "cforcesync: noop");
  679. }
  680.  
  681. static void
  682. cforceunmapfile()
  683. {
  684.     if (cforceseq == NULL)
  685.         return;
  686.     if (munmap(cforceseq, cforceseqsize) < 0) {
  687.         lg(LOG_ERR, "cforceunmapfile(): munmap: %s", strerror(errno));
  688.         exit(EX_SOFTWARE);
  689.     }
  690.     cforceseq = NULL;
  691. }
  692.