Add __printflike's where possible and fix all related bugs & issues.
[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 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 }