forked from gopasspw/gopass
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Create secure in-memory directory on macOS (gopasspw#144)
* Create secure in-memory directory on macOS Fixes #29 * Vendor github.com/cenkalti/backoff
- Loading branch information
1 parent
f57d3c5
commit 30c0a17
Showing
15 changed files
with
711 additions
and
28 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
package fsutil | ||
|
||
import ( | ||
"fmt" | ||
"io" | ||
"io/ioutil" | ||
"os" | ||
"path/filepath" | ||
) | ||
|
||
type tempfile struct { | ||
dir string | ||
dev string | ||
fh *os.File | ||
dbg bool | ||
} | ||
|
||
// TempFiler is a tempfile interface | ||
type TempFiler interface { | ||
io.WriteCloser | ||
Name() string | ||
Remove() error | ||
} | ||
|
||
// TempFile returns a new tempfile wrapper | ||
func TempFile(prefix string) (TempFiler, error) { | ||
td, err := ioutil.TempDir(tempdirBase(), prefix) | ||
if err != nil { | ||
return nil, err | ||
} | ||
tf := &tempfile{ | ||
dir: td, | ||
} | ||
if gdb := os.Getenv("GOPASS_DEBUG"); gdb == "true" { | ||
tf.dbg = true | ||
} | ||
if err := tf.mount(); err != nil { | ||
_ = os.RemoveAll(tf.dir) | ||
return nil, err | ||
} | ||
|
||
fn := filepath.Join(tf.dir, "tempfile") | ||
fh, err := os.OpenFile(fn, os.O_CREATE|os.O_EXCL|os.O_WRONLY, 0600) | ||
if err != nil { | ||
return nil, fmt.Errorf("Failed to open file %s: %s", fn, err) | ||
} | ||
tf.fh = fh | ||
|
||
return tf, nil | ||
} | ||
|
||
func (t *tempfile) Name() string { | ||
if t.fh == nil { | ||
return "" | ||
} | ||
return t.fh.Name() | ||
} | ||
|
||
func (t *tempfile) Write(p []byte) (int, error) { | ||
if t.fh == nil { | ||
return 0, fmt.Errorf("not initialized") | ||
} | ||
return t.fh.Write(p) | ||
} | ||
|
||
func (t *tempfile) Close() error { | ||
if t.fh == nil { | ||
return nil | ||
} | ||
return t.fh.Close() | ||
} | ||
|
||
func (t *tempfile) Remove() error { | ||
_ = t.Close() | ||
if err := t.unmount(); err != nil { | ||
return fmt.Errorf("Failed to unmount %s from %s: %s", t.dev, t.dir, err) | ||
} | ||
return os.RemoveAll(t.dir) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
// +build darwin | ||
|
||
package fsutil | ||
|
||
import ( | ||
"fmt" | ||
"os" | ||
"os/exec" | ||
"strings" | ||
"time" | ||
|
||
"github.com/cenkalti/backoff" | ||
) | ||
|
||
func tempdirBase() string { | ||
return "" | ||
} | ||
|
||
func (t *tempfile) mount() error { | ||
// create 16MB ramdisk | ||
cmd := exec.Command("hdid", "-drivekey", "system-image=yes", "-nomount", "ram://32768") | ||
cmd.Stderr = os.Stderr | ||
if t.dbg { | ||
fmt.Printf("[DEBUG] CMD: %s %+v\n", cmd.Path, cmd.Args) | ||
} | ||
out, err := cmd.Output() | ||
if err != nil { | ||
return fmt.Errorf("Failed to create disk with hdid: %s", err) | ||
} | ||
if t.dbg { | ||
fmt.Printf("[DEBUG] Output: %s\n", out) | ||
} | ||
p := strings.Split(string(out), " ") | ||
if len(p) < 1 { | ||
return fmt.Errorf("Unhandeled hdid output: %s", string(out)) | ||
} | ||
t.dev = p[0] | ||
|
||
// create filesystem on ramdisk | ||
cmd = exec.Command("newfs_hfs", "-M", "700", t.dev) | ||
cmd.Stderr = os.Stderr | ||
if t.dbg { | ||
cmd.Stdout = os.Stdout | ||
fmt.Printf("[DEBUG] CMD: %s %+v\n", cmd.Path, cmd.Args) | ||
} | ||
if err := cmd.Run(); err != nil { | ||
return fmt.Errorf("Failed to make filesystem on %s: %s", t.dev, err) | ||
} | ||
|
||
// mount ramdisk | ||
cmd = exec.Command("mount", "-t", "hfs", "-o", "noatime", "-o", "nobrowse", t.dev, t.dir) | ||
cmd.Stderr = os.Stderr | ||
if t.dbg { | ||
cmd.Stdout = os.Stdout | ||
fmt.Printf("[DEBUG] CMD: %s %+v\n", cmd.Path, cmd.Args) | ||
} | ||
if err := cmd.Run(); err != nil { | ||
return fmt.Errorf("Failed to mount filesystem %s to %s: %s", t.dev, t.dir, err) | ||
} | ||
time.Sleep(100 * time.Millisecond) | ||
return nil | ||
} | ||
|
||
func (t *tempfile) unmount() error { | ||
bo := backoff.NewExponentialBackOff() | ||
bo.MaxElapsedTime = 10 * time.Second | ||
return backoff.Retry(t.tryUnmount, bo) | ||
} | ||
|
||
func (t *tempfile) tryUnmount() error { | ||
if t.dir == "" || t.dev == "" { | ||
return fmt.Errorf("need dir and dev") | ||
} | ||
// unmount ramdisk | ||
cmd := exec.Command("diskutil", "unmountDisk", t.dev) | ||
cmd.Stderr = os.Stderr | ||
if t.dbg { | ||
cmd.Stdout = os.Stdout | ||
fmt.Printf("[DEBUG] CMD: %s %+v\n", cmd.Path, cmd.Args) | ||
} | ||
if err := cmd.Run(); err != nil { | ||
return err | ||
} | ||
|
||
// eject disk | ||
cmd = exec.Command("diskutil", "quiet", "eject", t.dev) | ||
cmd.Stderr = os.Stderr | ||
if t.dbg { | ||
cmd.Stdout = os.Stdout | ||
fmt.Printf("[DEBUG] CMD: %s %+v\n", cmd.Path, cmd.Args) | ||
} | ||
return cmd.Run() | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
// +build !linux,!darwin | ||
|
||
package fsutil | ||
|
||
// tempdir returns a temporary directory suiteable for sensitive data. On | ||
// Windows, just return empty string for ioutil.TempFile. | ||
func tempdirBase() string { | ||
return "" | ||
} | ||
|
||
func (t *tempfile) mount() error { | ||
_ = t.dev // to trick megacheck | ||
return nil | ||
} | ||
|
||
func (t *tempfile) unmount() error { | ||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
package fsutil | ||
|
||
import ( | ||
"io/ioutil" | ||
"os" | ||
"testing" | ||
) | ||
|
||
func TestTempdirBase(t *testing.T) { | ||
tempdir, err := ioutil.TempDir(tempdirBase(), "gopass-") | ||
if err != nil { | ||
t.Fatalf("Failed to create tempdir: %s", err) | ||
} | ||
defer func() { | ||
_ = os.RemoveAll(tempdir) | ||
}() | ||
} |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
Oops, something went wrong.