📄 ssl_nt.c
字号:
stream = NIL; /* no stream returned */ switch (*reason) { /* analyze reason */ case '*': /* certificate failure */ ++reason; /* skip over certificate failure indication */ /* pass to error callback */ if (sf) (*sf) (host,reason,flags); else { /* no error callback, build error message */ sprintf (tmp,"Certificate failure for %.80s: %.512s",host,reason); mm_log (tmp,ERROR); } case '\0': /* user answered no to certificate callback */ if (flags & NET_TRYSSL) /* return dummy stream to stop tryssl */ stream = (SSLSTREAM *) memset (fs_get (sizeof (SSLSTREAM)),0, sizeof (SSLSTREAM)); break; default: /* non-certificate failure */ if (flags & NET_TRYSSL); /* no error output if tryssl */ /* pass to error callback */ else if (sf) (*sf) (host,reason,flags); else { /* no error callback, build error message */ sprintf (tmp,"TLS/SSL failure for %.80s: %.512s",host,reason); mm_log (tmp,ERROR); } break; } fs_give ((void **) &buf); /* flush temporary buffer */ return stream;}/* Generate error text from SSL error code * Accepts: SSL status * scratch buffer * Returns: text if error status, else NIL */static char *ssl_analyze_status (SECURITY_STATUS err,char *buf){ switch (err) { case SEC_E_OK: /* no error */ case SEC_I_CONTINUE_NEEDED: case SEC_I_INCOMPLETE_CREDENTIALS: case SEC_E_INCOMPLETE_MESSAGE: return NIL; case SEC_E_NO_AUTHENTICATING_AUTHORITY: mm_log ("unexpected SEC_E_NO_AUTHENTICATING_AUTHORITY",NIL); return "*No authority could be contacted for authentication"; case SEC_E_WRONG_PRINCIPAL: mm_log ("unexpected SEC_E_WRONG_PRINCIPAL",NIL); case CERT_E_CN_NO_MATCH: return "*Server name does not match certificate"; case SEC_E_UNTRUSTED_ROOT: mm_log ("unexpected SEC_E_UNTRUSTED_ROOT",NIL); case CERT_E_UNTRUSTEDROOT: return "*Self-signed certificate or untrusted authority"; case SEC_E_CERT_EXPIRED: mm_log ("unexpected SEC_E_CERT_EXPIRED",NIL); case CERT_E_EXPIRED: return "*Certificate has expired"; case CERT_E_REVOKED: return "*Certificate revoked"; case SEC_E_INVALID_TOKEN: return "Invalid token, probably not an SSL server"; case SEC_E_UNSUPPORTED_FUNCTION: return "SSL not supported on this machine - upgrade your system software"; } sprintf (buf,"Unexpected SSPI or certificate error %lx - report this",err); return buf;}/* SSL receive line * Accepts: SSL stream * Returns: text line string or NIL if failure */char *ssl_getline (SSLSTREAM *stream){ unsigned long n,contd; char *ret = ssl_getline_work (stream,&n,&contd); if (ret && contd) { /* got a line needing continuation? */ STRINGLIST *stl = mail_newstringlist (); STRINGLIST *stc = stl; do { /* collect additional lines */ stc->text.data = (unsigned char *) ret; stc->text.size = n; stc = stc->next = mail_newstringlist (); ret = ssl_getline_work (stream,&n,&contd); } while (ret && contd); if (ret) { /* stash final part of line on list */ stc->text.data = (unsigned char *) ret; stc->text.size = n; /* determine how large a buffer we need */ for (n = 0, stc = stl; stc; stc = stc->next) n += stc->text.size; ret = fs_get (n + 1); /* copy parts into buffer */ for (n = 0, stc = stl; stc; n += stc->text.size, stc = stc->next) memcpy (ret + n,stc->text.data,stc->text.size); ret[n] = '\0'; } mail_free_stringlist (&stl);/* either way, done with list */ } return ret;}/* SSL receive line or partial line * Accepts: SSL stream * pointer to return size * pointer to return continuation flag * Returns: text line string, size and continuation flag, or NIL if failure */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){ while (stream->ictr < 1) { /* decrypted buffer empty? */ SECURITY_STATUS status; SecBuffer buf[4]; SecBufferDesc msg; size_t i; size_t n = 0; /* initially no bytes to decrypt */ do { /* yes, make sure have data from TCP */ if (stream->iextractr) { /* have previous unread data? */ memcpy (stream->ibuf + n,stream->iextraptr,stream->iextractr); n += stream->iextractr; /* update number of bytes read */ stream->iextractr = 0; /* no more extra data */ } else { /* read from TCP */ if (!tcp_getdata (stream->tcpstream)) return ssl_abort (stream); /* maximum amount of data to copy */ if (!(i = min (stream->bufsize - n,stream->tcpstream->ictr))) fatal ("incomplete SecBuffer exceeds maximum buffer size"); /* do the copy */ memcpy (stream->ibuf + n,stream->tcpstream->iptr,i); stream->tcpstream->iptr += i; stream->tcpstream->ictr -= i; n += i; /* update number of bytes to decrypt */ } buf[0].cbBuffer = n; /* first SecBuffer gets data */ buf[0].pvBuffer = stream->ibuf; buf[0].BufferType = SECBUFFER_DATA; /* subsequent ones are for spares */ buf[1].BufferType = buf[2].BufferType = buf[3].BufferType = SECBUFFER_EMPTY; msg.ulVersion = SECBUFFER_VERSION; msg.cBuffers = 4; /* number of SecBuffers */ msg.pBuffers = buf; /* first SecBuffer */ } while ((status = ((DECRYPT_MESSAGE_FN) sft->Reserved4) (&stream->context,&msg,0,NIL)) == SEC_E_INCOMPLETE_MESSAGE); switch (status) { case SEC_E_OK: /* won */ case SEC_I_RENEGOTIATE: /* won but lost it after this buffer */ /* hunt for a buffer */ for (i = 0; (i < 4) && (buf[i].BufferType != SECBUFFER_DATA) ; i++); if (i < 4) { /* found a buffer? */ /* yes, set up pointer and counter */ stream->iptr = buf[i].pvBuffer; stream->ictr = buf[i].cbBuffer; /* any unprocessed data? */ while (++i < 4) if (buf[i].BufferType == SECBUFFER_EXTRA) { /* yes, note for next time around */ stream->iextraptr = buf[i].pvBuffer; stream->iextractr = buf[i].cbBuffer; } } break; default: /* anything else means we've lost */ return ssl_abort (stream); } } return LONGT;}/* 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){ SecBuffer buf[4]; SecBufferDesc msg; char *s; size_t n; if (!stream->tcpstream) return NIL; /* until request satisfied */ for (s = stream->ibuf,n = 0; size;) { /* header */ buf[0].BufferType = SECBUFFER_STREAM_HEADER; memset (buf[0].pvBuffer = stream->obuf,0, buf[0].cbBuffer = stream->sizes.cbHeader); /* message (up to maximum size) */ buf[1].BufferType = SECBUFFER_DATA; memcpy (buf[1].pvBuffer = stream->obuf + stream->sizes.cbHeader,string, buf[1].cbBuffer = min (size,SSLBUFLEN)); /* trailer */ buf[2].BufferType = SECBUFFER_STREAM_TRAILER; memset (buf[2].pvBuffer = ((char *) buf[1].pvBuffer) + buf[1].cbBuffer,0, buf[2].cbBuffer = stream->sizes.cbTrailer); /* spare */ buf[3].BufferType = SECBUFFER_EMPTY; msg.ulVersion = SECBUFFER_VERSION; msg.cBuffers = 4; /* number of SecBuffers */ msg.pBuffers = buf; /* first SecBuffer */ string += buf[1].cbBuffer; size -= buf[1].cbBuffer; /* this many bytes processed */ /* encrypt and send message */ if ((((ENCRYPT_MESSAGE_FN) sft->Reserved3) (&stream->context,0,&msg,NIL) != SEC_E_OK) || !tcp_sout (stream->tcpstream,stream->obuf, buf[0].cbBuffer + buf[1].cbBuffer + buf[2].cbBuffer)) return ssl_abort (stream);/* encryption or sending failed */ } return LONGT;}/* 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){ if (stream->tcpstream) { /* close TCP stream */ sft->DeleteSecurityContext (&stream->context); sft->FreeCredentialHandle (&stream->cred); tcp_close (stream->tcpstream); stream->tcpstream = NIL; } if (stream->ibuf) fs_give ((void **) &stream->ibuf); if (stream->obuf) fs_give ((void **) &stream->obuf); 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);}#include "ssl_none.c" /* currently no server support */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -