#[macro_use]
extern crate bitflags;
use anyhow::Result;
use bytes::{Buf, BytesMut};
use std::{ops::Deref, time::Duration};
#[cfg(windows)]
use ::windows::Win32::Security::Credentials::SecHandle;
pub trait K5Cred: Sized {
fn server_acquire(
_flags: AcceptFlags,
principal: Option<&str>,
) -> Result<Self>;
fn client_acquire(
_flags: InitiateFlags,
principal: Option<&str>,
) -> Result<Self>;
}
pub trait K5Ctx {
type Buffer: Deref<Target = [u8]> + Send + Sync;
type IOVBuffer: Buf + Send + Sync;
fn wrap(&mut self, encrypt: bool, msg: &[u8]) -> Result<Self::Buffer>;
fn wrap_iov(&mut self, encrypt: bool, msg: BytesMut) -> Result<Self::IOVBuffer>;
fn unwrap(&mut self, msg: &[u8]) -> Result<Self::Buffer>;
fn unwrap_iov(&mut self, len: usize, msg: &mut BytesMut) -> Result<BytesMut>;
fn ttl(&mut self) -> Result<Duration>;
}
pub trait K5ServerCtx: K5Ctx {
fn client(&mut self) -> Result<String>;
}
#[cfg(unix)]
mod unix;
#[cfg(unix)]
use crate::unix::{
ClientCtx as ClientCtxImpl, Cred as CredImpl,
PendingClientCtx as PendingClientCtxImpl, PendingServerCtx as PendingServerCtxImpl,
ServerCtx as ServerCtxImpl
};
#[cfg(windows)]
mod windows;
#[cfg(windows)]
use crate::windows::{
ClientCtx as ClientCtxImpl, PendingClientCtx as PendingClientCtxImpl,
PendingServerCtx as PendingServerCtxImpl, ServerCtx as ServerCtxImpl,
Cred as CredImpl
};
pub enum Step<C, T> {
Finished(C),
Continue(T),
}
#[derive(Debug)]
pub struct Cred(CredImpl);
impl K5Cred for Cred {
fn server_acquire(flags: AcceptFlags, principal: Option<&str>) -> Result<Cred> {
CredImpl::server_acquire(flags, principal).map(Cred)
}
fn client_acquire(flags: InitiateFlags, principal: Option<&str>) -> Result<Cred> {
CredImpl::client_acquire(flags, principal).map(Cred)
}
}
impl From<CredImpl> for Cred {
fn from(cred: CredImpl) -> Self {
Cred(cred)
}
}
#[cfg(unix)]
impl From<libgssapi::credential::Cred> for Cred {
fn from(value: libgssapi::credential::Cred) -> Self {
Cred(CredImpl::from(value))
}
}
#[cfg(unix)]
impl Into<libgssapi::credential::Cred> for Cred {
fn into(self) -> libgssapi::credential::Cred {
self.0.into()
}
}
#[cfg(windows)]
impl From<SecHandle> for Cred {
fn from(value: SecHandle) -> Self {
Cred(CredImpl::from(value))
}
}
#[cfg(windows)]
impl Into<SecHandle> for Cred {
fn into(self) -> SecHandle {
self.0.into()
}
}
pub struct PendingClientCtx(PendingClientCtxImpl);
impl PendingClientCtx {
pub fn step(
self,
token: &[u8],
) -> Result<
Step<
(ClientCtx, Option<impl Deref<Target = [u8]>>),
(PendingClientCtx, impl Deref<Target = [u8]>),
>,
> {
Ok(match self.0.step(token)? {
Step::Finished((ctx, tok)) => {
Step::Finished((ClientCtx(ctx), tok))
}
Step::Continue((ctx, tok)) => {
Step::Continue((PendingClientCtx(ctx), tok))
}
})
}
}
bitflags! {
pub struct InitiateFlags: u32 {
const NEGOTIATE_TOKEN = 0x1;
}
}
#[derive(Debug)]
pub struct ClientCtx(ClientCtxImpl);
impl ClientCtx {
pub fn new(
flags: InitiateFlags,
principal: Option<&str>,
target_principal: &str,
channel_bindings: Option<&[u8]>,
) -> Result<(PendingClientCtx, impl Deref<Target = [u8]>)> {
let (pending, token) =
ClientCtxImpl::new(flags, principal, target_principal, channel_bindings)?;
Ok((PendingClientCtx(pending), token))
}
pub fn new_with_cred(
cred: Cred,
target_principal: &str,
channel_bindings: Option<&[u8]>
) -> Result<(PendingClientCtx, impl Deref<Target=[u8]>)> {
let (pending, token) =
ClientCtxImpl::new_with_cred(cred.0, target_principal, channel_bindings)?;
Ok((PendingClientCtx(pending), token))
}
}
impl K5Ctx for ClientCtx {
type Buffer = <ClientCtxImpl as K5Ctx>::Buffer;
type IOVBuffer = <ClientCtxImpl as K5Ctx>::IOVBuffer;
fn wrap(&mut self, encrypt: bool, msg: &[u8]) -> Result<Self::Buffer> {
K5Ctx::wrap(&mut self.0, encrypt, msg)
}
fn wrap_iov(&mut self, encrypt: bool, msg: BytesMut) -> Result<Self::IOVBuffer> {
K5Ctx::wrap_iov(&mut self.0, encrypt, msg)
}
fn unwrap(&mut self, msg: &[u8]) -> Result<Self::Buffer> {
K5Ctx::unwrap(&mut self.0, msg)
}
fn unwrap_iov(&mut self, len: usize, msg: &mut BytesMut) -> Result<BytesMut> {
K5Ctx::unwrap_iov(&mut self.0, len, msg)
}
fn ttl(&mut self) -> Result<Duration> {
K5Ctx::ttl(&mut self.0)
}
}
bitflags! {
pub struct AcceptFlags: u32 {
const NEGOTIATE_TOKEN = 0x1;
}
}
pub struct PendingServerCtx(PendingServerCtxImpl);
impl PendingServerCtx {
pub fn step(
self,
token: &[u8],
) -> Result<
Step<
(ServerCtx, Option<impl Deref<Target = [u8]>>),
(PendingServerCtx, impl Deref<Target = [u8]>),
>,
> {
Ok(match self.0.step(token)? {
Step::Finished((ctx, tok)) => {
Step::Finished((ServerCtx(ctx), tok))
}
Step::Continue((ctx, tok)) => {
Step::Continue((PendingServerCtx(ctx), tok))
}
})
}
}
#[derive(Debug)]
pub struct ServerCtx(ServerCtxImpl);
impl ServerCtx {
pub fn new(flags: AcceptFlags, principal: Option<&str>) -> Result<PendingServerCtx> {
Ok(PendingServerCtx(ServerCtxImpl::new(flags, principal)?))
}
pub fn new_with_cred(cred: Cred) -> Result<PendingServerCtx> {
Ok(PendingServerCtx(ServerCtxImpl::new_with_cred(cred.0)?))
}
}
impl K5Ctx for ServerCtx {
type Buffer = <ServerCtxImpl as K5Ctx>::Buffer;
type IOVBuffer = <ServerCtxImpl as K5Ctx>::IOVBuffer;
fn wrap(&mut self, encrypt: bool, msg: &[u8]) -> Result<Self::Buffer> {
K5Ctx::wrap(&mut self.0, encrypt, msg)
}
fn wrap_iov(&mut self, encrypt: bool, msg: BytesMut) -> Result<Self::IOVBuffer> {
K5Ctx::wrap_iov(&mut self.0, encrypt, msg)
}
fn unwrap(&mut self, msg: &[u8]) -> Result<Self::Buffer> {
K5Ctx::unwrap(&mut self.0, msg)
}
fn unwrap_iov(&mut self, len: usize, msg: &mut BytesMut) -> Result<BytesMut> {
K5Ctx::unwrap_iov(&mut self.0, len, msg)
}
fn ttl(&mut self) -> Result<Duration> {
K5Ctx::ttl(&mut self.0)
}
}
impl K5ServerCtx for ServerCtx {
fn client(&mut self) -> Result<String> {
K5ServerCtx::client(&mut self.0)
}
}