164562Sgshapiro/* 2261363Sgshapiro * Copyright (c) 1999-2006, 2008 Proofpoint, 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> 12266692SgshapiroSM_RCSID("@(#)$Id: sfsasl.c,v 8.121 2013-11-22 20:51:56 ca Exp $") 1364562Sgshapiro#include <stdlib.h> 1464562Sgshapiro#include <sendmail.h> 15159609Sgshapiro#include <sm/time.h> 16285303Sgshapiro#include <sm/fdset.h> 1790792Sgshapiro#include <errno.h> 18141858Sgshapiro 19141858Sgshapiro/* allow to disable error handling code just in case... */ 20141858Sgshapiro#ifndef DEAL_WITH_ERROR_SSL 21141858Sgshapiro# define DEAL_WITH_ERROR_SSL 1 22141858Sgshapiro#endif /* ! DEAL_WITH_ERROR_SSL */ 23141858Sgshapiro 2490792Sgshapiro#if SASL 2590792Sgshapiro# include "sfsasl.h" 2664562Sgshapiro 2790792Sgshapiro/* Structure used by the "sasl" file type */ 2890792Sgshapirostruct sasl_obj 2990792Sgshapiro{ 3090792Sgshapiro SM_FILE_T *fp; 3190792Sgshapiro sasl_conn_t *conn; 3290792Sgshapiro}; 3390792Sgshapiro 3490792Sgshapirostruct sasl_info 3590792Sgshapiro{ 3690792Sgshapiro SM_FILE_T *fp; 3790792Sgshapiro sasl_conn_t *conn; 3890792Sgshapiro}; 3990792Sgshapiro 4064562Sgshapiro/* 4190792Sgshapiro** SASL_GETINFO - returns requested information about a "sasl" file 4290792Sgshapiro** descriptor. 4390792Sgshapiro** 4490792Sgshapiro** Parameters: 4590792Sgshapiro** fp -- the file descriptor 4690792Sgshapiro** what -- the type of information requested 4790792Sgshapiro** valp -- the thang to return the information in 4890792Sgshapiro** 4990792Sgshapiro** Returns: 5090792Sgshapiro** -1 for unknown requests 5190792Sgshapiro** >=0 on success with valp filled in (if possible). 5264562Sgshapiro*/ 5364562Sgshapiro 5490792Sgshapirostatic int sasl_getinfo __P((SM_FILE_T *, int, void *)); 5564562Sgshapiro 5690792Sgshapirostatic int 5790792Sgshapirosasl_getinfo(fp, what, valp) 5890792Sgshapiro SM_FILE_T *fp; 5990792Sgshapiro int what; 6090792Sgshapiro void *valp; 6190792Sgshapiro{ 6290792Sgshapiro struct sasl_obj *so = (struct sasl_obj *) fp->f_cookie; 6390792Sgshapiro 6490792Sgshapiro switch (what) 6590792Sgshapiro { 6690792Sgshapiro case SM_IO_WHAT_FD: 6790792Sgshapiro if (so->fp == NULL) 6890792Sgshapiro return -1; 6990792Sgshapiro return so->fp->f_file; /* for stdio fileno() compatability */ 7090792Sgshapiro 7190792Sgshapiro case SM_IO_IS_READABLE: 7290792Sgshapiro if (so->fp == NULL) 7390792Sgshapiro return 0; 7490792Sgshapiro 7590792Sgshapiro /* get info from underlying file */ 7690792Sgshapiro return sm_io_getinfo(so->fp, what, valp); 7790792Sgshapiro 7890792Sgshapiro default: 7990792Sgshapiro return -1; 8090792Sgshapiro } 8190792Sgshapiro} 8290792Sgshapiro 8390792Sgshapiro/* 8490792Sgshapiro** SASL_OPEN -- creates the sasl specific information for opening a 8590792Sgshapiro** file of the sasl type. 8690792Sgshapiro** 8790792Sgshapiro** Parameters: 8890792Sgshapiro** fp -- the file pointer associated with the new open 8990792Sgshapiro** info -- contains the sasl connection information pointer and 9090792Sgshapiro** the original SM_FILE_T that holds the open 9190792Sgshapiro** flags -- ignored 9290792Sgshapiro** rpool -- ignored 9390792Sgshapiro** 9490792Sgshapiro** Returns: 9590792Sgshapiro** 0 on success 9690792Sgshapiro*/ 9790792Sgshapiro 9890792Sgshapirostatic int sasl_open __P((SM_FILE_T *, const void *, int, const void *)); 9990792Sgshapiro 10090792Sgshapiro/* ARGSUSED2 */ 10190792Sgshapirostatic int 10290792Sgshapirosasl_open(fp, info, flags, rpool) 10390792Sgshapiro SM_FILE_T *fp; 10490792Sgshapiro const void *info; 10590792Sgshapiro int flags; 10690792Sgshapiro const void *rpool; 10790792Sgshapiro{ 10890792Sgshapiro struct sasl_obj *so; 10990792Sgshapiro struct sasl_info *si = (struct sasl_info *) info; 11090792Sgshapiro 11190792Sgshapiro so = (struct sasl_obj *) sm_malloc(sizeof(struct sasl_obj)); 112120256Sgshapiro if (so == NULL) 113120256Sgshapiro { 114120256Sgshapiro errno = ENOMEM; 115120256Sgshapiro return -1; 116120256Sgshapiro } 11790792Sgshapiro so->fp = si->fp; 11890792Sgshapiro so->conn = si->conn; 11990792Sgshapiro 12090792Sgshapiro /* 12190792Sgshapiro ** The underlying 'fp' is set to SM_IO_NOW so that the entire 12290792Sgshapiro ** encoded string is written in one chunk. Otherwise there is 12390792Sgshapiro ** the possibility that it may appear illegal, bogus or 12490792Sgshapiro ** mangled to the other side of the connection. 12590792Sgshapiro ** We will read or write through 'fp' since it is the opaque 12690792Sgshapiro ** connection for the communications. We need to treat it this 12790792Sgshapiro ** way in case the encoded string is to be sent down a TLS 12890792Sgshapiro ** connection rather than, say, sm_io's stdio. 12990792Sgshapiro */ 13090792Sgshapiro 13190792Sgshapiro (void) sm_io_setvbuf(so->fp, SM_TIME_DEFAULT, NULL, SM_IO_NOW, 0); 13290792Sgshapiro fp->f_cookie = so; 13390792Sgshapiro return 0; 13490792Sgshapiro} 13590792Sgshapiro 13690792Sgshapiro/* 13790792Sgshapiro** SASL_CLOSE -- close the sasl specific parts of the sasl file pointer 13890792Sgshapiro** 13990792Sgshapiro** Parameters: 14090792Sgshapiro** fp -- the file pointer to close 14190792Sgshapiro** 14290792Sgshapiro** Returns: 14390792Sgshapiro** 0 on success 14490792Sgshapiro*/ 14590792Sgshapiro 14690792Sgshapirostatic int sasl_close __P((SM_FILE_T *)); 14790792Sgshapiro 14890792Sgshapirostatic int 14990792Sgshapirosasl_close(fp) 15090792Sgshapiro SM_FILE_T *fp; 15190792Sgshapiro{ 15290792Sgshapiro struct sasl_obj *so; 15390792Sgshapiro 15490792Sgshapiro so = (struct sasl_obj *) fp->f_cookie; 155120256Sgshapiro if (so == NULL) 156120256Sgshapiro return 0; 15790792Sgshapiro if (so->fp != NULL) 15890792Sgshapiro { 15990792Sgshapiro sm_io_close(so->fp, SM_TIME_DEFAULT); 16090792Sgshapiro so->fp = NULL; 16190792Sgshapiro } 16290792Sgshapiro sm_free(so); 16390792Sgshapiro so = NULL; 16490792Sgshapiro return 0; 16590792Sgshapiro} 16690792Sgshapiro 16771345Sgshapiro/* how to deallocate a buffer allocated by SASL */ 16890792Sgshapiroextern void sm_sasl_free __P((void *)); 16998841Sgshapiro# define SASL_DEALLOC(b) sm_sasl_free(b) 17071345Sgshapiro 17190792Sgshapiro/* 17290792Sgshapiro** SASL_READ -- read encrypted information and decrypt it for the caller 17390792Sgshapiro** 17490792Sgshapiro** Parameters: 17590792Sgshapiro** fp -- the file pointer 17690792Sgshapiro** buf -- the location to place the decrypted information 17790792Sgshapiro** size -- the number of bytes to read after decryption 17890792Sgshapiro** 17990792Sgshapiro** Results: 18090792Sgshapiro** -1 on error 18190792Sgshapiro** otherwise the number of bytes read 18290792Sgshapiro*/ 18390792Sgshapiro 18490792Sgshapirostatic ssize_t sasl_read __P((SM_FILE_T *, char *, size_t)); 18590792Sgshapiro 18664562Sgshapirostatic ssize_t 18790792Sgshapirosasl_read(fp, buf, size) 18890792Sgshapiro SM_FILE_T *fp; 18990792Sgshapiro char *buf; 19064562Sgshapiro size_t size; 19164562Sgshapiro{ 19290792Sgshapiro int result; 19390792Sgshapiro ssize_t len; 19498121Sgshapiro# if SASL >= 20000 195110560Sgshapiro static const char *outbuf = NULL; 19698121Sgshapiro# else /* SASL >= 20000 */ 19771345Sgshapiro static char *outbuf = NULL; 19898121Sgshapiro# endif /* SASL >= 20000 */ 19971345Sgshapiro static unsigned int outlen = 0; 20071345Sgshapiro static unsigned int offset = 0; 20190792Sgshapiro struct sasl_obj *so = (struct sasl_obj *) fp->f_cookie; 20264562Sgshapiro 20371345Sgshapiro /* 20471345Sgshapiro ** sasl_decode() may require more data than a single read() returns. 20571345Sgshapiro ** Hence we have to put a loop around the decoding. 20671345Sgshapiro ** This also requires that we may have to split up the returned 20771345Sgshapiro ** data since it might be larger than the allowed size. 20871345Sgshapiro ** Therefore we use a static pointer and return portions of it 20971345Sgshapiro ** if necessary. 210120256Sgshapiro ** XXX Note: This function is not thread-safe nor can it be used 211120256Sgshapiro ** on more than one file. A correct implementation would store 212120256Sgshapiro ** this data in fp->f_cookie. 21371345Sgshapiro */ 21464562Sgshapiro 215110560Sgshapiro# if SASL >= 20000 216110560Sgshapiro while (outlen == 0) 217110560Sgshapiro# else /* SASL >= 20000 */ 21871345Sgshapiro while (outbuf == NULL && outlen == 0) 219110560Sgshapiro# endif /* SASL >= 20000 */ 22064562Sgshapiro { 22190792Sgshapiro len = sm_io_read(so->fp, SM_TIME_DEFAULT, buf, size); 22271345Sgshapiro if (len <= 0) 22371345Sgshapiro return len; 22490792Sgshapiro result = sasl_decode(so->conn, buf, 22590792Sgshapiro (unsigned int) len, &outbuf, &outlen); 22671345Sgshapiro if (result != SASL_OK) 22771345Sgshapiro { 228157001Sgshapiro if (LogLevel > 7) 229157001Sgshapiro sm_syslog(LOG_WARNING, NOQID, 230157001Sgshapiro "AUTH: sasl_decode error=%d", result); 23171345Sgshapiro outbuf = NULL; 23271345Sgshapiro offset = 0; 23371345Sgshapiro outlen = 0; 23471345Sgshapiro return -1; 23571345Sgshapiro } 23664562Sgshapiro } 23764562Sgshapiro 23890792Sgshapiro if (outbuf == NULL) 23964562Sgshapiro { 24090792Sgshapiro /* be paranoid: outbuf == NULL but outlen != 0 */ 24190792Sgshapiro syserr("@sasl_read failure: outbuf == NULL but outlen != 0"); 24290792Sgshapiro /* NOTREACHED */ 24364562Sgshapiro } 24490792Sgshapiro if (outlen - offset > size) 24590792Sgshapiro { 24690792Sgshapiro /* return another part of the buffer */ 24790792Sgshapiro (void) memcpy(buf, outbuf + offset, size); 24890792Sgshapiro offset += size; 24990792Sgshapiro len = size; 25090792Sgshapiro } 25171345Sgshapiro else 25271345Sgshapiro { 25390792Sgshapiro /* return the rest of the buffer */ 25490792Sgshapiro len = outlen - offset; 25590792Sgshapiro (void) memcpy(buf, outbuf + offset, (size_t) len); 25698121Sgshapiro# if SASL < 20000 25790792Sgshapiro SASL_DEALLOC(outbuf); 25898121Sgshapiro# endif /* SASL < 20000 */ 25990792Sgshapiro outbuf = NULL; 26090792Sgshapiro offset = 0; 26190792Sgshapiro outlen = 0; 26271345Sgshapiro } 26390792Sgshapiro return len; 26464562Sgshapiro} 26564562Sgshapiro 26690792Sgshapiro/* 26790792Sgshapiro** SASL_WRITE -- write information out after encrypting it 26890792Sgshapiro** 26990792Sgshapiro** Parameters: 27090792Sgshapiro** fp -- the file pointer 27190792Sgshapiro** buf -- holds the data to be encrypted and written 27290792Sgshapiro** size -- the number of bytes to have encrypted and written 27390792Sgshapiro** 27490792Sgshapiro** Returns: 27590792Sgshapiro** -1 on error 27690792Sgshapiro** otherwise number of bytes written 27790792Sgshapiro*/ 27890792Sgshapiro 27990792Sgshapirostatic ssize_t sasl_write __P((SM_FILE_T *, const char *, size_t)); 28090792Sgshapiro 28164562Sgshapirostatic ssize_t 28290792Sgshapirosasl_write(fp, buf, size) 28390792Sgshapiro SM_FILE_T *fp; 28490792Sgshapiro const char *buf; 28564562Sgshapiro size_t size; 28664562Sgshapiro{ 28764562Sgshapiro int result; 28898121Sgshapiro# if SASL >= 20000 28998121Sgshapiro const char *outbuf; 29098121Sgshapiro# else /* SASL >= 20000 */ 29164562Sgshapiro char *outbuf; 29298121Sgshapiro# endif /* SASL >= 20000 */ 293141858Sgshapiro unsigned int outlen, *maxencode; 29490792Sgshapiro size_t ret = 0, total = 0; 29590792Sgshapiro struct sasl_obj *so = (struct sasl_obj *) fp->f_cookie; 29664562Sgshapiro 297141858Sgshapiro /* 298141858Sgshapiro ** Fetch the maximum input buffer size for sasl_encode(). 299141858Sgshapiro ** This can be less than the size set in attemptauth() 300203004Sgshapiro ** due to a negotiation with the other side, e.g., 301141858Sgshapiro ** Cyrus IMAP lmtp program sets maxbuf=4096, 302141858Sgshapiro ** digestmd5 substracts 25 and hence we'll get 4071 303141858Sgshapiro ** instead of 8192 (MAXOUTLEN). 304141858Sgshapiro ** Hack (for now): simply reduce the size, callers are (must be) 305141858Sgshapiro ** able to deal with that and invoke sasl_write() again with 306141858Sgshapiro ** the rest of the data. 307141858Sgshapiro ** Note: it would be better to store this value in the context 308141858Sgshapiro ** after the negotiation. 309141858Sgshapiro */ 310141858Sgshapiro 311141858Sgshapiro result = sasl_getprop(so->conn, SASL_MAXOUTBUF, 312157001Sgshapiro (const void **) &maxencode); 313141858Sgshapiro if (result == SASL_OK && size > *maxencode && *maxencode > 0) 314141858Sgshapiro size = *maxencode; 315141858Sgshapiro 31690792Sgshapiro result = sasl_encode(so->conn, buf, 31790792Sgshapiro (unsigned int) size, &outbuf, &outlen); 31864562Sgshapiro 31964562Sgshapiro if (result != SASL_OK) 320157001Sgshapiro { 321157001Sgshapiro if (LogLevel > 7) 322157001Sgshapiro sm_syslog(LOG_WARNING, NOQID, 323157001Sgshapiro "AUTH: sasl_encode error=%d", result); 32464562Sgshapiro return -1; 325157001Sgshapiro } 32664562Sgshapiro 32764562Sgshapiro if (outbuf != NULL) 32864562Sgshapiro { 32990792Sgshapiro while (outlen > 0) 33090792Sgshapiro { 331159609Sgshapiro errno = 0; 33294334Sgshapiro /* XXX result == 0? */ 33390792Sgshapiro ret = sm_io_write(so->fp, SM_TIME_DEFAULT, 33490792Sgshapiro &outbuf[total], outlen); 335120256Sgshapiro if (ret <= 0) 336120256Sgshapiro return ret; 33790792Sgshapiro outlen -= ret; 33890792Sgshapiro total += ret; 33990792Sgshapiro } 34098121Sgshapiro# if SASL < 20000 34171345Sgshapiro SASL_DEALLOC(outbuf); 34298121Sgshapiro# endif /* SASL < 20000 */ 34364562Sgshapiro } 34464562Sgshapiro return size; 34564562Sgshapiro} 34664562Sgshapiro 34790792Sgshapiro/* 34890792Sgshapiro** SFDCSASL -- create sasl file type and open in and out file pointers 34990792Sgshapiro** for sendmail to read from and write to. 35090792Sgshapiro** 35190792Sgshapiro** Parameters: 35290792Sgshapiro** fin -- the sm_io file encrypted data to be read from 353159609Sgshapiro** fout -- the sm_io file encrypted data to be written to 35490792Sgshapiro** conn -- the sasl connection pointer 355159609Sgshapiro** tmo -- timeout 35690792Sgshapiro** 35790792Sgshapiro** Returns: 35890792Sgshapiro** -1 on error 35990792Sgshapiro** 0 on success 36090792Sgshapiro** 36190792Sgshapiro** Side effects: 36290792Sgshapiro** The arguments "fin" and "fout" are replaced with the new 36390792Sgshapiro** SM_FILE_T pointers. 36490792Sgshapiro*/ 36590792Sgshapiro 36664562Sgshapiroint 367159609Sgshapirosfdcsasl(fin, fout, conn, tmo) 36890792Sgshapiro SM_FILE_T **fin; 36990792Sgshapiro SM_FILE_T **fout; 37064562Sgshapiro sasl_conn_t *conn; 371159609Sgshapiro int tmo; 37264562Sgshapiro{ 37390792Sgshapiro SM_FILE_T *newin, *newout; 37490792Sgshapiro SM_FILE_T SM_IO_SET_TYPE(sasl_vector, "sasl", sasl_open, sasl_close, 37590792Sgshapiro sasl_read, sasl_write, NULL, sasl_getinfo, NULL, 376159609Sgshapiro SM_TIME_DEFAULT); 37790792Sgshapiro struct sasl_info info; 37864562Sgshapiro 37964562Sgshapiro if (conn == NULL) 38064562Sgshapiro { 38164562Sgshapiro /* no need to do anything */ 38264562Sgshapiro return 0; 38364562Sgshapiro } 38464562Sgshapiro 38590792Sgshapiro SM_IO_INIT_TYPE(sasl_vector, "sasl", sasl_open, sasl_close, 38690792Sgshapiro sasl_read, sasl_write, NULL, sasl_getinfo, NULL, 387159609Sgshapiro SM_TIME_DEFAULT); 38890792Sgshapiro info.fp = *fin; 38990792Sgshapiro info.conn = conn; 390132943Sgshapiro newin = sm_io_open(&sasl_vector, SM_TIME_DEFAULT, &info, 391132943Sgshapiro SM_IO_RDONLY_B, NULL); 39264562Sgshapiro 39390792Sgshapiro if (newin == NULL) 39490792Sgshapiro return -1; 39564562Sgshapiro 39690792Sgshapiro info.fp = *fout; 39790792Sgshapiro info.conn = conn; 398132943Sgshapiro newout = sm_io_open(&sasl_vector, SM_TIME_DEFAULT, &info, 399132943Sgshapiro SM_IO_WRONLY_B, NULL); 40064562Sgshapiro 40190792Sgshapiro if (newout == NULL) 40264562Sgshapiro { 40390792Sgshapiro (void) sm_io_close(newin, SM_TIME_DEFAULT); 40464562Sgshapiro return -1; 40564562Sgshapiro } 40690792Sgshapiro sm_io_automode(newin, newout); 40790792Sgshapiro 408159609Sgshapiro sm_io_setinfo(*fin, SM_IO_WHAT_TIMEOUT, &tmo); 409159609Sgshapiro sm_io_setinfo(*fout, SM_IO_WHAT_TIMEOUT, &tmo); 410159609Sgshapiro 41190792Sgshapiro *fin = newin; 41290792Sgshapiro *fout = newout; 41364562Sgshapiro return 0; 41464562Sgshapiro} 41590792Sgshapiro#endif /* SASL */ 41664562Sgshapiro 41790792Sgshapiro#if STARTTLS 41890792Sgshapiro# include "sfsasl.h" 419285303Sgshapiro# include <openssl/err.h> 42090792Sgshapiro 42190792Sgshapiro/* Structure used by the "tls" file type */ 42290792Sgshapirostruct tls_obj 42390792Sgshapiro{ 42490792Sgshapiro SM_FILE_T *fp; 42590792Sgshapiro SSL *con; 42690792Sgshapiro}; 42790792Sgshapiro 42890792Sgshapirostruct tls_info 42990792Sgshapiro{ 43090792Sgshapiro SM_FILE_T *fp; 43190792Sgshapiro SSL *con; 43290792Sgshapiro}; 43390792Sgshapiro 43464562Sgshapiro/* 43590792Sgshapiro** TLS_GETINFO - returns requested information about a "tls" file 43690792Sgshapiro** descriptor. 43790792Sgshapiro** 43890792Sgshapiro** Parameters: 43990792Sgshapiro** fp -- the file descriptor 44090792Sgshapiro** what -- the type of information requested 44190792Sgshapiro** valp -- the thang to return the information in (unused) 44290792Sgshapiro** 44390792Sgshapiro** Returns: 44490792Sgshapiro** -1 for unknown requests 44590792Sgshapiro** >=0 on success with valp filled in (if possible). 44664562Sgshapiro*/ 44764562Sgshapiro 44890792Sgshapirostatic int tls_getinfo __P((SM_FILE_T *, int, void *)); 44964562Sgshapiro 45090792Sgshapiro/* ARGSUSED2 */ 45180785Sgshapirostatic int 45290792Sgshapirotls_getinfo(fp, what, valp) 45390792Sgshapiro SM_FILE_T *fp; 45490792Sgshapiro int what; 45590792Sgshapiro void *valp; 45664562Sgshapiro{ 45790792Sgshapiro struct tls_obj *so = (struct tls_obj *) fp->f_cookie; 45864562Sgshapiro 45990792Sgshapiro switch (what) 46064562Sgshapiro { 46190792Sgshapiro case SM_IO_WHAT_FD: 46290792Sgshapiro if (so->fp == NULL) 46390792Sgshapiro return -1; 46490792Sgshapiro return so->fp->f_file; /* for stdio fileno() compatability */ 46564562Sgshapiro 46690792Sgshapiro case SM_IO_IS_READABLE: 46790792Sgshapiro return SSL_pending(so->con) > 0; 46890792Sgshapiro 46990792Sgshapiro default: 47090792Sgshapiro return -1; 47190792Sgshapiro } 47290792Sgshapiro} 47390792Sgshapiro 47464562Sgshapiro/* 47590792Sgshapiro** TLS_OPEN -- creates the tls specific information for opening a 47690792Sgshapiro** file of the tls type. 47790792Sgshapiro** 47890792Sgshapiro** Parameters: 47990792Sgshapiro** fp -- the file pointer associated with the new open 48090792Sgshapiro** info -- the sm_io file pointer holding the open and the 48190792Sgshapiro** TLS encryption connection to be read from or written to 48290792Sgshapiro** flags -- ignored 48390792Sgshapiro** rpool -- ignored 48490792Sgshapiro** 48590792Sgshapiro** Returns: 48690792Sgshapiro** 0 on success 48764562Sgshapiro*/ 48890792Sgshapiro 48990792Sgshapirostatic int tls_open __P((SM_FILE_T *, const void *, int, const void *)); 49090792Sgshapiro 49190792Sgshapiro/* ARGSUSED2 */ 49290792Sgshapirostatic int 49390792Sgshapirotls_open(fp, info, flags, rpool) 49490792Sgshapiro SM_FILE_T *fp; 49590792Sgshapiro const void *info; 49690792Sgshapiro int flags; 49790792Sgshapiro const void *rpool; 49890792Sgshapiro{ 49990792Sgshapiro struct tls_obj *so; 50090792Sgshapiro struct tls_info *ti = (struct tls_info *) info; 50190792Sgshapiro 50290792Sgshapiro so = (struct tls_obj *) sm_malloc(sizeof(struct tls_obj)); 503120256Sgshapiro if (so == NULL) 504120256Sgshapiro { 505120256Sgshapiro errno = ENOMEM; 506120256Sgshapiro return -1; 507120256Sgshapiro } 50890792Sgshapiro so->fp = ti->fp; 50990792Sgshapiro so->con = ti->con; 51090792Sgshapiro 51190792Sgshapiro /* 51290792Sgshapiro ** We try to get the "raw" file descriptor that TLS uses to 51390792Sgshapiro ** do the actual read/write with. This is to allow us control 51490792Sgshapiro ** over the file descriptor being a blocking or non-blocking type. 51590792Sgshapiro ** Under the covers TLS handles the change and this allows us 51690792Sgshapiro ** to do timeouts with sm_io. 51790792Sgshapiro */ 51890792Sgshapiro 51990792Sgshapiro fp->f_file = sm_io_getinfo(so->fp, SM_IO_WHAT_FD, NULL); 52090792Sgshapiro (void) sm_io_setvbuf(so->fp, SM_TIME_DEFAULT, NULL, SM_IO_NOW, 0); 52190792Sgshapiro fp->f_cookie = so; 52290792Sgshapiro return 0; 52390792Sgshapiro} 52490792Sgshapiro 52590792Sgshapiro/* 52690792Sgshapiro** TLS_CLOSE -- close the tls specific parts of the tls file pointer 52790792Sgshapiro** 52890792Sgshapiro** Parameters: 52990792Sgshapiro** fp -- the file pointer to close 53090792Sgshapiro** 53190792Sgshapiro** Returns: 53290792Sgshapiro** 0 on success 53390792Sgshapiro*/ 53490792Sgshapiro 53590792Sgshapirostatic int tls_close __P((SM_FILE_T *)); 53690792Sgshapiro 53790792Sgshapirostatic int 53890792Sgshapirotls_close(fp) 53990792Sgshapiro SM_FILE_T *fp; 54090792Sgshapiro{ 54190792Sgshapiro struct tls_obj *so; 54290792Sgshapiro 54390792Sgshapiro so = (struct tls_obj *) fp->f_cookie; 544120256Sgshapiro if (so == NULL) 545120256Sgshapiro return 0; 54690792Sgshapiro if (so->fp != NULL) 54790792Sgshapiro { 54890792Sgshapiro sm_io_close(so->fp, SM_TIME_DEFAULT); 54990792Sgshapiro so->fp = NULL; 55064562Sgshapiro } 55190792Sgshapiro sm_free(so); 55290792Sgshapiro so = NULL; 55390792Sgshapiro return 0; 55464562Sgshapiro} 55564562Sgshapiro 55690792Sgshapiro/* maximum number of retries for TLS related I/O due to handshakes */ 55790792Sgshapiro# define MAX_TLS_IOS 4 55890792Sgshapiro 55990792Sgshapiro/* 560157001Sgshapiro** TLS_RETRY -- check whether a failed SSL operation can be retried 561157001Sgshapiro** 562157001Sgshapiro** Parameters: 563157001Sgshapiro** ssl -- TLS structure 564157001Sgshapiro** rfd -- read fd 565157001Sgshapiro** wfd -- write fd 566157001Sgshapiro** tlsstart -- start time of TLS operation 567157001Sgshapiro** timeout -- timeout for TLS operation 568157001Sgshapiro** err -- SSL error 569157001Sgshapiro** where -- description of operation 570157001Sgshapiro** 571157001Sgshapiro** Results: 572157001Sgshapiro** >0 on success 573157001Sgshapiro** 0 on timeout 574157001Sgshapiro** <0 on error 575157001Sgshapiro*/ 576157001Sgshapiro 577157001Sgshapiroint 578157001Sgshapirotls_retry(ssl, rfd, wfd, tlsstart, timeout, err, where) 579157001Sgshapiro SSL *ssl; 580157001Sgshapiro int rfd; 581157001Sgshapiro int wfd; 582157001Sgshapiro time_t tlsstart; 583157001Sgshapiro int timeout; 584157001Sgshapiro int err; 585157001Sgshapiro const char *where; 586157001Sgshapiro{ 587157001Sgshapiro int ret; 588157001Sgshapiro time_t left; 589157001Sgshapiro time_t now = curtime(); 590157001Sgshapiro struct timeval tv; 591157001Sgshapiro 592157001Sgshapiro ret = -1; 593157001Sgshapiro 594157001Sgshapiro /* 595157001Sgshapiro ** For SSL_ERROR_WANT_{READ,WRITE}: 596157001Sgshapiro ** There is not a complete SSL record available yet 597157001Sgshapiro ** or there is only a partial SSL record removed from 598157001Sgshapiro ** the network (socket) buffer into the SSL buffer. 599157001Sgshapiro ** The SSL_connect will only succeed when a full 600157001Sgshapiro ** SSL record is available (assuming a "real" error 601157001Sgshapiro ** doesn't happen). To handle when a "real" error 602157001Sgshapiro ** does happen the select is set for exceptions too. 603157001Sgshapiro ** The connection may be re-negotiated during this time 604157001Sgshapiro ** so both read and write "want errors" need to be handled. 605157001Sgshapiro ** A select() exception loops back so that a proper SSL 606157001Sgshapiro ** error message can be gotten. 607157001Sgshapiro */ 608157001Sgshapiro 609157001Sgshapiro left = timeout - (now - tlsstart); 610157001Sgshapiro if (left <= 0) 611157001Sgshapiro return 0; /* timeout */ 612157001Sgshapiro tv.tv_sec = left; 613157001Sgshapiro tv.tv_usec = 0; 614157001Sgshapiro 615157001Sgshapiro if (LogLevel > 14) 616157001Sgshapiro { 617157001Sgshapiro sm_syslog(LOG_INFO, NOQID, 618157001Sgshapiro "STARTTLS=%s, info: fds=%d/%d, err=%d", 619157001Sgshapiro where, rfd, wfd, err); 620157001Sgshapiro } 621157001Sgshapiro 622285303Sgshapiro if ((err == SSL_ERROR_WANT_READ && !SM_FD_OK_SELECT(rfd)) || 623285303Sgshapiro (err == SSL_ERROR_WANT_WRITE && !SM_FD_OK_SELECT(wfd))) 624157001Sgshapiro { 625157001Sgshapiro if (LogLevel > 5) 626157001Sgshapiro { 627157001Sgshapiro sm_syslog(LOG_ERR, NOQID, 628157001Sgshapiro "STARTTLS=%s, error: fd %d/%d too large", 629157001Sgshapiro where, rfd, wfd); 630285303Sgshapiro if (LogLevel > 8) 631285303Sgshapiro tlslogerr(LOG_WARNING, where); 632157001Sgshapiro } 633157001Sgshapiro errno = EINVAL; 634157001Sgshapiro } 635157001Sgshapiro else if (err == SSL_ERROR_WANT_READ) 636157001Sgshapiro { 637157001Sgshapiro fd_set ssl_maskr, ssl_maskx; 638249729Sgshapiro int save_errno = errno; 639157001Sgshapiro 640157001Sgshapiro FD_ZERO(&ssl_maskr); 641157001Sgshapiro FD_SET(rfd, &ssl_maskr); 642157001Sgshapiro FD_ZERO(&ssl_maskx); 643157001Sgshapiro FD_SET(rfd, &ssl_maskx); 644157001Sgshapiro do 645157001Sgshapiro { 646157001Sgshapiro ret = select(rfd + 1, &ssl_maskr, NULL, &ssl_maskx, 647157001Sgshapiro &tv); 648157001Sgshapiro } while (ret < 0 && errno == EINTR); 649157001Sgshapiro if (ret < 0 && errno > 0) 650157001Sgshapiro ret = -errno; 651249729Sgshapiro errno = save_errno; 652157001Sgshapiro } 653157001Sgshapiro else if (err == SSL_ERROR_WANT_WRITE) 654157001Sgshapiro { 655157001Sgshapiro fd_set ssl_maskw, ssl_maskx; 656249729Sgshapiro int save_errno = errno; 657157001Sgshapiro 658157001Sgshapiro FD_ZERO(&ssl_maskw); 659157001Sgshapiro FD_SET(wfd, &ssl_maskw); 660157001Sgshapiro FD_ZERO(&ssl_maskx); 661157001Sgshapiro FD_SET(rfd, &ssl_maskx); 662157001Sgshapiro do 663157001Sgshapiro { 664157001Sgshapiro ret = select(wfd + 1, NULL, &ssl_maskw, &ssl_maskx, 665157001Sgshapiro &tv); 666157001Sgshapiro } while (ret < 0 && errno == EINTR); 667157001Sgshapiro if (ret < 0 && errno > 0) 668157001Sgshapiro ret = -errno; 669249729Sgshapiro errno = save_errno; 670157001Sgshapiro } 671157001Sgshapiro return ret; 672157001Sgshapiro} 673157001Sgshapiro 674157001Sgshapiro/* errno to force refill() etc to stop (see IS_IO_ERROR()) */ 675157001Sgshapiro#ifdef ETIMEDOUT 676157001Sgshapiro# define SM_ERR_TIMEOUT ETIMEDOUT 677157001Sgshapiro#else /* ETIMEDOUT */ 678157001Sgshapiro# define SM_ERR_TIMEOUT EIO 679157001Sgshapiro#endif /* ETIMEDOUT */ 680157001Sgshapiro 681157001Sgshapiro/* 682182352Sgshapiro** SET_TLS_RD_TMO -- read secured information for the caller 683182352Sgshapiro** 684182352Sgshapiro** Parameters: 685182352Sgshapiro** rd_tmo -- read timeout 686182352Sgshapiro** 687182352Sgshapiro** Results: 688285303Sgshapiro** previous read timeout 689182352Sgshapiro** This is a hack: there is no way to pass it in 690182352Sgshapiro*/ 691182352Sgshapiro 692182352Sgshapirostatic int tls_rd_tmo = -1; 693182352Sgshapiro 694285303Sgshapiroint 695182352Sgshapiroset_tls_rd_tmo(rd_tmo) 696182352Sgshapiro int rd_tmo; 697182352Sgshapiro{ 698285303Sgshapiro int old_rd_tmo; 699285303Sgshapiro 700285303Sgshapiro old_rd_tmo = tls_rd_tmo; 701182352Sgshapiro tls_rd_tmo = rd_tmo; 702285303Sgshapiro return old_rd_tmo; 703182352Sgshapiro} 704182352Sgshapiro 705182352Sgshapiro/* 70690792Sgshapiro** TLS_READ -- read secured information for the caller 70790792Sgshapiro** 70890792Sgshapiro** Parameters: 70990792Sgshapiro** fp -- the file pointer 71090792Sgshapiro** buf -- the location to place the data 71190792Sgshapiro** size -- the number of bytes to read from connection 71290792Sgshapiro** 71390792Sgshapiro** Results: 71490792Sgshapiro** -1 on error 71590792Sgshapiro** otherwise the number of bytes read 71690792Sgshapiro*/ 71790792Sgshapiro 71890792Sgshapirostatic ssize_t tls_read __P((SM_FILE_T *, char *, size_t)); 71990792Sgshapiro 72064562Sgshapirostatic ssize_t 72190792Sgshapirotls_read(fp, buf, size) 72290792Sgshapiro SM_FILE_T *fp; 72390792Sgshapiro char *buf; 72464562Sgshapiro size_t size; 72564562Sgshapiro{ 726157001Sgshapiro int r, rfd, wfd, try, ssl_err; 72790792Sgshapiro struct tls_obj *so = (struct tls_obj *) fp->f_cookie; 728157001Sgshapiro time_t tlsstart; 72990792Sgshapiro char *err; 73064562Sgshapiro 731157001Sgshapiro try = 99; 732157001Sgshapiro err = NULL; 733157001Sgshapiro tlsstart = curtime(); 734157001Sgshapiro 735157001Sgshapiro retry: 73690792Sgshapiro r = SSL_read(so->con, (char *) buf, size); 73764562Sgshapiro 73890792Sgshapiro if (r > 0) 73990792Sgshapiro return r; 74064562Sgshapiro 74190792Sgshapiro err = NULL; 742157001Sgshapiro switch (ssl_err = SSL_get_error(so->con, r)) 74390792Sgshapiro { 74490792Sgshapiro case SSL_ERROR_NONE: 74590792Sgshapiro case SSL_ERROR_ZERO_RETURN: 74690792Sgshapiro break; 74790792Sgshapiro case SSL_ERROR_WANT_WRITE: 748157001Sgshapiro err = "read W BLOCK"; 749157001Sgshapiro /* FALLTHROUGH */ 75090792Sgshapiro case SSL_ERROR_WANT_READ: 751157001Sgshapiro if (err == NULL) 75290792Sgshapiro err = "read R BLOCK"; 753157001Sgshapiro rfd = SSL_get_rfd(so->con); 754157001Sgshapiro wfd = SSL_get_wfd(so->con); 755157001Sgshapiro try = tls_retry(so->con, rfd, wfd, tlsstart, 756182352Sgshapiro (tls_rd_tmo < 0) ? TimeOuts.to_datablock 757182352Sgshapiro : tls_rd_tmo, 758182352Sgshapiro ssl_err, "read"); 759157001Sgshapiro if (try > 0) 760157001Sgshapiro goto retry; 761157001Sgshapiro errno = SM_ERR_TIMEOUT; 76290792Sgshapiro break; 763157001Sgshapiro 76490792Sgshapiro case SSL_ERROR_WANT_X509_LOOKUP: 76590792Sgshapiro err = "write X BLOCK"; 76690792Sgshapiro break; 76790792Sgshapiro case SSL_ERROR_SYSCALL: 76890792Sgshapiro if (r == 0 && errno == 0) /* out of protocol EOF found */ 76990792Sgshapiro break; 77090792Sgshapiro err = "syscall error"; 77164562Sgshapiro/* 77290792Sgshapiro get_last_socket_error()); 77364562Sgshapiro*/ 77490792Sgshapiro break; 77590792Sgshapiro case SSL_ERROR_SSL: 776141858Sgshapiro#if DEAL_WITH_ERROR_SSL 777102528Sgshapiro if (r == 0 && errno == 0) /* out of protocol EOF found */ 778102528Sgshapiro break; 779141858Sgshapiro#endif /* DEAL_WITH_ERROR_SSL */ 78090792Sgshapiro err = "generic SSL error"; 781249729Sgshapiro 78290792Sgshapiro if (LogLevel > 9) 783249729Sgshapiro { 784249729Sgshapiro int pri; 785102528Sgshapiro 786249729Sgshapiro if (errno == EAGAIN && try > 0) 787249729Sgshapiro pri = LOG_DEBUG; 788249729Sgshapiro else 789249729Sgshapiro pri = LOG_WARNING; 790249729Sgshapiro tlslogerr(pri, "read"); 791249729Sgshapiro } 792249729Sgshapiro 793141858Sgshapiro#if DEAL_WITH_ERROR_SSL 794102528Sgshapiro /* avoid repeated calls? */ 795102528Sgshapiro if (r == 0) 796102528Sgshapiro r = -1; 797141858Sgshapiro#endif /* DEAL_WITH_ERROR_SSL */ 79890792Sgshapiro break; 79964562Sgshapiro } 80090792Sgshapiro if (err != NULL) 80190792Sgshapiro { 80294334Sgshapiro int save_errno; 80394334Sgshapiro 80494334Sgshapiro save_errno = (errno == 0) ? EIO : errno; 805157001Sgshapiro if (try == 0 && save_errno == SM_ERR_TIMEOUT) 806157001Sgshapiro { 807157001Sgshapiro if (LogLevel > 7) 808157001Sgshapiro sm_syslog(LOG_WARNING, NOQID, 809157001Sgshapiro "STARTTLS: read error=timeout"); 810157001Sgshapiro } 811157001Sgshapiro else if (LogLevel > 8) 812249729Sgshapiro { 813249729Sgshapiro int pri; 814249729Sgshapiro 815249729Sgshapiro if (save_errno == EAGAIN && try > 0) 816249729Sgshapiro pri = LOG_DEBUG; 817249729Sgshapiro else 818249729Sgshapiro pri = LOG_WARNING; 819249729Sgshapiro sm_syslog(pri, NOQID, 820157001Sgshapiro "STARTTLS: read error=%s (%d), errno=%d, get_error=%s, retry=%d, ssl_err=%d", 821120256Sgshapiro err, r, errno, 822157001Sgshapiro ERR_error_string(ERR_get_error(), NULL), try, 823157001Sgshapiro ssl_err); 824249729Sgshapiro } 825120256Sgshapiro else if (LogLevel > 7) 826120256Sgshapiro sm_syslog(LOG_WARNING, NOQID, 827285303Sgshapiro "STARTTLS: read error=%s (%d), errno=%d, retry=%d, ssl_err=%d", 828157001Sgshapiro err, r, errno, try, ssl_err); 82994334Sgshapiro errno = save_errno; 83090792Sgshapiro } 83164562Sgshapiro return r; 83264562Sgshapiro} 83364562Sgshapiro 83490792Sgshapiro/* 83590792Sgshapiro** TLS_WRITE -- write information out through secure connection 83690792Sgshapiro** 83790792Sgshapiro** Parameters: 83890792Sgshapiro** fp -- the file pointer 83990792Sgshapiro** buf -- holds the data to be securely written 84090792Sgshapiro** size -- the number of bytes to write 84190792Sgshapiro** 84290792Sgshapiro** Returns: 84390792Sgshapiro** -1 on error 84490792Sgshapiro** otherwise number of bytes written 84590792Sgshapiro*/ 84690792Sgshapiro 84790792Sgshapirostatic ssize_t tls_write __P((SM_FILE_T *, const char *, size_t)); 84890792Sgshapiro 84990792Sgshapirostatic ssize_t 85090792Sgshapirotls_write(fp, buf, size) 85190792Sgshapiro SM_FILE_T *fp; 85290792Sgshapiro const char *buf; 85390792Sgshapiro size_t size; 85464562Sgshapiro{ 855157001Sgshapiro int r, rfd, wfd, try, ssl_err; 85690792Sgshapiro struct tls_obj *so = (struct tls_obj *) fp->f_cookie; 857157001Sgshapiro time_t tlsstart; 85890792Sgshapiro char *err; 85964562Sgshapiro 860157001Sgshapiro try = 99; 861157001Sgshapiro err = NULL; 862157001Sgshapiro tlsstart = curtime(); 863157001Sgshapiro 864157001Sgshapiro retry: 86590792Sgshapiro r = SSL_write(so->con, (char *) buf, size); 86664562Sgshapiro 86790792Sgshapiro if (r > 0) 86890792Sgshapiro return r; 86990792Sgshapiro err = NULL; 870157001Sgshapiro switch (ssl_err = SSL_get_error(so->con, r)) 87190792Sgshapiro { 87290792Sgshapiro case SSL_ERROR_NONE: 87390792Sgshapiro case SSL_ERROR_ZERO_RETURN: 87490792Sgshapiro break; 87590792Sgshapiro case SSL_ERROR_WANT_WRITE: 876157001Sgshapiro err = "read W BLOCK"; 877157001Sgshapiro /* FALLTHROUGH */ 87890792Sgshapiro case SSL_ERROR_WANT_READ: 879157001Sgshapiro if (err == NULL) 880157001Sgshapiro err = "read R BLOCK"; 881157001Sgshapiro rfd = SSL_get_rfd(so->con); 882157001Sgshapiro wfd = SSL_get_wfd(so->con); 883157001Sgshapiro try = tls_retry(so->con, rfd, wfd, tlsstart, 884157001Sgshapiro DATA_PROGRESS_TIMEOUT, ssl_err, "write"); 885157001Sgshapiro if (try > 0) 886157001Sgshapiro goto retry; 887157001Sgshapiro errno = SM_ERR_TIMEOUT; 88890792Sgshapiro break; 88990792Sgshapiro case SSL_ERROR_WANT_X509_LOOKUP: 89090792Sgshapiro err = "write X BLOCK"; 89190792Sgshapiro break; 89290792Sgshapiro case SSL_ERROR_SYSCALL: 89390792Sgshapiro if (r == 0 && errno == 0) /* out of protocol EOF found */ 89490792Sgshapiro break; 89590792Sgshapiro err = "syscall error"; 89690792Sgshapiro/* 89790792Sgshapiro get_last_socket_error()); 89890792Sgshapiro*/ 89990792Sgshapiro break; 90090792Sgshapiro case SSL_ERROR_SSL: 90190792Sgshapiro err = "generic SSL error"; 90290792Sgshapiro/* 90390792Sgshapiro ERR_GET_REASON(ERR_peek_error())); 90490792Sgshapiro*/ 90590792Sgshapiro if (LogLevel > 9) 906249729Sgshapiro tlslogerr(LOG_WARNING, "write"); 907102528Sgshapiro 908141858Sgshapiro#if DEAL_WITH_ERROR_SSL 909102528Sgshapiro /* avoid repeated calls? */ 910102528Sgshapiro if (r == 0) 911102528Sgshapiro r = -1; 912141858Sgshapiro#endif /* DEAL_WITH_ERROR_SSL */ 91390792Sgshapiro break; 91490792Sgshapiro } 91590792Sgshapiro if (err != NULL) 91690792Sgshapiro { 91794334Sgshapiro int save_errno; 91894334Sgshapiro 91994334Sgshapiro save_errno = (errno == 0) ? EIO : errno; 920157001Sgshapiro if (try == 0 && save_errno == SM_ERR_TIMEOUT) 921157001Sgshapiro { 922157001Sgshapiro if (LogLevel > 7) 923157001Sgshapiro sm_syslog(LOG_WARNING, NOQID, 924157001Sgshapiro "STARTTLS: write error=timeout"); 925157001Sgshapiro } 926157001Sgshapiro else if (LogLevel > 8) 92790792Sgshapiro sm_syslog(LOG_WARNING, NOQID, 928157001Sgshapiro "STARTTLS: write error=%s (%d), errno=%d, get_error=%s, retry=%d, ssl_err=%d", 929120256Sgshapiro err, r, errno, 930157001Sgshapiro ERR_error_string(ERR_get_error(), NULL), try, 931157001Sgshapiro ssl_err); 932120256Sgshapiro else if (LogLevel > 7) 933120256Sgshapiro sm_syslog(LOG_WARNING, NOQID, 934157001Sgshapiro "STARTTLS: write error=%s (%d), errno=%d, retry=%d, ssl_err=%d", 935157001Sgshapiro err, r, errno, try, ssl_err); 93694334Sgshapiro errno = save_errno; 93790792Sgshapiro } 93890792Sgshapiro return r; 93964562Sgshapiro} 94064562Sgshapiro 94190792Sgshapiro/* 94290792Sgshapiro** SFDCTLS -- create tls file type and open in and out file pointers 94390792Sgshapiro** for sendmail to read from and write to. 94490792Sgshapiro** 94590792Sgshapiro** Parameters: 94690792Sgshapiro** fin -- data input source being replaced 94790792Sgshapiro** fout -- data output source being replaced 948120256Sgshapiro** con -- the tls connection pointer 94990792Sgshapiro** 95090792Sgshapiro** Returns: 95190792Sgshapiro** -1 on error 95290792Sgshapiro** 0 on success 95390792Sgshapiro** 95490792Sgshapiro** Side effects: 95590792Sgshapiro** The arguments "fin" and "fout" are replaced with the new 95690792Sgshapiro** SM_FILE_T pointers. 95790792Sgshapiro** The original "fin" and "fout" are preserved in the tls file 95890792Sgshapiro** type but are not actually used because of the design of TLS. 95990792Sgshapiro*/ 96090792Sgshapiro 96164562Sgshapiroint 96264562Sgshapirosfdctls(fin, fout, con) 96390792Sgshapiro SM_FILE_T **fin; 96490792Sgshapiro SM_FILE_T **fout; 96564562Sgshapiro SSL *con; 96664562Sgshapiro{ 96790792Sgshapiro SM_FILE_T *tlsin, *tlsout; 96890792Sgshapiro SM_FILE_T SM_IO_SET_TYPE(tls_vector, "tls", tls_open, tls_close, 96990792Sgshapiro tls_read, tls_write, NULL, tls_getinfo, NULL, 97090792Sgshapiro SM_TIME_FOREVER); 97190792Sgshapiro struct tls_info info; 97264562Sgshapiro 97390792Sgshapiro SM_ASSERT(con != NULL); 97464562Sgshapiro 97590792Sgshapiro SM_IO_INIT_TYPE(tls_vector, "tls", tls_open, tls_close, 97690792Sgshapiro tls_read, tls_write, NULL, tls_getinfo, NULL, 97790792Sgshapiro SM_TIME_FOREVER); 97890792Sgshapiro info.fp = *fin; 97990792Sgshapiro info.con = con; 980132943Sgshapiro tlsin = sm_io_open(&tls_vector, SM_TIME_DEFAULT, &info, SM_IO_RDONLY_B, 98190792Sgshapiro NULL); 98290792Sgshapiro if (tlsin == NULL) 98390792Sgshapiro return -1; 98464562Sgshapiro 98590792Sgshapiro info.fp = *fout; 986132943Sgshapiro tlsout = sm_io_open(&tls_vector, SM_TIME_DEFAULT, &info, SM_IO_WRONLY_B, 98790792Sgshapiro NULL); 98890792Sgshapiro if (tlsout == NULL) 98966494Sgshapiro { 99090792Sgshapiro (void) sm_io_close(tlsin, SM_TIME_DEFAULT); 99166494Sgshapiro return -1; 99266494Sgshapiro } 99390792Sgshapiro sm_io_automode(tlsin, tlsout); 99464562Sgshapiro 99590792Sgshapiro *fin = tlsin; 99690792Sgshapiro *fout = tlsout; 99764562Sgshapiro return 0; 99864562Sgshapiro} 99990792Sgshapiro#endif /* STARTTLS */ 1000