sfsasl.c revision 90792
164562Sgshapiro/* 277349Sgshapiro * Copyright (c) 1999-2001 Sendmail, Inc. and its suppliers. 364562Sgshapiro * All rights reserved. 464562Sgshapiro * 564562Sgshapiro * By using this file, you agree to the terms and conditions set 664562Sgshapiro * forth in the LICENSE file which can be found at the top level of 764562Sgshapiro * the sendmail distribution. 864562Sgshapiro * 964562Sgshapiro */ 1064562Sgshapiro 1190792Sgshapiro#include <sm/gen.h> 1290792SgshapiroSM_RCSID("@(#)$Id: sfsasl.c,v 8.86 2001/09/11 04:05:16 gshapiro Exp $") 1364562Sgshapiro#include <stdlib.h> 1464562Sgshapiro#include <sendmail.h> 1590792Sgshapiro#include <errno.h> 1690792Sgshapiro#if SASL 1790792Sgshapiro# include <sasl.h> 1890792Sgshapiro# include "sfsasl.h" 1964562Sgshapiro 2090792Sgshapiro/* Structure used by the "sasl" file type */ 2190792Sgshapirostruct sasl_obj 2290792Sgshapiro{ 2390792Sgshapiro SM_FILE_T *fp; 2490792Sgshapiro sasl_conn_t *conn; 2590792Sgshapiro}; 2690792Sgshapiro 2790792Sgshapirostruct sasl_info 2890792Sgshapiro{ 2990792Sgshapiro SM_FILE_T *fp; 3090792Sgshapiro sasl_conn_t *conn; 3190792Sgshapiro}; 3290792Sgshapiro 3364562Sgshapiro/* 3490792Sgshapiro** SASL_GETINFO - returns requested information about a "sasl" file 3590792Sgshapiro** descriptor. 3690792Sgshapiro** 3790792Sgshapiro** Parameters: 3890792Sgshapiro** fp -- the file descriptor 3990792Sgshapiro** what -- the type of information requested 4090792Sgshapiro** valp -- the thang to return the information in 4190792Sgshapiro** 4290792Sgshapiro** Returns: 4390792Sgshapiro** -1 for unknown requests 4490792Sgshapiro** >=0 on success with valp filled in (if possible). 4564562Sgshapiro*/ 4664562Sgshapiro 4790792Sgshapirostatic int sasl_getinfo __P((SM_FILE_T *, int, void *)); 4864562Sgshapiro 4990792Sgshapirostatic int 5090792Sgshapirosasl_getinfo(fp, what, valp) 5190792Sgshapiro SM_FILE_T *fp; 5290792Sgshapiro int what; 5390792Sgshapiro void *valp; 5490792Sgshapiro{ 5590792Sgshapiro struct sasl_obj *so = (struct sasl_obj *) fp->f_cookie; 5690792Sgshapiro 5790792Sgshapiro switch (what) 5890792Sgshapiro { 5990792Sgshapiro case SM_IO_WHAT_FD: 6090792Sgshapiro if (so->fp == NULL) 6190792Sgshapiro return -1; 6290792Sgshapiro return so->fp->f_file; /* for stdio fileno() compatability */ 6390792Sgshapiro 6490792Sgshapiro case SM_IO_IS_READABLE: 6590792Sgshapiro if (so->fp == NULL) 6690792Sgshapiro return 0; 6790792Sgshapiro 6890792Sgshapiro /* get info from underlying file */ 6990792Sgshapiro return sm_io_getinfo(so->fp, what, valp); 7090792Sgshapiro 7190792Sgshapiro default: 7290792Sgshapiro return -1; 7390792Sgshapiro } 7490792Sgshapiro} 7590792Sgshapiro 7690792Sgshapiro/* 7790792Sgshapiro** SASL_OPEN -- creates the sasl specific information for opening a 7890792Sgshapiro** file of the sasl type. 7990792Sgshapiro** 8090792Sgshapiro** Parameters: 8190792Sgshapiro** fp -- the file pointer associated with the new open 8290792Sgshapiro** info -- contains the sasl connection information pointer and 8390792Sgshapiro** the original SM_FILE_T that holds the open 8490792Sgshapiro** flags -- ignored 8590792Sgshapiro** rpool -- ignored 8690792Sgshapiro** 8790792Sgshapiro** Returns: 8890792Sgshapiro** 0 on success 8990792Sgshapiro*/ 9090792Sgshapiro 9190792Sgshapirostatic int sasl_open __P((SM_FILE_T *, const void *, int, const void *)); 9290792Sgshapiro 9390792Sgshapiro/* ARGSUSED2 */ 9490792Sgshapirostatic int 9590792Sgshapirosasl_open(fp, info, flags, rpool) 9690792Sgshapiro SM_FILE_T *fp; 9790792Sgshapiro const void *info; 9890792Sgshapiro int flags; 9990792Sgshapiro const void *rpool; 10090792Sgshapiro{ 10190792Sgshapiro struct sasl_obj *so; 10290792Sgshapiro struct sasl_info *si = (struct sasl_info *) info; 10390792Sgshapiro 10490792Sgshapiro so = (struct sasl_obj *) sm_malloc(sizeof(struct sasl_obj)); 10590792Sgshapiro so->fp = si->fp; 10690792Sgshapiro so->conn = si->conn; 10790792Sgshapiro 10890792Sgshapiro /* 10990792Sgshapiro ** The underlying 'fp' is set to SM_IO_NOW so that the entire 11090792Sgshapiro ** encoded string is written in one chunk. Otherwise there is 11190792Sgshapiro ** the possibility that it may appear illegal, bogus or 11290792Sgshapiro ** mangled to the other side of the connection. 11390792Sgshapiro ** We will read or write through 'fp' since it is the opaque 11490792Sgshapiro ** connection for the communications. We need to treat it this 11590792Sgshapiro ** way in case the encoded string is to be sent down a TLS 11690792Sgshapiro ** connection rather than, say, sm_io's stdio. 11790792Sgshapiro */ 11890792Sgshapiro 11990792Sgshapiro (void) sm_io_setvbuf(so->fp, SM_TIME_DEFAULT, NULL, SM_IO_NOW, 0); 12090792Sgshapiro fp->f_cookie = so; 12190792Sgshapiro return 0; 12290792Sgshapiro} 12390792Sgshapiro 12490792Sgshapiro/* 12590792Sgshapiro** SASL_CLOSE -- close the sasl specific parts of the sasl file pointer 12690792Sgshapiro** 12790792Sgshapiro** Parameters: 12890792Sgshapiro** fp -- the file pointer to close 12990792Sgshapiro** 13090792Sgshapiro** Returns: 13190792Sgshapiro** 0 on success 13290792Sgshapiro*/ 13390792Sgshapiro 13490792Sgshapirostatic int sasl_close __P((SM_FILE_T *)); 13590792Sgshapiro 13690792Sgshapirostatic int 13790792Sgshapirosasl_close(fp) 13890792Sgshapiro SM_FILE_T *fp; 13990792Sgshapiro{ 14090792Sgshapiro struct sasl_obj *so; 14190792Sgshapiro 14290792Sgshapiro so = (struct sasl_obj *) fp->f_cookie; 14390792Sgshapiro if (so->fp != NULL) 14490792Sgshapiro { 14590792Sgshapiro sm_io_close(so->fp, SM_TIME_DEFAULT); 14690792Sgshapiro so->fp = NULL; 14790792Sgshapiro } 14890792Sgshapiro sm_free(so); 14990792Sgshapiro so = NULL; 15090792Sgshapiro return 0; 15190792Sgshapiro} 15290792Sgshapiro 15371345Sgshapiro/* how to deallocate a buffer allocated by SASL */ 15490792Sgshapiroextern void sm_sasl_free __P((void *)); 15590792Sgshapiro# define SASL_DEALLOC(b) sm_sasl_free(b) 15671345Sgshapiro 15790792Sgshapiro/* 15890792Sgshapiro** SASL_READ -- read encrypted information and decrypt it for the caller 15990792Sgshapiro** 16090792Sgshapiro** Parameters: 16190792Sgshapiro** fp -- the file pointer 16290792Sgshapiro** buf -- the location to place the decrypted information 16390792Sgshapiro** size -- the number of bytes to read after decryption 16490792Sgshapiro** 16590792Sgshapiro** Results: 16690792Sgshapiro** -1 on error 16790792Sgshapiro** otherwise the number of bytes read 16890792Sgshapiro*/ 16990792Sgshapiro 17090792Sgshapirostatic ssize_t sasl_read __P((SM_FILE_T *, char *, size_t)); 17190792Sgshapiro 17264562Sgshapirostatic ssize_t 17390792Sgshapirosasl_read(fp, buf, size) 17490792Sgshapiro SM_FILE_T *fp; 17590792Sgshapiro char *buf; 17664562Sgshapiro size_t size; 17764562Sgshapiro{ 17890792Sgshapiro int result; 17990792Sgshapiro ssize_t len; 18071345Sgshapiro static char *outbuf = NULL; 18171345Sgshapiro static unsigned int outlen = 0; 18271345Sgshapiro static unsigned int offset = 0; 18390792Sgshapiro struct sasl_obj *so = (struct sasl_obj *) fp->f_cookie; 18464562Sgshapiro 18571345Sgshapiro /* 18671345Sgshapiro ** sasl_decode() may require more data than a single read() returns. 18771345Sgshapiro ** Hence we have to put a loop around the decoding. 18871345Sgshapiro ** This also requires that we may have to split up the returned 18971345Sgshapiro ** data since it might be larger than the allowed size. 19071345Sgshapiro ** Therefore we use a static pointer and return portions of it 19171345Sgshapiro ** if necessary. 19271345Sgshapiro */ 19364562Sgshapiro 19471345Sgshapiro while (outbuf == NULL && outlen == 0) 19564562Sgshapiro { 19690792Sgshapiro len = sm_io_read(so->fp, SM_TIME_DEFAULT, buf, size); 19771345Sgshapiro if (len <= 0) 19871345Sgshapiro return len; 19990792Sgshapiro result = sasl_decode(so->conn, buf, 20090792Sgshapiro (unsigned int) len, &outbuf, &outlen); 20171345Sgshapiro if (result != SASL_OK) 20271345Sgshapiro { 20371345Sgshapiro outbuf = NULL; 20471345Sgshapiro offset = 0; 20571345Sgshapiro outlen = 0; 20671345Sgshapiro return -1; 20771345Sgshapiro } 20864562Sgshapiro } 20964562Sgshapiro 21090792Sgshapiro if (outbuf == NULL) 21164562Sgshapiro { 21290792Sgshapiro /* be paranoid: outbuf == NULL but outlen != 0 */ 21390792Sgshapiro syserr("@sasl_read failure: outbuf == NULL but outlen != 0"); 21490792Sgshapiro /* NOTREACHED */ 21564562Sgshapiro } 21690792Sgshapiro if (outlen - offset > size) 21790792Sgshapiro { 21890792Sgshapiro /* return another part of the buffer */ 21990792Sgshapiro (void) memcpy(buf, outbuf + offset, size); 22090792Sgshapiro offset += size; 22190792Sgshapiro len = size; 22290792Sgshapiro } 22371345Sgshapiro else 22471345Sgshapiro { 22590792Sgshapiro /* return the rest of the buffer */ 22690792Sgshapiro len = outlen - offset; 22790792Sgshapiro (void) memcpy(buf, outbuf + offset, (size_t) len); 22890792Sgshapiro SASL_DEALLOC(outbuf); 22990792Sgshapiro outbuf = NULL; 23090792Sgshapiro offset = 0; 23190792Sgshapiro outlen = 0; 23271345Sgshapiro } 23390792Sgshapiro return len; 23464562Sgshapiro} 23564562Sgshapiro 23690792Sgshapiro/* 23790792Sgshapiro** SASL_WRITE -- write information out after encrypting it 23890792Sgshapiro** 23990792Sgshapiro** Parameters: 24090792Sgshapiro** fp -- the file pointer 24190792Sgshapiro** buf -- holds the data to be encrypted and written 24290792Sgshapiro** size -- the number of bytes to have encrypted and written 24390792Sgshapiro** 24490792Sgshapiro** Returns: 24590792Sgshapiro** -1 on error 24690792Sgshapiro** otherwise number of bytes written 24790792Sgshapiro*/ 24890792Sgshapiro 24990792Sgshapirostatic ssize_t sasl_write __P((SM_FILE_T *, const char *, size_t)); 25090792Sgshapiro 25164562Sgshapirostatic ssize_t 25290792Sgshapirosasl_write(fp, buf, size) 25390792Sgshapiro SM_FILE_T *fp; 25490792Sgshapiro const char *buf; 25564562Sgshapiro size_t size; 25664562Sgshapiro{ 25764562Sgshapiro int result; 25864562Sgshapiro char *outbuf; 25964562Sgshapiro unsigned int outlen; 26090792Sgshapiro size_t ret = 0, total = 0; 26190792Sgshapiro struct sasl_obj *so = (struct sasl_obj *) fp->f_cookie; 26264562Sgshapiro 26390792Sgshapiro result = sasl_encode(so->conn, buf, 26490792Sgshapiro (unsigned int) size, &outbuf, &outlen); 26564562Sgshapiro 26664562Sgshapiro if (result != SASL_OK) 26764562Sgshapiro return -1; 26864562Sgshapiro 26964562Sgshapiro if (outbuf != NULL) 27064562Sgshapiro { 27190792Sgshapiro while (outlen > 0) 27290792Sgshapiro { 27390792Sgshapiro ret = sm_io_write(so->fp, SM_TIME_DEFAULT, 27490792Sgshapiro &outbuf[total], outlen); 27590792Sgshapiro outlen -= ret; 27690792Sgshapiro total += ret; 27790792Sgshapiro } 27871345Sgshapiro SASL_DEALLOC(outbuf); 27964562Sgshapiro } 28064562Sgshapiro return size; 28164562Sgshapiro} 28264562Sgshapiro 28390792Sgshapiro/* 28490792Sgshapiro** SFDCSASL -- create sasl file type and open in and out file pointers 28590792Sgshapiro** for sendmail to read from and write to. 28690792Sgshapiro** 28790792Sgshapiro** Parameters: 28890792Sgshapiro** fin -- the sm_io file encrypted data to be read from 28990792Sgshapiro** fout -- the sm_io file encrypted data to be writen to 29090792Sgshapiro** conn -- the sasl connection pointer 29190792Sgshapiro** 29290792Sgshapiro** Returns: 29390792Sgshapiro** -1 on error 29490792Sgshapiro** 0 on success 29590792Sgshapiro** 29690792Sgshapiro** Side effects: 29790792Sgshapiro** The arguments "fin" and "fout" are replaced with the new 29890792Sgshapiro** SM_FILE_T pointers. 29990792Sgshapiro*/ 30090792Sgshapiro 30164562Sgshapiroint 30264562Sgshapirosfdcsasl(fin, fout, conn) 30390792Sgshapiro SM_FILE_T **fin; 30490792Sgshapiro SM_FILE_T **fout; 30564562Sgshapiro sasl_conn_t *conn; 30664562Sgshapiro{ 30790792Sgshapiro SM_FILE_T *newin, *newout; 30890792Sgshapiro SM_FILE_T SM_IO_SET_TYPE(sasl_vector, "sasl", sasl_open, sasl_close, 30990792Sgshapiro sasl_read, sasl_write, NULL, sasl_getinfo, NULL, 31090792Sgshapiro SM_TIME_FOREVER); 31190792Sgshapiro struct sasl_info info; 31264562Sgshapiro 31364562Sgshapiro if (conn == NULL) 31464562Sgshapiro { 31564562Sgshapiro /* no need to do anything */ 31664562Sgshapiro return 0; 31764562Sgshapiro } 31864562Sgshapiro 31990792Sgshapiro SM_IO_INIT_TYPE(sasl_vector, "sasl", sasl_open, sasl_close, 32090792Sgshapiro sasl_read, sasl_write, NULL, sasl_getinfo, NULL, 32190792Sgshapiro SM_TIME_FOREVER); 32290792Sgshapiro info.fp = *fin; 32390792Sgshapiro info.conn = conn; 32490792Sgshapiro newin = sm_io_open(&sasl_vector, SM_TIME_DEFAULT, &info, SM_IO_RDONLY, 32590792Sgshapiro NULL); 32664562Sgshapiro 32790792Sgshapiro if (newin == NULL) 32890792Sgshapiro return -1; 32964562Sgshapiro 33090792Sgshapiro info.fp = *fout; 33190792Sgshapiro info.conn = conn; 33290792Sgshapiro newout = sm_io_open(&sasl_vector, SM_TIME_DEFAULT, &info, SM_IO_WRONLY, 33390792Sgshapiro NULL); 33464562Sgshapiro 33590792Sgshapiro if (newout == NULL) 33664562Sgshapiro { 33790792Sgshapiro (void) sm_io_close(newin, SM_TIME_DEFAULT); 33864562Sgshapiro return -1; 33964562Sgshapiro } 34090792Sgshapiro sm_io_automode(newin, newout); 34190792Sgshapiro 34290792Sgshapiro *fin = newin; 34390792Sgshapiro *fout = newout; 34464562Sgshapiro return 0; 34564562Sgshapiro} 34690792Sgshapiro#endif /* SASL */ 34764562Sgshapiro 34890792Sgshapiro#if STARTTLS 34990792Sgshapiro# include "sfsasl.h" 35090792Sgshapiro# include <openssl/err.h> 35190792Sgshapiro 35290792Sgshapiro/* Structure used by the "tls" file type */ 35390792Sgshapirostruct tls_obj 35490792Sgshapiro{ 35590792Sgshapiro SM_FILE_T *fp; 35690792Sgshapiro SSL *con; 35790792Sgshapiro}; 35890792Sgshapiro 35990792Sgshapirostruct tls_info 36090792Sgshapiro{ 36190792Sgshapiro SM_FILE_T *fp; 36290792Sgshapiro SSL *con; 36390792Sgshapiro}; 36490792Sgshapiro 36564562Sgshapiro/* 36690792Sgshapiro** TLS_GETINFO - returns requested information about a "tls" file 36790792Sgshapiro** descriptor. 36890792Sgshapiro** 36990792Sgshapiro** Parameters: 37090792Sgshapiro** fp -- the file descriptor 37190792Sgshapiro** what -- the type of information requested 37290792Sgshapiro** valp -- the thang to return the information in (unused) 37390792Sgshapiro** 37490792Sgshapiro** Returns: 37590792Sgshapiro** -1 for unknown requests 37690792Sgshapiro** >=0 on success with valp filled in (if possible). 37764562Sgshapiro*/ 37864562Sgshapiro 37990792Sgshapirostatic int tls_getinfo __P((SM_FILE_T *, int, void *)); 38064562Sgshapiro 38190792Sgshapiro/* ARGSUSED2 */ 38280785Sgshapirostatic int 38390792Sgshapirotls_getinfo(fp, what, valp) 38490792Sgshapiro SM_FILE_T *fp; 38590792Sgshapiro int what; 38690792Sgshapiro void *valp; 38764562Sgshapiro{ 38890792Sgshapiro struct tls_obj *so = (struct tls_obj *) fp->f_cookie; 38964562Sgshapiro 39090792Sgshapiro switch (what) 39164562Sgshapiro { 39290792Sgshapiro case SM_IO_WHAT_FD: 39390792Sgshapiro if (so->fp == NULL) 39490792Sgshapiro return -1; 39590792Sgshapiro return so->fp->f_file; /* for stdio fileno() compatability */ 39664562Sgshapiro 39790792Sgshapiro case SM_IO_IS_READABLE: 39890792Sgshapiro return SSL_pending(so->con) > 0; 39990792Sgshapiro 40090792Sgshapiro default: 40190792Sgshapiro return -1; 40290792Sgshapiro } 40390792Sgshapiro} 40490792Sgshapiro 40564562Sgshapiro/* 40690792Sgshapiro** TLS_OPEN -- creates the tls specific information for opening a 40790792Sgshapiro** file of the tls type. 40890792Sgshapiro** 40990792Sgshapiro** Parameters: 41090792Sgshapiro** fp -- the file pointer associated with the new open 41190792Sgshapiro** info -- the sm_io file pointer holding the open and the 41290792Sgshapiro** TLS encryption connection to be read from or written to 41390792Sgshapiro** flags -- ignored 41490792Sgshapiro** rpool -- ignored 41590792Sgshapiro** 41690792Sgshapiro** Returns: 41790792Sgshapiro** 0 on success 41864562Sgshapiro*/ 41990792Sgshapiro 42090792Sgshapirostatic int tls_open __P((SM_FILE_T *, const void *, int, const void *)); 42190792Sgshapiro 42290792Sgshapiro/* ARGSUSED2 */ 42390792Sgshapirostatic int 42490792Sgshapirotls_open(fp, info, flags, rpool) 42590792Sgshapiro SM_FILE_T *fp; 42690792Sgshapiro const void *info; 42790792Sgshapiro int flags; 42890792Sgshapiro const void *rpool; 42990792Sgshapiro{ 43090792Sgshapiro struct tls_obj *so; 43190792Sgshapiro struct tls_info *ti = (struct tls_info *) info; 43290792Sgshapiro 43390792Sgshapiro so = (struct tls_obj *) sm_malloc(sizeof(struct tls_obj)); 43490792Sgshapiro so->fp = ti->fp; 43590792Sgshapiro so->con = ti->con; 43690792Sgshapiro 43790792Sgshapiro /* 43890792Sgshapiro ** We try to get the "raw" file descriptor that TLS uses to 43990792Sgshapiro ** do the actual read/write with. This is to allow us control 44090792Sgshapiro ** over the file descriptor being a blocking or non-blocking type. 44190792Sgshapiro ** Under the covers TLS handles the change and this allows us 44290792Sgshapiro ** to do timeouts with sm_io. 44390792Sgshapiro */ 44490792Sgshapiro 44590792Sgshapiro fp->f_file = sm_io_getinfo(so->fp, SM_IO_WHAT_FD, NULL); 44690792Sgshapiro (void) sm_io_setvbuf(so->fp, SM_TIME_DEFAULT, NULL, SM_IO_NOW, 0); 44790792Sgshapiro fp->f_cookie = so; 44890792Sgshapiro return 0; 44990792Sgshapiro} 45090792Sgshapiro 45190792Sgshapiro/* 45290792Sgshapiro** TLS_CLOSE -- close the tls specific parts of the tls file pointer 45390792Sgshapiro** 45490792Sgshapiro** Parameters: 45590792Sgshapiro** fp -- the file pointer to close 45690792Sgshapiro** 45790792Sgshapiro** Returns: 45890792Sgshapiro** 0 on success 45990792Sgshapiro*/ 46090792Sgshapiro 46190792Sgshapirostatic int tls_close __P((SM_FILE_T *)); 46290792Sgshapiro 46390792Sgshapirostatic int 46490792Sgshapirotls_close(fp) 46590792Sgshapiro SM_FILE_T *fp; 46690792Sgshapiro{ 46790792Sgshapiro struct tls_obj *so; 46890792Sgshapiro 46990792Sgshapiro so = (struct tls_obj *) fp->f_cookie; 47090792Sgshapiro if (so->fp != NULL) 47190792Sgshapiro { 47290792Sgshapiro sm_io_close(so->fp, SM_TIME_DEFAULT); 47390792Sgshapiro so->fp = NULL; 47464562Sgshapiro } 47590792Sgshapiro sm_free(so); 47690792Sgshapiro so = NULL; 47790792Sgshapiro return 0; 47864562Sgshapiro} 47964562Sgshapiro 48090792Sgshapiro/* maximum number of retries for TLS related I/O due to handshakes */ 48190792Sgshapiro# define MAX_TLS_IOS 4 48290792Sgshapiro 48390792Sgshapiro/* 48490792Sgshapiro** TLS_READ -- read secured information for the caller 48590792Sgshapiro** 48690792Sgshapiro** Parameters: 48790792Sgshapiro** fp -- the file pointer 48890792Sgshapiro** buf -- the location to place the data 48990792Sgshapiro** size -- the number of bytes to read from connection 49090792Sgshapiro** 49190792Sgshapiro** Results: 49290792Sgshapiro** -1 on error 49390792Sgshapiro** otherwise the number of bytes read 49490792Sgshapiro*/ 49590792Sgshapiro 49690792Sgshapirostatic ssize_t tls_read __P((SM_FILE_T *, char *, size_t)); 49790792Sgshapiro 49864562Sgshapirostatic ssize_t 49990792Sgshapirotls_read(fp, buf, size) 50090792Sgshapiro SM_FILE_T *fp; 50190792Sgshapiro char *buf; 50264562Sgshapiro size_t size; 50364562Sgshapiro{ 50464562Sgshapiro int r; 50590792Sgshapiro static int again = MAX_TLS_IOS; 50690792Sgshapiro struct tls_obj *so = (struct tls_obj *) fp->f_cookie; 50790792Sgshapiro char *err; 50864562Sgshapiro 50990792Sgshapiro r = SSL_read(so->con, (char *) buf, size); 51064562Sgshapiro 51190792Sgshapiro if (r > 0) 51264562Sgshapiro { 51390792Sgshapiro again = MAX_TLS_IOS; 51490792Sgshapiro return r; 51590792Sgshapiro } 51664562Sgshapiro 51790792Sgshapiro err = NULL; 51890792Sgshapiro switch (SSL_get_error(so->con, r)) 51990792Sgshapiro { 52090792Sgshapiro case SSL_ERROR_NONE: 52190792Sgshapiro case SSL_ERROR_ZERO_RETURN: 52290792Sgshapiro again = MAX_TLS_IOS; 52390792Sgshapiro break; 52490792Sgshapiro case SSL_ERROR_WANT_WRITE: 52590792Sgshapiro if (--again <= 0) 52690792Sgshapiro err = "read W BLOCK"; 52790792Sgshapiro else 52890792Sgshapiro errno = EAGAIN; 52990792Sgshapiro break; 53090792Sgshapiro case SSL_ERROR_WANT_READ: 53190792Sgshapiro if (--again <= 0) 53290792Sgshapiro err = "read R BLOCK"; 53390792Sgshapiro else 53490792Sgshapiro errno = EAGAIN; 53590792Sgshapiro break; 53690792Sgshapiro case SSL_ERROR_WANT_X509_LOOKUP: 53790792Sgshapiro err = "write X BLOCK"; 53890792Sgshapiro break; 53990792Sgshapiro case SSL_ERROR_SYSCALL: 54090792Sgshapiro if (r == 0 && errno == 0) /* out of protocol EOF found */ 54190792Sgshapiro break; 54290792Sgshapiro err = "syscall error"; 54364562Sgshapiro/* 54490792Sgshapiro get_last_socket_error()); 54564562Sgshapiro*/ 54690792Sgshapiro break; 54790792Sgshapiro case SSL_ERROR_SSL: 54890792Sgshapiro err = "generic SSL error"; 54990792Sgshapiro if (LogLevel > 9) 55090792Sgshapiro tlslogerr("read"); 55190792Sgshapiro break; 55264562Sgshapiro } 55390792Sgshapiro if (err != NULL) 55490792Sgshapiro { 55590792Sgshapiro again = MAX_TLS_IOS; 55690792Sgshapiro if (errno == 0) 55790792Sgshapiro errno = EIO; 55890792Sgshapiro if (LogLevel > 7) 55990792Sgshapiro sm_syslog(LOG_WARNING, NOQID, 56090792Sgshapiro "STARTTLS: read error=%s (%d)", err, r); 56190792Sgshapiro } 56264562Sgshapiro return r; 56364562Sgshapiro} 56464562Sgshapiro 56590792Sgshapiro/* 56690792Sgshapiro** TLS_WRITE -- write information out through secure connection 56790792Sgshapiro** 56890792Sgshapiro** Parameters: 56990792Sgshapiro** fp -- the file pointer 57090792Sgshapiro** buf -- holds the data to be securely written 57190792Sgshapiro** size -- the number of bytes to write 57290792Sgshapiro** 57390792Sgshapiro** Returns: 57490792Sgshapiro** -1 on error 57590792Sgshapiro** otherwise number of bytes written 57690792Sgshapiro*/ 57790792Sgshapiro 57890792Sgshapirostatic ssize_t tls_write __P((SM_FILE_T *, const char *, size_t)); 57990792Sgshapiro 58090792Sgshapirostatic ssize_t 58190792Sgshapirotls_write(fp, buf, size) 58290792Sgshapiro SM_FILE_T *fp; 58390792Sgshapiro const char *buf; 58490792Sgshapiro size_t size; 58564562Sgshapiro{ 58690792Sgshapiro int r; 58790792Sgshapiro static int again = MAX_TLS_IOS; 58890792Sgshapiro struct tls_obj *so = (struct tls_obj *) fp->f_cookie; 58990792Sgshapiro char *err; 59064562Sgshapiro 59190792Sgshapiro r = SSL_write(so->con, (char *) buf, size); 59264562Sgshapiro 59390792Sgshapiro if (r > 0) 59464562Sgshapiro { 59590792Sgshapiro again = MAX_TLS_IOS; 59690792Sgshapiro return r; 59764562Sgshapiro } 59890792Sgshapiro err = NULL; 59990792Sgshapiro switch (SSL_get_error(so->con, r)) 60090792Sgshapiro { 60190792Sgshapiro case SSL_ERROR_NONE: 60290792Sgshapiro case SSL_ERROR_ZERO_RETURN: 60390792Sgshapiro again = MAX_TLS_IOS; 60490792Sgshapiro break; 60590792Sgshapiro case SSL_ERROR_WANT_WRITE: 60690792Sgshapiro if (--again <= 0) 60790792Sgshapiro err = "write W BLOCK"; 60890792Sgshapiro else 60990792Sgshapiro errno = EAGAIN; 61090792Sgshapiro break; 61190792Sgshapiro case SSL_ERROR_WANT_READ: 61290792Sgshapiro if (--again <= 0) 61390792Sgshapiro err = "write R BLOCK"; 61490792Sgshapiro else 61590792Sgshapiro errno = EAGAIN; 61690792Sgshapiro break; 61790792Sgshapiro case SSL_ERROR_WANT_X509_LOOKUP: 61890792Sgshapiro err = "write X BLOCK"; 61990792Sgshapiro break; 62090792Sgshapiro case SSL_ERROR_SYSCALL: 62190792Sgshapiro if (r == 0 && errno == 0) /* out of protocol EOF found */ 62290792Sgshapiro break; 62390792Sgshapiro err = "syscall error"; 62490792Sgshapiro/* 62590792Sgshapiro get_last_socket_error()); 62690792Sgshapiro*/ 62790792Sgshapiro break; 62890792Sgshapiro case SSL_ERROR_SSL: 62990792Sgshapiro err = "generic SSL error"; 63090792Sgshapiro/* 63190792Sgshapiro ERR_GET_REASON(ERR_peek_error())); 63290792Sgshapiro*/ 63390792Sgshapiro if (LogLevel > 9) 63490792Sgshapiro tlslogerr("write"); 63590792Sgshapiro break; 63690792Sgshapiro } 63790792Sgshapiro if (err != NULL) 63890792Sgshapiro { 63990792Sgshapiro again = MAX_TLS_IOS; 64090792Sgshapiro if (errno == 0) 64190792Sgshapiro errno = EIO; 64290792Sgshapiro if (LogLevel > 7) 64390792Sgshapiro sm_syslog(LOG_WARNING, NOQID, 64490792Sgshapiro "STARTTLS: write error=%s (%d)", err, r); 64590792Sgshapiro } 64690792Sgshapiro return r; 64764562Sgshapiro} 64864562Sgshapiro 64990792Sgshapiro/* 65090792Sgshapiro** SFDCTLS -- create tls file type and open in and out file pointers 65190792Sgshapiro** for sendmail to read from and write to. 65290792Sgshapiro** 65390792Sgshapiro** Parameters: 65490792Sgshapiro** fin -- data input source being replaced 65590792Sgshapiro** fout -- data output source being replaced 65690792Sgshapiro** conn -- the tls connection pointer 65790792Sgshapiro** 65890792Sgshapiro** Returns: 65990792Sgshapiro** -1 on error 66090792Sgshapiro** 0 on success 66190792Sgshapiro** 66290792Sgshapiro** Side effects: 66390792Sgshapiro** The arguments "fin" and "fout" are replaced with the new 66490792Sgshapiro** SM_FILE_T pointers. 66590792Sgshapiro** The original "fin" and "fout" are preserved in the tls file 66690792Sgshapiro** type but are not actually used because of the design of TLS. 66790792Sgshapiro*/ 66890792Sgshapiro 66964562Sgshapiroint 67064562Sgshapirosfdctls(fin, fout, con) 67190792Sgshapiro SM_FILE_T **fin; 67290792Sgshapiro SM_FILE_T **fout; 67364562Sgshapiro SSL *con; 67464562Sgshapiro{ 67590792Sgshapiro SM_FILE_T *tlsin, *tlsout; 67690792Sgshapiro SM_FILE_T SM_IO_SET_TYPE(tls_vector, "tls", tls_open, tls_close, 67790792Sgshapiro tls_read, tls_write, NULL, tls_getinfo, NULL, 67890792Sgshapiro SM_TIME_FOREVER); 67990792Sgshapiro struct tls_info info; 68064562Sgshapiro 68190792Sgshapiro SM_ASSERT(con != NULL); 68264562Sgshapiro 68390792Sgshapiro SM_IO_INIT_TYPE(tls_vector, "tls", tls_open, tls_close, 68490792Sgshapiro tls_read, tls_write, NULL, tls_getinfo, NULL, 68590792Sgshapiro SM_TIME_FOREVER); 68690792Sgshapiro info.fp = *fin; 68790792Sgshapiro info.con = con; 68890792Sgshapiro tlsin = sm_io_open(&tls_vector, SM_TIME_DEFAULT, &info, SM_IO_RDONLY, 68990792Sgshapiro NULL); 69090792Sgshapiro if (tlsin == NULL) 69190792Sgshapiro return -1; 69264562Sgshapiro 69390792Sgshapiro info.fp = *fout; 69490792Sgshapiro tlsout = sm_io_open(&tls_vector, SM_TIME_DEFAULT, &info, SM_IO_WRONLY, 69590792Sgshapiro NULL); 69690792Sgshapiro if (tlsout == NULL) 69766494Sgshapiro { 69890792Sgshapiro (void) sm_io_close(tlsin, SM_TIME_DEFAULT); 69966494Sgshapiro return -1; 70066494Sgshapiro } 70190792Sgshapiro sm_io_automode(tlsin, tlsout); 70264562Sgshapiro 70390792Sgshapiro *fin = tlsin; 70490792Sgshapiro *fout = tlsout; 70564562Sgshapiro return 0; 70664562Sgshapiro} 70790792Sgshapiro#endif /* STARTTLS */ 708