Back to index

opendkim  2.6.2
vbr.c
Go to the documentation of this file.
00001 /*
00002 **  Copyright (c) 2007, 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 vbr_c_id[] = "@(#)$Id: vbr.c,v 1.5.2.1 2010/10/27 21:43:09 cm-msk Exp $";
00010 #endif /* !lint */
00011 
00012 /* for Solaris */
00013 #ifndef _REENTRANT
00014 # define _REENTRANT
00015 #endif /* ! REENTRANT */
00016 
00017 /* system includes */
00018 #include <sys/param.h>
00019 #include <sys/types.h>
00020 #include <sys/time.h>
00021 #include <netinet/in.h>
00022 #include <arpa/inet.h>
00023 #include <arpa/nameser.h>
00024 #include <netdb.h>
00025 #include <stdlib.h>
00026 #include <string.h>
00027 #include <errno.h>
00028 #include <assert.h>
00029 #include <resolv.h>
00030 
00031 #ifdef __STDC__
00032 # include <stdarg.h>
00033 #else /* __STDC__ */
00034 # include <varargs.h>
00035 #endif /* _STDC_ */
00036 
00037 /* libvbr includes */
00038 #include "vbr.h"
00039 
00040 #ifndef FALSE
00041 # define FALSE                     0
00042 #endif /* ! FALSE */
00043 #ifndef TRUE
00044 # define TRUE               1
00045 #endif /* ! TRUE */
00046 
00047 #define BUFRSZ                     2048
00048 #define       DEFERRLEN            64
00049 #define       DEFTIMEOUT           10
00050 #define MAXCNAMEDEPTH              3
00051 
00052 /* local definitions needed for DNS queries */
00053 #define MAXPACKET           8192
00054 #if defined(__RES) && (__RES >= 19940415)
00055 # define RES_UNC_T          char *
00056 #else /* __RES && __RES >= 19940415 */
00057 # define RES_UNC_T          unsigned char *
00058 #endif /* __RES && __RES >= 19940415 */
00059 #ifndef T_RRSIG
00060 # define T_RRSIG            46
00061 #endif /* ! T_RRSIG */
00062 
00063 #define VBR_DNS_ERROR              (-1)
00064 #define VBR_DNS_SUCCESS            0
00065 #define VBR_DNS_REPLY              1
00066 #define VBR_DNS_NOREPLY            2
00067 #define VBR_DNS_EXPIRED            3
00068 
00069 /* struct vbr_query -- an open VBR query */
00070 struct vbr_query
00071 {
00072        int           vq_error;
00073        size_t        vq_buflen;
00074        void *        vq_qh;
00075        u_char        vq_buf[HFIXEDSZ + MAXPACKET];
00076 };
00077 
00078 struct vbr_handle
00079 {
00080        u_int         vbr_opts;            /* options */
00081        size_t        vbr_errlen;          /* error buffer size */
00082        u_int         vbr_timeout;         /* query timeout */
00083        u_int         vbr_callback_int;    /* callback interval */
00084        void *        vbr_user_context;    /* user context for callback */
00085        void          (*vbr_dns_callback) (const void *);
00086        void *        (*vbr_malloc) (void *, size_t);
00087        void          (*vbr_free) (void *, void *);
00088        void *        vbr_closure;         /* memory closure */
00089        u_char *      vbr_domain;          /* sending domain */
00090        u_char *      vbr_type;            /* message type */
00091        u_char *      vbr_cert;            /* claimed certifiers */
00092        u_char *      vbr_error;           /* error buffer */
00093        u_char **     vbr_trusted;         /* trusted certifiers */
00094        void          *vbr_dns_service;
00095        int           (*vbr_dns_start) (void *, int,
00096                                        unsigned char *,
00097                                        unsigned char *,
00098                                        size_t,
00099                                        void **);
00100        int           (*vbr_dns_cancel) (void *, void *);
00101        int           (*vbr_dns_waitreply) (void *,
00102                                            void *,
00103                                            struct timeval *,
00104                                            size_t *,
00105                                            int *,
00106                                            int *);
00107 };
00108 
00109 /* prototypes */
00110 static void vbr_error __P((VBR *, const char *, ...));
00111 
00112 /* ========================= PRIVATE SECTION ========================= */
00113 
00114 #if HAVE_STRLCPY == 0
00115 
00116 /*
00117 **  Copyright (c) 1999-2002, Sendmail Inc. and its suppliers.
00118 **     All rights reserved.
00119 ** 
00120 **  By using this file, you agree to the terms and conditions set
00121 **  forth in the LICENSE file which can be found at the top level of
00122 **  the sendmail distribution.
00123 **
00124 **  Copyright (c) 2009, The OpenDKIM Project.  All rights reserved.
00125 */
00126 
00127 /*
00128 **  XXX the type of the length parameter has been changed
00129 **  from size_t to ssize_t to avoid theoretical problems with negative
00130 **  numbers passed into these functions.
00131 **  The real solution to this problem is to make sure that this doesn't
00132 **  happen, but for now we'll use this workaround.
00133 */
00134 
00135 #define       strlcpy(x,y,z)       vbr_strlcpy((x), (y), (z))
00136 
00137 /*
00138 **  VBR_STRLCPY -- size bounded string copy
00139 **
00140 **     This is a bounds-checking variant of strcpy.
00141 **     If size > 0, copy up to size-1 characters from the nul terminated
00142 **     string src to dst, nul terminating the result.  If size == 0,
00143 **     the dst buffer is not modified.
00144 **     Additional note: this function has been "tuned" to run fast and tested
00145 **     as such (versus versions in some OS's libc).
00146 **
00147 **     The result is strlen(src).  You can detect truncation (not all
00148 **     of the characters in the source string were copied) using the
00149 **     following idiom:
00150 **
00151 **            char *s, buf[BUFSIZ];
00152 **            ...
00153 **            if (vbr_strlcpy(buf, s, sizeof(buf)) >= sizeof(buf))
00154 **                   goto overflow;
00155 **
00156 **     Parameters:
00157 **            dst -- destination buffer
00158 **            src -- source string
00159 **            size -- size of destination buffer
00160 **
00161 **     Returns:
00162 **            strlen(src)
00163 */
00164 
00165 size_t
00166 vbr_strlcpy(dst, src, size)
00167        register char *dst;
00168        register const char *src;
00169        ssize_t size;
00170 {
00171        register ssize_t i;
00172 
00173        if (size-- <= 0)
00174               return strlen(src);
00175        for (i = 0; i < size && (dst[i] = src[i]) != 0; i++)
00176               continue;
00177        dst[i] = '\0';
00178        if (src[i] == '\0')
00179               return i;
00180        else
00181               return i + strlen(src + i);
00182 }
00183 #endif /* HAVE_STRLCPY == 0 */
00184 
00185 /*
00186 **  VBR_MALLOC -- allocate memory
00187 **
00188 **  Parameters:
00189 **     vbr -- VBR context in which this is performed
00190 **     closure -- opaque closure handle for the allocation
00191 **     nbytes -- number of bytes desired
00192 **
00193 **  Return value:
00194 **     Pointer to allocated memory, or NULL on failure.
00195 */
00196 
00197 static void *
00198 vbr_malloc(VBR *vbr, void *closure, size_t nbytes)
00199 {
00200        assert(vbr != NULL);
00201 
00202        if (vbr->vbr_malloc == NULL)
00203               return malloc(nbytes);
00204        else
00205               return vbr->vbr_malloc(closure, nbytes);
00206 }
00207 
00208 /*
00209 **  VBR_FREE -- release memory
00210 **
00211 **  Parameters:
00212 **     vbr -- VBR context in which this is performed
00213 **     closure -- opaque closure handle for the allocation
00214 **     ptr -- pointer to memory to be freed
00215 **
00216 **  Return value:
00217 **     None.
00218 */
00219 
00220 static void
00221 vbr_free(VBR *vbr, void *closure, void *ptr)
00222 {
00223        assert(vbr != NULL);
00224 
00225        if (vbr->vbr_free == NULL)
00226               free(ptr);
00227        else
00228               vbr->vbr_free(closure, ptr);
00229 }
00230 
00231 /*
00232 **  VBR_VERROR -- log an error into a VBR handle (varargs version)
00233 **
00234 **  Parameters:
00235 **     vbr -- VBR context in which this is performed
00236 **     format -- format to apply
00237 **     va -- argument list
00238 **
00239 **  Return value:
00240 **     None.
00241 */
00242 
00243 static void
00244 vbr_verror(VBR *vbr, const char *format, va_list va)
00245 {
00246        int flen;
00247        int saverr;
00248        u_char *new;
00249 
00250        assert(vbr != NULL);
00251        assert(format != NULL);
00252 
00253        saverr = errno;
00254 
00255        if (vbr->vbr_error == NULL)
00256        {
00257               vbr->vbr_error = vbr_malloc(vbr, vbr->vbr_closure, DEFERRLEN);
00258               if (vbr->vbr_error == NULL)
00259               {
00260                      errno = saverr;
00261                      return;
00262               }
00263               vbr->vbr_errlen = DEFERRLEN;
00264        }
00265 
00266        for (;;)
00267        {
00268               flen = vsnprintf((char *) vbr->vbr_error, vbr->vbr_errlen,
00269                                format, va);
00270 
00271               /* compensate for broken vsnprintf() implementations */
00272               if (flen == -1)
00273                      flen = vbr->vbr_errlen * 2;
00274 
00275               if (flen >= vbr->vbr_errlen)
00276               {
00277                      new = vbr_malloc(vbr, vbr->vbr_closure, flen + 1);
00278                      if (new == NULL)
00279                      {
00280                             errno = saverr;
00281                             return;
00282                      }
00283 
00284                      vbr_free(vbr, vbr->vbr_closure, vbr->vbr_error);
00285                      vbr->vbr_error = new;
00286                      vbr->vbr_errlen = flen + 1;
00287               }
00288               else
00289               {
00290                      break;
00291               }
00292        }
00293 
00294        errno = saverr;
00295 }
00296 
00297 /*
00298 **  VBR_ERROR -- log an error into a VBR handle
00299 **
00300 **  Parameters:
00301 **     vbr -- VBR context in which this is performed
00302 **     format -- format to apply
00303 **     ... -- arguments
00304 **
00305 **  Return value:
00306 **     None.
00307 */
00308 
00309 static void
00310 vbr_error(VBR *vbr, const char *format, ...)
00311 {
00312        va_list va;
00313 
00314        assert(vbr != NULL);
00315        assert(format != NULL);
00316 
00317        va_start(va, format);
00318        vbr_verror(vbr, format, va);
00319        va_end(va);
00320 }
00321 
00322 /*
00323 **  VBR_TIMEOUTS -- do timeout math
00324 **
00325 **  Parameters:
00326 **     timeout -- general VBR timeout
00327 **     ctimeout -- callback timeout
00328 **     wstart -- previous wait start time
00329 **     wstop -- previous wait stop time
00330 **     next -- computed next timeout (updated)
00331 **
00332 **  Return value:
00333 **     None.
00334 */
00335 
00336 static void
00337 vbr_timeouts(struct timeval *timeout, struct timeval *ctimeout,
00338              struct timeval *wstart, struct timeval *wstop,
00339              struct timeval **next)
00340 {
00341        assert(timeout != NULL);
00342        assert(ctimeout != NULL);
00343        assert(wstart != NULL);
00344        assert(wstop != NULL);
00345        assert(next != NULL);
00346 
00347        if (wstop->tv_sec == 0 && wstop->tv_usec == 0)
00348        {
00349               /* first pass */
00350               if (timeout->tv_sec < ctimeout->tv_sec ||
00351                   (timeout->tv_sec == ctimeout->tv_sec &&
00352                    timeout->tv_usec < ctimeout->tv_usec))
00353                      *next = timeout;
00354               else
00355                      *next = ctimeout;
00356        }
00357        else
00358        {
00359               struct timeval to1;
00360               struct timeval to2;
00361 
00362               /* compute start through overall timeout */
00363               memcpy(&to1, wstart, sizeof to1);
00364               to1.tv_sec += timeout->tv_sec;
00365               to1.tv_usec += timeout->tv_usec;
00366               if (to1.tv_usec > 1000000)
00367               {
00368                      to1.tv_sec += (to1.tv_usec / 1000000);
00369                      to1.tv_usec = (to1.tv_usec % 1000000);
00370               }
00371 
00372               /* compute stop through callback timeout */
00373               memcpy(&to2, wstop, sizeof to2);
00374               to2.tv_sec += ctimeout->tv_sec;
00375               to2.tv_usec += ctimeout->tv_usec;
00376               if (to2.tv_usec > 1000000)
00377               {
00378                      to2.tv_sec += (to2.tv_usec / 1000000);
00379                      to2.tv_usec = (to2.tv_usec % 1000000);
00380               }
00381 
00382               /* ...and decide */
00383               if (to1.tv_sec < to2.tv_sec ||
00384                   (to1.tv_sec == to2.tv_sec &&
00385                    to1.tv_usec < to2.tv_usec))
00386                      *next = timeout;
00387               else
00388                      *next = ctimeout;
00389        }
00390 }
00391 
00392 /*
00393 **  VBR_RES_CANCEL -- cancel a pending resolver query
00394 **
00395 **  Parameters:
00396 **     srv -- query service handle (ignored)
00397 **     qh -- query handle (ignored)
00398 **
00399 **  Return value:
00400 **     0 on success, !0 on error
00401 **
00402 **  Notes:
00403 **     The standard UNIX resolver is synchronous, so in theory this can
00404 **     never get called.  We have not yet got any use cases for one thread
00405 **     canceling another thread's pending queries, so for now just return 0.
00406 */
00407 
00408 static int
00409 vbr_res_cancel(void *srv, void *qh)
00410 {
00411        if (qh != NULL)
00412               free(qh);
00413 
00414        return 0;
00415 }
00416 
00417 /*
00418 **  VBR_RES_QUERY -- initiate a DNS query
00419 **
00420 **  Parameters:
00421 **     srv -- service handle (ignored)
00422 **     type -- RR type to query
00423 **     query -- the question to ask
00424 **     buf -- where to write the answer
00425 **     buflen -- bytes at "buf"
00426 **     qh -- query handle, used with vbr_res_waitreply
00427 **
00428 **  Return value:
00429 **     An VBR_DNS_* constant.
00430 **
00431 **  Notes:
00432 **     This is a stub for the stock UNIX resolver (res_) functions, which
00433 **     are synchronous so no handle needs to be created, so "qh" is set to
00434 **     "buf".  "buf" is actually populated before this returns (unless
00435 **     there's an error).
00436 */
00437 
00438 static int
00439 vbr_res_query(void *srv, int type, unsigned char *query, unsigned char *buf,
00440               size_t buflen, void **qh)
00441 {
00442        int n;
00443        int ret;
00444        struct vbr_query *vq;
00445        unsigned char qbuf[HFIXEDSZ + MAXPACKET];
00446 #ifdef HAVE_RES_NINIT
00447        struct __res_state statp;
00448 #endif /* HAVE_RES_NINIT */
00449 
00450 #ifdef HAVE_RES_NINIT
00451        memset(&statp, '\0', sizeof statp);
00452        res_ninit(&statp);
00453 #endif /* HAVE_RES_NINIT */
00454 
00455 #ifdef HAVE_RES_NINIT
00456        n = res_nmkquery(&statp, QUERY, (char *) query, C_IN, type, NULL, 0,
00457                         NULL, qbuf, sizeof qbuf);
00458 #else /* HAVE_RES_NINIT */
00459        n = res_mkquery(QUERY, (char *) query, C_IN, type, NULL, 0, NULL, qbuf,
00460                        sizeof qbuf);
00461 #endif /* HAVE_RES_NINIT */
00462        if (n == (size_t) -1)
00463        {
00464 #ifdef HAVE_RES_NINIT
00465               res_nclose(&statp);
00466 #endif /* HAVE_RES_NINIT */
00467               return VBR_DNS_ERROR;
00468        }
00469 
00470 #ifdef HAVE_RES_NINIT
00471        ret = res_nsend(&statp, qbuf, n, buf, buflen);
00472 #else /* HAVE_RES_NINIT */
00473        ret = res_send(qbuf, n, buf, buflen);
00474 #endif /* HAVE_RES_NINIT */
00475        if (ret == -1)
00476        {
00477 #ifdef HAVE_RES_NINIT
00478               res_nclose(&statp);
00479 #endif /* HAVE_RES_NINIT */
00480               return VBR_DNS_ERROR;
00481        }
00482 
00483 #ifdef HAVE_RES_NINIT
00484        res_nclose(&statp);
00485 #endif /* HAVE_RES_NINIT */
00486 
00487        vq = (struct vbr_query *) malloc(sizeof *vq);
00488        if (vq == NULL)
00489               return VBR_DNS_ERROR;
00490 
00491        if (ret == -1)
00492        {
00493               vq->vq_error = errno;
00494               vq->vq_buflen = 0;
00495        }
00496        else
00497        {
00498               vq->vq_error = 0;
00499               vq->vq_buflen = (size_t) ret;
00500        }
00501 
00502        *qh = (void *) vq;
00503 
00504        return VBR_DNS_SUCCESS;
00505 }
00506 
00507 /*
00508 **  VBR_RES_WAITREPLY -- wait for a reply to a pending query
00509 **
00510 **  Parameters:
00511 **     srv -- service handle
00512 **     qh -- query handle
00513 **     to -- timeout
00514 **     bytes -- number of bytes in the reply (returned)
00515 **     error -- error code (returned)
00516 **
00517 **  Return value:
00518 **     A VBR_DNS_* code.
00519 **
00520 **  Notes:
00521 **     Since the stock UNIX resolver is synchronous, the reply was completed
00522 **     before vbr_res_query() returned, and thus this is almost a no-op.
00523 */
00524 
00525 int
00526 vbr_res_waitreply(void *srv, void *qh, struct timeval *to, size_t *bytes,
00527                   int *error, int *dnssec)
00528 {
00529        struct vbr_query *vq;
00530 
00531        assert(qh != NULL);
00532 
00533        vq = qh;
00534 
00535        if (bytes != NULL)
00536               *bytes = vq->vq_buflen;
00537        if (error != NULL)
00538               *error = vq->vq_error;
00539 
00540        return VBR_DNS_SUCCESS;
00541 }
00542 
00543 /*
00544 **  VBR_TXT_DECODE -- decode a TXT reply
00545 **
00546 **  Parameters:
00547 **     ansbuf -- answer buffer
00548 **     anslen -- size of answer buffer
00549 **     buf -- output buffer
00550 **     buflen -- size of output buffer
00551 **
00552 **  Return value:
00553 **     TRUE iff ansbuf contains an IN TXT reply that could be deocde.
00554 */
00555 
00556 static _Bool
00557 vbr_txt_decode(u_char *ansbuf, size_t anslen, u_char *buf, size_t buflen)
00558 {
00559        int type = -1;
00560        int class = -1;
00561        int qdcount;
00562        int ancount;
00563        int n;
00564        int c;
00565        u_char *cp;
00566        u_char *eom;
00567        u_char *p;
00568        HEADER hdr;
00569        char qname[VBR_MAXHOSTNAMELEN + 1];
00570 
00571        assert(ansbuf != NULL);
00572        assert(buf != NULL);
00573 
00574        /* set up pointers */
00575        memcpy(&hdr, ansbuf, sizeof hdr);
00576        cp = ansbuf + HFIXEDSZ;
00577        eom = ansbuf + anslen;
00578 
00579        /* skip over the name at the front of the answer */
00580        for (qdcount = ntohs((unsigned short) hdr.qdcount);
00581             qdcount > 0;
00582             qdcount--)
00583        {
00584               /* copy it first */
00585               (void) dn_expand(ansbuf, eom, cp, qname, sizeof qname);
00586 
00587               if ((n = dn_skipname(cp, eom)) < 0)
00588                      return FALSE;
00589               cp += n;
00590 
00591               /* extract the type and class */
00592               if (cp + INT16SZ + INT16SZ > eom)
00593                      return FALSE;
00594 
00595               GETSHORT(type, cp);
00596               GETSHORT(class, cp);
00597        }
00598 
00599        if (type != T_TXT || class != C_IN)
00600               return FALSE;
00601 
00602        if (hdr.rcode == NXDOMAIN)
00603               return FALSE;
00604 
00605        /* get the answer count */
00606        ancount = ntohs((unsigned short) hdr.ancount);
00607        if (ancount == 0)
00608               return FALSE;
00609 
00610        /* if truncated, we can't do it */
00611        if (hdr.tc)
00612               return FALSE;
00613 
00614        /* grab the label, even though we know what we asked... */
00615        if ((n = dn_expand(ansbuf, eom, cp, (RES_UNC_T) qname,
00616                           sizeof qname)) < 0)
00617               return FALSE;
00618        /* ...and move past it */
00619        cp += n;
00620 
00621        /* extract the type and class */
00622        if (cp + INT16SZ + INT16SZ > eom)
00623               return FALSE;
00624        GETSHORT(type, cp);
00625        GETSHORT(class, cp);
00626 
00627        /* reject anything that's not valid (stupid wildcards) */
00628        if (type != T_TXT || class != C_IN)
00629               return FALSE;
00630 
00631        /* skip the TTL */
00632        cp += INT32SZ;
00633 
00634        /* get payload length */
00635        if (cp + INT16SZ > eom)
00636               return FALSE;
00637        GETSHORT(n, cp);
00638 
00639        /* XXX -- maybe deal with a partial reply rather than require it all */
00640        if (cp + n > eom)
00641               return FALSE;
00642 
00643        if (n > buflen)
00644               return FALSE;
00645 
00646        /* extract the payload */
00647        memset(buf, '\0', buflen);
00648        p = buf;
00649        while (n > 0)
00650        {
00651               c = *cp++;
00652               n--;
00653               while (c > 0)
00654               {
00655                      *p++ = *cp++;
00656                      c--;
00657                      n--;
00658               }
00659        }
00660 
00661        return TRUE;
00662 }
00663 
00664 /* ========================= PUBLIC SECTION ========================= */
00665 
00666 /*
00667 **  VBR_INIT -- initialize a VBR handle
00668 **
00669 **  Parameters:
00670 **     caller_mallocf -- caller-provided memory allocation function
00671 **     caller_freef -- caller-provided memory release function
00672 **     closure -- memory closure to pass to the above when used
00673 **
00674 **  Return value:
00675 **     A new VBR handle suitable for use with other VBR functions, or
00676 **     NULL on failure.
00677 **  
00678 **  Side effects:
00679 **     Strange radar returns at Indianapolis ARTCC.
00680 */
00681 
00682 VBR *
00683 vbr_init(void *(*caller_mallocf)(void *closure, size_t nbytes),
00684          void (*caller_freef)(void *closure, void *p),
00685          void *closure)
00686 {
00687        VBR *new;
00688 
00689        /* copy the parameters */
00690        new = (VBR *) malloc(sizeof(struct vbr_handle));
00691        if (new == NULL)
00692               return NULL;
00693 
00694        new->vbr_malloc = caller_mallocf;
00695        new->vbr_free = caller_freef;
00696        new->vbr_closure = closure;
00697        new->vbr_timeout = DEFTIMEOUT;
00698        new->vbr_callback_int = 0;
00699        new->vbr_dns_callback = NULL;
00700        new->vbr_user_context = NULL;
00701        new->vbr_errlen = 0;
00702        new->vbr_error = NULL;
00703 
00704        new->vbr_domain = NULL;
00705        new->vbr_type = NULL;
00706        new->vbr_cert = NULL;
00707        new->vbr_trusted = NULL;
00708 
00709        new->vbr_dns_service = NULL;
00710        new->vbr_dns_start = vbr_res_query;
00711        new->vbr_dns_waitreply = vbr_res_waitreply;
00712        new->vbr_dns_cancel = vbr_res_cancel;
00713 
00714        return new;
00715 }
00716 
00717 /*
00718 **  VBR_OPTIONS -- set VBR options
00719 **
00720 **  Parameters:
00721 **     vbr -- VBR handle to modify
00722 **     opts -- bitmask of options to use
00723 **
00724 **  Return value:
00725 **     None.
00726 */
00727 
00728 void
00729 vbr_options(VBR *vbr, unsigned int opts)
00730 {
00731        assert(vbr != NULL);
00732 
00733        vbr->vbr_opts = opts;
00734 }
00735 
00736 #define       CLOBBER(x)    if ((x) != NULL) \
00737                      { \
00738                             vbr_free(vbr, vbr->vbr_closure, (x)); \
00739                             (x) = NULL; \
00740                      }
00741 
00742 /*
00743 **  VBR_CLOSE -- shut down a VBR instance
00744 **
00745 **  Parameters:
00746 **     vbr -- VBR handle to shut down
00747 **
00748 **  Return value:
00749 **     None.
00750 */
00751 
00752 void
00753 vbr_close(VBR *vbr)
00754 {
00755        assert(vbr != NULL);
00756 
00757        CLOBBER(vbr->vbr_error);
00758 
00759        CLOBBER(vbr);
00760 }
00761 
00762 /*
00763 **  VBR_GETERROR -- return any stored error string from within the VBR
00764 **                  context handle
00765 **
00766 **  Parameters:
00767 **     vbr -- VBR handle from which to retrieve an error string
00768 **
00769 **  Return value:
00770 **     A pointer to the stored string, or NULL if none was stored.
00771 */
00772 
00773 const u_char *
00774 vbr_geterror(VBR *vbr)
00775 {
00776        assert(vbr != NULL);
00777 
00778        return vbr->vbr_error;
00779 }
00780 
00781 /* XXX -- need a function to take in a VBR-Info: header and parse it? */
00782 
00783 /*
00784 **  VBR_SETTIMEOUT -- set the DNS timeout
00785 **
00786 **  Parameters:
00787 **     vbr -- VBR handle, created by vbr_init()
00788 **     timeout -- requested timeout (seconds)
00789 **
00790 **  Return value:
00791 **     A VBR_STAT_* constant.
00792 */
00793 
00794 VBR_STAT
00795 vbr_settimeout(VBR *vbr, u_int timeout)
00796 {
00797        assert(vbr != NULL);
00798 
00799        vbr->vbr_timeout = timeout;
00800        return VBR_STAT_OK;
00801 }
00802 
00803 /*
00804 **  VBR_SETCALLBACKINT -- set the DNS callback interval
00805 **
00806 **  Parameters:
00807 **     vbr -- VBR handle, created by vbr_init()
00808 **     cbint -- requested callback interval (seconds)
00809 **
00810 **  Return value:
00811 **     A VBR_STAT_* constant.
00812 */
00813 
00814 VBR_STAT
00815 vbr_setcallbackint(VBR *vbr, u_int cbint)
00816 {
00817        assert(vbr != NULL);
00818 
00819        vbr->vbr_callback_int = cbint;
00820        return VBR_STAT_OK;
00821 }
00822 
00823 /*
00824 **  VBR_SETCALLBACKCTX -- set the DNS callback context
00825 **
00826 **  Parameters:
00827 **     vbr -- VBR handle, created by vbr_init()
00828 **     ctx -- context to pass to the DNS callback
00829 **
00830 **  Return value:
00831 **     A VBR_STAT_* constant.
00832 */
00833 
00834 VBR_STAT
00835 vbr_setcallbackctx(VBR *vbr, void *ctx)
00836 {
00837        assert(vbr != NULL);
00838 
00839        vbr->vbr_user_context = ctx;
00840        return VBR_STAT_OK;
00841 }
00842 
00843 /*
00844 **  VBR_SETDNSCALLBACK -- set the DNS wait callback
00845 **
00846 **  Parameters:
00847 **     vbr -- VBR handle, created by vbr_init()
00848 **     func -- function to call; should take an opaque context pointer
00849 **
00850 **  Return value:
00851 **     A VBR_STAT_* constant.
00852 */
00853 
00854 VBR_STAT
00855 vbr_setdnscallback(VBR *vbr, void (*func)(const void *context))
00856 {
00857        assert(vbr != NULL);
00858 
00859        vbr->vbr_dns_callback = func;
00860        return VBR_STAT_OK;
00861 }
00862 
00863 /*
00864 **  VBR_SETDOMAIN -- declare the sender's domain
00865 **
00866 **  Parameters:
00867 **     vbr -- VBR handle, created by vbr_init()
00868 **     cert -- certifiers string
00869 **
00870 **  Return value:
00871 **     None (yet).
00872 */
00873 
00874 void
00875 vbr_setdomain(VBR *vbr, u_char *domain)
00876 {
00877        assert(vbr != NULL);
00878        assert(domain != NULL);
00879 
00880        vbr->vbr_domain = domain;
00881 }
00882 
00883 /*
00884 **  VBR_SETCERT -- store the VBR certifiers of this message
00885 **
00886 **  Parameters:
00887 **     vbr -- VBR handle, created by vbr_init()
00888 **     cert -- certifiers string
00889 **
00890 **  Return value:
00891 **     None (yet).
00892 */
00893 
00894 void
00895 vbr_setcert(VBR *vbr, u_char *cert)
00896 {
00897        assert(vbr != NULL);
00898        assert(cert != NULL);
00899 
00900        vbr->vbr_cert = cert;
00901 }
00902 
00903 /*
00904 **  VBR_SETTYPE -- store the VBR type of this message
00905 **
00906 **  Parameters:
00907 **     vbr -- VBR handle, created by vbr_init()
00908 **     type -- type string
00909 **
00910 **  Return value:
00911 **     None (yet).
00912 */
00913 
00914 void
00915 vbr_settype(VBR *vbr, u_char *type)
00916 {
00917        assert(vbr != NULL);
00918        assert(type != NULL);
00919 
00920        vbr->vbr_type = type;
00921 }
00922 
00923 /*
00924 **  VBR_TRUSTEDCERTS -- store the trusted VBR certifiers
00925 **
00926 **  Parameters:
00927 **     vbr -- VBR handle, created by vbr_init()
00928 **     certs -- NULL-terminated list of trusted certifiers
00929 **
00930 **  Return value:
00931 **     None (yet).
00932 */
00933 
00934 void
00935 vbr_trustedcerts(VBR *vbr, u_char **certs)
00936 {
00937        assert(vbr != NULL);
00938        assert(certs != NULL);
00939 
00940        vbr->vbr_trusted = certs;
00941 }
00942 
00943 /*
00944 **  VBR_QUERY -- query the vouching servers for results
00945 **
00946 **  Parameters:
00947 **     vbr -- VBR handle
00948 **     res -- result string (one of "fail", "pass"); returned
00949 **     cert -- name of the certifier that returned a "pass"; returned
00950 **
00951 **  Return value:
00952 **     VBR_STAT_OK -- able to determine a result
00953 **     VBR_STAT_INVALID -- vbr_trustedcerts(), vbr_settype() and
00954 **                         vbr_setcert() were not all called
00955 **     VBR_STAT_DNSERROR -- DNS issue prevented resolution
00956 **
00957 **  Notes:
00958 **     - "pass" is the result if ANY certifier vouched for the message.
00959 **     - "res" is not modified if no result could be determined
00960 **     - there's no attempt to validate the values found
00961 **     - vbr_cert is destroyed by this function
00962 */
00963 
00964 VBR_STAT
00965 vbr_query(VBR *vbr, u_char **res, u_char **cert)
00966 {
00967        int c;
00968        int n;
00969        int status;
00970        int dnserr;
00971        struct vbr_query *vq;
00972        void *qh;
00973        u_char *p;
00974        u_char *last;
00975        u_char *last2;
00976        u_char *p2;
00977        struct timeval timeout;
00978        u_char certs[VBR_MAXHEADER + 1];
00979        u_char query[VBR_MAXHOSTNAMELEN + 1];
00980        unsigned char buf[BUFRSZ];
00981 
00982        assert(vbr != NULL);
00983        assert(res != NULL);
00984        assert(cert != NULL);
00985 
00986        if (vbr->vbr_type == NULL ||
00987            vbr->vbr_cert == NULL ||
00988            vbr->vbr_trusted == NULL)
00989        {
00990               vbr_error(vbr, "required data for VBR check missing");
00991               return VBR_STAT_INVALID;
00992        }
00993 
00994        strlcpy((char *) certs, vbr->vbr_cert, sizeof certs);
00995 
00996        if (vbr->vbr_malloc != NULL)
00997               vq = vbr->vbr_malloc(vbr->vbr_closure, sizeof(*vq));
00998        else
00999               vq = malloc(sizeof(*vq));
01000 
01001        if (vq == NULL)
01002               return VBR_STAT_NORESOURCE;
01003 
01004        memset(vq, '\0', sizeof *vq);
01005 
01006        for (c = 0; ; c++)
01007        {
01008               if ((vbr->vbr_opts & VBR_OPT_TRUSTEDONLY) != 0)
01009               {
01010                      /*
01011                      **  Query our trusted vouchers regardless of what the
01012                      **  sender said.
01013                      */
01014 
01015                      if (vbr->vbr_trusted[c] == NULL)
01016                             break;
01017                      else
01018                             p = vbr->vbr_trusted[c];
01019               }
01020               else
01021               {
01022                      /*
01023                      **  Query the sender's vouchers that also appear in our
01024                      **  trusted voucher list.
01025                      */
01026 
01027                      _Bool found;
01028 
01029                      p = (u_char *) strtok_r(c == 0 ? (char *) certs : NULL,
01030                                              ":", (char **) &last);
01031                      if (p == NULL)
01032                             break;
01033 
01034                      found = FALSE;
01035 
01036                      for (n = 0; vbr->vbr_trusted[n] != NULL; n++)
01037                      {
01038                             if (strcasecmp((char *) p,
01039                                            (char *) vbr->vbr_trusted[n]) == 0)
01040                             {
01041                                    found = TRUE;
01042                                    break;
01043                             }
01044                      }
01045 
01046                      if (!found)
01047                             continue;
01048               }      
01049 
01050               snprintf((char *) query, sizeof query, "%s.%s.%s",
01051                        vbr->vbr_domain, VBR_PREFIX, p);
01052 
01053               qh = NULL;
01054 
01055               status = vbr->vbr_dns_start(vbr->vbr_dns_service, T_TXT, query,
01056                                           vq->vq_buf, sizeof vq->vq_buf,
01057                                           &vq->vq_qh);
01058 
01059               if (status != VBR_STAT_OK)
01060               {
01061                      snprintf(vbr->vbr_error, sizeof vbr->vbr_error,
01062                               "unable to start query for '%s'",
01063                               query);
01064                      return VBR_STAT_DNSERROR;
01065               }
01066 
01067               timeout.tv_sec = vbr->vbr_timeout;
01068               timeout.tv_usec = 0;
01069 
01070               if (vbr->vbr_dns_callback == NULL)
01071               {
01072                      status = vbr->vbr_dns_waitreply(vbr->vbr_dns_service,
01073                                                      vq->vq_qh,
01074                                                      &timeout,
01075                                                      &vq->vq_buflen,
01076                                                      &dnserr,
01077                                                      NULL);
01078               }
01079               else
01080               {
01081                      struct timeval *to;
01082                      struct timeval wstart;
01083                      struct timeval wstop;
01084                      struct timeval ctimeout;
01085 
01086                      wstop.tv_sec = 0;
01087                      wstop.tv_usec = 0;
01088 
01089                      for (;;)
01090                      {
01091                             (void) gettimeofday(&wstart, NULL);
01092 
01093                             ctimeout.tv_sec = vbr->vbr_callback_int;
01094                             ctimeout.tv_usec = 0;
01095 
01096                             timeout.tv_sec = vbr->vbr_timeout;
01097                             timeout.tv_usec = 0;
01098 
01099                             vbr_timeouts(&timeout, &ctimeout,
01100                                          &wstart, &wstop,
01101                                          &to);
01102 
01103                             status = vbr->vbr_dns_waitreply(vbr->vbr_dns_service,
01104                                                             vq->vq_qh,
01105                                                             to,
01106                                                             &vq->vq_buflen,
01107                                                             &dnserr,
01108                                                             NULL);
01109 
01110                             (void) gettimeofday(&wstop, NULL);
01111 
01112                             if (status != VBR_DNS_NOREPLY ||
01113                                 to == &timeout)
01114                                    break;
01115 
01116                             vbr->vbr_dns_callback(vbr->vbr_user_context);
01117                      }
01118               }
01119 
01120               vbr->vbr_dns_cancel(vbr->vbr_dns_service, vq->vq_qh);
01121 
01122               if (status == VBR_DNS_ERROR || status == VBR_DNS_EXPIRED)
01123               {
01124                      vbr_error(vbr, "failed to retrieve %s", query);
01125                      return VBR_STAT_DNSERROR;
01126               }
01127 
01128               /* try to decode the reply */
01129               if (!vbr_txt_decode(vq->vq_buf, vq->vq_buflen,
01130                                   buf, sizeof buf))
01131                      continue;
01132 
01133               /* see if there's a vouch match */
01134               for (p2 = (u_char *) strtok_r((char *) buf, " \t",
01135                                             (char **) &last2);
01136                    p2 != NULL;
01137                    p2 = (u_char *) strtok_r(NULL, " \t",
01138                                             (char **) &last2))
01139               {
01140                      if (strcasecmp((char *) p2, VBR_ALL) == 0 ||
01141                          strcasecmp((char *) p2,
01142                                     (char *) vbr->vbr_type) == 0)
01143                      {
01144                             /* we have a winner! */
01145                             *res = (u_char *) "pass";
01146                             *cert = p;
01147                             return VBR_STAT_OK;
01148                      }
01149               }
01150        }
01151 
01152        /* nobody vouched */
01153        *res = (u_char *) "fail";
01154        return VBR_STAT_OK;
01155 }
01156 
01157 /*
01158 **  VBR_GETHEADER -- generate and store the VBR-Info header
01159 **
01160 **  Parameters:
01161 **     vbr -- VBR handle
01162 **     hdr -- header buffer
01163 **     len -- number of bytes available at "hdr"
01164 **
01165 **  Return value:
01166 **     VBR_STAT_OK -- success
01167 **     VBR_STAT_NORESOURCE -- "hdr" was too short
01168 **     VBR_STAT_INVALID -- not all VBR information was provided
01169 */
01170 
01171 VBR_STAT
01172 vbr_getheader(VBR *vbr, unsigned char *hdr, size_t len)
01173 {
01174        size_t olen;
01175 
01176        assert(vbr != NULL);
01177        assert(hdr != NULL);
01178 
01179        if (vbr->vbr_cert == NULL || vbr->vbr_type == NULL)
01180        {
01181               vbr_error(vbr, "VBR certifiers or type missing");
01182               return VBR_STAT_INVALID;
01183        }
01184 
01185        olen = snprintf((char *) hdr, len, "md=%s; mc=%s; mv=%s",
01186                        vbr->vbr_domain, vbr->vbr_type, vbr->vbr_cert);
01187        if (olen >= len)
01188        {
01189               vbr_error(vbr, "VBR buffer too small");
01190               return VBR_STAT_NORESOURCE;
01191        }
01192 
01193        return VBR_STAT_OK;
01194 }
01195 
01196 /*
01197 **  VBR_DNS_SET_QUERY_SERVICE -- stores a handle representing the DNS
01198 **                               query service to be used, returning any
01199 **                               previous handle
01200 **
01201 **  Parameters:
01202 **     vbr -- VBR library handle
01203 **     h -- handle to be used
01204 **
01205 **  Return value:
01206 **     Previously stored handle, or NULL if none.
01207 */
01208 
01209 void *
01210 vbr_dns_set_query_service(VBR *vbr, void *h)
01211 {
01212        void *old;
01213 
01214        assert(vbr != NULL);
01215 
01216        old = vbr->vbr_dns_service;
01217 
01218        vbr->vbr_dns_service = h;
01219 
01220        return old;
01221 }
01222 
01223 /*
01224 **  VBR_DNS_SET_QUERY_START -- stores a pointer to a query start function
01225 **
01226 **  Parameters:
01227 **     vbr -- VBR library handle
01228 **     func -- function to use to start queries
01229 **
01230 **  Return value:
01231 **     None.
01232 **
01233 **  Notes:
01234 **     "func" should match the following prototype:
01235 **            returns int (status)
01236 **            void *dns -- receives handle stored by
01237 **                         vbr_dns_set_query_service()
01238 **            int type -- DNS RR query type (C_IN assumed)
01239 **            char *query -- question to ask
01240 **            char *buf -- buffer into which to write reply
01241 **            size_t buflen -- size of buf
01242 **            void **qh -- returned query handle
01243 */
01244 
01245 void
01246 vbr_dns_set_query_start(VBR *vbr, int (*func)(void *, int,
01247                                               unsigned char *,
01248                                               unsigned char *,
01249                                               size_t, void **))
01250 {
01251        assert(vbr != NULL);
01252 
01253        vbr->vbr_dns_start = func;
01254 }
01255 
01256 /*
01257 **  VBR_DNS_SET_QUERY_CANCEL -- stores a pointer to a query cancel function
01258 **
01259 **  Parameters:
01260 **     vbr -- VBR library handle
01261 **     func -- function to use to cancel running queries
01262 **
01263 **  Return value:
01264 **     None.
01265 **
01266 **  Notes:
01267 **     "func" should match the following prototype:
01268 **            returns int (status)
01269 **            void *dns -- DNS service handle
01270 **            void *qh -- query handle to be canceled
01271 */
01272 
01273 void
01274 vbr_dns_set_query_cancel(VBR *vbr, int (*func)(void *, void *))
01275 {
01276        assert(vbr != NULL);
01277 
01278        vbr->vbr_dns_cancel = func;
01279 }
01280 
01281 /*
01282 **  VBR_DNS_SET_QUERY_WAITREPLY -- stores a pointer to wait for a DNS reply
01283 **
01284 **  Parameters:
01285 **     vbr -- VBR library handle
01286 **     func -- function to use to wait for a reply
01287 **
01288 **  Return value:
01289 **     None.
01290 **
01291 **  Notes:
01292 **     "func" should match the following prototype:
01293 **            returns int (status)
01294 **            void *dns -- DNS service handle
01295 **            void *qh -- handle of query that has completed
01296 **            struct timeval *timeout -- how long to wait
01297 **            size_t *bytes -- bytes returned
01298 **            int *error -- error code returned
01299 **            int *dnssec -- DNSSEC status returned
01300 */
01301 
01302 void
01303 vbr_dns_set_query_waitreply(VBR *vbr, int (*func)(void *, void *,
01304                                                   struct timeval *,
01305                                                   size_t *, int *,
01306                                                   int *))
01307 {
01308        assert(vbr != NULL);
01309 
01310        vbr->vbr_dns_waitreply = func;
01311 }