80c771b
Use a list of disconnected and connected sockets to talk to kpasswd
80c771b
servers, so we automatically try TCP if we fail to change the password
80c771b
UDP, or if the UDP-based server is just slow.
80c771b
80c771b
This patch looks big, but most of it's actually whitespace because
80c771b
most of the logic is no longer called as part of a loop with UDP and
80c771b
TCP being used in different iterations.  RT #5868.
80c771b
80c771b
Index: src/lib/krb5/os/changepw.c
80c771b
===================================================================
80c771b
--- src/lib/krb5/os/changepw.c	(revision 20199)
80c771b
+++ src/lib/krb5/os/changepw.c	(working copy)
80c771b
@@ -199,14 +199,14 @@
80c771b
     krb5_address 		remote_kaddr;
80c771b
     krb5_boolean		useTcp = 0;
80c771b
     GETSOCKNAME_ARG3_TYPE 	addrlen;
80c771b
-    krb5_error_code 		code = 0;
80c771b
+    krb5_error_code 		code = 0, code2 = 0;
80c771b
     char 			*code_string;
80c771b
-    int				local_result_code;
80c771b
+    int				local_result_code, i;
80c771b
     
80c771b
     struct sendto_callback_context  callback_ctx;
80c771b
     struct sendto_callback_info	callback_info;
80c771b
     struct sockaddr_storage	remote_addr;
80c771b
-    struct addrlist 		al = ADDRLIST_INIT;
80c771b
+    struct addrlist 		al = ADDRLIST_INIT, al2 = ADDRLIST_INIT;
80c771b
 
80c771b
     memset( &callback_ctx, 0, sizeof(struct sendto_callback_context));
80c771b
     callback_ctx.context = context;
80c771b
@@ -225,109 +225,104 @@
80c771b
 				     &callback_ctx.ap_req)))
80c771b
 	goto cleanup;
80c771b
 
