106f25ae9SGregory Neil Shapiro /* 2605302a5SGregory Neil Shapiro * Copyright (c) 1999-2002 Sendmail, Inc. and its suppliers. 306f25ae9SGregory Neil Shapiro * All rights reserved. 406f25ae9SGregory Neil Shapiro * 506f25ae9SGregory Neil Shapiro * By using this file, you agree to the terms and conditions set 606f25ae9SGregory Neil Shapiro * forth in the LICENSE file which can be found at the top level of 706f25ae9SGregory Neil Shapiro * the sendmail distribution. 806f25ae9SGregory Neil Shapiro * 906f25ae9SGregory Neil Shapiro */ 1006f25ae9SGregory Neil Shapiro 1140266059SGregory Neil Shapiro #include <sm/gen.h> 1213bd1963SGregory Neil Shapiro SM_RCSID("@(#)$Id: sfsasl.c,v 8.91.2.2 2002/09/12 21:07:50 ca Exp $") 1306f25ae9SGregory Neil Shapiro #include <stdlib.h> 1406f25ae9SGregory Neil Shapiro #include <sendmail.h> 1540266059SGregory Neil Shapiro #include <errno.h> 1640266059SGregory Neil Shapiro #if SASL 1706f25ae9SGregory Neil Shapiro # include "sfsasl.h" 1806f25ae9SGregory Neil Shapiro 1940266059SGregory Neil Shapiro /* Structure used by the "sasl" file type */ 2040266059SGregory Neil Shapiro struct sasl_obj 2140266059SGregory Neil Shapiro { 2240266059SGregory Neil Shapiro SM_FILE_T *fp; 2340266059SGregory Neil Shapiro sasl_conn_t *conn; 2440266059SGregory Neil Shapiro }; 2540266059SGregory Neil Shapiro 2640266059SGregory Neil Shapiro struct sasl_info 2740266059SGregory Neil Shapiro { 2840266059SGregory Neil Shapiro SM_FILE_T *fp; 2940266059SGregory Neil Shapiro sasl_conn_t *conn; 3040266059SGregory Neil Shapiro }; 3140266059SGregory Neil Shapiro 3240266059SGregory Neil Shapiro /* 3340266059SGregory Neil Shapiro ** SASL_GETINFO - returns requested information about a "sasl" file 3440266059SGregory Neil Shapiro ** descriptor. 3540266059SGregory Neil Shapiro ** 3640266059SGregory Neil Shapiro ** Parameters: 3740266059SGregory Neil Shapiro ** fp -- the file descriptor 3840266059SGregory Neil Shapiro ** what -- the type of information requested 3940266059SGregory Neil Shapiro ** valp -- the thang to return the information in 4040266059SGregory Neil Shapiro ** 4140266059SGregory Neil Shapiro ** Returns: 4240266059SGregory Neil Shapiro ** -1 for unknown requests 4340266059SGregory Neil Shapiro ** >=0 on success with valp filled in (if possible). 4440266059SGregory Neil Shapiro */ 4540266059SGregory Neil Shapiro 4640266059SGregory Neil Shapiro static int sasl_getinfo __P((SM_FILE_T *, int, void *)); 4740266059SGregory Neil Shapiro 4840266059SGregory Neil Shapiro static int 4940266059SGregory Neil Shapiro sasl_getinfo(fp, what, valp) 5040266059SGregory Neil Shapiro SM_FILE_T *fp; 5140266059SGregory Neil Shapiro int what; 5240266059SGregory Neil Shapiro void *valp; 5340266059SGregory Neil Shapiro { 5440266059SGregory Neil Shapiro struct sasl_obj *so = (struct sasl_obj *) fp->f_cookie; 5540266059SGregory Neil Shapiro 5640266059SGregory Neil Shapiro switch (what) 5740266059SGregory Neil Shapiro { 5840266059SGregory Neil Shapiro case SM_IO_WHAT_FD: 5940266059SGregory Neil Shapiro if (so->fp == NULL) 6040266059SGregory Neil Shapiro return -1; 6140266059SGregory Neil Shapiro return so->fp->f_file; /* for stdio fileno() compatability */ 6240266059SGregory Neil Shapiro 6340266059SGregory Neil Shapiro case SM_IO_IS_READABLE: 6440266059SGregory Neil Shapiro if (so->fp == NULL) 6540266059SGregory Neil Shapiro return 0; 6640266059SGregory Neil Shapiro 6740266059SGregory Neil Shapiro /* get info from underlying file */ 6840266059SGregory Neil Shapiro return sm_io_getinfo(so->fp, what, valp); 6940266059SGregory Neil Shapiro 7040266059SGregory Neil Shapiro default: 7140266059SGregory Neil Shapiro return -1; 7240266059SGregory Neil Shapiro } 7340266059SGregory Neil Shapiro } 7440266059SGregory Neil Shapiro 7540266059SGregory Neil Shapiro /* 7640266059SGregory Neil Shapiro ** SASL_OPEN -- creates the sasl specific information for opening a 7740266059SGregory Neil Shapiro ** file of the sasl type. 7840266059SGregory Neil Shapiro ** 7940266059SGregory Neil Shapiro ** Parameters: 8040266059SGregory Neil Shapiro ** fp -- the file pointer associated with the new open 8140266059SGregory Neil Shapiro ** info -- contains the sasl connection information pointer and 8240266059SGregory Neil Shapiro ** the original SM_FILE_T that holds the open 8340266059SGregory Neil Shapiro ** flags -- ignored 8440266059SGregory Neil Shapiro ** rpool -- ignored 8540266059SGregory Neil Shapiro ** 8640266059SGregory Neil Shapiro ** Returns: 8740266059SGregory Neil Shapiro ** 0 on success 8840266059SGregory Neil Shapiro */ 8940266059SGregory Neil Shapiro 9040266059SGregory Neil Shapiro static int sasl_open __P((SM_FILE_T *, const void *, int, const void *)); 9140266059SGregory Neil Shapiro 9240266059SGregory Neil Shapiro /* ARGSUSED2 */ 9340266059SGregory Neil Shapiro static int 9440266059SGregory Neil Shapiro sasl_open(fp, info, flags, rpool) 9540266059SGregory Neil Shapiro SM_FILE_T *fp; 9640266059SGregory Neil Shapiro const void *info; 9740266059SGregory Neil Shapiro int flags; 9840266059SGregory Neil Shapiro const void *rpool; 9940266059SGregory Neil Shapiro { 10040266059SGregory Neil Shapiro struct sasl_obj *so; 10140266059SGregory Neil Shapiro struct sasl_info *si = (struct sasl_info *) info; 10240266059SGregory Neil Shapiro 10340266059SGregory Neil Shapiro so = (struct sasl_obj *) sm_malloc(sizeof(struct sasl_obj)); 10440266059SGregory Neil Shapiro so->fp = si->fp; 10540266059SGregory Neil Shapiro so->conn = si->conn; 10640266059SGregory Neil Shapiro 10740266059SGregory Neil Shapiro /* 10840266059SGregory Neil Shapiro ** The underlying 'fp' is set to SM_IO_NOW so that the entire 10940266059SGregory Neil Shapiro ** encoded string is written in one chunk. Otherwise there is 11040266059SGregory Neil Shapiro ** the possibility that it may appear illegal, bogus or 11140266059SGregory Neil Shapiro ** mangled to the other side of the connection. 11240266059SGregory Neil Shapiro ** We will read or write through 'fp' since it is the opaque 11340266059SGregory Neil Shapiro ** connection for the communications. We need to treat it this 11440266059SGregory Neil Shapiro ** way in case the encoded string is to be sent down a TLS 11540266059SGregory Neil Shapiro ** connection rather than, say, sm_io's stdio. 11640266059SGregory Neil Shapiro */ 11740266059SGregory Neil Shapiro 11840266059SGregory Neil Shapiro (void) sm_io_setvbuf(so->fp, SM_TIME_DEFAULT, NULL, SM_IO_NOW, 0); 11940266059SGregory Neil Shapiro fp->f_cookie = so; 12040266059SGregory Neil Shapiro return 0; 12140266059SGregory Neil Shapiro } 12240266059SGregory Neil Shapiro 12340266059SGregory Neil Shapiro /* 12440266059SGregory Neil Shapiro ** SASL_CLOSE -- close the sasl specific parts of the sasl file pointer 12540266059SGregory Neil Shapiro ** 12640266059SGregory Neil Shapiro ** Parameters: 12740266059SGregory Neil Shapiro ** fp -- the file pointer to close 12840266059SGregory Neil Shapiro ** 12940266059SGregory Neil Shapiro ** Returns: 13040266059SGregory Neil Shapiro ** 0 on success 13140266059SGregory Neil Shapiro */ 13240266059SGregory Neil Shapiro 13340266059SGregory Neil Shapiro static int sasl_close __P((SM_FILE_T *)); 13440266059SGregory Neil Shapiro 13540266059SGregory Neil Shapiro static int 13640266059SGregory Neil Shapiro sasl_close(fp) 13740266059SGregory Neil Shapiro SM_FILE_T *fp; 13840266059SGregory Neil Shapiro { 13940266059SGregory Neil Shapiro struct sasl_obj *so; 14040266059SGregory Neil Shapiro 14140266059SGregory Neil Shapiro so = (struct sasl_obj *) fp->f_cookie; 14240266059SGregory Neil Shapiro if (so->fp != NULL) 14340266059SGregory Neil Shapiro { 14440266059SGregory Neil Shapiro sm_io_close(so->fp, SM_TIME_DEFAULT); 14540266059SGregory Neil Shapiro so->fp = NULL; 14640266059SGregory Neil Shapiro } 14740266059SGregory Neil Shapiro sm_free(so); 14840266059SGregory Neil Shapiro so = NULL; 14940266059SGregory Neil Shapiro return 0; 15040266059SGregory Neil Shapiro } 15140266059SGregory Neil Shapiro 152193538b7SGregory Neil Shapiro /* how to deallocate a buffer allocated by SASL */ 15340266059SGregory Neil Shapiro extern void sm_sasl_free __P((void *)); 15440266059SGregory Neil Shapiro # define SASL_DEALLOC(b) sm_sasl_free(b) 15540266059SGregory Neil Shapiro 15640266059SGregory Neil Shapiro /* 15740266059SGregory Neil Shapiro ** SASL_READ -- read encrypted information and decrypt it for the caller 15840266059SGregory Neil Shapiro ** 15940266059SGregory Neil Shapiro ** Parameters: 16040266059SGregory Neil Shapiro ** fp -- the file pointer 16140266059SGregory Neil Shapiro ** buf -- the location to place the decrypted information 16240266059SGregory Neil Shapiro ** size -- the number of bytes to read after decryption 16340266059SGregory Neil Shapiro ** 16440266059SGregory Neil Shapiro ** Results: 16540266059SGregory Neil Shapiro ** -1 on error 16640266059SGregory Neil Shapiro ** otherwise the number of bytes read 16740266059SGregory Neil Shapiro */ 16840266059SGregory Neil Shapiro 16940266059SGregory Neil Shapiro static ssize_t sasl_read __P((SM_FILE_T *, char *, size_t)); 170193538b7SGregory Neil Shapiro 17106f25ae9SGregory Neil Shapiro static ssize_t 17240266059SGregory Neil Shapiro sasl_read(fp, buf, size) 17340266059SGregory Neil Shapiro SM_FILE_T *fp; 17440266059SGregory Neil Shapiro char *buf; 17506f25ae9SGregory Neil Shapiro size_t size; 17606f25ae9SGregory Neil Shapiro { 17740266059SGregory Neil Shapiro int result; 17840266059SGregory Neil Shapiro ssize_t len; 17994c01205SGregory Neil Shapiro # if SASL >= 20000 18013bd1963SGregory Neil Shapiro static const char *outbuf = NULL; 18194c01205SGregory Neil Shapiro # else /* SASL >= 20000 */ 182193538b7SGregory Neil Shapiro static char *outbuf = NULL; 18394c01205SGregory Neil Shapiro # endif /* SASL >= 20000 */ 184193538b7SGregory Neil Shapiro static unsigned int outlen = 0; 185193538b7SGregory Neil Shapiro static unsigned int offset = 0; 18640266059SGregory Neil Shapiro struct sasl_obj *so = (struct sasl_obj *) fp->f_cookie; 18706f25ae9SGregory Neil Shapiro 188193538b7SGregory Neil Shapiro /* 189193538b7SGregory Neil Shapiro ** sasl_decode() may require more data than a single read() returns. 190193538b7SGregory Neil Shapiro ** Hence we have to put a loop around the decoding. 191193538b7SGregory Neil Shapiro ** This also requires that we may have to split up the returned 192193538b7SGregory Neil Shapiro ** data since it might be larger than the allowed size. 193193538b7SGregory Neil Shapiro ** Therefore we use a static pointer and return portions of it 194193538b7SGregory Neil Shapiro ** if necessary. 195193538b7SGregory Neil Shapiro */ 19606f25ae9SGregory Neil Shapiro 19713bd1963SGregory Neil Shapiro # if SASL >= 20000 19813bd1963SGregory Neil Shapiro while (outlen == 0) 19913bd1963SGregory Neil Shapiro # else /* SASL >= 20000 */ 200193538b7SGregory Neil Shapiro while (outbuf == NULL && outlen == 0) 20113bd1963SGregory Neil Shapiro # endif /* SASL >= 20000 */ 202193538b7SGregory Neil Shapiro { 20340266059SGregory Neil Shapiro len = sm_io_read(so->fp, SM_TIME_DEFAULT, buf, size); 20406f25ae9SGregory Neil Shapiro if (len <= 0) 20506f25ae9SGregory Neil Shapiro return len; 20640266059SGregory Neil Shapiro result = sasl_decode(so->conn, buf, 20740266059SGregory Neil Shapiro (unsigned int) len, &outbuf, &outlen); 20806f25ae9SGregory Neil Shapiro if (result != SASL_OK) 20906f25ae9SGregory Neil Shapiro { 210193538b7SGregory Neil Shapiro outbuf = NULL; 211193538b7SGregory Neil Shapiro offset = 0; 212193538b7SGregory Neil Shapiro outlen = 0; 21306f25ae9SGregory Neil Shapiro return -1; 21406f25ae9SGregory Neil Shapiro } 215193538b7SGregory Neil Shapiro } 21606f25ae9SGregory Neil Shapiro 21740266059SGregory Neil Shapiro if (outbuf == NULL) 21806f25ae9SGregory Neil Shapiro { 21940266059SGregory Neil Shapiro /* be paranoid: outbuf == NULL but outlen != 0 */ 22040266059SGregory Neil Shapiro syserr("@sasl_read failure: outbuf == NULL but outlen != 0"); 22140266059SGregory Neil Shapiro /* NOTREACHED */ 22240266059SGregory Neil Shapiro } 223193538b7SGregory Neil Shapiro if (outlen - offset > size) 224193538b7SGregory Neil Shapiro { 225193538b7SGregory Neil Shapiro /* return another part of the buffer */ 22640266059SGregory Neil Shapiro (void) memcpy(buf, outbuf + offset, size); 227193538b7SGregory Neil Shapiro offset += size; 22840266059SGregory Neil Shapiro len = size; 22906f25ae9SGregory Neil Shapiro } 230193538b7SGregory Neil Shapiro else 231193538b7SGregory Neil Shapiro { 232193538b7SGregory Neil Shapiro /* return the rest of the buffer */ 23340266059SGregory Neil Shapiro len = outlen - offset; 23440266059SGregory Neil Shapiro (void) memcpy(buf, outbuf + offset, (size_t) len); 23594c01205SGregory Neil Shapiro # if SASL < 20000 236193538b7SGregory Neil Shapiro SASL_DEALLOC(outbuf); 23794c01205SGregory Neil Shapiro # endif /* SASL < 20000 */ 238193538b7SGregory Neil Shapiro outbuf = NULL; 239193538b7SGregory Neil Shapiro offset = 0; 240193538b7SGregory Neil Shapiro outlen = 0; 241193538b7SGregory Neil Shapiro } 24240266059SGregory Neil Shapiro return len; 24306f25ae9SGregory Neil Shapiro } 24406f25ae9SGregory Neil Shapiro 24540266059SGregory Neil Shapiro /* 24640266059SGregory Neil Shapiro ** SASL_WRITE -- write information out after encrypting it 24740266059SGregory Neil Shapiro ** 24840266059SGregory Neil Shapiro ** Parameters: 24940266059SGregory Neil Shapiro ** fp -- the file pointer 25040266059SGregory Neil Shapiro ** buf -- holds the data to be encrypted and written 25140266059SGregory Neil Shapiro ** size -- the number of bytes to have encrypted and written 25240266059SGregory Neil Shapiro ** 25340266059SGregory Neil Shapiro ** Returns: 25440266059SGregory Neil Shapiro ** -1 on error 25540266059SGregory Neil Shapiro ** otherwise number of bytes written 25640266059SGregory Neil Shapiro */ 25740266059SGregory Neil Shapiro 25840266059SGregory Neil Shapiro static ssize_t sasl_write __P((SM_FILE_T *, const char *, size_t)); 25940266059SGregory Neil Shapiro 26006f25ae9SGregory Neil Shapiro static ssize_t 26140266059SGregory Neil Shapiro sasl_write(fp, buf, size) 26240266059SGregory Neil Shapiro SM_FILE_T *fp; 26340266059SGregory Neil Shapiro const char *buf; 26406f25ae9SGregory Neil Shapiro size_t size; 26506f25ae9SGregory Neil Shapiro { 26606f25ae9SGregory Neil Shapiro int result; 26794c01205SGregory Neil Shapiro # if SASL >= 20000 26894c01205SGregory Neil Shapiro const char *outbuf; 26994c01205SGregory Neil Shapiro # else /* SASL >= 20000 */ 27006f25ae9SGregory Neil Shapiro char *outbuf; 27194c01205SGregory Neil Shapiro # endif /* SASL >= 20000 */ 27206f25ae9SGregory Neil Shapiro unsigned int outlen; 27340266059SGregory Neil Shapiro size_t ret = 0, total = 0; 27440266059SGregory Neil Shapiro struct sasl_obj *so = (struct sasl_obj *) fp->f_cookie; 27506f25ae9SGregory Neil Shapiro 27640266059SGregory Neil Shapiro result = sasl_encode(so->conn, buf, 27740266059SGregory Neil Shapiro (unsigned int) size, &outbuf, &outlen); 27806f25ae9SGregory Neil Shapiro 27906f25ae9SGregory Neil Shapiro if (result != SASL_OK) 28006f25ae9SGregory Neil Shapiro return -1; 28106f25ae9SGregory Neil Shapiro 28206f25ae9SGregory Neil Shapiro if (outbuf != NULL) 28306f25ae9SGregory Neil Shapiro { 28440266059SGregory Neil Shapiro while (outlen > 0) 28540266059SGregory Neil Shapiro { 286605302a5SGregory Neil Shapiro /* XXX result == 0? */ 28740266059SGregory Neil Shapiro ret = sm_io_write(so->fp, SM_TIME_DEFAULT, 28840266059SGregory Neil Shapiro &outbuf[total], outlen); 28940266059SGregory Neil Shapiro outlen -= ret; 29040266059SGregory Neil Shapiro total += ret; 29140266059SGregory Neil Shapiro } 29294c01205SGregory Neil Shapiro # if SASL < 20000 293193538b7SGregory Neil Shapiro SASL_DEALLOC(outbuf); 29494c01205SGregory Neil Shapiro # endif /* SASL < 20000 */ 29506f25ae9SGregory Neil Shapiro } 29606f25ae9SGregory Neil Shapiro return size; 29706f25ae9SGregory Neil Shapiro } 29806f25ae9SGregory Neil Shapiro 29940266059SGregory Neil Shapiro /* 30040266059SGregory Neil Shapiro ** SFDCSASL -- create sasl file type and open in and out file pointers 30140266059SGregory Neil Shapiro ** for sendmail to read from and write to. 30240266059SGregory Neil Shapiro ** 30340266059SGregory Neil Shapiro ** Parameters: 30440266059SGregory Neil Shapiro ** fin -- the sm_io file encrypted data to be read from 30540266059SGregory Neil Shapiro ** fout -- the sm_io file encrypted data to be writen to 30640266059SGregory Neil Shapiro ** conn -- the sasl connection pointer 30740266059SGregory Neil Shapiro ** 30840266059SGregory Neil Shapiro ** Returns: 30940266059SGregory Neil Shapiro ** -1 on error 31040266059SGregory Neil Shapiro ** 0 on success 31140266059SGregory Neil Shapiro ** 31240266059SGregory Neil Shapiro ** Side effects: 31340266059SGregory Neil Shapiro ** The arguments "fin" and "fout" are replaced with the new 31440266059SGregory Neil Shapiro ** SM_FILE_T pointers. 31540266059SGregory Neil Shapiro */ 31640266059SGregory Neil Shapiro 31706f25ae9SGregory Neil Shapiro int 31806f25ae9SGregory Neil Shapiro sfdcsasl(fin, fout, conn) 31940266059SGregory Neil Shapiro SM_FILE_T **fin; 32040266059SGregory Neil Shapiro SM_FILE_T **fout; 32106f25ae9SGregory Neil Shapiro sasl_conn_t *conn; 32206f25ae9SGregory Neil Shapiro { 32340266059SGregory Neil Shapiro SM_FILE_T *newin, *newout; 32440266059SGregory Neil Shapiro SM_FILE_T SM_IO_SET_TYPE(sasl_vector, "sasl", sasl_open, sasl_close, 32540266059SGregory Neil Shapiro sasl_read, sasl_write, NULL, sasl_getinfo, NULL, 32640266059SGregory Neil Shapiro SM_TIME_FOREVER); 32740266059SGregory Neil Shapiro struct sasl_info info; 32806f25ae9SGregory Neil Shapiro 32906f25ae9SGregory Neil Shapiro if (conn == NULL) 33006f25ae9SGregory Neil Shapiro { 33106f25ae9SGregory Neil Shapiro /* no need to do anything */ 33206f25ae9SGregory Neil Shapiro return 0; 33306f25ae9SGregory Neil Shapiro } 33406f25ae9SGregory Neil Shapiro 33540266059SGregory Neil Shapiro SM_IO_INIT_TYPE(sasl_vector, "sasl", sasl_open, sasl_close, 33640266059SGregory Neil Shapiro sasl_read, sasl_write, NULL, sasl_getinfo, NULL, 33740266059SGregory Neil Shapiro SM_TIME_FOREVER); 33840266059SGregory Neil Shapiro info.fp = *fin; 33940266059SGregory Neil Shapiro info.conn = conn; 34040266059SGregory Neil Shapiro newin = sm_io_open(&sasl_vector, SM_TIME_DEFAULT, &info, SM_IO_RDONLY, 34140266059SGregory Neil Shapiro NULL); 34206f25ae9SGregory Neil Shapiro 34340266059SGregory Neil Shapiro if (newin == NULL) 34440266059SGregory Neil Shapiro return -1; 34506f25ae9SGregory Neil Shapiro 34640266059SGregory Neil Shapiro info.fp = *fout; 34740266059SGregory Neil Shapiro info.conn = conn; 34840266059SGregory Neil Shapiro newout = sm_io_open(&sasl_vector, SM_TIME_DEFAULT, &info, SM_IO_WRONLY, 34940266059SGregory Neil Shapiro NULL); 35006f25ae9SGregory Neil Shapiro 35140266059SGregory Neil Shapiro if (newout == NULL) 35206f25ae9SGregory Neil Shapiro { 35340266059SGregory Neil Shapiro (void) sm_io_close(newin, SM_TIME_DEFAULT); 35406f25ae9SGregory Neil Shapiro return -1; 35506f25ae9SGregory Neil Shapiro } 35640266059SGregory Neil Shapiro sm_io_automode(newin, newout); 35740266059SGregory Neil Shapiro 35840266059SGregory Neil Shapiro *fin = newin; 35940266059SGregory Neil Shapiro *fout = newout; 36006f25ae9SGregory Neil Shapiro return 0; 36106f25ae9SGregory Neil Shapiro } 36240266059SGregory Neil Shapiro #endif /* SASL */ 36306f25ae9SGregory Neil Shapiro 36440266059SGregory Neil Shapiro #if STARTTLS 36506f25ae9SGregory Neil Shapiro # include "sfsasl.h" 36606f25ae9SGregory Neil Shapiro # include <openssl/err.h> 36706f25ae9SGregory Neil Shapiro 36840266059SGregory Neil Shapiro /* Structure used by the "tls" file type */ 36940266059SGregory Neil Shapiro struct tls_obj 37040266059SGregory Neil Shapiro { 37140266059SGregory Neil Shapiro SM_FILE_T *fp; 37240266059SGregory Neil Shapiro SSL *con; 37340266059SGregory Neil Shapiro }; 37440266059SGregory Neil Shapiro 37540266059SGregory Neil Shapiro struct tls_info 37640266059SGregory Neil Shapiro { 37740266059SGregory Neil Shapiro SM_FILE_T *fp; 37840266059SGregory Neil Shapiro SSL *con; 37940266059SGregory Neil Shapiro }; 38040266059SGregory Neil Shapiro 38140266059SGregory Neil Shapiro /* 38240266059SGregory Neil Shapiro ** TLS_GETINFO - returns requested information about a "tls" file 38340266059SGregory Neil Shapiro ** descriptor. 38440266059SGregory Neil Shapiro ** 38540266059SGregory Neil Shapiro ** Parameters: 38640266059SGregory Neil Shapiro ** fp -- the file descriptor 38740266059SGregory Neil Shapiro ** what -- the type of information requested 38840266059SGregory Neil Shapiro ** valp -- the thang to return the information in (unused) 38940266059SGregory Neil Shapiro ** 39040266059SGregory Neil Shapiro ** Returns: 39140266059SGregory Neil Shapiro ** -1 for unknown requests 39240266059SGregory Neil Shapiro ** >=0 on success with valp filled in (if possible). 39340266059SGregory Neil Shapiro */ 39440266059SGregory Neil Shapiro 39540266059SGregory Neil Shapiro static int tls_getinfo __P((SM_FILE_T *, int, void *)); 39640266059SGregory Neil Shapiro 39740266059SGregory Neil Shapiro /* ARGSUSED2 */ 39813058a91SGregory Neil Shapiro static int 39940266059SGregory Neil Shapiro tls_getinfo(fp, what, valp) 40040266059SGregory Neil Shapiro SM_FILE_T *fp; 40140266059SGregory Neil Shapiro int what; 40240266059SGregory Neil Shapiro void *valp; 40340266059SGregory Neil Shapiro { 40440266059SGregory Neil Shapiro struct tls_obj *so = (struct tls_obj *) fp->f_cookie; 40540266059SGregory Neil Shapiro 40640266059SGregory Neil Shapiro switch (what) 40740266059SGregory Neil Shapiro { 40840266059SGregory Neil Shapiro case SM_IO_WHAT_FD: 40940266059SGregory Neil Shapiro if (so->fp == NULL) 41040266059SGregory Neil Shapiro return -1; 41140266059SGregory Neil Shapiro return so->fp->f_file; /* for stdio fileno() compatability */ 41240266059SGregory Neil Shapiro 41340266059SGregory Neil Shapiro case SM_IO_IS_READABLE: 41440266059SGregory Neil Shapiro return SSL_pending(so->con) > 0; 41540266059SGregory Neil Shapiro 41640266059SGregory Neil Shapiro default: 41740266059SGregory Neil Shapiro return -1; 41840266059SGregory Neil Shapiro } 41940266059SGregory Neil Shapiro } 42040266059SGregory Neil Shapiro 42140266059SGregory Neil Shapiro /* 42240266059SGregory Neil Shapiro ** TLS_OPEN -- creates the tls specific information for opening a 42340266059SGregory Neil Shapiro ** file of the tls type. 42440266059SGregory Neil Shapiro ** 42540266059SGregory Neil Shapiro ** Parameters: 42640266059SGregory Neil Shapiro ** fp -- the file pointer associated with the new open 42740266059SGregory Neil Shapiro ** info -- the sm_io file pointer holding the open and the 42840266059SGregory Neil Shapiro ** TLS encryption connection to be read from or written to 42940266059SGregory Neil Shapiro ** flags -- ignored 43040266059SGregory Neil Shapiro ** rpool -- ignored 43140266059SGregory Neil Shapiro ** 43240266059SGregory Neil Shapiro ** Returns: 43340266059SGregory Neil Shapiro ** 0 on success 43440266059SGregory Neil Shapiro */ 43540266059SGregory Neil Shapiro 43640266059SGregory Neil Shapiro static int tls_open __P((SM_FILE_T *, const void *, int, const void *)); 43740266059SGregory Neil Shapiro 43840266059SGregory Neil Shapiro /* ARGSUSED2 */ 43940266059SGregory Neil Shapiro static int 44040266059SGregory Neil Shapiro tls_open(fp, info, flags, rpool) 44140266059SGregory Neil Shapiro SM_FILE_T *fp; 44240266059SGregory Neil Shapiro const void *info; 44340266059SGregory Neil Shapiro int flags; 44440266059SGregory Neil Shapiro const void *rpool; 44540266059SGregory Neil Shapiro { 44640266059SGregory Neil Shapiro struct tls_obj *so; 44740266059SGregory Neil Shapiro struct tls_info *ti = (struct tls_info *) info; 44840266059SGregory Neil Shapiro 44940266059SGregory Neil Shapiro so = (struct tls_obj *) sm_malloc(sizeof(struct tls_obj)); 45040266059SGregory Neil Shapiro so->fp = ti->fp; 45140266059SGregory Neil Shapiro so->con = ti->con; 45240266059SGregory Neil Shapiro 45340266059SGregory Neil Shapiro /* 45440266059SGregory Neil Shapiro ** We try to get the "raw" file descriptor that TLS uses to 45540266059SGregory Neil Shapiro ** do the actual read/write with. This is to allow us control 45640266059SGregory Neil Shapiro ** over the file descriptor being a blocking or non-blocking type. 45740266059SGregory Neil Shapiro ** Under the covers TLS handles the change and this allows us 45840266059SGregory Neil Shapiro ** to do timeouts with sm_io. 45940266059SGregory Neil Shapiro */ 46040266059SGregory Neil Shapiro 46140266059SGregory Neil Shapiro fp->f_file = sm_io_getinfo(so->fp, SM_IO_WHAT_FD, NULL); 46240266059SGregory Neil Shapiro (void) sm_io_setvbuf(so->fp, SM_TIME_DEFAULT, NULL, SM_IO_NOW, 0); 46340266059SGregory Neil Shapiro fp->f_cookie = so; 46440266059SGregory Neil Shapiro return 0; 46540266059SGregory Neil Shapiro } 46640266059SGregory Neil Shapiro 46740266059SGregory Neil Shapiro /* 46840266059SGregory Neil Shapiro ** TLS_CLOSE -- close the tls specific parts of the tls file pointer 46940266059SGregory Neil Shapiro ** 47040266059SGregory Neil Shapiro ** Parameters: 47140266059SGregory Neil Shapiro ** fp -- the file pointer to close 47240266059SGregory Neil Shapiro ** 47340266059SGregory Neil Shapiro ** Returns: 47440266059SGregory Neil Shapiro ** 0 on success 47540266059SGregory Neil Shapiro */ 47640266059SGregory Neil Shapiro 47740266059SGregory Neil Shapiro static int tls_close __P((SM_FILE_T *)); 47840266059SGregory Neil Shapiro 47940266059SGregory Neil Shapiro static int 48040266059SGregory Neil Shapiro tls_close(fp) 48140266059SGregory Neil Shapiro SM_FILE_T *fp; 48240266059SGregory Neil Shapiro { 48340266059SGregory Neil Shapiro struct tls_obj *so; 48440266059SGregory Neil Shapiro 48540266059SGregory Neil Shapiro so = (struct tls_obj *) fp->f_cookie; 48640266059SGregory Neil Shapiro if (so->fp != NULL) 48740266059SGregory Neil Shapiro { 48840266059SGregory Neil Shapiro sm_io_close(so->fp, SM_TIME_DEFAULT); 48940266059SGregory Neil Shapiro so->fp = NULL; 49040266059SGregory Neil Shapiro } 49140266059SGregory Neil Shapiro sm_free(so); 49240266059SGregory Neil Shapiro so = NULL; 49340266059SGregory Neil Shapiro return 0; 49440266059SGregory Neil Shapiro } 49540266059SGregory Neil Shapiro 49640266059SGregory Neil Shapiro /* maximum number of retries for TLS related I/O due to handshakes */ 49740266059SGregory Neil Shapiro # define MAX_TLS_IOS 4 49840266059SGregory Neil Shapiro 49940266059SGregory Neil Shapiro /* 50040266059SGregory Neil Shapiro ** TLS_READ -- read secured information for the caller 50140266059SGregory Neil Shapiro ** 50240266059SGregory Neil Shapiro ** Parameters: 50340266059SGregory Neil Shapiro ** fp -- the file pointer 50440266059SGregory Neil Shapiro ** buf -- the location to place the data 50540266059SGregory Neil Shapiro ** size -- the number of bytes to read from connection 50640266059SGregory Neil Shapiro ** 50740266059SGregory Neil Shapiro ** Results: 50840266059SGregory Neil Shapiro ** -1 on error 50940266059SGregory Neil Shapiro ** otherwise the number of bytes read 51040266059SGregory Neil Shapiro */ 51140266059SGregory Neil Shapiro 51240266059SGregory Neil Shapiro static ssize_t tls_read __P((SM_FILE_T *, char *, size_t)); 51340266059SGregory Neil Shapiro 51440266059SGregory Neil Shapiro static ssize_t 51540266059SGregory Neil Shapiro tls_read(fp, buf, size) 51640266059SGregory Neil Shapiro SM_FILE_T *fp; 51713058a91SGregory Neil Shapiro char *buf; 51840266059SGregory Neil Shapiro size_t size; 51906f25ae9SGregory Neil Shapiro { 52006f25ae9SGregory Neil Shapiro int r; 52140266059SGregory Neil Shapiro static int again = MAX_TLS_IOS; 52240266059SGregory Neil Shapiro struct tls_obj *so = (struct tls_obj *) fp->f_cookie; 52306f25ae9SGregory Neil Shapiro char *err; 52406f25ae9SGregory Neil Shapiro 52540266059SGregory Neil Shapiro r = SSL_read(so->con, (char *) buf, size); 52640266059SGregory Neil Shapiro 52740266059SGregory Neil Shapiro if (r > 0) 52840266059SGregory Neil Shapiro { 52940266059SGregory Neil Shapiro again = MAX_TLS_IOS; 53040266059SGregory Neil Shapiro return r; 53140266059SGregory Neil Shapiro } 53240266059SGregory Neil Shapiro 53306f25ae9SGregory Neil Shapiro err = NULL; 53440266059SGregory Neil Shapiro switch (SSL_get_error(so->con, r)) 53506f25ae9SGregory Neil Shapiro { 53606f25ae9SGregory Neil Shapiro case SSL_ERROR_NONE: 53740266059SGregory Neil Shapiro case SSL_ERROR_ZERO_RETURN: 53840266059SGregory Neil Shapiro again = MAX_TLS_IOS; 53906f25ae9SGregory Neil Shapiro break; 54006f25ae9SGregory Neil Shapiro case SSL_ERROR_WANT_WRITE: 54140266059SGregory Neil Shapiro if (--again <= 0) 54240266059SGregory Neil Shapiro err = "read W BLOCK"; 54340266059SGregory Neil Shapiro else 54440266059SGregory Neil Shapiro errno = EAGAIN; 54506f25ae9SGregory Neil Shapiro break; 54606f25ae9SGregory Neil Shapiro case SSL_ERROR_WANT_READ: 54740266059SGregory Neil Shapiro if (--again <= 0) 54840266059SGregory Neil Shapiro err = "read R BLOCK"; 54940266059SGregory Neil Shapiro else 55040266059SGregory Neil Shapiro errno = EAGAIN; 55106f25ae9SGregory Neil Shapiro break; 55206f25ae9SGregory Neil Shapiro case SSL_ERROR_WANT_X509_LOOKUP: 55306f25ae9SGregory Neil Shapiro err = "write X BLOCK"; 55406f25ae9SGregory Neil Shapiro break; 55506f25ae9SGregory Neil Shapiro case SSL_ERROR_SYSCALL: 55640266059SGregory Neil Shapiro if (r == 0 && errno == 0) /* out of protocol EOF found */ 55740266059SGregory Neil Shapiro break; 55806f25ae9SGregory Neil Shapiro err = "syscall error"; 55906f25ae9SGregory Neil Shapiro /* 56006f25ae9SGregory Neil Shapiro get_last_socket_error()); 56106f25ae9SGregory Neil Shapiro */ 56206f25ae9SGregory Neil Shapiro break; 56306f25ae9SGregory Neil Shapiro case SSL_ERROR_SSL: 564959366dcSGregory Neil Shapiro #if _FFR_DEAL_WITH_ERROR_SSL 565959366dcSGregory Neil Shapiro if (r == 0 && errno == 0) /* out of protocol EOF found */ 566959366dcSGregory Neil Shapiro break; 567959366dcSGregory Neil Shapiro #endif /* _FFR_DEAL_WITH_ERROR_SSL */ 56806f25ae9SGregory Neil Shapiro err = "generic SSL error"; 56940266059SGregory Neil Shapiro if (LogLevel > 9) 57040266059SGregory Neil Shapiro tlslogerr("read"); 571959366dcSGregory Neil Shapiro 572959366dcSGregory Neil Shapiro #if _FFR_DEAL_WITH_ERROR_SSL 573959366dcSGregory Neil Shapiro /* avoid repeated calls? */ 574959366dcSGregory Neil Shapiro if (r == 0) 575959366dcSGregory Neil Shapiro r = -1; 576959366dcSGregory Neil Shapiro #endif /* _FFR_DEAL_WITH_ERROR_SSL */ 57706f25ae9SGregory Neil Shapiro break; 57806f25ae9SGregory Neil Shapiro } 57906f25ae9SGregory Neil Shapiro if (err != NULL) 58040266059SGregory Neil Shapiro { 581605302a5SGregory Neil Shapiro int save_errno; 582605302a5SGregory Neil Shapiro 583605302a5SGregory Neil Shapiro save_errno = (errno == 0) ? EIO : errno; 58440266059SGregory Neil Shapiro again = MAX_TLS_IOS; 58540266059SGregory Neil Shapiro if (LogLevel > 7) 58640266059SGregory Neil Shapiro sm_syslog(LOG_WARNING, NOQID, 58740266059SGregory Neil Shapiro "STARTTLS: read error=%s (%d)", err, r); 588605302a5SGregory Neil Shapiro errno = save_errno; 58906f25ae9SGregory Neil Shapiro } 59006f25ae9SGregory Neil Shapiro return r; 59106f25ae9SGregory Neil Shapiro } 59206f25ae9SGregory Neil Shapiro 59340266059SGregory Neil Shapiro /* 59440266059SGregory Neil Shapiro ** TLS_WRITE -- write information out through secure connection 59540266059SGregory Neil Shapiro ** 59640266059SGregory Neil Shapiro ** Parameters: 59740266059SGregory Neil Shapiro ** fp -- the file pointer 59840266059SGregory Neil Shapiro ** buf -- holds the data to be securely written 59940266059SGregory Neil Shapiro ** size -- the number of bytes to write 60040266059SGregory Neil Shapiro ** 60140266059SGregory Neil Shapiro ** Returns: 60240266059SGregory Neil Shapiro ** -1 on error 60340266059SGregory Neil Shapiro ** otherwise number of bytes written 60440266059SGregory Neil Shapiro */ 60540266059SGregory Neil Shapiro 60640266059SGregory Neil Shapiro static ssize_t tls_write __P((SM_FILE_T *, const char *, size_t)); 60740266059SGregory Neil Shapiro 60813058a91SGregory Neil Shapiro static ssize_t 60940266059SGregory Neil Shapiro tls_write(fp, buf, size) 61040266059SGregory Neil Shapiro SM_FILE_T *fp; 61113058a91SGregory Neil Shapiro const char *buf; 61240266059SGregory Neil Shapiro size_t size; 61306f25ae9SGregory Neil Shapiro { 61406f25ae9SGregory Neil Shapiro int r; 61540266059SGregory Neil Shapiro static int again = MAX_TLS_IOS; 61640266059SGregory Neil Shapiro struct tls_obj *so = (struct tls_obj *) fp->f_cookie; 61706f25ae9SGregory Neil Shapiro char *err; 61806f25ae9SGregory Neil Shapiro 61940266059SGregory Neil Shapiro r = SSL_write(so->con, (char *) buf, size); 62040266059SGregory Neil Shapiro 62140266059SGregory Neil Shapiro if (r > 0) 62240266059SGregory Neil Shapiro { 62340266059SGregory Neil Shapiro again = MAX_TLS_IOS; 62440266059SGregory Neil Shapiro return r; 62540266059SGregory Neil Shapiro } 62606f25ae9SGregory Neil Shapiro err = NULL; 62740266059SGregory Neil Shapiro switch (SSL_get_error(so->con, r)) 62806f25ae9SGregory Neil Shapiro { 62906f25ae9SGregory Neil Shapiro case SSL_ERROR_NONE: 63040266059SGregory Neil Shapiro case SSL_ERROR_ZERO_RETURN: 63140266059SGregory Neil Shapiro again = MAX_TLS_IOS; 63206f25ae9SGregory Neil Shapiro break; 63306f25ae9SGregory Neil Shapiro case SSL_ERROR_WANT_WRITE: 63440266059SGregory Neil Shapiro if (--again <= 0) 63506f25ae9SGregory Neil Shapiro err = "write W BLOCK"; 63640266059SGregory Neil Shapiro else 63740266059SGregory Neil Shapiro errno = EAGAIN; 63806f25ae9SGregory Neil Shapiro break; 63906f25ae9SGregory Neil Shapiro case SSL_ERROR_WANT_READ: 64040266059SGregory Neil Shapiro if (--again <= 0) 64106f25ae9SGregory Neil Shapiro err = "write R BLOCK"; 64240266059SGregory Neil Shapiro else 64340266059SGregory Neil Shapiro errno = EAGAIN; 64406f25ae9SGregory Neil Shapiro break; 64506f25ae9SGregory Neil Shapiro case SSL_ERROR_WANT_X509_LOOKUP: 64606f25ae9SGregory Neil Shapiro err = "write X BLOCK"; 64706f25ae9SGregory Neil Shapiro break; 64806f25ae9SGregory Neil Shapiro case SSL_ERROR_SYSCALL: 64940266059SGregory Neil Shapiro if (r == 0 && errno == 0) /* out of protocol EOF found */ 65040266059SGregory Neil Shapiro break; 65106f25ae9SGregory Neil Shapiro err = "syscall error"; 65206f25ae9SGregory Neil Shapiro /* 65306f25ae9SGregory Neil Shapiro get_last_socket_error()); 65406f25ae9SGregory Neil Shapiro */ 65506f25ae9SGregory Neil Shapiro break; 65606f25ae9SGregory Neil Shapiro case SSL_ERROR_SSL: 65706f25ae9SGregory Neil Shapiro err = "generic SSL error"; 65806f25ae9SGregory Neil Shapiro /* 65906f25ae9SGregory Neil Shapiro ERR_GET_REASON(ERR_peek_error())); 66006f25ae9SGregory Neil Shapiro */ 66140266059SGregory Neil Shapiro if (LogLevel > 9) 66240266059SGregory Neil Shapiro tlslogerr("write"); 663959366dcSGregory Neil Shapiro 664959366dcSGregory Neil Shapiro #if _FFR_DEAL_WITH_ERROR_SSL 665959366dcSGregory Neil Shapiro /* avoid repeated calls? */ 666959366dcSGregory Neil Shapiro if (r == 0) 667959366dcSGregory Neil Shapiro r = -1; 668959366dcSGregory Neil Shapiro #endif /* _FFR_DEAL_WITH_ERROR_SSL */ 66906f25ae9SGregory Neil Shapiro break; 67006f25ae9SGregory Neil Shapiro } 67106f25ae9SGregory Neil Shapiro if (err != NULL) 67240266059SGregory Neil Shapiro { 673605302a5SGregory Neil Shapiro int save_errno; 674605302a5SGregory Neil Shapiro 675605302a5SGregory Neil Shapiro save_errno = (errno == 0) ? EIO : errno; 67640266059SGregory Neil Shapiro again = MAX_TLS_IOS; 67740266059SGregory Neil Shapiro if (LogLevel > 7) 67840266059SGregory Neil Shapiro sm_syslog(LOG_WARNING, NOQID, 67940266059SGregory Neil Shapiro "STARTTLS: write error=%s (%d)", err, r); 680605302a5SGregory Neil Shapiro errno = save_errno; 68106f25ae9SGregory Neil Shapiro } 68206f25ae9SGregory Neil Shapiro return r; 68306f25ae9SGregory Neil Shapiro } 68406f25ae9SGregory Neil Shapiro 68540266059SGregory Neil Shapiro /* 68640266059SGregory Neil Shapiro ** SFDCTLS -- create tls file type and open in and out file pointers 68740266059SGregory Neil Shapiro ** for sendmail to read from and write to. 68840266059SGregory Neil Shapiro ** 68940266059SGregory Neil Shapiro ** Parameters: 69040266059SGregory Neil Shapiro ** fin -- data input source being replaced 69140266059SGregory Neil Shapiro ** fout -- data output source being replaced 69240266059SGregory Neil Shapiro ** conn -- the tls connection pointer 69340266059SGregory Neil Shapiro ** 69440266059SGregory Neil Shapiro ** Returns: 69540266059SGregory Neil Shapiro ** -1 on error 69640266059SGregory Neil Shapiro ** 0 on success 69740266059SGregory Neil Shapiro ** 69840266059SGregory Neil Shapiro ** Side effects: 69940266059SGregory Neil Shapiro ** The arguments "fin" and "fout" are replaced with the new 70040266059SGregory Neil Shapiro ** SM_FILE_T pointers. 70140266059SGregory Neil Shapiro ** The original "fin" and "fout" are preserved in the tls file 70240266059SGregory Neil Shapiro ** type but are not actually used because of the design of TLS. 70340266059SGregory Neil Shapiro */ 70406f25ae9SGregory Neil Shapiro 70506f25ae9SGregory Neil Shapiro int 70606f25ae9SGregory Neil Shapiro sfdctls(fin, fout, con) 70740266059SGregory Neil Shapiro SM_FILE_T **fin; 70840266059SGregory Neil Shapiro SM_FILE_T **fout; 70906f25ae9SGregory Neil Shapiro SSL *con; 71006f25ae9SGregory Neil Shapiro { 71140266059SGregory Neil Shapiro SM_FILE_T *tlsin, *tlsout; 71240266059SGregory Neil Shapiro SM_FILE_T SM_IO_SET_TYPE(tls_vector, "tls", tls_open, tls_close, 71340266059SGregory Neil Shapiro tls_read, tls_write, NULL, tls_getinfo, NULL, 71440266059SGregory Neil Shapiro SM_TIME_FOREVER); 71540266059SGregory Neil Shapiro struct tls_info info; 71606f25ae9SGregory Neil Shapiro 71740266059SGregory Neil Shapiro SM_ASSERT(con != NULL); 71806f25ae9SGregory Neil Shapiro 71940266059SGregory Neil Shapiro SM_IO_INIT_TYPE(tls_vector, "tls", tls_open, tls_close, 72040266059SGregory Neil Shapiro tls_read, tls_write, NULL, tls_getinfo, NULL, 72140266059SGregory Neil Shapiro SM_TIME_FOREVER); 72240266059SGregory Neil Shapiro info.fp = *fin; 72340266059SGregory Neil Shapiro info.con = con; 72440266059SGregory Neil Shapiro tlsin = sm_io_open(&tls_vector, SM_TIME_DEFAULT, &info, SM_IO_RDONLY, 72540266059SGregory Neil Shapiro NULL); 72640266059SGregory Neil Shapiro if (tlsin == NULL) 72740266059SGregory Neil Shapiro return -1; 72806f25ae9SGregory Neil Shapiro 72940266059SGregory Neil Shapiro info.fp = *fout; 73040266059SGregory Neil Shapiro tlsout = sm_io_open(&tls_vector, SM_TIME_DEFAULT, &info, SM_IO_WRONLY, 73140266059SGregory Neil Shapiro NULL); 73240266059SGregory Neil Shapiro if (tlsout == NULL) 73342e5d165SGregory Neil Shapiro { 73440266059SGregory Neil Shapiro (void) sm_io_close(tlsin, SM_TIME_DEFAULT); 73542e5d165SGregory Neil Shapiro return -1; 73642e5d165SGregory Neil Shapiro } 73740266059SGregory Neil Shapiro sm_io_automode(tlsin, tlsout); 73806f25ae9SGregory Neil Shapiro 73940266059SGregory Neil Shapiro *fin = tlsin; 74040266059SGregory Neil Shapiro *fout = tlsout; 74106f25ae9SGregory Neil Shapiro return 0; 74206f25ae9SGregory Neil Shapiro } 74340266059SGregory Neil Shapiro #endif /* STARTTLS */ 744