LCOV - code coverage report
Current view: top level - third_party/heimdal/lib/hx509 - file.c (source / functions) Hit Total Coverage
Test: coverage report for master 70ed9daf Lines: 69 210 32.9 %
Date: 2024-01-11 09:59:51 Functions: 3 11 27.3 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2005 - 2006 Kungliga Tekniska Högskolan
       3             :  * (Royal Institute of Technology, Stockholm, Sweden).
       4             :  * All rights reserved.
       5             :  *
       6             :  * Redistribution and use in source and binary forms, with or without
       7             :  * modification, are permitted provided that the following conditions
       8             :  * are met:
       9             :  *
      10             :  * 1. Redistributions of source code must retain the above copyright
      11             :  *    notice, this list of conditions and the following disclaimer.
      12             :  *
      13             :  * 2. Redistributions in binary form must reproduce the above copyright
      14             :  *    notice, this list of conditions and the following disclaimer in the
      15             :  *    documentation and/or other materials provided with the distribution.
      16             :  *
      17             :  * 3. Neither the name of the Institute nor the names of its contributors
      18             :  *    may be used to endorse or promote products derived from this software
      19             :  *    without specific prior written permission.
      20             :  *
      21             :  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
      22             :  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
      23             :  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
      24             :  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
      25             :  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
      26             :  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
      27             :  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
      28             :  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
      29             :  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
      30             :  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
      31             :  * SUCH DAMAGE.
      32             :  */
      33             : 
      34             : #include "hx_locl.h"
      35             : 
      36             : HX509_LIB_FUNCTION int HX509_LIB_CALL
      37           0 : _hx509_map_file_os(const char *fn, heim_octet_string *os)
      38             : {
      39           0 :     size_t length;
      40           0 :     void *data;
      41           0 :     int ret;
      42             : 
      43           0 :     ret = rk_undumpdata(fn, &data, &length);
      44             : 
      45           0 :     os->data = data;
      46           0 :     os->length = length;
      47             : 
      48           0 :     return ret;
      49             : }
      50             : 
      51             : HX509_LIB_FUNCTION void HX509_LIB_CALL
      52           0 : _hx509_unmap_file_os(heim_octet_string *os)
      53             : {
      54           0 :     rk_xfree(os->data);
      55           0 : }
      56             : 
      57             : HX509_LIB_FUNCTION int HX509_LIB_CALL
      58           0 : _hx509_write_file(const char *fn, const void *data, size_t length)
      59             : {
      60           0 :     rk_dumpdata(fn, data, length);
      61           0 :     return 0;
      62             : }
      63             : 
      64             : /*
      65             :  *
      66             :  */
      67             : 
      68             : static void
      69           0 : print_pem_stamp(FILE *f, const char *type, const char *str)
      70             : {
      71           0 :     fprintf(f, "-----%s %s-----\n", type, str);
      72           0 : }
      73             : 
      74             : HX509_LIB_FUNCTION int HX509_LIB_CALL
      75           0 : hx509_pem_write(hx509_context context, const char *type,
      76             :                 hx509_pem_header *headers, FILE *f,
      77             :                 const void *data, size_t size)
      78             : {
      79           0 :     const char *p = data;
      80           0 :     size_t length;
      81           0 :     char *line;
      82             : 
      83             : #define ENCODE_LINE_LENGTH      54
      84             : 
      85           0 :     print_pem_stamp(f, "BEGIN", type);
      86             : 
      87           0 :     while (headers) {
      88           0 :         fprintf(f, "%s: %s\n%s",
      89             :                 headers->header, headers->value,
      90           0 :                 headers->next ? "" : "\n");
      91           0 :         headers = headers->next;
      92             :     }
      93             : 
      94           0 :     while (size > 0) {
      95           0 :         ssize_t l;
      96             : 
      97           0 :         length = size;
      98           0 :         if (length > ENCODE_LINE_LENGTH)
      99           0 :             length = ENCODE_LINE_LENGTH;
     100             : 
     101           0 :         l = rk_base64_encode(p, length, &line);
     102           0 :         if (l < 0) {
     103           0 :             hx509_set_error_string(context, 0, ENOMEM,
     104             :                                    "malloc - out of memory");
     105           0 :             return ENOMEM;
     106             :         }
     107           0 :         size -= length;
     108           0 :         fprintf(f, "%s\n", line);
     109           0 :         p += length;
     110           0 :         free(line);
     111             :     }
     112             : 
     113           0 :     print_pem_stamp(f, "END", type);
     114             : 
     115           0 :     return 0;
     116             : }
     117             : 
     118             : /*
     119             :  *
     120             :  */
     121             : 
     122             : HX509_LIB_FUNCTION int HX509_LIB_CALL
     123           0 : hx509_pem_add_header(hx509_pem_header **headers,
     124             :                      const char *header, const char *value)
     125             : {
     126           0 :     hx509_pem_header *h;
     127             : 
     128           0 :     h = calloc(1, sizeof(*h));
     129           0 :     if (h == NULL)
     130           0 :         return ENOMEM;
     131           0 :     h->header = strdup(header);
     132           0 :     if (h->header == NULL) {
     133           0 :         free(h);
     134           0 :         return ENOMEM;
     135             :     }
     136           0 :     h->value = strdup(value);
     137           0 :     if (h->value == NULL) {
     138           0 :         free(h->header);
     139           0 :         free(h);
     140           0 :         return ENOMEM;
     141             :     }
     142             : 
     143           0 :     h->next = *headers;
     144           0 :     *headers = h;
     145             : 
     146           0 :     return 0;
     147             : }
     148             : 
     149             : HX509_LIB_FUNCTION void HX509_LIB_CALL
     150         379 : hx509_pem_free_header(hx509_pem_header *headers)
     151             : {
     152          32 :     hx509_pem_header *h;
     153         379 :     while (headers) {
     154           0 :         h = headers;
     155           0 :         headers = headers->next;
     156           0 :         free(h->header);
     157           0 :         free(h->value);
     158           0 :         free(h);
     159             :     }
     160         379 : }
     161             : 
     162             : /*
     163             :  *
     164             :  */
     165             : 
     166             : HX509_LIB_FUNCTION const char * HX509_LIB_CALL
     167          74 : hx509_pem_find_header(const hx509_pem_header *h, const char *header)
     168             : {
     169          74 :     while(h) {
     170           0 :         if (strcmp(header, h->header) == 0)
     171           0 :             return h->value;
     172           0 :         h = h->next;
     173             :     }
     174          66 :     return NULL;
     175             : }
     176             : 
     177             : 
     178             : /*
     179             :  *
     180             :  */
     181             : 
     182             : HX509_LIB_FUNCTION int HX509_LIB_CALL
     183         379 : hx509_pem_read(hx509_context context,
     184             :                FILE *f,
     185             :                hx509_pem_read_func func,
     186             :                void *ctx)
     187             : {
     188         379 :     hx509_pem_header *headers = NULL;
     189         379 :     char *type = NULL;
     190         379 :     void *data = NULL;
     191         379 :     size_t len = 0;
     192          32 :     char buf[1024];
     193         379 :     int ret = HX509_PARSING_KEY_FAILED;
     194             : 
     195          32 :     enum { BEFORE, SEARCHHEADER, INHEADER, INDATA, DONE } where;
     196             : 
     197         379 :     where = BEFORE;
     198             : 
     199       28277 :     while (fgets(buf, sizeof(buf), f) != NULL) {
     200        2688 :         char *p;
     201        2688 :         int i;
     202             : 
     203       27898 :         i = strcspn(buf, "\n");
     204       27898 :         if (buf[i] == '\n') {
     205       27898 :             buf[i] = '\0';
     206       27898 :             if (i > 0)
     207       27676 :                 i--;
     208             :         }
     209       27898 :         if (buf[i] == '\r') {
     210           0 :             buf[i] = '\0';
     211           0 :             if (i > 0)
     212           0 :                 i--;
     213             :         }
     214             : 
     215       27898 :         switch (where) {
     216       10029 :         case BEFORE:
     217       10029 :             if (strncmp("-----BEGIN ", buf, 11) == 0) {
     218         379 :                 type = strdup(buf + 11);
     219         379 :                 if (type == NULL)
     220           0 :                     break;
     221         379 :                 p = strchr(type, '-');
     222         379 :                 if (p)
     223         379 :                     *p = '\0';
     224         347 :                 where = SEARCHHEADER;
     225             :             }
     226        8917 :             break;
     227         379 :         case SEARCHHEADER:
     228         379 :             p = strchr(buf, ':');
     229         379 :             if (p == NULL) {
     230         379 :                 where = INDATA;
     231         379 :                 goto indata;
     232             :             }
     233           0 :             HEIM_FALLTHROUGH;
     234             :         case INHEADER:
     235           0 :             if (buf[0] == '\0') {
     236           0 :                 where = INDATA;
     237           0 :                 break;
     238             :             }
     239           0 :             p = strchr(buf, ':');
     240           0 :             if (p) {
     241           0 :                 *p++ = '\0';
     242           0 :                 while (isspace((unsigned char)*p))
     243           0 :                     p++;
     244           0 :                 ret = hx509_pem_add_header(&headers, buf, p);
     245           0 :                 if (ret)
     246           0 :                     abort();
     247             :             }
     248           0 :             break;
     249             :         case INDATA:
     250       17869 :         indata:
     251             : 
     252       17869 :             if (strncmp("-----END ", buf, 9) == 0) {
     253         347 :                 where = DONE;
     254         347 :                 break;
     255             :             }
     256             : 
     257       17490 :             p = emalloc(i);
     258       17490 :             i = rk_base64_decode(buf, p);
     259       17490 :             if (i < 0) {
     260           0 :                 free(p);
     261           0 :                 goto out;
     262             :             }
     263             : 
     264       17490 :             data = erealloc(data, len + i);
     265       17490 :             memcpy(((char *)data) + len, p, i);
     266       17490 :             free(p);
     267       17490 :             len += i;
     268       17490 :             break;
     269           0 :         case DONE:
     270           0 :             abort();
     271             :         }
     272             : 
     273       27898 :         if (where == DONE) {
     274         379 :             ret = (*func)(context, type, headers, data, len, ctx);
     275         379 :         out:
     276         379 :             free(data);
     277         379 :             data = NULL;
     278         379 :             len = 0;
     279         379 :             free(type);
     280         379 :             type = NULL;
     281         379 :             where = BEFORE;
     282         379 :             hx509_pem_free_header(headers);
     283         379 :             headers = NULL;
     284         379 :             if (ret)
     285           0 :                 break;
     286             :         }
     287             :     }
     288             : 
     289         379 :     if (where != BEFORE) {
     290           0 :         hx509_set_error_string(context, 0, HX509_PARSING_KEY_FAILED,
     291             :                                "File ends before end of PEM end tag");
     292           0 :         ret = HX509_PARSING_KEY_FAILED;
     293             :     }
     294         379 :     if (data)
     295           0 :         free(data);
     296         379 :     if (type)
     297           0 :         free(type);
     298         379 :     if (headers)
     299           0 :         hx509_pem_free_header(headers);
     300             : 
     301         379 :     return ret;
     302             : }
     303             : 
     304             : /*
     305             :  * On modern systems there's no such thing as scrubbing a file.  Not this way
     306             :  * anyways.  However, for now we'll cargo-cult this along just as in lib/krb5.
     307             :  */
     308             : static int
     309           0 : scrub_file(int fd, ssize_t sz)
     310             : {
     311           0 :     char buf[128];
     312             : 
     313           0 :     memset(buf, 0, sizeof(buf));
     314           0 :     while (sz > 0) {
     315           0 :         ssize_t tmp;
     316           0 :         size_t wr = sizeof(buf) > sz ? (size_t)sz : sizeof(buf);
     317             : 
     318           0 :         tmp = write(fd, buf, wr);
     319           0 :         if (tmp == -1)
     320           0 :             return errno;
     321           0 :         sz -= tmp;
     322             :     }
     323             : #ifdef _MSC_VER
     324             :     return _commit(fd);
     325             : #else
     326           0 :     return fsync(fd);
     327             : #endif
     328             : }
     329             : 
     330             : int
     331           0 : _hx509_erase_file(hx509_context context, const char *fn)
     332             : {
     333           0 :     struct stat sb1, sb2;
     334           0 :     int ret;
     335           0 :     int fd;
     336             : 
     337           0 :     if (fn == NULL)
     338           0 :         return 0;
     339             : 
     340             :     /* This is based on _krb5_erase_file(), minus file locking */
     341           0 :     ret = lstat(fn, &sb1);
     342           0 :     if (ret == -1 && errno == ENOENT)
     343           0 :         return 0;
     344           0 :     if (ret == -1) {
     345           0 :         hx509_set_error_string(context, 0, errno, "hx509_certs_destroy: "
     346           0 :                                "stat of \"%s\": %s", fn, strerror(errno));
     347           0 :         return errno;
     348             :     }
     349             : 
     350           0 :     fd = open(fn, O_RDWR | O_BINARY | O_CLOEXEC | O_NOFOLLOW);
     351           0 :     if (fd < 0)
     352           0 :         return errno == ENOENT ? 0 : errno;
     353           0 :     rk_cloexec(fd);
     354             : 
     355           0 :     if (unlink(fn) < 0) {
     356           0 :         ret = errno;
     357           0 :         (void) close(fd);
     358           0 :         hx509_set_error_string(context, 0, ret, "hx509_certs_destroy: "
     359             :                                "unlinking \"%s\": %s", fn, strerror(ret));
     360           0 :         return ret;
     361             :     }
     362             : 
     363             :     /* check TOCTOU, symlinks */
     364           0 :     ret = fstat(fd, &sb2);
     365           0 :     if (ret < 0) {
     366           0 :         ret = errno;
     367           0 :         hx509_set_error_string(context, 0, ret, "hx509_certs_destroy: "
     368             :                                "fstat of %d, \"%s\": %s", fd, fn,
     369             :                                strerror(ret));
     370           0 :         (void) close(fd);
     371           0 :         return ret;
     372             :     }
     373           0 :     if (sb1.st_dev != sb2.st_dev || sb1.st_ino != sb2.st_ino) {
     374           0 :         (void) close(fd);
     375           0 :         return EPERM;
     376             :     }
     377             : 
     378             :     /* there are still hard links to this file */
     379           0 :     if (sb2.st_nlink != 0) {
     380           0 :         close(fd);
     381           0 :         return 0;
     382             :     }
     383             : 
     384           0 :     ret = scrub_file(fd, sb2.st_size);
     385           0 :     (void) close(fd);
     386           0 :     return ret;
     387             : }

Generated by: LCOV version 1.14