Problems with SFTP server running on Linux (paths)

Discussion of open issues, suggestions and bugs regarding network security and data protection solution - SecureBridge
Post Reply
tcaduto12068
Posts: 74
Joined: Wed 17 Aug 2016 05:57

Problems with SFTP server running on Linux (paths)

Post by tcaduto12068 » Sat 12 Jan 2019 18:13

Hi,
I have been running a SFTP server built with SB for a few years now on windows and recently decided to port it to linux.
I have it compiling and running but the issue I am running into is with the absolute path and getting the directory listing.
The default event for getting the absolute path is returning a ./ and this is causing the getfullpath function to fail and then the findfirst function in the getdir list event fails.
Do you guys have any tips or examples on how to get this to work? I tried removing the . and then I can get a directory listing but it's for the real root and not the users home dir.

running the latest SB version from December and Lazarus 1.8 (latest stable version) on Manjaro Linux.

Thanks,

tcaduto12068
Posts: 74
Joined: Wed 17 Aug 2016 05:57

Re: Problems with SFTP server running on Linux (paths)

Post by tcaduto12068 » Mon 14 Jan 2019 19:46

Hi,
I think I figured this out and it's because on Linux the GetCanonicalPath function does nothing.
What it's supposed to do (and what it does on windows) is get a valid path that does not have the . or .. shortcuts in them.
When compiled on linux all it does is convert \ to /

So to get this working on linux under Free Pascal/Lazarus you need to do this.

result:= ExpandFileName(result)

This does the same thing as the windows only function PathCanonicalize

So a else would have to be added to the
{$IFDEF MSWINDOWS}

{$Else}
result:= ExpandFileName(result)
{$ENDIF}

The default ongetfullpath and ONGetAbsolutePath function also needs to be modified to work under Linux.
On linux the expandfilename for a . brings back the current working directory not / so if the path is . it needs to be converted to the pathdelim i.e. '/'

Code: Select all

procedure TSFTPDataMod.SFTPServerGetFullPath(Sender: TObject;
  SFTPSessionInfo: TScSFTPSessionInfo; var Path: string);
begin
Path := TScSFTPServer(sender).GetCanonicalPath(SFTPSessionInfo, Path);

  if Path = PathDelim then
    Path := SFTPSessionInfo.HomePath
  else
  if (Length(Path) > 0) and (Path[1] = PathDelim) then
    Path := SFTPSessionInfo.HomePath + Path
  else
    Path := IncludeTrailingBackslash(SFTPSessionInfo.HomePath) + Path;

if Path = '' then
  raise EScError.Create(sePathNotAllowed);

if Path <> PathDelim then
  Path := ExcludeTrailingBackslash(Path);

end;

Code: Select all

procedure TSFTPDataMod.SFTPServerGetAbsolutePath(Sender: TObject;
 SFTPSessionInfo: TScSFTPSessionInfo; const Path: string;
 const Control: TScSFTPRealpathControl; ComposePath: TStringList;
 var AbsolutePath: string; var Error: TScSFTPError);
var
  FullPath: string;
  i: integer;
  allowcwd:boolean;
  useobj:TuserObj;
  _path:string;
