Repository: Kimahriman/hdfs-native (language: python)

Issue:
Dynamically load libgssapi_krb5 at runtime
To help with portability, we should dynamically link to libgssapi_krb5 using `libloading` instead of using a compile to link. This will make it simple to cross-compile for various targets, as well as include in downstream wheels without needing to build via QEMU to get the right architecture for packaging the dynamic libraries


Discussion / hints:

Fix patch:
diff --git a/.github/workflows/python-release.yml b/.github/workflows/python-release.yml
index c95d841..9df5ffb 100644
--- a/.github/workflows/python-release.yml
+++ b/.github/workflows/python-release.yml
@@ -28,19 +28,12 @@ jobs:
         target: [x86_64, aarch64]
     steps:
       - uses: actions/checkout@v4
-      - name: Setup QEMU
-        uses: docker/setup-qemu-action@v3
-        if: ${{ matrix.target }} != 'x86_64'
       - name: Build wheels
         uses: PyO3/maturin-action@v1
         with:
           target: ${{ matrix.target }}
-          args: --release --out dist --find-interpreter --manifest-path python/Cargo.toml --features kerberos
+          args: --release --out dist --find-interpreter --manifest-path python/Cargo.toml
           sccache: 'true'
-          container: quay.io/pypa/manylinux2014_${{ matrix.target }}:latest
-          docker-options: -e LD_LIBRARY_PATH=/opt/rh/llvm-toolset-7.0/root/usr/lib64 -e LLVM_CONFIG_PATH=/opt/rh/llvm-toolset-7.0/root/usr/bin/llvm-config
-          before-script-linux: |
-            yum install -y epel-release && yum install -y krb5-devel llvm-toolset-7.0-clang llvm-toolset-7.0-llvm-devel
       - name: Upload wheels
         uses: actions/upload-artifact@v4
         with:
@@ -54,18 +47,12 @@ jobs:
         target: [x86_64, aarch64]
     steps:
       - uses: actions/checkout@v4
-      - name: Install native libs
-        run:
-          brew install krb5
       - name: Build wheels
         uses: PyO3/maturin-action@v1
         with:
           target: ${{ matrix.target }}
-          args: --release --out dist --find-interpreter --manifest-path python/Cargo.toml --features kerberos
+          args: --release --out dist --find-interpreter --manifest-path python/Cargo.toml
           sccache: 'true'
-        env:
-          BINDGEN_EXTRA_CLANG_ARGS: "-I/usr/local/include"
-          LIBRARY_PATH: /usr/local/lib
       - name: Upload wheels
         uses: actions/upload-artifact@v4
         with:
diff --git a/Cargo.lock b/Cargo.lock
index 8d28bd3..bdaa39e 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -128,29 +128,6 @@ dependencies = [
  "which",
 ]
 
-[[package]]
-name = "bindgen"
-version = "0.69.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a00dc851838a2120612785d195287475a3ac45514741da670b735818822129a0"
-dependencies = [
- "bitflags 2.5.0",
- "cexpr",
- "clang-sys",
- "itertools 0.12.1",
- "lazy_static",
- "lazycell",
- "log",
- "prettyplease",
- "proc-macro2",
- "quote",
- "regex",
- "rustc-hash",
- "shlex",
- "syn 2.0.66",
- "which",
-]
-
 [[package]]
 name = "bitflags"
 version = "1.3.2"
