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>
19 #include <sys/types.h>
20 #include <netinet/in.h>
21 #include <arpa/inet.h>
31 #define LOG_TAG "VoldCryptCmdListener"
33 #include <base/stringprintf.h>
34 #include <cutils/fs.h>
35 #include <cutils/log.h>
36 #include <cutils/sockets.h>
38 #include <sysutils/SocketClient.h>
39 #include <private/android_filesystem_config.h>
41 #include "CryptCommandListener.h"
43 #include "ResponseCode.h"
48 CryptCommandListener::CryptCommandListener() :
49 FrameworkListener("cryptd", true) {
50 registerCmd(new CryptfsCmd());
54 void CryptCommandListener::dumpArgs(int argc, char **argv, int argObscure) {
58 memset(buffer, 0, sizeof(buffer));
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 {}
65 if (((p - buffer) + len) < (sizeof(buffer)-1)) {
66 if (i == argObscure) {
82 void CryptCommandListener::dumpArgs(int /*argc*/, char ** /*argv*/, int /*argObscure*/) { }
85 int CryptCommandListener::sendGenericOkFail(SocketClient *cli, int cond) {
87 return cli->sendMsg(ResponseCode::CommandOkay, "Command succeeded", false);
89 return cli->sendMsg(ResponseCode::OperationFailed, "Command failed", false);
93 CryptCommandListener::CryptfsCmd::CryptfsCmd() :
94 VoldCommand("cryptfs") {
97 static int getType(const char* type)
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;
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);
120 cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing Argument", false);
126 if (!strcmp(argv[1], "checkpw")) {
128 cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: cryptfs checkpw <passwd>", false);
131 dumpArgs(argc, argv, 2);
132 rc = cryptfs_check_passwd(argv[2]);
133 } else if (!strcmp(argv[1], "restart")) {
135 cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: cryptfs restart", false);
138 dumpArgs(argc, argv, -1);
139 rc = cryptfs_restart();
140 } else if (!strcmp(argv[1], "cryptocomplete")) {
142 cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: cryptfs cryptocomplete", false);
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);
155 dumpArgs(argc, argv, 4);
158 for (tries = 0; tries < 2; ++tries) {
159 int type = getType(argv[3]);
161 cli->sendMsg(ResponseCode::CommandSyntaxError, syntax,
164 } else if (type == CRYPT_TYPE_DEFAULT) {
165 rc = cryptfs_enable_default(argv[2], /*allow_reboot*/false);
167 rc = cryptfs_enable(argv[2], type, argv[4],
168 /*allow_reboot*/false);
173 } else if (tries == 0) {
174 Process::killProcessesWithOpenFiles(DATA_MNT_POINT, SIGKILL);
177 } else if (!strcmp(argv[1], "enablefilecrypto")) {
178 const char* syntax = "Usage: cryptfs enablefilecrypto";
180 cli->sendMsg(ResponseCode::CommandSyntaxError, syntax, false);
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;
191 } else if (argc == 4) {
194 cli->sendMsg(ResponseCode::CommandSyntaxError, syntax, false);
197 int type = getType(argv[2]);
199 cli->sendMsg(ResponseCode::CommandSyntaxError, syntax, false);
202 SLOGD("cryptfs changepw %s {}", argv[2]);
203 rc = cryptfs_changepw(type, password);
204 } else if (!strcmp(argv[1], "verifypw")) {
206 cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: cryptfs verifypw <passwd>", false);
209 SLOGD("cryptfs verifypw {}");
210 rc = cryptfs_verify_passwd(argv[2]);
211 } else if (!strcmp(argv[1], "getfield")) {
213 int valbuf_len = PROPERTY_VALUE_MAX;
216 cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: cryptfs getfield <fieldname>", false);
219 dumpArgs(argc, argv, -1);
221 // Increase the buffer size until it is big enough for the field value stored.
223 valbuf = (char*)malloc(valbuf_len);
224 if (valbuf == NULL) {
225 cli->sendMsg(ResponseCode::OperationFailed, "Failed to allocate memory", false);
228 rc = cryptfs_getfield(argv[2], valbuf, valbuf_len);
229 if (rc != CRYPTO_GETFIELD_ERROR_BUF_TOO_SMALL) {
235 if (rc == CRYPTO_GETFIELD_OK) {
236 cli->sendMsg(ResponseCode::CryptfsGetfieldResult, valbuf, false);
239 } else if (!strcmp(argv[1], "setfield")) {
241 cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: cryptfs setfield <fieldname> <value>", false);
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);
257 case CRYPT_TYPE_PATTERN:
258 cli->sendMsg(ResponseCode::PasswordTypeResult, "pattern", false);
261 cli->sendMsg(ResponseCode::PasswordTypeResult, "pin", false);
263 case CRYPT_TYPE_DEFAULT:
264 cli->sendMsg(ResponseCode::PasswordTypeResult, "default", false);
267 /** @TODO better error and make sure handled by callers */
268 cli->sendMsg(ResponseCode::OpFailedStorageNotFound, "Error", false);
271 } else if (!strcmp(argv[1], "getpw")) {
272 SLOGD("cryptfs getpw");
273 dumpArgs(argc, argv, -1);
274 const char* password = cryptfs_get_password();
277 int size = asprintf(&message, "{{sensitive}} %s", password);
279 cli->sendMsg(ResponseCode::CommandOkay, message, false);
280 memset(message, 0, size);
286 } else if (!strcmp(argv[1], "clearpw")) {
287 SLOGD("cryptfs clearpw");
288 dumpArgs(argc, argv, -1);
289 cryptfs_clear_password();
292 dumpArgs(argc, argv, -1);
293 cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown cryptfs cmd", false);
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.
300 snprintf(msg, sizeof(msg), "%d", rc);
301 cli->sendMsg(ResponseCode::CommandOkay, msg, false);