Blame


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