!C99Shell v. 2.0 [PHP 7 Update] [25.02.2019]!

Software: Apache. PHP/5.6.40 

uname -a: Linux cpanel06wh.bkk1.cloud.z.com 2.6.32-954.3.5.lve1.4.80.el6.x86_64 #1 SMP Thu Sep 24
01:42:00 EDT 2020 x86_64
 

uid=851(cp949260) gid=853(cp949260) groups=853(cp949260) 

Safe-mode: OFF (not secure)

/opt/passenger-5.3.7-4.el6.cloudlinux/src/agent/Core/SpawningKit/Handshake/   drwxr-xr-x
Free 221.81 GB of 981.82 GB (22.59%)
Home    Back    Forward    UPDIR    Refresh    Search    Buffer    Encoder    Tools    Proc.    FTP brute    Sec.    SQL    PHP-code    Update    Feedback    Self remove    Logout    


Viewing file:     Prepare.h (17.61 KB)      -rw-r--r--
Select action/file-type:
(+) | (+) | (+) | Code (+) | Session (+) | (+) | SDB (+) | (+) | (+) | (+) | (+) | (+) |
/*
 *  Phusion Passenger - https://www.phusionpassenger.com/
 *  Copyright (c) 2016-2018 Phusion Holding B.V.
 *
 *  "Passenger", "Phusion Passenger" and "Union Station" are registered
 *  trademarks of Phusion Holding B.V.
 *
 *  Permission is hereby granted, free of charge, to any person obtaining a copy
 *  of this software and associated documentation files (the "Software"), to deal
 *  in the Software without restriction, including without limitation the rights
 *  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 *  copies of the Software, and to permit persons to whom the Software is
 *  furnished to do so, subject to the following conditions:
 *
 *  The above copyright notice and this permission notice shall be included in
 *  all copies or substantial portions of the Software.
 *
 *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 *  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 *  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 *  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 *  THE SOFTWARE.
 */
#ifndef _PASSENGER_SPAWNING_KIT_HANDSHAKE_PREPARE_H_
#define _PASSENGER_SPAWNING_KIT_HANDSHAKE_PREPARE_H_

#include <oxt/backtrace.hpp>
#include <boost/thread.hpp>
#include <boost/scoped_array.hpp>
#include <string>
#include <vector>
#include <stdexcept>
#include <algorithm>
#include <utility>
#include <cerrno>
#include <cstddef>
#include <cassert>

#include <sys/types.h>
#include <sys/stat.h>
#include <sys/un.h>
#include <sys/socket.h>
#include <pwd.h>
#include <grp.h>
#include <unistd.h>
#include <limits.h>

#include <jsoncpp/json.h>

#include <Constants.h>
#include <LoggingKit/LoggingKit.h>
#include <StaticString.h>
#include <Exceptions.h>
#include <FileTools/FileManip.h>
#include <FileTools/PathManip.h>
#include <SystemTools/UserDatabase.h>
#include <SystemTools/SystemTime.h>
#include <Utils/Timer.h>
#include <IOTools/IOUtils.h>
#include <StrIntTools/StrIntUtils.h>
#include <Core/SpawningKit/Context.h>
#include <Core/SpawningKit/Config.h>
#include <Core/SpawningKit/Journey.h>
#include <Core/SpawningKit/Exceptions.h>
#include <Core/SpawningKit/Handshake/Session.h>
#include <Core/SpawningKit/Handshake/WorkDir.h>

namespace Passenger {
namespace SpawningKit {

using namespace std;
using namespace oxt;


/**
 * For an introduction see README.md, section
 * "The preparation and the HandshakePrepare class".
 */
class HandshakePrepare {
private:
    HandshakeSession &session;
    Context * const context;
    Config * const config;
    Json::Value args;
    Timer<SystemTime::GRAN_10MSEC> timer;


