Skip to content
This repository has been archived by the owner on Sep 4, 2024. It is now read-only.

Commit

Permalink
Add FFI for libmsal and BrokerClientApplication
Browse files Browse the repository at this point in the history
Signed-off-by: David Mulder <[email protected]>
  • Loading branch information
dmulder committed May 31, 2024
1 parent a18297b commit ca5bfd1
Show file tree
Hide file tree
Showing 7 changed files with 1,779 additions and 0 deletions.
5 changes: 5 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ repository = "https://github.com/himmelblau-idm/msal"
[lib]
name = "msal"
path = "src/lib.rs"
crate-type = ["rlib", "cdylib"]

[features]
default = ["broker"]
Expand All @@ -35,3 +36,7 @@ kanidm-hsm-crypto = { version = "^0.2.0", optional = true }
regex = "^1.10.3"
zeroize = { version = "^1.7.0", features = ["zeroize_derive"] }
scraper = "0.19.0"
tokio = { version = "1.37.0", features = ["full"] }

[build-dependencies]
cbindgen = "0.26.0"
32 changes: 32 additions & 0 deletions build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/*
Unix Azure Entra ID implementation
Copyright (C) David Mulder <[email protected]> 2024
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
use std::env;
use std::path::PathBuf;

fn main() {
let profile = env::var("PROFILE").unwrap();
let out_path = match profile.as_str() {
"release" => PathBuf::from("target/release"),
_ => PathBuf::from("target/debug"),
};
let crate_dir = env::var("CARGO_MANIFEST_DIR").unwrap();

cbindgen::generate(crate_dir)
.expect("Couldn't write bindings!")
.write_to_file(out_path.join("include/msal.h"));
}
2 changes: 2 additions & 0 deletions cbindgen.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
language = "C"
include_guard = "MSAL_H"
106 changes: 106 additions & 0 deletions src/c_helper.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
/*
Unix Azure Entra ID implementation
Copyright (C) David Mulder <[email protected]> 2024
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/

use crate::MSAL_ERROR;
use std::ffi::{CStr, CString};
use std::os::raw::{c_char, c_int};
use std::ptr;
use std::slice;
use tracing::error;

pub(crate) fn wrap_c_char(input: *const c_char) -> Option<String> {
if input.is_null() {
return None;
}

let c_str = unsafe { CStr::from_ptr(input) };
match c_str.to_str() {
Ok(output) => Some(output.to_string()),
Err(_) => None,
}
}

pub(crate) fn wrap_string(input: &str) -> *mut c_char {
match CString::new(input.to_string()) {
Ok(msg) => msg.into_raw(),
Err(e) => {
error!("{:?}", e);
ptr::null_mut()
}
}
}

macro_rules! free_object {
($input:ident) => {{
if !$input.is_null() {
unsafe {
let _ = Box::from_raw($input);
}
}
}};
}

macro_rules! run_async {
($client:ident, $func:ident $(, $arg:expr)* $(,)?) => {{
match runtime::Runtime::new() {
Ok(rt) => rt.block_on(async {
match $client.$func($($arg),*).await {
Ok(resp) => Ok(resp),
Err(e) => {
error!("{:?}", e);
Err(MSAL_ERROR::from(e))
}
}
}),
Err(e) => {
error!("{:?}", e);
Err(MSAL_ERROR::NO_MEMORY)
}
}
}}
}

pub(crate) fn str_array_to_vec(
arr: *const *const c_char,
len: c_int,
) -> Result<Vec<String>, MSAL_ERROR> {
let slice = unsafe { slice::from_raw_parts(arr, len as usize) };
let mut array = Vec::new();
for &item in slice {
if item.is_null() {
error!("Invalid input {}!", stringify!($arr));
return Err(MSAL_ERROR::INVALID_POINTER);
}
let c_item = unsafe { CStr::from_ptr(item) };
let str_item = match c_item.to_str() {
Ok(str_item) => str_item,
Err(e) => {
error!("{:?}", e);
return Err(MSAL_ERROR::INVALID_POINTER);
}
};
array.push(str_item.to_string());
}
Ok(array)
}

macro_rules! str_vec_ref {
($items:ident) => {
$items.iter().map(|i| i.as_str()).collect()
};
}
1 change: 1 addition & 0 deletions src/discovery.rs
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,7 @@ struct NonceResp {
}

#[cfg(feature = "broker")]
#[derive(Clone)]
pub struct EnrollAttrs {
device_display_name: String,
device_type: String,
Expand Down
46 changes: 46 additions & 0 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
*/

use serde::{Deserialize, Serialize};
use std::convert::From;

pub const INVALID_CRED: u32 = 0xC3CE;
pub const REQUIRES_MFA: u32 = 0xC39C;
Expand Down Expand Up @@ -67,3 +68,48 @@ pub enum MsalError {
/// Continuing polling for an MFA auth
MFAPollContinue,
}

#[repr(C)]
#[allow(non_camel_case_types)]
pub enum MSAL_ERROR {
INVALID_JSON,
INVALID_BASE64,
INVALID_REGEX,
INVALID_PARSE,
ACQUIRE_TOKEN_FAILED,
GENERAL_FAILURE,
REQUEST_FAILED,
AUTH_TYPE_UNSUPPORTED,
TPM_FAIL,
URL_FORMAT_FAILED,
DEVICE_ENROLLMENT_FAIL,
CRYPTO_FAIL,
NOT_IMPLEMENTED,
CONFIG_ERROR,
MFA_POLL_CONTINUE,
SUCCESS,
INVALID_POINTER,
NO_MEMORY,
}

impl From<MsalError> for MSAL_ERROR {
fn from(error: MsalError) -> Self {
match error {
MsalError::InvalidJson(_) => MSAL_ERROR::INVALID_JSON,
MsalError::InvalidBase64(_) => MSAL_ERROR::INVALID_BASE64,
MsalError::InvalidRegex(_) => MSAL_ERROR::INVALID_REGEX,
MsalError::InvalidParse(_) => MSAL_ERROR::INVALID_PARSE,
MsalError::AcquireTokenFailed(_) => MSAL_ERROR::ACQUIRE_TOKEN_FAILED,
MsalError::GeneralFailure(_) => MSAL_ERROR::GENERAL_FAILURE,
MsalError::RequestFailed(_) => MSAL_ERROR::REQUEST_FAILED,
MsalError::AuthTypeUnsupported => MSAL_ERROR::AUTH_TYPE_UNSUPPORTED,
MsalError::TPMFail(_) => MSAL_ERROR::TPM_FAIL,
MsalError::URLFormatFailed(_) => MSAL_ERROR::URL_FORMAT_FAILED,
MsalError::DeviceEnrollmentFail(_) => MSAL_ERROR::DEVICE_ENROLLMENT_FAIL,
MsalError::CryptoFail(_) => MSAL_ERROR::CRYPTO_FAIL,
MsalError::NotImplemented => MSAL_ERROR::NOT_IMPLEMENTED,
MsalError::ConfigError(_) => MSAL_ERROR::CONFIG_ERROR,
MsalError::MFAPollContinue => MSAL_ERROR::MFA_POLL_CONTINUE,
}
}
}
Loading

0 comments on commit ca5bfd1

Please sign in to comment.