use bytes;
use libgssapi_sys::{
gss_buffer_desc, gss_buffer_desc_struct, gss_buffer_t, gss_release_buffer, OM_uint32,
GSS_S_COMPLETE,
};
#[cfg(feature = "s4u")]
use libgssapi_sys::{gss_buffer_set_t, gss_release_buffer_set};
use std::{
ffi,
marker::PhantomData,
ops::{Deref, DerefMut, Drop},
ptr, slice,
};
#[cfg(feature = "iov")]
mod iov {
use super::*;
use libgssapi_sys::{
gss_iov_buffer_desc, GSS_IOV_BUFFER_FLAG_ALLOCATE, GSS_IOV_BUFFER_FLAG_ALLOCATED,
GSS_IOV_BUFFER_TYPE_DATA, GSS_IOV_BUFFER_TYPE_EMPTY, GSS_IOV_BUFFER_TYPE_HEADER,
GSS_IOV_BUFFER_TYPE_MECH_PARAMS, GSS_IOV_BUFFER_TYPE_PADDING,
GSS_IOV_BUFFER_TYPE_SIGN_ONLY, GSS_IOV_BUFFER_TYPE_STREAM,
GSS_IOV_BUFFER_TYPE_TRAILER,
};
const GSS_IOV_BUFFER_FLAG_MASK: u32 = 0xFFFF0000;
#[derive(Debug, Clone, Copy)]
pub enum GssIovType {
Empty,
Data,
Header,
MechParams,
Trailer,
Padding,
Stream,
SignOnly,
}
impl GssIovType {
fn to_c(&self) -> u32 {
match self {
GssIovType::Empty => GSS_IOV_BUFFER_TYPE_EMPTY,
GssIovType::Data => GSS_IOV_BUFFER_TYPE_DATA,
GssIovType::Header => GSS_IOV_BUFFER_TYPE_HEADER,
GssIovType::MechParams => GSS_IOV_BUFFER_TYPE_MECH_PARAMS,
GssIovType::Trailer => GSS_IOV_BUFFER_TYPE_TRAILER,
GssIovType::Padding => GSS_IOV_BUFFER_TYPE_PADDING,
GssIovType::Stream => GSS_IOV_BUFFER_TYPE_STREAM,
GssIovType::SignOnly => GSS_IOV_BUFFER_TYPE_SIGN_ONLY,
}
}
fn from_c(t: u32) -> Option<Self> {
match t & !GSS_IOV_BUFFER_FLAG_MASK {
GSS_IOV_BUFFER_TYPE_EMPTY => Some(GssIovType::Empty),
GSS_IOV_BUFFER_TYPE_DATA => Some(GssIovType::Data),
GSS_IOV_BUFFER_TYPE_HEADER => Some(GssIovType::Header),
GSS_IOV_BUFFER_TYPE_MECH_PARAMS => Some(GssIovType::MechParams),
GSS_IOV_BUFFER_TYPE_TRAILER => Some(GssIovType::Trailer),
GSS_IOV_BUFFER_TYPE_PADDING => Some(GssIovType::Padding),
GSS_IOV_BUFFER_TYPE_STREAM => Some(GssIovType::Stream),
GSS_IOV_BUFFER_TYPE_SIGN_ONLY => Some(GssIovType::SignOnly),
_ => None,
}
}
}
#[repr(transparent)]
#[derive(Debug)]
pub struct GssIovFake(gss_iov_buffer_desc);
impl GssIovFake {
pub fn new(typ: GssIovType) -> GssIovFake {
let gss_iov = gss_iov_buffer_desc {
type_: typ.to_c(),
buffer: gss_buffer_desc_struct {
length: 0,
value: ptr::null_mut(),
},
};
GssIovFake(gss_iov)
}
pub fn len(&self) -> usize {
self.0.buffer.length as usize
}
}
#[repr(transparent)]
#[derive(Debug)]
pub struct GssIov<'a>(gss_iov_buffer_desc, PhantomData<&'a [u8]>);
unsafe impl<'a> Send for GssIov<'a> {}
unsafe impl<'a> Sync for GssIov<'a> {}
impl<'a> Drop for GssIov<'a> {
fn drop(&mut self) {
if self.0.type_ & GSS_IOV_BUFFER_FLAG_MASK & GSS_IOV_BUFFER_FLAG_ALLOCATED > 0
{
let mut minor = GSS_S_COMPLETE;
let _major = unsafe {
gss_release_buffer(
&mut minor as *mut OM_uint32,
&mut self.0.buffer as gss_buffer_t,
)
};
}
}
}
impl<'a> Deref for GssIov<'a> {
type Target = [u8];
fn deref(&self) -> &Self::Target {
let buf = self.0.buffer;
unsafe { slice::from_raw_parts(buf.value.cast(), buf.length as usize) }
}
}
impl<'a> DerefMut for GssIov<'a> {
fn deref_mut(&mut self) -> &mut Self::Target {
let buf = self.0.buffer;
unsafe { slice::from_raw_parts_mut(buf.value.cast(), buf.length as usize) }
}
}
impl<'a> GssIov<'a> {
pub fn new(typ: GssIovType, data: &'a mut [u8]) -> GssIov<'a> {
let gss_iov = gss_iov_buffer_desc {
type_: typ.to_c(),
buffer: gss_buffer_desc_struct {
length: data.len(),
value: data.as_mut_ptr().cast(),
},
};
GssIov(gss_iov, PhantomData)
}
pub fn new_alloc(typ: GssIovType) -> GssIov<'a> {
let gss_iov = gss_iov_buffer_desc {
type_: typ.to_c() | GSS_IOV_BUFFER_FLAG_ALLOCATE,
buffer: gss_buffer_desc_struct {
length: 0,
value: ptr::null_mut(),
},
};
GssIov(gss_iov, PhantomData)
}
pub fn typ(&self) -> Option<GssIovType> {
GssIovType::from_c(self.0.type_)
}
pub fn as_fake(self) -> GssIovFake {
GssIovFake(self.0)
}
pub fn header_length(&self, data: &GssIov<'a>) -> Option<usize> {
match GssIovType::from_c(self.0.type_) {
Some(GssIovType::Stream) => {
Some(data.0.buffer.value as usize - self.0.buffer.value as usize)
}
_ => None,
}
}
pub fn len(&self) -> usize {
self.0.buffer.length as usize
}
}
}
#[cfg(feature = "iov")]
pub use iov::*;
#[repr(transparent)]
#[derive(Debug)]
pub(crate) struct BufRef<'a>(gss_buffer_desc_struct, PhantomData<&'a [u8]>);
unsafe impl<'a> Send for BufRef<'a> {}
unsafe impl<'a> Sync for BufRef<'a> {}
impl<'a> Deref for BufRef<'a> {
type Target = [u8];
fn deref(&self) -> &Self::Target {
unsafe { slice::from_raw_parts(self.0.value.cast(), self.0.length as usize) }
}
}
impl<'a> From<&'a [u8]> for BufRef<'a> {
fn from(s: &[u8]) -> Self {
let gss_buf = gss_buffer_desc_struct {
length: s.len(),
value: s.as_ptr() as *mut ffi::c_void,
};
BufRef(gss_buf, PhantomData)
}
}
impl<'a> BufRef<'a> {
pub(crate) unsafe fn to_c(&mut self) -> gss_buffer_t {
&mut self.0 as gss_buffer_t
}
}
#[repr(transparent)]
#[allow(dead_code)]
#[derive(Debug)]
pub struct Buf(gss_buffer_desc);
unsafe impl Send for Buf {}
unsafe impl Sync for Buf {}
impl Deref for Buf {
type Target = [u8];
fn deref(&self) -> &Self::Target {
unsafe { slice::from_raw_parts(self.0.value.cast(), self.0.length as usize) }
}
}
impl DerefMut for Buf {
fn deref_mut(&mut self) -> &mut Self::Target {
unsafe { slice::from_raw_parts_mut(self.0.value.cast(), self.0.length as usize) }
}
}
impl Drop for Buf {
fn drop(&mut self) {
if !self.0.value.is_null() {
let mut minor = GSS_S_COMPLETE;
let _major = unsafe {
gss_release_buffer(
&mut minor as *mut OM_uint32,
&mut self.0 as gss_buffer_t,
)
};
}
}
}
impl Buf {
pub(crate) fn empty() -> Buf {
Buf(gss_buffer_desc {
length: 0,
value: ptr::null_mut(),
})
}
pub(crate) unsafe fn to_c(&mut self) -> gss_buffer_t {
&mut self.0 as gss_buffer_t
}
pub fn to_bytes(self) -> GssBytes {
GssBytes { pos: 0, buf: self }
}
}
#[derive(Debug)]
pub struct GssBytes {
pos: usize,
buf: Buf,
}
impl bytes::Buf for GssBytes {
fn remaining(&self) -> usize {
self.buf.0.length as usize - self.pos
}
fn chunk(&self) -> &[u8] {
&((*self.buf)[self.pos..])
}
fn advance(&mut self, cnt: usize) {
let rem = self.remaining();
if cnt > rem {
panic!(
"advancing {} would overrun the remaining buffer {}",
cnt, rem
);
} else {
self.pos += cnt;
}
}
}
impl GssBytes {
pub fn into_inner(self) -> Buf {
self.buf
}
}
#[cfg(feature = "s4u")]
mod s4u {
use super::*;
#[repr(transparent)]
#[allow(dead_code)]
#[derive(Debug)]
pub(crate) struct BufSet<'a>(gss_buffer_set_t, PhantomData<&'a [BufRef<'a>]>);
unsafe impl Send for BufSet<'_> {}
unsafe impl Sync for BufSet<'_> {}
impl<'a> Deref for BufSet<'a> {
type Target = [BufRef<'a>];
fn deref(&self) -> &'a Self::Target {
if self.0.is_null() {
&[]
} else {
unsafe { slice::from_raw_parts((*self.0).elements.cast(), (*self.0).count as usize) }
}
}
}
impl<'a> DerefMut for BufSet<'a> {
fn deref_mut(&mut self) -> &'a mut Self::Target {
if self.0.is_null() {
&mut []
} else {
unsafe { slice::from_raw_parts_mut((*self.0).elements.cast(), (*self.0).count as usize) }
}
}
}
impl Drop for BufSet<'_> {
fn drop(&mut self) {
if !self.0.is_null() {
let mut minor = GSS_S_COMPLETE;
let _major = unsafe {
gss_release_buffer_set(
&mut minor as *mut OM_uint32,
&mut self.0,
)
};
}
}
}
impl BufSet<'_> {
pub(crate) fn empty() -> Self {
Self(ptr::null_mut(), PhantomData)
}
pub(crate) unsafe fn to_c(&mut self) -> &mut gss_buffer_set_t {
&mut self.0
}
}
}
#[cfg(feature = "s4u")]
pub(crate) use s4u::*;