    void resolveUserAndGroup() {
        TRACE_POINT();
        string username = config->user.toString(); // null terminate string
        string groupname = config->group.toString(); // null terminate string
        OsUser osUser;
        OsGroup osGroup;

        if (lookupSystemUserByName(username, osUser)) {
            session.uid = osUser.pwd.pw_uid;
            session.shell = osUser.pwd.pw_shell;
            session.homedir = osUser.pwd.pw_dir;
        } else {
            if (looksLikePositiveNumber(username)) {
                P_WARN("OS user account '" << username << "' does not exist."
                    " Will assume that this is a UID.");
                session.uid = (uid_t) atoi(username);
            } else {
                throw RuntimeException("OS user account '" + username + "' does not exist");
            }
        }

        if (lookupSystemGroupByName(groupname, osGroup)) {
            session.gid = osGroup.grp.gr_gid;
        } else {
            if (looksLikePositiveNumber(groupname)) {
                P_WARN("OS group account '" << groupname << "' does not exist."
                    " Will assume that this is a GID.");
                session.gid = (gid_t) atoi(groupname);
            } else {
                throw RuntimeException("OS group account '" + groupname + "' does not exist");
            }
        }
    }

    void createWorkDir() {
        TRACE_POINT();
        session.workDir.reset(new HandshakeWorkDir());

        session.envDumpDir = session.workDir->getPath() + "/envdump";
        makeDirTree(session.envDumpDir,
            "u=rwx,g=,o=",
            session.uid,
            session.gid);
        makeDirTree(session.envDumpDir + "/annotations",
            "u=rwx,g=,o=",
            session.uid,
            session.gid);

        session.responseDir = session.workDir->getPath() + "/response";
        makeDirTree(session.responseDir,
            "u=rwx,g=,o=",
            session.uid,
            session.gid);
        createFifo(session.responseDir + "/finish");
        makeDirTree(session.responseDir + "/error",
            "u=rwx,g=,o=",
            session.uid,
            session.gid);
        makeDirTree(session.responseDir + "/steps",
            "u=rwx,g=,o=",
            session.uid,
            session.gid);


        createJourneyStepDirs(getFirstSubprocessJourneyStep(),
            getLastSubprocessJourneyStep());
        createJourneyStepDirs(getFirstPreloaderJourneyStep(),
            // Also create directory for PRELOADER_FINISH;
            // the preloader will want to write there.
            JourneyStep((int) getLastPreloaderJourneyStep() + 1));
    }

    void createJourneyStepDirs(JourneyStep firstStep, JourneyStep lastStep) {
        JourneyStep step;

        for (step = firstStep; step < lastStep; step = JourneyStep((int) step + 1)) {
            if (!session.journey.hasStep(step)) {
                continue;
            }

            string stepString = journeyStepToStringLowerCase(step);
            string stepDir = session.responseDir + "/steps/" + stepString;
            makeDirTree(stepDir, "u=rwx,g=,o=", session.uid, session.gid);
        }
    }

    void createFifo(const string &path) {
        int ret;

        do {
            ret = mkfifo(path.c_str(), 0600);
        } while (ret == -1 && errno == EINTR);
        if (ret == -1) {
            int e = errno;
            throw FileSystemException("Cannot create FIFO file " + path,
                e, path);
        }

        ret = syscalls::chown(path.c_str(),
            session.uid,
            session.gid);
        if (ret == -1) {
            int e = errno;
            throw FileSystemException(
                "Cannot change ownership for FIFO file " + path,
                e, path);
        }
    }

    // Open various workdir subdirectories because we'll use these file descriptors later in
    // safeReadFile() calls.
    void openWorkDirSubdirFds() {
        session.workDirFd = openDirFd(session.workDir->getPath());
        session.responseDirFd = openDirFd(session.responseDir);
        session.responseErrorDirFd = openDirFd(session.responseDir + "/error");
        session.envDumpDirFd = openDirFd(session.envDumpDir);
        session.envDumpAnnotationsDirFd = openDirFd(session.envDumpDir + "/annotations");
        openJourneyStepDirFds(getFirstSubprocessJourneyStep(),
            getLastSubprocessJourneyStep());
        openJourneyStepDirFds(getFirstPreloaderJourneyStep(),
            JourneyStep((int) getLastPreloaderJourneyStep() + 1));
    }

    void openJourneyStepDirFds(JourneyStep firstStep, JourneyStep lastStep) {
        JourneyStep step;

        for (step = firstStep; step < lastStep; step = JourneyStep((int) step + 1)) {
            if (!session.journey.hasStep(step)) {
                continue;
            }

            string stepString = journeyStepToStringLowerCase(step);
            string stepDir = session.responseDir + "/steps/" + stepString;
            session.stepDirFds.insert(make_pair(step, openDirFd(stepDir)));
        }
    }

