Recent

Author Topic: [Solved] Cannot open the default browser under Linux  (Read 5263 times)

devEric69

  • Hero Member
  • *****
  • Posts: 648
[Solved] Cannot open the default browser under Linux
« on: October 21, 2020, 12:16:30 pm »
Hello,

I'm trying to launch my default browser under Linux. When Icode OpenURL('https://www.noip.com/');, nothing happens.
But, if I launch the command xdg-open https://www.noip.com/ & in the terminal, Firefox opens - without problem - on the requested page \ URL.
So, i've then tested:

Code: Pascal  [Select][+][-]
  1. procedure TWebUtils.OpenURLinDefaultBrowser;
  2. var
  3.   oProcess: TProcess;
  4.   sCmd: string;
  5.   i, j, k: integer;
  6. begin
  7.   oProcess:= TProcess.Create(nil);
  8.   try
  9.     oProcess.Options:= [poWaitOnExit, poNoConsole];
  10.     sCmd:= '/usr/bin/xdg-open https://www.noip.com/ &';
  11.     oProcess.CommandLine:= sCmd;
  12.     oProcess.Execute;
  13.     i:= oProcess.ExitStatus;    // returns 1
  14.     j:= oProcess.ExitCode;      // returns 0
  15.     k:= oProcess.ProcessID;     // <== returns 36500, but 'ps -ef', in a terminal, doesn't report the existence of such a process??! Htop neither.
  16.     oProcess.CloseOutput;
  17.   finally
  18.     oProcess.Free;
  19.   end;
  20. end;  

I've found that xdg-open has a practice verbose debugging mode...:
Code: Bash  [Select][+][-]
  1. bash -x /usr/bin/xdg-open https://www.noip.com/
  2. + check_common_commands https://www.noip.com/
  3. + '[' 1 -gt 0 ']'
  4. + parm=https://www.noip.com/
  5. + shift
  6. + case "$parm" in
  7. + '[' 0 -gt 0 ']'
  8. + '[' -z '' ']'
  9. + unset XDG_UTILS_DEBUG_LEVEL
  10. + '[' 0 -lt 1 ']'
  11. + xdg_redirect_output=' > /dev/null 2> /dev/null'
  12. + '[' xhttps://www.noip.com/ '!=' x ']'
  13. + url=
  14. + '[' 1 -gt 0 ']'
  15. + parm=https://www.noip.com/
  16. + shift
  17. + case "$parm" in
  18. + '[' -n '' ']'
  19. + url=https://www.noip.com/
  20. + '[' 0 -gt 0 ']'
  21. + '[' -z https://www.noip.com/ ']'
  22. + detectDE
  23. + unset GREP_OPTIONS
  24. + '[' -n ubuntu:GNOME ']'
  25. + case "${XDG_CURRENT_DESKTOP}" in
  26. + '[' x = x ']'
  27. + '[' x '!=' x ']'
  28. + '[' xthis-is-deprecated '!=' x ']'
  29. + DE=gnome
  30. + '[' xgnome = x ']'
  31. + '[' xgnome = x ']'
  32. + '[' xgnome = xgnome ']'
  33. + which gnome-default-applications-properties
  34. + DE=gnome3
  35. + '[' -f /run/user/1000/flatpak-info ']'
  36. + '[' xgnome3 = x ']'
  37. + DEBUG 2 'Selected DE gnome3'
  38. + '[' -z '' ']'
  39. + return 0
  40. + case "${BROWSER}" in
  41. + case "$DE" in
  42. + open_gnome3 https://www.noip.com/
  43. + gio help open
  44. + gio open https://www.noip.com/
  45. + '[' 0 -eq 0 ']'
  46. + exit_success
  47. + '[' 0 -gt 0 ']'
  48. + exit 0
...but I can't run it from a TProcess instance either :( .

Does anyone have an idea, a track, to understand why I can't do the same thing with TProcess?
« Last Edit: October 23, 2020, 09:47:24 am by devEric69 »
use: Linux 64 bits (Ubuntu 20.04 LTS).
Lazarus version: 2.0.4 (svn revision: 62502M) compiled with fpc 3.0.4 - fpDebug \ Dwarf3.

Cyrax

  • Hero Member
  • *****
  • Posts: 836
Re: Cannot open the default browser under Linux
« Reply #1 on: October 21, 2020, 01:09:12 pm »
Rather than using TProcess.CommandLine directly, you should use TProcess.Parameters. Also do not use "&", only a shell program understands its internally.

trev

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 2020
  • Former Delphi 1-7, 10.2 user
Re: Cannot open the default browser under Linux
« Reply #2 on: October 21, 2020, 01:11:40 pm »
I'm trying to launch my default browser under Linux. When Icode OpenURL('https://www.noip.com/');, nothing happens.

