diff --git a/main.go b/main.go index 2e4122d..d73ada4 100644 --- a/main.go +++ b/main.go @@ -154,6 +154,8 @@ func main() { routes.Bind(gobottin.handleBind) routes.Search(gobottin.handleSearch) routes.Add(gobottin.handleAdd) + routes.Compare(gobottin.handleCompare) + routes.Delete(gobottin.handleDelete) ldapserver.Handle(routes) // listen on 10389 @@ -556,3 +558,131 @@ func (server *Server) handleAddInternal(state *State, r *message.AddRequest) (in return ldap.LDAPResultSuccess, nil } + +func (server *Server) handleCompare(s ldap.UserState, w ldap.ResponseWriter, m *ldap.Message) { + state := s.(*State) + r := m.GetCompareRequest() + + code, err := server.handleCompareInternal(state, &r) + + res := ldap.NewResponse(code) + if err != nil { + res.SetDiagnosticMessage(err.Error()) + } + w.Write(message.CompareResponse(res)) +} + +func (server *Server) handleCompareInternal(state *State, r *message.CompareRequest) (int, error) { + dn := string(r.Entry()) + attr := string(r.Ava().AttributeDesc()) + expected := string(r.Ava().AssertionValue()) + + _, err := server.checkSuffix(dn, false) + if err != nil { + return ldap.LDAPResultInvalidDNSyntax, err + } + + // TODO check user for permissions to read dn + + exists, err := server.objectExists(dn) + if err != nil { + return ldap.LDAPResultOperationsError, err + } + if !exists { + return ldap.LDAPResultNoSuchObject, fmt.Errorf("Not found: %s", dn) + } + + values, err := server.getAttribute(dn, attr) + if err != nil { + return ldap.LDAPResultOperationsError, err + } + + for _, v := range values { + if v == expected { + return ldap.LDAPResultCompareTrue, nil + } + } + + return ldap.LDAPResultCompareFalse, nil +} + +func (server *Server) handleDelete(s ldap.UserState, w ldap.ResponseWriter, m *ldap.Message) { + state := s.(*State) + r := m.GetDeleteRequest() + + code, err := server.handleDeleteInternal(state, &r) + + res := ldap.NewResponse(code) + if err != nil { + res.SetDiagnosticMessage(err.Error()) + } + w.Write(message.DelResponse(res)) +} + +func (server *Server) handleDeleteInternal(state *State, r *message.DelRequest) (int, error) { + dn := string(*r) + + _, err := server.checkSuffix(dn, false) + if err != nil { + return ldap.LDAPResultInvalidDNSyntax, err + } + + // TODO check user for permissions to write dn + + // Check that this LDAP entry exists and has no children + path := dnToConsul(dn) + "/" + items, _, err := server.kv.List(path, nil) + if err != nil { + return ldap.LDAPResultOperationsError, err + } + + if len(items) == 0 { + return ldap.LDAPResultNoSuchObject, fmt.Errorf("Not found: %s", dn) + } + for _, item := range items { + itemDN, _, _ := consulToDN(item) + if itemDN != dn { + return ldap.LDAPResultNotAllowedOnNonLeaf, fmt.Errorf( + "Cannot delete %d as it has children", dn) + } + } + + // Retrieve group membership before we delete everything + memberOf, err := server.getAttribute(dn, "memberOf") + if err != nil { + return ldap.LDAPResultOperationsError, err + } + + // Delete the LDAP entry + _, err = server.kv.DeleteTree(path, nil) + if err != nil { + return ldap.LDAPResultOperationsError, err + } + + // Delete it from the member list of all the groups it was a member of + if memberOf != nil { + for _, group := range memberOf { + groupMembers , err := server.getAttribute(dn, "member") + if err != nil { + return ldap.LDAPResultOperationsError, err + } + + newMembers := []string{} + for _, memb := range groupMembers { + if memb != dn { + newMembers = append(newMembers, memb) + } + } + + err = server.addElements(group, Entry{ + "member": newMembers, + }) + if err != nil { + return ldap.LDAPResultOperationsError, err + } + } + } + + return ldap.LDAPResultSuccess, nil +} +