xref: /freebsd/contrib/sendmail/src/sfsasl.c (revision 959366dcbe20824a331bcae977d662025850f481)
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>
12959366dcSGregory Neil Shapiro SM_RCSID("@(#)$Id: sfsasl.c,v 8.91.2.1 2002/08/27 01:35:17 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
18094c01205SGregory Neil Shapiro 	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 
197193538b7SGregory Neil Shapiro 	while (outbuf == NULL && outlen == 0)
198193538b7SGregory Neil Shapiro 	{
19940266059SGregory Neil Shapiro 		len = sm_io_read(so->fp, SM_TIME_DEFAULT, buf, size);
20006f25ae9SGregory Neil Shapiro 		if (len <= 0)
20106f25ae9SGregory Neil Shapiro 			return len;
20240266059SGregory Neil Shapiro 		result = sasl_decode(so->conn, buf,
20340266059SGregory Neil Shapiro 				     (unsigned int) len, &outbuf, &outlen);
20406f25ae9SGregory Neil Shapiro 		if (result != SASL_OK)
20506f25ae9SGregory Neil Shapiro 		{
206193538b7SGregory Neil Shapiro 			outbuf = NULL;
207193538b7SGregory Neil Shapiro 			offset = 0;
208193538b7SGregory Neil Shapiro 			outlen = 0;
20906f25ae9SGregory Neil Shapiro 			return -1;
21006f25ae9SGregory Neil Shapiro 		}
211193538b7SGregory Neil Shapiro 	}
21206f25ae9SGregory Neil Shapiro 
21340266059SGregory Neil Shapiro 	if (outbuf == NULL)
21406f25ae9SGregory Neil Shapiro 	{
21540266059SGregory Neil Shapiro 		/* be paranoid: outbuf == NULL but outlen != 0 */
21640266059SGregory Neil Shapiro 		syserr("@sasl_read failure: outbuf == NULL but outlen != 0");
21740266059SGregory Neil Shapiro 		/* NOTREACHED */
21840266059SGregory Neil Shapiro 	}
219193538b7SGregory Neil Shapiro 	if (outlen - offset > size)
220193538b7SGregory Neil Shapiro 	{
221193538b7SGregory Neil Shapiro 		/* return another part of the buffer */
22240266059SGregory Neil Shapiro 		(void) memcpy(buf, outbuf + offset, size);
223193538b7SGregory Neil Shapiro 		offset += size;
22440266059SGregory Neil Shapiro 		len = size;
22506f25ae9SGregory Neil Shapiro 	}
226193538b7SGregory Neil Shapiro 	else
227193538b7SGregory Neil Shapiro 	{
228193538b7SGregory Neil Shapiro 		/* return the rest of the buffer */
22940266059SGregory Neil Shapiro 		len = outlen - offset;
23040266059SGregory Neil Shapiro 		(void) memcpy(buf, outbuf + offset, (size_t) len);
23194c01205SGregory Neil Shapiro # if SASL < 20000
232193538b7SGregory Neil Shapiro 		SASL_DEALLOC(outbuf);
23394c01205SGregory Neil Shapiro # endif /* SASL < 20000 */
234193538b7SGregory Neil Shapiro 		outbuf = NULL;
235193538b7SGregory Neil Shapiro 		offset = 0;
236193538b7SGregory Neil Shapiro 		outlen = 0;
237193538b7SGregory Neil Shapiro 	}
23840266059SGregory Neil Shapiro 	return len;
23906f25ae9SGregory Neil Shapiro }
24006f25ae9SGregory Neil Shapiro 
24140266059SGregory Neil Shapiro /*
24240266059SGregory Neil Shapiro **  SASL_WRITE -- write information out after encrypting it
24340266059SGregory Neil Shapiro **
24440266059SGregory Neil Shapiro **	Parameters:
24540266059SGregory Neil Shapiro **		fp -- the file pointer
24640266059SGregory Neil Shapiro **		buf -- holds the data to be encrypted and written
24740266059SGregory Neil Shapiro **		size -- the number of bytes to have encrypted and written
24840266059SGregory Neil Shapiro **
24940266059SGregory Neil Shapiro **	Returns:
25040266059SGregory Neil Shapiro **		-1 on error
25140266059SGregory Neil Shapiro **		otherwise number of bytes written
25240266059SGregory Neil Shapiro */
25340266059SGregory Neil Shapiro 
25440266059SGregory Neil Shapiro static ssize_t sasl_write __P((SM_FILE_T *, const char *, size_t));
25540266059SGregory Neil Shapiro 
25606f25ae9SGregory Neil Shapiro static ssize_t
25740266059SGregory Neil Shapiro sasl_write(fp, buf, size)
25840266059SGregory Neil Shapiro 	SM_FILE_T *fp;
25940266059SGregory Neil Shapiro 	const char *buf;
26006f25ae9SGregory Neil Shapiro 	size_t size;
26106f25ae9SGregory Neil Shapiro {
26206f25ae9SGregory Neil Shapiro 	int result;
26394c01205SGregory Neil Shapiro # if SASL >= 20000
26494c01205SGregory Neil Shapiro 	const char *outbuf;
26594c01205SGregory Neil Shapiro # else /* SASL >= 20000 */
26606f25ae9SGregory Neil Shapiro 	char *outbuf;
26794c01205SGregory Neil Shapiro # endif /* SASL >= 20000 */
26806f25ae9SGregory Neil Shapiro 	unsigned int outlen;
26940266059SGregory Neil Shapiro 	size_t ret = 0, total = 0;
27040266059SGregory Neil Shapiro 	struct sasl_obj *so = (struct sasl_obj *) fp->f_cookie;
27106f25ae9SGregory Neil Shapiro 
27240266059SGregory Neil Shapiro 	result = sasl_encode(so->conn, buf,
27340266059SGregory Neil Shapiro 			     (unsigned int) size, &outbuf, &outlen);
27406f25ae9SGregory Neil Shapiro 
27506f25ae9SGregory Neil Shapiro 	if (result != SASL_OK)
27606f25ae9SGregory Neil Shapiro 		return -1;
27706f25ae9SGregory Neil Shapiro 
27806f25ae9SGregory Neil Shapiro 	if (outbuf != NULL)
27906f25ae9SGregory Neil Shapiro 	{
28040266059SGregory Neil Shapiro 		while (outlen > 0)
28140266059SGregory Neil Shapiro 		{
282605302a5SGregory Neil Shapiro 			/* XXX result == 0? */
28340266059SGregory Neil Shapiro 			ret = sm_io_write(so->fp, SM_TIME_DEFAULT,
28440266059SGregory Neil Shapiro 					  &outbuf[total], outlen);
28540266059SGregory Neil Shapiro 			outlen -= ret;
28640266059SGregory Neil Shapiro 			total += ret;
28740266059SGregory Neil Shapiro 		}
28894c01205SGregory Neil Shapiro # if SASL < 20000
289193538b7SGregory Neil Shapiro 		SASL_DEALLOC(outbuf);
29094c01205SGregory Neil Shapiro # endif /* SASL < 20000 */
29106f25ae9SGregory Neil Shapiro 	}
29206f25ae9SGregory Neil Shapiro 	return size;
29306f25ae9SGregory Neil Shapiro }
29406f25ae9SGregory Neil Shapiro 
29540266059SGregory Neil Shapiro /*
29640266059SGregory Neil Shapiro **  SFDCSASL -- create sasl file type and open in and out file pointers
29740266059SGregory Neil Shapiro **	       for sendmail to read from and write to.
29840266059SGregory Neil Shapiro **
29940266059SGregory Neil Shapiro **	Parameters:
30040266059SGregory Neil Shapiro **		fin -- the sm_io file encrypted data to be read from
30140266059SGregory Neil Shapiro **		fout -- the sm_io file encrypted data to be writen to
30240266059SGregory Neil Shapiro **		conn -- the sasl connection pointer
30340266059SGregory Neil Shapiro **
30440266059SGregory Neil Shapiro **	Returns:
30540266059SGregory Neil Shapiro **		-1 on error
30640266059SGregory Neil Shapiro **		0 on success
30740266059SGregory Neil Shapiro **
30840266059SGregory Neil Shapiro **	Side effects:
30940266059SGregory Neil Shapiro **		The arguments "fin" and "fout" are replaced with the new
31040266059SGregory Neil Shapiro **		SM_FILE_T pointers.
31140266059SGregory Neil Shapiro */
31240266059SGregory Neil Shapiro 
31306f25ae9SGregory Neil Shapiro int
31406f25ae9SGregory Neil Shapiro sfdcsasl(fin, fout, conn)
31540266059SGregory Neil Shapiro 	SM_FILE_T **fin;
31640266059SGregory Neil Shapiro 	SM_FILE_T **fout;
31706f25ae9SGregory Neil Shapiro 	sasl_conn_t *conn;
31806f25ae9SGregory Neil Shapiro {
31940266059SGregory Neil Shapiro 	SM_FILE_T *newin, *newout;
32040266059SGregory Neil Shapiro 	SM_FILE_T  SM_IO_SET_TYPE(sasl_vector, "sasl", sasl_open, sasl_close,
32140266059SGregory Neil Shapiro 		sasl_read, sasl_write, NULL, sasl_getinfo, NULL,
32240266059SGregory Neil Shapiro 		SM_TIME_FOREVER);
32340266059SGregory Neil Shapiro 	struct sasl_info info;
32406f25ae9SGregory Neil Shapiro 
32506f25ae9SGregory Neil Shapiro 	if (conn == NULL)
32606f25ae9SGregory Neil Shapiro 	{
32706f25ae9SGregory Neil Shapiro 		/* no need to do anything */
32806f25ae9SGregory Neil Shapiro 		return 0;
32906f25ae9SGregory Neil Shapiro 	}
33006f25ae9SGregory Neil Shapiro 
33140266059SGregory Neil Shapiro 	SM_IO_INIT_TYPE(sasl_vector, "sasl", sasl_open, sasl_close,
33240266059SGregory Neil Shapiro 		sasl_read, sasl_write, NULL, sasl_getinfo, NULL,
33340266059SGregory Neil Shapiro 		SM_TIME_FOREVER);
33440266059SGregory Neil Shapiro 	info.fp = *fin;
33540266059SGregory Neil Shapiro 	info.conn = conn;
33640266059SGregory Neil Shapiro 	newin = sm_io_open(&sasl_vector, SM_TIME_DEFAULT, &info, SM_IO_RDONLY,
33740266059SGregory Neil Shapiro 			   NULL);
33806f25ae9SGregory Neil Shapiro 
33940266059SGregory Neil Shapiro 	if (newin == NULL)
34040266059SGregory Neil Shapiro 		return -1;
34106f25ae9SGregory Neil Shapiro 
34240266059SGregory Neil Shapiro 	info.fp = *fout;
34340266059SGregory Neil Shapiro 	info.conn = conn;
34440266059SGregory Neil Shapiro 	newout = sm_io_open(&sasl_vector, SM_TIME_DEFAULT, &info, SM_IO_WRONLY,
34540266059SGregory Neil Shapiro 			    NULL);
34606f25ae9SGregory Neil Shapiro 
34740266059SGregory Neil Shapiro 	if (newout == NULL)
34806f25ae9SGregory Neil Shapiro 	{
34940266059SGregory Neil Shapiro 		(void) sm_io_close(newin, SM_TIME_DEFAULT);
35006f25ae9SGregory Neil Shapiro 		return -1;
35106f25ae9SGregory Neil Shapiro 	}
35240266059SGregory Neil Shapiro 	sm_io_automode(newin, newout);
35340266059SGregory Neil Shapiro 
35440266059SGregory Neil Shapiro 	*fin = newin;
35540266059SGregory Neil Shapiro 	*fout = newout;
35606f25ae9SGregory Neil Shapiro 	return 0;
35706f25ae9SGregory Neil Shapiro }
35840266059SGregory Neil Shapiro #endif /* SASL */
35906f25ae9SGregory Neil Shapiro 
36040266059SGregory Neil Shapiro #if STARTTLS
36106f25ae9SGregory Neil Shapiro # include "sfsasl.h"
36206f25ae9SGregory Neil Shapiro #  include <openssl/err.h>
36306f25ae9SGregory Neil Shapiro 
36440266059SGregory Neil Shapiro /* Structure used by the "tls" file type */
36540266059SGregory Neil Shapiro struct tls_obj
36640266059SGregory Neil Shapiro {
36740266059SGregory Neil Shapiro 	SM_FILE_T *fp;
36840266059SGregory Neil Shapiro 	SSL *con;
36940266059SGregory Neil Shapiro };
37040266059SGregory Neil Shapiro 
37140266059SGregory Neil Shapiro struct tls_info
37240266059SGregory Neil Shapiro {
37340266059SGregory Neil Shapiro 	SM_FILE_T *fp;
37440266059SGregory Neil Shapiro 	SSL *con;
37540266059SGregory Neil Shapiro };
37640266059SGregory Neil Shapiro 
37740266059SGregory Neil Shapiro /*
37840266059SGregory Neil Shapiro **  TLS_GETINFO - returns requested information about a "tls" file
37940266059SGregory Neil Shapiro **		 descriptor.
38040266059SGregory Neil Shapiro **
38140266059SGregory Neil Shapiro **	Parameters:
38240266059SGregory Neil Shapiro **		fp -- the file descriptor
38340266059SGregory Neil Shapiro **		what -- the type of information requested
38440266059SGregory Neil Shapiro **		valp -- the thang to return the information in (unused)
38540266059SGregory Neil Shapiro **
38640266059SGregory Neil Shapiro **	Returns:
38740266059SGregory Neil Shapiro **		-1 for unknown requests
38840266059SGregory Neil Shapiro **		>=0 on success with valp filled in (if possible).
38940266059SGregory Neil Shapiro */
39040266059SGregory Neil Shapiro 
39140266059SGregory Neil Shapiro static int tls_getinfo __P((SM_FILE_T *, int, void *));
39240266059SGregory Neil Shapiro 
39340266059SGregory Neil Shapiro /* ARGSUSED2 */
39413058a91SGregory Neil Shapiro static int
39540266059SGregory Neil Shapiro tls_getinfo(fp, what, valp)
39640266059SGregory Neil Shapiro 	SM_FILE_T *fp;
39740266059SGregory Neil Shapiro 	int what;
39840266059SGregory Neil Shapiro 	void *valp;
39940266059SGregory Neil Shapiro {
40040266059SGregory Neil Shapiro 	struct tls_obj *so = (struct tls_obj *) fp->f_cookie;
40140266059SGregory Neil Shapiro 
40240266059SGregory Neil Shapiro 	switch (what)
40340266059SGregory Neil Shapiro 	{
40440266059SGregory Neil Shapiro 	  case SM_IO_WHAT_FD:
40540266059SGregory Neil Shapiro 		if (so->fp == NULL)
40640266059SGregory Neil Shapiro 			return -1;
40740266059SGregory Neil Shapiro 		return so->fp->f_file; /* for stdio fileno() compatability */
40840266059SGregory Neil Shapiro 
40940266059SGregory Neil Shapiro 	  case SM_IO_IS_READABLE:
41040266059SGregory Neil Shapiro 		return SSL_pending(so->con) > 0;
41140266059SGregory Neil Shapiro 
41240266059SGregory Neil Shapiro 	  default:
41340266059SGregory Neil Shapiro 		return -1;
41440266059SGregory Neil Shapiro 	}
41540266059SGregory Neil Shapiro }
41640266059SGregory Neil Shapiro 
41740266059SGregory Neil Shapiro /*
41840266059SGregory Neil Shapiro **  TLS_OPEN -- creates the tls specific information for opening a
41940266059SGregory Neil Shapiro **	       file of the tls type.
42040266059SGregory Neil Shapiro **
42140266059SGregory Neil Shapiro **	Parameters:
42240266059SGregory Neil Shapiro **		fp -- the file pointer associated with the new open
42340266059SGregory Neil Shapiro **		info -- the sm_io file pointer holding the open and the
42440266059SGregory Neil Shapiro **			TLS encryption connection to be read from or written to
42540266059SGregory Neil Shapiro **		flags -- ignored
42640266059SGregory Neil Shapiro **		rpool -- ignored
42740266059SGregory Neil Shapiro **
42840266059SGregory Neil Shapiro **	Returns:
42940266059SGregory Neil Shapiro **		0 on success
43040266059SGregory Neil Shapiro */
43140266059SGregory Neil Shapiro 
43240266059SGregory Neil Shapiro static int tls_open __P((SM_FILE_T *, const void *, int, const void *));
43340266059SGregory Neil Shapiro 
43440266059SGregory Neil Shapiro /* ARGSUSED2 */
43540266059SGregory Neil Shapiro static int
43640266059SGregory Neil Shapiro tls_open(fp, info, flags, rpool)
43740266059SGregory Neil Shapiro 	SM_FILE_T *fp;
43840266059SGregory Neil Shapiro 	const void *info;
43940266059SGregory Neil Shapiro 	int flags;
44040266059SGregory Neil Shapiro 	const void *rpool;
44140266059SGregory Neil Shapiro {
44240266059SGregory Neil Shapiro 	struct tls_obj *so;
44340266059SGregory Neil Shapiro 	struct tls_info *ti = (struct tls_info *) info;
44440266059SGregory Neil Shapiro 
44540266059SGregory Neil Shapiro 	so = (struct tls_obj *) sm_malloc(sizeof(struct tls_obj));
44640266059SGregory Neil Shapiro 	so->fp = ti->fp;
44740266059SGregory Neil Shapiro 	so->con = ti->con;
44840266059SGregory Neil Shapiro 
44940266059SGregory Neil Shapiro 	/*
45040266059SGregory Neil Shapiro 	**  We try to get the "raw" file descriptor that TLS uses to
45140266059SGregory Neil Shapiro 	**  do the actual read/write with. This is to allow us control
45240266059SGregory Neil Shapiro 	**  over the file descriptor being a blocking or non-blocking type.
45340266059SGregory Neil Shapiro 	**  Under the covers TLS handles the change and this allows us
45440266059SGregory Neil Shapiro 	**  to do timeouts with sm_io.
45540266059SGregory Neil Shapiro 	*/
45640266059SGregory Neil Shapiro 
45740266059SGregory Neil Shapiro 	fp->f_file = sm_io_getinfo(so->fp, SM_IO_WHAT_FD, NULL);
45840266059SGregory Neil Shapiro 	(void) sm_io_setvbuf(so->fp, SM_TIME_DEFAULT, NULL, SM_IO_NOW, 0);
45940266059SGregory Neil Shapiro 	fp->f_cookie = so;
46040266059SGregory Neil Shapiro 	return 0;
46140266059SGregory Neil Shapiro }
46240266059SGregory Neil Shapiro 
46340266059SGregory Neil Shapiro /*
46440266059SGregory Neil Shapiro **  TLS_CLOSE -- close the tls specific parts of the tls file pointer
46540266059SGregory Neil Shapiro **
46640266059SGregory Neil Shapiro **	Parameters:
46740266059SGregory Neil Shapiro **		fp -- the file pointer to close
46840266059SGregory Neil Shapiro **
46940266059SGregory Neil Shapiro **	Returns:
47040266059SGregory Neil Shapiro **		0 on success
47140266059SGregory Neil Shapiro */
47240266059SGregory Neil Shapiro 
47340266059SGregory Neil Shapiro static int tls_close __P((SM_FILE_T *));
47440266059SGregory Neil Shapiro 
47540266059SGregory Neil Shapiro static int
47640266059SGregory Neil Shapiro tls_close(fp)
47740266059SGregory Neil Shapiro 	SM_FILE_T *fp;
47840266059SGregory Neil Shapiro {
47940266059SGregory Neil Shapiro 	struct tls_obj *so;
48040266059SGregory Neil Shapiro 
48140266059SGregory Neil Shapiro 	so = (struct tls_obj *) fp->f_cookie;
48240266059SGregory Neil Shapiro 	if (so->fp != NULL)
48340266059SGregory Neil Shapiro 	{
48440266059SGregory Neil Shapiro 		sm_io_close(so->fp, SM_TIME_DEFAULT);
48540266059SGregory Neil Shapiro 		so->fp = NULL;
48640266059SGregory Neil Shapiro 	}
48740266059SGregory Neil Shapiro 	sm_free(so);
48840266059SGregory Neil Shapiro 	so = NULL;
48940266059SGregory Neil Shapiro 	return 0;
49040266059SGregory Neil Shapiro }
49140266059SGregory Neil Shapiro 
49240266059SGregory Neil Shapiro /* maximum number of retries for TLS related I/O due to handshakes */
49340266059SGregory Neil Shapiro # define MAX_TLS_IOS	4
49440266059SGregory Neil Shapiro 
49540266059SGregory Neil Shapiro /*
49640266059SGregory Neil Shapiro **  TLS_READ -- read secured information for the caller
49740266059SGregory Neil Shapiro **
49840266059SGregory Neil Shapiro **	Parameters:
49940266059SGregory Neil Shapiro **		fp -- the file pointer
50040266059SGregory Neil Shapiro **		buf -- the location to place the data
50140266059SGregory Neil Shapiro **		size -- the number of bytes to read from connection
50240266059SGregory Neil Shapiro **
50340266059SGregory Neil Shapiro **	Results:
50440266059SGregory Neil Shapiro **		-1 on error
50540266059SGregory Neil Shapiro **		otherwise the number of bytes read
50640266059SGregory Neil Shapiro */
50740266059SGregory Neil Shapiro 
50840266059SGregory Neil Shapiro static ssize_t tls_read __P((SM_FILE_T *, char *, size_t));
50940266059SGregory Neil Shapiro 
51040266059SGregory Neil Shapiro static ssize_t
51140266059SGregory Neil Shapiro tls_read(fp, buf, size)
51240266059SGregory Neil Shapiro 	SM_FILE_T *fp;
51313058a91SGregory Neil Shapiro 	char *buf;
51440266059SGregory Neil Shapiro 	size_t size;
51506f25ae9SGregory Neil Shapiro {
51606f25ae9SGregory Neil Shapiro 	int r;
51740266059SGregory Neil Shapiro 	static int again = MAX_TLS_IOS;
51840266059SGregory Neil Shapiro 	struct tls_obj *so = (struct tls_obj *) fp->f_cookie;
51906f25ae9SGregory Neil Shapiro 	char *err;
52006f25ae9SGregory Neil Shapiro 
52140266059SGregory Neil Shapiro 	r = SSL_read(so->con, (char *) buf, size);
52240266059SGregory Neil Shapiro 
52340266059SGregory Neil Shapiro 	if (r > 0)
52440266059SGregory Neil Shapiro 	{
52540266059SGregory Neil Shapiro 		again = MAX_TLS_IOS;
52640266059SGregory Neil Shapiro 		return r;
52740266059SGregory Neil Shapiro 	}
52840266059SGregory Neil Shapiro 
52906f25ae9SGregory Neil Shapiro 	err = NULL;
53040266059SGregory Neil Shapiro 	switch (SSL_get_error(so->con, r))
53106f25ae9SGregory Neil Shapiro 	{
53206f25ae9SGregory Neil Shapiro 	  case SSL_ERROR_NONE:
53340266059SGregory Neil Shapiro 	  case SSL_ERROR_ZERO_RETURN:
53440266059SGregory Neil Shapiro 		again = MAX_TLS_IOS;
53506f25ae9SGregory Neil Shapiro 		break;
53606f25ae9SGregory Neil Shapiro 	  case SSL_ERROR_WANT_WRITE:
53740266059SGregory Neil Shapiro 		if (--again <= 0)
53840266059SGregory Neil Shapiro 			err = "read W BLOCK";
53940266059SGregory Neil Shapiro 		else
54040266059SGregory Neil Shapiro 			errno = EAGAIN;
54106f25ae9SGregory Neil Shapiro 		break;
54206f25ae9SGregory Neil Shapiro 	  case SSL_ERROR_WANT_READ:
54340266059SGregory Neil Shapiro 		if (--again <= 0)
54440266059SGregory Neil Shapiro 			err = "read R BLOCK";
54540266059SGregory Neil Shapiro 		else
54640266059SGregory Neil Shapiro 			errno = EAGAIN;
54706f25ae9SGregory Neil Shapiro 		break;
54806f25ae9SGregory Neil Shapiro 	  case SSL_ERROR_WANT_X509_LOOKUP:
54906f25ae9SGregory Neil Shapiro 		err = "write X BLOCK";
55006f25ae9SGregory Neil Shapiro 		break;
55106f25ae9SGregory Neil Shapiro 	  case SSL_ERROR_SYSCALL:
55240266059SGregory Neil Shapiro 		if (r == 0 && errno == 0) /* out of protocol EOF found */
55340266059SGregory Neil Shapiro 			break;
55406f25ae9SGregory Neil Shapiro 		err = "syscall error";
55506f25ae9SGregory Neil Shapiro /*
55606f25ae9SGregory Neil Shapiro 		get_last_socket_error());
55706f25ae9SGregory Neil Shapiro */
55806f25ae9SGregory Neil Shapiro 		break;
55906f25ae9SGregory Neil Shapiro 	  case SSL_ERROR_SSL:
560959366dcSGregory Neil Shapiro #if _FFR_DEAL_WITH_ERROR_SSL
561959366dcSGregory Neil Shapiro 		if (r == 0 && errno == 0) /* out of protocol EOF found */
562959366dcSGregory Neil Shapiro 			break;
563959366dcSGregory Neil Shapiro #endif /* _FFR_DEAL_WITH_ERROR_SSL */
56406f25ae9SGregory Neil Shapiro 		err = "generic SSL error";
56540266059SGregory Neil Shapiro 		if (LogLevel > 9)
56640266059SGregory Neil Shapiro 			tlslogerr("read");
567959366dcSGregory Neil Shapiro 
568959366dcSGregory Neil Shapiro #if _FFR_DEAL_WITH_ERROR_SSL
569959366dcSGregory Neil Shapiro 		/* avoid repeated calls? */
570959366dcSGregory Neil Shapiro 		if (r == 0)
571959366dcSGregory Neil Shapiro 			r = -1;
572959366dcSGregory Neil Shapiro #endif /* _FFR_DEAL_WITH_ERROR_SSL */
57306f25ae9SGregory Neil Shapiro 		break;
57406f25ae9SGregory Neil Shapiro 	}
57506f25ae9SGregory Neil Shapiro 	if (err != NULL)
57640266059SGregory Neil Shapiro 	{
577605302a5SGregory Neil Shapiro 		int save_errno;
578605302a5SGregory Neil Shapiro 
579605302a5SGregory Neil Shapiro 		save_errno = (errno == 0) ? EIO : errno;
58040266059SGregory Neil Shapiro 		again = MAX_TLS_IOS;
58140266059SGregory Neil Shapiro 		if (LogLevel > 7)
58240266059SGregory Neil Shapiro 			sm_syslog(LOG_WARNING, NOQID,
58340266059SGregory Neil Shapiro 				  "STARTTLS: read error=%s (%d)", err, r);
584605302a5SGregory Neil Shapiro 		errno = save_errno;
58506f25ae9SGregory Neil Shapiro 	}
58606f25ae9SGregory Neil Shapiro 	return r;
58706f25ae9SGregory Neil Shapiro }
58806f25ae9SGregory Neil Shapiro 
58940266059SGregory Neil Shapiro /*
59040266059SGregory Neil Shapiro **  TLS_WRITE -- write information out through secure connection
59140266059SGregory Neil Shapiro **
59240266059SGregory Neil Shapiro **	Parameters:
59340266059SGregory Neil Shapiro **		fp -- the file pointer
59440266059SGregory Neil Shapiro **		buf -- holds the data to be securely written
59540266059SGregory Neil Shapiro **		size -- the number of bytes to write
59640266059SGregory Neil Shapiro **
59740266059SGregory Neil Shapiro **	Returns:
59840266059SGregory Neil Shapiro **		-1 on error
59940266059SGregory Neil Shapiro **		otherwise number of bytes written
60040266059SGregory Neil Shapiro */
60140266059SGregory Neil Shapiro 
60240266059SGregory Neil Shapiro static ssize_t tls_write __P((SM_FILE_T *, const char *, size_t));
60340266059SGregory Neil Shapiro 
60413058a91SGregory Neil Shapiro static ssize_t
60540266059SGregory Neil Shapiro tls_write(fp, buf, size)
60640266059SGregory Neil Shapiro 	SM_FILE_T *fp;
60713058a91SGregory Neil Shapiro 	const char *buf;
60840266059SGregory Neil Shapiro 	size_t size;
60906f25ae9SGregory Neil Shapiro {
61006f25ae9SGregory Neil Shapiro 	int r;
61140266059SGregory Neil Shapiro 	static int again = MAX_TLS_IOS;
61240266059SGregory Neil Shapiro 	struct tls_obj *so = (struct tls_obj *) fp->f_cookie;
61306f25ae9SGregory Neil Shapiro 	char *err;
61406f25ae9SGregory Neil Shapiro 
61540266059SGregory Neil Shapiro 	r = SSL_write(so->con, (char *) buf, size);
61640266059SGregory Neil Shapiro 
61740266059SGregory Neil Shapiro 	if (r > 0)
61840266059SGregory Neil Shapiro 	{
61940266059SGregory Neil Shapiro 		again = MAX_TLS_IOS;
62040266059SGregory Neil Shapiro 		return r;
62140266059SGregory Neil Shapiro 	}
62206f25ae9SGregory Neil Shapiro 	err = NULL;
62340266059SGregory Neil Shapiro 	switch (SSL_get_error(so->con, r))
62406f25ae9SGregory Neil Shapiro 	{
62506f25ae9SGregory Neil Shapiro 	  case SSL_ERROR_NONE:
62640266059SGregory Neil Shapiro 	  case SSL_ERROR_ZERO_RETURN:
62740266059SGregory Neil Shapiro 		again = MAX_TLS_IOS;
62806f25ae9SGregory Neil Shapiro 		break;
62906f25ae9SGregory Neil Shapiro 	  case SSL_ERROR_WANT_WRITE:
63040266059SGregory Neil Shapiro 		if (--again <= 0)
63106f25ae9SGregory Neil Shapiro 			err = "write W BLOCK";
63240266059SGregory Neil Shapiro 		else
63340266059SGregory Neil Shapiro 			errno = EAGAIN;
63406f25ae9SGregory Neil Shapiro 		break;
63506f25ae9SGregory Neil Shapiro 	  case SSL_ERROR_WANT_READ:
63640266059SGregory Neil Shapiro 		if (--again <= 0)
63706f25ae9SGregory Neil Shapiro 			err = "write R BLOCK";
63840266059SGregory Neil Shapiro 		else
63940266059SGregory Neil Shapiro 			errno = EAGAIN;
64006f25ae9SGregory Neil Shapiro 		break;
64106f25ae9SGregory Neil Shapiro 	  case SSL_ERROR_WANT_X509_LOOKUP:
64206f25ae9SGregory Neil Shapiro 		err = "write X BLOCK";
64306f25ae9SGregory Neil Shapiro 		break;
64406f25ae9SGregory Neil Shapiro 	  case SSL_ERROR_SYSCALL:
64540266059SGregory Neil Shapiro 		if (r == 0 && errno == 0) /* out of protocol EOF found */
64640266059SGregory Neil Shapiro 			break;
64706f25ae9SGregory Neil Shapiro 		err = "syscall error";
64806f25ae9SGregory Neil Shapiro /*
64906f25ae9SGregory Neil Shapiro 		get_last_socket_error());
65006f25ae9SGregory Neil Shapiro */
65106f25ae9SGregory Neil Shapiro 		break;
65206f25ae9SGregory Neil Shapiro 	  case SSL_ERROR_SSL:
65306f25ae9SGregory Neil Shapiro 		err = "generic SSL error";
65406f25ae9SGregory Neil Shapiro /*
65506f25ae9SGregory Neil Shapiro 		ERR_GET_REASON(ERR_peek_error()));
65606f25ae9SGregory Neil Shapiro */
65740266059SGregory Neil Shapiro 		if (LogLevel > 9)
65840266059SGregory Neil Shapiro 			tlslogerr("write");
659959366dcSGregory Neil Shapiro 
660959366dcSGregory Neil Shapiro #if _FFR_DEAL_WITH_ERROR_SSL
661959366dcSGregory Neil Shapiro 		/* avoid repeated calls? */
662959366dcSGregory Neil Shapiro 		if (r == 0)
663959366dcSGregory Neil Shapiro 			r = -1;
664959366dcSGregory Neil Shapiro #endif /* _FFR_DEAL_WITH_ERROR_SSL */
66506f25ae9SGregory Neil Shapiro 		break;
66606f25ae9SGregory Neil Shapiro 	}
66706f25ae9SGregory Neil Shapiro 	if (err != NULL)
66840266059SGregory Neil Shapiro 	{
669605302a5SGregory Neil Shapiro 		int save_errno;
670605302a5SGregory Neil Shapiro 
671605302a5SGregory Neil Shapiro 		save_errno = (errno == 0) ? EIO : errno;
67240266059SGregory Neil Shapiro 		again = MAX_TLS_IOS;
67340266059SGregory Neil Shapiro 		if (LogLevel > 7)
67440266059SGregory Neil Shapiro 			sm_syslog(LOG_WARNING, NOQID,
67540266059SGregory Neil Shapiro 				  "STARTTLS: write error=%s (%d)", err, r);
676605302a5SGregory Neil Shapiro 		errno = save_errno;
67706f25ae9SGregory Neil Shapiro 	}
67806f25ae9SGregory Neil Shapiro 	return r;
67906f25ae9SGregory Neil Shapiro }
68006f25ae9SGregory Neil Shapiro 
68140266059SGregory Neil Shapiro /*
68240266059SGregory Neil Shapiro **  SFDCTLS -- create tls file type and open in and out file pointers
68340266059SGregory Neil Shapiro **	      for sendmail to read from and write to.
68440266059SGregory Neil Shapiro **
68540266059SGregory Neil Shapiro **	Parameters:
68640266059SGregory Neil Shapiro **		fin -- data input source being replaced
68740266059SGregory Neil Shapiro **		fout -- data output source being replaced
68840266059SGregory Neil Shapiro **		conn -- the tls connection pointer
68940266059SGregory Neil Shapiro **
69040266059SGregory Neil Shapiro **	Returns:
69140266059SGregory Neil Shapiro **		-1 on error
69240266059SGregory Neil Shapiro **		0 on success
69340266059SGregory Neil Shapiro **
69440266059SGregory Neil Shapiro **	Side effects:
69540266059SGregory Neil Shapiro **		The arguments "fin" and "fout" are replaced with the new
69640266059SGregory Neil Shapiro **		SM_FILE_T pointers.
69740266059SGregory Neil Shapiro **		The original "fin" and "fout" are preserved in the tls file
69840266059SGregory Neil Shapiro **		type but are not actually used because of the design of TLS.
69940266059SGregory Neil Shapiro */
70006f25ae9SGregory Neil Shapiro 
70106f25ae9SGregory Neil Shapiro int
70206f25ae9SGregory Neil Shapiro sfdctls(fin, fout, con)
70340266059SGregory Neil Shapiro 	SM_FILE_T **fin;
70440266059SGregory Neil Shapiro 	SM_FILE_T **fout;
70506f25ae9SGregory Neil Shapiro 	SSL *con;
70606f25ae9SGregory Neil Shapiro {
70740266059SGregory Neil Shapiro 	SM_FILE_T *tlsin, *tlsout;
70840266059SGregory Neil Shapiro 	SM_FILE_T SM_IO_SET_TYPE(tls_vector, "tls", tls_open, tls_close,
70940266059SGregory Neil Shapiro 		tls_read, tls_write, NULL, tls_getinfo, NULL,
71040266059SGregory Neil Shapiro 		SM_TIME_FOREVER);
71140266059SGregory Neil Shapiro 	struct tls_info info;
71206f25ae9SGregory Neil Shapiro 
71340266059SGregory Neil Shapiro 	SM_ASSERT(con != NULL);
71406f25ae9SGregory Neil Shapiro 
71540266059SGregory Neil Shapiro 	SM_IO_INIT_TYPE(tls_vector, "tls", tls_open, tls_close,
71640266059SGregory Neil Shapiro 		tls_read, tls_write, NULL, tls_getinfo, NULL,
71740266059SGregory Neil Shapiro 		SM_TIME_FOREVER);
71840266059SGregory Neil Shapiro 	info.fp = *fin;
71940266059SGregory Neil Shapiro 	info.con = con;
72040266059SGregory Neil Shapiro 	tlsin = sm_io_open(&tls_vector, SM_TIME_DEFAULT, &info, SM_IO_RDONLY,
72140266059SGregory Neil Shapiro 			   NULL);
72240266059SGregory Neil Shapiro 	if (tlsin == NULL)
72340266059SGregory Neil Shapiro 		return -1;
72406f25ae9SGregory Neil Shapiro 
72540266059SGregory Neil Shapiro 	info.fp = *fout;
72640266059SGregory Neil Shapiro 	tlsout = sm_io_open(&tls_vector, SM_TIME_DEFAULT, &info, SM_IO_WRONLY,
72740266059SGregory Neil Shapiro 			    NULL);
72840266059SGregory Neil Shapiro 	if (tlsout == NULL)
72942e5d165SGregory Neil Shapiro 	{
73040266059SGregory Neil Shapiro 		(void) sm_io_close(tlsin, SM_TIME_DEFAULT);
73142e5d165SGregory Neil Shapiro 		return -1;
73242e5d165SGregory Neil Shapiro 	}
73340266059SGregory Neil Shapiro 	sm_io_automode(tlsin, tlsout);
73406f25ae9SGregory Neil Shapiro 
73540266059SGregory Neil Shapiro 	*fin = tlsin;
73640266059SGregory Neil Shapiro 	*fout = tlsout;
73706f25ae9SGregory Neil Shapiro 	return 0;
73806f25ae9SGregory Neil Shapiro }
73940266059SGregory Neil Shapiro #endif /* STARTTLS */
740