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/types.h>
     20 #include <netinet/in.h>
     21 #include <arpa/inet.h>
     22 #include <dirent.h>
     23 #include <errno.h>
     24 #include <fcntl.h>
     25 #include <fs_mgr.h>
     26 #include <stdio.h>
     27 #include <string.h>
     28 #include <stdint.h>
     29 #include <inttypes.h>
     30 
     31 #define LOG_TAG "VoldCryptCmdListener"
     32 
     33 #include <base/stringprintf.h>
     34 #include <cutils/fs.h>
     35 #include <cutils/log.h>
     36 #include <cutils/sockets.h>
     37 
     38 #include <sysutils/SocketClient.h>
     39 #include <private/android_filesystem_config.h>
     40 
     41 #include "CryptCommandListener.h"
     42 #include "Process.h"
     43 #include "ResponseCode.h"
     44 #include "cryptfs.h"
     45 
     46 #define DUMP_ARGS 0
     47 
     48 CryptCommandListener::CryptCommandListener() :
     49 FrameworkListener("cryptd", true) {
     50     registerCmd(new CryptfsCmd());
     51 }
     52 
     53 #if DUMP_ARGS
     54 void CryptCommandListener::dumpArgs(int argc, char **argv, int argObscure) {
     55     char buffer[4096];
     56     char *p = buffer;
     57 
     58     memset(buffer, 0, sizeof(buffer));
     59     int i;
     60     for (i = 0; i < argc; i++) {
     61         unsigned int len = strlen(argv[i]) + 1; // Account for space
     62         if (i == argObscure) {
     63             len += 2; // Account for {}
     64         }
     65         if (((p - buffer) + len) < (sizeof(buffer)-1)) {
     66             if (i == argObscure) {
     67                 *p++ = '{';
     68                 *p++ = '}';
     69                 *p++ = ' ';
     70                 continue;
     71             }
     72             strcpy(p, argv[i]);
     73             p+= strlen(argv[i]);
     74             if (i != (argc -1)) {
     75                 *p++ = ' ';
     76             }
     77         }
     78     }
     79     SLOGD("%s", buffer);
     80 }
     81 #else
     82 void CryptCommandListener::dumpArgs(int /*argc*/, char ** /*argv*/, int /*argObscure*/) { }
     83 #endif
     84 
     85 int CryptCommandListener::sendGenericOkFail(SocketClient *cli, int cond) {
     86     if (!cond) {
     87         return cli->sendMsg(ResponseCode::CommandOkay, "Command succeeded", false);
     88     } else {
     89         return cli->sendMsg(ResponseCode::OperationFailed, "Command failed", false);
     90     }
     91 }
     92 
     93 CryptCommandListener::CryptfsCmd::CryptfsCmd() :
     94                  VoldCommand("cryptfs") {
     95 }
     96 
     97 static int getType(const char* type)
     98 {
     99     if (!strcmp(type, "default")) {
    100         return CRYPT_TYPE_DEFAULT;
    101     } else if (!strcmp(type, "password")) {
    102         return CRYPT_TYPE_PASSWORD;
    103     } else if (!strcmp(type, "pin")) {
    104         return CRYPT_TYPE_PIN;
    105     } else if (!strcmp(type, "pattern")) {
    106         return CRYPT_TYPE_PATTERN;
    107     } else {
    108         return -1;
    109     }
    110 }
    111 
    112 int CryptCommandListener::CryptfsCmd::runCommand(SocketClient *cli,
    113                                                  int argc, char **argv) {
    114     if ((cli->getUid() != 0) && (cli->getUid() != AID_SYSTEM)) {
    115         cli->sendMsg(ResponseCode::CommandNoPermission, "No permission to run cryptfs commands", false);
    116         return 0;
    117     }
    118 
    119     if (argc < 2) {
    120         cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing Argument", false);
    121         return 0;
    122     }
    123 
    124     int rc = 0;
    125 
    126     if (!strcmp(argv[1], "checkpw")) {
    127         if (argc != 3) {
    128             cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: cryptfs checkpw <passwd>", false);
    129             return 0;
    130         }
    131         dumpArgs(argc, argv, 2);
    132         rc = cryptfs_check_passwd(argv[2]);
    133     } else if (!strcmp(argv[1], "restart")) {
    134         if (argc != 2) {
    135             cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: cryptfs restart", false);
    136             return 0;
    137         }
    138         dumpArgs(argc, argv, -1);
    139         rc = cryptfs_restart();
    140     } else if (!strcmp(argv[1], "cryptocomplete")) {
    141         if (argc != 2) {
    142             cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: cryptfs cryptocomplete", false);
    143             return 0;
    144         }
    145         dumpArgs(argc, argv, -1);
    146         rc = cryptfs_crypto_complete();
    147     } else if (!strcmp(argv[1], "enablecrypto")) {
    148         const char* syntax = "Usage: cryptfs enablecrypto <wipe|inplace> "
    149                              "default|password|pin|pattern [passwd]";
    150         if ( (argc != 4 && argc != 5)
    151              || (strcmp(argv[2], "wipe") && strcmp(argv[2], "inplace")) ) {
    152             cli->sendMsg(ResponseCode::CommandSyntaxError, syntax, false);
    153             return 0;
    154         }
    155         dumpArgs(argc, argv, 4);
    156 
    157         int tries;
    158         for (tries = 0; tries < 2; ++tries) {
    159             int type = getType(argv[3]);
    160             if (type == -1) {
    161                 cli->sendMsg(ResponseCode::CommandSyntaxError, syntax,
    162                              false);
    163                 return 0;
    164             } else if (type == CRYPT_TYPE_DEFAULT) {
    165               rc = cryptfs_enable_default(argv[2], /*allow_reboot*/false);
    166             } else {
    167                 rc = cryptfs_enable(argv[2], type, argv[4],
    168                                     /*allow_reboot*/false);
    169             }
    170 
    171             if (rc == 0) {
    172                 break;
    173             } else if (tries == 0) {
    174                 Process::killProcessesWithOpenFiles(DATA_MNT_POINT, SIGKILL);
    175             }
    176         }
    177     } else if (!strcmp(argv[1], "enablefilecrypto")) {
    178         const char* syntax = "Usage: cryptfs enablefilecrypto";
    179         if (argc != 2) {
    180             cli->sendMsg(ResponseCode::CommandSyntaxError, syntax, false);
    181             return 0;
    182         }
    183         dumpArgs(argc, argv, -1);
    184         rc = cryptfs_enable_file();
    185     } else if (!strcmp(argv[1], "changepw")) {
    186         const char* syntax = "Usage: cryptfs changepw "
    187                              "default|password|pin|pattern [newpasswd]";
    188         const char* password;
    189         if (argc == 3) {
    190             password = "";
    191         } else if (argc == 4) {
    192             password = argv[3];
    193         } else {
    194             cli->sendMsg(ResponseCode::CommandSyntaxError, syntax, false);
    195             return 0;
    196         }
    197         int type = getType(argv[2]);
    198         if (type == -1) {
    199             cli->sendMsg(ResponseCode::CommandSyntaxError, syntax, false);
    200             return 0;
    201         }
    202         SLOGD("cryptfs changepw %s {}", argv[2]);
    203         rc = cryptfs_changepw(type, password);
    204     } else if (!strcmp(argv[1], "verifypw")) {
    205         if (argc != 3) {
    206             cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: cryptfs verifypw <passwd>", false);
    207             return 0;
    208         }
    209         SLOGD("cryptfs verifypw {}");
    210         rc = cryptfs_verify_passwd(argv[2]);
    211     } else if (!strcmp(argv[1], "getfield")) {
    212         char *valbuf;
    213         int valbuf_len = PROPERTY_VALUE_MAX;
    214 
    215         if (argc != 3) {
    216             cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: cryptfs getfield <fieldname>", false);
    217             return 0;
    218         }
    219         dumpArgs(argc, argv, -1);
    220 
    221         // Increase the buffer size until it is big enough for the field value stored.
    222         while (1) {
    223             valbuf = (char*)malloc(valbuf_len);
    224             if (valbuf == NULL) {
    225                 cli->sendMsg(ResponseCode::OperationFailed, "Failed to allocate memory", false);
    226                 return 0;
    227             }
    228             rc = cryptfs_getfield(argv[2], valbuf, valbuf_len);
    229             if (rc != CRYPTO_GETFIELD_ERROR_BUF_TOO_SMALL) {
    230                 break;
    231             }
    232             free(valbuf);
    233             valbuf_len *= 2;
    234         }
    235         if (rc == CRYPTO_GETFIELD_OK) {
    236             cli->sendMsg(ResponseCode::CryptfsGetfieldResult, valbuf, false);
    237         }
    238         free(valbuf);
    239     } else if (!strcmp(argv[1], "setfield")) {
    240         if (argc != 4) {
    241             cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: cryptfs setfield <fieldname> <value>", false);
    242             return 0;
    243         }
    244         dumpArgs(argc, argv, -1);
    245         rc = cryptfs_setfield(argv[2], argv[3]);
    246     } else if (!strcmp(argv[1], "mountdefaultencrypted")) {
    247         SLOGD("cryptfs mountdefaultencrypted");
    248         dumpArgs(argc, argv, -1);
    249         rc = cryptfs_mount_default_encrypted();
    250     } else if (!strcmp(argv[1], "getpwtype")) {
    251         SLOGD("cryptfs getpwtype");
    252         dumpArgs(argc, argv, -1);
    253         switch(cryptfs_get_password_type()) {
    254         case CRYPT_TYPE_PASSWORD:
    255             cli->sendMsg(ResponseCode::PasswordTypeResult, "password", false);
    256             return 0;
    257         case CRYPT_TYPE_PATTERN:
    258             cli->sendMsg(ResponseCode::PasswordTypeResult, "pattern", false);
    259             return 0;
    260         case CRYPT_TYPE_PIN:
    261             cli->sendMsg(ResponseCode::PasswordTypeResult, "pin", false);
    262             return 0;
    263         case CRYPT_TYPE_DEFAULT:
    264             cli->sendMsg(ResponseCode::PasswordTypeResult, "default", false);
    265             return 0;
    266         default:
    267           /** @TODO better error and make sure handled by callers */
    268             cli->sendMsg(ResponseCode::OpFailedStorageNotFound, "Error", false);
    269             return 0;
    270         }
    271     } else if (!strcmp(argv[1], "getpw")) {
    272         SLOGD("cryptfs getpw");
    273         dumpArgs(argc, argv, -1);
    274         const char* password = cryptfs_get_password();
    275         if (password) {
    276             char* message = 0;
    277             int size = asprintf(&message, "{{sensitive}} %s", password);
    278             if (size != -1) {
    279                 cli->sendMsg(ResponseCode::CommandOkay, message, false);
    280                 memset(message, 0, size);
    281                 free (message);
    282                 return 0;
    283             }
    284         }
    285         rc = -1;
    286     } else if (!strcmp(argv[1], "clearpw")) {
    287         SLOGD("cryptfs clearpw");
    288         dumpArgs(argc, argv, -1);
    289         cryptfs_clear_password();
    290         rc = 0;
    291     } else {
    292         dumpArgs(argc, argv, -1);
    293         cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown cryptfs cmd", false);
    294         return 0;
    295     }
    296 
    297     // Always report that the command succeeded and return the error code.
    298     // The caller will check the return value to see what the error was.
    299     char msg[255];
    300     snprintf(msg, sizeof(msg), "%d", rc);
    301     cli->sendMsg(ResponseCode::CommandOkay, msg, false);
    302 
    303     return 0;
    304 }
    305