xref: /freebsd/contrib/sendmail/src/sfsasl.c (revision 605302a5c9939b7eeda0a31f38901d9a8348e8cb)
106f25ae9SGregory Neil Shapiro /*
2605302a5SGregory Neil Shapiro  * Copyright (c) 1999-2002 Sendmail, Inc. and its suppliers.
306f25ae9SGregory Neil Shapiro  *	All rights reserved.
406f25ae9SGregory Neil Shapiro  *
506f25ae9SGregory Neil Shapiro  * By using this file, you agree to the terms and conditions set
606f25ae9SGregory Neil Shapiro  * forth in the LICENSE file which can be found at the top level of
706f25ae9SGregory Neil Shapiro  * the sendmail distribution.
806f25ae9SGregory Neil Shapiro  *
906f25ae9SGregory Neil Shapiro  */
1006f25ae9SGregory Neil Shapiro 
1140266059SGregory Neil Shapiro #include <sm/gen.h>
12605302a5SGregory Neil Shapiro SM_RCSID("@(#)$Id: sfsasl.c,v 8.89 2002/02/22 04:41:28 ca Exp $")
1306f25ae9SGregory Neil Shapiro #include <stdlib.h>
1406f25ae9SGregory Neil Shapiro #include <sendmail.h>
1540266059SGregory Neil Shapiro #include <errno.h>
1640266059SGregory Neil Shapiro #if SASL
1706f25ae9SGregory Neil Shapiro # include <sasl.h>
1806f25ae9SGregory Neil Shapiro # include "sfsasl.h"
1906f25ae9SGregory Neil Shapiro 
2040266059SGregory Neil Shapiro /* Structure used by the "sasl" file type */
2140266059SGregory Neil Shapiro struct sasl_obj
2240266059SGregory Neil Shapiro {
2340266059SGregory Neil Shapiro 	SM_FILE_T *fp;
2440266059SGregory Neil Shapiro 	sasl_conn_t *conn;
2540266059SGregory Neil Shapiro };
2640266059SGregory Neil Shapiro 
2740266059SGregory Neil Shapiro struct sasl_info
2840266059SGregory Neil Shapiro {
2940266059SGregory Neil Shapiro 	SM_FILE_T *fp;
3040266059SGregory Neil Shapiro 	sasl_conn_t *conn;
3140266059SGregory Neil Shapiro };
3240266059SGregory Neil Shapiro 
3340266059SGregory Neil Shapiro /*
3440266059SGregory Neil Shapiro **  SASL_GETINFO - returns requested information about a "sasl" file
3540266059SGregory Neil Shapiro **		  descriptor.
3640266059SGregory Neil Shapiro **
3740266059SGregory Neil Shapiro **	Parameters:
3840266059SGregory Neil Shapiro **		fp -- the file descriptor
3940266059SGregory Neil Shapiro **		what -- the type of information requested
4040266059SGregory Neil Shapiro **		valp -- the thang to return the information in
4140266059SGregory Neil Shapiro **
4240266059SGregory Neil Shapiro **	Returns:
4340266059SGregory Neil Shapiro **		-1 for unknown requests
4440266059SGregory Neil Shapiro **		>=0 on success with valp filled in (if possible).
4540266059SGregory Neil Shapiro */
4640266059SGregory Neil Shapiro 
4740266059SGregory Neil Shapiro static int sasl_getinfo __P((SM_FILE_T *, int, void *));
4840266059SGregory Neil Shapiro 
4940266059SGregory Neil Shapiro static int
5040266059SGregory Neil Shapiro sasl_getinfo(fp, what, valp)
5140266059SGregory Neil Shapiro 	SM_FILE_T *fp;
5240266059SGregory Neil Shapiro 	int what;
5340266059SGregory Neil Shapiro 	void *valp;
5440266059SGregory Neil Shapiro {
5540266059SGregory Neil Shapiro 	struct sasl_obj *so = (struct sasl_obj *) fp->f_cookie;
5640266059SGregory Neil Shapiro 
5740266059SGregory Neil Shapiro 	switch (what)
5840266059SGregory Neil Shapiro 	{
5940266059SGregory Neil Shapiro 	  case SM_IO_WHAT_FD:
6040266059SGregory Neil Shapiro 		if (so->fp == NULL)
6140266059SGregory Neil Shapiro 			return -1;
6240266059SGregory Neil Shapiro 		return so->fp->f_file; /* for stdio fileno() compatability */
6340266059SGregory Neil Shapiro 
6440266059SGregory Neil Shapiro 	  case SM_IO_IS_READABLE:
6540266059SGregory Neil Shapiro 		if (so->fp == NULL)
6640266059SGregory Neil Shapiro 			return 0;
6740266059SGregory Neil Shapiro 
6840266059SGregory Neil Shapiro 		/* get info from underlying file */
6940266059SGregory Neil Shapiro 		return sm_io_getinfo(so->fp, what, valp);
7040266059SGregory Neil Shapiro 
7140266059SGregory Neil Shapiro 	  default:
7240266059SGregory Neil Shapiro 		return -1;
7340266059SGregory Neil Shapiro 	}
7440266059SGregory Neil Shapiro }
7540266059SGregory Neil Shapiro 
7640266059SGregory Neil Shapiro /*
7740266059SGregory Neil Shapiro **  SASL_OPEN -- creates the sasl specific information for opening a
7840266059SGregory Neil Shapiro **		file of the sasl type.
7940266059SGregory Neil Shapiro **
8040266059SGregory Neil Shapiro **	Parameters:
8140266059SGregory Neil Shapiro **		fp -- the file pointer associated with the new open
8240266059SGregory Neil Shapiro **		info -- contains the sasl connection information pointer and
8340266059SGregory Neil Shapiro **			the original SM_FILE_T that holds the open
8440266059SGregory Neil Shapiro **		flags -- ignored
8540266059SGregory Neil Shapiro **		rpool -- ignored
8640266059SGregory Neil Shapiro **
8740266059SGregory Neil Shapiro **	Returns:
8840266059SGregory Neil Shapiro **		0 on success
8940266059SGregory Neil Shapiro */
9040266059SGregory Neil Shapiro 
9140266059SGregory Neil Shapiro static int sasl_open __P((SM_FILE_T *, const void *, int, const void *));
9240266059SGregory Neil Shapiro 
9340266059SGregory Neil Shapiro /* ARGSUSED2 */
9440266059SGregory Neil Shapiro static int
9540266059SGregory Neil Shapiro sasl_open(fp, info, flags, rpool)
9640266059SGregory Neil Shapiro 	SM_FILE_T *fp;
9740266059SGregory Neil Shapiro 	const void *info;
9840266059SGregory Neil Shapiro 	int flags;
9940266059SGregory Neil Shapiro 	const void *rpool;
10040266059SGregory Neil Shapiro {
10140266059SGregory Neil Shapiro 	struct sasl_obj *so;
10240266059SGregory Neil Shapiro 	struct sasl_info *si = (struct sasl_info *) info;
10340266059SGregory Neil Shapiro 
10440266059SGregory Neil Shapiro 	so = (struct sasl_obj *) sm_malloc(sizeof(struct sasl_obj));
10540266059SGregory Neil Shapiro 	so->fp = si->fp;
10640266059SGregory Neil Shapiro 	so->conn = si->conn;
10740266059SGregory Neil Shapiro 
10840266059SGregory Neil Shapiro 	/*
10940266059SGregory Neil Shapiro 	**  The underlying 'fp' is set to SM_IO_NOW so that the entire
11040266059SGregory Neil Shapiro 	**  encoded string is written in one chunk. Otherwise there is
11140266059SGregory Neil Shapiro 	**  the possibility that it may appear illegal, bogus or
11240266059SGregory Neil Shapiro 	**  mangled to the other side of the connection.
11340266059SGregory Neil Shapiro 	**  We will read or write through 'fp' since it is the opaque
11440266059SGregory Neil Shapiro 	**  connection for the communications. We need to treat it this
11540266059SGregory Neil Shapiro 	**  way in case the encoded string is to be sent down a TLS
11640266059SGregory Neil Shapiro 	**  connection rather than, say, sm_io's stdio.
11740266059SGregory Neil Shapiro 	*/
11840266059SGregory Neil Shapiro 
11940266059SGregory Neil Shapiro 	(void) sm_io_setvbuf(so->fp, SM_TIME_DEFAULT, NULL, SM_IO_NOW, 0);
12040266059SGregory Neil Shapiro 	fp->f_cookie = so;
12140266059SGregory Neil Shapiro 	return 0;
12240266059SGregory Neil Shapiro }
12340266059SGregory Neil Shapiro 
12440266059SGregory Neil Shapiro /*
12540266059SGregory Neil Shapiro **  SASL_CLOSE -- close the sasl specific parts of the sasl file pointer
12640266059SGregory Neil Shapiro **
12740266059SGregory Neil Shapiro **	Parameters:
12840266059SGregory Neil Shapiro **		fp -- the file pointer to close
12940266059SGregory Neil Shapiro **
13040266059SGregory Neil Shapiro **	Returns:
13140266059SGregory Neil Shapiro **		0 on success
13240266059SGregory Neil Shapiro */
13340266059SGregory Neil Shapiro 
13440266059SGregory Neil Shapiro static int sasl_close __P((SM_FILE_T *));
13540266059SGregory Neil Shapiro 
13640266059SGregory Neil Shapiro static int
13740266059SGregory Neil Shapiro sasl_close(fp)
13840266059SGregory Neil Shapiro 	SM_FILE_T *fp;
13940266059SGregory Neil Shapiro {
14040266059SGregory Neil Shapiro 	struct sasl_obj *so;
14140266059SGregory Neil Shapiro 
14240266059SGregory Neil Shapiro 	so = (struct sasl_obj *) fp->f_cookie;
14340266059SGregory Neil Shapiro 	if (so->fp != NULL)
14440266059SGregory Neil Shapiro 	{
14540266059SGregory Neil Shapiro 		sm_io_close(so->fp, SM_TIME_DEFAULT);
14640266059SGregory Neil Shapiro 		so->fp = NULL;
14740266059SGregory Neil Shapiro 	}
14840266059SGregory Neil Shapiro 	sm_free(so);
14940266059SGregory Neil Shapiro 	so = NULL;
15040266059SGregory Neil Shapiro 	return 0;
15140266059SGregory Neil Shapiro }
15240266059SGregory Neil Shapiro 
153193538b7SGregory Neil Shapiro /* how to deallocate a buffer allocated by SASL */
15440266059SGregory Neil Shapiro extern void	sm_sasl_free __P((void *));
15540266059SGregory Neil Shapiro # define SASL_DEALLOC(b)	sm_sasl_free(b)
15640266059SGregory Neil Shapiro 
15740266059SGregory Neil Shapiro /*
15840266059SGregory Neil Shapiro **  SASL_READ -- read encrypted information and decrypt it for the caller
15940266059SGregory Neil Shapiro **
16040266059SGregory Neil Shapiro **	Parameters:
16140266059SGregory Neil Shapiro **		fp -- the file pointer
16240266059SGregory Neil Shapiro **		buf -- the location to place the decrypted information
16340266059SGregory Neil Shapiro **		size -- the number of bytes to read after decryption
16440266059SGregory Neil Shapiro **
16540266059SGregory Neil Shapiro **	Results:
16640266059SGregory Neil Shapiro **		-1 on error
16740266059SGregory Neil Shapiro **		otherwise the number of bytes read
16840266059SGregory Neil Shapiro */
16940266059SGregory Neil Shapiro 
17040266059SGregory Neil Shapiro static ssize_t sasl_read __P((SM_FILE_T *, char *, size_t));
171193538b7SGregory Neil Shapiro 
17206f25ae9SGregory Neil Shapiro static ssize_t
17340266059SGregory Neil Shapiro sasl_read(fp, buf, size)
17440266059SGregory Neil Shapiro 	SM_FILE_T *fp;
17540266059SGregory Neil Shapiro 	char *buf;
17606f25ae9SGregory Neil Shapiro 	size_t size;
17706f25ae9SGregory Neil Shapiro {
17840266059SGregory Neil Shapiro 	int result;
17940266059SGregory Neil Shapiro 	ssize_t len;
180193538b7SGregory Neil Shapiro 	static char *outbuf = NULL;
181193538b7SGregory Neil Shapiro 	static unsigned int outlen = 0;
182193538b7SGregory Neil Shapiro 	static unsigned int offset = 0;
18340266059SGregory Neil Shapiro 	struct sasl_obj *so = (struct sasl_obj *) fp->f_cookie;
18406f25ae9SGregory Neil Shapiro 
185193538b7SGregory Neil Shapiro 	/*
186193538b7SGregory Neil Shapiro 	**  sasl_decode() may require more data than a single read() returns.
187193538b7SGregory Neil Shapiro 	**  Hence we have to put a loop around the decoding.
188193538b7SGregory Neil Shapiro 	**  This also requires that we may have to split up the returned
189193538b7SGregory Neil Shapiro 	**  data since it might be larger than the allowed size.
190193538b7SGregory Neil Shapiro 	**  Therefore we use a static pointer and return portions of it
191193538b7SGregory Neil Shapiro 	**  if necessary.
192193538b7SGregory Neil Shapiro 	*/
19306f25ae9SGregory Neil Shapiro 
194193538b7SGregory Neil Shapiro 	while (outbuf == NULL && outlen == 0)
195193538b7SGregory Neil Shapiro 	{
19640266059SGregory Neil Shapiro 		len = sm_io_read(so->fp, SM_TIME_DEFAULT, buf, size);
19706f25ae9SGregory Neil Shapiro 		if (len <= 0)
19806f25ae9SGregory Neil Shapiro 			return len;
19940266059SGregory Neil Shapiro 		result = sasl_decode(so->conn, buf,
20040266059SGregory Neil Shapiro 				     (unsigned int) len, &outbuf, &outlen);
20106f25ae9SGregory Neil Shapiro 		if (result != SASL_OK)
20206f25ae9SGregory Neil Shapiro 		{
203193538b7SGregory Neil Shapiro 			outbuf = NULL;
204193538b7SGregory Neil Shapiro 			offset = 0;
205193538b7SGregory Neil Shapiro 			outlen = 0;
20606f25ae9SGregory Neil Shapiro 			return -1;
20706f25ae9SGregory Neil Shapiro 		}
208193538b7SGregory Neil Shapiro 	}
20906f25ae9SGregory Neil Shapiro 
21040266059SGregory Neil Shapiro 	if (outbuf == NULL)
21106f25ae9SGregory Neil Shapiro 	{
21240266059SGregory Neil Shapiro 		/* be paranoid: outbuf == NULL but outlen != 0 */
21340266059SGregory Neil Shapiro 		syserr("@sasl_read failure: outbuf == NULL but outlen != 0");
21440266059SGregory Neil Shapiro 		/* NOTREACHED */
21540266059SGregory Neil Shapiro 	}
216193538b7SGregory Neil Shapiro 	if (outlen - offset > size)
217193538b7SGregory Neil Shapiro 	{
218193538b7SGregory Neil Shapiro 		/* return another part of the buffer */
21940266059SGregory Neil Shapiro 		(void) memcpy(buf, outbuf + offset, size);
220193538b7SGregory Neil Shapiro 		offset += size;
22140266059SGregory Neil Shapiro 		len = size;
22206f25ae9SGregory Neil Shapiro 	}
223193538b7SGregory Neil Shapiro 	else
224193538b7SGregory Neil Shapiro 	{
225193538b7SGregory Neil Shapiro 		/* return the rest of the buffer */
22640266059SGregory Neil Shapiro 		len = outlen - offset;
22740266059SGregory Neil Shapiro 		(void) memcpy(buf, outbuf + offset, (size_t) len);
228193538b7SGregory Neil Shapiro 		SASL_DEALLOC(outbuf);
229193538b7SGregory Neil Shapiro 		outbuf = NULL;
230193538b7SGregory Neil Shapiro 		offset = 0;
231193538b7SGregory Neil Shapiro 		outlen = 0;
232193538b7SGregory Neil Shapiro 	}
23340266059SGregory Neil Shapiro 	return len;
23406f25ae9SGregory Neil Shapiro }
23506f25ae9SGregory Neil Shapiro 
23640266059SGregory Neil Shapiro /*
23740266059SGregory Neil Shapiro **  SASL_WRITE -- write information out after encrypting it
23840266059SGregory Neil Shapiro **
23940266059SGregory Neil Shapiro **	Parameters:
24040266059SGregory Neil Shapiro **		fp -- the file pointer
24140266059SGregory Neil Shapiro **		buf -- holds the data to be encrypted and written
24240266059SGregory Neil Shapiro **		size -- the number of bytes to have encrypted and written
24340266059SGregory Neil Shapiro **
24440266059SGregory Neil Shapiro **	Returns:
24540266059SGregory Neil Shapiro **		-1 on error
24640266059SGregory Neil Shapiro **		otherwise number of bytes written
24740266059SGregory Neil Shapiro */
24840266059SGregory Neil Shapiro 
24940266059SGregory Neil Shapiro static ssize_t sasl_write __P((SM_FILE_T *, const char *, size_t));
25040266059SGregory Neil Shapiro 
25106f25ae9SGregory Neil Shapiro static ssize_t
25240266059SGregory Neil Shapiro sasl_write(fp, buf, size)
25340266059SGregory Neil Shapiro 	SM_FILE_T *fp;
25440266059SGregory Neil Shapiro 	const char *buf;
25506f25ae9SGregory Neil Shapiro 	size_t size;
25606f25ae9SGregory Neil Shapiro {
25706f25ae9SGregory Neil Shapiro 	int result;
25806f25ae9SGregory Neil Shapiro 	char *outbuf;
25906f25ae9SGregory Neil Shapiro 	unsigned int outlen;
26040266059SGregory Neil Shapiro 	size_t ret = 0, total = 0;
26140266059SGregory Neil Shapiro 	struct sasl_obj *so = (struct sasl_obj *) fp->f_cookie;
26206f25ae9SGregory Neil Shapiro 
26340266059SGregory Neil Shapiro 	result = sasl_encode(so->conn, buf,
26440266059SGregory Neil Shapiro 			     (unsigned int) size, &outbuf, &outlen);
26506f25ae9SGregory Neil Shapiro 
26606f25ae9SGregory Neil Shapiro 	if (result != SASL_OK)
26706f25ae9SGregory Neil Shapiro 		return -1;
26806f25ae9SGregory Neil Shapiro 
26906f25ae9SGregory Neil Shapiro 	if (outbuf != NULL)
27006f25ae9SGregory Neil Shapiro 	{
27140266059SGregory Neil Shapiro 		while (outlen > 0)
27240266059SGregory Neil Shapiro 		{
273605302a5SGregory Neil Shapiro 			/* XXX result == 0? */
27440266059SGregory Neil Shapiro 			ret = sm_io_write(so->fp, SM_TIME_DEFAULT,
27540266059SGregory Neil Shapiro 					  &outbuf[total], outlen);
27640266059SGregory Neil Shapiro 			outlen -= ret;
27740266059SGregory Neil Shapiro 			total += ret;
27840266059SGregory Neil Shapiro 		}
279193538b7SGregory Neil Shapiro 		SASL_DEALLOC(outbuf);
28006f25ae9SGregory Neil Shapiro 	}
28106f25ae9SGregory Neil Shapiro 	return size;
28206f25ae9SGregory Neil Shapiro }
28306f25ae9SGregory Neil Shapiro 
28440266059SGregory Neil Shapiro /*
28540266059SGregory Neil Shapiro **  SFDCSASL -- create sasl file type and open in and out file pointers
28640266059SGregory Neil Shapiro **	       for sendmail to read from and write to.
28740266059SGregory Neil Shapiro **
28840266059SGregory Neil Shapiro **	Parameters:
28940266059SGregory Neil Shapiro **		fin -- the sm_io file encrypted data to be read from
29040266059SGregory Neil Shapiro **		fout -- the sm_io file encrypted data to be writen to
29140266059SGregory Neil Shapiro **		conn -- the sasl connection pointer
29240266059SGregory Neil Shapiro **
29340266059SGregory Neil Shapiro **	Returns:
29440266059SGregory Neil Shapiro **		-1 on error
29540266059SGregory Neil Shapiro **		0 on success
29640266059SGregory Neil Shapiro **
29740266059SGregory Neil Shapiro **	Side effects:
29840266059SGregory Neil Shapiro **		The arguments "fin" and "fout" are replaced with the new
29940266059SGregory Neil Shapiro **		SM_FILE_T pointers.
30040266059SGregory Neil Shapiro */
30140266059SGregory Neil Shapiro 
30206f25ae9SGregory Neil Shapiro int
30306f25ae9SGregory Neil Shapiro sfdcsasl(fin, fout, conn)
30440266059SGregory Neil Shapiro 	SM_FILE_T **fin;
30540266059SGregory Neil Shapiro 	SM_FILE_T **fout;
30606f25ae9SGregory Neil Shapiro 	sasl_conn_t *conn;
30706f25ae9SGregory Neil Shapiro {
30840266059SGregory Neil Shapiro 	SM_FILE_T *newin, *newout;
30940266059SGregory Neil Shapiro 	SM_FILE_T  SM_IO_SET_TYPE(sasl_vector, "sasl", sasl_open, sasl_close,
31040266059SGregory Neil Shapiro 		sasl_read, sasl_write, NULL, sasl_getinfo, NULL,
31140266059SGregory Neil Shapiro 		SM_TIME_FOREVER);
31240266059SGregory Neil Shapiro 	struct sasl_info info;
31306f25ae9SGregory Neil Shapiro 
31406f25ae9SGregory Neil Shapiro 	if (conn == NULL)
31506f25ae9SGregory Neil Shapiro 	{
31606f25ae9SGregory Neil Shapiro 		/* no need to do anything */
31706f25ae9SGregory Neil Shapiro 		return 0;
31806f25ae9SGregory Neil Shapiro 	}
31906f25ae9SGregory Neil Shapiro 
32040266059SGregory Neil Shapiro 	SM_IO_INIT_TYPE(sasl_vector, "sasl", sasl_open, sasl_close,
32140266059SGregory Neil Shapiro 		sasl_read, sasl_write, NULL, sasl_getinfo, NULL,
32240266059SGregory Neil Shapiro 		SM_TIME_FOREVER);
32340266059SGregory Neil Shapiro 	info.fp = *fin;
32440266059SGregory Neil Shapiro 	info.conn = conn;
32540266059SGregory Neil Shapiro 	newin = sm_io_open(&sasl_vector, SM_TIME_DEFAULT, &info, SM_IO_RDONLY,
32640266059SGregory Neil Shapiro 			   NULL);
32706f25ae9SGregory Neil Shapiro 
32840266059SGregory Neil Shapiro 	if (newin == NULL)
32940266059SGregory Neil Shapiro 		return -1;
33006f25ae9SGregory Neil Shapiro 
33140266059SGregory Neil Shapiro 	info.fp = *fout;
33240266059SGregory Neil Shapiro 	info.conn = conn;
33340266059SGregory Neil Shapiro 	newout = sm_io_open(&sasl_vector, SM_TIME_DEFAULT, &info, SM_IO_WRONLY,
33440266059SGregory Neil Shapiro 			    NULL);
33506f25ae9SGregory Neil Shapiro 
33640266059SGregory Neil Shapiro 	if (newout == NULL)
33706f25ae9SGregory Neil Shapiro 	{
33840266059SGregory Neil Shapiro 		(void) sm_io_close(newin, SM_TIME_DEFAULT);
33906f25ae9SGregory Neil Shapiro 		return -1;
34006f25ae9SGregory Neil Shapiro 	}
34140266059SGregory Neil Shapiro 	sm_io_automode(newin, newout);
34240266059SGregory Neil Shapiro 
34340266059SGregory Neil Shapiro 	*fin = newin;
34440266059SGregory Neil Shapiro 	*fout = newout;
34506f25ae9SGregory Neil Shapiro 	return 0;
34606f25ae9SGregory Neil Shapiro }
34740266059SGregory Neil Shapiro #endif /* SASL */
34806f25ae9SGregory Neil Shapiro 
34940266059SGregory Neil Shapiro #if STARTTLS
35006f25ae9SGregory Neil Shapiro # include "sfsasl.h"
35106f25ae9SGregory Neil Shapiro #  include <openssl/err.h>
35206f25ae9SGregory Neil Shapiro 
35340266059SGregory Neil Shapiro /* Structure used by the "tls" file type */
35440266059SGregory Neil Shapiro struct tls_obj
35540266059SGregory Neil Shapiro {
35640266059SGregory Neil Shapiro 	SM_FILE_T *fp;
35740266059SGregory Neil Shapiro 	SSL *con;
35840266059SGregory Neil Shapiro };
35940266059SGregory Neil Shapiro 
36040266059SGregory Neil Shapiro struct tls_info
36140266059SGregory Neil Shapiro {
36240266059SGregory Neil Shapiro 	SM_FILE_T *fp;
36340266059SGregory Neil Shapiro 	SSL *con;
36440266059SGregory Neil Shapiro };
36540266059SGregory Neil Shapiro 
36640266059SGregory Neil Shapiro /*
36740266059SGregory Neil Shapiro **  TLS_GETINFO - returns requested information about a "tls" file
36840266059SGregory Neil Shapiro **		 descriptor.
36940266059SGregory Neil Shapiro **
37040266059SGregory Neil Shapiro **	Parameters:
37140266059SGregory Neil Shapiro **		fp -- the file descriptor
37240266059SGregory Neil Shapiro **		what -- the type of information requested
37340266059SGregory Neil Shapiro **		valp -- the thang to return the information in (unused)
37440266059SGregory Neil Shapiro **
37540266059SGregory Neil Shapiro **	Returns:
37640266059SGregory Neil Shapiro **		-1 for unknown requests
37740266059SGregory Neil Shapiro **		>=0 on success with valp filled in (if possible).
37840266059SGregory Neil Shapiro */
37940266059SGregory Neil Shapiro 
38040266059SGregory Neil Shapiro static int tls_getinfo __P((SM_FILE_T *, int, void *));
38140266059SGregory Neil Shapiro 
38240266059SGregory Neil Shapiro /* ARGSUSED2 */
38313058a91SGregory Neil Shapiro static int
38440266059SGregory Neil Shapiro tls_getinfo(fp, what, valp)
38540266059SGregory Neil Shapiro 	SM_FILE_T *fp;
38640266059SGregory Neil Shapiro 	int what;
38740266059SGregory Neil Shapiro 	void *valp;
38840266059SGregory Neil Shapiro {
38940266059SGregory Neil Shapiro 	struct tls_obj *so = (struct tls_obj *) fp->f_cookie;
39040266059SGregory Neil Shapiro 
39140266059SGregory Neil Shapiro 	switch (what)
39240266059SGregory Neil Shapiro 	{
39340266059SGregory Neil Shapiro 	  case SM_IO_WHAT_FD:
39440266059SGregory Neil Shapiro 		if (so->fp == NULL)
39540266059SGregory Neil Shapiro 			return -1;
39640266059SGregory Neil Shapiro 		return so->fp->f_file; /* for stdio fileno() compatability */
39740266059SGregory Neil Shapiro 
39840266059SGregory Neil Shapiro 	  case SM_IO_IS_READABLE:
39940266059SGregory Neil Shapiro 		return SSL_pending(so->con) > 0;
40040266059SGregory Neil Shapiro 
40140266059SGregory Neil Shapiro 	  default:
40240266059SGregory Neil Shapiro 		return -1;
40340266059SGregory Neil Shapiro 	}
40440266059SGregory Neil Shapiro }
40540266059SGregory Neil Shapiro 
40640266059SGregory Neil Shapiro /*
40740266059SGregory Neil Shapiro **  TLS_OPEN -- creates the tls specific information for opening a
40840266059SGregory Neil Shapiro **	       file of the tls type.
40940266059SGregory Neil Shapiro **
41040266059SGregory Neil Shapiro **	Parameters:
41140266059SGregory Neil Shapiro **		fp -- the file pointer associated with the new open
41240266059SGregory Neil Shapiro **		info -- the sm_io file pointer holding the open and the
41340266059SGregory Neil Shapiro **			TLS encryption connection to be read from or written to
41440266059SGregory Neil Shapiro **		flags -- ignored
41540266059SGregory Neil Shapiro **		rpool -- ignored
41640266059SGregory Neil Shapiro **
41740266059SGregory Neil Shapiro **	Returns:
41840266059SGregory Neil Shapiro **		0 on success
41940266059SGregory Neil Shapiro */
42040266059SGregory Neil Shapiro 
42140266059SGregory Neil Shapiro static int tls_open __P((SM_FILE_T *, const void *, int, const void *));
42240266059SGregory Neil Shapiro 
42340266059SGregory Neil Shapiro /* ARGSUSED2 */
42440266059SGregory Neil Shapiro static int
42540266059SGregory Neil Shapiro tls_open(fp, info, flags, rpool)
42640266059SGregory Neil Shapiro 	SM_FILE_T *fp;
42740266059SGregory Neil Shapiro 	const void *info;
42840266059SGregory Neil Shapiro 	int flags;
42940266059SGregory Neil Shapiro 	const void *rpool;
43040266059SGregory Neil Shapiro {
43140266059SGregory Neil Shapiro 	struct tls_obj *so;
43240266059SGregory Neil Shapiro 	struct tls_info *ti = (struct tls_info *) info;
43340266059SGregory Neil Shapiro 
43440266059SGregory Neil Shapiro 	so = (struct tls_obj *) sm_malloc(sizeof(struct tls_obj));
43540266059SGregory Neil Shapiro 	so->fp = ti->fp;
43640266059SGregory Neil Shapiro 	so->con = ti->con;
43740266059SGregory Neil Shapiro 
43840266059SGregory Neil Shapiro 	/*
43940266059SGregory Neil Shapiro 	**  We try to get the "raw" file descriptor that TLS uses to
44040266059SGregory Neil Shapiro 	**  do the actual read/write with. This is to allow us control
44140266059SGregory Neil Shapiro 	**  over the file descriptor being a blocking or non-blocking type.
44240266059SGregory Neil Shapiro 	**  Under the covers TLS handles the change and this allows us
44340266059SGregory Neil Shapiro 	**  to do timeouts with sm_io.
44440266059SGregory Neil Shapiro 	*/
44540266059SGregory Neil Shapiro 
44640266059SGregory Neil Shapiro 	fp->f_file = sm_io_getinfo(so->fp, SM_IO_WHAT_FD, NULL);
44740266059SGregory Neil Shapiro 	(void) sm_io_setvbuf(so->fp, SM_TIME_DEFAULT, NULL, SM_IO_NOW, 0);
44840266059SGregory Neil Shapiro 	fp->f_cookie = so;
44940266059SGregory Neil Shapiro 	return 0;
45040266059SGregory Neil Shapiro }
45140266059SGregory Neil Shapiro 
45240266059SGregory Neil Shapiro /*
45340266059SGregory Neil Shapiro **  TLS_CLOSE -- close the tls specific parts of the tls file pointer
45440266059SGregory Neil Shapiro **
45540266059SGregory Neil Shapiro **	Parameters:
45640266059SGregory Neil Shapiro **		fp -- the file pointer to close
45740266059SGregory Neil Shapiro **
45840266059SGregory Neil Shapiro **	Returns:
45940266059SGregory Neil Shapiro **		0 on success
46040266059SGregory Neil Shapiro */
46140266059SGregory Neil Shapiro 
46240266059SGregory Neil Shapiro static int tls_close __P((SM_FILE_T *));
46340266059SGregory Neil Shapiro 
46440266059SGregory Neil Shapiro static int
46540266059SGregory Neil Shapiro tls_close(fp)
46640266059SGregory Neil Shapiro 	SM_FILE_T *fp;
46740266059SGregory Neil Shapiro {
46840266059SGregory Neil Shapiro 	struct tls_obj *so;
46940266059SGregory Neil Shapiro 
47040266059SGregory Neil Shapiro 	so = (struct tls_obj *) fp->f_cookie;
47140266059SGregory Neil Shapiro 	if (so->fp != NULL)
47240266059SGregory Neil Shapiro 	{
47340266059SGregory Neil Shapiro 		sm_io_close(so->fp, SM_TIME_DEFAULT);
47440266059SGregory Neil Shapiro 		so->fp = NULL;
47540266059SGregory Neil Shapiro 	}
47640266059SGregory Neil Shapiro 	sm_free(so);
47740266059SGregory Neil Shapiro 	so = NULL;
47840266059SGregory Neil Shapiro 	return 0;
47940266059SGregory Neil Shapiro }
48040266059SGregory Neil Shapiro 
48140266059SGregory Neil Shapiro /* maximum number of retries for TLS related I/O due to handshakes */
48240266059SGregory Neil Shapiro # define MAX_TLS_IOS	4
48340266059SGregory Neil Shapiro 
48440266059SGregory Neil Shapiro /*
48540266059SGregory Neil Shapiro **  TLS_READ -- read secured information for the caller
48640266059SGregory Neil Shapiro **
48740266059SGregory Neil Shapiro **	Parameters:
48840266059SGregory Neil Shapiro **		fp -- the file pointer
48940266059SGregory Neil Shapiro **		buf -- the location to place the data
49040266059SGregory Neil Shapiro **		size -- the number of bytes to read from connection
49140266059SGregory Neil Shapiro **
49240266059SGregory Neil Shapiro **	Results:
49340266059SGregory Neil Shapiro **		-1 on error
49440266059SGregory Neil Shapiro **		otherwise the number of bytes read
49540266059SGregory Neil Shapiro */
49640266059SGregory Neil Shapiro 
49740266059SGregory Neil Shapiro static ssize_t tls_read __P((SM_FILE_T *, char *, size_t));
49840266059SGregory Neil Shapiro 
49940266059SGregory Neil Shapiro static ssize_t
50040266059SGregory Neil Shapiro tls_read(fp, buf, size)
50140266059SGregory Neil Shapiro 	SM_FILE_T *fp;
50213058a91SGregory Neil Shapiro 	char *buf;
50340266059SGregory Neil Shapiro 	size_t size;
50406f25ae9SGregory Neil Shapiro {
50506f25ae9SGregory Neil Shapiro 	int r;
50640266059SGregory Neil Shapiro 	static int again = MAX_TLS_IOS;
50740266059SGregory Neil Shapiro 	struct tls_obj *so = (struct tls_obj *) fp->f_cookie;
50806f25ae9SGregory Neil Shapiro 	char *err;
50906f25ae9SGregory Neil Shapiro 
51040266059SGregory Neil Shapiro 	r = SSL_read(so->con, (char *) buf, size);
51140266059SGregory Neil Shapiro 
51240266059SGregory Neil Shapiro 	if (r > 0)
51340266059SGregory Neil Shapiro 	{
51440266059SGregory Neil Shapiro 		again = MAX_TLS_IOS;
51540266059SGregory Neil Shapiro 		return r;
51640266059SGregory Neil Shapiro 	}
51740266059SGregory Neil Shapiro 
51806f25ae9SGregory Neil Shapiro 	err = NULL;
51940266059SGregory Neil Shapiro 	switch (SSL_get_error(so->con, r))
52006f25ae9SGregory Neil Shapiro 	{
52106f25ae9SGregory Neil Shapiro 	  case SSL_ERROR_NONE:
52240266059SGregory Neil Shapiro 	  case SSL_ERROR_ZERO_RETURN:
52340266059SGregory Neil Shapiro 		again = MAX_TLS_IOS;
52406f25ae9SGregory Neil Shapiro 		break;
52506f25ae9SGregory Neil Shapiro 	  case SSL_ERROR_WANT_WRITE:
52640266059SGregory Neil Shapiro 		if (--again <= 0)
52740266059SGregory Neil Shapiro 			err = "read W BLOCK";
52840266059SGregory Neil Shapiro 		else
52940266059SGregory Neil Shapiro 			errno = EAGAIN;
53006f25ae9SGregory Neil Shapiro 		break;
53106f25ae9SGregory Neil Shapiro 	  case SSL_ERROR_WANT_READ:
53240266059SGregory Neil Shapiro 		if (--again <= 0)
53340266059SGregory Neil Shapiro 			err = "read R BLOCK";
53440266059SGregory Neil Shapiro 		else
53540266059SGregory Neil Shapiro 			errno = EAGAIN;
53606f25ae9SGregory Neil Shapiro 		break;
53706f25ae9SGregory Neil Shapiro 	  case SSL_ERROR_WANT_X509_LOOKUP:
53806f25ae9SGregory Neil Shapiro 		err = "write X BLOCK";
53906f25ae9SGregory Neil Shapiro 		break;
54006f25ae9SGregory Neil Shapiro 	  case SSL_ERROR_SYSCALL:
54140266059SGregory Neil Shapiro 		if (r == 0 && errno == 0) /* out of protocol EOF found */
54240266059SGregory Neil Shapiro 			break;
54306f25ae9SGregory Neil Shapiro 		err = "syscall error";
54406f25ae9SGregory Neil Shapiro /*
54506f25ae9SGregory Neil Shapiro 		get_last_socket_error());
54606f25ae9SGregory Neil Shapiro */
54706f25ae9SGregory Neil Shapiro 		break;
54806f25ae9SGregory Neil Shapiro 	  case SSL_ERROR_SSL:
54906f25ae9SGregory Neil Shapiro 		err = "generic SSL error";
55040266059SGregory Neil Shapiro 		if (LogLevel > 9)
55140266059SGregory Neil Shapiro 			tlslogerr("read");
55206f25ae9SGregory Neil Shapiro 		break;
55306f25ae9SGregory Neil Shapiro 	}
55406f25ae9SGregory Neil Shapiro 	if (err != NULL)
55540266059SGregory Neil Shapiro 	{
556605302a5SGregory Neil Shapiro 		int save_errno;
557605302a5SGregory Neil Shapiro 
558605302a5SGregory Neil Shapiro 		save_errno = (errno == 0) ? EIO : errno;
55940266059SGregory Neil Shapiro 		again = MAX_TLS_IOS;
56040266059SGregory Neil Shapiro 		if (LogLevel > 7)
56140266059SGregory Neil Shapiro 			sm_syslog(LOG_WARNING, NOQID,
56240266059SGregory Neil Shapiro 				  "STARTTLS: read error=%s (%d)", err, r);
563605302a5SGregory Neil Shapiro 		errno = save_errno;
56406f25ae9SGregory Neil Shapiro 	}
56506f25ae9SGregory Neil Shapiro 	return r;
56606f25ae9SGregory Neil Shapiro }
56706f25ae9SGregory Neil Shapiro 
56840266059SGregory Neil Shapiro /*
56940266059SGregory Neil Shapiro **  TLS_WRITE -- write information out through secure connection
57040266059SGregory Neil Shapiro **
57140266059SGregory Neil Shapiro **	Parameters:
57240266059SGregory Neil Shapiro **		fp -- the file pointer
57340266059SGregory Neil Shapiro **		buf -- holds the data to be securely written
57440266059SGregory Neil Shapiro **		size -- the number of bytes to write
57540266059SGregory Neil Shapiro **
57640266059SGregory Neil Shapiro **	Returns:
57740266059SGregory Neil Shapiro **		-1 on error
57840266059SGregory Neil Shapiro **		otherwise number of bytes written
57940266059SGregory Neil Shapiro */
58040266059SGregory Neil Shapiro 
58140266059SGregory Neil Shapiro static ssize_t tls_write __P((SM_FILE_T *, const char *, size_t));
58240266059SGregory Neil Shapiro 
58313058a91SGregory Neil Shapiro static ssize_t
58440266059SGregory Neil Shapiro tls_write(fp, buf, size)
58540266059SGregory Neil Shapiro 	SM_FILE_T *fp;
58613058a91SGregory Neil Shapiro 	const char *buf;
58740266059SGregory Neil Shapiro 	size_t size;
58806f25ae9SGregory Neil Shapiro {
58906f25ae9SGregory Neil Shapiro 	int r;
59040266059SGregory Neil Shapiro 	static int again = MAX_TLS_IOS;
59140266059SGregory Neil Shapiro 	struct tls_obj *so = (struct tls_obj *) fp->f_cookie;
59206f25ae9SGregory Neil Shapiro 	char *err;
59306f25ae9SGregory Neil Shapiro 
59440266059SGregory Neil Shapiro 	r = SSL_write(so->con, (char *) buf, size);
59540266059SGregory Neil Shapiro 
59640266059SGregory Neil Shapiro 	if (r > 0)
59740266059SGregory Neil Shapiro 	{
59840266059SGregory Neil Shapiro 		again = MAX_TLS_IOS;
59940266059SGregory Neil Shapiro 		return r;
60040266059SGregory Neil Shapiro 	}
60106f25ae9SGregory Neil Shapiro 	err = NULL;
60240266059SGregory Neil Shapiro 	switch (SSL_get_error(so->con, r))
60306f25ae9SGregory Neil Shapiro 	{
60406f25ae9SGregory Neil Shapiro 	  case SSL_ERROR_NONE:
60540266059SGregory Neil Shapiro 	  case SSL_ERROR_ZERO_RETURN:
60640266059SGregory Neil Shapiro 		again = MAX_TLS_IOS;
60706f25ae9SGregory Neil Shapiro 		break;
60806f25ae9SGregory Neil Shapiro 	  case SSL_ERROR_WANT_WRITE:
60940266059SGregory Neil Shapiro 		if (--again <= 0)
61006f25ae9SGregory Neil Shapiro 			err = "write W BLOCK";
61140266059SGregory Neil Shapiro 		else
61240266059SGregory Neil Shapiro 			errno = EAGAIN;
61306f25ae9SGregory Neil Shapiro 		break;
61406f25ae9SGregory Neil Shapiro 	  case SSL_ERROR_WANT_READ:
61540266059SGregory Neil Shapiro 		if (--again <= 0)
61606f25ae9SGregory Neil Shapiro 			err = "write R BLOCK";
61740266059SGregory Neil Shapiro 		else
61840266059SGregory Neil Shapiro 			errno = EAGAIN;
61906f25ae9SGregory Neil Shapiro 		break;
62006f25ae9SGregory Neil Shapiro 	  case SSL_ERROR_WANT_X509_LOOKUP:
62106f25ae9SGregory Neil Shapiro 		err = "write X BLOCK";
62206f25ae9SGregory Neil Shapiro 		break;
62306f25ae9SGregory Neil Shapiro 	  case SSL_ERROR_SYSCALL:
62440266059SGregory Neil Shapiro 		if (r == 0 && errno == 0) /* out of protocol EOF found */
62540266059SGregory Neil Shapiro 			break;
62606f25ae9SGregory Neil Shapiro 		err = "syscall error";
62706f25ae9SGregory Neil Shapiro /*
62806f25ae9SGregory Neil Shapiro 		get_last_socket_error());
62906f25ae9SGregory Neil Shapiro */
63006f25ae9SGregory Neil Shapiro 		break;
63106f25ae9SGregory Neil Shapiro 	  case SSL_ERROR_SSL:
63206f25ae9SGregory Neil Shapiro 		err = "generic SSL error";
63306f25ae9SGregory Neil Shapiro /*
63406f25ae9SGregory Neil Shapiro 		ERR_GET_REASON(ERR_peek_error()));
63506f25ae9SGregory Neil Shapiro */
63640266059SGregory Neil Shapiro 		if (LogLevel > 9)
63740266059SGregory Neil Shapiro 			tlslogerr("write");
63806f25ae9SGregory Neil Shapiro 		break;
63906f25ae9SGregory Neil Shapiro 	}
64006f25ae9SGregory Neil Shapiro 	if (err != NULL)
64140266059SGregory Neil Shapiro 	{
642605302a5SGregory Neil Shapiro 		int save_errno;
643605302a5SGregory Neil Shapiro 
644605302a5SGregory Neil Shapiro 		save_errno = (errno == 0) ? EIO : errno;
64540266059SGregory Neil Shapiro 		again = MAX_TLS_IOS;
64640266059SGregory Neil Shapiro 		if (LogLevel > 7)
64740266059SGregory Neil Shapiro 			sm_syslog(LOG_WARNING, NOQID,
64840266059SGregory Neil Shapiro 				  "STARTTLS: write error=%s (%d)", err, r);
649605302a5SGregory Neil Shapiro 		errno = save_errno;
65006f25ae9SGregory Neil Shapiro 	}
65106f25ae9SGregory Neil Shapiro 	return r;
65206f25ae9SGregory Neil Shapiro }
65306f25ae9SGregory Neil Shapiro 
65440266059SGregory Neil Shapiro /*
65540266059SGregory Neil Shapiro **  SFDCTLS -- create tls file type and open in and out file pointers
65640266059SGregory Neil Shapiro **	      for sendmail to read from and write to.
65740266059SGregory Neil Shapiro **
65840266059SGregory Neil Shapiro **	Parameters:
65940266059SGregory Neil Shapiro **		fin -- data input source being replaced
66040266059SGregory Neil Shapiro **		fout -- data output source being replaced
66140266059SGregory Neil Shapiro **		conn -- the tls connection pointer
66240266059SGregory Neil Shapiro **
66340266059SGregory Neil Shapiro **	Returns:
66440266059SGregory Neil Shapiro **		-1 on error
66540266059SGregory Neil Shapiro **		0 on success
66640266059SGregory Neil Shapiro **
66740266059SGregory Neil Shapiro **	Side effects:
66840266059SGregory Neil Shapiro **		The arguments "fin" and "fout" are replaced with the new
66940266059SGregory Neil Shapiro **		SM_FILE_T pointers.
67040266059SGregory Neil Shapiro **		The original "fin" and "fout" are preserved in the tls file
67140266059SGregory Neil Shapiro **		type but are not actually used because of the design of TLS.
67240266059SGregory Neil Shapiro */
67306f25ae9SGregory Neil Shapiro 
67406f25ae9SGregory Neil Shapiro int
67506f25ae9SGregory Neil Shapiro sfdctls(fin, fout, con)
67640266059SGregory Neil Shapiro 	SM_FILE_T **fin;
67740266059SGregory Neil Shapiro 	SM_FILE_T **fout;
67806f25ae9SGregory Neil Shapiro 	SSL *con;
67906f25ae9SGregory Neil Shapiro {
68040266059SGregory Neil Shapiro 	SM_FILE_T *tlsin, *tlsout;
68140266059SGregory Neil Shapiro 	SM_FILE_T SM_IO_SET_TYPE(tls_vector, "tls", tls_open, tls_close,
68240266059SGregory Neil Shapiro 		tls_read, tls_write, NULL, tls_getinfo, NULL,
68340266059SGregory Neil Shapiro 		SM_TIME_FOREVER);
68440266059SGregory Neil Shapiro 	struct tls_info info;
68506f25ae9SGregory Neil Shapiro 
68640266059SGregory Neil Shapiro 	SM_ASSERT(con != NULL);
68706f25ae9SGregory Neil Shapiro 
68840266059SGregory Neil Shapiro 	SM_IO_INIT_TYPE(tls_vector, "tls", tls_open, tls_close,
68940266059SGregory Neil Shapiro 		tls_read, tls_write, NULL, tls_getinfo, NULL,
69040266059SGregory Neil Shapiro 		SM_TIME_FOREVER);
69140266059SGregory Neil Shapiro 	info.fp = *fin;
69240266059SGregory Neil Shapiro 	info.con = con;
69340266059SGregory Neil Shapiro 	tlsin = sm_io_open(&tls_vector, SM_TIME_DEFAULT, &info, SM_IO_RDONLY,
69440266059SGregory Neil Shapiro 			   NULL);
69540266059SGregory Neil Shapiro 	if (tlsin == NULL)
69640266059SGregory Neil Shapiro 		return -1;
69706f25ae9SGregory Neil Shapiro 
69840266059SGregory Neil Shapiro 	info.fp = *fout;
69940266059SGregory Neil Shapiro 	tlsout = sm_io_open(&tls_vector, SM_TIME_DEFAULT, &info, SM_IO_WRONLY,
70040266059SGregory Neil Shapiro 			    NULL);
70140266059SGregory Neil Shapiro 	if (tlsout == NULL)
70242e5d165SGregory Neil Shapiro 	{
70340266059SGregory Neil Shapiro 		(void) sm_io_close(tlsin, SM_TIME_DEFAULT);
70442e5d165SGregory Neil Shapiro 		return -1;
70542e5d165SGregory Neil Shapiro 	}
70640266059SGregory Neil Shapiro 	sm_io_automode(tlsin, tlsout);
70706f25ae9SGregory Neil Shapiro 
70840266059SGregory Neil Shapiro 	*fin = tlsin;
70940266059SGregory Neil Shapiro 	*fout = tlsout;
71006f25ae9SGregory Neil Shapiro 	return 0;
71106f25ae9SGregory Neil Shapiro }
71240266059SGregory Neil Shapiro #endif /* STARTTLS */
713