📄 auth_snt.c
字号:
/* * Program: SSL authentication/encryption module for Windows 9x and NT * * 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: 22 September 1998 * Last Edited: 4 October 2000 * * Copyright 2000 by the University of Washington * * This software is provided under specific, written license from the * University of Washington and may only be used, copied, modified, and * distributed under the terms of such license. This software is made * available "as is", and * THE UNIVERSITY OF WASHINGTON DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, * WITH REGARD TO THIS SOFTWARE, INCLUDING WITHOUT LIMITATION ALL IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, AND IN * NO EVENT SHALL THE UNIVERSITY OF WASHINGTON BE LIABLE FOR ANY SPECIAL, * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, TORT * (INCLUDING NEGLIGENCE) OR STRICT LIABILITY, ARISING OUT OF OR IN CONNECTION * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Export Regulations. Software, including technical data, is subject to U.S. * export control laws, including the U.S. Export Administration Act and its * associated regulations, and may be subject to export or import regulations * in other countries. Licensee agrees to comply strictly with all such * regulations and acknowledges that it has the responsibility to obtain * licenses to export, re-export, or import Software. Software may not be * downloaded, or otherwise exported or re-exported (i) into, or to a * national or resident of, Cuba, Iraq, Iran, North Korea, Libya, Sudan, * Syria or any country to which the U.S. has embargoed goods; or (ii) to * anyone on the U.S. Treasury Department's list of Specially Designated * Nations or the U.S. Commerce Department's Table of Denial Orders. */#define SECURITY_WIN32#include <sspi.h>#if(_WIN32_WINNT < 0x0400)#define UNISP_NAME "Microsoft Unified Security Protocol Provider"#else#include <wincrypt.h>ALGIDDEF#include <schnlsp.h>#endif#include <issperr.h> /* in case a binary runs on Windows 2000 */#ifndef ISC_REQ_MANUAL_CRED_VALIDATION#define ISC_REQ_MANUAL_CRED_VALIDATION 0x00080000#endif#ifndef SEC_E_UNTRUSTED_ROOT#define SEC_E_UNTRUSTED_ROOT ((HRESULT) 0x80090325L)#endif#ifndef SEC_E_CERT_EXPIRED#define SEC_E_CERT_EXPIRED ((HRESULT) 0x80090328L)#endif#define auth_ssl auth_snt#define SSLBUFLEN 8192/* SSL I/O stream */typedef struct ssl_stream { TCPSTREAM *tcpstream; /* TCP stream */ CredHandle cred; /* SSL credentials */ CtxtHandle context; /* SSL context */ /* stream encryption sizes */ SecPkgContext_StreamSizes sizes; int ictr; /* input counter */ char *iptr; /* input pointer */ int iextractr; /* extra input counter */ char *iextraptr; /* extra input pointer */ char *ibuf; /* input buffer */ char *obuf; /* output buffer */} SSLSTREAM;/* SSL stdio stream */typedef struct ssl_stdiostream { SSLSTREAM *sslstream; /* SSL stream */ int octr; /* output counter */ char *optr; /* output pointer */ char obuf[SSLBUFLEN]; /* output buffer */} SSLSTDIOSTREAM;/* SSL driver */struct ssl_driver { /* must parallel NETDRIVER in mail.h */ SSLSTREAM *(*open) (char *host,char *service,unsigned long port); SSLSTREAM *(*aopen) (NETMBX *mb,char *service,char *usrbuf); char *(*getline) (SSLSTREAM *stream); long (*getbuffer) (SSLSTREAM *stream,unsigned long size,char *buffer); long (*soutr) (SSLSTREAM *stream,char *string); long (*sout) (SSLSTREAM *stream,char *string,unsigned long size); void (*close) (SSLSTREAM *stream); char *(*host) (SSLSTREAM *stream); char *(*remotehost) (SSLSTREAM *stream); unsigned long (*port) (SSLSTREAM *stream); char *(*localhost) (SSLSTREAM *stream);};/* Function prototypes */void ssl_onceonlyinit (void);SSLSTREAM *ssl_open (char *host,char *service,unsigned long port);SSLSTREAM *ssl_aopen (NETMBX *mb,char *service,char *usrbuf);char *ssl_getline (SSLSTREAM *stream);long ssl_getbuffer (SSLSTREAM *stream,unsigned long size,char *buffer);long ssl_getdata (SSLSTREAM *stream);long ssl_soutr (SSLSTREAM *stream,char *string);long ssl_sout (SSLSTREAM *stream,char *string,unsigned long size);void ssl_close (SSLSTREAM *stream);long ssl_abort (SSLSTREAM *stream);char *ssl_host (SSLSTREAM *stream);char *ssl_remotehost (SSLSTREAM *stream);unsigned long ssl_port (SSLSTREAM *stream);char *ssl_localhost (SSLSTREAM *stream);long auth_plain_valid (void);long auth_plain_client (authchallenge_t challenger,authrespond_t responder, NETMBX *mb,void *stream,unsigned long *trial, char *user);char *auth_plain_server (authresponse_t responder,int argc,char *argv[]);void Server_init (char *server,char *service,char *altservice,char *sasl, void *clkint,void *kodint,void *hupint,void *trmint);long Server_input_wait (long seconds);char *ssl_start_tls (char *server);SSLSTDIOSTREAM *ssl_server_init (char *server);int ssl_getchar (void);char *ssl_gets (char *s,int n);int ssl_putchar (int c);int ssl_puts (char *s);int ssl_flush (void);/* Secure Sockets Layer network driver dispatch */static struct ssl_driver ssldriver = { ssl_open, /* open connection */ ssl_aopen, /* open preauthenticated connection */ ssl_getline, /* get a line */ ssl_getbuffer, /* get a buffer */ ssl_soutr, /* output pushed data */ ssl_sout, /* output string */ ssl_close, /* close connection */ ssl_host, /* return host name */ ssl_remotehost, /* return remote host name */ ssl_port, /* return port number */ ssl_localhost /* return local host name */}; /* security function table */static SecurityFunctionTable *sft = NIL;static unsigned long ssltsz = 0;/* SSL maximum token length */ /* non-NIL if doing SSL primary I/O */static SSLSTDIOSTREAM *sslstdio = NIL;static char *start_tls = NIL; /* non-NIL if start TLS requested *//* Secure sockets layer authenticator */AUTHENTICATOR auth_ssl = { AU_AUTHUSER, /* allow authuser */ "PLAIN", /* authenticator name */ auth_plain_valid, /* check if valid */ auth_plain_client, /* client method */ auth_plain_server, /* server method */ NIL /* next authenticator */};/* One-time SSL initialization */static int sslonceonly = 0;void ssl_onceonlyinit (void){ if (!sslonceonly++) { /* only need to call it once */ HINSTANCE lib; FARPROC pi; ULONG np; SecPkgInfo *pp; int i; /* get security library */ if (((lib = LoadLibrary ("schannel.dll")) || (lib = LoadLibrary ("security.dll"))) && (pi = GetProcAddress (lib,SECURITY_ENTRYPOINT)) && (sft = (SecurityFunctionTable *) pi ()) && !(sft->EnumerateSecurityPackages (&np,&pp))) { /* look for an SSL package */ for (i = 0; (i < (int) np); i++) if (!strcmp (pp[i].Name,UNISP_NAME)) { /* note maximum token size and name */ ssltsz = pp[i].cbMaxToken; /* link in the SSL driver */ mail_parameters (NIL,SET_ALTDRIVER,(void *) &ssldriver); mail_parameters (NIL,SET_ALTDRIVERNAME,(void *) "ssl"); mail_parameters (NIL,SET_ALTOPTIONNAME,(void *) "novalidate-cert"); /* set name and ports for services */ mail_parameters (NIL,SET_ALTIMAPNAME,(void *) "*imaps"); mail_parameters (NIL,SET_ALTIMAPPORT,(void *) 993); mail_parameters (NIL,SET_ALTPOPNAME,(void *) "*pop3s"); mail_parameters (NIL,SET_ALTPOPPORT,(void *) 995); mail_parameters (NIL,SET_ALTNNTPNAME,(void *) "*nntps"); mail_parameters (NIL,SET_ALTNNTPPORT,(void *) 563); mail_parameters (NIL,SET_ALTSMTPNAME,(void *) "*smtps"); mail_parameters (NIL,SET_ALTSMTPPORT,(void *) 465); return; /* all done */ } } }}/* SSL open * Accepts: host name * contact service name * contact port number * Returns: SSL stream if success else NIL */SSLSTREAM *ssl_open (char *host,char *service,unsigned long port){ SECURITY_STATUS e; ULONG a; TimeStamp t; SecBuffer ibuf[2],obuf[1]; SecBufferDesc ibufs,obufs; SSLSTREAM *stream = NIL; ULONG req = ISC_REQ_MUTUAL_AUTH | ISC_REQ_REPLAY_DETECT | ISC_REQ_SEQUENCE_DETECT | ISC_REQ_CONFIDENTIALITY | ISC_REQ_USE_SESSION_KEY | ISC_REQ_ALLOCATE_MEMORY | ISC_REQ_STREAM | ISC_REQ_EXTENDED_ERROR + ((port & NET_ALTOPT) ? ISC_REQ_MANUAL_CRED_VALIDATION : 0); int done = 0; TCPSTREAM *ts = tcp_open (host,service,port); int failed = T; if (ts) { /* got a TCPSTREAM? */ char *buf = (char *) fs_get (ssltsz); unsigned long size = 0; /* instantiate SSLSTREAM */ (stream = (SSLSTREAM *) memset (fs_get (sizeof (SSLSTREAM)),0, sizeof (SSLSTREAM)))->tcpstream = ts; /* acquire credentials */ if (sft->AcquireCredentialsHandle (NIL,UNISP_NAME,SECPKG_CRED_OUTBOUND,NIL,NIL,NIL,NIL,&stream->cred,&t) == SEC_E_OK) { while (!done) { /* negotiate negotiate security context */ /* initialize buffers */ ibuf[0].cbBuffer = size; ibuf[0].pvBuffer = buf; ibuf[1].cbBuffer = 0; ibuf[1].pvBuffer = NIL; obuf[0].cbBuffer = 0; obuf[0].pvBuffer = NIL; ibuf[0].BufferType = obuf[0].BufferType = SECBUFFER_TOKEN; ibuf[1].BufferType = SECBUFFER_EMPTY; /* initialize buffer descriptors */ ibufs.ulVersion = obufs.ulVersion = SECBUFFER_VERSION; ibufs.cBuffers = 2; obufs.cBuffers = 1; ibufs.pBuffers = ibuf; obufs.pBuffers = obuf; /* negotiate security */ e = sft->InitializeSecurityContext (&stream->cred,size ? &stream->context : NIL,host,req,0, SECURITY_NETWORK_DREP,size ? &ibufs : NIL,0,&stream->context,&obufs, &a,&t); /* have an output buffer we need to send? */ if (obuf[0].pvBuffer && obuf[0].cbBuffer) { if ((done >= 0) && /* do so if in good state */ !tcp_sout (stream->tcpstream,obuf[0].pvBuffer, obuf[0].cbBuffer)) done = -1; /* free the buffer */ sft->FreeContextBuffer (obuf[0].pvBuffer); } switch (e) { /* negotiation state */ case SEC_E_NO_AUTHENTICATING_AUTHORITY: mm_log ("No authority could be contacted for authentication",ERROR); done = -1; break; case SEC_E_WRONG_PRINCIPAL: mm_log ("Principal name incorrect",ERROR); done = -1; break; case SEC_E_UNTRUSTED_ROOT: mm_log ("Certificate chain issued by untrusted authority",ERROR); done = -1; break; case SEC_E_CERT_EXPIRED: mm_log ("Certificate has expired",ERROR); done = -1; break; case SEC_E_OK: done = T; /* got security context, all done */ /* any data to be regurgitated? */ if (ibuf[1].BufferType == SECBUFFER_EXTRA) { /* yes, set this as the new data */ memmove (stream->tcpstream->iptr = stream->tcpstream->ibuf, buf + size - ibuf[1].cbBuffer,ibuf[1].cbBuffer); stream->tcpstream->ictr = ibuf[1].cbBuffer; } if (sft->QueryContextAttributes (&stream->context,SECPKG_ATTR_STREAM_SIZES,&stream->sizes) == SEC_E_OK) { /* get stream sizes */ /* maximum SSL buffer size */ size_t i = stream->sizes.cbHeader + stream->sizes.cbMaximumMessage + stream->sizes.cbTrailer; /* make buffers */ stream->ibuf = (char *) fs_get (i); stream->obuf = (char *) fs_get (i); failed = NIL; /* mark success */ } break; case SEC_I_INCOMPLETE_CREDENTIALS: break; /* server wants client auth */ case SEC_I_CONTINUE_NEEDED: if (size) { /* continue, read any data? */ /* yes, anything regurgiated back to us? */ if (ibuf[1].BufferType == SECBUFFER_EXTRA) { /* yes, set this as the new data */ memmove (buf,buf + size - ibuf[1].cbBuffer,ibuf[1].cbBuffer); size = ibuf[1].cbBuffer; break; } size = 0; /* otherwise, read more stuff from server */ } case SEC_E_INCOMPLETE_MESSAGE: /* need to read more data from server */ if (tcp_getdata (stream->tcpstream)) { memcpy (buf+size,stream->tcpstream->iptr,stream->tcpstream->ictr); size += stream->tcpstream->ictr; /* empty it from TCP's buffers */ stream->tcpstream->iptr += stream->tcpstream->ictr; stream->tcpstream->ictr = 0; } else { mm_log ("Unexpected disconnect during SSL negotiation",ERROR); done = -1; } break; default: /* anything else is an error */ sprintf (buf,"Unexpected SChannel error %lx - report this",e); mm_log (buf,ERROR); done = -1; break; } } } if (failed) { /* failed to negotiate SSL */ if (!(port & 0x80000000)){/* only give error if not silent */ sprintf (buf,"Can't establish SSL session to %.80s/%.80s,%ld", host,service ? service : "SSL",port & 0xffff); mm_log (buf,ERROR); } ssl_close (stream); /* failed to do SSL */ } fs_give ((void **) &buf); /* flush temporary buffer */ }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -