"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 }