Skip to content

Commit

Permalink
Open source companion commit for rstudio/rstudio-pro#1237
Browse files Browse the repository at this point in the history
  • Loading branch information
kfeinauer committed Oct 10, 2019
1 parent b70e0e0 commit 0b964c6
Show file tree
Hide file tree
Showing 16 changed files with 182 additions and 41 deletions.
6 changes: 3 additions & 3 deletions src/cpp/conf/rserver-dev.conf
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ rsession-which-r=${LIBR_EXECUTABLE}
# don't daemonize so we can easily abort
server-daemonize=0

# set the data dir to be a user friendly place
server-data-dir=/tmp/rstudio-server

# don't validate that web authenticated users exist on the system
auth-validate-users=0

Expand All @@ -28,9 +31,6 @@ auth-none=0
# custom html for login page
auth-login-page-html=${CMAKE_CURRENT_SOURCE_DIR}/conf/login.html

# store the revocation list in a user-writeable place
auth-revocation-list-dir=$ENV{HOME}/.rstudio

# read gwt app directly from the source tree
www-local-path=${CMAKE_CURRENT_SOURCE_DIR}/../gwt/www
www-symbol-maps-path=${CMAKE_CURRENT_SOURCE_DIR}/../gwt/extras/rstudio/symbolMaps
Expand Down
24 changes: 23 additions & 1 deletion src/cpp/core/FileUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@

#include <core/system/System.hpp>

#ifndef _WIN32
#include <core/system/PosixUser.hpp>
#endif

namespace rstudio {
namespace core {
namespace file_utils {
Expand Down Expand Up @@ -99,7 +103,7 @@ std::string readFile(const FilePath& filePath)
return content;
}

#ifdef WIN32
#ifdef _WIN32
// test a filename to see if it corresponds to a reserved device name on
// Windows
bool isWindowsReservedName(const std::string& name)
Expand Down Expand Up @@ -158,6 +162,24 @@ bool isDirectoryWriteable(const FilePath& directory)
}
}

#ifndef _WIN32
Error changeOwnership(const FilePath& file,
const std::string& owner)
{
// changes ownership of file to the server user
core::system::user::User user;
Error error = core::system::user::userFromUsername(owner, &user);
if (error)
return error;

return core::system::posixCall<int>(
boost::bind(::chown,
file.absolutePath().c_str(),
user.userId,
user.groupId),
ERROR_LOCATION);
}
#endif

} // namespace file_utils
} // namespace core
Expand Down
7 changes: 6 additions & 1 deletion src/cpp/core/include/core/FileUtils.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ FilePath uniqueFilePath(const core::FilePath& parent,

std::string readFile(const core::FilePath& filePath);

#ifdef WIN32
#ifdef _WIN32
bool isWindowsReservedName(const std::string& name);
#endif

Expand All @@ -42,6 +42,11 @@ Error copyDirectory(const FilePath& sourceDirectory,

bool isDirectoryWriteable(const FilePath& directory);

#ifndef _WIN32
Error changeOwnership(const FilePath& file,
const std::string& owner);
#endif

} // namespace file_utils
} // namespace core
} // namespace rstudio
Expand Down
3 changes: 2 additions & 1 deletion src/cpp/monitor/include/monitor/MonitorConstants.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@
#ifndef MONITOR_CONSTANTS_HPP
#define MONITOR_CONSTANTS_HPP

#define kMonitorSocketPath "/tmp/rstudio-rserver/rserver-monitor.socket"
#define kMonitorSocket "rserver-monitor.socket"
#define kMonitorSocketPathEnvVar "RS_MONITOR_SOCKET_PATH"
#define kMonitorSharedSecretEnvVar "RS_MONITOR_SHARED_SECRET"
#define kMonitorIntervalSeconds "monitor-interval-seconds"

Expand Down
16 changes: 16 additions & 0 deletions src/cpp/r/session/RSessionState.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,22 @@ void setEnvVar(const std::string& name, const std::string& value)
if (name == "RSTUDIO_VERSION" && !core::system::getenv(name).empty())
return;

// don't restore socket path environment variables (should be set by main session initialization)
if (name == "RS_SERVER_RPC_SOCKET_PATH" && !core::system::getenv(name).empty())
return;

if (name == "RS_SERVER_TMP_DIR" && !core::system::getenv(name).empty())
return;

if (name == "RS_SERVER_LOCAL_SOCKET_PATH" && !core::system::getenv(name).empty())
return;

if (name == "RS_MONITOR_SOCKET_PATH" && !core::system::getenv(name).empty())
return;

if (name == "RS_SESSION_TMP_DIR" && !core::system::getenv(name).empty())
return;

core::system::setenv(name, value);
}

Expand Down
3 changes: 1 addition & 2 deletions src/cpp/rserver-dev.in
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,7 @@
# remove stream files/dirs
cleanupStreams()
{
rm -rf /tmp/rstudio-rsession
rm -rf /tmp/rstudio-rserver
rm -rf /tmp/rstudio-server
}
cleanupStreams

