func CheckAttributes(LdapConnection *ldap.Conn, LdapEntry, ADEntry *ldap.AddRequest) { var ADMapAggregated []MapADandLDAP var LDAPMapAggregated []MapADandLDAP for _, adEntries := range ADEntry.Attributes { if adEntries.Type == "memberOf" { adEntries.Vals = *ConvertAttributesToLower(&adEntries.Vals) } sort.Strings(adEntries.Vals) ADMapped := MapADandLDAP{adEntries.Type: adEntries.Vals} ADMapAggregated = append(ADMapAggregated, ADMapped) } for _, ldapEntries := range LdapEntry.Attributes { sort.Strings(ldapEntries.Vals) LDAPMapped := MapADandLDAP{ldapEntries.Type: ldapEntries.Vals} LDAPMapAggregated = append(LDAPMapAggregated, LDAPMapped) } Info.Println("Got from AD", ADMapAggregated) Info.Println("Got from LD", LDAPMapAggregated) if reflect.DeepEqual(ADMapAggregated, LDAPMapAggregated) == true { Info.Println("Both entries matches, passing...") } else { Info.Println("CHANGE DETECTED") Info.Println("AD -> ", ADMapAggregated) Info.Println("LD -> ", LDAPMapAggregated) delete := ldap.NewDelRequest(LdapEntry.DN, []ldap.Control{}) err := LdapConnection.Del(delete) if err != nil { Error.Println(err) } else { Info.Println(*delete, "Deleted") } err = LdapConnection.Add(ADEntry) if err != nil { Error.Println(err) } else { Info.Println(*ADEntry, "Added to ldap") } } }
func main() { logfileMain := "/var/log/ldapsync.log" //TAG := gosyncmodules.RandomGen(5) username, err := user.Current() gosyncmodules.CheckForError(err) loggerMain := gosyncmodules.StartLog(logfileMain, username) defer loggerMain.Close() configFile := "/etc/ldapsync.ini" gosyncmodules.CheckPerm(configFile) config, err := gosyncmodules.GetConfig(configFile) gosyncmodules.CheckForError(err) //AD Variables ADGlobal, err := config.GetSection("ADServer") gosyncmodules.CheckForError(err) ADHost, err := ADGlobal.GetKey("ADHost") gosyncmodules.CheckForError(err) ADPort, err := ADGlobal.GetKey("ADPort") gosyncmodules.CheckForError(err) ADPage, err := ADGlobal.GetKey("ADPage") gosyncmodules.CheckForError(err) ADConnTimeOut, err := ADGlobal.GetKey("ADConnTimeOut") gosyncmodules.CheckForError(err) ADUsername, err := ADGlobal.GetKey("username") gosyncmodules.CheckForError(err) ADPassword, err := ADGlobal.GetKey("password") gosyncmodules.CheckForError(err) ADBaseDN, err := ADGlobal.GetKey("basedn") gosyncmodules.CheckForError(err) ADAttr, err := ADGlobal.GetKey("attr") gosyncmodules.CheckForError(err) ADFilter, err := ADGlobal.GetKey("filter") gosyncmodules.CheckForError(err) AD_Port := ADPort.MustString("389") ADAttribute := make([]string, 0, 1) for _, i := range ADAttr.Strings(",") { ADAttribute = append(ADAttribute, i) } //LDAP Variables LDAPGlobal, err := config.GetSection("LDAPServer") gosyncmodules.CheckForError(err) LDAPHost, err := LDAPGlobal.GetKey("LDAPHost") gosyncmodules.CheckForError(err) LDAPPort, err := LDAPGlobal.GetKey("LDAPPort") gosyncmodules.CheckForError(err) LDAP_Port := LDAPPort.MustString("389") LDAPPage, err := LDAPGlobal.GetKey("LDAPPage") gosyncmodules.CheckForError(err) LDAPConnTimeOut, err := LDAPGlobal.GetKey("LDAPConnTimeOut") gosyncmodules.CheckForError(err) LDAPUsername, err := LDAPGlobal.GetKey("username") gosyncmodules.CheckForError(err) LDAPPassword, err := LDAPGlobal.GetKey("password") gosyncmodules.CheckForError(err) LDAPBaseDN, err := LDAPGlobal.GetKey("basedn") gosyncmodules.CheckForError(err) LDAPFilter, err := ADGlobal.GetKey("filter") gosyncmodules.CheckForError(err) LDAPAttr, err := LDAPGlobal.GetKey("attr") gosyncmodules.CheckForError(err) LDAPAttribute := make([]string, 0, 1) for _, i := range LDAPAttr.Strings(",") { LDAPAttribute = append(LDAPAttribute, i) } //AD to LDAP Mapping, replace and required variables ReplaceAttributes, err := config.GetSection("Replace") gosyncmodules.CheckForError(err) MapAttributes, err := config.GetSection("Map") gosyncmodules.CheckForError(err) //SyncVariables SyncDelay, err := config.GetSection("Sync") gosyncmodules.CheckForError(err) Delay, err := SyncDelay.GetKey("sleepTime") gosyncmodules.CheckForError(err) //End of variable declaration gosyncmodules.Info.Println("ADHost: ", ADHost) gosyncmodules.Info.Println("ADPort: ", ADPort) gosyncmodules.Info.Println("ADPageSize: ", ADPage) gosyncmodules.Info.Println("ADBaseDN: ", ADBaseDN) gosyncmodules.Info.Println("ADAttr: ", ADAttribute) gosyncmodules.Info.Println("ADFilter: ", ADFilter) gosyncmodules.Info.Println("LDAPHost: ", LDAPHost) gosyncmodules.Info.Println("LDAPPort: ", LDAP_Port) gosyncmodules.Info.Println("LDAPPageSize: ", LDAPPage) gosyncmodules.Info.Println("LDAPBaseDN: ", LDAPBaseDN) gosyncmodules.Info.Println("LDAPAttr: ", LDAPAttribute) gosyncmodules.Info.Println("LDAPFilter: ", LDAPFilter) var howtorun string if os.Args[1] == "--init" { howtorun = "init" } else if os.Args[1] == "--sync" { howtorun = "sync" } else { fmt.Println("Usage:\n\t", os.Args[0], "--init to do an init run to freshly populate ldap", "from AD. Caution, if there is data already populated in ldap,\n\t\t", "you may have to wipe it clean before doing init. \n\t", os.Args[0], "--sync to keep monitoring the changes and sync") os.Exit(1) } gosyncmodules.Info.Println("Starting script with", howtorun, "parameter") if howtorun == "init" { shutdownChannel := make(chan string) defer gosyncmodules.Info.Println("Closed blocking channel") defer close(shutdownChannel) gosyncmodules.Info.Println("Initializing bool channel and getting AD entries in goroutine") gosyncmodules.Info.Println("Gathering results") //Create channel to receive slice of struct ADElementsChan := make(chan *[]gosyncmodules.LDAPElement) gosyncmodules.Info.Println("Created channel of type", reflect.TypeOf(ADElementsChan)) go gosyncmodules.InitialrunAD(ADHost.String(), AD_Port, ADUsername.String(), ADPassword.String(), ADBaseDN.String(), ADFilter.String(), ADAttribute, ADPage.MustInt(500), ADConnTimeOut.MustInt(10), shutdownChannel, ADElementsChan) ADElements := <-ADElementsChan //Finished retriving AD results gosyncmodules.Info.Println(<-shutdownChannel) //Finished reading from Blocking channel gosyncmodules.InitialrunLDAP(LDAPHost.String(), LDAP_Port, LDAPUsername.String(), LDAPPassword.String(), LDAPBaseDN.String(), LDAPFilter.String(), LDAPAttribute, LDAPPage.MustInt(500), LDAPConnTimeOut.MustInt(10), ADElements, ReplaceAttributes, MapAttributes) gosyncmodules.Info.Println("Received", reflect.TypeOf(ADElementsChan), "from child thread, and has ", len(*ADElements), "elements") } else { gosyncmodules.Info.Println("Initiating sync") for { AddChan := make(chan gosyncmodules.Action) gosyncmodules.Info.Println("Created", reflect.TypeOf(AddChan)) DelChan := make(chan gosyncmodules.Action) gosyncmodules.Info.Println("Created", reflect.TypeOf(DelChan)) shutdownAddChan := make(chan string) shutdownDelChan := make(chan string) shutdownChannel := make(chan string) LdapConnectionChan := make(chan *ldap.Conn) gosyncmodules.Info.Println("Created channel of type", reflect.TypeOf(LdapConnectionChan)) ADElementsChan := make(chan *[]gosyncmodules.LDAPElement) gosyncmodules.Info.Println("Created channel of type", reflect.TypeOf(ADElementsChan)) LDAPElementsChan := make(chan *[]gosyncmodules.LDAPElement) gosyncmodules.Info.Println("Created channel of type", reflect.TypeOf(LDAPElementsChan)) go gosyncmodules.SyncrunLDAP(LDAPHost.String(), LDAP_Port, LDAPUsername.String(), LDAPPassword.String(), LDAPBaseDN.String(), LDAPFilter.String(), LDAPAttribute, LDAPPage.MustInt(500), LDAPConnTimeOut.MustInt(10), shutdownChannel, LDAPElementsChan, LdapConnectionChan, ReplaceAttributes, MapAttributes) go gosyncmodules.InitialrunAD(ADHost.String(), AD_Port, ADUsername.String(), ADPassword.String(), ADBaseDN.String(), ADFilter.String(), ADAttribute, ADPage.MustInt(500), ADConnTimeOut.MustInt(10), shutdownChannel, ADElementsChan) ADElements := <-ADElementsChan LDAPElements := <-LDAPElementsChan LDAPConnection := <-LdapConnectionChan gosyncmodules.Info.Println(<-shutdownChannel) gosyncmodules.Info.Println(<-shutdownChannel) ADElementsConverted := gosyncmodules.InitialPopulateToLdap(ADElements, LDAPConnection, ReplaceAttributes, MapAttributes, true) LDAPElementsConverted := gosyncmodules.InitialPopulateToLdap(LDAPElements, LDAPConnection, ReplaceAttributes, MapAttributes, true) gosyncmodules.ConvertRealmToLower(ADElementsConverted) gosyncmodules.Info.Println("Converted AD Realms to lowercase") go gosyncmodules.FindAdds(&ADElementsConverted, &LDAPElementsConverted, LDAPConnection, AddChan, shutdownAddChan) go gosyncmodules.FindDels(&LDAPElementsConverted, &ADElementsConverted, DelChan, shutdownDelChan) counter := 0 for { select { case Add := <-AddChan: for _, v := range Add { //gosyncmodules.Info.Println(k, ":", v) err := LDAPConnection.Add(v) if err != nil { gosyncmodules.Error.Println(err) } } case Del := <-DelChan: for _, v := range Del { //gosyncmodules.Info.Println(k, ":", v) delete := ldap.NewDelRequest(v.DN, []ldap.Control{}) err := LDAPConnection.Del(delete) if err != nil { gosyncmodules.Error.Println(err) } } case shutdownAdd := <-shutdownAddChan: gosyncmodules.Info.Println(shutdownAdd) counter += 1 case shutdownDel := <-shutdownDelChan: gosyncmodules.Info.Println(shutdownDel) counter += 1 } if counter == 2 { gosyncmodules.Info.Println("Counter reached") break } } LDAPConnection.Close() //Sleep the daemon close(shutdownDelChan) close(shutdownAddChan) close(shutdownChannel) close(LdapConnectionChan) close(ADElementsChan) close(LDAPElementsChan) gosyncmodules.Info.Println("Sleeping for", Delay.MustInt(5), "seconds, and iterating again...") gosyncmodules.Info.Println("Current active goroutines: ", runtime.NumGoroutine()) //Thanks to profiling, that helped finding a goroutine leak. /*buf1 := new(bytes.Buffer) pprof.Lookup("goroutine").WriteTo(buf1, 1) fmt.Println("pprof.Lookup.WriteTo report:\n", string(buf1.Bytes()[:buf1.Len()])) var buf [10240]byte out := buf[:runtime.Stack(buf[:], true)] fmt.Println("runtime.Stack report:\n", string(out))*/ time.Sleep(time.Second * time.Duration(Delay.MustInt(5))) } } }