    int openDirFd(const string &path) {
        int fd = open(path.c_str(), O_RDONLY);
        if (fd == -1) {
            int e = errno;
            throw FileSystemException("Cannot open " + path, e, path);
        }
        return fd;
    }

    void initializeResult() {
        session.result.initialize(*context, config);
    }

    void preparePredefinedArgs() {
        TRACE_POINT();
        struct sockaddr_un addr;

        args["passenger_root"] = context->resourceLocator->getInstallSpec();
        args["passenger_version"] = PASSENGER_VERSION;
        args["passenger_agent_path"] = context->resourceLocator->findSupportBinary(AGENT_EXE);
        args["ruby_libdir"] = context->resourceLocator->getRubyLibDir();
        args["node_libdir"] = context->resourceLocator->getNodeLibDir();
        args["integration_mode"] = context->integrationMode;
        args["gupid"] = session.result.gupid;
        args["UNIX_PATH_MAX"] = (Json::UInt64) sizeof(addr.sun_path) - 1;
        if (config->genericApp || config->findFreePort) {
            args["expected_start_port"] = session.expectedStartPort;
        }
        if (!config->apiKey.empty()) {
            args["connect_password"] = config->apiKey.toString();
        }
        if (!context->instanceDir.empty()) {
            args["instance_dir"] = context->instanceDir;
            args["socket_dir"] = context->instanceDir + "/apps.s";
        }
    }

    void prepareArgsFromAppConfig() {
        TRACE_POINT();
        const Json::Value appConfigJson = config->getConfidentialFieldsToPassToApp();
        Json::Value::const_iterator it, end = appConfigJson.end();
        for (it = appConfigJson.begin(); it != end; it++) {
            args[it.name()] = *it;
        }
    }

    void absolutizeKeyArgPaths() {
        TRACE_POINT();
        args["app_root"] = absolutizePath(args["app_root"].asString());
        if (args.isMember("startup_file")) {
            args["startup_file"] = absolutizePath(args["startup_file"].asString(),
                args["app_root"].asString());
        }
    }

    void dumpArgsIntoWorkDir() {
        TRACE_POINT();
        P_DEBUG("[App spawn arg] " << args.toStyledString());

        // The workDir is a new random dir. the files that we create here
        // should not exist, so if any exist then have createFile()
        // throw an error because it could be a bug or an attack.

        createFile(session.workDir->getPath() + "/args.json",
            args.toStyledString(), 0600,
            session.uid, session.gid,
            false, __FILE__, __LINE__);

        const string dir = session.workDir->getPath() + "/args";
        makeDirTree(dir, "u=rwx,g=,o=",
            session.uid,
            session.gid);

        const Json::Value &constArgs = const_cast<const Json::Value &>(args);
        Json::Value::const_iterator it, end = constArgs.end();
        for (it = constArgs.begin(); it != end; it++) {
            const Json::Value &value = *it;
            switch (value.type()) {
            case Json::nullValue:
            case Json::intValue:
            case Json::uintValue:
            case Json::realValue:
            case Json::stringValue:
            case Json::booleanValue:
                createFile(dir + "/" + it.name(),
                    jsonValueToString(*it),
                    0600, session.uid, session.gid,
                    false, __FILE__, __LINE__);
                break;
            default:
                createFile(dir + "/" + it.name() + ".json",
                    jsonValueToString(*it),
                    0600, session.uid, session.gid,
                    false, __FILE__, __LINE__);
                break;
            }
        }
    }

    string jsonValueToString(const Json::Value &value) const {
        switch (value.type()) {
        case Json::nullValue:
            return string();
        case Json::intValue:
            return toString(value.asInt64());
        case Json::uintValue:
            return toString(value.asUInt64());
        case Json::realValue:
            return toString(value.asDouble());
        case Json::stringValue:
            return value.asString();
        case Json::booleanValue:
            if (value.asBool()) {
                return "true";
            } else {
                return "false";
            }
        default:
            return value.toStyledString();
        }
    }

    #if 0
    void inferApplicationInfo() const {
        TRACE_POINT();
        session.result.codeRevision = readFromRevisionFile();
        if (session.result.codeRevision.empty()) {
            session.result.codeRevision = inferCodeRevisionFromCapistranoSymlink();
        }
    }

