Allow providers to be box dyn (#2794)

* Allow providers to be box dyn in kanidm_unixd
* Massive refactor
This commit is contained in:
Firstyear 2024-06-17 08:21:25 +10:00 committed by GitHub
parent 084fd9b32c
commit 0ce333ff5a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
31 changed files with 366 additions and 236 deletions

24
Cargo.lock generated
View file

@ -3396,16 +3396,30 @@ dependencies = [
"zxcvbn",
]
[[package]]
name = "kanidm_unix_common"
version = "1.3.0-dev"
dependencies = [
"bytes",
"csv",
"futures",
"kanidm_build_profiles",
"serde",
"serde_json",
"tokio",
"tokio-util",
"toml",
"tracing",
]
[[package]]
name = "kanidm_unix_int"
version = "1.3.0-dev"
dependencies = [
"async-trait",
"base64urlsafedata 0.5.0",
"bytes",
"clap",
"clap_complete",
"csv",
"futures",
"hashbrown 0.14.5",
"kanidm-hsm-crypto",
@ -3414,11 +3428,11 @@ dependencies = [
"kanidm_lib_crypto",
"kanidm_lib_file_permissions",
"kanidm_proto",
"kanidm_unix_common",
"kanidm_utils_users",
"kanidmd_core",
"kanidmd_testkit",
"libc",
"libsqlite3-sys",
"lru",
"mimalloc",
"notify-debouncer-full",
@ -4118,7 +4132,7 @@ dependencies = [
name = "nss_kanidm"
version = "1.3.0-dev"
dependencies = [
"kanidm_unix_int",
"kanidm_unix_common",
"lazy_static",
"libc",
"libnss",
@ -4533,7 +4547,7 @@ checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39"
name = "pam_kanidm"
version = "1.3.0-dev"
dependencies = [
"kanidm_unix_int",
"kanidm_unix_common",
"libc",
"pkg-config",
"tracing",

View file

@ -18,9 +18,10 @@ members = [
"tools/iam_migrations/freeipa",
"tools/iam_migrations/ldap",
"tools/orca",
"unix_integration",
"unix_integration/common",
"unix_integration/nss_kanidm",
"unix_integration/pam_kanidm",
"unix_integration/resolver",
"server/web_ui/admin",
"server/web_ui/login_flows",
"server/web_ui/user",
@ -135,7 +136,7 @@ kanidm-hsm-crypto = "^0.2.0"
kanidm_lib_crypto = { path = "./libs/crypto", version = "=1.3.0-dev" }
kanidm_lib_file_permissions = { path = "./libs/file_permissions", version = "=1.3.0-dev" }
kanidm_proto = { path = "./proto", version = "=1.3.0-dev" }
kanidm_unix_int = { path = "./unix_integration", version = "=1.3.0-dev" }
kanidm_unix_common = { path = "./unix_integration/common", version = "=1.3.0-dev" }
kanidm_utils_users = { path = "./libs/users", version = "=1.3.0-dev" }
sketching = { path = "./libs/sketching", version = "=1.3.0-dev" }

View file

@ -0,0 +1,36 @@
[package]
name = "kanidm_unix_common"
description = "Kanidm Unix Resolver - Common Libraries"
documentation = "https://docs.rs/kanidm/latest/kanidm/"
version = { workspace = true }
authors = { workspace = true }
rust-version = { workspace = true }
edition = { workspace = true }
license = { workspace = true }
homepage = { workspace = true }
repository = { workspace = true }
[features]
default = ["unix"]
unix = []
[lib]
name = "kanidm_unix_common"
path = "src/lib.rs"
test = true
doctest = false
[dependencies]
bytes = { workspace = true }
csv = { workspace = true }
futures = { workspace = true }
serde = { workspace = true, features = ["derive"] }
serde_json = { workspace = true }
toml = { workspace = true }
tokio = { workspace = true, features = ["time","net","macros"] }
tokio-util = { workspace = true, features = ["codec"] }
tracing = { workspace = true }
[build-dependencies]
kanidm_build_profiles = { workspace = true }

View file

@ -0,0 +1,6 @@
fn main() {
profiles::apply_profile();
println!("cargo:rerun-if-changed=build.rs");
println!("cargo:rerun-if-env-changed=OUT_DIR");
}

View file

@ -0,0 +1,28 @@
#![deny(warnings)]
#![warn(unused_extern_crates)]
#![deny(clippy::todo)]
#![deny(clippy::unimplemented)]
#![deny(clippy::unwrap_used)]
#![deny(clippy::expect_used)]
#![deny(clippy::panic)]
#![deny(clippy::unreachable)]
#![deny(clippy::await_holding_lock)]
#![deny(clippy::needless_pass_by_value)]
#![deny(clippy::trivially_copy_pass_by_ref)]
#[cfg(target_family = "unix")]
#[macro_use]
extern crate tracing;
#[cfg(target_family = "unix")]
pub mod client;
#[cfg(target_family = "unix")]
pub mod client_sync;
#[cfg(target_family = "unix")]
pub mod constants;
#[cfg(target_family = "unix")]
pub mod unix_config;
#[cfg(target_family = "unix")]
pub mod unix_passwd;
#[cfg(target_family = "unix")]
pub mod unix_proto;

View file

@ -0,0 +1,143 @@
use std::fmt::{Display, Formatter};
use std::fs::File;
use std::io::{ErrorKind, Read};
use std::path::Path;
use crate::unix_passwd::UnixIntegrationError;
use serde::Deserialize;
use crate::constants::*;
#[derive(Debug, Copy, Clone)]
pub enum HomeAttr {
Uuid,
Spn,
Name,
}
impl Display for HomeAttr {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{}",
match self {
HomeAttr::Uuid => "UUID",
HomeAttr::Spn => "SPN",
HomeAttr::Name => "Name",
}
)
}
}
#[derive(Debug, Copy, Clone)]
pub enum UidAttr {
Name,
Spn,
}
impl Display for UidAttr {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{}",
match self {
UidAttr::Name => "Name",
UidAttr::Spn => "SPN",
}
)
}
}
#[derive(Debug, Deserialize)]
struct ConfigInt {
sock_path: Option<String>,
conn_timeout: Option<u64>,
}
#[derive(Debug)]
pub struct KanidmUnixdConfig {
pub sock_path: String,
// pub conn_timeout: u64,
pub unix_sock_timeout: u64,
}
impl Default for KanidmUnixdConfig {
fn default() -> Self {
KanidmUnixdConfig::new()
}
}
impl Display for KanidmUnixdConfig {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
writeln!(f, "sock_path: {}", self.sock_path)?;
writeln!(f, "unix_sock_timeout: {}", self.unix_sock_timeout)
}
}
impl KanidmUnixdConfig {
pub fn new() -> Self {
KanidmUnixdConfig {
sock_path: DEFAULT_SOCK_PATH.to_string(),
unix_sock_timeout: DEFAULT_CONN_TIMEOUT * 2,
}
}
pub fn read_options_from_optional_config<P: AsRef<Path> + std::fmt::Debug>(
self,
config_path: P,
) -> Result<Self, UnixIntegrationError> {
debug!("Attempting to load configuration from {:#?}", &config_path);
let mut f = match File::open(&config_path) {
Ok(f) => {
debug!("Successfully opened configuration file {:#?}", &config_path);
f
}
Err(e) => {
match e.kind() {
ErrorKind::NotFound => {
debug!(
"Configuration file {:#?} not found, skipping.",
&config_path
);
}
ErrorKind::PermissionDenied => {
warn!(
"Permission denied loading configuration file {:#?}, skipping.",
&config_path
);
}
_ => {
debug!(
"Unable to open config file {:#?} [{:?}], skipping ...",
&config_path, e
);
}
};
return Ok(self);
}
};
let mut contents = String::new();
f.read_to_string(&mut contents).map_err(|e| {
error!("{:?}", e);
UnixIntegrationError
})?;
let config: ConfigInt = toml::from_str(contents.as_str()).map_err(|e| {
error!("{:?}", e);
UnixIntegrationError
})?;
let unix_sock_timeout = config
.conn_timeout
.map(|v| v * 2)
.unwrap_or(self.unix_sock_timeout);
// Now map the values into our config.
Ok(KanidmUnixdConfig {
sock_path: config.sock_path.unwrap_or(self.sock_path),
unix_sock_timeout,
})
}
}

View file

@ -15,7 +15,7 @@ crate-type = [ "cdylib" ]
path = "src/lib.rs"
[dependencies]
kanidm_unix_int = { workspace = true }
kanidm_unix_common = { workspace = true }
[target.'cfg(not(target_family = "windows"))'.dependencies]
libnss = { workspace = true }

View file

@ -16,7 +16,7 @@ crate-type = [ "cdylib" ]
path = "src/lib.rs"
[dependencies]
kanidm_unix_int = { workspace = true }
kanidm_unix_common = { workspace = true }
libc = { workspace = true }
tracing-subscriber = { workspace = true }
tracing = { workspace = true }

View file

@ -19,54 +19,55 @@ tpm = ["kanidm-hsm-crypto/tpm"]
[[bin]]
name = "kanidm_unixd"
path = "src/daemon.rs"
path = "src/bin/kanidm_unixd.rs"
required-features = ["unix"]
test = true
doctest = false
[[bin]]
name = "kanidm_unixd_tasks"
path = "src/tasks_daemon.rs"
path = "src/bin/kanidm_unixd_tasks.rs"
required-features = ["unix"]
test = true
doctest = false
[[bin]]
name = "kanidm_ssh_authorizedkeys"
path = "src/ssh_authorizedkeys.rs"
path = "src/bin/kanidm_ssh_authorizedkeys.rs"
required-features = ["unix"]
test = true
doctest = false
[[bin]]
name = "kanidm-unix"
path = "src/tool.rs"
path = "src/bin/kanidm-unix.rs"
required-features = ["unix"]
test = true
doctest = false
[lib]
name = "kanidm_unix_common"
name = "kanidm_unix_resolver"
path = "src/lib.rs"
test = true
doctest = false
[dependencies]
async-trait.workspace = true
base64urlsafedata = { workspace = true }
# base64urlsafedata = { workspace = true }
bytes = { workspace = true }
clap = { workspace = true, features = ["derive", "env"] }
csv = { workspace = true }
# csv = { workspace = true }
futures = { workspace = true }
hashbrown = { workspace = true }
libc = { workspace = true }
libsqlite3-sys = { workspace = true }
# libsqlite3-sys = { workspace = true }
lru = { workspace = true }
kanidm_client = { workspace = true }
kanidm_proto = { workspace = true }
kanidm-hsm-crypto = { workspace = true }
kanidm_lib_crypto = { workspace = true }
kanidm_lib_file_permissions = { workspace = true }
kanidm_unix_common = { workspace = true }
notify-debouncer-full = { workspace = true }
rpassword = { workspace = true }
rusqlite = { workspace = true }
@ -74,7 +75,6 @@ selinux = { workspace = true, optional = true }
serde = { workspace = true, features = ["derive"] }
serde_json = { workspace = true }
sketching = { workspace = true }
toml = { workspace = true }
tokio = { workspace = true, features = [
"rt",

View file

@ -25,7 +25,7 @@ use kanidm_unix_common::unix_proto::{
// use std::io;
use std::path::PathBuf;
include!("./opt/tool.rs");
include!("../opt/tool.rs");
#[tokio::main(flavor = "current_thread")]
async fn main() -> ExitCode {

View file

@ -22,7 +22,7 @@ use kanidm_unix_common::constants::DEFAULT_CONFIG_PATH;
use kanidm_unix_common::unix_config::KanidmUnixdConfig;
use kanidm_unix_common::unix_proto::{ClientRequest, ClientResponse};
include!("./opt/ssh_authorizedkeys.rs");
include!("../opt/ssh_authorizedkeys.rs");
#[tokio::main(flavor = "current_thread")]
async fn main() -> ExitCode {

View file

@ -27,13 +27,12 @@ use futures::{SinkExt, StreamExt};
use kanidm_client::KanidmClientBuilder;
use kanidm_proto::constants::DEFAULT_CLIENT_CONFIG_PATH;
use kanidm_unix_common::constants::DEFAULT_CONFIG_PATH;
use kanidm_unix_common::db::{Cache, CacheTxn, Db};
use kanidm_unix_common::idprovider::kanidm::KanidmProvider;
// use kanidm_unix_common::idprovider::interface::AuthSession;
use kanidm_unix_common::resolver::Resolver;
use kanidm_unix_common::unix_config::{HsmType, KanidmUnixdConfig};
use kanidm_unix_common::unix_passwd::{parse_etc_group, parse_etc_passwd};
use kanidm_unix_common::unix_proto::{ClientRequest, ClientResponse, TaskRequest, TaskResponse};
use kanidm_unix_resolver::db::{Cache, Db};
use kanidm_unix_resolver::idprovider::kanidm::KanidmProvider;
use kanidm_unix_resolver::resolver::Resolver;
use kanidm_unix_resolver::unix_config::{HsmType, KanidmUnixdConfig};
use kanidm_utils_users::{get_current_gid, get_current_uid, get_effective_gid, get_effective_uid};
use libc::umask;
@ -191,7 +190,7 @@ async fn handle_task_client(
async fn handle_client(
sock: UnixStream,
cachelayer: Arc<Resolver<KanidmProvider>>,
cachelayer: Arc<Resolver>,
task_channel_tx: &Sender<AsyncTaskRequest>,
) -> Result<(), Box<dyn Error>> {
debug!("Accepted connection");
@ -431,9 +430,7 @@ async fn handle_client(
Ok(())
}
async fn process_etc_passwd_group(
cachelayer: &Resolver<KanidmProvider>,
) -> Result<(), Box<dyn Error>> {
async fn process_etc_passwd_group(cachelayer: &Resolver) -> Result<(), Box<dyn Error>> {
let mut file = File::open("/etc/passwd").await?;
let mut contents = vec![];
file.read_to_end(&mut contents).await?;
@ -925,7 +922,7 @@ async fn main() -> ExitCode {
let cl_inner = match Resolver::new(
db,
idprovider,
Box::new(idprovider),
hsm,
machine_key,
cfg.cache_timeout,

View file

@ -21,8 +21,8 @@ use std::{fs, io};
use bytes::{BufMut, BytesMut};
use futures::{SinkExt, StreamExt};
use kanidm_unix_common::constants::DEFAULT_CONFIG_PATH;
use kanidm_unix_common::unix_config::KanidmUnixdConfig;
use kanidm_unix_common::unix_proto::{HomeDirectoryInfo, TaskRequest, TaskResponse};
use kanidm_unix_resolver::unix_config::KanidmUnixdConfig;
use kanidm_utils_users::{get_effective_gid, get_effective_uid};
use libc::{lchown, umask};
use sketching::tracing_forest::traits::*;
@ -35,7 +35,7 @@ use tokio_util::codec::{Decoder, Encoder, Framed};
use walkdir::WalkDir;
#[cfg(all(target_family = "unix", feature = "selinux"))]
use kanidm_unix_common::selinux_util;
use crate::selinux_util;
struct TaskCodec;

View file

@ -47,75 +47,6 @@ pub enum CacheError {
Tpm,
}
pub trait CacheTxn {
fn migrate(&mut self) -> Result<(), CacheError>;
fn commit(self) -> Result<(), CacheError>;
fn invalidate(&mut self) -> Result<(), CacheError>;
fn clear(&mut self) -> Result<(), CacheError>;
fn clear_hsm(&mut self) -> Result<(), CacheError>;
fn get_hsm_machine_key(&mut self) -> Result<Option<LoadableMachineKey>, CacheError>;
fn insert_hsm_machine_key(
&mut self,
machine_key: &LoadableMachineKey,
) -> Result<(), CacheError>;
fn get_hsm_hmac_key(&mut self) -> Result<Option<LoadableHmacKey>, CacheError>;
fn insert_hsm_hmac_key(&mut self, hmac_key: &LoadableHmacKey) -> Result<(), CacheError>;
fn get_account(&mut self, account_id: &Id) -> Result<Option<(UserToken, u64)>, CacheError>;
fn get_accounts(&mut self) -> Result<Vec<UserToken>, CacheError>;
fn update_account(&mut self, account: &UserToken, expire: u64) -> Result<(), CacheError>;
fn delete_account(&mut self, a_uuid: Uuid) -> Result<(), CacheError>;
fn update_account_password(
&mut self,
a_uuid: Uuid,
cred: &str,
hsm: &mut dyn Tpm,
hmac_key: &HmacKey,
) -> Result<(), CacheError>;
fn check_account_password(
&mut self,
a_uuid: Uuid,
cred: &str,
hsm: &mut dyn Tpm,
hmac_key: &HmacKey,
) -> Result<bool, CacheError>;
fn get_group(&mut self, grp_id: &Id) -> Result<Option<(GroupToken, u64)>, CacheError>;
fn get_group_members(&mut self, g_uuid: Uuid) -> Result<Vec<UserToken>, CacheError>;
fn get_groups(&mut self) -> Result<Vec<GroupToken>, CacheError>;
fn update_group(&mut self, grp: &GroupToken, expire: u64) -> Result<(), CacheError>;
fn delete_group(&mut self, g_uuid: Uuid) -> Result<(), CacheError>;
}
pub trait KeyStoreTxn {
fn get_tagged_hsm_key<K: DeserializeOwned>(
&mut self,
tag: &str,
) -> Result<Option<K>, CacheError>;
fn insert_tagged_hsm_key<K: Serialize>(&mut self, tag: &str, key: &K)
-> Result<(), CacheError>;
fn delete_tagged_hsm_key(&mut self, tag: &str) -> Result<(), CacheError>;
}
pub struct Db {
conn: Mutex<Connection>,
crypto_policy: CryptoPolicy,
@ -127,6 +58,16 @@ pub struct DbTxn<'a> {
crypto_policy: &'a CryptoPolicy,
}
pub struct KeyStoreTxn<'a, 'b> {
db: &'b mut DbTxn<'a>,
}
impl<'a, 'b> From<&'b mut DbTxn<'a>> for KeyStoreTxn<'a, 'b> {
fn from(db: &'b mut DbTxn<'a>) -> Self {
Self { db }
}
}
#[derive(Debug)]
/// Errors coming back from the `Db` struct
pub enum DbError {
@ -312,7 +253,28 @@ impl<'a> DbTxn<'a> {
}
}
impl<'a> KeyStoreTxn for DbTxn<'a> {
impl<'a, 'b> KeyStoreTxn<'a, 'b> {
pub fn get_tagged_hsm_key<K: DeserializeOwned>(
&mut self,
tag: &str,
) -> Result<Option<K>, CacheError> {
self.db.get_tagged_hsm_key(tag)
}
pub fn insert_tagged_hsm_key<K: Serialize>(
&mut self,
tag: &str,
key: &K,
) -> Result<(), CacheError> {
self.db.insert_tagged_hsm_key(tag, key)
}
pub fn delete_tagged_hsm_key(&mut self, tag: &str) -> Result<(), CacheError> {
self.db.delete_tagged_hsm_key(tag)
}
}
impl<'a> DbTxn<'a> {
fn get_tagged_hsm_key<K: DeserializeOwned>(
&mut self,
tag: &str,
@ -380,8 +342,8 @@ impl<'a> KeyStoreTxn for DbTxn<'a> {
}
}
impl<'a> CacheTxn for DbTxn<'a> {
fn migrate(&mut self) -> Result<(), CacheError> {
impl<'a> DbTxn<'a> {
pub fn migrate(&mut self) -> Result<(), CacheError> {
self.conn.set_prepared_statement_cache_capacity(16);
self.conn
.prepare("PRAGMA journal_mode=WAL;")
@ -488,7 +450,7 @@ impl<'a> CacheTxn for DbTxn<'a> {
Ok(())
}
fn commit(mut self) -> Result<(), CacheError> {
pub fn commit(mut self) -> Result<(), CacheError> {
// debug!("Committing BE txn");
if self.committed {
error!("Invalid state, SQL transaction was already committed!");
@ -502,7 +464,7 @@ impl<'a> CacheTxn for DbTxn<'a> {
.map_err(|e| self.sqlite_error("commit", &e))
}
fn invalidate(&mut self) -> Result<(), CacheError> {
pub fn invalidate(&mut self) -> Result<(), CacheError> {
self.conn
.execute("UPDATE group_t SET expiry = 0", [])
.map_err(|e| self.sqlite_error("update group_t", &e))?;
@ -514,7 +476,7 @@ impl<'a> CacheTxn for DbTxn<'a> {
Ok(())
}
fn clear(&mut self) -> Result<(), CacheError> {
pub fn clear(&mut self) -> Result<(), CacheError> {
self.conn
.execute("DELETE FROM memberof_t", [])
.map_err(|e| self.sqlite_error("delete memberof_t", &e))?;
@ -530,7 +492,7 @@ impl<'a> CacheTxn for DbTxn<'a> {
Ok(())
}
fn clear_hsm(&mut self) -> Result<(), CacheError> {
pub fn clear_hsm(&mut self) -> Result<(), CacheError> {
self.clear()?;
self.conn
@ -544,7 +506,7 @@ impl<'a> CacheTxn for DbTxn<'a> {
Ok(())
}
fn get_hsm_machine_key(&mut self) -> Result<Option<LoadableMachineKey>, CacheError> {
pub fn get_hsm_machine_key(&mut self) -> Result<Option<LoadableMachineKey>, CacheError> {
let mut stmt = self
.conn
.prepare("SELECT value FROM hsm_int_t WHERE key = 'mk'")
@ -565,7 +527,7 @@ impl<'a> CacheTxn for DbTxn<'a> {
}
}
fn insert_hsm_machine_key(
pub fn insert_hsm_machine_key(
&mut self,
machine_key: &LoadableMachineKey,
) -> Result<(), CacheError> {
@ -589,7 +551,7 @@ impl<'a> CacheTxn for DbTxn<'a> {
.map_err(|e| self.sqlite_error("execute", &e))
}
fn get_hsm_hmac_key(&mut self) -> Result<Option<LoadableHmacKey>, CacheError> {
pub fn get_hsm_hmac_key(&mut self) -> Result<Option<LoadableHmacKey>, CacheError> {
let mut stmt = self
.conn
.prepare("SELECT value FROM hsm_int_t WHERE key = 'hmac'")
@ -610,7 +572,7 @@ impl<'a> CacheTxn for DbTxn<'a> {
}
}
fn insert_hsm_hmac_key(&mut self, hmac_key: &LoadableHmacKey) -> Result<(), CacheError> {
pub fn insert_hsm_hmac_key(&mut self, hmac_key: &LoadableHmacKey) -> Result<(), CacheError> {
let data = serde_json::to_vec(hmac_key).map_err(|e| {
error!("insert_hsm_hmac_key json error -> {:?}", e);
CacheError::SerdeJson
@ -631,7 +593,7 @@ impl<'a> CacheTxn for DbTxn<'a> {
.map_err(|e| self.sqlite_error("execute", &e))
}
fn get_account(&mut self, account_id: &Id) -> Result<Option<(UserToken, u64)>, CacheError> {
pub fn get_account(&mut self, account_id: &Id) -> Result<Option<(UserToken, u64)>, CacheError> {
let data = match account_id {
Id::Name(n) => self.get_account_data_name(n.as_str()),
Id::Gid(g) => self.get_account_data_gid(*g),
@ -665,7 +627,7 @@ impl<'a> CacheTxn for DbTxn<'a> {
}
}
fn get_accounts(&mut self) -> Result<Vec<UserToken>, CacheError> {
pub fn get_accounts(&mut self) -> Result<Vec<UserToken>, CacheError> {
let mut stmt = self
.conn
.prepare("SELECT token FROM account_t")
@ -694,7 +656,7 @@ impl<'a> CacheTxn for DbTxn<'a> {
.collect())
}
fn update_account(&mut self, account: &UserToken, expire: u64) -> Result<(), CacheError> {
pub fn update_account(&mut self, account: &UserToken, expire: u64) -> Result<(), CacheError> {
let data = serde_json::to_vec(account).map_err(|e| {
error!("update_account json error -> {:?}", e);
CacheError::SerdeJson
@ -790,7 +752,7 @@ impl<'a> CacheTxn for DbTxn<'a> {
})
}
fn delete_account(&mut self, a_uuid: Uuid) -> Result<(), CacheError> {
pub fn delete_account(&mut self, a_uuid: Uuid) -> Result<(), CacheError> {
let account_uuid = a_uuid.as_hyphenated().to_string();
self.conn
@ -810,7 +772,7 @@ impl<'a> CacheTxn for DbTxn<'a> {
.map_err(|e| self.sqlite_error("account_t delete", &e))
}
fn update_account_password(
pub fn update_account_password(
&mut self,
a_uuid: Uuid,
cred: &str,
@ -841,7 +803,7 @@ impl<'a> CacheTxn for DbTxn<'a> {
.map(|_| ())
}
fn check_account_password(
pub fn check_account_password(
&mut self,
a_uuid: Uuid,
cred: &str,
@ -892,7 +854,7 @@ impl<'a> CacheTxn for DbTxn<'a> {
})
}
fn get_group(&mut self, grp_id: &Id) -> Result<Option<(GroupToken, u64)>, CacheError> {
pub fn get_group(&mut self, grp_id: &Id) -> Result<Option<(GroupToken, u64)>, CacheError> {
let data = match grp_id {
Id::Name(n) => self.get_group_data_name(n.as_str()),
Id::Gid(g) => self.get_group_data_gid(*g),
@ -926,7 +888,7 @@ impl<'a> CacheTxn for DbTxn<'a> {
}
}
fn get_group_members(&mut self, g_uuid: Uuid) -> Result<Vec<UserToken>, CacheError> {
pub fn get_group_members(&mut self, g_uuid: Uuid) -> Result<Vec<UserToken>, CacheError> {
let mut stmt = self
.conn
.prepare("SELECT account_t.token FROM (account_t, memberof_t) WHERE account_t.uuid = memberof_t.a_uuid AND memberof_t.g_uuid = :g_uuid")
@ -955,7 +917,7 @@ impl<'a> CacheTxn for DbTxn<'a> {
.collect()
}
fn get_groups(&mut self) -> Result<Vec<GroupToken>, CacheError> {
pub fn get_groups(&mut self) -> Result<Vec<GroupToken>, CacheError> {
let mut stmt = self
.conn
.prepare("SELECT token FROM group_t")
@ -984,7 +946,7 @@ impl<'a> CacheTxn for DbTxn<'a> {
.collect())
}
fn update_group(&mut self, grp: &GroupToken, expire: u64) -> Result<(), CacheError> {
pub fn update_group(&mut self, grp: &GroupToken, expire: u64) -> Result<(), CacheError> {
let data = serde_json::to_vec(grp).map_err(|e| {
error!("json error -> {:?}", e);
CacheError::SerdeJson
@ -1015,7 +977,7 @@ impl<'a> CacheTxn for DbTxn<'a> {
.map_err(|e| self.sqlite_error("execute", &e))
}
fn delete_group(&mut self, g_uuid: Uuid) -> Result<(), CacheError> {
pub fn delete_group(&mut self, g_uuid: Uuid) -> Result<(), CacheError> {
let group_uuid = g_uuid.as_hyphenated().to_string();
self.conn
.execute(
@ -1053,7 +1015,7 @@ impl<'a> Drop for DbTxn<'a> {
#[cfg(test)]
mod tests {
use super::{Cache, CacheTxn, Db};
use super::{Cache, Db};
use crate::idprovider::interface::{GroupToken, Id, UserToken};
use kanidm_hsm_crypto::{AuthValue, Tpm};

View file

@ -1,6 +1,8 @@
use crate::db::KeyStoreTxn;
use crate::unix_proto::{DeviceAuthorizationResponse, PamAuthRequest, PamAuthResponse};
use async_trait::async_trait;
use kanidm_unix_common::unix_proto::{
DeviceAuthorizationResponse, PamAuthRequest, PamAuthResponse,
};
use serde::{Deserialize, Serialize};
use tokio::sync::broadcast;
use uuid::Uuid;
@ -138,9 +140,9 @@ pub enum AuthCacheAction {
#[async_trait]
pub trait IdProvider {
async fn configure_hsm_keys<D: KeyStoreTxn + Send>(
async fn configure_hsm_keys(
&self,
_keystore: &mut D,
_keystore: &mut KeyStoreTxn,
_tpm: &mut tpm::BoxedDynTpm,
_machine_key: &tpm::MachineKey,
) -> Result<(), IdpError> {
@ -150,10 +152,10 @@ pub trait IdProvider {
/// This is similar to a "domain join" process. What do we actually need to pass here
/// for this to work for kanidm or himmelblau? Should we make it take a generic?
/*
async fn configure_machine_identity<D: KeyStoreTxn + Send>(
async fn configure_machine_identity(
&self,
_keystore: &mut D,
_tpm: &mut (dyn tpm::Tpm + Send),
_keystore: &mut KeyStoreTxn,
_tpm: &mut tpm::BoxedDynTpm,
_machine_key: &tpm::MachineKey,
) -> Result<(), IdpError> {
Ok(())
@ -170,32 +172,32 @@ pub trait IdProvider {
_machine_key: &tpm::MachineKey,
) -> Result<UserToken, IdpError>;
async fn unix_user_online_auth_init<D: KeyStoreTxn + Send>(
async fn unix_user_online_auth_init(
&self,
_account_id: &str,
_token: Option<&UserToken>,
_keystore: &mut D,
_keystore: &mut KeyStoreTxn,
_tpm: &mut tpm::BoxedDynTpm,
_machine_key: &tpm::MachineKey,
_shutdown_rx: &broadcast::Receiver<()>,
) -> Result<(AuthRequest, AuthCredHandler), IdpError>;
async fn unix_user_online_auth_step<D: KeyStoreTxn + Send>(
async fn unix_user_online_auth_step(
&self,
_account_id: &str,
_cred_handler: &mut AuthCredHandler,
_pam_next_req: PamAuthRequest,
_keystore: &mut D,
_keystore: &mut KeyStoreTxn,
_tpm: &mut tpm::BoxedDynTpm,
_machine_key: &tpm::MachineKey,
_shutdown_rx: &broadcast::Receiver<()>,
) -> Result<(AuthResult, AuthCacheAction), IdpError>;
async fn unix_user_offline_auth_init<D: KeyStoreTxn + Send>(
async fn unix_user_offline_auth_init(
&self,
_account_id: &str,
_token: Option<&UserToken>,
_keystore: &mut D,
_keystore: &mut KeyStoreTxn,
) -> Result<(AuthRequest, AuthCredHandler), IdpError>;
// I thought about this part of the interface a lot. we could have the
@ -217,13 +219,13 @@ pub trait IdProvider {
// unlock the associated TPM key. While we can't perform a full request
// for an auth token, we can verify that the PIN successfully unlocks the
// TPM key.
async fn unix_user_offline_auth_step<D: KeyStoreTxn + Send>(
async fn unix_user_offline_auth_step(
&self,
_account_id: &str,
_token: &UserToken,
_cred_handler: &mut AuthCredHandler,
_pam_next_req: PamAuthRequest,
_keystore: &mut D,
_keystore: &mut KeyStoreTxn,
_tpm: &mut tpm::BoxedDynTpm,
_machine_key: &tpm::MachineKey,
_online_at_init: bool,

View file

@ -19,7 +19,7 @@ use super::interface::{
IdpError,
UserToken,
};
use crate::unix_proto::PamAuthRequest;
use kanidm_unix_common::unix_proto::PamAuthRequest;
const TAG_IDKEY: &str = "idkey";
@ -85,9 +85,9 @@ impl From<UnixGroupToken> for GroupToken {
#[async_trait]
impl IdProvider for KanidmProvider {
async fn configure_hsm_keys<D: KeyStoreTxn + Send>(
async fn configure_hsm_keys(
&self,
keystore: &mut D,
keystore: &mut KeyStoreTxn,
tpm: &mut tpm::BoxedDynTpm,
machine_key: &tpm::MachineKey,
) -> Result<(), IdpError> {
@ -191,11 +191,11 @@ impl IdProvider for KanidmProvider {
}
}
async fn unix_user_online_auth_init<D: KeyStoreTxn + Send>(
async fn unix_user_online_auth_init(
&self,
_account_id: &str,
_token: Option<&UserToken>,
_keystore: &mut D,
_keystore: &mut KeyStoreTxn,
_tpm: &mut tpm::BoxedDynTpm,
_machine_key: &tpm::MachineKey,
_shutdown_rx: &broadcast::Receiver<()>,
@ -204,12 +204,12 @@ impl IdProvider for KanidmProvider {
Ok((AuthRequest::Password, AuthCredHandler::Password))
}
async fn unix_user_online_auth_step<D: KeyStoreTxn + Send>(
async fn unix_user_online_auth_step(
&self,
account_id: &str,
cred_handler: &mut AuthCredHandler,
pam_next_req: PamAuthRequest,
_keystore: &mut D,
_keystore: &mut KeyStoreTxn,
_tpm: &mut tpm::BoxedDynTpm,
_machine_key: &tpm::MachineKey,
_shutdown_rx: &broadcast::Receiver<()>,
@ -293,23 +293,23 @@ impl IdProvider for KanidmProvider {
}
}
async fn unix_user_offline_auth_init<D: KeyStoreTxn + Send>(
async fn unix_user_offline_auth_init(
&self,
_account_id: &str,
_token: Option<&UserToken>,
_keystore: &mut D,
_keystore: &mut KeyStoreTxn,
) -> Result<(AuthRequest, AuthCredHandler), IdpError> {
// Not sure that I need to do much here?
Ok((AuthRequest::Password, AuthCredHandler::Password))
}
async fn unix_user_offline_auth_step<D: KeyStoreTxn + Send>(
async fn unix_user_offline_auth_step(
&self,
_account_id: &str,
_token: &UserToken,
_cred_handler: &mut AuthCredHandler,
_pam_next_req: PamAuthRequest,
_keystore: &mut D,
_keystore: &mut KeyStoreTxn,
_tpm: &mut tpm::BoxedDynTpm,
_machine_key: &tpm::MachineKey,
_online_at_init: bool,

View file

@ -17,25 +17,13 @@ extern crate tracing;
#[macro_use]
extern crate rusqlite;
#[cfg(target_family = "unix")]
pub mod client;
#[cfg(target_family = "unix")]
pub mod client_sync;
#[cfg(target_family = "unix")]
pub mod constants;
#[cfg(target_family = "unix")]
pub mod db;
#[cfg(target_family = "unix")]
pub mod idprovider;
#[cfg(target_family = "unix")]
pub mod pam_data;
#[cfg(target_family = "unix")]
pub mod resolver;
#[cfg(all(target_family = "unix", feature = "selinux"))]
pub mod selinux_util;
#[cfg(target_family = "unix")]
pub mod unix_config;
#[cfg(target_family = "unix")]
pub mod unix_passwd;
#[cfg(target_family = "unix")]
pub mod unix_proto;

View file

@ -12,7 +12,7 @@ use lru::LruCache;
use tokio::sync::Mutex;
use uuid::Uuid;
use crate::db::{Cache, CacheTxn, Db};
use crate::db::{Cache, Db};
use crate::idprovider::interface::{
AuthCacheAction,
AuthCredHandler,
@ -25,7 +25,9 @@ use crate::idprovider::interface::{
UserToken,
};
use crate::unix_config::{HomeAttr, UidAttr};
use crate::unix_proto::{HomeDirectoryInfo, NssGroup, NssUser, PamAuthRequest, PamAuthResponse};
use kanidm_unix_common::unix_proto::{
HomeDirectoryInfo, NssGroup, NssUser, PamAuthRequest, PamAuthResponse,
};
use kanidm_hsm_crypto::{BoxedDynTpm, HmacKey, MachineKey, Tpm};
@ -58,16 +60,18 @@ pub enum AuthSession {
Denied,
}
pub struct Resolver<I>
where
I: IdProvider + Sync,
{
pub struct Resolver {
// Generic / modular types.
db: Db,
hsm: Mutex<BoxedDynTpm>,
machine_key: MachineKey,
hmac_key: HmacKey,
client: I,
// A local passwd/shadow resolver.
// A set of remote resolvers
client: Box<dyn IdProvider + Sync + Send>,
// Types to update still.
state: Mutex<CacheState>,
pam_allow_groups: BTreeSet<String>,
@ -92,14 +96,11 @@ impl Display for Id {
}
}
impl<I> Resolver<I>
where
I: IdProvider + Sync,
{
impl Resolver {
#[allow(clippy::too_many_arguments)]
pub async fn new(
db: Db,
client: I,
client: Box<dyn IdProvider + Sync + Send>,
hsm: BoxedDynTpm,
machine_key: MachineKey,
// cache timeout
@ -148,14 +149,11 @@ where
})?;
// Ask the client what keys it wants the HSM to configure.
// make a key store
// let mut ks = KeyStore::new(&mut dbtxn);
let result = client
.configure_hsm_keys(&mut dbtxn, hsm_lock.deref_mut(), &machine_key)
.configure_hsm_keys(&mut (&mut dbtxn).into(), hsm_lock.deref_mut(), &machine_key)
.await;
// drop(ks);
drop(hsm_lock);
result.map_err(|err| {
@ -900,7 +898,7 @@ where
.unix_user_online_auth_init(
account_id,
token.as_ref(),
&mut dbtxn,
&mut (&mut dbtxn).into(),
hsm_lock.deref_mut(),
&self.machine_key,
&shutdown_rx,
@ -911,7 +909,7 @@ where
// Can the auth proceed offline?
self.client
.unix_user_offline_auth_init(account_id, token.as_ref(), &mut dbtxn)
.unix_user_offline_auth_init(account_id, token.as_ref(), &mut (&mut dbtxn).into())
.await
};
@ -972,7 +970,7 @@ where
account_id,
cred_handler,
pam_next_req,
&mut dbtxn,
&mut (&mut dbtxn).into(),
hsm_lock.deref_mut(),
&self.machine_key,
shutdown_rx,
@ -1077,7 +1075,7 @@ where
token,
cred_handler,
pam_next_req,
&mut dbtxn,
&mut (&mut dbtxn).into(),
hsm_lock.deref_mut(),
&self.machine_key,
online_at_init,

View file

@ -6,11 +6,13 @@ use std::path::Path;
#[cfg(all(target_family = "unix", feature = "selinux"))]
use crate::selinux_util;
use crate::unix_passwd::UnixIntegrationError;
use kanidm_unix_common::unix_passwd::UnixIntegrationError;
pub(crate) use kanidm_unix_common::unix_config::{HomeAttr, UidAttr};
use serde::Deserialize;
use crate::constants::*;
use kanidm_unix_common::constants::*;
#[derive(Debug, Deserialize)]
struct ConfigInt {
@ -37,46 +39,6 @@ struct ConfigInt {
tpm_tcti_name: Option<String>,
}
#[derive(Debug, Copy, Clone)]
pub enum HomeAttr {
Uuid,
Spn,
Name,
}
impl Display for HomeAttr {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{}",
match self {
HomeAttr::Uuid => "UUID",
HomeAttr::Spn => "SPN",
HomeAttr::Name => "Name",
}
)
}
}
#[derive(Debug, Copy, Clone)]
pub enum UidAttr {
Name,
Spn,
}
impl Display for UidAttr {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{}",
match self {
UidAttr::Name => "Name",
UidAttr::Spn => "SPN",
}
)
}
}
#[derive(Debug, Clone, Default)]
pub enum HsmType {
#[cfg_attr(not(feature = "tpm"), default)]

View file

@ -10,10 +10,10 @@ use kanidm_unix_common::constants::{
DEFAULT_GID_ATTR_MAP, DEFAULT_HOME_ALIAS, DEFAULT_HOME_ATTR, DEFAULT_HOME_PREFIX,
DEFAULT_SHELL, DEFAULT_UID_ATTR_MAP,
};
use kanidm_unix_common::db::{Cache, CacheTxn, Db};
use kanidm_unix_common::idprovider::interface::Id;
use kanidm_unix_common::idprovider::kanidm::KanidmProvider;
use kanidm_unix_common::resolver::Resolver;
use kanidm_unix_resolver::db::{Cache, Db};
use kanidm_unix_resolver::idprovider::interface::Id;
use kanidm_unix_resolver::idprovider::kanidm::KanidmProvider;
use kanidm_unix_resolver::resolver::Resolver;
use kanidmd_core::config::{Configuration, IntegrationTestConfig, ServerRole};
use kanidmd_core::create_server_core;
use kanidmd_testkit::{is_free_port, PORT_ALLOC};
@ -40,7 +40,7 @@ where
Box::new(move |n| Box::pin(f(n)))
}
async fn setup_test(fix_fn: Fixture) -> (Resolver<KanidmProvider>, KanidmClient) {
async fn setup_test(fix_fn: Fixture) -> (Resolver, KanidmClient) {
sketching::test_init();
let mut counter = 0;
@ -125,7 +125,7 @@ async fn setup_test(fix_fn: Fixture) -> (Resolver<KanidmProvider>, KanidmClient)
let cachelayer = Resolver::new(
db,
idprovider,
Box::new(idprovider),
hsm,
machine_key,
300,

View file

@ -1,7 +0,0 @@
use serde::{Deserialize, Serialize};
/* This is the definition for extra data to be sent along with a pam_prompt
* request. It will be sent back to the idprovider to continue an auth attempt.
*/
#[derive(Serialize, Deserialize, Debug)]
pub struct PamData {}