xref: /illumos-gate/usr/src/cmd/sendmail/src/sfsasl.c (revision 3db86aab)
1 /*
2  * Copyright (c) 1999-2006 Sendmail, Inc. and its suppliers.
3  *	All rights reserved.
4  *
5  * By using this file, you agree to the terms and conditions set
6  * forth in the LICENSE file which can be found at the top level of
7  * the sendmail distribution.
8  *
9  */
10 
11 #pragma ident	"%Z%%M%	%I%	%E% SMI"
12 
13 #include <sm/gen.h>
14 SM_RCSID("@(#)$Id: sfsasl.c,v 8.115 2006/04/18 21:34:07 ca Exp $")
15 #include <stdlib.h>
16 #include <sendmail.h>
17 #include <sm/time.h>
18 #include <errno.h>
19 
20 /* allow to disable error handling code just in case... */
21 #ifndef DEAL_WITH_ERROR_SSL
22 # define DEAL_WITH_ERROR_SSL	1
23 #endif /* ! DEAL_WITH_ERROR_SSL */
24 
25 #if SASL
26 # include "sfsasl.h"
27 
28 /* Structure used by the "sasl" file type */
29 struct sasl_obj
30 {
31 	SM_FILE_T *fp;
32 	sasl_conn_t *conn;
33 };
34 
35 struct sasl_info
36 {
37 	SM_FILE_T *fp;
38 	sasl_conn_t *conn;
39 };
40 
41 /*
42 **  SASL_GETINFO - returns requested information about a "sasl" file
43 **		  descriptor.
44 **
45 **	Parameters:
46 **		fp -- the file descriptor
47 **		what -- the type of information requested
48 **		valp -- the thang to return the information in
49 **
50 **	Returns:
51 **		-1 for unknown requests
52 **		>=0 on success with valp filled in (if possible).
53 */
54 
55 static int sasl_getinfo __P((SM_FILE_T *, int, void *));
56 
57 static int
58 sasl_getinfo(fp, what, valp)
59 	SM_FILE_T *fp;
60 	int what;
61 	void *valp;
62 {
63 	struct sasl_obj *so = (struct sasl_obj *) fp->f_cookie;
64 
65 	switch (what)
66 	{
67 	  case SM_IO_WHAT_FD:
68 		if (so->fp == NULL)
69 			return -1;
70 		return so->fp->f_file; /* for stdio fileno() compatability */
71 
72 	  case SM_IO_IS_READABLE:
73 		if (so->fp == NULL)
74 			return 0;
75 
76 		/* get info from underlying file */
77 		return sm_io_getinfo(so->fp, what, valp);
78 
79 	  default:
80 		return -1;
81 	}
82 }
83 
84 /*
85 **  SASL_OPEN -- creates the sasl specific information for opening a
86 **		file of the sasl type.
87 **
88 **	Parameters:
89 **		fp -- the file pointer associated with the new open
90 **		info -- contains the sasl connection information pointer and
91 **			the original SM_FILE_T that holds the open
92 **		flags -- ignored
93 **		rpool -- ignored
94 **
95 **	Returns:
96 **		0 on success
97 */
98 
99 static int sasl_open __P((SM_FILE_T *, const void *, int, const void *));
100 
101 /* ARGSUSED2 */
102 static int
103 sasl_open(fp, info, flags, rpool)
104 	SM_FILE_T *fp;
105 	const void *info;
106 	int flags;
107 	const void *rpool;
108 {
109 	struct sasl_obj *so;
110 	struct sasl_info *si = (struct sasl_info *) info;
111 
112 	so = (struct sasl_obj *) sm_malloc(sizeof(struct sasl_obj));
113 	if (so == NULL)
114 	{
115 		errno = ENOMEM;
116 		return -1;
117 	}
118 	so->fp = si->fp;
119 	so->conn = si->conn;
120 
121 	/*
122 	**  The underlying 'fp' is set to SM_IO_NOW so that the entire
123 	**  encoded string is written in one chunk. Otherwise there is
124 	**  the possibility that it may appear illegal, bogus or
125 	**  mangled to the other side of the connection.
126 	**  We will read or write through 'fp' since it is the opaque
127 	**  connection for the communications. We need to treat it this
128 	**  way in case the encoded string is to be sent down a TLS
129 	**  connection rather than, say, sm_io's stdio.
130 	*/
131 
132 	(void) sm_io_setvbuf(so->fp, SM_TIME_DEFAULT, NULL, SM_IO_NOW, 0);
133 	fp->f_cookie = so;
134 	return 0;
135 }
136 
137 /*
138 **  SASL_CLOSE -- close the sasl specific parts of the sasl file pointer
139 **
140 **	Parameters:
141 **		fp -- the file pointer to close
142 **
143 **	Returns:
144 **		0 on success
145 */
146 
147 static int sasl_close __P((SM_FILE_T *));
148 
149 static int
150 sasl_close(fp)
151 	SM_FILE_T *fp;
152 {
153 	struct sasl_obj *so;
154 
155 	so = (struct sasl_obj *) fp->f_cookie;
156 	if (so == NULL)
157 		return 0;
158 	if (so->fp != NULL)
159 	{
160 		sm_io_close(so->fp, SM_TIME_DEFAULT);
161 		so->fp = NULL;
162 	}
163 	sm_free(so);
164 	so = NULL;
165 	return 0;
166 }
167 
168 /* how to deallocate a buffer allocated by SASL */
169 extern void	sm_sasl_free __P((void *));
170 #  define SASL_DEALLOC(b)	sm_sasl_free(b)
171 
172 /*
173 **  SASL_READ -- read encrypted information and decrypt it for the caller
174 **
175 **	Parameters:
176 **		fp -- the file pointer
177 **		buf -- the location to place the decrypted information
178 **		size -- the number of bytes to read after decryption
179 **
180 **	Results:
181 **		-1 on error
182 **		otherwise the number of bytes read
183 */
184 
185 static ssize_t sasl_read __P((SM_FILE_T *, char *, size_t));
186 
187 static ssize_t
188 sasl_read(fp, buf, size)
189 	SM_FILE_T *fp;
190 	char *buf;
191 	size_t size;
192 {
193 	int result;
194 	ssize_t len;
195 # if SASL >= 20000
196 	static const char *outbuf = NULL;
197 # else /* SASL >= 20000 */
198 	static char *outbuf = NULL;
199 # endif /* SASL >= 20000 */
200 	static unsigned int outlen = 0;
201 	static unsigned int offset = 0;
202 	struct sasl_obj *so = (struct sasl_obj *) fp->f_cookie;
203 
204 	/*
205 	**  sasl_decode() may require more data than a single read() returns.
206 	**  Hence we have to put a loop around the decoding.
207 	**  This also requires that we may have to split up the returned
208 	**  data since it might be larger than the allowed size.
209 	**  Therefore we use a static pointer and return portions of it
210 	**  if necessary.
211 	**  XXX Note: This function is not thread-safe nor can it be used
212 	**  on more than one file. A correct implementation would store
213 	**  this data in fp->f_cookie.
214 	*/
215 
216 # if SASL >= 20000
217 	while (outlen == 0)
218 # else /* SASL >= 20000 */
219 	while (outbuf == NULL && outlen == 0)
220 # endif /* SASL >= 20000 */
221 	{
222 		len = sm_io_read(so->fp, SM_TIME_DEFAULT, buf, size);
223 		if (len <= 0)
224 			return len;
225 		result = sasl_decode(so->conn, buf,
226 				     (unsigned int) len, &outbuf, &outlen);
227 		if (result != SASL_OK)
228 		{
229 			if (LogLevel > 7)
230 				sm_syslog(LOG_WARNING, NOQID,
231 					"AUTH: sasl_decode error=%d", result);
232 			outbuf = NULL;
233 			offset = 0;
234 			outlen = 0;
235 			return -1;
236 		}
237 	}
238 
239 	if (outbuf == NULL)
240 	{
241 		/* be paranoid: outbuf == NULL but outlen != 0 */
242 		syserr("@sasl_read failure: outbuf == NULL but outlen != 0");
243 		/* NOTREACHED */
244 	}
245 	if (outlen - offset > size)
246 	{
247 		/* return another part of the buffer */
248 		(void) memcpy(buf, outbuf + offset, size);
249 		offset += size;
250 		len = size;
251 	}
252 	else
253 	{
254 		/* return the rest of the buffer */
255 		len = outlen - offset;
256 		(void) memcpy(buf, outbuf + offset, (size_t) len);
257 # if SASL < 20000
258 		SASL_DEALLOC(outbuf);
259 # endif /* SASL < 20000 */
260 		outbuf = NULL;
261 		offset = 0;
262 		outlen = 0;
263 	}
264 	return len;
265 }
266 
267 /*
268 **  SASL_WRITE -- write information out after encrypting it
269 **
270 **	Parameters:
271 **		fp -- the file pointer
272 **		buf -- holds the data to be encrypted and written
273 **		size -- the number of bytes to have encrypted and written
274 **
275 **	Returns:
276 **		-1 on error
277 **		otherwise number of bytes written
278 */
279 
280 static ssize_t sasl_write __P((SM_FILE_T *, const char *, size_t));
281 
282 static ssize_t
283 sasl_write(fp, buf, size)
284 	SM_FILE_T *fp;
285 	const char *buf;
286 	size_t size;
287 {
288 	int result;
289 # if SASL >= 20000
290 	const char *outbuf;
291 # else /* SASL >= 20000 */
292 	char *outbuf;
293 # endif /* SASL >= 20000 */
294 	unsigned int outlen, *maxencode;
295 	size_t ret = 0, total = 0;
296 	struct sasl_obj *so = (struct sasl_obj *) fp->f_cookie;
297 
298 	/*
299 	**  Fetch the maximum input buffer size for sasl_encode().
300 	**  This can be less than the size set in attemptauth()
301 	**  due to a negotation with the other side, e.g.,
302 	**  Cyrus IMAP lmtp program sets maxbuf=4096,
303 	**  digestmd5 substracts 25 and hence we'll get 4071
304 	**  instead of 8192 (MAXOUTLEN).
305 	**  Hack (for now): simply reduce the size, callers are (must be)
306 	**  able to deal with that and invoke sasl_write() again with
307 	**  the rest of the data.
308 	**  Note: it would be better to store this value in the context
309 	**  after the negotiation.
310 	*/
311 
312 	result = sasl_getprop(so->conn, SASL_MAXOUTBUF,
313 				(const void **) &maxencode);
314 	if (result == SASL_OK && size > *maxencode && *maxencode > 0)
315 		size = *maxencode;
316 
317 	result = sasl_encode(so->conn, buf,
318 			     (unsigned int) size, &outbuf, &outlen);
319 
320 	if (result != SASL_OK)
321 	{
322 		if (LogLevel > 7)
323 			sm_syslog(LOG_WARNING, NOQID,
324 				"AUTH: sasl_encode error=%d", result);
325 		return -1;
326 	}
327 
328 	if (outbuf != NULL)
329 	{
330 		while (outlen > 0)
331 		{
332 			errno = 0;
333 			/* XXX result == 0? */
334 			ret = sm_io_write(so->fp, SM_TIME_DEFAULT,
335 					  &outbuf[total], outlen);
336 			if (ret <= 0)
337 				return ret;
338 			outlen -= ret;
339 			total += ret;
340 		}
341 # if SASL < 20000
342 		SASL_DEALLOC(outbuf);
343 # endif /* SASL < 20000 */
344 	}
345 	return size;
346 }
347 
348 /*
349 **  SFDCSASL -- create sasl file type and open in and out file pointers
350 **	       for sendmail to read from and write to.
351 **
352 **	Parameters:
353 **		fin -- the sm_io file encrypted data to be read from
354 **		fout -- the sm_io file encrypted data to be written to
355 **		conn -- the sasl connection pointer
356 **		tmo -- timeout
357 **
358 **	Returns:
359 **		-1 on error
360 **		0 on success
361 **
362 **	Side effects:
363 **		The arguments "fin" and "fout" are replaced with the new
364 **		SM_FILE_T pointers.
365 */
366 
367 int
368 sfdcsasl(fin, fout, conn, tmo)
369 	SM_FILE_T **fin;
370 	SM_FILE_T **fout;
371 	sasl_conn_t *conn;
372 	int tmo;
373 {
374 	SM_FILE_T *newin, *newout;
375 	SM_FILE_T  SM_IO_SET_TYPE(sasl_vector, "sasl", sasl_open, sasl_close,
376 		sasl_read, sasl_write, NULL, sasl_getinfo, NULL,
377 		SM_TIME_DEFAULT);
378 	struct sasl_info info;
379 
380 	if (conn == NULL)
381 	{
382 		/* no need to do anything */
383 		return 0;
384 	}
385 
386 	SM_IO_INIT_TYPE(sasl_vector, "sasl", sasl_open, sasl_close,
387 		sasl_read, sasl_write, NULL, sasl_getinfo, NULL,
388 		SM_TIME_DEFAULT);
389 	info.fp = *fin;
390 	info.conn = conn;
391 	newin = sm_io_open(&sasl_vector, SM_TIME_DEFAULT, &info,
392 			SM_IO_RDONLY_B, NULL);
393 
394 	if (newin == NULL)
395 		return -1;
396 
397 	info.fp = *fout;
398 	info.conn = conn;
399 	newout = sm_io_open(&sasl_vector, SM_TIME_DEFAULT, &info,
400 			SM_IO_WRONLY_B, NULL);
401 
402 	if (newout == NULL)
403 	{
404 		(void) sm_io_close(newin, SM_TIME_DEFAULT);
405 		return -1;
406 	}
407 	sm_io_automode(newin, newout);
408 
409 	sm_io_setinfo(*fin, SM_IO_WHAT_TIMEOUT, &tmo);
410 	sm_io_setinfo(*fout, SM_IO_WHAT_TIMEOUT, &tmo);
411 
412 	*fin = newin;
413 	*fout = newout;
414 	return 0;
415 }
416 #endif /* SASL */
417 
418 #if STARTTLS
419 # include "sfsasl.h"
420 #  include <openssl/err.h>
421 
422 /* Structure used by the "tls" file type */
423 struct tls_obj
424 {
425 	SM_FILE_T *fp;
426 	SSL *con;
427 };
428 
429 struct tls_info
430 {
431 	SM_FILE_T *fp;
432 	SSL *con;
433 };
434 
435 /*
436 **  TLS_GETINFO - returns requested information about a "tls" file
437 **		 descriptor.
438 **
439 **	Parameters:
440 **		fp -- the file descriptor
441 **		what -- the type of information requested
442 **		valp -- the thang to return the information in (unused)
443 **
444 **	Returns:
445 **		-1 for unknown requests
446 **		>=0 on success with valp filled in (if possible).
447 */
448 
449 static int tls_getinfo __P((SM_FILE_T *, int, void *));
450 
451 /* ARGSUSED2 */
452 static int
453 tls_getinfo(fp, what, valp)
454 	SM_FILE_T *fp;
455 	int what;
456 	void *valp;
457 {
458 	struct tls_obj *so = (struct tls_obj *) fp->f_cookie;
459 
460 	switch (what)
461 	{
462 	  case SM_IO_WHAT_FD:
463 		if (so->fp == NULL)
464 			return -1;
465 		return so->fp->f_file; /* for stdio fileno() compatability */
466 
467 	  case SM_IO_IS_READABLE:
468 		return SSL_pending(so->con) > 0;
469 
470 	  default:
471 		return -1;
472 	}
473 }
474 
475 /*
476 **  TLS_OPEN -- creates the tls specific information for opening a
477 **	       file of the tls type.
478 **
479 **	Parameters:
480 **		fp -- the file pointer associated with the new open
481 **		info -- the sm_io file pointer holding the open and the
482 **			TLS encryption connection to be read from or written to
483 **		flags -- ignored
484 **		rpool -- ignored
485 **
486 **	Returns:
487 **		0 on success
488 */
489 
490 static int tls_open __P((SM_FILE_T *, const void *, int, const void *));
491 
492 /* ARGSUSED2 */
493 static int
494 tls_open(fp, info, flags, rpool)
495 	SM_FILE_T *fp;
496 	const void *info;
497 	int flags;
498 	const void *rpool;
499 {
500 	struct tls_obj *so;
501 	struct tls_info *ti = (struct tls_info *) info;
502 
503 	so = (struct tls_obj *) sm_malloc(sizeof(struct tls_obj));
504 	if (so == NULL)
505 	{
506 		errno = ENOMEM;
507 		return -1;
508 	}
509 	so->fp = ti->fp;
510 	so->con = ti->con;
511 
512 	/*
513 	**  We try to get the "raw" file descriptor that TLS uses to
514 	**  do the actual read/write with. This is to allow us control
515 	**  over the file descriptor being a blocking or non-blocking type.
516 	**  Under the covers TLS handles the change and this allows us
517 	**  to do timeouts with sm_io.
518 	*/
519 
520 	fp->f_file = sm_io_getinfo(so->fp, SM_IO_WHAT_FD, NULL);
521 	(void) sm_io_setvbuf(so->fp, SM_TIME_DEFAULT, NULL, SM_IO_NOW, 0);
522 	fp->f_cookie = so;
523 	return 0;
524 }
525 
526 /*
527 **  TLS_CLOSE -- close the tls specific parts of the tls file pointer
528 **
529 **	Parameters:
530 **		fp -- the file pointer to close
531 **
532 **	Returns:
533 **		0 on success
534 */
535 
536 static int tls_close __P((SM_FILE_T *));
537 
538 static int
539 tls_close(fp)
540 	SM_FILE_T *fp;
541 {
542 	struct tls_obj *so;
543 
544 	so = (struct tls_obj *) fp->f_cookie;
545 	if (so == NULL)
546 		return 0;
547 	if (so->fp != NULL)
548 	{
549 		sm_io_close(so->fp, SM_TIME_DEFAULT);
550 		so->fp = NULL;
551 	}
552 	sm_free(so);
553 	so = NULL;
554 	return 0;
555 }
556 
557 /* maximum number of retries for TLS related I/O due to handshakes */
558 # define MAX_TLS_IOS	4
559 
560 /*
561 **  TLS_RETRY -- check whether a failed SSL operation can be retried
562 **
563 **	Parameters:
564 **		ssl -- TLS structure
565 **		rfd -- read fd
566 **		wfd -- write fd
567 **		tlsstart -- start time of TLS operation
568 **		timeout -- timeout for TLS operation
569 **		err -- SSL error
570 **		where -- description of operation
571 **
572 **	Results:
573 **		>0 on success
574 **		0 on timeout
575 **		<0 on error
576 */
577 
578 int
579 tls_retry(ssl, rfd, wfd, tlsstart, timeout, err, where)
580 	SSL *ssl;
581 	int rfd;
582 	int wfd;
583 	time_t tlsstart;
584 	int timeout;
585 	int err;
586 	const char *where;
587 {
588 	int ret;
589 	time_t left;
590 	time_t now = curtime();
591 	struct timeval tv;
592 
593 	ret = -1;
594 
595 	/*
596 	**  For SSL_ERROR_WANT_{READ,WRITE}:
597 	**  There is not a complete SSL record available yet
598 	**  or there is only a partial SSL record removed from
599 	**  the network (socket) buffer into the SSL buffer.
600 	**  The SSL_connect will only succeed when a full
601 	**  SSL record is available (assuming a "real" error
602 	**  doesn't happen). To handle when a "real" error
603 	**  does happen the select is set for exceptions too.
604 	**  The connection may be re-negotiated during this time
605 	**  so both read and write "want errors" need to be handled.
606 	**  A select() exception loops back so that a proper SSL
607 	**  error message can be gotten.
608 	*/
609 
610 	left = timeout - (now - tlsstart);
611 	if (left <= 0)
612 		return 0;	/* timeout */
613 	tv.tv_sec = left;
614 	tv.tv_usec = 0;
615 
616 	if (LogLevel > 14)
617 	{
618 		sm_syslog(LOG_INFO, NOQID,
619 			  "STARTTLS=%s, info: fds=%d/%d, err=%d",
620 			  where, rfd, wfd, err);
621 	}
622 
623 	if (FD_SETSIZE > 0 &&
624 	    ((err == SSL_ERROR_WANT_READ && rfd >= FD_SETSIZE) ||
625 	     (err == SSL_ERROR_WANT_WRITE && wfd >= FD_SETSIZE)))
626 	{
627 		if (LogLevel > 5)
628 		{
629 			sm_syslog(LOG_ERR, NOQID,
630 				  "STARTTLS=%s, error: fd %d/%d too large",
631 				  where, rfd, wfd);
632 		if (LogLevel > 8)
633 			tlslogerr(where);
634 		}
635 		errno = EINVAL;
636 	}
637 	else if (err == SSL_ERROR_WANT_READ)
638 	{
639 		fd_set ssl_maskr, ssl_maskx;
640 
641 		FD_ZERO(&ssl_maskr);
642 		FD_SET(rfd, &ssl_maskr);
643 		FD_ZERO(&ssl_maskx);
644 		FD_SET(rfd, &ssl_maskx);
645 		do
646 		{
647 			ret = select(rfd + 1, &ssl_maskr, NULL, &ssl_maskx,
648 					&tv);
649 		} while (ret < 0 && errno == EINTR);
650 		if (ret < 0 && errno > 0)
651 			ret = -errno;
652 	}
653 	else if (err == SSL_ERROR_WANT_WRITE)
654 	{
655 		fd_set ssl_maskw, ssl_maskx;
656 
657 		FD_ZERO(&ssl_maskw);
658 		FD_SET(wfd, &ssl_maskw);
659 		FD_ZERO(&ssl_maskx);
660 		FD_SET(rfd, &ssl_maskx);
661 		do
662 		{
663 			ret = select(wfd + 1, NULL, &ssl_maskw, &ssl_maskx,
664 					&tv);
665 		} while (ret < 0 && errno == EINTR);
666 		if (ret < 0 && errno > 0)
667 			ret = -errno;
668 	}
669 	return ret;
670 }
671 
672 /* errno to force refill() etc to stop (see IS_IO_ERROR()) */
673 #ifdef ETIMEDOUT
674 # define SM_ERR_TIMEOUT	ETIMEDOUT
675 #else /* ETIMEDOUT */
676 # define SM_ERR_TIMEOUT	EIO
677 #endif /* ETIMEDOUT */
678 
679 /*
680 **  TLS_READ -- read secured information for the caller
681 **
682 **	Parameters:
683 **		fp -- the file pointer
684 **		buf -- the location to place the data
685 **		size -- the number of bytes to read from connection
686 **
687 **	Results:
688 **		-1 on error
689 **		otherwise the number of bytes read
690 */
691 
692 static ssize_t tls_read __P((SM_FILE_T *, char *, size_t));
693 
694 static ssize_t
695 tls_read(fp, buf, size)
696 	SM_FILE_T *fp;
697 	char *buf;
698 	size_t size;
699 {
700 	int r, rfd, wfd, try, ssl_err;
701 	struct tls_obj *so = (struct tls_obj *) fp->f_cookie;
702 	time_t tlsstart;
703 	char *err;
704 
705 	try = 99;
706 	err = NULL;
707 	tlsstart = curtime();
708 
709   retry:
710 	r = SSL_read(so->con, (char *) buf, size);
711 
712 	if (r > 0)
713 		return r;
714 
715 	err = NULL;
716 	switch (ssl_err = SSL_get_error(so->con, r))
717 	{
718 	  case SSL_ERROR_NONE:
719 	  case SSL_ERROR_ZERO_RETURN:
720 		break;
721 	  case SSL_ERROR_WANT_WRITE:
722 		err = "read W BLOCK";
723 		/* FALLTHROUGH */
724 	  case SSL_ERROR_WANT_READ:
725 		if (err == NULL)
726 			err = "read R BLOCK";
727 		rfd = SSL_get_rfd(so->con);
728 		wfd = SSL_get_wfd(so->con);
729 		try = tls_retry(so->con, rfd, wfd, tlsstart,
730 				TimeOuts.to_datablock, ssl_err, "read");
731 		if (try > 0)
732 			goto retry;
733 		errno = SM_ERR_TIMEOUT;
734 		break;
735 
736 	  case SSL_ERROR_WANT_X509_LOOKUP:
737 		err = "write X BLOCK";
738 		break;
739 	  case SSL_ERROR_SYSCALL:
740 		if (r == 0 && errno == 0) /* out of protocol EOF found */
741 			break;
742 		err = "syscall error";
743 /*
744 		get_last_socket_error());
745 */
746 		break;
747 	  case SSL_ERROR_SSL:
748 #if DEAL_WITH_ERROR_SSL
749 		if (r == 0 && errno == 0) /* out of protocol EOF found */
750 			break;
751 #endif /* DEAL_WITH_ERROR_SSL */
752 		err = "generic SSL error";
753 		if (LogLevel > 9)
754 			tlslogerr("read");
755 
756 #if DEAL_WITH_ERROR_SSL
757 		/* avoid repeated calls? */
758 		if (r == 0)
759 			r = -1;
760 #endif /* DEAL_WITH_ERROR_SSL */
761 		break;
762 	}
763 	if (err != NULL)
764 	{
765 		int save_errno;
766 
767 		save_errno = (errno == 0) ? EIO : errno;
768 		if (try == 0 && save_errno == SM_ERR_TIMEOUT)
769 		{
770 			if (LogLevel > 7)
771 				sm_syslog(LOG_WARNING, NOQID,
772 					  "STARTTLS: read error=timeout");
773 		}
774 		else if (LogLevel > 8)
775 			sm_syslog(LOG_WARNING, NOQID,
776 				  "STARTTLS: read error=%s (%d), errno=%d, get_error=%s, retry=%d, ssl_err=%d",
777 				  err, r, errno,
778 				  ERR_error_string(ERR_get_error(), NULL), try,
779 				  ssl_err);
780 		else if (LogLevel > 7)
781 			sm_syslog(LOG_WARNING, NOQID,
782 				  "STARTTLS: read error=%s (%d), retry=%d, ssl_err=%d",
783 				  err, r, errno, try, ssl_err);
784 		errno = save_errno;
785 	}
786 	return r;
787 }
788 
789 /*
790 **  TLS_WRITE -- write information out through secure connection
791 **
792 **	Parameters:
793 **		fp -- the file pointer
794 **		buf -- holds the data to be securely written
795 **		size -- the number of bytes to write
796 **
797 **	Returns:
798 **		-1 on error
799 **		otherwise number of bytes written
800 */
801 
802 static ssize_t tls_write __P((SM_FILE_T *, const char *, size_t));
803 
804 static ssize_t
805 tls_write(fp, buf, size)
806 	SM_FILE_T *fp;
807 	const char *buf;
808 	size_t size;
809 {
810 	int r, rfd, wfd, try, ssl_err;
811 	struct tls_obj *so = (struct tls_obj *) fp->f_cookie;
812 	time_t tlsstart;
813 	char *err;
814 
815 	try = 99;
816 	err = NULL;
817 	tlsstart = curtime();
818 
819   retry:
820 	r = SSL_write(so->con, (char *) buf, size);
821 
822 	if (r > 0)
823 		return r;
824 	err = NULL;
825 	switch (ssl_err = SSL_get_error(so->con, r))
826 	{
827 	  case SSL_ERROR_NONE:
828 	  case SSL_ERROR_ZERO_RETURN:
829 		break;
830 	  case SSL_ERROR_WANT_WRITE:
831 		err = "read W BLOCK";
832 		/* FALLTHROUGH */
833 	  case SSL_ERROR_WANT_READ:
834 		if (err == NULL)
835 			err = "read R BLOCK";
836 		rfd = SSL_get_rfd(so->con);
837 		wfd = SSL_get_wfd(so->con);
838 		try = tls_retry(so->con, rfd, wfd, tlsstart,
839 				DATA_PROGRESS_TIMEOUT, ssl_err, "write");
840 		if (try > 0)
841 			goto retry;
842 		errno = SM_ERR_TIMEOUT;
843 		break;
844 	  case SSL_ERROR_WANT_X509_LOOKUP:
845 		err = "write X BLOCK";
846 		break;
847 	  case SSL_ERROR_SYSCALL:
848 		if (r == 0 && errno == 0) /* out of protocol EOF found */
849 			break;
850 		err = "syscall error";
851 /*
852 		get_last_socket_error());
853 */
854 		break;
855 	  case SSL_ERROR_SSL:
856 		err = "generic SSL error";
857 /*
858 		ERR_GET_REASON(ERR_peek_error()));
859 */
860 		if (LogLevel > 9)
861 			tlslogerr("write");
862 
863 #if DEAL_WITH_ERROR_SSL
864 		/* avoid repeated calls? */
865 		if (r == 0)
866 			r = -1;
867 #endif /* DEAL_WITH_ERROR_SSL */
868 		break;
869 	}
870 	if (err != NULL)
871 	{
872 		int save_errno;
873 
874 		save_errno = (errno == 0) ? EIO : errno;
875 		if (try == 0 && save_errno == SM_ERR_TIMEOUT)
876 		{
877 			if (LogLevel > 7)
878 				sm_syslog(LOG_WARNING, NOQID,
879 					  "STARTTLS: write error=timeout");
880 		}
881 		else if (LogLevel > 8)
882 			sm_syslog(LOG_WARNING, NOQID,
883 				  "STARTTLS: write error=%s (%d), errno=%d, get_error=%s, retry=%d, ssl_err=%d",
884 				  err, r, errno,
885 				  ERR_error_string(ERR_get_error(), NULL), try,
886 				  ssl_err);
887 		else if (LogLevel > 7)
888 			sm_syslog(LOG_WARNING, NOQID,
889 				  "STARTTLS: write error=%s (%d), errno=%d, retry=%d, ssl_err=%d",
890 				  err, r, errno, try, ssl_err);
891 		errno = save_errno;
892 	}
893 	return r;
894 }
895 
896 /*
897 **  SFDCTLS -- create tls file type and open in and out file pointers
898 **	      for sendmail to read from and write to.
899 **
900 **	Parameters:
901 **		fin -- data input source being replaced
902 **		fout -- data output source being replaced
903 **		con -- the tls connection pointer
904 **
905 **	Returns:
906 **		-1 on error
907 **		0 on success
908 **
909 **	Side effects:
910 **		The arguments "fin" and "fout" are replaced with the new
911 **		SM_FILE_T pointers.
912 **		The original "fin" and "fout" are preserved in the tls file
913 **		type but are not actually used because of the design of TLS.
914 */
915 
916 int
917 sfdctls(fin, fout, con)
918 	SM_FILE_T **fin;
919 	SM_FILE_T **fout;
920 	SSL *con;
921 {
922 	SM_FILE_T *tlsin, *tlsout;
923 	SM_FILE_T SM_IO_SET_TYPE(tls_vector, "tls", tls_open, tls_close,
924 		tls_read, tls_write, NULL, tls_getinfo, NULL,
925 		SM_TIME_FOREVER);
926 	struct tls_info info;
927 
928 	SM_ASSERT(con != NULL);
929 
930 	SM_IO_INIT_TYPE(tls_vector, "tls", tls_open, tls_close,
931 		tls_read, tls_write, NULL, tls_getinfo, NULL,
932 		SM_TIME_FOREVER);
933 	info.fp = *fin;
934 	info.con = con;
935 	tlsin = sm_io_open(&tls_vector, SM_TIME_DEFAULT, &info, SM_IO_RDONLY_B,
936 			   NULL);
937 	if (tlsin == NULL)
938 		return -1;
939 
940 	info.fp = *fout;
941 	tlsout = sm_io_open(&tls_vector, SM_TIME_DEFAULT, &info, SM_IO_WRONLY_B,
942 			    NULL);
943 	if (tlsout == NULL)
944 	{
945 		(void) sm_io_close(tlsin, SM_TIME_DEFAULT);
946 		return -1;
947 	}
948 	sm_io_automode(tlsin, tlsout);
949 
950 	*fin = tlsin;
951 	*fout = tlsout;
952 	return 0;
953 }
954 #endif /* STARTTLS */
955