summaryrefslogtreecommitdiff
path: root/python/enterprise.py
diff options
context:
space:
mode:
authorGlenn Smith <glenn@vector35.com>2021-08-23 19:05:09 -0400
committerGlenn Smith <glenn@vector35.com>2021-11-18 21:37:52 -0500
commit994a42659dc500f602e83f91501ec4a959481fa5 (patch)
treeca783900c9a6d41dbdd98a1cd66a083d3e886578 /python/enterprise.py
parent60f2ecd9d1961f7cd700e01f802bcf640c9d50e0 (diff)
Enterprise apis and support
Also secrets provider + openUrl
Diffstat (limited to 'python/enterprise.py')
-rw-r--r--python/enterprise.py189
1 files changed, 189 insertions, 0 deletions
diff --git a/python/enterprise.py b/python/enterprise.py
new file mode 100644
index 00000000..8eadb06c
--- /dev/null
+++ b/python/enterprise.py
@@ -0,0 +1,189 @@
+import ctypes
+from typing import Tuple, List, Optional
+
+import binaryninja._binaryninjacore as core
+import binaryninja
+
+if core.BNGetProduct() != "Binary Ninja Enterprise Client":
+ # None of these functions exist on other builds, so just raise here to notify anyone who tries to use this
+ raise RuntimeError("Cannot use Binary Ninja Enterprise client functionality with a non-Enterprise client.")
+
+
+def connect():
+ """
+ Connect to the Enterprise Server.
+ """
+ if not core.BNConnectEnterpriseServer():
+ raise RuntimeError(last_error())
+
+def is_connected() -> bool:
+ """
+ Determine if the Enterprise Server is currently connected.
+ :return: True if connected
+ """
+ return core.BNIsEnterpriseServerConnected()
+
+def authenticate_with_credentials(username: str, password: str):
+ """
+ Authenticate to the Enterprise Server with username/password credentials.
+ :param str username: Username to use.
+ :param str password: Password to use.
+ """
+ if not core.BNAuthenticateEnterpriseServerWithCredentials(username, password):
+ raise RuntimeError(last_error())
+
+def authenticate_with_method(method: str):
+ """
+ Authenticate to the Enterprise Server with a non-password method. Note that many of these will
+ open a URL for a browser-based login prompt, which may not be usable on headless installations.
+ See :func:`authentication_methods` for a list of accepted methods.
+ :param str method: Name of method to use.
+ """
+ if not core.BNAuthenticateEnterpriseServerWithMethod(method):
+ raise RuntimeError(last_error())
+
+def authentication_methods() -> List[Tuple[str, str]]:
+ """
+ Get a list of authentication methods accepted by the Enterprise Server.
+ :return: List of (<method name>, <method display name>) tuples
+ """
+ methods = ctypes.POINTER(ctypes.c_char_p)()
+ names = ctypes.POINTER(ctypes.c_char_p)()
+ count = core.BNGetEnterpriseServerAuthenticationMethods(methods, names)
+ results = []
+ for i in range(count):
+ results.append((core.pyNativeStr(methods[i]), core.pyNativeStr(names[i])))
+ core.BNFreeStringList(methods, count)
+ core.BNFreeStringList(names, count)
+ return results
+
+def deauthenticate():
+ """
+ Deauthenticate from the Enterprise server, clearing any cached credentials.
+ """
+ if not core.BNDeauthenticateEnterpriseServer():
+ raise RuntimeError(last_error())
+
+def cancel_authentication():
+ """
+ Cancel a call to :func:`authenticate_with_credentials` or :func:`authenticate_with_method`.
+ Note those functions are blocking, so this must be called on a separate thread.
+ """
+ core.BNCancelEnterpriseServerAuthentication()
+
+def is_authenticated() -> bool:
+ """
+ Determine if you have authenticated to the Enterprise Server.
+ :return: True if you are authenticated
+ """
+ return core.BNIsEnterpriseServerAuthenticated()
+
+def username() -> Optional[None]:
+ """
+ Get the username of the currently authenticated user to the Enterprise Server.
+ :return: Username, if authenticated. None, otherwise.
+ """
+ return core.BNGetEnterpriseServerUsername()
+
+def reservation_time_limit() -> int:
+ """
+ Get the maximum checkout duration allowed by the Enterprise Server.
+ .. note:: You must authenticate with the Enterprise Server before calling this.
+
+ :return: Duration, in seconds, of the maximum time you are allowed to checkout a license.
+ """
+ return core.BNGetEnterpriseServerReservationTimeLimit()
+
+def acquire_license(duration, cache=False):
+ """
+ Check out and activate a license from the Enterprise Server.
+ If ``cache`` is True, the checkout will be saved to a local secrets storage. This is platform-dependent:
+ - macOS: Saved to the user's keychain
+ - Windows: Saved to the credential store
+ - Linux: Saved with dbus's Secret Service API
+
+ .. note:: You must authenticate with the Enterprise Server before calling this.
+
+ .. warning:: If ``cache`` is False, you must remember to call :func:`release_license` before the process
+ exits to release the uncached license back to the server. If you forget to do so, you will
+ have to either wait for the checkout to expire or have an administrator revoke the checkout.
+
+ :param int duration: Desired length of license checkout, in seconds.
+ :param bool cache: If true, the license will be saved to a local secrets storage.
+ """
+ if not core.BNAcquireEnterpriseServerLicense(duration, cache):
+ raise RuntimeError(last_error())
+
+def release_license():
+ """
+ Release the currently checked out license back to the Enterprise Server.
+
+ .. note:: You must authenticate with the Enterprise Server before calling this.
+
+ .. note:: This will deactivate the Binary Ninja Enterprise client. You must call :func:`acquire_license`
+ again to continue using Binary Ninja Enterprise in the current process.
+ """
+ if not core.BNReleaseEnterpriseServerLicense():
+ raise RuntimeError(last_error())
+
+def license_expiration_time() -> int:
+ """
+ Get the expiry time of the current license checkout.
+ :return: Expiry time as a Unix epoch, or 0 if no license is checked out.
+ """
+ return core.BNGetEnterpriseServerLicenseExpirationTime()
+
+def license_duration() -> int:
+ """
+ Get the duration of the current license checkout.
+ :return: Duration, in seconds, of the total time of the current checkout.
+ """
+ return core.BNGetEnterpriseServerLicenseDuration()
+
+def is_license_still_activated() -> bool:
+ """
+ Determine if your current license checkout is still valid.
+ :return: True if your current checkout is still valid.
+ """
+ return core.BNIsEnterpriseServerLicenseStillActivated()
+
+def last_error() -> str:
+ """
+ Get a text representation the last error encountered by the Enterprise Client
+ :return: Last error message, or empty string if there is none.
+ """
+ return core.BNGetEnterpriseServerLastError()
+
+class LicenseCheckout:
+ """
+ Helper class for scripts to make use of a license checkout in a scope.
+
+ :Example:
+ enterprise.connect()
+ enterprise.authenticate_with_credentials("username", "password")
+ with enterprise.LicenseCheckout():
+ # Do some operation
+ bv = open_view("/bin/ls") # e.g
+ # License is released at end of scope
+
+ """
+
+ def __init__(self, duration=900, cache=False):
+ self.desired_duration = duration
+ self.desired_cache = cache
+
+ def __enter__(self):
+ # UI builds have their own license manager
+ if binaryninja.core_ui_enabled():
+ return
+ if not is_connected():
+ connect()
+ if not is_authenticated():
+ raise RuntimeError("Could not checkout a license: Not authenticated. Please use binaryninja.enterprise.authenticate_with_credentials or authenticate_with_method first!")
+ acquire_license(self.desired_duration, self.desired_cache)
+
+ def __exit__(self, exc_type, exc_val, exc_tb):
+ # UI builds have their own license manager
+ if binaryninja.core_ui_enabled():
+ return
+ release_license()