1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
|
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
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
}
defer socket.Close()
sock := make(chan *net.UnixConn)
go func() {
defer lsb.Recover()
for {
conn, err := socket.Accept()
if err != nil {
logger.Notice("%v", err)
}
if conn != nil {
sock <- conn.(*net.UnixConn)
}
}
}()
var wg sync.WaitGroup
defer wg.Wait()
defer sd.Notify(false, "STOPPING=1")
sd.Notify(false, "READY=1")
for {
select {
case sig := <-sigs:
switch sig {
case syscall.SIGTERM:
logger.Notice("Received SIGTERM, shutting down")
return lsb.EXIT_SUCCESS
case syscall.SIGHUP:
sd.Notify(false, "RELOADING=1")
err := backend.Reload()
if err != nil {
logger.Notice("Could not reload backend: %s", err.Error())
return lsb.EXIT_NOTRUNNING
}
sd.Notify(false, "READY=1")
}
case conn := <-sock:
wg.Add(1)
go func() {
defer lsb.Recover()
defer wg.Done()
handler(conn, backend)
}()
}
}
panic("not reached")
}
|