Filter:   InfoImg
download ssl.c
Language: C
License: GPL
Copyright: (C) 2002 by the past and present ircd coders, and others.
LOC: 210
Project Info
NeoStats
Server: SourceForge
Type: cvs
...stats\neostats\NeoIRCd\src\
   .cvsignore
   .depend
   adns.c
   balloc.c
   channel.c
   channel_mode.c
   class.c
   client.c
   cloak.c
   crypt.c
   descrip.mms
   dynlink.c
   event.c
   fdlist.c
   fileio.c
   getopt.c
   hash.c
   hook.c
   hostmask.c
   irc_string.c
   ircd.c
   ircd_parser.y
   ircd_signal.c
   ircdauth.c
   kdparse.c
   linebuf.c
   list.c
   listener.c
   m_error.c
   Makefile.in
   match.c
   md5.c
   memory.c
   messages.tab
   modules.c
   motd.c
   numeric.c
   packet.c
   parse.c
   restart.c
   resv.c
   rsa.c
   s_auth.c
   s_bsd.c
   s_bsd_devpoll.c
   s_bsd_kqueue.c
   s_bsd_poll.c
   s_bsd_select.c
   s_bsd_sigio.c
   s_conf.c
   s_debug.c
   s_gline.c
   s_log.c
   s_misc.c
   s_serv.c
   s_stats.c
   s_user.c
   scache.c
   send.c
   snprintf.c
   sprintf_irc.c
   ssl.c
   tools.c
   version.c.SH
   whowas.c

/*
 *  NeoIRCd: NeoStats Group. Based on Hybird7
 *  ssl.c: Listens on a port.
 *
 *  Copyright (C) 2002 by the past and present ircd coders, and others.
 *  Originally copied from Ultimate3, modified to work with NeoIRCd. 
 *
 *  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., 59 Temple Place, Suite 330, Boston, MA  02111-1307
 *  USA
 *
 *  $Id: ssl.c,v 1.4 2003/01/29 09:28:50 fishwaldo Exp $
 */

#include "stdinc.h"
#include "config.h"
#include "ircd_defs.h"
#include "s_log.h"
#include "common.h"
#include "ssl.h"
#include "client.h"
#include "send.h"
#include "s_conf.h"

#ifdef USE_SSL
#define IRCDSSL_CPATH "/home/fish/ircd/etc/ircd.crt"
#define IRCDSSL_KPATH "/home/fish/ircd/etc/ircd.key"


#define SAFE_SSL_READ	1
#define SAFE_SSL_WRITE	2
#define SAFE_SSL_ACCEPT	3

extern int errno;

SSL_CTX *ircdssl_ctx;
int ssl_capable = 0;

int
initssl (void)
{
  SSL_load_error_strings ();
  SSLeay_add_ssl_algorithms ();
  ircdssl_ctx = SSL_CTX_new (SSLv23_server_method ());
  if (!ircdssl_ctx)
    {
      ilog(L_ERROR, "initssl(): Failed to Create SSL context");
      return 0;
    }
  if (SSL_CTX_use_certificate_file (ircdssl_ctx,
				    ServerInfo.public_cert_file, SSL_FILETYPE_PEM) <= 0)
    {
      ilog(L_ERROR, "initssl(): Failed to initilize SSL Certificate File");
      SSL_CTX_free (ircdssl_ctx);
      return 0;
    }
  if (SSL_CTX_use_PrivateKey_file (ircdssl_ctx,
				   ServerInfo.private_cert_file, SSL_FILETYPE_PEM) <= 0)
    {
      ilog(L_ERROR, "initssl(): Failed to use Private Certificate");
      SSL_CTX_free (ircdssl_ctx);
      return 0;
    }
  if (!SSL_CTX_check_private_key (ircdssl_ctx))
    {
      ilog(L_ERROR, "Server certificate does not match Server key");
      SSL_CTX_free (ircdssl_ctx);
      return 0;
    }
  ilog(L_INFO, "SSL Initilized Successfully");
  return 1;
}