begin
     _path:=Path;
     if _path = '.' then
        _path:= '/';
     if sender = nil then
        exit;
     try
     allowcwd:=false;
     if assigned(SFTPSessionInfo.Client.Data) then
        begin
             useobj:=TuserObj(SFTPSessionInfo.Client.Data);
             allowcwd:=useobj.AllowCWD;
        end;
  AbsolutePath := IncludeTrailingBackslash( TScSFTPServer(sender).GetCanonicalPath(SFTPSessionInfo, _path));
  for i := 0 to ComposePath.Count - 1 do
    AbsolutePath := IncludeTrailingBackslash(AbsolutePath) + ComposePath[i];
  if (not allowcwd) and (AbsolutePath <> '/') then
     begin
           InitError(Error, erPermissionDenied);
           exit;
     end;
  FullPath :=  TScSFTPServer(sender).GetFullPath(SFTPSessionInfo, AbsolutePath);
  if (Control <> rcStatAlways) or FileExists(FullPath) or DirectoryExists(FullPath) then
    InitError(Error, erOk)
  else
    InitError(Error, erNoSuchFile);

  for i := 1 to Length(AbsolutePath) do
    if (AbsolutePath[i] = '\')  then
      AbsolutePath[i] := '/';

    except
          on e:exception do
          InitError(Error, erPermissionDenied);

     end;
end; 

tcaduto12068
Posts: 74
Joined: Wed 17 Aug 2016 05:57

Re: Problems with SFTP server running on Linux (paths)

Post by tcaduto12068 » Mon 14 Jan 2019 20:03

Would you guys at Devart be able to take a look at this and get it working under Linux for the next release of SB?
As of right now it's pretty much broken under Linux.

It took me quite awhile to get the functions working.

tcaduto12068
Posts: 74
Joined: Wed 17 Aug 2016 05:57

Re: Problems with SFTP server running on Linux (paths)

Post by tcaduto12068 » Mon 14 Jan 2019 21:48

Hi,
Might also be nice if you guys could add a OnGetCanoniclePath even like you have for the OnGetAbsolutePath
then we could use the expandfilename function without having to mess with the source or create a custom class derived from the sftpserver class.

ViktorV
Devart Team
Posts: 2546
Joined: Wed 30 Jul 2014 07:16

Re: Problems with SFTP server running on Linux (paths)

Post by ViktorV » Tue 15 Jan 2019 10:20

Thank you for the interest to our product and your contribution in our product development. We will consider the possibility of fixed this behavior in the next release of SecureBridge.

tcaduto12068
Posts: 74
Joined: Wed 17 Aug 2016 05:57

Re: Problems with SFTP server running on Linux (paths)

Post by tcaduto12068 » Wed 16 Jan 2019 01:19

Thanks,
one other issue on Linux I have run into is:
I wanted to implement my own ServerGetFullPath and there is a OnServerGetFullPath, but the problem is it's not implemented with a default event like the others, I had to chance in the source code a bit to fully implement my own:

in function TScSFTPServer.GetFullPath(SFTPSessionInfo: TScSFTPSessionInfo; const Path: string): string;

there is this:

Code: Select all

  if Assigned(OnGetFullPath) then
      OnGetFullPath(Self, SFTPSessionInfo, result);
I changed it to:

Code: Select all

  if Assigned(OnGetFullPath) then
    begin
         result:=path;
         OnGetFullPath(Self, SFTPSessionInfo, result);
    end;
This was the only way I could implement my own function and use my custom GetCanonicalPath so it all works the same on windows or Linux with FPC/Lazarus.

Hopefully you guys understand what I was trying to do here, basically it just didn't work the same on Linux because of the GetCanonicalPath function.

So in addition to what I said in other posts it would be super nice if OnGetFullPath was implemented like the others as a default event so it could be completely replaced and tweaked.

tcaduto12068
Posts: 74
Joined: Wed 17 Aug 2016 05:57

Re: Problems with SFTP server running on Linux (paths)

Post by tcaduto12068 » Wed 16 Jan 2019 01:58

Just a fyi, here is the cross platform function I came up with, I am sure it sucks compared to what you guys could do, but here is is anyways:

Code: Select all

function _pathcanonicalize(path: string): string;
 var
  i:integer;
  drive:string;
begin
     Result := Path;
     if result = '.' then
       result:=DirectorySeparator;
     result:=ExpandFileName(result);
       for i := 1 to Length(Result) do
           if Result[i] = {$IFDEF MSWINDOWS}'/'{$ELSE}'\'{$ENDIF} then
       Result[i] := PathDelim;
       drive := ExtractFileDrive(result); // e.g: "C:"
       result:=StringReplace(result,drive,'',[rfIgnoreCase]);
       result:= IncludeTrailingBackslash(result);
end;

ViktorV
Devart Team
Posts: 2546
Joined: Wed 30 Jul 2014 07:16

Re: Problems with SFTP server running on Linux (paths)

Post by ViktorV » Thu 17 Jan 2019 11:46

Thank you for the feedback. Each client's opinion is very important for us. We hope that our product will be useful for you in the implementation of your projects.
If you have any questions during using our products, please don't hesitate to contact us - and we will try to help you solve them.

ViktorV
Devart Team
Posts: 2546
Joined: Wed 30 Jul 2014 07:16

Re: Problems with SFTP server running on Linux (paths)

Post by ViktorV » Fri 22 Feb 2019 12:00

We fixed this issue.
The new SecureBridge build has been released today. It is already available for download on our official website.
Please try to use this build build of SecureBridge and inform us about the results.

Post Reply