CommandListener.cpp revision 75a5202d9f65747edabb1dd0ebd50a779d4142c2
1/*
2 * Copyright (C) 2008 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
29#define LOG_TAG "VoldCmdListener"
30#include <cutils/log.h>
31
32#include <sysutils/SocketClient.h>
33#include <private/android_filesystem_config.h>
34
35#include "CommandListener.h"
36#include "VolumeManager.h"
37#include "ResponseCode.h"
38#include "Process.h"
39#include "Loop.h"
40#include "Devmapper.h"
41#include "Ext4Crypt.h"
42#include "cryptfs.h"
43#include "fstrim.h"
44
45#define DUMP_ARGS 0
46
47CommandListener::CommandListener() :
48                 FrameworkListener("vold", true) {
49    registerCmd(new DumpCmd());
50    registerCmd(new VolumeCmd());
51    registerCmd(new AsecCmd());
52    registerCmd(new ObbCmd());
53    registerCmd(new StorageCmd());
54    registerCmd(new CryptfsCmd());
55    registerCmd(new FstrimCmd());
56}
57
58#if DUMP_ARGS
59void CommandListener::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 CommandListener::dumpArgs(int /*argc*/, char ** /*argv*/, int /*argObscure*/) { }
88#endif
89
90CommandListener::DumpCmd::DumpCmd() :
91                 VoldCommand("dump") {
92}
93
94int CommandListener::DumpCmd::runCommand(SocketClient *cli,
95                                         int /*argc*/, char ** /*argv*/) {
96    cli->sendMsg(0, "Dumping loop status", false);
97    if (Loop::dumpState(cli)) {
98        cli->sendMsg(ResponseCode::CommandOkay, "Loop dump failed", true);
99    }
100    cli->sendMsg(0, "Dumping DM status", false);
101    if (Devmapper::dumpState(cli)) {
102        cli->sendMsg(ResponseCode::CommandOkay, "Devmapper dump failed", true);
103    }
104    cli->sendMsg(0, "Dumping mounted filesystems", false);
105    FILE *fp = fopen("/proc/mounts", "r");
106    if (fp) {
107        char line[1024];
108        while (fgets(line, sizeof(line), fp)) {
109            line[strlen(line)-1] = '\0';
110            cli->sendMsg(0, line, false);;
111        }
112        fclose(fp);
113    }
114
115    cli->sendMsg(ResponseCode::CommandOkay, "dump complete", false);
116    return 0;
117}
118
119CommandListener::VolumeCmd::VolumeCmd() :
120                 VoldCommand("volume") {
121}
122
123int CommandListener::VolumeCmd::runCommand(SocketClient *cli,
124                                           int argc, char **argv) {
125    dumpArgs(argc, argv, -1);
126
127    if (argc < 2) {
128        cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing Argument", false);
129        return 0;
130    }
131
132    VolumeManager *vm = VolumeManager::Instance();
133    int rc = 0;
134
135    if (!strcmp(argv[1], "list")) {
136        bool broadcast = argc >= 3 && !strcmp(argv[2], "broadcast");
137        return vm->listVolumes(cli, broadcast);
138    } else if (!strcmp(argv[1], "debug")) {
139        if (argc != 3 || (argc == 3 && (strcmp(argv[2], "off") && strcmp(argv[2], "on")))) {
140            cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: volume debug <off/on>", false);
141            return 0;
142        }
143        vm->setDebug(!strcmp(argv[2], "on") ? true : false);
144    } else if (!strcmp(argv[1], "mount")) {
145        if (argc != 3) {
146            cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: volume mount <path>", false);
147            return 0;
148        }
149        rc = vm->mountVolume(argv[2]);
150    } else if (!strcmp(argv[1], "unmount")) {
151        if (argc < 3 || argc > 4 ||
152           ((argc == 4 && strcmp(argv[3], "force")) &&
153            (argc == 4 && strcmp(argv[3], "force_and_revert")))) {
154            cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: volume unmount <path> [force|force_and_revert]", false);
155            return 0;
156        }
157
158        bool force = false;
159        bool revert = false;
160        if (argc >= 4 && !strcmp(argv[3], "force")) {
161            force = true;
162        } else if (argc >= 4 && !strcmp(argv[3], "force_and_revert")) {
163            force = true;
164            revert = true;
165        }
166        rc = vm->unmountVolume(argv[2], force, revert);
167    } else if (!strcmp(argv[1], "format")) {
168        if (argc < 3 || argc > 4 ||
169            (argc == 4 && strcmp(argv[3], "wipe"))) {
170            cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: volume format <path> [wipe]", false);
171            return 0;
172        }
173        bool wipe = false;
174        if (argc >= 4 && !strcmp(argv[3], "wipe")) {
175            wipe = true;
176        }
177        rc = vm->formatVolume(argv[2], wipe);
178    } else if (!strcmp(argv[1], "share")) {
179        if (argc != 4) {
180            cli->sendMsg(ResponseCode::CommandSyntaxError,
181                    "Usage: volume share <path> <method>", false);
182            return 0;
183        }
184        rc = vm->shareVolume(argv[2], argv[3]);
185    } else if (!strcmp(argv[1], "unshare")) {
186        if (argc != 4) {
187            cli->sendMsg(ResponseCode::CommandSyntaxError,
188                    "Usage: volume unshare <path> <method>", false);
189            return 0;
190        }
191        rc = vm->unshareVolume(argv[2], argv[3]);
192    } else if (!strcmp(argv[1], "shared")) {
193        bool enabled = false;
194        if (argc != 4) {
195            cli->sendMsg(ResponseCode::CommandSyntaxError,
196                    "Usage: volume shared <path> <method>", false);
197            return 0;
198        }
199
200        if (vm->shareEnabled(argv[2], argv[3], &enabled)) {
201            cli->sendMsg(
202                    ResponseCode::OperationFailed, "Failed to determine share enable state", true);
203        } else {
204            cli->sendMsg(ResponseCode::ShareEnabledResult,
205                    (enabled ? "Share enabled" : "Share disabled"), false);
206        }
207        return 0;
208    } else if (!strcmp(argv[1], "mkdirs")) {
209        if (argc != 3) {
210            cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: volume mkdirs <path>", false);
211            return 0;
212        }
213        rc = vm->mkdirs(argv[2]);
214    } else {
215        cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown volume cmd", false);
216    }
217
218    if (!rc) {
219        cli->sendMsg(ResponseCode::CommandOkay, "volume operation succeeded", false);
220    } else {
221        rc = ResponseCode::convertFromErrno();
222        cli->sendMsg(rc, "volume operation failed", true);
223    }
224
225    return 0;
226}
227
228CommandListener::StorageCmd::StorageCmd() :
229                 VoldCommand("storage") {
230}
231
232int CommandListener::StorageCmd::runCommand(SocketClient *cli,
233                                                      int argc, char **argv) {
234    /* Guarantied to be initialized by vold's main() before the CommandListener is active */
235    extern struct fstab *fstab;
236
237    dumpArgs(argc, argv, -1);
238
239    if (argc < 2) {
240        cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing Argument", false);
241        return 0;
242    }
243
244    if (!strcmp(argv[1], "mountall")) {
245        if (argc != 2) {
246            cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: mountall", false);
247            return 0;
248        }
249        fs_mgr_mount_all(fstab);
250        cli->sendMsg(ResponseCode::CommandOkay, "Mountall ran successfully", false);
251        return 0;
252    }
253    if (!strcmp(argv[1], "users")) {
254        DIR *dir;
255        struct dirent *de;
256
257        if (argc < 3) {
258            cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing Argument: user <mountpoint>", false);
259            return 0;
260        }
261        if (!(dir = opendir("/proc"))) {
262            cli->sendMsg(ResponseCode::OperationFailed, "Failed to open /proc", true);
263            return 0;
264        }
265
266        while ((de = readdir(dir))) {
267            int pid = Process::getPid(de->d_name);
268
269            if (pid < 0) {
270                continue;
271            }
272
273            char processName[255];
274            Process::getProcessName(pid, processName, sizeof(processName));
275
276            if (Process::checkFileDescriptorSymLinks(pid, argv[2]) ||
277                Process::checkFileMaps(pid, argv[2]) ||
278                Process::checkSymLink(pid, argv[2], "cwd") ||
279                Process::checkSymLink(pid, argv[2], "root") ||
280                Process::checkSymLink(pid, argv[2], "exe")) {
281
282                char msg[1024];
283                snprintf(msg, sizeof(msg), "%d %s", pid, processName);
284                cli->sendMsg(ResponseCode::StorageUsersListResult, msg, false);
285            }
286        }
287        closedir(dir);
288        cli->sendMsg(ResponseCode::CommandOkay, "Storage user list complete", false);
289    } else {
290        cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown storage cmd", false);
291    }
292    return 0;
293}
294
295CommandListener::AsecCmd::AsecCmd() :
296                 VoldCommand("asec") {
297}
298
299void CommandListener::AsecCmd::listAsecsInDirectory(SocketClient *cli, const char *directory) {
300    DIR *d = opendir(directory);
301
302    if (!d) {
303        cli->sendMsg(ResponseCode::OperationFailed, "Failed to open asec dir", true);
304        return;
305    }
306
307    size_t dirent_len = offsetof(struct dirent, d_name) +
308            fpathconf(dirfd(d), _PC_NAME_MAX) + 1;
309
310    struct dirent *dent = (struct dirent *) malloc(dirent_len);
311    if (dent == NULL) {
312        cli->sendMsg(ResponseCode::OperationFailed, "Failed to allocate memory", true);
313        return;
314    }
315
316    struct dirent *result;
317
318    while (!readdir_r(d, dent, &result) && result != NULL) {
319        if (dent->d_name[0] == '.')
320            continue;
321        if (dent->d_type != DT_REG)
322            continue;
323        size_t name_len = strlen(dent->d_name);
324        if (name_len > 5 && name_len < 260 &&
325                !strcmp(&dent->d_name[name_len - 5], ".asec")) {
326            char id[255];
327            memset(id, 0, sizeof(id));
328            strlcpy(id, dent->d_name, name_len - 4);
329            cli->sendMsg(ResponseCode::AsecListResult, id, false);
330        }
331    }
332    closedir(d);
333
334    free(dent);
335}
336
337int CommandListener::AsecCmd::runCommand(SocketClient *cli,
338                                                      int argc, char **argv) {
339    if (argc < 2) {
340        cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing Argument", false);
341        return 0;
342    }
343
344    VolumeManager *vm = VolumeManager::Instance();
345    int rc = 0;
346
347    if (!strcmp(argv[1], "list")) {
348        dumpArgs(argc, argv, -1);
349
350        listAsecsInDirectory(cli, Volume::SEC_ASECDIR_EXT);
351        listAsecsInDirectory(cli, Volume::SEC_ASECDIR_INT);
352    } else if (!strcmp(argv[1], "create")) {
353        dumpArgs(argc, argv, 5);
354        if (argc != 8) {
355            cli->sendMsg(ResponseCode::CommandSyntaxError,
356                    "Usage: asec create <container-id> <size_mb> <fstype> <key> <ownerUid> "
357                    "<isExternal>", false);
358            return 0;
359        }
360
361        unsigned int numSectors = (atoi(argv[3]) * (1024 * 1024)) / 512;
362        const bool isExternal = (atoi(argv[7]) == 1);
363        rc = vm->createAsec(argv[2], numSectors, argv[4], argv[5], atoi(argv[6]), isExternal);
364    } else if (!strcmp(argv[1], "resize")) {
365        dumpArgs(argc, argv, -1);
366        if (argc != 5) {
367            cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: asec resize <container-id> <size_mb> <key>", false);
368            return 0;
369        }
370        unsigned int numSectors = (atoi(argv[3]) * (1024 * 1024)) / 512;
371        rc = vm->resizeAsec(argv[2], numSectors, argv[4]);
372    } else if (!strcmp(argv[1], "finalize")) {
373        dumpArgs(argc, argv, -1);
374        if (argc != 3) {
375            cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: asec finalize <container-id>", false);
376            return 0;
377        }
378        rc = vm->finalizeAsec(argv[2]);
379    } else if (!strcmp(argv[1], "fixperms")) {
380        dumpArgs(argc, argv, -1);
381        if  (argc != 5) {
382            cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: asec fixperms <container-id> <gid> <filename>", false);
383            return 0;
384        }
385
386        char *endptr;
387        gid_t gid = (gid_t) strtoul(argv[3], &endptr, 10);
388        if (*endptr != '\0') {
389            cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: asec fixperms <container-id> <gid> <filename>", false);
390            return 0;
391        }
392
393        rc = vm->fixupAsecPermissions(argv[2], gid, argv[4]);
394    } else if (!strcmp(argv[1], "destroy")) {
395        dumpArgs(argc, argv, -1);
396        if (argc < 3) {
397            cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: asec destroy <container-id> [force]", false);
398            return 0;
399        }
400        bool force = false;
401        if (argc > 3 && !strcmp(argv[3], "force")) {
402            force = true;
403        }
404        rc = vm->destroyAsec(argv[2], force);
405    } else if (!strcmp(argv[1], "mount")) {
406        dumpArgs(argc, argv, 3);
407        if (argc != 6) {
408            cli->sendMsg(ResponseCode::CommandSyntaxError,
409                    "Usage: asec mount <namespace-id> <key> <ownerUid> <ro|rw>", false);
410            return 0;
411        }
412        bool readOnly = true;
413        if (!strcmp(argv[5], "rw")) {
414            readOnly = false;
415        }
416        rc = vm->mountAsec(argv[2], argv[3], atoi(argv[4]), readOnly);
417    } else if (!strcmp(argv[1], "unmount")) {
418        dumpArgs(argc, argv, -1);
419        if (argc < 3) {
420            cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: asec unmount <container-id> [force]", false);
421            return 0;
422        }
423        bool force = false;
424        if (argc > 3 && !strcmp(argv[3], "force")) {
425            force = true;
426        }
427        rc = vm->unmountAsec(argv[2], force);
428    } else if (!strcmp(argv[1], "rename")) {
429        dumpArgs(argc, argv, -1);
430        if (argc != 4) {
431            cli->sendMsg(ResponseCode::CommandSyntaxError,
432                    "Usage: asec rename <old_id> <new_id>", false);
433            return 0;
434        }
435        rc = vm->renameAsec(argv[2], argv[3]);
436    } else if (!strcmp(argv[1], "path")) {
437        dumpArgs(argc, argv, -1);
438        if (argc != 3) {
439            cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: asec path <container-id>", false);
440            return 0;
441        }
442        char path[255];
443
444        if (!(rc = vm->getAsecMountPath(argv[2], path, sizeof(path)))) {
445            cli->sendMsg(ResponseCode::AsecPathResult, path, false);
446            return 0;
447        }
448    } else if (!strcmp(argv[1], "fspath")) {
449        dumpArgs(argc, argv, -1);
450        if (argc != 3) {
451            cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: asec fspath <container-id>", false);
452            return 0;
453        }
454        char path[255];
455
456        if (!(rc = vm->getAsecFilesystemPath(argv[2], path, sizeof(path)))) {
457            cli->sendMsg(ResponseCode::AsecPathResult, path, false);
458            return 0;
459        }
460    } else {
461        dumpArgs(argc, argv, -1);
462        cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown asec cmd", false);
463    }
464
465    if (!rc) {
466        cli->sendMsg(ResponseCode::CommandOkay, "asec operation succeeded", false);
467    } else {
468        rc = ResponseCode::convertFromErrno();
469        cli->sendMsg(rc, "asec operation failed", true);
470    }
471
472    return 0;
473}
474
475CommandListener::ObbCmd::ObbCmd() :
476                 VoldCommand("obb") {
477}
478
479int CommandListener::ObbCmd::runCommand(SocketClient *cli,
480                                                      int argc, char **argv) {
481    if (argc < 2) {
482        cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing Argument", false);
483        return 0;
484    }
485
486    VolumeManager *vm = VolumeManager::Instance();
487    int rc = 0;
488
489    if (!strcmp(argv[1], "list")) {
490        dumpArgs(argc, argv, -1);
491
492        rc = vm->listMountedObbs(cli);
493    } else if (!strcmp(argv[1], "mount")) {
494            dumpArgs(argc, argv, 3);
495            if (argc != 5) {
496                cli->sendMsg(ResponseCode::CommandSyntaxError,
497                        "Usage: obb mount <filename> <key> <ownerGid>", false);
498                return 0;
499            }
500            rc = vm->mountObb(argv[2], argv[3], atoi(argv[4]));
501    } else if (!strcmp(argv[1], "unmount")) {
502        dumpArgs(argc, argv, -1);
503        if (argc < 3) {
504            cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: obb unmount <source file> [force]", false);
505            return 0;
506        }
507        bool force = false;
508        if (argc > 3 && !strcmp(argv[3], "force")) {
509            force = true;
510        }
511        rc = vm->unmountObb(argv[2], force);
512    } else if (!strcmp(argv[1], "path")) {
513        dumpArgs(argc, argv, -1);
514        if (argc != 3) {
515            cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: obb path <source file>", false);
516            return 0;
517        }
518        char path[255];
519
520        if (!(rc = vm->getObbMountPath(argv[2], path, sizeof(path)))) {
521            cli->sendMsg(ResponseCode::AsecPathResult, path, false);
522            return 0;
523        }
524    } else {
525        dumpArgs(argc, argv, -1);
526        cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown obb cmd", false);
527    }
528
529    if (!rc) {
530        cli->sendMsg(ResponseCode::CommandOkay, "obb operation succeeded", false);
531    } else {
532        rc = ResponseCode::convertFromErrno();
533        cli->sendMsg(rc, "obb operation failed", true);
534    }
535
536    return 0;
537}
538
539CommandListener::CryptfsCmd::CryptfsCmd() :
540                 VoldCommand("cryptfs") {
541}
542
543static int getType(const char* type)
544{
545    if (!strcmp(type, "default")) {
546        return CRYPT_TYPE_DEFAULT;
547    } else if (!strcmp(type, "password")) {
548        return CRYPT_TYPE_PASSWORD;
549    } else if (!strcmp(type, "pin")) {
550        return CRYPT_TYPE_PIN;
551    } else if (!strcmp(type, "pattern")) {
552        return CRYPT_TYPE_PATTERN;
553    } else {
554        return -1;
555    }
556}
557
558int CommandListener::CryptfsCmd::runCommand(SocketClient *cli,
559                                                      int argc, char **argv) {
560    if ((cli->getUid() != 0) && (cli->getUid() != AID_SYSTEM)) {
561        cli->sendMsg(ResponseCode::CommandNoPermission, "No permission to run cryptfs commands", false);
562        return 0;
563    }
564
565    if (argc < 2) {
566        cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing Argument", false);
567        return 0;
568    }
569
570    int rc = 0;
571
572    if (!strcmp(argv[1], "checkpw")) {
573        if (argc != 3) {
574            cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: cryptfs checkpw <passwd>", false);
575            return 0;
576        }
577        dumpArgs(argc, argv, 2);
578        rc = cryptfs_check_passwd(argv[2]);
579    } else if (!strcmp(argv[1], "restart")) {
580        if (argc != 2) {
581            cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: cryptfs restart", false);
582            return 0;
583        }
584        dumpArgs(argc, argv, -1);
585        rc = cryptfs_restart();
586    } else if (!strcmp(argv[1], "cryptocomplete")) {
587        if (argc != 2) {
588            cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: cryptfs cryptocomplete", false);
589            return 0;
590        }
591        dumpArgs(argc, argv, -1);
592        rc = cryptfs_crypto_complete();
593    } else if (!strcmp(argv[1], "enablecrypto")) {
594        const char* syntax = "Usage: cryptfs enablecrypto <wipe|inplace> "
595                             "default|password|pin|pattern [passwd]";
596        if ( (argc != 4 && argc != 5)
597             || (strcmp(argv[2], "wipe") && strcmp(argv[2], "inplace")) ) {
598            cli->sendMsg(ResponseCode::CommandSyntaxError, syntax, false);
599            return 0;
600        }
601        dumpArgs(argc, argv, 4);
602
603        int tries;
604        for (tries = 0; tries < 2; ++tries) {
605            int type = getType(argv[3]);
606            if (type == -1) {
607                cli->sendMsg(ResponseCode::CommandSyntaxError, syntax,
608                             false);
609                return 0;
610            } else if (type == CRYPT_TYPE_DEFAULT) {
611              rc = cryptfs_enable_default(argv[2], /*allow_reboot*/false);
612            } else {
613                rc = cryptfs_enable(argv[2], type, argv[4],
614                                    /*allow_reboot*/false);
615            }
616
617            if (rc == 0) {
618                break;
619            } else if (tries == 0) {
620                Process::killProcessesWithOpenFiles(DATA_MNT_POINT, 2);
621            }
622        }
623    } else if (!strcmp(argv[1], "enablefilecrypto")) {
624        const char* syntax = "Usage: cryptfs enablefilecrypto";
625        if (argc != 2) {
626            cli->sendMsg(ResponseCode::CommandSyntaxError, syntax, false);
627            return 0;
628        }
629        dumpArgs(argc, argv, -1);
630        rc = cryptfs_enable_file();
631    } else if (!strcmp(argv[1], "changepw")) {
632        const char* syntax = "Usage: cryptfs changepw "
633                             "default|password|pin|pattern [newpasswd]";
634        const char* password;
635        if (argc == 3) {
636            password = "";
637        } else if (argc == 4) {
638            password = argv[3];
639        } else {
640            cli->sendMsg(ResponseCode::CommandSyntaxError, syntax, false);
641            return 0;
642        }
643        int type = getType(argv[2]);
644        if (type == -1) {
645            cli->sendMsg(ResponseCode::CommandSyntaxError, syntax, false);
646            return 0;
647        }
648        SLOGD("cryptfs changepw %s {}", argv[2]);
649        rc = cryptfs_changepw(type, password);
650    } else if (!strcmp(argv[1], "verifypw")) {
651        if (argc != 3) {
652            cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: cryptfs verifypw <passwd>", false);
653            return 0;
654        }
655        SLOGD("cryptfs verifypw {}");
656        rc = cryptfs_verify_passwd(argv[2]);
657    } else if (!strcmp(argv[1], "getfield")) {
658        char *valbuf;
659        int valbuf_len = PROPERTY_VALUE_MAX;
660
661        if (argc != 3) {
662            cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: cryptfs getfield <fieldname>", false);
663            return 0;
664        }
665        dumpArgs(argc, argv, -1);
666
667        // Increase the buffer size until it is big enough for the field value stored.
668        while (1) {
669            valbuf = (char*)malloc(valbuf_len);
670            if (valbuf == NULL) {
671                cli->sendMsg(ResponseCode::OperationFailed, "Failed to allocate memory", false);
672                return 0;
673            }
674            rc = cryptfs_getfield(argv[2], valbuf, valbuf_len);
675            if (rc != CRYPTO_GETFIELD_ERROR_BUF_TOO_SMALL) {
676                break;
677            }
678            free(valbuf);
679            valbuf_len *= 2;
680        }
681        if (rc == CRYPTO_GETFIELD_OK) {
682            cli->sendMsg(ResponseCode::CryptfsGetfieldResult, valbuf, false);
683        }
684        free(valbuf);
685    } else if (!strcmp(argv[1], "setfield")) {
686        if (argc != 4) {
687            cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: cryptfs setfield <fieldname> <value>", false);
688            return 0;
689        }
690        dumpArgs(argc, argv, -1);
691        rc = cryptfs_setfield(argv[2], argv[3]);
692    } else if (!strcmp(argv[1], "mountdefaultencrypted")) {
693        SLOGD("cryptfs mountdefaultencrypted");
694        dumpArgs(argc, argv, -1);
695        rc = cryptfs_mount_default_encrypted();
696    } else if (!strcmp(argv[1], "getpwtype")) {
697        SLOGD("cryptfs getpwtype");
698        dumpArgs(argc, argv, -1);
699        switch(cryptfs_get_password_type()) {
700        case CRYPT_TYPE_PASSWORD:
701            cli->sendMsg(ResponseCode::PasswordTypeResult, "password", false);
702            return 0;
703        case CRYPT_TYPE_PATTERN:
704            cli->sendMsg(ResponseCode::PasswordTypeResult, "pattern", false);
705            return 0;
706        case CRYPT_TYPE_PIN:
707            cli->sendMsg(ResponseCode::PasswordTypeResult, "pin", false);
708            return 0;
709        case CRYPT_TYPE_DEFAULT:
710            cli->sendMsg(ResponseCode::PasswordTypeResult, "default", false);
711            return 0;
712        default:
713          /** @TODO better error and make sure handled by callers */
714            cli->sendMsg(ResponseCode::OpFailedStorageNotFound, "Error", false);
715            return 0;
716        }
717    } else if (!strcmp(argv[1], "getpw")) {
718        SLOGD("cryptfs getpw");
719        dumpArgs(argc, argv, -1);
720        const char* password = cryptfs_get_password();
721        if (password) {
722            char* message = 0;
723            int size = asprintf(&message, "{{sensitive}} %s", password);
724            if (size != -1) {
725                cli->sendMsg(ResponseCode::CommandOkay, message, false);
726                memset(message, 0, size);
727                free (message);
728                return 0;
729            }
730        }
731        rc = -1;
732    } else if (!strcmp(argv[1], "clearpw")) {
733        SLOGD("cryptfs clearpw");
734        dumpArgs(argc, argv, -1);
735        cryptfs_clear_password();
736        rc = 0;
737    } else if (!strcmp(argv[1], "setusercryptopolicies")) {
738        if (argc != 3) {
739            cli->sendMsg(ResponseCode::CommandSyntaxError,
740                "Usage: cryptfs setusercryptopolicies <path>", false);
741            return 0;
742        }
743        SLOGD("cryptfs setusercryptopolicies");
744        dumpArgs(argc, argv, -1);
745        rc = e4crypt_set_user_crypto_policies(argv[2]);
746    } else if (!strcmp(argv[1], "createnewuserdir")) {
747        if (argc != 4) {
748            cli->sendMsg(ResponseCode::CommandSyntaxError,
749                "Usage: cryptfs createnewuserdir <userHandle> <path>", false);
750            return 0;
751        }
752        // ext4enc:TODO: send a CommandSyntaxError if argv[2] not an integer
753        SLOGD("cryptfs createnewuserdir");
754        dumpArgs(argc, argv, -1);
755        rc = e4crypt_create_new_user_dir(argv[2], argv[3]);
756    } else {
757        dumpArgs(argc, argv, -1);
758        cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown cryptfs cmd", false);
759        return 0;
760    }
761
762    // Always report that the command succeeded and return the error code.
763    // The caller will check the return value to see what the error was.
764    char msg[255];
765    snprintf(msg, sizeof(msg), "%d", rc);
766    cli->sendMsg(ResponseCode::CommandOkay, msg, false);
767
768    return 0;
769}
770
771CommandListener::FstrimCmd::FstrimCmd() :
772                 VoldCommand("fstrim") {
773}
774int CommandListener::FstrimCmd::runCommand(SocketClient *cli,
775                                                      int argc, char **argv) {
776    if ((cli->getUid() != 0) && (cli->getUid() != AID_SYSTEM)) {
777        cli->sendMsg(ResponseCode::CommandNoPermission, "No permission to run fstrim commands", false);
778        return 0;
779    }
780
781    if (argc < 2) {
782        cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing Argument", false);
783        return 0;
784    }
785
786    int rc = 0;
787
788    if (!strcmp(argv[1], "dotrim")) {
789        if (argc != 2) {
790            cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: fstrim dotrim", false);
791            return 0;
792        }
793        dumpArgs(argc, argv, -1);
794        rc = fstrim_filesystems(0);
795    } else if (!strcmp(argv[1], "dodtrim")) {
796        if (argc != 2) {
797            cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: fstrim dodtrim", false);
798            return 0;
799        }
800        dumpArgs(argc, argv, -1);
801        rc = fstrim_filesystems(1);   /* Do Deep Discard trim */
802    } else {
803        dumpArgs(argc, argv, -1);
804        cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown fstrim cmd", false);
805    }
806
807    // Always report that the command succeeded and return the error code.
808    // The caller will check the return value to see what the error was.
809    char msg[255];
810    snprintf(msg, sizeof(msg), "%d", rc);
811    cli->sendMsg(ResponseCode::CommandOkay, msg, false);
812
813    return 0;
814}
815