"Fossies" - the Fresh Open Source Software Archive

Member "cryptsetup-2.4.3/src/utils_tools.c" (13 Jan 2022, 12783 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_tools.c" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 2.4.1_vs_2.4.2.

    1 /*
    2  * cryptsetup - setup cryptographic volumes for dm-crypt
    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 "cryptsetup.h"
   25 #include <math.h>
   26 #include <signal.h>
   27 
   28 /* interrupt handling */
   29 volatile int quit = 0;
   30 static int signals_blocked = 0;
   31 
   32 static void int_handler(int sig __attribute__((__unused__)))
   33 {
   34     quit++;
   35 }
   36 
   37 int tools_signals_blocked(void)
   38 {
   39     return signals_blocked;
   40 }
   41 
   42 void set_int_block(int block)
   43 {
   44     sigset_t signals_open;
   45 
   46     log_dbg("%slocking interruption on signal.", block ? "B" : "Unb");
   47 
   48     sigemptyset(&signals_open);
   49     sigaddset(&signals_open, SIGINT);
   50     sigaddset(&signals_open, SIGTERM);
   51     sigprocmask(block ? SIG_SETMASK : SIG_UNBLOCK, &signals_open, NULL);
   52     signals_blocked = block;
   53     quit = 0;
   54 }
   55 
   56 void set_int_handler(int block)
   57 {
   58     struct sigaction sigaction_open;
   59 
   60     log_dbg("Installing SIGINT/SIGTERM handler.");
   61     memset(&sigaction_open, 0, sizeof(struct sigaction));
   62     sigaction_open.sa_handler = int_handler;
   63     sigaction(SIGINT, &sigaction_open, 0);
   64     sigaction(SIGTERM, &sigaction_open, 0);
   65     set_int_block(block);
   66 }
   67 
   68 void check_signal(int *r)
   69 {
   70     if (quit && !*r)
   71         *r = -EINTR;
   72 }
   73 
   74 void tool_log(int level, const char *msg, void *usrptr)
   75 {
   76     struct tools_log_params *params = (struct tools_log_params *)usrptr;
   77 
   78     switch (level) {
   79 
   80     case CRYPT_LOG_NORMAL:
   81         fprintf(stdout, "%s", msg);
   82         break;
   83     case CRYPT_LOG_VERBOSE:
   84         if (params && params->verbose)
   85             fprintf(stdout, "%s", msg);
   86         break;
   87     case CRYPT_LOG_ERROR:
   88         fprintf(stderr, "%s", msg);
   89         break;
   90     case CRYPT_LOG_DEBUG_JSON:
   91     case CRYPT_LOG_DEBUG:
   92         if (params && params->debug)
   93             fprintf(stdout, "# %s", msg);
   94         break;
   95     }
   96 }
   97 
   98 void quiet_log(int level, const char *msg, void *usrptr)
   99 {
  100     struct tools_log_params *params = (struct tools_log_params *)usrptr;
  101 
  102     if ((!params || !params->verbose) && (level == CRYPT_LOG_ERROR || level == CRYPT_LOG_NORMAL))
  103         return;
  104     tool_log(level, msg, usrptr);
  105 }
  106 
  107 static int _dialog(const char *msg, void *usrptr, int default_answer)
  108 {
  109     const char *fail_msg = (const char *)usrptr;
  110     char *answer = NULL;
  111     size_t size = 0;
  112     int r = default_answer, block;
  113 
  114     block = tools_signals_blocked();
  115     if (block)
  116         set_int_block(0);
  117 
  118     if (isatty(STDIN_FILENO)) {
  119         log_std(_("\nWARNING!\n========\n"));
  120         /* TRANSLATORS: User must type "YES" (in capital letters), do not translate this word. */
  121         log_std(_("%s\n\nAre you sure? (Type 'yes' in capital letters): "), msg);
  122         fflush(stdout);
  123         if(getline(&answer, &size, stdin) == -1) {
  124             r = 0;
  125             /* Aborted by signal */
  126             if (!quit)
  127                 log_err(_("Error reading response from terminal."));
  128             else
  129                 log_dbg("Query interrupted on signal.");
  130         } else {
  131             r = !strcmp(answer, "YES\n");
  132             if (!r && fail_msg)
  133                 log_err("%s", fail_msg);
  134         }
  135     }
  136 
  137     if (block && !quit)
  138         set_int_block(1);
  139 
  140     free(answer);
  141     return r;
  142 }
  143 
  144 int yesDialog(const char *msg, void *usrptr)
  145 {
  146     return _dialog(msg, usrptr, 1);
  147 }
  148 
  149 int noDialog(const char *msg, void *usrptr)
  150 {
  151     return _dialog(msg, usrptr, 0);
  152 }
  153 
  154 void show_status(int errcode)
  155 {
  156     char *crypt_error;
  157 
  158     if (!errcode) {
  159         log_verbose(_("Command successful."));
  160         return;
  161     }
  162 
  163     if (errcode < 0)
  164         errcode = translate_errno(errcode);
  165 
  166     if (errcode == 1)
  167         crypt_error = _("wrong or missing parameters");
  168     else if (errcode == 2)
  169         crypt_error = _("no permission or bad passphrase");
  170     else if (errcode == 3)
  171         crypt_error = _("out of memory");
  172     else if (errcode == 4)
  173         crypt_error = _("wrong device or file specified");
  174     else if (errcode == 5)
  175         crypt_error = _("device already exists or device is busy");
  176     else
  177         crypt_error = _("unknown error");
  178 
  179     log_verbose(_("Command failed with code %i (%s)."), -errcode, crypt_error);
  180 }
  181 
  182 const char *uuid_or_device(const char *spec)
  183 {
  184     static char device[PATH_MAX];
  185     char s, *ptr;
  186     int i = 0, uuid_len = 5;
  187 
  188     /* Check if it is correct UUID=<LUKS_UUID> format */
  189     if (spec && !strncmp(spec, "UUID=", uuid_len)) {
  190         strcpy(device, "/dev/disk/by-uuid/");
  191         ptr = &device[strlen(device)];
  192         i = uuid_len;
  193         while ((s = spec[i++]) && i < (PATH_MAX - 13)) {
  194             if (!isxdigit(s) && s != '-')
  195                 return spec; /* Bail it out */
  196             if (isalpha(s))
  197                 s = tolower(s);
  198             *ptr++ = s;
  199         }
  200         *ptr = '\0';
  201         return device;
  202     }
  203 
  204     return spec;
  205 }
  206 
  207 __attribute__ ((noreturn)) void usage(poptContext popt_context,
  208                          int exitcode, const char *error,
  209                          const char *more)
  210 {
  211     poptPrintUsage(popt_context, stderr, 0);
  212     if (error)
  213         log_err("%s: %s", more, error);
  214     tools_cleanup();
  215     poptFreeContext(popt_context);
  216     exit(exitcode);
  217 }
  218 
  219 void dbg_version_and_cmd(int argc, const char **argv)
  220 {
  221     int i;
  222 
  223     log_std("# %s %s processing \"", PACKAGE_NAME, PACKAGE_VERSION);
  224     for (i = 0; i < argc; i++) {
  225         if (i)
  226             log_std(" ");
  227         log_std("%s", argv[i]);
  228     }
  229     log_std("\"\n");
  230 }
  231 
  232 /* Translate exit code to simple codes */
  233 int translate_errno(int r)
  234 {
  235     switch (r) {
  236     case 0:     r = EXIT_SUCCESS; break;
  237     case -EEXIST:
  238     case -EBUSY:    r = 5; break;
  239     case -ENOTBLK:
  240     case -ENODEV:   r = 4; break;
  241     case -ENOMEM:   r = 3; break;
  242     case -EPERM:    r = 2; break;
  243     case -EINVAL:
  244     case -ENOENT:
  245     case -ENOSYS:
  246     default:    r = EXIT_FAILURE;
  247     }
  248     return r;
  249 }
  250 
  251 void tools_keyslot_msg(int keyslot, crypt_object_op op)
  252 {
  253     if (keyslot < 0)
  254         return;
  255 
  256     if (op == CREATED)
  257         log_verbose(_("Key slot %i created."), keyslot);
  258     else if (op == UNLOCKED)
  259         log_verbose(_("Key slot %i unlocked."), keyslot);
  260     else if (op == REMOVED)
  261         log_verbose(_("Key slot %i removed."), keyslot);
  262 }
  263 
  264 void tools_token_msg(int token, crypt_object_op op)
  265 {
  266     if (token < 0)
  267         return;
  268 
  269     if (op == CREATED)
  270         log_verbose(_("Token %i created."), token);
  271     else if (op == REMOVED)
  272         log_verbose(_("Token %i removed."), token);
  273 }
  274 
  275 void tools_token_error_msg(int error, const char *type, int token, bool pin_provided)
  276 {
  277     if (error >= 0)
  278         return;
  279 
  280     if (error == -ENOANO) {
  281         if (pin_provided)
  282             log_verbose(_("No token could be unlocked with this PIN."));
  283         else if (token != CRYPT_ANY_TOKEN)
  284             log_verbose(_("Token %i requires PIN."), token);
  285         else if (type)
  286             log_verbose(_("Token (type %s) requires PIN."), type);
  287     } else if (error == -EPERM) {
  288         if (token != CRYPT_ANY_TOKEN)
  289             log_verbose(_("Token %i cannot unlock assigned keyslot(s) (wrong keyslot passphrase)."), token);
  290         else if (type)
  291             log_verbose(_("Token (type %s) cannot unlock assigned keyslot(s) (wrong keyslot passphrase)."), type);
  292     } if (error == -EAGAIN) {
  293         if (token != CRYPT_ANY_TOKEN)
  294             log_verbose(_("Token %i requires additional missing resource."), token);
  295         else if (type)
  296             log_verbose(_("Token (type %s) requires additional missing resource."), type);
  297     } if (error == -ENOENT) {
  298         if (type)
  299             log_verbose(_("No usable token (type %s) is available."), type);
  300         else
  301             log_verbose(_("No usable token is available."));
  302     }
  303 }
  304 
  305 /*
  306  * Device size string parsing, suffixes:
  307  * s|S - 512 bytes sectors
  308  * k  |K  |m  |M  |g  |G  |t  |T   - 1024 base
  309  * kiB|KiB|miB|MiB|giB|GiB|tiB|TiB - 1024 base
  310  * kb |KB |mM |MB |gB |GB |tB |TB  - 1000 base
  311  */
  312 int tools_string_to_size(const char *s, uint64_t *size)
  313 {
  314     char *endp = NULL;
  315     size_t len;
  316     uint64_t mult_base, mult, tmp;
  317 
  318     *size = strtoull(s, &endp, 10);
  319     if (!isdigit(s[0]) ||
  320         (errno == ERANGE && *size == ULLONG_MAX) ||
  321         (errno != 0 && *size == 0))
  322         return -EINVAL;
  323 
  324     if (!endp || !*endp)
  325         return 0;
  326 
  327     len = strlen(endp);
  328     /* Allow "B" and "iB" suffixes */
  329     if (len > 3 ||
  330        (len == 3 && (endp[1] != 'i' || endp[2] != 'B')) ||
  331        (len == 2 && endp[1] != 'B'))
  332         return -EINVAL;
  333 
  334     if (len == 1 || len == 3)
  335         mult_base = 1024;
  336     else
  337         mult_base = 1000;
  338 
  339     mult = 1;
  340     switch (endp[0]) {
  341     case 's':
  342     case 'S': mult = 512;
  343         break;
  344     case 't':
  345     case 'T': mult *= mult_base;
  346          /* Fall through */
  347     case 'g':
  348     case 'G': mult *= mult_base;
  349          /* Fall through */
  350     case 'm':
  351     case 'M': mult *= mult_base;
  352          /* Fall through */
  353     case 'k':
  354     case 'K': mult *= mult_base;
  355         break;
  356     default:
  357         return -EINVAL;
  358     }
  359 
  360     tmp = *size * mult;
  361     if (*size && (tmp / *size) != mult) {
  362         log_dbg("Device size overflow.");
  363         return -EINVAL;
  364     }
  365 
  366     *size = tmp;
  367     return 0;
  368 }
  369 
  370 /* Time progress helper */
  371 
  372 /* The difference in seconds between two times in "timeval" format. */
  373 static double time_diff(struct timeval *start, struct timeval *end)
  374 {
  375     return (end->tv_sec - start->tv_sec)
  376         + (end->tv_usec - start->tv_usec) / 1E6;
  377 }
  378 
  379 static void tools_clear_line(void)
  380 {
  381     /* vt100 code clear line */
  382     log_std("\33[2K\r");
  383 }
  384 
  385 static void tools_time_progress(uint64_t device_size, uint64_t bytes, struct tools_progress_params *parms)
  386 {
  387     struct timeval now_time;
  388     unsigned long long mbytes, eta;
  389     double tdiff, uib, frequency;
  390     int final = (bytes == device_size);
  391     const char *eol, *ustr = "";
  392 
  393     gettimeofday(&now_time, NULL);
  394     if (parms->start_time.tv_sec == 0 && parms->start_time.tv_usec == 0) {
  395         parms->start_time = now_time;
  396         parms->end_time = now_time;
  397         parms->start_offset = bytes;
  398         return;
  399     }
  400 
  401     if (parms->frequency) {
  402         frequency = (double)parms->frequency;
  403         eol = "\n";
  404     } else {
  405         frequency = 0.5;
  406         eol = "";
  407     }
  408 
  409     if (!final && time_diff(&parms->end_time, &now_time) < frequency)
  410         return;
  411 
  412     parms->end_time = now_time;
  413 
  414     tdiff = time_diff(&parms->start_time, &parms->end_time);
  415     if (!tdiff)
  416         return;
  417 
  418     mbytes = bytes  / 1024 / 1024;
  419     uib = (double)(bytes - parms->start_offset) / tdiff;
  420 
  421     eta = (unsigned long long)(device_size / uib - tdiff);
  422 
  423     if (uib > 1073741824.0f) {
  424         uib /= 1073741824.0f;
  425         ustr = "Gi";
  426     } else if (uib > 1048576.0f) {
  427         uib /= 1048576.0f;
  428         ustr = "Mi";
  429     } else if (uib > 1024.0f) {
  430         uib /= 1024.0f;
  431         ustr = "Ki";
  432     }
  433 
  434     if (!parms->frequency)
  435         tools_clear_line();
  436     if (final)
  437         log_std("Finished, time %02llu:%02llu.%03llu, "
  438             "%4llu MiB written, speed %5.1f %sB/s\n",
  439             (unsigned long long)tdiff / 60,
  440             (unsigned long long)tdiff % 60,
  441             (unsigned long long)((tdiff - floor(tdiff)) * 1000.0),
  442             mbytes, uib, ustr);
  443     else
  444         log_std("Progress: %5.1f%%, ETA %02llu:%02llu, "
  445             "%4llu MiB written, speed %5.1f %sB/s%s",
  446             (double)bytes / device_size * 100,
  447             eta / 60, eta % 60, mbytes, uib, ustr, eol);
  448     fflush(stdout);
  449 }
  450 
  451 int tools_wipe_progress(uint64_t size, uint64_t offset, void *usrptr)
  452 {
  453     int r = 0;
  454     struct tools_progress_params *parms = (struct tools_progress_params *)usrptr;
  455 
  456     if (parms && !parms->batch_mode)
  457         tools_time_progress(size, offset, parms);
  458 
  459     check_signal(&r);
  460     if (r) {
  461         if (!parms || !parms->frequency)
  462             tools_clear_line();
  463         log_err(_("\nWipe interrupted."));
  464     }
  465 
  466     return r;
  467 }
  468 
  469 /*
  470  * Keyfile - is standard input treated as a binary file (no EOL handling).
  471  */
  472 int tools_is_stdin(const char *key_file)
  473 {
  474     if (!key_file)
  475         return 1;
  476 
  477     return strcmp(key_file, "-") ? 0 : 1;
  478 }
  479 
  480 int tools_reencrypt_progress(uint64_t size, uint64_t offset, void *usrptr)
  481 {
  482     int r = 0;
  483     struct tools_progress_params *parms = (struct tools_progress_params *)usrptr;
  484 
  485     if (parms && !parms->batch_mode)
  486         tools_time_progress(size, offset, parms);
  487 
  488     check_signal(&r);
  489     if (r) {
  490         if (!parms || !parms->frequency)
  491             tools_clear_line();
  492         log_err(_("\nReencryption interrupted."));
  493     }
  494 
  495     return r;
  496 }
  497 
  498 int tools_read_mk(const char *file, char **key, int keysize)
  499 {
  500     int fd = -1, r = -EINVAL;
  501 
  502     if (keysize <= 0 || !key)
  503         return -EINVAL;
  504 
  505     *key = crypt_safe_alloc(keysize);
  506     if (!*key)
  507         return -ENOMEM;
  508 
  509     fd = open(file, O_RDONLY);
  510     if (fd == -1) {
  511         log_err(_("Cannot read keyfile %s."), file);
  512         goto out;
  513     }
  514 
  515     if (read_buffer(fd, *key, keysize) != keysize) {
  516         log_err(_("Cannot read %d bytes from keyfile %s."), keysize, file);
  517         goto out;
  518     }
  519     r = 0;
  520 out:
  521     if (fd != -1)
  522         close(fd);
  523 
  524     if (r) {
  525         crypt_safe_free(*key);
  526         *key = NULL;
  527     }
  528 
  529     return r;
  530 }
  531 
  532 int tools_write_mk(const char *file, const char *key, int keysize)
  533 {
  534     int fd, r = -EINVAL;
  535 
  536     if (keysize <= 0 || !key)
  537         return -EINVAL;
  538 
  539     fd = open(file, O_CREAT|O_EXCL|O_WRONLY, S_IRUSR);
  540     if (fd < 0) {
  541         log_err(_("Cannot open keyfile %s for write."), file);
  542         return r;
  543     }
  544 
  545     if (write_buffer(fd, key, keysize) == keysize)
  546         r = 0;
  547     else
  548         log_err(_("Cannot write to keyfile %s."), file);
  549 
  550     close(fd);
  551     return r;
  552 }