OSDN Git Service

vold3: support the old SDCARD=xxx function
[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 <assert.h>
18 #include <stdlib.h>
19 #include <sys/socket.h>
20 #include <sys/stat.h>
21 #include <sys/types.h>
22 #include <netinet/in.h>
23 #include <arpa/inet.h>
24 #include <dirent.h>
25 #include <errno.h>
26 #include <fcntl.h>
27 #include <fs_mgr.h>
28 #include <stdio.h>
29 #include <string.h>
30 #include <stdint.h>
31 #include <inttypes.h>
32
33 #include <algorithm>
34 #include <thread>
35
36 #define LOG_TAG "VoldCryptCmdListener"
37
38 #include <android-base/logging.h>
39 #include <android-base/stringprintf.h>
40
41 #include <cutils/fs.h>
42 #include <cutils/log.h>
43 #include <cutils/sockets.h>
44
45 #include <sysutils/SocketClient.h>
46 #include <private/android_filesystem_config.h>
47
48 #include "CryptCommandListener.h"
49 #include "Process.h"
50 #include "ResponseCode.h"
51 #include "cryptfs.h"
52 #include "Ext4Crypt.h"
53 #include "Utils.h"
54
55 #define DUMP_ARGS 0
56
57 CryptCommandListener::CryptCommandListener() :
58 FrameworkListener("cryptd", true) {
59     registerCmd(new CryptfsCmd());
60 }
61
62 #if DUMP_ARGS
63 void CryptCommandListener::dumpArgs(int argc, char **argv, int argObscure) {
64     char buffer[4096];
65     char *p = buffer;
66
67     memset(buffer, 0, sizeof(buffer));
68     int i;
69     for (i = 0; i < argc; i++) {
70         unsigned int len = strlen(argv[i]) + 1; // Account for space
71         if (i == argObscure) {
72             len += 2; // Account for {}
73         }
74         if (((p - buffer) + len) < (sizeof(buffer)-1)) {
75             if (i == argObscure) {
76                 *p++ = '{';
77                 *p++ = '}';
78                 *p++ = ' ';
79                 continue;
80             }
81             strcpy(p, argv[i]);
82             p+= strlen(argv[i]);
83             if (i != (argc -1)) {
84                 *p++ = ' ';
85             }
86         }
87     }
88     SLOGD("%s", buffer);
89 }
90 #else
91 void CryptCommandListener::dumpArgs(int /*argc*/, char ** /*argv*/, int /*argObscure*/) { }
92 #endif
93
94 int CryptCommandListener::sendGenericOkFailOnBool(SocketClient *cli, bool success) {
95     if (success) {
96         return cli->sendMsg(ResponseCode::CommandOkay, "Command succeeded", false);
97     } else {
98         return cli->sendMsg(ResponseCode::OperationFailed, "Command failed", false);
99     }
100 }
101
102 CryptCommandListener::CryptfsCmd::CryptfsCmd() :
103                  VoldCommand("cryptfs") {
104 }
105
106 static int getType(const char* type)
107 {
108     if (!strcmp(type, "default")) {
109         return CRYPT_TYPE_DEFAULT;
110     } else if (!strcmp(type, "password")) {
111         return CRYPT_TYPE_PASSWORD;
112     } else if (!strcmp(type, "pin")) {
113         return CRYPT_TYPE_PIN;
114     } else if (!strcmp(type, "pattern")) {
115         return CRYPT_TYPE_PATTERN;
116     } else {
117         return -1;
118     }
119 }
120
121 static char* parseNull(char* arg) {
122     if (strcmp(arg, "!") == 0) {
123         return nullptr;
124     } else {
125         return arg;
126     }
127 }
128
129 static bool check_argc(SocketClient *cli, const std::string &subcommand, int argc,
130         int expected, std::string usage) {
131     assert(expected >= 2);
132     if (expected == 2) {
133         assert(usage.empty());
134     } else {
135         assert(!usage.empty());
136         assert(std::count(usage.begin(), usage.end(), ' ') + 3 == expected);
137     }
138     if (argc == expected) {
139         return true;
140     }
141     auto message = std::string() + "Usage: cryptfs " + subcommand;
142     if (!usage.empty()) {
143         message += " " + usage;
144     }
145     cli->sendMsg(ResponseCode::CommandSyntaxError, message.c_str(), false);
146     return false;
147 }
148
149 static int do_enablecrypto(char* arg2, char* arg4, int type, bool no_ui) {
150     int rc;
151     int tries;
152     for (tries = 0; tries < 2; ++tries) {
153         if (type == CRYPT_TYPE_DEFAULT) {
154             rc = cryptfs_enable_default(arg2, no_ui);
155         } else {
156             rc = cryptfs_enable(arg2, type, arg4, no_ui);
157         }
158
159         if (rc == 0) {
160             free(arg2);
161             free(arg4);
162             return 0;
163         } else if (tries == 0) {
164             Process::killProcessesWithOpenFiles(DATA_MNT_POINT, SIGKILL);
165         }
166     }
167
168     free(arg2);
169     free(arg4);
170     return -1;
171 }
172
173 int CryptCommandListener::CryptfsCmd::runCommand(SocketClient *cli,
174                                                  int argc, char **argv) {
175     if ((cli->getUid() != 0) && (cli->getUid() != AID_SYSTEM)) {
176         cli->sendMsg(ResponseCode::CommandNoPermission, "No permission to run cryptfs commands", false);
177         return 0;
178     }
179
180     if (argc < 2) {
181         cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing subcommand", false);
182         return 0;
183     }
184
185     int rc = 0;
186
187     std::string subcommand(argv[1]);
188     if (subcommand == "checkpw") {
189         if (!check_argc(cli, subcommand, argc, 3, "<passwd>")) return 0;
190         dumpArgs(argc, argv, 2);
191         rc = cryptfs_check_passwd(argv[2]);
192     } else if (subcommand == "restart") {
193         if (!check_argc(cli, subcommand, argc, 2, "")) return 0;
194         dumpArgs(argc, argv, -1);
195
196         // Spawn as thread so init can issue commands back to vold without
197         // causing deadlock, usually as a result of prep_data_fs.
198         std::thread(&cryptfs_restart).detach();
199     } else if (subcommand == "cryptocomplete") {
200         if (!check_argc(cli, subcommand, argc, 2, "")) return 0;
201         dumpArgs(argc, argv, -1);
202         rc = cryptfs_crypto_complete();
203     } else if (subcommand == "enablecrypto") {
204         const char* syntax = "Usage: cryptfs enablecrypto <wipe|inplace> "
205                              "default|password|pin|pattern [passwd] [noui]";
206
207         // This should be replaced with a command line parser if more options
208         // are added
209         bool valid = true;
210         bool no_ui = false;
211         int type = CRYPT_TYPE_DEFAULT;
212         int options = 4; // Optional parameters are at this offset
213         if (argc < 4) {
214             // Minimum 4 parameters
215             valid = false;
216         } else if (strcmp(argv[2], "wipe") && strcmp(argv[2], "inplace") ) {
217             // Second parameter must be wipe or inplace
218             valid = false;
219         } else {
220             // Third parameter must be valid type
221             type = getType(argv[3]);
222             if (type == -1) {
223                 valid = false;
224             } else if (type != CRYPT_TYPE_DEFAULT) {
225                 options++;
226             }
227         }
228
229         if (valid) {
230             if(argc < options) {
231                 // Too few parameters
232                 valid = false;
233             } else if (argc == options) {
234                 // No more, done
235             } else if (argc == options + 1) {
236                 // One option, must be noui
237                 if (!strcmp(argv[options], "noui")) {
238                     no_ui = true;
239                 } else {
240                     valid = false;
241                 }
242             } else {
243                 // Too many options
244                 valid = false;
245             }
246         }
247
248         if (!valid) {
249             cli->sendMsg(ResponseCode::CommandSyntaxError, syntax, false);
250             return 0;
251         }
252
253         dumpArgs(argc, argv, 4);
254
255         // Spawn as thread so init can issue commands back to vold without
256         // causing deadlock, usually as a result of prep_data_fs.
257         char* arg2 = argc > 2 ? strdup(argv[2]) : NULL;
258         char* arg4 = argc > 4 ? strdup(argv[4]) : NULL;
259         std::thread(&do_enablecrypto, arg2, arg4, type, no_ui).detach();
260     } else if (subcommand == "enablefilecrypto") {
261         if (!check_argc(cli, subcommand, argc, 2, "")) return 0;
262         dumpArgs(argc, argv, -1);
263         rc = cryptfs_enable_file();
264     } else if (subcommand == "changepw") {
265         const char* syntax = "Usage: cryptfs changepw "
266                              "default|password|pin|pattern [newpasswd]";
267         const char* password;
268         if (argc == 3) {
269             password = "";
270         } else if (argc == 4) {
271             password = argv[3];
272         } else {
273             cli->sendMsg(ResponseCode::CommandSyntaxError, syntax, false);
274             return 0;
275         }
276         int type = getType(argv[2]);
277         if (type == -1) {
278             cli->sendMsg(ResponseCode::CommandSyntaxError, syntax, false);
279             return 0;
280         }
281         SLOGD("cryptfs changepw %s {}", argv[2]);
282         rc = cryptfs_changepw(type, password);
283     } else if (subcommand == "verifypw") {
284         if (!check_argc(cli, subcommand, argc, 3, "<passwd>")) return 0;
285         SLOGD("cryptfs verifypw {}");
286         rc = cryptfs_verify_passwd(argv[2]);
287     } else if (subcommand == "getfield") {
288         if (!check_argc(cli, subcommand, argc, 3, "<fieldname>")) return 0;
289         char *valbuf;
290         int valbuf_len = PROPERTY_VALUE_MAX;
291
292         dumpArgs(argc, argv, -1);
293
294         // Increase the buffer size until it is big enough for the field value stored.
295         while (1) {
296             valbuf = (char*)malloc(valbuf_len);
297             if (valbuf == NULL) {
298                 cli->sendMsg(ResponseCode::OperationFailed, "Failed to allocate memory", false);
299                 return 0;
300             }
301             rc = cryptfs_getfield(argv[2], valbuf, valbuf_len);
302             if (rc != CRYPTO_GETFIELD_ERROR_BUF_TOO_SMALL) {
303                 break;
304             }
305             free(valbuf);
306             valbuf_len *= 2;
307         }
308         if (rc == CRYPTO_GETFIELD_OK) {
309             cli->sendMsg(ResponseCode::CryptfsGetfieldResult, valbuf, false);
310         }
311         free(valbuf);
312     } else if (subcommand == "setfield") {
313         if (!check_argc(cli, subcommand, argc, 4, "<fieldname> <value>")) return 0;
314         dumpArgs(argc, argv, -1);
315         rc = cryptfs_setfield(argv[2], argv[3]);
316     } else if (subcommand == "mountdefaultencrypted") {
317         if (!check_argc(cli, subcommand, argc, 2, "")) return 0;
318         SLOGD("cryptfs mountdefaultencrypted");
319         dumpArgs(argc, argv, -1);
320
321         // Spawn as thread so init can issue commands back to vold without
322         // causing deadlock, usually as a result of prep_data_fs.
323         std::thread(&cryptfs_mount_default_encrypted).detach();
324     } else if (subcommand == "getpwtype") {
325         if (!check_argc(cli, subcommand, argc, 2, "")) return 0;
326         SLOGD("cryptfs getpwtype");
327         dumpArgs(argc, argv, -1);
328         switch(cryptfs_get_password_type()) {
329         case CRYPT_TYPE_PASSWORD:
330             cli->sendMsg(ResponseCode::PasswordTypeResult, "password", false);
331             return 0;
332         case CRYPT_TYPE_PATTERN:
333             cli->sendMsg(ResponseCode::PasswordTypeResult, "pattern", false);
334             return 0;
335         case CRYPT_TYPE_PIN:
336             cli->sendMsg(ResponseCode::PasswordTypeResult, "pin", false);
337             return 0;
338         case CRYPT_TYPE_DEFAULT:
339             cli->sendMsg(ResponseCode::PasswordTypeResult, "default", false);
340             return 0;
341         default:
342           /** @TODO better error and make sure handled by callers */
343             cli->sendMsg(ResponseCode::OpFailedStorageNotFound, "Error", false);
344             return 0;
345         }
346     } else if (subcommand == "getpw") {
347         if (!check_argc(cli, subcommand, argc, 2, "")) return 0;
348         SLOGD("cryptfs getpw");
349         dumpArgs(argc, argv, -1);
350         const char* password = cryptfs_get_password();
351         if (password) {
352             char* message = 0;
353             int size = asprintf(&message, "{{sensitive}} %s", password);
354             if (size != -1) {
355                 cli->sendMsg(ResponseCode::CommandOkay, message, false);
356                 memset(message, 0, size);
357                 free (message);
358                 return 0;
359             }
360         }
361         rc = -1;
362     } else if (subcommand == "clearpw") {
363         if (!check_argc(cli, subcommand, argc, 2, "")) return 0;
364         SLOGD("cryptfs clearpw");
365         dumpArgs(argc, argv, -1);
366         cryptfs_clear_password();
367         rc = 0;
368
369     } else if (subcommand == "isConvertibleToFBE") {
370         if (!check_argc(cli, subcommand, argc, 2, "")) return 0;
371         // ext4enc:TODO: send a CommandSyntaxError if argv[2] not an integer
372         SLOGD("cryptfs isConvertibleToFBE");
373         dumpArgs(argc, argv, -1);
374         rc = cryptfs_isConvertibleToFBE();
375
376     } else if (subcommand == "init_user0") {
377         if (!check_argc(cli, subcommand, argc, 2, "")) return 0;
378         return sendGenericOkFailOnBool(cli, e4crypt_init_user0());
379
380     } else if (subcommand == "create_user_key") {
381         if (!check_argc(cli, subcommand, argc, 5, "<user> <serial> <ephemeral>")) return 0;
382         return sendGenericOkFailOnBool(cli, e4crypt_vold_create_user_key(
383             atoi(argv[2]), atoi(argv[3]), atoi(argv[4]) != 0));
384
385     } else if (subcommand == "destroy_user_key") {
386         if (!check_argc(cli, subcommand, argc, 3, "<user>")) return 0;
387         return sendGenericOkFailOnBool(cli, e4crypt_destroy_user_key(atoi(argv[2])));
388
389     } else if (subcommand == "add_user_key_auth") {
390         if (!check_argc(cli, subcommand, argc, 6, "<user> <serial> <token> <secret>")) return 0;
391         return sendGenericOkFailOnBool(cli, e4crypt_add_user_key_auth(
392             atoi(argv[2]), atoi(argv[3]), argv[4], argv[5]));
393
394     } else if (subcommand == "fixate_newest_user_key_auth") {
395         if (!check_argc(cli, subcommand, argc, 3, "<user>")) return 0;
396         return sendGenericOkFailOnBool(cli, e4crypt_fixate_newest_user_key_auth(atoi(argv[2])));
397
398     } else if (subcommand == "unlock_user_key") {
399         if (!check_argc(cli, subcommand, argc, 6, "<user> <serial> <token> <secret>")) return 0;
400         return sendGenericOkFailOnBool(cli, e4crypt_unlock_user_key(
401             atoi(argv[2]), atoi(argv[3]), argv[4], argv[5]));
402
403     } else if (subcommand == "lock_user_key") {
404         if (!check_argc(cli, subcommand, argc, 3, "<user>")) return 0;
405         return sendGenericOkFailOnBool(cli, e4crypt_lock_user_key(atoi(argv[2])));
406
407     } else if (subcommand == "prepare_user_storage") {
408         if (!check_argc(cli, subcommand, argc, 6, "<uuid> <user> <serial> <flags>")) return 0;
409         return sendGenericOkFailOnBool(cli, e4crypt_prepare_user_storage(
410             parseNull(argv[2]), atoi(argv[3]), atoi(argv[4]), atoi(argv[5])));
411
412     } else if (subcommand == "destroy_user_storage") {
413         if (!check_argc(cli, subcommand, argc, 5, "<uuid> <user> <flags>")) return 0;
414         return sendGenericOkFailOnBool(cli,
415                 e4crypt_destroy_user_storage(parseNull(argv[2]), atoi(argv[3]), atoi(argv[4])));
416
417     } else if (subcommand == "secdiscard") {
418         if (!check_argc(cli, subcommand, argc, 3, "<path>")) return 0;
419         return sendGenericOkFailOnBool(cli,
420                 e4crypt_secdiscard(parseNull(argv[2])));
421
422     } else {
423         dumpArgs(argc, argv, -1);
424         cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown cryptfs subcommand", false);
425         return 0;
426     }
427
428     // Always report that the command succeeded and return the error code.
429     // The caller will check the return value to see what the error was.
430     char msg[255];
431     snprintf(msg, sizeof(msg), "%d", rc);
432     cli->sendMsg(ResponseCode::CommandOkay, msg, false);
433
434     return 0;
435 }