ubuntuusers.de

Perl Script für /etc/shadow (Rechte)

Status: Gelöst | Ubuntu-Version: Ubuntu 9.10 (Karmic Koala)
Antworten |

Darkraziel

Anmeldungsdatum:
14. September 2008

Beiträge: 69

Hallo Allerseits

Folgendes Szenario: Ich schreibe mittels Apache, PHP und Perl ein Webportal. Dieses soll mittels einer Login-Seite abgesichert werden welche die Usernamen und Passwörter mit der /etc/shadow vergleicht. Um diese Datei auszulesen scheint Perl jedoch nicht genügend Rechte zu besitzen. Kann ich irgendwie dem Programm perl erlauben, genau diese Datei (und nur diese Datei) zu lesen?

Gibt es irgend eine Möglichkeit ohne das ich gleich die Benutzerrechte der shadow runter schrauben muss? Weil es ist ja eigentlich ein Sicherheitsaspekt das diese nicht für alle lesbar ist.

Gruss

diesch Team-Icon

Avatar von diesch

Anmeldungsdatum:
18. Februar 2009

Beiträge: 5072

Wohnort: Brandenburg an der Havel

Ein Webportal, das /etc/shadow für die Authentifizierung verwendet, klingt für mich nach keiner guten Idee - die Wahrscheinlichkeit, dass das sicherheitstechnisch eine Katastrophe wird, ist ziemlich hoch.

Warum legst du nicht eine eigene Datenbank für die Nutzer des Web-Portals an?

Darkraziel

(Themenstarter)

Anmeldungsdatum:
14. September 2008

Beiträge: 69

Eigentlich geht es mir darum, die Passwörter mit den Benutzerpasswörtern im System abzugleichen. Die Anzahl Benutzer wird sehr gering sein. Jeder Benutzer kriegt also seinen eigenen Benutzeraccount auf dem Server, dazu einen home-Ordner der per ssh übers Internet erreichbar sein wird. Die Authentifizierung im Portal würde natürlich dann über ssl von statten gehen. Wie kann ich es sonnst erreichen das die Passwörter die gleichen bleiben?

Ich könnte natürlich auch versuchen, die shadow in einem cronjob mit der Datenbank abzugleichen, aber da fange ich auch wieder von Null an...

sdx23

Anmeldungsdatum:
19. August 2008

Beiträge: 154

Man könnte passwd durch ein Skript ersetzen, welches nicht nur passwd selbst aufruft, sondern auch eine von der Webapplikation verwendete Datenbank pflegt.

Gruß

Kinch

Anmeldungsdatum:
6. Oktober 2007

Beiträge: 1261

Setz auf deinem Skript ein Setuid-Bit und gibts dem Root.

Denk aber dran die Login-Seite mit https zu sichern.

Darkraziel

(Themenstarter)

Anmeldungsdatum:
14. September 2008

Beiträge: 69

Danke für deinen Vorschlag.

Ich arbeite nun an einem Script das die Datei ausliest und die relevanten Einträge in der Datenbank erstellt bzw. erneuert. Dies will ich dann als Cronjob einrichten damit es auch eine Passwortänderung kein grosses Problem darstellt.

Wie ich das Programm durch ein Script ersetzen kann weiss ich leider nicht, kannst Du mir da auf die Sprünge helfen? Das wäre natürlich noch einmal besser, adduser und passwd das Script anzuhängen, denn dann wäre der Cronjob nicht nötig und die Änderung würde sofort auch in der Datenbank ausgeführt.

EDIT-→ Danke Kinch, von diesem Bit habe ich noch nie gehört, ich werde das einmal versuchen. Es wäre wohl genau das was ich brauche. Nun muss ich nur noch raus kriegen wie ich dieses Bit setze...

Kinch

Anmeldungsdatum:
6. Oktober 2007

Beiträge: 1261

Darkraziel schrieb:

Danke Kinch, von diesem Bit habe ich noch nie gehört, ich werde das einmal versuchen. Es wäre wohl genau das was ich brauche. Nun muss ich nur noch raus kriegen wie ich dieses Bit setze...

Ich glaub

sudo chmod u+s <pfad>

