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