diff --git a/programs/ziti-edge-tunnel/config-utils.c b/programs/ziti-edge-tunnel/config-utils.c index 97abf355..1971dbef 100644 --- a/programs/ziti-edge-tunnel/config-utils.c +++ b/programs/ziti-edge-tunnel/config-utils.c @@ -22,13 +22,19 @@ #include #endif -const char* app_data = "APPDATA"; +#if _WIN32 +#define realpath(rel, abs) _fullpath(abs, rel, FILENAME_MAX) +#endif + static char* identifier_path = NULL; -char* get_system_config_path() { +char* get_system_config_path(const char* base_dir) { + char actual_base_path[PATH_MAX]; + realpath(base_dir, actual_base_path); + char* config_path = malloc(FILENAME_MAX * sizeof(char)); #if _WIN32 - snprintf(config_path, FILENAME_MAX, "%s\\NetFoundry", getenv(app_data)); + snprintf(config_path, FILENAME_MAX, "%s%cNetFoundry", actual_base_path, PATH_SEP); #elif __linux__ snprintf(config_path, FILENAME_MAX, "/var/lib/ziti"); #else @@ -47,24 +53,3 @@ void set_identifier_path(char* id_path) { } } -char* get_config_file_name(char* config_path) { - if (config_path != NULL) { - char* config_file_name = calloc(FILENAME_MAX, sizeof(char)); - snprintf(config_file_name, FILENAME_MAX, "%s/config.json", config_path); - return config_file_name; - } else { - return "config.json"; - } - -} - -char* get_backup_config_file_name(char* config_path) { - if (config_path != NULL) { - char* bkp_config_file_name = calloc(FILENAME_MAX, sizeof(char)); - snprintf(bkp_config_file_name, FILENAME_MAX, "%s/config.json.backup", config_path); - return bkp_config_file_name; - } else { - return "config.json.backup"; - } -} - diff --git a/programs/ziti-edge-tunnel/include/config-utils.h b/programs/ziti-edge-tunnel/include/config-utils.h index 9cccd1e1..3315aff6 100644 --- a/programs/ziti-edge-tunnel/include/config-utils.h +++ b/programs/ziti-edge-tunnel/include/config-utils.h @@ -16,11 +16,10 @@ #ifndef ZITI_TUNNEL_SDK_C_CONFIG_UTILS_H #define ZITI_TUNNEL_SDK_C_CONFIG_UTILS_H +#define DEFAULT_STATE_FILE_NAME "config.json" -char* get_system_config_path(); +char* get_system_config_path(const char* base_path); void set_identifier_path(char* id_dir); char* get_identifier_path(); -char* get_config_file_name(char* config_path); -char* get_backup_config_file_name(char* config_path); #endif //ZITI_TUNNEL_SDK_C_CONFIG_UTILS_H diff --git a/programs/ziti-edge-tunnel/include/identity-utils.h b/programs/ziti-edge-tunnel/include/identity-utils.h index 8e6ad390..335ed4fa 100644 --- a/programs/ziti-edge-tunnel/include/identity-utils.h +++ b/programs/ziti-edge-tunnel/include/identity-utils.h @@ -82,6 +82,7 @@ int get_api_page_size(); tunnel_identity_array get_tunnel_identities_for_metrics(); +void normalize_identifier(char *str); #ifdef __cplusplus } diff --git a/programs/ziti-edge-tunnel/include/instance-config.h b/programs/ziti-edge-tunnel/include/instance-config.h index f752e9ed..6b522832 100644 --- a/programs/ziti-edge-tunnel/include/instance-config.h +++ b/programs/ziti-edge-tunnel/include/instance-config.h @@ -16,10 +16,13 @@ #ifndef ZITI_TUNNEL_SDK_C_INSTANCE_CONFIG_H #define ZITI_TUNNEL_SDK_C_INSTANCE_CONFIG_H +#include +#include bool load_tunnel_status_from_file(uv_loop_t *ziti_loop); bool save_tunnel_status_to_file(); -void initialize_instance_config(); +void initialize_instance_config(const char* config_dir); void cleanup_instance_config(); +char* get_config_file_name(); #endif //ZITI_TUNNEL_SDK_C_INSTANCE_CONFIG_H diff --git a/programs/ziti-edge-tunnel/include/windows/windows-scripts.h b/programs/ziti-edge-tunnel/include/windows/windows-scripts.h index 5454e4ca..45d42306 100644 --- a/programs/ziti-edge-tunnel/include/windows/windows-scripts.h +++ b/programs/ziti-edge-tunnel/include/windows/windows-scripts.h @@ -28,11 +28,13 @@ #include "ziti/model_support.h" -void add_nrpt_rules(uv_loop_t *nrpt_loop, model_map *hostnames, const char* dns_ip); -void remove_nrpt_rules(uv_loop_t *nrpt_loop, model_map *hostnames); -void remove_all_nrpt_rules(); bool is_nrpt_policies_effective(const char* tns_ip); -void remove_and_add_nrpt_rules(uv_loop_t *nrpt_loop, model_map *hostnames, const char* dns_ip); + +void add_nrpt_rules(uv_loop_t *nrpt_loop, model_map *hostnames, const char* dns_ip, const char* discriminator); +void remove_nrpt_rules(uv_loop_t *nrpt_loop, model_map *hostnames, const char* discriminator); +void remove_and_add_nrpt_rules(uv_loop_t *nrpt_loop, model_map *hostnames, const char* dns_ip, const char* discriminator); +void remove_all_nrpt_rules(); + void update_interface_metric(uv_loop_t *ziti_loop, wchar_t* tun_name, int metric); void update_symlink(uv_loop_t *symlink_loop, char* symlink, char* filename); diff --git a/programs/ziti-edge-tunnel/instance-config.c b/programs/ziti-edge-tunnel/instance-config.c index be22a0dc..1d172b22 100644 --- a/programs/ziti-edge-tunnel/instance-config.c +++ b/programs/ziti-edge-tunnel/instance-config.c @@ -14,6 +14,7 @@ limitations under the License. */ +#include "instance-config.h" #include #include #include @@ -21,6 +22,10 @@ #include "identity-utils.h" #include +#if _WIN32 +#define realpath(rel, abs) _fullpath(abs, rel, MAX_PATH) +#endif + // to store the whole tunnel status data #define MIN_BUFFER_LEN 512 @@ -28,7 +33,20 @@ static uv_sem_t sem; static unsigned int sem_value = 1; static int sem_initialized = -1; -void initialize_instance_config() { +static char* base_dir = NULL; + +/// +/// \param config_dir represents the location of the configuration to be used +void initialize_instance_config(const char* config_dir) { + if (!config_dir) { + //indicates this was started with -i (not -I). Operations should not do anything in this case + return; + } + + char actual_config_dir[PATH_MAX]; + realpath(config_dir, actual_config_dir); + + base_dir = strdup(actual_config_dir); //save the location of the config dir sem_initialized = uv_sem_init(&sem, sem_value); if (sem_initialized < 0) { ZITI_LOG(WARN, "Could not initialize lock for the config, config file may not be updated"); @@ -66,74 +84,56 @@ bool load_config_from_file(char* config_file_name) { } bool load_tunnel_status_from_file(uv_loop_t* ziti_loop) { - char* config_path = get_system_config_path(); - uv_fs_t fs; - int check = uv_fs_mkdir(ziti_loop, &fs, config_path, 0755, NULL); + int check = uv_fs_mkdir(ziti_loop, &fs, base_dir, 0755, NULL); if (check == 0) { - ZITI_LOG(TRACE, "config path is created at %s", config_path); + ZITI_LOG(TRACE, "config path is created at %s", base_dir); } else if (check == UV_EEXIST) { - ZITI_LOG(TRACE, "config path exists at %s", config_path); + ZITI_LOG(TRACE, "config path exists at %s", base_dir); } else { - ZITI_LOG(ERROR, "error creating %s: %s", config_path, uv_strerror(check)); + ZITI_LOG(ERROR, "error creating %s: %s", base_dir, uv_strerror(check)); return false; } bool loaded = false; - char* config_file_name = get_config_file_name(config_path); - char* bkp_config_file_name = get_backup_config_file_name(config_path); + char* config_file_name = get_config_file_name(); ZITI_LOG(INFO,"Loading config file from %s", config_file_name); // try to load tunnel status from config file loaded = load_config_from_file(config_file_name); - // try to load tunnel status from backup config file - if (!loaded) { - loaded = load_config_from_file(bkp_config_file_name); - } - // not able to load the tunnel status from both the config and backup files if (!loaded) { ZITI_LOG(WARN, "Config files %s and the backup file cannot be read or they do not exist, will create a new config file or the old one will be overwritten", config_file_name); } free(config_file_name); - free(bkp_config_file_name); - free(config_path); return loaded; } bool save_tunnel_status_to_file() { + if(!base_dir) { + // no base_dir indicates using -i not -I + ZITI_LOG(DEBUG, "skipping save_tunnel_status_to_file. base_dir is NULL, running with -i"); + return true; + } size_t json_len; char* tunnel_status = get_tunnel_config(&json_len); bool saved = false; if (json_len > 0) { - char* config_path = get_system_config_path(); - - char* config_file_name = get_config_file_name(config_path); - char* bkp_config_file_name = get_backup_config_file_name(config_path); + char* config_path = get_system_config_path(base_dir); + char* config_file_name = get_config_file_name(); if (sem_initialized == 0) { uv_sem_wait(&sem); } else { ZITI_LOG(ZITI_WTF, "Could not save the config file [%s] due to semaphore lock not initialized error.", config_file_name); free(config_file_name); - free(bkp_config_file_name); free(config_path); free(tunnel_status); return saved; } - //copy config to backup file - int rem = remove(bkp_config_file_name); - if (rem == 0) { - ZITI_LOG(DEBUG, "Deleted backup config file %s", bkp_config_file_name); - } - if (rename(config_file_name, bkp_config_file_name) == 0) { - ZITI_LOG(DEBUG, "Copied config file to backup config file %s", bkp_config_file_name); - } else { - ZITI_LOG(ERROR, "Could not copy config file [%s] to backup config file, the config might not exists at the moment", config_file_name); - } // write tunnel status to the config file FILE* config = fopen(config_file_name, "w"); @@ -152,14 +152,11 @@ bool save_tunnel_status_to_file() { } saved = true; fclose(config); - ZITI_LOG(DEBUG, "Saved current tunnel status into Config file %s", config_file_name); + ZITI_LOG(INFO, "Saved current tunnel status into Config file %s", config_file_name); } uv_sem_post(&sem); - - ZITI_LOG(TRACE, "Cleaning up resources used for the backup of tunnel config file %s", config_file_name); free(config_file_name); - free(bkp_config_file_name); free(config_path); } free(tunnel_status); @@ -176,4 +173,14 @@ void cleanup_instance_config() { } else { ZITI_LOG(ZITI_WTF, "Could not clean instance config. The semaphore is not initialized."); } +} + +char* get_config_file_name() { + if (base_dir != NULL) { + char* config_file_name = calloc(FILENAME_MAX, sizeof(char)); + snprintf(config_file_name, FILENAME_MAX, "%s%cconfig.json", base_dir, PATH_SEP); + return config_file_name; + } else { + return "config.json"; + } } \ No newline at end of file diff --git a/programs/ziti-edge-tunnel/instance.c b/programs/ziti-edge-tunnel/instance.c index 1ea7dbeb..ca6010d1 100644 --- a/programs/ziti-edge-tunnel/instance.c +++ b/programs/ziti-edge-tunnel/instance.c @@ -52,7 +52,9 @@ tunnel_identity *create_or_get_tunnel_identity(const char* identifier, const cha return id; } else { tunnel_identity *tnl_id = calloc(1, sizeof(struct tunnel_identity_s)); - tnl_id->Identifier = strdup(identifier); + char* dup_identifier = strdup(identifier); + normalize_identifier(dup_identifier); + tnl_id->Identifier = dup_identifier; if (filename != NULL) { char* extension = strstr(filename, ".json"); @@ -557,9 +559,10 @@ void normalize_identifier(char *str) { if (*str == find) { *str = replace; } + *str = (char)tolower((unsigned char)*str); // Convert to lowercase } #else - return; // nothing to normalize at this time + // nothing to normalize at this time #endif remove_duplicate_path_separators(init_pos, PATH_SEP); } @@ -581,7 +584,14 @@ void set_identifier_from_identities() { if (tnl_id->Identifier != NULL) { // set this field to false during initialization normalize_identifier((char*)tnl_id->Identifier); - model_map_set(&tnl_identity_map, tnl_id->Identifier, tnl_id); + // verify the identity file is still there before adding to the map + + struct stat buffer; + if (stat(tnl_id->Identifier, &buffer) == 0) { + model_map_set(&tnl_identity_map, tnl_id->Identifier, tnl_id); + } else { + ZITI_LOG(WARN, "identity was in config, but file no longer exists. identifier=%s", tnl_id->Identifier); + } } //on startup - set mfa needed to false to correctly reflect tunnel status. After the identity is loaded these //are set to true __if necessary__ diff --git a/programs/ziti-edge-tunnel/windows-scripts.c b/programs/ziti-edge-tunnel/windows-scripts.c index e4741bb6..82b3bd43 100644 --- a/programs/ziti-edge-tunnel/windows-scripts.c +++ b/programs/ziti-edge-tunnel/windows-scripts.c @@ -25,6 +25,8 @@ static char* const namespace_template = "%s@{n='%s';}"; static char* const exe_name = "ziti-edge-tunnel"; +bool other_tunnelers_active(const char* path); + struct hostname_s { char *hostname; LIST_ENTRY(hostname_s) _next; @@ -179,7 +181,7 @@ void chunked_add_nrpt_rules(uv_loop_t *ziti_loop, hostname_list_t *hostnames, ch } } -void add_nrpt_rules(uv_loop_t *nrpt_loop, model_map *hostnames, const char* dns_ip) { +void add_nrpt_rules(uv_loop_t *nrpt_loop, model_map *hostnames, const char* dns_ip, const char* discriminator) { ZITI_LOG(VERBOSE, "Add nrpt rules"); if (hostnames == NULL || model_map_size(hostnames) == 0) { @@ -211,7 +213,7 @@ void add_nrpt_rules(uv_loop_t *nrpt_loop, model_map *hostnames, const char* dns_ } } -void chunked_remove_nrpt_rules(uv_loop_t *ziti_loop, hostname_list_t *hostnames) { +void chunked_remove_nrpt_rules(uv_loop_t *ziti_loop, hostname_list_t *hostnames, const char* discriminator) { char script[MAX_POWERSHELL_SCRIPT_LEN] = { 0 }; size_t buf_len = snprintf(script, MAX_POWERSHELL_SCRIPT_LEN, "$toRemove = @(\n"); if (!is_buffer_available(buf_len, MAX_POWERSHELL_SCRIPT_LEN, script)) { @@ -270,7 +272,7 @@ void chunked_remove_nrpt_rules(uv_loop_t *ziti_loop, hostname_list_t *hostnames) } } -void remove_nrpt_rules(uv_loop_t *nrpt_loop, model_map *hostnames) { +void remove_nrpt_rules(uv_loop_t *nrpt_loop, model_map *hostnames, const char* discriminator) { ZITI_LOG(VERBOSE, "Remove nrpt rules"); if (hostnames == NULL || model_map_size(hostnames) == 0) { @@ -285,7 +287,7 @@ void remove_nrpt_rules(uv_loop_t *nrpt_loop, model_map *hostnames) { while(it != NULL) { const char* hostname = model_map_it_key(it); if (current_size > MAX_BUCKET_SIZE || rule_size > MAX_POWERSHELL_SCRIPT_LEN) { - chunked_remove_nrpt_rules(nrpt_loop, &host_names_list); + chunked_remove_nrpt_rules(nrpt_loop, &host_names_list, discriminator); rule_size = MIN_BUFFER_LEN; current_size = 0; } @@ -298,11 +300,17 @@ void remove_nrpt_rules(uv_loop_t *nrpt_loop, model_map *hostnames) { it = model_map_it_remove(it); } if (current_size > 0) { - chunked_remove_nrpt_rules(nrpt_loop, &host_names_list); + chunked_remove_nrpt_rules(nrpt_loop, &host_names_list, discriminator); } } void remove_all_nrpt_rules() { + //find all zet process, contact them and get their respective discriminator + if(other_tunnelers_active("\\\\.\\pipe\\ziti-edge-tunnel.sock*")) { + ZITI_LOG(INFO, "Other ziti-edge-tunnels are running"); + return; + } + char remove_cmd[MAX_POWERSHELL_COMMAND_LEN]; size_t buf_len = sprintf(remove_cmd, "powershell -Command \"Get-DnsClientNrptRule | Where { $_.Comment.StartsWith('Added by %s') } | Remove-DnsClientNrptRule -ErrorAction SilentlyContinue -Force\"", exe_name); ZITI_LOG(TRACE, "Removing all nrpt rules. total script size: %zd", buf_len); @@ -390,7 +398,7 @@ void chunked_remove_and_add_nrpt_rules(uv_loop_t *ziti_loop, hostname_list_t *ho } } -void remove_and_add_nrpt_rules(uv_loop_t *nrpt_loop, model_map *hostnames, const char* dns_ip) { +void remove_and_add_nrpt_rules(uv_loop_t *nrpt_loop, model_map *hostnames, const char* dns_ip, const char* discriminator) { ZITI_LOG(VERBOSE, "Remove and add nrpt rules"); if (hostnames == NULL || model_map_size(hostnames) == 0) { @@ -502,9 +510,9 @@ void update_interface_metric(uv_loop_t *ziti_loop, wchar_t* tun_name, int metric void update_symlink(uv_loop_t *symlink_loop, char* symlink, char* filename) { char script[MAX_POWERSHELL_SCRIPT_LEN] = { 0 }; - size_t buf_len = sprintf(script, "Get-Item -Path \"%s\" | Remove-Item\n", symlink); + size_t buf_len = sprintf(script, "Get-Item -Path \"%s\" | Remove-Item;", symlink); size_t copied = buf_len; - buf_len = sprintf(script + copied, "New-Item -Itemtype SymbolicLink -Path \"%s\" -Target \"%s\"", symlink, filename); + buf_len = sprintf(script + copied, "New-Item -Itemtype SymbolicLink -Path \"%s\" -Target \"%s\" | Out-Null", symlink, filename); copied += buf_len; ZITI_LOG(TRACE, "Updating symlink using script. total script size: %zd", copied); @@ -522,3 +530,27 @@ void update_symlink(uv_loop_t *symlink_loop, char* symlink, char* filename) { ZITI_LOG(DEBUG, "Updated symlink script"); } } + +bool other_tunnelers_active(const char* path) { + WIN32_FIND_DATA findFileData; + HANDLE hFind = FindFirstFile(path, &findFileData); + + if (hFind == INVALID_HANDLE_VALUE) { + DWORD err = GetLastError(); + if(err == ERROR_NO_MORE_FILES) { + //expected when nothing is running + } else { + ZITI_LOG(ERROR, "Unexpected error when trying to find other ziti-edge-tunnel instances. error=%d", err); + } + return false; + } + + do { + if (findFileData.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) { + return true; + } + } while (FindNextFile(hFind, &findFileData) != 0); + + FindClose(hFind); + return false; +} \ No newline at end of file diff --git a/programs/ziti-edge-tunnel/windows-service.c b/programs/ziti-edge-tunnel/windows-service.c index 6546e980..c2e41290 100644 --- a/programs/ziti-edge-tunnel/windows-service.c +++ b/programs/ziti-edge-tunnel/windows-service.c @@ -160,7 +160,7 @@ VOID WINAPI SvcMain( DWORD dwArgc, LPTSTR *lpszArgv ) ReportSvcStatus( SERVICE_START_PENDING, NO_ERROR, 3000 ); // Perform service-specific initialization and work. - char* config_dir = get_system_config_path(); + char* config_dir = get_system_config_path(getenv("APPDATA")); scm_service_init(config_dir); SvcInit( dwArgc, lpszArgv ); diff --git a/programs/ziti-edge-tunnel/windows/log_utils.c b/programs/ziti-edge-tunnel/windows/log_utils.c index 83796130..4be95fda 100644 --- a/programs/ziti-edge-tunnel/windows/log_utils.c +++ b/programs/ziti-edge-tunnel/windows/log_utils.c @@ -93,14 +93,6 @@ static char* get_log_path() { snprintf(log_path, FILENAME_MAX, "%slogs%cservice", process_dir, PATH_SEP); } mkdir_p(log_path); - - struct stat info; - if (stat(log_path, &info) != 0) { - fprintf(stderr,"\nlogging cannot proceed. the path could not be created: %s!\n", log_path); - } else { - fprintf(stderr,"\nlogs enabled at: %s\n", log_path); - } - return log_path; } diff --git a/programs/ziti-edge-tunnel/ziti-edge-tunnel.c b/programs/ziti-edge-tunnel/ziti-edge-tunnel.c index 0a3f53a1..e1a96e80 100644 --- a/programs/ziti-edge-tunnel/ziti-edge-tunnel.c +++ b/programs/ziti-edge-tunnel/ziti-edge-tunnel.c @@ -82,7 +82,6 @@ static void run_tunneler_loop(uv_loop_t* ziti_loop); static tunneler_context initialize_tunneler(netif_driver tun, uv_loop_t* ziti_loop); #if _WIN32 -static void move_config_from_previous_windows_backup(uv_loop_t *loop); #define LAST_CHAR_IPC_CMD '\n' #else #define LAST_CHAR_IPC_CMD '\0' @@ -135,6 +134,7 @@ static char *configured_cidr = NULL; static char *configured_log_level = NULL; static char *configured_proxy = NULL; static char *config_dir = NULL; +static char *ipc_discriminator = NULL; static uv_pipe_t cmd_server; static uv_pipe_t event_server; @@ -155,8 +155,8 @@ static uv_cond_t stop_cond; IMPL_ENUM(event, EVENT_ACTIONS) #if _WIN32 -static char sockfile[] = "\\\\.\\pipe\\ziti-edge-tunnel.sock"; -static char eventsockfile[] = "\\\\.\\pipe\\ziti-edge-tunnel-event.sock"; +static char sockfile__[] = "\\\\.\\pipe\\ziti-edge-tunnel.sock"; +static char eventsockfile__[] = "\\\\.\\pipe\\ziti-edge-tunnel-event.sock"; #elif __unix__ || unix || ( __APPLE__ && __MACH__ ) #include #include @@ -165,6 +165,9 @@ static char sockfile[] = SOCKET_PATH "/ziti-edge-tunnel.sock"; static char eventsockfile[] = SOCKET_PATH "/ziti-edge-tunnel-event.sock"; #endif +static char* sockfile; +static char* eventsockfile; + static int sizeof_event_clients_list() { struct event_conn_s *event_client; int size = 0; @@ -266,7 +269,7 @@ static void on_command_resp(const tunnel_result* result, void *ctx) { } if (model_map_size(&hostnamesToRemove) > 0) { - remove_nrpt_rules(global_loop_ref, &hostnamesToRemove); + remove_nrpt_rules(global_loop_ref, &hostnamesToRemove, ipc_discriminator); } } } else { @@ -561,9 +564,9 @@ static bool process_tunnel_commands(const tunnel_command *tnl_cmd, command_cb cb add_id_req->identifier = strdup(new_identifier); add_id_req->identifier_file_name = strdup(new_identifier_name); add_id_req->jwt_content = strdup(tunnel_add_identity_cmd.jwtContent); - add_id_req->use_keychain = tunnel_add_identity_cmd.useKeychain; - + add_id_req->use_keychain = true; enroll_ziti_async(global_loop_ref, add_id_req); + free_tunnel_add_identity(&tunnel_add_identity_cmd); return true; } @@ -714,7 +717,7 @@ static int start_cmd_socket(uv_loop_t *l) { #define CHECK_UV(op) do{ \ int uv_rc = (op); \ if (uv_rc != 0) { \ - ZITI_LOG(WARN, "failed to open IPC socket op=[%s] err=%d[%s]", #op, uv_rc, uv_strerror(uv_rc));\ + ZITI_LOG(WARN, "failed to open IPC socket path=[%s] op=[%s] err=%d[%s]", sockfile, #op, uv_rc, uv_strerror(uv_rc));\ goto uv_err; \ } \ } while(0) @@ -1102,36 +1105,39 @@ static void load_identities(uv_work_t *wr) { uv_dirent_t file; while (uv_fs_scandir_next(&fs, &file) == 0) { - ZITI_LOG(TRACE, "processing file: %s %d", file.name, rc); + char* file_as_identifier = malloc(MAXPATHLEN); + snprintf(file_as_identifier, MAXPATHLEN, "%s%c%s", config_dir, PATH_SEP, file.name); + normalize_identifier(file_as_identifier); + ZITI_LOG(TRACE, "processing file: %s %d", file_as_identifier, rc); if(file.type != UV_DIRENT_FILE) { - ZITI_LOG(DEBUG, "skipping file in config dir as it's not the proper type. type: %d. file: %s", file.type, file.name); - continue; + ZITI_LOG(DEBUG, "skipping file in config dir as it's not the proper type. type: %d. file: %s", file.type, file_as_identifier); + goto exit_loop; } - - if (strcasecmp(file.name, get_config_file_name(NULL)) == 0) { - ZITI_LOG(DEBUG, "skipping the configuration file: %s", file.name); - continue; - } else if(strcasecmp(file.name, get_backup_config_file_name(NULL)) == 0 ) { - ZITI_LOG(DEBUG, "skipping the backup configuration file: %s", file.name); - continue; + char* cfg_file_name = get_config_file_name(); + normalize_identifier(cfg_file_name); + if (strcasecmp(file_as_identifier, cfg_file_name) == 0) { + ZITI_LOG(DEBUG, "skipping the configuration file: %s", file_as_identifier); + goto exit_loop; } + free(cfg_file_name); - const char* ext = get_filename_ext(file.name); + const char* ext = get_filename_ext(file_as_identifier); // ignore back up files if (strcasecmp(ext, ".bak") == 0 || strcasecmp(ext, ".original") == 0 || strcasecmp(ext, "json") != 0) { - ZITI_LOG(DEBUG, "skipping backup file: %s", file.name); - continue; + ZITI_LOG(DEBUG, "skipping backup file: %s", file_as_identifier); + goto exit_loop; } - ZITI_LOG(INFO, "loading identity file: %s", file.name); + ZITI_LOG(INFO, "loading identity file: %s", file_as_identifier); if (file.type == UV_DIRENT_FILE) { struct cfg_instance_s *inst = calloc(1, sizeof(struct cfg_instance_s)); - inst->cfg = malloc(MAXPATHLEN); - snprintf(inst->cfg, MAXPATHLEN, "%s%c%s", config_dir, PATH_SEP, file.name); - create_or_get_tunnel_identity(inst->cfg, file.name); + inst->cfg = strdup(file_as_identifier); + create_or_get_tunnel_identity(inst->cfg, file_as_identifier); LIST_INSERT_HEAD(&load_list, inst, _next); } + exit_loop: + free(file_as_identifier); } } } @@ -1152,6 +1158,8 @@ static void load_identities_complete(uv_work_t * wr, int status) { struct cfg_instance_s *inst = LIST_FIRST(&load_list); LIST_REMOVE(inst, _next); + normalize_identifier(inst->cfg); + if (config_dir == NULL) { create_or_get_tunnel_identity(inst->cfg, inst->cfg); } @@ -1336,13 +1344,13 @@ static void on_event(const base_event *ev) { } if (id->Active && model_map_size(&hostnamesToEdit) > 0 && !is_host_only()) { - remove_and_add_nrpt_rules(global_loop_ref, &hostnamesToEdit, get_dns_ip()); + remove_and_add_nrpt_rules(global_loop_ref, &hostnamesToEdit, get_dns_ip(), ipc_discriminator); } if (id->Active && model_map_size(&hostnamesToAdd) > 0 && !is_host_only()) { - add_nrpt_rules(global_loop_ref, &hostnamesToAdd, get_dns_ip()); + add_nrpt_rules(global_loop_ref, &hostnamesToAdd, get_dns_ip(), ipc_discriminator); } if (model_map_size(&hostnamesToRemove) > 0 && !is_host_only()) { - remove_nrpt_rules(global_loop_ref, &hostnamesToRemove); + remove_nrpt_rules(global_loop_ref, &hostnamesToRemove, ipc_discriminator); } #endif @@ -1818,6 +1826,7 @@ static struct option run_options[] = { { "dns-ip-range", required_argument, NULL, 'd'}, { "dns-upstream", required_argument, NULL, 'u'}, { "proxy", required_argument, NULL, 'x' }, + { "ipc-discriminator", required_argument, NULL, 'p' }, }; static struct option run_host_options[] = { @@ -1884,17 +1893,20 @@ static int run_opts(int argc, char *argv[]) { optind = 0; bool identity_provided = false; - while ((c = getopt_long(argc, argv, "i:I:v:r:d:u:x:", + while ((c = getopt_long(argc, argv, "i:I:v:r:d:u:x:p:", run_options, &option_index)) != -1) { switch (c) { case 'i': { struct cfg_instance_s *inst = calloc(1, sizeof(struct cfg_instance_s)); + normalize_identifier(optarg); inst->cfg = strdup(optarg); + create_or_get_tunnel_identity(inst->cfg, inst->cfg); LIST_INSERT_HEAD(&load_list, inst, _next); identity_provided = true; break; } case 'I': + normalize_identifier(optarg); config_dir = optarg; identity_provided = true; break; @@ -1915,6 +1927,9 @@ static int run_opts(int argc, char *argv[]) { case 'x': configured_proxy = optarg; break; + case 'p': + ipc_discriminator = optarg; + break; default: { fprintf(stderr, "Unknown option '%c'\n", c); errors++; @@ -1942,6 +1957,7 @@ static int run_host_opts(int argc, char *argv[]) { case 'i': { struct cfg_instance_s *inst = calloc(1, sizeof(struct cfg_instance_s)); inst->cfg = strdup(optarg); + create_or_get_tunnel_identity(inst->cfg, inst->cfg); LIST_INSERT_HEAD(&load_list, inst, _next); identity_provided = true; break; @@ -1998,12 +2014,28 @@ static void interrupt_handler(int sig) { } #endif +static void configure_ipc() { + if(ipc_discriminator == NULL) { + int pid = getpid(); + ipc_discriminator = malloc(10); + snprintf(ipc_discriminator, 10, "%d", pid); + } + sockfile = calloc(strlen(sockfile__) + 1 + strlen(ipc_discriminator), sizeof(char)); + eventsockfile = calloc(strlen(eventsockfile__) + 1 + strlen(ipc_discriminator), sizeof(char)); + + strcat(sockfile, sockfile__); +// strcat(sockfile, "."); +// strcat(sockfile, ipc_discriminator); + + strcat(eventsockfile, eventsockfile__); +// strcat(eventsockfile, "."); +// strcat(eventsockfile, ipc_discriminator); +} + static void run(int argc, char *argv[]) { uv_cond_init(&stop_cond); uv_mutex_init(&stop_mutex); - initialize_instance_config(); - //set log level in precedence: command line flag (-v/--verbose) -> env var (ZITI_LOG) -> config file int log_level = get_log_level(configured_log_level); log_writer log_fn = NULL; @@ -2017,6 +2049,10 @@ static void run(int argc, char *argv[]) { signal(SIGINT, interrupt_handler); #endif + initialize_instance_config(config_dir); + + configure_ipc(); + ziti_log_init(global_loop_ref, log_level, log_fn); // generate tunnel status instance and save active state and start time @@ -2084,7 +2120,6 @@ static void run(int argc, char *argv[]) { ZITI_LOG(INFO," - initialized at : %s (local time), %s (UTC)", time_val, time_str); ZITI_LOG(INFO," - log file location: %s", get_log_file_name()); ZITI_LOG(INFO,"============================================================================"); - move_config_from_previous_windows_backup(global_loop_ref); ZITI_LOG(DEBUG, "granting se_debug privilege to current process to allow access to privileged processes during posture checks"); //ensure this process has the necessary access token to get the full path of privileged processes @@ -2508,6 +2543,7 @@ static int send_message_to_tunnel(char* message, bool show_result) { } static void send_message_to_tunnel_fn(int argc, char *argv[]) { + configure_ipc(); char* json = tunnel_command_to_json(&cmd, MODEL_JSON_COMPACT, NULL); int result = send_message_to_tunnel(json, cmd.show_result); free_tunnel_command(&cmd); @@ -2530,8 +2566,8 @@ static char* get_identity_opt(int argc, char *argv[]) { id = optarg; break; default: { - fprintf(stderr, "Unknown option '%c'\n", c); - errors++; + // not an error -- fprintf(stderr, "Unknown option '%c'\n", c); + //errors++; break; } } @@ -2547,9 +2583,34 @@ static char* get_identity_opt(int argc, char *argv[]) { static int ext_auth_opts(int argc, char *argv[]) { tunnel_identity_id id = { - .identifier = (char*)get_identity_opt(argc, argv), + }; + optind = 0; + static struct option opts[] = { + {"identity", required_argument, NULL, 'i'}, + { "verbose", required_argument, NULL, 'v'}, + { "ipc-discriminator", required_argument, NULL, 'p' } + }; + int c, option_index, errors = 0; + while ((c = getopt_long(argc, argv, "i:p:v:", opts, &option_index)) != -1) { + switch (c) { + case 'i': + id.identifier = optarg; + break; + case 'v': + configured_log_level = optarg; + break; + case 'p': + ipc_discriminator = optarg; + break; + default: { + fprintf(stderr, "Unknown option '%c'\n", c); + errors++; + break; + } + } + } cmd.command = TunnelCommands.ExternalAuth; cmd.data = tunnel_identity_id_to_json(&id, MODEL_JSON_COMPACT, NULL); return optind; @@ -3053,84 +3114,119 @@ static int add_identity_opts(int argc, char *argv[]) { return optind; } + static CommandLine enroll_cmd = make_command("enroll", "enroll Ziti identity", - "-j|--jwt -i|--identity [-k|--key [-c|--cert ]] [-n|--name ]", + "-j|--jwt -i|--identity [-k|--key [-c|--cert ]] [-n|--name ]\n", "\t-j|--jwt\tenrollment token file\n" "\t-x|--proxy type://[username[:password]@]hostname_or_ip:port\tproxy to use when connecting to OpenZiti controller. 'http' is currently the only supported type.\n" "\t-i|--identity\toutput identity file\n" "\t-K|--use-keychain\tuse keychain to generate/store private key\n" "\t-k|--key\tprivate key for enrollment\n" "\t-c|--cert\tcertificate for enrollment\n" - "\t-n|--name\tidentity name\n", + "\t-n|--name\tidentity name\n" + "\t-p|--ipc-discriminator\ta discriminator to apply to the IPC sockets\n", parse_enroll_opts, enroll); static CommandLine run_cmd = make_command("run", "run Ziti tunnel (required superuser access)", "-i [-r N] [-v N] [-d|--dns-ip-range N.N.N.N/n]", "\t-i|--identity \trun with provided identity file (required)\n" "\t-I|--identity-dir \tload identities from provided directory\n" "\t-x|--proxy type://[username[:password]@]hostname_or_ip:port\tproxy to use when" - " connecting to OpenZiti controller and edge routers. 'http' is currently the only supported type." + " connecting to OpenZiti controller and edge routers. 'http' is currently the only supported type.\n" "\t-v|--verbose N\tset log level, higher level -- more verbose (default 3)\n" "\t-r|--refresh N\tset service polling interval in seconds (default 10)\n" "\t-d|--dns-ip-range \tspecify CIDR block in which service DNS names" - " are assigned in N.N.N.N/n format (default " DEFAULT_DNS_CIDR ")\n", + " are assigned in N.N.N.N/n format (default " DEFAULT_DNS_CIDR ")\n" + "\t-p|--ipc-discriminator\ta discriminator to apply to the IPC sockets\n", run_opts, run); static CommandLine run_host_cmd = make_command("run-host", "run Ziti tunnel to host services", "-i [-r N] [-v N]", "\t-i|--identity \trun with provided identity file (required)\n" "\t-I|--identity-dir \tload identities from provided directory\n" "\t-x|--proxy type://[username[:password]@]hostname_or_ip:port\tproxy to use when" - " connecting to OpenZiti controller and edge routers" + " connecting to OpenZiti controller and edge routers\n" "\t-v|--verbose N\tset log level, higher level -- more verbose (default 3)\n" - "\t-r|--refresh N\tset service polling interval in seconds (default 10)\n", + "\t-r|--refresh N\tset service polling interval in seconds (default 10)\n" + "\t-p|--ipc-discriminator\ta discriminator to apply to the IPC sockets\n", run_host_opts, run); static CommandLine dump_cmd = make_command("dump", "dump the identities information", "[-i ] [-p ]", "\t-i|--identity\tdump identity info\n" - "\t-p|--dump_path\tdump into path\n", dump_opts, send_message_to_tunnel_fn); + "\t-p|--dump_path\tdump into path\n" + "\t-p|--ipc-discriminator\ta discriminator to apply to the IPC sockets\n", + dump_opts, send_message_to_tunnel_fn); static CommandLine ip_dump_cmd = make_command("ip_dump", "dump ip stack information", "[-p ]", - "\t-p|--dump_path\tdump into path\n", ip_dump_opts, send_message_to_tunnel_fn); + "\t-p|--dump_path\tdump into path\n" + "\t-p|--ipc-discriminator\ta discriminator to apply to the IPC sockets\n", + ip_dump_opts, send_message_to_tunnel_fn); static CommandLine on_off_id_cmd = make_command("on_off_identity", "enable/disable the identities information", "-i -o t|f", "\t-i|--identity\tidentity info that needs to be enabled/disabled\n" - "\t-o|--onoff\t't' or 'f' to enable or disable the identity\n", on_off_identity_opts, send_message_to_tunnel_fn); + "\t-o|--onoff\t't' or 'f' to enable or disable the identity\n" + "\t-p|--ipc-discriminator\ta discriminator to apply to the IPC sockets\n", + on_off_identity_opts, send_message_to_tunnel_fn); static CommandLine enable_id_cmd = make_command("enable", "enable the identities information", "[-i ]", - "\t-i|--identity\tidentity info that needs to be enabled\n", enable_identity_opts, send_message_to_tunnel_fn); + "\t-i|--identity\tidentity info that needs to be enabled\n" + "\t-p|--ipc-discriminator\ta discriminator to apply to the IPC sockets\n", + enable_identity_opts, send_message_to_tunnel_fn); static CommandLine enable_mfa_cmd = make_command("enable_mfa", "Enable MFA function fetches the totp url from the controller", "[-i ]", - "\t-i|--identity\tidentity info for enabling mfa\n", enable_mfa_opts, send_message_to_tunnel_fn); + "\t-i|--identity\tidentity info for enabling mfa\n" + "\t-p|--ipc-discriminator\ta discriminator to apply to the IPC sockets\n", + enable_mfa_opts, send_message_to_tunnel_fn); static CommandLine verify_mfa_cmd = make_command("verify_mfa", "Verify the mfa login using the auth code while enabling mfa", "[-i ] [-c ]", "\t-i|--identity\tidentity info to verify mfa login\n" - "\t-c|--authcode\tauth code to verify mfa login\n", verify_mfa_opts, send_message_to_tunnel_fn); + "\t-c|--authcode\tauth code to verify mfa login\n" + "\t-p|--ipc-discriminator\ta discriminator to apply to the IPC sockets\n", + verify_mfa_opts, send_message_to_tunnel_fn); static CommandLine remove_mfa_cmd = make_command("remove_mfa", "Removes MFA registration from the controller", "[-i ] [-c ]", "\t-i|--identity\tidentity info for removing mfa\n" - "\t-c|--authcode\tauth code to verify mfa login\n", remove_mfa_opts, send_message_to_tunnel_fn); + "\t-c|--authcode\tauth code to verify mfa login\n" + "\t-p|--ipc-discriminator\ta discriminator to apply to the IPC sockets\n", + remove_mfa_opts, send_message_to_tunnel_fn); static CommandLine submit_mfa_cmd = make_command("submit_mfa", "Submit MFA code to authenticate to the controller", "[-i ] [-c ]", "\t-i|--identity\tidentity info for submitting mfa\n" - "\t-c|--authcode\tauth code to authenticate mfa login\n", submit_mfa_opts, send_message_to_tunnel_fn); + "\t-c|--authcode\tauth code to authenticate mfa login\n" + "\t-p|--ipc-discriminator\ta discriminator to apply to the IPC sockets\n", + submit_mfa_opts, send_message_to_tunnel_fn); static CommandLine generate_mfa_codes_cmd = make_command("generate_mfa_codes", "Generate MFA codes", "[-i ] [-c ]", "\t-i|--identity\tidentity info for generating mfa codes\n" - "\t-c|--authcode\tauth code to authenticate the request for generating mfa codes\n", generate_mfa_codes_opts, send_message_to_tunnel_fn); + "\t-c|--authcode\tauth code to authenticate the request for generating mfa codes\n" + "\t-p|--ipc-discriminator\ta discriminator to apply to the IPC sockets\n", + generate_mfa_codes_opts, send_message_to_tunnel_fn); static CommandLine get_mfa_codes_cmd = make_command("get_mfa_codes", "Get MFA codes", "[-i ] [-c ]", "\t-i|--identity\tidentity info for fetching mfa codes\n" "\t-c|--authcode\tauth code to authenticate the request for fetching mfa codes\n", get_mfa_codes_opts, send_message_to_tunnel_fn); -static CommandLine get_status_cmd = make_command("tunnel_status", "Get Tunnel Status", "", "", get_status_opts, send_message_to_tunnel_fn); +static CommandLine get_status_cmd = make_command("tunnel_status", "Get Tunnel Status", "", "" + "\t-p|--ipc-discriminator\ta discriminator to apply to the IPC sockets\n", + get_status_opts, send_message_to_tunnel_fn); static CommandLine delete_id_cmd = make_command("delete", "delete the identities information", "[-i ]", - "\t-i|--identity\tidentity info that needs to be deleted\n", delete_identity_opts, send_message_to_tunnel_fn); + "\t-i|--identity\tidentity info that needs to be deleted\n" + "\t-p|--ipc-discriminator\ta discriminator to apply to the IPC sockets\n", + delete_identity_opts, send_message_to_tunnel_fn); static CommandLine add_id_cmd = make_command("add", "enroll and load the identity", "-j -i ", "\t-K|--use-keychain\tuse keychain to generate/store private key\n" "\t-j|--jwt\tenrollment token content\n" - "\t-i|--identity\toutput identity .json file (relative to \"-I\" config directory)\n", - add_identity_opts, send_message_to_tunnel_fn); + "\t-i|--identity\toutput identity .json file (relative to \"-I\" config directory)\n" + "\t-p|--ipc-discriminator\ta discriminator to apply to the IPC sockets\n", + add_identity_opts, send_message_to_tunnel_fn); static CommandLine set_log_level_cmd = make_command("set_log_level", "Set log level of the tunneler", "-l ", - "\t-l|--loglevel\tlog level of the tunneler\n", set_log_level_opts, send_message_to_tunnel_fn); + "\t-l|--loglevel\tlog level of the tunneler\n" + "\t-p|--ipc-discriminator\ta discriminator to apply to the IPC sockets\n", + set_log_level_opts, send_message_to_tunnel_fn); static CommandLine update_tun_ip_cmd = make_command("update_tun_ip", "Update tun ip of the tunneler", "[-t ] [-p ] [-d ]", "\t-t|--tunip\ttun ipv4 of the tunneler\n" "\t-p|--prefixlength\ttun ipv4 prefix length of the tunneler\n" - "\t-d|--addDNS\tAdd Dns to the tunneler\n", update_tun_ip_opts, send_message_to_tunnel_fn); + "\t-d|--addDNS\tAdd Dns to the tunneler\n" + "\t-p|--ipc-discriminator\ta discriminator to apply to the IPC sockets\n", + update_tun_ip_opts, send_message_to_tunnel_fn); static CommandLine ep_status_change_cmd = make_command("endpoint_sts_change", "send endpoint status change message to the tunneler", "[-w ] [-u ]", "\t-w|--wake\twake the tunneler\n" - "\t-u|--unlock\tunlock the tunneler\n", endpoint_status_change_opts, send_message_to_tunnel_fn); + "\t-u|--unlock\tunlock the tunneler\n" + "\t-p|--ipc-discriminator\ta discriminator to apply to the IPC sockets\n", + endpoint_status_change_opts, send_message_to_tunnel_fn); static CommandLine ext_auth_login = make_command( "ext-jwt-login", "login with ext JWT signer", "-i ", - "\t-i|--identity\tidentity to authenticate\n", + "\t-i|--identity\tidentity to authenticate\n" + "\t-v|--verbose N\tset log level, higher level -- more verbose (default 3)\n" + "\t-p|--ipc-discriminator\ta discriminator to apply to the IPC sockets\n", ext_auth_opts, send_message_to_tunnel_fn); #if _WIN32 @@ -3265,60 +3361,6 @@ void scm_service_stop() { uv_cond_wait(&stop_cond, &stop_mutex); uv_mutex_unlock(&stop_mutex); } - -static void move_config_from_previous_windows_backup(uv_loop_t *loop) { - char *backup_folders[] = { - "Windows.~BT\\Windows\\System32\\config\\systemprofile\\AppData\\Roaming\\NetFoundry", - "Windows.old\\Windows\\System32\\config\\systemprofile\\AppData\\Roaming\\NetFoundry", - NULL - }; - - char* system_drive = getenv("SystemDrive"); - - for (int i =0; backup_folders[i]; i++) { - char* config_dir_bkp = calloc(FILENAME_MAX, sizeof(char)); - sprintf(config_dir_bkp, "%s\\%s", system_drive, backup_folders[i]); - uv_fs_t fs; - int rc = uv_fs_access(loop, &fs, config_dir_bkp, 0, NULL); - if (rc < 0) { - uv_fs_req_cleanup(&fs); - continue; - } - rc = uv_fs_scandir(loop, &fs, config_dir_bkp, 0, NULL); - if (rc < 0) { - ZITI_LOG(ERROR, "failed to scan dir[%s]: %d/%s", config_dir_bkp, rc, uv_strerror(rc)); - uv_fs_req_cleanup(&fs); - continue; - } else if (rc == 0) { - uv_fs_req_cleanup(&fs); - continue; - } - ZITI_LOG(TRACE, "scan dir %s, file count: %d", config_dir_bkp, rc); - - uv_dirent_t file; - while (uv_fs_scandir_next(&fs, &file) == 0) { - if (file.type == UV_DIRENT_FILE) { - char old_file[FILENAME_MAX]; - snprintf(old_file, FILENAME_MAX, "%s\\%s", config_dir_bkp, file.name); - char new_file[FILENAME_MAX]; - snprintf(new_file, FILENAME_MAX, "%s\\%s", config_dir, file.name); - uv_fs_t fs_cpy; - rc = uv_fs_copyfile(loop, &fs_cpy, old_file, new_file, 0, NULL); - if (rc == 0) { - ZITI_LOG(INFO, "Restored old identity from the backup path - %s to new path - %s", old_file , new_file); - ZITI_LOG(INFO, "Removing old identity from the backup path - %s", old_file); - remove(old_file); - } else { - ZITI_LOG(ERROR, "failed to copy backup identity file[%s]: %d/%s", old_file, rc, uv_strerror(rc)); - } - uv_fs_req_cleanup(&fs_cpy); - } - } - free(config_dir_bkp); - config_dir_bkp = NULL; - uv_fs_req_cleanup(&fs); - } -} #endif static bool is_host_only() {