From 71a8d5de558a3c8238c64428f4f363c785ef089a Mon Sep 17 00:00:00 2001 From: Olof hagsand Date: Sun, 28 Jan 2024 17:07:44 +0100 Subject: [PATCH] New: [SSH StrictHostKeyChecking optional](https://github.com/clicon/clixon-controller/issues/96) --- CHANGELOG.md | 4 ++++ src/controller_device_handle.c | 6 +++-- src/controller_device_handle.h | 3 ++- src/controller_netconf.c | 22 +++++++++++++----- src/controller_netconf.h | 2 +- src/controller_rpc.c | 31 +++++++++++++++++--------- test/test-connect.sh | 4 ++++ yang/clixon-controller@2024-01-01.yang | 19 +++++++++++----- 8 files changed, 67 insertions(+), 24 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index af555fb..683d65e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ Expected: February 2024 ### New features +* New: [SSH StrictHostKeyChecking optional](https://github.com/clicon/clixon-controller/issues/96) * Replaced creator attributes with a configured solution * New: [show creator paths associated to service instance](https://github.com/clicon/clixon-controller/issues/90) * See https://clixon-controller-docs.readthedocs.io/en/latest/cli.html#creators @@ -27,6 +28,9 @@ Expected: February 2024 * `apply [template|services]` * New `clixon-controller@2024-01-01.yang` revision * Added warning field to transaction + * Added created-by-service grouping + * Added service-instance parameter to rpc controller-commit + * Added ssh-stricthostkey ### Corrected Bugs diff --git a/src/controller_device_handle.c b/src/controller_device_handle.c index d7a70b6..896128d 100644 --- a/src/controller_device_handle.c +++ b/src/controller_device_handle.c @@ -279,6 +279,7 @@ device_handle_each(clixon_handle h, * @param[in] h Clixon handle * @param[in] socktype Type of socket, internal/external/netconf/ssh * @param[in] dest Destination for some types + * @param[in] stricthostkey If set ensure strict hostkey checking. Only for ssh connections * @retval dh Clixon session handler * @retval NULL Error * @see clixon_client_disconnect Close the socket returned here @@ -286,7 +287,8 @@ device_handle_each(clixon_handle h, int device_handle_connect(device_handle dh, clixon_client_type socktype, - const char *dest) + const char *dest, + int stricthostkey) { int retval = -1; struct controller_device_handle *cdh = (struct controller_device_handle *)dh; @@ -310,7 +312,7 @@ device_handle_connect(device_handle dh, break; #ifdef SSH_BIN case CLIXON_CLIENT_SSH: - if (clixon_client_connect_ssh(h, dest, &cdh->cdh_pid, &cdh->cdh_socket) < 0) + if (clixon_client_connect_ssh(h, dest, stricthostkey, &cdh->cdh_pid, &cdh->cdh_socket) < 0) goto err; #else clixon_err(OE_UNIX, 0, "No ssh bin"); diff --git a/src/controller_device_handle.h b/src/controller_device_handle.h index 6cfb9f8..977cc72 100644 --- a/src/controller_device_handle.h +++ b/src/controller_device_handle.h @@ -56,7 +56,8 @@ int device_handle_free(device_handle dh); int device_handle_free_all(clixon_handle h); device_handle device_handle_find(clixon_handle h, const char *name); device_handle device_handle_each(clixon_handle h, device_handle dhprev); -int device_handle_connect(device_handle dh, clixon_client_type socktype, const char *dest); +int device_handle_connect(device_handle dh, clixon_client_type socktype, const char *dest, + int stricthostkey); int device_handle_disconnect(device_handle dh); /* Accessor functions */ diff --git a/src/controller_netconf.c b/src/controller_netconf.c index eaf5ade..2938396 100644 --- a/src/controller_netconf.c +++ b/src/controller_netconf.c @@ -112,12 +112,21 @@ clixon_client_connect_netconf(clixon_handle h, } /*! Connect using NETCONF over SSH + * + * @param[in] h Clixon handle + * @param[in] dest SSH destination + * @param[in] stricthostkey If set ensure strict hostkey checking. Only for ssh connections + * @param[out] pid Sub-process-id + * @param[out] sock Input/output socket + * @retval 0 OK + * @retval -1 Error */ int -clixon_client_connect_ssh(clixon_handle h, - const char *dest, - pid_t *pid, - int *sock) +clixon_client_connect_ssh(clixon_handle h, + const char *dest, + int stricthostkey, + pid_t *pid, + int *sock) { int retval = -1; int nr; @@ -141,7 +150,10 @@ clixon_client_connect_ssh(clixon_handle h, argv[i++] = (char*)dest; argv[i++] = "-T"; /* Disable pseudo-terminal allocation. */ argv[i++] = "-o"; - argv[i++] = "StrictHostKeyChecking=yes"; // dont ask + if (stricthostkey) + argv[i++] = "StrictHostKeyChecking=yes"; + else + argv[i++] = "StrictHostKeyChecking=no"; argv[i++] = "-o"; argv[i++] = "PasswordAuthentication=no"; // dont query argv[i++] = "-o"; diff --git a/src/controller_netconf.h b/src/controller_netconf.h index d28f8b2..70e0a59 100644 --- a/src/controller_netconf.h +++ b/src/controller_netconf.h @@ -44,7 +44,7 @@ extern "C" { #endif int clixon_client_connect_netconf(clixon_handle h, pid_t *pid, int *sock); -int clixon_client_connect_ssh(clixon_handle h, const char *dest, pid_t *pid, int *sock); +int clixon_client_connect_ssh(clixon_handle h, const char *dest, int stricthostkey, pid_t *pid, int *sock); #ifdef __cplusplus } diff --git a/src/controller_rpc.c b/src/controller_rpc.c index 5a8edfc..2e76d20 100644 --- a/src/controller_rpc.c +++ b/src/controller_rpc.c @@ -57,11 +57,11 @@ /*! Connect to device via Netconf SSH * - * @param[in] h Clixon handle - * @param[in] dh Device handle, either NULL or in closed state - * @param[in] name Device name - * @param[in] user Username for ssh login - * @param[in] addr Address for ssh to connect to + * @param[in] h Clixon handle + * @param[in] dh Device handle, either NULL or in closed state + * @param[in] user Username for ssh login + * @param[in] addr Address for ssh to connect to + * @param[in] stricthostkey If set ensure strict hostkey checking. Only for ssh * @retval 0 OK * @retval -1 Error */ @@ -69,7 +69,8 @@ static int connect_netconf_ssh(clixon_handle h, device_handle dh, char *user, - char *addr) + char *addr, + int stricthostkey) { int retval = -1; cbuf *cb = NULL; @@ -90,7 +91,7 @@ connect_netconf_ssh(clixon_handle h, if (user) cprintf(cb, "%s@", user); cprintf(cb, "%s", addr); - if (device_handle_connect(dh, CLIXON_CLIENT_SSH, cbuf_get(cb)) < 0) + if (device_handle_connect(dh, CLIXON_CLIENT_SSH, cbuf_get(cb), stricthostkey) < 0) goto done; if (device_state_set(dh, CS_CONNECTING) < 0) goto done; @@ -133,17 +134,19 @@ controller_connect(clixon_handle h, char *user = NULL; char *enablestr; char *yfstr; + char *str; cxobj *xb; cxobj *xdevprofile = NULL; cxobj *xmod = NULL; cxobj *xyanglib = NULL; + int ssh_stricthostkey = 1; clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__); if ((name = xml_find_body(xn, "name")) == NULL) goto ok; + dh = device_handle_find(h, name); /* can be NULL */ if ((enablestr = xml_find_body(xn, "enabled")) == NULL) goto ok; - dh = device_handle_find(h, name); /* can be NULL */ if (strcmp(enablestr, "false") == 0){ if ((dh = device_handle_new(h, name)) == NULL) goto done; @@ -181,6 +184,13 @@ controller_connect(clixon_handle h, } if (xb != NULL) user = xml_body(xb); + if ((xb = xml_find_type(xn, NULL, "ssh-stricthostkey", CX_ELMNT)) == NULL || + xml_flag(xb, XML_FLAG_DEFAULT)){ + if (xdevprofile) + xb = xml_find_type(xdevprofile, NULL, "ssh-stricthostkey", CX_ELMNT); + } + if (xb && (str = xml_body(xb)) != NULL) + ssh_stricthostkey = strcmp(str, "true") == 0; /* Now dh is either NULL or in closed state and with correct type * First create it if still NULL */ @@ -214,7 +224,7 @@ controller_connect(clixon_handle h, } /* Point of no return: assume errors handled in device_input_cb */ device_handle_tid_set(dh, ct->ct_id); - if (connect_netconf_ssh(h, dh, user, addr) < 0) /* match */ + if (connect_netconf_ssh(h, dh, user, addr, ssh_stricthostkey) < 0) /* match */ goto done; ok: retval = 1; @@ -1580,7 +1590,8 @@ rpc_connection_change(clixon_handle h, goto ok; } ct->ct_client_id = ce->ce_id; - if (xmldb_get(h, "running", nsc, "devices", &xret) < 0) + // XXX: Should work with WITHDEFAULTS_EXPLICIT? + if (xmldb_get0(h, "running", YB_MODULE, nsc, "devices", 1, WITHDEFAULTS_REPORT_ALL, &xret, NULL, NULL) < 0) goto done; if (xpath_vec(xret, nsc, "devices/device", &vec, &veclen) < 0) goto done; diff --git a/test/test-connect.sh b/test/test-connect.sh index 7653652..5e4146d 100755 --- a/test/test-connect.sh +++ b/test/test-connect.sh @@ -183,6 +183,10 @@ cmd="set devices device-profile myprofile user $USER" new "$cmd" expectpart "$($clixon_cli -1 -m configure -f $CFG $cmd)" 0 "^$" +cmd="set devices device-profile myprofile ssh-stricthostkey true" +new "$cmd" +expectpart "$($clixon_cli -1 -m configure -f $CFG $cmd)" 0 "^$" + cmd="set devices device-profile myprofile conn-type NETCONF_SSH" new "$cmd" expectpart "$($clixon_cli -1 -m configure -f $CFG $cmd)" 0 "^$" diff --git a/yang/clixon-controller@2024-01-01.yang b/yang/clixon-controller@2024-01-01.yang index 7568554..9e18069 100644 --- a/yang/clixon-controller@2024-01-01.yang +++ b/yang/clixon-controller@2024-01-01.yang @@ -33,6 +33,7 @@ module clixon-controller { "Added warning field to transaction Added created-by-service grouping Added service-instance parameter to rpc controller-commit + Added ssh-stricthostkey Released in 0.3.0"; } revision 2023-11-01 { @@ -305,6 +306,14 @@ module clixon-controller { type connection-type; default NETCONF_SSH; } + leaf ssh-stricthostkey { + when "../conn-type='NETCONF_SSH'"; + description + "If 0, do not, if 1, ensure strict hostkey checking + Only for ssh connections"; + type boolean; + default true; + } leaf yang-config{ description "How to bind device configuration to YANG."; type yang-config; @@ -476,6 +485,11 @@ module clixon-controller { type connection-state; default CLOSED; } + leaf conn-state-timestamp { + description "Timestamp when entering current state"; + config false; + type yang:date-and-time; + } container capabilities { description "May be duplicate if netconf-monitoring is implemented?"; @@ -486,11 +500,6 @@ module clixon-controller { "List of NETCONF capabilities supported by the server."; } } - leaf conn-state-timestamp { - description "Timestamp when entering current state"; - config false; - type yang:date-and-time; - } leaf sync-timestamp { description "Timestamp of last device synchronization"; config false;