Chris,This is the patch I did for Shannon McMackin's Bold 9000. This device makes two requests for the password so I had to change the way the password is handled. Before we would check if there was password in the Open function and force the setup to either send the password or not. Now I let the device determine if it needs a password then send the password and seed to the SendPassword function. In other words I made the SendPassword more generic by moving the seed packet check from the SendPassword function to the Open function.
There is still a problem on the Bold not closing properly and I'm working on that.
--Andy
diff --git a/src/m_ipmodem.cc b/src/m_ipmodem.cc index 23c81c1..dae0f08 100644 --- a/src/m_ipmodem.cc +++ b/src/m_ipmodem.cc @@ -60,95 +60,78 @@ IpModem::~IpModem() } } -bool IpModem::SendPassword(const char *password) +bool IpModem::SendPassword( const char *password, uint32_t seed ) { - if( !password || strlen(password) == 0 ) { - throw BadPassword("No password provided.", 0, false); - } - int read_ep = m_con.GetProbeResult().m_epModem.read; int write_ep = m_con.GetProbeResult().m_epModem.write; + unsigned char pwdigest[SHA_DIGEST_LENGTH]; + unsigned char prefixedhash[SHA_DIGEST_LENGTH + 4]; + unsigned char pw_response[SHA_DIGEST_LENGTH + 8]; + uint32_t new_seed; Data data; - m_dev.BulkWrite(write_ep, pw_start, sizeof(pw_start)); - m_dev.BulkRead(read_ep, data); - ddout("IPModem read packet.\n" << data); - - // Need to add checks for other packet types. - // check for 02 00 00 00 SS SS SS SS RR 00 00 00 0a 00 00 00 PP PP PP PP PP 00 00 00 78 56 34 12 - if( data.GetSize() >= 9 && data.GetData()[0] == 0x02 && - memcmp(data.GetData() + data.GetSize() - 4, special_flag, sizeof(special_flag))== 0 ) { - // Got a password request packet - ddout("IPModem password request packet:\n" << data); - - // Check how many retries are left - if( data.GetData()[8] < BARRY_MIN_PASSWORD_TRIES ) { - throw BadPassword("Fewer than " BARRY_MIN_PASSWORD_TRIES_ASC " password tries remaining in device. Refusing to proceed, to avoid device zapping itself. Use a Windows client, or re-cradle the device.", - data.GetData()[8], - true); - } + if( !password || strlen(password) == 0 ) { + throw BadPassword("No password provided.", 0, false); + } - // Build the password hash - unsigned char pwdigest[SHA_DIGEST_LENGTH]; - unsigned char prefixedhash[SHA_DIGEST_LENGTH + 4]; - unsigned char pw_response[SHA_DIGEST_LENGTH + 8]; - unsigned char seed[4]; + // Build the password hash + // first, hash the password by itself + SHA1((unsigned char *) password, strlen(password), pwdigest); - // first, hash the password by itself - SHA1((unsigned char *) password, strlen(password), pwdigest); + // prefix the resulting hash with the provided seed + memcpy(&prefixedhash[0], &seed, sizeof(uint32_t)); + memcpy(&prefixedhash[4], pwdigest, SHA_DIGEST_LENGTH); - // prefix the resulting hash with the provided seed - memcpy(&seed[0], data.GetData() + 4, sizeof(uint32_t)); - memcpy(&prefixedhash[0], &seed, sizeof(uint32_t)); - memcpy(&prefixedhash[4], pwdigest, SHA_DIGEST_LENGTH); + // hash again + SHA1((unsigned char *) prefixedhash, SHA_DIGEST_LENGTH + 4, pwdigest); - // hash again - SHA1((unsigned char *) prefixedhash, SHA_DIGEST_LENGTH + 4, pwdigest); + // Build the response packet + const char pw_rsphdr[] = { 0x03, 0x00, 0x00, 0x00 }; + memcpy(&pw_response[0], pw_rsphdr, sizeof(pw_rsphdr)); + memcpy(&pw_response[4], pwdigest, SHA_DIGEST_LENGTH); + memcpy(&pw_response[24], special_flag, sizeof(special_flag)); - // Build the response packet - const char pw_rsphdr[] = { 0x03, 0x00, 0x00, 0x00 }; - memcpy(&pw_response[0], pw_rsphdr, sizeof(pw_rsphdr)); - memcpy(&pw_response[4], pwdigest, SHA_DIGEST_LENGTH); - memcpy(&pw_response[24], special_flag, sizeof(special_flag)); + // Send the password response packet + m_dev.BulkWrite(write_ep, pw_response, sizeof(pw_response)); + m_dev.BulkRead(read_ep, data); + ddout("IPModem: Read password response.\n" << data); - // Send the password response packet - m_dev.BulkWrite(write_ep, pw_response, sizeof(pw_response)); - m_dev.BulkRead(read_ep, data); - ddout("IPModem read password response.\n" << data); - - // check response 04 00 00 00 ....... - // On the 8703e the seed is incremented, retries are reset to 10 when the password is accepted. - // if( data.GetData()[0] == 0x04 && data.GetData()[8] == 0x0a ) { - if( data.GetSize() >= 9 && data.GetData()[0] == 0x04 ) { - if( memcmp(data.GetData() + 4, seed, sizeof(seed)) == 0 ) { - ddout("IPModem invalid password.\n" << data); - throw BadPassword("Password rejected by device.", data.GetData()[8], false); - } - ddout("IPModem password accepted.\n"); - // send "start"? packet - m_dev.BulkWrite(write_ep, pw_start, sizeof(pw_start)); + // Added for the BB Storm 9000's second password request + if( data.GetSize() >= 16 && data.GetData()[0] == 0x00 ) { + try { + m_dev.BulkRead(read_ep, data, 500); + ddout("IPModem: Null Response Packet:\n" << data); + } + catch( Usb::Timeout &to ) { + // do nothing on timeouts + ddout("IPModem: Null Response Timeout"); + } + } - // send packet with the last 8 bytes of the password hash (session_key?) - //unsigned char pw_response[SHA_DIGEST_LENGTH + 8]; - unsigned char pw_rsphdr[] = { 0x00, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0xc2, 1, 0 }; + // check response 04 00 00 00 ....... + // On the 8703e the seed is incremented, retries are reset to 10 when the password is accepted. + // If data.GetData() + 4 is = to the orginal seed +1 or 00 00 00 00 then the password was acceppted. + // When data.GetData() + 4 is not 00 00 00 00 then data.GetData()[8] contains the number of password retrys left. + if( data.GetSize() >= 9 && data.GetData()[0] == 0x04 ) { + memcpy(&new_seed, data.GetData() + 4, sizeof(uint32_t)); + seed++; + if( seed == new_seed || new_seed == 0 ) { + ddout("IPModem: Password accepted.\n"); + // Create session key - last 8 bytes of the password hash memcpy(&m_session_key[0], pwdigest + 12, sizeof(m_session_key)); - memcpy(&pw_response[0], pw_rsphdr, sizeof(pw_rsphdr)); - memcpy(&pw_response[16], pwdigest + 12, 8); - //memcpy(&pw_response[16], m_session_key, 8); - memcpy(&pw_response[24], special_flag, sizeof(special_flag)); - m_dev.BulkWrite(write_ep, pw_response, sizeof(pw_response)); // blank password hashes as we don't need these anymore memset(pwdigest, 0, sizeof(pwdigest)); memset(prefixedhash, 0, sizeof(prefixedhash)); - - // The modem should be ready to accept AT commands return true; } - - // Unknown packet - ddout("IPModem Error unknown packet.\n" << data); + else { + ddout("IPModem: Invalid password.\n" << data); + throw BadPassword("Password rejected by device.", data.GetData()[8], false); + } } + // Unknown packet + ddout("IPModem: Error unknown packet.\n" << data); return false; } @@ -172,7 +155,7 @@ void *IpModem::DataReadThread(void *userptr) if( data.GetSize() > 4 && memcmp(data.GetData() + data.GetSize() - 4, special_flag, sizeof(special_flag)) == 0 ) { // log, then drop it on the floor for now - ddout("IPModem special packet:\n" << data); + ddout("IPModem: Special packet:\n" << data); continue; } @@ -190,7 +173,7 @@ void *IpModem::DataReadThread(void *userptr) } catch( Usb::Timeout &to ) { // do nothing on timeouts - ddout("Timeout in DataReadThread!"); + ddout("IPModem: Timeout in DataReadThread!"); } catch( std::exception &e ) { eout("Exception in IpModem::DataReadThread: " << e.what()); @@ -207,7 +190,10 @@ void IpModem::Open(const char *password) { int read_ep = m_con.GetProbeResult().m_epModem.read; int write_ep = m_con.GetProbeResult().m_epModem.write; + unsigned char response[28]; + uint32_t seed; Data data; + // check that we have endpoints for the modem const Usb::EndpointPair &pair = m_con.GetProbeResult().m_epModem; if( !pair.IsComplete() ) { @@ -224,28 +210,110 @@ void IpModem::Open(const char *password) m_dev.ClearHalt(pair.read); m_dev.ClearHalt(pair.write); - if( !password || strlen(password) == 0 ) { - Data block(start, sizeof(start)); - Write(block); + // Send stop command + ddout("IPModem: Sending Stop Response:\n"); + m_dev.BulkWrite(write_ep, stop, sizeof(stop)); + try { + m_dev.BulkRead(read_ep, data, 500); + ddout("IPModem: Stop Response Packet:\n" << data); } - else { - if( !SendPassword(password) ) { - throw Barry::Error("IpModem:: Error sending password."); + catch( Usb::Timeout &to ) { + // do nothing on timeouts + ddout("IPModem: Stop Response Timeout"); + } + + // Send start commands to figure out if the device needs a password. + ddout("IPModem: Sending Start Response:\n"); + m_dev.BulkWrite(write_ep, pw_start, sizeof(pw_start)); + m_dev.BulkRead(read_ep, data, 5000); + ddout("IPModem: Start Response Packet:\n" << data); + + // check for 02 00 00 00 SS SS SS SS RR 00 00 00 0a 00 00 00 PP PP PP PP PP 00 00 00 78 56 34 12 + if( data.GetSize() >= 9 && data.GetData()[0] == 0x02 && + memcmp(data.GetData() + data.GetSize() - 4, special_flag, sizeof(special_flag))== 0 ) { + // Got a password request packet + ddout("IPModem: Password request packet:\n" << data); + + // Check how many retries are left + if( data.GetData()[8] < BARRY_MIN_PASSWORD_TRIES ) { + throw BadPassword("Fewer than " BARRY_MIN_PASSWORD_TRIES_ASC " password tries remaining in device. Refusing to proceed, to avoid device zapping itself. Use a Windows client, or re-cradle the device.", + data.GetData()[8], + true); + } + memcpy(&seed, data.GetData() + 4, sizeof(uint32_t)); + // Send password + if( !SendPassword(password, seed) ) { + throw Barry::Error("IpModem: Error sending password."); + } + + // Re-send "start" packet + ddout("IPModem: Re-sending Start Response:\n"); + m_dev.BulkWrite(write_ep, pw_start, sizeof(pw_start)); + m_dev.BulkRead(read_ep, data); + ddout("IPModem: Start Response Packet:\n" << data); + + // send packet with the session_key + unsigned char response_header[] = { 0x00, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0xc2, 1, 0 }; + memcpy(&response[0], response_header, sizeof(response_header)); + memcpy(&response[16], m_session_key, sizeof(m_session_key)); + memcpy(&response[24], special_flag, sizeof(special_flag)); + ddout("IPModem: Sending Session key:\n"); + m_dev.BulkWrite(write_ep, response, sizeof(response)); + if( data.GetSize() >= 16 ) { + switch(data.GetData()[0]) + { + case 0x00: // Null packet + break; + + case 0x02: // password seed received + memcpy(&seed, data.GetData() + 4, sizeof(uint32_t)); + if( !SendPassword( password, seed ) ) { + throw Barry::Error("IpModem: Error sending password."); + } + break; + case 0x04: // command accepted + break; + + default: // ??? + ddout("IPModem: Unknown response.\n"); + break; + } } + } // see if the modem will respond to commands const char modem_command[] = { "AT\r" }; + //ddout("IPModem: Test command response.\n" << data); m_dev.BulkWrite(write_ep, modem_command, strlen(modem_command)); m_dev.BulkRead(read_ep, data); - ddout("IPModem:: AT command response.\n" << data); + ddout("IPModem: Test command response.\n" << data); if( data.GetSize() >= 1 ) { switch(data.GetData()[0]) { - case 0x02: // password seed received - throw BadPassword("This device requested a password.", - data.GetSize() >= 9 ? data.GetData()[8] : 0, false); + case 0x00: // Null packet + try { + m_dev.BulkRead(read_ep, data, 5000); + ddout("IPModem: AT Response Packet:\n" << data); + } + catch( Usb::Timeout &to ) { + // do nothing on timeouts + ddout("IPModem: AT Response Timeout"); + } + break; + case 0x02: // password seed received + if( !password || strlen(password) == 0 ) { + throw BadPassword("This device requested a password.", + data.GetSize() >= 9 ? data.GetData()[8] : 0, false); + } + else { // added for the Storm 9000 + memcpy(&seed, data.GetData() + 4, sizeof(uint32_t)); + if( !SendPassword( password, seed ) ) { + throw Barry::Error("IpModem: Error sending password."); + } + } + break; case 0x04: // command accepted break; @@ -253,17 +321,18 @@ void IpModem::Open(const char *password) throw BadPassword("This device requires a password.", 0, false); default: // ??? - ddout("IPModem:: unknown AT command response.\n"); + ddout("IPModem: Unknown AT command response.\n"); break; } } + ddout("IPModem: Modem Ready.\n"); // spawn read thread m_continue_reading = true; int ret = pthread_create(&m_modem_read_thread, NULL, &IpModem::DataReadThread, this); if( ret ) { m_continue_reading = false; - throw Barry::ErrnoError("IpModem:: Error creating USB read thread.", ret); + throw Barry::ErrnoError("IpModem: Error creating USB read thread.", ret); } } @@ -293,7 +362,7 @@ void IpModem::Close() Data data; //0 0 0 0 b0 0 0 0 0 0 0 0 0 c2 1 0 + session_key + special_flag - ddout("IpModem:: Closing connection."); + ddout("IpModem: Closing connection."); memset(end, 0, sizeof(end)); end[4] = 0xb0; end[13] = 0xc2; @@ -324,18 +393,18 @@ void IpModem::Close() m_dev.BulkWrite(write_ep, stop, sizeof(stop)); try { m_dev.BulkRead(read_ep, data, 5000); - ddout("IPModem:: Close read packet:\n" << data); + ddout("IPModem: Close read packet:\n" << data); } catch( Usb::Timeout &to ) { // do nothing on timeouts - ddout("IPModem:: Close Read Timeout"); + ddout("IPModem: Close Read Timeout"); } // stop the read thread if( m_continue_reading ) { m_continue_reading = false; pthread_join(m_modem_read_thread, NULL); } - ddout("IPmodem:: Closed!"); + ddout("IPmodem: Closed!"); } diff --git a/src/m_ipmodem.h b/src/m_ipmodem.h index 23e5ffa..c58882f 100644 --- a/src/m_ipmodem.h +++ b/src/m_ipmodem.h @@ -59,7 +59,7 @@ private: unsigned char m_session_key[8]; // = { 0x00, 0, 0, 0, 0, 0, 0, 0 }; private: - BXLOCAL bool SendPassword(const char *password = 0); + BXLOCAL bool SendPassword(const char *password = 0, uint32_t seed = 0); protected: static void *DataReadThread(void *userptr);
------------------------------------------------------------------------------ Check out the new SourceForge.net Marketplace. It is the best place to buy or sell services for just about anything Open Source. http://p.sf.net/sfu/Xq1LFB
_______________________________________________ Barry-devel mailing list Barry-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/barry-devel