blob: ac2607a1cef40e665a678572d0e6e268edd2cc3e [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 Lawrenced0b42952015-06-03 14:19:51 -0700125int CryptCommandListener::CryptfsCmd::runCommand(SocketClient *cli,
126 int argc, char **argv) {
127 if ((cli->getUid() != 0) && (cli->getUid() != AID_SYSTEM)) {
128 cli->sendMsg(ResponseCode::CommandNoPermission, "No permission to run cryptfs commands", false);
129 return 0;
130 }
131
132 if (argc < 2) {
133 cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing Argument", false);
134 return 0;
135 }
136
137 int rc = 0;
138
Jeff Sharkeyd2c96e72015-11-08 17:56:23 -0800139 std::string cmd(argv[1]);
Paul Lawrenced0b42952015-06-03 14:19:51 -0700140 if (!strcmp(argv[1], "checkpw")) {
141 if (argc != 3) {
142 cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: cryptfs checkpw <passwd>", false);
143 return 0;
144 }
145 dumpArgs(argc, argv, 2);
146 rc = cryptfs_check_passwd(argv[2]);
147 } else if (!strcmp(argv[1], "restart")) {
148 if (argc != 2) {
149 cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: cryptfs restart", false);
150 return 0;
151 }
152 dumpArgs(argc, argv, -1);
153 rc = cryptfs_restart();
154 } else if (!strcmp(argv[1], "cryptocomplete")) {
155 if (argc != 2) {
156 cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: cryptfs cryptocomplete", false);
157 return 0;
158 }
159 dumpArgs(argc, argv, -1);
160 rc = cryptfs_crypto_complete();
161 } else if (!strcmp(argv[1], "enablecrypto")) {
162 const char* syntax = "Usage: cryptfs enablecrypto <wipe|inplace> "
Paul Lawrence569649f2015-09-09 12:13:00 -0700163 "default|password|pin|pattern [passwd] [noui]";
164
165 // This should be replaced with a command line parser if more options
166 // are added
167 bool valid = true;
168 bool no_ui = false;
169 int type = CRYPT_TYPE_DEFAULT;
170 int options = 4; // Optional parameters are at this offset
171 if (argc < 4) {
172 // Minimum 4 parameters
173 valid = false;
174 } else if (strcmp(argv[2], "wipe") && strcmp(argv[2], "inplace") ) {
175 // Second parameter must be wipe or inplace
176 valid = false;
177 } else {
178 // Third parameter must be valid type
179 type = getType(argv[3]);
180 if (type == -1) {
181 valid = false;
182 } else if (type != CRYPT_TYPE_DEFAULT) {
183 options++;
184 }
185 }
186
187 if (valid) {
188 if(argc < options) {
189 // Too few parameters
190 valid = false;
191 } else if (argc == options) {
192 // No more, done
193 } else if (argc == options + 1) {
194 // One option, must be noui
195 if (!strcmp(argv[options], "noui")) {
196 no_ui = true;
197 } else {
198 valid = false;
199 }
200 } else {
201 // Too many options
202 valid = false;
203 }
204 }
205
206 if (!valid ) {
Paul Lawrenced0b42952015-06-03 14:19:51 -0700207 cli->sendMsg(ResponseCode::CommandSyntaxError, syntax, false);
208 return 0;
209 }
Paul Lawrence569649f2015-09-09 12:13:00 -0700210
Paul Lawrenced0b42952015-06-03 14:19:51 -0700211 dumpArgs(argc, argv, 4);
212
213 int tries;
214 for (tries = 0; tries < 2; ++tries) {
Paul Lawrenced0b42952015-06-03 14:19:51 -0700215 if (type == -1) {
216 cli->sendMsg(ResponseCode::CommandSyntaxError, syntax,
217 false);
218 return 0;
219 } else if (type == CRYPT_TYPE_DEFAULT) {
Paul Lawrence569649f2015-09-09 12:13:00 -0700220 rc = cryptfs_enable_default(argv[2], no_ui);
Paul Lawrenced0b42952015-06-03 14:19:51 -0700221 } else {
Paul Lawrence569649f2015-09-09 12:13:00 -0700222 rc = cryptfs_enable(argv[2], type, argv[4], no_ui);
Paul Lawrenced0b42952015-06-03 14:19:51 -0700223 }
224
225 if (rc == 0) {
226 break;
227 } else if (tries == 0) {
228 Process::killProcessesWithOpenFiles(DATA_MNT_POINT, SIGKILL);
229 }
230 }
231 } else if (!strcmp(argv[1], "enablefilecrypto")) {
232 const char* syntax = "Usage: cryptfs enablefilecrypto";
233 if (argc != 2) {
234 cli->sendMsg(ResponseCode::CommandSyntaxError, syntax, false);
235 return 0;
236 }
237 dumpArgs(argc, argv, -1);
238 rc = cryptfs_enable_file();
239 } else if (!strcmp(argv[1], "changepw")) {
240 const char* syntax = "Usage: cryptfs changepw "
241 "default|password|pin|pattern [newpasswd]";
242 const char* password;
243 if (argc == 3) {
244 password = "";
245 } else if (argc == 4) {
246 password = argv[3];
247 } else {
248 cli->sendMsg(ResponseCode::CommandSyntaxError, syntax, false);
249 return 0;
250 }
251 int type = getType(argv[2]);
252 if (type == -1) {
253 cli->sendMsg(ResponseCode::CommandSyntaxError, syntax, false);
254 return 0;
255 }
256 SLOGD("cryptfs changepw %s {}", argv[2]);
257 rc = cryptfs_changepw(type, password);
258 } else if (!strcmp(argv[1], "verifypw")) {
259 if (argc != 3) {
260 cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: cryptfs verifypw <passwd>", false);
261 return 0;
262 }
263 SLOGD("cryptfs verifypw {}");
264 rc = cryptfs_verify_passwd(argv[2]);
265 } else if (!strcmp(argv[1], "getfield")) {
266 char *valbuf;
267 int valbuf_len = PROPERTY_VALUE_MAX;
268
269 if (argc != 3) {
270 cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: cryptfs getfield <fieldname>", false);
271 return 0;
272 }
273 dumpArgs(argc, argv, -1);
274
275 // Increase the buffer size until it is big enough for the field value stored.
276 while (1) {
277 valbuf = (char*)malloc(valbuf_len);
278 if (valbuf == NULL) {
279 cli->sendMsg(ResponseCode::OperationFailed, "Failed to allocate memory", false);
280 return 0;
281 }
282 rc = cryptfs_getfield(argv[2], valbuf, valbuf_len);
283 if (rc != CRYPTO_GETFIELD_ERROR_BUF_TOO_SMALL) {
284 break;
285 }
286 free(valbuf);
287 valbuf_len *= 2;
288 }
289 if (rc == CRYPTO_GETFIELD_OK) {
290 cli->sendMsg(ResponseCode::CryptfsGetfieldResult, valbuf, false);
291 }
292 free(valbuf);
293 } else if (!strcmp(argv[1], "setfield")) {
294 if (argc != 4) {
295 cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: cryptfs setfield <fieldname> <value>", false);
296 return 0;
297 }
298 dumpArgs(argc, argv, -1);
299 rc = cryptfs_setfield(argv[2], argv[3]);
300 } else if (!strcmp(argv[1], "mountdefaultencrypted")) {
301 SLOGD("cryptfs mountdefaultencrypted");
302 dumpArgs(argc, argv, -1);
303 rc = cryptfs_mount_default_encrypted();
304 } else if (!strcmp(argv[1], "getpwtype")) {
305 SLOGD("cryptfs getpwtype");
306 dumpArgs(argc, argv, -1);
307 switch(cryptfs_get_password_type()) {
308 case CRYPT_TYPE_PASSWORD:
309 cli->sendMsg(ResponseCode::PasswordTypeResult, "password", false);
310 return 0;
311 case CRYPT_TYPE_PATTERN:
312 cli->sendMsg(ResponseCode::PasswordTypeResult, "pattern", false);
313 return 0;
314 case CRYPT_TYPE_PIN:
315 cli->sendMsg(ResponseCode::PasswordTypeResult, "pin", false);
316 return 0;
317 case CRYPT_TYPE_DEFAULT:
318 cli->sendMsg(ResponseCode::PasswordTypeResult, "default", false);
319 return 0;
320 default:
321 /** @TODO better error and make sure handled by callers */
322 cli->sendMsg(ResponseCode::OpFailedStorageNotFound, "Error", false);
323 return 0;
324 }
325 } else if (!strcmp(argv[1], "getpw")) {
326 SLOGD("cryptfs getpw");
327 dumpArgs(argc, argv, -1);
328 const char* password = cryptfs_get_password();
329 if (password) {
330 char* message = 0;
331 int size = asprintf(&message, "{{sensitive}} %s", password);
332 if (size != -1) {
333 cli->sendMsg(ResponseCode::CommandOkay, message, false);
334 memset(message, 0, size);
335 free (message);
336 return 0;
337 }
338 }
339 rc = -1;
340 } else if (!strcmp(argv[1], "clearpw")) {
341 SLOGD("cryptfs clearpw");
342 dumpArgs(argc, argv, -1);
343 cryptfs_clear_password();
344 rc = 0;
Paul Crowley95376d62015-05-06 15:04:43 +0100345 } else if (!strcmp(argv[1], "setusercryptopolicies")) {
346 if (argc != 3) {
347 cli->sendMsg(ResponseCode::CommandSyntaxError,
348 "Usage: cryptfs setusercryptopolicies <path>", false);
349 return 0;
350 }
351 SLOGD("cryptfs setusercryptopolicies");
352 dumpArgs(argc, argv, -1);
353 rc = e4crypt_set_user_crypto_policies(argv[2]);
Jeff Sharkeyd2c96e72015-11-08 17:56:23 -0800354
Paul Lawrence0c247462015-10-29 10:30:57 -0700355 } else if (!strcmp(argv[1], "isConvertibleToFBE")) {
356 if (argc != 2) {
357 cli->sendMsg(ResponseCode::CommandSyntaxError,
358 "Usage: cryptfs isConvertibleToFBE", false);
359 return 0;
360 }
361 // ext4enc:TODO: send a CommandSyntaxError if argv[2] not an integer
362 SLOGD("cryptfs isConvertibleToFBE");
363 dumpArgs(argc, argv, -1);
364 rc = cryptfs_isConvertibleToFBE();
Jeff Sharkeyd2c96e72015-11-08 17:56:23 -0800365
366 } else if (cmd == "create_user_key" && argc > 3) {
367 // create_user_key [user] [serial]
368 return sendGenericOkFail(cli, e4crypt_create_user_key(atoi(argv[2])));
369
370 } else if (cmd == "destroy_user_key" && argc > 2) {
371 // destroy_user_key [user]
372 return sendGenericOkFail(cli, e4crypt_destroy_user_key(atoi(argv[2])));
373
374 } else if (cmd == "unlock_user_key" && argc > 4) {
375 // unlock_user_key [user] [serial] [token]
376 return sendGenericOkFail(cli, e4crypt_unlock_user_key(atoi(argv[2]), parseNull(argv[4])));
377
378 } else if (cmd == "lock_user_key" && argc > 2) {
379 // lock_user_key [user]
380 return sendGenericOkFail(cli, e4crypt_lock_user_key(atoi(argv[2])));
381
382 } else if (cmd == "prepare_user_storage" && argc > 4) {
383 // prepare_user_storage [uuid] [user] [serial]
384 return sendGenericOkFail(cli,
385 e4crypt_prepare_user_storage(parseNull(argv[2]), atoi(argv[3])));
386
Paul Lawrenced0b42952015-06-03 14:19:51 -0700387 } else {
388 dumpArgs(argc, argv, -1);
389 cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown cryptfs cmd", false);
390 return 0;
391 }
392
393 // Always report that the command succeeded and return the error code.
394 // The caller will check the return value to see what the error was.
395 char msg[255];
396 snprintf(msg, sizeof(msg), "%d", rc);
397 cli->sendMsg(ResponseCode::CommandOkay, msg, false);
398
399 return 0;
400}