Move get_key to common code, simplify verify flags.
[platform/upstream/cryptsetup.git] / lib / utils.c
1 #include <stdio.h>
2 #include <string.h>
3 #include <stdlib.h>
4 #include <stddef.h>
5 #include <stdarg.h>
6 #include <errno.h>
7 #include <linux/fs.h>
8 #include <sys/types.h>
9 #include <unistd.h>
10 #include <sys/types.h>
11 #include <sys/stat.h>
12 #include <sys/ioctl.h>
13 #include <fcntl.h>
14 #include <termios.h>
15 #include <sys/mman.h>
16 #include <sys/resource.h>
17
18 #include "libcryptsetup.h"
19 #include "internal.h"
20
21 static char *error=NULL;
22
23 void set_error_va(const char *fmt, va_list va)
24 {
25         int r;
26
27         if(error) {
28                 free(error);
29                 error = NULL;
30         }
31
32         if(!fmt) return;
33
34         r = vasprintf(&error, fmt, va);
35         if (r < 0) {
36                 free(error);
37                 error = NULL;
38                 return;
39         }
40
41         if (r && error[r - 1] == '\n')
42                 error[r - 1] = '\0';
43 }
44
45 void set_error(const char *fmt, ...)
46 {
47         va_list va;
48
49         va_start(va, fmt);
50         set_error_va(fmt, va);
51         va_end(va);
52 }
53
54 const char *get_error(void)
55 {
56         return error;
57 }
58
59 static int get_alignment(int fd)
60 {
61         int alignment = DEFAULT_MEM_ALIGNMENT;
62
63 #ifdef _PC_REC_XFER_ALIGN
64         alignment = fpathconf(fd, _PC_REC_XFER_ALIGN);
65         if (alignment < 0)
66                 alignment = DEFAULT_MEM_ALIGNMENT;
67 #endif
68         return alignment;
69 }
70
71 static void *aligned_malloc(void **base, int size, int alignment)
72 {
73 #ifdef HAVE_POSIX_MEMALIGN
74         return posix_memalign(base, alignment, size) ? NULL : *base;
75 #else
76 /* Credits go to Michal's padlock patches for this alignment code */
77         char *ptr;
78
79         ptr  = malloc(size + alignment);
80         if(ptr == NULL) return NULL;
81
82         *base = ptr;
83         if(alignment > 1 && ((long)ptr & (alignment - 1))) {
84                 ptr += alignment - ((long)(ptr) & (alignment - 1));
85         }
86         return ptr;
87 #endif
88 }
89 static int sector_size(int fd) 
90 {
91         int bsize;
92         if (ioctl(fd,BLKSSZGET, &bsize) < 0)
93                 return -EINVAL;
94         else
95                 return bsize;
96 }
97
98 int sector_size_for_device(const char *device)
99 {
100         int fd = open(device, O_RDONLY);
101         int r;
102         if(fd < 0)
103                 return -EINVAL;
104         r = sector_size(fd);
105         close(fd);
106         return r;
107 }
108
109 ssize_t write_blockwise(int fd, const void *orig_buf, size_t count)
110 {
111         void *hangover_buf, *hangover_buf_base = NULL;
112         void *buf, *buf_base = NULL;
113         int r, hangover, solid, bsize, alignment;
114         ssize_t ret = -1;
115
116         if ((bsize = sector_size(fd)) < 0)
117                 return bsize;
118
119         hangover = count % bsize;
120         solid = count - hangover;
121         alignment = get_alignment(fd);
122
123         if ((long)orig_buf & (alignment - 1)) {
124                 buf = aligned_malloc(&buf_base, count, alignment);
125                 if (!buf)
126                         goto out;
127                 memcpy(buf, orig_buf, count);
128         } else
129                 buf = (void *)orig_buf;
130
131         r = write(fd, buf, solid);
132         if (r < 0 || r != solid)
133                 goto out;
134
135         if (hangover) {
136                 hangover_buf = aligned_malloc(&hangover_buf_base, bsize, alignment);
137                 if (!hangover_buf)
138                         goto out;
139
140                 r = read(fd, hangover_buf, bsize);
141                 if(r < 0 || r != bsize) goto out;
142
143                 r = lseek(fd, -bsize, SEEK_CUR);
144                 if (r < 0)
145                         goto out;
146                 memcpy(hangover_buf, buf + solid, hangover);
147
148                 r = write(fd, hangover_buf, bsize);
149                 if(r < 0 || r != bsize) goto out;
150                 free(hangover_buf_base);
151         }
152         ret = count;
153  out:
154         if (buf != orig_buf)
155                 free(buf_base);
156         return ret;
157 }
158
159 ssize_t read_blockwise(int fd, void *orig_buf, size_t count) {
160         void *hangover_buf, *hangover_buf_base;
161         void *buf, *buf_base = NULL;
162         int r, hangover, solid, bsize, alignment;
163         ssize_t ret = -1;
164
165         if ((bsize = sector_size(fd)) < 0)
166                 return bsize;
167
168         hangover = count % bsize;
169         solid = count - hangover;
170         alignment = get_alignment(fd);
171
172         if ((long)orig_buf & (alignment - 1)) {
173                 buf = aligned_malloc(&buf_base, count, alignment);
174                 if (!buf)
175                         goto out;
176         } else
177                 buf = orig_buf;
178
179         r = read(fd, buf, solid);
180         if(r < 0 || r != solid)
181                 goto out;
182
183         if (hangover) {
184                 hangover_buf = aligned_malloc(&hangover_buf_base, bsize, alignment);
185                 if (!hangover_buf)
186                         goto out;
187                 r = read(fd, hangover_buf, bsize);
188                 if (r <  0 || r != bsize)
189                         goto out;
190
191                 memcpy(buf + solid, hangover_buf, hangover);
192                 free(hangover_buf_base);
193         }
194         ret = count;
195  out:
196         if (buf != orig_buf) {
197                 memcpy(orig_buf, buf, count);
198                 free(buf_base);
199         }
200         return ret;
201 }
202
203 /* 
204  * Combines llseek with blockwise write. write_blockwise can already deal with short writes
205  * but we also need a function to deal with short writes at the start. But this information
206  * is implicitly included in the read/write offset, which can not be set to non-aligned 
207  * boundaries. Hence, we combine llseek with write.
208  */
209
210 ssize_t write_lseek_blockwise(int fd, const char *buf, size_t count, off_t offset) {
211         int bsize = sector_size(fd);
212         const char *orig_buf = buf;
213         char frontPadBuf[bsize];
214         int frontHang = offset % bsize;
215         int r;
216         int innerCount = count < bsize ? count : bsize;
217
218         if (bsize < 0)
219                 return bsize;
220
221         lseek(fd, offset - frontHang, SEEK_SET);
222         if(offset % bsize) {
223                 r = read(fd,frontPadBuf,bsize);
224                 if(r < 0) return -1;
225
226                 memcpy(frontPadBuf+frontHang, buf, innerCount);
227
228                 lseek(fd, offset - frontHang, SEEK_SET);
229                 r = write(fd,frontPadBuf,bsize);
230                 if(r < 0) return -1;
231
232                 buf += innerCount;
233                 count -= innerCount;
234         }
235         if(count <= 0) return buf - orig_buf;
236
237         return write_blockwise(fd, buf, count) + innerCount;
238 }
239
240 int device_ready(struct crypt_device *cd, const char *device, int mode)
241 {
242         int devfd, r = 1;
243         ssize_t s;
244         struct stat st;
245         char buf[512];
246
247         if(stat(device, &st) < 0) {
248                 log_err(cd, _("Device %s doesn't exist or access denied.\n"), device);
249                 return 0;
250         }
251
252         log_dbg("Trying to open and read device %s.", device);
253         devfd = open(device, mode | O_DIRECT | O_SYNC);
254         if(devfd < 0) {
255                 log_err(cd, _("Cannot open device %s for %s%s access.\n"), device,
256                         (mode & O_EXCL) ? _("exclusive ") : "",
257                         (mode & O_RDWR) ? _("writable") : _("read-only"));
258                 return 0;
259         }
260
261          /* Try to read first sector */
262         s = read_blockwise(devfd, buf, sizeof(buf));
263         if (s < 0 || s != sizeof(buf)) {
264                 log_err(cd, _("Cannot read device %s.\n"), device);
265                 r = 0;
266         }
267
268         memset(buf, 0, sizeof(buf));
269         close(devfd);
270
271         return r;
272 }
273
274 int get_device_infos(const char *device, struct device_infos *infos, struct crypt_device *cd)
275 {
276         uint64_t size;
277         unsigned long size_small;
278         int readonly = 0;
279         int ret = -1;
280         int fd;
281
282         /* Try to open read-write to check whether it is a read-only device */
283         fd = open(device, O_RDWR);
284         if (fd < 0) {
285                 if (errno == EROFS) {
286                         readonly = 1;
287                         fd = open(device, O_RDONLY);
288                 }
289         } else {
290                 close(fd);
291                 fd = open(device, O_RDONLY);
292         }
293         if (fd < 0) {
294                 log_err(cd, _("Cannot open device: %s\n"), device);
295                 return -1;
296         }
297
298 #ifdef BLKROGET
299         /* If the device can be opened read-write, i.e. readonly is still 0, then
300          * check whether BKROGET says that it is read-only. E.g. read-only loop
301          * devices may be openend read-write but are read-only according to BLKROGET
302          */
303         if (readonly == 0 && ioctl(fd, BLKROGET, &readonly) < 0) {
304                 log_err(cd, _("BLKROGET failed on device %s.\n"), device);
305                 goto out;
306         }
307 #else
308 #error BLKROGET not available
309 #endif
310
311 #ifdef BLKGETSIZE64
312         if (ioctl(fd, BLKGETSIZE64, &size) >= 0) {
313                 size >>= SECTOR_SHIFT;
314                 ret = 0;
315                 goto out;
316         }
317 #endif
318
319 #ifdef BLKGETSIZE
320         if (ioctl(fd, BLKGETSIZE, &size_small) >= 0) {
321                 size = (uint64_t)size_small;
322                 ret = 0;
323                 goto out;
324         }
325 #else
326 #       error Need at least the BLKGETSIZE ioctl!
327 #endif
328
329         log_err(cd, _("BLKGETSIZE failed on device %s.\n"), device);
330 out:
331         if (ret == 0) {
332                 infos->size = size;
333                 infos->readonly = readonly;
334         }
335         close(fd);
336         return ret;
337 }
338
339 int wipe_device_header(const char *device, int sectors)
340 {
341         char *buffer;
342         int size = sectors * SECTOR_SIZE;
343         int r = -1;
344         int devfd;
345
346         devfd = open(device, O_RDWR | O_DIRECT | O_SYNC);
347         if(devfd == -1)
348                 return -EINVAL;
349
350         buffer = malloc(size);
351         if (!buffer) {
352                 close(devfd);
353                 return -ENOMEM;
354         }
355         memset(buffer, 0, size);
356
357         r = write_blockwise(devfd, buffer, size) < size ? -EIO : 0;
358
359         free(buffer);
360         close(devfd);
361
362         return r;
363 }
364
365 /* MEMLOCK */
366 #define DEFAULT_PROCESS_PRIORITY -18
367
368 static int _priority;
369 static int _memlock_count = 0;
370
371 // return 1 if memory is locked
372 int crypt_memlock_inc(struct crypt_device *ctx)
373 {
374         if (!_memlock_count++) {
375                 log_dbg("Locking memory.");
376                 if (mlockall(MCL_CURRENT | MCL_FUTURE)) {
377                         log_err(ctx, _("WARNING!!! Possibly insecure memory. Are you root?\n"));
378                         _memlock_count--;
379                         return 0;
380                 }
381                 errno = 0;
382                 if (((_priority = getpriority(PRIO_PROCESS, 0)) == -1) && errno)
383                         log_err(ctx, _("Cannot get process priority.\n"));
384                 else
385                         if (setpriority(PRIO_PROCESS, 0, DEFAULT_PROCESS_PRIORITY))
386                                 log_err(ctx, _("setpriority %u failed: %s"),
387                                         DEFAULT_PROCESS_PRIORITY, strerror(errno));
388         }
389         return _memlock_count ? 1 : 0;
390 }
391
392 int crypt_memlock_dec(struct crypt_device *ctx)
393 {
394         if (_memlock_count && (!--_memlock_count)) {
395                 log_dbg("Unlocking memory.");
396                 if (munlockall())
397                         log_err(ctx, _("Cannot unlock memory."));
398                 if (setpriority(PRIO_PROCESS, 0, _priority))
399                         log_err(ctx, _("setpriority %u failed: %s"), _priority, strerror(errno));
400         }
401         return _memlock_count ? 1 : 0;
402 }
403
404 /* DEVICE TOPOLOGY */
405
406 /* block device topology ioctls, introduced in 2.6.32 */
407 #ifndef BLKIOMIN
408 #define BLKIOMIN    _IO(0x12,120)
409 #define BLKIOOPT    _IO(0x12,121)
410 #define BLKALIGNOFF _IO(0x12,122)
411 #endif
412
413 void get_topology_alignment(const char *device,
414                             unsigned long *required_alignment, /* bytes */
415                             unsigned long *alignment_offset,   /* bytes */
416                             unsigned long default_alignment)
417 {
418         int dev_alignment_offset = 0;
419         unsigned int min_io_size = 0, opt_io_size = 0;
420         unsigned long temp_alignment = 0;
421         int fd;
422
423         *required_alignment = default_alignment;
424         *alignment_offset = 0;
425
426         fd = open(device, O_RDONLY);
427         if (fd == -1)
428                 return;
429
430         /* minimum io size */
431         if (ioctl(fd, BLKIOMIN, &min_io_size) == -1) {
432                 log_dbg("Topology info for %s not supported, using default offset %lu bytes.",
433                         device, default_alignment);
434                 goto out;
435         }
436
437         /* optimal io size */
438         if (ioctl(fd, BLKIOOPT, &opt_io_size) == -1)
439                 opt_io_size = min_io_size;
440
441         /* alignment offset, bogus -1 means misaligned/unknown */
442         if (ioctl(fd, BLKALIGNOFF, &dev_alignment_offset) == -1 || dev_alignment_offset < 0)
443                 dev_alignment_offset = 0;
444         *alignment_offset = (unsigned long)dev_alignment_offset;
445
446         temp_alignment = (unsigned long)min_io_size;
447
448         if (temp_alignment < (unsigned long)opt_io_size)
449                 temp_alignment = (unsigned long)opt_io_size;
450
451         /* If calculated alignment is multiple of default, keep default */
452         if (temp_alignment && (default_alignment % temp_alignment))
453                 *required_alignment = temp_alignment;
454
455         log_dbg("Topology: IO (%u/%u), offset = %lu; Required alignment is %lu bytes.",
456                 min_io_size, opt_io_size, *alignment_offset, *required_alignment);
457 out:
458         (void)close(fd);
459 }