2121#include <netinet/in.h>
2222#include <netinet/tcp.h>
2323#include <pthread.h>
24+ #include <stdarg.h>
2425#include <stdlib.h>
2526#include <string.h>
2627#include <sys/socket.h>
@@ -1224,6 +1225,10 @@ nc_add_cpblt(const char *capab, char ***cpblts, uint32_t *count)
12241225 }
12251226
12261227 (* cpblts )[* count ] = strdup (capab );
1228+ if (!(* cpblts )[* count ]) {
1229+ ERRMEM ;
1230+ return -1 ;
1231+ }
12271232 ++ (* count );
12281233
12291234 /* terminating NULL */
@@ -1232,6 +1237,46 @@ nc_add_cpblt(const char *capab, char ***cpblts, uint32_t *count)
12321237 return 0 ;
12331238}
12341239
1240+ /**
1241+ * @brief Append string to a string buffer.
1242+ *
1243+ * @param[in,out] str String to append to.
1244+ * @param[in,out] used Used bytes of @p str excluding the terminating 0 byte.
1245+ * @param[in,out] size Size of @p str.
1246+ * @param[in] app_format Format string to append.
1247+ * @param[in] ... Format string arguments.
1248+ * @return 0 on success,
1249+ * @return -1 on error.
1250+ */
1251+ static int
1252+ nc_str_append (char * * str , uint32_t * used , uint32_t * size , const char * app_format , ...)
1253+ {
1254+ va_list ap ;
1255+ int r ;
1256+
1257+ /* try to append */
1258+ va_start (ap , app_format );
1259+ r = vsnprintf (* str + * used , * size - * used , app_format , ap );
1260+ va_end (ap );
1261+
1262+ if (* used + r >= * size ) {
1263+ /* enlarge */
1264+ * str = nc_realloc (* str , * used + r + 1 );
1265+ NC_CHECK_ERRMEM_RET (!* str , -1 );
1266+
1267+ * size = * used + r + 1 ;
1268+
1269+ /* append */
1270+ va_start (ap , app_format );
1271+ * used += vsnprintf (* str + * used , * size - * used , app_format , ap );
1272+ va_end (ap );
1273+ } else {
1274+ * used += r ;
1275+ }
1276+
1277+ return 0 ;
1278+ }
1279+
12351280/**
12361281 * @brief Get the server capabilities.
12371282 *
@@ -1245,15 +1290,11 @@ _nc_server_get_cpblts_version(const struct ly_ctx *ctx, LYS_VERSION version, int
12451290{
12461291 char * * cpblts ;
12471292 const struct lys_module * mod ;
1248- const char * feat ;
1249- int features_count = 0 , dev_count = 0 , str_len , len ;
1250- uint32_t i , count ;
1293+ uint32_t i , count , str_used = 0 , str_size = 0 ;
12511294 LY_ARRAY_COUNT_TYPE v ;
12521295 char * yl_content_id = NULL ;
12531296 uint32_t wd_also_supported , wd_basic_mode ;
1254-
1255- #define NC_CPBLT_BUF_LEN 4096
1256- char str [NC_CPBLT_BUF_LEN ];
1297+ char * str = NULL ;
12571298
12581299 NC_CHECK_ARG_RET (NULL , ctx , NULL );
12591300
@@ -1310,16 +1351,18 @@ _nc_server_get_cpblts_version(const struct ly_ctx *ctx, LYS_VERSION version, int
13101351 VRB (NULL , "with-defaults capability will not be advertised even though \"ietf-netconf-with-defaults\" "
13111352 "model is present, unknown basic-mode." );
13121353 } else {
1313- strcpy (str , "urn:ietf:params:netconf:capability:with-defaults:1.0" );
1354+ str_used = 0 ;
1355+ NC_CHECK_GOTO (nc_str_append (& str , & str_used , & str_size , "urn:ietf:params:netconf:capability:with-defaults:1.0" ),
1356+ unlock_error );
13141357 switch (wd_basic_mode ) {
13151358 case NC_WD_ALL :
1316- strcat ( str , "?basic-mode=report-all" );
1359+ NC_CHECK_GOTO ( nc_str_append ( & str , & str_used , & str_size , "?basic-mode=report-all" ), unlock_error );
13171360 break ;
13181361 case NC_WD_TRIM :
1319- strcat ( str , "?basic-mode=trim" );
1362+ NC_CHECK_GOTO ( nc_str_append ( & str , & str_used , & str_size , "?basic-mode=trim" ), unlock_error );
13201363 break ;
13211364 case NC_WD_EXPLICIT :
1322- strcat ( str , "?basic-mode=explicit" );
1365+ NC_CHECK_GOTO ( nc_str_append ( & str , & str_used , & str_size , "?basic-mode=explicit" ), unlock_error );
13231366 break ;
13241367 default :
13251368 ERRINT ;
@@ -1328,29 +1371,30 @@ _nc_server_get_cpblts_version(const struct ly_ctx *ctx, LYS_VERSION version, int
13281371
13291372 wd_also_supported = server_opts .wd_also_supported ;
13301373 if (wd_also_supported ) {
1331- strcat ( str , "&also-supported=" );
1374+ NC_CHECK_GOTO ( nc_str_append ( & str , & str_used , & str_size , "&also-supported=" ), unlock_error );
13321375 if (wd_also_supported & NC_WD_ALL ) {
1333- strcat ( str , "report-all," );
1376+ NC_CHECK_GOTO ( nc_str_append ( & str , & str_used , & str_size , "report-all," ), unlock_error );
13341377 }
13351378 if (wd_also_supported & NC_WD_ALL_TAG ) {
1336- strcat ( str , "report-all-tagged," );
1379+ NC_CHECK_GOTO ( nc_str_append ( & str , & str_used , & str_size , "report-all-tagged," ), unlock_error );
13371380 }
13381381 if (wd_also_supported & NC_WD_TRIM ) {
1339- strcat ( str , "trim," );
1382+ NC_CHECK_GOTO ( nc_str_append ( & str , & str_used , & str_size , "trim," ), unlock_error );
13401383 }
13411384 if (wd_also_supported & NC_WD_EXPLICIT ) {
1342- strcat ( str , "explicit," );
1385+ NC_CHECK_GOTO ( nc_str_append ( & str , & str_used , & str_size , "explicit," ), unlock_error );
13431386 }
1344- str [strlen (str ) - 1 ] = '\0' ;
1387+ str [str_used ] = '\0' ;
1388+ -- str_used ;
13451389
1346- NC_CHECK_GOTO (nc_add_cpblt (str , & cpblts , & count ), error );
1390+ NC_CHECK_GOTO (nc_add_cpblt (str , & cpblts , & count ), unlock_error );
13471391 }
13481392 }
13491393 }
13501394
13511395 /* other capabilities */
13521396 for (i = 0 ; i < server_opts .capabilities_count ; i ++ ) {
1353- NC_CHECK_GOTO (nc_add_cpblt (server_opts .capabilities [i ], & cpblts , & count ), error );
1397+ NC_CHECK_GOTO (nc_add_cpblt (server_opts .capabilities [i ], & cpblts , & count ), unlock_error );
13541398 }
13551399
13561400 /* models */
@@ -1379,14 +1423,18 @@ _nc_server_get_cpblts_version(const struct ly_ctx *ctx, LYS_VERSION version, int
13791423
13801424 if (!strcmp (mod -> revision , "2019-01-04" )) {
13811425 /* new one (capab defined in RFC 8526 section 2) */
1382- sprintf (str , "urn:ietf:params:netconf:capability:yang-library:1.1?revision=%s&content-id=%s" ,
1383- mod -> revision , yl_content_id );
1384- NC_CHECK_GOTO (nc_add_cpblt (str , & cpblts , & count ), error );
1426+ str_used = 0 ;
1427+ NC_CHECK_GOTO (nc_str_append (& str , & str_used , & str_size ,
1428+ "urn:ietf:params:netconf:capability:yang-library:1.1?revision=%s&content-id=%s" ,
1429+ mod -> revision , yl_content_id ), unlock_error );
1430+ NC_CHECK_GOTO (nc_add_cpblt (str , & cpblts , & count ), unlock_error );
13851431 } else {
13861432 /* old one (capab defined in RFC 7950 section 5.6.4) */
1387- sprintf (str , "urn:ietf:params:netconf:capability:yang-library:1.0?revision=%s&module-set-id=%s" ,
1388- mod -> revision , yl_content_id );
1389- NC_CHECK_GOTO (nc_add_cpblt (str , & cpblts , & count ), error );
1433+ str_used = 0 ;
1434+ NC_CHECK_GOTO (nc_str_append (& str , & str_used , & str_size ,
1435+ "urn:ietf:params:netconf:capability:yang-library:1.0?revision=%s&module-set-id=%s" ,
1436+ mod -> revision , yl_content_id ), unlock_error );
1437+ NC_CHECK_GOTO (nc_add_cpblt (str , & cpblts , & count ), unlock_error );
13901438 }
13911439 free (yl_content_id );
13921440 yl_content_id = NULL ;
@@ -1396,58 +1444,37 @@ _nc_server_get_cpblts_version(const struct ly_ctx *ctx, LYS_VERSION version, int
13961444 continue ;
13971445 }
13981446
1399- str_len = sprintf (str , "%s?module=%s%s%s" , mod -> ns , mod -> name , mod -> revision ? "&revision=" : "" ,
1400- mod -> revision ? mod -> revision : "" );
1447+ str_used = 0 ;
1448+ NC_CHECK_GOTO (nc_str_append (& str , & str_used , & str_size , "%s?module=%s%s%s" , mod -> ns , mod -> name ,
1449+ mod -> revision ? "&revision=" : "" , mod -> revision ? mod -> revision : "" ), unlock_error );
14011450
14021451 if (mod -> compiled ) {
1403- features_count = 0 ;
14041452 LY_ARRAY_FOR (mod -> compiled -> features , v ) {
1405- feat = mod -> compiled -> features [ v ];
1406- if (! features_count ) {
1407- strcat ( str , "&features=" );
1408- str_len += 10 ;
1453+ if (! v ) {
1454+ NC_CHECK_GOTO ( nc_str_append ( & str , & str_used , & str_size , "&features=" ), unlock_error );
1455+ } else {
1456+ NC_CHECK_GOTO ( nc_str_append ( & str , & str_used , & str_size , "," ), unlock_error ) ;
14091457 }
1410- len = strlen (feat );
1411- if (str_len + 1 + len >= NC_CPBLT_BUF_LEN ) {
1412- ERRINT ;
1413- break ;
1414- }
1415- if (features_count ) {
1416- strcat (str , "," );
1417- ++ str_len ;
1418- }
1419- strcat (str , feat );
1420- str_len += len ;
1421- features_count ++ ;
1458+ NC_CHECK_GOTO (nc_str_append (& str , & str_used , & str_size , mod -> compiled -> features [v ]), unlock_error );
14221459 }
14231460 }
14241461
1425- if (mod -> deviated_by ) {
1426- strcat (str , "&deviations=" );
1427- str_len += 12 ;
1428- dev_count = 0 ;
1429- LY_ARRAY_FOR (mod -> deviated_by , v ) {
1430- len = strlen (mod -> deviated_by [v ]-> name );
1431- if (str_len + 1 + len >= NC_CPBLT_BUF_LEN ) {
1432- ERRINT ;
1433- break ;
1434- }
1435- if (dev_count ) {
1436- strcat (str , "," );
1437- ++ str_len ;
1438- }
1439- strcat (str , mod -> deviated_by [v ]-> name );
1440- str_len += len ;
1441- dev_count ++ ;
1462+ LY_ARRAY_FOR (mod -> deviated_by , v ) {
1463+ if (!v ) {
1464+ NC_CHECK_GOTO (nc_str_append (& str , & str_used , & str_size , "&deviations=" ), unlock_error );
1465+ } else {
1466+ NC_CHECK_GOTO (nc_str_append (& str , & str_used , & str_size , "," ), unlock_error );
14421467 }
1468+ NC_CHECK_GOTO (nc_str_append (& str , & str_used , & str_size , mod -> deviated_by [v ]-> name ), unlock_error );
14431469 }
14441470
1445- NC_CHECK_GOTO (nc_add_cpblt (str , & cpblts , & count ), error );
1471+ NC_CHECK_GOTO (nc_add_cpblt (str , & cpblts , & count ), unlock_error );
14461472 }
14471473
14481474 /* HELLO UNLOCK */
14491475 nc_rwlock_unlock (& server_opts .hello_lock , __func__ );
14501476
1477+ free (str );
14511478 return cpblts ;
14521479
14531480unlock_error :
@@ -1462,6 +1489,7 @@ _nc_server_get_cpblts_version(const struct ly_ctx *ctx, LYS_VERSION version, int
14621489 free (cpblts );
14631490 }
14641491 free (yl_content_id );
1492+ free (str );
14651493 return NULL ;
14661494}
14671495
0 commit comments