xref: /freebsd/contrib/sendmail/src/sfsasl.c (revision 13bd19636bde9fea5821698cb77c32edee6a9ac9)
106f25ae9SGregory Neil Shapiro /*
2605302a5SGregory Neil Shapiro  * Copyright (c) 1999-2002 Sendmail, Inc. and its suppliers.
306f25ae9SGregory Neil Shapiro  *	All rights reserved.
406f25ae9SGregory Neil Shapiro  *
506f25ae9SGregory Neil Shapiro  * By using this file, you agree to the terms and conditions set
606f25ae9SGregory Neil Shapiro  * forth in the LICENSE file which can be found at the top level of
706f25ae9SGregory Neil Shapiro  * the sendmail distribution.
806f25ae9SGregory Neil Shapiro  *
906f25ae9SGregory Neil Shapiro  */
1006f25ae9SGregory Neil Shapiro 
1140266059SGregory Neil Shapiro #include <sm/gen.h>
1213bd1963SGregory Neil Shapiro SM_RCSID("@(#)$Id: sfsasl.c,v 8.91.2.2 2002/09/12 21:07:50 ca Exp $")
1306f25ae9SGregory Neil Shapiro #include <stdlib.h>
1406f25ae9SGregory Neil Shapiro #include <sendmail.h>
1540266059SGregory Neil Shapiro #include <errno.h>
1640266059SGregory Neil Shapiro #if SASL
1706f25ae9SGregory Neil Shapiro # include "sfsasl.h"
1806f25ae9SGregory Neil Shapiro 
1940266059SGregory Neil Shapiro /* Structure used by the "sasl" file type */
2040266059SGregory Neil Shapiro struct sasl_obj
2140266059SGregory Neil Shapiro {
2240266059SGregory Neil Shapiro 	SM_FILE_T *fp;
2340266059SGregory Neil Shapiro 	sasl_conn_t *conn;
2440266059SGregory Neil Shapiro };
2540266059SGregory Neil Shapiro 
2640266059SGregory Neil Shapiro struct sasl_info
2740266059SGregory Neil Shapiro {
2840266059SGregory Neil Shapiro 	SM_FILE_T *fp;
2940266059SGregory Neil Shapiro 	sasl_conn_t *conn;
3040266059SGregory Neil Shapiro };
3140266059SGregory Neil Shapiro 
3240266059SGregory Neil Shapiro /*
3340266059SGregory Neil Shapiro **  SASL_GETINFO - returns requested information about a "sasl" file
3440266059SGregory Neil Shapiro **		  descriptor.
3540266059SGregory Neil Shapiro **
3640266059SGregory Neil Shapiro **	Parameters:
3740266059SGregory Neil Shapiro **		fp -- the file descriptor
3840266059SGregory Neil Shapiro **		what -- the type of information requested
3940266059SGregory Neil Shapiro **		valp -- the thang to return the information in
4040266059SGregory Neil Shapiro **
4140266059SGregory Neil Shapiro **	Returns:
4240266059SGregory Neil Shapiro **		-1 for unknown requests
4340266059SGregory Neil Shapiro **		>=0 on success with valp filled in (if possible).
4440266059SGregory Neil Shapiro */
4540266059SGregory Neil Shapiro 
4640266059SGregory Neil Shapiro static int sasl_getinfo __P((SM_FILE_T *, int, void *));
4740266059SGregory Neil Shapiro 
4840266059SGregory Neil Shapiro static int
4940266059SGregory Neil Shapiro sasl_getinfo(fp, what, valp)
5040266059SGregory Neil Shapiro 	SM_FILE_T *fp;
5140266059SGregory Neil Shapiro 	int what;
5240266059SGregory Neil Shapiro 	void *valp;
5340266059SGregory Neil Shapiro {
5440266059SGregory Neil Shapiro 	struct sasl_obj *so = (struct sasl_obj *) fp->f_cookie;
5540266059SGregory Neil Shapiro 
5640266059SGregory Neil Shapiro 	switch (what)
5740266059SGregory Neil Shapiro 	{
5840266059SGregory Neil Shapiro 	  case SM_IO_WHAT_FD:
5940266059SGregory Neil Shapiro 		if (so->fp == NULL)
6040266059SGregory Neil Shapiro 			return -1;
6140266059SGregory Neil Shapiro 		return so->fp->f_file; /* for stdio fileno() compatability */
6240266059SGregory Neil Shapiro 
6340266059SGregory Neil Shapiro 	  case SM_IO_IS_READABLE:
6440266059SGregory Neil Shapiro 		if (so->fp == NULL)
6540266059SGregory Neil Shapiro 			return 0;
6640266059SGregory Neil Shapiro 
6740266059SGregory Neil Shapiro 		/* get info from underlying file */
6840266059SGregory Neil Shapiro 		return sm_io_getinfo(so->fp, what, valp);
6940266059SGregory Neil Shapiro 
7040266059SGregory Neil Shapiro 	  default:
7140266059SGregory Neil Shapiro 		return -1;
7240266059SGregory Neil Shapiro 	}
7340266059SGregory Neil Shapiro }
7440266059SGregory Neil Shapiro 
7540266059SGregory Neil Shapiro /*
7640266059SGregory Neil Shapiro **  SASL_OPEN -- creates the sasl specific information for opening a
7740266059SGregory Neil Shapiro **		file of the sasl type.
7840266059SGregory Neil Shapiro **
7940266059SGregory Neil Shapiro **	Parameters:
8040266059SGregory Neil Shapiro **		fp -- the file pointer associated with the new open
8140266059SGregory Neil Shapiro **		info -- contains the sasl connection information pointer and
8240266059SGregory Neil Shapiro **			the original SM_FILE_T that holds the open
8340266059SGregory Neil Shapiro **		flags -- ignored
8440266059SGregory Neil Shapiro **		rpool -- ignored
8540266059SGregory Neil Shapiro **
8640266059SGregory Neil Shapiro **	Returns:
8740266059SGregory Neil Shapiro **		0 on success
8840266059SGregory Neil Shapiro */
8940266059SGregory Neil Shapiro 
9040266059SGregory Neil Shapiro static int sasl_open __P((SM_FILE_T *, const void *, int, const void *));
9140266059SGregory Neil Shapiro 
9240266059SGregory Neil Shapiro /* ARGSUSED2 */
9340266059SGregory Neil Shapiro static int
9440266059SGregory Neil Shapiro sasl_open(fp, info, flags, rpool)
9540266059SGregory Neil Shapiro 	SM_FILE_T *fp;
9640266059SGregory Neil Shapiro 	const void *info;
9740266059SGregory Neil Shapiro 	int flags;
9840266059SGregory Neil Shapiro 	const void *rpool;
9940266059SGregory Neil Shapiro {
10040266059SGregory Neil Shapiro 	struct sasl_obj *so;
10140266059SGregory Neil Shapiro 	struct sasl_info *si = (struct sasl_info *) info;
10240266059SGregory Neil Shapiro 
10340266059SGregory Neil Shapiro 	so = (struct sasl_obj *) sm_malloc(sizeof(struct sasl_obj));
10440266059SGregory Neil Shapiro 	so->fp = si->fp;
10540266059SGregory Neil Shapiro 	so->conn = si->conn;
10640266059SGregory Neil Shapiro 
10740266059SGregory Neil Shapiro 	/*
10840266059SGregory Neil Shapiro 	**  The underlying 'fp' is set to SM_IO_NOW so that the entire
10940266059SGregory Neil Shapiro 	**  encoded string is written in one chunk. Otherwise there is
11040266059SGregory Neil Shapiro 	**  the possibility that it may appear illegal, bogus or
11140266059SGregory Neil Shapiro 	**  mangled to the other side of the connection.
11240266059SGregory Neil Shapiro 	**  We will read or write through 'fp' since it is the opaque
11340266059SGregory Neil Shapiro 	**  connection for the communications. We need to treat it this
11440266059SGregory Neil Shapiro 	**  way in case the encoded string is to be sent down a TLS
11540266059SGregory Neil Shapiro 	**  connection rather than, say, sm_io's stdio.
11640266059SGregory Neil Shapiro 	*/
11740266059SGregory Neil Shapiro 
11840266059SGregory Neil Shapiro 	(void) sm_io_setvbuf(so->fp, SM_TIME_DEFAULT, NULL, SM_IO_NOW, 0);
11940266059SGregory Neil Shapiro 	fp->f_cookie = so;
12040266059SGregory Neil Shapiro 	return 0;
12140266059SGregory Neil Shapiro }
12240266059SGregory Neil Shapiro 
12340266059SGregory Neil Shapiro /*
12440266059SGregory Neil Shapiro **  SASL_CLOSE -- close the sasl specific parts of the sasl file pointer
12540266059SGregory Neil Shapiro **
12640266059SGregory Neil Shapiro **	Parameters:
12740266059SGregory Neil Shapiro **		fp -- the file pointer to close
12840266059SGregory Neil Shapiro **
12940266059SGregory Neil Shapiro **	Returns:
13040266059SGregory Neil Shapiro **		0 on success
13140266059SGregory Neil Shapiro */
13240266059SGregory Neil Shapiro 
13340266059SGregory Neil Shapiro static int sasl_close __P((SM_FILE_T *));
13440266059SGregory Neil Shapiro 
13540266059SGregory Neil Shapiro static int
13640266059SGregory Neil Shapiro sasl_close(fp)
13740266059SGregory Neil Shapiro 	SM_FILE_T *fp;
13840266059SGregory Neil Shapiro {
13940266059SGregory Neil Shapiro 	struct sasl_obj *so;
14040266059SGregory Neil Shapiro 
14140266059SGregory Neil Shapiro 	so = (struct sasl_obj *) fp->f_cookie;
14240266059SGregory Neil Shapiro 	if (so->fp != NULL)
14340266059SGregory Neil Shapiro 	{
14440266059SGregory Neil Shapiro 		sm_io_close(so->fp, SM_TIME_DEFAULT);
14540266059SGregory Neil Shapiro 		so->fp = NULL;
14640266059SGregory Neil Shapiro 	}
14740266059SGregory Neil Shapiro 	sm_free(so);
14840266059SGregory Neil Shapiro 	so = NULL;
14940266059SGregory Neil Shapiro 	return 0;
15040266059SGregory Neil Shapiro }
15140266059SGregory Neil Shapiro 
152193538b7SGregory Neil Shapiro /* how to deallocate a buffer allocated by SASL */
15340266059SGregory Neil Shapiro extern void	sm_sasl_free __P((void *));
15440266059SGregory Neil Shapiro #  define SASL_DEALLOC(b)	sm_sasl_free(b)
15540266059SGregory Neil Shapiro 
15640266059SGregory Neil Shapiro /*
15740266059SGregory Neil Shapiro **  SASL_READ -- read encrypted information and decrypt it for the caller
15840266059SGregory Neil Shapiro **
15940266059SGregory Neil Shapiro **	Parameters:
16040266059SGregory Neil Shapiro **		fp -- the file pointer
16140266059SGregory Neil Shapiro **		buf -- the location to place the decrypted information
16240266059SGregory Neil Shapiro **		size -- the number of bytes to read after decryption
16340266059SGregory Neil Shapiro **
16440266059SGregory Neil Shapiro **	Results:
16540266059SGregory Neil Shapiro **		-1 on error
16640266059SGregory Neil Shapiro **		otherwise the number of bytes read
16740266059SGregory Neil Shapiro */
16840266059SGregory Neil Shapiro 
16940266059SGregory Neil Shapiro static ssize_t sasl_read __P((SM_FILE_T *, char *, size_t));
170193538b7SGregory Neil Shapiro 
17106f25ae9SGregory Neil Shapiro static ssize_t
17240266059SGregory Neil Shapiro sasl_read(fp, buf, size)
17340266059SGregory Neil Shapiro 	SM_FILE_T *fp;
17440266059SGregory Neil Shapiro 	char *buf;
17506f25ae9SGregory Neil Shapiro 	size_t size;
17606f25ae9SGregory Neil Shapiro {
17740266059SGregory Neil Shapiro 	int result;
17840266059SGregory Neil Shapiro 	ssize_t len;
17994c01205SGregory Neil Shapiro # if SASL >= 20000
18013bd1963SGregory Neil Shapiro 	static const char *outbuf = NULL;
18194c01205SGregory Neil Shapiro # else /* SASL >= 20000 */
182193538b7SGregory Neil Shapiro 	static char *outbuf = NULL;
18394c01205SGregory Neil Shapiro # endif /* SASL >= 20000 */
184193538b7SGregory Neil Shapiro 	static unsigned int outlen = 0;
185193538b7SGregory Neil Shapiro 	static unsigned int offset = 0;
18640266059SGregory Neil Shapiro 	struct sasl_obj *so = (struct sasl_obj *) fp->f_cookie;
18706f25ae9SGregory Neil Shapiro 
188193538b7SGregory Neil Shapiro 	/*
189193538b7SGregory Neil Shapiro 	**  sasl_decode() may require more data than a single read() returns.
190193538b7SGregory Neil Shapiro 	**  Hence we have to put a loop around the decoding.
191193538b7SGregory Neil Shapiro 	**  This also requires that we may have to split up the returned
192193538b7SGregory Neil Shapiro 	**  data since it might be larger than the allowed size.
193193538b7SGregory Neil Shapiro 	**  Therefore we use a static pointer and return portions of it
194193538b7SGregory Neil Shapiro 	**  if necessary.
195193538b7SGregory Neil Shapiro 	*/
19606f25ae9SGregory Neil Shapiro 
19713bd1963SGregory Neil Shapiro # if SASL >= 20000
19813bd1963SGregory Neil Shapiro 	while (outlen == 0)
19913bd1963SGregory Neil Shapiro # else /* SASL >= 20000 */
200193538b7SGregory Neil Shapiro 	while (outbuf == NULL && outlen == 0)
20113bd1963SGregory Neil Shapiro # endif /* SASL >= 20000 */
202193538b7SGregory Neil Shapiro 	{
20340266059SGregory Neil Shapiro 		len = sm_io_read(so->fp, SM_TIME_DEFAULT, buf, size);
20406f25ae9SGregory Neil Shapiro 		if (len <= 0)
20506f25ae9SGregory Neil Shapiro 			return len;
20640266059SGregory Neil Shapiro 		result = sasl_decode(so->conn, buf,
20740266059SGregory Neil Shapiro 				     (unsigned int) len, &outbuf, &outlen);
20806f25ae9SGregory Neil Shapiro 		if (result != SASL_OK)
20906f25ae9SGregory Neil Shapiro 		{
210193538b7SGregory Neil Shapiro 			outbuf = NULL;
211193538b7SGregory Neil Shapiro 			offset = 0;
212193538b7SGregory Neil Shapiro 			outlen = 0;
21306f25ae9SGregory Neil Shapiro 			return -1;
21406f25ae9SGregory Neil Shapiro 		}
215193538b7SGregory Neil Shapiro 	}
21606f25ae9SGregory Neil Shapiro 
21740266059SGregory Neil Shapiro 	if (outbuf == NULL)
21806f25ae9SGregory Neil Shapiro 	{
21940266059SGregory Neil Shapiro 		/* be paranoid: outbuf == NULL but outlen != 0 */
22040266059SGregory Neil Shapiro 		syserr("@sasl_read failure: outbuf == NULL but outlen != 0");
22140266059SGregory Neil Shapiro 		/* NOTREACHED */
22240266059SGregory Neil Shapiro 	}
223193538b7SGregory Neil Shapiro 	if (outlen - offset > size)
224193538b7SGregory Neil Shapiro 	{
225193538b7SGregory Neil Shapiro 		/* return another part of the buffer */
22640266059SGregory Neil Shapiro 		(void) memcpy(buf, outbuf + offset, size);
227193538b7SGregory Neil Shapiro 		offset += size;
22840266059SGregory Neil Shapiro 		len = size;
22906f25ae9SGregory Neil Shapiro 	}
230193538b7SGregory Neil Shapiro 	else
231193538b7SGregory Neil Shapiro 	{
232193538b7SGregory Neil Shapiro 		/* return the rest of the buffer */
23340266059SGregory Neil Shapiro 		len = outlen - offset;
23440266059SGregory Neil Shapiro 		(void) memcpy(buf, outbuf + offset, (size_t) len);
23594c01205SGregory Neil Shapiro # if SASL < 20000
236193538b7SGregory Neil Shapiro 		SASL_DEALLOC(outbuf);
23794c01205SGregory Neil Shapiro # endif /* SASL < 20000 */
238193538b7SGregory Neil Shapiro 		outbuf = NULL;
239193538b7SGregory Neil Shapiro 		offset = 0;
240193538b7SGregory Neil Shapiro 		outlen = 0;
241193538b7SGregory Neil Shapiro 	}
24240266059SGregory Neil Shapiro 	return len;
24306f25ae9SGregory Neil Shapiro }
24406f25ae9SGregory Neil Shapiro 
24540266059SGregory Neil Shapiro /*
24640266059SGregory Neil Shapiro **  SASL_WRITE -- write information out after encrypting it
24740266059SGregory Neil Shapiro **
24840266059SGregory Neil Shapiro **	Parameters:
24940266059SGregory Neil Shapiro **		fp -- the file pointer
25040266059SGregory Neil Shapiro **		buf -- holds the data to be encrypted and written
25140266059SGregory Neil Shapiro **		size -- the number of bytes to have encrypted and written
25240266059SGregory Neil Shapiro **
25340266059SGregory Neil Shapiro **	Returns:
25440266059SGregory Neil Shapiro **		-1 on error
25540266059SGregory Neil Shapiro **		otherwise number of bytes written
25640266059SGregory Neil Shapiro */
25740266059SGregory Neil Shapiro 
25840266059SGregory Neil Shapiro static ssize_t sasl_write __P((SM_FILE_T *, const char *, size_t));
25940266059SGregory Neil Shapiro 
26006f25ae9SGregory Neil Shapiro static ssize_t
26140266059SGregory Neil Shapiro sasl_write(fp, buf, size)
26240266059SGregory Neil Shapiro 	SM_FILE_T *fp;
26340266059SGregory Neil Shapiro 	const char *buf;
26406f25ae9SGregory Neil Shapiro 	size_t size;
26506f25ae9SGregory Neil Shapiro {
26606f25ae9SGregory Neil Shapiro 	int result;
26794c01205SGregory Neil Shapiro # if SASL >= 20000
26894c01205SGregory Neil Shapiro 	const char *outbuf;
26994c01205SGregory Neil Shapiro # else /* SASL >= 20000 */
27006f25ae9SGregory Neil Shapiro 	char *outbuf;
27194c01205SGregory Neil Shapiro # endif /* SASL >= 20000 */
27206f25ae9SGregory Neil Shapiro 	unsigned int outlen;
27340266059SGregory Neil Shapiro 	size_t ret = 0, total = 0;
27440266059SGregory Neil Shapiro 	struct sasl_obj *so = (struct sasl_obj *) fp->f_cookie;
27506f25ae9SGregory Neil Shapiro 
27640266059SGregory Neil Shapiro 	result = sasl_encode(so->conn, buf,
27740266059SGregory Neil Shapiro 			     (unsigned int) size, &outbuf, &outlen);
27806f25ae9SGregory Neil Shapiro 
27906f25ae9SGregory Neil Shapiro 	if (result != SASL_OK)
28006f25ae9SGregory Neil Shapiro 		return -1;
28106f25ae9SGregory Neil Shapiro 
28206f25ae9SGregory Neil Shapiro 	if (outbuf != NULL)
28306f25ae9SGregory Neil Shapiro 	{
28440266059SGregory Neil Shapiro 		while (outlen > 0)
28540266059SGregory Neil Shapiro 		{
286605302a5SGregory Neil Shapiro 			/* XXX result == 0? */
28740266059SGregory Neil Shapiro 			ret = sm_io_write(so->fp, SM_TIME_DEFAULT,
28840266059SGregory Neil Shapiro 					  &outbuf[total], outlen);
28940266059SGregory Neil Shapiro 			outlen -= ret;
29040266059SGregory Neil Shapiro 			total += ret;
29140266059SGregory Neil Shapiro 		}
29294c01205SGregory Neil Shapiro # if SASL < 20000
293193538b7SGregory Neil Shapiro 		SASL_DEALLOC(outbuf);
29494c01205SGregory Neil Shapiro # endif /* SASL < 20000 */
29506f25ae9SGregory Neil Shapiro 	}
29606f25ae9SGregory Neil Shapiro 	return size;
29706f25ae9SGregory Neil Shapiro }
29806f25ae9SGregory Neil Shapiro 
29940266059SGregory Neil Shapiro /*
30040266059SGregory Neil Shapiro **  SFDCSASL -- create sasl file type and open in and out file pointers
30140266059SGregory Neil Shapiro **	       for sendmail to read from and write to.
30240266059SGregory Neil Shapiro **
30340266059SGregory Neil Shapiro **	Parameters:
30440266059SGregory Neil Shapiro **		fin -- the sm_io file encrypted data to be read from
30540266059SGregory Neil Shapiro **		fout -- the sm_io file encrypted data to be writen to
30640266059SGregory Neil Shapiro **		conn -- the sasl connection pointer
30740266059SGregory Neil Shapiro **
30840266059SGregory Neil Shapiro **	Returns:
30940266059SGregory Neil Shapiro **		-1 on error
31040266059SGregory Neil Shapiro **		0 on success
31140266059SGregory Neil Shapiro **
31240266059SGregory Neil Shapiro **	Side effects:
31340266059SGregory Neil Shapiro **		The arguments "fin" and "fout" are replaced with the new
31440266059SGregory Neil Shapiro **		SM_FILE_T pointers.
31540266059SGregory Neil Shapiro */
31640266059SGregory Neil Shapiro 
31706f25ae9SGregory Neil Shapiro int
31806f25ae9SGregory Neil Shapiro sfdcsasl(fin, fout, conn)
31940266059SGregory Neil Shapiro 	SM_FILE_T **fin;
32040266059SGregory Neil Shapiro 	SM_FILE_T **fout;
32106f25ae9SGregory Neil Shapiro 	sasl_conn_t *conn;
32206f25ae9SGregory Neil Shapiro {
32340266059SGregory Neil Shapiro 	SM_FILE_T *newin, *newout;
32440266059SGregory Neil Shapiro 	SM_FILE_T  SM_IO_SET_TYPE(sasl_vector, "sasl", sasl_open, sasl_close,
32540266059SGregory Neil Shapiro 		sasl_read, sasl_write, NULL, sasl_getinfo, NULL,
32640266059SGregory Neil Shapiro 		SM_TIME_FOREVER);
32740266059SGregory Neil Shapiro 	struct sasl_info info;
32806f25ae9SGregory Neil Shapiro 
32906f25ae9SGregory Neil Shapiro 	if (conn == NULL)
33006f25ae9SGregory Neil Shapiro 	{
33106f25ae9SGregory Neil Shapiro 		/* no need to do anything */
33206f25ae9SGregory Neil Shapiro 		return 0;
33306f25ae9SGregory Neil Shapiro 	}
33406f25ae9SGregory Neil Shapiro 
33540266059SGregory Neil Shapiro 	SM_IO_INIT_TYPE(sasl_vector, "sasl", sasl_open, sasl_close,
33640266059SGregory Neil Shapiro 		sasl_read, sasl_write, NULL, sasl_getinfo, NULL,
33740266059SGregory Neil Shapiro 		SM_TIME_FOREVER);
33840266059SGregory Neil Shapiro 	info.fp = *fin;
33940266059SGregory Neil Shapiro 	info.conn = conn;
34040266059SGregory Neil Shapiro 	newin = sm_io_open(&sasl_vector, SM_TIME_DEFAULT, &info, SM_IO_RDONLY,
34140266059SGregory Neil Shapiro 			   NULL);
34206f25ae9SGregory Neil Shapiro 
34340266059SGregory Neil Shapiro 	if (newin == NULL)
34440266059SGregory Neil Shapiro 		return -1;
34506f25ae9SGregory Neil Shapiro 
34640266059SGregory Neil Shapiro 	info.fp = *fout;
34740266059SGregory Neil Shapiro 	info.conn = conn;
34840266059SGregory Neil Shapiro 	newout = sm_io_open(&sasl_vector, SM_TIME_DEFAULT, &info, SM_IO_WRONLY,
34940266059SGregory Neil Shapiro 			    NULL);
35006f25ae9SGregory Neil Shapiro 
35140266059SGregory Neil Shapiro 	if (newout == NULL)
35206f25ae9SGregory Neil Shapiro 	{
35340266059SGregory Neil Shapiro 		(void) sm_io_close(newin, SM_TIME_DEFAULT);
35406f25ae9SGregory Neil Shapiro 		return -1;
35506f25ae9SGregory Neil Shapiro 	}
35640266059SGregory Neil Shapiro 	sm_io_automode(newin, newout);
35740266059SGregory Neil Shapiro 
35840266059SGregory Neil Shapiro 	*fin = newin;
35940266059SGregory Neil Shapiro 	*fout = newout;
36006f25ae9SGregory Neil Shapiro 	return 0;
36106f25ae9SGregory Neil Shapiro }
36240266059SGregory Neil Shapiro #endif /* SASL */
36306f25ae9SGregory Neil Shapiro 
36440266059SGregory Neil Shapiro #if STARTTLS
36506f25ae9SGregory Neil Shapiro # include "sfsasl.h"
36606f25ae9SGregory Neil Shapiro #  include <openssl/err.h>
36706f25ae9SGregory Neil Shapiro 
36840266059SGregory Neil Shapiro /* Structure used by the "tls" file type */
36940266059SGregory Neil Shapiro struct tls_obj
37040266059SGregory Neil Shapiro {
37140266059SGregory Neil Shapiro 	SM_FILE_T *fp;
37240266059SGregory Neil Shapiro 	SSL *con;
37340266059SGregory Neil Shapiro };
37440266059SGregory Neil Shapiro 
37540266059SGregory Neil Shapiro struct tls_info
37640266059SGregory Neil Shapiro {
37740266059SGregory Neil Shapiro 	SM_FILE_T *fp;
37840266059SGregory Neil Shapiro 	SSL *con;
37940266059SGregory Neil Shapiro };
38040266059SGregory Neil Shapiro 
38140266059SGregory Neil Shapiro /*
38240266059SGregory Neil Shapiro **  TLS_GETINFO - returns requested information about a "tls" file
38340266059SGregory Neil Shapiro **		 descriptor.
38440266059SGregory Neil Shapiro **
38540266059SGregory Neil Shapiro **	Parameters:
38640266059SGregory Neil Shapiro **		fp -- the file descriptor
38740266059SGregory Neil Shapiro **		what -- the type of information requested
38840266059SGregory Neil Shapiro **		valp -- the thang to return the information in (unused)
38940266059SGregory Neil Shapiro **
39040266059SGregory Neil Shapiro **	Returns:
39140266059SGregory Neil Shapiro **		-1 for unknown requests
39240266059SGregory Neil Shapiro **		>=0 on success with valp filled in (if possible).
39340266059SGregory Neil Shapiro */
39440266059SGregory Neil Shapiro 
39540266059SGregory Neil Shapiro static int tls_getinfo __P((SM_FILE_T *, int, void *));
39640266059SGregory Neil Shapiro 
39740266059SGregory Neil Shapiro /* ARGSUSED2 */
39813058a91SGregory Neil Shapiro static int
39940266059SGregory Neil Shapiro tls_getinfo(fp, what, valp)
40040266059SGregory Neil Shapiro 	SM_FILE_T *fp;
40140266059SGregory Neil Shapiro 	int what;
40240266059SGregory Neil Shapiro 	void *valp;
40340266059SGregory Neil Shapiro {
40440266059SGregory Neil Shapiro 	struct tls_obj *so = (struct tls_obj *) fp->f_cookie;
40540266059SGregory Neil Shapiro 
40640266059SGregory Neil Shapiro 	switch (what)
40740266059SGregory Neil Shapiro 	{
40840266059SGregory Neil Shapiro 	  case SM_IO_WHAT_FD:
40940266059SGregory Neil Shapiro 		if (so->fp == NULL)
41040266059SGregory Neil Shapiro 			return -1;
41140266059SGregory Neil Shapiro 		return so->fp->f_file; /* for stdio fileno() compatability */
41240266059SGregory Neil Shapiro 
41340266059SGregory Neil Shapiro 	  case SM_IO_IS_READABLE:
41440266059SGregory Neil Shapiro 		return SSL_pending(so->con) > 0;
41540266059SGregory Neil Shapiro 
41640266059SGregory Neil Shapiro 	  default:
41740266059SGregory Neil Shapiro 		return -1;
41840266059SGregory Neil Shapiro 	}
41940266059SGregory Neil Shapiro }
42040266059SGregory Neil Shapiro 
42140266059SGregory Neil Shapiro /*
42240266059SGregory Neil Shapiro **  TLS_OPEN -- creates the tls specific information for opening a
42340266059SGregory Neil Shapiro **	       file of the tls type.
42440266059SGregory Neil Shapiro **
42540266059SGregory Neil Shapiro **	Parameters:
42640266059SGregory Neil Shapiro **		fp -- the file pointer associated with the new open
42740266059SGregory Neil Shapiro **		info -- the sm_io file pointer holding the open and the
42840266059SGregory Neil Shapiro **			TLS encryption connection to be read from or written to
42940266059SGregory Neil Shapiro **		flags -- ignored
43040266059SGregory Neil Shapiro **		rpool -- ignored
43140266059SGregory Neil Shapiro **
43240266059SGregory Neil Shapiro **	Returns:
43340266059SGregory Neil Shapiro **		0 on success
43440266059SGregory Neil Shapiro */
43540266059SGregory Neil Shapiro 
43640266059SGregory Neil Shapiro static int tls_open __P((SM_FILE_T *, const void *, int, const void *));
43740266059SGregory Neil Shapiro 
43840266059SGregory Neil Shapiro /* ARGSUSED2 */
43940266059SGregory Neil Shapiro static int
44040266059SGregory Neil Shapiro tls_open(fp, info, flags, rpool)
44140266059SGregory Neil Shapiro 	SM_FILE_T *fp;
44240266059SGregory Neil Shapiro 	const void *info;
44340266059SGregory Neil Shapiro 	int flags;
44440266059SGregory Neil Shapiro 	const void *rpool;
44540266059SGregory Neil Shapiro {
44640266059SGregory Neil Shapiro 	struct tls_obj *so;
44740266059SGregory Neil Shapiro 	struct tls_info *ti = (struct tls_info *) info;
44840266059SGregory Neil Shapiro 
44940266059SGregory Neil Shapiro 	so = (struct tls_obj *) sm_malloc(sizeof(struct tls_obj));
45040266059SGregory Neil Shapiro 	so->fp = ti->fp;
45140266059SGregory Neil Shapiro 	so->con = ti->con;
45240266059SGregory Neil Shapiro 
45340266059SGregory Neil Shapiro 	/*
45440266059SGregory Neil Shapiro 	**  We try to get the "raw" file descriptor that TLS uses to
45540266059SGregory Neil Shapiro 	**  do the actual read/write with. This is to allow us control
45640266059SGregory Neil Shapiro 	**  over the file descriptor being a blocking or non-blocking type.
45740266059SGregory Neil Shapiro 	**  Under the covers TLS handles the change and this allows us
45840266059SGregory Neil Shapiro 	**  to do timeouts with sm_io.
45940266059SGregory Neil Shapiro 	*/
46040266059SGregory Neil Shapiro 
46140266059SGregory Neil Shapiro 	fp->f_file = sm_io_getinfo(so->fp, SM_IO_WHAT_FD, NULL);
46240266059SGregory Neil Shapiro 	(void) sm_io_setvbuf(so->fp, SM_TIME_DEFAULT, NULL, SM_IO_NOW, 0);
46340266059SGregory Neil Shapiro 	fp->f_cookie = so;
46440266059SGregory Neil Shapiro 	return 0;
46540266059SGregory Neil Shapiro }
46640266059SGregory Neil Shapiro 
46740266059SGregory Neil Shapiro /*
46840266059SGregory Neil Shapiro **  TLS_CLOSE -- close the tls specific parts of the tls file pointer
46940266059SGregory Neil Shapiro **
47040266059SGregory Neil Shapiro **	Parameters:
47140266059SGregory Neil Shapiro **		fp -- the file pointer to close
47240266059SGregory Neil Shapiro **
47340266059SGregory Neil Shapiro **	Returns:
47440266059SGregory Neil Shapiro **		0 on success
47540266059SGregory Neil Shapiro */
47640266059SGregory Neil Shapiro 
47740266059SGregory Neil Shapiro static int tls_close __P((SM_FILE_T *));
47840266059SGregory Neil Shapiro 
47940266059SGregory Neil Shapiro static int
48040266059SGregory Neil Shapiro tls_close(fp)
48140266059SGregory Neil Shapiro 	SM_FILE_T *fp;
48240266059SGregory Neil Shapiro {
48340266059SGregory Neil Shapiro 	struct tls_obj *so;
48440266059SGregory Neil Shapiro 
48540266059SGregory Neil Shapiro 	so = (struct tls_obj *) fp->f_cookie;
48640266059SGregory Neil Shapiro 	if (so->fp != NULL)
48740266059SGregory Neil Shapiro 	{
48840266059SGregory Neil Shapiro 		sm_io_close(so->fp, SM_TIME_DEFAULT);
48940266059SGregory Neil Shapiro 		so->fp = NULL;
49040266059SGregory Neil Shapiro 	}
49140266059SGregory Neil Shapiro 	sm_free(so);
49240266059SGregory Neil Shapiro 	so = NULL;
49340266059SGregory Neil Shapiro 	return 0;
49440266059SGregory Neil Shapiro }
49540266059SGregory Neil Shapiro 
49640266059SGregory Neil Shapiro /* maximum number of retries for TLS related I/O due to handshakes */
49740266059SGregory Neil Shapiro # define MAX_TLS_IOS	4
49840266059SGregory Neil Shapiro 
49940266059SGregory Neil Shapiro /*
50040266059SGregory Neil Shapiro **  TLS_READ -- read secured information for the caller
50140266059SGregory Neil Shapiro **
50240266059SGregory Neil Shapiro **	Parameters:
50340266059SGregory Neil Shapiro **		fp -- the file pointer
50440266059SGregory Neil Shapiro **		buf -- the location to place the data
50540266059SGregory Neil Shapiro **		size -- the number of bytes to read from connection
50640266059SGregory Neil Shapiro **
50740266059SGregory Neil Shapiro **	Results:
50840266059SGregory Neil Shapiro **		-1 on error
50940266059SGregory Neil Shapiro **		otherwise the number of bytes read
51040266059SGregory Neil Shapiro */
51140266059SGregory Neil Shapiro 
51240266059SGregory Neil Shapiro static ssize_t tls_read __P((SM_FILE_T *, char *, size_t));
51340266059SGregory Neil Shapiro 
51440266059SGregory Neil Shapiro static ssize_t
51540266059SGregory Neil Shapiro tls_read(fp, buf, size)
51640266059SGregory Neil Shapiro 	SM_FILE_T *fp;
51713058a91SGregory Neil Shapiro 	char *buf;
51840266059SGregory Neil Shapiro 	size_t size;
51906f25ae9SGregory Neil Shapiro {
52006f25ae9SGregory Neil Shapiro 	int r;
52140266059SGregory Neil Shapiro 	static int again = MAX_TLS_IOS;
52240266059SGregory Neil Shapiro 	struct tls_obj *so = (struct tls_obj *) fp->f_cookie;
52306f25ae9SGregory Neil Shapiro 	char *err;
52406f25ae9SGregory Neil Shapiro 
52540266059SGregory Neil Shapiro 	r = SSL_read(so->con, (char *) buf, size);
52640266059SGregory Neil Shapiro 
52740266059SGregory Neil Shapiro 	if (r > 0)
52840266059SGregory Neil Shapiro 	{
52940266059SGregory Neil Shapiro 		again = MAX_TLS_IOS;
53040266059SGregory Neil Shapiro 		return r;
53140266059SGregory Neil Shapiro 	}
53240266059SGregory Neil Shapiro 
53306f25ae9SGregory Neil Shapiro 	err = NULL;
53440266059SGregory Neil Shapiro 	switch (SSL_get_error(so->con, r))
53506f25ae9SGregory Neil Shapiro 	{
53606f25ae9SGregory Neil Shapiro 	  case SSL_ERROR_NONE:
53740266059SGregory Neil Shapiro 	  case SSL_ERROR_ZERO_RETURN:
53840266059SGregory Neil Shapiro 		again = MAX_TLS_IOS;
53906f25ae9SGregory Neil Shapiro 		break;
54006f25ae9SGregory Neil Shapiro 	  case SSL_ERROR_WANT_WRITE:
54140266059SGregory Neil Shapiro 		if (--again <= 0)
54240266059SGregory Neil Shapiro 			err = "read W BLOCK";
54340266059SGregory Neil Shapiro 		else
54440266059SGregory Neil Shapiro 			errno = EAGAIN;
54506f25ae9SGregory Neil Shapiro 		break;
54606f25ae9SGregory Neil Shapiro 	  case SSL_ERROR_WANT_READ:
54740266059SGregory Neil Shapiro 		if (--again <= 0)
54840266059SGregory Neil Shapiro 			err = "read R BLOCK";
54940266059SGregory Neil Shapiro 		else
55040266059SGregory Neil Shapiro 			errno = EAGAIN;
55106f25ae9SGregory Neil Shapiro 		break;
55206f25ae9SGregory Neil Shapiro 	  case SSL_ERROR_WANT_X509_LOOKUP:
55306f25ae9SGregory Neil Shapiro 		err = "write X BLOCK";
55406f25ae9SGregory Neil Shapiro 		break;
55506f25ae9SGregory Neil Shapiro 	  case SSL_ERROR_SYSCALL:
55640266059SGregory Neil Shapiro 		if (r == 0 && errno == 0) /* out of protocol EOF found */
55740266059SGregory Neil Shapiro 			break;
55806f25ae9SGregory Neil Shapiro 		err = "syscall error";
55906f25ae9SGregory Neil Shapiro /*
56006f25ae9SGregory Neil Shapiro 		get_last_socket_error());
56106f25ae9SGregory Neil Shapiro */
56206f25ae9SGregory Neil Shapiro 		break;
56306f25ae9SGregory Neil Shapiro 	  case SSL_ERROR_SSL:
564959366dcSGregory Neil Shapiro #if _FFR_DEAL_WITH_ERROR_SSL
565959366dcSGregory Neil Shapiro 		if (r == 0 && errno == 0) /* out of protocol EOF found */
566959366dcSGregory Neil Shapiro 			break;
567959366dcSGregory Neil Shapiro #endif /* _FFR_DEAL_WITH_ERROR_SSL */
56806f25ae9SGregory Neil Shapiro 		err = "generic SSL error";
56940266059SGregory Neil Shapiro 		if (LogLevel > 9)
57040266059SGregory Neil Shapiro 			tlslogerr("read");
571959366dcSGregory Neil Shapiro 
572959366dcSGregory Neil Shapiro #if _FFR_DEAL_WITH_ERROR_SSL
573959366dcSGregory Neil Shapiro 		/* avoid repeated calls? */
574959366dcSGregory Neil Shapiro 		if (r == 0)
575959366dcSGregory Neil Shapiro 			r = -1;
576959366dcSGregory Neil Shapiro #endif /* _FFR_DEAL_WITH_ERROR_SSL */
57706f25ae9SGregory Neil Shapiro 		break;
57806f25ae9SGregory Neil Shapiro 	}
57906f25ae9SGregory Neil Shapiro 	if (err != NULL)
58040266059SGregory Neil Shapiro 	{
581605302a5SGregory Neil Shapiro 		int save_errno;
582605302a5SGregory Neil Shapiro 
583605302a5SGregory Neil Shapiro 		save_errno = (errno == 0) ? EIO : errno;
58440266059SGregory Neil Shapiro 		again = MAX_TLS_IOS;
58540266059SGregory Neil Shapiro 		if (LogLevel > 7)
58640266059SGregory Neil Shapiro 			sm_syslog(LOG_WARNING, NOQID,
58740266059SGregory Neil Shapiro 				  "STARTTLS: read error=%s (%d)", err, r);
588605302a5SGregory Neil Shapiro 		errno = save_errno;
58906f25ae9SGregory Neil Shapiro 	}
59006f25ae9SGregory Neil Shapiro 	return r;
59106f25ae9SGregory Neil Shapiro }
59206f25ae9SGregory Neil Shapiro 
59340266059SGregory Neil Shapiro /*
59440266059SGregory Neil Shapiro **  TLS_WRITE -- write information out through secure connection
59540266059SGregory Neil Shapiro **
59640266059SGregory Neil Shapiro **	Parameters:
59740266059SGregory Neil Shapiro **		fp -- the file pointer
59840266059SGregory Neil Shapiro **		buf -- holds the data to be securely written
59940266059SGregory Neil Shapiro **		size -- the number of bytes to write
60040266059SGregory Neil Shapiro **
60140266059SGregory Neil Shapiro **	Returns:
60240266059SGregory Neil Shapiro **		-1 on error
60340266059SGregory Neil Shapiro **		otherwise number of bytes written
60440266059SGregory Neil Shapiro */
60540266059SGregory Neil Shapiro 
60640266059SGregory Neil Shapiro static ssize_t tls_write __P((SM_FILE_T *, const char *, size_t));
60740266059SGregory Neil Shapiro 
60813058a91SGregory Neil Shapiro static ssize_t
60940266059SGregory Neil Shapiro tls_write(fp, buf, size)
61040266059SGregory Neil Shapiro 	SM_FILE_T *fp;
61113058a91SGregory Neil Shapiro 	const char *buf;
61240266059SGregory Neil Shapiro 	size_t size;
61306f25ae9SGregory Neil Shapiro {
61406f25ae9SGregory Neil Shapiro 	int r;
61540266059SGregory Neil Shapiro 	static int again = MAX_TLS_IOS;
61640266059SGregory Neil Shapiro 	struct tls_obj *so = (struct tls_obj *) fp->f_cookie;
61706f25ae9SGregory Neil Shapiro 	char *err;
61806f25ae9SGregory Neil Shapiro 
61940266059SGregory Neil Shapiro 	r = SSL_write(so->con, (char *) buf, size);
62040266059SGregory Neil Shapiro 
62140266059SGregory Neil Shapiro 	if (r > 0)
62240266059SGregory Neil Shapiro 	{
62340266059SGregory Neil Shapiro 		again = MAX_TLS_IOS;
62440266059SGregory Neil Shapiro 		return r;
62540266059SGregory Neil Shapiro 	}
62606f25ae9SGregory Neil Shapiro 	err = NULL;
62740266059SGregory Neil Shapiro 	switch (SSL_get_error(so->con, r))
62806f25ae9SGregory Neil Shapiro 	{
62906f25ae9SGregory Neil Shapiro 	  case SSL_ERROR_NONE:
63040266059SGregory Neil Shapiro 	  case SSL_ERROR_ZERO_RETURN:
63140266059SGregory Neil Shapiro 		again = MAX_TLS_IOS;
63206f25ae9SGregory Neil Shapiro 		break;
63306f25ae9SGregory Neil Shapiro 	  case SSL_ERROR_WANT_WRITE:
63440266059SGregory Neil Shapiro 		if (--again <= 0)
63506f25ae9SGregory Neil Shapiro 			err = "write W BLOCK";
63640266059SGregory Neil Shapiro 		else
63740266059SGregory Neil Shapiro 			errno = EAGAIN;
63806f25ae9SGregory Neil Shapiro 		break;
63906f25ae9SGregory Neil Shapiro 	  case SSL_ERROR_WANT_READ:
64040266059SGregory Neil Shapiro 		if (--again <= 0)
64106f25ae9SGregory Neil Shapiro 			err = "write R BLOCK";
64240266059SGregory Neil Shapiro 		else
64340266059SGregory Neil Shapiro 			errno = EAGAIN;
64406f25ae9SGregory Neil Shapiro 		break;
64506f25ae9SGregory Neil Shapiro 	  case SSL_ERROR_WANT_X509_LOOKUP:
64606f25ae9SGregory Neil Shapiro 		err = "write X BLOCK";
64706f25ae9SGregory Neil Shapiro 		break;
64806f25ae9SGregory Neil Shapiro 	  case SSL_ERROR_SYSCALL:
64940266059SGregory Neil Shapiro 		if (r == 0 && errno == 0) /* out of protocol EOF found */
65040266059SGregory Neil Shapiro 			break;
65106f25ae9SGregory Neil Shapiro 		err = "syscall error";
65206f25ae9SGregory Neil Shapiro /*
65306f25ae9SGregory Neil Shapiro 		get_last_socket_error());
65406f25ae9SGregory Neil Shapiro */
65506f25ae9SGregory Neil Shapiro 		break;
65606f25ae9SGregory Neil Shapiro 	  case SSL_ERROR_SSL:
65706f25ae9SGregory Neil Shapiro 		err = "generic SSL error";
65806f25ae9SGregory Neil Shapiro /*
65906f25ae9SGregory Neil Shapiro 		ERR_GET_REASON(ERR_peek_error()));
66006f25ae9SGregory Neil Shapiro */
66140266059SGregory Neil Shapiro 		if (LogLevel > 9)
66240266059SGregory Neil Shapiro 			tlslogerr("write");
663959366dcSGregory Neil Shapiro 
664959366dcSGregory Neil Shapiro #if _FFR_DEAL_WITH_ERROR_SSL
665959366dcSGregory Neil Shapiro 		/* avoid repeated calls? */
666959366dcSGregory Neil Shapiro 		if (r == 0)
667959366dcSGregory Neil Shapiro 			r = -1;
668959366dcSGregory Neil Shapiro #endif /* _FFR_DEAL_WITH_ERROR_SSL */
66906f25ae9SGregory Neil Shapiro 		break;
67006f25ae9SGregory Neil Shapiro 	}
67106f25ae9SGregory Neil Shapiro 	if (err != NULL)
67240266059SGregory Neil Shapiro 	{
673605302a5SGregory Neil Shapiro 		int save_errno;
674605302a5SGregory Neil Shapiro 
675605302a5SGregory Neil Shapiro 		save_errno = (errno == 0) ? EIO : errno;
67640266059SGregory Neil Shapiro 		again = MAX_TLS_IOS;
67740266059SGregory Neil Shapiro 		if (LogLevel > 7)
67840266059SGregory Neil Shapiro 			sm_syslog(LOG_WARNING, NOQID,
67940266059SGregory Neil Shapiro 				  "STARTTLS: write error=%s (%d)", err, r);
680605302a5SGregory Neil Shapiro 		errno = save_errno;
68106f25ae9SGregory Neil Shapiro 	}
68206f25ae9SGregory Neil Shapiro 	return r;
68306f25ae9SGregory Neil Shapiro }
68406f25ae9SGregory Neil Shapiro 
68540266059SGregory Neil Shapiro /*
68640266059SGregory Neil Shapiro **  SFDCTLS -- create tls file type and open in and out file pointers
68740266059SGregory Neil Shapiro **	      for sendmail to read from and write to.
68840266059SGregory Neil Shapiro **
68940266059SGregory Neil Shapiro **	Parameters:
69040266059SGregory Neil Shapiro **		fin -- data input source being replaced
69140266059SGregory Neil Shapiro **		fout -- data output source being replaced
69240266059SGregory Neil Shapiro **		conn -- the tls connection pointer
69340266059SGregory Neil Shapiro **
69440266059SGregory Neil Shapiro **	Returns:
69540266059SGregory Neil Shapiro **		-1 on error
69640266059SGregory Neil Shapiro **		0 on success
69740266059SGregory Neil Shapiro **
69840266059SGregory Neil Shapiro **	Side effects:
69940266059SGregory Neil Shapiro **		The arguments "fin" and "fout" are replaced with the new
70040266059SGregory Neil Shapiro **		SM_FILE_T pointers.
70140266059SGregory Neil Shapiro **		The original "fin" and "fout" are preserved in the tls file
70240266059SGregory Neil Shapiro **		type but are not actually used because of the design of TLS.
70340266059SGregory Neil Shapiro */
70406f25ae9SGregory Neil Shapiro 
70506f25ae9SGregory Neil Shapiro int
70606f25ae9SGregory Neil Shapiro sfdctls(fin, fout, con)
70740266059SGregory Neil Shapiro 	SM_FILE_T **fin;
70840266059SGregory Neil Shapiro 	SM_FILE_T **fout;
70906f25ae9SGregory Neil Shapiro 	SSL *con;
71006f25ae9SGregory Neil Shapiro {
71140266059SGregory Neil Shapiro 	SM_FILE_T *tlsin, *tlsout;
71240266059SGregory Neil Shapiro 	SM_FILE_T SM_IO_SET_TYPE(tls_vector, "tls", tls_open, tls_close,
71340266059SGregory Neil Shapiro 		tls_read, tls_write, NULL, tls_getinfo, NULL,
71440266059SGregory Neil Shapiro 		SM_TIME_FOREVER);
71540266059SGregory Neil Shapiro 	struct tls_info info;
71606f25ae9SGregory Neil Shapiro 
71740266059SGregory Neil Shapiro 	SM_ASSERT(con != NULL);
71806f25ae9SGregory Neil Shapiro 
71940266059SGregory Neil Shapiro 	SM_IO_INIT_TYPE(tls_vector, "tls", tls_open, tls_close,
72040266059SGregory Neil Shapiro 		tls_read, tls_write, NULL, tls_getinfo, NULL,
72140266059SGregory Neil Shapiro 		SM_TIME_FOREVER);
72240266059SGregory Neil Shapiro 	info.fp = *fin;
72340266059SGregory Neil Shapiro 	info.con = con;
72440266059SGregory Neil Shapiro 	tlsin = sm_io_open(&tls_vector, SM_TIME_DEFAULT, &info, SM_IO_RDONLY,
72540266059SGregory Neil Shapiro 			   NULL);
72640266059SGregory Neil Shapiro 	if (tlsin == NULL)
72740266059SGregory Neil Shapiro 		return -1;
72806f25ae9SGregory Neil Shapiro 
72940266059SGregory Neil Shapiro 	info.fp = *fout;
73040266059SGregory Neil Shapiro 	tlsout = sm_io_open(&tls_vector, SM_TIME_DEFAULT, &info, SM_IO_WRONLY,
73140266059SGregory Neil Shapiro 			    NULL);
73240266059SGregory Neil Shapiro 	if (tlsout == NULL)
73342e5d165SGregory Neil Shapiro 	{
73440266059SGregory Neil Shapiro 		(void) sm_io_close(tlsin, SM_TIME_DEFAULT);
73542e5d165SGregory Neil Shapiro 		return -1;
73642e5d165SGregory Neil Shapiro 	}
73740266059SGregory Neil Shapiro 	sm_io_automode(tlsin, tlsout);
73806f25ae9SGregory Neil Shapiro 
73940266059SGregory Neil Shapiro 	*fin = tlsin;
74040266059SGregory Neil Shapiro 	*fout = tlsout;
74106f25ae9SGregory Neil Shapiro 	return 0;
74206f25ae9SGregory Neil Shapiro }
74340266059SGregory Neil Shapiro #endif /* STARTTLS */
744