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

Anhänge


Quellcode für "fpexe.c"

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 fpexe.c wird hier zur Überprüfung dargestellt.

* ====================================================================
 *
 * FrontPage SUID-Stub-Programm
 *
 * Copyright (c) 1995-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(RS6000)
#define _ALL_SOURCE
#endif

#if defined(RS6000) | defined(UWARE7)
int initgroups (char *, int);
#endif

#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, usw. */
#endif
#endif

#if defined(UWARE7)
#define Vstat stat32
#define Vlstat lstat32
int lstat32 (const char *, struct stat *);
int stat32 (const char *, struct stat *);
#else
#define Vstat stat
#define Vlstat lstat
#endif 

#define CLEAN_PATH "PATH=/usr/bin:/bin"

static struct SaveEnvVars
{
    const char* szVar;
    int         iLen;
} gSafeEnvVars[] =
{
    { "AUTH_TYPE=", 0 },
    { "CONTENT_LENGTH=", 0 },
    { "CONTENT_TYPE=", 0 },
    { "DATE_GMT=", 0 },
    { "DATE_LOCAL=", 0 },
    { "DOCUMENT_NAME=", 0 },
    { "DOCUMENT_PATH_INFO=", 0 },
    { "DOCUMENT_ROOT=", 0 },
    { "DOCUMENT_URI=", 0 },
    { "FILEPATH_INFO=", 0 },
    { "GATEWAY_INTERFACE=", 0 },
    { "HTTP_", 0 },
    { "LAST_MODIFIED=", 0 },
    { "PATH_INFO=", 0 },
    { "PATH_TRANSLATED=", 0 },
    { "QUERY_STRING=", 0 },
    { "QUERY_STRING_UNESCAPED=", 0 },
    { "REDIRECT_QUERY_STRING=", 0 },
    { "REDIRECT_STATUS=", 0 },
    { "REDIRECT_URL=", 0 },
    { "REMOTE_ADDR=", 0 },
    { "REMOTE_HOST=", 0 },
    { "REMOTE_IDENT=", 0 },
    { "REMOTE_PORT=", 0 },
    { "REMOTE_USER=", 0 },
    { "REQUEST_METHOD=", 0 },
    { "SCRIPT_FILENAME=", 0 },
    { "SCRIPT_NAME=", 0 },
    { "SCRIPT_URI=", 0 },
    { "SCRIPT_URL=", 0 },
    { "SERVER_ADMIN=", 0 },
    { "SERVER_NAME=", 0 },
    { "SERVER_PORT=", 0 },
    { "SERVER_PROTOCOL=", 0 },
    { "SERVER_SOFTWARE=", 0 },
    { "TZ=", 0 },
    { "USER_NAME=", 0 },
    { 0, 0 }
};

/*
 * Ende benutzerkonfigurierbare Elemente
 */


#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <ctype.h>
#include <time.h>
#include <pwd.h>
#include <grp.h>
#if !defined(bsdi) && !defined(hpux) && !defined(sun) && !defined(linux) && !defined(SCO5) && !defined(UWARE7)
#include <sys/mode.h>
#endif

#if defined(sun) || defined(bsdi) || defined(sgi) || defined(SCO5) || defined(UWARE7)
extern const char ** environ;
#endif
extern int errno;


#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 */


#define FPKEYDIR "/usr/local/frontpage/version4.0/apache-fp"
#define KEYFILE  "/usr/local/frontpage/version4.0/apache-fp/suidkey.%d"
#define FPDIR    "/usr/local/frontpage/version4.0/exes"

/* Zulässige Module */
#define SHTML    "/_vti_bin/shtml.exe"
#define FPCOUNT  "/_vti_bin/fpcount.exe"
#define AUTHOR   "/_vti_bin/_vti_aut/author.exe" 
#define ADMIN    "/_vti_bin/_vti_adm/admin.exe" 


/*
 * Irgendwas ist nicht in Ordnung - Beenden
 */
