2 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
9 * Copyright 1990,2000 by the Massachusetts Institute of Technology.
11 * Export of this software from the United States of America may
12 * require a specific license from the United States Government.
13 * It is the responsibility of any person or organization contemplating
14 * export to obtain such a license before exporting.
16 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
17 * distribute this software and its documentation for any purpose and
18 * without fee is hereby granted, provided that the above copyright
19 * notice appear in all copies and that both that copyright notice and
20 * this permission notice appear in supporting documentation, and that
21 * the name of M.I.T. not be used in advertising or publicity pertaining
22 * to distribution of the software without specific, written prior
23 * permission. Furthermore if you modify this software you must label
24 * your software as modified software and not distribute it in such a
25 * fashion that it might be confused with the original M.I.T. software.
26 * M.I.T. makes no representations about the suitability of
27 * this software for any purpose. It is provided "as is" without express
28 * or implied warranty.
31 * Network code for Kerberos v5 KDC.
39 #include "adm_proto.h"
40 #include <sys/ioctl.h>
45 #include "port-sockets.h"
46 /* #include "socket-utils.h" */
48 #ifdef HAVE_NETINET_IN_H
49 #include <sys/types.h>
50 #include <netinet/in.h>
51 #include <sys/socket.h>
52 #ifdef HAVE_SYS_SOCKIO_H
53 /* for SIOCGIFCONF, etc. */
54 #include <sys/sockio.h>
60 #include <sys/select.h>
62 #include <arpa/inet.h>
66 #ifndef ARPHRD_ETHER /* OpenBSD breaks on multiple inclusions */
70 #ifdef HAVE_SYS_FILIO_H
71 #include <sys/filio.h> /* FIONBIO */
74 #include "fake-addrinfo.h"
76 /* Misc utility routines. */
78 set_sa_port(struct sockaddr
*addr
, int port
)
80 switch (addr
->sa_family
) {
82 sa2sin(addr
)->sin_port
= port
;
86 sa2sin6(addr
)->sin6_port
= port
;
94 static int ipv6_enabled()
97 static int result
= -1;
100 s
= socket(AF_INET6
, SOCK_STREAM
, 0);
114 setreuseaddr(int sock
, int value
)
116 return setsockopt(sock
, SOL_SOCKET
, SO_REUSEADDR
, &value
, sizeof(value
));
119 #if defined(KRB5_USE_INET6) && defined(IPV6_V6ONLY)
121 setv6only(int sock
, int value
)
123 return setsockopt(sock
, IPPROTO_IPV6
, IPV6_V6ONLY
, &value
, sizeof(value
));
128 static const char *paddr (struct sockaddr
*sa
)
130 static char buf
[100];
132 if (getnameinfo(sa
, socklen(sa
),
133 buf
, sizeof(buf
), portbuf
, sizeof(portbuf
),
134 NI_NUMERICHOST
|NI_NUMERICSERV
))
135 strcpy(buf
, "<unprintable>");
137 unsigned int len
= sizeof(buf
) - strlen(buf
);
138 char *p
= buf
+ strlen(buf
);
139 if (len
> 2+strlen(portbuf
)) {
142 strncpy(p
, portbuf
, len
);
150 enum kdc_conn_type
{ CONN_UDP
, CONN_TCP_LISTENER
, CONN_TCP
};
152 /* Per-connection info. */
155 enum kdc_conn_type type
;
156 void (*service
)(struct connection
*, const char *, int);
157 /* Solaris Kerberos: for auditing */
158 in_port_t port
; /* local port */
160 /* Type-specific information. */
169 struct sockaddr_storage addr_s
;
181 unsigned char lenbuf
[4];
185 /* crude denial-of-service avoidance support */
192 #define SET(TYPE) struct { TYPE *data; int n, max; }
194 /* Start at the top and work down -- this should allow for deletions
195 without disrupting the iteration, since we delete by overwriting
196 the element to be removed with the last element. */
197 #define FOREACH_ELT(set,idx,vvar) \
198 for (idx = set.n-1; idx >= 0 && (vvar = set.data[idx], 1); idx--)
200 #define GROW_SET(set, incr, tmpptr) \
201 (((int)(set.max + incr) < set.max \
202 || (((size_t)((int)(set.max + incr) * sizeof(set.data[0])) \
203 / sizeof(set.data[0])) \
204 != (set.max + incr))) \
206 : ((tmpptr = reallocarray(set.data, set.max + incr, sizeof (set.data[0]))) \
207 ? (set.data = tmpptr, set.max += incr, 1) \
210 /* 1 = success, 0 = failure */
211 #define ADD(set, val, tmpptr) \
212 ((set.n < set.max || GROW_SET(set, 10, tmpptr)) \
213 ? (set.data[set.n++] = val, 1) \
216 #define DEL(set, idx) \
217 (set.data[idx] = set.data[--set.n], 0)
219 #define FREE_SET_DATA(set) if(set.data) free(set.data); \
220 (set.data = 0, set.max = 0)
223 /* Set<struct connection *> connections; */
224 static SET(struct connection
*) connections
;
225 #define n_sockets connections.n
226 #define conns connections.data
228 /* Set<u_short> udp_port_data, tcp_port_data; */
229 static SET(u_short
) udp_port_data
, tcp_port_data
;
233 static struct select_state sstate
;
235 static krb5_error_code
add_udp_port(int port
)
240 u_short s_port
= port
;
245 FOREACH_ELT (udp_port_data
, i
, val
)
248 if (!ADD(udp_port_data
, s_port
, tmp
))
253 static krb5_error_code
add_tcp_port(int port
)
258 u_short s_port
= port
;
263 FOREACH_ELT (tcp_port_data
, i
, val
)
266 if (!ADD(tcp_port_data
, s_port
, tmp
))
272 #define USE_AF AF_INET
273 #define USE_TYPE SOCK_DGRAM
275 #define SOCKET_ERRNO errno
276 #include "foreachaddr.h"
280 krb5_error_code retval
;
283 static struct connection
*
284 add_fd (struct socksetup
*data
, int sock
, enum kdc_conn_type conntype
,
285 void (*service
)(struct connection
*, const char *, int))
287 struct connection
*newconn
;
290 newconn
= malloc(sizeof(*newconn
));
292 data
->retval
= errno
;
293 com_err(data
->prog
, errno
,
294 gettext("cannot allocate storage for connection info"));
297 if (!ADD(connections
, newconn
, tmp
)) {
298 data
->retval
= errno
;
299 com_err(data
->prog
, data
->retval
, gettext("cannot save socket info"));
304 memset(newconn
, 0, sizeof(*newconn
));
305 newconn
->type
= conntype
;
307 newconn
->service
= service
;
311 static void process_packet(struct connection
*, const char *, int);
312 static void accept_tcp_connection(struct connection
*, const char *, int);
313 static void process_tcp_connection(struct connection
*, const char *, int);
315 static struct connection
*
316 add_udp_fd (struct socksetup
*data
, int sock
)
318 return add_fd(data
, sock
, CONN_UDP
, process_packet
);
321 static struct connection
*
322 add_tcp_listener_fd (struct socksetup
*data
, int sock
)
324 return add_fd(data
, sock
, CONN_TCP_LISTENER
, accept_tcp_connection
);
327 static struct connection
*
328 add_tcp_data_fd (struct socksetup
*data
, int sock
)
330 return add_fd(data
, sock
, CONN_TCP
, process_tcp_connection
);
334 delete_fd (struct connection
*xconn
)
336 struct connection
*conn
;
339 FOREACH_ELT(connections
, i
, conn
)
350 static const int one
= 1;
351 return ioctlsocket(sock
, FIONBIO
, (const void *)&one
);
357 static const struct linger ling
= { 0, 0 };
358 return setsockopt(s
, SOL_SOCKET
, SO_LINGER
, &ling
, sizeof(ling
));
361 /* Returns -1 or socket fd. */
363 setup_a_tcp_listener(struct socksetup
*data
, struct sockaddr
*addr
)
367 sock
= socket(addr
->sa_family
, SOCK_STREAM
, 0);
369 com_err(data
->prog
, errno
,
370 gettext("Cannot create TCP server socket on %s"),
375 * Solaris Kerberos: noticed that there where bind problems for tcp sockets
376 * if kdc restarted quickly. Setting SO_REUSEADDR allowed binds to succeed.
378 if (setreuseaddr(sock
, 1) < 0) {
379 com_err(data
->prog
, errno
,
380 gettext("enabling SO_REUSEADDR on TCP socket"));
384 if (bind(sock
, addr
, socklen(addr
)) == -1) {
385 com_err(data
->prog
, errno
,
386 gettext("Cannot bind TCP server socket on %s"), paddr(addr
));
390 if (listen(sock
, 5) < 0) {
391 com_err(data
->prog
, errno
,
392 gettext("Cannot listen on TCP server socket on %s"),
398 com_err(data
->prog
, errno
,
399 gettext("cannot set listening tcp socket on %s non-blocking"),
404 if (setnolinger(sock
)) {
405 com_err(data
->prog
, errno
,
406 gettext("disabling SO_LINGER on TCP socket on %s"),
415 setup_tcp_listener_ports(struct socksetup
*data
)
417 struct sockaddr_in sin4
;
418 #ifdef KRB5_USE_INET6
419 struct sockaddr_in6 sin6
;
423 memset(&sin4
, 0, sizeof(sin4
));
424 sin4
.sin_family
= AF_INET
;
426 sin4
.sin_len
= sizeof(sin4
);
428 sin4
.sin_addr
.s_addr
= INADDR_ANY
;
430 #ifdef KRB5_USE_INET6
431 memset(&sin6
, 0, sizeof(sin6
));
432 sin6
.sin6_family
= AF_INET6
;
434 sin6
.sin6_len
= sizeof(sin6
);
436 sin6
.sin6_addr
= in6addr_any
;
439 FOREACH_ELT (tcp_port_data
, i
, port
) {
442 set_sa_port((struct sockaddr
*)&sin4
, htons(port
));
443 if (!ipv6_enabled()) {
444 s4
= setup_a_tcp_listener(data
, (struct sockaddr
*)&sin4
);
449 #ifndef KRB5_USE_INET6
454 set_sa_port((struct sockaddr
*)&sin6
, htons(port
));
456 s6
= setup_a_tcp_listener(data
, (struct sockaddr
*)&sin6
);
460 if (setv6only(s6
, 0))
461 com_err(data
->prog
, errno
,
462 gettext("setsockopt(IPV6_V6ONLY,0) failed"));
465 s4
= setup_a_tcp_listener(data
, (struct sockaddr
*)&sin4
);
466 #endif /* KRB5_USE_INET6 */
469 /* Sockets are created, prepare to listen on them. */
471 FD_SET(s4
, &sstate
.rfds
);
472 if (s4
>= sstate
.max
)
474 if (add_tcp_listener_fd(data
, s4
) == 0)
477 krb5_klog_syslog(LOG_INFO
, "listening on fd %d: tcp %s",
478 s4
, paddr((struct sockaddr
*)&sin4
));
480 #ifdef KRB5_USE_INET6
482 FD_SET(s6
, &sstate
.rfds
);
483 if (s6
>= sstate
.max
)
485 if (add_tcp_listener_fd(data
, s6
) == 0) {
489 krb5_klog_syslog(LOG_INFO
, "listening on fd %d: tcp %s",
490 s6
, paddr((struct sockaddr
*)&sin6
));
492 krb5_klog_syslog(LOG_INFO
,
493 "assuming IPv6 socket accepts IPv4");
501 setup_udp_port(void *P_data
, struct sockaddr
*addr
)
503 struct socksetup
*data
= P_data
;
505 char haddrbuf
[NI_MAXHOST
];
509 err
= getnameinfo(addr
, socklen(addr
), haddrbuf
, sizeof(haddrbuf
),
510 0, 0, NI_NUMERICHOST
);
512 strcpy(haddrbuf
, "<unprintable>");
514 switch (addr
->sa_family
) {
519 #ifdef KRB5_USE_INET6
523 static int first
= 1;
525 krb5_klog_syslog (LOG_INFO
, "skipping local ipv6 addresses");
532 #ifdef AF_LINK /* some BSD systems, AIX */
536 #ifdef AF_DLI /* Direct Link Interface - DEC Ultrix/OSF1 link layer? */
541 krb5_klog_syslog (LOG_INFO
,
542 "skipping unrecognized local address family %d",
547 FOREACH_ELT (udp_port_data
, i
, port
) {
548 sock
= socket (addr
->sa_family
, SOCK_DGRAM
, 0);
550 data
->retval
= errno
;
551 com_err(data
->prog
, data
->retval
,
552 gettext("Cannot create server socket for port %d address %s"),
556 set_sa_port(addr
, htons(port
));
557 if (bind (sock
, (struct sockaddr
*)addr
, socklen (addr
)) == -1) {
558 data
->retval
= errno
;
559 com_err(data
->prog
, data
->retval
,
560 gettext("Cannot bind server socket to port %d address %s"),
564 FD_SET (sock
, &sstate
.rfds
);
565 if (sock
>= sstate
.max
)
566 sstate
.max
= sock
+ 1;
567 krb5_klog_syslog (LOG_INFO
, "listening on fd %d: udp %s", sock
,
568 paddr((struct sockaddr
*)addr
));
569 if (add_udp_fd (data
, sock
) == 0)
576 static void klog_handler(const void *data
, size_t len
)
578 static char buf
[BUFSIZ
];
579 static int bufoffset
;
582 #define flush_buf() \
584 ? (((buf[0] == 0 || buf[0] == '\n') \
585 ? (fork()==0?abort():(void)0) \
587 krb5_klog_syslog(LOG_INFO, "%s", buf), \
588 memset(buf, 0, sizeof(buf)), \
592 p
= memchr(data
, 0, len
);
594 len
= (const char *)p
- (const char *)data
;
598 p
= memchr(data
, '\n', len
);
601 klog_handler(data
, (size_t)((const char *)p
- (const char *)data
));
603 len
-= ((const char *)p
- (const char *)data
) + 1;
604 data
= 1 + (const char *)p
;
605 goto scan_for_newlines
;
606 } else if (len
> sizeof(buf
) - 1 || len
+ bufoffset
> sizeof(buf
) - 1) {
607 size_t x
= sizeof(buf
) - len
- 1;
608 klog_handler(data
, x
);
611 data
= (const char *)data
+ x
;
612 goto scan_for_newlines
;
614 memcpy(buf
+ bufoffset
, data
, len
);
621 extern int krb5int_debug_sendto_kdc
;
622 extern void (*krb5int_sendtokdc_debug_handler
)(const void*, size_t);
625 setup_network(const char *prog
)
627 struct socksetup setup_data
;
628 krb5_error_code retval
;
632 FD_ZERO(&sstate
.rfds
);
633 FD_ZERO(&sstate
.wfds
);
634 FD_ZERO(&sstate
.xfds
);
637 /* krb5int_debug_sendto_kdc = 1; */
638 krb5int_sendtokdc_debug_handler
= klog_handler
;
640 /* Handle each realm's ports */
641 for (i
=0; i
<kdc_numrealms
; i
++) {
642 cp
= kdc_realmlist
[i
]->realm_ports
;
644 if (*cp
== ',' || isspace((int) *cp
)) {
648 port
= strtol(cp
, &cp
, 10);
651 retval
= add_udp_port(port
);
656 cp
= kdc_realmlist
[i
]->realm_tcp_ports
;
658 if (*cp
== ',' || isspace((int) *cp
)) {
662 port
= strtol(cp
, &cp
, 10);
665 retval
= add_tcp_port(port
);
671 setup_data
.prog
= prog
;
672 setup_data
.retval
= 0;
673 krb5_klog_syslog (LOG_INFO
, "setting up network...");
674 /* To do: Use RFC 2292 interface (or follow-on) and IPV6_PKTINFO,
675 so we might need only one UDP socket; fall back to binding
676 sockets on each address only if IPV6_PKTINFO isn't
678 if (foreach_localaddr (&setup_data
, setup_udp_port
, 0, 0)) {
679 return setup_data
.retval
;
681 setup_tcp_listener_ports(&setup_data
);
682 krb5_klog_syslog (LOG_INFO
, "set up %d sockets", n_sockets
);
683 if (n_sockets
== 0) {
684 com_err(prog
, 0, gettext("no sockets set up?"));
691 static void init_addr(krb5_fulladdr
*faddr
, struct sockaddr
*sa
)
693 switch (sa
->sa_family
) {
695 faddr
->address
->addrtype
= ADDRTYPE_INET
;
696 faddr
->address
->length
= IPV4_ADDR_LEN
;
697 faddr
->address
->contents
= (krb5_octet
*) &sa2sin(sa
)->sin_addr
;
698 faddr
->port
= ntohs(sa2sin(sa
)->sin_port
);
700 #ifdef KRB5_USE_INET6
702 if (IN6_IS_ADDR_V4MAPPED(&sa2sin6(sa
)->sin6_addr
)) {
703 faddr
->address
->addrtype
= ADDRTYPE_INET
;
704 faddr
->address
->length
= IPV4_ADDR_LEN
;
705 /* offset to RAM address of ipv4 part of ipv6 address */
706 faddr
->address
->contents
= (IPV6_ADDR_LEN
- IPV4_ADDR_LEN
) +
707 (krb5_octet
*) &sa2sin6(sa
)->sin6_addr
;
709 faddr
->address
->addrtype
= ADDRTYPE_INET6
;
710 faddr
->address
->length
= IPV6_ADDR_LEN
;
711 faddr
->address
->contents
= (krb5_octet
*) &sa2sin6(sa
)->sin6_addr
;
713 faddr
->port
= ntohs(sa2sin6(sa
)->sin6_port
);
717 faddr
->address
->addrtype
= -1;
718 faddr
->address
->length
= 0;
719 faddr
->address
->contents
= 0;
725 static void process_packet(struct connection
*conn
, const char *prog
,
731 krb5_error_code retval
;
732 struct sockaddr_storage saddr
;
736 char pktbuf
[MAX_DGRAM_SIZE
];
737 int port_fd
= conn
->fd
;
740 saddr_len
= sizeof(saddr
);
741 cc
= recvfrom(port_fd
, pktbuf
, sizeof(pktbuf
), 0,
742 (struct sockaddr
*)&saddr
, &saddr_len
);
745 /* This is how Linux indicates that a previous
746 transmission was refused, e.g., if the client timed out
747 before getting the response packet. */
748 && errno
!= ECONNREFUSED
750 com_err(prog
, errno
, gettext("while receiving from network"));
754 return; /* zero-length packet? */
757 request
.data
= pktbuf
;
758 faddr
.address
= &addr
;
759 init_addr(&faddr
, ss2sa(&saddr
));
760 /* this address is in net order */
761 if ((retval
= dispatch(&request
, &faddr
, &response
))) {
762 com_err(prog
, retval
, gettext("while dispatching (udp)"));
765 cc
= sendto(port_fd
, response
->data
, (socklen_t
) response
->length
, 0,
766 (struct sockaddr
*)&saddr
, saddr_len
);
769 krb5_free_data(kdc_context
, response
);
770 if (inet_ntop(((struct sockaddr
*)&saddr
)->sa_family
,
771 addr
.contents
, addrbuf
, sizeof(addrbuf
)) == 0) {
772 strcpy(addrbuf
, "?");
774 com_err(prog
, errno
, gettext("while sending reply to %s/%d"),
775 addrbuf
, faddr
.port
);
778 if (cc
!= response
->length
) {
779 krb5_free_data(kdc_context
, response
);
780 com_err(prog
, 0, gettext("short reply write %d vs %d\n"),
781 response
->length
, cc
);
784 krb5_free_data(kdc_context
, response
);
788 static int tcp_data_counter
;
789 /* Solaris kerberos: getting this value from elsewhere */
790 extern int max_tcp_data_connections
;
792 static void kill_tcp_connection(struct connection
*);
794 static void accept_tcp_connection(struct connection
*conn
, const char *prog
,
798 struct sockaddr_storage addr_s
;
799 struct sockaddr
*addr
= (struct sockaddr
*)&addr_s
;
800 socklen_t addrlen
= sizeof(addr_s
);
801 struct socksetup sockdata
;
802 struct connection
*newconn
;
805 s
= accept(conn
->fd
, addr
, &addrlen
);
808 setnbio(s
), setnolinger(s
);
810 sockdata
.prog
= prog
;
813 newconn
= add_tcp_data_fd(&sockdata
, s
);
817 if (getnameinfo((struct sockaddr
*)&addr_s
, addrlen
,
818 newconn
->u
.tcp
.addrbuf
, sizeof(newconn
->u
.tcp
.addrbuf
),
819 tmpbuf
, sizeof(tmpbuf
),
820 NI_NUMERICHOST
| NI_NUMERICSERV
))
821 strcpy(newconn
->u
.tcp
.addrbuf
, "???");
824 p
= newconn
->u
.tcp
.addrbuf
;
825 end
= p
+ sizeof(newconn
->u
.tcp
.addrbuf
);
827 if (end
- p
> 2 + strlen(tmpbuf
)) {
833 krb5_klog_syslog(LOG_INFO
, "accepted TCP connection on socket %d from %s",
834 s
, newconn
->u
.tcp
.addrbuf
);
837 newconn
->u
.tcp
.addr_s
= addr_s
;
838 newconn
->u
.tcp
.addrlen
= addrlen
;
839 newconn
->u
.tcp
.bufsiz
= 1024 * 1024;
840 newconn
->u
.tcp
.buffer
= malloc(newconn
->u
.tcp
.bufsiz
);
841 newconn
->u
.tcp
.start_time
= time(0);
843 if (++tcp_data_counter
> max_tcp_data_connections
) {
844 struct connection
*oldest_tcp
= NULL
;
845 struct connection
*c
;
848 krb5_klog_syslog(LOG_INFO
, "too many connections");
850 FOREACH_ELT (connections
, i
, c
) {
851 if (c
->type
!= CONN_TCP
)
856 krb5_klog_syslog(LOG_INFO
, "fd %d started at %ld", c
->fd
,
857 c
->u
.tcp
.start_time
);
859 if (oldest_tcp
== NULL
860 || oldest_tcp
->u
.tcp
.start_time
> c
->u
.tcp
.start_time
)
863 if (oldest_tcp
!= NULL
) {
864 krb5_klog_syslog(LOG_INFO
, "dropping tcp fd %d from %s",
865 oldest_tcp
->fd
, oldest_tcp
->u
.tcp
.addrbuf
);
866 kill_tcp_connection(oldest_tcp
);
870 if (newconn
->u
.tcp
.buffer
== 0) {
871 com_err(prog
, errno
, gettext("allocating buffer for new TCP session from %s"),
872 newconn
->u
.tcp
.addrbuf
);
878 newconn
->u
.tcp
.offset
= 0;
879 newconn
->u
.tcp
.faddr
.address
= &newconn
->u
.tcp
.kaddr
;
880 init_addr(&newconn
->u
.tcp
.faddr
, ss2sa(&newconn
->u
.tcp
.addr_s
));
881 SG_SET(&newconn
->u
.tcp
.sgbuf
[0], newconn
->u
.tcp
.lenbuf
, 4);
882 SG_SET(&newconn
->u
.tcp
.sgbuf
[1], 0, 0);
884 FD_SET(s
, &sstate
.rfds
);
890 kill_tcp_connection(struct connection
*conn
)
892 if (conn
->u
.tcp
.response
)
893 krb5_free_data(kdc_context
, conn
->u
.tcp
.response
);
894 free(conn
->u
.tcp
.buffer
);
895 FD_CLR(conn
->fd
, &sstate
.rfds
);
896 FD_CLR(conn
->fd
, &sstate
.wfds
);
897 if (sstate
.max
== conn
->fd
+ 1)
898 while (sstate
.max
> 0
899 && ! FD_ISSET(sstate
.max
-1, &sstate
.rfds
)
900 && ! FD_ISSET(sstate
.max
-1, &sstate
.wfds
)
901 /* && ! FD_ISSET(sstate.max-1, &sstate.xfds) */
910 static krb5_error_code
911 make_toolong_error (krb5_data
**out
)
914 krb5_error_code retval
;
917 retval
= krb5_us_timeofday(kdc_context
, &errpkt
.stime
, &errpkt
.susec
);
920 errpkt
.error
= KRB_ERR_FIELD_TOOLONG
;
921 errpkt
.server
= tgs_server
;
922 errpkt
.client
= NULL
;
925 errpkt
.text
.length
= 0;
926 errpkt
.text
.data
= 0;
927 errpkt
.e_data
.length
= 0;
928 errpkt
.e_data
.data
= 0;
929 scratch
= malloc(sizeof(*scratch
));
932 retval
= krb5_mk_error(kdc_context
, &errpkt
, scratch
);
943 process_tcp_connection(struct connection
*conn
, const char *prog
, int selflags
)
945 if (selflags
& SSF_WRITE
) {
947 SOCKET_WRITEV_TEMP tmp
;
949 nwrote
= SOCKET_WRITEV(conn
->fd
, conn
->u
.tcp
.sgp
, conn
->u
.tcp
.sgnum
,
952 goto kill_tcp_connection
;
956 goto kill_tcp_connection
;
958 sg_buf
*sgp
= conn
->u
.tcp
.sgp
;
959 if (nwrote
< SG_LEN(sgp
)) {
960 SG_ADVANCE(sgp
, nwrote
);
963 nwrote
-= SG_LEN(sgp
);
966 if (conn
->u
.tcp
.sgnum
== 0 && nwrote
!= 0)
970 if (conn
->u
.tcp
.sgnum
== 0) {
971 /* finished sending */
972 /* We should go back to reading, though if we sent a
973 FIELD_TOOLONG error in reply to a length with the high
974 bit set, RFC 4120 says we have to close the TCP
976 goto kill_tcp_connection
;
978 } else if (selflags
& SSF_READ
) {
979 /* Read message length and data into one big buffer, already
980 allocated at connect time. If we have a complete message,
981 we stop reading, so we should only be here if there is no
982 data in the buffer, or only an incomplete message. */
985 if (conn
->u
.tcp
.offset
< 4) {
986 /* msglen has not been computed */
987 /* XXX Doing at least two reads here, letting the kernel
988 worry about buffering. It'll be faster when we add
989 code to manage the buffer here. */
990 len
= 4 - conn
->u
.tcp
.offset
;
991 nread
= SOCKET_READ(conn
->fd
,
992 conn
->u
.tcp
.buffer
+ conn
->u
.tcp
.offset
, len
);
995 goto kill_tcp_connection
;
998 goto kill_tcp_connection
;
999 conn
->u
.tcp
.offset
+= nread
;
1000 if (conn
->u
.tcp
.offset
== 4) {
1001 unsigned char *p
= (unsigned char *)conn
->u
.tcp
.buffer
;
1002 conn
->u
.tcp
.msglen
= ((p
[0] << 24)
1006 if (conn
->u
.tcp
.msglen
> conn
->u
.tcp
.bufsiz
- 4) {
1007 krb5_error_code err
;
1008 /* message too big */
1009 krb5_klog_syslog(LOG_ERR
, "TCP client %s wants %lu bytes, cap is %lu",
1010 conn
->u
.tcp
.addrbuf
, (unsigned long) conn
->u
.tcp
.msglen
,
1011 (unsigned long) conn
->u
.tcp
.bufsiz
- 4);
1012 /* XXX Should return an error. */
1013 err
= make_toolong_error (&conn
->u
.tcp
.response
);
1015 krb5_klog_syslog(LOG_ERR
,
1016 "error constructing KRB_ERR_FIELD_TOOLONG error! %s",
1017 error_message(err
));
1018 goto kill_tcp_connection
;
1026 krb5_error_code err
;
1028 len
= conn
->u
.tcp
.msglen
- (conn
->u
.tcp
.offset
- 4);
1029 nread
= SOCKET_READ(conn
->fd
,
1030 conn
->u
.tcp
.buffer
+ conn
->u
.tcp
.offset
, len
);
1033 goto kill_tcp_connection
;
1036 goto kill_tcp_connection
;
1037 conn
->u
.tcp
.offset
+= nread
;
1038 if (conn
->u
.tcp
.offset
< conn
->u
.tcp
.msglen
+ 4)
1040 /* have a complete message, and exactly one message */
1041 request
.length
= conn
->u
.tcp
.msglen
;
1042 request
.data
= conn
->u
.tcp
.buffer
+ 4;
1043 err
= dispatch(&request
, &conn
->u
.tcp
.faddr
,
1044 &conn
->u
.tcp
.response
);
1046 com_err(prog
, err
, gettext("while dispatching (tcp)"));
1047 goto kill_tcp_connection
;
1050 conn
->u
.tcp
.lenbuf
[0] = 0xff & (conn
->u
.tcp
.response
->length
>> 24);
1051 conn
->u
.tcp
.lenbuf
[1] = 0xff & (conn
->u
.tcp
.response
->length
>> 16);
1052 conn
->u
.tcp
.lenbuf
[2] = 0xff & (conn
->u
.tcp
.response
->length
>> 8);
1053 conn
->u
.tcp
.lenbuf
[3] = 0xff & (conn
->u
.tcp
.response
->length
>> 0);
1054 SG_SET(&conn
->u
.tcp
.sgbuf
[1], conn
->u
.tcp
.response
->data
,
1055 conn
->u
.tcp
.response
->length
);
1056 conn
->u
.tcp
.sgp
= conn
->u
.tcp
.sgbuf
;
1057 conn
->u
.tcp
.sgnum
= 2;
1058 FD_CLR(conn
->fd
, &sstate
.rfds
);
1059 FD_SET(conn
->fd
, &sstate
.wfds
);
1066 kill_tcp_connection
:
1067 kill_tcp_connection(conn
);
1070 static void service_conn(struct connection
*conn
, const char *prog
,
1073 conn
->service(conn
, prog
, selflags
);
1077 listen_and_process(const char *prog
)
1080 /* This struct contains 3 fd_set objects; on some platforms, they
1081 can be rather large. Making this static avoids putting all
1082 that junk on the stack. */
1083 static struct select_state sout
;
1085 krb5_error_code err
;
1087 if (conns
== (struct connection
**) NULL
)
1090 while (!signal_requests_exit
) {
1091 if (signal_requests_hup
) {
1092 krb5_klog_reopen(kdc_context
);
1093 signal_requests_hup
= 0;
1095 sstate
.end_time
.tv_sec
= sstate
.end_time
.tv_usec
= 0;
1096 err
= krb5int_cm_call_select(&sstate
, &sout
, &sret
);
1098 com_err(prog
, err
, gettext("while selecting for network input(1)"));
1103 com_err(prog
, errno
, gettext("while selecting for network input(2)"));
1107 for (i
=0; i
<n_sockets
&& nfound
> 0; i
++) {
1109 if (conns
[i
]->fd
< 0)
1111 if (FD_ISSET(conns
[i
]->fd
, &sout
.rfds
))
1112 sflags
|= SSF_READ
, nfound
--;
1113 if (FD_ISSET(conns
[i
]->fd
, &sout
.wfds
))
1114 sflags
|= SSF_WRITE
, nfound
--;
1116 service_conn(conns
[i
], prog
, sflags
);
1123 closedown_network(const char *prog
)
1126 struct connection
*conn
;
1128 if (conns
== (struct connection
**) NULL
)
1131 FOREACH_ELT (connections
, i
, conn
) {
1133 (void) close(conn
->fd
);
1134 DEL (connections
, i
);
1135 /* There may also be per-connection data in the tcp structure
1136 (tcp.buffer, tcp.response) that we're not freeing here.
1137 That should only happen if we quit with a connection in
1141 FREE_SET_DATA(connections
);
1142 FREE_SET_DATA(udp_port_data
);
1143 FREE_SET_DATA(tcp_port_data
);