Subject: Re: Pluggable GSSAPI

From: Martin Rex <[email-masked]>
Date: Wed, 2 May 2007 12:14:33 +0200 (MEST)

Nicolas Williams wrote:
> 
> In the C bindings the minor_status parameter is always a OM_uint32 *, it
> is always a pointer.  And my proposal doesn't change the type, it's
> backwards compatible, both for binaries and source.

I'm sorry, but you appear to be misled.

Look at the function signature of gss_display_status again:
(taken from the sample header in rfc-2744, where I just noticed
 that it lacks an asterisk...):

   OM_uint32 gss_display_status
                 (OM_uint32 *,            /* minor_status */
                  OM_uint32,              /* status_value */
                  int,                    /* status_type */
                  const gss_OID,          /* mech_type */
                  OM_uint32 ,             /* message_context */
                  gss_buffer_t            /* status_string */
                 );

The minor_status that gss_display_status() translates into text
is the second function parameter and a 32-bit integer, NOT a pointer.
The first argument to all gss_api functions is a return parameter
to this particular function, and for gss_display_status(), it is
likely a local scratch variable that will get ENTIRELY ignored.

Quoting from MIT's krb5-1.0.5 gss-sample/gss_misc.c:

    static void display_status_1(m, code, type)
         char *m;
         OM_uint32 code;
         int type;
    {
         OM_uint32 maj_stat, min_stat;
         gss_buffer_desc msg;
         OM_uint32 msg_ctx;

         msg_ctx = 0;
         while (1) {
              maj_stat = gss_display_status(&min_stat, code,
                                           type, GSS_C_NULL_OID,
                                           &msg_ctx, &msg);
              if (display_file)
                  fprintf(display_file, "GSS-API error %s: %s\n", m,
                          (char *)msg.value);
              (void) gss_release_buffer(&min_stat, &msg);

              if (!msg_ctx)
                   break;
         }
    }

> 
> > I have seen gssapi mechanism that keep additional state around
> > for failed gssapi calls in a pretty useful and fairly robust
> > fashion.
> 
> Only by making assumptions about the app's thread model.

Wrong.  The GSS-API doesn't deal with multi-threading at all,
so first of all the app MUST apply the necessary precaution when
it does use multi-threading -- in particular if the app wants to
be a portable app and run with arbitrary gssapi mechanisms.

For multi-threading, this usually means that the app needs to
use locking around each GSS-API call, and in the particular
case here, the app should hold the lock until after any successor
call to gss_display_status() after a failed gss-api call.

The app also needs to make sure that the same lock is used
for all "protocol abstractions" that might involve the usage of
the same gssapi mechanism with the apps process space -- which
might be challenging for complex apps, in particular on Microsoft
Windows platforms where code duplication in DLLs is much more common
than on Posix platforms.

If you need efficient multithreading support for GSS-API plus
plug'n'play with arbitrary mechanisms, you should really work
hard and fast on a GSS-API v3 that provides the necessary API calls
(init/finis) and documents exactly what level of concurrency a
compliant mechanism must provide.

> 
> > They keep a small ring buffer of dynamically allocated failure messages
> > for failed gssapi calls and they related by minor_status code only.
> > If one cares for thread-safety, using a small ring buffer per-thread
> > might do for that.  Cleaning up dynamic thread local storage
> 
> That won't suffice: it assumes threads don't do GSS work for multiple
> different peers.  In today's world lots of multi-threaded apps don't
> dedicate a thread to each peer, instead they are async apps that use
> threads for concurrency.

Huh?  Of course that is sufficient.  If the app calls gss_display_status()
right after the failed GSS-API call, then this works perfectly fine and
100% reliable.

-Martin

_______________________________________________
Kitten mailing list
[email-masked]
https://www1.ietf.org/mailman/listinfo/kitten

---

From: Jeffrey Hutzelman <[email-masked]>
Date: Thu, 03 May 2007 21:37:32 -0400

> I'm sorry, but you appear to be misled.

Nope.  He said that "minor_status" is always a pointer, and he is correct. 
He said nothing about the "status_value_ parameter to gss_display_status. 
You're the one who keeps bringing up the issue of the type of that 
parameter, which is irrelevant to Nico's proposal.

> is the second function parameter and a 32-bit integer, NOT a pointer.

Correct.  However, you're missing Nico's point.  His proposal is to provide 
a new operation like this:

OM_uint32 gss_create_app_context(OM_uint32 *minor_status);

This operation returns results as usual, by returning the major status and 
storing the minor status in *minor_status.  However, if it succeeds it also 
has the side-effect of informing the GSS provider that any future calls to 
GSS-API functions with the same minor_status parameter (that is, the same 
_pointer_, not the same pointed-to value) are part of the same application 
context.  This information can be used by the provider to associate a 
context with parameters (set by additional new API functions), and also to 
remember complex error state.

So, as an example, when a GSS-API call fails in a way that makes it 
desirable to pass back dynamic error state(*), it can allocate a dynamic 
minor status value and store the mapping from that value to the complete 
error information with the context.  Then when gss_display_status is called 
with "minor_status" being the same pointer as used in previous calls, and 
status_value set to the dynamically-allocated value, it can look at the 
context to find the detailed information required to construct a status 
string for that value.

Note that, as Nico pointed out, all of this functionality applies only to 
applications which call gss_create_app_context.  By making that call, such 
applications indicate that they want the features provided by app contexts 
and agree to obey the additional constraints imposed by the extended 
interface.  For example, they MUST use the registered minor_status pointer 
for all GSS-API calls which are part of that context (note that the pointer 
is still a pointer to an OM_uint32 and is still used to return minor_status 
values), and they MUST use gss_display_status rather than attempt to 
interpret or display minor status values directly.

