xref: /freebsd/crypto/krb5/src/lib/apputils/net-server.c (revision 7f2fe78b9dd5f51c821d771b63d2e096f6fd49e9)
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