From 685746796ea2c8a1c804cfad33cb6eb14e979aa4 Mon Sep 17 00:00:00 2001 From: Doridian <git@doridian.net> Date: Sun, 29 Dec 2024 21:29:28 -0800 Subject: [PATCH 1/4] Add and implement basic NssGroupsByMember call --- unix_integration/common/src/unix_proto.rs | 2 ++ .../resolver/src/bin/kanidm_unixd.rs | 8 ++++++++ unix_integration/resolver/src/resolver.rs | 18 ++++++++++++++++++ 3 files changed, 28 insertions(+) diff --git a/unix_integration/common/src/unix_proto.rs b/unix_integration/common/src/unix_proto.rs index 69f88c100..5d1afb06c 100644 --- a/unix_integration/common/src/unix_proto.rs +++ b/unix_integration/common/src/unix_proto.rs @@ -121,6 +121,7 @@ pub enum ClientRequest { NssGroups, NssGroupByGid(u32), NssGroupByName(String), + NssGroupsByMember(String), PamAuthenticateInit { account_id: String, info: PamServiceInfo, @@ -144,6 +145,7 @@ impl ClientRequest { ClientRequest::NssGroups => "NssGroups".to_string(), ClientRequest::NssGroupByGid(id) => format!("NssGroupByGid({})", id), ClientRequest::NssGroupByName(id) => format!("NssGroupByName({})", id), + ClientRequest::NssGroupsByMember(id) => format!("NssGroupsByMember({})", id), ClientRequest::PamAuthenticateInit { account_id, info } => format!( "PamAuthenticateInit{{ account_id={} tty={} pam_secvice{} rhost={} }}", account_id, diff --git a/unix_integration/resolver/src/bin/kanidm_unixd.rs b/unix_integration/resolver/src/bin/kanidm_unixd.rs index 414554488..490ec34de 100644 --- a/unix_integration/resolver/src/bin/kanidm_unixd.rs +++ b/unix_integration/resolver/src/bin/kanidm_unixd.rs @@ -275,6 +275,14 @@ async fn handle_client( error!("unable to load group, returning empty."); ClientResponse::NssGroup(None) }), + ClientRequest::NssGroupsByMember(account_id) => cachelayer + .get_nssgroups_member_name(account_id.as_str()) + .await + .map(ClientResponse::NssGroups) + .unwrap_or_else(|_| { + error!("unable to enum groups"); + ClientResponse::NssGroups(Vec::new()) + }), ClientRequest::PamAuthenticateInit { account_id, info } => { match &pam_auth_session_state { Some(_auth_session) => { diff --git a/unix_integration/resolver/src/resolver.rs b/unix_integration/resolver/src/resolver.rs index d892086d8..ecb3167fe 100644 --- a/unix_integration/resolver/src/resolver.rs +++ b/unix_integration/resolver/src/resolver.rs @@ -736,6 +736,24 @@ impl Resolver { Ok(r) } + pub async fn get_nssgroups_member(&self, account_id: Id) -> Result<Vec<NssGroup>, ()> { + let account = self.get_nssaccount(account_id).await?; + if let Some(account) = account { + Ok(self.get_nssgroups().await. + unwrap_or_else(|_| Vec::new()) + .into_iter() + .filter(|g| g.members.contains(&account.name)) + .collect()) + } else { + Ok(Vec::new()) + } + } + + #[instrument(level = "debug", skip(self))] + pub async fn get_nssgroups_member_name(&self, account_id: &str) -> Result<Vec<NssGroup>, ()> { + self.get_nssgroups_member(Id::Name(account_id.to_string())).await + } + async fn get_nssgroup(&self, grp_id: Id) -> Result<Option<NssGroup>, ()> { if let Some(mut nss_group) = self.system_provider.get_nssgroup(&grp_id).await { debug!("system provider satisfied request"); From 8af51175f54572f57d208fd6f516c754fa77c6e3 Mon Sep 17 00:00:00 2001 From: Doridian <git@doridian.net> Date: Sun, 29 Dec 2024 21:46:24 -0800 Subject: [PATCH 2/4] Implement libnss side possibly --- unix_integration/nss_kanidm/src/core.rs | 36 ++++++++++++++++++++++++ unix_integration/nss_kanidm/src/hooks.rs | 14 +++++++++ 2 files changed, 50 insertions(+) diff --git a/unix_integration/nss_kanidm/src/core.rs b/unix_integration/nss_kanidm/src/core.rs index d60ba9839..3b067a72e 100644 --- a/unix_integration/nss_kanidm/src/core.rs +++ b/unix_integration/nss_kanidm/src/core.rs @@ -285,6 +285,42 @@ pub fn get_group_entry_by_name(name: String, req_options: RequestOptions) -> Res } } +pub fn get_group_entries_by_member(member: String, req_options: RequestOptions) -> Response<Vec<Group>> { + match req_options.connect_to_daemon() { + Source::Daemon(mut daemon_client) => { + let req = ClientRequest::NssGroupsByMember(member); + daemon_client + .call_and_wait(&req, None) + .map(|r| match r { + ClientResponse::NssGroups(l) => { + l.into_iter().map(group_from_nssgroup).collect() + } + _ => Vec::new(), + }) + .map(Response::Success) + .unwrap_or_else(|_| Response::Success(vec![])) + } + Source::Fallback { users: _, groups } => { + if groups.is_empty() { + return Response::Unavail; + } + + let membergroups = groups + .into_iter() + .filter_map(|etcgroup| { + if etcgroup.members.contains(&member) { + Some(group_from_etcgroup(etcgroup)) + } else { + None + } + }) + .collect(); + + Response::Success(membergroups) + } + } +} + fn passwd_from_etcuser(etc: EtcUser) -> Passwd { Passwd { name: etc.name, diff --git a/unix_integration/nss_kanidm/src/hooks.rs b/unix_integration/nss_kanidm/src/hooks.rs index 62386c987..5b7968438 100644 --- a/unix_integration/nss_kanidm/src/hooks.rs +++ b/unix_integration/nss_kanidm/src/hooks.rs @@ -3,6 +3,7 @@ use kanidm_unix_common::constants::DEFAULT_CONFIG_PATH; use libnss::group::{Group, GroupHooks}; use libnss::interop::Response; use libnss::passwd::{Passwd, PasswdHooks}; +use libnss::initgroups::{InitgroupsHooks}; struct KanidmPasswd; libnss_passwd_hooks!(kanidm, KanidmPasswd); @@ -61,3 +62,16 @@ impl GroupHooks for KanidmGroup { core::get_group_entry_by_name(name, req_opt) } } + +struct KanidmInitgroups; +libnss_initgroups_hooks!(kanidm, KanidmInitgroups); + +impl InitgroupsHooks for KanidmInitgroups { + fn get_entries_by_user(user: String) -> Response<Vec<Group>> { + let req_opt = RequestOptions::Main { + config_path: DEFAULT_CONFIG_PATH, + }; + + core::get_group_entries_by_member(user, req_opt) + } +} From 15410a783000760c6402537e9d78d97a216d3a9f Mon Sep 17 00:00:00 2001 From: Doridian <git@doridian.net> Date: Mon, 30 Dec 2024 00:04:02 -0800 Subject: [PATCH 3/4] Simplify logic --- unix_integration/resolver/src/resolver.rs | 21 ++++++--------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/unix_integration/resolver/src/resolver.rs b/unix_integration/resolver/src/resolver.rs index ecb3167fe..c16b9c942 100644 --- a/unix_integration/resolver/src/resolver.rs +++ b/unix_integration/resolver/src/resolver.rs @@ -736,22 +736,13 @@ impl Resolver { Ok(r) } - pub async fn get_nssgroups_member(&self, account_id: Id) -> Result<Vec<NssGroup>, ()> { - let account = self.get_nssaccount(account_id).await?; - if let Some(account) = account { - Ok(self.get_nssgroups().await. - unwrap_or_else(|_| Vec::new()) - .into_iter() - .filter(|g| g.members.contains(&account.name)) - .collect()) - } else { - Ok(Vec::new()) - } - } - - #[instrument(level = "debug", skip(self))] pub async fn get_nssgroups_member_name(&self, account_id: &str) -> Result<Vec<NssGroup>, ()> { - self.get_nssgroups_member(Id::Name(account_id.to_string())).await + let account_name = account_id.to_string(); + Ok(self.get_nssgroups().await. + unwrap_or_else(|_| Vec::new()) + .into_iter() + .filter(|g| g.members.contains(&account_name)) + .collect()) } async fn get_nssgroup(&self, grp_id: Id) -> Result<Option<NssGroup>, ()> { From 998e56d6482006aef5f6bf8e9c6896e5b2262f1a Mon Sep 17 00:00:00 2001 From: Doridian <git@doridian.net> Date: Tue, 7 Jan 2025 17:09:31 -0800 Subject: [PATCH 4/4] begin reworking --- unix_integration/resolver/src/db.rs | 31 +++++++++++++++++++++++ unix_integration/resolver/src/resolver.rs | 25 +++++++++++++----- 2 files changed, 50 insertions(+), 6 deletions(-) diff --git a/unix_integration/resolver/src/db.rs b/unix_integration/resolver/src/db.rs index 094562f97..3070ac57a 100644 --- a/unix_integration/resolver/src/db.rs +++ b/unix_integration/resolver/src/db.rs @@ -792,6 +792,37 @@ impl DbTxn<'_> { } } + pub fn get_user_groups(&mut self, a_uuid: Uuid) -> Result<Vec<GroupToken>, CacheError> { + let mut stmt = self + .conn + .prepare("SELECT group_t.token FROM (group_t, memberof_t) WHERE group_t.uuid = memberof_t.g_uuid AND memberof_t.a_uuid = :a_uuid") + .map_err(|e| { + self.sqlite_error("select prepare", &e) + })?; + + let data_iter = stmt + .query_map([a_uuid.as_hyphenated().to_string()], |row| row.get(0)) + .map_err(|e| self.sqlite_error("query_map", &e))?; + let data: Result<Vec<Vec<u8>>, _> = data_iter + .map(|v| v.map_err(|e| self.sqlite_error("map", &e))) + .collect(); + + let data = data?; + + Ok(data + .iter() + .filter_map(|token| { + // token convert with json. + // trace!("{:?}", token); + serde_json::from_slice(token.as_slice()) + .map_err(|e| { + error!("json error -> {:?}", e); + }) + .ok() + }) + .collect()) + } + pub fn get_group_members(&mut self, g_uuid: Uuid) -> Result<Vec<UserToken>, CacheError> { let mut stmt = self .conn diff --git a/unix_integration/resolver/src/resolver.rs b/unix_integration/resolver/src/resolver.rs index c16b9c942..12f55ed1f 100644 --- a/unix_integration/resolver/src/resolver.rs +++ b/unix_integration/resolver/src/resolver.rs @@ -576,6 +576,17 @@ impl Resolver { }) } + async fn get_usergroups(&self, g_uuid: Uuid) -> Vec<String> { + let mut dbtxn = self.db.write().await; + + dbtxn + .get_user_groups(g_uuid) + .unwrap_or_else(|_| Vec::new()) + .into_iter() + .map(|gt| self.token_gidattr(>)) + .collect() + } + async fn get_groupmembers(&self, g_uuid: Uuid) -> Vec<String> { let mut dbtxn = self.db.write().await; @@ -737,12 +748,14 @@ impl Resolver { } pub async fn get_nssgroups_member_name(&self, account_id: &str) -> Result<Vec<NssGroup>, ()> { - let account_name = account_id.to_string(); - Ok(self.get_nssgroups().await. - unwrap_or_else(|_| Vec::new()) - .into_iter() - .filter(|g| g.members.contains(&account_name)) - .collect()) + if let Some(nss_user) = self.get_nssaccount(&account_id).await { + Ok(self.get_usergroups(nss_user).await + .into_iter() + .map(|g| self.token_gidattr(&g)) + .collect()) + } else { + Ok(Vec::new()) + } } async fn get_nssgroup(&self, grp_id: Id) -> Result<Option<NssGroup>, ()> {