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