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