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