Microsoft Home Microsoft Home
 Resource-Kit für Microsoft FrontPage 2000-Servererweiterungen

Anhänge


Quellcode für das FrontPage Apache-Modul

Wenn die FrontPage 2000-Servererweiterungen für UNIX mit dem Apache-Webserver eingesetzt werden, wird zur Konfiguration empfohlen, für den Apache-Webserver einen Patch zu verwenden. Der Patch für den Apache-Webserver besteht aus zwei Änderungen:

  • Das FrontPage Apache-Modul mod_frontpage.c, das Remote-Anforderungen von den FrontPage-Clientprogrammen empfängt, die Sicherheit überprüft und die Anforderung an das Stub-Programm fpexe.c mit der SUID "root" weiterleitet.
  • Das Programm fpexe.c, das Dokumenterstellungsanforderungen vom FrontPage Apache-Modul übernimmt, eine zusätzliche Sicherheitsüberprüfung durchführt, die Benutzer-ID in den Besitzer der Website, in der die Dokumenterstellung erfolgt, ändert und dann die entsprechende CGI-Programmdatei der FrontPage-Servererweiterungen aufruft.

   

Der Quellcode für das FrontPage Apache-Modul wird hier zur Überprüfung dargestellt. Dieser Quellcode ist auch in den Downloadkits der FrontPage 2000-Servererweiterungen für UNIX enthalten und kann mit individuellen Builds des Apache-Webservers kompiliert werden.

--- ./src/include/httpd.h.orig    Mon Sep 21 15:12:17 1998
+++ ./src/include/httpd.h    Fri Sep 25 16:43:40 1998
@@ -719,7 +719,12 @@
 
     char *unparsed_uri;        /* nicht analysierter URI */
     char *uri;            /* Pfad des URI */
-    char *filename;
+    char *execfilename;        /* physischer Dateiname zum Programm */
+    char *filename;        /* logischer Dateiname zum Programm -- immer identisch
+                 * mit Ausnahme der FrontPage CGI-Programme, bei denen 
+                 * das CGI-Program ausgeführt wird in 
+                 * /usr/local/frontpage....
+                 */
     char *path_info;
     char *args;            /* gegebenenfalls QUERY_ARGS */
     struct stat finfo;        /* ST_MODE = Null, wenn keine Datei vorhanden */
--- ./src/main/http_request.c.orig    Mon Aug 10 20:09:46 1998
+++ ./src/main/http_request.c    Fri Sep 25 16:43:43 1998
@@ -187,6 +187,8 @@
     return OK;
     }
 