Expand Down
49 changes: 48 additions & 1 deletion src/cpp/server/ServerMain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@

#include <core/text/TemplateFilter.hpp>

#include <core/system/FileMode.hpp>
#include <core/system/PosixSystem.hpp>
#include <core/system/Crypto.hpp>

Expand All @@ -52,6 +53,7 @@
#include <server/ServerSessionProxy.hpp>
#include <server/ServerSessionManager.hpp>
#include <server/ServerProcessSupervisor.hpp>
#include <server/ServerPaths.hpp>

#include "ServerAddins.hpp"
#include "ServerBrowser.hpp"
Expand Down Expand Up @@ -529,6 +531,51 @@ int main(int argc, char * const argv[])
if (error)
return core::system::exitFailure(error, ERROR_LOCATION);

// initialize server data directory
FilePath serverDataDir = options.serverDataDir();
error = serverDataDir.ensureDirectory();
if (error)
return core::system::exitFailure(error, ERROR_LOCATION);

if (core::system::effectiveUserIsRoot())
{
error = file_utils::changeOwnership(serverDataDir, options.serverUser());
if (error)
return core::system::exitFailure(error, ERROR_LOCATION);
}

// ensure permissions - the folder needs to be readable and writeable
// by all users of the system, and the sticky bit must be set to ensure
// that users do not delete each others' sockets
struct stat st;
if (::stat(serverDataDir.absolutePath().c_str(), &st) == -1)
{
Error error = systemError(errno,
"Could not determine permissions on specified 'server-data-dir' "
"directory (" + serverDataDir.absolutePath() + ")",
ERROR_LOCATION);
return core::system::exitFailure(error, ERROR_LOCATION);
}

unsigned desiredMode = S_IRWXU | S_IRWXG | S_IRWXO | S_ISVTX;
if ((st.st_mode & desiredMode) != desiredMode)
{
// permissions aren't correct - attempt to fix them
Error error = core::system::changeFileMode(serverDataDir,
core::system::EveryoneReadWriteExecuteMode,
true);
if (error)
{
LOG_ERROR_MESSAGE("Could not change permissions for specified 'server-data-dir' - "
"the directory (" + serverDataDir.absolutePath() + ") must be "
"writeable by all users and have the sticky bit set");
return core::system::exitFailure(error, ERROR_LOCATION);
}
}

// export important environment variables
core::system::setenv(kSessionTmpDirEnvVar, sessionTmpDir().absolutePath());

// initialize File Lock
FileLock::initialize();

Expand Down Expand Up @@ -558,7 +605,7 @@ int main(int argc, char * const argv[])

// initialize monitor (needs to happen post http server init for access
// to the server's io service)
monitor::initializeMonitorClient(kMonitorSocketPath,
monitor::initializeMonitorClient(monitorSocketPath().absolutePath(),
server::options().monitorSharedSecret(),
s_pHttpServer->ioService());

Expand Down
11 changes: 9 additions & 2 deletions src/cpp/server/ServerOptions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,10 @@ ProgramStatus Options::read(int argc,
"set the umask to 022 on startup")
("secure-cookie-key-file",
value<std::string>(&secureCookieKeyFile_)->default_value(""),
"path override for secure cookie key");
"path override for secure cookie key")
("server-data-dir",
value<std::string>(&serverDataDir_)->default_value("/var/run/rstudio-server"),
"path to data directory where rstudio server will write run-time state");

// www - web server options
options_description www("www") ;
Expand Down Expand Up @@ -320,7 +323,7 @@ ProgramStatus Options::read(int argc,
value<int>(&authSignInThrottleSeconds_)->default_value(5),
"minimum amount of time a user must wait before attempting to sign in again")
("auth-revocation-list-dir",
value<std::string>(&authRevocationListDir_)->default_value("/var/run/rstudio-server"),
value<std::string>(&authRevocationListDir_)->default_value(""),
"path to the directory which contains the revocation list to be used for storing expired auth tokens")
("auth-cookies-force-secure",
value<bool>(&authCookiesForceSecure_)->default_value(false),
Expand Down Expand Up @@ -358,6 +361,10 @@ ProgramStatus Options::read(int argc,
// report deprecation warnings
reportDeprecationWarnings(dep, osWarnings);

// check auth revocation dir - if unspecified, it should be put under the server data dir
if (authRevocationListDir_.empty())
authRevocationListDir_ = serverDataDir_;

// call overlay hooks
resolveOverlayOptions();
std::string errMsg;
Expand Down
22 changes: 3 additions & 19 deletions src/cpp/server/auth/ServerAuthHandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -146,22 +146,6 @@ Error readRevocationList(std::vector<std::string>* pEntries)
return Success();
}

Error changeOwnership(const FilePath& file)
{
// changes ownership of file to the server user
core::system::user::User serverUser;
Error error = core::system::user::userFromUsername(options().serverUser(), &serverUser);
if (error)
return error;

return core::system::posixCall<int>(
boost::bind(::chown,
file.absolutePath().c_str(),
serverUser.userId,
serverUser.groupId),
ERROR_LOCATION);
}

} // anonymous namespace

