Add -c & -u cmdline options (#474)

This commit is contained in:
Ben RUBSON 2018-03-18 00:14:58 +01:00 committed by GitHub
parent dcf8435d4c
commit 11aec8f28d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 97 additions and 33 deletions

View File

@ -35,6 +35,10 @@
#include <fstream> #include <fstream>
#include <iostream> #include <iostream>
#include <list> #include <list>
#ifdef __APPLE__
#include <sys/mount.h>
#include <sys/param.h>
#endif
#include <sys/socket.h> #include <sys/socket.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/wait.h> #include <sys/wait.h>
@ -222,10 +226,19 @@ ConfigType readConfig_load(ConfigInfo *nm, const char *path,
* Try to locate the config file * Try to locate the config file
* Tries the most recent format first, then looks for older versions * Tries the most recent format first, then looks for older versions
*/ */
ConfigType readConfig(const string &rootDir, EncFSConfig *config) { ConfigType readConfig(const string &rootDir, EncFSConfig *config, const string &cmdConfig) {
ConfigInfo *nm = ConfigFileMapping; ConfigInfo *nm = ConfigFileMapping;
while (nm->fileName != nullptr) { while (nm->fileName != nullptr) {
// allow environment variable to override default config path // allow command line argument to override default config path
if (!cmdConfig.empty()) {
if (!fileExists(cmdConfig.c_str())) {
RLOG(ERROR)
<< "fatal: config file specified on command line does not exist: "
<< cmdConfig;
exit(1);
}
return readConfig_load(nm, cmdConfig.c_str(), config);
} // allow environment variable to override default config path
if (nm->environmentOverride != nullptr) { if (nm->environmentOverride != nullptr) {
char *envFile = getenv(nm->environmentOverride); char *envFile = getenv(nm->environmentOverride);
if (envFile != nullptr) { if (envFile != nullptr) {
@ -433,14 +446,18 @@ bool readV4Config(const char *configFile, EncFSConfig *config,
} }
bool saveConfig(ConfigType type, const string &rootDir, bool saveConfig(ConfigType type, const string &rootDir,
const EncFSConfig *config) { const EncFSConfig *config, const string &cmdConfig) {
bool ok = false; bool ok = false;
ConfigInfo *nm = ConfigFileMapping; ConfigInfo *nm = ConfigFileMapping;
while (nm->fileName != nullptr) { while (nm->fileName != nullptr) {
if (nm->type == type && (nm->saveFunc != nullptr)) { if (nm->type == type && (nm->saveFunc != nullptr)) {
string path = rootDir + nm->fileName; string path = rootDir + nm->fileName;
if (nm->environmentOverride != nullptr) { if (!cmdConfig.empty()) {
// use command line argument if specified
path.assign(cmdConfig);
}
else if (nm->environmentOverride != nullptr) {
// use environment file if specified.. // use environment file if specified..
const char *envFile = getenv(nm->environmentOverride); const char *envFile = getenv(nm->environmentOverride);
if (envFile != nullptr) { if (envFile != nullptr) {
@ -1199,7 +1216,7 @@ RootPtr createV6Config(EncFS_Context *ctx,
return rootInfo; return rootInfo;
} }
if (!saveConfig(Config_V6, rootDir, config.get())) { if (!saveConfig(Config_V6, rootDir, config.get(), opts->config)) {
return rootInfo; return rootInfo;
} }
@ -1559,7 +1576,7 @@ RootPtr initFS(EncFS_Context *ctx, const std::shared_ptr<EncFS_Opts> &opts) {
RootPtr rootInfo; RootPtr rootInfo;
std::shared_ptr<EncFSConfig> config(new EncFSConfig); std::shared_ptr<EncFSConfig> config(new EncFSConfig);
if (readConfig(opts->rootDir, config.get()) != Config_None) { if (readConfig(opts->rootDir, config.get(), opts->config) != Config_None) {
if (config->blockMACBytes == 0 && opts->requireMac) { if (config->blockMACBytes == 0 && opts->requireMac) {
cout << _( cout << _(
"The configuration disabled MAC, but you passed --require-macs\n"); "The configuration disabled MAC, but you passed --require-macs\n");
@ -1669,6 +1686,15 @@ RootPtr initFS(EncFS_Context *ctx, const std::shared_ptr<EncFS_Opts> &opts) {
return rootInfo; return rootInfo;
} }
void unmountFS(const char *mountPoint) {
// fuse_unmount succeeds and returns void
fuse_unmount(mountPoint, nullptr);
#ifdef __APPLE__
// fuse_unmount does not work on Mac OS, see #428
unmount(mountPoint, MNT_FORCE);
#endif
}
int remountFS(EncFS_Context *ctx) { int remountFS(EncFS_Context *ctx) {
VLOG(1) << "Attempting to reinitialize filesystem"; VLOG(1) << "Attempting to reinitialize filesystem";
@ -1689,13 +1715,8 @@ bool unmountFS(EncFS_Context *ctx) {
ctx->setRoot(std::shared_ptr<DirNode>()); ctx->setRoot(std::shared_ptr<DirNode>());
return false; return false;
} }
// Time to unmount! // Time to unmount!
#if FUSE_USE_VERSION < 30 unmountFS(ctx->opts->mountPoint.c_str());
fuse_unmount(ctx->opts->mountPoint.c_str(), nullptr);
#else
fuse_unmount(fuse_get_context()->fuse);
#endif
// fuse_unmount succeeds and returns void
RLOG(INFO) << "Filesystem inactive, unmounted: " << ctx->opts->mountPoint; RLOG(INFO) << "Filesystem inactive, unmounted: " << ctx->opts->mountPoint;
return true; return true;
} }

View File

@ -76,6 +76,7 @@ struct EncFS_Opts {
bool idleTracking; // turn on idle monitoring of filesystem bool idleTracking; // turn on idle monitoring of filesystem
bool mountOnDemand; // mounting on-demand bool mountOnDemand; // mounting on-demand
bool delayMount; // delay initial mount bool delayMount; // delay initial mount
bool unmount; // unmount
bool checkKey; // check crypto key decoding bool checkKey; // check crypto key decoding
bool forceDecode; // force decode on MAC block failures bool forceDecode; // force decode on MAC block failures
@ -98,12 +99,14 @@ struct EncFS_Opts {
bool requireMac; // Throw an error if MAC is disabled bool requireMac; // Throw an error if MAC is disabled
ConfigMode configMode; ConfigMode configMode;
std::string config; // path to configuration file (or empty)
EncFS_Opts() { EncFS_Opts() {
createIfNotFound = true; createIfNotFound = true;
idleTracking = false; idleTracking = false;
mountOnDemand = false; mountOnDemand = false;
delayMount = false; delayMount = false;
unmount = false;
checkKey = true; checkKey = true;
forceDecode = false; forceDecode = false;
useStdin = false; useStdin = false;
@ -120,19 +123,21 @@ struct EncFS_Opts {
/* /*
Read existing config file. Looks for any supported configuration version. Read existing config file. Looks for any supported configuration version.
*/ */
ConfigType readConfig(const std::string &rootDir, EncFSConfig *config); ConfigType readConfig(const std::string &rootDir, EncFSConfig *config, const std::string &cmdConfig);
/* /*
Save the configuration. Saves back as the same configuration type as was Save the configuration. Saves back as the same configuration type as was
read from. read from.
*/ */
bool saveConfig(ConfigType type, const std::string &rootdir, bool saveConfig(ConfigType type, const std::string &rootdir,
const EncFSConfig *config); const EncFSConfig *config, const std::string &cmdConfig);
class EncFS_Context; class EncFS_Context;
RootPtr initFS(EncFS_Context *ctx, const std::shared_ptr<EncFS_Opts> &opts); RootPtr initFS(EncFS_Context *ctx, const std::shared_ptr<EncFS_Opts> &opts);
void unmountFS(const char *mountPoint);
RootPtr createV6Config(EncFS_Context *ctx, RootPtr createV6Config(EncFS_Context *ctx,
const std::shared_ptr<EncFS_Opts> &opts); const std::shared_ptr<EncFS_Opts> &opts);

View File

@ -16,11 +16,11 @@ encfs - mounts or creates an encrypted virtual filesystem
=head1 SYNOPSIS =head1 SYNOPSIS
B<encfs> [B<--version>] [B<-v>|B<--verbose>] [B<-t>|B<--syslogtag>] B<encfs> [B<--version>] [B<-v>|B<--verbose>] [B<-c>|B<--config>] [B<-t>|B<--syslogtag>]
[B<-s>] [B<-f>] [B<--annotate>] [B<--standard>] [B<--paranoia>] [B<-s>] [B<-f>] [B<--annotate>] [B<--standard>] [B<--paranoia>]
[B<--reverse>] [B<--reversewrite>] [B<--extpass=program>] [B<-S>|B<--stdinpass>] [B<--reverse>] [B<--reversewrite>] [B<--extpass=program>] [B<-S>|B<--stdinpass>]
[B<--anykey>] [B<--forcedecode>] [B<-require-macs>] [B<--anykey>] [B<--forcedecode>] [B<-require-macs>]
[B<-i MINUTES>|B<--idle=MINUTES>] [B<-m>|B<--ondemand>] [B<--delaymount>] [B<-i MINUTES>|B<--idle=MINUTES>] [B<-m>|B<--ondemand>] [B<--delaymount>] [B<-u>|B<--unmount>]
[B<--public>] [B<--nocache>] [B<--no-default-flags>] [B<--public>] [B<--nocache>] [B<--no-default-flags>]
[B<-o FUSE_OPTION>] [B<-d>|B<--fuse-debug>] [B<-H>|B<--fuse-help>] [B<-o FUSE_OPTION>] [B<-d>|B<--fuse-debug>] [B<-H>|B<--fuse-help>]
I<rootdir> I<mountPoint> I<rootdir> I<mountPoint>
@ -48,6 +48,10 @@ may be an increasing number of choices.
Shows B<EncFS> version. Using B<--verbose> before B<--version> may display Shows B<EncFS> version. Using B<--verbose> before B<--version> may display
additional information. additional information.
=item B<-c>, B<--config>
Causes B<EncFS> to use the supplied file as the configuration file.
=item B<-v>, B<--verbose> =item B<-v>, B<--verbose>
Causes B<EncFS> to enable logging of various debug channels within B<EncFS>. Causes B<EncFS> to enable logging of various debug channels within B<EncFS>.
@ -204,6 +208,10 @@ password. If this succeeds, then the filesystem becomes available again.
Do not mount the filesystem when encfs starts; instead, delay mounting until Do not mount the filesystem when encfs starts; instead, delay mounting until
first use. This option only makes sense with B<--ondemand>. first use. This option only makes sense with B<--ondemand>.
=item B<-u>, B<--unmount>
Unmounts the specified I<mountPoint>.
=item B<--public> =item B<--public>
Attempt to make encfs behave as a typical multi-user filesystem. By default, Attempt to make encfs behave as a typical multi-user filesystem. By default,

View File

@ -165,7 +165,7 @@ static int showInfo(int argc, char **argv) {
if (!checkDir(rootDir)) return EXIT_FAILURE; if (!checkDir(rootDir)) return EXIT_FAILURE;
std::shared_ptr<EncFSConfig> config(new EncFSConfig); std::shared_ptr<EncFSConfig> config(new EncFSConfig);
ConfigType type = readConfig(rootDir, config.get()); ConfigType type = readConfig(rootDir, config.get(), "");
// show information stored in config.. // show information stored in config..
switch (type) { switch (type) {
@ -637,7 +637,7 @@ static int do_chpasswd(bool useStdin, bool annotate, bool checkOnly, int argc,
if (!checkDir(rootDir)) return EXIT_FAILURE; if (!checkDir(rootDir)) return EXIT_FAILURE;
EncFSConfig *config = new EncFSConfig; EncFSConfig *config = new EncFSConfig;
ConfigType cfgType = readConfig(rootDir, config); ConfigType cfgType = readConfig(rootDir, config, "");
if (cfgType == Config_None) { if (cfgType == Config_None) {
cout << _("Unable to load or parse config file\n"); cout << _("Unable to load or parse config file\n");
@ -698,7 +698,7 @@ static int do_chpasswd(bool useStdin, bool annotate, bool checkOnly, int argc,
config->assignKeyData(keyBuf, encodedKeySize); config->assignKeyData(keyBuf, encodedKeySize);
delete[] keyBuf; delete[] keyBuf;
if (saveConfig(cfgType, rootDir, config)) { if (saveConfig(cfgType, rootDir, config, "")) {
// password modified -- changes volume key of filesystem.. // password modified -- changes volume key of filesystem..
cout << _("Volume Key successfully updated.\n"); cout << _("Volume Key successfully updated.\n");
result = EXIT_SUCCESS; result = EXIT_SUCCESS;

View File

@ -162,6 +162,10 @@ static void usage(const char *name) {
"reverse encryption\n") "reverse encryption\n")
<< _(" --reversewrite\t\t" << _(" --reversewrite\t\t"
"reverse encryption with writes enabled\n") "reverse encryption with writes enabled\n")
<< _(" -c, --config=path\t\t"
"specifies config file (overrides ENV variable)\n")
<< _(" -u, --unmount\t\t"
"unmounts specified mountPoint\n")
// xgroup(usage) // xgroup(usage)
<< _(" --extpass=program\tUse external program for password prompt\n" << _(" --extpass=program\tUse external program for password prompt\n"
@ -217,6 +221,7 @@ static bool processArgs(int argc, char *argv[],
out->opts->annotate = false; out->opts->annotate = false;
out->opts->reverseEncryption = false; out->opts->reverseEncryption = false;
out->opts->requireMac = false; out->opts->requireMac = false;
out->opts->unmount = false;
bool useDefaultFlags = true; bool useDefaultFlags = true;
@ -255,6 +260,8 @@ static bool processArgs(int argc, char *argv[],
{"standard", 0, nullptr, '1'}, // standard configuration {"standard", 0, nullptr, '1'}, // standard configuration
{"paranoia", 0, nullptr, '2'}, // standard configuration {"paranoia", 0, nullptr, '2'}, // standard configuration
{"require-macs", 0, nullptr, LONG_OPT_REQUIRE_MAC}, // require MACs {"require-macs", 0, nullptr, LONG_OPT_REQUIRE_MAC}, // require MACs
{"config", 1, nullptr, 'c'}, // command-line-supplied config location
{"unmount", 1, nullptr, 'u'}, // unmount
{nullptr, 0, nullptr, 0}}; {nullptr, 0, nullptr, 0}};
while (true) { while (true) {
@ -269,8 +276,10 @@ static bool processArgs(int argc, char *argv[],
// 'S' : password from stdin // 'S' : password from stdin
// 'o' : arguments meant for fuse // 'o' : arguments meant for fuse
// 't' : syslog tag // 't' : syslog tag
// 'c' : configuration file
// 'u' : unmount
int res = int res =
getopt_long(argc, argv, "HsSfvdmi:o:t:", long_options, &option_index); getopt_long(argc, argv, "HsSfvdmi:o:t:c:u", long_options, &option_index);
if (res == -1) { if (res == -1) {
break; break;
@ -298,6 +307,14 @@ static bool processArgs(int argc, char *argv[],
case LONG_OPT_REQUIRE_MAC: case LONG_OPT_REQUIRE_MAC:
out->opts->requireMac = true; out->opts->requireMac = true;
break; break;
case 'c':
/* Take config file path from command
* line instead of ENV variable */
out->opts->config.assign(optarg);
break;
case 'u':
out->opts->unmount = true;
break;
case 'f': case 'f':
out->isDaemon = false; out->isDaemon = false;
// this option was added in fuse 2.x // this option was added in fuse 2.x
@ -376,7 +393,7 @@ static bool processArgs(int argc, char *argv[],
break; break;
case 'P': case 'P':
if (geteuid() != 0) { if (geteuid() != 0) {
RLOG(WARNING) << "option '--public' ignored for non-root user"; cerr << "option '--public' ignored for non-root user";
} else { } else {
out->opts->ownerCreate = true; out->opts->ownerCreate = true;
// add 'allow_other' option // add 'allow_other' option
@ -407,7 +424,7 @@ static bool processArgs(int argc, char *argv[],
// missing parameter for option.. // missing parameter for option..
break; break;
default: default:
RLOG(WARNING) << "getopt error: " << res; cerr << "getopt error: " << res;
break; break;
} }
} }
@ -416,6 +433,17 @@ static bool processArgs(int argc, char *argv[],
PUSHARG("-s"); PUSHARG("-s");
} }
// for --unmount, we should have exactly 1 argument - the mount point
if (out->opts->unmount) {
if (optind + 1 == argc) {
out->opts->mountPoint = slashTerminate(argv[optind++]);
return true;
}
// no mount point specified
cerr << _("Expecting one argument, aborting.") << endl;
return false;
}
// we should have at least 2 arguments left over - the source directory and // we should have at least 2 arguments left over - the source directory and
// the mount point. // the mount point.
if (optind + 2 <= argc) { if (optind + 2 <= argc) {
@ -425,7 +453,7 @@ static bool processArgs(int argc, char *argv[],
out->opts->mountPoint = slashTerminate(argv[optind++]); out->opts->mountPoint = slashTerminate(argv[optind++]);
} else { } else {
// no mount point specified // no mount point specified
cerr << _("Missing one or more arguments, aborting."); cerr << _("Missing one or more arguments, aborting.") << endl;
return false; return false;
} }
@ -575,6 +603,13 @@ int main(int argc, char *argv[]) {
return EXIT_FAILURE; return EXIT_FAILURE;
} }
// Let's unmount if requested
if (encfsArgs->opts->unmount) {
unmountFS(encfsArgs->opts->mountPoint.c_str());
cout << "Filesystem unmounting: " << encfsArgs->opts->mountPoint << endl;
return 0;
}
encfs::initLogging(encfsArgs->isVerbose, encfsArgs->isDaemon); encfs::initLogging(encfsArgs->isVerbose, encfsArgs->isDaemon);
ELPP_INITIALIZE_SYSLOG(encfsArgs->syslogTag.c_str(), LOG_PID, LOG_USER); ELPP_INITIALIZE_SYSLOG(encfsArgs->syslogTag.c_str(), LOG_PID, LOG_USER);

View File

@ -2,13 +2,7 @@
# works on Linux AND OSX # works on Linux AND OSX
sub portable_unmount { sub portable_unmount {
my $crypt = shift; my $crypt = shift;
my $fusermount = qx(which fusermount); qx(./build/encfs -u "$crypt" >/dev/null);
chomp($fusermount);
if(-f $fusermount) {
qx($fusermount -u "$crypt");
} else {
qx(umount "$crypt");
}
} }
# Helper function # Helper function

View File

@ -441,8 +441,9 @@ sub create_unmount_remount
# Unmount # Unmount
portable_unmount($mnt); portable_unmount($mnt);
# Mount again # Mount again, testing -c as the same time
system("./build/encfs --extpass=\"echo test\" $crypt $mnt 2>&1"); rename("$crypt/.encfs6.xml", "$crypt/.encfs6_moved.xml");
system("./build/encfs -c $crypt/.encfs6_moved.xml --extpass=\"echo test\" $crypt $mnt 2>&1");
ok( $? == 0, "encfs command returns 0") || return; ok( $? == 0, "encfs command returns 0") || return;
# Check if content is still there # Check if content is still there