]>
Commit | Line | Data |
---|---|---|
aba5acdf SH |
1 | diff -ur ../pidentd-3.0.12-orig/src/k_linux.c ./src/k_linux.c |
2 | --- ../pidentd-3.0.12-orig/src/k_linux.c Sat Jan 12 00:44:05 2002 | |
3 | +++ ./src/k_linux.c Sat Nov 3 07:51:28 2001 | |
4 | @@ -26,12 +26,65 @@ | |
5 | ||
6 | #include "pidentd.h" | |
7 | ||
8 | +#define NETLINK_TCPDIAG 4 | |
9 | +#define TCPDIAG_GETSOCK 18 | |
10 | + | |
11 | +#include <linux/uio.h> | |
12 | +#include <linux/netlink.h> | |
13 | + | |
14 | +/* Socket identity */ | |
15 | +struct tcpdiag_sockid | |
16 | +{ | |
17 | + __u16 tcpdiag_sport; | |
18 | + __u16 tcpdiag_dport; | |
19 | + __u32 tcpdiag_src[4]; | |
20 | + __u32 tcpdiag_dst[4]; | |
21 | + __u32 tcpdiag_if; | |
22 | + __u32 tcpdiag_cookie[2]; | |
23 | +#define TCPDIAG_NOCOOKIE (~0U) | |
24 | +}; | |
25 | + | |
26 | +/* Request structure */ | |
27 | + | |
28 | +struct tcpdiagreq | |
29 | +{ | |
30 | + __u8 tcpdiag_family; /* Family of addresses. */ | |
31 | + __u8 tcpdiag_src_len; | |
32 | + __u8 tcpdiag_dst_len; | |
33 | + __u8 tcpdiag_ext; /* Query extended information */ | |
34 | + | |
35 | + struct tcpdiag_sockid id; | |
36 | + | |
37 | + __u32 tcpdiag_states; /* States to dump */ | |
38 | + __u32 tcpdiag_dbs; /* Tables to dump (NI) */ | |
39 | +}; | |
40 | + | |
41 | +struct tcpdiagmsg | |
42 | +{ | |
43 | + __u8 tcpdiag_family; | |
44 | + __u8 tcpdiag_state; | |
45 | + __u8 tcpdiag_timer; | |
46 | + __u8 tcpdiag_retrans; | |
47 | + | |
48 | + struct tcpdiag_sockid id; | |
49 | + | |
50 | + __u32 tcpdiag_expires; | |
51 | + __u32 tcpdiag_rqueue; | |
52 | + __u32 tcpdiag_wqueue; | |
53 | + __u32 tcpdiag_uid; | |
54 | + __u32 tcpdiag_inode; | |
55 | +}; | |
56 | + | |
57 | + | |
58 | +int tcpdiag_fd = -1; | |
59 | + | |
60 | /* | |
61 | ** Make sure we are running on a supported OS version | |
62 | */ | |
63 | int | |
64 | ka_init(void) | |
65 | { | |
66 | + tcpdiag_fd = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_TCPDIAG); | |
67 | return 0; /* We always succeed */ | |
68 | } | |
69 | ||
70 | @@ -56,6 +109,144 @@ | |
71 | } | |
72 | ||
73 | ||
74 | + | |
75 | +int k_lookup_tcpdiag(struct kernel *kp) | |
76 | +{ | |
77 | + struct sockaddr_nl nladdr; | |
78 | + struct { | |
79 | + struct nlmsghdr nlh; | |
80 | + struct tcpdiagreq r; | |
81 | + } req; | |
82 | + struct msghdr msg; | |
83 | + char buf[8192]; | |
84 | + struct iovec iov[1]; | |
85 | + struct tcpdiagmsg *r; | |
86 | + static unsigned seqno = 123456; | |
87 | + | |
88 | + memset(&nladdr, 0, sizeof(nladdr)); | |
89 | + nladdr.nl_family = AF_NETLINK; | |
90 | + | |
91 | + req.nlh.nlmsg_len = sizeof(req); | |
92 | + req.nlh.nlmsg_type = TCPDIAG_GETSOCK; | |
93 | + req.nlh.nlmsg_flags = NLM_F_REQUEST; | |
94 | + req.nlh.nlmsg_pid = 0; | |
95 | + req.nlh.nlmsg_seq = ++seqno; | |
96 | + memset(&req.r, 0, sizeof(req.r)); | |
97 | + req.r.tcpdiag_family = AF_INET; | |
98 | + req.r.tcpdiag_states = ~0; | |
99 | + | |
100 | + req.r.id.tcpdiag_dport = kp->remote.sin_port; | |
101 | + req.r.id.tcpdiag_sport = kp->local.sin_port; | |
102 | + req.r.id.tcpdiag_dst[0] = kp->remote.sin_addr.s_addr; | |
103 | + req.r.id.tcpdiag_src[0] = kp->local.sin_addr.s_addr; | |
104 | + req.r.id.tcpdiag_cookie[0] = TCPDIAG_NOCOOKIE; | |
105 | + req.r.id.tcpdiag_cookie[1] = TCPDIAG_NOCOOKIE; | |
106 | + kp->ruid = NO_UID; | |
107 | + | |
108 | + iov[0] = (struct iovec){ &req, sizeof(req) }; | |
109 | + | |
110 | + msg = (struct msghdr) { | |
111 | + (void*)&nladdr, sizeof(nladdr), | |
112 | + iov, 1, | |
113 | + NULL, 0, | |
114 | + 0 | |
115 | + }; | |
116 | + | |
117 | + if (sendmsg(tcpdiag_fd, &msg, 0) < 0) { | |
118 | + if (errno == ECONNREFUSED) { | |
119 | + close(tcpdiag_fd); | |
120 | + tcpdiag_fd = -1; | |
121 | + return 0; | |
122 | + } | |
123 | + syslog(LOG_ERR, "system error on tcpdiag sendmsg: %m"); | |
124 | + return -1; | |
125 | + } | |
126 | + | |
127 | + iov[0] = (struct iovec){ buf, sizeof(buf) }; | |
128 | + | |
129 | + while (1) { | |
130 | + int status; | |
131 | + struct nlmsghdr *h; | |
132 | + | |
133 | + msg = (struct msghdr) { | |
134 | + (void*)&nladdr, sizeof(nladdr), | |
135 | + iov, 1, | |
136 | + NULL, 0, | |
137 | + 0 | |
138 | + }; | |
139 | + | |
140 | + status = recvmsg(tcpdiag_fd, &msg, 0); | |
141 | + | |
142 | + if (status < 0) { | |
143 | + if (errno == EINTR || errno == EAGAIN) | |
144 | + continue; | |
145 | + return -1; | |
146 | + } | |
147 | + if (status == 0) { | |
148 | + return -1; | |
149 | + } | |
150 | + | |
151 | + h = (struct nlmsghdr*)buf; | |
152 | + while (NLMSG_OK(h, status)) { | |
153 | + int err; | |
154 | + | |
155 | + if (/*h->nlmsg_pid != rth->local.nl_pid ||*/ | |
156 | + h->nlmsg_seq != seqno) | |
157 | + goto skip_it; | |
158 | + | |
159 | + if (h->nlmsg_type == NLMSG_DONE) | |
160 | + return -1; | |
161 | + if (h->nlmsg_type == NLMSG_ERROR) { | |
162 | + struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(h); | |
163 | + if (h->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr))) { | |
164 | + return -1; | |
165 | + } else { | |
166 | + errno = -err->error; | |
167 | + if (errno == ECONNREFUSED) { | |
168 | + close(tcpdiag_fd); | |
169 | + tcpdiag_fd = -1; | |
170 | + return 0; | |
171 | + } | |
172 | + if (errno != ENOENT) | |
173 | + syslog(LOG_ERR, "tcpdiag answers: %m"); | |
174 | + } | |
175 | + return -1; | |
176 | + } | |
177 | + | |
178 | + r = NLMSG_DATA(h); | |
179 | + | |
180 | + /* Lookup _may_ return listening socket, if no | |
181 | + * better matches are found. */ | |
182 | + if (r->id.tcpdiag_dport == kp->remote.sin_port && | |
183 | + r->id.tcpdiag_dst[0] == kp->remote.sin_addr.s_addr) { | |
184 | + kp->ruid = r->tcpdiag_uid; | |
185 | + if (!r->tcpdiag_inode && !r->tcpdiag_uid) { | |
186 | + /* _NEVER_ return "root" for closed | |
187 | + * sockets. Otherwise people think | |
188 | + * that it is sysadmin who abuses their | |
189 | + * poor ircd. :-) */ | |
190 | + syslog(LOG_NOTICE, | |
191 | + "Req for stale socket(%d) %d from %x/%d", | |
192 | + r->tcpdiag_state, ntohs(r->id.tcpdiag_sport), | |
193 | + r->id.tcpdiag_dst[0], ntohs(r->id.tcpdiag_dport)); | |
194 | + return -1; | |
195 | + } | |
196 | + return 1; | |
197 | + } | |
198 | + | |
199 | + return -1; | |
200 | + | |
201 | +skip_it: | |
202 | + h = NLMSG_NEXT(h, status); | |
203 | + } | |
204 | + if ((msg.msg_flags & MSG_TRUNC) || status) { | |
205 | + syslog(LOG_ERR, "truncated tcp_diag message"); | |
206 | + return -1; | |
207 | + } | |
208 | + } | |
209 | +} | |
210 | + | |
211 | + | |
212 | int | |
213 | ka_lookup(void *vp, struct kernel *kp) | |
214 | { | |
215 | @@ -64,16 +255,23 @@ | |
216 | long r_laddr, r_raddr, myladdr, myraddr; | |
217 | int r_lport, r_rport, mylport, myrport; | |
218 | int euid; | |
219 | - | |
220 | - | |
221 | + | |
222 | + if (tcpdiag_fd >= 0) { | |
223 | + int res; | |
224 | + if ((res = k_lookup_tcpdiag(kp)) != 0) | |
225 | + return res; | |
226 | + syslog(LOG_ERR, "tcp_diag is not loaded, fallback to proc"); | |
227 | + } | |
228 | + | |
229 | + | |
230 | r_rport = ntohs(kp->remote.sin_port); | |
231 | r_lport = ntohs(kp->local.sin_port); | |
232 | r_raddr = kp->remote.sin_addr.s_addr; | |
233 | r_laddr = kp->local.sin_addr.s_addr; | |
234 | + kp->ruid = NO_UID; | |
235 | ||
236 | fp = (FILE *) vp; | |
237 | ||
238 | - kp->ruid = NO_UID; | |
239 | rewind(fp); | |
240 | ||
241 | /* eat header */ | |
242 | @@ -82,13 +280,26 @@ | |
243 | ||
244 | while (fgets(buf, sizeof(buf)-1, fp) != NULL) | |
245 | { | |
246 | - if (sscanf(buf, "%*d: %lx:%x %lx:%x %*x %*x:%*x %*x:%*x %*x %d %*d %*d", | |
247 | - &myladdr, &mylport, &myraddr, &myrport, &euid) == 5) | |
248 | + int state, ino; | |
249 | + if (sscanf(buf, "%*d: %x:%x %x:%x %x %*x:%*x %*x:%*x %*x %d %*d %u", | |
250 | + &myladdr, &mylport, &myraddr, &myrport, | |
251 | + &state, &euid, &ino) == 7) | |
252 | { | |
253 | if (myladdr == r_laddr && mylport == r_lport && | |
254 | myraddr == r_raddr && myrport == r_rport) | |
255 | { | |
256 | kp->euid = euid; | |
257 | + if (ino == 0 && euid == 0) | |
258 | + { | |
259 | + /* _NEVER_ return "root" for closed | |
260 | + * sockets. Otherwise people think | |
261 | + * that it is sysadmin who abuses their | |
262 | + * poor ircd. :-) */ | |
263 | + syslog(LOG_NOTICE, | |
264 | + "Req for stale socket(%d) %d from %x/%d", | |
265 | + state, r_rport, r_raddr, r_lport); | |
266 | + return -1; | |
267 | + } | |
268 | return 1; | |
269 | } | |
270 | } |