void die(const char *msg)
{
    char timebuf[26];
    time_t t = time(0);
    strcpy(timebuf, ctime(&t));
    timebuf[24] = '\0';
    fprintf(stderr, "[%s] %s\n", timebuf, msg);
    printf("Inhaltstyp: text/html\n\n<HTML>*-*-* :-| :^| :-/ :-( 8-( *-*-*\n<ul>\n<li>Status=1\n<li>BS-Status=0\n<li>msg=FrontPage-Sicherheitsverletzung.\n<li>osmsg=\n</ul>\n");
    exit(0);
}

/*
 * Entfernen aller Variablen, bei denen es sich bekannterweise nicht um ein Standard-CGI- 
 * Betriebssystem-Umgebungsvariable handelt. Ferner: Reparieren von PATH.
 */
static void CleanEnvironment() 
{
    const char** pp;
    const char** ppi;
    struct SaveEnvVars* pOkEnv;

    for (ppi = pp = environ;  *pp;  pp++)
    {
        /*
         * Ineffiziente lineare Suche; kann mit Binärsuche verbessert werden.
         */
        for (pOkEnv = gSafeEnvVars;  pOkEnv->szVar;  pOkEnv++)
        {
            int iLen = pOkEnv->iLen;
            if (!iLen)
                pOkEnv->iLen = iLen = strlen(pOkEnv->szVar);

            if (strncmp(pOkEnv->szVar, *pp, iLen) == 0)
                break;
        }

        if (!strncmp(*pp, "PATH=", 5))
            *ppi++ = CLEAN_PATH;
        else if (pOkEnv->szVar)
            *ppi++ = *pp;
    }

    *ppi = 0;
}

