From c3dc2e93a04e9c9e3b8f82b1e988cfd2aceb41df Mon Sep 17 00:00:00 2001 From: Tj Date: Tue, 29 Mar 2016 14:21:03 +0100 Subject: [PATCH] Timestamp handling now 100% correct; device ATSE no longer required Signed-off-by: Tj --- Makefile | 3 +- cfe_generate_password.c | 93 +++++++++++++++++++++++++++++++---------- 2 files changed, 72 insertions(+), 24 deletions(-) diff --git a/Makefile b/Makefile index 3aaf3cc..77fa8c5 100644 --- a/Makefile +++ b/Makefile @@ -1,8 +1,9 @@ PROG=cfe_gen_pass SRC=cfe_generate_password +CFLAGS=-std=c11 $(PROG): $(SRC).c - $(CC) -o $@ $< $(CFLAGS) + $(CC) $(CFLAGS) -o $@ $< clean: rm -f $(PROG) diff --git a/cfe_generate_password.c b/cfe_generate_password.c index 7c5fb05..d51c0b9 100644 --- a/cfe_generate_password.c +++ b/cfe_generate_password.c @@ -22,10 +22,30 @@ eight digit hexadecimal 'password'. It is NOT necessary to have the device generate a 'seed' using "ATSE [MODEL-ID]" - because this tool can generate the seed from the device's first (base) MAC address - *provided* the "ATSE" command has NOT been executed since the device last booted. + because this tool can generate the seed from the device's first (base) MAC address. - Access to the device's console via a serial UART port is required to enter the password. + When the device generates a seed it combines the number of seconds since 1970-01-01 00:00:00 + with the router MAC address. Both are encoded in a single 6-byte hexadecimal + + Each value is truncated to its 3 least significant bytes so, for example: + + $ date +%F.%T; echo "obase=16;$(date +%s)" | bc + 2016-03-26.23:06:32 + 56F715F8 + # MAC Address: EC:43:F6:46:C0:80 + + becomes F715F8 concatenated with 46C080 + + CFE> ATSE DSL-2492GNAU-B1BC + F715F846C080 <<<< last 3 bytes of MAC address + ^^^^^^ + seconds since 1970-01-01 00:00:00 (2016-03-26 23:06:32) + + *NOTE: the default seed after power-up is 000000 so no time value needs to be specifed + if "ATSE " has not been executed on the device. + + Access to the device's console via a serial UART port, or a network telnet/ssh session, + is required to enter the password. So, for a device with base MAC address (reported by the CFE during boot) E.g: @@ -48,7 +68,7 @@ OK *** command status = 0 - The tool can accept a timestamp as 6 hexadecimal characters (useful for testing the algorithm): + The tool can accept a timestamp as 8 hexadecimal characters (useful for testing the algorithm): ./cfe_gen_pass -t 0FF020 -s ec:43:f6:46:c0:80 -p @@ -59,13 +79,15 @@ #include #include #include +#include static const float VERSION = 1.2f; -static const size_t TIMESTAMP_SIZE = 6; +static const size_t TIMESTAMP_SIZE = 8; static const size_t SEED_SIZE = 12; static const size_t PASSWORD_SIZE = 8; static const size_t MESSAGE_SIZE = 128; static const size_t MAC_ADDR_SIZE = 17; +static const size_t DATESTRING_SIZE = 20; static void pr_usage() @@ -74,7 +96,7 @@ pr_usage() "Usage:\n" " -v show version\n" " -s 00:01:02:03:04:05 create seed from MAC address\n" - " -t 000000 millisecond timestamp since boot\n" + " -t [00000000] seconds since 1970-01-01 (defaults to NOW) \n" " -p [SEED] generate password (with optional seed)\n\n" " E.g. -s 01:02:03:04:05 \n" " -s 01:02:03:04:05 -p\n" @@ -119,17 +141,19 @@ generate_seed(char *mac, char *timestamp, char *seed) size_t i; char *mac_ptr = mac + 9; size_t ts_len = strlen(timestamp); - for (i = 0; i < SEED_SIZE; ++i) { - /* if no timestamp assume CFE get_time() returned 0 and CFE g_pw_timestamp == 0x00000000 */ - if (i < 6) - seed[i] = ts_len ? timestamp[i] : '0'; - else { - if (*mac_ptr == ':' || *mac_ptr == '-') - ++mac_ptr; - seed[i] = *mac_ptr++; + if (ts_len == TIMESTAMP_SIZE) { + for (i = 0; i < SEED_SIZE; ++i) { + if (i < 6) // first half of seed is the truncated timestamp + seed[i] = timestamp[i+2]; + else { // second half is the truncated MAC address + if (*mac_ptr == ':' || *mac_ptr == '-') + ++mac_ptr; + seed[i] = *mac_ptr++; + } } - } - result = 1; + result = 1; + } else + pr_error_exit(0, "Timestamp ('%s') should be %d hexadecimal characters e.g: 56F715F8", timestamp, TIMESTAMP_SIZE); } else pr_error_exit(0, "MAC-ADDR should be %d characters, e.g: 00:01:02:03:04:05", MAC_ADDR_SIZE); @@ -172,11 +196,14 @@ main(int argc, char **argv, char **env) char timestamp[TIMESTAMP_SIZE + 1]; char seed[SEED_SIZE + 1]; char password[PASSWORD_SIZE + 1]; + char date_string[DATESTRING_SIZE + 1]; unsigned int opt_seed, opt_pass, opt_ts; - seed[0] = password[0] = 0; - seed[SEED_SIZE] = password[PASSWORD_SIZE] = timestamp[TIMESTAMP_SIZE] = 0; + time_t ts = 0; + struct tm *t = NULL; + seed[0] = password[0] = timestamp[0] = 0; + seed[SEED_SIZE] = password[PASSWORD_SIZE] = 0; opt_seed = opt_pass = opt_ts = 0; - strncpy(timestamp, "000000", TIMESTAMP_SIZE); + strncpy(timestamp, "00000000", TIMESTAMP_SIZE + 1); for (arg = 1; arg < (unsigned) argc; ++arg) { size_t arg_len = strlen(argv[arg]); @@ -206,7 +233,7 @@ main(int argc, char **argv, char **env) ++opt_pass; } else if (opt_ts == 1) { if (arg_len != TIMESTAMP_SIZE) - pr_error_exit(1, "timestamp length must be %d characters", TIMESTAMP_SIZE); + pr_error_exit(1, "timestamp length must be %d hexadecimal characters", TIMESTAMP_SIZE); strncpy(timestamp, argv[arg], TIMESTAMP_SIZE); ++opt_ts; @@ -220,9 +247,29 @@ main(int argc, char **argv, char **env) pr_error_exit(1, "password on its own requires a pre-generated seed"); else if (opt_seed && opt_pass && opt_pass != 1) pr_error_exit(1, "generating seed and password; cannot also accept pre-generated seed"); - else if (opt_ts == 1) - pr_error_exit(0, "missing timestamp; assuming 000000"); + else if (opt_pass == 2 && opt_ts) + pr_error_exit(1, "seed already contains a timestamp; cannot over-ride it"); + else if (opt_ts == 1 || opt_pass == 2) { // no timestamp provided; use NOW + ts = time(NULL); + if (ts) + snprintf(timestamp, TIMESTAMP_SIZE + 1, "%08lX", ts); + } + if (opt_pass == 2) { // try to figure out the correct date-time from the seed + // inherits the most significant 2 characters from the NOW time + strncpy(timestamp+2, seed, 6); + time_t tmp; + if (sscanf(timestamp, "%08lx", &tmp)) + if (tmp > ts-3600 && tmp < ts+3600) // timestamps are so close they must be for the same date + ts = tmp; + } + + if(opt_ts) { // ts needs to be valid to be converted to a time string + if(! sscanf(timestamp, "%08lx", &ts)) + pr_error_exit(1, "converting timestamp string ('%s') to number", timestamp); + } + t = gmtime(&ts); + strftime(date_string, DATESTRING_SIZE, "%F %T", t); if (opt_seed) if (! generate_seed(MAC_ADDR, timestamp, seed)) @@ -232,7 +279,7 @@ main(int argc, char **argv, char **env) pr_error_exit(0, "unable to generate password"); if (opt_seed || opt_pass) - printf("MAC address: %s Timestamp: %s Seed: %s Password: %s\n", MAC_ADDR, timestamp, seed, password); + printf("MAC address: %s Timestamp: %s (%s) Seed: %s Password: %s\n", MAC_ADDR, timestamp, date_string, seed, password); } return result; -- 2.17.1