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