diff options
| author | Glenn Smith <glenn@vector35.com> | 2021-08-23 19:05:09 -0400 |
|---|---|---|
| committer | Glenn Smith <glenn@vector35.com> | 2021-11-18 21:37:52 -0500 |
| commit | 994a42659dc500f602e83f91501ec4a959481fa5 (patch) | |
| tree | ca783900c9a6d41dbdd98a1cd66a083d3e886578 /python/enterprise.py | |
| parent | 60f2ecd9d1961f7cd700e01f802bcf640c9d50e0 (diff) | |
Enterprise apis and support
Also secrets provider + openUrl
Diffstat (limited to 'python/enterprise.py')
| -rw-r--r-- | python/enterprise.py | 189 |
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() |
