• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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