Es wäre auch möglich, dass das aber nicht auf Skripte funktioniert. Zumindest bei Shell-Skripten klappt das (aus guten Gründen) nicht. Ich weiß nicht, wie da die Sicherheitspolitik von Linux im Detail ist. Notfalls müsstest du das ganze in einer kompilierbaren* Sprache nachschreiben. „su” oder „sudo” arbeiten übrigens auch mit dem Setuid-Bit.

Edit: Es gibt übrigens noch mehr Wege und Mechanismen. Setuid ist das einfachst, aber auch gefährlichste. Es gibt zum Beispiel PAM: http://de.wikipedia.org/wiki/Pluggable_Authentication_Modules oder Policykit http://de.wikipedia.org/wiki/Policykit

*Ja ja, jede Sprache ist kompilierbar.

Darkraziel

(Themenstarter)

Anmeldungsdatum:
14. September 2008

Beiträge: 69

Danke es hat geklappt! Nach analysieren der Apache log-Dateien hab ich gesehen das für dieses setuid noch etwas nachinstalliert werden muss. Nach "aptitude install perl-suid" hats dann funktioniert.

Danke euch allen.

Gruss

Darkraziel

(Themenstarter)

Anmeldungsdatum:
14. September 2008

Beiträge: 69

Nun muss ich den Thread doch noch einmal öffnen... Ich habe ein folgeproblem: wenn dieses Bit gesetzt ist wird scheinbar der Taint-Mode eingeschaltet, also das -T flag. Nun habe ich eine Separate Datei für das öffnen der MySQL Datenbank, habe ich mir im PHP so angeeignet und halt ins Perl übernommen. Wenn ich in meinem Script aber jetze diese Datei mittels require einbinden möchte kommt so etwas:

./DB/mysql.inc.pl did not return a true value at /var/www/WG-Portal/loginpruefen.pl line 13. mit do anstatt require funktioniert es, aber in diesem Fall bekomme ich keine Variablen übergeben bzw. sie sind leer.

kann mir noch einmal wer helfen?

EDIT-→ Zusätzlich habe ich noch das Problem das ich die Datei die das Setuid-Bit besitzt per require aufruffen möchte und so eine kleine Bibliothek an Befehlen die Rootrechte benötigen bereitstellen kann. Wenn ich diese Datei aber per require aufruffe scheint es so als ob die Rechte von der aufrufenden Datei übernommen werden. Wenn ich es mit do anstatt require versuche sind zwar die Fehler weg (Konnte Datei nicht öffnen wegen zu wenig Rechten), es wird aber auch nichts ausgegeben. Wenn ich die uid mit $< und $> ausgebe kriege ich 33 anstatt 0, auch wenn das Bit gesetzt ist.

Kinch

Anmeldungsdatum:
6. Oktober 2007

Beiträge: 1261

Darkraziel schrieb:

./DB/mysql.inc.pl did not return a true value at /var/www/WG-Portal/loginpruefen.pl line 13.

Hast du mal eine „1;” an Ende deines Moduls gepackt? Module bindet man übrigens sauberer mit „use” ein; ob sich das für ein kleines Skript aber lohnt, sei mal dahin gestellt.

Zusätzlich habe ich noch das Problem das ich die Datei die das Setuid-Bit besitzt per require aufruffen möchte und so eine kleine Bibliothek an Befehlen die Rootrechte benötigen bereitstellen kann.

Ja, das wird so auch nicht funktionieren. Die User-ID (UID) ist an den Prozess und nicht an die Dateien gebunden. Wenn der Prozess mit normalen Rechten gestartet wird, dann behält er auch die UID bei, ganz gleich welche Datei er noch nachlädt. Wenn du ein Modul das Root-Rechte hat schreiben willst, wirst du dich da wohl oder übel mit der Interprozess-Kommunikation rumschlagen müssen. Dein Skript wird einen neuen Prozess mit Root-Rechten starten müssen, der macht seine Arbeit und schick die Ergebnisse an den ersten Prozess zurück. Das ist nicht schwer; unter Linux gibts dafür eine Reihe von Kommunikationskanälen (Pipes, Sockets, shared Memory, Message Queues) aber du wirst dich da wohl erst reinarbeiten müssen.

