use crate::{
error::{Error, MajorFlags},
util::{Buf, BufRef},
oid::Oid,
};
use libgssapi_sys::{
gss_OID, gss_OID_desc, gss_canonicalize_name, gss_display_name, gss_duplicate_name,
gss_import_name, gss_name_struct, gss_name_t, gss_release_name, gss_export_name,
OM_uint32, GSS_S_COMPLETE,
};
#[cfg(feature = "localname")]
use libgssapi_sys::gss_localname;
#[cfg(feature = "localname")]
use crate::oid::NO_OID;
use std::{ptr, fmt};
pub struct Name(gss_name_t);
unsafe impl Send for Name {}
unsafe impl Sync for Name {}
impl Drop for Name {
fn drop(&mut self) {
if !self.0.is_null() {
let mut _minor = GSS_S_COMPLETE;
let _major = unsafe {
gss_release_name(
&mut _minor as *mut OM_uint32,
&mut self.0 as *mut gss_name_t,
)
};
}
}
}
impl fmt::Debug for Name {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
if let Ok(buf) = self.display_name() {
if let Ok(s) = std::str::from_utf8(&buf) {
write!(f, "{}", s)
} else {
write!(f, "<name can't be decoded>")
}
} else {
write!(f, "<name can't be displayed>")
}
}
}
impl fmt::Display for Name {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
fmt::Debug::fmt(self, f)
}
}
impl Name {
pub(crate) unsafe fn to_c(&self) -> gss_name_t {
self.0
}
#[allow(dead_code)]
pub(crate) unsafe fn from_c(ptr: gss_name_t) -> Self {
Name(ptr)
}
pub fn new(s: &[u8], kind: Option<&Oid>) -> Result<Self, Error> {
let mut buf = BufRef::from(s);
let mut minor = GSS_S_COMPLETE;
let mut name = ptr::null_mut::<gss_name_struct>();
let major = unsafe {
gss_import_name(
&mut minor as *mut OM_uint32,
buf.to_c(),
match kind {
None => ptr::null_mut::<gss_OID_desc>(),
Some(kind) => kind.to_c(),
},
&mut name as *mut gss_name_t,
)
};
if major == GSS_S_COMPLETE {
Ok(Name(name))
} else {
Err(Error {
major: MajorFlags::from_bits_retain(major),
minor
})
}
}
pub fn canonicalize(&self, mech: Option<&Oid>) -> Result<Self, Error> {
let mut out = ptr::null_mut::<gss_name_struct>();
let mut minor = GSS_S_COMPLETE;
let major = unsafe {
gss_canonicalize_name(
&mut minor as *mut OM_uint32,
self.to_c(),
match mech {
None => ptr::null_mut::<gss_OID_desc>(),
Some(id) => id.to_c()
},
&mut out as *mut gss_name_t,
)
};
if major == GSS_S_COMPLETE {
Ok(Name(out))
} else {
Err(Error {
major: MajorFlags::from_bits_retain(major),
minor
})
}
}
pub fn export(&self) -> Result<Buf, Error> {
let mut out = Buf::empty();
let mut minor = GSS_S_COMPLETE;
let major = unsafe {
gss_export_name(
&mut minor as *mut OM_uint32,
self.0,
out.to_c()
)
};
if major == GSS_S_COMPLETE {
Ok(out)
} else {
Err(Error {
major: MajorFlags::from_bits_retain(major),
minor
})
}
}
pub fn display_name(&self) -> Result<Buf, Error> {
let mut out = Buf::empty();
let mut minor = GSS_S_COMPLETE;
let mut oid = ptr::null_mut::<gss_OID_desc>();
let major = unsafe {
gss_display_name(
&mut minor as *mut OM_uint32,
self.to_c(),
out.to_c(),
&mut oid as *mut gss_OID,
)
};
if major == GSS_S_COMPLETE {
Ok(out)
} else {
Err(Error {
major: MajorFlags::from_bits_retain(major),
minor
})
}
}
#[cfg(feature = "localname")]
pub fn local_name(&self, mechs: Option<&Oid>) -> Result<Buf, Error> {
let mut out = Buf::empty();
let mut minor = GSS_S_COMPLETE;
let major = unsafe {
gss_localname(
&mut minor as *mut OM_uint32,
self.0,
mechs.map_or(NO_OID, |o| o.to_c()),
out.to_c()
)
};
if major == GSS_S_COMPLETE {
Ok(out)
} else {
Err(Error {
major: MajorFlags::from_bits_retain(major),
minor
})
}
}
pub fn duplicate(&self) -> Result<Self, Error> {
let mut copy = ptr::null_mut::<gss_name_struct>();
let mut minor = GSS_S_COMPLETE;
let major = unsafe {
gss_duplicate_name(
&mut minor as *mut OM_uint32,
self.to_c(),
&mut copy as *mut gss_name_t,
)
};
if major == GSS_S_COMPLETE {
Ok(Name(copy))
} else {
Err(Error {
major: MajorFlags::from_bits_retain(major),
minor
})
}
}
}