1 /*
2  * The Sleuth Kit
3  *
4  * Brian Carrier [carrier <at> sleuthkit [dot] org]
5  * Copyright (c) 2006-2011 Brian Carrier, Basis Technology.  All rights reserved
6  * Copyright (c) 2003-2005 Brian Carrier.  All rights reserved
7  *
8  * This software is distributed under the Common Public License 1.0
9  */
10 
11 /** \file dos.c
12  * Contains the internal functions to process DOS Partition tables
13  */
14 
15 #include "tsk_vs_i.h"
16 #include "tsk_dos.h"
17 
18 
19 /* Check the extended partition flags */
20 #define dos_is_ext(x)	\
21 	((((x) == 0x05) || ((x) == 0x0F) || ((x) == 0x85)) ? 1 : 0)
22 
23 /*
24  * dos_get_desc
25  *
26  * Return a buffer with a string description of the partition type
27  *
28  * From: http://www.win.tue.nl/~aeb/partitions/partition_types-1.html
29  */
30 static char *
dos_get_desc(uint8_t ptype)31 dos_get_desc(uint8_t ptype)
32 {
33 #define DESC_LEN 64
34     char *str = tsk_malloc(DESC_LEN);
35     if (str == NULL)
36         return "";
37 
38     switch (ptype) {
39     case 0x00:
40         snprintf(str, DESC_LEN, "Empty (0x00)");
41         break;
42     case 0x01:
43         snprintf(str, DESC_LEN, "DOS FAT12 (0x01)");
44         break;
45     case 0x02:
46         snprintf(str, DESC_LEN, "XENIX root (0x02)");
47         break;
48     case 0x03:
49         snprintf(str, DESC_LEN, "XENIX /usr (0x03)");
50         break;
51     case 0x04:
52     case 0x06:
53         snprintf(str, DESC_LEN, "DOS FAT16 (0x%.2x)", ptype);
54         break;
55     case 0x05:
56         snprintf(str, DESC_LEN, "DOS Extended (0x05)");
57         break;
58     case 0x07:
59         snprintf(str, DESC_LEN, "NTFS / exFAT (0x07)");
60         break;
61     case 0x08:
62         snprintf(str, DESC_LEN, "AIX Boot (0x08)");
63         break;
64     case 0x09:
65         snprintf(str, DESC_LEN, "AIX Data (0x09)");
66         break;
67     case 0x0a:
68         snprintf(str, DESC_LEN, "OS/2 Boot Manager (0x0a)");
69         break;
70         /*
71            case 0x0a:
72            snprintf(str, DESC_LEN, "Coherent swap (0x0a)");
73            break;
74            case 0x0a:
75            snprintf(str, DESC_LEN, "OPUS (0x0a)");
76            break;
77          */
78     case 0x0b:
79     case 0x0c:
80         snprintf(str, DESC_LEN, "Win95 FAT32 (0x%.2x)", ptype);
81         break;
82     case 0x0e:
83         snprintf(str, DESC_LEN, "Win95 FAT16 (0x0e)");
84         break;
85     case 0x0f:
86         snprintf(str, DESC_LEN, "Win95 Extended (0x0f)");
87         break;
88     case 0x10:
89         snprintf(str, DESC_LEN, "OPUS (0x10)");
90         break;
91     case 0x11:
92         snprintf(str, DESC_LEN, "DOS FAT12 Hidden (0x11)");
93         break;
94     case 0x12:
95         snprintf(str, DESC_LEN, "Hibernation (0x12)");
96         break;
97     case 0x14:
98     case 0x16:
99         snprintf(str, DESC_LEN, "DOS FAT16 Hidden (0x%.2x)", ptype);
100         break;
101     case 0x17:
102         snprintf(str, DESC_LEN, "Hidden IFS/HPFS (0x17)");
103         break;
104     case 0x18:
105         snprintf(str, DESC_LEN, "AST SmartSleep (0x18)");
106         break;
107     case 0x19:
108     case 0x1b:
109     case 0x1c:
110         snprintf(str, DESC_LEN, "Win95 FAT32 Hidden (0x%.2x)", ptype);
111         break;
112     case 0x1e:
113         snprintf(str, DESC_LEN, "Win95 FAT16 Hidden (0x1e)");
114         break;
115     case 0x20:
116     case 0x22:
117     case 0x7e:
118     case 0x7f:
119     case 0xed:
120     case 0xf7:
121         snprintf(str, DESC_LEN, "Unused (0x%.2x)", ptype);
122         break;
123     case 0x21:
124     case 0x23:
125     case 0x26:
126     case 0x31:
127     case 0x33:
128     case 0x34:
129     case 0x36:
130     case 0x71:
131     case 0x73:
132     case 0x76:
133     case 0xf3:
134         snprintf(str, DESC_LEN, "Reserved (0x%.2x)", ptype);
135         break;
136     case 0x24:
137         snprintf(str, DESC_LEN, "NEC DOS 3.x (0x24)");
138         break;
139     case 0x32:
140         snprintf(str, DESC_LEN, "NOS (0x32)");
141         break;
142     case 0x35:
143         snprintf(str, DESC_LEN, "JFS on OS/2 or eCS  (0x35)");
144         break;
145     case 0x38:
146         snprintf(str, DESC_LEN, "THEOS v3.2 2gb (0x38)");
147         break;
148     case 0x39:
149         snprintf(str, DESC_LEN, "THEOS v4 Spanned (0x39)");
150         break;
151         /*
152            case 0x39:
153            snprintf(str, DESC_LEN, "Plan 9 (0x39)");
154            break;
155          */
156     case 0x3a:
157         snprintf(str, DESC_LEN, "THEOS v4 4gb (0x3a)");
158         break;
159     case 0x3b:
160         snprintf(str, DESC_LEN, "THEOS v4 Extended (0x3b)");
161         break;
162     case 0x3c:
163         snprintf(str, DESC_LEN, "PartitionMagic Recovery (0x3c)");
164         break;
165     case 0x3d:
166         snprintf(str, DESC_LEN, "Hidden NetWare (0x3d)");
167         break;
168     case 0x40:
169         snprintf(str, DESC_LEN, "Venix 80286 (0x40)");
170         break;
171     case 0x41:
172         snprintf(str, DESC_LEN,
173             "Linux/MINIX (Sharing Disk with DR-DOS) (0x41)");
174         break;
175         /*
176            case 0x41:
177            snprintf(str, DESC_LEN, "Personal RISC Boot (0x41)");
178            break;
179            case 0x41:
180            snprintf(str, DESC_LEN, "PPC PReP Boot (0x41)");
181            break;
182          */
183     case 0x42:
184         snprintf(str, DESC_LEN, "Win LVM / Secure FS (0x42)");
185         break;
186     case 0x43:
187         snprintf(str, DESC_LEN,
188             "Linux Native (Sharing Disk with DR-DOS) (0x43)");
189         break;
190     case 0x44:
191         snprintf(str, DESC_LEN, "GoBack (0x44)");
192         break;
193     case 0x45:
194         snprintf(str, DESC_LEN, "Boot-US Boot Manager (0x45)");
195         break;
196         /*
197            case 0x45:
198            snprintf(str, DESC_LEN, "Priam (0x45)");
199            break;
200            case 0x45:
201            snprintf(str, DESC_LEN, "EUMEL/Elan  (0x45)");
202            break;
203          */
204     case 0x46:
205         snprintf(str, DESC_LEN, "EUMEL/Elan  (0x46)");
206         break;
207     case 0x47:
208         snprintf(str, DESC_LEN, "EUMEL/Elan  (0x47)");
209         break;
210     case 0x48:
211         snprintf(str, DESC_LEN, "EUMEL/Elan  (0x48)");
212         break;
213     case 0x4a:
214         snprintf(str, DESC_LEN,
215             "Mark Aitchison's ALFS/THIN Lightweight Filesystem (0x4a)");
216         break;
217         /*case 0x4a:
218            snprintf(str, DESC_LEN, "AdaOS Aquila (0x4a)");
219            break; */
220     case 0x4c:
221         snprintf(str, DESC_LEN, "Oberon (0x4c)");
222         break;
223     case 0x4d:
224     case 0x4e:
225     case 0x4f:
226         snprintf(str, DESC_LEN, "QNX 4.x (0x%.2x)", ptype);
227         break;
228         /*case 0x4f:
229            snprintf(str, DESC_LEN, "Oberon (0x4f)");
230            break; */
231         /*case 0x52:
232            snprintf(str, DESC_LEN, "CP/M (0x52)");
233            break; */
234     case 0x50:
235     case 0x51:
236     case 0x53:
237     case 0x54:
238         snprintf(str, DESC_LEN, "OnTrack Disk Manager (0x%.2x)", ptype);
239         break;
240     case 0x52:
241         snprintf(str, DESC_LEN, "Microport SysV/AT (0x52)");
242         break;
243     case 0x55:
244         snprintf(str, DESC_LEN, "EZ-Drive (0x55)");
245         break;
246     case 0x56:
247         snprintf(str, DESC_LEN,
248             "AT&T MS-DOS 3.x Logically Sectored FAT (0x56)");
249         break;
250         /*case 0x56:
251            snprintf(str, DESC_LEN, "Golden Bow VFeature Partitioned Volume (0x56)");
252            break; */
253         /*case 0x56:
254            snprintf(str, DESC_LEN, "DM Converted to EZ-BIOS (0x56)");
255            break; */
256     case 0x57:
257         snprintf(str, DESC_LEN, "DrivePro (0x57)");
258         break;
259     case 0x5c:
260         snprintf(str, DESC_LEN, "Priam EDisk (0x5c)");
261         break;
262     case 0x61:
263         snprintf(str, DESC_LEN, "SpeedStor (0x61)");
264         break;
265     case 0x63:
266         snprintf(str, DESC_LEN, "UNIX System V (0x63)");
267         break;
268     case 0x64:
269     case 0x65:
270     case 0x66:
271     case 0x67:
272     case 0x68:
273     case 0x69:
274         snprintf(str, DESC_LEN, "Novell Netware (0x%.2x)", ptype);
275         break;
276     case 0x70:
277         snprintf(str, DESC_LEN, "DiskSecure Multi-Boot (0x70)");
278         break;
279     case 0x74:
280         snprintf(str, DESC_LEN, "Scramdisk (0x74)");
281         break;
282     case 0x75:
283         snprintf(str, DESC_LEN, "IBM PC/IX (0x75)");
284         break;
285     case 0x77:
286         snprintf(str, DESC_LEN, "VNDI (0x77)");
287         break;
288         /*case 0x77:
289            snprintf(str, DESC_LEN, "M2FS/M2CS (0x77)");
290            break; */
291     case 0x78:
292         snprintf(str, DESC_LEN, "XOSL FS (0x78)");
293         break;
294     case 0x80:
295         snprintf(str, DESC_LEN, "MINIX <=v1.4a (0x80)");
296         break;
297     case 0x81:
298         snprintf(str, DESC_LEN, "MINIX >=v1.4b, Early Linux (0x81)");
299         break;
300         /*case 0x81:
301            snprintf(str, DESC_LEN, "Mitac Disk Manager (0x81)");
302            break; */
303     case 0x82:
304         snprintf(str, DESC_LEN, "Linux Swap / Solaris x86 (0x82)");
305         break;
306     case 0x83:
307         snprintf(str, DESC_LEN, "Linux (0x83)");
308         break;
309     case 0x84:
310         snprintf(str, DESC_LEN, "Hibernation (0x84)");
311         break;
312     case 0x85:
313         snprintf(str, DESC_LEN, "Linux Extended (0x85)");
314         break;
315     case 0x86:
316         snprintf(str, DESC_LEN, "NTFS Volume Set (0x86)");
317         break;
318     case 0x87:
319         snprintf(str, DESC_LEN, "NTFS Volume Set (0x87)");
320         break;
321     case 0x8a:
322         snprintf(str, DESC_LEN, "Linux Kernel (0x8a)");
323         break;
324     case 0x8b:
325         snprintf(str, DESC_LEN, "Legacy Fault Tolerant FAT32 (0x8b)");
326         break;
327     case 0x8c:
328         snprintf(str, DESC_LEN,
329             "Legacy Fault Tolerant FAT32 using BIOS extd INT 13h (0x8c)");
330         break;
331     case 0x8d:
332         snprintf(str, DESC_LEN,
333             "Free FDISK Hidden Primary DOS FAT12 (0x8d)");
334         break;
335     case 0x8e:
336         snprintf(str, DESC_LEN, "Linux Logical Volume Manager (0x8e)");
337         break;
338     case 0x90:
339         snprintf(str, DESC_LEN,
340             "Free FDISK Hidden Primary DOS FAT16 (0x90)");
341         break;
342     case 0x91:
343         snprintf(str, DESC_LEN, "Free FDISK Hidden DOS Extended (0x91)");
344         break;
345     case 0x92:
346         snprintf(str, DESC_LEN,
347             "Free FDISK Hidden Primary DOS Large FAT16 (0x92)");
348         break;
349     case 0x93:
350         snprintf(str, DESC_LEN, "Linux Hidden (0x93)");
351         break;
352     case 0x94:
353         snprintf(str, DESC_LEN, "Amoeba Bad Block Table (0x94)");
354         break;
355     case 0x95:
356         snprintf(str, DESC_LEN, "MIT EXOPC (0x95)");
357         break;
358     case 0x97:
359         snprintf(str, DESC_LEN,
360             "Free FDISK Hidden Primary DOS FAT32 (0x97)");
361         break;
362     case 0x98:
363         snprintf(str, DESC_LEN,
364             "Free FDISK Hidden Primary DOS FAT32 LBA (0x98)");
365         break;
366         /*case 0x98:
367            snprintf(str, DESC_LEN, "Datalight ROM-DOS Super-Boot (0x98)");
368            break; */
369     case 0x99:
370         snprintf(str, DESC_LEN, "DCE376 Logical Drive (0x99)");
371         break;
372     case 0x9a:
373         snprintf(str, DESC_LEN,
374             "Free FDISK Hidden Primary DOS FAT16 LBA (0x9a)");
375         break;
376     case 0x9b:
377         snprintf(str, DESC_LEN,
378             "Free FDISK Hidden DOS Extended LBA (0x9b)");
379         break;
380     case 0x9f:
381         snprintf(str, DESC_LEN, "BSD/OS (0x9f)");
382         break;
383     case 0xa0:
384     case 0xa1:
385         snprintf(str, DESC_LEN, "Hibernation (0x%.2x)", ptype);
386         break;
387     case 0xa3:
388         snprintf(str, DESC_LEN,
389             "HP Volume Expansion (SpeedStor Variant) (0xa3)");
390         break;
391     case 0xa4:
392         snprintf(str, DESC_LEN,
393             "HP Volume Expansion (SpeedStor Variant) (0xa4)");
394         break;
395     case 0xa5:
396         snprintf(str, DESC_LEN, "BSD/386, 386BSD, NetBSD, FreeBSD (0xa5)");
397         break;
398     case 0xa6:
399         snprintf(str, DESC_LEN, "OpenBSD (0xa6)");
400         break;
401     case 0xa7:
402         snprintf(str, DESC_LEN, "NeXTSTEP (0xa7)");
403         break;
404     case 0xa8:
405         snprintf(str, DESC_LEN, "Mac OS X (0xa8)");
406         break;
407     case 0xa9:
408         snprintf(str, DESC_LEN, "NetBSD (0xa9)");
409         break;
410     case 0xaa:
411         snprintf(str, DESC_LEN, "Olivetti Fat 12 1.44MB Service (0xaa)");
412         break;
413     case 0xab:
414         snprintf(str, DESC_LEN, "Mac OS X Boot Partition (0xab)");
415         break;
416     case 0xae:
417         snprintf(str, DESC_LEN, "ShagOS Filesystem (0xae)");
418         break;
419     case 0xaf:
420         snprintf(str, DESC_LEN, "Mac OS X HFS (0xaf)");
421         break;
422     case 0xb0:
423         snprintf(str, DESC_LEN, "BootStar Dummy (0xb0)");
424         break;
425     case 0xb1:
426         snprintf(str, DESC_LEN,
427             "HP Volume Expansion (SpeedStor Variant) (0xb1)");
428         break;
429     case 0xb3:
430         snprintf(str, DESC_LEN,
431             "HP Volume Expansion (SpeedStor Variant) (0xb3)");
432         break;
433     case 0xb4:
434         snprintf(str, DESC_LEN,
435             "HP Volume Expansion (SpeedStor Variant) (0xb4)");
436         break;
437     case 0xb6:
438         snprintf(str, DESC_LEN,
439             "Corrupted Windows NT Mirror Set Master FAT16 (0xb6)");
440         break;
441         /*case 0xb6:
442            snprintf(str, DESC_LEN, "HP Volume Expansion (SpeedStor Variant) (0xb6)");
443            break; */
444     case 0xb7:
445         snprintf(str, DESC_LEN, "BSDI (0xb7)");
446         break;
447     case 0xb8:
448         snprintf(str, DESC_LEN, "BSDI Swap (0xb8)");
449         break;
450     case 0xbb:
451         snprintf(str, DESC_LEN, "Boot Wizard Hidden (0xbb)");
452         break;
453     case 0xbe:
454         snprintf(str, DESC_LEN, "Solaris 8 Boot (0xbe)");
455         break;
456     case 0xc0:
457         snprintf(str, DESC_LEN, "DR-DOS Secured (0xc0)");
458         break;
459         /*case 0xc0:
460            snprintf(str, DESC_LEN, "CTOS (0xc0)");
461            break; */
462         /*case 0xc0:
463            snprintf(str, DESC_LEN, "REAL/32 Secure Small (0xc0)");
464            break; */
465         /*case 0xc0:
466            snprintf(str, DESC_LEN, "NTFT (0xc0)");
467            break; */
468     case 0xc1:
469         snprintf(str, DESC_LEN, "DR-DOS Secured FAT12 (0xc1)");
470         break;
471     case 0xc2:
472         snprintf(str, DESC_LEN, "Hidden Linux (0xc2)");
473         break;
474     case 0xc3:
475         snprintf(str, DESC_LEN, "Hidden Linux Swap (0xc3)");
476         break;
477     case 0xc4:
478         snprintf(str, DESC_LEN, "DR-DOS Secured FAT16 <32M (0xc4)");
479         break;
480     case 0xc5:
481         snprintf(str, DESC_LEN, "DR-DOS Secured Extended (0xc5)");
482         break;
483     case 0xc6:
484     case 0xc7:
485         snprintf(str, DESC_LEN,
486             "Corrupted Windows NT Volume / Stripe Set (0x%.2x)", ptype);
487         break;
488     case 0xc8:
489         snprintf(str, DESC_LEN, "Reserved for DR-DOS 8.0+ (0xc8)");
490         break;
491     case 0xc9:
492         snprintf(str, DESC_LEN, "Reserved for DR-DOS 8.0+ (0xc9)");
493         break;
494     case 0xca:
495         snprintf(str, DESC_LEN, "Reserved for DR-DOS 8.0+ (0xca)");
496         break;
497     case 0xcb:
498         snprintf(str, DESC_LEN, "DR-DOS 7.04+ Secured FAT32 CHS (0xcb)");
499         break;
500     case 0xcc:
501         snprintf(str, DESC_LEN, "DR-DOS 7.04+ Secured FAT32 LBA (0xcc)");
502         break;
503     case 0xcd:
504         snprintf(str, DESC_LEN, "CTOS Memdump? (0xcd)");
505         break;
506     case 0xce:
507         snprintf(str, DESC_LEN, "DR-DOS 7.04+ FAT16X LBA (0xce)");
508         break;
509     case 0xcf:
510         snprintf(str, DESC_LEN, "DR-DOS 7.04+ Secured EXT DOS LBA (0xcf)");
511         break;
512     case 0xd0:
513         snprintf(str, DESC_LEN, "Multiuser DOS Secured (0xd0)");
514         break;
515         /*case 0xd0:
516            snprintf(str, DESC_LEN, "REAL/32 Secure Big (0xd0)");
517            break; */
518     case 0xd1:
519         snprintf(str, DESC_LEN, "Old Multiuser DOS Secured FAT12 (0xd1)");
520         break;
521     case 0xd4:
522         snprintf(str, DESC_LEN,
523             "Old Multiuser DOS Secured FAT16 <32M (0xd4)");
524         break;
525     case 0xd5:
526         snprintf(str, DESC_LEN,
527             "Old Multiuser DOS Secured extended (0xd5)");
528         break;
529     case 0xd6:
530         snprintf(str, DESC_LEN,
531             "Old Multiuser DOS Secured FAT16 >=32M (0xd6)");
532         break;
533     case 0xd8:
534         snprintf(str, DESC_LEN, "CP/M-86 (0xd8)");
535         break;
536     case 0xda:
537         snprintf(str, DESC_LEN, "Non-FS Data (0xda)");
538         break;
539     case 0xdb:
540         snprintf(str, DESC_LEN,
541             "Digital Research CP/M, Concurrent CP/M, Concurrent DOS (0xdb)");
542         break;
543         /*case 0xdb:
544            snprintf(str, DESC_LEN, "Unisys CTOS (0xdb)");
545            break; */
546         /*case 0xdb:
547            snprintf(str, DESC_LEN, "KDG Telemetry SCPU boot (0xdb)");
548            break; */
549     case 0xdd:
550         snprintf(str, DESC_LEN, "Hidden CTOS Memdump?  (0xdd)");
551         break;
552     case 0xde:
553         snprintf(str, DESC_LEN, "Dell Utilities FAT (0xde)");
554         break;
555         /*case 0xdf:
556            snprintf(str, DESC_LEN, "DG/UX Virtual Disk Manager (0xdf)");
557            break; */
558         /*case 0xdf:
559            snprintf(str, DESC_LEN, "BootIt EMBRM (0xdf)");
560            break; */
561     case 0xe0:
562         snprintf(str, DESC_LEN,
563             "Reserved by STMicroelectronics for ST AVFS. (0xe0)");
564         break;
565     case 0xe1:
566         snprintf(str, DESC_LEN,
567             "DOS Access or SpeedStor 12-bit FAT Extended (0xe1)");
568         break;
569     case 0xe3:
570         snprintf(str, DESC_LEN, "DOS R/O or SpeedStor (0xe3)");
571         break;
572     case 0xe4:
573         snprintf(str, DESC_LEN,
574             "SpeedStor 16-bit FAT Extended <1024 cyl. (0xe4)");
575         break;
576     case 0xe5:
577         snprintf(str, DESC_LEN,
578             "Tandy MS-DOS with Logically Sectored FAT (0xe5)");
579         break;
580     case 0xe6:
581         snprintf(str, DESC_LEN, "Storage Dimensions SpeedStor (0xe6)");
582         break;
583     case 0xeb:
584         snprintf(str, DESC_LEN, "BeOS BFS (0xeb)");
585         break;
586     case 0xee:
587         snprintf(str, DESC_LEN, "GPT Safety Partition (0xee)");
588         break;
589     case 0xef:
590         snprintf(str, DESC_LEN, "EFI File System (0xef)");
591         break;
592     case 0xf0:
593         snprintf(str, DESC_LEN, "Linux/PA-RISC Boot Loader (0xf0)");
594         break;
595     case 0xf1:
596         snprintf(str, DESC_LEN, "Storage Dimensions SpeedStor (0xf1)");
597         break;
598     case 0xf2:
599         snprintf(str, DESC_LEN, "DOS 3.3+ Secondary (0xf2)");
600         break;
601     case 0xf4:
602         snprintf(str, DESC_LEN, "SpeedStor Large (0xf4)");
603         break;
604         /*case 0xf4:
605            snprintf(str, DESC_LEN, "Prologue Single-Volume (0xf4)");
606            break; */
607     case 0xf5:
608         snprintf(str, DESC_LEN, "Prologue Multi-Volume (0xf5)");
609         break;
610     case 0xf6:
611         snprintf(str, DESC_LEN, "Storage Dimensions SpeedStor (0xf6)");
612         break;
613     case 0xf9:
614         snprintf(str, DESC_LEN, "pCache (0xf9)");
615         break;
616     case 0xfa:
617         snprintf(str, DESC_LEN, "Bochs (0xfa)");
618         break;
619     case 0xfb:
620         snprintf(str, DESC_LEN, "VMWare File System (0xfb)");
621         break;
622     case 0xfc:
623         snprintf(str, DESC_LEN, "VMWare Swap (0xfc)");
624         break;
625     case 0xfd:
626         snprintf(str, DESC_LEN, "Linux RAID (0xfd)");
627         break;
628     case 0xfe:
629         snprintf(str, DESC_LEN,
630             "Windows NT Disk Administrator Hidden (0xfe)");
631         break;
632         /*case 0xfe:
633            snprintf(str, DESC_LEN, "SpeedStor >1024 cyl. (0xfe)");
634            break; */
635         /*case 0xfe:
636            snprintf(str, DESC_LEN, "LANstep (0xfe)");
637            break; */
638         /*case 0xfe:
639            snprintf(str, DESC_LEN, "IBM PS/2 IML (0xfe)");
640            break; */
641         /*case 0xfe:
642            snprintf(str, DESC_LEN, "Old Linux Logical Volume Manager (0xfe)");
643            break; */
644     case 0xff:
645         snprintf(str, DESC_LEN, "Xenix Bad Block Table (0xff)");
646         break;
647     default:
648         snprintf(str, DESC_LEN, "Unknown Type (0x%.2x)", ptype);
649         break;
650     }
651 
652     return str;
653 }
654 
655 /*
656  * Load an extended partition table into the structure in TSK_VS_INFO.
657  *
658  * sect_cur: The sector where the extended table is located
659  * sect_ext_base: The sector of the primary extended table (this does
660  *   not change for recursive calls)
661  * table: a counter that identifies the table depth
662  *   (increases by 1 for each recursive call)
663  *
664  * For the primary extended table, sect_cur == sect_ext_base
665  *
666  * Return 1 on error and 0 on success
667  *
668  */
669 static uint8_t
dos_load_ext_table(TSK_VS_INFO * vs,TSK_DADDR_T sect_cur,TSK_DADDR_T sect_ext_base,int table)670 dos_load_ext_table(TSK_VS_INFO * vs, TSK_DADDR_T sect_cur,
671     TSK_DADDR_T sect_ext_base, int table)
672 {
673     dos_sect *sect;
674     char *sect_buf;
675     int i;
676     char *table_str;
677     ssize_t cnt;
678     TSK_DADDR_T max_addr = (vs->img_info->size - vs->offset) / vs->block_size;  // max sector
679 
680     if (tsk_verbose)
681         tsk_fprintf(stderr,
682             "dos_load_ext: Table Sector: %" PRIuDADDR
683             ", Primary Base Sector: %" PRIuDADDR "\n", sect_cur,
684             sect_ext_base);
685 
686     if ((sect_buf = tsk_malloc(vs->block_size)) == NULL)
687         return 1;
688     sect = (dos_sect *) sect_buf;
689 
690     /* Read the partition table sector */
691     cnt = tsk_vs_read_block(vs, sect_cur, sect_buf, vs->block_size);
692     if (cnt != vs->block_size) {
693         if (cnt >= 0) {
694             tsk_error_reset();
695             tsk_error_set_errno(TSK_ERR_VS_READ);
696         }
697         tsk_error_set_errstr2("Extended DOS table sector %" PRIuDADDR,
698             sect_cur);
699         free(sect_buf);
700         return 1;
701     }
702 
703     /* Sanity Check */
704     if (tsk_getu16(vs->endian, sect->magic) != DOS_MAGIC) {
705         tsk_error_reset();
706         tsk_error_set_errno(TSK_ERR_VS_MAGIC);
707         tsk_error_set_errstr("Extended DOS partition table in sector %"
708             PRIuDADDR, sect_cur);
709         free(sect_buf);
710         return 1;
711     }
712 
713     /* Add an entry of 1 length for the table  to the internal structure */
714     if ((table_str = tsk_malloc(32)) == NULL) {
715         free(sect_buf);
716         return 1;
717     }
718 
719     snprintf(table_str, 32, "Extended Table (#%d)", table);
720     if (NULL == tsk_vs_part_add(vs, (TSK_DADDR_T) sect_cur,
721             (TSK_DADDR_T) 1, TSK_VS_PART_FLAG_META, table_str, table,
722             -1)) {
723         free(sect_buf);
724         return 1;
725     }
726 
727     /* Cycle through the four partitions in the table
728      *
729      * When another extended partition is found, it is processed
730      * inside of the loop
731      */
732     for (i = 0; i < 4; i++) {
733         dos_part *part = &sect->ptable[i];
734 
735         /* Get the starting sector and size, we currently
736          * ignore CHS */
737         uint32_t part_start = tsk_getu32(vs->endian, part->start_sec);
738         uint32_t part_size = tsk_getu32(vs->endian, part->size_sec);
739 
740         if (tsk_verbose)
741             tsk_fprintf(stderr,
742                 "load_ext: %d:%d    Start: %" PRIu32 "   Size: %"
743                 PRIu32 "  Type: %d\n", table, i, part_start, part_size,
744                 part->ptype);
745 
746         /* part_start == 0 would cause infinite recursion */
747         if (part_size == 0 || part_start == 0)
748             continue;
749 
750         /* partitions are addressed differently
751          * in extended partitions */
752         if (dos_is_ext(part->ptype)) {
753 
754             TSK_VS_PART_INFO *part_info;
755 
756             /* Sanity check to prevent infinite recursion in dos_load_ext_table.
757              * If we already have a partition with this starting address then
758              * return an error. This will prevent any more partitions from being
759              * added but will leave any existing partitions alone. */
760             part_info = vs->part_list;
761             while (part_info != NULL) {
762                 if (part_info->start == (TSK_DADDR_T)(sect_ext_base + part_start)) {
763                     if (tsk_verbose)
764                         tsk_fprintf(stderr,
765                             "Starting sector %" PRIuDADDR
766                             " of extended partition has already been used\n",
767                             (TSK_DADDR_T)(sect_ext_base + part_start));
768                     tsk_error_reset();
769                     tsk_error_set_errno(TSK_ERR_VS_BLK_NUM);
770                     tsk_error_set_errstr
771                         ("dos_load_ext_table: Loop in partition table detected");
772                     return 1;
773                 }
774                 part_info = part_info->next;
775             }
776 
777             /* part start is added to the start of the
778              * first extended partition (the primary
779              * extended partition) */
780 
781             if (NULL == tsk_vs_part_add(vs,
782                     (TSK_DADDR_T) (sect_ext_base + part_start),
783                     (TSK_DADDR_T) part_size, TSK_VS_PART_FLAG_META,
784                     dos_get_desc(part->ptype), table, i)) {
785                 free(sect_buf);
786                 return 1;
787             }
788 
789             if (sect_ext_base + part_start > max_addr) {
790                 if (tsk_verbose)
791                     tsk_fprintf(stderr,
792                         "Starting sector %" PRIuDADDR
793                         " of extended partition too large for image\n",
794                         sect_ext_base + part_start);
795             }
796             /* Process the extended partition */
797             else if (dos_load_ext_table(vs, sect_ext_base + part_start,
798                     sect_ext_base, table + 1)) {
799                 free(sect_buf);
800                 return 1;
801             }
802         }
803 
804         else {
805             /* part_start is added to the start of the
806              * current partition for the actual
807              * starting location */
808 
809             // we ignore the max_addr checks on extended partitions...
810 
811             if (NULL == tsk_vs_part_add(vs,
812                     (TSK_DADDR_T) (sect_cur + part_start),
813                     (TSK_DADDR_T) part_size, TSK_VS_PART_FLAG_ALLOC,
814                     dos_get_desc(part->ptype), table, i)) {
815                 free(sect_buf);
816                 return 1;
817             }
818         }
819     }
820 
821     free(sect_buf);
822     return 0;
823 }
824 
825 
826 /*
827  * Load the primary partition table (MBR) into the internal
828  * data structures in TSK_VS_INFO
829  *
830  * This will automatically call load_ext_table for extended
831  * partitions
832  *
833  * sect_cur is the address of the table to load
834  *
835  * 0 is returned if the load is successful and 1 if error
836  */
837 static uint8_t
dos_load_prim_table(TSK_VS_INFO * vs,uint8_t test)838 dos_load_prim_table(TSK_VS_INFO * vs, uint8_t test)
839 {
840     dos_sect *sect;
841     char *sect_buf;
842     int i, added = 0;
843     char *table_str;
844     ssize_t cnt;
845     TSK_DADDR_T taddr = vs->offset / vs->block_size + DOS_PART_SOFFSET;
846     TSK_DADDR_T max_addr = (vs->img_info->size - vs->offset) / vs->block_size;  // max sector
847 
848     if (tsk_verbose)
849         tsk_fprintf(stderr,
850             "dos_load_prim: Table Sector: %" PRIuDADDR "\n", taddr);
851 
852     if ((sect_buf = tsk_malloc(vs->block_size)) == NULL)
853         return 1;
854     sect = (dos_sect *) sect_buf;
855 
856     /* Read the table */
857     cnt = tsk_vs_read_block
858         (vs, DOS_PART_SOFFSET, sect_buf, vs->block_size);
859 
860     if (cnt != vs->block_size) {
861         if (cnt >= 0) {
862             tsk_error_reset();
863             tsk_error_set_errno(TSK_ERR_VS_READ);
864         }
865         tsk_error_set_errstr2("Primary DOS table sector %" PRIuDADDR,
866             taddr);
867         free(sect_buf);
868         return 1;
869     }
870 
871 
872     /* Sanity Check */
873     if (tsk_vs_guessu16(vs, sect->magic, DOS_MAGIC)) {
874         tsk_error_reset();
875         tsk_error_set_errno(TSK_ERR_VS_MAGIC);
876         tsk_error_set_errstr
877             ("File is not a DOS partition (invalid primary magic) (Sector: %"
878             PRIuDADDR ")", taddr);
879         if (tsk_verbose)
880             fprintf(stderr,
881                 "File is not a DOS partition (invalid primary magic) (Sector: %"
882                 PRIuDADDR ")", taddr);
883         free(sect_buf);
884         return 1;
885     }
886 
887     /* Because FAT and NTFS use the same magic - check for a
888      * standard MS OEM name and sizes.  Not a great check, but we can't
889      * really test the table entries.
890      */
891     if (test) {
892         if (tsk_verbose)
893             tsk_fprintf(stderr,
894                 "dos_load_prim_table: Testing FAT/NTFS conditions\n");
895 
896         if (strncmp("MSDOS", sect->oemname, 5) == 0) {
897             tsk_error_reset();
898             tsk_error_set_errno(TSK_ERR_VS_MAGIC);
899             tsk_error_set_errstr
900                 ("dos_load_prim_table: MSDOS OEM name exists");
901             if (tsk_verbose)
902                 tsk_fprintf(stderr,
903                     "dos_load_prim_table: MSDOS OEM name exists\n");
904             free(sect_buf);
905             return 1;
906         }
907         else if (strncmp("MSWIN", sect->oemname, 5) == 0) {
908             tsk_error_reset();
909             tsk_error_set_errno(TSK_ERR_VS_MAGIC);
910             tsk_error_set_errstr
911                 ("dos_load_prim_table: MSWIN OEM name exists");
912             if (tsk_verbose)
913                 tsk_fprintf(stderr,
914                     "dos_load_prim_table: MSWIN OEM name exists\n");
915             free(sect_buf);
916             return 1;
917         }
918         else if (strncmp("NTFS", sect->oemname, 4) == 0) {
919             tsk_error_reset();
920             tsk_error_set_errno(TSK_ERR_VS_MAGIC);
921             tsk_error_set_errstr
922                 ("dos_load_prim_table: NTFS OEM name exists");
923             if (tsk_verbose)
924                 tsk_fprintf(stderr,
925                     "dos_load_prim_table: NTFS OEM name exists\n");
926             free(sect_buf);
927             return 1;
928         }
929         else if (strncmp("FAT", sect->oemname, 4) == 0) {
930             tsk_error_reset();
931             tsk_error_set_errno(TSK_ERR_VS_MAGIC);
932             tsk_error_set_errstr
933                 ("dos_load_prim_table: FAT OEM name exists");
934             if (tsk_verbose)
935                 tsk_fprintf(stderr,
936                     "dos_load_prim_table: FAT OEM name exists\n");
937             free(sect_buf);
938             return 1;
939         }
940     }
941 
942     /* Add an entry of 1 sector for the table  to the internal structure */
943     if ((table_str = tsk_malloc(32)) == NULL) {
944         free(sect_buf);
945         return 1;
946     }
947 
948     snprintf(table_str, 32, "Primary Table (#0)");
949     if (NULL == tsk_vs_part_add(vs, DOS_PART_SOFFSET, (TSK_DADDR_T) 1,
950             TSK_VS_PART_FLAG_META, table_str, -1, -1)) {
951         free(sect_buf);
952         return 1;
953     }
954 
955     /* Cycle through the partition table */
956     for (i = 0; i < 4; i++) {
957         dos_part *part = &sect->ptable[i];
958 
959         /* We currently ignore CHS */
960         uint32_t part_start = tsk_getu32(vs->endian, part->start_sec);
961         uint32_t part_size = tsk_getu32(vs->endian, part->size_sec);
962 
963         if (tsk_verbose)
964             tsk_fprintf(stderr,
965                 "load_pri:0:%d    Start: %" PRIu32 "   Size: %" PRIu32
966                 "  Type: %d\n", i, part_start, part_size, part->ptype);
967 
968         if (part_size == 0)
969             continue;
970 
971         // make sure the first couple are in the image bounds
972         if ((i < 2) && (part_start > max_addr)) {
973             tsk_error_reset();
974             tsk_error_set_errno(TSK_ERR_VS_BLK_NUM);
975             tsk_error_set_errstr
976                 ("dos_load_prim_table: Starting sector too large for image");
977             if (tsk_verbose)
978                 tsk_fprintf(stderr,
979                     "Starting sector %" PRIu32 " too large for image\n",
980                     part_start);
981             free(sect_buf);
982             return 1;
983         }
984 #if 0
985 // I'm not sure if this is too strict ...
986         else if ((part_start + part_size) > max_addr) {
987             tsk_error_reset();
988             tsk_error_set_errno(TSK_ERR_VS_BLK_NUM);
989             tsk_error_set_errstr
990                 ("dos_load_prim_table: Partition ends after image");
991             return 1;
992         }
993 #endif
994 
995         added = 1;
996 
997         /* Add the partition to the internal structure
998          * If it is an extended partition, process it now */
999         if (dos_is_ext(part->ptype)) {
1000             if (NULL == tsk_vs_part_add(vs, (TSK_DADDR_T) part_start,
1001                     (TSK_DADDR_T) part_size, TSK_VS_PART_FLAG_META,
1002                     dos_get_desc(part->ptype), 0, i)) {
1003                 free(sect_buf);
1004                 return 1;
1005             }
1006 
1007             if (dos_load_ext_table(vs, part_start, part_start, 1)) {
1008                 if (tsk_verbose) {
1009                     fprintf(stderr,
1010                         "Error loading extended table, moving on");
1011                     tsk_error_print(stderr);
1012                 }
1013                 tsk_error_reset();
1014             }
1015         }
1016         else {
1017             if (NULL == tsk_vs_part_add(vs, (TSK_DADDR_T) part_start,
1018                     (TSK_DADDR_T) part_size, TSK_VS_PART_FLAG_ALLOC,
1019                     dos_get_desc(part->ptype), 0, i)) {
1020                 free(sect_buf);
1021                 return 1;
1022             }
1023         }
1024     }
1025     free(sect_buf);
1026 
1027     if (added == 0) {
1028         if (tsk_verbose)
1029             tsk_fprintf(stderr, "dos_load_prim: No valid entries\n");
1030 
1031         tsk_error_reset();
1032         tsk_error_set_errno(TSK_ERR_VS_MAGIC);
1033         tsk_error_set_errstr
1034             ("dos_load_prim_table: No valid entries in primary table");
1035         return 1;
1036     }
1037     return 0;
1038 }
1039 
1040 
1041 static void
dos_close(TSK_VS_INFO * vs)1042 dos_close(TSK_VS_INFO * vs)
1043 {
1044     vs->tag = 0;
1045     tsk_vs_part_free(vs);
1046     free(vs);
1047 }
1048 
1049 
1050 /*
1051  * Given the path to the file, open it and load the internal
1052  * partition table structure
1053  *
1054  * offset is the byte offset to the start of the volume system
1055  *
1056  * If test is 1 then additional tests are performed to make sure
1057  * it isn't a FAT or NTFS file system. This is used when autodetection
1058  * is being used to detect the volume system type.
1059  */
1060 TSK_VS_INFO *
tsk_vs_dos_open(TSK_IMG_INFO * img_info,TSK_DADDR_T offset,uint8_t test)1061 tsk_vs_dos_open(TSK_IMG_INFO * img_info, TSK_DADDR_T offset, uint8_t test)
1062 {
1063     TSK_VS_INFO *vs;
1064 
1065     // clean up any errors that are lying around
1066     tsk_error_reset();
1067 
1068     if (img_info->sector_size == 0) {
1069         tsk_error_reset();
1070         tsk_error_set_errno(TSK_ERR_VS_ARG);
1071         tsk_error_set_errstr("tsk_vs_dos_open: sector size is 0");
1072         return NULL;
1073     }
1074 
1075     vs = (TSK_VS_INFO *) tsk_malloc(sizeof(*vs));
1076     if (vs == NULL)
1077         return NULL;
1078 
1079     vs->vstype = TSK_VS_TYPE_DOS;
1080     vs->tag = TSK_VS_INFO_TAG;
1081     vs->img_info = img_info;
1082 
1083     vs->offset = offset;
1084 
1085     /* initialize settings */
1086     vs->part_list = NULL;
1087     vs->part_count = 0;
1088     vs->endian = 0;
1089     vs->block_size = img_info->sector_size;
1090 
1091 
1092     /* Assign functions */
1093     vs->close = dos_close;
1094 
1095     /* Load the partitions into the sorted list */
1096     if (dos_load_prim_table(vs, test)) {
1097         dos_close(vs);
1098         return NULL;
1099     }
1100 
1101     /* fill in the sorted list with the 'unknown' values */
1102     if (tsk_vs_part_unused(vs)) {
1103         dos_close(vs);
1104         return NULL;
1105     }
1106 
1107     return vs;
1108 }
1109