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