"Fossies" - the Fresh Open Source Software Archive

Member "encfs-1.9.5/encfs/FileUtils.cpp" (27 Apr 2018, 55684 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 "FileUtils.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 redistribute it and/or modify it
    8  * under the terms of the GNU Lesser General Public License as published by the
    9  * Free Software Foundation, either version 3 of the License, or (at your
   10  * option) 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 Lesser General Public License
   15  * for more details.
   16  *
   17  * You should have received a copy of the GNU Lesser General Public License
   18  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
   19  */
   20 
   21 // defines needed for RedHat 7.3...
   22 #ifdef __linux__
   23 #define _XOPEN_SOURCE 500  // make sure pwrite() is pulled in
   24 #endif
   25 #define _BSD_SOURCE      // pick up setenv on RH7.3
   26 #define _DEFAULT_SOURCE  // Replaces _BSD_SOURCE
   27 
   28 #include "easylogging++.h"
   29 #include <cctype>
   30 #include <cerrno>
   31 #include <cstdio>
   32 #include <cstdlib>
   33 #include <cstring>
   34 #include <fcntl.h>
   35 #include <fstream>
   36 #include <iostream>
   37 #include <list>
   38 #ifdef __APPLE__
   39 #include <sys/mount.h>
   40 #include <sys/param.h>
   41 #endif
   42 #include <sys/socket.h>
   43 #include <sys/stat.h>
   44 #include <sys/wait.h>
   45 #include <tinyxml2.h>
   46 #include <unistd.h>
   47 #include <vector>
   48 
   49 #include "BlockNameIO.h"
   50 #include "Cipher.h"
   51 #include "CipherKey.h"
   52 #include "ConfigReader.h"
   53 #include "ConfigVar.h"
   54 #include "Context.h"
   55 #include "DirNode.h"
   56 #include "Error.h"
   57 #include "FSConfig.h"
   58 #include "FileUtils.h"
   59 #include "Interface.h"
   60 #include "NameIO.h"
   61 #include "Range.h"
   62 #include "XmlReader.h"
   63 #include "autosprintf.h"
   64 #include "base64.h"
   65 #include "config.h"
   66 #include "i18n.h"
   67 #include "intl/gettext.h"
   68 #include "readpassphrase.h"
   69 
   70 using namespace std;
   71 using gnu::autosprintf;
   72 
   73 namespace encfs {
   74 
   75 static const int DefaultBlockSize = 1024;
   76 // The maximum length of text passwords.  If longer are needed,
   77 // use the extpass option, as extpass can return arbitrary length binary data.
   78 static const int MaxPassBuf = 512;
   79 
   80 static const int NormalKDFDuration = 500;     // 1/2 a second
   81 static const int ParanoiaKDFDuration = 3000;  // 3 seconds
   82 
   83 // environment variable names for values encfs stores in the environment when
   84 // calling an external password program.
   85 static const char ENCFS_ENV_ROOTDIR[] = "encfs_root";
   86 static const char ENCFS_ENV_STDOUT[] = "encfs_stdout";
   87 static const char ENCFS_ENV_STDERR[] = "encfs_stderr";
   88 
   89 // static int V5SubVersion = 20040518;
   90 // static int V5SubVersion = 20040621; // add external IV chaining
   91 static int V5SubVersion = 20040813;  // fix MACFileIO block size issues
   92 static int V5SubVersionDefault = 0;
   93 
   94 // 20080813 was really made on 20080413 -- typo on date..
   95 // const int V6SubVersion = 20080813; // switch to v6/XML, add allowHoles option
   96 // const int V6SubVersion = 20080816; // add salt and iteration count
   97 /*
   98  * In boost 1.42+, serial numbers change to 8 bit, which means the date
   99  * numbering scheme does not work any longer.
  100  * boost-versioning.h implements a workaround that sets the version to
  101  * 20 for boost 1.42+. */
  102 const int V6SubVersion = 20100713;  // add version field for boost 1.42+
  103 
  104 struct ConfigInfo {
  105   const char *fileName;
  106   ConfigType type;
  107   const char *environmentOverride;
  108   bool (*loadFunc)(const char *fileName, EncFSConfig *config, ConfigInfo *cfg);
  109   bool (*saveFunc)(const char *fileName, const EncFSConfig *config);
  110   int currentSubVersion;
  111   int defaultSubVersion;
  112 } ConfigFileMapping[] = {
  113     // current format
  114     {".encfs6.xml", Config_V6, "ENCFS6_CONFIG", readV6Config, writeV6Config,
  115      V6SubVersion, 0},
  116     // backward compatible support for older versions
  117     {".encfs5", Config_V5, "ENCFS5_CONFIG", readV5Config, writeV5Config,
  118      V5SubVersion, V5SubVersionDefault},
  119     {".encfs4", Config_V4, nullptr, readV4Config, writeV4Config, 0, 0},
  120     // no longer support earlier versions
  121     {".encfs3", Config_V3, nullptr, nullptr, nullptr, 0, 0},
  122     {".encfs2", Config_Prehistoric, nullptr, nullptr, nullptr, 0, 0},
  123     {".encfs", Config_Prehistoric, nullptr, nullptr, nullptr, 0, 0},
  124     {nullptr, Config_None, nullptr, nullptr, nullptr, 0, 0}};
  125 
  126 EncFS_Root::EncFS_Root() = default;
  127 
  128 EncFS_Root::~EncFS_Root() = default;
  129 
  130 bool fileExists(const char *fileName) {
  131   struct stat buf;
  132   return lstat(fileName, &buf) == 0;
  133 }
  134 
  135 bool isDirectory(const char *fileName) {
  136   struct stat buf;
  137   if (lstat(fileName, &buf) == 0) {
  138     return S_ISDIR(buf.st_mode);
  139   }
  140   return false;
  141 }
  142 
  143 bool isAbsolutePath(const char *fileName) {
  144   return (fileName != nullptr) && fileName[0] != '\0' && fileName[0] == '/';
  145 }
  146 
  147 const char *lastPathElement(const char *name) {
  148   const char *loc = strrchr(name, '/');
  149   return loc != nullptr ? loc + 1 : name;
  150 }
  151 
  152 std::string parentDirectory(const std::string &path) {
  153   size_t last = path.find_last_of('/');
  154   if (last == string::npos) {
  155     return string("");
  156   }
  157   return path.substr(0, last);
  158 }
  159 
  160 bool userAllowMkdir(const char *path, mode_t mode) {
  161   return userAllowMkdir(0, path, mode);
  162 }
  163 
  164 bool userAllowMkdir(int promptno, const char *path, mode_t mode) {
  165   // TODO: can we internationalize the y/n names?  Seems strange to prompt in
  166   // their own language but then have to respond 'y' or 'n'.
  167   // xgroup(setup)
  168   cerr << autosprintf(
  169       _("The directory \"%s\" does not exist. Should it be created? "
  170         "(y,N) "),
  171       path);
  172   char answer[10];
  173   char *res;
  174 
  175   switch (promptno) {
  176     case 1:
  177       cerr << endl << "$PROMPT$ create_root_dir" << endl;
  178       break;
  179     case 2:
  180       cerr << endl << "$PROMPT$ create_mount_point" << endl;
  181       break;
  182     default:
  183       break;
  184   }
  185   res = fgets(answer, sizeof(answer), stdin);
  186 
  187   if (res != nullptr && toupper(answer[0]) == 'Y') {
  188     int result = mkdir(path, mode);
  189     if (result < 0) {
  190       perror(_("Unable to create directory: "));
  191       return false;
  192     }
  193     return true;
  194   }
  195   // Directory not created, by user request
  196   cerr << _("Directory not created.") << "\n";
  197   return false;
  198 }
  199 
  200 /**
  201  * Load config file by calling the load function on the filename
  202  */
  203 ConfigType readConfig_load(ConfigInfo *nm, const char *path,
  204                            EncFSConfig *config) {
  205   if (nm->loadFunc != nullptr) {
  206     try {
  207       if ((*nm->loadFunc)(path, config, nm)) {
  208         config->cfgType = nm->type;
  209         return nm->type;
  210       }
  211     } catch (encfs::Error &err) {
  212       RLOG(ERROR) << "readConfig error: " << err.what();
  213     }
  214 
  215     RLOG(ERROR) << "Found config file " << path
  216                 << ", but failed to load - exiting";
  217     exit(1);
  218   } else {
  219     // No load function - must be an unsupported type..
  220     config->cfgType = nm->type;
  221     return nm->type;
  222   }
  223 }
  224 
  225 /**
  226  * Try to locate the config file
  227  * Tries the most recent format first, then looks for older versions
  228  */
  229 ConfigType readConfig(const string &rootDir, EncFSConfig *config, const string &cmdConfig) {
  230   ConfigInfo *nm = ConfigFileMapping;
  231   while (nm->fileName != nullptr) {
  232    // allow command line argument to override default config path 
  233     if (!cmdConfig.empty()) {
  234       if (!fileExists(cmdConfig.c_str())) {
  235         RLOG(ERROR)
  236             << "fatal: config file specified on command line does not exist: "
  237             << cmdConfig;
  238         exit(1);
  239       }
  240       return readConfig_load(nm, cmdConfig.c_str(), config);
  241     }    // allow environment variable to override default config path
  242     if (nm->environmentOverride != nullptr) {
  243       char *envFile = getenv(nm->environmentOverride);
  244       if (envFile != nullptr) {
  245         if (!fileExists(envFile)) {
  246           RLOG(ERROR)
  247               << "fatal: config file specified by environment does not exist: "
  248               << envFile;
  249           exit(1);
  250         }
  251         return readConfig_load(nm, envFile, config);
  252       }
  253     }
  254     // the standard place to look is in the root directory
  255     string path = rootDir + nm->fileName;
  256     if (fileExists(path.c_str())) {
  257       return readConfig_load(nm, path.c_str(), config);
  258     }
  259 
  260     ++nm;
  261   }
  262 
  263   return Config_None;
  264 }
  265 
  266 /**
  267  * Read config file in current "V6" XML format, normally named ".encfs6.xml"
  268  * This format is in use since Apr 13, 2008 (commit 6d081f5c)
  269  */
  270 // Read a boost::serialization config file using an Xml reader..
  271 bool readV6Config(const char *configFile, EncFSConfig *cfg, ConfigInfo *info) {
  272   (void)info;
  273 
  274   XmlReader rdr;
  275   if (!rdr.load(configFile)) {
  276     RLOG(ERROR) << "Failed to load config file " << configFile;
  277     return false;
  278   }
  279 
  280   XmlValuePtr serialization = rdr["boost_serialization"];
  281   XmlValuePtr config = (*serialization)["cfg"];
  282   if (!config) {
  283     config = (*serialization)["config"];
  284   }
  285   if (!config) {
  286     RLOG(ERROR) << "Unable to find XML configuration in file " << configFile;
  287     return false;
  288   }
  289 
  290   int version;
  291   if (!config->read("version", &version) &&
  292       !config->read("@version", &version)) {
  293     RLOG(ERROR) << "Unable to find version in config file";
  294     return false;
  295   }
  296 
  297   // version numbering was complicated by boost::archive
  298   if (version == 20 || version >= 20100713) {
  299     VLOG(1) << "found new serialization format";
  300     cfg->subVersion = version;
  301   } else if (version == 26800) {
  302     VLOG(1) << "found 20080816 version";
  303     cfg->subVersion = 20080816;
  304   } else if (version == 26797) {
  305     VLOG(1) << "found 20080813";
  306     cfg->subVersion = 20080813;
  307   } else if (version < V5SubVersion) {
  308     RLOG(ERROR) << "Invalid version " << version << " - please fix config file";
  309   } else {
  310     VLOG(1) << "Boost <= 1.41 compatibility mode";
  311     cfg->subVersion = version;
  312   }
  313   VLOG(1) << "subVersion = " << cfg->subVersion;
  314 
  315   config->read("creator", &cfg->creator);
  316   config->read("cipherAlg", &cfg->cipherIface);
  317   config->read("nameAlg", &cfg->nameIface);
  318 
  319   config->read("keySize", &cfg->keySize);
  320 
  321   config->read("blockSize", &cfg->blockSize);
  322   config->read("plainData", &cfg->plainData);
  323   config->read("uniqueIV", &cfg->uniqueIV);
  324   config->read("chainedNameIV", &cfg->chainedNameIV);
  325   config->read("externalIVChaining", &cfg->externalIVChaining);
  326   config->read("blockMACBytes", &cfg->blockMACBytes);
  327   config->read("blockMACRandBytes", &cfg->blockMACRandBytes);
  328   config->read("allowHoles", &cfg->allowHoles);
  329 
  330   int encodedSize;
  331   config->read("encodedKeySize", &encodedSize);
  332   auto *key = new unsigned char[encodedSize];
  333   config->readB64("encodedKeyData", key, encodedSize);
  334   cfg->assignKeyData(key, encodedSize);
  335   delete[] key;
  336 
  337   if (cfg->subVersion >= 20080816) {
  338     int saltLen;
  339     config->read("saltLen", &saltLen);
  340     auto *salt = new unsigned char[saltLen];
  341     config->readB64("saltData", salt, saltLen);
  342     cfg->assignSaltData(salt, saltLen);
  343     delete[] salt;
  344 
  345     config->read("kdfIterations", &cfg->kdfIterations);
  346     config->read("desiredKDFDuration", &cfg->desiredKDFDuration);
  347   } else {
  348     cfg->kdfIterations = 16;
  349     cfg->desiredKDFDuration = NormalKDFDuration;
  350   }
  351 
  352   return true;
  353 }
  354 
  355 /**
  356  * Read config file in deprecated "V5" format, normally named ".encfs5"
  357  * This format has been used before Apr 13, 2008
  358  */
  359 bool readV5Config(const char *configFile, EncFSConfig *config,
  360                   ConfigInfo *info) {
  361   bool ok = false;
  362 
  363   // use Config to parse the file and query it..
  364   ConfigReader cfgRdr;
  365   if (cfgRdr.load(configFile)) {
  366     try {
  367       config->subVersion =
  368           cfgRdr["subVersion"].readInt(info->defaultSubVersion);
  369       if (config->subVersion > info->currentSubVersion) {
  370         /* config file specifies a version outside our supported
  371          range..   */
  372         RLOG(WARNING) << "Config subversion " << config->subVersion
  373                       << " found, which is newer than supported version "
  374                       << info->currentSubVersion;
  375         return false;
  376       }
  377       if (config->subVersion < 20040813) {
  378         RLOG(ERROR) << "This version of EncFS doesn't support "
  379                        "filesystems created before 2004-08-13";
  380         return false;
  381       }
  382 
  383       cfgRdr["creator"] >> config->creator;
  384       cfgRdr["cipher"] >> config->cipherIface;
  385       cfgRdr["naming"] >> config->nameIface;
  386       cfgRdr["keySize"] >> config->keySize;
  387       cfgRdr["blockSize"] >> config->blockSize;
  388 
  389       string data;
  390       cfgRdr["keyData"] >> data;
  391       config->assignKeyData(data);
  392       config->uniqueIV = cfgRdr["uniqueIV"].readBool(false);
  393       config->chainedNameIV = cfgRdr["chainedIV"].readBool(false);
  394       config->externalIVChaining = cfgRdr["externalIV"].readBool(false);
  395       config->blockMACBytes = cfgRdr["blockMACBytes"].readInt(0);
  396       config->blockMACRandBytes = cfgRdr["blockMACRandBytes"].readInt(0);
  397 
  398       ok = true;
  399     } catch (encfs::Error &err) {
  400       RLOG(WARNING) << err.what();
  401       VLOG(1) << "Error parsing data in config file " << configFile;
  402       ok = false;
  403     }
  404   }
  405 
  406   return ok;
  407 }
  408 
  409 /**
  410  * Read config file in deprecated "V4" format, normally named ".encfs4"
  411  * This format has been used before Jan 7, 2008
  412  */
  413 bool readV4Config(const char *configFile, EncFSConfig *config,
  414                   ConfigInfo *info) {
  415   bool ok = false;
  416 
  417   // use Config to parse the file and query it..
  418   ConfigReader cfgRdr;
  419   if (cfgRdr.load(configFile)) {
  420     try {
  421       cfgRdr["cipher"] >> config->cipherIface;
  422       cfgRdr["keySize"] >> config->keySize;
  423       cfgRdr["blockSize"] >> config->blockSize;
  424       string data;
  425       cfgRdr["keyData"] >> data;
  426       config->assignKeyData(data);
  427 
  428       // fill in default for V4
  429       config->nameIface = Interface("nameio/stream", 1, 0, 0);
  430       config->creator = "EncFS 1.0.x";
  431       config->subVersion = info->defaultSubVersion;
  432       config->blockMACBytes = 0;
  433       config->blockMACRandBytes = 0;
  434       config->uniqueIV = false;
  435       config->externalIVChaining = false;
  436       config->chainedNameIV = false;
  437 
  438       ok = true;
  439     } catch (encfs::Error &err) {
  440       RLOG(WARNING) << err.what();
  441       VLOG(1) << "Error parsing config file " << configFile;
  442       ok = false;
  443     }
  444   }
  445 
  446   return ok;
  447 }
  448 
  449 bool saveConfig(ConfigType type, const string &rootDir,
  450                 const EncFSConfig *config, const string &cmdConfig) {
  451   bool ok = false;
  452 
  453   ConfigInfo *nm = ConfigFileMapping;
  454   while (nm->fileName != nullptr) {
  455     if (nm->type == type && (nm->saveFunc != nullptr)) {
  456       string path = rootDir + nm->fileName;
  457       if (!cmdConfig.empty()) {
  458         // use command line argument if specified
  459         path.assign(cmdConfig);
  460       }
  461       else if (nm->environmentOverride != nullptr) {
  462         // use environment file if specified..
  463         const char *envFile = getenv(nm->environmentOverride);
  464         if (envFile != nullptr) {
  465           path.assign(envFile);
  466         }
  467       }
  468 
  469       try {
  470         ok = (*nm->saveFunc)(path.c_str(), config);
  471       } catch (encfs::Error &err) {
  472         RLOG(WARNING) << err.what();
  473         ok = false;
  474       }
  475       break;
  476     }
  477     ++nm;
  478   }
  479 
  480   return ok;
  481 }
  482 
  483 template <typename T>
  484 tinyxml2::XMLElement *addEl(tinyxml2::XMLDocument &doc,
  485                             tinyxml2::XMLNode *parent, const char *name,
  486                             const T &value) {
  487   auto el = doc.NewElement(name);
  488   el->SetText(value);
  489   parent->InsertEndChild(el);
  490   return el;
  491 }
  492 
  493 template <>
  494 tinyxml2::XMLElement *addEl<>(tinyxml2::XMLDocument &doc,
  495                               tinyxml2::XMLNode *parent, const char *name,
  496                               const Interface &iface) {
  497   auto el = doc.NewElement(name);
  498 
  499   auto n = doc.NewElement("name");
  500   n->SetText(iface.name().c_str());
  501   el->InsertEndChild(n);
  502 
  503   auto major = doc.NewElement("major");
  504   major->SetText(iface.current());
  505   el->InsertEndChild(major);
  506 
  507   auto minor = doc.NewElement("minor");
  508   minor->SetText(iface.revision());
  509   el->InsertEndChild(minor);
  510 
  511   parent->InsertEndChild(el);
  512   return el;
  513 }
  514 
  515 template <>
  516 tinyxml2::XMLElement *addEl<>(tinyxml2::XMLDocument &doc,
  517                               tinyxml2::XMLNode *parent, const char *name,
  518                               const std::vector<unsigned char> &data) {
  519   string v = string("\n") + B64StandardEncode(data) + "\n";
  520   return addEl(doc, parent, name, v.c_str());
  521 }
  522 
  523 bool writeV6Config(const char *configFile, const EncFSConfig *cfg) {
  524   tinyxml2::XMLDocument doc;
  525 
  526   // Various static tags are included to make the output compatible with
  527   // older boost-based readers.
  528   doc.InsertEndChild(doc.NewDeclaration(nullptr));
  529   doc.InsertEndChild(doc.NewUnknown("DOCTYPE boost_serialization"));
  530 
  531   auto header = doc.NewElement("boost_serialization");
  532   header->SetAttribute("signature", "serialization::archive");
  533   header->SetAttribute("version", "7");
  534   doc.InsertEndChild(header);
  535 
  536   auto config = doc.NewElement("cfg");
  537   config->SetAttribute("class_id", "0");
  538   config->SetAttribute("tracking_level", "0");
  539   config->SetAttribute("version", "20");
  540   header->InsertEndChild(config);
  541 
  542   addEl(doc, config, "version", V6SubVersion);
  543   addEl(doc, config, "creator", cfg->creator.c_str());
  544   auto cipherAlg = addEl(doc, config, "cipherAlg", cfg->cipherIface);
  545   cipherAlg->SetAttribute("class_id", "1");
  546   cipherAlg->SetAttribute("tracking_level", "0");
  547   cipherAlg->SetAttribute("version", "0");
  548   addEl(doc, config, "nameAlg", cfg->nameIface);
  549   addEl(doc, config, "keySize", cfg->keySize);
  550   addEl(doc, config, "blockSize", cfg->blockSize);
  551   addEl(doc, config, "plainData", (int)cfg->plainData);
  552   addEl(doc, config, "uniqueIV", (int)cfg->uniqueIV);
  553   addEl(doc, config, "chainedNameIV", (int)cfg->chainedNameIV);
  554   addEl(doc, config, "externalIVChaining", (int)cfg->externalIVChaining);
  555   addEl(doc, config, "blockMACBytes", cfg->blockMACBytes);
  556   addEl(doc, config, "blockMACRandBytes", cfg->blockMACRandBytes);
  557   addEl(doc, config, "allowHoles", (int)cfg->allowHoles);
  558   addEl(doc, config, "encodedKeySize", (int)cfg->keyData.size());
  559   addEl(doc, config, "encodedKeyData", cfg->keyData);
  560   addEl(doc, config, "saltLen", (int)cfg->salt.size());
  561   addEl(doc, config, "saltData", cfg->salt);
  562   addEl(doc, config, "kdfIterations", cfg->kdfIterations);
  563   addEl(doc, config, "desiredKDFDuration", (int)cfg->desiredKDFDuration);
  564 
  565   auto err = doc.SaveFile(configFile, false);
  566   return err == tinyxml2::XML_SUCCESS;
  567 }
  568 
  569 bool writeV5Config(const char *configFile, const EncFSConfig *config) {
  570   ConfigReader cfg;
  571 
  572   cfg["creator"] << config->creator;
  573   cfg["subVersion"] << config->subVersion;
  574   cfg["cipher"] << config->cipherIface;
  575   cfg["naming"] << config->nameIface;
  576   cfg["keySize"] << config->keySize;
  577   cfg["blockSize"] << config->blockSize;
  578   string key;
  579   key.assign((char *)config->getKeyData(), config->keyData.size());
  580   cfg["keyData"] << key;
  581   cfg["blockMACBytes"] << config->blockMACBytes;
  582   cfg["blockMACRandBytes"] << config->blockMACRandBytes;
  583   cfg["uniqueIV"] << config->uniqueIV;
  584   cfg["chainedIV"] << config->chainedNameIV;
  585   cfg["externalIV"] << config->externalIVChaining;
  586 
  587   return cfg.save(configFile);
  588 }
  589 
  590 bool writeV4Config(const char *configFile, const EncFSConfig *config) {
  591   ConfigReader cfg;
  592 
  593   cfg["cipher"] << config->cipherIface;
  594   cfg["keySize"] << config->keySize;
  595   cfg["blockSize"] << config->blockSize;
  596   string key;
  597   key.assign((char *)config->getKeyData(), config->keyData.size());
  598   cfg["keyData"] << key;
  599 
  600   return cfg.save(configFile);
  601 }
  602 
  603 static Cipher::CipherAlgorithm findCipherAlgorithm(const char *name,
  604                                                    int keySize) {
  605   Cipher::AlgorithmList algorithms = Cipher::GetAlgorithmList();
  606   Cipher::AlgorithmList::const_iterator it;
  607   for (it = algorithms.begin(); it != algorithms.end(); ++it) {
  608     if ((strcmp(name, it->name.c_str()) == 0) &&
  609         it->keyLength.allowed(keySize)) {
  610       return *it;
  611     }
  612   }
  613 
  614   Cipher::CipherAlgorithm result;
  615   return result;
  616 }
  617 
  618 /**
  619  * Ask the user which cipher to use
  620  */
  621 static Cipher::CipherAlgorithm selectCipherAlgorithm() {
  622   for (;;) {
  623     // figure out what cipher they want to use..
  624     // xgroup(setup)
  625     cout << _("The following cipher algorithms are available:") << "\n";
  626     Cipher::AlgorithmList algorithms = Cipher::GetAlgorithmList();
  627     Cipher::AlgorithmList::const_iterator it;
  628     int optNum = 1;
  629     for (it = algorithms.begin(); it != algorithms.end(); ++it, ++optNum) {
  630       cout << optNum << ". " << it->name << " : "
  631            << gettext(it->description.c_str()) << "\n";
  632       if (it->keyLength.min() == it->keyLength.max()) {
  633         // shown after algorithm name and description.
  634         // xgroup(setup)
  635         cout << autosprintf(_(" -- key length %i bits"), it->keyLength.min())
  636              << "\n";
  637       } else {
  638         cout << autosprintf(
  639                     // shown after algorithm name and description.
  640                     // xgroup(setup)
  641                     _(" -- Supports key lengths of %i to %i bits"),
  642                     it->keyLength.min(), it->keyLength.max())
  643              << "\n";
  644       }
  645 
  646       if (it->blockSize.min() == it->blockSize.max()) {
  647         cout << autosprintf(
  648                     // shown after algorithm name and description.
  649                     // xgroup(setup)
  650                     _(" -- block size %i bytes"), it->blockSize.min())
  651              << "\n";
  652       } else {
  653         cout << autosprintf(
  654                     // shown after algorithm name and description.
  655                     // xgroup(setup)
  656                     _(" -- Supports block sizes of %i to %i bytes"),
  657                     it->blockSize.min(), it->blockSize.max())
  658              << "\n";
  659       }
  660     }
  661 
  662     // xgroup(setup)
  663     cout << "\n" << _("Enter the number corresponding to your choice: ");
  664     char answer[10];
  665     char *res = fgets(answer, sizeof(answer), stdin);
  666     int cipherNum = (res == nullptr ? 0 : (int)strtol(answer, nullptr, 10));
  667     cout << "\n";
  668 
  669     if (cipherNum < 1 || cipherNum > (int)algorithms.size()) {
  670       cerr << _("Invalid selection.") << "\n";
  671       continue;
  672     }
  673 
  674     it = algorithms.begin();
  675     while (--cipherNum != 0) {  // numbering starts at 1
  676       ++it;
  677     }
  678 
  679     Cipher::CipherAlgorithm alg = *it;
  680 
  681     // xgroup(setup)
  682     cout << autosprintf(_("Selected algorithm \"%s\""), alg.name.c_str())
  683          << "\n\n";
  684 
  685     return alg;
  686   }
  687 }
  688 
  689 /**
  690  * Ask the user which encoding to use for file names
  691  */
  692 static Interface selectNameCoding() {
  693   for (;;) {
  694     // figure out what cipher they want to use..
  695     // xgroup(setup)
  696     cout << _("The following filename encoding algorithms are available:")
  697          << "\n";
  698     NameIO::AlgorithmList algorithms = NameIO::GetAlgorithmList();
  699     NameIO::AlgorithmList::const_iterator it;
  700     int optNum = 1;
  701     for (it = algorithms.begin(); it != algorithms.end(); ++it, ++optNum) {
  702       cout << optNum << ". " << it->name << " : "
  703            << gettext(it->description.c_str()) << "\n";
  704     }
  705 
  706     // xgroup(setup)
  707     cout << "\n" << _("Enter the number corresponding to your choice: ");
  708     char answer[10];
  709     char *res = fgets(answer, sizeof(answer), stdin);
  710     int algNum = (res == nullptr ? 0 : (int)strtol(answer, nullptr, 10));
  711     cout << "\n";
  712 
  713     if (algNum < 1 || algNum > (int)algorithms.size()) {
  714       cerr << _("Invalid selection.") << "\n";
  715       continue;
  716     }
  717 
  718     it = algorithms.begin();
  719     while (--algNum != 0) {  // numbering starts at 1
  720       ++it;
  721     }
  722 
  723     // xgroup(setup)
  724     cout << autosprintf(_("Selected algorithm \"%s\""), it->name.c_str())
  725          << "\"\n\n";
  726 
  727     return it->iface;
  728   }
  729 }
  730 
  731 /**
  732  * Ask the user which key size to use
  733  */
  734 static int selectKeySize(const Cipher::CipherAlgorithm &alg) {
  735   if (alg.keyLength.min() == alg.keyLength.max()) {
  736     cout << autosprintf(_("Using key size of %i bits"), alg.keyLength.min())
  737          << "\n";
  738     return alg.keyLength.min();
  739   }
  740 
  741   cout
  742       << autosprintf(
  743              // xgroup(setup)
  744              _("Please select a key size in bits.  The cipher you have chosen\n"
  745                "supports sizes from %i to %i bits in increments of %i bits.\n"
  746                "For example: "),
  747              alg.keyLength.min(), alg.keyLength.max(), alg.keyLength.inc())
  748       << "\n";
  749 
  750   int numAvail =
  751       (alg.keyLength.max() - alg.keyLength.min()) / alg.keyLength.inc();
  752 
  753   if (numAvail < 5) {
  754     // show them all
  755     for (int i = 0; i <= numAvail; ++i) {
  756       if (i != 0) {
  757         cout << ", ";
  758       }
  759       cout << alg.keyLength.min() + i * alg.keyLength.inc();
  760     }
  761   } else {
  762     // partial
  763     for (int i = 0; i < 3; ++i) {
  764       if (i != 0) {
  765         cout << ", ";
  766       }
  767       cout << alg.keyLength.min() + i * alg.keyLength.inc();
  768     }
  769     cout << " ... " << alg.keyLength.max() - alg.keyLength.inc();
  770     cout << ", " << alg.keyLength.max();
  771   }
  772   // xgroup(setup)
  773   cout << "\n" << _("Selected key size: ");
  774 
  775   char answer[10];
  776   char *res = fgets(answer, sizeof(answer), stdin);
  777   int keySize = (res == nullptr ? 0 : (int)strtol(answer, nullptr, 10));
  778   cout << "\n";
  779 
  780   keySize = alg.keyLength.closest(keySize);
  781 
  782   // xgroup(setup)
  783   cout << autosprintf(_("Using key size of %i bits"), keySize) << "\n\n";
  784 
  785   return keySize;
  786 }
  787 
  788 /**
  789  * Ask the user which block size to use
  790  */
  791 static int selectBlockSize(const Cipher::CipherAlgorithm &alg) {
  792   if (alg.blockSize.min() == alg.blockSize.max()) {
  793     cout << autosprintf(
  794                 // xgroup(setup)
  795                 _("Using filesystem block size of %i bytes"),
  796                 alg.blockSize.min())
  797          << "\n";
  798     return alg.blockSize.min();
  799   }
  800 
  801   cout << autosprintf(
  802       // xgroup(setup)
  803       _("Select a block size in bytes.  The cipher you have chosen\n"
  804         "supports sizes from %i to %i bytes in increments of %i.\n"
  805         "Or just hit enter for the default (%i bytes)\n"),
  806       alg.blockSize.min(), alg.blockSize.max(), alg.blockSize.inc(),
  807       DefaultBlockSize);
  808 
  809   // xgroup(setup)
  810   cout << "\n" << _("filesystem block size: ");
  811 
  812   int blockSize = DefaultBlockSize;
  813   char answer[10];
  814   char *res = fgets(answer, sizeof(answer), stdin);
  815   cout << "\n";
  816 
  817   if (res != nullptr && (int)strtol(answer, nullptr, 10) >= alg.blockSize.min()) {
  818     blockSize = (int)strtol(answer, nullptr, 10);
  819   }
  820 
  821   blockSize = alg.blockSize.closest(blockSize);
  822 
  823   // xgroup(setup)
  824   cout << autosprintf(_("Using filesystem block size of %i bytes"), blockSize)
  825        << "\n\n";
  826 
  827   return blockSize;
  828 }
  829 
  830 /**
  831  * Prompt the user for a "y" or "n" answer.
  832  * An empty answer returns defaultValue.
  833  */
  834 static bool boolDefault(const char *prompt, bool defaultValue) {
  835 
  836   cout << prompt;
  837   cout << "\n";
  838 
  839   string yesno;
  840 
  841   if (defaultValue) {
  842     yesno = "[y]/n: ";
  843   } else {
  844     yesno = "y/[n]: ";
  845   }
  846 
  847   string response;
  848   bool value;
  849 
  850   while (true) {
  851     cout << yesno;
  852     getline(cin, response);
  853 
  854     if (cin.fail() || response == "") {
  855       value = defaultValue;
  856       break;
  857     }
  858     if (response == "y") {
  859       value = true;
  860       break;
  861     }
  862     if (response == "n") {
  863       value = false;
  864       break;
  865     }
  866   }
  867 
  868   cout << "\n";
  869   return value;
  870 }
  871 
  872 static bool boolDefaultNo(const char *prompt) {
  873   return boolDefault(prompt, false);
  874 }
  875 
  876 static bool boolDefaultYes(const char *prompt) {
  877   return boolDefault(prompt, true);
  878 }
  879 
  880 /**
  881  * Ask the user to select plain data
  882  */
  883 static bool selectPlainData(bool insecure) {
  884   bool plainData = false;
  885   if (insecure) {
  886     plainData = boolDefaultNo(
  887         _("You used --insecure, you can then disable file data encryption\n"
  888            "which is of course abolutely discouraged.\n"
  889            "Disable file data encryption?"));
  890   }
  891   return plainData;
  892 }
  893 
  894 /**
  895  * Ask the user whether to enable block MAC and random header bytes
  896  */
  897 static void selectBlockMAC(int *macBytes, int *macRandBytes, bool forceMac) {
  898   bool addMAC = false;
  899   if (!forceMac) {
  900     // xgroup(setup)
  901     addMAC = boolDefaultNo(
  902         _("Enable block authentication code headers\n"
  903           "on every block in a file?  This adds about 8 bytes per block\n"
  904           "to the storage requirements for a file, and significantly affects\n"
  905           "performance but it also means [almost] any modifications or errors\n"
  906           "within a block will be caught and will cause a read error."));
  907   } else {
  908     cout << "\n\n"
  909          << _("You specified --require-macs.  "
  910               "Enabling block authentication code headers...")
  911          << "\n\n";
  912     addMAC = true;
  913   }
  914 
  915   if (addMAC) {
  916     *macBytes = 8;
  917   } else {
  918     *macBytes = 0;
  919   }
  920 
  921   // xgroup(setup)
  922   cout << _(
  923       "Add random bytes to each block header?\n"
  924       "This adds a performance penalty, but ensures that blocks\n"
  925       "have different authentication codes.  Note that you can\n"
  926       "have the same benefits by enabling per-file initialization\n"
  927       "vectors, which does not come with as great of performance\n"
  928       "penalty. \n"
  929       "Select a number of bytes, from 0 (no random bytes) to 8: ");
  930 
  931   char answer[10];
  932   int randSize = 0;
  933   char *res = fgets(answer, sizeof(answer), stdin);
  934   cout << "\n";
  935 
  936   randSize = (res == nullptr ? 0 : (int)strtol(answer, nullptr, 10));
  937   if (randSize < 0) {
  938     randSize = 0;
  939   }
  940   if (randSize > 8) {
  941     randSize = 8;
  942   }
  943 
  944   *macRandBytes = randSize;
  945 }
  946 
  947 /**
  948  * Ask the user if per-file unique IVs should be used
  949  */
  950 static bool selectUniqueIV(bool default_answer) {
  951   // xgroup(setup)
  952   return boolDefault(
  953       _("Enable per-file initialization vectors?\n"
  954         "This adds about 8 bytes per file to the storage requirements.\n"
  955         "It should not affect performance except possibly with applications\n"
  956         "which rely on block-aligned file io for performance."),
  957       default_answer);
  958 }
  959 
  960 /**
  961  * Ask the user if the filename IV should depend on the complete path
  962  */
  963 static bool selectChainedIV() {
  964   // xgroup(setup)
  965   return boolDefaultYes(
  966       _("Enable filename initialization vector chaining?\n"
  967         "This makes filename encoding dependent on the complete path, \n"
  968         "rather then encoding each path element individually."));
  969 }
  970 
  971 /**
  972  * Ask the user if the file IV should depend on the file path
  973  */
  974 static bool selectExternalChainedIV() {
  975   // xgroup(setup)
  976   return boolDefaultNo(
  977       _("Enable filename to IV header chaining?\n"
  978         "This makes file data encoding dependent on the complete file path.\n"
  979         "If a file is renamed, it will not decode sucessfully unless it\n"
  980         "was renamed by encfs with the proper key.\n"
  981         "If this option is enabled, then hard links will not be supported\n"
  982         "in the filesystem."));
  983 }
  984 
  985 /**
  986  * Ask the user if file holes should be passed through
  987  */
  988 static bool selectZeroBlockPassThrough() {
  989   // xgroup(setup)
  990   return boolDefaultYes(
  991       _("Enable file-hole pass-through?\n"
  992         "This avoids writing encrypted blocks when file holes are created."));
  993 }
  994 
  995 RootPtr createV6Config(EncFS_Context *ctx,
  996                        const std::shared_ptr<EncFS_Opts> &opts) {
  997   const std::string rootDir = opts->rootDir;
  998   bool enableIdleTracking = opts->idleTracking;
  999   bool forceDecode = opts->forceDecode;
 1000   const std::string passwordProgram = opts->passwordProgram;
 1001   bool useStdin = opts->useStdin;
 1002   bool reverseEncryption = opts->reverseEncryption;
 1003   ConfigMode configMode = opts->configMode;
 1004   bool annotate = opts->annotate;
 1005 
 1006   RootPtr rootInfo;
 1007 
 1008   // creating new volume key.. should check that is what the user is
 1009   // expecting...
 1010   // xgroup(setup)
 1011   cout << _("Creating new encrypted volume.") << endl;
 1012 
 1013   char answer[10] = {0};
 1014   if (configMode == Config_Prompt) {
 1015     // xgroup(setup)
 1016     cout << _(
 1017         "Please choose from one of the following options:\n"
 1018         " enter \"x\" for expert configuration mode,\n"
 1019         " enter \"p\" for pre-configured paranoia mode,\n"
 1020         " anything else, or an empty line will select standard mode.\n"
 1021         "?> ");
 1022 
 1023     if (annotate) {
 1024       cerr << "$PROMPT$ config_option" << endl;
 1025     }
 1026 
 1027     char *res = fgets(answer, sizeof(answer), stdin);
 1028     (void)res;
 1029     cout << "\n";
 1030   }
 1031 
 1032   //                               documented in ...
 1033   int keySize = 0;              // selectKeySize()
 1034   int blockSize = 0;            // selectBlockSize()
 1035   Cipher::CipherAlgorithm alg;  // selectCipherAlgorithm()
 1036   Interface nameIOIface;        // selectNameCoding()
 1037   int blockMACBytes = 0;        // selectBlockMAC()
 1038   int blockMACRandBytes = 0;    // selectBlockMAC()
 1039   bool plainData = false;       // selectPlainData()
 1040   bool uniqueIV = true;         // selectUniqueIV()
 1041   bool chainedIV = true;        // selectChainedIV()
 1042   bool externalIV = false;      // selectExternalChainedIV()
 1043   bool allowHoles = true;       // selectZeroBlockPassThrough()
 1044   long desiredKDFDuration = NormalKDFDuration;
 1045 
 1046   if (reverseEncryption) {
 1047     chainedIV = false;
 1048     externalIV = false;
 1049     uniqueIV = false;
 1050     blockMACBytes = 0;
 1051     blockMACRandBytes = 0;
 1052   }
 1053 
 1054   if (configMode == Config_Paranoia || answer[0] == 'p') {
 1055     if (reverseEncryption) {
 1056       cerr << _("Paranoia configuration not supported for reverse encryption");
 1057       return rootInfo;
 1058     }
 1059 
 1060     // xgroup(setup)
 1061     cout << _("Paranoia configuration selected.") << "\n";
 1062     // look for AES with 256 bit key..
 1063     // Use block filename encryption mode.
 1064     // Enable per-block HMAC headers at substantial performance penalty..
 1065     // Enable per-file initialization vector headers.
 1066     // Enable filename initialization vector chaning
 1067     keySize = 256;
 1068     blockSize = DefaultBlockSize;
 1069     alg = findCipherAlgorithm("AES", keySize);
 1070 
 1071 // If case-insensitive system, opt for Block32 filename encoding
 1072 #if defined(DEFAULT_CASE_INSENSITIVE)
 1073     nameIOIface = BlockNameIO::CurrentInterface(true);
 1074 #else
 1075     nameIOIface = BlockNameIO::CurrentInterface();
 1076 #endif
 1077 
 1078     blockMACBytes = 8;
 1079     blockMACRandBytes = 0;  // using uniqueIV, so this isn't necessary
 1080     externalIV = true;
 1081     desiredKDFDuration = ParanoiaKDFDuration;
 1082   } else if (configMode == Config_Standard || answer[0] != 'x') {
 1083     // xgroup(setup)
 1084     cout << _("Standard configuration selected.") << "\n";
 1085     // AES w/ 192 bit key, block name encoding, per-file initialization
 1086     // vectors are all standard.
 1087     keySize = 192;
 1088     blockSize = DefaultBlockSize;
 1089     alg = findCipherAlgorithm("AES", keySize);
 1090 
 1091 // If case-insensitive system, opt for Block32 filename encoding
 1092 #if defined(DEFAULT_CASE_INSENSITIVE)
 1093     nameIOIface = BlockNameIO::CurrentInterface(true);
 1094 #else
 1095     nameIOIface = BlockNameIO::CurrentInterface();
 1096 #endif
 1097 
 1098     if (opts->requireMac) {
 1099       blockMACBytes = 8;
 1100     }
 1101   }
 1102 
 1103   if (answer[0] == 'x' || alg.name.empty()) {
 1104     if (answer[0] != 'x') {
 1105       // xgroup(setup)
 1106       cout << _(
 1107           "Sorry, unable to locate cipher for predefined "
 1108           "configuration...\n"
 1109           "Falling through to Manual configuration mode.");
 1110     } else {
 1111       // xgroup(setup)
 1112       cout << _("Manual configuration mode selected.");
 1113     }
 1114     cout << endl;
 1115 
 1116     // query user for settings..
 1117     alg = selectCipherAlgorithm();
 1118     keySize = selectKeySize(alg);
 1119     blockSize = selectBlockSize(alg);
 1120     plainData = selectPlainData(opts->insecure);
 1121     nameIOIface = selectNameCoding();
 1122     if (plainData) {
 1123       cout << _("plain data - IV, MAC and file-hole disabled") << "\n";
 1124       allowHoles = false;
 1125       chainedIV = false;
 1126       externalIV = false;
 1127       uniqueIV = false;
 1128       blockMACBytes = 0;
 1129       blockMACRandBytes = 0;
 1130     }
 1131     else {
 1132       if (reverseEncryption) {
 1133         cout << _("reverse encryption - chained IV and MAC disabled") << "\n";
 1134         uniqueIV = selectUniqueIV(false);
 1135         /* If uniqueIV is off, writing can be allowed, because there
 1136          * is no header that could be overwritten.
 1137          * So if it is on, enforce readOnly. */
 1138         if (uniqueIV) {
 1139           opts->readOnly = true;
 1140         }
 1141       } else {
 1142         chainedIV = selectChainedIV();
 1143         uniqueIV = selectUniqueIV(true);
 1144         if (chainedIV && uniqueIV) {
 1145           externalIV = selectExternalChainedIV();
 1146         } else {
 1147           // xgroup(setup)
 1148           cout << _("External chained IV disabled, as both 'IV chaining'\n"
 1149                     "and 'unique IV' features are required for this option.")
 1150                << "\n";
 1151           externalIV = false;
 1152         }
 1153         selectBlockMAC(&blockMACBytes, &blockMACRandBytes, opts->requireMac);
 1154         allowHoles = selectZeroBlockPassThrough();
 1155       }
 1156     }
 1157   }
 1158 
 1159   std::shared_ptr<Cipher> cipher = Cipher::New(alg.name, keySize);
 1160   if (!cipher) {
 1161     cerr << autosprintf(
 1162         _("Unable to instanciate cipher %s, key size %i, block size %i"),
 1163         alg.name.c_str(), keySize, blockSize);
 1164     return rootInfo;
 1165   }
 1166   VLOG(1) << "Using cipher " << alg.name << ", key size " << keySize
 1167           << ", block size " << blockSize;
 1168 
 1169   std::shared_ptr<EncFSConfig> config(new EncFSConfig);
 1170 
 1171   config->cfgType = Config_V6;
 1172   config->cipherIface = cipher->interface();
 1173   config->keySize = keySize;
 1174   config->blockSize = blockSize;
 1175   config->plainData = plainData;
 1176   config->nameIface = nameIOIface;
 1177   config->creator = "EncFS " VERSION;
 1178   config->subVersion = V6SubVersion;
 1179   config->blockMACBytes = blockMACBytes;
 1180   config->blockMACRandBytes = blockMACRandBytes;
 1181   config->uniqueIV = uniqueIV;
 1182   config->chainedNameIV = chainedIV;
 1183   config->externalIVChaining = externalIV;
 1184   config->allowHoles = allowHoles;
 1185 
 1186   config->salt.clear();
 1187   config->kdfIterations = 0;  // filled in by keying function
 1188   config->desiredKDFDuration = desiredKDFDuration;
 1189 
 1190   cout << "\n";
 1191   // xgroup(setup)
 1192   cout << _("Configuration finished.  The filesystem to be created has\n"
 1193             "the following properties:")
 1194        << endl;
 1195   showFSInfo(config.get());
 1196 
 1197   if (config->externalIVChaining) {
 1198     cout << _("-------------------------- WARNING --------------------------\n")
 1199          << _("The external initialization-vector chaining option has been\n"
 1200               "enabled.  This option disables the use of hard links on the\n"
 1201               "filesystem. Without hard links, some programs may not work.\n"
 1202               "The programs 'mutt' and 'procmail' are known to fail.  For\n"
 1203               "more information, please see the encfs mailing list.\n"
 1204               "If you would like to choose another configuration setting,\n"
 1205               "please press CTRL-C now to abort and start over.")
 1206          << endl;
 1207     cout << endl;
 1208   }
 1209 
 1210   // xgroup(setup)
 1211   cout << _(
 1212       "Now you will need to enter a password for your filesystem.\n"
 1213       "You will need to remember this password, as there is absolutely\n"
 1214       "no recovery mechanism.  However, the password can be changed\n"
 1215       "later using encfsctl.\n\n");
 1216 
 1217   int encodedKeySize = cipher->encodedKeySize();
 1218   auto *encodedKey = new unsigned char[encodedKeySize];
 1219 
 1220   CipherKey volumeKey = cipher->newRandomKey();
 1221 
 1222   // get user key and use it to encode volume key
 1223   CipherKey userKey;
 1224   VLOG(1) << "useStdin: " << useStdin;
 1225   if (useStdin) {
 1226     if (annotate) {
 1227       cerr << "$PROMPT$ new_passwd" << endl;
 1228     }
 1229     userKey = config->getUserKey(useStdin);
 1230   } else if (!passwordProgram.empty()) {
 1231     userKey = config->getUserKey(passwordProgram, rootDir);
 1232   } else {
 1233     userKey = config->getNewUserKey();
 1234   }
 1235 
 1236   cipher->writeKey(volumeKey, encodedKey, userKey);
 1237   userKey.reset();
 1238 
 1239   config->assignKeyData(encodedKey, encodedKeySize);
 1240   delete[] encodedKey;
 1241 
 1242   if (!volumeKey) {
 1243     cerr << _(
 1244         "Failure generating new volume key! "
 1245         "Please report this error.");
 1246     return rootInfo;
 1247   }
 1248 
 1249   if (!saveConfig(Config_V6, rootDir, config.get(), opts->config)) {
 1250     return rootInfo;
 1251   }
 1252 
 1253   // fill in config struct
 1254   std::shared_ptr<NameIO> nameCoder =
 1255       NameIO::New(config->nameIface, cipher, volumeKey);
 1256   if (!nameCoder) {
 1257     cerr << _("Name coding interface not supported");
 1258     cout << _("The filename encoding interface requested is not available")
 1259          << endl;
 1260     return rootInfo;
 1261   }
 1262 
 1263   nameCoder->setChainedNameIV(config->chainedNameIV);
 1264   nameCoder->setReverseEncryption(reverseEncryption);
 1265 
 1266   FSConfigPtr fsConfig(new FSConfig);
 1267   if (plainData) {
 1268     static Interface NullInterface("nullCipher", 1, 0, 0);
 1269     fsConfig->cipher = Cipher::New(NullInterface, 0);
 1270   }
 1271   else {
 1272     fsConfig->cipher = cipher;
 1273   }
 1274   fsConfig->key = volumeKey;
 1275   fsConfig->nameCoding = nameCoder;
 1276   fsConfig->config = config;
 1277   fsConfig->forceDecode = forceDecode;
 1278   fsConfig->reverseEncryption = reverseEncryption;
 1279   fsConfig->idleTracking = enableIdleTracking;
 1280   fsConfig->opts = opts;
 1281 
 1282   rootInfo = std::make_shared<encfs::EncFS_Root>();
 1283   rootInfo->cipher = cipher;
 1284   rootInfo->volumeKey = volumeKey;
 1285   rootInfo->root = std::make_shared<DirNode>(ctx, rootDir, fsConfig);
 1286 
 1287   return rootInfo;
 1288 }
 1289 
 1290 void showFSInfo(const EncFSConfig *config) {
 1291   std::shared_ptr<Cipher> cipher = Cipher::New(config->cipherIface, -1);
 1292   {
 1293     cout << autosprintf(
 1294         // xgroup(diag)
 1295         _("Filesystem cipher: \"%s\", version %i:%i:%i"),
 1296         config->cipherIface.name().c_str(), config->cipherIface.current(),
 1297         config->cipherIface.revision(), config->cipherIface.age());
 1298     // check if we support this interface..
 1299     if (!cipher) {
 1300       cout << _(" (NOT supported)\n");
 1301     } else {
 1302       // if we're using a newer interface, show the version number
 1303       if (config->cipherIface != cipher->interface()) {
 1304         Interface iface = cipher->interface();
 1305         // xgroup(diag)
 1306         cout << autosprintf(_(" (using %i:%i:%i)\n"), iface.current(),
 1307                             iface.revision(), iface.age());
 1308       } else {
 1309         cout << "\n";
 1310       }
 1311     }
 1312   }
 1313   {
 1314     // xgroup(diag)
 1315     cout << autosprintf(_("Filename encoding: \"%s\", version %i:%i:%i"),
 1316                         config->nameIface.name().c_str(),
 1317                         config->nameIface.current(),
 1318                         config->nameIface.revision(), config->nameIface.age());
 1319 
 1320     // check if we support the filename encoding interface..
 1321     std::shared_ptr<NameIO> nameCoder =
 1322         NameIO::New(config->nameIface, cipher, CipherKey());
 1323     if (!nameCoder) {
 1324       // xgroup(diag)
 1325       cout << _(" (NOT supported)\n");
 1326     } else {
 1327       // if we're using a newer interface, show the version number
 1328       if (config->nameIface != nameCoder->interface()) {
 1329         Interface iface = nameCoder->interface();
 1330         cout << autosprintf(_(" (using %i:%i:%i)\n"), iface.current(),
 1331                             iface.revision(), iface.age());
 1332       } else {
 1333         cout << "\n";
 1334       }
 1335     }
 1336   }
 1337   {
 1338     cout << autosprintf(_("Key Size: %i bits"), config->keySize);
 1339     cipher = config->getCipher();
 1340     if (!cipher) {
 1341       // xgroup(diag)
 1342       cout << _(" (NOT supported)\n");
 1343     } else {
 1344       cout << "\n";
 1345     }
 1346   }
 1347   if (config->kdfIterations > 0 && !config->salt.empty()) {
 1348     cout << autosprintf(_("Using PBKDF2, with %i iterations"),
 1349                         config->kdfIterations)
 1350          << "\n";
 1351     cout << autosprintf(_("Salt Size: %i bits"), (int)(8 * config->salt.size()))
 1352          << "\n";
 1353   }
 1354   if ((config->blockMACBytes != 0) || (config->blockMACRandBytes != 0)) {
 1355     if (config->subVersion < 20040813) {
 1356       cout << autosprintf(
 1357                   // xgroup(diag)
 1358                   _("Block Size: %i bytes + %i byte MAC header"),
 1359                   config->blockSize,
 1360                   config->blockMACBytes + config->blockMACRandBytes)
 1361            << endl;
 1362     } else {
 1363       // new version stores the header as part of that block size..
 1364       cout << autosprintf(
 1365                   // xgroup(diag)
 1366                   _("Block Size: %i bytes, including %i byte MAC header"),
 1367                   config->blockSize,
 1368                   config->blockMACBytes + config->blockMACRandBytes)
 1369            << endl;
 1370     }
 1371   } else {
 1372     // xgroup(diag)
 1373     cout << autosprintf(_("Block Size: %i bytes"), config->blockSize);
 1374     cout << "\n";
 1375   }
 1376 
 1377   if (config->uniqueIV) {
 1378     // xgroup(diag)
 1379     cout << _("Each file contains 8 byte header with unique IV data.\n");
 1380   }
 1381   if (config->chainedNameIV) {
 1382     // xgroup(diag)
 1383     cout << _("Filenames encoded using IV chaining mode.\n");
 1384   }
 1385   if (config->externalIVChaining) {
 1386     // xgroup(diag)
 1387     cout << _("File data IV is chained to filename IV.\n");
 1388   }
 1389   if (config->allowHoles) {
 1390     // xgroup(diag)
 1391     cout << _("File holes passed through to ciphertext.\n");
 1392   }
 1393   cout << "\n";
 1394 }
 1395 std::shared_ptr<Cipher> EncFSConfig::getCipher() const {
 1396   return Cipher::New(cipherIface, keySize);
 1397 }
 1398 
 1399 void EncFSConfig::assignKeyData(const std::string &in) {
 1400   keyData.assign(in.data(), in.data() + in.length());
 1401 }
 1402 
 1403 void EncFSConfig::assignKeyData(unsigned char *data, int len) {
 1404   keyData.assign(data, data + len);
 1405 }
 1406 
 1407 void EncFSConfig::assignSaltData(unsigned char *data, int len) {
 1408   salt.assign(data, data + len);
 1409 }
 1410 
 1411 unsigned char *EncFSConfig::getKeyData() const {
 1412   return const_cast<unsigned char *>(&keyData.front());
 1413 }
 1414 
 1415 unsigned char *EncFSConfig::getSaltData() const {
 1416   return const_cast<unsigned char *>(&salt.front());
 1417 }
 1418 
 1419 CipherKey EncFSConfig::makeKey(const char *password, int passwdLen) {
 1420   CipherKey userKey;
 1421   std::shared_ptr<Cipher> cipher = getCipher();
 1422 
 1423   if (passwdLen == 0) {
 1424     cerr << _("fatal: zero-length passwords are not allowed\n");
 1425     exit(1);
 1426   }
 1427 
 1428   // if no salt is set and we're creating a new password for a new
 1429   // FS type, then initialize salt..
 1430   if (salt.empty() && kdfIterations == 0 && cfgType >= Config_V6) {
 1431     // upgrade to using salt
 1432     salt.resize(20);
 1433   }
 1434 
 1435   if (!salt.empty()) {
 1436     // if iterations isn't known, then we're creating a new key, so
 1437     // randomize the salt..
 1438     if (kdfIterations == 0 &&
 1439         !cipher->randomize(getSaltData(), salt.size(), true)) {
 1440       cout << _("Error creating salt\n");
 1441       return userKey;
 1442     }
 1443 
 1444     userKey = cipher->newKey(password, passwdLen, kdfIterations,
 1445                              desiredKDFDuration, getSaltData(), salt.size());
 1446   } else {
 1447     userKey = cipher->newKey(password, passwdLen);
 1448   }
 1449 
 1450   return userKey;
 1451 }
 1452 
 1453 CipherKey EncFSConfig::getUserKey(bool useStdin) {
 1454   char passBuf[MaxPassBuf];
 1455   char *res;
 1456 
 1457   if (useStdin) {
 1458     res = fgets(passBuf, sizeof(passBuf), stdin);
 1459     // Kill the trailing newline.
 1460     if (passBuf[strlen(passBuf) - 1] == '\n') {
 1461       passBuf[strlen(passBuf) - 1] = '\0';
 1462     }
 1463   } else {
 1464     // xgroup(common)
 1465     res = readpassphrase(_("EncFS Password: "), passBuf, sizeof(passBuf),
 1466                          RPP_ECHO_OFF);
 1467   }
 1468 
 1469   CipherKey userKey;
 1470   if (res == nullptr) {
 1471     cerr << _("fatal: error reading password\n");
 1472     exit(1);
 1473   } else {
 1474     userKey = makeKey(passBuf, strlen(passBuf));
 1475   }
 1476 
 1477   memset(passBuf, 0, sizeof(passBuf));
 1478 
 1479   return userKey;
 1480 }
 1481 
 1482 std::string readPassword(int FD) {
 1483   char buffer[1024];
 1484   string result;
 1485 
 1486   while (true) {
 1487     ssize_t rdSize = recv(FD, buffer, sizeof(buffer), 0);
 1488 
 1489     if (rdSize > 0) {
 1490       result.append(buffer, rdSize);
 1491       memset(buffer, 0, sizeof(buffer));
 1492     } else {
 1493       break;
 1494     }
 1495   }
 1496 
 1497   // chop off trailing "\n" if present..
 1498   // This is done so that we can use standard programs like ssh-askpass
 1499   // without modification, as it returns trailing newline..
 1500   if (!result.empty() && result[result.length() - 1] == '\n') {
 1501     result.resize(result.length() - 1);
 1502   }
 1503 
 1504   return result;
 1505 }
 1506 
 1507 CipherKey EncFSConfig::getUserKey(const std::string &passProg,
 1508                                   const std::string &rootDir) {
 1509   // have a child process run the command and get the result back to us.
 1510   int fds[2], pid;
 1511   int res;
 1512   CipherKey result;
 1513 
 1514   res = socketpair(PF_UNIX, SOCK_STREAM, 0, fds);
 1515   if (res == -1) {
 1516     perror(_("Internal error: socketpair() failed"));
 1517     return result;
 1518   }
 1519   VLOG(1) << "getUserKey: fds = " << fds[0] << ", " << fds[1];
 1520 
 1521   pid = fork();
 1522   if (pid == -1) {
 1523     perror(_("Internal error: fork() failed"));
 1524     close(fds[0]);
 1525     close(fds[1]);
 1526     return result;
 1527   }
 1528 
 1529   if (pid == 0) {
 1530     const char *argv[4];
 1531     argv[0] = "/bin/sh";
 1532     argv[1] = "-c";
 1533     argv[2] = passProg.c_str();
 1534     argv[3] = nullptr;
 1535 
 1536     // child process.. run the command and send output to fds[0]
 1537     close(fds[1]);  // we don't use the other half..
 1538 
 1539     // make a copy of stdout and stderr descriptors, and set an environment
 1540     // variable telling where to find them, in case a child wants it..
 1541     int stdOutCopy = dup(STDOUT_FILENO);
 1542     int stdErrCopy = dup(STDERR_FILENO);
 1543     // replace STDOUT with our socket, which we'll used to receive the
 1544     // password..
 1545     dup2(fds[0], STDOUT_FILENO);
 1546 
 1547     // ensure that STDOUT_FILENO and stdout/stderr are not closed on exec..
 1548     fcntl(STDOUT_FILENO, F_SETFD, 0);  // don't close on exec..
 1549     fcntl(stdOutCopy, F_SETFD, 0);
 1550     fcntl(stdErrCopy, F_SETFD, 0);
 1551 
 1552     char tmpBuf[8];
 1553 
 1554     setenv(ENCFS_ENV_ROOTDIR, rootDir.c_str(), 1);
 1555 
 1556     snprintf(tmpBuf, sizeof(tmpBuf) - 1, "%i", stdOutCopy);
 1557     setenv(ENCFS_ENV_STDOUT, tmpBuf, 1);
 1558 
 1559     snprintf(tmpBuf, sizeof(tmpBuf) - 1, "%i", stdErrCopy);
 1560     setenv(ENCFS_ENV_STDERR, tmpBuf, 1);
 1561 
 1562     execvp(argv[0], (char *const *)argv);  // returns only on error..
 1563 
 1564     perror(_("Internal error: failed to exec program"));
 1565     exit(1);
 1566   }
 1567 
 1568   close(fds[0]);
 1569   string password = readPassword(fds[1]);
 1570   close(fds[1]);
 1571 
 1572   waitpid(pid, nullptr, 0);
 1573 
 1574   // convert to key..
 1575   result = makeKey(password.c_str(), password.length());
 1576 
 1577   // clear buffer..
 1578   password.assign(password.length(), '\0');
 1579 
 1580   return result;
 1581 }
 1582 
 1583 CipherKey EncFSConfig::getNewUserKey() {
 1584   CipherKey userKey;
 1585   char passBuf[MaxPassBuf];
 1586   char passBuf2[MaxPassBuf];
 1587 
 1588   do {
 1589     // xgroup(common)
 1590     char *res1 = readpassphrase(_("New Encfs Password: "), passBuf,
 1591                                 sizeof(passBuf) - 1, RPP_ECHO_OFF);
 1592     // xgroup(common)
 1593     char *res2 = readpassphrase(_("Verify Encfs Password: "), passBuf2,
 1594                                 sizeof(passBuf2) - 1, RPP_ECHO_OFF);
 1595 
 1596     if ((res1 != nullptr) && (res2 != nullptr) &&
 1597         (strcmp(passBuf, passBuf2) == 0)) {
 1598       userKey = makeKey(passBuf, strlen(passBuf));
 1599     } else {
 1600       // xgroup(common) -- probably not common, but group with the others
 1601       cerr << _("Passwords did not match, please try again\n");
 1602     }
 1603 
 1604     memset(passBuf, 0, sizeof(passBuf));
 1605     memset(passBuf2, 0, sizeof(passBuf2));
 1606   } while (!userKey);
 1607 
 1608   return userKey;
 1609 }
 1610 
 1611 RootPtr initFS(EncFS_Context *ctx, const std::shared_ptr<EncFS_Opts> &opts) {
 1612   RootPtr rootInfo;
 1613   std::shared_ptr<EncFSConfig> config(new EncFSConfig);
 1614 
 1615   if (readConfig(opts->rootDir, config.get(), opts->config) != Config_None) {
 1616     if (config->blockMACBytes == 0 && opts->requireMac) {
 1617       cout << _(
 1618           "The configuration disabled MAC, but you passed --require-macs\n");
 1619       return rootInfo;
 1620     }
 1621 
 1622     if (opts->reverseEncryption) {
 1623       if (config->blockMACBytes != 0 || config->blockMACRandBytes != 0 ||
 1624           config->externalIVChaining || config->chainedNameIV) {
 1625         cout << _(
 1626             "The configuration loaded is not compatible with --reverse\n");
 1627         return rootInfo;
 1628       }
 1629       /* If uniqueIV is off, writing can be allowed, because there
 1630        * is no header that could be overwritten.
 1631        * So if it is on, enforce readOnly. */
 1632       if (config->uniqueIV) {
 1633         opts->readOnly = true;
 1634       }
 1635     }
 1636 
 1637     // first, instanciate the cipher.
 1638     std::shared_ptr<Cipher> cipher = config->getCipher();
 1639     if (!cipher) {
 1640       cerr << autosprintf(
 1641           _("Unable to find cipher %s, version %i:%i:%i"),
 1642           config->cipherIface.name().c_str(), config->cipherIface.current(),
 1643           config->cipherIface.revision(), config->cipherIface.age());
 1644       // xgroup(diag)
 1645       cout << _("The requested cipher interface is not available\n");
 1646       return rootInfo;
 1647     }
 1648 
 1649     if (opts->delayMount) {
 1650       rootInfo = std::make_shared<encfs::EncFS_Root>();
 1651       rootInfo->cipher = cipher;
 1652       rootInfo->root = std::shared_ptr<DirNode>();
 1653       return rootInfo;
 1654     }
 1655 
 1656     // get user key
 1657     CipherKey userKey;
 1658 
 1659     if (opts->passwordProgram.empty()) {
 1660       VLOG(1) << "useStdin: " << opts->useStdin;
 1661       if (opts->annotate) {
 1662         cerr << "$PROMPT$ passwd" << endl;
 1663       }
 1664       userKey = config->getUserKey(opts->useStdin);
 1665     } else {
 1666       userKey = config->getUserKey(opts->passwordProgram, opts->rootDir);
 1667     }
 1668 
 1669     if (!userKey) {
 1670       return rootInfo;
 1671     }
 1672 
 1673     VLOG(1) << "cipher key size = " << cipher->encodedKeySize();
 1674     // decode volume key..
 1675     CipherKey volumeKey =
 1676         cipher->readKey(config->getKeyData(), userKey, opts->checkKey);
 1677     userKey.reset();
 1678 
 1679     if (!volumeKey) {
 1680       // xgroup(diag)
 1681       cout << _("Error decoding volume key, password incorrect\n");
 1682       return rootInfo;
 1683     }
 1684 
 1685     std::shared_ptr<NameIO> nameCoder =
 1686         NameIO::New(config->nameIface, cipher, volumeKey);
 1687     if (!nameCoder) {
 1688       cerr << autosprintf(
 1689           _("Unable to find nameio interface '%s', version %i:%i:%i"),
 1690           config->nameIface.name().c_str(), config->nameIface.current(),
 1691           config->nameIface.revision(), config->nameIface.age());
 1692       // xgroup(diag)
 1693       cout << _(
 1694           "The requested filename coding interface is "
 1695           "not available\n");
 1696       return rootInfo;
 1697     }
 1698 
 1699     nameCoder->setChainedNameIV(config->chainedNameIV);
 1700     nameCoder->setReverseEncryption(opts->reverseEncryption);
 1701 
 1702     FSConfigPtr fsConfig(new FSConfig);
 1703     if (config->plainData) {
 1704       if (! opts->insecure) {
 1705         cout << _("Configuration use plainData but you did not use --insecure\n");
 1706         return rootInfo;
 1707       }
 1708       static Interface NullInterface("nullCipher", 1, 0, 0);
 1709       fsConfig->cipher = Cipher::New(NullInterface, 0);
 1710     }
 1711     else {
 1712       fsConfig->cipher = cipher;
 1713     }
 1714     fsConfig->key = volumeKey;
 1715     fsConfig->nameCoding = nameCoder;
 1716     fsConfig->config = config;
 1717     fsConfig->forceDecode = opts->forceDecode;
 1718     fsConfig->reverseEncryption = opts->reverseEncryption;
 1719     fsConfig->opts = opts;
 1720 
 1721     rootInfo = std::make_shared<encfs::EncFS_Root>();
 1722     rootInfo->cipher = cipher;
 1723     rootInfo->volumeKey = volumeKey;
 1724     rootInfo->root = std::make_shared<DirNode>(ctx, opts->rootDir, fsConfig);
 1725   } else {
 1726     if (opts->createIfNotFound) {
 1727       // creating a new encrypted filesystem
 1728       rootInfo = createV6Config(ctx, opts);
 1729     }
 1730   }
 1731 
 1732   return rootInfo;
 1733 }
 1734 
 1735 void unmountFS(const char *mountPoint) {
 1736   // fuse_unmount returns void, is assumed to succeed
 1737   fuse_unmount(mountPoint, nullptr);
 1738 #ifdef __APPLE__
 1739   // fuse_unmount does not work on Mac OS, see #428
 1740   // However it makes encfs to hang, so we must unmount
 1741   if (unmount(mountPoint, MNT_FORCE) != 0) {
 1742     int eno = errno;
 1743     if (eno != EINVAL) { //[EINVAL] The requested directory is not in the mount table.
 1744       RLOG(ERROR) << "Filesystem unmount failed: " << strerror(eno);
 1745     }
 1746   }
 1747 #endif
 1748 #ifdef __CYGWIN__
 1749   pid_t pid;
 1750   int status;
 1751   if ((pid = fork()) == 0) {
 1752     execl("/bin/pkill", "/bin/pkill", "-INT", "-if", string("(^|/)encfs .*(/|.:).* ").append(mountPoint).append("( |$)").c_str(), (char *)0);
 1753     int eno = errno;
 1754     RLOG(ERROR) << "Filesystem unmount failed: " << strerror(eno);
 1755     _Exit(127);
 1756   }
 1757   if (pid > 0) {
 1758     waitpid(pid, &status, 0);
 1759   }
 1760 #endif
 1761 }
 1762 
 1763 int remountFS(EncFS_Context *ctx) {
 1764   VLOG(1) << "Attempting to reinitialize filesystem";
 1765 
 1766   RootPtr rootInfo = initFS(ctx, ctx->opts);
 1767   if (rootInfo) {
 1768     ctx->setRoot(rootInfo->root);
 1769     return 0;
 1770   }
 1771   RLOG(WARNING) << "Remount failed";
 1772   return -EACCES;
 1773 }
 1774 
 1775 bool unmountFS(EncFS_Context *ctx) {
 1776   if (ctx->opts->mountOnDemand) {
 1777     VLOG(1) << "Detaching filesystem due to inactivity: "
 1778             << ctx->opts->unmountPoint;
 1779 
 1780     ctx->setRoot(std::shared_ptr<DirNode>());
 1781     return false;
 1782   }
 1783   // Time to unmount!
 1784   RLOG(INFO) << "Filesystem inactive, unmounting: " << ctx->opts->unmountPoint;
 1785   unmountFS(ctx->opts->unmountPoint.c_str());
 1786   return true;
 1787 }
 1788 
 1789 }  // namespace encfs