libkrimes 0.1.0

A pure rust, minimal kerberos library
Documentation
use super::CredentialCache;
use crate::ccache::cc_file::FileCredentialCacheContext;
use crate::error::KrbError;
use std::fs::{DirBuilder, File, Permissions};
use std::io::{Read, Write};
use std::os::unix::fs::DirBuilderExt;
use std::os::unix::fs::PermissionsExt;
use std::path::{Path, PathBuf};
use tracing::{error, trace};

fn create_ccache_dir(ccache_dir: &PathBuf) -> Result<(), KrbError> {
    trace!(?ccache_dir, "Check collection path");
    match std::fs::exists(ccache_dir) {
        Ok(true) => match ccache_dir.is_dir() {
            false => {
                error!(?ccache_dir, "Not a directory");
                Err(KrbError::CredentialCacheError)
            }
            true => Ok(()),
        },
        Ok(false) => DirBuilder::new()
            .recursive(true)
            .mode(0o700)
            .create(ccache_dir)
            .map_err(|e| {
                error!(?e, ?ccache_dir, "Failed to create directory",);
                KrbError::IoError
            }),
        Err(e) => {
            error!(?e, "Failed to check if path exists");
            Err(KrbError::IoError)
        }
    }
}

fn get_primary(path: &Path) -> Result<Option<PathBuf>, KrbError> {
    let primary = path.join("primary");
    match std::fs::exists(&primary) {
        Ok(true) => {
            let mut f = File::open(&primary).map_err(|e| {
                error!(?primary, ?e, "Failed to open file");
                KrbError::IoError
            })?;
            let mut buffer = String::new();
            f.read_to_string(&mut buffer).map_err(|e| {
                error!(?primary, ?e, "Filed to read file");
                KrbError::IoError
            })?;
            let primary_path = path.join(buffer.trim());
            trace!(?primary_path, "Primary credentials ccache");
            Ok(Some(primary_path))
        }
        Ok(false) => {
            trace!("No primary credentials ccache");
            Ok(None)
        }
        Err(e) => {
            error!(?e, ?primary, "Failed to read primary credentials");
            Err(KrbError::IoError)
        }
    }
}

fn set_primary(path: &Path, primary_name: &str) -> Result<(), KrbError> {
    let primary_path = path.join("primary");
    let mut f = File::create_new(&primary_path).map_err(|e| {
        error!(?e, ?primary_path, "Failed to create primary file");
        KrbError::IoError
    })?;

    let perms = Permissions::from_mode(0o600);
    f.set_permissions(perms).map_err(|x| {
        error!(?x, ?primary_path, "Failed to set primary file permissions");
        KrbError::IoError
    })?;

    f.write_all(primary_name.as_bytes()).map_err(|e| {
        error!(?e, ?primary_path, "Failed to write primary file");
        KrbError::IoError
    })
}

pub(super) fn resolve(ccache_name: &str) -> Result<Box<dyn CredentialCache>, KrbError> {
    trace!(?ccache_name, "Resolving dir credential cache");

    let ccache_name = ccache_name
        .strip_prefix("DIR:")
        .ok_or(KrbError::UnsupportedCredentialCacheType)?;

    let path = if ccache_name.starts_with(":") {
        trace!(?ccache_name, "Collection with subsidiary");
        let ccache_name = ccache_name
            .strip_prefix(":")
            .ok_or(KrbError::CredentialCacheError)?;
        let path = PathBuf::from(ccache_name);

        let collection_path = match path.parent() {
            Some(p) => Ok(PathBuf::from(p)),
            None => Err(KrbError::CredentialCacheError),
        }?;

        create_ccache_dir(&collection_path)?;
        path
    } else {
        trace!(?ccache_name, "Collection without subsidiary");
        let collection_path = PathBuf::from(ccache_name);
        create_ccache_dir(&collection_path)?;

        match get_primary(&collection_path)? {
            Some(primary_path) => primary_path,
            None => {
                set_primary(&collection_path, "tkt")?;
                collection_path.join("tkt")
            }
        }
    };

    trace!(?path, "Resolved dir subsidiary credential cache");

    let fcc = FileCredentialCacheContext { path };
    Ok(Box::new(fcc))
}