"Fossies" - the Fresh Open Source Software Archive

Member "tvnserver-2.0.4/rfb-sconn/RfbInitializer.cpp" (3 Aug 2011, 10511 Bytes) of archive /windows/misc/tvnserver-2.0.4-src.zip:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "RfbInitializer.cpp" see the Fossies "Dox" file reference documentation.

    1 // Copyright (C) 2008, 2009, 2010 GlavSoft LLC.
    2 // All rights reserved.
    3 //
    4 //-------------------------------------------------------------------------
    5 // This file is part of the TightVNC software.  Please visit our Web site:
    6 //
    7 //                       http://www.tightvnc.com/
    8 //
    9 // This program is free software; you can redistribute it and/or modify
   10 // it under the terms of the GNU General Public License as published by
   11 // the Free Software Foundation; either version 2 of the License, or
   12 // (at your option) any later version.
   13 //
   14 // This program is distributed in the hope that it will be useful,
   15 // but WITHOUT ANY WARRANTY; without even the implied warranty of
   16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   17 // GNU General Public License for more details.
   18 //
   19 // You should have received a copy of the GNU General Public License along
   20 // with this program; if not, write to the Free Software Foundation, Inc.,
   21 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
   22 //-------------------------------------------------------------------------
   23 //
   24 
   25 #include "RfbInitializer.h"
   26 #include "thread/AutoLock.h"
   27 #include "rfb/VendorDefs.h"
   28 #include "rfb/AuthDefs.h"
   29 #include "CapContainer.h"
   30 #include "server-config-lib/Configurator.h"
   31 #include "AuthException.h"
   32 #include "util/VncPassCrypt.h"
   33 #include "win-system/Environment.h"
   34 
   35 #include <stdlib.h>
   36 #include <time.h>
   37 
   38 RfbInitializer::RfbInitializer(Channel *stream,
   39                                ClientAuthListener *extAuthListener,
   40                                RfbClient *client, bool authAllowed)
   41 : m_shared(false),
   42   m_tightEnabled(false),
   43   m_minorVerNum(0),
   44   m_extAuthListener(extAuthListener),
   45   m_client(client),
   46   m_authAllowed(authAllowed),
   47   m_viewOnlyAuth(false)
   48 {
   49   m_output = new DataOutputStream(stream);
   50   m_input = new DataInputStream(stream);
   51 }
   52 
   53 RfbInitializer::~RfbInitializer()
   54 {
   55   delete m_output;
   56   delete m_input;
   57 }
   58 
   59 void RfbInitializer::authPhase()
   60 {
   61   initVersion();
   62   initAuthenticate();
   63   readClientInit();
   64 }
   65 
   66 void RfbInitializer::afterAuthPhase(const CapContainer *srvToClCaps,
   67                                     const CapContainer *clToSrvCaps,
   68                                     const CapContainer *encCaps,
   69                                     const Dimension *dim,
   70                                     const PixelFormat *pf)
   71 {
   72   sendServerInit(dim, pf);
   73   sendDesktopName();
   74   if (m_tightEnabled) {
   75     sendInteractionCaps(srvToClCaps, clToSrvCaps, encCaps);
   76   }
   77 }
   78 
   79 void RfbInitializer::initVersion()
   80 {
   81   char initVersionMsg[] = "RFB 003.008\n";
   82   char clientVersionMsg[13];
   83   size_t msgLen = 12;
   84   m_output->writeFully(initVersionMsg, msgLen);
   85   m_input->readFully(clientVersionMsg, msgLen);
   86   clientVersionMsg[12] = 0;
   87   m_minorVerNum = getProtocolMinorVersion(clientVersionMsg);
   88 
   89   try {
   90     checkForLoopback();
   91     checkForBan();
   92   } catch (Exception &e) {
   93     if (m_minorVerNum == 3) {
   94       m_output->writeUInt32(0);
   95     } else {
   96       m_output->writeUInt8(0);
   97     }
   98     StringStorage errorMessage(e.getMessage());
   99     size_t reasonLen = errorMessage.getLength();
  100     char *reason = new char[reasonLen + 1];
  101     try {
  102       if (errorMessage.toAnsiString(reason, reasonLen + 1)) {
  103         m_output->writeUInt32(reasonLen);
  104         m_output->writeFully(reason, reasonLen);
  105       }
  106     } catch (...) {
  107     }
  108     delete reason;
  109     throw;
  110   }
  111 }
  112 
  113 void RfbInitializer::checkForLoopback()
  114 {
  115   SocketAddressIPv4 sockAddr;
  116   m_client->getSocketAddr(&sockAddr);
  117   struct sockaddr_in addrIn = sockAddr.getSockAddr();
  118 
  119   bool isLoopback = (unsigned long)addrIn.sin_addr.S_un.S_addr == 16777343;
  120 
  121   ServerConfig *srvConf = Configurator::getInstance()->getServerConfig();
  122   if (isLoopback && !srvConf->isLoopbackConnectionsAllowed()) {
  123     throw Exception(_T("Sorry, loopback connections are not enabled"));
  124   }
  125   if (srvConf->isOnlyLoopbackConnectionsAllowed() && !isLoopback) {
  126     throw Exception(_T("Your connection has been rejected"));
  127   }
  128 }
  129 
  130 void RfbInitializer::doTightAuth()
  131 {
  132   m_output->writeUInt32(0);
  133   if (Configurator::getInstance()->getServerConfig()->isUsingAuthentication()
  134       && m_authAllowed) {
  135     CapContainer authInfo;
  136     authInfo.addCap(AuthDefs::VNC, VendorDefs::STANDARD, AuthDefs::SIG_VNC);
  137     m_output->writeUInt32(authInfo.getCapCount());
  138     authInfo.sendCaps(m_output);
  139     UINT32 clientAuthValue = m_input->readUInt32();
  140     if (!authInfo.includes(clientAuthValue)) {
  141       throw Exception(_T(""));
  142     }
  143     doAuth(clientAuthValue);
  144   } else {
  145     m_output->writeUInt32(0);
  146     doAuth(AuthDefs::NONE);
  147   }
  148 }
  149 
  150 void RfbInitializer::doAuth(UINT32 authType)
  151 {
  152   if (authType == AuthDefs::VNC) {
  153     doVncAuth();
  154   } else if (authType == AuthDefs::NONE) {
  155     doAuthNone();
  156   } else {
  157     throw Exception(_T(""));
  158   }
  159   m_extAuthListener->onCheckAccessControl(m_client);
  160   if (m_minorVerNum >= 8 || authType != AuthDefs::NONE) {
  161     m_output->writeUInt32(0); 
  162   }
  163 }
  164 
  165 void RfbInitializer::doVncAuth()
  166 {
  167   UINT8 challenge[16];
  168   srand((unsigned)time(0));
  169   for (int i = 0; i < sizeof(challenge); i++) {
  170     challenge[i] = rand() & 0xff;
  171   }
  172 
  173   m_output->writeFully(challenge, sizeof(challenge));
  174   UINT8 response[16];
  175   m_input->readFully(response, sizeof(response));
  176   checkForBan();
  177 
  178   ServerConfig *srvConf = Configurator::getInstance()->getServerConfig();
  179   bool hasPrim = srvConf->hasPrimaryPassword();
  180   bool hasRdly = srvConf->hasReadOnlyPassword();
  181 
  182   if (!hasPrim && !hasRdly) {
  183     throw AuthException(_T("Server is not configured properly"));
  184   }
  185 
  186   if (hasPrim) {
  187     UINT8 crypPrimPass[8];
  188     srvConf->getPrimaryPassword(crypPrimPass);
  189     VncPassCrypt passCrypt;
  190     passCrypt.updatePlain(crypPrimPass);
  191     if (passCrypt.challengeAndResponseIsValid(challenge, response)) {
  192       return;
  193     }
  194   }
  195   if (hasRdly) {
  196     UINT8 crypReadOnlyPass[8];
  197     srvConf->getReadOnlyPassword(crypReadOnlyPass);
  198     VncPassCrypt passCrypt;
  199     passCrypt.updatePlain(crypReadOnlyPass);
  200     if (passCrypt.challengeAndResponseIsValid(challenge, response)) {
  201       m_viewOnlyAuth = true;
  202       return;
  203     }
  204   }
  205   m_extAuthListener->onAuthFailed(m_client);
  206   throw AuthException(_T("Authentication failed"));
  207 }
  208 
  209 void RfbInitializer::doAuthNone()
  210 {
  211 }
  212 
  213 void RfbInitializer::initAuthenticate()
  214 {
  215   try {
  216     UINT32 primSecType = SecurityDefs::VNC;
  217     if (!Configurator::getInstance()->getServerConfig()->isUsingAuthentication()
  218         || !m_authAllowed) {
  219       primSecType = SecurityDefs::NONE;
  220     }
  221     if (m_minorVerNum >= 7) {
  222       m_output->writeUInt8(2);
  223       m_output->writeUInt8(primSecType);
  224       m_output->writeUInt8(SecurityDefs::TIGHT);
  225       UINT8 clientSecType = m_input->readUInt8();
  226       if (clientSecType == SecurityDefs::TIGHT) {
  227         m_tightEnabled = true;
  228         doTightAuth();
  229       } else {
  230         if (clientSecType != primSecType) {
  231           throw Exception(_T("Security types do not match"));
  232         }
  233         doAuth(AuthDefs::convertFromSecurityType(clientSecType));
  234       }
  235     } else {
  236       m_output->writeUInt32(primSecType);
  237       doAuth(AuthDefs::convertFromSecurityType(primSecType));
  238     }
  239   } catch (AuthException &e) {
  240     if (m_minorVerNum >= 8) {
  241       StringStorage errorMessage(e.getMessage());
  242       size_t reasonLen = errorMessage.getLength();
  243       char *reason = new char[reasonLen + 1];
  244       try {
  245         if (errorMessage.toAnsiString(reason, reasonLen + 1)) {
  246           m_output->writeUInt32(1); 
  247           m_output->writeUInt32(reasonLen);
  248           m_output->writeFully(reason, reasonLen);
  249         }
  250       } catch (...) {
  251         delete reason;
  252         throw;
  253       }
  254       delete reason;
  255     }
  256     throw;
  257   }
  258 }
  259 
  260 void RfbInitializer::readClientInit()
  261 {
  262   m_shared = m_input->readUInt8() != 0;
  263 }
  264 
  265 void RfbInitializer::sendServerInit(const Dimension *dim,
  266                                     const PixelFormat *pf)
  267 {
  268   m_output->writeUInt16((UINT16)dim->width);
  269   m_output->writeUInt16((UINT16)dim->height);
  270   m_output->writeUInt8((UINT8)pf->bitsPerPixel);
  271   m_output->writeUInt8((UINT8)pf->colorDepth);
  272   m_output->writeUInt8((UINT8)pf->bigEndian);
  273   m_output->writeUInt8(1);
  274   m_output->writeUInt16((UINT16)pf->redMax);
  275   m_output->writeUInt16((UINT16)pf->greenMax);
  276   m_output->writeUInt16((UINT16)pf->blueMax);
  277   m_output->writeUInt8((UINT8)pf->redShift);
  278   m_output->writeUInt8((UINT8)pf->greenShift);
  279   m_output->writeUInt8((UINT8)pf->blueShift);
  280   m_output->writeUInt8(0);
  281   m_output->writeUInt16(0);
  282 }
  283 
  284 void RfbInitializer::sendDesktopName()
  285 {
  286   StringStorage deskName;
  287   if (!Environment::getComputerName(&deskName)) {
  288     deskName.setString(_T("TightVNC Server"));
  289   }
  290 
  291   size_t dnLen = deskName.getLength();
  292   char *ansiName = new char[dnLen + 1];
  293   deskName.toAnsiString(ansiName, dnLen + 1);
  294 
  295   m_output->writeUInt32(dnLen);
  296   m_output->writeFully(ansiName, dnLen);
  297 }
  298 
  299 void RfbInitializer::sendInteractionCaps(const CapContainer *srvToClCaps,
  300                                          const CapContainer *clToSrvCaps,
  301                                          const CapContainer *encCaps)
  302 {
  303   m_output->writeUInt16(srvToClCaps->getCapCount());
  304   m_output->writeUInt16(clToSrvCaps->getCapCount());
  305   m_output->writeUInt16(encCaps->getCapCount());
  306   m_output->writeUInt16(0); 
  307 
  308   srvToClCaps->sendCaps(m_output);
  309   clToSrvCaps->sendCaps(m_output);
  310   encCaps->sendCaps(m_output);
  311 }
  312 
  313 unsigned int RfbInitializer::getProtocolMinorVersion(const char str[12])
  314 {
  315   if ( str[0] != 'R' || str[1] != 'F' || str[2] != 'B' || str[3] != ' ' ||
  316        !isdigit(str[4]) || !isdigit(str[5]) || !isdigit(str[6]) ||
  317        str[7] != '.' ||
  318        !isdigit(str[8]) || !isdigit(str[9]) || !isdigit(str[10]) ||
  319        str[11] != '\n' ) {
  320     throw Exception(_T("Invalid format of the RFB version message"));
  321   }
  322 
  323   unsigned int majorVersion =
  324     (str[4] - '0') * 100 + (str[5] - '0') * 10 + (str[6] - '0');
  325   if (majorVersion != 3) {
  326     throw Exception(_T("Unsupported RFB protocol version requested"));
  327   }
  328 
  329   unsigned int minorVersion =
  330     (str[8] - '0') * 100 + (str[9] - '0') * 10 + (str[10] - '0');
  331   return minorVersion;
  332 }
  333 
  334 void RfbInitializer::checkForBan()
  335 {
  336   if (m_extAuthListener->onCheckForBan(m_client)) {
  337     throw AuthException(_T("Your connection has been rejected"));
  338   }
  339 }