@@ -529,7 +506,7 @@ version = "0.1.12"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "0f38e500596a428817fd4fd8a9a21da32f4edb3250e87886039670b12ea02f5d"
 dependencies = [
- "bindgen 0.64.0",
+ "bindgen",
  "cc",
  "lazy_static",
  "libc",
@@ -709,6 +686,7 @@ version = "0.9.4"
 dependencies = [
  "aes",
  "base64",
+ "bitflags 2.5.0",
  "bytes",
  "cbc",
  "chrono",
@@ -724,7 +702,7 @@ dependencies = [
  "hex",
  "hmac",
  "libc",
- "libgssapi",
+ "libloading",
  "log",
  "md-5",
  "num-traits",
@@ -929,28 +907,6 @@ version = "0.2.155"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c"
 
-[[package]]
-name = "libgssapi"
-version = "0.7.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c502363cc9845707a9b9fa938b732111fa7d7a4e518ebda8e46c5a1471192a15"
-dependencies = [
- "bitflags 2.5.0",
- "bytes",
- "lazy_static",
- "libgssapi-sys",
-]
-
-[[package]]
-name = "libgssapi-sys"
-version = "0.3.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b57d9a71c774ec53b1b9119dbbcc589b5209831f0ddc0ff4210640051f545372"
-dependencies = [
- "bindgen 0.69.4",
- "pkg-config",
-]
-
 [[package]]
 name = "libloading"
 version = "0.8.3"
@@ -1147,12 +1103,6 @@ version = "0.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
 
-[[package]]
-name = "pkg-config"
-version = "0.3.30"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec"
-
 [[package]]
 name = "plotters"
 version = "0.3.6"
diff --git a/README.md b/README.md
index 941a5ee..66fc9b1 100644
--- a/README.md
+++ b/README.md
@@ -22,13 +22,31 @@ Here is a list of currently supported and unsupported but possible future featur
     - RS schema only, no support for RS-Legacy or XOR
 
 ### Security Features
-- [x] Kerberos authentication (GSSAPI SASL support)
+- [x] Kerberos authentication (GSSAPI SASL support) (requires libgssapi_krb5, see below)
 - [x] Token authentication (DIGEST-MD5 SASL support)
 - [x] NameNode SASL connection
 - [x] DataNode SASL connection
 - [x] DataNode data transfer encryption
 - [ ] Encryption at rest (KMS support)
 
+### Kerberos Support
+Kerberos (SASL GSSAPI) mechanism is supported through a runtime dynamic link to `libgssapi_krb5`. This must be installed separately, but is likely already installed on your system. If not you can install it by:
+
+#### Debian-based systems
+```bash
+apt-get install libgssapi-krb5-2
+```
+
+#### RHEL-based systems
+```bash
+yum install krb5-libs
+```
+
+#### MacOS
+```bash
+brew install krb5
+```
+
 ## Supported HDFS Settings
 The client will attempt to read Hadoop configs `core-site.xml` and `hdfs-site.xml` in the directories `$HADOOP_CONF_DIR` or if that doesn't exist, `$HADOOP_HOME/etc/hadoop`. Currently the supported configs that are used are:
 - `fs.defaultFS` - Client::default() support
@@ -41,24 +59,10 @@ All other settings are generally assumed to be the defaults currently. For insta
 
 ## Building
 
-### Mac
-```
-brew install krb5
-# You might need these env vars on newer Macs
-export BINDGEN_EXTRA_CLANG_ARGS="-I/opt/homebrew/include"
-export LIBRARY_PATH=/opt/homebrew/lib
-cargo build --features kerberos
-```
-
-### Ubuntu
 ```
-apt-get install clang libkrb5-dev
-cargo build --features kerberos
+cargo build
 ```
 
-## Crate features
-- `kerberos` - enables kerberos GSSAPI authentication support. This uses the `libgssapi` crate and supports integrity as well as confidentiality
-
 ## Object store implementation
 An object_store implementation for HDFS is provided in the [hdfs-native-object-store](./crates/hdfs-native-object-store/) crate.
 
@@ -66,7 +70,7 @@ An object_store implementation for HDFS is provided in the [hdfs-native-object-s
 The tests are mostly integration tests that utilize a small Java application in `rust/mindifs/` that runs a custom `MiniDFSCluster`. To run the tests, you need to have Java, Maven, Hadoop binaries, and Kerberos tools available and on your path. Any Java version between 8 and 17 should work.
 
 ```bash
-cargo test -p hdfs-native --features kerberos,intergation-test
+cargo test -p hdfs-native --features intergation-test
 ```
 
 ### Python tests
diff --git a/python/Cargo.toml b/python/Cargo.toml
index 28d6261..0d111e1 100644
--- a/python/Cargo.toml
+++ b/python/Cargo.toml
@@ -32,6 +32,3 @@ log = { workspace = true }
 pyo3 = { version = "0.20", features = ["extension-module", "abi3", "abi3-py38"] }
 thiserror = { workspace = true }
 tokio = { workspace = true, features = ["rt-multi-thread"] }
-
-[features]
-kerberos = ["hdfs-native/kerberos"]
diff --git a/python/README.md b/python/README.md
index 1e3bf3b..3eeb14b 100644
--- a/python/README.md
+++ b/python/README.md
@@ -15,6 +15,24 @@ client = Client("hdfs://localhost:9000")
 status = client.get_file_info("/file.txt")
 ```
 
+## Kerberos support
+Kerberos (SASL GSSAPI) is supported through a runtime dynamic link to `libgssapi_krb5`. This must be installed separately, but is likely already installed on your system. If not you can install it by:
+
+#### Debian-based systems
+```bash
+apt-get install libgssapi-krb5-2
+```
+
+#### RHEL-based systems
+```bash
+yum install krb5-libs
+```
+
+#### MacOS
+```bash
+brew install krb5
+```
+
 ## Running tests
 The same requirements apply as the Rust tests, requiring Java, Maven, Hadoop, and Kerberos tools to be on your path. Then you can:
 
diff --git a/rust/Cargo.toml b/rust/Cargo.toml
index dc9bb10..eb116c1 100644
--- a/rust/Cargo.toml
+++ b/rust/Cargo.toml
@@ -13,6 +13,7 @@ license = "Apache-2.0"
 [dependencies]
 aes = "0.8"
 base64 = "0.21"
+bitflags = "2"
 bytes = { workspace = true }
 cbc = "0.1"
 chrono = "0.4"
@@ -27,7 +28,7 @@ g2p = "1"
 hex = "0.4"
 hmac = "0.12"
 libc = "0.2"
-libgssapi = { version = "0.7", default-features = false, optional = true }
+libloading = "0.8"
 log = { workspace = true }
 md-5 = "0.10"
 num-traits = "0.2"
@@ -57,8 +58,6 @@ tempfile = "3"
 which = "4"
 
 [features]
-kerberos = ["libgssapi"]
-
 generate-protobuf = ["prost-build", "protobuf-src"]
 integration-test = ["which"]
 benchmark = ["fs-hdfs3", "which"]
diff --git a/rust/c_src/gssapi_mit.h b/rust/c_src/gssapi_mit.h
new file mode 100644
index 0000000..6505c8a
--- /dev/null
+++ b/rust/c_src/gssapi_mit.h
@@ -0,0 +1,34 @@
+#include <gssapi/gssapi.h>
+#include <gssapi/gssapi_krb5.h>
+
+const OM_uint32 _GSS_C_INDEFINITE = GSS_C_INDEFINITE;
+const OM_uint32 _GSS_C_CALLING_ERROR_MASK = GSS_C_CALLING_ERROR_MASK;
+const OM_uint32 _GSS_C_ROUTINE_ERROR_MASK = GSS_C_ROUTINE_ERROR_MASK;
+const OM_uint32 _GSS_C_SUPPLEMENTARY_MASK = GSS_C_SUPPLEMENTARY_MASK;
+const OM_uint32 _GSS_S_CALL_INACCESSIBLE_READ = GSS_S_CALL_INACCESSIBLE_READ;
+const OM_uint32 _GSS_S_CALL_INACCESSIBLE_WRITE = GSS_S_CALL_INACCESSIBLE_WRITE;
+const OM_uint32 _GSS_S_CALL_BAD_STRUCTURE = GSS_S_CALL_BAD_STRUCTURE;
+const OM_uint32 _GSS_S_BAD_MECH = GSS_S_BAD_MECH;
+const OM_uint32 _GSS_S_BAD_NAME = GSS_S_BAD_NAME;
+const OM_uint32 _GSS_S_BAD_NAMETYPE = GSS_S_BAD_NAMETYPE;
+const OM_uint32 _GSS_S_BAD_BINDINGS = GSS_S_BAD_BINDINGS;
+const OM_uint32 _GSS_S_BAD_STATUS = GSS_S_BAD_STATUS;
+const OM_uint32 _GSS_S_BAD_SIG = GSS_S_BAD_SIG;
+const OM_uint32 _GSS_S_BAD_MIC = GSS_S_BAD_SIG;
+const OM_uint32 _GSS_S_NO_CRED = GSS_S_NO_CRED;
+const OM_uint32 _GSS_S_NO_CONTEXT = GSS_S_NO_CONTEXT;
+const OM_uint32 _GSS_S_DEFECTIVE_TOKEN = GSS_S_DEFECTIVE_TOKEN;
+const OM_uint32 _GSS_S_DEFECTIVE_CREDENTIAL = GSS_S_DEFECTIVE_CREDENTIAL;
+const OM_uint32 _GSS_S_CREDENTIALS_EXPIRED = GSS_S_CREDENTIALS_EXPIRED;
+const OM_uint32 _GSS_S_CONTEXT_EXPIRED = GSS_S_CONTEXT_EXPIRED;
+const OM_uint32 _GSS_S_FAILURE = GSS_S_FAILURE;
+const OM_uint32 _GSS_S_BAD_QOP = GSS_S_BAD_QOP;
+const OM_uint32 _GSS_S_UNAUTHORIZED = GSS_S_UNAUTHORIZED;
+const OM_uint32 _GSS_S_UNAVAILABLE = GSS_S_UNAVAILABLE;
+const OM_uint32 _GSS_S_DUPLICATE_ELEMENT = GSS_S_DUPLICATE_ELEMENT;
+const OM_uint32 _GSS_S_NAME_NOT_MN = GSS_S_NAME_NOT_MN;
+const OM_uint32 _GSS_S_CONTINUE_NEEDED = GSS_S_CONTINUE_NEEDED;
+const OM_uint32 _GSS_S_DUPLICATE_TOKEN = GSS_S_DUPLICATE_TOKEN;
+const OM_uint32 _GSS_S_OLD_TOKEN = GSS_S_OLD_TOKEN;
+const OM_uint32 _GSS_S_UNSEQ_TOKEN = GSS_S_UNSEQ_TOKEN;
+const OM_uint32 _GSS_S_GAP_TOKEN = GSS_S_GAP_TOKEN;
\ No newline at end of file
diff --git a/rust/generate_gssapi_bindings.sh b/rust/generate_gssapi_bindings.sh
new file mode 100755
index 0000000..797484c
--- /dev/null
+++ b/rust/generate_gssapi_bindings.sh
@@ -0,0 +1,10 @@
+#!/usr/bin/env bash
+# Need main branch until next release for var support in dynamic loading
+cargo install --git https://github.com/rust-lang/rust-bindgen --branch main bindgen-cli
+
+bindgen c_src/gssapi_mit.h \
+    --allowlist-type "OM_.+|gss_.+" \
+    --allowlist-var "_?GSS_.+|gss_.+" \
+    --allowlist-function "gss_.*" \
+    --dynamic-loading GSSAPI \
+    -o src/security/gssapi_bindings.rs
\ No newline at end of file
diff --git a/rust/src/error.rs b/rust/src/error.rs
index e2aff56..b301fa5 100644
--- a/rust/src/error.rs
+++ b/rust/src/error.rs
@@ -1,7 +1,5 @@
 use std::io;
 
-#[cfg(feature = "kerberos")]
-use libgssapi::error::Error as GssapiError;
 use prost::DecodeError;
 use thiserror::Error;
 
@@ -45,9 +43,8 @@ pub enum HdfsError {
     FatalRPCError(String, String),
     #[error("SASL error")]
     SASLError(String),
-    #[cfg(feature = "kerberos")]
     #[error("GSSAPI error")]
-    GSSAPIError(#[from] GssapiError),
+    GSSAPIError(crate::security::gssapi::GssMajorCodes, u32, String),
     #[error("No valid SASL mechanism found")]
     NoSASLMechanism,
 }
diff --git a/rust/src/lib.rs b/rust/src/lib.rs
index ab2f89f..49b2b38 100644
--- a/rust/src/lib.rs
+++ b/rust/src/lib.rs
@@ -22,9 +22,6 @@
 //! # Ok(())
 //! # }
 //! ```
-//!
-//! # Optional cargo package features
-//! - `kerberos` - include support for Kerberos authentication. Uses the libgssapi package. Supports all RPC authentication and encryption methods.
 
 pub mod client;
 pub(crate) mod common;
diff --git a/rust/src/security/gssapi.rs b/rust/src/security/gssapi.rs
index c6aeff8..075ab39 100644
--- a/rust/src/security/gssapi.rs
+++ b/rust/src/security/gssapi.rs
@@ -1,14 +1,369 @@
 use core::fmt;
-use libgssapi::context::{ClientCtx, CtxFlags, SecurityContext};
-use libgssapi::credential::{Cred, CredUsage};
-use libgssapi::name::Name;
-use libgssapi::oid::{OidSet, GSS_MECH_KRB5, GSS_NT_HOSTBASED_SERVICE};
+use libloading::library_filename;
+use log::warn;
+use once_cell::sync::Lazy;
+use std::marker::PhantomData;
+use std::ops::Deref;
+use std::os::raw::c_void;
+use std::slice::from_raw_parts;
+use std::{ptr, slice};
 
-use crate::{HdfsError, Result};
+use crate::HdfsError;
 
 use super::sasl::SaslSession;
 use super::user::User;
 
+mod bindings {
+    #![allow(warnings)]
+    include!("./gssapi_bindings.rs");
+
+    unsafe impl Send for GSSAPI {}
+    unsafe impl Sync for GSSAPI {}
+}
+
+// Converting error codes to a bitflag provides names in debug output
+bitflags::bitflags! {
+    #[derive(Clone, Copy, Debug)]
+    pub struct GssMajorCodes: u32 {
+        const GSS_S_CALL_INACCESSIBLE_READ = bindings::_GSS_S_CALL_INACCESSIBLE_READ;
+        const GSS_S_CALL_INACCESSIBLE_WRITE = bindings::_GSS_S_CALL_INACCESSIBLE_WRITE;
+        const GSS_S_CALL_BAD_STRUCTURE = bindings::_GSS_S_CALL_BAD_STRUCTURE;
+        const GSS_S_BAD_MECH = bindings::_GSS_S_BAD_MECH;
+        const GSS_S_BAD_NAME = bindings::_GSS_S_BAD_NAME;
+        const GSS_S_BAD_NAMETYPE = bindings::_GSS_S_BAD_NAMETYPE;
+        const GSS_S_BAD_BINDINGS = bindings::_GSS_S_BAD_BINDINGS;
+        const GSS_S_BAD_STATUS = bindings::_GSS_S_BAD_STATUS;
+        const GSS_S_BAD_SIG = bindings::_GSS_S_BAD_SIG;
+        const GSS_S_BAD_MIC = bindings::_GSS_S_BAD_MIC;
+        const GSS_S_NO_CRED = bindings::_GSS_S_NO_CRED;
+        const GSS_S_NO_CONTEXT = bindings::_GSS_S_NO_CONTEXT;
+        const GSS_S_DEFECTIVE_TOKEN = bindings::_GSS_S_DEFECTIVE_TOKEN;
+        const GSS_S_DEFECTIVE_CREDENTIAL = bindings::_GSS_S_DEFECTIVE_CREDENTIAL;
+        const GSS_S_CREDENTIALS_EXPIRED = bindings::_GSS_S_CREDENTIALS_EXPIRED;
+        const GSS_S_CONTEXT_EXPIRED = bindings::_GSS_S_CONTEXT_EXPIRED;
+        const GSS_S_FAILURE = bindings::_GSS_S_FAILURE;
+        const GSS_S_BAD_QOP = bindings::_GSS_S_BAD_QOP;
+        const GSS_S_UNAUTHORIZED = bindings::_GSS_S_UNAUTHORIZED;
+        const GSS_S_UNAVAILABLE = bindings::_GSS_S_UNAVAILABLE;
+        const GSS_S_DUPLICATE_ELEMENT = bindings::_GSS_S_DUPLICATE_ELEMENT;
+        const GSS_S_NAME_NOT_MN = bindings::_GSS_S_NAME_NOT_MN;
+        const GSS_S_CONTINUE_NEEDED = bindings::_GSS_S_CONTINUE_NEEDED;
+        const GSS_S_DUPLICATE_TOKEN = bindings::_GSS_S_DUPLICATE_TOKEN;
+        const GSS_S_OLD_TOKEN = bindings::_GSS_S_OLD_TOKEN;
+        const GSS_S_UNSEQ_TOKEN = bindings::_GSS_S_UNSEQ_TOKEN;
+        const GSS_S_GAP_TOKEN = bindings::_GSS_S_GAP_TOKEN;
+    }
+}
+
+static LIBGSSAPI: Lazy<Option<bindings::GSSAPI>> =
+    Lazy::new(
+        || match unsafe { bindings::GSSAPI::new(library_filename("gssapi_krb5")) } {
+            Ok(gssapi) => Some(gssapi),
+            Err(e) => {
+                #[cfg(target_os = "macos")]
+                let message = "Try installing via \"brew install krb5\"";
+                #[cfg(target_os = "linux")]
+                let message = "On Debian based systems, try \"apt-get install libgssapi-krb5-2\"\n
+                           On RHEL based systems, try \"yum install krb5-libs\"";
+                #[cfg(not(any(target_os = "macos", target_os = "linux")))]
+                let message = "Loading Kerberos libraries are not supported on this system";
+                log::warn!("Failed to libgssapi_krb5.\n{}.\n{:?}", message, e);
+                None
+            }
+        },
+    );
+
+fn libgssapi() -> crate::Result<&'static bindings::GSSAPI> {
+    LIBGSSAPI.as_ref().ok_or(HdfsError::OperationFailed(
+        "Failed to load libgssapi_krb".to_string(),
+    ))
+}
+
+#[repr(transparent)]
+#[derive(Debug)]
+struct GssBuf<'a>(bindings::gss_buffer_desc_struct, PhantomData<&'a [u8]>);
+
+impl<'a> GssBuf<'a> {
+    fn new() -> Self {
+        Self(
+            bindings::gss_buffer_desc_struct {
+                length: 0,
+                value: ptr::null_mut(),
+            },
+            PhantomData {},
+        )
+    }
+}
+
+impl<'a> Deref for GssBuf<'a> {
+    type Target = [u8];
+
+    fn deref(&self) -> &Self::Target {
+        if self.0.value.is_null() && self.0.length == 0 {
+            &[]
+        } else {
+            unsafe { slice::from_raw_parts(self.0.value.cast(), self.0.length) }
+        }
+    }
+}
+
+impl<'a> From<&'a [u8]> for GssBuf<'a> {
+    fn from(s: &[u8]) -> Self {
+        let gss_buf = bindings::gss_buffer_desc_struct {
+            length: s.len(),
+            value: s.as_ptr() as *mut c_void,
+        };
+        GssBuf(gss_buf, PhantomData)
+    }
+}
+
+impl<'a> From<&'a str> for GssBuf<'a> {
+    fn from(s: &str) -> Self {
+        let gss_buf = bindings::gss_buffer_desc_struct {
+            length: s.as_bytes().len(),
+            value: s.as_ptr() as *mut c_void,
+        };
+        GssBuf(gss_buf, PhantomData)
+    }
+}
+
+impl<'a> GssBuf<'a> {
+    pub(crate) unsafe fn as_ptr(&mut self) -> bindings::gss_buffer_t {
+        &mut self.0 as bindings::gss_buffer_t
+    }
+}
+
+struct GssName {
+    name: bindings::gss_name_t,
+}
+
+impl GssName {
+    fn new() -> Self {
+        Self {
+            name: ptr::null_mut(),
+        }
+    }
+
+    fn with_target(target_name: &str) -> crate::Result<Self> {
+        let mut minor = bindings::GSS_S_COMPLETE;
+        let mut name = ptr::null_mut::<bindings::gss_name_struct>();
+
+        let mut name_buf = GssBuf::from(target_name);
+
+        let major = unsafe {
+            libgssapi()?.gss_import_name(
+                &mut minor,
+                name_buf.as_ptr(),
+                *libgssapi()?.GSS_C_NT_HOSTBASED_SERVICE(),
+                &mut name as *mut bindings::gss_name_t,
+            )
+        };
+        check_gss_ok(major, minor)?;
+        Ok(Self { name })
+    }
+
+    fn display_name(&self) -> crate::Result<String> {
+        let mut minor = 0;
+        let mut display_name = bindings::gss_buffer_desc_struct {
+            length: 0,
+            value: ptr::null_mut(),
+        };
+        let major = unsafe {
+            libgssapi()?.gss_display_name(&mut minor, self.name, &mut display_name, ptr::null_mut())
+        };
+        check_gss_ok(major, minor)?;
+
+        unsafe {
+            if display_name.value.is_null() {
+                Ok(String::new())
+            } else {
+                let slice: &[u8] = from_raw_parts(display_name.value.cast(), display_name.length);
+                Ok(String::from_utf8_lossy(slice).to_string())
+            }
+        }
+    }
+
+    fn as_ptr(&mut self) -> *mut bindings::gss_name_t {
+        &mut self.name
+    }
+}
+
+impl Drop for GssName {
+    fn drop(&mut self) {
+        if !self.name.is_null() {
+            let mut minor = bindings::GSS_S_COMPLETE;
+            let major = unsafe {
+                libgssapi()
+                    .unwrap()
+                    .gss_release_name(&mut minor, &mut self.name)
+            };
+            if let Err(e) = check_gss_ok(major, minor) {
+                warn!("Failed to release GSSAPI name: {:?}", e);
+            }
+        }
+    }
+}
+
+struct GssClientCtx {
+    ctx: bindings::gss_ctx_id_t,
+    target: GssName,
+    flags: u32,
+}
+
+unsafe impl Send for GssClientCtx {}
+unsafe impl Sync for GssClientCtx {}
+
+impl GssClientCtx {
+    fn new(target: GssName) -> Self {
+        let flags = bindings::GSS_C_DELEG_FLAG
+            | bindings::GSS_C_MUTUAL_FLAG
+            | bindings::GSS_C_REPLAY_FLAG
+            | bindings::GSS_C_SEQUENCE_FLAG
+            | bindings::GSS_C_CONF_FLAG
+            | bindings::GSS_C_INTEG_FLAG
+            | bindings::GSS_C_ANON_FLAG
+            | bindings::GSS_C_PROT_READY_FLAG
+            | bindings::GSS_C_TRANS_FLAG
+            | bindings::GSS_C_DELEG_POLICY_FLAG;
+        Self {
+            ctx: ptr::null_mut(),
+            target,
+            flags,
+        }
+    }
+
+    fn step(&mut self, token: Option<&[u8]>) -> crate::Result<(Option<Vec<u8>>, bool)> {
+        let mut minor = 0;
+        let mut flags_out = 0;
+        let mut out = bindings::gss_buffer_desc_struct {
+            value: ptr::null_mut(),
+            length: 0,
+        };
+
+        let mut token_buf = token.map(GssBuf::from);
+        let token_ptr = token_buf
+            .as_mut()
+            .map(|t| unsafe { t.as_ptr() })
+            .unwrap_or(ptr::null_mut());
+
+        let major = unsafe {
+            libgssapi()?.gss_init_sec_context(
+                &mut minor,
+                ptr::null_mut(),
+                &mut self.ctx as *mut bindings::gss_ctx_id_t,
+                self.target.name,
+                *libgssapi()?.gss_mech_krb5() as bindings::gss_OID,
+                self.flags,
+                bindings::_GSS_C_INDEFINITE,
+                ptr::null_mut(),
+                token_ptr,
+                ptr::null_mut(),
+                &mut out,
+                &mut flags_out,
+                ptr::null_mut(),
+            )
+        };
+
+        let complete = if major == bindings::GSS_S_CONTINUE_NEEDED {
+            false
+        } else {
+            check_gss_ok(major, minor)?;
+            true
+        };
+
+        self.flags |= flags_out;
+
+        let out_token = unsafe {
+            if out.value.is_null() {
+                None
+            } else {
+                let slice: &[u8] = from_raw_parts(out.value.cast(), out.length);
+                Some(slice.to_vec())
+            }
+        };
+
+        Ok((out_token, complete))
+    }
+
+    fn wrap(&mut self, encrypt: bool, buf: &[u8]) -> crate::Result<Vec<u8>> {
+        let mut minor = 0;
+        let mut buf_in = GssBuf::from(buf);
+        let mut buf_out = GssBuf::new();
+        let major = unsafe {
+            libgssapi()?.gss_wrap(
+                &mut minor,
+                self.ctx,
+                if encrypt { 1 } else { 0 },
+                bindings::GSS_C_QOP_DEFAULT,
+                buf_in.as_ptr(),
+                ptr::null_mut(),
+                buf_out.as_ptr(),
+            )
+        };
+        check_gss_ok(major, minor)?;
+
+        Ok(buf_out.to_vec())
+    }
+
+    fn unwrap(&mut self, buf: &[u8]) -> crate::Result<Vec<u8>> {
+        let mut minor = 0;
+        let mut buf_in = GssBuf::from(buf);
+        let mut buf_out = GssBuf::new();
+        let major = unsafe {
+            libgssapi()?.gss_unwrap(
+                &mut minor,
+                self.ctx,
+                buf_in.as_ptr(),
+                buf_out.as_ptr(),
+                ptr::null_mut(),
+                ptr::null_mut(),
+            )
+        };
+        check_gss_ok(major, minor)?;
+
+        Ok(buf_out.to_vec())
+    }
+
+    fn source_name(&mut self) -> crate::Result<GssName> {
+        let mut minor = 0;
+        let mut name = GssName::new();
+        let major = unsafe {
+            libgssapi()?.gss_inquire_context(
+                &mut minor,
+                self.ctx,
+                name.as_ptr(),
+                ptr::null_mut(),
+                ptr::null_mut(),
+                ptr::null_mut(),
+                ptr::null_mut(),
+                ptr::null_mut(),
+                ptr::null_mut(),
+            )
+        };
+        check_gss_ok(major, minor)?;
+
+        Ok(name)
+    }
+}
+
+impl Drop for GssClientCtx {
+    fn drop(&mut self) {
+        if !self.ctx.is_null() {
+            let mut minor = bindings::GSS_S_COMPLETE;
+            let major = unsafe {
+                libgssapi().unwrap().gss_delete_sec_context(
+                    &mut minor,
+                    &mut self.ctx,
+                    ptr::null_mut(),
+                )
+            };
+            if let Err(e) = check_gss_ok(major, minor) {
+                warn!("Failed to release GSSAPI context: {:?}", e);
+            }
+        }
+    }
+}
+
 #[repr(u8)]
 enum SecurityLayer {
     None = 1,
@@ -16,16 +371,48 @@ enum SecurityLayer {
     Confidentiality = 4,
 }
 
+fn check_gss_ok(mut major: u32, mut minor: u32) -> crate::Result<()> {
+    major &= (bindings::_GSS_C_CALLING_ERROR_MASK << bindings::GSS_C_CALLING_ERROR_OFFSET)
+        | (bindings::_GSS_C_ROUTINE_ERROR_MASK << bindings::GSS_C_ROUTINE_ERROR_OFFSET);
+    if major == bindings::GSS_S_COMPLETE {
+        Ok(())
+    } else {
+        let mut context = 0;
+        let mut msg = GssBuf::new();
+        let ret = unsafe {
+            libgssapi()?.gss_display_status(
+                &mut minor,
+                major,
+                bindings::GSS_C_GSS_CODE as i32,
+                ptr::null_mut(),
+                &mut context,
+                msg.as_ptr(),
+            )
+        };
+
+        let error_message = if ret == bindings::GSS_S_COMPLETE {
+            String::from_utf8_lossy(msg.as_ref()).to_string()
+        } else {
+            String::new()
+        };
+
+        Err(HdfsError::GSSAPIError(
+            GssMajorCodes::from_bits_retain(major),
+            minor,
+            error_message,
+        ))
+    }
+}
+
 #[derive(Debug)]
 pub struct GssapiSession {
-    principal: String,
     state: GssapiState,
 }
 
 enum GssapiState {
-    Pending(ClientCtx),
-    Last(ClientCtx),
-    Completed(Option<(ClientCtx, bool)>),
+    Pending(GssClientCtx),
+    Last(GssClientCtx),
+    Completed((String, Option<(GssClientCtx, bool)>)),
     Errored,
 }
 
@@ -41,26 +428,12 @@ impl fmt::Debug for GssapiState {
 }
 
 impl GssapiSession {
-    pub(crate) fn new(service: &str, hostname: &str) -> Result<Self> {
+    pub(crate) fn new(service: &str, hostname: &str) -> crate::Result<Self> {
         let targ_name = format!("{}@{}", service, hostname);
 
-        let target = Name::new(targ_name.as_bytes(), Some(&GSS_NT_HOSTBASED_SERVICE))?;
-
-        let mut krb5 = OidSet::new()?;
-        krb5.add(&GSS_MECH_KRB5)?;
-
-        let cred = Cred::acquire(None, None, CredUsage::Initiate, Some(&krb5))?;
-        let principal = cred.name()?.to_string();
-
-        let state = GssapiState::Pending(ClientCtx::new(
-            Some(cred),
-            target,
-            // Allow all flags. Setting them does not mean the final context will provide
-            // them, so this should not be an issue.
-            CtxFlags::all(),
-            Some(&GSS_MECH_KRB5),
-        ));
-        Ok(Self { state, principal })
+        let target = GssName::with_target(&targ_name)?;
+        let state = GssapiState::Pending(GssClientCtx::new(target));
+        Ok(Self { state })
     }
 }
 
@@ -69,12 +442,13 @@ impl SaslSession for GssapiSession {
         match core::mem::replace(&mut self.state, GssapiState::Errored) {
             GssapiState::Pending(mut ctx) => {
                 let mut ret = Vec::<u8>::new();
-                if let Some(token) = ctx.step(token, None)? {
+                let (out_token, complete) = ctx.step(token)?;
+                if let Some(token) = out_token {
                     if !token.is_empty() {
                         ret = token.to_vec();
                     }
                 }
-                if !ctx.is_complete() {
+                if !complete {
                     self.state = GssapiState::Pending(ctx);
                     return Ok((ret, false));
                 }
@@ -111,8 +485,10 @@ impl SaslSession for GssapiSession {
                     ));
                 };
 
+                let principal = ctx.source_name()?.display_name()?;
+
                 let wrapped = ctx.wrap(false, &response)?;
-                self.state = GssapiState::Completed(wrap.map(|e| (ctx, e)));
+                self.state = GssapiState::Completed((principal, wrap.map(|e| (ctx, e))));
                 Ok((wrapped.to_vec(), true))
             }
             GssapiState::Completed(..) | GssapiState::Errored => {
@@ -122,14 +498,14 @@ impl SaslSession for GssapiSession {
     }
 
     fn has_security_layer(&self) -> bool {
-        matches!(self.state, GssapiState::Completed(Some(_)))
+        matches!(self.state, GssapiState::Completed((_, Some(_))))
     }
 
     fn encode(&mut self, buf: &[u8]) -> crate::Result<Vec<u8>> {
         match self.state {
-            GssapiState::Completed(Some((ref mut ctx, encrypt))) => {
-                let unwrapped = ctx.wrap(encrypt, buf)?;
-                Ok(unwrapped.to_vec())
+            GssapiState::Completed((_, Some((ref mut ctx, encrypt)))) => {
+                let wrapped = ctx.wrap(encrypt, buf)?;
+                Ok(wrapped.to_vec())
             }
             _ => Err(HdfsError::SASLError(
                 "SASL session doesn't have security layer".to_string(),
@@ -139,7 +515,7 @@ impl SaslSession for GssapiSession {
 
     fn decode(&mut self, buf: &[u8]) -> crate::Result<Vec<u8>> {
         match self.state {
-            GssapiState::Completed(Some((ref mut ctx, _))) => {
+            GssapiState::Completed((_, Some((ref mut ctx, _)))) => {
                 let unwrapped = ctx.unwrap(buf)?;
                 Ok(unwrapped.to_vec())
             }
@@ -150,6 +526,13 @@ impl SaslSession for GssapiSession {
     }
 
     fn get_user_info(&self) -> crate::Result<super::user::UserInfo> {
-        Ok(User::get_user_info_from_principal(&self.principal))
+        match &self.state {
+            GssapiState::Completed((principal, _)) => {
+                Ok(User::get_user_info_from_principal(principal))
+            }
+            _ => Err(HdfsError::SASLError(
+                "SASL session doesn't have security layer".to_string(),
+            )),
+        }
     }
 }
diff --git a/rust/src/security/gssapi_bindings.rs b/rust/src/security/gssapi_bindings.rs
new file mode 100644
index 0000000..7fa246e
--- /dev/null
+++ b/rust/src/security/gssapi_bindings.rs
@@ -0,0 +1,1649 @@
+/* automatically generated by rust-bindgen 0.69.4 */
+
+pub const GSS_C_DELEG_FLAG: u32 = 1;
+pub const GSS_C_MUTUAL_FLAG: u32 = 2;
+pub const GSS_C_REPLAY_FLAG: u32 = 4;
+pub const GSS_C_SEQUENCE_FLAG: u32 = 8;
+pub const GSS_C_CONF_FLAG: u32 = 16;
+pub const GSS_C_INTEG_FLAG: u32 = 32;
+pub const GSS_C_ANON_FLAG: u32 = 64;
+pub const GSS_C_PROT_READY_FLAG: u32 = 128;
+pub const GSS_C_TRANS_FLAG: u32 = 256;
+pub const GSS_C_DELEG_POLICY_FLAG: u32 = 32768;
+pub const GSS_C_NO_UI_FLAG: u32 = 2147483648;
+pub const GSS_C_BOTH: u32 = 0;
+pub const GSS_C_INITIATE: u32 = 1;
+pub const GSS_C_ACCEPT: u32 = 2;
+pub const GSS_C_OPTION_MASK: u32 = 65535;
+pub const GSS_C_CRED_NO_UI: u32 = 65536;
+pub const GSS_C_GSS_CODE: u32 = 1;
+pub const GSS_C_MECH_CODE: u32 = 2;
+pub const GSS_C_AF_UNSPEC: u32 = 0;
+pub const GSS_C_AF_LOCAL: u32 = 1;
+pub const GSS_C_AF_INET: u32 = 2;
+pub const GSS_C_AF_IMPLINK: u32 = 3;
+pub const GSS_C_AF_PUP: u32 = 4;
+pub const GSS_C_AF_CHAOS: u32 = 5;
+pub const GSS_C_AF_NS: u32 = 6;
+pub const GSS_C_AF_NBS: u32 = 7;
+pub const GSS_C_AF_ECMA: u32 = 8;
+pub const GSS_C_AF_DATAKIT: u32 = 9;
+pub const GSS_C_AF_CCITT: u32 = 10;
+pub const GSS_C_AF_SNA: u32 = 11;
+pub const GSS_C_AF_DECnet: u32 = 12;
+pub const GSS_C_AF_DLI: u32 = 13;
+pub const GSS_C_AF_LAT: u32 = 14;
+pub const GSS_C_AF_HYLINK: u32 = 15;
+pub const GSS_C_AF_APPLETALK: u32 = 16;
+pub const GSS_C_AF_BSC: u32 = 17;
+pub const GSS_C_AF_DSS: u32 = 18;
+pub const GSS_C_AF_OSI: u32 = 19;
+pub const GSS_C_AF_X25: u32 = 21;
+pub const GSS_C_AF_NULLADDR: u32 = 255;
+pub const GSS_C_QOP_DEFAULT: u32 = 0;
+pub const GSS_S_COMPLETE: u32 = 0;
+pub const GSS_C_CALLING_ERROR_OFFSET: u32 = 24;
+pub const GSS_C_ROUTINE_ERROR_OFFSET: u32 = 16;
+pub const GSS_C_SUPPLEMENTARY_OFFSET: u32 = 0;
+pub const GSS_S_CONTINUE_NEEDED: u32 = 1;
+pub const GSS_S_DUPLICATE_TOKEN: u32 = 2;
+pub const GSS_S_OLD_TOKEN: u32 = 4;
+pub const GSS_S_UNSEQ_TOKEN: u32 = 8;
+pub const GSS_S_GAP_TOKEN: u32 = 16;
+pub const GSS_KRB5_UI_ALLOW: u32 = 1;
+pub const GSS_KRB5_UI_DENY: u32 = 2;
+pub const GSS_KRB5_UI_PROBE: u32 = 3;
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct gss_name_struct {
+    _unused: [u8; 0],
+}
+pub type gss_name_t = *mut gss_name_struct;
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct gss_cred_id_struct {
+    _unused: [u8; 0],
+}
+pub type gss_cred_id_t = *mut gss_cred_id_struct;
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct gss_ctx_id_struct {
+    _unused: [u8; 0],
+}
+pub type gss_ctx_id_t = *mut gss_ctx_id_struct;
+pub type gss_uint32 = u32;
+pub type gss_int32 = i32;
+pub type OM_uint32 = gss_uint32;
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct gss_OID_desc_struct {
+    pub length: OM_uint32,
+    pub elements: *mut ::std::os::raw::c_void,
+}
+const _: () = {
+    ["Size of gss_OID_desc_struct"][::std::mem::size_of::<gss_OID_desc_struct>() - 16usize];
+    ["Alignment of gss_OID_desc_struct"][::std::mem::align_of::<gss_OID_desc_struct>() - 8usize];
+    ["Offset of field: gss_OID_desc_struct::length"]
+        [::std::mem::offset_of!(gss_OID_desc_struct, length) - 0usize];
+    ["Offset of field: gss_OID_desc_struct::elements"]
+        [::std::mem::offset_of!(gss_OID_desc_struct, elements) - 8usize];
+};
+pub type gss_OID_desc = gss_OID_desc_struct;
+pub type gss_OID = *mut gss_OID_desc_struct;
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct gss_OID_set_desc_struct {
+    pub count: usize,
+    pub elements: gss_OID,
+}
+const _: () = {
+    ["Size of gss_OID_set_desc_struct"][::std::mem::size_of::<gss_OID_set_desc_struct>() - 16usize];
+    ["Alignment of gss_OID_set_desc_struct"]
+        [::std::mem::align_of::<gss_OID_set_desc_struct>() - 8usize];
+    ["Offset of field: gss_OID_set_desc_struct::count"]
+        [::std::mem::offset_of!(gss_OID_set_desc_struct, count) - 0usize];
+    ["Offset of field: gss_OID_set_desc_struct::elements"]
+        [::std::mem::offset_of!(gss_OID_set_desc_struct, elements) - 8usize];
+};
+pub type gss_OID_set_desc = gss_OID_set_desc_struct;
+pub type gss_OID_set = *mut gss_OID_set_desc_struct;
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct gss_buffer_desc_struct {
+    pub length: usize,
+    pub value: *mut ::std::os::raw::c_void,
+}
+const _: () = {
+    ["Size of gss_buffer_desc_struct"][::std::mem::size_of::<gss_buffer_desc_struct>() - 16usize];
+    ["Alignment of gss_buffer_desc_struct"]
+        [::std::mem::align_of::<gss_buffer_desc_struct>() - 8usize];
+    ["Offset of field: gss_buffer_desc_struct::length"]
+        [::std::mem::offset_of!(gss_buffer_desc_struct, length) - 0usize];
+    ["Offset of field: gss_buffer_desc_struct::value"]
+        [::std::mem::offset_of!(gss_buffer_desc_struct, value) - 8usize];
+};
+pub type gss_buffer_desc = gss_buffer_desc_struct;
+pub type gss_buffer_t = *mut gss_buffer_desc_struct;
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct gss_channel_bindings_struct {
+    pub initiator_addrtype: OM_uint32,
+    pub initiator_address: gss_buffer_desc,
+    pub acceptor_addrtype: OM_uint32,
+    pub acceptor_address: gss_buffer_desc,
+    pub application_data: gss_buffer_desc,
+}
+const _: () = {
+    ["Size of gss_channel_bindings_struct"]
+        [::std::mem::size_of::<gss_channel_bindings_struct>() - 64usize];
+    ["Alignment of gss_channel_bindings_struct"]
+        [::std::mem::align_of::<gss_channel_bindings_struct>() - 8usize];
+    ["Offset of field: gss_channel_bindings_struct::initiator_addrtype"]
+        [::std::mem::offset_of!(gss_channel_bindings_struct, initiator_addrtype) - 0usize];
+    ["Offset of field: gss_channel_bindings_struct::initiator_address"]
+        [::std::mem::offset_of!(gss_channel_bindings_struct, initiator_address) - 8usize];
+    ["Offset of field: gss_channel_bindings_struct::acceptor_addrtype"]
+        [::std::mem::offset_of!(gss_channel_bindings_struct, acceptor_addrtype) - 24usize];
+    ["Offset of field: gss_channel_bindings_struct::acceptor_address"]
+        [::std::mem::offset_of!(gss_channel_bindings_struct, acceptor_address) - 32usize];
+    ["Offset of field: gss_channel_bindings_struct::application_data"]
+        [::std::mem::offset_of!(gss_channel_bindings_struct, application_data) - 48usize];
+};
+pub type gss_channel_bindings_t = *mut gss_channel_bindings_struct;
+pub type gss_qop_t = OM_uint32;
+pub type gss_cred_usage_t = ::std::os::raw::c_int;
+pub type krb5_int32 = ::std::os::raw::c_int;
+pub type krb5_enctype = krb5_int32;
+pub type krb5_flags = krb5_int32;
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct _krb5_ccache {
+    _unused: [u8; 0],
+}
+pub type krb5_ccache = *mut _krb5_ccache;
+pub type gss_uint64 = u64;
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct gss_krb5_lucid_key {
+    pub type_: OM_uint32,
+    pub length: OM_uint32,
+    pub data: *mut ::std::os::raw::c_void,
+}
+const _: () = {
+    ["Size of gss_krb5_lucid_key"][::std::mem::size_of::<gss_krb5_lucid_key>() - 16usize];
+    ["Alignment of gss_krb5_lucid_key"][::std::mem::align_of::<gss_krb5_lucid_key>() - 8usize];
+    ["Offset of field: gss_krb5_lucid_key::type_"]
+        [::std::mem::offset_of!(gss_krb5_lucid_key, type_) - 0usize];
+    ["Offset of field: gss_krb5_lucid_key::length"]
+        [::std::mem::offset_of!(gss_krb5_lucid_key, length) - 4usize];
+    ["Offset of field: gss_krb5_lucid_key::data"]
+        [::std::mem::offset_of!(gss_krb5_lucid_key, data) - 8usize];
+};
+pub type gss_krb5_lucid_key_t = gss_krb5_lucid_key;
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct gss_krb5_rfc1964_keydata {
+    pub sign_alg: OM_uint32,
+    pub seal_alg: OM_uint32,
+    pub ctx_key: gss_krb5_lucid_key_t,
+}
+const _: () = {
+    ["Size of gss_krb5_rfc1964_keydata"]
+        [::std::mem::size_of::<gss_krb5_rfc1964_keydata>() - 24usize];
+    ["Alignment of gss_krb5_rfc1964_keydata"]
+        [::std::mem::align_of::<gss_krb5_rfc1964_keydata>() - 8usize];
+    ["Offset of field: gss_krb5_rfc1964_keydata::sign_alg"]
+        [::std::mem::offset_of!(gss_krb5_rfc1964_keydata, sign_alg) - 0usize];
+    ["Offset of field: gss_krb5_rfc1964_keydata::seal_alg"]
+        [::std::mem::offset_of!(gss_krb5_rfc1964_keydata, seal_alg) - 4usize];
+    ["Offset of field: gss_krb5_rfc1964_keydata::ctx_key"]
+        [::std::mem::offset_of!(gss_krb5_rfc1964_keydata, ctx_key) - 8usize];
+};
+pub type gss_krb5_rfc1964_keydata_t = gss_krb5_rfc1964_keydata;
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct gss_krb5_cfx_keydata {
+    pub have_acceptor_subkey: OM_uint32,
+    pub ctx_key: gss_krb5_lucid_key_t,
+    pub acceptor_subkey: gss_krb5_lucid_key_t,
+}
+const _: () = {
+    ["Size of gss_krb5_cfx_keydata"][::std::mem::size_of::<gss_krb5_cfx_keydata>() - 40usize];
+    ["Alignment of gss_krb5_cfx_keydata"][::std::mem::align_of::<gss_krb5_cfx_keydata>() - 8usize];
+    ["Offset of field: gss_krb5_cfx_keydata::have_acceptor_subkey"]
+        [::std::mem::offset_of!(gss_krb5_cfx_keydata, have_acceptor_subkey) - 0usize];
+    ["Offset of field: gss_krb5_cfx_keydata::ctx_key"]
+        [::std::mem::offset_of!(gss_krb5_cfx_keydata, ctx_key) - 8usize];
+    ["Offset of field: gss_krb5_cfx_keydata::acceptor_subkey"]
+        [::std::mem::offset_of!(gss_krb5_cfx_keydata, acceptor_subkey) - 24usize];
+};
+pub type gss_krb5_cfx_keydata_t = gss_krb5_cfx_keydata;
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct gss_krb5_lucid_context_v1 {
+    pub version: OM_uint32,
+    pub initiate: OM_uint32,
+    pub endtime: OM_uint32,
+    pub send_seq: gss_uint64,
+    pub recv_seq: gss_uint64,
+    pub protocol: OM_uint32,
+    pub rfc1964_kd: gss_krb5_rfc1964_keydata_t,
+    pub cfx_kd: gss_krb5_cfx_keydata_t,
+}
+const _: () = {
+    ["Size of gss_krb5_lucid_context_v1"]
+        [::std::mem::size_of::<gss_krb5_lucid_context_v1>() - 104usize];
+    ["Alignment of gss_krb5_lucid_context_v1"]
+        [::std::mem::align_of::<gss_krb5_lucid_context_v1>() - 8usize];
+    ["Offset of field: gss_krb5_lucid_context_v1::version"]
+        [::std::mem::offset_of!(gss_krb5_lucid_context_v1, version) - 0usize];
+    ["Offset of field: gss_krb5_lucid_context_v1::initiate"]
+        [::std::mem::offset_of!(gss_krb5_lucid_context_v1, initiate) - 4usize];
+    ["Offset of field: gss_krb5_lucid_context_v1::endtime"]
+        [::std::mem::offset_of!(gss_krb5_lucid_context_v1, endtime) - 8usize];
+    ["Offset of field: gss_krb5_lucid_context_v1::send_seq"]
+        [::std::mem::offset_of!(gss_krb5_lucid_context_v1, send_seq) - 16usize];
+    ["Offset of field: gss_krb5_lucid_context_v1::recv_seq"]
+        [::std::mem::offset_of!(gss_krb5_lucid_context_v1, recv_seq) - 24usize];
+    ["Offset of field: gss_krb5_lucid_context_v1::protocol"]
+        [::std::mem::offset_of!(gss_krb5_lucid_context_v1, protocol) - 32usize];
+    ["Offset of field: gss_krb5_lucid_context_v1::rfc1964_kd"]
+        [::std::mem::offset_of!(gss_krb5_lucid_context_v1, rfc1964_kd) - 40usize];
+    ["Offset of field: gss_krb5_lucid_context_v1::cfx_kd"]
+        [::std::mem::offset_of!(gss_krb5_lucid_context_v1, cfx_kd) - 64usize];
+};
+pub type gss_krb5_lucid_context_v1_t = gss_krb5_lucid_context_v1;
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct gss_krb5_lucid_context_version {
+    pub version: OM_uint32,
+}
+const _: () = {
+    ["Size of gss_krb5_lucid_context_version"]
+        [::std::mem::size_of::<gss_krb5_lucid_context_version>() - 4usize];
+    ["Alignment of gss_krb5_lucid_context_version"]
+        [::std::mem::align_of::<gss_krb5_lucid_context_version>() - 4usize];
+    ["Offset of field: gss_krb5_lucid_context_version::version"]
+        [::std::mem::offset_of!(gss_krb5_lucid_context_version, version) - 0usize];
+};
+pub type gss_krb5_lucid_context_version_t = gss_krb5_lucid_context_version;
+pub const _GSS_C_INDEFINITE: OM_uint32 = 4294967295;
+pub const _GSS_C_CALLING_ERROR_MASK: OM_uint32 = 255;
+pub const _GSS_C_ROUTINE_ERROR_MASK: OM_uint32 = 255;
+pub const _GSS_C_SUPPLEMENTARY_MASK: OM_uint32 = 65535;
+pub const _GSS_S_CALL_INACCESSIBLE_READ: OM_uint32 = 16777216;
+pub const _GSS_S_CALL_INACCESSIBLE_WRITE: OM_uint32 = 33554432;
+pub const _GSS_S_CALL_BAD_STRUCTURE: OM_uint32 = 50331648;
+pub const _GSS_S_BAD_MECH: OM_uint32 = 65536;
+pub const _GSS_S_BAD_NAME: OM_uint32 = 131072;
+pub const _GSS_S_BAD_NAMETYPE: OM_uint32 = 196608;
+pub const _GSS_S_BAD_BINDINGS: OM_uint32 = 262144;
+pub const _GSS_S_BAD_STATUS: OM_uint32 = 327680;
+pub const _GSS_S_BAD_SIG: OM_uint32 = 393216;
+pub const _GSS_S_BAD_MIC: OM_uint32 = 393216;
+pub const _GSS_S_NO_CRED: OM_uint32 = 458752;
+pub const _GSS_S_NO_CONTEXT: OM_uint32 = 524288;
+pub const _GSS_S_DEFECTIVE_TOKEN: OM_uint32 = 589824;
+pub const _GSS_S_DEFECTIVE_CREDENTIAL: OM_uint32 = 655360;
+pub const _GSS_S_CREDENTIALS_EXPIRED: OM_uint32 = 720896;
+pub const _GSS_S_CONTEXT_EXPIRED: OM_uint32 = 786432;
+pub const _GSS_S_FAILURE: OM_uint32 = 851968;
+pub const _GSS_S_BAD_QOP: OM_uint32 = 917504;
+pub const _GSS_S_UNAUTHORIZED: OM_uint32 = 983040;
+pub const _GSS_S_UNAVAILABLE: OM_uint32 = 1048576;
+pub const _GSS_S_DUPLICATE_ELEMENT: OM_uint32 = 1114112;
+pub const _GSS_S_NAME_NOT_MN: OM_uint32 = 1179648;
+pub const _GSS_S_CONTINUE_NEEDED: OM_uint32 = 1;
+pub const _GSS_S_DUPLICATE_TOKEN: OM_uint32 = 2;
+pub const _GSS_S_OLD_TOKEN: OM_uint32 = 4;
+pub const _GSS_S_UNSEQ_TOKEN: OM_uint32 = 8;
+pub const _GSS_S_GAP_TOKEN: OM_uint32 = 16;
+pub struct GSSAPI {
+    __library: ::libloading::Library,
+    pub GSS_C_NT_USER_NAME: Result<*mut gss_OID, ::libloading::Error>,
+    pub GSS_C_NT_MACHINE_UID_NAME: Result<*mut gss_OID, ::libloading::Error>,
+    pub GSS_C_NT_STRING_UID_NAME: Result<*mut gss_OID, ::libloading::Error>,
+    pub GSS_C_NT_HOSTBASED_SERVICE_X: Result<*mut gss_OID, ::libloading::Error>,
+    pub GSS_C_NT_HOSTBASED_SERVICE: Result<*mut gss_OID, ::libloading::Error>,
+    pub GSS_C_NT_ANONYMOUS: Result<*mut gss_OID, ::libloading::Error>,
+    pub GSS_C_NT_EXPORT_NAME: Result<*mut gss_OID, ::libloading::Error>,
+    pub gss_acquire_cred: Result<
+        unsafe extern "C" fn(
+            arg1: *mut OM_uint32,
+            arg2: gss_name_t,
+            arg3: OM_uint32,
+            arg4: gss_OID_set,
+            arg5: gss_cred_usage_t,
+            arg6: *mut gss_cred_id_t,
+            arg7: *mut gss_OID_set,
+            arg8: *mut OM_uint32,
+        ) -> OM_uint32,
+        ::libloading::Error,
+    >,
+    pub gss_release_cred: Result<
+        unsafe extern "C" fn(arg1: *mut OM_uint32, arg2: *mut gss_cred_id_t) -> OM_uint32,
+        ::libloading::Error,
+    >,
+    pub gss_init_sec_context: Result<
+        unsafe extern "C" fn(
+            arg1: *mut OM_uint32,
+            arg2: gss_cred_id_t,
+            arg3: *mut gss_ctx_id_t,
+            arg4: gss_name_t,
+            arg5: gss_OID,
+            arg6: OM_uint32,
+            arg7: OM_uint32,
+            arg8: gss_channel_bindings_t,
+            arg9: gss_buffer_t,
+            arg10: *mut gss_OID,
+            arg11: gss_buffer_t,
+            arg12: *mut OM_uint32,
+            arg13: *mut OM_uint32,
+        ) -> OM_uint32,
+        ::libloading::Error,
+    >,
+    pub gss_accept_sec_context: Result<
+        unsafe extern "C" fn(
+            arg1: *mut OM_uint32,
+            arg2: *mut gss_ctx_id_t,
+            arg3: gss_cred_id_t,
+            arg4: gss_buffer_t,
+            arg5: gss_channel_bindings_t,
+            arg6: *mut gss_name_t,
+            arg7: *mut gss_OID,
+            arg8: gss_buffer_t,
+            arg9: *mut OM_uint32,
+            arg10: *mut OM_uint32,
+            arg11: *mut gss_cred_id_t,
+        ) -> OM_uint32,
+        ::libloading::Error,
+    >,
+    pub gss_process_context_token: Result<
+        unsafe extern "C" fn(
+            arg1: *mut OM_uint32,
+            arg2: gss_ctx_id_t,
+            arg3: gss_buffer_t,
+        ) -> OM_uint32,
+        ::libloading::Error,
+    >,
+    pub gss_delete_sec_context: Result<
+        unsafe extern "C" fn(
+            arg1: *mut OM_uint32,
+            arg2: *mut gss_ctx_id_t,
+            arg3: gss_buffer_t,
+        ) -> OM_uint32,
+        ::libloading::Error,
+    >,
+    pub gss_context_time: Result<
+        unsafe extern "C" fn(
+            arg1: *mut OM_uint32,
+            arg2: gss_ctx_id_t,
+            arg3: *mut OM_uint32,
+        ) -> OM_uint32,
+        ::libloading::Error,
+    >,
+    pub gss_get_mic: Result<
+        unsafe extern "C" fn(
+            arg1: *mut OM_uint32,
+            arg2: gss_ctx_id_t,
+            arg3: gss_qop_t,
+            arg4: gss_buffer_t,
+            arg5: gss_buffer_t,
+        ) -> OM_uint32,
+        ::libloading::Error,
+    >,
+    pub gss_verify_mic: Result<
+        unsafe extern "C" fn(
+            arg1: *mut OM_uint32,
+            arg2: gss_ctx_id_t,
+            arg3: gss_buffer_t,
+            arg4: gss_buffer_t,
+            arg5: *mut gss_qop_t,
+        ) -> OM_uint32,
+        ::libloading::Error,
+    >,
+    pub gss_wrap: Result<
+        unsafe extern "C" fn(
+            arg1: *mut OM_uint32,
+            arg2: gss_ctx_id_t,
+            arg3: ::std::os::raw::c_int,
+            arg4: gss_qop_t,
+            arg5: gss_buffer_t,
+            arg6: *mut ::std::os::raw::c_int,
+            arg7: gss_buffer_t,
+        ) -> OM_uint32,
+        ::libloading::Error,
+    >,
+    pub gss_unwrap: Result<
+        unsafe extern "C" fn(
+            arg1: *mut OM_uint32,
+            arg2: gss_ctx_id_t,
+            arg3: gss_buffer_t,
+            arg4: gss_buffer_t,
+            arg5: *mut ::std::os::raw::c_int,
+            arg6: *mut gss_qop_t,
+        ) -> OM_uint32,
+        ::libloading::Error,
+    >,
+    pub gss_display_status: Result<
+        unsafe extern "C" fn(
+            arg1: *mut OM_uint32,
+            arg2: OM_uint32,
+            arg3: ::std::os::raw::c_int,
+            arg4: gss_OID,
+            arg5: *mut OM_uint32,
+            arg6: gss_buffer_t,
+        ) -> OM_uint32,
+        ::libloading::Error,
+    >,
+    pub gss_indicate_mechs: Result<
+        unsafe extern "C" fn(arg1: *mut OM_uint32, arg2: *mut gss_OID_set) -> OM_uint32,
+        ::libloading::Error,
+    >,
+    pub gss_compare_name: Result<
+        unsafe extern "C" fn(
+            arg1: *mut OM_uint32,
+            arg2: gss_name_t,
+            arg3: gss_name_t,
+            arg4: *mut ::std::os::raw::c_int,
+        ) -> OM_uint32,
+        ::libloading::Error,
+    >,
+    pub gss_display_name: Result<
+        unsafe extern "C" fn(
+            arg1: *mut OM_uint32,
+            arg2: gss_name_t,
+            arg3: gss_buffer_t,
+            arg4: *mut gss_OID,
+        ) -> OM_uint32,
+        ::libloading::Error,
+    >,
+    pub gss_import_name: Result<
+        unsafe extern "C" fn(
+            arg1: *mut OM_uint32,
+            arg2: gss_buffer_t,
+            arg3: gss_OID,
+            arg4: *mut gss_name_t,
+        ) -> OM_uint32,
+        ::libloading::Error,
+    >,
+    pub gss_release_name: Result<
+        unsafe extern "C" fn(arg1: *mut OM_uint32, arg2: *mut gss_name_t) -> OM_uint32,
+        ::libloading::Error,
+    >,
+    pub gss_release_buffer: Result<
+        unsafe extern "C" fn(arg1: *mut OM_uint32, arg2: gss_buffer_t) -> OM_uint32,
+        ::libloading::Error,
+    >,
+    pub gss_release_oid_set: Result<
+        unsafe extern "C" fn(arg1: *mut OM_uint32, arg2: *mut gss_OID_set) -> OM_uint32,
+        ::libloading::Error,
+    >,
+    pub gss_inquire_cred: Result<
+        unsafe extern "C" fn(
+            arg1: *mut OM_uint32,
+            arg2: gss_cred_id_t,
+            arg3: *mut gss_name_t,
+            arg4: *mut OM_uint32,
+            arg5: *mut gss_cred_usage_t,
+            arg6: *mut gss_OID_set,
+        ) -> OM_uint32,
+        ::libloading::Error,
+    >,
+    pub gss_inquire_context: Result<
+        unsafe extern "C" fn(
+            arg1: *mut OM_uint32,
+            arg2: gss_ctx_id_t,
+            arg3: *mut gss_name_t,
+            arg4: *mut gss_name_t,
+            arg5: *mut OM_uint32,
+            arg6: *mut gss_OID,
+            arg7: *mut OM_uint32,
+            arg8: *mut ::std::os::raw::c_int,
+            arg9: *mut ::std::os::raw::c_int,
+        ) -> OM_uint32,
+        ::libloading::Error,
+    >,
+    pub gss_wrap_size_limit: Result<
+        unsafe extern "C" fn(
+            arg1: *mut OM_uint32,
+            arg2: gss_ctx_id_t,
+            arg3: ::std::os::raw::c_int,
+            arg4: gss_qop_t,
+            arg5: OM_uint32,
+            arg6: *mut OM_uint32,
+        ) -> OM_uint32,
+        ::libloading::Error,
+    >,
+    pub gss_export_name_object: Result<
+        unsafe extern "C" fn(
+            arg1: *mut OM_uint32,
+            arg2: gss_name_t,
+            arg3: gss_OID,
+            arg4: *mut *mut ::std::os::raw::c_void,
+        ) -> OM_uint32,
+        ::libloading::Error,
+    >,
+    pub gss_add_cred: Result<
+        unsafe extern "C" fn(
+            arg1: *mut OM_uint32,
+            arg2: gss_cred_id_t,
+            arg3: gss_name_t,
+            arg4: gss_OID,
+            arg5: gss_cred_usage_t,
+            arg6: OM_uint32,
+            arg7: OM_uint32,
+            arg8: *mut gss_cred_id_t,
+            arg9: *mut gss_OID_set,
+            arg10: *mut OM_uint32,
+            arg11: *mut OM_uint32,
+        ) -> OM_uint32,
+        ::libloading::Error,
+    >,
+    pub gss_inquire_cred_by_mech: Result<
+        unsafe extern "C" fn(
+            arg1: *mut OM_uint32,
+            arg2: gss_cred_id_t,
+            arg3: gss_OID,
+            arg4: *mut gss_name_t,
+            arg5: *mut OM_uint32,
+            arg6: *mut OM_uint32,
+            arg7: *mut gss_cred_usage_t,
+        ) -> OM_uint32,
+        ::libloading::Error,
+    >,
+    pub gss_export_sec_context: Result<
+        unsafe extern "C" fn(
+            arg1: *mut OM_uint32,
+            arg2: *mut gss_ctx_id_t,
+            arg3: gss_buffer_t,
+        ) -> OM_uint32,
+        ::libloading::Error,
+    >,
+    pub gss_import_sec_context: Result<
+        unsafe extern "C" fn(
+            arg1: *mut OM_uint32,
+            arg2: gss_buffer_t,
+            arg3: *mut gss_ctx_id_t,
+        ) -> OM_uint32,
+        ::libloading::Error,
+    >,
+    pub gss_release_oid: Result<
+        unsafe extern "C" fn(arg1: *mut OM_uint32, arg2: *mut gss_OID) -> OM_uint32,
+        ::libloading::Error,
+    >,
+    pub gss_create_empty_oid_set: Result<
+        unsafe extern "C" fn(arg1: *mut OM_uint32, arg2: *mut gss_OID_set) -> OM_uint32,
+        ::libloading::Error,
+    >,
+    pub gss_add_oid_set_member: Result<
+        unsafe extern "C" fn(
+            arg1: *mut OM_uint32,
+            arg2: gss_OID,
+            arg3: *mut gss_OID_set,
+        ) -> OM_uint32,
+        ::libloading::Error,
+    >,
+    pub gss_test_oid_set_member: Result<
+        unsafe extern "C" fn(
+            arg1: *mut OM_uint32,
+            arg2: gss_OID,
+            arg3: gss_OID_set,
+            arg4: *mut ::std::os::raw::c_int,
+        ) -> OM_uint32,
+        ::libloading::Error,
+    >,
+    pub gss_str_to_oid: Result<
+        unsafe extern "C" fn(
+            arg1: *mut OM_uint32,
+            arg2: gss_buffer_t,
+            arg3: *mut gss_OID,
+        ) -> OM_uint32,
+        ::libloading::Error,
+    >,
+    pub gss_oid_to_str: Result<
+        unsafe extern "C" fn(arg1: *mut OM_uint32, arg2: gss_OID, arg3: gss_buffer_t) -> OM_uint32,
+        ::libloading::Error,
+    >,
+    pub gss_inquire_names_for_mech: Result<
+        unsafe extern "C" fn(
+            arg1: *mut OM_uint32,
+            arg2: gss_OID,
+            arg3: *mut gss_OID_set,
+        ) -> OM_uint32,
+        ::libloading::Error,
+    >,
+    pub gss_inquire_mechs_for_name: Result<
+        unsafe extern "C" fn(
+            arg1: *mut OM_uint32,
+            arg2: gss_name_t,
+            arg3: *mut gss_OID_set,
+        ) -> OM_uint32,
+        ::libloading::Error,
+    >,
+    pub gss_sign: Result<
+        unsafe extern "C" fn(
+            arg1: *mut OM_uint32,
+            arg2: gss_ctx_id_t,
+            arg3: ::std::os::raw::c_int,
+            arg4: gss_buffer_t,
+            arg5: gss_buffer_t,
+        ) -> OM_uint32,
+        ::libloading::Error,
+    >,
+    pub gss_verify: Result<
+        unsafe extern "C" fn(
+            arg1: *mut OM_uint32,
+            arg2: gss_ctx_id_t,
+            arg3: gss_buffer_t,
+            arg4: gss_buffer_t,
+            arg5: *mut ::std::os::raw::c_int,
+        ) -> OM_uint32,
+        ::libloading::Error,
+    >,
+    pub gss_seal: Result<
+        unsafe extern "C" fn(
+            arg1: *mut OM_uint32,
+            arg2: gss_ctx_id_t,
+            arg3: ::std::os::raw::c_int,
+            arg4: ::std::os::raw::c_int,
+            arg5: gss_buffer_t,
+            arg6: *mut ::std::os::raw::c_int,
+            arg7: gss_buffer_t,
+        ) -> OM_uint32,
+        ::libloading::Error,
+    >,
+    pub gss_unseal: Result<
+        unsafe extern "C" fn(
+            arg1: *mut OM_uint32,
+            arg2: gss_ctx_id_t,
+            arg3: gss_buffer_t,
+            arg4: gss_buffer_t,
+            arg5: *mut ::std::os::raw::c_int,
+            arg6: *mut ::std::os::raw::c_int,
+        ) -> OM_uint32,
+        ::libloading::Error,
+    >,
+    pub gss_export_name: Result<
+        unsafe extern "C" fn(
+            arg1: *mut OM_uint32,
+            arg2: gss_name_t,
+            arg3: gss_buffer_t,
+        ) -> OM_uint32,
+        ::libloading::Error,
+    >,
+    pub gss_duplicate_name: Result<
+        unsafe extern "C" fn(
+            arg1: *mut OM_uint32,
+            arg2: gss_name_t,
+            arg3: *mut gss_name_t,
+        ) -> OM_uint32,
+        ::libloading::Error,
+    >,
+    pub gss_canonicalize_name: Result<
+        unsafe extern "C" fn(
+            arg1: *mut OM_uint32,
+            arg2: gss_name_t,
+            arg3: gss_OID,
+            arg4: *mut gss_name_t,
+        ) -> OM_uint32,
+        ::libloading::Error,
+    >,
+    pub GSS_KRB5_NT_PRINCIPAL_NAME: Result<*mut *const gss_OID_desc, ::libloading::Error>,
+    pub gss_mech_krb5: Result<*mut *const gss_OID_desc, ::libloading::Error>,
+    pub gss_mech_krb5_old: Result<*mut *const gss_OID_desc, ::libloading::Error>,
+    pub gss_mech_set_krb5: Result<*mut *const gss_OID_set_desc, ::libloading::Error>,
+    pub gss_mech_set_krb5_old: Result<*mut *const gss_OID_set_desc, ::libloading::Error>,
+    pub gss_mech_set_krb5_both: Result<*mut *const gss_OID_set_desc, ::libloading::Error>,
+    pub gss_nt_krb5_name: Result<*mut *const gss_OID_desc, ::libloading::Error>,
+    pub gss_nt_krb5_principal: Result<*mut *const gss_OID_desc, ::libloading::Error>,
+    pub gss_krb5_get_tkt_flags: Result<
+        unsafe extern "C" fn(
+            minor_status: *mut OM_uint32,
+            context_handle: gss_ctx_id_t,
+            ticket_flags: *mut krb5_flags,
+        ) -> OM_uint32,
+        ::libloading::Error,
+    >,
+    pub gss_krb5_copy_ccache: Result<
+        unsafe extern "C" fn(
+            minor_status: *mut OM_uint32,
+            cred_handle: gss_cred_id_t,
+            out_ccache: krb5_ccache,
+        ) -> OM_uint32,
+        ::libloading::Error,
+    >,
+    pub gss_krb5_ccache_name: Result<
+        unsafe extern "C" fn(
+            minor_status: *mut OM_uint32,
+            name: *const ::std::os::raw::c_char,
+            out_name: *mut *const ::std::os::raw::c_char,
+        ) -> OM_uint32,
+        ::libloading::Error,
+    >,
+    pub gss_krb5_set_allowable_enctypes: Result<
+        unsafe extern "C" fn(
+            minor_status: *mut OM_uint32,
+            cred: gss_cred_id_t,
+            num_ktypes: OM_uint32,
+            ktypes: *mut krb5_enctype,
+        ) -> OM_uint32,
+        ::libloading::Error,
+    >,
+    pub gss_krb5_export_lucid_sec_context: Result<
+        unsafe extern "C" fn(
+            minor_status: *mut OM_uint32,
+            context_handle: *mut gss_ctx_id_t,
+            version: OM_uint32,
+            kctx: *mut *mut ::std::os::raw::c_void,
+        ) -> OM_uint32,
+        ::libloading::Error,
+    >,
+    pub gss_krb5_free_lucid_sec_context: Result<
+        unsafe extern "C" fn(
+            minor_status: *mut OM_uint32,
+            kctx: *mut ::std::os::raw::c_void,
+        ) -> OM_uint32,
+        ::libloading::Error,
+    >,
+    pub gss_krb5_ui: Result<
+        unsafe extern "C" fn(arg1: *mut OM_uint32, arg2: OM_uint32) -> OM_uint32,
+        ::libloading::Error,
+    >,
+}
+impl GSSAPI {
+    pub unsafe fn new<P>(path: P) -> Result<Self, ::libloading::Error>
+    where
+        P: AsRef<::std::ffi::OsStr>,
+    {
+        let library = ::libloading::Library::new(path)?;
+        Self::from_library(library)
+    }
+    pub unsafe fn from_library<L>(library: L) -> Result<Self, ::libloading::Error>
+    where
+        L: Into<::libloading::Library>,
+    {
+        let __library = library.into();
+        let GSS_C_NT_USER_NAME = __library
+            .get::<*mut gss_OID>(b"GSS_C_NT_USER_NAME\0")
+            .map(|sym| *sym);
+        let GSS_C_NT_MACHINE_UID_NAME = __library
+            .get::<*mut gss_OID>(b"GSS_C_NT_MACHINE_UID_NAME\0")
+            .map(|sym| *sym);
+        let GSS_C_NT_STRING_UID_NAME = __library
+            .get::<*mut gss_OID>(b"GSS_C_NT_STRING_UID_NAME\0")
+            .map(|sym| *sym);
+        let GSS_C_NT_HOSTBASED_SERVICE_X = __library
+            .get::<*mut gss_OID>(b"GSS_C_NT_HOSTBASED_SERVICE_X\0")
+            .map(|sym| *sym);
+        let GSS_C_NT_HOSTBASED_SERVICE = __library
+            .get::<*mut gss_OID>(b"GSS_C_NT_HOSTBASED_SERVICE\0")
+            .map(|sym| *sym);
+        let GSS_C_NT_ANONYMOUS = __library
+            .get::<*mut gss_OID>(b"GSS_C_NT_ANONYMOUS\0")
+            .map(|sym| *sym);
+        let GSS_C_NT_EXPORT_NAME = __library
+            .get::<*mut gss_OID>(b"GSS_C_NT_EXPORT_NAME\0")
+            .map(|sym| *sym);
+        let gss_acquire_cred = __library.get(b"gss_acquire_cred\0").map(|sym| *sym);
+        let gss_release_cred = __library.get(b"gss_release_cred\0").map(|sym| *sym);
+        let gss_init_sec_context = __library.get(b"gss_init_sec_context\0").map(|sym| *sym);
+        let gss_accept_sec_context = __library.get(b"gss_accept_sec_context\0").map(|sym| *sym);
+        let gss_process_context_token = __library
+            .get(b"gss_process_context_token\0")
+            .map(|sym| *sym);
+        let gss_delete_sec_context = __library.get(b"gss_delete_sec_context\0").map(|sym| *sym);
+        let gss_context_time = __library.get(b"gss_context_time\0").map(|sym| *sym);
+        let gss_get_mic = __library.get(b"gss_get_mic\0").map(|sym| *sym);
+        let gss_verify_mic = __library.get(b"gss_verify_mic\0").map(|sym| *sym);
+        let gss_wrap = __library.get(b"gss_wrap\0").map(|sym| *sym);
+        let gss_unwrap = __library.get(b"gss_unwrap\0").map(|sym| *sym);
+        let gss_display_status = __library.get(b"gss_display_status\0").map(|sym| *sym);
+        let gss_indicate_mechs = __library.get(b"gss_indicate_mechs\0").map(|sym| *sym);
+        let gss_compare_name = __library.get(b"gss_compare_name\0").map(|sym| *sym);
+        let gss_display_name = __library.get(b"gss_display_name\0").map(|sym| *sym);
+        let gss_import_name = __library.get(b"gss_import_name\0").map(|sym| *sym);
+        let gss_release_name = __library.get(b"gss_release_name\0").map(|sym| *sym);
+        let gss_release_buffer = __library.get(b"gss_release_buffer\0").map(|sym| *sym);
+        let gss_release_oid_set = __library.get(b"gss_release_oid_set\0").map(|sym| *sym);
+        let gss_inquire_cred = __library.get(b"gss_inquire_cred\0").map(|sym| *sym);
+        let gss_inquire_context = __library.get(b"gss_inquire_context\0").map(|sym| *sym);
+        let gss_wrap_size_limit = __library.get(b"gss_wrap_size_limit\0").map(|sym| *sym);
+        let gss_export_name_object = __library.get(b"gss_export_name_object\0").map(|sym| *sym);
+        let gss_add_cred = __library.get(b"gss_add_cred\0").map(|sym| *sym);
+        let gss_inquire_cred_by_mech = __library.get(b"gss_inquire_cred_by_mech\0").map(|sym| *sym);
+        let gss_export_sec_context = __library.get(b"gss_export_sec_context\0").map(|sym| *sym);
+        let gss_import_sec_context = __library.get(b"gss_import_sec_context\0").map(|sym| *sym);
+        let gss_release_oid = __library.get(b"gss_release_oid\0").map(|sym| *sym);
+        let gss_create_empty_oid_set = __library.get(b"gss_create_empty_oid_set\0").map(|sym| *sym);
+        let gss_add_oid_set_member = __library.get(b"gss_add_oid_set_member\0").map(|sym| *sym);
+        let gss_test_oid_set_member = __library.get(b"gss_test_oid_set_member\0").map(|sym| *sym);
+        let gss_str_to_oid = __library.get(b"gss_str_to_oid\0").map(|sym| *sym);
+        let gss_oid_to_str = __library.get(b"gss_oid_to_str\0").map(|sym| *sym);
+        let gss_inquire_names_for_mech = __library
+            .get(b"gss_inquire_names_for_mech\0")
+            .map(|sym| *sym);
+        let gss_inquire_mechs_for_name = __library
+            .get(b"gss_inquire_mechs_for_name\0")
+            .map(|sym| *sym);
+        let gss_sign = __library.get(b"gss_sign\0").map(|sym| *sym);
+        let gss_verify = __library.get(b"gss_verify\0").map(|sym| *sym);
+        let gss_seal = __library.get(b"gss_seal\0").map(|sym| *sym);
+        let gss_unseal = __library.get(b"gss_unseal\0").map(|sym| *sym);
+        let gss_export_name = __library.get(b"gss_export_name\0").map(|sym| *sym);
+        let gss_duplicate_name = __library.get(b"gss_duplicate_name\0").map(|sym| *sym);
+        let gss_canonicalize_name = __library.get(b"gss_canonicalize_name\0").map(|sym| *sym);
+        let GSS_KRB5_NT_PRINCIPAL_NAME = __library
+            .get::<*mut *const gss_OID_desc>(b"GSS_KRB5_NT_PRINCIPAL_NAME\0")
+            .map(|sym| *sym);
+        let gss_mech_krb5 = __library
+            .get::<*mut *const gss_OID_desc>(b"gss_mech_krb5\0")
+            .map(|sym| *sym);
+        let gss_mech_krb5_old = __library
+            .get::<*mut *const gss_OID_desc>(b"gss_mech_krb5_old\0")
+            .map(|sym| *sym);
+        let gss_mech_set_krb5 = __library
+            .get::<*mut *const gss_OID_set_desc>(b"gss_mech_set_krb5\0")
+            .map(|sym| *sym);
+        let gss_mech_set_krb5_old = __library
+            .get::<*mut *const gss_OID_set_desc>(b"gss_mech_set_krb5_old\0")
+            .map(|sym| *sym);
+        let gss_mech_set_krb5_both = __library
+            .get::<*mut *const gss_OID_set_desc>(b"gss_mech_set_krb5_both\0")
+            .map(|sym| *sym);
+        let gss_nt_krb5_name = __library
+            .get::<*mut *const gss_OID_desc>(b"gss_nt_krb5_name\0")
+            .map(|sym| *sym);
+        let gss_nt_krb5_principal = __library
+            .get::<*mut *const gss_OID_desc>(b"gss_nt_krb5_principal\0")
+            .map(|sym| *sym);
+        let gss_krb5_get_tkt_flags = __library.get(b"gss_krb5_get_tkt_flags\0").map(|sym| *sym);
+        let gss_krb5_copy_ccache = __library.get(b"gss_krb5_copy_ccache\0").map(|sym| *sym);
+        let gss_krb5_ccache_name = __library.get(b"gss_krb5_ccache_name\0").map(|sym| *sym);
+        let gss_krb5_set_allowable_enctypes = __library
+            .get(b"gss_krb5_set_allowable_enctypes\0")
+            .map(|sym| *sym);
+        let gss_krb5_export_lucid_sec_context = __library
+            .get(b"gss_krb5_export_lucid_sec_context\0")
+            .map(|sym| *sym);
+        let gss_krb5_free_lucid_sec_context = __library
+            .get(b"gss_krb5_free_lucid_sec_context\0")
+            .map(|sym| *sym);
+        let gss_krb5_ui = __library.get(b"gss_krb5_ui\0").map(|sym| *sym);
+        Ok(GSSAPI {
+            __library,
+            GSS_C_NT_USER_NAME,
+            GSS_C_NT_MACHINE_UID_NAME,
+            GSS_C_NT_STRING_UID_NAME,
+            GSS_C_NT_HOSTBASED_SERVICE_X,
+            GSS_C_NT_HOSTBASED_SERVICE,
+            GSS_C_NT_ANONYMOUS,
+            GSS_C_NT_EXPORT_NAME,
+            gss_acquire_cred,
+            gss_release_cred,
+            gss_init_sec_context,
+            gss_accept_sec_context,
+            gss_process_context_token,
+            gss_delete_sec_context,
+            gss_context_time,
+            gss_get_mic,
+            gss_verify_mic,
+            gss_wrap,
+            gss_unwrap,
+            gss_display_status,
+            gss_indicate_mechs,
+            gss_compare_name,
+            gss_display_name,
+            gss_import_name,
+            gss_release_name,
+            gss_release_buffer,
+            gss_release_oid_set,
+            gss_inquire_cred,
+            gss_inquire_context,
+            gss_wrap_size_limit,
+            gss_export_name_object,
+            gss_add_cred,
+            gss_inquire_cred_by_mech,
+            gss_export_sec_context,
+            gss_import_sec_context,
+            gss_release_oid,
+            gss_create_empty_oid_set,
+            gss_add_oid_set_member,
+            gss_test_oid_set_member,
+            gss_str_to_oid,
+            gss_oid_to_str,
+            gss_inquire_names_for_mech,
+            gss_inquire_mechs_for_name,
+            gss_sign,
+            gss_verify,
+            gss_seal,
+            gss_unseal,
+            gss_export_name,
+            gss_duplicate_name,
+            gss_canonicalize_name,
+            GSS_KRB5_NT_PRINCIPAL_NAME,
+            gss_mech_krb5,
+            gss_mech_krb5_old,
+            gss_mech_set_krb5,
+            gss_mech_set_krb5_old,
+            gss_mech_set_krb5_both,
+            gss_nt_krb5_name,
+            gss_nt_krb5_principal,
+            gss_krb5_get_tkt_flags,
+            gss_krb5_copy_ccache,
+            gss_krb5_ccache_name,
+            gss_krb5_set_allowable_enctypes,
+            gss_krb5_export_lucid_sec_context,
+            gss_krb5_free_lucid_sec_context,
+            gss_krb5_ui,
+        })
+    }
+    pub unsafe fn GSS_C_NT_USER_NAME(&self) -> *mut gss_OID {
+        *self
+            .GSS_C_NT_USER_NAME
+            .as_ref()
+            .expect("Expected variable, got error.")
+    }
+    pub unsafe fn GSS_C_NT_MACHINE_UID_NAME(&self) -> *mut gss_OID {
+        *self
+            .GSS_C_NT_MACHINE_UID_NAME
+            .as_ref()
+            .expect("Expected variable, got error.")
+    }
+    pub unsafe fn GSS_C_NT_STRING_UID_NAME(&self) -> *mut gss_OID {
+        *self
+            .GSS_C_NT_STRING_UID_NAME
+            .as_ref()
+            .expect("Expected variable, got error.")
+    }
+    pub unsafe fn GSS_C_NT_HOSTBASED_SERVICE_X(&self) -> *mut gss_OID {
+        *self
+            .GSS_C_NT_HOSTBASED_SERVICE_X
+            .as_ref()
+            .expect("Expected variable, got error.")
+    }
+    pub unsafe fn GSS_C_NT_HOSTBASED_SERVICE(&self) -> *mut gss_OID {
+        *self
+            .GSS_C_NT_HOSTBASED_SERVICE
+            .as_ref()
+            .expect("Expected variable, got error.")
+    }
+    pub unsafe fn GSS_C_NT_ANONYMOUS(&self) -> *mut gss_OID {
+        *self
+            .GSS_C_NT_ANONYMOUS
+            .as_ref()
+            .expect("Expected variable, got error.")
+    }
+    pub unsafe fn GSS_C_NT_EXPORT_NAME(&self) -> *mut gss_OID {
+        *self
+            .GSS_C_NT_EXPORT_NAME
+            .as_ref()
+            .expect("Expected variable, got error.")
+    }
+    pub unsafe fn gss_acquire_cred(
+        &self,
+        arg1: *mut OM_uint32,
+        arg2: gss_name_t,
+        arg3: OM_uint32,
+        arg4: gss_OID_set,
+        arg5: gss_cred_usage_t,
+        arg6: *mut gss_cred_id_t,
+        arg7: *mut gss_OID_set,
+        arg8: *mut OM_uint32,
+    ) -> OM_uint32 {
+        (self
+            .gss_acquire_cred
+            .as_ref()
+            .expect("Expected function, got error."))(
+            arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8,
+        )
+    }
+    pub unsafe fn gss_release_cred(
+        &self,
+        arg1: *mut OM_uint32,
+        arg2: *mut gss_cred_id_t,
+    ) -> OM_uint32 {
+        (self
+            .gss_release_cred
+            .as_ref()
+            .expect("Expected function, got error."))(arg1, arg2)
+    }
+    pub unsafe fn gss_init_sec_context(
+        &self,
+        arg1: *mut OM_uint32,
+        arg2: gss_cred_id_t,
+        arg3: *mut gss_ctx_id_t,
+        arg4: gss_name_t,
+        arg5: gss_OID,
+        arg6: OM_uint32,
+        arg7: OM_uint32,
+        arg8: gss_channel_bindings_t,
+        arg9: gss_buffer_t,
+        arg10: *mut gss_OID,
+        arg11: gss_buffer_t,
+        arg12: *mut OM_uint32,
+        arg13: *mut OM_uint32,
+    ) -> OM_uint32 {
+        (self
+            .gss_init_sec_context
+            .as_ref()
+            .expect("Expected function, got error."))(
+            arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13,
+        )
+    }
+    pub unsafe fn gss_accept_sec_context(
+        &self,
+        arg1: *mut OM_uint32,
+        arg2: *mut gss_ctx_id_t,
+        arg3: gss_cred_id_t,
+        arg4: gss_buffer_t,
+        arg5: gss_channel_bindings_t,
+        arg6: *mut gss_name_t,
+        arg7: *mut gss_OID,
+        arg8: gss_buffer_t,
+        arg9: *mut OM_uint32,
+        arg10: *mut OM_uint32,
+        arg11: *mut gss_cred_id_t,
+    ) -> OM_uint32 {
+        (self
+            .gss_accept_sec_context
+            .as_ref()
+            .expect("Expected function, got error."))(
+            arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11,
+        )
+    }
+    pub unsafe fn gss_process_context_token(
+        &self,
+        arg1: *mut OM_uint32,
+        arg2: gss_ctx_id_t,
+        arg3: gss_buffer_t,
+    ) -> OM_uint32 {
+        (self
+            .gss_process_context_token
+            .as_ref()
+            .expect("Expected function, got error."))(arg1, arg2, arg3)
+    }
+    pub unsafe fn gss_delete_sec_context(
+        &self,
+        arg1: *mut OM_uint32,
+        arg2: *mut gss_ctx_id_t,
+        arg3: gss_buffer_t,
+    ) -> OM_uint32 {
+        (self
+            .gss_delete_sec_context
+            .as_ref()
+            .expect("Expected function, got error."))(arg1, arg2, arg3)
+    }
+    pub unsafe fn gss_context_time(
+        &self,
+        arg1: *mut OM_uint32,
+        arg2: gss_ctx_id_t,
+        arg3: *mut OM_uint32,
+    ) -> OM_uint32 {
+        (self
+            .gss_context_time
+            .as_ref()
+            .expect("Expected function, got error."))(arg1, arg2, arg3)
+    }
+    pub unsafe fn gss_get_mic(
+        &self,
+        arg1: *mut OM_uint32,
+        arg2: gss_ctx_id_t,
+        arg3: gss_qop_t,
+        arg4: gss_buffer_t,
+        arg5: gss_buffer_t,
+    ) -> OM_uint32 {
+        (self
+            .gss_get_mic
+            .as_ref()
+            .expect("Expected function, got error."))(arg1, arg2, arg3, arg4, arg5)
+    }
+    pub unsafe fn gss_verify_mic(
+        &self,
+        arg1: *mut OM_uint32,
+        arg2: gss_ctx_id_t,
+        arg3: gss_buffer_t,
+        arg4: gss_buffer_t,
+        arg5: *mut gss_qop_t,
+    ) -> OM_uint32 {
+        (self
+            .gss_verify_mic
+            .as_ref()
+            .expect("Expected function, got error."))(arg1, arg2, arg3, arg4, arg5)
+    }
+    pub unsafe fn gss_wrap(
+        &self,
+        arg1: *mut OM_uint32,
+        arg2: gss_ctx_id_t,
+        arg3: ::std::os::raw::c_int,
+        arg4: gss_qop_t,
+        arg5: gss_buffer_t,
+        arg6: *mut ::std::os::raw::c_int,
+        arg7: gss_buffer_t,
+    ) -> OM_uint32 {
+        (self
+            .gss_wrap
+            .as_ref()
+            .expect("Expected function, got error."))(
+            arg1, arg2, arg3, arg4, arg5, arg6, arg7
+        )
+    }
+    pub unsafe fn gss_unwrap(
+        &self,
+        arg1: *mut OM_uint32,
+        arg2: gss_ctx_id_t,
+        arg3: gss_buffer_t,
+        arg4: gss_buffer_t,
+        arg5: *mut ::std::os::raw::c_int,
+        arg6: *mut gss_qop_t,
+    ) -> OM_uint32 {
+        (self
+            .gss_unwrap
+            .as_ref()
+            .expect("Expected function, got error."))(arg1, arg2, arg3, arg4, arg5, arg6)
+    }
+    pub unsafe fn gss_display_status(
+        &self,
+        arg1: *mut OM_uint32,
+        arg2: OM_uint32,
+        arg3: ::std::os::raw::c_int,
+        arg4: gss_OID,
+        arg5: *mut OM_uint32,
+        arg6: gss_buffer_t,
+    ) -> OM_uint32 {
+        (self
+            .gss_display_status
+            .as_ref()
+            .expect("Expected function, got error."))(arg1, arg2, arg3, arg4, arg5, arg6)
+    }
+    pub unsafe fn gss_indicate_mechs(
+        &self,
+        arg1: *mut OM_uint32,
+        arg2: *mut gss_OID_set,
+    ) -> OM_uint32 {
+        (self
+            .gss_indicate_mechs
+            .as_ref()
+            .expect("Expected function, got error."))(arg1, arg2)
+    }
+    pub unsafe fn gss_compare_name(
+        &self,
+        arg1: *mut OM_uint32,
+        arg2: gss_name_t,
+        arg3: gss_name_t,
+        arg4: *mut ::std::os::raw::c_int,
+    ) -> OM_uint32 {
+        (self
+            .gss_compare_name
+            .as_ref()
+            .expect("Expected function, got error."))(arg1, arg2, arg3, arg4)
+    }
+    pub unsafe fn gss_display_name(
+        &self,
+        arg1: *mut OM_uint32,
+        arg2: gss_name_t,
+        arg3: gss_buffer_t,
+        arg4: *mut gss_OID,
+    ) -> OM_uint32 {
+        (self
+            .gss_display_name
+            .as_ref()
+            .expect("Expected function, got error."))(arg1, arg2, arg3, arg4)
+    }
+    pub unsafe fn gss_import_name(
+        &self,
+        arg1: *mut OM_uint32,
+        arg2: gss_buffer_t,
+        arg3: gss_OID,
+        arg4: *mut gss_name_t,
+    ) -> OM_uint32 {
+        (self
+            .gss_import_name
+            .as_ref()
+            .expect("Expected function, got error."))(arg1, arg2, arg3, arg4)
+    }
+    pub unsafe fn gss_release_name(
+        &self,
+        arg1: *mut OM_uint32,
+        arg2: *mut gss_name_t,
+    ) -> OM_uint32 {
+        (self
+            .gss_release_name
+            .as_ref()
+            .expect("Expected function, got error."))(arg1, arg2)
+    }
+    pub unsafe fn gss_release_buffer(&self, arg1: *mut OM_uint32, arg2: gss_buffer_t) -> OM_uint32 {
+        (self
+            .gss_release_buffer
+            .as_ref()
+            .expect("Expected function, got error."))(arg1, arg2)
+    }
+    pub unsafe fn gss_release_oid_set(
+        &self,
+        arg1: *mut OM_uint32,
+        arg2: *mut gss_OID_set,
+    ) -> OM_uint32 {
+        (self
+            .gss_release_oid_set
+            .as_ref()
+            .expect("Expected function, got error."))(arg1, arg2)
+    }
+    pub unsafe fn gss_inquire_cred(
+        &self,
+        arg1: *mut OM_uint32,
+        arg2: gss_cred_id_t,
+        arg3: *mut gss_name_t,
+        arg4: *mut OM_uint32,
+        arg5: *mut gss_cred_usage_t,
+        arg6: *mut gss_OID_set,
+    ) -> OM_uint32 {
+        (self
+            .gss_inquire_cred
+            .as_ref()
+            .expect("Expected function, got error."))(arg1, arg2, arg3, arg4, arg5, arg6)
+    }
+    pub unsafe fn gss_inquire_context(
+        &self,
+        arg1: *mut OM_uint32,
+        arg2: gss_ctx_id_t,
+        arg3: *mut gss_name_t,
+        arg4: *mut gss_name_t,
+        arg5: *mut OM_uint32,
+        arg6: *mut gss_OID,
+        arg7: *mut OM_uint32,
+        arg8: *mut ::std::os::raw::c_int,
+        arg9: *mut ::std::os::raw::c_int,
+    ) -> OM_uint32 {
+        (self
+            .gss_inquire_context
+            .as_ref()
+            .expect("Expected function, got error."))(
+            arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9,
+        )
+    }
+    pub unsafe fn gss_wrap_size_limit(
+        &self,
+        arg1: *mut OM_uint32,
+        arg2: gss_ctx_id_t,
+        arg3: ::std::os::raw::c_int,
+        arg4: gss_qop_t,
+        arg5: OM_uint32,
+        arg6: *mut OM_uint32,
+    ) -> OM_uint32 {
+        (self
+            .gss_wrap_size_limit
+            .as_ref()
+            .expect("Expected function, got error."))(arg1, arg2, arg3, arg4, arg5, arg6)
+    }
+    pub unsafe fn gss_export_name_object(
+        &self,
+        arg1: *mut OM_uint32,
+        arg2: gss_name_t,
+        arg3: gss_OID,
+        arg4: *mut *mut ::std::os::raw::c_void,
+    ) -> OM_uint32 {
+        (self
+            .gss_export_name_object
+            .as_ref()
+            .expect("Expected function, got error."))(arg1, arg2, arg3, arg4)
+    }
+    pub unsafe fn gss_add_cred(
+        &self,
+        arg1: *mut OM_uint32,
+        arg2: gss_cred_id_t,
+        arg3: gss_name_t,
+        arg4: gss_OID,
+        arg5: gss_cred_usage_t,
+        arg6: OM_uint32,
+        arg7: OM_uint32,
+        arg8: *mut gss_cred_id_t,
+        arg9: *mut gss_OID_set,
+        arg10: *mut OM_uint32,
+        arg11: *mut OM_uint32,
+    ) -> OM_uint32 {
+        (self
+            .gss_add_cred
+            .as_ref()
+            .expect("Expected function, got error."))(
+            arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11,
+        )
+    }
+    pub unsafe fn gss_inquire_cred_by_mech(
+        &self,
+        arg1: *mut OM_uint32,
+        arg2: gss_cred_id_t,
+        arg3: gss_OID,
+        arg4: *mut gss_name_t,
+        arg5: *mut OM_uint32,
+        arg6: *mut OM_uint32,
+        arg7: *mut gss_cred_usage_t,
+    ) -> OM_uint32 {
+        (self
+            .gss_inquire_cred_by_mech
+            .as_ref()
+            .expect("Expected function, got error."))(
+            arg1, arg2, arg3, arg4, arg5, arg6, arg7
+        )
+    }
+    pub unsafe fn gss_export_sec_context(
+        &self,
+        arg1: *mut OM_uint32,
+        arg2: *mut gss_ctx_id_t,
+        arg3: gss_buffer_t,
+    ) -> OM_uint32 {
+        (self
+            .gss_export_sec_context
+            .as_ref()
+            .expect("Expected function, got error."))(arg1, arg2, arg3)
+    }
+    pub unsafe fn gss_import_sec_context(
+        &self,
+        arg1: *mut OM_uint32,
+        arg2: gss_buffer_t,
+        arg3: *mut gss_ctx_id_t,
+    ) -> OM_uint32 {
+        (self
+            .gss_import_sec_context
+            .as_ref()
+            .expect("Expected function, got error."))(arg1, arg2, arg3)
+    }
+    pub unsafe fn gss_release_oid(&self, arg1: *mut OM_uint32, arg2: *mut gss_OID) -> OM_uint32 {
+        (self
+            .gss_release_oid
+            .as_ref()
+            .expect("Expected function, got error."))(arg1, arg2)
+    }
+    pub unsafe fn gss_create_empty_oid_set(
+        &self,
+        arg1: *mut OM_uint32,
+        arg2: *mut gss_OID_set,
+    ) -> OM_uint32 {
+        (self
+            .gss_create_empty_oid_set
+            .as_ref()
+            .expect("Expected function, got error."))(arg1, arg2)
+    }
+    pub unsafe fn gss_add_oid_set_member(
+        &self,
+        arg1: *mut OM_uint32,
+        arg2: gss_OID,
+        arg3: *mut gss_OID_set,
+    ) -> OM_uint32 {
+        (self
+            .gss_add_oid_set_member
+            .as_ref()
+            .expect("Expected function, got error."))(arg1, arg2, arg3)
+    }
+    pub unsafe fn gss_test_oid_set_member(
+        &self,
+        arg1: *mut OM_uint32,
+        arg2: gss_OID,
+        arg3: gss_OID_set,
+        arg4: *mut ::std::os::raw::c_int,
+    ) -> OM_uint32 {
+        (self
+            .gss_test_oid_set_member
+            .as_ref()
+            .expect("Expected function, got error."))(arg1, arg2, arg3, arg4)
+    }
+    pub unsafe fn gss_str_to_oid(
+        &self,
+        arg1: *mut OM_uint32,
+        arg2: gss_buffer_t,
+        arg3: *mut gss_OID,
+    ) -> OM_uint32 {
+        (self
+            .gss_str_to_oid
+            .as_ref()
+            .expect("Expected function, got error."))(arg1, arg2, arg3)
+    }
+    pub unsafe fn gss_oid_to_str(
+        &self,
+        arg1: *mut OM_uint32,
+        arg2: gss_OID,
+        arg3: gss_buffer_t,
+    ) -> OM_uint32 {
+        (self
+            .gss_oid_to_str
+            .as_ref()
+            .expect("Expected function, got error."))(arg1, arg2, arg3)
+    }
+    pub unsafe fn gss_inquire_names_for_mech(
+        &self,
+        arg1: *mut OM_uint32,
+        arg2: gss_OID,
+        arg3: *mut gss_OID_set,
+    ) -> OM_uint32 {
+        (self
+            .gss_inquire_names_for_mech
+            .as_ref()
+            .expect("Expected function, got error."))(arg1, arg2, arg3)
+    }
+    pub unsafe fn gss_inquire_mechs_for_name(
+        &self,
+        arg1: *mut OM_uint32,
+        arg2: gss_name_t,
+        arg3: *mut gss_OID_set,
+    ) -> OM_uint32 {
+        (self
+            .gss_inquire_mechs_for_name
+            .as_ref()
+            .expect("Expected function, got error."))(arg1, arg2, arg3)
+    }
+    pub unsafe fn gss_sign(
+        &self,
+        arg1: *mut OM_uint32,
+        arg2: gss_ctx_id_t,
+        arg3: ::std::os::raw::c_int,
+        arg4: gss_buffer_t,
+        arg5: gss_buffer_t,
+    ) -> OM_uint32 {
+        (self
+            .gss_sign
+            .as_ref()
+            .expect("Expected function, got error."))(arg1, arg2, arg3, arg4, arg5)
+    }
+    pub unsafe fn gss_verify(
+        &self,
+        arg1: *mut OM_uint32,
+        arg2: gss_ctx_id_t,
+        arg3: gss_buffer_t,
+        arg4: gss_buffer_t,
+        arg5: *mut ::std::os::raw::c_int,
+    ) -> OM_uint32 {
+        (self
+            .gss_verify
+            .as_ref()
+            .expect("Expected function, got error."))(arg1, arg2, arg3, arg4, arg5)
+    }
+    pub unsafe fn gss_seal(
+        &self,
+        arg1: *mut OM_uint32,
+        arg2: gss_ctx_id_t,
+        arg3: ::std::os::raw::c_int,
+        arg4: ::std::os::raw::c_int,
+        arg5: gss_buffer_t,
+        arg6: *mut ::std::os::raw::c_int,
+        arg7: gss_buffer_t,
+    ) -> OM_uint32 {
+        (self
+            .gss_seal
+            .as_ref()
+            .expect("Expected function, got error."))(
+            arg1, arg2, arg3, arg4, arg5, arg6, arg7
+        )
+    }
+    pub unsafe fn gss_unseal(
+        &self,
+        arg1: *mut OM_uint32,
+        arg2: gss_ctx_id_t,
+        arg3: gss_buffer_t,
+        arg4: gss_buffer_t,
+        arg5: *mut ::std::os::raw::c_int,
+        arg6: *mut ::std::os::raw::c_int,
+    ) -> OM_uint32 {
+        (self
+            .gss_unseal
+            .as_ref()
+            .expect("Expected function, got error."))(arg1, arg2, arg3, arg4, arg5, arg6)
+    }
+    pub unsafe fn gss_export_name(
+        &self,
+        arg1: *mut OM_uint32,
+        arg2: gss_name_t,
+        arg3: gss_buffer_t,
+    ) -> OM_uint32 {
+        (self
+            .gss_export_name
+            .as_ref()
+            .expect("Expected function, got error."))(arg1, arg2, arg3)
+    }
+    pub unsafe fn gss_duplicate_name(
+        &self,
+        arg1: *mut OM_uint32,
+        arg2: gss_name_t,
+        arg3: *mut gss_name_t,
+    ) -> OM_uint32 {
+        (self
+            .gss_duplicate_name
+            .as_ref()
+            .expect("Expected function, got error."))(arg1, arg2, arg3)
+    }
+    pub unsafe fn gss_canonicalize_name(
+        &self,
+        arg1: *mut OM_uint32,
+        arg2: gss_name_t,
+        arg3: gss_OID,
+        arg4: *mut gss_name_t,
+    ) -> OM_uint32 {
+        (self
+            .gss_canonicalize_name
+            .as_ref()
+            .expect("Expected function, got error."))(arg1, arg2, arg3, arg4)
+    }
+    pub unsafe fn GSS_KRB5_NT_PRINCIPAL_NAME(&self) -> *mut *const gss_OID_desc {
+        *self
+            .GSS_KRB5_NT_PRINCIPAL_NAME
+            .as_ref()
+            .expect("Expected variable, got error.")
+    }
+    pub unsafe fn gss_mech_krb5(&self) -> *mut *const gss_OID_desc {
+        *self
+            .gss_mech_krb5
+            .as_ref()
+            .expect("Expected variable, got error.")
+    }
+    pub unsafe fn gss_mech_krb5_old(&self) -> *mut *const gss_OID_desc {
+        *self
+            .gss_mech_krb5_old
+            .as_ref()
+            .expect("Expected variable, got error.")
+    }
+    pub unsafe fn gss_mech_set_krb5(&self) -> *mut *const gss_OID_set_desc {
+        *self
+            .gss_mech_set_krb5
+            .as_ref()
+            .expect("Expected variable, got error.")
+    }
+    pub unsafe fn gss_mech_set_krb5_old(&self) -> *mut *const gss_OID_set_desc {
+        *self
+            .gss_mech_set_krb5_old
+            .as_ref()
+            .expect("Expected variable, got error.")
+    }
+    pub unsafe fn gss_mech_set_krb5_both(&self) -> *mut *const gss_OID_set_desc {
+        *self
+            .gss_mech_set_krb5_both
+            .as_ref()
+            .expect("Expected variable, got error.")
+    }
+    pub unsafe fn gss_nt_krb5_name(&self) -> *mut *const gss_OID_desc {
+        *self
+            .gss_nt_krb5_name
+            .as_ref()
+            .expect("Expected variable, got error.")
+    }
+    pub unsafe fn gss_nt_krb5_principal(&self) -> *mut *const gss_OID_desc {
+        *self
+            .gss_nt_krb5_principal
+            .as_ref()
+            .expect("Expected variable, got error.")
+    }
+    pub unsafe fn gss_krb5_get_tkt_flags(
+        &self,
+        minor_status: *mut OM_uint32,
+        context_handle: gss_ctx_id_t,
+        ticket_flags: *mut krb5_flags,
+    ) -> OM_uint32 {
+        (self
+            .gss_krb5_get_tkt_flags
+            .as_ref()
+            .expect("Expected function, got error."))(
+            minor_status, context_handle, ticket_flags
+        )
+    }
+    pub unsafe fn gss_krb5_copy_ccache(
+        &self,
+        minor_status: *mut OM_uint32,
+        cred_handle: gss_cred_id_t,
+        out_ccache: krb5_ccache,
+    ) -> OM_uint32 {
+        (self
+            .gss_krb5_copy_ccache
+            .as_ref()
+            .expect("Expected function, got error."))(minor_status, cred_handle, out_ccache)
+    }
+    pub unsafe fn gss_krb5_ccache_name(
+        &self,
+        minor_status: *mut OM_uint32,
+        name: *const ::std::os::raw::c_char,
+        out_name: *mut *const ::std::os::raw::c_char,
+    ) -> OM_uint32 {
+        (self
+            .gss_krb5_ccache_name
+            .as_ref()
+            .expect("Expected function, got error."))(minor_status, name, out_name)
+    }
+    pub unsafe fn gss_krb5_set_allowable_enctypes(
+        &self,
+        minor_status: *mut OM_uint32,
+        cred: gss_cred_id_t,
+        num_ktypes: OM_uint32,
+        ktypes: *mut krb5_enctype,
+    ) -> OM_uint32 {
+        (self
+            .gss_krb5_set_allowable_enctypes
+            .as_ref()
+            .expect("Expected function, got error."))(minor_status, cred, num_ktypes, ktypes)
+    }
+    pub unsafe fn gss_krb5_export_lucid_sec_context(
+        &self,
+        minor_status: *mut OM_uint32,
+        context_handle: *mut gss_ctx_id_t,
+        version: OM_uint32,
+        kctx: *mut *mut ::std::os::raw::c_void,
+    ) -> OM_uint32 {
+        (self
+            .gss_krb5_export_lucid_sec_context
+            .as_ref()
+            .expect("Expected function, got error."))(
+            minor_status, context_handle, version, kctx
+        )
+    }
+    pub unsafe fn gss_krb5_free_lucid_sec_context(
+        &self,
+        minor_status: *mut OM_uint32,
+        kctx: *mut ::std::os::raw::c_void,
+    ) -> OM_uint32 {
+        (self
+            .gss_krb5_free_lucid_sec_context
+            .as_ref()
+            .expect("Expected function, got error."))(minor_status, kctx)
+    }
+    pub unsafe fn gss_krb5_ui(&self, arg1: *mut OM_uint32, arg2: OM_uint32) -> OM_uint32 {
+        (self
+            .gss_krb5_ui
+            .as_ref()
+            .expect("Expected function, got error."))(arg1, arg2)
+    }
+}
diff --git a/rust/src/security/mod.rs b/rust/src/security/mod.rs
index de02f1a..b01cfba 100644
--- a/rust/src/security/mod.rs
+++ b/rust/src/security/mod.rs
@@ -1,5 +1,4 @@
 mod digest;
-#[cfg(feature = "kerberos")]
-mod gssapi;
+pub(crate) mod gssapi;
 pub mod sasl;
 pub mod user;
diff --git a/rust/src/security/sasl.rs b/rust/src/security/sasl.rs
index cf3e1fb..7fe2746 100644
--- a/rust/src/security/sasl.rs
+++ b/rust/src/security/sasl.rs
@@ -27,7 +27,6 @@ use crate::proto::{
 use crate::security::digest::DigestSaslSession;
 use crate::{HdfsError, Result};
 
-#[cfg(feature = "kerberos")]
 use super::gssapi::GssapiSession;
 use super::user::{User, UserInfo};
 
@@ -192,7 +191,6 @@ impl SaslRpcClient {
                 (Some(AuthMethod::Simple), _) => {
                     return Ok((auth.clone(), None));
                 }
-                #[cfg(feature = "kerberos")]
                 (Some(AuthMethod::Kerberos), _) => {
                     let session = GssapiSession::new(auth.protocol(), auth.server_id())?;
                     return Ok((auth.clone(), Some(Box::new(session))));
diff --git a/rust/src/security/user.rs b/rust/src/security/user.rs
index 623b955..ea1e08d 100644
--- a/rust/src/security/user.rs
+++ b/rust/src/security/user.rs
@@ -16,7 +16,6 @@ use crate::proto::hdfs::StorageTypeProto;
 use crate::Result;
 
 const HADOOP_USER_NAME: &str = "HADOOP_USER_NAME";
-#[cfg(feature = "kerberos")]
 const HADOOP_PROXY_USER: &str = "HADOOP_PROXY_USER";
 const HADOOP_TOKEN_FILE_LOCATION: &str = "HADOOP_TOKEN_FILE_LOCATION";
 const TOKEN_STORAGE_MAGIC: &[u8] = "HDTS".as_bytes();
@@ -125,6 +124,7 @@ impl BlockTokenIdentifier {
 }
 
 #[derive(Debug)]
+#[allow(dead_code)]
 pub struct Token {
     pub alias: String,
     pub identifier: Vec<u8>,
@@ -323,7 +323,6 @@ impl User {
             .find(|t| t.kind == kind && t.service == service)
     }
 
-    #[cfg(feature = "kerberos")]
     pub(crate) fn get_user_info_from_principal(principal: &str) -> UserInfo {
         let username = User::get_user_from_principal(principal);
         let proxy_user = env::var(HADOOP_PROXY_USER).ok();
@@ -347,7 +346,6 @@ impl User {
         }
     }
 
-    #[cfg(feature = "kerberos")]
     pub(crate) fn get_user_from_principal(principal: &str) -> String {
         // If there's a /, take the part before it.
         if let Some(index) = principal.find('/') {


Test patch:
diff --git a/.github/workflows/python-test.yml b/.github/workflows/python-test.yml
index 315e1a5..9241232 100644
--- a/.github/workflows/python-test.yml
+++ b/.github/workflows/python-test.yml
@@ -29,9 +29,6 @@ jobs:
           distribution: "temurin"
           java-version: "17"
 
-      - name: Install native libs
-        run: sudo apt-get install -y libkrb5-dev krb5-user
-
       - name: Download Hadoop
         run: |
           wget -q https://dlcdn.apache.org/hadoop/common/hadoop-3.3.6/hadoop-3.3.6.tar.gz
@@ -53,7 +50,7 @@ jobs:
           sccache: 'true'
           container: 'off'
           working-directory: ./python
-          args: --features kerberos --extras devel
+          args: --extras devel
       
       - name: Run lints
         run: |
@@ -74,12 +71,9 @@ jobs:
       - name: Build wheel
         uses: PyO3/maturin-action@v1
         with:
-          args: --release --out dist --find-interpreter --manifest-path python/Cargo.toml --features kerberos
+          args: --release --out dist --find-interpreter --manifest-path python/Cargo.toml
           sccache: 'true'
-          manylinux: '2014'
-          docker-options: -e LD_LIBRARY_PATH=/opt/rh/llvm-toolset-7.0/root/usr/lib64 -e LLVM_CONFIG_PATH=/opt/rh/llvm-toolset-7.0/root/usr/bin/llvm-config
-          before-script-linux: |
-            yum install -y epel-release && yum install -y krb5-devel llvm-toolset-7.0-clang llvm-toolset-7.0-llvm-devel
+
       - name: Upload wheels
         if: github.ref == 'refs/heads/master'
         uses: actions/upload-artifact@v4
diff --git a/.github/workflows/rust-test.yml b/.github/workflows/rust-test.yml
index 5811d24..84bb957 100644
--- a/.github/workflows/rust-test.yml
+++ b/.github/workflows/rust-test.yml
@@ -40,23 +40,17 @@ jobs:
 
       - uses: Swatinem/rust-cache@v2
 
-      - name: Install native libs
-        run: sudo apt-get install -y libkrb5-dev
-
       - name: build and lint with clippy
-        run: cargo clippy --all-targets --features kerberos,integration-test,benchmark -- -D warnings
+        run: cargo clippy --all-targets --features integration-test,benchmark -- -D warnings
 
       - name: Check docs
         run: cargo doc
 
       - name: Check no features
         run: cargo check --tests
-      
-      - name: Check kerberos
-        run: cargo check --tests --features kerberos
 
       - name: Check all features
-        run: cargo check --all-targets --features kerberos,integration-test,benchmark
+        run: cargo check --all-targets --features integration-test,benchmark
 
   test:
     strategy:
@@ -99,4 +93,4 @@ jobs:
           echo "$GITHUB_WORKSPACE/hadoop-3.4.0/bin" >> $GITHUB_PATH
 
       - name: Run tests
-        run: cargo test --features kerberos,integration-test
+        run: cargo test --features integration-test
diff --git a/rust/tests/test_ec.rs b/rust/tests/test_ec.rs
index f3975ab..9f895ce 100644
--- a/rust/tests/test_ec.rs
+++ b/rust/tests/test_ec.rs
@@ -98,10 +98,7 @@ mod test {
     async fn test_erasure_coded_read() -> Result<()> {
         let _ = env_logger::builder().is_test(true).try_init();
 
-        #[allow(unused_mut)]
-        let mut dfs_features = HashSet::from([DfsFeatures::EC]);
-        #[cfg(feature = "kerberos")]
-        dfs_features.insert(DfsFeatures::Security);
+        let dfs_features = HashSet::from([DfsFeatures::EC]);
 
         let dfs = MiniDfs::with_features(&dfs_features);
         let client = Client::default();
@@ -173,10 +170,7 @@ mod test {
     async fn test_erasure_coded_write() -> Result<()> {
         let _ = env_logger::builder().is_test(true).try_init();
 
-        #[allow(unused_mut)]
-        let mut dfs_features = HashSet::from([DfsFeatures::EC]);
-        #[cfg(feature = "kerberos")]
-        dfs_features.insert(DfsFeatures::Security);
+        let dfs_features = HashSet::from([DfsFeatures::EC]);
 
         let _dfs = MiniDfs::with_features(&dfs_features);
         let client = Client::default();
diff --git a/rust/tests/test_integration.rs b/rust/tests/test_integration.rs
index 80da9a7..5502d0b 100644
--- a/rust/tests/test_integration.rs
+++ b/rust/tests/test_integration.rs
@@ -17,7 +17,6 @@ mod test {
 
     #[tokio::test]
     #[serial]
-    #[cfg(feature = "kerberos")]
     async fn test_security_kerberos() {
         test_with_features(&HashSet::from([DfsFeatures::Security]))
             .await
@@ -34,7 +33,6 @@ mod test {
 
     #[tokio::test]
     #[serial]
-    #[cfg(feature = "kerberos")]
     async fn test_integrity_kerberos() {
         test_with_features(&HashSet::from([
             DfsFeatures::Security,
@@ -58,7 +56,6 @@ mod test {
 
     #[tokio::test]
     #[serial]
-    #[cfg(feature = "kerberos")]
     async fn test_privacy_kerberos() {
         test_with_features(&HashSet::from([
             DfsFeatures::Security,
@@ -82,7 +79,6 @@ mod test {
 
     #[tokio::test]
     #[serial]
-    #[cfg(feature = "kerberos")]
     async fn test_aes() {
         test_with_features(&HashSet::from([
             DfsFeatures::Security,
@@ -95,7 +91,6 @@ mod test {
 
     #[tokio::test]
     #[serial]
-    #[cfg(feature = "kerberos")]
     async fn test_forced_data_transfer_encryption() {
         // DataTransferEncryption enabled but privacy isn't, still force encryption
         test_with_features(&HashSet::from([
@@ -108,7 +103,6 @@ mod test {
 
     #[tokio::test]
     #[serial]
-    #[cfg(feature = "kerberos")]
     async fn test_data_transfer_encryption() {
         test_with_features(&HashSet::from([
             DfsFeatures::Security,
@@ -121,7 +115,6 @@ mod test {
 
     #[tokio::test]
     #[serial]
-    #[cfg(feature = "kerberos")]
     async fn test_data_transfer_encryption_aes() {
         test_with_features(&HashSet::from([
             DfsFeatures::Security,
@@ -143,7 +136,6 @@ mod test {
 
     #[tokio::test]
     #[serial]
-    #[cfg(feature = "kerberos")]
     async fn test_security_privacy_ha() {
         test_with_features(&HashSet::from([
             DfsFeatures::Security,
diff --git a/rust/tests/test_write_resiliency.rs b/rust/tests/test_write_resiliency.rs
index fb04463..03ac782 100644
--- a/rust/tests/test_write_resiliency.rs
+++ b/rust/tests/test_write_resiliency.rs
@@ -15,9 +15,6 @@ mod test {
     async fn test_write_resiliency() -> Result<()> {
         let _ = env_logger::builder().is_test(true).try_init();
 
-        #[cfg(feature = "kerberos")]
-        let _dfs = MiniDfs::with_features(&HashSet::from([DfsFeatures::HA, DfsFeatures::Security]));
-        #[cfg(not(feature = "kerberos"))]
         let _dfs = MiniDfs::with_features(&HashSet::from([DfsFeatures::HA]));
         let client = Client::default();