Exemple #1
0
static int selectBlockSize(const CipherV1::CipherAlgorithm &alg) {
  if (alg.blockSize.min() == alg.blockSize.max()) {
    cout << autosprintf(
                // xgroup(setup)
                _("Using filesystem block size of %i bytes"),
                alg.blockSize.min()) << "\n";
    return alg.blockSize.min();
  }

  cout << autosprintf(
              // xgroup(setup)
              _("Select a block size in bytes.  The cipher you have chosen\n"
                "supports sizes from %i to %i bytes in increments of %i.\n"
                "Or just hit enter for the default (%i bytes)\n"),
              alg.blockSize.min(), alg.blockSize.max(), alg.blockSize.inc(),
              DefaultBlockSize);

  // xgroup(setup)
  cout << "\n" << _("filesystem block size: ");

  int blockSize = DefaultBlockSize;
  char answer[10];
  char *res = fgets(answer, sizeof(answer), stdin);
  cout << "\n";

  if (res != 0 && atoi(answer) >= alg.blockSize.min()) blockSize = atoi(answer);

  blockSize = alg.blockSize.closest(blockSize);

  // xgroup(setup)
  cout << autosprintf(_("Using filesystem block size of %i bytes"), blockSize)
       << "\n\n";

  return blockSize;
}
Exemple #2
0
int main(int argc, char **argv) {
  encfs::init_mpool_mutex();
  
  START_EASYLOGGINGPP(argc, argv);
  encfs::initLogging();

#if defined(ENABLE_NLS) && defined(LOCALEDIR)
  setlocale(LC_ALL, "");
  bindtextdomain(PACKAGE, LOCALEDIR);
  textdomain(PACKAGE);
#endif

  SSL_load_error_strings();
  SSL_library_init();

  if (argc < 2) {
    usage(argv[0]);
    return EXIT_FAILURE;
  }

  // Skip over uninteresting args.
  while (argc > 2 && *argv[1] == '-') {
    VLOG(1) << "skipping arg " << argv[1];
    argc--;
    argv[1] = argv[0];
    argv++;
  }

  if (argc == 2 && !(*argv[1] == '-' && *(argv[1] + 1) == '-')) {
    // default command when only 1 argument given -- treat the argument as
    // a directory..
    return showInfo(argc, argv);
  } else {
    // find the specified command
    int offset = 0;
    while (commands[offset].name != 0) {
      if (!strcmp(argv[1], commands[offset].name)) break;
      ++offset;
    }

    if (commands[offset].name == 0) {
      cerr << autosprintf(_("invalid command: \"%s\""), argv[1]) << "\n";
    } else {
      if ((argc - 2 < commands[offset].minOptions) ||
          (argc - 2 > commands[offset].maxOptions)) {
        cerr << autosprintf(
                    _("Incorrect number of arguments for command \"%s\""),
                    argv[1])
             << "\n";
      } else
        return (*commands[offset].func)(argc - 1, argv + 1);
    }
  }

  return EXIT_FAILURE;
}
Exemple #3
0
static
int selectKeySize( const CipherV1::CipherAlgorithm &alg )
{
  if(alg.keyLength.min() == alg.keyLength.max())
  {
    cout << autosprintf(_("Using key size of %i bits"), 
        alg.keyLength.min()) << "\n";
    return alg.keyLength.min();
  }

  cout << autosprintf(
      // xgroup(setup)
      _("Please select a key size in bits.  The cipher you have chosen\n"
        "supports sizes from %i to %i bits in increments of %i bits.\n"
        "For example: "), alg.keyLength.min(), alg.keyLength.max(), 
      alg.keyLength.inc()) << "\n";

  int numAvail = (alg.keyLength.max() - alg.keyLength.min()) 
    / alg.keyLength.inc();

  if(numAvail < 5)
  {
    // show them all
    for(int i=0; i<=numAvail; ++i)
    {
      if(i) 
        cout << ", ";
      cout << alg.keyLength.min() + i * alg.keyLength.inc();
    }
  } else
  {
    // partial
    for(int i=0; i<3; ++i)
    {
      if(i) 
        cout << ", ";
      cout << alg.keyLength.min() + i * alg.keyLength.inc();
    }
    cout << " ... " << alg.keyLength.max() - alg.keyLength.inc();
    cout << ", " << alg.keyLength.max();
  }
  // xgroup(setup)
  cout << "\n" << _("Selected key size: ");

  char answer[10];
  char *res = fgets( answer, sizeof(answer), stdin );
  int keySize = (res == 0 ? 0 : atoi( answer ));
  cout << "\n";

  keySize = alg.keyLength.closest( keySize );

  // xgroup(setup)
  cout << autosprintf(_("Using key size of %i bits"), keySize) << "\n\n";

  return keySize;
}
Exemple #4
0
static int showInfo(int argc, char **argv) {
  (void)argc;
  string rootDir = argv[1];
  if (!checkDir(rootDir)) return EXIT_FAILURE;

  shared_ptr<EncFSConfig> config(new EncFSConfig);
  ConfigType type = readConfig(rootDir, config);

  // show information stored in config..
  switch (type) {
    case Config_None:
      // xgroup(diag)
      cout << _("Unable to load or parse config file\n");
      return EXIT_FAILURE;
    case Config_Prehistoric:
      // xgroup(diag)
      cout << _(
          "A really old EncFS filesystem was found. \n"
          "It is not supported in this EncFS build.\n");
      return EXIT_FAILURE;
    case Config_V3:
      // xgroup(diag)
      cout << "\n" << autosprintf(_("Version 3 configuration; "
                                    "created by %s\n"),
                                  config->creator.c_str());
      break;
    case Config_V4:
      // xgroup(diag)
      cout << "\n" << autosprintf(_("Version 4 configuration; "
                                    "created by %s\n"),
                                  config->creator.c_str());
      break;
    case Config_V5:
      // xgroup(diag)
      cout << "\n" << autosprintf(_("Version 5 configuration; "
                                    "created by %s (revision %i)\n"),
                                  config->creator.c_str(), config->subVersion);
      break;
    case Config_V6:
      // xgroup(diag)
      cout << "\n" << autosprintf(_("Version 6 configuration; "
                                    "created by %s (revision %i)\n"),
                                  config->creator.c_str(), config->subVersion);
      break;
  }

  showFSInfo(config);

  return EXIT_SUCCESS;
}
Exemple #5
0
int main(int argc, char **argv) {
  RLogInit(argc, argv);

#if defined(ENABLE_NLS) && defined(LOCALEDIR)
  setlocale(LC_ALL, "");
  bindtextdomain(PACKAGE, LOCALEDIR);
  textdomain(PACKAGE);
#endif

  SSL_load_error_strings();
  SSL_library_init();

  StdioNode *slog = new StdioNode(STDERR_FILENO);
  slog->subscribeTo(GetGlobalChannel("error"));
  slog->subscribeTo(GetGlobalChannel("warning"));

  if (argc < 2) {
    usage(argv[0]);
    return EXIT_FAILURE;
  }

  if (argc == 2 && !(*argv[1] == '-' && *(argv[1] + 1) == '-')) {
    // default command when only 1 argument given -- treat the argument as
    // a directory..
    return showInfo(argc, argv);
  } else {
    // find the specified command
    int offset = 0;
    while (commands[offset].name != 0) {
      if (!strcmp(argv[1], commands[offset].name)) break;
      ++offset;
    }

    if (commands[offset].name == 0) {
      cerr << autosprintf(_("invalid command: \"%s\""), argv[1]) << "\n";
    } else {
      if ((argc - 2 < commands[offset].minOptions) ||
          (argc - 2 > commands[offset].maxOptions)) {
        cerr << autosprintf(
                    _("Incorrect number of arguments for command \"%s\""),
                    argv[1]) << "\n";
      } else
        return (*commands[offset].func)(argc - 1, argv + 1);
    }
  }

  return EXIT_FAILURE;
}
Exemple #6
0
bool userAllowMkdir(int promptno, const char *path, mode_t mode) {
  // TODO: can we internationalize the y/n names?  Seems strange to prompt in
  // their own language but then have to respond 'y' or 'n'.
  // xgroup(setup)
  cerr << autosprintf(_("The directory \"%s\" does not exist. "
                        "Should it be created? (y,n) "),
                      path);
  char answer[10];
  char *res;

  switch (promptno) {
    case 1:
      cerr << endl << "$PROMPT$ create_root_dir" << endl;
      break;
    case 2:
      cerr << endl << "$PROMPT$ create_mount_point" << endl;
      break;
    default:
      break;
  }
  res = fgets(answer, sizeof(answer), stdin);

  if (res != 0 && toupper(answer[0]) == 'Y') {
    int result = mkdir(path, mode);
    if (result < 0) {
      perror(_("Unable to create directory: "));
      return false;
    } else
      return true;
  } else {
    // Directory not created, by user request
    cerr << _("Directory not created.") << "\n";
    return false;
  }
}
Exemple #7
0
static int showVersion(int argc, char **argv) {
  (void)argc;
  (void)argv;
  // xgroup(usage)
  cerr << autosprintf(_("encfsctl version %s"), VERSION) << "\n";

  return EXIT_SUCCESS;
}
Exemple #8
0
static bool checkDir(string &rootDir) {
  if (!isDirectory(rootDir.c_str())) {
    cerr << autosprintf(_("directory %s does not exist.\n"), rootDir.c_str());
    return false;
  }
  if (rootDir[rootDir.length() - 1] != '/') rootDir.append("/");

  return true;
}
Exemple #9
0
static void usage(const char *name) {
  // xgroup(usage)
  cerr << autosprintf(_("Build: encfs version %s"), VERSION) << "\n\n"
       // xgroup(usage)
       << autosprintf(
              _("Usage: %s [options] rootDir mountPoint [-- [FUSE Mount "
                "Options]]"),
              name) << "\n\n"
       // xgroup(usage)
       << _("Common Options:\n"
            "  -H\t\t\t"
            "show optional FUSE Mount Options\n"
            "  -s\t\t\t"
            "disable multithreaded operation\n"
            "  -f\t\t\t"
            "run in foreground (don't spawn daemon).\n"
            "\t\t\tError messages will be sent to stderr\n"
            "\t\t\tinstead of syslog.\n")

       // xgroup(usage)
       << _("  -v, --verbose\t\t"
            "verbose: output encfs debug messages\n"
            "  -i, --idle=MINUTES\t"
            "Auto unmount after period of inactivity\n"
            "  --anykey\t\t"
            "Do not verify correct key is being used\n"
            "  --forcedecode\t\t"
            "decode data even if an error is detected\n"
            "\t\t\t(for filesystems using MAC block headers)\n")
       << _("  --public\t\t"
            "act as a typical multi-user filesystem\n"
            "\t\t\t(encfs must be run as root)\n") << _("  --reverse\t\t"
                                                        "reverse encryption\n")

       // xgroup(usage)
       << _("  --extpass=program\tUse external program for password prompt\n"
            "\n"
            "Example, to mount at ~/crypt with raw storage in ~/.crypt :\n"
            "    encfs ~/.crypt ~/crypt\n"
            "\n")
       // xgroup(usage)
       << _("For more information, see the man page encfs(1)") << "\n" << endl;
}
Exemple #10
0
static int selectKDFDuration() {
  cout << autosprintf(_("Select desired KDF duration in milliseconds.\n"
                        "The default is 500 (half a second): "));

  char answer[10];
  char *res = fgets( answer, sizeof(answer), stdin );
  int duration = (res == 0 ? 0 : atoi( answer ));
  cout << "\n";

  return duration;
}
Exemple #11
0
static void usage(const char *name) {
  cerr << autosprintf(_("encfsctl version %s"), VERSION) << "\n"
       << _("Usage:\n")
       // displays usage commands, eg "./encfs (root dir) ..."
       // xgroup(usage)
       << autosprintf(
              _("%s (root dir)\n"
                "  -- displays information about the filesystem, or \n"),
              name);

  int offset = 0;
  while (commands[offset].name != 0) {
    if (commands[offset].argStr != 0) {
      cerr << "encfsctl " << commands[offset].name << " "
           << commands[offset].argStr << "\n"
           << gettext(commands[offset].usageStr) << "\n";
    }
    ++offset;
  }

  cerr << "\n"
       // xgroup(usage)
       << autosprintf(_("Example: \n%s info ~/.crypt\n"), name) << "\n";
}
Exemple #12
0
/*
    iterate recursively through the filesystem and print out names of files
    which have filenames which cannot be decoded with the given key..
*/
static int cmd_showcruft(int argc, char **argv) {
  (void)argc;

  RootPtr rootInfo = initRootInfo(argv[1]);

  if (!rootInfo) return EXIT_FAILURE;

  int filesFound = showcruft(rootInfo, "/");

  // TODO: the singular version should say "Found an invalid file", but all the
  // translations
  // depend upon this broken singular form, so it isn't easy to change.
  cerr << autosprintf(ngettext("Found %i invalid file.",
                               "Found %i invalid files.", filesFound),
                      filesFound) << "\n";

  return EXIT_SUCCESS;
}
Exemple #13
0
static
Interface selectNameCoding(const CipherV1::CipherAlgorithm &alg)
{
  for(;;)
  {
    // figure out what cipher they want to use..
    // xgroup(setup)
    cout << _("The following filename encoding algorithms are available:")
      << "\n";
    NameIO::AlgorithmList algorithms = NameIO::GetAlgorithmList();
    NameIO::AlgorithmList::const_iterator it;
    int optNum = 1;
    map<int, NameIO::AlgorithmList::const_iterator> algMap;
    for(it = algorithms.begin(); it != algorithms.end(); ++it)
    {
      cout << optNum << ". " << it->name
        << " : " << gettext(it->description.c_str()) << "\n";
      algMap[optNum++] = it;
    }

    // xgroup(setup)
    cout << "\n" << _("Enter the number corresponding to your choice: ");
    char answer[10];
    char *res = fgets( answer, sizeof(answer), stdin );
    int algNum = (res == 0 ? 0 : atoi( answer ));
    cout << "\n";

    if( algNum < 1 || algNum >= optNum )
    {
      cerr << _("Invalid selection.") << "\n";
      continue;
    }

    it = algMap[algNum];

    // xgroup(setup)
    cout << autosprintf(_("Selected algorithm \"%s\""), it->name.c_str()) 
      << "\"\n\n";

    return it->iface;
  }
}
Exemple #14
0
int showcruft(const std::shared_ptr<EncFS_Root> &rootInfo,
              const char *dirName) {
  int found = 0;
  DirTraverse dt = rootInfo->root->openDir(dirName);
  if (dt.valid()) {
    bool showedDir = false;
    for (string name = dt.nextInvalid(); !name.empty();
         name = dt.nextInvalid()) {
      string cpath = rootInfo->root->cipherPath(dirName);
      cpath += '/';
      cpath += name;

      if (!showedDir) {
        // just before showing a list of files in a directory
        cout << autosprintf(_("In directory %s: \n"), dirName);
        showedDir = true;
      }
      ++found;
      cout << cpath << "\n";
    }

    // now go back and look for directories to recurse into..
    dt = rootInfo->root->openDir(dirName);
    if (dt.valid()) {
      for (string name = dt.nextPlaintextName(); !name.empty();
           name = dt.nextPlaintextName()) {
        if (name == "." || name == "..") continue;

        string plainPath = dirName;
        plainPath += '/';
        plainPath += name;

        string cpath = rootInfo->root->cipherPath(plainPath.c_str());

        if (isDirectory(cpath.c_str()))
          found += showcruft(rootInfo, plainPath.c_str());
      }
    }
  }

  return found;
}
Exemple #15
0
static int do_chpasswd(bool useStdin, bool annotate, int argc, char **argv) {
  (void)argc;
  string rootDir = argv[1];
  if (!checkDir(rootDir)) return EXIT_FAILURE;

  shared_ptr<EncFSConfig> config(new EncFSConfig);
  ConfigType cfgType = readConfig(rootDir, config);

  if (cfgType == Config_None) {
    cout << _("Unable to load or parse config file\n");
    return EXIT_FAILURE;
  }

  // instanciate proper cipher
  shared_ptr<Cipher> cipher = Cipher::New(config->cipherIface, config->keySize);
  if (!cipher) {
    cout << autosprintf(_("Unable to find specified cipher \"%s\"\n"),
                        config->cipherIface.name().c_str());
    return EXIT_FAILURE;
  }

  // ask for existing password
  cout << _("Enter current Encfs password\n");
  if (annotate) cerr << "$PROMPT$ passwd" << endl;
  CipherKey userKey = config->getUserKey(useStdin);
  if (!userKey) return EXIT_FAILURE;

  // decode volume key using user key -- at this point we detect an incorrect
  // password if the key checksum does not match (causing readKey to fail).
  CipherKey volumeKey = cipher->readKey(config->getKeyData(), userKey);

  if (!volumeKey) {
    cout << _("Invalid password\n");
    return EXIT_FAILURE;
  }

  // Now, get New user key..
  userKey.reset();
  cout << _("Enter new Encfs password\n");
  // reinitialize salt and iteration count
  config->kdfIterations = 0;  // generate new

  if (useStdin) {
    if (annotate) cerr << "$PROMPT$ new_passwd" << endl;
    userKey = config->getUserKey(true);
  } else
    userKey = config->getNewUserKey();

  // re-encode the volume key using the new user key and write it out..
  int result = EXIT_FAILURE;
  if (userKey) {
    int encodedKeySize = cipher->encodedKeySize();
    unsigned char *keyBuf = new unsigned char[encodedKeySize];

    // encode volume key with new user key
    cipher->writeKey(volumeKey, keyBuf, userKey);
    userKey.reset();

    config->assignKeyData(keyBuf, encodedKeySize);
    delete[] keyBuf;

    if (saveConfig(cfgType, rootDir, config)) {
      // password modified -- changes volume key of filesystem..
      cout << _("Volume Key successfully updated.\n");
      result = EXIT_SUCCESS;
    } else {
      cout << _("Error saving modified config file.\n");
    }
  } else {
    cout << _("Error creating key\n");
  }

  volumeKey.reset();

  return result;
}
Exemple #16
0
static 
bool processArgs(int argc, char *argv[], const shared_ptr<EncFS_Args> &out)
{
  // set defaults
  out->isDaemon = true;
  out->isThreaded = true;
  out->isVerbose = false;
  out->idleTimeout = 0;
  out->fuseArgc = 0;
  out->opts->idleTracking = false;
  out->opts->checkKey = true;
  out->opts->forceDecode = false;
  out->opts->ownerCreate = false;
  out->opts->useStdin = false;
  out->opts->annotate = false;
  out->opts->reverseEncryption = false;

  bool useDefaultFlags = true;

  // pass executable name through
  out->fuseArgv[0] = lastPathElement(argv[0]);
  ++out->fuseArgc;

  // leave a space for mount point, as FUSE expects the mount point before
  // any flags
  out->fuseArgv[1] = NULL;
  ++out->fuseArgc;

  // TODO: can flags be internationalized?
  static struct option long_options[] = {
    {"fuse-debug", 0, 0, 'd'}, // Fuse debug mode
    {"forcedecode", 0, 0, 'D'}, // force decode
    // {"foreground", 0, 0, 'f'}, // foreground mode (no daemon)
    {"fuse-help", 0, 0, 'H'}, // fuse_mount usage
    {"idle", 1, 0, 'i'}, // idle timeout
    {"anykey", 0, 0, 'k'}, // skip key checks
    {"no-default-flags", 0, 0, 'N'}, // don't use default fuse flags
    {"ondemand", 0, 0, 'm'}, // mount on-demand
    {"public", 0, 0, 'P'}, // public mode
    {"extpass", 1, 0, 'p'}, // external password program
    // {"single-thread", 0, 0, 's'}, // single-threaded mode
    {"stdinpass", 0, 0, 'S'}, // read password from stdin
    {"annotate", 0, 0, 513}, // Print annotation lines to stderr
    {"verbose", 0, 0, 'v'}, // verbose mode
    {"version", 0, 0, 'V'}, //version
    {"reverse", 0, 0, 'r'}, // reverse encryption
    {"standard", 0, 0, '1'},  // standard configuration
    {"paranoia", 0, 0, '2'},  // standard configuration
    {0,0,0,0}
  };

  while (1)
  {
    int option_index = 0;

    // 's' : single-threaded mode
    // 'f' : foreground mode
    // 'v' : verbose mode (same as --verbose)
    // 'd' : fuse debug mode (same as --fusedebug)
    // 'i' : idle-timeout, takes argument
    // 'm' : mount-on-demand
    // 'S' : password from stdin
    // 'o' : arguments meant for fuse
    int res = getopt_long( argc, argv, "HsSfvVdmi:o:",
        long_options, &option_index);

    if(res == -1)
      break;

    switch( res )
    {
    case '1':
      out->opts->configMode = Config_Standard;
      break;
    case '2':
      out->opts->configMode = Config_Paranoia;
      break;
    case 's':
      out->isThreaded = false;
      break;
    case 'S':
      out->opts->useStdin = true;
      break;
    case 513:
      out->opts->annotate = true;
      break;
    case 'f':
      out->isDaemon = false;
      // this option was added in fuse 2.x
      PUSHARG("-f");
      break;
    case 'v':
      out->isVerbose = true;
      break;
    case 'd':
      PUSHARG("-d");
      break;
    case 'i':
      out->idleTimeout = strtol( optarg, (char**)NULL, 10);
      out->opts->idleTracking = true;
      break;
    case 'k':
      out->opts->checkKey = false;
      break;
    case 'D':
      out->opts->forceDecode = true;
      break;
    case 'r':
      out->opts->reverseEncryption = true;	    
      break;
    case 'm':
      out->opts->mountOnDemand = true;
      break;
    case 'N':
      useDefaultFlags = false;
      break;
    case 'o':
      PUSHARG("-o");
      PUSHARG( optarg );
      break;
    case 'p':
      out->opts->passwordProgram.assign( optarg );
      break;
    case 'P':
      if(geteuid() != 0)
        LOG(WARNING) << "option '--public' ignored for non-root user";
      else
      {
        out->opts->ownerCreate = true;
        // add 'allow_other' option
        // add 'default_permissions' option (default)
        PUSHARG("-o");
        PUSHARG("allow_other");
      }
      break;
    case 'V':
      // xgroup(usage)
      cerr << autosprintf(_("encfs version %s"), VERSION) << endl;
      exit(EXIT_SUCCESS);
      break;
    case 'H':
      FuseUsage();
      exit(EXIT_SUCCESS);
      break;
    case '?':
      // invalid options..
      break;
    case ':':
      // missing parameter for option..
      break;
    default:
      LOG(WARNING) << "getopt error: " << res;
      break;
    }
  }

  if(!out->isThreaded)
    PUSHARG("-s");

  if(useDefaultFlags)
  {
    PUSHARG("-o");
    PUSHARG("use_ino");
    PUSHARG("-o");
    PUSHARG("default_permissions");
  }

  // we should have at least 2 arguments left over - the source directory and
  // the mount point.
  if(optind+2 <= argc)
  {
    out->opts->rootDir = slashTerminate( argv[optind++] );
    out->mountPoint = argv[optind++];
  } else
  {
    // no mount point specified
    LOG(ERROR) << "Missing one or more arguments, aborting.";
    return false;
  }

  // If there are still extra unparsed arguments, pass them onto FUSE..
  if(optind < argc)
  {
    rAssert(out->fuseArgc < MaxFuseArgs);

    while(optind < argc)
    {
      rAssert(out->fuseArgc < MaxFuseArgs);
      out->fuseArgv[out->fuseArgc++] = argv[optind];
      ++optind;
    }
  }

  // sanity check
  if(out->isDaemon && 
      (!isAbsolutePath( out->mountPoint.c_str() ) ||
       !isAbsolutePath( out->opts->rootDir.c_str() ) ) 
    )
  {
    cerr << 
      // xgroup(usage)
      _("When specifying daemon mode, you must use absolute paths "
          "(beginning with '/')")
      << endl;
    return false;
  }

  // the raw directory may not be a subdirectory of the mount point.
  {
    string testMountPoint = slashTerminate( out->mountPoint );
    string testRootDir = 
      out->opts->rootDir.substr(0, testMountPoint.length());

    if( testMountPoint == testRootDir )
    {
      cerr << 
        // xgroup(usage)
        _("The raw directory may not be a subdirectory of the "
            "mount point.") << endl;
      return false;
    }
  }

  if(out->opts->mountOnDemand && out->opts->passwordProgram.empty())
  {
    cerr << 
      // xgroup(usage)
      _("Must set password program when using mount-on-demand")
      << endl;
    return false;
  }

  // check that the directories exist, or that we can create them..
  if(!isDirectory( out->opts->rootDir.c_str() ) && 
      !userAllowMkdir( out->opts->annotate? 1:0,
        out->opts->rootDir.c_str() ,0700))
  {
    LOG(WARNING) << "Unable to locate root directory, aborting.";
    return false;
  }
  if(!isDirectory( out->mountPoint.c_str() ) && 
      !userAllowMkdir( out->opts->annotate? 2:0,
        out->mountPoint.c_str(),0700))
  {
    LOG(WARNING) << "Unable to locate mount point, aborting.";
    return false;
  }

  // fill in mount path for fuse
  out->fuseArgv[1] = out->mountPoint.c_str();

  return true;
}
Exemple #17
0
void showFSInfo( const EncfsConfig &config )
{
  shared_ptr<CipherV1> cipher = CipherV1::New( config.cipher(), 
        config.key().size() );
  {
    cout << autosprintf(
        // xgroup(diag)
        _("Filesystem cipher: \"%s\", version %i:%i:%i"),
        config.cipher().name().c_str(), config.cipher().major(),
        config.cipher().minor(), config.cipher().age());
    // check if we support this interface..
    if(!cipher)
      cout << _(" (NOT supported)\n");
    else
    {
      // if we're using a newer interface, show the version number
      if( config.cipher() != cipher->interface() )
      {
        Interface iface = cipher->interface();
        // xgroup(diag)
        cout << autosprintf(_(" (using %i:%i:%i)\n"),
            iface.major(), iface.minor(), iface.age());
      } else
        cout << "\n";
    }
  }

  // xgroup(diag)
  cout << autosprintf(_("Filename encoding: \"%s\", version %i:%i:%i"),
          config.naming().name().c_str(), config.naming().major(),
          config.naming().minor(), config.naming().age());
    
  if (!cipher)
  {
      cout <<  "\n";
  } else
  {
    // check if we support the filename encoding interface..
    shared_ptr<NameIO> nameCoder = NameIO::New( config.naming(), cipher );
    if(!nameCoder)
    {
      // xgroup(diag)
      cout << _(" (NOT supported)\n");
    } else
    {
      // if we're using a newer interface, show the version number
      if( config.naming() != nameCoder->interface() )
      {
        Interface iface = nameCoder->interface();
        cout << autosprintf(_(" (using %i:%i:%i)\n"),
            iface.major(), iface.minor(), iface.age());
      } else
        cout << "\n";
    }
  }
  const EncryptedKey &key = config.key();
  {
    cout << autosprintf(_("Key Size: %i bits"), 8 * key.size());
    cipher = getCipher(config);
    if(!cipher)
    {
      // xgroup(diag)
      cout << _(" (NOT supported)\n");
    } else
      cout << "\n";
  }
  if(key.kdf_iterations() > 0 && key.salt().size() > 0)
  {
    cout << autosprintf(_("Using PBKDF2, with %i iterations"), 
        key.kdf_iterations()) << "\n";
    cout << autosprintf(_("Salt Size: %i bits"), 
        8*(int)key.salt().size()) << "\n";
  }
  if(config.block_mac_bytes() || config.block_mac_rand_bytes())
  {
    if(config.revision() < V5Latest)
    {
      cout << autosprintf(
          // xgroup(diag)
          _("Block Size: %i bytes + %i byte MAC header"),
          config.block_size(),
          config.block_mac_bytes() + config.block_mac_rand_bytes()) << endl;
    } else
    {
      // new version stores the header as part of that block size..
      cout << autosprintf(
          // xgroup(diag)
          _("Block Size: %i bytes, including %i byte MAC header"),
          config.block_size(),
          config.block_mac_bytes() + config.block_mac_rand_bytes()) << endl;
    }
  } else
  {
    // xgroup(diag)
    cout << autosprintf(_("Block Size: %i bytes"), config.block_size());
    cout << "\n";
  }

  if(config.unique_iv())
  {
    // xgroup(diag)
    cout << _("Each file contains 8 byte header with unique IV data.\n");
  }
  if(config.chained_iv())
  {
    // xgroup(diag)
    cout << _("Filenames encoded using IV chaining mode.\n");
  }
  if(config.external_iv())
  {
    // xgroup(diag)
    cout << _("File data IV is chained to filename IV.\n");
  }
  if(config.allow_holes())
  {
    // xgroup(diag)
    cout << _("File holes passed through to ciphertext.\n");
  }
  cout << "\n";
}
Exemple #18
0
static
CipherV1::CipherAlgorithm selectCipherAlgorithm()
{
  for(;;)
  {
    // figure out what cipher they want to use..
    // xgroup(setup)
    cout << _("The following cipher algorithms are available:") << "\n";
    int optNum = 0;
    auto algorithms = CipherV1::GetAlgorithmList();
    for (auto &it : algorithms)
    {
      cout << ++optNum << ". " << it.name
        << " : " << gettext(it.description.c_str()) << "\n";
      if(it.keyLength.min() == it.keyLength.max())
      {
        // shown after algorithm name and description.
        // xgroup(setup)
        cout << autosprintf(_(" -- key length %i bits")
            , it.keyLength.min()) << "\n";
      } else
      {
        cout << autosprintf(
            // shown after algorithm name and description.
            // xgroup(setup)
            _(" -- Supports key lengths of %i to %i bits"),
            it.keyLength.min(), it.keyLength.max()) << "\n";
      }

      if(it.blockSize.min() == it.blockSize.max())
      {
        cout << autosprintf(
            // shown after algorithm name and description.
            // xgroup(setup)
            _(" -- block size %i bytes"), it.blockSize.min()) 
          << "\n";
      } else
      {
        cout << autosprintf(
            // shown after algorithm name and description.
            // xgroup(setup)
            _(" -- Supports block sizes of %i to %i bytes"),
            it.blockSize.min(), it.blockSize.max()) << "\n";
      }
    }

    // xgroup(setup)
    cout << "\n" << _("Enter the number corresponding to your choice: ");
    char answer[10];
    char *res = fgets( answer, sizeof(answer), stdin );
    int cipherNum = (res == 0 ? 0 : atoi( answer ));
    cout << "\n";

    if( cipherNum < 1 || cipherNum > (int)algorithms.size() )
    {
      cerr << _("Invalid selection.") << "\n";
      continue;
    }

    CipherV1::CipherAlgorithm alg;
    for (auto &it : algorithms) 
    {
      if (!--cipherNum)
      {
        alg = it;
        break;
      }
    }

    // xgroup(setup)
    cout << autosprintf(_("Selected algorithm \"%s\""), alg.name.c_str()) 
      << "\n\n";

    return alg;
  }
}
Exemple #19
0
static bool processArgs(int argc, char *argv[],
                        const shared_ptr<EncFS_Args> &out) {
  // set defaults
  out->isDaemon = true;
  out->isThreaded = true;
  out->isVerbose = false;
  out->idleTimeout = 0;
  out->fuseArgc = 0;
  out->opts->idleTracking = false;
  out->opts->checkKey = true;
  out->opts->forceDecode = false;
  out->opts->ownerCreate = false;
  out->opts->useStdin = false;
  out->opts->annotate = false;
  out->opts->reverseEncryption = false;

  bool useDefaultFlags = true;

  // pass executable name through
  out->fuseArgv[0] = lastPathElement(argv[0]);
  ++out->fuseArgc;

  // leave a space for mount point, as FUSE expects the mount point before
  // any flags
  out->fuseArgv[1] = NULL;
  ++out->fuseArgc;

  // TODO: can flags be internationalized?
  static struct option long_options[] = {
      {"fuse-debug", 0, 0, 'd'},   // Fuse debug mode
      {"forcedecode", 0, 0, 'D'},  // force decode
      // {"foreground", 0, 0, 'f'}, // foreground mode (no daemon)
      {"fuse-help", 0, 0, 'H'},         // fuse_mount usage
      {"idle", 1, 0, 'i'},              // idle timeout
      {"anykey", 0, 0, 'k'},            // skip key checks
      {"no-default-flags", 0, 0, 'N'},  // don't use default fuse flags
      {"ondemand", 0, 0, 'm'},          // mount on-demand
      {"delaymount", 0, 0, 'M'},        // delay initial mount until use
      {"public", 0, 0, 'P'},            // public mode
      {"extpass", 1, 0, 'p'},           // external password program
      // {"single-thread", 0, 0, 's'}, // single-threaded mode
      {"stdinpass", 0, 0, 'S'},  // read password from stdin
      {"annotate", 0, 0, 513},   // Print annotation lines to stderr
      {"nocache", 0, 0, 514},    // disable caching
      {"verbose", 0, 0, 'v'},    // verbose mode
      {"version", 0, 0, 'V'},    // version
      {"reverse", 0, 0, 'r'},    // reverse encryption
      {"standard", 0, 0, '1'},   // standard configuration
      {"paranoia", 0, 0, '2'},   // standard configuration
      {0, 0, 0, 0}};

  while (1) {
    int option_index = 0;

    // 's' : single-threaded mode
    // 'f' : foreground mode
    // 'v' : verbose mode (same as --verbose)
    // 'd' : fuse debug mode (same as --fusedebug)
    // 'i' : idle-timeout, takes argument
    // 'm' : mount-on-demand
    // 'S' : password from stdin
    // 'o' : arguments meant for fuse
    int res =
        getopt_long(argc, argv, "HsSfvdmi:o:", long_options, &option_index);

    if (res == -1) break;

    switch (res) {
      case '1':
        out->opts->configMode = Config_Standard;
        break;
      case '2':
        out->opts->configMode = Config_Paranoia;
        break;
      case 's':
        out->isThreaded = false;
        break;
      case 'S':
        out->opts->useStdin = true;
        break;
      case 513:
        out->opts->annotate = true;
        break;
      case 'f':
        out->isDaemon = false;
        // this option was added in fuse 2.x
        PUSHARG("-f");
        break;
      case 'v':
        out->isVerbose = true;
        break;
      case 'd':
        PUSHARG("-d");
        break;
      case 'i':
        out->idleTimeout = strtol(optarg, (char **)NULL, 10);
        out->opts->idleTracking = true;
        break;
      case 'k':
        out->opts->checkKey = false;
        break;
      case 'D':
        out->opts->forceDecode = true;
        break;
      case 'r':
        out->opts->reverseEncryption = true;
        /* Reverse encryption does not support writing unless uniqueIV
         * is disabled (expert mode) */
        out->opts->readOnly = true;
        /* By default, the kernel caches file metadata for one second.
         * This is fine for EncFS' normal mode, but for --reverse, this
         * means that the encrypted view will be up to one second out of
         * date.
         * Quoting Goswin von Brederlow:
         * "Caching only works correctly if you implement a disk based
         * filesystem, one where only the fuse process can alter
         * metadata and all access goes only through fuse. Any overlay
         * filesystem where something can change the underlying
         * filesystem without going through fuse can run into
         * inconsistencies."
         * Enabling reverse automatically enables noCache */
      case 514:
        /* Disable EncFS block cache
         * Causes reverse grow tests to fail because short reads
         * are returned */
        out->opts->noCache = true;
        /* Disable kernel stat() cache
         * Causes reverse grow tests to fail because stale stat() data
         * is returned */
        PUSHARG("-oattr_timeout=0");
        /* Disable kernel dentry cache
         * Fallout unknown, disabling for safety */
        PUSHARG("-oentry_timeout=0");
        break;
      case 'm':
        out->opts->mountOnDemand = true;
        break;
      case 'M':
        out->opts->delayMount = true;
        break;
      case 'N':
        useDefaultFlags = false;
        break;
      case 'o':
        PUSHARG("-o");
        PUSHARG(optarg);
        break;
      case 'p':
        out->opts->passwordProgram.assign(optarg);
        break;
      case 'P':
        if (geteuid() != 0)
          rWarning(_("option '--public' ignored for non-root user"));
        else {
          out->opts->ownerCreate = true;
          // add 'allow_other' option
          // add 'default_permissions' option (default)
          PUSHARG("-o");
          PUSHARG("allow_other");
        }
        break;
      case 'V':
        // xgroup(usage)
        cerr << autosprintf(_("encfs version %s"), VERSION) << endl;
        exit(EXIT_SUCCESS);
        break;
      case 'H':
        FuseUsage();
        exit(EXIT_SUCCESS);
        break;
      case '?':
        // invalid options..
        break;
      case ':':
        // missing parameter for option..
        break;
      default:
        rWarning(_("getopt error: %i"), res);
        break;
    }
  }

  if (!out->isThreaded) PUSHARG("-s");

  if (useDefaultFlags) {
    PUSHARG("-o");
    PUSHARG("use_ino");
    PUSHARG("-o");
    PUSHARG("default_permissions");
  }

  // we should have at least 2 arguments left over - the source directory and
  // the mount point.
  if (optind + 2 <= argc) {
    out->opts->rootDir = slashTerminate(argv[optind++]);
    out->mountPoint = argv[optind++];
  } else {
    // no mount point specified
    rWarning(_("Missing one or more arguments, aborting."));
    return false;
  }

  // If there are still extra unparsed arguments, pass them onto FUSE..
  if (optind < argc) {
    rAssert(out->fuseArgc < MaxFuseArgs);

    while (optind < argc) {
      rAssert(out->fuseArgc < MaxFuseArgs);
      out->fuseArgv[out->fuseArgc++] = argv[optind];
      ++optind;
    }
  }

  // sanity check
  if (out->isDaemon && (!isAbsolutePath(out->mountPoint.c_str()) ||
                        !isAbsolutePath(out->opts->rootDir.c_str()))) {
    cerr <<
        // xgroup(usage)
        _("When specifying daemon mode, you must use absolute paths "
          "(beginning with '/')") << endl;
    return false;
  }

  // the raw directory may not be a subdirectory of the mount point.
  {
    string testMountPoint = slashTerminate(out->mountPoint);
    string testRootDir = out->opts->rootDir.substr(0, testMountPoint.length());

    if (testMountPoint == testRootDir) {
      cerr <<
          // xgroup(usage)
          _("The raw directory may not be a subdirectory of the "
            "mount point.") << endl;
      return false;
    }
  }

  if (out->opts->delayMount && !out->opts->mountOnDemand) {
    cerr <<
        // xgroup(usage)
        _("You must use mount-on-demand with delay-mount") << endl;
    return false;
  }

  if (out->opts->mountOnDemand && out->opts->passwordProgram.empty()) {
    cerr <<
        // xgroup(usage)
        _("Must set password program when using mount-on-demand") << endl;
    return false;
  }

  // check that the directories exist, or that we can create them..
  if (!isDirectory(out->opts->rootDir.c_str()) &&
      !userAllowMkdir(out->opts->annotate ? 1 : 0, out->opts->rootDir.c_str(),
                      0700)) {
    rWarning(_("Unable to locate root directory, aborting."));
    return false;
  }
  if (!isDirectory(out->mountPoint.c_str()) &&
      !userAllowMkdir(out->opts->annotate ? 2 : 0, out->mountPoint.c_str(),
                      0700)) {
    rWarning(_("Unable to locate mount point, aborting."));
    return false;
  }

  // fill in mount path for fuse
  out->fuseArgv[1] = out->mountPoint.c_str();

  return true;
}