diff --git a/CMakeLists.txt b/CMakeLists.txt index fa1eade3..b2390eb5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -49,8 +49,8 @@ set(LIBYANG_DEP_SOVERSION 3.0.0) set(LIBYANG_DEP_SOVERSION_MAJOR 3) # libnetconf2 required version -set(LIBNETCONF2_DEP_VERSION 3.4.0) -set(LIBNETCONF2_DEP_SOVERSION 4.3.6) +set(LIBNETCONF2_DEP_VERSION 3.5.0) +set(LIBNETCONF2_DEP_SOVERSION 4.4.0) set(LIBNETCONF2_DEP_SOVERSION_MAJOR 4) # sysrepo required version diff --git a/cli/commands.c b/cli/commands.c index 7d5b974d..99f30d8a 100644 --- a/cli/commands.c +++ b/cli/commands.c @@ -1275,7 +1275,7 @@ cmd_auth_help(void) static void cmd_knownhosts_help(void) { - printf("knownhosts [--help] [--del ]\n"); + printf("knownhosts (--help | --del | --mode )\n"); } static void @@ -1420,18 +1420,20 @@ cmd_auth(const char *arg, char **UNUSED(tmp_config_file)) static int cmd_knownhosts(const char *arg, char **UNUSED(tmp_config_file)) { - char *ptr, *kh_file, *line = NULL, **pkeys = NULL, *text; - int del_idx = -1, i, j, pkey_len = 0, written, text_len; + char *ptr, *kh_file = NULL, *line = NULL, **pkeys = NULL, *text = NULL, *mode = NULL; + int del_idx = -1, i, j, pkey_len = 0, written, text_len, ret = EXIT_SUCCESS; size_t line_len; - FILE *file; + FILE *file = NULL; struct passwd *pwd; struct arglist cmd; struct option long_options[] = { {"help", 0, 0, 'h'}, {"del", 1, 0, 'd'}, + {"mode", 1, 0, 'm'}, {0, 0, 0, 0} }; int option_index = 0, c; + NC_SSH_KNOWNHOSTS_MODE knownhosts_mode; optind = 0; @@ -1440,30 +1442,52 @@ cmd_knownhosts(const char *arg, char **UNUSED(tmp_config_file)) return EXIT_FAILURE; } - while ((c = getopt_long(cmd.count, cmd.list, "hd:", long_options, &option_index)) != -1) { + while ((c = getopt_long(cmd.count, cmd.list, "hd:m:", long_options, &option_index)) != -1) { switch (c) { case 'h': cmd_knownhosts_help(); - clear_arglist(&cmd); - return EXIT_SUCCESS; - break; + ret = EXIT_SUCCESS; + goto cleanup; case 'd': del_idx = strtol(optarg, &ptr, 10); if ((*ptr != '\0') || (del_idx < 0)) { ERROR("knownhosts", "Wrong index"); - clear_arglist(&cmd); - return EXIT_FAILURE; + ret = EXIT_FAILURE; + goto cleanup; } break; + case 'm': + mode = optarg; + break; default: ERROR("knownhosts", "Unknown option -%c", c); cmd_knownhosts_help(); - clear_arglist(&cmd); - return EXIT_FAILURE; + ret = EXIT_FAILURE; + goto cleanup; } } - clear_arglist(&cmd); + if (mode) { + if (!strcmp(mode, "accept")) { + knownhosts_mode = NC_SSH_KNOWNHOSTS_ACCEPT; + } else if (!strcmp(mode, "accept-new")) { + knownhosts_mode = NC_SSH_KNOWNHOSTS_ACCEPT_NEW; + } else if (!strcmp(mode, "ask")) { + knownhosts_mode = NC_SSH_KNOWNHOSTS_ASK; + } else if (!strcmp(mode, "skip")) { + knownhosts_mode = NC_SSH_KNOWNHOSTS_SKIP; + } else if (!strcmp(mode, "strict")) { + knownhosts_mode = NC_SSH_KNOWNHOSTS_STRICT; + } else { + ERROR("knownhosts", "Unknown mode \"%s\"", mode); + ret = EXIT_FAILURE; + goto cleanup; + } + + nc_client_ssh_set_knownhosts_mode(knownhosts_mode); + nc_client_ssh_ch_set_knownhosts_mode(knownhosts_mode); + goto cleanup; + } errno = 0; pwd = getpwuid(getuid()); @@ -1473,19 +1497,20 @@ cmd_knownhosts(const char *arg, char **UNUSED(tmp_config_file)) } else { ERROR("knownhosts", "Failed to get a pwd entry (%s)", strerror(errno)); } - return EXIT_FAILURE; + ret = EXIT_FAILURE; + goto cleanup; } if (asprintf(&kh_file, "%s/.ssh/known_hosts", pwd->pw_dir) == -1) { - return EXIT_FAILURE; + ret = EXIT_FAILURE; + goto cleanup; } if ((file = fopen(kh_file, "r+")) == NULL) { ERROR("knownhosts", "Cannot open \"%s\" (%s)", kh_file, strerror(errno)); - free(kh_file); - return EXIT_FAILURE; + ret = EXIT_FAILURE; + goto cleanup; } - free(kh_file); /* list */ if (del_idx == -1) { @@ -1558,17 +1583,16 @@ cmd_knownhosts(const char *arg, char **UNUSED(tmp_config_file)) text_len = ftell(file); if (text_len < 0) { ERROR("knownhosts", "ftell on the known hosts file failed (%s)", strerror(errno)); - fclose(file); - return EXIT_FAILURE; + ret = EXIT_FAILURE; + goto cleanup; } fseek(file, 0, SEEK_SET); text = malloc(text_len + 1); if (fread(text, 1, text_len, file) < (unsigned)text_len) { ERROR("knownhosts", "Cannot read known hosts file (%s)", strerror(ferror(file))); - free(text); - fclose(file); - return EXIT_FAILURE; + ret = EXIT_FAILURE; + goto cleanup; } text[text_len] = '\0'; fseek(file, 0, SEEK_SET); @@ -1577,9 +1601,8 @@ cmd_knownhosts(const char *arg, char **UNUSED(tmp_config_file)) if (!ptr || (strlen(ptr) < 2)) { ERROR("knownhosts", "Key index %d does not exist", del_idx); - free(text); - fclose(file); - return EXIT_FAILURE; + ret = EXIT_FAILURE; + goto cleanup; } if (ptr[0] == '\n') { @@ -1590,9 +1613,8 @@ cmd_knownhosts(const char *arg, char **UNUSED(tmp_config_file)) written = fwrite(text, 1, ptr - text, file); if (written < ptr - text) { ERROR("knownhosts", "Failed to write to known hosts file (%s)", strerror(ferror(file))); - free(text); - fclose(file); - return EXIT_FAILURE; + ret = EXIT_FAILURE; + goto cleanup; } ptr = strchr(ptr, '\n'); @@ -1602,23 +1624,27 @@ cmd_knownhosts(const char *arg, char **UNUSED(tmp_config_file)) /* write the rest */ if (fwrite(ptr, 1, strlen(ptr), file) < strlen(ptr)) { ERROR("knownhosts", "Failed to write to known hosts file (%s)", strerror(ferror(file))); - free(text); - fclose(file); - return EXIT_FAILURE; + ret = EXIT_FAILURE; + goto cleanup; } written += strlen(ptr); } - free(text); if (ftruncate(fileno(file), written) < 0) { ERROR("knownhosts", "ftruncate() on known hosts file failed (%s)", strerror(ferror(file))); - fclose(file); - return EXIT_FAILURE; + ret = EXIT_FAILURE; + goto cleanup; } } - fclose(file); - return EXIT_SUCCESS; +cleanup: + clear_arglist(&cmd); + free(kh_file); + free(text); + if (file) { + fclose(file); + } + return ret; } static int diff --git a/cli/doc/netopeer2-cli.1 b/cli/doc/netopeer2-cli.1 index 670ac9e7..a6ab1a73 100644 --- a/cli/doc/netopeer2-cli.1 +++ b/cli/doc/netopeer2-cli.1 @@ -935,7 +935,7 @@ Manage the user knownhosts file where all the known SSH server host keys are sto .PP .B knownhosts -[\-\-help] [\-\-del ] +(\-\-help | \-\-del | \-\-mode ) .PP .RS 4 @@ -948,6 +948,23 @@ a modified host key. .RE .PP +.B \-\-(m)ode +\fIaccept|accept-new|ask|skip|strict\fR +.RS 4 +Set the host key checking mode used when connecting over SSH. +.IP accept +Add the host key to the knownhosts file without prompting and allow connections to servers that changed their host key. +.IP accept-new +Add the host key to the knownhosts file without prompting, but only if it is not already there. +.IP \fIask\fR +Prompt the user to accept the host key. This is the default mode. +.IP skip +Skip the host key and do not add it to the knownhosts file. +.IP strict +Do not add the host key to the knownhosts file and refuse to connect to hosts whose host key is not known or has changed. +.RE +.PP + .SS listen Listen for a NETCONF Call Home connection.