libgssapi/
util.rs

1use bytes;
2use libgssapi_sys::{
3    gss_buffer_desc, gss_buffer_desc_struct, gss_buffer_t, gss_release_buffer, OM_uint32,
4    GSS_S_COMPLETE,
5};
6#[cfg(feature = "s4u")]
7use libgssapi_sys::{gss_buffer_set_t, gss_release_buffer_set};
8use std::{
9    ffi,
10    marker::PhantomData,
11    ops::{Deref, DerefMut, Drop},
12    ptr, slice,
13};
14
15#[cfg(feature = "iov")]
16mod iov {
17    use super::*;
18    use libgssapi_sys::{
19        gss_iov_buffer_desc, GSS_IOV_BUFFER_FLAG_ALLOCATE, GSS_IOV_BUFFER_FLAG_ALLOCATED,
20        GSS_IOV_BUFFER_TYPE_DATA, GSS_IOV_BUFFER_TYPE_EMPTY, GSS_IOV_BUFFER_TYPE_HEADER,
21        GSS_IOV_BUFFER_TYPE_MECH_PARAMS, GSS_IOV_BUFFER_TYPE_PADDING,
22        GSS_IOV_BUFFER_TYPE_SIGN_ONLY, GSS_IOV_BUFFER_TYPE_STREAM,
23        GSS_IOV_BUFFER_TYPE_TRAILER,
24    };
25    const GSS_IOV_BUFFER_FLAG_MASK: u32 = 0xFFFF0000;
26    #[derive(Debug, Clone, Copy)]
27    pub enum GssIovType {
28        Empty,
29        Data,
30        Header,
31        MechParams,
32        Trailer,
33        Padding,
34        Stream,
35        SignOnly,
36    }
37
38    impl GssIovType {
39        fn to_c(&self) -> u32 {
40            match self {
41                GssIovType::Empty => GSS_IOV_BUFFER_TYPE_EMPTY,
42                GssIovType::Data => GSS_IOV_BUFFER_TYPE_DATA,
43                GssIovType::Header => GSS_IOV_BUFFER_TYPE_HEADER,
44                GssIovType::MechParams => GSS_IOV_BUFFER_TYPE_MECH_PARAMS,
45                GssIovType::Trailer => GSS_IOV_BUFFER_TYPE_TRAILER,
46                GssIovType::Padding => GSS_IOV_BUFFER_TYPE_PADDING,
47                GssIovType::Stream => GSS_IOV_BUFFER_TYPE_STREAM,
48                GssIovType::SignOnly => GSS_IOV_BUFFER_TYPE_SIGN_ONLY,
49            }
50        }
51
52        fn from_c(t: u32) -> Option<Self> {
53            match t & !GSS_IOV_BUFFER_FLAG_MASK {
54                GSS_IOV_BUFFER_TYPE_EMPTY => Some(GssIovType::Empty),
55                GSS_IOV_BUFFER_TYPE_DATA => Some(GssIovType::Data),
56                GSS_IOV_BUFFER_TYPE_HEADER => Some(GssIovType::Header),
57                GSS_IOV_BUFFER_TYPE_MECH_PARAMS => Some(GssIovType::MechParams),
58                GSS_IOV_BUFFER_TYPE_TRAILER => Some(GssIovType::Trailer),
59                GSS_IOV_BUFFER_TYPE_PADDING => Some(GssIovType::Padding),
60                GSS_IOV_BUFFER_TYPE_STREAM => Some(GssIovType::Stream),
61                GSS_IOV_BUFFER_TYPE_SIGN_ONLY => Some(GssIovType::SignOnly),
62                _ => None,
63            }
64        }
65    }
66
67    /// this is a "fake" iov that exists only to ask gssapi how much space
68    /// it needs for the real one.
69    #[repr(transparent)]
70    #[derive(Debug)]
71    pub struct GssIovFake(gss_iov_buffer_desc);
72
73    impl GssIovFake {
74        /// Create a fake Iov for calls to wrap_iov_length
75        pub fn new(typ: GssIovType) -> GssIovFake {
76            let gss_iov = gss_iov_buffer_desc {
77                type_: typ.to_c(),
78                buffer: gss_buffer_desc_struct {
79                    length: 0,
80                    value: ptr::null_mut(),
81                },
82            };
83            GssIovFake(gss_iov)
84        }
85
86        pub fn len(&self) -> usize {
87            self.0.buffer.length as usize
88        }
89    }
90
91    #[repr(transparent)]
92    #[derive(Debug)]
93    pub struct GssIov<'a>(gss_iov_buffer_desc, PhantomData<&'a [u8]>);
94
95    unsafe impl<'a> Send for GssIov<'a> {}
96    unsafe impl<'a> Sync for GssIov<'a> {}
97
98    impl<'a> Drop for GssIov<'a> {
99        fn drop(&mut self) {
100            // check if the buffer was allocated by gssapi
101            if self.0.type_ & GSS_IOV_BUFFER_FLAG_MASK & GSS_IOV_BUFFER_FLAG_ALLOCATED > 0
102            {
103                let mut minor = GSS_S_COMPLETE;
104                let _major = unsafe {
105                    gss_release_buffer(
106                        &mut minor as *mut OM_uint32,
107                        &mut self.0.buffer as gss_buffer_t,
108                    )
109                };
110            }
111        }
112    }
113
114    impl<'a> Deref for GssIov<'a> {
115        type Target = [u8];
116
117        fn deref(&self) -> &Self::Target {
118            let buf = self.0.buffer;
119            if buf.value.is_null() && buf.length == 0 {
120                &[]
121            } else {
122                unsafe { slice::from_raw_parts(buf.value.cast(), buf.length as usize) }
123            }
124        }
125    }
126
127    impl<'a> DerefMut for GssIov<'a> {
128        fn deref_mut(&mut self) -> &mut Self::Target {
129            let buf = self.0.buffer;
130            unsafe {
131                if buf.value.is_null() && buf.length == 0 {
132                    &mut []
133                } else {
134                    slice::from_raw_parts_mut(buf.value.cast(), buf.length as usize)
135                }
136            }
137        }
138    }
139
140    impl<'a> GssIov<'a> {
141        /// Create a new real Iov for calls to wrap_iov.
142        pub fn new(typ: GssIovType, data: &'a mut [u8]) -> GssIov<'a> {
143            let gss_iov = gss_iov_buffer_desc {
144                type_: typ.to_c(),
145                buffer: gss_buffer_desc_struct {
146                    length: data.len(),
147                    value: data.as_mut_ptr().cast(),
148                },
149            };
150            GssIov(gss_iov, PhantomData)
151        }
152
153        /// Create a new real Iov that will have necessary storage
154        /// allocated as needed by gssapi.
155        pub fn new_alloc(typ: GssIovType) -> GssIov<'a> {
156            let gss_iov = gss_iov_buffer_desc {
157                type_: typ.to_c() | GSS_IOV_BUFFER_FLAG_ALLOCATE,
158                buffer: gss_buffer_desc_struct {
159                    length: 0,
160                    value: ptr::null_mut(),
161                },
162            };
163            GssIov(gss_iov, PhantomData)
164        }
165
166        pub fn typ(&self) -> Option<GssIovType> {
167            GssIovType::from_c(self.0.type_)
168        }
169
170        /// cast a real iov to a fake one. You need to do this for the
171        /// DATA buffer for the call to `wrap_iov_length`.
172        pub fn as_fake(self) -> GssIovFake {
173            GssIovFake(self.0)
174        }
175
176        /// In the special case where you unwrap a token using the
177        /// "stream" method, and end up with a pointer into it, you may
178        /// want to know the length of the header, so you can, for
179        /// example, split out just the data and send it somewhere without
180        /// copying it. This function will tell you that length. Don't use
181        /// it otherwise.
182        pub fn header_length(&self, data: &GssIov<'a>) -> Option<usize> {
183            match GssIovType::from_c(self.0.type_) {
184                Some(GssIovType::Stream) => {
185                    Some(data.0.buffer.value as usize - self.0.buffer.value as usize)
186                }
187                _ => None,
188            }
189        }
190
191        pub fn len(&self) -> usize {
192            self.0.buffer.length as usize
193        }
194    }
195}
196
197#[cfg(feature = "iov")]
198pub use iov::*;
199
200/* This type is dangerous, because we can't force C not to modify the
201 * contents of the pointer, and that could have serious
202 * consquences. We must use this type ONLY with gssapi functions that
203 * will not modify it. */
204#[repr(transparent)]
205#[derive(Debug)]
206pub(crate) struct BufRef<'a>(gss_buffer_desc_struct, PhantomData<&'a [u8]>);
207
208unsafe impl<'a> Send for BufRef<'a> {}
209unsafe impl<'a> Sync for BufRef<'a> {}
210
211impl<'a> Deref for BufRef<'a> {
212    type Target = [u8];
213
214    fn deref(&self) -> &Self::Target {
215        if self.0.value.is_null() && self.0.length == 0 {
216            &[]
217        } else {
218            unsafe { slice::from_raw_parts(self.0.value.cast(), self.0.length as usize) }
219        }
220    }
221}
222
223impl<'a> From<&'a [u8]> for BufRef<'a> {
224    fn from(s: &[u8]) -> Self {
225        let gss_buf = gss_buffer_desc_struct {
226            length: s.len(),
227            value: s.as_ptr() as *mut ffi::c_void,
228        };
229        BufRef(gss_buf, PhantomData)
230    }
231}
232
233impl<'a> BufRef<'a> {
234    pub(crate) unsafe fn to_c(&mut self) -> gss_buffer_t {
235        &mut self.0 as gss_buffer_t
236    }
237}
238
239/// This represents an owned buffer we got from gssapi, it will be
240/// deallocated via the library routine when it is dropped.
241#[repr(transparent)]
242#[allow(dead_code)]
243#[derive(Debug)]
244pub struct Buf(gss_buffer_desc);
245
246unsafe impl Send for Buf {}
247unsafe impl Sync for Buf {}
248
249impl Deref for Buf {
250    type Target = [u8];
251
252    fn deref(&self) -> &Self::Target {
253        unsafe {
254            if self.0.value.is_null() && self.0.length == 0 {
255                &[]
256            } else {
257                slice::from_raw_parts(self.0.value.cast(), self.0.length as usize)
258            }
259        }
260    }
261}
262
263impl DerefMut for Buf {
264    fn deref_mut(&mut self) -> &mut Self::Target {
265        unsafe {
266            if self.0.value.is_null() && self.0.length == 0 {
267                &mut []
268            } else {
269                slice::from_raw_parts_mut(self.0.value.cast(), self.0.length as usize)
270            }
271        }
272    }
273}
274
275impl Drop for Buf {
276    fn drop(&mut self) {
277        if !self.0.value.is_null() {
278            let mut minor = GSS_S_COMPLETE;
279            let _major = unsafe {
280                gss_release_buffer(
281                    &mut minor as *mut OM_uint32,
282                    &mut self.0 as gss_buffer_t,
283                )
284            };
285        }
286    }
287}
288
289impl Buf {
290    pub(crate) fn empty() -> Buf {
291        Buf(gss_buffer_desc {
292            length: 0,
293            value: ptr::null_mut(),
294        })
295    }
296
297    pub(crate) unsafe fn to_c(&mut self) -> gss_buffer_t {
298        &mut self.0 as gss_buffer_t
299    }
300
301    /// Wrap this bytes in a structure that implements `bytes::Buf`
302    pub fn to_bytes(self) -> GssBytes {
303        GssBytes { pos: 0, buf: self }
304    }
305}
306
307#[derive(Debug)]
308pub struct GssBytes {
309    pos: usize,
310    buf: Buf,
311}
312
313impl bytes::Buf for GssBytes {
314    fn remaining(&self) -> usize {
315        self.buf.0.length as usize - self.pos
316    }
317
318    fn chunk(&self) -> &[u8] {
319        &((*self.buf)[self.pos..])
320    }
321
322    fn advance(&mut self, cnt: usize) {
323        let rem = self.remaining();
324        if cnt > rem {
325            panic!(
326                "advancing {} would overrun the remaining buffer {}",
327                cnt, rem
328            );
329        } else {
330            self.pos += cnt;
331        }
332    }
333}
334
335impl GssBytes {
336    /// Consume the GssBytes and return the inner buffer
337    pub fn into_inner(self) -> Buf {
338        self.buf
339    }
340}
341
342#[cfg(feature = "s4u")]
343mod s4u {
344    use super::*;
345
346    /// This represents an owned buffer set we got from gssapi, it will be
347    /// deallocated via the library routine when it is dropped.
348    #[repr(transparent)]
349    #[allow(dead_code)]
350    #[derive(Debug)]
351    pub(crate) struct BufSet<'a>(gss_buffer_set_t, PhantomData<&'a [BufRef<'a>]>);
352
353    unsafe impl Send for BufSet<'_> {}
354    unsafe impl Sync for BufSet<'_> {}
355
356    impl<'a> Deref for BufSet<'a> {
357        type Target = [BufRef<'a>];
358
359        fn deref(&self) -> &'a Self::Target {
360            if self.0.is_null()
361                || unsafe { (*self.0).elements.is_null() && (*self.0).count == 0 }
362            {
363                &[]
364            } else {
365                unsafe {
366                    slice::from_raw_parts(
367                        (*self.0).elements.cast(),
368                        (*self.0).count as usize,
369                    )
370                }
371            }
372        }
373    }
374
375    impl<'a> DerefMut for BufSet<'a> {
376        fn deref_mut(&mut self) -> &'a mut Self::Target {
377            if self.0.is_null()
378                || unsafe { (*self.0).elements.is_null() && (*self.0).count == 0 }
379            {
380                &mut []
381            } else {
382                unsafe {
383                    slice::from_raw_parts_mut(
384                        (*self.0).elements.cast(),
385                        (*self.0).count as usize,
386                    )
387                }
388            }
389        }
390    }
391
392    impl Drop for BufSet<'_> {
393        fn drop(&mut self) {
394            if !self.0.is_null() {
395                let mut minor = GSS_S_COMPLETE;
396                let _major = unsafe {
397                    gss_release_buffer_set(&mut minor as *mut OM_uint32, &mut self.0)
398                };
399            }
400        }
401    }
402
403    impl BufSet<'_> {
404        pub(crate) fn empty() -> Self {
405            Self(ptr::null_mut(), PhantomData)
406        }
407
408        pub(crate) unsafe fn to_c(&mut self) -> &mut gss_buffer_set_t {
409            &mut self.0
410        }
411    }
412}
413
414#[cfg(feature = "s4u")]
415pub(crate) use s4u::*;