This works for me in Ubuntu 18.04 LTS and now 20.04 LTS:

Code: Pascal  [Select][+][-]
  1. procedure TForm2_About.LicLabel2Click(Sender: TObject);
  2. begin
  3.   OpenURL('https://unlicense.org/');
  4. end;
  5.  

firing up Firefox and taking me to unlicense.org.

marcov

  • Administrator
  • Hero Member
  • *
  • Posts: 11352
  • FPC developer.
Re: Cannot open the default browser under Linux
« Reply #3 on: October 21, 2020, 01:50:12 pm »
Your way of execution assumes that xdg-open is a binary, and not a script.


devEric69

  • Hero Member
  • *****
  • Posts: 648
Re: Cannot open the default browser under Linux
« Reply #4 on: October 21, 2020, 03:32:04 pm »
Quote
This works for me in Ubuntu 18.04 LTS and now 20.04 LTS

Okay, thank you. I'm investigating on my computer...
use: Linux 64 bits (Ubuntu 20.04 LTS).
Lazarus version: 2.0.4 (svn revision: 62502M) compiled with fpc 3.0.4 - fpDebug \ Dwarf3.

dogriz

  • Full Member
  • ***
  • Posts: 126
Re: Cannot open the default browser under Linux
« Reply #5 on: October 22, 2020, 07:54:49 am »
Your way of execution assumes that xdg-open is a binary, and not a script.
Why does that matter?
FPC 3.2.2
Lazarus 2.2.4
Debian x86_64, arm

PascalDragon

  • Hero Member
  • *****
  • Posts: 5444
  • Compiler Developer
Re: Cannot open the default browser under Linux
« Reply #6 on: October 22, 2020, 09:20:23 am »
Your way of execution assumes that xdg-open is a binary, and not a script.
Why does that matter?

