Add optional libpwquality support for new LUKS passwords.
[platform/upstream/cryptsetup.git] / src / utils_tools.c
1 /*
2  * cryptsetup - setup cryptographic volumes for dm-crypt
3  *
4  * Copyright (C) 2004, Christophe Saout <christophe@saout.de>
5  * Copyright (C) 2004-2007, Clemens Fruhwirth <clemens@endorphin.org>
6  * Copyright (C) 2009-2012, Red Hat, Inc. All rights reserved.
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License
10  * version 2 as published by the Free Software Foundation.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20  */
21
22 #include "cryptsetup.h"
23 #include <signal.h>
24
25 int opt_verbose = 0;
26 int opt_debug = 0;
27 int opt_batch_mode = 0;
28
29 /* interrupt handling */
30 volatile int quit = 0;
31 static int signals_blocked = 0;
32
33 static void int_handler(int sig __attribute__((__unused__)))
34 {
35         quit++;
36 }
37
38 int tools_signals_blocked(void)
39 {
40         return signals_blocked;
41 }
42
43 void set_int_block(int block)
44 {
45         sigset_t signals_open;
46
47         log_dbg("%slocking interruption on signal.", block ? "B" : "Unb");
48
49         sigemptyset(&signals_open);
50         sigaddset(&signals_open, SIGINT);
51         sigaddset(&signals_open, SIGTERM);
52         sigprocmask(block ? SIG_SETMASK : SIG_UNBLOCK, &signals_open, NULL);
53         signals_blocked = block;
54         quit = 0;
55 }
56
57 void set_int_handler(int block)
58 {
59         struct sigaction sigaction_open;
60
61         log_dbg("Installing SIGINT/SIGTERM handler.");
62         memset(&sigaction_open, 0, sizeof(struct sigaction));
63         sigaction_open.sa_handler = int_handler;
64         sigaction(SIGINT, &sigaction_open, 0);
65         sigaction(SIGTERM, &sigaction_open, 0);
66         set_int_block(block);
67 }
68
69 void check_signal(int *r)
70 {
71         if (quit && !*r)
72                 *r = -EINTR;
73 }
74
75 __attribute__((format(printf, 5, 6)))
76 void clogger(struct crypt_device *cd, int level, const char *file, int line,
77              const char *format, ...)
78 {
79         va_list argp;
80         char *target = NULL;
81
82         va_start(argp, format);
83
84         if (vasprintf(&target, format, argp) > 0) {
85                 if (level >= 0) {
86                         crypt_log(cd, level, target);
87 #ifdef CRYPT_DEBUG
88                 } else if (opt_debug)
89                         printf("# %s:%d %s\n", file ?: "?", line, target);
90 #else
91                 } else if (opt_debug)
92                         printf("# %s\n", target);
93 #endif
94         }
95
96         va_end(argp);
97         free(target);
98 }
99
100 void tool_log(int level, const char *msg, void *usrptr __attribute__((unused)))
101 {
102         switch(level) {
103
104         case CRYPT_LOG_NORMAL:
105                 fputs(msg, stdout);
106                 break;
107         case CRYPT_LOG_VERBOSE:
108                 if (opt_verbose)
109                         fputs(msg, stdout);
110                 break;
111         case CRYPT_LOG_ERROR:
112                 fputs(msg, stderr);
113                 break;
114         case CRYPT_LOG_DEBUG:
115                 if (opt_debug)
116                         printf("# %s\n", msg);
117                 break;
118         default:
119                 fprintf(stderr, "Internal error on logging class for msg: %s", msg);
120                 break;
121         }
122 }
123
124 void quiet_log(int level, const char *msg, void *usrptr)
125 {
126         if (!opt_verbose && (level == CRYPT_LOG_ERROR || level == CRYPT_LOG_NORMAL))
127                 level = CRYPT_LOG_VERBOSE;
128         tool_log(level, msg, usrptr);
129 }
130
131 int yesDialog(const char *msg, void *usrptr __attribute__((unused)))
132 {
133         char *answer = NULL;
134         size_t size = 0;
135         int r = 1, block;
136
137         block = tools_signals_blocked();
138         if (block)
139                 set_int_block(0);
140
141         if(isatty(STDIN_FILENO) && !opt_batch_mode) {
142                 log_std("\nWARNING!\n========\n");
143                 log_std("%s\n\nAre you sure? (Type uppercase yes): ", msg);
144                 if(getline(&answer, &size, stdin) == -1) {
145                         r = 0;
146                         /* Aborted by signal */
147                         if (!quit)
148                                 log_err(_("Error reading response from terminal.\n"));
149                         else
150                                 log_dbg("Query interrupted on signal.");
151                 } else if(strcmp(answer, "YES\n"))
152                         r = 0;
153         }
154
155         if (block && !quit)
156                 set_int_block(1);
157
158         free(answer);
159         return r;
160 }
161
162 void show_status(int errcode)
163 {
164         char error[256], *error_;
165
166         if(!opt_verbose)
167                 return;
168
169         if(!errcode) {
170                 log_std(_("Command successful.\n"));
171                 return;
172         }
173
174         crypt_get_error(error, sizeof(error));
175
176         if (!error[0]) {
177                 error_ = strerror_r(-errcode, error, sizeof(error));
178                 if (error_ != error) {
179                         strncpy(error, error_, sizeof(error));
180                         error[sizeof(error) - 1] = '\0';
181                 }
182         }
183
184         log_err(_("Command failed with code %i"), -errcode);
185         if (*error)
186                 log_err(": %s\n", error);
187         else
188                 log_err(".\n");
189 }
190
191 const char *uuid_or_device(const char *spec)
192 {
193         static char device[PATH_MAX];
194         char s, *ptr;
195         int i = 0, uuid_len = 5;
196
197         /* Check if it is correct UUID=<LUKS_UUID> format */
198         if (spec && !strncmp(spec, "UUID=", uuid_len)) {
199                 strcpy(device, "/dev/disk/by-uuid/");
200                 ptr = &device[strlen(device)];
201                 i = uuid_len;
202                 while ((s = spec[i++]) && i < PATH_MAX) {
203                         if (!isxdigit(s) && s != '-')
204                                 return spec; /* Bail it out */
205                         if (isalpha(s))
206                                 s = tolower(s);
207                         *ptr++ = s;
208                 }
209                 *ptr = '\0';
210                 return device;
211         }
212
213         return spec;
214 }
215
216 __attribute__ ((noreturn)) void usage(poptContext popt_context,
217                                              int exitcode, const char *error,
218                                              const char *more)
219 {
220         poptPrintUsage(popt_context, stderr, 0);
221         if (error)
222                 log_err("%s: %s\n", more, error);
223         poptFreeContext(popt_context);
224         exit(exitcode);
225 }
226
227 void dbg_version_and_cmd(int argc, const char **argv)
228 {
229         int i;
230
231         log_std("# %s %s processing \"", PACKAGE_NAME, PACKAGE_VERSION);
232         for (i = 0; i < argc; i++) {
233                 if (i)
234                         log_std(" ");
235                 log_std("%s", argv[i]);
236         }
237         log_std("\"\n");
238 }
239
240 /* Translate exit code to simple codes */
241 int translate_errno(int r)
242 {
243         switch (r) {
244         case 0:         r = EXIT_SUCCESS; break;
245         case -EEXIST:
246         case -EBUSY:    r = 5; break;
247         case -ENOTBLK:
248         case -ENODEV:   r = 4; break;
249         case -ENOMEM:   r = 3; break;
250         case -EPERM:    r = 2; break;
251         case -EINVAL:
252         case -ENOENT:
253         case -ENOSYS:
254         default:        r = EXIT_FAILURE;
255         }
256         return r;
257 }