use std::{
ffi,
ffi::{CStr, c_char},
};
use crate::TOKIO_RUNTIME;
#[derive(Debug, Default)]
#[repr(transparent)]
pub struct key(pub [u8; 32]);
macro_rules! impl_to_from {
($key:ty, $($keys:ty),+) => {
impl_to_from!($key);
impl_to_from!($($keys),+);
};
($key:ty$(,)?) => {
impl From<key> for $key {
fn from(value: key) -> Self {
value.0.into()
}
}
impl From<&key> for $key {
fn from(value: &key) -> Self {
value.0.into()
}
}
impl From<$key> for key {
fn from(value: $key) -> Self {
key(value.into())
}
}
impl From<&$key> for key {
fn from(value: &$key) -> Self {
key((*value).into())
}
}
};
}
impl_to_from!(
ts_keys::NodePublicKey,
ts_keys::NodePrivateKey,
ts_keys::DiscoPublicKey,
ts_keys::DiscoPrivateKey,
ts_keys::MachinePrivateKey,
ts_keys::MachinePublicKey,
ts_keys::NetworkLockPrivateKey,
ts_keys::NetworkLockPublicKey
);
#[derive(Debug, Default)]
#[repr(C)]
pub struct persisted_key_state {
pub node_private_key: key,
pub machine_private_key: key,
pub network_lock_private_key: key,
}
impl From<persisted_key_state> for ts_keys::PersistState {
fn from(value: persisted_key_state) -> Self {
(&value).into()
}
}
impl From<&persisted_key_state> for ts_keys::PersistState {
fn from(value: &persisted_key_state) -> Self {
ts_keys::PersistState {
machine_key: (&value.machine_private_key).into(),
network_lock_key: (&value.network_lock_private_key).into(),
node_key: (&value.node_private_key).into(),
}
}
}
impl From<ts_keys::PersistState> for persisted_key_state {
fn from(value: ts_keys::PersistState) -> Self {
Self {
machine_private_key: value.machine_key.into(),
network_lock_private_key: value.network_lock_key.into(),
node_private_key: value.node_key.into(),
}
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn ts_load_key_file(
path: *const c_char,
overwrite_if_invalid: bool,
key_state: &mut persisted_key_state,
) -> ffi::c_int {
let s = unsafe { CStr::from_ptr(path) };
let s = match s.to_str() {
Ok(s) => s,
Err(e) => {
tracing::error!(error = %e, "converting path to str");
return -1;
}
};
let mode = if overwrite_if_invalid {
tailscale::config::BadFormatBehavior::Overwrite
} else {
tailscale::config::BadFormatBehavior::Error
};
let _span = tracing::trace_span!("ts_load_key_file", ?mode, path = %s).entered();
match TOKIO_RUNTIME.block_on(tailscale::config::load_key_file(s, mode)) {
Ok(state) => {
*key_state = state.into();
tracing::info!(?key_state, "loaded key state");
0
}
Err(e) => {
tracing::error!(error = %e, "loading key file");
-1
}
}
}