diff --git a/include/ssl.h b/include/ssl.h index 18a47dcd9..2589a6f7a 100644 --- a/include/ssl.h +++ b/include/ssl.h @@ -9,4 +9,5 @@ extern void init_ssl(); extern int ssl_handshake(aClient *); /* Handshake the accpeted con.*/ extern int ssl_client_handshake(aClient *, ConfigItem_link *); /* and the initiated con.*/ extern int ircd_SSL_read(aClient *acptr, void *buf, int sz); -extern int ircd_SSL_write(aClient *acptr, const void *buf, int sz); \ No newline at end of file +extern int ircd_SSL_write(aClient *acptr, const void *buf, int sz); +extern int ircd_SSL_accept(aClient *acpr, int fd); \ No newline at end of file diff --git a/src/s_bsd.c b/src/s_bsd.c index 253f2b836..092ce9fe0 100644 --- a/src/s_bsd.c +++ b/src/s_bsd.c @@ -1590,7 +1590,17 @@ int read_message(time_t delay, fdlist *listp) continue; if (IsLog(cptr)) continue; - + +#ifdef USE_SSL + if (cptr->ssl != NULL && IsSSL(cptr) && + !SSL_is_init_finished((SSL *)cptr->ssl)) + { + if (IsDead(cptr) || (!ircd_SSL_accept(cptr, cptr->fd))) + close_connection(cptr); + continue; + } +#endif + if (DoingAuth(cptr)) { auth++; @@ -1960,6 +1970,7 @@ int read_message(time_t delay, fdlist *listp) continue; if (IsLog(cptr)) continue; + if (DoingAuth(cptr)) { if (auth == 0) diff --git a/src/ssl.c b/src/ssl.c index 56664a050..f38b826e6 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -30,6 +30,12 @@ extern HINSTANCE hInst; extern HWND hwIRCDWnd; #endif + +#define SAFE_SSL_READ 1 +#define SAFE_SSL_WRITE 2 +#define SAFE_SSL_ACCEPT 3 +static int fatal_ssl_error(int ssl_error, int where, aClient *sptr); + /* The SSL structures */ SSL_CTX *ctx_server; SSL_CTX *ctx_client; @@ -340,7 +346,7 @@ int ircd_SSL_read(aClient *acptr, void *buf, int sz) if(errno == EAGAIN) return 0; default: - return -1; + return fatal_ssl_error(ssl_err, SAFE_SSL_READ, acptr); } } return len; @@ -368,9 +374,106 @@ int ircd_SSL_write(aClient *acptr, const void *buf, int sz) if(errno == EAGAIN) return 0; default: - return -1; + return fatal_ssl_error(ssl_err, SAFE_SSL_WRITE, acptr); } } return len; } + +int ircd_SSL_accept(aClient *acptr, int fd) { + + int ssl_err; + + if((ssl_err = SSL_accept((SSL *)acptr->ssl)) <= 0) { + switch(ssl_err = SSL_get_error((SSL *)acptr->ssl, ssl_err)) { + case SSL_ERROR_SYSCALL: + if (errno == EINTR || errno == EWOULDBLOCK + || errno == EAGAIN) + case SSL_ERROR_WANT_READ: + case SSL_ERROR_WANT_WRITE: + /* handshake will be completed later . . */ + return 1; + default: + return fatal_ssl_error(ssl_err, SAFE_SSL_ACCEPT, acptr); + + } + /* NOTREACHED */ + return -1; + } + return 1; +} + +int SSL_smart_shutdown(SSL *ssl) { + char i; + int rc; + rc = 0; + for(i = 0; i < 4; i++) { + if((rc = SSL_shutdown(ssl))) + break; + } + + return rc; +} + +static int fatal_ssl_error(int ssl_error, int where, aClient *sptr) +{ + /* don`t alter errno */ + int errtmp = errno; + char *errstr = strerror(errtmp); + char *ssl_errstr, *ssl_func; + + switch(where) { + case SAFE_SSL_READ: + ssl_func = "SSL_read()"; + break; + case SAFE_SSL_WRITE: + ssl_func = "SSL_write()"; + break; + case SAFE_SSL_ACCEPT: + ssl_func = "SSL_accept()"; + break; + default: + ssl_func = "undefined SSL func"; + } + + switch(ssl_error) { + case SSL_ERROR_NONE: + ssl_errstr = "No error"; + break; + case SSL_ERROR_SSL: + ssl_errstr = "Internal OpenSSL error or protocol error"; + break; + case SSL_ERROR_WANT_READ: + ssl_errstr = "OpenSSL functions requested a read()"; + break; + case SSL_ERROR_WANT_WRITE: + ssl_errstr = "OpenSSL functions requested a write()"; + break; + case SSL_ERROR_WANT_X509_LOOKUP: + ssl_errstr = "OpenSSL requested a X509 lookup which didn`t arrive"; + break; + case SSL_ERROR_SYSCALL: + ssl_errstr = "Underlying syscall error"; + break; + case SSL_ERROR_ZERO_RETURN: + ssl_errstr = "Underlying socket operation returned zero"; + break; + case SSL_ERROR_WANT_CONNECT: + ssl_errstr = "OpenSSL functions wanted a connect()"; + break; + default: + ssl_errstr = "Unknown OpenSSL error (huh?)"; + } + /* if we reply() something here, we might just trigger another + * fatal_ssl_error() call and loop until a stack overflow... + * the client won`t get the ERROR : ... string, but this is + * the only way to do it. + * IRC protocol wasn`t SSL enabled .. --vejeta + */ + errno = errtmp ? errtmp : EIO; /* Stick a generic I/O error */ + sptr->flags |= FLAGS_DEADSOCKET; + return -1; +} + + #endif