Blame


1 92eb0426 2024-03-30 thomas /*
2 92eb0426 2024-03-30 thomas * Copyright (c) 2022, 2023 Stefan Sperling <stsp@openbsd.org>
3 92eb0426 2024-03-30 thomas *
4 92eb0426 2024-03-30 thomas * Permission to use, copy, modify, and distribute this software for any
5 92eb0426 2024-03-30 thomas * purpose with or without fee is hereby granted, provided that the above
6 92eb0426 2024-03-30 thomas * copyright notice and this permission notice appear in all copies.
7 92eb0426 2024-03-30 thomas *
8 92eb0426 2024-03-30 thomas * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 92eb0426 2024-03-30 thomas * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 92eb0426 2024-03-30 thomas * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 92eb0426 2024-03-30 thomas * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 92eb0426 2024-03-30 thomas * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 92eb0426 2024-03-30 thomas * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 92eb0426 2024-03-30 thomas * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 92eb0426 2024-03-30 thomas */
16 92eb0426 2024-03-30 thomas
17 a58e44b0 2024-03-30 thomas #include "got_compat.h"
18 a58e44b0 2024-03-30 thomas
19 92eb0426 2024-03-30 thomas #include <sys/types.h>
20 92eb0426 2024-03-30 thomas #include <sys/queue.h>
21 92eb0426 2024-03-30 thomas #include <sys/socket.h>
22 92eb0426 2024-03-30 thomas #include <sys/stat.h>
23 92eb0426 2024-03-30 thomas #include <sys/uio.h>
24 92eb0426 2024-03-30 thomas
25 92eb0426 2024-03-30 thomas #include <errno.h>
26 92eb0426 2024-03-30 thomas #include <event.h>
27 92eb0426 2024-03-30 thomas #include <limits.h>
28 92eb0426 2024-03-30 thomas #include <signal.h>
29 92eb0426 2024-03-30 thomas #include <stdint.h>
30 92eb0426 2024-03-30 thomas #include <stdio.h>
31 92eb0426 2024-03-30 thomas #include <stdlib.h>
32 92eb0426 2024-03-30 thomas #include <string.h>
33 92eb0426 2024-03-30 thomas #include <imsg.h>
34 92eb0426 2024-03-30 thomas #include <unistd.h>
35 92eb0426 2024-03-30 thomas
36 92eb0426 2024-03-30 thomas #include "got_error.h"
37 92eb0426 2024-03-30 thomas #include "got_repository.h"
38 92eb0426 2024-03-30 thomas #include "got_object.h"
39 92eb0426 2024-03-30 thomas #include "got_path.h"
40 92eb0426 2024-03-30 thomas #include "got_reference.h"
41 92eb0426 2024-03-30 thomas #include "got_opentemp.h"
42 92eb0426 2024-03-30 thomas
43 92eb0426 2024-03-30 thomas #include "got_lib_hash.h"
44 92eb0426 2024-03-30 thomas #include "got_lib_delta.h"
45 92eb0426 2024-03-30 thomas #include "got_lib_object.h"
46 92eb0426 2024-03-30 thomas #include "got_lib_object_cache.h"
47 92eb0426 2024-03-30 thomas #include "got_lib_pack.h"
48 92eb0426 2024-03-30 thomas #include "got_lib_repository.h"
49 92eb0426 2024-03-30 thomas #include "got_lib_gitproto.h"
50 92eb0426 2024-03-30 thomas
51 92eb0426 2024-03-30 thomas #include "gotd.h"
52 92eb0426 2024-03-30 thomas #include "log.h"
53 92eb0426 2024-03-30 thomas #include "session_read.h"
54 92eb0426 2024-03-30 thomas
55 92eb0426 2024-03-30 thomas enum gotd_session_read_state {
56 92eb0426 2024-03-30 thomas GOTD_STATE_EXPECT_LIST_REFS,
57 92eb0426 2024-03-30 thomas GOTD_STATE_EXPECT_CAPABILITIES,
58 92eb0426 2024-03-30 thomas GOTD_STATE_EXPECT_WANT,
59 92eb0426 2024-03-30 thomas GOTD_STATE_EXPECT_HAVE,
60 92eb0426 2024-03-30 thomas GOTD_STATE_EXPECT_DONE,
61 92eb0426 2024-03-30 thomas GOTD_STATE_DONE,
62 92eb0426 2024-03-30 thomas };
63 92eb0426 2024-03-30 thomas
64 92eb0426 2024-03-30 thomas static struct gotd_session_read {
65 92eb0426 2024-03-30 thomas pid_t pid;
66 92eb0426 2024-03-30 thomas const char *title;
67 92eb0426 2024-03-30 thomas struct got_repository *repo;
68 92eb0426 2024-03-30 thomas struct gotd_repo *repo_cfg;
69 92eb0426 2024-03-30 thomas int *pack_fds;
70 92eb0426 2024-03-30 thomas int *temp_fds;
71 92eb0426 2024-03-30 thomas struct gotd_imsgev parent_iev;
72 92eb0426 2024-03-30 thomas struct gotd_imsgev notifier_iev;
73 92eb0426 2024-03-30 thomas struct timeval request_timeout;
74 92eb0426 2024-03-30 thomas enum gotd_session_read_state state;
75 92eb0426 2024-03-30 thomas struct gotd_imsgev repo_child_iev;
76 92eb0426 2024-03-30 thomas } gotd_session;
77 92eb0426 2024-03-30 thomas
78 92eb0426 2024-03-30 thomas static struct gotd_session_client {
79 92eb0426 2024-03-30 thomas struct gotd_client_capability *capabilities;
80 92eb0426 2024-03-30 thomas size_t ncapa_alloc;
81 92eb0426 2024-03-30 thomas size_t ncapabilities;
82 92eb0426 2024-03-30 thomas uint32_t id;
83 92eb0426 2024-03-30 thomas int fd;
84 92eb0426 2024-03-30 thomas int delta_cache_fd;
85 92eb0426 2024-03-30 thomas struct gotd_imsgev iev;
86 92eb0426 2024-03-30 thomas struct event tmo;
87 92eb0426 2024-03-30 thomas uid_t euid;
88 92eb0426 2024-03-30 thomas gid_t egid;
89 92eb0426 2024-03-30 thomas char *username;
90 92eb0426 2024-03-30 thomas char *packfile_path;
91 92eb0426 2024-03-30 thomas char *packidx_path;
92 92eb0426 2024-03-30 thomas int nref_updates;
93 92eb0426 2024-03-30 thomas int accept_flush_pkt;
94 92eb0426 2024-03-30 thomas int flush_disconnect;
95 92eb0426 2024-03-30 thomas } gotd_session_client;
96 92eb0426 2024-03-30 thomas
97 92eb0426 2024-03-30 thomas static void session_read_shutdown(void);
98 92eb0426 2024-03-30 thomas
99 92eb0426 2024-03-30 thomas static void
100 92eb0426 2024-03-30 thomas disconnect(struct gotd_session_client *client)
101 92eb0426 2024-03-30 thomas {
102 92eb0426 2024-03-30 thomas log_debug("uid %d: disconnecting", client->euid);
103 92eb0426 2024-03-30 thomas
104 92eb0426 2024-03-30 thomas if (gotd_imsg_compose_event(&gotd_session.parent_iev,
105 92eb0426 2024-03-30 thomas GOTD_IMSG_DISCONNECT, PROC_SESSION_READ, -1, NULL, 0) == -1)
106 92eb0426 2024-03-30 thomas log_warn("imsg compose DISCONNECT");
107 92eb0426 2024-03-30 thomas
108 92eb0426 2024-03-30 thomas imsg_clear(&gotd_session.repo_child_iev.ibuf);
109 92eb0426 2024-03-30 thomas event_del(&gotd_session.repo_child_iev.ev);
110 92eb0426 2024-03-30 thomas evtimer_del(&client->tmo);
111 92eb0426 2024-03-30 thomas close(client->fd);
112 92eb0426 2024-03-30 thomas if (client->delta_cache_fd != -1)
113 92eb0426 2024-03-30 thomas close(client->delta_cache_fd);
114 92eb0426 2024-03-30 thomas if (client->packfile_path) {
115 92eb0426 2024-03-30 thomas if (unlink(client->packfile_path) == -1 && errno != ENOENT)
116 92eb0426 2024-03-30 thomas log_warn("unlink %s: ", client->packfile_path);
117 92eb0426 2024-03-30 thomas free(client->packfile_path);
118 92eb0426 2024-03-30 thomas }
119 92eb0426 2024-03-30 thomas if (client->packidx_path) {
120 92eb0426 2024-03-30 thomas if (unlink(client->packidx_path) == -1 && errno != ENOENT)
121 92eb0426 2024-03-30 thomas log_warn("unlink %s: ", client->packidx_path);
122 92eb0426 2024-03-30 thomas free(client->packidx_path);
123 92eb0426 2024-03-30 thomas }
124 92eb0426 2024-03-30 thomas free(client->capabilities);
125 92eb0426 2024-03-30 thomas
126 92eb0426 2024-03-30 thomas session_read_shutdown();
127 92eb0426 2024-03-30 thomas }
128 92eb0426 2024-03-30 thomas
129 92eb0426 2024-03-30 thomas static void
130 92eb0426 2024-03-30 thomas disconnect_on_error(struct gotd_session_client *client,
131 92eb0426 2024-03-30 thomas const struct got_error *err)
132 92eb0426 2024-03-30 thomas {
133 92eb0426 2024-03-30 thomas struct imsgbuf ibuf;
134 92eb0426 2024-03-30 thomas
135 92eb0426 2024-03-30 thomas if (err->code != GOT_ERR_EOF) {
136 92eb0426 2024-03-30 thomas log_warnx("uid %d: %s", client->euid, err->msg);
137 92eb0426 2024-03-30 thomas imsg_init(&ibuf, client->fd);
138 92eb0426 2024-03-30 thomas gotd_imsg_send_error(&ibuf, 0, PROC_SESSION_READ, err);
139 92eb0426 2024-03-30 thomas imsg_clear(&ibuf);
140 92eb0426 2024-03-30 thomas }
141 92eb0426 2024-03-30 thomas
142 92eb0426 2024-03-30 thomas disconnect(client);
143 92eb0426 2024-03-30 thomas }
144 92eb0426 2024-03-30 thomas
145 92eb0426 2024-03-30 thomas static void
146 92eb0426 2024-03-30 thomas gotd_request_timeout(int fd, short events, void *arg)
147 92eb0426 2024-03-30 thomas {
148 92eb0426 2024-03-30 thomas struct gotd_session_client *client = arg;
149 92eb0426 2024-03-30 thomas
150 92eb0426 2024-03-30 thomas log_debug("disconnecting uid %d due to timeout", client->euid);
151 92eb0426 2024-03-30 thomas disconnect(client);
152 92eb0426 2024-03-30 thomas }
153 92eb0426 2024-03-30 thomas
154 92eb0426 2024-03-30 thomas static void
155 92eb0426 2024-03-30 thomas session_read_sighdlr(int sig, short event, void *arg)
156 92eb0426 2024-03-30 thomas {
157 92eb0426 2024-03-30 thomas /*
158 92eb0426 2024-03-30 thomas * Normal signal handler rules don't apply because libevent
159 92eb0426 2024-03-30 thomas * decouples for us.
160 92eb0426 2024-03-30 thomas */
161 92eb0426 2024-03-30 thomas
162 92eb0426 2024-03-30 thomas switch (sig) {
163 92eb0426 2024-03-30 thomas case SIGHUP:
164 92eb0426 2024-03-30 thomas log_info("%s: ignoring SIGHUP", __func__);
165 92eb0426 2024-03-30 thomas break;
166 92eb0426 2024-03-30 thomas case SIGUSR1:
167 92eb0426 2024-03-30 thomas log_info("%s: ignoring SIGUSR1", __func__);
168 92eb0426 2024-03-30 thomas break;
169 92eb0426 2024-03-30 thomas case SIGTERM:
170 92eb0426 2024-03-30 thomas case SIGINT:
171 92eb0426 2024-03-30 thomas session_read_shutdown();
172 92eb0426 2024-03-30 thomas /* NOTREACHED */
173 92eb0426 2024-03-30 thomas break;
174 92eb0426 2024-03-30 thomas default:
175 92eb0426 2024-03-30 thomas fatalx("unexpected signal");
176 92eb0426 2024-03-30 thomas }
177 92eb0426 2024-03-30 thomas }
178 92eb0426 2024-03-30 thomas
179 92eb0426 2024-03-30 thomas static const struct got_error *
180 92eb0426 2024-03-30 thomas recv_packfile_done(struct imsg *imsg)
181 92eb0426 2024-03-30 thomas {
182 92eb0426 2024-03-30 thomas size_t datalen;
183 92eb0426 2024-03-30 thomas
184 92eb0426 2024-03-30 thomas log_debug("packfile-done received");
185 92eb0426 2024-03-30 thomas
186 92eb0426 2024-03-30 thomas datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
187 92eb0426 2024-03-30 thomas if (datalen != 0)
188 92eb0426 2024-03-30 thomas return got_error(GOT_ERR_PRIVSEP_LEN);
189 92eb0426 2024-03-30 thomas
190 92eb0426 2024-03-30 thomas return NULL;
191 92eb0426 2024-03-30 thomas }
192 92eb0426 2024-03-30 thomas
193 92eb0426 2024-03-30 thomas static void
194 92eb0426 2024-03-30 thomas session_dispatch_repo_child(int fd, short event, void *arg)
195 92eb0426 2024-03-30 thomas {
196 92eb0426 2024-03-30 thomas struct gotd_imsgev *iev = arg;
197 92eb0426 2024-03-30 thomas struct imsgbuf *ibuf = &iev->ibuf;
198 92eb0426 2024-03-30 thomas struct gotd_session_client *client = &gotd_session_client;
199 92eb0426 2024-03-30 thomas ssize_t n;
200 92eb0426 2024-03-30 thomas int shut = 0;
201 92eb0426 2024-03-30 thomas struct imsg imsg;
202 92eb0426 2024-03-30 thomas
203 92eb0426 2024-03-30 thomas if (event & EV_READ) {
204 92eb0426 2024-03-30 thomas if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN)
205 92eb0426 2024-03-30 thomas fatal("imsg_read error");
206 92eb0426 2024-03-30 thomas if (n == 0) {
207 92eb0426 2024-03-30 thomas /* Connection closed. */
208 92eb0426 2024-03-30 thomas shut = 1;
209 92eb0426 2024-03-30 thomas goto done;
210 92eb0426 2024-03-30 thomas }
211 92eb0426 2024-03-30 thomas }
212 92eb0426 2024-03-30 thomas
213 92eb0426 2024-03-30 thomas if (event & EV_WRITE) {
214 92eb0426 2024-03-30 thomas n = msgbuf_write(&ibuf->w);
215 92eb0426 2024-03-30 thomas if (n == -1 && errno != EAGAIN)
216 92eb0426 2024-03-30 thomas fatal("msgbuf_write");
217 92eb0426 2024-03-30 thomas if (n == 0) {
218 92eb0426 2024-03-30 thomas /* Connection closed. */
219 92eb0426 2024-03-30 thomas shut = 1;
220 92eb0426 2024-03-30 thomas goto done;
221 92eb0426 2024-03-30 thomas }
222 92eb0426 2024-03-30 thomas }
223 92eb0426 2024-03-30 thomas
224 92eb0426 2024-03-30 thomas for (;;) {
225 92eb0426 2024-03-30 thomas const struct got_error *err = NULL;
226 92eb0426 2024-03-30 thomas uint32_t client_id = 0;
227 92eb0426 2024-03-30 thomas int do_disconnect = 0;
228 92eb0426 2024-03-30 thomas
229 92eb0426 2024-03-30 thomas if ((n = imsg_get(ibuf, &imsg)) == -1)
230 92eb0426 2024-03-30 thomas fatal("%s: imsg_get error", __func__);
231 92eb0426 2024-03-30 thomas if (n == 0) /* No more messages. */
232 92eb0426 2024-03-30 thomas break;
233 92eb0426 2024-03-30 thomas
234 92eb0426 2024-03-30 thomas switch (imsg.hdr.type) {
235 92eb0426 2024-03-30 thomas case GOTD_IMSG_ERROR:
236 92eb0426 2024-03-30 thomas do_disconnect = 1;
237 92eb0426 2024-03-30 thomas err = gotd_imsg_recv_error(&client_id, &imsg);
238 92eb0426 2024-03-30 thomas break;
239 92eb0426 2024-03-30 thomas case GOTD_IMSG_PACKFILE_DONE:
240 92eb0426 2024-03-30 thomas do_disconnect = 1;
241 92eb0426 2024-03-30 thomas err = recv_packfile_done(&imsg);
242 92eb0426 2024-03-30 thomas break;
243 92eb0426 2024-03-30 thomas default:
244 92eb0426 2024-03-30 thomas log_debug("unexpected imsg %d", imsg.hdr.type);
245 92eb0426 2024-03-30 thomas break;
246 92eb0426 2024-03-30 thomas }
247 92eb0426 2024-03-30 thomas
248 92eb0426 2024-03-30 thomas if (do_disconnect) {
249 92eb0426 2024-03-30 thomas if (err)
250 92eb0426 2024-03-30 thomas disconnect_on_error(client, err);
251 92eb0426 2024-03-30 thomas else
252 92eb0426 2024-03-30 thomas disconnect(client);
253 92eb0426 2024-03-30 thomas } else {
254 92eb0426 2024-03-30 thomas if (err)
255 92eb0426 2024-03-30 thomas log_warnx("uid %d: %s", client->euid, err->msg);
256 92eb0426 2024-03-30 thomas }
257 92eb0426 2024-03-30 thomas imsg_free(&imsg);
258 92eb0426 2024-03-30 thomas }
259 92eb0426 2024-03-30 thomas done:
260 92eb0426 2024-03-30 thomas if (!shut) {
261 92eb0426 2024-03-30 thomas gotd_imsg_event_add(iev);
262 92eb0426 2024-03-30 thomas } else {
263 92eb0426 2024-03-30 thomas /* This pipe is dead. Remove its event handler */
264 92eb0426 2024-03-30 thomas event_del(&iev->ev);
265 92eb0426 2024-03-30 thomas event_loopexit(NULL);
266 92eb0426 2024-03-30 thomas }
267 92eb0426 2024-03-30 thomas }
268 92eb0426 2024-03-30 thomas
269 92eb0426 2024-03-30 thomas static const struct got_error *
270 92eb0426 2024-03-30 thomas recv_capabilities(struct gotd_session_client *client, struct imsg *imsg)
271 92eb0426 2024-03-30 thomas {
272 92eb0426 2024-03-30 thomas struct gotd_imsg_capabilities icapas;
273 92eb0426 2024-03-30 thomas size_t datalen;
274 92eb0426 2024-03-30 thomas
275 92eb0426 2024-03-30 thomas datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
276 92eb0426 2024-03-30 thomas if (datalen != sizeof(icapas))
277 92eb0426 2024-03-30 thomas return got_error(GOT_ERR_PRIVSEP_LEN);
278 92eb0426 2024-03-30 thomas memcpy(&icapas, imsg->data, sizeof(icapas));
279 92eb0426 2024-03-30 thomas
280 92eb0426 2024-03-30 thomas client->ncapa_alloc = icapas.ncapabilities;
281 92eb0426 2024-03-30 thomas client->capabilities = calloc(client->ncapa_alloc,
282 92eb0426 2024-03-30 thomas sizeof(*client->capabilities));
283 92eb0426 2024-03-30 thomas if (client->capabilities == NULL) {
284 92eb0426 2024-03-30 thomas client->ncapa_alloc = 0;
285 92eb0426 2024-03-30 thomas return got_error_from_errno("calloc");
286 92eb0426 2024-03-30 thomas }
287 92eb0426 2024-03-30 thomas
288 92eb0426 2024-03-30 thomas log_debug("expecting %zu capabilities from uid %d",
289 92eb0426 2024-03-30 thomas client->ncapa_alloc, client->euid);
290 92eb0426 2024-03-30 thomas return NULL;
291 92eb0426 2024-03-30 thomas }
292 92eb0426 2024-03-30 thomas
293 92eb0426 2024-03-30 thomas static const struct got_error *
294 92eb0426 2024-03-30 thomas recv_capability(struct gotd_session_client *client, struct imsg *imsg)
295 92eb0426 2024-03-30 thomas {
296 92eb0426 2024-03-30 thomas struct gotd_imsg_capability icapa;
297 92eb0426 2024-03-30 thomas struct gotd_client_capability *capa;
298 92eb0426 2024-03-30 thomas size_t datalen;
299 92eb0426 2024-03-30 thomas char *key, *value = NULL;
300 92eb0426 2024-03-30 thomas
301 92eb0426 2024-03-30 thomas if (client->capabilities == NULL ||
302 92eb0426 2024-03-30 thomas client->ncapabilities >= client->ncapa_alloc) {
303 92eb0426 2024-03-30 thomas return got_error_msg(GOT_ERR_BAD_REQUEST,
304 92eb0426 2024-03-30 thomas "unexpected capability received");
305 92eb0426 2024-03-30 thomas }
306 92eb0426 2024-03-30 thomas
307 92eb0426 2024-03-30 thomas memset(&icapa, 0, sizeof(icapa));
308 92eb0426 2024-03-30 thomas
309 92eb0426 2024-03-30 thomas datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
310 92eb0426 2024-03-30 thomas if (datalen < sizeof(icapa))
311 92eb0426 2024-03-30 thomas return got_error(GOT_ERR_PRIVSEP_LEN);
312 92eb0426 2024-03-30 thomas memcpy(&icapa, imsg->data, sizeof(icapa));
313 92eb0426 2024-03-30 thomas
314 92eb0426 2024-03-30 thomas if (datalen != sizeof(icapa) + icapa.key_len + icapa.value_len)
315 92eb0426 2024-03-30 thomas return got_error(GOT_ERR_PRIVSEP_LEN);
316 92eb0426 2024-03-30 thomas
317 92eb0426 2024-03-30 thomas key = strndup(imsg->data + sizeof(icapa), icapa.key_len);
318 92eb0426 2024-03-30 thomas if (key == NULL)
319 92eb0426 2024-03-30 thomas return got_error_from_errno("strndup");
320 92eb0426 2024-03-30 thomas if (icapa.value_len > 0) {
321 92eb0426 2024-03-30 thomas value = strndup(imsg->data + sizeof(icapa) + icapa.key_len,
322 92eb0426 2024-03-30 thomas icapa.value_len);
323 92eb0426 2024-03-30 thomas if (value == NULL) {
324 92eb0426 2024-03-30 thomas free(key);
325 92eb0426 2024-03-30 thomas return got_error_from_errno("strndup");
326 92eb0426 2024-03-30 thomas }
327 92eb0426 2024-03-30 thomas }
328 92eb0426 2024-03-30 thomas
329 92eb0426 2024-03-30 thomas capa = &client->capabilities[client->ncapabilities++];
330 92eb0426 2024-03-30 thomas capa->key = key;
331 92eb0426 2024-03-30 thomas capa->value = value;
332 92eb0426 2024-03-30 thomas
333 92eb0426 2024-03-30 thomas if (value)
334 92eb0426 2024-03-30 thomas log_debug("uid %d: capability %s=%s", client->euid, key, value);
335 92eb0426 2024-03-30 thomas else
336 92eb0426 2024-03-30 thomas log_debug("uid %d: capability %s", client->euid, key);
337 92eb0426 2024-03-30 thomas
338 92eb0426 2024-03-30 thomas return NULL;
339 92eb0426 2024-03-30 thomas }
340 92eb0426 2024-03-30 thomas
341 92eb0426 2024-03-30 thomas static const struct got_error *
342 92eb0426 2024-03-30 thomas forward_want(struct gotd_session_client *client, struct imsg *imsg)
343 92eb0426 2024-03-30 thomas {
344 92eb0426 2024-03-30 thomas struct gotd_imsg_want ireq;
345 92eb0426 2024-03-30 thomas struct gotd_imsg_want iwant;
346 92eb0426 2024-03-30 thomas size_t datalen;
347 92eb0426 2024-03-30 thomas
348 92eb0426 2024-03-30 thomas datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
349 92eb0426 2024-03-30 thomas if (datalen != sizeof(ireq))
350 92eb0426 2024-03-30 thomas return got_error(GOT_ERR_PRIVSEP_LEN);
351 92eb0426 2024-03-30 thomas
352 92eb0426 2024-03-30 thomas memcpy(&ireq, imsg->data, datalen);
353 92eb0426 2024-03-30 thomas
354 92eb0426 2024-03-30 thomas memset(&iwant, 0, sizeof(iwant));
355 92eb0426 2024-03-30 thomas memcpy(iwant.object_id, ireq.object_id, SHA1_DIGEST_LENGTH);
356 92eb0426 2024-03-30 thomas
357 92eb0426 2024-03-30 thomas if (gotd_imsg_compose_event(&gotd_session.repo_child_iev,
358 92eb0426 2024-03-30 thomas GOTD_IMSG_WANT, PROC_SESSION_READ, -1,
359 92eb0426 2024-03-30 thomas &iwant, sizeof(iwant)) == -1)
360 92eb0426 2024-03-30 thomas return got_error_from_errno("imsg compose WANT");
361 92eb0426 2024-03-30 thomas
362 92eb0426 2024-03-30 thomas return NULL;
363 92eb0426 2024-03-30 thomas }
364 92eb0426 2024-03-30 thomas
365 92eb0426 2024-03-30 thomas static const struct got_error *
366 92eb0426 2024-03-30 thomas forward_have(struct gotd_session_client *client, struct imsg *imsg)
367 92eb0426 2024-03-30 thomas {
368 92eb0426 2024-03-30 thomas struct gotd_imsg_have ireq;
369 92eb0426 2024-03-30 thomas struct gotd_imsg_have ihave;
370 92eb0426 2024-03-30 thomas size_t datalen;
371 92eb0426 2024-03-30 thomas
372 92eb0426 2024-03-30 thomas datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
373 92eb0426 2024-03-30 thomas if (datalen != sizeof(ireq))
374 92eb0426 2024-03-30 thomas return got_error(GOT_ERR_PRIVSEP_LEN);
375 92eb0426 2024-03-30 thomas
376 92eb0426 2024-03-30 thomas memcpy(&ireq, imsg->data, datalen);
377 92eb0426 2024-03-30 thomas
378 92eb0426 2024-03-30 thomas memset(&ihave, 0, sizeof(ihave));
379 92eb0426 2024-03-30 thomas memcpy(ihave.object_id, ireq.object_id, SHA1_DIGEST_LENGTH);
380 92eb0426 2024-03-30 thomas
381 92eb0426 2024-03-30 thomas if (gotd_imsg_compose_event(&gotd_session.repo_child_iev,
382 92eb0426 2024-03-30 thomas GOTD_IMSG_HAVE, PROC_SESSION_READ, -1,
383 92eb0426 2024-03-30 thomas &ihave, sizeof(ihave)) == -1)
384 92eb0426 2024-03-30 thomas return got_error_from_errno("imsg compose HAVE");
385 92eb0426 2024-03-30 thomas
386 92eb0426 2024-03-30 thomas return NULL;
387 92eb0426 2024-03-30 thomas }
388 92eb0426 2024-03-30 thomas
389 92eb0426 2024-03-30 thomas static int
390 92eb0426 2024-03-30 thomas client_has_capability(struct gotd_session_client *client, const char *capastr)
391 92eb0426 2024-03-30 thomas {
392 92eb0426 2024-03-30 thomas struct gotd_client_capability *capa;
393 92eb0426 2024-03-30 thomas size_t i;
394 92eb0426 2024-03-30 thomas
395 92eb0426 2024-03-30 thomas if (client->ncapabilities == 0)
396 92eb0426 2024-03-30 thomas return 0;
397 92eb0426 2024-03-30 thomas
398 92eb0426 2024-03-30 thomas for (i = 0; i < client->ncapabilities; i++) {
399 92eb0426 2024-03-30 thomas capa = &client->capabilities[i];
400 92eb0426 2024-03-30 thomas if (strcmp(capa->key, capastr) == 0)
401 92eb0426 2024-03-30 thomas return 1;
402 92eb0426 2024-03-30 thomas }
403 92eb0426 2024-03-30 thomas
404 92eb0426 2024-03-30 thomas return 0;
405 92eb0426 2024-03-30 thomas }
406 92eb0426 2024-03-30 thomas
407 92eb0426 2024-03-30 thomas static const struct got_error *
408 92eb0426 2024-03-30 thomas send_packfile(struct gotd_session_client *client)
409 92eb0426 2024-03-30 thomas {
410 92eb0426 2024-03-30 thomas const struct got_error *err = NULL;
411 92eb0426 2024-03-30 thomas struct gotd_imsg_send_packfile ipack;
412 92eb0426 2024-03-30 thomas int pipe[2];
413 92eb0426 2024-03-30 thomas
414 92eb0426 2024-03-30 thomas if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pipe) == -1)
415 92eb0426 2024-03-30 thomas return got_error_from_errno("socketpair");
416 92eb0426 2024-03-30 thomas
417 92eb0426 2024-03-30 thomas memset(&ipack, 0, sizeof(ipack));
418 92eb0426 2024-03-30 thomas
419 92eb0426 2024-03-30 thomas if (client_has_capability(client, GOT_CAPA_SIDE_BAND_64K))
420 92eb0426 2024-03-30 thomas ipack.report_progress = 1;
421 92eb0426 2024-03-30 thomas
422 92eb0426 2024-03-30 thomas client->delta_cache_fd = got_opentempfd();
423 92eb0426 2024-03-30 thomas if (client->delta_cache_fd == -1)
424 92eb0426 2024-03-30 thomas return got_error_from_errno("got_opentempfd");
425 92eb0426 2024-03-30 thomas
426 92eb0426 2024-03-30 thomas if (gotd_imsg_compose_event(&gotd_session.repo_child_iev,
427 92eb0426 2024-03-30 thomas GOTD_IMSG_SEND_PACKFILE, PROC_GOTD, client->delta_cache_fd,
428 92eb0426 2024-03-30 thomas &ipack, sizeof(ipack)) == -1) {
429 92eb0426 2024-03-30 thomas err = got_error_from_errno("imsg compose SEND_PACKFILE");
430 92eb0426 2024-03-30 thomas close(pipe[0]);
431 92eb0426 2024-03-30 thomas close(pipe[1]);
432 92eb0426 2024-03-30 thomas return err;
433 92eb0426 2024-03-30 thomas }
434 92eb0426 2024-03-30 thomas
435 92eb0426 2024-03-30 thomas /* Send pack pipe end 0 to repo child process. */
436 92eb0426 2024-03-30 thomas if (gotd_imsg_compose_event(&gotd_session.repo_child_iev,
437 92eb0426 2024-03-30 thomas GOTD_IMSG_PACKFILE_PIPE, PROC_GOTD, pipe[0], NULL, 0) == -1) {
438 92eb0426 2024-03-30 thomas err = got_error_from_errno("imsg compose PACKFILE_PIPE");
439 92eb0426 2024-03-30 thomas close(pipe[1]);
440 92eb0426 2024-03-30 thomas return err;
441 92eb0426 2024-03-30 thomas }
442 92eb0426 2024-03-30 thomas
443 92eb0426 2024-03-30 thomas /* Send pack pipe end 1 to gotsh(1) (expects just an fd, no data). */
444 92eb0426 2024-03-30 thomas if (gotd_imsg_compose_event(&client->iev,
445 92eb0426 2024-03-30 thomas GOTD_IMSG_PACKFILE_PIPE, PROC_GOTD, pipe[1], NULL, 0) == -1)
446 92eb0426 2024-03-30 thomas err = got_error_from_errno("imsg compose PACKFILE_PIPE");
447 92eb0426 2024-03-30 thomas
448 92eb0426 2024-03-30 thomas return err;
449 92eb0426 2024-03-30 thomas }
450 92eb0426 2024-03-30 thomas
451 92eb0426 2024-03-30 thomas static void
452 92eb0426 2024-03-30 thomas session_dispatch_client(int fd, short events, void *arg)
453 92eb0426 2024-03-30 thomas {
454 92eb0426 2024-03-30 thomas struct gotd_imsgev *iev = arg;
455 92eb0426 2024-03-30 thomas struct imsgbuf *ibuf = &iev->ibuf;
456 92eb0426 2024-03-30 thomas struct gotd_session_client *client = &gotd_session_client;
457 92eb0426 2024-03-30 thomas const struct got_error *err = NULL;
458 92eb0426 2024-03-30 thomas struct imsg imsg;
459 92eb0426 2024-03-30 thomas ssize_t n;
460 92eb0426 2024-03-30 thomas
461 92eb0426 2024-03-30 thomas if (events & EV_WRITE) {
462 92eb0426 2024-03-30 thomas while (ibuf->w.queued) {
463 92eb0426 2024-03-30 thomas n = msgbuf_write(&ibuf->w);
464 92eb0426 2024-03-30 thomas if (n == -1 && errno == EPIPE) {
465 92eb0426 2024-03-30 thomas /*
466 92eb0426 2024-03-30 thomas * The client has closed its socket.
467 92eb0426 2024-03-30 thomas * This can happen when Git clients are
468 92eb0426 2024-03-30 thomas * done sending pack file data.
469 92eb0426 2024-03-30 thomas */
470 92eb0426 2024-03-30 thomas msgbuf_clear(&ibuf->w);
471 92eb0426 2024-03-30 thomas continue;
472 92eb0426 2024-03-30 thomas } else if (n == -1 && errno != EAGAIN) {
473 92eb0426 2024-03-30 thomas err = got_error_from_errno("imsg_flush");
474 92eb0426 2024-03-30 thomas disconnect_on_error(client, err);
475 92eb0426 2024-03-30 thomas return;
476 92eb0426 2024-03-30 thomas }
477 92eb0426 2024-03-30 thomas if (n == 0) {
478 92eb0426 2024-03-30 thomas /* Connection closed. */
479 92eb0426 2024-03-30 thomas err = got_error(GOT_ERR_EOF);
480 92eb0426 2024-03-30 thomas disconnect_on_error(client, err);
481 92eb0426 2024-03-30 thomas return;
482 92eb0426 2024-03-30 thomas }
483 92eb0426 2024-03-30 thomas }
484 92eb0426 2024-03-30 thomas
485 92eb0426 2024-03-30 thomas if (client->flush_disconnect) {
486 92eb0426 2024-03-30 thomas disconnect(client);
487 92eb0426 2024-03-30 thomas return;
488 92eb0426 2024-03-30 thomas }
489 92eb0426 2024-03-30 thomas }
490 92eb0426 2024-03-30 thomas
491 92eb0426 2024-03-30 thomas if ((events & EV_READ) == 0)
492 92eb0426 2024-03-30 thomas return;
493 92eb0426 2024-03-30 thomas
494 92eb0426 2024-03-30 thomas memset(&imsg, 0, sizeof(imsg));
495 92eb0426 2024-03-30 thomas
496 92eb0426 2024-03-30 thomas while (err == NULL) {
497 92eb0426 2024-03-30 thomas err = gotd_imsg_recv(&imsg, ibuf, 0);
498 92eb0426 2024-03-30 thomas if (err) {
499 92eb0426 2024-03-30 thomas if (err->code == GOT_ERR_PRIVSEP_READ)
500 92eb0426 2024-03-30 thomas err = NULL;
501 92eb0426 2024-03-30 thomas else if (err->code == GOT_ERR_EOF &&
502 92eb0426 2024-03-30 thomas gotd_session.state ==
503 92eb0426 2024-03-30 thomas GOTD_STATE_EXPECT_CAPABILITIES) {
504 92eb0426 2024-03-30 thomas /*
505 92eb0426 2024-03-30 thomas * The client has closed its socket before
506 92eb0426 2024-03-30 thomas * sending its capability announcement.
507 92eb0426 2024-03-30 thomas * This can happen when Git clients have
508 92eb0426 2024-03-30 thomas * no ref-updates to send.
509 92eb0426 2024-03-30 thomas */
510 92eb0426 2024-03-30 thomas disconnect_on_error(client, err);
511 92eb0426 2024-03-30 thomas return;
512 92eb0426 2024-03-30 thomas }
513 92eb0426 2024-03-30 thomas break;
514 92eb0426 2024-03-30 thomas }
515 92eb0426 2024-03-30 thomas
516 92eb0426 2024-03-30 thomas evtimer_del(&client->tmo);
517 92eb0426 2024-03-30 thomas
518 92eb0426 2024-03-30 thomas switch (imsg.hdr.type) {
519 92eb0426 2024-03-30 thomas case GOTD_IMSG_CAPABILITIES:
520 92eb0426 2024-03-30 thomas if (gotd_session.state !=
521 92eb0426 2024-03-30 thomas GOTD_STATE_EXPECT_CAPABILITIES) {
522 92eb0426 2024-03-30 thomas err = got_error_msg(GOT_ERR_BAD_REQUEST,
523 92eb0426 2024-03-30 thomas "unexpected capabilities received");
524 92eb0426 2024-03-30 thomas break;
525 92eb0426 2024-03-30 thomas }
526 92eb0426 2024-03-30 thomas log_debug("receiving capabilities from uid %d",
527 92eb0426 2024-03-30 thomas client->euid);
528 92eb0426 2024-03-30 thomas err = recv_capabilities(client, &imsg);
529 92eb0426 2024-03-30 thomas break;
530 92eb0426 2024-03-30 thomas case GOTD_IMSG_CAPABILITY:
531 92eb0426 2024-03-30 thomas if (gotd_session.state != GOTD_STATE_EXPECT_CAPABILITIES) {
532 92eb0426 2024-03-30 thomas err = got_error_msg(GOT_ERR_BAD_REQUEST,
533 92eb0426 2024-03-30 thomas "unexpected capability received");
534 92eb0426 2024-03-30 thomas break;
535 92eb0426 2024-03-30 thomas }
536 92eb0426 2024-03-30 thomas err = recv_capability(client, &imsg);
537 92eb0426 2024-03-30 thomas if (err || client->ncapabilities < client->ncapa_alloc)
538 92eb0426 2024-03-30 thomas break;
539 92eb0426 2024-03-30 thomas gotd_session.state = GOTD_STATE_EXPECT_WANT;
540 92eb0426 2024-03-30 thomas client->accept_flush_pkt = 1;
541 92eb0426 2024-03-30 thomas log_debug("uid %d: expecting want-lines", client->euid);
542 92eb0426 2024-03-30 thomas break;
543 92eb0426 2024-03-30 thomas case GOTD_IMSG_WANT:
544 92eb0426 2024-03-30 thomas if (gotd_session.state != GOTD_STATE_EXPECT_WANT) {
545 92eb0426 2024-03-30 thomas err = got_error_msg(GOT_ERR_BAD_REQUEST,
546 92eb0426 2024-03-30 thomas "unexpected want-line received");
547 92eb0426 2024-03-30 thomas break;
548 92eb0426 2024-03-30 thomas }
549 92eb0426 2024-03-30 thomas log_debug("received want-line from uid %d",
550 92eb0426 2024-03-30 thomas client->euid);
551 92eb0426 2024-03-30 thomas client->accept_flush_pkt = 1;
552 92eb0426 2024-03-30 thomas err = forward_want(client, &imsg);
553 92eb0426 2024-03-30 thomas break;
554 92eb0426 2024-03-30 thomas case GOTD_IMSG_HAVE:
555 92eb0426 2024-03-30 thomas if (gotd_session.state != GOTD_STATE_EXPECT_HAVE) {
556 92eb0426 2024-03-30 thomas err = got_error_msg(GOT_ERR_BAD_REQUEST,
557 92eb0426 2024-03-30 thomas "unexpected have-line received");
558 92eb0426 2024-03-30 thomas break;
559 92eb0426 2024-03-30 thomas }
560 92eb0426 2024-03-30 thomas log_debug("received have-line from uid %d",
561 92eb0426 2024-03-30 thomas client->euid);
562 92eb0426 2024-03-30 thomas err = forward_have(client, &imsg);
563 92eb0426 2024-03-30 thomas if (err)
564 92eb0426 2024-03-30 thomas break;
565 92eb0426 2024-03-30 thomas client->accept_flush_pkt = 1;
566 92eb0426 2024-03-30 thomas break;
567 92eb0426 2024-03-30 thomas case GOTD_IMSG_FLUSH:
568 92eb0426 2024-03-30 thomas if (gotd_session.state != GOTD_STATE_EXPECT_WANT &&
569 92eb0426 2024-03-30 thomas gotd_session.state != GOTD_STATE_EXPECT_HAVE &&
570 92eb0426 2024-03-30 thomas gotd_session.state != GOTD_STATE_EXPECT_DONE) {
571 92eb0426 2024-03-30 thomas err = got_error_msg(GOT_ERR_BAD_REQUEST,
572 92eb0426 2024-03-30 thomas "unexpected flush-pkt received");
573 92eb0426 2024-03-30 thomas break;
574 92eb0426 2024-03-30 thomas }
575 92eb0426 2024-03-30 thomas if (!client->accept_flush_pkt) {
576 92eb0426 2024-03-30 thomas err = got_error_msg(GOT_ERR_BAD_REQUEST,
577 92eb0426 2024-03-30 thomas "unexpected flush-pkt received");
578 92eb0426 2024-03-30 thomas break;
579 92eb0426 2024-03-30 thomas }
580 92eb0426 2024-03-30 thomas
581 92eb0426 2024-03-30 thomas /*
582 92eb0426 2024-03-30 thomas * Accept just one flush packet at a time.
583 92eb0426 2024-03-30 thomas * Future client state transitions will set this flag
584 92eb0426 2024-03-30 thomas * again if another flush packet is expected.
585 92eb0426 2024-03-30 thomas */
586 92eb0426 2024-03-30 thomas client->accept_flush_pkt = 0;
587 92eb0426 2024-03-30 thomas
588 92eb0426 2024-03-30 thomas log_debug("received flush-pkt from uid %d",
589 92eb0426 2024-03-30 thomas client->euid);
590 92eb0426 2024-03-30 thomas if (gotd_session.state == GOTD_STATE_EXPECT_WANT) {
591 92eb0426 2024-03-30 thomas gotd_session.state = GOTD_STATE_EXPECT_HAVE;
592 92eb0426 2024-03-30 thomas log_debug("uid %d: expecting have-lines",
593 92eb0426 2024-03-30 thomas client->euid);
594 92eb0426 2024-03-30 thomas } else if (gotd_session.state == GOTD_STATE_EXPECT_HAVE) {
595 92eb0426 2024-03-30 thomas gotd_session.state = GOTD_STATE_EXPECT_DONE;
596 92eb0426 2024-03-30 thomas client->accept_flush_pkt = 1;
597 92eb0426 2024-03-30 thomas log_debug("uid %d: expecting 'done'",
598 92eb0426 2024-03-30 thomas client->euid);
599 92eb0426 2024-03-30 thomas } else if (gotd_session.state != GOTD_STATE_EXPECT_DONE) {
600 92eb0426 2024-03-30 thomas /* should not happen, see above */
601 92eb0426 2024-03-30 thomas err = got_error_msg(GOT_ERR_BAD_REQUEST,
602 92eb0426 2024-03-30 thomas "unexpected client state");
603 92eb0426 2024-03-30 thomas break;
604 92eb0426 2024-03-30 thomas }
605 92eb0426 2024-03-30 thomas break;
606 92eb0426 2024-03-30 thomas case GOTD_IMSG_DONE:
607 92eb0426 2024-03-30 thomas if (gotd_session.state != GOTD_STATE_EXPECT_HAVE &&
608 92eb0426 2024-03-30 thomas gotd_session.state != GOTD_STATE_EXPECT_DONE) {
609 92eb0426 2024-03-30 thomas err = got_error_msg(GOT_ERR_BAD_REQUEST,
610 92eb0426 2024-03-30 thomas "unexpected flush-pkt received");
611 92eb0426 2024-03-30 thomas break;
612 92eb0426 2024-03-30 thomas }
613 92eb0426 2024-03-30 thomas log_debug("received 'done' from uid %d", client->euid);
614 92eb0426 2024-03-30 thomas gotd_session.state = GOTD_STATE_DONE;
615 92eb0426 2024-03-30 thomas client->accept_flush_pkt = 1;
616 92eb0426 2024-03-30 thomas err = send_packfile(client);
617 92eb0426 2024-03-30 thomas break;
618 92eb0426 2024-03-30 thomas default:
619 92eb0426 2024-03-30 thomas log_debug("unexpected imsg %d", imsg.hdr.type);
620 92eb0426 2024-03-30 thomas err = got_error(GOT_ERR_PRIVSEP_MSG);
621 92eb0426 2024-03-30 thomas break;
622 92eb0426 2024-03-30 thomas }
623 92eb0426 2024-03-30 thomas
624 92eb0426 2024-03-30 thomas imsg_free(&imsg);
625 92eb0426 2024-03-30 thomas }
626 92eb0426 2024-03-30 thomas
627 92eb0426 2024-03-30 thomas if (err) {
628 92eb0426 2024-03-30 thomas if (err->code != GOT_ERR_EOF)
629 92eb0426 2024-03-30 thomas disconnect_on_error(client, err);
630 92eb0426 2024-03-30 thomas } else {
631 92eb0426 2024-03-30 thomas gotd_imsg_event_add(iev);
632 92eb0426 2024-03-30 thomas evtimer_add(&client->tmo, &gotd_session.request_timeout);
633 92eb0426 2024-03-30 thomas }
634 92eb0426 2024-03-30 thomas }
635 92eb0426 2024-03-30 thomas
636 92eb0426 2024-03-30 thomas static const struct got_error *
637 92eb0426 2024-03-30 thomas list_refs_request(void)
638 92eb0426 2024-03-30 thomas {
639 92eb0426 2024-03-30 thomas static const struct got_error *err;
640 92eb0426 2024-03-30 thomas struct gotd_session_client *client = &gotd_session_client;
641 92eb0426 2024-03-30 thomas struct gotd_imsgev *iev = &gotd_session.repo_child_iev;
642 92eb0426 2024-03-30 thomas int fd;
643 92eb0426 2024-03-30 thomas
644 92eb0426 2024-03-30 thomas if (gotd_session.state != GOTD_STATE_EXPECT_LIST_REFS)
645 92eb0426 2024-03-30 thomas return got_error(GOT_ERR_PRIVSEP_MSG);
646 92eb0426 2024-03-30 thomas
647 92eb0426 2024-03-30 thomas fd = dup(client->fd);
648 92eb0426 2024-03-30 thomas if (fd == -1)
649 92eb0426 2024-03-30 thomas return got_error_from_errno("dup");
650 92eb0426 2024-03-30 thomas
651 92eb0426 2024-03-30 thomas if (gotd_imsg_compose_event(iev, GOTD_IMSG_LIST_REFS_INTERNAL,
652 92eb0426 2024-03-30 thomas PROC_SESSION_READ, fd, NULL, 0) == -1) {
653 92eb0426 2024-03-30 thomas err = got_error_from_errno("imsg compose LIST_REFS_INTERNAL");
654 92eb0426 2024-03-30 thomas close(fd);
655 92eb0426 2024-03-30 thomas return err;
656 92eb0426 2024-03-30 thomas }
657 92eb0426 2024-03-30 thomas
658 92eb0426 2024-03-30 thomas gotd_session.state = GOTD_STATE_EXPECT_CAPABILITIES;
659 92eb0426 2024-03-30 thomas log_debug("uid %d: expecting capabilities", client->euid);
660 92eb0426 2024-03-30 thomas return NULL;
661 92eb0426 2024-03-30 thomas }
662 92eb0426 2024-03-30 thomas
663 92eb0426 2024-03-30 thomas static const struct got_error *
664 92eb0426 2024-03-30 thomas recv_connect(struct imsg *imsg)
665 92eb0426 2024-03-30 thomas {
666 92eb0426 2024-03-30 thomas struct gotd_session_client *client = &gotd_session_client;
667 92eb0426 2024-03-30 thomas struct gotd_imsg_connect iconnect;
668 92eb0426 2024-03-30 thomas size_t datalen;
669 92eb0426 2024-03-30 thomas
670 92eb0426 2024-03-30 thomas if (gotd_session.state != GOTD_STATE_EXPECT_LIST_REFS)
671 92eb0426 2024-03-30 thomas return got_error(GOT_ERR_PRIVSEP_MSG);
672 92eb0426 2024-03-30 thomas
673 92eb0426 2024-03-30 thomas datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
674 92eb0426 2024-03-30 thomas if (datalen < sizeof(iconnect))
675 92eb0426 2024-03-30 thomas return got_error(GOT_ERR_PRIVSEP_LEN);
676 92eb0426 2024-03-30 thomas memcpy(&iconnect, imsg->data, sizeof(iconnect));
677 92eb0426 2024-03-30 thomas if (iconnect.username_len == 0 ||
678 92eb0426 2024-03-30 thomas datalen != sizeof(iconnect) + iconnect.username_len)
679 92eb0426 2024-03-30 thomas return got_error(GOT_ERR_PRIVSEP_LEN);
680 92eb0426 2024-03-30 thomas
681 92eb0426 2024-03-30 thomas client->euid = iconnect.euid;
682 92eb0426 2024-03-30 thomas client->egid = iconnect.egid;
683 92eb0426 2024-03-30 thomas client->fd = imsg_get_fd(imsg);
684 92eb0426 2024-03-30 thomas if (client->fd == -1)
685 92eb0426 2024-03-30 thomas return got_error(GOT_ERR_PRIVSEP_NO_FD);
686 92eb0426 2024-03-30 thomas
687 92eb0426 2024-03-30 thomas client->username = strndup(imsg->data + sizeof(iconnect),
688 92eb0426 2024-03-30 thomas iconnect.username_len);
689 92eb0426 2024-03-30 thomas if (client->username == NULL)
690 92eb0426 2024-03-30 thomas return got_error_from_errno("strndup");
691 92eb0426 2024-03-30 thomas
692 92eb0426 2024-03-30 thomas imsg_init(&client->iev.ibuf, client->fd);
693 92eb0426 2024-03-30 thomas client->iev.handler = session_dispatch_client;
694 92eb0426 2024-03-30 thomas client->iev.events = EV_READ;
695 92eb0426 2024-03-30 thomas client->iev.handler_arg = NULL;
696 92eb0426 2024-03-30 thomas event_set(&client->iev.ev, client->iev.ibuf.fd, EV_READ,
697 92eb0426 2024-03-30 thomas session_dispatch_client, &client->iev);
698 92eb0426 2024-03-30 thomas gotd_imsg_event_add(&client->iev);
699 92eb0426 2024-03-30 thomas evtimer_set(&client->tmo, gotd_request_timeout, client);
700 92eb0426 2024-03-30 thomas
701 92eb0426 2024-03-30 thomas return NULL;
702 92eb0426 2024-03-30 thomas }
703 92eb0426 2024-03-30 thomas
704 92eb0426 2024-03-30 thomas static const struct got_error *
705 92eb0426 2024-03-30 thomas recv_repo_child(struct imsg *imsg)
706 92eb0426 2024-03-30 thomas {
707 92eb0426 2024-03-30 thomas struct gotd_imsg_connect_repo_child ichild;
708 92eb0426 2024-03-30 thomas struct gotd_session_client *client = &gotd_session_client;
709 92eb0426 2024-03-30 thomas size_t datalen;
710 92eb0426 2024-03-30 thomas int fd;
711 92eb0426 2024-03-30 thomas
712 92eb0426 2024-03-30 thomas if (gotd_session.state != GOTD_STATE_EXPECT_LIST_REFS)
713 92eb0426 2024-03-30 thomas return got_error(GOT_ERR_PRIVSEP_MSG);
714 92eb0426 2024-03-30 thomas
715 92eb0426 2024-03-30 thomas /* We should already have received a pipe to the listener. */
716 92eb0426 2024-03-30 thomas if (client->fd == -1)
717 92eb0426 2024-03-30 thomas return got_error(GOT_ERR_PRIVSEP_MSG);
718 92eb0426 2024-03-30 thomas
719 92eb0426 2024-03-30 thomas datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
720 92eb0426 2024-03-30 thomas if (datalen != sizeof(ichild))
721 92eb0426 2024-03-30 thomas return got_error(GOT_ERR_PRIVSEP_LEN);
722 92eb0426 2024-03-30 thomas
723 92eb0426 2024-03-30 thomas memcpy(&ichild, imsg->data, sizeof(ichild));
724 92eb0426 2024-03-30 thomas
725 92eb0426 2024-03-30 thomas if (ichild.proc_id != PROC_REPO_READ)
726 92eb0426 2024-03-30 thomas return got_error_msg(GOT_ERR_PRIVSEP_MSG,
727 92eb0426 2024-03-30 thomas "bad child process type");
728 92eb0426 2024-03-30 thomas
729 92eb0426 2024-03-30 thomas fd = imsg_get_fd(imsg);
730 92eb0426 2024-03-30 thomas if (fd == -1)
731 92eb0426 2024-03-30 thomas return got_error(GOT_ERR_PRIVSEP_NO_FD);
732 92eb0426 2024-03-30 thomas
733 92eb0426 2024-03-30 thomas imsg_init(&gotd_session.repo_child_iev.ibuf, fd);
734 92eb0426 2024-03-30 thomas gotd_session.repo_child_iev.handler = session_dispatch_repo_child;
735 92eb0426 2024-03-30 thomas gotd_session.repo_child_iev.events = EV_READ;
736 92eb0426 2024-03-30 thomas gotd_session.repo_child_iev.handler_arg = NULL;
737 92eb0426 2024-03-30 thomas event_set(&gotd_session.repo_child_iev.ev,
738 92eb0426 2024-03-30 thomas gotd_session.repo_child_iev.ibuf.fd, EV_READ,
739 92eb0426 2024-03-30 thomas session_dispatch_repo_child, &gotd_session.repo_child_iev);
740 92eb0426 2024-03-30 thomas gotd_imsg_event_add(&gotd_session.repo_child_iev);
741 92eb0426 2024-03-30 thomas
742 92eb0426 2024-03-30 thomas /* The "recvfd" pledge promise is no longer needed. */
743 92eb0426 2024-03-30 thomas if (pledge("stdio rpath wpath cpath sendfd fattr flock", NULL) == -1)
744 92eb0426 2024-03-30 thomas fatal("pledge");
745 92eb0426 2024-03-30 thomas
746 92eb0426 2024-03-30 thomas return NULL;
747 92eb0426 2024-03-30 thomas }
748 92eb0426 2024-03-30 thomas
749 92eb0426 2024-03-30 thomas static void
750 92eb0426 2024-03-30 thomas session_dispatch(int fd, short event, void *arg)
751 92eb0426 2024-03-30 thomas {
752 92eb0426 2024-03-30 thomas struct gotd_imsgev *iev = arg;
753 92eb0426 2024-03-30 thomas struct imsgbuf *ibuf = &iev->ibuf;
754 92eb0426 2024-03-30 thomas struct gotd_session_client *client = &gotd_session_client;
755 92eb0426 2024-03-30 thomas ssize_t n;
756 92eb0426 2024-03-30 thomas int shut = 0;
757 92eb0426 2024-03-30 thomas struct imsg imsg;
758 92eb0426 2024-03-30 thomas
759 92eb0426 2024-03-30 thomas if (event & EV_READ) {
760 92eb0426 2024-03-30 thomas if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN)
761 92eb0426 2024-03-30 thomas fatal("imsg_read error");
762 92eb0426 2024-03-30 thomas if (n == 0) {
763 92eb0426 2024-03-30 thomas /* Connection closed. */
764 92eb0426 2024-03-30 thomas shut = 1;
765 92eb0426 2024-03-30 thomas goto done;
766 92eb0426 2024-03-30 thomas }
767 92eb0426 2024-03-30 thomas }
768 92eb0426 2024-03-30 thomas
769 92eb0426 2024-03-30 thomas if (event & EV_WRITE) {
770 92eb0426 2024-03-30 thomas n = msgbuf_write(&ibuf->w);
771 92eb0426 2024-03-30 thomas if (n == -1 && errno != EAGAIN)
772 92eb0426 2024-03-30 thomas fatal("msgbuf_write");
773 92eb0426 2024-03-30 thomas if (n == 0) {
774 92eb0426 2024-03-30 thomas /* Connection closed. */
775 92eb0426 2024-03-30 thomas shut = 1;
776 92eb0426 2024-03-30 thomas goto done;
777 92eb0426 2024-03-30 thomas }
778 92eb0426 2024-03-30 thomas }
779 92eb0426 2024-03-30 thomas
780 92eb0426 2024-03-30 thomas for (;;) {
781 92eb0426 2024-03-30 thomas const struct got_error *err = NULL;
782 92eb0426 2024-03-30 thomas uint32_t client_id = 0;
783 92eb0426 2024-03-30 thomas int do_disconnect = 0, do_list_refs = 0;
784 92eb0426 2024-03-30 thomas
785 92eb0426 2024-03-30 thomas if ((n = imsg_get(ibuf, &imsg)) == -1)
786 92eb0426 2024-03-30 thomas fatal("%s: imsg_get error", __func__);
787 92eb0426 2024-03-30 thomas if (n == 0) /* No more messages. */
788 92eb0426 2024-03-30 thomas break;
789 92eb0426 2024-03-30 thomas
790 92eb0426 2024-03-30 thomas switch (imsg.hdr.type) {
791 92eb0426 2024-03-30 thomas case GOTD_IMSG_ERROR:
792 92eb0426 2024-03-30 thomas do_disconnect = 1;
793 92eb0426 2024-03-30 thomas err = gotd_imsg_recv_error(&client_id, &imsg);
794 92eb0426 2024-03-30 thomas break;
795 92eb0426 2024-03-30 thomas case GOTD_IMSG_CONNECT:
796 92eb0426 2024-03-30 thomas err = recv_connect(&imsg);
797 92eb0426 2024-03-30 thomas break;
798 92eb0426 2024-03-30 thomas case GOTD_IMSG_DISCONNECT:
799 92eb0426 2024-03-30 thomas do_disconnect = 1;
800 92eb0426 2024-03-30 thomas break;
801 92eb0426 2024-03-30 thomas case GOTD_IMSG_CONNECT_REPO_CHILD:
802 92eb0426 2024-03-30 thomas err = recv_repo_child(&imsg);
803 92eb0426 2024-03-30 thomas if (err)
804 92eb0426 2024-03-30 thomas break;
805 92eb0426 2024-03-30 thomas do_list_refs = 1;
806 92eb0426 2024-03-30 thomas break;
807 92eb0426 2024-03-30 thomas default:
808 92eb0426 2024-03-30 thomas log_debug("unexpected imsg %d", imsg.hdr.type);
809 92eb0426 2024-03-30 thomas break;
810 92eb0426 2024-03-30 thomas }
811 92eb0426 2024-03-30 thomas imsg_free(&imsg);
812 92eb0426 2024-03-30 thomas
813 92eb0426 2024-03-30 thomas if (do_disconnect) {
814 92eb0426 2024-03-30 thomas if (err)
815 92eb0426 2024-03-30 thomas disconnect_on_error(client, err);
816 92eb0426 2024-03-30 thomas else
817 92eb0426 2024-03-30 thomas disconnect(client);
818 92eb0426 2024-03-30 thomas } else if (do_list_refs)
819 92eb0426 2024-03-30 thomas err = list_refs_request();
820 92eb0426 2024-03-30 thomas
821 92eb0426 2024-03-30 thomas if (err)
822 92eb0426 2024-03-30 thomas log_warnx("uid %d: %s", client->euid, err->msg);
823 92eb0426 2024-03-30 thomas }
824 92eb0426 2024-03-30 thomas done:
825 92eb0426 2024-03-30 thomas if (!shut) {
826 92eb0426 2024-03-30 thomas gotd_imsg_event_add(iev);
827 92eb0426 2024-03-30 thomas } else {
828 92eb0426 2024-03-30 thomas /* This pipe is dead. Remove its event handler */
829 92eb0426 2024-03-30 thomas event_del(&iev->ev);
830 92eb0426 2024-03-30 thomas event_loopexit(NULL);
831 92eb0426 2024-03-30 thomas }
832 92eb0426 2024-03-30 thomas }
833 92eb0426 2024-03-30 thomas
834 92eb0426 2024-03-30 thomas void
835 92eb0426 2024-03-30 thomas session_read_main(const char *title, const char *repo_path,
836 92eb0426 2024-03-30 thomas int *pack_fds, int *temp_fds, struct timeval *request_timeout,
837 92eb0426 2024-03-30 thomas struct gotd_repo *repo_cfg)
838 92eb0426 2024-03-30 thomas {
839 92eb0426 2024-03-30 thomas const struct got_error *err = NULL;
840 92eb0426 2024-03-30 thomas struct event evsigint, evsigterm, evsighup, evsigusr1;
841 92eb0426 2024-03-30 thomas
842 92eb0426 2024-03-30 thomas gotd_session.title = title;
843 92eb0426 2024-03-30 thomas gotd_session.pid = getpid();
844 92eb0426 2024-03-30 thomas gotd_session.pack_fds = pack_fds;
845 92eb0426 2024-03-30 thomas gotd_session.temp_fds = temp_fds;
846 92eb0426 2024-03-30 thomas memcpy(&gotd_session.request_timeout, request_timeout,
847 92eb0426 2024-03-30 thomas sizeof(gotd_session.request_timeout));
848 92eb0426 2024-03-30 thomas gotd_session.repo_cfg = repo_cfg;
849 92eb0426 2024-03-30 thomas
850 92eb0426 2024-03-30 thomas imsg_init(&gotd_session.notifier_iev.ibuf, -1);
851 92eb0426 2024-03-30 thomas
852 92eb0426 2024-03-30 thomas err = got_repo_open(&gotd_session.repo, repo_path, NULL, pack_fds);
853 92eb0426 2024-03-30 thomas if (err)
854 92eb0426 2024-03-30 thomas goto done;
855 92eb0426 2024-03-30 thomas if (!got_repo_is_bare(gotd_session.repo)) {
856 92eb0426 2024-03-30 thomas err = got_error_msg(GOT_ERR_NOT_GIT_REPO,
857 92eb0426 2024-03-30 thomas "bare git repository required");
858 92eb0426 2024-03-30 thomas goto done;
859 92eb0426 2024-03-30 thomas }
860 92eb0426 2024-03-30 thomas
861 92eb0426 2024-03-30 thomas got_repo_temp_fds_set(gotd_session.repo, temp_fds);
862 92eb0426 2024-03-30 thomas
863 92eb0426 2024-03-30 thomas signal_set(&evsigint, SIGINT, session_read_sighdlr, NULL);
864 92eb0426 2024-03-30 thomas signal_set(&evsigterm, SIGTERM, session_read_sighdlr, NULL);
865 92eb0426 2024-03-30 thomas signal_set(&evsighup, SIGHUP, session_read_sighdlr, NULL);
866 92eb0426 2024-03-30 thomas signal_set(&evsigusr1, SIGUSR1, session_read_sighdlr, NULL);
867 92eb0426 2024-03-30 thomas signal(SIGPIPE, SIG_IGN);
868 92eb0426 2024-03-30 thomas
869 92eb0426 2024-03-30 thomas signal_add(&evsigint, NULL);
870 92eb0426 2024-03-30 thomas signal_add(&evsigterm, NULL);
871 92eb0426 2024-03-30 thomas signal_add(&evsighup, NULL);
872 92eb0426 2024-03-30 thomas signal_add(&evsigusr1, NULL);
873 92eb0426 2024-03-30 thomas
874 92eb0426 2024-03-30 thomas gotd_session.state = GOTD_STATE_EXPECT_LIST_REFS;
875 92eb0426 2024-03-30 thomas
876 92eb0426 2024-03-30 thomas gotd_session_client.fd = -1;
877 92eb0426 2024-03-30 thomas gotd_session_client.nref_updates = -1;
878 92eb0426 2024-03-30 thomas gotd_session_client.delta_cache_fd = -1;
879 92eb0426 2024-03-30 thomas gotd_session_client.accept_flush_pkt = 1;
880 92eb0426 2024-03-30 thomas
881 92eb0426 2024-03-30 thomas imsg_init(&gotd_session.parent_iev.ibuf, GOTD_FILENO_MSG_PIPE);
882 92eb0426 2024-03-30 thomas gotd_session.parent_iev.handler = session_dispatch;
883 92eb0426 2024-03-30 thomas gotd_session.parent_iev.events = EV_READ;
884 92eb0426 2024-03-30 thomas gotd_session.parent_iev.handler_arg = NULL;
885 92eb0426 2024-03-30 thomas event_set(&gotd_session.parent_iev.ev, gotd_session.parent_iev.ibuf.fd,
886 92eb0426 2024-03-30 thomas EV_READ, session_dispatch, &gotd_session.parent_iev);
887 92eb0426 2024-03-30 thomas if (gotd_imsg_compose_event(&gotd_session.parent_iev,
888 92eb0426 2024-03-30 thomas GOTD_IMSG_CLIENT_SESSION_READY, PROC_SESSION_READ,
889 92eb0426 2024-03-30 thomas -1, NULL, 0) == -1) {
890 92eb0426 2024-03-30 thomas err = got_error_from_errno("imsg compose CLIENT_SESSION_READY");
891 92eb0426 2024-03-30 thomas goto done;
892 92eb0426 2024-03-30 thomas }
893 92eb0426 2024-03-30 thomas
894 92eb0426 2024-03-30 thomas event_dispatch();
895 92eb0426 2024-03-30 thomas done:
896 92eb0426 2024-03-30 thomas if (err)
897 92eb0426 2024-03-30 thomas log_warnx("%s: %s", title, err->msg);
898 92eb0426 2024-03-30 thomas session_read_shutdown();
899 92eb0426 2024-03-30 thomas }
900 92eb0426 2024-03-30 thomas
901 92eb0426 2024-03-30 thomas static void
902 92eb0426 2024-03-30 thomas session_read_shutdown(void)
903 92eb0426 2024-03-30 thomas {
904 b1a47061 2024-03-30 thomas log_debug("%s: shutting down", gotd_session.title);
905 92eb0426 2024-03-30 thomas
906 92eb0426 2024-03-30 thomas if (gotd_session.repo)
907 92eb0426 2024-03-30 thomas got_repo_close(gotd_session.repo);
908 92eb0426 2024-03-30 thomas got_repo_pack_fds_close(gotd_session.pack_fds);
909 92eb0426 2024-03-30 thomas got_repo_temp_fds_close(gotd_session.temp_fds);
910 92eb0426 2024-03-30 thomas free(gotd_session_client.username);
911 92eb0426 2024-03-30 thomas exit(0);
912 92eb0426 2024-03-30 thomas }