sfsasl.c revision 90792
164562Sgshapiro/*
277349Sgshapiro * Copyright (c) 1999-2001 Sendmail, Inc. and its suppliers.
364562Sgshapiro *	All rights reserved.
464562Sgshapiro *
564562Sgshapiro * By using this file, you agree to the terms and conditions set
664562Sgshapiro * forth in the LICENSE file which can be found at the top level of
764562Sgshapiro * the sendmail distribution.
864562Sgshapiro *
964562Sgshapiro */
1064562Sgshapiro
1190792Sgshapiro#include <sm/gen.h>
1290792SgshapiroSM_RCSID("@(#)$Id: sfsasl.c,v 8.86 2001/09/11 04:05:16 gshapiro Exp $")
1364562Sgshapiro#include <stdlib.h>
1464562Sgshapiro#include <sendmail.h>
1590792Sgshapiro#include <errno.h>
1690792Sgshapiro#if SASL
1790792Sgshapiro# include <sasl.h>
1890792Sgshapiro# include "sfsasl.h"
1964562Sgshapiro
2090792Sgshapiro/* Structure used by the "sasl" file type */
2190792Sgshapirostruct sasl_obj
2290792Sgshapiro{
2390792Sgshapiro	SM_FILE_T *fp;
2490792Sgshapiro	sasl_conn_t *conn;
2590792Sgshapiro};
2690792Sgshapiro
2790792Sgshapirostruct sasl_info
2890792Sgshapiro{
2990792Sgshapiro	SM_FILE_T *fp;
3090792Sgshapiro	sasl_conn_t *conn;
3190792Sgshapiro};
3290792Sgshapiro
3364562Sgshapiro/*
3490792Sgshapiro**  SASL_GETINFO - returns requested information about a "sasl" file
3590792Sgshapiro**		  descriptor.
3690792Sgshapiro**
3790792Sgshapiro**	Parameters:
3890792Sgshapiro**		fp -- the file descriptor
3990792Sgshapiro**		what -- the type of information requested
4090792Sgshapiro**		valp -- the thang to return the information in
4190792Sgshapiro**
4290792Sgshapiro**	Returns:
4390792Sgshapiro**		-1 for unknown requests
4490792Sgshapiro**		>=0 on success with valp filled in (if possible).
4564562Sgshapiro*/
4664562Sgshapiro
4790792Sgshapirostatic int sasl_getinfo __P((SM_FILE_T *, int, void *));
4864562Sgshapiro
4990792Sgshapirostatic int
5090792Sgshapirosasl_getinfo(fp, what, valp)
5190792Sgshapiro	SM_FILE_T *fp;
5290792Sgshapiro	int what;
5390792Sgshapiro	void *valp;
5490792Sgshapiro{
5590792Sgshapiro	struct sasl_obj *so = (struct sasl_obj *) fp->f_cookie;
5690792Sgshapiro
5790792Sgshapiro	switch (what)
5890792Sgshapiro	{
5990792Sgshapiro	  case SM_IO_WHAT_FD:
6090792Sgshapiro		if (so->fp == NULL)
6190792Sgshapiro			return -1;
6290792Sgshapiro		return so->fp->f_file; /* for stdio fileno() compatability */
6390792Sgshapiro
6490792Sgshapiro	  case SM_IO_IS_READABLE:
6590792Sgshapiro		if (so->fp == NULL)
6690792Sgshapiro			return 0;
6790792Sgshapiro
6890792Sgshapiro		/* get info from underlying file */
6990792Sgshapiro		return sm_io_getinfo(so->fp, what, valp);
7090792Sgshapiro
7190792Sgshapiro	  default:
7290792Sgshapiro		return -1;
7390792Sgshapiro	}
7490792Sgshapiro}
7590792Sgshapiro
7690792Sgshapiro/*
7790792Sgshapiro**  SASL_OPEN -- creates the sasl specific information for opening a
7890792Sgshapiro**		file of the sasl type.
7990792Sgshapiro**
8090792Sgshapiro**	Parameters:
8190792Sgshapiro**		fp -- the file pointer associated with the new open
8290792Sgshapiro**		info -- contains the sasl connection information pointer and
8390792Sgshapiro**			the original SM_FILE_T that holds the open
8490792Sgshapiro**		flags -- ignored
8590792Sgshapiro**		rpool -- ignored
8690792Sgshapiro**
8790792Sgshapiro**	Returns:
8890792Sgshapiro**		0 on success
8990792Sgshapiro*/
9090792Sgshapiro
9190792Sgshapirostatic int sasl_open __P((SM_FILE_T *, const void *, int, const void *));
9290792Sgshapiro
9390792Sgshapiro/* ARGSUSED2 */
9490792Sgshapirostatic int
9590792Sgshapirosasl_open(fp, info, flags, rpool)
9690792Sgshapiro	SM_FILE_T *fp;
9790792Sgshapiro	const void *info;
9890792Sgshapiro	int flags;
9990792Sgshapiro	const void *rpool;
10090792Sgshapiro{
10190792Sgshapiro	struct sasl_obj *so;
10290792Sgshapiro	struct sasl_info *si = (struct sasl_info *) info;
10390792Sgshapiro
10490792Sgshapiro	so = (struct sasl_obj *) sm_malloc(sizeof(struct sasl_obj));
10590792Sgshapiro	so->fp = si->fp;
10690792Sgshapiro	so->conn = si->conn;
10790792Sgshapiro
10890792Sgshapiro	/*
10990792Sgshapiro	**  The underlying 'fp' is set to SM_IO_NOW so that the entire
11090792Sgshapiro	**  encoded string is written in one chunk. Otherwise there is
11190792Sgshapiro	**  the possibility that it may appear illegal, bogus or
11290792Sgshapiro	**  mangled to the other side of the connection.
11390792Sgshapiro	**  We will read or write through 'fp' since it is the opaque
11490792Sgshapiro	**  connection for the communications. We need to treat it this
11590792Sgshapiro	**  way in case the encoded string is to be sent down a TLS
11690792Sgshapiro	**  connection rather than, say, sm_io's stdio.
11790792Sgshapiro	*/
11890792Sgshapiro
11990792Sgshapiro	(void) sm_io_setvbuf(so->fp, SM_TIME_DEFAULT, NULL, SM_IO_NOW, 0);
12090792Sgshapiro	fp->f_cookie = so;
12190792Sgshapiro	return 0;
12290792Sgshapiro}
12390792Sgshapiro
12490792Sgshapiro/*
12590792Sgshapiro**  SASL_CLOSE -- close the sasl specific parts of the sasl file pointer
12690792Sgshapiro**
12790792Sgshapiro**	Parameters:
12890792Sgshapiro**		fp -- the file pointer to close
12990792Sgshapiro**
13090792Sgshapiro**	Returns:
13190792Sgshapiro**		0 on success
13290792Sgshapiro*/
13390792Sgshapiro
13490792Sgshapirostatic int sasl_close __P((SM_FILE_T *));
13590792Sgshapiro
13690792Sgshapirostatic int
13790792Sgshapirosasl_close(fp)
13890792Sgshapiro	SM_FILE_T *fp;
13990792Sgshapiro{
14090792Sgshapiro	struct sasl_obj *so;
14190792Sgshapiro
14290792Sgshapiro	so = (struct sasl_obj *) fp->f_cookie;
14390792Sgshapiro	if (so->fp != NULL)
14490792Sgshapiro	{
14590792Sgshapiro		sm_io_close(so->fp, SM_TIME_DEFAULT);
14690792Sgshapiro		so->fp = NULL;
14790792Sgshapiro	}
14890792Sgshapiro	sm_free(so);
14990792Sgshapiro	so = NULL;
15090792Sgshapiro	return 0;
15190792Sgshapiro}
15290792Sgshapiro
15371345Sgshapiro/* how to deallocate a buffer allocated by SASL */
15490792Sgshapiroextern void	sm_sasl_free __P((void *));
15590792Sgshapiro# define SASL_DEALLOC(b)	sm_sasl_free(b)
15671345Sgshapiro
15790792Sgshapiro/*
15890792Sgshapiro**  SASL_READ -- read encrypted information and decrypt it for the caller
15990792Sgshapiro**
16090792Sgshapiro**	Parameters:
16190792Sgshapiro**		fp -- the file pointer
16290792Sgshapiro**		buf -- the location to place the decrypted information
16390792Sgshapiro**		size -- the number of bytes to read after decryption
16490792Sgshapiro**
16590792Sgshapiro**	Results:
16690792Sgshapiro**		-1 on error
16790792Sgshapiro**		otherwise the number of bytes read
16890792Sgshapiro*/
16990792Sgshapiro
17090792Sgshapirostatic ssize_t sasl_read __P((SM_FILE_T *, char *, size_t));
17190792Sgshapiro
17264562Sgshapirostatic ssize_t
17390792Sgshapirosasl_read(fp, buf, size)
17490792Sgshapiro	SM_FILE_T *fp;
17590792Sgshapiro	char *buf;
17664562Sgshapiro	size_t size;
17764562Sgshapiro{
17890792Sgshapiro	int result;
17990792Sgshapiro	ssize_t len;
18071345Sgshapiro	static char *outbuf = NULL;
18171345Sgshapiro	static unsigned int outlen = 0;
18271345Sgshapiro	static unsigned int offset = 0;
18390792Sgshapiro	struct sasl_obj *so = (struct sasl_obj *) fp->f_cookie;
18464562Sgshapiro
18571345Sgshapiro	/*
18671345Sgshapiro	**  sasl_decode() may require more data than a single read() returns.
18771345Sgshapiro	**  Hence we have to put a loop around the decoding.
18871345Sgshapiro	**  This also requires that we may have to split up the returned
18971345Sgshapiro	**  data since it might be larger than the allowed size.
19071345Sgshapiro	**  Therefore we use a static pointer and return portions of it
19171345Sgshapiro	**  if necessary.
19271345Sgshapiro	*/
19364562Sgshapiro
19471345Sgshapiro	while (outbuf == NULL && outlen == 0)
19564562Sgshapiro	{
19690792Sgshapiro		len = sm_io_read(so->fp, SM_TIME_DEFAULT, buf, size);
19771345Sgshapiro		if (len <= 0)
19871345Sgshapiro			return len;
19990792Sgshapiro		result = sasl_decode(so->conn, buf,
20090792Sgshapiro				     (unsigned int) len, &outbuf, &outlen);
20171345Sgshapiro		if (result != SASL_OK)
20271345Sgshapiro		{
20371345Sgshapiro			outbuf = NULL;
20471345Sgshapiro			offset = 0;
20571345Sgshapiro			outlen = 0;
20671345Sgshapiro			return -1;
20771345Sgshapiro		}
20864562Sgshapiro	}
20964562Sgshapiro
21090792Sgshapiro	if (outbuf == NULL)
21164562Sgshapiro	{
21290792Sgshapiro		/* be paranoid: outbuf == NULL but outlen != 0 */
21390792Sgshapiro		syserr("@sasl_read failure: outbuf == NULL but outlen != 0");
21490792Sgshapiro		/* NOTREACHED */
21564562Sgshapiro	}
21690792Sgshapiro	if (outlen - offset > size)
21790792Sgshapiro	{
21890792Sgshapiro		/* return another part of the buffer */
21990792Sgshapiro		(void) memcpy(buf, outbuf + offset, size);
22090792Sgshapiro		offset += size;
22190792Sgshapiro		len = size;
22290792Sgshapiro	}
22371345Sgshapiro	else
22471345Sgshapiro	{
22590792Sgshapiro		/* return the rest of the buffer */
22690792Sgshapiro		len = outlen - offset;
22790792Sgshapiro		(void) memcpy(buf, outbuf + offset, (size_t) len);
22890792Sgshapiro		SASL_DEALLOC(outbuf);
22990792Sgshapiro		outbuf = NULL;
23090792Sgshapiro		offset = 0;
23190792Sgshapiro		outlen = 0;
23271345Sgshapiro	}
23390792Sgshapiro	return len;
23464562Sgshapiro}
23564562Sgshapiro
23690792Sgshapiro/*
23790792Sgshapiro**  SASL_WRITE -- write information out after encrypting it
23890792Sgshapiro**
23990792Sgshapiro**	Parameters:
24090792Sgshapiro**		fp -- the file pointer
24190792Sgshapiro**		buf -- holds the data to be encrypted and written
24290792Sgshapiro**		size -- the number of bytes to have encrypted and written
24390792Sgshapiro**
24490792Sgshapiro**	Returns:
24590792Sgshapiro**		-1 on error
24690792Sgshapiro**		otherwise number of bytes written
24790792Sgshapiro*/
24890792Sgshapiro
24990792Sgshapirostatic ssize_t sasl_write __P((SM_FILE_T *, const char *, size_t));
25090792Sgshapiro
25164562Sgshapirostatic ssize_t
25290792Sgshapirosasl_write(fp, buf, size)
25390792Sgshapiro	SM_FILE_T *fp;
25490792Sgshapiro	const char *buf;
25564562Sgshapiro	size_t size;
25664562Sgshapiro{
25764562Sgshapiro	int result;
25864562Sgshapiro	char *outbuf;
25964562Sgshapiro	unsigned int outlen;
26090792Sgshapiro	size_t ret = 0, total = 0;
26190792Sgshapiro	struct sasl_obj *so = (struct sasl_obj *) fp->f_cookie;
26264562Sgshapiro
26390792Sgshapiro	result = sasl_encode(so->conn, buf,
26490792Sgshapiro			     (unsigned int) size, &outbuf, &outlen);
26564562Sgshapiro
26664562Sgshapiro	if (result != SASL_OK)
26764562Sgshapiro		return -1;
26864562Sgshapiro
26964562Sgshapiro	if (outbuf != NULL)
27064562Sgshapiro	{
27190792Sgshapiro		while (outlen > 0)
27290792Sgshapiro		{
27390792Sgshapiro			ret = sm_io_write(so->fp, SM_TIME_DEFAULT,
27490792Sgshapiro					  &outbuf[total], outlen);
27590792Sgshapiro			outlen -= ret;
27690792Sgshapiro			total += ret;
27790792Sgshapiro		}
27871345Sgshapiro		SASL_DEALLOC(outbuf);
27964562Sgshapiro	}
28064562Sgshapiro	return size;
28164562Sgshapiro}
28264562Sgshapiro
28390792Sgshapiro/*
28490792Sgshapiro**  SFDCSASL -- create sasl file type and open in and out file pointers
28590792Sgshapiro**	       for sendmail to read from and write to.
28690792Sgshapiro**
28790792Sgshapiro**	Parameters:
28890792Sgshapiro**		fin -- the sm_io file encrypted data to be read from
28990792Sgshapiro**		fout -- the sm_io file encrypted data to be writen to
29090792Sgshapiro**		conn -- the sasl connection pointer
29190792Sgshapiro**
29290792Sgshapiro**	Returns:
29390792Sgshapiro**		-1 on error
29490792Sgshapiro**		0 on success
29590792Sgshapiro**
29690792Sgshapiro**	Side effects:
29790792Sgshapiro**		The arguments "fin" and "fout" are replaced with the new
29890792Sgshapiro**		SM_FILE_T pointers.
29990792Sgshapiro*/
30090792Sgshapiro
30164562Sgshapiroint
30264562Sgshapirosfdcsasl(fin, fout, conn)
30390792Sgshapiro	SM_FILE_T **fin;
30490792Sgshapiro	SM_FILE_T **fout;
30564562Sgshapiro	sasl_conn_t *conn;
30664562Sgshapiro{
30790792Sgshapiro	SM_FILE_T *newin, *newout;
30890792Sgshapiro	SM_FILE_T  SM_IO_SET_TYPE(sasl_vector, "sasl", sasl_open, sasl_close,
30990792Sgshapiro		sasl_read, sasl_write, NULL, sasl_getinfo, NULL,
31090792Sgshapiro		SM_TIME_FOREVER);
31190792Sgshapiro	struct sasl_info info;
31264562Sgshapiro
31364562Sgshapiro	if (conn == NULL)
31464562Sgshapiro	{
31564562Sgshapiro		/* no need to do anything */
31664562Sgshapiro		return 0;
31764562Sgshapiro	}
31864562Sgshapiro
31990792Sgshapiro	SM_IO_INIT_TYPE(sasl_vector, "sasl", sasl_open, sasl_close,
32090792Sgshapiro		sasl_read, sasl_write, NULL, sasl_getinfo, NULL,
32190792Sgshapiro		SM_TIME_FOREVER);
32290792Sgshapiro	info.fp = *fin;
32390792Sgshapiro	info.conn = conn;
32490792Sgshapiro	newin = sm_io_open(&sasl_vector, SM_TIME_DEFAULT, &info, SM_IO_RDONLY,
32590792Sgshapiro			   NULL);
32664562Sgshapiro
32790792Sgshapiro	if (newin == NULL)
32890792Sgshapiro		return -1;
32964562Sgshapiro
33090792Sgshapiro	info.fp = *fout;
33190792Sgshapiro	info.conn = conn;
33290792Sgshapiro	newout = sm_io_open(&sasl_vector, SM_TIME_DEFAULT, &info, SM_IO_WRONLY,
33390792Sgshapiro			    NULL);
33464562Sgshapiro
33590792Sgshapiro	if (newout == NULL)
33664562Sgshapiro	{
33790792Sgshapiro		(void) sm_io_close(newin, SM_TIME_DEFAULT);
33864562Sgshapiro		return -1;
33964562Sgshapiro	}
34090792Sgshapiro	sm_io_automode(newin, newout);
34190792Sgshapiro
34290792Sgshapiro	*fin = newin;
34390792Sgshapiro	*fout = newout;
34464562Sgshapiro	return 0;
34564562Sgshapiro}
34690792Sgshapiro#endif /* SASL */
34764562Sgshapiro
34890792Sgshapiro#if STARTTLS
34990792Sgshapiro# include "sfsasl.h"
35090792Sgshapiro#  include <openssl/err.h>
35190792Sgshapiro
35290792Sgshapiro/* Structure used by the "tls" file type */
35390792Sgshapirostruct tls_obj
35490792Sgshapiro{
35590792Sgshapiro	SM_FILE_T *fp;
35690792Sgshapiro	SSL *con;
35790792Sgshapiro};
35890792Sgshapiro
35990792Sgshapirostruct tls_info
36090792Sgshapiro{
36190792Sgshapiro	SM_FILE_T *fp;
36290792Sgshapiro	SSL *con;
36390792Sgshapiro};
36490792Sgshapiro
36564562Sgshapiro/*
36690792Sgshapiro**  TLS_GETINFO - returns requested information about a "tls" file
36790792Sgshapiro**		 descriptor.
36890792Sgshapiro**
36990792Sgshapiro**	Parameters:
37090792Sgshapiro**		fp -- the file descriptor
37190792Sgshapiro**		what -- the type of information requested
37290792Sgshapiro**		valp -- the thang to return the information in (unused)
37390792Sgshapiro**
37490792Sgshapiro**	Returns:
37590792Sgshapiro**		-1 for unknown requests
37690792Sgshapiro**		>=0 on success with valp filled in (if possible).
37764562Sgshapiro*/
37864562Sgshapiro
37990792Sgshapirostatic int tls_getinfo __P((SM_FILE_T *, int, void *));
38064562Sgshapiro
38190792Sgshapiro/* ARGSUSED2 */
38280785Sgshapirostatic int
38390792Sgshapirotls_getinfo(fp, what, valp)
38490792Sgshapiro	SM_FILE_T *fp;
38590792Sgshapiro	int what;
38690792Sgshapiro	void *valp;
38764562Sgshapiro{
38890792Sgshapiro	struct tls_obj *so = (struct tls_obj *) fp->f_cookie;
38964562Sgshapiro
39090792Sgshapiro	switch (what)
39164562Sgshapiro	{
39290792Sgshapiro	  case SM_IO_WHAT_FD:
39390792Sgshapiro		if (so->fp == NULL)
39490792Sgshapiro			return -1;
39590792Sgshapiro		return so->fp->f_file; /* for stdio fileno() compatability */
39664562Sgshapiro
39790792Sgshapiro	  case SM_IO_IS_READABLE:
39890792Sgshapiro		return SSL_pending(so->con) > 0;
39990792Sgshapiro
40090792Sgshapiro	  default:
40190792Sgshapiro		return -1;
40290792Sgshapiro	}
40390792Sgshapiro}
40490792Sgshapiro
40564562Sgshapiro/*
40690792Sgshapiro**  TLS_OPEN -- creates the tls specific information for opening a
40790792Sgshapiro**	       file of the tls type.
40890792Sgshapiro**
40990792Sgshapiro**	Parameters:
41090792Sgshapiro**		fp -- the file pointer associated with the new open
41190792Sgshapiro**		info -- the sm_io file pointer holding the open and the
41290792Sgshapiro**			TLS encryption connection to be read from or written to
41390792Sgshapiro**		flags -- ignored
41490792Sgshapiro**		rpool -- ignored
41590792Sgshapiro**
41690792Sgshapiro**	Returns:
41790792Sgshapiro**		0 on success
41864562Sgshapiro*/
41990792Sgshapiro
42090792Sgshapirostatic int tls_open __P((SM_FILE_T *, const void *, int, const void *));
42190792Sgshapiro
42290792Sgshapiro/* ARGSUSED2 */
42390792Sgshapirostatic int
42490792Sgshapirotls_open(fp, info, flags, rpool)
42590792Sgshapiro	SM_FILE_T *fp;
42690792Sgshapiro	const void *info;
42790792Sgshapiro	int flags;
42890792Sgshapiro	const void *rpool;
42990792Sgshapiro{
43090792Sgshapiro	struct tls_obj *so;
43190792Sgshapiro	struct tls_info *ti = (struct tls_info *) info;
43290792Sgshapiro
43390792Sgshapiro	so = (struct tls_obj *) sm_malloc(sizeof(struct tls_obj));
43490792Sgshapiro	so->fp = ti->fp;
43590792Sgshapiro	so->con = ti->con;
43690792Sgshapiro
43790792Sgshapiro	/*
43890792Sgshapiro	**  We try to get the "raw" file descriptor that TLS uses to
43990792Sgshapiro	**  do the actual read/write with. This is to allow us control
44090792Sgshapiro	**  over the file descriptor being a blocking or non-blocking type.
44190792Sgshapiro	**  Under the covers TLS handles the change and this allows us
44290792Sgshapiro	**  to do timeouts with sm_io.
44390792Sgshapiro	*/
44490792Sgshapiro
44590792Sgshapiro	fp->f_file = sm_io_getinfo(so->fp, SM_IO_WHAT_FD, NULL);
44690792Sgshapiro	(void) sm_io_setvbuf(so->fp, SM_TIME_DEFAULT, NULL, SM_IO_NOW, 0);
44790792Sgshapiro	fp->f_cookie = so;
44890792Sgshapiro	return 0;
44990792Sgshapiro}
45090792Sgshapiro
45190792Sgshapiro/*
45290792Sgshapiro**  TLS_CLOSE -- close the tls specific parts of the tls file pointer
45390792Sgshapiro**
45490792Sgshapiro**	Parameters:
45590792Sgshapiro**		fp -- the file pointer to close
45690792Sgshapiro**
45790792Sgshapiro**	Returns:
45890792Sgshapiro**		0 on success
45990792Sgshapiro*/
46090792Sgshapiro
46190792Sgshapirostatic int tls_close __P((SM_FILE_T *));
46290792Sgshapiro
46390792Sgshapirostatic int
46490792Sgshapirotls_close(fp)
46590792Sgshapiro	SM_FILE_T *fp;
46690792Sgshapiro{
46790792Sgshapiro	struct tls_obj *so;
46890792Sgshapiro
46990792Sgshapiro	so = (struct tls_obj *) fp->f_cookie;
47090792Sgshapiro	if (so->fp != NULL)
47190792Sgshapiro	{
47290792Sgshapiro		sm_io_close(so->fp, SM_TIME_DEFAULT);
47390792Sgshapiro		so->fp = NULL;
47464562Sgshapiro	}
47590792Sgshapiro	sm_free(so);
47690792Sgshapiro	so = NULL;
47790792Sgshapiro	return 0;
47864562Sgshapiro}
47964562Sgshapiro
48090792Sgshapiro/* maximum number of retries for TLS related I/O due to handshakes */
48190792Sgshapiro# define MAX_TLS_IOS	4
48290792Sgshapiro
48390792Sgshapiro/*
48490792Sgshapiro**  TLS_READ -- read secured information for the caller
48590792Sgshapiro**
48690792Sgshapiro**	Parameters:
48790792Sgshapiro**		fp -- the file pointer
48890792Sgshapiro**		buf -- the location to place the data
48990792Sgshapiro**		size -- the number of bytes to read from connection
49090792Sgshapiro**
49190792Sgshapiro**	Results:
49290792Sgshapiro**		-1 on error
49390792Sgshapiro**		otherwise the number of bytes read
49490792Sgshapiro*/
49590792Sgshapiro
49690792Sgshapirostatic ssize_t tls_read __P((SM_FILE_T *, char *, size_t));
49790792Sgshapiro
49864562Sgshapirostatic ssize_t
49990792Sgshapirotls_read(fp, buf, size)
50090792Sgshapiro	SM_FILE_T *fp;
50190792Sgshapiro	char *buf;
50264562Sgshapiro	size_t size;
50364562Sgshapiro{
50464562Sgshapiro	int r;
50590792Sgshapiro	static int again = MAX_TLS_IOS;
50690792Sgshapiro	struct tls_obj *so = (struct tls_obj *) fp->f_cookie;
50790792Sgshapiro	char *err;
50864562Sgshapiro
50990792Sgshapiro	r = SSL_read(so->con, (char *) buf, size);
51064562Sgshapiro
51190792Sgshapiro	if (r > 0)
51264562Sgshapiro	{
51390792Sgshapiro		again = MAX_TLS_IOS;
51490792Sgshapiro		return r;
51590792Sgshapiro	}
51664562Sgshapiro
51790792Sgshapiro	err = NULL;
51890792Sgshapiro	switch (SSL_get_error(so->con, r))
51990792Sgshapiro	{
52090792Sgshapiro	  case SSL_ERROR_NONE:
52190792Sgshapiro	  case SSL_ERROR_ZERO_RETURN:
52290792Sgshapiro		again = MAX_TLS_IOS;
52390792Sgshapiro		break;
52490792Sgshapiro	  case SSL_ERROR_WANT_WRITE:
52590792Sgshapiro		if (--again <= 0)
52690792Sgshapiro			err = "read W BLOCK";
52790792Sgshapiro		else
52890792Sgshapiro			errno = EAGAIN;
52990792Sgshapiro		break;
53090792Sgshapiro	  case SSL_ERROR_WANT_READ:
53190792Sgshapiro		if (--again <= 0)
53290792Sgshapiro			err = "read R BLOCK";
53390792Sgshapiro		else
53490792Sgshapiro			errno = EAGAIN;
53590792Sgshapiro		break;
53690792Sgshapiro	  case SSL_ERROR_WANT_X509_LOOKUP:
53790792Sgshapiro		err = "write X BLOCK";
53890792Sgshapiro		break;
53990792Sgshapiro	  case SSL_ERROR_SYSCALL:
54090792Sgshapiro		if (r == 0 && errno == 0) /* out of protocol EOF found */
54190792Sgshapiro			break;
54290792Sgshapiro		err = "syscall error";
54364562Sgshapiro/*
54490792Sgshapiro		get_last_socket_error());
54564562Sgshapiro*/
54690792Sgshapiro		break;
54790792Sgshapiro	  case SSL_ERROR_SSL:
54890792Sgshapiro		err = "generic SSL error";
54990792Sgshapiro		if (LogLevel > 9)
55090792Sgshapiro			tlslogerr("read");
55190792Sgshapiro		break;
55264562Sgshapiro	}
55390792Sgshapiro	if (err != NULL)
55490792Sgshapiro	{
55590792Sgshapiro		again = MAX_TLS_IOS;
55690792Sgshapiro		if (errno == 0)
55790792Sgshapiro			errno = EIO;
55890792Sgshapiro		if (LogLevel > 7)
55990792Sgshapiro			sm_syslog(LOG_WARNING, NOQID,
56090792Sgshapiro				  "STARTTLS: read error=%s (%d)", err, r);
56190792Sgshapiro	}
56264562Sgshapiro	return r;
56364562Sgshapiro}
56464562Sgshapiro
56590792Sgshapiro/*
56690792Sgshapiro**  TLS_WRITE -- write information out through secure connection
56790792Sgshapiro**
56890792Sgshapiro**	Parameters:
56990792Sgshapiro**		fp -- the file pointer
57090792Sgshapiro**		buf -- holds the data to be securely written
57190792Sgshapiro**		size -- the number of bytes to write
57290792Sgshapiro**
57390792Sgshapiro**	Returns:
57490792Sgshapiro**		-1 on error
57590792Sgshapiro**		otherwise number of bytes written
57690792Sgshapiro*/
57790792Sgshapiro
57890792Sgshapirostatic ssize_t tls_write __P((SM_FILE_T *, const char *, size_t));
57990792Sgshapiro
58090792Sgshapirostatic ssize_t
58190792Sgshapirotls_write(fp, buf, size)
58290792Sgshapiro	SM_FILE_T *fp;
58390792Sgshapiro	const char *buf;
58490792Sgshapiro	size_t size;
58564562Sgshapiro{
58690792Sgshapiro	int r;
58790792Sgshapiro	static int again = MAX_TLS_IOS;
58890792Sgshapiro	struct tls_obj *so = (struct tls_obj *) fp->f_cookie;
58990792Sgshapiro	char *err;
59064562Sgshapiro
59190792Sgshapiro	r = SSL_write(so->con, (char *) buf, size);
59264562Sgshapiro
59390792Sgshapiro	if (r > 0)
59464562Sgshapiro	{
59590792Sgshapiro		again = MAX_TLS_IOS;
59690792Sgshapiro		return r;
59764562Sgshapiro	}
59890792Sgshapiro	err = NULL;
59990792Sgshapiro	switch (SSL_get_error(so->con, r))
60090792Sgshapiro	{
60190792Sgshapiro	  case SSL_ERROR_NONE:
60290792Sgshapiro	  case SSL_ERROR_ZERO_RETURN:
60390792Sgshapiro		again = MAX_TLS_IOS;
60490792Sgshapiro		break;
60590792Sgshapiro	  case SSL_ERROR_WANT_WRITE:
60690792Sgshapiro		if (--again <= 0)
60790792Sgshapiro			err = "write W BLOCK";
60890792Sgshapiro		else
60990792Sgshapiro			errno = EAGAIN;
61090792Sgshapiro		break;
61190792Sgshapiro	  case SSL_ERROR_WANT_READ:
61290792Sgshapiro		if (--again <= 0)
61390792Sgshapiro			err = "write R BLOCK";
61490792Sgshapiro		else
61590792Sgshapiro			errno = EAGAIN;
61690792Sgshapiro		break;
61790792Sgshapiro	  case SSL_ERROR_WANT_X509_LOOKUP:
61890792Sgshapiro		err = "write X BLOCK";
61990792Sgshapiro		break;
62090792Sgshapiro	  case SSL_ERROR_SYSCALL:
62190792Sgshapiro		if (r == 0 && errno == 0) /* out of protocol EOF found */
62290792Sgshapiro			break;
62390792Sgshapiro		err = "syscall error";
62490792Sgshapiro/*
62590792Sgshapiro		get_last_socket_error());
62690792Sgshapiro*/
62790792Sgshapiro		break;
62890792Sgshapiro	  case SSL_ERROR_SSL:
62990792Sgshapiro		err = "generic SSL error";
63090792Sgshapiro/*
63190792Sgshapiro		ERR_GET_REASON(ERR_peek_error()));
63290792Sgshapiro*/
63390792Sgshapiro		if (LogLevel > 9)
63490792Sgshapiro			tlslogerr("write");
63590792Sgshapiro		break;
63690792Sgshapiro	}
63790792Sgshapiro	if (err != NULL)
63890792Sgshapiro	{
63990792Sgshapiro		again = MAX_TLS_IOS;
64090792Sgshapiro		if (errno == 0)
64190792Sgshapiro			errno = EIO;
64290792Sgshapiro		if (LogLevel > 7)
64390792Sgshapiro			sm_syslog(LOG_WARNING, NOQID,
64490792Sgshapiro				  "STARTTLS: write error=%s (%d)", err, r);
64590792Sgshapiro	}
64690792Sgshapiro	return r;
64764562Sgshapiro}
64864562Sgshapiro
64990792Sgshapiro/*
65090792Sgshapiro**  SFDCTLS -- create tls file type and open in and out file pointers
65190792Sgshapiro**	      for sendmail to read from and write to.
65290792Sgshapiro**
65390792Sgshapiro**	Parameters:
65490792Sgshapiro**		fin -- data input source being replaced
65590792Sgshapiro**		fout -- data output source being replaced
65690792Sgshapiro**		conn -- the tls connection pointer
65790792Sgshapiro**
65890792Sgshapiro**	Returns:
65990792Sgshapiro**		-1 on error
66090792Sgshapiro**		0 on success
66190792Sgshapiro**
66290792Sgshapiro**	Side effects:
66390792Sgshapiro**		The arguments "fin" and "fout" are replaced with the new
66490792Sgshapiro**		SM_FILE_T pointers.
66590792Sgshapiro**		The original "fin" and "fout" are preserved in the tls file
66690792Sgshapiro**		type but are not actually used because of the design of TLS.
66790792Sgshapiro*/
66890792Sgshapiro
66964562Sgshapiroint
67064562Sgshapirosfdctls(fin, fout, con)
67190792Sgshapiro	SM_FILE_T **fin;
67290792Sgshapiro	SM_FILE_T **fout;
67364562Sgshapiro	SSL *con;
67464562Sgshapiro{
67590792Sgshapiro	SM_FILE_T *tlsin, *tlsout;
67690792Sgshapiro	SM_FILE_T SM_IO_SET_TYPE(tls_vector, "tls", tls_open, tls_close,
67790792Sgshapiro		tls_read, tls_write, NULL, tls_getinfo, NULL,
67890792Sgshapiro		SM_TIME_FOREVER);
67990792Sgshapiro	struct tls_info info;
68064562Sgshapiro
68190792Sgshapiro	SM_ASSERT(con != NULL);
68264562Sgshapiro
68390792Sgshapiro	SM_IO_INIT_TYPE(tls_vector, "tls", tls_open, tls_close,
68490792Sgshapiro		tls_read, tls_write, NULL, tls_getinfo, NULL,
68590792Sgshapiro		SM_TIME_FOREVER);
68690792Sgshapiro	info.fp = *fin;
68790792Sgshapiro	info.con = con;
68890792Sgshapiro	tlsin = sm_io_open(&tls_vector, SM_TIME_DEFAULT, &info, SM_IO_RDONLY,
68990792Sgshapiro			   NULL);
69090792Sgshapiro	if (tlsin == NULL)
69190792Sgshapiro		return -1;
69264562Sgshapiro
69390792Sgshapiro	info.fp = *fout;
69490792Sgshapiro	tlsout = sm_io_open(&tls_vector, SM_TIME_DEFAULT, &info, SM_IO_WRONLY,
69590792Sgshapiro			    NULL);
69690792Sgshapiro	if (tlsout == NULL)
69766494Sgshapiro	{
69890792Sgshapiro		(void) sm_io_close(tlsin, SM_TIME_DEFAULT);
69966494Sgshapiro		return -1;
70066494Sgshapiro	}
70190792Sgshapiro	sm_io_automode(tlsin, tlsout);
70264562Sgshapiro
70390792Sgshapiro	*fin = tlsin;
70490792Sgshapiro	*fout = tlsout;
70564562Sgshapiro	return 0;
70664562Sgshapiro}
70790792Sgshapiro#endif /* STARTTLS */
708