extinfo.cpp 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. #include "rar.hpp"
  2. #include "hardlinks.cpp"
  3. #include "win32stm.cpp"
  4. #ifdef _WIN_ALL
  5. #include "win32acl.cpp"
  6. #include "win32lnk.cpp"
  7. #endif
  8. #ifdef _UNIX
  9. #include "uowners.cpp"
  10. #ifdef SAVE_LINKS
  11. #include "ulinks.cpp"
  12. #endif
  13. #endif
  14. // RAR2 service header extra records.
  15. #ifndef SFX_MODULE
  16. void SetExtraInfo20(CommandData *Cmd,Archive &Arc,wchar *Name)
  17. {
  18. if (Cmd->Test)
  19. return;
  20. switch(Arc.SubBlockHead.SubType)
  21. {
  22. #ifdef _UNIX
  23. case UO_HEAD:
  24. if (Cmd->ProcessOwners)
  25. ExtractUnixOwner20(Arc,Name);
  26. break;
  27. #endif
  28. #ifdef _WIN_ALL
  29. case NTACL_HEAD:
  30. if (Cmd->ProcessOwners)
  31. ExtractACL20(Arc,Name);
  32. break;
  33. case STREAM_HEAD:
  34. ExtractStreams20(Arc,Name);
  35. break;
  36. #endif
  37. }
  38. }
  39. #endif
  40. // RAR3 and RAR5 service header extra records.
  41. void SetExtraInfo(CommandData *Cmd,Archive &Arc,wchar *Name)
  42. {
  43. #ifdef _UNIX
  44. if (!Cmd->Test && Cmd->ProcessOwners && Arc.Format==RARFMT15 &&
  45. Arc.SubHead.CmpName(SUBHEAD_TYPE_UOWNER))
  46. ExtractUnixOwner30(Arc,Name);
  47. #endif
  48. #ifdef _WIN_ALL
  49. if (!Cmd->Test && Cmd->ProcessOwners && Arc.SubHead.CmpName(SUBHEAD_TYPE_ACL))
  50. ExtractACL(Arc,Name);
  51. if (Arc.SubHead.CmpName(SUBHEAD_TYPE_STREAM))
  52. ExtractStreams(Arc,Name,Cmd->Test);
  53. #endif
  54. }
  55. // Extra data stored directly in file header.
  56. void SetFileHeaderExtra(CommandData *Cmd,Archive &Arc,wchar *Name)
  57. {
  58. #ifdef _UNIX
  59. if (Cmd->ProcessOwners && Arc.Format==RARFMT50 && Arc.FileHead.UnixOwnerSet)
  60. SetUnixOwner(Arc,Name);
  61. #endif
  62. }
  63. // Calculate a number of path components except \. and \..
  64. static int CalcAllowedDepth(const wchar *Name)
  65. {
  66. int AllowedDepth=0;
  67. while (*Name!=0)
  68. {
  69. if (IsPathDiv(Name[0]) && Name[1]!=0 && !IsPathDiv(Name[1]))
  70. {
  71. bool Dot=Name[1]=='.' && (IsPathDiv(Name[2]) || Name[2]==0);
  72. bool Dot2=Name[1]=='.' && Name[2]=='.' && (IsPathDiv(Name[3]) || Name[3]==0);
  73. if (!Dot && !Dot2)
  74. AllowedDepth++;
  75. }
  76. Name++;
  77. }
  78. return AllowedDepth;
  79. }
  80. // Check if all existing path components are directories and not links.
  81. static bool LinkInPath(const wchar *Name)
  82. {
  83. wchar Path[NM];
  84. if (wcslen(Name)>=ASIZE(Path))
  85. return true; // It should not be that long, skip.
  86. wcsncpyz(Path,Name,ASIZE(Path));
  87. for (wchar *s=Path+wcslen(Path)-1;s>Path;s--)
  88. if (IsPathDiv(*s))
  89. {
  90. *s=0;
  91. FindData FD;
  92. if (FindFile::FastFind(Path,&FD,true) && (FD.IsLink || !FD.IsDir))
  93. return true;
  94. }
  95. return false;
  96. }
  97. bool IsRelativeSymlinkSafe(CommandData *Cmd,const wchar *SrcName,const wchar *PrepSrcName,const wchar *TargetName)
  98. {
  99. // Catch root dir based /path/file paths also as stuff like \\?\.
  100. // Do not check PrepSrcName here, it can be root based if destination path
  101. // is a root based.
  102. if (IsFullRootPath(SrcName) || IsFullRootPath(TargetName))
  103. return false;
  104. // Number of ".." in link target.
  105. int UpLevels=0;
  106. for (int Pos=0;*TargetName!=0;Pos++)
  107. {
  108. bool Dot2=TargetName[0]=='.' && TargetName[1]=='.' &&
  109. (IsPathDiv(TargetName[2]) || TargetName[2]==0) &&
  110. (Pos==0 || IsPathDiv(*(TargetName-1)));
  111. if (Dot2)
  112. UpLevels++;
  113. TargetName++;
  114. }
  115. // If link target includes "..", it must not have another links
  116. // in the path, because they can bypass our safety check. For example,
  117. // suppose we extracted "lnk1" -> "." first and "lnk1/lnk2" -> ".." next
  118. // or "dir/lnk1" -> ".." first and "dir/lnk1/lnk2" -> ".." next.
  119. if (UpLevels>0 && LinkInPath(PrepSrcName))
  120. return false;
  121. // We could check just prepared src name, but for extra safety
  122. // we check both original (as from archive header) and prepared
  123. // (after applying the destination path and -ep switches) names.
  124. int AllowedDepth=CalcAllowedDepth(SrcName); // Original name depth.
  125. // Remove the destination path from prepared name if any. We should not
  126. // count the destination path depth, because the link target must point
  127. // inside of this path, not outside of it.
  128. size_t ExtrPathLength=wcslen(Cmd->ExtrPath);
  129. if (ExtrPathLength>0 && wcsncmp(PrepSrcName,Cmd->ExtrPath,ExtrPathLength)==0)
  130. {
  131. PrepSrcName+=ExtrPathLength;
  132. while (IsPathDiv(*PrepSrcName))
  133. PrepSrcName++;
  134. }
  135. int PrepAllowedDepth=CalcAllowedDepth(PrepSrcName);
  136. return AllowedDepth>=UpLevels && PrepAllowedDepth>=UpLevels;
  137. }
  138. bool ExtractSymlink(CommandData *Cmd,ComprDataIO &DataIO,Archive &Arc,const wchar *LinkName)
  139. {
  140. #if defined(SAVE_LINKS) && defined(_UNIX)
  141. // For RAR 3.x archives we process links even in test mode to skip link data.
  142. if (Arc.Format==RARFMT15)
  143. return ExtractUnixLink30(Cmd,DataIO,Arc,LinkName);
  144. if (Arc.Format==RARFMT50)
  145. return ExtractUnixLink50(Cmd,LinkName,&Arc.FileHead);
  146. #elif defined _WIN_ALL
  147. // RAR 5.0 archives store link information in file header, so there is
  148. // no need to additionally test it if we do not create a file.
  149. if (Arc.Format==RARFMT50)
  150. return CreateReparsePoint(Cmd,LinkName,&Arc.FileHead);
  151. #endif
  152. return false;
  153. }