1bda92397SAlex Hornung /* 2*7a8ad07eSAlex 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> 44*7a8ad07eSAlex 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 53*7a8ad07eSAlex Hornung struct generic_opts { 54*7a8ad07eSAlex Hornung char *device; 55*7a8ad07eSAlex Hornung char *map_name; 56*7a8ad07eSAlex Hornung char *passphrase; 57*7a8ad07eSAlex Hornung const char *keyfiles[256]; 58*7a8ad07eSAlex Hornung int nkeyfiles; 59*7a8ad07eSAlex Hornung int ntries; 60*7a8ad07eSAlex Hornung unsigned long long timeout; 61*7a8ad07eSAlex Hornung }; 62*7a8ad07eSAlex Hornung 63b58f1e66SSascha Wildner static void syntax_error(const char *, ...) __printflike(1, 2); 64b58f1e66SSascha Wildner 65bda92397SAlex Hornung static int line_no = 1; 66bda92397SAlex Hornung 675e1ed6baSAlex Hornung static int iswhitespace(char c) 685e1ed6baSAlex Hornung { 695e1ed6baSAlex Hornung return _iswhitespace(c); 705e1ed6baSAlex Hornung } 715e1ed6baSAlex Hornung 725e1ed6baSAlex Hornung static int iscomma(char c) 735e1ed6baSAlex Hornung { 745e1ed6baSAlex Hornung return (c == ','); 755e1ed6baSAlex Hornung } 765e1ed6baSAlex Hornung 77bda92397SAlex Hornung static int yesDialog(char *msg __unused) 78bda92397SAlex Hornung { 79bda92397SAlex Hornung return 1; 80bda92397SAlex Hornung } 81bda92397SAlex Hornung 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 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 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 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 188*7a8ad07eSAlex 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 216*7a8ad07eSAlex 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 228*7a8ad07eSAlex Hornung go->timeout = ullval; 2295e1ed6baSAlex Hornung } else if (strcmp(option, "keyscript") == 0) { 2305e1ed6baSAlex Hornung if (noparam) 2315e1ed6baSAlex Hornung syntax_error("The option 'keyscript' needs a parameter"); 2325e1ed6baSAlex Hornung /* NOTREACHED */ 2335e1ed6baSAlex Hornung 2345e1ed6baSAlex Hornung /* Allocate safe key memory */ 2355e1ed6baSAlex Hornung buf = alloc_safe_mem(8192); 23644053572SAlex Hornung if (buf == NULL) 23744053572SAlex Hornung err(1, "Could not allocate safe memory"); 23844053572SAlex Hornung /* NOTREACHED */ 2395e1ed6baSAlex Hornung 2405e1ed6baSAlex Hornung fd = popen(parameter, "r"); 24144053572SAlex Hornung if (fd == NULL) 24244053572SAlex Hornung syntax_error("The 'keyscript' file could not be run"); 24344053572SAlex Hornung /* NOTREACHED */ 24444053572SAlex Hornung 2455e1ed6baSAlex Hornung if ((fread(buf, 1, sizeof(buf), fd)) == 0) 2465e1ed6baSAlex Hornung syntax_error("The 'keyscript' program failed"); 2475e1ed6baSAlex Hornung /* NOTREACHED */ 2485e1ed6baSAlex Hornung pclose(fd); 2495e1ed6baSAlex Hornung 2505e1ed6baSAlex Hornung /* Get rid of trailing new-line */ 2515e1ed6baSAlex Hornung if ((endptr = strrchr(buf, '\n')) != NULL) 2525e1ed6baSAlex Hornung *endptr = '\0'; 2535e1ed6baSAlex Hornung 254*7a8ad07eSAlex Hornung go->passphrase = buf; 2555e1ed6baSAlex Hornung } else if (strcmp(option, "none") == 0) { 2565e1ed6baSAlex Hornung /* Valid option, does nothing */ 2575e1ed6baSAlex Hornung } else { 2585e1ed6baSAlex Hornung syntax_error("Unknown option: %s", option); 2595e1ed6baSAlex Hornung /* NOTREACHED */ 2605e1ed6baSAlex Hornung } 2615e1ed6baSAlex Hornung 2625e1ed6baSAlex Hornung return 0; 2635e1ed6baSAlex Hornung } 2645e1ed6baSAlex Hornung 265*7a8ad07eSAlex Hornung static void 266*7a8ad07eSAlex Hornung generic_opts_to_luks(struct crypt_options *co, struct generic_opts *go) 267*7a8ad07eSAlex Hornung { 268*7a8ad07eSAlex Hornung if (go->nkeyfiles > 1) 269*7a8ad07eSAlex Hornung fprintf(stderr, "crypttab: Warning: LUKS only supports one " 270*7a8ad07eSAlex Hornung "keyfile; on line %d\n", line_no); 271*7a8ad07eSAlex Hornung 272*7a8ad07eSAlex Hornung co->icb = &cmd_icb; 273*7a8ad07eSAlex Hornung co->tries = go->ntries; 274*7a8ad07eSAlex Hornung co->name = go->map_name; 275*7a8ad07eSAlex Hornung co->device = go->device; 276*7a8ad07eSAlex Hornung co->key_file = (go->nkeyfiles == 1) ? go->keyfiles[0] : NULL; 277*7a8ad07eSAlex Hornung co->passphrase = go->passphrase; 278*7a8ad07eSAlex Hornung co->timeout = go->timeout; 279*7a8ad07eSAlex Hornung } 280*7a8ad07eSAlex Hornung 281*7a8ad07eSAlex Hornung static void 282*7a8ad07eSAlex Hornung generic_opts_to_tcplay(struct tc_api_opts *tco, struct generic_opts *go) 283*7a8ad07eSAlex Hornung { 284*7a8ad07eSAlex Hornung /* Make sure keyfile array is NULL-terminated */ 285*7a8ad07eSAlex Hornung go->keyfiles[go->nkeyfiles] = NULL; 286*7a8ad07eSAlex Hornung 287*7a8ad07eSAlex Hornung tco->tc_interactive_prompt = (go->passphrase != NULL) ? 0 : 1; 288*7a8ad07eSAlex Hornung tco->tc_password_retries = go->ntries; 289*7a8ad07eSAlex Hornung tco->tc_map_name = go->map_name; 290*7a8ad07eSAlex Hornung tco->tc_device = go->device; 291*7a8ad07eSAlex Hornung tco->tc_keyfiles = go->keyfiles; 292*7a8ad07eSAlex Hornung tco->tc_passphrase = go->passphrase; 293*7a8ad07eSAlex Hornung tco->tc_prompt_timeout = go->timeout; 294*7a8ad07eSAlex Hornung } 295*7a8ad07eSAlex Hornung 2965e1ed6baSAlex Hornung static int 2975e1ed6baSAlex Hornung entry_parser(char **tokens, char **options, int type) 298bda92397SAlex Hornung { 299bda92397SAlex Hornung struct crypt_options co; 300*7a8ad07eSAlex Hornung struct tc_api_opts tco; 301*7a8ad07eSAlex Hornung struct generic_opts go; 302*7a8ad07eSAlex Hornung int r, i, error, isluks; 303bda92397SAlex Hornung 304bda92397SAlex Hornung if (entry_check_num_args(tokens, 2) != 0) 305bda92397SAlex Hornung return 1; 306bda92397SAlex Hornung 307*7a8ad07eSAlex Hornung bzero(&go, sizeof(go)); 308bda92397SAlex Hornung bzero(&co, sizeof(co)); 309*7a8ad07eSAlex Hornung bzero(&tco, sizeof(tco)); 310bda92397SAlex Hornung 311*7a8ad07eSAlex Hornung 312*7a8ad07eSAlex Hornung go.ntries = 3; 313*7a8ad07eSAlex Hornung go.map_name = tokens[0]; 314*7a8ad07eSAlex Hornung go.device = tokens[1]; 315bda92397SAlex Hornung 3165e1ed6baSAlex Hornung /* (Try to) parse extra options */ 3175e1ed6baSAlex Hornung for (i = 0; options[i] != NULL; i++) 318*7a8ad07eSAlex Hornung parse_crypt_options(&go, options[i]); 3195e1ed6baSAlex Hornung 320*7a8ad07eSAlex Hornung if ((tokens[2] != NULL) && (strcmp(tokens[2], "none") != 0)) { 321*7a8ad07eSAlex Hornung /* We got a keyfile */ 322*7a8ad07eSAlex Hornung go.keyfiles[go.nkeyfiles++] = tokens[2]; 323*7a8ad07eSAlex Hornung } 324*7a8ad07eSAlex Hornung 325*7a8ad07eSAlex Hornung generic_opts_to_luks(&co, &go); 326*7a8ad07eSAlex Hornung generic_opts_to_tcplay(&tco, &go); 327*7a8ad07eSAlex Hornung 328*7a8ad07eSAlex Hornung /* 329*7a8ad07eSAlex Hornung * Check whether the device is a LUKS-formatted device; otherwise 330*7a8ad07eSAlex Hornung * we assume its a TrueCrypt volume. 331*7a8ad07eSAlex Hornung */ 332*7a8ad07eSAlex Hornung isluks = !crypt_isLuks(&co); 333*7a8ad07eSAlex Hornung 334*7a8ad07eSAlex Hornung if (!isluks) { 335*7a8ad07eSAlex Hornung if ((error = tc_api_init(0)) != 0) { 336*7a8ad07eSAlex Hornung fprintf(stderr, "crypttab: line %d: tc_api could not " 337*7a8ad07eSAlex Hornung "be initialized\n", line_no); 338bda92397SAlex Hornung return 1; 339bda92397SAlex Hornung } 340*7a8ad07eSAlex Hornung } 341bda92397SAlex Hornung 342bda92397SAlex Hornung if (type == CRYPTDISKS_STOP) { 343*7a8ad07eSAlex Hornung if (isluks) { 344bda92397SAlex Hornung /* Check if the device is active */ 345bda92397SAlex Hornung r = crypt_query_device(&co); 346bda92397SAlex Hornung 347bda92397SAlex Hornung /* If r > 0, then the device is active */ 348bda92397SAlex Hornung if (r <= 0) 349bda92397SAlex Hornung return 0; 350bda92397SAlex Hornung 351bda92397SAlex Hornung /* Actually close the device */ 352bda92397SAlex Hornung crypt_remove_device(&co); 353*7a8ad07eSAlex Hornung } else { 354*7a8ad07eSAlex Hornung /* Assume tcplay volume */ 355*7a8ad07eSAlex Hornung tc_api_unmap_volume(&tco); 356*7a8ad07eSAlex Hornung } 357bda92397SAlex Hornung } else if (type == CRYPTDISKS_START) { 358*7a8ad07eSAlex Hornung /* Open the device */ 359*7a8ad07eSAlex Hornung if (isluks) { 360*7a8ad07eSAlex Hornung if ((error = crypt_luksOpen(&co)) != 0) { 361*7a8ad07eSAlex Hornung fprintf(stderr, "crypttab: line %d: device %s " 362*7a8ad07eSAlex Hornung "could not be mapped / opened\n", 363*7a8ad07eSAlex Hornung line_no, tco.tc_device); 364*7a8ad07eSAlex Hornung return 1; 365*7a8ad07eSAlex Hornung } 366*7a8ad07eSAlex Hornung } else { 367*7a8ad07eSAlex Hornung /* Assume tcplay volume */ 368*7a8ad07eSAlex Hornung if ((error = tc_api_map_volume(&tco)) != 0) { 369*7a8ad07eSAlex Hornung fprintf(stderr, "crypttab: line %d: device %s " 370*7a8ad07eSAlex Hornung "could not be mapped / opened: %s\n", 371*7a8ad07eSAlex Hornung line_no, tco.tc_device, 372*7a8ad07eSAlex Hornung tc_api_get_error_msg()); 373*7a8ad07eSAlex Hornung tc_api_uninit(); 374*7a8ad07eSAlex Hornung return 1; 375*7a8ad07eSAlex Hornung } 376*7a8ad07eSAlex Hornung } 377bda92397SAlex Hornung } 378bda92397SAlex Hornung 379*7a8ad07eSAlex Hornung if (!isluks) 380*7a8ad07eSAlex Hornung tc_api_uninit(); 381bda92397SAlex Hornung 382bda92397SAlex Hornung return 0; 383bda92397SAlex Hornung } 384bda92397SAlex Hornung 385bda92397SAlex Hornung static int 386bda92397SAlex Hornung process_line(FILE* fd, int type) 387bda92397SAlex Hornung { 388bda92397SAlex Hornung char buffer[4096]; 389bda92397SAlex Hornung char *tokens[256]; 3905e1ed6baSAlex Hornung char *options[256]; 391bda92397SAlex Hornung int c, n, i = 0; 392bda92397SAlex Hornung int ret = 0; 393bda92397SAlex Hornung 394bda92397SAlex Hornung while (((c = fgetc(fd)) != EOF) && (c != '\n')) { 395bda92397SAlex Hornung buffer[i++] = (char)c; 396bda92397SAlex Hornung if (i == (sizeof(buffer) -1)) 397bda92397SAlex Hornung break; 398bda92397SAlex Hornung } 399bda92397SAlex Hornung buffer[i] = '\0'; 400bda92397SAlex Hornung 401bda92397SAlex Hornung if (feof(fd) || ferror(fd)) 402bda92397SAlex Hornung ret = 1; 403bda92397SAlex Hornung 404bda92397SAlex Hornung 4055e1ed6baSAlex Hornung n = line_tokenize(buffer, &iswhitespace, '#', tokens); 406bda92397SAlex Hornung 407bda92397SAlex Hornung /* 408bda92397SAlex Hornung * If there are not enough arguments for any function or it is 409bda92397SAlex Hornung * a line full of whitespaces, we just return here. Or if a 410bda92397SAlex Hornung * quote wasn't closed. 411bda92397SAlex Hornung */ 4125e1ed6baSAlex Hornung if ((n < 2) || (tokens[0][0] == '\0')) 413bda92397SAlex Hornung return ret; 414bda92397SAlex Hornung 4155e1ed6baSAlex Hornung /* 4165e1ed6baSAlex Hornung * If there are at least 4 tokens, one of them (the last) is a list 4175e1ed6baSAlex Hornung * of options. 4185e1ed6baSAlex Hornung */ 4195e1ed6baSAlex Hornung if (n >= 4) 4205e1ed6baSAlex Hornung { 4215e1ed6baSAlex Hornung i = line_tokenize(tokens[3], &iscomma, '#', options); 4225e1ed6baSAlex Hornung if (i == 0) 4235e1ed6baSAlex Hornung syntax_error("Invalid expression in options token"); 4245e1ed6baSAlex Hornung /* NOTREACHED */ 4255e1ed6baSAlex Hornung } 4265e1ed6baSAlex Hornung 4275e1ed6baSAlex Hornung entry_parser(tokens, options, type); 428bda92397SAlex Hornung 429bda92397SAlex Hornung return ret; 430bda92397SAlex Hornung } 431bda92397SAlex Hornung 432bda92397SAlex Hornung 433bda92397SAlex Hornung int 434bda92397SAlex Hornung main(int argc, char *argv[]) 435bda92397SAlex Hornung { 436bda92397SAlex Hornung FILE *fd; 437bda92397SAlex Hornung int ch, start = 0, stop = 0; 438bda92397SAlex Hornung 439bda92397SAlex Hornung while ((ch = getopt(argc, argv, "01")) != -1) { 440bda92397SAlex Hornung switch (ch) { 441bda92397SAlex Hornung case '1': 442bda92397SAlex Hornung start = 1; 443bda92397SAlex Hornung break; 444bda92397SAlex Hornung case '0': 445bda92397SAlex Hornung stop = 1; 446bda92397SAlex Hornung break; 447bda92397SAlex Hornung default: 448bda92397SAlex Hornung break; 449bda92397SAlex Hornung } 450bda92397SAlex Hornung } 451bda92397SAlex Hornung 452bda92397SAlex Hornung argc -= optind; 453bda92397SAlex Hornung argv += optind; 454bda92397SAlex Hornung 4555e1ed6baSAlex Hornung atexit(check_and_purge_safe_mem); 4565e1ed6baSAlex Hornung 457bda92397SAlex Hornung if ((start && stop) || (!start && !stop)) 458bda92397SAlex Hornung errx(1, "please specify exactly one of -0 and -1"); 459bda92397SAlex Hornung 460bda92397SAlex Hornung fd = fopen("/etc/crypttab", "r"); 461bda92397SAlex Hornung if (fd == NULL) 462bda92397SAlex Hornung err(1, "fopen"); 463bda92397SAlex Hornung /* NOTREACHED */ 464bda92397SAlex Hornung 465bda92397SAlex Hornung while (process_line(fd, (start) ? CRYPTDISKS_START : CRYPTDISKS_STOP) == 0) 466bda92397SAlex Hornung ++line_no; 467bda92397SAlex Hornung 468bda92397SAlex Hornung fclose(fd); 469bda92397SAlex Hornung return 0; 470bda92397SAlex Hornung } 4715e1ed6baSAlex Hornung 472