xref: /freebsd/contrib/sendmail/src/sfsasl.c (revision 3ff369fed2a08f32dda232c10470b949bef9489f)
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.90 2002/05/09 20:44:11 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 	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 
254 static ssize_t sasl_write __P((SM_FILE_T *, const char *, size_t));
255 
256 static ssize_t
257 sasl_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 
313 int
314 sfdcsasl(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 */
365 struct tls_obj
366 {
367 	SM_FILE_T *fp;
368 	SSL *con;
369 };
370 
371 struct 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 
391 static int tls_getinfo __P((SM_FILE_T *, int, void *));
392 
393 /* ARGSUSED2 */
394 static int
395 tls_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 
432 static int tls_open __P((SM_FILE_T *, const void *, int, const void *));
433 
434 /* ARGSUSED2 */
435 static int
436 tls_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 
473 static int tls_close __P((SM_FILE_T *));
474 
475 static int
476 tls_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 
508 static ssize_t tls_read __P((SM_FILE_T *, char *, size_t));
509 
510 static ssize_t
511 tls_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 		err = "generic SSL error";
561 		if (LogLevel > 9)
562 			tlslogerr("read");
563 		break;
564 	}
565 	if (err != NULL)
566 	{
567 		int save_errno;
568 
569 		save_errno = (errno == 0) ? EIO : errno;
570 		again = MAX_TLS_IOS;
571 		if (LogLevel > 7)
572 			sm_syslog(LOG_WARNING, NOQID,
573 				  "STARTTLS: read error=%s (%d)", err, r);
574 		errno = save_errno;
575 	}
576 	return r;
577 }
578 
579 /*
580 **  TLS_WRITE -- write information out through secure connection
581 **
582 **	Parameters:
583 **		fp -- the file pointer
584 **		buf -- holds the data to be securely written
585 **		size -- the number of bytes to write
586 **
587 **	Returns:
588 **		-1 on error
589 **		otherwise number of bytes written
590 */
591 
592 static ssize_t tls_write __P((SM_FILE_T *, const char *, size_t));
593 
594 static ssize_t
595 tls_write(fp, buf, size)
596 	SM_FILE_T *fp;
597 	const char *buf;
598 	size_t size;
599 {
600 	int r;
601 	static int again = MAX_TLS_IOS;
602 	struct tls_obj *so = (struct tls_obj *) fp->f_cookie;
603 	char *err;
604 
605 	r = SSL_write(so->con, (char *) buf, size);
606 
607 	if (r > 0)
608 	{
609 		again = MAX_TLS_IOS;
610 		return r;
611 	}
612 	err = NULL;
613 	switch (SSL_get_error(so->con, r))
614 	{
615 	  case SSL_ERROR_NONE:
616 	  case SSL_ERROR_ZERO_RETURN:
617 		again = MAX_TLS_IOS;
618 		break;
619 	  case SSL_ERROR_WANT_WRITE:
620 		if (--again <= 0)
621 			err = "write W BLOCK";
622 		else
623 			errno = EAGAIN;
624 		break;
625 	  case SSL_ERROR_WANT_READ:
626 		if (--again <= 0)
627 			err = "write R BLOCK";
628 		else
629 			errno = EAGAIN;
630 		break;
631 	  case SSL_ERROR_WANT_X509_LOOKUP:
632 		err = "write X BLOCK";
633 		break;
634 	  case SSL_ERROR_SYSCALL:
635 		if (r == 0 && errno == 0) /* out of protocol EOF found */
636 			break;
637 		err = "syscall error";
638 /*
639 		get_last_socket_error());
640 */
641 		break;
642 	  case SSL_ERROR_SSL:
643 		err = "generic SSL error";
644 /*
645 		ERR_GET_REASON(ERR_peek_error()));
646 */
647 		if (LogLevel > 9)
648 			tlslogerr("write");
649 		break;
650 	}
651 	if (err != NULL)
652 	{
653 		int save_errno;
654 
655 		save_errno = (errno == 0) ? EIO : errno;
656 		again = MAX_TLS_IOS;
657 		if (LogLevel > 7)
658 			sm_syslog(LOG_WARNING, NOQID,
659 				  "STARTTLS: write error=%s (%d)", err, r);
660 		errno = save_errno;
661 	}
662 	return r;
663 }
664 
665 /*
666 **  SFDCTLS -- create tls file type and open in and out file pointers
667 **	      for sendmail to read from and write to.
668 **
669 **	Parameters:
670 **		fin -- data input source being replaced
671 **		fout -- data output source being replaced
672 **		conn -- the tls connection pointer
673 **
674 **	Returns:
675 **		-1 on error
676 **		0 on success
677 **
678 **	Side effects:
679 **		The arguments "fin" and "fout" are replaced with the new
680 **		SM_FILE_T pointers.
681 **		The original "fin" and "fout" are preserved in the tls file
682 **		type but are not actually used because of the design of TLS.
683 */
684 
685 int
686 sfdctls(fin, fout, con)
687 	SM_FILE_T **fin;
688 	SM_FILE_T **fout;
689 	SSL *con;
690 {
691 	SM_FILE_T *tlsin, *tlsout;
692 	SM_FILE_T SM_IO_SET_TYPE(tls_vector, "tls", tls_open, tls_close,
693 		tls_read, tls_write, NULL, tls_getinfo, NULL,
694 		SM_TIME_FOREVER);
695 	struct tls_info info;
696 
697 	SM_ASSERT(con != NULL);
698 
699 	SM_IO_INIT_TYPE(tls_vector, "tls", tls_open, tls_close,
700 		tls_read, tls_write, NULL, tls_getinfo, NULL,
701 		SM_TIME_FOREVER);
702 	info.fp = *fin;
703 	info.con = con;
704 	tlsin = sm_io_open(&tls_vector, SM_TIME_DEFAULT, &info, SM_IO_RDONLY,
705 			   NULL);
706 	if (tlsin == NULL)
707 		return -1;
708 
709 	info.fp = *fout;
710 	tlsout = sm_io_open(&tls_vector, SM_TIME_DEFAULT, &info, SM_IO_WRONLY,
711 			    NULL);
712 	if (tlsout == NULL)
713 	{
714 		(void) sm_io_close(tlsin, SM_TIME_DEFAULT);
715 		return -1;
716 	}
717 	sm_io_automode(tlsin, tlsout);
718 
719 	*fin = tlsin;
720 	*fout = tlsout;
721 	return 0;
722 }
723 #endif /* STARTTLS */
724