diff --git a/kdc/hprop.c b/kdc/hprop.c index 46666ee6d..91e8994d6 100644 --- a/kdc/hprop.c +++ b/kdc/hprop.c @@ -62,52 +62,41 @@ static int kaspecials_flag; static int open_socket(krb5_context context, const char *hostname) { - struct hostent *hp = NULL; + struct addrinfo *ai, *a; + struct addrinfo hints; int error; - int af; - char **h; - int port; + char portstr[NI_MAXSERV]; -#ifdef HAVE_IPV6 - if (hp == NULL) - hp = getipnodebyname (hostname, AF_INET6, 0, &error); -#endif - if (hp == NULL) - hp = getipnodebyname (hostname, AF_INET, 0, &error); + memset (&hints, 0, sizeof(hints)); + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = IPPROTO_TCP; - if(hp == NULL){ - warnx("%s: %s", hostname, hstrerror(error)); + snprintf (portstr, sizeof(portstr), + "%u", + ntohs(krb5_getportbyname (context, "hprop", "tcp", HPROP_PORT))); + + error = getaddrinfo (hostname, portstr, &hints, &ai); + if (error) { + warnx ("%s: %s", hostname, gai_strerror(error)); return -1; } - - port = krb5_getportbyname (context, "hprop", "tcp", HPROP_PORT); - - af = hp->h_addrtype; - - for (h = hp->h_addr_list; *h != NULL; ++h) { + + for (a = ai; a != NULL; a = a->ai_next) { int s; - struct sockaddr_storage sa_ss; - struct sockaddr *sa = (struct sockaddr *)&sa_ss; - s = socket(af, SOCK_STREAM, 0); - if(s < 0){ - warn("socket"); - freehostent (hp); - return -1; - } - - sa->sa_family = af; - socket_set_address_and_port (sa, *h, port); - - if (connect (s, sa, socket_sockaddr_size(sa)) < 0) { + s = socket (a->ai_family, a->ai_socktype, a->ai_protocol); + if (s < 0) + continue; + if (connect (s, a->ai_addr, a->ai_addrlen) < 0) { warn ("connect(%s)", hostname); close (s); continue; } - freehostent (hp); + freeaddrinfo (ai); return s; } - freehostent (hp); + warnx ("failed to contact %s", hostname); + freeaddrinfo (ai); return -1; } diff --git a/lib/kadm5/init_c.c b/lib/kadm5/init_c.c index 558ae04b2..69a4869fa 100644 --- a/lib/kadm5/init_c.c +++ b/lib/kadm5/init_c.c @@ -273,26 +273,6 @@ get_cred_cache(krb5_context context, return ret; } -static kadm5_ret_t -open_socket(struct hostent *hp, short port, int *sock) -{ - struct sockaddr_in sin; - int s; - s = socket(AF_INET, SOCK_STREAM, 0); - if(s < 0) - return KADM5_FAILURE; - memset(&sin, 0, sizeof(sin)); - sin.sin_family = AF_INET; - sin.sin_port = port; - memcpy(&sin.sin_addr, hp->h_addr, hp->h_length); - if(connect(s, (struct sockaddr*)&sin, sizeof(sin)) < 0){ - close(s); - return KADM5_RPC_ERROR; - } - *sock = s; - return 0; -} - static kadm5_ret_t kadm5_c_init_with_context(krb5_context context, const char *client_name, @@ -311,28 +291,55 @@ kadm5_c_init_with_context(krb5_context context, krb5_principal server; krb5_ccache cc; int s; - struct hostent *hp; + struct addrinfo *ai, *a; + struct addrinfo hints; + int error; + char portstr[NI_MAXSERV]; + + memset (&hints, 0, sizeof(hints)); + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = IPPROTO_TCP; + + snprintf (portstr, sizeof(portstr), "%u", ctx->kadmind_port); ret = _kadm5_c_init_context(&ctx, realm_params, context); if(ret) return ret; - hp = gethostbyname(ctx->admin_server); - if(hp == NULL) + + error = getaddrinfo (ctx->admin_server, portstr, + &hints, &ai); + if (error) return KADM5_BAD_SERVER_NAME; - ret = open_socket(hp, ctx->kadmind_port, &s); - if(ret) - return ret; + for (a = ai; a != NULL; a = a->ai_next) { + int s; + s = socket (a->ai_family, a->ai_socktype, a->ai_protocol); + if (s < 0) + continue; + if (connect (s, a->ai_addr, a->ai_addrlen) < 0) { + warn ("connect(%s)", ctx->admin_server); + close (s); + continue; + } + break; + } + if (a == NULL) { + freeaddrinfo (ai); + warnx ("failed to contact %s", ctx->admin_server); + return KADM5_FAILURE; + } ret = get_cred_cache(context, client_name, service_name, password, prompter, keytab, ccache, &cc); if(ret) { + freeaddrinfo (ai); close(s); return ret; } ret = krb5_parse_name(context, KADM5_ADMIN_SERVICE, &server); if(ret) { + freeaddrinfo (ai); if(ccache == NULL) krb5_cc_close(context, cc); close(s); @@ -360,14 +367,24 @@ kadm5_c_init_with_context(krb5_context context, krb5_data_free(&enc_data); } else if(ret == KRB5_SENDAUTH_BADAPPLVERS) { close(s); - ret = open_socket(hp, ctx->kadmind_port, &s); - if(ret) - return ret; + + s = socket (a->ai_family, a->ai_socktype, a->ai_protocol); + if (s < 0) { + freeaddrinfo (ai); + return errno; + } + if (connect (s, a->ai_addr, a->ai_addrlen) < 0) { + freeaddrinfo (ai); + return errno; + } + freeaddrinfo (ai); + ret = krb5_sendauth(context, &ctx->ac, &s, KADMIN_OLD_APPL_VERSION, NULL, server, AP_OPTS_MUTUAL_REQUIRED, NULL, NULL, cc, NULL, NULL, NULL); } + freeaddrinfo (ai); if(ret) { close(s); return ret; diff --git a/lib/krb5/changepw.c b/lib/krb5/changepw.c index c869a5392..934f3411c 100644 --- a/lib/krb5/changepw.c +++ b/lib/krb5/changepw.c @@ -38,14 +38,16 @@ RCSID("$Id$"); static krb5_error_code get_kdc_address (krb5_context context, krb5_realm realm, - struct sockaddr *sa, - int *sa_size) + struct addrinfo **ai) { + struct addrinfo hints; krb5_error_code ret; - struct hostent *hostent; char **hostlist; + int port = 0; + char portstr[NI_MAXSERV]; + int error; + char *host; char *dot; - char *p; ret = krb5_get_krb_admin_hst (context, &realm, @@ -53,33 +55,26 @@ get_kdc_address (krb5_context context, if (ret) return ret; - p = *hostlist; + host = *hostlist; - dot = strchr (p, ':'); - if (dot) - *dot = '\0'; + dot = strchr (host, ':'); + if (dot != NULL) { + char *end; -#ifdef HAVE_GETHOSTBYNAME2 -#ifdef HAVE_IPV6 - hostent = gethostbyname2 (p, AF_INET6); - if (hostent == NULL) -#endif - hostent = gethostbyname2 (p, AF_INET); -#else - hostent = roken_gethostbyname (p); -#endif + *dot++ = '\0'; + port = strtol (dot, &end, 0); + } + if (port == 0) + port = krb5_getportbyname (context, "kpasswd", "udp", KPASSWD_PORT); + snprintf (portstr, sizeof(portstr), "%u", ntohs(port)); + + memset (&hints, 0, sizeof(hints)); + hints.ai_socktype = SOCK_DGRAM; + hints.ai_protocol = IPPROTO_UDP; + + error = getaddrinfo (host, portstr, &hints, ai); krb5_free_krbhst (context, hostlist); - if (hostent == NULL) - return h_errno; /* XXX */ - - return krb5_h_addr2sockaddr (hostent->h_addrtype, - hostent->h_addr_list[0], - sa, - sa_size, - krb5_getportbyname (context, - "kpasswd", - "udp", - KPASSWD_PORT)); + return error; } static krb5_error_code @@ -284,6 +279,8 @@ krb5_change_password (krb5_context context, krb5_auth_context auth_context = NULL; int sock; int i; + struct addrinfo *ai, *a; + struct sockaddr_storage __ss; struct sockaddr *sa = (struct sockaddr *)&__ss; int sa_size = sizeof(__ss); @@ -292,55 +289,60 @@ krb5_change_password (krb5_context context, if (ret) return ret; - ret = get_kdc_address (context, creds->client->realm, sa, &sa_size); + ret = get_kdc_address (context, creds->client->realm, &ai); if (ret) goto out; - sock = socket (sa->sa_family, SOCK_DGRAM, 0); - if (sock < 0) { - ret = errno; - goto out; - } - krb5_auth_con_setflags (context, auth_context, KRB5_AUTH_CONTEXT_DO_SEQUENCE); - for (i = 0; i < 5; ++i) { - fd_set fdset; - struct timeval tv; + for (a = ai; a != NULL; a = a->ai_next) { + sock = socket (a->ai_family, a->ai_socktype, a->ai_protocol); + if (sock < 0) + continue; - ret = send_request (context, - &auth_context, - creds, - sock, - sa, - sa_size, - newpw); - if (ret) - goto out; + for (i = 0; i < 5; ++i) { + fd_set fdset; + struct timeval tv; - FD_ZERO(&fdset); - FD_SET(sock, &fdset); - tv.tv_usec = 0; - tv.tv_sec = 1 << i; + ret = send_request (context, + &auth_context, + creds, + sock, + sa, + sa_size, + newpw); + if (ret) + goto out; - ret = select (sock + 1, &fdset, NULL, NULL, &tv); - if (ret < 0 && errno != EINTR) - goto out; - if (ret == 1) + FD_ZERO(&fdset); + FD_SET(sock, &fdset); + tv.tv_usec = 0; + tv.tv_sec = 1 << i; + + ret = select (sock + 1, &fdset, NULL, NULL, &tv); + if (ret < 0 && errno != EINTR) + goto out; + if (ret == 1) + break; + } + if (i == 5) { + ret = KRB5_KDC_UNREACH; + close (sock); + continue; + } + + ret = process_reply (context, + auth_context, + sock, + result_code, + result_code_string, + result_string); + close (sock); + if (ret == 0) break; } - if (i == 5) { - ret = KRB5_KDC_UNREACH; - goto out; - } - - ret = process_reply (context, - auth_context, - sock, - result_code, - result_code_string, - result_string); + freeaddrinfo (ai); out: krb5_auth_con_free (context, auth_context);