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