2 * Copyright (C) 2015 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 #include <sys/socket.h>
20 #include <sys/types.h>
21 #include <netinet/in.h>
22 #include <arpa/inet.h>
32 #define LOG_TAG "VoldCryptCmdListener"
34 #include <android-base/logging.h>
35 #include <android-base/stringprintf.h>
37 #include <cutils/fs.h>
38 #include <cutils/log.h>
39 #include <cutils/sockets.h>
41 #include <sysutils/SocketClient.h>
42 #include <private/android_filesystem_config.h>
44 #include "CryptCommandListener.h"
46 #include "ResponseCode.h"
48 #include "Ext4Crypt.h"
53 CryptCommandListener::CryptCommandListener() :
54 FrameworkListener("cryptd", true) {
55 registerCmd(new CryptfsCmd());
59 void CryptCommandListener::dumpArgs(int argc, char **argv, int argObscure) {
63 memset(buffer, 0, sizeof(buffer));
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 {}
70 if (((p - buffer) + len) < (sizeof(buffer)-1)) {
71 if (i == argObscure) {
87 void CryptCommandListener::dumpArgs(int /*argc*/, char ** /*argv*/, int /*argObscure*/) { }
90 int CryptCommandListener::sendGenericOkFail(SocketClient *cli, int cond) {
92 return cli->sendMsg(ResponseCode::CommandOkay, "Command succeeded", false);
94 return cli->sendMsg(ResponseCode::OperationFailed, "Command failed", false);
98 CryptCommandListener::CryptfsCmd::CryptfsCmd() :
99 VoldCommand("cryptfs") {
102 static int getType(const char* type)
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;
117 static char* parseNull(char* arg) {
118 if (strcmp(arg, "!") == 0) {
125 #define CHECK_ARGC(expected, error) \
127 if (argc != (expected)) { \
128 cli->sendMsg(ResponseCode::CommandSyntaxError, ("Usage: cryptfs " error), false); \
133 int 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);
141 cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing Argument", false);
147 std::string cmd(argv[1]);
148 if (!strcmp(argv[1], "checkpw")) {
149 CHECK_ARGC(3, "checkpw <passwd>");
150 dumpArgs(argc, argv, 2);
151 rc = cryptfs_check_passwd(argv[2]);
152 } else if (!strcmp(argv[1], "restart")) {
153 CHECK_ARGC(2, "restart");
154 dumpArgs(argc, argv, -1);
155 rc = cryptfs_restart();
156 } else if (!strcmp(argv[1], "cryptocomplete")) {
157 CHECK_ARGC(2, "cryptocomplete");
158 dumpArgs(argc, argv, -1);
159 rc = cryptfs_crypto_complete();
160 } else if (!strcmp(argv[1], "enablecrypto")) {
161 const char* syntax = "Usage: cryptfs enablecrypto <wipe|inplace> "
162 "default|password|pin|pattern [passwd] [noui]";
164 // This should be replaced with a command line parser if more options
168 int type = CRYPT_TYPE_DEFAULT;
169 int options = 4; // Optional parameters are at this offset
171 // Minimum 4 parameters
173 } else if (strcmp(argv[2], "wipe") && strcmp(argv[2], "inplace") ) {
174 // Second parameter must be wipe or inplace
177 // Third parameter must be valid type
178 type = getType(argv[3]);
181 } else if (type != CRYPT_TYPE_DEFAULT) {
188 // Too few parameters
190 } else if (argc == options) {
192 } else if (argc == options + 1) {
193 // One option, must be noui
194 if (!strcmp(argv[options], "noui")) {
206 cli->sendMsg(ResponseCode::CommandSyntaxError, syntax, false);
210 dumpArgs(argc, argv, 4);
213 for (tries = 0; tries < 2; ++tries) {
215 cli->sendMsg(ResponseCode::CommandSyntaxError, syntax,
218 } else if (type == CRYPT_TYPE_DEFAULT) {
219 rc = cryptfs_enable_default(argv[2], no_ui);
221 rc = cryptfs_enable(argv[2], type, argv[4], no_ui);
226 } else if (tries == 0) {
227 Process::killProcessesWithOpenFiles(DATA_MNT_POINT, SIGKILL);
230 } else if (!strcmp(argv[1], "enablefilecrypto")) {
231 CHECK_ARGC(2, "enablefilecrypto");
232 dumpArgs(argc, argv, -1);
233 rc = cryptfs_enable_file();
234 } else if (!strcmp(argv[1], "changepw")) {
235 const char* syntax = "Usage: cryptfs changepw "
236 "default|password|pin|pattern [newpasswd]";
237 const char* password;
240 } else if (argc == 4) {
243 cli->sendMsg(ResponseCode::CommandSyntaxError, syntax, false);
246 int type = getType(argv[2]);
248 cli->sendMsg(ResponseCode::CommandSyntaxError, syntax, false);
251 SLOGD("cryptfs changepw %s {}", argv[2]);
252 rc = cryptfs_changepw(type, password);
253 } else if (!strcmp(argv[1], "verifypw")) {
254 CHECK_ARGC(3, "verifypw <passwd>");
255 SLOGD("cryptfs verifypw {}");
256 rc = cryptfs_verify_passwd(argv[2]);
257 } else if (!strcmp(argv[1], "getfield")) {
258 CHECK_ARGC(3, "getfield <fieldname>");
260 int valbuf_len = PROPERTY_VALUE_MAX;
262 dumpArgs(argc, argv, -1);
264 // Increase the buffer size until it is big enough for the field value stored.
266 valbuf = (char*)malloc(valbuf_len);
267 if (valbuf == NULL) {
268 cli->sendMsg(ResponseCode::OperationFailed, "Failed to allocate memory", false);
271 rc = cryptfs_getfield(argv[2], valbuf, valbuf_len);
272 if (rc != CRYPTO_GETFIELD_ERROR_BUF_TOO_SMALL) {
278 if (rc == CRYPTO_GETFIELD_OK) {
279 cli->sendMsg(ResponseCode::CryptfsGetfieldResult, valbuf, false);
282 } else if (!strcmp(argv[1], "setfield")) {
283 CHECK_ARGC(4, "setfield <fieldname> <value>");
284 dumpArgs(argc, argv, -1);
285 rc = cryptfs_setfield(argv[2], argv[3]);
286 } else if (!strcmp(argv[1], "mountdefaultencrypted")) {
287 CHECK_ARGC(2, "mountdefaultencrypted");
288 SLOGD("cryptfs mountdefaultencrypted");
289 dumpArgs(argc, argv, -1);
290 rc = cryptfs_mount_default_encrypted();
291 } else if (!strcmp(argv[1], "getpwtype")) {
292 CHECK_ARGC(2, "getpwtype");
293 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);
299 case CRYPT_TYPE_PATTERN:
300 cli->sendMsg(ResponseCode::PasswordTypeResult, "pattern", false);
303 cli->sendMsg(ResponseCode::PasswordTypeResult, "pin", false);
305 case CRYPT_TYPE_DEFAULT:
306 cli->sendMsg(ResponseCode::PasswordTypeResult, "default", false);
309 /** @TODO better error and make sure handled by callers */
310 cli->sendMsg(ResponseCode::OpFailedStorageNotFound, "Error", false);
313 } else if (!strcmp(argv[1], "getpw")) {
314 CHECK_ARGC(2, "getpw");
315 SLOGD("cryptfs getpw");
316 dumpArgs(argc, argv, -1);
317 const char* password = cryptfs_get_password();
320 int size = asprintf(&message, "{{sensitive}} %s", password);
322 cli->sendMsg(ResponseCode::CommandOkay, message, false);
323 memset(message, 0, size);
329 } else if (!strcmp(argv[1], "clearpw")) {
330 CHECK_ARGC(2, "clearpw");
331 SLOGD("cryptfs clearpw");
332 dumpArgs(argc, argv, -1);
333 cryptfs_clear_password();
335 } else if (!strcmp(argv[1], "setusercryptopolicies")) {
336 CHECK_ARGC(3, "setusercryptopolicies <path>");
337 SLOGD("cryptfs setusercryptopolicies");
338 dumpArgs(argc, argv, -1);
339 rc = e4crypt_vold_set_user_crypto_policies(argv[2]);
341 } else if (!strcmp(argv[1], "isConvertibleToFBE")) {
342 CHECK_ARGC(2, "isConvertibleToFBE");
343 // ext4enc:TODO: send a CommandSyntaxError if argv[2] not an integer
344 SLOGD("cryptfs isConvertibleToFBE");
345 dumpArgs(argc, argv, -1);
346 rc = cryptfs_isConvertibleToFBE();
348 } else if (cmd == "create_user_key") {
349 CHECK_ARGC(5, "create_user_key <user> <serial> <ephemeral>");
350 return sendGenericOkFail(cli,
351 e4crypt_vold_create_user_key(atoi(argv[2]),
353 atoi(argv[4]) != 0));
355 } else if (cmd == "destroy_user_key") {
356 CHECK_ARGC(3, "destroy_user_key <user>");
357 return sendGenericOkFail(cli, e4crypt_destroy_user_key(atoi(argv[2])));
359 } else if (cmd == "unlock_user_key") {
360 CHECK_ARGC(5, "unlock_user_key <user> <serial> <token>");
361 return sendGenericOkFail(cli, e4crypt_unlock_user_key(atoi(argv[2]), parseNull(argv[4])));
363 } else if (cmd == "lock_user_key") {
364 CHECK_ARGC(3, "lock_user_key <user>");
365 return sendGenericOkFail(cli, e4crypt_lock_user_key(atoi(argv[2])));
367 } else if (cmd == "prepare_user_storage") {
368 CHECK_ARGC(6, "prepare_user_storage <uuid> <user> <serial> <ephemeral>");
369 return sendGenericOkFail(cli, e4crypt_prepare_user_storage(
370 parseNull(argv[2]), atoi(argv[3]), atoi(argv[4]) != 0));
373 dumpArgs(argc, argv, -1);
374 cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown cryptfs cmd", false);
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.
381 snprintf(msg, sizeof(msg), "%d", rc);
382 cli->sendMsg(ResponseCode::CommandOkay, msg, false);