package ldap import ( "context" "time" ldap "github.com/vjeantet/ldapserver" ) // rpcTimeout bounds every NetAuth call made on behalf of one client // request. The gRPC client dials lazily and never applies its own // deadline, so without this a stalled server socket hangs the handler // goroutine and the LDAP client behind it forever. const rpcTimeout = 30 * time.Second func (s *server) handleBind(w ldap.ResponseWriter, m *ldap.Message) { ctx, cancel := context.WithTimeout(context.Background(), rpcTimeout) defer cancel() r := m.GetBindRequest() // The server only supports simple auth, no SASL or anything // fancy because we are after all just fronting another // protocol. if r.AuthenticationChoice() != "simple" { s.markUnbound(m) res := ldap.NewBindResponse(ldap.LDAPResultUnwillingToPerform) res.SetDiagnosticMessage("Authentication choice not supported") w.Write(res) return } s.l.Debug("Bind from dn", "dn", r.Name()) if s.allowAnon && r.Name() == "" { s.markBound(m) res := ldap.NewBindResponse(ldap.LDAPResultSuccess) w.Write(res) return } entityID, err := s.entityIDFromDN(r.Name()) if err != nil { s.markUnbound(m) res := ldap.NewBindResponse(ldap.LDAPResultInvalidDNSyntax) res.SetDiagnosticMessage(err.Error()) s.l.Warn("Request with invalid DN", "dn", r.Name()) w.Write(res) return } if err := s.c.AuthEntity(ctx, entityID, string(r.AuthenticationSimple())); err != nil { s.l.Warn("NetAuth authentication failed", "id", entityID, "error", err) s.markUnbound(m) res := ldap.NewBindResponse(ldap.LDAPResultInvalidCredentials) res.SetDiagnosticMessage("invalid credentials") w.Write(res) return } s.markBound(m) res := ldap.NewBindResponse(ldap.LDAPResultSuccess) w.Write(res) }