Discussion:
Plug-in interfaces & internal APIs
Ken Hornstein
2015-05-16 06:14:24 UTC
Permalink
So I've been spending recent time converting some of our horrible, ancient
hacks into plugins for the new version of MIT Kerberos. That's actually
going pretty well, but it led me to see some things I wish existed in
the plugin API.

I know that doing your own PKINIT plugin requires a lot of internal
interfaces and changing that is hard. But most of the plugins I've written
still require internal interfaces, and that's a bit frustrating.

The biggest issue is configuration; most of the plugins require some KDC-wide
configuration (e.g.: Yubikey requires a few parameters, like the URL for
the validation server, a client identifier, an API key, etc etc). Right
now you have to call the internal profile APIs to get stuff out of krb5.conf
or kdc.conf. This makes me wonder exactly what people's thoughts were in
terms of plugin configuration (it may be that this was never considered).

The second thing I've run into is storing per-principal information.
I know about the set_strings/get_strings interface; we use that, and
it's great! But we have some cases where the plugin needs to modify
some data associated with the principal, and there is no set_strings
interface. I know there's a callback to retrieve the principal record,
but I was wondering if that's the preferred method for storing stuff,
or if there should be an additional callback to store string data
(or TL_DATA) on a per-principal bases.

Thoughts? These are just things that have popped out at me in the past
few weeks.

--Ken
_______________________________________________
krbdev mailing list ***@mit.edu
https://mailman.mit.edu/mailman/listinfo/krbdev
Greg Hudson
2015-05-16 15:15:59 UTC
Permalink
Post by Ken Hornstein
I know that doing your own PKINIT plugin requires a lot of internal
interfaces and changing that is hard.
If you have another way of doing ASN.1 (such as asn1c), you could
implement PKINIT without internal interfaces, in principle.

Of course, if you want to copy and modify the existing PKINIT module,
our use of internal interfaces for ASN.1 (and possibly other things) is
prohibitive. The only really practical solution is to fork the whole
tree, modify it, build it, and install only the PKINIT module. We'd
rather it not be necessary to modify PKINIT, and I think we've discussed
what is required for that for your case and just haven't done the work.
Post by Ken Hornstein
The biggest issue is configuration; most of the plugins require some KDC-wide
configuration (e.g.: Yubikey requires a few parameters, like the URL for
the validation server, a client identifier, an API key, etc etc). Right
now you have to call the internal profile APIs to get stuff out of krb5.conf
or kdc.conf. This makes me wonder exactly what people's thoughts were in
terms of plugin configuration (it may be that this was never considered).
You can call krb5_get_profile(), profile_get_*(), and profile_release().
Those are all public libkrb5 APIs. Avoid using the krb5_appdefault_*()
interfaces; they are pretty broken.

Heimdal has krb5_config_get_*() interfaces, which I think is a cleaner
solution, but we wouldn't get a lot of benefit out of implementing them
since we're stuck supporting the profile APIs indefinitely.
Post by Ken Hornstein
The second thing I've run into is storing per-principal information.
I know about the set_strings/get_strings interface; we use that, and
it's great! But we have some cases where the plugin needs to modify
some data associated with the principal, and there is no set_strings
interface. I know there's a callback to retrieve the principal record,
but I was wondering if that's the preferred method for storing stuff,
or if there should be an additional callback to store string data
(or TL_DATA) on a per-principal bases.
For the moment, using the client_entry callback and libkdb5 is the only
way to do this.

We could consider adding a set_string callback, but it would raise
architectural issues. The KDC was originally a read-only consumer of
the KDB, unless built with KRBCONF_KDC_MODIFIES_KDB. We changed that
(conditionally) when we implemented account lockout, but that change
hasn't been consequence-free for performance and concurrency behavior.
It might have been better--although much more difficult--if we had
implemented a second, non-replicated database for ephemeral principal
data such as lockout counters.
_______________________________________________
krbdev mailing list ***@mit.edu
https://mailman.mit.edu/mailman/listinfo/krbdev
Ken Hornstein
2015-05-18 21:07:45 UTC
Permalink
Post by Greg Hudson
Post by Ken Hornstein
I know that doing your own PKINIT plugin requires a lot of internal
interfaces and changing that is hard.
If you have another way of doing ASN.1 (such as asn1c), you could
implement PKINIT without internal interfaces, in principle.
Yeah, but ... who really wants to do that?
Post by Greg Hudson
Of course, if you want to copy and modify the existing PKINIT module,
our use of internal interfaces for ASN.1 (and possibly other things) is
prohibitive. The only really practical solution is to fork the whole
tree, modify it, build it, and install only the PKINIT module. We'd
rather it not be necessary to modify PKINIT, and I think we've discussed
what is required for that for your case and just haven't done the work.
Right, right ... I didn't want to come across like I was blaming you guys.
I got busy and didn't get a chance to work on giving you my changes.

