Documentation

Generated on Thu Aug 31 00:02:28 2006

 

Connection.cpp

Go to the documentation of this file.
00001 
00002 // $Id: Connection.cpp,v 1.19 2005/09/01 20:49:17 klas Exp $
00003 //
00004 // Usage: Data class. inherited from Connection, everything pertaining to
00005 //        data connection goes here.
00006 //
00007 //  A part of babyftpd, licensed under the GNU GPL, see the file
00008 //    LICENSE for complete information.
00010 
00011 #define CONNECTION_CPP
00012 #define NETINCLS
00013 #define BABY_CORE
00014 #include "Connection.h"
00015 
00016 Connection::Connection()
00017 {
00018   pthread_rwlock_init(&this->lock, NULL);
00019   this->_settings.reset();
00020   this->_packet_size = READ_SIZE;
00021   this->_transfered = 0;
00022 }
00023 
00024 Connection::~Connection()
00025 {
00026   if(this->_socket_id)
00027     close(this->_socket_id);
00028 
00029   pthread_rwlock_destroy(&this->lock);
00030 
00031 #ifdef USE_TLS
00032   // TLS cleanup here.
00033   if(this->settings(TLS_INITED))
00034   {
00035     gnutls_db_remove_session(this->session);
00036     gnutls_deinit(this->session);
00037   }
00038 #endif
00039   if(this->thread_id())
00040   {
00041     sem_wait(&cleanup_list_lock);
00042     cleanup_list.push_back(this->thread_id());
00043     sem_post(&cleanup_list_lock);
00044   }
00045 }
00046 
00047 ssize_t Connection::send(const char *message, size_t len)
00048 {
00049   assert(len <= this->_packet_size && len > 0);
00050   ssize_t ret = -1;
00051 
00052   BABY_WRLOCK(this->lock);
00053 #ifdef USE_TLS
00054   if(this->settings(TLS_ENABLED))
00055   {
00056     ret = gnutls_record_send(this->session, message, len);
00057     if(ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED)
00058       ret = gnutls_record_send(this->session, message, len);
00059   }
00060   else
00061 #endif // USE_TLS
00062     ret = write(this->_socket_id, message, len);
00063 
00064   BABY_UNLOCK(this->lock);
00065   if(ret < 0)
00066     logging->log_this(3, TYPE_INFO, "write to socket " +
00067         util.itos(this->socket_id()) + " failed: %m");
00068   else
00069     this->transfered(this->transfered() + ret);
00070 
00071   return ret;
00072 }
00073 
00074 ssize_t Connection::receive(char *message, size_t len)
00075 {
00076   assert(len <= this->_packet_size && len > 0);
00077   ssize_t ret = -1;
00078 
00079 #ifdef USE_TLS
00080   if(this->settings(TLS_ENABLED))
00081     ret = gnutls_record_recv(this->session, message, len);
00082   else
00083 #endif
00084     ret = read(this->socket_id(), message, len);
00085 
00086   this->transfered(this->transfered() + ret);
00087 
00088   return ret;
00089 }
00090 
00091 Connection &Connection::operator<<(long long int num)
00092 {
00093   return (*this << util.itos(num));
00094 }
00095 
00096 Connection &Connection::operator<<(string message)
00097 {
00098   if(this->send(message.c_str(), message.size()) < 0)
00099   this->settings(FAILURE, B_SET);
00100   return *this;
00101 }
00102 
00103 #ifdef USE_TLS
00104 bool Connection::engage_tls(void)
00105 {
00106   bool ret = false;
00107   gnutls_init(&session, GNUTLS_SERVER);
00108 
00109   gnutls_set_default_priority(this->session);
00110 
00111   gnutls_credentials_set(this->session, GNUTLS_CRD_CERTIFICATE, x509_cred);
00112 
00113   gnutls_certificate_server_set_request(this->session, GNUTLS_CERT_REQUEST);
00114 
00115   gnutls_dh_set_prime_bits(this->session, 1024);
00116 
00117   // these are for the connection cache
00118   gnutls_db_set_retrieve_function(this->session, tls_db_fetch);
00119   gnutls_db_set_remove_function(this->session, tls_db_delete);
00120   gnutls_db_set_store_function(this->session, tls_db_store);
00121   gnutls_db_set_ptr(this->session, NULL);
00122 
00123   // associating the session with the socket.
00124   gnutls_transport_set_ptr(this->session,
00125       reinterpret_cast<gnutls_transport_ptr>(this->socket_id()));
00126   this->settings(TLS_INITED, B_SET);
00127 
00128   if(gnutls_handshake(this->session) >= 0)
00129   {
00130     this->settings(TLS_ENABLED, B_SET);
00131     this->packet_size(gnutls_record_get_max_size(this->session));
00132     ret = true;
00133   }
00134 
00135   return ret;
00136 }
00137 
00138 bool Connection::disengage_tls(void)
00139 {
00140   gnutls_bye(this->session, GNUTLS_SHUT_RDWR);
00141   this->settings(TLS_ENABLED, B_RESET);
00142   return true;
00143 }
00144 
00145 bool Connection::verify_cert(void)
00146 {
00147   bool ret = false;
00148   if (gnutls_certificate_type_get(this->session) == GNUTLS_CRT_X509)
00149   {
00150     int verified = gnutls_certificate_verify_peers(this->session);
00151     if(util.is_set(verified, GNUTLS_CERT_REVOKED))
00152       logging->log_this(2, TYPE_AUTH, this->user_name() +
00153           + " tried to login with a revoked certificate.");
00154     else if(!util.is_set(verified, GNUTLS_CERT_INVALID) &&
00155         !util.is_set(verified, GNUTLS_CERT_SIGNER_NOT_FOUND))
00156     {
00157       unsigned int cert_list_size = 0;
00158       // I really hope gnutls has their locking code in shape. get_peers just
00159       // gives us some memory.. *shudder*                     
00160       const gnutls_datum *cert_list = gnutls_certificate_get_peers(
00161           this->session, &cert_list_size);
00162       if(cert_list_size > 0)
00163       {
00164         gnutls_x509_crt peer_cert;
00165         gnutls_x509_crt_init(&peer_cert);
00166         gnutls_x509_crt_import(peer_cert, &cert_list[0], GNUTLS_X509_FMT_DER);
00167         char dn_buf[200] = {0}, ca_buf[200] = {0};
00168         size_t buf_size = 199, ca_size = 199;
00169         gnutls_x509_crt_get_dn(peer_cert, dn_buf, &buf_size);
00170         gnutls_x509_crt_get_issuer_dn(peer_cert, ca_buf, &ca_size);
00171         if(buf_size > 0 && ca_size > 0)
00172         {
00173           // here we call an external program to ask if this user may login
00174           // with this cert.
00175           //  format is "<user> <host/ip> <ca-dn> <cert-dn>"
00176           string call = config->general.verify_client + " " +
00177             this->user_name() + " " + this->host_name() +
00178             " \"" + ca_buf + "\" \"" + dn_buf + "\"";
00179           logging->log_this(5, TYPE_DEBUG, "running:" + call);
00180           int approved = system(call.c_str());
00181           if(WEXITSTATUS(approved) == 0)
00182             ret = true;
00183         }
00184         gnutls_x509_crt_deinit(peer_cert);
00185       }
00186     }
00187   }
00188   return ret;
00189 }
00190 #endif // USE_TLS