Logo Search packages:      
Sourcecode: dcc version File versions  Download package

ckparse.c

/* Distributed Checksum Clearinghouse
 *
 * parse a named checksum
 *
 * Copyright (c) 2005 by Rhyolite Software
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND RHYOLITE SOFTWARE DISCLAIMS ALL
 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL RHYOLITE SOFTWARE
 * BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES
 * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
 * SOFTWARE.
 *
 * Rhyolite Software DCC 1.2.74-1.44 $Revision$
 */

#include "dcc_ck.h"
#ifndef DCC_WIN32
#include <arpa/inet.h>
#endif

static int                    /* -1=fatal 0=failed 1=ok 2=resolved */
dcc_host2ck(DCC_EMSG emsg, DCC_WF *wf,
          const char *ck,           /* this string of an IP address */
          const char *fnm, int lineno,
          DCC_TGTS tgts,            /* # of targets */
          DCC_PARSED_CK_FNC fnc,    /* do something with each checksum */
          DCC_PARSED_CIDR_CK_FNC cidr_fnc,
          DCC_PARSED_CK_LOCK unlock)      /* unlock file if resolve hostname */
{
      int error;
      struct in6_addr addr6, mask6;
      DCC_SUM sum;
      DCC_SOCKU *sup;
      int i, j, bits;

      /* recognize xxx.xxx.xxx.xxx/y for IP address blocks
       * as well as simple IP addresses */
      bits = dcc_str2cidr(emsg, &addr6, &mask6, ck, fnm, lineno);
      if (bits < 0)
            return 0;

      if (bits > 0) {
            /* use client CIDR block masks */
            if (128-bits >= 8 && cidr_fnc)
                  return cidr_fnc(emsg, wf->info, fnm, lineno,
                              bits, &addr6, &mask6, tgts);

            /* Allow class-B sized blocks in server whitelists.
             * Client whitelists come here with non-null cidr_fnc */
            if (128-bits > 16) {
                  dcc_pemsg(EX_NOHOST, emsg,
                          "CIDR block length in %s too large%s",
                          ck, fnm_lineno(fnm, lineno));
                  return 0;
            }

            for (i = 1 << (128-bits); i > 0; --i) {
                  dcc_ck_ipv6(sum, &addr6);
                  j = fnc(emsg, wf, fnm, lineno, DCC_CK_IP, sum, tgts);
                  if (j <= 0)
                        return j;
                  addr6.s6_addr32[3] = ntohl(addr6.s6_addr32[3]);
                  ++addr6.s6_addr32[3];
                  addr6.s6_addr32[3] = htonl(addr6.s6_addr32[3]);
            }
            return 1;
      }

      /* we appear to have a host name,
       * which are not allowed in per-user whitelists */
      if (wf->flags & DCC_WF_PER_USER) {
            dcc_pemsg(EX_NOHOST, emsg,
                    "hostname checksum illegal%s",
                    fnm_lineno(fnm, lineno));
            return 0;
      }

      /* Don't keep the table write-locked while we try to
       * resolve hostnames into IP addresses.
       * This unlocks the DCC_WF as well as the file, and so must
       * not be done to private whitelists.  This implies that we
       * cannot spend time waiting for DNS resolutions of host names
       * in private or per-user whitelists. */
      if (unlock) {
            if (!unlock(emsg, wf))
                  return -1;
            dcc_wf_unlock(wf);
      }

      memset(&addr6, 0, sizeof(addr6));
      dcc_host_lock();
      /* don't use SOCKS because the only IP addresses it makes
       * send to white-list are inside the SOCKS firewall */
      if (!dcc_get_host(ck, 1, &error)) {
            dcc_pemsg(EX_NOHOST, emsg,
                    "hostname \"%s\": %s%s",
                    ck, DCC_HSTRERROR(error), fnm_lineno(fnm, lineno));
            dcc_host_unlock();
            if (unlock)
                  dcc_wf_lock(wf);
            return 0;
      }

      if (unlock)
            dcc_wf_lock(wf);
      for (sup = dcc_hostaddrs; sup < dcc_hostaddrs_end; ++sup) {
            if (sup->sa.sa_family == AF_INET6) {
                  dcc_ck_ipv6(sum, &sup->ipv6.sin6_addr);
            } else {
                  dcc_ipv4toipv6(&addr6, sup->ipv4.sin_addr);
                  dcc_ck_ipv6(sum, &addr6);
            }
            j = fnc(emsg, wf, fnm, lineno, DCC_CK_IP, sum, tgts);
            if (j <= 0) {
                  dcc_host_unlock();
                  if (unlock)
                        dcc_wf_lock(wf);
                  return j;
            }
      }
      dcc_host_unlock();
      return 2;
}



