Skip to content

Commit 81242fe

Browse files
romanmichalvasko
authored andcommitted
session client ssh ch UPDATE add knownhosts API
1 parent 848bdaa commit 81242fe

File tree

5 files changed

+107
-26
lines changed

5 files changed

+107
-26
lines changed

src/session_client.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,13 +78,15 @@ static struct nc_client_context context_main = {
7878
.auth_pref = {{NC_SSH_AUTH_INTERACTIVE, 1}, {NC_SSH_AUTH_PASSWORD, 2}, {NC_SSH_AUTH_PUBLICKEY, 3}},
7979
.auth_password = sshauth_password,
8080
.auth_interactive = sshauth_interactive,
81-
.auth_privkey_passphrase = sshauth_privkey_passphrase
81+
.auth_privkey_passphrase = sshauth_privkey_passphrase,
82+
.knownhosts_mode = NC_SSH_KNOWNHOSTS_ASK
8283
},
8384
.ssh_ch_opts = {
8485
.auth_pref = {{NC_SSH_AUTH_INTERACTIVE, 1}, {NC_SSH_AUTH_PASSWORD, 2}, {NC_SSH_AUTH_PUBLICKEY, 3}},
8586
.auth_password = sshauth_password,
8687
.auth_interactive = sshauth_interactive,
87-
.auth_privkey_passphrase = sshauth_privkey_passphrase
88+
.auth_privkey_passphrase = sshauth_privkey_passphrase,
89+
.knownhosts_mode = NC_SSH_KNOWNHOSTS_ASK
8890
},
8991
#endif /* NC_ENABLED_SSH_TLS */
9092
/* .tls_ structures zeroed */

src/session_client.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,8 @@ struct nc_session *nc_connect_unix(const char *address, struct ly_ctx *ctx);
190190
/**
191191
* @brief Set the behaviour of checking the host key and adding/reading entries to/from the known_hosts file.
192192
*
193+
* The default mode is ::NC_SSH_KNOWNHOSTS_ASK.
194+
*
193195
* @param[in] mode Server host key checking mode.
194196
*/
195197
void nc_client_ssh_set_knownhosts_mode(NC_SSH_KNOWNHOSTS_MODE mode);

