xref: /dragonfly/sbin/cryptdisks/cryptdisks.c (revision 10cbe914)
1 /*
2  * Copyright (c) 2009 The DragonFly Project.  All rights reserved.
3  *
4  * This code is derived from software contributed to The DragonFly Project
5  * by Alex Hornung <ahornung@gmail.com>
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
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
16  *    distribution.
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.
20  *
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
32  * SUCH DAMAGE.
33  */
34 
35 #include <stdio.h>
36 #include <stdarg.h>
37 #include <string.h>
38 #include <unistd.h>
39 #include <errno.h>
40 #include <err.h>
41 
42 #include <libcryptsetup.h>
43 
44 #define iswhitespace(X)	((((X) == ' ') || ((X) == '\t'))?1:0)
45 
46 #define CRYPTDISKS_START	1
47 #define CRYPTDISKS_STOP		2
48 
49 static int line_no = 1;
50 
51 static int yesDialog(char *msg __unused)
52 {
53 	return 1;
54 }
55 
56 static void cmdLineLog(int level __unused, char *msg)
57 {
58 	printf("%s", msg);
59 }
60 
61 static struct interface_callbacks cmd_icb = {
62 	.yesDialog = yesDialog,
63 	.log = cmdLineLog,
64 };
65 
66 static void
67 syntax_error(const char *fmt, ...)
68 {
69 	char buf[1024];
70 	va_list ap;
71 
72 	va_start(ap, fmt);
73 	vsnprintf(buf, sizeof(buf), fmt, ap);
74 	va_end(ap);
75 	errx(1, "crypttab: syntax error on line %d: %s\n", line_no, buf);
76 }
77 
78 
79 static int
80 entry_check_num_args(char **tokens, int num)
81 {
82 	int i;
83 
84 	for (i = 0; tokens[i] != NULL; i++)
85 		;
86 
87 	if (i < num) {
88 		syntax_error("at least %d tokens were expected but only %d were found", num, i);
89 		return 1;
90 	}
91 	return 0;
92 }
93 
94 static int
95 entry_parser(char **tokens, int type)
96 {
97 	struct crypt_options co;
98 	int r, error;
99 
100 	if (entry_check_num_args(tokens, 2) != 0)
101 		return 1;
102 
103 	bzero(&co, sizeof(co));
104 
105 	co.icb = &cmd_icb;
106 	co.name = tokens[0];
107 	co.device = tokens[1];
108 
109 	error = crypt_isLuks(&co);
110 	if (error) {
111 		printf("crypttab: line %d: device %s is not a luks device\n",
112 		    line_no, co.device);
113 		return 1;
114 	}
115 
116 	if (type == CRYPTDISKS_STOP) {
117 		/* Check if the device is active */
118 		r = crypt_query_device(&co);
119 
120 		/* If r > 0, then the device is active */
121 		if (r <= 0)
122 			return 0;
123 
124 		/* Actually close the device */
125 		crypt_remove_device(&co);
126 	} else if (type == CRYPTDISKS_START) {
127 		if ((tokens[2] != NULL) && (strcmp(tokens[2], "none") != 0)) {
128 			/* We got a keyfile */
129 			co.key_file = tokens[2];
130 		}
131 
132 		/* Open the device */
133 		crypt_luksOpen(&co);
134 	}
135 
136 	return 0;
137 }
138 
139 static int
140 process_line(FILE* fd, int type)
141 {
142 	char buffer[4096];
143 	char *tokens[256];
144 	int c, n, i = 0;
145 	int quote = 0;
146 	int ret = 0;
147 
148 	while (((c = fgetc(fd)) != EOF) && (c != '\n')) {
149 		buffer[i++] = (char)c;
150 		if (i == (sizeof(buffer) -1))
151 			break;
152 	}
153 	buffer[i] = '\0';
154 
155 	if (feof(fd) || ferror(fd))
156 		ret = 1;
157 	c = 0;
158 	while (((buffer[c] == ' ') || (buffer[c] == '\t')) && (c < i)) c++;
159 	/*
160 	 * If this line effectively (after indentation) begins with the comment
161 	 * character #, we ignore the rest of the line.
162 	 */
163 	if (buffer[c] == '#')
164 		return 0;
165 
166 	tokens[0] = &buffer[c];
167 	for (n = 1; c < i; c++) {
168 		if (buffer[c] == '"') {
169 			quote = !quote;
170 			if (quote) {
171 				if ((c >= 1) && (&buffer[c] != tokens[n-1])) {
172 					syntax_error("stray opening quote not at beginning of token");
173 					/* NOTREACHED */
174 				}
175 				tokens[n-1] = &buffer[c+1];
176 			} else {
177 				if ((c < i-1) && (!iswhitespace(buffer[c+1]))) {
178 					syntax_error("stray closing quote not at end of token");
179 					/* NOTREACHED */
180 				}
181 				buffer[c] = '\0';
182 			}
183 		}
184 
185 		if (quote) {
186 			continue;
187 		}
188 
189 		if ((buffer[c] == ' ') || (buffer[c] == '\t')) {
190 			buffer[c++] = '\0';
191 			while ((iswhitespace(buffer[c])) && (c < i)) c++;
192 			tokens[n++] = &buffer[c--];
193 		}
194 	}
195 	tokens[n] = NULL;
196 
197 	/*
198 	 * If there are not enough arguments for any function or it is
199 	 * a line full of whitespaces, we just return here. Or if a
200 	 * quote wasn't closed.
201 	 */
202 	if ((quote) || (n < 2) || (tokens[0][0] == '\0'))
203 		return ret;
204 
205 	entry_parser(tokens, type);
206 
207 	return ret;
208 }
209 
210 
211 int
212 main(int argc, char *argv[])
213 {
214 	FILE *fd;
215 	int ch, start = 0, stop = 0;
216 
217 	while ((ch = getopt(argc, argv, "01")) != -1) {
218 		switch (ch) {
219 		case '1':
220 			start = 1;
221 			break;
222 		case '0':
223 			stop = 1;
224 			break;
225 		default:
226 			break;
227 		}
228 	}
229 
230 	argc -= optind;
231 	argv += optind;
232 
233 	if ((start && stop) || (!start && !stop))
234 		errx(1, "please specify exactly one of -0 and -1");
235 
236 	fd = fopen("/etc/crypttab", "r");
237 	if (fd == NULL)
238 		err(1, "fopen");
239 		/* NOTREACHED */
240 
241 	while (process_line(fd, (start) ? CRYPTDISKS_START : CRYPTDISKS_STOP) == 0)
242 		++line_no;
243 
244 	fclose(fd);
245 	return 0;
246 }
247