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