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 <iostream>
#include <list>
#ifdef __APPLE__
#include <sys/mount.h>
#include <sys/param.h>
#endif
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/wait.h>
@ -222,10 +226,19 @@ ConfigType readConfig_load(ConfigInfo *nm, const char *path,
* Try to locate the config file
* 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;
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) {
char *envFile = getenv(nm->environmentOverride);
if (envFile != nullptr) {
@ -433,14 +446,18 @@ bool readV4Config(const char *configFile, EncFSConfig *config,
}
bool saveConfig(ConfigType type, const string &rootDir,
const EncFSConfig *config) {
const EncFSConfig *config, const string &cmdConfig) {
bool ok = false;
ConfigInfo *nm = ConfigFileMapping;
while (nm->fileName != nullptr) {
if (nm->type == type && (nm->saveFunc != nullptr)) {
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..
const char *envFile = getenv(nm->environmentOverride);
if (envFile != nullptr) {
@ -1199,7 +1216,7 @@ RootPtr createV6Config(EncFS_Context *ctx,
return rootInfo;
}
if (!saveConfig(Config_V6, rootDir, config.get())) {
if (!saveConfig(Config_V6, rootDir, config.get(), opts->config)) {
return rootInfo;
}
@ -1559,7 +1576,7 @@ RootPtr initFS(EncFS_Context *ctx, const std::shared_ptr<EncFS_Opts> &opts) {
RootPtr rootInfo;
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) {
cout << _(
"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;
}
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) {
VLOG(1) << "Attempting to reinitialize filesystem";
@ -1690,12 +1716,7 @@ bool unmountFS(EncFS_Context *ctx) {
return false;
}
// Time to unmount!
#if FUSE_USE_VERSION < 30
fuse_unmount(ctx->opts->mountPoint.c_str(), nullptr);
#else
fuse_unmount(fuse_get_context()->fuse);
#endif
// fuse_unmount succeeds and returns void
unmountFS(ctx->opts->mountPoint.c_str());
RLOG(INFO) << "Filesystem inactive, unmounted: " << ctx->opts->mountPoint;
return true;
}

View File

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

View File

@ -16,11 +16,11 @@ encfs - mounts or creates an encrypted virtual filesystem
=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<--reverse>] [B<--reversewrite>] [B<--extpass=program>] [B<-S>|B<--stdinpass>]
[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<-o FUSE_OPTION>] [B<-d>|B<--fuse-debug>] [B<-H>|B<--fuse-help>]
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
additional information.
=item B<-c>, B<--config>
Causes B<EncFS> to use the supplied file as the configuration file.
=item B<-v>, B<--verbose>
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
first use. This option only makes sense with B<--ondemand>.
=item B<-u>, B<--unmount>
Unmounts the specified I<mountPoint>.
=item B<--public>
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;
std::shared_ptr<EncFSConfig> config(new EncFSConfig);
ConfigType type = readConfig(rootDir, config.get());
ConfigType type = readConfig(rootDir, config.get(), "");
// show information stored in config..
switch (type) {
@ -637,7 +637,7 @@ static int do_chpasswd(bool useStdin, bool annotate, bool checkOnly, int argc,
if (!checkDir(rootDir)) return EXIT_FAILURE;
EncFSConfig *config = new EncFSConfig;
ConfigType cfgType = readConfig(rootDir, config);
ConfigType cfgType = readConfig(rootDir, config, "");
if (cfgType == Config_None) {
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);
delete[] keyBuf;
if (saveConfig(cfgType, rootDir, config)) {
if (saveConfig(cfgType, rootDir, config, "")) {
// password modified -- changes volume key of filesystem..
cout << _("Volume Key successfully updated.\n");
result = EXIT_SUCCESS;

View File

@ -162,6 +162,10 @@ static void usage(const char *name) {
"reverse encryption\n")
<< _(" --reversewrite\t\t"
"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)
<< _(" --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->reverseEncryption = false;
out->opts->requireMac = false;
out->opts->unmount = false;
bool useDefaultFlags = true;
@ -255,6 +260,8 @@ static bool processArgs(int argc, char *argv[],
{"standard", 0, nullptr, '1'}, // standard configuration
{"paranoia", 0, nullptr, '2'}, // standard configuration
{"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}};
while (true) {
@ -269,8 +276,10 @@ static bool processArgs(int argc, char *argv[],
// 'S' : password from stdin
// 'o' : arguments meant for fuse
// 't' : syslog tag
// 'c' : configuration file
// 'u' : unmount
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) {
break;
@ -298,6 +307,14 @@ static bool processArgs(int argc, char *argv[],
case LONG_OPT_REQUIRE_MAC:
out->opts->requireMac = true;
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':
out->isDaemon = false;
// this option was added in fuse 2.x
@ -376,7 +393,7 @@ static bool processArgs(int argc, char *argv[],
break;
case 'P':
if (geteuid() != 0) {
RLOG(WARNING) << "option '--public' ignored for non-root user";
cerr << "option '--public' ignored for non-root user";
} else {
out->opts->ownerCreate = true;
// add 'allow_other' option
@ -407,7 +424,7 @@ static bool processArgs(int argc, char *argv[],
// missing parameter for option..
break;
default:
RLOG(WARNING) << "getopt error: " << res;
cerr << "getopt error: " << res;
break;
}
}
@ -416,6 +433,17 @@ static bool processArgs(int argc, char *argv[],
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
// the mount point.
if (optind + 2 <= argc) {
@ -425,7 +453,7 @@ static bool processArgs(int argc, char *argv[],
out->opts->mountPoint = slashTerminate(argv[optind++]);
} else {
// no mount point specified
cerr << _("Missing one or more arguments, aborting.");
cerr << _("Missing one or more arguments, aborting.") << endl;
return false;
}
@ -575,6 +603,13 @@ int main(int argc, char *argv[]) {
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);
ELPP_INITIALIZE_SYSLOG(encfsArgs->syslogTag.c_str(), LOG_PID, LOG_USER);

View File

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

View File

@ -441,8 +441,9 @@ sub create_unmount_remount
# Unmount
portable_unmount($mnt);
# Mount again
system("./build/encfs --extpass=\"echo test\" $crypt $mnt 2>&1");
# Mount again, testing -c as the same time
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;
# Check if content is still there