1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79
|
#include "rar.hpp"
static bool IsFullRootPath(const char *PathA) // Unix ASCII version.
{
return *PathA==CPATHDIVIDER;
}
static bool IsRelativeSymlinkSafe(const char *SrcName,const char *TargetName)
{
if (IsFullRootPath(SrcName))
return false;
int AllowedDepth=0;
while (*SrcName!=0)
{
if (IsPathDiv(SrcName[0]) && SrcName[1]!=0 && !IsPathDiv(SrcName[1]))
{
bool Dot=SrcName[1]=='.' && (IsPathDiv(SrcName[2]) || SrcName[2]==0);
bool Dot2=SrcName[1]=='.' && SrcName[2]=='.' && (IsPathDiv(SrcName[3]) || SrcName[3]==0);
if (!Dot && !Dot2)
AllowedDepth++;
}
SrcName++;
}
if (IsFullRootPath(TargetName)) // Catch root dir based /path/file paths.
return false;
for (int Pos=0;*TargetName!=0;Pos++)
{
bool Dot2=TargetName[0]=='.' && TargetName[1]=='.' &&
(IsPathDiv(TargetName[2]) || TargetName[2]==0) &&
(Pos==0 || IsPathDiv(*(TargetName-1)));
if (Dot2)
AllowedDepth--;
TargetName++;
}
return AllowedDepth>=0;
}
bool ExtractLink(CommandData *Cmd,ComprDataIO &DataIO,Archive &Arc,const char *LinkName,uint &LinkCRC,bool Create)
{
#if defined(SAVE_LINKS) && defined(_UNIX)
char LinkTarget[NM];
if (IsLink(Arc.NewLhd.FileAttr))
{
int DataSize=Min(Arc.NewLhd.PackSize,sizeof(LinkTarget)-1);
DataIO.UnpRead((byte *)LinkTarget,DataSize);
LinkTarget[DataSize]=0;
if (Create)
{
if (!Cmd->AbsoluteLinks && (IsFullRootPath(LinkTarget) ||
!IsRelativeSymlinkSafe(Arc.FileName,LinkTarget))) {
int NameSize=Min(DataSize,strlen(LinkTarget));
LinkCRC=CRC(0xffffffff,LinkTarget,NameSize);
return(false);
}
CreatePath(LinkName,NULL,true);
if (symlink(LinkTarget,LinkName)==-1) // Error.
if (errno==EEXIST)
Log(Arc.FileName,St(MSymLinkExists),LinkName);
else
{
Log(Arc.FileName,St(MErrCreateLnk),LinkName);
ErrHandler.SetErrorCode(WARNING);
}
// We do not set time of created symlink, because utime changes
// time of link target and lutimes is not available on all Linux
// systems at the moment of writing this code.
}
int NameSize=Min(DataSize,strlen(LinkTarget));
LinkCRC=CRC(0xffffffff,LinkTarget,NameSize);
return(true);
}
#endif
return(false);
}
|