"Fossies" - the Fresh Open Source Software Archive

Member "encfs-1.9.5/encfs/encfsctl.cpp" (27 Apr 2018, 22751 Bytes) of package /linux/misc/encfs-1.9.5.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "encfsctl.cpp" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 1.9.4_vs_1.9.5.

    1 /*****************************************************************************
    2  * Author:   Valient Gough <vgough@pobox.com>
    3  *
    4  *****************************************************************************
    5  * Copyright (c) 2004, Valient Gough
    6  *
    7  * This program is free software; you can distribute it and/or modify it under
    8  * the terms of the GNU General Public License (GPL), as published by the Free
    9  * Software Foundation; either version 2 of the License, or (at your option)
   10  * any later version.
   11  *
   12  * This program is distributed in the hope that it will be useful, but WITHOUT
   13  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   14  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
   15  * more details.
   16  */
   17 
   18 #include <fcntl.h>
   19 #include <getopt.h>
   20 #include <iostream>
   21 #include <limits.h>
   22 #include <memory>
   23 #include <stdio.h>
   24 #include <stdlib.h>
   25 #include <string.h>
   26 #include <string>
   27 #include <sys/stat.h>
   28 #include <time.h>
   29 #include <unistd.h>
   30 #include <vector>
   31 
   32 #define NO_DES
   33 #include <openssl/ssl.h>
   34 
   35 #include "Cipher.h"
   36 #include "CipherKey.h"
   37 #include "Context.h"
   38 #include "DirNode.h"
   39 #include "Error.h"
   40 #include "FSConfig.h"
   41 #include "FileNode.h"
   42 #include "FileUtils.h"
   43 #include "Interface.h"
   44 #include "autosprintf.h"
   45 #include "config.h"
   46 #include "i18n.h"
   47 #include "intl/gettext.h"
   48 
   49 #ifndef PATH_MAX
   50 #define PATH_MAX 4096
   51 #endif
   52 
   53 using namespace std;
   54 using gnu::autosprintf;
   55 using namespace encfs;
   56 
   57 static int showInfo(int argc, char **argv);
   58 static int showVersion(int argc, char **argv);
   59 static int chpasswd(int argc, char **argv);
   60 static int chpasswdAutomaticly(int argc, char **argv);
   61 static int ckpasswdAutomaticly(int argc, char **argv);
   62 static int cmd_ls(int argc, char **argv);
   63 static int cmd_decode(int argc, char **argv);
   64 static int cmd_encode(int argc, char **argv);
   65 static int cmd_showcruft(int argc, char **argv);
   66 static int cmd_cat(int argc, char **argv);
   67 static int cmd_export(int argc, char **argv);
   68 static int cmd_showKey(int argc, char **argv);
   69 
   70 struct CommandOpts {
   71   const char *name;
   72   int minOptions;
   73   int maxOptions;
   74   int (*func)(int argc, char **argv);
   75   const char *argStr;
   76   const char *usageStr;
   77 } commands[] = {
   78     {"info", 1, 1, showInfo, "(root dir)",
   79      // xgroup(usage)
   80      gettext_noop("  -- show information (Default command)")},
   81     {"showKey", 1, 1, cmd_showKey, "(root dir)",
   82      // xgroup(usage)
   83      gettext_noop("  -- show key")},
   84     {"passwd", 1, 1, chpasswd, "(root dir)",
   85      // xgroup(usage)
   86      gettext_noop("  -- change password for volume")},
   87     {"autopasswd", 1, 1, chpasswdAutomaticly, "(root dir)",
   88      // xgroup(usage)
   89      gettext_noop("  -- change password for volume, taking password"
   90                   " from standard input.\n\tNo prompts are issued.")},
   91     {"autocheckpasswd", 1, 1, ckpasswdAutomaticly, "(root dir)",
   92      // xgroup(usage)
   93      gettext_noop("  -- check password for volume, taking password"
   94                   " from standard input.\n\tNo prompts are issued.")},
   95     {"ls", 1, 2, cmd_ls, 0, 0},
   96     {"showcruft", 1, 1, cmd_showcruft, "(root dir)",
   97      // xgroup(usage)
   98      gettext_noop("  -- show undecodable filenames in the volume")},
   99     {"cat", 2, 4, cmd_cat, "[--extpass=prog] [--reverse] (root dir) path",
  100      // xgroup(usage)
  101      gettext_noop("  -- decodes the file and cats it to standard out")},
  102     {"decode", 1, 100, cmd_decode,
  103      "[--extpass=prog] (root dir) [encoded-name ...]",
  104      // xgroup(usage)
  105      gettext_noop("  -- decodes name and prints plaintext version")},
  106     {"encode", 1, 100, cmd_encode,
  107      "[--extpass=prog] (root dir) [plaintext-name ...]",
  108      // xgroup(usage)
  109      gettext_noop("  -- encodes a filename and print result")},
  110     {"export", 2, 2, cmd_export, "(root dir) path",
  111      // xgroup(usage)
  112      gettext_noop("  -- decrypts a volume and writes results to path")},
  113     {"--version", 0, 0, showVersion, "",
  114      // xgroup(usage)
  115      gettext_noop("  -- print version number and exit")},
  116     {0, 0, 0, 0, 0, 0}};
  117 
  118 auto ctx = std::make_shared<EncFS_Context>();
  119 
  120 static void usage(const char *name) {
  121   cerr << autosprintf(_("encfsctl version %s"), VERSION) << "\n"
  122        << _("Usage:\n")
  123        // displays usage commands, eg "./encfs (root dir) ..."
  124        // xgroup(usage)
  125        << autosprintf(
  126               _("%s (root dir)\n"
  127                 "  -- displays information about the filesystem, or \n"),
  128               name);
  129 
  130   int offset = 0;
  131   while (commands[offset].name != 0) {
  132     if (commands[offset].argStr != 0) {
  133       cerr << "encfsctl " << commands[offset].name << " "
  134            << commands[offset].argStr << "\n"
  135            << gettext(commands[offset].usageStr) << "\n";
  136     }
  137     ++offset;
  138   }
  139 
  140   cerr << "\n"
  141        // xgroup(usage)
  142        << autosprintf(_("Example: \n%s info ~/.crypt\n"), name) << "\n";
  143 }
  144 
  145 static bool checkDir(string &rootDir) {
  146   if (!isDirectory(rootDir.c_str())) {
  147     cerr << autosprintf(_("directory %s does not exist.\n"), rootDir.c_str());
  148     return false;
  149   }
  150   if (rootDir[rootDir.length() - 1] != '/') rootDir.append("/");
  151 
  152   return true;
  153 }
  154 
  155 static int showVersion(int argc, char **argv) {
  156   (void)argc;
  157   (void)argv;
  158   // xgroup(usage)
  159   cerr << autosprintf(_("encfsctl version %s"), VERSION) << "\n";
  160 
  161   return EXIT_SUCCESS;
  162 }
  163 
  164 static int showInfo(int argc, char **argv) {
  165   (void)argc;
  166   string rootDir = argv[1];
  167   if (!checkDir(rootDir)) return EXIT_FAILURE;
  168 
  169   std::shared_ptr<EncFSConfig> config(new EncFSConfig);
  170   ConfigType type = readConfig(rootDir, config.get(), "");
  171 
  172   // show information stored in config..
  173   switch (type) {
  174     case Config_None:
  175       // xgroup(diag)
  176       cout << _("Unable to load or parse config file\n");
  177       return EXIT_FAILURE;
  178     case Config_Prehistoric:
  179       // xgroup(diag)
  180       cout << _(
  181           "A really old EncFS filesystem was found. \n"
  182           "It is not supported in this EncFS build.\n");
  183       return EXIT_FAILURE;
  184     case Config_V3:
  185       // xgroup(diag)
  186       cout << "\n"
  187            << autosprintf(_("Version 3 configuration; "
  188                             "created by %s\n"),
  189                           config->creator.c_str());
  190       break;
  191     case Config_V4:
  192       // xgroup(diag)
  193       cout << "\n"
  194            << autosprintf(_("Version 4 configuration; "
  195                             "created by %s\n"),
  196                           config->creator.c_str());
  197       break;
  198     case Config_V5:
  199       // xgroup(diag)
  200       cout << "\n"
  201            << autosprintf(_("Version 5 configuration; "
  202                             "created by %s (revision %i)\n"),
  203                           config->creator.c_str(), config->subVersion);
  204       break;
  205     case Config_V6:
  206       // xgroup(diag)
  207       cout << "\n"
  208            << autosprintf(_("Version 6 configuration; "
  209                             "created by %s (revision %i)\n"),
  210                           config->creator.c_str(), config->subVersion);
  211       break;
  212   }
  213 
  214   showFSInfo(config.get());
  215 
  216   return EXIT_SUCCESS;
  217 }
  218 
  219 static RootPtr initRootInfo(int &argc, char **&argv) {
  220   RootPtr result;
  221   std::shared_ptr<EncFS_Opts> opts(new EncFS_Opts());
  222   opts->createIfNotFound = false;
  223   opts->checkKey = false;
  224 
  225   static struct option long_options[] = {{"extpass", 1, 0, 'p'}, {"reverse", 0, nullptr, 'r'}, {0, 0, 0, 0}};
  226 
  227   for (;;) {
  228     int option_index = 0;
  229 
  230     int res = getopt_long(argc, argv, "", long_options, &option_index);
  231     if (res == -1) break;
  232 
  233     switch (res) {
  234       case 'p':
  235         opts->passwordProgram.assign(optarg);
  236         break;
  237       case 'r':
  238         opts->reverseEncryption = true;
  239         break;
  240       default:
  241         RLOG(WARNING) << "getopt error: " << res;
  242         break;
  243     }
  244   }
  245 
  246   argc -= optind;
  247   argv += optind;
  248 
  249   if (argc == 0) {
  250     cerr << _("Incorrect number of arguments") << "\n";
  251   } else {
  252     opts->rootDir = string(argv[0]);
  253 
  254     --argc;
  255     ++argv;
  256 
  257     ctx->publicFilesystem = opts->ownerCreate;
  258     if (checkDir(opts->rootDir)) result = initFS(ctx.get(), opts);
  259 
  260     if (!result)
  261       cerr << _("Unable to initialize encrypted filesystem - check path.\n");
  262   }
  263 
  264   return result;
  265 }
  266 
  267 static RootPtr initRootInfo(const char *crootDir) {
  268   string rootDir(crootDir);
  269   RootPtr result;
  270 
  271   if (checkDir(rootDir)) {
  272     std::shared_ptr<EncFS_Opts> opts(new EncFS_Opts());
  273     opts->rootDir = rootDir;
  274     opts->createIfNotFound = false;
  275     opts->checkKey = false;
  276 
  277     ctx->publicFilesystem = opts->ownerCreate;
  278     result = initFS(ctx.get(), opts);
  279   }
  280 
  281   if (!result)
  282     cerr << _("Unable to initialize encrypted filesystem - check path.\n");
  283 
  284   return result;
  285 }
  286 
  287 static int cmd_showKey(int argc, char **argv) {
  288   (void)argc;
  289   RootPtr rootInfo = initRootInfo(argv[1]);
  290 
  291   if (!rootInfo)
  292     return EXIT_FAILURE;
  293   else {
  294     // encode with itself
  295     string b64Key = rootInfo->cipher->encodeAsString(rootInfo->volumeKey,
  296                                                      rootInfo->volumeKey);
  297 
  298     cout << b64Key << "\n";
  299 
  300     return EXIT_SUCCESS;
  301   }
  302 }
  303 
  304 static int cmd_decode(int argc, char **argv) {
  305   RootPtr rootInfo = initRootInfo(argc, argv);
  306   if (!rootInfo) return EXIT_FAILURE;
  307 
  308   if (argc > 0) {
  309     for (int i = 0; i < argc; ++i) {
  310       string name = rootInfo->root->plainPath(argv[i]);
  311       cout << name << "\n";
  312     }
  313   } else {
  314     char buf[PATH_MAX + 1];
  315     while (cin.getline(buf, PATH_MAX)) {
  316       cout << rootInfo->root->plainPath(buf) << "\n";
  317     }
  318   }
  319   return EXIT_SUCCESS;
  320 }
  321 
  322 static int cmd_encode(int argc, char **argv) {
  323   RootPtr rootInfo = initRootInfo(argc, argv);
  324   if (!rootInfo) return EXIT_FAILURE;
  325 
  326   if (argc > 0) {
  327     for (int i = 0; i < argc; ++i) {
  328       string name = rootInfo->root->cipherPathWithoutRoot(argv[i]);
  329       cout << name << "\n";
  330     }
  331   } else {
  332     char buf[PATH_MAX + 1];
  333     while (cin.getline(buf, PATH_MAX)) {
  334       cout << rootInfo->root->cipherPathWithoutRoot(buf) << "\n";
  335     }
  336   }
  337   return EXIT_SUCCESS;
  338 }
  339 
  340 static int cmd_ls(int argc, char **argv) {
  341   (void)argc;
  342 
  343   RootPtr rootInfo = initRootInfo(argv[1]);
  344 
  345   if (!rootInfo) return EXIT_FAILURE;
  346 
  347   // show files in directory
  348   {
  349     DirTraverse dt = rootInfo->root->openDir("/");
  350     if (dt.valid()) {
  351       for (string name = dt.nextPlaintextName(); !name.empty();
  352            name = dt.nextPlaintextName()) {
  353         std::shared_ptr<FileNode> fnode =
  354             rootInfo->root->lookupNode(name.c_str(), "encfsctl-ls");
  355         struct stat stbuf;
  356         fnode->getAttr(&stbuf);
  357 
  358         struct tm stm;
  359         localtime_r(&stbuf.st_mtime, &stm);
  360         stm.tm_year += 1900;
  361         // TODO: when I add "%s" to the end and name.c_str(), I get a
  362         // seg fault from within strlen.  Why ???
  363         printf("%11i %4i-%02i-%02i %02i:%02i:%02i %s\n", int(stbuf.st_size),
  364                int(stm.tm_year), int(stm.tm_mon), int(stm.tm_mday),
  365                int(stm.tm_hour), int(stm.tm_min), int(stm.tm_sec),
  366                name.c_str());
  367       }
  368     }
  369   }
  370 
  371   return EXIT_SUCCESS;
  372 }
  373 
  374 // apply an operation to every block in the file
  375 template <typename T>
  376 int processContents(const std::shared_ptr<EncFS_Root> &rootInfo,
  377                     const char *path, T &op) {
  378   int errCode = 0;
  379   std::shared_ptr<FileNode> node;
  380 
  381   try {
  382     node = rootInfo->root->openNode(path, "encfsctl", O_RDONLY, &errCode);
  383   }
  384   catch(...) {}
  385 
  386   if (!node) {
  387     // try treating filename as an enciphered path
  388     string plainName = rootInfo->root->plainPath(path);
  389     if (plainName.length() > 0) {
  390       node = rootInfo->root->lookupNode(plainName.c_str(), "encfsctl");
  391     }
  392     if (node) {
  393       errCode = node->open(O_RDONLY);
  394       if (errCode < 0) node.reset();
  395     }
  396   }
  397 
  398   if (!node) {
  399     cerr << "unable to open " << path << "\n";
  400     return errCode;
  401   } else {
  402     unsigned char buf[512];
  403     int blocks = (node->getSize() + sizeof(buf) - 1) / sizeof(buf);
  404     // read all the data in blocks
  405     for (int i = 0; i < blocks; ++i) {
  406       int bytes = node->read(i * sizeof(buf), buf, sizeof(buf));
  407       int res = op(buf, bytes);
  408       if (res < 0) return res;
  409     }
  410   }
  411   return 0;
  412 }
  413 
  414 class WriteOutput {
  415   int _fd;
  416 
  417  public:
  418   WriteOutput(int fd) { _fd = fd; }
  419   ~WriteOutput() { close(_fd); }
  420 
  421   int operator()(const void *buf, int count) {
  422     return (int)write(_fd, buf, count);
  423   }
  424 };
  425 
  426 static int cmd_cat(int argc, char **argv) {
  427   RootPtr rootInfo = initRootInfo(argc, argv);
  428 
  429   if (!rootInfo) return EXIT_FAILURE;
  430 
  431   const char *path = argv[0];
  432   // If user provides a leading slash, in reverse mode, it will be converted
  433   // to "+" by plainpath, and will fail to decode... Workaround below then...
  434   if (path[0] == '/') {
  435     path++;
  436   }
  437   WriteOutput output(STDOUT_FILENO);
  438   int errCode = processContents(rootInfo, path, output);
  439 
  440   return errCode;
  441 }
  442 
  443 static int copyLink(const struct stat &stBuf,
  444                     const std::shared_ptr<EncFS_Root> &rootInfo,
  445                     const string &cpath, const string &destName) {
  446   std::vector<char> buf(stBuf.st_size + 1, '\0');
  447   int res = ::readlink(cpath.c_str(), buf.data(), stBuf.st_size);
  448   if (res == -1) {
  449     cerr << "unable to readlink of " << cpath << "\n";
  450     return EXIT_FAILURE;
  451   }
  452 
  453   buf[res] = '\0';
  454   string decodedLink = rootInfo->root->plainPath(buf.data());
  455 
  456   res = ::symlink(decodedLink.c_str(), destName.c_str());
  457   if (res == -1) {
  458     cerr << "unable to create symlink for " << cpath << " to " << decodedLink
  459          << "\n";
  460   }
  461 
  462   return EXIT_SUCCESS;
  463 }
  464 
  465 static int copyContents(const std::shared_ptr<EncFS_Root> &rootInfo,
  466                         const char *encfsName, const char *targetName) {
  467   std::shared_ptr<FileNode> node =
  468       rootInfo->root->lookupNode(encfsName, "encfsctl");
  469 
  470   if (!node) {
  471     cerr << "unable to open " << encfsName << "\n";
  472     return EXIT_FAILURE;
  473   } else {
  474     struct stat st;
  475 
  476     if (node->getAttr(&st) != 0) return EXIT_FAILURE;
  477 
  478     if ((st.st_mode & S_IFMT) == S_IFLNK) {
  479       string d = rootInfo->root->cipherPath(encfsName);
  480       char linkContents[PATH_MAX + 2];
  481 
  482       if (readlink(d.c_str(), linkContents, PATH_MAX + 1) <= 0) {
  483         cerr << "unable to read link " << encfsName << "\n";
  484         return EXIT_FAILURE;
  485       }
  486       if (symlink(rootInfo->root->plainPath(linkContents).c_str(),
  487                   targetName) != 0) {
  488         cerr << "unable to create symlink " << targetName << "\n";
  489         return EXIT_FAILURE;
  490       }
  491     } else {
  492       int outfd = creat(targetName, st.st_mode);
  493 
  494       WriteOutput output(outfd);
  495       processContents(rootInfo, encfsName, output);
  496     }
  497   }
  498   return EXIT_SUCCESS;
  499 }
  500 
  501 static bool endsWith(const string &str, char ch) {
  502   if (str.empty())
  503     return false;
  504   else
  505     return str[str.length() - 1] == ch;
  506 }
  507 
  508 static int traverseDirs(const std::shared_ptr<EncFS_Root> &rootInfo,
  509                         string volumeDir, string destDir) {
  510   if (!endsWith(volumeDir, '/')) volumeDir.append("/");
  511   if (!endsWith(destDir, '/')) destDir.append("/");
  512 
  513   // Lookup directory node so we can create a destination directory
  514   // with the same permissions
  515   {
  516     struct stat st;
  517     std::shared_ptr<FileNode> dirNode =
  518         rootInfo->root->lookupNode(volumeDir.c_str(), "encfsctl");
  519     if (dirNode->getAttr(&st)) return EXIT_FAILURE;
  520 
  521     mkdir(destDir.c_str(), st.st_mode);
  522   }
  523 
  524   // show files in directory
  525   DirTraverse dt = rootInfo->root->openDir(volumeDir.c_str());
  526   if (dt.valid()) {
  527     for (string name = dt.nextPlaintextName(); !name.empty();
  528          name = dt.nextPlaintextName()) {
  529       // Recurse to subdirectories
  530       if (name != "." && name != "..") {
  531         string plainPath = volumeDir + name;
  532         string cpath = rootInfo->root->cipherPath(plainPath.c_str());
  533         string destName = destDir + name;
  534 
  535         int r = EXIT_SUCCESS;
  536         struct stat stBuf;
  537         if (!lstat(cpath.c_str(), &stBuf)) {
  538           if (S_ISDIR(stBuf.st_mode)) {
  539             traverseDirs(rootInfo, (plainPath + '/').c_str(), destName + '/');
  540           } else if (S_ISLNK(stBuf.st_mode)) {
  541             r = copyLink(stBuf, rootInfo, cpath, destName);
  542           } else {
  543             r = copyContents(rootInfo, plainPath.c_str(), destName.c_str());
  544           }
  545         } else {
  546           r = EXIT_FAILURE;
  547         }
  548 
  549         if (r != EXIT_SUCCESS) return r;
  550       }
  551     }
  552   }
  553   return EXIT_SUCCESS;
  554 }
  555 
  556 static int cmd_export(int argc, char **argv) {
  557   (void)argc;
  558 
  559   RootPtr rootInfo = initRootInfo(argv[1]);
  560 
  561   if (!rootInfo) return EXIT_FAILURE;
  562 
  563   string destDir = argv[2];
  564   // if the dir doesn't exist, then create it (with user permission)
  565   if (!checkDir(destDir) && !userAllowMkdir(destDir.c_str(), 0700))
  566     return EXIT_FAILURE;
  567 
  568   return traverseDirs(rootInfo, "/", destDir);
  569 }
  570 
  571 int showcruft(const std::shared_ptr<EncFS_Root> &rootInfo,
  572               const char *dirName) {
  573   int found = 0;
  574   DirTraverse dt = rootInfo->root->openDir(dirName);
  575   if (dt.valid()) {
  576     bool showedDir = false;
  577     for (string name = dt.nextInvalid(); !name.empty();
  578          name = dt.nextInvalid()) {
  579       string cpath = rootInfo->root->cipherPath(dirName);
  580       cpath += '/';
  581       cpath += name;
  582 
  583       if (!showedDir) {
  584         // just before showing a list of files in a directory
  585         cout << autosprintf(_("In directory %s: \n"), dirName);
  586         showedDir = true;
  587       }
  588       ++found;
  589       cout << cpath << "\n";
  590     }
  591 
  592     // now go back and look for directories to recurse into..
  593     dt = rootInfo->root->openDir(dirName);
  594     if (dt.valid()) {
  595       for (string name = dt.nextPlaintextName(); !name.empty();
  596            name = dt.nextPlaintextName()) {
  597         if (name == "." || name == "..") continue;
  598 
  599         string plainPath = dirName;
  600         plainPath += '/';
  601         plainPath += name;
  602 
  603         string cpath = rootInfo->root->cipherPath(plainPath.c_str());
  604 
  605         if (isDirectory(cpath.c_str()))
  606           found += showcruft(rootInfo, plainPath.c_str());
  607       }
  608     }
  609   }
  610 
  611   return found;
  612 }
  613 
  614 /*
  615     iterate recursively through the filesystem and print out names of files
  616     which have filenames which cannot be decoded with the given key..
  617 */
  618 static int cmd_showcruft(int argc, char **argv) {
  619   (void)argc;
  620 
  621   RootPtr rootInfo = initRootInfo(argv[1]);
  622 
  623   if (!rootInfo) return EXIT_FAILURE;
  624 
  625   int filesFound = showcruft(rootInfo, "/");
  626 
  627   // TODO: the singular version should say "Found an invalid file", but all the
  628   // translations
  629   // depend upon this broken singular form, so it isn't easy to change.
  630   cerr << autosprintf(ngettext("Found %i invalid file.",
  631                                "Found %i invalid files.", filesFound),
  632                       filesFound)
  633        << "\n";
  634 
  635   return EXIT_SUCCESS;
  636 }
  637 
  638 static int do_chpasswd(bool useStdin, bool annotate, bool checkOnly, int argc,
  639                        char **argv) {
  640   (void)argc;
  641   string rootDir = argv[1];
  642   if (!checkDir(rootDir)) return EXIT_FAILURE;
  643 
  644   EncFSConfig *config = new EncFSConfig;
  645   ConfigType cfgType = readConfig(rootDir, config, "");
  646 
  647   if (cfgType == Config_None) {
  648     cout << _("Unable to load or parse config file\n");
  649     return EXIT_FAILURE;
  650   }
  651 
  652   // instanciate proper cipher
  653   std::shared_ptr<Cipher> cipher =
  654       Cipher::New(config->cipherIface, config->keySize);
  655   if (!cipher) {
  656     cout << autosprintf(_("Unable to find specified cipher \"%s\"\n"),
  657                         config->cipherIface.name().c_str());
  658     return EXIT_FAILURE;
  659   }
  660 
  661   // ask for existing password
  662   cout << _("Enter current Encfs password\n");
  663   if (annotate) cerr << "$PROMPT$ passwd" << endl;
  664   CipherKey userKey = config->getUserKey(useStdin);
  665   if (!userKey) return EXIT_FAILURE;
  666 
  667   // decode volume key using user key -- at this point we detect an incorrect
  668   // password if the key checksum does not match (causing readKey to fail).
  669   CipherKey volumeKey = cipher->readKey(config->getKeyData(), userKey);
  670 
  671   if (!volumeKey) {
  672     cout << _("Invalid password\n");
  673     return EXIT_FAILURE;
  674   }
  675 
  676   if (checkOnly) {
  677     cout << _("Password is correct\n");
  678     return EXIT_SUCCESS;
  679   }
  680 
  681   // Now, get New user key..
  682   userKey.reset();
  683   cout << _("Enter new Encfs password\n");
  684   // reinitialize salt and iteration count
  685   config->kdfIterations = 0;  // generate new
  686 
  687   if (useStdin) {
  688     if (annotate) cerr << "$PROMPT$ new_passwd" << endl;
  689     userKey = config->getUserKey(true);
  690   } else
  691     userKey = config->getNewUserKey();
  692 
  693   // re-encode the volume key using the new user key and write it out..
  694   int result = EXIT_FAILURE;
  695   if (userKey) {
  696     int encodedKeySize = cipher->encodedKeySize();
  697     unsigned char *keyBuf = new unsigned char[encodedKeySize];
  698 
  699     // encode volume key with new user key
  700     cipher->writeKey(volumeKey, keyBuf, userKey);
  701     userKey.reset();
  702 
  703     config->assignKeyData(keyBuf, encodedKeySize);
  704     delete[] keyBuf;
  705 
  706     if (saveConfig(cfgType, rootDir, config, "")) {
  707       // password modified -- changes volume key of filesystem..
  708       cout << _("Volume Key successfully updated.\n");
  709       result = EXIT_SUCCESS;
  710     } else {
  711       cout << _("Error saving modified config file.\n");
  712     }
  713   } else {
  714     cout << _("Error creating key\n");
  715   }
  716 
  717   volumeKey.reset();
  718 
  719   return result;
  720 }
  721 
  722 static int chpasswd(int argc, char **argv) {
  723   return do_chpasswd(false, false, false, argc, argv);
  724 }
  725 
  726 static int chpasswdAutomaticly(int argc, char **argv) {
  727   return do_chpasswd(true, false, false, argc, argv);
  728 }
  729 
  730 static int ckpasswdAutomaticly(int argc, char **argv) {
  731   return do_chpasswd(true, false, true, argc, argv);
  732 }
  733 
  734 int main(int argc, char **argv) {
  735   START_EASYLOGGINGPP(argc, argv);
  736   encfs::initLogging();
  737 
  738 #if defined(ENABLE_NLS) && defined(LOCALEDIR)
  739   setlocale(LC_ALL, "");
  740   bindtextdomain(PACKAGE, LOCALEDIR);
  741   textdomain(PACKAGE);
  742 #endif
  743 
  744   SSL_load_error_strings();
  745   SSL_library_init();
  746 
  747   if (argc < 2) {
  748     usage(argv[0]);
  749     return EXIT_FAILURE;
  750   }
  751 
  752   // Skip over uninteresting args.
  753   while (argc > 2 && *argv[1] == '-') {
  754     VLOG(1) << "skipping arg " << argv[1];
  755     argc--;
  756     argv[1] = argv[0];
  757     argv++;
  758   }
  759 
  760   if (argc == 2 && !(*argv[1] == '-' && *(argv[1] + 1) == '-')) {
  761     // default command when only 1 argument given -- treat the argument as
  762     // a directory..
  763     return showInfo(argc, argv);
  764   } else {
  765     // find the specified command
  766     int offset = 0;
  767     while (commands[offset].name != 0) {
  768       if (!strcmp(argv[1], commands[offset].name)) break;
  769       ++offset;
  770     }
  771 
  772     if (commands[offset].name == 0) {
  773       cerr << autosprintf(_("invalid command: \"%s\""), argv[1]) << "\n";
  774     } else {
  775       if ((argc - 2 < commands[offset].minOptions) ||
  776           (argc - 2 > commands[offset].maxOptions)) {
  777         cerr << autosprintf(
  778                     _("Incorrect number of arguments for command \"%s\""),
  779                     argv[1])
  780              << "\n";
  781       } else
  782         return (*commands[offset].func)(argc - 1, argv + 1);
  783     }
  784   }
  785 
  786   return EXIT_FAILURE;
  787 }