Coverage Report

Created: 2023-06-07 06:02

/src/unrar/ulinks.cpp
Line
Count
Source (jump to first uncovered line)
1
2
3
static bool UnixSymlink(CommandData *Cmd,const char *Target,const wchar *LinkName,RarTime *ftm,RarTime *fta)
4
0
{
5
0
  CreatePath(LinkName,true,Cmd->DisableNames);
6
7
  // Overwrite prompt was already issued and confirmed earlier, so we can
8
  // remove existing symlink or regular file here. PrepareToDelete was also
9
  // called earlier inside of uiAskReplaceEx.
10
0
  DelFile(LinkName);
11
12
0
  char LinkNameA[NM];
13
0
  WideToChar(LinkName,LinkNameA,ASIZE(LinkNameA));
14
0
  if (symlink(Target,LinkNameA)==-1) // Error.
15
0
  {
16
0
    if (errno==EEXIST)
17
0
      uiMsg(UIERROR_ULINKEXIST,LinkName);
18
0
    else
19
0
    {
20
0
      uiMsg(UIERROR_SLINKCREATE,UINULL,LinkName);
21
0
      ErrHandler.SetErrorCode(RARX_WARNING);
22
0
    }
23
0
    return false;
24
0
  }
25
0
#ifdef USE_LUTIMES
26
0
#ifdef UNIX_TIME_NS
27
0
  timespec times[2];
28
0
  times[0].tv_sec=fta->GetUnix();
29
0
  times[0].tv_nsec=fta->IsSet() ? long(fta->GetUnixNS()%1000000000) : UTIME_NOW;
30
0
  times[1].tv_sec=ftm->GetUnix();
31
0
  times[1].tv_nsec=ftm->IsSet() ? long(ftm->GetUnixNS()%1000000000) : UTIME_NOW;
32
0
  utimensat(AT_FDCWD,LinkNameA,times,AT_SYMLINK_NOFOLLOW);
33
#else
34
  struct timeval tv[2];
35
  tv[0].tv_sec=fta->GetUnix();
36
  tv[0].tv_usec=long(fta->GetUnixNS()%1000000000/1000);
37
  tv[1].tv_sec=ftm->GetUnix();
38
  tv[1].tv_usec=long(ftm->GetUnixNS()%1000000000/1000);
39
  lutimes(LinkNameA,tv);
40
#endif
41
0
#endif
42
43
0
  return true;
44
0
}
45
46
47
static bool IsFullPath(const char *PathA) // Unix ASCII version.
48
0
{
49
0
  return *PathA==CPATHDIVIDER;
50
0
}
51
52
53
// For security purpose we prefer to be sure that CharToWide completed
54
// successfully and even if it truncated a string for some reason,
55
// it didn't affect the number of path related characters we analyze
56
// in IsRelativeSymlinkSafe later.
57
// This check is likely to be excessive, but let's keep it anyway.
58
static bool SafeCharToWide(const char *Src,wchar *Dest,size_t DestSize)
59
0
{
60
0
  if (!CharToWide(Src,Dest,DestSize) || *Dest==0)
61
0
    return false;
62
0
  uint SrcChars=0,DestChars=0;
63
0
  for (uint I=0;Src[I]!=0;I++)
64
0
    if (Src[I]=='/' || Src[I]=='.')
65
0
      SrcChars++;
66
0
  for (uint I=0;Dest[I]!=0;I++)
67
0
    if (Dest[I]=='/' || Dest[I]=='.')
68
0
      DestChars++;
69
0
  return SrcChars==DestChars;
70
0
}
71
72
73
bool ExtractUnixLink30(CommandData *Cmd,ComprDataIO &DataIO,Archive &Arc,const wchar *LinkName)
74
0
{
75
0
  char Target[NM];
76
0
  if (IsLink(Arc.FileHead.FileAttr))
77
0
  {
78
0
    size_t DataSize=(size_t)Arc.FileHead.PackSize;
79
0
    if (DataSize>ASIZE(Target)-1)
80
0
      return false;
81
0
    if ((size_t)DataIO.UnpRead((byte *)Target,DataSize)!=DataSize)
82
0
      return false;
83
0
    Target[DataSize]=0;
84
85
0
    DataIO.UnpHash.Init(Arc.FileHead.FileHash.Type,1);
86
0
    DataIO.UnpHash.Update(Target,strlen(Target));
87
0
    DataIO.UnpHash.Result(&Arc.FileHead.FileHash);
88
89
    // Return true in case of bad checksum, so link will be processed further
90
    // and extraction routine will report the checksum error.
91
0
    if (!DataIO.UnpHash.Cmp(&Arc.FileHead.FileHash,Arc.FileHead.UseHashKey ? Arc.FileHead.HashKey:NULL))
92
0
      return true;
93
94
0
    wchar TargetW[NM];
95
0
    if (!SafeCharToWide(Target,TargetW,ASIZE(TargetW)))
96
0
      return false;
97
    // Use Arc.FileHead.FileName instead of LinkName, since LinkName
98
    // can include the destination path as a prefix, which can
99
    // confuse IsRelativeSymlinkSafe algorithm.
100
0
    if (!Cmd->AbsoluteLinks && (IsFullPath(TargetW) ||
101
0
        !IsRelativeSymlinkSafe(Cmd,Arc.FileHead.FileName,LinkName,TargetW)))
102
0
      return false;
103
0
    return UnixSymlink(Cmd,Target,LinkName,&Arc.FileHead.mtime,&Arc.FileHead.atime);
104
0
  }
105
0
  return false;
106
0
}
107
108
109
bool ExtractUnixLink50(CommandData *Cmd,const wchar *Name,FileHeader *hd)
110
0
{
111
0
  char Target[NM];
112
0
  WideToChar(hd->RedirName,Target,ASIZE(Target));
113
0
  if (hd->RedirType==FSREDIR_WINSYMLINK || hd->RedirType==FSREDIR_JUNCTION)
114
0
  {
115
    // Cannot create Windows absolute path symlinks in Unix. Only relative path
116
    // Windows symlinks can be created here. RAR 5.0 used \??\ prefix
117
    // for Windows absolute symlinks, since RAR 5.1 /??/ is used.
118
    // We escape ? as \? to avoid "trigraph" warning
119
0
    if (strncmp(Target,"\\??\\",4)==0 || strncmp(Target,"/\?\?/",4)==0)
120
0
      return false;
121
0
    DosSlashToUnix(Target,Target,ASIZE(Target));
122
0
  }
123
124
0
  wchar TargetW[NM];
125
0
  if (!SafeCharToWide(Target,TargetW,ASIZE(TargetW)))
126
0
    return false;
127
  // Use hd->FileName instead of LinkName, since LinkName can include
128
  // the destination path as a prefix, which can confuse
129
  // IsRelativeSymlinkSafe algorithm.
130
  // 2022.05.04: Use TargetW instead of previously used hd->RedirName
131
  // for security reason.
132
0
  if (!Cmd->AbsoluteLinks && (IsFullPath(TargetW) ||
133
0
      !IsRelativeSymlinkSafe(Cmd,hd->FileName,Name,TargetW)))
134
0
    return false;
135
0
  return UnixSymlink(Cmd,Target,Name,&hd->mtime,&hd->atime);
136
0
}