int vsf_ftpdataio_post_mark_connect(struct vsf_session* p_sess) { int ret = 0; if (!p_sess->data_use_ssl) { return 1; } if (!p_sess->ssl_slave_active) { ret = ssl_accept(p_sess, p_sess->data_fd); } else { int sock_ret; priv_sock_send_cmd(p_sess->ssl_consumer_fd, PRIV_SOCK_DO_SSL_HANDSHAKE); priv_sock_send_fd(p_sess->ssl_consumer_fd, p_sess->data_fd); sock_ret = priv_sock_get_result(p_sess->ssl_consumer_fd); if (sock_ret == PRIV_SOCK_RESULT_OK) { ret = 1; } } if (ret != 1) { if (tunable_require_ssl_reuse) { vsf_cmdio_write_exit(p_sess, FTP_DATATLSBAD, "SSL connection failed: session reuse required", 1); } else { vsf_cmdio_write(p_sess, FTP_DATATLSBAD, "SSL connection failed"); } } return ret; }
/** Perform an SSL handshake. * In some cases, a handshake may block, so we may have to call this * function again. Accordingly, we return state information that * tells us if we need to do that. * \param ssl pointer to an SSL object. * \return resulting state of the object. */ int ssl_handshake(SSL *ssl) { int ret; int state = 0; if ((ret = SSL_do_handshake(ssl)) <= 0) { switch (SSL_get_error(ssl, ret)) { case SSL_ERROR_WANT_READ: /* We must want for the socket to be readable, and then repeat * the call. */ ssl_debugdump("SSL_do_handshake wants read"); state = MYSSL_RB | MYSSL_HANDSHAKE; break; case SSL_ERROR_WANT_WRITE: /* We must want for the socket to be writable, and then repeat * the call. */ ssl_debugdump("SSL_do_handshake wants write"); state = MYSSL_WB | MYSSL_HANDSHAKE; break; default: /* Oops, don't know what's wrong */ ssl_errordump("Error in ssl_handshake"); state = -1; } } else { state = ssl_accept(ssl); } return state; }
/** Given an accepted connection on the listening socket, set up SSL. * \param sock an accepted socket (returned by accept()) * \param state pointer to place to return connection state. * \return an SSL object to associate with the listen end of this connection. */ SSL * ssl_listen(int sock, int *state) { SSL *ssl; ssl = ssl_setup_socket(sock); *state = ssl_accept(ssl); return ssl; }
int vsf_ftpdataio_post_mark_connect(struct vsf_session* p_sess) { if (p_sess->data_use_ssl) { if (!ssl_accept(p_sess, p_sess->data_fd)) { vsf_cmdio_write( p_sess, FTP_DATATLSBAD, "Secure connection negotiation failed."); return 0; } } return 1; }
int Sys_accept_SSL(int sockfd) { if (sockfd != INVALID_SOCKET) { if (g_enableSSL) { int rc = ssl_accept(sockfd); if (rc == -1) { // SSL problem close(sockfd); return -1; } } } return sockfd; }
int Sys_accept(int listenfd, struct sockaddr* cliaddr, int* addrlen) { int sockfd = accept(listenfd, cliaddr, (socklen_t*)addrlen); if (sockfd != INVALID_SOCKET) { if (g_enableSSL) { g_AcceptSock = sockfd; int rc = ssl_accept(sockfd); g_AcceptSock = 0; if (rc == -1) { // SSL problem close(sockfd); return -1; } } } return sockfd; }
int vsf_ftpdataio_post_mark_connect(struct vsf_session* p_sess) { int ret = 0; if (!p_sess->data_use_ssl) { return 1; } if (!p_sess->ssl_slave_active) { ret = ssl_accept(p_sess, p_sess->data_fd); } else { int sock_ret; priv_sock_send_cmd(p_sess->ssl_consumer_fd, PRIV_SOCK_DO_SSL_HANDSHAKE); priv_sock_send_fd(p_sess->ssl_consumer_fd, p_sess->data_fd); sock_ret = priv_sock_get_result(p_sess->ssl_consumer_fd); if (sock_ret == PRIV_SOCK_RESULT_OK) { ret = 1; } } if (ret != 1) { static struct mystr s_err_msg; str_alloc_text(&s_err_msg, "SSL connection failed"); if (tunable_require_ssl_reuse) { str_append_text(&s_err_msg, "; session reuse required"); str_append_text( &s_err_msg, ": see require_ssl_reuse option in vsftpd.conf man page"); } vsf_cmdio_write_str(p_sess, FTP_DATATLSBAD, &s_err_msg); } return ret; }
/* Handle the connection of a client. */ static void connection_handler(t_session *session) { int result; #ifdef ENABLE_SSL t_ssl_accept_data sad; #endif #ifdef ENABLE_DEBUG session->current_task = "thread started"; #endif #ifdef ENABLE_SSL if (session->binding->use_ssl) { sad.context = &(session->ssl_context); sad.client_fd = &(session->client_socket); sad.private_key = session->binding->private_key; sad.certificate = session->binding->certificate; sad.ca_certificate = session->binding->ca_certificate; sad.ca_crl = session->binding->ca_crl; sad.timeout = session->kept_alive == 0 ? session->binding->time_for_1st_request : session->binding->time_for_request; sad.min_ssl_version = session->config->min_ssl_version; sad.dh_size = session->config->dh_size; #ifdef ENABLE_DEBUG sad.thread_id = session->thread_id; session->current_task = "ssl accept"; #endif switch (ssl_accept(&sad)) { case SSL_HANDSHAKE_NO_MATCH: log_system(session, "No cypher overlap during SSL handshake."); break; case SSL_HANDSHAKE_TIMEOUT: handle_timeout(session); break; case SSL_HANDSHAKE_OKE: session->socket_open = true; break; } } else #endif session->socket_open = true; if (session->socket_open) { #ifdef ENABLE_MONITOR if (session->config->monitor_enabled) { monitor_count_connection(session); } #endif do { result = serve_client(session); handle_request_result(session, result); #ifdef ENABLE_TOMAHAWK if (session->parsing_oke) { show_request_to_admins(session->method, session->request_uri, session->http_version, &(session->ip_address), session->http_headers, session->return_code, session->bytes_sent); } #endif #ifdef ENABLE_DEBUG session->current_task = "request done"; #endif if (session->socket_open) { /* Flush the output-buffer */ if (send_buffer(session, NULL, 0) == -1) { session->keep_alive = false; } } #ifdef ENABLE_MONITOR if (session->config->monitor_enabled) { monitor_count_host(session); } #endif reset_session(session); #ifdef ENABLE_DEBUG session->current_task = "session reset"; #endif if ((session->kept_alive > 0) && (session->config->ban_on_flooding > 0)) { if (client_is_flooding(session)) { if (ip_allowed(&(session->ip_address), session->config->banlist_mask) != deny) { ban_ip(&(session->ip_address), session->config->ban_on_flooding, session->config->kick_on_ban); log_system(session, "Client banned because of flooding"); session->keep_alive = false; #ifdef ENABLE_MONITOR if (session->config->monitor_enabled) { monitor_count_ban(session); } #endif } } } } while (session->keep_alive && session->socket_open); #ifdef ENABLE_DEBUG session->current_task = "session done"; #endif destroy_session(session); close_socket(session); } else { close(session->client_socket); } if (session->config->reconnect_delay > 0) { mark_client_for_removal(session, session->config->reconnect_delay); } else { remove_client(session, true); } #ifdef ENABLE_DEBUG /* Show memory usage by thread */ memdbg_print_log(false); #endif /* Client session ends here */ #ifndef ENABLE_THREAD_POOL pthread_exit(NULL); #endif }
/* Handle the connection of a client. */ static void connection_handler(t_session *session) { int result; #ifdef ENABLE_SSL t_ssl_accept_data sad; #endif #ifdef ENABLE_MONITOR int connections; #ifdef ENABLE_DEBUG session->current_task = "thread started"; #endif connections = ++open_connections; if (session->config->monitor_enabled) { if (connections > session->config->monitor_stats.simultaneous_connections) { session->config->monitor_stats.simultaneous_connections = connections; } } #endif #ifdef ENABLE_SSL if (session->binding->use_ssl) { sad.context = &(session->ssl_context); sad.client_fd = &(session->client_socket); sad.private_key = session->binding->private_key; sad.certificate = session->binding->certificate; sad.ca_certificate = session->binding->ca_certificate; sad.ca_crl = session->binding->ca_crl; sad.timeout = session->kept_alive == 0 ? session->binding->time_for_1st_request : session->binding->time_for_request; sad.min_ssl_version = session->config->min_ssl_version; sad.dh_size = session->config->dh_size; #ifdef ENABLE_DEBUG session->current_task = "ssl accept"; #endif switch (ssl_accept(&sad)) { case -2: handle_timeout(session); break; case 0: session->socket_open = true; break; } } else #endif session->socket_open = true; if (session->socket_open) { do { result = serve_client(session); handle_request_result(session, result); #ifdef ENABLE_DEBUG session->current_task = "request done"; #endif if (session->socket_open) { send_buffer(session, NULL, 0); /* Flush the output-buffer */ } #ifdef ENABLE_MONITOR if (session->config->monitor_enabled) { monitor_counter_request(session); if (session->host->monitor_requests && (result > 0)) { monitor_request(session); } } #endif reset_session(session); #ifdef ENABLE_DEBUG session->current_task = "session reset"; #endif if ((session->kept_alive > 0) && (session->config->ban_on_flooding > 0)) { if (client_is_flooding(session)) { if (ip_allowed(&(session->ip_address), session->config->banlist_mask) != deny) { ban_ip(&(session->ip_address), session->config->ban_on_flooding, session->config->kick_on_ban); log_system(session, "Client banned because of flooding"); session->keep_alive = false; #ifdef ENABLE_MONITOR if (session->config->monitor_enabled) { monitor_counter_ban(session); } #endif } } } } while (session->keep_alive && session->socket_open); #ifdef ENABLE_DEBUG session->current_task = "session done"; #endif destroy_session(session); close_socket(session); } else { close(session->client_socket); } #ifdef ENABLE_MONITOR open_connections--; #endif if (session->config->reconnect_delay > 0) { mark_client_for_removal(session, session->config->reconnect_delay); } else { remove_client(session, true); } /* Client session ends here */ #ifndef ENABLE_THREAD_POOL pthread_exit(NULL); #endif }
void ssl_slave(struct vsf_session* p_sess) { struct mystr data_str = INIT_MYSTR; str_reserve(&data_str, VSFTP_DATA_BUFSIZE); /* Before becoming the slave, clear the alarm for the FTP protocol. */ vsf_sysutil_clear_alarm(); /* No need for any further communications with the privileged parent. */ priv_sock_set_parent_context(p_sess); if (tunable_setproctitle_enable) { vsf_sysutil_setproctitle("SSL handler"); } while (1) { char cmd = priv_sock_get_cmd(p_sess->ssl_slave_fd); int ret; if (cmd == PRIV_SOCK_GET_USER_CMD) { ret = ftp_getline(p_sess, &p_sess->ftp_cmd_str, p_sess->p_control_line_buf); priv_sock_send_int(p_sess->ssl_slave_fd, ret); if (ret >= 0) { priv_sock_send_str(p_sess->ssl_slave_fd, &p_sess->ftp_cmd_str); } } else if (cmd == PRIV_SOCK_WRITE_USER_RESP) { priv_sock_get_str(p_sess->ssl_slave_fd, &p_sess->ftp_cmd_str); ret = ftp_write_str(p_sess, &p_sess->ftp_cmd_str, kVSFRWControl); priv_sock_send_int(p_sess->ssl_slave_fd, ret); } else if (cmd == PRIV_SOCK_DO_SSL_HANDSHAKE) { char result = PRIV_SOCK_RESULT_BAD; if (p_sess->data_fd != -1 || p_sess->p_data_ssl != 0) { bug("state not clean"); } p_sess->data_fd = priv_sock_recv_fd(p_sess->ssl_slave_fd); ret = ssl_accept(p_sess, p_sess->data_fd); if (ret == 1) { result = PRIV_SOCK_RESULT_OK; } else { vsf_sysutil_close(p_sess->data_fd); p_sess->data_fd = -1; } priv_sock_send_result(p_sess->ssl_slave_fd, result); } else if (cmd == PRIV_SOCK_DO_SSL_READ) { str_trunc(&data_str, VSFTP_DATA_BUFSIZE); ret = ssl_read_into_str(p_sess, p_sess->p_data_ssl, &data_str); priv_sock_send_int(p_sess->ssl_slave_fd, ret); priv_sock_send_str(p_sess->ssl_slave_fd, &data_str); } else if (cmd == PRIV_SOCK_DO_SSL_WRITE) { priv_sock_get_str(p_sess->ssl_slave_fd, &data_str); ret = ssl_write(p_sess->p_data_ssl, str_getbuf(&data_str), str_getlen(&data_str)); priv_sock_send_int(p_sess->ssl_slave_fd, ret); } else if (cmd == PRIV_SOCK_DO_SSL_CLOSE) { char result = PRIV_SOCK_RESULT_BAD; if (p_sess->data_fd == -1 && p_sess->p_data_ssl == 0) { result = PRIV_SOCK_RESULT_OK; } else { ret = ssl_data_close(p_sess); if (ret == 1) { result = PRIV_SOCK_RESULT_OK; } vsf_sysutil_close(p_sess->data_fd); p_sess->data_fd = -1; } priv_sock_send_result(p_sess->ssl_slave_fd, result); } else { die("bad request in process_ssl_slave_req"); } } }