src/session_client_ch.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,27 @@ int nc_accept_callhome(int timeout, struct ly_ctx *ctx, struct nc_session **sess
6363
* @{
6464
*/
6565

66+
/**
67+
* @brief Set SSH Call Home behaviour of checking the host key and adding/reading entries to/from the known_hosts file.
68+
*
69+
* The default mode is ::NC_SSH_KNOWNHOSTS_ASK.
70+
*
71+
* @param[in] mode Server host key checking mode.
72+
*/
73+
void nc_client_ssh_ch_set_knownhosts_mode(NC_SSH_KNOWNHOSTS_MODE mode);
74+
75+
/**
76+
* @brief Set SSH Call Home path to the known_hosts file for connections.
77+
*
78+
* Repetetive calling replaces the value. If the given file doesn't exist and the process has sufficient
79+
* rights, it gets created whenever the file is needed, otherwise an error occurs. If NULL is passed or the
80+
* path isn't set, the default known_hosts file will be used.
81+
*
82+
* @param[in] path Path to the known_hosts file.
83+
* @return 0 on success, 1 on error.
84+
*/
85+
int nc_client_ssh_ch_set_knownhosts_path(const char *path);
86+
6687
/**
6788
* @brief Set SSH Call Home password authentication callback.
6889
*

src/session_client_ssh.c

Lines changed: 79 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -401,12 +401,56 @@ nc_client_ssh_do_dnssec_sshfp_check(ssh_session session, enum ssh_keytypes_e srv
401401

402402
#endif
403403

404+
/**
405+
* @brief Convert knownhosts mode to string.
406+
*
407+
* @param[in] knownhosts_mode Knownhosts mode.
408+
* @return Knownhosts mode string.
409+
*/
410+
static const char *
411+
nc_client_ssh_knownhosts_mode2str(NC_SSH_KNOWNHOSTS_MODE knownhosts_mode)
412+
{
413+
const char *mode_str;
414+
415+
switch (knownhosts_mode) {
416+
case NC_SSH_KNOWNHOSTS_ASK:
417+
mode_str = "ask";
418+
break;
419+
case NC_SSH_KNOWNHOSTS_STRICT:
420+
mode_str = "strict";
421+
break;
422+
case NC_SSH_KNOWNHOSTS_ACCEPT_NEW:
423+
mode_str = "accept-new";
424+
break;
425+
case NC_SSH_KNOWNHOSTS_ACCEPT:
426+
mode_str = "accept";
427+
break;
428+
case NC_SSH_KNOWNHOSTS_SKIP:
429+
mode_str = "skip";
430+
break;
431+
default:
432+
mode_str = "unknown";
433+
break;
434+
}
435+
436+
return mode_str;
437+
}
438+
439+
/**
440+
* @brief Perform the hostkey check.
441+
*
442+
* @param[in] hostname Expected hostname.
443+
* @param[in] port Expected port.
444+
* @param[in] knownhosts_mode Knownhosts mode.
445+
* @param[in] session libssh session.
446+
* @return 0 on success, -1 on error.
447+
*/
404448
static int
405-
nc_client_ssh_auth_hostkey_check(const char *hostname, uint16_t port, ssh_session session)
449+
nc_client_ssh_auth_hostkey_check(const char *hostname, uint16_t port,
450+
NC_SSH_KNOWNHOSTS_MODE knownhosts_mode, ssh_session session)
406451
{
407452
char *hexa = NULL;
408453
unsigned char *hash_sha1 = NULL;
409-
NC_SSH_KNOWNHOSTS_MODE knownhosts_mode = ssh_opts.knownhosts_mode;
410454
enum ssh_keytypes_e srv_pubkey_type;
411455
int state;
412456

@@ -420,6 +464,8 @@ nc_client_ssh_auth_hostkey_check(const char *hostname, uint16_t port, ssh_sessio
420464
int dnssec_ret;
421465
#endif
422466

467+
VRB(NULL, "Server hostkey check mode: %s.", nc_client_ssh_knownhosts_mode2str(knownhosts_mode));
468+
423469
if (knownhosts_mode == NC_SSH_KNOWNHOSTS_SKIP) {
424470
/* skip all hostkey checks */
425471
return 0;
@@ -744,28 +790,46 @@ sshauth_privkey_passphrase(const char *privkey_path, void *UNUSED(priv))
744790
#endif
745791
}
746792

747-
API int
748-
nc_client_ssh_set_knownhosts_path(const char *path)
793+
static int
794+
_nc_client_ssh_set_knownhosts_path(const char *path, struct nc_client_ssh_opts *opts)
749795
{
750-
free(ssh_opts.knownhosts_path);
796+
free(opts->knownhosts_path);
751797

752798
if (!path) {
753-
ssh_opts.knownhosts_path = NULL;
799+
opts->knownhosts_path = NULL;
754800
return 0;
755801
}
756802

757-
ssh_opts.knownhosts_path = strdup(path);
758-
NC_CHECK_ERRMEM_RET(!ssh_opts.knownhosts_path, 1);
803+
opts->knownhosts_path = strdup(path);
804+
NC_CHECK_ERRMEM_RET(!opts->knownhosts_path, 1);
759805

760806
return 0;
761807
}
762808

809+
API int
810+
nc_client_ssh_set_knownhosts_path(const char *path)
811+
{
812+
return _nc_client_ssh_set_knownhosts_path(path, &ssh_opts);
813+
}
814+
815+
API int
816+
nc_client_ssh_ch_set_knownhosts_path(const char *path)
817+
{
818+
return _nc_client_ssh_set_knownhosts_path(path, &ssh_ch_opts);
819+
}
820+
763821
API void
764822
nc_client_ssh_set_knownhosts_mode(NC_SSH_KNOWNHOSTS_MODE mode)
765823
{
766824
ssh_opts.knownhosts_mode = mode;
767825
}
768826

827+
API void
828+
nc_client_ssh_ch_set_knownhosts_mode(NC_SSH_KNOWNHOSTS_MODE mode)
829+
{
830+
ssh_ch_opts.knownhosts_mode = mode;
831+
}
832+
769833
static void
770834
_nc_client_ssh_set_auth_password_clb(char *(*auth_password)(const char *username, const char *hostname, void *priv),
771835
void *priv, struct nc_client_ssh_opts *opts)
@@ -1254,7 +1318,7 @@ connect_ssh_session(struct nc_session *session, struct nc_client_ssh_opts *opts,
12541318
return -1;
12551319
}
12561320

1257-
if (nc_client_ssh_auth_hostkey_check(session->host, session->port, ssh_sess)) {
1321+
if (nc_client_ssh_auth_hostkey_check(session->host, session->port, opts->knownhosts_mode, ssh_sess)) {
12581322
ERR(session, "Checking the host key failed.");
12591323
return -1;
12601324
}
@@ -1701,7 +1765,6 @@ nc_connect_ssh(const char *host, uint16_t port, struct ly_ctx *ctx)
17011765
struct nc_session *session = NULL;
17021766
char *buf = NULL;
17031767
size_t buf_len = 0;
1704-
char *known_hosts_path = NULL;
17051768

17061769
/* process parameters */
17071770
if (!host || (host[0] == '\0')) {
@@ -1727,15 +1790,6 @@ nc_connect_ssh(const char *host, uint16_t port, struct ly_ctx *ctx)
17271790
pw = nc_getpw(0, username, &pw_buf, &buf, &buf_len);
17281791
}
17291792

1730-
if (ssh_opts.knownhosts_path) {
1731-
/* known_hosts file path was set so use it */
1732-
known_hosts_path = strdup(ssh_opts.knownhosts_path);
1733-
NC_CHECK_ERRMEM_GOTO(!known_hosts_path, , fail);
1734-
} else if (pw) {
1735-
/* path not set explicitly, but current user's username found in /etc/passwd, so create the path */
1736-
NC_CHECK_ERRMEM_GOTO(asprintf(&known_hosts_path, "%s/.ssh/known_hosts", pw->pw_dir) == -1, , fail);
1737-
}
1738-
17391793
/* prepare session structure */
17401794
session = nc_new_session(NC_CLIENT, 0);
17411795
NC_CHECK_ERRMEM_GOTO(!session, , fail);
@@ -1757,8 +1811,8 @@ nc_connect_ssh(const char *host, uint16_t port, struct ly_ctx *ctx)
17571811
ssh_options_set(session->ti.libssh.session, SSH_OPTIONS_PORT, &port_uint);
17581812
ssh_options_set(session->ti.libssh.session, SSH_OPTIONS_USER, username);
17591813
ssh_options_set(session->ti.libssh.session, SSH_OPTIONS_TIMEOUT, &timeout);
1760-
if (known_hosts_path) {
1761-
ssh_options_set(session->ti.libssh.session, SSH_OPTIONS_KNOWNHOSTS, known_hosts_path);
1814+
if (ssh_opts.knownhosts_path) {
1815+
ssh_options_set(session->ti.libssh.session, SSH_OPTIONS_KNOWNHOSTS, ssh_opts.knownhosts_path);
17621816
}
17631817

17641818
/* create and assign communication socket */
@@ -1800,12 +1854,10 @@ nc_connect_ssh(const char *host, uint16_t port, struct ly_ctx *ctx)
18001854
session->port = port;
18011855

18021856
free(buf);
1803-
free(known_hosts_path);
18041857
return session;
18051858

18061859
fail:
18071860
free(buf);
1808-
free(known_hosts_path);
18091861
free(ip_host);
18101862
nc_session_free(session, NULL);
18111863
return NULL;
@@ -1922,6 +1974,10 @@ nc_accept_callhome_ssh_sock(int sock, const char *host, uint16_t port, struct ly
19221974
ssh_options_set(sess, SSH_OPTIONS_USER, ssh_ch_opts.username);
19231975
}
19241976

1977+
if (ssh_ch_opts.knownhosts_path) {
1978+
ssh_options_set(sess, SSH_OPTIONS_KNOWNHOSTS, ssh_ch_opts.knownhosts_path);
1979+
}
1980+
19251981
ssh_options_set(sess, SSH_OPTIONS_HOSTKEYS, "ssh-ed25519,ecdsa-sha2-nistp256,"
19261982
"ecdsa-sha2-nistp384,ecdsa-sha2-nistp521,ssh-rsa,rsa-sha2-512,rsa-sha2-256,ssh-dss");
19271983
#ifdef HAVE_LIBSSH_OPTIONS_PUBLICKEY_ACCEPTED_TYPES

tests/test_ch.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ client_thread_ssh(void *arg)
132132
struct ln2_test_ctx *test_ctx = arg;
133133

134134
/* skip all hostkey and known_hosts checks */
135-
nc_client_ssh_set_knownhosts_mode(NC_SSH_KNOWNHOSTS_SKIP);
135+
nc_client_ssh_ch_set_knownhosts_mode(NC_SSH_KNOWNHOSTS_SKIP);
136136

137137
/* set directory where to search for modules */
138138
ret = nc_client_set_schema_searchpath(MODULES_DIR);

0 commit comments

Comments
 (0)