Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/crypto/krb5/src/lib/apputils/net-server.c
39562 views
1
/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2
/* lib/apputils/net-server.c - Network code for krb5 servers (kdc, kadmind) */
3
/*
4
* Copyright 1990,2000,2007,2008,2009,2010,2016 by the Massachusetts Institute
5
* of Technology.
6
*
7
* Export of this software from the United States of America may
8
* require a specific license from the United States Government.
9
* It is the responsibility of any person or organization contemplating
10
* export to obtain such a license before exporting.
11
*
12
* WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
13
* distribute this software and its documentation for any purpose and
14
* without fee is hereby granted, provided that the above copyright
15
* notice appear in all copies and that both that copyright notice and
16
* this permission notice appear in supporting documentation, and that
17
* the name of M.I.T. not be used in advertising or publicity pertaining
18
* to distribution of the software without specific, written prior
19
* permission. Furthermore if you modify this software you must label
20
* your software as modified software and not distribute it in such a
21
* fashion that it might be confused with the original M.I.T. software.
22
* M.I.T. makes no representations about the suitability of
23
* this software for any purpose. It is provided "as is" without express
24
* or implied warranty.
25
*/
26
27
#include "k5-int.h"
28
#include "adm_proto.h"
29
#include <sys/ioctl.h>
30
#include <syslog.h>
31
32
#include <stddef.h>
33
#include "port-sockets.h"
34
#include "socket-utils.h"
35
36
#include <gssrpc/rpc.h>
37
38
#ifdef HAVE_NETINET_IN_H
39
#include <sys/types.h>
40
#include <netinet/in.h>
41
#include <sys/socket.h>
42
#include <sys/un.h>
43
#ifdef HAVE_SYS_SOCKIO_H
44
/* for SIOCGIFCONF, etc. */
45
#include <sys/sockio.h>
46
#endif
47
#include <sys/time.h>
48
#if HAVE_SYS_SELECT_H
49
#include <sys/select.h>
50
#endif
51
#include <arpa/inet.h>
52
53
#ifndef ARPHRD_ETHER /* OpenBSD breaks on multiple inclusions */
54
#include <net/if.h>
55
#endif
56
57
#ifdef HAVE_SYS_FILIO_H
58
#include <sys/filio.h> /* FIONBIO */
59
#endif
60
61
#include "fake-addrinfo.h"
62
#include "net-server.h"
63
#include <signal.h>
64
#include <netdb.h>
65
66
#include "udppktinfo.h"
67
68
/* List of systemd socket activation addresses and socket types. */
69
struct sockact_list {
70
size_t nsockets;
71
struct {
72
struct sockaddr_storage addr;
73
int type;
74
} *fds;
75
};
76
77
/* When systemd socket activation is used, caller-provided sockets begin at
78
* file descriptor 3. */
79
const int SOCKACT_START = 3;
80
81
/* XXX */
82
#define KDC5_NONET (-1779992062L)
83
84
static int stream_data_counter;
85
static int max_stream_data_connections = 45;
86
87
static int
88
setreuseaddr(int sock, int value)
89
{
90
int st;
91
92
st = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &value, sizeof(value));
93
if (st)
94
return st;
95
#if defined(SO_REUSEPORT) && defined(__APPLE__)
96
/* macOS experimentally needs this flag as well to avoid conflicts between
97
* recently exited server processes and new ones. */
98
st = setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, &value, sizeof(value));
99
if (st)
100
return st;
101
#endif
102
return 0;
103
}
104
105
#if defined(IPV6_V6ONLY)
106
static int
107
setv6only(int sock, int value)
108
{
109
return setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &value, sizeof(value));
110
}
111
#endif
112
113
/* KDC data. */
114
115
enum conn_type {
116
CONN_UDP, CONN_TCP_LISTENER, CONN_TCP, CONN_RPC_LISTENER, CONN_RPC,
117
CONN_UNIXSOCK_LISTENER, CONN_UNIXSOCK
118
};
119
120
static const char *const conn_type_names[] = {
121
[CONN_UDP] = "UDP",
122
[CONN_TCP_LISTENER] = "TCP listener",
123
[CONN_TCP] = "TCP",
124
[CONN_RPC_LISTENER] = "RPC listener",
125
[CONN_RPC] = "RPC",
126
[CONN_UNIXSOCK_LISTENER] = "UNIX domain socket listener",
127
[CONN_UNIXSOCK] = "UNIX domain socket"
128
};
129
130
enum bind_type {
131
UDP, TCP, RPC, UNX
132
};
133
134
static const char *const bind_type_names[] = {
135
[UDP] = "UDP",
136
[TCP] = "TCP",
137
[RPC] = "RPC",
138
[UNX] = "UNIXSOCK",
139
};
140
141
/* Per-connection info. */
142
struct connection {
143
void *handle;
144
const char *prog;
145
enum conn_type type;
146
147
/* Connection fields (TCP or RPC) */
148
struct sockaddr_storage addr_s;
149
socklen_t addrlen;
150
char addrbuf[128];
151
152
/* Incoming data (TCP) */
153
size_t bufsiz;
154
size_t offset;
155
char *buffer;
156
size_t msglen;
157
158
/* Outgoing data (TCP) */
159
krb5_data *response;
160
unsigned char lenbuf[4];
161
sg_buf sgbuf[2];
162
sg_buf *sgp;
163
int sgnum;
164
165
/* Crude denial-of-service avoidance support (TCP or RPC) */
166
time_t start_time;
167
168
/* RPC-specific fields */
169
SVCXPRT *transp;
170
int rpc_force_close;
171
};
172
173
#define SET(TYPE) struct { TYPE *data; size_t n, max; }
174
175
/* Start at the top and work down -- this should allow for deletions
176
without disrupting the iteration, since we delete by overwriting
177
the element to be removed with the last element. */
178
#define FOREACH_ELT(set,idx,vvar) \
179
for (idx = set.n-1; idx >= 0 && (vvar = set.data[idx], 1); idx--)
180
181
#define GROW_SET(set, incr, tmpptr) \
182
((set.max + incr < set.max \
183
|| ((set.max + incr) * sizeof(set.data[0]) / sizeof(set.data[0]) \
184
!= set.max + incr)) \
185
? 0 /* overflow */ \
186
: ((tmpptr = realloc(set.data, \
187
(set.max + incr) * sizeof(set.data[0]))) \
188
? (set.data = tmpptr, set.max += incr, 1) \
189
: 0))
190
191
/* 1 = success, 0 = failure */
192
#define ADD(set, val, tmpptr) \
193
((set.n < set.max || GROW_SET(set, 10, tmpptr)) \
194
? (set.data[set.n++] = val, 1) \
195
: 0)
196
197
#define DEL(set, idx) \
198
(set.data[idx] = set.data[--set.n], 0)
199
200
#define FREE_SET_DATA(set) \
201
(free(set.data), set.data = 0, set.max = 0, set.n = 0)
202
203
/*
204
* N.B.: The Emacs cc-mode indentation code seems to get confused if
205
* the macro argument here is one word only. So use "unsigned short"
206
* instead of the "u_short" we were using before.
207
*/
208
struct rpc_svc_data {
209
u_long prognum;
210
u_long versnum;
211
void (*dispatch)(struct svc_req *, SVCXPRT *);
212
};
213
214
struct bind_address {
215
char *address;
216
u_short port;
217
enum bind_type type;
218
struct rpc_svc_data rpc_svc_data;
219
};
220
221
static SET(verto_ev *) events;
222
static SET(struct bind_address) bind_addresses;
223
224
verto_ctx *
225
loop_init(verto_ev_type types)
226
{
227
types |= VERTO_EV_TYPE_IO;
228
types |= VERTO_EV_TYPE_SIGNAL;
229
types |= VERTO_EV_TYPE_TIMEOUT;
230
return verto_default(NULL, types);
231
}
232
233
static void
234
do_break(verto_ctx *ctx, verto_ev *ev)
235
{
236
krb5_klog_syslog(LOG_DEBUG, _("Got signal to request exit"));
237
verto_break(ctx);
238
}
239
240
struct sighup_context {
241
void *handle;
242
void (*reset)(void *);
243
};
244
245
static void
246
do_reset(verto_ctx *ctx, verto_ev *ev)
247
{
248
struct sighup_context *sc = (struct sighup_context*) verto_get_private(ev);
249
250
krb5_klog_syslog(LOG_DEBUG, _("Got signal to reset"));
251
krb5_klog_reopen(get_context(sc->handle));
252
if (sc->reset)
253
sc->reset(sc->handle);
254
}
255
256
static void
257
free_sighup_context(verto_ctx *ctx, verto_ev *ev)
258
{
259
free(verto_get_private(ev));
260
}
261
262
krb5_error_code
263
loop_setup_signals(verto_ctx *ctx, void *handle, void (*reset)(void *))
264
{
265
struct sighup_context *sc;
266
verto_ev *ev;
267
268
if (!verto_add_signal(ctx, VERTO_EV_FLAG_PERSIST, do_break, SIGINT) ||
269
!verto_add_signal(ctx, VERTO_EV_FLAG_PERSIST, do_break, SIGTERM) ||
270
!verto_add_signal(ctx, VERTO_EV_FLAG_PERSIST, do_break, SIGQUIT) ||
271
!verto_add_signal(ctx, VERTO_EV_FLAG_PERSIST, VERTO_SIG_IGN, SIGPIPE))
272
return ENOMEM;
273
274
ev = verto_add_signal(ctx, VERTO_EV_FLAG_PERSIST, do_reset, SIGHUP);
275
if (!ev)
276
return ENOMEM;
277
278
sc = malloc(sizeof(*sc));
279
if (!sc)
280
return ENOMEM;
281
282
sc->handle = handle;
283
sc->reset = reset;
284
verto_set_private(ev, sc, free_sighup_context);
285
return 0;
286
}
287
288
/*
289
* Add a bind address to the loop.
290
*
291
* Arguments:
292
* - address
293
* An address string, hostname, or UNIX socket path.
294
* Pass NULL to use the wildcard address for IP sockets.
295
* - port
296
* What port the socket should be set to (for IPv4 or IPv6).
297
* - type
298
* bind_type for the socket.
299
* - rpc_data
300
* For RPC addresses, the svc_register() arguments to use when TCP
301
* connections are created. Ignored for other types.
302
*/
303
static krb5_error_code
304
loop_add_address(const char *address, int port, enum bind_type type,
305
struct rpc_svc_data *rpc_data)
306
{
307
struct bind_address addr, val;
308
int i;
309
void *tmp;
310
char *addr_copy = NULL;
311
312
assert(!(type == RPC && rpc_data == NULL));
313
314
/* Make sure a valid port number was passed. */
315
if (port < 0 || port > 65535) {
316
krb5_klog_syslog(LOG_ERR, _("Invalid port %d"), port);
317
return EINVAL;
318
}
319
320
/* Check for conflicting addresses. */
321
FOREACH_ELT(bind_addresses, i, val) {
322
if (type != val.type || port != val.port)
323
continue;
324
325
/* If a wildcard address is being added, make sure to remove any direct
326
* addresses. */
327
if (address == NULL && val.address != NULL) {
328
krb5_klog_syslog(LOG_DEBUG,
329
_("Removing address %s since wildcard address"
330
" is being added"),
331
val.address);
332
free(val.address);
333
DEL(bind_addresses, i);
334
} else if (val.address == NULL || !strcmp(address, val.address)) {
335
krb5_klog_syslog(LOG_DEBUG,
336
_("Address already added to server"));
337
return 0;
338
}
339
}
340
341
/* Copy the address if it is specified. */
342
if (address != NULL) {
343
addr_copy = strdup(address);
344
if (addr_copy == NULL)
345
return ENOMEM;
346
}
347
348
/* Add the new address to bind_addresses. */
349
memset(&addr, 0, sizeof(addr));
350
addr.address = addr_copy;
351
addr.port = port;
352
addr.type = type;
353
if (rpc_data != NULL)
354
addr.rpc_svc_data = *rpc_data;
355
if (!ADD(bind_addresses, addr, tmp)) {
356
free(addr_copy);
357
return ENOMEM;
358
}
359
360
return 0;
361
}
362
363
/*
364
* Add bind addresses to the loop.
365
*
366
* Arguments:
367
*
368
* - addresses
369
* A string for the addresses. Pass NULL to use the wildcard address.
370
* Supported delimiters can be found in ADDRESSES_DELIM. Addresses are
371
* parsed with k5_parse_host_name().
372
* - default_port
373
* What port the socket should be set to if not specified in addresses.
374
* - type
375
* bind_type for the socket.
376
* - rpc_data
377
* For RPC addresses, the svc_register() arguments to use when TCP
378
* connections are created. Ignored for other types.
379
*/
380
static krb5_error_code
381
loop_add_addresses(const char *addresses, int default_port,
382
enum bind_type type, struct rpc_svc_data *rpc_data)
383
{
384
krb5_error_code ret = 0;
385
char *addresses_copy = NULL, *host = NULL, *saveptr, *addr;
386
int port;
387
388
/* If no addresses are set, add a wildcard address. */
389
if (addresses == NULL)
390
return loop_add_address(NULL, default_port, type, rpc_data);
391
392
/* Copy the addresses string before using strtok(). */
393
addresses_copy = strdup(addresses);
394
if (addresses_copy == NULL) {
395
ret = ENOMEM;
396
goto cleanup;
397
}
398
399
/* Loop through each address in the string and add it to the loop. */
400
addr = strtok_r(addresses_copy, ADDRESSES_DELIM, &saveptr);
401
for (; addr != NULL; addr = strtok_r(NULL, ADDRESSES_DELIM, &saveptr)) {
402
if (type == UNX) {
403
/* Skip non-pathnames when binding UNIX domain sockets. */
404
if (*addr != '/')
405
continue;
406
ret = loop_add_address(addr, 0, type, rpc_data);
407
if (ret)
408
goto cleanup;
409
continue;
410
} else if (*addr == '/') {
411
/* Skip pathnames when not binding UNIX domain sockets. */
412
continue;
413
}
414
415
/* Parse the host string. */
416
ret = k5_parse_host_string(addr, default_port, &host, &port);
417
if (ret)
418
goto cleanup;
419
420
ret = loop_add_address(host, port, type, rpc_data);
421
if (ret)
422
goto cleanup;
423
424
free(host);
425
host = NULL;
426
}
427
428
ret = 0;
429
cleanup:
430
free(addresses_copy);
431
free(host);
432
return ret;
433
}
434
435
krb5_error_code
436
loop_add_udp_address(int default_port, const char *addresses)
437
{
438
return loop_add_addresses(addresses, default_port, UDP, NULL);
439
}
440
441
krb5_error_code
442
loop_add_tcp_address(int default_port, const char *addresses)
443
{
444
return loop_add_addresses(addresses, default_port, TCP, NULL);
445
}
446
447
krb5_error_code
448
loop_add_rpc_service(int default_port, const char *addresses, u_long prognum,
449
u_long versnum,
450
void (*dispatchfn)(struct svc_req *, SVCXPRT *))
451
{
452
struct rpc_svc_data svc;
453
454
svc.prognum = prognum;
455
svc.versnum = versnum;
456
svc.dispatch = dispatchfn;
457
return loop_add_addresses(addresses, default_port, RPC, &svc);
458
}
459
460
krb5_error_code
461
loop_add_unix_socket(const char *socket_paths)
462
{
463
/* There is no wildcard or default UNIX domain socket. */
464
if (socket_paths == NULL)
465
return 0;
466
467
return loop_add_addresses(socket_paths, 0, UNX, NULL);
468
}
469
470
#define USE_AF AF_INET
471
#define USE_TYPE SOCK_DGRAM
472
#define USE_PROTO 0
473
#define SOCKET_ERRNO errno
474
#include "foreachaddr.h"
475
476
static void
477
free_connection(struct connection *conn)
478
{
479
if (!conn)
480
return;
481
if (conn->response)
482
krb5_free_data(get_context(conn->handle), conn->response);
483
if (conn->buffer)
484
free(conn->buffer);
485
if (conn->type == CONN_RPC_LISTENER && conn->transp != NULL)
486
svc_destroy(conn->transp);
487
free(conn);
488
}
489
490
static void
491
remove_event_from_set(verto_ev *ev)
492
{
493
verto_ev *tmp;
494
int i;
495
496
/* Remove the event from the events. */
497
FOREACH_ELT(events, i, tmp)
498
if (tmp == ev) {
499
DEL(events, i);
500
break;
501
}
502
}
503
504
static void
505
free_socket(verto_ctx *ctx, verto_ev *ev)
506
{
507
struct connection *conn = NULL;
508
fd_set fds;
509
int fd;
510
511
remove_event_from_set(ev);
512
513
fd = verto_get_fd(ev);
514
conn = verto_get_private(ev);
515
516
/* Close the file descriptor. */
517
krb5_klog_syslog(LOG_INFO, _("closing down fd %d"), fd);
518
if (fd >= 0 && (!conn || conn->type != CONN_RPC || conn->rpc_force_close))
519
close(fd);
520
521
/* Free the connection struct. */
522
if (conn) {
523
switch (conn->type) {
524
case CONN_RPC:
525
if (conn->rpc_force_close) {
526
FD_ZERO(&fds);
527
FD_SET(fd, &fds);
528
svc_getreqset(&fds);
529
if (FD_ISSET(fd, &svc_fdset)) {
530
krb5_klog_syslog(LOG_ERR,
531
_("descriptor %d closed but still "
532
"in svc_fdset"),
533
fd);
534
}
535
}
536
/* Fall through. */
537
case CONN_TCP:
538
case CONN_UNIXSOCK:
539
stream_data_counter--;
540
break;
541
default:
542
break;
543
}
544
545
free_connection(conn);
546
}
547
}
548
549
static verto_ev *
550
make_event(verto_ctx *ctx, verto_ev_flag flags, verto_callback callback,
551
int sock, struct connection *conn)
552
{
553
verto_ev *ev;
554
void *tmp;
555
556
ev = verto_add_io(ctx, flags, callback, sock);
557
if (!ev) {
558
com_err(conn->prog, ENOMEM, _("cannot create io event"));
559
return NULL;
560
}
561
562
if (!ADD(events, ev, tmp)) {
563
com_err(conn->prog, ENOMEM, _("cannot save event"));
564
verto_del(ev);
565
return NULL;
566
}
567
568
verto_set_private(ev, conn, free_socket);
569
return ev;
570
}
571
572
static krb5_error_code
573
add_fd(int sock, enum conn_type conntype, verto_ev_flag flags, void *handle,
574
const char *prog, verto_ctx *ctx, verto_callback callback,
575
verto_ev **ev_out)
576
{
577
struct connection *newconn;
578
579
*ev_out = NULL;
580
581
#ifndef _WIN32
582
if (sock >= FD_SETSIZE) {
583
com_err(prog, 0, _("file descriptor number %d too high"), sock);
584
return EMFILE;
585
}
586
#endif
587
newconn = malloc(sizeof(*newconn));
588
if (newconn == NULL) {
589
com_err(prog, ENOMEM,
590
_("cannot allocate storage for connection info"));
591
return ENOMEM;
592
}
593
memset(newconn, 0, sizeof(*newconn));
594
newconn->handle = handle;
595
newconn->prog = prog;
596
newconn->type = conntype;
597
598
*ev_out = make_event(ctx, flags, callback, sock, newconn);
599
return 0;
600
}
601
602
static void process_packet(verto_ctx *ctx, verto_ev *ev);
603
static void accept_stream_connection(verto_ctx *ctx, verto_ev *ev);
604
static void process_stream_connection_read(verto_ctx *ctx, verto_ev *ev);
605
static void process_stream_connection_write(verto_ctx *ctx, verto_ev *ev);
606
static void accept_rpc_connection(verto_ctx *ctx, verto_ev *ev);
607
static void process_rpc_connection(verto_ctx *ctx, verto_ev *ev);
608
609
/*
610
* Create a socket and bind it to addr. Ensure the socket will work with
611
* select(). Set the socket cloexec, reuseaddr, and if applicable v6-only.
612
* Does not call listen(). On failure, log an error and return an error code.
613
*/
614
static krb5_error_code
615
create_server_socket(struct sockaddr *addr, int type, const char *prog,
616
int *fd_out)
617
{
618
int sock, e;
619
char addrbuf[128];
620
621
*fd_out = -1;
622
623
if (addr->sa_family == AF_UNIX)
624
(void)unlink(sa2sun(addr)->sun_path);
625
sock = socket(addr->sa_family, type, 0);
626
if (sock == -1) {
627
e = errno;
628
k5_print_addr_port(addr, addrbuf, sizeof(addrbuf));
629
com_err(prog, e, _("Cannot create TCP server socket on %s"), addrbuf);
630
return e;
631
}
632
set_cloexec_fd(sock);
633
634
#ifndef _WIN32 /* Windows FD_SETSIZE is a count. */
635
if (sock >= FD_SETSIZE) {
636
close(sock);
637
k5_print_addr_port(addr, addrbuf, sizeof(addrbuf));
638
com_err(prog, 0, _("TCP socket fd number %d (for %s) too high"),
639
sock, addrbuf);
640
return EMFILE;
641
}
642
#endif
643
644
if (setreuseaddr(sock, 1) < 0)
645
com_err(prog, errno, _("Cannot enable SO_REUSEADDR on fd %d"), sock);
646
647
if (addr->sa_family == AF_INET6) {
648
#ifdef IPV6_V6ONLY
649
if (setv6only(sock, 1)) {
650
com_err(prog, errno, _("setsockopt(%d,IPV6_V6ONLY,1) failed"),
651
sock);
652
} else {
653
com_err(prog, 0, _("setsockopt(%d,IPV6_V6ONLY,1) worked"), sock);
654
}
655
#else
656
krb5_klog_syslog(LOG_INFO, _("no IPV6_V6ONLY socket option support"));
657
#endif /* IPV6_V6ONLY */
658
}
659
660
if (bind(sock, addr, sa_socklen(addr)) == -1) {
661
e = errno;
662
k5_print_addr_port(addr, addrbuf, sizeof(addrbuf));
663
com_err(prog, e, _("Cannot bind server socket on %s"), addrbuf);
664
close(sock);
665
return e;
666
}
667
668
*fd_out = sock;
669
return 0;
670
}
671
672
static const int one = 1;
673
674
static int
675
setnbio(int sock)
676
{
677
return ioctlsocket(sock, FIONBIO, (const void *)&one);
678
}
679
680
static int
681
setkeepalive(int sock)
682
{
683
return setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, &one, sizeof(one));
684
}
685
686
static int
687
setnolinger(int s)
688
{
689
static const struct linger ling = { 0, 0 };
690
return setsockopt(s, SOL_SOCKET, SO_LINGER, &ling, sizeof(ling));
691
}
692
693
/* An enum map to socket families for each bind_type. */
694
static const int bind_socktypes[] =
695
{
696
[UDP] = SOCK_DGRAM,
697
[TCP] = SOCK_STREAM,
698
[RPC] = SOCK_STREAM,
699
[UNX] = SOCK_STREAM
700
};
701
702
/* An enum map containing conn_type (for struct connection) for each
703
* bind_type. */
704
static const enum conn_type bind_conn_types[] =
705
{
706
[UDP] = CONN_UDP,
707
[TCP] = CONN_TCP_LISTENER,
708
[RPC] = CONN_RPC_LISTENER,
709
[UNX] = CONN_UNIXSOCK_LISTENER
710
};
711
712
/* If any systemd socket activation fds are indicated by the environment, set
713
* them close-on-exec and put their addresses and socket types into *list. */
714
static void
715
init_sockact_list(struct sockact_list *list)
716
{
717
const char *v;
718
char *end;
719
long lpid;
720
int fd;
721
size_t nfds, i;
722
socklen_t slen;
723
724
list->nsockets = 0;
725
list->fds = NULL;
726
727
/* Check if LISTEN_FDS is meant for this process. */
728
v = getenv("LISTEN_PID");
729
if (v == NULL)
730
return;
731
lpid = strtol(v, &end, 10);
732
if (end == NULL || end == v || *end != '\0' || lpid != getpid())
733
return;
734
735
/* Get the number of activated sockets. */
736
v = getenv("LISTEN_FDS");
737
if (v == NULL)
738
return;
739
nfds = strtoul(v, &end, 10);
740
if (end == NULL || end == v || *end != '\0')
741
return;
742
if (nfds == 0 || nfds > (size_t)INT_MAX - SOCKACT_START)
743
return;
744
745
list->fds = calloc(nfds, sizeof(*list->fds));
746
if (list->fds == NULL)
747
return;
748
749
for (i = 0; i < nfds; i++) {
750
fd = i + SOCKACT_START;
751
set_cloexec_fd(fd);
752
slen = sizeof(list->fds[i].addr);
753
(void)getsockname(fd, ss2sa(&list->fds[i].addr), &slen);
754
slen = sizeof(list->fds[i].type);
755
(void)getsockopt(fd, SOL_SOCKET, SO_TYPE, &list->fds[i].type, &slen);
756
}
757
758
list->nsockets = nfds;
759
}
760
761
/* Release any storage used by *list. */
762
static void
763
fini_sockact_list(struct sockact_list *list)
764
{
765
free(list->fds);
766
list->fds = NULL;
767
list->nsockets = 0;
768
}
769
770
/* If sa matches an address in *list, return the associated file descriptor and
771
* clear the address from *list. Otherwise return -1. */
772
static int
773
find_sockact(struct sockact_list *list, const struct sockaddr *sa, int type)
774
{
775
size_t i;
776
777
for (i = 0; i < list->nsockets; i++) {
778
if (list->fds[i].type == type &&
779
sa_equal(ss2sa(&list->fds[i].addr), sa)) {
780
list->fds[i].type = -1;
781
memset(&list->fds[i].addr, 0, sizeof(list->fds[i].addr));
782
return i + SOCKACT_START;
783
}
784
}
785
return -1;
786
}
787
788
/*
789
* Set up a listening socket.
790
*
791
* Arguments:
792
*
793
* - ba
794
* The bind address and port for the socket.
795
* - ai
796
* The addrinfo struct to use for creating the socket.
797
* - ctype
798
* The conn_type of this socket.
799
*/
800
static krb5_error_code
801
setup_socket(struct bind_address *ba, struct sockaddr *sock_address,
802
struct sockact_list *sockacts, void *handle, const char *prog,
803
verto_ctx *ctx, int listen_backlog, verto_callback vcb,
804
enum conn_type ctype)
805
{
806
krb5_error_code ret;
807
struct connection *conn;
808
verto_ev_flag flags;
809
verto_ev *ev = NULL;
810
int sock = -1;
811
char addrbuf[128];
812
813
k5_print_addr_port(sock_address, addrbuf, sizeof(addrbuf));
814
krb5_klog_syslog(LOG_DEBUG, _("Setting up %s socket for address %s"),
815
bind_type_names[ba->type], addrbuf);
816
817
if (sockacts->nsockets > 0) {
818
/* Look for a systemd socket activation fd matching sock_address. */
819
sock = find_sockact(sockacts, sock_address, bind_socktypes[ba->type]);
820
if (sock == -1) {
821
/* Ignore configured addresses that don't match any caller-provided
822
* sockets. */
823
ret = 0;
824
goto cleanup;
825
}
826
} else {
827
/* We're not using socket activation; create the socket. */
828
ret = create_server_socket(sock_address, bind_socktypes[ba->type],
829
prog, &sock);
830
if (ret)
831
goto cleanup;
832
833
/* Listen for backlogged connections on stream sockets. (For RPC
834
* sockets this will be done by svc_register().) */
835
if ((ba->type == TCP || ba->type == UNX) &&
836
listen(sock, listen_backlog) != 0) {
837
ret = errno;
838
com_err(prog, errno, _("Cannot listen on %s server socket on %s"),
839
bind_type_names[ba->type], addrbuf);
840
goto cleanup;
841
}
842
}
843
844
/* Set non-blocking I/O for non-RPC listener sockets. */
845
if (ba->type != RPC && setnbio(sock) != 0) {
846
ret = errno;
847
com_err(prog, errno,
848
_("cannot set listening %s socket on %s non-blocking"),
849
bind_type_names[ba->type], addrbuf);
850
goto cleanup;
851
}
852
853
/* Turn off the linger option for TCP sockets. */
854
if (ba->type == TCP && setnolinger(sock) != 0) {
855
ret = errno;
856
com_err(prog, errno, _("cannot set SO_LINGER on %s socket on %s"),
857
bind_type_names[ba->type], addrbuf);
858
goto cleanup;
859
}
860
861
/* Try to turn on pktinfo for UDP wildcard sockets. */
862
if (ba->type == UDP && sa_is_wildcard(sock_address)) {
863
krb5_klog_syslog(LOG_DEBUG, _("Setting pktinfo on socket %s"),
864
addrbuf);
865
ret = set_pktinfo(sock, sock_address->sa_family);
866
if (ret) {
867
com_err(prog, ret,
868
_("Cannot request packet info for UDP socket address "
869
"%s port %d"), addrbuf, ba->port);
870
krb5_klog_syslog(LOG_INFO, _("System does not support pktinfo yet "
871
"binding to a wildcard address. "
872
"Packets are not guaranteed to "
873
"return on the received address."));
874
}
875
}
876
877
/* Add the socket to the event loop. */
878
flags = VERTO_EV_FLAG_IO_READ | VERTO_EV_FLAG_PERSIST |
879
VERTO_EV_FLAG_REINITIABLE;
880
ret = add_fd(sock, ctype, flags, handle, prog, ctx, vcb, &ev);
881
if (ret) {
882
krb5_klog_syslog(LOG_ERR, _("Error attempting to add verto event"));
883
goto cleanup;
884
}
885
886
if (ba->type == RPC) {
887
conn = verto_get_private(ev);
888
conn->transp = svctcp_create(sock, 0, 0);
889
if (conn->transp == NULL) {
890
ret = errno;
891
krb5_klog_syslog(LOG_ERR, _("Cannot create RPC service: %s"),
892
strerror(ret));
893
goto cleanup;
894
}
895
896
ret = svc_register(conn->transp, ba->rpc_svc_data.prognum,
897
ba->rpc_svc_data.versnum, ba->rpc_svc_data.dispatch,
898
0);
899
if (!ret) {
900
ret = errno;
901
krb5_klog_syslog(LOG_ERR, _("Cannot register RPC service: %s"),
902
strerror(ret));
903
goto cleanup;
904
}
905
}
906
907
ev = NULL;
908
sock = -1;
909
ret = 0;
910
911
cleanup:
912
if (sock >= 0)
913
close(sock);
914
if (ev != NULL)
915
verto_del(ev);
916
return ret;
917
}
918
919
/*
920
* Setup all the socket addresses that the net-server should listen to.
921
*
922
* This function uses getaddrinfo to figure out all the addresses. This will
923
* automatically figure out which socket families that should be used on the
924
* host making it useful even for wildcard addresses.
925
*/
926
static krb5_error_code
927
setup_addresses(verto_ctx *ctx, void *handle, const char *prog,
928
int listen_backlog)
929
{
930
/* An bind_type enum map for the verto callback functions. */
931
static verto_callback *const verto_callbacks[] = {
932
[UDP] = &process_packet,
933
[TCP] = &accept_stream_connection,
934
[RPC] = &accept_rpc_connection,
935
[UNX] = &accept_stream_connection
936
};
937
krb5_error_code ret = 0;
938
size_t i;
939
int err, bound_any;
940
struct bind_address addr;
941
struct sockaddr_un sun;
942
struct addrinfo hints, *ai_list = NULL, *ai = NULL;
943
struct sockact_list sockacts = { 0 };
944
verto_callback vcb;
945
char addrbuf[128];
946
947
/* Check to make sure addresses were added to the server. */
948
if (bind_addresses.n == 0) {
949
krb5_klog_syslog(LOG_ERR, _("No addresses added to the net server"));
950
return EINVAL;
951
}
952
953
/* Ask for all address families, listener addresses, and no port name
954
* resolution. */
955
memset(&hints, 0, sizeof(struct addrinfo));
956
hints.ai_family = AF_UNSPEC;
957
hints.ai_flags = AI_PASSIVE;
958
#ifdef AI_NUMERICSERV
959
hints.ai_flags |= AI_NUMERICSERV;
960
#endif
961
962
init_sockact_list(&sockacts);
963
964
/* Add all the requested addresses. */
965
for (i = 0; i < bind_addresses.n; i++) {
966
addr = bind_addresses.data[i];
967
hints.ai_socktype = bind_socktypes[addr.type];
968
969
if (addr.type == UNX) {
970
sun.sun_family = AF_UNIX;
971
if (strlcpy(sun.sun_path, addr.address, sizeof(sun.sun_path)) >=
972
sizeof(sun.sun_path)) {
973
ret = ENAMETOOLONG;
974
krb5_klog_syslog(LOG_ERR,
975
_("UNIX domain socket path too long: %s"),
976
addr.address);
977
goto cleanup;
978
}
979
ret = setup_socket(&addr, (struct sockaddr *)&sun, &sockacts,
980
handle, prog, ctx, listen_backlog,
981
verto_callbacks[addr.type],
982
bind_conn_types[addr.type]);
983
if (ret) {
984
krb5_klog_syslog(LOG_ERR,
985
_("Failed setting up a UNIX socket (for %s)"),
986
addr.address);
987
goto cleanup;
988
}
989
continue;
990
}
991
992
/* Call getaddrinfo, using a dummy port value. */
993
err = getaddrinfo(addr.address, "0", &hints, &ai_list);
994
if (err) {
995
krb5_klog_syslog(LOG_ERR,
996
_("Failed getting address info (for %s): %s"),
997
(addr.address == NULL) ? "<wildcard>" :
998
addr.address, gai_strerror(err));
999
ret = EIO;
1000
goto cleanup;
1001
}
1002
1003
/*
1004
* Loop through all the sockets that getaddrinfo could find to match
1005
* the requested address. For wildcard listeners, this should usually
1006
* have two results, one for each of IPv4 and IPv6, or one or the
1007
* other, depending on the system. On IPv4-only systems, getaddrinfo()
1008
* may return both IPv4 and IPv6 addresses, but creating an IPv6 socket
1009
* may give an EAFNOSUPPORT error, so tolerate that error as long as we
1010
* can bind at least one socket.
1011
*/
1012
bound_any = 0;
1013
for (ai = ai_list; ai != NULL; ai = ai->ai_next) {
1014
/* Make sure getaddrinfo returned a socket with the same type that
1015
* was requested. */
1016
assert(hints.ai_socktype == ai->ai_socktype);
1017
1018
/* Set the real port number. */
1019
sa_setport(ai->ai_addr, addr.port);
1020
1021
ret = setup_socket(&addr, ai->ai_addr, &sockacts, handle, prog,
1022
ctx, listen_backlog, verto_callbacks[addr.type],
1023
bind_conn_types[addr.type]);
1024
if (ret) {
1025
k5_print_addr(ai->ai_addr, addrbuf, sizeof(addrbuf));
1026
krb5_klog_syslog(LOG_ERR,
1027
_("Failed setting up a %s socket (for %s)"),
1028
bind_type_names[addr.type], addrbuf);
1029
if (ret != EAFNOSUPPORT)
1030
goto cleanup;
1031
} else {
1032
bound_any = 1;
1033
}
1034
}
1035
if (!bound_any)
1036
goto cleanup;
1037
ret = 0;
1038
1039
if (ai_list != NULL)
1040
freeaddrinfo(ai_list);
1041
ai_list = NULL;
1042
}
1043
1044
cleanup:
1045
if (ai_list != NULL)
1046
freeaddrinfo(ai_list);
1047
fini_sockact_list(&sockacts);
1048
return ret;
1049
}
1050
1051
krb5_error_code
1052
loop_setup_network(verto_ctx *ctx, void *handle, const char *prog,
1053
int listen_backlog)
1054
{
1055
krb5_error_code ret;
1056
verto_ev *ev;
1057
int i;
1058
1059
/* Check to make sure that at least one address was added to the loop. */
1060
if (bind_addresses.n == 0)
1061
return EINVAL;
1062
1063
/* Close any open connections. */
1064
FOREACH_ELT(events, i, ev)
1065
verto_del(ev);
1066
events.n = 0;
1067
1068
krb5_klog_syslog(LOG_INFO, _("setting up network..."));
1069
ret = setup_addresses(ctx, handle, prog, listen_backlog);
1070
if (ret) {
1071
com_err(prog, ret, _("Error setting up network"));
1072
exit(1);
1073
}
1074
krb5_klog_syslog (LOG_INFO, _("set up %d sockets"), (int) events.n);
1075
if (events.n == 0) {
1076
/* If no sockets were set up, we can't continue. */
1077
com_err(prog, 0, _("no sockets set up?"));
1078
exit (1);
1079
}
1080
1081
return 0;
1082
}
1083
1084
struct udp_dispatch_state {
1085
void *handle;
1086
const char *prog;
1087
int port_fd;
1088
struct sockaddr_storage saddr;
1089
struct sockaddr_storage daddr;
1090
aux_addressing_info auxaddr;
1091
krb5_data request;
1092
char pktbuf[MAX_DGRAM_SIZE];
1093
};
1094
1095
static void
1096
process_packet_response(void *arg, krb5_error_code code, krb5_data *response)
1097
{
1098
struct udp_dispatch_state *state = arg;
1099
int cc;
1100
1101
if (code)
1102
com_err(state->prog ? state->prog : NULL, code,
1103
_("while dispatching (udp)"));
1104
if (code || response == NULL)
1105
goto out;
1106
1107
cc = send_to_from(state->port_fd, response->data,
1108
(socklen_t)response->length, 0, ss2sa(&state->saddr),
1109
ss2sa(&state->daddr), &state->auxaddr);
1110
if (cc == -1) {
1111
/* Note that the local address (daddr*) has no port number
1112
* info associated with it. */
1113
char sbuf[128], dbuf[128];
1114
int e = errno;
1115
1116
k5_print_addr_port(ss2sa(&state->saddr), sbuf, sizeof(sbuf));
1117
k5_print_addr(ss2sa(&state->daddr), dbuf, sizeof(dbuf));
1118
com_err(state->prog, e, _("while sending reply to %s from %s"),
1119
sbuf, dbuf);
1120
goto out;
1121
}
1122
if ((size_t)cc != response->length) {
1123
com_err(state->prog, 0, _("short reply write %d vs %d\n"),
1124
response->length, cc);
1125
}
1126
1127
out:
1128
krb5_free_data(get_context(state->handle), response);
1129
free(state);
1130
}
1131
1132
static void
1133
process_packet(verto_ctx *ctx, verto_ev *ev)
1134
{
1135
int cc;
1136
struct connection *conn;
1137
struct udp_dispatch_state *state;
1138
socklen_t slen;
1139
1140
conn = verto_get_private(ev);
1141
1142
state = malloc(sizeof(*state));
1143
if (!state) {
1144
com_err(conn->prog, ENOMEM, _("while dispatching (udp)"));
1145
return;
1146
}
1147
1148
state->handle = conn->handle;
1149
state->prog = conn->prog;
1150
state->port_fd = verto_get_fd(ev);
1151
assert(state->port_fd >= 0);
1152
1153
memset(&state->auxaddr, 0, sizeof(state->auxaddr));
1154
cc = recv_from_to(state->port_fd, state->pktbuf, sizeof(state->pktbuf), 0,
1155
&state->saddr, &state->daddr, &state->auxaddr);
1156
if (cc == -1) {
1157
if (errno != EINTR && errno != EAGAIN
1158
/*
1159
* This is how Linux indicates that a previous transmission was
1160
* refused, e.g., if the client timed out before getting the
1161
* response packet.
1162
*/
1163
&& errno != ECONNREFUSED
1164
)
1165
com_err(conn->prog, errno, _("while receiving from network"));
1166
free(state);
1167
return;
1168
}
1169
if (!cc) { /* zero-length packet? */
1170
free(state);
1171
return;
1172
}
1173
1174
if (state->daddr.ss_family == AF_UNSPEC && conn->type == CONN_UDP) {
1175
/*
1176
* An address couldn't be obtained, so the PKTINFO option probably
1177
* isn't available. If the socket is bound to a specific address, then
1178
* try to get the address here.
1179
*/
1180
slen = sizeof(state->daddr);
1181
(void)getsockname(state->port_fd, ss2sa(&state->daddr), &slen);
1182
}
1183
1184
state->request.length = cc;
1185
state->request.data = state->pktbuf;
1186
1187
dispatch(state->handle, ss2sa(&state->daddr), ss2sa(&state->saddr),
1188
&state->request, 0, ctx, process_packet_response, state);
1189
}
1190
1191
static int
1192
kill_lru_stream_connection(void *handle, verto_ev *newev)
1193
{
1194
struct connection *c = NULL, *oldest_c = NULL;
1195
verto_ev *ev, *oldest_ev = NULL;
1196
int i, fd = -1;
1197
1198
krb5_klog_syslog(LOG_INFO, _("too many connections"));
1199
1200
FOREACH_ELT (events, i, ev) {
1201
if (ev == newev)
1202
continue;
1203
1204
c = verto_get_private(ev);
1205
if (!c)
1206
continue;
1207
if (c->type != CONN_TCP && c->type != CONN_RPC &&
1208
c->type != CONN_UNIXSOCK)
1209
continue;
1210
if (oldest_c == NULL
1211
|| oldest_c->start_time > c->start_time) {
1212
oldest_ev = ev;
1213
oldest_c = c;
1214
}
1215
}
1216
if (oldest_c != NULL) {
1217
krb5_klog_syslog(LOG_INFO, _("dropping %s fd %d from %s"),
1218
conn_type_names[oldest_c->type],
1219
verto_get_fd(oldest_ev), oldest_c->addrbuf);
1220
if (oldest_c->type == CONN_RPC)
1221
oldest_c->rpc_force_close = 1;
1222
verto_del(oldest_ev);
1223
}
1224
return fd;
1225
}
1226
1227
static void
1228
accept_stream_connection(verto_ctx *ctx, verto_ev *ev)
1229
{
1230
int s;
1231
struct sockaddr_storage addr;
1232
socklen_t addrlen = sizeof(addr);
1233
struct connection *newconn, *conn;
1234
enum conn_type ctype;
1235
verto_ev_flag flags;
1236
verto_ev *newev;
1237
1238
conn = verto_get_private(ev);
1239
s = accept(verto_get_fd(ev), ss2sa(&addr), &addrlen);
1240
if (s < 0)
1241
return;
1242
set_cloexec_fd(s);
1243
#ifndef _WIN32
1244
if (s >= FD_SETSIZE) {
1245
close(s);
1246
return;
1247
}
1248
#endif
1249
setnbio(s);
1250
setnolinger(s);
1251
if (addr.ss_family != AF_UNIX)
1252
setkeepalive(s);
1253
1254
flags = VERTO_EV_FLAG_IO_READ | VERTO_EV_FLAG_PERSIST;
1255
ctype = (conn->type == CONN_TCP_LISTENER) ? CONN_TCP : CONN_UNIXSOCK;
1256
if (add_fd(s, ctype, flags, conn->handle, conn->prog, ctx,
1257
process_stream_connection_read, &newev) != 0) {
1258
close(s);
1259
return;
1260
}
1261
newconn = verto_get_private(newev);
1262
1263
if (addr.ss_family == AF_UNIX) {
1264
/* accept() doesn't fill in sun_path as the client socket isn't bound.
1265
* For logging purposes we will use the target address. */
1266
addrlen = sizeof(addr);
1267
if (getsockname(s, ss2sa(&addr), &addrlen) < 0) {
1268
com_err(conn->prog, errno, _("Failed to get address for %d"), s);
1269
close(s);
1270
return;
1271
}
1272
}
1273
1274
k5_print_addr_port(ss2sa(&addr), newconn->addrbuf,
1275
sizeof(newconn->addrbuf));
1276
newconn->addr_s = addr;
1277
newconn->addrlen = addrlen;
1278
newconn->bufsiz = 1024 * 1024;
1279
newconn->buffer = malloc(newconn->bufsiz);
1280
newconn->start_time = time(0);
1281
1282
if (++stream_data_counter > max_stream_data_connections)
1283
kill_lru_stream_connection(conn->handle, newev);
1284
1285
if (newconn->buffer == 0) {
1286
com_err(conn->prog, errno,
1287
_("allocating buffer for new TCP session from %s"),
1288
newconn->addrbuf);
1289
verto_del(newev);
1290
return;
1291
}
1292
newconn->offset = 0;
1293
SG_SET(&newconn->sgbuf[0], newconn->lenbuf, 4);
1294
SG_SET(&newconn->sgbuf[1], 0, 0);
1295
}
1296
1297
struct tcp_dispatch_state {
1298
struct sockaddr_storage local_saddr;
1299
struct connection *conn;
1300
krb5_data request;
1301
verto_ctx *ctx;
1302
int sock;
1303
};
1304
1305
static void
1306
process_stream_response(void *arg, krb5_error_code code, krb5_data *response)
1307
{
1308
struct tcp_dispatch_state *state = arg;
1309
verto_ev *ev;
1310
1311
assert(state);
1312
state->conn->response = response;
1313
1314
if (code)
1315
com_err(state->conn->prog, code, _("while dispatching (tcp)"));
1316
if (code || !response)
1317
goto kill_tcp_connection;
1318
1319
/* Queue outgoing response. */
1320
store_32_be(response->length, state->conn->lenbuf);
1321
SG_SET(&state->conn->sgbuf[1], response->data, response->length);
1322
state->conn->sgp = state->conn->sgbuf;
1323
state->conn->sgnum = 2;
1324
1325
ev = make_event(state->ctx, VERTO_EV_FLAG_IO_WRITE | VERTO_EV_FLAG_PERSIST,
1326
process_stream_connection_write, state->sock, state->conn);
1327
if (ev) {
1328
free(state);
1329
return;
1330
}
1331
1332
kill_tcp_connection:
1333
stream_data_counter--;
1334
free_connection(state->conn);
1335
close(state->sock);
1336
free(state);
1337
}
1338
1339
/* Creates the tcp_dispatch_state and deletes the verto event. */
1340
static struct tcp_dispatch_state *
1341
prepare_for_dispatch(verto_ctx *ctx, verto_ev *ev)
1342
{
1343
struct tcp_dispatch_state *state;
1344
1345
state = malloc(sizeof(*state));
1346
if (!state) {
1347
krb5_klog_syslog(LOG_ERR, _("error allocating tcp dispatch private!"));
1348
return NULL;
1349
}
1350
state->conn = verto_get_private(ev);
1351
state->sock = verto_get_fd(ev);
1352
state->ctx = ctx;
1353
verto_set_private(ev, NULL, NULL); /* Don't close the fd or free conn! */
1354
remove_event_from_set(ev); /* Remove it from the set. */
1355
verto_del(ev);
1356
return state;
1357
}
1358
1359
static void
1360
process_stream_connection_read(verto_ctx *ctx, verto_ev *ev)
1361
{
1362
struct tcp_dispatch_state *state = NULL;
1363
struct connection *conn = NULL;
1364
ssize_t nread;
1365
size_t len;
1366
1367
conn = verto_get_private(ev);
1368
1369
/*
1370
* Read message length and data into one big buffer, already allocated
1371
* at connect time. If we have a complete message, we stop reading, so
1372
* we should only be here if there is no data in the buffer, or only an
1373
* incomplete message.
1374
*/
1375
if (conn->offset < 4) {
1376
krb5_data *response = NULL;
1377
1378
/* msglen has not been computed. XXX Doing at least two reads
1379
* here, letting the kernel worry about buffering. */
1380
len = 4 - conn->offset;
1381
nread = SOCKET_READ(verto_get_fd(ev),
1382
conn->buffer + conn->offset, len);
1383
if (nread < 0) /* error */
1384
goto kill_tcp_connection;
1385
if (nread == 0) /* eof */
1386
goto kill_tcp_connection;
1387
conn->offset += nread;
1388
if (conn->offset == 4) {
1389
unsigned char *p = (unsigned char *)conn->buffer;
1390
conn->msglen = load_32_be(p);
1391
if (conn->msglen > conn->bufsiz - 4) {
1392
krb5_error_code err;
1393
/* Message too big. */
1394
krb5_klog_syslog(LOG_ERR, _("TCP client %s wants %lu bytes, "
1395
"cap is %lu"), conn->addrbuf,
1396
(unsigned long) conn->msglen,
1397
(unsigned long) conn->bufsiz - 4);
1398
/* XXX Should return an error. */
1399
err = make_toolong_error (conn->handle,
1400
&response);
1401
if (err) {
1402
krb5_klog_syslog(LOG_ERR, _("error constructing "
1403
"KRB_ERR_FIELD_TOOLONG error! %s"),
1404
error_message(err));
1405
goto kill_tcp_connection;
1406
}
1407
1408
state = prepare_for_dispatch(ctx, ev);
1409
if (!state) {
1410
krb5_free_data(get_context(conn->handle), response);
1411
goto kill_tcp_connection;
1412
}
1413
process_stream_response(state, 0, response);
1414
}
1415
}
1416
} else {
1417
/* msglen known. */
1418
socklen_t local_saddrlen = sizeof(struct sockaddr_storage);
1419
1420
len = conn->msglen - (conn->offset - 4);
1421
nread = SOCKET_READ(verto_get_fd(ev),
1422
conn->buffer + conn->offset, len);
1423
if (nread < 0) /* error */
1424
goto kill_tcp_connection;
1425
if (nread == 0) /* eof */
1426
goto kill_tcp_connection;
1427
conn->offset += nread;
1428
if (conn->offset < conn->msglen + 4)
1429
return;
1430
1431
/* Have a complete message, and exactly one message. */
1432
state = prepare_for_dispatch(ctx, ev);
1433
if (!state)
1434
goto kill_tcp_connection;
1435
1436
state->request.length = conn->msglen;
1437
state->request.data = conn->buffer + 4;
1438
1439
if (getsockname(verto_get_fd(ev), ss2sa(&state->local_saddr),
1440
&local_saddrlen) < 0) {
1441
krb5_klog_syslog(LOG_ERR, _("getsockname failed: %s"),
1442
error_message(errno));
1443
goto kill_tcp_connection;
1444
}
1445
dispatch(state->conn->handle, ss2sa(&state->local_saddr),
1446
ss2sa(&conn->addr_s), &state->request, 1, ctx,
1447
process_stream_response, state);
1448
}
1449
1450
return;
1451
1452
kill_tcp_connection:
1453
verto_del(ev);
1454
}
1455
1456
static void
1457
process_stream_connection_write(verto_ctx *ctx, verto_ev *ev)
1458
{
1459
struct connection *conn;
1460
SOCKET_WRITEV_TEMP tmp;
1461
ssize_t nwrote;
1462
int sock;
1463
1464
conn = verto_get_private(ev);
1465
sock = verto_get_fd(ev);
1466
1467
nwrote = SOCKET_WRITEV(sock, conn->sgp,
1468
conn->sgnum, tmp);
1469
if (nwrote > 0) { /* non-error and non-eof */
1470
while (nwrote) {
1471
sg_buf *sgp = conn->sgp;
1472
if ((size_t)nwrote < SG_LEN(sgp)) {
1473
SG_ADVANCE(sgp, (size_t)nwrote);
1474
nwrote = 0;
1475
} else {
1476
nwrote -= SG_LEN(sgp);
1477
conn->sgp++;
1478
conn->sgnum--;
1479
if (conn->sgnum == 0 && nwrote != 0)
1480
abort();
1481
}
1482
}
1483
1484
/* If we still have more data to send, just return so that
1485
* the main loop can call this function again when the socket
1486
* is ready for more writing. */
1487
if (conn->sgnum > 0)
1488
return;
1489
}
1490
1491
/* Finished sending. We should go back to reading, though if we
1492
* sent a FIELD_TOOLONG error in reply to a length with the high
1493
* bit set, RFC 4120 says we have to close the TCP stream. */
1494
verto_del(ev);
1495
}
1496
1497
void
1498
loop_free(verto_ctx *ctx)
1499
{
1500
int i;
1501
struct bind_address val;
1502
1503
verto_free(ctx);
1504
1505
/* Free each addresses added to the loop. */
1506
FOREACH_ELT(bind_addresses, i, val)
1507
free(val.address);
1508
FREE_SET_DATA(bind_addresses);
1509
FREE_SET_DATA(events);
1510
}
1511
1512
static int
1513
have_event_for_fd(int fd)
1514
{
1515
verto_ev *ev;
1516
int i;
1517
1518
FOREACH_ELT(events, i, ev) {
1519
if (verto_get_fd(ev) == fd)
1520
return 1;
1521
}
1522
1523
return 0;
1524
}
1525
1526
static void
1527
accept_rpc_connection(verto_ctx *ctx, verto_ev *ev)
1528
{
1529
verto_ev_flag flags;
1530
struct connection *conn;
1531
fd_set fds;
1532
int s;
1533
1534
conn = verto_get_private(ev);
1535
1536
/* Service the woken RPC listener descriptor. */
1537
FD_ZERO(&fds);
1538
FD_SET(verto_get_fd(ev), &fds);
1539
svc_getreqset(&fds);
1540
1541
/* Scan svc_fdset for any new connections. */
1542
for (s = 0; s < FD_SETSIZE; s++) {
1543
struct sockaddr_storage addr;
1544
socklen_t addrlen = sizeof(addr);
1545
struct connection *newconn;
1546
verto_ev *newev;
1547
1548
/* If we already have this fd, continue. */
1549
if (!FD_ISSET(s, &svc_fdset) || have_event_for_fd(s))
1550
continue;
1551
1552
flags = VERTO_EV_FLAG_IO_READ | VERTO_EV_FLAG_PERSIST;
1553
if (add_fd(s, CONN_RPC, flags, conn->handle, conn->prog, ctx,
1554
process_rpc_connection, &newev) != 0)
1555
continue;
1556
newconn = verto_get_private(newev);
1557
1558
set_cloexec_fd(s);
1559
1560
if (getpeername(s, ss2sa(&addr), &addrlen) != 0) {
1561
strlcpy(newconn->addrbuf, "<unknown>", sizeof(newconn->addrbuf));
1562
} else {
1563
k5_print_addr_port(ss2sa(&addr), newconn->addrbuf,
1564
sizeof(newconn->addrbuf));
1565
}
1566
1567
newconn->addr_s = addr;
1568
newconn->addrlen = addrlen;
1569
newconn->start_time = time(0);
1570
1571
if (++stream_data_counter > max_stream_data_connections)
1572
kill_lru_stream_connection(newconn->handle, newev);
1573
}
1574
}
1575
1576
static void
1577
process_rpc_connection(verto_ctx *ctx, verto_ev *ev)
1578
{
1579
fd_set fds;
1580
1581
FD_ZERO(&fds);
1582
FD_SET(verto_get_fd(ev), &fds);
1583
svc_getreqset(&fds);
1584
1585
if (!FD_ISSET(verto_get_fd(ev), &svc_fdset))
1586
verto_del(ev);
1587
}
1588
1589
#endif /* INET */
1590
1591