/*
* ----------------------------------------------------------------
* Night Light IRC Proxy - Client I/O SSL Functions
* ----------------------------------------------------------------
* Copyright (C) 2006-2007 Jonas Kvinge <jonas@night-light.net>
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Last modified by:
* Jonas Kvinge (24.11.2007)
*
*/
#define CLIENT_IO_SSL_C
#define NEED_SYS_TYPES_H 1 /* Extra types */
#define NEED_SYS_PARAM_H 1 /* Some systems need this */
#define NEED_LIMITS_H 0 /* Kernel limits */
#define NEED_STDARG_H 1 /* va_list, etc */
#define NEED_ERRNO_H 1 /* errno */
#define NEED_CTYPE_H 0 /* isdigit(), etc */
#define NEED_NETINET_IN_H 1 /* in_addr, sockaddr_in, etc */
#define NEED_ARPA_INET_H 1 /* inet_ntoa(), inet_aton(), etc */
#define NEED_STDIO_H 1 /* Standard C UNIX functions */
#define NEED_STDLIB_H 1 /* malloc(), exit(), atoi(), etc */
#define NEED_TIME_H 1 /* time(), etc */
#define NEED_SYSCTL_H 0 /* sysctl(), etc */
#define NEED_SYS_STAT_H 0 /* chmod(), mkdir(), etc */
#define NEED_SYS_UIO_H 0 /* iovec, etc */
#define NEED_FCNTL_H 1 /* open(), creat(), fcntl(), etc */
#define NEED_SYS_IOCTL_H 0 /* ioctl(), etc */
#define NEED_SYS_FILIO_H 0 /* Solaris need this for ioctl(), etc */
#define NEED_UNISTD_H 1 /* Unix standard functions */
#define NEED_STRING_H 1 /* C string functions */
#define NEED_SIGNAL_H 0 /* Signal functions */
#define NEED_SYS_SOCKET_H 1 /* Socket functions */
#define NEED_NETDB_H 1 /* Network database functions */
#define NEED_ARPA_NAMESER_H 0 /* Nameserver definitions */
#define NEED_GETUSERPW_HEADERS 0 /* Functions to retrive system passwords */
#define NEED_ARES 1 /* Functions needed for ares */
#define NEED_SSL 1 /* Needed for SSL support */
#include "includes.h"
#include "irc.h"
#include "client.h"
#include "client_connection.h"
#include "client_parser.h"
#include "client_io_ssl.h"
/* CLIENT_RECV_SSL FUNCTION - JONAS (15.11.2006) */
void client_recv_ssl(struct Client_Struct *ClientS) {
signed long int Result = 0;
unsigned long int OldLen = 0;
unsigned long int NewLen = 0;
char RecvBuffer[RECVBUFFERLEN+1] = "";
char *RecvBufferPT = NULL;
assert(ClientS != NULL);
ClientS->LastRecvTime = NOW;
if (!Client_IsSSLHandshake(ClientS)) {
Result = SSL_accept(ClientS->SSL_H);
if (Result <= 0) {
signed long int sslerrno = SSL_get_error(ClientS->SSL_H, Result);
if ((sslerrno == SSL_ERROR_WANT_READ) || (sslerrno == SSL_ERROR_WANT_WRITE)) { return; }
client_cleanup(ClientS, "Failed SSL Handshake for client %s (%s): [%ld] %s.", ClientS->HostName, ClientS->HostIPS, sslerrno, ERR_error_string(sslerrno, NULL));
return;
}
Client_SetSSLHandshake(ClientS);
ClientS->Cert = SSL_get_peer_certificate(ClientS->SSL_H);
sysprint(BITMASK_MAIN, "SSL Handshake for client %s (%s) completed successfully.", ClientS->HostName, ClientS->HostIPS);
return;
}
do {
memset(&RecvBuffer, 0, sizeof(RecvBuffer));
Result = SSL_read(ClientS->SSL_H, RecvBuffer, RECVBUFFERLEN);
if (Result < 0) {
signed long int sslerrno = SSL_get_error(ClientS->SSL_H, Result);
if ((sslerrno == SSL_ERROR_WANT_READ) || (sslerrno == SSL_ERROR_WANT_WRITE)) { break; }
client_cleanup(ClientS, "Closing client connection %s (%s), read error: [%ld] %s", ClientS->HostName, ClientS->HostIPS, sslerrno, ERR_error_string(sslerrno, NULL));
return;
}
if (Result == 0) {
if (ClientS->RecvBuffer != NULL) { client_parse(ClientS); }
client_cleanup(ClientS, "EOF to client %s (%s).", ClientS->HostName, ClientS->HostIPS);
return;
}
if (ClientS->RecvBuffer == NULL) { OldLen = 0; }
else { OldLen = strlen(ClientS->RecvBuffer); }
NewLen = OldLen + Result + 1;
RecvBufferPT = realloc(ClientS->RecvBuffer, NewLen);
if (RecvBufferPT == NULL) {
client_close(ClientS, "Memory allocation failure: [%d] %s", errno, strerror(errno));
return;
}
ClientS->RecvBuffer = RecvBufferPT;
RecvBufferPT += OldLen;
strcpy(RecvBufferPT, RecvBuffer);
}
while (Result >= RECVBUFFERLEN);
if (Client_IsSentError(ClientS)) { return; }
client_parse(ClientS);
}
/* CLIENT_SEND_SSL FUNCTION - JONAS (15.11.2006) */
void client_send_ssl(struct Client_Struct *ClientS) {
char *SendBufferPT = NULL;
char SendBuffer[SENDBUFFERLEN+1] = "";
unsigned long int SendLen = 0;
unsigned long int SentLen = 0;
signed long int Result = 0;
assert(ClientS != NULL);
if (!Client_IsSSLHandshake(ClientS)) {
Result = SSL_accept(ClientS->SSL_H);
if (Result <= 0) {
signed long int sslerrno = SSL_get_error(ClientS->SSL_H, Result);
if ((sslerrno == SSL_ERROR_WANT_READ) || (sslerrno == SSL_ERROR_WANT_WRITE)) { return; }
client_cleanup(ClientS, "Failed SSL Handshake for client %s (%s): [%ld] %s.", ClientS->HostName, ClientS->HostIPS, sslerrno, ERR_error_string(sslerrno, NULL));
return;
}
Client_SetSSLHandshake(ClientS);
ClientS->Cert = SSL_get_peer_certificate(ClientS->SSL_H);
sysprint(BITMASK_MAIN, "SSL Handshake for client %s (%s) completed successfully.", ClientS->HostName, ClientS->HostIPS);
return;
}
for (SendBufferPT = ClientS->SendBuffer ; *SendBufferPT != '\0' ; SendBufferPT += SentLen) {
SendLen = strlen(SendBufferPT);
if (SendLen > SENDBUFFERLEN) { SendLen = SENDBUFFERLEN; }
memset(&SendBuffer, 0, sizeof(SendBuffer));
strncpy(SendBuffer, SendBufferPT, SendLen);
ERR_clear_error();
Result = SSL_write(ClientS->SSL_H, SendBufferPT, SendLen);
if (Result <= 0) {
signed long int sslerrno = SSL_get_error(ClientS->SSL_H, Result);
if ((sslerrno == SSL_ERROR_WANT_READ) || (sslerrno == SSL_ERROR_WANT_WRITE)) {
unsigned long int Len = 0;
sysprint(BITMASK_MAIN, "Write error to client %s (%s): [%ld] %s", ClientS->HostName, ClientS->HostIPS, sslerrno, ERR_error_string(sslerrno, NULL));
Len = strlen(SendBufferPT) + 1;
memmove(ClientS->SendBuffer, SendBufferPT, Len);
SendBufferPT = realloc(ClientS->SendBuffer, Len);
assert(SendBufferPT != NULL);
ClientS->SendBuffer = SendBufferPT;
return;
}
client_cleanup(ClientS, "Closing client connection %s (%s), write error: [%ld] %s", ClientS->HostName, ClientS->HostIPS, sslerrno, ERR_error_string(sslerrno, NULL));
return;
}
SentLen = Result;
assert(SentLen == SendLen);
}
FREE(ClientS->SendBuffer);
if (Client_IsSentError(ClientS)) { client_cleanup(ClientS, "Successfully closed connection to client %s (%s).", ClientS->HostName, ClientS->HostIPS); }
}
syntax highlighted by Code2HTML, v. 0.9.1