Subject: All upstream commits until r59 combined Author: Daviedev Forwarded: not-needed --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,13 @@ -0.3: +1.0 Daniel J Blueman + - Fix behaviour with newer U3 devices + - Printing fixes + - Detach mass-storage prior to USB access + - Gracefully quit with Ctrl-C + - Print data partition size when too small + - Limit update printing rate + - Fix linking to libusb; recommended over SG + +0.3 - Detect correct subsystem from configure. - Use MinGW/MSYS to build on MS Windows - Hide password input under MS Windows --- a/TODO +++ b/TODO @@ -1,6 +1,5 @@ Major: - If possible open sg subsystem Read-only to work around NOMEDIUM error with encrypted partition - - Handle ctrl-c - Documentation - Further documentation of U3 features - Document which options are destructive --- a/configure.ac +++ b/configure.ac @@ -37,11 +37,11 @@ # Checks for libraries. #FIXME: PKG_CHECK_MODULES not provided on MinGW -#AS_IF([ test x$subsystem = xlibusb ], -# [ PKG_CHECK_MODULES([LIBUSB], [libusb], -# [ ], -# [ AC_MSG_FAILURE([libusb is required but not found.]) ]) -# ]) +AS_IF([ test x$subsystem = xlibusb ], + [ PKG_CHECK_MODULES([LIBUSB], [libusb], + [ ], + [ AC_MSG_FAILURE([libusb is required but not found.]) ]) + ]) # Checks for header files. AC_HEADER_STDC --- /dev/null +++ b/doc/commands.txt @@ -0,0 +1,579 @@ + +--- + +>> 0x00 +description: + Read a page with some sort of device info + +type: request + +command: + + CBWCB = 0xFF 0x00 0x00 0x03 0x00 0x27 0x00 0x00 0x00 0x00 0x00 0x00 + + byte data description + ------------------------------------------------------------------------------ + 0 0xFF SCSI opcode + 1-2 0x0000 command + 3-4 0x0003 Page number + 5-6 0x27 Request data length + 9 0x0 ??? sofware update tool also uses 0x01 here + + valid page numbers according to bCSWStatus: + verbatime: 0x3, 0x4, 0x6, 0x8, 0xa, 0xc, 0xe, 0x13, 0x14 + +data: + 6+ bytes + + 0000 03 00 01 00 27 00 |....'. | + + byte data description + ------------------------------------------------------------------------------ + 0-1 0x0003 page number + 2-3 0x0001 ??? mostly 0x01, once 0x03 + 4-5 0x0027 total usefull data length (including 6 byte header) + + +page 0x03: + + 0000 03 00 01 00 27 00 77 00 00 00 03 81 07 06 54 30 |....'.w.......T0| + 0016 30 30 30 31 31 41 31 41 41 31 31 41 41 41 31 81 |00011A1AA11AAA1.| + 0032 07 06 54 91 4e 0f 00 |..T.N..| + + byte data description + ------------------------------------------------------------------------------ + 0-5 header(see above) + 6 Real size of full record...???? + 7-11 ??? same for both verbatime and sandisk + 11-14 0x54060781 ??? same as @ byte 31 (actual value different on verbatim) + 15-30 "000011A1AA11AAA1" Serial number + 31-34 0x54060781 ??? same as @ byte 11 + 35-38 0x000f4e91 Device size in 512-byte blocks + +page 0x0c: + + 0000 0c 00 01 00 0a 00 10 27 00 00 |.......'.. | + + byte data description + ------------------------------------------------------------------------------ + 0-5 header(see above) + 6-9 0x00002710 Maximum wrong password try for secure zone. + +--- + +>> 0x20 +description: + Round CD size to a value the device likes + +type: action + +command: + CBWCB = 0xFF 0x20 0x00 0x02 0xFF 0x03 0x00 0x00 0x00 0x00 0x00 0x00 + + byte data description + ------------------------------------------------------------------------------ + 0 0xFF scsi opcode + 1-2 0x0020 command + 3 0x02 ??? can atleast be 0x02 and 0x03 but not 0, 1, 4, is + this some sort of domain id to select the partition, + like in 0x21, byte 3??? the verbatim is less picky and + accepts all values... + 4-7 0x3FF Value to round (in 512-byte sectors) + 8 0x0 Direction to round(0x00 = down, 0x01 = up) + +data: + 4 bytes + + 0000 00 02 00 00 |....| + + byte data description + ------------------------------------------------------------------------------ + 0-3 0x200 Rounded value + +--- + +>> 0x21 +description: + get information about the partition configuration + +type: request + +command: + CBWCB = 0xFF 0x21 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + + byte data description + ------------------------------------------------------------------------------ + +data: + + 0000 02 02 00 00 00 91 1e 0f 00 03 01 00 00 00 30 00 |..............0.| + can be read in any multiple of 8 all dat beyond the above data is zero(0) + + u3-remover uses the following data(IIRC), (0x0f4e91 == full drive size): + 0000 01 02 00 00 00 91 4e 0f 00 |......... | + + + byte data description + ------------------------------------------------------------------------------ + 0 02 amount of available records, where 1 record = 8 byte??? + 1 02 ??? some sort of domain id??? + 3-4 00 00 00 ?? + 5-8 0x000F1E91 size of data partition in 512-byte sectors + 9 0x03 ?? some sort of domain id???? + 10 0x01 ?? WARNING: If set to 0 on Sandisk cruzer, cd drive + will show up as direct-access, but can't be used, also + drive doesn't react to command 0x00, page 3 and you + won't be able to re-partition device!!!! + 11-12 00 00 ?? + 13-15 0x003000 size of cdrom partitoin in 512-byte sectors + +--- + +>> 0x22 +description: + Repartition device + +type: action + +command: + CBWCB = 0xFF 0x22 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + + byte data description + ------------------------------------------------------------------------------ + +data: + 0000 02 02 00 00 00 91 1e 0f 00 03 01 00 00 00 30 00 |..............0.| + 0016 00 |. | + + + byte data description + ------------------------------------------------------------------------------ + 0 0x02 amount of dword of data(+1byte+1dword=packet_size) + 1-4 0x00000002 ??? + 5-8 0x000f1e91 Size of data partition in 512-byte sectors + 9-12 0x00000103 ??? 0x0003 make's it a direct access partition.(but can't partition afterwards, and page 3 of command 0x0000 isn't accessible anymore...) + 13-16 0x00003000 Size of CD partition in 512-byte sectors + +--- + +>> 0x42 +description: + Write block of data to CD-rom partition + +type: action + +command: + CBWCB = 0xFF 0x42 0x00 0x01 0x00 0x00 0x01 0x1D 0x00 0x00 0x00 0x01 + + byte data description + ------------------------------------------------------------------------------ + 0 0xFF scsi opcode + 1-2 0x42 command + 3 0x01 ??? + 4-7 0x0000011D Block Address (Big Endian!!!!!!!) + 8-11 0x01 ??? (Big Endian?) + +data: + A 2048 byte block + +--- + +>> 0x61 +description: + read out hidden data/config storage. Looks the same as with mDrive. + +type: request + +command: + CBWCB = 0xFF 0x61 0x00 0x01 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + + byte data description + ------------------------------------------------------------------------------ + +data: + + + byte data description + ------------------------------------------------------------------------------ + +--- + +>> 0x63 +description: + read out hidden data/config storage. Looks the similar as with mDrive. + +type: request + +command: + CBWCB = 0xFF 0x63 0x00 0x00 0x00 0x55 0x33 0x49 0x4E 0x50 0x52 0x50 + + byte data description + ------------------------------------------------------------------------------ + +data: + + + byte data description + ------------------------------------------------------------------------------ + +--- + +>> 0xA0 +description: + get some sort of data partition information + +type: request + +command: + + CBWCB = 0xFF 0xA0 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + + byte data description + ------------------------------------------------------------------------------ + +data: + 16 byte + + 0000 40 ab 1d 00 00 00 00 00 00 00 00 00 00 00 00 00 |@...............| + + 0000 40 ab 1d 00 40 ab 1d 00 01 00 00 00 00 00 00 00 |@...@...........| (secured) + + + byte data description + ------------------------------------------------------------------------------ + 0-3 0x001dab40 Total data partition size + 4-7 0x001dab40 Amount of data partition encrypted???? + 8-11 0x00000001 Lock(=0) or Unlocked(=1) + 12-15 0x00000000 Wrong password try counter + +--- + +>> 0xA1 +description: + FUZED + +type: Request? + +command: + + CBWCB = 0xFF 0xA1 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + + byte data description + ------------------------------------------------------------------------------ + 0 scsi opcode + 1-2 command + 3 0 Failes on Sandisk if != 0 + 4- changing these doesn't seem to have any effect + +data: + + data is random, and changes due to executing commands + + byte data description + ------------------------------------------------------------------------------ + + +--- + +>> 0xA2 +description: + Secure data partition + + Password hash is a md5 sum of the unicode password including the terminating + null. So for a password of 'a' the following byte stream is fead to the md5 + function: 0x61 0x00 0x00 0x00 == UNICODE "a\0" + + It seems that if the whole of the data partition is made secure zone, then + the data currently on the data partition is accessible in the secure zone. + If only a part of the data partition is made secure zone than the first part + of the data on the partition is retained and the rest isn't accessible. In + this case the secure zone will contain garbage(the data on that was on that + part of the data partition but decrypted with an other key). + + If the device is already secured and this command is issued again, the current + data on the device is lost(if secure zone == 100%). + +type: action + +command: + + CBWCB = 0xFF 0xA2 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + + byte data description + ------------------------------------------------------------------------------ + +data: + 20 byte + + 0000 40 ab 1d 00 33 2c e7 85 e9 73 57 4a 1c 5f da f3 |@...3,...sWJ._..| + 0016 ee e3 f0 83 |....| + + + byte data description + ------------------------------------------------------------------------------ + 0-3 0x001dab40 Size of private zone???? + 4-19 ... Password hash ( pass='a') + + +--- + +>> 0xA3 +description: + value rounding for data partition securing + +type: request + +command: + CBWCB = 0xFF 0xA3 0x00 0x00 0x40 0xAB 0x1D 0x00 0x01 0x00 0x00 0x00 + + byte data description + ------------------------------------------------------------------------------ + 0 0xFF scsi opcode + 1-2 0x00A3 Command + 3 0x00 ??? + 4-7 0x001DAB40 Value to round (in 512-byte sectors) + 8 0x01 Direction to round(0x00 = down, 0x01 = up) + + +data: + 4 byte + + 0000 40 ab 1d 00 |@...| + + byte data description + ------------------------------------------------------------------------------ + 0-3 0x001DAB40 Rounded value + +--- + +>> 0xA4 +description: + unlock device + + Password hash is a md5 sum of the unicode password including the terminating + null. So for a password of 'a' the following byte stream is fead to the md5 + function: 0x61 0x00 0x00 0x00 == UNICODE "a\0" + +type: action + +command: + + CBWCB = 0xFF 0xA4 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + + byte data description + ------------------------------------------------------------------------------ + +data: + 16 byte + + 0000 33 2c e7 85 e9 73 57 4a 1c 5f da f3 ee e3 f0 83 |3,...sWJ._......| + + byte data description + ------------------------------------------------------------------------------ + 0-15 ... password hash (pass='a') + +--- + +>> 0xA6 +description: + change password + + Password hash is a md5 sum of the unicode password including the terminating + null. So for a password of 'a' the following byte stream is fead to the md5 + function: 0x61 0x00 0x00 0x00 == UNICODE "a\0" + +type: action + +command: + + CBWCB = 0xFF 0xA6 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + + byte data description + ------------------------------------------------------------------------------ + +data: + + 0000 33 2c e7 85 e9 73 57 4a 1c 5f da f3 ee e3 f0 83 |3,...sWJ._......| + 0016 c0 51 c1 bb 98 b7 1c cb 15 b0 cf 9c 67 d1 43 ee |.Q..........g.C.| + + byte data description + ------------------------------------------------------------------------------ + 0-15 ... Old password hash ( pass='a') + 16-31 ... New password hash ( pass='b') + +--- + +>> 0xA7 +description: + Remove security + + Password hash is a md5 sum of the unicode password including the terminating + null. So for a password of 'a' the following byte stream is fead to the md5 + function: 0x61 0x00 0x00 0x00 == UNICODE "a\0" + + hmm... if security zone size != size of data partition, then this fails!!! + it returns a failed status but doesn't increase the password try counter, + even if password was incorrect.... to remove the secure zone if it doesn't + fully occupy the data partition, recreate the secure zone with maximum size. + > Possible cause: If this command is issued the secure zone becomes the public + zone, and thus all data on the disk will be retained. It is suspected that all + partitions/zones are stored encrypted on the flash device(Yes, even the public + zone). So, if this command is issued the secure zone key is decrypted(if + encrypted at all) and the zone is marked as public. Logically this would not + work if there is a public and secure zone. Then you would end up with two + public zone's with different encryptions keys. + + Byte 3 of command does something... but still doesn't allow for removing half + secure zones. + +type: action + +command: + + CBWCB = 0xFF 0xA7 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + + byte data description + ------------------------------------------------------------------------------ + +data: + + 0000 c0 51 c1 bb 98 b7 1c cb 15 b0 cf 9c 67 d1 43 ee |.Q..........g.C.| + + byte data description + ------------------------------------------------------------------------------ + 0-15 ... Password hash (in this case 'b') + +--- + +>> 0x100 +description: + seen used after a 0xA4(with some normal scsi stuff in between...). + generate reset some sort of reset or insert condition on data disk. Linux old 2.4 + usb-storage sees it as a disconnect of the drive. + +type: + +command: + + CBWCB = 0xFF 0x00 0x01 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + + byte data description + ------------------------------------------------------------------------------ + +data: + No data.... + + +--- + +>> 0x101 +description: + disconnect's and possibly reconnects device + +type: action + +command: + + CBWCB = 0xFF 0x01 0x01 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + + byte data description + ------------------------------------------------------------------------------ + +data: + 12 bytes + + 0000 50 00 00 00 40 9c 00 00 01 00 00 00 |P...@.......| + + byte data description + ------------------------------------------------------------------------------ + 8 0x01 If 1 reconnect after disconnect, else not + all other byte's dont seem to have any effect... + +--- + +>> 0x103 +description: +Get chip maker and version + +type: request + +command: + + CBWCB = 0xFF 0x03 0x01 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + + byte data description + ------------------------------------------------------------------------------ + +data: + 24 bytes + + 0000 33 2e 32 31 00 00 00 00 53 61 6e 44 69 73 6b 20 |3.21....SanDisk | + 0016 00 00 00 00 00 00 00 00 |........| + + byte data description + ------------------------------------------------------------------------------ + 0-7 "3.21" Chip version + 8-23 "SanDisk" Chip maker + + + + + + + +possible read commands: +0x20 +0x21 +0x61 +0x63 +0x68 +0x6b 512? +0x81 128-byte +0x84 64-byte +0x85 64-byte +0x88 64-byte +0xa1 4-byte +0xc1 +0xe2 = read random?, 64-byte + +0x102 512-byte + +Write: +0x01 -> 0x1f +0x22 -> 0x40 +0x42 +0x60 +0x62 +0x6a +0x6c +0x6d +0x6e +0x82 128 byte +0x83 64 byte? +0x86 +0x87 +0xc0 +0xc2 + + + + +--- + +>> +description: + +type: + +command: + + byte data description + ------------------------------------------------------------------------------ + +data: + + + byte data description + ------------------------------------------------------------------------------ + + --- a/src/display_progress.c +++ b/src/display_progress.c @@ -20,17 +20,18 @@ #include void display_progress(unsigned int cur, unsigned int total) { - unsigned int procent; - unsigned int bar_len; - int i; + static unsigned int last = 0; + unsigned int percent; + unsigned int bar_len, i; if (total == 0) return; - procent = (cur * 100) / total; + percent = (cur * 100) / total; + if (percent == last) return; putchar('|'); bar_len = (cur * PROGRESS_BAR_WIDTH) / total; - for (i =0; i < bar_len; i++) { + for (i = 0; i < bar_len; i++) { putchar('*'); } for (i = bar_len; i < PROGRESS_BAR_WIDTH; i++) { @@ -38,6 +39,8 @@ } putchar('|'); - printf(" %d%%\r", procent); + printf(" %d%%\r", percent); fflush(stdout); + + last = percent; } --- a/src/main.c +++ b/src/main.c @@ -24,6 +24,8 @@ #include #include #include +#include +#include #include #include @@ -42,10 +44,11 @@ #define MAX_FILENAME_STRING_LENGTH 1024 #define MAX_PASSWORD_LENGTH 1024 -char *version = VERSION; +static char *version = VERSION; int debug = 0; -int batch_mode = 0; +static int batch_mode = 0; +static int quit = 0; enum action_t { unknown, load, partition, dump, info, unlock, change_password, enable_security, disable_security, reset_security }; @@ -57,7 +60,7 @@ * * @returns TRUE if user wants to continue else FALSE to abort. */ -int confirm() { +static int confirm(void) { char c; int retval; int done; @@ -93,24 +96,24 @@ /** * Symbols of size multiplication factors. */ -char factor_symbols[] = "kMGTPE"; +static char factor_symbols[] = " kMGTPE"; /** * Print bytes is human readable fashion. * * @param size Data size to print */ -void print_human_size(uint64_t size) { - float fsize = 0; +static void print_human_size(uint64_t size) { + double fsize = 0; unsigned int factor = 0; fsize = size; - while (fsize > 1024) { + while (fsize >= 1024) { fsize /= 1024; factor++; } - printf("%.2f %cB", fsize, factor_symbols[factor-1]); + printf("%.2f %cB", fsize, factor_symbols[factor]); } /** @@ -122,7 +125,7 @@ * @returns U3_SUCCESS if successful, else U3_FAILURE and * an error string can be obtained using u3_error() */ -int get_tries_left(u3_handle_t *device, int *tries) { +static int get_tries_left(u3_handle_t *device, int *tries) { struct dpart_info dpinfo; struct property_0C security_properties; @@ -151,10 +154,10 @@ /********************************** Actions ***********************************/ -int do_load(u3_handle_t *device, char *iso_filename) { +static int do_load(u3_handle_t *device, char *iso_filename) { struct stat file_stat; struct part_info pinfo; - uint32_t cd_size; + off_t cd_size; FILE *fp; uint8_t buffer[U3_BLOCK_SIZE]; unsigned int bytes_read=0; @@ -171,10 +174,10 @@ return EXIT_FAILURE; } - cd_size = file_stat.st_size / U3_SECTOR_SIZE; + cd_size = ((uintmax_t) file_stat.st_size) / U3_SECTOR_SIZE; if (file_stat.st_size % U3_SECTOR_SIZE) cd_size++; - block_cnt = file_stat.st_size / U3_BLOCK_SIZE; + block_cnt = ((uintmax_t) file_stat.st_size) / U3_BLOCK_SIZE; if (file_stat.st_size % U3_BLOCK_SIZE) block_cnt++; @@ -186,10 +189,10 @@ } if (cd_size > pinfo.cd_size) { - fprintf(stderr, "CD image(%lu byte) is to big for current cd " - "partition(%u byte), please repartition device.\n", - file_stat.st_size, - U3_SECTOR_SIZE * pinfo.cd_size); + fprintf(stderr, "CD image (%ju bytes) is to big for current CD " + "partition (%llu bytes)\n", + (uintmax_t) file_stat.st_size, + 1ll * U3_SECTOR_SIZE * pinfo.cd_size); return EXIT_FAILURE; } @@ -228,7 +231,7 @@ } block_num++; - } while (!feof(fp)); + } while (!feof(fp) && !quit); display_progress(block_num, block_cnt); putchar('\n'); @@ -238,7 +241,7 @@ return EXIT_SUCCESS; } -int do_partition(u3_handle_t *device, char *size_string) { +static int do_partition(u3_handle_t *device, char *size_string) { uint64_t size; uint32_t cd_sectors; @@ -263,7 +266,7 @@ return EXIT_SUCCESS; } -int do_unlock(u3_handle_t *device, char *password) { +static int do_unlock(u3_handle_t *device, char *password) { int result=0; int tries_left=0; @@ -297,7 +300,7 @@ } } -int do_change_password(u3_handle_t *device, char *password, +static int do_change_password(u3_handle_t *device, char *password, char *new_password) { int result=0; @@ -335,7 +338,7 @@ } } -int do_enable_security(u3_handle_t *device, char *password) { +static int do_enable_security(u3_handle_t *device, char *password) { if (u3_enable_security(device, password) != U3_SUCCESS) { fprintf(stderr, "u3_enable_security() failed: %s\n", u3_error_msg(device)); @@ -345,7 +348,7 @@ return EXIT_SUCCESS; } -int do_disable_security(u3_handle_t *device, char *password) { +static int do_disable_security(u3_handle_t *device, char *password) { int result=0; int tries_left=0; @@ -380,7 +383,7 @@ } } -int do_reset_security(u3_handle_t *device) { +static int do_reset_security(u3_handle_t *device) { int result=0; // the enable security command is always possible without the correct @@ -408,7 +411,7 @@ } } -int do_info(u3_handle_t *device) { +static int do_info(u3_handle_t *device) { struct part_info pinfo; struct dpart_info dpinfo; struct chip_info cinfo; @@ -484,8 +487,8 @@ return EXIT_SUCCESS; } -int do_dump(u3_handle_t *device) { - int retval = EXIT_SUCCESS; +static int do_dump(u3_handle_t *device) { + int retval; struct part_info pinfo; struct dpart_info dpinfo; @@ -595,12 +598,12 @@ } } - return EXIT_SUCCESS; + return retval; } /************************************ Main ************************************/ -void usage(const char *name) { +static void usage(const char *name) { printf("u3-tool %s - U3 USB stick manager\n", version); printf("\n"); printf("Usage: %s [options] \n", name); @@ -622,7 +625,7 @@ printf("For the device name use:\n %s\n", u3_subsystem_help); } -void print_version() { +static void print_version(void) { printf("u3-tool %s\n", version); printf("subsystem: %s\n", u3_subsystem_name); printf("\n"); @@ -632,6 +635,10 @@ "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n"); } +static void set_quit(int sig) { + quit = 1; +} + int main(int argc, char *argv[]) { u3_handle_t device; @@ -711,6 +718,9 @@ } device_name = argv[optind]; + assert(signal(SIGINT, set_quit) != SIG_ERR); + assert(signal(SIGTERM, set_quit) != SIG_ERR); + // // open the device // @@ -772,9 +782,9 @@ case partition: printf("\n"); printf("WARNING: Loading a new cd image causes the "); - printf("whole device to be whiped. This INCLUDES\n "); + printf("whole device to be wiped. This INCLUDES\n "); printf("the data partition.\n"); - printf("I repeat: ANY EXCISTING DATA WILL BE LOST!\n"); + printf("I repeat: ANY EXISTING DATA WILL BE LOST!\n"); if (confirm()) retval = do_partition(&device, size_string); break; --- a/src/secure_input.c +++ b/src/secure_input.c @@ -33,9 +33,9 @@ DWORD mode; HANDLE ih; #else - struct termio ttymode; + struct termios ttymode; #endif - int pos; + size_t pos; int ch; // input checking @@ -51,9 +51,9 @@ } SetConsoleMode(ih, mode & ~(ENABLE_ECHO_INPUT )); #else - ioctl(STDIN_FILENO, TCGETA, &ttymode); + tcgetattr(STDIN_FILENO, &ttymode); ttymode.c_lflag &= ~( ECHO | ECHOE | ECHONL ); - ioctl(STDIN_FILENO, TCSETAF, &ttymode); + tcsetattr(STDIN_FILENO, TCSAFLUSH, &ttymode); #endif pos=0; @@ -75,7 +75,7 @@ fputc('\n', stdout); #else ttymode.c_lflag |= ECHO | ECHOE | ECHONL; - ioctl(STDIN_FILENO, TCSETAF, &ttymode); + tcsetattr(STDIN_FILENO, TCSAFLUSH, &ttymode); fputc('\n', stdout); #endif } --- a/src/u3_commands.c +++ b/src/u3_commands.c @@ -52,10 +52,9 @@ * U3_PASSWORD_HASH_LEN long. */ void u3_pass_to_hash(const char *password, uint8_t *hash) { - unsigned int passlen; + unsigned int passlen, i; unsigned int unicode_passlen; uint8_t *unicode_pass; - int i; passlen = strlen(password); unicode_passlen = (passlen+1)*2; @@ -178,7 +177,7 @@ return U3_FAILURE; } if (cd_size > device_properties.device_size) { - u3_set_error(device, "Requested CD size is to big for device"); + u3_set_error(device, "Requested CD size is larger than device (%ull bytes)", device_properties.device_size << 9ULL); return U3_FAILURE; } --- /dev/null +++ b/src/u3_scsi_debug.c @@ -0,0 +1,111 @@ +/** + * u3-tool - U3 USB stick manager + * Copyright (C) 2007 Daviedev, daviedev@users.sourceforge.net + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#include "u3_scsi.h" +#include "u3_error.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "sg_err.h" + +#define U3_TIMEOUT 2000 //2000 millisecs == 2 seconds + +int u3_open(u3_handle_t *device, const char *which) +{ + FILE *fp; + + u3_set_error(device, ""); + device->dev = NULL; + + if (strcmp(which, "stdout") == 0) { + fp = stdout; + } else if (strcmp(which, "stderr") == 0) { + fp = stderr; + } else { + u3_set_error(device, "unknown output '%s', 'stdout' and " + "'stderr' only supported", which); + return U3_FAILURE; + } + + device->dev = fp; + return U3_SUCCESS; +} + +void u3_close(u3_handle_t *device) +{ + FILE *fp = (FILE *)(device->dev); +// if (fp != stdout && fp != stderr) { +// fclose(fp); +// } +} + +int u3_send_cmd(u3_handle_t *device, uint8_t cmd[U3_CMD_LEN], + int dxfer_direction, int dxfer_length, uint8_t *dxfer_data, + uint8_t *status) +{ + FILE *fp = (FILE *)device->dev; + int i; + + fprintf(fp, "---------------------------------------------------------" + "-----------------------\n"); + + fprintf(fp, "Command block:\n"); + for (i=0; i < U3_CMD_LEN; i++) { + fprintf(fp, "%.2X ", cmd[i]); + } + fprintf(fp, "\n"); + + fprintf(fp, "\n"); + switch (dxfer_direction) { + case U3_DATA_NONE: + fprintf(fp, "No data\n"); + break; + case U3_DATA_TO_DEV: + fprintf(fp, "Sending %d bytes of data to device\n", dxfer_length); + + fprintf(fp, "Data:"); + for (i=0; i < dxfer_length; i++) { + if (i % 8 == 0) fprintf(fp, "\n%.4x\t", i); + fprintf(fp, "%.2x ", dxfer_data[i]); + } + fprintf(fp, "\n"); + break; + case U3_DATA_FROM_DEV: + fprintf(fp, "Reading %d bytes of data from device\n", dxfer_length); + memset(dxfer_data, 0, dxfer_length); + break; + } + + fprintf(fp, "---------------------------------------------------------" + "-----------------------\n"); + + *status = 0; + + return U3_SUCCESS; +} + + --- a/src/u3_scsi_sg.c +++ b/src/u3_scsi_sg.c @@ -32,13 +32,14 @@ #include #include #include +#include #include #include #include "sg_err.h" -#define U3_TIMEOUT 2000 //2000 millisecs == 2 seconds +#define SG_TIMEOUT 2000 //2000 millisecs == 2 seconds const char *u3_subsystem_name = "sg"; const char *u3_subsystem_help = "'/dev/sda0', '/dev/sg3'"; @@ -97,6 +98,7 @@ { int *sg_fd = (int *)device->dev; close(*sg_fd); + free(sg_fd); } int u3_send_cmd(u3_handle_t *device, uint8_t cmd[U3_CMD_LEN], @@ -123,23 +125,23 @@ // Prepare command memset(&io_hdr, 0, sizeof(sg_io_hdr_t)); io_hdr.interface_id = 'S'; // fixed + io_hdr.dxfer_direction = dxfer_direction; // Select data direction io_hdr.cmd_len = U3_CMD_LEN; // length of command in bytes - // io_hdr.iovec_count = 0; // don't use iovector stuff - io_hdr.mx_sb_len = sizeof(sense_buf); // sense buffer size. do we use this??? - io_hdr.dxfer_direction = dxfer_direction; // send data to device + io_hdr.mx_sb_len = 0; // sense buffer size. do we use this??? + io_hdr.iovec_count = 0; // don't use iovector stuff io_hdr.dxfer_len = dxfer_length; // Size of data transfered io_hdr.dxferp = dxfer_data; // Data buffer to transfer io_hdr.cmdp = cmd; // Command buffer to execute io_hdr.sbp = sense_buf; // Sense buffer - io_hdr.timeout = U3_TIMEOUT; // timeout - // io_hdr.flags = 0; // take defaults: indirect IO, etc + io_hdr.timeout = SG_TIMEOUT; // timeout + io_hdr.flags = 0; // take defaults: indirect IO, etc // io_hdr.pack_id = 0; // internal packet. used by te program to recognize packets // io_hdr.usr_ptr = NULL; // user data // preform ioctl on device if (ioctl(*sg_fd, SG_IO, &io_hdr) < 0) { u3_set_error(device, "Failed executing scsi command: " - "SG_IO ioctl Failed"); + "SG_IO ioctl failed with %s", strerror(errno)); return U3_FAILURE; } --- a/src/u3_scsi_spt.c +++ b/src/u3_scsi_spt.c @@ -36,7 +36,7 @@ #include #include -#define U3_TIMEOUT 2 // 2 seconds +#define SPT_TIMEOUT 2 // 2 seconds const char *u3_subsystem_name = "spt"; const char *u3_subsystem_help = "The drive letter of the device"; @@ -58,11 +58,11 @@ return U3_FAILURE; } - //take the drive letter and put it in the format used in CreateFile + // Take the drive letter and put it in the format used in CreateFile memcpy(lpszDeviceName, (char *) "\\\\.\\*:", 7); lpszDeviceName[4] = which[0]; - //get a handle to the device, the parameters used here must be used in order for this to work + // Get a handle to the device, the parameters used here must be used in order for this to work hDevice=CreateFile(lpszDeviceName, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, @@ -71,7 +71,8 @@ FILE_ATTRIBUTE_NORMAL, NULL); - //if for some reason we couldn't get a handle to the device we will try again using slightly different parameters for CreateFile + // If for some reason we couldn't get a handle to the device we will try again using slightly + // different parameters for CreateFile if (hDevice==INVALID_HANDLE_VALUE) { u3_set_error(device, "Failed openning handle for %s: Error %d\n", which, GetLastError()); @@ -118,19 +119,40 @@ sptd.SenseInfoLength = 0; // don't use this currently... sptd.DataIn = dxfer_direction; // data direction sptd.DataTransferLength = dxfer_length; // Size of data transfered - sptd.TimeOutValue = U3_TIMEOUT; // timeout in seconds + sptd.TimeOutValue = SPT_TIMEOUT; // timeout in seconds sptd.DataBuffer = dxfer_data; // data buffer //sptd.SenseInfoOffset = offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS, sbuf); memcpy(sptd.Cdb, cmd, U3_CMD_LEN); // preform ioctl on device - err = DeviceIoControl(hDevice, IOCTL_SCSI_PASS_THROUGH_DIRECT, &sptd, - sizeof(sptd), &sptd, sizeof(sptd), &returned, NULL); + err = DeviceIoControl(hDevice, IOCTL_SCSI_PASS_THROUGH_DIRECT, &sptd, + sizeof(sptd), &sptd, sizeof(sptd), &returned, NULL); // evaluate result if (!err) { - u3_set_error(device, "Failed executing scsi command: " - "Error %d", GetLastError()); + DWORD errcode; + LPVOID lpMsgBuf; + + errcode = GetLastError(); + + err = FormatMessage( + FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + errcode, + 0, + (LPTSTR) &lpMsgBuf, + 0, + NULL); + + if (err != 0) { + u3_set_error(device, "Failed executing scsi command: " + "%s (Error %d)", lpMsgBuf, errcode); + LocalFree(lpMsgBuf); + } else { + u3_set_error(device, "Failed executing scsi command: " + "Unknown Error %d", errcode); + } + return U3_FAILURE; } --- a/src/u3_scsi_usb.c +++ b/src/u3_scsi_usb.c @@ -1,6 +1,6 @@ /** * u3-tool - U3 USB stick manager - * Copyright (C) 2007 Daviedev, daviedev@users.sourceforge.net + * Copyright (C) 2011 Daviedev, daviedev@users.sourceforge.net * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -30,34 +30,35 @@ #include #include #include +#include #include #include #include // USB maximum packet length -#define USB_MAX_PACKET_LEN 256 +#define USB_MAX_PACKET_LEN 2048 // USB command block wrapper length #define U3_CBWCB_LEN 12 -// USB MSC command/status wrapper signatures -#define CBW_SIGNATURE 0x43425355 -#define CSW_SIGNATURE 0x53425355 - // USB MSC command block wrapper data direction bits #define CBW_DATA_IN 0x80 #define CBW_DATA_OUT 0x00 #define CBW_DATA_NONE 0x00 #define CBW_FLAG_DIRECTION 0x80 -#define U3_DEVICE_TIMEOUT 20000 //2000 millisecs == 2 seconds +#define U3_DEVICE_TIMEOUT 2000 //2000 millisecs == 2 seconds -#define U3_DEV_LIST_LENGTH 4 -uint16_t u3_dev_list[U3_DEV_LIST_LENGTH][2] = { +uint16_t u3_dev_list[][2] = { { 0x08ec, 0x0020 }, // Verbatim Store 'N Go { 0x0781, 0x5406 }, // Sandisk Cruzer Micro { 0x0781, 0x5408 }, // Sandisk Cruzer Titanium { 0x0781, 0x550a }, // Sandisk Cruzer Pattern + { 0x0781, 0x5151 }, // Sandisk Cruzer Micro Skin 8GB (Thanks to dnelson @sf) + { 0x0781, 0x540e }, // Sandisk Cruzer Contour + { 0x0781, 0x5530 }, // Sandisk Cruzer + { 0x0781, 0x5535 }, // Sandisk Ultra Backup + { 0, 0 }, }; struct u3_usb_handle { @@ -69,7 +70,7 @@ typedef struct u3_usb_handle u3_usb_handle_t; struct usb_msc_cbw { - uint32_t dCBWSignature; + uint8_t dCBWSignature[4]; uint32_t dCBWTag; uint32_t dCBWDataTransferLength; uint8_t bmCBWFlags; @@ -79,7 +80,7 @@ } __attribute__ ((packed)); struct usb_msc_csw { - uint32_t dCSWSignature; + uint8_t dCSWSignature[4]; uint32_t dCSWTag; uint32_t dCSWDataResidue; uint8_t bCSWStatus; @@ -88,7 +89,7 @@ const char *u3_subsystem_name = "libusb"; const char *u3_subsystem_help = "'scan' to automatically use the first detected U3 device, or 'vid:pid' if not detected"; -struct usb_device * +static struct usb_device * locate_u3_device(uint16_t vid, uint16_t pid) { struct usb_bus *bus; @@ -115,6 +116,7 @@ { uint16_t vid, pid; regex_t vid_pid_regex; + int has_vid_pid = 0; struct usb_device *u3_device; u3_usb_handle_t *handle_wrapper; @@ -125,7 +127,6 @@ int err; char errbuf[U3_MAX_ERROR_LEN]; - int i; // init u3_set_error(device, ""); @@ -137,25 +138,45 @@ "expression: %s", errbuf); return U3_FAILURE; } + if (regexec(&vid_pid_regex, which, 0, 0, 0) == 0) { + // Do de regexing here, this prevents leaking of the + // vid_pid_regex memory + char *seperator=0; + has_vid_pid = 1; + vid = strtoul(which, &seperator, 16); + pid = strtoul(seperator+1, &seperator, 16); + } + regfree(&vid_pid_regex); usb_init(); if (debug) usb_set_debug(255); // Find device - if (regexec(&vid_pid_regex, which, 0, 0, 0) == 0) { - char *seperator=0; - vid = strtoul(which, &seperator, 16); - pid = strtoul(seperator+1, &seperator, 16); + if (has_vid_pid) { u3_device = locate_u3_device(vid, pid); + + if (u3_device == NULL) { + u3_set_error(device, "Could not locate the U3 device '%s', " + "try 'scan' for first available device", which); + return U3_FAILURE; + } } else if (strcmp(which, "scan") == 0) { - i = 0; + int i = 0; u3_device = NULL; - while (u3_device == NULL && i < U3_DEV_LIST_LENGTH) { + while (u3_device == NULL && + !(u3_dev_list[i][0] == 0 && u3_dev_list[i][1] == 0)) + { u3_device = locate_u3_device(u3_dev_list[i][0], u3_dev_list[i][1]); i++; } + + if (u3_device == NULL) { + u3_set_error(device, "Could not locate any known U3 device, " + "the VID:PID of your device might not be known to U3 tool"); + return U3_FAILURE; + } // } else if (regexec(&serial_regex, which, 0, 0, 0) == 0) { //TODO: search for a specific serial number } else { @@ -164,14 +185,6 @@ return U3_FAILURE; } - regfree(&vid_pid_regex); - - if (u3_device == NULL) { - u3_set_error(device, "Could not locate the U3 device '%s', " - "try 'scan' for first available device", which); - return U3_FAILURE; - } - // Open device handle_wrapper = (u3_usb_handle_t *) malloc(sizeof(u3_usb_handle_t)); if (handle_wrapper == NULL) { @@ -203,8 +216,13 @@ goto open_fail; } interface_desc = config_desc->interface->altsetting; - handle_wrapper->interface_num = interface_desc->bInterfaceNumber; + err = usb_detach_kernel_driver_np(handle_wrapper->handle, handle_wrapper->interface_num); + if (err != 0 && err != -61) { + u3_set_error(device, "failed to detach USB device with %s", strerror(errno)); + goto open_fail; + } + if ((err=usb_claim_interface(handle_wrapper->handle, handle_wrapper->interface_num)) != 0) { @@ -274,6 +292,8 @@ int dxfer_direction, int dxfer_length, uint8_t *dxfer_data, uint8_t *status) { + unsigned int tag = 1; + int res; u3_usb_handle_t *handle_wrapper = (u3_usb_handle_t *) device->dev; struct usb_msc_cbw cbw; struct usb_msc_csw csw; @@ -294,16 +314,21 @@ } // Prepare command - memset(&cbw, 0, sizeof(cbw)); - cbw.dCBWSignature = CBW_SIGNATURE; + memset(&cbw, 0, sizeof(cbw)); + cbw.dCBWSignature[0] = 'U'; + cbw.dCBWSignature[1] = 'S'; + cbw.dCBWSignature[2] = 'B'; + cbw.dCBWSignature[3] = 'C'; cbw.dCBWDataTransferLength = dxfer_length; - cbw.bmCBWFlags |= (dxfer_direction & CBW_FLAG_DIRECTION); - cbw.bCBWCBLength = U3_CBWCB_LEN; - memcpy(&(cbw.CBWCB), cmd, U3_CBWCB_LEN); + cbw.bmCBWFlags = dxfer_direction & CBW_FLAG_DIRECTION; + cbw.dCBWTag = tag; + cbw.bCBWLUN = 1; + cbw.bCBWCBLength = U3_CBWCB_LEN; + memcpy(&(cbw.CBWCB), cmd, U3_CBWCB_LEN); // send command - if (usb_bulk_write(handle_wrapper->handle, handle_wrapper->ep_out, - (char *) &cbw, sizeof(cbw), U3_DEVICE_TIMEOUT) + if ((res = usb_bulk_write(handle_wrapper->handle, handle_wrapper->ep_out, + (char *) &cbw, sizeof(cbw), U3_DEVICE_TIMEOUT)) != sizeof(cbw)) { u3_set_error(device, "Failed executing scsi command: " @@ -321,10 +346,10 @@ if (plen > USB_MAX_PACKET_LEN) plen = USB_MAX_PACKET_LEN; - if (usb_bulk_write(handle_wrapper->handle, + if ((res = usb_bulk_write(handle_wrapper->handle, handle_wrapper->ep_out, (char *) dxfer_data+bytes_send, plen, - U3_DEVICE_TIMEOUT) != plen) + U3_DEVICE_TIMEOUT)) < 0) { u3_set_error(device, "Failed executing scsi command: " "Could not write data to device"); @@ -334,9 +359,9 @@ bytes_send += plen; } } else if (dxfer_direction == CBW_DATA_IN) { - if (usb_bulk_read(handle_wrapper->handle, handle_wrapper->ep_in, + if ((res = usb_bulk_read(handle_wrapper->handle, handle_wrapper->ep_in, (char *) dxfer_data, dxfer_length, - U3_DEVICE_TIMEOUT) != dxfer_length) + U3_DEVICE_TIMEOUT)) < 0) { u3_set_error(device, "Failed executing scsi command: " "Could not read data from device"); @@ -344,16 +369,20 @@ } } + memset(&csw, 0, sizeof(csw)); + // read command status - if (usb_bulk_read(handle_wrapper->handle, handle_wrapper->ep_in, - (char *) &csw, sizeof(csw), U3_DEVICE_TIMEOUT) - != sizeof(csw)) + if ((res = usb_bulk_read(handle_wrapper->handle, handle_wrapper->ep_in, + (char *) &csw, sizeof(csw), U3_DEVICE_TIMEOUT)) + < 0) { u3_set_error(device, "Failed executing scsi command: " "Could not read command status from device"); return U3_FAILURE; } + assert(tag == csw.dCSWTag); + tag++; *status = csw.bCSWStatus; return U3_SUCCESS;