chown() mit PHP und Apache als Superuser?

Dieses Thema im Forum "Web-Programmierung" wurde erstellt von sevY, 17.08.2005.

  1. sevY

    sevY Thread Starter Gast

    Hi zusammen,

    ich habe mir ein kleines Adminpanel zum Anlegen von vhost, webalizer, temp_site gebaut.
    SysCP & Co waren mir zu oversized.

    Mein Problem:

    Ich möchte als UID ftpuser und als GID apache nehmen.
    PHP 5.0.4 (via APXS2 unter Apache2) führt das Kommando allerdings mit diesen Parametern nicht aus.

    Laut manual muss der ausführende Superuser sein. Der apache läuft als apache:apache

    Wie bekomme ich nun das ganze hin?



    Hier das Script:

    PHP:

    <?php 
    header
    ('Content-Type: text/html; charset=utf-8'); 
    require_once(
    'config.inc.php');
    ?>
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
    <html>
    <head>
    <meta http-equiv="content-type" content="text/html; charset=utf-8">
    <link rel="stylesheet" href="default.inc.css" type="text/css">
    <title>ROPEnetwork Setup Tool</title>
    </head>
    <body>

    <?php

    if(isset($_POST['setup']) && is_dir($webroot.'/'.$_POST['directory'])) {
        
    $base=$webroot.'/'.$_POST['directory'].'/'.$_POST['domain'];
        
        
        if(isset(
    $_POST['create_docroot'])) {
        
     
            
    mkdir($base,intval(0777,8)) or exit('Error while creating '.$base);
            
    chmod($base,intval(0774,8)) or exit('Error while changing mode for '.$base.' to 0774');
            
    chown($base,$uid) or exit('Error while changing owner of '.$base.' to '.$uid);
            
    chgrp($base,$gid) or exit('Error while changing group of '.$base.' to '.$gid);
       
      
            
    $folderset=array(array('htdocs',0774),array('logs',0070),array('session',0070),array('tmp',0070),array('cgi',0740),array('webalizer',0770),array('webalizer/'.$_POST['domain'],0770));
            foreach(
    $folderset as $part) {
                
    mkdir($base.'/'.$part[0],intval(0777,8)) or exit('Error while creating '.$base.'/'.$part[0]);
                
    chmod($base.'/'.$part[0],intval($part[1],8)) or exit('Error while changing mode for '.$base.' to 0774');
                
    chown($base.'/'.$part[0],$uid) or exit('Error while changing owner of '.$base.' to '.$uid);
                
    chgrp($base.'/'.$part[0],$gid)  or exit('Error while changing group of '.$base.' to '.$gid);
            }
        }
        
        if(isset(
    $_POST['create_html'])) {
            
    copy($html_tpl,$base.'/htdocs/index.html') or exit('Error while copying '.$html_tpl.' to '.$base.'/htdocs/index.html');
        }
        
        
        if(isset(
    $_POST['create_vhost'])) {
            
    file_put_contents($vhostdir.'/'.$_POST['domain'].'.conf',ereg_replace('{LOG}',$logdir,ereg_replace('{DOMAIN}',$_POST['domain'],ereg_replace('{BASE}',$base,file_get_contents($vhost_tpl))))) or exit('Error while writing Apache2 vHost to '.$vhostdir.'/'.$_POST['domain'].'.conf');
        }
        
        if(isset(
    $_POST['create_webalizer'])) {
            
    file_put_contents($webalizerdir.'/'.$_POST['domain'].'.webalizer',ereg_replace('{LOG}',$logdir,ereg_replace('{DOMAIN}',$_POST['domain'],ereg_replace('{BASE}',$base,file_get_contents($webalizer_tpl))))) or exit('Error while writing Webalizer Config to '.$webalizerdir.'/'.$_POST['domain'].'.webalizer');
        }

    }





    ?>
    <div class="main">
        <div class="content">
            <form action="<?php echo $_SERVER['PHP_SELF']; ?>" method="post">
                <input type="hidden" name="setup" value="1">
                <select class="singleline" name="directory">
                    <?php
                    
    foreach(scandir($webroot) as $directory) {
                        echo 
    '<option value="'.$directory.'">'.$directory.'</option>';
                    }
                    
    ?>
                </select><br>
                <input class="singleline" type="text" name="domain" value="domain.tld"><br>
                <input type="checkbox" name="create_docroot" checked="checked"> Create Docroot?<br>
                <input type="checkbox" name="create_vhost" checked="checked"> Create vHost?<br>
                <input type="checkbox" name="create_webalizer" checked="checked"> Create Webalizer?<br>
                <input type="checkbox" name="create_html" checked="checked"> Create HTML?<br>
                <input class="submit" type="submit" value="Setup"></form></div></div>
    </body>
    </html>

    Hier die Config
    PHP:
    <?php
    error_reporting
    (0); 
    $webroot='/var/www';
    $uid='ftpuser';
    $gid='apache';
    $html_tpl='default/default.tpl';
    $vhost_tpl='default/default.conf';
    $webalizer_tpl='default/default.webalizer';
    $vhostdir='/etc/apache2/vhosts.d';
    $webalizerdir='/etc/webalizer/vhosts';
    $logdir='/var/log/apache2';
    ?>
    Viele Grüße

    Yves
     
  2. Delmar

    Delmar MacUser Mitglied

    Beiträge:
    803
    Zustimmungen:
    1
    MacUser seit:
    28.09.2002
    Yves alter Haudegen,

    du formatierst ja immer noch so grauenhaft wie früher ... stimmt nicht, ist
    schon um einiges besser geworden.

    Zu Deinem Problem: Idealerweise müsstest Du dem User apache die Gruppe
    admin zuweisen, was natürlich nicht gerade dem Sicherheitsgedanken ent-
    spricht. Warum willst Du eigentlich die Verzeichnisse den verschiedenen Be-
    nutzern zuordnen - welcher Vorteil ergibt sich daraus?


    PS: Wohne jetzt in Hannover ... ist aber scheiße da, wie Du gesagt hast! :mad:
     
  3. one.nomad

    one.nomad MacUser Mitglied

    Beiträge:
    49
    Zustimmungen:
    0
    MacUser seit:
    16.08.2005
    Mh, also falls du nur usern noch zugriff auf die verzeichnisse geben willst, wie waere es mit Access Controll Lists? Muss natuerlich vom jeweiligen betriebssystem unterstuetzt werden, auf dem deine daten liegen (z.b. 10.4 kann es ja nun gluecklicherweise)
     
  4. dannycool

    dannycool MacUser Mitglied

    Beiträge:
    1.485
    Zustimmungen:
    34
    MacUser seit:
    02.02.2005
    Du kannst das eigentlich nicht in einer verantwortlich verwalteten PHP-Umgebung auf diese Weise machen.

    Die einzige Möglichkeit ist ein Daemon oder ein externes Programm, das vom PHP-Script mit den nötigen Rechten gestartet werden kann, um die Dateirechte umzusetzen. Dafür kannst Du z.B. ein C-Programm schreiben, das die Aufrufe ausführt, die ausführbare Datei root gehören lassen, und das suid-Flag setzen. Eine andere Alternative wäre, dem Apache-User sudo zu erlauben, natürlich nur für den einen Befehl den Du tatsächlich privilegiert ausführen musst. Denk aber immer dran: Je mehr ein PHP-Script Dein System administrieren kann, desto mehr kann es auch jemand, der eine Lücke darin (oder sonstwo in Deinem Webserver!) ausnutzt!
     
  5. maceis

    maceis MacUser Mitglied

    Beiträge:
    16.645
    Zustimmungen:
    596
    MacUser seit:
    24.09.2003
    Auah!
    Abgesehen davon glaube ich, dass das nicht genügt, weil
    Gruppe "admin" != "Superuser"
    Die Idee mit dem C oder c++ Wrapper ist gut und funktioniert vermutlich auch; bei dem sudo frage ich mich, wer das Passwort eingibt.
    Oder willst Du sudo ohne Passwort einsetzen (wieder auah!)
     
    Zuletzt bearbeitet: 21.08.2005
  6. sevY

    sevY Thread Starter Gast

    Hi,

    ich habe das Script gebaut, um "SysCP" like neue Kunden auf unserern Server einzurichten (das ganze ist seit gestern auf eine Art CRM ausgebaut…).
    Ich war und bin kein Fan von Confixx, Virtuoso, SysCP, Webmin & Co, da mir diese System teilweise zu komplex und auch zu unsicher sind.

    Nur ist es bei mittlerweile knapp mehr als 800 Domains m.E. nach höchste Zeit, mal eine Alternative zum manuelle einrichten per Shell zu finden.
    Bisher habe ich das immer mit Bash Scripts und einer Checkliste manuell gemacht… vHosts erstellt, FTP Accounts angelegt usw. …dauerte pro Neukunden gut und gerne 30 Minuten.
    Ich musste ja auch noch die ganzen Daten in das Formblatt für Neukunden einfügen… alá „Willkommen, hier sind Ihre Zugangsdaten, das sind die technischen Details Ihres Accounts“… und dann halt noch den ganzen Buchhaltungskram.

    Naja… SysCP usw. wollte ich trotzdem nicht… ich vertraue in der Hinsicht nur dem, was ich selbst geschrieben habe.

    Nur zur Technik… chown() und chgrp() Funktioniert ausschließlich als Superuser.
    Und Apache als Superuser laufen zu lassen… ich weiss nicht. Eventuell könnte man mit mod_suexec das PHP Script über FastCGI aufrufen… und eben nur diesem einen vHost entsprechend einen Superuser als suexecuser zukommen lassen.

    Warum die Sache mit den Gruppen? Ganz einfach… ich bin sehr pingelig was Rechtevergabe auf den Produktivsystemen angeht… ist es angedacht (auch aufgrund des chrooted laufenden Apache2), das jeder Neukunde auch einen eigenen User bekommt und entsprechend das vHost dann damit betrieben wird.
    Ist mittlerweile auch ein muss, da wir TCL, Ruby, Python usw. anbieten… und es da keine OpenBaseDirRestrictions wie bei PHP gibt.

    Nun… warum PHP? Ich habe in letzter Zeit viel mit PHP gemacht… es sind erstaunliche Dinge möglich, wenn man mal in die tiefen des ZendCore abtaucht… Semaphoren, Session Wrapper für Servlets usw. … und da dachte ich „nimm' doch PHP bevor Du die Java-Wemmse rausholst“.
    In C bin ich (noch) nicht so fit, das ich sowas „sicher“ schreiben kann.

    Aber vielleicht baue ich das ganze auch auf Commandline Ebene… das PHP Script bekommt dann eine Shebang-Line und ist unabhängig vom Apache.


    Liebe Grüße
    Yves
     
  7. sevY

    sevY Thread Starter Gast

    Achso… das System ist Gentoo Linux 2005.0 Hardened, es laufen Apache2 und PHP5 (noch als APXS2 Modul… demnächst als Fast-CGI Executable)… PureFTP, Postfix, Cyrus (Aggretator Cluster), MySQL und PostgreSQL.
    Aufgrund dieser „nicht-standard“ Ausstattung möchte ich gerne selbst ein Admintool entwickeln… eben um alles nach „eigenem Ermessen“ verwalten zu können… und Dinge, die mir zu heikel sind, nur in Form eines Befehls in einer DB ablegen und gesondert freischalten… usw.
     
  8. dannycool

    dannycool MacUser Mitglied

    Beiträge:
    1.485
    Zustimmungen:
    34
    MacUser seit:
    02.02.2005
    Ja. Auf dem Mac gibt es diese Gruppe und Mitglieder sind Administratoren. Das heißt aber auch nur, dass man sudo benutzen darf um root zu werden. Man ist es nicht automatisch ständig.

    Das funktioniert unter Garantie, ist aber sehr aufwändig.

    Bei sudo ohne Passwort kann man immernoch sagen, dass man nur die entsprechenden chown- und chgrp-Aufrufe machen darf. Jemanden in sudoers einzutragen, heißt nicht automatisch, dass der alles darf. Man kann das auch für ein Programm einzeln (z.B. eben chown) machen, und dann weiters noch die erlaubten Argumente für dieses Programm festlegen.

    Optimal ist das trotzdem nicht, aber man muss kein C programmieren können. Scriptsprachen eignen sich für so einen Wrapper ja nicht so toll.
     
  9. dannycool

    dannycool MacUser Mitglied

    Beiträge:
    1.485
    Zustimmungen:
    34
    MacUser seit:
    02.02.2005
    Noch eine kleine Ergänzung: Sämtliche solchen Interfaces, die ich bisher näher betrachtet habe (hauptsächlich in kommerziellen Produkten) haben das über einen Daemon gelöst, der über RPC die entsprechenden Aktionen (und nur die) ausgeführt hat. Das ist aber natürlich mit Abstand das aufwändigste.

    Was ich selbst machen würde kann ich leider nicht sagen, da ich Linux am liebsten per bash bediene. ;)
     
  10. maceis

    maceis MacUser Mitglied

    Beiträge:
    16.645
    Zustimmungen:
    596
    MacUser seit:
    24.09.2003
    Nein, eigentlich kann man das sehr flach halten.
    Man kann ja die Kommandos in einer beliebigen Skriptsprache schreiben und in C/c++ nur einen Wrapper erstellen, der dann das SUID Bit erhält.
    Der Wrapper ruft dann das Arbeitsskript auf und zwar mit entsprechenden Rechten.
    Ist relativ harmlos.


    Das ist mir bekannt, aber auch hier würde ich nicht chgrp etc. pauschal "freischalten", sondern mit einem Programm arbeiten, dass eben die erforderlichen Aufrufe enthält.
    Bin aber trotzdem nicht so begeistert von diesem Ansatz, weil es eine zusätzliche Ebene einführt, ohne das Ausgangsproblem zu lösen.

    Wenn man das in einer Scriptsprache umsetzen würde, könnte man auf einen Wrapper komplett verzichten.
    Das Problem ist, dass man dann die Skriptausführung mit SUID Bit aktivieren muss (ist ne sysctl Variable, IIRC), dann allerdings könnte auch das "Arbeitsskript" direkt das SUID Bit erhalten.

    Zusammenfassung:
    Nach meiner Ansicht ist die beste und einfachste Lösung ein kompiliertes Programm (binary), welches nur die Aufgabe hat, das Skript in dem (ausschließlich) die erforderlichen Kommandos stehen, mit ausreichenden Rechten aufzurufen.
    C oder c++ bieten sich da an, theoretisch würde das aber (wennn es denn unter Mac OS X wäre) sogar mit einem kompilierten AppleSkript funktionieren.
     
Die Seite wird geladen...