Subject: Re: [kitten] gss_userok

From: Simon Josefsson <[email-masked]>
Date: Tue, 05 Apr 2011 21:05:32 +0200

[email-masked] writes:

> I just merged Luke's implementation gss_userok to the MIT krb5 trunk,
> and Sam brought to my attention that it conflicts with the Gnu GSS
> version of the symbol, which has the prototype:
>
>   int gss_userok(const gss_name_t name, const char *username);
>
> The version Luke committed is based on OpenSolaris's private
> __gss_userok():
>
>   OM_uint32 __gss_userok(OM_uint32 *minor, const gss_name_t name,
>                          const char *user, int *user_ok);
>
> We don't want to conflict with Shishi, but we do want the major and
> minor return codes; we believe an app should get "I ran into an error
> trying to find the answer" rather than just "no" if something goes
> wrong.  So, our plan is to rename the symbol to gss_login_ok() and
> make a wrapper for the Gnu GSS gss_userok().
>
> I think this is all pretty straightforward, but I wanted to raise the
> issue here in case other implementors thought we should do something
> different.

That sounds good to me (thanks for renaming it rather than using the
same name) -- but are you sure the semantics for these functions are the
same?

The documentation for my gss_userok is this:

 * Compare the username against the output from gss_export_name()
 * invoked on @name, after removing the leading OID.  This answers the
 * question whether the particular mechanism would authenticate them
 * as the same principal

It is thus only a convenience function that could be implemented by the
application.

I recall seeing some "userok" functions that did more than just name
comparisons, e.g. doing some mechanism-dependennt authorization decision
involving files in user's home directory.  I'm not sure which semantics
it is that you are after.

/Simon

---

From: Luke Howard <[email-masked]>
Date: Wed, 6 Apr 2011 09:48:29 +1000

> it is that you are after.

The MIT and Heimdal implementations have three strategies:

* mechanism specific (for the krb5 mech, krb5_aname_to_localname)
* attribute based (look for a match against the local-login-user GSS attribute)
* name based (import username, canonicalize and compare)

See below:

        /* If mech returns yes, we return yes */
        major = mech_userok(minor, unionName, user, user_ok);
        if (major == GSS_S_COMPLETE && *user_ok)
                return (GSS_S_COMPLETE);

        /* If attribute exists, we evaluate attribute */
        if (attr_userok(minor, name, user, user_ok) == GSS_S_COMPLETE)
                return (GSS_S_COMPLETE);

        /* If mech returns unavail, we compare the local name */
        if (major == GSS_S_UNAVAILABLE) {
                major = compare_names_userok(minor, unionName->mech_type,
                                             name, user, user_ok);
        }

-- Luke

---

From: Luke Howard <[email-masked]>
Date: Wed, 6 Apr 2011 10:22:57 +1000

> * mechanism specific (for the krb5 mech, krb5_aname_to_localname)

Sorry, that should have been krb5_kuserok.

-- Luke

---

From: Nico Williams <[email-masked]>
Date: Tue, 5 Apr 2011 20:07:27 -0500

>  * Compare the username against the output from gss_export_name()

How could that work?!

>  * question whether the particular mechanism would authenticate them

I don't follow.

> It is thus only a convenience function that could be implemented by the

Of course.  But the mechanism provider too could implement it.  And so
could the mechglue.  The Solaris version lets the mechanism provider
implement it.

> it is that you are after.

So, traditionally krb5_kuserok() did aname2lname and ~/.k5login
processing.  And I'd be happy to see any number of alternatives.  The
semantics of this function are that it answers with a boolean the
question of "does this principal have the right to login to this local
account?".

Nico
--

---

From: Greg Hudson <[email-masked]>
Date: Wed, 06 Apr 2011 11:29:55 -0400

> same name) -- but are you sure the semantics for these functions are the

No, which argues against creating a wrapper for your prototype.

However, I'm confused about your semantics.  First, why are you
specifying the implementation of the function as part of the API
contract?  Does the app want to know how the decision is made, or does
it just want to ask a question (is this MN authorized to login as this
user according to the mechanism's logic)?

Second, to the best of my understanding, gss_export_name() isn't
intended to output anything like a username (with OID prefix).  It's
just intended to produce a string which compares equal to the same name
exported within another process.  So if you are going to specify the
function's implementation, the specification you chose doesn't seem
conceptually consistent with the design of GSSAPI.  Sun's fallback if
the mech doesn't implement a userok handler seems more consistent:

  1. gss_import_name() username with name type GSS_C_NT_USER_NAME
  2. gss_canonicalize_name() the result with name's mech
  3. gss_compare_name() the result to name

---

From: Nico Williams <[email-masked]>
Date: Wed, 6 Apr 2011 10:38:56 -0500

> the mech doesn't implement a userok handler seems more consistent:

I made this point too.  If it doesn't work in Shishi (and I fail to
see how it works as described, but then, I suspect Simon just flubbed
the description) then I'll be much less inclined to accept the Shishi
prototype.  But also, quite separately, the specific details of how
the function works are implementation-specific -- what matters is what
the function is supposed to do, not how it works.

