-
Notifications
You must be signed in to change notification settings - Fork 20
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
Conversation
Fixes #39 |
There was a problem hiding this 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!
} | ||
|
||
int pam_sm_setcred(pam_handle_t *pamh, int flags, int argc, const char **argv) { | ||
return PAM_SUCCESS; |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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
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; |
There was a problem hiding this comment.
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 withpam_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.
There was a problem hiding this comment.
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.
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; | ||
} |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
a578764
to
de41c2c
Compare
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 :) |
There was a problem hiding this 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', |
There was a problem hiding this comment.
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. :)
There was a problem hiding this comment.
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. |
There was a problem hiding this comment.
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.)
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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
.
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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.
login/meson.build
Outdated
dependencies : [libpam], | ||
link_with : [glome_lib, login_lib], | ||
include_directories : glome_incdir, | ||
install : true) |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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
And this PR needs to be merged/rebased first to resolve the conflict. |
94753a9
to
a92c9e2
Compare
PR rebased on top of master. |
ce66037
to
51a0e3e
Compare
Reuses much of the existing glome-login functions.
Reuses much of the existing glome-login functions.