+    if (r->execfilename) path = r->execfilename;
+
 #ifdef WIN32
     /* Wenn Pfad = x:/, dann konvertieren in x:/., damit stat korrekt funktioniert */
     if(strlen(path) == 3 && path[1] == ':') {
@@ -459,6 +461,7 @@
             res = ap_parse_htaccess(&htaccess_conf, r, overrides_here,
                                  ap_pstrdup(r->pool, test_dirname),
                                  sconf->access_name);
+            if (r->execfilename) r->filename = r->execfilename;
             if (res)
                 return res;
 
--- ./src/main/util.c.orig    Thu Sep 17 11:56:08 1998
+++ ./src/main/util.c    Fri Sep 25 16:43:44 1998
@@ -582,7 +582,7 @@
     char *res;
 
     for (x = 0; (*line)[x]; x++) {
-    if (ap_isspace((*line)[x])) {
+    if (ap_isspace((*line)[x]) && ((*line)[x] & 0x80)==0) {
         pos = x;
         break;
     }
--- ./mod_frontpage.c.orig    Fri Sep 25 16:43:44 1998
+++ ./mod_frontpage.c    Fri Sep 25 16:43:45 1998
@@ -0,0 +1,777 @@
+/* ====================================================================
+ *
+ * Apache FrontPage-Modul.
+ *
+ * Copyright (c) 1996-1998 Microsoft Corporation -- Alle Rechte vorbehalten.
+ *
+ * KEINE GEWÄHRLEISTUNG. Microsoft schließt jede Gewährleistung für diesen Code und
+ * diese Informationen aus. Dieser Code und diese Informationen sowie jede dazugehörige  
+ * Dokumentation wird in der vorliegenden Form zur Verfügung ohne jegliche Gewährleistung, 
+ * weder direkt oder indirekt, einschließlich, aber nicht beschränkt auf, implizierte 
+ * Gerwährleistung oder Handelsüblichkeit, Eignung für einen bestimmten Zweck oder 
+ * Nichtverletzung. Das gesamte Risiko hinsichtlich Einsatz und Leistung dieses Codes und 
+ * dieser Informationen liegt beim Benutzer.
+ *
+ * KEINE HAFTUNG FÜR SCHÄDEN. Weder Microsoft noch seine Lieferanten sind
+ * für irgendwelche Schäden (einschließlich, aber nicht beschränkt auf, Schäden aus
+ * entgangenem Gewinn, Betriebsunterbrechung, Verlust von geschäftlichen Informationen
+ * oder andere finanzielle Einbußen) ersatzpflichtig, die sich aus der Verwendung oder 
+ * der Nichteinsetzbarkeit dieses Microsoft-Produkts ergeben, selbst wenn Microsoft von der 
+ * Möglichkeit eines solchen Schadens unterrichtet worden ist. Da einige Staaten/ 
+ * Rechtsordnungen den Ausschluss oder die Beschränkung der Gewährleistung für 
+ * Folgeschäden oder jeden anderen Schaden nicht zulassen, kann die obige Einschränkung 
+ * für Sie nicht gelten.
+ *
+ * Version 4.0.4.3
+ *
+ */
+
+
+/*
+ * Benutzerkonfigurierbare Elemente.  Die Servererweiterungen werden bei einer
+ * UID/GID kleiner als LOWEST_VALID_UID/LOWEST_VALID_GID nicht ausgeführt.
+ */
+
+#if defined(LINUX)
+#define LOWEST_VALID_UID 15
+#else
+#define LOWEST_VALID_UID 11
+#endif
+
+#if defined(HPUX) || defined(IRIX) || defined(SUNOS4)
+#define LOWEST_VALID_GID 20
+#else
+#if defined(SCO)
+#define LOWEST_VALID_GID 24
+#else
+#define LOWEST_VALID_GID 21   /* Solaris, AIX, Alpha, Bsdi, *BSD, usw. */
+#endif
+#endif
+
+/*
+ * Ende benutzerkonfigurierbare Elemente
+ */
+
+
+#include "httpd.h"
+#include "http_config.h"
+#include "http_conf_globals.h"
+
+#include <stdio.h>
+#include <sys/time.h>
+
+#if defined(UWARE7) || UW==700
+#define Vstat stat32
+#define Vlstat lstat32
+#else
+#define Vstat stat
+#define Vlstat lstat
+#endif 
+
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+#ifndef MAXPATHLEN
+#define MAXPATHLEN 1024
+#endif
+#if (MAXPATHLEN < 1024)
+#undef MAXPATHLEN
+#define MAXPATHLEN 1024
+#endif
+
+#define KEYLEN 128                  /* Muss Mehrfaches von sizeof(int) sein */
+
+static char gszKeyVal[KEYLEN+1];    /* Vom Modul verwendeter SUID-Schlüsselwert */
+static int  gfdKeyPipe[2];          /* Umleitung an Stub-CGI-Programm fpexe */
+static int  gbKeyPipeActive;        /* Umleitung an Stub-CGI-Programm fpexe aktiv */
+static int  gbEnabled;              /* TRUE, wenn SUID-Schema aktiviert */
+static int  giInitializeCount;      /* Aufruf von FrontPageInit bereits erfolgt */
+
+static const char* FP         =
+          "/usr/local/frontpage/version4.0";
+static const char* FPKEYDIR   =
+          "/usr/local/frontpage/version4.0/apache-fp";
+static const char* KEYFILEXOR =
+          "/usr/local/frontpage/version4.0/apache-fp/suidkey";
+static const char* KEYFILE    =
+          "/usr/local/frontpage/version4.0/apache-fp/suidkey.%d";
+static const char* FPSTUBDIR  =
+          "/usr/local/frontpage/version4.0/apache-fp/_vti_bin";
+static const char* FPSTUB     =
+          "/usr/local/frontpage/version4.0/apache-fp/_vti_bin/fpexe";
+static const char* SHTML      =
+          "/_vti_bin/shtml.exe";
+static const char* SHTML2     =
+          "/_vti_bin/shtml.dll";
+static const char* VTI_BIN    =
+          "/_vti_bin";
+static const char* FPCOUNT    =
+          "/_vti_bin/fpcount.exe";
+static const char* AUTHOR     =
+          "/_vti_bin/_vti_aut/author.exe" ;
+static const char* ADMIN      =
+          "/_vti_bin/_vti_adm/admin.exe" ;
+
+
+/*
+ * Speichern einer Fehlerbeschreibung in HTTPD-Fehlerprotokoll. Die Länge 
+ * der Formatzeichenfolge sollte auf 1800 Byte beschränkt sein.
+ */
+static void LogFrontPageError(
+    server_rec* s,
+    const char* szFormat,
+    const char* szFile,
+    const char* szRoutine,
+    int bIsDisabled)
+{
+    char szBuf[MAXPATHLEN * 2];
+    sprintf(szBuf, szFormat, szFile);
+    strcat(szBuf, " in ");
+    strcat(szBuf, szRoutine);
+    strcat(szBuf, ".");
+    if (bIsDisabled)
+    {
+        strcat(szBuf, "  Solange dieses Problem nicht behoben ist, wird der FrontPage-Sicherheitspatch deaktiviert und die FrontPage-Erweiterungen funktionieren möglicherweise nicht einwandfrei.");
+        gbEnabled = FALSE;            /* Deaktivierung doppelt sicher stellen  */
+    }
+    ap_log_error_old(szBuf, s);
+}
+
+
+/*
+ * Alte Schlüsseldateien löschen. Tritt beim Löschen der alten Schlüsseldateien 
+ * ein Fehler auf, wird das FrontPage SUID-Schema dennoch fortgesetzt.
+ */
+static void FrontPageCleanup(server_rec *s)
+{
+    DIR *d;
+    struct DIR_TYPE *dstruct;
+    int myPid = getpid();
+    
+    if (!(d = opendir(FPKEYDIR)))
+    {
+        /*
+         * Dieser Fall sollte selten vorkommen, da das Skript als root ausgeführt wird
+         * und auf das Verzeichnis Zugriff haben sollte. Alte Schlüsseldateien können
+         * ausgenutzt werden. Benutzerwiederherstellung: Prüfen von Existenz
+         * und ordnungsgemäßem Schutz (Besitzer = root, Berechtigungen = rwx--x--x)
+         * des Verzeichnisses, und dass keine alten Schlüsseldateien darin gespeichert
+         * sind (suidkey.*, wobei * eine nicht vorhandene PID bezeichnet).
+         */
+        LogFrontPageError(s, "Alte Schlüsseldateien können im Verzeichnis \"%-.1024s\" nicht gelöscht werden",
+                          FPKEYDIR, "FrontPageCleanup()", FALSE);
+        return;
+    }
+
+    while ((dstruct = readdir(d)))
+    {
+        if (strncmp("suidkey.", dstruct->d_name, 8) == 0)
+        {
+            /*
+             * Sicherstellen, dass die Schlüsseldatei eine PID besitzt - sonst
+             * ist sie bedeutungslos und kann ignoriert werden.
+             */
+            char* pEnd = 0;
+            int pid = strtol(dstruct->d_name + 8, &pEnd, 10);
+            if (!pEnd || *pEnd)
+                continue;
+
+            /*
+             * Sicherstellen, dass kein anderer Server diese Schlüsseldatei
+             * verwendet. Ist die Prozessgruppe nicht vorhanden, dann ist die Datei
+             * veraltet und kann gelöscht werden.
+             */
+            if (pid == myPid || kill(pid, 0) == -1)
+            {
+                char szBuf[MAXPATHLEN];
+                sprintf(szBuf, "%-.500s/%-.500s", FPKEYDIR, dstruct->d_name);
+                if (unlink(szBuf) == -1)
+                {
+                    /*
+                     * Dies sollte selten vorkommen, dass das Skript als
+                     * root ausgeführt wird und immer die Berechtigung zum Löschen der 
+                     * Datei haben sollte. Alte Schlüsseldateien können ausgenutzt werden.  
+                     * Benutzerwiederherstellung: Löschen der riskanten Datei.
+                     */
+                    LogFrontPageError(s, "Link zur alten Schlüsseldatei  \"%-.1024s\" kann nicht aufgehoben werden",
+                                      szBuf, "FrontPageCleanup()", FALSE);
+                }
+            }
+        }
+    }
+
+    closedir(d);
+}
+
+/*
+ * Prüfen, dass die aktuellen Berechtigung für die Ausführung des FrontPage
+ * fpexe SUID-Stub-Programms richtig sind. Sonst wird ein Fehler protokolliert
+ * und die Initialisierung beendet, und so das FrontPage SUID-Schema deaktiviert.
+ * Überprüft werden die Dateiberechtigungen (Besitzer = root, kein Schreibzugriff für
+ * group, other) und der Schreibschutz für das Verzeichnis.
+ */
+static int FrontPageCheckup(server_rec *s)
+{
+    struct stat fs;
+ 
+    if (geteuid() != 0)
+    {
+        /*
+         * Skript muss als root ausgeführt werden, damit das Sicherheits-
+         * schema einwandfrei funktioniert.
+         * Benutzerwiederherstellung: Server als root ausführen.
+         */
+        LogFrontPageError(s, "Keine Ausführung als root",
+                          0, "FrontPageCheckup()", TRUE);
+        return (FALSE);
+    }
+
+    if (Vlstat(FPKEYDIR, &fs) == -1          || /* stat für Schlüsselverz. unmöglich*/
+        fs.st_uid                           || /* root nicht Besitzer von Schlüsselverz. */
+        (fs.st_mode & (S_IRGRP | S_IROTH))  || /* Lesezugriff auf Schlüsselverz. */
+        (fs.st_mode & (S_IWGRP | S_IWOTH))  || /* Schreibzugriff auf Schlüsselverz. */
+        !(fs.st_mode & (S_IXGRP | S_IXOTH)) || /* Schlüsselverz. nicht ausführbar */
+        !(S_ISDIR(fs.st_mode)))
+    {
+        /*
+         * Benutzerwiederherstellung: Besitzer für Verzeichnis als root festlegen 
+         * mit Berechtigungen rwx--x--x. Beachten Sie, dass das Ausführungsbit für
+         * group und other benötigt wird, damit Programme, die nicht als
+         * root laufen, apache-fp/_vti_bin/fpexe ausführen können (obwohl ein
+         * anderer Benutzer als root das Verzeichnis nicht auflisten kann).
+         */
+        LogFrontPageError(s, "Falsche Berechtigungen für Schlüsselverzeichnis \"%-.1024s\"", 
+                                    FPKEYDIR, "FrontPageCheckup()", TRUE);
+        return (FALSE);
+    }
+
+    if (Vlstat(FPSTUBDIR, &fs) == -1         || /* stat für Stub-Verz. nicht möglich */
+        fs.st_uid                           || /* root nicht Besitzer des Stub-Verz. */
+        (fs.st_mode & (S_IWGRP | S_IWOTH))  || /* Lesezugriff auf Stub-Verz. */
+        (!S_ISDIR(fs.st_mode)))
+    {
+        /*
+         * Benutzerwiederherstellung: root als Besitzer des Verzeichnisses mit den 
+         * Berechtigungen r*x*-x*-x festlegen.
+         */
+        LogFrontPageError(s, "Falsche Berechtigungen für Stub-Verzeichnis \"%-.1024s\"", 
+                                    FPSTUBDIR, "FrontPageCheckup()", TRUE);
+        return (FALSE);
+    }
+
+    if (Vstat(FPSTUB, &fs) == -1             || /* stat für Stub-Progr. nicht möglich */
+        fs.st_uid                           || /* root nicht Besitzer des Stub-Progr. */
+        !(fs.st_mode & S_ISUID)             || /* Kein set-uid für Stub-Progr. */
+        (fs.st_mode & S_ISGID)              || /* set-gid für Stub-Progr. */
+        (fs.st_mode & (S_IWGRP | S_IWOTH))  || /* Schreibzugriff auf Stub-Progr. */
+        !(fs.st_mode & (S_IXGRP | S_IXOTH)))   /* Stub-Progr. nicht ausführbar */
+    {
+        /*
+         * Benutzerwiederherstellung: root als Besitzer des Stub-Programms mit
+         * den Berechtigungen r*s*-x*-x festlegen.
+         */
+        LogFrontPageError(s, "Falsche Berechtigungen für Stub-Programm \"%-.1024s\"", 
+                                    FPSTUB, "FrontPageCheckup()", TRUE);
+        return (FALSE);
+    }
+
+    return (TRUE);
+}
+
+
+/*
+ * Modulinitialisierung: Erstellen von suidkey-Datei und lokalem Wert.
+ * Bei irgendwelchen Fehlern wird die Schlüsseldatei nicht erstellt, und
+ * daher kann das SUID-Stub-Programm fpexe nicht ausgeführt werden.
+ */
+static void FrontPageInit(server_rec *s, pool *p)
+{
+    int fdPipe[2];
+    pid_t pid;
+    FILE *f;
+    struct stat fs;
+    int fd;
+    char szKeyFile[MAXPATHLEN];
+    int iRandom[5];
+    char* szRandom = (char*)iRandom;
+    struct timeval tp;
+    struct timezone tz;
+    
+    (void)p;   /* p wird nicht verwendet */
+
+    /*
+     * Standalone-Server rufen die Initialisierung zweimal auf: einmal in main() 
+     * und erneut in standalone_main(). Die vollständige Initialisierung des ersten 
+     * Aufrufs ist Zeitverschwendung. Ist Eile geboten, kann die alte Datei suidkey.pgrpid
+     * belassen werden.
+     */
+    if (ap_standalone && !giInitializeCount++)
+        return;
+
+    /*
+     * Deaktivieren des SUID-Schemas, bis Alles 100%-ig funktioniert.
+     */
+    gbEnabled = FALSE;
+    gbKeyPipeActive = FALSE;
+
+    /*
+     * Alte Schlüsseldateien vor dem Start löschen
+     */
+    FrontPageCleanup(s);
+    if (!FrontPageCheckup(s))
+        return;
+    
+    if (pipe(fdPipe) == -1)
+    {
+        /*
+         * Dieser Fall sollte selten vorkommen. Benutzerwiederherstellung: Stellen Sie fest,
+         * warum das System keine Pipe zuordnen kann (ist die Dateitabelle mit
+         * abgelaufenen Prozessen gefüllt?). Beheben Sie das Problem oder starten Sie den 
+         * Rechner neu, und versuchen Sie es dann erneut.
+         */
+        LogFrontPageError(s, "pipe() fehlgeschlagen", 0, "FrontPageInit()", TRUE);
+        return;
+    }
+    
+    gettimeofday(&tp, &tz);
+    iRandom[0] = tp.tv_sec;
+    iRandom[1] = tp.tv_usec | tp.tv_usec << 20;
+
+    pid = fork();
+    if (pid == -1)
+    {
+        /*
+         * Dieser Fall sollte selten vorkommen. Benutzerwiederherstellung: Stellen Sie fest,
+         * warum das System keinen Prozess zuordnen kann (ist die Dateitabelle mit
+         * abgelaufenen Prozessen gefüllt?). Beheben Sie das Problem oder starten Sie den 
+         * Rechner neu, und versuchen Sie es dann erneut.
+         */
+        LogFrontPageError(s, "fork() fehlgeschlagen", 0, "FrontPageInit()", TRUE);
+        return;
+    }
+    
+    if (pid)
+    {
+        /*
+         * Übergeordneter Prozess. Versuch, eine Zufallszahl von dem
+         * untergeordneten Prozess zu lesen.
+         */
+
+        unsigned int npos = (unsigned int)-1;
+        unsigned int v1 = npos, v2 = npos, v3 = npos, v4 = npos;
+        int stat;
+        int iCount;
+
+        close(fdPipe[1]);
+        if (waitpid(pid, &stat, 0) == -1 ||
+            (!WIFEXITED(stat) || WIFEXITED(stat) && WEXITSTATUS(stat)))
+        {
+            /*
+             * Dieser Fall sollte selten vorkommen. Benutzerwiederherstellung: Sicherstellen, 
+             * dass /bin/sh existiert, oder das Shellverzeichnis unten im execl
+             * Befehl ändern. Probieren Sie die in RAND_CMD definierten Befehle in einer
+             * /bin/sh-Sitzung, um sicherzustellen, dass sie einwandfrei funktionieren. Erstellen
+             * Sie dieses Modul sowie HTTPD mit den richtigen Befehlen neu.
+             */
+            LogFrontPageError(s, "Zufallszahlengenerator mit Fehler abgebrochen", 
+                                         0, "FrontPageInit()", TRUE);
+            return;
+        }
+
+        iCount = read(fdPipe[0], gszKeyVal, KEYLEN);
+        close(fdPipe[0]);
+        if (iCount < 0)
+        {
+            /*
+             * Dieser Fall sollte selten vorkommen. Informationen zur Benutzerwiederherstellung 
+             * finden Sie oben im Kommentar zum waitpid-Fehler.
+             */
+            LogFrontPageError(s, "Zufallszahlen konnten nicht gelesen werden", 
+                                         0, "FrontPageInit()", TRUE);
+            return;
+        }
+        gszKeyVal[iCount] = 0;
+
+        sscanf(gszKeyVal, "%u %u %u %u", &v2, &v1, &v4, &v3);
+        if (v1 == npos || v2 == npos || v3 == npos || v4 == npos)
+        {
+            /*
+             * Dieser Fall sollte selten vorkommen. Informationen zur Benutzerwiederherstellung 
+             * finden Sie oben im Kommentar zum waitpid-Fehler.
+             */
+            LogFrontPageError(s, "Zufallszahlen konnten nicht gescannt werden", 
+                                         0, "FrontPageInit()", TRUE);
+            return;
+        }
+
+        iRandom[2] = (v1 << 16) + v2 + (v4 << 12) + v3;
+    }
+    else
+    {
+        /*
+         * Untergeordneter Prozess. Erstellen einer Zufallszahl, die nur
+         * schwer dupliziert werden kann.
+         */
+
+        if (dup2(fdPipe[1], 1) == -1)
+            exit(1);                    /* Übergeordnetes Programm übernimmt den Fehler */
+
+        close(fdPipe[0]);
+
+#ifdef LINUX
+#define RAND_CMD "/bin/ps laxww | /usr/bin/sum ; /bin/ps laxww | /usr/bin/sum"
+#else
+#if defined ( bsdi ) || ( defined ( BSD ) && ( BSD >= 199103 ))
+#define RAND_CMD "/bin/ps laxww | /usr/bin/cksum -o 1 ; /bin/ps laxww | /usr/bin/cksum -o 1"
+#else
+#define RAND_CMD "/bin/ps -ea | /bin/sum ; /bin/ps -ea | /bin/sum"
+#endif
+#endif
+        execl("/bin/sh", "/bin/sh", "-c", RAND_CMD, NULL);
+        exit(1);
+    }
+
+    gettimeofday(&tp, &tz);
+    iRandom[3] = tp.tv_sec;
+    iRandom[4] = tp.tv_usec | tp.tv_usec << 20;
+
+    /*
+     * Feststellen, ob eine 'suidkey'-Datei existiert, in die der Schlüssel eingefügt werden soll.
+     */
+    if (Vstat(KEYFILEXOR, &fs) == -1)
+    {
+        /*
+         * Sicherheitsverletzung, falls Schlüsseldatei nicht vorhanden. Benutzer-
+         * wiederherstellung: Sicherstellen, dass die Schlüsseldatei vorhanden und
+         * ordnungsgemäß geschützt ist (Besitzer = root, Berechtigungen = r**------).
+         */
+        LogFrontPageError(s, "Die Schlüsseldatei \"%-.1024s\" ist nicht vorhanden", 
+                                    KEYFILEXOR, "FrontPageInit()", TRUE);
+        return;
+    }
+    else
+    {
+        int i, iCount;
+        char szBuf[KEYLEN];
+
+        if ((fs.st_mode & (S_IRWXG | S_IRWXO)) || fs.st_uid)
+        {
+            /*
+             * Sicherheitsverletzung, falls der Besitzer der Schlüsseldatei nicht root 
+             * und gegenüber allen anderen Gruppen ungeschützt ist. Benutzerwiederherstellung: 
+             * Sicherstellen, dass die Schlüsseldatei ordnungsgemäß geschützt ist 
+             * (Besitzer= root, Berechtigungen = r**------).
+             */
+            LogFrontPageError(s, "Auf die Schlüsseldatei \"%-.1024s\" darf nur root zugreifen können",
+                              KEYFILEXOR, "FrontPageInit()", TRUE);
+            return;
+        }
+
+        if ((fd = open(KEYFILEXOR, O_RDONLY)) == -1)
+        {
+            /*
+             * Dieser Fall sollte selten vorkommen. Benutzerwiederherstellung: Sicherstellen,
+             * dass die Schlüsseldatei existiert, Besitzer und Berechtigungen in Ordnung sind
+             * und dass die Datei lesbar ist.
+             */
+            LogFrontPageError(s, "Schlüsseldatei \"%-.1024s\" kann nicht geöffnet werden",
+                              KEYFILEXOR, "FrontPageInit()", TRUE);
+            return;
+        }
+
+        iCount = read(fd, szBuf, KEYLEN);
+        if (iCount < 8)
+        {
+            /*
+             * Die Schlüsseldatei muss mindestens 8 Byte groß sein. Ist sie länger als 128
+             * Byte, werden nur die ersten 128 Byte verwendet. Zulässig sind alle 
+             * Zeichenwerte von 0-255. Benutzerwiederherstellung: Sicherstellen, dass 
+             * die Schlüsseldatei mindestens 8 Byte lang ist.
+             */
+            LogFrontPageError(s, "Schlüsseldatei \"%-.1024s\" nicht lesbar oder zu kurz",
+                              KEYFILEXOR, "FrontPageInit()", TRUE);
+            close(fd);
+            return;
+        }
+
+        /*
+         * Jetzt wird der effektiv verwendete Schlüssel erstellt: XOR des Schlüssels
+         * mit 5 "zufälligen" 32-Bit-Ganzzahlen. Die primäre Sicherheit dieses
+         * Schemas stellt den Schlüssel dar; die ordnungsgemäße Festlegung und 
+         * häufige Änderungen gewährleisten die Sicherheit des FrontPage SUID-Schemas.
+         * Der Zweck der oben erstellten 5 zufälligen 32-Bit-Ganzzahlen liegt allein
+         * darin, das "Knacken" des Schlüssels zu erschweren. (Dabei wird 
+         * davon ausgegangen, dass die Schlüsseldateien einwandfrei geschützt sind).  
+         * Falls Sie einen anderen Algorithmus zum Erzeugen der 5 zufälligen Ganzahlen 
+         * verwenden möchten, können Sie dies tun (Infos dazu finden Sie bei Lavarand (TM) 
+         * von SGI unter lavarand.sgi.com).
+         */
+        for (i = 0;  i < KEYLEN;  i++)
+            gszKeyVal[i] = szBuf[i % iCount] ^ szRandom[i % sizeof(iRandom)];
+
+        /*
+         * Vielen Dank an A.Mayrhofer@Austria.EU.net 980130
+         */
+        close(fd);
+    }
+
+#if defined(SUNOS4)
+    pid = getpgrp(0);
+#else
+    pid = getpgrp();
+#endif
+    sprintf(szKeyFile, KEYFILE, (int)pid);
+
+    fd = creat(szKeyFile, 0600);
+    if (fd < 0)
+    {
+        /*
+         * Dieser Fall sollte selten vorkommen, das das Skript als root ausgeführt wird und
+         * immer über die Berechtigung verfügen sollte, die Datei zu erstellen.  
+         * Benutzerwiederherstellung: Überprüfen, ob genügend Speicherplatz auf der Festplatte 
+         * vorhanden ist, und sich die Datei nicht in einem freigegebenen NFS-Verzeichnis 
+         * befindet, in dem Sie keine Berechtigungen besitzen.
+         */
+        LogFrontPageError(s, "Schlüsseldatei \"%-.1024s\" konnte nicht erstellt werden",
+                          szKeyFile, "FrontPageInit()", TRUE);
+        return;
+    }
+
+    if (write(fd, gszKeyVal, 128) != 128)
+    {
+        /*
+         * Dieser Fall sollte selten vorkommen. Benutzerwiederherstellung: Überprüfen, ob 
+         * genügend Speicherplatz auf der Festplatte vorhanden ist.
+         */
+        close(fd);  
+        unlink(szKeyFile);
+        LogFrontPageError(s, "Schreiben in Schlüsseldatei \"%-.1024s\" nicht möglich",
+                          szKeyFile, "FrontPageInit()", TRUE);
+        return;
+    }
+
+    close(fd);  
+
+    /*
+     * Es scheint Alles in Ordnung zu sein, um mit dem SUID-Schema zu beginnen.
+     */
+    gbEnabled = TRUE;
+
+    /*
+     * Vielen Dank an Scot Hetzel (hetzels@westbend.net)
+     */
+    ap_add_version_component("FrontPage/4.0.4.3");
+}
+
+
+/*
+ * Suche nach gültigen FrontPage-Erweiterungen und gegebenenfalls 
+ * Imitieren eines Skriptalias. Bei Problemen: Ablehnung.
+ */
+static int FrontPageAlias(
+    request_rec* r,
+    char* szCgi,
+    const char* szFpexe)
+{
+    int iLen;
+    struct stat webroot;
+    struct stat vti_pvt;
+    struct stat stub;
+    char szBuf[MAXPATHLEN];
+    char chSave;
+
+    /*
+     * Ablehnen, wenn Stub nicht ausgeführt werden kann oder beschreibbar ist.
+     */
+    if (Vstat(FPSTUB, &stub) == -1 || !(stub.st_mode & S_IXOTH) ||
+        stub.st_mode & (S_IWGRP | S_IWOTH))
+    {
+        /*
+         * Die Berechtigunen des Stub-Programms waren einwandfrei; was ist passiert?  
+         * Benutzerwiederherstellung: Besitzer des Stub-Programms als root mit den
+         * Berechtigungen r*s*-x*-x festlegen.
+         */
+        LogFrontPageError(r->server, "Falsche Berechtigungen für Stub-Progr. \"%-.1024s\"",
+                          FPSTUB, "FrontPageAlias()", FALSE);
+        return DECLINED;
+    }
+
+    chSave = szCgi[1];
+    szCgi[1] = '\0';
+    ap_translate_name(r);
+    szCgi[1] = chSave;
+
+    /*
+     * Schrägstrich am Ende entfernen (verwirrt einige Betriebssysteme).
+     */
+    iLen = strlen(r->filename);
+    r->filename[--iLen] = 0;
+
+    if (iLen > MAXPATHLEN - 10)
+        return DECLINED;
+    sprintf(szBuf, "%s/_vti_pvt", r->filename);
+
+    /*
+     * Ablehnen, wenn webroot und webroot/_vti_pvt nicht den gleichen Benutzer
+     * und die gleiche Gruppe besitzen 
+     * oder uid < LOWEST_VALID_UID bzw. gid < LOWEST_VALID_GID ist.
+     */
+    if (Vstat(szBuf, &vti_pvt) == -1       ||
+        vti_pvt.st_uid < LOWEST_VALID_UID ||
+        vti_pvt.st_gid < LOWEST_VALID_GID ||
+        Vstat(r->filename, &webroot) != 0  ||
+        webroot.st_uid != vti_pvt.st_uid  || 
+        webroot.st_gid != vti_pvt.st_gid)
+    {
+        /*
+         * Webroot und webroot/_vti_pvt passen nicht. Benutzerwiederherstellung: Korrigieren 
+         * der Besitzer und Gruppen beider Verzeichnisse, sodass sie übereinstimmen und
+         * uid sowie gid im zulässigen Bereich liegen.
+         */
+        LogFrontPageError(r->server, "Falsche Berechtigungen für webroot \"%-.0124s\" und das webroot-Verzeichnis _vti_pvt",
+                          szBuf, "FrontPageAlias()", FALSE);
+        return DECLINED;
+    }
+ 
+    /*
+     * Wenn Pipe aktiv, liegt das daran, dass vorher ein CGI-Programm ausgeführt wurde.
+     * Das CGI-Programm muss jetzt fertig sein (sonst würde die nächste Anforderung
+     * nicht aufgeführt). Die Pipe kann und sollte geschlossen werden, um ein 
+     * Ressourcenloch zu vermeiden.
+     */
+    if (gbKeyPipeActive)
+    {
+        close(gfdKeyPipe[0]);
+        gbKeyPipeActive = FALSE;
+    }
+
+    /*
+     * Falls keine Pipe erstellt werden kann, ist dies kritisch. Daher: Aufzeichnen eines
+     * Fehlers und Ablehnung. Dieser Fall sollte selten vorkommen. Benutzerwiederherstellung: 
+     * Überprüfen, warum das System keine Pipe zuordnen konnte (ist die Dateitabelle mit
+     * abgelaufenen Prozessen gefüllt?). Problem korrigieren oder Rechner neu starten, 
+     * und den Vorgang erneut versuchen.
+     */
+    if (pipe(gfdKeyPipe) == -1)
+    {
+        LogFrontPageError(r->server, "pipe() failed", 0,
+                          "FrontPageAlias()", FALSE);
+        return DECLINED;
+    }
+
+    /*
+     * Anmerkung: ap_pstrdup ordnet Speicher zu, überprüft jedoch, ob genügend Speicher 
+     * vorhanden ist - keine Rückkehr, wenn zu wenig Speicher.
+     */
+    r->handler = ap_pstrdup(r->pool, "cgi-script");
+    ap_table_set(r->notes, "alias-forced-type", r->handler);
+
+    ap_table_set(r->subprocess_env, "FPEXE", ap_pstrdup(r->pool, szFpexe));
+    sprintf(szBuf, "%d", webroot.st_uid );
+    ap_table_set(r->subprocess_env, "FPUID", ap_pstrdup(r->pool, szBuf));
+    sprintf(szBuf, "%d", webroot.st_gid );
+    ap_table_set(r->subprocess_env, "FPGID", ap_pstrdup(r->pool, szBuf));
+    sprintf(szBuf, "%d", gfdKeyPipe[0]);
+    ap_table_set(r->subprocess_env, "FPFD", ap_pstrdup(r->pool, szBuf));
+
+    r->execfilename = ap_pstrcat(r->pool, FPSTUB, szCgi+strlen(szFpexe), NULL);
+    r->filename = ap_pstrcat(r->pool, r->filename, szCgi, NULL);
+
+    if (write(gfdKeyPipe[1], gszKeyVal, 128) != 128)
+    {
+        /*
+         * Falls nicht in die Pipe geschrieben werden kann, ist dies kritisch. Daher: Aufzeichnen 
+         * eines Fehlers und Ablehnung. Dieser Fall sollte selten vorkommen. Benutzer-
+         * wiederherstellung: Überprüfen, warum das System nicht in die Pipe schreiben kann 
+         * (ist das System überlastet?), Problem korrigieren oder Rechner neu starten, 
+         * und den Vorgang erneut versuchen.
+         */
+        LogFrontPageError(r->server, "Schreiben in Pipe nicht möglich", 0,
+                          "FrontPageAlias()", FALSE);
+        close (gfdKeyPipe[0]);
+        close (gfdKeyPipe[1]);
+        return DECLINED;
+    }
+    close(gfdKeyPipe[1]);
+
+    gbKeyPipeActive = TRUE;
+    return OK;
+}
+
+
+/*
+ * Diese Routine sucht nach shtml.exe, fpcount.exe, author.exe und admin.exe
+ * in einem URI. Falls gefunden: Aufruf von FrontPageAlias(), um eine Überprüfung  
+ * durchzuführen, ob eine zulässige FrontPage-Situation vorliegt.
+ *
+ * Rückgabewert ist OK oder DECLINED.
+ */
+static int FrontPageXlate(
+    request_rec *r)
+{
+    char *szVti;
+    char *szCgi;
+
+    /*
+     * Ablehung, falls keine einwandfreie Initialisierung.
+     */
+    if (!gbEnabled)
+        return DECLINED;
+
+    /*
+     * Einmalige Überprüfung, ob in _vti_bin alles in Ordnung ist. Dies ist viel schneller
+     * als die Überprüfung aller vier Pfade, da sonst Alles definitiv keine
+     * FrontPage-Situation darstellt.
+     */
+    if (!(szVti = strstr(r->uri, VTI_BIN)))
+        return DECLINED;
+
+    /* 
+     * Überprüfen der FrontPage-Servererweiterungen:
+     * .../_vti_bin/shtml.exe...
+     * .../_vti_bin/shtml.dll...
+     * .../_vti_bin/fpcount.exe...
+     * .../_vti_bin/_vti_aut/author.exe...
+     * .../_vti_bin/_vti_adm/admin.exe...
+     */
+    if (szCgi = strstr(szVti, AUTHOR ))
+        return FrontPageAlias(r, szCgi, AUTHOR);
+    /*
+     * Unbeabsichtigtes Konvertieren von shtml.dll in shtml.exe
+     * Vielen Dank für die Idee an Scot Hetzel (hetzels@westbend.net)
+     */
+    if (szCgi = strstr(szVti, SHTML2 ))
+    {
+        int iShtmlExtPos = strlen(SHTML2) - 3;
+        strncpy(szCgi + iShtmlExtPos, SHTML + iShtmlExtPos, 3);
+    }
+    if (szCgi = strstr(szVti, SHTML  ))
+        return FrontPageAlias(r, szCgi, SHTML);
+    if (szCgi = strstr(szVti, ADMIN  ))
+        return FrontPageAlias(r, szCgi, ADMIN);
+    if (szCgi = strstr(szVti, FPCOUNT))
+        return FrontPageAlias(r, szCgi, FPCOUNT);
+
+    return DECLINED;    
+}
+
+
+/*
+ * Deklarieren des Skripts, sodass es von den Konfigurationsroutinen gefunden werden kann.
+ */
+module frontpage_module = 
+{
+    STANDARD_MODULE_STUFF,
+    FrontPageInit,             /* Initialisierung*/
+    NULL,                      /* Konfigurationserstellung für jedes Verzeichnis */
+    NULL,                      /* Zusammenführen der Verz.konfig. - Standard = Überschrieben */
+    NULL,                      /* Erstellen Serverkonfiguration */
+    NULL,                      /* Zusammenführen Serverkonfiguration */
+    NULL,                      /* Befehlstabelle */
+    NULL,                      /* [6] Liste der Behandlungsroutinen */
+    FrontPageXlate,            /* [1] Umsetzung Dateiname in URI */
+    NULL,                      /* [4] Überprüfen der HTTP-Benutzer-ID */
+    NULL,                      /* [5] Überprüfen, ob die HTTP-Benutzer-ID *hier* gültig ist */
+    NULL,                      /* [3] Überprüfen des Zugriffs anhand Hostadresse, usw. */
+    NULL,                      /* [6] Überprüfen/Festlegen MIME-Typ */
+    NULL,                      /* [7] Korrekturen */
+    NULL,                      /* [9] Protokollierung */
+    NULL,                      /* [2] Kopfzeilenanalyse */
+};

ZURÜCK  NACH OBEN

Letzte Aktualisierung: November 1998
©1998 Microsoft Corporation. Alle Rechte vorbehalten. Nutzungsbedingungen.