Skip to content

Commit

Permalink
Try harder to avoid password change replay errors
Browse files Browse the repository at this point in the history
Commit d7b3018 (ticket 7905) changed
change_set_password() to prefer TCP.  However, because UDP_LAST falls
back to UDP after one second, we can still get a replay error due to a
dropped packet, before the TCP layer has a chance to retry.

Instead, try k5_sendto() with NO_UDP, and only fall back to UDP after
TCP fails completely without reaching a server.  In sendto_kdc.c,
implement an ONLY_UDP transport strategy to allow the UDP fallback.

ticket: 9037
  • Loading branch information
greghudson committed Mar 17, 2022
1 parent cbfe46c commit 6297788
Show file tree
Hide file tree
Showing 3 changed files with 17 additions and 5 deletions.
9 changes: 8 additions & 1 deletion src/lib/krb5/os/changepw.c
Original file line number Diff line number Diff line change
Expand Up @@ -255,9 +255,16 @@ change_set_password(krb5_context context,
callback_info.pfn_cleanup = kpasswd_sendto_msg_cleanup;
krb5_free_data_contents(callback_ctx.context, &chpw_rep);

/* UDP retransmits may be seen as replays. Only try UDP after other
* transports fail completely. */
code = k5_sendto(callback_ctx.context, NULL, &creds->server->realm,
&sl, UDP_LAST, &callback_info, &chpw_rep,
&sl, NO_UDP, &callback_info, &chpw_rep,
ss2sa(&remote_addr), &addrlen, NULL, NULL, NULL);
if (code == KRB5_KDC_UNREACH) {
code = k5_sendto(callback_ctx.context, NULL, &creds->server->realm,
&sl, ONLY_UDP, &callback_info, &chpw_rep,
ss2sa(&remote_addr), &addrlen, NULL, NULL, NULL);
}
if (code)
goto cleanup;

Expand Down
1 change: 1 addition & 0 deletions src/lib/krb5/os/os-proto.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ typedef enum {
UDP_FIRST = 0,
UDP_LAST,
NO_UDP,
ONLY_UDP
} k5_transport_strategy;

/* A single server hostname or address. */
Expand Down
12 changes: 8 additions & 4 deletions src/lib/krb5/os/sendto_kdc.c
Original file line number Diff line number Diff line change
Expand Up @@ -804,11 +804,14 @@ resolve_server(krb5_context context, const krb5_data *realm,
int err, result;
char portbuf[PORT_LENGTH];

/* Skip UDP entries if we don't want UDP. */
/* Skip entries excluded by the strategy. */
if (strategy == NO_UDP && entry->transport == UDP)
return 0;
if (strategy == ONLY_UDP && entry->transport != UDP &&
entry->transport != TCP_OR_UDP)
return 0;

transport = (strategy == UDP_FIRST) ? UDP : TCP;
transport = (strategy == UDP_FIRST || strategy == ONLY_UDP) ? UDP : TCP;
if (entry->hostname == NULL) {
/* Added by a module, so transport is either TCP or UDP. */
ai.ai_socktype = socktype_for_transport(entry->transport);
Expand Down Expand Up @@ -852,8 +855,9 @@ resolve_server(krb5_context context, const krb5_data *realm,
}

/* For TCP_OR_UDP entries, add each address again with the non-preferred
* transport, unless we are avoiding UDP. Flag these as deferred. */
if (retval == 0 && entry->transport == TCP_OR_UDP && strategy != NO_UDP) {
* transport, if there is one. Flag these as deferred. */
if (retval == 0 && entry->transport == TCP_OR_UDP &&
(strategy == UDP_FIRST || strategy == UDP_LAST)) {
transport = (strategy == UDP_FIRST) ? TCP : UDP;
for (a = addrs; a != 0 && retval == 0; a = a->ai_next) {
a->ai_socktype = socktype_for_transport(transport);
Expand Down

0 comments on commit 6297788

Please sign in to comment.