Makefile: Add security compiling option (RELRO, SC, and FORTIFY)
[platform/upstream/cryptsetup.git] / src / utils_tools.c
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-2023 Red Hat, Inc. All rights reserved.
7  * Copyright (C) 2009-2023 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 <signal.h>
26
27 /* interrupt handling */
28 volatile int quit = 0;
29 static int signals_blocked = 0;
30
31 static void int_handler(int sig __attribute__((__unused__)))
32 {
33         quit++;
34 }
35
36 int tools_signals_blocked(void)
37 {
38         return signals_blocked;
39 }
40
41 void set_int_block(int block)
42 {
43         sigset_t signals_open;
44
45         log_dbg("%slocking interruption on signal.", block ? "B" : "Unb");
46
47         sigemptyset(&signals_open);
48         sigaddset(&signals_open, SIGINT);
49         sigaddset(&signals_open, SIGTERM);
50         sigprocmask(block ? SIG_SETMASK : SIG_UNBLOCK, &signals_open, NULL);
51         signals_blocked = block;
52         quit = 0;
53 }
54
55 void set_int_handler(int block)
56 {
57         struct sigaction sigaction_open;
58
59         log_dbg("Installing SIGINT/SIGTERM handler.");
60         memset(&sigaction_open, 0, sizeof(struct sigaction));
61         sigaction_open.sa_handler = int_handler;
62         sigaction(SIGINT, &sigaction_open, 0);
63         sigaction(SIGTERM, &sigaction_open, 0);
64         set_int_block(block);
65 }
66
67 void check_signal(int *r)
68 {
69         if (quit && !*r)
70                 *r = -EINTR;
71 }
72
73 void tool_log(int level, const char *msg, void *usrptr)
74 {
75         struct tools_log_params *params = (struct tools_log_params *)usrptr;
76
77         switch (level) {
78
79         case CRYPT_LOG_NORMAL:
80                 fprintf(stdout, "%s", msg);
81                 break;
82         case CRYPT_LOG_VERBOSE:
83                 if (params && params->verbose)
84                         fprintf(stdout, "%s", msg);
85                 break;
86         case CRYPT_LOG_ERROR:
87                 fprintf(stderr, "%s", msg);
88                 break;
89         case CRYPT_LOG_DEBUG_JSON:
90         case CRYPT_LOG_DEBUG:
91                 if (params && params->debug)
92                         fprintf(stdout, "# %s", msg);
93                 break;
94         }
95 }
96
97 void quiet_log(int level, const char *msg, void *usrptr)
98 {
99         struct tools_log_params *params = (struct tools_log_params *)usrptr;
100
101         if ((!params || !params->verbose) && (level == CRYPT_LOG_ERROR || level == CRYPT_LOG_NORMAL))
102                 return;
103         tool_log(level, msg, usrptr);
104 }
105
106 static int _dialog(const char *msg, void *usrptr, int default_answer)
107 {
108         const char *fail_msg = (const char *)usrptr;
109         char *answer = NULL;
110         size_t size = 0;
111         int r = default_answer, block;
112
113         block = tools_signals_blocked();
114         if (block)
115                 set_int_block(0);
116
117         if (isatty(STDIN_FILENO)) {
118                 log_std(_("\nWARNING!\n========\n"));
119                 /* TRANSLATORS: User must type "YES" (in capital letters), do not translate this word. */
120                 log_std(_("%s\n\nAre you sure? (Type 'yes' in capital letters): "), msg);
121                 fflush(stdout);
122                 if(getline(&answer, &size, stdin) == -1) {
123                         r = 0;
124                         /* Aborted by signal */
125                         if (!quit)
126                                 log_err(_("Error reading response from terminal."));
127                         else
128                                 log_dbg("Query interrupted on signal.");
129                 } else {
130                         r = !strcmp(answer, "YES\n");
131                         if (!r && fail_msg)
132                                 log_err("%s", fail_msg);
133                 }
134         }
135
136         if (block && !quit)
137                 set_int_block(1);
138
139         free(answer);
140         return r;
141 }
142
143 int yesDialog(const char *msg, void *usrptr)
144 {
145         return _dialog(msg, usrptr, 1);
146 }
147
148 int noDialog(const char *msg, void *usrptr)
149 {
150         return _dialog(msg, usrptr, 0);
151 }
152
153 void show_status(int errcode)
154 {
155         char *crypt_error;
156
157         if (!errcode) {
158                 log_verbose(_("Command successful."));
159                 return;
160         }
161
162         if (errcode < 0)
163                 errcode = translate_errno(errcode);
164
165         if (errcode == 1)
166                 crypt_error = _("wrong or missing parameters");
167         else if (errcode == 2)
168                 crypt_error = _("no permission or bad passphrase");
169         else if (errcode == 3)
170                 crypt_error = _("out of memory");
171         else if (errcode == 4)
172                 crypt_error = _("wrong device or file specified");
173         else if (errcode == 5)
174                 crypt_error = _("device already exists or device is busy");
175         else
176                 crypt_error = _("unknown error");
177
178         log_verbose(_("Command failed with code %i (%s)."), -errcode, crypt_error);
179 }
180
181 const char *uuid_or_device(const char *spec)
182 {
183         static char device[PATH_MAX];
184         char s, *ptr;
185         int i = 0, uuid_len = 5;
186
187         /* Check if it is correct UUID=<LUKS_UUID> format */
188         if (spec && !strncmp(spec, "UUID=", uuid_len)) {
189                 strcpy(device, "/dev/disk/by-uuid/");
190                 ptr = &device[strlen(device)];
191                 i = uuid_len;
192                 while ((s = spec[i++]) && i < (PATH_MAX - 13)) {
193                         if (!isxdigit(s) && s != '-')
194                                 return spec; /* Bail it out */
195                         if (isalpha(s))
196                                 s = tolower(s);
197                         *ptr++ = s;
198                 }
199                 *ptr = '\0';
200                 return device;
201         }
202
203         return spec;
204 }
205
206 __attribute__ ((noreturn)) void usage(poptContext popt_context,
207                                              int exitcode, const char *error,
208                                              const char *more)
209 {
210         poptPrintUsage(popt_context, stderr, 0);
211         if (error)
212                 log_err("%s: %s", more, error);
213         tools_cleanup();
214         poptFreeContext(popt_context);
215         exit(exitcode);
216 }
217
218 void dbg_version_and_cmd(int argc, const char **argv)
219 {
220         int i;
221
222         log_std("# %s %s processing \"", PACKAGE_NAME, PACKAGE_VERSION);
223         for (i = 0; i < argc; i++) {
224                 if (i)
225                         log_std(" ");
226                 log_std("%s", argv[i]);
227         }
228         log_std("\"\n");
229 }
230
231 /* Translate exit code to simple codes */
232 int translate_errno(int r)
233 {
234         switch (r) {
235         case 0:         r = EXIT_SUCCESS; break;
236         case -EEXIST:
237         case -EBUSY:    r = 5; break;
238         case -ENOTBLK:
239         case -ENODEV:   r = 4; break;
240         case -ENOMEM:   r = 3; break;
241         case -EPERM:    r = 2; break;
242         case -EINVAL:
243         case -ENOENT:
244         case -ENOSYS:
245         default:        r = EXIT_FAILURE;
246         }
247         return r;
248 }
249
250 void tools_keyslot_msg(int keyslot, crypt_object_op op)
251 {
252         if (keyslot < 0)
253                 return;
254
255         if (op == CREATED)
256                 log_verbose(_("Key slot %i created."), keyslot);
257         else if (op == UNLOCKED)
258                 log_verbose(_("Key slot %i unlocked."), keyslot);
259         else if (op == REMOVED)
260                 log_verbose(_("Key slot %i removed."), keyslot);
261 }
262
263 void tools_token_msg(int token, crypt_object_op op)
264 {
265         if (token < 0)
266                 return;
267
268         if (op == CREATED)
269                 log_verbose(_("Token %i created."), token);
270         else if (op == REMOVED)
271                 log_verbose(_("Token %i removed."), token);
272 }
273
274 void tools_token_error_msg(int error, const char *type, int token, bool pin_provided)
275 {
276         if (error >= 0)
277                 return;
278
279         if (error == -ENOANO) {
280                 if (pin_provided)
281                         log_verbose(_("No token could be unlocked with this PIN."));
282                 else if (token != CRYPT_ANY_TOKEN)
283                         log_verbose(_("Token %i requires PIN."), token);
284                 else if (type)
285                         log_verbose(_("Token (type %s) requires PIN."), type);
286         } else if (error == -EPERM) {
287                 if (token != CRYPT_ANY_TOKEN)
288                         log_verbose(_("Token %i cannot unlock assigned keyslot(s) (wrong keyslot passphrase)."), token);
289                 else if (type)
290                         log_verbose(_("Token (type %s) cannot unlock assigned keyslot(s) (wrong keyslot passphrase)."), type);
291         } if (error == -EAGAIN) {
292                 if (token != CRYPT_ANY_TOKEN)
293                         log_verbose(_("Token %i requires additional missing resource."), token);
294                 else if (type)
295                         log_verbose(_("Token (type %s) requires additional missing resource."), type);
296         } if (error == -ENOENT) {
297                 if (type)
298                         log_verbose(_("No usable token (type %s) is available."), type);
299                 else
300                         log_verbose(_("No usable token is available."));
301         }
302 }
303
304 /*
305  * Device size string parsing, suffixes:
306  * s|S - 512 bytes sectors
307  * k  |K  |m  |M  |g  |G  |t  |T   - 1024 base
308  * kiB|KiB|miB|MiB|giB|GiB|tiB|TiB - 1024 base
309  * kb |KB |mM |MB |gB |GB |tB |TB  - 1000 base
310  */
311 int tools_string_to_size(const char *s, uint64_t *size)
312 {
313         char *endp = NULL;
314         size_t len;
315         uint64_t mult_base, mult, tmp;
316
317         *size = strtoull(s, &endp, 10);
318         if (!isdigit(s[0]) ||
319             (errno == ERANGE && *size == ULLONG_MAX) ||
320             (errno != 0 && *size == 0))
321                 return -EINVAL;
322
323         if (!endp || !*endp)
324                 return 0;
325
326         len = strlen(endp);
327         /* Allow "B" and "iB" suffixes */
328         if (len > 3 ||
329            (len == 3 && (endp[1] != 'i' || endp[2] != 'B')) ||
330            (len == 2 && endp[1] != 'B'))
331                 return -EINVAL;
332
333         if (len == 1 || len == 3)
334                 mult_base = 1024;
335         else
336                 mult_base = 1000;
337
338         mult = 1;
339         switch (endp[0]) {
340         case 's':
341         case 'S': mult = 512;
342                 break;
343         case 't':
344         case 'T': mult *= mult_base;
345                  /* Fall through */
346         case 'g':
347         case 'G': mult *= mult_base;
348                  /* Fall through */
349         case 'm':
350         case 'M': mult *= mult_base;
351                  /* Fall through */
352         case 'k':
353         case 'K': mult *= mult_base;
354                 break;
355         default:
356                 return -EINVAL;
357         }
358
359         tmp = *size * mult;
360         if (*size && (tmp / *size) != mult) {
361                 log_dbg("Device size overflow.");
362                 return -EINVAL;
363         }
364
365         *size = tmp;
366         return 0;
367 }
368
369 /*
370  * Keyfile - is standard input treated as a binary file (no EOL handling).
371  */
372 int tools_is_stdin(const char *key_file)
373 {
374         if (!key_file)
375                 return 1;
376
377         return strcmp(key_file, "-") ? 0 : 1;
378 }
379
380 int tools_read_vk(const char *file, char **key, int keysize)
381 {
382         int fd = -1, r = -EINVAL;
383
384         if (keysize <= 0 || !key)
385                 return -EINVAL;
386
387         *key = crypt_safe_alloc(keysize);
388         if (!*key)
389                 return -ENOMEM;
390
391         fd = open(file, O_RDONLY);
392         if (fd == -1) {
393                 log_err(_("Cannot read keyfile %s."), file);
394                 goto out;
395         }
396
397         if (read_buffer(fd, *key, keysize) != keysize) {
398                 log_err(_("Cannot read %d bytes from keyfile %s."), keysize, file);
399                 goto out;
400         }
401         r = 0;
402 out:
403         if (fd != -1)
404                 close(fd);
405
406         if (r) {
407                 crypt_safe_free(*key);
408                 *key = NULL;
409         }
410
411         return r;
412 }
413
414 int tools_write_mk(const char *file, const char *key, int keysize)
415 {
416         int fd, r = -EINVAL;
417
418         if (keysize <= 0 || !key)
419                 return -EINVAL;
420
421         fd = open(file, O_CREAT|O_EXCL|O_WRONLY, S_IRUSR);
422         if (fd < 0) {
423                 log_err(_("Cannot open keyfile %s for write."), file);
424                 return r;
425         }
426
427         if (write_buffer(fd, key, keysize) == keysize)
428                 r = 0;
429         else
430                 log_err(_("Cannot write to keyfile %s."), file);
431
432         close(fd);
433         return r;
434 }
435
436 void tools_package_version(const char *name, bool use_pwlibs)
437 {
438         bool udev = false, blkid = false, keyring = false, fips = false;
439         bool kernel_capi = false, pwquality = false, passwdqc = false;
440 #ifdef USE_UDEV
441         udev = true;
442 #endif
443 #ifdef HAVE_BLKID
444         blkid = true;
445 #endif
446 #ifdef KERNEL_KEYRING
447         keyring = true;
448 #endif
449 #ifdef ENABLE_FIPS
450         fips = true;
451 #endif
452 #ifdef ENABLE_AF_ALG
453         kernel_capi = true;
454 #endif
455 #if defined(ENABLE_PWQUALITY)
456         pwquality = true;
457 #elif defined(ENABLE_PASSWDQC)
458         passwdqc = true;
459 #endif
460         log_std("%s %s flags: %s%s%s%s%s%s%s\n", name, PACKAGE_VERSION,
461                 udev ?  "UDEV " : "",
462                 blkid ? "BLKID " : "",
463                 keyring ? "KEYRING " : "",
464                 fips ? "FIPS " : "",
465                 kernel_capi ? "KERNEL_CAPI " : "",
466                 pwquality && use_pwlibs ? "PWQUALITY " : "",
467                 passwdqc && use_pwlibs ? "PASSWDQC " : "");
468 }