aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJakob Unterwurzacher2015-11-15 13:38:19 +0100
committerJakob Unterwurzacher2015-11-15 13:42:04 +0100
commitd95fc2333aa5c05de713694c0893c7690655a584 (patch)
tree676402f6a85ab21839c7757dfbf9493ca921770d
parent066c2c90eb0a156efe9d1a407b32350673a09fed (diff)
Add "-extpass" cli option and associated tests
-rw-r--r--MANPAGE.md5
-rw-r--r--cryptfs/filter.go5
-rw-r--r--integration_tests/cli_test.go46
-rw-r--r--integration_tests/helpers.go16
-rw-r--r--main.go25
-rw-r--r--password.go54
6 files changed, 116 insertions, 35 deletions
diff --git a/MANPAGE.md b/MANPAGE.md
index 2f72169..517cc82 100644
--- a/MANPAGE.md
+++ b/MANPAGE.md
@@ -39,6 +39,11 @@ Options:
**-debug**
: Enable debug output
+**-extpass string**
+: Use an external program (like ssh-askpass) for the password prompt.
+The program should return the password on stdout, a trailing newline is
+stripped by gocryptfs.
+
**-f**
: Stay in the foreground
diff --git a/cryptfs/filter.go b/cryptfs/filter.go
index 079b64f..f80889d 100644
--- a/cryptfs/filter.go
+++ b/cryptfs/filter.go
@@ -6,8 +6,9 @@ package cryptfs
// when file names are not encrypted
func (be *CryptFS) IsFiltered(path string) bool {
// gocryptfs.conf in the root directory is forbidden
- if be.plaintextNames == true && path == "gocryptfs.conf" {
- Warn.Printf("The name \"/gocryptfs.conf\" is reserved when \"--plaintextnames\" is used\n")
+ if be.plaintextNames == true && path == ConfDefaultName {
+ Warn.Printf("The name /%s is reserved when -plaintextnames is used\n",
+ ConfDefaultName)
return true
}
return false
diff --git a/integration_tests/cli_test.go b/integration_tests/cli_test.go
new file mode 100644
index 0000000..a696600
--- /dev/null
+++ b/integration_tests/cli_test.go
@@ -0,0 +1,46 @@
+package integration_tests
+
+// Test CLI operations like "-init", "-password" etc
+
+import (
+ "os"
+ "os/exec"
+ "testing"
+
+ "github.com/rfjakob/gocryptfs/cryptfs"
+)
+
+func TestInit(t *testing.T) {
+ dir := tmpDir + "TestInit/"
+ err := os.Mkdir(dir, 0777)
+ if err != nil {
+ t.Fatal(err)
+ }
+ cmd := exec.Command(gocryptfsBinary, "-init", "-extpass", "echo test", dir)
+ if testing.Verbose() {
+ cmd.Stdout = os.Stdout
+ cmd.Stderr = os.Stderr
+ }
+ err = cmd.Run()
+ if err != nil {
+ t.Error(err)
+ }
+ _, err = os.Stat(dir + cryptfs.ConfDefaultName)
+ if err != nil {
+ t.Error(err)
+ }
+}
+
+// "dir" has been initialized by TestInit
+func TestPasswd(t *testing.T) {
+ dir := tmpDir + "TestInit/"
+ cmd := exec.Command(gocryptfsBinary, "-passwd", "-extpass", "echo test", dir)
+ if testing.Verbose() {
+ cmd.Stdout = os.Stdout
+ cmd.Stderr = os.Stderr
+ }
+ err := cmd.Run()
+ if err != nil {
+ t.Error(err)
+ }
+}
diff --git a/integration_tests/helpers.go b/integration_tests/helpers.go
index fdad28b..3ab1d21 100644
--- a/integration_tests/helpers.go
+++ b/integration_tests/helpers.go
@@ -10,13 +10,13 @@ import (
"testing"
)
+// Note: the code assumes that all have a trailing slash
const tmpDir = "/tmp/gocryptfs_main_test/"
-
-// Mountpoint
-// Note: the code assumes that both have a trailing slash!
const plainDir = tmpDir + "plain/"
const cipherDir = tmpDir + "cipher/"
+const gocryptfsBinary = "../gocryptfs"
+
func resetTmpDir() {
fu := exec.Command("fusermount", "-z", "-u", plainDir)
fu.Run()
@@ -40,11 +40,11 @@ func mount(extraArgs ...string) {
//args = append(args, "--fusedebug")
args = append(args, cipherDir)
args = append(args, plainDir)
- c := exec.Command("../gocryptfs", args...)
- // Warning messages clutter the test output. Uncomment if you want to debug
- // failures.
- //c.Stdout = os.Stdout
- //c.Stderr = os.Stderr
+ c := exec.Command(gocryptfsBinary, args...)
+ if testing.Verbose() {
+ c.Stdout = os.Stdout
+ c.Stderr = os.Stderr
+ }
err := c.Run()
if err != nil {
fmt.Println(err)
diff --git a/main.go b/main.go
index e9eef33..5fcf95e 100644
--- a/main.go
+++ b/main.go
@@ -44,7 +44,7 @@ func initDir(args *argContainer) {
}
cryptfs.Info.Printf("Choose a password for protecting your files.\n")
- password := readPasswordTwice()
+ password := readPasswordTwice(args.extpass)
err = cryptfs.CreateConfFile(args.config, password, args.plaintextnames)
if err != nil {
fmt.Println(err)
@@ -66,25 +66,25 @@ func usageText() {
type argContainer struct {
debug, init, zerokey, fusedebug, openssl, passwd, foreground, version,
plaintextnames, quiet bool
- masterkey, mountpoint, cipherdir, cpuprofile, config string
- notifypid int
+ masterkey, mountpoint, cipherdir, cpuprofile, config, extpass string
+ notifypid int
}
var flagSet *flag.FlagSet
// loadConfig - load the config file "filename", prompting the user for the password
-func loadConfig(filename string) (masterkey []byte, confFile *cryptfs.ConfFile) {
+func loadConfig(args *argContainer) (masterkey []byte, confFile *cryptfs.ConfFile) {
// Check if the file exists at all before prompting for a password
- _, err := os.Stat(filename)
+ _, err := os.Stat(args.config)
if err != nil {
fmt.Print(err)
os.Exit(ERREXIT_LOADCONF)
}
fmt.Printf("Password: ")
- pw := readPassword()
+ pw := readPassword(args.extpass)
cryptfs.Info.Printf("Decrypting master key... ")
cryptfs.Warn.Disable() // Silence DecryptBlock() error messages on incorrect password
- masterkey, confFile, err = cryptfs.LoadConfFile(filename, pw)
+ masterkey, confFile, err = cryptfs.LoadConfFile(args.config, pw)
cryptfs.Warn.Enable()
if err != nil {
fmt.Println(err)
@@ -97,10 +97,10 @@ func loadConfig(filename string) (masterkey []byte, confFile *cryptfs.ConfFile)
}
// changePassword - change the password of config file "filename"
-func changePassword(filename string) {
- masterkey, confFile := loadConfig(filename)
+func changePassword(args *argContainer) {
+ masterkey, confFile := loadConfig(args)
fmt.Printf("Please enter your new password.\n")
- newPw := readPasswordTwice()
+ newPw := readPasswordTwice(args.extpass)
confFile.EncryptKey(masterkey, newPw)
err := confFile.WriteFile()
if err != nil {
@@ -139,6 +139,7 @@ func main() {
flagSet.StringVar(&args.masterkey, "masterkey", "", "Mount with explicit master key")
flagSet.StringVar(&args.cpuprofile, "cpuprofile", "", "Write cpu profile to specified file")
flagSet.StringVar(&args.config, "config", "", "Use specified config file instead of CIPHERDIR/gocryptfs.conf")
+ flagSet.StringVar(&args.extpass, "extpass", "", "Use external program for the password prompt")
flagSet.IntVar(&args.notifypid, "notifypid", 0, "Send USR1 to the specified process after "+
"successful mount - used internally for daemonization")
flagSet.Parse(os.Args[1:])
@@ -215,7 +216,7 @@ func main() {
fmt.Printf("Usage: %s -passwd [OPTIONS] CIPHERDIR\n", PROGRAM_NAME)
os.Exit(ERREXIT_USAGE)
}
- changePassword(args.config) // does not return
+ changePassword(&args) // does not return
}
// Mount
// Check mountpoint
@@ -248,7 +249,7 @@ func main() {
} else {
// Load master key from config file
var confFile *cryptfs.ConfFile
- masterkey, confFile = loadConfig(args.config)
+ masterkey, confFile = loadConfig(&args)
printMasterKey(masterkey)
args.plaintextnames = confFile.PlaintextNames()
}
diff --git a/password.go b/password.go
index 6b3452a..ede65dd 100644
--- a/password.go
+++ b/password.go
@@ -2,15 +2,18 @@ package main
import (
"fmt"
- "golang.org/x/crypto/ssh/terminal"
"os"
+ "os/exec"
+ "strings"
+
+ "golang.org/x/crypto/ssh/terminal"
)
-func readPasswordTwice() string {
+func readPasswordTwice(extpass string) string {
fmt.Printf("Password: ")
- p1 := readPassword()
- fmt.Printf("Repeat: ")
- p2 := readPassword()
+ p1 := readPassword(extpass)
+ fmt.Printf("Repeat: ")
+ p2 := readPassword(extpass)
if p1 != p2 {
fmt.Printf("Passwords do not match\n")
os.Exit(ERREXIT_PASSWORD)
@@ -18,14 +21,39 @@ func readPasswordTwice() string {
return p1
}
-// Get password from terminal
-func readPassword() string {
- fd := int(os.Stdin.Fd())
- p, err := terminal.ReadPassword(fd)
- fmt.Printf("\n")
- if err != nil {
- fmt.Printf("Error: Could not read password: %v\n", err)
+// readPassword - get password from terminal
+// or from the "extpass" program
+func readPassword(extpass string) string {
+ var password string
+ var err error
+ var output []byte
+ if extpass != "" {
+ parts := strings.Split(extpass, " ")
+ cmd := exec.Command(parts[0], parts[1:]...)
+ cmd.Stderr = os.Stderr
+ output, err = cmd.Output()
+ if err != nil {
+ fmt.Printf("extpass program returned error: %v\n", err)
+ os.Exit(ERREXIT_PASSWORD)
+ }
+ fmt.Printf("(extpass)\n")
+ // Trim trailing newline like terminal.ReadPassword() does
+ if output[len(output)-1] == '\n' {
+ output = output[:len(output)-1]
+ }
+ } else {
+ fd := int(os.Stdin.Fd())
+ output, err = terminal.ReadPassword(fd)
+ if err != nil {
+ fmt.Printf("Error: Could not read password from terminal: %v\n", err)
+ os.Exit(ERREXIT_PASSWORD)
+ }
+ fmt.Printf("\n")
+ }
+ password = string(output)
+ if password == "" {
+ fmt.Printf("Error: password is empty\n")
os.Exit(ERREXIT_PASSWORD)
}
- return string(p)
+ return password
}