(*) Yes, there are situations in which dynamically-allocated minor status 
values and additional error information are relevant, and a 32-bit 
namespace with static meaning simply will not cut it.  For example, a krb5 
mechanism implementation that fails to find a service key may wish to 
report the name, enctype, and kvno of the service key it as unable to find. 
Two of these are permitted to be arbitrary 32-bit integers, and the third 
has a namespace much larger than that.

> call to gss_display_status() after a failed gss-api call.

And this is an assumption you make about the app's threading model.  There 
is nothing in the GSS-API which requires applications to behave in this 
way, and while it is generally accepted that holding a lock around each 
call is required, there is nothing in the GSS-API spec which suggests that 
an application would need to hold a lock around multiple calls in order for 
a call to gss_display_status to return meaningful results.

> right after the failed GSS-API call

Sounds like another assumption to me, or perhaps the same one.  When 
designing an API, and especially when extending an existing one, you don't 
get to make assumptions about what applications do that go beyond what the 
spec says the MUST do.  The GSS-API spec does not discuss threading at all; 
it certainly does not specify that an application wishing to get meaningful 
results from gss_display_status MUST make the gss_display_status call 
before making any other GSS-API call in the same thread.

Nico....

I think I like your proposal.  It is elegant and probably qualifies as a 
hack (sense 2).  However, it has a fatal flaw - if Martin didn't see what 
you were getting at, than neither will most mere mortals.  I think that in 
the name of sanity, we need to pass on this one.

I think I'm beginning to agree with Jeff on this one - skip the band-aids 
on GSSAPIv2, and deal with this properly in v3.

-- Jeff

---

From: Martin Rex <[email-masked]>
Date: Fri, 4 May 2007 06:04:52 +0200 (MEST)

> remember complex error state.

That would mean that perfectly correct GSS-API v2 application will
receive a much less useful error information than GSS-API v2.5
apps that know how to frob gss_create_app_context()?

Which would mean that this is *NOT* about a fully backwards compatible
change for GSS-API v2 -- I explicitly asked about this!

If you want a feature with GSS-API v2, then by all means make it
work fully and correctly with the existing spec and portable
apps based on it.

Otherwise make the necessary changes to the API that you need
and go for a backwards incompatible GSS-API v3.

A truely portable application should be perfectly fine with a
very small number of static buffers.   Make it per thread
if your mechanism is offering multi-threading beyond GSS-API v2
and the application (ab)uses this.

An application with massive parallelism (whether multi-threaded
or single-threaded asynchronus) that does *NOT* pick up and
error code directly after a failed GSS-API call deserves to loose
because it is severely broken.

-Martin

---

From: Nicolas Williams <[email-masked]>
Date: Thu, 3 May 2007 23:50:20 -0500

> apps that know how to frob gss_create_app_context()?

No, they *already* receive much less useful error information than they
_could_ with this extension.

> change for GSS-API v2 -- I explicitly asked about this!

Your facts are incorrect (see above), so we don't necessarily have to
debate the merits of this [astounding and truly tyranical] view of
backward compatibility.

Can you actually find a valid technical argument against the proposal?

If not then please say so and then attack the proposal from a stylistic
or idealistic p.o.v.

E.g., "this feels odd and will be difficult to explain without
explaining the history of it, so why not do the gss3_* thing instead?"

Such arguments are legitimate.  They're also subjective.  As is any
argument for my proposal.

This is a choice between pragmatism (incremental change) and. idealism
(start from scratch).

I can be idealistic at times, so I'm sympathetic.  I can also be
pragmatic.

And let's be absolutely clear: even GSSv3 would have to be backwards
compatible with GSSv2 at the application protocol level.  Oh, sure, we
might introduce new token types for new functionality, but they'd never
be produced where app protocols that use GSSv2 wouldn't expect them.  I
mention this because if you care about the GSS-APIv2u1 then you cannot
say "you can't touch this, but you can do what you like in GSSv3" and
wash your hands -- you'd have to continue to pay attention and seek to
protect the protocol from our supposedly misguided efforts.

Both, this proposal (OK, let's call it GSSv2.5) and a GSSv3 approach
require some minor editing of existing GSS application code, but the
pragmatic approach, GSSv2.5, requires somewhat less editing of
application code and *much* less editing of framework/ mechanism code,
which means it should be much easier to implement and deploy quickly
(meaning: at all).

Nico
--

---

From: Jeffrey Hutzelman <[email-masked]>
Date: Fri, 4 May 2007 14:12:30 -0400 (EDT)

> apps that know how to frob gss_create_app_context()?

Well, yes.  The proposed new interface makes it possible for the GSS-API
provider to provide more detailed information than is possible under the
current GSS-APIv2 interface.  Existing apps should get as much
information as they always have; the fact that they can't get more is not
reason to impose that limitation on new applications.

> change for GSS-API v2 -- I explicitly asked about this!

Yes, it is backward-compatible.  Existing applications will continue to
work the same as they always have.

> A truely portable application

You keep using this phrase, but what you mean is "an application that not
only complies with the spec, but with my preconceptions about what
mechanisms must and must not do based on how my own application behaves.
I understand you have a fairly complete test suite for verifying that
GSS-API mechanisms will work with SAP, and it's useful for finding
problems with mechanism implementations.  However, the GSS-API
specification is defined byb RFC2743, not by your test suite or by your
memory of what you or anyone else might have been thinking when it was
written.

> because it is severely broken.

Again, you are conflating "does not meet my expectations" with "severly
broken".  They are not the same thing, and you need to stop making
assertions to the effect that anything that does not conform to your
expectations or philosophy is "broken" or "deserves to lose".  That is not
how reasonable people develop protocol or API standards.

-- Jeff