Scripts are executed by a shell. It is the one that interprets the shebang (#!) at the start to determine the correct interpreter.
TProcess however uses fork/exec and thus the kernel to start binaries and the kernel itself does not handle scripts. Thus you need to start a shell and pass it the command to ensure that it is executed.

Note: in theory it would be possible to set up the Linux kernel to handle this using the binfmt_misc functionality, but that is not done by default, thus you can't rely on it.

MarkMLl

  • Hero Member
  • *****
  • Posts: 6647
Re: Cannot open the default browser under Linux
« Reply #7 on: October 22, 2020, 10:02:26 am »
Scripts are executed by a shell. It is the one that interprets the shebang (#!) at the start to determine the correct interpreter.
TProcess however uses fork/exec and thus the kernel to start binaries and the kernel itself does not handle scripts. Thus you need to start a shell and pass it the command to ensure that it is executed.

The kernel most definitely used to, and I have no reason to believe that this has changed: i.e. the shebang is specifically processed by code in the Linux kernel rather than relying on a shell, which is different from some other unix implementations.

However I had an odd situation a couple of weeks ago (please note that I'm working from memory here) where I found that RunCommand() etc. wouldn't execute a script under certain conditions (I think it was while being debugged), but the program concerned is doing some very odd things with POSIX capabilities etc.:

Code: [Select]
(* If the file is executable then assume that this is a script or program that  *)
(* checks the content of the file of interest, and if it fails to return a zero *)
(* result return false. Otherwise assume that the name is that of the file of   *)
(* interest and return false if the age is greater than was specified on the    *)
(* command line. ExecuteProcess() might misbehave under gdbserver, if in doubt  *)
(* use "old school" debugging techniques.                                       *)

    if fpStat(mon[i].name, buff) <> 0 then (* Probably same as FileExists() above *)
      exit(false);
    if buff.mode and &001 = &001 then begin (* Executable by "other"            *)
      try
        age := ExecuteProcess(mon[i].name, IntToStr(mon[i].mins))
      except
        age := $ffff
      end;
      if age <> 0 then                  (* Visible for debugging                *)
        exit(false)
      else
        smallest := 2                   (* See comment on result/sideffect below *)
    end else begin

(* There's a misnomer here that always catches me out: this returns a timestamp *)
(* rather than an age (relative timestamp).                                     *)

      age := FileAge(mon[i].name);      (* Visible for debugging                *)
      scratch := DateTimeToStr(FileDateTodateTime(age));
      age := Round((UTC_Now() - FileDateTodateTime(age)) * MinsPerDay);
      if age > mon[i].mins then
        exit(false)
    end
  end;

The parameter mon[ i].name is *directly* from the command line, and in this particular case is normally a Perl script. Works just fine.

Code: [Select]
#!/usr/bin/perl

$MAINLOG = '/var/log/exim4/mainlog';
$MAINLOG1 = $MAINLOG . '.1';            # Optional "last" logfile
$LIMIT = 90;
...

This has definitely been the case since approximately the 2.2 kernel, which I dived into because somebody (on a private conferencing system) had made the same assertion in a somewhat less pleasant way. I don't know what the original rationale was but I'd speculate that somebody wanted something like to be able to write init in either Perl or as a binary. However these days it makes since since it ensures that POSIX capabilities and other EAs relating to e.g. SELinux can be applied strictly to a single script, rather than having a specially tailored shell which could be abused.

MarkMLl
« Last Edit: October 22, 2020, 11:01:40 am by MarkMLl »
MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

PascalDragon

  • Hero Member
  • *****
  • Posts: 5444
  • Compiler Developer
Re: Cannot open the default browser under Linux
« Reply #8 on: October 22, 2020, 01:36:20 pm »
Scripts are executed by a shell. It is the one that interprets the shebang (#!) at the start to determine the correct interpreter.
TProcess however uses fork/exec and thus the kernel to start binaries and the kernel itself does not handle scripts. Thus you need to start a shell and pass it the command to ensure that it is executed.

The kernel most definitely used to, and I have no reason to believe that this has changed: i.e. the shebang is specifically processed by code in the Linux kernel rather than relying on a shell, which is different from some other unix implementations.

Indeed you're right: The Linux kernel initializes a binfmt loader for script files by default.

This might not work on every *nix system however as POSIX states this about the exec* family of calls:

Quote
Historically, there have been two ways that implementations can exec shell scripts.

One common historical implementation is that the execl(), execv(), execle(), and execve() functions return an [ENOEXEC] error for any file not recognizable as executable, including a shell script. When the execlp() and execvp() functions encounter such a file, they assume the file to be a shell script and invoke a known command interpreter to interpret such files. This is now required by POSIX.1-2017. These implementations of execvp() and execlp() only give the [ENOEXEC] error in the rare case of a problem with the command interpreter's executable file. Because of these implementations, the [ENOEXEC] error is not mentioned for execlp() or execvp(), although implementations can still give it.

Another way that some historical implementations handle shell scripts is by recognizing the first two bytes of the file as the character string "#!" and using the remainder of the first line of the file as the name of the command interpreter to execute.

TProcess uses either execve or execv, but never exec*p, thus it's not cross platform to assume that TProcess can indeed start a shell script.

MarkMLl

  • Hero Member
  • *****
  • Posts: 6647
Re: Cannot open the default browser under Linux
« Reply #9 on: October 22, 2020, 01:52:56 pm »
This might not work on every *nix system however as POSIX states this about the exec* family of calls:

Very much agreed. I'm not really in a position to look at e.g. Solaris at the moment, much as I'd like to.

I suspect though that things like POSIX capabilities would be a major incentive for a kernel to handle the shebang etc. internally, since generally speaking anything that moves a file to a new inode will- by design- lose the EAs that implement them hence the capabilities will need to be reapplied by a privileged user. I don't know whether an equivalently-robust alternative could be implemented if the kernel didn't at least read the EAs of the file to be executed.

I'm not sure which way this argues, but I spotted something on StackOverflow recently where it was being asked why one of the major distreaux (possibly Red Hat) mandated that shebang lines like

#!/bin/sh -x

should be avoided, instead using

#!/bin/sh

set -x


and so on. My assumption is that that's in recognition of the fact that it's normally the kernel that parses the shebang and that the parser might have limitations e.g. in the line length it's prepared to accept.

MarkMLl

MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

devEric69

  • Hero Member
  • *****
  • Posts: 648
Re: Cannot open the default browser under Linux
« Reply #10 on: October 22, 2020, 09:36:25 pm »
I finally found the reason, which is due to the rights policy under Linux. I run a Lazarus as 'root', to open Firefox in a 'user01' session:

Code: Text  [Select][+][-]
  1. Initialization output:
  2. Running Firefox as root in a regular user's session is not supported.  ($XAUTHORITY is /run/user/1000/gdm/Xauthority which is owned by user01.)
  3. Running Firefox as root in a regular user's session is not supported.  ($XAUTHORITY is /run/user/1000/gdm/Xauthority which is owned by user01.)
  4. Running Firefox as root in a regular user's session is not supported.  ($XAUTHORITY is /run/user/1000/gdm/Xauthority which is owned by user01.)
  5. /usr/bin/xdg-open: 869: iceweasel: not found
  6. /usr/bin/xdg-open: 869: seamonkey: not found
  7. /usr/bin/xdg-open: 869: mozilla: not found
  8. /usr/bin/xdg-open: 869: epiphany: not found
  9. /usr/bin/xdg-open: 869: konqueror: not found
  10. /usr/bin/xdg-open: 869: chromium: not found
  11. /usr/bin/xdg-open: 869: chromium-browser: not found
  12. /usr/bin/xdg-open: 869: google-chrome: not found
  13. /usr/bin/xdg-open: 869: www-browser: not found
  14. /usr/bin/xdg-open: 869: links2: not found
  15. /usr/bin/xdg-open: 869: elinks: not found
  16. /usr/bin/xdg-open: 869: links: not found
  17. /usr/bin/xdg-open: 869: lynx: not found
  18. /usr/bin/xdg-open: 869: w3m: not found
  19. xdg-open: no method available for opening 'https://unlicense.org/''

In such a case, is there a way to code, with Lazarus, in the program, a workaround to this kind of problem :-\ ?
use: Linux 64 bits (Ubuntu 20.04 LTS).
Lazarus version: 2.0.4 (svn revision: 62502M) compiled with fpc 3.0.4 - fpDebug \ Dwarf3.

Bart

  • Hero Member
  • *****
  • Posts: 5265
    • Bart en Mariska's Webstek
Re: Cannot open the default browser under Linux
« Reply #11 on: October 22, 2020, 09:50:36 pm »
I finally found the reason, which is due to the rights policy under Linux. I run a Lazarus as 'root',

Why?
I can't think of a reason why you should do that.

Bart

devEric69

  • Hero Member
  • *****
  • Posts: 648
Re: Cannot open the default browser under Linux
« Reply #12 on: October 22, 2020, 09:58:57 pm »
Indeed. No serious or legitimate reason  ;D .

But out of curiosity, there would be an imaginable and codable "strategy" :D ?
use: Linux 64 bits (Ubuntu 20.04 LTS).
Lazarus version: 2.0.4 (svn revision: 62502M) compiled with fpc 3.0.4 - fpDebug \ Dwarf3.

MarkMLl

  • Hero Member
  • *****
  • Posts: 6647
Re: Cannot open the default browser under Linux
« Reply #13 on: October 22, 2020, 10:21:49 pm »
In such a case, is there a way to code, with Lazarus, in the program, a workaround to this kind of problem :-\ ?

Don't run as root, you're a disaster waiting to happen. xdgopen is quite correctly set up to not run something as complex as a browser with elevated rights, and you should be applying the same philosophy to the Lazarus IDE.

If your program needs a specific right over and above those held by ordinary users, then you should be using POSIX capabilities. And what's more if at all possible you should be exploiting the extra capability and then releasing it before starting the GUI part of your program, so that when complex stuff starts there's less chance of damage if something dodgy or malicious turns out to be buried in a library. **

And while gdb has problems debugging that, gdbserver works perfectly well except- as I noted earlier- when trying to run something with a shebang (see PascalDragon's comments for the probable reason).

** Same philosophy as a setuid program, which you'll find is fundamentally incompatible with some widget sets for security reasons.

MarkMLl
MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

devEric69

  • Hero Member
  • *****
  • Posts: 648
Re: Cannot open the default browser under Linux
« Reply #14 on: October 23, 2020, 09:46:59 am »
Quote
Don't run as root, you're a disaster waiting to happen.

In a certain way, yes: indeed, I'm not exempt from forgetting code that would (conditionally) bypass the security layer during development, and that I'll forget to remove in the release >:D . And without help or leads from some other people, I am unable to find such a code - by myself - to bypass the xdg-open's security.

Quote
If your program needs a specific right over and above those held by ordinary users, then you should be using POSIX capabilities.

I am 'root' in development only. I always test afterwards, regularly, the software as 'user01'.
Now, it's sure that the POSIX software layer which ensures the security, is clearly more aware than me, of the vulnerabilities that may exist, and is more consistent with its constant 'proprietary' + 'group' + 'others' strategy rights flags, to apply to the program when it is installed. In fact, I follow a "everything must be embedded with or near the binary" installation strategy, thanks to AppImage. It's my assumption, that hard disk space is no more the limiting factor, for a client GUI application.

Quote
And while gdb has problems debugging that, gdbserver works perfectly well except - as I noted earlier - when trying to run something with a shebang (see PascalDragon's comments for the probable reason).

That's good to know. I would switch from fpDebug to gdbServer temporarily in the future, when I'll suspect a specific right problem.

Thank you - all - for your contributions. I close this thread, concerning me.
« Last Edit: October 23, 2020, 09:57:38 am by devEric69 »
use: Linux 64 bits (Ubuntu 20.04 LTS).
Lazarus version: 2.0.4 (svn revision: 62502M) compiled with fpc 3.0.4 - fpDebug \ Dwarf3.

 

TinyPortal © 2005-2018