    string readFromRevisionFile() const {
        TRACE_POINT();
        string filename = config->appRoot + "/REVISION";
        try {
            if (fileExists(filename)) {
                return strip(readAll(filename));
            }
        } catch (const SystemException &e) {
            P_WARN("Cannot access " << filename << ": " << e.what());
        }
        return string();
    }

    string inferCodeRevisionFromCapistranoSymlink() const {
        TRACE_POINT();
        if (extractBaseName(config->appRoot) == "current") {
            string appRoot = config->appRoot.toString(); // null terminate string
            char buf[PATH_MAX + 1];
            ssize_t ret;

            do {
                ret = readlink(appRoot.c_str(), buf, PATH_MAX);
            } while (ret == -1 && errno == EINTR);
            if (ret == -1) {
                if (errno == EINVAL) {
                    return string();
                } else {
                    int e = errno;
                    P_WARN("Cannot read symlink " << appRoot << ": " << strerror(e));
                }
            }

            buf[ret] = '\0';
            return extractBaseName(buf);
        } else {
            return string();
        }
    }
    #endif

    void findFreePortOrSocketFile() {
        TRACE_POINT();
        session.expectedStartPort = findFreePort();
        if (session.expectedStartPort == 0) {
            throwSpawnExceptionBecauseOfFailureToFindFreePort();
        }

        // TODO: support Unix domain sockets in the future
        // session.expectedStartSocketFile = findFreeSocketFile();
    }

    unsigned int findFreePort() {
        TRACE_POINT();
        unsigned int tryCount = 1;
        unsigned int maxTries;

        while (true) {
            unsigned int port;

            boost::this_thread::interruption_point();

            {
                boost::lock_guard<boost::mutex> l(context->syncher);
                port = context->nextPort;
                context->nextPort++;
                if (context->nextPort > context->maxPortRange) {
                    context->nextPort = context->minPortRange;
                }
                maxTries = context->maxPortRange -
                    context->minPortRange + 1;
            }

            unsigned long long timeout1 = 100000;
            unsigned long long timeout2 = 100000;

            if (!pingTcpServer("127.0.0.1", port, &timeout1)
             && !pingTcpServer("0.0.0.0", port, &timeout2))
            {
                return port;
            } else if (tryCount >= maxTries) {
                return 0;
            } else if (timer.usecElapsed() >= session.timeoutUsec) {
                throwSpawnExceptionBecauseOfPortFindingTimeout();
            } // else: try again
        }
    }

    void adjustTimeout() {
        unsigned long long elapsed = timer.usecElapsed();

        if (elapsed >= session.timeoutUsec) {
            session.timeoutUsec = 0;
        } else {
            session.timeoutUsec -= elapsed;
        }
    }

    void throwSpawnExceptionBecauseOfPortFindingTimeout() {
        assert(config->genericApp || config->findFreePort);
        SpawnException e(TIMEOUT_ERROR, session.journey, config);
        e.setProblemDescriptionHTML(
            "<p>The " PROGRAM_NAME " application server tried"
            " to look for a free TCP port for the web application"
            " to start on. But this took too much time, so "
            SHORT_PROGRAM_NAME " put a stop to that.</p>");

        unsigned int minPortRange, maxPortRange;
        {
            boost::lock_guard<boost::mutex> l(context->syncher);
            minPortRange = context->minPortRange;
            maxPortRange = context->maxPortRange;
        }

        e.setSolutionDescriptionHTML(
            "<div class=\"multiple-solutions\">"

            "<h3>Check whether the server is low on resources</h3>"
            "<p>Maybe the server is currently so low on resources that"
            " all the work that needed to be done, could not finish within"
            " the given time limit."
            " Please inspect the server resource utilization statistics"
            " in the <em>diagnostics</em> section to verify"
            " whether server is indeed low on resources.</p>"
            "<p>If so, then either increase the spawn timeout (currently"
            " configured at " + toString(config->startTimeoutMsec / 1000)
            + " sec), or find a way to lower the server's resource"
            " utilization.</p>"

            "<h3>Limit the port range that " SHORT_PROGRAM_NAME " searches in</h3>"
            "<p>Maybe the port range in which " SHORT_PROGRAM_NAME
            " tried to search for a free port for the application is"
            " large, and at the same time there were very few free ports"
            " available.</p>"
            "<p>If this is the case, then please configure the "
            SHORT_PROGRAM_NAME " application spawning port range"
            " to a range that is known to have many free ports. The port"
            " range is currently configured at " + toString(minPortRange)
            + "-" + toString(maxPortRange) + ".</p>"

            "</div>"
        );

        throw e.finalize();
    }

