Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Method to check quickly whether krb5_kuserok or krb5_verify_init_creds could ever pass? #1157

Open
riastradh opened this issue Jun 15, 2023 · 11 comments

Comments

@riastradh
Copy link

The NetBSD pam_ksu module has a bug causing su(1) to hang on network access if you have /etc/krb5.conf or ~/.krb5/config, even if the host has no /root/.k5login or keytabs (https://gnats.netbsd.org/57470).

This happens because pam_ksu does various work to determine a default realm and KDC and principal before it can determine whether that principal is authorized by /root/.k5login, via krb5_kuserok, or the user has or can get a valid service ticket, via krb5_verify_init_creds (with ap_req_nofail=1 hard-coded so that there's no exploitable hole).

What's the best way to skip all this early, so that enabling a seamless client-side SSO experience by creating an empty ~/.krb5/config or /etc/krb5.conf doesn't cause hiccups in unrelated things like local su(1) on an otherwise non-kerberized host?

  1. Skip if there's no user principal krb5_kuserok could possibly pass with because there's no /root/.k5login.
    • There's a snag here: The SIMPLE kuserok rule might apply. But in this case, it makes no sense because the context is switching users, so presumably there's no reason to even check if the calling user and the target user are the same.
  2. Skip if there's no service principal krb5_verify_init_creds could possibly pass with because's no keytab.
@nicowilliams
Copy link
Contributor

What does pam_ksu do?

@nicowilliams
Copy link
Contributor

Accessing ~/.krb5/config could have other I/O problems if $HOME is NFS-mounted, or similar.

This happens because pam_ksu does various work to determine a default realm and KDC and principal before it can determine whether that principal is authorized by /root/.k5login, via krb5_kuserok, [...]

So there's a system keytab but no /etc/krb5.conf?

Determining what the "default realm" is in a zero-conf way is hard, and possibly the hardest zero-conf problem facing Heimdal and MIT Kerberos. We should really dispense with the concept of trying to determine it. If you enter a principal name not qualified by a realm name and the host does not know anything like a default_realm then that could just be a "too bad, you lose" situation, or if we have something like a keytab or PKINIT certificates we could try all the realm names we can glean from those.

@riastradh
Copy link
Author

What does pam_ksu do?

Decides whether a calling user is authorized to switch to a target user with su(1).

Accessing ~/.krb5/config could have other I/O problems if $HOME is NFS-mounted, or similar.

True. A reliable way to avoid both problems would be to disable pam_ksu. But it is on by default in NetBSD and has been for a long time; whether to disable it by default is a separate issue.

This happens because pam_ksu does various work to determine a default realm and KDC and principal before it can determine whether that principal is authorized by /root/.k5login, via krb5_kuserok, [...]

So there's a system keytab but no /etc/krb5.conf?

No, other way around: there is a ~/.krb5/config (or /etc/krb5.conf) but no system keytab and no /root/.k5login.

The scenario is that I'm using krb5 purely for client-side SSO on my laptop to authenticate to remote systems, but creating ~/.krb5/config for that purpose had the side effect of making local su(1) hang waiting for network access.

@nicowilliams
Copy link
Contributor

Ouch. That's very painful. A bit of a deadly embrace. Hmmm.

Also, it seems like a very bad idea for pam_ksu to read ~/.krb5/config, and if su is set-uid, it really shouldn't read it because of this at line 47:

 39 heim_context
 40 heim_context_init(void)
 41 {
 42     heim_context context;
 43
 44     if ((context = calloc(1, sizeof(*context))) == NULL)
 45         return NULL;
 46
 47     context->homedir_access = !issuid();
 48     context->log_utc = 1;
 49     context->error_string = NULL;
 50     context->debug_dest = NULL;
 51     context->warn_dest = NULL;
 52     context->log_dest = NULL;
 53     context->time_fmt = NULL;
 54     context->et_list = NULL;
 55     return context;
 56 }

Is su(1) not set-uid on NetBSD? Is Heimdal's issuid() broken on NetBSD?

@riastradh
Copy link
Author

Also, it seems like a very bad idea for pam_ksu to read ~/.krb5/config,

I thought about that, but the main risk I see is that parsing user-controlled input is fraught with peril. I would hope that the Heimdal krb5.conf parser is robust, of course, but perhaps that's naive optimism shining through. Are there other risks than that? Surely, even if the user's ~/.krb5/config file points to a malicious KDC, nothing should be able to bypass (a) /root/.k5login, or (b) krb5_verify_initial_creds with /etc/keytab, right?

and if su is set-uid, it really shouldn't read it because of this at line 47:

 39 heim_context
 40 heim_context_init(void)
[...]
 47     context->homedir_access = !issuid();
[...]

Is su(1) not set-uid on NetBSD? Is Heimdal's issuid() broken on NetBSD?

This logic appears to be new since Heimdal 7.7.0, which is what NetBSD currently ships with. (To be updated soon, probably once the openssl3 dust settles.)

That said, ~/.krb5/config aside, it would be nice if an empty /etc/krb5.conf could enable seamless client-side SSO without triggering any similar misbehaviour.

@nicowilliams
Copy link
Contributor

Also, it seems like a very bad idea for pam_ksu to read ~/.krb5/config,

I thought about that, but the main risk I see is that parsing user-controlled input is fraught with peril. I would hope that the Heimdal krb5.conf parser is robust, of course, but perhaps that's naive optimism shining through. Are there other risks than that? Surely, even if the user's ~/.krb5/config file points to a malicious KDC, nothing should be able to bypass (a) /root/.k5login, or (b) krb5_verify_initial_creds with /etc/keytab, right?

Apart from parsing robustness concerns one might have to think about how any of the many parameters in the configuration might affect pam_ksu's behavior. I certainly have not done that thinking.

Is su(1) not set-uid on NetBSD? Is Heimdal's issuid() broken on NetBSD?

This logic appears to be new since Heimdal 7.7.0, which is what NetBSD currently ships with. (To be updated soon, probably once the openssl3 dust settles.)

I see. Well, we really need to do an 8.0 release. The issues w.r.t. kinit and cache collections are among the blocking issues. In the meantime, I'd advise backporting issuid() and use of secure_getenv().

That said, ~/.krb5/config aside, it would be nice if an empty /etc/krb5.conf could enable seamless client-side SSO without triggering any similar misbehaviour.

Even a missing /etc/krb5.conf ought to work well enough. My thinking w.r.t. to default_realm is that we should not try to guess what it is in any way that does network I/O. But that will probably break backwards compatibility, so either we do that only in 8.0 or we provide config parameter to re-enable default_realm lookup or a ./configure option to enable it by default at build configuration time.

@elric1
Copy link
Member

elric1 commented Jun 16, 2023

I gave this some thought quite some time ago w.r.t. NetBSD's behaviour vis a vis Kerberos. I have always felt deeply unsatisfied that the presence of krb5.conf(5) has been used by NetBSD to enable or disable Kerberos. This is quite broken behaviour because you should be able to use Kerberos in a zero-conf way without /etc/krb5.conf. The reason that NetBSD chose to do this was because Kerberos was hard-coded in the login logic in the days before PAM.
Now that we have PAM, surely the most obvious solution to these issues would be to comment out the Kerberos lines in the PAM stacks by default?
In all honesty, a properly run Kerberos shop should be quite picky about where you accept a Kerberos passwd as you should be using proper Kerberos authn everywhere except logging into a physical terminal. Putting Kerberos PAM modules in place for things like su is encouraging people to have practices which are not uniformly recommended. E.g. I kinit to elric/root on my desktop and SSH into my servers when I need root rather using su or sudo once I am there. Sending your password over the wire is exactly what Kerberos was designed to avoid, after all.

@elric1
Copy link
Member

elric1 commented Jun 16, 2023

NetBSD's PAM stack also should not be reaching through the layers of abstration. Assuming that /etc/krb5.conf has a meaning to Heimdal is not part of the promise that Heimdal makes to its developers, it is an internal config file. Checking for ~/.krb5/config as well shows this quite well. When NetBSD embarked on its path of checking /etc/krb5.conf, it took on the task of examining and adapting to every future update to Heimdal's configuration.

@riastradh
Copy link
Author

I gave this some thought quite some time ago w.r.t. NetBSD's behaviour vis a vis Kerberos. I have always felt deeply unsatisfied that the presence of krb5.conf(5) has been used by NetBSD to enable or disable Kerberos. This is quite broken behaviour because you should be able to use Kerberos in a zero-conf way without /etc/krb5.conf.

Yes. I'm trying to shake out all the issues that get in the way of having kinit and client-side SSO just work out of the box with zero configuration.

The reason that NetBSD chose to do this was because Kerberos was hard-coded in the login logic in the days before PAM. Now that we have PAM, surely the most obvious solution to these issues would be to comment out the Kerberos lines in the PAM stacks by default?

Personally I have no objection to that. Of course, this poses compatibility issues for anyone who has been using pam_ksu (and, similarly, pam_krb5) for password entry -- an incautious update could lock you out if you relied on that. Probably better to discuss that question in a NetBSD forum like tech-security@ (maybe with a poll of netbsd-users@) rather than here, though!

@elric1
Copy link
Member

elric1 commented Jun 16, 2023

Personally I have no objection to that. Of course, this poses compatibility issues for anyone who has been using pam_ksu (and, similarly, pam_krb5) for password entry -- an incautious update could lock you out if you relied on that. Probably better to discuss that question in a NetBSD forum like tech-security@ (maybe with a poll of netbsd-users@) rather than here, though!

Agreed. Essentially, I think that turning on SSO should be a conscious choice by the user and that PAM is the logical place to make said choice as you may very well say: I'd like krb5 for xdm (or display_manager on NetBSD) but not SSH or su. Conditionalising things on /etc/krb5.conf is confusing (as no one else does it) and not granular enough.

I do think, though, that Heimdal could modify krb5_verify_user(3) to check that a keytab is present if krb5_verify_opt_set_secure(3) has been set to true and fail early if there is no possibility that it could verify that the user's tickets are valid.

@nicowilliams
Copy link
Contributor

nicowilliams commented Jun 16, 2023

I'd expect that a pam_ksu would return PAM_IGNORE unless it has a keytab -- it shouldn't even bother to try anything if there's no keytab. Only by having a keytab could it truly authenticate the user with Kerberos, therefore no keytab -> no Kerberos. Therefore it is having a keytab and not a krb5.conf that matters.

True, the verify_ap_req_nofail setting should default to not needing a keytab. Even better: since only the krb5_verify_init_creds() API uses that setting, we should just remove it and always insist on verifying the credentials using a keytab.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants