diff --git a/examples/cpp/keymanagement.cpp b/examples/cpp/keymanagement.cpp new file mode 100644 index 0000000..8164db7 --- /dev/null +++ b/examples/cpp/keymanagement.cpp @@ -0,0 +1,118 @@ +/** + * libzt API example + * + * Demonstrates how to manage ZeroTier node identities (public/secret keypairs) without + * local storage. In this mode you are responsible for saving keys. + */ + +#include +#include +#include + +#include "ZeroTierSockets.h" + +struct Node +{ + Node() : online(false), joinedAtLeastOneNetwork(false), id(0) {} + bool online; + bool joinedAtLeastOneNetwork; + uint64_t id; + // etc +} myNode; + +/* Callback handler, you should return control from this function as quickly as you can +to ensure timely receipt of future events. You should not call libzt API functions from +this function unless it's something trivial like zts_inet_ntop() or similar that has +no state-change implications. */ +void on_zts_event(void *msgPtr) +{ + struct zts_callback_msg *msg = (struct zts_callback_msg *)msgPtr; + + if (msg->eventCode == ZTS_EVENT_NODE_ONLINE) { + printf("ZTS_EVENT_NODE_ONLINE --- This node's ID is %llx\n", msg->node->address); + myNode.id = msg->node->address; + myNode.online = true; + } + if (msg->eventCode == ZTS_EVENT_NODE_OFFLINE) { + printf("ZTS_EVENT_NODE_OFFLINE --- Check your physical Internet connection, router, firewall, etc. What ports are you blocking?\n"); + myNode.online = false; + } + if (msg->eventCode == ZTS_EVENT_NETWORK_READY_IP6) { + printf("ZTS_EVENT_NETWORK_READY_IP6 --- Network config received. IPv6 traffic can now be sent over network %llx\n", + msg->network->nwid); + myNode.joinedAtLeastOneNetwork = true; + } +} + +#define KEY_BUF_LEN 2048 + +int main(int argc, char **argv) +{ + if (argc != 3) { + printf("\nlibzt example\n"); + printf("earthtest \n"); + exit(0); + } + int ztServicePort = atoi(argv[2]); // Port ZT uses to send encrypted UDP packets to peers (try something like 9994) + int err = ZTS_ERR_OK; + + + // BEGIN key handling + + + // Do not allow ZT to write anything to disk + zts_disable_local_storage(1); + + // Buffer used to store identity keypair (if someone can read this, they can impersonate your node!) + char keypair[KEY_BUF_LEN]; + memset(keypair, 0, KEY_BUF_LEN); + + printf("\n\nGenerating new identity...\n"); + uint16_t keypair_len = KEY_BUF_LEN; + zts_generate_orphan_identity(keypair, &keypair_len); + printf("keypair(len=%d) = [%s]\n", keypair_len, keypair); + + // Verification is not necessary, but could be useful after reading identities from + // your custom data store. + printf("\n\nVerifying ident...\n"); + if (zts_verify_identity(keypair)) { + printf("\tIdentity is valid\n"); + } else { + printf("\tIdentity is invalid\n"); + } + + printf("\n\nStarting node with generated identity...\n"); + zts_start_with_identity(keypair, keypair_len, &on_zts_event, ztServicePort); + + printf("\n\nWaiting for node to come online...\n"); + while (!myNode.online) { zts_delay_ms(50); } + + printf("\n\nAs a test, copy node's identity keypair back into buffer...\n"); + memset(keypair, 0, KEY_BUF_LEN); + keypair_len = KEY_BUF_LEN; + zts_get_node_identity(keypair, &keypair_len); + printf("keypair(len=%d) = [%s]\n", keypair_len, keypair); + + + // END key handling + + + uint64_t nwid = 0x8056c2e21c000001; + + if((err = zts_join(nwid)) != ZTS_ERR_OK) { + printf("Unable to join network, error = %d. Exiting.\n", err); + exit(1); + } + printf("Joining network %llx\n", nwid); + while (!myNode.joinedAtLeastOneNetwork) { zts_delay_ms(50); } + + // Idle and just show callback events, stack statistics, etc + + printf("Node will now idle...\n"); + while (true) { zts_delay_ms(1000); } + + // Shut down service and stack threads + + zts_stop(); + return 0; +} diff --git a/include/ZeroTierSockets.h b/include/ZeroTierSockets.h index 95e9b93..fd2e996 100644 --- a/include/ZeroTierSockets.h +++ b/include/ZeroTierSockets.h @@ -1,10 +1,10 @@ /* - * Copyright (c)2013-2020 ZeroTier, Inc. + * Copyright (c)2013-2021 ZeroTier, Inc. * * Use of this software is governed by the Business Source License included * in the LICENSE.TXT file in the project's root directory. * - * Change Date: 2024-01-01 + * Change Date: 2025-01-01 * * On the date above, in accordance with the Business Source License, use * of this software will be governed by version 2.0 of the Apache License. @@ -840,6 +840,201 @@ struct zts_peer_list #define ZTCALL #endif +////////////////////////////////////////////////////////////////////////////// +// Central API // +////////////////////////////////////////////////////////////////////////////// + +#ifndef NO_CENTRAL_API + +#define CENTRAL_API_DEFAULT_URL "https://my.zerotier.com" +#define CENRTAL_API_MAX_URL_LEN 128 +#define CENTRAL_API_TOKEN_LEN 32 +#define CENTRAL_API_RESP_BUF_DEFAULT_SZ (128*1024) + +#define HTTP_GET 0 +#define HTTP_POST 1 +#define HTTP_DELETE 2 + +#define ZTS_CENTRAL_NODE_AUTH_FALSE 0 +#define ZTS_CENTRAL_NODE_AUTH_TRUE 1 + +#define ZTS_CENTRAL_READ 1 +#define ZTS_CENTRAL_WRITE 2 + +/** + * @brief Enables read/write capability. Default before calling this is + * read-only (ZTS_CENTRAL_READ.) + * + * @param modes Whether the API allows read, write, or both + */ +ZTS_API void ZTCALL zts_central_api_set_access(int8_t modes); + +/** + * @brief Enables or disables libcurl verbosity + * + * @param is_verbose Whether debug information is desired + */ +ZTS_API void ZTCALL zts_central_api_set_verbose(int8_t is_verbose); + +ZTS_API void ZTCALL zts_central_api_clear_response_buffer(); + +/** + * @brief Set the Central API URL and user API token. + * + * @param url_str The URL to the Central API server + * @param token_str User API token + * @param response_buffer Destination buffer for raw JSON output + * @param buffer_len Size of buffer for server response (specify 0 for default size) + * @return ZTS_ERR_OK on success. ZTS_ERR_ARG if invalid arguments provided. + */ +ZTS_API int ZTCALL zts_central_api_init(const char *url_str, const char *token_str, char *response_buffer, uint32_t buffer_len); + +ZTS_API void ZTCALL zts_central_api_cleanup(); + +/** + * @brief Copies the JSON-formatted string buffer from the last request into a user-provided buffer. + * + * @param dest_buffer User-provided destination buffer + * @param dest_buffer_len Length of aforementioned buffer + * @return ZTS_ERR_OK if all contents were copied successfully. ZTS_ERR_ARG if provided buffer was too small. + */ +ZTS_API int ZTCALL zts_get_last_response_buffer(char *dest_buffer, int dest_buffer_len); + +/** + * @brief Get the status of the Central API server. + * + * @return Standard HTTP response codes. + */ +ZTS_API int ZTCALL zts_central_api_get_status(int *http_response_code); + +/** + * @brief Get the currently authenticated user’s user record. + * + * @return Standard HTTP response codes. + */ +ZTS_API int ZTCALL zts_central_api_get_self(int *http_response_code); + +/** + * @brief Retrieve a Network. + * + * @return Standard HTTP response codes. + */ +ZTS_API int ZTCALL zts_central_api_get_network(int *http_response_code, int64_t nwid); + +/** + * @brief Update or create a Network. + * + * Only fields marked as [rw] can be directly modified. If other fields are + * present in the posted request they are ignored. New networks can be created by POSTing + * to /api/network with no networkId parameter. The server will create a random unused + * network ID and return the new network record. + * + * @return Standard HTTP response codes. + */ +ZTS_API int ZTCALL zts_central_api_update_network(int *http_response_code, int64_t nwid); + +/** + * @brief Delete a Network. + * + * Delete a network and all its related information permanently. + * Use extreme caution as this cannot be undone! + * + * @return Standard HTTP response codes. + */ +ZTS_API int ZTCALL zts_central_api_delete_network(int *http_response_code, int64_t nwid); + +/** + * @brief Get All Viewable Networks. + * + * Get all networks for which you have at least read access. + * + * @return Standard HTTP response codes. + */ +ZTS_API int ZTCALL zts_central_api_get_networks(int *http_response_code); +/** + * @brief Retrieve a Member. + * + * @return Standard HTTP response codes. + */ +ZTS_API int ZTCALL zts_central_api_get_member(int *http_response_code, int64_t nwid, int64_t nodeid); + +/** + * @brief Update or add a Member. + * + * New members can be added to a network by POSTing them. + * + * @return Standard HTTP response codes. + */ +ZTS_API int ZTCALL zts_central_api_update_member(int *http_response_code, int64_t nwid, int64_t nodeid, char *post_data); + +/** + * @brief Authorize or (De)authorize a node on a network. This operation is idempotent. + * + * @param nwid The network ID + * @param nodeid The node ID + * @param is_authed Boolean value for whether this node should be authorized + * @return Standard HTTP response codes. ZTS_ERR_ARG invalid argument specified. + */ +ZTS_API int ZTCALL zts_set_node_auth(int *http_response_code, int64_t nwid, int64_t nodeid, int8_t is_authed); + +/** + * @brief Get All Members of a Network. + * + * Get all members of a network for which you have at least read access. + * + * @return Standard HTTP response codes. + */ +ZTS_API int ZTCALL zts_central_api_get_members_of_network(int *http_response_code, int64_t nwid); + +#endif // NO_CENTRAL_API + +////////////////////////////////////////////////////////////////////////////// +// Identity Management // +////////////////////////////////////////////////////////////////////////////// + +/** + * @brief Generates a node identity (public/secret keypair) and stores it in a user-provided buffer. + * + * @param key_pair_str User-provided destination buffer + * @param key_buf_len Length of user-provided destination buffer. Will be set to number of bytes copied. + * @return ZTS_ERR_OK on success. ZTS_ERR_SERVICE on failure. + */ +ZTS_API int ZTCALL zts_generate_orphan_identity(char *key_pair_str, uint16_t *key_buf_len); + +/** + * @brief Verifies that a keypair is valid for use. + * + * @param key_pair_str Buffer containing keypair + * @return ZTS_ERR_OK on success. ZTS_ERR_SERVICE on failure. + */ +ZTS_API int ZTCALL zts_verify_identity(const char *key_pair_str); + +/** + * @brief Copies the current node's identity into a buffer + * + * @param key_pair_str User-provided destination buffer + * @param key_buf_len Length of user-provided destination buffer. Will be set to number of bytes copied. + * @return ZTS_ERR_OK on success. ZTS_ERR_SERVICE on failure. + */ +ZTS_API int ZTCALL zts_get_node_identity(char *key_pair_str, uint16_t *key_buf_len); + +/** + * @brief Starts the ZeroTier service and notifies user application of events via callback. This + * variant will assign a user-provided identity to the node. + * + * @param path path directory where configuration files are stored + * @param callback User-specified callback for ZTS_EVENT_* events + * @param port Port that the library should use for talking to other ZeroTier nodes + * @return ZTS_ERR_OK on success. ZTS_ERR_SERVICE or ZTS_ERR_ARG on failure + */ +#ifdef ZTS_PINVOKE + ZTS_API int ZTCALL zts_start_with_identity(const char *key_pair_str, uint16_t key_buf_len, + CppCallback callback, uint16_t port); +#else + ZTS_API int ZTCALL zts_start_with_identity(const char *key_pair_str, uint16_t key_buf_len, + void (*callback)(void *), uint16_t port); +#endif + /** * @brief Enable or disable whether the service will cache network details (enabled by default) * @@ -882,14 +1077,24 @@ ZTS_API int ZTCALL zts_allow_peer_caching(uint8_t allowed); */ ZTS_API int ZTCALL zts_allow_local_conf(uint8_t allowed); +/** + * @brief Enable or disable whether the service will read or write config data to local storage + * + * @usage Should be called before zts_start() if you intend on changing its state. + * + * @param enabled Whether or not this feature is enabled + * @return ZTS_ERR_OK on success. ZTS_ERR_SERVICE on failure. + */ +ZTS_API int ZTCALL zts_disable_local_storage(uint8_t disabled); + /** * @brief Starts the ZeroTier service and notifies user application of events via callback * * @param path path directory where configuration files are stored * @param callback User-specified callback for ZTS_EVENT_* events + * @param port Port that the library should use for talking to other ZeroTier nodes * @return ZTS_ERR_OK on success. ZTS_ERR_SERVICE or ZTS_ERR_ARG on failure */ - #ifdef ZTS_PINVOKE // Used by P/INVOKE wrappers typedef void (*CppCallback)(void *msg); diff --git a/src/Controls.cpp b/src/Controls.cpp index 808fb7a..00a9f9c 100644 --- a/src/Controls.cpp +++ b/src/Controls.cpp @@ -1,10 +1,10 @@ /* - * Copyright (c)2013-2020 ZeroTier, Inc. + * Copyright (c)2013-2021 ZeroTier, Inc. * * Use of this software is governed by the Business Source License included * in the LICENSE.TXT file in the project's root directory. * - * Change Date: 2024-01-01 + * Change Date: 2025-01-01 * * On the date above, in accordance with the Business Source License, use * of this software will be governed by version 2.0 of the Apache License. @@ -14,7 +14,7 @@ /** * @file * - * Network control interface + * Node / Network control interface */ #include @@ -50,6 +50,7 @@ namespace ZeroTier extern uint8_t allowNetworkCaching; extern uint8_t allowPeerCaching; extern uint8_t allowLocalConf; + extern uint8_t disableLocalStorage; // Off by default #ifdef SDK_JNI // References to JNI objects and VM kept for future callbacks @@ -63,6 +64,134 @@ namespace ZeroTier extern "C" { #endif +int zts_generate_orphan_identity(char *key_pair_str, uint16_t *key_buf_len) +{ + if (*key_buf_len < ZT_IDENTITY_STRING_BUFFER_LENGTH || key_pair_str == NULL) { + return ZTS_ERR_ARG; + } + Identity id; + id.generate(); + char idtmp[1024]; + std::string idser = id.toString(true,idtmp); + uint16_t key_pair_len = idser.length(); + if (key_pair_len > *key_buf_len) { + return ZTS_ERR_ARG; + } + memcpy(key_pair_str, idser.c_str(), key_pair_len); + *key_buf_len = key_pair_len; + return ZTS_ERR_OK; +} + +int zts_verify_identity(const char *key_pair_str) +{ + if (key_pair_str == NULL || strlen(key_pair_str) > ZT_IDENTITY_STRING_BUFFER_LENGTH) { + return false; + } + Identity id; + if ((strlen(key_pair_str) > 32) && (key_pair_str[10] == ':')) { + if (id.fromString(key_pair_str)) { + return true; + } + } + return false; +} + +int zts_get_node_identity(char *key_pair_str, uint16_t *key_buf_len) +{ + Mutex::Lock _l(serviceLock); + if (*key_buf_len == 0 || key_pair_str == NULL) { + return ZTS_ERR_ARG; + } + if (!service) { + return ZTS_ERR_SERVICE; + } + service->getIdentity(key_pair_str, key_buf_len); + return *key_buf_len > 0 ? ZTS_ERR_OK : ZTS_ERR_GENERAL; +} + +// TODO: This logic should be further generalized in the next API redesign +#ifdef ZTS_PINVOKE +int zts_start_with_identity(const char *key_pair_str, uint16_t key_buf_len, + CppCallback callback, uint16_t port) +#else +int zts_start_with_identity(const char *key_pair_str, uint16_t key_buf_len, + void (*callback)(void *), uint16_t port) +#endif +{ + if (!zts_verify_identity(key_pair_str)) { + return ZTS_ERR_ARG; + } + Mutex::Lock _l(serviceLock); + _lwip_driver_init(); + if (service || _getState(ZTS_STATE_NODE_RUNNING)) { + // Service is already initialized + return ZTS_ERR_SERVICE; + } + if (_getState(ZTS_STATE_FREE_CALLED)) { + // Stack (presumably lwIP) has been dismantled, + // an application restart is required now + return ZTS_ERR_SERVICE; + } + if (port < 0 || port > 0xFFFF) { + return ZTS_ERR_ARG; + } + serviceParameters *params = new serviceParameters(); + params->port = port; + params->path = ""; + + Identity id; + if ((strlen(key_pair_str) > 32) && (key_pair_str[10] == ':')) { + if (id.fromString(key_pair_str)) { + id.toString(false, params->publicIdentityStr); + id.toString(true, params->secretIdentityStr); + } + } + if (!id) { + return ZTS_ERR_ARG; + } + +#ifdef SDK_JNI + _userEventCallbackFunc = callback; +#else + _userEventCallbackFunc = callback; +#endif + if (!_isCallbackRegistered()) { + // Must have a callback + return ZTS_ERR_ARG; + } + int err; + int retval = ZTS_ERR_OK; + + _setState(ZTS_STATE_CALLBACKS_RUNNING); + _setState(ZTS_STATE_NODE_RUNNING); + // Start the ZT service thread +#if defined(__WINDOWS__) + WSAStartup(MAKEWORD(2, 2), &wsaData); + HANDLE serviceThread = CreateThread(NULL, 0, _runNodeService, (void*)params, 0, NULL); + HANDLE callbackThread = CreateThread(NULL, 0, _runCallbacks, NULL, 0, NULL); +#else + pthread_t service_thread; + pthread_t callback_thread; + if ((err = pthread_create(&service_thread, NULL, _runNodeService, (void*)params)) != 0) { + retval = err; + } + if ((err = pthread_create(&callback_thread, NULL, _runCallbacks, NULL)) != 0) { + retval = err; + } +#endif +#if defined(__linux__) + pthread_setname_np(service_thread, ZTS_SERVICE_THREAD_NAME); + pthread_setname_np(callback_thread, ZTS_EVENT_CALLBACK_THREAD_NAME); +#endif + if (retval != ZTS_ERR_OK) { + _clrState(ZTS_STATE_CALLBACKS_RUNNING); + _clrState(ZTS_STATE_NODE_RUNNING); + _clearRegisteredCallback(); + //delete params; + } + return retval; +} + int zts_allow_network_caching(uint8_t allowed = 1) { Mutex::Lock _l(serviceLock); @@ -93,6 +222,16 @@ int zts_allow_local_conf(uint8_t allowed = 1) return ZTS_ERR_SERVICE; } +int zts_disable_local_storage(uint8_t disabled) +{ + Mutex::Lock _l(serviceLock); + if(!service) { + disableLocalStorage = disabled; + return ZTS_ERR_OK; + } + return ZTS_ERR_SERVICE; +} + #ifdef ZTS_PINVOKE int zts_start(const char *path, CppCallback callback, uint16_t port) #else diff --git a/src/NodeService.cpp b/src/NodeService.cpp index b15fbee..0522a54 100644 --- a/src/NodeService.cpp +++ b/src/NodeService.cpp @@ -1,10 +1,10 @@ /* - * Copyright (c)2013-2020 ZeroTier, Inc. + * Copyright (c)2013-2021 ZeroTier, Inc. * * Use of this software is governed by the Business Source License included * in the LICENSE.TXT file in the project's root directory. * - * Change Date: 2024-01-01 + * Change Date: 2025-01-01 * * On the date above, in accordance with the Business Source License, use * of this software will be governed by version 2.0 of the Apache License. @@ -63,6 +63,7 @@ namespace ZeroTier { uint8_t allowNetworkCaching; uint8_t allowPeerCaching; uint8_t allowLocalConf; +uint8_t disableLocalStorage; // Off by default typedef VirtualTap EthernetTap; @@ -937,6 +938,21 @@ public: _node->leave(nwid, NULL, NULL); } + inline void getIdentity(char *key_pair_str, uint16_t *key_buf_len) + { + if (key_pair_str == NULL || *key_buf_len < ZT_IDENTITY_STRING_BUFFER_LENGTH) { + return; + } + uint16_t keylen = strlen(_userProvidedSecretIdentity); + if (*key_buf_len < keylen) { + *key_buf_len = 0; + return; + } + memcpy(key_pair_str, _userProvidedSecretIdentity, keylen); + *key_buf_len = keylen; + } + + // TODO: This logic should be further generalized in the next API redesign inline void nodeStatePutFunction(enum ZT_StateObjectType type,const uint64_t id[2],const void *data,int len) { char p[1024]; @@ -947,30 +963,52 @@ public: switch(type) { case ZT_STATE_OBJECT_IDENTITY_PUBLIC: - OSUtils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "identity.public",_homePath.c_str()); + memcpy(_userProvidedPublicIdentity, data, len); + if (disableLocalStorage) { + return; + } else { + OSUtils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "identity.public",_homePath.c_str()); + } break; case ZT_STATE_OBJECT_IDENTITY_SECRET: - OSUtils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "identity.secret",_homePath.c_str()); + memcpy(_userProvidedSecretIdentity, data, len); + if (disableLocalStorage) { + return; + } else { + OSUtils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "identity.secret",_homePath.c_str()); + } secure = true; break; case ZT_STATE_OBJECT_PLANET: - OSUtils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "planet",_homePath.c_str()); + if (disableLocalStorage) { + return; + } else { + OSUtils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "planet",_homePath.c_str()); + } break; case ZT_STATE_OBJECT_NETWORK_CONFIG: - if (allowNetworkCaching) { - OSUtils::ztsnprintf(dirname,sizeof(dirname),"%s" ZT_PATH_SEPARATOR_S "networks.d",_homePath.c_str()); - OSUtils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "%.16llx.conf",dirname,(unsigned long long)id[0]); - secure = true; - } else { + if (disableLocalStorage) { return; + } else { + if (allowNetworkCaching) { + OSUtils::ztsnprintf(dirname,sizeof(dirname),"%s" ZT_PATH_SEPARATOR_S "networks.d",_homePath.c_str()); + OSUtils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "%.16llx.conf",dirname,(unsigned long long)id[0]); + secure = true; + } else { + return; + } } break; case ZT_STATE_OBJECT_PEER: - if (allowPeerCaching) { - OSUtils::ztsnprintf(dirname,sizeof(dirname),"%s" ZT_PATH_SEPARATOR_S "peers.d",_homePath.c_str()); - OSUtils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "%.10llx.peer",dirname,(unsigned long long)id[0]); + if (disableLocalStorage) { + return; } else { - return; // Do nothing + if (allowPeerCaching) { + OSUtils::ztsnprintf(dirname,sizeof(dirname),"%s" ZT_PATH_SEPARATOR_S "peers.d",_homePath.c_str()); + OSUtils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "%.10llx.peer",dirname,(unsigned long long)id[0]); + } else { + return; // Do nothing + } } break; default: @@ -1009,25 +1047,57 @@ public: } } + // TODO: This logic should be further generalized in the next API redesign inline int nodeStateGetFunction(enum ZT_StateObjectType type,const uint64_t id[2],void *data,unsigned int maxlen) { char p[4096]; + int keylen = 0; switch(type) { case ZT_STATE_OBJECT_IDENTITY_PUBLIC: - OSUtils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "identity.public",_homePath.c_str()); + if (disableLocalStorage) { + keylen = strlen(_userProvidedPublicIdentity); + if (keylen > maxlen) { + return -1; + } + if (keylen > 0) { + memcpy(data, _userProvidedPublicIdentity, keylen); + return keylen; + } + } else { + OSUtils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "identity.public",_homePath.c_str()); + } break; case ZT_STATE_OBJECT_IDENTITY_SECRET: - OSUtils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "identity.secret",_homePath.c_str()); + if (disableLocalStorage) { + keylen = strlen(_userProvidedSecretIdentity); + if (keylen > maxlen) { + return -1; + } + if (keylen > 0) { + memcpy(data, _userProvidedSecretIdentity, keylen); + return keylen; + } + } else { + OSUtils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "identity.secret",_homePath.c_str()); + } break; case ZT_STATE_OBJECT_PLANET: - OSUtils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "planet",_homePath.c_str()); + if (disableLocalStorage) { + return -1; + } else { + OSUtils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "planet",_homePath.c_str()); + } break; case ZT_STATE_OBJECT_NETWORK_CONFIG: - if (allowNetworkCaching) { - OSUtils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "networks.d" ZT_PATH_SEPARATOR_S "%.16llx.conf",_homePath.c_str(),(unsigned long long)id[0]); - } - else { + if (disableLocalStorage) { return -1; + } else { + if (allowNetworkCaching) { + OSUtils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "networks.d" ZT_PATH_SEPARATOR_S "%.16llx.conf",_homePath.c_str(),(unsigned long long)id[0]); + } + else { + return -1; + } } break; case ZT_STATE_OBJECT_PEER: @@ -1312,6 +1382,11 @@ void *_runNodeService(void *arg) service = NodeService::newInstance(params->path.c_str(),params->port); service->_userProvidedPort = params->port; service->_userProvidedPath = params->path; + if (strlen(params->publicIdentityStr) > 0 && strlen(params->secretIdentityStr) > 0 && params->path.length() == 0) { + memcpy(service->_userProvidedPublicIdentity, params->publicIdentityStr, strlen(params->publicIdentityStr)); + memcpy(service->_userProvidedSecretIdentity, params->secretIdentityStr, strlen(params->secretIdentityStr)); + } + serviceLock.unlock(); switch(service->run()) { case NodeService::ONE_STILL_RUNNING: diff --git a/src/NodeService.hpp b/src/NodeService.hpp index 6eb9bf9..813567c 100644 --- a/src/NodeService.hpp +++ b/src/NodeService.hpp @@ -1,10 +1,10 @@ /* - * Copyright (c)2013-2020 ZeroTier, Inc. + * Copyright (c)2013-2021 ZeroTier, Inc. * * Use of this software is governed by the Business Source License included * in the LICENSE.TXT file in the project's root directory. * - * Change Date: 2024-01-01 + * Change Date: 2025-01-01 * * On the date above, in accordance with the Business Source License, use * of this software will be governed by version 2.0 of the Apache License. @@ -54,6 +54,8 @@ public: uint16_t _userProvidedPort; std::string _userProvidedPath; + char _userProvidedPublicIdentity[ZT_IDENTITY_STRING_BUFFER_LENGTH]; + char _userProvidedSecretIdentity[ZT_IDENTITY_STRING_BUFFER_LENGTH]; /** * Returned by node main if/when it terminates @@ -171,6 +173,7 @@ public: virtual void join(uint64_t nwid) = 0; virtual void leave(uint64_t nwid) = 0; + virtual void getIdentity(char *key_pair_str, uint16_t *key_buf_len) = 0; /** * Terminate background service (can be called from other threads) @@ -203,6 +206,8 @@ struct serviceParameters { int port; std::string path; + char publicIdentityStr[ZT_IDENTITY_STRING_BUFFER_LENGTH]; + char secretIdentityStr[ZT_IDENTITY_STRING_BUFFER_LENGTH]; }; #ifdef __WINDOWS__