OSDN Git Service

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