krb5/krb5 — pull request #104 by nexue (2014-04-17 20:41:55+00:00)
Title: kpasswd returns KDC reply did not match expectations

Dear MIT kerberos dev team,

I am working with Tomas Kuthan and Will Fiveash together on the dropin project.
This is an old bug fix from our bug pool. I investigated current MIT kerberos code
and compared with our Solaris kerberos code. It seems that MIT kerberos is still
affected by this bug. And our bug fix is applicable for this bug fix. Following is the
bug description in detail:

When invoking kpasswd against a Heimdal 0.7.2 server the following error
message is reported:

kpasswd: Cannot establish a session with the Kerberos administrative server
for realm HEIMDAL.REALM. KDC reply did not match expectations.

During the AS exchange the client has set the renewable-ok option, so this
allows the KDC to issue a renewable ticket if the requested end time can not
be issued. In this case the client requests a very large end time (0) that
is well beyond the policy limit (default of 7 days). So the KDC issues a
ticket that has a renew-till time that is the smaller of the request end time
(0) or the maximum policy time (starttime + max renew life time). It will
choose the latter.

The starttime is based on the KDC's local clock, so if the client's clock is
slower than the KDC's then you can reach a condition in which the requested
renew time is less than the one received in the ticket. When this occurs the
following check succeeds from lines below:

src/lib/krb5/krb/get_in_tkt.c::verify_as_reply:
...
174 if ((!canon_ok &&
175 (!krb5_principal_compare(context, as_reply->client, request->client) ||
176 !krb5_principal_compare(context, as_reply->enc_part2->server, request->server)))
177 || !krb5_principal_compare(context, as_reply->enc_part2->server, as_reply->ticket->server)
178 || (request->nonce != as_reply->enc_part2->nonce)
179 /* XXX check for extraneous flags */
180 /* XXX || (!krb5_addresses_compare(context, addrs, as_reply->enc_part2->caddrs)) */
181 || ((request->kdc_options & KDC_OPT_POSTDATED) &&
182 (request->from != 0) &&
183 (request->from != as_reply->enc_part2->times.starttime))
184 || ((request->till != 0) &&
185 (as_reply->enc_part2->times.endtime > request->till))
186 || ((request->kdc_options & KDC_OPT_RENEWABLE) &&
187 (request->rtime != 0) &&
188 (as_reply->enc_part2->times.renew_till > request->rtime))
189 || ((request->kdc_options & KDC_OPT_RENEWABLE_OK) &&
190 !(request->kdc_options & KDC_OPT_RENEWABLE) &&
191 (as_reply->enc_part2->flags & KDC_OPT_RENEWABLE) &&
192 (request->till != 0) &&
193 (as_reply->enc_part2->times.renew_till > request->till))
194 ) {
195 return KRB5_KDCREP_MODIFIED;
196 }

This is an invalid check and should only be made if the KDC_OPT_RENEWABLE_OK
is not set in the request.

For this bug fix, I compiled through and did the gmake check with no errors reported.

Best,
Neng