package nslcd_systemd import ( "fmt" "net" "nslcd_proto" "os" "os/signal" sd "sd_daemon" "sd_daemon/logger" "sd_daemon/lsb" "sync" "syscall" ) type Backend interface { nslcd_proto.Backend Init() error Reload() error Close() } func get_socket() (socket net.Listener, err error) { socket = nil err = nil fds := sd.ListenFds(true) if fds == nil { err = fmt.Errorf("Failed to aquire sockets from systemd") return } if len(fds) != 1 { err = fmt.Errorf("Wrong number of sockets from systemd: expected %d but got %d", 1, len(fds)) return } socket, err = net.FileListener(fds[0]) fds[0].Close() return } func getpeercred(conn *net.UnixConn) (cred nslcd_proto.Ucred, err error) { file, err := conn.File() if err != nil { return } defer file.Close() _cred, err := syscall.GetsockoptUcred(int(file.Fd()), syscall.SOL_SOCKET, syscall.SO_PEERCRED) cred = nslcd_proto.Ucred(*_cred) return } func handler(conn *net.UnixConn, backend nslcd_proto.Backend) { defer conn.Close() cred, err := getpeercred(conn) if err != nil { logger.Debug("Connection from unknown client") } else { logger.Debug("Connection from pid=%v uid=%v gid=%v", cred.Pid, cred.Uid, cred.Gid) } err = nslcd_proto.HandleRequest(backend, conn, conn, cred) if err != nil { logger.Notice("Error while handling request: %v", err) } } func Main(backend Backend) uint8 { var err error = nil var socket net.Listener = nil defer func() { if socket != nil { socket.Close() } }() sigs := make(chan os.Signal) signal.Notify(sigs, syscall.SIGTERM, syscall.SIGHUP) disable_nss_module() err = backend.Init() if err != nil { logger.Err("Could not initialize backend: %v", err) sd.Notify(false, "STOPPING=1") return lsb.EXIT_FAILURE } defer backend.Close() socket, err = get_socket() if err != nil { logger.Err("%v", err) sd.Notify(false, "STOPPING=1") return lsb.EXIT_NOTRUNNING } sock := make(chan *net.UnixConn) go func() { defer lsb.Recover() for { conn, err := socket.Accept() if err != nil { logger.Notice("Could not accept connection: %v", err) } sock <- conn.(*net.UnixConn) } }() exit := lsb.EXIT_SUCCESS var wg sync.WaitGroup sd.Notify(false, "READY=1") Loop: for { select { case sig := <-sigs: switch sig { case syscall.SIGTERM: logger.Notice("Received SIGTERM, shutting down") break Loop case syscall.SIGHUP: sd.Notify(false, "RELOADING=1") err := backend.Reload() if err != nil { logger.Notice("Could not reload backend: %s", err.Error()) exit = lsb.EXIT_NOTRUNNING break Loop } sd.Notify(false, "READY=1") } case conn := <-sock: wg.Add(1) go func() { defer lsb.Recover() defer wg.Done() handler(conn, backend) }() } } sd.Notify(false, "STOPPING=1") wg.Wait() return exit }