[RFC] fix bug 12007

Uri Simchoni uri at samba.org
Wed Jul 6 06:51:00 UTC 2016


I think we're in agreement that Heimdal is at fault here, so I propose
the following:
1. Fix bundled Heimdal not to try the keytab at all unless a
CLIENT_KRB5_KTNAME env is set, and try to upstream this.
2. We still remain with users (real or imaginary) that use out-of-tree
Heimdal, 1.5.x or something, for a member server setup. For those we
can't fix Heimdal, and its a change in samba that created the issue, the
fact that it's a correct change notwithstanding. So I propose that for
those (based on compile time defines) we use kinit always.

As for your remarks about kinit: The usage pattern for the net tool and
for winbindd is:
1. Obtain username/password from secrets.tdb or (in the case of net)
from the U parameter. There's no single-sign-on operation for net AFAICT.
2. sent KRB5_CCNAME to MEMORY:something, to create a separate ccache
3. Invoke libads (for ldap) and/or the smbcli (for smb) - those can
theoretically share the credentials.
4. Internally, smb never assumes it got credentials from some prior
operation, it always uses the user/password for kinit, whereas libads
first tries gssapi, and if that fails runs kinit and re-tries.

I'll open a separate bug on the delegation issue.


On 07/06/2016 12:18 AM, Simo wrote:
> On Mon, 2016-07-04 at 21:44 +0300, Uri Simchoni wrote:
>> On 07/04/2016 06:50 PM, Simo wrote:
>>> Sorry have been thinking more.
>> <snip>
>>>>>> of Kerberos. The attached fix replaces gss_acquire_cred by
>>>>>> gss_krb5_import_cred().
>>> This sounds wrong, and we should fix Heimdal if it is trying to re-
>>> acquire the same ticket, not try to work around it.
>>> Are you saying the current ccache has a valid TGT but it ignores it
>>> and
>>> tries to acquire a new one ?
>>> If there are no credentials it is perfectly normal to make an AS
>>> request, I do not understand what the problem is here. Do we, by
>>> chance
>>> copy in some ccache just the LDAP ticket and not the TGT ?
>> The problem I am trying to fix is that winbindd is emitting AS
>> requests
>> for root at realm, and this happens from within gss_acquire_cred().
>> Heimdal
>> is trying to acquire the wrong TGT, if no TGT exist in the ccache,
>> and
>> in a way it has no chance of succeeding whatsoever (it doesn't have
>> the
>> password of root so what good would a TGT of root do, even if we got
>> one?).
>> Thinking about it some more, the issue is more fundamental:
>> 1. libads expects that the default ccache either has only a TGT of
>> the
>> "right" user (the one the application has specified for libads to use
>> -
>> machine account or otherwise), or that its attempt to bind would
>> fail.
>> Upon failure it would do a kinit and retry.
>> 2. Heimdal's gss_acquire_cred() OTOH, when encountering an empty
>> ccache,
>> tries to get credentials from the default keytab. It is in this code
>> path that the AS request for root is made.
>> 3. Usually this extra attempt with the keytab would fail, creating
>> the
>> nuisance with the AS request - maybe we can fix that with Heimdal for
>> the case where no keytab exists.
>> 4. But what if a keytab does exist, and contains valid password for
>> the
>> current user? In that case, gss_acquire_cred() might obtain the
>> credentials of the current user, whereas libads expected to be of its
>> user - could be a username specified via the -U parameter, or the
>> machine account.
> It seem like the whole setup is incorrect if these things happen
> 1. libads as any other program using GSSAPI rightfully expect to have
> the proper crdentials, so the application or the user calling it needs
> to provide appropriate credentials or fail.
> 2/3. If Heimdal tries to perform an AS request when it doesn't have a
> keytab then I think Heimdal needs to be fixed.
> 4. In MIT a keytab is used to acquire credentials for Initiation only
> if the CLIENT_KRB5_KTNAME variable is set, so again it seem that
> Heimdal is not behaving properly here, and causing unnecessary churn.
> If the application is properly set up (access to keytab provided if,
> and only if needed, otherwise proper credentials provided) then a
> gss_acquire_cred() or a gss_init_sec_context() call [in MIT acquiring
> creds can be delayed to the context establishment call in some cases]
> should cause an AS request only when intended (no valid TGT in the
> ccache and a keytab has been provided).
>> Up until the April security release, gensec_gse was used only for SMB
>> connections, and there we don't seem to reuse a TGT between
>> connections
> This looks like a bug.
>> - we always do a kinit first (in cli_session_setup_spnego_send()).
> This is inefficient, is there a good reason why ?
>> Libads does something new in that respect.
> We should probably fix libads, in general we've shrouded this whole
> process with way too much magic and made this area of the code obscure
> and hard to deal with in the process unfortunately. We should unwind it
> if enough energy to do that can be found, it helps nobody when it is
> hard to understand what credentials are used and how, and there lie
> potential bugs.
>> The fix tries to probe the ccache more gently than
>> gss_acquire_cred().
> The "fix" is incorrect I am afraid.
>>  I don't know why Heimdal is also trying the keytab, but they would
>> probably insist on doing it. Assuming that's true, the fix is to
>> always do a kinit before the bind attempt (or to improve libads's
>> integration with gensec and cli_credentials, because those track the
>> content of the ccache without a need to probe it).
> A kinit requires access to credentials, which is not granted when you
> are a physical user that has a perfectly valid TGT in the ccache.
> I understand this is a performance issue mostly, because if you do not
> have valid credentials the end state is just that you get a failure.
> however I am confused by the fact you are trying to import an existing
> ccache. Does it mean you have a valid ccache but that this ccache is
> not the *default* ccache for the process and is not being found ?
> For MIT you can use the gss_acquire_cred_from() interface in that case
> (you pass a "ccache: name" pair in). I do not think Heimdal implements
> it yet unfortunately, in that case you can try to have a fallback
> function to call gss_krb5_ccache_name() which sets the default ccache
> name before the regular gss_acquire_cred()
> Be careful with this one as it applies to *any* further gssapi calls
> within the process, so it could lead to undesired results if multiple
> gss_acquire_cred(0 calls are performed. Unsetting the default ccache
> (and resetting it to the actual default ccache) can be done by passing
> NULL as name, so this may be made safe by using a tight loop and
> perhaps some locking (if threads are being used).
> Simo.
>>>>>> I'd like some feedback from those familiar with this code -
>>>>>> 1. It could be that the right fix is in Heimdal
>>> Definitely if it really is a bug in finding a valid credential in
>>> the
>>> cache.
>>>>>> 2. The reason for acquiring the credentials (in client
>>>>>> context!)
>>>>>> seems
>>>>>> to be to be able to set GSS_KRB5_CRED_NO_CI_FLAGS_X option on
>>>>>> the
>>>>>> credentials - not sure what scenario this fixes and how to
>>>>>> test
>>>>>> there's
>>>>>> no degradation there.
>>> This is fundamental, otherwise LDAP binds will fail because AD uses
>>> the
>>> CI flags instead of the SASL negotiation, so we need to be able to
>>> control exactly what flags we send (normally both Heimdal and MIT
>>> Kerberos send both Confidentiality and Integrity flags
>>> unconditionally,
>>> because that is mandated by the Spec, but Microsoft interpreted it
>>> differently in some protocols).
>> I can test with Windows then. Only tested with Samba AD so far.
>>>>>> 3. Perhaps someone can easily determine the MIT behavior - if
>>>>>> MIT
>>>>>> is not
>>>>>> sending this request then maybe the patch should be #ifdef'd
>>>>>> on
>>>>>> Kerberos
>>>>>> type - use the more portable gss_acquire_cred() with MIT
>>>>>> Kerberos.
>>> We must use gss_acquire_cred() sorry.
>> MIT seems to have a gss_krb5_import_cred() - can't we use that and
>> fall
>> back to gss_acquire_cred() only for older versions?
>>>>>> Thanks,
>>>>>> Uri.
>>>>> One more things - the gensec_gse code also makes an extra TGS
>>>>> handshake,
>>>>> requesting a TGT, because it requires delegation for the
>>>>> security
>>>>> context. Do we need delegation for LDAP sasl binding/wrapping?
>>>> Generally no, we don't, it should be somehow selectable, base on
>>>> the
>>>> target machine's "allowed to delegate to" (IIRC) flag.
>>> Brain fart here. We *definitely* almost never want to delegate a
>>> TGT,
>>> but we definitely want to request a forwardable ticket, so that the
>>> server can perform constrained delegation if it is authorized and
>>> so
>>> configured.
>>> What flags are passed in ? Can you point me at the code path that
>>> generates this ?
>> It's in the default gse context flags.
>> In  gse_context_init(), we have:
>>         gse_ctx->gss_want_flags = GSS_C_MUTUAL_FLAG |
>>                                 *GSS_C_DELEG_FLAG* |
>>                                 GSS_C_DELEG_POLICY_FLAG |
>>                                 GSS_C_REPLAY_FLAG |
>>                                 GSS_C_SEQUENCE_FLAG;
>>> Simo.

More information about the samba-technical mailing list