network.c revision 7c478bd95313f5f23a4c958a745db2134aa03244
/*
* Copyright 2004 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
*
* Copyright 1990,2000 by the Massachusetts Institute of Technology.
*
* Export of this software from the United States of America may
* require a specific license from the United States Government.
* It is the responsibility of any person or organization contemplating
* export to obtain such a license before exporting.
*
* WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
* distribute this software and its documentation for any purpose and
* without fee is hereby granted, provided that the above copyright
* notice appear in all copies and that both that copyright notice and
* this permission notice appear in supporting documentation, and that
* the name of M.I.T. not be used in advertising or publicity pertaining
* to distribution of the software without specific, written prior
* permission. Furthermore if you modify this software you must label
* your software as modified software and not distribute it in such a
* fashion that it might be confused with the original M.I.T. software.
* M.I.T. makes no representations about the suitability of
* this software for any purpose. It is provided "as is" without express
* or implied warranty.
*
*
* Network code for Kerberos v5 KDC.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#define NEED_SOCKETS
#include "k5-int.h"
#include "com_err.h"
#include "kdc_util.h"
#include "extern.h"
#include "kdc5_err.h"
#include "adm_proto.h"
#include <syslog.h>
#include <stddef.h>
#include <ctype.h>
#include <port-sockets.h>
/* #include <socket-utils.h> */
#ifdef HAVE_NETINET_IN_H
#ifdef HAVE_SYS_SOCKIO_H
/* for SIOCGIFCONF, etc. */
#endif
#include <libintl.h>
#endif
#ifndef ARPHRD_ETHER /* OpenBSD breaks on multiple inclusions */
#endif
#ifdef HAVE_SYS_FILIO_H
#endif
#include <fake-addrinfo.h>
/* Misc utility routines. */
static void
{
case AF_INET:
break;
#ifdef KRB5_USE_INET6
case AF_INET6:
break;
#endif
default:
break;
}
}
static int
{
#ifdef KRB5_USE_INET6
static int result = -1;
if (result == -1) {
int s;
if (s >= 0) {
result = 1;
close(s);
} else
result = 0;
}
return (result);
#else
return (0);
#endif
}
static int
{
}
#if defined(KRB5_USE_INET6) && defined(IPV6_V6ONLY)
static int
{
}
#endif
{
static char buf[100];
char portbuf[10];
else {
*p++ = '.';
len--;
}
}
return buf;
}
/* KDC data. */
/* Per-connection info. */
struct connection {
int fd;
void (*service)(struct connection *, const char *, int);
/* Solaris Kerberos: for auditing */
union {
/* Type-specific information. */
struct {
int x;
} udp;
struct {
int x;
} tcp_listener;
struct {
/* connection */
struct sockaddr_storage addr_s;
char addrbuf[56];
/* incoming */
char *buffer;
/* outgoing */
unsigned char lenbuf[4];
int sgnum;
/* crude denial-of-service avoidance support */
} tcp;
} u;
};
/* Start at the top and work down -- this should allow for deletions
without disrupting the iteration, since we delete by overwriting
the element to be removed with the last element. */
? 0 /* overflow */ \
: 0))
/* 1 = success, 0 = failure */
: 0)
/* Set<struct connection *> connections; */
#define n_sockets connections.n
/* Set<u_short> udp_port_data, tcp_port_data; */
#include <cm.h>
static struct select_state sstate;
{
int i;
void *tmp;
return EINVAL;
return 0;
return ENOMEM;
return 0;
}
{
int i;
void *tmp;
return EINVAL;
return 0;
return ENOMEM;
return 0;
}
#define USE_TYPE SOCK_DGRAM
#define USE_PROTO 0
#define SOCKET_ERRNO errno
struct socksetup {
const char *prog;
};
static struct connection *
void (*service)(struct connection *, const char *, int))
{
struct connection *newconn;
void *tmp;
if (newconn == 0) {
gettext("cannot allocate storage for connection info"));
return 0;
}
return 0;
}
return newconn;
}
static void process_packet(struct connection *, const char *, int);
static void accept_tcp_connection(struct connection *, const char *, int);
static void process_tcp_connection(struct connection *, const char *, int);
static struct connection *
{
}
static struct connection *
{
}
static struct connection *
{
}
static void
{
struct connection *conn;
int i;
DEL(connections, i);
/* Solaris kerberos: fix memory leak */
return;
}
}
static int
{
static const int one = 1;
}
static int
setnolinger(int s)
{
}
/* Returns -1 or socket fd. */
static int
{
int sock;
if (sock == -1) {
gettext("Cannot create TCP server socket on %s"),
return -1;
}
/*
* Solaris Kerberos: noticed that there where bind problems for tcp sockets
* if kdc restarted quickly. Setting SO_REUSEADDR allowed binds to succeed.
*/
gettext("enabling SO_REUSEADDR on TCP socket"));
return -1;
}
return -1;
}
gettext("Cannot listen on TCP server socket on %s"),
return -1;
}
gettext("cannot set listening tcp socket on %s non-blocking"),
return -1;
}
if (setnolinger(sock)) {
gettext("disabling SO_LINGER on TCP socket on %s"),
return -1;
}
return sock;
}
static int
{
struct sockaddr_in sin4;
#ifdef KRB5_USE_INET6
struct sockaddr_in6 sin6;
#endif
int i, port;
#ifdef HAVE_SA_LEN
#endif
#ifdef KRB5_USE_INET6
#ifdef SIN6_LEN
#endif
#endif
if (!ipv6_enabled()) {
if (s4 < 0)
return -1;
s6 = -1;
} else {
#ifndef KRB5_USE_INET6
abort();
#else
if (s6 < 0)
return -1;
#ifdef IPV6_V6ONLY
gettext("setsockopt(IPV6_V6ONLY,0) failed"));
#endif
#endif /* KRB5_USE_INET6 */
}
/* Sockets are created, prepare to listen on them. */
if (s4 >= 0) {
else
}
#ifdef KRB5_USE_INET6
if (s6 >= 0) {
s6 = -1;
} else
if (s4 < 0)
"assuming IPv6 socket accepts IPv4");
}
#endif
}
return 0;
}
static int
{
int sock = -1, i;
char haddrbuf[NI_MAXHOST];
int err;
0, 0, NI_NUMERICHOST);
if (err)
case AF_INET:
break;
#ifdef AF_INET6
case AF_INET6:
#ifdef KRB5_USE_INET6
break;
#else
{
static int first = 1;
if (first) {
first = 0;
}
return 0;
}
#endif
#endif
#ifdef AF_LINK /* some BSD systems, AIX */
case AF_LINK:
return 0;
#endif
default:
"skipping unrecognized local address family %d",
return 0;
}
if (sock == -1) {
gettext("Cannot create server socket for port %d address %s"),
return 1;
}
gettext("Cannot bind server socket to port %d address %s"),
return 1;
}
return 1;
}
return 0;
}
#if 1
{
static int bufoffset;
void *p;
#define flush_buf() \
(bufoffset \
: (void)0), \
bufoffset = 0) \
: 0)
if (p)
if (len == 0)
return;
if (p) {
if (p != data)
flush_buf();
data = 1 + (const char *)p;
goto scan_for_newlines;
klog_handler(data, x);
flush_buf();
len -= x;
goto scan_for_newlines;
} else {
}
}
#endif
extern void (*krb5int_sendtokdc_debug_handler)(const void*, size_t);
setup_network(const char *prog)
{
struct socksetup setup_data;
char *cp;
int i, port;
/* Handle each realm's ports */
for (i=0; i<kdc_numrealms; i++) {
cp++;
continue;
}
if (cp == 0)
break;
if (retval)
return retval;
}
cp++;
continue;
}
if (cp == 0)
break;
if (retval)
return retval;
}
}
setup_data.retval = 0;
/* To do: Use RFC 2292 interface (or follow-on) and IPV6_PKTINFO,
so we might need only one UDP socket; fall back to binding
sockets on each address only if IPV6_PKTINFO isn't
supported. */
return setup_data.retval;
}
if (n_sockets == 0) {
exit (1);
}
return 0;
}
{
case AF_INET:
break;
#ifdef KRB5_USE_INET6
case AF_INET6:
/* offset to RAM address of ipv4 part of ipv6 address */
} else {
}
break;
#endif
default:
break;
}
}
int selflags)
{
int cc;
struct sockaddr_storage saddr;
char pktbuf[MAX_DGRAM_SIZE];
if (cc == -1) {
/* This is how Linux indicates that a previous
transmission was refused, e.g., if the client timed out
before getting the response packet. */
&& errno != ECONNREFUSED
)
return;
}
if (!cc)
return; /* zero-length packet? */
/* this address is in net order */
return;
}
if (cc == -1) {
char addrbuf[46];
}
return;
}
return;
}
return;
}
static int tcp_data_counter;
/* Solaris kerberos: getting this value from elsewhere */
extern int max_tcp_data_connections;
static void kill_tcp_connection(struct connection *);
int selflags)
{
int s;
struct sockaddr_storage addr_s;
struct connection *newconn;
char tmpbuf[10];
if (s < 0)
return;
setnbio(s), setnolinger(s);
if (newconn == 0)
return;
else {
char *p, *end;
p += strlen(p);
*p++ = '.';
}
}
if (++tcp_data_counter > max_tcp_data_connections) {
struct connection *c;
int i;
FOREACH_ELT (connections, i, c) {
continue;
if (c == newconn)
continue;
#if 0
c->u.tcp.start_time);
#endif
if (oldest_tcp == NULL
oldest_tcp = c;
}
if (oldest_tcp != NULL) {
oldest_tcp = NULL;
}
}
close(s);
return;
}
}
static void
{
/* && ! FD_ISSET(sstate.max-1, &sstate.xfds) */
)
/* Solaris kerberos: fix memory leak */
}
static void
{
tmp);
if (nwrote < 0) {
e = SOCKET_ERRNO;
goto kill_tcp_connection;
}
if (nwrote == 0)
/* eof */
goto kill_tcp_connection;
while (nwrote) {
nwrote = 0;
} else {
abort();
}
}
/* finished sending */
/* should go back to reading */
goto kill_tcp_connection;
}
/* Read message length and data into one big buffer, already
allocated at connect time. If we have a complete message,
we stop reading, so we should only be here if there is no
data in the buffer, or only an incomplete message. */
/* msglen has not been computed */
/* XXX Doing at least two reads here, letting the kernel
worry about buffering. It'll be faster when we add
code to manage the buffer here. */
if (nread < 0)
/* error */
goto kill_tcp_connection;
if (nread == 0)
/* eof */
goto kill_tcp_connection;
| (p[1] << 16)
| (p[2] << 8)
| p[3]);
/* message too big */
/* XXX Should return an error. */
goto kill_tcp_connection;
}
}
} else {
/* msglen known */
if (nread < 0)
/* error */
goto kill_tcp_connection;
if (nread == 0)
/* eof */
goto kill_tcp_connection;
return;
/* have a complete message, and exactly one message */
if (err) {
goto kill_tcp_connection;
}
}
} else
abort();
return;
}
int selflags)
{
}
listen_and_process(const char *prog)
{
int nfound;
struct select_state sout;
int i, sret;
return KDC5_NONET;
while (!signal_requests_exit) {
if (signal_requests_hup) {
signal_requests_hup = 0;
}
if (err) {
continue;
}
if (sret == -1) {
continue;
}
int sflags = 0;
abort();
if (sflags)
}
}
return 0;
}
closedown_network(const char *prog)
{
int i;
struct connection *conn;
return KDC5_NONET;
DEL (connections, i);
}
return 0;
}
#endif /* INET */