/* * ---------------------------------------------------------------- * Night Light IRC Proxy - Client I/O SSL Functions * ---------------------------------------------------------------- * Copyright (C) 2006-2007 Jonas Kvinge * 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); } }