Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sudo-project
GitHub Repository: sudo-project/sudo
Path: blob/main/logsrvd/logsrvd_relay.c
1532 views
1
/*
2
* SPDX-License-Identifier: ISC
3
*
4
* Copyright (c) 2019-2023, 2025 Todd C. Miller <[email protected]>
5
*
6
* Permission to use, copy, modify, and distribute this software for any
7
* purpose with or without fee is hereby granted, provided that the above
8
* copyright notice and this permission notice appear in all copies.
9
*
10
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17
*/
18
19
#include <config.h>
20
21
#include <sys/stat.h>
22
#include <sys/types.h>
23
#include <sys/socket.h>
24
#include <netinet/in.h>
25
#include <netinet/tcp.h>
26
#include <arpa/inet.h>
27
28
#include <errno.h>
29
#include <fcntl.h>
30
#include <limits.h>
31
#ifdef HAVE_STDBOOL_H
32
# include <stdbool.h>
33
#else
34
# include <compat/stdbool.h>
35
#endif /* HAVE_STDBOOL_H */
36
#if defined(HAVE_STDINT_H)
37
# include <stdint.h>
38
#elif defined(HAVE_INTTYPES_H)
39
# include <inttypes.h>
40
#endif
41
#include <stdio.h>
42
#include <stdlib.h>
43
#include <string.h>
44
#include <time.h>
45
#include <unistd.h>
46
47
#define NEED_INET_NTOP /* to expose sudo_inet_ntop in sudo_compat.h */
48
49
#include <sudo_compat.h>
50
#include <sudo_debug.h>
51
#include <sudo_event.h>
52
#include <sudo_eventlog.h>
53
#include <sudo_gettext.h>
54
#include <sudo_iolog.h>
55
#include <sudo_fatal.h>
56
#include <sudo_queue.h>
57
#include <sudo_util.h>
58
59
#include <logsrvd.h>
60
61
static void relay_client_msg_cb(int fd, int what, void *v);
62
static void relay_server_msg_cb(int fd, int what, void *v);
63
static void connect_cb(int sock, int what, void *v);
64
static bool start_relay(int sock, struct connection_closure *closure);
65
66
/*
67
* Free a struct relay_closure container and its contents.
68
*/
69
void
70
relay_closure_free(struct relay_closure *relay_closure)
71
{
72
struct connection_buffer *buf;
73
debug_decl(relay_closure_free, SUDO_DEBUG_UTIL);
74
75
#if defined(HAVE_OPENSSL)
76
if (relay_closure->tls_client.ssl != NULL) {
77
sudo_debug_printf(SUDO_DEBUG_INFO|SUDO_DEBUG_LINENO,
78
"closing down TLS connection to %s",
79
relay_closure->relay_name.name);
80
if (SSL_shutdown(relay_closure->tls_client.ssl) == 0)
81
SSL_shutdown(relay_closure->tls_client.ssl);
82
SSL_free(relay_closure->tls_client.ssl);
83
}
84
#endif
85
if (relay_closure->relays != NULL)
86
address_list_delref(relay_closure->relays);
87
sudo_rcstr_delref(relay_closure->relay_name.name);
88
sudo_ev_free(relay_closure->read_ev);
89
sudo_ev_free(relay_closure->write_ev);
90
sudo_ev_free(relay_closure->connect_ev);
91
free(relay_closure->read_buf.data);
92
while ((buf = TAILQ_FIRST(&relay_closure->write_bufs)) != NULL) {
93
TAILQ_REMOVE(&relay_closure->write_bufs, buf, entries);
94
free(buf->data);
95
free(buf);
96
}
97
if (relay_closure->sock != -1) {
98
shutdown(relay_closure->sock, SHUT_RDWR);
99
close(relay_closure->sock);
100
}
101
free(relay_closure);
102
103
debug_return;
104
}
105
106
/*
107
* Allocate a relay closure.
108
* Note that allocation of the events is deferred until we know the socket.
109
*/
110
static struct relay_closure *
111
relay_closure_alloc(void)
112
{
113
struct relay_closure *relay_closure;
114
debug_decl(relay_closure_alloc, SUDO_DEBUG_UTIL);
115
116
if ((relay_closure = calloc(1, sizeof(*relay_closure))) == NULL)
117
debug_return_ptr(NULL);
118
119
/* We take a reference to relays so it doesn't change while connecting. */
120
relay_closure->sock = -1;
121
relay_closure->relays = logsrvd_conf_relay_address();
122
address_list_addref(relay_closure->relays);
123
TAILQ_INIT(&relay_closure->write_bufs);
124
125
relay_closure->read_buf.size = 8 * 1024;
126
relay_closure->read_buf.data = malloc(relay_closure->read_buf.size);
127
if (relay_closure->read_buf.data == NULL)
128
goto bad;
129
130
debug_return_ptr(relay_closure);
131
bad:
132
relay_closure_free(relay_closure);
133
debug_return_ptr(NULL);
134
}
135
136
/*
137
* Allocate a new buffer, copy buf to it and insert on the write queue.
138
* On success the relay write event is enabled.
139
* The length parameter does not include space for the message's wire size.
140
*/
141
static bool
142
relay_enqueue_write(const uint8_t *msgbuf, size_t len,
143
struct connection_closure *closure)
144
{
145
struct relay_closure *relay_closure = closure->relay_closure;
146
struct connection_buffer *buf;
147
uint32_t msg_len;
148
bool ret = false;
149
debug_decl(relay_enqueue_write, SUDO_DEBUG_UTIL);
150
151
/* Wire message size is used for length encoding, precedes message. */
152
msg_len = htonl((uint32_t)len);
153
154
sudo_debug_printf(SUDO_DEBUG_INFO|SUDO_DEBUG_LINENO,
155
"size + client message %zu bytes", len);
156
157
if ((buf = get_free_buf(sizeof(msg_len) + len, closure)) == NULL) {
158
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
159
"unable to allocate connection_buffer");
160
goto done;
161
}
162
memcpy(buf->data, &msg_len, sizeof(msg_len));
163
memcpy(buf->data + sizeof(msg_len), msgbuf, len);
164
buf->len = sizeof(msg_len) + len;
165
166
if (sudo_ev_add(closure->evbase, relay_closure->write_ev, NULL, false) == -1) {
167
sudo_warnx("%s", U_("unable to add event to queue"));
168
goto done;
169
}
170
171
TAILQ_INSERT_TAIL(&relay_closure->write_bufs, buf, entries);
172
buf = NULL;
173
174
ret = true;
175
176
done:
177
if (buf != NULL) {
178
free(buf->data);
179
free(buf);
180
}
181
debug_return_bool(ret);
182
}
183
184
/*
185
* Format a ClientMessage and store the wire format message in buf.
186
* Returns true on success, false on failure.
187
*/
188
static bool
189
fmt_client_message(struct connection_closure *closure, ClientMessage *msg)
190
{
191
struct relay_closure *relay_closure = closure->relay_closure;
192
struct connection_buffer *buf = NULL;
193
uint32_t msg_len;
194
bool ret = false;
195
size_t len;
196
debug_decl(fmt_client_message, SUDO_DEBUG_UTIL);
197
198
len = client_message__get_packed_size(msg);
199
if (len > MESSAGE_SIZE_MAX) {
200
sudo_warnx(U_("client message too large: %zu"), len);
201
goto done;
202
}
203
204
/* Wire message size is used for length encoding, precedes message. */
205
msg_len = htonl((uint32_t)len);
206
len += sizeof(msg_len);
207
208
sudo_debug_printf(SUDO_DEBUG_INFO|SUDO_DEBUG_LINENO,
209
"size + client message %zu bytes", len);
210
211
if ((buf = get_free_buf(len, closure)) == NULL) {
212
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
213
"unable to allocate connection_buffer");
214
goto done;
215
}
216
memcpy(buf->data, &msg_len, sizeof(msg_len));
217
client_message__pack(msg, buf->data + sizeof(msg_len));
218
buf->len = len;
219
TAILQ_INSERT_TAIL(&relay_closure->write_bufs, buf, entries);
220
221
ret = true;
222
223
done:
224
debug_return_bool(ret);
225
}
226
227
static bool
228
fmt_client_hello(struct connection_closure *closure)
229
{
230
struct relay_closure *relay_closure = closure->relay_closure;
231
ClientMessage client_msg = CLIENT_MESSAGE__INIT;
232
ClientHello hello_msg = CLIENT_HELLO__INIT;
233
bool ret;
234
debug_decl(fmt_client_hello, SUDO_DEBUG_UTIL);
235
236
sudo_debug_printf(SUDO_DEBUG_INFO, "%s: sending ClientHello", __func__);
237
hello_msg.client_id = (char *)"Sudo Logsrvd " PACKAGE_VERSION;
238
239
client_msg.u.hello_msg = &hello_msg;
240
client_msg.type_case = CLIENT_MESSAGE__TYPE_HELLO_MSG;
241
ret = fmt_client_message(closure, &client_msg);
242
if (ret) {
243
if (sudo_ev_add(closure->evbase, relay_closure->read_ev, NULL, false) == -1) {
244
sudo_warnx("%s", U_("unable to add event to queue"));
245
ret = false;
246
}
247
if (sudo_ev_add(closure->evbase, relay_closure->write_ev, NULL, false) == -1) {
248
sudo_warnx("%s", U_("unable to add event to queue"));
249
ret = false;
250
}
251
}
252
253
debug_return_bool(ret);
254
}
255
256
#if defined(HAVE_OPENSSL)
257
/* Wrapper for start_relay() called via tls_connect_cb() */
258
static bool
259
tls_client_start_fn(struct tls_client_closure *tls_client)
260
{
261
sudo_ev_free(tls_client->tls_connect_ev);
262
tls_client->tls_connect_ev = NULL;
263
return start_relay(SSL_get_fd(tls_client->ssl), tls_client->parent_closure);
264
}
265
266
/* Perform TLS connection to the relay host. */
267
static bool
268
connect_relay_tls(struct connection_closure *closure)
269
{
270
struct tls_client_closure *tls_client = &closure->relay_closure->tls_client;
271
const struct timespec *timeout = logsrvd_conf_relay_connect_timeout();
272
SSL_CTX *ssl_ctx = logsrvd_relay_tls_ctx();
273
debug_decl(connect_relay_tls, SUDO_DEBUG_UTIL);
274
275
/* Populate struct tls_client_closure. */
276
tls_client->parent_closure = closure;
277
tls_client->evbase = closure->evbase;
278
tls_client->tls_connect_ev = sudo_ev_alloc(closure->relay_closure->sock,
279
SUDO_EV_WRITE, tls_connect_cb, tls_client);
280
if (tls_client->tls_connect_ev == NULL)
281
goto bad;
282
tls_client->peer_name = &closure->relay_closure->relay_name;
283
if (timeout != NULL) {
284
tls_client->connect_timeout = *timeout;
285
} else {
286
sudo_timespecclear(&tls_client->connect_timeout);
287
}
288
tls_client->start_fn = tls_client_start_fn;
289
if (!tls_ctx_client_setup(ssl_ctx, closure->relay_closure->sock, tls_client))
290
goto bad;
291
292
debug_return_bool(true);
293
bad:
294
debug_return_bool(false);
295
}
296
#endif /* HAVE_OPENSSL */
297
298
/*
299
* Try to connect to the next relay host.
300
* Returns 0 on success, -1 on error, setting errno.
301
* If there is no next relay, errno is set to ENOENT.
302
*/
303
static int
304
connect_relay_next(struct connection_closure *closure)
305
{
306
struct relay_closure *relay_closure = closure->relay_closure;
307
struct server_address *relay;
308
int ret, sock = -1;
309
char *addr;
310
debug_decl(connect_relay_next, SUDO_DEBUG_UTIL);
311
312
/* Get next relay or return ENOENT none are left. */
313
if (relay_closure->relay_addr != NULL) {
314
relay = TAILQ_NEXT(relay_closure->relay_addr, entries);
315
} else {
316
relay = TAILQ_FIRST(relay_closure->relays);
317
}
318
if (relay == NULL) {
319
errno = ENOENT;
320
goto bad;
321
}
322
relay_closure->relay_addr = relay;
323
324
sock = socket(relay->sa_un.sa.sa_family, SOCK_STREAM, 0);
325
if (sock == -1) {
326
sudo_warn("socket");
327
goto bad;
328
}
329
if (logsrvd_conf_relay_tcp_keepalive()) {
330
int keepalive = 1;
331
if (setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, &keepalive,
332
sizeof(keepalive)) == -1) {
333
sudo_warn("SO_KEEPALIVE");
334
}
335
}
336
ret = fcntl(sock, F_GETFL, 0);
337
if (ret == -1 || fcntl(sock, F_SETFL, ret | O_NONBLOCK) == -1) {
338
sudo_warn("fcntl(O_NONBLOCK)");
339
goto bad;
340
}
341
342
ret = connect(sock, &relay->sa_un.sa, relay->sa_size);
343
if (ret == -1 && errno != EINPROGRESS)
344
goto bad;
345
346
switch (relay->sa_un.sa.sa_family) {
347
case AF_INET:
348
addr = (char *)&relay->sa_un.sin.sin_addr;
349
break;
350
#ifdef HAVE_STRUCT_IN6_ADDR
351
case AF_INET6:
352
addr = (char *)&relay->sa_un.sin6.sin6_addr;
353
break;
354
#endif
355
default:
356
errno = EAFNOSUPPORT;
357
sudo_warn("connect");
358
goto bad;
359
}
360
inet_ntop(relay->sa_un.sa.sa_family, addr,
361
relay_closure->relay_name.ipaddr,
362
sizeof(relay_closure->relay_name.ipaddr));
363
relay_closure->relay_name.name = sudo_rcstr_addref(relay->sa_host);
364
365
if (ret == 0) {
366
if (relay_closure->sock != -1) {
367
shutdown(relay_closure->sock, SHUT_RDWR);
368
close(relay_closure->sock);
369
}
370
relay_closure->sock = sock;
371
#if defined(HAVE_OPENSSL)
372
/* Relay connection succeeded, start TLS handshake. */
373
if (relay_closure->relay_addr->tls) {
374
if (!connect_relay_tls(closure))
375
goto bad;
376
} else
377
#endif
378
{
379
/* Connection succeeded without blocking. */
380
if (!start_relay(sock, closure))
381
goto bad;
382
}
383
} else {
384
/* Connection will be completed in connect_cb(). */
385
relay_closure->connect_ev = sudo_ev_alloc(sock, SUDO_EV_WRITE,
386
connect_cb, closure);
387
if (relay_closure->connect_ev == NULL)
388
goto bad;
389
if (sudo_ev_add(closure->evbase, relay_closure->connect_ev,
390
logsrvd_conf_relay_connect_timeout(), false) == -1) {
391
sudo_warnx("%s", U_("unable to add event to queue"));
392
goto bad;
393
}
394
if (relay_closure->sock != -1) {
395
shutdown(relay_closure->sock, SHUT_RDWR);
396
close(relay_closure->sock);
397
}
398
relay_closure->sock = sock;
399
closure->state = CONNECTING;
400
}
401
debug_return_int(ret);
402
403
bad:
404
/* Connection or system error. */
405
if (sock != -1) {
406
shutdown(sock, SHUT_RDWR);
407
close(sock);
408
}
409
sudo_rcstr_delref(relay_closure->relay_name.name);
410
relay_closure->relay_name.name = NULL;
411
sudo_ev_free(relay_closure->connect_ev);
412
relay_closure->connect_ev = NULL;
413
debug_return_int(-1);
414
}
415
416
static void
417
connect_cb(int sock, int what, void *v)
418
{
419
struct connection_closure *closure = v;
420
struct relay_closure *relay_closure = closure->relay_closure;
421
int errnum, optval, ret;
422
socklen_t optlen = sizeof(optval);
423
debug_decl(connect_cb, SUDO_DEBUG_UTIL);
424
425
if (what == SUDO_EV_TIMEOUT) {
426
errnum = ETIMEDOUT;
427
} else {
428
ret = getsockopt(sock, SOL_SOCKET, SO_ERROR, &optval, &optlen);
429
errnum = ret == 0 ? optval : errno;
430
}
431
if (errnum == 0) {
432
closure->state = INITIAL;
433
#if defined(HAVE_OPENSSL)
434
/* Relay connection succeeded, start TLS handshake. */
435
if (relay_closure->relay_addr->tls) {
436
if (!connect_relay_tls(closure)) {
437
closure->errstr = _("TLS handshake with relay host failed");
438
if (!schedule_error_message(closure->errstr, closure))
439
connection_close(closure);
440
}
441
} else
442
#endif
443
{
444
/* Relay connection succeeded, start talking to the client. */
445
if (!start_relay(sock, closure)) {
446
closure->errstr = _("unable to allocate memory");
447
if (!schedule_error_message(closure->errstr, closure))
448
connection_close(closure);
449
}
450
}
451
} else {
452
/* Connection failed, try next relay (if any). */
453
int res;
454
sudo_debug_printf(SUDO_DEBUG_WARN|SUDO_DEBUG_LINENO,
455
"unable to connect to relay %s (%s): %s",
456
relay_closure->relay_name.name, relay_closure->relay_name.ipaddr,
457
strerror(errnum));
458
while ((res = connect_relay_next(closure)) == -1) {
459
if (errno == ENOENT || errno == EINPROGRESS) {
460
/* Out of relays or connecting asynchronously. */
461
break;
462
}
463
}
464
if (res == -1 && errno != EINPROGRESS) {
465
closure->errstr = _("unable to connect to relay host");
466
if (!schedule_error_message(closure->errstr, closure))
467
connection_close(closure);
468
}
469
}
470
471
debug_return;
472
}
473
474
/* Connect to the first available relay host. */
475
bool
476
connect_relay(struct connection_closure *closure)
477
{
478
struct relay_closure *relay_closure;
479
int res;
480
debug_decl(connect_relay, SUDO_DEBUG_UTIL);
481
482
relay_closure = closure->relay_closure = relay_closure_alloc();
483
if (relay_closure == NULL)
484
debug_return_bool(false);
485
486
while ((res = connect_relay_next(closure)) == -1) {
487
if (errno == ENOENT || errno == EINPROGRESS) {
488
/* Out of relays or connecting asynchronously. */
489
break;
490
}
491
}
492
493
if (res == -1 && errno != EINPROGRESS)
494
debug_return_bool(false);
495
496
/* Switch to relay client message handlers. */
497
closure->cms = &cms_relay;
498
debug_return_bool(true);
499
}
500
501
/*
502
* Respond to a ServerHello message from the relay.
503
* Returns true on success, false on error.
504
*/
505
static bool
506
handle_server_hello(const ServerHello *msg, struct connection_closure *closure)
507
{
508
struct relay_closure *relay_closure = closure->relay_closure;
509
debug_decl(handle_server_hello, SUDO_DEBUG_UTIL);
510
511
if (closure->state != INITIAL) {
512
sudo_warnx(U_("unexpected state %d for %s"), closure->state,
513
relay_closure->relay_name.ipaddr);
514
closure->errstr = _("state machine error");
515
debug_return_bool(false);
516
}
517
518
/* Check that ServerHello is valid. */
519
if (msg == NULL || msg->server_id == NULL || msg->server_id[0] == '\0') {
520
sudo_warnx(U_("%s: invalid ServerHello, missing server_id"),
521
relay_closure->relay_name.ipaddr);
522
closure->errstr = _("invalid ServerHello");
523
debug_return_bool(false);
524
}
525
526
sudo_debug_printf(SUDO_DEBUG_INFO|SUDO_DEBUG_LINENO,
527
"relay server %s (%s) ID %s", relay_closure->relay_name.name,
528
relay_closure->relay_name.ipaddr, msg->server_id);
529
530
/* TODO: handle redirect */
531
532
debug_return_bool(true);
533
}
534
535
/*
536
* Respond to a commit_point ServerMessage from the relay.
537
* Returns true on success, false on error.
538
*/
539
static bool
540
handle_commit_point(const TimeSpec *commit_point,
541
struct connection_closure *closure)
542
{
543
debug_decl(handle_commit_point, SUDO_DEBUG_UTIL);
544
545
if (closure->state < RUNNING) {
546
sudo_warnx(U_("unexpected state %d for %s"), closure->state,
547
closure->relay_closure->relay_name.ipaddr);
548
closure->errstr = _("state machine error");
549
debug_return_bool(false);
550
}
551
552
/* Check that ServerMessage's commit_point is valid. */
553
if (commit_point == NULL) {
554
sudo_warnx(U_("%s: invalid ServerMessage, missing commit_point"),
555
closure->relay_closure->relay_name.ipaddr);
556
closure->errstr = _("invalid ServerMessage");
557
debug_return_bool(false);
558
}
559
560
/* Pass commit point from relay to client. */
561
debug_return_bool(schedule_commit_point(commit_point, closure));
562
}
563
564
/*
565
* Respond to a log_id ServerMessage from the relay.
566
* Returns true on success, false on error.
567
*/
568
static bool
569
handle_log_id(const char *id, struct connection_closure *closure)
570
{
571
ServerMessage msg = SERVER_MESSAGE__INIT;
572
bool ret = false;
573
debug_decl(handle_log_id, SUDO_DEBUG_UTIL);
574
575
sudo_debug_printf(SUDO_DEBUG_INFO|SUDO_DEBUG_LINENO,
576
"log ID %s from relay %s (%s)", id,
577
closure->relay_closure->relay_name.name,
578
closure->relay_closure->relay_name.ipaddr);
579
580
/* No client connection when replaying a journaled entry. */
581
if (closure->write_ev == NULL)
582
debug_return_bool(true);
583
584
if (id[0] == '\0') {
585
sudo_warnx(U_("%s: invalid ServerMessage, missing log_id string"),
586
closure->relay_closure->relay_name.ipaddr);
587
closure->errstr = _("invalid ServerMessage");
588
goto done;
589
}
590
591
/*
592
* We currently pass log_id to the client without modifying it.
593
* TODO: append relay host to the log_id so we can restart the
594
* session with the proper relay if more than one is configured.
595
*/
596
msg.u.log_id = (char *)id;
597
msg.type_case = SERVER_MESSAGE__TYPE_LOG_ID;
598
ret = fmt_server_message(closure, &msg);
599
if (ret) {
600
if (sudo_ev_add(closure->evbase, closure->write_ev,
601
logsrvd_conf_relay_timeout(), false) == -1) {
602
sudo_warnx("%s", U_("unable to add event to queue"));
603
ret = false;
604
}
605
}
606
607
done:
608
debug_return_bool(ret);
609
}
610
611
/*
612
* Respond to an error ServerMessage from the relay.
613
* Returns true on success, false on error.
614
*/
615
static bool
616
handle_server_error(const char *errmsg, struct connection_closure *closure)
617
{
618
struct relay_closure *relay_closure = closure->relay_closure;
619
debug_decl(handle_server_error, SUDO_DEBUG_UTIL);
620
621
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
622
"error message received from relay %s (%s): %s",
623
relay_closure->relay_name.name, relay_closure->relay_name.ipaddr,
624
errmsg);
625
626
/* Server will drop connection after the error message. */
627
sudo_ev_del(closure->evbase, closure->relay_closure->read_ev);
628
sudo_ev_del(closure->evbase, closure->relay_closure->write_ev);
629
630
/* Missing error string. */
631
if (errmsg[0] == '\0')
632
errmsg = "unknown error";
633
634
if (!schedule_error_message(errmsg, closure))
635
debug_return_bool(false);
636
637
debug_return_bool(true);
638
}
639
640
/*
641
* Respond to an abort ServerMessage from the relay.
642
* Returns true on success, false on error.
643
*/
644
static bool
645
handle_server_abort(const char *errmsg, struct connection_closure *closure)
646
{
647
struct relay_closure *relay_closure = closure->relay_closure;
648
debug_decl(handle_server_abort, SUDO_DEBUG_UTIL);
649
650
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
651
"abort message received from relay %s (%s): %s",
652
relay_closure->relay_name.name, relay_closure->relay_name.ipaddr,
653
errmsg);
654
655
/* Missing error string. */
656
if (errmsg[0] == '\0')
657
errmsg = "unknown error";
658
659
if (!schedule_error_message(errmsg, closure))
660
debug_return_bool(false);
661
662
debug_return_bool(true);
663
}
664
665
/*
666
* Respond to a ServerMessage from the relay.
667
* Returns true on success, false on error.
668
*/
669
static bool
670
handle_server_message(const uint8_t *buf, size_t len,
671
struct connection_closure *closure)
672
{
673
ServerMessage *msg;
674
bool ret = false;
675
debug_decl(handle_server_message, SUDO_DEBUG_UTIL);
676
677
sudo_debug_printf(SUDO_DEBUG_INFO, "%s: unpacking ServerMessage", __func__);
678
msg = server_message__unpack(NULL, len, buf);
679
if (msg == NULL) {
680
sudo_warnx(U_("unable to unpack %s size %zu"), "ServerMessage", len);
681
debug_return_bool(false);
682
}
683
684
switch (msg->type_case) {
685
case SERVER_MESSAGE__TYPE_HELLO:
686
if ((ret = handle_server_hello(msg->u.hello, closure))) {
687
/* Relay server said hello, start talking to client. */
688
ret = start_protocol(closure);
689
}
690
break;
691
case SERVER_MESSAGE__TYPE_COMMIT_POINT:
692
ret = handle_commit_point(msg->u.commit_point, closure);
693
break;
694
case SERVER_MESSAGE__TYPE_LOG_ID:
695
ret = handle_log_id(msg->u.log_id, closure);
696
break;
697
case SERVER_MESSAGE__TYPE_ERROR:
698
ret = handle_server_error(msg->u.error, closure);
699
break;
700
case SERVER_MESSAGE__TYPE_ABORT:
701
ret = handle_server_abort(msg->u.abort, closure);
702
break;
703
default:
704
sudo_warnx(U_("unexpected type_case value %d in %s from %s"),
705
msg->type_case, "ServerMessage",
706
closure->relay_closure->relay_name.ipaddr);
707
closure->errstr = _("unrecognized ServerMessage type");
708
break;
709
}
710
711
server_message__free_unpacked(msg, NULL);
712
debug_return_bool(ret);
713
}
714
715
/*
716
* Read and unpack a ServerMessage from the relay (read callback).
717
*/
718
static void
719
relay_server_msg_cb(int fd, int what, void *v)
720
{
721
struct connection_closure *closure = v;
722
struct relay_closure *relay_closure = closure->relay_closure;
723
struct connection_buffer *buf = &relay_closure->read_buf;
724
size_t nread;
725
uint32_t msg_len;
726
debug_decl(relay_server_msg_cb, SUDO_DEBUG_UTIL);
727
728
/* For TLS we may need to read as part of SSL_write_ex(). */
729
if (relay_closure->write_instead_of_read) {
730
relay_closure->write_instead_of_read = false;
731
relay_client_msg_cb(fd, what, v);
732
debug_return;
733
}
734
735
if (what == SUDO_EV_TIMEOUT) {
736
sudo_warnx(U_("timed out reading from relay %s (%s)"),
737
relay_closure->relay_name.name, relay_closure->relay_name.ipaddr);
738
closure->errstr = _("timeout reading from relay");
739
goto send_error;
740
}
741
742
#if defined(HAVE_OPENSSL)
743
if (relay_closure->tls_client.ssl != NULL) {
744
SSL *ssl = relay_closure->tls_client.ssl;
745
int result;
746
747
sudo_debug_printf(SUDO_DEBUG_INFO,
748
"%s: ServerMessage from relay %s (%s) [TLS]", __func__,
749
relay_closure->relay_name.name, relay_closure->relay_name.ipaddr);
750
result = SSL_read_ex(ssl, buf->data + buf->len, buf->size - buf->len,
751
&nread);
752
if (result <= 0) {
753
unsigned long errcode;
754
const char *errstr;
755
756
switch (SSL_get_error(ssl, result)) {
757
case SSL_ERROR_ZERO_RETURN:
758
/* ssl connection shutdown cleanly */
759
nread = 0;
760
break;
761
case SSL_ERROR_WANT_READ:
762
/* ssl wants to read more, read event is always active */
763
sudo_debug_printf(SUDO_DEBUG_NOTICE|SUDO_DEBUG_LINENO,
764
"SSL_read_ex returns SSL_ERROR_WANT_READ");
765
debug_return;
766
case SSL_ERROR_WANT_WRITE:
767
/* ssl wants to write, schedule a write if not pending */
768
sudo_debug_printf(SUDO_DEBUG_NOTICE|SUDO_DEBUG_LINENO,
769
"SSL_read_ex returns SSL_ERROR_WANT_WRITE");
770
if (!sudo_ev_pending(relay_closure->write_ev, SUDO_EV_WRITE, NULL)) {
771
/* Enable a temporary write event. */
772
if (sudo_ev_add(closure->evbase, relay_closure->write_ev, NULL, false) == -1) {
773
sudo_warnx("%s", U_("unable to add event to queue"));
774
closure->errstr = _("unable to allocate memory");
775
goto send_error;
776
}
777
relay_closure->temporary_write_event = true;
778
}
779
/* Redirect write event to finish SSL_read_ex() */
780
relay_closure->read_instead_of_write = true;
781
debug_return;
782
case SSL_ERROR_SSL:
783
/*
784
* For TLS 1.3, if the cert verify function on the server
785
* returns an error, OpenSSL will send an internal error
786
* alert when we read ServerHello. Convert to a more useful
787
* message and hope that no actual internal error occurs.
788
*/
789
errcode = ERR_get_error();
790
#if !defined(HAVE_WOLFSSL)
791
if (closure->state == INITIAL &&
792
ERR_GET_REASON(errcode) == SSL_R_TLSV1_ALERT_INTERNAL_ERROR) {
793
errstr = _("relay host name does not match certificate");
794
closure->errstr = errstr;
795
} else
796
#endif
797
{
798
errstr = ERR_reason_error_string(errcode);
799
closure->errstr = _("error reading from relay");
800
}
801
sudo_warnx("%s: SSL_read_ex: %s",
802
relay_closure->relay_name.ipaddr,
803
errstr ? errstr : strerror(errno));
804
goto send_error;
805
case SSL_ERROR_SYSCALL:
806
if (nread == 0) {
807
/* EOF, handled below */
808
sudo_warnx(U_("EOF from %s without proper TLS shutdown"),
809
relay_closure->relay_name.ipaddr);
810
break;
811
}
812
sudo_warn("%s: SSL_read_ex", relay_closure->relay_name.ipaddr);
813
closure->errstr = _("error reading from relay");
814
goto send_error;
815
default:
816
errstr = ERR_reason_error_string(ERR_get_error());
817
sudo_warnx("%s: SSL_read_ex: %s",
818
relay_closure->relay_name.ipaddr,
819
errstr ? errstr : strerror(errno));
820
closure->errstr = _("error reading from relay");
821
goto send_error;
822
}
823
}
824
} else
825
#endif
826
{
827
ssize_t n;
828
829
sudo_debug_printf(SUDO_DEBUG_INFO,
830
"%s: ServerMessage from relay %s (%s)", __func__,
831
relay_closure->relay_name.name, relay_closure->relay_name.ipaddr);
832
n = read(fd, buf->data + buf->len, buf->size - buf->len);
833
if (n < 0) {
834
if (errno == EAGAIN || errno == EINTR)
835
debug_return;
836
sudo_warn("%s: read", relay_closure->relay_name.ipaddr);
837
closure->errstr = _("error reading from relay");
838
goto send_error;
839
}
840
nread = (size_t)n;
841
}
842
843
sudo_debug_printf(SUDO_DEBUG_INFO,
844
"%s: received %zd bytes from relay %s (%s)", __func__, nread,
845
relay_closure->relay_name.name, relay_closure->relay_name.ipaddr);
846
if (nread == 0) {
847
/* EOF from relay server, close the socket. */
848
shutdown(relay_closure->sock, SHUT_RDWR);
849
close(relay_closure->sock);
850
relay_closure->sock = -1;
851
sudo_ev_del(closure->evbase, relay_closure->read_ev);
852
sudo_ev_del(closure->evbase, relay_closure->write_ev);
853
854
if (closure->state != FINISHED) {
855
sudo_debug_printf(SUDO_DEBUG_WARN|SUDO_DEBUG_LINENO,
856
"premature EOF from %s (%s) [state %d]",
857
relay_closure->relay_name.name,
858
relay_closure->relay_name.ipaddr, closure->state);
859
closure->errstr = _("relay server closed connection");
860
goto send_error;
861
}
862
if (closure->sock == -1)
863
connection_close(closure);
864
debug_return;
865
}
866
if (nread > SIZE_MAX - buf->len) {
867
sudo_warnx(U_("internal error, %s overflow"), __func__);
868
closure->errstr = _("error reading from relay");
869
goto send_error;
870
}
871
buf->len += nread;
872
873
while (buf->len - buf->off >= sizeof(msg_len)) {
874
/* Read wire message size (uint32_t in network byte order). */
875
memcpy(&msg_len, buf->data + buf->off, sizeof(msg_len));
876
msg_len = ntohl(msg_len);
877
878
if (msg_len > MESSAGE_SIZE_MAX) {
879
sudo_warnx(U_("server message too large: %zu"), (size_t)msg_len);
880
closure->errstr = _("server message too large");
881
goto send_error;
882
}
883
884
if (msg_len + sizeof(msg_len) > buf->len - buf->off) {
885
/* Incomplete message, we'll read the rest next time. */
886
if (!expand_buf(buf, msg_len + sizeof(msg_len))) {
887
closure->errstr = _("unable to allocate memory");
888
goto send_error;
889
}
890
debug_return;
891
}
892
893
/* Parse ServerMessage (could be zero bytes). */
894
sudo_debug_printf(SUDO_DEBUG_INFO,
895
"%s: parsing ServerMessage, size %u", __func__, msg_len);
896
buf->off += sizeof(msg_len);
897
if (!handle_server_message(buf->data + buf->off, msg_len, closure))
898
goto send_error;
899
buf->off += msg_len;
900
}
901
if (buf->len != buf->off) {
902
memmove(buf->data, buf->data + buf->off, buf->len - buf->off);
903
}
904
buf->len -= buf->off;
905
buf->off = 0;
906
debug_return;
907
908
send_error:
909
/*
910
* Try to send client an error message before closing connection.
911
* If we are already in an error state, just give up.
912
*/
913
if (!schedule_error_message(closure->errstr, closure))
914
goto close_connection;
915
debug_return;
916
917
close_connection:
918
connection_close(closure);
919
debug_return;
920
}
921
922
/*
923
* Forward a ClientMessage to the relay (write callback).
924
*/
925
static void
926
relay_client_msg_cb(int fd, int what, void *v)
927
{
928
struct connection_closure *closure = v;
929
struct relay_closure *relay_closure = closure->relay_closure;
930
struct connection_buffer *buf;
931
size_t nwritten;
932
debug_decl(relay_client_msg_cb, SUDO_DEBUG_UTIL);
933
934
/* For TLS we may need to write as part of SSL_read_ex(). */
935
if (relay_closure->read_instead_of_write) {
936
relay_closure->read_instead_of_write = false;
937
/* Delete write event if it was only due to SSL_read_ex(). */
938
if (relay_closure->temporary_write_event) {
939
relay_closure->temporary_write_event = false;
940
sudo_ev_del(closure->evbase, relay_closure->write_ev);
941
}
942
relay_server_msg_cb(fd, what, v);
943
debug_return;
944
}
945
946
if (what == SUDO_EV_TIMEOUT) {
947
sudo_warnx(U_("timed out writing to relay %s (%s)"),
948
relay_closure->relay_name.name, relay_closure->relay_name.ipaddr);
949
closure->errstr = _("timeout writing to relay");
950
goto send_error;
951
}
952
953
if ((buf = TAILQ_FIRST(&relay_closure->write_bufs)) == NULL) {
954
sudo_warnx(U_("missing write buffer for client %s"),
955
relay_closure->relay_name.ipaddr);
956
goto close_connection;
957
}
958
959
sudo_debug_printf(SUDO_DEBUG_INFO, "%s: sending %zu bytes to server %s (%s)",
960
__func__, buf->len - buf->off, relay_closure->relay_name.name,
961
relay_closure->relay_name.ipaddr);
962
963
#if defined(HAVE_OPENSSL)
964
if (relay_closure->tls_client.ssl != NULL) {
965
SSL *ssl = relay_closure->tls_client.ssl;
966
const int result = SSL_write_ex(ssl, buf->data + buf->off,
967
buf->len - buf->off, &nwritten);
968
if (result <= 0) {
969
const char *errstr;
970
971
switch (SSL_get_error(ssl, result)) {
972
case SSL_ERROR_ZERO_RETURN:
973
/* ssl connection shutdown cleanly */
974
shutdown(relay_closure->sock, SHUT_RDWR);
975
close(relay_closure->sock);
976
relay_closure->sock = -1;
977
sudo_ev_del(closure->evbase, relay_closure->read_ev);
978
sudo_ev_del(closure->evbase, relay_closure->write_ev);
979
980
if (closure->state != FINISHED) {
981
sudo_debug_printf(SUDO_DEBUG_WARN|SUDO_DEBUG_LINENO,
982
"premature EOF from %s (state %d)",
983
relay_closure->relay_name.ipaddr, closure->state);
984
closure->errstr = _("relay server closed connection");
985
goto send_error;
986
}
987
debug_return;
988
case SSL_ERROR_WANT_READ:
989
/* ssl wants to read, read event always active */
990
sudo_debug_printf(SUDO_DEBUG_NOTICE|SUDO_DEBUG_LINENO,
991
"SSL_write_ex returns SSL_ERROR_WANT_READ");
992
/* Redirect read event to finish SSL_write_ex() */
993
relay_closure->write_instead_of_read = true;
994
debug_return;
995
case SSL_ERROR_WANT_WRITE:
996
/* ssl wants to write more, write event remains active */
997
sudo_debug_printf(SUDO_DEBUG_NOTICE|SUDO_DEBUG_LINENO,
998
"SSL_write_ex returns SSL_ERROR_WANT_WRITE");
999
debug_return;
1000
case SSL_ERROR_SYSCALL:
1001
sudo_warn("%s: SSL_write_ex",
1002
relay_closure->relay_name.ipaddr);
1003
closure->errstr = _("error writing to relay");
1004
goto send_error;
1005
default:
1006
errstr = ERR_reason_error_string(ERR_get_error());
1007
sudo_warnx("%s: SSL_write_ex: %s",
1008
relay_closure->relay_name.ipaddr,
1009
errstr ? errstr : strerror(errno));
1010
closure->errstr = _("error writing to relay");
1011
goto send_error;
1012
}
1013
}
1014
} else
1015
#endif
1016
{
1017
const ssize_t n = write(fd, buf->data + buf->off, buf->len - buf->off);
1018
if (n < 0) {
1019
if (errno == EAGAIN || errno == EINTR)
1020
debug_return;
1021
sudo_warn("%s: write", relay_closure->relay_name.ipaddr);
1022
closure->errstr = _("error writing to relay");
1023
goto send_error;
1024
}
1025
nwritten = (size_t)n;
1026
}
1027
if (nwritten > SIZE_MAX - buf->off) {
1028
sudo_warnx(U_("internal error, %s overflow"), __func__);
1029
closure->errstr = _("error writing to relay");
1030
goto send_error;
1031
}
1032
buf->off += nwritten;
1033
1034
if (buf->off == buf->len) {
1035
/* sent entire message, move buf to free list */
1036
sudo_debug_printf(SUDO_DEBUG_INFO,
1037
"%s: finished sending %zu bytes to server", __func__, buf->len);
1038
buf->off = 0;
1039
buf->len = 0;
1040
TAILQ_REMOVE(&relay_closure->write_bufs, buf, entries);
1041
TAILQ_INSERT_TAIL(&closure->free_bufs, buf, entries);
1042
if (TAILQ_EMPTY(&relay_closure->write_bufs)) {
1043
/* Write queue empty, check state. */
1044
sudo_ev_del(closure->evbase, relay_closure->write_ev);
1045
if (closure->error || closure->state == FINISHED ||
1046
closure->state == SHUTDOWN)
1047
goto close_connection;
1048
}
1049
}
1050
debug_return;
1051
1052
send_error:
1053
/*
1054
* Try to send client an error message before closing connection.
1055
* If we are already in an error state, just give up.
1056
*/
1057
if (!schedule_error_message(closure->errstr, closure))
1058
goto close_connection;
1059
debug_return;
1060
1061
close_connection:
1062
connection_close(closure);
1063
debug_return;
1064
}
1065
1066
/* Begin the conversation with the relay host. */
1067
static bool
1068
start_relay(int sock, struct connection_closure *closure)
1069
{
1070
struct relay_closure *relay_closure = closure->relay_closure;
1071
debug_decl(start_relay, SUDO_DEBUG_UTIL);
1072
1073
/* No longer need the connect event. */
1074
sudo_ev_free(relay_closure->connect_ev);
1075
relay_closure->connect_ev = NULL;
1076
1077
/* Allocate relay read/write events now that we know the socket. */
1078
relay_closure->read_ev = sudo_ev_alloc(sock, SUDO_EV_READ|SUDO_EV_PERSIST,
1079
relay_server_msg_cb, closure);
1080
relay_closure->write_ev = sudo_ev_alloc(sock, SUDO_EV_WRITE|SUDO_EV_PERSIST,
1081
relay_client_msg_cb, closure);
1082
if (relay_closure->read_ev == NULL || relay_closure->write_ev == NULL)
1083
debug_return_bool(false);
1084
1085
/* Start communication with the relay server by saying hello. */
1086
debug_return_bool(fmt_client_hello(closure));
1087
}
1088
1089
/*
1090
* Relay an AcceptMessage from the client to the relay server.
1091
*/
1092
static bool
1093
relay_accept(const AcceptMessage *msg, const uint8_t *buf, size_t len,
1094
struct connection_closure *closure)
1095
{
1096
struct relay_closure *relay_closure = closure->relay_closure;
1097
const char *source = closure->journal_path ? closure->journal_path :
1098
closure->ipaddr;
1099
debug_decl(relay_accept, SUDO_DEBUG_UTIL);
1100
1101
sudo_debug_printf(SUDO_DEBUG_INFO,
1102
"%s: relaying AcceptMessage from %s to %s (%s)", __func__, source,
1103
relay_closure->relay_name.name, relay_closure->relay_name.ipaddr);
1104
1105
debug_return_bool(relay_enqueue_write(buf, len, closure));
1106
}
1107
1108
/*
1109
* Relay a RejectMessage from the client to the relay server.
1110
*/
1111
static bool
1112
relay_reject(const RejectMessage *msg, const uint8_t *buf, size_t len,
1113
struct connection_closure *closure)
1114
{
1115
struct relay_closure *relay_closure = closure->relay_closure;
1116
const char *source = closure->journal_path ? closure->journal_path :
1117
closure->ipaddr;
1118
debug_decl(relay_reject, SUDO_DEBUG_UTIL);
1119
1120
sudo_debug_printf(SUDO_DEBUG_INFO,
1121
"%s: relaying RejectMessage from %s to %s (%s)", __func__, source,
1122
relay_closure->relay_name.name, relay_closure->relay_name.ipaddr);
1123
1124
debug_return_bool(relay_enqueue_write(buf, len, closure));
1125
}
1126
1127
/*
1128
* Relay an ExitMessage from the client to the relay server.
1129
*/
1130
static bool
1131
relay_exit(const ExitMessage *msg, const uint8_t *buf, size_t len,
1132
struct connection_closure *closure)
1133
{
1134
struct relay_closure *relay_closure = closure->relay_closure;
1135
const char *source = closure->journal_path ? closure->journal_path :
1136
closure->ipaddr;
1137
debug_decl(relay_exit, SUDO_DEBUG_UTIL);
1138
1139
sudo_debug_printf(SUDO_DEBUG_INFO,
1140
"%s: relaying ExitMessage from %s to %s (%s)", __func__, source,
1141
relay_closure->relay_name.name, relay_closure->relay_name.ipaddr);
1142
1143
debug_return_bool(relay_enqueue_write(buf, len, closure));
1144
}
1145
1146
/*
1147
* Relay a RestartMessage from the client to the relay server.
1148
*/
1149
static bool
1150
relay_restart(const RestartMessage *msg, const uint8_t *buf, size_t len,
1151
struct connection_closure *closure)
1152
{
1153
struct relay_closure *relay_closure = closure->relay_closure;
1154
const char *source = closure->journal_path ? closure->journal_path :
1155
closure->ipaddr;
1156
debug_decl(relay_restart, SUDO_DEBUG_UTIL);
1157
1158
sudo_debug_printf(SUDO_DEBUG_INFO,
1159
"%s: relaying RestartMessage from %s to %s (%s)", __func__, source,
1160
relay_closure->relay_name.name, relay_closure->relay_name.ipaddr);
1161
1162
debug_return_bool(relay_enqueue_write(buf, len, closure));
1163
}
1164
1165
/*
1166
* Relay an AlertMessage from the client to the relay server.
1167
*/
1168
static bool
1169
relay_alert(const AlertMessage *msg, const uint8_t *buf, size_t len,
1170
struct connection_closure *closure)
1171
{
1172
struct relay_closure *relay_closure = closure->relay_closure;
1173
const char *source = closure->journal_path ? closure->journal_path :
1174
closure->ipaddr;
1175
debug_decl(relay_alert, SUDO_DEBUG_UTIL);
1176
1177
sudo_debug_printf(SUDO_DEBUG_INFO,
1178
"%s: relaying AlertMessage from %s to %s (%s)", __func__, source,
1179
relay_closure->relay_name.name, relay_closure->relay_name.ipaddr);
1180
1181
debug_return_bool(relay_enqueue_write(buf, len, closure));
1182
}
1183
1184
/*
1185
* Relay a CommandSuspend from the client to the relay server.
1186
*/
1187
static bool
1188
relay_suspend(const CommandSuspend *msg, const uint8_t *buf, size_t len,
1189
struct connection_closure *closure)
1190
{
1191
struct relay_closure *relay_closure = closure->relay_closure;
1192
const char *source = closure->journal_path ? closure->journal_path :
1193
closure->ipaddr;
1194
debug_decl(relay_suspend, SUDO_DEBUG_UTIL);
1195
1196
sudo_debug_printf(SUDO_DEBUG_INFO,
1197
"%s: relaying CommandSuspend from %s to %s (%s)", __func__, source,
1198
relay_closure->relay_name.name, relay_closure->relay_name.ipaddr);
1199
1200
debug_return_bool(relay_enqueue_write(buf, len, closure));
1201
}
1202
1203
/*
1204
* Relay a ChangeWindowSize from the client to the relay server.
1205
*/
1206
static bool
1207
relay_winsize(const ChangeWindowSize *msg, const uint8_t *buf, size_t len,
1208
struct connection_closure *closure)
1209
{
1210
struct relay_closure *relay_closure = closure->relay_closure;
1211
const char *source = closure->journal_path ? closure->journal_path :
1212
closure->ipaddr;
1213
debug_decl(relay_winsize, SUDO_DEBUG_UTIL);
1214
1215
sudo_debug_printf(SUDO_DEBUG_INFO,
1216
"%s: relaying ChangeWindowSize from %s to %s (%s)", __func__, source,
1217
relay_closure->relay_name.name, relay_closure->relay_name.ipaddr);
1218
1219
debug_return_bool(relay_enqueue_write(buf, len, closure));
1220
}
1221
1222
/*
1223
* Relay an IoBuffer from the client to the relay server.
1224
*/
1225
static bool
1226
relay_iobuf(int iofd, const IoBuffer *iobuf, const uint8_t *buf, size_t len,
1227
struct connection_closure *closure)
1228
{
1229
struct relay_closure *relay_closure = closure->relay_closure;
1230
const char *source = closure->journal_path ? closure->journal_path :
1231
closure->ipaddr;
1232
debug_decl(relay_iobuf, SUDO_DEBUG_UTIL);
1233
1234
sudo_debug_printf(SUDO_DEBUG_INFO,
1235
"%s: relaying IoBuffer from %s to %s (%s)", __func__, source,
1236
relay_closure->relay_name.name, relay_closure->relay_name.ipaddr);
1237
1238
debug_return_bool(relay_enqueue_write(buf, len, closure));
1239
}
1240
1241
/*
1242
* Shutdown relay connection when server is exiting.
1243
*/
1244
bool
1245
relay_shutdown(struct connection_closure *closure)
1246
{
1247
struct relay_closure *relay_closure = closure->relay_closure;
1248
debug_decl(relay_shutdown, SUDO_DEBUG_UTIL);
1249
1250
/* Close connection unless relay events are pending. */
1251
if (!sudo_ev_pending(relay_closure->read_ev, SUDO_EV_READ, NULL) &&
1252
!sudo_ev_pending(relay_closure->write_ev, SUDO_EV_WRITE, NULL) &&
1253
TAILQ_EMPTY(&relay_closure->write_bufs)) {
1254
connection_close(closure);
1255
}
1256
1257
debug_return_bool(true);
1258
}
1259
1260
struct client_message_switch cms_relay = {
1261
relay_accept,
1262
relay_reject,
1263
relay_exit,
1264
relay_restart,
1265
relay_alert,
1266
relay_iobuf,
1267
relay_suspend,
1268
relay_winsize
1269
};
1270
1271