    void throwSpawnExceptionBecauseOfFailureToFindFreePort() {
        assert(config->genericApp || config->findFreePort);
        unsigned int minPortRange, maxPortRange;
        {
            boost::lock_guard<boost::mutex> l(context->syncher);
            minPortRange = context->minPortRange;
            maxPortRange = context->maxPortRange;
        }

        SpawnException e(INTERNAL_ERROR, session.journey, config);
        e.setSummary("Could not find a free port to spawn the application on.");
        e.setProblemDescriptionHTML(
            "<p>The " PROGRAM_NAME " application server tried"
            " to look for a free TCP port for the web application"
            " to start on, but was unable to find one.</p>");
        e.setSolutionDescriptionHTML(
            "<div class=\"sole-solutions\">"

            "<p>Maybe the port range in which " SHORT_PROGRAM_NAME
            " tried to search for a free port, had very few or no"
            " free ports.</p>"
            "<p>If this is the case, then please configure the "
            SHORT_PROGRAM_NAME " application spawning port range"
            " to a range that is known to have many free ports. The port"
            " range is currently configured at " + toString(minPortRange)
            + "-" + toString(maxPortRange) + ".</p>"

            "</div>");
        throw e.finalize();
    }

public:
    struct DebugSupport {
        virtual ~DebugSupport() { }
        virtual void beforeAdjustTimeout() { }
    };

    DebugSupport *debugSupport;


    HandshakePrepare(HandshakeSession &_session,
        const Json::Value &extraArgs = Json::Value())
        : session(_session),
          context(_session.context),
          config(_session.config),
          args(extraArgs),
          timer(false),
          debugSupport(NULL)
    {
        assert(_session.context != NULL);
        assert(_session.context->isFinalized());
        assert(_session.config != NULL);
    }

    HandshakePrepare &execute() {
        TRACE_POINT();

        // We do not set SPAWNING_KIT_PREPARATION to the IN_PROGRESS or
        // PERFORMED state here. That will be done by the caller because
        // it may want to perform additional preparation.

        try {
            timer.start();

            resolveUserAndGroup();
            createWorkDir();
            openWorkDirSubdirFds();
            initializeResult();

            UPDATE_TRACE_POINT();
            // Disabled to fix CVE-2017-16355
            //inferApplicationInfo();
            if (config->genericApp || config->findFreePort) {
                findFreePortOrSocketFile();
            }

            UPDATE_TRACE_POINT();
            preparePredefinedArgs();
            prepareArgsFromAppConfig();
            absolutizeKeyArgPaths();
            dumpArgsIntoWorkDir();

            if (debugSupport != NULL) {
                debugSupport->beforeAdjustTimeout();
            }

            adjustTimeout();
        } catch (const SpawnException &) {
            session.journey.setStepErrored(SPAWNING_KIT_PREPARATION);
            throw;
        } catch (const std::exception &e) {
            session.journey.setStepErrored(SPAWNING_KIT_PREPARATION);
            throw SpawnException(e, session.journey, config).finalize();
        }

        return *this;
    }

    void finalize() {
        session.workDir->finalize(session.uid, session.gid);
    }
};


} // namespace SpawningKit
} // namespace Passenger

#endif /* _PASSENGER_SPAWNING_KIT_HANDSHAKE_PREPARE_H_ */

:: Command execute ::

Enter:
 
Select:
 

:: Search ::
  - regexp 

:: Upload ::
 
[ Read-Only ]

:: Make Dir ::
 
[ Read-Only ]
:: Make File ::
 
[ Read-Only ]

:: Go Dir ::
 
:: Go File ::
 

--[ c99shell v. 2.0 [PHP 7 Update] [25.02.2019] maintained by KaizenLouie | C99Shell Github | Generation time: 0.0607 ]--