Back to index

opendkim  2.6.6
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, 2012, 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 *p;
00137        char path[MAXPATHLEN + 1];
00138 
00139        assert(dkim != NULL);
00140        assert(fp != NULL);
00141 
00142        if (dkim->dkim_id != NULL)
00143        {
00144               snprintf(path, MAXPATHLEN, "%s/dkim.%s.XXXXXX",
00145                        dkim->dkim_libhandle->dkiml_tmpdir, dkim->dkim_id);
00146        }
00147        else
00148        {
00149               snprintf(path, MAXPATHLEN, "%s/dkim.XXXXXX",
00150                        dkim->dkim_libhandle->dkiml_tmpdir);
00151        }
00152 
00153        for (p = path + strlen(dkim->dkim_libhandle->dkiml_tmpdir) + 1;
00154             *p != '\0';
00155             p++)
00156        {
00157               if (*p == '/')
00158                      *p = '.';
00159        }
00160 
00161        fd = mkstemp(path);
00162        if (fd == -1)
00163        {
00164               dkim_error(dkim, "can't create temporary file at %s: %s",
00165                          path, strerror(errno));
00166               return DKIM_STAT_NORESOURCE;
00167        }
00168 
00169        *fp = fd;
00170 
00171        if (!keep)
00172               (void) unlink(path);
00173 
00174        return DKIM_STAT_OK;
00175 }
00176 
00177 /*
00178 **  DKIM_DSTRING_RESIZE -- resize a dynamic string (dstring)
00179 **
00180 **  Parameters:
00181 **     dstr -- DKIM_DSTRING handle
00182 **     len -- number of bytes desired
00183 **
00184 **  Return value:
00185 **     TRUE iff the resize worked (or wasn't needed)
00186 **
00187 **  Notes:
00188 **     This will actually ensure that there are "len" bytes available.
00189 **     The caller must account for the NULL byte when requesting a
00190 **     specific size.
00191 */
00192 
00193 static _Bool
00194 dkim_dstring_resize(struct dkim_dstring *dstr, int len)
00195 {
00196        int newsz;
00197        unsigned char *new;
00198        DKIM *dkim;
00199        DKIM_LIB *lib;
00200 
00201        assert(dstr != NULL);
00202        assert(len > 0);
00203 
00204        if (dstr->ds_alloc >= len)
00205               return TRUE;
00206 
00207        dkim = dstr->ds_dkim;
00208        lib = dkim->dkim_libhandle;
00209 
00210        /* must resize */
00211        for (newsz = dstr->ds_alloc * 2;
00212             newsz < len;
00213             newsz *= 2)
00214        {
00215               /* impose ds_max limit, if specified */
00216               if (dstr->ds_max > 0 && newsz > dstr->ds_max)
00217               {
00218                      if (len <= dstr->ds_max)
00219                      {
00220                             newsz = len;
00221                             break;
00222                      }
00223 
00224                      dkim_error(dkim, "maximum string size exceeded");
00225                      return FALSE;
00226               }
00227 
00228               /* check for overflow */
00229               if (newsz > INT_MAX / 2)
00230               {
00231                      /* next iteration will overflow "newsz" */
00232                      dkim_error(dkim, "internal string limit reached");
00233                      return FALSE;
00234               }
00235        }
00236 
00237        new = dkim_malloc(lib, dkim->dkim_closure, newsz);
00238        if (new == NULL)
00239        {
00240               dkim_error(dkim, "unable to allocate %d byte(s)", newsz);
00241               return FALSE;
00242        }
00243 
00244        memcpy(new, dstr->ds_buf, dstr->ds_alloc);
00245 
00246        dkim_mfree(lib, dkim->dkim_closure, dstr->ds_buf);
00247 
00248        dstr->ds_alloc = newsz;
00249        dstr->ds_buf = new;
00250 
00251        return TRUE;
00252 }
00253 
00254 /*
00255 **  DKIM_DSTRING_NEW -- make a new dstring
00256 **
00257 **  Parameters:
00258 **     dkim -- DKIM handle
00259 **     len -- initial number of bytes
00260 **     maxlen -- maximum allowed length, including the NULL byte
00261 **               (0 == unbounded)
00262 **
00263 **  Return value:
00264 **     A DKIM_DSTRING handle, or NULL on failure.
00265 */
00266 
00267 struct dkim_dstring *
00268 dkim_dstring_new(DKIM *dkim, int len, int maxlen)
00269 {
00270        struct dkim_dstring *new;
00271        DKIM_LIB *lib;
00272 
00273        assert(dkim != NULL);
00274 
00275        /* fail on invalid parameters */
00276        if ((maxlen > 0 && len > maxlen) || len < 0)
00277               return NULL;
00278 
00279        lib = dkim->dkim_libhandle;
00280 
00281        if (len < BUFRSZ)
00282               len = BUFRSZ;
00283 
00284        new = dkim_malloc(lib, dkim->dkim_closure, sizeof(struct dkim_dstring));
00285        if (new == NULL)
00286        {
00287               dkim_error(dkim, "unable to allocate %d byte(s)",
00288                          sizeof(struct dkim_dstring));
00289               return NULL;
00290        }
00291 
00292        new->ds_buf = dkim_malloc(lib, dkim->dkim_closure, len);
00293        if (new->ds_buf == NULL)
00294        {
00295               dkim_error(dkim, "unable to allocate %d byte(s)",
00296                          sizeof(struct dkim_dstring));
00297               dkim_mfree(lib, dkim->dkim_closure, new);
00298               return NULL;
00299        }
00300 
00301        memset(new->ds_buf, '\0', len);
00302        new->ds_alloc = len;
00303        new->ds_len = 0;
00304        new->ds_max = maxlen;
00305        new->ds_dkim = dkim;
00306 
00307        return new;
00308 }
00309 
00310 /*
00311 **  DKIM_DSTRING_FREE -- destroy an existing dstring
00312 **
00313 **  Parameters:
00314 **     dstr -- DKIM_DSTRING handle to be destroyed
00315 **
00316 **  Return value:
00317 **     None.
00318 */
00319 
00320 void
00321 dkim_dstring_free(struct dkim_dstring *dstr)
00322 {
00323        DKIM_LIB *lib;
00324        DKIM *dkim;
00325 
00326        assert(dstr != NULL);
00327 
00328        dkim = dstr->ds_dkim;
00329        lib = dkim->dkim_libhandle;
00330 
00331        dkim_mfree(lib, dkim->dkim_closure, dstr->ds_buf);
00332        dkim_mfree(lib, dkim->dkim_closure, dstr);
00333 }
00334 
00335 /*
00336 **  DKIM_DSTRING_COPY -- copy data into a dstring
00337 **
00338 **  Parameters:
00339 **     dstr -- DKIM_DSTRING handle to update
00340 **     str -- input string
00341 **
00342 **  Return value:
00343 **     TRUE iff the copy succeeded.
00344 **
00345 **  Side effects:
00346 **     The dstring may be resized.
00347 */
00348 
00349 _Bool
00350 dkim_dstring_copy(struct dkim_dstring *dstr, unsigned char *str)
00351 {
00352        int len;
00353 
00354        assert(dstr != NULL);
00355        assert(str != NULL);
00356 
00357        len = strlen((char *) str);
00358 
00359        /* too big? */
00360        if (dstr->ds_max > 0 && len >= dstr->ds_max)
00361               return FALSE;
00362 
00363        /* fits now? */
00364        if (dstr->ds_alloc <= len)
00365        {
00366               /* nope; try to resize */
00367               if (!dkim_dstring_resize(dstr, len + 1))
00368                      return FALSE;
00369        }
00370 
00371        /* copy */
00372        memcpy(dstr->ds_buf, str, len + 1);
00373        dstr->ds_len = len;
00374 
00375        return TRUE;
00376 }
00377 
00378 /*
00379 **  DKIM_DSTRING_CAT -- append data onto a dstring
00380 **
00381 **  Parameters:
00382 **     dstr -- DKIM_DSTRING handle to update
00383 **     str -- input string
00384 **
00385 **  Return value:
00386 **     TRUE iff the update succeeded.
00387 **
00388 **  Side effects:
00389 **     The dstring may be resized.
00390 */
00391 
00392 _Bool
00393 dkim_dstring_cat(struct dkim_dstring *dstr, unsigned char *str)
00394 {
00395        size_t len;
00396        size_t needed;
00397 
00398        assert(dstr != NULL);
00399        assert(str != NULL);
00400 
00401        len = strlen((char *) str);
00402        needed = dstr->ds_len + len;
00403 
00404        /* too big? */
00405        if (dstr->ds_max > 0 && needed >= dstr->ds_max)
00406               return FALSE;
00407 
00408        /* fits now? */
00409        if (dstr->ds_alloc <= needed)
00410        {
00411               /* nope; try to resize */
00412               if (!dkim_dstring_resize(dstr, needed + 1))
00413                      return FALSE;
00414        }
00415 
00416        /* append */
00417        memcpy(dstr->ds_buf + dstr->ds_len, str, len + 1);
00418        dstr->ds_len += len;
00419 
00420        return TRUE;
00421 }
00422 
00423 /*
00424 **  DKIM_DSTRING_CAT1 -- append one byte onto a dstring
00425 **
00426 **  Parameters:
00427 **     dstr -- DKIM_DSTRING handle to update
00428 **     c -- input character
00429 **
00430 **  Return value:
00431 **     TRUE iff the update succeeded.
00432 **
00433 **  Side effects:
00434 **     The dstring may be resized.
00435 */
00436 
00437 _Bool
00438 dkim_dstring_cat1(struct dkim_dstring *dstr, int c)
00439 {
00440        int len;
00441 
00442        assert(dstr != NULL);
00443 
00444        len = dstr->ds_len + 1;
00445 
00446        /* too big? */
00447        if (dstr->ds_max > 0 && len >= dstr->ds_max)
00448               return FALSE;
00449 
00450        /* fits now? */
00451        if (dstr->ds_alloc <= len)
00452        {
00453               /* nope; try to resize */
00454               if (!dkim_dstring_resize(dstr, len + 1))
00455                      return FALSE;
00456        }
00457 
00458        /* append */
00459        dstr->ds_buf[dstr->ds_len++] = c;
00460        dstr->ds_buf[dstr->ds_len] = '\0';
00461 
00462        return TRUE;
00463 }
00464 
00465 /*
00466 **  DKIM_DSTRING_CATN -- append 'n' bytes onto a dstring
00467 **
00468 **  Parameters:
00469 **     dstr -- DKIM_DSTRING handle to update
00470 **     str -- input string
00471 **     nbytes -- number of bytes to append
00472 **
00473 **  Return value:
00474 **     TRUE iff the update succeeded.
00475 **
00476 **  Side effects:
00477 **     The dstring may be resized.
00478 */
00479 
00480 _Bool
00481 dkim_dstring_catn(struct dkim_dstring *dstr, unsigned char *str, size_t nbytes)
00482 {
00483        size_t needed;
00484 
00485        assert(dstr != NULL);
00486        assert(str != NULL);
00487 
00488        needed = dstr->ds_len + nbytes;
00489 
00490        /* too big? */
00491        if (dstr->ds_max > 0 && needed >= dstr->ds_max)
00492               return FALSE;
00493 
00494        /* fits now? */
00495        if (dstr->ds_alloc <= needed)
00496        {
00497               /* nope; try to resize */
00498               if (!dkim_dstring_resize(dstr, needed + 1))
00499                      return FALSE;
00500        }
00501 
00502        /* append */
00503        memcpy(dstr->ds_buf + dstr->ds_len, str, nbytes);
00504        dstr->ds_len += nbytes;
00505        dstr->ds_buf[dstr->ds_len] = '\0';
00506 
00507        return TRUE;
00508 }
00509 
00510 /*
00511 **  DKIM_DSTRING_GET -- retrieve data in a dstring
00512 **
00513 **  Parameters:
00514 **     dstr -- DKIM_STRING handle whose string should be retrieved
00515 **
00516 **  Return value:
00517 **     Pointer to the NULL-terminated contents of "dstr".
00518 */
00519 
00520 unsigned char *
00521 dkim_dstring_get(struct dkim_dstring *dstr)
00522 {
00523        assert(dstr != NULL);
00524 
00525        return dstr->ds_buf;
00526 }
00527 
00528 /*
00529 **  DKIM_DSTRING_LEN -- retrieve length of data in a dstring
00530 **
00531 **  Parameters:
00532 **     dstr -- DKIM_STRING handle whose string should be retrieved
00533 **
00534 **  Return value:
00535 **     Number of bytes in a dstring.
00536 */
00537 
00538 int
00539 dkim_dstring_len(struct dkim_dstring *dstr)
00540 {
00541        assert(dstr != NULL);
00542 
00543        return dstr->ds_len;
00544 }
00545 
00546 /*
00547 **  DKIM_DSTRING_BLANK -- clear out the contents of a dstring
00548 **
00549 **  Parameters:
00550 **     dstr -- DKIM_STRING handle whose string should be cleared
00551 **
00552 **  Return value:
00553 **     None.
00554 */
00555 
00556 void
00557 dkim_dstring_blank(struct dkim_dstring *dstr)
00558 {
00559        assert(dstr != NULL);
00560 
00561        dstr->ds_len = 0;
00562        dstr->ds_buf[0] = '\0';
00563 }
00564 
00565 /*
00566 **  DKIM_DSTRING_PRINTF -- write variable length formatted output to a dstring
00567 **
00568 **  Parameters:
00569 **     dstr -- DKIM_STRING handle to be updated
00570 **     fmt -- format
00571 **     ... -- variable arguments
00572 **
00573 **  Return value:
00574 **     New size, or -1 on error.
00575 */
00576 
00577 size_t
00578 dkim_dstring_printf(struct dkim_dstring *dstr, char *fmt, ...)
00579 {
00580        size_t len;
00581        va_list ap;
00582        va_list ap2;
00583 
00584        assert(dstr != NULL);
00585        assert(fmt != NULL);
00586 
00587        va_start(ap, fmt);
00588        va_copy(ap2, ap);
00589        len = vsnprintf((char *) dstr->ds_buf + dstr->ds_len, dstr->ds_alloc,
00590                        fmt, ap);
00591        va_end(ap);
00592 
00593        if (len > dstr->ds_len)
00594        {
00595               if (!dkim_dstring_resize(dstr, len + 1))
00596               {
00597                      va_end(ap2);
00598                      return (size_t) -1;
00599               }
00600 
00601               len = vsnprintf((char *) dstr->ds_buf + dstr->ds_len,
00602                               dstr->ds_alloc, fmt, ap2);
00603        }
00604 
00605        va_end(ap2);
00606 
00607        dstr->ds_len += len;
00608 
00609        return dstr->ds_len;
00610 }