From cbadf0af9bf713bf83726dc90e44e4fcd2239944 Mon Sep 17 00:00:00 2001 From: James Hodgkinson Date: Sun, 3 Dec 2023 16:34:02 +1000 Subject: [PATCH] Unixd build/debugging updates (#2350) * noisy for no reason message * updating build script to include unix modules * adding restart config for kanidm systemd services --- .codespell_dictionary | 3 ++ Makefile | 1 + libs/crypto/src/lib.rs | 4 +-- platform/crossbuild/build.sh | 9 +++++ .../debian/systemd/kanidm-unixd-tasks.service | 5 +++ platform/debian/systemd/kanidm-unixd.service | 5 +++ unix_integration/src/client.rs | 2 +- unix_integration/src/daemon.rs | 7 ++++ unix_integration/src/resolver.rs | 8 ++++- unix_integration/src/tool.rs | 16 ++++++--- unix_integration/src/unix_proto.rs | 36 +++++++++++++++++++ 11 files changed, 88 insertions(+), 8 deletions(-) create mode 100644 .codespell_dictionary diff --git a/.codespell_dictionary b/.codespell_dictionary new file mode 100644 index 000000000..c712ac458 --- /dev/null +++ b/.codespell_dictionary @@ -0,0 +1,3 @@ +attesation->attestation +kandim->kanidm +Kandim->kanidm diff --git a/Makefile b/Makefile index 47f873e90..0920b128c 100644 --- a/Makefile +++ b/Makefile @@ -133,6 +133,7 @@ install-tools: codespell: ## spell-check things. codespell: codespell -c \ + -D .codespell_dictionary \ --ignore-words .codespell_ignore \ --skip='./target,./pykanidm/.venv,./pykanidm/.mypy_cache,./.mypy_cache,./pykanidm/poetry.lock' \ --skip='./book/*.js' \ diff --git a/libs/crypto/src/lib.rs b/libs/crypto/src/lib.rs index ea6ea071c..81b8b292a 100644 --- a/libs/crypto/src/lib.rs +++ b/libs/crypto/src/lib.rs @@ -13,7 +13,7 @@ use argon2::{Algorithm, Argon2, Params, PasswordHash, Version}; use base64::engine::GeneralPurpose; use base64::{alphabet, Engine}; -use tracing::{debug, error, info, trace, warn}; +use tracing::{debug, error, trace, warn}; use base64::engine::general_purpose; use base64urlsafedata::Base64UrlSafeData; @@ -378,7 +378,7 @@ impl CryptoPolicy { pbkdf2_cost, argon2id_params, }; - info!(pbkdf2_cost = %p.pbkdf2_cost, argon2id_m = %p.argon2id_params.m_cost(), argon2id_p = %p.argon2id_params.p_cost(), argon2id_t = %p.argon2id_params.t_cost(), ); + debug!(pbkdf2_cost = %p.pbkdf2_cost, argon2id_m = %p.argon2id_params.m_cost(), argon2id_p = %p.argon2id_params.p_cost(), argon2id_t = %p.argon2id_params.t_cost(), ); p } } diff --git a/platform/crossbuild/build.sh b/platform/crossbuild/build.sh index ca8647871..38f686fb8 100755 --- a/platform/crossbuild/build.sh +++ b/platform/crossbuild/build.sh @@ -29,11 +29,20 @@ CROSS_CONFIG="platform/crossbuild/${1}/Cross.toml" \ --bin kanidm_ssh_authorizedkeys \ --bin kanidm-unix \ --release +CROSS_CONFIG="platform/crossbuild/${1}/Cross.toml" \ + cross build --target aarch64-unknown-linux-gnu \ + -p pam_kanidm \ + -p nss_kanidm \ + --release find "./target/aarch64-unknown-linux-gnu/release/" -maxdepth 1 \ -type f -not -name '*.d' \ -name 'kanidm*' \ -exec mv "{}" "${TARGET_DIR}/" \; + +find "./target/aarch64-unknown-linux-gnu/release/" -maxdepth 1 \ + -name '*kanidm*.so' \ + -exec mv "{}" "${TARGET_DIR}/" \; # find "${TARGET_DIR}" -name '*.d' -delete echo "Contents of ${TARGET_DIR}" diff --git a/platform/debian/systemd/kanidm-unixd-tasks.service b/platform/debian/systemd/kanidm-unixd-tasks.service index 4aabbb8eb..56e9277c8 100644 --- a/platform/debian/systemd/kanidm-unixd-tasks.service +++ b/platform/debian/systemd/kanidm-unixd-tasks.service @@ -10,6 +10,11 @@ User=root Type=simple ExecStart=/usr/sbin/kanidm_unixd_tasks +# because kanidm-unixd might have failed for some reason but we need to try again later +Restart=always +RestartSec=30 + + CapabilityBoundingSet=CAP_CHOWN CAP_FOWNER CAP_DAC_OVERRIDE CAP_DAC_READ_SEARCH # SystemCallFilter=@aio @basic-io @chown @file-system @io-event @network-io @sync ProtectSystem=strict diff --git a/platform/debian/systemd/kanidm-unixd.service b/platform/debian/systemd/kanidm-unixd.service index d5d3f5f36..0004e0015 100644 --- a/platform/debian/systemd/kanidm-unixd.service +++ b/platform/debian/systemd/kanidm-unixd.service @@ -13,9 +13,14 @@ SupplementaryGroups=tss UMask=0027 CacheDirectory=kanidm-unixd RuntimeDirectory=kanidm-unixd +StateDirectory=kanidm-unixd + Type=simple ExecStart=/usr/sbin/kanidm_unixd +# auth going down is bad, but infinite speedlooping is worse +Restart=always +RestartSec=30 # Implied by dynamic user. # ProtectHome= diff --git a/unix_integration/src/client.rs b/unix_integration/src/client.rs index a13b45b18..7dfca0170 100644 --- a/unix_integration/src/client.rs +++ b/unix_integration/src/client.rs @@ -37,7 +37,7 @@ impl Encoder for ClientCodec { error!("socket encoding error -> {:?}", e); IoError::new(ErrorKind::Other, "JSON encode error") })?; - debug!("Attempting to send request -> {:?} ...", data); + debug!("Attempting to send request -> {}", msg.as_safe_string()); dst.put(data.as_slice()); Ok(()) } diff --git a/unix_integration/src/daemon.rs b/unix_integration/src/daemon.rs index 3ba804187..030452cfb 100644 --- a/unix_integration/src/daemon.rs +++ b/unix_integration/src/daemon.rs @@ -843,6 +843,13 @@ async fn main() -> ExitCode { return ExitCode::FAILURE } + if !cfg.default_shell.is_empty() { + let shell_path = PathBuf::from_str(&cfg.default_shell).expect("Failed to build a representation of your default_shell path!"); + if !shell_path.exists() { + error!("Cannot find configured default shell at {}, this could cause login issues!", shell_path.display()) + } + } + // Okay, the hsm is now loaded and ready to go. let cl_inner = match Resolver::new( diff --git a/unix_integration/src/resolver.rs b/unix_integration/src/resolver.rs index 8d87e378d..d14515826 100644 --- a/unix_integration/src/resolver.rs +++ b/unix_integration/src/resolver.rs @@ -273,7 +273,9 @@ where // * uuid // Attempt to search these in the db. let mut dbtxn = self.db.write().await; - let r = dbtxn.get_account(account_id).map_err(|_| ())?; + let r = dbtxn.get_account(account_id).map_err(|err| { + debug!("get_cached_usertoken {:?}", err); + })?; match r { Some((ut, ex)) => { @@ -484,6 +486,10 @@ where Ok(mut n_tok) => { if self.check_nxset(&n_tok.name, n_tok.gidnumber).await { // Refuse to release the token, it's in the denied set. + debug!( + "Account {:?} is in denied set, refusing to release token. It may need to be in the allow_local_account_override configuration list.", + account_id + ); self.delete_cache_usertoken(n_tok.uuid).await?; Ok(None) } else { diff --git a/unix_integration/src/tool.rs b/unix_integration/src/tool.rs index 607017739..65fb3a4ec 100644 --- a/unix_integration/src/tool.rs +++ b/unix_integration/src/tool.rs @@ -61,22 +61,22 @@ async fn main() -> ExitCode { return ExitCode::FAILURE; }; + info!("Sending request for user {}", &account_id); + let mut req = ClientRequest::PamAuthenticateInit(account_id.clone()); loop { match call_daemon(cfg.sock_path.as_str(), req, cfg.unix_sock_timeout).await { Ok(r) => match r { ClientResponse::PamAuthenticateStepResponse(PamAuthResponse::Success) => { - // ClientResponse::PamStatus(Some(true)) => { println!("auth success!"); break; } ClientResponse::PamAuthenticateStepResponse(PamAuthResponse::Denied) => { - // ClientResponse::PamStatus(Some(false)) => { println!("auth failed!"); break; } ClientResponse::PamAuthenticateStepResponse(PamAuthResponse::Unknown) => { - // ClientResponse::PamStatus(None) => { + debug!("User may need to be in allow_local_account_override"); println!("auth user unknown"); break; } @@ -96,7 +96,15 @@ async fn main() -> ExitCode { }); continue; } - _ => { + ClientResponse::PamAuthenticateStepResponse(_) + | ClientResponse::SshKeys(_) + | ClientResponse::NssAccounts(_) + | ClientResponse::NssAccount(_) + | ClientResponse::NssGroup(_) + | ClientResponse::NssGroups(_) + | ClientResponse::Ok + | ClientResponse::Error + | ClientResponse::PamStatus(_) => { // unexpected response. error!("Error: unexpected response -> {:?}", r); break; diff --git a/unix_integration/src/unix_proto.rs b/unix_integration/src/unix_proto.rs index e175c53c2..3e1ab6191 100644 --- a/unix_integration/src/unix_proto.rs +++ b/unix_integration/src/unix_proto.rs @@ -72,6 +72,30 @@ pub enum ClientRequest { Status, } +impl ClientRequest { + /// Get a safe display version of the request, without credentials. + pub fn as_safe_string(&self) -> String { + match self { + ClientRequest::SshKey(id) => format!("SshKey({})", id), + ClientRequest::NssAccounts => "NssAccounts".to_string(), + ClientRequest::NssAccountByUid(id) => format!("NssAccountByUid({})", id), + ClientRequest::NssAccountByName(id) => format!("NssAccountByName({})", id), + ClientRequest::NssGroups => "NssGroups".to_string(), + ClientRequest::NssGroupByGid(id) => format!("NssGroupByGid({})", id), + ClientRequest::NssGroupByName(id) => format!("NssGroupByName({})", id), + ClientRequest::PamAuthenticateInit(id) => format!("PamAuthenticateInit({})", id), + ClientRequest::PamAuthenticateStep(_) => "PamAuthenticateStep".to_string(), + ClientRequest::PamAccountAllowed(id) => { + format!("PamAccountAllowed({})", id) + } + ClientRequest::PamAccountBeginSession(_) => "PamAccountBeginSession".to_string(), + ClientRequest::InvalidateCache => "InvalidateCache".to_string(), + ClientRequest::ClearCache => "ClearCache".to_string(), + ClientRequest::Status => "Status".to_string(), + } + } +} + #[derive(Serialize, Deserialize, Debug)] pub enum ClientResponse { SshKeys(Vec), @@ -110,3 +134,15 @@ pub enum TaskResponse { Success, Error(String), } + +#[test] +fn test_clientrequest_as_safe_string() { + assert_eq!( + ClientRequest::NssAccounts.as_safe_string(), + "NssAccounts".to_string() + ); + assert_eq!( + ClientRequest::SshKey("cheese".to_string()).as_safe_string(), + format!("SshKey({})", "cheese") + ); +}