Zum Thema Prozesse hat mir eigentlich das Buch sehr geholfen: http://unixguru.haas.homelinux.net/node387.html

Ist zwar alles C, lässt sich aber 1:1 auf Perl übetragen.

Darkraziel

(Themenstarter)

Anmeldungsdatum:
14. September 2008

Beiträge: 69

Danke für deine Antwort. Ich habe mich nun ein wenig eingelesen und etwas rumprobiert.

Als erstes habe ich es mit fork() versucht, die pid wird aber scheinbar auch geklont, brachte also keinen Erfolg. als nächstes habe ich es mit

1
open(HANDLER,  "|./parseshadow.pl")

versucht, dies würde funktionieren, aber nur so lange das -T im aufruffenden Script nicht ist. Da ich das ganze natürlich so sicher wie möglich gestalten möchte, sollte der -T Switch auch drinne sein.

Folgender Fehler wird mir mit -T ausgegeben, ich kann leider nicht viel damit anfangen... Insecure $ENV{PATH} while running with -T switch at /var/www/WG-Portal/loginpruefen.pl line 23.

Das zweite Problem ist, das ich mit dieser Pipe nicht wirklich rausgekriegt habe wie die beiden Prozesse komunizieren können.

Es gibt scheinbar so viele Möglichkeiten einen Prozess zu erstellen, jedoch sind wohl nicht alle geeignet für das setuid-Bit... Kannst Du mir da noch einen Stups in die richtige Richtung geben?

EDIT-→ Den Fehler konnte ich nun nach weiterem googeln beheben:

1
2
delete @ENV{qw(IFS CDPATH ENV BASH_ENV)};
$ENV{PATH} = ("/var/www/WG-Portal");

Wie ich mit den Pipes umzugehen habe was die kommunikation betrifft habe ich leider immer noch nicht raus gekriegt...

Danke für die Hilfe

Gruss

Darkraziel

(Themenstarter)

Anmeldungsdatum:
14. September 2008

Beiträge: 69

Ich konnte das Problem nun endlich lösen. Der Vollständigkeit halber schreibe ich das hier einmal nieder, vielleicht hilft es ja noch jemandem. Zuerst habe ich gedacht ich könnte es über den Befehl open2 lösen, ich musste jedoch feststellen das dieser mit dem mod_perl vom Apache nicht gut zusammenarbeitet.

Mit IPC::Run hat es dann geklapt. Im Folgenden sind die zwei Scripts in abgespeckter Verision wie sie bei mir Funktionieren.

Datei loginpruefen.pl:

 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
#!/usr/bin/perl -Tw

use CGI;
use IPC::Run qw(start finish);

use strict;

delete @ENV{qw(IFS CDPATH ENV BASH_ENV)};   # Make %ENV safer
$ENV{PATH} = ("/var/www/WG-Portal");

my $cgi = new CGI;
my %params = $cgi->Vars;

my $username = $params{'name'};
my $pwd = $params{'passwort'};

# ./parseshadow.pl in neuem Prozess starten
my @cmd = qw(./parseshadow.pl);
my $h = start \@cmd,
	'<pipe', \*IN,
	'>pipe', \*OUT,
	'2>pipe', \*ERR
	or die "@cmd returned $?";

print IN $username; #$username an parseshadow.pl übergeben
close IN;
my $zeile = <OUT>; #Die ausgegebene Zeile von parseshadow.pl in $zeile speichern
finish $h; #auf Prozessende warten (glaube ich jedenfalls)

######
#Verarbeitung der oben erhaltenen Zeile
######

Datei parseshadow.pl:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
#!/usr/bin/perl -Tw

use strict;

my $in;
$in .= $_ while(<STDIN>); #Alle Eingaben der anderen Datei in $in schreiben

# $in auf richtigkeit überprüfen und in $username schreiben
my $username;
if ($in =~ m/([a-zA-Z0-9_]*)/) {
 $username = $1;
}

#####
Verarbeitung von $username
#####

print $ergebnis #Dies wird von der anderen Datei abgefangen und nicht auf der Seite ausgegeben

Meine Scripte sind noch etwas länger, dies sind nur die Grundfunktionen die ich benutzt habe um ein Script in einen Separaten Prozess auszulagern.

Gruss

Antworten |