Blob Blame History Raw
Use a list of disconnected and connected sockets to talk to kpasswd
servers, so we automatically try TCP if we fail to change the password
UDP, or if the UDP-based server is just slow.

This patch looks big, but most of it's actually whitespace because
most of the logic is no longer called as part of a loop with UDP and
TCP being used in different iterations.  RT #5868.

Index: src/lib/krb5/os/changepw.c
===================================================================
--- src/lib/krb5/os/changepw.c	(revision 20199)
+++ src/lib/krb5/os/changepw.c	(working copy)
@@ -199,14 +199,14 @@
     krb5_address 		remote_kaddr;
     krb5_boolean		useTcp = 0;
     GETSOCKNAME_ARG3_TYPE 	addrlen;
-    krb5_error_code 		code = 0;
+    krb5_error_code 		code = 0, code2 = 0;
     char 			*code_string;
-    int				local_result_code;
+    int				local_result_code, i;
     
     struct sendto_callback_context  callback_ctx;
     struct sendto_callback_info	callback_info;
     struct sockaddr_storage	remote_addr;
-    struct addrlist 		al = ADDRLIST_INIT;
+    struct addrlist 		al = ADDRLIST_INIT, al2 = ADDRLIST_INIT;
 
     memset( &callback_ctx, 0, sizeof(struct sendto_callback_context));
     callback_ctx.context = context;
@@ -225,109 +225,104 @@
 				     &callback_ctx.ap_req)))
 	goto cleanup;
 
