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/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
33 #include <base/stringprintf.h>
34 #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"
45 #include "Ext4Crypt.h"
46
47 #define DUMP_ARGS 0
48
CryptCommandListener()49 CryptCommandListener::CryptCommandListener() :
50 FrameworkListener("cryptd", true) {
51 registerCmd(new CryptfsCmd());
52 }
53
54 #if DUMP_ARGS
dumpArgs(int argc,char ** argv,int argObscure)55 void 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
dumpArgs(int,char **,int)83 void CryptCommandListener::dumpArgs(int /*argc*/, char ** /*argv*/, int /*argObscure*/) { }
84 #endif
85
sendGenericOkFail(SocketClient * cli,int cond)86 int 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
CryptfsCmd()94 CryptCommandListener::CryptfsCmd::CryptfsCmd() :
95 VoldCommand("cryptfs") {
96 }
97
getType(const char * type)98 static 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
runCommand(SocketClient * cli,int argc,char ** argv)113 int 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] [noui]";
151
152 // This should be replaced with a command line parser if more options
153 // are added
154 bool valid = true;
155 bool no_ui = false;
156 int type = CRYPT_TYPE_DEFAULT;
157 int options = 4; // Optional parameters are at this offset
158 if (argc < 4) {
159 // Minimum 4 parameters
160 valid = false;
161 } else if (strcmp(argv[2], "wipe") && strcmp(argv[2], "inplace") ) {
162 // Second parameter must be wipe or inplace
163 valid = false;
164 } else {
165 // Third parameter must be valid type
166 type = getType(argv[3]);
167 if (type == -1) {
168 valid = false;
169 } else if (type != CRYPT_TYPE_DEFAULT) {
170 options++;
171 }
172 }
173
174 if (valid) {
175 if(argc < options) {
176 // Too few parameters
177 valid = false;
178 } else if (argc == options) {
179 // No more, done
180 } else if (argc == options + 1) {
181 // One option, must be noui
182 if (!strcmp(argv[options], "noui")) {
183 no_ui = true;
184 } else {
185 valid = false;
186 }
187 } else {
188 // Too many options
189 valid = false;
190 }
191 }
192
193 if (!valid ) {
194 cli->sendMsg(ResponseCode::CommandSyntaxError, syntax, false);
195 return 0;
196 }
197
198 dumpArgs(argc, argv, 4);
199
200 int tries;
201 for (tries = 0; tries < 2; ++tries) {
202 if (type == -1) {
203 cli->sendMsg(ResponseCode::CommandSyntaxError, syntax,
204 false);
205 return 0;
206 } else if (type == CRYPT_TYPE_DEFAULT) {
207 rc = cryptfs_enable_default(argv[2], no_ui);
208 } else {
209 rc = cryptfs_enable(argv[2], type, argv[4], no_ui);
210 }
211
212 if (rc == 0) {
213 break;
214 } else if (tries == 0) {
215 Process::killProcessesWithOpenFiles(DATA_MNT_POINT, SIGKILL);
216 }
217 }
218 } else if (!strcmp(argv[1], "enablefilecrypto")) {
219 const char* syntax = "Usage: cryptfs enablefilecrypto";
220 if (argc != 2) {
221 cli->sendMsg(ResponseCode::CommandSyntaxError, syntax, false);
222 return 0;
223 }
224 dumpArgs(argc, argv, -1);
225 rc = cryptfs_enable_file();
226 } else if (!strcmp(argv[1], "changepw")) {
227 const char* syntax = "Usage: cryptfs changepw "
228 "default|password|pin|pattern [newpasswd]";
229 const char* password;
230 if (argc == 3) {
231 password = "";
232 } else if (argc == 4) {
233 password = argv[3];
234 } else {
235 cli->sendMsg(ResponseCode::CommandSyntaxError, syntax, false);
236 return 0;
237 }
238 int type = getType(argv[2]);
239 if (type == -1) {
240 cli->sendMsg(ResponseCode::CommandSyntaxError, syntax, false);
241 return 0;
242 }
243 SLOGD("cryptfs changepw %s {}", argv[2]);
244 rc = cryptfs_changepw(type, password);
245 } else if (!strcmp(argv[1], "verifypw")) {
246 if (argc != 3) {
247 cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: cryptfs verifypw <passwd>", false);
248 return 0;
249 }
250 SLOGD("cryptfs verifypw {}");
251 rc = cryptfs_verify_passwd(argv[2]);
252 } else if (!strcmp(argv[1], "getfield")) {
253 char *valbuf;
254 int valbuf_len = PROPERTY_VALUE_MAX;
255
256 if (argc != 3) {
257 cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: cryptfs getfield <fieldname>", false);
258 return 0;
259 }
260 dumpArgs(argc, argv, -1);
261
262 // Increase the buffer size until it is big enough for the field value stored.
263 while (1) {
264 valbuf = (char*)malloc(valbuf_len);
265 if (valbuf == NULL) {
266 cli->sendMsg(ResponseCode::OperationFailed, "Failed to allocate memory", false);
267 return 0;
268 }
269 rc = cryptfs_getfield(argv[2], valbuf, valbuf_len);
270 if (rc != CRYPTO_GETFIELD_ERROR_BUF_TOO_SMALL) {
271 break;
272 }
273 free(valbuf);
274 valbuf_len *= 2;
275 }
276 if (rc == CRYPTO_GETFIELD_OK) {
277 cli->sendMsg(ResponseCode::CryptfsGetfieldResult, valbuf, false);
278 }
279 free(valbuf);
280 } else if (!strcmp(argv[1], "setfield")) {
281 if (argc != 4) {
282 cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: cryptfs setfield <fieldname> <value>", false);
283 return 0;
284 }
285 dumpArgs(argc, argv, -1);
286 rc = cryptfs_setfield(argv[2], argv[3]);
287 } else if (!strcmp(argv[1], "mountdefaultencrypted")) {
288 SLOGD("cryptfs mountdefaultencrypted");
289 dumpArgs(argc, argv, -1);
290 rc = cryptfs_mount_default_encrypted();
291 } else if (!strcmp(argv[1], "getpwtype")) {
292 SLOGD("cryptfs getpwtype");
293 dumpArgs(argc, argv, -1);
294 switch(cryptfs_get_password_type()) {
295 case CRYPT_TYPE_PASSWORD:
296 cli->sendMsg(ResponseCode::PasswordTypeResult, "password", false);
297 return 0;
298 case CRYPT_TYPE_PATTERN:
299 cli->sendMsg(ResponseCode::PasswordTypeResult, "pattern", false);
300 return 0;
301 case CRYPT_TYPE_PIN:
302 cli->sendMsg(ResponseCode::PasswordTypeResult, "pin", false);
303 return 0;
304 case CRYPT_TYPE_DEFAULT:
305 cli->sendMsg(ResponseCode::PasswordTypeResult, "default", false);
306 return 0;
307 default:
308 /** @TODO better error and make sure handled by callers */
309 cli->sendMsg(ResponseCode::OpFailedStorageNotFound, "Error", false);
310 return 0;
311 }
312 } else if (!strcmp(argv[1], "getpw")) {
313 SLOGD("cryptfs getpw");
314 dumpArgs(argc, argv, -1);
315 const char* password = cryptfs_get_password();
316 if (password) {
317 char* message = 0;
318 int size = asprintf(&message, "{{sensitive}} %s", password);
319 if (size != -1) {
320 cli->sendMsg(ResponseCode::CommandOkay, message, false);
321 memset(message, 0, size);
322 free (message);
323 return 0;
324 }
325 }
326 rc = -1;
327 } else if (!strcmp(argv[1], "clearpw")) {
328 SLOGD("cryptfs clearpw");
329 dumpArgs(argc, argv, -1);
330 cryptfs_clear_password();
331 rc = 0;
332 } else if (!strcmp(argv[1], "setusercryptopolicies")) {
333 if (argc != 3) {
334 cli->sendMsg(ResponseCode::CommandSyntaxError,
335 "Usage: cryptfs setusercryptopolicies <path>", false);
336 return 0;
337 }
338 SLOGD("cryptfs setusercryptopolicies");
339 dumpArgs(argc, argv, -1);
340 rc = e4crypt_set_user_crypto_policies(argv[2]);
341 } else if (!strcmp(argv[1], "createnewuserdir")) {
342 if (argc != 4) {
343 cli->sendMsg(ResponseCode::CommandSyntaxError,
344 "Usage: cryptfs createnewuserdir <userHandle> <path>", false);
345 return 0;
346 }
347 // ext4enc:TODO: send a CommandSyntaxError if argv[2] not an integer
348 SLOGD("cryptfs createnewuserdir");
349 dumpArgs(argc, argv, -1);
350 rc = e4crypt_create_new_user_dir(argv[2], argv[3]);
351 } else if (!strcmp(argv[1], "deleteuserkey")) {
352 if (argc != 3) {
353 cli->sendMsg(ResponseCode::CommandSyntaxError,
354 "Usage: cryptfs deleteuserkey <userHandle>", false);
355 return 0;
356 }
357 // ext4enc:TODO: send a CommandSyntaxError if argv[2] not an integer
358 SLOGD("cryptfs deleteuserkey");
359 dumpArgs(argc, argv, -1);
360 rc = e4crypt_delete_user_key(argv[2]);
361 } else {
362 dumpArgs(argc, argv, -1);
363 cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown cryptfs cmd", false);
364 return 0;
365 }
366
367 // Always report that the command succeeded and return the error code.
368 // The caller will check the return value to see what the error was.
369 char msg[255];
370 snprintf(msg, sizeof(msg), "%d", rc);
371 cli->sendMsg(ResponseCode::CommandOkay, msg, false);
372
373 return 0;
374 }
375