diff options
Diffstat (limited to 'sendmail/src/sfsasl.c')
-rw-r--r-- | sendmail/src/sfsasl.c | 952 |
1 files changed, 952 insertions, 0 deletions
diff --git a/sendmail/src/sfsasl.c b/sendmail/src/sfsasl.c new file mode 100644 index 0000000..216d87e --- /dev/null +++ b/sendmail/src/sfsasl.c @@ -0,0 +1,952 @@ +/* + * Copyright (c) 1999-2006 Sendmail, Inc. and its suppliers. + * All rights reserved. + * + * By using this file, you agree to the terms and conditions set + * forth in the LICENSE file which can be found at the top level of + * the sendmail distribution. + * + */ + +#include <sm/gen.h> +SM_RCSID("@(#)$Id: sfsasl.c,v 8.115 2006/04/18 21:34:07 ca Exp $") +#include <stdlib.h> +#include <sendmail.h> +#include <sm/time.h> +#include <errno.h> + +/* allow to disable error handling code just in case... */ +#ifndef DEAL_WITH_ERROR_SSL +# define DEAL_WITH_ERROR_SSL 1 +#endif /* ! DEAL_WITH_ERROR_SSL */ + +#if SASL +# include "sfsasl.h" + +/* Structure used by the "sasl" file type */ +struct sasl_obj +{ + SM_FILE_T *fp; + sasl_conn_t *conn; +}; + +struct sasl_info +{ + SM_FILE_T *fp; + sasl_conn_t *conn; +}; + +/* +** SASL_GETINFO - returns requested information about a "sasl" file +** descriptor. +** +** Parameters: +** fp -- the file descriptor +** what -- the type of information requested +** valp -- the thang to return the information in +** +** Returns: +** -1 for unknown requests +** >=0 on success with valp filled in (if possible). +*/ + +static int sasl_getinfo __P((SM_FILE_T *, int, void *)); + +static int +sasl_getinfo(fp, what, valp) + SM_FILE_T *fp; + int what; + void *valp; +{ + struct sasl_obj *so = (struct sasl_obj *) fp->f_cookie; + + switch (what) + { + case SM_IO_WHAT_FD: + if (so->fp == NULL) + return -1; + return so->fp->f_file; /* for stdio fileno() compatability */ + + case SM_IO_IS_READABLE: + if (so->fp == NULL) + return 0; + + /* get info from underlying file */ + return sm_io_getinfo(so->fp, what, valp); + + default: + return -1; + } +} + +/* +** SASL_OPEN -- creates the sasl specific information for opening a +** file of the sasl type. +** +** Parameters: +** fp -- the file pointer associated with the new open +** info -- contains the sasl connection information pointer and +** the original SM_FILE_T that holds the open +** flags -- ignored +** rpool -- ignored +** +** Returns: +** 0 on success +*/ + +static int sasl_open __P((SM_FILE_T *, const void *, int, const void *)); + +/* ARGSUSED2 */ +static int +sasl_open(fp, info, flags, rpool) + SM_FILE_T *fp; + const void *info; + int flags; + const void *rpool; +{ + struct sasl_obj *so; + struct sasl_info *si = (struct sasl_info *) info; + + so = (struct sasl_obj *) sm_malloc(sizeof(struct sasl_obj)); + if (so == NULL) + { + errno = ENOMEM; + return -1; + } + so->fp = si->fp; + so->conn = si->conn; + + /* + ** The underlying 'fp' is set to SM_IO_NOW so that the entire + ** encoded string is written in one chunk. Otherwise there is + ** the possibility that it may appear illegal, bogus or + ** mangled to the other side of the connection. + ** We will read or write through 'fp' since it is the opaque + ** connection for the communications. We need to treat it this + ** way in case the encoded string is to be sent down a TLS + ** connection rather than, say, sm_io's stdio. + */ + + (void) sm_io_setvbuf(so->fp, SM_TIME_DEFAULT, NULL, SM_IO_NOW, 0); + fp->f_cookie = so; + return 0; +} + +/* +** SASL_CLOSE -- close the sasl specific parts of the sasl file pointer +** +** Parameters: +** fp -- the file pointer to close +** +** Returns: +** 0 on success +*/ + +static int sasl_close __P((SM_FILE_T *)); + +static int +sasl_close(fp) + SM_FILE_T *fp; +{ + struct sasl_obj *so; + + so = (struct sasl_obj *) fp->f_cookie; + if (so == NULL) + return 0; + if (so->fp != NULL) + { + sm_io_close(so->fp, SM_TIME_DEFAULT); + so->fp = NULL; + } + sm_free(so); + so = NULL; + return 0; +} + +/* how to deallocate a buffer allocated by SASL */ +extern void sm_sasl_free __P((void *)); +# define SASL_DEALLOC(b) sm_sasl_free(b) + +/* +** SASL_READ -- read encrypted information and decrypt it for the caller +** +** Parameters: +** fp -- the file pointer +** buf -- the location to place the decrypted information +** size -- the number of bytes to read after decryption +** +** Results: +** -1 on error +** otherwise the number of bytes read +*/ + +static ssize_t sasl_read __P((SM_FILE_T *, char *, size_t)); + +static ssize_t +sasl_read(fp, buf, size) + SM_FILE_T *fp; + char *buf; + size_t size; +{ + int result; + ssize_t len; +# if SASL >= 20000 + static const char *outbuf = NULL; +# else /* SASL >= 20000 */ + static char *outbuf = NULL; +# endif /* SASL >= 20000 */ + static unsigned int outlen = 0; + static unsigned int offset = 0; + struct sasl_obj *so = (struct sasl_obj *) fp->f_cookie; + + /* + ** sasl_decode() may require more data than a single read() returns. + ** Hence we have to put a loop around the decoding. + ** This also requires that we may have to split up the returned + ** data since it might be larger than the allowed size. + ** Therefore we use a static pointer and return portions of it + ** if necessary. + ** XXX Note: This function is not thread-safe nor can it be used + ** on more than one file. A correct implementation would store + ** this data in fp->f_cookie. + */ + +# if SASL >= 20000 + while (outlen == 0) +# else /* SASL >= 20000 */ + while (outbuf == NULL && outlen == 0) +# endif /* SASL >= 20000 */ + { + len = sm_io_read(so->fp, SM_TIME_DEFAULT, buf, size); + if (len <= 0) + return len; + result = sasl_decode(so->conn, buf, + (unsigned int) len, &outbuf, &outlen); + if (result != SASL_OK) + { + if (LogLevel > 7) + sm_syslog(LOG_WARNING, NOQID, + "AUTH: sasl_decode error=%d", result); + outbuf = NULL; + offset = 0; + outlen = 0; + return -1; + } + } + + if (outbuf == NULL) + { + /* be paranoid: outbuf == NULL but outlen != 0 */ + syserr("@sasl_read failure: outbuf == NULL but outlen != 0"); + /* NOTREACHED */ + } + if (outlen - offset > size) + { + /* return another part of the buffer */ + (void) memcpy(buf, outbuf + offset, size); + offset += size; + len = size; + } + else + { + /* return the rest of the buffer */ + len = outlen - offset; + (void) memcpy(buf, outbuf + offset, (size_t) len); +# if SASL < 20000 + SASL_DEALLOC(outbuf); +# endif /* SASL < 20000 */ + outbuf = NULL; + offset = 0; + outlen = 0; + } + return len; +} + +/* +** SASL_WRITE -- write information out after encrypting it +** +** Parameters: +** fp -- the file pointer +** buf -- holds the data to be encrypted and written +** size -- the number of bytes to have encrypted and written +** +** Returns: +** -1 on error +** otherwise number of bytes written +*/ + +static ssize_t sasl_write __P((SM_FILE_T *, const char *, size_t)); + +static ssize_t +sasl_write(fp, buf, size) + SM_FILE_T *fp; + const char *buf; + size_t size; +{ + int result; +# if SASL >= 20000 + const char *outbuf; +# else /* SASL >= 20000 */ + char *outbuf; +# endif /* SASL >= 20000 */ + unsigned int outlen, *maxencode; + size_t ret = 0, total = 0; + struct sasl_obj *so = (struct sasl_obj *) fp->f_cookie; + + /* + ** Fetch the maximum input buffer size for sasl_encode(). + ** This can be less than the size set in attemptauth() + ** due to a negotation with the other side, e.g., + ** Cyrus IMAP lmtp program sets maxbuf=4096, + ** digestmd5 substracts 25 and hence we'll get 4071 + ** instead of 8192 (MAXOUTLEN). + ** Hack (for now): simply reduce the size, callers are (must be) + ** able to deal with that and invoke sasl_write() again with + ** the rest of the data. + ** Note: it would be better to store this value in the context + ** after the negotiation. + */ + + result = sasl_getprop(so->conn, SASL_MAXOUTBUF, + (const void **) &maxencode); + if (result == SASL_OK && size > *maxencode && *maxencode > 0) + size = *maxencode; + + result = sasl_encode(so->conn, buf, + (unsigned int) size, &outbuf, &outlen); + + if (result != SASL_OK) + { + if (LogLevel > 7) + sm_syslog(LOG_WARNING, NOQID, + "AUTH: sasl_encode error=%d", result); + return -1; + } + + if (outbuf != NULL) + { + while (outlen > 0) + { + errno = 0; + /* XXX result == 0? */ + ret = sm_io_write(so->fp, SM_TIME_DEFAULT, + &outbuf[total], outlen); + if (ret <= 0) + return ret; + outlen -= ret; + total += ret; + } +# if SASL < 20000 + SASL_DEALLOC(outbuf); +# endif /* SASL < 20000 */ + } + return size; +} + +/* +** SFDCSASL -- create sasl file type and open in and out file pointers +** for sendmail to read from and write to. +** +** Parameters: +** fin -- the sm_io file encrypted data to be read from +** fout -- the sm_io file encrypted data to be written to +** conn -- the sasl connection pointer +** tmo -- timeout +** +** Returns: +** -1 on error +** 0 on success +** +** Side effects: +** The arguments "fin" and "fout" are replaced with the new +** SM_FILE_T pointers. +*/ + +int +sfdcsasl(fin, fout, conn, tmo) + SM_FILE_T **fin; + SM_FILE_T **fout; + sasl_conn_t *conn; + int tmo; +{ + SM_FILE_T *newin, *newout; + SM_FILE_T SM_IO_SET_TYPE(sasl_vector, "sasl", sasl_open, sasl_close, + sasl_read, sasl_write, NULL, sasl_getinfo, NULL, + SM_TIME_DEFAULT); + struct sasl_info info; + + if (conn == NULL) + { + /* no need to do anything */ + return 0; + } + + SM_IO_INIT_TYPE(sasl_vector, "sasl", sasl_open, sasl_close, + sasl_read, sasl_write, NULL, sasl_getinfo, NULL, + SM_TIME_DEFAULT); + info.fp = *fin; + info.conn = conn; + newin = sm_io_open(&sasl_vector, SM_TIME_DEFAULT, &info, + SM_IO_RDONLY_B, NULL); + + if (newin == NULL) + return -1; + + info.fp = *fout; + info.conn = conn; + newout = sm_io_open(&sasl_vector, SM_TIME_DEFAULT, &info, + SM_IO_WRONLY_B, NULL); + + if (newout == NULL) + { + (void) sm_io_close(newin, SM_TIME_DEFAULT); + return -1; + } + sm_io_automode(newin, newout); + + sm_io_setinfo(*fin, SM_IO_WHAT_TIMEOUT, &tmo); + sm_io_setinfo(*fout, SM_IO_WHAT_TIMEOUT, &tmo); + + *fin = newin; + *fout = newout; + return 0; +} +#endif /* SASL */ + +#if STARTTLS +# include "sfsasl.h" +# include <openssl/err.h> + +/* Structure used by the "tls" file type */ +struct tls_obj +{ + SM_FILE_T *fp; + SSL *con; +}; + +struct tls_info +{ + SM_FILE_T *fp; + SSL *con; +}; + +/* +** TLS_GETINFO - returns requested information about a "tls" file +** descriptor. +** +** Parameters: +** fp -- the file descriptor +** what -- the type of information requested +** valp -- the thang to return the information in (unused) +** +** Returns: +** -1 for unknown requests +** >=0 on success with valp filled in (if possible). +*/ + +static int tls_getinfo __P((SM_FILE_T *, int, void *)); + +/* ARGSUSED2 */ +static int +tls_getinfo(fp, what, valp) + SM_FILE_T *fp; + int what; + void *valp; +{ + struct tls_obj *so = (struct tls_obj *) fp->f_cookie; + + switch (what) + { + case SM_IO_WHAT_FD: + if (so->fp == NULL) + return -1; + return so->fp->f_file; /* for stdio fileno() compatability */ + + case SM_IO_IS_READABLE: + return SSL_pending(so->con) > 0; + + default: + return -1; + } +} + +/* +** TLS_OPEN -- creates the tls specific information for opening a +** file of the tls type. +** +** Parameters: +** fp -- the file pointer associated with the new open +** info -- the sm_io file pointer holding the open and the +** TLS encryption connection to be read from or written to +** flags -- ignored +** rpool -- ignored +** +** Returns: +** 0 on success +*/ + +static int tls_open __P((SM_FILE_T *, const void *, int, const void *)); + +/* ARGSUSED2 */ +static int +tls_open(fp, info, flags, rpool) + SM_FILE_T *fp; + const void *info; + int flags; + const void *rpool; +{ + struct tls_obj *so; + struct tls_info *ti = (struct tls_info *) info; + + so = (struct tls_obj *) sm_malloc(sizeof(struct tls_obj)); + if (so == NULL) + { + errno = ENOMEM; + return -1; + } + so->fp = ti->fp; + so->con = ti->con; + + /* + ** We try to get the "raw" file descriptor that TLS uses to + ** do the actual read/write with. This is to allow us control + ** over the file descriptor being a blocking or non-blocking type. + ** Under the covers TLS handles the change and this allows us + ** to do timeouts with sm_io. + */ + + fp->f_file = sm_io_getinfo(so->fp, SM_IO_WHAT_FD, NULL); + (void) sm_io_setvbuf(so->fp, SM_TIME_DEFAULT, NULL, SM_IO_NOW, 0); + fp->f_cookie = so; + return 0; +} + +/* +** TLS_CLOSE -- close the tls specific parts of the tls file pointer +** +** Parameters: +** fp -- the file pointer to close +** +** Returns: +** 0 on success +*/ + +static int tls_close __P((SM_FILE_T *)); + +static int +tls_close(fp) + SM_FILE_T *fp; +{ + struct tls_obj *so; + + so = (struct tls_obj *) fp->f_cookie; + if (so == NULL) + return 0; + if (so->fp != NULL) + { + sm_io_close(so->fp, SM_TIME_DEFAULT); + so->fp = NULL; + } + sm_free(so); + so = NULL; + return 0; +} + +/* maximum number of retries for TLS related I/O due to handshakes */ +# define MAX_TLS_IOS 4 + +/* +** TLS_RETRY -- check whether a failed SSL operation can be retried +** +** Parameters: +** ssl -- TLS structure +** rfd -- read fd +** wfd -- write fd +** tlsstart -- start time of TLS operation +** timeout -- timeout for TLS operation +** err -- SSL error +** where -- description of operation +** +** Results: +** >0 on success +** 0 on timeout +** <0 on error +*/ + +int +tls_retry(ssl, rfd, wfd, tlsstart, timeout, err, where) + SSL *ssl; + int rfd; + int wfd; + time_t tlsstart; + int timeout; + int err; + const char *where; +{ + int ret; + time_t left; + time_t now = curtime(); + struct timeval tv; + + ret = -1; + + /* + ** For SSL_ERROR_WANT_{READ,WRITE}: + ** There is not a complete SSL record available yet + ** or there is only a partial SSL record removed from + ** the network (socket) buffer into the SSL buffer. + ** The SSL_connect will only succeed when a full + ** SSL record is available (assuming a "real" error + ** doesn't happen). To handle when a "real" error + ** does happen the select is set for exceptions too. + ** The connection may be re-negotiated during this time + ** so both read and write "want errors" need to be handled. + ** A select() exception loops back so that a proper SSL + ** error message can be gotten. + */ + + left = timeout - (now - tlsstart); + if (left <= 0) + return 0; /* timeout */ + tv.tv_sec = left; + tv.tv_usec = 0; + + if (LogLevel > 14) + { + sm_syslog(LOG_INFO, NOQID, + "STARTTLS=%s, info: fds=%d/%d, err=%d", + where, rfd, wfd, err); + } + + if (FD_SETSIZE > 0 && + ((err == SSL_ERROR_WANT_READ && rfd >= FD_SETSIZE) || + (err == SSL_ERROR_WANT_WRITE && wfd >= FD_SETSIZE))) + { + if (LogLevel > 5) + { + sm_syslog(LOG_ERR, NOQID, + "STARTTLS=%s, error: fd %d/%d too large", + where, rfd, wfd); + if (LogLevel > 8) + tlslogerr(where); + } + errno = EINVAL; + } + else if (err == SSL_ERROR_WANT_READ) + { + fd_set ssl_maskr, ssl_maskx; + + FD_ZERO(&ssl_maskr); + FD_SET(rfd, &ssl_maskr); + FD_ZERO(&ssl_maskx); + FD_SET(rfd, &ssl_maskx); + do + { + ret = select(rfd + 1, &ssl_maskr, NULL, &ssl_maskx, + &tv); + } while (ret < 0 && errno == EINTR); + if (ret < 0 && errno > 0) + ret = -errno; + } + else if (err == SSL_ERROR_WANT_WRITE) + { + fd_set ssl_maskw, ssl_maskx; + + FD_ZERO(&ssl_maskw); + FD_SET(wfd, &ssl_maskw); + FD_ZERO(&ssl_maskx); + FD_SET(rfd, &ssl_maskx); + do + { + ret = select(wfd + 1, NULL, &ssl_maskw, &ssl_maskx, + &tv); + } while (ret < 0 && errno == EINTR); + if (ret < 0 && errno > 0) + ret = -errno; + } + return ret; +} + +/* errno to force refill() etc to stop (see IS_IO_ERROR()) */ +#ifdef ETIMEDOUT +# define SM_ERR_TIMEOUT ETIMEDOUT +#else /* ETIMEDOUT */ +# define SM_ERR_TIMEOUT EIO +#endif /* ETIMEDOUT */ + +/* +** TLS_READ -- read secured information for the caller +** +** Parameters: +** fp -- the file pointer +** buf -- the location to place the data +** size -- the number of bytes to read from connection +** +** Results: +** -1 on error +** otherwise the number of bytes read +*/ + +static ssize_t tls_read __P((SM_FILE_T *, char *, size_t)); + +static ssize_t +tls_read(fp, buf, size) + SM_FILE_T *fp; + char *buf; + size_t size; +{ + int r, rfd, wfd, try, ssl_err; + struct tls_obj *so = (struct tls_obj *) fp->f_cookie; + time_t tlsstart; + char *err; + + try = 99; + err = NULL; + tlsstart = curtime(); + + retry: + r = SSL_read(so->con, (char *) buf, size); + + if (r > 0) + return r; + + err = NULL; + switch (ssl_err = SSL_get_error(so->con, r)) + { + case SSL_ERROR_NONE: + case SSL_ERROR_ZERO_RETURN: + break; + case SSL_ERROR_WANT_WRITE: + err = "read W BLOCK"; + /* FALLTHROUGH */ + case SSL_ERROR_WANT_READ: + if (err == NULL) + err = "read R BLOCK"; + rfd = SSL_get_rfd(so->con); + wfd = SSL_get_wfd(so->con); + try = tls_retry(so->con, rfd, wfd, tlsstart, + TimeOuts.to_datablock, ssl_err, "read"); + if (try > 0) + goto retry; + errno = SM_ERR_TIMEOUT; + break; + + case SSL_ERROR_WANT_X509_LOOKUP: + err = "write X BLOCK"; + break; + case SSL_ERROR_SYSCALL: + if (r == 0 && errno == 0) /* out of protocol EOF found */ + break; + err = "syscall error"; +/* + get_last_socket_error()); +*/ + break; + case SSL_ERROR_SSL: +#if DEAL_WITH_ERROR_SSL + if (r == 0 && errno == 0) /* out of protocol EOF found */ + break; +#endif /* DEAL_WITH_ERROR_SSL */ + err = "generic SSL error"; + if (LogLevel > 9) + tlslogerr("read"); + +#if DEAL_WITH_ERROR_SSL + /* avoid repeated calls? */ + if (r == 0) + r = -1; +#endif /* DEAL_WITH_ERROR_SSL */ + break; + } + if (err != NULL) + { + int save_errno; + + save_errno = (errno == 0) ? EIO : errno; + if (try == 0 && save_errno == SM_ERR_TIMEOUT) + { + if (LogLevel > 7) + sm_syslog(LOG_WARNING, NOQID, + "STARTTLS: read error=timeout"); + } + else if (LogLevel > 8) + sm_syslog(LOG_WARNING, NOQID, + "STARTTLS: read error=%s (%d), errno=%d, get_error=%s, retry=%d, ssl_err=%d", + err, r, errno, + ERR_error_string(ERR_get_error(), NULL), try, + ssl_err); + else if (LogLevel > 7) + sm_syslog(LOG_WARNING, NOQID, + "STARTTLS: read error=%s (%d), retry=%d, ssl_err=%d", + err, r, errno, try, ssl_err); + errno = save_errno; + } + return r; +} + +/* +** TLS_WRITE -- write information out through secure connection +** +** Parameters: +** fp -- the file pointer +** buf -- holds the data to be securely written +** size -- the number of bytes to write +** +** Returns: +** -1 on error +** otherwise number of bytes written +*/ + +static ssize_t tls_write __P((SM_FILE_T *, const char *, size_t)); + +static ssize_t +tls_write(fp, buf, size) + SM_FILE_T *fp; + const char *buf; + size_t size; +{ + int r, rfd, wfd, try, ssl_err; + struct tls_obj *so = (struct tls_obj *) fp->f_cookie; + time_t tlsstart; + char *err; + + try = 99; + err = NULL; + tlsstart = curtime(); + + retry: + r = SSL_write(so->con, (char *) buf, size); + + if (r > 0) + return r; + err = NULL; + switch (ssl_err = SSL_get_error(so->con, r)) + { + case SSL_ERROR_NONE: + case SSL_ERROR_ZERO_RETURN: + break; + case SSL_ERROR_WANT_WRITE: + err = "read W BLOCK"; + /* FALLTHROUGH */ + case SSL_ERROR_WANT_READ: + if (err == NULL) + err = "read R BLOCK"; + rfd = SSL_get_rfd(so->con); + wfd = SSL_get_wfd(so->con); + try = tls_retry(so->con, rfd, wfd, tlsstart, + DATA_PROGRESS_TIMEOUT, ssl_err, "write"); + if (try > 0) + goto retry; + errno = SM_ERR_TIMEOUT; + break; + case SSL_ERROR_WANT_X509_LOOKUP: + err = "write X BLOCK"; + break; + case SSL_ERROR_SYSCALL: + if (r == 0 && errno == 0) /* out of protocol EOF found */ + break; + err = "syscall error"; +/* + get_last_socket_error()); +*/ + break; + case SSL_ERROR_SSL: + err = "generic SSL error"; +/* + ERR_GET_REASON(ERR_peek_error())); +*/ + if (LogLevel > 9) + tlslogerr("write"); + +#if DEAL_WITH_ERROR_SSL + /* avoid repeated calls? */ + if (r == 0) + r = -1; +#endif /* DEAL_WITH_ERROR_SSL */ + break; + } + if (err != NULL) + { + int save_errno; + + save_errno = (errno == 0) ? EIO : errno; + if (try == 0 && save_errno == SM_ERR_TIMEOUT) + { + if (LogLevel > 7) + sm_syslog(LOG_WARNING, NOQID, + "STARTTLS: write error=timeout"); + } + else if (LogLevel > 8) + sm_syslog(LOG_WARNING, NOQID, + "STARTTLS: write error=%s (%d), errno=%d, get_error=%s, retry=%d, ssl_err=%d", + err, r, errno, + ERR_error_string(ERR_get_error(), NULL), try, + ssl_err); + else if (LogLevel > 7) + sm_syslog(LOG_WARNING, NOQID, + "STARTTLS: write error=%s (%d), errno=%d, retry=%d, ssl_err=%d", + err, r, errno, try, ssl_err); + errno = save_errno; + } + return r; +} + +/* +** SFDCTLS -- create tls file type and open in and out file pointers +** for sendmail to read from and write to. +** +** Parameters: +** fin -- data input source being replaced +** fout -- data output source being replaced +** con -- the tls connection pointer +** +** Returns: +** -1 on error +** 0 on success +** +** Side effects: +** The arguments "fin" and "fout" are replaced with the new +** SM_FILE_T pointers. +** The original "fin" and "fout" are preserved in the tls file +** type but are not actually used because of the design of TLS. +*/ + +int +sfdctls(fin, fout, con) + SM_FILE_T **fin; + SM_FILE_T **fout; + SSL *con; +{ + SM_FILE_T *tlsin, *tlsout; + SM_FILE_T SM_IO_SET_TYPE(tls_vector, "tls", tls_open, tls_close, + tls_read, tls_write, NULL, tls_getinfo, NULL, + SM_TIME_FOREVER); + struct tls_info info; + + SM_ASSERT(con != NULL); + + SM_IO_INIT_TYPE(tls_vector, "tls", tls_open, tls_close, + tls_read, tls_write, NULL, tls_getinfo, NULL, + SM_TIME_FOREVER); + info.fp = *fin; + info.con = con; + tlsin = sm_io_open(&tls_vector, SM_TIME_DEFAULT, &info, SM_IO_RDONLY_B, + NULL); + if (tlsin == NULL) + return -1; + + info.fp = *fout; + tlsout = sm_io_open(&tls_vector, SM_TIME_DEFAULT, &info, SM_IO_WRONLY_B, + NULL); + if (tlsout == NULL) + { + (void) sm_io_close(tlsin, SM_TIME_DEFAULT); + return -1; + } + sm_io_automode(tlsin, tlsout); + + *fin = tlsin; + *fout = tlsout; + return 0; +} +#endif /* STARTTLS */ |