blob: 93f953fa53a0b2e14c5799ddfa3811f907fbd813 [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
32#define LOG_TAG "VoldCryptCmdListener"
33
Elliott Hughes6bf05472015-12-04 17:55:33 -080034#include <android-base/logging.h>
Elliott Hughes7e128fb2015-12-04 15:50:53 -080035#include <android-base/stringprintf.h>
Jeff Sharkeyd2c96e72015-11-08 17:56:23 -080036
Paul Lawrenced0b42952015-06-03 14:19:51 -070037#include <cutils/fs.h>
38#include <cutils/log.h>
39#include <cutils/sockets.h>
40
41#include <sysutils/SocketClient.h>
42#include <private/android_filesystem_config.h>
43
44#include "CryptCommandListener.h"
45#include "Process.h"
46#include "ResponseCode.h"
47#include "cryptfs.h"
Paul Crowley95376d62015-05-06 15:04:43 +010048#include "Ext4Crypt.h"
Jeff Sharkeyd2c96e72015-11-08 17:56:23 -080049#include "Utils.h"
Paul Lawrenced0b42952015-06-03 14:19:51 -070050
51#define DUMP_ARGS 0
52
53CryptCommandListener::CryptCommandListener() :
54FrameworkListener("cryptd", true) {
55 registerCmd(new CryptfsCmd());
56}
57
58#if DUMP_ARGS
59void CryptCommandListener::dumpArgs(int argc, char **argv, int argObscure) {
60 char buffer[4096];
61 char *p = buffer;
62
63 memset(buffer, 0, sizeof(buffer));
64 int i;
65 for (i = 0; i < argc; i++) {
66 unsigned int len = strlen(argv[i]) + 1; // Account for space
67 if (i == argObscure) {
68 len += 2; // Account for {}
69 }
70 if (((p - buffer) + len) < (sizeof(buffer)-1)) {
71 if (i == argObscure) {
72 *p++ = '{';
73 *p++ = '}';
74 *p++ = ' ';
75 continue;
76 }
77 strcpy(p, argv[i]);
78 p+= strlen(argv[i]);
79 if (i != (argc -1)) {
80 *p++ = ' ';
81 }
82 }
83 }
84 SLOGD("%s", buffer);
85}
86#else
87void CryptCommandListener::dumpArgs(int /*argc*/, char ** /*argv*/, int /*argObscure*/) { }
88#endif
89
90int CryptCommandListener::sendGenericOkFail(SocketClient *cli, int cond) {
91 if (!cond) {
92 return cli->sendMsg(ResponseCode::CommandOkay, "Command succeeded", false);
93 } else {
94 return cli->sendMsg(ResponseCode::OperationFailed, "Command failed", false);
95 }
96}
97
98CryptCommandListener::CryptfsCmd::CryptfsCmd() :
99 VoldCommand("cryptfs") {
100}
101
102static int getType(const char* type)
103{
104 if (!strcmp(type, "default")) {
105 return CRYPT_TYPE_DEFAULT;
106 } else if (!strcmp(type, "password")) {
107 return CRYPT_TYPE_PASSWORD;
108 } else if (!strcmp(type, "pin")) {
109 return CRYPT_TYPE_PIN;
110 } else if (!strcmp(type, "pattern")) {
111 return CRYPT_TYPE_PATTERN;
112 } else {
113 return -1;
114 }
115}
116
Jeff Sharkeyd2c96e72015-11-08 17:56:23 -0800117static char* parseNull(char* arg) {
118 if (strcmp(arg, "!") == 0) {
119 return nullptr;
120 } else {
121 return arg;
122 }
123}
124
Paul Crowley34b813e2015-12-10 16:26:15 +0000125#define CHECK_ARGC(expected, error) \
126 do { \
127 if (argc != (expected)) { \
128 cli->sendMsg(ResponseCode::CommandSyntaxError, ("Usage: cryptfs " error), false); \
129 return 0; \
130 } \
131 } while (0)
132
Paul Lawrenced0b42952015-06-03 14:19:51 -0700133int CryptCommandListener::CryptfsCmd::runCommand(SocketClient *cli,
134 int argc, char **argv) {
135 if ((cli->getUid() != 0) && (cli->getUid() != AID_SYSTEM)) {
136 cli->sendMsg(ResponseCode::CommandNoPermission, "No permission to run cryptfs commands", false);
137 return 0;
138 }
139
140 if (argc < 2) {
141 cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing Argument", false);
142 return 0;
143 }
144
145 int rc = 0;
146
Paul Crowleyee6b1642015-12-10 16:51:53 +0000147 std::string subcommand(argv[1]);
148 if (subcommand == "checkpw") {
Paul Crowley34b813e2015-12-10 16:26:15 +0000149 CHECK_ARGC(3, "checkpw <passwd>");
Paul Lawrenced0b42952015-06-03 14:19:51 -0700150 dumpArgs(argc, argv, 2);
151 rc = cryptfs_check_passwd(argv[2]);
Paul Crowleyee6b1642015-12-10 16:51:53 +0000152 } else if (subcommand == "restart") {
Paul Crowley34b813e2015-12-10 16:26:15 +0000153 CHECK_ARGC(2, "restart");
Paul Lawrenced0b42952015-06-03 14:19:51 -0700154 dumpArgs(argc, argv, -1);
155 rc = cryptfs_restart();
Paul Crowleyee6b1642015-12-10 16:51:53 +0000156 } else if (subcommand == "cryptocomplete") {
Paul Crowley34b813e2015-12-10 16:26:15 +0000157 CHECK_ARGC(2, "cryptocomplete");
Paul Lawrenced0b42952015-06-03 14:19:51 -0700158 dumpArgs(argc, argv, -1);
159 rc = cryptfs_crypto_complete();
Paul Crowleyee6b1642015-12-10 16:51:53 +0000160 } else if (subcommand == "enablecrypto") {
Paul Lawrenced0b42952015-06-03 14:19:51 -0700161 const char* syntax = "Usage: cryptfs enablecrypto <wipe|inplace> "
Paul Lawrence569649f2015-09-09 12:13:00 -0700162 "default|password|pin|pattern [passwd] [noui]";
163
164 // This should be replaced with a command line parser if more options
165 // are added
166 bool valid = true;
167 bool no_ui = false;
168 int type = CRYPT_TYPE_DEFAULT;
169 int options = 4; // Optional parameters are at this offset
170 if (argc < 4) {
171 // Minimum 4 parameters
172 valid = false;
173 } else if (strcmp(argv[2], "wipe") && strcmp(argv[2], "inplace") ) {
174 // Second parameter must be wipe or inplace
175 valid = false;
176 } else {
177 // Third parameter must be valid type
178 type = getType(argv[3]);
179 if (type == -1) {
180 valid = false;
181 } else if (type != CRYPT_TYPE_DEFAULT) {
182 options++;
183 }
184 }
185
186 if (valid) {
187 if(argc < options) {
188 // Too few parameters
189 valid = false;
190 } else if (argc == options) {
191 // No more, done
192 } else if (argc == options + 1) {
193 // One option, must be noui
194 if (!strcmp(argv[options], "noui")) {
195 no_ui = true;
196 } else {
197 valid = false;
198 }
199 } else {
200 // Too many options
201 valid = false;
202 }
203 }
204
205 if (!valid ) {
Paul Lawrenced0b42952015-06-03 14:19:51 -0700206 cli->sendMsg(ResponseCode::CommandSyntaxError, syntax, false);
207 return 0;
208 }
Paul Lawrence569649f2015-09-09 12:13:00 -0700209
Paul Lawrenced0b42952015-06-03 14:19:51 -0700210 dumpArgs(argc, argv, 4);
211
212 int tries;
213 for (tries = 0; tries < 2; ++tries) {
Paul Lawrenced0b42952015-06-03 14:19:51 -0700214 if (type == -1) {
215 cli->sendMsg(ResponseCode::CommandSyntaxError, syntax,
216 false);
217 return 0;
218 } else if (type == CRYPT_TYPE_DEFAULT) {
Paul Lawrence569649f2015-09-09 12:13:00 -0700219 rc = cryptfs_enable_default(argv[2], no_ui);
Paul Lawrenced0b42952015-06-03 14:19:51 -0700220 } else {
Paul Lawrence569649f2015-09-09 12:13:00 -0700221 rc = cryptfs_enable(argv[2], type, argv[4], no_ui);
Paul Lawrenced0b42952015-06-03 14:19:51 -0700222 }
223
224 if (rc == 0) {
225 break;
226 } else if (tries == 0) {
227 Process::killProcessesWithOpenFiles(DATA_MNT_POINT, SIGKILL);
228 }
229 }
Paul Crowleyee6b1642015-12-10 16:51:53 +0000230 } else if (subcommand == "enablefilecrypto") {
Paul Crowley34b813e2015-12-10 16:26:15 +0000231 CHECK_ARGC(2, "enablefilecrypto");
Paul Lawrenced0b42952015-06-03 14:19:51 -0700232 dumpArgs(argc, argv, -1);
233 rc = cryptfs_enable_file();
Paul Crowleyee6b1642015-12-10 16:51:53 +0000234 } else if (subcommand == "changepw") {
Paul Lawrenced0b42952015-06-03 14:19:51 -0700235 const char* syntax = "Usage: cryptfs changepw "
236 "default|password|pin|pattern [newpasswd]";
237 const char* password;
238 if (argc == 3) {
239 password = "";
240 } else if (argc == 4) {
241 password = argv[3];
242 } else {
243 cli->sendMsg(ResponseCode::CommandSyntaxError, syntax, false);
244 return 0;
245 }
246 int type = getType(argv[2]);
247 if (type == -1) {
248 cli->sendMsg(ResponseCode::CommandSyntaxError, syntax, false);
249 return 0;
250 }
251 SLOGD("cryptfs changepw %s {}", argv[2]);
252 rc = cryptfs_changepw(type, password);
Paul Crowleyee6b1642015-12-10 16:51:53 +0000253 } else if (subcommand == "verifypw") {
Paul Crowley34b813e2015-12-10 16:26:15 +0000254 CHECK_ARGC(3, "verifypw <passwd>");
Paul Lawrenced0b42952015-06-03 14:19:51 -0700255 SLOGD("cryptfs verifypw {}");
256 rc = cryptfs_verify_passwd(argv[2]);
Paul Crowleyee6b1642015-12-10 16:51:53 +0000257 } else if (subcommand == "getfield") {
Paul Crowley34b813e2015-12-10 16:26:15 +0000258 CHECK_ARGC(3, "getfield <fieldname>");
Paul Lawrenced0b42952015-06-03 14:19:51 -0700259 char *valbuf;
260 int valbuf_len = PROPERTY_VALUE_MAX;
261
Paul Lawrenced0b42952015-06-03 14:19:51 -0700262 dumpArgs(argc, argv, -1);
263
264 // Increase the buffer size until it is big enough for the field value stored.
265 while (1) {
266 valbuf = (char*)malloc(valbuf_len);
267 if (valbuf == NULL) {
268 cli->sendMsg(ResponseCode::OperationFailed, "Failed to allocate memory", false);
269 return 0;
270 }
271 rc = cryptfs_getfield(argv[2], valbuf, valbuf_len);
272 if (rc != CRYPTO_GETFIELD_ERROR_BUF_TOO_SMALL) {
273 break;
274 }
275 free(valbuf);
276 valbuf_len *= 2;
277 }
278 if (rc == CRYPTO_GETFIELD_OK) {
279 cli->sendMsg(ResponseCode::CryptfsGetfieldResult, valbuf, false);
280 }
281 free(valbuf);
Paul Crowleyee6b1642015-12-10 16:51:53 +0000282 } else if (subcommand == "setfield") {
Paul Crowley34b813e2015-12-10 16:26:15 +0000283 CHECK_ARGC(4, "setfield <fieldname> <value>");
Paul Lawrenced0b42952015-06-03 14:19:51 -0700284 dumpArgs(argc, argv, -1);
285 rc = cryptfs_setfield(argv[2], argv[3]);
Paul Crowleyee6b1642015-12-10 16:51:53 +0000286 } else if (subcommand == "mountdefaultencrypted") {
Paul Crowley34b813e2015-12-10 16:26:15 +0000287 CHECK_ARGC(2, "mountdefaultencrypted");
Paul Lawrenced0b42952015-06-03 14:19:51 -0700288 SLOGD("cryptfs mountdefaultencrypted");
289 dumpArgs(argc, argv, -1);
290 rc = cryptfs_mount_default_encrypted();
Paul Crowleyee6b1642015-12-10 16:51:53 +0000291 } else if (subcommand == "getpwtype") {
Paul Crowley34b813e2015-12-10 16:26:15 +0000292 CHECK_ARGC(2, "getpwtype");
Paul Lawrenced0b42952015-06-03 14:19:51 -0700293 SLOGD("cryptfs getpwtype");
294 dumpArgs(argc, argv, -1);
295 switch(cryptfs_get_password_type()) {
296 case CRYPT_TYPE_PASSWORD:
297 cli->sendMsg(ResponseCode::PasswordTypeResult, "password", false);
298 return 0;
299 case CRYPT_TYPE_PATTERN:
300 cli->sendMsg(ResponseCode::PasswordTypeResult, "pattern", false);
301 return 0;
302 case CRYPT_TYPE_PIN:
303 cli->sendMsg(ResponseCode::PasswordTypeResult, "pin", false);
304 return 0;
305 case CRYPT_TYPE_DEFAULT:
306 cli->sendMsg(ResponseCode::PasswordTypeResult, "default", false);
307 return 0;
308 default:
309 /** @TODO better error and make sure handled by callers */
310 cli->sendMsg(ResponseCode::OpFailedStorageNotFound, "Error", false);
311 return 0;
312 }
Paul Crowleyee6b1642015-12-10 16:51:53 +0000313 } else if (subcommand == "getpw") {
Paul Crowley34b813e2015-12-10 16:26:15 +0000314 CHECK_ARGC(2, "getpw");
Paul Lawrenced0b42952015-06-03 14:19:51 -0700315 SLOGD("cryptfs getpw");
316 dumpArgs(argc, argv, -1);
317 const char* password = cryptfs_get_password();
318 if (password) {
319 char* message = 0;
320 int size = asprintf(&message, "{{sensitive}} %s", password);
321 if (size != -1) {
322 cli->sendMsg(ResponseCode::CommandOkay, message, false);
323 memset(message, 0, size);
324 free (message);
325 return 0;
326 }
327 }
328 rc = -1;
Paul Crowleyee6b1642015-12-10 16:51:53 +0000329 } else if (subcommand == "clearpw") {
Paul Crowley34b813e2015-12-10 16:26:15 +0000330 CHECK_ARGC(2, "clearpw");
Paul Lawrenced0b42952015-06-03 14:19:51 -0700331 SLOGD("cryptfs clearpw");
332 dumpArgs(argc, argv, -1);
333 cryptfs_clear_password();
334 rc = 0;
Paul Crowleyee6b1642015-12-10 16:51:53 +0000335 } else if (subcommand == "setusercryptopolicies") {
Paul Crowley34b813e2015-12-10 16:26:15 +0000336 CHECK_ARGC(3, "setusercryptopolicies <path>");
Paul Crowley95376d62015-05-06 15:04:43 +0100337 SLOGD("cryptfs setusercryptopolicies");
338 dumpArgs(argc, argv, -1);
Paul Crowley27cbce92015-12-10 14:51:30 +0000339 rc = e4crypt_vold_set_user_crypto_policies(argv[2]);
Jeff Sharkeyd2c96e72015-11-08 17:56:23 -0800340
Paul Crowleyee6b1642015-12-10 16:51:53 +0000341 } else if (subcommand == "isConvertibleToFBE") {
Paul Crowley34b813e2015-12-10 16:26:15 +0000342 CHECK_ARGC(2, "isConvertibleToFBE");
Paul Lawrence0c247462015-10-29 10:30:57 -0700343 // ext4enc:TODO: send a CommandSyntaxError if argv[2] not an integer
344 SLOGD("cryptfs isConvertibleToFBE");
345 dumpArgs(argc, argv, -1);
346 rc = cryptfs_isConvertibleToFBE();
Jeff Sharkeyd2c96e72015-11-08 17:56:23 -0800347
Paul Crowleyee6b1642015-12-10 16:51:53 +0000348 } else if (subcommand == "create_user_key") {
Paul Crowley34b813e2015-12-10 16:26:15 +0000349 CHECK_ARGC(5, "create_user_key <user> <serial> <ephemeral>");
Lenka Trochtova395039f2015-11-25 10:13:03 +0100350 return sendGenericOkFail(cli,
Paul Crowley27cbce92015-12-10 14:51:30 +0000351 e4crypt_vold_create_user_key(atoi(argv[2]),
352 atoi(argv[3]),
353 atoi(argv[4]) != 0));
Jeff Sharkeyd2c96e72015-11-08 17:56:23 -0800354
Paul Crowleyee6b1642015-12-10 16:51:53 +0000355 } else if (subcommand == "destroy_user_key") {
Paul Crowley34b813e2015-12-10 16:26:15 +0000356 CHECK_ARGC(3, "destroy_user_key <user>");
Jeff Sharkeyd2c96e72015-11-08 17:56:23 -0800357 return sendGenericOkFail(cli, e4crypt_destroy_user_key(atoi(argv[2])));
358
Paul Crowleyee6b1642015-12-10 16:51:53 +0000359 } else if (subcommand == "unlock_user_key") {
Paul Crowley34b813e2015-12-10 16:26:15 +0000360 CHECK_ARGC(5, "unlock_user_key <user> <serial> <token>");
Jeff Sharkeyd2c96e72015-11-08 17:56:23 -0800361 return sendGenericOkFail(cli, e4crypt_unlock_user_key(atoi(argv[2]), parseNull(argv[4])));
362
Paul Crowleyee6b1642015-12-10 16:51:53 +0000363 } else if (subcommand == "lock_user_key") {
Paul Crowley34b813e2015-12-10 16:26:15 +0000364 CHECK_ARGC(3, "lock_user_key <user>");
Jeff Sharkeyd2c96e72015-11-08 17:56:23 -0800365 return sendGenericOkFail(cli, e4crypt_lock_user_key(atoi(argv[2])));
366
Paul Crowleyee6b1642015-12-10 16:51:53 +0000367 } else if (subcommand == "prepare_user_storage") {
Paul Crowley34b813e2015-12-10 16:26:15 +0000368 CHECK_ARGC(6, "prepare_user_storage <uuid> <user> <serial> <ephemeral>");
Lenka Trochtova395039f2015-11-25 10:13:03 +0100369 return sendGenericOkFail(cli, e4crypt_prepare_user_storage(
370 parseNull(argv[2]), atoi(argv[3]), atoi(argv[4]) != 0));
Jeff Sharkeyd2c96e72015-11-08 17:56:23 -0800371
Paul Lawrenced0b42952015-06-03 14:19:51 -0700372 } else {
373 dumpArgs(argc, argv, -1);
Paul Crowleyee6b1642015-12-10 16:51:53 +0000374 cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown cryptfs subcommand", false);
Paul Lawrenced0b42952015-06-03 14:19:51 -0700375 return 0;
376 }
377
378 // Always report that the command succeeded and return the error code.
379 // The caller will check the return value to see what the error was.
380 char msg[255];
381 snprintf(msg, sizeof(msg), "%d", rc);
382 cli->sendMsg(ResponseCode::CommandOkay, msg, false);
383
384 return 0;
385}