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