in pam_ussh.go [70:202]
func authenticate(w io.Writer, uid int, username, ca string, principals map[string]struct{}) AuthResult {
authSock := os.Getenv("SSH_AUTH_SOCK")
if authSock == "" {
fmt.Fprint(w, "No SSH_AUTH_SOCK")
return AuthError
}
origEUID := os.Geteuid()
if os.Getuid() != origEUID || origEUID == 0 {
// Note: this only sets the euid and doesn't do anything with the egid.
// That should be fine for most cases, but it's worth calling out.
if !seteuid(uid) {
pamLog("error dropping privs from %d to %d", origEUID, uid)
return AuthError
}
defer func() {
if !seteuid(origEUID) {
pamLog("error resetting uid to %d", origEUID)
}
}()
}
agentSock, err := net.Dial("unix", authSock)
if err != nil {
fmt.Fprintf(w, "error connecting to %s: %v\n", authSock, err)
// if we're here, we probably can't stat the socket to get the owner uid
// to decorate the logs, but we might be able to read the parent directory.
ownerUID := ownerUID(path.Dir(authSock))
pamLog("error opening auth sock (sock owner: %d/%s) by (caller: %d/%s)",
ownerUID, getUsername(ownerUID), os.Getuid(), username)
return AuthError
}
a := agent.NewClient(agentSock)
keys, err := a.List()
if err != nil {
pamLog("Error listing keys: %v", err)
return AuthError
}
if len(keys) == 0 {
pamLog("No certs loaded.\n")
return AuthError
}
caBytes, err := ioutil.ReadFile(ca)
if err != nil {
pamLog("error reading ca: %v\n", err)
return AuthError
}
var caPubkeys []ssh.PublicKey
in := caBytes
for {
pubKey, _, _, rest, err := ssh.ParseAuthorizedKey(in)
if err != nil {
pamLog("skipping bad public key: %v", err)
} else {
caPubkeys = append(caPubkeys, pubKey)
}
if len(rest) == 0 {
break
}
in = rest
}
c := &ssh.CertChecker{
IsUserAuthority: func(auth ssh.PublicKey) bool {
for _, k := range caPubkeys {
if bytes.Equal(auth.Marshal(), k.Marshal()) {
return true
}
}
return false
},
}
for idx := range keys {
pubKey, err := ssh.ParsePublicKey(keys[idx].Marshal())
if err != nil {
continue
}
cert, ok := pubKey.(*ssh.Certificate)
if !ok {
continue
}
if err := c.CheckCert(username, cert); err != nil {
continue
}
if !c.IsUserAuthority(cert.SignatureKey) {
pamLog("certificate signed by unrecognized authority")
continue
}
// for the ssh agent to sign some data validating that they do in fact
// have the private key
randBytes := make([]byte, 32)
if _, err := rand.Read(randBytes); err != nil {
pamLog("Error grabbing random bytes: %v\n", err)
return AuthError
}
signedData, err := a.Sign(pubKey, randBytes)
if err != nil {
pamLog("error signing data: %v\n", err)
return AuthError
}
if err := pubKey.Verify(randBytes, signedData); err != nil {
pamLog("signature verification failed: %v\n", err)
return AuthError
}
if len(principals) == 0 {
pamLog("Authentication succeeded for %q (cert %q, %d)",
username, cert.ValidPrincipals[0], cert.Serial)
return AuthSuccess
}
for _, p := range cert.ValidPrincipals {
if _, ok := principals[p]; ok {
pamLog("Authentication succeded for %s. Matched principal %s, cert %d",
cert.ValidPrincipals[0], p, cert.Serial)
return AuthSuccess
}
}
}
pamLog("no valid certs found")
return AuthError
}