Example #1
0
File: socket.c Project: lb1a/avfs
/* sock_peek is recv(...,MSG_PEEK) with a timeout of SOCKET_TIMEOUT.
 * Returns length of data read or SOCK_* on error */
int sock_peek(nsocket *sock, char *buffer, size_t count) 
{
    int ret;
    ret = sock_block(sock, SOCKET_READ_TIMEOUT);
    if (ret < 0) {
	return ret;
    }
    /* Got data */
#ifdef ENABLE_SSL
    if (sock->ssl) {
	ret = SSL_peek(sock->ssl, buffer, count);
	/* TODO: This is the fetchmail fix as in sock_readline.
	 * Do we really need it? */
	if (ret == 0) {
	    if (sock->ssl->shutdown) {
		return SOCK_CLOSED;
	    }
	    if (0 != ERR_get_error()) {
		sock->error = ERROR_SSL_STRING;
		return SOCK_ERROR;
	    }
	}
    } else {
#endif
    do {
#ifndef BEOS_PRE_BONE
	ret = recv(sock->fd, buffer, count, MSG_PEEK);
#else /* we're on BeOS pre-BONE so we need to use the buffer... */
	if (sock->peeked_bytes_avail > 0) {
	    /* we've got some from last time!!! */
	    if (count >= sock->peeked_bytes_avail) {
		strncpy(buffer, sock->peeked_bytes_curpos, sock->peeked_bytes_avail);
		ret = sock->peeked_bytes_avail;
	    } else {
		strncpy(buffer, sock->peeked_bytes_curpos, count);
		ret = count;
	    }
	} else {
	    if (count > MAX_PEEK_BUFFER)
		count = MAX_PEEK_BUFFER;
	    ret = recv(sock->fd, buffer, count, 0);
	    sock->peeked_bytes_avail = ret;
	    strncpy(sock->peeked_bytes, buffer, ret);
	    sock->peeked_bytes_curpos = sock->peeked_bytes;
	}
#endif
    } while (ret == -1 && errno == EINTR);
#ifdef ENABLE_SSL
    }
#endif
    /* According to the Single Unix Spec, recv() will return
     * zero if the socket has been closed the other end. */
    if (ret == 0) {
	ret = SOCK_CLOSED;
    } else if (ret < 0) {
	sock->error = strerror(errno);
	ret = SOCK_ERROR;
    } 
    return ret;
}
Example #2
0
gint ssl_peek(SSL *ssl, gchar *buf, gint len)
{
	gint err, ret;

	if (SSL_pending(ssl) == 0) {
		if (fd_check_io(SSL_get_rfd(ssl), G_IO_IN) < 0)
			return -1;
	}

	ret = SSL_peek(ssl, buf, len);

	switch ((err = SSL_get_error(ssl, ret))) {
	case SSL_ERROR_NONE:
		return ret;
	case SSL_ERROR_WANT_READ:
	case SSL_ERROR_WANT_WRITE:
		errno = EAGAIN;
		return -1;
	case SSL_ERROR_ZERO_RETURN:
		return 0;
	default:
		g_warning("SSL_peek() returned error %d, ret = %d\n", err, ret);
		if (ret == 0)
			return 0;
		return -1;
	}
}
Example #3
0
int SSLSocket::wait(uint32_t millis, int waitFor) throw(SocketException) {
	if(ssl && (waitFor & Socket::WAIT_READ)) {
		/** @todo Take writing into account as well if reading is possible? */
		char c;
		if(SSL_peek(ssl, &c, 1) > 0)
			return WAIT_READ;
	}
	return Socket::wait(millis, waitFor);
}
Example #4
0
std::pair<bool, bool> SSLSocket::wait(uint64_t millis, bool checkRead, bool checkWrite) {
	if(ssl && checkRead) {
		/** @todo Take writing into account as well if reading is possible? */
		char c;
		if(SSL_peek(ssl, &c, 1) > 0)
			return std::make_pair(true, false);
	}
	return Socket::wait(millis, checkRead, checkWrite);
}
Example #5
0
int ssl_client_peek(ssl_client * cli, void * buffer, size_t length){
  socklen_t len = SSL_peek(cli->ssl, buffer, length);
  int accepted[] = {SSL_ERROR_WANT_READ, SSL_ERROR_ZERO_RETURN};
  int code[] = {-1, -2};
  int ecode = handle_ssl_error2(cli->ssl, len, accepted, code, array_count(accepted));
  if(ecode < 0)
    return ecode;
  return len;
}
Example #6
0
bool GSISocketServer::Peek(int bufsize, std::string& s)
{
  if (!ssl) {
    SetError("No connection established");
    return false;
  }

  ERR_clear_error();

  int ret = -1, ret2 = -1;

  char *buffer = (char *)OPENSSL_malloc(bufsize);

  int fd = BIO_get_fd(SSL_get_rbio(ssl), NULL);
  time_t starttime, curtime;

  int error = 0;
  int expected = 0;

  starttime = time(NULL);

  do {
    ret = do_select(fd, starttime, timeout, expected);
    curtime = time(NULL);

    if (ret > 0) {
      ret2 = SSL_peek(ssl, buffer, bufsize);

      if (ret2 <= 0)
        expected = error = SSL_get_error(ssl, ret2);
    }
  } while ((ret > 0) && 
           ((ret2 <= 0) && 
            (((timeout == -1) ||
              ((timeout != -1) && 
               (curtime - starttime < timeout))) &&
             ((error == SSL_ERROR_WANT_READ) ||
              (error == SSL_ERROR_WANT_WRITE)))));
            
  if (ret <= 0 || ret2 <= 0) {
    if (timeout != -1 && (curtime - starttime >= timeout))
      SetError("Connection stuck during read: timeout reached.");
    else
      SetErrorOpenSSL("Error during SSL read:");
    OPENSSL_free(buffer);
    ERR_clear_error();
    return false;
  }

  s = std::string(buffer, ret2);
  OPENSSL_free(buffer);
  ERR_clear_error();
  return true;

}
Example #7
0
int	HttpsRetriever::openssl_peek (int fd, char *buf, int bufsize, void *ctx)
{
	  int ret;
	  SSL *ssl = (SSL *) ctx;
	  do
	    ret = SSL_peek (ssl, buf, bufsize);
	  while (ret == -1
		 && SSL_get_error (ssl, ret) == SSL_ERROR_SYSCALL
		 && errno == EINTR);
	  return ret;
}
Example #8
0
int SSLSocket::wait(uint64_t millis, int waitFor)
{
#ifdef HEADER_OPENSSLV_H
	if (ssl && (waitFor & Socket::WAIT_READ))
	{
		/** @todo Take writing into account as well if reading is possible? */
		char c;
		if (SSL_peek(ssl, &c, 1) > 0)
			return WAIT_READ;
	}
#endif
	return Socket::wait(millis, waitFor);
}
Example #9
0
static int
openssl_peek (int fd, char *buf, int bufsize, void *arg)
{
  int ret;
  struct openssl_transport_context *ctx = arg;
  SSL *conn = ctx->conn;
  do
    ret = SSL_peek (conn, buf, bufsize);
  while (ret == -1
         && SSL_get_error (conn, ret) == SSL_ERROR_SYSCALL
         && errno == EINTR);
  return ret;
}
Example #10
0
int rocksock_ssl_peek(rocksock* sock, int *result) {
        char buf[4];
	int ret;
	ret = SSL_peek(sock->ssl, buf, 1);
	if(ret >= 0) *result = 1;
	else {
		ret = SSL_get_error(sock->ssl, ret);
		if(ret == SSL_ERROR_WANT_READ)
			return rocksock_seterror(sock, RS_ET_OWN, RS_E_HIT_READTIMEOUT, ROCKSOCK_FILENAME, __LINE__);
		return rocksock_seterror(sock, RS_ET_SSL, ret, ROCKSOCK_FILENAME, __LINE__);
        }
	return rocksock_seterror(sock, RS_ET_OWN, 0, NULL, 0);
}
Example #11
0
/* Return value:
 * >0: the number of bytes actually read from SSL connection
 * SSL_AGAIN: need to read again
 * SSL_ERROR: failed, call ossSSLGetError() & ossSSLGetErrorMessage() for reason
 * SSL_TIMEOUT: only in windows
 *
 * NOTE: in constrast to the ossSSLRead(), the data in the SSL buffer is unmodified
 * after the ossSSLPeek() opertaion
 */