However ... it does in my mind at least raise the larger issue is that it
would be nice for plugins to have the ability to access the ASN.1 encoding/
decoding routines for various Kerberos messages (I am thinking of SAM2
in particular). I am not sure if there is some way to pass up the expanded
structure for the upper-level library to encode/decode (I know that the
way SAM2 works this is particular problematic). Just thinking out loud
here; it's not an easy problem.
Post by Greg Hudson
You can call krb5_get_profile(), profile_get_*(), and profile_release().
Those are all public libkrb5 APIs. Avoid using the krb5_appdefault_*()
interfaces; they are pretty broken.
Hm, I thought those were private, but I see now that they are in profile.h.
My apologies!
Post by Greg Hudson
Post by Ken Hornstein
The second thing I've run into is storing per-principal information.
I know about the set_strings/get_strings interface; we use that, and
it's great! But we have some cases where the plugin needs to modify
some data associated with the principal, and there is no set_strings
interface. I know there's a callback to retrieve the principal record,
but I was wondering if that's the preferred method for storing stuff,
or if there should be an additional callback to store string data
(or TL_DATA) on a per-principal bases.
For the moment, using the client_entry callback and libkdb5 is the only
way to do this.
Fair enough; if that's the answer then I can live with that; I can understand
the issues with making set_strings public from the plugin API, but those
are consequences we've been living with and haven't really been a problem
for us.

Looking at other internal interfaces .... I see that I currently use
krb5int_c_combine_keys() and krb5int_c_mandatory_cksumtype(). The
former, okay, I know you're not crazy about exposing that one. But
how about the latter?

--Ken
_______________________________________________
krbdev mailing list ***@mit.edu
https://mailman.mit.edu/mailman/listinfo/krbdev
Greg Hudson
2015-05-18 22:21:37 UTC
Permalink
Post by Ken Hornstein
However ... it does in my mind at least raise the larger issue is that it
would be nice for plugins to have the ability to access the ASN.1 encoding/
decoding routines for various Kerberos messages (I am thinking of SAM2
in particular). I am not sure if there is some way to pass up the expanded
structure for the upper-level library to encode/decode (I know that the
way SAM2 works this is particular problematic). Just thinking out loud
here; it's not an easy problem.
We could expose structures and encoder functions which are currently
internal, at the cost of significantly increasing our API surface. But
most of the time plugin modules want to encode structures we don't
already have internal encoders for, which make use of RFC 4120 or other
existing Kerberos types.

Exposing a generally extensible ASN.1 framework is on our wishlist, but
it's not an easy problem (I'll skip the essay on why this is).
Post by Ken Hornstein
Looking at other internal interfaces .... I see that I currently use
krb5int_c_combine_keys() and krb5int_c_mandatory_cksumtype(). The
former, okay, I know you're not crazy about exposing that one. But
how about the latter?
I don't think there's really anything stopping us from exposing a
krb5_c_mandatory_checksum() function. The internal function was added
in 2003 by Ken Raeburn with a "Not sure it's ready for exposure just
yet" comment. My guess is that he had concerns about the answers for
DES enctypes, which I think were resolved in 2010 by SA-2010-007.

However, since 1.8 it's been possible to pass a checksum type of 0 to
krb5_c_make_checksum() to use the mandatory checksum type. That covers
most of the reasons one would want to use krb5_c_mandatory_checksum(),
removing a lot of the impetus for doing the (relatively minimal) work of
exposing it. We can still do it if there's a need.
_______________________________________________
krbdev mailing list ***@mit.edu
https://mailman.mit.edu/mailman/listinfo/krbdev

Loading...