discuss@menelaus.mit.edu: [938] in Kerberos-V5-bugs [938] in Kerberos-V5-bugs home help back first fref pref prev next nref lref last post Kerberos 5-B4-pl3 bug report (lib/krb5/os/sendto_kdc.c) patch #2 daemon@ATHENA.MIT.EDU (Craig Leres) Fri Nov 4 01:57:13 1994 To: krb5-bugs@MIT.EDU
Cc: hobbit@asylum.sf.ca.us
Date: Thu, 03 Nov 94 22:57:04 PST
From: Craig Leres
We noticed that retries when doing things like getting an initial
ticket with kinit were broken. It usually took two tries to get a
ticket over an isdn line and it didn't seem to be possible over a slip
line.
The problem was krb5_sendto_kdc() was opening one socket per address
family (!?!?) and trying to do a connect to change the address before
each send(). It may not be obvious from the man page but the kernel
source clearly shows that you fail with EISCONN when you attempt to
connect() an already connected socket. This means that only the first
send() works and all the others are aborted on the connect() attempt.
So if the reply doesn't come back within the initial timeout (1
second), you lose.
I changed the code to open one socket per host socket address (i.e.
host and port) and only do the connect once. My appended context
diff also includes another change I submited:
This source wants to include krb5/sysincl.h to pick the FD_ZERO() and
FD_SET() macros.
Craig
------
*** kerberosV.virgin/src/lib/krb5/os/sendto_kdc.c Thu Aug 18 15:08:02 1994
--- kerberosV/src/lib/krb5/os/sendto_kdc.c Thu Nov 3 22:55:14 1994
***************
*** 28,33 ****
--- 28,34 ----
#include
#include
+ #include
#include
#include
***************
*** 40,50 ****
#include
#endif
- #ifndef AF_MAX
- /* good enough -- only missing on old linux so far anyhow. */
- #define AF_MAX 10
- #endif
-
/*
* send the formatted request 'message' to a KDC for realm 'realm' and
* return the response (if any) in 'reply'.
--- 41,46 ----
***************
*** 76,82 ****
int naddr;
int sent, nready;
krb5_error_code retval;
! int socklist[AF_MAX]; /* one for each, if necessary! */
fd_set readable;
struct timeval waitlen;
int cc;
--- 72,78 ----
int naddr;
int sent, nready;
krb5_error_code retval;
! int *socklist;
fd_set readable;
struct timeval waitlen;
int cc;
***************
*** 89,100 ****
return retval;
if (naddr == 0)
return KRB5_REALM_UNKNOWN;
!
! for (i = 0; i < AF_MAX; i++)
socklist[i] = -1;
if (!(reply->data = malloc(krb5_max_dgram_size))) {
krb5_xfree(addr);
return ENOMEM;
}
reply->length = krb5_max_dgram_size;
--- 85,103 ----
return retval;
if (naddr == 0)
return KRB5_REALM_UNKNOWN;
!
! socklist = (int *)malloc(naddr * sizeof(int));
! if (socklist == NULL) {
! krb5_xfree(addr);
! krb5_xfree(socklist);
! return ENOMEM;
! }
! for (i = 0; i < naddr; i++)
socklist[i] = -1;
if (!(reply->data = malloc(krb5_max_dgram_size))) {
krb5_xfree(addr);
+ krb5_xfree(socklist);
return ENOMEM;
}
reply->length = krb5_max_dgram_size;
***************
*** 109,135 ****
for (host = 0; host < naddr; host++) {
/* send to the host, wait timeout seconds for a response,
then move on. */
! /* cache some sockets for various address families in the
! list */
! if (socklist[addr[host].sa_family] == -1) {
/* XXX 4.2/4.3BSD has PF_xxx = AF_xxx, so the socket
creation here will work properly... */
! socklist[addr[host].sa_family] = socket(addr[host].sa_family,
! SOCK_DGRAM,
! 0); /* XXX always zero? */
! if (socklist[addr[host].sa_family] == -1)
continue; /* try other hosts */
}
! /* have a socket to send/recv from */
! /* On BSD systems, a connected UDP socket will get connection
! refused and net unreachable errors while an unconnected
! socket will time out, so use connect, send, recv instead of
! sendto, recvfrom. The connect here may return an error if
! the destination host is known to be unreachable. */
! if (connect(socklist[addr[host].sa_family],
! &addr[host], sizeof(addr[host])) == -1)
! continue;
! if (send(socklist[addr[host].sa_family],
message->data, message->length, 0) != message->length)
continue;
retry:
--- 112,143 ----
for (host = 0; host < naddr; host++) {
/* send to the host, wait timeout seconds for a response,
then move on. */
! /* cache some sockets for each host */
! if (socklist[host] == -1) {
/* XXX 4.2/4.3BSD has PF_xxx = AF_xxx, so the socket
creation here will work properly... */
! /*
! * From socket(2):
! *
! * The protocol specifies a particular protocol to be
! * used with the socket. Normally only a single
! * protocol exists to support a particular socket type
! * within a given protocol family.
! */
! socklist[host] = socket(addr[host].sa_family, SOCK_DGRAM, 0);
! if (socklist[host] == -1)
continue; /* try other hosts */
+ /* have a socket to send/recv from */
+ /* On BSD systems, a connected UDP socket will get connection
+ refused and net unreachable errors while an unconnected
+ socket will time out, so use connect, send, recv instead of
+ sendto, recvfrom. The connect here may return an error if
+ the destination host is known to be unreachable. */
+ if (connect(socklist[host],
+ &addr[host], sizeof(addr[host])) == -1)
+ continue;
}
! if (send(socklist[host],
message->data, message->length, 0) != message->length)
continue;
retry:
***************
*** 136,143 ****
waitlen.tv_usec = 0;
waitlen.tv_sec = timeout;
FD_ZERO(&readable);
! FD_SET(socklist[addr[host].sa_family], &readable);
! if (nready = select(1 + socklist[addr[host].sa_family],
&readable,
0,
0,
--- 144,151 ----
waitlen.tv_usec = 0;
waitlen.tv_sec = timeout;
FD_ZERO(&readable);
! FD_SET(socklist[host], &readable);
! if (nready = select(1 + socklist[host],
&readable,
0,
0,
***************
*** 148,154 ****
retval = errno;
goto out;
}
! if ((cc = recv(socklist[addr[host].sa_family],
reply->data, reply->length, 0)) == -1)
{
/* man page says error could be:
--- 156,162 ----
retval = errno;
goto out;
}
! if ((cc = recv(socklist[host],
reply->data, reply->length, 0)) == -1)
{
/* man page says error could be:
***************
*** 193,202 ****
}
retval = KRB5_KDC_UNREACH;
out:
! for (i = 0; i < AF_MAX; i++)
if (socklist[i] != -1)
(void) close(socklist[i]);
krb5_xfree(addr);
if (retval) {
free(reply->data);
reply->data = 0;
--- 201,211 ----
}
retval = KRB5_KDC_UNREACH;
out:
! for (i = 0; i < naddr; i++)
if (socklist[i] != -1)
(void) close(socklist[i]);
krb5_xfree(addr);
+ krb5_xfree(socklist);
if (retval) {
free(reply->data);
reply->data = 0;
home help back first fref pref prev next nref lref last post