package ldap import ( "fmt" "os" "sync/atomic" "github.com/hashicorp/go-hclog" ldap "github.com/vjeantet/ldapserver" ) // Option handle configuration of the underlying ldap.server type. type Option func(*server) // protocolSink receives the protocol level output of the underlying // LDAP server. The underlying server logs through a single process // wide variable, so the destination is swapped atomically: replacing // it while connections from an earlier server instance are still // logging would otherwise be a data race. var protocolSink atomic.Value // hclog.Logger func init() { // Route the underlying server's output through the sink rather // than letting it write directly to stdout. ldap.Logger = &protocolLogger{} } // WithLogger sets the loggers for the server. Protocol chatter from // the underlying LDAP server is funneled into the provided hclog and // downgraded to trace level, which is the only level at which that // output is interesting. func WithLogger(l hclog.Logger) Option { return func(s *server) { s.l = l.Named("ldap") protocolSink.Store(l.Named("ldap.protocol")) } } // protocolLogger adapts hclog to the small logging interface the // underlying LDAP server uses. Everything it emits is protocol level // noise, so it arrives as trace; fatal keeps its exit semantics. type protocolLogger struct{} func (p *protocolLogger) sink() hclog.Logger { if l, ok := protocolSink.Load().(hclog.Logger); ok { return l } return hclog.NewNullLogger() } func (p *protocolLogger) Print(v ...interface{}) { p.sink().Trace(fmt.Sprint(v...)) } func (p *protocolLogger) Printf(f string, v ...interface{}) { p.sink().Trace(fmt.Sprintf(f, v...)) } func (p *protocolLogger) Println(v ...interface{}) { p.sink().Trace(fmt.Sprintln(v...)) } func (p *protocolLogger) Fatal(v ...interface{}) { p.sink().Error(fmt.Sprint(v...)) os.Exit(1) } func (p *protocolLogger) Fatalf(f string, v ...interface{}) { p.sink().Error(fmt.Sprintf(f, v...)) os.Exit(1) } func (p *protocolLogger) Fatalln(v ...interface{}) { p.sink().Error(fmt.Sprintln(v...)) os.Exit(1) } func (p *protocolLogger) Panic(v ...interface{}) { panic(fmt.Sprint(v...)) } func (p *protocolLogger) Panicf(f string, v ...interface{}) { panic(fmt.Sprintf(f, v...)) } func (p *protocolLogger) Panicln(v ...interface{}) { panic(fmt.Sprint(v...)) } // WithNetAuth sets the NetAuth client for the server. func WithNetAuth(n naClient) Option { return func(s *server) { s.c = n } } // WithAnonBind enables anonymous bind support which is necessary in // some cases that the client wishes to do an initial anonymous bind, // followed by an immediate rebind as a real entity. func WithAnonBind(a bool) Option { return func(s *server) { s.allowAnon = a } }