Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sudo-project
GitHub Repository: sudo-project/sudo
Path: blob/main/logsrvd/logsrvd.c
3832 views
1
/*
2
* SPDX-License-Identifier: ISC
3
*
4
* Copyright (c) 2019-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/resource.h>
22
#include <sys/socket.h>
23
#include <sys/stat.h>
24
#include <sys/types.h>
25
#include <netinet/in.h>
26
#include <netinet/tcp.h>
27
#include <arpa/inet.h>
28
29
#include <errno.h>
30
#include <fcntl.h>
31
#include <limits.h>
32
#include <netdb.h>
33
#ifdef HAVE_STDBOOL_H
34
# include <stdbool.h>
35
#else
36
# include <compat/stdbool.h>
37
#endif /* HAVE_STDBOOL_H */
38
#if defined(HAVE_STDINT_H)
39
# include <stdint.h>
40
#elif defined(HAVE_INTTYPES_H)
41
# include <inttypes.h>
42
#endif
43
#include <stdio.h>
44
#include <stdlib.h>
45
#include <string.h>
46
#include <time.h>
47
#include <unistd.h>
48
#ifdef HAVE_GETOPT_LONG
49
# include <getopt.h>
50
# else
51
# include <compat/getopt.h>
52
#endif /* HAVE_GETOPT_LONG */
53
54
#define NEED_INET_NTOP /* to expose sudo_inet_ntop in sudo_compat.h */
55
56
#include <pathnames.h>
57
#include <sudo_compat.h>
58
#include <sudo_conf.h>
59
#include <sudo_debug.h>
60
#include <sudo_event.h>
61
#include <sudo_eventlog.h>
62
#include <sudo_fatal.h>
63
#include <sudo_gettext.h>
64
#include <sudo_json.h>
65
#include <sudo_iolog.h>
66
#include <sudo_queue.h>
67
#include <sudo_rand.h>
68
#include <sudo_util.h>
69
70
#include <logsrvd.h>
71
#include <hostcheck.h>
72
73
/*
74
* Sudo I/O audit server.
75
*/
76
static int logsrvd_debug_instance = SUDO_DEBUG_INSTANCE_INITIALIZER;
77
TAILQ_HEAD(connection_list, connection_closure);
78
static struct connection_list connections = TAILQ_HEAD_INITIALIZER(connections);
79
static struct listener_list listeners = TAILQ_HEAD_INITIALIZER(listeners);
80
static const char server_id[] = "Sudo Audit Server " PACKAGE_VERSION;
81
static const char *conf_file = NULL;
82
83
/* Event loop callbacks. */
84
static void client_msg_cb(int fd, int what, void *v);
85
static void server_msg_cb(int fd, int what, void *v);
86
static void server_commit_cb(int fd, int what, void *v);
87
#if defined(HAVE_OPENSSL)
88
static void tls_handshake_cb(int fd, int what, void *v);
89
#endif
90
91
static double random_drop;
92
93
/*
94
* Free a struct connection_closure container and its contents.
95
*/
96
static void
97
connection_closure_free(struct connection_closure *closure)
98
{
99
debug_decl(connection_closure_free, SUDO_DEBUG_UTIL);
100
101
if (closure != NULL) {
102
bool shutting_down = closure->state == SHUTDOWN;
103
struct sudo_event_base *evbase = closure->evbase;
104
struct connection_buffer *buf;
105
106
TAILQ_REMOVE(&connections, closure, entries);
107
108
if (closure->state == CONNECTING && closure->journal != NULL) {
109
/* Failed to relay journal file, retry later. */
110
logsrvd_queue_insert(closure);
111
}
112
if (closure->relay_closure != NULL)
113
relay_closure_free(closure->relay_closure);
114
#if defined(HAVE_OPENSSL)
115
if (closure->ssl != NULL) {
116
/* Must call SSL_shutdown() before closing closure->sock. */
117
sudo_debug_printf(SUDO_DEBUG_INFO|SUDO_DEBUG_LINENO,
118
"closing down TLS connection from %s", closure->ipaddr);
119
if (SSL_shutdown(closure->ssl) == 0)
120
SSL_shutdown(closure->ssl);
121
SSL_free(closure->ssl);
122
}
123
free(closure->name);
124
#endif
125
if (closure->sock != -1) {
126
shutdown(closure->sock, SHUT_RDWR);
127
close(closure->sock);
128
}
129
iolog_close_all(closure);
130
sudo_ev_free(closure->commit_ev);
131
sudo_ev_free(closure->read_ev);
132
sudo_ev_free(closure->write_ev);
133
#if defined(HAVE_OPENSSL)
134
sudo_ev_free(closure->ssl_accept_ev);
135
#endif
136
eventlog_free(closure->evlog);
137
free(closure->read_buf.data);
138
while ((buf = TAILQ_FIRST(&closure->write_bufs)) != NULL) {
139
sudo_debug_printf(SUDO_DEBUG_WARN|SUDO_DEBUG_LINENO,
140
"discarding write buffer %p, len %zu", buf, buf->len - buf->off);
141
TAILQ_REMOVE(&closure->write_bufs, buf, entries);
142
free(buf->data);
143
free(buf);
144
}
145
while ((buf = TAILQ_FIRST(&closure->free_bufs)) != NULL) {
146
TAILQ_REMOVE(&closure->free_bufs, buf, entries);
147
free(buf->data);
148
free(buf);
149
}
150
free(closure->journal_path);
151
if (closure->journal != NULL)
152
fclose(closure->journal);
153
free(closure);
154
155
if (shutting_down && TAILQ_EMPTY(&connections))
156
sudo_ev_loopbreak(evbase);
157
}
158
159
debug_return;
160
}
161
162
/*
163
* Allocate a new connection closure.
164
*/
165
struct connection_closure *
166
connection_closure_alloc(int fd, bool tls, bool relay_only,
167
struct sudo_event_base *base)
168
{
169
struct connection_closure *closure;
170
debug_decl(connection_closure_alloc, SUDO_DEBUG_UTIL);
171
172
if ((closure = calloc(1, sizeof(*closure))) == NULL)
173
debug_return_ptr(NULL);
174
175
closure->iolog_dir_fd = -1;
176
closure->sock = relay_only ? -1 : fd;
177
closure->evbase = base;
178
TAILQ_INIT(&closure->write_bufs);
179
TAILQ_INIT(&closure->free_bufs);
180
181
/* Use different message handlers depending on the operating mode. */
182
if (relay_only) {
183
closure->cms = &cms_relay;
184
} else if (logsrvd_conf_relay_store_first()) {
185
closure->store_first = true;
186
closure->cms = &cms_journal;
187
} else {
188
closure->cms = &cms_local;
189
}
190
191
TAILQ_INSERT_TAIL(&connections, closure, entries);
192
193
closure->read_buf.size = 64 * 1024;
194
closure->read_buf.data = malloc(closure->read_buf.size);
195
if (closure->read_buf.data == NULL)
196
goto bad;
197
198
closure->read_ev = sudo_ev_alloc(fd, SUDO_EV_READ|SUDO_EV_PERSIST,
199
client_msg_cb, closure);
200
if (closure->read_ev == NULL)
201
goto bad;
202
203
if (!relay_only) {
204
closure->write_ev = sudo_ev_alloc(fd, SUDO_EV_WRITE|SUDO_EV_PERSIST,
205
server_msg_cb, closure);
206
if (closure->write_ev == NULL)
207
goto bad;
208
209
closure->commit_ev = sudo_ev_alloc(-1, SUDO_EV_TIMEOUT,
210
server_commit_cb, closure);
211
if (closure->commit_ev == NULL)
212
goto bad;
213
}
214
#if defined(HAVE_OPENSSL)
215
if (tls) {
216
closure->ssl_accept_ev = sudo_ev_alloc(fd, SUDO_EV_READ,
217
tls_handshake_cb, closure);
218
if (closure->ssl_accept_ev == NULL)
219
goto bad;
220
}
221
#endif
222
223
debug_return_ptr(closure);
224
bad:
225
connection_closure_free(closure);
226
debug_return_ptr(NULL);
227
}
228
229
/*
230
* Close the client connection when finished.
231
* If in store-and-forward mode, initiate a relay connection.
232
* Otherwise, free the connection closure, removing any events.
233
*/
234
void
235
connection_close(struct connection_closure *closure)
236
{
237
struct connection_closure *new_closure;
238
debug_decl(connection_close, SUDO_DEBUG_UTIL);
239
240
if (closure == NULL)
241
debug_return;
242
243
/* Final state should be FINISHED except on error. */
244
sudo_debug_printf(SUDO_DEBUG_INFO|SUDO_DEBUG_LINENO,
245
"%s: closure %p, final state %d, relay_closure %p, "
246
"journal file %p, journal path %s", __func__, closure,
247
closure->state, closure->relay_closure, closure->journal,
248
closure->journal_path ? closure->journal_path : "");
249
250
/*
251
* If we finished a client connection in store-and-forward mode,
252
* create a new connection for the relay and replay the journal.
253
*/
254
if (closure->store_first && closure->state == FINISHED &&
255
closure->relay_closure == NULL && closure->journal != NULL) {
256
new_closure = connection_closure_alloc(fileno(closure->journal), false,
257
true, closure->evbase);
258
if (new_closure != NULL) {
259
/* Re-parent journal settings. */
260
new_closure->journal = closure->journal;
261
closure->journal = NULL;
262
new_closure->journal_path = closure->journal_path;
263
closure->journal_path = NULL;
264
265
/* Connect to the first relay available asynchronously. */
266
if (!connect_relay(new_closure)) {
267
sudo_warnx("%s", U_("unable to connect to relay"));
268
connection_closure_free(new_closure);
269
}
270
}
271
}
272
if (closure->state == FINISHED && closure->journal_path != NULL) {
273
/* Journal relayed successfully, remove backing file. */
274
sudo_debug_printf(SUDO_DEBUG_INFO|SUDO_DEBUG_LINENO,
275
"removing journal file %s", closure->journal_path);
276
unlink(closure->journal_path);
277
278
/* Process the next outgoing file (if any). */
279
logsrvd_queue_enable(0, closure->evbase);
280
}
281
connection_closure_free(closure);
282
283
debug_return;
284
}
285
286
struct connection_buffer *
287
get_free_buf(size_t len, struct connection_closure *closure)
288
{
289
struct connection_buffer *buf;
290
debug_decl(get_free_buf, SUDO_DEBUG_UTIL);
291
292
buf = TAILQ_FIRST(&closure->free_bufs);
293
if (buf != NULL) {
294
TAILQ_REMOVE(&closure->free_bufs, buf, entries);
295
} else {
296
if ((buf = calloc(1, sizeof(*buf))) == NULL)
297
goto oom;
298
}
299
300
if (len > buf->size) {
301
const size_t new_size = sudo_pow2_roundup(len);
302
if (new_size < len) {
303
/* overflow */
304
errno = ENOMEM;
305
goto oom;
306
}
307
free(buf->data);
308
if ((buf->data = malloc(new_size)) == NULL)
309
goto oom;
310
buf->size = new_size;
311
}
312
313
debug_return_ptr(buf);
314
oom:
315
if (buf != NULL) {
316
free(buf->data);
317
free(buf);
318
}
319
sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
320
debug_return_ptr(NULL);
321
}
322
323
bool
324
fmt_server_message(struct connection_closure *closure, ServerMessage *msg)
325
{
326
struct connection_buffer *buf = NULL;
327
uint32_t msg_len;
328
bool ret = false;
329
size_t len;
330
debug_decl(fmt_server_message, SUDO_DEBUG_UTIL);
331
332
len = server_message__get_packed_size(msg);
333
if (len > MESSAGE_SIZE_MAX) {
334
sudo_warnx(U_("server message too large: %zu"), len);
335
goto done;
336
}
337
338
/* Wire message size is used for length encoding, precedes message. */
339
msg_len = htonl((uint32_t)len);
340
len += sizeof(msg_len);
341
342
sudo_debug_printf(SUDO_DEBUG_INFO|SUDO_DEBUG_LINENO,
343
"size + server message %zu bytes", len);
344
345
if ((buf = get_free_buf(len, closure)) == NULL) {
346
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
347
"unable to allocate connection_buffer");
348
goto done;
349
}
350
memcpy(buf->data, &msg_len, sizeof(msg_len));
351
server_message__pack(msg, buf->data + sizeof(msg_len));
352
buf->len = len;
353
TAILQ_INSERT_TAIL(&closure->write_bufs, buf, entries);
354
355
ret = true;
356
357
done:
358
debug_return_bool(ret);
359
}
360
361
static bool
362
fmt_hello_message(struct connection_closure *closure)
363
{
364
ServerMessage msg = SERVER_MESSAGE__INIT;
365
ServerHello hello = SERVER_HELLO__INIT;
366
debug_decl(fmt_hello_message, SUDO_DEBUG_UTIL);
367
368
/* TODO: implement redirect and servers array. */
369
hello.server_id = (char *)server_id;
370
hello.subcommands = true;
371
msg.u.hello = &hello;
372
msg.type_case = SERVER_MESSAGE__TYPE_HELLO;
373
374
debug_return_bool(fmt_server_message(closure, &msg));
375
}
376
377
static char *
378
gen_log_id(const unsigned char *uuid, const char *path,
379
struct connection_closure *closure)
380
{
381
size_t b64_size, id_len, pathlen = strlen(path);
382
char *b64_id = NULL;
383
unsigned char *id;
384
debug_decl(gen_log_id, SUDO_DEBUG_UTIL);
385
386
/* Log ID is 16-byte UUID + path. */
387
id_len = 16 + pathlen;
388
if ((id = malloc(id_len)) == NULL) {
389
sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
390
goto done;
391
}
392
memcpy(id, uuid, 16);
393
memcpy(id + 16, path, pathlen);
394
395
/* Base64 encode log ID */
396
b64_size = ((id_len + 2) / 3 * 4) + 1;
397
if ((b64_id = malloc(b64_size)) == NULL) {
398
sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
399
goto done;
400
}
401
if (sudo_base64_encode(id, id_len, b64_id, b64_size) == (size_t)-1) {
402
sudo_warnx("%s", U_("unable to base64 log ID"));
403
free(b64_id);
404
b64_id = NULL;
405
}
406
407
done:
408
free(id);
409
debug_return_str(b64_id);
410
}
411
412
bool
413
fmt_log_id_message(const unsigned char uuid[restrict static 16],
414
const char *path, struct connection_closure *closure)
415
{
416
ServerMessage msg = SERVER_MESSAGE__INIT;
417
bool ret = false;
418
debug_decl(fmt_log_id_message, SUDO_DEBUG_UTIL);
419
420
/* Generate log_id from path and closure's UUID */
421
msg.type_case = SERVER_MESSAGE__TYPE_LOG_ID;
422
msg.u.log_id = gen_log_id(uuid, path, closure);
423
if (msg.u.log_id != NULL) {
424
ret = fmt_server_message(closure, &msg);
425
free(msg.u.log_id);
426
}
427
428
debug_return_bool(ret);
429
}
430
431
static bool
432
fmt_error_message(const char *errstr, struct connection_closure *closure)
433
{
434
ServerMessage msg = SERVER_MESSAGE__INIT;
435
debug_decl(fmt_error_message, SUDO_DEBUG_UTIL);
436
437
msg.u.error = (char *)errstr;
438
msg.type_case = SERVER_MESSAGE__TYPE_ERROR;
439
440
debug_return_bool(fmt_server_message(closure, &msg));
441
}
442
443
/*
444
* Format a ServerMessage with the error string and add it to the write queue.
445
* Also sets the error flag state to true.
446
* Returns true if successfully scheduled, else false.
447
*/
448
bool
449
schedule_error_message(const char *errstr, struct connection_closure *closure)
450
{
451
bool ret = false;
452
debug_decl(schedule_error_message, SUDO_DEBUG_UTIL);
453
454
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
455
"send error to client: %s", errstr ? errstr : "none");
456
457
/*
458
* Prevent further reads from the client and any relay I/O.
459
* Just write the error to the client.
460
*/
461
sudo_ev_del(closure->evbase, closure->read_ev);
462
if (closure->relay_closure != NULL) {
463
sudo_ev_del(closure->evbase, closure->relay_closure->read_ev);
464
sudo_ev_del(closure->evbase, closure->relay_closure->write_ev);
465
}
466
467
if (errstr == NULL || closure->error || closure->write_ev == NULL)
468
goto done;
469
470
/* Format error message and add to the write queue. */
471
if (!fmt_error_message(errstr, closure))
472
goto done;
473
if (sudo_ev_add(closure->evbase, closure->write_ev,
474
logsrvd_conf_server_timeout(), true) == -1) {
475
sudo_warnx("%s", U_("unable to add event to queue"));
476
goto done;
477
}
478
ret = true;
479
480
done:
481
closure->error = true;
482
debug_return_bool(ret);
483
}
484
485
/*
486
* AcceptMessage handler.
487
*/
488
static bool
489
handle_accept(const AcceptMessage *msg, const uint8_t *buf, size_t len,
490
struct connection_closure *closure)
491
{
492
const char *source = closure->journal_path ? closure->journal_path :
493
closure->ipaddr;
494
bool ret;
495
debug_decl(handle_accept, SUDO_DEBUG_UTIL);
496
497
/* We can get an AcceptMessage for a sub-command during a session. */
498
if (closure->state == EXITED || closure->state == FINISHED) {
499
sudo_warnx(U_("unexpected state %d for %s"), closure->state, source);
500
closure->errstr = _("state machine error");
501
debug_return_bool(false);
502
}
503
504
/* Check that message is valid. */
505
if (msg == NULL || msg->submit_time == NULL || msg->n_info_msgs == 0) {
506
sudo_warnx(U_("%s: %s"), source, U_("invalid AcceptMessage"));
507
closure->errstr = _("invalid AcceptMessage");
508
debug_return_bool(false);
509
}
510
sudo_debug_printf(SUDO_DEBUG_INFO, "%s: received AcceptMessage from %s",
511
__func__, source);
512
513
ret = closure->cms->accept(msg, buf, len, closure);
514
if (ret && closure->state == INITIAL) {
515
if (msg->expect_iobufs)
516
closure->log_io = true;
517
closure->state = RUNNING;
518
}
519
debug_return_bool(ret);
520
}
521
522
/*
523
* RejectMessage handler.
524
*/
525
static bool
526
handle_reject(const RejectMessage *msg, const uint8_t *buf, size_t len,
527
struct connection_closure *closure)
528
{
529
const char *source = closure->journal_path ? closure->journal_path :
530
closure->ipaddr;
531
bool ret;
532
debug_decl(handle_reject, SUDO_DEBUG_UTIL);
533
534
/* We can get a RejectMessage for a sub-command during a session. */
535
if (closure->state == EXITED || closure->state == FINISHED) {
536
sudo_warnx(U_("unexpected state %d for %s"), closure->state, source);
537
closure->errstr = _("state machine error");
538
debug_return_bool(false);
539
}
540
541
/* Check that message is valid. */
542
if (msg == NULL || msg->submit_time == NULL || msg->reason[0] == '\0' ||
543
msg->n_info_msgs == 0) {
544
sudo_warnx(U_("%s: %s"), source, U_("invalid RejectMessage"));
545
closure->errstr = _("invalid RejectMessage");
546
debug_return_bool(false);
547
}
548
sudo_debug_printf(SUDO_DEBUG_INFO, "%s: received RejectMessage from %s",
549
__func__, source);
550
551
ret = closure->cms->reject(msg, buf, len, closure);
552
if (ret && closure->state == INITIAL) {
553
closure->state = FINISHED;
554
}
555
556
debug_return_bool(ret);
557
}
558
559
static bool
560
handle_exit(const ExitMessage *msg, const uint8_t *buf, size_t len,
561
struct connection_closure *closure)
562
{
563
const char *source = closure->journal_path ? closure->journal_path :
564
closure->ipaddr;
565
bool ret;
566
debug_decl(handle_exit, SUDO_DEBUG_UTIL);
567
568
if (closure->state != RUNNING) {
569
sudo_warnx(U_("unexpected state %d for %s"), closure->state, source);
570
closure->errstr = _("state machine error");
571
debug_return_bool(false);
572
}
573
574
/*
575
* Check that message is valid.
576
* The run_time field is optional and will not be present
577
* when sending old, pre-JSON I/O logs via sudo_sendlog.
578
*/
579
if (msg == NULL) {
580
sudo_warnx(U_("%s: %s"), source, U_("invalid ExitMessage"));
581
closure->errstr = _("invalid ExitMessage");
582
debug_return_bool(false);
583
}
584
sudo_debug_printf(SUDO_DEBUG_INFO, "%s: received ExitMessage from %s",
585
source, __func__);
586
587
ret = closure->cms->exit(msg, buf, len, closure);
588
if (ret) {
589
if (sudo_timespecisset(&closure->elapsed_time)) {
590
sudo_debug_printf(SUDO_DEBUG_INFO, "%s: elapsed time: [%lld, %ld]",
591
__func__, (long long)closure->elapsed_time.tv_sec,
592
closure->elapsed_time.tv_nsec);
593
}
594
595
if (closure->log_io) {
596
/* Command exited, client waiting for final commit point. */
597
closure->state = EXITED;
598
599
/* Relay host will send the final commit point. */
600
if (closure->relay_closure == NULL) {
601
struct timespec tv = { 0, 0 };
602
if (sudo_ev_add(closure->evbase, closure->commit_ev, &tv, false) == -1) {
603
sudo_warnx("%s", U_("unable to add event to queue"));
604
ret = false;
605
}
606
}
607
} else {
608
/* No commit point to send to client, we are finished. */
609
closure->state = FINISHED;
610
}
611
}
612
sudo_ev_del(closure->evbase, closure->read_ev);
613
614
debug_return_bool(ret);
615
}
616
617
static bool
618
handle_restart(const RestartMessage *msg, const uint8_t *buf, size_t len,
619
struct connection_closure *closure)
620
{
621
const char *source = closure->journal_path ? closure->journal_path :
622
closure->ipaddr;
623
bool ret = true;
624
debug_decl(handle_restart, SUDO_DEBUG_UTIL);
625
626
if (closure->state != INITIAL) {
627
sudo_warnx(U_("unexpected state %d for %s"), closure->state, source);
628
closure->errstr = _("state machine error");
629
debug_return_bool(false);
630
}
631
632
/* Check that message is valid. */
633
if (msg == NULL || msg->log_id[0] == '\0' || !valid_timespec(msg->resume_point)) {
634
sudo_warnx(U_("%s: %s"), source, U_("invalid RestartMessage"));
635
closure->errstr = _("invalid RestartMessage");
636
debug_return_bool(false);
637
}
638
sudo_debug_printf(SUDO_DEBUG_INFO,
639
"%s: received RestartMessage for %s from %s", __func__, msg->log_id,
640
source);
641
642
/* Only I/O logs are restartable. */
643
closure->log_io = true;
644
645
if (closure->cms->restart(msg, buf, len, closure)) {
646
/* Successfully restarted. */
647
closure->state = RUNNING;
648
} else {
649
/* Report error to client before closing the connection. */
650
sudo_debug_printf(SUDO_DEBUG_WARN, "%s: unable to restart I/O log",
651
__func__);
652
if (!schedule_error_message(closure->errstr, closure))
653
ret = false;
654
}
655
656
debug_return_bool(ret);
657
}
658
659
static bool
660
handle_alert(const AlertMessage *msg, const uint8_t *buf, size_t len,
661
struct connection_closure *closure)
662
{
663
const char *source = closure->journal_path ? closure->journal_path :
664
closure->ipaddr;
665
debug_decl(handle_alert, SUDO_DEBUG_UTIL);
666
667
/* Check that message is valid. */
668
if (msg == NULL || msg->alert_time == NULL || msg->reason[0] == '\0') {
669
sudo_warnx(U_("%s: %s"), source, U_("invalid AlertMessage"));
670
closure->errstr = _("invalid AlertMessage");
671
debug_return_bool(false);
672
}
673
sudo_debug_printf(SUDO_DEBUG_INFO, "%s: received AlertMessage from %s",
674
source, __func__);
675
676
debug_return_bool(closure->cms->alert(msg, buf, len, closure));
677
}
678
679
/* Enable a commit event if not relaying and it is not already pending. */
680
static bool
681
enable_commit(struct connection_closure *closure)
682
{
683
debug_decl(enable_commit, SUDO_DEBUG_UTIL);
684
685
if (closure->relay_closure == NULL) {
686
if (!ISSET(closure->commit_ev->flags, SUDO_EVQ_INSERTED)) {
687
struct timespec tv = { ACK_FREQUENCY, 0 };
688
if (sudo_ev_add(closure->evbase, closure->commit_ev, &tv, false) == -1) {
689
sudo_warnx("%s", U_("unable to add event to queue"));
690
debug_return_bool(false);
691
}
692
}
693
}
694
debug_return_bool(true);
695
}
696
697
static bool
698
handle_iobuf(int iofd, const IoBuffer *iobuf, const uint8_t *buf, size_t len,
699
struct connection_closure *closure)
700
{
701
const char *source = closure->journal_path ? closure->journal_path :
702
closure->ipaddr;
703
debug_decl(handle_iobuf, SUDO_DEBUG_UTIL);
704
705
if (closure->state != RUNNING) {
706
sudo_warnx(U_("unexpected state %d for %s"), closure->state, source);
707
closure->errstr = _("state machine error");
708
debug_return_bool(false);
709
}
710
if (!closure->log_io) {
711
sudo_warnx(U_("%s: unexpected IoBuffer"), source);
712
closure->errstr = _("protocol error");
713
debug_return_bool(false);
714
}
715
716
/* Check that message is valid. */
717
if (iobuf == NULL || iobuf->data.len == 0 || !valid_timespec(iobuf->delay)) {
718
sudo_warnx(U_("%s: %s"), source, U_("invalid IoBuffer"));
719
closure->errstr = _("invalid IoBuffer");
720
debug_return_bool(false);
721
}
722
723
sudo_debug_printf(SUDO_DEBUG_INFO, "%s: received IoBuffer from %s",
724
source, __func__);
725
726
/* Random drop is a debugging tool to test client restart. */
727
if (random_drop > 0.0) {
728
double randval = arc4random() / (double)UINT32_MAX;
729
if (randval < random_drop) {
730
closure->errstr = _("randomly dropping connection");
731
sudo_debug_printf(SUDO_DEBUG_WARN|SUDO_DEBUG_LINENO,
732
"randomly dropping connection (%f < %f)", randval, random_drop);
733
debug_return_bool(false);
734
}
735
}
736
737
if (!closure->cms->iobuf(iofd, iobuf, buf, len, closure))
738
debug_return_bool(false);
739
if (!enable_commit(closure))
740
debug_return_bool(false);
741
742
debug_return_bool(true);
743
}
744
745
static bool
746
handle_winsize(const ChangeWindowSize *msg, const uint8_t *buf, size_t len,
747
struct connection_closure *closure)
748
{
749
const char *source = closure->journal_path ? closure->journal_path :
750
closure->ipaddr;
751
debug_decl(handle_winsize, SUDO_DEBUG_UTIL);
752
753
if (closure->state != RUNNING) {
754
sudo_warnx(U_("unexpected state %d for %s"), closure->state, source);
755
closure->errstr = _("state machine error");
756
debug_return_bool(false);
757
}
758
if (!closure->log_io) {
759
sudo_warnx(U_("%s: unexpected IoBuffer"), source);
760
closure->errstr = _("protocol error");
761
debug_return_bool(false);
762
}
763
764
/* Check that message is valid. */
765
if (msg == NULL || !valid_timespec(msg->delay)) {
766
sudo_warnx(U_("%s: %s"), source, U_("invalid ChangeWindowSize"));
767
closure->errstr = _("invalid ChangeWindowSize");
768
debug_return_bool(false);
769
}
770
sudo_debug_printf(SUDO_DEBUG_INFO, "%s: received ChangeWindowSize from %s",
771
source, __func__);
772
773
if (!closure->cms->winsize(msg, buf, len, closure))
774
debug_return_bool(false);
775
if (!enable_commit(closure))
776
debug_return_bool(false);
777
778
debug_return_bool(true);
779
}
780
781
static bool
782
handle_suspend(const CommandSuspend *msg, const uint8_t *buf, size_t len,
783
struct connection_closure *closure)
784
{
785
const char *source = closure->journal_path ? closure->journal_path :
786
closure->ipaddr;
787
debug_decl(handle_syspend, SUDO_DEBUG_UTIL);
788
789
if (closure->state != RUNNING) {
790
sudo_warnx(U_("unexpected state %d for %s"), closure->state, source);
791
closure->errstr = _("state machine error");
792
debug_return_bool(false);
793
}
794
if (!closure->log_io) {
795
sudo_warnx(U_("%s: unexpected IoBuffer"), source);
796
closure->errstr = _("protocol error");
797
debug_return_bool(false);
798
}
799
800
/* Check that message is valid. */
801
if (msg == NULL || !valid_timespec(msg->delay)) {
802
sudo_warnx(U_("%s: %s"), source, U_("invalid CommandSuspend"));
803
closure->errstr = _("invalid CommandSuspend");
804
debug_return_bool(false);
805
}
806
if (strcmp(msg->signal, "STOP") != 0 && strcmp(msg->signal, "TSTP") != 0 &&
807
strcmp(msg->signal, "CONT") != 0 &&
808
strcmp(msg->signal, "TTIN") != 0 &&
809
strcmp(msg->signal, "TTOU") != 0) {
810
sudo_warnx(U_("%s: %s"), source, U_("invalid CommandSuspend"));
811
closure->errstr = _("invalid CommandSuspend");
812
debug_return_bool(false);
813
}
814
815
sudo_debug_printf(SUDO_DEBUG_INFO, "%s: received CommandSuspend from %s",
816
source, __func__);
817
818
if (!closure->cms->suspend(msg, buf, len, closure))
819
debug_return_bool(false);
820
if (!enable_commit(closure))
821
debug_return_bool(false);
822
823
debug_return_bool(true);
824
}
825
826
static bool
827
handle_client_hello(const ClientHello *msg, const uint8_t *buf, size_t len,
828
struct connection_closure *closure)
829
{
830
const char *source = closure->journal_path ? closure->journal_path :
831
closure->ipaddr;
832
debug_decl(handle_client_hello, SUDO_DEBUG_UTIL);
833
834
if (closure->state != INITIAL) {
835
sudo_warnx(U_("unexpected state %d for %s"), closure->state, source);
836
closure->errstr = _("state machine error");
837
debug_return_bool(false);
838
}
839
840
/* Check that message is valid. */
841
if (msg == NULL || msg->client_id[0] == '\0') {
842
sudo_warnx(U_("%s: %s"), source, U_("invalid ClientHello"));
843
closure->errstr = _("invalid ClientHello");
844
debug_return_bool(false);
845
}
846
sudo_debug_printf(SUDO_DEBUG_INFO, "%s: received ClientHello",
847
__func__);
848
sudo_debug_printf(SUDO_DEBUG_INFO, "%s: client ID %s",
849
__func__, msg->client_id);
850
851
debug_return_bool(true);
852
}
853
854
static bool
855
handle_client_message(const uint8_t *buf, size_t len,
856
struct connection_closure *closure)
857
{
858
const char *source = closure->journal_path ? closure->journal_path :
859
closure->ipaddr;
860
ClientMessage *msg;
861
bool ret = false;
862
debug_decl(handle_client_message, SUDO_DEBUG_UTIL);
863
864
/* TODO: can we extract type_case without unpacking for relay case? */
865
msg = client_message__unpack(NULL, len, buf);
866
if (msg == NULL) {
867
sudo_warnx(U_("unable to unpack %s size %zu"), "ClientMessage", len);
868
debug_return_bool(false);
869
}
870
871
switch (msg->type_case) {
872
case CLIENT_MESSAGE__TYPE_ACCEPT_MSG:
873
ret = handle_accept(msg->u.accept_msg, buf, len, closure);
874
break;
875
case CLIENT_MESSAGE__TYPE_REJECT_MSG:
876
ret = handle_reject(msg->u.reject_msg, buf, len, closure);
877
break;
878
case CLIENT_MESSAGE__TYPE_EXIT_MSG:
879
ret = handle_exit(msg->u.exit_msg, buf, len, closure);
880
break;
881
case CLIENT_MESSAGE__TYPE_RESTART_MSG:
882
ret = handle_restart(msg->u.restart_msg, buf, len, closure);
883
break;
884
case CLIENT_MESSAGE__TYPE_ALERT_MSG:
885
ret = handle_alert(msg->u.alert_msg, buf, len, closure);
886
break;
887
case CLIENT_MESSAGE__TYPE_TTYIN_BUF:
888
ret = handle_iobuf(IOFD_TTYIN, msg->u.ttyin_buf, buf, len, closure);
889
break;
890
case CLIENT_MESSAGE__TYPE_TTYOUT_BUF:
891
ret = handle_iobuf(IOFD_TTYOUT, msg->u.ttyout_buf, buf, len, closure);
892
break;
893
case CLIENT_MESSAGE__TYPE_STDIN_BUF:
894
ret = handle_iobuf(IOFD_STDIN, msg->u.stdin_buf, buf, len, closure);
895
break;
896
case CLIENT_MESSAGE__TYPE_STDOUT_BUF:
897
ret = handle_iobuf(IOFD_STDOUT, msg->u.stdout_buf, buf, len, closure);
898
break;
899
case CLIENT_MESSAGE__TYPE_STDERR_BUF:
900
ret = handle_iobuf(IOFD_STDERR, msg->u.stderr_buf, buf, len, closure);
901
break;
902
case CLIENT_MESSAGE__TYPE_WINSIZE_EVENT:
903
ret = handle_winsize(msg->u.winsize_event, buf, len, closure);
904
break;
905
case CLIENT_MESSAGE__TYPE_SUSPEND_EVENT:
906
ret = handle_suspend(msg->u.suspend_event, buf, len, closure);
907
break;
908
case CLIENT_MESSAGE__TYPE_HELLO_MSG:
909
ret = handle_client_hello(msg->u.hello_msg, buf, len, closure);
910
break;
911
default:
912
sudo_warnx(U_("unexpected type_case value %d in %s from %s"),
913
msg->type_case, "ClientMessage", source);
914
closure->errstr = _("unrecognized ClientMessage type");
915
break;
916
}
917
client_message__free_unpacked(msg, NULL);
918
919
debug_return_bool(ret);
920
}
921
922
static void
923
shutdown_cb(int unused, int what, void *v)
924
{
925
struct sudo_event_base *base = v;
926
debug_decl(shutdown_cb, SUDO_DEBUG_UTIL);
927
928
sudo_ev_loopbreak(base);
929
930
debug_return;
931
}
932
933
/*
934
* Shut down active client connections if any, or exit immediately.
935
*/
936
static void
937
server_shutdown(struct sudo_event_base *base)
938
{
939
struct connection_closure *closure, *next;
940
struct sudo_event *ev;
941
struct timespec tv = { 0, 0 };
942
debug_decl(server_shutdown, SUDO_DEBUG_UTIL);
943
944
if (TAILQ_EMPTY(&connections)) {
945
sudo_ev_loopbreak(base);
946
debug_return;
947
}
948
949
TAILQ_FOREACH_SAFE(closure, &connections, entries, next) {
950
closure->state = SHUTDOWN;
951
sudo_ev_del(base, closure->read_ev);
952
if (closure->relay_closure != NULL) {
953
/* Connection being relayed, check for pending I/O. */
954
relay_shutdown(closure);
955
} else if (closure->log_io) {
956
/* Schedule final commit point for the connection. */
957
if (sudo_ev_add(base, closure->commit_ev, &tv, false) == -1) {
958
sudo_warnx("%s", U_("unable to add event to queue"));
959
}
960
} else {
961
/* No commit point, close connection immediately. */
962
connection_close(closure);
963
}
964
}
965
966
if (!TAILQ_EMPTY(&connections)) {
967
/* We need a timed event to exit even if clients time out. */
968
ev = sudo_ev_alloc(-1, SUDO_EV_TIMEOUT, shutdown_cb, base);
969
if (ev != NULL) {
970
tv.tv_sec = SHUTDOWN_TIMEO;
971
if (sudo_ev_add(base, ev, &tv, false) == -1) {
972
sudo_warnx("%s", U_("unable to add event to queue"));
973
}
974
}
975
}
976
977
debug_return;
978
}
979
980
/*
981
* Send a server message to the client.
982
*/
983
static void
984
server_msg_cb(int fd, int what, void *v)
985
{
986
struct connection_closure *closure = v;
987
struct connection_buffer *buf;
988
size_t nwritten;
989
debug_decl(server_msg_cb, SUDO_DEBUG_UTIL);
990
991
/* For TLS we may need to write as part of SSL_read_ex(). */
992
if (closure->read_instead_of_write) {
993
closure->read_instead_of_write = false;
994
/* Delete write event if it was only due to SSL_read_ex(). */
995
if (closure->temporary_write_event) {
996
closure->temporary_write_event = false;
997
sudo_ev_del(closure->evbase, closure->write_ev);
998
}
999
client_msg_cb(fd, what, v);
1000
debug_return;
1001
}
1002
1003
if (what == SUDO_EV_TIMEOUT) {
1004
sudo_warnx(U_("timed out writing to client %s"), closure->ipaddr);
1005
goto finished;
1006
}
1007
1008
if ((buf = TAILQ_FIRST(&closure->write_bufs)) == NULL) {
1009
sudo_warnx(U_("missing write buffer for client %s"), closure->ipaddr);
1010
goto finished;
1011
}
1012
1013
sudo_debug_printf(SUDO_DEBUG_INFO, "%s: sending %zu bytes to client (%s)",
1014
__func__, buf->len - buf->off, closure->ipaddr);
1015
1016
#if defined(HAVE_OPENSSL)
1017
if (closure->ssl != NULL) {
1018
const int result = SSL_write_ex(closure->ssl, buf->data + buf->off,
1019
buf->len - buf->off, &nwritten);
1020
if (result <= 0) {
1021
const char *errstr;
1022
switch (SSL_get_error(closure->ssl, result)) {
1023
case SSL_ERROR_WANT_READ:
1024
/* ssl wants to read, read event always active */
1025
sudo_debug_printf(SUDO_DEBUG_NOTICE|SUDO_DEBUG_LINENO,
1026
"SSL_write_ex returns SSL_ERROR_WANT_READ");
1027
/* Redirect persistent read event to finish SSL_write_ex() */
1028
closure->write_instead_of_read = true;
1029
debug_return;
1030
case SSL_ERROR_WANT_WRITE:
1031
/* ssl wants to write more, write event remains active */
1032
sudo_debug_printf(SUDO_DEBUG_NOTICE|SUDO_DEBUG_LINENO,
1033
"SSL_write_ex returns SSL_ERROR_WANT_WRITE");
1034
debug_return;
1035
case SSL_ERROR_SYSCALL:
1036
sudo_warn("%s: SSL_write_ex", closure->ipaddr);
1037
goto finished;
1038
default:
1039
errstr = ERR_reason_error_string(ERR_get_error());
1040
sudo_warnx("%s: SSL_write_ex: %s", closure->ipaddr,
1041
errstr ? errstr : strerror(errno));
1042
goto finished;
1043
}
1044
}
1045
} else
1046
#endif
1047
{
1048
const ssize_t n = write(fd, buf->data + buf->off, buf->len - buf->off);
1049
if (n < 0) {
1050
if (errno == EAGAIN || errno == EINTR)
1051
debug_return;
1052
sudo_warn("%s: write", closure->ipaddr);
1053
goto finished;
1054
}
1055
nwritten = (size_t)n;
1056
}
1057
if (nwritten > SIZE_MAX - buf->off) {
1058
sudo_warnx(U_("internal error, %s overflow"), __func__);
1059
goto finished;
1060
}
1061
buf->off += nwritten;
1062
1063
if (buf->off == buf->len) {
1064
/* sent entire message, move buf to free list */
1065
sudo_debug_printf(SUDO_DEBUG_INFO,
1066
"%s: finished sending %zu bytes to client", __func__, buf->len);
1067
buf->off = 0;
1068
buf->len = 0;
1069
TAILQ_REMOVE(&closure->write_bufs, buf, entries);
1070
TAILQ_INSERT_TAIL(&closure->free_bufs, buf, entries);
1071
if (TAILQ_EMPTY(&closure->write_bufs)) {
1072
/* Write queue empty, check state. */
1073
sudo_ev_del(closure->evbase, closure->write_ev);
1074
if (closure->error || closure->state == FINISHED ||
1075
closure->state == SHUTDOWN)
1076
goto finished;
1077
}
1078
}
1079
debug_return;
1080
1081
finished:
1082
connection_close(closure);
1083
debug_return;
1084
}
1085
1086
/*
1087
* Receive client message(s).
1088
*/
1089
static void
1090
client_msg_cb(int fd, int what, void *v)
1091
{
1092
struct connection_closure *closure = v;
1093
struct connection_buffer *buf = &closure->read_buf;
1094
const char *source = closure->journal_path ? closure->journal_path :
1095
closure->ipaddr;
1096
uint32_t msg_len;
1097
size_t nread;
1098
debug_decl(client_msg_cb, SUDO_DEBUG_UTIL);
1099
1100
/* For TLS we may need to read as part of SSL_write_ex(). */
1101
if (closure->write_instead_of_read) {
1102
closure->write_instead_of_read = false;
1103
server_msg_cb(fd, what, v);
1104
debug_return;
1105
}
1106
1107
if (what == SUDO_EV_TIMEOUT) {
1108
sudo_warnx(U_("timed out reading from client %s"), closure->ipaddr);
1109
goto close_connection;
1110
}
1111
1112
#if defined(HAVE_OPENSSL)
1113
if (closure->ssl != NULL) {
1114
const int result = SSL_read_ex(closure->ssl, buf->data + buf->len,
1115
buf->size - buf->len, &nread);
1116
if (result <= 0) {
1117
const char *errstr;
1118
switch (SSL_get_error(closure->ssl, result)) {
1119
case SSL_ERROR_ZERO_RETURN:
1120
/* ssl connection shutdown cleanly */
1121
nread = 0;
1122
break;
1123
case SSL_ERROR_WANT_READ:
1124
/* ssl wants to read more, read event is always active */
1125
sudo_debug_printf(SUDO_DEBUG_NOTICE|SUDO_DEBUG_LINENO,
1126
"SSL_read_ex returns SSL_ERROR_WANT_READ");
1127
/* Read event is always active. */
1128
debug_return;
1129
case SSL_ERROR_WANT_WRITE:
1130
/* ssl wants to write, schedule a write if not pending */
1131
sudo_debug_printf(SUDO_DEBUG_NOTICE|SUDO_DEBUG_LINENO,
1132
"SSL_read_ex returns SSL_ERROR_WANT_WRITE");
1133
if (!sudo_ev_pending(closure->write_ev, SUDO_EV_WRITE, NULL)) {
1134
/* Enable a temporary write event. */
1135
if (sudo_ev_add(closure->evbase, closure->write_ev,
1136
logsrvd_conf_server_timeout(), false) == -1) {
1137
sudo_warnx("%s", U_("unable to add event to queue"));
1138
closure->errstr = _("unable to allocate memory");
1139
goto send_error;
1140
}
1141
closure->temporary_write_event = true;
1142
}
1143
/* Redirect write event to finish SSL_read_ex() */
1144
closure->read_instead_of_write = true;
1145
debug_return;
1146
case SSL_ERROR_SYSCALL:
1147
if (nread == 0) {
1148
/* EOF, handled below */
1149
sudo_warnx(U_("EOF from %s without proper TLS shutdown"),
1150
closure->ipaddr);
1151
break;
1152
}
1153
sudo_warn("%s: SSL_read_ex", closure->ipaddr);
1154
goto close_connection;
1155
default:
1156
errstr = ERR_reason_error_string(ERR_get_error());
1157
sudo_warnx("%s: SSL_read_ex: %s", closure->ipaddr,
1158
errstr ? errstr : strerror(errno));
1159
goto close_connection;
1160
}
1161
}
1162
} else
1163
#endif
1164
{
1165
const ssize_t n = read(fd, buf->data + buf->len, buf->size - buf->len);
1166
if (n < 0) {
1167
if (errno == EAGAIN || errno == EINTR)
1168
debug_return;
1169
sudo_warn("%s: read", closure->ipaddr);
1170
goto close_connection;
1171
}
1172
nread = (size_t)n;
1173
}
1174
1175
sudo_debug_printf(SUDO_DEBUG_INFO, "%s: received %zd bytes from client %s",
1176
__func__, nread, closure->ipaddr);
1177
if (nread == 0) {
1178
if (closure->state != FINISHED) {
1179
sudo_debug_printf(SUDO_DEBUG_WARN|SUDO_DEBUG_LINENO,
1180
"unexpected EOF");
1181
}
1182
goto close_connection;
1183
}
1184
if (nread > SIZE_MAX - buf->len) {
1185
sudo_warnx(U_("internal error, %s overflow"), __func__);
1186
goto close_connection;
1187
}
1188
buf->len += nread;
1189
1190
while (buf->len - buf->off >= sizeof(msg_len)) {
1191
/* Read wire message size (uint32_t in network byte order). */
1192
memcpy(&msg_len, buf->data + buf->off, sizeof(msg_len));
1193
msg_len = ntohl(msg_len);
1194
1195
if (msg_len > MESSAGE_SIZE_MAX) {
1196
sudo_warnx(U_("client message too large: %zu"), (size_t)msg_len);
1197
closure->errstr = _("client message too large");
1198
goto send_error;
1199
}
1200
1201
if (msg_len + sizeof(msg_len) > buf->len - buf->off) {
1202
/* Incomplete message, we'll read the rest next time. */
1203
if (!expand_buf(buf, msg_len + sizeof(msg_len))) {
1204
closure->errstr = _("unable to allocate memory");
1205
goto send_error;
1206
}
1207
debug_return;
1208
}
1209
1210
/* Parse ClientMessage (could be zero bytes). */
1211
sudo_debug_printf(SUDO_DEBUG_INFO,
1212
"%s: parsing ClientMessage, size %u", __func__, msg_len);
1213
buf->off += sizeof(msg_len);
1214
if (!handle_client_message(buf->data + buf->off, msg_len, closure)) {
1215
/* Use specific error string if one is set. */
1216
if (closure->errstr == NULL) {
1217
sudo_warnx(U_("%s: %s"), source, U_("invalid ClientMessage"));
1218
closure->errstr = _("invalid ClientMessage");
1219
}
1220
goto send_error;
1221
}
1222
buf->off += msg_len;
1223
}
1224
if (buf->len != buf->off) {
1225
memmove(buf->data, buf->data + buf->off, buf->len - buf->off);
1226
}
1227
buf->len -= buf->off;
1228
buf->off = 0;
1229
1230
if (closure->state == FINISHED && closure->relay_closure == NULL)
1231
goto close_connection;
1232
1233
debug_return;
1234
1235
send_error:
1236
/*
1237
* Try to send client an error message before closing the connection.
1238
*/
1239
if (!schedule_error_message(closure->errstr, closure))
1240
goto close_connection;
1241
debug_return;
1242
1243
close_connection:
1244
connection_close(closure);
1245
debug_return;
1246
}
1247
1248
/*
1249
* Format and schedule a commit_point message.
1250
*/
1251
bool
1252
schedule_commit_point(const TimeSpec *commit_point,
1253
struct connection_closure *closure)
1254
{
1255
debug_decl(schedule_commit_point, SUDO_DEBUG_UTIL);
1256
1257
if (closure->write_ev != NULL) {
1258
/* Send an acknowledgement of what we've committed to disk. */
1259
ServerMessage msg = SERVER_MESSAGE__INIT;
1260
msg.u.commit_point = (TimeSpec *)commit_point;
1261
msg.type_case = SERVER_MESSAGE__TYPE_COMMIT_POINT;
1262
1263
sudo_debug_printf(SUDO_DEBUG_INFO,
1264
"%s: sending commit point [%lld, %ld]", __func__,
1265
(long long)commit_point->tv_sec, (long)commit_point->tv_nsec);
1266
1267
if (!fmt_server_message(closure, &msg))
1268
goto bad;
1269
if (sudo_ev_add(closure->evbase, closure->write_ev,
1270
logsrvd_conf_server_timeout(), false) == -1) {
1271
sudo_warnx("%s", U_("unable to add event to queue"));
1272
goto bad;
1273
}
1274
}
1275
1276
if (closure->state == EXITED)
1277
closure->state = FINISHED;
1278
debug_return_bool(true);
1279
bad:
1280
debug_return_bool(false);
1281
}
1282
1283
/*
1284
* Time-based event that fires periodically to report to the client
1285
* what has been committed to disk.
1286
*/
1287
static void
1288
server_commit_cb(int unused, int what, void *v)
1289
{
1290
struct connection_closure *closure = v;
1291
TimeSpec commit_point = TIME_SPEC__INIT;
1292
debug_decl(server_commit_cb, SUDO_DEBUG_UTIL);
1293
1294
/* Flush I/O logs before sending commit point if needed. */
1295
if (!iolog_get_flush())
1296
iolog_flush_all(closure);
1297
1298
commit_point.tv_sec = closure->elapsed_time.tv_sec;
1299
commit_point.tv_nsec = (int32_t)closure->elapsed_time.tv_nsec;
1300
if (!schedule_commit_point(&commit_point, closure))
1301
connection_close(closure);
1302
1303
debug_return;
1304
}
1305
1306
/*
1307
* Begin the sudo logserver protocol.
1308
* When we enter the event loop the ServerHello message will be written
1309
* and any pending ClientMessage will be read.
1310
*/
1311
bool
1312
start_protocol(struct connection_closure *closure)
1313
{
1314
const struct timespec *timeout = logsrvd_conf_server_timeout();
1315
debug_decl(start_protocol, SUDO_DEBUG_UTIL);
1316
1317
if (closure->relay_closure != NULL && closure->relay_closure->relays != NULL) {
1318
/* No longer need the stashed relays list. */
1319
address_list_delref(closure->relay_closure->relays);
1320
closure->relay_closure->relays = NULL;
1321
closure->relay_closure->relay_addr = NULL;
1322
}
1323
1324
/* When replaying a journal there is no write event. */
1325
if (closure->write_ev != NULL) {
1326
if (!fmt_hello_message(closure))
1327
debug_return_bool(false);
1328
1329
if (sudo_ev_add(closure->evbase, closure->write_ev, timeout, false) == -1)
1330
debug_return_bool(false);
1331
}
1332
1333
/* No read timeout, client messages may happen at arbitrary times. */
1334
if (sudo_ev_add(closure->evbase, closure->read_ev, NULL, false) == -1)
1335
debug_return_bool(false);
1336
1337
debug_return_bool(true);
1338
}
1339
1340
#if defined(HAVE_OPENSSL)
1341
static int
1342
verify_peer_identity(int preverify_ok, X509_STORE_CTX *ctx)
1343
{
1344
HostnameValidationResult result;
1345
struct connection_closure *closure;
1346
SSL *ssl;
1347
X509 *current_cert;
1348
X509 *peer_cert;
1349
debug_decl(verify_peer_identity, SUDO_DEBUG_UTIL);
1350
1351
current_cert = X509_STORE_CTX_get_current_cert(ctx);
1352
1353
/* if pre-verification of the cert failed, just propagate that result back */
1354
if (preverify_ok != 1) {
1355
int err = X509_STORE_CTX_get_error(ctx);
1356
char current_cert_name[256] = "";
1357
if (current_cert != NULL)
1358
X509_NAME_oneline(X509_get_subject_name(current_cert), current_cert_name, sizeof(current_cert_name));
1359
1360
sudo_debug_printf(SUDO_DEBUG_INFO|SUDO_DEBUG_LINENO,
1361
"TLS verification failed for cert '%s': '%d:%s'", current_cert_name,
1362
err, X509_verify_cert_error_string(err));
1363
debug_return_int(0);
1364
}
1365
1366
/* since this callback is called for each cert in the chain,
1367
* check that current cert is the peer's certificate
1368
*/
1369
peer_cert = X509_STORE_CTX_get0_cert(ctx);
1370
1371
if (current_cert != peer_cert) {
1372
debug_return_int(1);
1373
}
1374
1375
/* read out the attached object (closure) from the ssl connection object */
1376
ssl = X509_STORE_CTX_get_ex_data(ctx, SSL_get_ex_data_X509_STORE_CTX_idx());
1377
closure = (struct connection_closure *)SSL_get_ex_data(ssl, 1);
1378
1379
result = validate_hostname(peer_cert, closure->name, closure->ipaddr);
1380
if (result != MatchFound) {
1381
sudo_debug_printf(SUDO_DEBUG_INFO|SUDO_DEBUG_LINENO,
1382
"hostname validation failed");
1383
debug_return_int(0);
1384
}
1385
debug_return_int(1);
1386
}
1387
1388
/*
1389
* Set the TLS verify callback to verify_peer_identity().
1390
*/
1391
static void
1392
set_tls_verify_peer(void)
1393
{
1394
SSL_CTX *server_ctx = logsrvd_server_tls_ctx();
1395
SSL_CTX *relay_ctx = logsrvd_relay_tls_ctx();
1396
debug_decl(set_tls_verify_peer, SUDO_DEBUG_UTIL);
1397
1398
if (server_ctx != NULL && logsrvd_conf_server_tls_check_peer()) {
1399
/* Verify server cert during the handshake. */
1400
SSL_CTX_set_verify(server_ctx,
1401
SSL_VERIFY_PEER|SSL_VERIFY_FAIL_IF_NO_PEER_CERT,
1402
verify_peer_identity);
1403
}
1404
if (relay_ctx != NULL && logsrvd_conf_relay_tls_check_peer()) {
1405
/* Verify relay cert during the handshake. */
1406
SSL_CTX_set_verify(relay_ctx,
1407
SSL_VERIFY_PEER|SSL_VERIFY_FAIL_IF_NO_PEER_CERT,
1408
verify_peer_identity);
1409
}
1410
1411
debug_return;
1412
}
1413
1414
static void
1415
tls_handshake_cb(int fd, int what, void *v)
1416
{
1417
struct connection_closure *closure = v;
1418
const char *errstr;
1419
int err, handshake_status;
1420
debug_decl(tls_handshake_cb, SUDO_DEBUG_UTIL);
1421
1422
if (what == SUDO_EV_TIMEOUT) {
1423
sudo_warnx("TLS handshake with %s timed out", closure->ipaddr);
1424
goto bad;
1425
}
1426
1427
handshake_status = SSL_accept(closure->ssl);
1428
err = SSL_get_error(closure->ssl, handshake_status);
1429
switch (err) {
1430
case SSL_ERROR_NONE:
1431
/* ssl handshake was successful */
1432
sudo_debug_printf(SUDO_DEBUG_INFO|SUDO_DEBUG_LINENO,
1433
"TLS handshake successful");
1434
break;
1435
case SSL_ERROR_WANT_READ:
1436
/* ssl handshake is ongoing, re-schedule the SSL_accept() call */
1437
sudo_debug_printf(SUDO_DEBUG_NOTICE|SUDO_DEBUG_LINENO,
1438
"SSL_accept returns SSL_ERROR_WANT_READ");
1439
if (what != SUDO_EV_READ) {
1440
if (sudo_ev_set(closure->ssl_accept_ev, closure->sock,
1441
SUDO_EV_READ, tls_handshake_cb, closure) == -1) {
1442
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
1443
"unable to set ssl_accept_ev to SUDO_EV_READ");
1444
goto bad;
1445
}
1446
}
1447
if (sudo_ev_add(closure->evbase, closure->ssl_accept_ev,
1448
logsrvd_conf_server_timeout(), false) == -1) {
1449
sudo_warnx("%s", U_("unable to add event to queue"));
1450
goto bad;
1451
}
1452
debug_return;
1453
case SSL_ERROR_WANT_WRITE:
1454
/* ssl handshake is ongoing, re-schedule the SSL_accept() call */
1455
sudo_debug_printf(SUDO_DEBUG_NOTICE|SUDO_DEBUG_LINENO,
1456
"SSL_accept returns SSL_ERROR_WANT_WRITE");
1457
if (what != SUDO_EV_WRITE) {
1458
if (sudo_ev_set(closure->ssl_accept_ev, closure->sock,
1459
SUDO_EV_WRITE, tls_handshake_cb, closure) == -1) {
1460
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
1461
"unable to set ssl_accept_ev to SUDO_EV_WRITE");
1462
goto bad;
1463
}
1464
}
1465
if (sudo_ev_add(closure->evbase, closure->ssl_accept_ev,
1466
logsrvd_conf_server_timeout(), false) == -1) {
1467
sudo_warnx("%s", U_("unable to add event to queue"));
1468
goto bad;
1469
}
1470
debug_return;
1471
case SSL_ERROR_SYSCALL:
1472
sudo_warn("%s: SSL_accept", closure->ipaddr);
1473
goto bad;
1474
default:
1475
errstr = ERR_reason_error_string(ERR_get_error());
1476
sudo_warnx("%s: SSL_accept: %s", closure->ipaddr,
1477
errstr ? errstr : strerror(errno));
1478
goto bad;
1479
}
1480
1481
sudo_debug_printf(SUDO_DEBUG_INFO|SUDO_DEBUG_LINENO,
1482
"TLS version: %s, negotiated cipher suite: %s",
1483
SSL_get_version(closure->ssl),
1484
SSL_get_cipher(closure->ssl));
1485
1486
/* Start the actual protocol now that the TLS handshake is complete. */
1487
if (!TAILQ_EMPTY(logsrvd_conf_relay_address()) && !closure->store_first) {
1488
if (!connect_relay(closure))
1489
goto bad;
1490
} else {
1491
if (!start_protocol(closure))
1492
goto bad;
1493
}
1494
1495
debug_return;
1496
bad:
1497
connection_close(closure);
1498
debug_return;
1499
}
1500
#endif /* HAVE_OPENSSL */
1501
1502
/*
1503
* New connection.
1504
* Allocate a connection closure and optionally perform TLS handshake.
1505
*/
1506
static bool
1507
new_connection(int sock, bool tls, const union sockaddr_union *sa_un,
1508
socklen_t salen, struct sudo_event_base *evbase)
1509
{
1510
struct connection_closure *closure;
1511
debug_decl(new_connection, SUDO_DEBUG_UTIL);
1512
1513
if ((closure = connection_closure_alloc(sock, tls, false, evbase)) == NULL) {
1514
close(sock);
1515
goto bad;
1516
}
1517
1518
/* store the peer's IP address in the closure object */
1519
if (sa_un->sa.sa_family == AF_INET) {
1520
inet_ntop(AF_INET, &sa_un->sin.sin_addr, closure->ipaddr,
1521
sizeof(closure->ipaddr));
1522
#ifdef HAVE_STRUCT_IN6_ADDR
1523
} else if (sa_un->sa.sa_family == AF_INET6) {
1524
inet_ntop(AF_INET6, &sa_un->sin6.sin6_addr, closure->ipaddr,
1525
sizeof(closure->ipaddr));
1526
#endif /* HAVE_STRUCT_IN6_ADDR */
1527
} else {
1528
errno = EAFNOSUPPORT;
1529
sudo_warn("%s", U_("unable to get remote IP addr"));
1530
goto bad;
1531
}
1532
sudo_debug_printf(SUDO_DEBUG_INFO|SUDO_DEBUG_LINENO,
1533
"connection from %s", closure->ipaddr);
1534
1535
#if defined(HAVE_OPENSSL)
1536
/* If TLS is enabled, perform the TLS handshake first. */
1537
if (tls) {
1538
const char *errstr;
1539
1540
/* Create the SSL object for the closure and attach it to the socket */
1541
if ((closure->ssl = SSL_new(logsrvd_server_tls_ctx())) == NULL) {
1542
errstr = ERR_reason_error_string(ERR_get_error());
1543
sudo_warnx(U_("%s: %s"), "SSL_new",
1544
errstr ? errstr : strerror(errno));
1545
goto bad;
1546
}
1547
1548
if (SSL_set_fd(closure->ssl, closure->sock) != 1) {
1549
errstr = ERR_reason_error_string(ERR_get_error());
1550
sudo_warnx(U_("%s: %s"), "SSL_set_fd",
1551
errstr ? errstr : strerror(errno));
1552
goto bad;
1553
}
1554
1555
if (logsrvd_conf_server_tls_check_peer()) {
1556
/* Hostname to verify in certificate during handshake. */
1557
char hbuf[NI_MAXHOST];
1558
const int error = getnameinfo(&sa_un->sa, salen, hbuf,
1559
sizeof(hbuf), NULL, 0, NI_NAMEREQD);
1560
if (error == 0) {
1561
closure->name = strdup(hbuf);
1562
if (closure->name == NULL) {
1563
sudo_warnx(U_("%s: %s"), __func__,
1564
U_("unable to allocate memory"));
1565
goto bad;
1566
}
1567
} else {
1568
sudo_gai_warn(error, _("unable to resolve host %s"),
1569
closure->ipaddr);
1570
}
1571
}
1572
1573
/* attach the closure object to the ssl connection object to make it
1574
available during hostname matching
1575
*/
1576
if (SSL_set_ex_data(closure->ssl, 1, closure) <= 0) {
1577
errstr = ERR_reason_error_string(ERR_get_error());
1578
sudo_warnx(U_("Unable to attach user data to the ssl object: %s"),
1579
errstr ? errstr : strerror(errno));
1580
goto bad;
1581
}
1582
1583
/* Enable SSL_accept to begin handshake with client. */
1584
if (sudo_ev_add(evbase, closure->ssl_accept_ev,
1585
logsrvd_conf_server_timeout(), false) == -1) {
1586
sudo_warnx("%s", U_("unable to add event to queue"));
1587
goto bad;
1588
}
1589
}
1590
#endif
1591
/* If no TLS handshake, start the protocol immediately. */
1592
if (!tls) {
1593
if (!TAILQ_EMPTY(logsrvd_conf_relay_address()) && !closure->store_first) {
1594
if (!connect_relay(closure))
1595
goto bad;
1596
} else {
1597
if (!start_protocol(closure))
1598
goto bad;
1599
}
1600
}
1601
1602
debug_return_bool(true);
1603
bad:
1604
connection_close(closure);
1605
debug_return_bool(false);
1606
}
1607
1608
static int
1609
open_listener_socket(struct server_address *addr)
1610
{
1611
int flags, on, sock;
1612
const char *family = "inet4";
1613
debug_decl(open_listener_socket, SUDO_DEBUG_UTIL);
1614
1615
if ((sock = socket(addr->sa_un.sa.sa_family, SOCK_STREAM, 0)) == -1) {
1616
sudo_warn("socket");
1617
goto bad;
1618
}
1619
on = 1;
1620
#ifdef HAVE_STRUCT_IN6_ADDR
1621
if (addr->sa_un.sa.sa_family == AF_INET6) {
1622
family = "inet6";
1623
# ifdef IPV6_V6ONLY
1624
/* Disable IPv4-mapped IPv6 addresses. */
1625
if (setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)) == -1)
1626
sudo_warn("IPV6_V6ONLY");
1627
# endif
1628
}
1629
#endif
1630
if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) == -1)
1631
sudo_warn("SO_REUSEADDR");
1632
if (bind(sock, &addr->sa_un.sa, addr->sa_size) == -1) {
1633
/* TODO: only warn once for IPv4 and IPv6 or disambiguate */
1634
sudo_warn("%s (%s)", addr->sa_str, family);
1635
goto bad;
1636
}
1637
if (listen(sock, SOMAXCONN) == -1) {
1638
sudo_warn("listen");
1639
goto bad;
1640
}
1641
flags = fcntl(sock, F_GETFL, 0);
1642
if (flags == -1 || fcntl(sock, F_SETFL, flags | O_NONBLOCK) == -1) {
1643
sudo_warn("fcntl(O_NONBLOCK)");
1644
goto bad;
1645
}
1646
sudo_debug_printf(SUDO_DEBUG_INFO, "listening on %s (%s)", addr->sa_str,
1647
family);
1648
1649
debug_return_int(sock);
1650
bad:
1651
if (sock != -1)
1652
close(sock);
1653
debug_return_int(-1);
1654
}
1655
1656
static void
1657
free_listener(struct listener *l)
1658
{
1659
debug_decl(free_listener, SUDO_DEBUG_UTIL);
1660
1661
if (l != NULL) {
1662
sudo_ev_free(l->ev);
1663
sudo_rcstr_delref(l->sa_str);
1664
if (l->sock != -1)
1665
close(l->sock);
1666
free(l);
1667
}
1668
1669
debug_return;
1670
}
1671
1672
static void
1673
listener_cb(int fd, int what, void *v)
1674
{
1675
struct listener *l = v;
1676
struct sudo_event_base *evbase = sudo_ev_get_base(l->ev);
1677
union sockaddr_union sa_un;
1678
socklen_t salen = sizeof(sa_un);
1679
int sock;
1680
debug_decl(listener_cb, SUDO_DEBUG_UTIL);
1681
1682
memset(&sa_un, 0, sizeof(sa_un));
1683
sock = accept(fd, &sa_un.sa, &salen);
1684
if (sock != -1) {
1685
if (logsrvd_conf_server_tcp_keepalive()) {
1686
int keepalive = 1;
1687
if (setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, &keepalive,
1688
sizeof(keepalive)) == -1) {
1689
sudo_warn("SO_KEEPALIVE");
1690
}
1691
}
1692
if (!new_connection(sock, l->tls, &sa_un, salen, evbase)) {
1693
/* TODO: pause accepting on ENOMEM */
1694
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
1695
"unable to start new connection");
1696
}
1697
} else {
1698
if (errno == EAGAIN || errno == EINTR)
1699
debug_return;
1700
/* TODO: pause accepting on ENFILE and EMFILE */
1701
sudo_warn("accept");
1702
}
1703
1704
debug_return;
1705
}
1706
1707
static bool
1708
register_listener(struct server_address *addr, struct sudo_event_base *evbase)
1709
{
1710
struct listener *l = NULL;
1711
int sock;
1712
debug_decl(register_listener, SUDO_DEBUG_UTIL);
1713
1714
sock = open_listener_socket(addr);
1715
if (sock == -1)
1716
goto bad;
1717
1718
if ((l = calloc(1, sizeof(*l))) == NULL) {
1719
sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
1720
goto bad;
1721
}
1722
l->ev = sudo_ev_alloc(sock, SUDO_EV_READ|SUDO_EV_PERSIST, listener_cb, l);
1723
if (l->ev == NULL) {
1724
sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
1725
goto bad;
1726
}
1727
l->sa_str = addr->sa_str;
1728
sudo_rcstr_addref(l->sa_str);
1729
l->sock = sock;
1730
sock = -1;
1731
l->tls = addr->tls;
1732
1733
if (sudo_ev_add(evbase, l->ev, NULL, false) == -1) {
1734
sudo_warn("%s", U_("unable to add event to queue"));
1735
goto bad;
1736
}
1737
TAILQ_INSERT_TAIL(&listeners, l, entries);
1738
1739
debug_return_bool(true);
1740
bad:
1741
if (sock != -1)
1742
close(sock);
1743
free_listener(l);
1744
debug_return_bool(false);
1745
}
1746
1747
/*
1748
* Register listeners and set the TLS verify callback.
1749
*/
1750
static bool
1751
server_setup(struct sudo_event_base *base)
1752
{
1753
struct listener_list kept_listeners =
1754
TAILQ_HEAD_INITIALIZER(kept_listeners);
1755
struct server_address *addr;
1756
struct listener *l;
1757
int nlisteners = 0;
1758
bool ret;
1759
debug_decl(server_setup, SUDO_DEBUG_UTIL);
1760
1761
/*
1762
* Free any listeners not present in the new config.
1763
* We must free non-matching listeners before adding new ones.
1764
*/
1765
while ((l = TAILQ_FIRST(&listeners)) != NULL) {
1766
TAILQ_REMOVE(&listeners, l, entries);
1767
1768
TAILQ_FOREACH(addr, logsrvd_conf_server_listen_address(), entries) {
1769
if (strcmp(addr->sa_str, l->sa_str) == 0) {
1770
TAILQ_INSERT_TAIL(&kept_listeners, l, entries);
1771
break;
1772
}
1773
}
1774
if (addr == NULL) {
1775
/* Listener not used in new config. */
1776
free_listener(l);
1777
}
1778
}
1779
1780
/* Register new listeners, reusing existing ones. */
1781
TAILQ_FOREACH(addr, logsrvd_conf_server_listen_address(), entries) {
1782
/* Check for addr in kept_listeners first. */
1783
TAILQ_FOREACH(l, &kept_listeners, entries) {
1784
if (strcmp(addr->sa_str, l->sa_str) == 0) {
1785
/* Reuse existing listener. */
1786
TAILQ_REMOVE(&kept_listeners, l, entries);
1787
TAILQ_INSERT_TAIL(&listeners, l, entries);
1788
1789
/* Update l->sa_str from new addr. */
1790
sudo_rcstr_delref(l->sa_str);
1791
l->sa_str = addr->sa_str;
1792
sudo_rcstr_addref(l->sa_str);
1793
1794
nlisteners++;
1795
break;
1796
}
1797
}
1798
1799
if (l == NULL) {
1800
/* Register new listener. */
1801
nlisteners += register_listener(addr, base);
1802
}
1803
}
1804
if (!TAILQ_EMPTY(&kept_listeners))
1805
sudo_warnx("bug: kept_listeners not empty");
1806
1807
ret = nlisteners > 0;
1808
1809
#if defined(HAVE_OPENSSL)
1810
if (ret)
1811
set_tls_verify_peer();
1812
#endif
1813
1814
debug_return_bool(ret);
1815
}
1816
1817
/*
1818
* Reload config and re-initialize listeners.
1819
*/
1820
static void
1821
server_reload(struct sudo_event_base *evbase)
1822
{
1823
debug_decl(server_reload, SUDO_DEBUG_UTIL);
1824
1825
sudo_debug_printf(SUDO_DEBUG_INFO, "reloading server config");
1826
if (logsrvd_conf_read(conf_file)) {
1827
/* Re-initialize listeners. */
1828
if (!server_setup(evbase))
1829
sudo_fatalx("%s", U_("unable to setup listen socket"));
1830
1831
/* Re-read sudo.conf and re-initialize debugging. */
1832
sudo_debug_deregister(logsrvd_debug_instance);
1833
logsrvd_debug_instance = SUDO_DEBUG_INSTANCE_INITIALIZER;
1834
if (sudo_conf_read(NULL, SUDO_CONF_DEBUG) != -1) {
1835
logsrvd_debug_instance = sudo_debug_register(getprogname(),
1836
NULL, NULL, sudo_conf_debug_files(getprogname()), -1);
1837
}
1838
}
1839
1840
debug_return;
1841
}
1842
1843
/*
1844
* Dump server information to the debug file.
1845
* Includes information about listeners and client connections.
1846
*/
1847
static void
1848
server_dump_stats(void)
1849
{
1850
struct server_address *addr;
1851
struct connection_closure *closure;
1852
int n;
1853
debug_decl(server_dump_stats, SUDO_DEBUG_UTIL);
1854
1855
sudo_debug_printf(SUDO_DEBUG_INFO, "%s", server_id);
1856
sudo_debug_printf(SUDO_DEBUG_INFO, "configuration file: %s",
1857
conf_file ? conf_file : _PATH_SUDO_LOGSRVD_CONF);
1858
1859
sudo_debug_printf(SUDO_DEBUG_INFO, "listen addresses:");
1860
n = 0;
1861
TAILQ_FOREACH(addr, logsrvd_conf_server_listen_address(), entries) {
1862
union sockaddr_union *sa_un = &addr->sa_un;
1863
char ipaddr[INET6_ADDRSTRLEN];
1864
1865
switch (sa_un->sa.sa_family) {
1866
case AF_INET:
1867
inet_ntop(AF_INET, &sa_un->sin.sin_addr, ipaddr, sizeof(ipaddr));
1868
break;
1869
#ifdef HAVE_STRUCT_IN6_ADDR
1870
case AF_INET6:
1871
inet_ntop(AF_INET6, &sa_un->sin6.sin6_addr, ipaddr, sizeof(ipaddr));
1872
break;
1873
#endif /* HAVE_STRUCT_IN6_ADDR */
1874
default:
1875
(void)strlcpy(ipaddr, "[unknown]", sizeof(ipaddr));
1876
break;
1877
}
1878
sudo_debug_printf(SUDO_DEBUG_INFO, " %d: %s [%s]", ++n,
1879
addr->sa_str, ipaddr);
1880
}
1881
1882
if (!TAILQ_EMPTY(&connections)) {
1883
n = 0;
1884
sudo_debug_printf(SUDO_DEBUG_INFO, "client connections:");
1885
TAILQ_FOREACH(closure, &connections, entries) {
1886
struct relay_closure *relay_closure = closure->relay_closure;
1887
1888
n++;
1889
if (closure->sock == -1) {
1890
sudo_debug_printf(SUDO_DEBUG_INFO, " %2d: journal %s", n,
1891
closure->journal_path ? closure->journal_path : "none");
1892
sudo_debug_printf(SUDO_DEBUG_INFO, " %2d: fd %d", n,
1893
closure->journal ? fileno(closure->journal) : -1);
1894
} else {
1895
sudo_debug_printf(SUDO_DEBUG_INFO, " %2d: addr %s%s", n,
1896
closure->ipaddr, closure->tls ? " (TLS)" : "");
1897
sudo_debug_printf(SUDO_DEBUG_INFO, " %2d: sock %d", n,
1898
closure->sock);
1899
}
1900
if (relay_closure != NULL) {
1901
sudo_debug_printf(SUDO_DEBUG_INFO, " relay: %s (%s)",
1902
relay_closure->relay_name.name,
1903
relay_closure->relay_name.ipaddr);
1904
sudo_debug_printf(SUDO_DEBUG_INFO, " relay sock: %d",
1905
relay_closure->sock);
1906
}
1907
sudo_debug_printf(SUDO_DEBUG_INFO, " state: %d", closure->state);
1908
if (closure->errstr != NULL) {
1909
sudo_debug_printf(SUDO_DEBUG_INFO, " error: %s",
1910
closure->errstr);
1911
}
1912
sudo_debug_printf(SUDO_DEBUG_INFO, " log I/O: %s",
1913
closure->log_io ? "true" : "false");
1914
sudo_debug_printf(SUDO_DEBUG_INFO, " store first: %s",
1915
closure->store_first ? "true" : "false");
1916
if (sudo_timespecisset(&closure->elapsed_time)) {
1917
sudo_debug_printf(SUDO_DEBUG_INFO,
1918
" elapsed time: [%lld, %ld]",
1919
(long long)closure->elapsed_time.tv_sec,
1920
(long)closure->elapsed_time.tv_nsec);
1921
}
1922
}
1923
sudo_debug_printf(SUDO_DEBUG_INFO, "%d client connection(s)\n", n);
1924
}
1925
logsrvd_queue_dump();
1926
1927
debug_return;
1928
}
1929
1930
static void
1931
signal_cb(int signo, int what, void *v)
1932
{
1933
struct sudo_event_base *base = v;
1934
debug_decl(signal_cb, SUDO_DEBUG_UTIL);
1935
1936
switch (signo) {
1937
case SIGHUP:
1938
server_reload(base);
1939
break;
1940
case SIGINT:
1941
case SIGTERM:
1942
/* Shut down active connections. */
1943
server_shutdown(base);
1944
break;
1945
case SIGUSR1:
1946
server_dump_stats();
1947
break;
1948
default:
1949
sudo_warnx(U_("unexpected signal %d"), signo);
1950
break;
1951
}
1952
1953
debug_return;
1954
}
1955
1956
static void
1957
register_signal(int signo, struct sudo_event_base *base)
1958
{
1959
struct sudo_event *ev;
1960
debug_decl(register_signal, SUDO_DEBUG_UTIL);
1961
1962
ev = sudo_ev_alloc(signo, SUDO_EV_SIGNAL, signal_cb, base);
1963
if (ev == NULL)
1964
sudo_fatalx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
1965
if (sudo_ev_add(base, ev, NULL, false) == -1)
1966
sudo_fatal("%s", U_("unable to add event to queue"));
1967
1968
debug_return;
1969
}
1970
1971
static void
1972
logsrvd_cleanup(void)
1973
{
1974
/* TODO: cleanup like on signal */
1975
return;
1976
}
1977
1978
/*
1979
* Write the process ID into a file, typically /var/run/sudo/sudo_logsrvd.pid.
1980
* If the parent directory doesn't exist, it will be created.
1981
*/
1982
static void
1983
write_pidfile(void)
1984
{
1985
FILE *fp;
1986
int dfd, fd;
1987
mode_t oldmask;
1988
const char *pid_file = logsrvd_conf_pid_file();
1989
debug_decl(write_pidfile, SUDO_DEBUG_UTIL);
1990
1991
if (pid_file == NULL)
1992
debug_return;
1993
1994
/* Default logsrvd umask is more restrictive (077). */
1995
oldmask = umask(S_IWGRP|S_IWOTH);
1996
1997
dfd = sudo_open_parent_dir(pid_file, ROOT_UID, ROOT_GID,
1998
S_IRWXU|S_IXGRP|S_IXOTH, false);
1999
if (dfd != -1) {
2000
const char *base = sudo_basename(pid_file);
2001
fd = openat(dfd, base, O_WRONLY|O_CREAT|O_NOFOLLOW, 0644);
2002
if (fd == -1 || (fp = fdopen(fd, "w")) == NULL) {
2003
sudo_warn("%s", pid_file);
2004
if (fd != -1)
2005
close(fd);
2006
} else {
2007
fprintf(fp, "%u\n", (unsigned int)getpid());
2008
fflush(fp);
2009
if (ferror(fp))
2010
sudo_warn("%s", pid_file);
2011
fclose(fp);
2012
}
2013
close(dfd);
2014
}
2015
umask(oldmask);
2016
2017
debug_return;
2018
}
2019
2020
/*
2021
* Increase the number of open files to the maximum value.
2022
*/
2023
static void
2024
unlimit_nofile(void)
2025
{
2026
struct rlimit rl = { RLIM_INFINITY, RLIM_INFINITY };
2027
struct rlimit nofilelimit;
2028
debug_decl(unlimit_nofile, SUDO_DEBUG_UTIL);
2029
2030
if (getrlimit(RLIMIT_NOFILE, &nofilelimit) != 0) {
2031
sudo_warn("getrlimit(RLIMIT_NOFILE)");
2032
debug_return;
2033
}
2034
sudo_debug_printf(SUDO_DEBUG_INFO,
2035
"RLIMIT_NOFILE [%lld, %lld] -> [inf, inf]",
2036
(long long)nofilelimit.rlim_cur, (long long)nofilelimit.rlim_max);
2037
if (setrlimit(RLIMIT_NOFILE, &rl) == -1) {
2038
/* Unable to set to infinity, set to max instead. */
2039
rl.rlim_cur = rl.rlim_max = nofilelimit.rlim_max;
2040
sudo_debug_printf(SUDO_DEBUG_INFO,
2041
"RLIMIT_NOFILE [%lld, %lld] -> [%lld, %lld]",
2042
(long long)nofilelimit.rlim_cur, (long long)nofilelimit.rlim_max,
2043
(long long)rl.rlim_cur, (long long)rl.rlim_max);
2044
if (setrlimit(RLIMIT_NOFILE, &rl) != 0)
2045
sudo_warn("setrlimit(RLIMIT_NOFILE)");
2046
}
2047
debug_return;
2048
}
2049
2050
/*
2051
* Fork, detach from the terminal and write pid file unless nofork set.
2052
*/
2053
static void
2054
daemonize(bool nofork)
2055
{
2056
int fd;
2057
debug_decl(daemonize, SUDO_DEBUG_UTIL);
2058
2059
if (chdir("/") == -1)
2060
sudo_warn("chdir(\"/\")");
2061
2062
if (!nofork) {
2063
switch (sudo_debug_fork()) {
2064
case -1:
2065
sudo_fatal("fork");
2066
case 0:
2067
/* child */
2068
break;
2069
default:
2070
/* parent, exit */
2071
_exit(EXIT_SUCCESS);
2072
}
2073
2074
/* detach from terminal and write pid file. */
2075
if (setsid() == -1)
2076
sudo_fatal("setsid");
2077
write_pidfile();
2078
2079
if ((fd = open(_PATH_DEVNULL, O_RDWR)) != -1) {
2080
(void) dup2(fd, STDIN_FILENO);
2081
(void) dup2(fd, STDOUT_FILENO);
2082
(void) dup2(fd, STDERR_FILENO);
2083
if (fd > STDERR_FILENO)
2084
(void) close(fd);
2085
}
2086
} else {
2087
if ((fd = open(_PATH_DEVNULL, O_RDWR)) != -1) {
2088
/* Preserve stdout/stderr in nofork mode (if open). */
2089
(void) dup2(fd, STDIN_FILENO);
2090
if (fcntl(STDOUT_FILENO, F_GETFL) == -1)
2091
(void) dup2(fd, STDOUT_FILENO);
2092
if (fcntl(STDERR_FILENO, F_GETFL) == -1)
2093
(void) dup2(fd, STDERR_FILENO);
2094
if (fd > STDERR_FILENO)
2095
(void) close(fd);
2096
}
2097
}
2098
2099
/* Disable logging to stderr after we become a daemon. */
2100
logsrvd_warn_stderr(false);
2101
2102
debug_return;
2103
}
2104
2105
static void
2106
display_usage(FILE *fp)
2107
{
2108
fprintf(fp, "usage: %s [-n] [-f conf_file] [-R percentage]\n",
2109
getprogname());
2110
}
2111
2112
sudo_noreturn static void
2113
usage(void)
2114
{
2115
display_usage(stderr);
2116
exit(EXIT_FAILURE);
2117
}
2118
2119
sudo_noreturn static void
2120
help(void)
2121
{
2122
printf("%s - %s\n\n", getprogname(), _("sudo log server"));
2123
display_usage(stdout);
2124
printf("\n%s\n", _("Options:"));
2125
printf(" -f, --file %s\n",
2126
_("path to configuration file"));
2127
printf(" -h, --help %s\n",
2128
_("display help message and exit"));
2129
printf(" -n, --no-fork %s\n",
2130
_("do not fork, run in the foreground"));
2131
printf(" -R, --random-drop %s\n",
2132
_("percent chance connections will drop"));
2133
printf(" -V, --version %s\n",
2134
_("display version information and exit"));
2135
putchar('\n');
2136
exit(EXIT_SUCCESS);
2137
}
2138
2139
static const char short_opts[] = "f:hnR:V";
2140
static struct option long_opts[] = {
2141
{ "file", required_argument, NULL, 'f' },
2142
{ "help", no_argument, NULL, 'h' },
2143
{ "no-fork", no_argument, NULL, 'n' },
2144
{ "random-drop", required_argument, NULL, 'R' },
2145
{ "version", no_argument, NULL, 'V' },
2146
{ NULL, no_argument, NULL, 0 },
2147
};
2148
2149
sudo_dso_public int main(int argc, char *argv[]);
2150
2151
int
2152
main(int argc, char *argv[])
2153
{
2154
struct sudo_event_base *evbase;
2155
bool nofork = false;
2156
char *ep;
2157
int ch;
2158
debug_decl_vars(main, SUDO_DEBUG_MAIN);
2159
2160
#if defined(SUDO_DEVEL) && defined(__OpenBSD__)
2161
{
2162
extern char *malloc_options;
2163
malloc_options = "S";
2164
}
2165
#endif
2166
2167
initprogname(argc > 0 ? argv[0] : "sudo_logsrvd");
2168
setlocale(LC_ALL, "");
2169
bindtextdomain("sudo", LOCALEDIR); /* XXX - add logsrvd domain */
2170
textdomain("sudo");
2171
2172
/* Create files readable/writable only by owner. */
2173
umask(S_IRWXG|S_IRWXO);
2174
2175
/* Register fatal/fatalx callback. */
2176
sudo_fatal_callback_register(logsrvd_cleanup);
2177
2178
/* Read sudo.conf and initialize the debug subsystem. */
2179
if (sudo_conf_read(NULL, SUDO_CONF_DEBUG) == -1)
2180
return EXIT_FAILURE;
2181
logsrvd_debug_instance = sudo_debug_register(getprogname(), NULL, NULL,
2182
sudo_conf_debug_files(getprogname()), -1);
2183
2184
if (protobuf_c_version_number() < 1003000)
2185
sudo_fatalx("%s", U_("Protobuf-C version 1.3 or higher required"));
2186
2187
while ((ch = getopt_long(argc, argv, short_opts, long_opts, NULL)) != -1) {
2188
switch (ch) {
2189
case 'f':
2190
conf_file = optarg;
2191
break;
2192
case 'h':
2193
help();
2194
/* NOTREACHED */
2195
case 'n':
2196
nofork = true;
2197
break;
2198
case 'R':
2199
/* random connection drop probability as a percentage (debug) */
2200
errno = 0;
2201
random_drop = strtod(optarg, &ep);
2202
if (*ep != '\0' || errno != 0)
2203
sudo_fatalx(U_("invalid random drop value: %s"), optarg);
2204
random_drop /= 100.0; /* convert from percentage */
2205
break;
2206
case 'V':
2207
(void)printf(_("%s version %s\n"), getprogname(),
2208
PACKAGE_VERSION);
2209
return 0;
2210
default:
2211
usage();
2212
}
2213
}
2214
2215
/* Read sudo_logsrvd.conf */
2216
if (!logsrvd_conf_read(conf_file))
2217
return EXIT_FAILURE;
2218
2219
/* Crank the open file limit to the maximum value allowed. */
2220
unlimit_nofile();
2221
2222
if ((evbase = sudo_ev_base_alloc()) == NULL)
2223
sudo_fatalx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
2224
2225
/* Initialize listeners. */
2226
if (!server_setup(evbase))
2227
sudo_fatalx("%s", U_("unable to setup listen socket"));
2228
2229
if (!logsrvd_queue_scan(evbase)) {
2230
/* Error displayed by logsrvd_queue_scan() */
2231
return EXIT_FAILURE;
2232
}
2233
2234
register_signal(SIGHUP, evbase);
2235
register_signal(SIGINT, evbase);
2236
register_signal(SIGTERM, evbase);
2237
register_signal(SIGUSR1, evbase);
2238
2239
/* Point of no return. */
2240
daemonize(nofork);
2241
signal(SIGPIPE, SIG_IGN);
2242
2243
sudo_ev_dispatch(evbase);
2244
if (!nofork && logsrvd_conf_pid_file() != NULL)
2245
unlink(logsrvd_conf_pid_file());
2246
logsrvd_conf_cleanup();
2247
2248
debug_return_int(0);
2249
}
2250
2251