368c503169f357488269141c8db4032435dc88c0
[dragonfly.git] / sbin / cryptdisks / cryptdisks.c
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 }