Skip to content

Commit

Permalink
Checkout enterprise license in rust headless mode
Browse files Browse the repository at this point in the history
  • Loading branch information
emesare committed Oct 2, 2024
1 parent 7e8d66a commit 855dd63
Show file tree
Hide file tree
Showing 2 changed files with 81 additions and 0 deletions.
66 changes: 66 additions & 0 deletions rust/src/enterprise.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,68 @@ use std::time::{Duration, SystemTime, UNIX_EPOCH};
use crate::rc::Array;
use crate::string::{BnStrCompatible, BnString};


#[derive(Debug)]
pub struct EnterpriseCheckoutError(pub String);

impl std::fmt::Display for EnterpriseCheckoutError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.0)
}
}

impl std::error::Error for EnterpriseCheckoutError {}

pub fn checkout_license(duration: Duration) -> Result<(), EnterpriseCheckoutError> {
if crate::is_ui_enabled() {
return Ok(());
}

if !is_server_initialized() {
if !initialize_server() && is_server_floating_license() {
return Err(EnterpriseCheckoutError(server_last_error().to_string()));
}
}

if is_server_floating_license() {
if !is_server_connected() && !connect_server() {
return Err(EnterpriseCheckoutError(server_last_error().to_string()));
}

if !is_server_authenticated() {
if !authenticate_server_with_method("Keychain", false) {
let Some(username) = std::env::var("BN_ENTERPRISE_USERNAME").ok() else {
return Err(EnterpriseCheckoutError("BN_ENTERPRISE_USERNAME not set when attempting to authenticate with credentials".to_string()));
};
let Some(password) = std::env::var("BN_ENTERPRISE_PASSWORD").ok() else {
return Err(EnterpriseCheckoutError("BN_ENTERPRISE_PASSWORD not set when attempting to authenticate with credentials".to_string()));
};
if !authenticate_server_with_credentials(username, password, true) {
let failed_message = "Could not checkout a license: Not authenticated. Try one of the following: \n \
- Log in and check out a license for an extended time\n \
- Set BN_ENTERPRISE_USERNAME and BN_ENTERPRISE_PASSWORD environment variables\n \
- Use binaryninja::enterprise::{authenticate_server_with_method OR authenticate_server_with_credentials} in your code";
return Err(EnterpriseCheckoutError(failed_message.to_string()));
}
}
}
}

if !is_server_license_still_activated() || (!is_server_floating_license() && crate::license_expiration_time() < SystemTime::now()) {
if !update_server_license(duration) {
return Err(EnterpriseCheckoutError("Failed to refresh expired license".to_string()));
}
}

Ok(())
}

pub fn release_license() {
if !crate::is_ui_enabled() {
release_server_license();
}
}

pub fn server_username() -> BnString {
unsafe { BnString::from_raw(binaryninjacore_sys::BNGetEnterpriseServerUsername()) }
}
Expand Down Expand Up @@ -125,6 +187,10 @@ pub fn is_server_initialized() -> bool {
unsafe { binaryninjacore_sys::BNIsEnterpriseServerInitialized() }
}

pub fn initialize_server() -> bool {
unsafe { binaryninjacore_sys::BNInitializeEnterpriseServer() }
}

pub fn server_last_error() -> BnString {
unsafe { BnString::from_raw(binaryninjacore_sys::BNGetEnterpriseServerLastError()) }
}
Expand Down
15 changes: 15 additions & 0 deletions rust/src/headless.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ use crate::{

use std::env;
use std::path::PathBuf;
use std::time::Duration;

#[cfg(not(target_os = "windows"))]
fn binja_path() -> PathBuf {
Expand Down Expand Up @@ -82,6 +83,13 @@ use binaryninjacore_sys::{BNInitPlugins, BNInitRepoPlugins, BNSetBundledPluginDi
///
/// You can instead call this through [`Session`] or [`script_helper`]
pub fn init() {
match crate::product().as_str() {
"Binary Ninja Enterprise Client" | "Binary Ninja Ultimate" => {
crate::enterprise::checkout_license(Duration::from_secs(900)).expect("Failed to checkout license");
},
_ => {}
}

unsafe {
let path = binja_path().join("plugins").into_os_string();
let path = path.into_string().unwrap();
Expand All @@ -96,6 +104,13 @@ pub fn init() {
///
/// ⚠️ Important! Must be called at the end of scripts. ⚠️
pub fn shutdown() {
match crate::product().as_str() {
"Binary Ninja Enterprise Client" | "Binary Ninja Ultimate" => {
crate::enterprise::release_license()
},
_ => {}
}

unsafe { binaryninjacore_sys::BNShutdown() };
}

Expand Down

0 comments on commit 855dd63

Please sign in to comment.