1 /*
2 * Copyright © Jan Engelhardt, 2008-2011
3 *
4 * This file is part of pam_mount; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public License
6 * as published by the Free Software Foundation; either version 2.1
7 * of the License, or (at your option) any later version.
8 */
9 #include <sys/mount.h>
10 #include <sys/stat.h>
11 #include <sys/types.h>
12 #include <sys/wait.h>
13 #include <assert.h>
14 #include <errno.h>
15 #include <fcntl.h>
16 #include <limits.h>
17 #include <signal.h>
18 #include <stdbool.h>
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include <unistd.h>
23 #include <libHX.h>
24 #include "pam_mount.h"
25 #ifdef HAVE_LIBCRYPTO
26 # include <openssl/evp.h>
27 #endif
28
29 /**
30 * @object: volume or mountpoint; used by remount
31 * @container: path to the volume (like (bdev) /dev/sda2 or
32 * (file) /home/user.!@#)
33 * @mountpoint: where to put this
34 * @extra_options: options to pass down
35 * @no_update: do not update mtab
36 * @loop_device: loop device association, if any
37 * @crypto_device: crypto device
38 * @trunc_keysize: override cryptsetup keysize
39 * (needed for ASCII keys, see SF#2727353)
40 * @is_cont: looks like a container; used by remount
41 * @blkdev: true if @container is a block device
42 * @fsck: true if fsck should be performed
43 * @remount: issue a remount
44 */
45 struct mount_options {
46 hxmc_t *object, *container, *mountpoint;
47 const char *fstype;
48 const char *dmcrypt_cipher, *dmcrypt_hash;
49 const char *fsk_hash, *fsk_cipher, *fsk_file;
50 hxmc_t *fsk_password, *extra_opts, *crypto_device;
51 char *loop_device;
52 unsigned int no_update, readonly, trunc_keysize;
53 int dm_timeout;
54 bool is_cont;
55 bool blkdev;
56 bool fsck;
57 bool remount;
58 };
59
60 /**
61 * @object: what umount should look for
62 * @no_update: skip updating mtab
63 * @ro_fallback: remount read-only on umount error
64 * @is_cont: @object denotes the container
65 * @blkdev: @container is a block device
66 */
67 struct umount_options {
68 hxmc_t *object;
69 unsigned int no_update, ro_fallback;
70 bool is_cont, blkdev;
71 };
72
mtcr_parse_suboptions(const struct HXoptcb * cbi)73 static void mtcr_parse_suboptions(const struct HXoptcb *cbi)
74 {
75 struct mount_options *mo = cbi->current->uptr;
76 hxmc_t *passthru;
77 bool first = true;
78 char *copt;
79 char *key;
80
81 if ((copt = xstrdup(cbi->data)) == NULL)
82 return;
83 if ((passthru = HXmc_meminit(NULL, strlen(copt))) == NULL)
84 abort();
85
86 while ((key = HX_strsep(&copt, ",")) != NULL) {
87 char *value = strchr(key, '=');
88
89 if (value != NULL)
90 *value++ = '\0';
91 while (HX_isspace(*key))
92 ++key;
93 if (strcmp(key, "cipher") == 0) {
94 mo->dmcrypt_cipher = value;
95 if (cipher_digest_security(value) < 1)
96 fprintf(stderr, "Cipher \"%s\" is considered "
97 "insecure.\n", value);
98 } else if (strcmp(key, "fsk_cipher") == 0) {
99 mo->fsk_cipher = value;
100 if (cipher_digest_security(value) < 1)
101 fprintf(stderr, "Cipher \"%s\" is considered "
102 "insecure.\n", value);
103 } else if (strcmp(key, "fsk_hash") == 0) {
104 mo->fsk_hash = value;
105 if (cipher_digest_security(value) < 1)
106 fprintf(stderr, "Hash \"%s\" is considered "
107 "insecure.\n", value);
108 } else if (strcmp(key, "dm-timeout") == 0)
109 mo->dm_timeout = strtoul(value, NULL, 0);
110 else if (strcmp(key, "fstype") == 0)
111 mo->fstype = value;
112 else if (strcmp(key, "keyfile") == 0)
113 mo->fsk_file = value;
114 else if (strcmp(key, "keysize") == 0)
115 mo->trunc_keysize = strtoul(value, NULL, 0) / CHAR_BIT;
116 else if (strcmp(key, "fsck") == 0)
117 mo->fsck = true;
118 else if (strcmp(key, "loop") == 0)
119 /* automatically detected anyway */
120 l0g("loop mount option ignored\n");
121 else if (strcmp(key, "hash") == 0) {
122 mo->dmcrypt_hash = value;
123 if (cipher_digest_security(value) < 1)
124 fprintf(stderr, "Hash \"%s\" is considered "
125 "insecure.\n", value);
126 } else if (strcmp(key, "verbose") == 0)
127 Debug = pmtlog_path[PMTLOG_DBG][PMTLOG_STDERR] = true;
128 else {
129 if (!first)
130 HXmc_strcat(&passthru, ",");
131 first = false;
132 HXmc_strcat(&passthru, key);
133 if (value != NULL) {
134 HXmc_strcat(&passthru, "=");
135 HXmc_strcat(&passthru, value);
136 }
137 }
138
139 /* Options added to passthrough, but also inspected by us. */
140 if (strcmp(key, "remount") == 0)
141 mo->remount = true;
142 else if (strcmp(key, "ro") == 0)
143 mo->readonly = LOSETUP_RO;
144 else if (strcmp(key, "rw") == 0)
145 mo->readonly = LOSETUP_RW;
146 }
147
148 if (*passthru != '\0') {
149 if (mo->extra_opts == NULL) {
150 mo->extra_opts = passthru;
151 } else if (*mo->extra_opts != '\0') {
152 HXmc_strcat(&mo->extra_opts, ",");
153 HXmc_strcat(&mo->extra_opts, passthru);
154 HXmc_free(passthru);
155 }
156 } else {
157 HXmc_free(passthru);
158 }
159 }
160
161 /**
162 * keyfile passthru (kfpt)
163 */
kfpt_selected(const char * c)164 static bool kfpt_selected(const char *c)
165 {
166 return c != NULL && strcmp(c, "none") == 0;
167 }
168
mtcr_get_mount_options(int * argc,const char *** argv,struct mount_options * opt)169 static bool mtcr_get_mount_options(int *argc, const char ***argv,
170 struct mount_options *opt)
171 {
172 struct stat sb;
173 struct HXoption options_table[] = {
174 {.sh = 'n', .type = HXTYPE_NONE, .ptr = &opt->no_update,
175 .help = "Do not update /etc/mtab"},
176 {.sh = 'o', .type = HXTYPE_STRING, .cb = mtcr_parse_suboptions,
177 .uptr = opt, .help = "Mount options"},
178 {.sh = 'r', .type = HXTYPE_NONE, .ptr = &opt->readonly,
179 .help = "Set up devices and mounts as read-only"},
180 {.sh = 'v', .type = HXTYPE_NONE, .ptr = &Debug,
181 .help = "Enable debugging"},
182 HXOPT_AUTOHELP,
183 HXOPT_TABLEEND,
184 };
185 bool kfpt;
186 int ret;
187
188 if (HX_getopt(options_table, argc, argv, HXOPT_USAGEONERR) !=
189 HXOPT_ERR_SUCCESS)
190 return false;
191
192 pmtlog_path[PMTLOG_DBG][PMTLOG_STDERR] = Debug;
193
194 if (opt->remount) {
195 if (*argc < 2 || *(*argv)[1] == '\0') {
196 fprintf(stderr, "%s: You need to specify the container "
197 "or its mountpoint\n", **argv);
198 return false;
199 }
200
201 /* Only absolute paths should be in mtab. */
202 ret = HX_realpath(&opt->object, (*argv)[1],
203 HX_REALPATH_DEFAULT | HX_REALPATH_ABSOLUTE);
204 if (ret < 0) {
205 fprintf(stderr, "realpath %s: %s\n",
206 (*argv)[1], strerror(-ret));
207 return false;
208 }
209 if (stat(opt->object, &sb) < 0) {
210 /* If it does not exist, it cannot be the container. */
211 opt->is_cont = false;
212 if (errno != ENOENT) {
213 fprintf(stderr, "stat %s: %s\n", opt->object,
214 strerror(errno));
215 return false;
216 }
217 } else {
218 /* If it is a directory, it cannot be the container either. */
219 if (!S_ISDIR(sb.st_mode))
220 opt->is_cont = true;
221 if (S_ISBLK(sb.st_mode))
222 opt->blkdev = true;
223 }
224
225 return true;
226 }
227
228 if (*argc < 2 || *(*argv)[1] == '\0') {
229 fprintf(stderr, "%s: You need to specify the device to mount\n",
230 **argv);
231 return false;
232 }
233 if (*argc < 3 || *(*argv)[2] == '\0') {
234 fprintf(stderr, "%s: You need to specify the mountpoint\n",
235 **argv);
236 return false;
237 }
238
239 ret = HX_realpath(&opt->container, (*argv)[1],
240 HX_REALPATH_DEFAULT | HX_REALPATH_ABSOLUTE);
241 if (ret < 0) {
242 fprintf(stderr, "realpath %s: %s\n",
243 (*argv)[1], strerror(-ret));
244 return false;
245 }
246 ret = HX_realpath(&opt->mountpoint, (*argv)[2],
247 HX_REALPATH_DEFAULT | HX_REALPATH_ABSOLUTE);
248 if (ret < 0) {
249 fprintf(stderr, "realpath %s: %s\n",
250 (*argv)[2], strerror(-ret));
251 return false;
252 }
253
254 if (stat(opt->mountpoint, &sb) < 0) {
255 fprintf(stderr, "%s: stat %s: %s\n", **argv, opt->mountpoint,
256 strerror(errno));
257 return false;
258 } else if (!S_ISDIR(sb.st_mode)) {
259 fprintf(stderr, "%s: %s is not a directory\n",
260 **argv, opt->mountpoint);
261 return false;
262 }
263
264 if (stat(opt->container, &sb) < 0) {
265 fprintf(stderr, "%s: stat %s: %s\n", **argv, opt->container,
266 strerror(errno));
267 return false;
268 } else if (S_ISBLK(sb.st_mode)) {
269 opt->blkdev = true;
270 } else if (!S_ISREG(sb.st_mode)) {
271 fprintf(stderr, "%s: %s must either be a regular file or "
272 "block device\n", **argv, opt->container);
273 return false;
274 }
275
276 kfpt = kfpt_selected(opt->fsk_cipher);
277 if (opt->fsk_file == NULL) {
278 if (opt->fsk_cipher != NULL)
279 fprintf(stderr, "%s: fsk_cipher is ignored because no "
280 "keyfile given\n", **argv);
281 if (opt->fsk_hash != NULL)
282 fprintf(stderr, "%s: fsk_hash is ignored because no "
283 "keyfile given\n", **argv);
284 } else {
285 if (opt->fsk_cipher == NULL) {
286 fprintf(stderr, "%s: No openssl cipher specified "
287 "(use -o fsk_cipher=xxx)\n", **argv);
288 return false;
289 } else if (!kfpt && opt->fsk_hash == NULL) {
290 fprintf(stderr, "%s: No openssl hash specified "
291 "(use -o fsk_hash=xxx)\n", **argv);
292 return false;
293 }
294 }
295
296 #ifdef HAVE_LIBCRYPTSETUP
297 ret = dmc_is_luks(opt->container, opt->blkdev);
298 if (ret > 0) {
299 /* LUKS */
300 if (opt->dmcrypt_cipher != NULL)
301 fprintf(stderr, "%s: dmcrypt cipher ignored for LUKS "
302 "volumes\n", **argv);
303 if (opt->dmcrypt_hash != NULL)
304 fprintf(stderr, "%s: dmcrypt hash ignored for LUKS "
305 "volumes\n", **argv);
306 } else if (ret == 0) {
307 /* PLAIN */
308 if (opt->dmcrypt_cipher == NULL) {
309 fprintf(stderr, "%s: No dmcrypt cipher specified "
310 "(use -o cipher=xxx)\n", **argv);
311 return false;
312 }
313 }
314 #endif
315
316 if (opt->dmcrypt_hash == NULL)
317 opt->dmcrypt_hash = "plain";
318 if (!kfpt)
319 opt->fsk_password = pmt_get_password(NULL);
320 return true;
321 }
322
mtcr_slurp_file(const char * file)323 static hxmc_t *mtcr_slurp_file(const char *file)
324 {
325 struct stat sb;
326 char tmp[4096];
327 hxmc_t *buf;
328 int fd;
329
330 if ((fd = open(file, O_RDONLY | O_BINARY)) < 0) {
331 fprintf(stderr, "Could not open %s: %s\n",
332 file, strerror(errno));
333 return NULL;
334 }
335
336 if (fstat(fd, &sb) == 0 && S_ISREG(sb.st_mode))
337 buf = HXmc_meminit(NULL, sb.st_size);
338 else
339 buf = HXmc_meminit(NULL, 4096 / CHAR_BIT);
340
341 if (buf == NULL) {
342 fprintf(stderr, "%s: %s\n", __func__, strerror(errno));
343 } else {
344 ssize_t ret;
345 while ((ret = read(fd, tmp, sizeof(tmp))) > 0)
346 HXmc_memcat(&buf, tmp, ret);
347 }
348 close(fd);
349 return buf;
350 }
351
352 /**
353 * mtcr_mount
354 *
355 * Returns positive non-zero for success.
356 */
mtcr_mount(struct mount_options * opt)357 static int mtcr_mount(struct mount_options *opt)
358 {
359 const char *mount_args[8];
360 const char *fsck_args[4];
361 struct stat sb;
362 int ret, argk;
363 hxmc_t *key;
364 struct ehd_mount mount_info;
365 struct ehd_mtreq mount_request = {
366 .container = opt->container,
367 .fs_cipher = opt->dmcrypt_cipher,
368 .fs_hash = opt->dmcrypt_hash,
369 .readonly = opt->readonly,
370
371 /* Hack for CRYPT_PLAIN. */
372 .trunc_keysize = 256 / CHAR_BIT,
373 };
374
375 if (opt->fsk_file == NULL) {
376 /* LUKS derives the key material on its own */
377 key = HXmc_meminit(opt->fsk_password,
378 HXmc_length(opt->fsk_password));
379 if (key == NULL) {
380 fprintf(stderr, "HXmc_dup: %s\n", strerror(errno));
381 return 0;
382 }
383 /* Leave trunc_keysize at 0 */
384 } else if (kfpt_selected(opt->fsk_cipher)) {
385 key = mtcr_slurp_file(opt->fsk_file);
386 if (key == NULL)
387 return 0;
388 mount_request.trunc_keysize = HXmc_length(key);
389 } else {
390 #ifdef HAVE_LIBCRYPTO
391 key = ehd_decrypt_key(opt->fsk_file, opt->fsk_hash,
392 opt->fsk_cipher, opt->fsk_password);
393 if (key == NULL) {
394 fprintf(stderr, "Error while decrypting fskey\n");
395 return 0;
396 }
397 mount_request.trunc_keysize = HXmc_length(key);
398 #else
399 fprintf(stderr, "mtcrypt was compiled without OpenSSL support\n");
400 return 0;
401 #endif
402 }
403
404 mount_request.key_data = key;
405 mount_request.key_size = HXmc_length(key);
406 if (opt->trunc_keysize != 0)
407 mount_request.trunc_keysize = opt->trunc_keysize;
408
409 w4rn("keysize=%u trunc_keysize=%u\n", mount_request.key_size,
410 mount_request.trunc_keysize);
411 if ((ret = ehd_load(&mount_request, &mount_info)) < 0) {
412 fprintf(stderr, "ehd_load: %s\n", strerror(errno));
413 return 0;
414 } else if (ret == 0) {
415 return 0;
416 }
417 HXmc_free(key);
418 if (mount_info.crypto_device == NULL) {
419 if (Debug)
420 fprintf(stderr, "No crypto device assigned\n");
421 ehd_unload(&mount_info);
422 ehd_mtfree(&mount_info);
423 return 0;
424 }
425
426 opt->dm_timeout *= 3;
427 while (stat(mount_info.crypto_device, &sb) < 0 && errno == ENOENT &&
428 opt->dm_timeout-- > 0)
429 usleep(333333);
430
431 if (opt->fsck) {
432 argk = 0;
433 fsck_args[argk++] = "fsck";
434 fsck_args[argk++] = "-p";
435 fsck_args[argk++] = mount_info.crypto_device;
436 fsck_args[argk] = NULL;
437 assert(argk < ARRAY_SIZE(fsck_args));
438
439 arglist_llog(fsck_args);
440 ret = HXproc_run_sync(fsck_args, HXPROC_VERBOSE);
441
442 /*
443 * Return codes higher than 1 indicate that manual intervention
444 * is required, therefore abort the mount/login.
445 * Lower than 0: internal error (e.g. fork).
446 */
447 if (ret != 0 && ret != 1) {
448 fprintf(stderr, "Automatic fsck failed, manual "
449 "intervention required, run_sync status %d\n",
450 ret);
451 ehd_unload(&mount_info);
452 ehd_mtfree(&mount_info);
453 return false;
454 }
455 }
456
457 argk = 0;
458 mount_args[argk++] = "mount";
459 if (opt->fstype != NULL) {
460 mount_args[argk++] = "-t";
461 mount_args[argk++] = opt->fstype;
462 }
463 if (opt->extra_opts != NULL) {
464 mount_args[argk++] = "-o";
465 mount_args[argk++] = opt->extra_opts;
466 }
467 mount_args[argk++] = mount_info.crypto_device;
468 mount_args[argk++] = opt->mountpoint;
469 mount_args[argk] = NULL;
470
471 assert(argk < ARRAY_SIZE(mount_args));
472 arglist_llog(mount_args);
473 if ((ret = HXproc_run_sync(mount_args, HXPROC_VERBOSE)) != 0) {
474 fprintf(stderr, "mount failed with run_sync status %d\n", ret);
475 ehd_unload(&mount_info);
476 ret = 0;
477 } else if ((ret = pmt_cmtab_add(opt->mountpoint,
478 mount_info.container, mount_info.loop_device,
479 mount_info.crypto_device)) <= 0) {
480 fprintf(stderr, "pmt_cmtab_add: %s\n", strerror(errno));
481 /* ignore error on cmtab - let user have his crypto */
482 } else if (opt->no_update) {
483 /* awesome logic */;
484 } else {
485 pmt_smtab_add(mount_info.container, opt->mountpoint,
486 "crypt", (opt->extra_opts != NULL) ?
487 opt->extra_opts : "defaults");
488 }
489
490 ehd_mtfree(&mount_info);
491 return ret;
492 }
493
mtcr_get_umount_options(int * argc,const char *** argv,struct umount_options * opt)494 static bool mtcr_get_umount_options(int *argc, const char ***argv,
495 struct umount_options *opt)
496 {
497 struct stat sb;
498 struct HXoption options_table[] = {
499 {.sh = 'f', .type = HXTYPE_NONE,
500 .help = "(Option ignored)"},
501 {.sh = 'n', .type = HXTYPE_NONE, .ptr = &opt->no_update,
502 .help = "Do not update /etc/mtab"},
503 {.sh = 'r', .type = HXTYPE_NONE, .ptr = &opt->ro_fallback,
504 .help = "(Option ignored)"},
505 {.sh = 'v', .type = HXTYPE_NONE, .ptr = &Debug,
506 .help = "Be verbose - enable debugging"},
507 HXOPT_AUTOHELP,
508 HXOPT_TABLEEND,
509 };
510 int ret;
511
512 if (HX_getopt(options_table, argc, argv, HXOPT_USAGEONERR) !=
513 HXOPT_ERR_SUCCESS)
514 return false;
515
516 pmtlog_path[PMTLOG_DBG][PMTLOG_STDERR] = Debug;
517
518 if (*argc < 2 || *(*argv)[1] == '\0') {
519 fprintf(stderr, "%s: You need to specify the container "
520 "or its mountpoint\n", **argv);
521 return false;
522 }
523
524 ret = HX_realpath(&opt->object, (*argv)[1],
525 HX_REALPATH_DEFAULT | HX_REALPATH_ABSOLUTE);
526 if (ret < 0) {
527 fprintf(stderr, "realpath %s: %s\n",
528 (*argv)[1], strerror(-ret));
529 return false;
530 }
531 if (stat(opt->object, &sb) < 0) {
532 /* If it does not exist, it cannot be the container. */
533 opt->is_cont = false;
534 if (errno != ENOENT) {
535 fprintf(stderr, "stat %s: %s\n", opt->object,
536 strerror(errno));
537 return false;
538 }
539 } else {
540 /* If it is a directory, it cannot be the container either. */
541 if (!S_ISDIR(sb.st_mode))
542 opt->is_cont = true;
543 if (S_ISBLK(sb.st_mode))
544 opt->blkdev = true;
545 }
546
547 return true;
548 }
549
550 /**
551 * mtcr_remount - remount the actual FS
552 */
mtcr_remount(struct mount_options * opt)553 static int mtcr_remount(struct mount_options *opt)
554 {
555 const char *rmt_args[5];
556 int ret, argk = 0;
557 char *mntpt, *cont;
558
559 ret = pmt_cmtab_get(opt->object, opt->is_cont ?
560 CMTABF_CONTAINER : CMTABF_MOUNTPOINT, &mntpt, &cont, NULL, NULL);
561 if (ret == 0) {
562 fprintf(stderr, "Nothing found that could be remounted.\n");
563 return 1;
564 } else if (ret < 0) {
565 fprintf(stderr, "pmt_cmtab_get: %s\n", strerror(-ret));
566 return ret;
567 }
568
569 if (!opt->no_update)
570 pmt_smtab_remove(mntpt, SMTABF_MOUNTPOINT);
571 rmt_args[argk++] = "mount";
572 rmt_args[argk++] = "-o";
573 rmt_args[argk++] = opt->extra_opts;
574 rmt_args[argk++] = mntpt;
575 rmt_args[argk] = NULL;
576 assert(argk < ARRAY_SIZE(rmt_args));
577
578 ret = HXproc_run_sync(rmt_args, HXPROC_VERBOSE);
579 if (ret != 0)
580 fprintf(stderr, "remount %s failed with run_sync status %d\n",
581 opt->object, ret);
582
583 if (!opt->no_update)
584 pmt_smtab_add(cont, mntpt, "crypt", (opt->extra_opts != NULL) ?
585 opt->extra_opts : "defaults");
586 free(mntpt);
587 free(cont);
588 return ret;
589 }
590
591 /**
592 */
mtcr_log_contents(const char * file)593 static void mtcr_log_contents(const char *file)
594 {
595 hxmc_t *ln = NULL;
596 FILE *fp;
597
598 if (file == NULL)
599 return;
600 w4rn("Dumping contents of %s\n", file);
601 if ((fp = fopen(file, "r")) == NULL) {
602 w4rn("Failed to open %s: %s\n", file, strerror(errno));
603 return;
604 }
605 while (HX_getl(&ln, fp) != NULL) {
606 HX_chomp(ln);
607 w4rn("%s\n", ln);
608 }
609 HXmc_free(ln);
610 fclose(fp);
611 }
612
613 /**
614 * mtcr_umount - unloads the EHD from mountpoint
615 *
616 * Returns positive non-zero for success.
617 */
mtcr_umount(struct umount_options * opt)618 static int mtcr_umount(struct umount_options *opt)
619 {
620 const char *umount_args[3];
621 int final_ret, ret, argk = 0;
622 struct ehd_mount mount_info;
623 char *mountpoint = NULL;
624
625 memset(&mount_info, 0, sizeof(mount_info));
626 ret = pmt_cmtab_get(opt->object, opt->is_cont ? CMTABF_CONTAINER :
627 CMTABF_MOUNTPOINT, &mountpoint, &mount_info.container,
628 &mount_info.loop_device, &mount_info.crypto_device);
629 if (ret < 0) {
630 fprintf(stderr, "pmt_cmtab_get: %s\n", strerror(-ret));
631 return 0;
632 } else if (ret == 0) {
633 fprintf(stderr, "No vfsmount found while searching for \"%s\" "
634 "as a container file, or as a mountpoint. (According "
635 "to the intersection of cmtab (%s) with smtabs)\n",
636 opt->object, pmt_cmtab_path());
637 mtcr_log_contents(pmt_cmtab_path());
638 mtcr_log_contents(pmt_smtab_path());
639 mtcr_log_contents(pmt_kmtab_path());
640 return 1;
641 } else {
642 if (ret & PMT_BY_CONTAINER)
643 w4rn("Found container in smtab\n");
644 if (ret & PMT_BY_CRYPTODEV)
645 w4rn("Found crypto device in smtab\n");
646 }
647
648 if (!opt->no_update)
649 pmt_smtab_remove(mountpoint, SMTABF_MOUNTPOINT);
650 pmt_cmtab_remove(mountpoint);
651
652 umount_args[argk++] = "umount";
653 umount_args[argk++] = mountpoint;
654 umount_args[argk] = NULL;
655
656 assert(argk < ARRAY_SIZE(umount_args));
657 arglist_llog(umount_args);
658 if ((final_ret = HXproc_run_sync(umount_args, HXPROC_VERBOSE)) != 0) {
659 fprintf(stderr, "umount %s failed with run_sync status %d\n",
660 opt->object, ret);
661 final_ret = 0;
662 ehd_unload(&mount_info);
663 } else if ((ret = ehd_unload(&mount_info)) <= 0) {
664 fprintf(stderr, "ehd_unload: %s\n", strerror(-ret));
665 final_ret = 0;
666 } else {
667 final_ret = 1;
668 }
669
670 return final_ret;
671 }
672
main(int argc,const char ** argv)673 int main(int argc, const char **argv)
674 {
675 struct stat sb;
676 int ret;
677
678 if (stat("/etc/mtab", &sb) == 0 && (sb.st_mode & S_IWUGO) == 0)
679 fprintf(stderr, "NOTE: mount.crypt does not support utab "
680 "(systems with no mtab or read-only mtab) yet. This "
681 "means that you will temporarily need to call "
682 "umount.crypt(8) rather than umount(8) to get crypto "
683 "volumes unmounted.\n");
684
685 ret = HX_init();
686 if (ret <= 0) {
687 fprintf(stderr, "HX_init: %s\n", strerror(errno));
688 abort();
689 }
690
691 Debug = false;
692 pmtlog_path[PMTLOG_ERR][PMTLOG_STDERR] = true;
693 pmtlog_prefix = HX_basename(*argv);
694
695 setenv("PATH", PMT_DFL_PATH, true);
696 #ifdef HAVE_LIBCRYPTO
697 OpenSSL_add_all_ciphers();
698 OpenSSL_add_all_digests();
699 #endif
700
701 /*
702 * When invoking umount.crypt via the libtool helper script,
703 * argv[0] is always "mount.crypt" due to the symlinking.
704 */
705 if (strncmp(HX_basename(*argv), "umount", 6) == 0 ||
706 getenv("PMT_DEBUG_UMOUNT") != NULL) {
707 struct umount_options opt;
708
709 memset(&opt, 0, sizeof(opt));
710 if (!mtcr_get_umount_options(&argc, &argv, &opt))
711 return EXIT_FAILURE;
712
713 return mtcr_umount(&opt) > 0 ? EXIT_SUCCESS : EXIT_FAILURE;
714 } else {
715 struct mount_options opt;
716
717 memset(&opt, 0, sizeof(opt));
718 if (!mtcr_get_mount_options(&argc, &argv, &opt))
719 return EXIT_FAILURE;
720
721 if (opt.remount)
722 return (mtcr_remount(&opt) > 0) ?
723 EXIT_SUCCESS : EXIT_FAILURE;
724 else
725 return (mtcr_mount(&opt) > 0) ?
726 EXIT_SUCCESS : EXIT_FAILURE;
727 }
728
729 return EXIT_FAILURE;
730 }
731