xref: /freebsd/contrib/sendmail/src/sfsasl.c (revision da7d7b9c861cf98e912c0bd1e549752d2dae4fb6)
106f25ae9SGregory Neil Shapiro /*
25dd76dd0SGregory Neil Shapiro  * Copyright (c) 1999-2006, 2008 Proofpoint, 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>
124313cc83SGregory Neil Shapiro SM_RCSID("@(#)$Id: sfsasl.c,v 8.121 2013-11-22 20:51:56 ca Exp $")
1306f25ae9SGregory Neil Shapiro #include <stdlib.h>
1406f25ae9SGregory Neil Shapiro #include <sendmail.h>
15af9557fdSGregory Neil Shapiro #include <sm/time.h>
16*da7d7b9cSGregory Neil Shapiro #include <sm/fdset.h>
1740266059SGregory Neil Shapiro #include <errno.h>
18b6bacd31SGregory Neil Shapiro 
19b6bacd31SGregory Neil Shapiro /* allow to disable error handling code just in case... */
20b6bacd31SGregory Neil Shapiro #ifndef DEAL_WITH_ERROR_SSL
21b6bacd31SGregory Neil Shapiro # define DEAL_WITH_ERROR_SSL	1
22b6bacd31SGregory Neil Shapiro #endif /* ! DEAL_WITH_ERROR_SSL */
23b6bacd31SGregory Neil Shapiro 
2440266059SGregory Neil Shapiro #if SASL
2506f25ae9SGregory Neil Shapiro # include "sfsasl.h"
2606f25ae9SGregory Neil Shapiro 
2740266059SGregory Neil Shapiro /* Structure used by the "sasl" file type */
2840266059SGregory Neil Shapiro struct sasl_obj
2940266059SGregory Neil Shapiro {
3040266059SGregory Neil Shapiro 	SM_FILE_T *fp;
3140266059SGregory Neil Shapiro 	sasl_conn_t *conn;
3240266059SGregory Neil Shapiro };
3340266059SGregory Neil Shapiro 
3440266059SGregory Neil Shapiro struct sasl_info
3540266059SGregory Neil Shapiro {
3640266059SGregory Neil Shapiro 	SM_FILE_T *fp;
3740266059SGregory Neil Shapiro 	sasl_conn_t *conn;
3840266059SGregory Neil Shapiro };
3940266059SGregory Neil Shapiro 
4040266059SGregory Neil Shapiro /*
4140266059SGregory Neil Shapiro **  SASL_GETINFO - returns requested information about a "sasl" file
4240266059SGregory Neil Shapiro **		  descriptor.
4340266059SGregory Neil Shapiro **
4440266059SGregory Neil Shapiro **	Parameters:
4540266059SGregory Neil Shapiro **		fp -- the file descriptor
4640266059SGregory Neil Shapiro **		what -- the type of information requested
4740266059SGregory Neil Shapiro **		valp -- the thang to return the information in
4840266059SGregory Neil Shapiro **
4940266059SGregory Neil Shapiro **	Returns:
5040266059SGregory Neil Shapiro **		-1 for unknown requests
5140266059SGregory Neil Shapiro **		>=0 on success with valp filled in (if possible).
5240266059SGregory Neil Shapiro */
5340266059SGregory Neil Shapiro 
5440266059SGregory Neil Shapiro static int sasl_getinfo __P((SM_FILE_T *, int, void *));
5540266059SGregory Neil Shapiro 
5640266059SGregory Neil Shapiro static int
5740266059SGregory Neil Shapiro sasl_getinfo(fp, what, valp)
5840266059SGregory Neil Shapiro 	SM_FILE_T *fp;
5940266059SGregory Neil Shapiro 	int what;
6040266059SGregory Neil Shapiro 	void *valp;
6140266059SGregory Neil Shapiro {
6240266059SGregory Neil Shapiro 	struct sasl_obj *so = (struct sasl_obj *) fp->f_cookie;
6340266059SGregory Neil Shapiro 
6440266059SGregory Neil Shapiro 	switch (what)
6540266059SGregory Neil Shapiro 	{
6640266059SGregory Neil Shapiro 	  case SM_IO_WHAT_FD:
6740266059SGregory Neil Shapiro 		if (so->fp == NULL)
6840266059SGregory Neil Shapiro 			return -1;
6940266059SGregory Neil Shapiro 		return so->fp->f_file; /* for stdio fileno() compatability */
7040266059SGregory Neil Shapiro 
7140266059SGregory Neil Shapiro 	  case SM_IO_IS_READABLE:
7240266059SGregory Neil Shapiro 		if (so->fp == NULL)
7340266059SGregory Neil Shapiro 			return 0;
7440266059SGregory Neil Shapiro 
7540266059SGregory Neil Shapiro 		/* get info from underlying file */
7640266059SGregory Neil Shapiro 		return sm_io_getinfo(so->fp, what, valp);
7740266059SGregory Neil Shapiro 
7840266059SGregory Neil Shapiro 	  default:
7940266059SGregory Neil Shapiro 		return -1;
8040266059SGregory Neil Shapiro 	}
8140266059SGregory Neil Shapiro }
8240266059SGregory Neil Shapiro 
8340266059SGregory Neil Shapiro /*
8440266059SGregory Neil Shapiro **  SASL_OPEN -- creates the sasl specific information for opening a
8540266059SGregory Neil Shapiro **		file of the sasl type.
8640266059SGregory Neil Shapiro **
8740266059SGregory Neil Shapiro **	Parameters:
8840266059SGregory Neil Shapiro **		fp -- the file pointer associated with the new open
8940266059SGregory Neil Shapiro **		info -- contains the sasl connection information pointer and
9040266059SGregory Neil Shapiro **			the original SM_FILE_T that holds the open
9140266059SGregory Neil Shapiro **		flags -- ignored
9240266059SGregory Neil Shapiro **		rpool -- ignored
9340266059SGregory Neil Shapiro **
9440266059SGregory Neil Shapiro **	Returns:
9540266059SGregory Neil Shapiro **		0 on success
9640266059SGregory Neil Shapiro */
9740266059SGregory Neil Shapiro 
9840266059SGregory Neil Shapiro static int sasl_open __P((SM_FILE_T *, const void *, int, const void *));
9940266059SGregory Neil Shapiro 
10040266059SGregory Neil Shapiro /* ARGSUSED2 */
10140266059SGregory Neil Shapiro static int
10240266059SGregory Neil Shapiro sasl_open(fp, info, flags, rpool)
10340266059SGregory Neil Shapiro 	SM_FILE_T *fp;
10440266059SGregory Neil Shapiro 	const void *info;
10540266059SGregory Neil Shapiro 	int flags;
10640266059SGregory Neil Shapiro 	const void *rpool;
10740266059SGregory Neil Shapiro {
10840266059SGregory Neil Shapiro 	struct sasl_obj *so;
10940266059SGregory Neil Shapiro 	struct sasl_info *si = (struct sasl_info *) info;
11040266059SGregory Neil Shapiro 
11140266059SGregory Neil Shapiro 	so = (struct sasl_obj *) sm_malloc(sizeof(struct sasl_obj));
112a7ec597cSGregory Neil Shapiro 	if (so == NULL)
113a7ec597cSGregory Neil Shapiro 	{
114a7ec597cSGregory Neil Shapiro 		errno = ENOMEM;
115a7ec597cSGregory Neil Shapiro 		return -1;
116a7ec597cSGregory Neil Shapiro 	}
11740266059SGregory Neil Shapiro 	so->fp = si->fp;
11840266059SGregory Neil Shapiro 	so->conn = si->conn;
11940266059SGregory Neil Shapiro 
12040266059SGregory Neil Shapiro 	/*
12140266059SGregory Neil Shapiro 	**  The underlying 'fp' is set to SM_IO_NOW so that the entire
12240266059SGregory Neil Shapiro 	**  encoded string is written in one chunk. Otherwise there is
12340266059SGregory Neil Shapiro 	**  the possibility that it may appear illegal, bogus or
12440266059SGregory Neil Shapiro 	**  mangled to the other side of the connection.
12540266059SGregory Neil Shapiro 	**  We will read or write through 'fp' since it is the opaque
12640266059SGregory Neil Shapiro 	**  connection for the communications. We need to treat it this
12740266059SGregory Neil Shapiro 	**  way in case the encoded string is to be sent down a TLS
12840266059SGregory Neil Shapiro 	**  connection rather than, say, sm_io's stdio.
12940266059SGregory Neil Shapiro 	*/
13040266059SGregory Neil Shapiro 
13140266059SGregory Neil Shapiro 	(void) sm_io_setvbuf(so->fp, SM_TIME_DEFAULT, NULL, SM_IO_NOW, 0);
13240266059SGregory Neil Shapiro 	fp->f_cookie = so;
13340266059SGregory Neil Shapiro 	return 0;
13440266059SGregory Neil Shapiro }
13540266059SGregory Neil Shapiro 
13640266059SGregory Neil Shapiro /*
13740266059SGregory Neil Shapiro **  SASL_CLOSE -- close the sasl specific parts of the sasl file pointer
13840266059SGregory Neil Shapiro **
13940266059SGregory Neil Shapiro **	Parameters:
14040266059SGregory Neil Shapiro **		fp -- the file pointer to close
14140266059SGregory Neil Shapiro **
14240266059SGregory Neil Shapiro **	Returns:
14340266059SGregory Neil Shapiro **		0 on success
14440266059SGregory Neil Shapiro */
14540266059SGregory Neil Shapiro 
14640266059SGregory Neil Shapiro static int sasl_close __P((SM_FILE_T *));
14740266059SGregory Neil Shapiro 
14840266059SGregory Neil Shapiro static int
14940266059SGregory Neil Shapiro sasl_close(fp)
15040266059SGregory Neil Shapiro 	SM_FILE_T *fp;
15140266059SGregory Neil Shapiro {
15240266059SGregory Neil Shapiro 	struct sasl_obj *so;
15340266059SGregory Neil Shapiro 
15440266059SGregory Neil Shapiro 	so = (struct sasl_obj *) fp->f_cookie;
155a7ec597cSGregory Neil Shapiro 	if (so == NULL)
156a7ec597cSGregory Neil Shapiro 		return 0;
15740266059SGregory Neil Shapiro 	if (so->fp != NULL)
15840266059SGregory Neil Shapiro 	{
15940266059SGregory Neil Shapiro 		sm_io_close(so->fp, SM_TIME_DEFAULT);
16040266059SGregory Neil Shapiro 		so->fp = NULL;
16140266059SGregory Neil Shapiro 	}
16240266059SGregory Neil Shapiro 	sm_free(so);
16340266059SGregory Neil Shapiro 	so = NULL;
16440266059SGregory Neil Shapiro 	return 0;
16540266059SGregory Neil Shapiro }
16640266059SGregory Neil Shapiro 
167193538b7SGregory Neil Shapiro /* how to deallocate a buffer allocated by SASL */
16840266059SGregory Neil Shapiro extern void	sm_sasl_free __P((void *));
16940266059SGregory Neil Shapiro #  define SASL_DEALLOC(b)	sm_sasl_free(b)
17040266059SGregory Neil Shapiro 
17140266059SGregory Neil Shapiro /*
17240266059SGregory Neil Shapiro **  SASL_READ -- read encrypted information and decrypt it for the caller
17340266059SGregory Neil Shapiro **
17440266059SGregory Neil Shapiro **	Parameters:
17540266059SGregory Neil Shapiro **		fp -- the file pointer
17640266059SGregory Neil Shapiro **		buf -- the location to place the decrypted information
17740266059SGregory Neil Shapiro **		size -- the number of bytes to read after decryption
17840266059SGregory Neil Shapiro **
17940266059SGregory Neil Shapiro **	Results:
18040266059SGregory Neil Shapiro **		-1 on error
18140266059SGregory Neil Shapiro **		otherwise the number of bytes read
18240266059SGregory Neil Shapiro */
18340266059SGregory Neil Shapiro 
18440266059SGregory Neil Shapiro static ssize_t sasl_read __P((SM_FILE_T *, char *, size_t));
185193538b7SGregory Neil Shapiro 
18606f25ae9SGregory Neil Shapiro static ssize_t
18740266059SGregory Neil Shapiro sasl_read(fp, buf, size)
18840266059SGregory Neil Shapiro 	SM_FILE_T *fp;
18940266059SGregory Neil Shapiro 	char *buf;
19006f25ae9SGregory Neil Shapiro 	size_t size;
19106f25ae9SGregory Neil Shapiro {
19240266059SGregory Neil Shapiro 	int result;
19340266059SGregory Neil Shapiro 	ssize_t len;
19494c01205SGregory Neil Shapiro # if SASL >= 20000
19513bd1963SGregory Neil Shapiro 	static const char *outbuf = NULL;
19694c01205SGregory Neil Shapiro # else /* SASL >= 20000 */
197193538b7SGregory Neil Shapiro 	static char *outbuf = NULL;
19894c01205SGregory Neil Shapiro # endif /* SASL >= 20000 */
199193538b7SGregory Neil Shapiro 	static unsigned int outlen = 0;
200193538b7SGregory Neil Shapiro 	static unsigned int offset = 0;
20140266059SGregory Neil Shapiro 	struct sasl_obj *so = (struct sasl_obj *) fp->f_cookie;
20206f25ae9SGregory Neil Shapiro 
203193538b7SGregory Neil Shapiro 	/*
204193538b7SGregory Neil Shapiro 	**  sasl_decode() may require more data than a single read() returns.
205193538b7SGregory Neil Shapiro 	**  Hence we have to put a loop around the decoding.
206193538b7SGregory Neil Shapiro 	**  This also requires that we may have to split up the returned
207193538b7SGregory Neil Shapiro 	**  data since it might be larger than the allowed size.
208193538b7SGregory Neil Shapiro 	**  Therefore we use a static pointer and return portions of it
209193538b7SGregory Neil Shapiro 	**  if necessary.
210a7ec597cSGregory Neil Shapiro 	**  XXX Note: This function is not thread-safe nor can it be used
211a7ec597cSGregory Neil Shapiro 	**  on more than one file. A correct implementation would store
212a7ec597cSGregory Neil Shapiro 	**  this data in fp->f_cookie.
213193538b7SGregory Neil Shapiro 	*/
21406f25ae9SGregory Neil Shapiro 
21513bd1963SGregory Neil Shapiro # if SASL >= 20000
21613bd1963SGregory Neil Shapiro 	while (outlen == 0)
21713bd1963SGregory Neil Shapiro # else /* SASL >= 20000 */
218193538b7SGregory Neil Shapiro 	while (outbuf == NULL && outlen == 0)
21913bd1963SGregory Neil Shapiro # endif /* SASL >= 20000 */
220193538b7SGregory Neil Shapiro 	{
22140266059SGregory Neil Shapiro 		len = sm_io_read(so->fp, SM_TIME_DEFAULT, buf, size);
22206f25ae9SGregory Neil Shapiro 		if (len <= 0)
22306f25ae9SGregory Neil Shapiro 			return len;
22440266059SGregory Neil Shapiro 		result = sasl_decode(so->conn, buf,
22540266059SGregory Neil Shapiro 				     (unsigned int) len, &outbuf, &outlen);
22606f25ae9SGregory Neil Shapiro 		if (result != SASL_OK)
22706f25ae9SGregory Neil Shapiro 		{
2284e4196cbSGregory Neil Shapiro 			if (LogLevel > 7)
2294e4196cbSGregory Neil Shapiro 				sm_syslog(LOG_WARNING, NOQID,
2304e4196cbSGregory Neil Shapiro 					"AUTH: sasl_decode error=%d", result);
231193538b7SGregory Neil Shapiro 			outbuf = NULL;
232193538b7SGregory Neil Shapiro 			offset = 0;
233193538b7SGregory Neil Shapiro 			outlen = 0;
23406f25ae9SGregory Neil Shapiro 			return -1;
23506f25ae9SGregory Neil Shapiro 		}
236193538b7SGregory Neil Shapiro 	}
23706f25ae9SGregory Neil Shapiro 
23840266059SGregory Neil Shapiro 	if (outbuf == NULL)
23906f25ae9SGregory Neil Shapiro 	{
24040266059SGregory Neil Shapiro 		/* be paranoid: outbuf == NULL but outlen != 0 */
24140266059SGregory Neil Shapiro 		syserr("@sasl_read failure: outbuf == NULL but outlen != 0");
24240266059SGregory Neil Shapiro 		/* NOTREACHED */
24340266059SGregory Neil Shapiro 	}
244193538b7SGregory Neil Shapiro 	if (outlen - offset > size)
245193538b7SGregory Neil Shapiro 	{
246193538b7SGregory Neil Shapiro 		/* return another part of the buffer */
24740266059SGregory Neil Shapiro 		(void) memcpy(buf, outbuf + offset, size);
248193538b7SGregory Neil Shapiro 		offset += size;
24940266059SGregory Neil Shapiro 		len = size;
25006f25ae9SGregory Neil Shapiro 	}
251193538b7SGregory Neil Shapiro 	else
252193538b7SGregory Neil Shapiro 	{
253193538b7SGregory Neil Shapiro 		/* return the rest of the buffer */
25440266059SGregory Neil Shapiro 		len = outlen - offset;
25540266059SGregory Neil Shapiro 		(void) memcpy(buf, outbuf + offset, (size_t) len);
25694c01205SGregory Neil Shapiro # if SASL < 20000
257193538b7SGregory Neil Shapiro 		SASL_DEALLOC(outbuf);
25894c01205SGregory Neil Shapiro # endif /* SASL < 20000 */
259193538b7SGregory Neil Shapiro 		outbuf = NULL;
260193538b7SGregory Neil Shapiro 		offset = 0;
261193538b7SGregory Neil Shapiro 		outlen = 0;
262193538b7SGregory Neil Shapiro 	}
26340266059SGregory Neil Shapiro 	return len;
26406f25ae9SGregory Neil Shapiro }
26506f25ae9SGregory Neil Shapiro 
26640266059SGregory Neil Shapiro /*
26740266059SGregory Neil Shapiro **  SASL_WRITE -- write information out after encrypting it
26840266059SGregory Neil Shapiro **
26940266059SGregory Neil Shapiro **	Parameters:
27040266059SGregory Neil Shapiro **		fp -- the file pointer
27140266059SGregory Neil Shapiro **		buf -- holds the data to be encrypted and written
27240266059SGregory Neil Shapiro **		size -- the number of bytes to have encrypted and written
27340266059SGregory Neil Shapiro **
27440266059SGregory Neil Shapiro **	Returns:
27540266059SGregory Neil Shapiro **		-1 on error
27640266059SGregory Neil Shapiro **		otherwise number of bytes written
27740266059SGregory Neil Shapiro */
27840266059SGregory Neil Shapiro 
27940266059SGregory Neil Shapiro static ssize_t sasl_write __P((SM_FILE_T *, const char *, size_t));
28040266059SGregory Neil Shapiro 
28106f25ae9SGregory Neil Shapiro static ssize_t
28240266059SGregory Neil Shapiro sasl_write(fp, buf, size)
28340266059SGregory Neil Shapiro 	SM_FILE_T *fp;
28440266059SGregory Neil Shapiro 	const char *buf;
28506f25ae9SGregory Neil Shapiro 	size_t size;
28606f25ae9SGregory Neil Shapiro {
28706f25ae9SGregory Neil Shapiro 	int result;
28894c01205SGregory Neil Shapiro # if SASL >= 20000
28994c01205SGregory Neil Shapiro 	const char *outbuf;
29094c01205SGregory Neil Shapiro # else /* SASL >= 20000 */
29106f25ae9SGregory Neil Shapiro 	char *outbuf;
29294c01205SGregory Neil Shapiro # endif /* SASL >= 20000 */
293b6bacd31SGregory Neil Shapiro 	unsigned int outlen, *maxencode;
29440266059SGregory Neil Shapiro 	size_t ret = 0, total = 0;
29540266059SGregory Neil Shapiro 	struct sasl_obj *so = (struct sasl_obj *) fp->f_cookie;
29606f25ae9SGregory Neil Shapiro 
297b6bacd31SGregory Neil Shapiro 	/*
298b6bacd31SGregory Neil Shapiro 	**  Fetch the maximum input buffer size for sasl_encode().
299b6bacd31SGregory Neil Shapiro 	**  This can be less than the size set in attemptauth()
3009bd497b8SGregory Neil Shapiro 	**  due to a negotiation with the other side, e.g.,
301b6bacd31SGregory Neil Shapiro 	**  Cyrus IMAP lmtp program sets maxbuf=4096,
302b6bacd31SGregory Neil Shapiro 	**  digestmd5 substracts 25 and hence we'll get 4071
303b6bacd31SGregory Neil Shapiro 	**  instead of 8192 (MAXOUTLEN).
304b6bacd31SGregory Neil Shapiro 	**  Hack (for now): simply reduce the size, callers are (must be)
305b6bacd31SGregory Neil Shapiro 	**  able to deal with that and invoke sasl_write() again with
306b6bacd31SGregory Neil Shapiro 	**  the rest of the data.
307b6bacd31SGregory Neil Shapiro 	**  Note: it would be better to store this value in the context
308b6bacd31SGregory Neil Shapiro 	**  after the negotiation.
309b6bacd31SGregory Neil Shapiro 	*/
310b6bacd31SGregory Neil Shapiro 
311b6bacd31SGregory Neil Shapiro 	result = sasl_getprop(so->conn, SASL_MAXOUTBUF,
312b6bacd31SGregory Neil Shapiro 				(const void **) &maxencode);
313b6bacd31SGregory Neil Shapiro 	if (result == SASL_OK && size > *maxencode && *maxencode > 0)
314b6bacd31SGregory Neil Shapiro 		size = *maxencode;
315b6bacd31SGregory Neil Shapiro 
31640266059SGregory Neil Shapiro 	result = sasl_encode(so->conn, buf,
31740266059SGregory Neil Shapiro 			     (unsigned int) size, &outbuf, &outlen);
31806f25ae9SGregory Neil Shapiro 
31906f25ae9SGregory Neil Shapiro 	if (result != SASL_OK)
3204e4196cbSGregory Neil Shapiro 	{
3214e4196cbSGregory Neil Shapiro 		if (LogLevel > 7)
3224e4196cbSGregory Neil Shapiro 			sm_syslog(LOG_WARNING, NOQID,
3234e4196cbSGregory Neil Shapiro 				"AUTH: sasl_encode error=%d", result);
32406f25ae9SGregory Neil Shapiro 		return -1;
3254e4196cbSGregory Neil Shapiro 	}
32606f25ae9SGregory Neil Shapiro 
32706f25ae9SGregory Neil Shapiro 	if (outbuf != NULL)
32806f25ae9SGregory Neil Shapiro 	{
32940266059SGregory Neil Shapiro 		while (outlen > 0)
33040266059SGregory Neil Shapiro 		{
331af9557fdSGregory Neil Shapiro 			errno = 0;
332605302a5SGregory Neil Shapiro 			/* XXX result == 0? */
33340266059SGregory Neil Shapiro 			ret = sm_io_write(so->fp, SM_TIME_DEFAULT,
33440266059SGregory Neil Shapiro 					  &outbuf[total], outlen);
335a7ec597cSGregory Neil Shapiro 			if (ret <= 0)
336a7ec597cSGregory Neil Shapiro 				return ret;
33740266059SGregory Neil Shapiro 			outlen -= ret;
33840266059SGregory Neil Shapiro 			total += ret;
33940266059SGregory Neil Shapiro 		}
34094c01205SGregory Neil Shapiro # if SASL < 20000
341193538b7SGregory Neil Shapiro 		SASL_DEALLOC(outbuf);
34294c01205SGregory Neil Shapiro # endif /* SASL < 20000 */
34306f25ae9SGregory Neil Shapiro 	}
34406f25ae9SGregory Neil Shapiro 	return size;
34506f25ae9SGregory Neil Shapiro }
34606f25ae9SGregory Neil Shapiro 
34740266059SGregory Neil Shapiro /*
34840266059SGregory Neil Shapiro **  SFDCSASL -- create sasl file type and open in and out file pointers
34940266059SGregory Neil Shapiro **	       for sendmail to read from and write to.
35040266059SGregory Neil Shapiro **
35140266059SGregory Neil Shapiro **	Parameters:
35240266059SGregory Neil Shapiro **		fin -- the sm_io file encrypted data to be read from
353af9557fdSGregory Neil Shapiro **		fout -- the sm_io file encrypted data to be written to
35440266059SGregory Neil Shapiro **		conn -- the sasl connection pointer
355af9557fdSGregory Neil Shapiro **		tmo -- timeout
35640266059SGregory Neil Shapiro **
35740266059SGregory Neil Shapiro **	Returns:
35840266059SGregory Neil Shapiro **		-1 on error
35940266059SGregory Neil Shapiro **		0 on success
36040266059SGregory Neil Shapiro **
36140266059SGregory Neil Shapiro **	Side effects:
36240266059SGregory Neil Shapiro **		The arguments "fin" and "fout" are replaced with the new
36340266059SGregory Neil Shapiro **		SM_FILE_T pointers.
36440266059SGregory Neil Shapiro */
36540266059SGregory Neil Shapiro 
36606f25ae9SGregory Neil Shapiro int
367af9557fdSGregory Neil Shapiro sfdcsasl(fin, fout, conn, tmo)
36840266059SGregory Neil Shapiro 	SM_FILE_T **fin;
36940266059SGregory Neil Shapiro 	SM_FILE_T **fout;
37006f25ae9SGregory Neil Shapiro 	sasl_conn_t *conn;
371af9557fdSGregory Neil Shapiro 	int tmo;
37206f25ae9SGregory Neil Shapiro {
37340266059SGregory Neil Shapiro 	SM_FILE_T *newin, *newout;
37440266059SGregory Neil Shapiro 	SM_FILE_T  SM_IO_SET_TYPE(sasl_vector, "sasl", sasl_open, sasl_close,
37540266059SGregory Neil Shapiro 		sasl_read, sasl_write, NULL, sasl_getinfo, NULL,
376af9557fdSGregory Neil Shapiro 		SM_TIME_DEFAULT);
37740266059SGregory Neil Shapiro 	struct sasl_info info;
37806f25ae9SGregory Neil Shapiro 
37906f25ae9SGregory Neil Shapiro 	if (conn == NULL)
38006f25ae9SGregory Neil Shapiro 	{
38106f25ae9SGregory Neil Shapiro 		/* no need to do anything */
38206f25ae9SGregory Neil Shapiro 		return 0;
38306f25ae9SGregory Neil Shapiro 	}
38406f25ae9SGregory Neil Shapiro 
38540266059SGregory Neil Shapiro 	SM_IO_INIT_TYPE(sasl_vector, "sasl", sasl_open, sasl_close,
38640266059SGregory Neil Shapiro 		sasl_read, sasl_write, NULL, sasl_getinfo, NULL,
387af9557fdSGregory Neil Shapiro 		SM_TIME_DEFAULT);
38840266059SGregory Neil Shapiro 	info.fp = *fin;
38940266059SGregory Neil Shapiro 	info.conn = conn;
390e92d3f3fSGregory Neil Shapiro 	newin = sm_io_open(&sasl_vector, SM_TIME_DEFAULT, &info,
391e92d3f3fSGregory Neil Shapiro 			SM_IO_RDONLY_B, NULL);
39206f25ae9SGregory Neil Shapiro 
39340266059SGregory Neil Shapiro 	if (newin == NULL)
39440266059SGregory Neil Shapiro 		return -1;
39506f25ae9SGregory Neil Shapiro 
39640266059SGregory Neil Shapiro 	info.fp = *fout;
39740266059SGregory Neil Shapiro 	info.conn = conn;
398e92d3f3fSGregory Neil Shapiro 	newout = sm_io_open(&sasl_vector, SM_TIME_DEFAULT, &info,
399e92d3f3fSGregory Neil Shapiro 			SM_IO_WRONLY_B, NULL);
40006f25ae9SGregory Neil Shapiro 
40140266059SGregory Neil Shapiro 	if (newout == NULL)
40206f25ae9SGregory Neil Shapiro 	{
40340266059SGregory Neil Shapiro 		(void) sm_io_close(newin, SM_TIME_DEFAULT);
40406f25ae9SGregory Neil Shapiro 		return -1;
40506f25ae9SGregory Neil Shapiro 	}
40640266059SGregory Neil Shapiro 	sm_io_automode(newin, newout);
40740266059SGregory Neil Shapiro 
408af9557fdSGregory Neil Shapiro 	sm_io_setinfo(*fin, SM_IO_WHAT_TIMEOUT, &tmo);
409af9557fdSGregory Neil Shapiro 	sm_io_setinfo(*fout, SM_IO_WHAT_TIMEOUT, &tmo);
410af9557fdSGregory Neil Shapiro 
41140266059SGregory Neil Shapiro 	*fin = newin;
41240266059SGregory Neil Shapiro 	*fout = newout;
41306f25ae9SGregory Neil Shapiro 	return 0;
41406f25ae9SGregory Neil Shapiro }
41540266059SGregory Neil Shapiro #endif /* SASL */
41606f25ae9SGregory Neil Shapiro 
41740266059SGregory Neil Shapiro #if STARTTLS
41806f25ae9SGregory Neil Shapiro # include "sfsasl.h"
41906f25ae9SGregory Neil Shapiro # include <openssl/err.h>
42006f25ae9SGregory Neil Shapiro 
42140266059SGregory Neil Shapiro /* Structure used by the "tls" file type */
42240266059SGregory Neil Shapiro struct tls_obj
42340266059SGregory Neil Shapiro {
42440266059SGregory Neil Shapiro 	SM_FILE_T *fp;
42540266059SGregory Neil Shapiro 	SSL *con;
42640266059SGregory Neil Shapiro };
42740266059SGregory Neil Shapiro 
42840266059SGregory Neil Shapiro struct tls_info
42940266059SGregory Neil Shapiro {
43040266059SGregory Neil Shapiro 	SM_FILE_T *fp;
43140266059SGregory Neil Shapiro 	SSL *con;
43240266059SGregory Neil Shapiro };
43340266059SGregory Neil Shapiro 
43440266059SGregory Neil Shapiro /*
43540266059SGregory Neil Shapiro **  TLS_GETINFO - returns requested information about a "tls" file
43640266059SGregory Neil Shapiro **		 descriptor.
43740266059SGregory Neil Shapiro **
43840266059SGregory Neil Shapiro **	Parameters:
43940266059SGregory Neil Shapiro **		fp -- the file descriptor
44040266059SGregory Neil Shapiro **		what -- the type of information requested
44140266059SGregory Neil Shapiro **		valp -- the thang to return the information in (unused)
44240266059SGregory Neil Shapiro **
44340266059SGregory Neil Shapiro **	Returns:
44440266059SGregory Neil Shapiro **		-1 for unknown requests
44540266059SGregory Neil Shapiro **		>=0 on success with valp filled in (if possible).
44640266059SGregory Neil Shapiro */
44740266059SGregory Neil Shapiro 
44840266059SGregory Neil Shapiro static int tls_getinfo __P((SM_FILE_T *, int, void *));
44940266059SGregory Neil Shapiro 
45040266059SGregory Neil Shapiro /* ARGSUSED2 */
45113058a91SGregory Neil Shapiro static int
45240266059SGregory Neil Shapiro tls_getinfo(fp, what, valp)
45340266059SGregory Neil Shapiro 	SM_FILE_T *fp;
45440266059SGregory Neil Shapiro 	int what;
45540266059SGregory Neil Shapiro 	void *valp;
45640266059SGregory Neil Shapiro {
45740266059SGregory Neil Shapiro 	struct tls_obj *so = (struct tls_obj *) fp->f_cookie;
45840266059SGregory Neil Shapiro 
45940266059SGregory Neil Shapiro 	switch (what)
46040266059SGregory Neil Shapiro 	{
46140266059SGregory Neil Shapiro 	  case SM_IO_WHAT_FD:
46240266059SGregory Neil Shapiro 		if (so->fp == NULL)
46340266059SGregory Neil Shapiro 			return -1;
46440266059SGregory Neil Shapiro 		return so->fp->f_file; /* for stdio fileno() compatability */
46540266059SGregory Neil Shapiro 
46640266059SGregory Neil Shapiro 	  case SM_IO_IS_READABLE:
46740266059SGregory Neil Shapiro 		return SSL_pending(so->con) > 0;
46840266059SGregory Neil Shapiro 
46940266059SGregory Neil Shapiro 	  default:
47040266059SGregory Neil Shapiro 		return -1;
47140266059SGregory Neil Shapiro 	}
47240266059SGregory Neil Shapiro }
47340266059SGregory Neil Shapiro 
47440266059SGregory Neil Shapiro /*
47540266059SGregory Neil Shapiro **  TLS_OPEN -- creates the tls specific information for opening a
47640266059SGregory Neil Shapiro **	       file of the tls type.
47740266059SGregory Neil Shapiro **
47840266059SGregory Neil Shapiro **	Parameters:
47940266059SGregory Neil Shapiro **		fp -- the file pointer associated with the new open
48040266059SGregory Neil Shapiro **		info -- the sm_io file pointer holding the open and the
48140266059SGregory Neil Shapiro **			TLS encryption connection to be read from or written to
48240266059SGregory Neil Shapiro **		flags -- ignored
48340266059SGregory Neil Shapiro **		rpool -- ignored
48440266059SGregory Neil Shapiro **
48540266059SGregory Neil Shapiro **	Returns:
48640266059SGregory Neil Shapiro **		0 on success
48740266059SGregory Neil Shapiro */
48840266059SGregory Neil Shapiro 
48940266059SGregory Neil Shapiro static int tls_open __P((SM_FILE_T *, const void *, int, const void *));
49040266059SGregory Neil Shapiro 
49140266059SGregory Neil Shapiro /* ARGSUSED2 */
49240266059SGregory Neil Shapiro static int
49340266059SGregory Neil Shapiro tls_open(fp, info, flags, rpool)
49440266059SGregory Neil Shapiro 	SM_FILE_T *fp;
49540266059SGregory Neil Shapiro 	const void *info;
49640266059SGregory Neil Shapiro 	int flags;
49740266059SGregory Neil Shapiro 	const void *rpool;
49840266059SGregory Neil Shapiro {
49940266059SGregory Neil Shapiro 	struct tls_obj *so;
50040266059SGregory Neil Shapiro 	struct tls_info *ti = (struct tls_info *) info;
50140266059SGregory Neil Shapiro 
50240266059SGregory Neil Shapiro 	so = (struct tls_obj *) sm_malloc(sizeof(struct tls_obj));
503a7ec597cSGregory Neil Shapiro 	if (so == NULL)
504a7ec597cSGregory Neil Shapiro 	{
505a7ec597cSGregory Neil Shapiro 		errno = ENOMEM;
506a7ec597cSGregory Neil Shapiro 		return -1;
507a7ec597cSGregory Neil Shapiro 	}
50840266059SGregory Neil Shapiro 	so->fp = ti->fp;
50940266059SGregory Neil Shapiro 	so->con = ti->con;
51040266059SGregory Neil Shapiro 
51140266059SGregory Neil Shapiro 	/*
51240266059SGregory Neil Shapiro 	**  We try to get the "raw" file descriptor that TLS uses to
51340266059SGregory Neil Shapiro 	**  do the actual read/write with. This is to allow us control
51440266059SGregory Neil Shapiro 	**  over the file descriptor being a blocking or non-blocking type.
51540266059SGregory Neil Shapiro 	**  Under the covers TLS handles the change and this allows us
51640266059SGregory Neil Shapiro 	**  to do timeouts with sm_io.
51740266059SGregory Neil Shapiro 	*/
51840266059SGregory Neil Shapiro 
51940266059SGregory Neil Shapiro 	fp->f_file = sm_io_getinfo(so->fp, SM_IO_WHAT_FD, NULL);
52040266059SGregory Neil Shapiro 	(void) sm_io_setvbuf(so->fp, SM_TIME_DEFAULT, NULL, SM_IO_NOW, 0);
52140266059SGregory Neil Shapiro 	fp->f_cookie = so;
52240266059SGregory Neil Shapiro 	return 0;
52340266059SGregory Neil Shapiro }
52440266059SGregory Neil Shapiro 
52540266059SGregory Neil Shapiro /*
52640266059SGregory Neil Shapiro **  TLS_CLOSE -- close the tls specific parts of the tls file pointer
52740266059SGregory Neil Shapiro **
52840266059SGregory Neil Shapiro **	Parameters:
52940266059SGregory Neil Shapiro **		fp -- the file pointer to close
53040266059SGregory Neil Shapiro **
53140266059SGregory Neil Shapiro **	Returns:
53240266059SGregory Neil Shapiro **		0 on success
53340266059SGregory Neil Shapiro */
53440266059SGregory Neil Shapiro 
53540266059SGregory Neil Shapiro static int tls_close __P((SM_FILE_T *));
53640266059SGregory Neil Shapiro 
53740266059SGregory Neil Shapiro static int
53840266059SGregory Neil Shapiro tls_close(fp)
53940266059SGregory Neil Shapiro 	SM_FILE_T *fp;
54040266059SGregory Neil Shapiro {
54140266059SGregory Neil Shapiro 	struct tls_obj *so;
54240266059SGregory Neil Shapiro 
54340266059SGregory Neil Shapiro 	so = (struct tls_obj *) fp->f_cookie;
544a7ec597cSGregory Neil Shapiro 	if (so == NULL)
545a7ec597cSGregory Neil Shapiro 		return 0;
54640266059SGregory Neil Shapiro 	if (so->fp != NULL)
54740266059SGregory Neil Shapiro 	{
54840266059SGregory Neil Shapiro 		sm_io_close(so->fp, SM_TIME_DEFAULT);
54940266059SGregory Neil Shapiro 		so->fp = NULL;
55040266059SGregory Neil Shapiro 	}
55140266059SGregory Neil Shapiro 	sm_free(so);
55240266059SGregory Neil Shapiro 	so = NULL;
55340266059SGregory Neil Shapiro 	return 0;
55440266059SGregory Neil Shapiro }
55540266059SGregory Neil Shapiro 
55640266059SGregory Neil Shapiro /* maximum number of retries for TLS related I/O due to handshakes */
55740266059SGregory Neil Shapiro # define MAX_TLS_IOS	4
55840266059SGregory Neil Shapiro 
55940266059SGregory Neil Shapiro /*
5604e4196cbSGregory Neil Shapiro **  TLS_RETRY -- check whether a failed SSL operation can be retried
5614e4196cbSGregory Neil Shapiro **
5624e4196cbSGregory Neil Shapiro **	Parameters:
5634e4196cbSGregory Neil Shapiro **		ssl -- TLS structure
5644e4196cbSGregory Neil Shapiro **		rfd -- read fd
5654e4196cbSGregory Neil Shapiro **		wfd -- write fd
5664e4196cbSGregory Neil Shapiro **		tlsstart -- start time of TLS operation
5674e4196cbSGregory Neil Shapiro **		timeout -- timeout for TLS operation
5684e4196cbSGregory Neil Shapiro **		err -- SSL error
5694e4196cbSGregory Neil Shapiro **		where -- description of operation
5704e4196cbSGregory Neil Shapiro **
5714e4196cbSGregory Neil Shapiro **	Results:
5724e4196cbSGregory Neil Shapiro **		>0 on success
5734e4196cbSGregory Neil Shapiro **		0 on timeout
5744e4196cbSGregory Neil Shapiro **		<0 on error
5754e4196cbSGregory Neil Shapiro */
5764e4196cbSGregory Neil Shapiro 
5774e4196cbSGregory Neil Shapiro int
5784e4196cbSGregory Neil Shapiro tls_retry(ssl, rfd, wfd, tlsstart, timeout, err, where)
5794e4196cbSGregory Neil Shapiro 	SSL *ssl;
5804e4196cbSGregory Neil Shapiro 	int rfd;
5814e4196cbSGregory Neil Shapiro 	int wfd;
5824e4196cbSGregory Neil Shapiro 	time_t tlsstart;
5834e4196cbSGregory Neil Shapiro 	int timeout;
5844e4196cbSGregory Neil Shapiro 	int err;
5854e4196cbSGregory Neil Shapiro 	const char *where;
5864e4196cbSGregory Neil Shapiro {
5874e4196cbSGregory Neil Shapiro 	int ret;
5884e4196cbSGregory Neil Shapiro 	time_t left;
5894e4196cbSGregory Neil Shapiro 	time_t now = curtime();
5904e4196cbSGregory Neil Shapiro 	struct timeval tv;
5914e4196cbSGregory Neil Shapiro 
5924e4196cbSGregory Neil Shapiro 	ret = -1;
5934e4196cbSGregory Neil Shapiro 
5944e4196cbSGregory Neil Shapiro 	/*
5954e4196cbSGregory Neil Shapiro 	**  For SSL_ERROR_WANT_{READ,WRITE}:
5964e4196cbSGregory Neil Shapiro 	**  There is not a complete SSL record available yet
5974e4196cbSGregory Neil Shapiro 	**  or there is only a partial SSL record removed from
5984e4196cbSGregory Neil Shapiro 	**  the network (socket) buffer into the SSL buffer.
5994e4196cbSGregory Neil Shapiro 	**  The SSL_connect will only succeed when a full
6004e4196cbSGregory Neil Shapiro 	**  SSL record is available (assuming a "real" error
6014e4196cbSGregory Neil Shapiro 	**  doesn't happen). To handle when a "real" error
6024e4196cbSGregory Neil Shapiro 	**  does happen the select is set for exceptions too.
6034e4196cbSGregory Neil Shapiro 	**  The connection may be re-negotiated during this time
6044e4196cbSGregory Neil Shapiro 	**  so both read and write "want errors" need to be handled.
6054e4196cbSGregory Neil Shapiro 	**  A select() exception loops back so that a proper SSL
6064e4196cbSGregory Neil Shapiro 	**  error message can be gotten.
6074e4196cbSGregory Neil Shapiro 	*/
6084e4196cbSGregory Neil Shapiro 
6094e4196cbSGregory Neil Shapiro 	left = timeout - (now - tlsstart);
6104e4196cbSGregory Neil Shapiro 	if (left <= 0)
6114e4196cbSGregory Neil Shapiro 		return 0;	/* timeout */
6124e4196cbSGregory Neil Shapiro 	tv.tv_sec = left;
6134e4196cbSGregory Neil Shapiro 	tv.tv_usec = 0;
6144e4196cbSGregory Neil Shapiro 
6154e4196cbSGregory Neil Shapiro 	if (LogLevel > 14)
6164e4196cbSGregory Neil Shapiro 	{
6174e4196cbSGregory Neil Shapiro 		sm_syslog(LOG_INFO, NOQID,
6184e4196cbSGregory Neil Shapiro 			  "STARTTLS=%s, info: fds=%d/%d, err=%d",
6194e4196cbSGregory Neil Shapiro 			  where, rfd, wfd, err);
6204e4196cbSGregory Neil Shapiro 	}
6214e4196cbSGregory Neil Shapiro 
622*da7d7b9cSGregory Neil Shapiro 	if ((err == SSL_ERROR_WANT_READ && !SM_FD_OK_SELECT(rfd)) ||
623*da7d7b9cSGregory Neil Shapiro 	    (err == SSL_ERROR_WANT_WRITE && !SM_FD_OK_SELECT(wfd)))
6244e4196cbSGregory Neil Shapiro 	{
6254e4196cbSGregory Neil Shapiro 		if (LogLevel > 5)
6264e4196cbSGregory Neil Shapiro 		{
6274e4196cbSGregory Neil Shapiro 			sm_syslog(LOG_ERR, NOQID,
6284e4196cbSGregory Neil Shapiro 				  "STARTTLS=%s, error: fd %d/%d too large",
6294e4196cbSGregory Neil Shapiro 				  where, rfd, wfd);
6304e4196cbSGregory Neil Shapiro 			if (LogLevel > 8)
631552d4955SGregory Neil Shapiro 				tlslogerr(LOG_WARNING, where);
6324e4196cbSGregory Neil Shapiro 		}
6334e4196cbSGregory Neil Shapiro 		errno = EINVAL;
6344e4196cbSGregory Neil Shapiro 	}
6354e4196cbSGregory Neil Shapiro 	else if (err == SSL_ERROR_WANT_READ)
6364e4196cbSGregory Neil Shapiro 	{
6374e4196cbSGregory Neil Shapiro 		fd_set ssl_maskr, ssl_maskx;
638552d4955SGregory Neil Shapiro 		int save_errno = errno;
6394e4196cbSGregory Neil Shapiro 
6404e4196cbSGregory Neil Shapiro 		FD_ZERO(&ssl_maskr);
6414e4196cbSGregory Neil Shapiro 		FD_SET(rfd, &ssl_maskr);
6424e4196cbSGregory Neil Shapiro 		FD_ZERO(&ssl_maskx);
6434e4196cbSGregory Neil Shapiro 		FD_SET(rfd, &ssl_maskx);
6444e4196cbSGregory Neil Shapiro 		do
6454e4196cbSGregory Neil Shapiro 		{
6464e4196cbSGregory Neil Shapiro 			ret = select(rfd + 1, &ssl_maskr, NULL, &ssl_maskx,
6474e4196cbSGregory Neil Shapiro 					&tv);
6484e4196cbSGregory Neil Shapiro 		} while (ret < 0 && errno == EINTR);
6494e4196cbSGregory Neil Shapiro 		if (ret < 0 && errno > 0)
6504e4196cbSGregory Neil Shapiro 			ret = -errno;
651552d4955SGregory Neil Shapiro 		errno = save_errno;
6524e4196cbSGregory Neil Shapiro 	}
6534e4196cbSGregory Neil Shapiro 	else if (err == SSL_ERROR_WANT_WRITE)
6544e4196cbSGregory Neil Shapiro 	{
6554e4196cbSGregory Neil Shapiro 		fd_set ssl_maskw, ssl_maskx;
656552d4955SGregory Neil Shapiro 		int save_errno = errno;
6574e4196cbSGregory Neil Shapiro 
6584e4196cbSGregory Neil Shapiro 		FD_ZERO(&ssl_maskw);
6594e4196cbSGregory Neil Shapiro 		FD_SET(wfd, &ssl_maskw);
6604e4196cbSGregory Neil Shapiro 		FD_ZERO(&ssl_maskx);
6614e4196cbSGregory Neil Shapiro 		FD_SET(rfd, &ssl_maskx);
6624e4196cbSGregory Neil Shapiro 		do
6634e4196cbSGregory Neil Shapiro 		{
6644e4196cbSGregory Neil Shapiro 			ret = select(wfd + 1, NULL, &ssl_maskw, &ssl_maskx,
6654e4196cbSGregory Neil Shapiro 					&tv);
6664e4196cbSGregory Neil Shapiro 		} while (ret < 0 && errno == EINTR);
6674e4196cbSGregory Neil Shapiro 		if (ret < 0 && errno > 0)
6684e4196cbSGregory Neil Shapiro 			ret = -errno;
669552d4955SGregory Neil Shapiro 		errno = save_errno;
6704e4196cbSGregory Neil Shapiro 	}
6714e4196cbSGregory Neil Shapiro 	return ret;
6724e4196cbSGregory Neil Shapiro }
6734e4196cbSGregory Neil Shapiro 
6744e4196cbSGregory Neil Shapiro /* errno to force refill() etc to stop (see IS_IO_ERROR()) */
6754e4196cbSGregory Neil Shapiro #ifdef ETIMEDOUT
6764e4196cbSGregory Neil Shapiro # define SM_ERR_TIMEOUT	ETIMEDOUT
6774e4196cbSGregory Neil Shapiro #else /* ETIMEDOUT */
6784e4196cbSGregory Neil Shapiro # define SM_ERR_TIMEOUT	EIO
6794e4196cbSGregory Neil Shapiro #endif /* ETIMEDOUT */
6804e4196cbSGregory Neil Shapiro 
6814e4196cbSGregory Neil Shapiro /*
682e3793f76SGregory Neil Shapiro **  SET_TLS_RD_TMO -- read secured information for the caller
683e3793f76SGregory Neil Shapiro **
684e3793f76SGregory Neil Shapiro **	Parameters:
685e3793f76SGregory Neil Shapiro **		rd_tmo -- read timeout
686e3793f76SGregory Neil Shapiro **
687e3793f76SGregory Neil Shapiro **	Results:
688*da7d7b9cSGregory Neil Shapiro **		previous read timeout
689e3793f76SGregory Neil Shapiro **	This is a hack: there is no way to pass it in
690e3793f76SGregory Neil Shapiro */
691e3793f76SGregory Neil Shapiro 
692e3793f76SGregory Neil Shapiro static int tls_rd_tmo = -1;
693e3793f76SGregory Neil Shapiro 
694*da7d7b9cSGregory Neil Shapiro int
695e3793f76SGregory Neil Shapiro set_tls_rd_tmo(rd_tmo)
696e3793f76SGregory Neil Shapiro 	int rd_tmo;
697e3793f76SGregory Neil Shapiro {
698*da7d7b9cSGregory Neil Shapiro 	int old_rd_tmo;
699*da7d7b9cSGregory Neil Shapiro 
700*da7d7b9cSGregory Neil Shapiro 	old_rd_tmo = tls_rd_tmo;
701e3793f76SGregory Neil Shapiro 	tls_rd_tmo = rd_tmo;
702*da7d7b9cSGregory Neil Shapiro 	return old_rd_tmo;
703e3793f76SGregory Neil Shapiro }
704e3793f76SGregory Neil Shapiro 
705e3793f76SGregory Neil Shapiro /*
70640266059SGregory Neil Shapiro **  TLS_READ -- read secured information for the caller
70740266059SGregory Neil Shapiro **
70840266059SGregory Neil Shapiro **	Parameters:
70940266059SGregory Neil Shapiro **		fp -- the file pointer
71040266059SGregory Neil Shapiro **		buf -- the location to place the data
71140266059SGregory Neil Shapiro **		size -- the number of bytes to read from connection
71240266059SGregory Neil Shapiro **
71340266059SGregory Neil Shapiro **	Results:
71440266059SGregory Neil Shapiro **		-1 on error
71540266059SGregory Neil Shapiro **		otherwise the number of bytes read
71640266059SGregory Neil Shapiro */
71740266059SGregory Neil Shapiro 
71840266059SGregory Neil Shapiro static ssize_t tls_read __P((SM_FILE_T *, char *, size_t));
71940266059SGregory Neil Shapiro 
72040266059SGregory Neil Shapiro static ssize_t
72140266059SGregory Neil Shapiro tls_read(fp, buf, size)
72240266059SGregory Neil Shapiro 	SM_FILE_T *fp;
72313058a91SGregory Neil Shapiro 	char *buf;
72440266059SGregory Neil Shapiro 	size_t size;
72506f25ae9SGregory Neil Shapiro {
7264e4196cbSGregory Neil Shapiro 	int r, rfd, wfd, try, ssl_err;
72740266059SGregory Neil Shapiro 	struct tls_obj *so = (struct tls_obj *) fp->f_cookie;
7284e4196cbSGregory Neil Shapiro 	time_t tlsstart;
72906f25ae9SGregory Neil Shapiro 	char *err;
73006f25ae9SGregory Neil Shapiro 
7314e4196cbSGregory Neil Shapiro 	try = 99;
7324e4196cbSGregory Neil Shapiro 	err = NULL;
7334e4196cbSGregory Neil Shapiro 	tlsstart = curtime();
7344e4196cbSGregory Neil Shapiro 
7354e4196cbSGregory Neil Shapiro   retry:
73640266059SGregory Neil Shapiro 	r = SSL_read(so->con, (char *) buf, size);
73740266059SGregory Neil Shapiro 
73840266059SGregory Neil Shapiro 	if (r > 0)
73940266059SGregory Neil Shapiro 		return r;
74040266059SGregory Neil Shapiro 
74106f25ae9SGregory Neil Shapiro 	err = NULL;
7424e4196cbSGregory Neil Shapiro 	switch (ssl_err = SSL_get_error(so->con, r))
74306f25ae9SGregory Neil Shapiro 	{
74406f25ae9SGregory Neil Shapiro 	  case SSL_ERROR_NONE:
74540266059SGregory Neil Shapiro 	  case SSL_ERROR_ZERO_RETURN:
74606f25ae9SGregory Neil Shapiro 		break;
74706f25ae9SGregory Neil Shapiro 	  case SSL_ERROR_WANT_WRITE:
74840266059SGregory Neil Shapiro 		err = "read W BLOCK";
7494e4196cbSGregory Neil Shapiro 		/* FALLTHROUGH */
75006f25ae9SGregory Neil Shapiro 	  case SSL_ERROR_WANT_READ:
7514e4196cbSGregory Neil Shapiro 		if (err == NULL)
75240266059SGregory Neil Shapiro 			err = "read R BLOCK";
7534e4196cbSGregory Neil Shapiro 		rfd = SSL_get_rfd(so->con);
7544e4196cbSGregory Neil Shapiro 		wfd = SSL_get_wfd(so->con);
7554e4196cbSGregory Neil Shapiro 		try = tls_retry(so->con, rfd, wfd, tlsstart,
756e3793f76SGregory Neil Shapiro 				(tls_rd_tmo < 0) ? TimeOuts.to_datablock
757e3793f76SGregory Neil Shapiro 						 : tls_rd_tmo,
758e3793f76SGregory Neil Shapiro 				ssl_err, "read");
7594e4196cbSGregory Neil Shapiro 		if (try > 0)
7604e4196cbSGregory Neil Shapiro 			goto retry;
7614e4196cbSGregory Neil Shapiro 		errno = SM_ERR_TIMEOUT;
76206f25ae9SGregory Neil Shapiro 		break;
7634e4196cbSGregory Neil Shapiro 
76406f25ae9SGregory Neil Shapiro 	  case SSL_ERROR_WANT_X509_LOOKUP:
76506f25ae9SGregory Neil Shapiro 		err = "write X BLOCK";
76606f25ae9SGregory Neil Shapiro 		break;
76706f25ae9SGregory Neil Shapiro 	  case SSL_ERROR_SYSCALL:
76840266059SGregory Neil Shapiro 		if (r == 0 && errno == 0) /* out of protocol EOF found */
76940266059SGregory Neil Shapiro 			break;
77006f25ae9SGregory Neil Shapiro 		err = "syscall error";
77106f25ae9SGregory Neil Shapiro /*
77206f25ae9SGregory Neil Shapiro 		get_last_socket_error());
77306f25ae9SGregory Neil Shapiro */
77406f25ae9SGregory Neil Shapiro 		break;
77506f25ae9SGregory Neil Shapiro 	  case SSL_ERROR_SSL:
776b6bacd31SGregory Neil Shapiro #if DEAL_WITH_ERROR_SSL
777959366dcSGregory Neil Shapiro 		if (r == 0 && errno == 0) /* out of protocol EOF found */
778959366dcSGregory Neil Shapiro 			break;
779b6bacd31SGregory Neil Shapiro #endif /* DEAL_WITH_ERROR_SSL */
78006f25ae9SGregory Neil Shapiro 		err = "generic SSL error";
781552d4955SGregory Neil Shapiro 
78240266059SGregory Neil Shapiro 		if (LogLevel > 9)
783552d4955SGregory Neil Shapiro 		{
784552d4955SGregory Neil Shapiro 			int pri;
785552d4955SGregory Neil Shapiro 
786552d4955SGregory Neil Shapiro 			if (errno == EAGAIN && try > 0)
787552d4955SGregory Neil Shapiro 				pri = LOG_DEBUG;
788552d4955SGregory Neil Shapiro 			else
789552d4955SGregory Neil Shapiro 				pri = LOG_WARNING;
790552d4955SGregory Neil Shapiro 			tlslogerr(pri, "read");
791552d4955SGregory Neil Shapiro 		}
792959366dcSGregory Neil Shapiro 
793b6bacd31SGregory Neil Shapiro #if DEAL_WITH_ERROR_SSL
794959366dcSGregory Neil Shapiro 		/* avoid repeated calls? */
795959366dcSGregory Neil Shapiro 		if (r == 0)
796959366dcSGregory Neil Shapiro 			r = -1;
797b6bacd31SGregory Neil Shapiro #endif /* DEAL_WITH_ERROR_SSL */
79806f25ae9SGregory Neil Shapiro 		break;
79906f25ae9SGregory Neil Shapiro 	}
80006f25ae9SGregory Neil Shapiro 	if (err != NULL)
80140266059SGregory Neil Shapiro 	{
802605302a5SGregory Neil Shapiro 		int save_errno;
803605302a5SGregory Neil Shapiro 
804605302a5SGregory Neil Shapiro 		save_errno = (errno == 0) ? EIO : errno;
8054e4196cbSGregory Neil Shapiro 		if (try == 0 && save_errno == SM_ERR_TIMEOUT)
8064e4196cbSGregory Neil Shapiro 		{
8074e4196cbSGregory Neil Shapiro 			if (LogLevel > 7)
808a7ec597cSGregory Neil Shapiro 				sm_syslog(LOG_WARNING, NOQID,
8094e4196cbSGregory Neil Shapiro 					  "STARTTLS: read error=timeout");
8104e4196cbSGregory Neil Shapiro 		}
8114e4196cbSGregory Neil Shapiro 		else if (LogLevel > 8)
812552d4955SGregory Neil Shapiro 		{
813552d4955SGregory Neil Shapiro 			int pri;
814552d4955SGregory Neil Shapiro 
815552d4955SGregory Neil Shapiro 			if (save_errno == EAGAIN && try > 0)
816552d4955SGregory Neil Shapiro 				pri = LOG_DEBUG;
817552d4955SGregory Neil Shapiro 			else
818552d4955SGregory Neil Shapiro 				pri = LOG_WARNING;
819552d4955SGregory Neil Shapiro 			sm_syslog(pri, NOQID,
8204e4196cbSGregory Neil Shapiro 				  "STARTTLS: read error=%s (%d), errno=%d, get_error=%s, retry=%d, ssl_err=%d",
821a7ec597cSGregory Neil Shapiro 				  err, r, errno,
8224e4196cbSGregory Neil Shapiro 				  ERR_error_string(ERR_get_error(), NULL), try,
8234e4196cbSGregory Neil Shapiro 				  ssl_err);
824552d4955SGregory Neil Shapiro 		}
825a7ec597cSGregory Neil Shapiro 		else if (LogLevel > 7)
82640266059SGregory Neil Shapiro 			sm_syslog(LOG_WARNING, NOQID,
827*da7d7b9cSGregory Neil Shapiro 				  "STARTTLS: read error=%s (%d), errno=%d, retry=%d, ssl_err=%d",
8284e4196cbSGregory Neil Shapiro 				  err, r, errno, try, ssl_err);
829605302a5SGregory Neil Shapiro 		errno = save_errno;
83006f25ae9SGregory Neil Shapiro 	}
83106f25ae9SGregory Neil Shapiro 	return r;
83206f25ae9SGregory Neil Shapiro }
83306f25ae9SGregory Neil Shapiro 
83440266059SGregory Neil Shapiro /*
83540266059SGregory Neil Shapiro **  TLS_WRITE -- write information out through secure connection
83640266059SGregory Neil Shapiro **
83740266059SGregory Neil Shapiro **	Parameters:
83840266059SGregory Neil Shapiro **		fp -- the file pointer
83940266059SGregory Neil Shapiro **		buf -- holds the data to be securely written
84040266059SGregory Neil Shapiro **		size -- the number of bytes to write
84140266059SGregory Neil Shapiro **
84240266059SGregory Neil Shapiro **	Returns:
84340266059SGregory Neil Shapiro **		-1 on error
84440266059SGregory Neil Shapiro **		otherwise number of bytes written
84540266059SGregory Neil Shapiro */
84640266059SGregory Neil Shapiro 
84740266059SGregory Neil Shapiro static ssize_t tls_write __P((SM_FILE_T *, const char *, size_t));
84840266059SGregory Neil Shapiro 
84913058a91SGregory Neil Shapiro static ssize_t
85040266059SGregory Neil Shapiro tls_write(fp, buf, size)
85140266059SGregory Neil Shapiro 	SM_FILE_T *fp;
85213058a91SGregory Neil Shapiro 	const char *buf;
85340266059SGregory Neil Shapiro 	size_t size;
85406f25ae9SGregory Neil Shapiro {
8554e4196cbSGregory Neil Shapiro 	int r, rfd, wfd, try, ssl_err;
85640266059SGregory Neil Shapiro 	struct tls_obj *so = (struct tls_obj *) fp->f_cookie;
8574e4196cbSGregory Neil Shapiro 	time_t tlsstart;
85806f25ae9SGregory Neil Shapiro 	char *err;
85906f25ae9SGregory Neil Shapiro 
8604e4196cbSGregory Neil Shapiro 	try = 99;
8614e4196cbSGregory Neil Shapiro 	err = NULL;
8624e4196cbSGregory Neil Shapiro 	tlsstart = curtime();
8634e4196cbSGregory Neil Shapiro 
8644e4196cbSGregory Neil Shapiro   retry:
86540266059SGregory Neil Shapiro 	r = SSL_write(so->con, (char *) buf, size);
86640266059SGregory Neil Shapiro 
86740266059SGregory Neil Shapiro 	if (r > 0)
86840266059SGregory Neil Shapiro 		return r;
86906f25ae9SGregory Neil Shapiro 	err = NULL;
8704e4196cbSGregory Neil Shapiro 	switch (ssl_err = SSL_get_error(so->con, r))
87106f25ae9SGregory Neil Shapiro 	{
87206f25ae9SGregory Neil Shapiro 	  case SSL_ERROR_NONE:
87340266059SGregory Neil Shapiro 	  case SSL_ERROR_ZERO_RETURN:
87406f25ae9SGregory Neil Shapiro 		break;
87506f25ae9SGregory Neil Shapiro 	  case SSL_ERROR_WANT_WRITE:
8764e4196cbSGregory Neil Shapiro 		err = "read W BLOCK";
8774e4196cbSGregory Neil Shapiro 		/* FALLTHROUGH */
87806f25ae9SGregory Neil Shapiro 	  case SSL_ERROR_WANT_READ:
8794e4196cbSGregory Neil Shapiro 		if (err == NULL)
8804e4196cbSGregory Neil Shapiro 			err = "read R BLOCK";
8814e4196cbSGregory Neil Shapiro 		rfd = SSL_get_rfd(so->con);
8824e4196cbSGregory Neil Shapiro 		wfd = SSL_get_wfd(so->con);
8834e4196cbSGregory Neil Shapiro 		try = tls_retry(so->con, rfd, wfd, tlsstart,
8844e4196cbSGregory Neil Shapiro 				DATA_PROGRESS_TIMEOUT, ssl_err, "write");
8854e4196cbSGregory Neil Shapiro 		if (try > 0)
8864e4196cbSGregory Neil Shapiro 			goto retry;
8874e4196cbSGregory Neil Shapiro 		errno = SM_ERR_TIMEOUT;
88806f25ae9SGregory Neil Shapiro 		break;
88906f25ae9SGregory Neil Shapiro 	  case SSL_ERROR_WANT_X509_LOOKUP:
89006f25ae9SGregory Neil Shapiro 		err = "write X BLOCK";
89106f25ae9SGregory Neil Shapiro 		break;
89206f25ae9SGregory Neil Shapiro 	  case SSL_ERROR_SYSCALL:
89340266059SGregory Neil Shapiro 		if (r == 0 && errno == 0) /* out of protocol EOF found */
89440266059SGregory Neil Shapiro 			break;
89506f25ae9SGregory Neil Shapiro 		err = "syscall error";
89606f25ae9SGregory Neil Shapiro /*
89706f25ae9SGregory Neil Shapiro 		get_last_socket_error());
89806f25ae9SGregory Neil Shapiro */
89906f25ae9SGregory Neil Shapiro 		break;
90006f25ae9SGregory Neil Shapiro 	  case SSL_ERROR_SSL:
90106f25ae9SGregory Neil Shapiro 		err = "generic SSL error";
90206f25ae9SGregory Neil Shapiro /*
90306f25ae9SGregory Neil Shapiro 		ERR_GET_REASON(ERR_peek_error()));
90406f25ae9SGregory Neil Shapiro */
90540266059SGregory Neil Shapiro 		if (LogLevel > 9)
906552d4955SGregory Neil Shapiro 			tlslogerr(LOG_WARNING, "write");
907959366dcSGregory Neil Shapiro 
908b6bacd31SGregory Neil Shapiro #if DEAL_WITH_ERROR_SSL
909959366dcSGregory Neil Shapiro 		/* avoid repeated calls? */
910959366dcSGregory Neil Shapiro 		if (r == 0)
911959366dcSGregory Neil Shapiro 			r = -1;
912b6bacd31SGregory Neil Shapiro #endif /* DEAL_WITH_ERROR_SSL */
91306f25ae9SGregory Neil Shapiro 		break;
91406f25ae9SGregory Neil Shapiro 	}
91506f25ae9SGregory Neil Shapiro 	if (err != NULL)
91640266059SGregory Neil Shapiro 	{
917605302a5SGregory Neil Shapiro 		int save_errno;
918605302a5SGregory Neil Shapiro 
919605302a5SGregory Neil Shapiro 		save_errno = (errno == 0) ? EIO : errno;
9204e4196cbSGregory Neil Shapiro 		if (try == 0 && save_errno == SM_ERR_TIMEOUT)
9214e4196cbSGregory Neil Shapiro 		{
9224e4196cbSGregory Neil Shapiro 			if (LogLevel > 7)
923a7ec597cSGregory Neil Shapiro 				sm_syslog(LOG_WARNING, NOQID,
9244e4196cbSGregory Neil Shapiro 					  "STARTTLS: write error=timeout");
9254e4196cbSGregory Neil Shapiro 		}
9264e4196cbSGregory Neil Shapiro 		else if (LogLevel > 8)
9274e4196cbSGregory Neil Shapiro 			sm_syslog(LOG_WARNING, NOQID,
9284e4196cbSGregory Neil Shapiro 				  "STARTTLS: write error=%s (%d), errno=%d, get_error=%s, retry=%d, ssl_err=%d",
929a7ec597cSGregory Neil Shapiro 				  err, r, errno,
9304e4196cbSGregory Neil Shapiro 				  ERR_error_string(ERR_get_error(), NULL), try,
9314e4196cbSGregory Neil Shapiro 				  ssl_err);
932a7ec597cSGregory Neil Shapiro 		else if (LogLevel > 7)
93340266059SGregory Neil Shapiro 			sm_syslog(LOG_WARNING, NOQID,
9344e4196cbSGregory Neil Shapiro 				  "STARTTLS: write error=%s (%d), errno=%d, retry=%d, ssl_err=%d",
9354e4196cbSGregory Neil Shapiro 				  err, r, errno, try, ssl_err);
936605302a5SGregory Neil Shapiro 		errno = save_errno;
93706f25ae9SGregory Neil Shapiro 	}
93806f25ae9SGregory Neil Shapiro 	return r;
93906f25ae9SGregory Neil Shapiro }
94006f25ae9SGregory Neil Shapiro 
94140266059SGregory Neil Shapiro /*
94240266059SGregory Neil Shapiro **  SFDCTLS -- create tls file type and open in and out file pointers
94340266059SGregory Neil Shapiro **	      for sendmail to read from and write to.
94440266059SGregory Neil Shapiro **
94540266059SGregory Neil Shapiro **	Parameters:
94640266059SGregory Neil Shapiro **		fin -- data input source being replaced
94740266059SGregory Neil Shapiro **		fout -- data output source being replaced
948a7ec597cSGregory Neil Shapiro **		con -- the tls connection pointer
94940266059SGregory Neil Shapiro **
95040266059SGregory Neil Shapiro **	Returns:
95140266059SGregory Neil Shapiro **		-1 on error
95240266059SGregory Neil Shapiro **		0 on success
95340266059SGregory Neil Shapiro **
95440266059SGregory Neil Shapiro **	Side effects:
95540266059SGregory Neil Shapiro **		The arguments "fin" and "fout" are replaced with the new
95640266059SGregory Neil Shapiro **		SM_FILE_T pointers.
95740266059SGregory Neil Shapiro **		The original "fin" and "fout" are preserved in the tls file
95840266059SGregory Neil Shapiro **		type but are not actually used because of the design of TLS.
95940266059SGregory Neil Shapiro */
96006f25ae9SGregory Neil Shapiro 
96106f25ae9SGregory Neil Shapiro int
96206f25ae9SGregory Neil Shapiro sfdctls(fin, fout, con)
96340266059SGregory Neil Shapiro 	SM_FILE_T **fin;
96440266059SGregory Neil Shapiro 	SM_FILE_T **fout;
96506f25ae9SGregory Neil Shapiro 	SSL *con;
96606f25ae9SGregory Neil Shapiro {
96740266059SGregory Neil Shapiro 	SM_FILE_T *tlsin, *tlsout;
96840266059SGregory Neil Shapiro 	SM_FILE_T SM_IO_SET_TYPE(tls_vector, "tls", tls_open, tls_close,
96940266059SGregory Neil Shapiro 		tls_read, tls_write, NULL, tls_getinfo, NULL,
97040266059SGregory Neil Shapiro 		SM_TIME_FOREVER);
97140266059SGregory Neil Shapiro 	struct tls_info info;
97206f25ae9SGregory Neil Shapiro 
97340266059SGregory Neil Shapiro 	SM_ASSERT(con != NULL);
97406f25ae9SGregory Neil Shapiro 
97540266059SGregory Neil Shapiro 	SM_IO_INIT_TYPE(tls_vector, "tls", tls_open, tls_close,
97640266059SGregory Neil Shapiro 		tls_read, tls_write, NULL, tls_getinfo, NULL,
97740266059SGregory Neil Shapiro 		SM_TIME_FOREVER);
97840266059SGregory Neil Shapiro 	info.fp = *fin;
97940266059SGregory Neil Shapiro 	info.con = con;
980e92d3f3fSGregory Neil Shapiro 	tlsin = sm_io_open(&tls_vector, SM_TIME_DEFAULT, &info, SM_IO_RDONLY_B,
98140266059SGregory Neil Shapiro 			   NULL);
98240266059SGregory Neil Shapiro 	if (tlsin == NULL)
98340266059SGregory Neil Shapiro 		return -1;
98406f25ae9SGregory Neil Shapiro 
98540266059SGregory Neil Shapiro 	info.fp = *fout;
986e92d3f3fSGregory Neil Shapiro 	tlsout = sm_io_open(&tls_vector, SM_TIME_DEFAULT, &info, SM_IO_WRONLY_B,
98740266059SGregory Neil Shapiro 			    NULL);
98840266059SGregory Neil Shapiro 	if (tlsout == NULL)
98942e5d165SGregory Neil Shapiro 	{
99040266059SGregory Neil Shapiro 		(void) sm_io_close(tlsin, SM_TIME_DEFAULT);
99142e5d165SGregory Neil Shapiro 		return -1;
99242e5d165SGregory Neil Shapiro 	}
99340266059SGregory Neil Shapiro 	sm_io_automode(tlsin, tlsout);
99406f25ae9SGregory Neil Shapiro 
99540266059SGregory Neil Shapiro 	*fin = tlsin;
99640266059SGregory Neil Shapiro 	*fout = tlsout;
99706f25ae9SGregory Neil Shapiro 	return 0;
99806f25ae9SGregory Neil Shapiro }
99940266059SGregory Neil Shapiro #endif /* STARTTLS */
1000