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

Implement PAM authentication module for GLOME #73

Merged
merged 1 commit into from
Jan 12, 2021

Conversation

vvidic
Copy link
Collaborator

@vvidic vvidic commented Dec 20, 2020

Reuses much of the existing glome-login functions.

@vvidic
Copy link
Collaborator Author

vvidic commented Dec 20, 2020

Fixes #39

Copy link
Collaborator

@burgerdev burgerdev left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks a lot for your PR, it's much appreciated!

login/pam.c Show resolved Hide resolved
}

int pam_sm_setcred(pam_handle_t *pamh, int flags, int argc, const char **argv) {
return PAM_SUCCESS;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Intuitively, I would have expected a PAM_CRED_UNAVAIL or PAM_CRED_ERR, and after reading the docs I'm confused. Could you please document the reason for returning success?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added a comment for PAM_SUCCESS in the new version of the patch.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But if we return PAM_SUCCESS here, applications will see pam_setcred(3) return with PAM_SUCCESS as well, won't they? According to the manual, this return value should be interpreted as Data was successful stored, and since we're not storing anything may be disingenuous.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PAM_CRED_UNAVAIL: This module cannot retrieve the user's credentials. sounds correct to me.

login/pam.c Outdated Show resolved Hide resolved
login/pam.c Outdated
Comment on lines 41 to 47
config->reboot_user = DEFAULT_REBOOT_USER;
config->login_path = DEFAULT_LOGIN_PATH;
config->lockdown_path = NULL;
config->url_prefix = NULL;
config->auth_delay_sec = DEFAULT_AUTH_DELAY;
config->input_timeout_sec = DEFAULT_INPUT_TIMEOUT;
config->options = SYSLOG;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some of these options are imho not relevant for the PAM module:

  • auth_delay_sec should probably be implemented with pam_faildelay
  • Not entirely sure about input_timeout_sec, but I did not find other PAM modules with a configurable timeout.
  • Lockdown path is a runtime environment detail that should be handled outside of the GLOME module (c.f. pam_time).
  • The PAM module arguably should not cause reboots, so we don't need to know about a reboot_user.
  • The same goes for login_path.

Actually, I think it might be better not to use the configuration facilities of /sbin/glome-login at all and rather implement only the strictly necessary options (service key, debug, machineid?) as PAM module arguments.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed the parameters that are not relevant for PAM module.

As for input_timeout_sec it seems that PAM prompt waits 60 seconds for input so this should work by default too.

Comment on lines +231 to +213
int r = parse_pam_args(pamh, argc, argv, &config);
if (r < 0) {
pam_syslog(pamh, LOG_ERR, "failed to parse pam module arguments (%d)", r);
return rc;
}

r = parse_config_file(&config);
if (r < 0) {
pam_syslog(pamh, LOG_ERR, "failed to read config file: %s (%d)",
config.config_path, r);
return rc;
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I have a pam module config that specifies a custom service key and there happens to be a global config file with another service key, the global one would be chosen, wouldn't it? This may be unexpected.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, this behaviour is mentioned already in #33. Patch is now updated to prefer the parameter over the config file.

@vvidic
Copy link
Collaborator Author

vvidic commented Jan 7, 2021 via email

@burgerdev
Copy link
Collaborator

On Thu, Jan 07, 2021 at 06:50:51AM -0800, Markus Rudy wrote: PAM_CRED_UNAVAIL: This module cannot retrieve the user's credentials. sounds correct to me.
I will test with PAM_CRED_UNAVAIL, but I suspect it will cause PAM stack to fail as mentioned here under RETURN VALUES: https://man7.org/linux/man-pages/man3/pam_sm_setcred.3.html Also Google Authenticator uses PAM_SUCCESS for this function: https://github.com/google/google-authenticator-libpam/blob/master/src/pam_google_authenticator.c#L2192

-- Valentin

I see: if we were to stack GLOME and some password-based login, we would not be able to change the password if the GLOME stack returned UNAVAIL. I don't quite understand the design decision (by PAM), but in that case, and since we have a precedent in Google Authenticator, let's keep it as is. Thanks for following up.

Time to resolve that merge conflict :)

Copy link
Member

@pkern pkern left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you so much for your contribution! This LGTM as-is except one nit (install dir).

link_with : login_lib,
include_directories : glome_incdir,
install : true,
install_dir : get_option('sbindir'))

cc = meson.get_compiler('c')
libpam = cc.find_library('pam')
pam_glome = shared_library('pam_glome',
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was a little tempted to say that this should be conditional. On the other hand I'm of the belief that in the public build glome-login should eventually die and only ship the PAM module. :)

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suppose there is no harm in building both until the decision is made on glome-login.

login/pam.c Outdated
return failure(EXITCODE_INVALID_INPUT_SIZE, error_tag, "authcode-length");
}

// We can use insecure strncmp() because it's a *one-time* code.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Something like this always makes me a little uncomfortable. Is that because we don't have a constant-time check available? You already need to point out that it's safe, so if there's no drawback to just doing the right thing, it'd be better to do that? (Or maybe I'm off here and it just instills a wrong sense of security.)

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, this is a strange comment and I don't know why is strncmp insecure here since the length is checked few lines before. The comment comes from the original login.c so we should probably check with the author there.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The original author didn't mean memory safety. :)

It's about strncmp() being susceptible to timing attacks which doesn't matter in this particular context given that we are comparing one time code. I am fine with using constant-time comparison here, especially if it makes more people sleep better at nights.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added a XOR loop now, please check if this is ok now.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since we already have the OpenSSL dependency I'd prefer using CRYPTO_memcmp.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Used CRYPTO_memcmp, thanks.


* `config_path=PATH` - location of the configuration file to parse (defaults to
`/etc/glome/config`)
* `service_key=KEY` - use hex-encoded `KEY` as the service key (defaults to key
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't we also need a key ID in this case?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added a new option service_key_version for setting the key ID.

dependencies : [libpam],
link_with : [glome_lib, login_lib],
include_directories : glome_incdir,
install : true)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add a TODO to install this into the correct directory or add the support for that. I know it's messy, at least last time I looked at how to solve this there was no pre-built support in meson.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added support to install as $libdir/security/pam_glome.so

@pkern
Copy link
Member

pkern commented Jan 8, 2021

And this PR needs to be merged/rebased first to resolve the conflict.

@vvidic
Copy link
Collaborator Author

vvidic commented Jan 8, 2021

And this PR needs to be merged/rebased first to resolve the conflict.

PR rebased on top of master.

Reuses much of the existing glome-login functions.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants