xref: /freebsd/contrib/sendmail/src/sfsasl.c (revision 2ef40764f06885f97d380ee8de0ced64930423db)
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>
12 SM_RCSID("@(#)$Id: sfsasl.c,v 8.91.2.2 2002/09/12 21:07:50 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 	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 
133 static int sasl_close __P((SM_FILE_T *));
134 
135 static int
136 sasl_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 */
153 extern 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 
169 static ssize_t sasl_read __P((SM_FILE_T *, char *, size_t));
170 
171 static ssize_t
172 sasl_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 	static 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 # if SASL >= 20000
198 	while (outlen == 0)
199 # else /* SASL >= 20000 */
200 	while (outbuf == NULL && outlen == 0)
201 # endif /* SASL >= 20000 */
202 	{
203 		len = sm_io_read(so->fp, SM_TIME_DEFAULT, buf, size);
204 		if (len <= 0)
205 			return len;
206 		result = sasl_decode(so->conn, buf,
207 				     (unsigned int) len, &outbuf, &outlen);
208 		if (result != SASL_OK)
209 		{
210 			outbuf = NULL;
211 			offset = 0;
212 			outlen = 0;
213 			return -1;
214 		}
215 	}
216 
217 	if (outbuf == NULL)
218 	{
219 		/* be paranoid: outbuf == NULL but outlen != 0 */
220 		syserr("@sasl_read failure: outbuf == NULL but outlen != 0");
221 		/* NOTREACHED */
222 	}
223 	if (outlen - offset > size)
224 	{
225 		/* return another part of the buffer */
226 		(void) memcpy(buf, outbuf + offset, size);
227 		offset += size;
228 		len = size;
229 	}
230 	else
231 	{
232 		/* return the rest of the buffer */
233 		len = outlen - offset;
234 		(void) memcpy(buf, outbuf + offset, (size_t) len);
235 # if SASL < 20000
236 		SASL_DEALLOC(outbuf);
237 # endif /* SASL < 20000 */
238 		outbuf = NULL;
239 		offset = 0;
240 		outlen = 0;
241 	}
242 	return len;
243 }
244 
245 /*
246 **  SASL_WRITE -- write information out after encrypting it
247 **
248 **	Parameters:
249 **		fp -- the file pointer
250 **		buf -- holds the data to be encrypted and written
251 **		size -- the number of bytes to have encrypted and written
252 **
253 **	Returns:
254 **		-1 on error
255 **		otherwise number of bytes written
256 */
257 
258 static ssize_t sasl_write __P((SM_FILE_T *, const char *, size_t));
259 
260 static ssize_t
261 sasl_write(fp, buf, size)
262 	SM_FILE_T *fp;
263 	const char *buf;
264 	size_t size;
265 {
266 	int result;
267 # if SASL >= 20000
268 	const char *outbuf;
269 # else /* SASL >= 20000 */
270 	char *outbuf;
271 # endif /* SASL >= 20000 */
272 	unsigned int outlen;
273 	size_t ret = 0, total = 0;
274 	struct sasl_obj *so = (struct sasl_obj *) fp->f_cookie;
275 
276 	result = sasl_encode(so->conn, buf,
277 			     (unsigned int) size, &outbuf, &outlen);
278 
279 	if (result != SASL_OK)
280 		return -1;
281 
282 	if (outbuf != NULL)
283 	{
284 		while (outlen > 0)
285 		{
286 			/* XXX result == 0? */
287 			ret = sm_io_write(so->fp, SM_TIME_DEFAULT,
288 					  &outbuf[total], outlen);
289 			outlen -= ret;
290 			total += ret;
291 		}
292 # if SASL < 20000
293 		SASL_DEALLOC(outbuf);
294 # endif /* SASL < 20000 */
295 	}
296 	return size;
297 }
298 
299 /*
300 **  SFDCSASL -- create sasl file type and open in and out file pointers
301 **	       for sendmail to read from and write to.
302 **
303 **	Parameters:
304 **		fin -- the sm_io file encrypted data to be read from
305 **		fout -- the sm_io file encrypted data to be writen to
306 **		conn -- the sasl connection pointer
307 **
308 **	Returns:
309 **		-1 on error
310 **		0 on success
311 **
312 **	Side effects:
313 **		The arguments "fin" and "fout" are replaced with the new
314 **		SM_FILE_T pointers.
315 */
316 
317 int
318 sfdcsasl(fin, fout, conn)
319 	SM_FILE_T **fin;
320 	SM_FILE_T **fout;
321 	sasl_conn_t *conn;
322 {
323 	SM_FILE_T *newin, *newout;
324 	SM_FILE_T  SM_IO_SET_TYPE(sasl_vector, "sasl", sasl_open, sasl_close,
325 		sasl_read, sasl_write, NULL, sasl_getinfo, NULL,
326 		SM_TIME_FOREVER);
327 	struct sasl_info info;
328 
329 	if (conn == NULL)
330 	{
331 		/* no need to do anything */
332 		return 0;
333 	}
334 
335 	SM_IO_INIT_TYPE(sasl_vector, "sasl", sasl_open, sasl_close,
336 		sasl_read, sasl_write, NULL, sasl_getinfo, NULL,
337 		SM_TIME_FOREVER);
338 	info.fp = *fin;
339 	info.conn = conn;
340 	newin = sm_io_open(&sasl_vector, SM_TIME_DEFAULT, &info, SM_IO_RDONLY,
341 			   NULL);
342 
343 	if (newin == NULL)
344 		return -1;
345 
346 	info.fp = *fout;
347 	info.conn = conn;
348 	newout = sm_io_open(&sasl_vector, SM_TIME_DEFAULT, &info, SM_IO_WRONLY,
349 			    NULL);
350 
351 	if (newout == NULL)
352 	{
353 		(void) sm_io_close(newin, SM_TIME_DEFAULT);
354 		return -1;
355 	}
356 	sm_io_automode(newin, newout);
357 
358 	*fin = newin;
359 	*fout = newout;
360 	return 0;
361 }
362 #endif /* SASL */
363 
364 #if STARTTLS
365 # include "sfsasl.h"
366 #  include <openssl/err.h>
367 
368 /* Structure used by the "tls" file type */
369 struct tls_obj
370 {
371 	SM_FILE_T *fp;
372 	SSL *con;
373 };
374 
375 struct tls_info
376 {
377 	SM_FILE_T *fp;
378 	SSL *con;
379 };
380 
381 /*
382 **  TLS_GETINFO - returns requested information about a "tls" file
383 **		 descriptor.
384 **
385 **	Parameters:
386 **		fp -- the file descriptor
387 **		what -- the type of information requested
388 **		valp -- the thang to return the information in (unused)
389 **
390 **	Returns:
391 **		-1 for unknown requests
392 **		>=0 on success with valp filled in (if possible).
393 */
394 
395 static int tls_getinfo __P((SM_FILE_T *, int, void *));
396 
397 /* ARGSUSED2 */
398 static int
399 tls_getinfo(fp, what, valp)
400 	SM_FILE_T *fp;
401 	int what;
402 	void *valp;
403 {
404 	struct tls_obj *so = (struct tls_obj *) fp->f_cookie;
405 
406 	switch (what)
407 	{
408 	  case SM_IO_WHAT_FD:
409 		if (so->fp == NULL)
410 			return -1;
411 		return so->fp->f_file; /* for stdio fileno() compatability */
412 
413 	  case SM_IO_IS_READABLE:
414 		return SSL_pending(so->con) > 0;
415 
416 	  default:
417 		return -1;
418 	}
419 }
420 
421 /*
422 **  TLS_OPEN -- creates the tls specific information for opening a
423 **	       file of the tls type.
424 **
425 **	Parameters:
426 **		fp -- the file pointer associated with the new open
427 **		info -- the sm_io file pointer holding the open and the
428 **			TLS encryption connection to be read from or written to
429 **		flags -- ignored
430 **		rpool -- ignored
431 **
432 **	Returns:
433 **		0 on success
434 */
435 
436 static int tls_open __P((SM_FILE_T *, const void *, int, const void *));
437 
438 /* ARGSUSED2 */
439 static int
440 tls_open(fp, info, flags, rpool)
441 	SM_FILE_T *fp;
442 	const void *info;
443 	int flags;
444 	const void *rpool;
445 {
446 	struct tls_obj *so;
447 	struct tls_info *ti = (struct tls_info *) info;
448 
449 	so = (struct tls_obj *) sm_malloc(sizeof(struct tls_obj));
450 	so->fp = ti->fp;
451 	so->con = ti->con;
452 
453 	/*
454 	**  We try to get the "raw" file descriptor that TLS uses to
455 	**  do the actual read/write with. This is to allow us control
456 	**  over the file descriptor being a blocking or non-blocking type.
457 	**  Under the covers TLS handles the change and this allows us
458 	**  to do timeouts with sm_io.
459 	*/
460 
461 	fp->f_file = sm_io_getinfo(so->fp, SM_IO_WHAT_FD, NULL);
462 	(void) sm_io_setvbuf(so->fp, SM_TIME_DEFAULT, NULL, SM_IO_NOW, 0);
463 	fp->f_cookie = so;
464 	return 0;
465 }
466 
467 /*
468 **  TLS_CLOSE -- close the tls specific parts of the tls file pointer
469 **
470 **	Parameters:
471 **		fp -- the file pointer to close
472 **
473 **	Returns:
474 **		0 on success
475 */
476 
477 static int tls_close __P((SM_FILE_T *));
478 
479 static int
480 tls_close(fp)
481 	SM_FILE_T *fp;
482 {
483 	struct tls_obj *so;
484 
485 	so = (struct tls_obj *) fp->f_cookie;
486 	if (so->fp != NULL)
487 	{
488 		sm_io_close(so->fp, SM_TIME_DEFAULT);
489 		so->fp = NULL;
490 	}
491 	sm_free(so);
492 	so = NULL;
493 	return 0;
494 }
495 
496 /* maximum number of retries for TLS related I/O due to handshakes */
497 # define MAX_TLS_IOS	4
498 
499 /*
500 **  TLS_READ -- read secured information for the caller
501 **
502 **	Parameters:
503 **		fp -- the file pointer
504 **		buf -- the location to place the data
505 **		size -- the number of bytes to read from connection
506 **
507 **	Results:
508 **		-1 on error
509 **		otherwise the number of bytes read
510 */
511 
512 static ssize_t tls_read __P((SM_FILE_T *, char *, size_t));
513 
514 static ssize_t
515 tls_read(fp, buf, size)
516 	SM_FILE_T *fp;
517 	char *buf;
518 	size_t size;
519 {
520 	int r;
521 	static int again = MAX_TLS_IOS;
522 	struct tls_obj *so = (struct tls_obj *) fp->f_cookie;
523 	char *err;
524 
525 	r = SSL_read(so->con, (char *) buf, size);
526 
527 	if (r > 0)
528 	{
529 		again = MAX_TLS_IOS;
530 		return r;
531 	}
532 
533 	err = NULL;
534 	switch (SSL_get_error(so->con, r))
535 	{
536 	  case SSL_ERROR_NONE:
537 	  case SSL_ERROR_ZERO_RETURN:
538 		again = MAX_TLS_IOS;
539 		break;
540 	  case SSL_ERROR_WANT_WRITE:
541 		if (--again <= 0)
542 			err = "read W BLOCK";
543 		else
544 			errno = EAGAIN;
545 		break;
546 	  case SSL_ERROR_WANT_READ:
547 		if (--again <= 0)
548 			err = "read R BLOCK";
549 		else
550 			errno = EAGAIN;
551 		break;
552 	  case SSL_ERROR_WANT_X509_LOOKUP:
553 		err = "write X BLOCK";
554 		break;
555 	  case SSL_ERROR_SYSCALL:
556 		if (r == 0 && errno == 0) /* out of protocol EOF found */
557 			break;
558 		err = "syscall error";
559 /*
560 		get_last_socket_error());
561 */
562 		break;
563 	  case SSL_ERROR_SSL:
564 #if _FFR_DEAL_WITH_ERROR_SSL
565 		if (r == 0 && errno == 0) /* out of protocol EOF found */
566 			break;
567 #endif /* _FFR_DEAL_WITH_ERROR_SSL */
568 		err = "generic SSL error";
569 		if (LogLevel > 9)
570 			tlslogerr("read");
571 
572 #if _FFR_DEAL_WITH_ERROR_SSL
573 		/* avoid repeated calls? */
574 		if (r == 0)
575 			r = -1;
576 #endif /* _FFR_DEAL_WITH_ERROR_SSL */
577 		break;
578 	}
579 	if (err != NULL)
580 	{
581 		int save_errno;
582 
583 		save_errno = (errno == 0) ? EIO : errno;
584 		again = MAX_TLS_IOS;
585 		if (LogLevel > 7)
586 			sm_syslog(LOG_WARNING, NOQID,
587 				  "STARTTLS: read error=%s (%d)", err, r);
588 		errno = save_errno;
589 	}
590 	return r;
591 }
592 
593 /*
594 **  TLS_WRITE -- write information out through secure connection
595 **
596 **	Parameters:
597 **		fp -- the file pointer
598 **		buf -- holds the data to be securely written
599 **		size -- the number of bytes to write
600 **
601 **	Returns:
602 **		-1 on error
603 **		otherwise number of bytes written
604 */
605 
606 static ssize_t tls_write __P((SM_FILE_T *, const char *, size_t));
607 
608 static ssize_t
609 tls_write(fp, buf, size)
610 	SM_FILE_T *fp;
611 	const char *buf;
612 	size_t size;
613 {
614 	int r;
615 	static int again = MAX_TLS_IOS;
616 	struct tls_obj *so = (struct tls_obj *) fp->f_cookie;
617 	char *err;
618 
619 	r = SSL_write(so->con, (char *) buf, size);
620 
621 	if (r > 0)
622 	{
623 		again = MAX_TLS_IOS;
624 		return r;
625 	}
626 	err = NULL;
627 	switch (SSL_get_error(so->con, r))
628 	{
629 	  case SSL_ERROR_NONE:
630 	  case SSL_ERROR_ZERO_RETURN:
631 		again = MAX_TLS_IOS;
632 		break;
633 	  case SSL_ERROR_WANT_WRITE:
634 		if (--again <= 0)
635 			err = "write W BLOCK";
636 		else
637 			errno = EAGAIN;
638 		break;
639 	  case SSL_ERROR_WANT_READ:
640 		if (--again <= 0)
641 			err = "write R BLOCK";
642 		else
643 			errno = EAGAIN;
644 		break;
645 	  case SSL_ERROR_WANT_X509_LOOKUP:
646 		err = "write X BLOCK";
647 		break;
648 	  case SSL_ERROR_SYSCALL:
649 		if (r == 0 && errno == 0) /* out of protocol EOF found */
650 			break;
651 		err = "syscall error";
652 /*
653 		get_last_socket_error());
654 */
655 		break;
656 	  case SSL_ERROR_SSL:
657 		err = "generic SSL error";
658 /*
659 		ERR_GET_REASON(ERR_peek_error()));
660 */
661 		if (LogLevel > 9)
662 			tlslogerr("write");
663 
664 #if _FFR_DEAL_WITH_ERROR_SSL
665 		/* avoid repeated calls? */
666 		if (r == 0)
667 			r = -1;
668 #endif /* _FFR_DEAL_WITH_ERROR_SSL */
669 		break;
670 	}
671 	if (err != NULL)
672 	{
673 		int save_errno;
674 
675 		save_errno = (errno == 0) ? EIO : errno;
676 		again = MAX_TLS_IOS;
677 		if (LogLevel > 7)
678 			sm_syslog(LOG_WARNING, NOQID,
679 				  "STARTTLS: write error=%s (%d)", err, r);
680 		errno = save_errno;
681 	}
682 	return r;
683 }
684 
685 /*
686 **  SFDCTLS -- create tls file type and open in and out file pointers
687 **	      for sendmail to read from and write to.
688 **
689 **	Parameters:
690 **		fin -- data input source being replaced
691 **		fout -- data output source being replaced
692 **		conn -- the tls connection pointer
693 **
694 **	Returns:
695 **		-1 on error
696 **		0 on success
697 **
698 **	Side effects:
699 **		The arguments "fin" and "fout" are replaced with the new
700 **		SM_FILE_T pointers.
701 **		The original "fin" and "fout" are preserved in the tls file
702 **		type but are not actually used because of the design of TLS.
703 */
704 
705 int
706 sfdctls(fin, fout, con)
707 	SM_FILE_T **fin;
708 	SM_FILE_T **fout;
709 	SSL *con;
710 {
711 	SM_FILE_T *tlsin, *tlsout;
712 	SM_FILE_T SM_IO_SET_TYPE(tls_vector, "tls", tls_open, tls_close,
713 		tls_read, tls_write, NULL, tls_getinfo, NULL,
714 		SM_TIME_FOREVER);
715 	struct tls_info info;
716 
717 	SM_ASSERT(con != NULL);
718 
719 	SM_IO_INIT_TYPE(tls_vector, "tls", tls_open, tls_close,
720 		tls_read, tls_write, NULL, tls_getinfo, NULL,
721 		SM_TIME_FOREVER);
722 	info.fp = *fin;
723 	info.con = con;
724 	tlsin = sm_io_open(&tls_vector, SM_TIME_DEFAULT, &info, SM_IO_RDONLY,
725 			   NULL);
726 	if (tlsin == NULL)
727 		return -1;
728 
729 	info.fp = *fout;
730 	tlsout = sm_io_open(&tls_vector, SM_TIME_DEFAULT, &info, SM_IO_WRONLY,
731 			    NULL);
732 	if (tlsout == NULL)
733 	{
734 		(void) sm_io_close(tlsin, SM_TIME_DEFAULT);
735 		return -1;
736 	}
737 	sm_io_automode(tlsin, tlsout);
738 
739 	*fin = tlsin;
740 	*fout = tlsout;
741 	return 0;
742 }
743 #endif /* STARTTLS */
744