Blame


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