1bda92397SAlex Hornung /*
27a8ad07eSAlex Hornung * Copyright (c) 2009-2011 The DragonFly Project. All rights reserved.
3bda92397SAlex Hornung *
4bda92397SAlex Hornung * This code is derived from software contributed to The DragonFly Project
5bda92397SAlex Hornung * by Alex Hornung <ahornung@gmail.com>
6bda92397SAlex Hornung *
7bda92397SAlex Hornung * Redistribution and use in source and binary forms, with or without
8bda92397SAlex Hornung * modification, are permitted provided that the following conditions
9bda92397SAlex Hornung * are met:
10bda92397SAlex Hornung *
11bda92397SAlex Hornung * 1. Redistributions of source code must retain the above copyright
12bda92397SAlex Hornung * notice, this list of conditions and the following disclaimer.
13bda92397SAlex Hornung * 2. Redistributions in binary form must reproduce the above copyright
14bda92397SAlex Hornung * notice, this list of conditions and the following disclaimer in
15bda92397SAlex Hornung * the documentation and/or other materials provided with the
16bda92397SAlex Hornung * distribution.
17bda92397SAlex Hornung * 3. Neither the name of The DragonFly Project nor the names of its
18bda92397SAlex Hornung * contributors may be used to endorse or promote products derived
19bda92397SAlex Hornung * from this software without specific, prior written permission.
20bda92397SAlex Hornung *
21bda92397SAlex Hornung * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22bda92397SAlex Hornung * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23bda92397SAlex Hornung * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24bda92397SAlex Hornung * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25bda92397SAlex Hornung * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26bda92397SAlex Hornung * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27bda92397SAlex Hornung * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28bda92397SAlex Hornung * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29bda92397SAlex Hornung * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30bda92397SAlex Hornung * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31bda92397SAlex Hornung * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32bda92397SAlex Hornung * SUCH DAMAGE.
33bda92397SAlex Hornung */
34bda92397SAlex Hornung
35bda92397SAlex Hornung #include <stdio.h>
36bda92397SAlex Hornung #include <stdarg.h>
37bda92397SAlex Hornung #include <string.h>
385e1ed6baSAlex Hornung #include <stdlib.h>
39bda92397SAlex Hornung #include <unistd.h>
40bda92397SAlex Hornung #include <errno.h>
41bda92397SAlex Hornung #include <err.h>
42bda92397SAlex Hornung
43bda92397SAlex Hornung #include <libcryptsetup.h>
447a8ad07eSAlex Hornung #include <tcplay_api.h>
45bda92397SAlex Hornung
465e1ed6baSAlex Hornung #include "safe_mem.h"
475e1ed6baSAlex Hornung
485e1ed6baSAlex Hornung #define _iswhitespace(X) ((((X) == ' ') || ((X) == '\t'))?1:0)
49bda92397SAlex Hornung
50bda92397SAlex Hornung #define CRYPTDISKS_START 1
51bda92397SAlex Hornung #define CRYPTDISKS_STOP 2
52bda92397SAlex Hornung
537a8ad07eSAlex Hornung struct generic_opts {
547a8ad07eSAlex Hornung char *device;
557a8ad07eSAlex Hornung char *map_name;
567a8ad07eSAlex Hornung char *passphrase;
577a8ad07eSAlex Hornung const char *keyfiles[256];
587a8ad07eSAlex Hornung int nkeyfiles;
597a8ad07eSAlex Hornung int ntries;
607a8ad07eSAlex Hornung unsigned long long timeout;
617a8ad07eSAlex Hornung };
627a8ad07eSAlex Hornung
63b58f1e66SSascha Wildner static void syntax_error(const char *, ...) __printflike(1, 2);
64b58f1e66SSascha Wildner
65bda92397SAlex Hornung static int line_no = 1;
66bda92397SAlex Hornung
iswhitespace(char c)675e1ed6baSAlex Hornung static int iswhitespace(char c)
685e1ed6baSAlex Hornung {
695e1ed6baSAlex Hornung return _iswhitespace(c);
705e1ed6baSAlex Hornung }
715e1ed6baSAlex Hornung
iscomma(char c)725e1ed6baSAlex Hornung static int iscomma(char c)
735e1ed6baSAlex Hornung {
745e1ed6baSAlex Hornung return (c == ',');
755e1ed6baSAlex Hornung }
765e1ed6baSAlex Hornung
yesDialog(char * msg __unused)77bda92397SAlex Hornung static int yesDialog(char *msg __unused)
78bda92397SAlex Hornung {
79bda92397SAlex Hornung return 1;
80bda92397SAlex Hornung }
81bda92397SAlex Hornung
cmdLineLog(int level __unused,char * msg)82bda92397SAlex Hornung static void cmdLineLog(int level __unused, char *msg)
83bda92397SAlex Hornung {
84bda92397SAlex Hornung printf("%s", msg);
85bda92397SAlex Hornung }
86bda92397SAlex Hornung
87bda92397SAlex Hornung static struct interface_callbacks cmd_icb = {
88bda92397SAlex Hornung .yesDialog = yesDialog,
89bda92397SAlex Hornung .log = cmdLineLog,
90bda92397SAlex Hornung };
91bda92397SAlex Hornung
92bda92397SAlex Hornung static void
syntax_error(const char * fmt,...)93bda92397SAlex Hornung syntax_error(const char *fmt, ...)
94bda92397SAlex Hornung {
95bda92397SAlex Hornung char buf[1024];
96bda92397SAlex Hornung va_list ap;
97bda92397SAlex Hornung
98bda92397SAlex Hornung va_start(ap, fmt);
99bda92397SAlex Hornung vsnprintf(buf, sizeof(buf), fmt, ap);
100bda92397SAlex Hornung va_end(ap);
101bda92397SAlex Hornung errx(1, "crypttab: syntax error on line %d: %s\n", line_no, buf);
102bda92397SAlex Hornung }
103bda92397SAlex Hornung
104bda92397SAlex Hornung
105bda92397SAlex Hornung static int
entry_check_num_args(char ** tokens,int num)106bda92397SAlex Hornung entry_check_num_args(char **tokens, int num)
107bda92397SAlex Hornung {
108bda92397SAlex Hornung int i;
109bda92397SAlex Hornung
110bda92397SAlex Hornung for (i = 0; tokens[i] != NULL; i++)
111bda92397SAlex Hornung ;
112bda92397SAlex Hornung
113bda92397SAlex Hornung if (i < num) {
1145e1ed6baSAlex Hornung syntax_error("at least %d tokens were expected but only %d "
1155e1ed6baSAlex Hornung "were found", num, i);
116bda92397SAlex Hornung return 1;
117bda92397SAlex Hornung }
118bda92397SAlex Hornung return 0;
119bda92397SAlex Hornung }
120bda92397SAlex Hornung
121bda92397SAlex Hornung static int
line_tokenize(char * buffer,int (* is_sep)(char),char comment_char,char ** tokens)1225e1ed6baSAlex Hornung line_tokenize(char *buffer, int (*is_sep)(char), char comment_char, char **tokens)
1235e1ed6baSAlex Hornung {
1245e1ed6baSAlex Hornung int c, n, i;
1255e1ed6baSAlex Hornung int quote = 0;
1265e1ed6baSAlex Hornung
1275e1ed6baSAlex Hornung i = strlen(buffer) + 1;
1285e1ed6baSAlex Hornung c = 0;
1295e1ed6baSAlex Hornung
1305e1ed6baSAlex Hornung /* Skip leading white-space */
1315e1ed6baSAlex Hornung while ((_iswhitespace(buffer[c])) && (c < i)) c++;
1325e1ed6baSAlex Hornung
1335e1ed6baSAlex Hornung /*
1345e1ed6baSAlex Hornung * If this line effectively (after indentation) begins with the comment
1355e1ed6baSAlex Hornung * character, we ignore the rest of the line.
1365e1ed6baSAlex Hornung */
1375e1ed6baSAlex Hornung if (buffer[c] == comment_char)
1385e1ed6baSAlex Hornung return 0;
1395e1ed6baSAlex Hornung
1405e1ed6baSAlex Hornung tokens[0] = &buffer[c];
1415e1ed6baSAlex Hornung for (n = 1; c < i; c++) {
1425e1ed6baSAlex Hornung if (buffer[c] == '"') {
1435e1ed6baSAlex Hornung quote = !quote;
1445e1ed6baSAlex Hornung if (quote) {
1455e1ed6baSAlex Hornung if ((c >= 1) && (&buffer[c] != tokens[n-1])) {
1465e1ed6baSAlex Hornung #if 0
1475e1ed6baSAlex Hornung syntax_error("stray opening quote not "
1485e1ed6baSAlex Hornung "at beginning of token");
1495e1ed6baSAlex Hornung /* NOTREACHED */
1505e1ed6baSAlex Hornung #endif
1515e1ed6baSAlex Hornung } else {
1525e1ed6baSAlex Hornung tokens[n-1] = &buffer[c+1];
1535e1ed6baSAlex Hornung }
1545e1ed6baSAlex Hornung } else {
1555e1ed6baSAlex Hornung if ((c < i-1) && (!is_sep(buffer[c+1]))) {
1565e1ed6baSAlex Hornung #if 0
1575e1ed6baSAlex Hornung syntax_error("stray closing quote not "
1585e1ed6baSAlex Hornung "at end of token");
1595e1ed6baSAlex Hornung /* NOTREACHED */
1605e1ed6baSAlex Hornung #endif
1615e1ed6baSAlex Hornung } else {
1625e1ed6baSAlex Hornung buffer[c] = '\0';
1635e1ed6baSAlex Hornung }
1645e1ed6baSAlex Hornung }
1655e1ed6baSAlex Hornung }
1665e1ed6baSAlex Hornung
1675e1ed6baSAlex Hornung if (quote) {
1685e1ed6baSAlex Hornung continue;
1695e1ed6baSAlex Hornung }
1705e1ed6baSAlex Hornung
1715e1ed6baSAlex Hornung if (is_sep(buffer[c])) {
1725e1ed6baSAlex Hornung buffer[c++] = '\0';
1735e1ed6baSAlex Hornung while ((_iswhitespace(buffer[c])) && (c < i)) c++;
1745e1ed6baSAlex Hornung tokens[n++] = &buffer[c--];
1755e1ed6baSAlex Hornung }
1765e1ed6baSAlex Hornung }
1775e1ed6baSAlex Hornung tokens[n] = NULL;
1785e1ed6baSAlex Hornung
1795e1ed6baSAlex Hornung if (quote) {
1805e1ed6baSAlex Hornung tokens[0] = NULL;
1815e1ed6baSAlex Hornung return 0;
1825e1ed6baSAlex Hornung }
1835e1ed6baSAlex Hornung
1845e1ed6baSAlex Hornung return n;
1855e1ed6baSAlex Hornung }
1865e1ed6baSAlex Hornung
1875e1ed6baSAlex Hornung static int
parse_crypt_options(struct generic_opts * go,char * option)1887a8ad07eSAlex Hornung parse_crypt_options(struct generic_opts *go, char *option)
1895e1ed6baSAlex Hornung {
1905e1ed6baSAlex Hornung char *parameter, *endptr;
1915e1ed6baSAlex Hornung char *buf;
1925e1ed6baSAlex Hornung long lval;
1935e1ed6baSAlex Hornung unsigned long long ullval;
1945e1ed6baSAlex Hornung int noparam = 0;
1955e1ed6baSAlex Hornung FILE *fd;
1965e1ed6baSAlex Hornung
1975e1ed6baSAlex Hornung parameter = strchr(option, '=');
1985e1ed6baSAlex Hornung noparam = (parameter == NULL);
1995e1ed6baSAlex Hornung if (!noparam)
2005e1ed6baSAlex Hornung {
2015e1ed6baSAlex Hornung *parameter = '\0';
2025e1ed6baSAlex Hornung ++parameter;
2035e1ed6baSAlex Hornung }
2045e1ed6baSAlex Hornung
2055e1ed6baSAlex Hornung if (strcmp(option, "tries") == 0) {
2065e1ed6baSAlex Hornung if (noparam)
2075e1ed6baSAlex Hornung syntax_error("The option 'tries' needs a parameter");
2085e1ed6baSAlex Hornung /* NOTREACHED */
2095e1ed6baSAlex Hornung
2105e1ed6baSAlex Hornung lval = strtol(parameter, &endptr, 10);
2115e1ed6baSAlex Hornung if (*endptr != '\0')
2125e1ed6baSAlex Hornung syntax_error("The option 'tries' expects an integer "
2135e1ed6baSAlex Hornung "parameter, not '%s'", parameter);
2145e1ed6baSAlex Hornung /* NOTREACHED */
2155e1ed6baSAlex Hornung
2167a8ad07eSAlex Hornung go->ntries = (int)lval;
2175e1ed6baSAlex Hornung } else if (strcmp(option, "timeout") == 0) {
2185e1ed6baSAlex Hornung if (noparam)
2195e1ed6baSAlex Hornung syntax_error("The option 'timeout' needs a parameter");
2205e1ed6baSAlex Hornung /* NOTREACHED */
2215e1ed6baSAlex Hornung
2225e1ed6baSAlex Hornung ullval = strtoull(parameter, &endptr, 10);
2235e1ed6baSAlex Hornung if (*endptr != '\0')
2245e1ed6baSAlex Hornung syntax_error("The option 'timeout' expects an integer "
2255e1ed6baSAlex Hornung "parameter, not '%s'", parameter);
2265e1ed6baSAlex Hornung /* NOTREACHED */
2275e1ed6baSAlex Hornung
2287a8ad07eSAlex Hornung go->timeout = ullval;
2295e1ed6baSAlex Hornung } else if (strcmp(option, "keyscript") == 0) {
2301c482147SSascha Wildner size_t keymem_len = 8192;
2311c482147SSascha Wildner
2325e1ed6baSAlex Hornung if (noparam)
2335e1ed6baSAlex Hornung syntax_error("The option 'keyscript' needs a parameter");
2345e1ed6baSAlex Hornung /* NOTREACHED */
2355e1ed6baSAlex Hornung
2365e1ed6baSAlex Hornung /* Allocate safe key memory */
2371c482147SSascha Wildner buf = alloc_safe_mem(keymem_len);
23844053572SAlex Hornung if (buf == NULL)
23944053572SAlex Hornung err(1, "Could not allocate safe memory");
24044053572SAlex Hornung /* NOTREACHED */
2415e1ed6baSAlex Hornung
2425e1ed6baSAlex Hornung fd = popen(parameter, "r");
24344053572SAlex Hornung if (fd == NULL)
24444053572SAlex Hornung syntax_error("The 'keyscript' file could not be run");
24544053572SAlex Hornung /* NOTREACHED */
24644053572SAlex Hornung
2471c482147SSascha Wildner if ((fread(buf, 1, keymem_len, fd)) == 0)
2485e1ed6baSAlex Hornung syntax_error("The 'keyscript' program failed");
2495e1ed6baSAlex Hornung /* NOTREACHED */
2505e1ed6baSAlex Hornung pclose(fd);
2515e1ed6baSAlex Hornung
2525e1ed6baSAlex Hornung /* Get rid of trailing new-line */
2535e1ed6baSAlex Hornung if ((endptr = strrchr(buf, '\n')) != NULL)
2545e1ed6baSAlex Hornung *endptr = '\0';
2555e1ed6baSAlex Hornung
2567a8ad07eSAlex Hornung go->passphrase = buf;
2575e1ed6baSAlex Hornung } else if (strcmp(option, "none") == 0) {
2585e1ed6baSAlex Hornung /* Valid option, does nothing */
2595e1ed6baSAlex Hornung } else {
2605e1ed6baSAlex Hornung syntax_error("Unknown option: %s", option);
2615e1ed6baSAlex Hornung /* NOTREACHED */
2625e1ed6baSAlex Hornung }
2635e1ed6baSAlex Hornung
2645e1ed6baSAlex Hornung return 0;
2655e1ed6baSAlex Hornung }
2665e1ed6baSAlex Hornung
2677a8ad07eSAlex Hornung static void
generic_opts_to_luks(struct crypt_options * co,struct generic_opts * go)2687a8ad07eSAlex Hornung generic_opts_to_luks(struct crypt_options *co, struct generic_opts *go)
2697a8ad07eSAlex Hornung {
2707a8ad07eSAlex Hornung if (go->nkeyfiles > 1)
2717a8ad07eSAlex Hornung fprintf(stderr, "crypttab: Warning: LUKS only supports one "
2727a8ad07eSAlex Hornung "keyfile; on line %d\n", line_no);
2737a8ad07eSAlex Hornung
2747a8ad07eSAlex Hornung co->icb = &cmd_icb;
2757a8ad07eSAlex Hornung co->tries = go->ntries;
2767a8ad07eSAlex Hornung co->name = go->map_name;
2777a8ad07eSAlex Hornung co->device = go->device;
2787a8ad07eSAlex Hornung co->key_file = (go->nkeyfiles == 1) ? go->keyfiles[0] : NULL;
2797a8ad07eSAlex Hornung co->passphrase = go->passphrase;
2807a8ad07eSAlex Hornung co->timeout = go->timeout;
2817a8ad07eSAlex Hornung }
2827a8ad07eSAlex Hornung
2835e1ed6baSAlex Hornung static int
entry_parser(char ** tokens,char ** options,int type)2845e1ed6baSAlex Hornung entry_parser(char **tokens, char **options, int type)
285bda92397SAlex Hornung {
286bda92397SAlex Hornung struct crypt_options co;
287*653318caSAlex Hornung tc_api_task tcplay_task;
2887a8ad07eSAlex Hornung struct generic_opts go;
2897a8ad07eSAlex Hornung int r, i, error, isluks;
290bda92397SAlex Hornung
291bda92397SAlex Hornung if (entry_check_num_args(tokens, 2) != 0)
292bda92397SAlex Hornung return 1;
293bda92397SAlex Hornung
2947a8ad07eSAlex Hornung bzero(&go, sizeof(go));
295bda92397SAlex Hornung bzero(&co, sizeof(co));
296bda92397SAlex Hornung
2977a8ad07eSAlex Hornung
2987a8ad07eSAlex Hornung go.ntries = 3;
2997a8ad07eSAlex Hornung go.map_name = tokens[0];
3007a8ad07eSAlex Hornung go.device = tokens[1];
301bda92397SAlex Hornung
3025e1ed6baSAlex Hornung /* (Try to) parse extra options */
3035e1ed6baSAlex Hornung for (i = 0; options[i] != NULL; i++)
3047a8ad07eSAlex Hornung parse_crypt_options(&go, options[i]);
3055e1ed6baSAlex Hornung
3067a8ad07eSAlex Hornung if ((tokens[2] != NULL) && (strcmp(tokens[2], "none") != 0)) {
3077a8ad07eSAlex Hornung /* We got a keyfile */
3087a8ad07eSAlex Hornung go.keyfiles[go.nkeyfiles++] = tokens[2];
3097a8ad07eSAlex Hornung }
3107a8ad07eSAlex Hornung
3117a8ad07eSAlex Hornung generic_opts_to_luks(&co, &go);
3127a8ad07eSAlex Hornung
3137a8ad07eSAlex Hornung /*
3147a8ad07eSAlex Hornung * Check whether the device is a LUKS-formatted device; otherwise
3157a8ad07eSAlex Hornung * we assume its a TrueCrypt volume.
3167a8ad07eSAlex Hornung */
3177a8ad07eSAlex Hornung isluks = !crypt_isLuks(&co);
3187a8ad07eSAlex Hornung
3197a8ad07eSAlex Hornung if (!isluks) {
3207a8ad07eSAlex Hornung if ((error = tc_api_init(0)) != 0) {
3217a8ad07eSAlex Hornung fprintf(stderr, "crypttab: line %d: tc_api could not "
3227a8ad07eSAlex Hornung "be initialized\n", line_no);
323bda92397SAlex Hornung return 1;
324bda92397SAlex Hornung }
3257a8ad07eSAlex Hornung }
326bda92397SAlex Hornung
327bda92397SAlex Hornung if (type == CRYPTDISKS_STOP) {
3287a8ad07eSAlex Hornung if (isluks) {
329bda92397SAlex Hornung /* Check if the device is active */
330bda92397SAlex Hornung r = crypt_query_device(&co);
331bda92397SAlex Hornung
332bda92397SAlex Hornung /* If r > 0, then the device is active */
333bda92397SAlex Hornung if (r <= 0)
334bda92397SAlex Hornung return 0;
335bda92397SAlex Hornung
336bda92397SAlex Hornung /* Actually close the device */
337bda92397SAlex Hornung crypt_remove_device(&co);
3387a8ad07eSAlex Hornung } else {
3397a8ad07eSAlex Hornung /* Assume tcplay volume */
340*653318caSAlex Hornung if ((tcplay_task = tc_api_task_init("unmap")) == NULL) {
341*653318caSAlex Hornung fprintf(stderr, "tc_api_task_init failed.\n");
342*653318caSAlex Hornung goto tcplay_err;
343*653318caSAlex Hornung }
344*653318caSAlex Hornung if ((error = tc_api_task_set(tcplay_task, "dev", go.device))) {
345*653318caSAlex Hornung fprintf(stderr, "tc_api_task_set dev failed\n");
346*653318caSAlex Hornung goto tcplay_err;
347*653318caSAlex Hornung }
348*653318caSAlex Hornung if ((error = tc_api_task_set(tcplay_task, "map_name",
349*653318caSAlex Hornung go.map_name))) {
350*653318caSAlex Hornung fprintf(stderr, "tc_api_task_set map_name failed\n");
351*653318caSAlex Hornung goto tcplay_err;
352*653318caSAlex Hornung }
353*653318caSAlex Hornung if ((error = tc_api_task_do(tcplay_task))) {
354*653318caSAlex Hornung fprintf(stderr, "crypttab: line %d: device %s "
355*653318caSAlex Hornung "could not be unmapped: %s\n",
356*653318caSAlex Hornung line_no, go.device,
357*653318caSAlex Hornung tc_api_task_get_error(tcplay_task));
358*653318caSAlex Hornung goto tcplay_err;
359*653318caSAlex Hornung }
360*653318caSAlex Hornung if ((error = tc_api_task_uninit(tcplay_task))) {
361*653318caSAlex Hornung fprintf(stderr, "tc_api_task_uninit failed\n");
362*653318caSAlex Hornung goto tcplay_err;
363*653318caSAlex Hornung }
364*653318caSAlex Hornung
3657a8ad07eSAlex Hornung }
366bda92397SAlex Hornung } else if (type == CRYPTDISKS_START) {
3677a8ad07eSAlex Hornung /* Open the device */
3687a8ad07eSAlex Hornung if (isluks) {
3697a8ad07eSAlex Hornung if ((error = crypt_luksOpen(&co)) != 0) {
3707a8ad07eSAlex Hornung fprintf(stderr, "crypttab: line %d: device %s "
3717a8ad07eSAlex Hornung "could not be mapped/opened\n",
372*653318caSAlex Hornung line_no, co.device);
3737a8ad07eSAlex Hornung return 1;
3747a8ad07eSAlex Hornung }
3757a8ad07eSAlex Hornung } else {
376*653318caSAlex Hornung if ((tcplay_task = tc_api_task_init("map")) == NULL) {
377*653318caSAlex Hornung fprintf(stderr, "tc_api_task_init failed.\n");
378*653318caSAlex Hornung goto tcplay_err;
379*653318caSAlex Hornung }
380*653318caSAlex Hornung if ((error = tc_api_task_set(tcplay_task, "dev", go.device))) {
381*653318caSAlex Hornung fprintf(stderr, "tc_api_task_set dev failed\n");
382*653318caSAlex Hornung goto tcplay_err;
383*653318caSAlex Hornung }
384*653318caSAlex Hornung if ((error = tc_api_task_set(tcplay_task, "map_name",
385*653318caSAlex Hornung go.map_name))) {
386*653318caSAlex Hornung fprintf(stderr, "tc_api_task_set map_name failed\n");
387*653318caSAlex Hornung goto tcplay_err;
388*653318caSAlex Hornung }
389*653318caSAlex Hornung if ((error = tc_api_task_set(tcplay_task, "interactive",
390*653318caSAlex Hornung (go.passphrase != NULL) ? 0 : 1))) {
391*653318caSAlex Hornung fprintf(stderr, "tc_api_task_set map_name failed\n");
392*653318caSAlex Hornung goto tcplay_err;
393*653318caSAlex Hornung }
394*653318caSAlex Hornung if ((error = tc_api_task_set(tcplay_task, "retries",
395*653318caSAlex Hornung go.ntries))) {
396*653318caSAlex Hornung fprintf(stderr, "tc_api_task_set map_name failed\n");
397*653318caSAlex Hornung goto tcplay_err;
398*653318caSAlex Hornung }
399*653318caSAlex Hornung if ((error = tc_api_task_set(tcplay_task, "timeout",
400*653318caSAlex Hornung go.timeout))) {
401*653318caSAlex Hornung fprintf(stderr, "tc_api_task_set map_name failed\n");
402*653318caSAlex Hornung goto tcplay_err;
403*653318caSAlex Hornung }
404*653318caSAlex Hornung
405*653318caSAlex Hornung if (go.passphrase != NULL) {
406*653318caSAlex Hornung if ((error = tc_api_task_set(tcplay_task, "passphrase",
407*653318caSAlex Hornung go.passphrase))) {
408*653318caSAlex Hornung fprintf(stderr, "tc_api_task_set map_name failed\n");
409*653318caSAlex Hornung goto tcplay_err;
410*653318caSAlex Hornung }
411*653318caSAlex Hornung }
412*653318caSAlex Hornung
413*653318caSAlex Hornung for (i = 0; i < go.nkeyfiles; i++) {
414*653318caSAlex Hornung if ((error = tc_api_task_set(tcplay_task, "keyfiles",
415*653318caSAlex Hornung go.keyfiles[i]))) {
416*653318caSAlex Hornung fprintf(stderr, "tc_api_task_set keyfile failed\n");
417*653318caSAlex Hornung goto tcplay_err;
418*653318caSAlex Hornung }
419*653318caSAlex Hornung }
420*653318caSAlex Hornung if ((error = tc_api_task_do(tcplay_task))) {
4217a8ad07eSAlex Hornung fprintf(stderr, "crypttab: line %d: device %s "
4227a8ad07eSAlex Hornung "could not be mapped/opened: %s\n",
423*653318caSAlex Hornung line_no, go.device,
424*653318caSAlex Hornung tc_api_task_get_error(tcplay_task));
425*653318caSAlex Hornung goto tcplay_err;
426*653318caSAlex Hornung }
427*653318caSAlex Hornung if ((error = tc_api_task_uninit(tcplay_task))) {
428*653318caSAlex Hornung fprintf(stderr, "tc_api_task_uninit failed\n");
429*653318caSAlex Hornung goto tcplay_err;
4307a8ad07eSAlex Hornung }
4317a8ad07eSAlex Hornung }
432bda92397SAlex Hornung }
433bda92397SAlex Hornung
4347a8ad07eSAlex Hornung if (!isluks)
4357a8ad07eSAlex Hornung tc_api_uninit();
436bda92397SAlex Hornung
437bda92397SAlex Hornung return 0;
438*653318caSAlex Hornung
439*653318caSAlex Hornung tcplay_err:
440*653318caSAlex Hornung tc_api_uninit();
441*653318caSAlex Hornung return 1;
442bda92397SAlex Hornung }
443bda92397SAlex Hornung
444bda92397SAlex Hornung static int
process_line(FILE * fd,int type)445bda92397SAlex Hornung process_line(FILE* fd, int type)
446bda92397SAlex Hornung {
447bda92397SAlex Hornung char buffer[4096];
448bda92397SAlex Hornung char *tokens[256];
4495e1ed6baSAlex Hornung char *options[256];
450bda92397SAlex Hornung int c, n, i = 0;
451bda92397SAlex Hornung int ret = 0;
452bda92397SAlex Hornung
453bda92397SAlex Hornung while (((c = fgetc(fd)) != EOF) && (c != '\n')) {
454bda92397SAlex Hornung buffer[i++] = (char)c;
455bda92397SAlex Hornung if (i == (sizeof(buffer) -1))
456bda92397SAlex Hornung break;
457bda92397SAlex Hornung }
458bda92397SAlex Hornung buffer[i] = '\0';
459bda92397SAlex Hornung
460bda92397SAlex Hornung if (feof(fd) || ferror(fd))
461bda92397SAlex Hornung ret = 1;
462bda92397SAlex Hornung
463bda92397SAlex Hornung
4645e1ed6baSAlex Hornung n = line_tokenize(buffer, &iswhitespace, '#', tokens);
465bda92397SAlex Hornung
466bda92397SAlex Hornung /*
467bda92397SAlex Hornung * If there are not enough arguments for any function or it is
468bda92397SAlex Hornung * a line full of whitespaces, we just return here. Or if a
469bda92397SAlex Hornung * quote wasn't closed.
470bda92397SAlex Hornung */
4715e1ed6baSAlex Hornung if ((n < 2) || (tokens[0][0] == '\0'))
472bda92397SAlex Hornung return ret;
473bda92397SAlex Hornung
4745e1ed6baSAlex Hornung /*
4755e1ed6baSAlex Hornung * If there are at least 4 tokens, one of them (the last) is a list
4765e1ed6baSAlex Hornung * of options.
4775e1ed6baSAlex Hornung */
4785e1ed6baSAlex Hornung if (n >= 4)
4795e1ed6baSAlex Hornung {
4805e1ed6baSAlex Hornung i = line_tokenize(tokens[3], &iscomma, '#', options);
4815e1ed6baSAlex Hornung if (i == 0)
4825e1ed6baSAlex Hornung syntax_error("Invalid expression in options token");
4835e1ed6baSAlex Hornung /* NOTREACHED */
4845e1ed6baSAlex Hornung }
4855e1ed6baSAlex Hornung
4865e1ed6baSAlex Hornung entry_parser(tokens, options, type);
487bda92397SAlex Hornung
488bda92397SAlex Hornung return ret;
489bda92397SAlex Hornung }
490bda92397SAlex Hornung
491bda92397SAlex Hornung
492bda92397SAlex Hornung int
main(int argc,char * argv[])493bda92397SAlex Hornung main(int argc, char *argv[])
494bda92397SAlex Hornung {
495bda92397SAlex Hornung FILE *fd;
496bda92397SAlex Hornung int ch, start = 0, stop = 0;
497bda92397SAlex Hornung
498bda92397SAlex Hornung while ((ch = getopt(argc, argv, "01")) != -1) {
499bda92397SAlex Hornung switch (ch) {
500bda92397SAlex Hornung case '1':
501bda92397SAlex Hornung start = 1;
502bda92397SAlex Hornung break;
503bda92397SAlex Hornung case '0':
504bda92397SAlex Hornung stop = 1;
505bda92397SAlex Hornung break;
506bda92397SAlex Hornung default:
507bda92397SAlex Hornung break;
508bda92397SAlex Hornung }
509bda92397SAlex Hornung }
510bda92397SAlex Hornung
511bda92397SAlex Hornung argc -= optind;
512bda92397SAlex Hornung argv += optind;
513bda92397SAlex Hornung
5145e1ed6baSAlex Hornung atexit(check_and_purge_safe_mem);
5155e1ed6baSAlex Hornung
516bda92397SAlex Hornung if ((start && stop) || (!start && !stop))
517bda92397SAlex Hornung errx(1, "please specify exactly one of -0 and -1");
518bda92397SAlex Hornung
519bda92397SAlex Hornung fd = fopen("/etc/crypttab", "r");
520bda92397SAlex Hornung if (fd == NULL)
521bda92397SAlex Hornung err(1, "fopen");
522bda92397SAlex Hornung /* NOTREACHED */
523bda92397SAlex Hornung
524bda92397SAlex Hornung while (process_line(fd, (start) ? CRYPTDISKS_START : CRYPTDISKS_STOP) == 0)
525bda92397SAlex Hornung ++line_no;
526bda92397SAlex Hornung
527bda92397SAlex Hornung fclose(fd);
528bda92397SAlex Hornung return 0;
529bda92397SAlex Hornung }
5305e1ed6baSAlex Hornung
531