Vidalia  0.2.15
TorSettings.cpp
Go to the documentation of this file.
00001 /*
00002 **  This file is part of Vidalia, and is subject to the license terms in the
00003 **  LICENSE file, found in the top level directory of this distribution. If you
00004 **  did not receive the LICENSE file with this file, you may obtain it from the
00005 **  Vidalia source package distributed by the Vidalia Project at
00006 **  http://www.torproject.org/projects/vidalia.html. No part of Vidalia, 
00007 **  including this file, may be copied, modified, propagated, or distributed 
00008 **  except according to the terms described in the LICENSE file.
00009 */
00010 
00011 /*
00012 ** \file TorSettings.cpp
00013 ** \brief Settings used for starting and running Tor
00014 */
00015 
00016 #include "TorSettings.h"
00017 #include "Vidalia.h"
00018 #include "crypto.h"
00019 #include "file.h"
00020 #include "stringutil.h"
00021 #if defined(Q_OS_WIN32)
00022 #include "win32.h"
00023 #include <QFileInfo>
00024 #endif
00025 
00026 #include <QDir>
00027 #include <QProcess>
00028 
00029 /* Tor Settings */
00030 #define SETTING_TOR_EXECUTABLE      "TorExecutable"
00031 #define SETTING_TORRC               "Torrc"
00032 #define SETTING_CONTROL_ADDR        "ControlAddr"
00033 #define SETTING_CONTROL_PORT        "ControlPort"
00034 #define SETTING_SOCKET_PATH         "ControlSocket"
00035 #define SETTING_CONTROL_METHOD      "ControlMethod"
00036 #define SETTING_AUTH_TOKEN          "AuthToken"
00037 #define SETTING_TOR_USER            "User"
00038 #define SETTING_TOR_GROUP           "Group"
00039 #define SETTING_DATA_DIRECTORY      "DataDirectory"
00040 #define SETTING_AUTH_METHOD         "AuthenticationMethod"
00041 #define SETTING_CONTROL_PASSWORD    "ControlPassword"
00042 #define SETTING_USE_RANDOM_PASSWORD "UseRandomPassword"
00043 #define SETTING_WARN_PLAINTEXT_PORTS    "WarnPlaintextPorts"
00044 #define SETTING_REJECT_PLAINTEXT_PORTS  "RejectPlaintextPorts"
00045 #define SETTING_BOOTSTRAP            "Bootstrap"
00046 #define SETTING_BOOTSTRAP_FROM       "BootstrapFrom"
00047 #define SETTING_AUTOCONTROL          "AutoControl"
00048 
00049 /** Default to using hashed password authentication */
00050 #define DEFAULT_AUTH_METHOD     PasswordAuth
00051 /** Default control method */
00052 #define DEFAULT_CONTROL_METHOD  "ControlPort"
00053 /** Default socket path */
00054 #define DEFAULT_SOCKET_PATH  ""
00055 
00056 /* Arguments we can pass to Tor on the command-line */
00057 #define TOR_ARG_CONTROL_PORT    "ControlPort"
00058 #define TOR_ARG_TORRC           "-f"
00059 #define TOR_ARG_DATA_DIRECTORY  "DataDirectory"
00060 #define TOR_ARG_HASHED_PASSWORD "HashedControlPassword"
00061 #define TOR_ARG_COOKIE_AUTH     "CookieAuthentication"
00062 
00063 /** Generate random control passwords of 16 characters */
00064 #define PASSWORD_LEN    16
00065 
00066 
00067 /** Default constructor */
00068 TorSettings::TorSettings(TorControl *torControl)
00069 : AbstractTorSettings("Tor", torControl)
00070 {
00071 #if defined(Q_OS_WIN32)
00072   QString programFiles = win32_program_files_folder();
00073   if (QFileInfo(programFiles + "\\Vidalia Bundle\\Tor\\tor.exe").exists())
00074     setDefault(SETTING_TOR_EXECUTABLE,
00075                programFiles + "\\Vidalia Bundle\\Tor\\tor.exe");
00076   else
00077     setDefault(SETTING_TOR_EXECUTABLE, programFiles + "\\Tor\\tor.exe");
00078 #else
00079   setDefault(SETTING_TOR_EXECUTABLE, "tor");
00080 #endif
00081 
00082   setDefault(SETTING_TORRC,         Vidalia::dataDirectory() + "/torrc");
00083   setDefault(SETTING_CONTROL_ADDR,  "127.0.0.1");
00084   setDefault(SETTING_CONTROL_PORT,  9051);
00085   setDefault(SETTING_AUTH_METHOD,   toString(DEFAULT_AUTH_METHOD));
00086   setDefault(SETTING_CONTROL_METHOD, DEFAULT_CONTROL_METHOD);
00087   setDefault(SETTING_SOCKET_PATH, DEFAULT_SOCKET_PATH);
00088   setDefault(SETTING_DATA_DIRECTORY, "");
00089   setDefault(SETTING_CONTROL_PASSWORD, "");
00090   setDefault(SETTING_USE_RANDOM_PASSWORD, true);
00091   setDefault(SETTING_WARN_PLAINTEXT_PORTS, QList<QVariant>() << 23 << 109 
00092                                                              << 110 << 143);
00093   setDefault(SETTING_REJECT_PLAINTEXT_PORTS, QList<QVariant>());
00094   setDefault(SETTING_BOOTSTRAP, false);
00095   setDefault(SETTING_BOOTSTRAP_FROM, "");
00096   setDefault(SETTING_AUTOCONTROL, false);
00097 }
00098 
00099 /** Applies any changes to Tor's control port or authentication settings. */
00100 bool
00101 TorSettings::apply(QString *errmsg)
00102 {
00103   QHash<QString, QString> conf;
00104   QString hashedPassword;
00105 
00106   conf.insert(SETTING_CONTROL_PORT,
00107               localValue(SETTING_CONTROL_PORT).toString());
00108   
00109   AuthenticationMethod authMethod = 
00110     toAuthenticationMethod(localValue(SETTING_AUTH_METHOD).toString());
00111   switch (authMethod) {
00112     case CookieAuth:
00113       conf.insert(TOR_ARG_COOKIE_AUTH,    "1");
00114       conf.insert(TOR_ARG_HASHED_PASSWORD, "");
00115       break;
00116     case PasswordAuth:
00117       hashedPassword = useRandomPassword() 
00118                           ? hashPassword(randomPassword())
00119                           : hashPassword(getControlPassword());
00120       if (hashedPassword.isEmpty()) {
00121         if (errmsg)
00122           *errmsg =  tr("Failed to hash the control password.");
00123         return false;
00124       }
00125       conf.insert(TOR_ARG_COOKIE_AUTH,    "0");
00126       conf.insert(TOR_ARG_HASHED_PASSWORD, hashedPassword);
00127       break;
00128     default:
00129       conf.insert(TOR_ARG_COOKIE_AUTH,    "0");
00130       conf.insert(TOR_ARG_HASHED_PASSWORD, "");
00131   }
00132 
00133   conf.insert(SETTING_WARN_PLAINTEXT_PORTS,
00134               localValue(SETTING_WARN_PLAINTEXT_PORTS).toStringList().join(","));
00135   conf.insert(SETTING_REJECT_PLAINTEXT_PORTS,
00136               localValue(SETTING_REJECT_PLAINTEXT_PORTS).toStringList().join(","));
00137 
00138   return torControl()->setConf(conf, errmsg);
00139 }
00140 
00141 /** Gets the location of Tor's data directory. */
00142 QString
00143 TorSettings::getDataDirectory() const
00144 {
00145   return QDir::convertSeparators(value(SETTING_DATA_DIRECTORY).toString());
00146 }
00147 
00148 /** Sets the location to use as Tor's data directory. */
00149 void
00150 TorSettings::setDataDirectory(const QString &dataDirectory)
00151 {
00152   setValue(SETTING_DATA_DIRECTORY, dataDirectory);
00153 }
00154 
00155 /** Returns a fully-qualified path to Tor's executable, including the
00156  * executable name. */
00157 QString
00158 TorSettings::getExecutable() const
00159 {
00160   QString tor = localValue(SETTING_TOR_EXECUTABLE).toString();
00161   if (tor.isEmpty()) /* Don't let the Tor executable name be empty */
00162     tor = defaultValue(SETTING_TOR_EXECUTABLE).toString();
00163   return QDir::convertSeparators(tor);
00164 }
00165 
00166 /** Sets the location and name of Tor's executable to the given string. */
00167 void
00168 TorSettings::setExecutable(const QString &torExecutable)
00169 {
00170   setValue(SETTING_TOR_EXECUTABLE, torExecutable);
00171 }
00172 
00173 /** Returns the torrc that will be used when starting Tor. */
00174 QString
00175 TorSettings::getTorrc() const
00176 {
00177   QString torrc;
00178   TorControl *tc = torControl();
00179   if (tc && tc->isConnected() && tc->getInfo("config-file", torrc))
00180     return QDir::convertSeparators(torrc);
00181   return QDir::convertSeparators(localValue(SETTING_TORRC).toString());
00182 }
00183 
00184 /** Sets the torrc that will be used when starting Tor.
00185  * \param torrc The torrc to use. 
00186  */
00187 void
00188 TorSettings::setTorrc(const QString &torrc)
00189 {
00190   setValue(SETTING_TORRC, torrc);
00191 }
00192 
00193 /** Get the address or hostname used to connect to Tor */
00194 QHostAddress
00195 TorSettings::getControlAddress() const
00196 {
00197   QString addr = localValue(SETTING_CONTROL_ADDR).toString();
00198   return QHostAddress(addr);
00199 }
00200 
00201 /** Set the address or hostname used to connect to Tor */
00202 void
00203 TorSettings::setControlAddress(const QHostAddress &addr)
00204 {
00205   setValue(SETTING_CONTROL_ADDR, addr.toString());
00206 }
00207 
00208 /** Get the control port used to connect to Tor */
00209 quint16
00210 TorSettings::getControlPort() const
00211 {
00212   return (quint16)value(SETTING_CONTROL_PORT).toInt();
00213 }
00214 
00215 /** Set the control port used to connect to Tor */
00216 void
00217 TorSettings::setControlPort(quint16 port)
00218 {
00219   setValue(SETTING_CONTROL_PORT, port);
00220 }
00221 
00222 /** Get the path for ControlSocket */
00223 QString 
00224 TorSettings::getSocketPath() const
00225 {
00226   return value(SETTING_SOCKET_PATH).toString();
00227 }
00228 
00229 /** Set the path for ControlSocket */
00230 void 
00231 TorSettings::setSocketPath(const QString &path)
00232 {
00233   setValue(SETTING_SOCKET_PATH, path);
00234 }
00235 
00236 /** Get the current control method */
00237 ControlMethod::Method
00238 TorSettings::getControlMethod() const
00239 {
00240   return ControlMethod::fromString(localValue(SETTING_CONTROL_METHOD).toString());
00241 }
00242 
00243 /** Set the control method */
00244 void 
00245 TorSettings::setControlMethod(ControlMethod::Method method)
00246 {
00247   setValue(SETTING_CONTROL_METHOD, ControlMethod::toString(method));
00248 }
00249 
00250 /** Returns the plaintext (i.e., not hashed) control password used when
00251  * authenticating to Tor. */
00252 QString
00253 TorSettings::getControlPassword() const
00254 {
00255   return localValue(SETTING_CONTROL_PASSWORD).toString();
00256 }
00257 
00258 /** Sets the control password used when starting Tor with
00259  * HashedControlPassword to <b>password</b>. */
00260 void
00261 TorSettings::setControlPassword(const QString &password)
00262 {
00263   setValue(SETTING_CONTROL_PASSWORD, password);
00264 }
00265 
00266 /** Returns true if a new, random control password is to be used each time Tor
00267  * is started. */
00268 bool
00269 TorSettings::useRandomPassword() const
00270 {
00271   return localValue(SETTING_USE_RANDOM_PASSWORD).toBool();
00272 }
00273 
00274 /** Sets whether or not to generate and use a random control password each
00275  * time Tor is started. */
00276 void
00277 TorSettings::setUseRandomPassword(bool useRandomPassword)
00278 {
00279   setValue(SETTING_USE_RANDOM_PASSWORD, useRandomPassword);
00280 }
00281 
00282 /** Returns the current authentication method used when connecting to Tor. */
00283 TorSettings::AuthenticationMethod
00284 TorSettings::getAuthenticationMethod() const
00285 {
00286   AuthenticationMethod type = UnknownAuth;
00287   TorControl *tc = torControl();
00288 
00289   if (tc && tc->isConnected()) {
00290     QHash<QString,QString> conf;
00291     conf.insert(TOR_ARG_COOKIE_AUTH, "");
00292     conf.insert(TOR_ARG_HASHED_PASSWORD, "");
00293     if (tc->getConf(conf)) {
00294       if (conf.value(TOR_ARG_COOKIE_AUTH) == "1")
00295         type = CookieAuth;
00296       else if (!conf.value(TOR_ARG_HASHED_PASSWORD).isEmpty())
00297         type = PasswordAuth;
00298     }
00299   }
00300   if (type == UnknownAuth)
00301     type = toAuthenticationMethod(localValue(SETTING_AUTH_METHOD).toString());
00302   return (type == UnknownAuth ? DEFAULT_AUTH_METHOD : type);
00303 }
00304 
00305 /** Sets the authentication method used when starting Tor to <b>method</b>. */
00306 void
00307 TorSettings::setAuthenticationMethod(AuthenticationMethod method)
00308 {
00309   setValue(SETTING_AUTH_METHOD, toString(method));
00310 }
00311 
00312 /** Returns the current list of ports that will cause Tor to issue a warning
00313  * when the user tries to connect to one of them. */
00314 QList<quint16>
00315 TorSettings::getWarnPlaintextPorts() const
00316 {
00317   QList<quint16> out;
00318   QList<QVariant> ports;
00319 
00320   ports = value(SETTING_WARN_PLAINTEXT_PORTS).toList();
00321   foreach (QVariant port, ports) {
00322     out << port.toUInt();
00323   }
00324   return out;
00325 }
00326 
00327 /** Sets the list of ports that will cause Tor to issue a warning when the
00328  * user tries to connect to one of them. */
00329 void
00330 TorSettings::setWarnPlaintextPorts(const QList<quint16> &ports)
00331 {
00332   QList<QVariant> warnList;
00333   foreach (quint16 port, ports) {
00334     warnList << QVariant(port);
00335   }
00336   setValue(SETTING_WARN_PLAINTEXT_PORTS, warnList);
00337 }
00338 
00339 /** Returns the current list of ports that will cause Tor to reject the
00340  * connection when the user tries to connect to one of them. */
00341 QList<quint16>
00342 TorSettings::getRejectPlaintextPorts() const
00343 {
00344   QList<quint16> out;
00345   QList<QVariant> ports;
00346 
00347   ports = value(SETTING_REJECT_PLAINTEXT_PORTS).toList();
00348   foreach (QVariant port, ports) {
00349     out << port.toUInt();
00350   }
00351   return out;
00352 }
00353 
00354 /** Sets the list of ports that will cause Tor to reject the connection
00355  * when the user tries to connect to one of them. */
00356 void
00357 TorSettings::setRejectPlaintextPorts(const QList<quint16> &ports)
00358 {
00359   QList<QVariant> rejectList;
00360   foreach (quint16 port, ports) {
00361     rejectList << QVariant(port);
00362   }
00363   setValue(SETTING_REJECT_PLAINTEXT_PORTS, rejectList);
00364 }
00365 
00366 /** Returns the string description of the authentication method specified by
00367  * <b>method</b>. The authentication method string is stored in Vidalia's
00368  * configuration file. */
00369 QString
00370 TorSettings::toString(AuthenticationMethod method) const
00371 {
00372   switch (method) {
00373     case NullAuth:  return "none";
00374     case PasswordAuth:  return "password";
00375     case CookieAuth:  return "cookie";
00376     default: break;
00377   }
00378   return "unknown";
00379 }
00380 
00381 /** Returns the AuthenticationMethod enum value for the string
00382  * description of the authentication method given in <b>authMethod</b>. */
00383 TorSettings::AuthenticationMethod
00384 TorSettings::toAuthenticationMethod(const QString &authMethod) const
00385 { 
00386   QString str = authMethod.toLower();
00387   if (str == toString(NullAuth))
00388     return NullAuth;
00389   else if (str == toString(PasswordAuth))
00390     return PasswordAuth;
00391   else if (str == toString(CookieAuth))
00392     return CookieAuth;
00393   return UnknownAuth;
00394 }
00395 
00396 /** Generates a random control password consisting of PASSWORD_LEN characters. */
00397 QString
00398 TorSettings::randomPassword()
00399 {
00400   return crypto_rand_string(PASSWORD_LEN);
00401 }
00402 
00403 /** Returns the hash of <b>password</b> as given by the command "tor
00404  * --hash-password foo". */
00405 QString
00406 TorSettings::hashPassword(const QString &password)
00407 {
00408   QByteArray salt;
00409   
00410   /* Generate an 8 octet salt value. Bail if we fail to generate enough
00411    * random bytes (unlikely). */
00412   while (salt.size() < 8) {
00413     QByteArray bytes = crypto_rand_bytes(8-salt.size());
00414     if (bytes.isNull())
00415       return QString();
00416     salt.append(bytes);
00417   }
00418 
00419   /* Generate the salted hash of the specified password. 96 is the one-octet
00420    * RFC 2440 coded count value hardcoded into Tor. Specifies that we should
00421    * hash 64K worth of data. */
00422   QByteArray key = crypto_secret_to_key(password, salt, 96);
00423   if (key.isNull())
00424     return QString();
00425   salt.append(96); /* Append the coded count value to the salt */
00426 
00427   /* Convert the result to hexadecimal and put it in the format Tor wants. */
00428   return QString("16:%1%2").arg(base16_encode(salt))
00429                            .arg(base16_encode(key));
00430 }
00431 
00432 void
00433 TorSettings::setBootstrap(bool enabled)
00434 {
00435   setValue(SETTING_BOOTSTRAP, enabled);
00436 }
00437 
00438 bool
00439 TorSettings::bootstrap() const
00440 {
00441   return value(SETTING_BOOTSTRAP).toBool();
00442 }
00443 
00444 void
00445 TorSettings::setBootstrapFrom(const QString &from)
00446 {
00447   setValue(SETTING_BOOTSTRAP_FROM, from);
00448 }
00449 
00450 QString
00451 TorSettings::bootstrapFrom() const
00452 {
00453   return QDir::convertSeparators(value(SETTING_BOOTSTRAP_FROM).toString());
00454 }
00455 
00456 bool 
00457 TorSettings::autoControlPort() const
00458 {
00459   return value(SETTING_AUTOCONTROL).toBool();
00460 }
00461 
00462 void 
00463 TorSettings::setAutoControlPort(const bool autoControl)
00464 {
00465   setValue(SETTING_AUTOCONTROL, autoControl);
00466 }