Blame


1 d93ecf7d 2022-12-14 stsp /*
2 d93ecf7d 2022-12-14 stsp * Copyright (c) 2022 Stefan Sperling <stsp@openbsd.org>
3 d93ecf7d 2022-12-14 stsp *
4 d93ecf7d 2022-12-14 stsp * Permission to use, copy, modify, and distribute this software for any
5 d93ecf7d 2022-12-14 stsp * purpose with or without fee is hereby granted, provided that the above
6 d93ecf7d 2022-12-14 stsp * copyright notice and this permission notice appear in all copies.
7 d93ecf7d 2022-12-14 stsp *
8 d93ecf7d 2022-12-14 stsp * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 d93ecf7d 2022-12-14 stsp * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 d93ecf7d 2022-12-14 stsp * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 d93ecf7d 2022-12-14 stsp * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 d93ecf7d 2022-12-14 stsp * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 d93ecf7d 2022-12-14 stsp * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 d93ecf7d 2022-12-14 stsp * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 d93ecf7d 2022-12-14 stsp */
16 d93ecf7d 2022-12-14 stsp
17 d93ecf7d 2022-12-14 stsp #include <sys/types.h>
18 d93ecf7d 2022-12-14 stsp #include <sys/queue.h>
19 d93ecf7d 2022-12-14 stsp #include <sys/socket.h>
20 d93ecf7d 2022-12-14 stsp #include <sys/uio.h>
21 d93ecf7d 2022-12-14 stsp
22 d93ecf7d 2022-12-14 stsp #include <errno.h>
23 d93ecf7d 2022-12-14 stsp #include <event.h>
24 d93ecf7d 2022-12-14 stsp #include <siphash.h>
25 d93ecf7d 2022-12-14 stsp #include <stdint.h>
26 d93ecf7d 2022-12-14 stsp #include <stdio.h>
27 d93ecf7d 2022-12-14 stsp #include <stdlib.h>
28 d93ecf7d 2022-12-14 stsp #include <string.h>
29 d93ecf7d 2022-12-14 stsp #include <imsg.h>
30 d93ecf7d 2022-12-14 stsp #include <limits.h>
31 d93ecf7d 2022-12-14 stsp #include <sha1.h>
32 69c6accf 2023-02-04 op #include <sha2.h>
33 d93ecf7d 2022-12-14 stsp #include <signal.h>
34 d93ecf7d 2022-12-14 stsp #include <unistd.h>
35 d93ecf7d 2022-12-14 stsp
36 d93ecf7d 2022-12-14 stsp #include "got_error.h"
37 d93ecf7d 2022-12-14 stsp
38 d93ecf7d 2022-12-14 stsp #include "gotd.h"
39 d93ecf7d 2022-12-14 stsp #include "log.h"
40 d93ecf7d 2022-12-14 stsp #include "listen.h"
41 d93ecf7d 2022-12-14 stsp
42 d93ecf7d 2022-12-14 stsp #ifndef nitems
43 d93ecf7d 2022-12-14 stsp #define nitems(_a) (sizeof((_a)) / sizeof((_a)[0]))
44 d93ecf7d 2022-12-14 stsp #endif
45 d93ecf7d 2022-12-14 stsp
46 d93ecf7d 2022-12-14 stsp struct gotd_listen_client {
47 d93ecf7d 2022-12-14 stsp STAILQ_ENTRY(gotd_listen_client) entry;
48 d93ecf7d 2022-12-14 stsp uint32_t id;
49 d93ecf7d 2022-12-14 stsp int fd;
50 7a0564e3 2022-12-30 stsp uid_t euid;
51 d93ecf7d 2022-12-14 stsp };
52 d93ecf7d 2022-12-14 stsp STAILQ_HEAD(gotd_listen_clients, gotd_listen_client);
53 d93ecf7d 2022-12-14 stsp
54 d93ecf7d 2022-12-14 stsp static struct gotd_listen_clients gotd_listen_clients[GOTD_CLIENT_TABLE_SIZE];
55 d93ecf7d 2022-12-14 stsp static SIPHASH_KEY clients_hash_key;
56 d93ecf7d 2022-12-14 stsp static volatile int listen_client_cnt;
57 d93ecf7d 2022-12-14 stsp static int inflight;
58 d93ecf7d 2022-12-14 stsp
59 7a0564e3 2022-12-30 stsp struct gotd_uid_connection_counter {
60 7a0564e3 2022-12-30 stsp STAILQ_ENTRY(gotd_uid_connection_counter) entry;
61 7a0564e3 2022-12-30 stsp uid_t euid;
62 7a0564e3 2022-12-30 stsp int nconnections;
63 7a0564e3 2022-12-30 stsp };
64 7a0564e3 2022-12-30 stsp STAILQ_HEAD(gotd_client_uids, gotd_uid_connection_counter);
65 7a0564e3 2022-12-30 stsp static struct gotd_client_uids gotd_client_uids[GOTD_CLIENT_TABLE_SIZE];
66 7a0564e3 2022-12-30 stsp static SIPHASH_KEY uid_hash_key;
67 7a0564e3 2022-12-30 stsp
68 d93ecf7d 2022-12-14 stsp static struct {
69 d93ecf7d 2022-12-14 stsp pid_t pid;
70 d93ecf7d 2022-12-14 stsp const char *title;
71 d93ecf7d 2022-12-14 stsp int fd;
72 d93ecf7d 2022-12-14 stsp struct gotd_imsgev iev;
73 d93ecf7d 2022-12-14 stsp struct gotd_imsgev pause;
74 40b85cca 2023-01-03 stsp struct gotd_uid_connection_limit *connection_limits;
75 40b85cca 2023-01-03 stsp size_t nconnection_limits;
76 d93ecf7d 2022-12-14 stsp } gotd_listen;
77 d93ecf7d 2022-12-14 stsp
78 d93ecf7d 2022-12-14 stsp static int inflight;
79 d93ecf7d 2022-12-14 stsp
80 d93ecf7d 2022-12-14 stsp static void listen_shutdown(void);
81 d93ecf7d 2022-12-14 stsp
82 d93ecf7d 2022-12-14 stsp static void
83 d93ecf7d 2022-12-14 stsp listen_sighdlr(int sig, short event, void *arg)
84 d93ecf7d 2022-12-14 stsp {
85 d93ecf7d 2022-12-14 stsp /*
86 d93ecf7d 2022-12-14 stsp * Normal signal handler rules don't apply because libevent
87 d93ecf7d 2022-12-14 stsp * decouples for us.
88 d93ecf7d 2022-12-14 stsp */
89 d93ecf7d 2022-12-14 stsp
90 d93ecf7d 2022-12-14 stsp switch (sig) {
91 d93ecf7d 2022-12-14 stsp case SIGHUP:
92 d93ecf7d 2022-12-14 stsp break;
93 d93ecf7d 2022-12-14 stsp case SIGUSR1:
94 d93ecf7d 2022-12-14 stsp break;
95 d93ecf7d 2022-12-14 stsp case SIGTERM:
96 d93ecf7d 2022-12-14 stsp case SIGINT:
97 d93ecf7d 2022-12-14 stsp listen_shutdown();
98 d93ecf7d 2022-12-14 stsp /* NOTREACHED */
99 d93ecf7d 2022-12-14 stsp break;
100 d93ecf7d 2022-12-14 stsp default:
101 d93ecf7d 2022-12-14 stsp fatalx("unexpected signal");
102 d93ecf7d 2022-12-14 stsp }
103 d93ecf7d 2022-12-14 stsp }
104 d93ecf7d 2022-12-14 stsp
105 d93ecf7d 2022-12-14 stsp static uint64_t
106 d93ecf7d 2022-12-14 stsp client_hash(uint32_t client_id)
107 d93ecf7d 2022-12-14 stsp {
108 d93ecf7d 2022-12-14 stsp return SipHash24(&clients_hash_key, &client_id, sizeof(client_id));
109 d93ecf7d 2022-12-14 stsp }
110 d93ecf7d 2022-12-14 stsp
111 d93ecf7d 2022-12-14 stsp static void
112 d93ecf7d 2022-12-14 stsp add_client(struct gotd_listen_client *client)
113 d93ecf7d 2022-12-14 stsp {
114 d93ecf7d 2022-12-14 stsp uint64_t slot = client_hash(client->id) % nitems(gotd_listen_clients);
115 d93ecf7d 2022-12-14 stsp STAILQ_INSERT_HEAD(&gotd_listen_clients[slot], client, entry);
116 d93ecf7d 2022-12-14 stsp listen_client_cnt++;
117 d93ecf7d 2022-12-14 stsp }
118 d93ecf7d 2022-12-14 stsp
119 d93ecf7d 2022-12-14 stsp static struct gotd_listen_client *
120 d93ecf7d 2022-12-14 stsp find_client(uint32_t client_id)
121 d93ecf7d 2022-12-14 stsp {
122 d93ecf7d 2022-12-14 stsp uint64_t slot;
123 d93ecf7d 2022-12-14 stsp struct gotd_listen_client *c;
124 d93ecf7d 2022-12-14 stsp
125 d93ecf7d 2022-12-14 stsp slot = client_hash(client_id) % nitems(gotd_listen_clients);
126 d93ecf7d 2022-12-14 stsp STAILQ_FOREACH(c, &gotd_listen_clients[slot], entry) {
127 d93ecf7d 2022-12-14 stsp if (c->id == client_id)
128 d93ecf7d 2022-12-14 stsp return c;
129 d93ecf7d 2022-12-14 stsp }
130 d93ecf7d 2022-12-14 stsp
131 d93ecf7d 2022-12-14 stsp return NULL;
132 d93ecf7d 2022-12-14 stsp }
133 d93ecf7d 2022-12-14 stsp
134 d93ecf7d 2022-12-14 stsp static uint32_t
135 d93ecf7d 2022-12-14 stsp get_client_id(void)
136 d93ecf7d 2022-12-14 stsp {
137 d93ecf7d 2022-12-14 stsp int duplicate = 0;
138 d93ecf7d 2022-12-14 stsp uint32_t id;
139 d93ecf7d 2022-12-14 stsp
140 d93ecf7d 2022-12-14 stsp do {
141 d93ecf7d 2022-12-14 stsp id = arc4random();
142 d93ecf7d 2022-12-14 stsp duplicate = (find_client(id) != NULL);
143 d93ecf7d 2022-12-14 stsp } while (duplicate || id == 0);
144 d93ecf7d 2022-12-14 stsp
145 d93ecf7d 2022-12-14 stsp return id;
146 7a0564e3 2022-12-30 stsp }
147 7a0564e3 2022-12-30 stsp
148 7a0564e3 2022-12-30 stsp static uint64_t
149 7a0564e3 2022-12-30 stsp uid_hash(uid_t euid)
150 7a0564e3 2022-12-30 stsp {
151 7a0564e3 2022-12-30 stsp return SipHash24(&uid_hash_key, &euid, sizeof(euid));
152 7a0564e3 2022-12-30 stsp }
153 7a0564e3 2022-12-30 stsp
154 7a0564e3 2022-12-30 stsp static void
155 7a0564e3 2022-12-30 stsp add_uid_connection_counter(struct gotd_uid_connection_counter *counter)
156 7a0564e3 2022-12-30 stsp {
157 7a0564e3 2022-12-30 stsp uint64_t slot = uid_hash(counter->euid) % nitems(gotd_client_uids);
158 7a0564e3 2022-12-30 stsp STAILQ_INSERT_HEAD(&gotd_client_uids[slot], counter, entry);
159 7a0564e3 2022-12-30 stsp }
160 7a0564e3 2022-12-30 stsp
161 7a0564e3 2022-12-30 stsp static void
162 7a0564e3 2022-12-30 stsp remove_uid_connection_counter(struct gotd_uid_connection_counter *counter)
163 7a0564e3 2022-12-30 stsp {
164 7a0564e3 2022-12-30 stsp uint64_t slot = uid_hash(counter->euid) % nitems(gotd_client_uids);
165 7a0564e3 2022-12-30 stsp STAILQ_REMOVE(&gotd_client_uids[slot], counter,
166 7a0564e3 2022-12-30 stsp gotd_uid_connection_counter, entry);
167 7a0564e3 2022-12-30 stsp }
168 7a0564e3 2022-12-30 stsp
169 7a0564e3 2022-12-30 stsp static struct gotd_uid_connection_counter *
170 7a0564e3 2022-12-30 stsp find_uid_connection_counter(uid_t euid)
171 7a0564e3 2022-12-30 stsp {
172 7a0564e3 2022-12-30 stsp uint64_t slot;
173 7a0564e3 2022-12-30 stsp struct gotd_uid_connection_counter *c;
174 7a0564e3 2022-12-30 stsp
175 7a0564e3 2022-12-30 stsp slot = uid_hash(euid) % nitems(gotd_client_uids);
176 7a0564e3 2022-12-30 stsp STAILQ_FOREACH(c, &gotd_client_uids[slot], entry) {
177 7a0564e3 2022-12-30 stsp if (c->euid == euid)
178 7a0564e3 2022-12-30 stsp return c;
179 40b85cca 2023-01-03 stsp }
180 40b85cca 2023-01-03 stsp
181 40b85cca 2023-01-03 stsp return NULL;
182 40b85cca 2023-01-03 stsp }
183 40b85cca 2023-01-03 stsp
184 40b85cca 2023-01-03 stsp struct gotd_uid_connection_limit *
185 40b85cca 2023-01-03 stsp gotd_find_uid_connection_limit(struct gotd_uid_connection_limit *limits,
186 40b85cca 2023-01-03 stsp size_t nlimits, uid_t uid)
187 40b85cca 2023-01-03 stsp {
188 40b85cca 2023-01-03 stsp /* This array is always sorted to allow for binary search. */
189 40b85cca 2023-01-03 stsp int i, left = 0, right = nlimits - 1;
190 40b85cca 2023-01-03 stsp
191 40b85cca 2023-01-03 stsp while (left <= right) {
192 40b85cca 2023-01-03 stsp i = ((left + right) / 2);
193 40b85cca 2023-01-03 stsp if (limits[i].uid == uid)
194 40b85cca 2023-01-03 stsp return &limits[i];
195 40b85cca 2023-01-03 stsp if (limits[i].uid > uid)
196 40b85cca 2023-01-03 stsp left = i + 1;
197 40b85cca 2023-01-03 stsp else
198 40b85cca 2023-01-03 stsp right = i - 1;
199 7a0564e3 2022-12-30 stsp }
200 7a0564e3 2022-12-30 stsp
201 7a0564e3 2022-12-30 stsp return NULL;
202 d93ecf7d 2022-12-14 stsp }
203 d93ecf7d 2022-12-14 stsp
204 d93ecf7d 2022-12-14 stsp static const struct got_error *
205 d93ecf7d 2022-12-14 stsp disconnect(struct gotd_listen_client *client)
206 d93ecf7d 2022-12-14 stsp {
207 7a0564e3 2022-12-30 stsp struct gotd_uid_connection_counter *counter;
208 d93ecf7d 2022-12-14 stsp uint64_t slot;
209 d93ecf7d 2022-12-14 stsp int client_fd;
210 d93ecf7d 2022-12-14 stsp
211 d93ecf7d 2022-12-14 stsp log_debug("client on fd %d disconnecting", client->fd);
212 d93ecf7d 2022-12-14 stsp
213 d93ecf7d 2022-12-14 stsp slot = client_hash(client->id) % nitems(gotd_listen_clients);
214 d93ecf7d 2022-12-14 stsp STAILQ_REMOVE(&gotd_listen_clients[slot], client,
215 d93ecf7d 2022-12-14 stsp gotd_listen_client, entry);
216 7a0564e3 2022-12-30 stsp
217 7a0564e3 2022-12-30 stsp counter = find_uid_connection_counter(client->euid);
218 7a0564e3 2022-12-30 stsp if (counter) {
219 7a0564e3 2022-12-30 stsp if (counter->nconnections > 0)
220 7a0564e3 2022-12-30 stsp counter->nconnections--;
221 7a0564e3 2022-12-30 stsp if (counter->nconnections == 0) {
222 7a0564e3 2022-12-30 stsp remove_uid_connection_counter(counter);
223 7a0564e3 2022-12-30 stsp free(counter);
224 7a0564e3 2022-12-30 stsp }
225 7a0564e3 2022-12-30 stsp }
226 7a0564e3 2022-12-30 stsp
227 d93ecf7d 2022-12-14 stsp client_fd = client->fd;
228 d93ecf7d 2022-12-14 stsp free(client);
229 d93ecf7d 2022-12-14 stsp inflight--;
230 d93ecf7d 2022-12-14 stsp listen_client_cnt--;
231 d93ecf7d 2022-12-14 stsp if (close(client_fd) == -1)
232 d93ecf7d 2022-12-14 stsp return got_error_from_errno("close");
233 d93ecf7d 2022-12-14 stsp
234 d93ecf7d 2022-12-14 stsp return NULL;
235 d93ecf7d 2022-12-14 stsp }
236 d93ecf7d 2022-12-14 stsp
237 d93ecf7d 2022-12-14 stsp static int
238 d93ecf7d 2022-12-14 stsp accept_reserve(int fd, struct sockaddr *addr, socklen_t *addrlen,
239 d93ecf7d 2022-12-14 stsp int reserve, volatile int *counter)
240 d93ecf7d 2022-12-14 stsp {
241 d93ecf7d 2022-12-14 stsp int ret;
242 d93ecf7d 2022-12-14 stsp
243 d93ecf7d 2022-12-14 stsp if (getdtablecount() + reserve +
244 d93ecf7d 2022-12-14 stsp ((*counter + 1) * GOTD_FD_NEEDED) >= getdtablesize()) {
245 d93ecf7d 2022-12-14 stsp log_debug("inflight fds exceeded");
246 d93ecf7d 2022-12-14 stsp errno = EMFILE;
247 d93ecf7d 2022-12-14 stsp return -1;
248 d93ecf7d 2022-12-14 stsp }
249 d93ecf7d 2022-12-14 stsp
250 d93ecf7d 2022-12-14 stsp if ((ret = accept4(fd, addr, addrlen,
251 d93ecf7d 2022-12-14 stsp SOCK_NONBLOCK | SOCK_CLOEXEC)) > -1) {
252 d93ecf7d 2022-12-14 stsp (*counter)++;
253 d93ecf7d 2022-12-14 stsp }
254 d93ecf7d 2022-12-14 stsp
255 d93ecf7d 2022-12-14 stsp return ret;
256 d93ecf7d 2022-12-14 stsp }
257 d93ecf7d 2022-12-14 stsp
258 d93ecf7d 2022-12-14 stsp static void
259 d93ecf7d 2022-12-14 stsp gotd_accept_paused(int fd, short event, void *arg)
260 d93ecf7d 2022-12-14 stsp {
261 d93ecf7d 2022-12-14 stsp event_add(&gotd_listen.iev.ev, NULL);
262 d93ecf7d 2022-12-14 stsp }
263 d93ecf7d 2022-12-14 stsp
264 d93ecf7d 2022-12-14 stsp static void
265 d93ecf7d 2022-12-14 stsp gotd_accept(int fd, short event, void *arg)
266 d93ecf7d 2022-12-14 stsp {
267 d93ecf7d 2022-12-14 stsp struct gotd_imsgev *iev = arg;
268 d93ecf7d 2022-12-14 stsp struct sockaddr_storage ss;
269 d93ecf7d 2022-12-14 stsp struct timeval backoff;
270 d93ecf7d 2022-12-14 stsp socklen_t len;
271 d93ecf7d 2022-12-14 stsp int s = -1;
272 d93ecf7d 2022-12-14 stsp struct gotd_listen_client *client = NULL;
273 7a0564e3 2022-12-30 stsp struct gotd_uid_connection_counter *counter = NULL;
274 d93ecf7d 2022-12-14 stsp struct gotd_imsg_connect iconn;
275 365cf0f3 2022-12-29 stsp uid_t euid;
276 365cf0f3 2022-12-29 stsp gid_t egid;
277 d93ecf7d 2022-12-14 stsp
278 d93ecf7d 2022-12-14 stsp backoff.tv_sec = 1;
279 d93ecf7d 2022-12-14 stsp backoff.tv_usec = 0;
280 d93ecf7d 2022-12-14 stsp
281 d93ecf7d 2022-12-14 stsp if (event_add(&gotd_listen.iev.ev, NULL) == -1) {
282 d93ecf7d 2022-12-14 stsp log_warn("event_add");
283 d93ecf7d 2022-12-14 stsp return;
284 d93ecf7d 2022-12-14 stsp }
285 d93ecf7d 2022-12-14 stsp if (event & EV_TIMEOUT)
286 d93ecf7d 2022-12-14 stsp return;
287 d93ecf7d 2022-12-14 stsp
288 d93ecf7d 2022-12-14 stsp len = sizeof(ss);
289 d93ecf7d 2022-12-14 stsp
290 d93ecf7d 2022-12-14 stsp /* Other backoff conditions apart from EMFILE/ENFILE? */
291 d93ecf7d 2022-12-14 stsp s = accept_reserve(fd, (struct sockaddr *)&ss, &len, GOTD_FD_RESERVE,
292 d93ecf7d 2022-12-14 stsp &inflight);
293 d93ecf7d 2022-12-14 stsp if (s == -1) {
294 d93ecf7d 2022-12-14 stsp switch (errno) {
295 d93ecf7d 2022-12-14 stsp case EINTR:
296 d93ecf7d 2022-12-14 stsp case EWOULDBLOCK:
297 d93ecf7d 2022-12-14 stsp case ECONNABORTED:
298 d93ecf7d 2022-12-14 stsp return;
299 d93ecf7d 2022-12-14 stsp case EMFILE:
300 d93ecf7d 2022-12-14 stsp case ENFILE:
301 d93ecf7d 2022-12-14 stsp event_del(&gotd_listen.iev.ev);
302 d93ecf7d 2022-12-14 stsp evtimer_add(&gotd_listen.pause.ev, &backoff);
303 d93ecf7d 2022-12-14 stsp return;
304 d93ecf7d 2022-12-14 stsp default:
305 d93ecf7d 2022-12-14 stsp log_warn("accept");
306 d93ecf7d 2022-12-14 stsp return;
307 d93ecf7d 2022-12-14 stsp }
308 d93ecf7d 2022-12-14 stsp }
309 d93ecf7d 2022-12-14 stsp
310 d93ecf7d 2022-12-14 stsp if (listen_client_cnt >= GOTD_MAXCLIENTS)
311 365cf0f3 2022-12-29 stsp goto err;
312 365cf0f3 2022-12-29 stsp
313 365cf0f3 2022-12-29 stsp if (getpeereid(s, &euid, &egid) == -1) {
314 365cf0f3 2022-12-29 stsp log_warn("getpeerid");
315 d93ecf7d 2022-12-14 stsp goto err;
316 365cf0f3 2022-12-29 stsp }
317 d93ecf7d 2022-12-14 stsp
318 7a0564e3 2022-12-30 stsp counter = find_uid_connection_counter(euid);
319 7a0564e3 2022-12-30 stsp if (counter == NULL) {
320 7a0564e3 2022-12-30 stsp counter = calloc(1, sizeof(*counter));
321 7a0564e3 2022-12-30 stsp if (counter == NULL) {
322 7a0564e3 2022-12-30 stsp log_warn("%s: calloc", __func__);
323 7a0564e3 2022-12-30 stsp goto err;
324 7a0564e3 2022-12-30 stsp }
325 7a0564e3 2022-12-30 stsp counter->euid = euid;
326 7a0564e3 2022-12-30 stsp counter->nconnections = 1;
327 7a0564e3 2022-12-30 stsp add_uid_connection_counter(counter);
328 7a0564e3 2022-12-30 stsp } else {
329 40b85cca 2023-01-03 stsp int max_connections = GOTD_MAX_CONN_PER_UID;
330 40b85cca 2023-01-03 stsp struct gotd_uid_connection_limit *limit;
331 40b85cca 2023-01-03 stsp
332 40b85cca 2023-01-03 stsp limit = gotd_find_uid_connection_limit(
333 40b85cca 2023-01-03 stsp gotd_listen.connection_limits,
334 40b85cca 2023-01-03 stsp gotd_listen.nconnection_limits, euid);
335 40b85cca 2023-01-03 stsp if (limit)
336 40b85cca 2023-01-03 stsp max_connections = limit->max_connections;
337 40b85cca 2023-01-03 stsp
338 40b85cca 2023-01-03 stsp if (counter->nconnections >= max_connections) {
339 7a0564e3 2022-12-30 stsp log_warnx("maximum connections exceeded for uid %d",
340 7a0564e3 2022-12-30 stsp euid);
341 7a0564e3 2022-12-30 stsp goto err;
342 7a0564e3 2022-12-30 stsp }
343 7a0564e3 2022-12-30 stsp counter->nconnections++;
344 7a0564e3 2022-12-30 stsp }
345 7a0564e3 2022-12-30 stsp
346 d93ecf7d 2022-12-14 stsp client = calloc(1, sizeof(*client));
347 d93ecf7d 2022-12-14 stsp if (client == NULL) {
348 d93ecf7d 2022-12-14 stsp log_warn("%s: calloc", __func__);
349 d93ecf7d 2022-12-14 stsp goto err;
350 d93ecf7d 2022-12-14 stsp }
351 d93ecf7d 2022-12-14 stsp client->id = get_client_id();
352 d93ecf7d 2022-12-14 stsp client->fd = s;
353 7a0564e3 2022-12-30 stsp client->euid = euid;
354 d93ecf7d 2022-12-14 stsp s = -1;
355 d93ecf7d 2022-12-14 stsp add_client(client);
356 365cf0f3 2022-12-29 stsp log_debug("%s: new client connected on fd %d uid %d gid %d", __func__,
357 365cf0f3 2022-12-29 stsp client->fd, euid, egid);
358 d93ecf7d 2022-12-14 stsp
359 d93ecf7d 2022-12-14 stsp memset(&iconn, 0, sizeof(iconn));
360 d93ecf7d 2022-12-14 stsp iconn.client_id = client->id;
361 365cf0f3 2022-12-29 stsp iconn.euid = euid;
362 365cf0f3 2022-12-29 stsp iconn.egid = egid;
363 d93ecf7d 2022-12-14 stsp s = dup(client->fd);
364 d93ecf7d 2022-12-14 stsp if (s == -1) {
365 d93ecf7d 2022-12-14 stsp log_warn("%s: dup", __func__);
366 d93ecf7d 2022-12-14 stsp goto err;
367 d93ecf7d 2022-12-14 stsp }
368 d93ecf7d 2022-12-14 stsp if (gotd_imsg_compose_event(iev, GOTD_IMSG_CONNECT, PROC_LISTEN, s,
369 d93ecf7d 2022-12-14 stsp &iconn, sizeof(iconn)) == -1) {
370 d93ecf7d 2022-12-14 stsp log_warn("imsg compose CONNECT");
371 d93ecf7d 2022-12-14 stsp goto err;
372 d93ecf7d 2022-12-14 stsp }
373 d93ecf7d 2022-12-14 stsp
374 d93ecf7d 2022-12-14 stsp return;
375 d93ecf7d 2022-12-14 stsp err:
376 d93ecf7d 2022-12-14 stsp inflight--;
377 d93ecf7d 2022-12-14 stsp if (client)
378 d93ecf7d 2022-12-14 stsp disconnect(client);
379 d93ecf7d 2022-12-14 stsp if (s != -1)
380 d93ecf7d 2022-12-14 stsp close(s);
381 d93ecf7d 2022-12-14 stsp }
382 d93ecf7d 2022-12-14 stsp
383 d93ecf7d 2022-12-14 stsp static const struct got_error *
384 d93ecf7d 2022-12-14 stsp recv_disconnect(struct imsg *imsg)
385 d93ecf7d 2022-12-14 stsp {
386 d93ecf7d 2022-12-14 stsp struct gotd_imsg_disconnect idisconnect;
387 d93ecf7d 2022-12-14 stsp size_t datalen;
388 d93ecf7d 2022-12-14 stsp struct gotd_listen_client *client = NULL;
389 d93ecf7d 2022-12-14 stsp
390 d93ecf7d 2022-12-14 stsp datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
391 d93ecf7d 2022-12-14 stsp if (datalen != sizeof(idisconnect))
392 d93ecf7d 2022-12-14 stsp return got_error(GOT_ERR_PRIVSEP_LEN);
393 d93ecf7d 2022-12-14 stsp memcpy(&idisconnect, imsg->data, sizeof(idisconnect));
394 d93ecf7d 2022-12-14 stsp
395 d93ecf7d 2022-12-14 stsp log_debug("client disconnecting");
396 d93ecf7d 2022-12-14 stsp
397 d93ecf7d 2022-12-14 stsp client = find_client(idisconnect.client_id);
398 d93ecf7d 2022-12-14 stsp if (client == NULL)
399 d93ecf7d 2022-12-14 stsp return got_error(GOT_ERR_CLIENT_ID);
400 d93ecf7d 2022-12-14 stsp
401 d93ecf7d 2022-12-14 stsp return disconnect(client);
402 d93ecf7d 2022-12-14 stsp }
403 d93ecf7d 2022-12-14 stsp
404 d93ecf7d 2022-12-14 stsp static void
405 d93ecf7d 2022-12-14 stsp listen_dispatch(int fd, short event, void *arg)
406 d93ecf7d 2022-12-14 stsp {
407 d93ecf7d 2022-12-14 stsp const struct got_error *err = NULL;
408 d93ecf7d 2022-12-14 stsp struct gotd_imsgev *iev = arg;
409 d93ecf7d 2022-12-14 stsp struct imsgbuf *ibuf = &iev->ibuf;
410 d93ecf7d 2022-12-14 stsp struct imsg imsg;
411 d93ecf7d 2022-12-14 stsp ssize_t n;
412 d93ecf7d 2022-12-14 stsp int shut = 0;
413 d93ecf7d 2022-12-14 stsp
414 d93ecf7d 2022-12-14 stsp if (event & EV_READ) {
415 d93ecf7d 2022-12-14 stsp if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN)
416 d93ecf7d 2022-12-14 stsp fatal("imsg_read error");
417 d93ecf7d 2022-12-14 stsp if (n == 0) /* Connection closed. */
418 d93ecf7d 2022-12-14 stsp shut = 1;
419 d93ecf7d 2022-12-14 stsp }
420 d93ecf7d 2022-12-14 stsp
421 d93ecf7d 2022-12-14 stsp if (event & EV_WRITE) {
422 d93ecf7d 2022-12-14 stsp n = msgbuf_write(&ibuf->w);
423 d93ecf7d 2022-12-14 stsp if (n == -1 && errno != EAGAIN)
424 d93ecf7d 2022-12-14 stsp fatal("msgbuf_write");
425 d93ecf7d 2022-12-14 stsp if (n == 0) /* Connection closed. */
426 d93ecf7d 2022-12-14 stsp shut = 1;
427 d93ecf7d 2022-12-14 stsp }
428 d93ecf7d 2022-12-14 stsp
429 d93ecf7d 2022-12-14 stsp for (;;) {
430 d93ecf7d 2022-12-14 stsp if ((n = imsg_get(ibuf, &imsg)) == -1)
431 d93ecf7d 2022-12-14 stsp fatal("%s: imsg_get", __func__);
432 d93ecf7d 2022-12-14 stsp if (n == 0) /* No more messages. */
433 d93ecf7d 2022-12-14 stsp break;
434 d93ecf7d 2022-12-14 stsp
435 d93ecf7d 2022-12-14 stsp switch (imsg.hdr.type) {
436 d93ecf7d 2022-12-14 stsp case GOTD_IMSG_DISCONNECT:
437 d93ecf7d 2022-12-14 stsp err = recv_disconnect(&imsg);
438 d93ecf7d 2022-12-14 stsp if (err)
439 d93ecf7d 2022-12-14 stsp log_warnx("%s: disconnect: %s",
440 d93ecf7d 2022-12-14 stsp gotd_listen.title, err->msg);
441 d93ecf7d 2022-12-14 stsp break;
442 d93ecf7d 2022-12-14 stsp default:
443 d93ecf7d 2022-12-14 stsp log_debug("%s: unexpected imsg %d", gotd_listen.title,
444 d93ecf7d 2022-12-14 stsp imsg.hdr.type);
445 d93ecf7d 2022-12-14 stsp break;
446 d93ecf7d 2022-12-14 stsp }
447 d93ecf7d 2022-12-14 stsp
448 d93ecf7d 2022-12-14 stsp imsg_free(&imsg);
449 d93ecf7d 2022-12-14 stsp }
450 d93ecf7d 2022-12-14 stsp
451 d93ecf7d 2022-12-14 stsp if (!shut) {
452 d93ecf7d 2022-12-14 stsp gotd_imsg_event_add(iev);
453 d93ecf7d 2022-12-14 stsp } else {
454 d93ecf7d 2022-12-14 stsp /* This pipe is dead. Remove its event handler */
455 d93ecf7d 2022-12-14 stsp event_del(&iev->ev);
456 d93ecf7d 2022-12-14 stsp event_loopexit(NULL);
457 d93ecf7d 2022-12-14 stsp }
458 d93ecf7d 2022-12-14 stsp }
459 d93ecf7d 2022-12-14 stsp
460 d93ecf7d 2022-12-14 stsp void
461 40b85cca 2023-01-03 stsp listen_main(const char *title, int gotd_socket,
462 40b85cca 2023-01-03 stsp struct gotd_uid_connection_limit *connection_limits,
463 40b85cca 2023-01-03 stsp size_t nconnection_limits)
464 d93ecf7d 2022-12-14 stsp {
465 d93ecf7d 2022-12-14 stsp struct gotd_imsgev iev;
466 d93ecf7d 2022-12-14 stsp struct event evsigint, evsigterm, evsighup, evsigusr1;
467 c602198a 2022-12-30 stsp
468 c602198a 2022-12-30 stsp arc4random_buf(&clients_hash_key, sizeof(clients_hash_key));
469 7a0564e3 2022-12-30 stsp arc4random_buf(&uid_hash_key, sizeof(uid_hash_key));
470 d93ecf7d 2022-12-14 stsp
471 d93ecf7d 2022-12-14 stsp gotd_listen.title = title;
472 d93ecf7d 2022-12-14 stsp gotd_listen.pid = getpid();
473 d93ecf7d 2022-12-14 stsp gotd_listen.fd = gotd_socket;
474 40b85cca 2023-01-03 stsp gotd_listen.connection_limits = connection_limits;
475 40b85cca 2023-01-03 stsp gotd_listen.nconnection_limits = nconnection_limits;
476 d93ecf7d 2022-12-14 stsp
477 d93ecf7d 2022-12-14 stsp signal_set(&evsigint, SIGINT, listen_sighdlr, NULL);
478 d93ecf7d 2022-12-14 stsp signal_set(&evsigterm, SIGTERM, listen_sighdlr, NULL);
479 d93ecf7d 2022-12-14 stsp signal_set(&evsighup, SIGHUP, listen_sighdlr, NULL);
480 d93ecf7d 2022-12-14 stsp signal_set(&evsigusr1, SIGUSR1, listen_sighdlr, NULL);
481 d93ecf7d 2022-12-14 stsp signal(SIGPIPE, SIG_IGN);
482 d93ecf7d 2022-12-14 stsp
483 d93ecf7d 2022-12-14 stsp signal_add(&evsigint, NULL);
484 d93ecf7d 2022-12-14 stsp signal_add(&evsigterm, NULL);
485 d93ecf7d 2022-12-14 stsp signal_add(&evsighup, NULL);
486 d93ecf7d 2022-12-14 stsp signal_add(&evsigusr1, NULL);
487 d93ecf7d 2022-12-14 stsp
488 d93ecf7d 2022-12-14 stsp imsg_init(&iev.ibuf, GOTD_FILENO_MSG_PIPE);
489 d93ecf7d 2022-12-14 stsp iev.handler = listen_dispatch;
490 d93ecf7d 2022-12-14 stsp iev.events = EV_READ;
491 d93ecf7d 2022-12-14 stsp iev.handler_arg = NULL;
492 d93ecf7d 2022-12-14 stsp event_set(&iev.ev, iev.ibuf.fd, EV_READ, listen_dispatch, &iev);
493 d93ecf7d 2022-12-14 stsp if (event_add(&iev.ev, NULL) == -1)
494 d93ecf7d 2022-12-14 stsp fatalx("event add");
495 d93ecf7d 2022-12-14 stsp
496 d93ecf7d 2022-12-14 stsp event_set(&gotd_listen.iev.ev, gotd_listen.fd, EV_READ | EV_PERSIST,
497 d93ecf7d 2022-12-14 stsp gotd_accept, &iev);
498 d93ecf7d 2022-12-14 stsp if (event_add(&gotd_listen.iev.ev, NULL))
499 d93ecf7d 2022-12-14 stsp fatalx("event add");
500 d93ecf7d 2022-12-14 stsp evtimer_set(&gotd_listen.pause.ev, gotd_accept_paused, NULL);
501 d93ecf7d 2022-12-14 stsp
502 d93ecf7d 2022-12-14 stsp event_dispatch();
503 d93ecf7d 2022-12-14 stsp
504 d93ecf7d 2022-12-14 stsp listen_shutdown();
505 d93ecf7d 2022-12-14 stsp }
506 d93ecf7d 2022-12-14 stsp
507 d93ecf7d 2022-12-14 stsp static void
508 d93ecf7d 2022-12-14 stsp listen_shutdown(void)
509 d93ecf7d 2022-12-14 stsp {
510 d93ecf7d 2022-12-14 stsp log_debug("%s: shutting down", gotd_listen.title);
511 d93ecf7d 2022-12-14 stsp
512 40b85cca 2023-01-03 stsp free(gotd_listen.connection_limits);
513 d93ecf7d 2022-12-14 stsp if (gotd_listen.fd != -1)
514 d93ecf7d 2022-12-14 stsp close(gotd_listen.fd);
515 d93ecf7d 2022-12-14 stsp
516 d93ecf7d 2022-12-14 stsp exit(0);
517 d93ecf7d 2022-12-14 stsp }