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