* XNS support is untested, but "Should just work".
*/
-
#define NEED_SOCKETS
#include "k5-int.h"
-#ifndef _MSDOS
+#if !defined(HAVE_MACSOCK_H) && !defined(_MSDOS) && !defined(_WIN32)
/* needed for solaris, harmless elsewhere... */
#define BSD_COMP
* type; you have to ask for one with a valid type.
*
*/
-#ifdef KRB5_USE_INET
+#ifdef HAVE_NETINET_IN_H
#include <netinet/in.h>
* Add more address families here.
*/
+/*
+ * BSD 4.4 defines the size of an ifreq to be
+ * max(sizeof(ifreq), sizeof(ifreq.ifr_name)+ifreq.ifr_addr.sa_len
+ * However, under earlier systems, sa_len isn't present, so the size is
+ * just sizeof(struct ifreq)
+ */
+#ifdef HAVE_SA_LEN
+#ifndef max
+#define max(a,b) ((a) > (b) ? (a) : (b))
+#endif
+#define ifreq_size(i) max(sizeof(struct ifreq),\
+ sizeof((i).ifr_name)+(i).ifr_addr.sa_len)
+#else
+#define ifreq_size(i) sizeof(struct ifreq)
+#endif /* HAVE_SA_LEN*/
+
+
+
extern int errno;
/*
* This uses the SIOCGIFCONF, SIOCGIFFLAGS, and SIOCGIFADDR ioctl's.
*/
-krb5_error_code INTERFACE
-krb5_os_localaddr(addr)
- krb5_address ***addr;
+KRB5_DLLIMP krb5_error_code KRB5_CALLCONV
+krb5_os_localaddr(context, addr)
+ krb5_context context;
+ krb5_address FAR * FAR * FAR *addr;
{
- struct ifreq *ifr;
+ struct ifreq *ifr, ifreq;
struct ifconf ifc;
int s, code, n, i;
char buf[1024];
int n_found;
int mem_err = 0;
+ memset(buf, 0, sizeof(buf));
ifc.ifc_len = sizeof(buf);
ifc.ifc_buf = buf;
-
+
s = socket (USE_AF, USE_TYPE, USE_PROTO);
if (s < 0)
- return errno;
+ return SOCKET_ERRNO;
code = ioctl (s, SIOCGIFCONF, (char *)&ifc);
if (code < 0) {
int retval = errno;
- close(s);
+ closesocket (s);
return retval;
}
- n = ifc.ifc_len / sizeof (struct ifreq);
+ n = ifc.ifc_len;
- for (n_found=0, i=0; i<n && ! mem_err; i++) {
+n_found = 0;
+ for (i = 0; i < n; i+= ifreq_size(*ifr) ) {
krb5_address *address;
- ifr = &ifc.ifc_req[i];
-
- if (ioctl (s, SIOCGIFFLAGS, (char *)ifr) < 0)
+ ifr = (struct ifreq *)((caddr_t) ifc.ifc_buf+i);
+
+ strncpy(ifreq.ifr_name, ifr->ifr_name, sizeof (ifreq.ifr_name));
+ if (ioctl (s, SIOCGIFFLAGS, (char *)&ifreq) < 0)
continue;
#ifdef IFF_LOOPBACK
- if (ifr->ifr_flags & IFF_LOOPBACK)
+ if (ifreq.ifr_flags & IFF_LOOPBACK)
continue;
#endif
- if (!(ifr->ifr_flags & IFF_UP))
+ if (!(ifreq.ifr_flags & IFF_UP))
/* interface is down; skip */
continue;
- if (ioctl (s, SIOCGIFADDR, (char *)ifr) < 0)
- /* can't get address */
- continue;
-
/* ifr->ifr_addr has what we want! */
switch (ifr->ifr_addr.sa_family) {
-#ifdef KRB5_USE_INET
+#ifdef HAVE_NETINET_IN_H
case AF_INET:
{
struct sockaddr_in *in =
address = (krb5_address *)
malloc (sizeof(krb5_address));
if (address) {
+ address->magic = KV5M_ADDRESS;
address->addrtype = ADDRTYPE_INET;
address->length = sizeof(struct in_addr);
address->contents = (unsigned char *)malloc(address->length);
case AF_XNS:
{
struct sockaddr_ns *ns =
- (struct sockaddr_ns *)&ifr->ifr_addr;
+ (struct sockaddr_ns *)&ifr->ifr_addr;
address = (krb5_address *)
malloc (sizeof (krb5_address) + sizeof (struct ns_addr));
if (address) {
+ address->magic = KV5M_ADDRESS;
address->addrtype = ADDRTYPE_XNS;
/* XXX should we perhaps use ns_host instead? */
addr_temp[n_found++] = address;
address = 0;
}
- close(s);
+ closesocket(s);
*addr = (krb5_address **)malloc (sizeof (krb5_address *) * (n_found+1));
if (*addr == 0)
return 0;
}
-#else /* DOS version */
+#else /* Windows/Mac version */
+
+/*
+ * Hold on to your lunch! Backup kludge method of obtaining your
+ * local IP address, courtesy of Windows Socket Network Programming,
+ * by Robert Quinn
+ */
+#if defined(_MSDOS) || defined(_WIN32)
+static struct hostent *local_addr_fallback_kludge()
+{
+ static struct hostent host;
+ static SOCKADDR_IN addr;
+ static char * ip_ptrs[2];
+ SOCKET sock;
+ int size = sizeof(SOCKADDR);
+ int err;
+
+ sock = socket(AF_INET, SOCK_DGRAM, 0);
+ if (sock == INVALID_SOCKET)
+ return NULL;
+
+ /* connect to arbitrary port and address (NOT loopback) */
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons(IPPORT_ECHO);
+ addr.sin_addr.s_addr = inet_addr("204.137.220.51");
+
+ err = connect(sock, (LPSOCKADDR) &addr, sizeof(SOCKADDR));
+ if (err == SOCKET_ERROR)
+ return NULL;
+
+ err = getsockname(sock, (LPSOCKADDR) &addr, (int FAR *) size);
+ if (err == SOCKET_ERROR)
+ return NULL;
+
+ closesocket(sock);
+
+ host.h_name = 0;
+ host.h_aliases = 0;
+ host.h_addrtype = AF_INET;
+ host.h_length = 4;
+ host.h_addr_list = ip_ptrs;
+ ip_ptrs[0] = (char *) &addr.sin_addr.s_addr;
+ ip_ptrs[1] = NULL;
+
+ return &host;
+}
+#endif
/* No ioctls in winsock so we just assume there is only one networking
* card per machine, so gethostent is good enough.
*/
-
-krb5_error_code INTERFACE
-krb5_os_localaddr (krb5_address ***addr) {
+KRB5_DLLIMP krb5_error_code KRB5_CALLCONV
+krb5_os_localaddr (krb5_context context, krb5_address ***addr) {
char host[64]; /* Name of local machine */
struct hostent *hostrec;
int err;
if (*addr == NULL)
return ENOMEM;
+ err = 0;
+
if (gethostname (host, sizeof(host))) {
- err = WSAGetLastError();
- return err;
+ err = SOCKET_ERRNO;
+ }
+
+ if (!err) {
+ hostrec = gethostbyname (host);
+ if (hostrec == NULL) {
+ err = SOCKET_ERRNO;
+ }
}
-
- hostrec = gethostbyname (host);
- if (hostrec == NULL) {
- err = WSAGetLastError();
- return err;
+ if (err) {
+ hostrec = local_addr_fallback_kludge();
+ if (!hostrec)
+ return err;
}
(*addr)[0] = calloc (1, sizeof(krb5_address));
free (*addr);
return ENOMEM;
}
- (*addr)[0]->addrtype = ADDRTYPE_INET;
- (*addr)[0]->length = sizeof(struct in_addr);
+ (*addr)[0]->magic = KV5M_ADDRESS;
+ (*addr)[0]->addrtype = hostrec->h_addrtype;
+ (*addr)[0]->length = hostrec->h_length;
(*addr)[0]->contents = (unsigned char *)malloc((*addr)[0]->length);
if (!(*addr)[0]->contents) {
free((*addr)[0]);
free(*addr);
return ENOMEM;
} else {
- memcpy ((char *)(*addr)[0]->contents,
- (char *)hostrec->h_addr,
+ memcpy ((*addr)[0]->contents,
+ hostrec->h_addr,
(*addr)[0]->length);
}
+ /* FIXME, deal with the case where gethostent returns multiple addrs */
return(0);
}
#endif
+