From 7a35260b12125ac95a79ef72ea0d3af43f1d33fb Mon Sep 17 00:00:00 2001 From: George Baltz N3GB Date: Mon, 1 Jun 2026 10:58:50 -0400 Subject: [PATCH 1/7] Don't return more than the caller expected If more needed, call again. --- src/iofunc.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/iofunc.c b/src/iofunc.c index 6d38f1873..83f4ae795 100644 --- a/src/iofunc.c +++ b/src/iofunc.c @@ -1475,9 +1475,6 @@ shortcut: return -RIG_EIO; } - // check to see if our string starts with \...if so we need more chars - if (total_count == 0 && rxbuffer[total_count] == '\\') { rxmax = (rxmax - 1) * 5; } - total_count += (int) rd_count; if (total_count == rxmax) { break; } From fa6ae2adba24b068381a1c183b50c5e495bac88c Mon Sep 17 00:00:00 2001 From: George Baltz N3GB Date: Tue, 2 Jun 2026 11:46:22 -0400 Subject: [PATCH 2/7] Fix unterminated string Add debug print --- rigs/dummy/netrigctl.c | 6 +++++- security/password.c | 1 + 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/rigs/dummy/netrigctl.c b/rigs/dummy/netrigctl.c index b80326761..2e4b732d3 100644 --- a/rigs/dummy/netrigctl.c +++ b/rigs/dummy/netrigctl.c @@ -2766,7 +2766,11 @@ int netrigctl_password(RIG *rig, const char *key1) SNPRINTF(cmdbuf, sizeof(cmdbuf), "\\password %s\n", key1); retval = netrigctl_transaction(rig, cmdbuf, strlen(cmdbuf), buf); - if (retval != RIG_OK) { retval = -RIG_EPROTO; } + if (retval != RIG_OK) + { + rig_debug(RIG_DEBUG_ERR, "%s; retval = %d\n", __func__, retval); + retval = -RIG_EPROTO; + } RETURNFUNC(retval); } diff --git a/security/password.c b/security/password.c index b45f3be1d..5fb86c39d 100644 --- a/security/password.c +++ b/security/password.c @@ -56,6 +56,7 @@ HAMLIB_EXPORT(void) rig_password_generate_secret(char *pass, const char *md5str = rig_make_md5(newpass); strncpy(result, md5str, HAMLIB_SECRET_LENGTH); + result[HAMLIB_SECRET_LENGTH] = '\0'; // now that we have the md5 we'll do the AES256 From 7fc138934970acd1136c054217a158f9e2b3da32 Mon Sep 17 00:00:00 2001 From: George Baltz N3GB Date: Wed, 3 Jun 2026 13:07:07 -0400 Subject: [PATCH 3/7] Turn off passwords and their help text Disable them until they work --- include/hamlib/rig.h | 7 +++++++ rigs/dummy/netrigctl.c | 2 +- tests/rigctl_parse.c | 8 +++++++- tests/rigctld.c | 6 ++++++ tests/rigctltcp.c | 6 ++++++ 5 files changed, 27 insertions(+), 2 deletions(-) diff --git a/include/hamlib/rig.h b/include/hamlib/rig.h index e03998623..502539a17 100644 --- a/include/hamlib/rig.h +++ b/include/hamlib/rig.h @@ -35,6 +35,13 @@ // Our shared secret password #define HAMLIB_SECRET_LENGTH 32 +/* + * Temporary disable of rigctld/rigctltcp passwords and their help text, so no expctations + * of them working + * Set this to 1 when they are repaired + */ +#define RIGCTLD_PASSWORDS 0 + #define HAMLIB_TRACE rig_debug(RIG_DEBUG_TRACE,"%s%s(%d) trace\n",hl_stars(STATE(rig)->depth), __FILE__, __LINE__) #define __FILENAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__) diff --git a/rigs/dummy/netrigctl.c b/rigs/dummy/netrigctl.c index 2e4b732d3..b10d140a3 100644 --- a/rigs/dummy/netrigctl.c +++ b/rigs/dummy/netrigctl.c @@ -2768,7 +2768,7 @@ int netrigctl_password(RIG *rig, const char *key1) if (retval != RIG_OK) { - rig_debug(RIG_DEBUG_ERR, "%s; retval = %d\n", __func__, retval); + //rig_debug(RIG_DEBUG_ERR, "%s; retval = %d\n", __func__, retval); retval = -RIG_EPROTO; } diff --git a/tests/rigctl_parse.c b/tests/rigctl_parse.c index 23f36f77b..64efe7c02 100644 --- a/tests/rigctl_parse.c +++ b/tests/rigctl_parse.c @@ -258,8 +258,10 @@ declare_proto_rig(set_cache); declare_proto_rig(get_cache); declare_proto_rig(halt); declare_proto_rig(pause); +#if RIGCTLD_PASSWORDS declare_proto_rig(password); //declare_proto_rig(set_password); +#endif declare_proto_rig(set_clock); declare_proto_rig(get_clock); declare_proto_rig(set_separator); @@ -376,8 +378,10 @@ static struct test_table test_list[] = { 0xf8, "set_clock", ACTION(set_clock), ARG_IN | ARG_NOVFO, "local or utc or YYYY-MM-DDTHH:MM:SS.sss+ZZ or YYYY-MM-DDTHH:MM+ZZ" }, { 0xf1, "halt", ACTION(halt), ARG_NOVFO }, /* rigctld only--halt the daemon */ { 0x8c, "pause", ACTION(pause), ARG_IN | ARG_NOVFO, "Seconds" }, +#if RIGCTLD_PASSWORDS { 0x98, "password", ACTION(password), ARG_IN | ARG_NOVFO, "Password" }, // { 0x99, "set_password", ACTION(set_password), ARG_IN | ARG_NOVFO, "Password" }, +#endif { 0xa0, "set_separator", ACTION(set_separator), ARG_IN | ARG_NOVFO, "Separator" }, { 0xa1, "get_separator", ACTION(get_separator), ARG_NOVFO, "Separator" }, { 0xa2, "set_lock_mode", ACTION(set_lock_mode), ARG_IN | ARG_NOVFO, "Locked" }, @@ -5533,7 +5537,8 @@ declare_proto_rig(pause) return (RIG_OK); } -int rigctld_password_check(RIG *rig, const char *md5) +#if RIGCTLD_PASSWORDS +static int rigctld_password_check(RIG *rig, const char *md5) { int retval = -RIG_EINVAL; //fprintf(fout, "password %s\n", password); @@ -5583,6 +5588,7 @@ declare_proto_rig(password) RETURNFUNC2(retval); } +#endif #if 0 // don't think we need this yet /* 0x99 */ diff --git a/tests/rigctld.c b/tests/rigctld.c index a74da1665..966d91216 100644 --- a/tests/rigctld.c +++ b/tests/rigctld.c @@ -107,7 +107,9 @@ static struct option long_options[] = {"twiddle_rit", 1, 0, 'w'}, {"uplink", 1, 0, 'x'}, {"debug-time-stamps", 0, 0, 'Z'}, +#if RIGCTLD_PASSWORDS {"password", 1, 0, 'A'}, +#endif {"rigctld-idle", 0, 0, 'R'}, {"bind-all", 0, 0, 'b'}, {0, 0, 0, 0} @@ -320,6 +322,7 @@ int main(int argc, char *argv[]) bind_all = 1; break; +#if RIGCTLD_PASSWORDS case 'A': strncpy(rigctld_password, optarg, sizeof(rigctld_password) - 1); //char *md5 = rig_make_m d5(rigctld_password); @@ -328,6 +331,7 @@ int main(int argc, char *argv[]) printf("Secret key: %s\n", md5); rig_settings_save("sharedkey", md5, e_CHAR); break; +#endif case 'm': my_model = atoi(optarg); @@ -1392,7 +1396,9 @@ static void usage(FILE *fout) " -w, --twiddle_rit=SECONDS suppress VFOB getfreq so RIT can be twiddled\n" " -x, --uplink=OPTION set uplink get_freq ignore, option 1=Sub, 2=Main\n" " -Z, --debug-time-stamps enable time stamps for debug messages\n" +#if RIGCTLD_PASSWORDS " -A, --password=PASSWORD set password for rigctld access (NOT IMPLEMENTED)\n" +#endif " -R, --rigctld-idle make rigctld close the rig when no clients are connected\n" " -b, --bind-all make rigctld bind to first network device available\n" " -h, --help display this help and exit\n" diff --git a/tests/rigctltcp.c b/tests/rigctltcp.c index 9d0050484..5987ca897 100644 --- a/tests/rigctltcp.c +++ b/tests/rigctltcp.c @@ -112,7 +112,9 @@ static struct option long_options[] = {"debug-time-stamps", 0, 0, 'Z'}, {"multicast-addr", 1, 0, 'M'}, {"multicast-port", 1, 0, 'n'}, +#if RIGCTLD_PASSWORDS {"password", 1, 0, 'A'}, +#endif {"rigctld-idle", 0, 0, 'R'}, {0, 0, 0, 0} }; @@ -313,6 +315,7 @@ int main(int argc, char *argv[]) rigctld_idle = 1; break; +#if RIIGCTLD_PASSWORDS case 'A': strncpy(rigctld_password, optarg, sizeof(rigctld_password) - 1); //char *md5 = rig_make_m d5(rigctld_password); @@ -321,6 +324,7 @@ int main(int argc, char *argv[]) printf("Secret key: %s\n", md5); rig_settings_save("sharedkey", md5, e_CHAR); break; +#endif case 'm': my_model = atoi(optarg); @@ -1390,7 +1394,9 @@ static void usage(FILE *fout) " -w, --twiddle_rit=SECONDS suppress VFOB getfreq so RIT can be twiddled\n" " -x, --uplink=OPTION set uplink get_freq ignore, option 1=Sub, 2=Main\n" " -Z, --debug-time-stamps enable time stamps for debug messages\n" +#if RIGCTLD_PASSWORDS " -A, --password=PASSWORD set password for rigctld access (64 chars max), default none\n" +#endif " -R, --rigctltcp-idle make rigctltcp close the rig when no clients are connected\n" " -h, --help display this help and exit\n" " -V, --version output version information and exit\n\n", From b56f8d8f8a6c0558b56beefc84668f7be5a75a1d Mon Sep 17 00:00:00 2001 From: George Baltz N3GB Date: Wed, 3 Jun 2026 14:48:05 -0400 Subject: [PATCH 4/7] Infrastructure and setup for associating connection data with thread Will allow rigctl_parse() routines access to connection data, without reworking all of the internal and external interfaces. --- tests/rigctl.c | 1 + tests/rigctl_parse.c | 16 ++++++++++++++-- tests/rigctl_parse.h | 19 +++++++++++++++++++ tests/rigctld.c | 13 ++----------- tests/rigctltcp.c | 13 ++----------- 5 files changed, 38 insertions(+), 24 deletions(-) diff --git a/tests/rigctl.c b/tests/rigctl.c index 36bbeb547..55c7c17ed 100644 --- a/tests/rigctl.c +++ b/tests/rigctl.c @@ -792,6 +792,7 @@ int main(int argc, char *argv[]) #endif elapsed_ms(&powerstat_check_time, HAMLIB_ELAPSED_SET); + rigctl_parse_init(); // Not really needed here (yet) do { diff --git a/tests/rigctl_parse.c b/tests/rigctl_parse.c index 64efe7c02..e1013a068 100644 --- a/tests/rigctl_parse.c +++ b/tests/rigctl_parse.c @@ -108,8 +108,7 @@ int is_passwordOK; int is_rigctld; extern int lock_mode; // used by rigctld extern powerstat_t rig_powerstat; - - +pthread_key_t thread_data_key; /* variables for readline support */ @@ -704,6 +703,19 @@ static int next_word(char *buffer, int argc, char *argv[], int newline) }) +void rigctl_parse_init(/* int threaded */) +{ + int retval; + + retval = pthread_key_create(&thread_data_key, NULL); + if (retval != 0) + { + rig_debug(RIG_DEBUG_ERR, "%s: Thread data key not created\n", __func__); + } + + return; +} + int rigctl_parse(RIG *my_rig, FILE *fin, FILE *fout, char *argv[], int argc, sync_cb_t sync_cb, int interactive, int prompt, int *vfo_opt, char send_cmd_term, diff --git a/tests/rigctl_parse.h b/tests/rigctl_parse.h index 7eb88f735..84c6bd35c 100644 --- a/tests/rigctl_parse.h +++ b/tests/rigctl_parse.h @@ -26,11 +26,29 @@ #define RIGCTL_PARSE_H #include +#include #include "hamlib/rig.h" #define RIGCTL_PARSE_END 1 #define RIGCTL_PARSE_ERROR 2 +/* Data that ties each thread to a connection + * Serves as the initial thread data, then as the state info for individual + * connections + */ +struct handle_data +{ + RIG *rig; + int sock; + struct sockaddr_storage cli_addr; + socklen_t clilen; + int vfo_mode; + int use_password; + int is_passwordOK; +}; + +extern pthread_key_t thread_data_key; + /* * external prototype */ @@ -51,6 +69,7 @@ int print_conf_list(const struct confparams *cfp, rig_ptr_t data); int print_conf_list2(const struct confparams *cfp, rig_ptr_t data); int set_conf(RIG *my_rig, char *conf_parms); +void rigctl_parse_init(void); typedef void (*sync_cb_t)(int); int rigctl_parse(RIG *my_rig, FILE *fin, FILE *fout, char *argv[], int argc, sync_cb_t sync_cb, int interactive, int prompt, int * vfo_mode, char send_cmd_term, diff --git a/tests/rigctld.c b/tests/rigctld.c index 966d91216..938d6277d 100644 --- a/tests/rigctld.c +++ b/tests/rigctld.c @@ -116,17 +116,6 @@ static struct option long_options[] = }; -struct handle_data -{ - RIG *rig; - int sock; - struct sockaddr_storage cli_addr; - socklen_t clilen; - int vfo_mode; - int use_password; -}; - - /* * Prototypes */ @@ -975,6 +964,8 @@ int main(int argc, char *argv[]) #endif #endif + rigctl_parse_init(); + /* * main loop accepting connections */ diff --git a/tests/rigctltcp.c b/tests/rigctltcp.c index 5987ca897..343f618bf 100644 --- a/tests/rigctltcp.c +++ b/tests/rigctltcp.c @@ -120,17 +120,6 @@ static struct option long_options[] = }; -struct handle_data -{ - RIG *rig; - int sock; - struct sockaddr_storage cli_addr; - socklen_t clilen; - int vfo_mode; - int use_password; -}; - - void *handle_socket(void *arg); static void usage(FILE *fout); @@ -880,6 +869,8 @@ int main(int argc, char *argv[]) #endif #endif + rigctl_parse_init(); + /* * main loop accepting connections */ From cef2d9d3a962ffbc7ea263d11115b7b51c3b627a Mon Sep 17 00:00:00 2001 From: George Baltz N3GB Date: Wed, 3 Jun 2026 16:52:49 -0400 Subject: [PATCH 5/7] Move password status to connection specific data. Fix memory leak in rigctld_password_check() --- tests/rigctl_parse.c | 34 +++++++++++++++++++++++++++------- tests/rigctld.c | 8 ++++++++ tests/rigctltcp.c | 8 ++++++++ 3 files changed, 43 insertions(+), 7 deletions(-) diff --git a/tests/rigctl_parse.c b/tests/rigctl_parse.c index e1013a068..9c4282147 100644 --- a/tests/rigctl_parse.c +++ b/tests/rigctl_parse.c @@ -104,7 +104,6 @@ extern int read_history(); static int chk_vfo_executed; char rigctld_password[65]; -int is_passwordOK; int is_rigctld; extern int lock_mode; // used by rigctld extern powerstat_t rig_powerstat; @@ -725,6 +724,7 @@ int rigctl_parse(RIG *my_rig, FILE *fin, FILE *fout, char *argv[], int argc, unsigned char cmd; struct test_table *cmd_entry = NULL; struct rig_state *rs = STATE(my_rig); + struct handle_data *connection; char command[MAXARGSZ + 1] = ""; char arg1[MAXARGSZ + 1], *p1 = NULL; @@ -1833,7 +1833,9 @@ readline_repeat: else if (strcmp(cmd_entry->arg1, "Password") == 0) { preCmd = 1; } } - if (use_password && !is_passwordOK && (cmd_entry->arg1 != NULL) && !preCmd) + connection = pthread_getspecific(thread_data_key); // Get state of this connection + + if (use_password && !(connection ? connection->is_passwordOK : 0) && (cmd_entry->arg1 != NULL) && !preCmd) { rig_debug(RIG_DEBUG_ERR, "%s: password has not been provided\n", __func__); fflush(fin); @@ -5550,21 +5552,28 @@ declare_proto_rig(pause) } #if RIGCTLD_PASSWORDS +// Compare our known secret with remote submission +// Returns 1 if match, 0 if not static int rigctld_password_check(RIG *rig, const char *md5) { - int retval = -RIG_EINVAL; + int retval; + int i, len, hits; //fprintf(fout, "password %s\n", password); //rig_debug(RIG_DEBUG_TRACE, "%s: %s == %s\n", __func__, md5, rigctld_password); - is_passwordOK = 0; char *mymd5 = rig_make_md5(rigctld_password); - if (strcmp(md5, mymd5) == 0) + /* Brute force, constant time comparison */ + len = strlen(mymd5); + for (i = hits = 0; i <= len; i++) { - retval = RIG_OK; - is_passwordOK = 1; + hits += (int)(md5[i] == mymd5[i]); } + retval = (hits == len + 1); // Entire string + terminator + + free(mymd5); + return (retval); } @@ -5573,12 +5582,23 @@ declare_proto_rig(password) { int retval = -RIG_EPROTO; const char *key = arg1; + struct handle_data *connection; ENTERFUNC2; if (is_rigctld) { retval = rigctld_password_check(rig, key); + connection = pthread_getspecific(thread_data_key); + if (connection) + { + connection->is_passwordOK = retval; + retval = retval == 1 ? RIG_OK : -RIG_EPROTO; + } + else + { + retval = -RIG_EPROTO; + } } else { diff --git a/tests/rigctld.c b/tests/rigctld.c index 938d6277d..de4b77ef1 100644 --- a/tests/rigctld.c +++ b/tests/rigctld.c @@ -1165,6 +1165,13 @@ void *handle_socket(void *arg) goto handle_exit; } + retcode = pthread_setspecific(thread_data_key, arg); + if (0 != retcode) + { + rig_debug(RIG_DEBUG_ERR, "%s: Could not set thread daya\n", __func__); + // What do we do here? + } + mutex_rigctld(1); ++client_count; @@ -1352,6 +1359,7 @@ handle_exit: #endif + pthread_setspecific(thread_data_key, NULL); // The pthreads we're done with the data free(arg); pthread_exit(NULL); diff --git a/tests/rigctltcp.c b/tests/rigctltcp.c index 343f618bf..215a64377 100644 --- a/tests/rigctltcp.c +++ b/tests/rigctltcp.c @@ -1063,6 +1063,13 @@ void *handle_socket(void *arg) goto handle_exit; } + retcode = pthread_setspecific(thread_data_key, arg); + if (retcode != 0) + { + rig_debug(RIG_DEBUG_ERR, "%s: Could not set thread data\n", __func__); + // What should we do here??? + } + mutex_rigctld(1); ++client_count; @@ -1349,6 +1356,7 @@ handle_exit: #endif + pthread_setspecific(thread_data_key, NULL); free(arg); pthread_exit(NULL); From 039a4f8bfe334866124e70bf56e5440b1a478331 Mon Sep 17 00:00:00 2001 From: George Baltz N3GB Date: Wed, 3 Jun 2026 17:15:30 -0400 Subject: [PATCH 6/7] Turn passwords on again --- include/hamlib/rig.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/hamlib/rig.h b/include/hamlib/rig.h index 502539a17..077e05276 100644 --- a/include/hamlib/rig.h +++ b/include/hamlib/rig.h @@ -40,7 +40,7 @@ * of them working * Set this to 1 when they are repaired */ -#define RIGCTLD_PASSWORDS 0 +#define RIGCTLD_PASSWORDS 1 #define HAMLIB_TRACE rig_debug(RIG_DEBUG_TRACE,"%s%s(%d) trace\n",hl_stars(STATE(rig)->depth), __FILE__, __LINE__) #define __FILENAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__) From 11dbace2309686bde10e5a517d46ae7b60055af6 Mon Sep 17 00:00:00 2001 From: George Baltz N3GB Date: Thu, 4 Jun 2026 11:33:09 -0400 Subject: [PATCH 7/7] Make a padded copy of input so compare doesn't overread Cleanup: Fix typo and formatting Move RIGCTLD_PASSWORDS from rig.h to rigctl_parse.h --- include/hamlib/rig.h | 7 ------- tests/rigctl_parse.c | 10 +++++++--- tests/rigctl_parse.h | 7 +++++++ tests/rigctld.c | 2 +- 4 files changed, 15 insertions(+), 11 deletions(-) diff --git a/include/hamlib/rig.h b/include/hamlib/rig.h index 077e05276..e03998623 100644 --- a/include/hamlib/rig.h +++ b/include/hamlib/rig.h @@ -35,13 +35,6 @@ // Our shared secret password #define HAMLIB_SECRET_LENGTH 32 -/* - * Temporary disable of rigctld/rigctltcp passwords and their help text, so no expctations - * of them working - * Set this to 1 when they are repaired - */ -#define RIGCTLD_PASSWORDS 1 - #define HAMLIB_TRACE rig_debug(RIG_DEBUG_TRACE,"%s%s(%d) trace\n",hl_stars(STATE(rig)->depth), __FILE__, __LINE__) #define __FILENAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__) diff --git a/tests/rigctl_parse.c b/tests/rigctl_parse.c index 9c4282147..7079212e3 100644 --- a/tests/rigctl_parse.c +++ b/tests/rigctl_parse.c @@ -5558,16 +5558,20 @@ static int rigctld_password_check(RIG *rig, const char *md5) { int retval; int i, len, hits; + char padded[HAMLIB_SECRET_LENGTH + 1]; //fprintf(fout, "password %s\n", password); //rig_debug(RIG_DEBUG_TRACE, "%s: %s == %s\n", __func__, md5, rigctld_password); char *mymd5 = rig_make_md5(rigctld_password); - /* Brute force, constant time comparison */ len = strlen(mymd5); + strncpy(padded, md5, HAMLIB_SECRET_LENGTH); + padded[HAMLIB_SECRET_LENGTH] = '\0'; // Make sure it's a terminated string + + /* Brute force, constant time comparison */ for (i = hits = 0; i <= len; i++) { - hits += (int)(md5[i] == mymd5[i]); + hits += (int)(padded[i] == mymd5[i]); } retval = (hits == len + 1); // Entire string + terminator @@ -5589,7 +5593,7 @@ declare_proto_rig(password) if (is_rigctld) { retval = rigctld_password_check(rig, key); - connection = pthread_getspecific(thread_data_key); + connection = pthread_getspecific(thread_data_key); if (connection) { connection->is_passwordOK = retval; diff --git a/tests/rigctl_parse.h b/tests/rigctl_parse.h index 84c6bd35c..d7e3a7632 100644 --- a/tests/rigctl_parse.h +++ b/tests/rigctl_parse.h @@ -32,6 +32,13 @@ #define RIGCTL_PARSE_END 1 #define RIGCTL_PARSE_ERROR 2 +/* + * Temporary disable of rigctld/rigctltcp passwords and their help text, so no expctations + * of them working + * Set this to 1 when they are repaired + */ +#define RIGCTLD_PASSWORDS 1 + /* Data that ties each thread to a connection * Serves as the initial thread data, then as the state info for individual * connections diff --git a/tests/rigctld.c b/tests/rigctld.c index de4b77ef1..2a45900c8 100644 --- a/tests/rigctld.c +++ b/tests/rigctld.c @@ -1359,7 +1359,7 @@ handle_exit: #endif - pthread_setspecific(thread_data_key, NULL); // The pthreads we're done with the data + pthread_setspecific(thread_data_key, NULL); // Tell pthreads we're done with the data free(arg); pthread_exit(NULL);