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 delimeters 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 | AI_NUMERICSERV;
832
833 /* Add all the requested addresses. */
834 for (i = 0; i < bind_addresses.n; i++) {
835 addr = bind_addresses.data[i];
836 hints.ai_socktype = bind_socktypes[addr.type];
837
838 /* Call getaddrinfo, using a dummy port value. */
839 err = getaddrinfo(addr.address, "0", &hints, &ai_list);
840 if (err) {
841 krb5_klog_syslog(LOG_ERR,
842 _("Failed getting address info (for %s): %s"),
843 (addr.address == NULL) ? "<wildcard>" :
844 addr.address, gai_strerror(err));
845 ret = EIO;
846 goto cleanup;
847 }
848
849 /*
850 * Loop through all the sockets that getaddrinfo could find to match
851 * the requested address. For wildcard listeners, this should usually
852 * have two results, one for each of IPv4 and IPv6, or one or the
853 * other, depending on the system. On IPv4-only systems, getaddrinfo()
854 * may return both IPv4 and IPv6 addresses, but creating an IPv6 socket
855 * may give an EAFNOSUPPORT error, so tolerate that error as long as we
856 * can bind at least one socket.
857 */
858 bound_any = 0;
859 for (ai = ai_list; ai != NULL; ai = ai->ai_next) {
860 /* Make sure getaddrinfo returned a socket with the same type that
861 * was requested. */
862 assert(hints.ai_socktype == ai->ai_socktype);
863
864 /* Set the real port number. */
865 sa_setport(ai->ai_addr, addr.port);
866
867 ret = setup_socket(&addr, ai->ai_addr, handle, prog, ctx,
868 tcp_listen_backlog, verto_callbacks[addr.type],
869 bind_conn_types[addr.type]);
870 if (ret) {
871 krb5_klog_syslog(LOG_ERR,
872 _("Failed setting up a %s socket (for %s)"),
873 bind_type_names[addr.type],
874 paddr(ai->ai_addr));
875 if (ret != EAFNOSUPPORT)
876 goto cleanup;
877 } else {
878 bound_any = 1;
879 }
880 }
881 if (!bound_any)
882 goto cleanup;
883 ret = 0;
884
885 if (ai_list != NULL)
886 freeaddrinfo(ai_list);
887 ai_list = NULL;
888 }
889
890 cleanup:
891 if (ai_list != NULL)
892 freeaddrinfo(ai_list);
893 return ret;
894 }
895
896 krb5_error_code
loop_setup_network(verto_ctx * ctx,void * handle,const char * prog,int tcp_listen_backlog)897 loop_setup_network(verto_ctx *ctx, void *handle, const char *prog,
898 int tcp_listen_backlog)
899 {
900 krb5_error_code ret;
901 verto_ev *ev;
902 int i;
903
904 /* Check to make sure that at least one address was added to the loop. */
905 if (bind_addresses.n == 0)
906 return EINVAL;
907
908 /* Close any open connections. */
909 FOREACH_ELT(events, i, ev)
910 verto_del(ev);
911 events.n = 0;
912
913 krb5_klog_syslog(LOG_INFO, _("setting up network..."));
914 ret = setup_addresses(ctx, handle, prog, tcp_listen_backlog);
915 if (ret) {
916 com_err(prog, ret, _("Error setting up network"));
917 exit(1);
918 }
919 krb5_klog_syslog (LOG_INFO, _("set up %d sockets"), (int) events.n);
920 if (events.n == 0) {
921 /* If no sockets were set up, we can't continue. */
922 com_err(prog, 0, _("no sockets set up?"));
923 exit (1);
924 }
925
926 return 0;
927 }
928
929 void
init_addr(krb5_fulladdr * faddr,struct sockaddr * sa)930 init_addr(krb5_fulladdr *faddr, struct sockaddr *sa)
931 {
932 switch (sa->sa_family) {
933 case AF_INET:
934 faddr->address->addrtype = ADDRTYPE_INET;
935 faddr->address->length = 4;
936 faddr->address->contents = (krb5_octet *) &sa2sin(sa)->sin_addr;
937 faddr->port = ntohs(sa2sin(sa)->sin_port);
938 break;
939 case AF_INET6:
940 if (IN6_IS_ADDR_V4MAPPED(&sa2sin6(sa)->sin6_addr)) {
941 faddr->address->addrtype = ADDRTYPE_INET;
942 faddr->address->length = 4;
943 faddr->address->contents = 12 + (krb5_octet *) &sa2sin6(sa)->sin6_addr;
944 } else {
945 faddr->address->addrtype = ADDRTYPE_INET6;
946 faddr->address->length = 16;
947 faddr->address->contents = (krb5_octet *) &sa2sin6(sa)->sin6_addr;
948 }
949 faddr->port = ntohs(sa2sin6(sa)->sin6_port);
950 break;
951 default:
952 faddr->address->addrtype = -1;
953 faddr->address->length = 0;
954 faddr->address->contents = 0;
955 faddr->port = 0;
956 break;
957 }
958 }
959
960 struct udp_dispatch_state {
961 void *handle;
962 const char *prog;
963 int port_fd;
964 krb5_address remote_addr_buf;
965 krb5_fulladdr remote_addr;
966 krb5_address local_addr_buf;
967 krb5_fulladdr local_addr;
968 socklen_t saddr_len;
969 socklen_t daddr_len;
970 struct sockaddr_storage saddr;
971 struct sockaddr_storage daddr;
972 aux_addressing_info auxaddr;
973 krb5_data request;
974 char pktbuf[MAX_DGRAM_SIZE];
975 };
976
977 static void
process_packet_response(void * arg,krb5_error_code code,krb5_data * response)978 process_packet_response(void *arg, krb5_error_code code, krb5_data *response)
979 {
980 struct udp_dispatch_state *state = arg;
981 int cc;
982
983 if (code)
984 com_err(state->prog ? state->prog : NULL, code,
985 _("while dispatching (udp)"));
986 if (code || response == NULL)
987 goto out;
988
989 cc = send_to_from(state->port_fd, response->data,
990 (socklen_t) response->length, 0,
991 (struct sockaddr *)&state->saddr, state->saddr_len,
992 (struct sockaddr *)&state->daddr, state->daddr_len,
993 &state->auxaddr);
994 if (cc == -1) {
995 /* Note that the local address (daddr*) has no port number
996 * info associated with it. */
997 char saddrbuf[NI_MAXHOST], sportbuf[NI_MAXSERV];
998 char daddrbuf[NI_MAXHOST];
999 int e = errno;
1000
1001 if (getnameinfo((struct sockaddr *)&state->daddr, state->daddr_len,
1002 daddrbuf, sizeof(daddrbuf), 0, 0,
1003 NI_NUMERICHOST) != 0) {
1004 strlcpy(daddrbuf, "?", sizeof(daddrbuf));
1005 }
1006
1007 if (getnameinfo((struct sockaddr *)&state->saddr, state->saddr_len,
1008 saddrbuf, sizeof(saddrbuf), sportbuf, sizeof(sportbuf),
1009 NI_NUMERICHOST|NI_NUMERICSERV) != 0) {
1010 strlcpy(saddrbuf, "?", sizeof(saddrbuf));
1011 strlcpy(sportbuf, "?", sizeof(sportbuf));
1012 }
1013
1014 com_err(state->prog, e, _("while sending reply to %s/%s from %s"),
1015 saddrbuf, sportbuf, daddrbuf);
1016 goto out;
1017 }
1018 if ((size_t)cc != response->length) {
1019 com_err(state->prog, 0, _("short reply write %d vs %d\n"),
1020 response->length, cc);
1021 }
1022
1023 out:
1024 krb5_free_data(get_context(state->handle), response);
1025 free(state);
1026 }
1027
1028 static void
process_packet(verto_ctx * ctx,verto_ev * ev)1029 process_packet(verto_ctx *ctx, verto_ev *ev)
1030 {
1031 int cc;
1032 struct connection *conn;
1033 struct udp_dispatch_state *state;
1034
1035 conn = verto_get_private(ev);
1036
1037 state = malloc(sizeof(*state));
1038 if (!state) {
1039 com_err(conn->prog, ENOMEM, _("while dispatching (udp)"));
1040 return;
1041 }
1042
1043 state->handle = conn->handle;
1044 state->prog = conn->prog;
1045 state->port_fd = verto_get_fd(ev);
1046 assert(state->port_fd >= 0);
1047
1048 state->saddr_len = sizeof(state->saddr);
1049 state->daddr_len = sizeof(state->daddr);
1050 memset(&state->auxaddr, 0, sizeof(state->auxaddr));
1051 cc = recv_from_to(state->port_fd, state->pktbuf, sizeof(state->pktbuf), 0,
1052 (struct sockaddr *)&state->saddr, &state->saddr_len,
1053 (struct sockaddr *)&state->daddr, &state->daddr_len,
1054 &state->auxaddr);
1055 if (cc == -1) {
1056 if (errno != EINTR && errno != EAGAIN
1057 /*
1058 * This is how Linux indicates that a previous transmission was
1059 * refused, e.g., if the client timed out before getting the
1060 * response packet.
1061 */
1062 && errno != ECONNREFUSED
1063 )
1064 com_err(conn->prog, errno, _("while receiving from network"));
1065 free(state);
1066 return;
1067 }
1068 if (!cc) { /* zero-length packet? */
1069 free(state);
1070 return;
1071 }
1072
1073 if (state->daddr_len == 0 && conn->type == CONN_UDP) {
1074 /*
1075 * An address couldn't be obtained, so the PKTINFO option probably
1076 * isn't available. If the socket is bound to a specific address, then
1077 * try to get the address here.
1078 */
1079 state->daddr_len = sizeof(state->daddr);
1080 if (getsockname(state->port_fd, (struct sockaddr *)&state->daddr,
1081 &state->daddr_len) != 0)
1082 state->daddr_len = 0;
1083 /* On failure, keep going anyways. */
1084 }
1085
1086 state->request.length = cc;
1087 state->request.data = state->pktbuf;
1088
1089 state->remote_addr.address = &state->remote_addr_buf;
1090 init_addr(&state->remote_addr, ss2sa(&state->saddr));
1091
1092 state->local_addr.address = &state->local_addr_buf;
1093 init_addr(&state->local_addr, ss2sa(&state->daddr));
1094
1095 /* This address is in net order. */
1096 dispatch(state->handle, &state->local_addr, &state->remote_addr,
1097 &state->request, 0, ctx, process_packet_response, state);
1098 }
1099
1100 static int
kill_lru_tcp_or_rpc_connection(void * handle,verto_ev * newev)1101 kill_lru_tcp_or_rpc_connection(void *handle, verto_ev *newev)
1102 {
1103 struct connection *c = NULL, *oldest_c = NULL;
1104 verto_ev *ev, *oldest_ev = NULL;
1105 int i, fd = -1;
1106
1107 krb5_klog_syslog(LOG_INFO, _("too many connections"));
1108
1109 FOREACH_ELT (events, i, ev) {
1110 if (ev == newev)
1111 continue;
1112
1113 c = verto_get_private(ev);
1114 if (!c)
1115 continue;
1116 if (c->type != CONN_TCP && c->type != CONN_RPC)
1117 continue;
1118 if (oldest_c == NULL
1119 || oldest_c->start_time > c->start_time) {
1120 oldest_ev = ev;
1121 oldest_c = c;
1122 }
1123 }
1124 if (oldest_c != NULL) {
1125 krb5_klog_syslog(LOG_INFO, _("dropping %s fd %d from %s"),
1126 c->type == CONN_RPC ? "rpc" : "tcp",
1127 verto_get_fd(oldest_ev), oldest_c->addrbuf);
1128 if (oldest_c->type == CONN_RPC)
1129 oldest_c->rpc_force_close = 1;
1130 verto_del(oldest_ev);
1131 }
1132 return fd;
1133 }
1134
1135 static void
accept_tcp_connection(verto_ctx * ctx,verto_ev * ev)1136 accept_tcp_connection(verto_ctx *ctx, verto_ev *ev)
1137 {
1138 int s;
1139 struct sockaddr_storage addr_s;
1140 struct sockaddr *addr = (struct sockaddr *)&addr_s;
1141 socklen_t addrlen = sizeof(addr_s);
1142 struct connection *newconn, *conn;
1143 char tmpbuf[10];
1144 verto_ev_flag flags;
1145 verto_ev *newev;
1146
1147 conn = verto_get_private(ev);
1148 s = accept(verto_get_fd(ev), addr, &addrlen);
1149 if (s < 0)
1150 return;
1151 set_cloexec_fd(s);
1152 #ifndef _WIN32
1153 if (s >= FD_SETSIZE) {
1154 close(s);
1155 return;
1156 }
1157 #endif
1158 setnbio(s), setnolinger(s), setkeepalive(s);
1159
1160 flags = VERTO_EV_FLAG_IO_READ | VERTO_EV_FLAG_PERSIST;
1161 if (add_fd(s, CONN_TCP, flags, conn->handle, conn->prog, ctx,
1162 process_tcp_connection_read, &newev) != 0) {
1163 close(s);
1164 return;
1165 }
1166 newconn = verto_get_private(newev);
1167
1168 if (getnameinfo((struct sockaddr *)&addr_s, addrlen,
1169 newconn->addrbuf, sizeof(newconn->addrbuf),
1170 tmpbuf, sizeof(tmpbuf),
1171 NI_NUMERICHOST | NI_NUMERICSERV))
1172 strlcpy(newconn->addrbuf, "???", sizeof(newconn->addrbuf));
1173 else {
1174 char *p, *end;
1175 p = newconn->addrbuf;
1176 end = p + sizeof(newconn->addrbuf);
1177 p += strlen(p);
1178 if ((size_t)(end - p) > 2 + strlen(tmpbuf)) {
1179 *p++ = '.';
1180 strlcpy(p, tmpbuf, end - p);
1181 }
1182 }
1183
1184 newconn->addr_s = addr_s;
1185 newconn->addrlen = addrlen;
1186 newconn->bufsiz = 1024 * 1024;
1187 newconn->buffer = malloc(newconn->bufsiz);
1188 newconn->start_time = time(0);
1189
1190 if (++tcp_or_rpc_data_counter > max_tcp_or_rpc_data_connections)
1191 kill_lru_tcp_or_rpc_connection(conn->handle, newev);
1192
1193 if (newconn->buffer == 0) {
1194 com_err(conn->prog, errno,
1195 _("allocating buffer for new TCP session from %s"),
1196 newconn->addrbuf);
1197 verto_del(newev);
1198 return;
1199 }
1200 newconn->offset = 0;
1201 newconn->remote_addr.address = &newconn->remote_addr_buf;
1202 init_addr(&newconn->remote_addr, ss2sa(&newconn->addr_s));
1203 SG_SET(&newconn->sgbuf[0], newconn->lenbuf, 4);
1204 SG_SET(&newconn->sgbuf[1], 0, 0);
1205 }
1206
1207 struct tcp_dispatch_state {
1208 struct sockaddr_storage local_saddr;
1209 krb5_address local_addr_buf;
1210 krb5_fulladdr local_addr;
1211 struct connection *conn;
1212 krb5_data request;
1213 verto_ctx *ctx;
1214 int sock;
1215 };
1216
1217 static void
process_tcp_response(void * arg,krb5_error_code code,krb5_data * response)1218 process_tcp_response(void *arg, krb5_error_code code, krb5_data *response)
1219 {
1220 struct tcp_dispatch_state *state = arg;
1221 verto_ev *ev;
1222
1223 assert(state);
1224 state->conn->response = response;
1225
1226 if (code)
1227 com_err(state->conn->prog, code, _("while dispatching (tcp)"));
1228 if (code || !response)
1229 goto kill_tcp_connection;
1230
1231 /* Queue outgoing response. */
1232 store_32_be(response->length, state->conn->lenbuf);
1233 SG_SET(&state->conn->sgbuf[1], response->data, response->length);
1234 state->conn->sgp = state->conn->sgbuf;
1235 state->conn->sgnum = 2;
1236
1237 ev = make_event(state->ctx, VERTO_EV_FLAG_IO_WRITE | VERTO_EV_FLAG_PERSIST,
1238 process_tcp_connection_write, state->sock, state->conn);
1239 if (ev) {
1240 free(state);
1241 return;
1242 }
1243
1244 kill_tcp_connection:
1245 tcp_or_rpc_data_counter--;
1246 free_connection(state->conn);
1247 close(state->sock);
1248 free(state);
1249 }
1250
1251 /* Creates the tcp_dispatch_state and deletes the verto event. */
1252 static struct tcp_dispatch_state *
prepare_for_dispatch(verto_ctx * ctx,verto_ev * ev)1253 prepare_for_dispatch(verto_ctx *ctx, verto_ev *ev)
1254 {
1255 struct tcp_dispatch_state *state;
1256
1257 state = malloc(sizeof(*state));
1258 if (!state) {
1259 krb5_klog_syslog(LOG_ERR, _("error allocating tcp dispatch private!"));
1260 return NULL;
1261 }
1262 state->conn = verto_get_private(ev);
1263 state->sock = verto_get_fd(ev);
1264 state->ctx = ctx;
1265 verto_set_private(ev, NULL, NULL); /* Don't close the fd or free conn! */
1266 remove_event_from_set(ev); /* Remove it from the set. */
1267 verto_del(ev);
1268 return state;
1269 }
1270
1271 static void
process_tcp_connection_read(verto_ctx * ctx,verto_ev * ev)1272 process_tcp_connection_read(verto_ctx *ctx, verto_ev *ev)
1273 {
1274 struct tcp_dispatch_state *state = NULL;
1275 struct connection *conn = NULL;
1276 ssize_t nread;
1277 size_t len;
1278
1279 conn = verto_get_private(ev);
1280
1281 /*
1282 * Read message length and data into one big buffer, already allocated
1283 * at connect time. If we have a complete message, we stop reading, so
1284 * we should only be here if there is no data in the buffer, or only an
1285 * incomplete message.
1286 */
1287 if (conn->offset < 4) {
1288 krb5_data *response = NULL;
1289
1290 /* msglen has not been computed. XXX Doing at least two reads
1291 * here, letting the kernel worry about buffering. */
1292 len = 4 - conn->offset;
1293 nread = SOCKET_READ(verto_get_fd(ev),
1294 conn->buffer + conn->offset, len);
1295 if (nread < 0) /* error */
1296 goto kill_tcp_connection;
1297 if (nread == 0) /* eof */
1298 goto kill_tcp_connection;
1299 conn->offset += nread;
1300 if (conn->offset == 4) {
1301 unsigned char *p = (unsigned char *)conn->buffer;
1302 conn->msglen = load_32_be(p);
1303 if (conn->msglen > conn->bufsiz - 4) {
1304 krb5_error_code err;
1305 /* Message too big. */
1306 krb5_klog_syslog(LOG_ERR, _("TCP client %s wants %lu bytes, "
1307 "cap is %lu"), conn->addrbuf,
1308 (unsigned long) conn->msglen,
1309 (unsigned long) conn->bufsiz - 4);
1310 /* XXX Should return an error. */
1311 err = make_toolong_error (conn->handle,
1312 &response);
1313 if (err) {
1314 krb5_klog_syslog(LOG_ERR, _("error constructing "
1315 "KRB_ERR_FIELD_TOOLONG error! %s"),
1316 error_message(err));
1317 goto kill_tcp_connection;
1318 }
1319
1320 state = prepare_for_dispatch(ctx, ev);
1321 if (!state) {
1322 krb5_free_data(get_context(conn->handle), response);
1323 goto kill_tcp_connection;
1324 }
1325 process_tcp_response(state, 0, response);
1326 }
1327 }
1328 } else {
1329 /* msglen known. */
1330 socklen_t local_saddrlen = sizeof(struct sockaddr_storage);
1331
1332 len = conn->msglen - (conn->offset - 4);
1333 nread = SOCKET_READ(verto_get_fd(ev),
1334 conn->buffer + conn->offset, len);
1335 if (nread < 0) /* error */
1336 goto kill_tcp_connection;
1337 if (nread == 0) /* eof */
1338 goto kill_tcp_connection;
1339 conn->offset += nread;
1340 if (conn->offset < conn->msglen + 4)
1341 return;
1342
1343 /* Have a complete message, and exactly one message. */
1344 state = prepare_for_dispatch(ctx, ev);
1345 if (!state)
1346 goto kill_tcp_connection;
1347
1348 state->request.length = conn->msglen;
1349 state->request.data = conn->buffer + 4;
1350
1351 if (getsockname(verto_get_fd(ev), ss2sa(&state->local_saddr),
1352 &local_saddrlen) < 0) {
1353 krb5_klog_syslog(LOG_ERR, _("getsockname failed: %s"),
1354 error_message(errno));
1355 goto kill_tcp_connection;
1356 }
1357 state->local_addr.address = &state->local_addr_buf;
1358 init_addr(&state->local_addr, ss2sa(&state->local_saddr));
1359 dispatch(state->conn->handle, &state->local_addr, &conn->remote_addr,
1360 &state->request, 1, ctx, process_tcp_response, state);
1361 }
1362
1363 return;
1364
1365 kill_tcp_connection:
1366 verto_del(ev);
1367 }
1368
1369 static void
process_tcp_connection_write(verto_ctx * ctx,verto_ev * ev)1370 process_tcp_connection_write(verto_ctx *ctx, verto_ev *ev)
1371 {
1372 struct connection *conn;
1373 SOCKET_WRITEV_TEMP tmp;
1374 ssize_t nwrote;
1375 int sock;
1376
1377 conn = verto_get_private(ev);
1378 sock = verto_get_fd(ev);
1379
1380 nwrote = SOCKET_WRITEV(sock, conn->sgp,
1381 conn->sgnum, tmp);
1382 if (nwrote > 0) { /* non-error and non-eof */
1383 while (nwrote) {
1384 sg_buf *sgp = conn->sgp;
1385 if ((size_t)nwrote < SG_LEN(sgp)) {
1386 SG_ADVANCE(sgp, (size_t)nwrote);
1387 nwrote = 0;
1388 } else {
1389 nwrote -= SG_LEN(sgp);
1390 conn->sgp++;
1391 conn->sgnum--;
1392 if (conn->sgnum == 0 && nwrote != 0)
1393 abort();
1394 }
1395 }
1396
1397 /* If we still have more data to send, just return so that
1398 * the main loop can call this function again when the socket
1399 * is ready for more writing. */
1400 if (conn->sgnum > 0)
1401 return;
1402 }
1403
1404 /* Finished sending. We should go back to reading, though if we
1405 * sent a FIELD_TOOLONG error in reply to a length with the high
1406 * bit set, RFC 4120 says we have to close the TCP stream. */
1407 verto_del(ev);
1408 }
1409
1410 void
loop_free(verto_ctx * ctx)1411 loop_free(verto_ctx *ctx)
1412 {
1413 int i;
1414 struct bind_address val;
1415
1416 verto_free(ctx);
1417
1418 /* Free each addresses added to the loop. */
1419 FOREACH_ELT(bind_addresses, i, val)
1420 free(val.address);
1421 FREE_SET_DATA(bind_addresses);
1422 FREE_SET_DATA(events);
1423 }
1424
1425 static int
have_event_for_fd(int fd)1426 have_event_for_fd(int fd)
1427 {
1428 verto_ev *ev;
1429 int i;
1430
1431 FOREACH_ELT(events, i, ev) {
1432 if (verto_get_fd(ev) == fd)
1433 return 1;
1434 }
1435
1436 return 0;
1437 }
1438
1439 static void
accept_rpc_connection(verto_ctx * ctx,verto_ev * ev)1440 accept_rpc_connection(verto_ctx *ctx, verto_ev *ev)
1441 {
1442 verto_ev_flag flags;
1443 struct connection *conn;
1444 fd_set fds;
1445 int s;
1446
1447 conn = verto_get_private(ev);
1448
1449 /* Service the woken RPC listener descriptor. */
1450 FD_ZERO(&fds);
1451 FD_SET(verto_get_fd(ev), &fds);
1452 svc_getreqset(&fds);
1453
1454 /* Scan svc_fdset for any new connections. */
1455 for (s = 0; s < FD_SETSIZE; s++) {
1456 struct sockaddr_storage addr_s;
1457 struct sockaddr *addr = (struct sockaddr *) &addr_s;
1458 socklen_t addrlen = sizeof(addr_s);
1459 struct connection *newconn;
1460 char tmpbuf[10];
1461 verto_ev *newev;
1462
1463 /* If we already have this fd, continue. */
1464 if (!FD_ISSET(s, &svc_fdset) || have_event_for_fd(s))
1465 continue;
1466
1467 flags = VERTO_EV_FLAG_IO_READ | VERTO_EV_FLAG_PERSIST;
1468 if (add_fd(s, CONN_RPC, flags, conn->handle, conn->prog, ctx,
1469 process_rpc_connection, &newev) != 0)
1470 continue;
1471 newconn = verto_get_private(newev);
1472
1473 set_cloexec_fd(s);
1474
1475 if (getpeername(s, addr, &addrlen) ||
1476 getnameinfo(addr, addrlen,
1477 newconn->addrbuf,
1478 sizeof(newconn->addrbuf),
1479 tmpbuf, sizeof(tmpbuf),
1480 NI_NUMERICHOST | NI_NUMERICSERV)) {
1481 strlcpy(newconn->addrbuf, "???",
1482 sizeof(newconn->addrbuf));
1483 } else {
1484 char *p, *end;
1485 p = newconn->addrbuf;
1486 end = p + sizeof(newconn->addrbuf);
1487 p += strlen(p);
1488 if ((size_t)(end - p) > 2 + strlen(tmpbuf)) {
1489 *p++ = '.';
1490 strlcpy(p, tmpbuf, end - p);
1491 }
1492 }
1493
1494 newconn->addr_s = addr_s;
1495 newconn->addrlen = addrlen;
1496 newconn->start_time = time(0);
1497
1498 if (++tcp_or_rpc_data_counter > max_tcp_or_rpc_data_connections)
1499 kill_lru_tcp_or_rpc_connection(newconn->handle, newev);
1500
1501 newconn->remote_addr.address = &newconn->remote_addr_buf;
1502 init_addr(&newconn->remote_addr, ss2sa(&newconn->addr_s));
1503 }
1504 }
1505
1506 static void
process_rpc_connection(verto_ctx * ctx,verto_ev * ev)1507 process_rpc_connection(verto_ctx *ctx, verto_ev *ev)
1508 {
1509 fd_set fds;
1510
1511 FD_ZERO(&fds);
1512 FD_SET(verto_get_fd(ev), &fds);
1513 svc_getreqset(&fds);
1514
1515 if (!FD_ISSET(verto_get_fd(ev), &svc_fdset))
1516 verto_del(ev);
1517 }
1518
1519 #endif /* INET */
1520