2 * Copyright (C) 2015 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 #include <sys/socket.h>
20 #include <sys/types.h>
21 #include <netinet/in.h>
22 #include <arpa/inet.h>
35 #define LOG_TAG "VoldCryptCmdListener"
37 #include <android-base/logging.h>
38 #include <android-base/stringprintf.h>
40 #include <cutils/fs.h>
41 #include <cutils/log.h>
42 #include <cutils/sockets.h>
44 #include <sysutils/SocketClient.h>
45 #include <private/android_filesystem_config.h>
47 #include "CryptCommandListener.h"
49 #include "ResponseCode.h"
51 #include "Ext4Crypt.h"
56 CryptCommandListener::CryptCommandListener() :
57 FrameworkListener("cryptd", true) {
58 registerCmd(new CryptfsCmd());
62 void CryptCommandListener::dumpArgs(int argc, char **argv, int argObscure) {
66 memset(buffer, 0, sizeof(buffer));
68 for (i = 0; i < argc; i++) {
69 unsigned int len = strlen(argv[i]) + 1; // Account for space
70 if (i == argObscure) {
71 len += 2; // Account for {}
73 if (((p - buffer) + len) < (sizeof(buffer)-1)) {
74 if (i == argObscure) {
90 void CryptCommandListener::dumpArgs(int /*argc*/, char ** /*argv*/, int /*argObscure*/) { }
93 int CryptCommandListener::sendGenericOkFail(SocketClient *cli, int cond) {
95 return cli->sendMsg(ResponseCode::CommandOkay, "Command succeeded", false);
97 return cli->sendMsg(ResponseCode::OperationFailed, "Command failed", false);
101 CryptCommandListener::CryptfsCmd::CryptfsCmd() :
102 VoldCommand("cryptfs") {
105 static int getType(const char* type)
107 if (!strcmp(type, "default")) {
108 return CRYPT_TYPE_DEFAULT;
109 } else if (!strcmp(type, "password")) {
110 return CRYPT_TYPE_PASSWORD;
111 } else if (!strcmp(type, "pin")) {
112 return CRYPT_TYPE_PIN;
113 } else if (!strcmp(type, "pattern")) {
114 return CRYPT_TYPE_PATTERN;
120 static char* parseNull(char* arg) {
121 if (strcmp(arg, "!") == 0) {
128 static bool check_argc(SocketClient *cli, const std::string &subcommand, int argc,
129 int expected, std::string usage) {
130 assert(expected >= 2);
132 assert(usage.empty());
134 assert(!usage.empty());
135 assert(std::count(usage.begin(), usage.end(), ' ') + 3 == expected);
137 if (argc == expected) {
140 auto message = std::string() + "Usage: cryptfs " + subcommand;
141 if (!usage.empty()) {
142 message += " " + usage;
144 cli->sendMsg(ResponseCode::CommandSyntaxError, message.c_str(), false);
148 static int do_enablecrypto(char** argv, int type, bool no_ui) {
151 for (tries = 0; tries < 2; ++tries) {
152 if (type == CRYPT_TYPE_DEFAULT) {
153 rc = cryptfs_enable_default(argv[2], no_ui);
155 rc = cryptfs_enable(argv[2], type, argv[4], no_ui);
160 } else if (tries == 0) {
161 Process::killProcessesWithOpenFiles(DATA_MNT_POINT, SIGKILL);
167 int CryptCommandListener::CryptfsCmd::runCommand(SocketClient *cli,
168 int argc, char **argv) {
169 if ((cli->getUid() != 0) && (cli->getUid() != AID_SYSTEM)) {
170 cli->sendMsg(ResponseCode::CommandNoPermission, "No permission to run cryptfs commands", false);
175 cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing subcommand", false);
181 std::string subcommand(argv[1]);
182 if (subcommand == "checkpw") {
183 if (!check_argc(cli, subcommand, argc, 3, "<passwd>")) return 0;
184 dumpArgs(argc, argv, 2);
185 rc = cryptfs_check_passwd(argv[2]);
186 } else if (subcommand == "restart") {
187 if (!check_argc(cli, subcommand, argc, 2, "")) return 0;
188 dumpArgs(argc, argv, -1);
190 // Spawn as thread so init can issue commands back to vold without
191 // causing deadlock, usually as a result of prep_data_fs.
192 std::thread(&cryptfs_restart).detach();
193 } else if (subcommand == "cryptocomplete") {
194 if (!check_argc(cli, subcommand, argc, 2, "")) return 0;
195 dumpArgs(argc, argv, -1);
196 rc = cryptfs_crypto_complete();
197 } else if (subcommand == "enablecrypto") {
198 const char* syntax = "Usage: cryptfs enablecrypto <wipe|inplace> "
199 "default|password|pin|pattern [passwd] [noui]";
201 // This should be replaced with a command line parser if more options
205 int type = CRYPT_TYPE_DEFAULT;
206 int options = 4; // Optional parameters are at this offset
208 // Minimum 4 parameters
210 } else if (strcmp(argv[2], "wipe") && strcmp(argv[2], "inplace") ) {
211 // Second parameter must be wipe or inplace
214 // Third parameter must be valid type
215 type = getType(argv[3]);
218 } else if (type != CRYPT_TYPE_DEFAULT) {
225 // Too few parameters
227 } else if (argc == options) {
229 } else if (argc == options + 1) {
230 // One option, must be noui
231 if (!strcmp(argv[options], "noui")) {
243 cli->sendMsg(ResponseCode::CommandSyntaxError, syntax, false);
247 dumpArgs(argc, argv, 4);
249 // Spawn as thread so init can issue commands back to vold without
250 // causing deadlock, usually as a result of prep_data_fs.
251 std::thread(&do_enablecrypto, argv, type, no_ui).detach();
252 } else if (subcommand == "enablefilecrypto") {
253 if (!check_argc(cli, subcommand, argc, 2, "")) return 0;
254 dumpArgs(argc, argv, -1);
255 rc = cryptfs_enable_file();
256 } else if (subcommand == "changepw") {
257 const char* syntax = "Usage: cryptfs changepw "
258 "default|password|pin|pattern [newpasswd]";
259 const char* password;
262 } else if (argc == 4) {
265 cli->sendMsg(ResponseCode::CommandSyntaxError, syntax, false);
268 int type = getType(argv[2]);
270 cli->sendMsg(ResponseCode::CommandSyntaxError, syntax, false);
273 SLOGD("cryptfs changepw %s {}", argv[2]);
274 rc = cryptfs_changepw(type, password);
275 } else if (subcommand == "verifypw") {
276 if (!check_argc(cli, subcommand, argc, 3, "<passwd>")) return 0;
277 SLOGD("cryptfs verifypw {}");
278 rc = cryptfs_verify_passwd(argv[2]);
279 } else if (subcommand == "getfield") {
280 if (!check_argc(cli, subcommand, argc, 3, "<fieldname>")) return 0;
282 int valbuf_len = PROPERTY_VALUE_MAX;
284 dumpArgs(argc, argv, -1);
286 // Increase the buffer size until it is big enough for the field value stored.
288 valbuf = (char*)malloc(valbuf_len);
289 if (valbuf == NULL) {
290 cli->sendMsg(ResponseCode::OperationFailed, "Failed to allocate memory", false);
293 rc = cryptfs_getfield(argv[2], valbuf, valbuf_len);
294 if (rc != CRYPTO_GETFIELD_ERROR_BUF_TOO_SMALL) {
300 if (rc == CRYPTO_GETFIELD_OK) {
301 cli->sendMsg(ResponseCode::CryptfsGetfieldResult, valbuf, false);
304 } else if (subcommand == "setfield") {
305 if (!check_argc(cli, subcommand, argc, 4, "<fieldname> <value>")) return 0;
306 dumpArgs(argc, argv, -1);
307 rc = cryptfs_setfield(argv[2], argv[3]);
308 } else if (subcommand == "mountdefaultencrypted") {
309 if (!check_argc(cli, subcommand, argc, 2, "")) return 0;
310 SLOGD("cryptfs mountdefaultencrypted");
311 dumpArgs(argc, argv, -1);
313 // Spawn as thread so init can issue commands back to vold without
314 // causing deadlock, usually as a result of prep_data_fs.
315 std::thread(&cryptfs_mount_default_encrypted).detach();
316 } else if (subcommand == "getpwtype") {
317 if (!check_argc(cli, subcommand, argc, 2, "")) return 0;
318 SLOGD("cryptfs getpwtype");
319 dumpArgs(argc, argv, -1);
320 switch(cryptfs_get_password_type()) {
321 case CRYPT_TYPE_PASSWORD:
322 cli->sendMsg(ResponseCode::PasswordTypeResult, "password", false);
324 case CRYPT_TYPE_PATTERN:
325 cli->sendMsg(ResponseCode::PasswordTypeResult, "pattern", false);
328 cli->sendMsg(ResponseCode::PasswordTypeResult, "pin", false);
330 case CRYPT_TYPE_DEFAULT:
331 cli->sendMsg(ResponseCode::PasswordTypeResult, "default", false);
334 /** @TODO better error and make sure handled by callers */
335 cli->sendMsg(ResponseCode::OpFailedStorageNotFound, "Error", false);
338 } else if (subcommand == "getpw") {
339 if (!check_argc(cli, subcommand, argc, 2, "")) return 0;
340 SLOGD("cryptfs getpw");
341 dumpArgs(argc, argv, -1);
342 const char* password = cryptfs_get_password();
345 int size = asprintf(&message, "{{sensitive}} %s", password);
347 cli->sendMsg(ResponseCode::CommandOkay, message, false);
348 memset(message, 0, size);
354 } else if (subcommand == "clearpw") {
355 if (!check_argc(cli, subcommand, argc, 2, "")) return 0;
356 SLOGD("cryptfs clearpw");
357 dumpArgs(argc, argv, -1);
358 cryptfs_clear_password();
361 } else if (subcommand == "isConvertibleToFBE") {
362 if (!check_argc(cli, subcommand, argc, 2, "")) return 0;
363 // ext4enc:TODO: send a CommandSyntaxError if argv[2] not an integer
364 SLOGD("cryptfs isConvertibleToFBE");
365 dumpArgs(argc, argv, -1);
366 rc = cryptfs_isConvertibleToFBE();
368 } else if (subcommand == "init_user0") {
369 if (!check_argc(cli, subcommand, argc, 2, "")) return 0;
370 return sendGenericOkFail(cli, e4crypt_init_user0());
372 } else if (subcommand == "create_user_key") {
373 if (!check_argc(cli, subcommand, argc, 5, "<user> <serial> <ephemeral>")) return 0;
374 return sendGenericOkFail(cli,
375 e4crypt_vold_create_user_key(atoi(argv[2]),
377 atoi(argv[4]) != 0));
379 } else if (subcommand == "destroy_user_key") {
380 if (!check_argc(cli, subcommand, argc, 3, "<user>")) return 0;
381 return sendGenericOkFail(cli, e4crypt_destroy_user_key(atoi(argv[2])));
383 } else if (subcommand == "change_user_key") {
384 if (!check_argc(cli, subcommand, argc, 7,
385 "<user> <serial> <token> <old_secret> <new_secret>")) return 0;
386 return sendGenericOkFail(cli, e4crypt_change_user_key(
387 atoi(argv[2]), atoi(argv[3]), argv[4], argv[5], argv[6]));
389 } else if (subcommand == "unlock_user_key") {
390 if (!check_argc(cli, subcommand, argc, 6, "<user> <serial> <token> <secret>")) return 0;
391 return sendGenericOkFail(cli, e4crypt_unlock_user_key(
392 atoi(argv[2]), atoi(argv[3]), argv[4], argv[5]));
394 } else if (subcommand == "lock_user_key") {
395 if (!check_argc(cli, subcommand, argc, 3, "<user>")) return 0;
396 return sendGenericOkFail(cli, e4crypt_lock_user_key(atoi(argv[2])));
398 } else if (subcommand == "prepare_user_storage") {
399 if (!check_argc(cli, subcommand, argc, 6, "<uuid> <user> <serial> <flags>")) return 0;
400 return sendGenericOkFail(cli,
401 e4crypt_prepare_user_storage(parseNull(argv[2]),
407 dumpArgs(argc, argv, -1);
408 cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown cryptfs subcommand", false);
412 // Always report that the command succeeded and return the error code.
413 // The caller will check the return value to see what the error was.
415 snprintf(msg, sizeof(msg), "%d", rc);
416 cli->sendMsg(ResponseCode::CommandOkay, msg, false);