1 /* ========================================================================
2  * Copyright 1988-2008 University of Washington
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  *
11  * ========================================================================
12  */
13 
14 /*
15  * Program:	SSL authentication/encryption module for Windows 9x and NT
16  *
17  * Author:	Mark Crispin
18  *		Networks and Distributed Computing
19  *		Computing & Communications
20  *		University of Washington
21  *		Administration Building, AG-44
22  *		Seattle, WA  98195
23  *		Internet: MRC@CAC.Washington.EDU
24  *
25  * Date:	22 September 1998
26  * Last Edited:	13 January 2008
27  */
28 
29 #define SECURITY_WIN32
30 #include <sspi.h>
31 #if(_WIN32_WINNT < 0x0400)
32 typedef unsigned int ALG_ID;
33 #else
34 #include <wincrypt.h>
35 ALGIDDEF
36 #endif
37 #include <schnlsp.h>
38 #include <issperr.h>
39 
40 				/* in case a binary runs on Windows 2000 */
41 #ifndef ISC_REQ_MANUAL_CRED_VALIDATION
42 #define ISC_REQ_MANUAL_CRED_VALIDATION 0x00080000
43 #endif
44 #ifndef SEC_E_UNTRUSTED_ROOT
45 #define SEC_E_UNTRUSTED_ROOT ((HRESULT) 0x80090325L)
46 #endif
47 #ifndef SEC_E_CERT_EXPIRED
48 #define SEC_E_CERT_EXPIRED ((HRESULT) 0x80090328L)
49 #endif
50 
51 
52 #define SSLBUFLEN 8192
53 
54 
55 /* SSL I/O stream */
56 
57 typedef struct ssl_stream {
58   TCPSTREAM *tcpstream;		/* TCP stream */
59   CredHandle cred;		/* SSL credentials */
60   CtxtHandle context;		/* SSL context */
61 				/* stream encryption sizes */
62   SecPkgContext_StreamSizes sizes;
63   size_t bufsize;
64   int ictr;			/* input counter */
65   char *iptr;			/* input pointer */
66   int iextractr;		/* extra input counter */
67   char *iextraptr;		/* extra input pointer */
68   char *ibuf;			/* input buffer */
69   char *obuf;			/* output buffer */
70 } SSLSTREAM;
71 
72 #include "sslio.h"
73 
74 
75 /* Function prototypes */
76 
77 static SSLSTREAM *ssl_start(TCPSTREAM *tstream,char *host,unsigned long flags);
78 static char *ssl_analyze_status (SECURITY_STATUS err,char *buf);
79 static char *ssl_getline_work (SSLSTREAM *stream,unsigned long *size,
80 			       long *contd);
81 static long ssl_abort (SSLSTREAM *stream);
82 
83 /* Secure Sockets Layer network driver dispatch */
84 
85 static struct ssl_driver ssldriver = {
86   ssl_open,			/* open connection */
87   ssl_aopen,			/* open preauthenticated connection */
88   ssl_getline,			/* get a line */
89   ssl_getbuffer,		/* get a buffer */
90   ssl_soutr,			/* output pushed data */
91   ssl_sout,			/* output string */
92   ssl_close,			/* close connection */
93   ssl_host,			/* return host name */
94   ssl_remotehost,		/* return remote host name */
95   ssl_port,			/* return port number */
96   ssl_localhost			/* return local host name */
97 };
98 
99 				/* security function table */
100 static SecurityFunctionTable *sft = NIL;
101 static unsigned long ssltsz = 0;/* SSL maximum token length */
102 
103 /* One-time SSL initialization */
104 
105 static int sslonceonly = 0;
106 
ssl_onceonlyinit(void)107 void ssl_onceonlyinit (void)
108 {
109   if (!sslonceonly++) {		/* only need to call it once */
110     HINSTANCE lib;
111     FARPROC pi;
112     ULONG np;
113     SecPkgInfo *pp;
114     int i;
115 				/* get security library */
116     if (((lib = LoadLibrary ("schannel.dll")) ||
117 	 (lib = LoadLibrary ("security.dll"))) &&
118 	(pi = GetProcAddress (lib,SECURITY_ENTRYPOINT)) &&
119 	(sft = (SecurityFunctionTable *) pi ()) &&
120 	!(sft->EnumerateSecurityPackages (&np,&pp))) {
121 				/* look for an SSL package */
122       for (i = 0; (i < (int) np); i++) if (!strcmp (pp[i].Name,UNISP_NAME)) {
123 				/* note maximum token size and name */
124 	ssltsz = pp[i].cbMaxToken;
125 				/* apply runtime linkage */
126 	mail_parameters (NIL,SET_SSLDRIVER,(void *) &ssldriver);
127 	mail_parameters (NIL,SET_SSLSTART,(void *) ssl_start);
128 	return;			/* all done */
129       }
130     }
131   }
132 }
133 
134 /* SSL open
135  * Accepts: host name
136  *	    contact service name
137  *	    contact port number
138  * Returns: SSL stream if success else NIL
139  */
140 
ssl_open(char * host,char * service,unsigned long port)141 SSLSTREAM *ssl_open (char *host,char *service,unsigned long port)
142 {
143   TCPSTREAM *stream = tcp_open (host,service,port);
144   return stream ? ssl_start (stream,host,port) : NIL;
145 }
146 
147 
148 /* SSL authenticated open
149  * Accepts: host name
150  *	    service name
151  *	    returned user name buffer
152  * Returns: SSL stream if success else NIL
153  */
154 
ssl_aopen(NETMBX * mb,char * service,char * usrbuf)155 SSLSTREAM *ssl_aopen (NETMBX *mb,char *service,char *usrbuf)
156 {
157   return NIL;			/* don't use this mechanism with SSL */
158 }
159 
160 /* Start SSL/TLS negotiations
161  * Accepts: open TCP stream of session
162  *	    user's host name
163  *	    flags
164  * Returns: SSL stream if success else NIL
165  */
166 
ssl_start(TCPSTREAM * tstream,char * host,unsigned long flags)167 static SSLSTREAM *ssl_start (TCPSTREAM *tstream,char *host,unsigned long flags)
168 {
169   SECURITY_STATUS e;
170   ULONG a;
171   TimeStamp t;
172   SecBuffer ibuf[2],obuf[1];
173   SecBufferDesc ibufs,obufs;
174   char tmp[MAILTMPLEN];
175   char *reason = NIL;
176   ULONG req = ISC_REQ_REPLAY_DETECT | ISC_REQ_SEQUENCE_DETECT |
177     ISC_REQ_CONFIDENTIALITY | ISC_REQ_USE_SESSION_KEY |
178       ISC_REQ_ALLOCATE_MEMORY | ISC_REQ_STREAM | ISC_REQ_EXTENDED_ERROR +
179 	((flags & NET_NOVALIDATECERT) ? ISC_REQ_MANUAL_CRED_VALIDATION :
180 	 ISC_REQ_MUTUAL_AUTH);
181   SCHANNEL_CRED tlscred;
182   char *buf = (char *) fs_get (ssltsz);
183   unsigned long size = 0;
184   sslfailure_t sf = (sslfailure_t) mail_parameters (NIL,GET_SSLFAILURE,NIL);
185   SSLSTREAM *stream = (SSLSTREAM *) memset (fs_get (sizeof (SSLSTREAM)),0,
186 					    sizeof (SSLSTREAM));
187   stream->tcpstream = tstream;	/* bind TCP stream */
188 				/* initialize TLS credential */
189   memset (&tlscred,0,sizeof (SCHANNEL_CRED));
190   tlscred.dwVersion = SCHANNEL_CRED_VERSION;
191   tlscred.grbitEnabledProtocols = SP_PROT_TLS1;
192 
193 				/* acquire credentials */
194   if (sft->AcquireCredentialsHandle
195       (NIL,UNISP_NAME,SECPKG_CRED_OUTBOUND,NIL,(flags & NET_TLSCLIENT) ?
196        &tlscred : NIL,NIL,NIL,&stream->cred,&t)
197       != SEC_E_OK) reason = "Acquire credentials handle failed";
198   else while (!reason) {	/* negotiate security context */
199 				/* initialize buffers */
200     ibuf[0].cbBuffer = size; ibuf[0].pvBuffer = buf;
201     ibuf[1].cbBuffer = 0; ibuf[1].pvBuffer = NIL;
202     obuf[0].cbBuffer = 0; obuf[0].pvBuffer = NIL;
203     ibuf[0].BufferType = obuf[0].BufferType = SECBUFFER_TOKEN;
204     ibuf[1].BufferType = SECBUFFER_EMPTY;
205 				/* initialize buffer descriptors */
206     ibufs.ulVersion = obufs.ulVersion = SECBUFFER_VERSION;
207     ibufs.cBuffers = 2; obufs.cBuffers = 1;
208     ibufs.pBuffers = ibuf; obufs.pBuffers = obuf;
209 				/* negotiate security */
210     e = sft->InitializeSecurityContext
211       (&stream->cred,size ? &stream->context : NIL,host,req,0,
212        SECURITY_NETWORK_DREP,size? &ibufs:NIL,0,&stream->context,&obufs,&a,&t);
213 				/* have an output buffer we need to send? */
214     if (obuf[0].pvBuffer && obuf[0].cbBuffer) {
215       if (!tcp_sout (stream->tcpstream,obuf[0].pvBuffer,obuf[0].cbBuffer))
216 	reason = "Unexpected TCP output disconnect";
217 				/* free the buffer */
218       sft->FreeContextBuffer (obuf[0].pvBuffer);
219     }
220     if (!reason) switch (e) {	/* negotiation state */
221     case SEC_I_INCOMPLETE_CREDENTIALS:
222       break;			/* server wants client auth */
223     case SEC_I_CONTINUE_NEEDED:
224       if (size) {		/* continue, read any data? */
225 				/* yes, anything regurgiated back to us? */
226 	if (ibuf[1].BufferType == SECBUFFER_EXTRA) {
227 				/* yes, set this as the new data */
228 	  memmove (buf,buf + size - ibuf[1].cbBuffer,ibuf[1].cbBuffer);
229 	  size = ibuf[1].cbBuffer;
230 	  break;
231 	}
232 	size = 0;		/* otherwise, read more stuff from server */
233       }
234     case SEC_E_INCOMPLETE_MESSAGE:
235 				/* need to read more data from server */
236       if (!tcp_getdata (stream->tcpstream))
237 	reason = "Unexpected TCP input disconnect";
238       else {
239 	memcpy (buf+size,stream->tcpstream->iptr,stream->tcpstream->ictr);
240 	size += stream->tcpstream->ictr;
241 				/* empty it from TCP's buffers */
242 	stream->tcpstream->iptr += stream->tcpstream->ictr;
243 	stream->tcpstream->ictr = 0;
244       }
245       break;
246 
247     case SEC_E_OK:		/* success, any data to be regurgitated? */
248       if (ibuf[1].BufferType == SECBUFFER_EXTRA) {
249 				/* yes, set this as the new data */
250 	memmove (stream->tcpstream->iptr = stream->tcpstream->ibuf,
251 		 buf + size - ibuf[1].cbBuffer,ibuf[1].cbBuffer);
252 	stream->tcpstream->ictr = ibuf[1].cbBuffer;
253       }
254       if (reason = ssl_analyze_status
255 	  (sft->QueryContextAttributes
256 	   (&stream->context,SECPKG_ATTR_STREAM_SIZES,&stream->sizes),buf))
257 	break;			/* error getting sizes */
258       fs_give ((void **) &buf);	/* flush temporary buffer */
259 				/* make maximum-sized buffers */
260       stream->bufsize = stream->sizes.cbHeader +
261 	stream->sizes.cbMaximumMessage + stream->sizes.cbTrailer;
262       if (stream->sizes.cbMaximumMessage < SSLBUFLEN)
263 	fatal ("cbMaximumMessage is less than SSLBUFLEN!");
264       else if (stream->sizes.cbMaximumMessage < 16384) {
265 	sprintf (tmp,"WINDOWS BUG: cbMaximumMessage = %ld, should be 16384",
266 		 (long) stream->sizes.cbMaximumMessage);
267 	mm_log (tmp,NIL);
268       }
269       stream->ibuf = (char *) fs_get (stream->bufsize);
270       stream->obuf = (char *) fs_get (stream->bufsize);
271       return stream;
272     default:
273       reason = ssl_analyze_status (e,buf);
274     }
275   }
276   ssl_close (stream);		/* failed to do SSL */
277   stream = NIL;			/* no stream returned */
278   fs_give ((void **) &buf);	/* flush temporary buffer */
279   switch (*reason) {		/* analyze reason */
280   case '*':			/* certificate failure */
281     ++reason;			/* skip over certificate failure indication */
282 				/* pass to error callback */
283     if (sf) (*sf) (host,reason,flags);
284     else {			/* no error callback, build error message */
285       sprintf (tmp,"Certificate failure for %.80s: %.512s",host,reason);
286       mm_log (tmp,ERROR);
287     }
288   case '\0':			/* user answered no to certificate callback */
289     if (flags & NET_TRYSSL)	/* return dummy stream to stop tryssl */
290       stream = (SSLSTREAM *) memset (fs_get (sizeof (SSLSTREAM)),0,
291 				     sizeof (SSLSTREAM));
292     break;
293   default:			/* non-certificate failure */
294     if (flags & NET_TRYSSL);	/* no error output if tryssl */
295 				/* pass to error callback */
296     else if (sf) (*sf) (host,reason,flags);
297     else {			/* no error callback, build error message */
298       sprintf (tmp,"TLS/SSL failure for %.80s: %.512s",host,reason);
299       mm_log (tmp,ERROR);
300     }
301     break;
302   }
303   return stream;
304 }
305 
306 /* Generate error text from SSL error code
307  * Accepts: SSL status
308  *	    scratch buffer
309  * Returns: text if error status, else NIL
310  */
311 
ssl_analyze_status(SECURITY_STATUS err,char * buf)312 static char *ssl_analyze_status (SECURITY_STATUS err,char *buf)
313 {
314   switch (err) {
315   case SEC_E_OK:		/* no error */
316   case SEC_I_CONTINUE_NEEDED:
317   case SEC_I_INCOMPLETE_CREDENTIALS:
318   case SEC_E_INCOMPLETE_MESSAGE:
319     return NIL;
320   case SEC_E_NO_AUTHENTICATING_AUTHORITY:
321     return "*No authority could be contacted for authentication";
322   case SEC_E_WRONG_PRINCIPAL:
323     return "*Server name does not match certificate";
324   case SEC_E_UNTRUSTED_ROOT:
325     return "*Self-signed certificate or untrusted authority";
326   case SEC_E_CERT_EXPIRED:
327     return "*Certificate has expired";
328   case SEC_E_INVALID_TOKEN:
329     return "Invalid token, probably not an SSL server";
330   case SEC_E_UNSUPPORTED_FUNCTION:
331     return "SSL not supported on this machine - upgrade your system software";
332   }
333   sprintf (buf,"Unexpected SChannel error %lx - report this",err);
334   return buf;
335 }
336 
337 /* SSL receive line
338  * Accepts: SSL stream
339  * Returns: text line string or NIL if failure
340  */
341 
ssl_getline(SSLSTREAM * stream)342 char *ssl_getline (SSLSTREAM *stream)
343 {
344   unsigned long n,contd;
345   char *ret = ssl_getline_work (stream,&n,&contd);
346   if (ret && contd) {		/* got a line needing continuation? */
347     STRINGLIST *stl = mail_newstringlist ();
348     STRINGLIST *stc = stl;
349     do {			/* collect additional lines */
350       stc->text.data = (unsigned char *) ret;
351       stc->text.size = n;
352       stc = stc->next = mail_newstringlist ();
353       ret = ssl_getline_work (stream,&n,&contd);
354     } while (ret && contd);
355     if (ret) {			/* stash final part of line on list */
356       stc->text.data = (unsigned char *) ret;
357       stc->text.size = n;
358 				/* determine how large a buffer we need */
359       for (n = 0, stc = stl; stc; stc = stc->next) n += stc->text.size;
360       ret = fs_get (n + 1);	/* copy parts into buffer */
361       for (n = 0, stc = stl; stc; n += stc->text.size, stc = stc->next)
362 	memcpy (ret + n,stc->text.data,stc->text.size);
363       ret[n] = '\0';
364     }
365     mail_free_stringlist (&stl);/* either way, done with list */
366   }
367   return ret;
368 }
369 
370 /* SSL receive line or partial line
371  * Accepts: SSL stream
372  *	    pointer to return size
373  *	    pointer to return continuation flag
374  * Returns: text line string, size and continuation flag, or NIL if failure
375  */
376 
ssl_getline_work(SSLSTREAM * stream,unsigned long * size,long * contd)377 static char *ssl_getline_work (SSLSTREAM *stream,unsigned long *size,
378 			       long *contd)
379 {
380   unsigned long n;
381   char *s,*ret,c,d;
382   *contd = NIL;			/* assume no continuation */
383 				/* make sure have data */
384   if (!ssl_getdata (stream)) return NIL;
385   for (s = stream->iptr, n = 0, c = '\0'; stream->ictr--; n++, c = d) {
386     d = *stream->iptr++;	/* slurp another character */
387     if ((c == '\015') && (d == '\012')) {
388       ret = (char *) fs_get (n--);
389       memcpy (ret,s,*size = n);	/* copy into a free storage string */
390       ret[n] = '\0';		/* tie off string with null */
391       return ret;
392     }
393   }
394 				/* copy partial string from buffer */
395   memcpy ((ret = (char *) fs_get (n)),s,*size = n);
396 				/* get more data from the net */
397   if (!ssl_getdata (stream)) fs_give ((void **) &ret);
398 				/* special case of newline broken by buffer */
399   else if ((c == '\015') && (*stream->iptr == '\012')) {
400     stream->iptr++;		/* eat the line feed */
401     stream->ictr--;
402     ret[*size = --n] = '\0';	/* tie off string with null */
403   }
404   else *contd = LONGT;		/* continuation needed */
405   return ret;
406 }
407 
408 /* SSL receive buffer
409  * Accepts: SSL stream
410  *	    size in bytes
411  *	    buffer to read into
412  * Returns: T if success, NIL otherwise
413  */
414 
ssl_getbuffer(SSLSTREAM * stream,unsigned long size,char * buffer)415 long ssl_getbuffer (SSLSTREAM *stream,unsigned long size,char *buffer)
416 {
417   unsigned long n;
418   while (size > 0) {		/* until request satisfied */
419     if (!ssl_getdata (stream)) return NIL;
420     n = min (size,stream->ictr);/* number of bytes to transfer */
421 				/* do the copy */
422     memcpy (buffer,stream->iptr,n);
423     buffer += n;		/* update pointer */
424     stream->iptr += n;
425     size -= n;			/* update # of bytes to do */
426     stream->ictr -= n;
427   }
428   buffer[0] = '\0';		/* tie off string */
429   return T;
430 }
431 
432 /* SSL receive data
433  * Accepts: TCP/IP stream
434  * Returns: T if success, NIL otherwise
435  */
436 
ssl_getdata(SSLSTREAM * stream)437 long ssl_getdata (SSLSTREAM *stream)
438 {
439   while (stream->ictr < 1) {	/* decrypted buffer empty? */
440     SECURITY_STATUS status;
441     SecBuffer buf[4];
442     SecBufferDesc msg;
443     size_t i;
444     size_t n = 0;		/* initially no bytes to decrypt */
445     do {			/* yes, make sure have data from TCP */
446       if (stream->iextractr) {	/* have previous unread data? */
447 	memcpy (stream->ibuf + n,stream->iextraptr,stream->iextractr);
448 	n += stream->iextractr;	/* update number of bytes read */
449 	stream->iextractr = 0;	/* no more extra data */
450       }
451       else {			/* read from TCP */
452 	if (!tcp_getdata (stream->tcpstream)) return ssl_abort (stream);
453 				/* maximum amount of data to copy */
454 	if (!(i = min (stream->bufsize - n,stream->tcpstream->ictr)))
455 	  fatal ("incomplete SecBuffer exceeds maximum buffer size");
456 				/* do the copy */
457 	memcpy (stream->ibuf + n,stream->tcpstream->iptr,i);
458 	stream->tcpstream->iptr += i;
459 	stream->tcpstream->ictr -= i;
460 	n += i;			/* update number of bytes to decrypt */
461       }
462       buf[0].cbBuffer = n;	/* first SecBuffer gets data */
463       buf[0].pvBuffer = stream->ibuf;
464       buf[0].BufferType = SECBUFFER_DATA;
465 				/* subsequent ones are for spares */
466       buf[1].BufferType = buf[2].BufferType = buf[3].BufferType =
467 	SECBUFFER_EMPTY;
468       msg.ulVersion = SECBUFFER_VERSION;
469       msg.cBuffers = 4;		/* number of SecBuffers */
470       msg.pBuffers = buf;	/* first SecBuffer */
471 
472     } while ((status = ((DECRYPT_MESSAGE_FN) sft->Reserved4)
473 	      (&stream->context,&msg,0,NIL)) == SEC_E_INCOMPLETE_MESSAGE);
474     switch (status) {
475     case SEC_E_OK:		/* won */
476     case SEC_I_RENEGOTIATE:	/* won but lost it after this buffer */
477 				/* hunt for a buffer */
478       for (i = 0; (i < 4) && (buf[i].BufferType != SECBUFFER_DATA) ; i++);
479       if (i < 4) {		/* found a buffer? */
480 				/* yes, set up pointer and counter */
481 	stream->iptr = buf[i].pvBuffer;
482 	stream->ictr = buf[i].cbBuffer;
483 				/* any unprocessed data? */
484 	while (++i < 4) if (buf[i].BufferType == SECBUFFER_EXTRA) {
485 				/* yes, note for next time around */
486 	  stream->iextraptr = buf[i].pvBuffer;
487 	  stream->iextractr = buf[i].cbBuffer;
488 	}
489       }
490       break;
491     default:			/* anything else means we've lost */
492       return ssl_abort (stream);
493     }
494   }
495   return LONGT;
496 }
497 
498 /* SSL send string as record
499  * Accepts: SSL stream
500  *	    string pointer
501  * Returns: T if success else NIL
502  */
503 
ssl_soutr(SSLSTREAM * stream,char * string)504 long ssl_soutr (SSLSTREAM *stream,char *string)
505 {
506   return ssl_sout (stream,string,(unsigned long) strlen (string));
507 }
508 
509 
510 /* SSL send string
511  * Accepts: SSL stream
512  *	    string pointer
513  *	    byte count
514  * Returns: T if success else NIL
515  */
516 
ssl_sout(SSLSTREAM * stream,char * string,unsigned long size)517 long ssl_sout (SSLSTREAM *stream,char *string,unsigned long size)
518 {
519   SecBuffer buf[4];
520   SecBufferDesc msg;
521   char *s = stream->ibuf;
522   size_t n = 0;
523   while (size) {		/* until satisfied request */
524 				/* header */
525     buf[0].BufferType = SECBUFFER_STREAM_HEADER;
526     memset (buf[0].pvBuffer = stream->obuf,0,
527 	    buf[0].cbBuffer = stream->sizes.cbHeader);
528 				/* message (up to maximum size) */
529     buf[1].BufferType = SECBUFFER_DATA;
530     memcpy (buf[1].pvBuffer = stream->obuf + stream->sizes.cbHeader,string,
531 	    buf[1].cbBuffer = min (size,SSLBUFLEN));
532 				/* trailer */
533     buf[2].BufferType = SECBUFFER_STREAM_TRAILER;
534     memset (buf[2].pvBuffer = ((char *) buf[1].pvBuffer) + buf[1].cbBuffer,0,
535 	    buf[2].cbBuffer = stream->sizes.cbTrailer);
536 				/* spare */
537     buf[3].BufferType = SECBUFFER_EMPTY;
538     msg.ulVersion = SECBUFFER_VERSION;
539     msg.cBuffers = 4;		/* number of SecBuffers */
540     msg.pBuffers = buf;		/* first SecBuffer */
541     string += buf[1].cbBuffer;
542     size -= buf[1].cbBuffer;	/* this many bytes processed */
543 				/* encrypt and send message */
544     if ((((ENCRYPT_MESSAGE_FN) sft->Reserved3)
545 	 (&stream->context,0,&msg,NIL) != SEC_E_OK) ||
546 	!tcp_sout (stream->tcpstream,stream->obuf,
547 		   buf[0].cbBuffer + buf[1].cbBuffer + buf[2].cbBuffer))
548       return ssl_abort (stream);/* encryption or sending failed */
549   }
550   return LONGT;
551 }
552 
553 /* SSL close
554  * Accepts: SSL stream
555  */
556 
ssl_close(SSLSTREAM * stream)557 void ssl_close (SSLSTREAM *stream)
558 {
559   ssl_abort (stream);		/* nuke the stream */
560   fs_give ((void **) &stream);	/* flush the stream */
561 }
562 
563 
564 /* SSL abort stream
565  * Accepts: SSL stream
566  * Returns: NIL always
567  */
568 
ssl_abort(SSLSTREAM * stream)569 static long ssl_abort (SSLSTREAM *stream)
570 {
571   if (stream->tcpstream) {	/* close TCP stream */
572     sft->DeleteSecurityContext (&stream->context);
573     sft->FreeCredentialHandle (&stream->cred);
574     tcp_close (stream->tcpstream);
575     stream->tcpstream = NIL;
576   }
577   if (stream->ibuf) fs_give ((void **) &stream->ibuf);
578   if (stream->obuf) fs_give ((void **) &stream->obuf);
579   return NIL;
580 }
581 
582 /* SSL get host name
583  * Accepts: SSL stream
584  * Returns: host name for this stream
585  */
586 
ssl_host(SSLSTREAM * stream)587 char *ssl_host (SSLSTREAM *stream)
588 {
589   return tcp_host (stream->tcpstream);
590 }
591 
592 
593 /* SSL get remote host name
594  * Accepts: SSL stream
595  * Returns: host name for this stream
596  */
597 
ssl_remotehost(SSLSTREAM * stream)598 char *ssl_remotehost (SSLSTREAM *stream)
599 {
600   return tcp_remotehost (stream->tcpstream);
601 }
602 
603 
604 /* SSL return port for this stream
605  * Accepts: SSL stream
606  * Returns: port number for this stream
607  */
608 
ssl_port(SSLSTREAM * stream)609 unsigned long ssl_port (SSLSTREAM *stream)
610 {
611   return tcp_port (stream->tcpstream);
612 }
613 
614 
615 /* SSL get local host name
616  * Accepts: SSL stream
617  * Returns: local host name
618  */
619 
ssl_localhost(SSLSTREAM * stream)620 char *ssl_localhost (SSLSTREAM *stream)
621 {
622   return tcp_localhost (stream->tcpstream);
623 }
624 
625 #include "ssl_none.c"		/* currently no server support */
626