Deleted Added
sdiff udiff text old ( 102528 ) new ( 110560 )
full compact
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 */