From ea8801f23d5aa0eea1e53a4a39b006d81800d998 Mon Sep 17 00:00:00 2001 From: James Hodgkinson Date: Mon, 6 Sep 2021 07:48:37 +1000 Subject: [PATCH] Improving logging and docs around unixd/PAM/NSS (#577) --- kanidm_book/src/pam_and_nsswitch.md | 42 +++++++++++++++++++++++++-- kanidm_unix_int/pam_kanidm/src/lib.rs | 17 +++++++++-- kanidm_unix_int/src/cache.rs | 39 ++++++++++++++++--------- 3 files changed, 80 insertions(+), 18 deletions(-) diff --git a/kanidm_book/src/pam_and_nsswitch.md b/kanidm_book/src/pam_and_nsswitch.md index dd7ab1fb8..31ed01835 100644 --- a/kanidm_book/src/pam_and_nsswitch.md +++ b/kanidm_book/src/pam_and_nsswitch.md @@ -241,6 +241,35 @@ edit the content. ## Troubleshooting +### Check POSIX-status of group and config + +If authentication is failing via PAM, make sure that a list of groups is configured in `/etc/kanidm/unixd`: + +``` +pam_allowed_login_groups = ["example_group"] +``` + +Check the status of the group with `kanidm group posix show example_group`. If you get something similar to the below: + +```shell +> kanidm group posix show example_group +Using cached token for name idm_admin +Error -> Http(500, Some(InvalidAccountState("Missing class: account && posixaccount OR group && posixgroup")), "b71f137e-39f3-4368-9e58-21d26671ae24") +``` + +POSIX-enable the group with `kanidm group posix set example_group`. You should get a result similar to this when you search for your group name: + +```shell +> kanidm group posix show example_group +[ spn: example_group@kanidm.example.com, gidnumber: 3443347205 name: example_group, uuid: b71f137e-39f3-4368-9e58-21d26671ae24 ] +``` + +Also, ensure the target user is in the group by running: + +``` +> kanidm group list_members example_group +``` + ### Increase logging For the unixd daemon, you can increase the logging with: @@ -262,10 +291,10 @@ To debug the pam module interactions add `debug` to the module arguments such as ### Check the socket permissions -Check that the /var/run/kanidm-unixd/sock is 777, and that non-root readers can see it with +Check that the `/var/run/kanidm-unixd/sock` is 777, and that non-root readers can see it with ls or other tools. -Ensure that /var/run/kanidm-unixd/task_sock is 700, and that it is owned by the kanidm unixd +Ensure that `/var/run/kanidm-unixd/task_sock` is 700, and that it is owned by the kanidm unixd process user. ### Check you can access the kanidm server @@ -279,6 +308,15 @@ You can check this with the client tools: You should have: /usr/lib64/libnss_kanidm.so.2 + /usr/lib64/security/pam_kanidm.so + +The exact path *may* change depending on your distribution, `pam_unixd.so` should be co-located with pam_kanidm.so so looking for it findable with: + +``` +find /usr/ -name 'pam_unix.so' +``` + +For example, on a Debian machine, it's located in `/usr/lib/x86_64-linux-gnu/security/`. ### Increase connection timeout diff --git a/kanidm_unix_int/pam_kanidm/src/lib.rs b/kanidm_unix_int/pam_kanidm/src/lib.rs index 6a25e0166..f386366f4 100644 --- a/kanidm_unix_int/pam_kanidm/src/lib.rs +++ b/kanidm_unix_int/pam_kanidm/src/lib.rs @@ -94,31 +94,42 @@ impl PamHooks for PamKanidm { match call_daemon_blocking(cfg.sock_path.as_str(), &req) { Ok(r) => match r { ClientResponse::PamStatus(Some(true)) => { - // println!("PAM_SUCCESS"); + if opts.debug { + println!("PamResultCode::PAM_SUCCESS"); + } PamResultCode::PAM_SUCCESS } ClientResponse::PamStatus(Some(false)) => { // println!("PAM_IGNORE"); + if opts.debug { + println!("PamResultCode::PAM_AUTH_ERR"); + } PamResultCode::PAM_AUTH_ERR } ClientResponse::PamStatus(None) => { if opts.ignore_unknown_user { + if opts.debug { + println!("PamResultCode::PAM_IGNORE"); + } PamResultCode::PAM_IGNORE } else { + if opts.debug { + println!("PamResultCode::PAM_USER_UNKNOWN"); + } PamResultCode::PAM_USER_UNKNOWN } } _ => { // unexpected response. if opts.debug { - println!("PAM_IGNORE -> {:?}", r); + println!("PamResultCode::PAM_IGNORE -> {:?}", r); } PamResultCode::PAM_IGNORE } }, Err(e) => { if opts.debug { - println!("PAM_IGNORE -> {:?}", e); + println!("PamResultCode::PAM_IGNORE -> {:?}", e); } PamResultCode::PAM_IGNORE } diff --git a/kanidm_unix_int/src/cache.rs b/kanidm_unix_int/src/cache.rs index bb80b1104..9256a71d6 100644 --- a/kanidm_unix_int/src/cache.rs +++ b/kanidm_unix_int/src/cache.rs @@ -80,6 +80,10 @@ impl CacheLayer { dbtxn.commit()?; } + if pam_allow_groups.len() == 0 { + eprintln!("Will not be able to authenticate users, pam_allow_groups config is not configured."); + } + // We assume we are offline at start up, and we mark the next "online check" as // being valid from "now". Ok(CacheLayer { @@ -858,21 +862,30 @@ impl CacheLayer { pub async fn pam_account_allowed(&self, account_id: &str) -> Result, ()> { let token = self.get_usertoken(Id::Name(account_id.to_string())).await?; - Ok(token.map(|tok| { - let user_set: BTreeSet<_> = tok - .groups - .iter() - .map(|g| vec![g.name.clone(), g.spn.clone(), g.uuid.clone()]) - .flatten() - .collect(); + if self.pam_allow_groups.len() == 0 { + // can't allow anything if the group list is zero... + eprintln!("Cannot authenticate users, no allowed groups in configuration!"); + Ok(Some(false)) + } else { + Ok(token.map(|tok| { + let user_set: BTreeSet<_> = tok + .groups + .iter() + .map(|g| vec![g.name.clone(), g.spn.clone(), g.uuid.clone()]) + .flatten() + .collect(); - debug!( - "Checking if -> {:?} & {:?}", - user_set, self.pam_allow_groups - ); + debug!( + "Checking if user is in allowed groups ({:?}) -> {:?}", + self.pam_allow_groups, user_set, + ); + let intersection_count = user_set.intersection(&self.pam_allow_groups).count(); + debug!("Number of intersecting groups: {}", intersection_count); + debug!("User has valid token: {}", tok.valid); - user_set.intersection(&self.pam_allow_groups).count() > 0 && tok.valid - })) + intersection_count > 0 && tok.valid + })) + } } pub async fn pam_account_authenticate(