diff options
| author | Jakob Unterwurzacher | 2016-10-08 18:27:31 +0200 | 
|---|---|---|
| committer | Jakob Unterwurzacher | 2016-10-08 18:43:24 +0200 | 
| commit | 631c538f13997aa8ab4db40c39178a645adf32c3 (patch) | |
| tree | cf304db4b76d1a712bbe9c7eff9f915d6d58c49e | |
| parent | 89bcc50294c765315fafa0d2201edfc59438ff8f (diff) | |
main: split doMount into its own file
Ongoing effort to reduce the size of main().
| -rw-r--r-- | main.go | 210 | ||||
| -rw-r--r-- | mount.go | 221 | 
2 files changed, 224 insertions, 207 deletions
| @@ -1,29 +1,17 @@  package main  import ( -	"encoding/json"  	"fmt" -	"log/syslog"  	"os" -	"os/exec" -	"os/signal" +  	"path/filepath"  	"runtime"  	"runtime/pprof"  	"strconv" -	"strings" -	"syscall"  	"time" -	"github.com/hanwen/go-fuse/fuse" -	"github.com/hanwen/go-fuse/fuse/nodefs" -	"github.com/hanwen/go-fuse/fuse/pathfs" -  	"github.com/rfjakob/gocryptfs/internal/configfile"  	"github.com/rfjakob/gocryptfs/internal/contentenc" -	"github.com/rfjakob/gocryptfs/internal/cryptocore" -	"github.com/rfjakob/gocryptfs/internal/fusefrontend" -	"github.com/rfjakob/gocryptfs/internal/fusefrontend_reverse"  	"github.com/rfjakob/gocryptfs/internal/readpassword"  	"github.com/rfjakob/gocryptfs/internal/stupidgcm"  	"github.com/rfjakob/gocryptfs/internal/tlog" @@ -62,7 +50,7 @@ Options:  	flagSet.PrintDefaults()  } -// loadConfig - load the config file "filename", prompting the user for the password +// loadConfig loads the config file "args.config", prompting the user for the password  func loadConfig(args *argContainer) (masterkey []byte, confFile *configfile.ConfFile) {  	// Check if the file can be opened at all before prompting for a password  	fd, err := os.Open(args.config) @@ -78,7 +66,6 @@ func loadConfig(args *argContainer) (masterkey []byte, confFile *configfile.Conf  		tlog.Fatal.Println(err)  		os.Exit(ErrExitLoadConf)  	} -  	return masterkey, confFile  } @@ -227,196 +214,5 @@ func main() {  		changePassword(&args) // does not return  	}  	// Mount -	// Check mountpoint -	if flagSet.NArg() != 2 { -		tlog.Fatal.Printf("Usage: %s [OPTIONS] CIPHERDIR MOUNTPOINT", tlog.ProgramName) -		os.Exit(ErrExitUsage) -	} -	args.mountpoint, err = filepath.Abs(flagSet.Arg(1)) -	if err != nil { -		tlog.Fatal.Printf("Invalid mountpoint: %v", err) -		os.Exit(ErrExitMountPoint) -	} -	if args.nonempty { -		err = checkDir(args.mountpoint) -	} else { -		err = checkDirEmpty(args.mountpoint) -	} -	if err != nil { -		tlog.Fatal.Printf("Invalid mountpoint: %v", err) -		os.Exit(ErrExitMountPoint) -	} -	// Get master key -	var masterkey []byte -	var confFile *configfile.ConfFile -	if args.masterkey != "" { -		// "-masterkey" -		tlog.Info.Printf("Using explicit master key.") -		masterkey = parseMasterKey(args.masterkey) -		tlog.Info.Printf(tlog.ColorYellow + -			"THE MASTER KEY IS VISIBLE VIA \"ps ax\" AND MAY BE STORED IN YOUR SHELL HISTORY!\n" + -			"ONLY USE THIS MODE FOR EMERGENCIES." + tlog.ColorReset) -	} else if args.zerokey { -		// "-zerokey" -		tlog.Info.Printf("Using all-zero dummy master key.") -		tlog.Info.Printf(tlog.ColorYellow + -			"ZEROKEY MODE PROVIDES NO SECURITY AT ALL AND SHOULD ONLY BE USED FOR TESTING." + -			tlog.ColorReset) -		masterkey = make([]byte, cryptocore.KeyLen) -	} else { -		// Load master key from config file -		masterkey, confFile = loadConfig(&args) -		printMasterKey(masterkey) -	} -	// Initialize FUSE server -	tlog.Debug.Printf("cli args: %v", args) -	srv := initFuseFrontend(masterkey, args, confFile) -	tlog.Info.Println(tlog.ColorGreen + "Filesystem mounted and ready." + tlog.ColorReset) -	// We have been forked into the background, as evidenced by the set -	// "notifypid". -	if args.notifypid > 0 { -		// Chdir to the root directory so we don't block unmounting the CWD -		os.Chdir("/") -		// Switch to syslog -		if !args.nosyslog { -			tlog.Info.SwitchToSyslog(syslog.LOG_USER | syslog.LOG_INFO) -			tlog.Debug.SwitchToSyslog(syslog.LOG_USER | syslog.LOG_DEBUG) -			tlog.Warn.SwitchToSyslog(syslog.LOG_USER | syslog.LOG_WARNING) -			tlog.SwitchLoggerToSyslog(syslog.LOG_USER | syslog.LOG_WARNING) -			// Daemons should close all fds (and we don't want to get killed by -			// SIGPIPE if any of those get closed on the other end) -			os.Stderr.Close() -			os.Stdout.Close() -			os.Stdin.Close() -		} -		// Send SIGUSR1 to our parent -		sendUsr1(args.notifypid) -	} -	// Wait for SIGINT in the background and unmount ourselves if we get it. -	// This prevents a dangling "Transport endpoint is not connected" -	// mountpoint if the user hits CTRL-C. -	handleSigint(srv, args.mountpoint) -	// Jump into server loop. Returns when it gets an umount request from the kernel. -	srv.Serve() -	// main exits with code 0 -} - -// initFuseFrontend - initialize gocryptfs/fusefrontend -// Calls os.Exit on errors -func initFuseFrontend(key []byte, args argContainer, confFile *configfile.ConfFile) *fuse.Server { -	// Reconciliate CLI and config file arguments into a fusefrontend.Args struct -	// that is passed to the filesystem implementation -	cryptoBackend := cryptocore.BackendGoGCM -	if args.openssl { -		cryptoBackend = cryptocore.BackendOpenSSL -	} -	if args.aessiv { -		cryptoBackend = cryptocore.BackendAESSIV -	} -	frontendArgs := fusefrontend.Args{ -		Cipherdir:      args.cipherdir, -		Masterkey:      key, -		PlaintextNames: args.plaintextnames, -		LongNames:      args.longnames, -		CryptoBackend:  cryptoBackend, -	} -	// confFile is nil when "-zerokey" or "-masterkey" was used -	if confFile != nil { -		// Settings from the config file override command line args -		frontendArgs.PlaintextNames = confFile.IsFeatureFlagSet(configfile.FlagPlaintextNames) -		if confFile.IsFeatureFlagSet(configfile.FlagAESSIV) { -			frontendArgs.CryptoBackend = cryptocore.BackendAESSIV -		} else if args.reverse { -			tlog.Fatal.Printf("AES-SIV is required by reverse mode, but not enabled in the config file") -			os.Exit(ErrExitUsage) -		} -	} -	// If allow_other is set and we run as root, try to give newly created files to -	// the right user. -	if args.allow_other && os.Getuid() == 0 { -		frontendArgs.PreserveOwner = true -	} -	jsonBytes, _ := json.MarshalIndent(frontendArgs, "", "\t") -	tlog.Debug.Printf("frontendArgs: %s", string(jsonBytes)) -	var finalFs pathfs.FileSystem -	if args.reverse { -		finalFs = fusefrontend_reverse.NewFS(frontendArgs) -	} else { -		finalFs = fusefrontend.NewFS(frontendArgs) -	} -	pathFsOpts := &pathfs.PathNodeFsOptions{ClientInodes: true} -	pathFs := pathfs.NewPathNodeFs(finalFs, pathFsOpts) -	fuseOpts := &nodefs.Options{ -		// These options are to be compatible with libfuse defaults, -		// making benchmarking easier. -		NegativeTimeout: time.Second, -		AttrTimeout:     time.Second, -		EntryTimeout:    time.Second, -	} -	conn := nodefs.NewFileSystemConnector(pathFs.Root(), fuseOpts) -	var mOpts fuse.MountOptions -	mOpts.AllowOther = false -	if args.allow_other { -		tlog.Info.Printf(tlog.ColorYellow + "The option \"-allow_other\" is set. Make sure the file " + -			"permissions protect your data from unwanted access." + tlog.ColorReset) -		mOpts.AllowOther = true -		// Make the kernel check the file permissions for us -		mOpts.Options = append(mOpts.Options, "default_permissions") -	} -	if args.nonempty { -		mOpts.Options = append(mOpts.Options, "nonempty") -	} -	// Set values shown in "df -T" and friends -	// First column, "Filesystem" -	mOpts.Options = append(mOpts.Options, "fsname="+args.cipherdir) -	// Second column, "Type", will be shown as "fuse." + Name -	mOpts.Name = "gocryptfs" -	if args.reverse { -		mOpts.Name += "-reverse" -	} - -	// The kernel enforces read-only operation, we just have to pass "ro". -	// Reverse mounts are always read-only -	if args.ro || args.reverse { -		mOpts.Options = append(mOpts.Options, "ro") -	} -	// Add additional mount options (if any) after the stock ones, so the user has -	// a chance to override them. -	if args.o != "" { -		parts := strings.Split(args.o, ",") -		tlog.Debug.Printf("Adding -o mount options: %v", parts) -		mOpts.Options = append(mOpts.Options, parts...) -	} -	srv, err := fuse.NewServer(conn.RawFS(), args.mountpoint, &mOpts) -	if err != nil { -		tlog.Fatal.Printf("Mount failed: %v", err) -		os.Exit(ErrExitMount) -	} -	srv.SetDebug(args.fusedebug) - -	// All FUSE file and directory create calls carry explicit permission -	// information. We need an unrestricted umask to create the files and -	// directories with the requested permissions. -	syscall.Umask(0000) - -	return srv -} - -func handleSigint(srv *fuse.Server, mountpoint string) { -	ch := make(chan os.Signal, 1) -	signal.Notify(ch, os.Interrupt) -	signal.Notify(ch, syscall.SIGTERM) -	go func() { -		<-ch -		err := srv.Unmount() -		if err != nil { -			tlog.Warn.Print(err) -			tlog.Info.Printf("Trying lazy unmount") -			cmd := exec.Command("fusermount", "-u", "-z", mountpoint) -			cmd.Stdout = os.Stdout -			cmd.Stderr = os.Stderr -			cmd.Run() -		} -		os.Exit(1) -	}() +	os.Exit(doMount(&args))  } diff --git a/mount.go b/mount.go new file mode 100644 index 0000000..56f1dc1 --- /dev/null +++ b/mount.go @@ -0,0 +1,221 @@ +package main + +import ( +	"encoding/json" +	"log/syslog" +	"os" +	"os/exec" +	"os/signal" +	"path/filepath" +	"strings" +	"syscall" +	"time" + +	"github.com/hanwen/go-fuse/fuse" +	"github.com/hanwen/go-fuse/fuse/nodefs" +	"github.com/hanwen/go-fuse/fuse/pathfs" + +	"github.com/rfjakob/gocryptfs/internal/configfile" +	"github.com/rfjakob/gocryptfs/internal/cryptocore" +	"github.com/rfjakob/gocryptfs/internal/fusefrontend" +	"github.com/rfjakob/gocryptfs/internal/fusefrontend_reverse" +	"github.com/rfjakob/gocryptfs/internal/tlog" +) + +// doMount mounts an encrypted directory. +// Called from main. +func doMount(args *argContainer) int { +	// Check mountpoint +	if flagSet.NArg() != 2 { +		tlog.Fatal.Printf("Usage: %s [OPTIONS] CIPHERDIR MOUNTPOINT", tlog.ProgramName) +		os.Exit(ErrExitUsage) +	} +	var err error +	args.mountpoint, err = filepath.Abs(flagSet.Arg(1)) +	if err != nil { +		tlog.Fatal.Printf("Invalid mountpoint: %v", err) +		os.Exit(ErrExitMountPoint) +	} +	if args.nonempty { +		err = checkDir(args.mountpoint) +	} else { +		err = checkDirEmpty(args.mountpoint) +	} +	if err != nil { +		tlog.Fatal.Printf("Invalid mountpoint: %v", err) +		os.Exit(ErrExitMountPoint) +	} +	// Get master key +	var masterkey []byte +	var confFile *configfile.ConfFile +	if args.masterkey != "" { +		// "-masterkey" +		tlog.Info.Printf("Using explicit master key.") +		masterkey = parseMasterKey(args.masterkey) +		tlog.Info.Printf(tlog.ColorYellow + +			"THE MASTER KEY IS VISIBLE VIA \"ps ax\" AND MAY BE STORED IN YOUR SHELL HISTORY!\n" + +			"ONLY USE THIS MODE FOR EMERGENCIES." + tlog.ColorReset) +	} else if args.zerokey { +		// "-zerokey" +		tlog.Info.Printf("Using all-zero dummy master key.") +		tlog.Info.Printf(tlog.ColorYellow + +			"ZEROKEY MODE PROVIDES NO SECURITY AT ALL AND SHOULD ONLY BE USED FOR TESTING." + +			tlog.ColorReset) +		masterkey = make([]byte, cryptocore.KeyLen) +	} else { +		// Load master key from config file +		masterkey, confFile = loadConfig(args) +		printMasterKey(masterkey) +	} +	// Initialize FUSE server +	tlog.Debug.Printf("cli args: %v", args) +	srv := initFuseFrontend(masterkey, args, confFile) +	tlog.Info.Println(tlog.ColorGreen + "Filesystem mounted and ready." + tlog.ColorReset) +	// We have been forked into the background, as evidenced by the set +	// "notifypid". +	if args.notifypid > 0 { +		// Chdir to the root directory so we don't block unmounting the CWD +		os.Chdir("/") +		// Switch to syslog +		if !args.nosyslog { +			tlog.Info.SwitchToSyslog(syslog.LOG_USER | syslog.LOG_INFO) +			tlog.Debug.SwitchToSyslog(syslog.LOG_USER | syslog.LOG_DEBUG) +			tlog.Warn.SwitchToSyslog(syslog.LOG_USER | syslog.LOG_WARNING) +			tlog.SwitchLoggerToSyslog(syslog.LOG_USER | syslog.LOG_WARNING) +			// Daemons should close all fds (and we don't want to get killed by +			// SIGPIPE if any of those get closed on the other end) +			os.Stderr.Close() +			os.Stdout.Close() +			os.Stdin.Close() +		} +		// Send SIGUSR1 to our parent +		sendUsr1(args.notifypid) +	} +	// Wait for SIGINT in the background and unmount ourselves if we get it. +	// This prevents a dangling "Transport endpoint is not connected" +	// mountpoint if the user hits CTRL-C. +	handleSigint(srv, args.mountpoint) +	// Jump into server loop. Returns when it gets an umount request from the kernel. +	srv.Serve() +	return 0 +} + +// initFuseFrontend - initialize gocryptfs/fusefrontend +// Calls os.Exit on errors +func initFuseFrontend(key []byte, args *argContainer, confFile *configfile.ConfFile) *fuse.Server { +	// Reconciliate CLI and config file arguments into a fusefrontend.Args struct +	// that is passed to the filesystem implementation +	cryptoBackend := cryptocore.BackendGoGCM +	if args.openssl { +		cryptoBackend = cryptocore.BackendOpenSSL +	} +	if args.aessiv { +		cryptoBackend = cryptocore.BackendAESSIV +	} +	frontendArgs := fusefrontend.Args{ +		Cipherdir:      args.cipherdir, +		Masterkey:      key, +		PlaintextNames: args.plaintextnames, +		LongNames:      args.longnames, +		CryptoBackend:  cryptoBackend, +	} +	// confFile is nil when "-zerokey" or "-masterkey" was used +	if confFile != nil { +		// Settings from the config file override command line args +		frontendArgs.PlaintextNames = confFile.IsFeatureFlagSet(configfile.FlagPlaintextNames) +		if confFile.IsFeatureFlagSet(configfile.FlagAESSIV) { +			frontendArgs.CryptoBackend = cryptocore.BackendAESSIV +		} else if args.reverse { +			tlog.Fatal.Printf("AES-SIV is required by reverse mode, but not enabled in the config file") +			os.Exit(ErrExitUsage) +		} +	} +	// If allow_other is set and we run as root, try to give newly created files to +	// the right user. +	if args.allow_other && os.Getuid() == 0 { +		frontendArgs.PreserveOwner = true +	} +	jsonBytes, _ := json.MarshalIndent(frontendArgs, "", "\t") +	tlog.Debug.Printf("frontendArgs: %s", string(jsonBytes)) +	var finalFs pathfs.FileSystem +	if args.reverse { +		finalFs = fusefrontend_reverse.NewFS(frontendArgs) +	} else { +		finalFs = fusefrontend.NewFS(frontendArgs) +	} +	pathFsOpts := &pathfs.PathNodeFsOptions{ClientInodes: true} +	pathFs := pathfs.NewPathNodeFs(finalFs, pathFsOpts) +	fuseOpts := &nodefs.Options{ +		// These options are to be compatible with libfuse defaults, +		// making benchmarking easier. +		NegativeTimeout: time.Second, +		AttrTimeout:     time.Second, +		EntryTimeout:    time.Second, +	} +	conn := nodefs.NewFileSystemConnector(pathFs.Root(), fuseOpts) +	var mOpts fuse.MountOptions +	mOpts.AllowOther = false +	if args.allow_other { +		tlog.Info.Printf(tlog.ColorYellow + "The option \"-allow_other\" is set. Make sure the file " + +			"permissions protect your data from unwanted access." + tlog.ColorReset) +		mOpts.AllowOther = true +		// Make the kernel check the file permissions for us +		mOpts.Options = append(mOpts.Options, "default_permissions") +	} +	if args.nonempty { +		mOpts.Options = append(mOpts.Options, "nonempty") +	} +	// Set values shown in "df -T" and friends +	// First column, "Filesystem" +	mOpts.Options = append(mOpts.Options, "fsname="+args.cipherdir) +	// Second column, "Type", will be shown as "fuse." + Name +	mOpts.Name = "gocryptfs" +	if args.reverse { +		mOpts.Name += "-reverse" +	} + +	// The kernel enforces read-only operation, we just have to pass "ro". +	// Reverse mounts are always read-only +	if args.ro || args.reverse { +		mOpts.Options = append(mOpts.Options, "ro") +	} +	// Add additional mount options (if any) after the stock ones, so the user has +	// a chance to override them. +	if args.o != "" { +		parts := strings.Split(args.o, ",") +		tlog.Debug.Printf("Adding -o mount options: %v", parts) +		mOpts.Options = append(mOpts.Options, parts...) +	} +	srv, err := fuse.NewServer(conn.RawFS(), args.mountpoint, &mOpts) +	if err != nil { +		tlog.Fatal.Printf("Mount failed: %v", err) +		os.Exit(ErrExitMount) +	} +	srv.SetDebug(args.fusedebug) + +	// All FUSE file and directory create calls carry explicit permission +	// information. We need an unrestricted umask to create the files and +	// directories with the requested permissions. +	syscall.Umask(0000) + +	return srv +} + +func handleSigint(srv *fuse.Server, mountpoint string) { +	ch := make(chan os.Signal, 1) +	signal.Notify(ch, os.Interrupt) +	signal.Notify(ch, syscall.SIGTERM) +	go func() { +		<-ch +		err := srv.Unmount() +		if err != nil { +			tlog.Warn.Print(err) +			tlog.Info.Printf("Trying lazy unmount") +			cmd := exec.Command("fusermount", "-u", "-z", mountpoint) +			cmd.Stdout = os.Stdout +			cmd.Stderr = os.Stderr +			cmd.Run() +		} +		os.Exit(1) +	}() +} | 
