anastasis

Credential backup and recovery protocol and service
Log | Files | Refs | Submodules | README | LICENSE

anastasis-cli-common.c (4090B)


      1 /*
      2   This file is part of Anastasis
      3   Copyright (C) 2026 Anastasis SARL
      4 
      5   Anastasis is free software; you can redistribute it and/or modify it under the
      6   terms of the GNU Lesser General Public License as published by the Free Software
      7   Foundation; either version 3, or (at your option) any later version.
      8 
      9   Anastasis is distributed in the hope that it will be useful, but WITHOUT ANY
     10   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
     11   A PARTICULAR PURPOSE.  See the GNU Affero General Public License for more details.
     12 
     13   You should have received a copy of the GNU Affero General Public License along with
     14   Anastasis; see the file COPYING.GPL.  If not, see <http://www.gnu.org/licenses/>
     15 */
     16 /**
     17  * @file cli/anastasis-cli-common.c
     18  * @brief helpers shared by the Anastasis command line tools
     19  * @author Christian Grothoff
     20  */
     21 
     22 #include "platform.h"
     23 #include <gnunet/gnunet_util_lib.h>
     24 #include "anastasis-cli-common.h"
     25 
     26 #ifndef MAP_ANONYMOUS
     27 #define MAP_ANONYMOUS MAP_ANON
     28 #endif
     29 
     30 
     31 /**
     32  * Report that the input was larger than #ANASTASIS_CLI_MAX_STATE_SIZE.
     33  *
     34  * @param[out] error error structure to fill in
     35  */
     36 static void
     37 set_too_big (json_error_t *error)
     38 {
     39   GNUNET_snprintf (error->text,
     40                    sizeof (error->text),
     41                    "input exceeds the limit of %llu bytes",
     42                    (unsigned long long) ANASTASIS_CLI_MAX_STATE_SIZE);
     43 }
     44 
     45 
     46 json_t *
     47 ANASTASIS_CLI_json_load_capped (FILE *f,
     48                                 json_error_t *error)
     49 {
     50   int fd = fileno (f);
     51   struct stat sb;
     52   off_t fsize = -1;
     53   size_t map_size;
     54   size_t len;
     55   void *map;
     56   json_t *ret;
     57 
     58   memset (error,
     59           0,
     60           sizeof (*error));
     61   if ( (-1 != fd) &&
     62        (0 == fstat (fd,
     63                     &sb)) &&
     64        (S_ISREG (sb.st_mode)) &&
     65        (0 == ftello (f)) )
     66     fsize = sb.st_size;
     67   if (-1 != fsize)
     68   {
     69     /* Regular file positioned at the start: the size is known before we touch
     70        the data, so the limit is a single comparison and the file itself can
     71        serve as the buffer. */
     72     if (fsize > (off_t) ANASTASIS_CLI_MAX_STATE_SIZE)
     73     {
     74       set_too_big (error);
     75       return NULL;
     76     }
     77     if (0 == fsize)
     78       return json_loadb ("",   /* mmap() rejects a zero-length mapping */
     79                          0,
     80                          JSON_DECODE_ANY,
     81                          error);
     82     map_size = (size_t) fsize;
     83     len = map_size;
     84     map = mmap (NULL,
     85                 map_size,
     86                 PROT_READ,
     87                 MAP_PRIVATE,
     88                 fd,
     89                 0);
     90   }
     91   else
     92   {
     93     /* A pipe or terminal has no size to stat and nothing to map, so read into
     94        an anonymous mapping one byte larger than the limit: the pages we never
     95        fill cost nothing, and filling the last one means the input is too big. */
     96     map_size = ANASTASIS_CLI_MAX_STATE_SIZE + 1;
     97     len = 0;
     98     map = mmap (NULL,
     99                 map_size,
    100                 PROT_READ | PROT_WRITE,
    101                 MAP_PRIVATE | MAP_ANONYMOUS,
    102                 -1,
    103                 0);
    104   }
    105   if (MAP_FAILED == map)
    106   {
    107     GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
    108                          "mmap");
    109     GNUNET_snprintf (error->text,
    110                      sizeof (error->text),
    111                      "failed to map input: %s",
    112                      strerror (errno));
    113     return NULL;
    114   }
    115   if (-1 == fsize)
    116   {
    117     while (len < map_size)
    118     {
    119       size_t got;
    120 
    121       got = fread ((char *) map + len,
    122                    1,
    123                    map_size - len,
    124                    f);
    125       if (0 == got)
    126         break;   /* EOF or error; ferror() is reported as a parse failure below */
    127       len += got;
    128     }
    129     if (len == map_size)
    130     {
    131       GNUNET_break (0 == munmap (map,
    132                                  map_size));
    133       set_too_big (error);
    134       return NULL;
    135     }
    136   }
    137   ret = json_loadb (map,
    138                     len,
    139                     JSON_DECODE_ANY,
    140                     error);
    141   GNUNET_break (0 == munmap (map,
    142                              map_size));
    143   return ret;
    144 }
    145 
    146 
    147 /* end of anastasis-cli-common.c */