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

📄 smtp.c

📁 广泛使用的邮件服务器!同时
💻 C
📖 第 1 页 / 共 2 页
字号:
/* ======================================================================== * Copyright 1988-2008 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * *     http://www.apache.org/licenses/LICENSE-2.0 * *  * ======================================================================== *//* * Program:	Simple Mail Transfer Protocol (SMTP) routines * * Author:	Mark Crispin *		Networks and Distributed Computing *		Computing & Communications *		University of Washington *		Administration Building, AG-44 *		Seattle, WA  98195 *		Internet: MRC@CAC.Washington.EDU * * Date:	27 July 1988 * Last Edited:	28 January 2008 * * This original version of this file is * Copyright 1988 Stanford University * and was developed in the Symbolic Systems Resources Group of the Knowledge * Systems Laboratory at Stanford University in 1987-88, and was funded by the * Biomedical Research Technology Program of the National Institutes of Health * under grant number RR-00785. */#include <ctype.h>#include <stdio.h>#include "c-client.h"/* Constants */#define SMTPSSLPORT (long) 465	/* former assigned SSL TCP contact port */#define SMTPGREET (long) 220	/* SMTP successful greeting */#define SMTPAUTHED (long) 235	/* SMTP successful authentication */#define SMTPOK (long) 250	/* SMTP OK code */#define SMTPAUTHREADY (long) 334/* SMTP ready for authentication */#define SMTPREADY (long) 354	/* SMTP ready for data */#define SMTPSOFTFATAL (long) 421/* SMTP soft fatal code */#define SMTPWANTAUTH (long) 505	/* SMTP authentication needed */#define SMTPWANTAUTH2 (long) 530/* SMTP authentication needed */#define SMTPUNAVAIL (long) 550	/* SMTP mailbox unavailable */#define SMTPHARDERROR (long) 554/* SMTP miscellaneous hard failure *//* Convenient access to protocol-specific data */#define ESMTP stream->protocol.esmtp/* Function prototypes */void *smtp_challenge (void *s,unsigned long *len);long smtp_response (void *s,char *response,unsigned long size);long smtp_auth (SENDSTREAM *stream,NETMBX *mb,char *tmp);long smtp_rcpt (SENDSTREAM *stream,ADDRESS *adr,long *error);long smtp_send (SENDSTREAM *stream,char *command,char *args);long smtp_reply (SENDSTREAM *stream);long smtp_ehlo (SENDSTREAM *stream,char *host,NETMBX *mb);long smtp_fake (SENDSTREAM *stream,char *text);static long smtp_seterror (SENDSTREAM *stream,long code,char *text);long smtp_soutr (void *stream,char *s);/* Mailer parameters */static unsigned long smtp_maxlogintrials = MAXLOGINTRIALS;static long smtp_port = 0;	/* default port override */static long smtp_sslport = 0;#ifndef RFC2821#define RFC2821			/* RFC 2821 compliance */#endif/* SMTP limits, current as of RFC 2821 */#define SMTPMAXLOCALPART 64#define SMTPMAXDOMAIN 255#define SMTPMAXPATH 256/* I have seen local parts of more than 64 octets, in spite of the SMTP * limits.  So, we'll have a more generous limit that's still guaranteed * not to pop the buffer, and let the server worry about it.  As of this * writing, it comes out to 240.  Anyone with a mailbox name larger than * that is in serious need of a life or at least a new ISP!  23 June 1998 */#define MAXLOCALPART ((MAILTMPLEN - (SMTPMAXDOMAIN + SMTPMAXPATH + 32)) / 2)/* Mail Transfer Protocol manipulate driver parameters * Accepts: function code *	    function-dependent value * Returns: function-dependent return value */void *smtp_parameters (long function,void *value){  switch ((int) function) {  case SET_MAXLOGINTRIALS:    smtp_maxlogintrials = (unsigned long) value;    break;  case GET_MAXLOGINTRIALS:    value = (void *) smtp_maxlogintrials;    break;  case SET_SMTPPORT:    smtp_port = (long) value;    break;  case GET_SMTPPORT:    value = (void *) smtp_port;    break;  case SET_SSLSMTPPORT:    smtp_sslport = (long) value;    break;  case GET_SSLSMTPPORT:    value = (void *) smtp_sslport;    break;  default:    value = NIL;		/* error case */    break;  }  return value;}/* Mail Transfer Protocol open connection * Accepts: network driver *	    service host list *	    port number *	    service name *	    SMTP open options * Returns: SEND stream on success, NIL on failure */SENDSTREAM *smtp_open_full (NETDRIVER *dv,char **hostlist,char *service,			    unsigned long port,long options){  SENDSTREAM *stream = NIL;  long reply;  char *s,tmp[MAILTMPLEN];  NETSTREAM *netstream;  NETMBX mb;  if (!(hostlist && *hostlist)) mm_log ("Missing SMTP service host",ERROR);				/* maximum domain name is 64 characters */  else do if (strlen (*hostlist) < SMTPMAXDOMAIN) {    sprintf (tmp,"{%.1000s}",*hostlist);    if (!mail_valid_net_parse_work (tmp,&mb,service ? service : "smtp") ||	mb.anoflag || mb.readonlyflag) {      sprintf (tmp,"Invalid host specifier: %.80s",*hostlist);      mm_log (tmp,ERROR);    }    else {			/* light tryssl flag if requested */      mb.trysslflag = (options & SOP_TRYSSL) ? T : NIL;				/* explicit port overrides all */      if (mb.port) port = mb.port;				/* else /submit overrides port argument */      else if (!compare_cstring (mb.service,"submit")) {	port = SUBMITTCPPORT;	/* override port, use IANA name */	strcpy (mb.service,"submission");      }				/* else port argument overrides SMTP port */      else if (!port) port = smtp_port ? smtp_port : SMTPTCPPORT;      if (netstream =		/* try to open ordinary connection */	  net_open (&mb,dv,port,		    (NETDRIVER *) mail_parameters (NIL,GET_SSLDRIVER,NIL),		    "*smtps",smtp_sslport ? smtp_sslport : SMTPSSLPORT)) {	stream = (SENDSTREAM *) memset (fs_get (sizeof (SENDSTREAM)),0,					sizeof (SENDSTREAM));	stream->netstream = netstream;	stream->host = cpystr ((long) mail_parameters (NIL,GET_TRUSTDNS,NIL) ?			       net_host (netstream) : mb.host);	stream->debug = (mb.dbgflag || (options & OP_DEBUG)) ? T : NIL;	if (options & SOP_SECURE) mb.secflag = T;				/* get name of local host to use */	s = compare_cstring ("localhost",mb.host) ?	  net_localhost (netstream) : "localhost";	do reply = smtp_reply (stream);	while ((reply < 100) || (stream->reply[3] == '-'));	if (reply != SMTPGREET){/* get SMTP greeting */	  sprintf (tmp,"SMTP greeting failure: %.80s",stream->reply);	  mm_log (tmp,ERROR);	  stream = smtp_close (stream);	}				/* try EHLO first, then HELO */	else if (((reply = smtp_ehlo (stream,s,&mb)) != SMTPOK) &&		 ((reply = smtp_send (stream,"HELO",s)) != SMTPOK)) {	  sprintf (tmp,"SMTP hello failure: %.80s",stream->reply);	  mm_log (tmp,ERROR);	  stream = smtp_close (stream);	}	else {	  NETDRIVER *ssld =(NETDRIVER *)mail_parameters(NIL,GET_SSLDRIVER,NIL);	  sslstart_t stls = (sslstart_t) mail_parameters(NIL,GET_SSLSTART,NIL);	  ESMTP.ok = T;		/* ESMTP server, start TLS if present */	  if (!dv && stls && ESMTP.service.starttls &&	      !mb.sslflag && !mb.notlsflag &&	      (smtp_send (stream,"STARTTLS",NIL) == SMTPGREET)) {	    mb.tlsflag = T;	/* TLS OK, get into TLS at this end */	    stream->netstream->dtb = ssld;				/* TLS started, negotiate it */	    if (!(stream->netstream->stream = (*stls)		  (stream->netstream->stream,mb.host,		   (mb.tlssslv23 ? NIL : NET_TLSCLIENT) |		   (mb.novalidate ? NET_NOVALIDATECERT:NIL)))){				/* TLS negotiation failed after STARTTLS */	      sprintf (tmp,"Unable to negotiate TLS with this server: %.80s",		       mb.host);	      mm_log (tmp,ERROR);				/* close without doing QUIT */	      if (stream->netstream) net_close (stream->netstream);	      stream->netstream = NIL;	      stream = smtp_close (stream);	    }				/* TLS OK, re-negotiate EHLO */	    else if ((reply = smtp_ehlo (stream,s,&mb)) != SMTPOK) {	      sprintf (tmp,"SMTP EHLO failure after STARTTLS: %.80s",		       stream->reply);	      mm_log (tmp,ERROR);	      stream = smtp_close (stream);	    }	    else ESMTP.ok = T;	/* TLS OK and EHLO successful */	  }	  else if (mb.tlsflag) {/* user specified /tls but can't do it */	    sprintf (tmp,"TLS unavailable with this server: %.80s",mb.host);	    mm_log (tmp,ERROR);	    stream = smtp_close (stream);	  }				/* remote name for authentication */	  if (stream && ((mb.secflag || mb.user[0]))) {	    if (ESMTP.auth) {	/* use authenticator? */	      if ((long) mail_parameters (NIL,GET_TRUSTDNS,NIL)) {				/* remote name for authentication */		strncpy (mb.host,			 (long) mail_parameters (NIL,GET_SASLUSESPTRNAME,NIL) ?			 net_remotehost (netstream) : net_host (netstream),			 NETMAXHOST-1);		mb.host[NETMAXHOST-1] = '\0';	      }	      if (!smtp_auth (stream,&mb,tmp)) stream = smtp_close (stream);	    }	    else {		/* no available authenticators? */	      sprintf (tmp,"%sSMTP authentication not available: %.80s",		       mb.secflag ? "Secure " : "",mb.host);	      mm_log (tmp,ERROR);	      stream = smtp_close (stream);	    }	  }	}      }    }  } while (!stream && *++hostlist);  if (stream) {			/* set stream options if have a stream */    if (options &(SOP_DSN | SOP_DSN_NOTIFY_FAILURE | SOP_DSN_NOTIFY_DELAY |		  SOP_DSN_NOTIFY_SUCCESS | SOP_DSN_RETURN_FULL)) {      ESMTP.dsn.want = T;      if (options & SOP_DSN_NOTIFY_FAILURE) ESMTP.dsn.notify.failure = T;      if (options & SOP_DSN_NOTIFY_DELAY) ESMTP.dsn.notify.delay = T;      if (options & SOP_DSN_NOTIFY_SUCCESS) ESMTP.dsn.notify.success = T;      if (options & SOP_DSN_RETURN_FULL) ESMTP.dsn.full = T;    }    if (options & SOP_8BITMIME) ESMTP.eightbit.want = T;  }  return stream;}/* SMTP authenticate * Accepts: stream to login *	    parsed network mailbox structure *	    scratch buffer *	    place to return user name * Returns: T on success, NIL on failure */long smtp_auth (SENDSTREAM *stream,NETMBX *mb,char *tmp){  unsigned long trial,auths;  char *lsterr = NIL;  char usr[MAILTMPLEN];  AUTHENTICATOR *at;  long ret = NIL;  for (auths = ESMTP.auth, stream->saslcancel = NIL;       !ret && stream->netstream && auths &&       (at = mail_lookup_auth (find_rightmost_bit (&auths) + 1)); ) {    if (lsterr) {		/* previous authenticator failed? */      sprintf (tmp,"Retrying using %s authentication after %.80s",	       at->name,lsterr);      mm_log (tmp,NIL);      fs_give ((void **) &lsterr);    }    trial = 0;			/* initial trial count */    tmp[0] = '\0';		/* empty buffer */    if (stream->netstream) do {      if (lsterr) {	sprintf (tmp,"Retrying %s authentication after %.80s",at->name,lsterr);	mm_log (tmp,WARN);	fs_give ((void **) &lsterr);      }      stream->saslcancel = NIL;      if (smtp_send (stream,"AUTH",at->name) == SMTPAUTHREADY) {				/* hide client authentication responses */	if (!(at->flags & AU_SECURE)) stream->sensitive = T;	if ((*at->client) (smtp_challenge,smtp_response,"smtp",mb,stream,			   &trial,usr)) {	  if (stream->replycode == SMTPAUTHED) {	    ESMTP.auth = NIL;	/* disable authenticators */	    ret = LONGT;	  }				/* if main program requested cancellation */	  else if (!trial) mm_log ("SMTP Authentication cancelled",ERROR);	}	stream->sensitive = NIL;/* unhide */      }				/* remember response if error and no cancel */      if (!ret && trial) lsterr = cpystr (stream->reply);    } while (!ret && stream->netstream && trial &&	     (trial < smtp_maxlogintrials));  }  if (lsterr) {			/* previous authenticator failed? */    if (!stream->saslcancel) {	/* don't do this if a cancel */      sprintf (tmp,"Can not authenticate to SMTP server: %.80s",lsterr);      mm_log (tmp,ERROR);    }    fs_give ((void **) &lsterr);  }  return ret;			/* authentication failed */}/* Get challenge to authenticator in binary * Accepts: stream *	    pointer to returned size * Returns: challenge or NIL if not challenge */void *smtp_challenge (void *s,unsigned long *len){  char tmp[MAILTMPLEN];  void *ret = NIL;  SENDSTREAM *stream = (SENDSTREAM *) s;  if ((stream->replycode == SMTPAUTHREADY) &&      !(ret = rfc822_base64 ((unsigned char *) stream->reply + 4,			     strlen (stream->reply + 4),len))) {    sprintf (tmp,"SMTP SERVER BUG (invalid challenge): %.80s",stream->reply+4);    mm_log (tmp,ERROR);  }  return ret;}/* Send authenticator response in BASE64 * Accepts: MAIL stream *	    string to send *	    length of string * Returns: T, always */long smtp_response (void *s,char *response,unsigned long size){  SENDSTREAM *stream = (SENDSTREAM *) s;  unsigned long i,j;  char *t,*u;  if (response) {		/* make CRLFless BASE64 string */    if (size) {      for (t = (char *) rfc822_binary ((void *) response,size,&i),u = t,j = 0;	   j < i; j++) if (t[j] > ' ') *u++ = t[j];      *u = '\0';		/* tie off string */      i = smtp_send (stream,t,NIL);      fs_give ((void **) &t);    }    else i = smtp_send (stream,"",NIL);  }  else {			/* abort requested */    i = smtp_send (stream,"*",NIL);    stream->saslcancel = T;	/* mark protocol-requested SASL cancel */  }  return LONGT;}/* Mail Transfer Protocol close connection * Accepts: SEND stream * Returns: NIL always */SENDSTREAM *smtp_close (SENDSTREAM *stream){  if (stream) {			/* send "QUIT" */    if (stream->netstream) {	/* do close actions if have netstream */

⌨️ 快捷键说明

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