80c771b
-    do {
80c771b
-	if ((code = krb5_locate_kpasswd(callback_ctx.context,
80c771b
-					krb5_princ_realm(callback_ctx.context,
80c771b
-							 creds->server),
80c771b
-					&al, useTcp)))
80c771b
-	    break;
80c771b
-
80c771b
+    code = krb5_locate_kpasswd(callback_ctx.context,
80c771b
+			       krb5_princ_realm(callback_ctx.context,
80c771b
+						creds->server),
80c771b
+			       &al, useTcp);
80c771b
+    code2 = krb5_locate_kpasswd(callback_ctx.context,
80c771b
+				krb5_princ_realm(callback_ctx.context,
80c771b
+						 creds->server),
80c771b
+				&al2, !useTcp);
80c771b
+    if ((al.naddrs + al2.naddrs) == 0) {
80c771b
+	if (!code)
80c771b
+	    code = code2 ? code2 : KRB5_REALM_CANT_RESOLVE;
80c771b
+	goto cleanup;
80c771b
+    }
80c771b
+
80c771b
+    if (al2.naddrs > 0) {
80c771b
+	if (krb5int_grow_addrlist(&al, al2.naddrs))
80c771b
+	    goto cleanup;
80c771b
+	for (i = 0; i < al2.naddrs; i++)
80c771b
+	    al.addrs[al.naddrs++] = al2.addrs[i];
80c771b
+	al2.naddrs = 0;
80c771b
+    }
80c771b
+
80c771b
-	addrlen = sizeof(remote_addr);
80c771b
-
80c771b
-	callback_info.context = (void*) &callback_ctx;
80c771b
-	callback_info.pfn_callback = kpasswd_sendto_msg_callback;
80c771b
-	callback_info.pfn_cleanup = kpasswd_sendto_msg_cleanup;
80c771b
-
80c771b
-	if ((code = krb5int_sendto(callback_ctx.context, 
80c771b
-				   NULL, 
80c771b
-				   &al, 
80c771b
-				   &callback_info,
80c771b
-				   &chpw_rep,
80c771b
-				   NULL,
80c771b
-				   NULL,
80c771b
-				   ss2sa(&remote_addr),
80c771b
-                                   &addrlen,
80c771b
-				   NULL,
80c771b
-				   NULL,
80c771b
-				   NULL
80c771b
-		 ))) {
80c771b
-
80c771b
-	    /*
80c771b
-	     * Here we may want to switch to TCP on some errors.
80c771b
-	     * right?
80c771b
-	     */
80c771b
-	    break;
80c771b
-	}
80c771b
-
80c771b
+    addrlen = sizeof(remote_addr);
80c771b
+
80c771b
+    callback_info.context = (void*) &callback_ctx;
80c771b
+    callback_info.pfn_callback = kpasswd_sendto_msg_callback;
80c771b
+    callback_info.pfn_cleanup = kpasswd_sendto_msg_cleanup;
80c771b
+
80c771b
+    if ((code = krb5int_sendto(callback_ctx.context, 
80c771b
+			       NULL, 
80c771b
+			       &al, 
80c771b
+			       &callback_info,
80c771b
+			       &chpw_rep,
80c771b
+			       NULL,
80c771b
+			       NULL,
80c771b
+			       ss2sa(&remote_addr),
80c771b
+			       &addrlen,
80c771b
+			       NULL,
80c771b
+			       NULL,
80c771b
+			       NULL
80c771b
+		 )))
80c771b
+	goto cleanup;
80c771b
+
80c771b
-	remote_kaddr.addrtype = ADDRTYPE_INET;
80c771b
-	remote_kaddr.length = sizeof(ss2sin(&remote_addr)->sin_addr);
80c771b
-	remote_kaddr.contents = (krb5_octet *) &ss2sin(&remote_addr)->sin_addr;
80c771b
-
80c771b
-	if ((code = krb5_auth_con_setaddrs(callback_ctx.context,  
80c771b
-					   callback_ctx.auth_context,  
80c771b
-					   NULL, 
80c771b
-					   &remote_kaddr)))
80c771b
-	    break;
80c771b
-
80c771b
+    remote_kaddr.addrtype = ADDRTYPE_INET;
80c771b
+    remote_kaddr.length = sizeof(ss2sin(&remote_addr)->sin_addr);
80c771b
+    remote_kaddr.contents = (krb5_octet *) &ss2sin(&remote_addr)->sin_addr;
80c771b
+
80c771b
+    if ((code = krb5_auth_con_setaddrs(callback_ctx.context,  
80c771b
+				       callback_ctx.auth_context,
80c771b
+				       NULL,
80c771b
+				       &remote_kaddr)))
80c771b
+	goto cleanup;
80c771b
+
80c771b
-	if (set_password_for)
80c771b
-	    code = krb5int_rd_setpw_rep(callback_ctx.context, 
80c771b
-					callback_ctx.auth_context, 
80c771b
-					&chpw_rep, 
80c771b
-					&local_result_code, 
80c771b
-					result_string);
80c771b
-	else
80c771b
-	    code = krb5int_rd_chpw_rep(callback_ctx.context, 
80c771b
-				       callback_ctx.auth_context, 
80c771b
-				       &chpw_rep, 
80c771b
-				       &local_result_code, 
80c771b
-				       result_string);
80c771b
-
80c771b
-	if (code) {
80c771b
-	    if (code == KRB5KRB_ERR_RESPONSE_TOO_BIG && !useTcp ) {
80c771b
-		krb5int_free_addrlist (&al);
80c771b
-		useTcp = 1;
80c771b
-		continue;
80c771b
-	    }
80c771b
-
80c771b
-	    break;
80c771b
-	}
80c771b
-
80c771b
-	if (result_code)
80c771b
-	    *result_code = local_result_code;
80c771b
-	
80c771b
+    if (set_password_for)
80c771b
+	code = krb5int_rd_setpw_rep(callback_ctx.context, 
80c771b
+				    callback_ctx.auth_context, 
80c771b
+				    &chpw_rep, 
80c771b
+				    &local_result_code, 
80c771b
+				    result_string);
80c771b
+    else
80c771b
+	code = krb5int_rd_chpw_rep(callback_ctx.context, 
80c771b
+				   callback_ctx.auth_context, 
80c771b
+				   &chpw_rep, 
80c771b
+				   &local_result_code, 
80c771b
+				   result_string);
80c771b
+
80c771b
+    if (code)
80c771b
+	goto cleanup;
80c771b
+
80c771b
+    if (result_code)
80c771b
+	*result_code = local_result_code;
80c771b
+	
80c771b
-	if (result_code_string) {
80c771b
-	    if (set_password_for)
80c771b
-		code = krb5int_setpw_result_code_string(callback_ctx.context, 
80c771b
-							local_result_code, 
80c771b
-							(const char **)&code_string);
80c771b
-	    else
80c771b
-		code = krb5_chpw_result_code_string(callback_ctx.context, 
80c771b
-						    local_result_code, 
80c771b
-						    &code_string);
80c771b
-	    if(code)
80c771b
-		goto cleanup;
80c771b
-
80c771b
-	    result_code_string->length = strlen(code_string);
80c771b
-	    result_code_string->data = malloc(result_code_string->length);
80c771b
-	    if (result_code_string->data == NULL) {
80c771b
-		code = ENOMEM;
80c771b
-		goto cleanup;
80c771b
-	    }
80c771b
-	    strncpy(result_code_string->data, code_string, result_code_string->length);
80c771b
-	}
80c771b
-
80c771b
-	if (code == KRB5KRB_ERR_RESPONSE_TOO_BIG && !useTcp ) {
80c771b
-	    krb5int_free_addrlist (&al);
80c771b
-	    useTcp = 1;
80c771b
-        } else {
80c771b
-	    break;
80c771b
-	} 
80c771b
-    } while (TRUE);
80c771b
+    if (result_code_string) {
80c771b
+	if (set_password_for)
80c771b
+	    code = krb5int_setpw_result_code_string(callback_ctx.context, 
80c771b
+						    local_result_code, 
80c771b
+						    (const char **) &code_string);
80c771b
+	else
80c771b
+	    code = krb5_chpw_result_code_string(callback_ctx.context, 
80c771b
+						local_result_code, 
80c771b
+						&code_string);
80c771b
+	if (code)
80c771b
+	    goto cleanup;
80c771b
+
80c771b
+	result_code_string->length = strlen(code_string);
80c771b
+	result_code_string->data = malloc(result_code_string->length);
80c771b
+	if (result_code_string->data == NULL) {
80c771b
+	    code = ENOMEM;
80c771b
+	    goto cleanup;
80c771b
+	}
80c771b
+	strncpy(result_code_string->data, code_string, result_code_string->length);
80c771b
+    }
80c771b
 
80c771b
 cleanup:
80c771b
     if (callback_ctx.auth_context != NULL)
80c771b
 	krb5_auth_con_free(callback_ctx.context, callback_ctx.auth_context);
80c771b
 
80c771b
+    krb5int_free_addrlist (&al2;;
80c771b
     krb5int_free_addrlist (&al);
80c771b
     krb5_free_data_contents(callback_ctx.context, &callback_ctx.ap_req);
80c771b