1 #include "rar.hpp"
2 
ReadHeader()3 size_t Archive::ReadHeader()
4 {
5   // Once we failed to decrypt an encrypted block, there is no reason to
6   // attempt to do it further. We'll never be successful and only generate
7   // endless errors.
8   if (FailedHeaderDecryption)
9     return 0;
10 
11   CurBlockPos=Tell();
12 
13   // Other developers asked us to initialize it to suppress "may be used
14   // uninitialized" warning in code below in some compilers.
15   size_t ReadSize=0;
16 
17   switch(Format)
18   {
19 #ifndef SFX_MODULE
20     case RARFMT14:
21       ReadSize=ReadHeader14();
22       break;
23 #endif
24     case RARFMT15:
25       ReadSize=ReadHeader15();
26       break;
27     case RARFMT50:
28       ReadSize=ReadHeader50();
29       break;
30   }
31 
32   // It is important to check ReadSize>0 here, because it is normal
33   // for RAR2 and RAR3 archives without end of archive block to have
34   // NextBlockPos==CurBlockPos after the end of archive has reached.
35   if (ReadSize>0 && NextBlockPos<=CurBlockPos)
36   {
37     BrokenHeaderMsg();
38     ReadSize=0;
39   }
40 
41   if (ReadSize==0)
42     CurHeaderType=HEAD_UNKNOWN;
43 
44   return ReadSize;
45 }
46 
47 
SearchBlock(HEADER_TYPE HeaderType)48 size_t Archive::SearchBlock(HEADER_TYPE HeaderType)
49 {
50   size_t Size,Count=0;
51   while ((Size=ReadHeader())!=0 &&
52          (HeaderType==HEAD_ENDARC || GetHeaderType()!=HEAD_ENDARC))
53   {
54     if ((++Count & 127)==0)
55       Wait();
56     if (GetHeaderType()==HeaderType)
57       return Size;
58     SeekToNext();
59   }
60   return 0;
61 }
62 
63 
SearchSubBlock(const wchar * Type)64 size_t Archive::SearchSubBlock(const wchar *Type)
65 {
66   size_t Size,Count=0;
67   while ((Size=ReadHeader())!=0 && GetHeaderType()!=HEAD_ENDARC)
68   {
69     if ((++Count & 127)==0)
70       Wait();
71     if (GetHeaderType()==HEAD_SERVICE && SubHead.CmpName(Type))
72       return Size;
73     SeekToNext();
74   }
75   return 0;
76 }
77 
78 
SearchRR()79 size_t Archive::SearchRR()
80 {
81   // If locator extra field is available for recovery record, let's utilize it.
82   if (MainHead.Locator && MainHead.RROffset!=0)
83   {
84     uint64 CurPos=Tell();
85     Seek(MainHead.RROffset,SEEK_SET);
86     size_t Size=ReadHeader();
87     if (Size!=0 && !BrokenHeader && GetHeaderType()==HEAD_SERVICE && SubHead.CmpName(SUBHEAD_TYPE_RR))
88       return Size;
89     Seek(CurPos,SEEK_SET);
90   }
91   // Otherwise scan the entire archive to find the recovery record.
92   return SearchSubBlock(SUBHEAD_TYPE_RR);
93 }
94 
95 
UnexpEndArcMsg()96 void Archive::UnexpEndArcMsg()
97 {
98   int64 ArcSize=FileLength();
99 
100   // If block positions are equal to file size, this is not an error.
101   // It can happen when we reached the end of older RAR 1.5 archive,
102   // which did not have the end of archive block.
103   if (CurBlockPos!=ArcSize || NextBlockPos!=ArcSize)
104   {
105     uiMsg(UIERROR_UNEXPEOF,FileName);
106     ErrHandler.SetErrorCode(RARX_WARNING);
107   }
108 }
109 
110 
BrokenHeaderMsg()111 void Archive::BrokenHeaderMsg()
112 {
113   uiMsg(UIERROR_HEADERBROKEN,FileName);
114   BrokenHeader=true;
115   ErrHandler.SetErrorCode(RARX_CRC);
116 }
117 
118 
UnkEncVerMsg(const wchar * Name,const wchar * Info)119 void Archive::UnkEncVerMsg(const wchar *Name,const wchar *Info)
120 {
121   uiMsg(UIERROR_UNKNOWNENCMETHOD,FileName,Name,Info);
122   ErrHandler.SetErrorCode(RARX_WARNING);
123 }
124 
125 
126 // Return f in case of signed integer overflow or negative parameters
127 // or v1+v2 otherwise. We use it for file offsets, which are signed
128 // for compatibility with off_t in POSIX file functions and third party code.
129 // Signed integer overflow is the undefined behavior according to
130 // C++ standard and it causes fuzzers to complain.
SafeAdd(int64 v1,int64 v2,int64 f)131 inline int64 SafeAdd(int64 v1,int64 v2,int64 f)
132 {
133   return v1>=0 && v2>=0 && v1<=MAX_INT64-v2 ? v1+v2 : f;
134 }
135 
136 
ReadHeader15()137 size_t Archive::ReadHeader15()
138 {
139   RawRead Raw(this);
140 
141   bool Decrypt=Encrypted && CurBlockPos>(int64)SFXSize+SIZEOF_MARKHEAD3;
142 
143   if (Decrypt)
144   {
145 #ifdef RAR_NOCRYPT // For rarext.dll and unrar_nocrypt.dll.
146     return 0;
147 #else
148     RequestArcPassword();
149 
150     byte Salt[SIZE_SALT30];
151     if (Read(Salt,SIZE_SALT30)!=SIZE_SALT30)
152     {
153       UnexpEndArcMsg();
154       return 0;
155     }
156     HeadersCrypt.SetCryptKeys(false,CRYPT_RAR30,&Cmd->Password,Salt,NULL,0,NULL,NULL);
157     Raw.SetCrypt(&HeadersCrypt);
158 #endif
159   }
160 
161   Raw.Read(SIZEOF_SHORTBLOCKHEAD);
162   if (Raw.Size()==0)
163   {
164     UnexpEndArcMsg();
165     return 0;
166   }
167 
168   ShortBlock.HeadCRC=Raw.Get2();
169 
170   ShortBlock.Reset();
171 
172   uint HeaderType=Raw.Get1();
173   ShortBlock.Flags=Raw.Get2();
174   ShortBlock.SkipIfUnknown=(ShortBlock.Flags & SKIP_IF_UNKNOWN)!=0;
175   ShortBlock.HeadSize=Raw.Get2();
176 
177   ShortBlock.HeaderType=(HEADER_TYPE)HeaderType;
178   if (ShortBlock.HeadSize<SIZEOF_SHORTBLOCKHEAD)
179   {
180     BrokenHeaderMsg();
181     return 0;
182   }
183 
184   // For simpler further processing we map header types common
185   // for RAR 1.5 and 5.0 formats to RAR 5.0 values. It does not include
186   // header types specific for RAR 1.5 - 4.x only.
187   switch(ShortBlock.HeaderType)
188   {
189     case HEAD3_MAIN:    ShortBlock.HeaderType=HEAD_MAIN;     break;
190     case HEAD3_FILE:    ShortBlock.HeaderType=HEAD_FILE;     break;
191     case HEAD3_SERVICE: ShortBlock.HeaderType=HEAD_SERVICE;  break;
192     case HEAD3_ENDARC:  ShortBlock.HeaderType=HEAD_ENDARC;   break;
193   }
194   CurHeaderType=ShortBlock.HeaderType;
195 
196   if (ShortBlock.HeaderType==HEAD3_CMT)
197   {
198     // Old style (up to RAR 2.9) comment header embedded into main
199     // or file header. We must not read the entire ShortBlock.HeadSize here
200     // to not break the comment processing logic later.
201     Raw.Read(SIZEOF_COMMHEAD-SIZEOF_SHORTBLOCKHEAD);
202   }
203   else
204     if (ShortBlock.HeaderType==HEAD_MAIN && (ShortBlock.Flags & MHD_COMMENT)!=0)
205     {
206       // Old style (up to RAR 2.9) main archive comment embedded into
207       // the main archive header found. While we can read the entire
208       // ShortBlock.HeadSize here and remove this part of "if", it would be
209       // waste of memory, because we'll read and process this comment data
210       // in other function anyway and we do not need them here now.
211       Raw.Read(SIZEOF_MAINHEAD3-SIZEOF_SHORTBLOCKHEAD);
212     }
213     else
214       Raw.Read(ShortBlock.HeadSize-SIZEOF_SHORTBLOCKHEAD);
215 
216   NextBlockPos=CurBlockPos+FullHeaderSize(ShortBlock.HeadSize);
217 
218   switch(ShortBlock.HeaderType)
219   {
220     case HEAD_MAIN:
221       MainHead.Reset();
222       *(BaseBlock *)&MainHead=ShortBlock;
223       MainHead.HighPosAV=Raw.Get2();
224       MainHead.PosAV=Raw.Get4();
225 
226       Volume=(MainHead.Flags & MHD_VOLUME)!=0;
227       Solid=(MainHead.Flags & MHD_SOLID)!=0;
228       Locked=(MainHead.Flags & MHD_LOCK)!=0;
229       Protected=(MainHead.Flags & MHD_PROTECT)!=0;
230       Encrypted=(MainHead.Flags & MHD_PASSWORD)!=0;
231       Signed=MainHead.PosAV!=0 || MainHead.HighPosAV!=0;
232       MainHead.CommentInHeader=(MainHead.Flags & MHD_COMMENT)!=0;
233 
234       // Only for encrypted 3.0+ archives. 2.x archives did not have this
235       // flag, so for non-encrypted archives, we'll set it later based on
236       // file attributes.
237       FirstVolume=(MainHead.Flags & MHD_FIRSTVOLUME)!=0;
238 
239       NewNumbering=(MainHead.Flags & MHD_NEWNUMBERING)!=0;
240       break;
241     case HEAD_FILE:
242     case HEAD_SERVICE:
243       {
244         bool FileBlock=ShortBlock.HeaderType==HEAD_FILE;
245         FileHeader *hd=FileBlock ? &FileHead:&SubHead;
246         hd->Reset();
247 
248         *(BaseBlock *)hd=ShortBlock;
249 
250         hd->SplitBefore=(hd->Flags & LHD_SPLIT_BEFORE)!=0;
251         hd->SplitAfter=(hd->Flags & LHD_SPLIT_AFTER)!=0;
252         hd->Encrypted=(hd->Flags & LHD_PASSWORD)!=0;
253         hd->SaltSet=(hd->Flags & LHD_SALT)!=0;
254         hd->Solid=FileBlock && (hd->Flags & LHD_SOLID)!=0;
255         hd->SubBlock=!FileBlock && (hd->Flags & LHD_SOLID)!=0;
256         hd->Dir=(hd->Flags & LHD_WINDOWMASK)==LHD_DIRECTORY;
257         hd->WinSize=hd->Dir ? 0:0x10000<<((hd->Flags & LHD_WINDOWMASK)>>5);
258         hd->CommentInHeader=(hd->Flags & LHD_COMMENT)!=0;
259         hd->Version=(hd->Flags & LHD_VERSION)!=0;
260 
261         hd->DataSize=Raw.Get4();
262         uint LowUnpSize=Raw.Get4();
263         hd->HostOS=Raw.Get1();
264 
265         hd->FileHash.Type=HASH_CRC32;
266         hd->FileHash.CRC32=Raw.Get4();
267 
268         uint FileTime=Raw.Get4();
269         hd->UnpVer=Raw.Get1();
270 
271         hd->Method=Raw.Get1()-0x30;
272         size_t NameSize=Raw.Get2();
273         hd->FileAttr=Raw.Get4();
274 
275         // RAR15 did not use the special dictionary size to mark dirs.
276         if (hd->UnpVer<20 && (hd->FileAttr & 0x10)!=0)
277           hd->Dir=true;
278 
279         hd->CryptMethod=CRYPT_NONE;
280         if (hd->Encrypted)
281           switch(hd->UnpVer)
282           {
283             case 13: hd->CryptMethod=CRYPT_RAR13; break;
284             case 15: hd->CryptMethod=CRYPT_RAR15; break;
285             case 20:
286             case 26: hd->CryptMethod=CRYPT_RAR20; break;
287             default: hd->CryptMethod=CRYPT_RAR30; break;
288           }
289 
290         hd->HSType=HSYS_UNKNOWN;
291         if (hd->HostOS==HOST_UNIX || hd->HostOS==HOST_BEOS)
292           hd->HSType=HSYS_UNIX;
293         else
294           if (hd->HostOS<HOST_MAX)
295             hd->HSType=HSYS_WINDOWS;
296 
297         hd->RedirType=FSREDIR_NONE;
298 
299         // RAR 4.x Unix symlink.
300         if (hd->HostOS==HOST_UNIX && (hd->FileAttr & 0xF000)==0xA000)
301         {
302           hd->RedirType=FSREDIR_UNIXSYMLINK;
303           *hd->RedirName=0;
304         }
305 
306         hd->Inherited=!FileBlock && (hd->SubFlags & SUBHEAD_FLAGS_INHERITED)!=0;
307 
308         hd->LargeFile=(hd->Flags & LHD_LARGE)!=0;
309 
310         uint HighPackSize,HighUnpSize;
311         if (hd->LargeFile)
312         {
313           HighPackSize=Raw.Get4();
314           HighUnpSize=Raw.Get4();
315           hd->UnknownUnpSize=(LowUnpSize==0xffffffff && HighUnpSize==0xffffffff);
316         }
317         else
318         {
319           HighPackSize=HighUnpSize=0;
320           // UnpSize equal to 0xffffffff without LHD_LARGE flag indicates
321           // that we do not know the unpacked file size and must unpack it
322           // until we find the end of file marker in compressed data.
323           hd->UnknownUnpSize=(LowUnpSize==0xffffffff);
324         }
325         hd->PackSize=INT32TO64(HighPackSize,hd->DataSize);
326         hd->UnpSize=INT32TO64(HighUnpSize,LowUnpSize);
327         if (hd->UnknownUnpSize)
328           hd->UnpSize=INT64NDF;
329 
330         char FileName[NM*4];
331         size_t ReadNameSize=Min(NameSize,ASIZE(FileName)-1);
332         Raw.GetB((byte *)FileName,ReadNameSize);
333         FileName[ReadNameSize]=0;
334 
335         if (FileBlock)
336         {
337           *hd->FileName=0;
338           if ((hd->Flags & LHD_UNICODE)!=0)
339           {
340             EncodeFileName NameCoder;
341             size_t Length=strlen(FileName);
342             Length++;
343             if (ReadNameSize>Length)
344               NameCoder.Decode(FileName,ReadNameSize,(byte *)FileName+Length,
345                                ReadNameSize-Length,hd->FileName,
346                              ASIZE(hd->FileName));
347           }
348 
349           if (*hd->FileName==0)
350             ArcCharToWide(FileName,hd->FileName,ASIZE(hd->FileName),ACTW_OEM);
351 
352 #ifndef SFX_MODULE
353           ConvertNameCase(hd->FileName);
354 #endif
355           ConvertFileHeader(hd);
356         }
357         else
358         {
359           CharToWide(FileName,hd->FileName,ASIZE(hd->FileName));
360 
361           // Calculate the size of optional data.
362           int DataSize=int(hd->HeadSize-NameSize-SIZEOF_FILEHEAD3);
363           if ((hd->Flags & LHD_SALT)!=0)
364             DataSize-=SIZE_SALT30;
365 
366           if (DataSize>0)
367           {
368             // Here we read optional additional fields for subheaders.
369             // They are stored after the file name and before salt.
370             hd->SubData.Alloc(DataSize);
371             Raw.GetB(&hd->SubData[0],DataSize);
372 
373             }
374 
375           if (hd->CmpName(SUBHEAD_TYPE_CMT))
376             MainComment=true;
377         }
378         if ((hd->Flags & LHD_SALT)!=0)
379           Raw.GetB(hd->Salt,SIZE_SALT30);
380         hd->mtime.SetDos(FileTime);
381         if ((hd->Flags & LHD_EXTTIME)!=0)
382         {
383           ushort Flags=Raw.Get2();
384           RarTime *tbl[4];
385           tbl[0]=&FileHead.mtime;
386           tbl[1]=&FileHead.ctime;
387           tbl[2]=&FileHead.atime;
388           tbl[3]=NULL; // Archive time is not used now.
389           for (int I=0;I<4;I++)
390           {
391             RarTime *CurTime=tbl[I];
392             uint rmode=Flags>>(3-I)*4;
393             if ((rmode & 8)==0 || CurTime==NULL)
394               continue;
395             if (I!=0)
396             {
397               uint DosTime=Raw.Get4();
398               CurTime->SetDos(DosTime);
399             }
400             RarLocalTime rlt;
401             CurTime->GetLocal(&rlt);
402             if (rmode & 4)
403               rlt.Second++;
404             rlt.Reminder=0;
405             uint count=rmode&3;
406             for (uint J=0;J<count;J++)
407             {
408               byte CurByte=Raw.Get1();
409               rlt.Reminder|=(((uint)CurByte)<<((J+3-count)*8));
410             }
411             // Convert from 100ns RAR precision to REMINDER_PRECISION.
412             rlt.Reminder*=RarTime::REMINDER_PRECISION/10000000;
413             CurTime->SetLocal(&rlt);
414           }
415         }
416         // Set to 0 in case of overflow, so end of ReadHeader cares about it.
417         NextBlockPos=SafeAdd(NextBlockPos,hd->PackSize,0);
418 
419         bool CRCProcessedOnly=hd->CommentInHeader;
420         ushort HeaderCRC=Raw.GetCRC15(CRCProcessedOnly);
421         if (hd->HeadCRC!=HeaderCRC)
422         {
423           BrokenHeader=true;
424           ErrHandler.SetErrorCode(RARX_WARNING);
425 
426           // If we have a broken encrypted header, we do not need to display
427           // the error message here, because it will be displayed for such
428           // headers later in this function. Also such headers are unlikely
429           // to have anything sensible in file name field, so it is useless
430           // to display the file name.
431           if (!Decrypt)
432             uiMsg(UIERROR_FHEADERBROKEN,Archive::FileName,hd->FileName);
433         }
434       }
435       break;
436     case HEAD_ENDARC:
437       *(BaseBlock *)&EndArcHead=ShortBlock;
438       EndArcHead.NextVolume=(EndArcHead.Flags & EARC_NEXT_VOLUME)!=0;
439       EndArcHead.DataCRC=(EndArcHead.Flags & EARC_DATACRC)!=0;
440       EndArcHead.RevSpace=(EndArcHead.Flags & EARC_REVSPACE)!=0;
441       EndArcHead.StoreVolNumber=(EndArcHead.Flags & EARC_VOLNUMBER)!=0;
442       if (EndArcHead.DataCRC)
443         EndArcHead.ArcDataCRC=Raw.Get4();
444       if (EndArcHead.StoreVolNumber)
445         VolNumber=EndArcHead.VolNumber=Raw.Get2();
446       break;
447 #ifndef SFX_MODULE
448     case HEAD3_CMT:
449       *(BaseBlock *)&CommHead=ShortBlock;
450       CommHead.UnpSize=Raw.Get2();
451       CommHead.UnpVer=Raw.Get1();
452       CommHead.Method=Raw.Get1();
453       CommHead.CommCRC=Raw.Get2();
454       break;
455     case HEAD3_PROTECT:
456       *(BaseBlock *)&ProtectHead=ShortBlock;
457       ProtectHead.DataSize=Raw.Get4();
458       ProtectHead.Version=Raw.Get1();
459       ProtectHead.RecSectors=Raw.Get2();
460       ProtectHead.TotalBlocks=Raw.Get4();
461       Raw.GetB(ProtectHead.Mark,8);
462       NextBlockPos+=ProtectHead.DataSize;
463       break;
464     case HEAD3_OLDSERVICE: // RAR 2.9 and earlier.
465       *(BaseBlock *)&SubBlockHead=ShortBlock;
466       SubBlockHead.DataSize=Raw.Get4();
467       NextBlockPos+=SubBlockHead.DataSize;
468       SubBlockHead.SubType=Raw.Get2();
469       SubBlockHead.Level=Raw.Get1();
470       switch(SubBlockHead.SubType)
471       {
472         case UO_HEAD:
473           *(SubBlockHeader *)&UOHead=SubBlockHead;
474           UOHead.OwnerNameSize=Raw.Get2();
475           UOHead.GroupNameSize=Raw.Get2();
476           if (UOHead.OwnerNameSize>=ASIZE(UOHead.OwnerName))
477             UOHead.OwnerNameSize=ASIZE(UOHead.OwnerName)-1;
478           if (UOHead.GroupNameSize>=ASIZE(UOHead.GroupName))
479             UOHead.GroupNameSize=ASIZE(UOHead.GroupName)-1;
480           Raw.GetB(UOHead.OwnerName,UOHead.OwnerNameSize);
481           Raw.GetB(UOHead.GroupName,UOHead.GroupNameSize);
482           UOHead.OwnerName[UOHead.OwnerNameSize]=0;
483           UOHead.GroupName[UOHead.GroupNameSize]=0;
484           break;
485         case NTACL_HEAD:
486           *(SubBlockHeader *)&EAHead=SubBlockHead;
487           EAHead.UnpSize=Raw.Get4();
488           EAHead.UnpVer=Raw.Get1();
489           EAHead.Method=Raw.Get1();
490           EAHead.EACRC=Raw.Get4();
491           break;
492         case STREAM_HEAD:
493           *(SubBlockHeader *)&StreamHead=SubBlockHead;
494           StreamHead.UnpSize=Raw.Get4();
495           StreamHead.UnpVer=Raw.Get1();
496           StreamHead.Method=Raw.Get1();
497           StreamHead.StreamCRC=Raw.Get4();
498           StreamHead.StreamNameSize=Raw.Get2();
499           if (StreamHead.StreamNameSize>=ASIZE(StreamHead.StreamName))
500             StreamHead.StreamNameSize=ASIZE(StreamHead.StreamName)-1;
501           Raw.GetB(StreamHead.StreamName,StreamHead.StreamNameSize);
502           StreamHead.StreamName[StreamHead.StreamNameSize]=0;
503           break;
504       }
505       break;
506 #endif
507     default:
508       if (ShortBlock.Flags & LONG_BLOCK)
509         NextBlockPos+=Raw.Get4();
510       break;
511   }
512 
513   ushort HeaderCRC=Raw.GetCRC15(false);
514 
515   // Old AV header does not have header CRC properly set.
516   if (ShortBlock.HeadCRC!=HeaderCRC && ShortBlock.HeaderType!=HEAD3_SIGN &&
517       ShortBlock.HeaderType!=HEAD3_AV)
518   {
519     bool Recovered=false;
520     if (ShortBlock.HeaderType==HEAD_ENDARC && EndArcHead.RevSpace)
521     {
522       // Last 7 bytes of recovered volume can contain zeroes, because
523       // REV files store its own information (volume number, etc.) here.
524       int64 Length=Tell();
525       Seek(Length-7,SEEK_SET);
526       Recovered=true;
527       for (int J=0;J<7;J++)
528         if (GetByte()!=0)
529           Recovered=false;
530     }
531     if (!Recovered)
532     {
533       BrokenHeader=true;
534       ErrHandler.SetErrorCode(RARX_CRC);
535 
536       if (Decrypt)
537       {
538         uiMsg(UIERROR_CHECKSUMENC,FileName,FileName);
539         FailedHeaderDecryption=true;
540         return 0;
541       }
542     }
543   }
544 
545   return Raw.Size();
546 }
547 
548 
ReadHeader50()549 size_t Archive::ReadHeader50()
550 {
551   RawRead Raw(this);
552 
553   bool Decrypt=Encrypted && CurBlockPos>(int64)SFXSize+SIZEOF_MARKHEAD5;
554 
555   if (Decrypt)
556   {
557 #if defined(RAR_NOCRYPT)
558     return 0;
559 #else
560 
561     byte HeadersInitV[SIZE_INITV];
562     if (Read(HeadersInitV,SIZE_INITV)!=SIZE_INITV)
563     {
564       UnexpEndArcMsg();
565       return 0;
566     }
567 
568     // We repeat the password request only for manually entered passwords
569     // and not for -p<pwd>. Wrong password can be intentionally provided
570     // in -p<pwd> to not stop batch processing for encrypted archives.
571     bool GlobalPassword=Cmd->Password.IsSet() || uiIsGlobalPasswordSet();
572 
573     while (true) // Repeat the password prompt for wrong passwords.
574     {
575       RequestArcPassword();
576 
577     byte PswCheck[SIZE_PSWCHECK];
578     HeadersCrypt.SetCryptKeys(false,CRYPT_RAR50,&Cmd->Password,CryptHead.Salt,HeadersInitV,CryptHead.Lg2Count,NULL,PswCheck);
579     // Verify password validity.
580     if (CryptHead.UsePswCheck && memcmp(PswCheck,CryptHead.PswCheck,SIZE_PSWCHECK)!=0)
581     {
582         if (GlobalPassword) // For -p<pwd> or Ctrl+P.
583         {
584           // This message is used by Android GUI to reset cached passwords.
585           // Update appropriate code if changed.
586           uiMsg(UIERROR_BADPSW,FileName,FileName);
587       FailedHeaderDecryption=true;
588       ErrHandler.SetErrorCode(RARX_BADPWD);
589       return 0;
590     }
591         else // For passwords entered manually.
592         {
593           // This message is used by Android GUI and Windows GUI and SFX to
594           // reset cached passwords. Update appropriate code if changed.
595           uiMsg(UIWAIT_BADPSW,FileName,FileName);
596           Cmd->Password.Clean();
597         }
598 
599 #ifdef RARDLL
600         // Avoid new requests for unrar.dll to prevent the infinite loop
601         // if app always returns the same password.
602         ErrHandler.SetErrorCode(RARX_BADPWD);
603         Cmd->DllError=ERAR_BAD_PASSWORD;
604         ErrHandler.Exit(RARX_BADPWD);
605 #else
606         continue; // Request a password again.
607 #endif
608       }
609       break;
610     }
611 
612     Raw.SetCrypt(&HeadersCrypt);
613 #endif
614   }
615 
616   // Header size must not occupy more than 3 variable length integer bytes
617   // resulting in 2 MB maximum header size (MAX_HEADER_SIZE_RAR5),
618   // so here we read 4 byte CRC32 followed by 3 bytes or less of header size.
619   const size_t FirstReadSize=7; // Smallest possible block size.
620   if (Raw.Read(FirstReadSize)<FirstReadSize)
621   {
622     UnexpEndArcMsg();
623     return 0;
624   }
625 
626   ShortBlock.Reset();
627   ShortBlock.HeadCRC=Raw.Get4();
628   uint SizeBytes=Raw.GetVSize(4);
629   uint64 BlockSize=Raw.GetV();
630 
631   if (BlockSize==0 || SizeBytes==0)
632   {
633     BrokenHeaderMsg();
634     return 0;
635   }
636 
637   int SizeToRead=int(BlockSize);
638   SizeToRead-=FirstReadSize-SizeBytes-4; // Adjust overread size bytes if any.
639   uint HeaderSize=4+SizeBytes+(uint)BlockSize;
640 
641   if (SizeToRead<0 || HeaderSize<SIZEOF_SHORTBLOCKHEAD5)
642   {
643     BrokenHeaderMsg();
644     return 0;
645   }
646 
647   Raw.Read(SizeToRead);
648 
649   if (Raw.Size()<HeaderSize)
650   {
651     UnexpEndArcMsg();
652     return 0;
653   }
654 
655   uint HeaderCRC=Raw.GetCRC50();
656 
657   ShortBlock.HeaderType=(HEADER_TYPE)Raw.GetV();
658   ShortBlock.Flags=(uint)Raw.GetV();
659   ShortBlock.SkipIfUnknown=(ShortBlock.Flags & HFL_SKIPIFUNKNOWN)!=0;
660   ShortBlock.HeadSize=HeaderSize;
661 
662   CurHeaderType=ShortBlock.HeaderType;
663 
664   bool BadCRC=(ShortBlock.HeadCRC!=HeaderCRC);
665   if (BadCRC)
666   {
667     BrokenHeaderMsg(); // Report, but attempt to process.
668 
669     BrokenHeader=true;
670     ErrHandler.SetErrorCode(RARX_CRC);
671 
672     if (Decrypt)
673     {
674       uiMsg(UIERROR_CHECKSUMENC,FileName,FileName);
675       FailedHeaderDecryption=true;
676       return 0;
677     }
678   }
679 
680   uint64 ExtraSize=0;
681   if ((ShortBlock.Flags & HFL_EXTRA)!=0)
682   {
683     ExtraSize=Raw.GetV();
684     if (ExtraSize>=ShortBlock.HeadSize)
685     {
686       BrokenHeaderMsg();
687       return 0;
688     }
689   }
690 
691   uint64 DataSize=0;
692   if ((ShortBlock.Flags & HFL_DATA)!=0)
693     DataSize=Raw.GetV();
694 
695   NextBlockPos=CurBlockPos+FullHeaderSize(ShortBlock.HeadSize);
696   // Set to 0 in case of overflow, so end of ReadHeader cares about it.
697   NextBlockPos=SafeAdd(NextBlockPos,DataSize,0);
698 
699   switch(ShortBlock.HeaderType)
700   {
701     case HEAD_CRYPT:
702       {
703         *(BaseBlock *)&CryptHead=ShortBlock;
704         uint CryptVersion=(uint)Raw.GetV();
705         if (CryptVersion>CRYPT_VERSION)
706         {
707           wchar Info[20];
708           swprintf(Info,ASIZE(Info),L"h%u",CryptVersion);
709           UnkEncVerMsg(FileName,Info);
710           return 0;
711         }
712         uint EncFlags=(uint)Raw.GetV();
713         CryptHead.UsePswCheck=(EncFlags & CHFL_CRYPT_PSWCHECK)!=0;
714         CryptHead.Lg2Count=Raw.Get1();
715         if (CryptHead.Lg2Count>CRYPT5_KDF_LG2_COUNT_MAX)
716         {
717           wchar Info[20];
718           swprintf(Info,ASIZE(Info),L"hc%u",CryptHead.Lg2Count);
719           UnkEncVerMsg(FileName,Info);
720           return 0;
721         }
722 
723         Raw.GetB(CryptHead.Salt,SIZE_SALT50);
724         if (CryptHead.UsePswCheck)
725         {
726           Raw.GetB(CryptHead.PswCheck,SIZE_PSWCHECK);
727 
728           byte csum[SIZE_PSWCHECK_CSUM];
729           Raw.GetB(csum,SIZE_PSWCHECK_CSUM);
730 
731           sha256_context ctx;
732           sha256_init(&ctx);
733           sha256_process(&ctx, CryptHead.PswCheck, SIZE_PSWCHECK);
734 
735           byte Digest[SHA256_DIGEST_SIZE];
736           sha256_done(&ctx, Digest);
737 
738           CryptHead.UsePswCheck=memcmp(csum,Digest,SIZE_PSWCHECK_CSUM)==0;
739         }
740         Encrypted=true;
741       }
742       break;
743     case HEAD_MAIN:
744       {
745         MainHead.Reset();
746         *(BaseBlock *)&MainHead=ShortBlock;
747         uint ArcFlags=(uint)Raw.GetV();
748 
749         Volume=(ArcFlags & MHFL_VOLUME)!=0;
750         Solid=(ArcFlags & MHFL_SOLID)!=0;
751         Locked=(ArcFlags & MHFL_LOCK)!=0;
752         Protected=(ArcFlags & MHFL_PROTECT)!=0;
753         Signed=false;
754         NewNumbering=true;
755 
756         if ((ArcFlags & MHFL_VOLNUMBER)!=0)
757           VolNumber=(uint)Raw.GetV();
758         else
759           VolNumber=0;
760         FirstVolume=Volume && VolNumber==0;
761 
762         if (ExtraSize!=0)
763           ProcessExtra50(&Raw,(size_t)ExtraSize,&MainHead);
764 
765 #ifdef USE_QOPEN
766         if (!ProhibitQOpen && MainHead.Locator && MainHead.QOpenOffset>0 && Cmd->QOpenMode!=QOPEN_NONE)
767         {
768           // We seek to QO block in the end of archive when processing
769           // QOpen.Load, so we need to preserve current block positions
770           // to not break normal archive processing by calling function.
771           int64 SaveCurBlockPos=CurBlockPos,SaveNextBlockPos=NextBlockPos;
772           HEADER_TYPE SaveCurHeaderType=CurHeaderType;
773 
774           QOpen.Init(this,false);
775           QOpen.Load(MainHead.QOpenOffset);
776 
777           CurBlockPos=SaveCurBlockPos;
778           NextBlockPos=SaveNextBlockPos;
779           CurHeaderType=SaveCurHeaderType;
780         }
781 #endif
782       }
783       break;
784     case HEAD_FILE:
785     case HEAD_SERVICE:
786       {
787         FileHeader *hd=ShortBlock.HeaderType==HEAD_FILE ? &FileHead:&SubHead;
788         hd->Reset();
789         *(BaseBlock *)hd=ShortBlock;
790 
791         bool FileBlock=ShortBlock.HeaderType==HEAD_FILE;
792 
793         hd->LargeFile=true;
794 
795         hd->PackSize=DataSize;
796         hd->FileFlags=(uint)Raw.GetV();
797         hd->UnpSize=Raw.GetV();
798 
799         hd->UnknownUnpSize=(hd->FileFlags & FHFL_UNPUNKNOWN)!=0;
800         if (hd->UnknownUnpSize)
801           hd->UnpSize=INT64NDF;
802 
803         hd->MaxSize=Max(hd->PackSize,hd->UnpSize);
804         hd->FileAttr=(uint)Raw.GetV();
805         if ((hd->FileFlags & FHFL_UTIME)!=0)
806           hd->mtime.SetUnix((time_t)Raw.Get4());
807 
808         hd->FileHash.Type=HASH_NONE;
809         if ((hd->FileFlags & FHFL_CRC32)!=0)
810         {
811           hd->FileHash.Type=HASH_CRC32;
812           hd->FileHash.CRC32=Raw.Get4();
813         }
814 
815         hd->RedirType=FSREDIR_NONE;
816 
817         uint CompInfo=(uint)Raw.GetV();
818         hd->Method=(CompInfo>>7) & 7;
819 
820         // "+ 50" to not mix with old RAR format algorithms. For example,
821         // we may need to use the compression algorithm 15 in the future,
822         // but it was already used in RAR 1.5 and Unpack needs to distinguish
823         // them.
824         hd->UnpVer=(CompInfo & 0x3f) + 50;
825         if (hd->UnpVer!=50) // Only 5.0 compression is known now.
826           hd->UnpVer=VER_UNKNOWN;
827 
828         hd->HostOS=(byte)Raw.GetV();
829         size_t NameSize=(size_t)Raw.GetV();
830         hd->Inherited=(ShortBlock.Flags & HFL_INHERITED)!=0;
831 
832         hd->HSType=HSYS_UNKNOWN;
833         if (hd->HostOS==HOST5_UNIX)
834           hd->HSType=HSYS_UNIX;
835         else
836           if (hd->HostOS==HOST5_WINDOWS)
837             hd->HSType=HSYS_WINDOWS;
838 
839         hd->SplitBefore=(hd->Flags & HFL_SPLITBEFORE)!=0;
840         hd->SplitAfter=(hd->Flags & HFL_SPLITAFTER)!=0;
841         hd->SubBlock=(hd->Flags & HFL_CHILD)!=0;
842         hd->Solid=FileBlock && (CompInfo & FCI_SOLID)!=0;
843         hd->Dir=(hd->FileFlags & FHFL_DIRECTORY)!=0;
844         hd->WinSize=hd->Dir ? 0:size_t(0x20000)<<((CompInfo>>10)&0xf);
845 
846         hd->CryptMethod=hd->Encrypted ? CRYPT_RAR50:CRYPT_NONE;
847 
848         char FileName[NM*4];
849         size_t ReadNameSize=Min(NameSize,ASIZE(FileName)-1);
850         Raw.GetB((byte *)FileName,ReadNameSize);
851         FileName[ReadNameSize]=0;
852 
853         UtfToWide(FileName,hd->FileName,ASIZE(hd->FileName));
854 
855         // Should do it before converting names, because extra fields can
856         // affect name processing, like in case of NTFS streams.
857         if (ExtraSize!=0)
858           ProcessExtra50(&Raw,(size_t)ExtraSize,hd);
859 
860         if (FileBlock)
861         {
862 #ifndef SFX_MODULE
863           ConvertNameCase(hd->FileName);
864 #endif
865           ConvertFileHeader(hd);
866         }
867 
868         if (!FileBlock && hd->CmpName(SUBHEAD_TYPE_CMT))
869           MainComment=true;
870 
871 #if 0
872         // For RAR5 format we read the user specified recovery percent here.
873         // It would be useful to do it for shell extension too, so we display
874         // the correct recovery record size in archive properties. But then
875         // we would need to include the entire recovery record processing
876         // code to shell extension, which is not done now.
877         if (!FileBlock && hd->CmpName(SUBHEAD_TYPE_RR) && hd->SubData.Size()>0)
878         {
879           RecoveryPercent=hd->SubData[0];
880           RSBlockHeader Header;
881           GetRRInfo(this,&Header);
882           RecoverySize=Header.RecSectionSize*Header.RecCount;
883         }
884 #endif
885 
886         if (BadCRC) // Add the file name to broken header message displayed above.
887           uiMsg(UIERROR_FHEADERBROKEN,Archive::FileName,hd->FileName);
888       }
889       break;
890     case HEAD_ENDARC:
891       {
892         *(BaseBlock *)&EndArcHead=ShortBlock;
893         uint ArcFlags=(uint)Raw.GetV();
894         EndArcHead.NextVolume=(ArcFlags & EHFL_NEXTVOLUME)!=0;
895         EndArcHead.StoreVolNumber=false;
896         EndArcHead.DataCRC=false;
897         EndArcHead.RevSpace=false;
898       }
899       break;
900   }
901 
902   return Raw.Size();
903 }
904 
905 
906 #if !defined(RAR_NOCRYPT)
RequestArcPassword()907 void Archive::RequestArcPassword()
908 {
909   if (!Cmd->Password.IsSet())
910   {
911 #ifdef RARDLL
912     if (Cmd->Callback!=NULL)
913     {
914       wchar PasswordW[MAXPASSWORD];
915       *PasswordW=0;
916       if (Cmd->Callback(UCM_NEEDPASSWORDW,Cmd->UserData,(LPARAM)PasswordW,ASIZE(PasswordW))==-1)
917         *PasswordW=0;
918       if (*PasswordW==0)
919       {
920         char PasswordA[MAXPASSWORD];
921         *PasswordA=0;
922         if (Cmd->Callback(UCM_NEEDPASSWORD,Cmd->UserData,(LPARAM)PasswordA,ASIZE(PasswordA))==-1)
923           *PasswordA=0;
924         GetWideName(PasswordA,NULL,PasswordW,ASIZE(PasswordW));
925         cleandata(PasswordA,sizeof(PasswordA));
926       }
927       Cmd->Password.Set(PasswordW);
928       cleandata(PasswordW,sizeof(PasswordW));
929     }
930     if (!Cmd->Password.IsSet())
931     {
932       Close();
933       Cmd->DllError=ERAR_MISSING_PASSWORD;
934       ErrHandler.Exit(RARX_USERBREAK);
935     }
936 #else
937     if (!uiGetPassword(UIPASSWORD_ARCHIVE,FileName,&Cmd->Password))
938     {
939       Close();
940       uiMsg(UIERROR_INCERRCOUNT); // Prevent archive deleting if delete after extraction is on.
941       ErrHandler.Exit(RARX_USERBREAK);
942     }
943 #endif
944     Cmd->ManualPassword=true;
945   }
946 }
947 #endif
948 
949 
ProcessExtra50(RawRead * Raw,size_t ExtraSize,BaseBlock * bb)950 void Archive::ProcessExtra50(RawRead *Raw,size_t ExtraSize,BaseBlock *bb)
951 {
952   // Read extra data from the end of block skipping any fields before it.
953   size_t ExtraStart=Raw->Size()-ExtraSize;
954   if (ExtraStart<Raw->GetPos())
955     return;
956   Raw->SetPos(ExtraStart);
957   while (Raw->DataLeft()>=2)
958   {
959     int64 FieldSize=Raw->GetV(); // Needs to be signed for check below and can be negative.
960     if (FieldSize<=0 || Raw->DataLeft()==0 || FieldSize>(int64)Raw->DataLeft())
961       break;
962     size_t NextPos=size_t(Raw->GetPos()+FieldSize);
963     uint64 FieldType=Raw->GetV();
964 
965     FieldSize=int64(NextPos-Raw->GetPos()); // Field size without size and type fields.
966 
967     if (FieldSize<0) // FieldType is longer than expected extra field size.
968       break;
969 
970     if (bb->HeaderType==HEAD_MAIN)
971     {
972       MainHeader *hd=(MainHeader *)bb;
973       if (FieldType==MHEXTRA_LOCATOR)
974       {
975         hd->Locator=true;
976         uint Flags=(uint)Raw->GetV();
977         if ((Flags & MHEXTRA_LOCATOR_QLIST)!=0)
978         {
979           uint64 Offset=Raw->GetV();
980           if (Offset!=0) // 0 means that reserved space was not enough to write the offset.
981             hd->QOpenOffset=Offset+CurBlockPos;
982         }
983         if ((Flags & MHEXTRA_LOCATOR_RR)!=0)
984         {
985           uint64 Offset=Raw->GetV();
986           if (Offset!=0) // 0 means that reserved space was not enough to write the offset.
987             hd->RROffset=Offset+CurBlockPos;
988         }
989       }
990     }
991 
992     if (bb->HeaderType==HEAD_FILE || bb->HeaderType==HEAD_SERVICE)
993     {
994       FileHeader *hd=(FileHeader *)bb;
995       switch(FieldType)
996       {
997         case FHEXTRA_CRYPT:
998           {
999             FileHeader *hd=(FileHeader *)bb;
1000             uint EncVersion=(uint)Raw->GetV();
1001             if (EncVersion > CRYPT_VERSION)
1002             {
1003               wchar Info[20];
1004               swprintf(Info,ASIZE(Info),L"x%u",EncVersion);
1005               UnkEncVerMsg(hd->FileName,Info);
1006             }
1007             else
1008             {
1009               uint Flags=(uint)Raw->GetV();
1010               hd->UsePswCheck=(Flags & FHEXTRA_CRYPT_PSWCHECK)!=0;
1011               hd->UseHashKey=(Flags & FHEXTRA_CRYPT_HASHMAC)!=0;
1012               hd->Lg2Count=Raw->Get1();
1013               if (hd->Lg2Count>CRYPT5_KDF_LG2_COUNT_MAX)
1014               {
1015                 wchar Info[20];
1016                 swprintf(Info,ASIZE(Info),L"xc%u",hd->Lg2Count);
1017                 UnkEncVerMsg(hd->FileName,Info);
1018               }
1019               Raw->GetB(hd->Salt,SIZE_SALT50);
1020               Raw->GetB(hd->InitV,SIZE_INITV);
1021               if (hd->UsePswCheck)
1022               {
1023                 Raw->GetB(hd->PswCheck,SIZE_PSWCHECK);
1024 
1025                 // It is important to know if password check data is valid.
1026                 // If it is damaged and header CRC32 fails to detect it,
1027                 // archiver would refuse to decompress a possibly valid file.
1028                 // Since we want to be sure distinguishing a wrong password
1029                 // or corrupt file data, we use 64-bit password check data
1030                 // and to control its validity we use 32 bits of password
1031                 // check data SHA-256 additionally to 32-bit header CRC32.
1032                 byte csum[SIZE_PSWCHECK_CSUM];
1033                 Raw->GetB(csum,SIZE_PSWCHECK_CSUM);
1034 
1035                 sha256_context ctx;
1036                 sha256_init(&ctx);
1037                 sha256_process(&ctx, hd->PswCheck, SIZE_PSWCHECK);
1038 
1039                 byte Digest[SHA256_DIGEST_SIZE];
1040                 sha256_done(&ctx, Digest);
1041 
1042                 hd->UsePswCheck=memcmp(csum,Digest,SIZE_PSWCHECK_CSUM)==0;
1043 
1044                 // RAR 5.21 and earlier set PswCheck field in service records to 0
1045                 // even if UsePswCheck was present.
1046                 if (bb->HeaderType==HEAD_SERVICE && memcmp(hd->PswCheck,"\0\0\0\0\0\0\0\0",SIZE_PSWCHECK)==0)
1047                   hd->UsePswCheck=0;
1048               }
1049               hd->SaltSet=true;
1050               hd->CryptMethod=CRYPT_RAR50;
1051               hd->Encrypted=true;
1052             }
1053           }
1054           break;
1055         case FHEXTRA_HASH:
1056           {
1057             FileHeader *hd=(FileHeader *)bb;
1058             uint Type=(uint)Raw->GetV();
1059             if (Type==FHEXTRA_HASH_BLAKE2)
1060             {
1061               hd->FileHash.Type=HASH_BLAKE2;
1062               Raw->GetB(hd->FileHash.Digest,BLAKE2_DIGEST_SIZE);
1063             }
1064           }
1065           break;
1066         case FHEXTRA_HTIME:
1067           if (FieldSize>=5)
1068           {
1069             byte Flags=(byte)Raw->GetV();
1070             bool UnixTime=(Flags & FHEXTRA_HTIME_UNIXTIME)!=0;
1071             if ((Flags & FHEXTRA_HTIME_MTIME)!=0)
1072               if (UnixTime)
1073                 hd->mtime.SetUnix(Raw->Get4());
1074               else
1075                 hd->mtime.SetWin(Raw->Get8());
1076             if ((Flags & FHEXTRA_HTIME_CTIME)!=0)
1077               if (UnixTime)
1078                 hd->ctime.SetUnix(Raw->Get4());
1079               else
1080                 hd->ctime.SetWin(Raw->Get8());
1081             if ((Flags & FHEXTRA_HTIME_ATIME)!=0)
1082               if (UnixTime)
1083                 hd->atime.SetUnix((time_t)Raw->Get4());
1084               else
1085                 hd->atime.SetWin(Raw->Get8());
1086             if (UnixTime && (Flags & FHEXTRA_HTIME_UNIX_NS)!=0) // Add nanoseconds.
1087             {
1088               uint ns;
1089               if ((Flags & FHEXTRA_HTIME_MTIME)!=0 && (ns=(Raw->Get4() & 0x3fffffff))<1000000000)
1090                 hd->mtime.Adjust(ns);
1091               if ((Flags & FHEXTRA_HTIME_CTIME)!=0 && (ns=(Raw->Get4() & 0x3fffffff))<1000000000)
1092                 hd->ctime.Adjust(ns);
1093               if ((Flags & FHEXTRA_HTIME_ATIME)!=0 && (ns=(Raw->Get4() & 0x3fffffff))<1000000000)
1094                 hd->atime.Adjust(ns);
1095             }
1096           }
1097           break;
1098         case FHEXTRA_VERSION:
1099           if (FieldSize>=1)
1100           {
1101             Raw->GetV(); // Skip flags field.
1102             uint Version=(uint)Raw->GetV();
1103             if (Version!=0)
1104             {
1105               hd->Version=true;
1106 
1107               wchar VerText[20];
1108               swprintf(VerText,ASIZE(VerText),L";%u",Version);
1109               wcsncatz(hd->FileName,VerText,ASIZE(hd->FileName));
1110             }
1111           }
1112           break;
1113         case FHEXTRA_REDIR:
1114           {
1115             hd->RedirType=(FILE_SYSTEM_REDIRECT)Raw->GetV();
1116             uint Flags=(uint)Raw->GetV();
1117             hd->DirTarget=(Flags & FHEXTRA_REDIR_DIR)!=0;
1118             size_t NameSize=(size_t)Raw->GetV();
1119 
1120             char UtfName[NM*4];
1121             *UtfName=0;
1122             if (NameSize<ASIZE(UtfName)-1)
1123             {
1124               Raw->GetB(UtfName,NameSize);
1125               UtfName[NameSize]=0;
1126             }
1127 #ifdef _WIN_ALL
1128             UnixSlashToDos(UtfName,UtfName,ASIZE(UtfName));
1129 #endif
1130             UtfToWide(UtfName,hd->RedirName,ASIZE(hd->RedirName));
1131           }
1132           break;
1133         case FHEXTRA_UOWNER:
1134           {
1135             uint Flags=(uint)Raw->GetV();
1136             hd->UnixOwnerNumeric=(Flags & FHEXTRA_UOWNER_NUMUID)!=0;
1137             hd->UnixGroupNumeric=(Flags & FHEXTRA_UOWNER_NUMGID)!=0;
1138             *hd->UnixOwnerName=*hd->UnixGroupName=0;
1139             if ((Flags & FHEXTRA_UOWNER_UNAME)!=0)
1140             {
1141               size_t Length=(size_t)Raw->GetV();
1142               Length=Min(Length,ASIZE(hd->UnixOwnerName)-1);
1143               Raw->GetB(hd->UnixOwnerName,Length);
1144               hd->UnixOwnerName[Length]=0;
1145             }
1146             if ((Flags & FHEXTRA_UOWNER_GNAME)!=0)
1147             {
1148               size_t Length=(size_t)Raw->GetV();
1149               Length=Min(Length,ASIZE(hd->UnixGroupName)-1);
1150               Raw->GetB(hd->UnixGroupName,Length);
1151               hd->UnixGroupName[Length]=0;
1152             }
1153 #ifdef _UNIX
1154             if (hd->UnixOwnerNumeric)
1155               hd->UnixOwnerID=(uid_t)Raw->GetV();
1156             if (hd->UnixGroupNumeric)
1157               hd->UnixGroupID=(gid_t)Raw->GetV();
1158 #else
1159             // Need these fields in Windows too for 'list' command,
1160             // but uid_t and gid_t are not defined.
1161             if (hd->UnixOwnerNumeric)
1162               hd->UnixOwnerID=(uint)Raw->GetV();
1163             if (hd->UnixGroupNumeric)
1164               hd->UnixGroupID=(uint)Raw->GetV();
1165 #endif
1166             hd->UnixOwnerSet=true;
1167           }
1168           break;
1169         case FHEXTRA_SUBDATA:
1170           {
1171             // RAR 5.21 and earlier set FHEXTRA_SUBDATA size to 1 less than
1172             // required. It did not hurt extraction, because UnRAR 5.21
1173             // and earlier ignored this field and set FieldSize as data left
1174             // in entire extra area. But now we set the correct field size
1175             // and set FieldSize based on the actual extra record size,
1176             // so we need to adjust it for those older archives here.
1177             // FHEXTRA_SUBDATA in those archives always belongs to HEAD_SERVICE
1178             // and always is last in extra area. So since its size is by 1
1179             // less than needed, we always have 1 byte left in extra area,
1180             // which fact we use here to detect such archives.
1181             if (bb->HeaderType==HEAD_SERVICE && Raw->Size()-NextPos==1)
1182               FieldSize++;
1183 
1184             // We cannot allocate too much memory here, because above
1185             // we check FieldSize againt Raw size and we control that Raw size
1186             // is sensible when reading headers.
1187             hd->SubData.Alloc((size_t)FieldSize);
1188             Raw->GetB(hd->SubData.Addr(0),(size_t)FieldSize);
1189           }
1190           break;
1191       }
1192     }
1193 
1194     Raw->SetPos(NextPos);
1195   }
1196 }
1197 
1198 
1199 #ifndef SFX_MODULE
ReadHeader14()1200 size_t Archive::ReadHeader14()
1201 {
1202   RawRead Raw(this);
1203   if (CurBlockPos<=(int64)SFXSize)
1204   {
1205     Raw.Read(SIZEOF_MAINHEAD14);
1206     MainHead.Reset();
1207     byte Mark[4];
1208     Raw.GetB(Mark,4);
1209     uint HeadSize=Raw.Get2();
1210     if (HeadSize<7)
1211       return false;
1212     byte Flags=Raw.Get1();
1213     NextBlockPos=CurBlockPos+HeadSize;
1214     CurHeaderType=HEAD_MAIN;
1215 
1216     Volume=(Flags & MHD_VOLUME)!=0;
1217     Solid=(Flags & MHD_SOLID)!=0;
1218     Locked=(Flags & MHD_LOCK)!=0;
1219     MainHead.CommentInHeader=(Flags & MHD_COMMENT)!=0;
1220     MainHead.PackComment=(Flags & MHD_PACK_COMMENT)!=0;
1221   }
1222   else
1223   {
1224     Raw.Read(SIZEOF_FILEHEAD14);
1225     FileHead.Reset();
1226 
1227     FileHead.HeaderType=HEAD_FILE;
1228     FileHead.DataSize=Raw.Get4();
1229     FileHead.UnpSize=Raw.Get4();
1230     FileHead.FileHash.Type=HASH_RAR14;
1231     FileHead.FileHash.CRC32=Raw.Get2();
1232     FileHead.HeadSize=Raw.Get2();
1233     if (FileHead.HeadSize<21)
1234       return false;
1235     uint FileTime=Raw.Get4();
1236     FileHead.FileAttr=Raw.Get1();
1237     FileHead.Flags=Raw.Get1()|LONG_BLOCK;
1238     FileHead.UnpVer=(Raw.Get1()==2) ? 13 : 10;
1239     size_t NameSize=Raw.Get1();
1240     FileHead.Method=Raw.Get1();
1241 
1242     FileHead.SplitBefore=(FileHead.Flags & LHD_SPLIT_BEFORE)!=0;
1243     FileHead.SplitAfter=(FileHead.Flags & LHD_SPLIT_AFTER)!=0;
1244     FileHead.Encrypted=(FileHead.Flags & LHD_PASSWORD)!=0;
1245     FileHead.CryptMethod=FileHead.Encrypted ? CRYPT_RAR13:CRYPT_NONE;
1246 
1247     FileHead.PackSize=FileHead.DataSize;
1248     FileHead.WinSize=0x10000;
1249     FileHead.Dir=(FileHead.FileAttr & 0x10)!=0;
1250 
1251     FileHead.HostOS=HOST_MSDOS;
1252     FileHead.HSType=HSYS_WINDOWS;
1253 
1254     FileHead.mtime.SetDos(FileTime);
1255 
1256     Raw.Read(NameSize);
1257 
1258     char FileName[NM];
1259     size_t ReadNameSize=Min(NameSize,ASIZE(FileName)-1);
1260     Raw.GetB((byte *)FileName,ReadNameSize);
1261     FileName[ReadNameSize]=0;
1262     IntToExt(FileName,FileName,ASIZE(FileName));
1263     CharToWide(FileName,FileHead.FileName,ASIZE(FileHead.FileName));
1264     ConvertNameCase(FileHead.FileName);
1265     ConvertFileHeader(&FileHead);
1266 
1267     if (Raw.Size()!=0)
1268       NextBlockPos=CurBlockPos+FileHead.HeadSize+FileHead.PackSize;
1269     CurHeaderType=HEAD_FILE;
1270   }
1271   return NextBlockPos>CurBlockPos ? Raw.Size() : 0;
1272 }
1273 #endif
1274 
1275 
1276 #ifndef SFX_MODULE
ConvertNameCase(wchar * Name)1277 void Archive::ConvertNameCase(wchar *Name)
1278 {
1279   if (Cmd->ConvertNames==NAMES_UPPERCASE)
1280     wcsupper(Name);
1281   if (Cmd->ConvertNames==NAMES_LOWERCASE)
1282     wcslower(Name);
1283 }
1284 #endif
1285 
1286 
IsArcDir()1287 bool Archive::IsArcDir()
1288 {
1289   return FileHead.Dir;
1290 }
1291 
1292 
ConvertAttributes()1293 void Archive::ConvertAttributes()
1294 {
1295 #if defined(_WIN_ALL) || defined(_EMX)
1296   if (FileHead.HSType!=HSYS_WINDOWS)
1297     FileHead.FileAttr=FileHead.Dir ? 0x10 : 0x20;
1298 #endif
1299 #ifdef _UNIX
1300   // umask defines which permission bits must not be set by default
1301   // when creating a file or directory. The typical default value
1302   // for the process umask is S_IWGRP | S_IWOTH (octal 022),
1303   // resulting in 0644 mode for new files.
1304   // Normally umask is applied automatically when creating a file,
1305   // but we set attributes with chmod later, so we need to calculate
1306   // resulting attributes here. We do it only for non-Unix archives.
1307   // We restore native Unix attributes as is, because it can be backup.
1308   static mode_t mask = (mode_t) -1;
1309 
1310   if (mask == (mode_t) -1)
1311   {
1312     // umask call returns the current umask value. Argument (022) is not
1313     // important here.
1314     mask = umask(022);
1315 
1316     // Restore the original umask value, which was changed to 022 above.
1317     umask(mask);
1318   }
1319 
1320   switch(FileHead.HSType)
1321   {
1322     case HSYS_WINDOWS:
1323       {
1324         // Mapping MSDOS, OS/2 and Windows file attributes to Unix.
1325 
1326         if (FileHead.FileAttr & 0x10) // FILE_ATTRIBUTE_DIRECTORY
1327         {
1328           // For directories we use 0777 mask.
1329           FileHead.FileAttr=0777 & ~mask;
1330         }
1331         else
1332           if (FileHead.FileAttr & 1)  // FILE_ATTRIBUTE_READONLY
1333           {
1334             // For read only files we use 0444 mask with 'w' bits turned off.
1335             FileHead.FileAttr=0444 & ~mask;
1336           }
1337           else
1338           {
1339             // umask does not set +x for regular files, so we use 0666
1340             // instead of 0777 as for directories.
1341             FileHead.FileAttr=0666 & ~mask;
1342           }
1343       }
1344       break;
1345     case HSYS_UNIX:
1346       break;
1347     default:
1348       if (FileHead.Dir)
1349         FileHead.FileAttr=0x41ff & ~mask;
1350       else
1351         FileHead.FileAttr=0x81b6 & ~mask;
1352       break;
1353   }
1354 #endif
1355 }
1356 
1357 
ConvertFileHeader(FileHeader * hd)1358 void Archive::ConvertFileHeader(FileHeader *hd)
1359 {
1360   if (hd->HSType==HSYS_UNKNOWN)
1361     if (hd->Dir)
1362       hd->FileAttr=0x10;
1363     else
1364       hd->FileAttr=0x20;
1365 
1366 #ifdef _WIN_ALL
1367   if (hd->HSType==HSYS_UNIX) // Convert Unix, OS X and Android decomposed chracters to Windows precomposed.
1368     ConvertToPrecomposed(hd->FileName,ASIZE(hd->FileName));
1369 #endif
1370 
1371   for (wchar *s=hd->FileName;*s!=0;s++)
1372   {
1373 #ifdef _UNIX
1374     // Backslash is the invalid character for Windows file headers,
1375     // but it can present in Unix file names extracted in Unix.
1376     if (*s=='\\' && Format==RARFMT50 && hd->HSType==HSYS_WINDOWS)
1377       *s='_';
1378 #endif
1379 
1380 #if defined(_WIN_ALL) || defined(_EMX)
1381     // RAR 5.0 archives do not use '\' as path separator, so if we see it,
1382     // it means that it is a part of Unix file name, which we cannot
1383     // extract in Windows.
1384     if (*s=='\\' && Format==RARFMT50)
1385       *s='_';
1386 
1387     // ':' in file names is allowed in Unix, but not in Windows.
1388     // Even worse, file data will be written to NTFS stream on NTFS,
1389     // so automatic name correction on file create error in extraction
1390     // routine does not work. In Windows and DOS versions we better
1391     // replace ':' now.
1392     if (*s==':')
1393       *s='_';
1394 #endif
1395 
1396     // This code must be performed only after other path separator checks,
1397     // because it produces backslashes illegal for some of checks above.
1398     // Backslash is allowed in file names in Unix, but not in Windows.
1399     // Still, RAR 4.x uses backslashes as path separator even in Unix.
1400     // Forward slash is not allowed in both systems. In RAR 5.0 we use
1401     // the forward slash as universal path separator.
1402     if (*s=='/' || *s=='\\' && Format!=RARFMT50)
1403       *s=CPATHDIVIDER;
1404   }
1405 }
1406 
1407 
GetStartPos()1408 int64 Archive::GetStartPos()
1409 {
1410   int64 StartPos=SFXSize+MarkHead.HeadSize;
1411   if (Format==RARFMT15)
1412     StartPos+=MainHead.HeadSize;
1413   else // RAR 5.0.
1414     StartPos+=CryptHead.HeadSize+FullHeaderSize(MainHead.HeadSize);
1415   return StartPos;
1416 }
1417 
1418 
ReadSubData(Array<byte> * UnpData,File * DestFile,bool TestMode)1419 bool Archive::ReadSubData(Array<byte> *UnpData,File *DestFile,bool TestMode)
1420 {
1421   if (BrokenHeader)
1422   {
1423     uiMsg(UIERROR_SUBHEADERBROKEN,FileName);
1424     ErrHandler.SetErrorCode(RARX_CRC);
1425     return false;
1426   }
1427   if (SubHead.Method>5 || SubHead.UnpVer>(Format==RARFMT50 ? VER_UNPACK5:VER_UNPACK))
1428   {
1429     uiMsg(UIERROR_SUBHEADERUNKNOWN,FileName);
1430     return false;
1431   }
1432 
1433   if (SubHead.PackSize==0 && !SubHead.SplitAfter)
1434     return true;
1435 
1436   SubDataIO.Init();
1437   Unpack Unpack(&SubDataIO);
1438   Unpack.Init(SubHead.WinSize,false);
1439 
1440   if (DestFile==NULL)
1441   {
1442     if (SubHead.UnpSize>0x1000000)
1443     {
1444       // So huge allocation must never happen in valid archives.
1445       uiMsg(UIERROR_SUBHEADERUNKNOWN,FileName);
1446       return false;
1447     }
1448     if (UnpData==NULL)
1449       SubDataIO.SetTestMode(true);
1450     else
1451     {
1452       UnpData->Alloc((size_t)SubHead.UnpSize);
1453       SubDataIO.SetUnpackToMemory(&(*UnpData)[0],(uint)SubHead.UnpSize);
1454     }
1455   }
1456   if (SubHead.Encrypted)
1457     if (Cmd->Password.IsSet())
1458       SubDataIO.SetEncryption(false,SubHead.CryptMethod,&Cmd->Password,
1459                 SubHead.SaltSet ? SubHead.Salt:NULL,SubHead.InitV,
1460                 SubHead.Lg2Count,SubHead.HashKey,SubHead.PswCheck);
1461     else
1462       return false;
1463   SubDataIO.UnpHash.Init(SubHead.FileHash.Type,1);
1464   SubDataIO.SetPackedSizeToRead(SubHead.PackSize);
1465   SubDataIO.EnableShowProgress(false);
1466   SubDataIO.SetFiles(this,DestFile);
1467   SubDataIO.SetTestMode(TestMode);
1468   SubDataIO.UnpVolume=SubHead.SplitAfter;
1469   SubDataIO.SetSubHeader(&SubHead,NULL);
1470   Unpack.SetDestSize(SubHead.UnpSize);
1471   if (SubHead.Method==0)
1472     CmdExtract::UnstoreFile(SubDataIO,SubHead.UnpSize);
1473   else
1474     Unpack.DoUnpack(SubHead.UnpVer,false);
1475 
1476   if (!SubDataIO.UnpHash.Cmp(&SubHead.FileHash,SubHead.UseHashKey ? SubHead.HashKey:NULL))
1477   {
1478     uiMsg(UIERROR_SUBHEADERDATABROKEN,FileName,SubHead.FileName);
1479     ErrHandler.SetErrorCode(RARX_CRC);
1480     if (UnpData!=NULL)
1481       UnpData->Reset();
1482     return false;
1483   }
1484   return true;
1485 }
1486