⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ssl_unix.c

📁 广泛使用的邮件服务器!同时
💻 C
📖 第 1 页 / 共 2 页
字号:
static char *ssl_getline_work (SSLSTREAM *stream,unsigned long *size,			       long *contd){  unsigned long n;  char *s,*ret,c,d;  *contd = NIL;			/* assume no continuation */				/* make sure have data */  if (!ssl_getdata (stream)) return NIL;  for (s = stream->iptr, n = 0, c = '\0'; stream->ictr--; n++, c = d) {    d = *stream->iptr++;	/* slurp another character */    if ((c == '\015') && (d == '\012')) {      ret = (char *) fs_get (n--);      memcpy (ret,s,*size = n);	/* copy into a free storage string */      ret[n] = '\0';		/* tie off string with null */      return ret;    }  }				/* copy partial string from buffer */  memcpy ((ret = (char *) fs_get (n)),s,*size = n);				/* get more data from the net */  if (!ssl_getdata (stream)) fs_give ((void **) &ret);				/* special case of newline broken by buffer */  else if ((c == '\015') && (*stream->iptr == '\012')) {    stream->iptr++;		/* eat the line feed */    stream->ictr--;    ret[*size = --n] = '\0';	/* tie off string with null */  }  else *contd = LONGT;		/* continuation needed */  return ret;}/* SSL receive buffer * Accepts: SSL stream *	    size in bytes *	    buffer to read into * Returns: T if success, NIL otherwise */long ssl_getbuffer (SSLSTREAM *stream,unsigned long size,char *buffer){  unsigned long n;  while (size > 0) {		/* until request satisfied */    if (!ssl_getdata (stream)) return NIL;    n = min (size,stream->ictr);/* number of bytes to transfer */				/* do the copy */    memcpy (buffer,stream->iptr,n);    buffer += n;		/* update pointer */    stream->iptr += n;    size -= n;			/* update # of bytes to do */    stream->ictr -= n;  }  buffer[0] = '\0';		/* tie off string */  return T;}/* SSL receive data * Accepts: TCP/IP stream * Returns: T if success, NIL otherwise */long ssl_getdata (SSLSTREAM *stream){  int i,sock;  fd_set fds,efds;  struct timeval tmo;  tcptimeout_t tmoh = (tcptimeout_t) mail_parameters (NIL,GET_TIMEOUT,NIL);  long ttmo_read = (long) mail_parameters (NIL,GET_READTIMEOUT,NIL);  time_t t = time (0);  blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL);  if (!stream->con || ((sock = SSL_get_fd (stream->con)) < 0)) return NIL;				/* tcp_unix should have prevented this */  if (sock >= FD_SETSIZE) fatal ("unselectable socket in ssl_getdata()");  (*bn) (BLOCK_TCPREAD,NIL);  while (stream->ictr < 1) {	/* if nothing in the buffer */    time_t tl = time (0);	/* start of request */    time_t now = tl;    int ti = ttmo_read ? now + ttmo_read : 0;    if (SSL_pending (stream->con)) i = 1;    else {      if (tcpdebug) mm_log ("Reading SSL data",TCPDEBUG);      tmo.tv_usec = 0;      FD_ZERO (&fds);		/* initialize selection vector */      FD_ZERO (&efds);		/* handle errors too */      FD_SET (sock,&fds);	/* set bit in selection vector */      FD_SET (sock,&efds);	/* set bit in error selection vector */      errno = NIL;		/* block and read */      do {			/* block under timeout */	tmo.tv_sec = ti ? ti - now : 0;	i = select (sock+1,&fds,0,&efds,ti ? &tmo : 0);	now = time (0);		/* fake timeout if interrupt & time expired */	if ((i < 0) && (errno == EINTR) && ti && (ti <= now)) i = 0;      } while ((i < 0) && (errno == EINTR));    }    if (i) {			/* non-timeout result from select? */      errno = 0;		/* just in case */      if (i > 0)		/* read what we can */	while (((i = SSL_read (stream->con,stream->ibuf,SSLBUFLEN)) < 0) &&	       ((errno == EINTR) ||		(SSL_get_error (stream->con,i) == SSL_ERROR_WANT_READ)));      if (i <= 0) {		/* error seen? */	if (tcpdebug) {	  char *s,tmp[MAILTMPLEN];	  if (i) sprintf (s = tmp,"SSL data read I/O error %d SSL error %d",			  errno,SSL_get_error (stream->con,i));	  else s = "SSL data read end of file";	  mm_log (s,TCPDEBUG);	}	return ssl_abort (stream);      }      stream->iptr = stream->ibuf;/* point at TCP buffer */      stream->ictr = i;		/* set new byte count */      if (tcpdebug) mm_log ("Successfully read SSL data",TCPDEBUG);    }				/* timeout, punt unless told not to */    else if (!tmoh || !(*tmoh) (now - t,now - tl)) {      if (tcpdebug) mm_log ("SSL data read timeout",TCPDEBUG);      return ssl_abort (stream);    }  }  (*bn) (BLOCK_NONE,NIL);  return T;}/* SSL send string as record * Accepts: SSL stream *	    string pointer * Returns: T if success else NIL */long ssl_soutr (SSLSTREAM *stream,char *string){  return ssl_sout (stream,string,(unsigned long) strlen (string));}/* SSL send string * Accepts: SSL stream *	    string pointer *	    byte count * Returns: T if success else NIL */long ssl_sout (SSLSTREAM *stream,char *string,unsigned long size){  long i;  blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL);  if (!stream->con) return NIL;  (*bn) (BLOCK_TCPWRITE,NIL);  if (tcpdebug) mm_log ("Writing to SSL",TCPDEBUG);				/* until request satisfied */  for (i = 0; size > 0; string += i,size -= i)				/* write as much as we can */    if ((i = SSL_write (stream->con,string,(int) min (SSLBUFLEN,size))) < 0) {      if (tcpdebug) {	char tmp[MAILTMPLEN];	sprintf (tmp,"SSL data write I/O error %d SSL error %d",		 errno,SSL_get_error (stream->con,i));	mm_log (tmp,TCPDEBUG);      }      return ssl_abort (stream);/* write failed */    }  if (tcpdebug) mm_log ("successfully wrote to TCP",TCPDEBUG);  (*bn) (BLOCK_NONE,NIL);  return LONGT;			/* all done */}/* SSL close * Accepts: SSL stream */void ssl_close (SSLSTREAM *stream){  ssl_abort (stream);		/* nuke the stream */  fs_give ((void **) &stream);	/* flush the stream */}/* SSL abort stream * Accepts: SSL stream * Returns: NIL always */static long ssl_abort (SSLSTREAM *stream){  blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL);  if (stream->con) {		/* close SSL connection */    SSL_shutdown (stream->con);    SSL_free (stream->con);    stream->con = NIL;  }  if (stream->context) {	/* clean up context */    SSL_CTX_free (stream->context);    stream->context = NIL;  }  if (stream->tcpstream) {	/* close TCP stream */    tcp_close (stream->tcpstream);    stream->tcpstream = NIL;  }  (*bn) (BLOCK_NONE,NIL);  return NIL;}/* SSL get host name * Accepts: SSL stream * Returns: host name for this stream */char *ssl_host (SSLSTREAM *stream){  return tcp_host (stream->tcpstream);}/* SSL get remote host name * Accepts: SSL stream * Returns: host name for this stream */char *ssl_remotehost (SSLSTREAM *stream){  return tcp_remotehost (stream->tcpstream);}/* SSL return port for this stream * Accepts: SSL stream * Returns: port number for this stream */unsigned long ssl_port (SSLSTREAM *stream){  return tcp_port (stream->tcpstream);}/* SSL get local host name * Accepts: SSL stream * Returns: local host name */char *ssl_localhost (SSLSTREAM *stream){  return tcp_localhost (stream->tcpstream);}/* Start TLS * Accepts: /etc/services service name * Returns: cpystr'd error string if TLS failed, else NIL for success */char *ssl_start_tls (char *server){  char tmp[MAILTMPLEN];  struct stat sbuf;  if (sslstdio) return cpystr ("Already in an SSL session");  if (start_tls) return cpystr ("TLS already started");  if (server) {			/* build specific certificate/key file name */    sprintf (tmp,"%s/%s-%s.pem",SSL_CERT_DIRECTORY,server,tcp_serveraddr ());    if (stat (tmp,&sbuf)) {	/* use non-specific name if no specific file */      sprintf (tmp,"%s/%s.pem",SSL_CERT_DIRECTORY,server);      if (stat (tmp,&sbuf)) return cpystr ("Server certificate not installed");    }    start_tls = server;		/* switch to STARTTLS mode */  }  return NIL;}/* Init server for SSL * Accepts: server name */void ssl_server_init (char *server){  char cert[MAILTMPLEN],key[MAILTMPLEN];  unsigned long i;  struct stat sbuf;  SSLSTREAM *stream = (SSLSTREAM *) memset (fs_get (sizeof (SSLSTREAM)),0,					    sizeof (SSLSTREAM));  ssl_onceonlyinit ();		/* make sure algorithms added */  ERR_load_crypto_strings ();  SSL_load_error_strings ();				/* build specific certificate/key file names */  sprintf (cert,"%s/%s-%s.pem",SSL_CERT_DIRECTORY,server,tcp_serveraddr ());  sprintf (key,"%s/%s-%s.pem",SSL_KEY_DIRECTORY,server,tcp_serveraddr ());				/* use non-specific name if no specific cert */  if (stat (cert,&sbuf)) sprintf (cert,"%s/%s.pem",SSL_CERT_DIRECTORY,server);  if (stat (key,&sbuf)) {	/* use non-specific name if no specific key */    sprintf (key,"%s/%s.pem",SSL_KEY_DIRECTORY,server);				/* use cert file as fallback for key */    if (stat (key,&sbuf)) strcpy (key,cert);  }				/* create context */  if (!(stream->context = SSL_CTX_new (start_tls ?				       TLSv1_server_method () :				       SSLv23_server_method ())))    syslog (LOG_ALERT,"Unable to create SSL context, host=%.80s",	    tcp_clienthost ());  else {			/* set context options */    SSL_CTX_set_options (stream->context,SSL_OP_ALL);				/* set cipher list */    if (!SSL_CTX_set_cipher_list (stream->context,SSLCIPHERLIST))      syslog (LOG_ALERT,"Unable to set cipher list %.80s, host=%.80s",	      SSLCIPHERLIST,tcp_clienthost ());				/* load certificate */    else if (!SSL_CTX_use_certificate_chain_file (stream->context,cert))      syslog (LOG_ALERT,"Unable to load certificate from %.80s, host=%.80s",	      cert,tcp_clienthost ());				/* load key */    else if (!(SSL_CTX_use_RSAPrivateKey_file (stream->context,key,					       SSL_FILETYPE_PEM)))      syslog (LOG_ALERT,"Unable to load private key from %.80s, host=%.80s",	      key,tcp_clienthost ());    else {			/* generate key if needed */      if (SSL_CTX_need_tmp_RSA (stream->context))	SSL_CTX_set_tmp_rsa_callback (stream->context,ssl_genkey);				/* create new SSL connection */      if (!(stream->con = SSL_new (stream->context)))	syslog (LOG_ALERT,"Unable to create SSL connection, host=%.80s",		tcp_clienthost ());      else {			/* set file descriptor */	SSL_set_fd (stream->con,0);				/* all OK if accepted */	if (SSL_accept (stream->con) < 0)	  syslog (LOG_INFO,"Unable to accept SSL connection, host=%.80s",		  tcp_clienthost ());	else {			/* server set up */	  sslstdio = (SSLSTDIOSTREAM *)	    memset (fs_get (sizeof(SSLSTDIOSTREAM)),0,sizeof (SSLSTDIOSTREAM));	  sslstdio->sslstream = stream;				/* available space in output buffer */	  sslstdio->octr = SSLBUFLEN;				/* current output buffer pointer */	  sslstdio->optr = sslstdio->obuf;				/* allow plaintext if disable value was 2 */	  if ((long) mail_parameters (NIL,GET_DISABLEPLAINTEXT,NIL) > 1)	    mail_parameters (NIL,SET_DISABLEPLAINTEXT,NIL);				/* unhide PLAIN SASL authenticator */	  mail_parameters (NIL,UNHIDE_AUTHENTICATOR,"PLAIN");	  mail_parameters (NIL,UNHIDE_AUTHENTICATOR,"LOGIN");	  return;	}      }    }    }  while (i = ERR_get_error ())	/* SSL failure */    syslog (LOG_ERR,"SSL error status: %.80s",ERR_error_string (i,NIL));  ssl_close (stream);		/* punt stream */  exit (1);			/* punt this program too */}/* Generate one-time key for server * Accepts: SSL connection *	    export flag *	    keylength * Returns: generated key, always */static RSA *ssl_genkey (SSL *con,int export,int keylength){  unsigned long i;  static RSA *key = NIL;  if (!key) {			/* if don't have a key already */				/* generate key */    if (!(key = RSA_generate_key (export ? keylength : 1024,RSA_F4,NIL,NIL))) {      syslog (LOG_ALERT,"Unable to generate temp key, host=%.80s",	      tcp_clienthost ());      while (i = ERR_get_error ())	syslog (LOG_ALERT,"SSL error status: %s",ERR_error_string (i,NIL));      exit (1);    }  }  return key;}/* Wait for stdin input * Accepts: timeout in seconds * Returns: T if have input on stdin, else NIL */long ssl_server_input_wait (long seconds){  int i,sock;  fd_set fds,efd;  struct timeval tmo;  SSLSTREAM *stream;  if (!sslstdio) return server_input_wait (seconds);				/* input available in buffer */  if (((stream = sslstdio->sslstream)->ictr > 0) ||      !stream->con || ((sock = SSL_get_fd (stream->con)) < 0)) return LONGT;				/* sock ought to be 0 always */  if (sock >= FD_SETSIZE) fatal ("unselectable socket in ssl_getdata()");				/* input available from SSL */  if (SSL_pending (stream->con) &&      ((i = SSL_read (stream->con,stream->ibuf,SSLBUFLEN)) > 0)) {    stream->iptr = stream->ibuf;/* point at TCP buffer */    stream->ictr = i;		/* set new byte count */    return LONGT;  }  FD_ZERO (&fds);		/* initialize selection vector */  FD_ZERO (&efd);		/* initialize selection vector */  FD_SET (sock,&fds);		/* set bit in selection vector */  FD_SET (sock,&efd);		/* set bit in selection vector */  tmo.tv_sec = seconds; tmo.tv_usec = 0;				/* see if input available from the socket */  return select (sock+1,&fds,0,&efd,&tmo) ? LONGT : NIL;}#include "sslstdio.c"

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -