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