Lines 1-6
Link Here
|
1 |
/* Originally from Ted's losetup.c */ |
1 |
/* Taken from Ted's losetup.c - Mitch <m.dsouza@mrc-apu.cam.ac.uk> */ |
|
|
2 |
/* Added vfs mount options - aeb - 960223 */ |
3 |
/* Removed lomount - aeb - 960224 */ |
4 |
|
5 |
/* |
6 |
* 1999-02-22 Arkadiusz Mi¶kiewicz <misiek@pld.ORG.PL> |
7 |
* - added Native Language Support |
8 |
* 1999-03-21 Arnaldo Carvalho de Melo <acme@conectiva.com.br> |
9 |
* - fixed strerr(errno) in gettext calls |
10 |
* 2001-04-11 Jari Ruusu |
11 |
* - added AES support |
12 |
*/ |
13 |
|
14 |
#define LOOPMAJOR 7 |
15 |
|
2 |
/* |
16 |
/* |
3 |
* losetup.c - setup and control loop devices |
17 |
* losetup.c - setup and control loop devices |
4 |
*/ |
18 |
*/ |
5 |
|
19 |
|
6 |
#include <stdio.h> |
20 |
#include <stdio.h> |
Lines 8-1060
Link Here
|
8 |
#include <ctype.h> |
22 |
#include <ctype.h> |
9 |
#include <fcntl.h> |
23 |
#include <fcntl.h> |
10 |
#include <errno.h> |
24 |
#include <errno.h> |
11 |
#include <stdlib.h> |
25 |
#include <stdlib.h> |
12 |
#include <unistd.h> |
26 |
#include <unistd.h> |
|
|
27 |
#include <pwd.h> |
28 |
#include <sys/types.h> |
13 |
#include <sys/ioctl.h> |
29 |
#include <sys/ioctl.h> |
14 |
#include <sys/stat.h> |
30 |
#include <sys/stat.h> |
15 |
#include <sys/mman.h> |
31 |
#include <sys/mman.h> |
16 |
#include <sys/sysmacros.h> |
32 |
#include <sys/sysmacros.h> |
17 |
#include <inttypes.h> |
33 |
#include <sys/wait.h> |
18 |
#include <dirent.h> |
34 |
#include <limits.h> |
|
|
35 |
#include <fcntl.h> |
36 |
#include <mntent.h> |
37 |
#include <locale.h> |
38 |
#include <sys/time.h> |
39 |
#include <sys/utsname.h> |
40 |
#include <signal.h> |
19 |
|
41 |
|
20 |
#include "loop.h" |
42 |
#include "loop.h" |
21 |
#include "lomount.h" |
43 |
#include "lomount.h" |
22 |
#include "xstrncpy.h" |
44 |
#include "xstrncpy.h" |
23 |
#include "nls.h" |
45 |
#include "nls.h" |
24 |
#include "sundries.h" |
46 |
#include "sha512.h" |
25 |
#include "xmalloc.h" |
47 |
#include "rmd160.h" |
26 |
#include "realpath.h" |
48 |
#include "aes.h" |
27 |
|
49 |
|
28 |
#ifndef HAVE_VERSIONSORT |
50 |
#if !defined(BLKGETSIZE64) |
29 |
# include "strverscmp.h" |
51 |
# define BLKGETSIZE64 _IOR(0x12,114,size_t) |
30 |
#endif |
52 |
#endif |
31 |
|
53 |
|
32 |
#define SIZE(a) (sizeof(a)/sizeof(a[0])) |
54 |
extern int verbose; |
|
|
55 |
extern char *xstrdup (const char *s); /* not: #include "sundries.h" */ |
56 |
extern void error (const char *fmt, ...); /* idem */ |
57 |
extern void show_all_loops(void); |
58 |
extern int read_options_from_fstab(char *, char **); |
59 |
extern int recompute_loop_dev_size(char *); |
33 |
|
60 |
|
34 |
#ifdef LOOP_SET_FD |
61 |
#if !defined(LOOP_PASSWORD_MIN_LENGTH) |
35 |
|
62 |
# define LOOP_PASSWORD_MIN_LENGTH 20 |
36 |
static int is_associated(int dev, struct stat *file, unsigned long long offset, int isoff); |
63 |
#endif |
37 |
|
64 |
|
38 |
static int |
65 |
char *passFDnumber = (char *)0; |
39 |
loop_info64_to_old(const struct loop_info64 *info64, struct loop_info *info) |
66 |
char *passAskTwice = (char *)0; |
40 |
{ |
67 |
char *passSeedString = (char *)0; |
41 |
memset(info, 0, sizeof(*info)); |
68 |
char *passHashFuncName = (char *)0; |
42 |
info->lo_number = info64->lo_number; |
69 |
char *passIterThousands = (char *)0; |
43 |
info->lo_device = info64->lo_device; |
70 |
char *loInitValue = (char *)0; |
44 |
info->lo_inode = info64->lo_inode; |
71 |
char *gpgKeyFile = (char *)0; |
45 |
info->lo_rdevice = info64->lo_rdevice; |
72 |
char *gpgHomeDir = (char *)0; |
46 |
info->lo_offset = info64->lo_offset; |
73 |
char *clearTextKeyFile = (char *)0; |
47 |
info->lo_encrypt_type = info64->lo_encrypt_type; |
74 |
char *loopOffsetBytes = (char *)0; |
48 |
info->lo_encrypt_key_size = info64->lo_encrypt_key_size; |
75 |
char *loopSizeBytes = (char *)0; |
49 |
info->lo_flags = info64->lo_flags; |
76 |
char *loopEncryptionType = (char *)0; |
50 |
info->lo_init[0] = info64->lo_init[0]; |
77 |
|
51 |
info->lo_init[1] = info64->lo_init[1]; |
78 |
static int multiKeyMode = 0; /* 0=single-key 64=multi-key-v2 65=multi-key-v3 1000=any */ |
52 |
if (info->lo_encrypt_type == LO_CRYPT_CRYPTOAPI) |
79 |
static char *multiKeyPass[66]; |
53 |
memcpy(info->lo_name, info64->lo_crypt_name, LO_NAME_SIZE); |
80 |
static char *loopFileName; |
54 |
else |
|
|
55 |
memcpy(info->lo_name, info64->lo_file_name, LO_NAME_SIZE); |
56 |
memcpy(info->lo_encrypt_key, info64->lo_encrypt_key, LO_KEY_SIZE); |
57 |
|
58 |
/* error in case values were truncated */ |
59 |
if (info->lo_device != info64->lo_device || |
60 |
info->lo_rdevice != info64->lo_rdevice || |
61 |
info->lo_inode != info64->lo_inode || |
62 |
info->lo_offset != info64->lo_offset) |
63 |
return -EOVERFLOW; |
64 |
|
65 |
return 0; |
66 |
} |
67 |
|
68 |
#define DEV_LOOP_PATH "/dev/loop" |
69 |
#define DEV_PATH "/dev" |
70 |
#define SYSFS_BLOCK_PATH "/sys/block" |
71 |
#define LOOPMAJOR 7 |
72 |
#define NLOOPS_DEFAULT 8 /* /dev/loop[0-7] */ |
73 |
|
74 |
struct looplist { |
75 |
int flag; /* scanning options */ |
76 |
int ndef; /* number of tested default devices */ |
77 |
struct dirent **names; /* scandir-like list of loop devices */ |
78 |
int nnames; /* number of items in names */ |
79 |
int ncur; /* current possition in direcotry */ |
80 |
char name[32]; /* device name */ |
81 |
int ct_perm; /* count permission problems */ |
82 |
int ct_succ; /* count number of successfully |
83 |
detected devices */ |
84 |
}; |
85 |
|
86 |
#define LLFLG_USEDONLY (1 << 1) /* return used devices only */ |
87 |
#define LLFLG_FREEONLY (1 << 2) /* return non-used devices */ |
88 |
#define LLFLG_DONE (1 << 3) /* all is done */ |
89 |
#define LLFLG_SYSFS (1 << 4) /* try to use /sys/block */ |
90 |
#define LLFLG_SUBDIR (1 << 5) /* /dev/loop/N */ |
91 |
#define LLFLG_DFLT (1 << 6) /* directly try to check default loops */ |
92 |
|
81 |
|
93 |
int |
82 |
#ifdef MAIN |
94 |
is_loop_device (const char *device) { |
83 |
static char * |
95 |
struct stat st; |
84 |
crypt_name (int id, int *flags) { |
|
|
85 |
int i; |
96 |
|
86 |
|
97 |
return (stat(device, &st) == 0 && |
87 |
for (i = 0; loop_crypt_type_tbl[i].id != -1; i++) |
98 |
S_ISBLK(st.st_mode) && |
88 |
if(id == loop_crypt_type_tbl[i].id) { |
99 |
major(st.st_rdev) == LOOPMAJOR); |
89 |
*flags = loop_crypt_type_tbl[i].flags; |
|
|
90 |
return loop_crypt_type_tbl[i].name; |
91 |
} |
92 |
*flags = 0; |
93 |
if(id == 18) |
94 |
return "CryptoAPI"; |
95 |
return "undefined"; |
100 |
} |
96 |
} |
101 |
|
97 |
|
102 |
static int |
98 |
static int |
103 |
is_loop_used(int fd) |
99 |
show_loop(char *device) { |
104 |
{ |
100 |
struct loop_info64 loopinfo; |
105 |
struct loop_info li; |
101 |
int fd; |
106 |
return ioctl (fd, LOOP_GET_STATUS, &li) == 0; |
102 |
|
|
|
103 |
if ((fd = open(device, O_RDONLY)) < 0) { |
104 |
int errsv = errno; |
105 |
fprintf(stderr, _("loop: can't open device %s: %s\n"), |
106 |
device, strerror (errsv)); |
107 |
return 2; |
108 |
} |
109 |
if (loop_get_status64_ioctl(fd, &loopinfo) < 0) { |
110 |
int errsv = errno; |
111 |
fprintf(stderr, _("loop: can't get info on device %s: %s\n"), |
112 |
device, strerror (errsv)); |
113 |
close (fd); |
114 |
return 1; |
115 |
} |
116 |
loopinfo.lo_file_name[LO_NAME_SIZE-1] = 0; |
117 |
loopinfo.lo_crypt_name[LO_NAME_SIZE-1] = 0; |
118 |
printf("%s: [%04llx]:%llu (%s)", device, (unsigned long long)loopinfo.lo_device, |
119 |
(unsigned long long)loopinfo.lo_inode, loopinfo.lo_file_name); |
120 |
if (loopinfo.lo_offset) { |
121 |
if ((long long)loopinfo.lo_offset < 0) { |
122 |
printf(_(" offset=@%llu"), -((unsigned long long)loopinfo.lo_offset)); |
123 |
} else { |
124 |
printf(_(" offset=%llu"), (unsigned long long)loopinfo.lo_offset); |
125 |
} |
126 |
} |
127 |
if (loopinfo.lo_sizelimit) |
128 |
printf(_(" sizelimit=%llu"), (unsigned long long)loopinfo.lo_sizelimit); |
129 |
if (loopinfo.lo_encrypt_type) { |
130 |
int flags; |
131 |
char *s = crypt_name (loopinfo.lo_encrypt_type, &flags); |
132 |
|
133 |
printf(_(" encryption=%s"), s); |
134 |
/* type 18 == LO_CRYPT_CRYPTOAPI */ |
135 |
if (loopinfo.lo_encrypt_type == 18) { |
136 |
printf("/%s", loopinfo.lo_crypt_name); |
137 |
} else { |
138 |
if(flags & 2) |
139 |
printf("-"); |
140 |
if(flags & 1) |
141 |
printf("%u", (unsigned int)loopinfo.lo_encrypt_key_size << 3); |
142 |
} |
143 |
} |
144 |
switch(loopinfo.lo_flags & 0x180000) { |
145 |
case 0x180000: |
146 |
printf(_(" multi-key-v3")); |
147 |
break; |
148 |
case 0x100000: |
149 |
printf(_(" multi-key-v2")); |
150 |
break; |
151 |
} |
152 |
/* type 2 == LO_CRYPT_DES */ |
153 |
if (loopinfo.lo_init[0] && (loopinfo.lo_encrypt_type != 2)) |
154 |
printf(_(" loinit=%llu"), (unsigned long long)loopinfo.lo_init[0]); |
155 |
if (loopinfo.lo_flags & 0x200000) |
156 |
printf(_(" read-only")); |
157 |
printf("\n"); |
158 |
close (fd); |
159 |
|
160 |
return 0; |
107 |
} |
161 |
} |
|
|
162 |
#endif |
108 |
|
163 |
|
109 |
int |
164 |
#define SIZE(a) (sizeof(a)/sizeof(a[0])) |
110 |
is_loop_autoclear(const char *device) |
|
|
111 |
{ |
112 |
struct loop_info lo; |
113 |
struct loop_info64 lo64; |
114 |
int fd, rc = 0; |
115 |
|
165 |
|
116 |
if ((fd = open(device, O_RDONLY)) < 0) |
166 |
char * |
117 |
return 0; |
167 |
find_unused_loop_device (void) { |
|
|
168 |
/* Just creating a device, say in /tmp, is probably a bad idea - |
169 |
people might have problems with backup or so. |
170 |
So, we just try /dev/loop[0-7]. */ |
171 |
char dev[20]; |
172 |
char *loop_formats[] = { "/dev/loop%d", "/dev/loop/%d" }; |
173 |
int i, j, fd, somedev = 0, someloop = 0; |
174 |
struct stat statbuf; |
118 |
|
175 |
|
119 |
if (ioctl(fd, LOOP_GET_STATUS64, &lo64) == 0) { |
176 |
for (j = 0; j < SIZE(loop_formats); j++) { |
120 |
if (lo64.lo_flags & LO_FLAGS_AUTOCLEAR) |
177 |
for(i = 0; i < 256; i++) { |
121 |
rc = 1; |
178 |
sprintf(dev, loop_formats[j], i); |
122 |
|
179 |
if (stat (dev, &statbuf) == 0 && S_ISBLK(statbuf.st_mode)) { |
123 |
} else if (ioctl(fd, LOOP_GET_STATUS, &lo) == 0) { |
180 |
somedev++; |
124 |
if (lo.lo_flags & LO_FLAGS_AUTOCLEAR) |
181 |
fd = open (dev, O_RDONLY); |
125 |
rc = 1; |
182 |
if (fd >= 0) { |
|
|
183 |
if (is_unused_loop_device(fd) == 0) |
184 |
someloop++; /* in use */ |
185 |
else if (errno == ENXIO) { |
186 |
close (fd); |
187 |
return xstrdup(dev);/* probably free */ |
188 |
} |
189 |
close (fd); |
190 |
} |
191 |
continue;/* continue trying as long as devices exist */ |
192 |
} |
193 |
break; |
194 |
} |
126 |
} |
195 |
} |
127 |
|
196 |
|
128 |
close(fd); |
197 |
if (!somedev) |
129 |
return rc; |
198 |
error(_("mount: could not find any device /dev/loop#")); |
130 |
} |
199 |
else if (!someloop) |
131 |
|
200 |
error(_("mount: Could not find any loop device. Maybe this kernel does not know\n" |
132 |
static char * |
201 |
" about the loop device? (If so, recompile or `modprobe loop'.)")); |
133 |
looplist_mk_devname(struct looplist *ll, int num) |
|
|
134 |
{ |
135 |
if (ll->flag & LLFLG_SUBDIR) |
136 |
snprintf(ll->name, sizeof(ll->name), |
137 |
DEV_LOOP_PATH "/%d", num); |
138 |
else |
202 |
else |
139 |
snprintf(ll->name, sizeof(ll->name), |
203 |
error(_("mount: could not find any free loop device")); |
140 |
DEV_PATH "/loop%d", num); |
204 |
return 0; |
141 |
|
|
|
142 |
return is_loop_device(ll->name) ? ll->name : NULL; |
143 |
} |
205 |
} |
144 |
|
206 |
|
145 |
/* ignores all non-loop devices, default loop devices */ |
207 |
#if !defined(MAIN) |
146 |
static int |
208 |
int is_loop_active(const char *dev, const char *backdev) |
147 |
filter_loop(const struct dirent *d) |
|
|
148 |
{ |
209 |
{ |
149 |
return strncmp(d->d_name, "loop", 4) == 0; |
210 |
int fd; |
|
|
211 |
int ret = 0; |
212 |
struct stat statbuf; |
213 |
struct loop_info64 loopinfo; |
214 |
if (stat (dev, &statbuf) == 0 && S_ISBLK(statbuf.st_mode)) { |
215 |
fd = open (dev, O_RDONLY); |
216 |
if (fd < 0) |
217 |
return 0; |
218 |
if ((loop_get_status64_ioctl(fd, &loopinfo) == 0) |
219 |
&& (stat (backdev, &statbuf) == 0) |
220 |
&& (statbuf.st_dev == loopinfo.lo_device) |
221 |
&& (statbuf.st_ino == loopinfo.lo_inode)) |
222 |
ret = 1; /* backing device matches */ |
223 |
memset(&loopinfo, 0, sizeof(loopinfo)); |
224 |
close(fd); |
225 |
} |
226 |
return ret; |
150 |
} |
227 |
} |
|
|
228 |
#endif |
151 |
|
229 |
|
152 |
/* all loops exclude default loops */ |
230 |
static int rd_wr_retry(int fd, char *buf, int cnt, int w) |
153 |
static int |
|
|
154 |
filter_loop_ndflt(const struct dirent *d) |
155 |
{ |
231 |
{ |
156 |
int mn; |
232 |
int x, y, z; |
157 |
|
233 |
|
158 |
if (strncmp(d->d_name, "loop", 4) == 0 && |
234 |
x = 0; |
159 |
sscanf(d->d_name, "loop%d", &mn) == 1 && |
235 |
while(x < cnt) { |
160 |
mn >= NLOOPS_DEFAULT) |
236 |
y = cnt - x; |
161 |
return 1; |
237 |
if(w) { |
162 |
return 0; |
238 |
z = write(fd, buf + x, y); |
|
|
239 |
} else { |
240 |
z = read(fd, buf + x, y); |
241 |
if (!z) return x; |
242 |
} |
243 |
if(z < 0) { |
244 |
if ((errno == EAGAIN) || (errno == ENOMEM) || (errno == ERESTART) || (errno == EINTR)) { |
245 |
continue; |
246 |
} |
247 |
return x; |
248 |
} |
249 |
x += z; |
250 |
} |
251 |
return x; |
163 |
} |
252 |
} |
164 |
|
253 |
|
165 |
static int |
254 |
static char *get_FD_pass(int fd) |
166 |
filter_loop_num(const struct dirent *d) |
|
|
167 |
{ |
255 |
{ |
168 |
char *end = NULL; |
256 |
char *p = NULL, *n; |
169 |
int mn = strtol(d->d_name, &end, 10); |
257 |
int x = 0, y = 0; |
170 |
|
258 |
|
171 |
if (mn >= NLOOPS_DEFAULT && end && *end == '\0') |
259 |
do { |
172 |
return 1; |
260 |
if(y >= (x - 1)) { |
173 |
return 0; |
261 |
x += 128; |
|
|
262 |
/* Must enforce some max limit here -- this code */ |
263 |
/* runs as part of mount, and mount is setuid root */ |
264 |
/* and has used mlockall(MCL_CURRENT | MCL_FUTURE) */ |
265 |
if(x > (4*1024)) return(NULL); |
266 |
n = malloc(x); |
267 |
if(!n) return(NULL); |
268 |
if(p) { |
269 |
memcpy(n, p, y); |
270 |
memset(p, 0, y); |
271 |
free(p); |
272 |
} |
273 |
p = n; |
274 |
} |
275 |
if(rd_wr_retry(fd, p + y, 1, 0) != 1) break; |
276 |
if((p[y] == '\n') || !p[y]) break; |
277 |
y++; |
278 |
} while(1); |
279 |
if(p) p[y] = 0; |
280 |
return p; |
174 |
} |
281 |
} |
175 |
|
282 |
|
176 |
static int |
283 |
static unsigned long long mystrtoull(char *s, int acceptAT) |
177 |
looplist_open(struct looplist *ll, int flag) |
|
|
178 |
{ |
284 |
{ |
179 |
struct stat st; |
285 |
unsigned long long v = 0; |
|
|
286 |
int negative = 0; |
180 |
|
287 |
|
181 |
memset(ll, 0, sizeof(*ll)); |
288 |
while ((*s == ' ') || (*s == '\t')) |
182 |
ll->flag = flag; |
289 |
s++; |
183 |
ll->ndef = -1; |
290 |
if (acceptAT && (*s == '@')) { |
184 |
ll->ncur = -1; |
291 |
s++; |
185 |
|
292 |
negative = 1; |
186 |
if (stat(DEV_PATH, &st) == -1 || (!S_ISDIR(st.st_mode))) |
293 |
} |
187 |
return -1; /* /dev doesn't exist */ |
294 |
if (*s == '0') { |
188 |
|
295 |
s++; |
189 |
if (stat(DEV_LOOP_PATH, &st) == 0 && S_ISDIR(st.st_mode)) |
296 |
if ((*s == 'x') || (*s == 'X')) { |
190 |
ll->flag |= LLFLG_SUBDIR; /* /dev/loop/ exists */ |
297 |
s++; |
191 |
|
298 |
sscanf(s, "%llx", &v); |
192 |
if ((ll->flag & LLFLG_USEDONLY) && |
299 |
} else { |
193 |
stat(SYSFS_BLOCK_PATH, &st) == 0 && |
300 |
sscanf(s, "%llo", &v); |
194 |
S_ISDIR(st.st_mode)) |
301 |
} |
195 |
ll->flag |= LLFLG_SYSFS; /* try to use /sys/block/loopN */ |
302 |
} else { |
196 |
|
303 |
sscanf(s, "%llu", &v); |
197 |
ll->flag |= LLFLG_DFLT; /* required! */ |
304 |
} |
198 |
return 0; |
305 |
return negative ? -v : v; |
199 |
} |
306 |
} |
200 |
|
307 |
|
201 |
static void |
308 |
static void warnAboutBadKeyData(int x) |
202 |
looplist_close(struct looplist *ll) |
|
|
203 |
{ |
309 |
{ |
204 |
if (ll->names) { |
310 |
if((x > 1) && (x != 64) && (x != 65)) { |
205 |
for(++ll->ncur; ll->ncur < ll->nnames; ll->ncur++) |
311 |
fprintf(stderr, _("Warning: Unknown key data format - using it anyway\n")); |
206 |
free(ll->names[ll->ncur]); |
|
|
207 |
|
208 |
free(ll->names); |
209 |
ll->names = NULL; |
210 |
ll->nnames = 0; |
211 |
} |
312 |
} |
212 |
ll->ncur = -1; |
|
|
213 |
ll->flag |= LLFLG_DONE; |
214 |
} |
313 |
} |
215 |
|
314 |
|
216 |
static int |
315 |
static int are_these_files_same(const char *name1, const char *name2) |
217 |
looplist_is_wanted(struct looplist *ll, int fd) |
|
|
218 |
{ |
316 |
{ |
219 |
int ret; |
317 |
struct stat statbuf1; |
220 |
|
318 |
struct stat statbuf2; |
221 |
if (!(ll->flag & (LLFLG_USEDONLY | LLFLG_FREEONLY))) |
|
|
222 |
return 1; |
223 |
ret = is_loop_used(fd); |
224 |
|
319 |
|
225 |
if ((ll->flag & LLFLG_USEDONLY) && ret == 0) |
320 |
if(!name1 || !*name1 || !name2 || !*name2) return 0; |
226 |
return 0; |
321 |
if(stat(name1, &statbuf1)) return 0; |
227 |
if ((ll->flag & LLFLG_FREEONLY) && ret == 1) |
322 |
if(stat(name2, &statbuf2)) return 0; |
228 |
return 0; |
323 |
if(statbuf1.st_dev != statbuf2.st_dev) return 0; |
229 |
|
324 |
if(statbuf1.st_ino != statbuf2.st_ino) return 0; |
230 |
return 1; |
325 |
return 1; /* are same */ |
231 |
} |
326 |
} |
232 |
|
327 |
|
233 |
static int |
328 |
static char *do_GPG_pipe(char *pass) |
234 |
looplist_next(struct looplist *ll) |
|
|
235 |
{ |
329 |
{ |
236 |
int fd; |
330 |
int x, pfdi[2], pfdo[2]; |
237 |
int ret; |
331 |
char str[10], *a[16], *e[2], *h; |
238 |
char *dirname, *dev; |
332 |
pid_t gpid; |
239 |
|
333 |
struct passwd *p; |
240 |
if (ll->flag & LLFLG_DONE) |
334 |
void *oldSigPipeHandler; |
241 |
return -1; |
|
|
242 |
|
335 |
|
243 |
/* A) try to use /sys/block/loopN devices (for losetup -a only) |
336 |
if((getuid() == 0) && gpgHomeDir && gpgHomeDir[0]) { |
244 |
*/ |
337 |
h = gpgHomeDir; |
245 |
if (ll->flag & LLFLG_SYSFS) { |
338 |
} else { |
246 |
int mn; |
339 |
if(!(p = getpwuid(getuid()))) { |
247 |
|
340 |
fprintf(stderr, _("Error: Unable to detect home directory for uid %d\n"), (int)getuid()); |
248 |
if (!ll->nnames) { |
341 |
return NULL; |
249 |
ll->nnames = scandir(SYSFS_BLOCK_PATH, &ll->names, |
|
|
250 |
filter_loop, versionsort); |
251 |
ll->ncur = -1; |
252 |
} |
253 |
for(++ll->ncur; ll->ncur < ll->nnames; ll->ncur++) { |
254 |
ret = sscanf(ll->names[ll->ncur]->d_name, "loop%d", &mn); |
255 |
free(ll->names[ll->ncur]); |
256 |
if (ret != 1) |
257 |
continue; |
258 |
dev = looplist_mk_devname(ll, mn); |
259 |
if (dev) { |
260 |
ll->ct_succ++; |
261 |
if ((fd = open(dev, O_RDONLY)) > -1) { |
262 |
if (looplist_is_wanted(ll, fd)) |
263 |
return fd; |
264 |
close(fd); |
265 |
} else if (errno == EACCES) |
266 |
ll->ct_perm++; |
267 |
} |
268 |
} |
342 |
} |
269 |
if (ll->nnames) |
343 |
h = p->pw_dir; |
270 |
free(ll->names); |
|
|
271 |
ll->names = NULL; |
272 |
ll->ncur = -1; |
273 |
ll->nnames = 0; |
274 |
ll->flag &= ~LLFLG_SYSFS; |
275 |
goto done; |
276 |
} |
344 |
} |
277 |
|
345 |
if(!(e[0] = malloc(strlen(h) + 6))) { |
278 |
/* B) Classic way, try first eight loop devices (default number |
346 |
nomem1: |
279 |
* of loop devices). This is enough for 99% of all cases. |
347 |
fprintf(stderr, _("Error: Unable to allocate memory\n")); |
280 |
*/ |
348 |
return NULL; |
281 |
if (ll->flag & LLFLG_DFLT) { |
|
|
282 |
for (++ll->ncur; ll->ncur < NLOOPS_DEFAULT; ll->ncur++) { |
283 |
dev = looplist_mk_devname(ll, ll->ncur); |
284 |
if (dev) { |
285 |
ll->ct_succ++; |
286 |
if ((fd = open(dev, O_RDONLY)) > -1) { |
287 |
if (looplist_is_wanted(ll, fd)) |
288 |
return fd; |
289 |
close(fd); |
290 |
} else if (errno == EACCES) |
291 |
ll->ct_perm++; |
292 |
} |
293 |
} |
294 |
ll->flag &= ~LLFLG_DFLT; |
295 |
ll->ncur = -1; |
296 |
} |
349 |
} |
|
|
350 |
sprintf(e[0], "HOME=%s", h); |
351 |
e[1] = 0; |
297 |
|
352 |
|
|
|
353 |
if(pipe(&pfdi[0])) { |
354 |
nomem2: |
355 |
free(e[0]); |
356 |
goto nomem1; |
357 |
} |
358 |
if(pipe(&pfdo[0])) { |
359 |
close(pfdi[0]); |
360 |
close(pfdi[1]); |
361 |
goto nomem2; |
362 |
} |
298 |
|
363 |
|
299 |
/* C) the worst posibility, scan all /dev or /dev/loop |
364 |
/* |
|
|
365 |
* When this code is run as part of losetup, normal read permissions |
366 |
* affect the open() below because losetup is not setuid-root. |
367 |
* |
368 |
* When this code is run as part of mount, only root can set |
369 |
* 'gpgKeyFile' and as such, only root can decide what file is opened |
370 |
* below. However, since mount is usually setuid-root all non-root |
371 |
* users can also open() the file too, but that file's contents are |
372 |
* only piped to gpg. This readable-for-all is intended behaviour, |
373 |
* and is very useful in situations where non-root users mount loop |
374 |
* devices with their own gpg private key, and yet don't have access |
375 |
* to the actual key used to encrypt loop device. |
300 |
*/ |
376 |
*/ |
301 |
dirname = ll->flag & LLFLG_SUBDIR ? DEV_LOOP_PATH : DEV_PATH; |
377 |
if((x = open(gpgKeyFile, O_RDONLY)) == -1) { |
|
|
378 |
fprintf(stderr, _("Error: unable to open %s for reading\n"), gpgKeyFile); |
379 |
nomem3: |
380 |
free(e[0]); |
381 |
close(pfdo[0]); |
382 |
close(pfdo[1]); |
383 |
close(pfdi[0]); |
384 |
close(pfdi[1]); |
385 |
return NULL; |
386 |
} |
302 |
|
387 |
|
303 |
if (!ll->nnames) { |
388 |
/* |
304 |
ll->nnames = scandir(dirname, &ll->names, |
389 |
* If someone puts a gpg key file at beginning of device and |
305 |
ll->flag & LLFLG_SUBDIR ? |
390 |
* puts the real file system at some offset into the device, |
306 |
filter_loop_num : filter_loop_ndflt, |
391 |
* this code extracts that gpg key file into a temp file so gpg |
307 |
versionsort); |
392 |
* won't end up reading whole device when decrypting the key file. |
308 |
ll->ncur = -1; |
393 |
* |
309 |
} |
394 |
* Example of encrypted cdrom mount with 8192 bytes reserved for gpg key file: |
310 |
|
395 |
* mount -t iso9660 /dev/cdrom /cdrom -o loop=/dev/loop0,encryption=AES128,gpgkey=/dev/cdrom,offset=8192 |
311 |
for(++ll->ncur; ll->ncur < ll->nnames; ll->ncur++) { |
396 |
* ^^^^^^^^^^ ^^^^^^^^^^ ^^^^ |
312 |
struct stat st; |
397 |
*/ |
313 |
|
398 |
if(loopOffsetBytes && are_these_files_same(loopFileName, gpgKeyFile)) { |
314 |
snprintf(ll->name, sizeof(ll->name), |
399 |
FILE *f; |
315 |
"%s/%s", dirname, ll->names[ll->ncur]->d_name); |
400 |
char b[1024]; |
316 |
free(ll->names[ll->ncur]); |
401 |
long long cnt; |
317 |
ret = stat(ll->name, &st); |
402 |
int cnt2, cnt3; |
318 |
|
403 |
|
319 |
if (ret == 0 && S_ISBLK(st.st_mode) && |
404 |
cnt = mystrtoull(loopOffsetBytes, 1); |
320 |
major(st.st_rdev) == LOOPMAJOR) { |
405 |
if(cnt < 0) cnt = -cnt; |
321 |
ll->ct_succ++; |
406 |
if(cnt > (1024 * 1024)) cnt = 1024 * 1024; /* sanity check */ |
322 |
fd = open(ll->name, O_RDONLY); |
407 |
f = tmpfile(); |
323 |
|
408 |
if(!f) { |
324 |
if (fd != -1) { |
409 |
fprintf(stderr, _("Error: unable to create temp file\n")); |
325 |
if (looplist_is_wanted(ll, fd)) |
410 |
close(x); |
326 |
return fd; |
411 |
goto nomem3; |
327 |
close(fd); |
412 |
} |
328 |
} else if (errno == EACCES) |
413 |
while(cnt > 0) { |
329 |
ll->ct_perm++; |
414 |
cnt2 = sizeof(b); |
|
|
415 |
if(cnt < cnt2) cnt2 = cnt; |
416 |
cnt3 = rd_wr_retry(x, b, cnt2, 0); |
417 |
if(cnt3 && (fwrite(b, cnt3, 1, f) != 1)) { |
418 |
tmpWrErr: |
419 |
fprintf(stderr, _("Error: unable to write to temp file\n")); |
420 |
fclose(f); |
421 |
close(x); |
422 |
goto nomem3; |
423 |
} |
424 |
if(cnt2 != cnt3) break; |
425 |
cnt -= cnt3; |
426 |
} |
427 |
if(fflush(f)) goto tmpWrErr; |
428 |
close(x); |
429 |
x = dup(fileno(f)); |
430 |
fclose(f); |
431 |
lseek(x, 0L, SEEK_SET); |
432 |
} |
433 |
|
434 |
sprintf(str, "%d", pfdi[0]); |
435 |
if(!(gpid = fork())) { |
436 |
dup2(x, 0); |
437 |
dup2(pfdo[1], 1); |
438 |
close(x); |
439 |
close(pfdi[1]); |
440 |
close(pfdo[0]); |
441 |
close(pfdo[1]); |
442 |
if((x = open("/dev/null", O_WRONLY)) >= 0) { |
443 |
dup2(x, 2); |
444 |
close(x); |
445 |
} |
446 |
x = 0; |
447 |
a[x++] = "gpg"; |
448 |
if(gpgHomeDir && gpgHomeDir[0]) { |
449 |
a[x++] = "--homedir"; |
450 |
a[x++] = gpgHomeDir; |
451 |
} |
452 |
a[x++] = "--no-options"; |
453 |
a[x++] = "--quiet"; |
454 |
a[x++] = "--batch"; |
455 |
a[x++] = "--no-tty"; |
456 |
a[x++] = "--passphrase-fd"; |
457 |
a[x++] = str; |
458 |
a[x++] = "--decrypt"; |
459 |
a[x] = 0; |
460 |
if(setgid(getgid())) exit(1); |
461 |
if(setuid(getuid())) exit(1); |
462 |
for(x = 3; x < 1024; x++) { |
463 |
if(x == pfdi[0]) continue; |
464 |
close(x); |
465 |
} |
466 |
execve("/bin/gpg", &a[0], &e[0]); |
467 |
execve("/usr/bin/gpg", &a[0], &e[0]); |
468 |
execve("/usr/local/bin/gpg", &a[0], &e[0]); |
469 |
exit(1); |
470 |
} |
471 |
free(e[0]); |
472 |
close(x); |
473 |
close(pfdi[0]); |
474 |
close(pfdo[1]); |
475 |
if(gpid == -1) { |
476 |
close(pfdi[1]); |
477 |
close(pfdo[0]); |
478 |
goto nomem1; |
479 |
} |
480 |
|
481 |
x = strlen(pass); |
482 |
|
483 |
/* ignore possible SIGPIPE signal while writing to gpg */ |
484 |
oldSigPipeHandler = signal(SIGPIPE, SIG_IGN); |
485 |
rd_wr_retry(pfdi[1], pass, x, 1); |
486 |
rd_wr_retry(pfdi[1], "\n", 1, 1); |
487 |
if(oldSigPipeHandler != SIG_ERR) signal(SIGPIPE, oldSigPipeHandler); |
488 |
|
489 |
close(pfdi[1]); |
490 |
memset(pass, 0, x); |
491 |
x = 0; |
492 |
while(x < 66) { |
493 |
multiKeyPass[x] = get_FD_pass(pfdo[0]); |
494 |
if(!multiKeyPass[x]) { |
495 |
/* mem alloc failed - abort */ |
496 |
multiKeyPass[0] = 0; |
497 |
break; |
330 |
} |
498 |
} |
|
|
499 |
if(strlen(multiKeyPass[x]) < LOOP_PASSWORD_MIN_LENGTH) break; |
500 |
x++; |
331 |
} |
501 |
} |
332 |
done: |
502 |
warnAboutBadKeyData(x); |
333 |
looplist_close(ll); |
503 |
if(x >= 65) |
334 |
return -1; |
504 |
multiKeyMode = 65; |
|
|
505 |
if(x == 64) |
506 |
multiKeyMode = 64; |
507 |
close(pfdo[0]); |
508 |
waitpid(gpid, &x, 0); |
509 |
if(!multiKeyPass[0]) goto nomem1; |
510 |
return multiKeyPass[0]; |
335 |
} |
511 |
} |
336 |
|
512 |
|
337 |
#ifdef MAIN |
513 |
static char *sGetPass(int minLen, int warnLen) |
338 |
|
514 |
{ |
339 |
static int |
515 |
char *p, *s, *seed; |
340 |
show_loop_fd(int fd, char *device) { |
516 |
int i, ask2, close_i_fd = 0; |
341 |
struct loop_info loopinfo; |
|
|
342 |
struct loop_info64 loopinfo64; |
343 |
int errsv; |
344 |
|
345 |
if (ioctl(fd, LOOP_GET_STATUS64, &loopinfo64) == 0) { |
346 |
|
347 |
loopinfo64.lo_file_name[LO_NAME_SIZE-2] = '*'; |
348 |
loopinfo64.lo_file_name[LO_NAME_SIZE-1] = 0; |
349 |
loopinfo64.lo_crypt_name[LO_NAME_SIZE-1] = 0; |
350 |
|
351 |
printf("%s: [%04" PRIx64 "]:%" PRIu64 " (%s)", |
352 |
device, loopinfo64.lo_device, loopinfo64.lo_inode, |
353 |
loopinfo64.lo_file_name); |
354 |
|
355 |
if (loopinfo64.lo_offset) |
356 |
printf(_(", offset %" PRIu64 ), loopinfo64.lo_offset); |
357 |
|
358 |
if (loopinfo64.lo_sizelimit) |
359 |
printf(_(", sizelimit %" PRIu64 ), loopinfo64.lo_sizelimit); |
360 |
|
361 |
if (loopinfo64.lo_encrypt_type || |
362 |
loopinfo64.lo_crypt_name[0]) { |
363 |
char *e = (char *)loopinfo64.lo_crypt_name; |
364 |
|
517 |
|
365 |
if (*e == 0 && loopinfo64.lo_encrypt_type == 1) |
518 |
if(!passFDnumber) { |
366 |
e = "XOR"; |
519 |
if(clearTextKeyFile) { |
367 |
printf(_(", encryption %s (type %" PRIu32 ")"), |
520 |
if((i = open(clearTextKeyFile, O_RDONLY)) == -1) { |
368 |
e, loopinfo64.lo_encrypt_type); |
521 |
fprintf(stderr, _("Error: unable to open %s for reading\n"), clearTextKeyFile); |
|
|
522 |
return NULL; |
523 |
} |
524 |
close_i_fd = 1; |
525 |
goto contReadFrom_i; |
369 |
} |
526 |
} |
370 |
printf("\n"); |
527 |
p = getpass(_("Password: ")); |
371 |
return 0; |
528 |
ask2 = passAskTwice ? 1 : 0; |
|
|
529 |
} else { |
530 |
i = atoi(passFDnumber); |
531 |
contReadFrom_i: |
532 |
if(gpgKeyFile && gpgKeyFile[0]) { |
533 |
p = get_FD_pass(i); |
534 |
if(close_i_fd) close(i); |
535 |
} else { |
536 |
int x = 0; |
537 |
while(x < 66) { |
538 |
multiKeyPass[x] = get_FD_pass(i); |
539 |
if(!multiKeyPass[x]) goto nomem; |
540 |
if(strlen(multiKeyPass[x]) < LOOP_PASSWORD_MIN_LENGTH) break; |
541 |
x++; |
542 |
} |
543 |
if(close_i_fd) close(i); |
544 |
warnAboutBadKeyData(x); |
545 |
if(x >= 65) { |
546 |
multiKeyMode = 65; |
547 |
return multiKeyPass[0]; |
548 |
} |
549 |
if(x == 64) { |
550 |
multiKeyMode = 64; |
551 |
return multiKeyPass[0]; |
552 |
} |
553 |
p = multiKeyPass[0]; |
554 |
} |
555 |
ask2 = 0; |
372 |
} |
556 |
} |
373 |
|
557 |
if(!p) goto nomem; |
374 |
if (ioctl(fd, LOOP_GET_STATUS, &loopinfo) == 0) { |
558 |
if(gpgKeyFile && gpgKeyFile[0]) { |
375 |
printf ("%s: [%04x]:%ld (%s)", |
559 |
if(ask2) { |
376 |
device, (unsigned int)loopinfo.lo_device, loopinfo.lo_inode, |
560 |
i = strlen(p); |
377 |
loopinfo.lo_name); |
561 |
s = malloc(i + 1); |
378 |
|
562 |
if(!s) goto nomem; |
379 |
if (loopinfo.lo_offset) |
563 |
strcpy(s, p); |
380 |
printf(_(", offset %d"), loopinfo.lo_offset); |
564 |
p = getpass(_("Retype password: ")); |
381 |
|
565 |
if(!p) goto nomem; |
382 |
if (loopinfo.lo_encrypt_type) |
566 |
if(strcmp(s, p)) goto compareErr; |
383 |
printf(_(", encryption type %d\n"), |
567 |
memset(s, 0, i); |
384 |
loopinfo.lo_encrypt_type); |
568 |
free(s); |
385 |
|
569 |
ask2 = 0; |
386 |
printf("\n"); |
570 |
} |
387 |
return 0; |
571 |
p = do_GPG_pipe(p); |
|
|
572 |
if(!p) return(NULL); |
573 |
if(!p[0]) { |
574 |
fprintf(stderr, _("Error: gpg key file decryption failed\n")); |
575 |
return(NULL); |
576 |
} |
577 |
if(multiKeyMode) return(p); |
388 |
} |
578 |
} |
389 |
|
579 |
i = strlen(p); |
390 |
errsv = errno; |
580 |
if(i < minLen) { |
391 |
fprintf(stderr, _("loop: can't get info on device %s: %s\n"), |
581 |
fprintf(stderr, _("Error: Password must be at least %d characters.\n"), minLen); |
392 |
device, strerror (errsv)); |
582 |
return(NULL); |
393 |
return 1; |
583 |
} |
|
|
584 |
seed = passSeedString; |
585 |
if(!seed) seed = ""; |
586 |
s = malloc(i + strlen(seed) + 1); |
587 |
if(!s) { |
588 |
nomem: |
589 |
fprintf(stderr, _("Error: Unable to allocate memory\n")); |
590 |
return(NULL); |
591 |
} |
592 |
strcpy(s, p); |
593 |
memset(p, 0, i); |
594 |
if(ask2) { |
595 |
p = getpass(_("Retype password: ")); |
596 |
if(!p) goto nomem; |
597 |
if(strcmp(s, p)) { |
598 |
compareErr: |
599 |
fprintf(stderr, _("Error: Passwords are not identical\n")); |
600 |
return(NULL); |
601 |
} |
602 |
memset(p, 0, i); |
603 |
} |
604 |
if(i < warnLen) { |
605 |
fprintf(stderr, _("WARNING - Please use longer password (%d or more characters)\n"), LOOP_PASSWORD_MIN_LENGTH); |
606 |
} |
607 |
strcat(s, seed); |
608 |
return(s); |
394 |
} |
609 |
} |
395 |
|
610 |
|
396 |
static int |
611 |
/* this is for compatibility with historic loop-AES version */ |
397 |
show_loop(char *device) { |
612 |
static void unhashed1_key_setup(unsigned char *keyStr, int ile, unsigned char *keyBuf, int bufSize) |
398 |
int ret, fd; |
613 |
{ |
|
|
614 |
register int x, y, z, cnt = ile; |
615 |
unsigned char *kp; |
399 |
|
616 |
|
400 |
if ((fd = open(device, O_RDONLY)) < 0) { |
617 |
memset(keyBuf, 0, bufSize); |
401 |
int errsv = errno; |
618 |
kp = keyStr; |
402 |
fprintf(stderr, _("loop: can't open device %s: %s\n"), |
619 |
for(x = 0; x < (bufSize * 8); x += 6) { |
403 |
device, strerror (errsv)); |
620 |
y = *kp++; |
404 |
return 2; |
621 |
if(--cnt <= 0) { |
|
|
622 |
kp = keyStr; |
623 |
cnt = ile; |
624 |
} |
625 |
if((y >= '0') && (y <= '9')) y -= '0'; |
626 |
else if((y >= 'A') && (y <= 'Z')) y -= ('A' - 10); |
627 |
else if((y >= 'a') && (y <= 'z')) y -= ('a' - 36); |
628 |
else if((y == '.') || (y == '/')) y += (62 - '.'); |
629 |
else y &= 63; |
630 |
z = x >> 3; |
631 |
if(z < bufSize) { |
632 |
keyBuf[z] |= y << (x & 7); |
633 |
} |
634 |
z++; |
635 |
if(z < bufSize) { |
636 |
keyBuf[z] |= y >> (8 - (x & 7)); |
637 |
} |
405 |
} |
638 |
} |
406 |
ret = show_loop_fd(fd, device); |
|
|
407 |
close(fd); |
408 |
return ret; |
409 |
} |
639 |
} |
410 |
|
640 |
|
|
|
641 |
/* this is for compatibility with mainline mount */ |
642 |
static void unhashed2_key_setup(unsigned char *keyStr, int ile, unsigned char *keyBuf, int bufSize) |
643 |
{ |
644 |
memset(keyBuf, 0, bufSize); |
645 |
strncpy((char *)keyBuf, (char *)keyStr, bufSize - 1); |
646 |
keyBuf[bufSize - 1] = 0; |
647 |
} |
411 |
|
648 |
|
412 |
static int |
649 |
static void rmd160HashTwiceWithA(unsigned char *ib, int ile, unsigned char *ob, int ole) |
413 |
show_used_loop_devices (void) { |
650 |
{ |
414 |
struct looplist ll; |
651 |
char tmpBuf[20 + 20]; |
415 |
int fd; |
652 |
char pwdCopy[130]; |
416 |
|
653 |
|
417 |
if (looplist_open(&ll, LLFLG_USEDONLY) == -1) { |
654 |
if(ole < 1) return; |
418 |
error(_("%s: /dev directory does not exist."), progname); |
655 |
memset(ob, 0, ole); |
419 |
return 1; |
656 |
if(ole > 40) ole = 40; |
420 |
} |
657 |
rmd160_hash_buffer(&tmpBuf[0], (char *)ib, ile); |
|
|
658 |
pwdCopy[0] = 'A'; |
659 |
if(ile > sizeof(pwdCopy) - 1) ile = sizeof(pwdCopy) - 1; |
660 |
memcpy(pwdCopy + 1, ib, ile); |
661 |
rmd160_hash_buffer(&tmpBuf[20], pwdCopy, ile + 1); |
662 |
memcpy(ob, tmpBuf, ole); |
663 |
memset(tmpBuf, 0, sizeof(tmpBuf)); |
664 |
memset(pwdCopy, 0, sizeof(pwdCopy)); |
665 |
} |
421 |
|
666 |
|
422 |
while((fd = looplist_next(&ll)) != -1) { |
667 |
extern long long llseek(int, long long, int); |
423 |
show_loop_fd(fd, ll.name); |
|
|
424 |
close(fd); |
425 |
} |
426 |
looplist_close(&ll); |
427 |
|
668 |
|
428 |
if (ll.ct_succ && ll.ct_perm) { |
669 |
static long long xx_lseek(int fd, long long offset, int whence) |
429 |
error(_("%s: no permission to look at /dev/loop#"), progname); |
670 |
{ |
430 |
return 1; |
671 |
if(sizeof(off_t) >= 8) { |
|
|
672 |
return lseek(fd, offset, whence); |
673 |
} else { |
674 |
return llseek(fd, offset, whence); |
431 |
} |
675 |
} |
432 |
return 0; |
|
|
433 |
} |
676 |
} |
434 |
|
677 |
|
435 |
/* list all associated loop devices */ |
678 |
static int loop_create_random_keys(char *partition, long long offset, long long sizelimit, int loopro, unsigned char *k) |
436 |
static int |
|
|
437 |
show_associated_loop_devices(char *filename, unsigned long long offset, int isoff) |
438 |
{ |
679 |
{ |
439 |
struct looplist ll; |
680 |
int x, y, fd; |
440 |
struct stat filestat; |
681 |
sha512_context s; |
441 |
int fd; |
682 |
unsigned char b[4096]; |
442 |
|
683 |
|
443 |
if (stat(filename, &filestat) == -1) { |
684 |
if(loopro) { |
444 |
perror(filename); |
685 |
fprintf(stderr, _("Error: read-only device %s\n"), partition); |
445 |
return 1; |
686 |
return 1; |
446 |
} |
687 |
} |
447 |
|
688 |
|
448 |
if (looplist_open(&ll, LLFLG_USEDONLY) == -1) { |
689 |
/* |
449 |
error(_("%s: /dev directory does not exist."), progname); |
690 |
* Compute SHA-512 over first 40 KB of old fs data. SHA-512 hash |
|
|
691 |
* output is then used as entropy for new fs encryption key. |
692 |
*/ |
693 |
if((fd = open(partition, O_RDWR)) == -1) { |
694 |
seekFailed: |
695 |
fprintf(stderr, _("Error: unable to open/seek device %s\n"), partition); |
450 |
return 1; |
696 |
return 1; |
451 |
} |
697 |
} |
452 |
|
698 |
if(offset < 0) offset = -offset; |
453 |
while((fd = looplist_next(&ll)) != -1) { |
699 |
if(xx_lseek(fd, offset, SEEK_SET) == -1) { |
454 |
if (is_associated(fd, &filestat, offset, isoff) == 1) |
|
|
455 |
show_loop_fd(fd, ll.name); |
456 |
close(fd); |
700 |
close(fd); |
|
|
701 |
goto seekFailed; |
457 |
} |
702 |
} |
458 |
looplist_close(&ll); |
703 |
sha512_init(&s); |
459 |
|
704 |
for(x = 1; x <= 10; x++) { |
460 |
return 0; |
705 |
if((sizelimit > 0) && ((sizeof(b) * x) > sizelimit)) break; |
461 |
} |
706 |
if(rd_wr_retry(fd, &b[0], sizeof(b), 0) != sizeof(b)) break; |
462 |
|
707 |
sha512_write(&s, &b[0], sizeof(b)); |
463 |
#endif /* MAIN */ |
|
|
464 |
|
465 |
/* check if the loopfile is already associated with the same given |
466 |
* parameters. |
467 |
* |
468 |
* returns: -1 error |
469 |
* 0 unused |
470 |
* 1 loop device already used |
471 |
*/ |
472 |
static int |
473 |
is_associated(int dev, struct stat *file, unsigned long long offset, int isoff) |
474 |
{ |
475 |
struct loop_info64 linfo64; |
476 |
struct loop_info64 linfo; |
477 |
int ret = 0; |
478 |
|
479 |
if (ioctl(dev, LOOP_GET_STATUS64, &linfo64) == 0) { |
480 |
if (file->st_dev == linfo64.lo_device && |
481 |
file->st_ino == linfo64.lo_inode && |
482 |
(isoff == 0 || offset == linfo64.lo_offset)) |
483 |
ret = 1; |
484 |
return ret; |
485 |
} |
486 |
if (ioctl(dev, LOOP_GET_STATUS, &linfo) == 0) { |
487 |
if (file->st_dev == linfo.lo_device && |
488 |
file->st_ino == linfo.lo_inode && |
489 |
(isoff == 0 || offset == linfo.lo_offset)) |
490 |
ret = 1; |
491 |
return ret; |
492 |
} |
493 |
|
494 |
return errno == ENXIO ? 0 : -1; |
495 |
} |
496 |
|
497 |
/* check if the loop file is already used with the same given |
498 |
* parameters. We check for device no, inode and offset. |
499 |
* returns: associated devname or NULL |
500 |
*/ |
501 |
char * |
502 |
loopfile_used (const char *filename, unsigned long long offset) { |
503 |
struct looplist ll; |
504 |
char *devname = NULL; |
505 |
struct stat filestat; |
506 |
int fd; |
507 |
|
508 |
if (stat(filename, &filestat) == -1) { |
509 |
perror(filename); |
510 |
return NULL; |
511 |
} |
512 |
|
513 |
if (looplist_open(&ll, LLFLG_USEDONLY) == -1) { |
514 |
error(_("%s: /dev directory does not exist."), progname); |
515 |
return NULL; |
516 |
} |
708 |
} |
|
|
709 |
sha512_final(&s); |
517 |
|
710 |
|
518 |
while((fd = looplist_next(&ll)) != -1) { |
711 |
/* |
519 |
int res = is_associated(fd, &filestat, offset, 1); |
712 |
* Overwrite 40 KB of old fs data 20 times so that recovering |
520 |
close(fd); |
713 |
* SHA-512 output beyond this point is difficult and expensive. |
521 |
if (res == 1) { |
714 |
*/ |
522 |
devname = xstrdup(ll.name); |
715 |
for(y = 0; y < 20; y++) { |
523 |
break; |
716 |
int z; |
|
|
717 |
struct { |
718 |
struct timeval tv; |
719 |
unsigned char h[64]; |
720 |
int x,y,z; |
721 |
} j; |
722 |
if(xx_lseek(fd, offset, SEEK_SET) == -1) break; |
723 |
memcpy(&j.h[0], &s.sha_out[0], 64); |
724 |
gettimeofday(&j.tv, NULL); |
725 |
j.y = y; |
726 |
for(x = 1; x <= 10; x++) { |
727 |
j.x = x; |
728 |
for(z = 0; z < sizeof(b); z += 64) { |
729 |
j.z = z; |
730 |
sha512_hash_buffer((unsigned char *)&j, sizeof(j), &b[z], 64); |
731 |
} |
732 |
if((sizelimit > 0) && ((sizeof(b) * x) > sizelimit)) break; |
733 |
if(rd_wr_retry(fd, &b[0], sizeof(b), 1) != sizeof(b)) break; |
524 |
} |
734 |
} |
|
|
735 |
memset(&j, 0, sizeof(j)); |
736 |
if(fsync(fd)) break; |
525 |
} |
737 |
} |
526 |
looplist_close(&ll); |
738 |
close(fd); |
527 |
|
|
|
528 |
return devname; |
529 |
} |
530 |
|
531 |
int |
532 |
loopfile_used_with(char *devname, const char *filename, unsigned long long offset) |
533 |
{ |
534 |
struct stat statbuf; |
535 |
int fd, ret; |
536 |
|
739 |
|
537 |
if (!is_loop_device(devname)) |
740 |
/* |
538 |
return 0; |
741 |
* Use all 512 bits of hash output |
|
|
742 |
*/ |
743 |
memcpy(&b[0], &s.sha_out[0], 64); |
744 |
memset(&s, 0, sizeof(s)); |
539 |
|
745 |
|
540 |
if (stat(filename, &statbuf) == -1) { |
746 |
/* |
541 |
perror(filename); |
747 |
* Read 32 bytes of random entropy from kernel's random |
542 |
return -1; |
748 |
* number generator. This code may be executed early on startup |
|
|
749 |
* scripts and amount of random entropy may be non-existent. |
750 |
* SHA-512 of old fs data is used as workaround for missing |
751 |
* entropy in kernel's random number generator. |
752 |
*/ |
753 |
if((fd = open("/dev/urandom", O_RDONLY)) == -1) { |
754 |
fprintf(stderr, _("Error: unable to open /dev/urandom\n")); |
755 |
return 1; |
543 |
} |
756 |
} |
|
|
757 |
rd_wr_retry(fd, &b[64], 32, 0); |
544 |
|
758 |
|
545 |
fd = open(devname, O_RDONLY); |
759 |
/* generate multi-key hashes */ |
546 |
if (fd == -1) { |
760 |
x = 0; |
547 |
perror(devname); |
761 |
while(x < 65) { |
548 |
return -1; |
762 |
rd_wr_retry(fd, &b[64+32], 16, 0); |
|
|
763 |
sha512_hash_buffer(&b[0], 64+32+16, k, 32); |
764 |
k += 32; |
765 |
x++; |
549 |
} |
766 |
} |
550 |
ret = is_associated(fd, &statbuf, offset, 1); |
|
|
551 |
|
767 |
|
552 |
close(fd); |
768 |
close(fd); |
553 |
return ret; |
769 |
memset(&b[0], 0, sizeof(b)); |
|
|
770 |
return 0; |
554 |
} |
771 |
} |
555 |
|
772 |
|
556 |
char * |
773 |
#if !defined(MAIN) |
557 |
find_unused_loop_device (void) { |
774 |
static int loop_fork_mkfs_command(char *device, char *fstype) |
558 |
struct looplist ll; |
775 |
{ |
559 |
char *devname = NULL; |
776 |
int x, y = 0; |
560 |
int fd; |
777 |
char *a[10], *e[1]; |
561 |
|
778 |
|
562 |
if (looplist_open(&ll, LLFLG_FREEONLY) == -1) { |
779 |
sync(); |
563 |
error(_("%s: /dev directory does not exist."), progname); |
780 |
if(!(x = fork())) { |
564 |
return NULL; |
781 |
if((x = open("/dev/null", O_WRONLY)) >= 0) { |
|
|
782 |
dup2(x, 0); |
783 |
dup2(x, 1); |
784 |
dup2(x, 2); |
785 |
close(x); |
786 |
} |
787 |
x = 0; |
788 |
a[x++] = "mkfs"; |
789 |
a[x++] = "-t"; |
790 |
a[x++] = fstype; |
791 |
/* mkfs.reiserfs and mkfs.xfs need -f option */ |
792 |
if(!strcmp(fstype, "reiserfs") || !strcmp(fstype, "xfs")) { |
793 |
a[x++] = "-f"; |
794 |
} |
795 |
a[x++] = device; |
796 |
a[x] = 0; |
797 |
e[0] = 0; |
798 |
if(setgid(getgid())) exit(1); |
799 |
if(setuid(getuid())) exit(1); |
800 |
for(x = 3; x < 1024; x++) { |
801 |
close(x); |
802 |
} |
803 |
execve("/sbin/mkfs", &a[0], &e[0]); |
804 |
exit(1); |
565 |
} |
805 |
} |
566 |
|
806 |
if(x == -1) { |
567 |
if ((fd = looplist_next(&ll)) != -1) { |
807 |
fprintf(stderr, _("Error: fork failed\n")); |
568 |
close(fd); |
808 |
return 1; |
569 |
devname = xstrdup(ll.name); |
|
|
570 |
} |
809 |
} |
571 |
looplist_close(&ll); |
810 |
waitpid(x, &y, 0); |
572 |
if (devname) |
811 |
sync(); |
573 |
return devname; |
812 |
if(!WIFEXITED(y) || (WEXITSTATUS(y) != 0)) { |
574 |
|
813 |
fprintf(stderr, _("Error: encrypted file system mkfs failed\n")); |
575 |
if (ll.ct_succ && ll.ct_perm) |
814 |
return 1; |
576 |
error(_("%s: no permission to look at /dev/loop#"), progname); |
|
|
577 |
else if (ll.ct_succ) |
578 |
error(_("%s: could not find any free loop device"), progname); |
579 |
else |
580 |
error(_( |
581 |
"%s: Could not find any loop device. Maybe this kernel " |
582 |
"does not know\n" |
583 |
" about the loop device? (If so, recompile or " |
584 |
"`modprobe loop'.)"), progname); |
585 |
return NULL; |
586 |
} |
587 |
|
588 |
/* |
589 |
* A function to read the passphrase either from the terminal or from |
590 |
* an open file descriptor. |
591 |
*/ |
592 |
static char * |
593 |
xgetpass(int pfd, const char *prompt) { |
594 |
char *pass; |
595 |
int buflen, i; |
596 |
|
597 |
if (pfd < 0) /* terminal */ |
598 |
return getpass(prompt); |
599 |
|
600 |
pass = NULL; |
601 |
buflen = 0; |
602 |
for (i=0; ; i++) { |
603 |
if (i >= buflen-1) { |
604 |
/* we're running out of space in the buffer. |
605 |
* Make it bigger: */ |
606 |
char *tmppass = pass; |
607 |
buflen += 128; |
608 |
pass = realloc(tmppass, buflen); |
609 |
if (pass == NULL) { |
610 |
/* realloc failed. Stop reading. */ |
611 |
error(_("Out of memory while reading passphrase")); |
612 |
pass = tmppass; /* the old buffer hasn't changed */ |
613 |
break; |
614 |
} |
615 |
} |
616 |
if (read(pfd, pass+i, 1) != 1 || |
617 |
pass[i] == '\n' || pass[i] == 0) |
618 |
break; |
619 |
} |
815 |
} |
620 |
|
816 |
return 0; |
621 |
if (pass == NULL) |
|
|
622 |
return ""; |
623 |
|
624 |
pass[i] = 0; |
625 |
return pass; |
626 |
} |
627 |
|
628 |
static int |
629 |
digits_only(const char *s) { |
630 |
while (*s) |
631 |
if (!isdigit(*s++)) |
632 |
return 0; |
633 |
return 1; |
634 |
} |
817 |
} |
|
|
818 |
#endif |
635 |
|
819 |
|
636 |
/* |
820 |
/* |
637 |
* return codes: |
821 |
* return codes: |
638 |
* 0 - success |
822 |
* 0 - success |
639 |
* 1 - error |
823 |
* 1 - error |
640 |
* 2 - error (EBUSY) |
824 |
* 2 - error (EBUSY) |
641 |
*/ |
825 |
*/ |
642 |
int |
826 |
int |
643 |
set_loop(const char *device, const char *file, unsigned long long offset, |
827 |
set_loop(const char *device, const char *file, int *loopro, const char **fstype, unsigned int *AutoChmodPtr, int busyRetVal) { |
644 |
unsigned long long sizelimit, const char *encryption, int pfd, int *options) { |
828 |
struct loop_info64 loopinfo; |
645 |
struct loop_info64 loopinfo64; |
829 |
int fd, ffd, mode, i, errRetVal = 1; |
646 |
int fd, ffd, mode, i; |
830 |
char *pass, *apiName = NULL; |
647 |
char *pass; |
831 |
void (*hashFunc)(unsigned char *, int, unsigned char *, int); |
648 |
char *filename; |
832 |
unsigned char multiKeyBits[65][32]; |
649 |
|
833 |
int minPassLen = LOOP_PASSWORD_MIN_LENGTH; |
650 |
if (verbose) { |
834 |
int run_mkfs_command = 0; |
651 |
char *xdev = loopfile_used(file, offset); |
835 |
|
652 |
|
836 |
loopFileName = (char *)file; |
653 |
if (xdev) { |
837 |
multiKeyMode = 0; |
654 |
printf(_("warning: %s is already associated with %s\n"), |
838 |
mode = (*loopro ? O_RDONLY : O_RDWR); |
655 |
file, xdev); |
|
|
656 |
free(xdev); |
657 |
} |
658 |
} |
659 |
|
660 |
mode = (*options & SETLOOP_RDONLY) ? O_RDONLY : O_RDWR; |
661 |
if ((ffd = open(file, mode)) < 0) { |
839 |
if ((ffd = open(file, mode)) < 0) { |
662 |
if (!(*options & SETLOOP_RDONLY) && |
840 |
if (!(*loopro) && |
663 |
(errno == EROFS || errno == EACCES)) |
841 |
(errno == EROFS || errno == EACCES)) |
664 |
ffd = open(file, mode = O_RDONLY); |
842 |
ffd = open(file, mode = O_RDONLY); |
665 |
if (ffd < 0) { |
843 |
if (ffd < 0) { |
666 |
perror(file); |
844 |
perror(file); |
667 |
return 1; |
845 |
return 1; |
668 |
} |
846 |
} |
669 |
if (verbose) |
847 |
if (verbose) |
670 |
printf(_("warning: %s: is write-protected, using read-only.\n"), |
848 |
printf(_("warning: %s: is write-protected, using read-only.\n"), |
671 |
file); |
849 |
file); |
672 |
*options |= SETLOOP_RDONLY; |
|
|
673 |
} |
850 |
} |
674 |
if ((fd = open(device, mode)) < 0) { |
851 |
if ((fd = open(device, mode)) < 0) { |
675 |
perror (device); |
852 |
perror (device); |
676 |
close(ffd); |
853 |
goto close_ffd_return1; |
677 |
return 1; |
|
|
678 |
} |
854 |
} |
679 |
memset(&loopinfo64, 0, sizeof(loopinfo64)); |
855 |
*loopro = (mode == O_RDONLY); |
680 |
|
856 |
|
681 |
if (!(filename = canonicalize(file))) |
857 |
if (ioctl(fd, LOOP_SET_FD, ffd) < 0) { |
682 |
filename = (char *) file; |
858 |
if(errno == EBUSY) |
683 |
xstrncpy((char *)loopinfo64.lo_file_name, filename, LO_NAME_SIZE); |
859 |
errRetVal = busyRetVal; |
684 |
|
860 |
if((errRetVal != 2) || verbose) |
685 |
if (encryption && *encryption) { |
861 |
perror("ioctl: LOOP_SET_FD"); |
686 |
if (digits_only(encryption)) { |
862 |
keyclean_close_fd_ffd_return1: |
687 |
loopinfo64.lo_encrypt_type = atoi(encryption); |
863 |
memset(loopinfo.lo_encrypt_key, 0, sizeof(loopinfo.lo_encrypt_key)); |
688 |
} else { |
864 |
memset(&multiKeyBits[0][0], 0, sizeof(multiKeyBits)); |
689 |
loopinfo64.lo_encrypt_type = LO_CRYPT_CRYPTOAPI; |
865 |
close (fd); |
690 |
snprintf((char *)loopinfo64.lo_crypt_name, LO_NAME_SIZE, |
866 |
close_ffd_return1: |
691 |
"%s", encryption); |
867 |
close (ffd); |
692 |
} |
868 |
return errRetVal; |
693 |
} |
869 |
} |
694 |
|
870 |
|
695 |
loopinfo64.lo_offset = offset; |
871 |
memset (&loopinfo, 0, sizeof (loopinfo)); |
696 |
loopinfo64.lo_sizelimit = sizelimit; |
872 |
xstrncpy ((char *)loopinfo.lo_file_name, file, LO_NAME_SIZE); |
|
|
873 |
if (loopEncryptionType) |
874 |
loopinfo.lo_encrypt_type = loop_crypt_type (loopEncryptionType, &loopinfo.lo_encrypt_key_size, &apiName); |
875 |
if (loopOffsetBytes) |
876 |
loopinfo.lo_offset = mystrtoull(loopOffsetBytes, 1); |
877 |
if (loopSizeBytes) |
878 |
loopinfo.lo_sizelimit = mystrtoull(loopSizeBytes, 0); |
697 |
|
879 |
|
698 |
#ifdef MCL_FUTURE |
880 |
#ifdef MCL_FUTURE |
699 |
/* |
881 |
/* |
700 |
* Oh-oh, sensitive data coming up. Better lock into memory to prevent |
882 |
* Oh-oh, sensitive data coming up. Better lock into memory to prevent |
701 |
* passwd etc being swapped out and left somewhere on disk. |
883 |
* passwd etc being swapped out and left somewhere on disk. |
702 |
*/ |
884 |
*/ |
703 |
if (loopinfo64.lo_encrypt_type != LO_CRYPT_NONE) { |
885 |
|
704 |
if(mlockall(MCL_CURRENT | MCL_FUTURE)) { |
886 |
if(loopinfo.lo_encrypt_type && mlockall(MCL_CURRENT | MCL_FUTURE)) { |
705 |
perror("memlock"); |
887 |
perror("memlock"); |
706 |
fprintf(stderr, _("Couldn't lock into memory, exiting.\n")); |
888 |
ioctl (fd, LOOP_CLR_FD, 0); |
707 |
exit(1); |
889 |
fprintf(stderr, _("Couldn't lock into memory, exiting.\n")); |
708 |
} |
890 |
exit(1); |
709 |
} |
891 |
} |
710 |
#endif |
892 |
#endif |
711 |
|
893 |
|
712 |
switch (loopinfo64.lo_encrypt_type) { |
894 |
switch (loopinfo.lo_encrypt_type) { |
713 |
case LO_CRYPT_NONE: |
895 |
case LO_CRYPT_NONE: |
714 |
loopinfo64.lo_encrypt_key_size = 0; |
896 |
loopinfo.lo_encrypt_key_size = 0; |
715 |
break; |
897 |
break; |
716 |
case LO_CRYPT_XOR: |
898 |
case LO_CRYPT_XOR: |
717 |
pass = getpass(_("Password: ")); |
899 |
pass = sGetPass (1, 0); |
718 |
goto gotpass; |
900 |
if(!pass) goto loop_clr_fd_out; |
|
|
901 |
xstrncpy ((char *)loopinfo.lo_encrypt_key, pass, LO_KEY_SIZE); |
902 |
loopinfo.lo_encrypt_key_size = strlen((char*)loopinfo.lo_encrypt_key); |
903 |
break; |
904 |
case 3: /* LO_CRYPT_FISH2 */ |
905 |
case 4: /* LO_CRYPT_BLOW */ |
906 |
case 7: /* LO_CRYPT_SERPENT */ |
907 |
case 8: /* LO_CRYPT_MARS */ |
908 |
case 11: /* LO_CRYPT_RC6 */ |
909 |
case 12: /* LO_CRYPT_DES_EDE3 */ |
910 |
case 16: /* LO_CRYPT_AES */ |
911 |
case 18: /* LO_CRYPT_CRYPTOAPI */ |
912 |
/* set default hash function */ |
913 |
hashFunc = sha256_hash_buffer; |
914 |
if(loopinfo.lo_encrypt_key_size == 24) hashFunc = sha384_hash_buffer; |
915 |
if(loopinfo.lo_encrypt_key_size == 32) hashFunc = sha512_hash_buffer; |
916 |
/* possibly override default hash function */ |
917 |
if(passHashFuncName) { |
918 |
if(!strcasecmp(passHashFuncName, "sha256")) { |
919 |
hashFunc = sha256_hash_buffer; |
920 |
} else if(!strcasecmp(passHashFuncName, "sha384")) { |
921 |
hashFunc = sha384_hash_buffer; |
922 |
} else if(!strcasecmp(passHashFuncName, "sha512")) { |
923 |
hashFunc = sha512_hash_buffer; |
924 |
} else if(!strcasecmp(passHashFuncName, "rmd160")) { |
925 |
hashFunc = rmd160HashTwiceWithA; |
926 |
minPassLen = 1; |
927 |
} else if(!strcasecmp(passHashFuncName, "unhashed1")) { |
928 |
hashFunc = unhashed1_key_setup; |
929 |
} else if(!strcasecmp(passHashFuncName, "unhashed2")) { |
930 |
hashFunc = unhashed2_key_setup; |
931 |
minPassLen = 1; |
932 |
} else if(!strcasecmp(passHashFuncName, "unhashed3") && passFDnumber && !gpgKeyFile) { |
933 |
/* unhashed3 hash type reads binary key from file descriptor. */ |
934 |
/* This is not compatible with gpgkey= mount option */ |
935 |
if(rd_wr_retry(atoi(passFDnumber), (char *)&loopinfo.lo_encrypt_key[0], LO_KEY_SIZE, 0) < 1) { |
936 |
fprintf(stderr, _("Error: couldn't read binary key\n")); |
937 |
goto loop_clr_fd_out; |
938 |
} |
939 |
break; /* out of switch(loopinfo.lo_encrypt_type) */ |
940 |
} else if(!strncasecmp(passHashFuncName, "random", 6) && ((passHashFuncName[6] == 0) || (passHashFuncName[6] == '/'))) { |
941 |
/* random hash type sets up 65 random keys */ |
942 |
/* WARNING! DO NOT USE RANDOM HASH TYPE ON PARTITION WITH EXISTING */ |
943 |
/* IMPORTANT DATA ON IT. RANDOM HASH TYPE WILL DESTROY YOUR DATA. */ |
944 |
if(loop_create_random_keys((char*)file, loopinfo.lo_offset, loopinfo.lo_sizelimit, *loopro, &multiKeyBits[0][0])) { |
945 |
goto loop_clr_fd_out; |
946 |
} |
947 |
memcpy(&loopinfo.lo_encrypt_key[0], &multiKeyBits[0][0], sizeof(loopinfo.lo_encrypt_key)); |
948 |
run_mkfs_command = multiKeyMode = 1000; |
949 |
break; /* out of switch(loopinfo.lo_encrypt_type) */ |
950 |
} |
951 |
} |
952 |
pass = sGetPass (minPassLen, LOOP_PASSWORD_MIN_LENGTH); |
953 |
if(!pass) goto loop_clr_fd_out; |
954 |
i = strlen(pass); |
955 |
if(hashFunc == unhashed1_key_setup) { |
956 |
/* this is for compatibility with historic loop-AES version */ |
957 |
loopinfo.lo_encrypt_key_size = 16; /* 128 bits */ |
958 |
if(i >= 32) loopinfo.lo_encrypt_key_size = 24; /* 192 bits */ |
959 |
if(i >= 43) loopinfo.lo_encrypt_key_size = 32; /* 256 bits */ |
960 |
} |
961 |
(*hashFunc)((unsigned char *)pass, i, &loopinfo.lo_encrypt_key[0], sizeof(loopinfo.lo_encrypt_key)); |
962 |
if(multiKeyMode) { |
963 |
int r = 0, t; |
964 |
while(r < multiKeyMode) { |
965 |
t = strlen(multiKeyPass[r]); |
966 |
(*hashFunc)((unsigned char *)multiKeyPass[r], t, &multiKeyBits[r][0], 32); |
967 |
memset(multiKeyPass[r], 0, t); |
968 |
/* |
969 |
* MultiKeyMode uses md5 IV. One key mode uses sector IV. Sector IV |
970 |
* and md5 IV v2 and v3 are all computed differently. This first key |
971 |
* byte XOR with 0x55/0xF4 is needed to cause complete decrypt failure |
972 |
* in cases where data is encrypted with one type of IV and decrypted |
973 |
* with another type IV. If identical key was used but only IV was |
974 |
* computed differently, only first plaintext block of 512 byte CBC |
975 |
* chain would decrypt incorrectly and rest would decrypt correctly. |
976 |
* Partially correct decryption is dangerous. Decrypting all blocks |
977 |
* incorrectly is safer because file system mount will simply fail. |
978 |
*/ |
979 |
if(multiKeyMode == 65) { |
980 |
multiKeyBits[r][0] ^= 0xF4; /* version 3 */ |
981 |
} else { |
982 |
multiKeyBits[r][0] ^= 0x55; /* version 2 */ |
983 |
} |
984 |
r++; |
985 |
} |
986 |
} else if(passIterThousands) { |
987 |
aes_context ctx; |
988 |
unsigned long iter = 0; |
989 |
unsigned char tempkey[32]; |
990 |
/* |
991 |
* Set up AES-256 encryption key using same password and hash function |
992 |
* as before but with password bit 0 flipped before hashing. That key |
993 |
* is then used to encrypt actual loop key 'itercountk' thousand times. |
994 |
*/ |
995 |
pass[0] ^= 1; |
996 |
(*hashFunc)((unsigned char *)pass, i, &tempkey[0], 32); |
997 |
aes_set_key(&ctx, &tempkey[0], 32, 0); |
998 |
sscanf(passIterThousands, "%lu", &iter); |
999 |
iter *= 1000; |
1000 |
while(iter > 0) { |
1001 |
/* encrypt both 128bit blocks with AES-256 */ |
1002 |
aes_encrypt(&ctx, &loopinfo.lo_encrypt_key[ 0], &loopinfo.lo_encrypt_key[ 0]); |
1003 |
aes_encrypt(&ctx, &loopinfo.lo_encrypt_key[16], &loopinfo.lo_encrypt_key[16]); |
1004 |
/* exchange upper half of first block with lower half of second block */ |
1005 |
memcpy(&tempkey[0], &loopinfo.lo_encrypt_key[8], 8); |
1006 |
memcpy(&loopinfo.lo_encrypt_key[8], &loopinfo.lo_encrypt_key[16], 8); |
1007 |
memcpy(&loopinfo.lo_encrypt_key[16], &tempkey[0], 8); |
1008 |
iter--; |
1009 |
} |
1010 |
memset(&ctx, 0, sizeof(ctx)); |
1011 |
memset(&tempkey[0], 0, sizeof(tempkey)); |
1012 |
} |
1013 |
memset(pass, 0, i); /* erase original password */ |
1014 |
break; |
719 |
default: |
1015 |
default: |
720 |
pass = xgetpass(pfd, _("Password: ")); |
1016 |
fprintf (stderr, _("Error: don't know how to get key for encryption system %d\n"), loopinfo.lo_encrypt_type); |
721 |
gotpass: |
1017 |
goto loop_clr_fd_out; |
722 |
memset(loopinfo64.lo_encrypt_key, 0, LO_KEY_SIZE); |
|
|
723 |
xstrncpy((char *)loopinfo64.lo_encrypt_key, pass, LO_KEY_SIZE); |
724 |
memset(pass, 0, strlen(pass)); |
725 |
loopinfo64.lo_encrypt_key_size = LO_KEY_SIZE; |
726 |
} |
1018 |
} |
727 |
|
1019 |
|
728 |
if (ioctl(fd, LOOP_SET_FD, ffd) < 0) { |
1020 |
if(loInitValue) { |
729 |
int rc = 1; |
1021 |
/* cipher modules are free to do whatever they want with this value */ |
730 |
|
1022 |
i = 0; |
731 |
if (errno == EBUSY) { |
1023 |
sscanf(loInitValue, "%d", &i); |
732 |
if (verbose) |
1024 |
loopinfo.lo_init[0] = i; |
733 |
printf(_("ioctl LOOP_SET_FD failed: %s\n"), |
1025 |
} |
734 |
strerror(errno)); |
1026 |
|
735 |
rc = 2; |
1027 |
/* type 18 == LO_CRYPT_CRYPTOAPI */ |
736 |
} else |
1028 |
if ((loopinfo.lo_encrypt_type == 18) || (loop_set_status64_ioctl(fd, &loopinfo) < 0)) { |
737 |
perror("ioctl: LOOP_SET_FD"); |
1029 |
/* direct cipher interface failed - try CryptoAPI interface now */ |
738 |
|
1030 |
if(!apiName || (try_cryptoapi_loop_interface(fd, &loopinfo, apiName) < 0)) { |
739 |
close(fd); |
1031 |
fprintf(stderr, _("ioctl: LOOP_SET_STATUS: %s, requested cipher or key length (%d bits) not supported by kernel\n"), strerror(errno), loopinfo.lo_encrypt_key_size << 3); |
740 |
close(ffd); |
1032 |
loop_clr_fd_out: |
741 |
if (file != filename) |
1033 |
(void) ioctl (fd, LOOP_CLR_FD, 0); |
742 |
free(filename); |
1034 |
goto keyclean_close_fd_ffd_return1; |
743 |
return rc; |
1035 |
} |
|
|
1036 |
} |
1037 |
if(multiKeyMode >= 65) { |
1038 |
if(ioctl(fd, LOOP_MULTI_KEY_SETUP_V3, &multiKeyBits[0][0]) < 0) { |
1039 |
if(multiKeyMode == 1000) goto try_v2_setup; |
1040 |
perror("ioctl: LOOP_MULTI_KEY_SETUP_V3"); |
1041 |
goto loop_clr_fd_out; |
1042 |
} |
1043 |
} else if(multiKeyMode == 64) { |
1044 |
try_v2_setup: |
1045 |
if((ioctl(fd, LOOP_MULTI_KEY_SETUP, &multiKeyBits[0][0]) < 0) && (multiKeyMode != 1000)) { |
1046 |
perror("ioctl: LOOP_MULTI_KEY_SETUP"); |
1047 |
goto loop_clr_fd_out; |
1048 |
} |
744 |
} |
1049 |
} |
745 |
close (ffd); |
|
|
746 |
|
747 |
if (*options & SETLOOP_AUTOCLEAR) |
748 |
loopinfo64.lo_flags = LO_FLAGS_AUTOCLEAR; |
749 |
|
1050 |
|
750 |
i = ioctl(fd, LOOP_SET_STATUS64, &loopinfo64); |
1051 |
memset(loopinfo.lo_encrypt_key, 0, sizeof(loopinfo.lo_encrypt_key)); |
751 |
if (i) { |
1052 |
memset(&multiKeyBits[0][0], 0, sizeof(multiKeyBits)); |
752 |
struct loop_info loopinfo; |
1053 |
close (fd); |
753 |
int errsv = errno; |
1054 |
close (ffd); |
754 |
|
1055 |
|
755 |
i = loop_info64_to_old(&loopinfo64, &loopinfo); |
1056 |
#if !defined(MAIN) |
756 |
if (i) { |
1057 |
if(run_mkfs_command && fstype && *fstype && **fstype && (getuid() == 0)) { |
757 |
errno = errsv; |
1058 |
if(!loop_fork_mkfs_command((char *)device, (char *)(*fstype))) { |
758 |
*options &= ~SETLOOP_AUTOCLEAR; |
1059 |
/* !strncasecmp(passHashFuncName, "random", 6) test matched */ |
759 |
perror("ioctl: LOOP_SET_STATUS64"); |
1060 |
/* This reads octal mode for newly created file system root */ |
|
|
1061 |
/* directory node from '-o phash=random/1777' mount option. */ |
1062 |
/* octal mode--^^^^ */ |
1063 |
sscanf(passHashFuncName + 6, "/%o", AutoChmodPtr); |
760 |
} else { |
1064 |
} else { |
761 |
i = ioctl(fd, LOOP_SET_STATUS, &loopinfo); |
1065 |
if((fd = open(device, mode)) >= 0) { |
762 |
if (i) |
1066 |
ioctl(fd, LOOP_CLR_FD, 0); |
763 |
perror("ioctl: LOOP_SET_STATUS"); |
1067 |
close(fd); |
764 |
else if (*options & SETLOOP_AUTOCLEAR) |
1068 |
return 1; |
765 |
{ |
|
|
766 |
i = ioctl(fd, LOOP_GET_STATUS, &loopinfo); |
767 |
if (i || !(loopinfo.lo_flags & LO_FLAGS_AUTOCLEAR)) |
768 |
*options &= ~SETLOOP_AUTOCLEAR; |
769 |
} |
1069 |
} |
770 |
} |
1070 |
} |
771 |
memset(&loopinfo, 0, sizeof(loopinfo)); |
|
|
772 |
} |
1071 |
} |
773 |
else if (*options & SETLOOP_AUTOCLEAR) |
1072 |
#endif |
774 |
{ |
|
|
775 |
i = ioctl(fd, LOOP_GET_STATUS64, &loopinfo64); |
776 |
if (i || !(loopinfo64.lo_flags & LO_FLAGS_AUTOCLEAR)) |
777 |
*options &= ~SETLOOP_AUTOCLEAR; |
778 |
} |
779 |
memset(&loopinfo64, 0, sizeof(loopinfo64)); |
780 |
|
781 |
|
782 |
if (i) { |
783 |
ioctl (fd, LOOP_CLR_FD, 0); |
784 |
close (fd); |
785 |
if (file != filename) |
786 |
free(filename); |
787 |
return 1; |
788 |
} |
789 |
|
790 |
/* |
791 |
* HACK: here we're leeking a file descriptor, |
792 |
* but mount is a short-lived process anyway. |
793 |
*/ |
794 |
if (!(*options & SETLOOP_AUTOCLEAR)) |
795 |
close (fd); |
796 |
|
1073 |
|
797 |
if (verbose > 1) |
1074 |
if (verbose > 1) |
798 |
printf(_("set_loop(%s,%s,%llu,%llu): success\n"), |
1075 |
printf(_("set_loop(%s,%s): success\n"), device, file); |
799 |
device, filename, offset, sizelimit); |
|
|
800 |
if (file != filename) |
801 |
free(filename); |
802 |
return 0; |
1076 |
return 0; |
803 |
} |
1077 |
} |
804 |
|
1078 |
|
805 |
int |
1079 |
#ifdef MAIN |
806 |
del_loop (const char *device) { |
|
|
807 |
int fd; |
808 |
|
1080 |
|
809 |
if ((fd = open (device, O_RDONLY)) < 0) { |
1081 |
#include <getopt.h> |
810 |
int errsv = errno; |
1082 |
#include <stdarg.h> |
811 |
fprintf(stderr, _("loop: can't delete device %s: %s\n"), |
1083 |
|
812 |
device, strerror (errsv)); |
1084 |
int verbose = 0; |
813 |
return 1; |
1085 |
static char *progname; |
814 |
} |
|
|
815 |
if (ioctl (fd, LOOP_CLR_FD, 0) < 0) { |
816 |
perror ("ioctl: LOOP_CLR_FD"); |
817 |
close(fd); |
818 |
return 1; |
819 |
} |
820 |
close (fd); |
821 |
if (verbose > 1) |
822 |
printf(_("del_loop(%s): success\n"), device); |
823 |
return 0; |
824 |
} |
825 |
|
1086 |
|
826 |
#else /* no LOOP_SET_FD defined */ |
|
|
827 |
static void |
1087 |
static void |
828 |
mutter(void) { |
1088 |
usage(void) { |
829 |
fprintf(stderr, |
1089 |
fprintf(stderr, _("usage:\n\ |
830 |
_("This mount was compiled without loop support. " |
1090 |
%s [options] loop_device file # setup\n\ |
831 |
"Please recompile.\n")); |
1091 |
%s -F [options] loop_device [file] # setup, read /etc/fstab\n\ |
|
|
1092 |
%s loop_device # give info\n\ |
1093 |
%s -a # give info of all loops\n\ |
1094 |
%s -f # show next free loop device\n\ |
1095 |
%s -d loop_device # delete\n\ |
1096 |
%s -R loop_device # resize\n\ |
1097 |
options: -e encryption -o offset -s sizelimit -p passwdfd -T -S pseed\n\ |
1098 |
-H phash -I loinit -K gpgkey -G gpghome -C itercountk -v -r\n\ |
1099 |
-P cleartextkey\n"), |
1100 |
progname, progname, progname, progname, progname, progname, progname); |
1101 |
exit(1); |
832 |
} |
1102 |
} |
833 |
|
1103 |
|
834 |
int |
1104 |
void |
835 |
set_loop(const char *device, const char *file, unsigned long long offset, |
1105 |
show_all_loops(void) |
836 |
unsigned long long sizelimit, const char *encryption, int pfd, int *loopro, |
1106 |
{ |
837 |
int keysz, int hash_pass) { |
1107 |
char dev[20]; |
838 |
mutter(); |
1108 |
char *lfmt[] = { "/dev/loop%d", "/dev/loop/%d" }; |
839 |
return 1; |
1109 |
int i, j, fd, x; |
|
|
1110 |
struct stat statbuf; |
1111 |
|
1112 |
for(i = 0; i < 256; i++) { |
1113 |
for(j = (sizeof(lfmt) / sizeof(lfmt[0])) - 1; j >= 0; j--) { |
1114 |
sprintf(dev, lfmt[j], i); |
1115 |
if(stat(dev, &statbuf) == 0 && S_ISBLK(statbuf.st_mode)) { |
1116 |
fd = open(dev, O_RDONLY); |
1117 |
if(fd >= 0) { |
1118 |
x = is_unused_loop_device(fd); |
1119 |
close(fd); |
1120 |
if(x == 0) { |
1121 |
show_loop(dev); |
1122 |
j = 0; |
1123 |
} |
1124 |
} |
1125 |
} |
1126 |
} |
1127 |
} |
840 |
} |
1128 |
} |
841 |
|
1129 |
|
842 |
int |
1130 |
int |
843 |
del_loop (const char *device) { |
1131 |
read_options_from_fstab(char *loopToFind, char **partitionPtr) |
844 |
mutter(); |
1132 |
{ |
845 |
return 1; |
1133 |
FILE *f; |
846 |
} |
1134 |
struct mntent *m; |
|
|
1135 |
int y, foundMatch = 0; |
1136 |
char *opt, *fr1, *fr2; |
1137 |
struct options { |
1138 |
char *name; /* name of /etc/fstab option */ |
1139 |
char **dest; /* destination where it is written to */ |
1140 |
char *line; /* temp */ |
1141 |
}; |
1142 |
struct options tbl[] = { |
1143 |
{ "device/file name ", partitionPtr }, /* must be index 0 */ |
1144 |
{ "loop=", &loopToFind }, /* must be index 1 */ |
1145 |
{ "offset=", &loopOffsetBytes }, |
1146 |
{ "sizelimit=", &loopSizeBytes }, |
1147 |
{ "encryption=", &loopEncryptionType }, |
1148 |
{ "pseed=", &passSeedString }, |
1149 |
{ "phash=", &passHashFuncName }, |
1150 |
{ "loinit=", &loInitValue }, |
1151 |
{ "gpgkey=", &gpgKeyFile }, |
1152 |
{ "gpghome=", &gpgHomeDir }, |
1153 |
{ "cleartextkey=", &clearTextKeyFile }, |
1154 |
{ "itercountk=", &passIterThousands }, |
1155 |
}; |
1156 |
struct options *p; |
847 |
|
1157 |
|
848 |
char * |
1158 |
if (!(f = setmntent("/etc/fstab", "r"))) { |
849 |
find_unused_loop_device (void) { |
1159 |
fprintf(stderr, _("Error: unable to open /etc/fstab for reading\n")); |
850 |
mutter(); |
1160 |
return 0; |
851 |
return 0; |
1161 |
} |
|
|
1162 |
while ((m = getmntent(f)) != NULL) { |
1163 |
tbl[0].line = fr1 = xstrdup(m->mnt_fsname); |
1164 |
p = &tbl[1]; |
1165 |
do { |
1166 |
p->line = NULL; |
1167 |
} while (++p < &tbl[sizeof(tbl) / sizeof(struct options)]); |
1168 |
opt = fr2 = xstrdup(m->mnt_opts); |
1169 |
for (opt = strtok(opt, ","); opt != NULL; opt = strtok(NULL, ",")) { |
1170 |
p = &tbl[1]; |
1171 |
do { |
1172 |
y = strlen(p->name); |
1173 |
if (!strncmp(opt, p->name, y)) |
1174 |
p->line = opt + y; |
1175 |
} while (++p < &tbl[sizeof(tbl) / sizeof(struct options)]); |
1176 |
} |
1177 |
if (tbl[1].line && !strcmp(loopToFind, tbl[1].line)) { |
1178 |
if (++foundMatch > 1) { |
1179 |
fprintf(stderr, _("Error: multiple loop=%s options found in /etc/fstab\n"), loopToFind); |
1180 |
endmntent(f); |
1181 |
return 0; |
1182 |
} |
1183 |
p = &tbl[0]; |
1184 |
do { |
1185 |
if (!*p->dest && p->line) { |
1186 |
*p->dest = p->line; |
1187 |
if (verbose) |
1188 |
printf(_("using %s%s from /etc/fstab\n"), p->name, p->line); |
1189 |
} |
1190 |
} while (++p < &tbl[sizeof(tbl) / sizeof(struct options)]); |
1191 |
fr1 = fr2 = NULL; |
1192 |
} |
1193 |
if(fr1) free(fr1); |
1194 |
if(fr2) free(fr2); |
1195 |
} |
1196 |
endmntent(f); |
1197 |
if (foundMatch == 0) { |
1198 |
fprintf(stderr, _("Error: loop=%s option not found in /etc/fstab\n"), loopToFind); |
1199 |
} |
1200 |
return foundMatch; |
852 |
} |
1201 |
} |
853 |
|
1202 |
|
854 |
#endif /* !LOOP_SET_FD */ |
1203 |
int |
855 |
|
1204 |
recompute_loop_dev_size(char *device) |
856 |
#ifdef MAIN |
1205 |
{ |
857 |
|
1206 |
int fd, err1 = 0, err2, err3; |
858 |
#ifdef LOOP_SET_FD |
1207 |
long long oldBytes = -1, newBytes = -1; |
859 |
|
|
|
860 |
#include <getopt.h> |
861 |
#include <stdarg.h> |
862 |
|
1208 |
|
863 |
static void |
1209 |
fd = open(device, O_RDONLY); |
864 |
usage(void) { |
1210 |
if(fd < 0) { |
865 |
fprintf(stderr, _("\nUsage:\n" |
1211 |
perror(device); |
866 |
" %1$s loop_device give info\n" |
1212 |
return 1; |
867 |
" %1$s -a | --all list all used\n" |
1213 |
} |
868 |
" %1$s -d | --detach <loopdev> delete\n" |
1214 |
if(verbose) { |
869 |
" %1$s -f | --find find unused\n" |
1215 |
err1 = ioctl(fd, BLKGETSIZE64, &oldBytes); |
870 |
" %1$s -j | --associated <file> [-o <num>] list all associated with <file>\n" |
1216 |
} |
871 |
" %1$s [ options ] {-f|--find|loopdev} <file> setup\n"), |
1217 |
err2 = ioctl(fd, LOOP_RECOMPUTE_DEV_SIZE, 0); |
872 |
progname); |
1218 |
if(err2) { |
873 |
|
1219 |
perror(device); |
874 |
fprintf(stderr, _("\nOptions:\n" |
1220 |
goto done1; |
875 |
" -e | --encryption <type> enable data encryption with specified <name/num>\n" |
1221 |
} |
876 |
" -h | --help this help\n" |
1222 |
if(verbose) { |
877 |
" -o | --offset <num> start at offset <num> into file\n" |
1223 |
err3 = ioctl(fd, BLKGETSIZE64, &newBytes); |
878 |
" --sizelimit <num> loop limited to only <num> bytes of the file\n" |
1224 |
if(!err1 && (oldBytes >= 0)) { |
879 |
" -p | --pass-fd <num> read passphrase from file descriptor <num>\n" |
1225 |
printf("%s: old size %lld bytes\n", device, oldBytes); |
880 |
" -r | --read-only setup read-only loop device\n" |
1226 |
} |
881 |
" --show print device name (with -f <file>)\n" |
1227 |
if(!err3 && (newBytes >= 0)) { |
882 |
" -v | --verbose verbose mode\n\n")); |
1228 |
printf("%s: new size %lld bytes\n", device, newBytes); |
883 |
exit(1); |
1229 |
} |
884 |
} |
1230 |
} |
|
|
1231 |
done1: |
1232 |
close(fd); |
1233 |
return err2; |
1234 |
} |
885 |
|
1235 |
|
886 |
int |
1236 |
int |
887 |
main(int argc, char **argv) { |
1237 |
main(int argc, char **argv) { |
888 |
char *p, *offset, *sizelimit, *encryption, *passfd, *device, *file, *assoc; |
1238 |
char *partitionName = NULL; |
889 |
int delete, find, c, all; |
1239 |
char *device = NULL; |
|
|
1240 |
int delete,find,c,option_a=0,option_F=0,option_R=0,setup_o=0; |
890 |
int res = 0; |
1241 |
int res = 0; |
891 |
int showdev = 0; |
|
|
892 |
int ro = 0; |
1242 |
int ro = 0; |
893 |
int pfd = -1; |
|
|
894 |
unsigned long long off, slimit; |
895 |
struct option longopts[] = { |
896 |
{ "all", 0, 0, 'a' }, |
897 |
{ "detach", 0, 0, 'd' }, |
898 |
{ "encryption", 1, 0, 'e' }, |
899 |
{ "find", 0, 0, 'f' }, |
900 |
{ "help", 0, 0, 'h' }, |
901 |
{ "associated", 1, 0, 'j' }, |
902 |
{ "offset", 1, 0, 'o' }, |
903 |
{ "sizelimit", 1, 0, 128 }, |
904 |
{ "pass-fd", 1, 0, 'p' }, |
905 |
{ "read-only", 0, 0, 'r' }, |
906 |
{ "show", 0, 0, 's' }, |
907 |
{ "verbose", 0, 0, 'v' }, |
908 |
{ NULL, 0, 0, 0 } |
909 |
}; |
910 |
|
1243 |
|
911 |
setlocale(LC_ALL, ""); |
1244 |
setlocale(LC_ALL, ""); |
912 |
bindtextdomain(PACKAGE, LOCALEDIR); |
1245 |
bindtextdomain(PACKAGE, LOCALEDIR); |
913 |
textdomain(PACKAGE); |
1246 |
textdomain(PACKAGE); |
914 |
|
1247 |
|
915 |
delete = find = all = 0; |
1248 |
delete = find = 0; |
916 |
off = 0; |
|
|
917 |
slimit = 0; |
918 |
assoc = offset = sizelimit = encryption = passfd = NULL; |
919 |
|
920 |
progname = argv[0]; |
1249 |
progname = argv[0]; |
921 |
if ((p = strrchr(progname, '/')) != NULL) |
1250 |
while ((c = getopt(argc,argv,"aC:de:fFG:H:I:K:o:p:P:rRs:S:Tv")) != -1) { |
922 |
progname = p+1; |
|
|
923 |
|
924 |
while ((c = getopt_long(argc, argv, "ade:E:fhj:o:p:rsv", |
925 |
longopts, NULL)) != -1) { |
926 |
switch (c) { |
1251 |
switch (c) { |
927 |
case 'a': |
1252 |
case 'a': /* show status of all loops */ |
928 |
all = 1; |
1253 |
option_a = 1; |
929 |
break; |
1254 |
break; |
930 |
case 'r': |
1255 |
case 'C': |
931 |
ro = 1; |
1256 |
passIterThousands = optarg; |
|
|
1257 |
setup_o = 1; |
932 |
break; |
1258 |
break; |
933 |
case 'd': |
1259 |
case 'd': |
934 |
delete = 1; |
1260 |
delete = 1; |
935 |
break; |
1261 |
break; |
936 |
case 'E': |
|
|
937 |
case 'e': |
1262 |
case 'e': |
938 |
encryption = optarg; |
1263 |
loopEncryptionType = optarg; |
|
|
1264 |
setup_o = 1; |
939 |
break; |
1265 |
break; |
940 |
case 'f': |
1266 |
case 'f': /* find free loop */ |
941 |
find = 1; |
1267 |
find = 1; |
942 |
break; |
1268 |
break; |
943 |
case 'j': |
1269 |
case 'F': /* read loop related options from /etc/fstab */ |
944 |
assoc = optarg; |
1270 |
option_F = 1; |
|
|
1271 |
setup_o = 1; |
1272 |
break; |
1273 |
case 'G': /* GnuPG home dir */ |
1274 |
gpgHomeDir = optarg; |
1275 |
setup_o = 1; |
1276 |
break; |
1277 |
case 'H': /* passphrase hash function name */ |
1278 |
passHashFuncName = optarg; |
1279 |
setup_o = 1; |
1280 |
break; |
1281 |
case 'I': /* lo_init[0] value (in string form) */ |
1282 |
loInitValue = optarg; |
1283 |
setup_o = 1; |
1284 |
break; |
1285 |
case 'K': /* GnuPG key file name */ |
1286 |
gpgKeyFile = optarg; |
1287 |
setup_o = 1; |
945 |
break; |
1288 |
break; |
946 |
case 'o': |
1289 |
case 'o': |
947 |
offset = optarg; |
1290 |
loopOffsetBytes = optarg; |
|
|
1291 |
setup_o = 1; |
1292 |
break; |
1293 |
case 'p': /* read passphrase from given fd */ |
1294 |
passFDnumber = optarg; |
1295 |
setup_o = 1; |
948 |
break; |
1296 |
break; |
949 |
case 'p': |
1297 |
case 'P': /* read passphrase from given file */ |
950 |
passfd = optarg; |
1298 |
clearTextKeyFile = optarg; |
|
|
1299 |
setup_o = 1; |
1300 |
break; |
1301 |
case 'r': /* read-only */ |
1302 |
ro = 1; |
1303 |
setup_o = 1; |
1304 |
break; |
1305 |
case 'R': /* recompute loop dev size */ |
1306 |
option_R = 1; |
951 |
break; |
1307 |
break; |
952 |
case 's': |
1308 |
case 's': |
953 |
showdev = 1; |
1309 |
loopSizeBytes = optarg; |
|
|
1310 |
setup_o = 1; |
1311 |
break; |
1312 |
case 'S': /* optional seed for passphrase */ |
1313 |
passSeedString = optarg; |
1314 |
setup_o = 1; |
1315 |
break; |
1316 |
case 'T': /* ask passphrase _twice_ */ |
1317 |
passAskTwice = "T"; |
1318 |
setup_o = 1; |
954 |
break; |
1319 |
break; |
955 |
case 'v': |
1320 |
case 'v': |
956 |
verbose = 1; |
1321 |
verbose++; |
957 |
break; |
1322 |
break; |
958 |
|
|
|
959 |
case 128: /* --sizelimit */ |
960 |
sizelimit = optarg; |
961 |
break; |
962 |
|
963 |
default: |
1323 |
default: |
964 |
usage(); |
1324 |
usage(); |
965 |
} |
1325 |
} |
966 |
} |
1326 |
} |
967 |
|
1327 |
if (option_a + delete + option_R + setup_o + find > 1) usage(); |
968 |
if (argc == 1) { |
1328 |
if (option_a) { |
969 |
usage(); |
1329 |
/* show all loops */ |
970 |
} else if (delete) { |
1330 |
if (argc != optind) usage(); |
971 |
if (argc != optind+1 || encryption || offset || sizelimit || |
1331 |
show_all_loops(); |
972 |
find || all || showdev || assoc || ro) |
1332 |
res = 0; |
973 |
usage(); |
|
|
974 |
} else if (find) { |
1333 |
} else if (find) { |
975 |
if (all || assoc || argc < optind || argc > optind+1) |
1334 |
if (argc != optind) |
976 |
usage(); |
|
|
977 |
} else if (all) { |
978 |
if (argc > 2) |
979 |
usage(); |
1335 |
usage(); |
980 |
} else if (assoc) { |
|
|
981 |
if (encryption || showdev || passfd || ro) |
982 |
usage(); |
983 |
} else { |
984 |
if (argc < optind+1 || argc > optind+2) |
985 |
usage(); |
986 |
} |
987 |
|
988 |
if (offset && sscanf(offset, "%llu", &off) != 1) |
989 |
usage(); |
990 |
|
991 |
if (sizelimit && sscanf(sizelimit, "%llu", &slimit) != 1) |
992 |
usage(); |
993 |
|
994 |
if (all) |
995 |
return show_used_loop_devices(); |
996 |
else if (assoc) |
997 |
return show_associated_loop_devices(assoc, off, offset ? 1 : 0); |
998 |
else if (find) { |
999 |
device = find_unused_loop_device(); |
1336 |
device = find_unused_loop_device(); |
1000 |
if (device == NULL) |
1337 |
if (device == NULL) |
1001 |
return -1; |
1338 |
return -1; |
1002 |
if (argc == optind) { |
1339 |
if (verbose) |
1003 |
if (verbose) |
1340 |
printf("Loop device is %s\n", device); |
1004 |
printf(_("Loop device is %s\n"), device); |
1341 |
printf("%s\n", device); |
1005 |
printf("%s\n", device); |
1342 |
res = 0; |
1006 |
return 0; |
1343 |
} else if (delete) { |
1007 |
} |
1344 |
/* delete loop */ |
1008 |
file = argv[optind]; |
1345 |
if (argc != optind+1) usage(); |
|
|
1346 |
res = del_loop(argv[optind]); |
1347 |
} else if (option_R) { |
1348 |
/* resize existing loop */ |
1349 |
if (argc != optind+1) usage(); |
1350 |
res = recompute_loop_dev_size(argv[optind]); |
1351 |
} else if ((argc == optind+1) && !setup_o) { |
1352 |
/* show one loop */ |
1353 |
res = show_loop(argv[optind]); |
1009 |
} else { |
1354 |
} else { |
1010 |
device = argv[optind]; |
1355 |
/* set up new loop */ |
1011 |
if (argc == optind+1) |
1356 |
if ((argc < optind+1) || ((argc == optind+1) && !option_F) || (argc > optind+2)) |
1012 |
file = NULL; |
|
|
1013 |
else |
1014 |
file = argv[optind+1]; |
1015 |
} |
1016 |
|
1017 |
if (delete) |
1018 |
res = del_loop(device); |
1019 |
else if (file == NULL) |
1020 |
res = show_loop(device); |
1021 |
else { |
1022 |
if (passfd && sscanf(passfd, "%d", &pfd) != 1) |
1023 |
usage(); |
1357 |
usage(); |
1024 |
do { |
1358 |
if (argc > optind+1) |
1025 |
res = set_loop(device, file, off, slimit, encryption, pfd, &ro); |
1359 |
partitionName = argv[optind+1]; |
1026 |
if (res == 2 && find) { |
1360 |
if (option_F && (read_options_from_fstab(argv[optind], &partitionName) != 1)) |
1027 |
if (verbose) |
1361 |
exit(1); |
1028 |
printf(_("stolen loop=%s...trying again\n"), |
1362 |
res = set_loop(argv[optind],partitionName,&ro,(const char**)0,(unsigned int *)0, 1); |
1029 |
device); |
|
|
1030 |
free(device); |
1031 |
if (!(device = find_unused_loop_device())) |
1032 |
return -1; |
1033 |
} |
1034 |
} while (find && res == 2); |
1035 |
|
1036 |
if (device) { |
1037 |
if (res == 2) |
1038 |
error(_("%s: %s: device is busy"), progname, device); |
1039 |
else if (res == 0) { |
1040 |
if (verbose) |
1041 |
printf(_("Loop device is %s\n"), device); |
1042 |
if (showdev && find) |
1043 |
printf("%s\n", device); |
1044 |
} |
1045 |
} |
1046 |
} |
1363 |
} |
1047 |
return res; |
1364 |
return res; |
1048 |
} |
1365 |
} |
1049 |
|
1366 |
#endif |
1050 |
#else /* LOOP_SET_FD not defined */ |
|
|
1051 |
|
1052 |
int |
1053 |
main(int argc, char **argv) { |
1054 |
fprintf(stderr, |
1055 |
_("No loop support was available at compile time. " |
1056 |
"Please recompile.\n")); |
1057 |
return -1; |
1058 |
} |
1059 |
#endif /* !LOOP_SET_FD*/ |
1060 |
#endif /* MAIN */ |