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