/* generate checksum value from the name of the checksum and a string */
int                           /* 2=resolved, 1=ok, 0=bad, -1=fatal */
dcc_parse_ck(DCC_EMSG emsg,         /* failure message here */
           DCC_WF *wf,
           const char *fnm,         /* 0 or location of cksum */
           int lineno,
           const char *type_nm,     /* type of checksum */
           const char *str,         /* ASCII string to generate checksum */
           DCC_TGTS tgts,           /* # of targets */
           DCC_PARSED_CK_FNC fnc,   /* do something with the checksum */
           DCC_PARSED_CIDR_CK_FNC cidr_fnc,
           DCC_PARSED_CK_LOCK unlock)     /* unlock for IP address */
{
      DCC_CK_TYPES type;
      DCC_SUM sum;
      const char *pstr;
      char *phdr, c, hdr_buf[80];

      /* look for the name of the checksum
       * to find the checksumming function */
      type = dcc_str2type(type_nm);
      /* compute the checksum */
      switch (type) {
      case DCC_CK_IP:
            return dcc_host2ck(emsg, wf, str, fnm, lineno,
                           tgts, fnc, cidr_fnc, unlock);

      case DCC_CK_ENV_FROM:
      case DCC_CK_FROM:
      case DCC_CK_MESSAGE_ID:
      case DCC_CK_RECEIVED:
      case DCC_CK_ENV_TO:
            dcc_str2ck(sum, 0, 0, str);
            return fnc(emsg, wf, fnm, lineno, type, sum, tgts);

      case DCC_CK_SUB:
            str += strspn(str, DCC_WHITESPACE);
            pstr = str;
            phdr = hdr_buf;
            for (;;) {
                  c = *pstr++;
                  if (c == '\0' || c == ':'
                      || DCC_IS_WHITE(c))
                        break;
                  c = DCC_TO_LOWER(c);
                  *phdr++ = c;
                  if (phdr >= &hdr_buf[sizeof(hdr_buf)]) {
                        dcc_pemsg(EX_DATAERR, emsg,
                                " imposible substitute header name"
                                " in \"%s\"%s",
                                str, fnm_lineno(fnm, lineno));
                        return 0;
                  }
            }
            pstr += strspn(pstr, DCC_WHITESPACE);
            if (*pstr == '\0' || phdr == hdr_buf) {
                  dcc_pemsg(EX_DATAERR, emsg,
                          " substitute header name absent in \"%s\"%s",
                          str, fnm_lineno(fnm, lineno));
                  return 0;
            }
            dcc_str2ck(sum, hdr_buf, phdr-hdr_buf, pstr);
            return fnc(emsg, wf, fnm, lineno, type, sum, tgts);

      case DCC_CK_INVALID:
      case DCC_CK_BODY:
      case DCC_CK_FUZ1:
      case DCC_CK_FUZ2:
      case DCC_CK_GREY_MSG:
      case DCC_CK_GREY_TRIPLE:
      case DCC_CK_SRVR_ID:
            break;
      }

      dcc_pemsg(EX_DATAERR, emsg, "unrecognized checksum type \"%s\"%s",
              type_nm, fnm_lineno(fnm, lineno));
      return 0;
}



/* generate checksum value from the name of the checksum and hex values */
int                           /* 1=ok, 0=bad checksum, -1=fatal */
dcc_parse_hex_ck(DCC_EMSG emsg,           /* failure message here */
             DCC_WF *wf,
             const char *fnm, /* 0 or location of cksum */
             int lineno,
             const char *type_nm,   /* type of checksum */
             const char *str, /* ASCII string to generate checksum */
             DCC_TGTS tgts,         /* # of targets */
             DCC_PARSED_CK_FNC fnc) /* do something with the checksum */
{
      DCC_CK_TYPES type;
      union {
          u_int32_t n[4];
          DCC_SUM sum;
      } u;

      type = dcc_str2type(type_nm);
      if (type == DCC_CK_INVALID) {
            dcc_pemsg(EX_DATAERR, emsg,
                    "unrecognized checksum type \"%s\"%s",
                    type_nm, fnm_lineno(fnm, lineno));
            return 0;
      }

      /* compute the checksum */
      if (4 != sscanf(str, DCC_CKSUM_HEX_PAT"\n",
                  &u.n[0], &u.n[1], &u.n[2], &u.n[3])
          && (type != DCC_CK_SUB
            || 4 != sscanf(str, "%*s "DCC_CKSUM_HEX_PAT"\n",
                         &u.n[0], &u.n[1], &u.n[2], &u.n[3]))) {
            dcc_pemsg(EX_DATAERR, emsg,
                    "unrecognized checksum values \"%s\"%s",
                    str, fnm_lineno(fnm, lineno));
            return 0;
      }
      u.n[0] = htonl(u.n[0]);
      u.n[1] = htonl(u.n[1]);
      u.n[2] = htonl(u.n[2]);
      u.n[3] = htonl(u.n[3]);

      /* apply the function to the checksum */
      return fnc(emsg, wf, fnm, lineno, type, u.sum, tgts);
}

Generated by  Doxygen 1.6.0   Back to index