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 ** \version $Id: torsettings.cpp 3755 2009-05-02 02:57:49Z edmanm $
00014 ** \brief Settings used for starting and running Tor
00015 */
00016 
00017 #include <QDir>
00018 #include <QProcess>
00019 #include <crypto.h>
00020 #include <vidalia.h>
00021 
00022 #if defined(Q_OS_WIN32)
00023 #include <QFileInfo>
00024 #include <win32.h>
00025 #endif
00026 
00027 #include "torsettings.h"
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_AUTH_TOKEN          "AuthToken"
00035 #define SETTING_TOR_USER            "User"
00036 #define SETTING_TOR_GROUP           "Group"
00037 #define SETTING_DATA_DIRECTORY      "DataDirectory"
00038 #define SETTING_AUTH_METHOD         "AuthenticationMethod"
00039 #define SETTING_CONTROL_PASSWORD    "ControlPassword"
00040 #define SETTING_USE_RANDOM_PASSWORD "UseRandomPassword"
00041 
00042 /** Default to using hashed password authentication */
00043 #define DEFAULT_AUTH_METHOD     PasswordAuth
00044 
00045 /* Arguments we can pass to Tor on the command-line */
00046 #define TOR_ARG_CONTROL_PORT    "ControlPort"
00047 #define TOR_ARG_TORRC           "-f"
00048 #define TOR_ARG_DATA_DIRECTORY  "DataDirectory"
00049 #define TOR_ARG_HASHED_PASSWORD "HashedControlPassword"
00050 #define TOR_ARG_COOKIE_AUTH     "CookieAuthentication"
00051 
00052 /** Generate random control passwords of 16 characters */
00053 #define PASSWORD_LEN    16
00054 
00055 
00056 /** Default constructor */
00057 TorSettings::TorSettings(TorControl *torControl)
00058 : AbstractTorSettings("Tor", torControl)
00059 {
00060 #if defined(Q_OS_WIN32)
00061   QString programFiles = win32_program_files_folder();
00062   if (QFileInfo(programFiles + "\\Vidalia Bundle\\Tor\\tor.exe").exists())
00063     setDefault(SETTING_TOR_EXECUTABLE,
00064                programFiles + "\\Vidalia Bundle\\Tor\\tor.exe");
00065   else
00066     setDefault(SETTING_TOR_EXECUTABLE, programFiles + "\\Tor\\tor.exe");
00067 #else
00068   setDefault(SETTING_TOR_EXECUTABLE, "tor");
00069 #endif
00070 
00071   setDefault(SETTING_TORRC,         Vidalia::dataDirectory() + "/torrc");
00072   setDefault(SETTING_CONTROL_ADDR,  "127.0.0.1");
00073   setDefault(SETTING_CONTROL_PORT,  9051);
00074   setDefault(SETTING_AUTH_METHOD,   toString(DEFAULT_AUTH_METHOD));
00075   setDefault(SETTING_DATA_DIRECTORY, "");
00076   setDefault(SETTING_CONTROL_PASSWORD, "");
00077   setDefault(SETTING_USE_RANDOM_PASSWORD, true);
00078 }
00079 
00080 /** Applies any changes to Tor's control port or authentication settings. */
00081 bool
00082 TorSettings::apply(QString *errmsg)
00083 {
00084   QHash<QString, QString> conf;
00085   QString hashedPassword;
00086 
00087   conf.insert(SETTING_CONTROL_PORT,
00088               localValue(SETTING_CONTROL_PORT).toString());
00089   
00090   AuthenticationMethod authMethod = 
00091     toAuthenticationMethod(localValue(SETTING_AUTH_METHOD).toString());
00092   switch (authMethod) {
00093     case CookieAuth:
00094       conf.insert(TOR_ARG_COOKIE_AUTH,    "1");
00095       conf.insert(TOR_ARG_HASHED_PASSWORD, "");
00096       break;
00097     case PasswordAuth:
00098       hashedPassword = useRandomPassword() 
00099                           ? hashPassword(randomPassword())
00100                           : hashPassword(getControlPassword());
00101       if (hashedPassword.isEmpty()) {
00102         if (errmsg)
00103           *errmsg =  tr("Failed to hash the control password.");
00104         return false;
00105       }
00106       conf.insert(TOR_ARG_COOKIE_AUTH,    "0");
00107       conf.insert(TOR_ARG_HASHED_PASSWORD, hashedPassword);
00108       break;
00109     default:
00110       conf.insert(TOR_ARG_COOKIE_AUTH,    "0");
00111       conf.insert(TOR_ARG_HASHED_PASSWORD, "");
00112   }
00113   return torControl()->setConf(conf, errmsg);
00114 }
00115 
00116 /** Gets the location of Tor's data directory. */
00117 QString
00118 TorSettings::getDataDirectory() const
00119 {
00120   return QDir::convertSeparators(value(SETTING_DATA_DIRECTORY).toString());
00121 }
00122 
00123 /** Sets the location to use as Tor's data directory. */
00124 void
00125 TorSettings::setDataDirectory(const QString &dataDirectory)
00126 {
00127   setValue(SETTING_DATA_DIRECTORY, dataDirectory);
00128 }
00129 
00130 /** Returns a fully-qualified path to Tor's executable, including the
00131  * executable name. */
00132 QString
00133 TorSettings::getExecutable() const
00134 {
00135   QString tor = localValue(SETTING_TOR_EXECUTABLE).toString();
00136   if (tor.isEmpty()) /* Don't let the Tor executable name be empty */
00137     tor = defaultValue(SETTING_TOR_EXECUTABLE).toString();
00138   return QDir::convertSeparators(tor);
00139 }
00140 
00141 /** Sets the location and name of Tor's executable to the given string. */
00142 void
00143 TorSettings::setExecutable(const QString &torExecutable)
00144 {
00145   setValue(SETTING_TOR_EXECUTABLE, torExecutable);
00146 }
00147 
00148 /** Returns the torrc that will be used when starting Tor. */
00149 QString
00150 TorSettings::getTorrc() const
00151 {
00152   QString torrc;
00153   TorControl *tc = torControl();
00154   if (tc && tc->isConnected() && tc->getInfo("config-file", torrc))
00155     return QDir::convertSeparators(torrc);
00156   return QDir::convertSeparators(localValue(SETTING_TORRC).toString());
00157 }
00158 
00159 /** Sets the torrc that will be used when starting Tor.
00160  * \param torrc The torrc to use. 
00161  */
00162 void
00163 TorSettings::setTorrc(const QString &torrc)
00164 {
00165   setValue(SETTING_TORRC, torrc);
00166 }
00167 
00168 /** Get the address or hostname used to connect to Tor */
00169 QHostAddress
00170 TorSettings::getControlAddress() const
00171 {
00172   QString addr = localValue(SETTING_CONTROL_ADDR).toString();
00173   return QHostAddress(addr);
00174 }
00175 
00176 /** Set the address or hostname used to connect to Tor */
00177 void
00178 TorSettings::setControlAddress(const QHostAddress &addr)
00179 {
00180   setValue(SETTING_CONTROL_ADDR, addr.toString());
00181 }
00182 
00183 /** Get the control port used to connect to Tor */
00184 quint16
00185 TorSettings::getControlPort() const
00186 {
00187   return (quint16)value(SETTING_CONTROL_PORT).toInt();
00188 }
00189 
00190 /** Set the control port used to connect to Tor */
00191 void
00192 TorSettings::setControlPort(quint16 port)
00193 {
00194   setValue(SETTING_CONTROL_PORT, port);
00195 }
00196 
00197 /** Returns the plaintext (i.e., not hashed) control password used when
00198  * authenticating to Tor. */
00199 QString
00200 TorSettings::getControlPassword() const
00201 {
00202   return localValue(SETTING_CONTROL_PASSWORD).toString();
00203 }
00204 
00205 /** Sets the control password used when starting Tor with
00206  * HashedControlPassword to <b>password</b>. */
00207 void
00208 TorSettings::setControlPassword(const QString &password)
00209 {
00210   setValue(SETTING_CONTROL_PASSWORD, password);
00211 }
00212 
00213 /** Returns true if a new, random control password is to be used each time Tor
00214  * is started. */
00215 bool
00216 TorSettings::useRandomPassword() const
00217 {
00218   return localValue(SETTING_USE_RANDOM_PASSWORD).toBool();
00219 }
00220 
00221 /** Sets whether or not to generate and use a random control password each
00222  * time Tor is started. */
00223 void
00224 TorSettings::setUseRandomPassword(bool useRandomPassword)
00225 {
00226   setValue(SETTING_USE_RANDOM_PASSWORD, useRandomPassword);
00227 }
00228 
00229 /** Returns the current authentication method used when connecting to Tor. */
00230 TorSettings::AuthenticationMethod
00231 TorSettings::getAuthenticationMethod() const
00232 {
00233   AuthenticationMethod type = UnknownAuth;
00234   TorControl *tc = torControl();
00235 
00236   if (tc && tc->isConnected()) {
00237     QHash<QString,QString> conf;
00238     conf.insert(TOR_ARG_COOKIE_AUTH, "");
00239     conf.insert(TOR_ARG_HASHED_PASSWORD, "");
00240     if (tc->getConf(conf)) {
00241       if (conf.value(TOR_ARG_COOKIE_AUTH) == "1")
00242         type = CookieAuth;
00243       else if (!conf.value(TOR_ARG_HASHED_PASSWORD).isEmpty())
00244         type = PasswordAuth;
00245     }
00246   }
00247   if (type == UnknownAuth)
00248     type = toAuthenticationMethod(localValue(SETTING_AUTH_METHOD).toString());
00249   return (type == UnknownAuth ? DEFAULT_AUTH_METHOD : type);
00250 }
00251 
00252 /** Sets the authentication method used when starting Tor to <b>method</b>. */
00253 void
00254 TorSettings::setAuthenticationMethod(AuthenticationMethod method)
00255 {
00256   setValue(SETTING_AUTH_METHOD, toString(method));
00257 }
00258 
00259 /** Returns the string description of the authentication method specified by
00260  * <b>method</b>. The authentication method string is stored in Vidalia's
00261  * configuration file. */
00262 QString
00263 TorSettings::toString(AuthenticationMethod method) const
00264 {
00265   switch (method) {
00266     case NullAuth:  return "none";
00267     case PasswordAuth:  return "password";
00268     case CookieAuth:  return "cookie";
00269     default: break;
00270   }
00271   return "unknown";
00272 }
00273 
00274 /** Returns the AuthenticationMethod enum value for the string
00275  * description of the authentication method given in <b>authMethod</b>. */
00276 TorSettings::AuthenticationMethod
00277 TorSettings::toAuthenticationMethod(const QString &authMethod) const
00278 { 
00279   QString str = authMethod.toLower();
00280   if (str == toString(NullAuth))
00281     return NullAuth;
00282   else if (str == toString(PasswordAuth))
00283     return PasswordAuth;
00284   else if (str == toString(CookieAuth))
00285     return CookieAuth;
00286   return UnknownAuth;
00287 }
00288 
00289 /** Generates a random control password consisting of PASSWORD_LEN characters. */
00290 QString
00291 TorSettings::randomPassword()
00292 {
00293   return crypto_rand_string(PASSWORD_LEN);
00294 }
00295 
00296 /** Returns the hash of <b>password</b> as given by the command "tor
00297  * --hash-password foo". */
00298 QString
00299 TorSettings::hashPassword(const QString &password)
00300 {
00301   TorSettings settings;
00302   QProcess tor;
00303   QString dataDirectory, line;
00304   QStringList args;
00305 
00306   QStringList env = QProcess::systemEnvironment();
00307 #if !defined(Q_OS_WIN32)
00308   /* Add "/usr/sbin" to an existing $PATH, so this works on Debian too. */
00309   for (int i = 0; i < env.size(); i++) {
00310     QString envVar = env.at(i);
00311     if (envVar.startsWith("PATH="))
00312       env.replace(i, envVar += ":/usr/sbin");
00313   }
00314 #endif
00315   tor.setEnvironment(env);
00316 
00317   /* Tor writes its state file even if all we're doing is --hash-password. So
00318    * if the user has configured a non-default data directory, then include
00319    * that in the list of command line arguments. */
00320   dataDirectory = settings.getDataDirectory();
00321   if (!dataDirectory.isEmpty())
00322     args << "DataDirectory" << dataDirectory;
00323   args << "--hash-password" << password;
00324   
00325   /* Run Tor, tell it to hash the given password, and then wait for it to
00326    * finish. */
00327   tor.start(settings.getExecutable(), args);
00328   if (!tor.waitForStarted() || !tor.waitForFinished())
00329     return QString();
00330 
00331   /* The hashed password will (hopefully) be the line that starts with "16:" */
00332   while (tor.canReadLine()) {
00333     line = tor.readLine();
00334     if (line.startsWith("16:"))
00335       return line.trimmed();
00336   }
00337   return QString();
00338 }
00339 

Generated on Tue Jul 7 16:58:27 2009 for Vidalia by  doxygen 1.4.7