namespace overlay {
Expand Down Expand Up @@ -410,7 +394,7 @@ Error initialize()
// create revocation list directory and ensure the server user has permission to write to it
// if the directory already exists, we will not attempt to change ownership as this means
// the directory was setup by an administrator and we should respect its permissions
FilePath rootDir(options().authRevocationListDir());
FilePath rootDir = options().authRevocationListDir();
if (!rootDir.exists())
{
Error error = rootDir.ensureDirectory();
Expand All @@ -422,7 +406,7 @@ Error initialize()

if (core::system::effectiveUserIsRoot())
{
error = changeOwnership(rootDir);
error = file_utils::changeOwnership(rootDir, options().serverUser());
if (error)
{
LOG_ERROR_MESSAGE("Could not change ownership of revocation list directory " + rootDir.absolutePath());
Expand Down Expand Up @@ -464,7 +448,7 @@ Error initialize()
{
// ensure revocation file is owned by the server user
// this ensures that it can be written to even when we drop privilege
error = changeOwnership(s_revocationList);
error = file_utils::changeOwnership(s_revocationList, options().serverUser());
if (error)
return error;
}
Expand Down
6 changes: 4 additions & 2 deletions src/cpp/server/include/server/ServerConstants.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,12 @@
#define SERVER_CONSTANTS_HPP

#define kRStudioSessionRequiredHeader "X-RStudio-Session-Required"
#define kRStudioServerLocalStream "/tmp/rstudio-rserver/rserver.socket"
#define kServerTmpDir "/tmp/rstudio-rserver"
#define kServerLocalSocket "rserver.socket"
#define kServerLocalSocketPathEnvVar "RS_SERVER_LOCAL_SOCKET_PATH"
#define kServerTmpDir "rstudio-rserver"
#define kUserIdCookie "user-id"
#define kPersistAuthCookie "persist-auth"
#define kServerTmpDirEnvVar "RS_SERVER_TMP_DIR"

#endif // SERVER_CONSTANTS_HPP

10 changes: 8 additions & 2 deletions src/cpp/server/include/server/ServerOptions.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,11 @@ class Options : boost::noncopyable

bool serverSetUmask() const { return serverSetUmask_; }

core::FilePath serverDataDir() const
{
return core::FilePath(serverDataDir_);
}

// www
std::string wwwAddress() const
{
Expand Down Expand Up @@ -194,9 +199,9 @@ class Options : boost::noncopyable
return std::string(authPamHelperPath_.c_str());
}

std::string authRevocationListDir() const
core::FilePath authRevocationListDir() const
{
return authRevocationListDir_;
return core::FilePath(authRevocationListDir_);
}

bool authPamRequirePasswordPrompt() const
Expand Down Expand Up @@ -304,6 +309,7 @@ class Options : boost::noncopyable
bool serverAppArmorEnabled_;
bool serverSetUmask_;
bool serverOffline_;
std::string serverDataDir_;
std::string wwwAddress_ ;
std::string wwwPort_ ;
std::string wwwLocalPath_ ;
Expand Down
43 changes: 43 additions & 0 deletions src/cpp/server/include/server/ServerPaths.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
* ServerPaths.hpp
*
* Copyright (C) 2019 by RStudio, Inc.
*
* Unless you have received this program directly from RStudio pursuant
* to the terms of a commercial license agreement with RStudio, then
* this program is licensed to you under the terms of version 3 of the
* GNU Affero General Public License. This program is distributed WITHOUT
* ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF NON-INFRINGEMENT,
* MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Please refer to the
* AGPL (http://www.gnu.org/licenses/agpl-3.0.txt) for more details.
*
*/

#ifndef SERVER_PATHS_HPP
#define SERVER_PATHS_HPP

#include <core/FilePath.hpp>

#include <monitor/MonitorConstants.hpp>

#include <server/ServerConstants.hpp>
#include <server/ServerOptions.hpp>

#include <session/SessionConstants.hpp>

namespace rstudio {
namespace server {

using namespace core;

inline FilePath serverTmpDir() { return options().serverDataDir().childPath(kServerTmpDir); }
inline FilePath serverLocalSocketPath() { return serverTmpDir().childPath(kServerLocalSocket); }
inline FilePath monitorSocketPath() { return serverTmpDir().childPath(kMonitorSocket); }
inline FilePath sessionTmpDir() { return options().serverDataDir().childPath(kSessionTmpDir); }

} // namespace server
} // namespace rstudio


#endif // SERVER_PATHS_HPP

Loading

0 comments on commit 0b964c6

Please sign in to comment.