-    do {
-	if ((code = krb5_locate_kpasswd(callback_ctx.context,
-					krb5_princ_realm(callback_ctx.context,
-							 creds->server),
-					&al, useTcp)))
-	    break;
-
+    code = krb5_locate_kpasswd(callback_ctx.context,
+			       krb5_princ_realm(callback_ctx.context,
+						creds->server),
+			       &al, useTcp);
+    code2 = krb5_locate_kpasswd(callback_ctx.context,
+				krb5_princ_realm(callback_ctx.context,
+						 creds->server),
+				&al2, !useTcp);
+    if ((al.naddrs + al2.naddrs) == 0) {
+	if (!code)
+	    code = code2 ? code2 : KRB5_REALM_CANT_RESOLVE;
+	goto cleanup;
+    }
+
+    if (al2.naddrs > 0) {
+	if (krb5int_grow_addrlist(&al, al2.naddrs))
+	    goto cleanup;
+	for (i = 0; i < al2.naddrs; i++)
+	    al.addrs[al.naddrs++] = al2.addrs[i];
+	al2.naddrs = 0;
+    }
+
-	addrlen = sizeof(remote_addr);
-
-	callback_info.context = (void*) &callback_ctx;
-	callback_info.pfn_callback = kpasswd_sendto_msg_callback;
-	callback_info.pfn_cleanup = kpasswd_sendto_msg_cleanup;
-
-	if ((code = krb5int_sendto(callback_ctx.context, 
-				   NULL, 
-				   &al, 
-				   &callback_info,
-				   &chpw_rep,
-				   NULL,
-				   NULL,
-				   ss2sa(&remote_addr),
-                                   &addrlen,
-				   NULL,
-				   NULL,
-				   NULL
-		 ))) {
-
-	    /*
-	     * Here we may want to switch to TCP on some errors.
-	     * right?
-	     */
-	    break;
-	}
-
+    addrlen = sizeof(remote_addr);
+
+    callback_info.context = (void*) &callback_ctx;
+    callback_info.pfn_callback = kpasswd_sendto_msg_callback;
+    callback_info.pfn_cleanup = kpasswd_sendto_msg_cleanup;
+
+    if ((code = krb5int_sendto(callback_ctx.context, 
+			       NULL, 
+			       &al, 
+			       &callback_info,
+			       &chpw_rep,
+			       NULL,
+			       NULL,
+			       ss2sa(&remote_addr),
+			       &addrlen,
+			       NULL,
+			       NULL,
+			       NULL
+		 )))
+	goto cleanup;
+
-	remote_kaddr.addrtype = ADDRTYPE_INET;
-	remote_kaddr.length = sizeof(ss2sin(&remote_addr)->sin_addr);
-	remote_kaddr.contents = (krb5_octet *) &ss2sin(&remote_addr)->sin_addr;
-
-	if ((code = krb5_auth_con_setaddrs(callback_ctx.context,  
-					   callback_ctx.auth_context,  
-					   NULL, 
-					   &remote_kaddr)))
-	    break;
-
+    remote_kaddr.addrtype = ADDRTYPE_INET;
+    remote_kaddr.length = sizeof(ss2sin(&remote_addr)->sin_addr);
+    remote_kaddr.contents = (krb5_octet *) &ss2sin(&remote_addr)->sin_addr;
+
+    if ((code = krb5_auth_con_setaddrs(callback_ctx.context,  
+				       callback_ctx.auth_context,
+				       NULL,
+				       &remote_kaddr)))
+	goto cleanup;
+
-	if (set_password_for)
-	    code = krb5int_rd_setpw_rep(callback_ctx.context, 
-					callback_ctx.auth_context, 
-					&chpw_rep, 
-					&local_result_code, 
-					result_string);
-	else
-	    code = krb5int_rd_chpw_rep(callback_ctx.context, 
-				       callback_ctx.auth_context, 
-				       &chpw_rep, 
-				       &local_result_code, 
-				       result_string);
-
-	if (code) {
-	    if (code == KRB5KRB_ERR_RESPONSE_TOO_BIG && !useTcp ) {
-		krb5int_free_addrlist (&al);
-		useTcp = 1;
-		continue;
-	    }
-
-	    break;
-	}
-
-	if (result_code)
-	    *result_code = local_result_code;
-	
+    if (set_password_for)
+	code = krb5int_rd_setpw_rep(callback_ctx.context, 
+				    callback_ctx.auth_context, 
+				    &chpw_rep, 
+				    &local_result_code, 
+				    result_string);
+    else
+	code = krb5int_rd_chpw_rep(callback_ctx.context, 
+				   callback_ctx.auth_context, 
+				   &chpw_rep, 
+				   &local_result_code, 
+				   result_string);
+
+    if (code)
+	goto cleanup;
+
+    if (result_code)
+	*result_code = local_result_code;
+	
-	if (result_code_string) {
-	    if (set_password_for)
-		code = krb5int_setpw_result_code_string(callback_ctx.context, 
-							local_result_code, 
-							(const char **)&code_string);
-	    else
-		code = krb5_chpw_result_code_string(callback_ctx.context, 
-						    local_result_code, 
-						    &code_string);
-	    if(code)
-		goto cleanup;
-
-	    result_code_string->length = strlen(code_string);
-	    result_code_string->data = malloc(result_code_string->length);
-	    if (result_code_string->data == NULL) {
-		code = ENOMEM;
-		goto cleanup;
-	    }
-	    strncpy(result_code_string->data, code_string, result_code_string->length);
-	}
-
-	if (code == KRB5KRB_ERR_RESPONSE_TOO_BIG && !useTcp ) {
-	    krb5int_free_addrlist (&al);
-	    useTcp = 1;
-        } else {
-	    break;
-	} 
-    } while (TRUE);
+    if (result_code_string) {
+	if (set_password_for)
+	    code = krb5int_setpw_result_code_string(callback_ctx.context, 
+						    local_result_code, 
+						    (const char **) &code_string);
+	else
+	    code = krb5_chpw_result_code_string(callback_ctx.context, 
+						local_result_code, 
+						&code_string);
+	if (code)
+	    goto cleanup;
+
+	result_code_string->length = strlen(code_string);
+	result_code_string->data = malloc(result_code_string->length);
+	if (result_code_string->data == NULL) {
+	    code = ENOMEM;
+	    goto cleanup;
+	}
+	strncpy(result_code_string->data, code_string, result_code_string->length);
+    }
 
 cleanup:
     if (callback_ctx.auth_context != NULL)
 	krb5_auth_con_free(callback_ctx.context, callback_ctx.auth_context);
 
+    krb5int_free_addrlist (&al2);
     krb5int_free_addrlist (&al);
     krb5_free_data_contents(callback_ctx.context, &callback_ctx.ap_req);