Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add -c & -u cmdline options #474

Merged
merged 7 commits into from
Mar 17, 2018
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 34 additions & 13 deletions encfs/FileUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -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");
Expand Down Expand Up @@ -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";

Expand All @@ -1689,13 +1715,8 @@ bool unmountFS(EncFS_Context *ctx) {
ctx->setRoot(std::shared_ptr<DirNode>());
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
// Time to unmount!
unmountFS(ctx->opts->mountPoint.c_str());
RLOG(INFO) << "Filesystem inactive, unmounted: " << ctx->opts->mountPoint;
return true;
}
Expand Down
9 changes: 7 additions & 2 deletions encfs/FileUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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;
Expand All @@ -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);

Expand Down
12 changes: 10 additions & 2 deletions encfs/encfs.pod
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down Expand Up @@ -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>.
Expand Down Expand Up @@ -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,
Expand Down
6 changes: 3 additions & 3 deletions encfs/encfsctl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,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) {
Expand Down Expand Up @@ -622,7 +622,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");
Expand Down Expand Up @@ -683,7 +683,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;
Expand Down
43 changes: 39 additions & 4 deletions encfs/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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) {
Expand All @@ -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;
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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;
}
}
Expand All @@ -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) {
Expand All @@ -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;
}

Expand Down Expand Up @@ -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);

Expand Down
8 changes: 1 addition & 7 deletions integration/common.pl
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
5 changes: 3 additions & 2 deletions integration/normal.t.pl
Original file line number Diff line number Diff line change
Expand Up @@ -436,8 +436,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
Expand Down