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> 12605302a5SGregory Neil Shapiro SM_RCSID("@(#)$Id: sfsasl.c,v 8.89 2002/02/22 04:41:28 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 <sasl.h> 1806f25ae9SGregory Neil Shapiro # include "sfsasl.h" 1906f25ae9SGregory Neil Shapiro 2040266059SGregory Neil Shapiro /* Structure used by the "sasl" file type */ 2140266059SGregory Neil Shapiro struct sasl_obj 2240266059SGregory Neil Shapiro { 2340266059SGregory Neil Shapiro SM_FILE_T *fp; 2440266059SGregory Neil Shapiro sasl_conn_t *conn; 2540266059SGregory Neil Shapiro }; 2640266059SGregory Neil Shapiro 2740266059SGregory Neil Shapiro struct sasl_info 2840266059SGregory Neil Shapiro { 2940266059SGregory Neil Shapiro SM_FILE_T *fp; 3040266059SGregory Neil Shapiro sasl_conn_t *conn; 3140266059SGregory Neil Shapiro }; 3240266059SGregory Neil Shapiro 3340266059SGregory Neil Shapiro /* 3440266059SGregory Neil Shapiro ** SASL_GETINFO - returns requested information about a "sasl" file 3540266059SGregory Neil Shapiro ** descriptor. 3640266059SGregory Neil Shapiro ** 3740266059SGregory Neil Shapiro ** Parameters: 3840266059SGregory Neil Shapiro ** fp -- the file descriptor 3940266059SGregory Neil Shapiro ** what -- the type of information requested 4040266059SGregory Neil Shapiro ** valp -- the thang to return the information in 4140266059SGregory Neil Shapiro ** 4240266059SGregory Neil Shapiro ** Returns: 4340266059SGregory Neil Shapiro ** -1 for unknown requests 4440266059SGregory Neil Shapiro ** >=0 on success with valp filled in (if possible). 4540266059SGregory Neil Shapiro */ 4640266059SGregory Neil Shapiro 4740266059SGregory Neil Shapiro static int sasl_getinfo __P((SM_FILE_T *, int, void *)); 4840266059SGregory Neil Shapiro 4940266059SGregory Neil Shapiro static int 5040266059SGregory Neil Shapiro sasl_getinfo(fp, what, valp) 5140266059SGregory Neil Shapiro SM_FILE_T *fp; 5240266059SGregory Neil Shapiro int what; 5340266059SGregory Neil Shapiro void *valp; 5440266059SGregory Neil Shapiro { 5540266059SGregory Neil Shapiro struct sasl_obj *so = (struct sasl_obj *) fp->f_cookie; 5640266059SGregory Neil Shapiro 5740266059SGregory Neil Shapiro switch (what) 5840266059SGregory Neil Shapiro { 5940266059SGregory Neil Shapiro case SM_IO_WHAT_FD: 6040266059SGregory Neil Shapiro if (so->fp == NULL) 6140266059SGregory Neil Shapiro return -1; 6240266059SGregory Neil Shapiro return so->fp->f_file; /* for stdio fileno() compatability */ 6340266059SGregory Neil Shapiro 6440266059SGregory Neil Shapiro case SM_IO_IS_READABLE: 6540266059SGregory Neil Shapiro if (so->fp == NULL) 6640266059SGregory Neil Shapiro return 0; 6740266059SGregory Neil Shapiro 6840266059SGregory Neil Shapiro /* get info from underlying file */ 6940266059SGregory Neil Shapiro return sm_io_getinfo(so->fp, what, valp); 7040266059SGregory Neil Shapiro 7140266059SGregory Neil Shapiro default: 7240266059SGregory Neil Shapiro return -1; 7340266059SGregory Neil Shapiro } 7440266059SGregory Neil Shapiro } 7540266059SGregory Neil Shapiro 7640266059SGregory Neil Shapiro /* 7740266059SGregory Neil Shapiro ** SASL_OPEN -- creates the sasl specific information for opening a 7840266059SGregory Neil Shapiro ** file of the sasl type. 7940266059SGregory Neil Shapiro ** 8040266059SGregory Neil Shapiro ** Parameters: 8140266059SGregory Neil Shapiro ** fp -- the file pointer associated with the new open 8240266059SGregory Neil Shapiro ** info -- contains the sasl connection information pointer and 8340266059SGregory Neil Shapiro ** the original SM_FILE_T that holds the open 8440266059SGregory Neil Shapiro ** flags -- ignored 8540266059SGregory Neil Shapiro ** rpool -- ignored 8640266059SGregory Neil Shapiro ** 8740266059SGregory Neil Shapiro ** Returns: 8840266059SGregory Neil Shapiro ** 0 on success 8940266059SGregory Neil Shapiro */ 9040266059SGregory Neil Shapiro 9140266059SGregory Neil Shapiro static int sasl_open __P((SM_FILE_T *, const void *, int, const void *)); 9240266059SGregory Neil Shapiro 9340266059SGregory Neil Shapiro /* ARGSUSED2 */ 9440266059SGregory Neil Shapiro static int 9540266059SGregory Neil Shapiro sasl_open(fp, info, flags, rpool) 9640266059SGregory Neil Shapiro SM_FILE_T *fp; 9740266059SGregory Neil Shapiro const void *info; 9840266059SGregory Neil Shapiro int flags; 9940266059SGregory Neil Shapiro const void *rpool; 10040266059SGregory Neil Shapiro { 10140266059SGregory Neil Shapiro struct sasl_obj *so; 10240266059SGregory Neil Shapiro struct sasl_info *si = (struct sasl_info *) info; 10340266059SGregory Neil Shapiro 10440266059SGregory Neil Shapiro so = (struct sasl_obj *) sm_malloc(sizeof(struct sasl_obj)); 10540266059SGregory Neil Shapiro so->fp = si->fp; 10640266059SGregory Neil Shapiro so->conn = si->conn; 10740266059SGregory Neil Shapiro 10840266059SGregory Neil Shapiro /* 10940266059SGregory Neil Shapiro ** The underlying 'fp' is set to SM_IO_NOW so that the entire 11040266059SGregory Neil Shapiro ** encoded string is written in one chunk. Otherwise there is 11140266059SGregory Neil Shapiro ** the possibility that it may appear illegal, bogus or 11240266059SGregory Neil Shapiro ** mangled to the other side of the connection. 11340266059SGregory Neil Shapiro ** We will read or write through 'fp' since it is the opaque 11440266059SGregory Neil Shapiro ** connection for the communications. We need to treat it this 11540266059SGregory Neil Shapiro ** way in case the encoded string is to be sent down a TLS 11640266059SGregory Neil Shapiro ** connection rather than, say, sm_io's stdio. 11740266059SGregory Neil Shapiro */ 11840266059SGregory Neil Shapiro 11940266059SGregory Neil Shapiro (void) sm_io_setvbuf(so->fp, SM_TIME_DEFAULT, NULL, SM_IO_NOW, 0); 12040266059SGregory Neil Shapiro fp->f_cookie = so; 12140266059SGregory Neil Shapiro return 0; 12240266059SGregory Neil Shapiro } 12340266059SGregory Neil Shapiro 12440266059SGregory Neil Shapiro /* 12540266059SGregory Neil Shapiro ** SASL_CLOSE -- close the sasl specific parts of the sasl file pointer 12640266059SGregory Neil Shapiro ** 12740266059SGregory Neil Shapiro ** Parameters: 12840266059SGregory Neil Shapiro ** fp -- the file pointer to close 12940266059SGregory Neil Shapiro ** 13040266059SGregory Neil Shapiro ** Returns: 13140266059SGregory Neil Shapiro ** 0 on success 13240266059SGregory Neil Shapiro */ 13340266059SGregory Neil Shapiro 13440266059SGregory Neil Shapiro static int sasl_close __P((SM_FILE_T *)); 13540266059SGregory Neil Shapiro 13640266059SGregory Neil Shapiro static int 13740266059SGregory Neil Shapiro sasl_close(fp) 13840266059SGregory Neil Shapiro SM_FILE_T *fp; 13940266059SGregory Neil Shapiro { 14040266059SGregory Neil Shapiro struct sasl_obj *so; 14140266059SGregory Neil Shapiro 14240266059SGregory Neil Shapiro so = (struct sasl_obj *) fp->f_cookie; 14340266059SGregory Neil Shapiro if (so->fp != NULL) 14440266059SGregory Neil Shapiro { 14540266059SGregory Neil Shapiro sm_io_close(so->fp, SM_TIME_DEFAULT); 14640266059SGregory Neil Shapiro so->fp = NULL; 14740266059SGregory Neil Shapiro } 14840266059SGregory Neil Shapiro sm_free(so); 14940266059SGregory Neil Shapiro so = NULL; 15040266059SGregory Neil Shapiro return 0; 15140266059SGregory Neil Shapiro } 15240266059SGregory Neil Shapiro 153193538b7SGregory Neil Shapiro /* how to deallocate a buffer allocated by SASL */ 15440266059SGregory Neil Shapiro extern void sm_sasl_free __P((void *)); 15540266059SGregory Neil Shapiro # define SASL_DEALLOC(b) sm_sasl_free(b) 15640266059SGregory Neil Shapiro 15740266059SGregory Neil Shapiro /* 15840266059SGregory Neil Shapiro ** SASL_READ -- read encrypted information and decrypt it for the caller 15940266059SGregory Neil Shapiro ** 16040266059SGregory Neil Shapiro ** Parameters: 16140266059SGregory Neil Shapiro ** fp -- the file pointer 16240266059SGregory Neil Shapiro ** buf -- the location to place the decrypted information 16340266059SGregory Neil Shapiro ** size -- the number of bytes to read after decryption 16440266059SGregory Neil Shapiro ** 16540266059SGregory Neil Shapiro ** Results: 16640266059SGregory Neil Shapiro ** -1 on error 16740266059SGregory Neil Shapiro ** otherwise the number of bytes read 16840266059SGregory Neil Shapiro */ 16940266059SGregory Neil Shapiro 17040266059SGregory Neil Shapiro static ssize_t sasl_read __P((SM_FILE_T *, char *, size_t)); 171193538b7SGregory Neil Shapiro 17206f25ae9SGregory Neil Shapiro static ssize_t 17340266059SGregory Neil Shapiro sasl_read(fp, buf, size) 17440266059SGregory Neil Shapiro SM_FILE_T *fp; 17540266059SGregory Neil Shapiro char *buf; 17606f25ae9SGregory Neil Shapiro size_t size; 17706f25ae9SGregory Neil Shapiro { 17840266059SGregory Neil Shapiro int result; 17940266059SGregory Neil Shapiro ssize_t len; 180193538b7SGregory Neil Shapiro static char *outbuf = NULL; 181193538b7SGregory Neil Shapiro static unsigned int outlen = 0; 182193538b7SGregory Neil Shapiro static unsigned int offset = 0; 18340266059SGregory Neil Shapiro struct sasl_obj *so = (struct sasl_obj *) fp->f_cookie; 18406f25ae9SGregory Neil Shapiro 185193538b7SGregory Neil Shapiro /* 186193538b7SGregory Neil Shapiro ** sasl_decode() may require more data than a single read() returns. 187193538b7SGregory Neil Shapiro ** Hence we have to put a loop around the decoding. 188193538b7SGregory Neil Shapiro ** This also requires that we may have to split up the returned 189193538b7SGregory Neil Shapiro ** data since it might be larger than the allowed size. 190193538b7SGregory Neil Shapiro ** Therefore we use a static pointer and return portions of it 191193538b7SGregory Neil Shapiro ** if necessary. 192193538b7SGregory Neil Shapiro */ 19306f25ae9SGregory Neil Shapiro 194193538b7SGregory Neil Shapiro while (outbuf == NULL && outlen == 0) 195193538b7SGregory Neil Shapiro { 19640266059SGregory Neil Shapiro len = sm_io_read(so->fp, SM_TIME_DEFAULT, buf, size); 19706f25ae9SGregory Neil Shapiro if (len <= 0) 19806f25ae9SGregory Neil Shapiro return len; 19940266059SGregory Neil Shapiro result = sasl_decode(so->conn, buf, 20040266059SGregory Neil Shapiro (unsigned int) len, &outbuf, &outlen); 20106f25ae9SGregory Neil Shapiro if (result != SASL_OK) 20206f25ae9SGregory Neil Shapiro { 203193538b7SGregory Neil Shapiro outbuf = NULL; 204193538b7SGregory Neil Shapiro offset = 0; 205193538b7SGregory Neil Shapiro outlen = 0; 20606f25ae9SGregory Neil Shapiro return -1; 20706f25ae9SGregory Neil Shapiro } 208193538b7SGregory Neil Shapiro } 20906f25ae9SGregory Neil Shapiro 21040266059SGregory Neil Shapiro if (outbuf == NULL) 21106f25ae9SGregory Neil Shapiro { 21240266059SGregory Neil Shapiro /* be paranoid: outbuf == NULL but outlen != 0 */ 21340266059SGregory Neil Shapiro syserr("@sasl_read failure: outbuf == NULL but outlen != 0"); 21440266059SGregory Neil Shapiro /* NOTREACHED */ 21540266059SGregory Neil Shapiro } 216193538b7SGregory Neil Shapiro if (outlen - offset > size) 217193538b7SGregory Neil Shapiro { 218193538b7SGregory Neil Shapiro /* return another part of the buffer */ 21940266059SGregory Neil Shapiro (void) memcpy(buf, outbuf + offset, size); 220193538b7SGregory Neil Shapiro offset += size; 22140266059SGregory Neil Shapiro len = size; 22206f25ae9SGregory Neil Shapiro } 223193538b7SGregory Neil Shapiro else 224193538b7SGregory Neil Shapiro { 225193538b7SGregory Neil Shapiro /* return the rest of the buffer */ 22640266059SGregory Neil Shapiro len = outlen - offset; 22740266059SGregory Neil Shapiro (void) memcpy(buf, outbuf + offset, (size_t) len); 228193538b7SGregory Neil Shapiro SASL_DEALLOC(outbuf); 229193538b7SGregory Neil Shapiro outbuf = NULL; 230193538b7SGregory Neil Shapiro offset = 0; 231193538b7SGregory Neil Shapiro outlen = 0; 232193538b7SGregory Neil Shapiro } 23340266059SGregory Neil Shapiro return len; 23406f25ae9SGregory Neil Shapiro } 23506f25ae9SGregory Neil Shapiro 23640266059SGregory Neil Shapiro /* 23740266059SGregory Neil Shapiro ** SASL_WRITE -- write information out after encrypting it 23840266059SGregory Neil Shapiro ** 23940266059SGregory Neil Shapiro ** Parameters: 24040266059SGregory Neil Shapiro ** fp -- the file pointer 24140266059SGregory Neil Shapiro ** buf -- holds the data to be encrypted and written 24240266059SGregory Neil Shapiro ** size -- the number of bytes to have encrypted and written 24340266059SGregory Neil Shapiro ** 24440266059SGregory Neil Shapiro ** Returns: 24540266059SGregory Neil Shapiro ** -1 on error 24640266059SGregory Neil Shapiro ** otherwise number of bytes written 24740266059SGregory Neil Shapiro */ 24840266059SGregory Neil Shapiro 24940266059SGregory Neil Shapiro static ssize_t sasl_write __P((SM_FILE_T *, const char *, size_t)); 25040266059SGregory Neil Shapiro 25106f25ae9SGregory Neil Shapiro static ssize_t 25240266059SGregory Neil Shapiro sasl_write(fp, buf, size) 25340266059SGregory Neil Shapiro SM_FILE_T *fp; 25440266059SGregory Neil Shapiro const char *buf; 25506f25ae9SGregory Neil Shapiro size_t size; 25606f25ae9SGregory Neil Shapiro { 25706f25ae9SGregory Neil Shapiro int result; 25806f25ae9SGregory Neil Shapiro char *outbuf; 25906f25ae9SGregory Neil Shapiro unsigned int outlen; 26040266059SGregory Neil Shapiro size_t ret = 0, total = 0; 26140266059SGregory Neil Shapiro struct sasl_obj *so = (struct sasl_obj *) fp->f_cookie; 26206f25ae9SGregory Neil Shapiro 26340266059SGregory Neil Shapiro result = sasl_encode(so->conn, buf, 26440266059SGregory Neil Shapiro (unsigned int) size, &outbuf, &outlen); 26506f25ae9SGregory Neil Shapiro 26606f25ae9SGregory Neil Shapiro if (result != SASL_OK) 26706f25ae9SGregory Neil Shapiro return -1; 26806f25ae9SGregory Neil Shapiro 26906f25ae9SGregory Neil Shapiro if (outbuf != NULL) 27006f25ae9SGregory Neil Shapiro { 27140266059SGregory Neil Shapiro while (outlen > 0) 27240266059SGregory Neil Shapiro { 273605302a5SGregory Neil Shapiro /* XXX result == 0? */ 27440266059SGregory Neil Shapiro ret = sm_io_write(so->fp, SM_TIME_DEFAULT, 27540266059SGregory Neil Shapiro &outbuf[total], outlen); 27640266059SGregory Neil Shapiro outlen -= ret; 27740266059SGregory Neil Shapiro total += ret; 27840266059SGregory Neil Shapiro } 279193538b7SGregory Neil Shapiro SASL_DEALLOC(outbuf); 28006f25ae9SGregory Neil Shapiro } 28106f25ae9SGregory Neil Shapiro return size; 28206f25ae9SGregory Neil Shapiro } 28306f25ae9SGregory Neil Shapiro 28440266059SGregory Neil Shapiro /* 28540266059SGregory Neil Shapiro ** SFDCSASL -- create sasl file type and open in and out file pointers 28640266059SGregory Neil Shapiro ** for sendmail to read from and write to. 28740266059SGregory Neil Shapiro ** 28840266059SGregory Neil Shapiro ** Parameters: 28940266059SGregory Neil Shapiro ** fin -- the sm_io file encrypted data to be read from 29040266059SGregory Neil Shapiro ** fout -- the sm_io file encrypted data to be writen to 29140266059SGregory Neil Shapiro ** conn -- the sasl connection pointer 29240266059SGregory Neil Shapiro ** 29340266059SGregory Neil Shapiro ** Returns: 29440266059SGregory Neil Shapiro ** -1 on error 29540266059SGregory Neil Shapiro ** 0 on success 29640266059SGregory Neil Shapiro ** 29740266059SGregory Neil Shapiro ** Side effects: 29840266059SGregory Neil Shapiro ** The arguments "fin" and "fout" are replaced with the new 29940266059SGregory Neil Shapiro ** SM_FILE_T pointers. 30040266059SGregory Neil Shapiro */ 30140266059SGregory Neil Shapiro 30206f25ae9SGregory Neil Shapiro int 30306f25ae9SGregory Neil Shapiro sfdcsasl(fin, fout, conn) 30440266059SGregory Neil Shapiro SM_FILE_T **fin; 30540266059SGregory Neil Shapiro SM_FILE_T **fout; 30606f25ae9SGregory Neil Shapiro sasl_conn_t *conn; 30706f25ae9SGregory Neil Shapiro { 30840266059SGregory Neil Shapiro SM_FILE_T *newin, *newout; 30940266059SGregory Neil Shapiro SM_FILE_T SM_IO_SET_TYPE(sasl_vector, "sasl", sasl_open, sasl_close, 31040266059SGregory Neil Shapiro sasl_read, sasl_write, NULL, sasl_getinfo, NULL, 31140266059SGregory Neil Shapiro SM_TIME_FOREVER); 31240266059SGregory Neil Shapiro struct sasl_info info; 31306f25ae9SGregory Neil Shapiro 31406f25ae9SGregory Neil Shapiro if (conn == NULL) 31506f25ae9SGregory Neil Shapiro { 31606f25ae9SGregory Neil Shapiro /* no need to do anything */ 31706f25ae9SGregory Neil Shapiro return 0; 31806f25ae9SGregory Neil Shapiro } 31906f25ae9SGregory Neil Shapiro 32040266059SGregory Neil Shapiro SM_IO_INIT_TYPE(sasl_vector, "sasl", sasl_open, sasl_close, 32140266059SGregory Neil Shapiro sasl_read, sasl_write, NULL, sasl_getinfo, NULL, 32240266059SGregory Neil Shapiro SM_TIME_FOREVER); 32340266059SGregory Neil Shapiro info.fp = *fin; 32440266059SGregory Neil Shapiro info.conn = conn; 32540266059SGregory Neil Shapiro newin = sm_io_open(&sasl_vector, SM_TIME_DEFAULT, &info, SM_IO_RDONLY, 32640266059SGregory Neil Shapiro NULL); 32706f25ae9SGregory Neil Shapiro 32840266059SGregory Neil Shapiro if (newin == NULL) 32940266059SGregory Neil Shapiro return -1; 33006f25ae9SGregory Neil Shapiro 33140266059SGregory Neil Shapiro info.fp = *fout; 33240266059SGregory Neil Shapiro info.conn = conn; 33340266059SGregory Neil Shapiro newout = sm_io_open(&sasl_vector, SM_TIME_DEFAULT, &info, SM_IO_WRONLY, 33440266059SGregory Neil Shapiro NULL); 33506f25ae9SGregory Neil Shapiro 33640266059SGregory Neil Shapiro if (newout == NULL) 33706f25ae9SGregory Neil Shapiro { 33840266059SGregory Neil Shapiro (void) sm_io_close(newin, SM_TIME_DEFAULT); 33906f25ae9SGregory Neil Shapiro return -1; 34006f25ae9SGregory Neil Shapiro } 34140266059SGregory Neil Shapiro sm_io_automode(newin, newout); 34240266059SGregory Neil Shapiro 34340266059SGregory Neil Shapiro *fin = newin; 34440266059SGregory Neil Shapiro *fout = newout; 34506f25ae9SGregory Neil Shapiro return 0; 34606f25ae9SGregory Neil Shapiro } 34740266059SGregory Neil Shapiro #endif /* SASL */ 34806f25ae9SGregory Neil Shapiro 34940266059SGregory Neil Shapiro #if STARTTLS 35006f25ae9SGregory Neil Shapiro # include "sfsasl.h" 35106f25ae9SGregory Neil Shapiro # include <openssl/err.h> 35206f25ae9SGregory Neil Shapiro 35340266059SGregory Neil Shapiro /* Structure used by the "tls" file type */ 35440266059SGregory Neil Shapiro struct tls_obj 35540266059SGregory Neil Shapiro { 35640266059SGregory Neil Shapiro SM_FILE_T *fp; 35740266059SGregory Neil Shapiro SSL *con; 35840266059SGregory Neil Shapiro }; 35940266059SGregory Neil Shapiro 36040266059SGregory Neil Shapiro struct tls_info 36140266059SGregory Neil Shapiro { 36240266059SGregory Neil Shapiro SM_FILE_T *fp; 36340266059SGregory Neil Shapiro SSL *con; 36440266059SGregory Neil Shapiro }; 36540266059SGregory Neil Shapiro 36640266059SGregory Neil Shapiro /* 36740266059SGregory Neil Shapiro ** TLS_GETINFO - returns requested information about a "tls" file 36840266059SGregory Neil Shapiro ** descriptor. 36940266059SGregory Neil Shapiro ** 37040266059SGregory Neil Shapiro ** Parameters: 37140266059SGregory Neil Shapiro ** fp -- the file descriptor 37240266059SGregory Neil Shapiro ** what -- the type of information requested 37340266059SGregory Neil Shapiro ** valp -- the thang to return the information in (unused) 37440266059SGregory Neil Shapiro ** 37540266059SGregory Neil Shapiro ** Returns: 37640266059SGregory Neil Shapiro ** -1 for unknown requests 37740266059SGregory Neil Shapiro ** >=0 on success with valp filled in (if possible). 37840266059SGregory Neil Shapiro */ 37940266059SGregory Neil Shapiro 38040266059SGregory Neil Shapiro static int tls_getinfo __P((SM_FILE_T *, int, void *)); 38140266059SGregory Neil Shapiro 38240266059SGregory Neil Shapiro /* ARGSUSED2 */ 38313058a91SGregory Neil Shapiro static int 38440266059SGregory Neil Shapiro tls_getinfo(fp, what, valp) 38540266059SGregory Neil Shapiro SM_FILE_T *fp; 38640266059SGregory Neil Shapiro int what; 38740266059SGregory Neil Shapiro void *valp; 38840266059SGregory Neil Shapiro { 38940266059SGregory Neil Shapiro struct tls_obj *so = (struct tls_obj *) fp->f_cookie; 39040266059SGregory Neil Shapiro 39140266059SGregory Neil Shapiro switch (what) 39240266059SGregory Neil Shapiro { 39340266059SGregory Neil Shapiro case SM_IO_WHAT_FD: 39440266059SGregory Neil Shapiro if (so->fp == NULL) 39540266059SGregory Neil Shapiro return -1; 39640266059SGregory Neil Shapiro return so->fp->f_file; /* for stdio fileno() compatability */ 39740266059SGregory Neil Shapiro 39840266059SGregory Neil Shapiro case SM_IO_IS_READABLE: 39940266059SGregory Neil Shapiro return SSL_pending(so->con) > 0; 40040266059SGregory Neil Shapiro 40140266059SGregory Neil Shapiro default: 40240266059SGregory Neil Shapiro return -1; 40340266059SGregory Neil Shapiro } 40440266059SGregory Neil Shapiro } 40540266059SGregory Neil Shapiro 40640266059SGregory Neil Shapiro /* 40740266059SGregory Neil Shapiro ** TLS_OPEN -- creates the tls specific information for opening a 40840266059SGregory Neil Shapiro ** file of the tls type. 40940266059SGregory Neil Shapiro ** 41040266059SGregory Neil Shapiro ** Parameters: 41140266059SGregory Neil Shapiro ** fp -- the file pointer associated with the new open 41240266059SGregory Neil Shapiro ** info -- the sm_io file pointer holding the open and the 41340266059SGregory Neil Shapiro ** TLS encryption connection to be read from or written to 41440266059SGregory Neil Shapiro ** flags -- ignored 41540266059SGregory Neil Shapiro ** rpool -- ignored 41640266059SGregory Neil Shapiro ** 41740266059SGregory Neil Shapiro ** Returns: 41840266059SGregory Neil Shapiro ** 0 on success 41940266059SGregory Neil Shapiro */ 42040266059SGregory Neil Shapiro 42140266059SGregory Neil Shapiro static int tls_open __P((SM_FILE_T *, const void *, int, const void *)); 42240266059SGregory Neil Shapiro 42340266059SGregory Neil Shapiro /* ARGSUSED2 */ 42440266059SGregory Neil Shapiro static int 42540266059SGregory Neil Shapiro tls_open(fp, info, flags, rpool) 42640266059SGregory Neil Shapiro SM_FILE_T *fp; 42740266059SGregory Neil Shapiro const void *info; 42840266059SGregory Neil Shapiro int flags; 42940266059SGregory Neil Shapiro const void *rpool; 43040266059SGregory Neil Shapiro { 43140266059SGregory Neil Shapiro struct tls_obj *so; 43240266059SGregory Neil Shapiro struct tls_info *ti = (struct tls_info *) info; 43340266059SGregory Neil Shapiro 43440266059SGregory Neil Shapiro so = (struct tls_obj *) sm_malloc(sizeof(struct tls_obj)); 43540266059SGregory Neil Shapiro so->fp = ti->fp; 43640266059SGregory Neil Shapiro so->con = ti->con; 43740266059SGregory Neil Shapiro 43840266059SGregory Neil Shapiro /* 43940266059SGregory Neil Shapiro ** We try to get the "raw" file descriptor that TLS uses to 44040266059SGregory Neil Shapiro ** do the actual read/write with. This is to allow us control 44140266059SGregory Neil Shapiro ** over the file descriptor being a blocking or non-blocking type. 44240266059SGregory Neil Shapiro ** Under the covers TLS handles the change and this allows us 44340266059SGregory Neil Shapiro ** to do timeouts with sm_io. 44440266059SGregory Neil Shapiro */ 44540266059SGregory Neil Shapiro 44640266059SGregory Neil Shapiro fp->f_file = sm_io_getinfo(so->fp, SM_IO_WHAT_FD, NULL); 44740266059SGregory Neil Shapiro (void) sm_io_setvbuf(so->fp, SM_TIME_DEFAULT, NULL, SM_IO_NOW, 0); 44840266059SGregory Neil Shapiro fp->f_cookie = so; 44940266059SGregory Neil Shapiro return 0; 45040266059SGregory Neil Shapiro } 45140266059SGregory Neil Shapiro 45240266059SGregory Neil Shapiro /* 45340266059SGregory Neil Shapiro ** TLS_CLOSE -- close the tls specific parts of the tls file pointer 45440266059SGregory Neil Shapiro ** 45540266059SGregory Neil Shapiro ** Parameters: 45640266059SGregory Neil Shapiro ** fp -- the file pointer to close 45740266059SGregory Neil Shapiro ** 45840266059SGregory Neil Shapiro ** Returns: 45940266059SGregory Neil Shapiro ** 0 on success 46040266059SGregory Neil Shapiro */ 46140266059SGregory Neil Shapiro 46240266059SGregory Neil Shapiro static int tls_close __P((SM_FILE_T *)); 46340266059SGregory Neil Shapiro 46440266059SGregory Neil Shapiro static int 46540266059SGregory Neil Shapiro tls_close(fp) 46640266059SGregory Neil Shapiro SM_FILE_T *fp; 46740266059SGregory Neil Shapiro { 46840266059SGregory Neil Shapiro struct tls_obj *so; 46940266059SGregory Neil Shapiro 47040266059SGregory Neil Shapiro so = (struct tls_obj *) fp->f_cookie; 47140266059SGregory Neil Shapiro if (so->fp != NULL) 47240266059SGregory Neil Shapiro { 47340266059SGregory Neil Shapiro sm_io_close(so->fp, SM_TIME_DEFAULT); 47440266059SGregory Neil Shapiro so->fp = NULL; 47540266059SGregory Neil Shapiro } 47640266059SGregory Neil Shapiro sm_free(so); 47740266059SGregory Neil Shapiro so = NULL; 47840266059SGregory Neil Shapiro return 0; 47940266059SGregory Neil Shapiro } 48040266059SGregory Neil Shapiro 48140266059SGregory Neil Shapiro /* maximum number of retries for TLS related I/O due to handshakes */ 48240266059SGregory Neil Shapiro # define MAX_TLS_IOS 4 48340266059SGregory Neil Shapiro 48440266059SGregory Neil Shapiro /* 48540266059SGregory Neil Shapiro ** TLS_READ -- read secured information for the caller 48640266059SGregory Neil Shapiro ** 48740266059SGregory Neil Shapiro ** Parameters: 48840266059SGregory Neil Shapiro ** fp -- the file pointer 48940266059SGregory Neil Shapiro ** buf -- the location to place the data 49040266059SGregory Neil Shapiro ** size -- the number of bytes to read from connection 49140266059SGregory Neil Shapiro ** 49240266059SGregory Neil Shapiro ** Results: 49340266059SGregory Neil Shapiro ** -1 on error 49440266059SGregory Neil Shapiro ** otherwise the number of bytes read 49540266059SGregory Neil Shapiro */ 49640266059SGregory Neil Shapiro 49740266059SGregory Neil Shapiro static ssize_t tls_read __P((SM_FILE_T *, char *, size_t)); 49840266059SGregory Neil Shapiro 49940266059SGregory Neil Shapiro static ssize_t 50040266059SGregory Neil Shapiro tls_read(fp, buf, size) 50140266059SGregory Neil Shapiro SM_FILE_T *fp; 50213058a91SGregory Neil Shapiro char *buf; 50340266059SGregory Neil Shapiro size_t size; 50406f25ae9SGregory Neil Shapiro { 50506f25ae9SGregory Neil Shapiro int r; 50640266059SGregory Neil Shapiro static int again = MAX_TLS_IOS; 50740266059SGregory Neil Shapiro struct tls_obj *so = (struct tls_obj *) fp->f_cookie; 50806f25ae9SGregory Neil Shapiro char *err; 50906f25ae9SGregory Neil Shapiro 51040266059SGregory Neil Shapiro r = SSL_read(so->con, (char *) buf, size); 51140266059SGregory Neil Shapiro 51240266059SGregory Neil Shapiro if (r > 0) 51340266059SGregory Neil Shapiro { 51440266059SGregory Neil Shapiro again = MAX_TLS_IOS; 51540266059SGregory Neil Shapiro return r; 51640266059SGregory Neil Shapiro } 51740266059SGregory Neil Shapiro 51806f25ae9SGregory Neil Shapiro err = NULL; 51940266059SGregory Neil Shapiro switch (SSL_get_error(so->con, r)) 52006f25ae9SGregory Neil Shapiro { 52106f25ae9SGregory Neil Shapiro case SSL_ERROR_NONE: 52240266059SGregory Neil Shapiro case SSL_ERROR_ZERO_RETURN: 52340266059SGregory Neil Shapiro again = MAX_TLS_IOS; 52406f25ae9SGregory Neil Shapiro break; 52506f25ae9SGregory Neil Shapiro case SSL_ERROR_WANT_WRITE: 52640266059SGregory Neil Shapiro if (--again <= 0) 52740266059SGregory Neil Shapiro err = "read W BLOCK"; 52840266059SGregory Neil Shapiro else 52940266059SGregory Neil Shapiro errno = EAGAIN; 53006f25ae9SGregory Neil Shapiro break; 53106f25ae9SGregory Neil Shapiro case SSL_ERROR_WANT_READ: 53240266059SGregory Neil Shapiro if (--again <= 0) 53340266059SGregory Neil Shapiro err = "read R BLOCK"; 53440266059SGregory Neil Shapiro else 53540266059SGregory Neil Shapiro errno = EAGAIN; 53606f25ae9SGregory Neil Shapiro break; 53706f25ae9SGregory Neil Shapiro case SSL_ERROR_WANT_X509_LOOKUP: 53806f25ae9SGregory Neil Shapiro err = "write X BLOCK"; 53906f25ae9SGregory Neil Shapiro break; 54006f25ae9SGregory Neil Shapiro case SSL_ERROR_SYSCALL: 54140266059SGregory Neil Shapiro if (r == 0 && errno == 0) /* out of protocol EOF found */ 54240266059SGregory Neil Shapiro break; 54306f25ae9SGregory Neil Shapiro err = "syscall error"; 54406f25ae9SGregory Neil Shapiro /* 54506f25ae9SGregory Neil Shapiro get_last_socket_error()); 54606f25ae9SGregory Neil Shapiro */ 54706f25ae9SGregory Neil Shapiro break; 54806f25ae9SGregory Neil Shapiro case SSL_ERROR_SSL: 54906f25ae9SGregory Neil Shapiro err = "generic SSL error"; 55040266059SGregory Neil Shapiro if (LogLevel > 9) 55140266059SGregory Neil Shapiro tlslogerr("read"); 55206f25ae9SGregory Neil Shapiro break; 55306f25ae9SGregory Neil Shapiro } 55406f25ae9SGregory Neil Shapiro if (err != NULL) 55540266059SGregory Neil Shapiro { 556605302a5SGregory Neil Shapiro int save_errno; 557605302a5SGregory Neil Shapiro 558605302a5SGregory Neil Shapiro save_errno = (errno == 0) ? EIO : errno; 55940266059SGregory Neil Shapiro again = MAX_TLS_IOS; 56040266059SGregory Neil Shapiro if (LogLevel > 7) 56140266059SGregory Neil Shapiro sm_syslog(LOG_WARNING, NOQID, 56240266059SGregory Neil Shapiro "STARTTLS: read error=%s (%d)", err, r); 563605302a5SGregory Neil Shapiro errno = save_errno; 56406f25ae9SGregory Neil Shapiro } 56506f25ae9SGregory Neil Shapiro return r; 56606f25ae9SGregory Neil Shapiro } 56706f25ae9SGregory Neil Shapiro 56840266059SGregory Neil Shapiro /* 56940266059SGregory Neil Shapiro ** TLS_WRITE -- write information out through secure connection 57040266059SGregory Neil Shapiro ** 57140266059SGregory Neil Shapiro ** Parameters: 57240266059SGregory Neil Shapiro ** fp -- the file pointer 57340266059SGregory Neil Shapiro ** buf -- holds the data to be securely written 57440266059SGregory Neil Shapiro ** size -- the number of bytes to write 57540266059SGregory Neil Shapiro ** 57640266059SGregory Neil Shapiro ** Returns: 57740266059SGregory Neil Shapiro ** -1 on error 57840266059SGregory Neil Shapiro ** otherwise number of bytes written 57940266059SGregory Neil Shapiro */ 58040266059SGregory Neil Shapiro 58140266059SGregory Neil Shapiro static ssize_t tls_write __P((SM_FILE_T *, const char *, size_t)); 58240266059SGregory Neil Shapiro 58313058a91SGregory Neil Shapiro static ssize_t 58440266059SGregory Neil Shapiro tls_write(fp, buf, size) 58540266059SGregory Neil Shapiro SM_FILE_T *fp; 58613058a91SGregory Neil Shapiro const char *buf; 58740266059SGregory Neil Shapiro size_t size; 58806f25ae9SGregory Neil Shapiro { 58906f25ae9SGregory Neil Shapiro int r; 59040266059SGregory Neil Shapiro static int again = MAX_TLS_IOS; 59140266059SGregory Neil Shapiro struct tls_obj *so = (struct tls_obj *) fp->f_cookie; 59206f25ae9SGregory Neil Shapiro char *err; 59306f25ae9SGregory Neil Shapiro 59440266059SGregory Neil Shapiro r = SSL_write(so->con, (char *) buf, size); 59540266059SGregory Neil Shapiro 59640266059SGregory Neil Shapiro if (r > 0) 59740266059SGregory Neil Shapiro { 59840266059SGregory Neil Shapiro again = MAX_TLS_IOS; 59940266059SGregory Neil Shapiro return r; 60040266059SGregory Neil Shapiro } 60106f25ae9SGregory Neil Shapiro err = NULL; 60240266059SGregory Neil Shapiro switch (SSL_get_error(so->con, r)) 60306f25ae9SGregory Neil Shapiro { 60406f25ae9SGregory Neil Shapiro case SSL_ERROR_NONE: 60540266059SGregory Neil Shapiro case SSL_ERROR_ZERO_RETURN: 60640266059SGregory Neil Shapiro again = MAX_TLS_IOS; 60706f25ae9SGregory Neil Shapiro break; 60806f25ae9SGregory Neil Shapiro case SSL_ERROR_WANT_WRITE: 60940266059SGregory Neil Shapiro if (--again <= 0) 61006f25ae9SGregory Neil Shapiro err = "write W BLOCK"; 61140266059SGregory Neil Shapiro else 61240266059SGregory Neil Shapiro errno = EAGAIN; 61306f25ae9SGregory Neil Shapiro break; 61406f25ae9SGregory Neil Shapiro case SSL_ERROR_WANT_READ: 61540266059SGregory Neil Shapiro if (--again <= 0) 61606f25ae9SGregory Neil Shapiro err = "write R BLOCK"; 61740266059SGregory Neil Shapiro else 61840266059SGregory Neil Shapiro errno = EAGAIN; 61906f25ae9SGregory Neil Shapiro break; 62006f25ae9SGregory Neil Shapiro case SSL_ERROR_WANT_X509_LOOKUP: 62106f25ae9SGregory Neil Shapiro err = "write X BLOCK"; 62206f25ae9SGregory Neil Shapiro break; 62306f25ae9SGregory Neil Shapiro case SSL_ERROR_SYSCALL: 62440266059SGregory Neil Shapiro if (r == 0 && errno == 0) /* out of protocol EOF found */ 62540266059SGregory Neil Shapiro break; 62606f25ae9SGregory Neil Shapiro err = "syscall error"; 62706f25ae9SGregory Neil Shapiro /* 62806f25ae9SGregory Neil Shapiro get_last_socket_error()); 62906f25ae9SGregory Neil Shapiro */ 63006f25ae9SGregory Neil Shapiro break; 63106f25ae9SGregory Neil Shapiro case SSL_ERROR_SSL: 63206f25ae9SGregory Neil Shapiro err = "generic SSL error"; 63306f25ae9SGregory Neil Shapiro /* 63406f25ae9SGregory Neil Shapiro ERR_GET_REASON(ERR_peek_error())); 63506f25ae9SGregory Neil Shapiro */ 63640266059SGregory Neil Shapiro if (LogLevel > 9) 63740266059SGregory Neil Shapiro tlslogerr("write"); 63806f25ae9SGregory Neil Shapiro break; 63906f25ae9SGregory Neil Shapiro } 64006f25ae9SGregory Neil Shapiro if (err != NULL) 64140266059SGregory Neil Shapiro { 642605302a5SGregory Neil Shapiro int save_errno; 643605302a5SGregory Neil Shapiro 644605302a5SGregory Neil Shapiro save_errno = (errno == 0) ? EIO : errno; 64540266059SGregory Neil Shapiro again = MAX_TLS_IOS; 64640266059SGregory Neil Shapiro if (LogLevel > 7) 64740266059SGregory Neil Shapiro sm_syslog(LOG_WARNING, NOQID, 64840266059SGregory Neil Shapiro "STARTTLS: write error=%s (%d)", err, r); 649605302a5SGregory Neil Shapiro errno = save_errno; 65006f25ae9SGregory Neil Shapiro } 65106f25ae9SGregory Neil Shapiro return r; 65206f25ae9SGregory Neil Shapiro } 65306f25ae9SGregory Neil Shapiro 65440266059SGregory Neil Shapiro /* 65540266059SGregory Neil Shapiro ** SFDCTLS -- create tls file type and open in and out file pointers 65640266059SGregory Neil Shapiro ** for sendmail to read from and write to. 65740266059SGregory Neil Shapiro ** 65840266059SGregory Neil Shapiro ** Parameters: 65940266059SGregory Neil Shapiro ** fin -- data input source being replaced 66040266059SGregory Neil Shapiro ** fout -- data output source being replaced 66140266059SGregory Neil Shapiro ** conn -- the tls connection pointer 66240266059SGregory Neil Shapiro ** 66340266059SGregory Neil Shapiro ** Returns: 66440266059SGregory Neil Shapiro ** -1 on error 66540266059SGregory Neil Shapiro ** 0 on success 66640266059SGregory Neil Shapiro ** 66740266059SGregory Neil Shapiro ** Side effects: 66840266059SGregory Neil Shapiro ** The arguments "fin" and "fout" are replaced with the new 66940266059SGregory Neil Shapiro ** SM_FILE_T pointers. 67040266059SGregory Neil Shapiro ** The original "fin" and "fout" are preserved in the tls file 67140266059SGregory Neil Shapiro ** type but are not actually used because of the design of TLS. 67240266059SGregory Neil Shapiro */ 67306f25ae9SGregory Neil Shapiro 67406f25ae9SGregory Neil Shapiro int 67506f25ae9SGregory Neil Shapiro sfdctls(fin, fout, con) 67640266059SGregory Neil Shapiro SM_FILE_T **fin; 67740266059SGregory Neil Shapiro SM_FILE_T **fout; 67806f25ae9SGregory Neil Shapiro SSL *con; 67906f25ae9SGregory Neil Shapiro { 68040266059SGregory Neil Shapiro SM_FILE_T *tlsin, *tlsout; 68140266059SGregory Neil Shapiro SM_FILE_T SM_IO_SET_TYPE(tls_vector, "tls", tls_open, tls_close, 68240266059SGregory Neil Shapiro tls_read, tls_write, NULL, tls_getinfo, NULL, 68340266059SGregory Neil Shapiro SM_TIME_FOREVER); 68440266059SGregory Neil Shapiro struct tls_info info; 68506f25ae9SGregory Neil Shapiro 68640266059SGregory Neil Shapiro SM_ASSERT(con != NULL); 68706f25ae9SGregory Neil Shapiro 68840266059SGregory Neil Shapiro SM_IO_INIT_TYPE(tls_vector, "tls", tls_open, tls_close, 68940266059SGregory Neil Shapiro tls_read, tls_write, NULL, tls_getinfo, NULL, 69040266059SGregory Neil Shapiro SM_TIME_FOREVER); 69140266059SGregory Neil Shapiro info.fp = *fin; 69240266059SGregory Neil Shapiro info.con = con; 69340266059SGregory Neil Shapiro tlsin = sm_io_open(&tls_vector, SM_TIME_DEFAULT, &info, SM_IO_RDONLY, 69440266059SGregory Neil Shapiro NULL); 69540266059SGregory Neil Shapiro if (tlsin == NULL) 69640266059SGregory Neil Shapiro return -1; 69706f25ae9SGregory Neil Shapiro 69840266059SGregory Neil Shapiro info.fp = *fout; 69940266059SGregory Neil Shapiro tlsout = sm_io_open(&tls_vector, SM_TIME_DEFAULT, &info, SM_IO_WRONLY, 70040266059SGregory Neil Shapiro NULL); 70140266059SGregory Neil Shapiro if (tlsout == NULL) 70242e5d165SGregory Neil Shapiro { 70340266059SGregory Neil Shapiro (void) sm_io_close(tlsin, SM_TIME_DEFAULT); 70442e5d165SGregory Neil Shapiro return -1; 70542e5d165SGregory Neil Shapiro } 70640266059SGregory Neil Shapiro sm_io_automode(tlsin, tlsout); 70706f25ae9SGregory Neil Shapiro 70840266059SGregory Neil Shapiro *fin = tlsin; 70940266059SGregory Neil Shapiro *fout = tlsout; 71006f25ae9SGregory Neil Shapiro return 0; 71106f25ae9SGregory Neil Shapiro } 71240266059SGregory Neil Shapiro #endif /* STARTTLS */ 713