diff --git a/rigs/dummy/netrigctl.c b/rigs/dummy/netrigctl.c index b80326761..b10d140a3 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 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; } 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 04b68cac3..b41c42680 100644 --- a/tests/rigctl_parse.c +++ b/tests/rigctl_parse.c @@ -104,12 +104,10 @@ 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; - - +pthread_key_t thread_data_key; /* variables for readline support */ @@ -258,8 +256,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 +376,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" }, @@ -700,6 +702,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, @@ -709,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; @@ -1817,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); @@ -5533,21 +5551,33 @@ declare_proto_rig(pause) return (RIG_OK); } -int rigctld_password_check(RIG *rig, const char *md5) +#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; + 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); - is_passwordOK = 0; char *mymd5 = rig_make_md5(rigctld_password); - if (strcmp(md5, mymd5) == 0) + 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++) { - retval = RIG_OK; - is_passwordOK = 1; + hits += (int)(padded[i] == mymd5[i]); } + retval = (hits == len + 1); // Entire string + terminator + + free(mymd5); + return (retval); } @@ -5556,12 +5586,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 { @@ -5583,6 +5624,7 @@ declare_proto_rig(password) RETURNFUNC2(retval); } +#endif #if 0 // don't think we need this yet /* 0x99 */ diff --git a/tests/rigctl_parse.h b/tests/rigctl_parse.h index 7eb88f735..d7e3a7632 100644 --- a/tests/rigctl_parse.h +++ b/tests/rigctl_parse.h @@ -26,11 +26,36 @@ #define RIGCTL_PARSE_H #include +#include #include "hamlib/rig.h" #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 + */ +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 +76,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 a74da1665..2a45900c8 100644 --- a/tests/rigctld.c +++ b/tests/rigctld.c @@ -107,24 +107,15 @@ 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} }; -struct handle_data -{ - RIG *rig; - int sock; - struct sockaddr_storage cli_addr; - socklen_t clilen; - int vfo_mode; - int use_password; -}; - - /* * Prototypes */ @@ -320,6 +311,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 +320,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); @@ -971,6 +964,8 @@ int main(int argc, char *argv[]) #endif #endif + rigctl_parse_init(); + /* * main loop accepting connections */ @@ -1170,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; @@ -1357,6 +1359,7 @@ handle_exit: #endif + pthread_setspecific(thread_data_key, NULL); // Tell pthreads we're done with the data free(arg); pthread_exit(NULL); @@ -1392,7 +1395,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..215a64377 100644 --- a/tests/rigctltcp.c +++ b/tests/rigctltcp.c @@ -112,23 +112,14 @@ 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} }; -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); @@ -313,6 +304,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 +313,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); @@ -876,6 +869,8 @@ int main(int argc, char *argv[]) #endif #endif + rigctl_parse_init(); + /* * main loop accepting connections */ @@ -1068,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; @@ -1354,6 +1356,7 @@ handle_exit: #endif + pthread_setspecific(thread_data_key, NULL); free(arg); pthread_exit(NULL); @@ -1390,7 +1393,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",