Vidalia 0.2.12

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