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 } 449