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/stat.h>
20 #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 #include <algorithm>
33 #include <thread>
34
35 #define LOG_TAG "VoldCryptCmdListener"
36
37 #include <android-base/logging.h>
38 #include <android-base/stringprintf.h>
39
40 #include <cutils/fs.h>
41 #include <cutils/log.h>
42 #include <cutils/sockets.h>
43
44 #include <sysutils/SocketClient.h>
45 #include <private/android_filesystem_config.h>
46
47 #include "CryptCommandListener.h"
48 #include "Process.h"
49 #include "ResponseCode.h"
50 #include "cryptfs.h"
51 #include "Ext4Crypt.h"
52 #include "Utils.h"
53
54 #define DUMP_ARGS 0
55
CryptCommandListener()56 CryptCommandListener::CryptCommandListener() :
57 FrameworkListener("cryptd", true) {
58 registerCmd(new CryptfsCmd());
59 }
60
61 #if DUMP_ARGS
dumpArgs(int argc,char ** argv,int argObscure)62 void CryptCommandListener::dumpArgs(int argc, char **argv, int argObscure) {
63 char buffer[4096];
64 char *p = buffer;
65
66 memset(buffer, 0, sizeof(buffer));
67 int i;
68 for (i = 0; i < argc; i++) {
69 unsigned int len = strlen(argv[i]) + 1; // Account for space
70 if (i == argObscure) {
71 len += 2; // Account for {}
72 }
73 if (((p - buffer) + len) < (sizeof(buffer)-1)) {
74 if (i == argObscure) {
75 *p++ = '{';
76 *p++ = '}';
77 *p++ = ' ';
78 continue;
79 }
80 strcpy(p, argv[i]);
81 p+= strlen(argv[i]);
82 if (i != (argc -1)) {
83 *p++ = ' ';
84 }
85 }
86 }
87 SLOGD("%s", buffer);
88 }
89 #else
dumpArgs(int,char **,int)90 void CryptCommandListener::dumpArgs(int /*argc*/, char ** /*argv*/, int /*argObscure*/) { }
91 #endif
92
sendGenericOkFailOnBool(SocketClient * cli,bool success)93 int CryptCommandListener::sendGenericOkFailOnBool(SocketClient *cli, bool success) {
94 if (success) {
95 return cli->sendMsg(ResponseCode::CommandOkay, "Command succeeded", false);
96 } else {
97 return cli->sendMsg(ResponseCode::OperationFailed, "Command failed", false);
98 }
99 }
100
CryptfsCmd()101 CryptCommandListener::CryptfsCmd::CryptfsCmd() :
102 VoldCommand("cryptfs") {
103 }
104
getType(const char * type)105 static int getType(const char* type)
106 {
107 if (!strcmp(type, "default")) {
108 return CRYPT_TYPE_DEFAULT;
109 } else if (!strcmp(type, "password")) {
110 return CRYPT_TYPE_PASSWORD;
111 } else if (!strcmp(type, "pin")) {
112 return CRYPT_TYPE_PIN;
113 } else if (!strcmp(type, "pattern")) {
114 return CRYPT_TYPE_PATTERN;
115 } else {
116 return -1;
117 }
118 }
119
parseNull(char * arg)120 static char* parseNull(char* arg) {
121 if (strcmp(arg, "!") == 0) {
122 return nullptr;
123 } else {
124 return arg;
125 }
126 }
127
check_argc(SocketClient * cli,const std::string & subcommand,int argc,int expected,std::string usage)128 static bool check_argc(SocketClient *cli, const std::string &subcommand, int argc,
129 int expected, std::string usage) {
130 assert(expected >= 2);
131 if (expected == 2) {
132 assert(usage.empty());
133 } else {
134 assert(!usage.empty());
135 assert(std::count(usage.begin(), usage.end(), ' ') + 3 == expected);
136 }
137 if (argc == expected) {
138 return true;
139 }
140 auto message = std::string() + "Usage: cryptfs " + subcommand;
141 if (!usage.empty()) {
142 message += " " + usage;
143 }
144 cli->sendMsg(ResponseCode::CommandSyntaxError, message.c_str(), false);
145 return false;
146 }
147
do_enablecrypto(char * arg2,char * arg4,int type,bool no_ui)148 static int do_enablecrypto(char* arg2, char* arg4, int type, bool no_ui) {
149 int rc;
150 int tries;
151 for (tries = 0; tries < 2; ++tries) {
152 if (type == CRYPT_TYPE_DEFAULT) {
153 rc = cryptfs_enable_default(arg2, no_ui);
154 } else {
155 rc = cryptfs_enable(arg2, type, arg4, no_ui);
156 }
157
158 if (rc == 0) {
159 free(arg2);
160 free(arg4);
161 return 0;
162 } else if (tries == 0) {
163 Process::killProcessesWithOpenFiles(DATA_MNT_POINT, SIGKILL);
164 }
165 }
166
167 free(arg2);
168 free(arg4);
169 return -1;
170 }
171
runCommand(SocketClient * cli,int argc,char ** argv)172 int CryptCommandListener::CryptfsCmd::runCommand(SocketClient *cli,
173 int argc, char **argv) {
174 if ((cli->getUid() != 0) && (cli->getUid() != AID_SYSTEM)) {
175 cli->sendMsg(ResponseCode::CommandNoPermission, "No permission to run cryptfs commands", false);
176 return 0;
177 }
178
179 if (argc < 2) {
180 cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing subcommand", false);
181 return 0;
182 }
183
184 int rc = 0;
185
186 std::string subcommand(argv[1]);
187 if (subcommand == "checkpw") {
188 if (!check_argc(cli, subcommand, argc, 3, "<passwd>")) return 0;
189 dumpArgs(argc, argv, 2);
190 rc = cryptfs_check_passwd(argv[2]);
191 } else if (subcommand == "restart") {
192 if (!check_argc(cli, subcommand, argc, 2, "")) return 0;
193 dumpArgs(argc, argv, -1);
194
195 // Spawn as thread so init can issue commands back to vold without
196 // causing deadlock, usually as a result of prep_data_fs.
197 std::thread(&cryptfs_restart).detach();
198 } else if (subcommand == "cryptocomplete") {
199 if (!check_argc(cli, subcommand, argc, 2, "")) return 0;
200 dumpArgs(argc, argv, -1);
201 rc = cryptfs_crypto_complete();
202 } else if (subcommand == "enablecrypto") {
203 const char* syntax = "Usage: cryptfs enablecrypto <wipe|inplace> "
204 "default|password|pin|pattern [passwd] [noui]";
205
206 // This should be replaced with a command line parser if more options
207 // are added
208 bool valid = true;
209 bool no_ui = false;
210 int type = CRYPT_TYPE_DEFAULT;
211 int options = 4; // Optional parameters are at this offset
212 if (argc < 4) {
213 // Minimum 4 parameters
214 valid = false;
215 } else if (strcmp(argv[2], "wipe") && strcmp(argv[2], "inplace") ) {
216 // Second parameter must be wipe or inplace
217 valid = false;
218 } else {
219 // Third parameter must be valid type
220 type = getType(argv[3]);
221 if (type == -1) {
222 valid = false;
223 } else if (type != CRYPT_TYPE_DEFAULT) {
224 options++;
225 }
226 }
227
228 if (valid) {
229 if(argc < options) {
230 // Too few parameters
231 valid = false;
232 } else if (argc == options) {
233 // No more, done
234 } else if (argc == options + 1) {
235 // One option, must be noui
236 if (!strcmp(argv[options], "noui")) {
237 no_ui = true;
238 } else {
239 valid = false;
240 }
241 } else {
242 // Too many options
243 valid = false;
244 }
245 }
246
247 if (!valid) {
248 cli->sendMsg(ResponseCode::CommandSyntaxError, syntax, false);
249 return 0;
250 }
251
252 dumpArgs(argc, argv, 4);
253
254 // Spawn as thread so init can issue commands back to vold without
255 // causing deadlock, usually as a result of prep_data_fs.
256 char* arg2 = argc > 2 ? strdup(argv[2]) : NULL;
257 char* arg4 = argc > 4 ? strdup(argv[4]) : NULL;
258 std::thread(&do_enablecrypto, arg2, arg4, type, no_ui).detach();
259 } else if (subcommand == "enablefilecrypto") {
260 if (!check_argc(cli, subcommand, argc, 2, "")) return 0;
261 dumpArgs(argc, argv, -1);
262 rc = cryptfs_enable_file();
263 } else if (subcommand == "changepw") {
264 const char* syntax = "Usage: cryptfs changepw "
265 "default|password|pin|pattern [newpasswd]";
266 const char* password;
267 if (argc == 3) {
268 password = "";
269 } else if (argc == 4) {
270 password = argv[3];
271 } else {
272 cli->sendMsg(ResponseCode::CommandSyntaxError, syntax, false);
273 return 0;
274 }
275 int type = getType(argv[2]);
276 if (type == -1) {
277 cli->sendMsg(ResponseCode::CommandSyntaxError, syntax, false);
278 return 0;
279 }
280 SLOGD("cryptfs changepw %s {}", argv[2]);
281 rc = cryptfs_changepw(type, password);
282 } else if (subcommand == "verifypw") {
283 if (!check_argc(cli, subcommand, argc, 3, "<passwd>")) return 0;
284 SLOGD("cryptfs verifypw {}");
285 rc = cryptfs_verify_passwd(argv[2]);
286 } else if (subcommand == "getfield") {
287 if (!check_argc(cli, subcommand, argc, 3, "<fieldname>")) return 0;
288 char *valbuf;
289 int valbuf_len = PROPERTY_VALUE_MAX;
290
291 dumpArgs(argc, argv, -1);
292
293 // Increase the buffer size until it is big enough for the field value stored.
294 while (1) {
295 valbuf = (char*)malloc(valbuf_len);
296 if (valbuf == NULL) {
297 cli->sendMsg(ResponseCode::OperationFailed, "Failed to allocate memory", false);
298 return 0;
299 }
300 rc = cryptfs_getfield(argv[2], valbuf, valbuf_len);
301 if (rc != CRYPTO_GETFIELD_ERROR_BUF_TOO_SMALL) {
302 break;
303 }
304 free(valbuf);
305 valbuf_len *= 2;
306 }
307 if (rc == CRYPTO_GETFIELD_OK) {
308 cli->sendMsg(ResponseCode::CryptfsGetfieldResult, valbuf, false);
309 }
310 free(valbuf);
311 } else if (subcommand == "setfield") {
312 if (!check_argc(cli, subcommand, argc, 4, "<fieldname> <value>")) return 0;
313 dumpArgs(argc, argv, -1);
314 rc = cryptfs_setfield(argv[2], argv[3]);
315 } else if (subcommand == "mountdefaultencrypted") {
316 if (!check_argc(cli, subcommand, argc, 2, "")) return 0;
317 SLOGD("cryptfs mountdefaultencrypted");
318 dumpArgs(argc, argv, -1);
319
320 // Spawn as thread so init can issue commands back to vold without
321 // causing deadlock, usually as a result of prep_data_fs.
322 std::thread(&cryptfs_mount_default_encrypted).detach();
323 } else if (subcommand == "getpwtype") {
324 if (!check_argc(cli, subcommand, argc, 2, "")) return 0;
325 SLOGD("cryptfs getpwtype");
326 dumpArgs(argc, argv, -1);
327 switch(cryptfs_get_password_type()) {
328 case CRYPT_TYPE_PASSWORD:
329 cli->sendMsg(ResponseCode::PasswordTypeResult, "password", false);
330 return 0;
331 case CRYPT_TYPE_PATTERN:
332 cli->sendMsg(ResponseCode::PasswordTypeResult, "pattern", false);
333 return 0;
334 case CRYPT_TYPE_PIN:
335 cli->sendMsg(ResponseCode::PasswordTypeResult, "pin", false);
336 return 0;
337 case CRYPT_TYPE_DEFAULT:
338 cli->sendMsg(ResponseCode::PasswordTypeResult, "default", false);
339 return 0;
340 default:
341 /** @TODO better error and make sure handled by callers */
342 cli->sendMsg(ResponseCode::OpFailedStorageNotFound, "Error", false);
343 return 0;
344 }
345 } else if (subcommand == "getpw") {
346 if (!check_argc(cli, subcommand, argc, 2, "")) return 0;
347 SLOGD("cryptfs getpw");
348 dumpArgs(argc, argv, -1);
349 const char* password = cryptfs_get_password();
350 if (password) {
351 char* message = 0;
352 int size = asprintf(&message, "{{sensitive}} %s", password);
353 if (size != -1) {
354 cli->sendMsg(ResponseCode::CommandOkay, message, false);
355 memset(message, 0, size);
356 free (message);
357 return 0;
358 }
359 }
360 rc = -1;
361 } else if (subcommand == "clearpw") {
362 if (!check_argc(cli, subcommand, argc, 2, "")) return 0;
363 SLOGD("cryptfs clearpw");
364 dumpArgs(argc, argv, -1);
365 cryptfs_clear_password();
366 rc = 0;
367
368 } else if (subcommand == "isConvertibleToFBE") {
369 if (!check_argc(cli, subcommand, argc, 2, "")) return 0;
370 // ext4enc:TODO: send a CommandSyntaxError if argv[2] not an integer
371 SLOGD("cryptfs isConvertibleToFBE");
372 dumpArgs(argc, argv, -1);
373 rc = cryptfs_isConvertibleToFBE();
374
375 } else if (subcommand == "init_user0") {
376 if (!check_argc(cli, subcommand, argc, 2, "")) return 0;
377 return sendGenericOkFailOnBool(cli, e4crypt_init_user0());
378
379 } else if (subcommand == "create_user_key") {
380 if (!check_argc(cli, subcommand, argc, 5, "<user> <serial> <ephemeral>")) return 0;
381 return sendGenericOkFailOnBool(cli, e4crypt_vold_create_user_key(
382 atoi(argv[2]), atoi(argv[3]), atoi(argv[4]) != 0));
383
384 } else if (subcommand == "destroy_user_key") {
385 if (!check_argc(cli, subcommand, argc, 3, "<user>")) return 0;
386 return sendGenericOkFailOnBool(cli, e4crypt_destroy_user_key(atoi(argv[2])));
387
388 } else if (subcommand == "add_user_key_auth") {
389 if (!check_argc(cli, subcommand, argc, 6, "<user> <serial> <token> <secret>")) return 0;
390 return sendGenericOkFailOnBool(cli, e4crypt_add_user_key_auth(
391 atoi(argv[2]), atoi(argv[3]), argv[4], argv[5]));
392
393 } else if (subcommand == "fixate_newest_user_key_auth") {
394 if (!check_argc(cli, subcommand, argc, 3, "<user>")) return 0;
395 return sendGenericOkFailOnBool(cli, e4crypt_fixate_newest_user_key_auth(atoi(argv[2])));
396
397 } else if (subcommand == "unlock_user_key") {
398 if (!check_argc(cli, subcommand, argc, 6, "<user> <serial> <token> <secret>")) return 0;
399 return sendGenericOkFailOnBool(cli, e4crypt_unlock_user_key(
400 atoi(argv[2]), atoi(argv[3]), argv[4], argv[5]));
401
402 } else if (subcommand == "lock_user_key") {
403 if (!check_argc(cli, subcommand, argc, 3, "<user>")) return 0;
404 return sendGenericOkFailOnBool(cli, e4crypt_lock_user_key(atoi(argv[2])));
405
406 } else if (subcommand == "prepare_user_storage") {
407 if (!check_argc(cli, subcommand, argc, 6, "<uuid> <user> <serial> <flags>")) return 0;
408 return sendGenericOkFailOnBool(cli, e4crypt_prepare_user_storage(
409 parseNull(argv[2]), atoi(argv[3]), atoi(argv[4]), atoi(argv[5])));
410
411 } else if (subcommand == "destroy_user_storage") {
412 if (!check_argc(cli, subcommand, argc, 5, "<uuid> <user> <flags>")) return 0;
413 return sendGenericOkFailOnBool(cli,
414 e4crypt_destroy_user_storage(parseNull(argv[2]), atoi(argv[3]), atoi(argv[4])));
415
416 } else {
417 dumpArgs(argc, argv, -1);
418 cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown cryptfs subcommand", false);
419 return 0;
420 }
421
422 // Always report that the command succeeded and return the error code.
423 // The caller will check the return value to see what the error was.
424 char msg[255];
425 snprintf(msg, sizeof(msg), "%d", rc);
426 cli->sendMsg(ResponseCode::CommandOkay, msg, false);
427
428 return 0;
429 }
430