"Fossies" - the Fresh Open Source Software Archive

Member "cryptsetup-2.4.3/lib/utils.c" (13 Jan 2022, 8499 Bytes) of package /linux/misc/cryptsetup-2.4.3.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "utils.c" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 2.3.6_vs_2.4.0.

    1 /*
    2  * utils - miscellaneous device utilities for cryptsetup
    3  *
    4  * Copyright (C) 2004 Jana Saout <jana@saout.de>
    5  * Copyright (C) 2004-2007 Clemens Fruhwirth <clemens@endorphin.org>
    6  * Copyright (C) 2009-2021 Red Hat, Inc. All rights reserved.
    7  * Copyright (C) 2009-2021 Milan Broz
    8  *
    9  * This program is free software; you can redistribute it and/or
   10  * modify it under the terms of the GNU General Public License
   11  * as published by the Free Software Foundation; either version 2
   12  * of the License, or (at your option) any later version.
   13  *
   14  * This program is distributed in the hope that it will be useful,
   15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
   16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   17  * GNU General Public License for more details.
   18  *
   19  * You should have received a copy of the GNU General Public License
   20  * along with this program; if not, write to the Free Software
   21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
   22  */
   23 
   24 #include <stdio.h>
   25 #include <errno.h>
   26 #include <sys/mman.h>
   27 #include <sys/resource.h>
   28 #include <sys/stat.h>
   29 #include <sys/utsname.h>
   30 
   31 #include "internal.h"
   32 
   33 size_t crypt_getpagesize(void)
   34 {
   35     long r = sysconf(_SC_PAGESIZE);
   36     return r <= 0 ? DEFAULT_MEM_ALIGNMENT : (size_t)r;
   37 }
   38 
   39 unsigned crypt_cpusonline(void)
   40 {
   41     long r = sysconf(_SC_NPROCESSORS_ONLN);
   42     return r < 0 ? 1 : r;
   43 }
   44 
   45 uint64_t crypt_getphysmemory_kb(void)
   46 {
   47     long pagesize, phys_pages;
   48     uint64_t phys_memory_kb;
   49 
   50     pagesize = sysconf(_SC_PAGESIZE);
   51     phys_pages = sysconf(_SC_PHYS_PAGES);
   52 
   53     if (pagesize < 0 || phys_pages < 0)
   54         return 0;
   55 
   56     phys_memory_kb = pagesize / 1024;
   57     phys_memory_kb *= phys_pages;
   58 
   59     return phys_memory_kb;
   60 }
   61 
   62 /* MEMLOCK */
   63 #define DEFAULT_PROCESS_PRIORITY -18
   64 
   65 static int _priority;
   66 static int _memlock_count = 0;
   67 
   68 // return 1 if memory is locked
   69 int crypt_memlock_inc(struct crypt_device *ctx)
   70 {
   71     if (!_memlock_count++) {
   72         log_dbg(ctx, "Locking memory.");
   73         if (mlockall(MCL_CURRENT | MCL_FUTURE) == -1) {
   74             log_dbg(ctx, "Cannot lock memory with mlockall.");
   75             _memlock_count--;
   76             return 0;
   77         }
   78         errno = 0;
   79         if (((_priority = getpriority(PRIO_PROCESS, 0)) == -1) && errno)
   80             log_err(ctx, _("Cannot get process priority."));
   81         else
   82             if (setpriority(PRIO_PROCESS, 0, DEFAULT_PROCESS_PRIORITY))
   83                 log_dbg(ctx, "setpriority %d failed: %s",
   84                     DEFAULT_PROCESS_PRIORITY, strerror(errno));
   85     }
   86     return _memlock_count ? 1 : 0;
   87 }
   88 
   89 int crypt_memlock_dec(struct crypt_device *ctx)
   90 {
   91     if (_memlock_count && (!--_memlock_count)) {
   92         log_dbg(ctx, "Unlocking memory.");
   93         if (munlockall() == -1)
   94             log_err(ctx, _("Cannot unlock memory."));
   95         if (setpriority(PRIO_PROCESS, 0, _priority))
   96             log_dbg(ctx, "setpriority %d failed: %s", _priority, strerror(errno));
   97     }
   98     return _memlock_count ? 1 : 0;
   99 }
  100 
  101 /* Keyfile processing */
  102 
  103 /*
  104  * A simple call to lseek(3) might not be possible for some inputs (e.g.
  105  * reading from a pipe), so this function instead reads of up to BUFSIZ bytes
  106  * at a time until the specified number of bytes. It returns -1 on read error
  107  * or when it reaches EOF before the requested number of bytes have been
  108  * discarded.
  109  */
  110 static int keyfile_seek(int fd, uint64_t bytes)
  111 {
  112     char tmp[BUFSIZ];
  113     size_t next_read;
  114     ssize_t bytes_r;
  115     off64_t r;
  116 
  117     r = lseek64(fd, bytes, SEEK_CUR);
  118     if (r > 0)
  119         return 0;
  120     if (r < 0 && errno != ESPIPE)
  121         return -1;
  122 
  123     while (bytes > 0) {
  124         /* figure out how much to read */
  125         next_read = bytes > sizeof(tmp) ? sizeof(tmp) : (size_t)bytes;
  126 
  127         bytes_r = read(fd, tmp, next_read);
  128         if (bytes_r < 0) {
  129             if (errno == EINTR)
  130                 continue;
  131 
  132             crypt_safe_memzero(tmp, sizeof(tmp));
  133             /* read error */
  134             return -1;
  135         }
  136 
  137         if (bytes_r == 0)
  138             /* EOF */
  139             break;
  140 
  141         bytes -= bytes_r;
  142     }
  143 
  144     crypt_safe_memzero(tmp, sizeof(tmp));
  145     return bytes == 0 ? 0 : -1;
  146 }
  147 
  148 int crypt_keyfile_device_read(struct crypt_device *cd,  const char *keyfile,
  149                   char **key, size_t *key_size_read,
  150                   uint64_t keyfile_offset, size_t key_size,
  151                   uint32_t flags)
  152 {
  153     int fd, regular_file, char_to_read = 0, char_read = 0, unlimited_read = 0;
  154     int r = -EINVAL, newline;
  155     char *pass = NULL;
  156     size_t buflen, i;
  157     uint64_t file_read_size;
  158     struct stat st;
  159 
  160     if (!key || !key_size_read)
  161         return -EINVAL;
  162 
  163     *key = NULL;
  164     *key_size_read = 0;
  165 
  166     fd = keyfile ? open(keyfile, O_RDONLY) : STDIN_FILENO;
  167     if (fd < 0) {
  168         log_err(cd, _("Failed to open key file."));
  169         return -EINVAL;
  170     }
  171 
  172     if (isatty(fd)) {
  173         log_err(cd, _("Cannot read keyfile from a terminal."));
  174         goto out;
  175     }
  176 
  177     /* If not requested otherwise, we limit input to prevent memory exhaustion */
  178     if (key_size == 0) {
  179         key_size = DEFAULT_KEYFILE_SIZE_MAXKB * 1024 + 1;
  180         unlimited_read = 1;
  181         /* use 4k for buffer (page divisor but avoid huge pages) */
  182         buflen = 4096 - sizeof(size_t); // sizeof(struct safe_allocation);
  183     } else
  184         buflen = key_size;
  185 
  186     regular_file = 0;
  187     if (keyfile) {
  188         if (stat(keyfile, &st) < 0) {
  189             log_err(cd, _("Failed to stat key file."));
  190             goto out;
  191         }
  192         if (S_ISREG(st.st_mode)) {
  193             regular_file = 1;
  194             file_read_size = (uint64_t)st.st_size;
  195 
  196             if (keyfile_offset > file_read_size) {
  197                 log_err(cd, _("Cannot seek to requested keyfile offset."));
  198                 goto out;
  199             }
  200             file_read_size -= keyfile_offset;
  201 
  202             /* known keyfile size, alloc it in one step */
  203             if (file_read_size >= (uint64_t)key_size)
  204                 buflen = key_size;
  205             else if (file_read_size)
  206                 buflen = file_read_size;
  207         }
  208     }
  209 
  210     pass = crypt_safe_alloc(buflen);
  211     if (!pass) {
  212         log_err(cd, _("Out of memory while reading passphrase."));
  213         goto out;
  214     }
  215 
  216     /* Discard keyfile_offset bytes on input */
  217     if (keyfile_offset && keyfile_seek(fd, keyfile_offset) < 0) {
  218         log_err(cd, _("Cannot seek to requested keyfile offset."));
  219         goto out;
  220     }
  221 
  222     for (i = 0, newline = 0; i < key_size; i += char_read) {
  223         if (i == buflen) {
  224             buflen += 4096;
  225             pass = crypt_safe_realloc(pass, buflen);
  226             if (!pass) {
  227                 log_err(cd, _("Out of memory while reading passphrase."));
  228                 r = -ENOMEM;
  229                 goto out;
  230             }
  231         }
  232 
  233         if (flags & CRYPT_KEYFILE_STOP_EOL) {
  234             /* If we should stop on newline, we must read the input
  235              * one character at the time. Otherwise we might end up
  236              * having read some bytes after the newline, which we
  237              * promised not to do.
  238              */
  239             char_to_read = 1;
  240         } else {
  241             /* char_to_read = min(key_size - i, buflen - i) */
  242             char_to_read = key_size < buflen ?
  243                 key_size - i : buflen - i;
  244         }
  245         char_read = read_buffer(fd, &pass[i], char_to_read);
  246         if (char_read < 0) {
  247             log_err(cd, _("Error reading passphrase."));
  248             r = -EPIPE;
  249             goto out;
  250         }
  251 
  252         if (char_read == 0)
  253             break;
  254         /* Stop on newline only if not requested read from keyfile */
  255         if ((flags & CRYPT_KEYFILE_STOP_EOL) && pass[i] == '\n') {
  256             newline = 1;
  257             pass[i] = '\0';
  258             break;
  259         }
  260     }
  261 
  262     /* Fail if piped input dies reading nothing */
  263     if (!i && !regular_file && !newline) {
  264         log_err(cd, _("Nothing to read on input."));
  265         r = -EPIPE;
  266         goto out;
  267     }
  268 
  269     /* Fail if we exceeded internal default (no specified size) */
  270     if (unlimited_read && i == key_size) {
  271         log_err(cd, _("Maximum keyfile size exceeded."));
  272         goto out;
  273     }
  274 
  275     if (!unlimited_read && i != key_size) {
  276         log_err(cd, _("Cannot read requested amount of data."));
  277         goto out;
  278     }
  279 
  280     *key = pass;
  281     *key_size_read = i;
  282     r = 0;
  283 out:
  284     if (fd != STDIN_FILENO)
  285         close(fd);
  286 
  287     if (r)
  288         crypt_safe_free(pass);
  289     return r;
  290 }
  291 
  292 int crypt_keyfile_read(struct crypt_device *cd,  const char *keyfile,
  293                char **key, size_t *key_size_read,
  294                size_t keyfile_offset, size_t keyfile_size_max,
  295                uint32_t flags)
  296 {
  297     return crypt_keyfile_device_read(cd, keyfile, key, key_size_read,
  298                      keyfile_offset, keyfile_size_max, flags);
  299 }
  300 
  301 int kernel_version(uint64_t *kversion)
  302 {
  303     struct utsname uts;
  304     uint16_t maj, min, patch, rel;
  305     int r = -EINVAL;
  306 
  307     if (uname(&uts) < 0)
  308         return r;
  309 
  310     if (sscanf(uts.release, "%" SCNu16  ".%" SCNu16 ".%" SCNu16 "-%" SCNu16,
  311            &maj, &min, &patch, &rel) == 4)
  312         r = 0;
  313     else if (sscanf(uts.release,  "%" SCNu16 ".%" SCNu16 ".%" SCNu16,
  314             &maj, &min, &patch) == 3) {
  315         rel = 0;
  316         r = 0;
  317     }
  318 
  319     if (!r)
  320         *kversion = compact_version(maj, min, patch, rel);
  321 
  322     return r;
  323 }
  324 
  325 bool crypt_string_in(const char *str, char **list, size_t list_size)
  326 {
  327     size_t i;
  328 
  329     for (i = 0; *list && i < list_size; i++, list++)
  330         if (!strcmp(str, *list))
  331             return true;
  332 
  333     return false;
  334 }
  335 
  336 /* compare two strings (allows NULL values) */
  337 int crypt_strcmp(const char *a, const char *b)
  338 {
  339     if (!a && !b)
  340         return 0;
  341     else if (!a || !b)
  342         return 1;
  343     return strcmp(a, b);
  344 }