Question about krb5_rd_req - Kerberos

This is a discussion on Question about krb5_rd_req - Kerberos ; -----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
I've been testing authentication code that is intended to work with an
Active Directory KDC, as well as with an MIT K5 KDC, and which uses the
MIT K5 libraries. This is 'proxy auth', ...

Question about krb5_rd_req

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

I've been testing authentication code that is intended to work with an
Active Directory KDC, as well as with an MIT K5 KDC, and which uses the
MIT K5 libraries. This is 'proxy auth', where I do the AS_REQ and also
process the AP_REQ in the same code, using a keytab file.

[Everything that follows applies when using krb5-1.3.4 and krb5-1.4.2].

As it happens, the keytabs that were generated for me by the AD folks were
based on the wrong password for the service principals, so, naturally, the
rd_req failed. However, I found the particular symptoms interesting and
wonder if this is intentional or an inadvertent by-product of the MIT
library logic.

If I call krb5_rd_req specifying NULL for the server principal, then the
error message I get is 'Bad encryption type while decoding authenticator'
(RC=188). But if I specify the server principal in krb5_rd_req, then I
get this error: 'Decrypt integrity check failed' (RC=31).

[Both forms of the call to krb5_rd_req work fine when the keytabs are OK].

We've now got our keytabs corrected, but I'm still curious about the
different error messages for the same keytabs, depending (it appears) only
on whether a server principal is supplied in the call to krb5_rd_req. Is
this discrepancy intended? Right now, it's just curiosity on my part.

Re: Question about krb5_rd_req

>If I call krb5_rd_req specifying NULL for the server principal, then the
>error message I get is 'Bad encryption type while decoding authenticator'
>(RC=188). But if I specify the server principal in krb5_rd_req, then I
>get this error: 'Decrypt integrity check failed' (RC=31).
>
>[Both forms of the call to krb5_rd_req work fine when the keytabs are OK].
>
>We've now got our keytabs corrected, but I'm still curious about the
>different error messages for the same keytabs, depending (it appears) only
>on whether a server principal is supplied in the call to krb5_rd_req. Is
>this discrepancy intended? Right now, it's just curiosity on my part.

How facinating. In theory, it really should be the same because in rd_req.c,
if server == NULL, it uses the server principal out of the AP_REQ.

It would be interesting to see what the code path is that is causing this;
I have personally never seen "Bad encryption type" in this scenario, even
for services which pass in NULL for the server principal. Maybe it's worth
running it under a debugger?

Is KRB5_CONFIG info cached?

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

[I apologize for the length of this, but it's about a problem that is
proving to be very inscrutable and it needs some explanation].

I'm doing some testing of code that authenticates against both an MIT K5
KDC and an Active Directory KDC. I've written a perl subroutine that uses
Jeff Horwitz's Authen::Krb5 module, which seems to work fine for
individual authentications.

However, here's my problem. I need to call my subroutine twice from the
same perl script, once pointing to our MIT KDC and the second time
pointing to our campus AD KDC. I control which KDC I'm using by
manipulating the 'KRB5_CONFIG' environment variable within my subroutine,
based on an argument from the caller that specifies the KDC to use. And,
of course, depending on which KDC it is, I use a keytab file that was
generated on the appropriate KDC.

When I do this, I find that the second call fails, apparently because I
wind up connecting to the wrong KDC. If I call the MIT KDC first,
authentication succeeds; then the second call (to the AD KDC) gives this
message (from get_in_tkt_with_password):

Cannot resolve network address for KDC in requested realm

I can see in the MIT KDC logs that the first authentication did, in fact,
succeed. And, although I don't have access to the AD KDC logs, my code
displays the realm being used and it is, indeed, that of the AD KDC.

If I call the AD KDC first, then authentication succeeds, but the second
call (to the MIT KDC) gives this message (also from
get_in_tkt_with_password):

Server not found in Kerberos database

I believe that both symptoms are consistent with my connecting to the
wrong KDC; i.e., the second call still tries to connect to the KDC of the
first call.

However, my code also displays the name of the krb5.conf file being used
and it's always correct! I obtain this value by doing a 'echo
$KRB5_CONFIG' in my subroutine, so presumably that really does reflect the
environment at the time the subroutine is run. Also, I give my
credentials cache a name containing the PID, so I can also see that both
calls are taking place within the same process (as I'd expect, since it's
all one perl script).

So, on the one hand, it would seem that the environment variable is being
set correctly. Yet, the evidence is that I'm connecting to the same KDC
both times (but, of course, the second call is using the wrong keytab
file).

I should also say that if I make both calls to the same KDC, I get two
good authentications. Also, if I enter the wrong password, I can tell
from the failure responses which KDC I'm talking to, because AD always
returns 'preauth failed', while MIT KDC returns 'Decrypt integrity check
failed'.

Any ideas about this? Is there any way to force connection to a specific
KDC other than using the 'KRB5_CONFIG' environment variable? (We don't
use SRV records here, so that's not an option even if it would help in
this case).

