imapext-2007

view src/osdep/nt/ssl_w2k.c @ 0:ada5e610ab86

imap-2007e
author yuuji@gentei.org
date Mon, 14 Sep 2009 15:17:45 +0900
parents
children
line source
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 */
14 /*
15 * Program: SSL authentication/encryption module for Windows 2000
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 */
29 #define SECURITY_WIN32
30 #include <sspi.h>
31 #include <schannel.h>
34 #define SSLBUFLEN 8192
37 /* SSL I/O stream */
39 typedef struct ssl_stream {
40 TCPSTREAM *tcpstream; /* TCP stream */
41 CredHandle cred; /* SSL credentials */
42 CtxtHandle context; /* SSL context */
43 /* stream encryption sizes */
44 SecPkgContext_StreamSizes sizes;
45 size_t bufsize;
46 int ictr; /* input counter */
47 char *iptr; /* input pointer */
48 int iextractr; /* extra input counter */
49 char *iextraptr; /* extra input pointer */
50 char *ibuf; /* input buffer */
51 char *obuf; /* output buffer */
52 } SSLSTREAM;
54 #include "sslio.h"
57 /* Function prototypes */
59 static SSLSTREAM *ssl_start(TCPSTREAM *tstream,char *host,unsigned long flags);
60 static char *ssl_analyze_status (SECURITY_STATUS err,char *buf);
61 static char *ssl_getline_work (SSLSTREAM *stream,unsigned long *size,
62 long *contd);
63 static long ssl_abort (SSLSTREAM *stream);
65 /* Secure Sockets Layer network driver dispatch */
67 static struct ssl_driver ssldriver = {
68 ssl_open, /* open connection */
69 ssl_aopen, /* open preauthenticated connection */
70 ssl_getline, /* get a line */
71 ssl_getbuffer, /* get a buffer */
72 ssl_soutr, /* output pushed data */
73 ssl_sout, /* output string */
74 ssl_close, /* close connection */
75 ssl_host, /* return host name */
76 ssl_remotehost, /* return remote host name */
77 ssl_port, /* return port number */
78 ssl_localhost /* return local host name */
79 };
81 static unsigned long ssltsz = 0;/* SSL maximum token length */
83 /* One-time SSL initialization */
85 static int sslonceonly = 0;
87 void ssl_onceonlyinit (void)
88 {
89 if (!sslonceonly++) { /* only need to call it once */
90 ULONG np;
91 SecPkgInfo *pp;
92 int i;
93 /* get security library */
94 if (!EnumerateSecurityPackages (&np,&pp)) {
95 /* look for an SSL package */
96 for (i = 0; (i < (int) np); i++) if (!strcmp (pp[i].Name,UNISP_NAME)) {
97 /* note maximum token size and name */
98 ssltsz = pp[i].cbMaxToken;
99 /* apply runtime linkage */
100 mail_parameters (NIL,SET_SSLDRIVER,(void *) &ssldriver);
101 mail_parameters (NIL,SET_SSLSTART,(void *) ssl_start);
102 return; /* all done */
103 }
104 }
105 }
106 }
108 /* SSL open
109 * Accepts: host name
110 * contact service name
111 * contact port number
112 * Returns: SSL stream if success else NIL
113 */
115 SSLSTREAM *ssl_open (char *host,char *service,unsigned long port)
116 {
117 TCPSTREAM *stream = tcp_open (host,service,port);
118 return stream ? ssl_start (stream,host,port) : NIL;
119 }
122 /* SSL authenticated open
123 * Accepts: host name
124 * service name
125 * returned user name buffer
126 * Returns: SSL stream if success else NIL
127 */
129 SSLSTREAM *ssl_aopen (NETMBX *mb,char *service,char *usrbuf)
130 {
131 return NIL; /* don't use this mechanism with SSL */
132 }
134 /* Start SSL/TLS negotiations
135 * Accepts: open TCP stream of session
136 * user's host name
137 * flags
138 * Returns: SSL stream if success else NIL
139 */
141 static SSLSTREAM *ssl_start (TCPSTREAM *tstream,char *host,unsigned long flags)
142 {
143 SECURITY_STATUS e;
144 ULONG a;
145 TimeStamp t;
146 SecBuffer ibuf[2],obuf[1];
147 SecBufferDesc ibufs,obufs;
148 SCHANNEL_CRED tlscred;
149 CERT_CONTEXT *cert = NIL;
150 CERT_CHAIN_PARA chparam;
151 CERT_CHAIN_CONTEXT *chain;
152 SSL_EXTRA_CERT_CHAIN_POLICY_PARA policy;
153 CERT_CHAIN_POLICY_PARA polparam;
154 CERT_CHAIN_POLICY_STATUS status;
155 char tmp[MAILTMPLEN],certname[256];
156 char *reason = NIL;
157 ULONG req = ISC_REQ_REPLAY_DETECT | ISC_REQ_SEQUENCE_DETECT |
158 ISC_REQ_CONFIDENTIALITY | ISC_REQ_USE_SESSION_KEY |
159 ISC_REQ_ALLOCATE_MEMORY | ISC_REQ_STREAM | ISC_REQ_EXTENDED_ERROR |
160 ISC_REQ_MANUAL_CRED_VALIDATION;
161 LPSTR usage[] = {
162 szOID_PKIX_KP_SERVER_AUTH,
163 szOID_SERVER_GATED_CRYPTO,
164 szOID_SGC_NETSCAPE
165 };
166 PWSTR whost = NIL;
167 char *buf = (char *) fs_get (ssltsz);
168 unsigned long size = 0;
169 sslcertificatequery_t scq =
170 (sslcertificatequery_t) mail_parameters (NIL,GET_SSLCERTIFICATEQUERY,NIL);
171 sslfailure_t sf = (sslfailure_t) mail_parameters (NIL,GET_SSLFAILURE,NIL);
172 SSLSTREAM *stream = (SSLSTREAM *) memset (fs_get (sizeof (SSLSTREAM)),0,
173 sizeof (SSLSTREAM));
174 stream->tcpstream = tstream; /* bind TCP stream */
175 /* initialize TLS credential */
176 memset (&tlscred,0,sizeof (SCHANNEL_CRED));
177 tlscred.dwVersion = SCHANNEL_CRED_VERSION;
178 tlscred.grbitEnabledProtocols = SP_PROT_TLS1;
180 /* acquire credentials */
181 if (AcquireCredentialsHandle
182 (NIL,UNISP_NAME,SECPKG_CRED_OUTBOUND,NIL,(flags & NET_TLSCLIENT) ?
183 &tlscred : NIL,NIL,NIL,&stream->cred,&t)
184 != SEC_E_OK) reason = "Acquire credentials handle failed";
185 else while (!reason) { /* negotiate security context */
186 /* initialize buffers */
187 ibuf[0].cbBuffer = size; ibuf[0].pvBuffer = buf;
188 ibuf[1].cbBuffer = 0; ibuf[1].pvBuffer = NIL;
189 obuf[0].cbBuffer = 0; obuf[0].pvBuffer = NIL;
190 ibuf[0].BufferType = obuf[0].BufferType = SECBUFFER_TOKEN;
191 ibuf[1].BufferType = SECBUFFER_EMPTY;
192 /* initialize buffer descriptors */
193 ibufs.ulVersion = obufs.ulVersion = SECBUFFER_VERSION;
194 ibufs.cBuffers = 2; obufs.cBuffers = 1;
195 ibufs.pBuffers = ibuf; obufs.pBuffers = obuf;
196 /* negotiate security */
197 e = InitializeSecurityContext
198 (&stream->cred,size ? &stream->context : NIL,host,req,0,
199 SECURITY_NETWORK_DREP,size? &ibufs:NIL,0,&stream->context,&obufs,&a,&t);
200 /* have an output buffer we need to send? */
201 if (obuf[0].pvBuffer && obuf[0].cbBuffer) {
202 if (!tcp_sout (stream->tcpstream,obuf[0].pvBuffer,obuf[0].cbBuffer))
203 reason = "Unexpected TCP output disconnect";
204 /* free the buffer */
205 FreeContextBuffer (obuf[0].pvBuffer);
206 }
207 if (!reason) switch (e) { /* negotiation state */
208 case SEC_I_INCOMPLETE_CREDENTIALS:
209 break; /* server wants client auth */
210 case SEC_I_CONTINUE_NEEDED:
211 if (size) { /* continue, read any data? */
212 /* yes, anything regurgiated back to us? */
213 if (ibuf[1].BufferType == SECBUFFER_EXTRA) {
214 /* yes, set this as the new data */
215 memmove (buf,buf + size - ibuf[1].cbBuffer,ibuf[1].cbBuffer);
216 size = ibuf[1].cbBuffer;
217 break;
218 }
219 size = 0; /* otherwise, read more stuff from server */
220 }
221 case SEC_E_INCOMPLETE_MESSAGE:
222 /* need to read more data from server */
223 if (!tcp_getdata (stream->tcpstream))
224 reason = "Unexpected TCP input disconnect";
225 else {
226 memcpy (buf+size,stream->tcpstream->iptr,stream->tcpstream->ictr);
227 size += stream->tcpstream->ictr;
228 /* empty it from TCP's buffers */
229 stream->tcpstream->iptr += stream->tcpstream->ictr;
230 stream->tcpstream->ictr = 0;
231 }
232 break;
234 case SEC_E_OK: /* success, any data to be regurgitated? */
235 if (ibuf[1].BufferType == SECBUFFER_EXTRA) {
236 /* yes, set this as the new data */
237 memmove (stream->tcpstream->iptr = stream->tcpstream->ibuf,
238 buf + size - ibuf[1].cbBuffer,ibuf[1].cbBuffer);
239 stream->tcpstream->ictr = ibuf[1].cbBuffer;
240 }
241 if (!(flags & NET_NOVALIDATECERT)) {
242 /* need validation, make wchar of host */
243 if (!((size = MultiByteToWideChar (CP_ACP,0,host,-1,NIL,0)) &&
244 (whost = (PWSTR) fs_get (size*sizeof (WCHAR))) &&
245 MultiByteToWideChar (CP_ACP,0,host,-1,whost,size)))
246 fatal ("Can't make wchar of host name!");
247 /* get certificate */
248 if ((QueryContextAttributes
249 (&stream->context,SECPKG_ATTR_REMOTE_CERT_CONTEXT,&cert) !=
250 SEC_E_OK) || !cert) {
251 reason = "*Unable to get certificate";
252 strcpy (certname,"<no certificate>");
253 }
254 else { /* get certificate subject name */
255 CertNameToStr (X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
256 &cert->pCertInfo->Subject,CERT_X500_NAME_STR,
257 certname,255);
258 /* build certificate chain */
259 memset (&chparam,0,sizeof (chparam));
260 chparam.cbSize = sizeof (chparam);
261 chparam.RequestedUsage.dwType = USAGE_MATCH_TYPE_OR;
262 chparam.RequestedUsage.Usage.rgpszUsageIdentifier = usage;
263 chparam.RequestedUsage.Usage.cUsageIdentifier =
264 sizeof (usage) / sizeof (LPSTR);
265 if (!CertGetCertificateChain
266 (NIL,cert,NIL,cert->hCertStore,&chparam,NIL,NIL,&chain))
267 reason = ssl_analyze_status (GetLastError (),tmp);
268 else { /* validate certificate chain */
269 memset (&policy,0,sizeof (SSL_EXTRA_CERT_CHAIN_POLICY_PARA));
270 policy.cbStruct = sizeof (SSL_EXTRA_CERT_CHAIN_POLICY_PARA);
271 policy.dwAuthType = AUTHTYPE_SERVER;
272 policy.fdwChecks = NIL;
273 policy.pwszServerName = whost;
274 memset (&polparam,0,sizeof (polparam));
275 polparam.cbSize = sizeof (polparam);
276 polparam.pvExtraPolicyPara = &policy;
277 memset (&status,0,sizeof (status));
278 status.cbSize = sizeof (status);
279 if (!CertVerifyCertificateChainPolicy
280 (CERT_CHAIN_POLICY_SSL,chain,&polparam,&status))
281 reason = ssl_analyze_status (GetLastError (),tmp);
282 else if (status.dwError)
283 reason = ssl_analyze_status (status.dwError,tmp);
284 CertFreeCertificateChain (chain);
285 }
286 CertFreeCertificateContext (cert);
287 }
288 if (whost) fs_give ((void **) &whost);
290 if (reason) { /* got an error? */
291 /* application callback */
292 if (scq) reason = (*scq) ((*reason == '*') ? reason + 1 : reason,
293 host,certname) ? NIL : "";
294 else if (*certname) { /* error message to return via mm_log() */
295 sprintf (buf,"*%.128s: %.255s",
296 (*reason == '*') ? reason + 1 : reason,certname);
297 reason = buf;
298 }
299 }
300 }
301 if (reason ||
302 (reason = ssl_analyze_status
303 (QueryContextAttributes
304 (&stream->context,SECPKG_ATTR_STREAM_SIZES,&stream->sizes),buf)))
305 break; /* error in certificate or getting sizes */
306 fs_give ((void **) &buf); /* flush temporary buffer */
307 /* make maximum-sized buffers */
308 stream->bufsize = stream->sizes.cbHeader +
309 stream->sizes.cbMaximumMessage + stream->sizes.cbTrailer;
310 if (stream->sizes.cbMaximumMessage < SSLBUFLEN)
311 fatal ("cbMaximumMessage is less than SSLBUFLEN!");
312 else if (stream->sizes.cbMaximumMessage < 16384) {
313 sprintf (tmp,"WINDOWS BUG: cbMaximumMessage = %ld, should be 16384",
314 (long) stream->sizes.cbMaximumMessage);
315 mm_log (tmp,NIL);
316 }
317 stream->ibuf = (char *) fs_get (stream->bufsize);
318 stream->obuf = (char *) fs_get (stream->bufsize);
319 return stream;
320 default:
321 reason = ssl_analyze_status (e,buf);
322 }
323 }
324 ssl_close (stream); /* failed to do SSL */
325 stream = NIL; /* no stream returned */
326 switch (*reason) { /* analyze reason */
327 case '*': /* certificate failure */
328 ++reason; /* skip over certificate failure indication */
329 /* pass to error callback */
330 if (sf) (*sf) (host,reason,flags);
331 else { /* no error callback, build error message */
332 sprintf (tmp,"Certificate failure for %.80s: %.512s",host,reason);
333 mm_log (tmp,ERROR);
334 }
335 case '\0': /* user answered no to certificate callback */
336 if (flags & NET_TRYSSL) /* return dummy stream to stop tryssl */
337 stream = (SSLSTREAM *) memset (fs_get (sizeof (SSLSTREAM)),0,
338 sizeof (SSLSTREAM));
339 break;
340 default: /* non-certificate failure */
341 if (flags & NET_TRYSSL); /* no error output if tryssl */
342 /* pass to error callback */
343 else if (sf) (*sf) (host,reason,flags);
344 else { /* no error callback, build error message */
345 sprintf (tmp,"TLS/SSL failure for %.80s: %.512s",host,reason);
346 mm_log (tmp,ERROR);
347 }
348 break;
349 }
350 fs_give ((void **) &buf); /* flush temporary buffer */
351 return stream;
352 }
354 /* Generate error text from SSL error code
355 * Accepts: SSL status
356 * scratch buffer
357 * Returns: text if error status, else NIL
358 */
360 static char *ssl_analyze_status (SECURITY_STATUS err,char *buf)
361 {
362 switch (err) {
363 case SEC_E_OK: /* no error */
364 case SEC_I_CONTINUE_NEEDED:
365 case SEC_I_INCOMPLETE_CREDENTIALS:
366 case SEC_E_INCOMPLETE_MESSAGE:
367 return NIL;
368 case SEC_E_NO_AUTHENTICATING_AUTHORITY:
369 mm_log ("unexpected SEC_E_NO_AUTHENTICATING_AUTHORITY",NIL);
370 return "*No authority could be contacted for authentication";
371 case SEC_E_WRONG_PRINCIPAL:
372 mm_log ("unexpected SEC_E_WRONG_PRINCIPAL",NIL);
373 case CERT_E_CN_NO_MATCH:
374 return "*Server name does not match certificate";
375 case SEC_E_UNTRUSTED_ROOT:
376 mm_log ("unexpected SEC_E_UNTRUSTED_ROOT",NIL);
377 case CERT_E_UNTRUSTEDROOT:
378 return "*Self-signed certificate or untrusted authority";
379 case SEC_E_CERT_EXPIRED:
380 mm_log ("unexpected SEC_E_CERT_EXPIRED",NIL);
381 case CERT_E_EXPIRED:
382 return "*Certificate has expired";
383 case CERT_E_REVOKED:
384 return "*Certificate revoked";
385 case SEC_E_INVALID_TOKEN:
386 return "Invalid token, probably not an SSL server";
387 case SEC_E_UNSUPPORTED_FUNCTION:
388 return "SSL not supported on this machine - upgrade your system software";
389 }
390 sprintf (buf,"Unexpected SSPI or certificate error %lx - report this",err);
391 return buf;
392 }
394 /* SSL receive line
395 * Accepts: SSL stream
396 * Returns: text line string or NIL if failure
397 */
399 char *ssl_getline (SSLSTREAM *stream)
400 {
401 unsigned long n,contd;
402 char *ret = ssl_getline_work (stream,&n,&contd);
403 if (ret && contd) { /* got a line needing continuation? */
404 STRINGLIST *stl = mail_newstringlist ();
405 STRINGLIST *stc = stl;
406 do { /* collect additional lines */
407 stc->text.data = (unsigned char *) ret;
408 stc->text.size = n;
409 stc = stc->next = mail_newstringlist ();
410 ret = ssl_getline_work (stream,&n,&contd);
411 } while (ret && contd);
412 if (ret) { /* stash final part of line on list */
413 stc->text.data = (unsigned char *) ret;
414 stc->text.size = n;
415 /* determine how large a buffer we need */
416 for (n = 0, stc = stl; stc; stc = stc->next) n += stc->text.size;
417 ret = fs_get (n + 1); /* copy parts into buffer */
418 for (n = 0, stc = stl; stc; n += stc->text.size, stc = stc->next)
419 memcpy (ret + n,stc->text.data,stc->text.size);
420 ret[n] = '\0';
421 }
422 mail_free_stringlist (&stl);/* either way, done with list */
423 }
424 return ret;
425 }
427 /* SSL receive line or partial line
428 * Accepts: SSL stream
429 * pointer to return size
430 * pointer to return continuation flag
431 * Returns: text line string, size and continuation flag, or NIL if failure
432 */
434 static char *ssl_getline_work (SSLSTREAM *stream,unsigned long *size,
435 long *contd)
436 {
437 unsigned long n;
438 char *s,*ret,c,d;
439 *contd = NIL; /* assume no continuation */
440 /* make sure have data */
441 if (!ssl_getdata (stream)) return NIL;
442 for (s = stream->iptr, n = 0, c = '\0'; stream->ictr--; n++, c = d) {
443 d = *stream->iptr++; /* slurp another character */
444 if ((c == '\015') && (d == '\012')) {
445 ret = (char *) fs_get (n--);
446 memcpy (ret,s,*size = n); /* copy into a free storage string */
447 ret[n] = '\0'; /* tie off string with null */
448 return ret;
449 }
450 }
451 /* copy partial string from buffer */
452 memcpy ((ret = (char *) fs_get (n)),s,*size = n);
453 /* get more data from the net */
454 if (!ssl_getdata (stream)) fs_give ((void **) &ret);
455 /* special case of newline broken by buffer */
456 else if ((c == '\015') && (*stream->iptr == '\012')) {
457 stream->iptr++; /* eat the line feed */
458 stream->ictr--;
459 ret[*size = --n] = '\0'; /* tie off string with null */
460 }
461 else *contd = LONGT; /* continuation needed */
462 return ret;
463 }
465 /* SSL receive buffer
466 * Accepts: SSL stream
467 * size in bytes
468 * buffer to read into
469 * Returns: T if success, NIL otherwise
470 */
472 long ssl_getbuffer (SSLSTREAM *stream,unsigned long size,char *buffer)
473 {
474 unsigned long n;
475 while (size > 0) { /* until request satisfied */
476 if (!ssl_getdata (stream)) return NIL;
477 n = min (size,stream->ictr);/* number of bytes to transfer */
478 /* do the copy */
479 memcpy (buffer,stream->iptr,n);
480 buffer += n; /* update pointer */
481 stream->iptr += n;
482 size -= n; /* update # of bytes to do */
483 stream->ictr -= n;
484 }
485 buffer[0] = '\0'; /* tie off string */
486 return T;
487 }
489 /* SSL receive data
490 * Accepts: TCP/IP stream
491 * Returns: T if success, NIL otherwise
492 */
494 long ssl_getdata (SSLSTREAM *stream)
495 {
496 while (stream->ictr < 1) { /* decrypted buffer empty? */
497 SECURITY_STATUS status;
498 SecBuffer buf[4];
499 SecBufferDesc msg;
500 size_t i;
501 size_t n = 0; /* initially no bytes to decrypt */
502 do { /* yes, make sure have data from TCP */
503 if (stream->iextractr) { /* have previous unread data? */
504 memcpy (stream->ibuf + n,stream->iextraptr,stream->iextractr);
505 n += stream->iextractr; /* update number of bytes read */
506 stream->iextractr = 0; /* no more extra data */
507 }
508 else { /* read from TCP */
509 if (!tcp_getdata (stream->tcpstream)) return ssl_abort (stream);
510 /* maximum amount of data to copy */
511 if (!(i = min (stream->bufsize - n,stream->tcpstream->ictr)))
512 fatal ("incomplete SecBuffer exceeds maximum buffer size");
513 /* do the copy */
514 memcpy (stream->ibuf + n,stream->tcpstream->iptr,i);
515 stream->tcpstream->iptr += i;
516 stream->tcpstream->ictr -= i;
517 n += i; /* update number of bytes to decrypt */
518 }
519 buf[0].cbBuffer = n; /* first SecBuffer gets data */
520 buf[0].pvBuffer = stream->ibuf;
521 buf[0].BufferType = SECBUFFER_DATA;
522 /* subsequent ones are for spares */
523 buf[1].BufferType = buf[2].BufferType = buf[3].BufferType =
524 SECBUFFER_EMPTY;
525 msg.ulVersion = SECBUFFER_VERSION;
526 msg.cBuffers = 4; /* number of SecBuffers */
527 msg.pBuffers = buf; /* first SecBuffer */
528 } while ((status = DecryptMessage
529 (&stream->context,&msg,0,NIL)) == SEC_E_INCOMPLETE_MESSAGE);
530 switch (status) {
531 case SEC_E_OK: /* won */
532 case SEC_I_RENEGOTIATE: /* won but lost it after this buffer */
533 /* hunt for a buffer */
534 for (i = 0; (i < 4) && (buf[i].BufferType != SECBUFFER_DATA) ; i++);
535 if (i < 4) { /* found a buffer? */
536 /* yes, set up pointer and counter */
537 stream->iptr = buf[i].pvBuffer;
538 stream->ictr = buf[i].cbBuffer;
539 /* any unprocessed data? */
540 while (++i < 4) if (buf[i].BufferType == SECBUFFER_EXTRA) {
541 /* yes, note for next time around */
542 stream->iextraptr = buf[i].pvBuffer;
543 stream->iextractr = buf[i].cbBuffer;
544 }
545 }
546 break;
547 default: /* anything else means we've lost */
548 return ssl_abort (stream);
549 }
550 }
551 return LONGT;
552 }
554 /* SSL send string as record
555 * Accepts: SSL stream
556 * string pointer
557 * Returns: T if success else NIL
558 */
560 long ssl_soutr (SSLSTREAM *stream,char *string)
561 {
562 return ssl_sout (stream,string,(unsigned long) strlen (string));
563 }
566 /* SSL send string
567 * Accepts: SSL stream
568 * string pointer
569 * byte count
570 * Returns: T if success else NIL
571 */
573 long ssl_sout (SSLSTREAM *stream,char *string,unsigned long size)
574 {
575 SecBuffer buf[4];
576 SecBufferDesc msg;
577 char *s;
578 size_t n;
579 if (!stream->tcpstream) return NIL;
580 /* until request satisfied */
581 for (s = stream->ibuf,n = 0; size;) {
582 /* header */
583 buf[0].BufferType = SECBUFFER_STREAM_HEADER;
584 memset (buf[0].pvBuffer = stream->obuf,0,
585 buf[0].cbBuffer = stream->sizes.cbHeader);
586 /* message (up to maximum size) */
587 buf[1].BufferType = SECBUFFER_DATA;
588 memcpy (buf[1].pvBuffer = stream->obuf + stream->sizes.cbHeader,string,
589 buf[1].cbBuffer = min (size,SSLBUFLEN));
590 /* trailer */
591 buf[2].BufferType = SECBUFFER_STREAM_TRAILER;
592 memset (buf[2].pvBuffer = ((char *) buf[1].pvBuffer) + buf[1].cbBuffer,0,
593 buf[2].cbBuffer = stream->sizes.cbTrailer);
594 /* spare */
595 buf[3].BufferType = SECBUFFER_EMPTY;
596 msg.ulVersion = SECBUFFER_VERSION;
597 msg.cBuffers = 4; /* number of SecBuffers */
598 msg.pBuffers = buf; /* first SecBuffer */
599 string += buf[1].cbBuffer;
600 size -= buf[1].cbBuffer; /* this many bytes processed */
601 /* encrypt and send message */
602 if ((EncryptMessage
603 (&stream->context,0,&msg,NIL) != SEC_E_OK) ||
604 !tcp_sout (stream->tcpstream,stream->obuf,
605 buf[0].cbBuffer + buf[1].cbBuffer + buf[2].cbBuffer))
606 return ssl_abort (stream);/* encryption or sending failed */
607 }
608 return LONGT;
609 }
611 /* SSL close
612 * Accepts: SSL stream
613 */
615 void ssl_close (SSLSTREAM *stream)
616 {
617 ssl_abort (stream); /* nuke the stream */
618 fs_give ((void **) &stream); /* flush the stream */
619 }
622 /* SSL abort stream
623 * Accepts: SSL stream
624 * Returns: NIL always
625 */
627 static long ssl_abort (SSLSTREAM *stream)
628 {
629 if (stream->tcpstream) { /* close TCP stream */
630 DeleteSecurityContext (&stream->context);
631 FreeCredentialHandle (&stream->cred);
632 tcp_close (stream->tcpstream);
633 stream->tcpstream = NIL;
634 }
635 if (stream->ibuf) fs_give ((void **) &stream->ibuf);
636 if (stream->obuf) fs_give ((void **) &stream->obuf);
637 return NIL;
638 }
640 /* SSL get host name
641 * Accepts: SSL stream
642 * Returns: host name for this stream
643 */
645 char *ssl_host (SSLSTREAM *stream)
646 {
647 return tcp_host (stream->tcpstream);
648 }
651 /* SSL get remote host name
652 * Accepts: SSL stream
653 * Returns: host name for this stream
654 */
656 char *ssl_remotehost (SSLSTREAM *stream)
657 {
658 return tcp_remotehost (stream->tcpstream);
659 }
662 /* SSL return port for this stream
663 * Accepts: SSL stream
664 * Returns: port number for this stream
665 */
667 unsigned long ssl_port (SSLSTREAM *stream)
668 {
669 return tcp_port (stream->tcpstream);
670 }
673 /* SSL get local host name
674 * Accepts: SSL stream
675 * Returns: local host name
676 */
678 char *ssl_localhost (SSLSTREAM *stream)
679 {
680 return tcp_localhost (stream->tcpstream);
681 }
683 #include "ssl_none.c" /* currently no server support */

UW-IMAP'd extensions by yuuji