xref: /freebsd/contrib/sendmail/src/sfsasl.c (revision d39bd2c1388b520fcba9abed1932acacead60fba)
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>
16da7d7b9cSGregory 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
225b0945b5SGregory Neil Shapiro #endif
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
sasl_getinfo(fp,what,valp)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;
695b0945b5SGregory Neil Shapiro 		return so->fp->f_file; /* for stdio fileno() compatibility */
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
sasl_open(fp,info,flags,rpool)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
sasl_close(fp)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;
1572fb4f839SGregory Neil Shapiro 	SM_CLOSE_FP(so->fp);
15840266059SGregory Neil Shapiro 	sm_free(so);
15940266059SGregory Neil Shapiro 	so = NULL;
16040266059SGregory Neil Shapiro 	return 0;
16140266059SGregory Neil Shapiro }
16240266059SGregory Neil Shapiro 
163193538b7SGregory Neil Shapiro /* how to deallocate a buffer allocated by SASL */
16440266059SGregory Neil Shapiro extern void	sm_sasl_free __P((void *));
16540266059SGregory Neil Shapiro #  define SASL_DEALLOC(b)	sm_sasl_free(b)
16640266059SGregory Neil Shapiro 
16740266059SGregory Neil Shapiro /*
16840266059SGregory Neil Shapiro **  SASL_READ -- read encrypted information and decrypt it for the caller
16940266059SGregory Neil Shapiro **
17040266059SGregory Neil Shapiro **	Parameters:
17140266059SGregory Neil Shapiro **		fp -- the file pointer
17240266059SGregory Neil Shapiro **		buf -- the location to place the decrypted information
17340266059SGregory Neil Shapiro **		size -- the number of bytes to read after decryption
17440266059SGregory Neil Shapiro **
175*d39bd2c1SGregory Neil Shapiro **	Returns:
17640266059SGregory Neil Shapiro **		-1 on error
17740266059SGregory Neil Shapiro **		otherwise the number of bytes read
17840266059SGregory Neil Shapiro */
17940266059SGregory Neil Shapiro 
18040266059SGregory Neil Shapiro static ssize_t sasl_read __P((SM_FILE_T *, char *, size_t));
181193538b7SGregory Neil Shapiro 
18206f25ae9SGregory Neil Shapiro static ssize_t
sasl_read(fp,buf,size)18340266059SGregory Neil Shapiro sasl_read(fp, buf, size)
18440266059SGregory Neil Shapiro 	SM_FILE_T *fp;
18540266059SGregory Neil Shapiro 	char *buf;
18606f25ae9SGregory Neil Shapiro 	size_t size;
18706f25ae9SGregory Neil Shapiro {
18840266059SGregory Neil Shapiro 	int result;
18940266059SGregory Neil Shapiro 	ssize_t len;
19094c01205SGregory Neil Shapiro # if SASL >= 20000
19113bd1963SGregory Neil Shapiro 	static const char *outbuf = NULL;
1925b0945b5SGregory Neil Shapiro # else
193193538b7SGregory Neil Shapiro 	static char *outbuf = NULL;
1945b0945b5SGregory Neil Shapiro # endif
195193538b7SGregory Neil Shapiro 	static unsigned int outlen = 0;
196193538b7SGregory Neil Shapiro 	static unsigned int offset = 0;
19740266059SGregory Neil Shapiro 	struct sasl_obj *so = (struct sasl_obj *) fp->f_cookie;
19806f25ae9SGregory Neil Shapiro 
199193538b7SGregory Neil Shapiro 	/*
200193538b7SGregory Neil Shapiro 	**  sasl_decode() may require more data than a single read() returns.
201193538b7SGregory Neil Shapiro 	**  Hence we have to put a loop around the decoding.
202193538b7SGregory Neil Shapiro 	**  This also requires that we may have to split up the returned
203193538b7SGregory Neil Shapiro 	**  data since it might be larger than the allowed size.
204193538b7SGregory Neil Shapiro 	**  Therefore we use a static pointer and return portions of it
205193538b7SGregory Neil Shapiro 	**  if necessary.
206a7ec597cSGregory Neil Shapiro 	**  XXX Note: This function is not thread-safe nor can it be used
207a7ec597cSGregory Neil Shapiro 	**  on more than one file. A correct implementation would store
208a7ec597cSGregory Neil Shapiro 	**  this data in fp->f_cookie.
209193538b7SGregory Neil Shapiro 	*/
21006f25ae9SGregory Neil Shapiro 
21113bd1963SGregory Neil Shapiro # if SASL >= 20000
21213bd1963SGregory Neil Shapiro 	while (outlen == 0)
2135b0945b5SGregory Neil Shapiro # else
214193538b7SGregory Neil Shapiro 	while (outbuf == NULL && outlen == 0)
2155b0945b5SGregory Neil Shapiro # endif
216193538b7SGregory Neil Shapiro 	{
21740266059SGregory Neil Shapiro 		len = sm_io_read(so->fp, SM_TIME_DEFAULT, buf, size);
21806f25ae9SGregory Neil Shapiro 		if (len <= 0)
21906f25ae9SGregory Neil Shapiro 			return len;
22040266059SGregory Neil Shapiro 		result = sasl_decode(so->conn, buf,
22140266059SGregory Neil Shapiro 				     (unsigned int) len, &outbuf, &outlen);
22206f25ae9SGregory Neil Shapiro 		if (result != SASL_OK)
22306f25ae9SGregory Neil Shapiro 		{
2244e4196cbSGregory Neil Shapiro 			if (LogLevel > 7)
2254e4196cbSGregory Neil Shapiro 				sm_syslog(LOG_WARNING, NOQID,
2264e4196cbSGregory Neil Shapiro 					"AUTH: sasl_decode error=%d", result);
227193538b7SGregory Neil Shapiro 			outbuf = NULL;
228193538b7SGregory Neil Shapiro 			offset = 0;
229193538b7SGregory Neil Shapiro 			outlen = 0;
23006f25ae9SGregory Neil Shapiro 			return -1;
23106f25ae9SGregory Neil Shapiro 		}
232193538b7SGregory Neil Shapiro 	}
23306f25ae9SGregory Neil Shapiro 
23440266059SGregory Neil Shapiro 	if (outbuf == NULL)
23506f25ae9SGregory Neil Shapiro 	{
23640266059SGregory Neil Shapiro 		/* be paranoid: outbuf == NULL but outlen != 0 */
23740266059SGregory Neil Shapiro 		syserr("@sasl_read failure: outbuf == NULL but outlen != 0");
23840266059SGregory Neil Shapiro 		/* NOTREACHED */
23940266059SGregory Neil Shapiro 	}
240193538b7SGregory Neil Shapiro 	if (outlen - offset > size)
241193538b7SGregory Neil Shapiro 	{
242193538b7SGregory Neil Shapiro 		/* return another part of the buffer */
24340266059SGregory Neil Shapiro 		(void) memcpy(buf, outbuf + offset, size);
244193538b7SGregory Neil Shapiro 		offset += size;
24540266059SGregory Neil Shapiro 		len = size;
24606f25ae9SGregory Neil Shapiro 	}
247193538b7SGregory Neil Shapiro 	else
248193538b7SGregory Neil Shapiro 	{
249193538b7SGregory Neil Shapiro 		/* return the rest of the buffer */
25040266059SGregory Neil Shapiro 		len = outlen - offset;
25140266059SGregory Neil Shapiro 		(void) memcpy(buf, outbuf + offset, (size_t) len);
25294c01205SGregory Neil Shapiro # if SASL < 20000
253193538b7SGregory Neil Shapiro 		SASL_DEALLOC(outbuf);
2545b0945b5SGregory Neil Shapiro # endif
255193538b7SGregory Neil Shapiro 		outbuf = NULL;
256193538b7SGregory Neil Shapiro 		offset = 0;
257193538b7SGregory Neil Shapiro 		outlen = 0;
258193538b7SGregory Neil Shapiro 	}
25940266059SGregory Neil Shapiro 	return len;
26006f25ae9SGregory Neil Shapiro }
26106f25ae9SGregory Neil Shapiro 
26240266059SGregory Neil Shapiro /*
26340266059SGregory Neil Shapiro **  SASL_WRITE -- write information out after encrypting it
26440266059SGregory Neil Shapiro **
26540266059SGregory Neil Shapiro **	Parameters:
26640266059SGregory Neil Shapiro **		fp -- the file pointer
26740266059SGregory Neil Shapiro **		buf -- holds the data to be encrypted and written
26840266059SGregory Neil Shapiro **		size -- the number of bytes to have encrypted and written
26940266059SGregory Neil Shapiro **
27040266059SGregory Neil Shapiro **	Returns:
27140266059SGregory Neil Shapiro **		-1 on error
27240266059SGregory Neil Shapiro **		otherwise number of bytes written
27340266059SGregory Neil Shapiro */
27440266059SGregory Neil Shapiro 
27540266059SGregory Neil Shapiro static ssize_t sasl_write __P((SM_FILE_T *, const char *, size_t));
27640266059SGregory Neil Shapiro 
27706f25ae9SGregory Neil Shapiro static ssize_t
sasl_write(fp,buf,size)27840266059SGregory Neil Shapiro sasl_write(fp, buf, size)
27940266059SGregory Neil Shapiro 	SM_FILE_T *fp;
28040266059SGregory Neil Shapiro 	const char *buf;
28106f25ae9SGregory Neil Shapiro 	size_t size;
28206f25ae9SGregory Neil Shapiro {
28306f25ae9SGregory Neil Shapiro 	int result;
28494c01205SGregory Neil Shapiro # if SASL >= 20000
28594c01205SGregory Neil Shapiro 	const char *outbuf;
2865b0945b5SGregory Neil Shapiro # else
28706f25ae9SGregory Neil Shapiro 	char *outbuf;
2885b0945b5SGregory Neil Shapiro # endif
289b6bacd31SGregory Neil Shapiro 	unsigned int outlen, *maxencode;
29040266059SGregory Neil Shapiro 	size_t ret = 0, total = 0;
29140266059SGregory Neil Shapiro 	struct sasl_obj *so = (struct sasl_obj *) fp->f_cookie;
29206f25ae9SGregory Neil Shapiro 
293b6bacd31SGregory Neil Shapiro 	/*
294b6bacd31SGregory Neil Shapiro 	**  Fetch the maximum input buffer size for sasl_encode().
295b6bacd31SGregory Neil Shapiro 	**  This can be less than the size set in attemptauth()
2969bd497b8SGregory Neil Shapiro 	**  due to a negotiation with the other side, e.g.,
297b6bacd31SGregory Neil Shapiro 	**  Cyrus IMAP lmtp program sets maxbuf=4096,
2985b0945b5SGregory Neil Shapiro 	**  digestmd5 subtracts 25 and hence we'll get 4071
299b6bacd31SGregory Neil Shapiro 	**  instead of 8192 (MAXOUTLEN).
300b6bacd31SGregory Neil Shapiro 	**  Hack (for now): simply reduce the size, callers are (must be)
301b6bacd31SGregory Neil Shapiro 	**  able to deal with that and invoke sasl_write() again with
302b6bacd31SGregory Neil Shapiro 	**  the rest of the data.
303b6bacd31SGregory Neil Shapiro 	**  Note: it would be better to store this value in the context
304b6bacd31SGregory Neil Shapiro 	**  after the negotiation.
305b6bacd31SGregory Neil Shapiro 	*/
306b6bacd31SGregory Neil Shapiro 
307b6bacd31SGregory Neil Shapiro 	result = sasl_getprop(so->conn, SASL_MAXOUTBUF,
308b6bacd31SGregory Neil Shapiro 				(const void **) &maxencode);
309b6bacd31SGregory Neil Shapiro 	if (result == SASL_OK && size > *maxencode && *maxencode > 0)
310b6bacd31SGregory Neil Shapiro 		size = *maxencode;
311b6bacd31SGregory Neil Shapiro 
31240266059SGregory Neil Shapiro 	result = sasl_encode(so->conn, buf,
31340266059SGregory Neil Shapiro 			     (unsigned int) size, &outbuf, &outlen);
31406f25ae9SGregory Neil Shapiro 
31506f25ae9SGregory Neil Shapiro 	if (result != SASL_OK)
3164e4196cbSGregory Neil Shapiro 	{
3174e4196cbSGregory Neil Shapiro 		if (LogLevel > 7)
3184e4196cbSGregory Neil Shapiro 			sm_syslog(LOG_WARNING, NOQID,
3194e4196cbSGregory Neil Shapiro 				"AUTH: sasl_encode error=%d", result);
32006f25ae9SGregory Neil Shapiro 		return -1;
3214e4196cbSGregory Neil Shapiro 	}
32206f25ae9SGregory Neil Shapiro 
32306f25ae9SGregory Neil Shapiro 	if (outbuf != NULL)
32406f25ae9SGregory Neil Shapiro 	{
32540266059SGregory Neil Shapiro 		while (outlen > 0)
32640266059SGregory Neil Shapiro 		{
327af9557fdSGregory Neil Shapiro 			errno = 0;
328605302a5SGregory Neil Shapiro 			/* XXX result == 0? */
32940266059SGregory Neil Shapiro 			ret = sm_io_write(so->fp, SM_TIME_DEFAULT,
33040266059SGregory Neil Shapiro 					  &outbuf[total], outlen);
331a7ec597cSGregory Neil Shapiro 			if (ret <= 0)
332a7ec597cSGregory Neil Shapiro 				return ret;
33340266059SGregory Neil Shapiro 			outlen -= ret;
33440266059SGregory Neil Shapiro 			total += ret;
33540266059SGregory Neil Shapiro 		}
33694c01205SGregory Neil Shapiro # if SASL < 20000
337193538b7SGregory Neil Shapiro 		SASL_DEALLOC(outbuf);
3385b0945b5SGregory Neil Shapiro # endif
33906f25ae9SGregory Neil Shapiro 	}
34006f25ae9SGregory Neil Shapiro 	return size;
34106f25ae9SGregory Neil Shapiro }
34206f25ae9SGregory Neil Shapiro 
34340266059SGregory Neil Shapiro /*
34440266059SGregory Neil Shapiro **  SFDCSASL -- create sasl file type and open in and out file pointers
34540266059SGregory Neil Shapiro **	       for sendmail to read from and write to.
34640266059SGregory Neil Shapiro **
34740266059SGregory Neil Shapiro **	Parameters:
34840266059SGregory Neil Shapiro **		fin -- the sm_io file encrypted data to be read from
349af9557fdSGregory Neil Shapiro **		fout -- the sm_io file encrypted data to be written to
35040266059SGregory Neil Shapiro **		conn -- the sasl connection pointer
351af9557fdSGregory Neil Shapiro **		tmo -- timeout
35240266059SGregory Neil Shapiro **
35340266059SGregory Neil Shapiro **	Returns:
35440266059SGregory Neil Shapiro **		-1 on error
35540266059SGregory Neil Shapiro **		0 on success
35640266059SGregory Neil Shapiro **
35740266059SGregory Neil Shapiro **	Side effects:
35840266059SGregory Neil Shapiro **		The arguments "fin" and "fout" are replaced with the new
35940266059SGregory Neil Shapiro **		SM_FILE_T pointers.
36040266059SGregory Neil Shapiro */
36140266059SGregory Neil Shapiro 
36206f25ae9SGregory Neil Shapiro int
sfdcsasl(fin,fout,conn,tmo)363af9557fdSGregory Neil Shapiro sfdcsasl(fin, fout, conn, tmo)
36440266059SGregory Neil Shapiro 	SM_FILE_T **fin;
36540266059SGregory Neil Shapiro 	SM_FILE_T **fout;
36606f25ae9SGregory Neil Shapiro 	sasl_conn_t *conn;
367af9557fdSGregory Neil Shapiro 	int tmo;
36806f25ae9SGregory Neil Shapiro {
36940266059SGregory Neil Shapiro 	SM_FILE_T *newin, *newout;
37040266059SGregory Neil Shapiro 	SM_FILE_T  SM_IO_SET_TYPE(sasl_vector, "sasl", sasl_open, sasl_close,
37140266059SGregory Neil Shapiro 		sasl_read, sasl_write, NULL, sasl_getinfo, NULL,
372af9557fdSGregory Neil Shapiro 		SM_TIME_DEFAULT);
37340266059SGregory Neil Shapiro 	struct sasl_info info;
37406f25ae9SGregory Neil Shapiro 
37506f25ae9SGregory Neil Shapiro 	if (conn == NULL)
37606f25ae9SGregory Neil Shapiro 	{
37706f25ae9SGregory Neil Shapiro 		/* no need to do anything */
37806f25ae9SGregory Neil Shapiro 		return 0;
37906f25ae9SGregory Neil Shapiro 	}
38006f25ae9SGregory Neil Shapiro 
38140266059SGregory Neil Shapiro 	SM_IO_INIT_TYPE(sasl_vector, "sasl", sasl_open, sasl_close,
38240266059SGregory Neil Shapiro 		sasl_read, sasl_write, NULL, sasl_getinfo, NULL,
383af9557fdSGregory Neil Shapiro 		SM_TIME_DEFAULT);
38440266059SGregory Neil Shapiro 	info.fp = *fin;
38540266059SGregory Neil Shapiro 	info.conn = conn;
386e92d3f3fSGregory Neil Shapiro 	newin = sm_io_open(&sasl_vector, SM_TIME_DEFAULT, &info,
387e92d3f3fSGregory Neil Shapiro 			SM_IO_RDONLY_B, NULL);
38806f25ae9SGregory Neil Shapiro 
38940266059SGregory Neil Shapiro 	if (newin == NULL)
39040266059SGregory Neil Shapiro 		return -1;
39106f25ae9SGregory Neil Shapiro 
39240266059SGregory Neil Shapiro 	info.fp = *fout;
39340266059SGregory Neil Shapiro 	info.conn = conn;
394e92d3f3fSGregory Neil Shapiro 	newout = sm_io_open(&sasl_vector, SM_TIME_DEFAULT, &info,
395e92d3f3fSGregory Neil Shapiro 			SM_IO_WRONLY_B, NULL);
39606f25ae9SGregory Neil Shapiro 
39740266059SGregory Neil Shapiro 	if (newout == NULL)
39806f25ae9SGregory Neil Shapiro 	{
39940266059SGregory Neil Shapiro 		(void) sm_io_close(newin, SM_TIME_DEFAULT);
40006f25ae9SGregory Neil Shapiro 		return -1;
40106f25ae9SGregory Neil Shapiro 	}
40240266059SGregory Neil Shapiro 	sm_io_automode(newin, newout);
40340266059SGregory Neil Shapiro 
404af9557fdSGregory Neil Shapiro 	sm_io_setinfo(*fin, SM_IO_WHAT_TIMEOUT, &tmo);
405af9557fdSGregory Neil Shapiro 	sm_io_setinfo(*fout, SM_IO_WHAT_TIMEOUT, &tmo);
406af9557fdSGregory Neil Shapiro 
40740266059SGregory Neil Shapiro 	*fin = newin;
40840266059SGregory Neil Shapiro 	*fout = newout;
40906f25ae9SGregory Neil Shapiro 	return 0;
41006f25ae9SGregory Neil Shapiro }
41140266059SGregory Neil Shapiro #endif /* SASL */
41206f25ae9SGregory Neil Shapiro 
41340266059SGregory Neil Shapiro #if STARTTLS
41406f25ae9SGregory Neil Shapiro # include "sfsasl.h"
4155b0945b5SGregory Neil Shapiro # include <tls.h>
41606f25ae9SGregory Neil Shapiro # include <openssl/err.h>
41706f25ae9SGregory Neil Shapiro 
41840266059SGregory Neil Shapiro /* Structure used by the "tls" file type */
41940266059SGregory Neil Shapiro struct tls_obj
42040266059SGregory Neil Shapiro {
42140266059SGregory Neil Shapiro 	SM_FILE_T *fp;
42240266059SGregory Neil Shapiro 	SSL *con;
42340266059SGregory Neil Shapiro };
42440266059SGregory Neil Shapiro 
42540266059SGregory Neil Shapiro struct tls_info
42640266059SGregory Neil Shapiro {
42740266059SGregory Neil Shapiro 	SM_FILE_T *fp;
42840266059SGregory Neil Shapiro 	SSL *con;
42940266059SGregory Neil Shapiro };
43040266059SGregory Neil Shapiro 
43140266059SGregory Neil Shapiro /*
43240266059SGregory Neil Shapiro **  TLS_GETINFO - returns requested information about a "tls" file
43340266059SGregory Neil Shapiro **		 descriptor.
43440266059SGregory Neil Shapiro **
43540266059SGregory Neil Shapiro **	Parameters:
43640266059SGregory Neil Shapiro **		fp -- the file descriptor
43740266059SGregory Neil Shapiro **		what -- the type of information requested
43840266059SGregory Neil Shapiro **		valp -- the thang to return the information in (unused)
43940266059SGregory Neil Shapiro **
44040266059SGregory Neil Shapiro **	Returns:
44140266059SGregory Neil Shapiro **		-1 for unknown requests
44240266059SGregory Neil Shapiro **		>=0 on success with valp filled in (if possible).
44340266059SGregory Neil Shapiro */
44440266059SGregory Neil Shapiro 
44540266059SGregory Neil Shapiro static int tls_getinfo __P((SM_FILE_T *, int, void *));
44640266059SGregory Neil Shapiro 
44740266059SGregory Neil Shapiro /* ARGSUSED2 */
44813058a91SGregory Neil Shapiro static int
tls_getinfo(fp,what,valp)44940266059SGregory Neil Shapiro tls_getinfo(fp, what, valp)
45040266059SGregory Neil Shapiro 	SM_FILE_T *fp;
45140266059SGregory Neil Shapiro 	int what;
45240266059SGregory Neil Shapiro 	void *valp;
45340266059SGregory Neil Shapiro {
45440266059SGregory Neil Shapiro 	struct tls_obj *so = (struct tls_obj *) fp->f_cookie;
45540266059SGregory Neil Shapiro 
45640266059SGregory Neil Shapiro 	switch (what)
45740266059SGregory Neil Shapiro 	{
45840266059SGregory Neil Shapiro 	  case SM_IO_WHAT_FD:
45940266059SGregory Neil Shapiro 		if (so->fp == NULL)
46040266059SGregory Neil Shapiro 			return -1;
4615b0945b5SGregory Neil Shapiro 		return so->fp->f_file; /* for stdio fileno() compatibility */
46240266059SGregory Neil Shapiro 
46340266059SGregory Neil Shapiro 	  case SM_IO_IS_READABLE:
46440266059SGregory Neil Shapiro 		return SSL_pending(so->con) > 0;
46540266059SGregory Neil Shapiro 
46640266059SGregory Neil Shapiro 	  default:
46740266059SGregory Neil Shapiro 		return -1;
46840266059SGregory Neil Shapiro 	}
46940266059SGregory Neil Shapiro }
47040266059SGregory Neil Shapiro 
47140266059SGregory Neil Shapiro /*
47240266059SGregory Neil Shapiro **  TLS_OPEN -- creates the tls specific information for opening a
47340266059SGregory Neil Shapiro **	       file of the tls type.
47440266059SGregory Neil Shapiro **
47540266059SGregory Neil Shapiro **	Parameters:
47640266059SGregory Neil Shapiro **		fp -- the file pointer associated with the new open
47740266059SGregory Neil Shapiro **		info -- the sm_io file pointer holding the open and the
47840266059SGregory Neil Shapiro **			TLS encryption connection to be read from or written to
47940266059SGregory Neil Shapiro **		flags -- ignored
48040266059SGregory Neil Shapiro **		rpool -- ignored
48140266059SGregory Neil Shapiro **
48240266059SGregory Neil Shapiro **	Returns:
48340266059SGregory Neil Shapiro **		0 on success
48440266059SGregory Neil Shapiro */
48540266059SGregory Neil Shapiro 
48640266059SGregory Neil Shapiro static int tls_open __P((SM_FILE_T *, const void *, int, const void *));
48740266059SGregory Neil Shapiro 
48840266059SGregory Neil Shapiro /* ARGSUSED2 */
48940266059SGregory Neil Shapiro static int
tls_open(fp,info,flags,rpool)49040266059SGregory Neil Shapiro tls_open(fp, info, flags, rpool)
49140266059SGregory Neil Shapiro 	SM_FILE_T *fp;
49240266059SGregory Neil Shapiro 	const void *info;
49340266059SGregory Neil Shapiro 	int flags;
49440266059SGregory Neil Shapiro 	const void *rpool;
49540266059SGregory Neil Shapiro {
49640266059SGregory Neil Shapiro 	struct tls_obj *so;
49740266059SGregory Neil Shapiro 	struct tls_info *ti = (struct tls_info *) info;
49840266059SGregory Neil Shapiro 
49940266059SGregory Neil Shapiro 	so = (struct tls_obj *) sm_malloc(sizeof(struct tls_obj));
500a7ec597cSGregory Neil Shapiro 	if (so == NULL)
501a7ec597cSGregory Neil Shapiro 	{
502a7ec597cSGregory Neil Shapiro 		errno = ENOMEM;
503a7ec597cSGregory Neil Shapiro 		return -1;
504a7ec597cSGregory Neil Shapiro 	}
50540266059SGregory Neil Shapiro 	so->fp = ti->fp;
50640266059SGregory Neil Shapiro 	so->con = ti->con;
50740266059SGregory Neil Shapiro 
50840266059SGregory Neil Shapiro 	/*
50940266059SGregory Neil Shapiro 	**  We try to get the "raw" file descriptor that TLS uses to
51040266059SGregory Neil Shapiro 	**  do the actual read/write with. This is to allow us control
51140266059SGregory Neil Shapiro 	**  over the file descriptor being a blocking or non-blocking type.
51240266059SGregory Neil Shapiro 	**  Under the covers TLS handles the change and this allows us
51340266059SGregory Neil Shapiro 	**  to do timeouts with sm_io.
51440266059SGregory Neil Shapiro 	*/
51540266059SGregory Neil Shapiro 
51640266059SGregory Neil Shapiro 	fp->f_file = sm_io_getinfo(so->fp, SM_IO_WHAT_FD, NULL);
51740266059SGregory Neil Shapiro 	(void) sm_io_setvbuf(so->fp, SM_TIME_DEFAULT, NULL, SM_IO_NOW, 0);
51840266059SGregory Neil Shapiro 	fp->f_cookie = so;
51940266059SGregory Neil Shapiro 	return 0;
52040266059SGregory Neil Shapiro }
52140266059SGregory Neil Shapiro 
52240266059SGregory Neil Shapiro /*
52340266059SGregory Neil Shapiro **  TLS_CLOSE -- close the tls specific parts of the tls file pointer
52440266059SGregory Neil Shapiro **
52540266059SGregory Neil Shapiro **	Parameters:
52640266059SGregory Neil Shapiro **		fp -- the file pointer to close
52740266059SGregory Neil Shapiro **
52840266059SGregory Neil Shapiro **	Returns:
52940266059SGregory Neil Shapiro **		0 on success
53040266059SGregory Neil Shapiro */
53140266059SGregory Neil Shapiro 
53240266059SGregory Neil Shapiro static int tls_close __P((SM_FILE_T *));
53340266059SGregory Neil Shapiro 
53440266059SGregory Neil Shapiro static int
tls_close(fp)53540266059SGregory Neil Shapiro tls_close(fp)
53640266059SGregory Neil Shapiro 	SM_FILE_T *fp;
53740266059SGregory Neil Shapiro {
53840266059SGregory Neil Shapiro 	struct tls_obj *so;
53940266059SGregory Neil Shapiro 
54040266059SGregory Neil Shapiro 	so = (struct tls_obj *) fp->f_cookie;
541a7ec597cSGregory Neil Shapiro 	if (so == NULL)
542a7ec597cSGregory Neil Shapiro 		return 0;
5432fb4f839SGregory Neil Shapiro 	SM_CLOSE_FP(so->fp);
54440266059SGregory Neil Shapiro 	sm_free(so);
54540266059SGregory Neil Shapiro 	so = NULL;
54640266059SGregory Neil Shapiro 	return 0;
54740266059SGregory Neil Shapiro }
54840266059SGregory Neil Shapiro 
54940266059SGregory Neil Shapiro /* maximum number of retries for TLS related I/O due to handshakes */
55040266059SGregory Neil Shapiro # define MAX_TLS_IOS	4
55140266059SGregory Neil Shapiro 
55240266059SGregory Neil Shapiro /*
5534e4196cbSGregory Neil Shapiro **  TLS_RETRY -- check whether a failed SSL operation can be retried
5544e4196cbSGregory Neil Shapiro **
5554e4196cbSGregory Neil Shapiro **	Parameters:
5564e4196cbSGregory Neil Shapiro **		ssl -- TLS structure
5574e4196cbSGregory Neil Shapiro **		rfd -- read fd
5584e4196cbSGregory Neil Shapiro **		wfd -- write fd
5594e4196cbSGregory Neil Shapiro **		tlsstart -- start time of TLS operation
5604e4196cbSGregory Neil Shapiro **		timeout -- timeout for TLS operation
5614e4196cbSGregory Neil Shapiro **		err -- SSL error
5624e4196cbSGregory Neil Shapiro **		where -- description of operation
5634e4196cbSGregory Neil Shapiro **
564*d39bd2c1SGregory Neil Shapiro **	Returns:
5654e4196cbSGregory Neil Shapiro **		>0 on success
5664e4196cbSGregory Neil Shapiro **		0 on timeout
5674e4196cbSGregory Neil Shapiro **		<0 on error
5684e4196cbSGregory Neil Shapiro */
5694e4196cbSGregory Neil Shapiro 
5704e4196cbSGregory Neil Shapiro int
tls_retry(ssl,rfd,wfd,tlsstart,timeout,err,where)5714e4196cbSGregory Neil Shapiro tls_retry(ssl, rfd, wfd, tlsstart, timeout, err, where)
5724e4196cbSGregory Neil Shapiro 	SSL *ssl;
5734e4196cbSGregory Neil Shapiro 	int rfd;
5744e4196cbSGregory Neil Shapiro 	int wfd;
5754e4196cbSGregory Neil Shapiro 	time_t tlsstart;
5764e4196cbSGregory Neil Shapiro 	int timeout;
5774e4196cbSGregory Neil Shapiro 	int err;
5784e4196cbSGregory Neil Shapiro 	const char *where;
5794e4196cbSGregory Neil Shapiro {
5804e4196cbSGregory Neil Shapiro 	int ret;
5814e4196cbSGregory Neil Shapiro 	time_t left;
5824e4196cbSGregory Neil Shapiro 	time_t now = curtime();
5834e4196cbSGregory Neil Shapiro 	struct timeval tv;
5844e4196cbSGregory Neil Shapiro 
5854e4196cbSGregory Neil Shapiro 	ret = -1;
5864e4196cbSGregory Neil Shapiro 
5874e4196cbSGregory Neil Shapiro 	/*
5884e4196cbSGregory Neil Shapiro 	**  For SSL_ERROR_WANT_{READ,WRITE}:
5894e4196cbSGregory Neil Shapiro 	**  There is not a complete SSL record available yet
5904e4196cbSGregory Neil Shapiro 	**  or there is only a partial SSL record removed from
5914e4196cbSGregory Neil Shapiro 	**  the network (socket) buffer into the SSL buffer.
5924e4196cbSGregory Neil Shapiro 	**  The SSL_connect will only succeed when a full
5934e4196cbSGregory Neil Shapiro 	**  SSL record is available (assuming a "real" error
5944e4196cbSGregory Neil Shapiro 	**  doesn't happen). To handle when a "real" error
5954e4196cbSGregory Neil Shapiro 	**  does happen the select is set for exceptions too.
5964e4196cbSGregory Neil Shapiro 	**  The connection may be re-negotiated during this time
5974e4196cbSGregory Neil Shapiro 	**  so both read and write "want errors" need to be handled.
5984e4196cbSGregory Neil Shapiro 	**  A select() exception loops back so that a proper SSL
5994e4196cbSGregory Neil Shapiro 	**  error message can be gotten.
6004e4196cbSGregory Neil Shapiro 	*/
6014e4196cbSGregory Neil Shapiro 
6024e4196cbSGregory Neil Shapiro 	left = timeout - (now - tlsstart);
6034e4196cbSGregory Neil Shapiro 	if (left <= 0)
6044e4196cbSGregory Neil Shapiro 		return 0;	/* timeout */
6054e4196cbSGregory Neil Shapiro 	tv.tv_sec = left;
6064e4196cbSGregory Neil Shapiro 	tv.tv_usec = 0;
6074e4196cbSGregory Neil Shapiro 
6084e4196cbSGregory Neil Shapiro 	if (LogLevel > 14)
6094e4196cbSGregory Neil Shapiro 	{
6104e4196cbSGregory Neil Shapiro 		sm_syslog(LOG_INFO, NOQID,
6114e4196cbSGregory Neil Shapiro 			  "STARTTLS=%s, info: fds=%d/%d, err=%d",
6124e4196cbSGregory Neil Shapiro 			  where, rfd, wfd, err);
6134e4196cbSGregory Neil Shapiro 	}
6144e4196cbSGregory Neil Shapiro 
615da7d7b9cSGregory Neil Shapiro 	if ((err == SSL_ERROR_WANT_READ && !SM_FD_OK_SELECT(rfd)) ||
616da7d7b9cSGregory Neil Shapiro 	    (err == SSL_ERROR_WANT_WRITE && !SM_FD_OK_SELECT(wfd)))
6174e4196cbSGregory Neil Shapiro 	{
6184e4196cbSGregory Neil Shapiro 		if (LogLevel > 5)
6194e4196cbSGregory Neil Shapiro 		{
6204e4196cbSGregory Neil Shapiro 			sm_syslog(LOG_ERR, NOQID,
6214e4196cbSGregory Neil Shapiro 				  "STARTTLS=%s, error: fd %d/%d too large",
6224e4196cbSGregory Neil Shapiro 				  where, rfd, wfd);
6235b0945b5SGregory Neil Shapiro 			tlslogerr(LOG_WARNING, 8, where);
6244e4196cbSGregory Neil Shapiro 		}
6254e4196cbSGregory Neil Shapiro 		errno = EINVAL;
6264e4196cbSGregory Neil Shapiro 	}
6274e4196cbSGregory Neil Shapiro 	else if (err == SSL_ERROR_WANT_READ)
6284e4196cbSGregory Neil Shapiro 	{
6294e4196cbSGregory Neil Shapiro 		fd_set ssl_maskr, ssl_maskx;
630552d4955SGregory Neil Shapiro 		int save_errno = errno;
6314e4196cbSGregory Neil Shapiro 
6324e4196cbSGregory Neil Shapiro 		FD_ZERO(&ssl_maskr);
6334e4196cbSGregory Neil Shapiro 		FD_SET(rfd, &ssl_maskr);
6344e4196cbSGregory Neil Shapiro 		FD_ZERO(&ssl_maskx);
6354e4196cbSGregory Neil Shapiro 		FD_SET(rfd, &ssl_maskx);
6364e4196cbSGregory Neil Shapiro 		do
6374e4196cbSGregory Neil Shapiro 		{
6384e4196cbSGregory Neil Shapiro 			ret = select(rfd + 1, &ssl_maskr, NULL, &ssl_maskx,
6394e4196cbSGregory Neil Shapiro 					&tv);
6404e4196cbSGregory Neil Shapiro 		} while (ret < 0 && errno == EINTR);
6414e4196cbSGregory Neil Shapiro 		if (ret < 0 && errno > 0)
6424e4196cbSGregory Neil Shapiro 			ret = -errno;
643552d4955SGregory Neil Shapiro 		errno = save_errno;
6444e4196cbSGregory Neil Shapiro 	}
6454e4196cbSGregory Neil Shapiro 	else if (err == SSL_ERROR_WANT_WRITE)
6464e4196cbSGregory Neil Shapiro 	{
6474e4196cbSGregory Neil Shapiro 		fd_set ssl_maskw, ssl_maskx;
648552d4955SGregory Neil Shapiro 		int save_errno = errno;
6494e4196cbSGregory Neil Shapiro 
6504e4196cbSGregory Neil Shapiro 		FD_ZERO(&ssl_maskw);
6514e4196cbSGregory Neil Shapiro 		FD_SET(wfd, &ssl_maskw);
6524e4196cbSGregory Neil Shapiro 		FD_ZERO(&ssl_maskx);
6534e4196cbSGregory Neil Shapiro 		FD_SET(rfd, &ssl_maskx);
6544e4196cbSGregory Neil Shapiro 		do
6554e4196cbSGregory Neil Shapiro 		{
6564e4196cbSGregory Neil Shapiro 			ret = select(wfd + 1, NULL, &ssl_maskw, &ssl_maskx,
6574e4196cbSGregory Neil Shapiro 					&tv);
6584e4196cbSGregory Neil Shapiro 		} while (ret < 0 && errno == EINTR);
6594e4196cbSGregory Neil Shapiro 		if (ret < 0 && errno > 0)
6604e4196cbSGregory Neil Shapiro 			ret = -errno;
661552d4955SGregory Neil Shapiro 		errno = save_errno;
6624e4196cbSGregory Neil Shapiro 	}
6634e4196cbSGregory Neil Shapiro 	return ret;
6644e4196cbSGregory Neil Shapiro }
6654e4196cbSGregory Neil Shapiro 
6664e4196cbSGregory Neil Shapiro /* errno to force refill() etc to stop (see IS_IO_ERROR()) */
6674e4196cbSGregory Neil Shapiro # ifdef ETIMEDOUT
6684e4196cbSGregory Neil Shapiro #  define SM_ERR_TIMEOUT	ETIMEDOUT
6695b0945b5SGregory Neil Shapiro # else
6704e4196cbSGregory Neil Shapiro #  define SM_ERR_TIMEOUT	EIO
6715b0945b5SGregory Neil Shapiro # endif
6724e4196cbSGregory Neil Shapiro 
6734e4196cbSGregory Neil Shapiro /*
674e3793f76SGregory Neil Shapiro **  SET_TLS_RD_TMO -- read secured information for the caller
675e3793f76SGregory Neil Shapiro **
676e3793f76SGregory Neil Shapiro **	Parameters:
677e3793f76SGregory Neil Shapiro **		rd_tmo -- read timeout
678e3793f76SGregory Neil Shapiro **
679*d39bd2c1SGregory Neil Shapiro **	Returns:
680da7d7b9cSGregory Neil Shapiro **		previous read timeout
681e3793f76SGregory Neil Shapiro **	This is a hack: there is no way to pass it in
682e3793f76SGregory Neil Shapiro */
683e3793f76SGregory Neil Shapiro 
684e3793f76SGregory Neil Shapiro static int tls_rd_tmo = -1;
685e3793f76SGregory Neil Shapiro 
686da7d7b9cSGregory Neil Shapiro int
set_tls_rd_tmo(rd_tmo)687e3793f76SGregory Neil Shapiro set_tls_rd_tmo(rd_tmo)
688e3793f76SGregory Neil Shapiro 	int rd_tmo;
689e3793f76SGregory Neil Shapiro {
690da7d7b9cSGregory Neil Shapiro 	int old_rd_tmo;
691da7d7b9cSGregory Neil Shapiro 
692da7d7b9cSGregory Neil Shapiro 	old_rd_tmo = tls_rd_tmo;
693e3793f76SGregory Neil Shapiro 	tls_rd_tmo = rd_tmo;
694da7d7b9cSGregory Neil Shapiro 	return old_rd_tmo;
695e3793f76SGregory Neil Shapiro }
696e3793f76SGregory Neil Shapiro 
697e3793f76SGregory Neil Shapiro /*
69840266059SGregory Neil Shapiro **  TLS_READ -- read secured information for the caller
69940266059SGregory Neil Shapiro **
70040266059SGregory Neil Shapiro **	Parameters:
70140266059SGregory Neil Shapiro **		fp -- the file pointer
70240266059SGregory Neil Shapiro **		buf -- the location to place the data
70340266059SGregory Neil Shapiro **		size -- the number of bytes to read from connection
70440266059SGregory Neil Shapiro **
705*d39bd2c1SGregory Neil Shapiro **	Returns:
70640266059SGregory Neil Shapiro **		-1 on error
70740266059SGregory Neil Shapiro **		otherwise the number of bytes read
70840266059SGregory Neil Shapiro */
70940266059SGregory Neil Shapiro 
71040266059SGregory Neil Shapiro static ssize_t tls_read __P((SM_FILE_T *, char *, size_t));
71140266059SGregory Neil Shapiro 
71240266059SGregory Neil Shapiro static ssize_t
tls_read(fp,buf,size)71340266059SGregory Neil Shapiro tls_read(fp, buf, size)
71440266059SGregory Neil Shapiro 	SM_FILE_T *fp;
71513058a91SGregory Neil Shapiro 	char *buf;
71640266059SGregory Neil Shapiro 	size_t size;
71706f25ae9SGregory Neil Shapiro {
7184e4196cbSGregory Neil Shapiro 	int r, rfd, wfd, try, ssl_err;
71940266059SGregory Neil Shapiro 	struct tls_obj *so = (struct tls_obj *) fp->f_cookie;
7204e4196cbSGregory Neil Shapiro 	time_t tlsstart;
72106f25ae9SGregory Neil Shapiro 	char *err;
72206f25ae9SGregory Neil Shapiro 
7234e4196cbSGregory Neil Shapiro 	try = 99;
7244e4196cbSGregory Neil Shapiro 	err = NULL;
7254e4196cbSGregory Neil Shapiro 	tlsstart = curtime();
7264e4196cbSGregory Neil Shapiro 
7274e4196cbSGregory Neil Shapiro   retry:
72840266059SGregory Neil Shapiro 	r = SSL_read(so->con, (char *) buf, size);
72940266059SGregory Neil Shapiro 
73040266059SGregory Neil Shapiro 	if (r > 0)
73140266059SGregory Neil Shapiro 		return r;
73240266059SGregory Neil Shapiro 
73306f25ae9SGregory Neil Shapiro 	err = NULL;
7344e4196cbSGregory Neil Shapiro 	switch (ssl_err = SSL_get_error(so->con, r))
73506f25ae9SGregory Neil Shapiro 	{
73606f25ae9SGregory Neil Shapiro 	  case SSL_ERROR_NONE:
73740266059SGregory Neil Shapiro 	  case SSL_ERROR_ZERO_RETURN:
73806f25ae9SGregory Neil Shapiro 		break;
73906f25ae9SGregory Neil Shapiro 	  case SSL_ERROR_WANT_WRITE:
74040266059SGregory Neil Shapiro 		err = "read W BLOCK";
7414e4196cbSGregory Neil Shapiro 		/* FALLTHROUGH */
74206f25ae9SGregory Neil Shapiro 	  case SSL_ERROR_WANT_READ:
7434e4196cbSGregory Neil Shapiro 		if (err == NULL)
74440266059SGregory Neil Shapiro 			err = "read R BLOCK";
7454e4196cbSGregory Neil Shapiro 		rfd = SSL_get_rfd(so->con);
7464e4196cbSGregory Neil Shapiro 		wfd = SSL_get_wfd(so->con);
7474e4196cbSGregory Neil Shapiro 		try = tls_retry(so->con, rfd, wfd, tlsstart,
748e3793f76SGregory Neil Shapiro 				(tls_rd_tmo < 0) ? TimeOuts.to_datablock
749e3793f76SGregory Neil Shapiro 						 : tls_rd_tmo,
750e3793f76SGregory Neil Shapiro 				ssl_err, "read");
7514e4196cbSGregory Neil Shapiro 		if (try > 0)
7524e4196cbSGregory Neil Shapiro 			goto retry;
7534e4196cbSGregory Neil Shapiro 		errno = SM_ERR_TIMEOUT;
75406f25ae9SGregory Neil Shapiro 		break;
7554e4196cbSGregory Neil Shapiro 
75606f25ae9SGregory Neil Shapiro 	  case SSL_ERROR_WANT_X509_LOOKUP:
75706f25ae9SGregory Neil Shapiro 		err = "write X BLOCK";
75806f25ae9SGregory Neil Shapiro 		break;
75906f25ae9SGregory Neil Shapiro 	  case SSL_ERROR_SYSCALL:
76040266059SGregory Neil Shapiro 		if (r == 0 && errno == 0) /* out of protocol EOF found */
76140266059SGregory Neil Shapiro 			break;
76206f25ae9SGregory Neil Shapiro 		err = "syscall error";
76306f25ae9SGregory Neil Shapiro 		break;
76406f25ae9SGregory Neil Shapiro 	  case SSL_ERROR_SSL:
765b6bacd31SGregory Neil Shapiro # if DEAL_WITH_ERROR_SSL
766959366dcSGregory Neil Shapiro 		if (r == 0 && errno == 0) /* out of protocol EOF found */
767959366dcSGregory Neil Shapiro 			break;
7685b0945b5SGregory Neil Shapiro # endif
76906f25ae9SGregory Neil Shapiro 		err = "generic SSL error";
770552d4955SGregory Neil Shapiro 
77140266059SGregory Neil Shapiro 		if (LogLevel > 9)
772552d4955SGregory Neil Shapiro 		{
773552d4955SGregory Neil Shapiro 			int pri;
774552d4955SGregory Neil Shapiro 
775552d4955SGregory Neil Shapiro 			if (errno == EAGAIN && try > 0)
776552d4955SGregory Neil Shapiro 				pri = LOG_DEBUG;
777552d4955SGregory Neil Shapiro 			else
778552d4955SGregory Neil Shapiro 				pri = LOG_WARNING;
7795b0945b5SGregory Neil Shapiro 			tlslogerr(pri, 9, "read");
780552d4955SGregory Neil Shapiro 		}
781959366dcSGregory Neil Shapiro 
782b6bacd31SGregory Neil Shapiro # if DEAL_WITH_ERROR_SSL
783959366dcSGregory Neil Shapiro 		/* avoid repeated calls? */
784959366dcSGregory Neil Shapiro 		if (r == 0)
785959366dcSGregory Neil Shapiro 			r = -1;
7865b0945b5SGregory Neil Shapiro # endif
78706f25ae9SGregory Neil Shapiro 		break;
78806f25ae9SGregory Neil Shapiro 	}
78906f25ae9SGregory Neil Shapiro 	if (err != NULL)
79040266059SGregory Neil Shapiro 	{
791605302a5SGregory Neil Shapiro 		int save_errno;
792605302a5SGregory Neil Shapiro 
793605302a5SGregory Neil Shapiro 		save_errno = (errno == 0) ? EIO : errno;
7944e4196cbSGregory Neil Shapiro 		if (try == 0 && save_errno == SM_ERR_TIMEOUT)
7954e4196cbSGregory Neil Shapiro 		{
7964e4196cbSGregory Neil Shapiro 			if (LogLevel > 7)
797a7ec597cSGregory Neil Shapiro 				sm_syslog(LOG_WARNING, NOQID,
7984e4196cbSGregory Neil Shapiro 					  "STARTTLS: read error=timeout");
7994e4196cbSGregory Neil Shapiro 		}
8004e4196cbSGregory Neil Shapiro 		else if (LogLevel > 8)
801552d4955SGregory Neil Shapiro 		{
802552d4955SGregory Neil Shapiro 			int pri;
803552d4955SGregory Neil Shapiro 
804552d4955SGregory Neil Shapiro 			if (save_errno == EAGAIN && try > 0)
805552d4955SGregory Neil Shapiro 				pri = LOG_DEBUG;
806552d4955SGregory Neil Shapiro 			else
807552d4955SGregory Neil Shapiro 				pri = LOG_WARNING;
808552d4955SGregory Neil Shapiro 			sm_syslog(pri, NOQID,
8094e4196cbSGregory Neil Shapiro 				  "STARTTLS: read error=%s (%d), errno=%d, get_error=%s, retry=%d, ssl_err=%d",
810a7ec597cSGregory Neil Shapiro 				  err, r, errno,
8114e4196cbSGregory Neil Shapiro 				  ERR_error_string(ERR_get_error(), NULL), try,
8124e4196cbSGregory Neil Shapiro 				  ssl_err);
813552d4955SGregory Neil Shapiro 		}
814a7ec597cSGregory Neil Shapiro 		else if (LogLevel > 7)
81540266059SGregory Neil Shapiro 			sm_syslog(LOG_WARNING, NOQID,
816da7d7b9cSGregory Neil Shapiro 				  "STARTTLS: read error=%s (%d), errno=%d, retry=%d, ssl_err=%d",
8174e4196cbSGregory Neil Shapiro 				  err, r, errno, try, ssl_err);
818605302a5SGregory Neil Shapiro 		errno = save_errno;
81906f25ae9SGregory Neil Shapiro 	}
82006f25ae9SGregory Neil Shapiro 	return r;
82106f25ae9SGregory Neil Shapiro }
82206f25ae9SGregory Neil Shapiro 
82340266059SGregory Neil Shapiro /*
82440266059SGregory Neil Shapiro **  TLS_WRITE -- write information out through secure connection
82540266059SGregory Neil Shapiro **
82640266059SGregory Neil Shapiro **	Parameters:
82740266059SGregory Neil Shapiro **		fp -- the file pointer
82840266059SGregory Neil Shapiro **		buf -- holds the data to be securely written
82940266059SGregory Neil Shapiro **		size -- the number of bytes to write
83040266059SGregory Neil Shapiro **
83140266059SGregory Neil Shapiro **	Returns:
83240266059SGregory Neil Shapiro **		-1 on error
83340266059SGregory Neil Shapiro **		otherwise number of bytes written
83440266059SGregory Neil Shapiro */
83540266059SGregory Neil Shapiro 
83640266059SGregory Neil Shapiro static ssize_t tls_write __P((SM_FILE_T *, const char *, size_t));
83740266059SGregory Neil Shapiro 
83813058a91SGregory Neil Shapiro static ssize_t
tls_write(fp,buf,size)83940266059SGregory Neil Shapiro tls_write(fp, buf, size)
84040266059SGregory Neil Shapiro 	SM_FILE_T *fp;
84113058a91SGregory Neil Shapiro 	const char *buf;
84240266059SGregory Neil Shapiro 	size_t size;
84306f25ae9SGregory Neil Shapiro {
8444e4196cbSGregory Neil Shapiro 	int r, rfd, wfd, try, ssl_err;
84540266059SGregory Neil Shapiro 	struct tls_obj *so = (struct tls_obj *) fp->f_cookie;
8464e4196cbSGregory Neil Shapiro 	time_t tlsstart;
84706f25ae9SGregory Neil Shapiro 	char *err;
84806f25ae9SGregory Neil Shapiro 
8494e4196cbSGregory Neil Shapiro 	try = 99;
8504e4196cbSGregory Neil Shapiro 	err = NULL;
8514e4196cbSGregory Neil Shapiro 	tlsstart = curtime();
8524e4196cbSGregory Neil Shapiro 
8534e4196cbSGregory Neil Shapiro   retry:
85440266059SGregory Neil Shapiro 	r = SSL_write(so->con, (char *) buf, size);
85540266059SGregory Neil Shapiro 
85640266059SGregory Neil Shapiro 	if (r > 0)
85740266059SGregory Neil Shapiro 		return r;
85806f25ae9SGregory Neil Shapiro 	err = NULL;
8594e4196cbSGregory Neil Shapiro 	switch (ssl_err = SSL_get_error(so->con, r))
86006f25ae9SGregory Neil Shapiro 	{
86106f25ae9SGregory Neil Shapiro 	  case SSL_ERROR_NONE:
86240266059SGregory Neil Shapiro 	  case SSL_ERROR_ZERO_RETURN:
86306f25ae9SGregory Neil Shapiro 		break;
86406f25ae9SGregory Neil Shapiro 	  case SSL_ERROR_WANT_WRITE:
8654e4196cbSGregory Neil Shapiro 		err = "read W BLOCK";
8664e4196cbSGregory Neil Shapiro 		/* FALLTHROUGH */
86706f25ae9SGregory Neil Shapiro 	  case SSL_ERROR_WANT_READ:
8684e4196cbSGregory Neil Shapiro 		if (err == NULL)
8694e4196cbSGregory Neil Shapiro 			err = "read R BLOCK";
8704e4196cbSGregory Neil Shapiro 		rfd = SSL_get_rfd(so->con);
8714e4196cbSGregory Neil Shapiro 		wfd = SSL_get_wfd(so->con);
8724e4196cbSGregory Neil Shapiro 		try = tls_retry(so->con, rfd, wfd, tlsstart,
8734e4196cbSGregory Neil Shapiro 				DATA_PROGRESS_TIMEOUT, ssl_err, "write");
8744e4196cbSGregory Neil Shapiro 		if (try > 0)
8754e4196cbSGregory Neil Shapiro 			goto retry;
8764e4196cbSGregory Neil Shapiro 		errno = SM_ERR_TIMEOUT;
87706f25ae9SGregory Neil Shapiro 		break;
87806f25ae9SGregory Neil Shapiro 	  case SSL_ERROR_WANT_X509_LOOKUP:
87906f25ae9SGregory Neil Shapiro 		err = "write X BLOCK";
88006f25ae9SGregory Neil Shapiro 		break;
88106f25ae9SGregory Neil Shapiro 	  case SSL_ERROR_SYSCALL:
88240266059SGregory Neil Shapiro 		if (r == 0 && errno == 0) /* out of protocol EOF found */
88340266059SGregory Neil Shapiro 			break;
88406f25ae9SGregory Neil Shapiro 		err = "syscall error";
88506f25ae9SGregory Neil Shapiro 		break;
88606f25ae9SGregory Neil Shapiro 	  case SSL_ERROR_SSL:
88706f25ae9SGregory Neil Shapiro 		err = "generic SSL error";
88806f25ae9SGregory Neil Shapiro /*
88906f25ae9SGregory Neil Shapiro 		ERR_GET_REASON(ERR_peek_error()));
89006f25ae9SGregory Neil Shapiro */
8915b0945b5SGregory Neil Shapiro 		tlslogerr(LOG_WARNING, 9, "write");
892959366dcSGregory Neil Shapiro 
893b6bacd31SGregory Neil Shapiro # if DEAL_WITH_ERROR_SSL
894959366dcSGregory Neil Shapiro 		/* avoid repeated calls? */
895959366dcSGregory Neil Shapiro 		if (r == 0)
896959366dcSGregory Neil Shapiro 			r = -1;
8975b0945b5SGregory Neil Shapiro # endif
89806f25ae9SGregory Neil Shapiro 		break;
89906f25ae9SGregory Neil Shapiro 	}
90006f25ae9SGregory Neil Shapiro 	if (err != NULL)
90140266059SGregory Neil Shapiro 	{
902605302a5SGregory Neil Shapiro 		int save_errno;
903605302a5SGregory Neil Shapiro 
904605302a5SGregory Neil Shapiro 		save_errno = (errno == 0) ? EIO : errno;
9054e4196cbSGregory Neil Shapiro 		if (try == 0 && save_errno == SM_ERR_TIMEOUT)
9064e4196cbSGregory Neil Shapiro 		{
9074e4196cbSGregory Neil Shapiro 			if (LogLevel > 7)
908a7ec597cSGregory Neil Shapiro 				sm_syslog(LOG_WARNING, NOQID,
9094e4196cbSGregory Neil Shapiro 					  "STARTTLS: write error=timeout");
9104e4196cbSGregory Neil Shapiro 		}
9114e4196cbSGregory Neil Shapiro 		else if (LogLevel > 8)
9124e4196cbSGregory Neil Shapiro 			sm_syslog(LOG_WARNING, NOQID,
9134e4196cbSGregory Neil Shapiro 				  "STARTTLS: write error=%s (%d), errno=%d, get_error=%s, retry=%d, ssl_err=%d",
914a7ec597cSGregory Neil Shapiro 				  err, r, errno,
9154e4196cbSGregory Neil Shapiro 				  ERR_error_string(ERR_get_error(), NULL), try,
9164e4196cbSGregory Neil Shapiro 				  ssl_err);
917a7ec597cSGregory Neil Shapiro 		else if (LogLevel > 7)
91840266059SGregory Neil Shapiro 			sm_syslog(LOG_WARNING, NOQID,
9194e4196cbSGregory Neil Shapiro 				  "STARTTLS: write error=%s (%d), errno=%d, retry=%d, ssl_err=%d",
9204e4196cbSGregory Neil Shapiro 				  err, r, errno, try, ssl_err);
921605302a5SGregory Neil Shapiro 		errno = save_errno;
92206f25ae9SGregory Neil Shapiro 	}
92306f25ae9SGregory Neil Shapiro 	return r;
92406f25ae9SGregory Neil Shapiro }
92506f25ae9SGregory Neil Shapiro 
92640266059SGregory Neil Shapiro /*
92740266059SGregory Neil Shapiro **  SFDCTLS -- create tls file type and open in and out file pointers
92840266059SGregory Neil Shapiro **	      for sendmail to read from and write to.
92940266059SGregory Neil Shapiro **
93040266059SGregory Neil Shapiro **	Parameters:
93140266059SGregory Neil Shapiro **		fin -- data input source being replaced
93240266059SGregory Neil Shapiro **		fout -- data output source being replaced
933a7ec597cSGregory Neil Shapiro **		con -- the tls connection pointer
93440266059SGregory Neil Shapiro **
93540266059SGregory Neil Shapiro **	Returns:
93640266059SGregory Neil Shapiro **		-1 on error
93740266059SGregory Neil Shapiro **		0 on success
93840266059SGregory Neil Shapiro **
93940266059SGregory Neil Shapiro **	Side effects:
94040266059SGregory Neil Shapiro **		The arguments "fin" and "fout" are replaced with the new
94140266059SGregory Neil Shapiro **		SM_FILE_T pointers.
94240266059SGregory Neil Shapiro **		The original "fin" and "fout" are preserved in the tls file
94340266059SGregory Neil Shapiro **		type but are not actually used because of the design of TLS.
94440266059SGregory Neil Shapiro */
94506f25ae9SGregory Neil Shapiro 
94606f25ae9SGregory Neil Shapiro int
sfdctls(fin,fout,con)94706f25ae9SGregory Neil Shapiro sfdctls(fin, fout, con)
94840266059SGregory Neil Shapiro 	SM_FILE_T **fin;
94940266059SGregory Neil Shapiro 	SM_FILE_T **fout;
95006f25ae9SGregory Neil Shapiro 	SSL *con;
95106f25ae9SGregory Neil Shapiro {
95240266059SGregory Neil Shapiro 	SM_FILE_T *tlsin, *tlsout;
95340266059SGregory Neil Shapiro 	SM_FILE_T SM_IO_SET_TYPE(tls_vector, "tls", tls_open, tls_close,
95440266059SGregory Neil Shapiro 		tls_read, tls_write, NULL, tls_getinfo, NULL,
95540266059SGregory Neil Shapiro 		SM_TIME_FOREVER);
95640266059SGregory Neil Shapiro 	struct tls_info info;
95706f25ae9SGregory Neil Shapiro 
95840266059SGregory Neil Shapiro 	SM_ASSERT(con != NULL);
95906f25ae9SGregory Neil Shapiro 
96040266059SGregory Neil Shapiro 	SM_IO_INIT_TYPE(tls_vector, "tls", tls_open, tls_close,
96140266059SGregory Neil Shapiro 		tls_read, tls_write, NULL, tls_getinfo, NULL,
96240266059SGregory Neil Shapiro 		SM_TIME_FOREVER);
96340266059SGregory Neil Shapiro 	info.fp = *fin;
96440266059SGregory Neil Shapiro 	info.con = con;
965e92d3f3fSGregory Neil Shapiro 	tlsin = sm_io_open(&tls_vector, SM_TIME_DEFAULT, &info, SM_IO_RDONLY_B,
96640266059SGregory Neil Shapiro 			   NULL);
96740266059SGregory Neil Shapiro 	if (tlsin == NULL)
96840266059SGregory Neil Shapiro 		return -1;
96906f25ae9SGregory Neil Shapiro 
97040266059SGregory Neil Shapiro 	info.fp = *fout;
971e92d3f3fSGregory Neil Shapiro 	tlsout = sm_io_open(&tls_vector, SM_TIME_DEFAULT, &info, SM_IO_WRONLY_B,
97240266059SGregory Neil Shapiro 			    NULL);
97340266059SGregory Neil Shapiro 	if (tlsout == NULL)
97442e5d165SGregory Neil Shapiro 	{
97540266059SGregory Neil Shapiro 		(void) sm_io_close(tlsin, SM_TIME_DEFAULT);
97642e5d165SGregory Neil Shapiro 		return -1;
97742e5d165SGregory Neil Shapiro 	}
97840266059SGregory Neil Shapiro 	sm_io_automode(tlsin, tlsout);
97906f25ae9SGregory Neil Shapiro 
98040266059SGregory Neil Shapiro 	*fin = tlsin;
98140266059SGregory Neil Shapiro 	*fout = tlsout;
98206f25ae9SGregory Neil Shapiro 	return 0;
98306f25ae9SGregory Neil Shapiro }
98440266059SGregory Neil Shapiro #endif /* STARTTLS */
985