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