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
134
135
136
137
138
139
140
|
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.Debug("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()
}
}()
disable_nss_module()
err = backend.Init()
if err != nil {
logger.Err("%s", err.Error())
sd.Notify(false, "STOPPING=1")
return lsb.EXIT_FAILURE
}
defer backend.Close()
socket, err = get_socket()
if err != nil {
logger.Err("%s", err.Error())
sd.Notify(false, "STOPPING=1")
return lsb.EXIT_NOTRUNNING
}
sigs := make(chan os.Signal, 1)
signal.Notify(sigs, syscall.SIGTERM, syscall.SIGHUP)
sock := make(chan *net.UnixConn, 1)
go func() {
defer lsb.Recover()
for {
conn, err := socket.Accept()
if err != nil {
logger.Notice("Accept: %s", err.Error())
}
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:
break Loop
case syscall.SIGHUP:
sd.Notify(false, "RELOADING=1")
err := backend.Reload()
if err != nil {
logger.Notice("Reload: %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
}
|