From: Ken Raeburn Date: Thu, 26 Apr 2001 03:57:48 +0000 (+0000) Subject: back out changes that shouldn't have been checked in yet X-Git-Tag: krb5-1.3-alpha1~1549 X-Git-Url: http://git.tremily.us/?a=commitdiff_plain;h=940ff1b84565c238e93e0cba20eccf9a03d1fca1;p=krb5.git back out changes that shouldn't have been checked in yet git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@13198 dc483132-0cff-0310-8789-dd5450dbe970 --- diff --git a/src/lib/krb5/os/accessor.c b/src/lib/krb5/os/accessor.c index d3c842a86..d0d0dc21d 100644 --- a/src/lib/krb5/os/accessor.c +++ b/src/lib/krb5/os/accessor.c @@ -37,7 +37,6 @@ krb5int_accessor(internals, version) if (version == KRB5INT_ACCESS_VERSION) { krb5int_access internals_temp; - internals_temp.krb5_locate_server = krb5int_locate_server; internals_temp.krb5_locate_kdc = krb5_locate_kdc; internals_temp.krb5_max_skdc_timeout = krb5_max_skdc_timeout; internals_temp.krb5_skdc_timeout_shift = krb5_skdc_timeout_shift; diff --git a/src/lib/krb5/os/changepw.c b/src/lib/krb5/os/changepw.c index 1eefe6d98..61cfea01f 100644 --- a/src/lib/krb5/os/changepw.c +++ b/src/lib/krb5/os/changepw.c @@ -8,7 +8,7 @@ * 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 @@ -22,7 +22,7 @@ * 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. - * + * */ #define NEED_SOCKETS @@ -49,21 +49,6 @@ #endif #endif /* _WIN32 && !__CYGWIN32__ */ -/* There's a lot of confusion between pointers to different sockaddr - types, and pointers with different degrees of indirection. Use - this function in this file to ensure we don't do something silly - like cast a "sockaddr **" to a "sockaddr_in *". */ -static struct sockaddr_in *sa2sin (struct sockaddr *sa) -{ - return (struct sockaddr_in *) sa; -} -#ifdef KRB5_USE_INET6xxNotUsed -static struct sockaddr_in6 *sa2sin6 (struct sockaddr *sa) -{ - return (struct sockaddr_in6 *) sa; -} -#endif - /* * Wrapper function for the two backends */ @@ -72,30 +57,54 @@ static krb5_error_code krb5_locate_kpasswd(context, realm, addr_pp, naddrs) krb5_context context; const krb5_data *realm; - struct sockaddr ***addr_pp; + struct sockaddr **addr_pp; int *naddrs; { krb5_error_code code; + int i; - code = krb5int_locate_server (context, realm, addr_pp, naddrs, 0, - "kpasswd_server", "_kpasswd", 0, - DEFAULT_KPASSWD_PORT, 0); + /* + * We always try the local file first + */ + + code = krb5_locate_srv_conf(context, realm, "kpasswd_server", + addr_pp, naddrs, 0); if (code) { - code = krb5int_locate_server (context, realm, addr_pp, naddrs, 0, - "admin_server", "_kerberos-adm", 1, - DEFAULT_KPASSWD_PORT, 0); - if (!code) { - /* Success with admin_server but now we need to change the - port number to use DEFAULT_KPASSWD_PORT. */ - int i; - for ( i=0;i<*naddrs;i++ ) { - struct sockaddr *a = (*addr_pp)[i]; - if (a->sa_family == AF_INET) - sa2sin (a)->sin_port = htons(DEFAULT_KPASSWD_PORT); - } - } + code = krb5_locate_srv_conf(context, realm, "admin_server", + addr_pp, naddrs, 0); + if ( !code ) { + /* success with admin_server but now we need to change the port */ + /* number to use DEFAULT_KPASSWD_PORT. */ + for ( i=0;i<*naddrs;i++ ) { + struct sockaddr_in *sockin = (struct sockaddr_in *) addr_pp[i]; + sockin->sin_port = htons(DEFAULT_KPASSWD_PORT); + } + } } +#ifdef KRB5_DNS_LOOKUP + if (code) { + int use_dns = _krb5_use_dns_kdc(context); + if ( use_dns ) { + code = krb5_locate_srv_dns(realm, "_kpasswd", "_udp", + addr_pp, naddrs); + if ( code ) { + code = krb5_locate_srv_dns(realm, + "_kerberos-adm", + "_tcp", + addr_pp, naddrs); + if ( !code ) { + /* success with admin_server but now we need to change the port */ + /* number to use DEFAULT_KPASSWD_PORT. */ + for ( i=0;i<*naddrs;i++ ) { + struct sockaddr_in *sockin = (struct sockaddr_in *) addr_pp[i]; + sockin->sin_port = htons(DEFAULT_KPASSWD_PORT); + } + } + } + } + } +#endif /* KRB5_DNS_LOOKUP */ return (code); } @@ -116,7 +125,7 @@ krb5_change_password(context, creds, newpw, result_code, char *code_string; krb5_error_code code = 0; int i, addrlen; - struct sockaddr **addr_p, local_addr, remote_addr, tmp_addr; + struct sockaddr *addr_p, local_addr, remote_addr, tmp_addr; int naddr_p; int cc, local_result_code, tmp_len; SOCKET s1 = INVALID_SOCKET, s2 = INVALID_SOCKET; @@ -128,18 +137,18 @@ krb5_change_password(context, creds, newpw, result_code, memset(&chpw_req, 0, sizeof(krb5_data)); memset(&chpw_rep, 0, sizeof(krb5_data)); memset(&ap_req, 0, sizeof(krb5_data)); - + /* initialize auth_context so that we know we have to free it */ if ((code = krb5_auth_con_init(context, &auth_context))) goto cleanup; - - if ((code = krb5_mk_req_extended(context, &auth_context, + + if ((code = krb5_mk_req_extended(context, &auth_context, AP_OPTS_USE_SUBKEY, NULL, creds, &ap_req))) goto cleanup; - if ((code = krb5_locate_kpasswd(context, - krb5_princ_realm(context, creds->client), + if ((code = krb5_locate_kpasswd(context, + krb5_princ_realm(context, creds->client), &addr_p, &naddr_p))) goto cleanup; @@ -147,7 +156,7 @@ krb5_change_password(context, creds, newpw, result_code, is left unconnected in case the server is multihomed and routes are asymmetric. s2 is connected to resolve routes and get addresses. this is the *only* way to get proper addresses for - multihomed hosts if routing is asymmetric. + multihomed hosts if routing is asymmetric. A related problem in the server, but not the client, is that many os's have no way to disconnect a connected udp socket, so @@ -159,207 +168,212 @@ krb5_change_password(context, creds, newpw, result_code, hostname resolution to get the local ip addr) will work and interoperate if the client is single-homed. */ - if ((s1 = socket(AF_INET, SOCK_DGRAM, 0)) == INVALID_SOCKET) { - code = SOCKET_ERRNO; - goto cleanup; - } - - if ((s2 = socket(AF_INET, SOCK_DGRAM, 0)) == INVALID_SOCKET) { - code = SOCKET_ERRNO; - goto cleanup; - } - - for (i=0; isa_family != AF_INET) - continue; - - if (connect(s2, addr_p[i], sizeof(addr_p[i])) == SOCKET_ERROR) { - if (SOCKET_ERRNO == ECONNREFUSED || SOCKET_ERRNO == EHOSTUNREACH) - continue; /* try the next addr */ - - code = SOCKET_ERRNO; - goto cleanup; - } - - addrlen = sizeof(local_addr); - - if (getsockname(s2, &local_addr, &addrlen) < 0) { - if (SOCKET_ERRNO == ECONNREFUSED || SOCKET_ERRNO == EHOSTUNREACH) - continue; /* try the next addr */ - + if ((s1 = socket(AF_INET, SOCK_DGRAM, 0)) == INVALID_SOCKET) + { code = SOCKET_ERRNO; goto cleanup; - } - - /* some brain-dead OS's don't return useful information from - * the getsockname call. Namely, windows and solaris. */ - - if (sa2sin(&local_addr)->sin_addr.s_addr != 0) { - local_kaddr.addrtype = ADDRTYPE_INET; - local_kaddr.length = sizeof(sa2sin(&local_addr)->sin_addr); - local_kaddr.contents = (krb5_octet *) &sa2sin(&local_addr)->sin_addr; - } else { - krb5_address **addrs; - - krb5_os_localaddr(context, &addrs); - - local_kaddr.magic = addrs[0]->magic; - local_kaddr.addrtype = addrs[0]->addrtype; - local_kaddr.length = addrs[0]->length; - local_kaddr.contents = malloc(addrs[0]->length); - memcpy(local_kaddr.contents, addrs[0]->contents, addrs[0]->length); - - krb5_free_addresses(context, addrs); - } - - addrlen = sizeof(remote_addr); - if (getpeername(s2, &remote_addr, &addrlen) < 0) { - if (SOCKET_ERRNO == ECONNREFUSED || SOCKET_ERRNO == EHOSTUNREACH) - continue; /* try the next addr */ + } + if ((s2 = socket(AF_INET, SOCK_DGRAM, 0)) == INVALID_SOCKET) + { code = SOCKET_ERRNO; goto cleanup; - } - - remote_kaddr.addrtype = ADDRTYPE_INET; - remote_kaddr.length = sizeof(sa2sin(&remote_addr)->sin_addr); - remote_kaddr.contents = (krb5_octet *) &sa2sin(&remote_addr)->sin_addr; - - /* mk_priv requires that the local address be set. - getsockname is used for this. rd_priv requires that the - remote address be set. recvfrom is used for this. If - rd_priv is given a local address, and the message has the - recipient addr in it, this will be checked. However, there - is simply no way to know ahead of time what address the - message will be delivered *to*. Therefore, it is important - that either no recipient address is in the messages when - mk_priv is called, or that no local address is passed to - rd_priv. Both is a better idea, and I have done that. In - summary, when mk_priv is called, *only* a local address is - specified. when rd_priv is called, *only* a remote address - is specified. Are we having fun yet? */ - - if ((code = krb5_auth_con_setaddrs(context, auth_context, - &local_kaddr, NULL))) { - code = SOCKET_ERRNO; - goto cleanup; - } - - if ((code = krb5_mk_chpw_req(context, auth_context, &ap_req, - newpw, &chpw_req))) - { - code = SOCKET_ERRNO; - goto cleanup; - } - - if ((cc = sendto(s1, chpw_req.data, (int) chpw_req.length, 0, - addr_p[i], sizeof(addr_p[i]))) != chpw_req.length) - { - if ((cc < 0) && ((SOCKET_ERRNO == ECONNREFUSED) || - (SOCKET_ERRNO == EHOSTUNREACH))) - continue; /* try the next addr */ - - code = (cc < 0) ? SOCKET_ERRNO : ECONNABORTED; - goto cleanup; - } - - chpw_rep.length = 1500; - chpw_rep.data = (char *) malloc(chpw_rep.length); - - /* XXX need a timeout/retry loop here */ - FD_ZERO (&fdset); - FD_SET (s1, &fdset); - timeout.tv_sec = 120; - timeout.tv_usec = 0; - switch (select (s1 + 1, &fdset, 0, 0, &timeout)) { - case -1: - code = SOCKET_ERRNO; - goto cleanup; - case 0: - code = ETIMEDOUT; - goto cleanup; - default: - /* fall through */ - ; - } - - /* "recv" would be good enough here... except that Windows/NT - commits the atrocity of returning -1 to indicate failure, - but leaving errno set to 0. - - "recvfrom(...,NULL,NULL)" would seem to be a good enough - alternative, and it works on NT, but it doesn't work on - SunOS 4.1.4 or Irix 5.3. Thus we must actually accept the - value and discard it. */ - tmp_len = sizeof(tmp_addr); - if ((cc = recvfrom(s1, chpw_rep.data, (int) chpw_rep.length, - 0, &tmp_addr, &tmp_len)) < 0) - { - code = SOCKET_ERRNO; - goto cleanup; - } - - closesocket(s1); - s1 = INVALID_SOCKET; - closesocket(s2); - s2 = INVALID_SOCKET; - - chpw_rep.length = cc; - - if ((code = krb5_auth_con_setaddrs(context, auth_context, - NULL, &remote_kaddr))) - goto cleanup; - - if ((code = krb5_rd_chpw_rep(context, auth_context, &chpw_rep, - &local_result_code, - result_string))) - goto cleanup; - - if (result_code) - *result_code = local_result_code; + } + + for (i=0; isin_addr.s_addr != 0) + { + local_kaddr.addrtype = ADDRTYPE_INET; + local_kaddr.length = sizeof(((struct sockaddr_in *) &local_addr)->sin_addr); + local_kaddr.contents = (krb5_octet *) &(((struct sockaddr_in *) &local_addr)->sin_addr); + } + else + { + krb5_address **addrs; + + krb5_os_localaddr(context, &addrs); + + local_kaddr.magic = addrs[0]->magic; + local_kaddr.addrtype = addrs[0]->addrtype; + local_kaddr.length = addrs[0]->length; + local_kaddr.contents = malloc(addrs[0]->length); + memcpy(local_kaddr.contents, addrs[0]->contents, addrs[0]->length); + + krb5_free_addresses(context, addrs); + } + + addrlen = sizeof(remote_addr); + if (getpeername(s2, &remote_addr, &addrlen) < 0) + { + if ((SOCKET_ERRNO == ECONNREFUSED) || (SOCKET_ERRNO == EHOSTUNREACH)) + continue; /* try the next addr */ + + code = SOCKET_ERRNO; + goto cleanup; + } + + remote_kaddr.addrtype = ADDRTYPE_INET; + remote_kaddr.length = sizeof(((struct sockaddr_in *) &remote_addr)->sin_addr); + remote_kaddr.contents = (krb5_octet *) &(((struct sockaddr_in *) &remote_addr)->sin_addr); + + /* mk_priv requires that the local address be set. + getsockname is used for this. rd_priv requires that the + remote address be set. recvfrom is used for this. If + rd_priv is given a local address, and the message has the + recipient addr in it, this will be checked. However, there + is simply no way to know ahead of time what address the + message will be delivered *to*. Therefore, it is important + that either no recipient address is in the messages when + mk_priv is called, or that no local address is passed to + rd_priv. Both is a better idea, and I have done that. In + summary, when mk_priv is called, *only* a local address is + specified. when rd_priv is called, *only* a remote address + is specified. Are we having fun yet? */ + + if ((code = krb5_auth_con_setaddrs(context, auth_context, + &local_kaddr, NULL))) + { + code = SOCKET_ERRNO; + goto cleanup; + } + + if ((code = krb5_mk_chpw_req(context, auth_context, &ap_req, + newpw, &chpw_req))) + { + code = SOCKET_ERRNO; + goto cleanup; + } + + if ((cc = sendto(s1, chpw_req.data, (int) chpw_req.length, 0, + (struct sockaddr *) &addr_p[i], + sizeof(addr_p[i]))) != chpw_req.length) + { + if ((cc < 0) && ((SOCKET_ERRNO == ECONNREFUSED) || + (SOCKET_ERRNO == EHOSTUNREACH))) + continue; /* try the next addr */ + + code = (cc < 0) ? SOCKET_ERRNO : ECONNABORTED; + goto cleanup; + } + + chpw_rep.length = 1500; + chpw_rep.data = (char *) malloc(chpw_rep.length); + + /* XXX need a timeout/retry loop here */ + FD_ZERO (&fdset); + FD_SET (s1, &fdset); + timeout.tv_sec = 120; + timeout.tv_usec = 0; + switch (select (s1 + 1, &fdset, 0, 0, &timeout)) { + case -1: + code = SOCKET_ERRNO; + goto cleanup; + case 0: + code = ETIMEDOUT; + goto cleanup; + default: + /* fall through */ + ; + } + + /* "recv" would be good enough here... except that Windows/NT + commits the atrocity of returning -1 to indicate failure, + but leaving errno set to 0. + + "recvfrom(...,NULL,NULL)" would seem to be a good enough + alternative, and it works on NT, but it doesn't work on + SunOS 4.1.4 or Irix 5.3. Thus we must actually accept the + value and discard it. */ + tmp_len = sizeof(tmp_addr); + if ((cc = recvfrom(s1, chpw_rep.data, (int) chpw_rep.length, + 0, &tmp_addr, &tmp_len)) < 0) + { + code = SOCKET_ERRNO; + goto cleanup; + } + + closesocket(s1); + s1 = INVALID_SOCKET; + closesocket(s2); + s2 = INVALID_SOCKET; + + chpw_rep.length = cc; + + if ((code = krb5_auth_con_setaddrs(context, auth_context, + NULL, &remote_kaddr))) + goto cleanup; + + if ((code = krb5_rd_chpw_rep(context, auth_context, &chpw_rep, + &local_result_code, + result_string))) + goto cleanup; + + if (result_code) + *result_code = local_result_code; + + if (result_code_string) + { + if ((code = krb5_chpw_result_code_string(context, + local_result_code, + &code_string))) + goto cleanup; + + result_code_string->length = strlen(code_string); + if ((result_code_string->data = + (char *) malloc(result_code_string->length)) == NULL) + return(ENOMEM); + strncpy(result_code_string->data, code_string, result_code_string->length); + } + + code = 0; goto cleanup; - - result_code_string->length = strlen(code_string); - if ((result_code_string->data = - (char *) malloc(result_code_string->length)) == NULL) - return(ENOMEM); - strncpy(result_code_string->data, code_string, result_code_string->length); - } - - code = 0; - goto cleanup; - } + } code = SOCKET_ERRNO; - + cleanup: - if (auth_context != NULL) - krb5_auth_con_free(context, auth_context); - - if (addr_p != NULL) { - for (i = 0; i < naddr_p; i++) - krb5_xfree (addr_p[i]); - krb5_xfree(addr_p); - } - - if (s1 != INVALID_SOCKET) - closesocket(s1); - - if (s2 != INVALID_SOCKET) - closesocket(s2); - + if(auth_context != NULL) + krb5_auth_con_free(context, auth_context); + + if(addr_p != NULL) + krb5_xfree(addr_p); + + if(s1 != INVALID_SOCKET) + closesocket(s1); + + if(s2 != INVALID_SOCKET) + closesocket(s2); + krb5_free_data_contents(context, &chpw_req); krb5_free_data_contents(context, &chpw_rep); - krb5_free_data_contents(context, &ap_req); - + krb5_free_data_contents(context, &ap_req); + return(code); } diff --git a/src/lib/krb5/os/locate_kdc.c b/src/lib/krb5/os/locate_kdc.c index 808f868fc..48a014770 100644 --- a/src/lib/krb5/os/locate_kdc.c +++ b/src/lib/krb5/os/locate_kdc.c @@ -1,7 +1,7 @@ /* * lib/krb5/os/locate_kdc.c * - * Copyright 1990,2000,2001 by the Massachusetts Institute of Technology. + * Copyright 1990 by the Massachusetts Institute of Technology. * All Rights Reserved. * * Export of this software from the United States of America may @@ -50,6 +50,9 @@ #endif #define MAX_DNS_NAMELEN (15*(MAXHOSTNAMELEN + 1)+1) +#ifndef KPASSWD_PORTNAME +#define KPASSWD_PORTNAME "kpasswd" +#endif #if KRB5_DNS_LOOKUP_KDC #define DEFAULT_LOOKUP_KDC 1 @@ -104,286 +107,32 @@ _krb5_use_dns_realm(context) #endif /* KRB5_DNS_LOOKUP */ -static int get_port (const char *service, int stream, int defalt) -{ -#ifdef HAVE_GETADDRINFO - struct addrinfo hints = { 0 }; - struct addrinfo *ai; - int err; - - hints.ai_family = PF_INET; - hints.ai_socktype = stream ? SOCK_STREAM : SOCK_DGRAM; - err = getaddrinfo (NULL, service, &hints, &ai); - if (err == 0 && ai != 0) { - if (ai->ai_addr->sa_family == AF_INET) { - int port = ((struct sockaddr_in *)ai->ai_addr)->sin_port; - freeaddrinfo (ai); - return port; - } - freeaddrinfo (ai); - } - /* Any error - don't complain, just use default. */ - return htons (defalt); -#else - struct servent *sp; - sp = getservbyname (service, stream ? "tcp" : "udp"); /* NOT THREAD SAFE */ - if (sp) - return sp->s_port; - return htons (defalt); -#endif -} - -struct addrlist { - struct sockaddr **addrs; - int naddrs; - int space; -}; -#define ADDRLIST_INIT { 0, 0, 0 } - -static int -grow_list (struct addrlist *lp, int nmore) -{ - int i; - int newspace = lp->space + nmore; - size_t newsize = newspace * sizeof (struct addrlist); - struct sockaddr **newaddrs; - - newaddrs = realloc (lp->addrs, newsize); - - if (newaddrs == NULL) - return errno; - for (i = lp->space; i < newspace; i++) - newaddrs[i] = NULL; - lp->addrs = newaddrs; - lp->space = newspace; - return 0; -} - -static void -free_list (struct addrlist *lp) -{ - int i; - for (i = 0; i < lp->naddrs; i++) - free (lp->addrs[i]); - free (lp->addrs); - lp->addrs = NULL; - lp->naddrs = lp->space = 0; -} - -static int -add_sockaddr_to_list (struct addrlist *lp, const struct sockaddr *addr, - size_t len) -{ - struct sockaddr *copy; - -#ifdef TEST - fprintf (stderr, "\tadding sockaddr family %2d", addr->sa_family); - if (addr->sa_family == AF_INET) - fprintf (stderr, "\t%s", - inet_ntoa (((const struct sockaddr_in *)addr)->sin_addr)); - fprintf (stderr, "\n"); -#endif - - if (lp->naddrs == lp->space) { - int err = grow_list (lp, 1); - if (err) - return err; - } - copy = malloc (len); - if (copy == NULL) - return errno; - memcpy (copy, addr, len); - lp->addrs[lp->naddrs++] = copy; - return 0; -} - -#ifdef HAVE_GETADDRINFO -static int translate_ai_error (int err) -{ - switch (err) { - case 0: - return 0; - case EAI_ADDRFAMILY: - case EAI_BADFLAGS: - case EAI_FAMILY: - case EAI_SOCKTYPE: - case EAI_SERVICE: - /* All of these indicate bad inputs to getaddrinfo. */ - return EINVAL; - case EAI_AGAIN: - /* Translate to standard errno code. */ - return EAGAIN; - case EAI_MEMORY: - /* Translate to standard errno code. */ - return ENOMEM; - case EAI_NODATA: - case EAI_NONAME: - /* Name not known or no address data, but no error. Do - nothing more. */ - return 0; - case EAI_SYSTEM: - /* System error, duh. */ - return errno; - default: - /* An error code we haven't handled? */ - return EINVAL; - } -} - -static int add_addrinfo_to_list (struct addrlist *lp, struct addrinfo *a) -{ - return add_sockaddr_to_list (lp, a->ai_addr, a->ai_addrlen); -} - -static void set_port_num (struct sockaddr *addr, int num) -{ - switch (addr->sa_family) { - case AF_INET: - ((struct sockaddr_in *)addr)->sin_port = num; - break; - case AF_INET6: - ((struct sockaddr_in6 *)addr)->sin6_port = num; - break; - } -} -#endif - -/* There's also gethostbyname_r, which is IPv4-only but thread-safe; - it wants the caller to supply scratch space and a hostent - structure. Let's go for IPv6 support before thread safety, though; - it's easier to accomplish, and will probably be finished first - anyways. */ -#if !defined (HAVE_GETADDRINFO) && !defined (HAVE_GETIPNODEBYNAME) -#undef getipnodebyname -#define freehostent(X) ((void)(X)) -#ifdef HAVE_GETHOSTBYNAME2 -#define getipnodebyname(NAME,AF,FLAGS,ERRP) (gethostbyname2(NAME,AF)) -#else -#define getipnodebyname(NAME,AF,FLAGS,ERRP) ((AF)==AF_INET?gethostbyname(NAME):(struct hostent *)0) -#endif -#endif - -static int -add_host_to_list (struct addrlist *lp, const char *hostname, - int port, int secport) -{ -#ifdef HAVE_GETADDRINFO - int err; - struct addrinfo *addrs, *a; - -#ifdef TEST - fprintf (stderr, "adding hostname %s, ports %d,%d\n", hostname, - ntohs (port), ntohs (secport)); -#endif - - err = getaddrinfo (hostname, NULL, NULL, &addrs); - if (err) - return translate_ai_error (err); - for (a = addrs; a; a = a->ai_next) { - set_port_num (a->ai_addr, port); - err = add_addrinfo_to_list (lp, a); - if (err) - break; - - if (secport == 0) - continue; - - set_port_num (a->ai_addr, secport); - err = add_addrinfo_to_list (lp, a); - if (err) - break; - } - freeaddrinfo (addrs); - return err; -#else - int err; - struct hostent *hp; - int i; - -#ifdef TEST - fprintf (stderr, "adding hostname %s, ports %d,%d\n", hostname, port, secport); -#endif - - hp = getipnodebyname (hostname, AF_INET, 0, &err); - if (hp != NULL) { - for (i = 0; hp->h_addr_list[i] != 0; i++) { - struct sockaddr_in sin4; - - memset (&sin4, 0, sizeof (sin4)); - memcpy (&sin4.sin_addr, hp->h_addr_list[i], - sizeof (sin4.sin_addr)); - sin4.sin_family = AF_INET; - sin4.sin_port = port; - err = add_sockaddr_to_list (lp, (struct sockaddr *) &sin4, - sizeof (sin4)); - if (err) - break; - if (secport != 0) { - sin4.sin_port = secport; - err = add_sockaddr_to_list (lp, (struct sockaddr *) &sin4, - sizeof (sin4)); - } - - if (err) - break; - } - freehostent (hp); - } -#if defined (KRB5_USE_INET6) - hp = getipnodebyname (hostname, AF_INET6, 0, &err); /* NOT THREAD SAFE */ - if (hp != NULL) { - for (i = 0; hp->h_addr_list[i] != 0; i++) { - struct sockaddr_in6 sin6; - - memset (&sin6, 0, sizeof (sin6)); - memcpy (&sin6.sin6_addr, hp->h_addr_list[i], - sizeof (sin6.sin6_addr)); - sin6.sin6_family = AF_INET6; - sin6.sin6_port = port; - err = add_sockaddr_to_list (lp, (struct sockaddr *) &sin6, - sizeof (sin6)); - if (err) - break; - if (secport != 0) { - sin6.sin6_port = secport; - err = add_sockaddr_to_list (lp, (struct sockaddr *) &sin6, - sizeof (sin6)); - if (err) - break; - } - } - freehostent (hp); - } -#endif - return 0; -#endif -} - /* * returns count of number of addresses found * if master is non-NULL, it is filled in with the index of * the master kdc */ -static krb5_error_code -krb5_locate_srv_conf_1(context, realm, name, addrlist, get_masters, - udpport, sec_udpport) +krb5_error_code +krb5_locate_srv_conf(context, realm, name, addr_pp, naddrs, get_masters) krb5_context context; const krb5_data *realm; const char * name; - struct addrlist *addrlist; + struct sockaddr **addr_pp; + int *naddrs; int get_masters; - int udpport, sec_udpport; { const char *realm_srv_names[4]; char **masterlist, **hostlist, *host, *port, *cp; krb5_error_code code; - int i, j, count, ismaster; - -#ifdef TEST - fprintf (stderr, - "looking in krb5.conf for realm %s entry %s; ports %d,%d\n", - realm->data, name, ntohs (udpport), ntohs (sec_udpport)); + int i, j, out, count, ismaster; + struct sockaddr *addr_p; + struct sockaddr_in *sin_p; + struct hostent *hp; + struct servent *sp; +#ifdef HAVE_NETINET_IN_H + u_short udpport; + u_short sec_udpport; #endif if ((host = malloc(realm->length + 1)) == NULL) @@ -409,6 +158,27 @@ krb5_locate_srv_conf_1(context, realm, name, addrlist, get_masters, return code; } +#ifdef HAVE_NETINET_IN_H + if ( !strcmp(name,"kpasswd_server") ) { + if ((sp = getservbyname(KPASSWD_PORTNAME, "udp"))) + udpport = sp->s_port; + else + udpport = htons(DEFAULT_KPASSWD_PORT); + sec_udpport = 0; + } else { + if ((sp = getservbyname(KDC_PORTNAME, "udp"))) + udpport = sp->s_port; + else + udpport = htons(KRB5_DEFAULT_PORT); + if ((sp = getservbyname(KDC_SECONDARY_PORTNAME, "udp"))) + sec_udpport = sp->s_port; + else + sec_udpport = htons(KRB5_DEFAULT_SEC_PORT); + } +#endif + if (sec_udpport == udpport) + sec_udpport = 0; + count = 0; while (hostlist && hostlist[count]) count++; @@ -416,7 +186,7 @@ krb5_locate_srv_conf_1(context, realm, name, addrlist, get_masters, if (count == 0) { profile_free_list(hostlist); krb5_xfree(host); - addrlist->naddrs = 0; + *naddrs = 0; return 0; } @@ -462,9 +232,16 @@ krb5_locate_srv_conf_1(context, realm, name, addrlist, get_masters, count = count * 2; #endif - for (i=0; hostlist[i]; i++) { - int p1, p2; + addr_p = (struct sockaddr *)malloc (sizeof (struct sockaddr) * count); + if (addr_p == NULL) { + if (hostlist) + profile_free_list(hostlist); + if (masterlist) + profile_free_list(masterlist); + return ENOMEM; + } + for (i=0, out=0; hostlist[i]; i++) { host = hostlist[i]; /* * Strip off excess whitespace @@ -481,6 +258,10 @@ krb5_locate_srv_conf_1(context, realm, name, addrlist, get_masters, port++; } + if ((hp = gethostbyname(hostlist[i])) == 0) { + continue; + } + ismaster = 0; if (masterlist) { for (j=0; masterlist[j]; j++) { @@ -490,37 +271,44 @@ krb5_locate_srv_conf_1(context, realm, name, addrlist, get_masters, } } - if (get_masters && !ismaster) - continue; + if ( !get_masters || ismaster ) { + switch (hp->h_addrtype) { - if (port) { - unsigned long l; -#ifdef HAVE_STROUL - char *endptr; - l = strtoul (port, &endptr, 10); - if (endptr == NULL || *endptr != 0) - return EINVAL; -#else - l = atoi (port); +#ifdef HAVE_NETINET_IN_H + case AF_INET: + for (j=0; hp->h_addr_list[j]; j++) { + sin_p = (struct sockaddr_in *) &addr_p[out++]; + memset ((char *)sin_p, 0, sizeof(struct sockaddr)); + sin_p->sin_family = hp->h_addrtype; + sin_p->sin_port = port ? htons(atoi(port)) : udpport; + memcpy((char *)&sin_p->sin_addr, + (char *)hp->h_addr_list[j], + sizeof(struct in_addr)); + if (out+1 >= count) { + count += 5; + addr_p = (struct sockaddr *) + realloc ((char *)addr_p, + sizeof(struct sockaddr) * count); + if (addr_p == NULL) { + if ( hostlist ) + profile_free_list(hostlist); + if ( masterlist ) + profile_free_list(masterlist); + return ENOMEM; + } + } + if (sec_udpport && !port) { + addr_p[out] = addr_p[out-1]; + sin_p = (struct sockaddr_in *) &addr_p[out++]; + sin_p->sin_port = sec_udpport; + } + } + break; #endif - /* L is unsigned, don't need to check <0. */ - if (l > 65535) - return EINVAL; - p1 = htons (l); - p2 = 0; - } else { - p1 = udpport; - p2 = sec_udpport; - } - - code = add_host_to_list (addrlist, hostlist[i], p1, p2); - if (code) { - if (hostlist) - profile_free_list (hostlist); - if (masterlist) - profile_free_list (masterlist); - return code; - } + default: + break; + } + } } if (hostlist) @@ -528,56 +316,40 @@ krb5_locate_srv_conf_1(context, realm, name, addrlist, get_masters, if (masterlist) profile_free_list(masterlist); - return 0; -} - -static krb5_error_code -krb5_locate_srv_conf(context, realm, name, addr_pp, naddrs, get_masters, - udpport, sec_udpport) - krb5_context context; - const krb5_data *realm; - const char * name; - struct sockaddr ***addr_pp; - int *naddrs; - int get_masters; - int udpport, sec_udpport; -{ - krb5_error_code ret; - struct addrlist al = ADDRLIST_INIT; - - ret = krb5_locate_srv_conf_1 (context, realm, name, &al, - get_masters, udpport, sec_udpport); - if (ret) { - free_list (&al); - return ret; + if (out == 0) { /* Couldn't resolve any KDC names */ + free (addr_p); + return KRB5_REALM_CANT_RESOLVE; } - if (al.naddrs == 0) /* Couldn't resolve any KDC names */ - return KRB5_REALM_CANT_RESOLVE; - *addr_pp = al.addrs; - *naddrs = al.naddrs; + + *addr_pp = addr_p; + *naddrs = out; return 0; } - #ifdef KRB5_DNS_LOOKUP /* * Lookup a KDC via DNS SRV records */ -static krb5_error_code -krb5_locate_srv_dns_1 (realm, service, protocol, addrlist) +krb5_error_code +krb5_locate_srv_dns(realm, service, protocol, addr_pp, naddrs) const krb5_data *realm; const char *service; const char *protocol; - struct addrlist *addrlist; + struct sockaddr **addr_pp; + int *naddrs; { + int out, j, count; union { unsigned char bytes[2048]; HEADER hdr; } answer; unsigned char *p=NULL; char host[MAX_DNS_NAMELEN], *h; + struct sockaddr *addr = NULL; + struct sockaddr_in *sin_p = NULL; + struct hostent *hp = NULL; int type, class; int priority, weight, size, len, numanswers, numqueries, rdlen; unsigned short port; @@ -592,7 +364,13 @@ krb5_locate_srv_dns_1 (realm, service, protocol, addrlist) struct srv_dns_entry *head = NULL; struct srv_dns_entry *srv = NULL, *entry = NULL; - krb5_error_code code = 0; + + out = 0; + addr = (struct sockaddr *) malloc(sizeof(struct sockaddr)); + if (addr == NULL) + return ENOMEM; + + count = 1; /* * First off, build a query of the form: @@ -612,22 +390,19 @@ krb5_locate_srv_dns_1 (realm, service, protocol, addrlist) realm->data); /* Realm names don't (normally) end with ".", but if the query - doesn't end with "." and doesn't get an answer as is, the - resolv code will try appending the local domain. Since the - realm names are absolutes, let's stop that. + doesn't end with "." and doesn't get an answer as is, the + resolv code will try appending the local domain. Since the + realm names are absolutes, let's stop that. - But only if a name has been specified. If we are performing - a search on the prefix alone then the intention is to allow - the local domain or domain search lists to be expanded. */ + But only if a name has been specified. If we are performing + a search on the prefix alone then the intention is to allow + the local domain or domain search lists to be expanded. + */ h = host + strlen (host); if ((h > host) && (h[-1] != '.') && ((h - host + 1) < sizeof(host))) strcpy (h, "."); -#ifdef TEST - fprintf (stderr, "sending DNS SRV query for %s\n", host); -#endif - size = res_search(host, C_IN, T_SRV, answer.bytes, sizeof(answer.bytes)); if (size < hdrsize) @@ -771,20 +546,36 @@ krb5_locate_srv_dns_1 (realm, service, protocol, addrlist) if (head == NULL) goto out; -#ifdef TEST - fprintf (stderr, "walking answer list:\n"); -#endif for (entry = head; entry != NULL; entry = entry->next) { -#ifdef TEST - fprintf (stderr, "\tport=%d host=%s\n", entry->port, entry->host); -#endif - code = add_host_to_list (addrlist, entry->host, htons (entry->port), 0); - if (code) - break; + hp = gethostbyname(entry->host); + if (hp != 0) { + switch (hp->h_addrtype) { +#ifdef HAVE_NETINET_IN_H + case AF_INET: + for (j=0; hp->h_addr_list[j]; j++) { + sin_p = (struct sockaddr_in *) &addr[out++]; + memset ((char *) sin_p, 0, sizeof (struct sockaddr)); + sin_p->sin_family = hp->h_addrtype; + sin_p->sin_port = htons(entry->port); + memcpy((char *) &sin_p->sin_addr, + (char *) hp->h_addr_list[j], + sizeof(struct in_addr)); + if (out + 1 >= count) { + count += 5; + addr = (struct sockaddr *) + realloc((char *) addr, + sizeof(struct sockaddr) * count); + if (!addr) + goto out; + } + } + break; +#endif /* HAVE_NETINET_IN_H */ + default: + break; + } + } } -#ifdef TEST - fprintf (stderr, "[end]\n"); -#endif for (entry = head; entry != NULL; ) { free(entry->host); @@ -799,22 +590,15 @@ krb5_locate_srv_dns_1 (realm, service, protocol, addrlist) if (srv) free(srv); - return code; -} - -static krb5_error_code -krb5_locate_srv_dns(realm, service, protocol, addr_pp, naddrs) - const krb5_data *realm; - const char *service; - const char *protocol; - struct sockaddr ***addr_pp; - int *naddrs; -{ - struct addrlist al = ADDRLIST_INIT; - krb5_error_code code; + if (out == 0) { /* No good servers */ + if (addr) + free(addr); + return KRB5_REALM_CANT_RESOLVE; + } - code = krb5_locate_srv_dns_1 (realm, service, protocol, &al); - return code; + *addr_pp = addr; + *naddrs = out; + return 0; } #endif /* KRB5_DNS_LOOKUP */ @@ -823,63 +607,56 @@ krb5_locate_srv_dns(realm, service, protocol, addr_pp, naddrs) */ krb5_error_code -krb5int_locate_server (krb5_context context, const krb5_data *realm, - struct sockaddr ***addr_pp, int *naddrs, - int get_masters, - const char *profname, const char *dnsname, - int is_stream, - /* network order port numbers! */ - int dflport1, int dflport2) +krb5_locate_kdc(context, realm, addr_pp, naddrs, get_masters) + krb5_context context; + const krb5_data *realm; + struct sockaddr **addr_pp; + int *naddrs; + int get_masters; { krb5_error_code code; - struct addrlist al = ADDRLIST_INIT; /* * We always try the local file first */ - code = krb5_locate_srv_conf(context, realm, profname, &al, get_masters); + code = krb5_locate_srv_conf(context, realm, "kdc", addr_pp, naddrs, + get_masters); #ifdef KRB5_DNS_LOOKUP if (code) { - int use_dns = _krb5_use_dns_kdc(context); - if (use_dns) - code = krb5_locate_srv_dns(realm, dnsname, - is_stream ? "_tcp" : "_udp", &al); + int use_dns = _krb5_use_dns_kdc(context); + if ( use_dns ) { + code = krb5_locate_srv_dns(realm, + get_masters ? "_kerberos-master" : "_kerberos", + "_udp", addr_pp, naddrs); + } } #endif /* KRB5_DNS_LOOKUP */ - if (al.naddrs == 0) { /* No good servers */ - return KRB5_REALM_CANT_RESOLVE; - } - if (code == 0) { - *addr_pp = al.addrs; - *naddrs = al.naddrs; - } - return code; + return (code); } +#if 0 /* Why is this useful? It's not used now, and it's certainly + not useful if you don't have the DNS code enabled. -KR */ + +/* + * It turns out that it is really useful to be able to use these functions + * for other things (like admin servers), so create an abstract function + * for this + */ + krb5_error_code -krb5_locate_kdc(context, realm, addr_pp, naddrs, get_masters) - krb5_context context; +krb5_locate_server(realm, name, proto, addr_pp, naddrs) const krb5_data *realm; - struct sockaddr ***addr_pp; + const char *name, *proto; + struct sockaddr **addr_pp; int *naddrs; - int get_masters; { - int udpport, sec_udpport; - - udpport = get_port (KDC_PORTNAME, 0, KRB5_DEFAULT_PORT); - sec_udpport = get_port (KDC_SECONDARY_PORTNAME, 0, - (udpport == htons (KRB5_DEFAULT_PORT) - ? KRB5_DEFAULT_SEC_PORT - : KRB5_DEFAULT_PORT)); - if (sec_udpport == udpport) - sec_udpport = 0; - - return krb5int_locate_server (context, realm, addr_pp, naddrs, get_masters, - "kdc", - (get_masters - ? "_kerberos-master" - : "_kerberos"), - 0, udpport, sec_udpport); + krb5_error_code code = KRB5_REALM_UNKNOWN; +#ifdef KRB5_DNS_LOOKUP + code = krb5_locate_srv_dns(realm, name, proto, + (struct sockaddr **) addr_pp, naddrs); +#endif /* KRB5_DNS_LOOKUP */ + return (code); } +#endif diff --git a/src/lib/krb5/os/os-proto.h b/src/lib/krb5/os/os-proto.h index ceba9b477..12e2afb48 100644 --- a/src/lib/krb5/os/os-proto.h +++ b/src/lib/krb5/os/os-proto.h @@ -34,7 +34,7 @@ krb5_error_code krb5_locate_kdc PROTOTYPE((krb5_context, const krb5_data *, - struct sockaddr ***, + struct sockaddr **, int *, int)); #endif diff --git a/src/lib/krb5/os/sendto_kdc.c b/src/lib/krb5/os/sendto_kdc.c index 86665b412..58c97f837 100644 --- a/src/lib/krb5/os/sendto_kdc.c +++ b/src/lib/krb5/os/sendto_kdc.c @@ -63,7 +63,7 @@ krb5_sendto_kdc (context, message, realm, reply, use_master) int use_master; { register int timeout, host, i; - struct sockaddr **addr; + struct sockaddr *addr; int naddr; int sent, nready; krb5_error_code retval; @@ -90,8 +90,6 @@ krb5_sendto_kdc (context, message, realm, reply, use_master) socklist[i] = INVALID_SOCKET; if (!(reply->data = malloc(krb5_max_dgram_size))) { - for (i = 0; i < naddr; i++) - krb5_xfree (addr[i]); krb5_xfree(addr); krb5_xfree(socklist); return ENOMEM; @@ -135,7 +133,7 @@ krb5_sendto_kdc (context, message, realm, reply, use_master) * protocol exists to support a particular socket type * within a given protocol family. */ - socklist[host] = socket(addr[host]->sa_family, SOCK_DGRAM, 0); + socklist[host] = socket(addr[host].sa_family, SOCK_DGRAM, 0); if (socklist[host] == INVALID_SOCKET) continue; /* try other hosts */ /* have a socket to send/recv from */ @@ -145,7 +143,7 @@ krb5_sendto_kdc (context, message, realm, reply, use_master) 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])) == SOCKET_ERROR) + &addr[host], sizeof(addr[host])) == SOCKET_ERROR) continue; } if (send(socklist[host],