Home | History | Annotate | Download | only in vold
      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