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