use crate::{context::Context, sys::library_match};
const KADM5_OK: i32 = 0;
const KRB5_OK: i32 = 0;
#[derive(thiserror::Error, Debug)]
#[non_exhaustive]
pub enum Error {
#[error("Kerberos error: {message} (code: {code})")]
Kerberos {
code: i64,
message: String,
},
#[error("KAdmin error: {message} (code: {code})")]
KAdmin {
code: i64,
message: String,
},
#[error("Conversion to encryption type failed")]
EncryptionTypeConversion,
#[error("Conversion to salt type failed")]
SaltTypeConversion,
#[error("NULL pointer dereference error")]
NullPointerDereference,
#[error(transparent)]
CStringConversion(#[from] std::ffi::IntoStringError),
#[error(transparent)]
CStringImportFromVec(#[from] std::ffi::FromVecWithNulError),
#[error(transparent)]
StringConversion(#[from] std::ffi::NulError),
#[error("Failed to send operation to executor")]
ThreadSendError,
#[error("Failed to receive result from executor")]
ThreadRecvError(#[from] std::sync::mpsc::RecvError),
#[error("Failed to convert krb5 timestamp to chrono DateTime")]
TimestampConversion,
#[error("Failed to convert chrono DateTime to krb5 timestamp")]
DateTimeConversion(std::num::TryFromIntError),
#[error("Failed to convert Duration to a krb5 deltat")]
DurationConversion(std::num::TryFromIntError),
#[error("Failed to acquire the kadmin initialisation lock")]
LockError,
#[error("Failed to load the kadm5 library")]
LibraryLoadError(#[from] dlopen2::Error),
#[error("The library is not compatible with the current operation")]
LibraryMismatch(&'static str),
}
impl<T> From<std::sync::mpsc::SendError<T>> for Error {
fn from(_error: std::sync::mpsc::SendError<T>) -> Self {
Self::ThreadSendError
}
}
pub type Result<T> = std::result::Result<T, Error>;
pub(crate) fn krb5_error_code_escape_hatch(context: &Context, code: i64) -> Result<()> {
if code == KRB5_OK as i64 {
Ok(())
} else {
Err(Error::Kerberos {
code,
message: context.error_code_to_message(code),
})
}
}
macro_rules! kadm5_error_enum {
(
$libname:ident;
$(#[$outer:meta])*
$EnumName:ident { $($manual_fields:tt)* }
) => {
$(#[$outer])*
enum $EnumName {
#[error("Operation failed for unspecified reason")]
Failure = kadm5_error_enum!($libname, KADM5_FAILURE),
#[error("Operation requires ``get'' privilege")]
AuthGet = kadm5_error_enum!($libname, KADM5_AUTH_GET),
#[error("Operation requires ``add'' privilege")]
AuthAdd = kadm5_error_enum!($libname, KADM5_AUTH_ADD),
#[error("Operation requires ``modify'' privilege")]
AuthModify = kadm5_error_enum!($libname, KADM5_AUTH_MODIFY),
#[error("Operation requires ``delete'' privilege")]
AuthDelete = kadm5_error_enum!($libname, KADM5_AUTH_DELETE),
#[error("Insufficient authorization for operation")]
AuthInsufficient = kadm5_error_enum!($libname, KADM5_AUTH_INSUFFICIENT),
#[error("Database inconsistency detected")]
BadDb = kadm5_error_enum!($libname, KADM5_BAD_DB),
#[error("Principal or policy already exists")]
Dup = kadm5_error_enum!($libname, KADM5_DUP),
#[error("Communication failure with server")]
RpcError = kadm5_error_enum!($libname, KADM5_RPC_ERROR),
#[error("No administration server found for realm")]
NoSrv = kadm5_error_enum!($libname, KADM5_NO_SRV),
#[error("Password history entry (kadmin/history) contains unsupported key type")]
BadHistKey = kadm5_error_enum!($libname, KADM5_BAD_HIST_KEY),
#[error("Connection to server not initialized")]
NotInit = kadm5_error_enum!($libname, KADM5_NOT_INIT),
#[error("Principal does not exist")]
UnkPrinc = kadm5_error_enum!($libname, KADM5_UNK_PRINC),
#[error("Policy does not exist")]
UnkPolicy = kadm5_error_enum!($libname, KADM5_UNK_POLICY),
#[error("Invalid field mask for operation")]
BadMask = kadm5_error_enum!($libname, KADM5_BAD_MASK),
#[error("Invalid number of character classes")]
BadClass = kadm5_error_enum!($libname, KADM5_BAD_CLASS),
#[error("Invalid password length")]
BadLength = kadm5_error_enum!($libname, KADM5_BAD_LENGTH),
#[error("Illegal policy name")]
BadPolicy = kadm5_error_enum!($libname, KADM5_BAD_POLICY),
#[error("Illegal principal name")]
BadPrincipal = kadm5_error_enum!($libname, KADM5_BAD_PRINCIPAL),
#[error("Invalid auxillary attributes")]
BadAuxAttr = kadm5_error_enum!($libname, KADM5_BAD_AUX_ATTR),
#[error("Invalid password history count")]
BadHistory = kadm5_error_enum!($libname, KADM5_BAD_HISTORY),
#[error("Password minimum life is greater then password maximum life")]
BadMinPassLife = kadm5_error_enum!($libname, KADM5_BAD_MIN_PASS_LIFE),
#[error("Password is too short")]
PassQTooshort = kadm5_error_enum!($libname, KADM5_PASS_Q_TOOSHORT),
#[error("Password does not contain enough character classes")]
PassQClass = kadm5_error_enum!($libname, KADM5_PASS_Q_CLASS),
#[error("Password is in the password dictionary")]
PassQDict = kadm5_error_enum!($libname, KADM5_PASS_Q_DICT),
#[error("Cannot reuse password")]
PassReuse = kadm5_error_enum!($libname, KADM5_PASS_REUSE),
#[error("Current password's minimum life has not expired")]
PassToosoon = kadm5_error_enum!($libname, KADM5_PASS_TOOSOON),
#[error("Policy is in use")]
PolicyRef = kadm5_error_enum!($libname, KADM5_POLICY_REF),
#[error("Connection to server already initialized")]
Init = kadm5_error_enum!($libname, KADM5_INIT),
#[error("Incorrect password")]
BadPassword = kadm5_error_enum!($libname, KADM5_BAD_PASSWORD),
#[error("Cannot change protected principal")]
ProtectPrincipal = kadm5_error_enum!($libname, KADM5_PROTECT_PRINCIPAL),
#[error("Programmer error! Bad Admin server handle")]
BadServerHandle = kadm5_error_enum!($libname, KADM5_BAD_SERVER_HANDLE),
#[error("Programmer error! Bad API structure version")]
BadStructVersion = kadm5_error_enum!($libname, KADM5_BAD_STRUCT_VERSION),
#[error("API structure version specified by application is no longer supported (to fix, recompile application against current Admin API header files and libraries)")]
OldStructVersion = kadm5_error_enum!($libname, KADM5_OLD_STRUCT_VERSION),
#[error("API structure version specified by application is unknown to libraries (to fix, obtain current Admin API header files and libraries and recompile application)")]
NewStructVersion = kadm5_error_enum!($libname, KADM5_NEW_STRUCT_VERSION),
#[error("Programmer error! Bad API version")]
BadApiVersion = kadm5_error_enum!($libname, KADM5_BAD_API_VERSION),
#[error("API version specified by application is no longer supported by libraries (to fix, update application to adhere to current API version and recompile)")]
OldLibApiVersion = kadm5_error_enum!($libname, KADM5_OLD_LIB_API_VERSION),
#[error("API version specified by application is no longer supported by server (to fix, update application to adhere to current API version and recompile)")]
OldServerApiVersion = kadm5_error_enum!($libname, KADM5_OLD_SERVER_API_VERSION),
#[error("API version specified by application is unknown to libraries (to fix, obtain current Admin API header files and libraries and recompile application)")]
NewLibApiVersion = kadm5_error_enum!($libname, KADM5_NEW_LIB_API_VERSION),
#[error("API version specified by application is unknown to server (to fix, obtain and install newest Admin Server)")]
NewServerApiVersion = kadm5_error_enum!($libname, KADM5_NEW_SERVER_API_VERSION),
#[error("Database error! Required principal missing")]
SecurePrincMissing = kadm5_error_enum!($libname, KADM5_SECURE_PRINC_MISSING),
#[error("The salt type of the specified principal does not support renaming")]
NoRenameSalt = kadm5_error_enum!($libname, KADM5_NO_RENAME_SALT),
#[error("Illegal configuration parameter for remote KADM5 client")]
BadClientParams = kadm5_error_enum!($libname, KADM5_BAD_CLIENT_PARAMS),
#[error("Illegal configuration parameter for local KADM5 client.")]
BadServerParams = kadm5_error_enum!($libname, KADM5_BAD_SERVER_PARAMS),
#[error("Operation requires ``list'' privilege")]
AuthList = kadm5_error_enum!($libname, KADM5_AUTH_LIST),
#[error("Operation requires ``change-password'' privilege")]
AuthChangepw = kadm5_error_enum!($libname, KADM5_AUTH_CHANGEPW),
#[error("Programmer error! Illegal tagged data list element type")]
BadTlType = kadm5_error_enum!($libname, KADM5_BAD_TL_TYPE),
#[error("Required parameters in kdc.conf missing")]
MissingConfParams = kadm5_error_enum!($libname, KADM5_MISSING_CONF_PARAMS),
#[error("Bad krb5 admin server hostname")]
BadServerName = kadm5_error_enum!($libname, KADM5_BAD_SERVER_NAME),
#[error("Mismatched enctypes for setkey3")]
Setkey3EtypeMismatch = kadm5_error_enum!($libname, KADM5_SETKEY3_ETYPE_MISMATCH),
$($manual_fields)*
}
impl From<$EnumName> for Error {
fn from(error: $EnumName) -> Self {
Error::KAdmin {
code: error as i64,
message: error.to_string()
}
}
}
};
(mit_client, $const:ident) => {
crate::sys::mit_client::$const as i64
};
(mit_server, $const:ident) => {
crate::sys::mit_server::$const as i64
};
(heimdal_client, $const:ident) => {
crate::sys::heimdal_client::$const as i64
};
(heimdal_server, $const:ident) => {
crate::sys::heimdal_server::$const as i64
};
}
#[cfg(mit_client)]
kadm5_error_enum!(
mit_client;
#[derive(thiserror::Error, strum::FromRepr, Copy, Clone, Debug)]
#[non_exhaustive]
#[repr(i64)]
KAdm5ErrorMitClient {
#[error("Unspecified password quality failure")]
PassQGeneric = kadm5_error_enum!(mit_client, KADM5_PASS_Q_GENERIC),
#[error("GSS-API (or Kerberos) error")]
GssError = kadm5_error_enum!(mit_client, KADM5_GSS_ERROR),
#[error("Operation requires ``set-key'' privilege")]
AuthSetkey = kadm5_error_enum!(mit_client, KADM5_AUTH_SETKEY),
#[error("Multiple values for single or folded enctype")]
SetkeyDupEnctypes = kadm5_error_enum!(mit_client, KADM5_SETKEY_DUP_ENCTYPES),
#[error("Invalid enctype for setv4key")]
Setv4keyInvalEnctype = kadm5_error_enum!(mit_client, KADM5_SETV4KEY_INVAL_ENCTYPE),
#[error("Missing parameters in krb5.conf required for kadmin client")]
MissingKrb5ConfParams = kadm5_error_enum!(mit_client, KADM5_MISSING_KRB5_CONF_PARAMS),
#[error("XDR encoding error")]
XdrFailure = kadm5_error_enum!(mit_client, KADM5_XDR_FAILURE),
#[error("Cannot resolve network address for admin server in requested realm")]
CantResolve = kadm5_error_enum!(mit_client, KADM5_CANT_RESOLVE),
#[error("Invalid key/salt tuples")]
BadKeysalts = kadm5_error_enum!(mit_client, KADM5_BAD_KEYSALTS),
#[error("Invalid multiple or duplicate kvnos in setkey operation")]
SetkeyBadKvno = kadm5_error_enum!(mit_client, KADM5_SETKEY_BAD_KVNO),
#[error("Operation requires ``extract-keys'' privilege")]
AuthExtract = kadm5_error_enum!(mit_client, KADM5_AUTH_EXTRACT),
#[error("Principal keys are locked down")]
ProtectKeys = kadm5_error_enum!(mit_client, KADM5_PROTECT_KEYS),
#[error("Operation requires initial ticket")]
AuthInitial = kadm5_error_enum!(mit_client, KADM5_AUTH_INITIAL),
}
);
#[cfg(mit_server)]
kadm5_error_enum!(
mit_server;
#[derive(thiserror::Error, strum::FromRepr, Copy, Clone, Debug)]
#[non_exhaustive]
#[repr(i64)]
KAdm5ErrorMitServer {
#[error("Unspecified password quality failure")]
PassQGeneric = kadm5_error_enum!(mit_server, KADM5_PASS_Q_GENERIC),
#[error("GSS-API (or Kerberos) error")]
GssError = kadm5_error_enum!(mit_server, KADM5_GSS_ERROR),
#[error("Operation requires ``set-key'' privilege")]
AuthSetkey = kadm5_error_enum!(mit_server, KADM5_AUTH_SETKEY),
#[error("Multiple values for single or folded enctype")]
SetkeyDupEnctypes = kadm5_error_enum!(mit_server, KADM5_SETKEY_DUP_ENCTYPES),
#[error("Invalid enctype for setv4key")]
Setv4keyInvalEnctype = kadm5_error_enum!(mit_server, KADM5_SETV4KEY_INVAL_ENCTYPE),
#[error("Missing parameters in krb5.conf required for kadmin client")]
MissingKrb5ConfParams = kadm5_error_enum!(mit_server, KADM5_MISSING_KRB5_CONF_PARAMS),
#[error("XDR encoding error")]
XdrFailure = kadm5_error_enum!(mit_server, KADM5_XDR_FAILURE),
#[error("Cannot resolve network address for admin server in requested realm")]
CantResolve = kadm5_error_enum!(mit_server, KADM5_CANT_RESOLVE),
#[error("Invalid key/salt tuples")]
BadKeysalts = kadm5_error_enum!(mit_server, KADM5_BAD_KEYSALTS),
#[error("Invalid multiple or duplicate kvnos in setkey operation")]
SetkeyBadKvno = kadm5_error_enum!(mit_server, KADM5_SETKEY_BAD_KVNO),
#[error("Operation requires ``extract-keys'' privilege")]
AuthExtract = kadm5_error_enum!(mit_server, KADM5_AUTH_EXTRACT),
#[error("Principal keys are locked down")]
ProtectKeys = kadm5_error_enum!(mit_server, KADM5_PROTECT_KEYS),
#[error("Operation requires initial ticket")]
AuthInitial = kadm5_error_enum!(mit_server, KADM5_AUTH_INITIAL),
}
);
#[cfg(heimdal_client)]
kadm5_error_enum!(
heimdal_client;
#[derive(thiserror::Error, strum::FromRepr, Copy, Clone, Debug)]
#[non_exhaustive]
#[repr(i64)]
KAdm5ErrorHeimdalClient {
#[error("Key/salt tuples not supported by this function")]
KsTupleNosupp = kadm5_error_enum!(heimdal_client, KADM5_KS_TUPLE_NOSUPP),
#[error("Given usage of kadm5_decrypt() not supported")]
DecryptUsageNosupp = kadm5_error_enum!(heimdal_client, KADM5_DECRYPT_USAGE_NOSUPP),
#[error("Policy operations not supported")]
PolicyOpNosupp = kadm5_error_enum!(heimdal_client, KADM5_POLICY_OP_NOSUPP),
#[error("Operation requires `get_keys' privilege")]
AuthGetKeys = kadm5_error_enum!(heimdal_client, KADM5_AUTH_GET_KEYS),
#[error("Database already locked")]
AlreadyLocked = kadm5_error_enum!(heimdal_client, KADM5_ALREADY_LOCKED),
#[error("Database not locked")]
NotLocked = kadm5_error_enum!(heimdal_client, KADM5_NOT_LOCKED),
#[error("Incremental propagation log got corrupted")]
LogCorrupt = kadm5_error_enum!(heimdal_client, KADM5_LOG_CORRUPT),
#[error("Incremental propagation log must be upgraded")]
LogNeedsUpgrade = kadm5_error_enum!(heimdal_client, KADM5_LOG_NEEDS_UPGRADE),
#[error("Keep old keys option not supported")]
KeepoldNosupp = kadm5_error_enum!(heimdal_client, KADM5_KEEPOLD_NOSUPP),
}
);
#[cfg(heimdal_server)]
kadm5_error_enum!(
heimdal_server;
#[derive(thiserror::Error, strum::FromRepr, Copy, Clone, Debug)]
#[non_exhaustive]
#[repr(i64)]
KAdm5ErrorHeimdalServer {
#[error("Key/salt tuples not supported by this function")]
KsTupleNosupp = kadm5_error_enum!(heimdal_server, KADM5_KS_TUPLE_NOSUPP),
#[error("Given usage of kadm5_decrypt() not supported")]
DecryptUsageNosupp = kadm5_error_enum!(heimdal_server, KADM5_DECRYPT_USAGE_NOSUPP),
#[error("Policy operations not supported")]
PolicyOpNosupp = kadm5_error_enum!(heimdal_server, KADM5_POLICY_OP_NOSUPP),
#[error("Operation requires `get_keys' privilege")]
AuthGetKeys = kadm5_error_enum!(heimdal_server, KADM5_AUTH_GET_KEYS),
#[error("Database already locked")]
AlreadyLocked = kadm5_error_enum!(heimdal_server, KADM5_ALREADY_LOCKED),
#[error("Database not locked")]
NotLocked = kadm5_error_enum!(heimdal_server, KADM5_NOT_LOCKED),
#[error("Incremental propagation log got corrupted")]
LogCorrupt = kadm5_error_enum!(heimdal_server, KADM5_LOG_CORRUPT),
#[error("Incremental propagation log must be upgraded")]
LogNeedsUpgrade = kadm5_error_enum!(heimdal_server, KADM5_LOG_NEEDS_UPGRADE),
#[error("Keep old keys option not supported")]
KeepoldNosupp = kadm5_error_enum!(heimdal_server, KADM5_KEEPOLD_NOSUPP),
}
);
pub(crate) fn kadm5_ret_t_escape_hatch(context: &Context, code: i64) -> Result<()> {
if code == KADM5_OK as i64 {
return Ok(());
}
if let Some(err) = library_match!(
&context.library;
mit_client => |_cont, _lib| {
KAdm5ErrorMitClient::from_repr(code).map(|e| e.into())
},
mit_server => |_cont, _lib| {
KAdm5ErrorMitServer::from_repr(code).map(|e| e.into())
},
heimdal_client => |_cont, _lib| {
KAdm5ErrorHeimdalClient::from_repr(code).map(|e| e.into())
},
heimdal_server => |_cont, _lib| {
KAdm5ErrorHeimdalServer::from_repr(code).map(|e| e.into())
}
) {
Err(err)
} else {
krb5_error_code_escape_hatch(context, code)
}
}