// parameters.cpp /** * Copyright (C) 2012 10gen Inc. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License, version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . * * As a special exception, the copyright holders give permission to link the * code of portions of this program with the OpenSSL library under certain * conditions as described in each individual source file and distribute * linked combinations including the program with the OpenSSL library. You * must comply with the GNU Affero General Public License in all respects for * all of the code used other than as permitted herein. If you modify file(s) * with this exception, you may extend this exception to your version of the * file(s), but you are not obligated to do so. If you do not wish to do so, * delete this exception statement from your version. If you delete this * exception statement from all source files in the program, then also delete * it in the license file. */ #include "mongo/pch.h" #include "mongo/client/replica_set_monitor.h" #include "mongo/client/sasl_client_authenticate.h" #include "mongo/db/auth/authorization_manager.h" #include "mongo/db/auth/security_key.h" #include "mongo/db/commands.h" #include "mongo/db/server_parameters.h" #include "mongo/db/storage_options.h" #include "mongo/util/mongoutils/str.h" #include "mongo/util/net/ssl_manager.h" #include "mongo/util/net/ssl_options.h" namespace mongo { namespace { void appendParameterNames( stringstream& help ) { help << "supported:\n"; const ServerParameter::Map& m = ServerParameterSet::getGlobal()->getMap(); for ( ServerParameter::Map::const_iterator i = m.begin(); i != m.end(); ++i ) { help << " " << i->first << "\n"; } } } class CmdGet : public Command { public: CmdGet() : Command( "getParameter" ) { } virtual bool slaveOk() const { return true; } virtual bool adminOnly() const { return true; } virtual bool isWriteCommandForConfigServer() const { return false; } virtual void addRequiredPrivileges(const std::string& dbname, const BSONObj& cmdObj, std::vector* out) { ActionSet actions; actions.addAction(ActionType::getParameter); out->push_back(Privilege(ResourcePattern::forClusterResource(), actions)); } virtual void help( stringstream &help ) const { help << "get administrative option(s)\nexample:\n"; help << "{ getParameter:1, notablescan:1 }\n"; appendParameterNames( help ); help << "{ getParameter:'*' } to get everything\n"; } bool run(OperationContext* txn, const string& dbname, BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool fromRepl ) { bool all = *cmdObj.firstElement().valuestrsafe() == '*'; int before = result.len(); // TODO: convert to ServerParameters -- SERVER-10515 if (isJournalingEnabled() && (all || cmdObj.hasElement("journalCommitInterval")) && !isMongos()) { result.append("journalCommitInterval", getJournalCommitInterval()); } if( all || cmdObj.hasElement( "traceExceptions" ) ) { result.append("traceExceptions", DBException::traceExceptions); } if( all || cmdObj.hasElement( "replMonitorMaxFailedChecks" ) ) { result.append("replMonitorMaxFailedChecks", ReplicaSetMonitor::maxConsecutiveFailedChecks); } const ServerParameter::Map& m = ServerParameterSet::getGlobal()->getMap(); for ( ServerParameter::Map::const_iterator i = m.begin(); i != m.end(); ++i ) { if ( all || cmdObj.hasElement( i->first.c_str() ) ) { i->second->append( result, i->second->name() ); } } if ( before == result.len() ) { errmsg = "no option found to get"; return false; } return true; } } cmdGet; class CmdSet : public Command { public: CmdSet() : Command( "setParameter" ) { } virtual bool slaveOk() const { return true; } virtual bool adminOnly() const { return true; } virtual bool isWriteCommandForConfigServer() const { return false; } virtual void addRequiredPrivileges(const std::string& dbname, const BSONObj& cmdObj, std::vector* out) { ActionSet actions; actions.addAction(ActionType::setParameter); out->push_back(Privilege(ResourcePattern::forClusterResource(), actions)); } virtual void help( stringstream &help ) const { help << "set administrative option(s)\n"; help << "{ setParameter:1, : }\n"; appendParameterNames( help ); } bool run(OperationContext* txn, const string& dbname, BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool fromRepl ) { int s = 0; bool found = false; // TODO: convert to ServerParameters -- SERVER-10515 if( cmdObj.hasElement("journalCommitInterval") ) { if (isMongos()) { errmsg = "cannot set journalCommitInterval on a mongos"; return false; } if(!isJournalingEnabled()) { errmsg = "journaling is off"; return false; } int x = (int) cmdObj["journalCommitInterval"].Number(); verify( x > 1 && x < 500 ); setJournalCommitInterval(x); log() << "setParameter journalCommitInterval=" << x << endl; s++; } if( cmdObj.hasElement( "traceExceptions" ) ) { if( s == 0 ) result.append( "was", DBException::traceExceptions ); DBException::traceExceptions = cmdObj["traceExceptions"].Bool(); s++; } if( cmdObj.hasElement( "replMonitorMaxFailedChecks" ) ) { if( s == 0 ) result.append( "was", ReplicaSetMonitor::maxConsecutiveFailedChecks ); ReplicaSetMonitor::maxConsecutiveFailedChecks = cmdObj["replMonitorMaxFailedChecks"].numberInt(); s++; } const ServerParameter::Map& m = ServerParameterSet::getGlobal()->getMap(); BSONObjIterator i( cmdObj ); i.next(); // skip past command name while ( i.more() ) { BSONElement e = i.next(); ServerParameter::Map::const_iterator j = m.find( e.fieldName() ); if ( j == m.end() ) continue; if ( ! j->second->allowedToChangeAtRuntime() ) { errmsg = str::stream() << "not allowed to change [" << e.fieldName() << "] at runtime"; return false; } if ( s == 0 ) j->second->append( result, "was" ); Status status = j->second->set( e ); if ( status.isOK() ) { s++; continue; } errmsg = status.reason(); result.append( "code", status.code() ); return false; } if( s == 0 && !found ) { errmsg = "no option found to set, use help:true to see options "; return false; } return true; } } cmdSet; namespace { class LogLevelSetting : public ServerParameter { public: LogLevelSetting() : ServerParameter(ServerParameterSet::getGlobal(), "logLevel") {} virtual void append(BSONObjBuilder& b, const std::string& name) { b << name << logger::globalLogDomain()->getMinimumLogSeverity().toInt(); } virtual Status set(const BSONElement& newValueElement) { typedef logger::LogSeverity LogSeverity; int newValue; if (!newValueElement.coerce(&newValue) || newValue < 0) return Status(ErrorCodes::BadValue, mongoutils::str::stream() << "Invalid value for logLevel: " << newValueElement); LogSeverity newSeverity = (newValue > 0) ? LogSeverity::Debug(newValue) : LogSeverity::Log(); logger::globalLogDomain()->setMinimumLoggedSeverity(newSeverity); return Status::OK(); } virtual Status setFromString(const std::string& str) { typedef logger::LogSeverity LogSeverity; int newValue; Status status = parseNumberFromString(str, &newValue); if (!status.isOK()) return status; if (newValue < 0) return Status(ErrorCodes::BadValue, mongoutils::str::stream() << "Invalid value for logLevel: " << newValue); LogSeverity newSeverity = (newValue > 0) ? LogSeverity::Debug(newValue) : LogSeverity::Log(); logger::globalLogDomain()->setMinimumLoggedSeverity(newSeverity); return Status::OK(); } } logLevelSetting; class SSLModeSetting : public ServerParameter { public: SSLModeSetting() : ServerParameter(ServerParameterSet::getGlobal(), "sslMode", false, // allowedToChangeAtStartup true // allowedToChangeAtRuntime ) {} std::string sslModeStr() { switch (sslGlobalParams.sslMode.load()) { case SSLGlobalParams::SSLMode_disabled: return "disabled"; case SSLGlobalParams::SSLMode_allowSSL: return "allowSSL"; case SSLGlobalParams::SSLMode_preferSSL: return "preferSSL"; case SSLGlobalParams::SSLMode_requireSSL: return "requireSSL"; default: return "undefined"; } } virtual void append(BSONObjBuilder& b, const std::string& name) { b << name << sslModeStr(); } virtual Status set(const BSONElement& newValueElement) { try { return setFromString(newValueElement.String()); } catch (MsgAssertionException msg) { return Status(ErrorCodes::BadValue, mongoutils::str::stream() << "Invalid value for sslMode via setParameter command: " << newValueElement); } } virtual Status setFromString(const std::string& str) { #ifndef MONGO_SSL return Status(ErrorCodes::IllegalOperation, mongoutils::str::stream() << "Unable to set sslMode, SSL support is not compiled into server"); #endif if (str != "disabled" && str != "allowSSL" && str != "preferSSL" && str != "requireSSL") { return Status(ErrorCodes::BadValue, mongoutils::str::stream() << "Invalid value for sslMode via setParameter command: " << str); } int oldMode = sslGlobalParams.sslMode.load(); if (str == "preferSSL" && oldMode == SSLGlobalParams::SSLMode_allowSSL) { sslGlobalParams.sslMode.store(SSLGlobalParams::SSLMode_preferSSL); } else if (str == "requireSSL" && oldMode == SSLGlobalParams::SSLMode_preferSSL) { sslGlobalParams.sslMode.store(SSLGlobalParams::SSLMode_requireSSL); } else { return Status(ErrorCodes::BadValue, mongoutils::str::stream() << "Illegal state transition for sslMode, attempt to change from " << sslModeStr() << " to " << str); } return Status::OK(); } } sslModeSetting; class ClusterAuthModeSetting : public ServerParameter { public: ClusterAuthModeSetting() : ServerParameter(ServerParameterSet::getGlobal(), "clusterAuthMode", false, // allowedToChangeAtStartup true // allowedToChangeAtRuntime ) {} std::string clusterAuthModeStr() { switch (serverGlobalParams.clusterAuthMode.load()) { case ServerGlobalParams::ClusterAuthMode_keyFile: return "keyFile"; case ServerGlobalParams::ClusterAuthMode_sendKeyFile: return "sendKeyFile"; case ServerGlobalParams::ClusterAuthMode_sendX509: return "sendX509"; case ServerGlobalParams::ClusterAuthMode_x509: return "x509"; default: return "undefined"; } } virtual void append(BSONObjBuilder& b, const std::string& name) { b << name << clusterAuthModeStr(); } virtual Status set(const BSONElement& newValueElement) { try { return setFromString(newValueElement.String()); } catch (MsgAssertionException msg) { return Status(ErrorCodes::BadValue, mongoutils::str::stream() << "Invalid value for clusterAuthMode via setParameter command: " << newValueElement); } } virtual Status setFromString(const std::string& str) { #ifndef MONGO_SSL return Status(ErrorCodes::IllegalOperation, mongoutils::str::stream() << "Unable to set clusterAuthMode, " << "SSL support is not compiled into server"); #endif if (str != "keyFile" && str != "sendKeyFile" && str != "sendX509" && str != "x509") { return Status(ErrorCodes::BadValue, mongoutils::str::stream() << "Invalid value for clusterAuthMode via setParameter command: " << str); } int oldMode = serverGlobalParams.clusterAuthMode.load(); int sslMode = sslGlobalParams.sslMode.load(); if (str == "sendX509" && oldMode == ServerGlobalParams::ClusterAuthMode_sendKeyFile) { if (sslMode == SSLGlobalParams::SSLMode_disabled || sslMode == SSLGlobalParams::SSLMode_allowSSL) { return Status(ErrorCodes::BadValue, mongoutils::str::stream() << "Illegal state transition for clusterAuthMode, " << "need to enable SSL for outgoing connections"); } serverGlobalParams.clusterAuthMode.store (ServerGlobalParams::ClusterAuthMode_sendX509); #ifdef MONGO_SSL setInternalUserAuthParams(BSON(saslCommandMechanismFieldName << "MONGODB-X509" << saslCommandUserDBFieldName << "$external" << saslCommandUserFieldName << getSSLManager()->getClientSubjectName())); #endif } else if (str == "x509" && oldMode == ServerGlobalParams::ClusterAuthMode_sendX509) { serverGlobalParams.clusterAuthMode.store (ServerGlobalParams::ClusterAuthMode_x509); } else { return Status(ErrorCodes::BadValue, mongoutils::str::stream() << "Illegal state transition for clusterAuthMode, change from " << clusterAuthModeStr() << " to " << str); } return Status::OK(); } } clusterAuthModeSetting; ExportedServerParameter QuietSetting( ServerParameterSet::getGlobal(), "quiet", &serverGlobalParams.quiet, true, true ); } }