github.com/keybase/client/go@v0.0.0-20240309051027-028f7c731f8b/pinentry/pinentry_nix.go (about) 1 // Copyright 2015 Keybase, Inc. All rights reserved. Use of 2 // this source code is governed by the included BSD license. 3 4 //go:build darwin || dragonfly || freebsd || linux || nacl || netbsd || openbsd || solaris 5 // +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris 6 7 package pinentry 8 9 import ( 10 "fmt" 11 "os" 12 "path/filepath" 13 14 "os/exec" 15 16 "github.com/keybase/client/go/logger" 17 ) 18 19 // 20 // some borrowed from here: 21 // 22 // https://github.com/bradfitz/camlistore/blob/master/pkg/misc/pinentry/pinentry.go 23 // 24 // Under the Apache 2.0 license 25 // 26 27 func canExec(s string) error { 28 fi, err := os.Stat(s) 29 if err != nil { 30 return err 31 } 32 mode := fi.Mode() 33 34 // 35 // Only consider non-directories that have at least one +x 36 // bit set. 37 // 38 // TODO: Recheck this on Windows! 39 // See here for lookpath: http://golang.org/src/pkg/os/exec/lp_windows.go 40 // 41 // Similar to check from exec.LookPath below 42 // See here: http://golang.org/src/pkg/os/exec/lp_unix.go 43 // 44 switch { 45 case mode.IsDir(): 46 return fmt.Errorf("Program '%s' is a directory", s) 47 case int(mode)&0111 == 0: 48 return fmt.Errorf("Program '%s' isn't executable", s) 49 default: 50 return nil 51 } 52 } 53 54 func FindPinentry(log logger.Logger) (string, error) { 55 if !HasWindows() { 56 return "", fmt.Errorf("Can't spawn gui window, not using pinentry") 57 } 58 bins := []string{ 59 // If you install MacTools you'll wind up with this pinentry 60 "/usr/local/MacGPG2/libexec/pinentry-mac.app/Contents/MacOS/pinentry-mac", 61 } 62 63 extraPaths := []string{} 64 65 log.Debug("+ FindPinentry()") 66 67 cmds := []string{ 68 "pinentry-gtk-2", 69 "pinentry-qt4", 70 "pinentry", 71 } 72 73 checkFull := func(s string) bool { 74 log.Debug("| Check fullpath %s", s) 75 found := (canExec(s) == nil) 76 if found { 77 log.Debug("- Found: %s", s) 78 } 79 return found 80 } 81 82 for _, b := range bins { 83 if checkFull(b) { 84 return b, nil 85 } 86 } 87 88 path := os.Getenv("PATH") 89 for _, c := range cmds { 90 log.Debug("| Looking for %s in standard PATH %s", c, path) 91 fullc, err := exec.LookPath(c) 92 if err == nil { 93 log.Debug("- Found %s", fullc) 94 return fullc, nil 95 } 96 } 97 98 for _, ep := range extraPaths { 99 for _, c := range cmds { 100 full := filepath.Join(ep, c) 101 if checkFull(full) { 102 return full, nil 103 } 104 } 105 } 106 107 log.Debug("- FindPinentry: none found") 108 return "", fmt.Errorf("No pinentry found, checked a bunch of different places") 109 } 110 111 func (pe *Pinentry) GetTerminalName() { 112 // Noop on all platforms but Windows 113 }