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 
fileExists(const char * fileName)130 bool fileExists(const char *fileName) {
131   struct stat buf;
132   return lstat(fileName, &buf) == 0;
133 }
134 
isDirectory(const char * fileName)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 
isAbsolutePath(const char * fileName)143 bool isAbsolutePath(const char *fileName) {
144   return (fileName != nullptr) && fileName[0] != '\0' && fileName[0] == '/';
145 }
146 
lastPathElement(const char * name)147 const char *lastPathElement(const char *name) {
148   const char *loc = strrchr(name, '/');
149   return loc != nullptr ? loc + 1 : name;
150 }
151 
parentDirectory(const std::string & path)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 
userAllowMkdir(const char * path,mode_t mode)160 bool userAllowMkdir(const char *path, mode_t mode) {
161   return userAllowMkdir(0, path, mode);
162 }
163 
userAllowMkdir(int promptno,const char * path,mode_t mode)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  */
readConfig_load(ConfigInfo * nm,const char * path,EncFSConfig * config)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  */
readConfig(const string & rootDir,EncFSConfig * config,const string & cmdConfig)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..
readV6Config(const char * configFile,EncFSConfig * cfg,ConfigInfo * info)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  */
readV5Config(const char * configFile,EncFSConfig * config,ConfigInfo * info)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  */
readV4Config(const char * configFile,EncFSConfig * config,ConfigInfo * info)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 
saveConfig(ConfigType type,const string & rootDir,const EncFSConfig * config,const string & cmdConfig)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>
addEl(tinyxml2::XMLDocument & doc,tinyxml2::XMLNode * parent,const char * name,const T & value)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 <>
addEl(tinyxml2::XMLDocument & doc,tinyxml2::XMLNode * parent,const char * name,const Interface & iface)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 <>
addEl(tinyxml2::XMLDocument & doc,tinyxml2::XMLNode * parent,const char * name,const std::vector<unsigned char> & data)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 
writeV6Config(const char * configFile,const EncFSConfig * cfg)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 
writeV5Config(const char * configFile,const EncFSConfig * config)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 
writeV4Config(const char * configFile,const EncFSConfig * config)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 
findCipherAlgorithm(const char * name,int keySize)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  */
selectCipherAlgorithm()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  */
selectNameCoding()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  */
selectKeySize(const Cipher::CipherAlgorithm & alg)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  */
selectBlockSize(const Cipher::CipherAlgorithm & alg)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  */
boolDefault(const char * prompt,bool defaultValue)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 
boolDefaultNo(const char * prompt)872 static bool boolDefaultNo(const char *prompt) {
873   return boolDefault(prompt, false);
874 }
875 
boolDefaultYes(const char * prompt)876 static bool boolDefaultYes(const char *prompt) {
877   return boolDefault(prompt, true);
878 }
879 
880 /**
881  * Ask the user to select plain data
882  */
selectPlainData(bool insecure)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  */
selectBlockMAC(int * macBytes,int * macRandBytes,bool forceMac)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  */
selectUniqueIV(bool default_answer)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  */
selectChainedIV()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  */
selectExternalChainedIV()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  */
selectZeroBlockPassThrough()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 
createV6Config(EncFS_Context * ctx,const std::shared_ptr<EncFS_Opts> & opts)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 
showFSInfo(const EncFSConfig * config)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 }
getCipher() const1395 std::shared_ptr<Cipher> EncFSConfig::getCipher() const {
1396   return Cipher::New(cipherIface, keySize);
1397 }
1398 
assignKeyData(const std::string & in)1399 void EncFSConfig::assignKeyData(const std::string &in) {
1400   keyData.assign(in.data(), in.data() + in.length());
1401 }
1402 
assignKeyData(unsigned char * data,int len)1403 void EncFSConfig::assignKeyData(unsigned char *data, int len) {
1404   keyData.assign(data, data + len);
1405 }
1406 
assignSaltData(unsigned char * data,int len)1407 void EncFSConfig::assignSaltData(unsigned char *data, int len) {
1408   salt.assign(data, data + len);
1409 }
1410 
getKeyData() const1411 unsigned char *EncFSConfig::getKeyData() const {
1412   return const_cast<unsigned char *>(&keyData.front());
1413 }
1414 
getSaltData() const1415 unsigned char *EncFSConfig::getSaltData() const {
1416   return const_cast<unsigned char *>(&salt.front());
1417 }
1418 
makeKey(const char * password,int passwdLen)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 
getUserKey(bool useStdin)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 
readPassword(int FD)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 
getUserKey(const std::string & passProg,const std::string & rootDir)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 
getNewUserKey()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 
initFS(EncFS_Context * ctx,const std::shared_ptr<EncFS_Opts> & opts)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 
unmountFS(const char * mountPoint)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 
remountFS(EncFS_Context * ctx)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 
unmountFS(EncFS_Context * ctx)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
1790