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