INT32 ossSSLPeek(SSLHandle* handle, void* buf, INT32 num)
{
   INT32 status;
   INT32 ret = SSL_OK;

   SSL_ASSERT(NULL != handle);
   SSL_ASSERT(NULL != handle->ssl);
   SSL_ASSERT(NULL != buf);

   status = SSL_peek(handle->ssl, buf, num);
   ret = _ossSSLCheckStatus(handle, status);

   if (SSL_OK != ret)
   {
      status = ret;
   }

   return status;
}
Example #12
0
int
ssl23_peek(SSL *s, void *buf, int len)
{
	int n;

	errno = 0;
	if (SSL_in_init(s) && (!s->in_handshake)) {
		n = s->handshake_func(s);
		if (n < 0)
			return (n);
		if (n == 0) {
			SSLerr(SSL_F_SSL23_PEEK, SSL_R_SSL_HANDSHAKE_FAILURE);
			return (-1);
		}
		return (SSL_peek(s, buf, len));
	} else {
		ssl_undefined_function(s);
		return (-1);
	}
}
Example #13
0
static int openssl_ssl_peek(lua_State*L)
{
  SSL* s = CHECK_OBJECT(1, SSL, "openssl.ssl");
  int num = luaL_optint(L, 2, SSL_pending(s));
  void* buf;
  int ret;

  num = num ? num : 4096;
  buf = malloc(num);
  ret = SSL_peek(s, buf, num);
  if (ret > 0)
  {
    lua_pushlstring(L, buf, ret);
    ret = 1;
  } else
  {
    ret = openssl_ssl_pushresult(L, s, ret);
  }
  free(buf);
  return ret;
}
Example #14
0
bool SSLSocket::checkLiveness() {
  if (getFd() == -1) {
    return false;
  }

  pollfd p;
  p.fd = getFd();
  p.events = POLLIN | POLLERR | POLLHUP | POLLPRI;
  p.revents = 0;
  if (poll(&p, 1, 0) > 0 && p.revents > 0) {
    char buf;
    if (m_data->m_ssl_active) {
      while (true) {
        int n = SSL_peek(m_data->m_handle, &buf, sizeof(buf));
        if (n <= 0) {
          int err = SSL_get_error(m_data->m_handle, n);
          if (err == SSL_ERROR_SYSCALL) {
            return errno == EAGAIN;
          }

          if (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE) {
            /* re-negotiate */
            continue;
          }

          /* any other problem is a fatal error */
          return false;
        }
        /* either peek succeeded or there was an error; we
         * have set the alive flag appropriately */
        break;
      }
    } else if (0 == recv(getFd(), &buf, sizeof(buf), MSG_PEEK) &&
               errno != EAGAIN) {
      return false;
    }
  }
  return true;
}
Example #15
0
/*
 * This function extracts data from the SSL context and puts
 * it into a buffer.
 */
static int est_io_read_raw (SSL *ssl, unsigned char *buf, int buf_max,
                            int *read_cnt, int sock_read_timeout)
{
    int cur_cnt;
    char peek_read_buf;

    *read_cnt = 0;
    cur_cnt  = est_ssl_read(ssl, buf, buf_max, sock_read_timeout);
    if (cur_cnt < 0) {
        EST_LOG_ERR("TLS read error");
	ossl_dump_ssl_errors();
        return (EST_ERR_SSL_READ);
    }
    *read_cnt += cur_cnt;

    /*
     * Multiple calls to SSL_read may be required to get the full
     * HTTP payload.
     */
    while (cur_cnt > 0 && *read_cnt < buf_max) {
        cur_cnt = est_ssl_read(ssl, (buf + *read_cnt), (buf_max - *read_cnt),
                               sock_read_timeout);
        if (cur_cnt < 0) {
            EST_LOG_ERR("TLS read error");
	    ossl_dump_ssl_errors();
            return (EST_ERR_SSL_READ);
        }
        *read_cnt += cur_cnt;
    }

    if ((*read_cnt == buf_max) && SSL_peek(ssl, &peek_read_buf, 1)) {
        EST_LOG_ERR("Buffer too small for received message");
        return(EST_ERR_READ_BUFFER_TOO_SMALL);
    }
    
    return (EST_ERR_NONE);
}
Example #16
0
/** @brief Checks if the socket is still connected to the remote host.
 *  @returns True if the connection is still active, false otherwise.
 */