static int fatal_ssl_error (int, int, struct Client *);

int
safe_SSL_read (struct Client * client_p, void *buf, int sz)
{
  int len, ssl_err;

  bzero(buf, sz);
  len = SSL_read(client_p->localClient->ssl, buf, sz);

  if (len <= 0)
    {
      switch (ssl_err = SSL_get_error (client_p->localClient->ssl, len))
	{
	case SSL_ERROR_SYSCALL:
	  if (errno == EWOULDBLOCK || errno == EAGAIN || errno == EINTR)
	    {
		case SSL_ERROR_WANT_READ:
		      	errno = EWOULDBLOCK;
	      		return -1;
	    }
	case SSL_ERROR_SSL:
#ifdef DEBUG
	      fatal_ssl_error(ssl_err, SAFE_SSL_READ, client_p);
#endif	      
	  if (errno == EAGAIN)
	    return -1;
	default:
	  return fatal_ssl_error (ssl_err, SAFE_SSL_READ, client_p);
	}
    }
  return len;
}

int
safe_SSL_write (struct Client *client_p, const void *buf, int sz)
{
  int len, ssl_err;

  len = SSL_write (client_p->localClient->ssl, buf, sz);
  if (len <= 0)
    {
      switch (ssl_err = SSL_get_error (client_p->localClient->ssl, len))
	{
	case SSL_ERROR_SYSCALL:
	  if (errno == EWOULDBLOCK || errno == EAGAIN || errno == EINTR)
	    {
	case SSL_ERROR_WANT_WRITE:
	      errno = EWOULDBLOCK;
	      return 0;
	    }
	case SSL_ERROR_SSL:
	  if (errno == EAGAIN)
	    return 0;
	default:
	  return fatal_ssl_error (ssl_err, SAFE_SSL_WRITE, client_p);
	}
    }
  return len;
}

int
safe_SSL_accept (struct Client *client_p, int fd)
{

  int ssl_err;

  if ((ssl_err = SSL_accept (client_p->localClient->ssl)) <= 0)
    {
      switch (ssl_err = SSL_get_error (client_p->localClient->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 . . */
#ifdef DEBUG
	    fatal_ssl_error(ssl_err, SAFE_SSL_ACCEPT, client_p);
#endif
	    return 0;
	default:
	  return fatal_ssl_error (ssl_err, SAFE_SSL_ACCEPT, client_p);

	}
      /* NOTREACHED */
      return -1;
    }
  return 1;
}

int
SSL_smart_shutdown (struct Client *client_p)
{
  char i;
  int rc;

  rc = 0;
  SSL_set_shutdown(client_p->localClient->ssl, SSL_RECEIVED_SHUTDOWN);
  for (i = 0; i < 4; i++)
    {
      if ((rc = SSL_shutdown (client_p->localClient->ssl)))
	break;
    }
  SSL_free(client_p->localClient->ssl);
  client_p->localClient->ssl = NULL;                
  return rc;
}

static int
fatal_ssl_error (int ssl_error, int where, struct Client *client_p)
{
  /* 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 [this is a bug] reporto to fish@dynam.ac";
    }

  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?)";
    }

  sendto_realops_flags(FLAGS_DEBUG,L_ALL, "%s to %s!%s@%s aborted with %serror (%s). [%s]",
		      ssl_func, client_p->name ? client_p->name : "<unknown>",
		      client_p->username, 
		      client_p->host,
		      (errno > 0) ? " " : " no ", errstr, ssl_errstr);
  ilog (L_ERROR, "SSL error in %s: %s [%s]", ssl_func, errstr, ssl_errstr);

  /* 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 */
#if 0
  sptr->sockerr = IRCERR_SSL;
  sptr->flags |= FLAGS_DEADSOCKET;
#endif 
  return -1;
}
#endif