Example #1
0
// pathfsFrontend - initialize gocryptfs/pathfs_frontend
// Calls os.Exit on errors
func pathfsFrontend(key []byte, args argContainer, confFile *cryptfs.ConfFile) *fuse.Server {

	// Reconciliate CLI and config file arguments into a Args struct that is passed to the
	// filesystem implementation
	frontendArgs := pathfs_frontend.Args{
		Cipherdir:      args.cipherdir,
		Masterkey:      key,
		OpenSSL:        args.openssl,
		PlaintextNames: args.plaintextnames,
		DirIV:          args.diriv,
		EMENames:       args.emenames,
		GCMIV128:       args.gcmiv128,
	}
	// 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(cryptfs.FlagPlaintextNames)
		frontendArgs.DirIV = confFile.IsFeatureFlagSet(cryptfs.FlagDirIV)
		frontendArgs.EMENames = confFile.IsFeatureFlagSet(cryptfs.FlagEMENames)
		frontendArgs.GCMIV128 = confFile.IsFeatureFlagSet(cryptfs.FlagGCMIV128)
	}
	// EMENames implies DirIV, both on the command line and in the config file.
	if frontendArgs.EMENames {
		frontendArgs.DirIV = true
	}
	// PlainTexnames disables both EMENames and DirIV
	if frontendArgs.PlaintextNames {
		frontendArgs.DirIV = false
		frontendArgs.EMENames = false
	}
	cryptfs.Debug.Printf("frontendArgs: ")
	cryptfs.Debug.JSONDump(frontendArgs)

	finalFs := pathfs_frontend.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
	// 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"

	srv, err := fuse.NewServer(conn.RawFS(), args.mountpoint, &mOpts)
	if err != nil {
		fmt.Printf("Mount failed: %v", err)
		os.Exit(ERREXIT_MOUNT)
	}
	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
}
Example #2
0
func main() {
	runtime.GOMAXPROCS(4)

	// Parse command line arguments
	var debug, init, zerokey, fusedebug, openssl, passwd, foreground, version bool
	var masterkey, mountpoint, cipherdir string

	flag.Usage = usageText
	flag.BoolVar(&debug, "debug", false, "Enable debug output")
	flag.BoolVar(&fusedebug, "fusedebug", false, "Enable fuse library debug output")
	flag.BoolVar(&init, "init", false, "Initialize encrypted directory")
	flag.BoolVar(&zerokey, "zerokey", false, "Use all-zero dummy master key")
	flag.BoolVar(&openssl, "openssl", true, "Use OpenSSL instead of built-in Go crypto")
	flag.BoolVar(&passwd, "passwd", false, "Change password")
	flag.BoolVar(&foreground, "f", false, "Stay in the foreground")
	flag.BoolVar(&version, "version", false, "Print version and exit")
	flag.StringVar(&masterkey, "masterkey", "", "Mount with explicit master key")
	var cpuprofile = flag.String("cpuprofile", "", "Write cpu profile to specified file")

	flag.Parse()
	if version {
		fmt.Printf("%s %s; ", PROGRAM_NAME, GitVersion)
		fmt.Printf("on-disk format %d\n", cryptfs.HEADER_CURRENT_VERSION)
		os.Exit(0)
	}
	if !foreground {
		daemonize() // does not return
	}
	if *cpuprofile != "" {
		f, err := os.Create(*cpuprofile)
		if err != nil {
			fmt.Println(err)
			os.Exit(ERREXIT_INIT)
		}
		fmt.Printf("Writing CPU profile to %s\n", *cpuprofile)
		pprof.StartCPUProfile(f)
		defer pprof.StopCPUProfile()
	}
	if debug {
		cryptfs.Debug.Enable()
		cryptfs.Debug.Printf("Debug output enabled\n")
	}
	if openssl == false {
		fmt.Printf("Openssl disabled\n")
	}
	if init {
		if flag.NArg() != 1 {
			fmt.Printf("Usage: %s --init CIPHERDIR\n", PROGRAM_NAME)
			os.Exit(ERREXIT_USAGE)
		}
		initDir(flag.Arg(0)) // does not return
	}
	if passwd {
		if flag.NArg() != 1 {
			fmt.Printf("Usage: %s --passwd CIPHERDIR\n", PROGRAM_NAME)
			os.Exit(ERREXIT_USAGE)
		}
	} else {
		// Normal mount
		if flag.NArg() < 2 {
			usageText()
			os.Exit(ERREXIT_USAGE)
		}
		mountpoint, _ = filepath.Abs(flag.Arg(1))
		err := checkDirEmpty(mountpoint)
		if err != nil {
			fmt.Printf("Invalid MOUNTPOINT: %v\n", err)
			os.Exit(ERREXIT_MOUNTPOINT)
		}
	}
	cipherdir, _ = filepath.Abs(flag.Arg(0))
	err := checkDir(cipherdir)
	if err != nil {
		fmt.Printf("Invalid CIPHERDIR: %v\n", err)
		os.Exit(ERREXIT_CIPHERDIR)
	}

	var cf *cryptfs.ConfFile
	var currentPassword string
	key := make([]byte, cryptfs.KEY_LEN)
	if zerokey {
		fmt.Printf("Zerokey mode active: using all-zero dummy master key.\n")
	} else if len(masterkey) > 0 {
		key = parseMasterKey(masterkey)
		fmt.Printf("Using explicit master key.\n")
	} else {
		cfname := filepath.Join(cipherdir, cryptfs.ConfDefaultName)
		_, err = os.Stat(cfname)
		if err != nil {
			fmt.Printf("Error: %s not found in CIPHERDIR\n", cryptfs.ConfDefaultName)
			fmt.Printf("Please run \"%s --init %s\" first\n", os.Args[0], flag.Arg(0))
			os.Exit(ERREXIT_LOADCONF)
		}
		if passwd == true {
			fmt.Printf("Old password: "******"Password: "******"\nDecrypting master key... ")
		cryptfs.Warn.Disable() // Silence DecryptBlock() error messages on incorrect password
		key, cf, err = cryptfs.LoadConfFile(cfname, currentPassword)
		cryptfs.Warn.Enable()
		if err != nil {
			fmt.Println(err)
			os.Exit(ERREXIT_LOADCONF)
		}
		fmt.Printf("done.\n")
	}
	if passwd == true {
		fmt.Printf("Please enter the new password.\n")
		newPassword := readPasswordTwice()
		if newPassword == currentPassword {
			fmt.Printf("New and old passwords are identical\n")
			os.Exit(ERREXIT_PASSWORD)
		}
		cf.EncryptKey(key, newPassword)
		err := cf.WriteFile()
		if err != nil {
			fmt.Println(err)
			os.Exit(ERREXIT_INIT)
		}
		fmt.Printf("Password changed.\n")
		os.Exit(0)
	}

	srv := pathfsFrontend(key, cipherdir, mountpoint, fusedebug, openssl)

	if zerokey == false && len(masterkey) == 0 {
		printMasterKey(key)
	} else if zerokey == true {
		fmt.Printf("ZEROKEY MODE PROVIDES NO SECURITY AT ALL AND SHOULD ONLY BE USED FOR TESTING.\n")
	} else if len(masterkey) > 0 {
		fmt.Printf("THE MASTER KEY IS VISIBLE VIA \"ps -auxwww\", ONLY USE THIS MODE FOR EMERGENCIES.\n")
	}

	fmt.Println("Filesystem ready.")
	// Send notification to our parent
	sendUsr1()
	// Wait for SIGING in the background and unmount ourselves if we get it
	// This prevents a dangling "Transport endpoint is not connected" mountpoint
	handleSigint(srv, mountpoint)
	// Jump into server loop. Returns when it gets an umount request from the kernel.
	srv.Serve()
	// main returns with code 0
}