2 * Copyright (c) 2009 The DragonFly Project. All rights reserved.
4 * This code is derived from software contributed to The DragonFly Project
5 * by Alex Hornung <ahornung@gmail.com>
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
17 * 3. Neither the name of The DragonFly Project nor the names of its
18 * contributors may be used to endorse or promote products derived
19 * from this software without specific, prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
43 #include <libcryptsetup.h>
47 #define _iswhitespace(X) ((((X) == ' ') || ((X) == '\t'))?1:0)
49 #define CRYPTDISKS_START 1
50 #define CRYPTDISKS_STOP 2
52 static void syntax_error(const char *, ...) __printflike(1, 2);
54 static int line_no = 1;
56 static int iswhitespace(char c)
58 return _iswhitespace(c);
61 static int iscomma(char c)
66 static int yesDialog(char *msg __unused)
71 static void cmdLineLog(int level __unused, char *msg)
76 static struct interface_callbacks cmd_icb = {
77 .yesDialog = yesDialog,
82 syntax_error(const char *fmt, ...)
88 vsnprintf(buf, sizeof(buf), fmt, ap);
90 errx(1, "crypttab: syntax error on line %d: %s\n", line_no, buf);
95 entry_check_num_args(char **tokens, int num)
99 for (i = 0; tokens[i] != NULL; i++)
103 syntax_error("at least %d tokens were expected but only %d "
104 "were found", num, i);
111 line_tokenize(char *buffer, int (*is_sep)(char), char comment_char, char **tokens)
116 i = strlen(buffer) + 1;
119 /* Skip leading white-space */
120 while ((_iswhitespace(buffer[c])) && (c < i)) c++;
123 * If this line effectively (after indentation) begins with the comment
124 * character, we ignore the rest of the line.
126 if (buffer[c] == comment_char)
129 tokens[0] = &buffer[c];
130 for (n = 1; c < i; c++) {
131 if (buffer[c] == '"') {
134 if ((c >= 1) && (&buffer[c] != tokens[n-1])) {
136 syntax_error("stray opening quote not "
137 "at beginning of token");
141 tokens[n-1] = &buffer[c+1];
144 if ((c < i-1) && (!is_sep(buffer[c+1]))) {
146 syntax_error("stray closing quote not "
160 if (is_sep(buffer[c])) {
162 while ((_iswhitespace(buffer[c])) && (c < i)) c++;
163 tokens[n++] = &buffer[c--];
177 parse_crypt_options(struct crypt_options *co, char *option)
179 char *parameter, *endptr;
182 unsigned long long ullval;
186 parameter = strchr(option, '=');
187 noparam = (parameter == NULL);
194 if (strcmp(option, "tries") == 0) {
196 syntax_error("The option 'tries' needs a parameter");
199 lval = strtol(parameter, &endptr, 10);
201 syntax_error("The option 'tries' expects an integer "
202 "parameter, not '%s'", parameter);
205 co->tries = (int)lval;
206 } else if (strcmp(option, "timeout") == 0) {
208 syntax_error("The option 'timeout' needs a parameter");
211 ullval = strtoull(parameter, &endptr, 10);
213 syntax_error("The option 'timeout' expects an integer "
214 "parameter, not '%s'", parameter);
217 co->timeout = ullval;
218 } else if (strcmp(option, "keyscript") == 0) {
220 syntax_error("The option 'keyscript' needs a parameter");
223 /* Allocate safe key memory */
224 buf = alloc_safe_mem(8192);
226 fd = popen(parameter, "r");
227 if ((fread(buf, 1, sizeof(buf), fd)) == 0)
228 syntax_error("The 'keyscript' program failed");
232 /* Get rid of trailing new-line */
233 if ((endptr = strrchr(buf, '\n')) != NULL)
236 co->passphrase = buf;
237 } else if (strcmp(option, "none") == 0) {
238 /* Valid option, does nothing */
240 syntax_error("Unknown option: %s", option);
248 entry_parser(char **tokens, char **options, int type)
250 struct crypt_options co;
253 if (entry_check_num_args(tokens, 2) != 0)
256 bzero(&co, sizeof(co));
261 co.device = tokens[1];
263 /* (Try to) parse extra options */
264 for (i = 0; options[i] != NULL; i++)
265 parse_crypt_options(&co, options[i]);
267 /* Verify that the device is indeed a LUKS-formatted device */
268 error = crypt_isLuks(&co);
270 printf("crypttab: line %d: device %s is not a luks device\n",
275 if (type == CRYPTDISKS_STOP) {
276 /* Check if the device is active */
277 r = crypt_query_device(&co);
279 /* If r > 0, then the device is active */
283 /* Actually close the device */
284 crypt_remove_device(&co);
285 } else if (type == CRYPTDISKS_START) {
286 if ((tokens[2] != NULL) && (strcmp(tokens[2], "none") != 0)) {
287 /* We got a keyfile */
288 co.key_file = tokens[2];
291 /* Open the device */
299 process_line(FILE* fd, int type)
307 while (((c = fgetc(fd)) != EOF) && (c != '\n')) {
308 buffer[i++] = (char)c;
309 if (i == (sizeof(buffer) -1))
314 if (feof(fd) || ferror(fd))
318 n = line_tokenize(buffer, &iswhitespace, '#', tokens);
321 * If there are not enough arguments for any function or it is
322 * a line full of whitespaces, we just return here. Or if a
323 * quote wasn't closed.
325 if ((n < 2) || (tokens[0][0] == '\0'))
329 * If there are at least 4 tokens, one of them (the last) is a list
334 i = line_tokenize(tokens[3], &iscomma, '#', options);
336 syntax_error("Invalid expression in options token");
340 entry_parser(tokens, options, type);
347 main(int argc, char *argv[])
350 int ch, start = 0, stop = 0;
352 while ((ch = getopt(argc, argv, "01")) != -1) {
368 atexit(check_and_purge_safe_mem);
370 if ((start && stop) || (!start && !stop))
371 errx(1, "please specify exactly one of -0 and -1");
373 fd = fopen("/etc/crypttab", "r");
378 while (process_line(fd, (start) ? CRYPTDISKS_START : CRYPTDISKS_STOP) == 0)