blob: cebd271a0aa50c2245063a39a294b3328ebbbece [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>
19#include <sys/types.h>
20#include <netinet/in.h>
21#include <arpa/inet.h>
22#include <dirent.h>
23#include <errno.h>
24#include <fcntl.h>
25#include <fs_mgr.h>
26#include <stdio.h>
27#include <string.h>
28#include <stdint.h>
29#include <inttypes.h>
30
31#define LOG_TAG "VoldCryptCmdListener"
32
Elliott Hughes7e128fb2015-12-04 15:50:53 -080033#include <android-base/stringprintf.h>
Paul Lawrenced0b42952015-06-03 14:19:51 -070034#include <cutils/fs.h>
35#include <cutils/log.h>
36#include <cutils/sockets.h>
37
38#include <sysutils/SocketClient.h>
39#include <private/android_filesystem_config.h>
40
41#include "CryptCommandListener.h"
42#include "Process.h"
43#include "ResponseCode.h"
44#include "cryptfs.h"
Paul Crowley95376d62015-05-06 15:04:43 +010045#include "Ext4Crypt.h"
Paul Lawrenced0b42952015-06-03 14:19:51 -070046
47#define DUMP_ARGS 0
48
49CryptCommandListener::CryptCommandListener() :
50FrameworkListener("cryptd", true) {
51 registerCmd(new CryptfsCmd());
52}
53
54#if DUMP_ARGS
55void CryptCommandListener::dumpArgs(int argc, char **argv, int argObscure) {
56 char buffer[4096];
57 char *p = buffer;
58
59 memset(buffer, 0, sizeof(buffer));
60 int i;
61 for (i = 0; i < argc; i++) {
62 unsigned int len = strlen(argv[i]) + 1; // Account for space
63 if (i == argObscure) {
64 len += 2; // Account for {}
65 }
66 if (((p - buffer) + len) < (sizeof(buffer)-1)) {
67 if (i == argObscure) {
68 *p++ = '{';
69 *p++ = '}';
70 *p++ = ' ';
71 continue;
72 }
73 strcpy(p, argv[i]);
74 p+= strlen(argv[i]);
75 if (i != (argc -1)) {
76 *p++ = ' ';
77 }
78 }
79 }
80 SLOGD("%s", buffer);
81}
82#else
83void CryptCommandListener::dumpArgs(int /*argc*/, char ** /*argv*/, int /*argObscure*/) { }
84#endif
85
86int CryptCommandListener::sendGenericOkFail(SocketClient *cli, int cond) {
87 if (!cond) {
88 return cli->sendMsg(ResponseCode::CommandOkay, "Command succeeded", false);
89 } else {
90 return cli->sendMsg(ResponseCode::OperationFailed, "Command failed", false);
91 }
92}
93
94CryptCommandListener::CryptfsCmd::CryptfsCmd() :
95 VoldCommand("cryptfs") {
96}
97
98static int getType(const char* type)
99{
100 if (!strcmp(type, "default")) {
101 return CRYPT_TYPE_DEFAULT;
102 } else if (!strcmp(type, "password")) {
103 return CRYPT_TYPE_PASSWORD;
104 } else if (!strcmp(type, "pin")) {
105 return CRYPT_TYPE_PIN;
106 } else if (!strcmp(type, "pattern")) {
107 return CRYPT_TYPE_PATTERN;
108 } else {
109 return -1;
110 }
111}
112
113int CryptCommandListener::CryptfsCmd::runCommand(SocketClient *cli,
114 int argc, char **argv) {
115 if ((cli->getUid() != 0) && (cli->getUid() != AID_SYSTEM)) {
116 cli->sendMsg(ResponseCode::CommandNoPermission, "No permission to run cryptfs commands", false);
117 return 0;
118 }
119
120 if (argc < 2) {
121 cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing Argument", false);
122 return 0;
123 }
124
125 int rc = 0;
126
127 if (!strcmp(argv[1], "checkpw")) {
128 if (argc != 3) {
129 cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: cryptfs checkpw <passwd>", false);
130 return 0;
131 }
132 dumpArgs(argc, argv, 2);
133 rc = cryptfs_check_passwd(argv[2]);
134 } else if (!strcmp(argv[1], "restart")) {
135 if (argc != 2) {
136 cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: cryptfs restart", false);
137 return 0;
138 }
139 dumpArgs(argc, argv, -1);
140 rc = cryptfs_restart();
141 } else if (!strcmp(argv[1], "cryptocomplete")) {
142 if (argc != 2) {
143 cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: cryptfs cryptocomplete", false);
144 return 0;
145 }
146 dumpArgs(argc, argv, -1);
147 rc = cryptfs_crypto_complete();
148 } else if (!strcmp(argv[1], "enablecrypto")) {
149 const char* syntax = "Usage: cryptfs enablecrypto <wipe|inplace> "
150 "default|password|pin|pattern [passwd]";
151 if ( (argc != 4 && argc != 5)
152 || (strcmp(argv[2], "wipe") && strcmp(argv[2], "inplace")) ) {
153 cli->sendMsg(ResponseCode::CommandSyntaxError, syntax, false);
154 return 0;
155 }
156 dumpArgs(argc, argv, 4);
157
158 int tries;
159 for (tries = 0; tries < 2; ++tries) {
160 int type = getType(argv[3]);
161 if (type == -1) {
162 cli->sendMsg(ResponseCode::CommandSyntaxError, syntax,
163 false);
164 return 0;
165 } else if (type == CRYPT_TYPE_DEFAULT) {
166 rc = cryptfs_enable_default(argv[2], /*allow_reboot*/false);
167 } else {
168 rc = cryptfs_enable(argv[2], type, argv[4],
169 /*allow_reboot*/false);
170 }
171
172 if (rc == 0) {
173 break;
174 } else if (tries == 0) {
175 Process::killProcessesWithOpenFiles(DATA_MNT_POINT, SIGKILL);
176 }
177 }
178 } else if (!strcmp(argv[1], "enablefilecrypto")) {
179 const char* syntax = "Usage: cryptfs enablefilecrypto";
180 if (argc != 2) {
181 cli->sendMsg(ResponseCode::CommandSyntaxError, syntax, false);
182 return 0;
183 }
184 dumpArgs(argc, argv, -1);
185 rc = cryptfs_enable_file();
186 } else if (!strcmp(argv[1], "changepw")) {
187 const char* syntax = "Usage: cryptfs changepw "
188 "default|password|pin|pattern [newpasswd]";
189 const char* password;
190 if (argc == 3) {
191 password = "";
192 } else if (argc == 4) {
193 password = argv[3];
194 } else {
195 cli->sendMsg(ResponseCode::CommandSyntaxError, syntax, false);
196 return 0;
197 }
198 int type = getType(argv[2]);
199 if (type == -1) {
200 cli->sendMsg(ResponseCode::CommandSyntaxError, syntax, false);
201 return 0;
202 }
203 SLOGD("cryptfs changepw %s {}", argv[2]);
204 rc = cryptfs_changepw(type, password);
205 } else if (!strcmp(argv[1], "verifypw")) {
206 if (argc != 3) {
207 cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: cryptfs verifypw <passwd>", false);
208 return 0;
209 }
210 SLOGD("cryptfs verifypw {}");
211 rc = cryptfs_verify_passwd(argv[2]);
212 } else if (!strcmp(argv[1], "getfield")) {
213 char *valbuf;
214 int valbuf_len = PROPERTY_VALUE_MAX;
215
216 if (argc != 3) {
217 cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: cryptfs getfield <fieldname>", false);
218 return 0;
219 }
220 dumpArgs(argc, argv, -1);
221
222 // Increase the buffer size until it is big enough for the field value stored.
223 while (1) {
224 valbuf = (char*)malloc(valbuf_len);
225 if (valbuf == NULL) {
226 cli->sendMsg(ResponseCode::OperationFailed, "Failed to allocate memory", false);
227 return 0;
228 }
229 rc = cryptfs_getfield(argv[2], valbuf, valbuf_len);
230 if (rc != CRYPTO_GETFIELD_ERROR_BUF_TOO_SMALL) {
231 break;
232 }
233 free(valbuf);
234 valbuf_len *= 2;
235 }
236 if (rc == CRYPTO_GETFIELD_OK) {
237 cli->sendMsg(ResponseCode::CryptfsGetfieldResult, valbuf, false);
238 }
239 free(valbuf);
240 } else if (!strcmp(argv[1], "setfield")) {
241 if (argc != 4) {
242 cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: cryptfs setfield <fieldname> <value>", false);
243 return 0;
244 }
245 dumpArgs(argc, argv, -1);
246 rc = cryptfs_setfield(argv[2], argv[3]);
247 } else if (!strcmp(argv[1], "mountdefaultencrypted")) {
248 SLOGD("cryptfs mountdefaultencrypted");
249 dumpArgs(argc, argv, -1);
250 rc = cryptfs_mount_default_encrypted();
251 } else if (!strcmp(argv[1], "getpwtype")) {
252 SLOGD("cryptfs getpwtype");
253 dumpArgs(argc, argv, -1);
254 switch(cryptfs_get_password_type()) {
255 case CRYPT_TYPE_PASSWORD:
256 cli->sendMsg(ResponseCode::PasswordTypeResult, "password", false);
257 return 0;
258 case CRYPT_TYPE_PATTERN:
259 cli->sendMsg(ResponseCode::PasswordTypeResult, "pattern", false);
260 return 0;
261 case CRYPT_TYPE_PIN:
262 cli->sendMsg(ResponseCode::PasswordTypeResult, "pin", false);
263 return 0;
264 case CRYPT_TYPE_DEFAULT:
265 cli->sendMsg(ResponseCode::PasswordTypeResult, "default", false);
266 return 0;
267 default:
268 /** @TODO better error and make sure handled by callers */
269 cli->sendMsg(ResponseCode::OpFailedStorageNotFound, "Error", false);
270 return 0;
271 }
272 } else if (!strcmp(argv[1], "getpw")) {
273 SLOGD("cryptfs getpw");
274 dumpArgs(argc, argv, -1);
275 const char* password = cryptfs_get_password();
276 if (password) {
277 char* message = 0;
278 int size = asprintf(&message, "{{sensitive}} %s", password);
279 if (size != -1) {
280 cli->sendMsg(ResponseCode::CommandOkay, message, false);
281 memset(message, 0, size);
282 free (message);
283 return 0;
284 }
285 }
286 rc = -1;
287 } else if (!strcmp(argv[1], "clearpw")) {
288 SLOGD("cryptfs clearpw");
289 dumpArgs(argc, argv, -1);
290 cryptfs_clear_password();
291 rc = 0;
Paul Crowley95376d62015-05-06 15:04:43 +0100292 } else if (!strcmp(argv[1], "setusercryptopolicies")) {
293 if (argc != 3) {
294 cli->sendMsg(ResponseCode::CommandSyntaxError,
295 "Usage: cryptfs setusercryptopolicies <path>", false);
296 return 0;
297 }
298 SLOGD("cryptfs setusercryptopolicies");
299 dumpArgs(argc, argv, -1);
300 rc = e4crypt_set_user_crypto_policies(argv[2]);
301 } else if (!strcmp(argv[1], "createnewuserdir")) {
302 if (argc != 4) {
303 cli->sendMsg(ResponseCode::CommandSyntaxError,
304 "Usage: cryptfs createnewuserdir <userHandle> <path>", false);
305 return 0;
306 }
307 // ext4enc:TODO: send a CommandSyntaxError if argv[2] not an integer
308 SLOGD("cryptfs createnewuserdir");
309 dumpArgs(argc, argv, -1);
310 rc = e4crypt_create_new_user_dir(argv[2], argv[3]);
Paul Crowleyb33e8872015-05-19 12:34:09 +0100311 } else if (!strcmp(argv[1], "deleteuserkey")) {
312 if (argc != 3) {
313 cli->sendMsg(ResponseCode::CommandSyntaxError,
314 "Usage: cryptfs deleteuserkey <userHandle>", false);
315 return 0;
316 }
317 // ext4enc:TODO: send a CommandSyntaxError if argv[2] not an integer
318 SLOGD("cryptfs deleteuserkey");
319 dumpArgs(argc, argv, -1);
320 rc = e4crypt_delete_user_key(argv[2]);
Paul Lawrenced0b42952015-06-03 14:19:51 -0700321 } else {
322 dumpArgs(argc, argv, -1);
323 cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown cryptfs cmd", false);
324 return 0;
325 }
326
327 // Always report that the command succeeded and return the error code.
328 // The caller will check the return value to see what the error was.
329 char msg[255];
330 snprintf(msg, sizeof(msg), "%d", rc);
331 cli->sendMsg(ResponseCode::CommandOkay, msg, false);
332
333 return 0;
334}