Back to index

opendkim  2.6.4
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 **  $Id: util.c,v 1.47.2.1 2010/10/27 21:43:09 cm-msk Exp $
00008 */
00009 
00010 #ifndef lint
00011 static char util_c_id[] = "@(#)$Id: util.c,v 1.47.2.1 2010/10/27 21:43:09 cm-msk Exp $";
00012 #endif /* !lint */
00013 
00014 #include "build-config.h"
00015 
00016 /* system includes */
00017 #include <sys/param.h>
00018 #include <sys/types.h>
00019 #include <sys/wait.h>
00020 #include <sys/time.h>
00021 #include <sys/resource.h>
00022 #include <sys/file.h>
00023 #include <netinet/in.h>
00024 #include <sys/un.h>
00025 #include <arpa/inet.h>
00026 #include <assert.h>
00027 #include <syslog.h>
00028 #include <stdarg.h>
00029 #include <stdlib.h>
00030 #include <errno.h>
00031 #include <string.h>
00032 #include <ctype.h>
00033 #include <stdio.h>
00034 #include <netdb.h>
00035 #include <fcntl.h>
00036 #include <unistd.h>
00037 #include <limits.h>
00038 #ifdef _FFR_REPLACE_RULES
00039 # include <regex.h>
00040 #endif /* _FFR_REPLACE_RULES */
00041 
00042 #ifdef HAVE_PATHS_H
00043 # include <paths.h>
00044 #endif /* HAVE_PATHS_H */
00045 #ifndef _PATH_DEVNULL
00046 # define _PATH_DEVNULL             "/dev/null"
00047 #endif /* ! _PATH_DEVNULL */
00048 
00049 #ifdef SOLARIS
00050 # if SOLARIS <= 20600
00051 #  define socklen_t size_t
00052 # endif /* SOLARIS <= 20600 */
00053 #endif /* SOLARIS */
00054 
00055 /* libopendkim includes */
00056 #include <dkim-strl.h>
00057 
00058 /* opendkim includes */
00059 #include "opendkim.h"
00060 #include "util.h"
00061 #include "opendkim-db.h"
00062 
00063 /* macros */
00064 #define       DEFARGS              8
00065 
00066 /* missing definitions */
00067 #ifndef INADDR_NONE
00068 # define INADDR_NONE ((uint32_t) -1)
00069 #endif /* ! INADDR_NONE */
00070 
00071 /* globals */
00072 #ifdef POPAUTH
00073 static pthread_mutex_t pop_lock;
00074 #endif /* POPAUTH */
00075 
00076 static char *optlist[] =
00077 {
00078 #if DEBUG
00079        "DEBUG",
00080 #endif /* DEBUG */
00081 
00082 #if POLL
00083        "POLL",
00084 #endif /* POLL */
00085 
00086 #if POPAUTH
00087        "POPAUTH",
00088 #endif /* POPAUTH */
00089 
00090 #if QUERY_CACHE
00091        "QUERY_CACHE",
00092 #endif /* QUERY_CACHE */
00093 
00094 #if USE_ARLIB
00095        "USE_ARLIB",
00096 #endif /* USE_ARLIB */
00097 
00098 #if USE_DB
00099        "USE_DB",
00100 #endif /* USE_DB */
00101 
00102 #if USE_ERLANG
00103        "USE_ERLANG",
00104 #endif /* USE_ERLANG */
00105 
00106 #if USE_JANSSON
00107        "USE_JANSSON",
00108 #endif /* USE_JANSSON */
00109 
00110 #if USE_LDAP
00111        "USE_LDAP",
00112 #endif /* USE_LDAP */
00113 
00114 #if USE_LUA
00115        "USE_LUA",
00116 #endif /* USE_LUA */
00117 
00118 #if USE_MDB
00119        "USE_MDB",
00120 #endif /* USE_MDB */
00121 
00122 #if USE_ODBX
00123        "USE_ODBX",
00124 #endif /* USE_ODBX */
00125 
00126 #if USE_UNBOUND
00127        "USE_UNBOUND",
00128 #endif /* USE_UNBOUND */
00129 
00130 #if USE_XML2
00131        "USE_XML2",
00132 #endif /* USE_XML2 */
00133 
00134 #ifdef _FFR_ADSP_LISTS
00135        "_FFR_ADSP_LISTS",
00136 #endif /* _FFR_ADSP_LISTS */
00137 
00138 #ifdef _FFR_ATPS
00139        "_FFR_ATPS",
00140 #endif /* _FFR_ATPS */
00141 
00142 #ifdef _FFR_DEFAULT_SENDER
00143        "_FFR_DEFAULT_SENDER",
00144 #endif /* _FFR_DEFAULT_SENDER */
00145 
00146 #if _FFR_DIFFHEADERS
00147        "_FFR_DIFFHEADERS",
00148 #endif /* _FFR_DIFFHEADERS */
00149 
00150 #if _FFR_DKIM_REPUTATION
00151        "_FFR_DKIM_REPUTATION",
00152 #endif /* _FFR_DKIM_REPUTATION */
00153 
00154 #if _FFR_IDENTITY_HEADER
00155        "_FFR_IDENTITY_HEADER",
00156 #endif /* _FFR_IDENTITY_HEADER */
00157 
00158 #if _FFR_LDAP_CACHING
00159        "_FFR_LDAP_CACHING",
00160 #endif /* _FFR_LDAP_CACHING */
00161 
00162 #if _FFR_LUA_GLOBALS
00163        "_FFR_LUA_GLOBALS",
00164 #endif /* _FFR_LUA_GLOBALS */
00165 
00166 #if _FFR_OVERSIGN
00167        "_FFR_OVERSIGN",
00168 #endif /* _FFR_OVERSIGN */
00169 
00170 #if _FFR_POSTGRESQL_RECONNECT_HACK
00171        "_FFR_POSTGRESQL_RECONNECT_HACK",
00172 #endif /* _FFR_POSTGRESQL_RECONNECT_HACK */
00173 
00174 #if _FFR_RATE_LIMIT
00175        "_FFR_RATE_LIMIT",
00176 #endif /* _FFR_RATE_LIMIT */
00177 
00178 #if _FFR_RBL
00179        "_FFR_RBL",
00180 #endif /* _FFR_RBL */
00181 
00182 #if _FFR_REDIRECT
00183        "_FFR_REDIRECT",
00184 #endif /* _FFR_REDIRECT */
00185 
00186 #if _FFR_REPLACE_RULES
00187        "_FFR_REPLACE_RULES",
00188 #endif /* _FFR_REPLACE_RULES */
00189 
00190 #if _FFR_REPUTATION
00191        "_FFR_REPUTATION",
00192 #endif /* _FFR_REPUTATION */
00193 
00194 #if _FFR_REPUTATION_CACHE
00195        "_FFR_REPUTATION_CACHE",
00196 #endif /* _FFR_REPUTATION_CACHE */
00197 
00198 #if _FFR_RESIGN
00199        "_FFR_RESIGN",
00200 #endif /* _FFR_RESIGN */
00201 
00202 #if _FFR_SENDER_MACRO
00203        "_FFR_SENDER_MACRO",
00204 #endif /* _FFR_SENDER_MACRO */
00205 
00206 #ifdef _FFR_SOCKETDB
00207        "_FFR_SOCKETDB",
00208 #endif /* _FFR_SOCKETDB */
00209 
00210 #if _FFR_STATS
00211        "_FFR_STATS",
00212 #endif /* _FFR_STATS */
00213 
00214 #if _FFR_STATSEXT
00215        "_FFR_STATSEXT",
00216 #endif /* _FFR_STATSEXT */
00217 
00218 #if _FFR_VBR
00219        "_FFR_VBR",
00220 #endif /* _FFR_VBR */
00221 
00222        NULL
00223 };
00224 
00225 /* struct dkimf_dstring -- a dynamically-sized string */
00226 struct dkimf_dstring
00227 {
00228        int                  ds_alloc;
00229        int                  ds_max;
00230        int                  ds_len;
00231        u_char *             ds_buf;
00232 };
00233 
00234 /* base64 alphabet */
00235 static unsigned char alphabet[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
00236 
00237 /*
00238 **  DKIMF_ISBLANK -- return TRUE iff a string contains only whitespace
00239 **  
00240 **  Parameters:
00241 **     str -- string to check
00242 **
00243 **  Return value:
00244 **     TRUE if "str" is either zero-length or contains only whitespace
00245 */
00246 
00247 _Bool
00248 dkimf_isblank(char *str)
00249 {
00250        char *p;
00251 
00252        for (p = str; *p != '\0'; p++)
00253        {
00254               if (isascii(*p) && isspace(*p))
00255                      continue;
00256 
00257               return FALSE;
00258        }
00259 
00260        return TRUE;
00261 }
00262 
00263 /*
00264 **  DKIMF_OPTLIST -- print active FFRs
00265 **
00266 **  Parameters:
00267 **     where -- where to write the list
00268 **
00269 **  Return value:
00270 **     None.
00271 */
00272 
00273 void
00274 dkimf_optlist(FILE *where)
00275 {
00276        _Bool first = TRUE;
00277        int c;
00278 
00279        assert(where != NULL);
00280 
00281        for (c = 0; optlist[c] != NULL; c++)
00282        {
00283               if (first)
00284               {
00285                      fprintf(where, "\tActive code options:\n");
00286                      first = FALSE;
00287               }
00288 
00289               fprintf(where, "\t\t%s\n", optlist[c]);
00290        }
00291         fprintf(where, "\t%s\n", LIBOPENDKIM_FEATURE_STRING);
00292 }
00293 
00294 /*
00295 **  DKIMF_SETMAXFD -- increase the file descriptor limit as much as possible
00296 **
00297 **  Parameters:
00298 **     None.
00299 **
00300 **  Return value:
00301 **     None.
00302 */
00303 
00304 void
00305 dkimf_setmaxfd(void)
00306 {
00307        struct rlimit rlp;
00308 
00309        if (getrlimit(RLIMIT_NOFILE, &rlp) != 0)
00310        {
00311               syslog(LOG_WARNING, "getrlimit(): %s", strerror(errno));
00312        }
00313        else
00314        {
00315               rlp.rlim_cur = rlp.rlim_max;
00316               if (setrlimit(RLIMIT_NOFILE, &rlp) != 0)
00317               {
00318                      syslog(LOG_WARNING, "setrlimit(): %s",
00319                             strerror(errno));
00320               }
00321        }
00322 }
00323 
00324 /*
00325 **  DKIMF_STRIPBRACKETS -- remove angle brackets from the sender address
00326 **
00327 **  Parameters:
00328 **     addr -- address to be processed
00329 **
00330 **  Return value:
00331 **     None.
00332 */
00333 
00334 void
00335 dkimf_stripbrackets(char *addr)
00336 {
00337        char *p, *q;
00338 
00339        assert(addr != NULL);
00340 
00341        p = addr;
00342        q = addr + strlen(addr) - 1;
00343 
00344        while (*p == '<' && *q == '>')
00345        {
00346               p++;
00347               *q-- = '\0';
00348        }
00349 
00350        if (p != addr)
00351        {
00352               for (q = addr; *p != '\0'; p++, q++)
00353                      *q = *p;
00354               *q = '\0';
00355        }
00356 }
00357 
00358 /*
00359 **  DKIMF_LOWERCASE -- lowercase-ize a string
00360 **
00361 **  Parameters:
00362 **     str -- string to convert
00363 **
00364 **  Return value:
00365 **     None.
00366 */
00367 
00368 void
00369 dkimf_lowercase(u_char *str)
00370 {
00371        u_char *p;
00372 
00373        assert(str != NULL);
00374 
00375        for (p = str; *p != '\0'; p++)
00376        {
00377               if (isascii(*p) && isupper(*p))
00378                      *p = tolower(*p);
00379        }
00380 }
00381 
00382 /*
00383 **  DKIMF_CHECKHOST -- check the peerlist for a host and its wildcards
00384 **
00385 **  Parameters:
00386 **     db -- DB of records to check
00387 **     host -- hostname to find
00388 **
00389 **  Return value:
00390 **     TRUE if there's a match, FALSE otherwise.
00391 */
00392 
00393 _Bool
00394 dkimf_checkhost(DKIMF_DB db, char *host)
00395 {
00396        _Bool exists;
00397        int status;
00398        char *p;
00399        char buf[BUFRSZ + 1];
00400 
00401        assert(host != NULL);
00402 
00403        /* short circuit */
00404        if (db == NULL)
00405               return FALSE;
00406 
00407        /* iterate over the possibilities */
00408        for (p = host;
00409             p != NULL;
00410             p = (p == host ? strchr(host, '.') : strchr(p + 1, '.')))
00411        {
00412               /* try the negative case */
00413               snprintf(buf, sizeof buf, "!%s", p);
00414               exists = FALSE;
00415               status = dkimf_db_get(db, buf, 0, NULL, 0, &exists);
00416               if (status != 0)
00417                      return FALSE;
00418               else if (exists)
00419                      return FALSE;
00420 
00421               /* ...and now the positive case */
00422               exists = FALSE;
00423               status = dkimf_db_get(db, &buf[1], 0, NULL, 0, &exists);
00424               if (status != 0)
00425                      return FALSE;
00426               if (exists)
00427                      return TRUE;
00428        }
00429 
00430        return FALSE;
00431 }
00432 
00433 /*
00434 **  DKIMF_CHECKIP -- check a peerlist table for an IP address or its matching
00435 **                 wildcards
00436 **
00437 **  Parameters:
00438 **     db -- db to check
00439 **     ip -- IP address to find
00440 **
00441 **  Return value:
00442 **     TRUE if there's a match, FALSE otherwise.
00443 */
00444 
00445 _Bool
00446 dkimf_checkip(DKIMF_DB db, struct sockaddr *ip)
00447 {
00448        _Bool exists;
00449        char ipbuf[DKIM_MAXHOSTNAMELEN + 1];
00450 
00451        assert(ip != NULL);
00452 
00453        /* short circuit */
00454        if (db == NULL)
00455               return FALSE;
00456 
00457 #if AF_INET6
00458        if (ip->sa_family == AF_INET6)
00459        {
00460               int status;
00461               int bits;
00462               size_t dst_len;
00463               char *dst;
00464               struct sockaddr_in6 sin6;
00465               struct in6_addr addr;
00466 
00467               memcpy(&sin6, ip, sizeof sin6);
00468 
00469               memcpy(&addr, &sin6.sin6_addr, sizeof addr);
00470 
00471               memset(ipbuf, '\0', sizeof ipbuf);
00472               ipbuf[0] = '!';
00473 
00474               dst = &ipbuf[1];
00475               dst_len = sizeof ipbuf - 1;
00476 
00477               inet_ntop(AF_INET6, &addr, dst, dst_len);
00478               dkimf_lowercase((u_char *) dst);
00479 
00480               exists = FALSE;
00481 
00482               status = dkimf_db_get(db, ipbuf, 0, NULL, 0, &exists);
00483               if (status != 0)
00484                      return FALSE;
00485               if (exists)
00486                      return FALSE;
00487 
00488               status = dkimf_db_get(db, &ipbuf[1], 0, NULL, 0,
00489                                     &exists);
00490               if (status != 0)
00491                      return FALSE;
00492               if (exists)
00493                      return TRUE;
00494 
00495               /* iterate over possible bitwise expressions */
00496               for (bits = 0; bits <= 128; bits++)
00497               {
00498                      size_t sz;
00499 
00500                      /* try this one */
00501                      memset(ipbuf, '\0', sizeof ipbuf);
00502                      ipbuf[0] = '!';
00503 
00504                      dst = &ipbuf[1];
00505                      dst_len = sizeof ipbuf - 1;
00506 
00507                      inet_ntop(AF_INET6, &addr, dst, dst_len);
00508                      dkimf_lowercase((u_char *) dst);
00509 
00510                      sz = strlcat(ipbuf, "/", sizeof ipbuf);
00511                      if (sz >= sizeof ipbuf)
00512                             return FALSE;
00513 
00514                      dst = &ipbuf[sz];
00515                      dst_len = sizeof ipbuf - sz;
00516 
00517                      sz = snprintf(dst, dst_len, "%d", 128 - bits);
00518                      if (sz >= sizeof ipbuf)
00519                             return FALSE;
00520 
00521                      exists = FALSE;
00522 
00523                      status = dkimf_db_get(db, ipbuf, 0, NULL, 0, &exists);
00524                      if (status != 0)
00525                             return FALSE;
00526                      else if (exists)
00527                             return FALSE;
00528 
00529                      status = dkimf_db_get(db, &ipbuf[1], 0, NULL, 0,
00530                                            &exists);
00531                      if (status != 0)
00532                             return FALSE;
00533                      else if (exists)
00534                             return TRUE;
00535 
00536                      /* flip off a bit */
00537                      if (bits != 128)
00538                      {
00539                             int idx;
00540                             int bit;
00541 
00542                             idx = 15 - (bits / 8);
00543                             bit = bits % 8;
00544                             addr.s6_addr[idx] &= ~(1 << bit);
00545                      }
00546               }
00547        }
00548 #endif /* AF_INET6 */
00549 
00550        if (ip->sa_family == AF_INET)
00551        {
00552               _Bool exists;
00553               int c;
00554               int status;
00555               int bits;
00556               struct in_addr addr;
00557               struct in_addr mask;
00558               struct sockaddr_in sin;
00559 
00560               memcpy(&sin, ip, sizeof sin);
00561               memcpy(&addr.s_addr, &sin.sin_addr, sizeof addr.s_addr);
00562 
00563               /* try the IP address directly */
00564               exists = FALSE;
00565 
00566               ipbuf[0] = '!';
00567               (void) dkimf_inet_ntoa(addr, &ipbuf[1], sizeof ipbuf - 1);
00568               status = dkimf_db_get(db, ipbuf, 0, NULL, 0, &exists);
00569               if (status != 0)
00570                      return FALSE;
00571               if (exists)
00572                      return FALSE;
00573 
00574               status = dkimf_db_get(db, &ipbuf[1], 0, NULL, 0, &exists);
00575               if (status != 0)
00576                      return FALSE;
00577               if (exists)
00578                      return TRUE;
00579 
00580               /* iterate over possible bitwise expressions */
00581               for (bits = 32; bits >= 0; bits--)
00582               {
00583                      if (bits == 32)
00584                      {
00585                             mask.s_addr = 0xffffffff;
00586                      }
00587                      else
00588                      {
00589                             mask.s_addr = 0;
00590                             for (c = 0; c < bits; c++)
00591                                    mask.s_addr |= htonl(1 << (31 - c));
00592                      }
00593 
00594                      addr.s_addr = addr.s_addr & mask.s_addr;
00595 
00596                      memset(ipbuf, '\0', sizeof ipbuf);
00597                      ipbuf[0] = '!';
00598                      (void) dkimf_inet_ntoa(addr, &ipbuf[1],
00599                                             sizeof ipbuf - 1);
00600                      c = strlen(ipbuf);
00601                      ipbuf[c] = '/';
00602                      c++;
00603 
00604                      snprintf(&ipbuf[c], sizeof ipbuf - c, "%d", bits);
00605 
00606                      exists = FALSE;
00607                      status = dkimf_db_get(db, ipbuf, 0, NULL, 0, &exists);
00608                      if (status != 0)
00609                             return FALSE;
00610                      if (exists)
00611                             return FALSE;
00612 
00613                      status = dkimf_db_get(db, &ipbuf[1], 0, NULL, 0,
00614                                            &exists);
00615                      if (status != 0)
00616                             return FALSE;
00617                      if (exists)
00618                             return TRUE;
00619 
00620                      (void) dkimf_inet_ntoa(mask, &ipbuf[c],
00621                                             sizeof ipbuf - c);
00622               
00623                      exists = FALSE;
00624                      status = dkimf_db_get(db, ipbuf, 0, NULL, 0,
00625                                            &exists);
00626                      if (status != 0)
00627                             return FALSE;
00628                      if (exists)
00629                             return FALSE;
00630 
00631                      status = dkimf_db_get(db, &ipbuf[1], 0, NULL, 0,
00632                                            &exists);
00633                      if (status != 0)
00634                             return FALSE;
00635                      if (exists)
00636                             return TRUE;
00637               }
00638        }
00639 
00640        return FALSE;
00641 }
00642 
00643 #ifdef POPAUTH
00644 /*
00645 **  DKIMF_INITPOPAUTH -- initialize POPAUTH stuff
00646 **
00647 **  Parameters:
00648 **     None.
00649 **
00650 **  Return value:
00651 **     0 on success, an error code on failure.  See pthread_mutex_init().
00652 */
00653 
00654 int
00655 dkimf_initpopauth(void)
00656 {
00657        return pthread_mutex_init(&pop_lock, NULL);
00658 }
00659 
00660 /*
00661 **  DKIMF_CHECKPOPAUTH -- check a POP before SMTP database for client
00662 **                        authentication
00663 **
00664 **  Parameters:
00665 **     db -- DB handle to use for searching
00666 **     ip -- IP address to find
00667 **
00668 **  Return value:
00669 **     TRUE iff the database could be opened and the client was verified.
00670 **
00671 **  Notes:
00672 **     - does the key contain anything meaningful, like an expiry time?
00673 */
00674 
00675 _Bool
00676 dkimf_checkpopauth(DKIMF_DB db, struct sockaddr *ip)
00677 {
00678        _Bool exists;
00679        int status;
00680        struct sockaddr_in *sin;
00681        struct in_addr addr;
00682        char ipbuf[DKIM_MAXHOSTNAMELEN + 1];
00683 
00684        assert(ip != NULL);
00685 
00686        if (db == NULL)
00687               return FALSE;
00688 
00689        /* skip anything not IPv4 (for now) */
00690        if (ip->sa_family != AF_INET)
00691               return FALSE;
00692        else
00693               sin = (struct sockaddr_in *) ip;
00694 
00695 
00696        memcpy(&addr.s_addr, &sin->sin_addr, sizeof addr.s_addr);
00697 
00698        dkimf_inet_ntoa(addr, ipbuf, sizeof ipbuf);
00699        exists = FALSE;
00700        status = dkimf_db_get(db, ipbuf, 0, NULL, 0, &exists);
00701        return (status == 0 && exists);
00702 }
00703 #endif /* POPAUTH */
00704 
00705 #ifdef _FFR_REPLACE_RULES
00706 /*
00707 **  DKIMF_LOAD_REPLIST -- load a list of replace patterns
00708 **
00709 **  Parameters:
00710 **     in -- input stream (must already be open)
00711 **     list -- list to be updated
00712 **
00713 **  Return value:
00714 **     TRUE if successful, FALSE otherwise
00715 **
00716 **  Side effects:
00717 **     Prints an error message when appropriate.
00718 */
00719 
00720 _Bool
00721 dkimf_load_replist(FILE *in, struct replace **list)
00722 {
00723        int line;
00724        int status;
00725        char *p;
00726        struct replace *newrep;
00727        char rule[BUFRSZ + 1];
00728 
00729        assert(in != NULL);
00730        assert(list != NULL);
00731 
00732        memset(rule, '\0', sizeof rule);
00733 
00734        while (fgets(rule, sizeof(rule) - 1, in) != NULL)
00735        {
00736               line++;
00737 
00738               for (p = rule; *p != '\0'; p++)
00739               {
00740                      if (*p == '\n' || *p == '#')
00741                      {
00742                             *p = '\0';
00743                             break;
00744                      }
00745               }
00746 
00747               if (dkimf_isblank(rule))
00748                      continue;
00749 
00750               newrep = (struct replace *) malloc(sizeof(struct replace));
00751               if (newrep == NULL)
00752               {
00753                      fprintf(stderr, "%s: malloc(): %s\n", progname,
00754                              strerror(errno));
00755                      return FALSE;
00756               }
00757 
00758               p = strrchr(rule, '\t');
00759               if (p == NULL)
00760                      return FALSE;
00761 
00762               *p = '\0';
00763 
00764               status = regcomp(&newrep->repl_re, rule, 0);
00765               if (status != 0)
00766               {
00767                      fprintf(stderr, "%s: regcomp() failed\n", progname);
00768                      return FALSE;
00769               }
00770 
00771               newrep->repl_txt = strdup(p + 1);
00772               if (newrep->repl_txt == NULL)
00773               {
00774                      fprintf(stderr, "%s: strdup(): %s\n", progname,
00775                              strerror(errno));
00776                      return FALSE;
00777               }
00778 
00779               newrep->repl_next = *list;
00780 
00781               *list = newrep;
00782        }
00783 
00784        return TRUE;
00785 }
00786 
00787 /*
00788 **  DKIMF_FREE_REPLIST -- destroy a list of replacement information
00789 **
00790 **  Parameters:
00791 **     list -- list to destroy
00792 **
00793 **  Return value:
00794 **     None.
00795 */
00796 
00797 void
00798 dkimf_free_replist(struct replace *list)
00799 {
00800        struct replace *cur;
00801        struct replace *next;
00802 
00803        assert(list != NULL);
00804 
00805        for (cur = list; cur != NULL; cur = next)
00806        {
00807               next = cur->repl_next;
00808               regfree(&cur->repl_re);
00809               free(cur->repl_txt);
00810               free(cur);
00811        }
00812 }
00813 
00814 #endif /* _FFR_REPLACE_RULES */
00815 
00816 /*
00817 **  DKIMF_INET_NTOA -- thread-safe inet_ntoa()
00818 **
00819 **  Parameters:
00820 **     a -- (struct in_addr) to be converted
00821 **     buf -- destination buffer
00822 **     buflen -- number of bytes at buf
00823 **
00824 **  Return value:
00825 **     Size of the resultant string.  If the result is greater than buflen,
00826 **     then buf does not contain the complete result.
00827 */
00828 
00829 size_t
00830 dkimf_inet_ntoa(struct in_addr a, char *buf, size_t buflen)
00831 {
00832        in_addr_t addr;
00833 
00834        assert(buf != NULL);
00835 
00836        addr = ntohl(a.s_addr);
00837 
00838        return snprintf(buf, buflen, "%d.%d.%d.%d",
00839                        (addr >> 24), (addr >> 16) & 0xff,
00840                        (addr >> 8) & 0xff, addr & 0xff);
00841 }
00842 
00843 /*
00844 **  DKIMF_TRIMSPACES -- trim trailing whitespace
00845 **
00846 **  Parameters:
00847 **     str -- string to modify
00848 **
00849 **  Return value:
00850 **     None.
00851 */
00852 
00853 void
00854 dkimf_trimspaces(u_char *str)
00855 {
00856        size_t len = 0;
00857        u_char *p;
00858        u_char *last;
00859        u_char *firsttext = NULL;
00860 
00861        assert(str != NULL);
00862 
00863        last = NULL;
00864 
00865        for (p = str; *p != '\0'; p++)
00866        {
00867               len++;
00868 
00869               if (isascii(*p) && isspace(*p))
00870               {
00871                      if (last == NULL)
00872                      {
00873                             last = p;
00874                             continue;
00875                      }
00876               }
00877               else
00878               {
00879                      last = NULL;
00880                      if (firsttext == NULL)
00881                             firsttext = p;
00882               }
00883        }
00884 
00885        if (last != NULL)
00886               *last = '\0';
00887 
00888        if (firsttext != NULL && firsttext != str)
00889               memmove(str, firsttext, len - (firsttext - str) + 1);
00890 }
00891 
00892 /*
00893 **  DKIMF_STRIPCR -- remove CRs
00894 **
00895 **  Parameters:
00896 **     str -- string to modify
00897 **
00898 **  Return value:
00899 **     None.
00900 */
00901 
00902 void
00903 dkimf_stripcr(char *str)
00904 {
00905        char *p;
00906        char *q;
00907 
00908        assert(str != NULL);
00909 
00910        for (p = str, q = str; *p != '\0'; p++)
00911        {
00912               if (*p == '\r')
00913                      continue;
00914 
00915               if (q != p)
00916                      *q = *p;
00917               q++;
00918        }
00919 
00920        if (q != p)
00921               *q = *p;
00922 }
00923 
00924 /*
00925 **  DKIMF_MKPATH -- generate a path
00926 **
00927 **  Parameters:
00928 **     path -- output buffer
00929 **     pathlen -- bytes available at "path"
00930 **     root -- root to infer; if empty, use getcwd()
00931 **     file -- filename to use
00932 **
00933 **  Return value:
00934 **     None.
00935 */
00936 
00937 void
00938 dkimf_mkpath(char *path, size_t pathlen, char *root, char *file)
00939 {
00940        assert(path != NULL);
00941        assert(root != NULL);
00942        assert(file != NULL);
00943 
00944        if (file[0] == '/')                       /* explicit path */
00945        {
00946               strlcpy(path, file, pathlen);
00947        }
00948        else if (root[0] == '\0')                 /* no root, use cwd */
00949        {
00950               (void) getcwd(path, pathlen);
00951               strlcat(path, "/", pathlen);
00952               strlcat(path, file, pathlen);
00953        }
00954        else                                      /* use root */
00955        {
00956               strlcpy(path, root, pathlen);
00957               if (root[strlen(root) - 1] != '/')
00958                      strlcat(path, "/", pathlen);
00959               strlcat(path, file, pathlen);
00960        }
00961 }
00962 
00963 /*
00964 **  DKIMF_HOSTLIST -- see if a hostname is in a pattern of hosts/domains
00965 **
00966 **  Parameters:
00967 **     host -- hostname to compare
00968 **     list -- NULL-terminated char * array to search
00969 **
00970 **  Return value:
00971 **     TRUE iff either "host" was in the list or it match a domain pattern
00972 **     found in the list.
00973 */
00974 
00975 _Bool
00976 dkimf_hostlist(char *host, char **list)
00977 {
00978        int c;
00979        char *p;
00980 
00981        assert(host != NULL);
00982        assert(list != NULL);
00983 
00984        /* walk the entire list */
00985        for (c = 0; list[c] != NULL; c++)
00986        {
00987               /* first try a full hostname match */
00988               if (strcasecmp(host, list[c]) == 0)
00989                      return TRUE;
00990 
00991               /* try each domain */
00992               for (p = strchr(host, '.'); p != NULL; p = strchr(p + 1, '.'))
00993               {
00994                      if (strcasecmp(p, list[c]) == 0)
00995                             return TRUE;
00996               }
00997        }
00998 
00999        /* not found */
01000        return FALSE;
01001 }
01002 
01003 /*
01004 **  DKIMF_DSTRING_RESIZE -- resize a dynamic string (dstring)
01005 **
01006 **  Parameters:
01007 **     dstr -- DKIMF_DSTRING handle
01008 **     len -- number of bytes desired
01009 **
01010 **  Return value:
01011 **     TRUE iff the resize worked (or wasn't needed)
01012 **
01013 **  Notes:
01014 **     This will actually ensure that there are "len" bytes available.
01015 **     The caller must account for the NULL byte when requesting a
01016 **     specific size.
01017 */
01018 
01019 static _Bool
01020 dkimf_dstring_resize(struct dkimf_dstring *dstr, int len)
01021 {
01022        int newsz;
01023        u_char *new;
01024 
01025        assert(dstr != NULL);
01026        assert(len > 0);
01027 
01028        if (dstr->ds_alloc >= len)
01029               return TRUE;
01030 
01031        /* must resize */
01032        for (newsz = dstr->ds_alloc * 2;
01033             newsz < len;
01034             newsz *= 2)
01035        {
01036               /* impose ds_max limit, if specified */
01037               if (dstr->ds_max > 0 && newsz > dstr->ds_max)
01038               {
01039                      if (len <= dstr->ds_max)
01040                      {
01041                             newsz = len;
01042                             break;
01043                      }
01044 
01045                      return FALSE;
01046               }
01047 
01048               /* check for overflow */
01049               if (newsz > INT_MAX / 2)
01050               {
01051                      /* next iteration will overflow "newsz" */
01052                      return FALSE;
01053               }
01054        }
01055 
01056        new = malloc(newsz);
01057        if (new == NULL)
01058               return FALSE;
01059 
01060        memcpy(new, dstr->ds_buf, dstr->ds_alloc);
01061 
01062        free(dstr->ds_buf);
01063 
01064        dstr->ds_alloc = newsz;
01065        dstr->ds_buf = new;
01066 
01067        return TRUE;
01068 }
01069 
01070 /*
01071 **  DKIMF_DSTRING_NEW -- make a new dstring
01072 **
01073 **  Parameters:
01074 **     dkim -- DKIM handle
01075 **     len -- initial number of bytes
01076 **     maxlen -- maximum allowed length (0 == unbounded)
01077 **
01078 **  Return value:
01079 **     A DKIMF_DSTRING handle, or NULL on failure.
01080 */
01081 
01082 struct dkimf_dstring *
01083 dkimf_dstring_new(int len, int maxlen)
01084 {
01085        struct dkimf_dstring *new;
01086 
01087        /* fail on invalid parameters */
01088        if ((maxlen > 0 && len > maxlen) || len == 0)
01089               return NULL;
01090 
01091        if (len < BUFRSZ)
01092               len = BUFRSZ;
01093 
01094        new = malloc(sizeof(struct dkimf_dstring));
01095        if (new == NULL)
01096               return NULL;
01097 
01098        new->ds_buf = malloc(len);
01099        if (new->ds_buf == NULL)
01100        {
01101               free(new);
01102               return NULL;
01103        }
01104 
01105        memset(new->ds_buf, '\0', len);
01106        new->ds_alloc = len;
01107        new->ds_len = 0;
01108        new->ds_max = maxlen;
01109 
01110        return new;
01111 }
01112 
01113 /*
01114 **  DKIMF_DSTRING_FREE -- destroy an existing dstring
01115 **
01116 **  Parameters:
01117 **     dstr -- DKIMF_DSTRING handle to be destroyed
01118 **
01119 **  Return value:
01120 **     None.
01121 */
01122 
01123 void
01124 dkimf_dstring_free(struct dkimf_dstring *dstr)
01125 {
01126        assert(dstr != NULL);
01127 
01128        free(dstr->ds_buf);
01129        free(dstr);
01130 }
01131 
01132 /*
01133 **  DKIMF_DSTRING_COPY -- copy data into a dstring
01134 **
01135 **  Parameters:
01136 **     dstr -- DKIMF_DSTRING handle to update
01137 **     str -- input string
01138 **
01139 **  Return value:
01140 **     TRUE iff the copy succeeded.
01141 **
01142 **  Side effects:
01143 **     The dstring may be resized.
01144 */
01145 
01146 _Bool
01147 dkimf_dstring_copy(struct dkimf_dstring *dstr, u_char *str)
01148 {
01149        int len;
01150 
01151        assert(dstr != NULL);
01152        assert(str != NULL);
01153 
01154        len = strlen((char *) str);
01155 
01156        /* too big? */
01157        if (dstr->ds_max > 0 && len >= dstr->ds_max)
01158               return FALSE;
01159 
01160        /* fits now? */
01161        if (dstr->ds_alloc <= len)
01162        {
01163               /* nope; try to resize */
01164               if (!dkimf_dstring_resize(dstr, len + 1))
01165                      return FALSE;
01166        }
01167 
01168        /* copy */
01169        dstr->ds_len = strlcpy((char *) dstr->ds_buf, (char *) str,
01170                               dstr->ds_alloc);
01171 
01172        return TRUE;
01173 }
01174 
01175 /*
01176 **  DKIMF_DSTRING_CAT -- append data onto a dstring
01177 **
01178 **  Parameters:
01179 **     dstr -- DKIMF_DSTRING handle to update
01180 **     str -- input string
01181 **
01182 **  Return value:
01183 **     TRUE iff the update succeeded.
01184 **
01185 **  Side effects:
01186 **     The dstring may be resized.
01187 */
01188 
01189 _Bool
01190 dkimf_dstring_cat(struct dkimf_dstring *dstr, u_char *str)
01191 {
01192        int len;
01193 
01194        assert(dstr != NULL);
01195        assert(str != NULL);
01196 
01197        len = strlen((char *) str) + dstr->ds_len;
01198 
01199        /* too big? */
01200        if (dstr->ds_max > 0 && len >= dstr->ds_max)
01201               return FALSE;
01202 
01203        /* fits now? */
01204        if (dstr->ds_alloc <= len)
01205        {
01206               /* nope; try to resize */
01207               if (!dkimf_dstring_resize(dstr, len + 1))
01208                      return FALSE;
01209        }
01210 
01211        /* append */
01212        dstr->ds_len = strlcat((char *) dstr->ds_buf, (char *) str,
01213                               dstr->ds_alloc);
01214 
01215        return TRUE;
01216 }
01217 
01218 /*
01219 **  DKIMF_DSTRING_CAT1 -- append one byte onto a dstring
01220 **
01221 **  Parameters:
01222 **     dstr -- DKIMF_DSTRING handle to update
01223 **     c -- input character
01224 **
01225 **  Return value:
01226 **     TRUE iff the update succeeded.
01227 **
01228 **  Side effects:
01229 **     The dstring may be resized.
01230 */
01231 
01232 _Bool
01233 dkimf_dstring_cat1(struct dkimf_dstring *dstr, int c)
01234 {
01235        int len;
01236 
01237        assert(dstr != NULL);
01238 
01239        len = dstr->ds_len + 1;
01240 
01241        /* too big? */
01242        if (dstr->ds_max > 0 && len >= dstr->ds_max)
01243               return FALSE;
01244 
01245        /* fits now? */
01246        if (dstr->ds_alloc <= len)
01247        {
01248               /* nope; try to resize */
01249               if (!dkimf_dstring_resize(dstr, len + 1))
01250                      return FALSE;
01251        }
01252 
01253        /* append */
01254        dstr->ds_buf[dstr->ds_len++] = c;
01255        dstr->ds_buf[dstr->ds_len] = '\0';
01256 
01257        return TRUE;
01258 }
01259 
01260 /*
01261 **  DKIMF_DSTRING_CATN -- append 'n' bytes onto a dstring
01262 **
01263 **  Parameters:
01264 **     dstr -- DKIMF_DSTRING handle to update
01265 **     str -- input string
01266 **     nbytes -- number of bytes to append
01267 **
01268 **  Return value:
01269 **     TRUE iff the update succeeded.
01270 **
01271 **  Side effects:
01272 **     The dstring may be resized.
01273 */
01274 
01275 _Bool
01276 dkimf_dstring_catn(struct dkimf_dstring *dstr, unsigned char *str,
01277                    size_t nbytes)
01278 {
01279        size_t needed;
01280 
01281        assert(dstr != NULL);
01282        assert(str != NULL);
01283 
01284        needed = dstr->ds_len + nbytes;
01285 
01286        /* too big? */
01287        if (dstr->ds_max > 0 && needed >= dstr->ds_max)
01288               return FALSE;
01289 
01290        /* fits now? */
01291        if (dstr->ds_alloc <= needed)
01292        {
01293               /* nope; try to resize */
01294               if (!dkimf_dstring_resize(dstr, needed + 1))
01295                      return FALSE;
01296        }
01297 
01298        /* append */
01299        memcpy(dstr->ds_buf + dstr->ds_len, str, nbytes);
01300        dstr->ds_len += nbytes;
01301        dstr->ds_buf[dstr->ds_len] = '\0';
01302 
01303        return TRUE;
01304 }
01305 
01306 /*
01307 **  DKIMF_DSTRING_GET -- retrieve data in a dstring
01308 **
01309 **  Parameters:
01310 **     dstr -- DKIMF_DSTRING handle whose string should be retrieved
01311 **
01312 **  Return value:
01313 **     Pointer to the NULL-terminated contents of "dstr".
01314 */
01315 
01316 u_char *
01317 dkimf_dstring_get(struct dkimf_dstring *dstr)
01318 {
01319        assert(dstr != NULL);
01320 
01321        return dstr->ds_buf;
01322 }
01323 
01324 /*
01325 **  DKIMF_DSTRING_LEN -- retrieve length of data in a dstring
01326 **
01327 **  Parameters:
01328 **     dstr -- DKIMF_DSTRING handle whose string should be retrieved
01329 **
01330 **  Return value:
01331 **     Number of bytes in a dstring.
01332 */
01333 
01334 int
01335 dkimf_dstring_len(struct dkimf_dstring *dstr)
01336 {
01337        assert(dstr != NULL);
01338 
01339        return dstr->ds_len;
01340 }
01341 
01342 /*
01343 **  DKIMF_DSTRING_BLANK -- clear out the contents of a dstring
01344 **
01345 **  Parameters:
01346 **     dstr -- DKIMF_DSTRING handle whose string should be cleared
01347 **
01348 **  Return value:
01349 **     None.
01350 */
01351 
01352 void
01353 dkimf_dstring_blank(struct dkimf_dstring *dstr)
01354 {
01355        assert(dstr != NULL);
01356 
01357        dstr->ds_len = 0;
01358        dstr->ds_buf[0] = '\0';
01359 }
01360 
01361 /*
01362 **  DKIMF_DSTRING_CHOP -- truncate contents of a dstring
01363 **
01364 **  Parameters:
01365 **     dstr -- DKIMF_DSTRING handle whose string should be cleared
01366 **     len -- length after which to clobber
01367 **
01368 **  Return value:
01369 **     None.
01370 */
01371 
01372 void
01373 dkimf_dstring_chop(struct dkimf_dstring *dstr, int len)
01374 {
01375        assert(dstr != NULL);
01376 
01377        if (len < dstr->ds_len)
01378        {
01379               dstr->ds_len = len;
01380               dstr->ds_buf[len] = '\0';
01381        }
01382 }
01383 
01384 /*
01385 **  DKIMF_DSTRING_PRINTF -- write variable length formatted output to a dstring
01386 **
01387 **  Parameters:
01388 **     dstr -- DKIMF_STRING handle to be updated
01389 **     fmt -- format
01390 **     ... -- variable arguments
01391 **
01392 **  Return value:
01393 **     New size, or -1 on error.
01394 */
01395 
01396 size_t
01397 dkimf_dstring_printf(struct dkimf_dstring *dstr, char *fmt, ...)
01398 {
01399        size_t len;
01400        va_list ap;
01401        va_list ap2;
01402 
01403        assert(dstr != NULL);
01404        assert(fmt != NULL);
01405 
01406        va_start(ap, fmt);
01407        va_copy(ap2, ap);
01408        len = vsnprintf((char *) dstr->ds_buf + dstr->ds_len, dstr->ds_alloc,
01409                        fmt, ap);
01410        va_end(ap);
01411 
01412        if (len > dstr->ds_len)
01413        {
01414               if (!dkimf_dstring_resize(dstr, len + 1))
01415               {
01416                      va_end(ap2);
01417                      return (size_t) -1;
01418               }
01419 
01420               len = vsnprintf((char *) dstr->ds_buf + dstr->ds_len,
01421                               dstr->ds_alloc, fmt, ap2);
01422        }
01423 
01424        va_end(ap2);
01425 
01426        dstr->ds_len += len;
01427 
01428        return dstr->ds_len;
01429 }
01430 
01431 /*
01432 **  DKIMF_SOCKET_CLEANUP -- try to clean up the socket
01433 **
01434 **  Parameters:
01435 **     sockspec -- socket specification
01436 **
01437 **  Return value:
01438 **     0 -- nothing to cleanup or cleanup successful
01439 **     other -- an error code (a la errno)
01440 */
01441 
01442 int
01443 dkimf_socket_cleanup(char *sockspec)
01444 {
01445        int s;
01446        char *colon;
01447        struct sockaddr_un sock;
01448 
01449        assert(sockspec != NULL);
01450 
01451        /* we only care about "local" or "unix" sockets */
01452        colon = strchr(sockspec, ':');
01453        if (colon != NULL)
01454        {
01455               if (strncasecmp(sockspec, "local:", 6) != 0 &&
01456                   strncasecmp(sockspec, "unix:", 5) != 0)
01457                      return 0;
01458        }
01459 
01460        /* find the filename */
01461        if (colon == NULL)
01462        {
01463               colon = sockspec;
01464        }
01465        else
01466        {
01467               if (*(colon + 1) == '\0')
01468                      return EINVAL;
01469        }
01470 
01471        /* get a socket */
01472        s = socket(PF_UNIX, SOCK_STREAM, 0);
01473        if (s == -1)
01474               return errno;
01475 
01476        /* set up a connection */
01477        memset(&sock, '\0', sizeof sock);
01478 #ifdef BSD
01479        sock.sun_len = sizeof sock;
01480 #endif /* BSD */
01481        sock.sun_family = PF_UNIX;
01482        strlcpy(sock.sun_path, colon + 1, sizeof sock.sun_path);
01483 
01484        /* try to connect */
01485        if (connect(s, (struct sockaddr *) &sock, (socklen_t) sizeof sock) != 0)
01486        {
01487               /* if ECONNREFUSED, try to unlink */
01488               if (errno == ECONNREFUSED)
01489               {
01490                      close(s);
01491 
01492                      if (unlink(sock.sun_path) == 0)
01493                             return 0;
01494                      else
01495                             return errno;
01496               }
01497 
01498               /* if ENOENT, the socket's not there */
01499               else if (errno == ENOENT)
01500               {
01501                      close(s);
01502 
01503                      return 0;
01504               }
01505 
01506               /* something else happened */
01507               else
01508               {
01509                      int saveerr;
01510 
01511                      saveerr = errno;
01512 
01513                      close(s);
01514 
01515                      return saveerr;
01516               }
01517        }
01518 
01519        /* connection apparently succeeded */
01520        close(s);
01521        return EADDRINUSE;
01522 }
01523 
01524 /*
01525 **  DKIMF_MKREGEXP -- make a regexp string from a glob string
01526 **
01527 **  Parameters:
01528 **     src -- source string
01529 **     dst -- destination string
01530 **     dstlen -- space available at "dest"
01531 **
01532 **  Return value:
01533 **     TRUE iff "dest" was big enough (based on destlen)
01534 */
01535 
01536 _Bool
01537 dkimf_mkregexp(char *src, char *dst, size_t dstlen)
01538 {
01539        char *p;
01540        char *q;
01541        char *end;
01542 
01543        assert(src != NULL);
01544        assert(dst != NULL);
01545 
01546        if (dstlen == 0)
01547               return FALSE;
01548 
01549        dst[0] = '^';
01550 
01551        end = dst + dstlen;
01552 
01553        for (p = src, q = dst + 1; *p != '\0' && q < end; p++)
01554        {
01555               switch (*p)
01556               {
01557                 case '*':
01558                      *q = '.';
01559                      q++;
01560                      *q = '*';
01561                      q++;
01562                      break;
01563 
01564                 case '.':
01565                      *q = '\\';
01566                      q++;
01567                      *q = '.';
01568                      q++;
01569                      break;
01570 
01571                 default:
01572                      *q = *p;
01573                      q++;
01574                      break;
01575               }
01576        }
01577 
01578        *q++ = '$';
01579 
01580        if (q >= end)
01581               return FALSE;
01582        else
01583               return TRUE;
01584 }
01585 
01586 /*
01587 **  DKIMF_BASE64_ENCODE_FILE -- base64-encode a file
01588 **
01589 **  Parameters:
01590 **     infd -- input file descriptor
01591 **     out -- output stream
01592 **     lm -- left margin
01593 **     rm -- right margin
01594 **     initial -- space consumed on the initial line
01595 **
01596 **  Return value:
01597 **     None (yet).
01598 */
01599 
01600 void
01601 dkimf_base64_encode_file(infd, out, lm, rm, initial)
01602        int infd;
01603        FILE *out;
01604        int lm;
01605        int rm;
01606        int initial;
01607 {
01608        int len;
01609        int bits;
01610        int c;
01611        int d;
01612        int char_count;
01613        ssize_t rlen;
01614        char buf[MAXBUFRSZ];
01615 
01616        assert(infd >= 0);
01617        assert(out != NULL);
01618        assert(lm >= 0);
01619        assert(rm >= 0);
01620        assert(initial >= 0);
01621 
01622        bits = 0;
01623        char_count = 0;
01624        len = initial;
01625 
01626        (void) lseek(infd, 0, SEEK_SET);
01627 
01628        for (;;)
01629        {
01630               rlen = read(infd, buf, sizeof buf);
01631               if (rlen == -1)
01632                      break;
01633 
01634               for (c = 0; c < rlen; c++)
01635               {
01636                      bits += buf[c];
01637                      char_count++;
01638                      if (char_count == 3)
01639                      {
01640                             fputc(alphabet[bits >> 18], out);
01641                             fputc(alphabet[(bits >> 12) & 0x3f], out);
01642                             fputc(alphabet[(bits >> 6) & 0x3f], out);
01643                             fputc(alphabet[bits & 0x3f], out);
01644                             len += 4;
01645                             if (rm > 0 && lm > 0 && len >= rm - 4)
01646                             {
01647                                    fputc('\n', out);
01648                                    for (d = 0; d < lm; d++)
01649                                           fputc(' ', out);
01650                                    len = lm;
01651                             }
01652                             bits = 0;
01653                             char_count = 0;
01654                      }
01655                      else
01656                      {
01657                             bits <<= 8;
01658                      }
01659               }
01660 
01661               if (rlen < (ssize_t) sizeof buf)
01662                      break;
01663        }
01664 
01665        if (char_count != 0)
01666        {
01667               if (rm > 0 && lm > 0 && len >= rm - 4)
01668               {
01669                      fputc('\n', out);
01670                      for (d = 0; d < lm; d++)
01671                             fputc(' ', out);
01672               }
01673               bits <<= 16 - (8 * char_count);
01674               fputc(alphabet[bits >> 18], out);
01675               fputc(alphabet[(bits >> 12) & 0x3f], out);
01676               if (char_count == 1)
01677                      fputc('=', out);
01678               else
01679                      fputc(alphabet[(bits >> 6) & 0x3f], out);
01680               fputc('=', out);
01681        }
01682 }
01683 
01684 /*
01685 **  DKIMF_SUBDOMAIN -- determine whether or not one domain is a subdomain
01686 **                     of the other
01687 **
01688 **  Parameters:
01689 **     d1 -- candidate domain
01690 **     d2 -- possible superdomain
01691 **
01692 **  Return value:
01693 **     TRUE iff d1 is a subdomain of d2.
01694 */
01695 
01696 _Bool
01697 dkimf_subdomain(char *d1, char *d2)
01698 {
01699        char *p;
01700 
01701        assert(d1 != NULL);
01702        assert(d2 != NULL);
01703 
01704 #if 0
01705        if (strcasecmp(d1, d2) == 0)
01706               return TRUE;
01707 #endif /* 0 */
01708 
01709        for (p = strchr(d1, '.'); p != NULL; p = strchr(p + 1, '.'))
01710        {
01711               if (strcasecmp(d2, p + 1) == 0)
01712                      return TRUE;
01713        }
01714 
01715        return FALSE;
01716 }
01717 
01718 /*
01719 **  DKIMF_IPSTRING -- convert an IP address to a string
01720 **
01721 **  Parameters:
01722 **     buf -- target buffer
01723 **     buflen -- bytes available at "buf"
01724 **     ss -- socket description
01725 **
01726 **  Return value:
01727 **     None.
01728 */
01729 
01730 void
01731 dkimf_ipstring(char *buf, size_t buflen, struct sockaddr_storage *ss)
01732 {
01733        assert(buf != NULL);
01734        assert(ss != NULL);
01735 
01736        switch (ss->ss_family)
01737        {
01738          case AF_INET:
01739          {
01740               struct sockaddr_in *sa;
01741 
01742               sa = (struct sockaddr_in *) ss;
01743 
01744               (void) inet_ntop(ss->ss_family, &sa->sin_addr, buf, buflen);
01745 
01746               break;
01747          }
01748 
01749 #ifdef AF_INET6
01750          case AF_INET6:
01751          {
01752               struct sockaddr_in6 *sa;
01753 
01754               sa = (struct sockaddr_in6 *) ss;
01755 
01756               (void) inet_ntop(ss->ss_family, &sa->sin6_addr, buf, buflen);
01757 
01758               break;
01759          }
01760 #endif /* AF_INET6 */
01761 
01762          default:
01763               break;
01764        }
01765 }
01766 
01767 #ifdef USE_UNBOUND
01768 /*
01769 **  DKIMF_TIMESPEC_PAST -- return TRUE iff the time described by a timespec
01770 **                         structure has passed
01771 **
01772 **  Parameters:
01773 **     ts -- timespec structure to evaluate
01774 **
01775 **  Return value:
01776 **     TRUE if "tv" refers to a time in the past, false otherwise.
01777 */
01778 
01779 _Bool
01780 dkimf_timespec_past(struct timespec *ts)
01781 {
01782        struct timeval now;
01783 
01784        assert(ts != NULL);
01785 
01786        (void) gettimeofday(&now, NULL);
01787 
01788        if (now.tv_sec > ts->tv_sec ||
01789            (now.tv_sec == ts->tv_sec && now.tv_usec * 1000 > ts->tv_nsec))
01790               return TRUE;
01791        else
01792               return FALSE;
01793 }
01794 
01795 /*
01796 **  DKIMF_WAIT_FD -- wait for a descriptor to become read-ready
01797 **
01798 **  Parameters:
01799 **     fd -- descriptor of interest
01800 **     until -- maximum wait time
01801 **
01802 **  Return value:
01803 **     1 -- descriptor is ready
01804 **     0 -- timeout
01805 **     -1 -- error
01806 */
01807 
01808 int
01809 dkimf_wait_fd(int fd, struct timespec *until)
01810 {
01811        fd_set fds;
01812        struct timeval now;
01813        struct timeval left;
01814 
01815        assert(fd >= 0);
01816 
01817        (void) gettimeofday(&now, NULL);
01818 
01819        if (until != NULL)
01820        {
01821               if (until->tv_sec < now.tv_sec ||
01822                   (until->tv_sec == now.tv_sec &&
01823                    until->tv_nsec < now.tv_usec * 1000))
01824               {
01825                      left.tv_sec = 0;
01826                      left.tv_usec = 0;
01827               }
01828               else
01829               {
01830                      left.tv_sec = until->tv_sec - now.tv_sec;
01831                      left.tv_usec = until->tv_nsec / 1000 - now.tv_usec;
01832 
01833                      if (until->tv_nsec / 1000 < now.tv_usec)
01834                      {
01835                             left.tv_usec += 1000000;
01836                             left.tv_sec--;
01837                      }
01838               }
01839        }
01840 
01841        FD_ZERO(&fds);
01842        FD_SET(fd, &fds);
01843 
01844        return select(fd + 1, &fds, NULL, NULL, until == NULL ? NULL : &left);
01845 }
01846 #endif /* USE_UNBOUND */