sfsasl.c revision 102528
1/*
2 * Copyright (c) 1999-2002 Sendmail, Inc. and its suppliers.
3 *	All rights reserved.
4 *
5 * By using this file, you agree to the terms and conditions set
6 * forth in the LICENSE file which can be found at the top level of
7 * the sendmail distribution.
8 *
9 */
10
11#include <sm/gen.h>
12SM_RCSID("@(#)$Id: sfsasl.c,v 8.91.2.1 2002/08/27 01:35:17 ca Exp $")
13#include <stdlib.h>
14#include <sendmail.h>
15#include <errno.h>
16#if SASL
17# include "sfsasl.h"
18
19/* Structure used by the "sasl" file type */
20struct sasl_obj
21{
22	SM_FILE_T *fp;
23	sasl_conn_t *conn;
24};
25
26struct sasl_info
27{
28	SM_FILE_T *fp;
29	sasl_conn_t *conn;
30};
31
32/*
33**  SASL_GETINFO - returns requested information about a "sasl" file
34**		  descriptor.
35**
36**	Parameters:
37**		fp -- the file descriptor
38**		what -- the type of information requested
39**		valp -- the thang to return the information in
40**
41**	Returns:
42**		-1 for unknown requests
43**		>=0 on success with valp filled in (if possible).
44*/
45
46static int sasl_getinfo __P((SM_FILE_T *, int, void *));
47
48static int
49sasl_getinfo(fp, what, valp)
50	SM_FILE_T *fp;
51	int what;
52	void *valp;
53{
54	struct sasl_obj *so = (struct sasl_obj *) fp->f_cookie;
55
56	switch (what)
57	{
58	  case SM_IO_WHAT_FD:
59		if (so->fp == NULL)
60			return -1;
61		return so->fp->f_file; /* for stdio fileno() compatability */
62
63	  case SM_IO_IS_READABLE:
64		if (so->fp == NULL)
65			return 0;
66
67		/* get info from underlying file */
68		return sm_io_getinfo(so->fp, what, valp);
69
70	  default:
71		return -1;
72	}
73}
74
75/*
76**  SASL_OPEN -- creates the sasl specific information for opening a
77**		file of the sasl type.
78**
79**	Parameters:
80**		fp -- the file pointer associated with the new open
81**		info -- contains the sasl connection information pointer and
82**			the original SM_FILE_T that holds the open
83**		flags -- ignored
84**		rpool -- ignored
85**
86**	Returns:
87**		0 on success
88*/
89
90static int sasl_open __P((SM_FILE_T *, const void *, int, const void *));
91
92/* ARGSUSED2 */
93static int
94sasl_open(fp, info, flags, rpool)
95	SM_FILE_T *fp;
96	const void *info;
97	int flags;
98	const void *rpool;
99{
100	struct sasl_obj *so;
101	struct sasl_info *si = (struct sasl_info *) info;
102
103	so = (struct sasl_obj *) sm_malloc(sizeof(struct sasl_obj));
104	so->fp = si->fp;
105	so->conn = si->conn;
106
107	/*
108	**  The underlying 'fp' is set to SM_IO_NOW so that the entire
109	**  encoded string is written in one chunk. Otherwise there is
110	**  the possibility that it may appear illegal, bogus or
111	**  mangled to the other side of the connection.
112	**  We will read or write through 'fp' since it is the opaque
113	**  connection for the communications. We need to treat it this
114	**  way in case the encoded string is to be sent down a TLS
115	**  connection rather than, say, sm_io's stdio.
116	*/
117
118	(void) sm_io_setvbuf(so->fp, SM_TIME_DEFAULT, NULL, SM_IO_NOW, 0);
119	fp->f_cookie = so;
120	return 0;
121}
122
123/*
124**  SASL_CLOSE -- close the sasl specific parts of the sasl file pointer
125**
126**	Parameters:
127**		fp -- the file pointer to close
128**
129**	Returns:
130**		0 on success
131*/
132
133static int sasl_close __P((SM_FILE_T *));
134
135static int
136sasl_close(fp)
137	SM_FILE_T *fp;
138{
139	struct sasl_obj *so;
140
141	so = (struct sasl_obj *) fp->f_cookie;
142	if (so->fp != NULL)
143	{
144		sm_io_close(so->fp, SM_TIME_DEFAULT);
145		so->fp = NULL;
146	}
147	sm_free(so);
148	so = NULL;
149	return 0;
150}
151
152/* how to deallocate a buffer allocated by SASL */
153extern void	sm_sasl_free __P((void *));
154#  define SASL_DEALLOC(b)	sm_sasl_free(b)
155
156/*
157**  SASL_READ -- read encrypted information and decrypt it for the caller
158**
159**	Parameters:
160**		fp -- the file pointer
161**		buf -- the location to place the decrypted information
162**		size -- the number of bytes to read after decryption
163**
164**	Results:
165**		-1 on error
166**		otherwise the number of bytes read
167*/
168
169static ssize_t sasl_read __P((SM_FILE_T *, char *, size_t));
170
171static ssize_t
172sasl_read(fp, buf, size)
173	SM_FILE_T *fp;
174	char *buf;
175	size_t size;
176{
177	int result;
178	ssize_t len;
179# if SASL >= 20000
180	const char *outbuf = NULL;
181# else /* SASL >= 20000 */
182	static char *outbuf = NULL;
183# endif /* SASL >= 20000 */
184	static unsigned int outlen = 0;
185	static unsigned int offset = 0;
186	struct sasl_obj *so = (struct sasl_obj *) fp->f_cookie;
187
188	/*
189	**  sasl_decode() may require more data than a single read() returns.
190	**  Hence we have to put a loop around the decoding.
191	**  This also requires that we may have to split up the returned
192	**  data since it might be larger than the allowed size.
193	**  Therefore we use a static pointer and return portions of it
194	**  if necessary.
195	*/
196
197	while (outbuf == NULL && outlen == 0)
198	{
199		len = sm_io_read(so->fp, SM_TIME_DEFAULT, buf, size);
200		if (len <= 0)
201			return len;
202		result = sasl_decode(so->conn, buf,
203				     (unsigned int) len, &outbuf, &outlen);
204		if (result != SASL_OK)
205		{
206			outbuf = NULL;
207			offset = 0;
208			outlen = 0;
209			return -1;
210		}
211	}
212
213	if (outbuf == NULL)
214	{
215		/* be paranoid: outbuf == NULL but outlen != 0 */
216		syserr("@sasl_read failure: outbuf == NULL but outlen != 0");
217		/* NOTREACHED */
218	}
219	if (outlen - offset > size)
220	{
221		/* return another part of the buffer */
222		(void) memcpy(buf, outbuf + offset, size);
223		offset += size;
224		len = size;
225	}
226	else
227	{
228		/* return the rest of the buffer */
229		len = outlen - offset;
230		(void) memcpy(buf, outbuf + offset, (size_t) len);
231# if SASL < 20000
232		SASL_DEALLOC(outbuf);
233# endif /* SASL < 20000 */
234		outbuf = NULL;
235		offset = 0;
236		outlen = 0;
237	}
238	return len;
239}
240
241/*
242**  SASL_WRITE -- write information out after encrypting it
243**
244**	Parameters:
245**		fp -- the file pointer
246**		buf -- holds the data to be encrypted and written
247**		size -- the number of bytes to have encrypted and written
248**
249**	Returns:
250**		-1 on error
251**		otherwise number of bytes written
252*/
253
254static ssize_t sasl_write __P((SM_FILE_T *, const char *, size_t));
255
256static ssize_t
257sasl_write(fp, buf, size)
258	SM_FILE_T *fp;
259	const char *buf;
260	size_t size;
261{
262	int result;
263# if SASL >= 20000
264	const char *outbuf;
265# else /* SASL >= 20000 */
266	char *outbuf;
267# endif /* SASL >= 20000 */
268	unsigned int outlen;
269	size_t ret = 0, total = 0;
270	struct sasl_obj *so = (struct sasl_obj *) fp->f_cookie;
271
272	result = sasl_encode(so->conn, buf,
273			     (unsigned int) size, &outbuf, &outlen);
274
275	if (result != SASL_OK)
276		return -1;
277
278	if (outbuf != NULL)
279	{
280		while (outlen > 0)
281		{
282			/* XXX result == 0? */
283			ret = sm_io_write(so->fp, SM_TIME_DEFAULT,
284					  &outbuf[total], outlen);
285			outlen -= ret;
286			total += ret;
287		}
288# if SASL < 20000
289		SASL_DEALLOC(outbuf);
290# endif /* SASL < 20000 */
291	}
292	return size;
293}
294
295/*
296**  SFDCSASL -- create sasl file type and open in and out file pointers
297**	       for sendmail to read from and write to.
298**
299**	Parameters:
300**		fin -- the sm_io file encrypted data to be read from
301**		fout -- the sm_io file encrypted data to be writen to
302**		conn -- the sasl connection pointer
303**
304**	Returns:
305**		-1 on error
306**		0 on success
307**
308**	Side effects:
309**		The arguments "fin" and "fout" are replaced with the new
310**		SM_FILE_T pointers.
311*/
312
313int
314sfdcsasl(fin, fout, conn)
315	SM_FILE_T **fin;
316	SM_FILE_T **fout;
317	sasl_conn_t *conn;
318{
319	SM_FILE_T *newin, *newout;
320	SM_FILE_T  SM_IO_SET_TYPE(sasl_vector, "sasl", sasl_open, sasl_close,
321		sasl_read, sasl_write, NULL, sasl_getinfo, NULL,
322		SM_TIME_FOREVER);
323	struct sasl_info info;
324
325	if (conn == NULL)
326	{
327		/* no need to do anything */
328		return 0;
329	}
330
331	SM_IO_INIT_TYPE(sasl_vector, "sasl", sasl_open, sasl_close,
332		sasl_read, sasl_write, NULL, sasl_getinfo, NULL,
333		SM_TIME_FOREVER);
334	info.fp = *fin;
335	info.conn = conn;
336	newin = sm_io_open(&sasl_vector, SM_TIME_DEFAULT, &info, SM_IO_RDONLY,
337			   NULL);
338
339	if (newin == NULL)
340		return -1;
341
342	info.fp = *fout;
343	info.conn = conn;
344	newout = sm_io_open(&sasl_vector, SM_TIME_DEFAULT, &info, SM_IO_WRONLY,
345			    NULL);
346
347	if (newout == NULL)
348	{
349		(void) sm_io_close(newin, SM_TIME_DEFAULT);
350		return -1;
351	}
352	sm_io_automode(newin, newout);
353
354	*fin = newin;
355	*fout = newout;
356	return 0;
357}
358#endif /* SASL */
359
360#if STARTTLS
361# include "sfsasl.h"
362#  include <openssl/err.h>
363
364/* Structure used by the "tls" file type */
365struct tls_obj
366{
367	SM_FILE_T *fp;
368	SSL *con;
369};
370
371struct tls_info
372{
373	SM_FILE_T *fp;
374	SSL *con;
375};
376
377/*
378**  TLS_GETINFO - returns requested information about a "tls" file
379**		 descriptor.
380**
381**	Parameters:
382**		fp -- the file descriptor
383**		what -- the type of information requested
384**		valp -- the thang to return the information in (unused)
385**
386**	Returns:
387**		-1 for unknown requests
388**		>=0 on success with valp filled in (if possible).
389*/
390
391static int tls_getinfo __P((SM_FILE_T *, int, void *));
392
393/* ARGSUSED2 */
394static int
395tls_getinfo(fp, what, valp)
396	SM_FILE_T *fp;
397	int what;
398	void *valp;
399{
400	struct tls_obj *so = (struct tls_obj *) fp->f_cookie;
401
402	switch (what)
403	{
404	  case SM_IO_WHAT_FD:
405		if (so->fp == NULL)
406			return -1;
407		return so->fp->f_file; /* for stdio fileno() compatability */
408
409	  case SM_IO_IS_READABLE:
410		return SSL_pending(so->con) > 0;
411
412	  default:
413		return -1;
414	}
415}
416
417/*
418**  TLS_OPEN -- creates the tls specific information for opening a
419**	       file of the tls type.
420**
421**	Parameters:
422**		fp -- the file pointer associated with the new open
423**		info -- the sm_io file pointer holding the open and the
424**			TLS encryption connection to be read from or written to
425**		flags -- ignored
426**		rpool -- ignored
427**
428**	Returns:
429**		0 on success
430*/
431
432static int tls_open __P((SM_FILE_T *, const void *, int, const void *));
433
434/* ARGSUSED2 */
435static int
436tls_open(fp, info, flags, rpool)
437	SM_FILE_T *fp;
438	const void *info;
439	int flags;
440	const void *rpool;
441{
442	struct tls_obj *so;
443	struct tls_info *ti = (struct tls_info *) info;
444
445	so = (struct tls_obj *) sm_malloc(sizeof(struct tls_obj));
446	so->fp = ti->fp;
447	so->con = ti->con;
448
449	/*
450	**  We try to get the "raw" file descriptor that TLS uses to
451	**  do the actual read/write with. This is to allow us control
452	**  over the file descriptor being a blocking or non-blocking type.
453	**  Under the covers TLS handles the change and this allows us
454	**  to do timeouts with sm_io.
455	*/
456
457	fp->f_file = sm_io_getinfo(so->fp, SM_IO_WHAT_FD, NULL);
458	(void) sm_io_setvbuf(so->fp, SM_TIME_DEFAULT, NULL, SM_IO_NOW, 0);
459	fp->f_cookie = so;
460	return 0;
461}
462
463/*
464**  TLS_CLOSE -- close the tls specific parts of the tls file pointer
465**
466**	Parameters:
467**		fp -- the file pointer to close
468**
469**	Returns:
470**		0 on success
471*/
472
473static int tls_close __P((SM_FILE_T *));
474
475static int
476tls_close(fp)
477	SM_FILE_T *fp;
478{
479	struct tls_obj *so;
480
481	so = (struct tls_obj *) fp->f_cookie;
482	if (so->fp != NULL)
483	{
484		sm_io_close(so->fp, SM_TIME_DEFAULT);
485		so->fp = NULL;
486	}
487	sm_free(so);
488	so = NULL;
489	return 0;
490}
491
492/* maximum number of retries for TLS related I/O due to handshakes */
493# define MAX_TLS_IOS	4
494
495/*
496**  TLS_READ -- read secured information for the caller
497**
498**	Parameters:
499**		fp -- the file pointer
500**		buf -- the location to place the data
501**		size -- the number of bytes to read from connection
502**
503**	Results:
504**		-1 on error
505**		otherwise the number of bytes read
506*/
507
508static ssize_t tls_read __P((SM_FILE_T *, char *, size_t));
509
510static ssize_t
511tls_read(fp, buf, size)
512	SM_FILE_T *fp;
513	char *buf;
514	size_t size;
515{
516	int r;
517	static int again = MAX_TLS_IOS;
518	struct tls_obj *so = (struct tls_obj *) fp->f_cookie;
519	char *err;
520
521	r = SSL_read(so->con, (char *) buf, size);
522
523	if (r > 0)
524	{
525		again = MAX_TLS_IOS;
526		return r;
527	}
528
529	err = NULL;
530	switch (SSL_get_error(so->con, r))
531	{
532	  case SSL_ERROR_NONE:
533	  case SSL_ERROR_ZERO_RETURN:
534		again = MAX_TLS_IOS;
535		break;
536	  case SSL_ERROR_WANT_WRITE:
537		if (--again <= 0)
538			err = "read W BLOCK";
539		else
540			errno = EAGAIN;
541		break;
542	  case SSL_ERROR_WANT_READ:
543		if (--again <= 0)
544			err = "read R BLOCK";
545		else
546			errno = EAGAIN;
547		break;
548	  case SSL_ERROR_WANT_X509_LOOKUP:
549		err = "write X BLOCK";
550		break;
551	  case SSL_ERROR_SYSCALL:
552		if (r == 0 && errno == 0) /* out of protocol EOF found */
553			break;
554		err = "syscall error";
555/*
556		get_last_socket_error());
557*/
558		break;
559	  case SSL_ERROR_SSL:
560#if _FFR_DEAL_WITH_ERROR_SSL
561		if (r == 0 && errno == 0) /* out of protocol EOF found */
562			break;
563#endif /* _FFR_DEAL_WITH_ERROR_SSL */
564		err = "generic SSL error";
565		if (LogLevel > 9)
566			tlslogerr("read");
567
568#if _FFR_DEAL_WITH_ERROR_SSL
569		/* avoid repeated calls? */
570		if (r == 0)
571			r = -1;
572#endif /* _FFR_DEAL_WITH_ERROR_SSL */
573		break;
574	}
575	if (err != NULL)
576	{
577		int save_errno;
578
579		save_errno = (errno == 0) ? EIO : errno;
580		again = MAX_TLS_IOS;
581		if (LogLevel > 7)
582			sm_syslog(LOG_WARNING, NOQID,
583				  "STARTTLS: read error=%s (%d)", err, r);
584		errno = save_errno;
585	}
586	return r;
587}
588
589/*
590**  TLS_WRITE -- write information out through secure connection
591**
592**	Parameters:
593**		fp -- the file pointer
594**		buf -- holds the data to be securely written
595**		size -- the number of bytes to write
596**
597**	Returns:
598**		-1 on error
599**		otherwise number of bytes written
600*/
601
602static ssize_t tls_write __P((SM_FILE_T *, const char *, size_t));
603
604static ssize_t
605tls_write(fp, buf, size)
606	SM_FILE_T *fp;
607	const char *buf;
608	size_t size;
609{
610	int r;
611	static int again = MAX_TLS_IOS;
612	struct tls_obj *so = (struct tls_obj *) fp->f_cookie;
613	char *err;
614
615	r = SSL_write(so->con, (char *) buf, size);
616
617	if (r > 0)
618	{
619		again = MAX_TLS_IOS;
620		return r;
621	}
622	err = NULL;
623	switch (SSL_get_error(so->con, r))
624	{
625	  case SSL_ERROR_NONE:
626	  case SSL_ERROR_ZERO_RETURN:
627		again = MAX_TLS_IOS;
628		break;
629	  case SSL_ERROR_WANT_WRITE:
630		if (--again <= 0)
631			err = "write W BLOCK";
632		else
633			errno = EAGAIN;
634		break;
635	  case SSL_ERROR_WANT_READ:
636		if (--again <= 0)
637			err = "write R BLOCK";
638		else
639			errno = EAGAIN;
640		break;
641	  case SSL_ERROR_WANT_X509_LOOKUP:
642		err = "write X BLOCK";
643		break;
644	  case SSL_ERROR_SYSCALL:
645		if (r == 0 && errno == 0) /* out of protocol EOF found */
646			break;
647		err = "syscall error";
648/*
649		get_last_socket_error());
650*/
651		break;
652	  case SSL_ERROR_SSL:
653		err = "generic SSL error";
654/*
655		ERR_GET_REASON(ERR_peek_error()));
656*/
657		if (LogLevel > 9)
658			tlslogerr("write");
659
660#if _FFR_DEAL_WITH_ERROR_SSL
661		/* avoid repeated calls? */
662		if (r == 0)
663			r = -1;
664#endif /* _FFR_DEAL_WITH_ERROR_SSL */
665		break;
666	}
667	if (err != NULL)
668	{
669		int save_errno;
670
671		save_errno = (errno == 0) ? EIO : errno;
672		again = MAX_TLS_IOS;
673		if (LogLevel > 7)
674			sm_syslog(LOG_WARNING, NOQID,
675				  "STARTTLS: write error=%s (%d)", err, r);
676		errno = save_errno;
677	}
678	return r;
679}
680
681/*
682**  SFDCTLS -- create tls file type and open in and out file pointers
683**	      for sendmail to read from and write to.
684**
685**	Parameters:
686**		fin -- data input source being replaced
687**		fout -- data output source being replaced
688**		conn -- the tls connection pointer
689**
690**	Returns:
691**		-1 on error
692**		0 on success
693**
694**	Side effects:
695**		The arguments "fin" and "fout" are replaced with the new
696**		SM_FILE_T pointers.
697**		The original "fin" and "fout" are preserved in the tls file
698**		type but are not actually used because of the design of TLS.
699*/
700
701int
702sfdctls(fin, fout, con)
703	SM_FILE_T **fin;
704	SM_FILE_T **fout;
705	SSL *con;
706{
707	SM_FILE_T *tlsin, *tlsout;
708	SM_FILE_T SM_IO_SET_TYPE(tls_vector, "tls", tls_open, tls_close,
709		tls_read, tls_write, NULL, tls_getinfo, NULL,
710		SM_TIME_FOREVER);
711	struct tls_info info;
712
713	SM_ASSERT(con != NULL);
714
715	SM_IO_INIT_TYPE(tls_vector, "tls", tls_open, tls_close,
716		tls_read, tls_write, NULL, tls_getinfo, NULL,
717		SM_TIME_FOREVER);
718	info.fp = *fin;
719	info.con = con;
720	tlsin = sm_io_open(&tls_vector, SM_TIME_DEFAULT, &info, SM_IO_RDONLY,
721			   NULL);
722	if (tlsin == NULL)
723		return -1;
724
725	info.fp = *fout;
726	tlsout = sm_io_open(&tls_vector, SM_TIME_DEFAULT, &info, SM_IO_WRONLY,
727			    NULL);
728	if (tlsout == NULL)
729	{
730		(void) sm_io_close(tlsin, SM_TIME_DEFAULT);
731		return -1;
732	}
733	sm_io_automode(tlsin, tlsout);
734
735	*fin = tlsin;
736	*fout = tlsout;
737	return 0;
738}
739#endif /* STARTTLS */
740