164562Sgshapiro/* 2261194Sgshapiro * 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> 12266527SgshapiroSM_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> 16285229Sgshapiro#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 22363466Sgshapiro#endif 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; 69363466Sgshapiro return so->fp->f_file; /* for stdio fileno() compatibility */ 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; 196363466Sgshapiro# else 19771345Sgshapiro static char *outbuf = NULL; 198363466Sgshapiro# endif 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) 217363466Sgshapiro# else 21871345Sgshapiro while (outbuf == NULL && outlen == 0) 219363466Sgshapiro# endif 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); 258363466Sgshapiro# endif 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; 290363466Sgshapiro# else 29164562Sgshapiro char *outbuf; 292363466Sgshapiro# endif 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, 302363466Sgshapiro ** digestmd5 subtracts 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); 342363466Sgshapiro# endif 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" 419363466Sgshapiro# include <tls.h> 420285229Sgshapiro# include <openssl/err.h> 42190792Sgshapiro 42290792Sgshapiro/* Structure used by the "tls" file type */ 42390792Sgshapirostruct tls_obj 42490792Sgshapiro{ 42590792Sgshapiro SM_FILE_T *fp; 42690792Sgshapiro SSL *con; 42790792Sgshapiro}; 42890792Sgshapiro 42990792Sgshapirostruct tls_info 43090792Sgshapiro{ 43190792Sgshapiro SM_FILE_T *fp; 43290792Sgshapiro SSL *con; 43390792Sgshapiro}; 43490792Sgshapiro 43564562Sgshapiro/* 43690792Sgshapiro** TLS_GETINFO - returns requested information about a "tls" file 43790792Sgshapiro** descriptor. 43890792Sgshapiro** 43990792Sgshapiro** Parameters: 44090792Sgshapiro** fp -- the file descriptor 44190792Sgshapiro** what -- the type of information requested 44290792Sgshapiro** valp -- the thang to return the information in (unused) 44390792Sgshapiro** 44490792Sgshapiro** Returns: 44590792Sgshapiro** -1 for unknown requests 44690792Sgshapiro** >=0 on success with valp filled in (if possible). 44764562Sgshapiro*/ 44864562Sgshapiro 44990792Sgshapirostatic int tls_getinfo __P((SM_FILE_T *, int, void *)); 45064562Sgshapiro 45190792Sgshapiro/* ARGSUSED2 */ 45280785Sgshapirostatic int 45390792Sgshapirotls_getinfo(fp, what, valp) 45490792Sgshapiro SM_FILE_T *fp; 45590792Sgshapiro int what; 45690792Sgshapiro void *valp; 45764562Sgshapiro{ 45890792Sgshapiro struct tls_obj *so = (struct tls_obj *) fp->f_cookie; 45964562Sgshapiro 46090792Sgshapiro switch (what) 46164562Sgshapiro { 46290792Sgshapiro case SM_IO_WHAT_FD: 46390792Sgshapiro if (so->fp == NULL) 46490792Sgshapiro return -1; 465363466Sgshapiro return so->fp->f_file; /* for stdio fileno() compatibility */ 46664562Sgshapiro 46790792Sgshapiro case SM_IO_IS_READABLE: 46890792Sgshapiro return SSL_pending(so->con) > 0; 46990792Sgshapiro 47090792Sgshapiro default: 47190792Sgshapiro return -1; 47290792Sgshapiro } 47390792Sgshapiro} 47490792Sgshapiro 47564562Sgshapiro/* 47690792Sgshapiro** TLS_OPEN -- creates the tls specific information for opening a 47790792Sgshapiro** file of the tls type. 47890792Sgshapiro** 47990792Sgshapiro** Parameters: 48090792Sgshapiro** fp -- the file pointer associated with the new open 48190792Sgshapiro** info -- the sm_io file pointer holding the open and the 48290792Sgshapiro** TLS encryption connection to be read from or written to 48390792Sgshapiro** flags -- ignored 48490792Sgshapiro** rpool -- ignored 48590792Sgshapiro** 48690792Sgshapiro** Returns: 48790792Sgshapiro** 0 on success 48864562Sgshapiro*/ 48990792Sgshapiro 49090792Sgshapirostatic int tls_open __P((SM_FILE_T *, const void *, int, const void *)); 49190792Sgshapiro 49290792Sgshapiro/* ARGSUSED2 */ 49390792Sgshapirostatic int 49490792Sgshapirotls_open(fp, info, flags, rpool) 49590792Sgshapiro SM_FILE_T *fp; 49690792Sgshapiro const void *info; 49790792Sgshapiro int flags; 49890792Sgshapiro const void *rpool; 49990792Sgshapiro{ 50090792Sgshapiro struct tls_obj *so; 50190792Sgshapiro struct tls_info *ti = (struct tls_info *) info; 50290792Sgshapiro 50390792Sgshapiro so = (struct tls_obj *) sm_malloc(sizeof(struct tls_obj)); 504120256Sgshapiro if (so == NULL) 505120256Sgshapiro { 506120256Sgshapiro errno = ENOMEM; 507120256Sgshapiro return -1; 508120256Sgshapiro } 50990792Sgshapiro so->fp = ti->fp; 51090792Sgshapiro so->con = ti->con; 51190792Sgshapiro 51290792Sgshapiro /* 51390792Sgshapiro ** We try to get the "raw" file descriptor that TLS uses to 51490792Sgshapiro ** do the actual read/write with. This is to allow us control 51590792Sgshapiro ** over the file descriptor being a blocking or non-blocking type. 51690792Sgshapiro ** Under the covers TLS handles the change and this allows us 51790792Sgshapiro ** to do timeouts with sm_io. 51890792Sgshapiro */ 51990792Sgshapiro 52090792Sgshapiro fp->f_file = sm_io_getinfo(so->fp, SM_IO_WHAT_FD, NULL); 52190792Sgshapiro (void) sm_io_setvbuf(so->fp, SM_TIME_DEFAULT, NULL, SM_IO_NOW, 0); 52290792Sgshapiro fp->f_cookie = so; 52390792Sgshapiro return 0; 52490792Sgshapiro} 52590792Sgshapiro 52690792Sgshapiro/* 52790792Sgshapiro** TLS_CLOSE -- close the tls specific parts of the tls file pointer 52890792Sgshapiro** 52990792Sgshapiro** Parameters: 53090792Sgshapiro** fp -- the file pointer to close 53190792Sgshapiro** 53290792Sgshapiro** Returns: 53390792Sgshapiro** 0 on success 53490792Sgshapiro*/ 53590792Sgshapiro 53690792Sgshapirostatic int tls_close __P((SM_FILE_T *)); 53790792Sgshapiro 53890792Sgshapirostatic int 53990792Sgshapirotls_close(fp) 54090792Sgshapiro SM_FILE_T *fp; 54190792Sgshapiro{ 54290792Sgshapiro struct tls_obj *so; 54390792Sgshapiro 54490792Sgshapiro so = (struct tls_obj *) fp->f_cookie; 545120256Sgshapiro if (so == NULL) 546120256Sgshapiro return 0; 54790792Sgshapiro if (so->fp != NULL) 54890792Sgshapiro { 54990792Sgshapiro sm_io_close(so->fp, SM_TIME_DEFAULT); 55090792Sgshapiro so->fp = NULL; 55164562Sgshapiro } 55290792Sgshapiro sm_free(so); 55390792Sgshapiro so = NULL; 55490792Sgshapiro return 0; 55564562Sgshapiro} 55664562Sgshapiro 55790792Sgshapiro/* maximum number of retries for TLS related I/O due to handshakes */ 55890792Sgshapiro# define MAX_TLS_IOS 4 55990792Sgshapiro 56090792Sgshapiro/* 561157001Sgshapiro** TLS_RETRY -- check whether a failed SSL operation can be retried 562157001Sgshapiro** 563157001Sgshapiro** Parameters: 564157001Sgshapiro** ssl -- TLS structure 565157001Sgshapiro** rfd -- read fd 566157001Sgshapiro** wfd -- write fd 567157001Sgshapiro** tlsstart -- start time of TLS operation 568157001Sgshapiro** timeout -- timeout for TLS operation 569157001Sgshapiro** err -- SSL error 570157001Sgshapiro** where -- description of operation 571157001Sgshapiro** 572157001Sgshapiro** Results: 573157001Sgshapiro** >0 on success 574157001Sgshapiro** 0 on timeout 575157001Sgshapiro** <0 on error 576157001Sgshapiro*/ 577157001Sgshapiro 578157001Sgshapiroint 579157001Sgshapirotls_retry(ssl, rfd, wfd, tlsstart, timeout, err, where) 580157001Sgshapiro SSL *ssl; 581157001Sgshapiro int rfd; 582157001Sgshapiro int wfd; 583157001Sgshapiro time_t tlsstart; 584157001Sgshapiro int timeout; 585157001Sgshapiro int err; 586157001Sgshapiro const char *where; 587157001Sgshapiro{ 588157001Sgshapiro int ret; 589157001Sgshapiro time_t left; 590157001Sgshapiro time_t now = curtime(); 591157001Sgshapiro struct timeval tv; 592157001Sgshapiro 593157001Sgshapiro ret = -1; 594157001Sgshapiro 595157001Sgshapiro /* 596157001Sgshapiro ** For SSL_ERROR_WANT_{READ,WRITE}: 597157001Sgshapiro ** There is not a complete SSL record available yet 598157001Sgshapiro ** or there is only a partial SSL record removed from 599157001Sgshapiro ** the network (socket) buffer into the SSL buffer. 600157001Sgshapiro ** The SSL_connect will only succeed when a full 601157001Sgshapiro ** SSL record is available (assuming a "real" error 602157001Sgshapiro ** doesn't happen). To handle when a "real" error 603157001Sgshapiro ** does happen the select is set for exceptions too. 604157001Sgshapiro ** The connection may be re-negotiated during this time 605157001Sgshapiro ** so both read and write "want errors" need to be handled. 606157001Sgshapiro ** A select() exception loops back so that a proper SSL 607157001Sgshapiro ** error message can be gotten. 608157001Sgshapiro */ 609157001Sgshapiro 610157001Sgshapiro left = timeout - (now - tlsstart); 611157001Sgshapiro if (left <= 0) 612157001Sgshapiro return 0; /* timeout */ 613157001Sgshapiro tv.tv_sec = left; 614157001Sgshapiro tv.tv_usec = 0; 615157001Sgshapiro 616157001Sgshapiro if (LogLevel > 14) 617157001Sgshapiro { 618157001Sgshapiro sm_syslog(LOG_INFO, NOQID, 619157001Sgshapiro "STARTTLS=%s, info: fds=%d/%d, err=%d", 620157001Sgshapiro where, rfd, wfd, err); 621157001Sgshapiro } 622157001Sgshapiro 623285229Sgshapiro if ((err == SSL_ERROR_WANT_READ && !SM_FD_OK_SELECT(rfd)) || 624285229Sgshapiro (err == SSL_ERROR_WANT_WRITE && !SM_FD_OK_SELECT(wfd))) 625157001Sgshapiro { 626157001Sgshapiro if (LogLevel > 5) 627157001Sgshapiro { 628157001Sgshapiro sm_syslog(LOG_ERR, NOQID, 629157001Sgshapiro "STARTTLS=%s, error: fd %d/%d too large", 630157001Sgshapiro where, rfd, wfd); 631363466Sgshapiro tlslogerr(LOG_WARNING, 8, 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 677363466Sgshapiro#else 678157001Sgshapiro# define SM_ERR_TIMEOUT EIO 679363466Sgshapiro#endif 680157001Sgshapiro 681157001Sgshapiro/* 682182352Sgshapiro** SET_TLS_RD_TMO -- read secured information for the caller 683182352Sgshapiro** 684182352Sgshapiro** Parameters: 685182352Sgshapiro** rd_tmo -- read timeout 686182352Sgshapiro** 687182352Sgshapiro** Results: 688285229Sgshapiro** 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 694285229Sgshapiroint 695182352Sgshapiroset_tls_rd_tmo(rd_tmo) 696182352Sgshapiro int rd_tmo; 697182352Sgshapiro{ 698285229Sgshapiro int old_rd_tmo; 699285229Sgshapiro 700285229Sgshapiro old_rd_tmo = tls_rd_tmo; 701182352Sgshapiro tls_rd_tmo = rd_tmo; 702285229Sgshapiro 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"; 77190792Sgshapiro break; 77290792Sgshapiro case SSL_ERROR_SSL: 773141858Sgshapiro#if DEAL_WITH_ERROR_SSL 774102528Sgshapiro if (r == 0 && errno == 0) /* out of protocol EOF found */ 775102528Sgshapiro break; 776363466Sgshapiro#endif 77790792Sgshapiro err = "generic SSL error"; 778249729Sgshapiro 77990792Sgshapiro if (LogLevel > 9) 780249729Sgshapiro { 781249729Sgshapiro int pri; 782102528Sgshapiro 783249729Sgshapiro if (errno == EAGAIN && try > 0) 784249729Sgshapiro pri = LOG_DEBUG; 785249729Sgshapiro else 786249729Sgshapiro pri = LOG_WARNING; 787363466Sgshapiro tlslogerr(pri, 9, "read"); 788249729Sgshapiro } 789249729Sgshapiro 790141858Sgshapiro#if DEAL_WITH_ERROR_SSL 791102528Sgshapiro /* avoid repeated calls? */ 792102528Sgshapiro if (r == 0) 793102528Sgshapiro r = -1; 794363466Sgshapiro#endif 79590792Sgshapiro break; 79664562Sgshapiro } 79790792Sgshapiro if (err != NULL) 79890792Sgshapiro { 79994334Sgshapiro int save_errno; 80094334Sgshapiro 80194334Sgshapiro save_errno = (errno == 0) ? EIO : errno; 802157001Sgshapiro if (try == 0 && save_errno == SM_ERR_TIMEOUT) 803157001Sgshapiro { 804157001Sgshapiro if (LogLevel > 7) 805157001Sgshapiro sm_syslog(LOG_WARNING, NOQID, 806157001Sgshapiro "STARTTLS: read error=timeout"); 807157001Sgshapiro } 808157001Sgshapiro else if (LogLevel > 8) 809249729Sgshapiro { 810249729Sgshapiro int pri; 811249729Sgshapiro 812249729Sgshapiro if (save_errno == EAGAIN && try > 0) 813249729Sgshapiro pri = LOG_DEBUG; 814249729Sgshapiro else 815249729Sgshapiro pri = LOG_WARNING; 816249729Sgshapiro sm_syslog(pri, NOQID, 817157001Sgshapiro "STARTTLS: read error=%s (%d), errno=%d, get_error=%s, retry=%d, ssl_err=%d", 818120256Sgshapiro err, r, errno, 819157001Sgshapiro ERR_error_string(ERR_get_error(), NULL), try, 820157001Sgshapiro ssl_err); 821249729Sgshapiro } 822120256Sgshapiro else if (LogLevel > 7) 823120256Sgshapiro sm_syslog(LOG_WARNING, NOQID, 824285229Sgshapiro "STARTTLS: read error=%s (%d), errno=%d, retry=%d, ssl_err=%d", 825157001Sgshapiro err, r, errno, try, ssl_err); 82694334Sgshapiro errno = save_errno; 82790792Sgshapiro } 82864562Sgshapiro return r; 82964562Sgshapiro} 83064562Sgshapiro 83190792Sgshapiro/* 83290792Sgshapiro** TLS_WRITE -- write information out through secure connection 83390792Sgshapiro** 83490792Sgshapiro** Parameters: 83590792Sgshapiro** fp -- the file pointer 83690792Sgshapiro** buf -- holds the data to be securely written 83790792Sgshapiro** size -- the number of bytes to write 83890792Sgshapiro** 83990792Sgshapiro** Returns: 84090792Sgshapiro** -1 on error 84190792Sgshapiro** otherwise number of bytes written 84290792Sgshapiro*/ 84390792Sgshapiro 84490792Sgshapirostatic ssize_t tls_write __P((SM_FILE_T *, const char *, size_t)); 84590792Sgshapiro 84690792Sgshapirostatic ssize_t 84790792Sgshapirotls_write(fp, buf, size) 84890792Sgshapiro SM_FILE_T *fp; 84990792Sgshapiro const char *buf; 85090792Sgshapiro size_t size; 85164562Sgshapiro{ 852157001Sgshapiro int r, rfd, wfd, try, ssl_err; 85390792Sgshapiro struct tls_obj *so = (struct tls_obj *) fp->f_cookie; 854157001Sgshapiro time_t tlsstart; 85590792Sgshapiro char *err; 85664562Sgshapiro 857157001Sgshapiro try = 99; 858157001Sgshapiro err = NULL; 859157001Sgshapiro tlsstart = curtime(); 860157001Sgshapiro 861157001Sgshapiro retry: 86290792Sgshapiro r = SSL_write(so->con, (char *) buf, size); 86364562Sgshapiro 86490792Sgshapiro if (r > 0) 86590792Sgshapiro return r; 86690792Sgshapiro err = NULL; 867157001Sgshapiro switch (ssl_err = SSL_get_error(so->con, r)) 86890792Sgshapiro { 86990792Sgshapiro case SSL_ERROR_NONE: 87090792Sgshapiro case SSL_ERROR_ZERO_RETURN: 87190792Sgshapiro break; 87290792Sgshapiro case SSL_ERROR_WANT_WRITE: 873157001Sgshapiro err = "read W BLOCK"; 874157001Sgshapiro /* FALLTHROUGH */ 87590792Sgshapiro case SSL_ERROR_WANT_READ: 876157001Sgshapiro if (err == NULL) 877157001Sgshapiro err = "read R BLOCK"; 878157001Sgshapiro rfd = SSL_get_rfd(so->con); 879157001Sgshapiro wfd = SSL_get_wfd(so->con); 880157001Sgshapiro try = tls_retry(so->con, rfd, wfd, tlsstart, 881157001Sgshapiro DATA_PROGRESS_TIMEOUT, ssl_err, "write"); 882157001Sgshapiro if (try > 0) 883157001Sgshapiro goto retry; 884157001Sgshapiro errno = SM_ERR_TIMEOUT; 88590792Sgshapiro break; 88690792Sgshapiro case SSL_ERROR_WANT_X509_LOOKUP: 88790792Sgshapiro err = "write X BLOCK"; 88890792Sgshapiro break; 88990792Sgshapiro case SSL_ERROR_SYSCALL: 89090792Sgshapiro if (r == 0 && errno == 0) /* out of protocol EOF found */ 89190792Sgshapiro break; 89290792Sgshapiro err = "syscall error"; 89390792Sgshapiro break; 89490792Sgshapiro case SSL_ERROR_SSL: 89590792Sgshapiro err = "generic SSL error"; 89690792Sgshapiro/* 89790792Sgshapiro ERR_GET_REASON(ERR_peek_error())); 89890792Sgshapiro*/ 899363466Sgshapiro tlslogerr(LOG_WARNING, 9, "write"); 900102528Sgshapiro 901141858Sgshapiro#if DEAL_WITH_ERROR_SSL 902102528Sgshapiro /* avoid repeated calls? */ 903102528Sgshapiro if (r == 0) 904102528Sgshapiro r = -1; 905363466Sgshapiro#endif 90690792Sgshapiro break; 90790792Sgshapiro } 90890792Sgshapiro if (err != NULL) 90990792Sgshapiro { 91094334Sgshapiro int save_errno; 91194334Sgshapiro 91294334Sgshapiro save_errno = (errno == 0) ? EIO : errno; 913157001Sgshapiro if (try == 0 && save_errno == SM_ERR_TIMEOUT) 914157001Sgshapiro { 915157001Sgshapiro if (LogLevel > 7) 916157001Sgshapiro sm_syslog(LOG_WARNING, NOQID, 917157001Sgshapiro "STARTTLS: write error=timeout"); 918157001Sgshapiro } 919157001Sgshapiro else if (LogLevel > 8) 92090792Sgshapiro sm_syslog(LOG_WARNING, NOQID, 921157001Sgshapiro "STARTTLS: write error=%s (%d), errno=%d, get_error=%s, retry=%d, ssl_err=%d", 922120256Sgshapiro err, r, errno, 923157001Sgshapiro ERR_error_string(ERR_get_error(), NULL), try, 924157001Sgshapiro ssl_err); 925120256Sgshapiro else if (LogLevel > 7) 926120256Sgshapiro sm_syslog(LOG_WARNING, NOQID, 927157001Sgshapiro "STARTTLS: write error=%s (%d), errno=%d, retry=%d, ssl_err=%d", 928157001Sgshapiro err, r, errno, try, ssl_err); 92994334Sgshapiro errno = save_errno; 93090792Sgshapiro } 93190792Sgshapiro return r; 93264562Sgshapiro} 93364562Sgshapiro 93490792Sgshapiro/* 93590792Sgshapiro** SFDCTLS -- create tls file type and open in and out file pointers 93690792Sgshapiro** for sendmail to read from and write to. 93790792Sgshapiro** 93890792Sgshapiro** Parameters: 93990792Sgshapiro** fin -- data input source being replaced 94090792Sgshapiro** fout -- data output source being replaced 941120256Sgshapiro** con -- the tls connection pointer 94290792Sgshapiro** 94390792Sgshapiro** Returns: 94490792Sgshapiro** -1 on error 94590792Sgshapiro** 0 on success 94690792Sgshapiro** 94790792Sgshapiro** Side effects: 94890792Sgshapiro** The arguments "fin" and "fout" are replaced with the new 94990792Sgshapiro** SM_FILE_T pointers. 95090792Sgshapiro** The original "fin" and "fout" are preserved in the tls file 95190792Sgshapiro** type but are not actually used because of the design of TLS. 95290792Sgshapiro*/ 95390792Sgshapiro 95464562Sgshapiroint 95564562Sgshapirosfdctls(fin, fout, con) 95690792Sgshapiro SM_FILE_T **fin; 95790792Sgshapiro SM_FILE_T **fout; 95864562Sgshapiro SSL *con; 95964562Sgshapiro{ 96090792Sgshapiro SM_FILE_T *tlsin, *tlsout; 96190792Sgshapiro SM_FILE_T SM_IO_SET_TYPE(tls_vector, "tls", tls_open, tls_close, 96290792Sgshapiro tls_read, tls_write, NULL, tls_getinfo, NULL, 96390792Sgshapiro SM_TIME_FOREVER); 96490792Sgshapiro struct tls_info info; 96564562Sgshapiro 96690792Sgshapiro SM_ASSERT(con != NULL); 96764562Sgshapiro 96890792Sgshapiro SM_IO_INIT_TYPE(tls_vector, "tls", tls_open, tls_close, 96990792Sgshapiro tls_read, tls_write, NULL, tls_getinfo, NULL, 97090792Sgshapiro SM_TIME_FOREVER); 97190792Sgshapiro info.fp = *fin; 97290792Sgshapiro info.con = con; 973132943Sgshapiro tlsin = sm_io_open(&tls_vector, SM_TIME_DEFAULT, &info, SM_IO_RDONLY_B, 97490792Sgshapiro NULL); 97590792Sgshapiro if (tlsin == NULL) 97690792Sgshapiro return -1; 97764562Sgshapiro 97890792Sgshapiro info.fp = *fout; 979132943Sgshapiro tlsout = sm_io_open(&tls_vector, SM_TIME_DEFAULT, &info, SM_IO_WRONLY_B, 98090792Sgshapiro NULL); 98190792Sgshapiro if (tlsout == NULL) 98266494Sgshapiro { 98390792Sgshapiro (void) sm_io_close(tlsin, SM_TIME_DEFAULT); 98466494Sgshapiro return -1; 98566494Sgshapiro } 98690792Sgshapiro sm_io_automode(tlsin, tlsout); 98764562Sgshapiro 98890792Sgshapiro *fin = tlsin; 98990792Sgshapiro *fout = tlsout; 99064562Sgshapiro return 0; 99164562Sgshapiro} 99290792Sgshapiro#endif /* STARTTLS */ 993