OSDN Git Service

Simplify test for right argc in cryptfs commands, and test more.
[android-x86/system-vold.git] / CryptCommandListener.cpp
1 /*
2  * Copyright (C) 2015 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include <stdlib.h>
18 #include <sys/socket.h>
19 #include <sys/stat.h>
20 #include <sys/types.h>
21 #include <netinet/in.h>
22 #include <arpa/inet.h>
23 #include <dirent.h>
24 #include <errno.h>
25 #include <fcntl.h>
26 #include <fs_mgr.h>
27 #include <stdio.h>
28 #include <string.h>
29 #include <stdint.h>
30 #include <inttypes.h>
31
32 #define LOG_TAG "VoldCryptCmdListener"
33
34 #include <android-base/logging.h>
35 #include <android-base/stringprintf.h>
36
37 #include <cutils/fs.h>
38 #include <cutils/log.h>
39 #include <cutils/sockets.h>
40
41 #include <sysutils/SocketClient.h>
42 #include <private/android_filesystem_config.h>
43
44 #include "CryptCommandListener.h"
45 #include "Process.h"
46 #include "ResponseCode.h"
47 #include "cryptfs.h"
48 #include "Ext4Crypt.h"
49 #include "Utils.h"
50
51 #define DUMP_ARGS 0
52
53 CryptCommandListener::CryptCommandListener() :
54 FrameworkListener("cryptd", true) {
55     registerCmd(new CryptfsCmd());
56 }
57
58 #if DUMP_ARGS
59 void CryptCommandListener::dumpArgs(int argc, char **argv, int argObscure) {
60     char buffer[4096];
61     char *p = buffer;
62
63     memset(buffer, 0, sizeof(buffer));
64     int i;
65     for (i = 0; i < argc; i++) {
66         unsigned int len = strlen(argv[i]) + 1; // Account for space
67         if (i == argObscure) {
68             len += 2; // Account for {}
69         }
70         if (((p - buffer) + len) < (sizeof(buffer)-1)) {
71             if (i == argObscure) {
72                 *p++ = '{';
73                 *p++ = '}';
74                 *p++ = ' ';
75                 continue;
76             }
77             strcpy(p, argv[i]);
78             p+= strlen(argv[i]);
79             if (i != (argc -1)) {
80                 *p++ = ' ';
81             }
82         }
83     }
84     SLOGD("%s", buffer);
85 }
86 #else
87 void CryptCommandListener::dumpArgs(int /*argc*/, char ** /*argv*/, int /*argObscure*/) { }
88 #endif
89
90 int CryptCommandListener::sendGenericOkFail(SocketClient *cli, int cond) {
91     if (!cond) {
92         return cli->sendMsg(ResponseCode::CommandOkay, "Command succeeded", false);
93     } else {
94         return cli->sendMsg(ResponseCode::OperationFailed, "Command failed", false);
95     }
96 }
97
98 CryptCommandListener::CryptfsCmd::CryptfsCmd() :
99                  VoldCommand("cryptfs") {
100 }
101
102 static int getType(const char* type)
103 {
104     if (!strcmp(type, "default")) {
105         return CRYPT_TYPE_DEFAULT;
106     } else if (!strcmp(type, "password")) {
107         return CRYPT_TYPE_PASSWORD;
108     } else if (!strcmp(type, "pin")) {
109         return CRYPT_TYPE_PIN;
110     } else if (!strcmp(type, "pattern")) {
111         return CRYPT_TYPE_PATTERN;
112     } else {
113         return -1;
114     }
115 }
116
117 static char* parseNull(char* arg) {
118     if (strcmp(arg, "!") == 0) {
119         return nullptr;
120     } else {
121         return arg;
122     }
123 }
124
125 #define CHECK_ARGC(expected, error) \
126     do { \
127         if (argc != (expected)) { \
128             cli->sendMsg(ResponseCode::CommandSyntaxError, ("Usage: cryptfs " error), false); \
129             return 0; \
130         } \
131     } while (0)
132
133 int CryptCommandListener::CryptfsCmd::runCommand(SocketClient *cli,
134                                                  int argc, char **argv) {
135     if ((cli->getUid() != 0) && (cli->getUid() != AID_SYSTEM)) {
136         cli->sendMsg(ResponseCode::CommandNoPermission, "No permission to run cryptfs commands", false);
137         return 0;
138     }
139
140     if (argc < 2) {
141         cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing Argument", false);
142         return 0;
143     }
144
145     int rc = 0;
146
147     std::string cmd(argv[1]);
148     if (!strcmp(argv[1], "checkpw")) {
149         CHECK_ARGC(3, "checkpw <passwd>");
150         dumpArgs(argc, argv, 2);
151         rc = cryptfs_check_passwd(argv[2]);
152     } else if (!strcmp(argv[1], "restart")) {
153         CHECK_ARGC(2, "restart");
154         dumpArgs(argc, argv, -1);
155         rc = cryptfs_restart();
156     } else if (!strcmp(argv[1], "cryptocomplete")) {
157         CHECK_ARGC(2, "cryptocomplete");
158         dumpArgs(argc, argv, -1);
159         rc = cryptfs_crypto_complete();
160     } else if (!strcmp(argv[1], "enablecrypto")) {
161         const char* syntax = "Usage: cryptfs enablecrypto <wipe|inplace> "
162                              "default|password|pin|pattern [passwd] [noui]";
163
164         // This should be replaced with a command line parser if more options
165         // are added
166         bool valid = true;
167         bool no_ui = false;
168         int type = CRYPT_TYPE_DEFAULT;
169         int options = 4; // Optional parameters are at this offset
170         if (argc < 4) {
171             // Minimum 4 parameters
172             valid = false;
173         } else if (strcmp(argv[2], "wipe") && strcmp(argv[2], "inplace") ) {
174             // Second parameter must be wipe or inplace
175             valid = false;
176         } else {
177             // Third parameter must be valid type
178             type = getType(argv[3]);
179             if (type == -1) {
180                 valid = false;
181             } else if (type != CRYPT_TYPE_DEFAULT) {
182                 options++;
183             }
184         }
185
186         if (valid) {
187             if(argc < options) {
188                 // Too few parameters
189                 valid = false;
190             } else if (argc == options) {
191                 // No more, done
192             } else if (argc == options + 1) {
193                 // One option, must be noui
194                 if (!strcmp(argv[options], "noui")) {
195                     no_ui = true;
196                 } else {
197                     valid = false;
198                 }
199             } else {
200                 // Too many options
201                 valid = false;
202             }
203         }
204
205         if (!valid ) {
206             cli->sendMsg(ResponseCode::CommandSyntaxError, syntax, false);
207             return 0;
208         }
209
210         dumpArgs(argc, argv, 4);
211
212         int tries;
213         for (tries = 0; tries < 2; ++tries) {
214             if (type == -1) {
215                 cli->sendMsg(ResponseCode::CommandSyntaxError, syntax,
216                              false);
217                 return 0;
218             } else if (type == CRYPT_TYPE_DEFAULT) {
219               rc = cryptfs_enable_default(argv[2], no_ui);
220             } else {
221                 rc = cryptfs_enable(argv[2], type, argv[4], no_ui);
222             }
223
224             if (rc == 0) {
225                 break;
226             } else if (tries == 0) {
227                 Process::killProcessesWithOpenFiles(DATA_MNT_POINT, SIGKILL);
228             }
229         }
230     } else if (!strcmp(argv[1], "enablefilecrypto")) {
231         CHECK_ARGC(2, "enablefilecrypto");
232         dumpArgs(argc, argv, -1);
233         rc = cryptfs_enable_file();
234     } else if (!strcmp(argv[1], "changepw")) {
235         const char* syntax = "Usage: cryptfs changepw "
236                              "default|password|pin|pattern [newpasswd]";
237         const char* password;
238         if (argc == 3) {
239             password = "";
240         } else if (argc == 4) {
241             password = argv[3];
242         } else {
243             cli->sendMsg(ResponseCode::CommandSyntaxError, syntax, false);
244             return 0;
245         }
246         int type = getType(argv[2]);
247         if (type == -1) {
248             cli->sendMsg(ResponseCode::CommandSyntaxError, syntax, false);
249             return 0;
250         }
251         SLOGD("cryptfs changepw %s {}", argv[2]);
252         rc = cryptfs_changepw(type, password);
253     } else if (!strcmp(argv[1], "verifypw")) {
254         CHECK_ARGC(3, "verifypw <passwd>");
255         SLOGD("cryptfs verifypw {}");
256         rc = cryptfs_verify_passwd(argv[2]);
257     } else if (!strcmp(argv[1], "getfield")) {
258         CHECK_ARGC(3, "getfield <fieldname>");
259         char *valbuf;
260         int valbuf_len = PROPERTY_VALUE_MAX;
261
262         dumpArgs(argc, argv, -1);
263
264         // Increase the buffer size until it is big enough for the field value stored.
265         while (1) {
266             valbuf = (char*)malloc(valbuf_len);
267             if (valbuf == NULL) {
268                 cli->sendMsg(ResponseCode::OperationFailed, "Failed to allocate memory", false);
269                 return 0;
270             }
271             rc = cryptfs_getfield(argv[2], valbuf, valbuf_len);
272             if (rc != CRYPTO_GETFIELD_ERROR_BUF_TOO_SMALL) {
273                 break;
274             }
275             free(valbuf);
276             valbuf_len *= 2;
277         }
278         if (rc == CRYPTO_GETFIELD_OK) {
279             cli->sendMsg(ResponseCode::CryptfsGetfieldResult, valbuf, false);
280         }
281         free(valbuf);
282     } else if (!strcmp(argv[1], "setfield")) {
283         CHECK_ARGC(4, "setfield <fieldname> <value>");
284         dumpArgs(argc, argv, -1);
285         rc = cryptfs_setfield(argv[2], argv[3]);
286     } else if (!strcmp(argv[1], "mountdefaultencrypted")) {
287         CHECK_ARGC(2, "mountdefaultencrypted");
288         SLOGD("cryptfs mountdefaultencrypted");
289         dumpArgs(argc, argv, -1);
290         rc = cryptfs_mount_default_encrypted();
291     } else if (!strcmp(argv[1], "getpwtype")) {
292         CHECK_ARGC(2, "getpwtype");
293         SLOGD("cryptfs getpwtype");
294         dumpArgs(argc, argv, -1);
295         switch(cryptfs_get_password_type()) {
296         case CRYPT_TYPE_PASSWORD:
297             cli->sendMsg(ResponseCode::PasswordTypeResult, "password", false);
298             return 0;
299         case CRYPT_TYPE_PATTERN:
300             cli->sendMsg(ResponseCode::PasswordTypeResult, "pattern", false);
301             return 0;
302         case CRYPT_TYPE_PIN:
303             cli->sendMsg(ResponseCode::PasswordTypeResult, "pin", false);
304             return 0;
305         case CRYPT_TYPE_DEFAULT:
306             cli->sendMsg(ResponseCode::PasswordTypeResult, "default", false);
307             return 0;
308         default:
309           /** @TODO better error and make sure handled by callers */
310             cli->sendMsg(ResponseCode::OpFailedStorageNotFound, "Error", false);
311             return 0;
312         }
313     } else if (!strcmp(argv[1], "getpw")) {
314         CHECK_ARGC(2, "getpw");
315         SLOGD("cryptfs getpw");
316         dumpArgs(argc, argv, -1);
317         const char* password = cryptfs_get_password();
318         if (password) {
319             char* message = 0;
320             int size = asprintf(&message, "{{sensitive}} %s", password);
321             if (size != -1) {
322                 cli->sendMsg(ResponseCode::CommandOkay, message, false);
323                 memset(message, 0, size);
324                 free (message);
325                 return 0;
326             }
327         }
328         rc = -1;
329     } else if (!strcmp(argv[1], "clearpw")) {
330         CHECK_ARGC(2, "clearpw");
331         SLOGD("cryptfs clearpw");
332         dumpArgs(argc, argv, -1);
333         cryptfs_clear_password();
334         rc = 0;
335     } else if (!strcmp(argv[1], "setusercryptopolicies")) {
336         CHECK_ARGC(3, "setusercryptopolicies <path>");
337         SLOGD("cryptfs setusercryptopolicies");
338         dumpArgs(argc, argv, -1);
339         rc = e4crypt_vold_set_user_crypto_policies(argv[2]);
340
341     } else if (!strcmp(argv[1], "isConvertibleToFBE")) {
342         CHECK_ARGC(2, "isConvertibleToFBE");
343         // ext4enc:TODO: send a CommandSyntaxError if argv[2] not an integer
344         SLOGD("cryptfs isConvertibleToFBE");
345         dumpArgs(argc, argv, -1);
346         rc = cryptfs_isConvertibleToFBE();
347
348     } else if (cmd == "create_user_key") {
349         CHECK_ARGC(5, "create_user_key <user> <serial> <ephemeral>");
350         return sendGenericOkFail(cli,
351                                  e4crypt_vold_create_user_key(atoi(argv[2]),
352                                                               atoi(argv[3]),
353                                                               atoi(argv[4]) != 0));
354
355     } else if (cmd == "destroy_user_key") {
356         CHECK_ARGC(3, "destroy_user_key <user>");
357         return sendGenericOkFail(cli, e4crypt_destroy_user_key(atoi(argv[2])));
358
359     } else if (cmd == "unlock_user_key") {
360         CHECK_ARGC(5, "unlock_user_key <user> <serial> <token>");
361         return sendGenericOkFail(cli, e4crypt_unlock_user_key(atoi(argv[2]), parseNull(argv[4])));
362
363     } else if (cmd == "lock_user_key") {
364         CHECK_ARGC(3, "lock_user_key <user>");
365         return sendGenericOkFail(cli, e4crypt_lock_user_key(atoi(argv[2])));
366
367     } else if (cmd == "prepare_user_storage") {
368         CHECK_ARGC(6, "prepare_user_storage <uuid> <user> <serial> <ephemeral>");
369         return sendGenericOkFail(cli, e4crypt_prepare_user_storage(
370                 parseNull(argv[2]), atoi(argv[3]), atoi(argv[4]) != 0));
371
372     } else {
373         dumpArgs(argc, argv, -1);
374         cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown cryptfs cmd", false);
375         return 0;
376     }
377
378     // Always report that the command succeeded and return the error code.
379     // The caller will check the return value to see what the error was.
380     char msg[255];
381     snprintf(msg, sizeof(msg), "%d", rc);
382     cli->sendMsg(ResponseCode::CommandOkay, msg, false);
383
384     return 0;
385 }