int main(int argc, char **argv)
{
    struct passwd* pw = 0;
    const char* szFpUserName;
    const char* szFpExe = getenv("FPEXE");
    const char* szFpUid = getenv("FPUID");
    const char* szFpGid = getenv("FPGID");
    const char* szFpFd  = getenv("FPFD");
    char* pEnd;
    char* pDir;
    uid_t iFpUid;
    uid_t iFpGid;
    uid_t iBinUid;
    int iFpFd;
    int iKeyFd;
    int iCount;
    char szKeyFile[MAXPATHLEN];
    char szWork[MAXPATHLEN];
    char inpKey[KEYLEN];
    char refKey[KEYLEN];
    struct stat fs;
    
    /*
     * Gewährleisten, dass die SUID dieses Programms tatsächlich auf root festgelegt wurde
     */
    if (geteuid())
        /*
         * Benutzerwiederherstellung: Sicherstellen, dass SUID von fpexe auf root festgelegt ist
         */
        die("FrontPage SUID-Fehler: keine Ausführung als root");

    /*
     * Gewährleisten, dass es sich bei dem Benutzer, unter dem der Webserver ausgeführt wird,
     * um einen zulässigen Benutzer handelt
     */
    if (!getpwuid(getuid()))
        /*
         * Benutzerwiederherstellung: Sicherstellen, dass sich der Webserverbenutzer in 
         * /etc/passwd befindet
         */
        die("FrontPage SUID-Fehler: unzulässige UID");

    /*
     * Gewährleisten, dass die richtigen Argumente verwendet werden (Übergabe in Umgebung)
     */
    if (!szFpExe || !szFpUid || !szFpGid || !szFpFd)
        /*
         * Benutzerwiederherstellung: Sicherstellen, dass fpexe auf einem gepatchten 
         * Apache-Server ausgeführt wird
         */
        die("FrontPage SUID-Fehler: unzulässige Umgebungsargumente");

    /*
     * Überprüfen der Argumente
     */
    if (strcmp(szFpExe, SHTML) != 0   &&
        strcmp(szFpExe, FPCOUNT) != 0 &&
        strcmp(szFpExe, AUTHOR) != 0  &&
        strcmp(szFpExe, ADMIN) != 0)
        /*
         * Benutzerwiederherstellung: Sicherstellen, dass fpexe nur aufgerufen wurde, um 
         * Programme der FrontPage-Servererweiterungen auszuführen.
         */
        die("FrontPage SUID-Fehler: Zielprogrammverletzung");

    if (strlen(szFpExe) + strlen(FPDIR) + 1 > MAXPATHLEN)
        die("FrontPage SUID-Fehler: Pfad zu lang");
    strcpy(szWork, FPDIR);
    strcat(szWork, szFpExe);

    iFpUid = strtol(szFpUid, &pEnd, 10);
    if (!pEnd || *pEnd)
        iFpUid = 0;
    if (iFpUid < LOWEST_VALID_UID || !(pw = getpwuid(iFpUid)))
        /*
         * Benutzerwiederherstellung: Sicherstellen, dass die FrontPage-Benutzer-IDs den 
         * obigen Mindestanforderungen genügen
         */
        die("FrontPage SUID-Fehler: unzulässige Ziel-UID");
    szFpUserName = strdup(pw->pw_name);

    iFpGid = strtol(szFpGid, &pEnd, 10);
    if (!pEnd || *pEnd)
        iFpGid = 0;
    if (iFpGid < LOWEST_VALID_GID || !getgrgid(iFpGid))
        /*
         * Benutzerwiederherstellung: Sicherstellen, dass die FrontPage-Gruppen-IDs den 
         * obigen Mindestanforderungen genügen
         */
        die("FrontPage SUID-Fehler: unzulässige Ziel-GID");

    iFpFd = strtol(szFpFd, &pEnd, 10);
    if (!pEnd || *pEnd)
        iFpFd = -1;
    if (iFpFd < 0)
        /*
         * Benutzerwiederherstellung: Sicherstellen, dass fpexe auf einem gepatchten Apache-
         * Server ausgeführt wird
         */
        die("FrontPage SUID-Fehler: unzulässiger Schlüsseldateideskriptor");

    /*
     * Schlüssel vom Server lesen. Solange noch als root angemeldet und Zugriff
     * möglich, Lesen des Schlüssels aus der Masterschlüsseldatei.  
     * Übereinstimmung des Schlüssels prüfen.
     */
    if (Vlstat(FPKEYDIR, &fs) == -1 ||
        (fs.st_mode & (S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)) || fs.st_uid ||
        !(S_ISDIR(fs.st_mode)))
        /*
         * Benutzerwiederherstellung: Besitzer des Verzeichnisses als root mit
         * den Berechtigungen rwx--x--x festlegen.
         */
        die("FrontPage SUID-Fehler: Schlüsseldateiverzeichnis unsicher");

#if defined(sun) && !defined(__SVR4)
    sprintf(szKeyFile, KEYFILE, (int)getpgrp(0));
#else
    sprintf(szKeyFile, KEYFILE, (int)getpgrp());
#endif
    if (Vstat(szKeyFile, &fs) == -1 ||
        (fs.st_mode & (S_IRWXG | S_IRWXO)) || fs.st_uid)
        /*
         * Benutzerwiederherstellung: Sicherstellen, dass die Schlüsseldatei ordnungsgemäß 
         * geschützt ist (Besitzer = root, Berechtigungen = r**------). Neustarten des gepatchten 
         * Apache-Servers.
         */
        die("FrontPage SUID-Fehler: Sicherheitsverletzung der Schlüsseldatei");
    
    iKeyFd = open(szKeyFile, O_RDONLY);
    if (iKeyFd < 0)
        /*
         * Benutzerwiederherstellung: Sicherstellen, dass fpexe auf einem gepatchten
         * Apache-Server ausgeführt wird. Neustarten des gepatchten Apache-Servers.
         */
        die("FrontPage SUID-Fehler: Schlüsseldatei konnte nicht geöffnet werden" );
    iCount = read(iKeyFd, refKey, sizeof(refKey));
    close(iKeyFd);
    if (iCount != sizeof(refKey))
        /*
         * Benutzerwiederherstellung:  Sicherstellen, dass fpexe auf einem gepatchten
         * Apache-Server ausgeführt wird. Neustarten des gepatchten Apache-Servers.
         */
        die("FrontPage SUID-Fehler: aus Schlüsseldatei konnte kein gültiger Schlüssel gelesen werden");

    iCount = read(iFpFd, inpKey, sizeof(inpKey));
    close(iFpFd);
    if (iCount != sizeof(inpKey))
        /*
         * Benutzerwiederherstellung: Sicherstellen, dass fpexe auf einem gepatchten 
         * Apache-Server ausgeführt wird
         */
        die("FrontPage SUID-Fehler: Lesen eines zulässigen Eingabeschlüssels nicht möglich");

    if (memcmp(inpKey, refKey, sizeof(refKey)) != 0)
        /*
         * Benutzerwiederherstellung: Sicherstellen, dass fpexe auf einem gepatchten 
         * Apache-Server ausgeführt wird
         */
        die("FrontPage SUID-Fehler: Schlüsselsicherheitsverletzung");

    /*
     * Ändern von Benutzer- und Gruppen-IDs in angegebenen Benutzer
     */
    if (setgid(iFpGid) == -1 || initgroups(szFpUserName, iFpGid) == -1)
        /*
         * Benutzerwiederherstellung:  Sicherstellen, dass der Benutzer in 
         * /etc/passwd und /etc/group ordnungsgemäß registriert ist.
         */
        die("FrontPage SUID-Fehler: setgid() fehlgeschlagen");
    
    if (setuid(iFpUid) == -1)
        /*
         * Benutzerwiederherstellung: Sicherstellen, dass der Benutzer in 
         * /etc/passwd ordnungsgemäß registriert ist.
         */
        die("FrontPage SUID-Fehler: setuid() fehlgeschlagen");

    /*
     * Überprüfen des Zielverzeichnisses.
     */
    iBinUid = 0;
    if (pw = getpwnam("bin"))
        iBinUid = pw->pw_uid;

    pDir = strrchr(szWork, '/');
    *pDir = 0;
    if (Vlstat(szWork, &fs) == -1 || (fs.st_mode & (S_IWGRP | S_IWOTH)) ||
                                    (fs.st_uid != iBinUid && fs.st_uid != 0) ||
                                    !(S_ISDIR(fs.st_mode)))
        /*
         * Benutzerwiederherstellung: Sicherstellen, dass die ausführbaren FrontPage 
         * Programme verfügbar sind, der Besitzer des Verzeichnisses auf bin oder root und
         * die Berechtigungen auf rwx*-x*-x festgelegt sind.
         */
        die("FrontPage SUID-Fehler: Zielverzeichnis nicht gefunden oder unsicher");

    *pDir = '/';

    /*
     * Überprüfen des Zielprogramms
     */
    if (Vstat(szWork, &fs) == -1 || ((fs.st_mode & (S_IWGRP | S_IWOTH)) ||
                                    (fs.st_mode & (S_ISUID | S_ISGID)) ||
                                    (fs.st_uid != iBinUid && fs.st_uid != 0)))
        /*
         * Benutzerwiederherstellung: Sicherstellen, dass die ausführbaren FrontPage 
         * Programme verfügbar sind, der Besitzer des Verzeichnisses auf bin oder root und
         * die Berechtigungen auf rwx*-x*-x festgelegt sind.
         */
        die("FrontPage SUID-Fehler: Zielprogramm nicht gefunden oder unsicher");

    *pDir = '/';

    /*
     * Sicherstellen, dass die Umgebung keine unsicheren Werte enthält.
     */
    CleanEnvironment();

    /*
     * Das angegebene Programm ausführen.
     */
    argv[0] = szWork;
    umask(022);
    execv(argv[0], argv);

    /*
     * Sollte niemals vorkommen. Beenden mit Fehler.
     */
    return (1);
}

ZURÜCK  NACH OBEN    

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