mirror of
https://github.com/samba-team/samba.git
synced 2025-01-08 21:18:16 +03:00
Add the Azure Entra Id Daemon
Signed-off-by: David Mulder <dmulder@samba.org> Reviewed-by: Alexander Bokovoy <ab@samba.org>
This commit is contained in:
parent
f1aa68041e
commit
aea926391f
@ -12,21 +12,36 @@ homepage.workspace = true
|
||||
version.workspace = true
|
||||
|
||||
[dependencies]
|
||||
libhimmelblau = "0.2.7"
|
||||
ntstatus_gen.workspace = true
|
||||
param = { workspace = true }
|
||||
sock = { workspace = true }
|
||||
tdb = { workspace = true }
|
||||
dbg = { workspace = true }
|
||||
chelps.workspace = true
|
||||
clap = "4.5.9"
|
||||
kanidm-hsm-crypto = "0.2.0"
|
||||
serde_json = "1.0.120"
|
||||
tokio = { version = "1.38.1", features = [ "rt", "macros" ] }
|
||||
tokio-util = { version = "0.7.11", features = ["codec"] }
|
||||
bytes = "1.6.1"
|
||||
futures = "0.3.30"
|
||||
serde = "1.0.204"
|
||||
idmap = { workspace = true }
|
||||
libc = "0.2.155"
|
||||
|
||||
[workspace]
|
||||
members = [
|
||||
"chelps", "dbg", "idmap",
|
||||
"ntstatus_gen",
|
||||
"param", "tdb",
|
||||
"param", "sock", "tdb",
|
||||
]
|
||||
|
||||
[workspace.dependencies]
|
||||
param = { path = "param" }
|
||||
dbg = { path = "dbg" }
|
||||
chelps = { path = "chelps" }
|
||||
sock = { path = "sock" }
|
||||
ntstatus_gen = { path = "ntstatus_gen" }
|
||||
tdb = { path = "tdb" }
|
||||
idmap = { path = "idmap" }
|
||||
|
18
himmelblaud/build.rs
Normal file
18
himmelblaud/build.rs
Normal file
@ -0,0 +1,18 @@
|
||||
use std::env;
|
||||
|
||||
fn main() {
|
||||
// Re-export the Target OS, so that Himmelblaud has access to this at
|
||||
// runtime.
|
||||
if &env::var("CARGO_CFG_TARGET_OS").unwrap() != "none" {
|
||||
println!(
|
||||
"cargo:rustc-env=TARGET_OS={}",
|
||||
&env::var("CARGO_CFG_TARGET_OS").unwrap()
|
||||
);
|
||||
} else {
|
||||
println!(
|
||||
"cargo:rustc-env=TARGET_OS={}",
|
||||
&env::var("CARGO_CFG_TARGET_FAMILY").unwrap()
|
||||
);
|
||||
}
|
||||
println!("cargo:rerun-if-changed-env=TARGET");
|
||||
}
|
12
himmelblaud/sock/Cargo.toml
Normal file
12
himmelblaud/sock/Cargo.toml
Normal file
@ -0,0 +1,12 @@
|
||||
[package]
|
||||
name = "sock"
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
homepage.workspace = true
|
||||
version.workspace = true
|
||||
|
||||
[dependencies]
|
||||
libc = "0.2.155"
|
||||
libnss = "0.8.0"
|
||||
serde = { version = "1.0.204", features = ["derive"] }
|
||||
serde_json = "1.0.120"
|
57
himmelblaud/sock/src/lib.rs
Normal file
57
himmelblaud/sock/src/lib.rs
Normal file
@ -0,0 +1,57 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
|
||||
Unix socket communication for the Himmelblau daemon
|
||||
|
||||
Copyright (C) David Mulder 2024
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
mod proto;
|
||||
pub use proto::*;
|
||||
|
||||
use serde_json::{from_slice as json_from_slice, to_vec as json_to_vec};
|
||||
use std::error::Error;
|
||||
use std::io::{Read, Write};
|
||||
use std::os::unix::net::UnixStream;
|
||||
use std::time::Duration;
|
||||
|
||||
pub struct ClientStream {
|
||||
stream: UnixStream,
|
||||
}
|
||||
|
||||
impl ClientStream {
|
||||
pub fn new(path: &str) -> Result<Self, Box<dyn Error>> {
|
||||
Ok(ClientStream {
|
||||
stream: UnixStream::connect(path)?,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn send(
|
||||
&mut self,
|
||||
req: &Request,
|
||||
timeout: u64,
|
||||
) -> Result<Response, Box<dyn Error>> {
|
||||
let timeout = Duration::from_secs(timeout);
|
||||
self.stream.set_read_timeout(Some(timeout))?;
|
||||
self.stream.set_write_timeout(Some(timeout))?;
|
||||
let req_bytes = json_to_vec(req)?;
|
||||
self.stream.write_all(&req_bytes)?;
|
||||
let mut buf = Vec::new();
|
||||
self.stream.read_to_end(&mut buf)?;
|
||||
let resp: Response = json_from_slice(&buf)?;
|
||||
Ok(resp)
|
||||
}
|
||||
}
|
115
himmelblaud/sock/src/proto.rs
Normal file
115
himmelblaud/sock/src/proto.rs
Normal file
@ -0,0 +1,115 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
|
||||
Unix socket communication for the Himmelblau daemon
|
||||
|
||||
Copyright (C) David Mulder 2024
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
use libc::uid_t;
|
||||
use libnss::group::Group as NssGroup;
|
||||
use libnss::passwd::Passwd as NssPasswd;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct Passwd {
|
||||
pub name: String,
|
||||
pub passwd: String,
|
||||
pub uid: u32,
|
||||
pub gid: u32,
|
||||
pub gecos: String,
|
||||
pub dir: String,
|
||||
pub shell: String,
|
||||
}
|
||||
|
||||
impl From<Passwd> for NssPasswd {
|
||||
fn from(val: Passwd) -> Self {
|
||||
NssPasswd {
|
||||
name: val.name,
|
||||
passwd: val.passwd,
|
||||
uid: val.uid,
|
||||
gid: val.gid,
|
||||
gecos: val.gecos,
|
||||
dir: val.dir,
|
||||
shell: val.shell,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct Group {
|
||||
pub name: String,
|
||||
pub passwd: String,
|
||||
pub gid: u32,
|
||||
pub members: Vec<String>,
|
||||
}
|
||||
|
||||
impl From<Group> for NssGroup {
|
||||
fn from(val: Group) -> Self {
|
||||
NssGroup {
|
||||
name: val.name,
|
||||
passwd: val.passwd,
|
||||
gid: val.gid,
|
||||
members: val.members,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub enum PamAuthRequest {
|
||||
Password { cred: String },
|
||||
MFACode { cred: String },
|
||||
MFAPoll { poll_attempt: u32 },
|
||||
SetupPin { pin: String },
|
||||
Pin { pin: String },
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub enum Request {
|
||||
NssAccounts,
|
||||
NssAccountByUid(uid_t),
|
||||
NssAccountByName(String),
|
||||
NssGroups,
|
||||
NssGroupByGid(uid_t),
|
||||
NssGroupByName(String),
|
||||
PamAuthenticateInit(String),
|
||||
PamAuthenticateStep(PamAuthRequest),
|
||||
PamAccountAllowed(String),
|
||||
PamAccountBeginSession(String),
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub enum PamAuthResponse {
|
||||
Unknown,
|
||||
Success,
|
||||
Denied,
|
||||
Password,
|
||||
MFACode { msg: String },
|
||||
MFAPoll { msg: String, polling_interval: u32 },
|
||||
SetupPin { msg: String },
|
||||
Pin,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub enum Response {
|
||||
NssAccounts(Vec<Passwd>),
|
||||
NssAccount(Option<Passwd>),
|
||||
NssGroups(Vec<Group>),
|
||||
NssGroup(Option<Group>),
|
||||
PamStatus(Option<bool>),
|
||||
PamAuthStepResponse(PamAuthResponse),
|
||||
Success,
|
||||
Error,
|
||||
}
|
1
himmelblaud/src/constants.rs
Normal file
1
himmelblaud/src/constants.rs
Normal file
@ -0,0 +1 @@
|
||||
pub const DEFAULT_ODC_PROVIDER: &str = "odc.officeapps.live.com";
|
153
himmelblaud/src/himmelblaud.rs
Normal file
153
himmelblaud/src/himmelblaud.rs
Normal file
@ -0,0 +1,153 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
|
||||
Himmelblau daemon
|
||||
|
||||
Copyright (C) David Mulder 2024
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
use crate::cache::{GroupCache, PrivateCache, UserCache};
|
||||
use bytes::{BufMut, BytesMut};
|
||||
use dbg::{DBG_DEBUG, DBG_ERR};
|
||||
use futures::{SinkExt, StreamExt};
|
||||
use himmelblau::graph::Graph;
|
||||
use himmelblau::BrokerClientApplication;
|
||||
use idmap::Idmap;
|
||||
use kanidm_hsm_crypto::{BoxedDynTpm, MachineKey};
|
||||
use param::LoadParm;
|
||||
use sock::{Request, Response};
|
||||
use std::error::Error;
|
||||
use std::io;
|
||||
use std::io::{Error as IoError, ErrorKind};
|
||||
use std::sync::Arc;
|
||||
use tokio::net::UnixStream;
|
||||
use tokio::sync::Mutex;
|
||||
use tokio_util::codec::{Decoder, Encoder, Framed};
|
||||
|
||||
pub(crate) struct Resolver {
|
||||
realm: String,
|
||||
tenant_id: String,
|
||||
lp: LoadParm,
|
||||
idmap: Idmap,
|
||||
graph: Graph,
|
||||
pcache: PrivateCache,
|
||||
user_cache: UserCache,
|
||||
group_cache: GroupCache,
|
||||
hsm: Mutex<BoxedDynTpm>,
|
||||
machine_key: MachineKey,
|
||||
client: Arc<Mutex<BrokerClientApplication>>,
|
||||
}
|
||||
|
||||
impl Resolver {
|
||||
pub(crate) fn new(
|
||||
realm: &str,
|
||||
tenant_id: &str,
|
||||
lp: LoadParm,
|
||||
idmap: Idmap,
|
||||
graph: Graph,
|
||||
pcache: PrivateCache,
|
||||
user_cache: UserCache,
|
||||
group_cache: GroupCache,
|
||||
hsm: BoxedDynTpm,
|
||||
machine_key: MachineKey,
|
||||
client: BrokerClientApplication,
|
||||
) -> Self {
|
||||
Resolver {
|
||||
realm: realm.to_string(),
|
||||
tenant_id: tenant_id.to_string(),
|
||||
lp,
|
||||
idmap,
|
||||
graph,
|
||||
pcache,
|
||||
user_cache,
|
||||
group_cache,
|
||||
hsm: Mutex::new(hsm),
|
||||
machine_key,
|
||||
client: Arc::new(Mutex::new(client)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct ClientCodec;
|
||||
|
||||
impl Decoder for ClientCodec {
|
||||
type Error = io::Error;
|
||||
type Item = Request;
|
||||
|
||||
fn decode(
|
||||
&mut self,
|
||||
src: &mut BytesMut,
|
||||
) -> Result<Option<Self::Item>, Self::Error> {
|
||||
match serde_json::from_slice::<Request>(src) {
|
||||
Ok(msg) => {
|
||||
src.clear();
|
||||
Ok(Some(msg))
|
||||
}
|
||||
_ => Ok(None),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Encoder<Response> for ClientCodec {
|
||||
type Error = io::Error;
|
||||
|
||||
fn encode(
|
||||
&mut self,
|
||||
msg: Response,
|
||||
dst: &mut BytesMut,
|
||||
) -> Result<(), Self::Error> {
|
||||
DBG_DEBUG!("Attempting to send response -> {:?} ...", msg);
|
||||
let data = serde_json::to_vec(&msg).map_err(|e| {
|
||||
DBG_ERR!("socket encoding error -> {:?}", e);
|
||||
io::Error::new(ErrorKind::Other, "JSON encode error")
|
||||
})?;
|
||||
dst.put(data.as_slice());
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl ClientCodec {
|
||||
fn new() -> Self {
|
||||
ClientCodec
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) async fn handle_client(
|
||||
stream: UnixStream,
|
||||
resolver: Arc<Mutex<Resolver>>,
|
||||
) -> Result<(), Box<dyn Error>> {
|
||||
DBG_DEBUG!("Accepted connection");
|
||||
|
||||
let Ok(_ucred) = stream.peer_cred() else {
|
||||
return Err(Box::new(IoError::new(
|
||||
ErrorKind::Other,
|
||||
"Unable to verify peer credentials.",
|
||||
)));
|
||||
};
|
||||
|
||||
let mut reqs = Framed::new(stream, ClientCodec::new());
|
||||
|
||||
while let Some(Ok(req)) = reqs.next().await {
|
||||
let resp = match req {
|
||||
_ => todo!(),
|
||||
};
|
||||
reqs.send(resp).await?;
|
||||
reqs.flush().await?;
|
||||
DBG_DEBUG!("flushed response!");
|
||||
}
|
||||
|
||||
DBG_DEBUG!("Disconnecting client ...");
|
||||
Ok(())
|
||||
}
|
@ -1 +1,382 @@
|
||||
fn main() {}
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
|
||||
Himmelblau daemon
|
||||
|
||||
Copyright (C) David Mulder 2024
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
use clap::{Arg, ArgAction, Command};
|
||||
use dbg::*;
|
||||
use himmelblau::graph::Graph;
|
||||
use himmelblau::BrokerClientApplication;
|
||||
use idmap::Idmap;
|
||||
use kanidm_hsm_crypto::soft::SoftTpm;
|
||||
use kanidm_hsm_crypto::{BoxedDynTpm, Tpm};
|
||||
use param::LoadParm;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::process::ExitCode;
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::sync::Arc;
|
||||
use tokio::net::UnixListener;
|
||||
use tokio::signal::unix::{signal, SignalKind};
|
||||
use tokio::sync::Mutex;
|
||||
|
||||
mod constants;
|
||||
use constants::DEFAULT_ODC_PROVIDER;
|
||||
mod cache;
|
||||
mod himmelblaud;
|
||||
use cache::{GroupCache, PrivateCache, UserCache};
|
||||
|
||||
#[tokio::main(flavor = "current_thread")]
|
||||
async fn main() -> ExitCode {
|
||||
let clap_args = Command::new("himmelblaud")
|
||||
.version(env!("CARGO_PKG_VERSION"))
|
||||
.about("Samba Himmelblau Authentication Daemon")
|
||||
.arg(
|
||||
Arg::new("debuglevel")
|
||||
.help("Set debug level")
|
||||
.short('d')
|
||||
.long("debuglevel")
|
||||
.value_parser(
|
||||
clap::value_parser!(u16).range(0..(MAX_DEBUG_LEVEL as i64)),
|
||||
)
|
||||
.action(ArgAction::Set),
|
||||
)
|
||||
.arg(
|
||||
Arg::new("debug-stdout")
|
||||
.help("Send debug output to standard output")
|
||||
.long("debug-stdout")
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
.arg(
|
||||
Arg::new("configfile")
|
||||
.help("Use alternative configuration file")
|
||||
.short('s')
|
||||
.long("configfile")
|
||||
.action(ArgAction::Set),
|
||||
)
|
||||
.get_matches();
|
||||
|
||||
let stop_now = Arc::new(AtomicBool::new(false));
|
||||
let terminate_now = Arc::clone(&stop_now);
|
||||
let quit_now = Arc::clone(&stop_now);
|
||||
let interrupt_now = Arc::clone(&stop_now);
|
||||
|
||||
async {
|
||||
// Set the command line debug level
|
||||
if let Some(debuglevel) = clap_args.get_one::<u16>("debuglevel") {
|
||||
debuglevel_set!(*debuglevel);
|
||||
}
|
||||
|
||||
// Initialize the LoadParm from the command line specified config file
|
||||
let lp = match LoadParm::new(
|
||||
clap_args
|
||||
.get_one::<String>("configfile")
|
||||
.map(|x| x.as_str()),
|
||||
) {
|
||||
Ok(lp) => lp,
|
||||
Err(e) => {
|
||||
eprintln!("Failed loading smb.conf: {:?}", e);
|
||||
return ExitCode::FAILURE;
|
||||
}
|
||||
};
|
||||
|
||||
// Check that the realm is configured. This the bare minimum for
|
||||
// himmelblaud, since a device join can happen at authentication time,
|
||||
// but we need to know the permitted enrollment domain.
|
||||
let realm = match lp.realm() {
|
||||
Ok(Some(realm)) => realm,
|
||||
_ => {
|
||||
eprintln!(
|
||||
"The realm MUST be set in the \
|
||||
smb.conf to start himmelblaud"
|
||||
);
|
||||
return ExitCode::FAILURE;
|
||||
}
|
||||
};
|
||||
|
||||
// Setup logging, either to the configured logfile, or to stdout, depending
|
||||
// on what is specified on the command line.
|
||||
match lp.logfile() {
|
||||
Ok(Some(logfile)) => debug_set_logfile(&logfile),
|
||||
_ => {
|
||||
eprintln!("Failed to determine logfile name");
|
||||
return ExitCode::FAILURE;
|
||||
}
|
||||
}
|
||||
match clap_args.get_flag("debug-stdout") {
|
||||
true => setup_logging(env!("CARGO_PKG_NAME"), DEBUG_STDOUT),
|
||||
false => setup_logging(env!("CARGO_PKG_NAME"), DEBUG_FILE),
|
||||
}
|
||||
|
||||
// Determine the unix socket path
|
||||
let sock_dir_str = match lp.winbindd_socket_directory() {
|
||||
Ok(Some(sock_dir)) => sock_dir,
|
||||
_ => return ExitCode::FAILURE,
|
||||
};
|
||||
let sock_dir = Path::new(&sock_dir_str);
|
||||
let mut sock_path = PathBuf::from(sock_dir);
|
||||
sock_path.push("hb_pipe");
|
||||
let sock_path = match sock_path.to_str() {
|
||||
Some(sock_path) => sock_path,
|
||||
None => return ExitCode::FAILURE,
|
||||
};
|
||||
|
||||
// Initialize the Himmelblau cache
|
||||
let private_cache_path = match lp.private_path("himmelblau.tdb") {
|
||||
Ok(Some(private_cache_path)) => private_cache_path,
|
||||
_ => {
|
||||
DBG_ERR!("Failed to determine private cache path");
|
||||
return ExitCode::FAILURE;
|
||||
}
|
||||
};
|
||||
let mut pcache = match PrivateCache::new(&private_cache_path) {
|
||||
Ok(cache) => cache,
|
||||
Err(e) => {
|
||||
DBG_ERR!(
|
||||
"Failed to open the himmelblau private cache: {:?}",
|
||||
e
|
||||
);
|
||||
return ExitCode::FAILURE;
|
||||
}
|
||||
};
|
||||
|
||||
let cache_dir = match lp.cache_directory() {
|
||||
Ok(Some(cache_dir)) => cache_dir,
|
||||
_ => {
|
||||
DBG_ERR!("Failed to determine cache directory");
|
||||
return ExitCode::FAILURE;
|
||||
}
|
||||
};
|
||||
|
||||
let user_cache_path = Path::new(&cache_dir)
|
||||
.join("himmelblau_users.tdb")
|
||||
.display()
|
||||
.to_string();
|
||||
let user_cache = match UserCache::new(&user_cache_path) {
|
||||
Ok(cache) => cache,
|
||||
Err(e) => {
|
||||
DBG_ERR!("Failed to open the himmelblau user cache: {:?}", e);
|
||||
return ExitCode::FAILURE;
|
||||
}
|
||||
};
|
||||
|
||||
let group_cache_path = Path::new(&cache_dir)
|
||||
.join("himmelblau_groups.tdb")
|
||||
.display()
|
||||
.to_string();
|
||||
let group_cache = match GroupCache::new(&group_cache_path) {
|
||||
Ok(cache) => cache,
|
||||
Err(e) => {
|
||||
DBG_ERR!("Failed to open the himmelblau group cache: {:?}", e);
|
||||
return ExitCode::FAILURE;
|
||||
}
|
||||
};
|
||||
|
||||
// Check for and create the hsm pin if required.
|
||||
let auth_value = match pcache.hsm_pin_fetch_or_create() {
|
||||
Ok(auth_value) => auth_value,
|
||||
Err(e) => {
|
||||
DBG_ERR!("{:?}", e);
|
||||
return ExitCode::FAILURE;
|
||||
}
|
||||
};
|
||||
|
||||
// Setup the HSM and its machine key
|
||||
let mut hsm: BoxedDynTpm = BoxedDynTpm::new(SoftTpm::new());
|
||||
|
||||
let loadable_machine_key = match pcache
|
||||
.loadable_machine_key_fetch_or_create(&mut hsm, &auth_value)
|
||||
{
|
||||
Ok(lmk) => lmk,
|
||||
Err(e) => {
|
||||
DBG_ERR!("{:?}", e);
|
||||
return ExitCode::FAILURE;
|
||||
}
|
||||
};
|
||||
|
||||
let res = hsm.machine_key_load(&auth_value, &loadable_machine_key);
|
||||
let machine_key = match res {
|
||||
Ok(machine_key) => machine_key,
|
||||
Err(e) => {
|
||||
DBG_ERR!("Unable to load machine root key: {:?}", e);
|
||||
DBG_INFO!("This can occur if you have changed your HSM pin.");
|
||||
DBG_INFO!(
|
||||
"To proceed, run `tdbtool erase {}`",
|
||||
private_cache_path
|
||||
);
|
||||
DBG_INFO!("The host will forget domain enrollments.");
|
||||
return ExitCode::FAILURE;
|
||||
}
|
||||
};
|
||||
|
||||
// Get the transport key for a joined domain
|
||||
let loadable_transport_key =
|
||||
pcache.loadable_transport_key_fetch(&realm);
|
||||
|
||||
// Get the certificate key for a joined domain
|
||||
let loadable_cert_key = pcache.loadable_cert_key_fetch(&realm);
|
||||
|
||||
// Contact the odc provider to get the authority host and tenant id
|
||||
let graph = match Graph::new(DEFAULT_ODC_PROVIDER, &realm).await {
|
||||
Ok(graph) => graph,
|
||||
Err(e) => {
|
||||
DBG_ERR!("Failed initializing the graph: {:?}", e);
|
||||
return ExitCode::FAILURE;
|
||||
}
|
||||
};
|
||||
let authority_host = graph.authority_host();
|
||||
let tenant_id = graph.tenant_id();
|
||||
let authority = format!("https://{}/{}", authority_host, tenant_id);
|
||||
|
||||
let client = match BrokerClientApplication::new(
|
||||
Some(&authority),
|
||||
loadable_transport_key,
|
||||
loadable_cert_key,
|
||||
) {
|
||||
Ok(client) => client,
|
||||
Err(e) => {
|
||||
DBG_ERR!("Failed initializing the broker: {:?}", e);
|
||||
return ExitCode::FAILURE;
|
||||
}
|
||||
};
|
||||
|
||||
let mut idmap = match Idmap::new() {
|
||||
Ok(idmap) => idmap,
|
||||
Err(e) => {
|
||||
DBG_ERR!("Failed initializing the idmapper: {:?}", e);
|
||||
return ExitCode::FAILURE;
|
||||
}
|
||||
};
|
||||
// Configure the idmap range
|
||||
let (low, high) = match lp.idmap_range(&realm) {
|
||||
Ok(res) => res,
|
||||
Err(e) => {
|
||||
DBG_ERR!("Failed fetching idmap range: {:?}", e);
|
||||
return ExitCode::FAILURE;
|
||||
}
|
||||
};
|
||||
if let Err(e) = idmap.add_gen_domain(&realm, &tenant_id, (low, high)) {
|
||||
DBG_ERR!("Failed adding the domain idmap range: {:?}", e);
|
||||
return ExitCode::FAILURE;
|
||||
}
|
||||
|
||||
let resolver = Arc::new(Mutex::new(himmelblaud::Resolver::new(
|
||||
&realm,
|
||||
&tenant_id,
|
||||
lp,
|
||||
idmap,
|
||||
graph,
|
||||
pcache,
|
||||
user_cache,
|
||||
group_cache,
|
||||
hsm,
|
||||
machine_key,
|
||||
client,
|
||||
)));
|
||||
|
||||
// Listen for incomming requests from PAM and NSS
|
||||
let listener = match UnixListener::bind(sock_path) {
|
||||
Ok(listener) => listener,
|
||||
Err(e) => {
|
||||
DBG_ERR!("Failed setting up the socket listener: {:?}", e);
|
||||
return ExitCode::FAILURE;
|
||||
}
|
||||
};
|
||||
|
||||
let server = tokio::spawn(async move {
|
||||
while !stop_now.load(Ordering::Relaxed) {
|
||||
let resolver_ref = resolver.clone();
|
||||
match listener.accept().await {
|
||||
Ok((socket, _addr)) => {
|
||||
tokio::spawn(async move {
|
||||
if let Err(e) = himmelblaud::handle_client(
|
||||
socket,
|
||||
resolver_ref.clone(),
|
||||
)
|
||||
.await
|
||||
{
|
||||
DBG_ERR!(
|
||||
"handle_client error occurred: {:?}",
|
||||
e
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
Err(e) => {
|
||||
DBG_ERR!("Error while handling connection: {:?}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
let terminate_task = tokio::spawn(async move {
|
||||
match signal(SignalKind::terminate()) {
|
||||
Ok(mut stream) => {
|
||||
stream.recv().await;
|
||||
terminate_now.store(true, Ordering::Relaxed);
|
||||
}
|
||||
Err(e) => {
|
||||
DBG_ERR!("Failed registering terminate signal: {}", e);
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
let quit_task = tokio::spawn(async move {
|
||||
match signal(SignalKind::quit()) {
|
||||
Ok(mut stream) => {
|
||||
stream.recv().await;
|
||||
quit_now.store(true, Ordering::Relaxed);
|
||||
}
|
||||
Err(e) => {
|
||||
DBG_ERR!("Failed registering quit signal: {}", e);
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
let interrupt_task = tokio::spawn(async move {
|
||||
match signal(SignalKind::interrupt()) {
|
||||
Ok(mut stream) => {
|
||||
stream.recv().await;
|
||||
interrupt_now.store(true, Ordering::Relaxed);
|
||||
}
|
||||
Err(e) => {
|
||||
DBG_ERR!("Failed registering interrupt signal: {}", e);
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
DBG_INFO!("Server started ...");
|
||||
|
||||
tokio::select! {
|
||||
_ = server => {
|
||||
DBG_DEBUG!("Main listener task is terminating");
|
||||
},
|
||||
_ = terminate_task => {
|
||||
DBG_DEBUG!("Received signal to terminate");
|
||||
},
|
||||
_ = quit_task => {
|
||||
DBG_DEBUG!("Received signal to quit");
|
||||
},
|
||||
_ = interrupt_task => {
|
||||
DBG_DEBUG!("Received signal to interrupt");
|
||||
}
|
||||
}
|
||||
|
||||
ExitCode::SUCCESS
|
||||
}
|
||||
.await
|
||||
}
|
||||
|
4
himmelblaud/wscript_build
Normal file
4
himmelblaud/wscript_build
Normal file
@ -0,0 +1,4 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
bld.SAMBA_RUST_BINARY('himmelblaud',
|
||||
source='src/main.rs param/src/lib.rs chelps/src/lib.rs dbg/src/lib.rs ntstatus_gen/src/lib.rs sock/src/lib.rs tdb/src/lib.rs version/src/lib.rs')
|
@ -155,6 +155,7 @@ bld.RECURSE('dfs_server')
|
||||
bld.RECURSE('file_server')
|
||||
bld.RECURSE('lib/krb5_wrap')
|
||||
bld.RECURSE('packaging')
|
||||
bld.RECURSE('himmelblaud')
|
||||
|
||||
bld.RECURSE('testsuite/headers')
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user