Back to index

opendkim  2.6.4
dkim-util.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, The OpenDKIM Project.  All rights reserved.
00006 */
00007 
00008 #ifndef lint
00009 static char dkim_util_c_id[] = "@(#)$Id: dkim-util.c,v 1.7.58.1 2010/10/27 21:43:08 cm-msk Exp $";
00010 #endif /* !lint */
00011 
00012 #include "build-config.h"
00013 
00014 /* system includes */
00015 #include <sys/param.h>
00016 #include <sys/types.h>
00017 #ifdef HAVE_STDBOOL_H
00018 # include <stdbool.h>
00019 #endif /* HAVE_STDBOOL_H */
00020 #include <stdlib.h>
00021 #include <stdarg.h>
00022 #include <assert.h>
00023 #include <unistd.h>
00024 #include <limits.h>
00025 #include <string.h>
00026 #include <errno.h>
00027 #include <stdio.h>
00028 
00029 /* libopendkim includes */
00030 #include "dkim-internal.h"
00031 #include "dkim-types.h"
00032 #include "dkim-util.h"
00033 
00034 /* prototypes */
00035 extern void dkim_error __P((DKIM *, const char *, ...));
00036 
00037 /*
00038 **  DKIM_MALLOC -- allocate memory
00039 **
00040 **  Parameters:
00041 **     libhandle -- DKIM library context in which this is performed
00042 **     closure -- opaque closure handle for the allocation
00043 **     nbytes -- number of bytes desired
00044 **
00045 **  Return value:
00046 **     Pointer to allocated memory, or NULL on failure.
00047 */
00048 
00049 void *
00050 dkim_malloc(DKIM_LIB *libhandle, void *closure, size_t nbytes)
00051 {
00052        assert(libhandle != NULL);
00053 
00054        if (libhandle->dkiml_malloc == NULL)
00055               return malloc(nbytes);
00056        else
00057               return libhandle->dkiml_malloc(closure, nbytes);
00058 }
00059 
00060 /*
00061 **  DKIM_MFREE -- release memory
00062 **
00063 **  Parameters:
00064 **     dkim -- DKIM context in which this is performed
00065 **     closure -- opaque closure handle for the allocation
00066 **     ptr -- pointer to memory to be freed
00067 **
00068 **  Return value:
00069 **     None.
00070 */
00071 
00072 void
00073 dkim_mfree(DKIM_LIB *libhandle, void *closure, void *ptr)
00074 {
00075        assert(libhandle != NULL);
00076 
00077        if (libhandle->dkiml_free == NULL)
00078               free(ptr);
00079        else
00080               libhandle->dkiml_free(closure, ptr);
00081 }
00082 
00083 /*
00084 **  DKIM_STRDUP -- duplicate a string
00085 **
00086 **  Parameters:
00087 **     dkim -- DKIM handle
00088 **     str -- string to clone
00089 **     len -- bytes to copy (0 == copy to NULL byte)
00090 **
00091 **  Return value:
00092 **     Pointer to a new copy of "str" allocated from within the appropriate
00093 **     context, or NULL on failure.
00094 */
00095 
00096 unsigned char *
00097 dkim_strdup(DKIM *dkim, const unsigned char *str, size_t len)
00098 {
00099        unsigned char *new;
00100 
00101        assert(dkim != NULL);
00102        assert(str != NULL);
00103 
00104        if (len == 0)
00105               len = strlen((char *) str);
00106 
00107        new = dkim_malloc(dkim->dkim_libhandle, dkim->dkim_closure, len + 1);
00108        if (new != NULL)
00109        {
00110               memcpy(new, str, len);
00111               new[len] = '\0';
00112        }
00113        else
00114        {
00115               dkim_error(dkim, "unable to allocate %d byte(s)", len + 1);
00116        }
00117        return new;
00118 }
00119 
00120 /*
00121 **  DKIM_TMPFILE -- open a temporary file
00122 **
00123 **  Parameters:
00124 **     dkim -- DKIM handle
00125 **     fp -- descriptor (returned)
00126 **     keep -- if FALSE, unlink() the file once created
00127 **
00128 **  Return value:
00129 **     A DKIM_STAT_* constant.
00130 */
00131 
00132 DKIM_STAT
00133 dkim_tmpfile(DKIM *dkim, int *fp, _Bool keep)
00134 {
00135        int fd;
00136        char path[MAXPATHLEN + 1];
00137 
00138        assert(dkim != NULL);
00139        assert(fp != NULL);
00140 
00141        if (dkim->dkim_id != NULL)
00142        {
00143               snprintf(path, MAXPATHLEN, "%s/dkim.%s.XXXXXX",
00144                        dkim->dkim_libhandle->dkiml_tmpdir, dkim->dkim_id);
00145        }
00146        else
00147        {
00148               snprintf(path, MAXPATHLEN, "%s/dkim.XXXXXX",
00149                        dkim->dkim_libhandle->dkiml_tmpdir);
00150        }
00151 
00152        fd = mkstemp(path);
00153        if (fd == -1)
00154        {
00155               dkim_error(dkim, "can't create temporary file at %s: %s",
00156                          path, strerror(errno));
00157               return DKIM_STAT_NORESOURCE;
00158        }
00159 
00160        *fp = fd;
00161 
00162        if (!keep)
00163               (void) unlink(path);
00164 
00165        return DKIM_STAT_OK;
00166 }
00167 
00168 /*
00169 **  DKIM_DSTRING_RESIZE -- resize a dynamic string (dstring)
00170 **
00171 **  Parameters:
00172 **     dstr -- DKIM_DSTRING handle
00173 **     len -- number of bytes desired
00174 **
00175 **  Return value:
00176 **     TRUE iff the resize worked (or wasn't needed)
00177 **
00178 **  Notes:
00179 **     This will actually ensure that there are "len" bytes available.
00180 **     The caller must account for the NULL byte when requesting a
00181 **     specific size.
00182 */
00183 
00184 static _Bool
00185 dkim_dstring_resize(struct dkim_dstring *dstr, int len)
00186 {
00187        int newsz;
00188        unsigned char *new;
00189        DKIM *dkim;
00190        DKIM_LIB *lib;
00191 
00192        assert(dstr != NULL);
00193        assert(len > 0);
00194 
00195        if (dstr->ds_alloc >= len)
00196               return TRUE;
00197 
00198        dkim = dstr->ds_dkim;
00199        lib = dkim->dkim_libhandle;
00200 
00201        /* must resize */
00202        for (newsz = dstr->ds_alloc * 2;
00203             newsz < len;
00204             newsz *= 2)
00205        {
00206               /* impose ds_max limit, if specified */
00207               if (dstr->ds_max > 0 && newsz > dstr->ds_max)
00208               {
00209                      if (len <= dstr->ds_max)
00210                      {
00211                             newsz = len;
00212                             break;
00213                      }
00214 
00215                      dkim_error(dkim, "maximum string size exceeded");
00216                      return FALSE;
00217               }
00218 
00219               /* check for overflow */
00220               if (newsz > INT_MAX / 2)
00221               {
00222                      /* next iteration will overflow "newsz" */
00223                      dkim_error(dkim, "internal string limit reached");
00224                      return FALSE;
00225               }
00226        }
00227 
00228        new = dkim_malloc(lib, dkim->dkim_closure, newsz);
00229        if (new == NULL)
00230        {
00231               dkim_error(dkim, "unable to allocate %d byte(s)", newsz);
00232               return FALSE;
00233        }
00234 
00235        memcpy(new, dstr->ds_buf, dstr->ds_alloc);
00236 
00237        dkim_mfree(lib, dkim->dkim_closure, dstr->ds_buf);
00238 
00239        dstr->ds_alloc = newsz;
00240        dstr->ds_buf = new;
00241 
00242        return TRUE;
00243 }
00244 
00245 /*
00246 **  DKIM_DSTRING_NEW -- make a new dstring
00247 **
00248 **  Parameters:
00249 **     dkim -- DKIM handle
00250 **     len -- initial number of bytes
00251 **     maxlen -- maximum allowed length, including the NULL byte
00252 **               (0 == unbounded)
00253 **
00254 **  Return value:
00255 **     A DKIM_DSTRING handle, or NULL on failure.
00256 */
00257 
00258 struct dkim_dstring *
00259 dkim_dstring_new(DKIM *dkim, int len, int maxlen)
00260 {
00261        struct dkim_dstring *new;
00262        DKIM_LIB *lib;
00263 
00264        assert(dkim != NULL);
00265 
00266        /* fail on invalid parameters */
00267        if ((maxlen > 0 && len > maxlen) || len < 0)
00268               return NULL;
00269 
00270        lib = dkim->dkim_libhandle;
00271 
00272        if (len < BUFRSZ)
00273               len = BUFRSZ;
00274 
00275        new = dkim_malloc(lib, dkim->dkim_closure, sizeof(struct dkim_dstring));
00276        if (new == NULL)
00277        {
00278               dkim_error(dkim, "unable to allocate %d byte(s)",
00279                          sizeof(struct dkim_dstring));
00280               return NULL;
00281        }
00282 
00283        new->ds_buf = dkim_malloc(lib, dkim->dkim_closure, len);
00284        if (new->ds_buf == NULL)
00285        {
00286               dkim_error(dkim, "unable to allocate %d byte(s)",
00287                          sizeof(struct dkim_dstring));
00288               dkim_mfree(lib, dkim->dkim_closure, new);
00289               return NULL;
00290        }
00291 
00292        memset(new->ds_buf, '\0', len);
00293        new->ds_alloc = len;
00294        new->ds_len = 0;
00295        new->ds_max = maxlen;
00296        new->ds_dkim = dkim;
00297 
00298        return new;
00299 }
00300 
00301 /*
00302 **  DKIM_DSTRING_FREE -- destroy an existing dstring
00303 **
00304 **  Parameters:
00305 **     dstr -- DKIM_DSTRING handle to be destroyed
00306 **
00307 **  Return value:
00308 **     None.
00309 */
00310 
00311 void
00312 dkim_dstring_free(struct dkim_dstring *dstr)
00313 {
00314        DKIM_LIB *lib;
00315        DKIM *dkim;
00316 
00317        assert(dstr != NULL);
00318 
00319        dkim = dstr->ds_dkim;
00320        lib = dkim->dkim_libhandle;
00321 
00322        dkim_mfree(lib, dkim->dkim_closure, dstr->ds_buf);
00323        dkim_mfree(lib, dkim->dkim_closure, dstr);
00324 }
00325 
00326 /*
00327 **  DKIM_DSTRING_COPY -- copy data into a dstring
00328 **
00329 **  Parameters:
00330 **     dstr -- DKIM_DSTRING handle to update
00331 **     str -- input string
00332 **
00333 **  Return value:
00334 **     TRUE iff the copy succeeded.
00335 **
00336 **  Side effects:
00337 **     The dstring may be resized.
00338 */
00339 
00340 _Bool
00341 dkim_dstring_copy(struct dkim_dstring *dstr, unsigned char *str)
00342 {
00343        int len;
00344 
00345        assert(dstr != NULL);
00346        assert(str != NULL);
00347 
00348        len = strlen((char *) str);
00349 
00350        /* too big? */
00351        if (dstr->ds_max > 0 && len >= dstr->ds_max)
00352               return FALSE;
00353 
00354        /* fits now? */
00355        if (dstr->ds_alloc <= len)
00356        {
00357               /* nope; try to resize */
00358               if (!dkim_dstring_resize(dstr, len + 1))
00359                      return FALSE;
00360        }
00361 
00362        /* copy */
00363        memcpy(dstr->ds_buf, str, len + 1);
00364        dstr->ds_len = len;
00365 
00366        return TRUE;
00367 }
00368 
00369 /*
00370 **  DKIM_DSTRING_CAT -- append data onto a dstring
00371 **
00372 **  Parameters:
00373 **     dstr -- DKIM_DSTRING handle to update
00374 **     str -- input string
00375 **
00376 **  Return value:
00377 **     TRUE iff the update succeeded.
00378 **
00379 **  Side effects:
00380 **     The dstring may be resized.
00381 */
00382 
00383 _Bool
00384 dkim_dstring_cat(struct dkim_dstring *dstr, unsigned char *str)
00385 {
00386        size_t len;
00387        size_t needed;
00388 
00389        assert(dstr != NULL);
00390        assert(str != NULL);
00391 
00392        len = strlen((char *) str);
00393        needed = dstr->ds_len + len;
00394 
00395        /* too big? */
00396        if (dstr->ds_max > 0 && needed >= dstr->ds_max)
00397               return FALSE;
00398 
00399        /* fits now? */
00400        if (dstr->ds_alloc <= needed)
00401        {
00402               /* nope; try to resize */
00403               if (!dkim_dstring_resize(dstr, needed + 1))
00404                      return FALSE;
00405        }
00406 
00407        /* append */
00408        memcpy(dstr->ds_buf + dstr->ds_len, str, len + 1);
00409        dstr->ds_len += len;
00410 
00411        return TRUE;
00412 }
00413 
00414 /*
00415 **  DKIM_DSTRING_CAT1 -- append one byte onto a dstring
00416 **
00417 **  Parameters:
00418 **     dstr -- DKIM_DSTRING handle to update
00419 **     c -- input character
00420 **
00421 **  Return value:
00422 **     TRUE iff the update succeeded.
00423 **
00424 **  Side effects:
00425 **     The dstring may be resized.
00426 */
00427 
00428 _Bool
00429 dkim_dstring_cat1(struct dkim_dstring *dstr, int c)
00430 {
00431        int len;
00432 
00433        assert(dstr != NULL);
00434 
00435        len = dstr->ds_len + 1;
00436 
00437        /* too big? */
00438        if (dstr->ds_max > 0 && len >= dstr->ds_max)
00439               return FALSE;
00440 
00441        /* fits now? */
00442        if (dstr->ds_alloc <= len)
00443        {
00444               /* nope; try to resize */
00445               if (!dkim_dstring_resize(dstr, len + 1))
00446                      return FALSE;
00447        }
00448 
00449        /* append */
00450        dstr->ds_buf[dstr->ds_len++] = c;
00451        dstr->ds_buf[dstr->ds_len] = '\0';
00452 
00453        return TRUE;
00454 }
00455 
00456 /*
00457 **  DKIM_DSTRING_CATN -- append 'n' bytes onto a dstring
00458 **
00459 **  Parameters:
00460 **     dstr -- DKIM_DSTRING handle to update
00461 **     str -- input string
00462 **     nbytes -- number of bytes to append
00463 **
00464 **  Return value:
00465 **     TRUE iff the update succeeded.
00466 **
00467 **  Side effects:
00468 **     The dstring may be resized.
00469 */
00470 
00471 _Bool
00472 dkim_dstring_catn(struct dkim_dstring *dstr, unsigned char *str, size_t nbytes)
00473 {
00474        size_t needed;
00475 
00476        assert(dstr != NULL);
00477        assert(str != NULL);
00478 
00479        needed = dstr->ds_len + nbytes;
00480 
00481        /* too big? */
00482        if (dstr->ds_max > 0 && needed >= dstr->ds_max)
00483               return FALSE;
00484 
00485        /* fits now? */
00486        if (dstr->ds_alloc <= needed)
00487        {
00488               /* nope; try to resize */
00489               if (!dkim_dstring_resize(dstr, needed + 1))
00490                      return FALSE;
00491        }
00492 
00493        /* append */
00494        memcpy(dstr->ds_buf + dstr->ds_len, str, nbytes);
00495        dstr->ds_len += nbytes;
00496        dstr->ds_buf[dstr->ds_len] = '\0';
00497 
00498        return TRUE;
00499 }
00500 
00501 /*
00502 **  DKIM_DSTRING_GET -- retrieve data in a dstring
00503 **
00504 **  Parameters:
00505 **     dstr -- DKIM_STRING handle whose string should be retrieved
00506 **
00507 **  Return value:
00508 **     Pointer to the NULL-terminated contents of "dstr".
00509 */
00510 
00511 unsigned char *
00512 dkim_dstring_get(struct dkim_dstring *dstr)
00513 {
00514        assert(dstr != NULL);
00515 
00516        return dstr->ds_buf;
00517 }
00518 
00519 /*
00520 **  DKIM_DSTRING_LEN -- retrieve length of data in a dstring
00521 **
00522 **  Parameters:
00523 **     dstr -- DKIM_STRING handle whose string should be retrieved
00524 **
00525 **  Return value:
00526 **     Number of bytes in a dstring.
00527 */
00528 
00529 int
00530 dkim_dstring_len(struct dkim_dstring *dstr)
00531 {
00532        assert(dstr != NULL);
00533 
00534        return dstr->ds_len;
00535 }
00536 
00537 /*
00538 **  DKIM_DSTRING_BLANK -- clear out the contents of a dstring
00539 **
00540 **  Parameters:
00541 **     dstr -- DKIM_STRING handle whose string should be cleared
00542 **
00543 **  Return value:
00544 **     None.
00545 */
00546 
00547 void
00548 dkim_dstring_blank(struct dkim_dstring *dstr)
00549 {
00550        assert(dstr != NULL);
00551 
00552        dstr->ds_len = 0;
00553        dstr->ds_buf[0] = '\0';
00554 }
00555 
00556 /*
00557 **  DKIM_DSTRING_PRINTF -- write variable length formatted output to a dstring
00558 **
00559 **  Parameters:
00560 **     dstr -- DKIM_STRING handle to be updated
00561 **     fmt -- format
00562 **     ... -- variable arguments
00563 **
00564 **  Return value:
00565 **     New size, or -1 on error.
00566 */
00567 
00568 size_t
00569 dkim_dstring_printf(struct dkim_dstring *dstr, char *fmt, ...)
00570 {
00571        size_t len;
00572        va_list ap;
00573        va_list ap2;
00574 
00575        assert(dstr != NULL);
00576        assert(fmt != NULL);
00577 
00578        va_start(ap, fmt);
00579        va_copy(ap2, ap);
00580        len = vsnprintf((char *) dstr->ds_buf + dstr->ds_len, dstr->ds_alloc,
00581                        fmt, ap);
00582        va_end(ap);
00583 
00584        if (len > dstr->ds_len)
00585        {
00586               if (!dkim_dstring_resize(dstr, len + 1))
00587               {
00588                      va_end(ap2);
00589                      return (size_t) -1;
00590               }
00591 
00592               len = vsnprintf((char *) dstr->ds_buf + dstr->ds_len,
00593                               dstr->ds_alloc, fmt, ap2);
00594        }
00595 
00596        va_end(ap2);
00597 
00598        dstr->ds_len += len;
00599 
00600        return dstr->ds_len;
00601 }