OPeNDAP Hyrax Back End Server (BES) Updated for version 3.8.3
|
00001 // PPTServer.cc 00002 00003 // This file is part of bes, A C++ back-end server implementation framework 00004 // for the OPeNDAP Data Access Protocol. 00005 00006 // Copyright (c) 2004-2009 University Corporation for Atmospheric Research 00007 // Author: Patrick West <pwest@ucar.edu> and Jose Garcia <jgarcia@ucar.edu> 00008 // 00009 // This library is free software; you can redistribute it and/or 00010 // modify it under the terms of the GNU Lesser General Public 00011 // License as published by the Free Software Foundation; either 00012 // version 2.1 of the License, or (at your option) any later version. 00013 // 00014 // This library is distributed in the hope that it will be useful, 00015 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00016 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00017 // Lesser General Public License for more details. 00018 // 00019 // You should have received a copy of the GNU Lesser General Public 00020 // License along with this library; if not, write to the Free Software 00021 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 00022 // 00023 // You can contact University Corporation for Atmospheric Research at 00024 // 3080 Center Green Drive, Boulder, CO 80301 00025 00026 // (c) COPYRIGHT University Corporation for Atmospheric Research 2004-2005 00027 // Please read the full copyright statement in the file COPYRIGHT_UCAR. 00028 // 00029 // Authors: 00030 // pwest Patrick West <pwest@ucar.edu> 00031 // jgarcia Jose Garcia <jgarcia@ucar.edu> 00032 00033 #include <config.h> 00034 00035 #include <string> 00036 #include <sstream> 00037 #include <cstdlib> 00038 00039 using std::string ; 00040 using std::ostringstream ; 00041 00042 #include "PPTServer.h" 00043 #include "BESInternalError.h" 00044 #include "BESSyntaxUserError.h" 00045 #include "PPTProtocol.h" 00046 #include "SocketListener.h" 00047 #include "ServerHandler.h" 00048 #include "Socket.h" 00049 #include "TheBESKeys.h" 00050 #include "BESDebug.h" 00051 00052 #include "config.h" 00053 #ifdef HAVE_OPENSSL 00054 #include "SSLServer.h" 00055 #endif 00056 00057 #define PPT_SERVER_DEFAULT_TIMEOUT 1 00058 00059 PPTServer::PPTServer( ServerHandler *handler, 00060 SocketListener *listener, 00061 bool isSecure ) 00062 : PPTConnection( PPT_SERVER_DEFAULT_TIMEOUT), 00063 _handler( handler ), 00064 _listener( listener ), 00065 _secure( isSecure ) 00066 { 00067 if( !handler ) 00068 { 00069 string err( "Null handler passed to PPTServer" ) ; 00070 throw BESInternalError( err, __FILE__, __LINE__ ) ; 00071 } 00072 if( !listener ) 00073 { 00074 string err( "Null listener passed to PPTServer" ) ; 00075 throw BESInternalError( err, __FILE__, __LINE__ ) ; 00076 } 00077 #ifndef HAVE_OPENSSL 00078 if( _secure ) 00079 { 00080 string err("Server requested to be secure but OpenSSL is not built in"); 00081 throw BESInternalError( err, __FILE__, __LINE__ ) ; 00082 } 00083 #endif 00084 00085 // get the certificate and key file information 00086 if( _secure ) 00087 { 00088 get_secure_files() ; 00089 } 00090 } 00091 00092 PPTServer::~PPTServer() 00093 { 00094 } 00095 00096 void 00097 PPTServer::get_secure_files() 00098 { 00099 bool found = false ; 00100 TheBESKeys::TheKeys()->get_value( "BES.ServerCertFile", _cfile, found ) ; 00101 if( !found || _cfile.empty() ) 00102 { 00103 string err = "Unable to determine server certificate file." ; 00104 throw BESSyntaxUserError( err, __FILE__, __LINE__ ) ; 00105 } 00106 00107 found = false ; 00108 TheBESKeys::TheKeys()->get_value( "BES.ServerCertAuthFile", _cafile, found); 00109 if( !found || _cafile.empty() ) 00110 { 00111 string err = "Unable to determine server certificate authority file." ; 00112 throw BESSyntaxUserError( err, __FILE__, __LINE__ ) ; 00113 } 00114 00115 found = false ; 00116 TheBESKeys::TheKeys()->get_value( "BES.ServerKeyFile", _kfile, found ) ; 00117 if( !found || _kfile.empty() ) 00118 { 00119 string err = "Unable to determine server key file." ; 00120 throw BESSyntaxUserError( err, __FILE__, __LINE__ ) ; 00121 } 00122 00123 found = false ; 00124 string portstr ; 00125 TheBESKeys::TheKeys()->get_value( "BES.ServerSecurePort", portstr, found ) ; 00126 if( !found || portstr.empty() ) 00127 { 00128 string err = "Unable to determine secure connection port." ; 00129 throw BESSyntaxUserError( err, __FILE__, __LINE__ ) ; 00130 } 00131 _securePort = atoi( portstr.c_str() ) ; 00132 if( !_securePort ) 00133 { 00134 string err = (string)"Unable to determine secure connection port " 00135 + "from string " + portstr ; 00136 throw BESSyntaxUserError( err, __FILE__, __LINE__ ) ; 00137 } 00138 } 00139 00145 void 00146 PPTServer::initConnection() 00147 { 00148 for(;;) 00149 { 00150 _mySock = _listener->accept() ; 00151 if( _mySock ) 00152 { 00153 if( _mySock->allowConnection() == true ) 00154 { 00155 // welcome the client 00156 if( welcomeClient( ) != -1 ) 00157 { 00158 // now hand it off to the handler 00159 _handler->handle( this ) ; 00160 } 00161 } 00162 else 00163 { 00164 _mySock->close(); 00165 } 00166 } 00167 } 00168 } 00169 00170 void 00171 PPTServer::closeConnection() 00172 { 00173 if( _mySock ) _mySock->close() ; 00174 } 00175 00176 int 00177 PPTServer::welcomeClient() 00178 { 00179 // Doing a non blocking read in case the connection is being initiated 00180 // by a non-bes client. Don't want this to block. pcw - 3/5/07 00181 // int bytesRead = _mySock->receive( inBuff, ppt_buffer_size ) ; 00182 // 00183 // We are receiving handshaking tokens, so the buffer doesn't need to be 00184 // all that big. pcw - 05/31/08 00185 unsigned int ppt_buffer_size = 64 ; 00186 char *inBuff = new char[ppt_buffer_size+1] ; 00187 int bytesRead = readBufferNonBlocking( inBuff, ppt_buffer_size ) ; 00188 00189 // if the read of the initial connection fails or blocks, then return 00190 if( bytesRead == -1 ) 00191 { 00192 _mySock->close() ; 00193 delete [] inBuff ; 00194 return -1 ; 00195 } 00196 00197 string status( inBuff, bytesRead ) ; 00198 delete [] inBuff ; 00199 00200 if( status != PPTProtocol::PPTCLIENT_TESTING_CONNECTION ) 00201 { 00202 /* If cannot negotiate with the client then we don't want to exit 00203 * by throwing an exception, we want to return and let the caller 00204 * clean up the connection 00205 */ 00206 string err( "PPT cannot negotiate, " ) ; 00207 err += " client started the connection with " + status ; 00208 BESDEBUG( "ppt", err << endl ) ; 00209 //throw BESInternalError( err, __FILE__, __LINE__ ) ; 00210 send( err ) ; 00211 _mySock->close() ; 00212 return -1 ; 00213 } 00214 00215 if( !_secure ) 00216 { 00217 send( PPTProtocol::PPTSERVER_CONNECTION_OK ) ; 00218 } 00219 else 00220 { 00221 authenticateClient() ; 00222 } 00223 00224 return 0 ; 00225 } 00226 00227 void 00228 PPTServer::authenticateClient() 00229 { 00230 #ifdef HAVE_OPENSSL 00231 BESDEBUG( "ppt", "requiring secure connection: port = " 00232 << _securePort << endl ) ; 00233 // let the client know that it needs to authenticate 00234 send( PPTProtocol::PPTSERVER_AUTHENTICATE ) ; 00235 00236 // wait for the client request for the secure port 00237 // We are waiting for a ppt tocken requesting the secure port number. 00238 // The buffer doesn't need to be all that big. pcw - 05/31/08 00239 unsigned int ppt_buffer_size = 64 ; 00240 char *inBuff = new char[ppt_buffer_size] ; 00241 int bytesRead = _mySock->receive( inBuff, ppt_buffer_size ) ; 00242 string portRequest( inBuff, bytesRead ) ; 00243 delete [] inBuff ; 00244 if( portRequest != PPTProtocol::PPTCLIENT_REQUEST_AUTHPORT ) 00245 { 00246 string err( "Secure connection ... expecting request for port" ) ; 00247 err += " client requested " + portRequest ; 00248 throw BESInternalError( err, __FILE__, __LINE__ ) ; 00249 } 00250 00251 // send the secure port number back to the client 00252 ostringstream portResponse ; 00253 portResponse << _securePort << PPTProtocol::PPT_COMPLETE_DATA_TRANSMITION ; 00254 send( portResponse.str() ) ; 00255 00256 // create a secure server object and authenticate 00257 SSLServer server( _securePort, _cfile, _cafile, _kfile ) ; 00258 server.initConnection() ; 00259 server.closeConnection() ; 00260 00261 // if it authenticates, good, if not, an exception is thrown, no need to 00262 // do anything else here. 00263 #else 00264 string err = (string)"Authentication requested for this server " 00265 + "but OpenSSL is not built into the server" ; 00266 throw BESInternalError( err, __FILE__, __LINE__ ) ; 00267 #endif 00268 } 00269 00276 void 00277 PPTServer::dump( ostream &strm ) const 00278 { 00279 strm << BESIndent::LMarg << "PPTServer::dump - (" 00280 << (void *)this << ")" << endl ; 00281 BESIndent::Indent() ; 00282 if( _handler ) 00283 { 00284 strm << BESIndent::LMarg << "server handler:" << endl ; 00285 BESIndent::Indent() ; 00286 _handler->dump( strm ) ; 00287 BESIndent::UnIndent() ; 00288 } 00289 else 00290 { 00291 strm << BESIndent::LMarg << "server handler: null" << endl ; 00292 } 00293 if( _listener ) 00294 { 00295 strm << BESIndent::LMarg << "listener:" << endl ; 00296 BESIndent::Indent() ; 00297 _listener->dump( strm ) ; 00298 BESIndent::UnIndent() ; 00299 } 00300 else 00301 { 00302 strm << BESIndent::LMarg << "listener: null" << endl ; 00303 } 00304 strm << BESIndent::LMarg << "secure? " << _secure << endl ; 00305 if( _secure ) 00306 { 00307 BESIndent::Indent() ; 00308 strm << BESIndent::LMarg << "cert file: " << _cfile << endl ; 00309 strm << BESIndent::LMarg << "cert authority file: " << _cafile << endl ; 00310 strm << BESIndent::LMarg << "key file: " << _kfile << endl ; 00311 strm << BESIndent::LMarg << "secure port: " << _securePort << endl ; 00312 BESIndent::UnIndent() ; 00313 } 00314 PPTConnection::dump( strm ) ; 00315 BESIndent::UnIndent() ; 00316 } 00317