Re: Is KRB5_CONFIG info cached?

On Jun 29, 2006, at 17:21, Mike Friedman wrote:
> Any ideas about this? Is there any way to force connection to a
> specific
> KDC other than using the 'KRB5_CONFIG' environment variable? (We
> don't
> use SRV records here, so that's not an option even if it would help in
> this case).

When a krb5_context is created, the current setting for KRB5_CONFIG
is lookup up and effectively cached. Actually, we open the listed
files if they exist, and occasionally go back and check if the files
we've read have changed; so if a file is listed in KRB5_CONFIG but
doesn't exist, a context is created, and then the file is created, we
won't look at it for use in that context.

I don't know what the perl module is doing.

If these KDCs are for two different realms, can you list both config
files in KRB5_CONFIG?

If you've got one realm name but two different databases and KDCs,
well, it's going to hurt. :-)
But in 1.5 (betas out already, release expected RSN) we have support
for a plugin that tells the library where to find the KDC (or certain
other services) for a realm; you might be able to do something with
that. (The sample code for that plugin, not built or compiled
normally, loads and runs a Python script. So maybe you can find a
way to get it to play nice with your Perl script.)

Re: Is KRB5_CONFIG info cached?

Mike Friedman writes:
> Date: Thu, 29 Jun 2006 14:21:57 -0700 (PDT)
> From: Mike Friedman
> To: kerberos@mit.edu
> Subject: Is KRB5_CONFIG info cached?
> In-Reply-To: <200606212039.k5LKdYDa013625@ginger.cmf.nrl.navy.mi l>
....
>
> [I apologize for the length of this, but it's about a problem that is
> proving to be very inscrutable and it needs some explanation].
>
> I'm doing some testing of code that authenticates against both an MIT K5
> KDC and an Active Directory KDC. I've written a perl subroutine that uses
> Jeff Horwitz's Authen::Krb5 module, which seems to work fine for
> individual authentications.
>
> However, here's my problem. I need to call my subroutine twice from the
> same perl script, once pointing to our MIT KDC and the second time
> pointing to our campus AD KDC. I control which KDC I'm using by
> manipulating the 'KRB5_CONFIG' environment variable within my subroutine,
> based on an argument from the caller that specifies the KDC to use. And,
> of course, depending on which KDC it is, I use a keytab file that was
> generated on the appropriate KDC.
....

As long as the KDCs are in different realms, you ought to be able
to use one context, and one KRB5_CONFIG file, to access both. It
doesn't matter if you normally use SRV records; if you put
explicit host information in your config file, kerberos will use
that; if you set [libdefaults] dns_fallback = false, you can
forbid it from even thinking about looking at DNS.
The kerberos server will not know or care whether you found it
via DNS or a config file.

As it happens, I've been using Jeff's code for some other stuff.

So, at a closer look at Jeff Horwitz's code, looks like he
expects Authen::Krb5::init_context(). He's got this
right before:
if (context) croak("Authen::Krb5 already initialized");

So the first call you make to Authen::Krb5::init_context() will pick
up whatever's currently in KRB5_CONFIG, and you can't be making any
subsequent calls to that unless you're catching and discarding the
ensuing croak. If you want to have fun, you can probably call
Authen::Krb5::krb5_free_context();
but that won't buy you anything unless you edit Krb5.xs and
add a "context = 0" after the krb5_free_context call.

Re: Is KRB5_CONFIG info cached?

On Thu, 29 Jun 2006 at 18:43 (-0400), Marcus Watts wrote:
> As long as the KDCs are in different realms, you ought to be able to use
> one context, and one KRB5_CONFIG file, to access both.

Marcus,

But each time I call my subroutine, I get a new context.
> As it happens, I've been using Jeff's code for some other stuff.
>
> So, at a closer look at Jeff Horwitz's code, looks like he expects
> Authen::Krb5::init_context(). He's got this right before:
> if (context) croak("Authen::Krb5 already initialized");

I ran into this problem a while back and contacted Jeff about it. He
suggested the fix you mentioned (to free_context()), which I implemented.
So I don't have the problem of the context hanging around, because I do a
free_context() at the end of my subroutine.

Ken,

You said,
> If these KDCs are for two different realms, can you list both config
> files in KRB5_CONFIG?

But then how do I get the *default realm* set correctly? In my script, I
do a parse_name() to create a principal object corresponding to the TGS
service principal (e.g., krbtgt/@). (It's this principal
object that I must pass to get_in_tkt_with_password()). And,
unfortunately, parse_name() complains if my config file doesn't have a
default realm, so defining both realms in the [realms] stanza doesn't do
me any good. But if I do define a default realm, then that's the KDC to
which I get connected, regardless of the realm name I specify when
constructing the TGS service principal name itself.

So, it seems I need to point to a different config file each time I want
to go to a different KDC. And, I don't know any way except the
KRB5_CONFIG environment variable to do it from within my subroutine code.

