@@ -1084,6 +1084,68 @@ nc_server_ssh_set_authkey_path_format(const char *path)
10841084 return ret ;
10851085}
10861086
1087+ /**
1088+ * @brief Forge the SSH protocol identification string based on the given prefix and the library versions.
1089+ *
1090+ * @param[in] prefix Optional prefix to include in the protocol string, can be NULL.
1091+ * @return Protocol string on success, NULL on error.
1092+ */
1093+ static char *
1094+ nc_server_ssh_forge_protocol_string (const char * prefix )
1095+ {
1096+ int r ;
1097+ char * protocol_str = NULL ;
1098+
1099+ if (prefix ) {
1100+ r = asprintf (& protocol_str , "%s-libnetconf2_%s-libssh_%d.%d.%d" ,
1101+ prefix , NC_VERSION ,
1102+ LIBSSH_VERSION_MAJOR , LIBSSH_VERSION_MINOR , LIBSSH_VERSION_MICRO );
1103+ } else {
1104+ r = asprintf (& protocol_str , "libnetconf2_%s-libssh_%d.%d.%d" ,
1105+ NC_VERSION ,
1106+ LIBSSH_VERSION_MAJOR , LIBSSH_VERSION_MINOR , LIBSSH_VERSION_MICRO );
1107+ }
1108+ NC_CHECK_ERRMEM_RET (r == -1 , NULL );
1109+
1110+ if (strlen (protocol_str ) > 245 ) {
1111+ ERR (NULL , "SSH protocol identification string too long (max 245 characters)." );
1112+ free (protocol_str );
1113+ return NULL ;
1114+ }
1115+
1116+ return protocol_str ;
1117+ }
1118+
1119+ API int
1120+ nc_server_ssh_set_protocol_string (const char * prefix )
1121+ {
1122+ int rc = 0 ;
1123+ char * protocol_str = NULL ;
1124+
1125+ NC_CHECK_ARG_RET (NULL , prefix , 1 );
1126+
1127+ protocol_str = nc_server_ssh_forge_protocol_string (prefix );
1128+ NC_CHECK_ERRMEM_GOTO (!protocol_str , rc = 1 , cleanup );
1129+
1130+ /* CONFIG LOCK */
1131+ if (nc_rwlock_lock (& server_opts .config_lock , NC_RWLOCK_WRITE , NC_CONFIG_LOCK_TIMEOUT , __func__ ) != 1 ) {
1132+ rc = 1 ;
1133+ goto cleanup ;
1134+ }
1135+
1136+ /* transfer ownership */
1137+ free (server_opts .ssh_protocol_string );
1138+ server_opts .ssh_protocol_string = protocol_str ;
1139+ protocol_str = NULL ;
1140+
1141+ /* CONFIG UNLOCK */
1142+ nc_rwlock_unlock (& server_opts .config_lock , __func__ );
1143+
1144+ cleanup :
1145+ free (protocol_str );
1146+ return rc ;
1147+ }
1148+
10871149/**
10881150 * @brief Get the public key type from binary data.
10891151 *
@@ -1206,22 +1268,42 @@ nc_server_ssh_auth_pubkey_compare_key(ssh_key key, struct nc_public_key *pubkeys
12061268/**
12071269 * @brief Handle authentication request for the None method.
12081270 *
1271+ * @param[in] session NETCONF session.
1272+ * @param[in] banner SSH banner to send to the client, if any.
12091273 * @param[in] local_users_supported Whether the server supports local users.
12101274 * @param[in] auth_client Configured client's authentication data.
12111275 * @param[in] msg libssh message.
12121276 * @return 0 if the authentication was successful, -1 if not (@p msg already replied to).
12131277 */
12141278static int
1215- nc_server_ssh_auth_none (int local_users_supported , struct nc_auth_client * auth_client , ssh_message msg )
1279+ nc_server_ssh_auth_none (struct nc_session * session , const char * banner , int local_users_supported ,
1280+ struct nc_auth_client * auth_client , ssh_message msg )
12161281{
12171282 assert (!local_users_supported || auth_client );
12181283
1284+ #if (LIBSSH_VERSION_MAJOR > 0 ) || (LIBSSH_VERSION_MAJOR == 0 && LIBSSH_VERSION_MINOR >= 10 )
1285+ ssh_string ban ;
1286+
1287+ /* send the SSH banner if set, as a client just requested authentication and this is the right time to send it */
1288+ if (banner ) {
1289+ ban = ssh_string_from_char (banner );
1290+ if (ban ) {
1291+ if (ssh_send_issue_banner (session -> ti .libssh .session , ban )) {
1292+ ERR (session , "Failed to send SSH banner (%s)." , ssh_get_error (session -> ti .libssh .session ));
1293+ }
1294+ ssh_string_free (ban );
1295+ }
1296+ }
1297+ #else
1298+ if (banner ) {
1299+ WRN (session , "SSH banner set but cannot be sent (libssh version 0.10.0 or later required)." );
1300+ }
1301+ #endif
1302+
12191303 if (local_users_supported && auth_client -> none_enabled ) {
1220- /* success */
12211304 return 0 ;
12221305 }
12231306
1224- /* reply and return -1 so that this does not get counted as an unsuccessful authentication attempt */
12251307 ssh_message_reply_default (msg );
12261308 return -1 ;
12271309}
@@ -1602,7 +1684,7 @@ nc_server_ssh_auth(struct nc_session *session, struct nc_server_ssh_opts *opts,
16021684 * configured auth methods, otherwise for system users just one is needed,
16031685 * 0 return indicates success, 1 fail (msg not yet replied to), -1 fail (msg was replied to) */
16041686 if (method == SSH_AUTH_METHOD_NONE ) {
1605- ret = nc_server_ssh_auth_none (local_users_supported , auth_client , msg );
1687+ ret = nc_server_ssh_auth_none (session , opts -> banner , local_users_supported , auth_client , msg );
16061688 } else if (method == SSH_AUTH_METHOD_PASSWORD ) {
16071689 ret = nc_server_ssh_auth_password (session , local_users_supported , auth_client , msg );
16081690 } else if (method == SSH_AUTH_METHOD_PUBLICKEY ) {
@@ -1972,7 +2054,8 @@ nc_accept_ssh_session(struct nc_session *session, struct nc_server_ssh_opts *opt
19722054 ssh_bind sbind = NULL ;
19732055 int rc = 1 , r ;
19742056 struct timespec ts_timeout ;
1975- const char * err_msg , * banner ;
2057+ const char * err_msg ;
2058+ char * proto_str = NULL , * proto_str_dyn = NULL ;
19762059
19772060 /* other transport-specific data */
19782061 session -> ti_type = NC_TI_SSH ;
@@ -2031,13 +2114,15 @@ nc_accept_ssh_session(struct nc_session *session, struct nc_server_ssh_opts *opt
20312114 }
20322115 }
20332116
2034- /* configure the ssh banner */
2035- if (opts -> banner ) {
2036- banner = opts -> banner ;
2117+ /* configure the ssh protocol identification string */
2118+ if (server_opts . ssh_protocol_string ) {
2119+ proto_str = server_opts . ssh_protocol_string ;
20372120 } else {
2038- banner = "libnetconf2-" NC_VERSION ;
2121+ proto_str_dyn = nc_server_ssh_forge_protocol_string (NULL );
2122+ NC_CHECK_ERRMEM_GOTO (!proto_str_dyn , rc = -1 , cleanup );
2123+ proto_str = proto_str_dyn ;
20392124 }
2040- if (ssh_bind_options_set (sbind , SSH_BIND_OPTIONS_BANNER , banner )) {
2125+ if (ssh_bind_options_set (sbind , SSH_BIND_OPTIONS_BANNER , proto_str )) {
20412126 rc = -1 ;
20422127 goto cleanup ;
20432128 }
@@ -2112,6 +2197,7 @@ nc_accept_ssh_session(struct nc_session *session, struct nc_server_ssh_opts *opt
21122197 if (sock > -1 ) {
21132198 close (sock );
21142199 }
2200+ free (proto_str_dyn );
21152201 ssh_bind_free (sbind );
21162202 return rc ;
21172203}
0 commit comments