Blame SOURCES/Prefer-TCP-to-UDP-for-password-changes.patch

749169
From aa346834947ef65c293a29300b0f98b1825d8508 Mon Sep 17 00:00:00 2001
dad97c
From: Robbie Harwood <rharwood@redhat.com>
dad97c
Date: Mon, 8 Oct 2018 16:02:12 -0400
dad97c
Subject: [PATCH] Prefer TCP to UDP for password changes
dad97c
dad97c
When password changes are performed over UDP, spotty networks may
dad97c
cause the client to retransmit.  This leads to replay errors if the
dad97c
kpasswd server receives both requests, which hide the actual request
dad97c
status and make it appear that the password has not been changed, when
dad97c
it may in fact have been.  Use TCP instead with UDP fallback to avoid
dad97c
this issue.
dad97c
dad97c
ticket: 7905
dad97c
(cherry picked from commit d7b3018d338fc9c989c3fa17505870f23c3759a8)
dad97c
---
dad97c
 src/lib/krb5/os/changepw.c | 110 ++++++++++++++-----------------------
dad97c
 1 file changed, 42 insertions(+), 68 deletions(-)
dad97c
dad97c
diff --git a/src/lib/krb5/os/changepw.c b/src/lib/krb5/os/changepw.c
dad97c
index e4db57084..9f968da7f 100644
dad97c
--- a/src/lib/krb5/os/changepw.c
dad97c
+++ b/src/lib/krb5/os/changepw.c
dad97c
@@ -59,13 +59,12 @@ struct sendto_callback_context {
dad97c
 
dad97c
 static krb5_error_code
dad97c
 locate_kpasswd(krb5_context context, const krb5_data *realm,
dad97c
-               struct serverlist *serverlist, krb5_boolean no_udp)
dad97c
+               struct serverlist *serverlist)
dad97c
 {
dad97c
     krb5_error_code code;
dad97c
 
dad97c
     code = k5_locate_server(context, realm, serverlist, locate_service_kpasswd,
dad97c
-                            no_udp);
dad97c
-
dad97c
+                            FALSE);
dad97c
     if (code == KRB5_REALM_CANT_RESOLVE || code == KRB5_REALM_UNKNOWN) {
dad97c
         code = k5_locate_server(context, realm, serverlist,
dad97c
                                 locate_service_kadmin, TRUE);
dad97c
@@ -76,7 +75,7 @@ locate_kpasswd(krb5_context context, const krb5_data *realm,
dad97c
             for (i = 0; i < serverlist->nservers; i++) {
dad97c
                 struct server_entry *s = &serverlist->servers[i];
dad97c
 
dad97c
-                if (!no_udp && s->transport == TCP)
dad97c
+                if (s->transport == TCP)
dad97c
                     s->transport = TCP_OR_UDP;
dad97c
                 if (s->hostname != NULL)
dad97c
                     s->port = DEFAULT_KPASSWD_PORT;
dad97c
@@ -214,7 +213,6 @@ change_set_password(krb5_context context,
dad97c
                     krb5_data *result_string)
dad97c
 {
dad97c
     krb5_data                   chpw_rep;
dad97c
-    krb5_boolean                no_udp = FALSE;
dad97c
     GETSOCKNAME_ARG3_TYPE       addrlen;
dad97c
     krb5_error_code             code = 0;
dad97c
     char                        *code_string;
dad97c
@@ -246,73 +244,49 @@ change_set_password(krb5_context context,
dad97c
     callback_ctx.remote_seq_num = callback_ctx.auth_context->remote_seq_number;
dad97c
     callback_ctx.local_seq_num = callback_ctx.auth_context->local_seq_number;
dad97c
 
dad97c
-    do {
dad97c
-        k5_transport_strategy strategy = no_udp ? NO_UDP : UDP_FIRST;
dad97c
+    code = locate_kpasswd(callback_ctx.context, &creds->server->realm, &sl);
dad97c
+    if (code)
dad97c
+        goto cleanup;
dad97c
 
dad97c
-        code = locate_kpasswd(callback_ctx.context, &creds->server->realm, &sl,
dad97c
-                              no_udp);
dad97c
+    addrlen = sizeof(remote_addr);
dad97c
+
dad97c
+    callback_info.data = &callback_ctx;
dad97c
+    callback_info.pfn_callback = kpasswd_sendto_msg_callback;
dad97c
+    callback_info.pfn_cleanup = kpasswd_sendto_msg_cleanup;
dad97c
+    krb5_free_data_contents(callback_ctx.context, &chpw_rep);
dad97c
+
dad97c
+    code = k5_sendto(callback_ctx.context, NULL, &creds->server->realm,
dad97c
+                     &sl, UDP_LAST, &callback_info, &chpw_rep,
dad97c
+                     ss2sa(&remote_addr), &addrlen, NULL, NULL, NULL);
dad97c
+    if (code)
dad97c
+        goto cleanup;
dad97c
+
dad97c
+    code = krb5int_rd_chpw_rep(callback_ctx.context,
dad97c
+                               callback_ctx.auth_context,
dad97c
+                               &chpw_rep, &local_result_code,
dad97c
+                               result_string);
dad97c
+
dad97c
+    if (code)
dad97c
+        goto cleanup;
dad97c
+
dad97c
+    if (result_code)
dad97c
+        *result_code = local_result_code;
dad97c
+
dad97c
+    if (result_code_string) {
dad97c
+        code = krb5_chpw_result_code_string(callback_ctx.context,
dad97c
+                                            local_result_code,
dad97c
+                                            &code_string);
dad97c
         if (code)
dad97c
-            break;
dad97c
+            goto cleanup;
dad97c
 
dad97c
-        addrlen = sizeof(remote_addr);
dad97c
-
dad97c
-        callback_info.data = &callback_ctx;
dad97c
-        callback_info.pfn_callback = kpasswd_sendto_msg_callback;
dad97c
-        callback_info.pfn_cleanup = kpasswd_sendto_msg_cleanup;
dad97c
-        krb5_free_data_contents(callback_ctx.context, &chpw_rep);
dad97c
-
dad97c
-        code = k5_sendto(callback_ctx.context, NULL, &creds->server->realm,
dad97c
-                         &sl, strategy, &callback_info, &chpw_rep,
dad97c
-                         ss2sa(&remote_addr), &addrlen, NULL, NULL, NULL);
dad97c
-        if (code) {
dad97c
-            /*
dad97c
-             * Here we may want to switch to TCP on some errors.
dad97c
-             * right?
dad97c
-             */
dad97c
-            break;
dad97c
+        result_code_string->length = strlen(code_string);
dad97c
+        result_code_string->data = malloc(result_code_string->length);
dad97c
+        if (result_code_string->data == NULL) {
dad97c
+            code = ENOMEM;
dad97c
+            goto cleanup;
dad97c
         }
dad97c
-
dad97c
-        code = krb5int_rd_chpw_rep(callback_ctx.context,
dad97c
-                                   callback_ctx.auth_context,
dad97c
-                                   &chpw_rep, &local_result_code,
dad97c
-                                   result_string);
dad97c
-
dad97c
-        if (code) {
dad97c
-            if (code == KRB5KRB_ERR_RESPONSE_TOO_BIG && !no_udp) {
dad97c
-                k5_free_serverlist(&sl);
dad97c
-                no_udp = 1;
dad97c
-                continue;
dad97c
-            }
dad97c
-
dad97c
-            break;
dad97c
-        }
dad97c
-
dad97c
-        if (result_code)
dad97c
-            *result_code = local_result_code;
dad97c
-
dad97c
-        if (result_code_string) {
dad97c
-            code = krb5_chpw_result_code_string(callback_ctx.context,
dad97c
-                                                local_result_code,
dad97c
-                                                &code_string);
dad97c
-            if (code)
dad97c
-                goto cleanup;
dad97c
-
dad97c
-            result_code_string->length = strlen(code_string);
dad97c
-            result_code_string->data = malloc(result_code_string->length);
dad97c
-            if (result_code_string->data == NULL) {
dad97c
-                code = ENOMEM;
dad97c
-                goto cleanup;
dad97c
-            }
dad97c
-            strncpy(result_code_string->data, code_string, result_code_string->length);
dad97c
-        }
dad97c
-
dad97c
-        if (code == KRB5KRB_ERR_RESPONSE_TOO_BIG && !no_udp) {
dad97c
-            k5_free_serverlist(&sl);
dad97c
-            no_udp = 1;
dad97c
-        } else {
dad97c
-            break;
dad97c
-        }
dad97c
-    } while (TRUE);
dad97c
+        strncpy(result_code_string->data, code_string, result_code_string->length);
dad97c
+    }
dad97c
 
dad97c
 cleanup:
dad97c
     if (callback_ctx.auth_context != NULL)