Skip to content

Commit 855dd63

Browse files
committed
Checkout enterprise license in rust headless mode
1 parent 7e8d66a commit 855dd63

File tree

2 files changed

+81
-0
lines changed

2 files changed

+81
-0
lines changed

rust/src/enterprise.rs

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,68 @@ use std::time::{Duration, SystemTime, UNIX_EPOCH};
44
use crate::rc::Array;
55
use crate::string::{BnStrCompatible, BnString};
66

7+
8+
#[derive(Debug)]
9+
pub struct EnterpriseCheckoutError(pub String);
10+
11+
impl std::fmt::Display for EnterpriseCheckoutError {
12+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
13+
write!(f, "{}", self.0)
14+
}
15+
}
16+
17+
impl std::error::Error for EnterpriseCheckoutError {}
18+
19+
pub fn checkout_license(duration: Duration) -> Result<(), EnterpriseCheckoutError> {
20+
if crate::is_ui_enabled() {
21+
return Ok(());
22+
}
23+
24+
if !is_server_initialized() {
25+
if !initialize_server() && is_server_floating_license() {
26+
return Err(EnterpriseCheckoutError(server_last_error().to_string()));
27+
}
28+
}
29+
30+
if is_server_floating_license() {
31+
if !is_server_connected() && !connect_server() {
32+
return Err(EnterpriseCheckoutError(server_last_error().to_string()));
33+
}
34+
35+
if !is_server_authenticated() {
36+
if !authenticate_server_with_method("Keychain", false) {
37+
let Some(username) = std::env::var("BN_ENTERPRISE_USERNAME").ok() else {
38+
return Err(EnterpriseCheckoutError("BN_ENTERPRISE_USERNAME not set when attempting to authenticate with credentials".to_string()));
39+
};
40+
let Some(password) = std::env::var("BN_ENTERPRISE_PASSWORD").ok() else {
41+
return Err(EnterpriseCheckoutError("BN_ENTERPRISE_PASSWORD not set when attempting to authenticate with credentials".to_string()));
42+
};
43+
if !authenticate_server_with_credentials(username, password, true) {
44+
let failed_message = "Could not checkout a license: Not authenticated. Try one of the following: \n \
45+
- Log in and check out a license for an extended time\n \
46+
- Set BN_ENTERPRISE_USERNAME and BN_ENTERPRISE_PASSWORD environment variables\n \
47+
- Use binaryninja::enterprise::{authenticate_server_with_method OR authenticate_server_with_credentials} in your code";
48+
return Err(EnterpriseCheckoutError(failed_message.to_string()));
49+
}
50+
}
51+
}
52+
}
53+
54+
if !is_server_license_still_activated() || (!is_server_floating_license() && crate::license_expiration_time() < SystemTime::now()) {
55+
if !update_server_license(duration) {
56+
return Err(EnterpriseCheckoutError("Failed to refresh expired license".to_string()));
57+
}
58+
}
59+
60+
Ok(())
61+
}
62+
63+
pub fn release_license() {
64+
if !crate::is_ui_enabled() {
65+
release_server_license();
66+
}
67+
}
68+
769
pub fn server_username() -> BnString {
870
unsafe { BnString::from_raw(binaryninjacore_sys::BNGetEnterpriseServerUsername()) }
971
}
@@ -125,6 +187,10 @@ pub fn is_server_initialized() -> bool {
125187
unsafe { binaryninjacore_sys::BNIsEnterpriseServerInitialized() }
126188
}
127189

190+
pub fn initialize_server() -> bool {
191+
unsafe { binaryninjacore_sys::BNInitializeEnterpriseServer() }
192+
}
193+
128194
pub fn server_last_error() -> BnString {
129195
unsafe { BnString::from_raw(binaryninjacore_sys::BNGetEnterpriseServerLastError()) }
130196
}

rust/src/headless.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ use crate::{
2020

2121
use std::env;
2222
use std::path::PathBuf;
23+
use std::time::Duration;
2324

2425
#[cfg(not(target_os = "windows"))]
2526
fn binja_path() -> PathBuf {
@@ -82,6 +83,13 @@ use binaryninjacore_sys::{BNInitPlugins, BNInitRepoPlugins, BNSetBundledPluginDi
8283
///
8384
/// You can instead call this through [`Session`] or [`script_helper`]
8485
pub fn init() {
86+
match crate::product().as_str() {
87+
"Binary Ninja Enterprise Client" | "Binary Ninja Ultimate" => {
88+
crate::enterprise::checkout_license(Duration::from_secs(900)).expect("Failed to checkout license");
89+
},
90+
_ => {}
91+
}
92+
8593
unsafe {
8694
let path = binja_path().join("plugins").into_os_string();
8795
let path = path.into_string().unwrap();
@@ -96,6 +104,13 @@ pub fn init() {
96104
///
97105
/// ⚠️ Important! Must be called at the end of scripts. ⚠️
98106
pub fn shutdown() {
107+
match crate::product().as_str() {
108+
"Binary Ninja Enterprise Client" | "Binary Ninja Ultimate" => {
109+
crate::enterprise::release_license()
110+
},
111+
_ => {}
112+
}
113+
99114
unsafe { binaryninjacore_sys::BNShutdown() };
100115
}
101116

0 commit comments

Comments
 (0)