Alexander (HH): /Sicherheit: Untaint my Vars und per sudo Ausführen

Beitrag lesen

Moin Moin!

Für einen trivialen Daemon kommst Du mit 10 Zeilen Shell-Script aus. Siehe auch the djb way.

Muss ich mir mal im Detail anschauen, denn das Symlinken und die Arbeit mit relativen Pfaden wollen geübt sein.

Du brauchst weder relative Pfade noch Symlinks für die daemontools.

(BTW: Wie bekomme ich denn unter Unix/Linux den kompletten Pfad eines ausgeführten Programms? $0 oder argv[0] in C enthalten nur den Namen, wie er auf der Konsole eingegeben wird.)

Im Zweifel gar nicht.

Viele, aber nicht alle Unixe haben ein /proc-Dateisystem, von denen haben wiederum einige den Symlink /proc/self, andere nicht, dort mußt Du Dir die PID über getpid() besorgen. Schließlich findest Du in /proc/self bzw. /proc/$PID gelegentlich einen Symlink, der auf das zum Prozess gehörende Executable zeigt. Unter Linux heißt der Symlink exe, andere Unixe haben andere Namen. /proc muß übrigens nicht zwingend gemountet sein, und andere Unixe verstecken diese Information auch gerne mal an anderer Stelle.

Mac OS X z.B. scheint kein /proc zu kennen.

Mag wohl sein, bei mir gammelt kein angefressenes Obst rum. Ein Unix-Derivat auf Intel- oder AMD-Standard-Hardware kann man wesentlich billiger bekommen.

Übrigens: Rate mal, was folgendes Programm unter Linux ausspuckt. Und zwar egal, wie Du es aufrufst. Nicht mogeln! Erst mal aufschreiben, dann ausprobieren:

#!/usr/bin/perl

print readlink("/proc/self/exe"),"\n";


>   
> Wenn ich [readlink](http://perldoc.perl.org/functions/exec.html) richtig verstanden habe, gibt die Funktion das Ziel eines Symlinks zurück. Jetzt wäre nur noch die Frage, welches die zum Prozess gehörende Executable ist. Nachdem ich gerade ein wenig mit ps(1) herum gespielt habe, teilt #! in der ersten Zeile einer ausführbaren Datei der Shell mit: Nimm den folgenden Pfad bis zum Zeilenende als Interpreter dieser Datei. Genau das zeigt ps auch an.  
  
Exakt. /proc/self/exe nützt dir exakt gar nichts, wenn Du dich mit einem Interpreter rumschlägst. Du findest immer nur den Interpreter, nicht das Script.  
  

> > Du suchst den absoluten Pfad des aktuellen Scripts, und der ist nicht immer leicht zu ermitteln. [FindBin](http://search.cpan.org/perldoc?FindBin) schafft das oft, aber nicht immer. Einige Probleme sind in der Doku beschrieben, aber wohl nicht alle.  
>   
> ~~~perl

#!/usr/bin/perl -Tw  

>   
> use strict;  
> use FindBin;  
>   
> print $FindBin::Script, ' ', $FindBin::RealScript, "\n"

$ ./f
f f
$ $PWD/f
f f

Sollte da nicht etwas Anderes herauskommen?

: $Script - basename of script from which perl was invoked

Ändere das Script mal in:

  
#!/usr/bin/perl -Tw  
  
use strict;  
use FindBin;  
  
print "Script=$FindBin::Script Bin=$FindBin::Bin RealScript=$FindBin::RealScript RealBin=$FindBin::RealBin\n";  

Script in /tmp/f

(cd ; ln -s /tmp/f xyz)
(cd ; ./xyz )
$HOME/xyz
(cd /tmp ; ./f)
/tmp/f

Was passiert, wenn exec() fehlschlägt?

Sofern -T nicht zuschlägt, läuft das Programm weiter. In diesem Falle wäre also exec @args or die $! die richtige Wahl – „beende dich oder sterbe“.

Richtig! Wobei Du da auch ausnahmsweise das "or" gegen ein Semikolon tauschen kannst.

In Deinem kleinen Script rennst Du in ...

my $socket = new IO::Socket::INET (
        Listen          => 5,
        LocalPort       => $port,
        Proto           => 'tcp',
        Reuse           => 1,
        );
die $! unless $socket;


> >   
> > ... rein. Und das fällt unter Linux wegen $port<1024 fürchterlich auf die Nase. Glück gehabt. ;-)  
>   
> Und Windows interessiert mich an dieser Stelle auch gar nicht.  
  
Hab ich was von Windows gesagt?  
  

> > Wieso schreibst Du eigentlich `die $! unless $socket`{:.language-perl}? Erstens ist das nicht das gewohnte Pattern `... or die`{:.language-perl}, zweitens fehlt da noch Text.  
>   
> Was denn für Text?  
  
Sowas wie "Could not open socket: ". Sonst bekommst Du sowas:  
  
  
/tmp>cat foo  
~~~perl
#!/usr/bin/perl -w  
use strict;  
use warnings;  
use IO::Socket;  
  
my $sock=IO::Socket::INET->new(  
        Proto => 'tcp',  
        Reuse => 1,  
        Listen => 1,  
        LocalPort => 80,  
) or die $!;  

/tmp>chmod +x foo

/tmp>./foo
Permission denied at ./foo line 6.

Und die Indirect Object Notation $object=new CLASSNAME (@args); sollte man sich auch verkneifen, weil die nicht immer eindeutig ist und daher mehr Arbeit beim Parsen macht.

Wie jetzt?

  
# veraltet, indirekt  
my $socket=new IO::Socket::INET (...);  
  
# gut, direkt  
my $socket=IO::Socket::INET->new(...);  

Siehe auch: Perl Best Practices, perlobj/Indirect Object Syntax: "The other way to invoke a method is by using the so-called "indirect object" notation. This syntax was available in Perl 4 long before objects were introduced" und "The -> notation suffers from neither of these disturbing ambiguities, so we recommend you use it exclusively."

Alexander

--
Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so".