Back to index

opendkim  2.6.6
util.c
Go to the documentation of this file.
00001 /*
00002 **  Copyright (c) 2005-2009 Sendmail, Inc. and its suppliers.
00003 **    All rights reserved.
00004 **
00005 **  Copyright (c) 2009-2012, The OpenDKIM Project.  All rights reserved.
00006 */
00007 
00008 #ifndef lint
00009 static char util_c_id[] = "@(#)$Id: util.c,v 1.12.10.1 2010/10/27 21:43:08 cm-msk Exp $";
00010 #endif /* !lint */
00011 
00012 #include "build-config.h"
00013 
00014 /* system includes */
00015 #include <sys/types.h>
00016 #include <arpa/inet.h>
00017 #include <arpa/nameser.h>
00018 #include <netinet/in.h>
00019 #ifdef HAVE_STDBOOL_H
00020 # include <stdbool.h>
00021 #endif /* HAVE_STDBOOL_H */
00022 #include <ctype.h>
00023 #include <assert.h>
00024 #include <string.h>
00025 #include <errno.h>
00026 #include <netdb.h>
00027 #include <resolv.h>
00028 #include <stdlib.h>
00029 
00030 /* libopendkim includes */
00031 #include "dkim-internal.h"
00032 #include "util.h"
00033 #include "dkim-strl.h"
00034 
00035 #if defined(__RES) && (__RES >= 19940415)
00036 # define RES_UNC_T          char *
00037 #else /* __RES && __RES >= 19940415 */
00038 # define RES_UNC_T          unsigned char *
00039 #endif /* __RES && __RES >= 19940415 */
00040 
00041 /*
00042 **  DKIM_COLLAPSE -- remove spaces from a string
00043 **
00044 **  Parameters:
00045 **     str -- string to process
00046 **
00047 **  Return value:
00048 **     None.
00049 */
00050 
00051 void
00052 dkim_collapse(u_char *str)
00053 {
00054        u_char *q;
00055        u_char *r;
00056 
00057        assert(str != NULL);
00058 
00059        for (q = str, r = str; *q != '\0'; q++)
00060        {
00061               if (!isspace(*q))
00062               {
00063                      if (q != r)
00064                             *r = *q;
00065                      r++;
00066               }
00067        }
00068 
00069        *r = '\0';
00070 }
00071 
00072 /*
00073 **  DKIM_HDRLIST -- build up a header list for use in a regexp
00074 **
00075 **  Parameters:
00076 **     buf -- where to write
00077 **     buflen -- bytes at "buf"
00078 **     hdrlist -- array of header names
00079 **     first -- first call
00080 **
00081 **  Return value:
00082 **     TRUE iff everything fit.
00083 */
00084 
00085 _Bool
00086 dkim_hdrlist(u_char *buf, size_t buflen, u_char **hdrlist, _Bool first)
00087 {
00088        _Bool escape = FALSE;
00089        int c;
00090        int len;
00091        u_char *p;
00092        u_char *q;
00093        u_char *end;
00094 
00095        assert(buf != NULL);
00096        assert(hdrlist != NULL);
00097 
00098        for (c = 0; ; c++)
00099        {
00100               if (hdrlist[c] == NULL)
00101                      break;
00102 
00103               if (!first)
00104               {
00105                      len = strlcat((char *) buf, "|", buflen);
00106                      if (len >= buflen)
00107                             return FALSE;
00108               }
00109               else
00110               {
00111                      len = strlen((char *) buf);
00112               }
00113 
00114               first = FALSE;
00115 
00116               q = &buf[len];
00117               end = &buf[buflen - 1];
00118 
00119               for (p = hdrlist[c]; *p != '\0'; p++)
00120               {
00121                      if (q >= end)
00122                             return FALSE;
00123 
00124                      if (escape)
00125                      {
00126                             *q = *p;
00127                             q++;
00128                             escape = FALSE;
00129                      }
00130 
00131                      switch (*p)
00132                      {
00133                        case '*':
00134                             *q = '.';
00135                             q++;
00136                             if (q >= end)
00137                                    return FALSE;
00138                             *q = '*';
00139                             q++;
00140                             break;
00141 
00142                        case '.':
00143                             *q = '\\';
00144                             q++;
00145                             if (q >= end)
00146                                    return FALSE;
00147                             *q = '.';
00148                             q++;
00149                             break;
00150 
00151                        case '\\':
00152                             escape = TRUE;
00153                             break;
00154 
00155                        default:
00156                             *q = *p;
00157                             q++;
00158                             break;
00159                      }
00160               }
00161        }
00162 
00163        return TRUE;
00164 }
00165 
00166 /*
00167 **  DKIM_LOWERHDR -- convert a string (presumably a header) to all lowercase,
00168 **                   but only up to a colon
00169 **
00170 **  Parameters:
00171 **     str -- string to modify
00172 **
00173 **  Return value:
00174 **     None.
00175 */
00176 
00177 void
00178 dkim_lowerhdr(unsigned char *str)
00179 {
00180        unsigned char *p;
00181 
00182        assert(str != NULL);
00183 
00184        for (p = str; *p != '\0'; p++)
00185        {
00186               if (*p == ':')
00187                      return;
00188 
00189               if (isascii(*p) && isupper(*p))
00190                      *p = tolower(*p);
00191        }
00192 }
00193 
00194 /*
00195 **  DKIM_HEXCHAR -- translate a hexadecimal character
00196 **  
00197 **  Parameters:
00198 **     c -- character to translate
00199 **
00200 **  Return value:
00201 **     Decimal equivalent.
00202 */
00203 
00204 int
00205 dkim_hexchar(int c)
00206 {
00207        switch (c)
00208        {
00209          case '0':
00210          case '1':
00211          case '2':
00212          case '3':
00213          case '4':
00214          case '5':
00215          case '6':
00216          case '7':
00217          case '8':
00218          case '9':
00219               return c - '0';
00220 
00221          case 'A':
00222          case 'B':
00223          case 'C':
00224          case 'D':
00225          case 'E':
00226          case 'F':
00227               return 10 + c - 'A';
00228 
00229          case 'a':
00230          case 'b':
00231          case 'c':
00232          case 'd':
00233          case 'e':
00234          case 'f':
00235               return 10 + c - 'a';
00236 
00237          default:
00238               assert(0);
00239               return -1;
00240        }
00241 }
00242 
00243 /*
00244 **  DKIM_QP_DECODE -- decode a quoted-printable string
00245 **
00246 **  Parameters:
00247 **     in -- input
00248 **     out -- output
00249 **     outlen -- bytes available at "out"
00250 **
00251 **  Return value:
00252 **     >= 0 -- number of bytes in output
00253 **     -1 -- parse error
00254 **
00255 **  Notes:
00256 **     The returned number of bytes can be larger than "outlen" if
00257 **     "out" wasn't big enough to contain the decoded output.  The function
00258 **     does not guarantee string termination.
00259 */
00260 
00261 int
00262 dkim_qp_decode(unsigned char *in, unsigned char *out, int outlen)
00263 {
00264        unsigned char next1;
00265        unsigned char next2 = 0;
00266        int xl;
00267        int decode = 0;
00268        unsigned char const *p;
00269        unsigned char *q;
00270        unsigned char *pos;
00271        unsigned char const *start;
00272        unsigned char const *stop;
00273        unsigned char *end;
00274        char const *hexdigits = "0123456789ABCDEF";
00275 
00276        assert(in != NULL);
00277        assert(out != NULL);
00278 
00279        start = NULL;
00280        stop = NULL;
00281 
00282        end = out + outlen;
00283 
00284        for (p = in, q = out; *p != '\0'; p++)
00285        {
00286               switch (*p)
00287               {
00288                 case '=':
00289                      next1 = *(p + 1);
00290                      if (next1 != '\0')
00291                             next2 = *(p + 2);
00292 
00293                      /* = at EOL */
00294                      if (next1 == '\n' ||
00295                          (next1 == '\r' && next2 == '\n'))
00296                      {
00297                             stop = p;
00298                             if (start != NULL)
00299                             {
00300                                    unsigned char const *x;
00301 
00302                                    for (x = start; x <= stop; x++)
00303                                    {
00304                                           decode++;
00305 
00306                                           if (q <= end)
00307                                           {
00308                                                  *q = *x;
00309                                                  q++;
00310                                           }
00311                                    }
00312                             }
00313                             start = NULL;
00314                             stop = NULL;
00315 
00316                             p++;
00317                             if (next2 == '\n')
00318                                    p++;
00319                             break;
00320                      }
00321 
00322                      /* = elsewhere */
00323                      pos = (unsigned char *) strchr(hexdigits, next1);
00324                      if (pos == NULL)
00325                             return -1;
00326                      xl = (pos - (unsigned char *) hexdigits) * 16;
00327 
00328                      pos = (unsigned char *) strchr(hexdigits, next2);
00329                      if (pos == NULL)
00330                             return -1;
00331                      xl += (pos - (unsigned char *) hexdigits);
00332 
00333                      stop = p;
00334                      if (start != NULL)
00335                      {
00336                             unsigned char const *x;
00337 
00338                             for (x = start; x < stop; x++)
00339                             {
00340                                    decode++;
00341 
00342                                    if (q <= end)
00343                                    {
00344                                           *q = *x;
00345                                           q++;
00346                                    }
00347                             }
00348                      }
00349                      start = NULL;
00350                      stop = NULL;
00351 
00352                      if (q <= end)
00353                      {
00354                             *q = xl;
00355                             q++;
00356                      }
00357 
00358                      decode++;
00359 
00360                      p += 2;
00361 
00362                      break;
00363 
00364                 case ' ':
00365                 case '\t':
00366                      if (start == NULL)
00367                             start = p;
00368                      break;
00369 
00370                 case '\r':
00371                      break;
00372 
00373                 case '\n':
00374                      if (stop == NULL)
00375                             stop = p;
00376                      if (start != NULL)
00377                      {
00378                             unsigned char const *x;
00379 
00380                             for (x = start; x <= stop; x++)
00381                             {
00382                                    decode++;
00383 
00384                                    if (q <= end)
00385                                    {
00386                                           *q = *x;
00387                                           q++;
00388                                    }
00389                             }
00390                      }
00391 
00392                      if (p > in && *(p - 1) != '\r')
00393                      {
00394                             decode++;
00395 
00396                             if (q <= end)
00397                             {
00398                                    *q = '\n';
00399                                    q++;
00400                             }
00401                      }
00402                      else
00403                      {
00404                             decode += 2;
00405                             if (q <= end)
00406                             {
00407                                    *q = '\r';
00408                                    q++;
00409                             }
00410                             if (q <= end)
00411                             {
00412                                    *q = '\n';
00413                                    q++;
00414                             }
00415                      }
00416 
00417                      start = NULL;
00418                      stop = NULL;
00419                      break;
00420 
00421                 default:
00422                      if (start == NULL)
00423                             start = p;
00424                      stop = p;
00425                      break;
00426               }
00427        }
00428 
00429        if (start != NULL)
00430        {
00431               unsigned char const *x;
00432 
00433               for (x = start; x < p; x++)
00434               {
00435                      decode++;
00436 
00437                      if (q <= end)
00438                      {
00439                             *q = *x;
00440                             q++;
00441                      }
00442               }
00443        }
00444 
00445        return decode;
00446 }
00447 
00448 #ifdef NEED_FAST_STRTOUL
00449 /*
00450 **  DKIM_STRTOUL -- convert string to unsigned long
00451 **
00452 **  Parameters:
00453 **     str -- string to convert
00454 **     endptr -- pointer to store string after value
00455 **     base -- base to convert from
00456 **
00457 **  Return value:
00458 **     Value of string as unsigned long
00459 */
00460 
00461 unsigned long
00462 dkim_strtoul(const char *str, char **endptr, int base)
00463 {
00464        char start = '+';
00465        static char cutlim = ULONG_MAX % 10;
00466        char c;
00467        _Bool erange = FALSE;
00468        static unsigned long cutoff = ULONG_MAX / 10;
00469        unsigned long value = 0;
00470        const char *subj;
00471        const char *cur;
00472 
00473        if (base != 10)
00474               return strtoul(str, endptr, base);
00475 
00476        if (str == NULL)
00477        {
00478               errno = EINVAL;
00479               return value;
00480        }
00481 
00482        subj = str;
00483 
00484        while (*subj != '\0' && isspace(*subj))
00485               subj++;
00486 
00487        if (*subj == '-' || *subj == '+')
00488               start = *subj++;
00489 
00490        for (cur = subj; *cur >= '0' && *cur <= '9'; cur++)
00491        {
00492               if (erange)
00493                      continue;
00494 
00495               c = *cur - '0';
00496 
00497               if ((value > cutoff) || (value == cutoff && c > cutlim))
00498               {
00499                      erange = TRUE;
00500                      continue;
00501               }
00502 
00503               value = (value * 10) + c;
00504        }
00505 
00506        if (cur == subj)
00507        {
00508               if (endptr != NULL)
00509                      *endptr = (char *) str;
00510               errno = EINVAL;
00511               return 0;
00512        }
00513 
00514        if (endptr != NULL)
00515               *endptr = (char *) cur;
00516 
00517        if (erange)
00518        {
00519               errno = ERANGE;
00520               return ULONG_MAX;
00521        }
00522 
00523        if (start == '-')
00524               return -value;
00525        else
00526               return value;
00527 }
00528 
00529 /*
00530 **  DKIM_STRTOULL -- convert string to unsigned long long
00531 **
00532 **  Parameters:
00533 **     str -- string to convert
00534 **     endptr -- pointer to store string after value
00535 **     base -- base to convert from
00536 **
00537 **  Return value:
00538 **     Value of string as unsigned long long
00539 */
00540 
00541 unsigned long long
00542 dkim_strtoull(const char *str, char **endptr, int base)
00543 {
00544        char start = '+';
00545        char c;
00546        _Bool erange = FALSE;
00547        static char cutlim = ULLONG_MAX % 10;
00548        static unsigned long long cutoff = ULLONG_MAX / 10;
00549        unsigned long long value = 0;
00550        const char *subj;
00551        const char *cur;
00552 
00553        if (base != 10)
00554               return strtoull(str, endptr, base);
00555 
00556        if (str == NULL)
00557        {
00558               errno = EINVAL;
00559               return value;
00560        }
00561 
00562        subj = str;
00563 
00564        while (*subj && isspace(*subj))
00565               subj++;
00566 
00567        if (*subj == '-' || *subj == '+')
00568               start = *subj++;
00569 
00570        for (cur = subj; *cur >= '0' && *cur <= '9'; cur++)
00571        {
00572               if (erange)
00573                      continue;
00574 
00575               c = *cur - '0';
00576 
00577               if ((value > cutoff) || (value == cutoff && c > cutlim))
00578               {
00579                      erange = 1;
00580                      continue;
00581               }
00582 
00583               value = (value * 10) + c;
00584        }
00585 
00586        if (cur == subj)
00587        {
00588               if (endptr != NULL)
00589                      *endptr = (char *) str;
00590               errno = EINVAL;
00591               return 0;
00592        }
00593 
00594        if (endptr != NULL)
00595               *endptr = (char *) cur;
00596 
00597        if (erange != 0)
00598        {
00599               errno = ERANGE;
00600               return ULLONG_MAX;
00601        }
00602 
00603        if (start == '-')
00604               return -value;
00605        else
00606               return value;
00607 }
00608 #endif /* NEED_FAST_STRTOUL */
00609 
00610 /*
00611 **  DKIM_CHECK_DNS_REPLY -- see if a DNS reply is truncated or corrupt
00612 **
00613 **  Parameters:
00614 **     ansbuf -- answer buffer
00615 **     anslen -- number of bytes returned
00616 **     xclass -- expected class
00617 **     xtype -- expected type
00618 **
00619 **  Return value:
00620 **     2 -- reply not usable
00621 **     1 -- reply truncated but usable
00622 **     0 -- reply intact (but may not be what you want)
00623 **     -1 -- other error
00624 */
00625 
00626 int
00627 dkim_check_dns_reply(unsigned char *ansbuf, size_t anslen,
00628                      int xclass, int xtype)
00629 {
00630        _Bool trunc = FALSE;
00631        int qdcount;
00632        int ancount;
00633        int n;
00634        uint16_t type = (uint16_t) -1;
00635        uint16_t class = (uint16_t) -1;
00636        uint32_t ttl;
00637        unsigned char *cp;
00638        unsigned char *eom;
00639        HEADER hdr;
00640        unsigned char name[DKIM_MAXHOSTNAMELEN + 1];
00641 
00642        assert(ansbuf != NULL);
00643 
00644        /* set up pointers */
00645        memcpy(&hdr, ansbuf, sizeof hdr);
00646        cp = ansbuf + HFIXEDSZ;
00647        eom = ansbuf + anslen;
00648 
00649        /* skip over the name at the front of the answer */
00650        for (qdcount = ntohs((unsigned short) hdr.qdcount);
00651             qdcount > 0;
00652             qdcount--)
00653        {
00654               /* copy it first */
00655               (void) dn_expand((unsigned char *) ansbuf, eom, cp,
00656                                (RES_UNC_T) name, sizeof name);
00657 
00658               if ((n = dn_skipname(cp, eom)) < 0)
00659                      return 2;
00660 
00661               cp += n;
00662 
00663               /* extract the type and class */
00664               if (cp + INT16SZ + INT16SZ > eom)
00665                      return 2;
00666 
00667               GETSHORT(type, cp);
00668               GETSHORT(class, cp);
00669        }
00670 
00671        if (type != xtype || class != xclass)
00672               return 0;
00673 
00674        /* if NXDOMAIN, return DKIM_STAT_NOKEY */
00675        if (hdr.rcode == NXDOMAIN)
00676               return 0;
00677 
00678        /* if truncated, we can't do it */
00679        if (hdr.tc)
00680               trunc = TRUE;
00681 
00682        /* get the answer count */
00683        ancount = ntohs((unsigned short) hdr.ancount);
00684        if (ancount == 0)
00685               return (trunc ? 2 : 0);
00686 
00687        /*
00688        **  Extract the data from the first TXT answer.
00689        */
00690 
00691        while (--ancount >= 0 && cp < eom)
00692        {
00693               /* grab the label, even though we know what we asked... */
00694               if ((n = dn_expand((unsigned char *) ansbuf, eom, cp,
00695                                  (RES_UNC_T) name, sizeof name)) < 0)
00696                      return 2;
00697 
00698               /* ...and move past it */
00699               cp += n;
00700 
00701               /* extract the type and class */
00702               if (cp + INT16SZ + INT16SZ + INT32SZ > eom)
00703                      return 2;
00704 
00705               GETSHORT(type, cp);
00706               GETSHORT(class, cp);
00707               GETLONG(ttl, cp);
00708 
00709               /* skip CNAME if found; assume it was resolved */
00710               if (type == T_CNAME)
00711               {
00712                      if ((n = dn_expand((u_char *) ansbuf, eom, cp,
00713                                         (RES_UNC_T) name, sizeof name)) < 0)
00714                             return 2;
00715 
00716                      cp += n;
00717                      continue;
00718               }
00719               else if (type != xtype)
00720               {
00721                      return (trunc ? 1 : 0);
00722               }
00723 
00724               /* found a record we can use; break */
00725               break;
00726        }
00727 
00728        /* if ancount went below 0, there were no good records */
00729        if (ancount < 0)
00730               return (trunc ? 1 : 0);
00731 
00732        /* get payload length */
00733        if (cp + INT16SZ > eom)
00734               return 2;
00735 
00736        GETSHORT(n, cp);
00737 
00738        /*
00739        **  XXX -- maybe deal with a partial reply rather than require
00740        **        it all
00741        */
00742 
00743        if (cp + n > eom)
00744               return 2;
00745 
00746        return (trunc ? 1 : 0);
00747 }
00748 
00749 /*
00750 **  DKIM_MIN_TIMEVAL -- determine the timeout to apply before reaching
00751 **                      one of two timevals
00752 **
00753 **  Parameters:
00754 **     t1 -- first timeout (absolute)
00755 **     t2 -- second timeout (absolute) (may be NULL)
00756 **     t -- final timeout (relative)
00757 **     which -- which of t1 and t2 hit first
00758 **
00759 **  Return value:
00760 **     None.
00761 */
00762 
00763 void
00764 dkim_min_timeval(struct timeval *t1, struct timeval *t2, struct timeval *t,
00765                  struct timeval **which)
00766 {
00767        struct timeval *next;
00768        struct timeval now;
00769 
00770        assert(t1 != NULL);
00771        assert(t != NULL);
00772 
00773        if (t2 == NULL ||
00774            t2->tv_sec > t1->tv_sec ||
00775            (t2->tv_sec == t1->tv_sec && t2->tv_usec > t1->tv_usec))
00776               next = t1;
00777        else
00778               next = t2;
00779 
00780        (void) gettimeofday(&now, NULL);
00781 
00782        if (next->tv_sec < now.tv_sec ||
00783            (next->tv_sec == now.tv_sec && next->tv_usec < now.tv_usec))
00784        {
00785               t->tv_sec = 0;
00786               t->tv_usec = 0;
00787        }
00788        else
00789        {
00790               t->tv_sec = next->tv_sec - now.tv_sec;
00791               if (next->tv_usec < now.tv_usec)
00792               {
00793                      t->tv_sec--;
00794                      t->tv_usec = next->tv_usec - now.tv_usec + 1000000;
00795               }
00796               else
00797               {
00798                      t->tv_usec = next->tv_usec - now.tv_usec;
00799               }
00800        }
00801 
00802        if (which != NULL)
00803               *which = next;
00804 }
00805 
00806 /*
00807 **  DKIM_COPY_ARRAY -- copy an array of char pointers
00808 **
00809 **  Parameters:
00810 **     in -- input array, must be NULL-terminated
00811 **
00812 **  Return value:
00813 **     A copy of "in" and its elements, or NULL on failure.
00814 */
00815 
00816 const char **
00817 dkim_copy_array(char **in)
00818 {
00819        unsigned int c;
00820        unsigned int n;
00821        char **out;
00822 
00823        assert(in != NULL);
00824 
00825        for (n = 0; in[n] != NULL; n++)
00826               continue;
00827 
00828        out = malloc(sizeof(char *) * (n + 1));
00829 
00830        for (c = 0; c < n; c++)
00831        {
00832               out[c] = strdup(in[c]);
00833               if (out[c] == NULL)
00834               {
00835                      for (n = 0; n < c; n++)
00836                             free(out[n]);
00837                      free(out);
00838                      return NULL;
00839               }
00840        }
00841 
00842        out[c] = NULL;
00843 
00844        return (const char **) out;
00845 }
00846 
00847 /*
00848 **  DKIM_CLOBBER_ARRAY -- clobber a cloned array of char pointers
00849 **
00850 **  Parameters:
00851 **     in -- input array, must be NULL-terminated
00852 **
00853 **  Return value:
00854 **     None.
00855 */
00856 
00857 void
00858 dkim_clobber_array(char **in)
00859 {
00860        unsigned int n;
00861 
00862        assert(in != NULL);
00863 
00864        for (n = 0; in[n] != NULL; n++)
00865               free(in[n]);
00866 
00867        free(in);
00868 }