/* * Load the primary partition table (MBR) into the internal * data structures in MM_INFO * * This will automatically call load_ext_table for extended * partitions * * sect_cur is the addres of the table to load * * 0 is returned if the load is successful and 1 if error */ static uint8_t dos_load_prim_table(MM_INFO * mm, uint8_t test) { dos_sect sect; int i; char *table_str; SSIZE_T cnt; DADDR_T taddr = mm->offset / mm->block_size + DOS_PART_SOFFSET; DADDR_T max_addr = (mm->img_info->size - mm->offset) / mm->block_size; // max sector if (verbose) fprintf(stderr, "dos_load_prim: Table Sector: %" PRIuDADDR "\n", taddr); /* Read the table */ cnt = mm_read_block_nobuf (mm, (char *) §, sizeof(sect), DOS_PART_SOFFSET); if (cnt != sizeof(sect)) { snprintf(tsk_errstr2, TSK_ERRSTR_L, "Primary DOS table sector %" PRIuDADDR, taddr); if (cnt != -1) { tsk_errno = TSK_ERR_MM_READ; tsk_errstr[0] = '\0'; } return 1; } /* Sanity Check */ if (mm_guessu16(mm, sect.magic, DOS_MAGIC)) { tsk_errno = TSK_ERR_MM_MAGIC; snprintf(tsk_errstr, TSK_ERRSTR_L, "File is not a DOS partition (invalid primary magic) (Sector: %" PRIuDADDR ")", taddr); tsk_errstr2[0] = '\0'; return 1; } /* Because FAT and NTFS use the same magic - check for a * standard MS OEM name and sizes. Not a great check, but we can't * really test the table entries. */ if (test) { if (verbose) fprintf(stderr, "dos_load_prim_table: Testing FAT/NTFS conditions\n"); if (strncmp("MSDOS", sect.oemname, 5) == 0) { tsk_errno = TSK_ERR_MM_MAGIC; snprintf(tsk_errstr, TSK_ERRSTR_L, "dos_load_prim_table: MSDOS OEM name exists"); tsk_errstr2[0] = '\0'; return 1; } else if (strncmp("MSWIN", sect.oemname, 5) == 0) { tsk_errno = TSK_ERR_MM_MAGIC; snprintf(tsk_errstr, TSK_ERRSTR_L, "dos_load_prim_table: MSWIN OEM name exists"); tsk_errstr2[0] = '\0'; return 1; } else if (strncmp("NTFS", sect.oemname, 4) == 0) { tsk_errno = TSK_ERR_MM_MAGIC; snprintf(tsk_errstr, TSK_ERRSTR_L, "dos_load_prim_table: NTFS OEM name exists"); tsk_errstr2[0] = '\0'; return 1; } } /* Add an entry of 1 sector for the table to the internal structure */ if ((table_str = mymalloc(32)) == NULL) return 1; snprintf(table_str, 32, "Primary Table (#0)"); if (NULL == mm_part_add(mm, DOS_PART_SOFFSET, (DADDR_T) 1, MM_TYPE_DESC, table_str, -1, -1)) return 1; /* Cycle through the partition table */ for (i = 0; i < 4; i++) { dos_part *part = §.ptable[i]; /* We currently ignore CHS */ uint32_t part_start = getu32(mm, part->start_sec); uint32_t part_size = getu32(mm, part->size_sec); if (verbose) fprintf(stderr, "load_pri:0:%d Start: %" PRIu32 " Size: %" PRIu32 " Type: %d\n", i, part_start, part_size, part->ptype); if (part_size == 0) continue; if (part_start > max_addr) { tsk_errno = TSK_ERR_MM_BLK_NUM; snprintf(tsk_errstr, TSK_ERRSTR_L, "dos_load_prim_table: Starting sector too large for image"); tsk_errstr2[0] = '\0'; return 1; } #if 0 // I'm not sure if this is too strict ... else if ((part_start + part_size) > max_addr) { tsk_errno = TSK_ERR_MM_BLK_NUM snprintf(tsk_errstr, TSK_ERRSTR_L, "dos_load_prim_table: Partition ends after image"); tsk_errstr2[0] = '\0'; return 1; } #endif /* Add the partition to the internal structure * If it is an extended partition, process it now */ if (dos_is_ext(part->ptype)) { if (NULL == mm_part_add(mm, (DADDR_T) part_start, (DADDR_T) part_size, MM_TYPE_DESC, dos_get_desc(part->ptype), 0, i)) return 1; if (dos_load_ext_table(mm, part_start, part_start, 1)) return 1; } else { if (NULL == mm_part_add(mm, (DADDR_T) part_start, (DADDR_T) part_size, MM_TYPE_VOL, dos_get_desc(part->ptype), 0, i)) return 1; } } return 0; }
/* * Load the primary partition table (MBR) into the internal * data structures in TSK_VS_INFO * * This will automatically call load_ext_table for extended * partitions * * sect_cur is the address of the table to load * * 0 is returned if the load is successful and 1 if error */ static uint8_t dos_load_prim_table(TSK_VS_INFO * vs, uint8_t test) { dos_sect *sect; char *sect_buf; int i, added = 0; char *table_str; ssize_t cnt; TSK_DADDR_T taddr = vs->offset / vs->block_size + DOS_PART_SOFFSET; TSK_DADDR_T max_addr = (vs->img_info->size - vs->offset) / vs->block_size; // max sector if (tsk_verbose) tsk_fprintf(stderr, "dos_load_prim: Table Sector: %" PRIuDADDR "\n", taddr); if ((sect_buf = tsk_malloc(vs->block_size)) == NULL) return 1; sect = (dos_sect *) sect_buf; /* Read the table */ cnt = tsk_vs_read_block (vs, DOS_PART_SOFFSET, sect_buf, vs->block_size); if (cnt != vs->block_size) { if (cnt >= 0) { tsk_error_reset(); tsk_error_set_errno(TSK_ERR_VS_READ); } tsk_error_set_errstr2("Primary DOS table sector %" PRIuDADDR, taddr); free(sect_buf); return 1; } /* Sanity Check */ if (tsk_vs_guessu16(vs, sect->magic, DOS_MAGIC)) { tsk_error_reset(); tsk_error_set_errno(TSK_ERR_VS_MAGIC); tsk_error_set_errstr ("File is not a DOS partition (invalid primary magic) (Sector: %" PRIuDADDR ")", taddr); if (tsk_verbose) fprintf(stderr, "File is not a DOS partition (invalid primary magic) (Sector: %" PRIuDADDR ")", taddr); free(sect_buf); return 1; } /* Because FAT and NTFS use the same magic - check for a * standard MS OEM name and sizes. Not a great check, but we can't * really test the table entries. */ if (test) { if (tsk_verbose) tsk_fprintf(stderr, "dos_load_prim_table: Testing FAT/NTFS conditions\n"); if (strncmp("MSDOS", sect->oemname, 5) == 0) { tsk_error_reset(); tsk_error_set_errno(TSK_ERR_VS_MAGIC); tsk_error_set_errstr ("dos_load_prim_table: MSDOS OEM name exists"); if (tsk_verbose) tsk_fprintf(stderr, "dos_load_prim_table: MSDOS OEM name exists\n"); free(sect_buf); return 1; } else if (strncmp("MSWIN", sect->oemname, 5) == 0) { tsk_error_reset(); tsk_error_set_errno(TSK_ERR_VS_MAGIC); tsk_error_set_errstr ("dos_load_prim_table: MSWIN OEM name exists"); if (tsk_verbose) tsk_fprintf(stderr, "dos_load_prim_table: MSWIN OEM name exists\n"); free(sect_buf); return 1; } else if (strncmp("NTFS", sect->oemname, 4) == 0) { tsk_error_reset(); tsk_error_set_errno(TSK_ERR_VS_MAGIC); tsk_error_set_errstr ("dos_load_prim_table: NTFS OEM name exists"); if (tsk_verbose) tsk_fprintf(stderr, "dos_load_prim_table: NTFS OEM name exists\n"); free(sect_buf); return 1; } else if (strncmp("FAT", sect->oemname, 4) == 0) { tsk_error_reset(); tsk_error_set_errno(TSK_ERR_VS_MAGIC); tsk_error_set_errstr ("dos_load_prim_table: FAT OEM name exists"); if (tsk_verbose) tsk_fprintf(stderr, "dos_load_prim_table: FAT OEM name exists\n"); free(sect_buf); return 1; } } /* Add an entry of 1 sector for the table to the internal structure */ if ((table_str = tsk_malloc(32)) == NULL) { free(sect_buf); return 1; } snprintf(table_str, 32, "Primary Table (#0)"); if (NULL == tsk_vs_part_add(vs, DOS_PART_SOFFSET, (TSK_DADDR_T) 1, TSK_VS_PART_FLAG_META, table_str, -1, -1)) { free(sect_buf); return 1; } /* Cycle through the partition table */ for (i = 0; i < 4; i++) { dos_part *part = §->ptable[i]; /* We currently ignore CHS */ uint32_t part_start = tsk_getu32(vs->endian, part->start_sec); uint32_t part_size = tsk_getu32(vs->endian, part->size_sec); if (tsk_verbose) tsk_fprintf(stderr, "load_pri:0:%d Start: %" PRIu32 " Size: %" PRIu32 " Type: %d\n", i, part_start, part_size, part->ptype); if (part_size == 0) continue; // make sure the first couple are in the image bounds if ((i < 2) && (part_start > max_addr)) { tsk_error_reset(); tsk_error_set_errno(TSK_ERR_VS_BLK_NUM); tsk_error_set_errstr ("dos_load_prim_table: Starting sector too large for image"); if (tsk_verbose) tsk_fprintf(stderr, "Starting sector %" PRIu32 " too large for image\n", part_start); free(sect_buf); return 1; } #if 0 // I'm not sure if this is too strict ... else if ((part_start + part_size) > max_addr) { tsk_error_reset(); tsk_error_set_errno(TSK_ERR_VS_BLK_NUM); tsk_error_set_errstr ("dos_load_prim_table: Partition ends after image"); return 1; } #endif added = 1; /* Add the partition to the internal structure * If it is an extended partition, process it now */ if (dos_is_ext(part->ptype)) { if (NULL == tsk_vs_part_add(vs, (TSK_DADDR_T) part_start, (TSK_DADDR_T) part_size, TSK_VS_PART_FLAG_META, dos_get_desc(part->ptype), 0, i)) { free(sect_buf); return 1; } if (dos_load_ext_table(vs, part_start, part_start, 1)) { if (tsk_verbose) { fprintf(stderr, "Error loading extended table, moving on"); tsk_error_print(stderr); } tsk_error_reset(); } } else { if (NULL == tsk_vs_part_add(vs, (TSK_DADDR_T) part_start, (TSK_DADDR_T) part_size, TSK_VS_PART_FLAG_ALLOC, dos_get_desc(part->ptype), 0, i)) { free(sect_buf); return 1; } } } free(sect_buf); if (added == 0) { if (tsk_verbose) tsk_fprintf(stderr, "dos_load_prim: No valid entries\n"); tsk_error_reset(); tsk_error_set_errno(TSK_ERR_VS_MAGIC); tsk_error_set_errstr ("dos_load_prim_table: No valid entries in primary table"); return 1; } return 0; }
/* * Load an extended partition table into the structure in MM_INFO. * * sect_cur: The sector where the extended table is located * sect_ext_base: The sector of the primary extended table (this does * not change for recursive calls) * table: a counter that identifies the table depth * (increases by 1 for each recursive call) * * For the primary extended table, sect_cur == sect_ext_base * * Return 1 on error and 0 on success * */ static uint8_t dos_load_ext_table(MM_INFO * mm, DADDR_T sect_cur, DADDR_T sect_ext_base, int table) { dos_sect sect; int i; char *table_str; SSIZE_T cnt; DADDR_T max_addr = (mm->img_info->size - mm->offset) / mm->block_size; // max sector if (verbose) fprintf(stderr, "dos_load_ext: Table Sector: %" PRIuDADDR ", Primary Base Sector: %" PRIuDADDR "\n", sect_cur, sect_ext_base); /* Read the partition table sector */ cnt = mm_read_block_nobuf (mm, (char *) §, sizeof(sect), (DADDR_T) sect_cur); if (cnt != sizeof(sect)) { snprintf(tsk_errstr2, TSK_ERRSTR_L, "Extended DOS table sector %" PRIuDADDR, sect_cur); if (cnt != -1) { tsk_errno = TSK_ERR_MM_READ; tsk_errstr[0] = '\0'; } return 1; } /* Sanity Check */ if (getu16(mm, sect.magic) != DOS_MAGIC) { tsk_errno = TSK_ERR_MM_MAGIC; snprintf(tsk_errstr, TSK_ERRSTR_L, "Extended DOS partition table in sector %" PRIuDADDR, sect_cur); tsk_errstr2[0] = '\0'; return 1; } /* Add an entry of 1 length for the table to the internal structure */ if ((table_str = mymalloc(32)) == NULL) return 1; snprintf(table_str, 32, "Extended Table (#%d)", table); if (NULL == mm_part_add(mm, (DADDR_T) sect_cur, (DADDR_T) 1, MM_TYPE_DESC, table_str, table, -1)) { return 1; } /* Cycle through the four partitions in the table * * When another extended partition is found, it is processed * inside of the loop */ for (i = 0; i < 4; i++) { dos_part *part = §.ptable[i]; /* Get the starting sector and size, we currently * ignore CHS */ uint32_t part_start = getu32(mm, part->start_sec); uint32_t part_size = getu32(mm, part->size_sec); if (verbose) fprintf(stderr, "load_ext: %d:%d Start: %" PRIu32 " Size: %" PRIu32 " Type: %d\n", table, i, part_start, part_size, part->ptype); if (part_size == 0) continue; /* partitions are addressed differently * in extended partitions */ if (dos_is_ext(part->ptype)) { /* part start is added to the start of the * first extended partition (the primary * extended partition) */ if (sect_ext_base + part_start > max_addr) { tsk_errno = TSK_ERR_MM_BLK_NUM; snprintf(tsk_errstr, TSK_ERRSTR_L, "dos_load_ext_table: Starting sector too large for image"); tsk_errstr2[0] = '\0'; return 1; } if (NULL == mm_part_add(mm, (DADDR_T) (sect_ext_base + part_start), (DADDR_T) part_size, MM_TYPE_DESC, dos_get_desc(part->ptype), table, i)) return 1; /* Process the extended partition */ if (dos_load_ext_table(mm, sect_ext_base + part_start, sect_ext_base, table + 1)) return 1; } else { /* part_start is added to the start of the * current partition for the actual * starting location */ if (sect_cur + part_start > max_addr) { tsk_errno = TSK_ERR_MM_BLK_NUM; snprintf(tsk_errstr, TSK_ERRSTR_L, "dos_load_ext_table: Starting sector too large for image"); tsk_errstr2[0] = '\0'; return 1; } if (NULL == mm_part_add(mm, (DADDR_T) (sect_cur + part_start), (DADDR_T) part_size, MM_TYPE_VOL, dos_get_desc(part->ptype), table, i)) return 1; } } return 0; }
/* * Load an extended partition table into the structure in TSK_VS_INFO. * * sect_cur: The sector where the extended table is located * sect_ext_base: The sector of the primary extended table (this does * not change for recursive calls) * table: a counter that identifies the table depth * (increases by 1 for each recursive call) * * For the primary extended table, sect_cur == sect_ext_base * * Return 1 on error and 0 on success * */ static uint8_t dos_load_ext_table(TSK_VS_INFO * vs, TSK_DADDR_T sect_cur, TSK_DADDR_T sect_ext_base, int table) { dos_sect *sect; char *sect_buf; int i; char *table_str; ssize_t cnt; TSK_DADDR_T max_addr = (vs->img_info->size - vs->offset) / vs->block_size; // max sector if (tsk_verbose) tsk_fprintf(stderr, "dos_load_ext: Table Sector: %" PRIuDADDR ", Primary Base Sector: %" PRIuDADDR "\n", sect_cur, sect_ext_base); if ((sect_buf = tsk_malloc(vs->block_size)) == NULL) return 1; sect = (dos_sect *) sect_buf; /* Read the partition table sector */ cnt = tsk_vs_read_block(vs, sect_cur, sect_buf, vs->block_size); if (cnt != vs->block_size) { if (cnt >= 0) { tsk_error_reset(); tsk_error_set_errno(TSK_ERR_VS_READ); } tsk_error_set_errstr2("Extended DOS table sector %" PRIuDADDR, sect_cur); free(sect_buf); return 1; } /* Sanity Check */ if (tsk_getu16(vs->endian, sect->magic) != DOS_MAGIC) { tsk_error_reset(); tsk_error_set_errno(TSK_ERR_VS_MAGIC); tsk_error_set_errstr("Extended DOS partition table in sector %" PRIuDADDR, sect_cur); free(sect_buf); return 1; } /* Add an entry of 1 length for the table to the internal structure */ if ((table_str = tsk_malloc(32)) == NULL) { free(sect_buf); return 1; } snprintf(table_str, 32, "Extended Table (#%d)", table); if (NULL == tsk_vs_part_add(vs, (TSK_DADDR_T) sect_cur, (TSK_DADDR_T) 1, TSK_VS_PART_FLAG_META, table_str, table, -1)) { free(sect_buf); return 1; } /* Cycle through the four partitions in the table * * When another extended partition is found, it is processed * inside of the loop */ for (i = 0; i < 4; i++) { dos_part *part = §->ptable[i]; /* Get the starting sector and size, we currently * ignore CHS */ uint32_t part_start = tsk_getu32(vs->endian, part->start_sec); uint32_t part_size = tsk_getu32(vs->endian, part->size_sec); if (tsk_verbose) tsk_fprintf(stderr, "load_ext: %d:%d Start: %" PRIu32 " Size: %" PRIu32 " Type: %d\n", table, i, part_start, part_size, part->ptype); if (part_size == 0) continue; /* partitions are addressed differently * in extended partitions */ if (dos_is_ext(part->ptype)) { /* part start is added to the start of the * first extended partition (the primary * extended partition) */ if (NULL == tsk_vs_part_add(vs, (TSK_DADDR_T) (sect_ext_base + part_start), (TSK_DADDR_T) part_size, TSK_VS_PART_FLAG_META, dos_get_desc(part->ptype), table, i)) { free(sect_buf); return 1; } if (sect_ext_base + part_start > max_addr) { if (tsk_verbose) tsk_fprintf(stderr, "Starting sector %" PRIuDADDR " of extended partition too large for image\n", sect_ext_base + part_start); } /* Process the extended partition */ else if (dos_load_ext_table(vs, sect_ext_base + part_start, sect_ext_base, table + 1)) { free(sect_buf); return 1; } } else { /* part_start is added to the start of the * current partition for the actual * starting location */ // we ignore the max_addr checks on extended partitions... if (NULL == tsk_vs_part_add(vs, (TSK_DADDR_T) (sect_cur + part_start), (TSK_DADDR_T) part_size, TSK_VS_PART_FLAG_ALLOC, dos_get_desc(part->ptype), table, i)) { free(sect_buf); return 1; } } } free(sect_buf); return 0; }