bool Jatta::Network::SocketTCP::IsConnected()
{
#   ifdef OpenSSL_FOUND
    if (connectionSecure)
    {
        char data;
        if (sock == INVALID_SOCKET)
        {
            return false;
        }
        if (SSL_peek(sslHandle, &data, 1) == 0)
        {
            sock = INVALID_SOCKET;
            return false;
        }
        return true;
    }
#   endif

    // Check if we've already determined the connection is dead.  If so, we can go ahead and return.
    if (sock == INVALID_SOCKET)
    {
        return false;
    }

    // Check if recv is returning 0.  In that case, the remote host has disconnected gracefully.
    // TODO: receive could return non-zero and still fail, certain winsock errors indicate this
    // add a check for those for a more accurate isConnected() method
    char data;
    if (recv(sock, &data, 1, MSG_PEEK) == 0)
    {
        sock = INVALID_SOCKET;
        return false;
    }
    return true;
}
bool SSLSocket::waitWant(int ret, uint64_t millis) {
#ifdef HEADER_OPENSSLV_H
	int err = SSL_get_error(ssl, ret);
	switch(err) {
	case SSL_ERROR_WANT_READ:
		return wait(millis, Socket::WAIT_READ) == WAIT_READ;
	case SSL_ERROR_WANT_WRITE:
		return wait(millis, Socket::WAIT_WRITE) == WAIT_WRITE;
#else
	int err = ssl->last_error;
	switch(err) {
	case GNUTLS_E_INTERRUPTED:
	case GNUTLS_E_AGAIN: 
	{
		int waitFor = wait(millis, Socket::WAIT_READ | Socket::WAIT_WRITE);
		return (waitFor & Socket::WAIT_READ) || (waitFor & Socket::WAIT_WRITE);
	}
#endif
	// Check if this is a fatal error...
	default: checkSSL(ret);
	}
	dcdebug("SSL: Unexpected fallthrough");
	// There was no error?
	return true;
}

int SSLSocket::read(void* aBuffer, int aBufLen) throw(SocketException) {
	if(!ssl) {
		return -1;
	}
	int len = checkSSL(SSL_read(ssl, aBuffer, aBufLen));

	if(len > 0) {
		stats.totalDown += len;
		//dcdebug("In(s): %.*s\n", len, (char*)aBuffer);
	}
	return len;
}

int SSLSocket::write(const void* aBuffer, int aLen) throw(SocketException) {
	if(!ssl) {
		return -1;
	}
	int ret = checkSSL(SSL_write(ssl, aBuffer, aLen));
	if(ret > 0) {
		stats.totalUp += ret;
		//dcdebug("Out(s): %.*s\n", ret, (char*)aBuffer);
	}
	return ret;
}

int SSLSocket::checkSSL(int ret) throw(SocketException) {
	if(!ssl) {
		return -1;
	}
	if(ret <= 0) {
		int err = SSL_get_error(ssl, ret);
		switch(err) {
			case SSL_ERROR_NONE:		// Fallthrough - YaSSL doesn't for example return an openssl compatible error on recv fail
			case SSL_ERROR_WANT_READ:	// Fallthrough
			case SSL_ERROR_WANT_WRITE:
				return -1;
			case SSL_ERROR_ZERO_RETURN:
#ifndef HEADER_OPENSSLV_H
				if(ssl->last_error == GNUTLS_E_INTERRUPTED || ssl->last_error == GNUTLS_E_AGAIN)
					return -1;
#endif				
				throw SocketException(STRING(CONNECTION_CLOSED));
			default:
				{
					ssl.reset();
					// @todo replace 80 with MAX_ERROR_SZ or whatever's appropriate for yaSSL in some nice way...
					char errbuf[80];

					/* TODO: better message for SSL_ERROR_SYSCALL
					 * If the error queue is empty (i.e. ERR_get_error() returns 0), ret can be used to find out more about the error: 
					 * If ret == 0, an EOF was observed that violates the protocol. If ret == -1, the underlying BIO reported an I/O error 
					 * (for socket I/O on Unix systems, consult errno for details).
					 */
					int error = ERR_get_error();
					sprintf(errbuf, "%s %d: %s", CSTRING(SSL_ERROR), err, (error == 0) ? CSTRING(CONNECTION_CLOSED) : ERR_reason_error_string(error));
					throw SSLSocketException(errbuf);
				}
		}
	}
	return ret;
}

int SSLSocket::wait(uint64_t millis, int waitFor) throw(SocketException) {
#ifdef HEADER_OPENSSLV_H
	if(ssl && (waitFor & Socket::WAIT_READ)) {
		/** @todo Take writing into account as well if reading is possible? */
		char c;
		if(SSL_peek(ssl, &c, 1) > 0)
			return WAIT_READ;
	}
#endif
	return Socket::wait(millis, waitFor);
}

bool SSLSocket::isTrusted() throw() {
	if(!ssl) {
		return false;
	}

#ifdef HEADER_OPENSSLV_H
	if(SSL_get_verify_result(ssl) != X509_V_OK) {
		return false;
	}
#else
	if(gnutls_certificate_verify_peers(((SSL*)ssl)->gnutls_state) != 0) {
		return false;
	}
#endif

	X509* cert = SSL_get_peer_certificate(ssl);
	if(!cert) {
		return false;
	}

	X509_free(cert);

	return true;
}

std::string SSLSocket::getCipherName() throw() {
	if(!ssl)
		return Util::emptyString;
	
	return SSL_get_cipher_name(ssl);
}

std::string SSLSocket::getDigest() const throw() {
#ifdef HEADER_OPENSSLV_H

	if(!ssl)
		return Util::emptyString;
	X509* x509 = SSL_get_peer_certificate(ssl);
	if(!x509)
		return Util::emptyString;
	
	return ssl::X509_digest(x509, EVP_sha1());
#else
	return Util::emptyString;
#endif
}

void SSLSocket::shutdown() throw() {
	if(ssl)
		SSL_shutdown(ssl);
}

void SSLSocket::close() throw() {
	if(ssl) {
		ssl.reset();
	}
	Socket::shutdown();
	Socket::close();
}

} // namespace dcpp
Example #18
0
static void net_on_input(peer_t *peer)
{
	int ret = 0;
	int nbyte = 0;
	netc_t *netc = NULL;

	netc = peer->ext_ptr;
	peer->buffer_data_len = peer->recv(peer);

	if (netc->security_level > NET_UNSECURE
			&& netc->kconn->status == KRYPT_HANDSHAKE) {


		ret = krypt_do_handshake(netc->kconn, peer->buffer, peer->buffer_data_len);
		peer->buffer_data_len = 0;
		net_do_krypt(netc);
		if (ret == 0) {				// handshake successfull

			netc->on_secure(netc);		// inform upper-layer

			// Handle the fact that we can receive handshake data
			// and DNDS Messages at the same time from the underlying
			// network buffer.
			char peek;
			ret = SSL_peek(netc->kconn->ssl, &peek, 1);
			if (ret == 1) {
				// There is still data in the SSL object,
				// continue further to process pending data.
			}
			else {
				return;
			}
		}
		else if (ret == -1) {			// handshake failed
			netc->on_disconnect(netc);	// inform upper-layer
			peer->disconnect(peer);		// inform lower-layer
			net_connection_free(netc);
			return;
		}

		// handshake flow ends here if no more data has to be processed
	}

	if (netc->security_level > NET_UNSECURE
			&& netc->kconn->status == KRYPT_SECURE) {

		int peek = 0; // buffer to hold the byte we are peeking at
		int state_p = 0;

		do {
			nbyte = krypt_push_encrypted_data(netc->kconn, peer->buffer + peer->buffer_offset,
								peer->buffer_data_len);

			if (nbyte > 0 && nbyte < peer->buffer_data_len) {
				peer->buffer_data_len -= nbyte;
				peer->buffer_offset += nbyte;
			}
			else{
				peer->buffer_data_len = 0;
				peer->buffer_offset = 0;
			}

			ret = krypt_decrypt_buf(netc->kconn);
			if (ret == 0) {
				serialize_buf_in(netc, netc->kconn->buf_decrypt, netc->kconn->buf_decrypt_data_size);
				netc->kconn->buf_decrypt_data_size = 0; // mark the buffer as empty
				state_p = SSL_peek(netc->kconn->ssl, &peek, 1);
			}
			net_do_krypt(netc);

			// decryption doesn't fail and (SSL data pending or data to feed to BIO)
		} while (ret == 0 && (state_p == 1 || peer->buffer_data_len > 0));
	}
	else if (netc->security_level == NET_UNSECURE) {
		serialize_buf_in(netc, peer->buffer, peer->buffer_data_len);
	}

	ret = net_decode_msg(netc);
	if (ret == -1) {
		netc->on_disconnect(netc);	// inform upper-layer
		peer->disconnect(peer);		// inform lower-layer
		net_connection_free(netc);
	}
	else if (netc->security_level > NET_UNSECURE
			&& netc->kconn->status == KRYPT_SECURE) {

		/* Catch server renegotiation */
		krypt_decrypt_buf(netc->kconn);
		net_do_krypt(netc);

		if (mbuf_count(netc->queue_msg) > 0)
			netc->on_input(netc);
	}
}
Example #19
0
/* OS dependent */
Boolean rocs_socket_readpeek( iOSocket inst, char* buf, int size, Boolean peek ) {
#ifdef __ROCS_SOCKET__
    iOSocketData o = Data(inst);
    int readed   = 0;
    int treaded  = 0;
    int flags    = peek ? MSG_PEEK:0;

    o->readed = 0;

    while( treaded < size ) {

        if( o->ssl ) {
#ifdef __OPENSSL__
            if( peek )
                readed = SSL_peek( o->ssl_sh, buf + treaded, size - treaded );
            else
                readed = SSL_read( o->ssl_sh, buf + treaded, size - treaded );
#endif
        }
        else
            readed = recv( o->sh, buf + treaded, size - treaded, flags );

        /* Has otherside closed the connection? */
        if( readed == 0 ) {
            o->rc = errno;
            o->broken = True;
            TraceOp.trc( name, TRCLEVEL_INFO, __LINE__, 9999, "Other side has closed connection." );
            TraceOp.trc( name, TRCLEVEL_DEBUG, __LINE__, 9999, "errno=%d, read=%d", errno, readed );
            return False;
        }

        if( peek ) {
            o->rc = WSAGetLastError();
            o->peeked = readed;
            if( readed == -1 && o->rc != 0 && o->rc != WSAETIMEDOUT && o->rc != WSAEINTR && o->rc != WSAEWOULDBLOCK ) {
                if( o->ssl ) {
#ifdef __OPENSSL__
                    ERR_print_errors_fp( (FILE*)TraceOp.getF(NULL) );
                    fflush( (FILE*)TraceOp.getF(NULL) );
#endif
                }

                TraceOp.trc( name, TRCLEVEL_WARNING, __LINE__, 9999, "*broken* errno=%d, rc=%d, readed=%d", errno, o->rc, readed );
                o->broken = True;
            }
            /* WinSock problems: http://sources.redhat.com/ml/cygwin/2001-08/msg00628.html
             * MSG_PEEK always returns 1 with Windows NT & 2000; XP returns correct number. */
            /* return (readed >= size) ? True:False; */
            return (readed >= 1) ? True:False;
        }

        if( readed < 0 )
        {
            o->rc = WSAGetLastError();
            /* For none blocking...
            if( !o->blocking && o->rc == WSAEWOULDBLOCK ) {
              ThreadOp.sleep(10);
              continue;
            }
            */
            if( o->rc == WSAEWOULDBLOCK || o->rc == WSAESHUTDOWN || o->rc == WSAENOTSOCK || o->rc == WSAETIMEDOUT || o->rc == WSAECONNRESET )
                rocs_socket_close(o);

            if( o->ssl ) {
#ifdef __OPENSSL__
                ERR_print_errors_fp( (FILE*)TraceOp.getF(NULL) );
                fflush( (FILE*)TraceOp.getF(NULL) );
#endif
            }

            TraceOp.trc( name, TRCLEVEL_EXCEPTION, __LINE__, 9999, "recv() failed [%d] size=%d readed=%d", o->rc, size, treaded );

            return False;
        }
        treaded += readed;
    }
    o->readed = treaded;
    if( treaded > 1 )
        TraceOp.trc( name, TRCLEVEL_DEBUG, __LINE__, 9999, "%d bytes read from socket.", treaded );
#endif
    return True;
}
Example #20
0
int Jatta::Network::SocketTCP::Peek(void* data, unsigned int size)
{
#   ifdef OpenSSL_FOUND
    if (connectionSecure)
    {
        int amount;
        if (sock == INVALID_SOCKET)
        {
            return false;
        }

        while (true)
        {
            amount = SSL_peek(sslHandle, (char*)data, size);

            if (amount == 0)
            {
                Close();
                return 0;
            }
            else if (amount > 0)
            {
                return amount;
            }

            int error = SSL_get_error(sslHandle, amount);

            if (error == SSL_ERROR_WANT_READ || error == SSL_ERROR_WANT_WRITE)
            {
                //Handle these errors then try again.
                //Just waiting it out seems to work.
            }
            else
            {
                throw NetworkException(NetworkExceptionCode::FAILED_PEEK, NetworkExceptionReason::UNKNOWN);
            }
        }
    }
#   endif
    // Check if the socket is valid before we continue.
    if (sock == INVALID_SOCKET)
    {
        throw NetworkException(NetworkExceptionCode::FAILED_PEEK, NetworkExceptionReason::SOCKET_INVALID);
    }

    // Pizza delivery!
    int amount;
    //Peek normally
    if ((amount = ::recv(sock, (char*)data, size, MSG_PEEK)) == SOCKET_ERROR)
    {
        // Check if recv failed because of a WOULDBLOCK error.  This basically means that there was
        // nothing to be received.  In that case, just return 0.  Otherwise, there was an error.
#       ifdef JATTA_WINDOWS
        if (WSAGetLastError() == WSAEWOULDBLOCK)
#       else
        if (errno == EWOULDBLOCK)
#       endif
        {
            return 0;
        }
        else
        {
            throw NetworkException(NetworkExceptionCode::FAILED_PEEK, NetworkExceptionReason::UNKNOWN);
        }
    }

    // Check if recv returned 0, if so, the remove socket disconnected gracefully.
    if (amount == 0)
    {
        Close();
        return 0;
    }
    else
    {
        return amount;
    }
}
Example #21
0
File: socket.c Project: lb1a/avfs
/* This is from from Eric Raymond's fetchmail (SockRead() in socket.c)
 * since I wouldn't have a clue how to do it properly.
 * This function is Copyright 1999 (C) Eric Raymond.
 * Modifications Copyright 2000 (C) Joe Orton
 */
