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