BTW, we really need to get the IANA registry going.  These sorts of
conflicts will only arise more often now that we have so many GSS
mechglues (Shishi, MIT, Heimdal, and Solaris').

Nico
--

---

From: Martin Rex <[email-masked]>
Date: Wed, 6 Apr 2011 22:25:06 +0200 (MEST)

> user according to the mechanism's logic)?

Standardizing a GSS-API function without nailing down the exact
semantics would seem strange to me.

gss_userok() appears to be an extremely Kerberos5-specific function
and even there, it appears to be inherently non-portable.
Only the application knows the exact usage/purpose of the
authentication (file access, shell-acces, ftp access, pop/imap access,
web-shop access, discussion forum access).

Even Microsoft makes a careful distinction between "network logon"
and "interactive logon", in that domain users are usually allowed
to access a servers file shares (relying on the ACLs to provide
access control), while disallowing interactive logon for mere
domain users as a security precaution.

The described gss_userok() semantics do not make sense for GSS-API
mechanisms that are not used by the OS itself but only by the
application to distinguish application-level users.  The latter
is actually the more common situation when using GSS-API with
our apps.  Most of the (~20) GSS-API mechanisms that can be
used with our application are not integrated with the logon of
the underlying OS.

In order to support rfc4559 (HTTP Negotiate) with Kerberos, all
the app would have to do is implement unpacking of AP_REQ and
creation of AP_REP.  There is no need for the underlying OS to
be aware of any of the users that are authenticating, it is
perfectly sufficient if the application is able to distinguish
users.

When Apps are using with PKI-based SSO-Infrastructures where some
of the communication protocols are using GSS-API for authentication
and others use TLS with client certs, then it is not unusual
that the TLS client cert authenticated users are not even visible
to the underlying OS.  The application will likely want to use
a unified approach to distinguish clients, independent on whether
they use a communication protocol with GSS-API and client cert
or a Web Browser with TLS client cert.

-Martin

---

From: Greg Hudson <[email-masked]>
Date: Wed, 06 Apr 2011 18:12:04 -0400

> semantics would seem strange to me.

Really?  The exact semantics of, say, gss_acquire_cred are
mech-dependent.  Even if you delve into the mechanism standards, they
typically only define token formats; the details of things like
credential management are implementation-dependent.

The proposed gss_userok() (Solaris version) has fewer constraints than
something like gss_acquire_cred, but that's only because the answer is
so simple (yes or no).

> and even there, it appears to be inherently non-portable.

I don't think it's krb5-specific at all; it assumes that the mechanism
has its fingers in the login authorization pie, but any mechanism could
do that.  (The krb5 team isn't wild about having its fingers in that
pie, but the logistics of pulling our fingers out aren't attractive.  A
krb5-specific PAM module is the only other likely owner of that pie, and
not every user of krb5_kuserok() necessarily wants to use PAM.)

It's non-portable to some extent; a platform may or may not have a
concept of "login".  Within the space of POSIX platforms it's portable.

> web-shop access, discussion forum access).

If the application integrates with system accounts (sshd, ftpd) then it
could have an interest in this function.  If the application has its own
concept of users, then it wouldn't be interested (although Sam may
disagree on that).

> used with our application are not integrated with the logon of

So, you probably wouldn't use such a mechanism with an application like
sshd or ftpd.  If you did, gss_userok() would probably just always say
no.  (In the Solaris implementation, if the mech doesn't have a
gss_userok function, the mechglue performs a check using
import/canonicalize/compare, and a mech like you posit would probably
just refuse to import a username.)

> In order to support rfc4559 (HTTP Negotiate) with Kerberos[...]

I wouldn't expect an httpd to use gss_userok, unless it was running as
root on a POSIX-ish system and trying to behave like an ftpd.

---

From: Nico Williams <[email-masked]>
Date: Wed, 6 Apr 2011 19:12:27 -0500

> semantics would seem strange to me.

Just what are you (and Simon) going on about?  The semantics are
nailed down (the function is a boolean predicate answering the
question "is the given principal allowed access to the named user
account?").  Simon didn't think so and then asked about what we should
all consider _implementation_-specific behaviors, not semantics.
Maybe I'm missing something, maybe the implementation of MIT krb5's
krb5_userok() is actually semantics and I just have a completely
different understanding or expectation of where the line is between
semantics and behavior that is/should be implementation-specific, but
I don't think so.

> and even there, it appears to be inherently non-portable.

In Solaris it also works for mech_dh.  So, it's NOT
mechanism-specific.  I have an existence proof.  Q.E.D.

This function *is* specific to something though: to operating systems
with a notion of user account that is distinct from GSS principal
names.  That's *all* multi-user operating systems that I'm aware of,
pretty much.  In other words: this is a theoretically not generic API,
but in practice it's quite generic.

> web-shop access, discussion forum access).

True.  That's why the function refers to a whole user account and
assumes full access.  If you want fine-grained authorization wrapped
in a GSS function or set of functions, well, that's going to be a lot
more operating system- and even application-specific, which is to say:
not standardizable.  And yet, so many programs are happy with a
userok() type function, and so many sysadmins are happy to allow it:
because it's useful enough and a whole lot better than nothing.

> domain users as a security precaution.

Understood.  I assert that's not an issue here.  I suppose we could
add arguments to distinguish between types of login, but we'll quickly
reach the limit of what we can reasonably standardize.

> used with our application are not integrated with the logon of

This is true.  Such applications must not use this function.  What
does this say about whether we should or should not standardize this
function?

Nico
--