blob: 2eac60e2b8a3d2e2910f257ea38eecbcabff230c [file] [log] [blame]
Paul Lawrenced0b42952015-06-03 14:19:51 -07001/*
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>
Jeff Sharkeyd2c96e72015-11-08 17:56:23 -080019#include <sys/stat.h>
Paul Lawrenced0b42952015-06-03 14:19:51 -070020#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
Paul Crowley415d3602015-12-14 15:52:19 +000032#include <algorithm>
33
Paul Lawrenced0b42952015-06-03 14:19:51 -070034#define LOG_TAG "VoldCryptCmdListener"
35
Elliott Hughes6bf05472015-12-04 17:55:33 -080036#include <android-base/logging.h>
Elliott Hughes7e128fb2015-12-04 15:50:53 -080037#include <android-base/stringprintf.h>
Jeff Sharkeyd2c96e72015-11-08 17:56:23 -080038
Paul Lawrenced0b42952015-06-03 14:19:51 -070039#include <cutils/fs.h>
40#include <cutils/log.h>
41#include <cutils/sockets.h>
42
43#include <sysutils/SocketClient.h>
44#include <private/android_filesystem_config.h>
45
46#include "CryptCommandListener.h"
47#include "Process.h"
48#include "ResponseCode.h"
49#include "cryptfs.h"
Paul Crowley95376d62015-05-06 15:04:43 +010050#include "Ext4Crypt.h"
Jeff Sharkeyd2c96e72015-11-08 17:56:23 -080051#include "Utils.h"
Paul Lawrenced0b42952015-06-03 14:19:51 -070052
53#define DUMP_ARGS 0
54
55CryptCommandListener::CryptCommandListener() :
56FrameworkListener("cryptd", true) {
57 registerCmd(new CryptfsCmd());
58}
59
60#if DUMP_ARGS
61void CryptCommandListener::dumpArgs(int argc, char **argv, int argObscure) {
62 char buffer[4096];
63 char *p = buffer;
64
65 memset(buffer, 0, sizeof(buffer));
66 int i;
67 for (i = 0; i < argc; i++) {
68 unsigned int len = strlen(argv[i]) + 1; // Account for space
69 if (i == argObscure) {
70 len += 2; // Account for {}
71 }
72 if (((p - buffer) + len) < (sizeof(buffer)-1)) {
73 if (i == argObscure) {
74 *p++ = '{';
75 *p++ = '}';
76 *p++ = ' ';
77 continue;
78 }
79 strcpy(p, argv[i]);
80 p+= strlen(argv[i]);
81 if (i != (argc -1)) {
82 *p++ = ' ';
83 }
84 }
85 }
86 SLOGD("%s", buffer);
87}
88#else
89void CryptCommandListener::dumpArgs(int /*argc*/, char ** /*argv*/, int /*argObscure*/) { }
90#endif
91
92int CryptCommandListener::sendGenericOkFail(SocketClient *cli, int cond) {
93 if (!cond) {
94 return cli->sendMsg(ResponseCode::CommandOkay, "Command succeeded", false);
95 } else {
96 return cli->sendMsg(ResponseCode::OperationFailed, "Command failed", false);
97 }
98}
99
100CryptCommandListener::CryptfsCmd::CryptfsCmd() :
101 VoldCommand("cryptfs") {
102}
103
104static int getType(const char* type)
105{
106 if (!strcmp(type, "default")) {
107 return CRYPT_TYPE_DEFAULT;
108 } else if (!strcmp(type, "password")) {
109 return CRYPT_TYPE_PASSWORD;
110 } else if (!strcmp(type, "pin")) {
111 return CRYPT_TYPE_PIN;
112 } else if (!strcmp(type, "pattern")) {
113 return CRYPT_TYPE_PATTERN;
114 } else {
115 return -1;
116 }
117}
118
Jeff Sharkeyd2c96e72015-11-08 17:56:23 -0800119static char* parseNull(char* arg) {
120 if (strcmp(arg, "!") == 0) {
121 return nullptr;
122 } else {
123 return arg;
124 }
125}
126
Paul Crowley415d3602015-12-14 15:52:19 +0000127static bool check_argc(SocketClient *cli, const std::string &subcommand, int argc,
128 int expected, std::string usage) {
129 assert(expected >= 2);
130 if (expected == 2) {
131 assert(usage.empty());
132 } else {
133 assert(!usage.empty());
134 assert(std::count(usage.begin(), usage.end(), ' ') + 3 == expected);
135 }
136 if (argc == expected) {
137 return true;
138 }
139 auto message = std::string() + "Usage: cryptfs " + subcommand;
140 if (!usage.empty()) {
141 message += " " + usage;
142 }
143 cli->sendMsg(ResponseCode::CommandSyntaxError, message.c_str(), false);
144 return false;
145}
Paul Crowley34b813e2015-12-10 16:26:15 +0000146
Paul Lawrenced0b42952015-06-03 14:19:51 -0700147int CryptCommandListener::CryptfsCmd::runCommand(SocketClient *cli,
148 int argc, char **argv) {
149 if ((cli->getUid() != 0) && (cli->getUid() != AID_SYSTEM)) {
150 cli->sendMsg(ResponseCode::CommandNoPermission, "No permission to run cryptfs commands", false);
151 return 0;
152 }
153
154 if (argc < 2) {
Paul Crowley415d3602015-12-14 15:52:19 +0000155 cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing subcommand", false);
Paul Lawrenced0b42952015-06-03 14:19:51 -0700156 return 0;
157 }
158
159 int rc = 0;
160
Paul Crowleyee6b1642015-12-10 16:51:53 +0000161 std::string subcommand(argv[1]);
162 if (subcommand == "checkpw") {
Paul Crowley415d3602015-12-14 15:52:19 +0000163 if (!check_argc(cli, subcommand, argc, 3, "<passwd>")) return 0;
Paul Lawrenced0b42952015-06-03 14:19:51 -0700164 dumpArgs(argc, argv, 2);
165 rc = cryptfs_check_passwd(argv[2]);
Paul Crowleyee6b1642015-12-10 16:51:53 +0000166 } else if (subcommand == "restart") {
Paul Crowley415d3602015-12-14 15:52:19 +0000167 if (!check_argc(cli, subcommand, argc, 2, "")) return 0;
Paul Lawrenced0b42952015-06-03 14:19:51 -0700168 dumpArgs(argc, argv, -1);
169 rc = cryptfs_restart();
Paul Crowleyee6b1642015-12-10 16:51:53 +0000170 } else if (subcommand == "cryptocomplete") {
Paul Crowley415d3602015-12-14 15:52:19 +0000171 if (!check_argc(cli, subcommand, argc, 2, "")) return 0;
Paul Lawrenced0b42952015-06-03 14:19:51 -0700172 dumpArgs(argc, argv, -1);
173 rc = cryptfs_crypto_complete();
Paul Crowleyee6b1642015-12-10 16:51:53 +0000174 } else if (subcommand == "enablecrypto") {
Paul Lawrenced0b42952015-06-03 14:19:51 -0700175 const char* syntax = "Usage: cryptfs enablecrypto <wipe|inplace> "
Paul Lawrence569649f2015-09-09 12:13:00 -0700176 "default|password|pin|pattern [passwd] [noui]";
177
178 // This should be replaced with a command line parser if more options
179 // are added
180 bool valid = true;
181 bool no_ui = false;
182 int type = CRYPT_TYPE_DEFAULT;
183 int options = 4; // Optional parameters are at this offset
184 if (argc < 4) {
185 // Minimum 4 parameters
186 valid = false;
187 } else if (strcmp(argv[2], "wipe") && strcmp(argv[2], "inplace") ) {
188 // Second parameter must be wipe or inplace
189 valid = false;
190 } else {
191 // Third parameter must be valid type
192 type = getType(argv[3]);
193 if (type == -1) {
194 valid = false;
195 } else if (type != CRYPT_TYPE_DEFAULT) {
196 options++;
197 }
198 }
199
200 if (valid) {
201 if(argc < options) {
202 // Too few parameters
203 valid = false;
204 } else if (argc == options) {
205 // No more, done
206 } else if (argc == options + 1) {
207 // One option, must be noui
208 if (!strcmp(argv[options], "noui")) {
209 no_ui = true;
210 } else {
211 valid = false;
212 }
213 } else {
214 // Too many options
215 valid = false;
216 }
217 }
218
219 if (!valid ) {
Paul Lawrenced0b42952015-06-03 14:19:51 -0700220 cli->sendMsg(ResponseCode::CommandSyntaxError, syntax, false);
221 return 0;
222 }
Paul Lawrence569649f2015-09-09 12:13:00 -0700223
Paul Lawrenced0b42952015-06-03 14:19:51 -0700224 dumpArgs(argc, argv, 4);
225
226 int tries;
227 for (tries = 0; tries < 2; ++tries) {
Paul Lawrenced0b42952015-06-03 14:19:51 -0700228 if (type == -1) {
229 cli->sendMsg(ResponseCode::CommandSyntaxError, syntax,
230 false);
231 return 0;
232 } else if (type == CRYPT_TYPE_DEFAULT) {
Paul Lawrence569649f2015-09-09 12:13:00 -0700233 rc = cryptfs_enable_default(argv[2], no_ui);
Paul Lawrenced0b42952015-06-03 14:19:51 -0700234 } else {
Paul Lawrence569649f2015-09-09 12:13:00 -0700235 rc = cryptfs_enable(argv[2], type, argv[4], no_ui);
Paul Lawrenced0b42952015-06-03 14:19:51 -0700236 }
237
238 if (rc == 0) {
239 break;
240 } else if (tries == 0) {
241 Process::killProcessesWithOpenFiles(DATA_MNT_POINT, SIGKILL);
242 }
243 }
Paul Crowleyee6b1642015-12-10 16:51:53 +0000244 } else if (subcommand == "enablefilecrypto") {
Paul Crowley415d3602015-12-14 15:52:19 +0000245 if (!check_argc(cli, subcommand, argc, 2, "")) return 0;
Paul Lawrenced0b42952015-06-03 14:19:51 -0700246 dumpArgs(argc, argv, -1);
247 rc = cryptfs_enable_file();
Paul Crowleyee6b1642015-12-10 16:51:53 +0000248 } else if (subcommand == "changepw") {
Paul Lawrenced0b42952015-06-03 14:19:51 -0700249 const char* syntax = "Usage: cryptfs changepw "
250 "default|password|pin|pattern [newpasswd]";
251 const char* password;
252 if (argc == 3) {
253 password = "";
254 } else if (argc == 4) {
255 password = argv[3];
256 } else {
257 cli->sendMsg(ResponseCode::CommandSyntaxError, syntax, false);
258 return 0;
259 }
260 int type = getType(argv[2]);
261 if (type == -1) {
262 cli->sendMsg(ResponseCode::CommandSyntaxError, syntax, false);
263 return 0;
264 }
265 SLOGD("cryptfs changepw %s {}", argv[2]);
266 rc = cryptfs_changepw(type, password);
Paul Crowleyee6b1642015-12-10 16:51:53 +0000267 } else if (subcommand == "verifypw") {
Paul Crowley415d3602015-12-14 15:52:19 +0000268 if (!check_argc(cli, subcommand, argc, 3, "<passwd>")) return 0;
Paul Lawrenced0b42952015-06-03 14:19:51 -0700269 SLOGD("cryptfs verifypw {}");
270 rc = cryptfs_verify_passwd(argv[2]);
Paul Crowleyee6b1642015-12-10 16:51:53 +0000271 } else if (subcommand == "getfield") {
Paul Crowley415d3602015-12-14 15:52:19 +0000272 if (!check_argc(cli, subcommand, argc, 3, "<fieldname>")) return 0;
Paul Lawrenced0b42952015-06-03 14:19:51 -0700273 char *valbuf;
274 int valbuf_len = PROPERTY_VALUE_MAX;
275
Paul Lawrenced0b42952015-06-03 14:19:51 -0700276 dumpArgs(argc, argv, -1);
277
278 // Increase the buffer size until it is big enough for the field value stored.
279 while (1) {
280 valbuf = (char*)malloc(valbuf_len);
281 if (valbuf == NULL) {
282 cli->sendMsg(ResponseCode::OperationFailed, "Failed to allocate memory", false);
283 return 0;
284 }
285 rc = cryptfs_getfield(argv[2], valbuf, valbuf_len);
286 if (rc != CRYPTO_GETFIELD_ERROR_BUF_TOO_SMALL) {
287 break;
288 }
289 free(valbuf);
290 valbuf_len *= 2;
291 }
292 if (rc == CRYPTO_GETFIELD_OK) {
293 cli->sendMsg(ResponseCode::CryptfsGetfieldResult, valbuf, false);
294 }
295 free(valbuf);
Paul Crowleyee6b1642015-12-10 16:51:53 +0000296 } else if (subcommand == "setfield") {
Paul Crowley415d3602015-12-14 15:52:19 +0000297 if (!check_argc(cli, subcommand, argc, 4, "<fieldname> <value>")) return 0;
Paul Lawrenced0b42952015-06-03 14:19:51 -0700298 dumpArgs(argc, argv, -1);
299 rc = cryptfs_setfield(argv[2], argv[3]);
Paul Crowleyee6b1642015-12-10 16:51:53 +0000300 } else if (subcommand == "mountdefaultencrypted") {
Paul Crowley415d3602015-12-14 15:52:19 +0000301 if (!check_argc(cli, subcommand, argc, 2, "")) return 0;
Paul Lawrenced0b42952015-06-03 14:19:51 -0700302 SLOGD("cryptfs mountdefaultencrypted");
303 dumpArgs(argc, argv, -1);
304 rc = cryptfs_mount_default_encrypted();
Paul Crowleyee6b1642015-12-10 16:51:53 +0000305 } else if (subcommand == "getpwtype") {
Paul Crowley415d3602015-12-14 15:52:19 +0000306 if (!check_argc(cli, subcommand, argc, 2, "")) return 0;
Paul Lawrenced0b42952015-06-03 14:19:51 -0700307 SLOGD("cryptfs getpwtype");
308 dumpArgs(argc, argv, -1);
309 switch(cryptfs_get_password_type()) {
310 case CRYPT_TYPE_PASSWORD:
311 cli->sendMsg(ResponseCode::PasswordTypeResult, "password", false);
312 return 0;
313 case CRYPT_TYPE_PATTERN:
314 cli->sendMsg(ResponseCode::PasswordTypeResult, "pattern", false);
315 return 0;
316 case CRYPT_TYPE_PIN:
317 cli->sendMsg(ResponseCode::PasswordTypeResult, "pin", false);
318 return 0;
319 case CRYPT_TYPE_DEFAULT:
320 cli->sendMsg(ResponseCode::PasswordTypeResult, "default", false);
321 return 0;
322 default:
323 /** @TODO better error and make sure handled by callers */
324 cli->sendMsg(ResponseCode::OpFailedStorageNotFound, "Error", false);
325 return 0;
326 }
Paul Crowleyee6b1642015-12-10 16:51:53 +0000327 } else if (subcommand == "getpw") {
Paul Crowley415d3602015-12-14 15:52:19 +0000328 if (!check_argc(cli, subcommand, argc, 2, "")) return 0;
Paul Lawrenced0b42952015-06-03 14:19:51 -0700329 SLOGD("cryptfs getpw");
330 dumpArgs(argc, argv, -1);
331 const char* password = cryptfs_get_password();
332 if (password) {
333 char* message = 0;
334 int size = asprintf(&message, "{{sensitive}} %s", password);
335 if (size != -1) {
336 cli->sendMsg(ResponseCode::CommandOkay, message, false);
337 memset(message, 0, size);
338 free (message);
339 return 0;
340 }
341 }
342 rc = -1;
Paul Crowleyee6b1642015-12-10 16:51:53 +0000343 } else if (subcommand == "clearpw") {
Paul Crowley415d3602015-12-14 15:52:19 +0000344 if (!check_argc(cli, subcommand, argc, 2, "")) return 0;
Paul Lawrenced0b42952015-06-03 14:19:51 -0700345 SLOGD("cryptfs clearpw");
346 dumpArgs(argc, argv, -1);
347 cryptfs_clear_password();
348 rc = 0;
Jeff Sharkeyd2c96e72015-11-08 17:56:23 -0800349
Paul Crowleyee6b1642015-12-10 16:51:53 +0000350 } else if (subcommand == "isConvertibleToFBE") {
Paul Crowley415d3602015-12-14 15:52:19 +0000351 if (!check_argc(cli, subcommand, argc, 2, "")) return 0;
Paul Lawrence0c247462015-10-29 10:30:57 -0700352 // ext4enc:TODO: send a CommandSyntaxError if argv[2] not an integer
353 SLOGD("cryptfs isConvertibleToFBE");
354 dumpArgs(argc, argv, -1);
355 rc = cryptfs_isConvertibleToFBE();
Jeff Sharkeyd2c96e72015-11-08 17:56:23 -0800356
Paul Crowley8fb12fd2016-02-01 14:28:12 +0000357 } else if (subcommand == "init_user0") {
358 if (!check_argc(cli, subcommand, argc, 2, "")) return 0;
359 return sendGenericOkFail(cli, e4crypt_init_user0());
360
Paul Crowleyee6b1642015-12-10 16:51:53 +0000361 } else if (subcommand == "create_user_key") {
Paul Crowley415d3602015-12-14 15:52:19 +0000362 if (!check_argc(cli, subcommand, argc, 5, "<user> <serial> <ephemeral>")) return 0;
Lenka Trochtova395039f2015-11-25 10:13:03 +0100363 return sendGenericOkFail(cli,
Paul Crowley27cbce92015-12-10 14:51:30 +0000364 e4crypt_vold_create_user_key(atoi(argv[2]),
365 atoi(argv[3]),
366 atoi(argv[4]) != 0));
Jeff Sharkeyd2c96e72015-11-08 17:56:23 -0800367
Paul Crowleyee6b1642015-12-10 16:51:53 +0000368 } else if (subcommand == "destroy_user_key") {
Paul Crowley415d3602015-12-14 15:52:19 +0000369 if (!check_argc(cli, subcommand, argc, 3, "<user>")) return 0;
Jeff Sharkeyd2c96e72015-11-08 17:56:23 -0800370 return sendGenericOkFail(cli, e4crypt_destroy_user_key(atoi(argv[2])));
371
Paul Crowleyee6b1642015-12-10 16:51:53 +0000372 } else if (subcommand == "unlock_user_key") {
Paul Crowley415d3602015-12-14 15:52:19 +0000373 if (!check_argc(cli, subcommand, argc, 5, "<user> <serial> <token>")) return 0;
Paul Crowley285956f2016-01-20 13:12:38 +0000374 return sendGenericOkFail(cli, e4crypt_unlock_user_key(
375 atoi(argv[2]), atoi(argv[3]), parseNull(argv[4])));
Jeff Sharkeyd2c96e72015-11-08 17:56:23 -0800376
Paul Crowleyee6b1642015-12-10 16:51:53 +0000377 } else if (subcommand == "lock_user_key") {
Paul Crowley415d3602015-12-14 15:52:19 +0000378 if (!check_argc(cli, subcommand, argc, 3, "<user>")) return 0;
Jeff Sharkeyd2c96e72015-11-08 17:56:23 -0800379 return sendGenericOkFail(cli, e4crypt_lock_user_key(atoi(argv[2])));
380
Paul Crowleyee6b1642015-12-10 16:51:53 +0000381 } else if (subcommand == "prepare_user_storage") {
Paul Crowley415d3602015-12-14 15:52:19 +0000382 if (!check_argc(cli, subcommand, argc, 6, "<uuid> <user> <serial> <ephemeral>")) return 0;
Lenka Trochtova9ad43692015-12-11 13:27:26 +0100383 return sendGenericOkFail(cli,
384 e4crypt_prepare_user_storage(parseNull(argv[2]),
385 atoi(argv[3]),
386 atoi(argv[4]),
387 atoi(argv[5]) != 0));
Jeff Sharkeyd2c96e72015-11-08 17:56:23 -0800388
Paul Lawrenced0b42952015-06-03 14:19:51 -0700389 } else {
390 dumpArgs(argc, argv, -1);
Paul Crowleyee6b1642015-12-10 16:51:53 +0000391 cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown cryptfs subcommand", false);
Paul Lawrenced0b42952015-06-03 14:19:51 -0700392 return 0;
393 }
394
395 // Always report that the command succeeded and return the error code.
396 // The caller will check the return value to see what the error was.
397 char msg[255];
398 snprintf(msg, sizeof(msg), "%d", rc);
399 cli->sendMsg(ResponseCode::CommandOkay, msg, false);
400
401 return 0;
402}