But given that I get a new context each time, why can't I reset the value
of KRB5_CONFIG on each call and have it be honored? This is the crux of
the matter, apparently.

Re: Is KRB5_CONFIG info cached?

On Jun 29, 2006, at 19:41, Mike Friedman wrote:
>> If these KDCs are for two different realms, can you list both
>> config files in KRB5_CONFIG?
>
> But then how do I get the *default realm* set correctly? In my
> script, I do a parse_name() to create a principal object
> corresponding to the TGS service principal (e.g., krbtgt/
> @). (It's this principal object that I must pass to
> get_in_tkt_with_password()). And, unfortunately, parse_name()
> complains if my config file doesn't have a default realm, so
> defining both realms in the [realms] stanza doesn't do me any good.

krb5_set_default_realm ?
> But if I do define a default realm, then that's the KDC to which I
> get connected, regardless of the realm name I specify when
> constructing the TGS service principal name itself.

That sounds like a bug. If this is for getting initial tickets, and
you're specifying the non-default realm in both the client principal
name and the TGS service principal name, it should only contact that
non-default realm's KDC.
> But given that I get a new context each time, why can't I reset the
> value of KRB5_CONFIG on each call and have it be honored? This is
> the crux of the matter, apparently.

If you don't mind digging into the krb5 library code, change lib/krb5/
os/init_os_ctx.cs_get_default_config_files or set a breakpoint in
gdb, and examine the result of calling getenv.

Re: Is KRB5_CONFIG info cached?

Mike Friedman writes:

....
> > So, at a closer look at Jeff Horwitz's code, looks like he expects
> > Authen::Krb5::init_context(). He's got this right before:
> > if (context) croak("Authen::Krb5 already initialized");
>
> I ran into this problem a while back and contacted Jeff about it. He
> suggested the fix you mentioned (to free_context()), which I implemented.
> So I don't have the problem of the context hanging around, because I do a
> free_context() at the end of my subroutine.

I see. I'm not quite sure how I missed the part where you said
that up front, but whatever.
>
> Ken,
>
> You said,
>
> > If these KDCs are for two different realms, can you list both config
> > files in KRB5_CONFIG?
>
> But then how do I get the *default realm* set correctly? In my script, I
> do a parse_name() to create a principal object corresponding to the TGS
> service principal (e.g., krbtgt/@). (It's this principal
> object that I must pass to get_in_tkt_with_password()). And,
> unfortunately, parse_name() complains if my config file doesn't have a
> default realm, so defining both realms in the [realms] stanza doesn't do
> me any good. But if I do define a default realm, then that's the KDC to
> which I get connected, regardless of the realm name I specify when
> constructing the TGS service principal name itself.
>
> So, it seems I need to point to a different config file each time I want
> to go to a different KDC. And, I don't know any way except the
> KRB5_CONFIG environment variable to do it from within my subroutine code.
>
> But given that I get a new context each time, why can't I reset the value
> of KRB5_CONFIG on each call and have it be honored? This is the crux of
> the matter, apparently.

I believe you're still barking up the wrong tree. The default
realm is just that, a default. If you really want to specify
two different realms, then that's fine -- that's why you can
specify the realm explicitly and override the default.

This was my test krb5 configuration file. Note it has CATS, DOGS,
and the default realm is something else again -- UMICH.EDU .
Note that /etc/krb5.conf - the default configuration file, does not
have CATS (it does have DOGS, UMICH.EDU plus more junk.)

There it is, working. I got a tgt for CATS (therefore I must have
been using k5.conf), and I could then reinitialize & fetch a tgt
for DOGS. One perl script, one run, two successful initial authentications,
in different realms - and no messing around with changing default realm,
context, or environment variables. If I wanted to keep both tgts, I
could probably stuff both tgt's into one credential cache - or I could
easily manage two separate credential caches using cc_resolve.

Note that if I actually cared *which* kdc I was going to inside
of one realm, like strawdogs vs. reservoirdogs, I'd have to do something
else. The only reason I can think of where I'd want to do that is for
testing or monitoring purposes.

If you still want to get a context more than once, Ken's
idea to set a breakpoint on krb5_init_context or trap its
call to getenv is a great idea. A fancier scheme would be
to rework Jeff's code so that you can have more than one
krb5 context accessible from perl at the same time.

Re: Is KRB5_CONFIG info cached?

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

On Fri, 30 Jun 2006 at 01:39 (-0400), Marcus Watts wrote:
> I believe you're still barking up the wrong tree. The default realm is
> just that, a default. If you really want to specify two different
> realms, then that's fine -- that's why you can specify the realm
> explicitly and override the default.

Marcus,

You're right, as I discovered late yesterday. My problem was that in
specifying the client (user) principal to be authenticated, I wasn't
qualifying it with the realm, so I kept getting the default realm as
listed in my config file. Once I fixed that, each of my subroutine calls
would connect to the proper realm.