grim/convey

Bump the version for release
v0.14.0-alpha3
2018-02-20, Gary Kramlich
166a6d1979fa
Bump the version for release
// Convey
// Copyright 2016-2018 Gary Kramlich <grim@reaperworld.com>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package ssh
import (
"fmt"
"io"
"net"
"os"
"strings"
"golang.org/x/crypto/ssh"
"golang.org/x/crypto/ssh/agent"
)
// KeysAvailable returns True if there is at least one key that the ssh agent
// knows about, otherwise false. err will be set if there is an error along
// the way.
func KeysAvailable(identites []string) (bool, error) {
sshAgent, err := net.Dial("unix", os.Getenv("SSH_AUTH_SOCK"))
if err != nil {
return false, err
}
return keysAvailable(sshAgent, identites)
}
func keysAvailable(rw io.ReadWriter, identities []string) (bool, error) {
keys, err := agent.NewClient(rw).List()
if err != nil {
return false, err
}
// this runs in O(m * n) but thankful the number of keys should be low.
for _, identity := range identities {
if identity == "*" {
// if the user doesn't care which key and we have a key, return true
if len(keys) > 0 {
return true, nil
}
// if the user doesn't care which key but we have no keys, return an error
return false, fmt.Errorf("no ssh keys available")
}
uIdentity := strings.ToUpper(identity)
for _, pubKey := range keys {
fpSHA256 := strings.ToUpper(ssh.FingerprintSHA256(pubKey))
fpMD5 := strings.ToUpper(ssh.FingerprintLegacyMD5(pubKey))
if strings.HasPrefix(uIdentity, "SHA256:") {
if uIdentity == fpSHA256 {
return true, nil
}
} else if strings.HasPrefix(uIdentity, "MD5:") {
if uIdentity[4:] == fpMD5 {
return true, nil
}
} else {
// no known prefix check sha256 then md5, then give up
if uIdentity == fpSHA256[7:] || uIdentity == fpMD5 {
return true, nil
}
}
}
}
if err == nil {
err = fmt.Errorf("no usable ssh identities found")
}
return false, err
}
// ShouldEnable returns true if the ssh agent should be enabled.
func ShouldEnable(identities []string) (bool, error) {
if len(identities) <= 0 {
return false, nil
}
haveKeys, err := KeysAvailable(identities)
if err != nil {
return false, fmt.Errorf("error talking to ssh-agent: %s", err)
}
if !haveKeys {
return false, fmt.Errorf("no keys available in ssh-agent")
}
return true, nil
}