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