int sock_readline(nsocket *sock, char *buf, int len)
{
    char *newline, *bp = buf;
    int n;

    do {
	/* 
	 * The reason for these gymnastics is that we want two things:
	 * (1) to read \n-terminated lines,
	 * (2) to return the true length of data read, even if the
	 *     data coming in has embedded NULS.
	 */
#ifdef	ENABLE_SSL

	if (sock->ssl) {
	    /* Hack alert! */
	    /* OK...  SSL_peek works a little different from MSG_PEEK
	       Problem is that SSL_peek can return 0 if there is no
	       data currently available.  If, on the other hand, we
	       loose the socket, we also get a zero, but the SSL_read
	       then SEGFAULTS!  To deal with this, we'll check the
	       error code any time we get a return of zero from
	       SSL_peek.  If we have an error, we bail.  If we don't,
	       we read one character in SSL_read and loop.  This
	       should continue to work even if they later change the
	       behavior of SSL_peek to "fix" this problem...  :-(*/
	    DEBUG(DEBUG_SOCKET, "SSL readline... \n");
	    if ((n = SSL_peek(sock->ssl, bp, len)) < 0) {
		sock->error = ERROR_SSL_STRING;
		return(-1);
	    }
	    if (0 == n) {
		/* SSL_peek says no data...  Does he mean no data
		   or did the connection blow up?  If we got an error
		   then bail! */
		DEBUG(DEBUG_SOCKET, "SSL_Peek says no data!\n");
		/* Check properly to see if the connection has closed */
		if (sock->ssl->shutdown) {
		    DEBUG(DEBUG_SOCKET, "SSL says shutdown.");
		    return SOCK_CLOSED;
		} else if (0 != (n = ERR_get_error())) {
		    DEBUG(DEBUG_SOCKET, "SSL error occured.\n");
		    sock->error = ERROR_SSL_STRING;
		    return -1;
		}
		    
		/* We didn't get an error so read at least one
		   character at this point and loop */
		n = 1;
		/* Make sure newline start out NULL!  We don't have a
		 * string to pass through the strchr at this point yet
		 * */
		newline = NULL;
	    } else if ((newline = memchr(bp, '\n', n)) != NULL)
		n = newline - bp + 1;
	    n = SSL_read(sock->ssl, bp, n);
	    DEBUG(DEBUG_SOCKET, "SSL_read returned %d\n", n);
	    if (n == -1) {
		sock->error = ERROR_SSL_STRING;
		return(-1);
	    }
	    /* Check for case where our single character turned out to
	     * be a newline...  (It wasn't going to get caught by
	     * the strchr above if it came from the hack...). */
	    if (NULL == newline && 1 == n && '\n' == *bp) {
		/* Got our newline - this will break
				out of the loop now */
		newline = bp;
	    }
	} else {
#endif
	    if ((n = sock_peek(sock, bp, len)) <= 0)
		return n;
	    if ((newline = memchr(bp, '\n', n)) != NULL)
		n = newline - bp + 1;
	    if ((n = sock_read(sock, bp, n)) < 0)
		return n;
#ifdef ENABLE_SSL
	}
#endif
	bp += n;
	len -= n;
	if (len < 1) {
	    sock->error = _("Line too long");
	    return SOCK_FULL;
	}
    } while (!newline && len);
    *bp = '\0';
    return bp - buf;
}
Example #22
0
int dual_tls_recv(rad_listen_t *listener)
{
	RADIUS_PACKET *packet;
	RAD_REQUEST_FUNP fun = NULL;
	listen_socket_t *sock = listener->data;
	RADCLIENT	*client = sock->client;
	BIO		*rbio;

	if (listener->status != RAD_LISTEN_STATUS_KNOWN) return 0;

redo:
	if (!tls_socket_recv(listener)) {
		return 0;
	}

	rad_assert(sock->packet != NULL);
	rad_assert(sock->ssn != NULL);
	rad_assert(client != NULL);

	packet = talloc_steal(NULL, sock->packet);
	sock->packet = NULL;

	/*
	 *	Some sanity checks, based on the packet code.
	 *
	 *	"auth+acct" are marked as "auth", with the "dual" flag
	 *	set.
	 */
	switch (packet->code) {
	case PW_CODE_ACCESS_REQUEST:
		if (listener->type != RAD_LISTEN_AUTH) goto bad_packet;
		FR_STATS_INC(auth, total_requests);
		fun = rad_authenticate;
		break;

#ifdef WITH_ACCOUNTING
	case PW_CODE_ACCOUNTING_REQUEST:
		if (listener->type != RAD_LISTEN_ACCT) {
			/*
			 *	Allow auth + dual.  Disallow
			 *	everything else.
			 */
			if (!((listener->type == RAD_LISTEN_AUTH) &&
			      (listener->dual))) {
				    goto bad_packet;
			}
		}
		FR_STATS_INC(acct, total_requests);
		fun = rad_accounting;
		break;
#endif

	case PW_CODE_STATUS_SERVER:
		if (!main_config.status_server) {
			FR_STATS_INC(auth, total_unknown_types);
			WARN("Ignoring Status-Server request due to security configuration");
			rad_free(&packet);
			return 0;
		}
		fun = rad_status_server;
		break;

	default:
	bad_packet:
		FR_STATS_INC(auth, total_unknown_types);

		DEBUG("Invalid packet code %d sent from client %s port %d : IGNORED",
		      packet->code, client->shortname, packet->src_port);
		rad_free(&packet);
		return 0;
	} /* switch over packet types */

	if (!request_receive(NULL, listener, packet, client, fun)) {
		FR_STATS_INC(auth, total_packets_dropped);
		rad_free(&packet);
		return 0;
	}

	/*
	 *	Check for more application data.
	 *
	 *	If there is pending SSL data, "peek" at the
	 *	application data.  If we get at least one byte of
	 *	application data, go back to tls_socket_recv().
	 *	SSL_peek() will set SSL_pending(), and
	 *	tls_socket_recv() will read another packet.
	 */
	rbio = SSL_get_rbio(sock->ssn->ssl);
	if (BIO_ctrl_pending(rbio)) {
		char buf[1];
		int peek = SSL_peek(sock->ssn->ssl, buf, 1);

		if (peek > 0) {
			DEBUG("more TLS records after dual_tls_recv");
			goto redo;
		}
	}

	return 1;
}
Example #23
0
int MAIN(int argc, char **argv)
{
    int off=0;
    SSL *con=NULL,*con2=NULL;
    X509_STORE *store = NULL;
    int s,k,width,state=0;
    char *cbuf=NULL,*sbuf=NULL,*mbuf=NULL;
    int cbuf_len,cbuf_off;
    int sbuf_len,sbuf_off;
    fd_set readfds,writefds;
    short port=PORT;
    int full_log=1;
    char *host=SSL_HOST_NAME;
    char *cert_file=NULL,*key_file=NULL;
    int cert_format = FORMAT_PEM, key_format = FORMAT_PEM;
    char *passarg = NULL, *pass = NULL;
    X509 *cert = NULL;
    EVP_PKEY *key = NULL;
    char *CApath=NULL,*CAfile=NULL,*cipher=NULL;
    int reconnect=0,badop=0,verify=SSL_VERIFY_NONE,bugs=0;
    int crlf=0;
    int write_tty,read_tty,write_ssl,read_ssl,tty_on,ssl_pending;
    SSL_CTX *ctx=NULL;
    int ret=1,in_init=1,i,nbio_test=0;
    int starttls_proto = PROTO_OFF;
    int prexit = 0, vflags = 0;
    SSL_METHOD *meth=NULL;
#ifdef sock_type
#undef sock_type
#endif
    int sock_type=SOCK_STREAM;
    BIO *sbio;
    char *inrand=NULL;
    int mbuf_len=0;
#ifndef OPENSSL_NO_ENGINE
    char *engine_id=NULL;
    ENGINE *e=NULL;
#endif
#if defined(OPENSSL_SYS_WINDOWS) || defined(OPENSSL_SYS_MSDOS) || defined(OPENSSL_SYS_NETWARE)
    struct timeval tv;
#endif

    struct sockaddr peer;
    int peerlen = sizeof(peer);
    int enable_timeouts = 0 ;
    long mtu = 0;

#if !defined(OPENSSL_NO_SSL2) && !defined(OPENSSL_NO_SSL3)
    meth=SSLv23_client_method();
#elif !defined(OPENSSL_NO_SSL3)
    meth=SSLv3_client_method();
#elif !defined(OPENSSL_NO_SSL2)
    meth=SSLv2_client_method();
#endif

    apps_startup();
    c_Pause=0;
    c_quiet=0;
    c_ign_eof=0;
    c_debug=0;
    c_msg=0;
    c_showcerts=0;

    if (bio_err == NULL)
        bio_err=BIO_new_fp(stderr,BIO_NOCLOSE);

    if (!load_config(bio_err, NULL))
        goto end;

    if (	((cbuf=OPENSSL_malloc(BUFSIZZ)) == NULL) ||
            ((sbuf=OPENSSL_malloc(BUFSIZZ)) == NULL) ||
            ((mbuf=OPENSSL_malloc(BUFSIZZ)) == NULL))
    {
        BIO_printf(bio_err,"out of memory\n");
        goto end;
    }

    verify_depth=0;
    verify_error=X509_V_OK;
#ifdef FIONBIO
    c_nbio=0;
#endif

    argc--;
    argv++;
    while (argc >= 1)
    {
        if	(strcmp(*argv,"-host") == 0)
        {
            if (--argc < 1) goto bad;
            host= *(++argv);
        }
        else if	(strcmp(*argv,"-port") == 0)
        {
            if (--argc < 1) goto bad;
            port=atoi(*(++argv));
            if (port == 0) goto bad;
        }
        else if (strcmp(*argv,"-connect") == 0)
        {
            if (--argc < 1) goto bad;
            if (!extract_host_port(*(++argv),&host,NULL,&port))
                goto bad;
        }
        else if	(strcmp(*argv,"-verify") == 0)
        {
            verify=SSL_VERIFY_PEER;
            if (--argc < 1) goto bad;
            verify_depth=atoi(*(++argv));
            BIO_printf(bio_err,"verify depth is %d\n",verify_depth);
        }
        else if	(strcmp(*argv,"-cert") == 0)
        {
            if (--argc < 1) goto bad;
            cert_file= *(++argv);
        }
        else if	(strcmp(*argv,"-certform") == 0)
        {
            if (--argc < 1) goto bad;
            cert_format = str2fmt(*(++argv));
        }
        else if	(strcmp(*argv,"-crl_check") == 0)
            vflags |= X509_V_FLAG_CRL_CHECK;
        else if	(strcmp(*argv,"-crl_check_all") == 0)
            vflags |= X509_V_FLAG_CRL_CHECK|X509_V_FLAG_CRL_CHECK_ALL;
        else if	(strcmp(*argv,"-prexit") == 0)
            prexit=1;
        else if	(strcmp(*argv,"-crlf") == 0)
            crlf=1;
        else if	(strcmp(*argv,"-quiet") == 0)
        {
            c_quiet=1;
            c_ign_eof=1;
        }
        else if	(strcmp(*argv,"-ign_eof") == 0)
            c_ign_eof=1;
        else if	(strcmp(*argv,"-pause") == 0)
            c_Pause=1;
        else if	(strcmp(*argv,"-debug") == 0)
            c_debug=1;
#ifdef WATT32
        else if (strcmp(*argv,"-wdebug") == 0)
            dbug_init();
#endif
        else if	(strcmp(*argv,"-msg") == 0)
            c_msg=1;
        else if	(strcmp(*argv,"-showcerts") == 0)
            c_showcerts=1;
        else if	(strcmp(*argv,"-nbio_test") == 0)
            nbio_test=1;
        else if	(strcmp(*argv,"-state") == 0)
            state=1;
#ifndef OPENSSL_NO_SSL2
        else if	(strcmp(*argv,"-ssl2") == 0)
            meth=SSLv2_client_method();
#endif
#ifndef OPENSSL_NO_SSL3
        else if	(strcmp(*argv,"-ssl3") == 0)
            meth=SSLv3_client_method();
#endif
#ifndef OPENSSL_NO_TLS1
        else if	(strcmp(*argv,"-tls1") == 0)
            meth=TLSv1_client_method();
#endif
#ifndef OPENSSL_NO_DTLS1
        else if	(strcmp(*argv,"-dtls1") == 0)
        {
            meth=DTLSv1_client_method();
            sock_type=SOCK_DGRAM;
        }
        else if (strcmp(*argv,"-timeout") == 0)
            enable_timeouts=1;
        else if (strcmp(*argv,"-mtu") == 0)
        {
            if (--argc < 1) goto bad;
            mtu = atol(*(++argv));
        }
#endif
        else if (strcmp(*argv,"-bugs") == 0)
            bugs=1;
        else if	(strcmp(*argv,"-keyform") == 0)
        {
            if (--argc < 1) goto bad;
            key_format = str2fmt(*(++argv));
        }
        else if	(strcmp(*argv,"-pass") == 0)
        {
            if (--argc < 1) goto bad;
            passarg = *(++argv);
        }
        else if	(strcmp(*argv,"-key") == 0)
        {
            if (--argc < 1) goto bad;
            key_file= *(++argv);
        }
        else if	(strcmp(*argv,"-reconnect") == 0)
        {
            reconnect=5;
        }
        else if	(strcmp(*argv,"-CApath") == 0)
        {
            if (--argc < 1) goto bad;
            CApath= *(++argv);
        }
        else if	(strcmp(*argv,"-CAfile") == 0)
        {
            if (--argc < 1) goto bad;
            CAfile= *(++argv);
        }
        else if (strcmp(*argv,"-no_tls1") == 0)
            off|=SSL_OP_NO_TLSv1;
        else if (strcmp(*argv,"-no_ssl3") == 0)
            off|=SSL_OP_NO_SSLv3;
        else if (strcmp(*argv,"-no_ssl2") == 0)
            off|=SSL_OP_NO_SSLv2;
        else if (strcmp(*argv,"-serverpref") == 0)
            off|=SSL_OP_CIPHER_SERVER_PREFERENCE;
        else if	(strcmp(*argv,"-cipher") == 0)
        {
            if (--argc < 1) goto bad;
            cipher= *(++argv);
        }
#ifdef FIONBIO
        else if (strcmp(*argv,"-nbio") == 0)
        {
            c_nbio=1;
        }
#endif
        else if	(strcmp(*argv,"-starttls") == 0)
        {
            if (--argc < 1) goto bad;
            ++argv;
            if (strcmp(*argv,"smtp") == 0)
                starttls_proto = PROTO_SMTP;
            else if (strcmp(*argv,"pop3") == 0)
                starttls_proto = PROTO_POP3;
            else if (strcmp(*argv,"imap") == 0)
                starttls_proto = PROTO_IMAP;
            else if (strcmp(*argv,"ftp") == 0)
                starttls_proto = PROTO_FTP;
            else
                goto bad;
        }
#ifndef OPENSSL_NO_ENGINE
        else if	(strcmp(*argv,"-engine") == 0)
        {
            if (--argc < 1) goto bad;
            engine_id = *(++argv);
        }
#endif
        else if (strcmp(*argv,"-rand") == 0)
        {
            if (--argc < 1) goto bad;
            inrand= *(++argv);
        }
        else
        {
            BIO_printf(bio_err,"unknown option %s\n",*argv);
            badop=1;
            break;
        }
        argc--;
        argv++;
    }
    if (badop)
    {
bad:
        sc_usage();
        goto end;
    }

    OpenSSL_add_ssl_algorithms();
    SSL_load_error_strings();

#ifndef OPENSSL_NO_ENGINE
    e = setup_engine(bio_err, engine_id, 1);
#endif
    if (!app_passwd(bio_err, passarg, NULL, &pass, NULL))
    {
        BIO_printf(bio_err, "Error getting password\n");
        goto end;
    }

    if (key_file == NULL)
        key_file = cert_file;


    if (key_file)

    {

        key = load_key(bio_err, key_file, key_format, 0, pass, e,
                       "client certificate private key file");
        if (!key)
        {
            ERR_print_errors(bio_err);
            goto end;
        }

    }

    if (cert_file)

    {
        cert = load_cert(bio_err,cert_file,cert_format,
                         NULL, e, "client certificate file");

        if (!cert)
        {
            ERR_print_errors(bio_err);
            goto end;
        }
    }

    if (!app_RAND_load_file(NULL, bio_err, 1) && inrand == NULL
            && !RAND_status())
    {
        BIO_printf(bio_err,"warning, not much extra random data, consider using the -rand option\n");
    }
    if (inrand != NULL)
        BIO_printf(bio_err,"%ld semi-random bytes loaded\n",
                   app_RAND_load_files(inrand));

    if (bio_c_out == NULL)
    {
        if (c_quiet && !c_debug && !c_msg)
        {
            bio_c_out=BIO_new(BIO_s_null());
        }
        else
        {
            if (bio_c_out == NULL)
                bio_c_out=BIO_new_fp(stdout,BIO_NOCLOSE);
        }
    }

    ctx=SSL_CTX_new(meth);
    if (ctx == NULL)
    {
        ERR_print_errors(bio_err);
        goto end;
    }

    if (bugs)
        SSL_CTX_set_options(ctx,SSL_OP_ALL|off);
    else
        SSL_CTX_set_options(ctx,off);
    /* DTLS: partial reads end up discarding unread UDP bytes :-(
     * Setting read ahead solves this problem.
     */
    if (sock_type == SOCK_DGRAM) SSL_CTX_set_read_ahead(ctx, 1);

    if (state) SSL_CTX_set_info_callback(ctx,apps_ssl_info_callback);
    if (cipher != NULL)
        if(!SSL_CTX_set_cipher_list(ctx,cipher)) {
            BIO_printf(bio_err,"error setting cipher list\n");
            ERR_print_errors(bio_err);
            goto end;
        }
#if 0
        else
            SSL_CTX_set_cipher_list(ctx,getenv("SSL_CIPHER"));
#endif

    SSL_CTX_set_verify(ctx,verify,verify_callback);
    if (!set_cert_key_stuff(ctx,cert,key))
        goto end;

    if ((!SSL_CTX_load_verify_locations(ctx,CAfile,CApath)) ||
            (!SSL_CTX_set_default_verify_paths(ctx)))
    {
        /* BIO_printf(bio_err,"error setting default verify locations\n"); */
        ERR_print_errors(bio_err);
        /* goto end; */
    }

    store = SSL_CTX_get_cert_store(ctx);
    X509_STORE_set_flags(store, vflags);

    con=SSL_new(ctx);
#ifndef OPENSSL_NO_KRB5
    if (con  &&  (con->kssl_ctx = kssl_ctx_new()) != NULL)
    {
        kssl_ctx_setstring(con->kssl_ctx, KSSL_SERVER, host);
    }
#endif	/* OPENSSL_NO_KRB5  */
    /*	SSL_set_cipher_list(con,"RC4-MD5"); */

re_start:

    if (init_client(&s,host,port,sock_type) == 0)
    {
        BIO_printf(bio_err,"connect:errno=%d\n",get_last_socket_error());
        SHUTDOWN(s);
        goto end;
    }
    BIO_printf(bio_c_out,"CONNECTED(%08X)\n",s);

#ifdef FIONBIO
    if (c_nbio)
    {
        unsigned long l=1;
        BIO_printf(bio_c_out,"turning on non blocking io\n");
        if (BIO_socket_ioctl(s,FIONBIO,&l) < 0)
        {
            ERR_print_errors(bio_err);
            goto end;
        }
    }
#endif
    if (c_Pause & 0x01) con->debug=1;

    if ( SSL_version(con) == DTLS1_VERSION)
    {
        struct timeval timeout;

        sbio=BIO_new_dgram(s,BIO_NOCLOSE);
        if (getsockname(s, &peer, (void *)&peerlen) < 0)
        {
            BIO_printf(bio_err, "getsockname:errno=%d\n",
                       get_last_socket_error());
            SHUTDOWN(s);
            goto end;
        }

        (void)BIO_ctrl_set_connected(sbio, 1, &peer);

        if ( enable_timeouts)
        {
            timeout.tv_sec = 0;
            timeout.tv_usec = DGRAM_RCV_TIMEOUT;
            BIO_ctrl(sbio, BIO_CTRL_DGRAM_SET_RECV_TIMEOUT, 0, &timeout);

            timeout.tv_sec = 0;
            timeout.tv_usec = DGRAM_SND_TIMEOUT;
            BIO_ctrl(sbio, BIO_CTRL_DGRAM_SET_SEND_TIMEOUT, 0, &timeout);
        }

        if ( mtu > 0)
        {
            SSL_set_options(con, SSL_OP_NO_QUERY_MTU);
            SSL_set_mtu(con, mtu);
        }
        else
            /* want to do MTU discovery */
            BIO_ctrl(sbio, BIO_CTRL_DGRAM_MTU_DISCOVER, 0, NULL);
    }
    else
        sbio=BIO_new_socket(s,BIO_NOCLOSE);



    if (nbio_test)
    {
        BIO *test;

        test=BIO_new(BIO_f_nbio_test());
        sbio=BIO_push(test,sbio);
    }

    if (c_debug)
    {
        con->debug=1;
        BIO_set_callback(sbio,bio_dump_callback);
        BIO_set_callback_arg(sbio,(char *)bio_c_out);
    }
    if (c_msg)
    {
        SSL_set_msg_callback(con, msg_cb);
        SSL_set_msg_callback_arg(con, bio_c_out);
    }

    SSL_set_bio(con,sbio,sbio);
    SSL_set_connect_state(con);

    /* ok, lets connect */
    width=SSL_get_fd(con)+1;

    read_tty=1;
    write_tty=0;
    tty_on=0;
    read_ssl=1;
    write_ssl=1;

    cbuf_len=0;
    cbuf_off=0;
    sbuf_len=0;
    sbuf_off=0;

    /* This is an ugly hack that does a lot of assumptions */
    /* We do have to handle multi-line responses which may come
       in a single packet or not. We therefore have to use
       BIO_gets() which does need a buffering BIO. So during
       the initial chitchat we do push a buffering BIO into the
       chain that is removed again later on to not disturb the
       rest of the s_client operation. */
    if (starttls_proto == PROTO_SMTP)
    {
        int foundit=0;
        BIO *fbio = BIO_new(BIO_f_buffer());
        BIO_push(fbio, sbio);
        /* wait for multi-line response to end from SMTP */
        do
        {
            mbuf_len = BIO_gets(fbio,mbuf,BUFSIZZ);
        }
        while (mbuf_len>3 && mbuf[3]=='-');
        /* STARTTLS command requires EHLO... */
        BIO_printf(fbio,"EHLO openssl.client.net\r\n");
        (void)BIO_flush(fbio);
        /* wait for multi-line response to end EHLO SMTP response */
        do
        {
            mbuf_len = BIO_gets(fbio,mbuf,BUFSIZZ);
            if (strstr(mbuf,"STARTTLS"))
                foundit=1;
        }
        while (mbuf_len>3 && mbuf[3]=='-');
        (void)BIO_flush(fbio);
        BIO_pop(fbio);
        BIO_free(fbio);
        if (!foundit)
            BIO_printf(bio_err,
                       "didn't found starttls in server response,"
                       " try anyway...\n");
        BIO_printf(sbio,"STARTTLS\r\n");
        BIO_read(sbio,sbuf,BUFSIZZ);
    }
    else if (starttls_proto == PROTO_POP3)
    {
        BIO_read(sbio,mbuf,BUFSIZZ);
        BIO_printf(sbio,"STLS\r\n");
        BIO_read(sbio,sbuf,BUFSIZZ);
    }
    else if (starttls_proto == PROTO_IMAP)
    {
        int foundit=0;
        BIO *fbio = BIO_new(BIO_f_buffer());
        BIO_push(fbio, sbio);
        BIO_gets(fbio,mbuf,BUFSIZZ);
        /* STARTTLS command requires CAPABILITY... */
        BIO_printf(fbio,". CAPABILITY\r\n");
        (void)BIO_flush(fbio);
        /* wait for multi-line CAPABILITY response */
        do
        {
            mbuf_len = BIO_gets(fbio,mbuf,BUFSIZZ);
            if (strstr(mbuf,"STARTTLS"))
                foundit=1;
        }
        while (mbuf_len>3 && mbuf[0]!='.');
        (void)BIO_flush(fbio);
        BIO_pop(fbio);
        BIO_free(fbio);
        if (!foundit)
            BIO_printf(bio_err,
                       "didn't found STARTTLS in server response,"
                       " try anyway...\n");
        BIO_printf(sbio,". STARTTLS\r\n");
        BIO_read(sbio,sbuf,BUFSIZZ);
    }
    else if (starttls_proto == PROTO_FTP)
    {
        BIO *fbio = BIO_new(BIO_f_buffer());
        BIO_push(fbio, sbio);
        /* wait for multi-line response to end from FTP */
        do
        {
            mbuf_len = BIO_gets(fbio,mbuf,BUFSIZZ);
        }
        while (mbuf_len>3 && mbuf[3]=='-');
        (void)BIO_flush(fbio);
        BIO_pop(fbio);
        BIO_free(fbio);
        BIO_printf(sbio,"AUTH TLS\r\n");
        BIO_read(sbio,sbuf,BUFSIZZ);
    }

    for (;;)
    {
        FD_ZERO(&readfds);
        FD_ZERO(&writefds);

        if (SSL_in_init(con) && !SSL_total_renegotiations(con))
        {
            in_init=1;
            tty_on=0;
        }
        else
        {
            tty_on=1;
            if (in_init)
            {
                in_init=0;
                print_stuff(bio_c_out,con,full_log);
                if (full_log > 0) full_log--;

                if (starttls_proto)
                {
                    BIO_printf(bio_err,"%s",mbuf);
                    /* We don't need to know any more */
                    starttls_proto = PROTO_OFF;
                }

                if (reconnect)
                {
                    reconnect--;
                    BIO_printf(bio_c_out,"drop connection and then reconnect\n");
                    SSL_shutdown(con);
                    SSL_set_connect_state(con);
                    SHUTDOWN(SSL_get_fd(con));
                    goto re_start;
                }
            }
        }

        ssl_pending = read_ssl && SSL_pending(con);

        if (!ssl_pending)
        {
#if !defined(OPENSSL_SYS_WINDOWS) && !defined(OPENSSL_SYS_MSDOS) && !defined(OPENSSL_SYS_NETWARE)
            if (tty_on)
            {
                if (read_tty)  FD_SET(fileno(stdin),&readfds);
                if (write_tty) FD_SET(fileno(stdout),&writefds);
            }
            if (read_ssl)
                FD_SET(SSL_get_fd(con),&readfds);
            if (write_ssl)
                FD_SET(SSL_get_fd(con),&writefds);
#else
            if(!tty_on || !write_tty) {
                if (read_ssl)
                    FD_SET(SSL_get_fd(con),&readfds);
                if (write_ssl)
                    FD_SET(SSL_get_fd(con),&writefds);
            }
#endif
            /*			printf("mode tty(%d %d%d) ssl(%d%d)\n",
            				tty_on,read_tty,write_tty,read_ssl,write_ssl);*/

            /* Note: under VMS with SOCKETSHR the second parameter
             * is currently of type (int *) whereas under other
             * systems it is (void *) if you don't have a cast it
             * will choke the compiler: if you do have a cast then
             * you can either go for (int *) or (void *).
             */
#if defined(OPENSSL_SYS_WINDOWS) || defined(OPENSSL_SYS_MSDOS)
            /* Under Windows/DOS we make the assumption that we can
            * always write to the tty: therefore if we need to
            		 * write to the tty we just fall through. Otherwise
            		 * we timeout the select every second and see if there
            		 * are any keypresses. Note: this is a hack, in a proper
            		 * Windows application we wouldn't do this.
            		 */
            i=0;
            if(!write_tty) {
                if(read_tty) {
                    tv.tv_sec = 1;
                    tv.tv_usec = 0;
                    i=select(width,(void *)&readfds,(void *)&writefds,
                             NULL,&tv);
#if defined(OPENSSL_SYS_WINCE) || defined(OPENSSL_SYS_MSDOS)
                    if(!i && (!_kbhit() || !read_tty) ) continue;
#else
                    if(!i && (!((_kbhit()) || (WAIT_OBJECT_0 == WaitForSingleObject(GetStdHandle(STD_INPUT_HANDLE), 0))) || !read_tty) ) continue;
#endif
                } else 	i=select(width,(void *)&readfds,(void *)&writefds,
                                     NULL,NULL);
            }
#elif defined(OPENSSL_SYS_NETWARE)
            if(!write_tty) {
                if(read_tty) {
                    tv.tv_sec = 1;
                    tv.tv_usec = 0;
                    i=select(width,(void *)&readfds,(void *)&writefds,
                             NULL,&tv);
                } else 	i=select(width,(void *)&readfds,(void *)&writefds,
                                     NULL,NULL);
            }
#else
            i=select(width,(void *)&readfds,(void *)&writefds,
                     NULL,NULL);
#endif
            if ( i < 0)
            {
                BIO_printf(bio_err,"bad select %d\n",
                           get_last_socket_error());
                goto shut;
                /* goto end; */
            }
        }

        if (!ssl_pending && FD_ISSET(SSL_get_fd(con),&writefds))
        {
            k=SSL_write(con,&(cbuf[cbuf_off]),
                        (unsigned int)cbuf_len);
            switch (SSL_get_error(con,k))
            {
            case SSL_ERROR_NONE:
                cbuf_off+=k;
                cbuf_len-=k;
                if (k <= 0) goto end;
                /* we have done a  write(con,NULL,0); */
                if (cbuf_len <= 0)
                {
                    read_tty=1;
                    write_ssl=0;
                }
                else /* if (cbuf_len > 0) */
                {
                    read_tty=0;
                    write_ssl=1;
                }
                break;
            case SSL_ERROR_WANT_WRITE:
                BIO_printf(bio_c_out,"write W BLOCK\n");
                write_ssl=1;
                read_tty=0;
                break;
            case SSL_ERROR_WANT_READ:
                BIO_printf(bio_c_out,"write R BLOCK\n");
                write_tty=0;
                read_ssl=1;
                write_ssl=0;
                break;
            case SSL_ERROR_WANT_X509_LOOKUP:
                BIO_printf(bio_c_out,"write X BLOCK\n");
                break;
            case SSL_ERROR_ZERO_RETURN:
                if (cbuf_len != 0)
                {
                    BIO_printf(bio_c_out,"shutdown\n");
                    goto shut;
                }
                else
                {
                    read_tty=1;
                    write_ssl=0;
                    break;
                }

            case SSL_ERROR_SYSCALL:
                if ((k != 0) || (cbuf_len != 0))
                {
                    BIO_printf(bio_err,"write:errno=%d\n",
                               get_last_socket_error());
                    goto shut;
                }
                else
                {
                    read_tty=1;
                    write_ssl=0;
                }
                break;
            case SSL_ERROR_SSL:
                ERR_print_errors(bio_err);
                goto shut;
            }
        }
#if defined(OPENSSL_SYS_WINDOWS) || defined(OPENSSL_SYS_MSDOS) || defined(OPENSSL_SYS_NETWARE)
        /* Assume Windows/DOS can always write */
        else if (!ssl_pending && write_tty)
#else
        else if (!ssl_pending && FD_ISSET(fileno(stdout),&writefds))
#endif
        {
#ifdef CHARSET_EBCDIC
            ascii2ebcdic(&(sbuf[sbuf_off]),&(sbuf[sbuf_off]),sbuf_len);
#endif
            i=write(fileno(stdout),&(sbuf[sbuf_off]),sbuf_len);

            if (i <= 0)
            {
                BIO_printf(bio_c_out,"DONE\n");
                goto shut;
                /* goto end; */
            }

            sbuf_len-=i;;
            sbuf_off+=i;
            if (sbuf_len <= 0)
            {
                read_ssl=1;
                write_tty=0;
            }
        }
        else if (ssl_pending || FD_ISSET(SSL_get_fd(con),&readfds))
        {
#ifdef RENEG
        { static int iiii; if (++iiii == 52) {
                    SSL_renegotiate(con);
                    iiii=0;
                }
            }
#endif
#if 1
            k=SSL_read(con,sbuf,1024 /* BUFSIZZ */ );
#else
            /* Demo for pending and peek :-) */
            k=SSL_read(con,sbuf,16);
            {   char zbuf[10240];
                printf("read=%d pending=%d peek=%d\n",k,SSL_pending(con),SSL_peek(con,zbuf,10240));
            }
#endif

            switch (SSL_get_error(con,k))
            {
            case SSL_ERROR_NONE:
                if (k <= 0)
                    goto end;
                sbuf_off=0;
                sbuf_len=k;

                read_ssl=0;
                write_tty=1;
                break;
            case SSL_ERROR_WANT_WRITE:
                BIO_printf(bio_c_out,"read W BLOCK\n");
                write_ssl=1;
                read_tty=0;
                break;
            case SSL_ERROR_WANT_READ:
                BIO_printf(bio_c_out,"read R BLOCK\n");
                write_tty=0;
                read_ssl=1;
                if ((read_tty == 0) && (write_ssl == 0))
                    write_ssl=1;
                break;
            case SSL_ERROR_WANT_X509_LOOKUP:
                BIO_printf(bio_c_out,"read X BLOCK\n");
                break;
            case SSL_ERROR_SYSCALL:
                BIO_printf(bio_err,"read:errno=%d\n",get_last_socket_error());
                goto shut;
            case SSL_ERROR_ZERO_RETURN:
                BIO_printf(bio_c_out,"closed\n");
                goto shut;
            case SSL_ERROR_SSL:
                ERR_print_errors(bio_err);
                goto shut;
                /* break; */
            }
        }

#if defined(OPENSSL_SYS_WINDOWS) || defined(OPENSSL_SYS_MSDOS)
#if defined(OPENSSL_SYS_WINCE) || defined(OPENSSL_SYS_MSDOS)
        else if (_kbhit())
#else
        else if ((_kbhit()) || (WAIT_OBJECT_0 == WaitForSingleObject(GetStdHandle(STD_INPUT_HANDLE), 0)))
#endif
#elif defined (OPENSSL_SYS_NETWARE)
        else if (_kbhit())
#else
        else if (FD_ISSET(fileno(stdin),&readfds))
#endif
        {
            if (crlf)
            {
                int j, lf_num;

                i=read(fileno(stdin),cbuf,BUFSIZZ/2);
                lf_num = 0;
                /* both loops are skipped when i <= 0 */
                for (j = 0; j < i; j++)
                    if (cbuf[j] == '\n')
                        lf_num++;
                for (j = i-1; j >= 0; j--)
                {
                    cbuf[j+lf_num] = cbuf[j];
                    if (cbuf[j] == '\n')
                    {
                        lf_num--;
                        i++;
                        cbuf[j+lf_num] = '\r';
                    }
                }
                assert(lf_num == 0);
            }
            else
                i=read(fileno(stdin),cbuf,BUFSIZZ);

            if ((!c_ign_eof) && ((i <= 0) || (cbuf[0] == 'Q')))
            {
                BIO_printf(bio_err,"DONE\n");
                goto shut;
            }

            if ((!c_ign_eof) && (cbuf[0] == 'R'))
            {
                BIO_printf(bio_err,"RENEGOTIATING\n");
                SSL_renegotiate(con);
                cbuf_len=0;
            }
            else
            {
                cbuf_len=i;
                cbuf_off=0;
#ifdef CHARSET_EBCDIC
                ebcdic2ascii(cbuf, cbuf, i);
#endif
            }

            write_ssl=1;
            read_tty=0;
        }
    }
shut:
    SSL_shutdown(con);
    SHUTDOWN(SSL_get_fd(con));
    ret=0;
end:
    if(prexit) print_stuff(bio_c_out,con,1);
    if (con != NULL) SSL_free(con);
    if (con2 != NULL) SSL_free(con2);
    if (ctx != NULL) SSL_CTX_free(ctx);
    if (cert)
        X509_free(cert);
    if (key)
        EVP_PKEY_free(key);
    if (pass)
        OPENSSL_free(pass);
    if (cbuf != NULL) {
        OPENSSL_cleanse(cbuf,BUFSIZZ);
        OPENSSL_free(cbuf);
    }
    if (sbuf != NULL) {
        OPENSSL_cleanse(sbuf,BUFSIZZ);
        OPENSSL_free(sbuf);
    }
    if (mbuf != NULL) {
        OPENSSL_cleanse(mbuf,BUFSIZZ);
        OPENSSL_free(mbuf);
    }
    if (bio_c_out != NULL)
    {
        BIO_free(bio_c_out);
        bio_c_out=NULL;
    }
    apps_shutdown();
    OPENSSL_EXIT(ret);
}
Example #24
0
int ssl_server_peek(ssl_server_con * con, void * buffer, size_t buffer_size){
  return SSL_peek(con->ssl, buffer, buffer_size);
}