106f25ae9SGregory Neil Shapiro /* 25dd76dd0SGregory Neil Shapiro * Copyright (c) 1999-2006, 2008 Proofpoint, Inc. and its suppliers. 306f25ae9SGregory Neil Shapiro * All rights reserved. 406f25ae9SGregory Neil Shapiro * 506f25ae9SGregory Neil Shapiro * By using this file, you agree to the terms and conditions set 606f25ae9SGregory Neil Shapiro * forth in the LICENSE file which can be found at the top level of 706f25ae9SGregory Neil Shapiro * the sendmail distribution. 806f25ae9SGregory Neil Shapiro * 906f25ae9SGregory Neil Shapiro */ 1006f25ae9SGregory Neil Shapiro 1140266059SGregory Neil Shapiro #include <sm/gen.h> 124313cc83SGregory Neil Shapiro SM_RCSID("@(#)$Id: sfsasl.c,v 8.121 2013-11-22 20:51:56 ca Exp $") 1306f25ae9SGregory Neil Shapiro #include <stdlib.h> 1406f25ae9SGregory Neil Shapiro #include <sendmail.h> 15af9557fdSGregory Neil Shapiro #include <sm/time.h> 16*da7d7b9cSGregory Neil Shapiro #include <sm/fdset.h> 1740266059SGregory Neil Shapiro #include <errno.h> 18b6bacd31SGregory Neil Shapiro 19b6bacd31SGregory Neil Shapiro /* allow to disable error handling code just in case... */ 20b6bacd31SGregory Neil Shapiro #ifndef DEAL_WITH_ERROR_SSL 21b6bacd31SGregory Neil Shapiro # define DEAL_WITH_ERROR_SSL 1 22b6bacd31SGregory Neil Shapiro #endif /* ! DEAL_WITH_ERROR_SSL */ 23b6bacd31SGregory Neil Shapiro 2440266059SGregory Neil Shapiro #if SASL 2506f25ae9SGregory Neil Shapiro # include "sfsasl.h" 2606f25ae9SGregory Neil Shapiro 2740266059SGregory Neil Shapiro /* Structure used by the "sasl" file type */ 2840266059SGregory Neil Shapiro struct sasl_obj 2940266059SGregory Neil Shapiro { 3040266059SGregory Neil Shapiro SM_FILE_T *fp; 3140266059SGregory Neil Shapiro sasl_conn_t *conn; 3240266059SGregory Neil Shapiro }; 3340266059SGregory Neil Shapiro 3440266059SGregory Neil Shapiro struct sasl_info 3540266059SGregory Neil Shapiro { 3640266059SGregory Neil Shapiro SM_FILE_T *fp; 3740266059SGregory Neil Shapiro sasl_conn_t *conn; 3840266059SGregory Neil Shapiro }; 3940266059SGregory Neil Shapiro 4040266059SGregory Neil Shapiro /* 4140266059SGregory Neil Shapiro ** SASL_GETINFO - returns requested information about a "sasl" file 4240266059SGregory Neil Shapiro ** descriptor. 4340266059SGregory Neil Shapiro ** 4440266059SGregory Neil Shapiro ** Parameters: 4540266059SGregory Neil Shapiro ** fp -- the file descriptor 4640266059SGregory Neil Shapiro ** what -- the type of information requested 4740266059SGregory Neil Shapiro ** valp -- the thang to return the information in 4840266059SGregory Neil Shapiro ** 4940266059SGregory Neil Shapiro ** Returns: 5040266059SGregory Neil Shapiro ** -1 for unknown requests 5140266059SGregory Neil Shapiro ** >=0 on success with valp filled in (if possible). 5240266059SGregory Neil Shapiro */ 5340266059SGregory Neil Shapiro 5440266059SGregory Neil Shapiro static int sasl_getinfo __P((SM_FILE_T *, int, void *)); 5540266059SGregory Neil Shapiro 5640266059SGregory Neil Shapiro static int 5740266059SGregory Neil Shapiro sasl_getinfo(fp, what, valp) 5840266059SGregory Neil Shapiro SM_FILE_T *fp; 5940266059SGregory Neil Shapiro int what; 6040266059SGregory Neil Shapiro void *valp; 6140266059SGregory Neil Shapiro { 6240266059SGregory Neil Shapiro struct sasl_obj *so = (struct sasl_obj *) fp->f_cookie; 6340266059SGregory Neil Shapiro 6440266059SGregory Neil Shapiro switch (what) 6540266059SGregory Neil Shapiro { 6640266059SGregory Neil Shapiro case SM_IO_WHAT_FD: 6740266059SGregory Neil Shapiro if (so->fp == NULL) 6840266059SGregory Neil Shapiro return -1; 6940266059SGregory Neil Shapiro return so->fp->f_file; /* for stdio fileno() compatability */ 7040266059SGregory Neil Shapiro 7140266059SGregory Neil Shapiro case SM_IO_IS_READABLE: 7240266059SGregory Neil Shapiro if (so->fp == NULL) 7340266059SGregory Neil Shapiro return 0; 7440266059SGregory Neil Shapiro 7540266059SGregory Neil Shapiro /* get info from underlying file */ 7640266059SGregory Neil Shapiro return sm_io_getinfo(so->fp, what, valp); 7740266059SGregory Neil Shapiro 7840266059SGregory Neil Shapiro default: 7940266059SGregory Neil Shapiro return -1; 8040266059SGregory Neil Shapiro } 8140266059SGregory Neil Shapiro } 8240266059SGregory Neil Shapiro 8340266059SGregory Neil Shapiro /* 8440266059SGregory Neil Shapiro ** SASL_OPEN -- creates the sasl specific information for opening a 8540266059SGregory Neil Shapiro ** file of the sasl type. 8640266059SGregory Neil Shapiro ** 8740266059SGregory Neil Shapiro ** Parameters: 8840266059SGregory Neil Shapiro ** fp -- the file pointer associated with the new open 8940266059SGregory Neil Shapiro ** info -- contains the sasl connection information pointer and 9040266059SGregory Neil Shapiro ** the original SM_FILE_T that holds the open 9140266059SGregory Neil Shapiro ** flags -- ignored 9240266059SGregory Neil Shapiro ** rpool -- ignored 9340266059SGregory Neil Shapiro ** 9440266059SGregory Neil Shapiro ** Returns: 9540266059SGregory Neil Shapiro ** 0 on success 9640266059SGregory Neil Shapiro */ 9740266059SGregory Neil Shapiro 9840266059SGregory Neil Shapiro static int sasl_open __P((SM_FILE_T *, const void *, int, const void *)); 9940266059SGregory Neil Shapiro 10040266059SGregory Neil Shapiro /* ARGSUSED2 */ 10140266059SGregory Neil Shapiro static int 10240266059SGregory Neil Shapiro sasl_open(fp, info, flags, rpool) 10340266059SGregory Neil Shapiro SM_FILE_T *fp; 10440266059SGregory Neil Shapiro const void *info; 10540266059SGregory Neil Shapiro int flags; 10640266059SGregory Neil Shapiro const void *rpool; 10740266059SGregory Neil Shapiro { 10840266059SGregory Neil Shapiro struct sasl_obj *so; 10940266059SGregory Neil Shapiro struct sasl_info *si = (struct sasl_info *) info; 11040266059SGregory Neil Shapiro 11140266059SGregory Neil Shapiro so = (struct sasl_obj *) sm_malloc(sizeof(struct sasl_obj)); 112a7ec597cSGregory Neil Shapiro if (so == NULL) 113a7ec597cSGregory Neil Shapiro { 114a7ec597cSGregory Neil Shapiro errno = ENOMEM; 115a7ec597cSGregory Neil Shapiro return -1; 116a7ec597cSGregory Neil Shapiro } 11740266059SGregory Neil Shapiro so->fp = si->fp; 11840266059SGregory Neil Shapiro so->conn = si->conn; 11940266059SGregory Neil Shapiro 12040266059SGregory Neil Shapiro /* 12140266059SGregory Neil Shapiro ** The underlying 'fp' is set to SM_IO_NOW so that the entire 12240266059SGregory Neil Shapiro ** encoded string is written in one chunk. Otherwise there is 12340266059SGregory Neil Shapiro ** the possibility that it may appear illegal, bogus or 12440266059SGregory Neil Shapiro ** mangled to the other side of the connection. 12540266059SGregory Neil Shapiro ** We will read or write through 'fp' since it is the opaque 12640266059SGregory Neil Shapiro ** connection for the communications. We need to treat it this 12740266059SGregory Neil Shapiro ** way in case the encoded string is to be sent down a TLS 12840266059SGregory Neil Shapiro ** connection rather than, say, sm_io's stdio. 12940266059SGregory Neil Shapiro */ 13040266059SGregory Neil Shapiro 13140266059SGregory Neil Shapiro (void) sm_io_setvbuf(so->fp, SM_TIME_DEFAULT, NULL, SM_IO_NOW, 0); 13240266059SGregory Neil Shapiro fp->f_cookie = so; 13340266059SGregory Neil Shapiro return 0; 13440266059SGregory Neil Shapiro } 13540266059SGregory Neil Shapiro 13640266059SGregory Neil Shapiro /* 13740266059SGregory Neil Shapiro ** SASL_CLOSE -- close the sasl specific parts of the sasl file pointer 13840266059SGregory Neil Shapiro ** 13940266059SGregory Neil Shapiro ** Parameters: 14040266059SGregory Neil Shapiro ** fp -- the file pointer to close 14140266059SGregory Neil Shapiro ** 14240266059SGregory Neil Shapiro ** Returns: 14340266059SGregory Neil Shapiro ** 0 on success 14440266059SGregory Neil Shapiro */ 14540266059SGregory Neil Shapiro 14640266059SGregory Neil Shapiro static int sasl_close __P((SM_FILE_T *)); 14740266059SGregory Neil Shapiro 14840266059SGregory Neil Shapiro static int 14940266059SGregory Neil Shapiro sasl_close(fp) 15040266059SGregory Neil Shapiro SM_FILE_T *fp; 15140266059SGregory Neil Shapiro { 15240266059SGregory Neil Shapiro struct sasl_obj *so; 15340266059SGregory Neil Shapiro 15440266059SGregory Neil Shapiro so = (struct sasl_obj *) fp->f_cookie; 155a7ec597cSGregory Neil Shapiro if (so == NULL) 156a7ec597cSGregory Neil Shapiro return 0; 15740266059SGregory Neil Shapiro if (so->fp != NULL) 15840266059SGregory Neil Shapiro { 15940266059SGregory Neil Shapiro sm_io_close(so->fp, SM_TIME_DEFAULT); 16040266059SGregory Neil Shapiro so->fp = NULL; 16140266059SGregory Neil Shapiro } 16240266059SGregory Neil Shapiro sm_free(so); 16340266059SGregory Neil Shapiro so = NULL; 16440266059SGregory Neil Shapiro return 0; 16540266059SGregory Neil Shapiro } 16640266059SGregory Neil Shapiro 167193538b7SGregory Neil Shapiro /* how to deallocate a buffer allocated by SASL */ 16840266059SGregory Neil Shapiro extern void sm_sasl_free __P((void *)); 16940266059SGregory Neil Shapiro # define SASL_DEALLOC(b) sm_sasl_free(b) 17040266059SGregory Neil Shapiro 17140266059SGregory Neil Shapiro /* 17240266059SGregory Neil Shapiro ** SASL_READ -- read encrypted information and decrypt it for the caller 17340266059SGregory Neil Shapiro ** 17440266059SGregory Neil Shapiro ** Parameters: 17540266059SGregory Neil Shapiro ** fp -- the file pointer 17640266059SGregory Neil Shapiro ** buf -- the location to place the decrypted information 17740266059SGregory Neil Shapiro ** size -- the number of bytes to read after decryption 17840266059SGregory Neil Shapiro ** 17940266059SGregory Neil Shapiro ** Results: 18040266059SGregory Neil Shapiro ** -1 on error 18140266059SGregory Neil Shapiro ** otherwise the number of bytes read 18240266059SGregory Neil Shapiro */ 18340266059SGregory Neil Shapiro 18440266059SGregory Neil Shapiro static ssize_t sasl_read __P((SM_FILE_T *, char *, size_t)); 185193538b7SGregory Neil Shapiro 18606f25ae9SGregory Neil Shapiro static ssize_t 18740266059SGregory Neil Shapiro sasl_read(fp, buf, size) 18840266059SGregory Neil Shapiro SM_FILE_T *fp; 18940266059SGregory Neil Shapiro char *buf; 19006f25ae9SGregory Neil Shapiro size_t size; 19106f25ae9SGregory Neil Shapiro { 19240266059SGregory Neil Shapiro int result; 19340266059SGregory Neil Shapiro ssize_t len; 19494c01205SGregory Neil Shapiro # if SASL >= 20000 19513bd1963SGregory Neil Shapiro static const char *outbuf = NULL; 19694c01205SGregory Neil Shapiro # else /* SASL >= 20000 */ 197193538b7SGregory Neil Shapiro static char *outbuf = NULL; 19894c01205SGregory Neil Shapiro # endif /* SASL >= 20000 */ 199193538b7SGregory Neil Shapiro static unsigned int outlen = 0; 200193538b7SGregory Neil Shapiro static unsigned int offset = 0; 20140266059SGregory Neil Shapiro struct sasl_obj *so = (struct sasl_obj *) fp->f_cookie; 20206f25ae9SGregory Neil Shapiro 203193538b7SGregory Neil Shapiro /* 204193538b7SGregory Neil Shapiro ** sasl_decode() may require more data than a single read() returns. 205193538b7SGregory Neil Shapiro ** Hence we have to put a loop around the decoding. 206193538b7SGregory Neil Shapiro ** This also requires that we may have to split up the returned 207193538b7SGregory Neil Shapiro ** data since it might be larger than the allowed size. 208193538b7SGregory Neil Shapiro ** Therefore we use a static pointer and return portions of it 209193538b7SGregory Neil Shapiro ** if necessary. 210a7ec597cSGregory Neil Shapiro ** XXX Note: This function is not thread-safe nor can it be used 211a7ec597cSGregory Neil Shapiro ** on more than one file. A correct implementation would store 212a7ec597cSGregory Neil Shapiro ** this data in fp->f_cookie. 213193538b7SGregory Neil Shapiro */ 21406f25ae9SGregory Neil Shapiro 21513bd1963SGregory Neil Shapiro # if SASL >= 20000 21613bd1963SGregory Neil Shapiro while (outlen == 0) 21713bd1963SGregory Neil Shapiro # else /* SASL >= 20000 */ 218193538b7SGregory Neil Shapiro while (outbuf == NULL && outlen == 0) 21913bd1963SGregory Neil Shapiro # endif /* SASL >= 20000 */ 220193538b7SGregory Neil Shapiro { 22140266059SGregory Neil Shapiro len = sm_io_read(so->fp, SM_TIME_DEFAULT, buf, size); 22206f25ae9SGregory Neil Shapiro if (len <= 0) 22306f25ae9SGregory Neil Shapiro return len; 22440266059SGregory Neil Shapiro result = sasl_decode(so->conn, buf, 22540266059SGregory Neil Shapiro (unsigned int) len, &outbuf, &outlen); 22606f25ae9SGregory Neil Shapiro if (result != SASL_OK) 22706f25ae9SGregory Neil Shapiro { 2284e4196cbSGregory Neil Shapiro if (LogLevel > 7) 2294e4196cbSGregory Neil Shapiro sm_syslog(LOG_WARNING, NOQID, 2304e4196cbSGregory Neil Shapiro "AUTH: sasl_decode error=%d", result); 231193538b7SGregory Neil Shapiro outbuf = NULL; 232193538b7SGregory Neil Shapiro offset = 0; 233193538b7SGregory Neil Shapiro outlen = 0; 23406f25ae9SGregory Neil Shapiro return -1; 23506f25ae9SGregory Neil Shapiro } 236193538b7SGregory Neil Shapiro } 23706f25ae9SGregory Neil Shapiro 23840266059SGregory Neil Shapiro if (outbuf == NULL) 23906f25ae9SGregory Neil Shapiro { 24040266059SGregory Neil Shapiro /* be paranoid: outbuf == NULL but outlen != 0 */ 24140266059SGregory Neil Shapiro syserr("@sasl_read failure: outbuf == NULL but outlen != 0"); 24240266059SGregory Neil Shapiro /* NOTREACHED */ 24340266059SGregory Neil Shapiro } 244193538b7SGregory Neil Shapiro if (outlen - offset > size) 245193538b7SGregory Neil Shapiro { 246193538b7SGregory Neil Shapiro /* return another part of the buffer */ 24740266059SGregory Neil Shapiro (void) memcpy(buf, outbuf + offset, size); 248193538b7SGregory Neil Shapiro offset += size; 24940266059SGregory Neil Shapiro len = size; 25006f25ae9SGregory Neil Shapiro } 251193538b7SGregory Neil Shapiro else 252193538b7SGregory Neil Shapiro { 253193538b7SGregory Neil Shapiro /* return the rest of the buffer */ 25440266059SGregory Neil Shapiro len = outlen - offset; 25540266059SGregory Neil Shapiro (void) memcpy(buf, outbuf + offset, (size_t) len); 25694c01205SGregory Neil Shapiro # if SASL < 20000 257193538b7SGregory Neil Shapiro SASL_DEALLOC(outbuf); 25894c01205SGregory Neil Shapiro # endif /* SASL < 20000 */ 259193538b7SGregory Neil Shapiro outbuf = NULL; 260193538b7SGregory Neil Shapiro offset = 0; 261193538b7SGregory Neil Shapiro outlen = 0; 262193538b7SGregory Neil Shapiro } 26340266059SGregory Neil Shapiro return len; 26406f25ae9SGregory Neil Shapiro } 26506f25ae9SGregory Neil Shapiro 26640266059SGregory Neil Shapiro /* 26740266059SGregory Neil Shapiro ** SASL_WRITE -- write information out after encrypting it 26840266059SGregory Neil Shapiro ** 26940266059SGregory Neil Shapiro ** Parameters: 27040266059SGregory Neil Shapiro ** fp -- the file pointer 27140266059SGregory Neil Shapiro ** buf -- holds the data to be encrypted and written 27240266059SGregory Neil Shapiro ** size -- the number of bytes to have encrypted and written 27340266059SGregory Neil Shapiro ** 27440266059SGregory Neil Shapiro ** Returns: 27540266059SGregory Neil Shapiro ** -1 on error 27640266059SGregory Neil Shapiro ** otherwise number of bytes written 27740266059SGregory Neil Shapiro */ 27840266059SGregory Neil Shapiro 27940266059SGregory Neil Shapiro static ssize_t sasl_write __P((SM_FILE_T *, const char *, size_t)); 28040266059SGregory Neil Shapiro 28106f25ae9SGregory Neil Shapiro static ssize_t 28240266059SGregory Neil Shapiro sasl_write(fp, buf, size) 28340266059SGregory Neil Shapiro SM_FILE_T *fp; 28440266059SGregory Neil Shapiro const char *buf; 28506f25ae9SGregory Neil Shapiro size_t size; 28606f25ae9SGregory Neil Shapiro { 28706f25ae9SGregory Neil Shapiro int result; 28894c01205SGregory Neil Shapiro # if SASL >= 20000 28994c01205SGregory Neil Shapiro const char *outbuf; 29094c01205SGregory Neil Shapiro # else /* SASL >= 20000 */ 29106f25ae9SGregory Neil Shapiro char *outbuf; 29294c01205SGregory Neil Shapiro # endif /* SASL >= 20000 */ 293b6bacd31SGregory Neil Shapiro unsigned int outlen, *maxencode; 29440266059SGregory Neil Shapiro size_t ret = 0, total = 0; 29540266059SGregory Neil Shapiro struct sasl_obj *so = (struct sasl_obj *) fp->f_cookie; 29606f25ae9SGregory Neil Shapiro 297b6bacd31SGregory Neil Shapiro /* 298b6bacd31SGregory Neil Shapiro ** Fetch the maximum input buffer size for sasl_encode(). 299b6bacd31SGregory Neil Shapiro ** This can be less than the size set in attemptauth() 3009bd497b8SGregory Neil Shapiro ** due to a negotiation with the other side, e.g., 301b6bacd31SGregory Neil Shapiro ** Cyrus IMAP lmtp program sets maxbuf=4096, 302b6bacd31SGregory Neil Shapiro ** digestmd5 substracts 25 and hence we'll get 4071 303b6bacd31SGregory Neil Shapiro ** instead of 8192 (MAXOUTLEN). 304b6bacd31SGregory Neil Shapiro ** Hack (for now): simply reduce the size, callers are (must be) 305b6bacd31SGregory Neil Shapiro ** able to deal with that and invoke sasl_write() again with 306b6bacd31SGregory Neil Shapiro ** the rest of the data. 307b6bacd31SGregory Neil Shapiro ** Note: it would be better to store this value in the context 308b6bacd31SGregory Neil Shapiro ** after the negotiation. 309b6bacd31SGregory Neil Shapiro */ 310b6bacd31SGregory Neil Shapiro 311b6bacd31SGregory Neil Shapiro result = sasl_getprop(so->conn, SASL_MAXOUTBUF, 312b6bacd31SGregory Neil Shapiro (const void **) &maxencode); 313b6bacd31SGregory Neil Shapiro if (result == SASL_OK && size > *maxencode && *maxencode > 0) 314b6bacd31SGregory Neil Shapiro size = *maxencode; 315b6bacd31SGregory Neil Shapiro 31640266059SGregory Neil Shapiro result = sasl_encode(so->conn, buf, 31740266059SGregory Neil Shapiro (unsigned int) size, &outbuf, &outlen); 31806f25ae9SGregory Neil Shapiro 31906f25ae9SGregory Neil Shapiro if (result != SASL_OK) 3204e4196cbSGregory Neil Shapiro { 3214e4196cbSGregory Neil Shapiro if (LogLevel > 7) 3224e4196cbSGregory Neil Shapiro sm_syslog(LOG_WARNING, NOQID, 3234e4196cbSGregory Neil Shapiro "AUTH: sasl_encode error=%d", result); 32406f25ae9SGregory Neil Shapiro return -1; 3254e4196cbSGregory Neil Shapiro } 32606f25ae9SGregory Neil Shapiro 32706f25ae9SGregory Neil Shapiro if (outbuf != NULL) 32806f25ae9SGregory Neil Shapiro { 32940266059SGregory Neil Shapiro while (outlen > 0) 33040266059SGregory Neil Shapiro { 331af9557fdSGregory Neil Shapiro errno = 0; 332605302a5SGregory Neil Shapiro /* XXX result == 0? */ 33340266059SGregory Neil Shapiro ret = sm_io_write(so->fp, SM_TIME_DEFAULT, 33440266059SGregory Neil Shapiro &outbuf[total], outlen); 335a7ec597cSGregory Neil Shapiro if (ret <= 0) 336a7ec597cSGregory Neil Shapiro return ret; 33740266059SGregory Neil Shapiro outlen -= ret; 33840266059SGregory Neil Shapiro total += ret; 33940266059SGregory Neil Shapiro } 34094c01205SGregory Neil Shapiro # if SASL < 20000 341193538b7SGregory Neil Shapiro SASL_DEALLOC(outbuf); 34294c01205SGregory Neil Shapiro # endif /* SASL < 20000 */ 34306f25ae9SGregory Neil Shapiro } 34406f25ae9SGregory Neil Shapiro return size; 34506f25ae9SGregory Neil Shapiro } 34606f25ae9SGregory Neil Shapiro 34740266059SGregory Neil Shapiro /* 34840266059SGregory Neil Shapiro ** SFDCSASL -- create sasl file type and open in and out file pointers 34940266059SGregory Neil Shapiro ** for sendmail to read from and write to. 35040266059SGregory Neil Shapiro ** 35140266059SGregory Neil Shapiro ** Parameters: 35240266059SGregory Neil Shapiro ** fin -- the sm_io file encrypted data to be read from 353af9557fdSGregory Neil Shapiro ** fout -- the sm_io file encrypted data to be written to 35440266059SGregory Neil Shapiro ** conn -- the sasl connection pointer 355af9557fdSGregory Neil Shapiro ** tmo -- timeout 35640266059SGregory Neil Shapiro ** 35740266059SGregory Neil Shapiro ** Returns: 35840266059SGregory Neil Shapiro ** -1 on error 35940266059SGregory Neil Shapiro ** 0 on success 36040266059SGregory Neil Shapiro ** 36140266059SGregory Neil Shapiro ** Side effects: 36240266059SGregory Neil Shapiro ** The arguments "fin" and "fout" are replaced with the new 36340266059SGregory Neil Shapiro ** SM_FILE_T pointers. 36440266059SGregory Neil Shapiro */ 36540266059SGregory Neil Shapiro 36606f25ae9SGregory Neil Shapiro int 367af9557fdSGregory Neil Shapiro sfdcsasl(fin, fout, conn, tmo) 36840266059SGregory Neil Shapiro SM_FILE_T **fin; 36940266059SGregory Neil Shapiro SM_FILE_T **fout; 37006f25ae9SGregory Neil Shapiro sasl_conn_t *conn; 371af9557fdSGregory Neil Shapiro int tmo; 37206f25ae9SGregory Neil Shapiro { 37340266059SGregory Neil Shapiro SM_FILE_T *newin, *newout; 37440266059SGregory Neil Shapiro SM_FILE_T SM_IO_SET_TYPE(sasl_vector, "sasl", sasl_open, sasl_close, 37540266059SGregory Neil Shapiro sasl_read, sasl_write, NULL, sasl_getinfo, NULL, 376af9557fdSGregory Neil Shapiro SM_TIME_DEFAULT); 37740266059SGregory Neil Shapiro struct sasl_info info; 37806f25ae9SGregory Neil Shapiro 37906f25ae9SGregory Neil Shapiro if (conn == NULL) 38006f25ae9SGregory Neil Shapiro { 38106f25ae9SGregory Neil Shapiro /* no need to do anything */ 38206f25ae9SGregory Neil Shapiro return 0; 38306f25ae9SGregory Neil Shapiro } 38406f25ae9SGregory Neil Shapiro 38540266059SGregory Neil Shapiro SM_IO_INIT_TYPE(sasl_vector, "sasl", sasl_open, sasl_close, 38640266059SGregory Neil Shapiro sasl_read, sasl_write, NULL, sasl_getinfo, NULL, 387af9557fdSGregory Neil Shapiro SM_TIME_DEFAULT); 38840266059SGregory Neil Shapiro info.fp = *fin; 38940266059SGregory Neil Shapiro info.conn = conn; 390e92d3f3fSGregory Neil Shapiro newin = sm_io_open(&sasl_vector, SM_TIME_DEFAULT, &info, 391e92d3f3fSGregory Neil Shapiro SM_IO_RDONLY_B, NULL); 39206f25ae9SGregory Neil Shapiro 39340266059SGregory Neil Shapiro if (newin == NULL) 39440266059SGregory Neil Shapiro return -1; 39506f25ae9SGregory Neil Shapiro 39640266059SGregory Neil Shapiro info.fp = *fout; 39740266059SGregory Neil Shapiro info.conn = conn; 398e92d3f3fSGregory Neil Shapiro newout = sm_io_open(&sasl_vector, SM_TIME_DEFAULT, &info, 399e92d3f3fSGregory Neil Shapiro SM_IO_WRONLY_B, NULL); 40006f25ae9SGregory Neil Shapiro 40140266059SGregory Neil Shapiro if (newout == NULL) 40206f25ae9SGregory Neil Shapiro { 40340266059SGregory Neil Shapiro (void) sm_io_close(newin, SM_TIME_DEFAULT); 40406f25ae9SGregory Neil Shapiro return -1; 40506f25ae9SGregory Neil Shapiro } 40640266059SGregory Neil Shapiro sm_io_automode(newin, newout); 40740266059SGregory Neil Shapiro 408af9557fdSGregory Neil Shapiro sm_io_setinfo(*fin, SM_IO_WHAT_TIMEOUT, &tmo); 409af9557fdSGregory Neil Shapiro sm_io_setinfo(*fout, SM_IO_WHAT_TIMEOUT, &tmo); 410af9557fdSGregory Neil Shapiro 41140266059SGregory Neil Shapiro *fin = newin; 41240266059SGregory Neil Shapiro *fout = newout; 41306f25ae9SGregory Neil Shapiro return 0; 41406f25ae9SGregory Neil Shapiro } 41540266059SGregory Neil Shapiro #endif /* SASL */ 41606f25ae9SGregory Neil Shapiro 41740266059SGregory Neil Shapiro #if STARTTLS 41806f25ae9SGregory Neil Shapiro # include "sfsasl.h" 41906f25ae9SGregory Neil Shapiro # include <openssl/err.h> 42006f25ae9SGregory Neil Shapiro 42140266059SGregory Neil Shapiro /* Structure used by the "tls" file type */ 42240266059SGregory Neil Shapiro struct tls_obj 42340266059SGregory Neil Shapiro { 42440266059SGregory Neil Shapiro SM_FILE_T *fp; 42540266059SGregory Neil Shapiro SSL *con; 42640266059SGregory Neil Shapiro }; 42740266059SGregory Neil Shapiro 42840266059SGregory Neil Shapiro struct tls_info 42940266059SGregory Neil Shapiro { 43040266059SGregory Neil Shapiro SM_FILE_T *fp; 43140266059SGregory Neil Shapiro SSL *con; 43240266059SGregory Neil Shapiro }; 43340266059SGregory Neil Shapiro 43440266059SGregory Neil Shapiro /* 43540266059SGregory Neil Shapiro ** TLS_GETINFO - returns requested information about a "tls" file 43640266059SGregory Neil Shapiro ** descriptor. 43740266059SGregory Neil Shapiro ** 43840266059SGregory Neil Shapiro ** Parameters: 43940266059SGregory Neil Shapiro ** fp -- the file descriptor 44040266059SGregory Neil Shapiro ** what -- the type of information requested 44140266059SGregory Neil Shapiro ** valp -- the thang to return the information in (unused) 44240266059SGregory Neil Shapiro ** 44340266059SGregory Neil Shapiro ** Returns: 44440266059SGregory Neil Shapiro ** -1 for unknown requests 44540266059SGregory Neil Shapiro ** >=0 on success with valp filled in (if possible). 44640266059SGregory Neil Shapiro */ 44740266059SGregory Neil Shapiro 44840266059SGregory Neil Shapiro static int tls_getinfo __P((SM_FILE_T *, int, void *)); 44940266059SGregory Neil Shapiro 45040266059SGregory Neil Shapiro /* ARGSUSED2 */ 45113058a91SGregory Neil Shapiro static int 45240266059SGregory Neil Shapiro tls_getinfo(fp, what, valp) 45340266059SGregory Neil Shapiro SM_FILE_T *fp; 45440266059SGregory Neil Shapiro int what; 45540266059SGregory Neil Shapiro void *valp; 45640266059SGregory Neil Shapiro { 45740266059SGregory Neil Shapiro struct tls_obj *so = (struct tls_obj *) fp->f_cookie; 45840266059SGregory Neil Shapiro 45940266059SGregory Neil Shapiro switch (what) 46040266059SGregory Neil Shapiro { 46140266059SGregory Neil Shapiro case SM_IO_WHAT_FD: 46240266059SGregory Neil Shapiro if (so->fp == NULL) 46340266059SGregory Neil Shapiro return -1; 46440266059SGregory Neil Shapiro return so->fp->f_file; /* for stdio fileno() compatability */ 46540266059SGregory Neil Shapiro 46640266059SGregory Neil Shapiro case SM_IO_IS_READABLE: 46740266059SGregory Neil Shapiro return SSL_pending(so->con) > 0; 46840266059SGregory Neil Shapiro 46940266059SGregory Neil Shapiro default: 47040266059SGregory Neil Shapiro return -1; 47140266059SGregory Neil Shapiro } 47240266059SGregory Neil Shapiro } 47340266059SGregory Neil Shapiro 47440266059SGregory Neil Shapiro /* 47540266059SGregory Neil Shapiro ** TLS_OPEN -- creates the tls specific information for opening a 47640266059SGregory Neil Shapiro ** file of the tls type. 47740266059SGregory Neil Shapiro ** 47840266059SGregory Neil Shapiro ** Parameters: 47940266059SGregory Neil Shapiro ** fp -- the file pointer associated with the new open 48040266059SGregory Neil Shapiro ** info -- the sm_io file pointer holding the open and the 48140266059SGregory Neil Shapiro ** TLS encryption connection to be read from or written to 48240266059SGregory Neil Shapiro ** flags -- ignored 48340266059SGregory Neil Shapiro ** rpool -- ignored 48440266059SGregory Neil Shapiro ** 48540266059SGregory Neil Shapiro ** Returns: 48640266059SGregory Neil Shapiro ** 0 on success 48740266059SGregory Neil Shapiro */ 48840266059SGregory Neil Shapiro 48940266059SGregory Neil Shapiro static int tls_open __P((SM_FILE_T *, const void *, int, const void *)); 49040266059SGregory Neil Shapiro 49140266059SGregory Neil Shapiro /* ARGSUSED2 */ 49240266059SGregory Neil Shapiro static int 49340266059SGregory Neil Shapiro tls_open(fp, info, flags, rpool) 49440266059SGregory Neil Shapiro SM_FILE_T *fp; 49540266059SGregory Neil Shapiro const void *info; 49640266059SGregory Neil Shapiro int flags; 49740266059SGregory Neil Shapiro const void *rpool; 49840266059SGregory Neil Shapiro { 49940266059SGregory Neil Shapiro struct tls_obj *so; 50040266059SGregory Neil Shapiro struct tls_info *ti = (struct tls_info *) info; 50140266059SGregory Neil Shapiro 50240266059SGregory Neil Shapiro so = (struct tls_obj *) sm_malloc(sizeof(struct tls_obj)); 503a7ec597cSGregory Neil Shapiro if (so == NULL) 504a7ec597cSGregory Neil Shapiro { 505a7ec597cSGregory Neil Shapiro errno = ENOMEM; 506a7ec597cSGregory Neil Shapiro return -1; 507a7ec597cSGregory Neil Shapiro } 50840266059SGregory Neil Shapiro so->fp = ti->fp; 50940266059SGregory Neil Shapiro so->con = ti->con; 51040266059SGregory Neil Shapiro 51140266059SGregory Neil Shapiro /* 51240266059SGregory Neil Shapiro ** We try to get the "raw" file descriptor that TLS uses to 51340266059SGregory Neil Shapiro ** do the actual read/write with. This is to allow us control 51440266059SGregory Neil Shapiro ** over the file descriptor being a blocking or non-blocking type. 51540266059SGregory Neil Shapiro ** Under the covers TLS handles the change and this allows us 51640266059SGregory Neil Shapiro ** to do timeouts with sm_io. 51740266059SGregory Neil Shapiro */ 51840266059SGregory Neil Shapiro 51940266059SGregory Neil Shapiro fp->f_file = sm_io_getinfo(so->fp, SM_IO_WHAT_FD, NULL); 52040266059SGregory Neil Shapiro (void) sm_io_setvbuf(so->fp, SM_TIME_DEFAULT, NULL, SM_IO_NOW, 0); 52140266059SGregory Neil Shapiro fp->f_cookie = so; 52240266059SGregory Neil Shapiro return 0; 52340266059SGregory Neil Shapiro } 52440266059SGregory Neil Shapiro 52540266059SGregory Neil Shapiro /* 52640266059SGregory Neil Shapiro ** TLS_CLOSE -- close the tls specific parts of the tls file pointer 52740266059SGregory Neil Shapiro ** 52840266059SGregory Neil Shapiro ** Parameters: 52940266059SGregory Neil Shapiro ** fp -- the file pointer to close 53040266059SGregory Neil Shapiro ** 53140266059SGregory Neil Shapiro ** Returns: 53240266059SGregory Neil Shapiro ** 0 on success 53340266059SGregory Neil Shapiro */ 53440266059SGregory Neil Shapiro 53540266059SGregory Neil Shapiro static int tls_close __P((SM_FILE_T *)); 53640266059SGregory Neil Shapiro 53740266059SGregory Neil Shapiro static int 53840266059SGregory Neil Shapiro tls_close(fp) 53940266059SGregory Neil Shapiro SM_FILE_T *fp; 54040266059SGregory Neil Shapiro { 54140266059SGregory Neil Shapiro struct tls_obj *so; 54240266059SGregory Neil Shapiro 54340266059SGregory Neil Shapiro so = (struct tls_obj *) fp->f_cookie; 544a7ec597cSGregory Neil Shapiro if (so == NULL) 545a7ec597cSGregory Neil Shapiro return 0; 54640266059SGregory Neil Shapiro if (so->fp != NULL) 54740266059SGregory Neil Shapiro { 54840266059SGregory Neil Shapiro sm_io_close(so->fp, SM_TIME_DEFAULT); 54940266059SGregory Neil Shapiro so->fp = NULL; 55040266059SGregory Neil Shapiro } 55140266059SGregory Neil Shapiro sm_free(so); 55240266059SGregory Neil Shapiro so = NULL; 55340266059SGregory Neil Shapiro return 0; 55440266059SGregory Neil Shapiro } 55540266059SGregory Neil Shapiro 55640266059SGregory Neil Shapiro /* maximum number of retries for TLS related I/O due to handshakes */ 55740266059SGregory Neil Shapiro # define MAX_TLS_IOS 4 55840266059SGregory Neil Shapiro 55940266059SGregory Neil Shapiro /* 5604e4196cbSGregory Neil Shapiro ** TLS_RETRY -- check whether a failed SSL operation can be retried 5614e4196cbSGregory Neil Shapiro ** 5624e4196cbSGregory Neil Shapiro ** Parameters: 5634e4196cbSGregory Neil Shapiro ** ssl -- TLS structure 5644e4196cbSGregory Neil Shapiro ** rfd -- read fd 5654e4196cbSGregory Neil Shapiro ** wfd -- write fd 5664e4196cbSGregory Neil Shapiro ** tlsstart -- start time of TLS operation 5674e4196cbSGregory Neil Shapiro ** timeout -- timeout for TLS operation 5684e4196cbSGregory Neil Shapiro ** err -- SSL error 5694e4196cbSGregory Neil Shapiro ** where -- description of operation 5704e4196cbSGregory Neil Shapiro ** 5714e4196cbSGregory Neil Shapiro ** Results: 5724e4196cbSGregory Neil Shapiro ** >0 on success 5734e4196cbSGregory Neil Shapiro ** 0 on timeout 5744e4196cbSGregory Neil Shapiro ** <0 on error 5754e4196cbSGregory Neil Shapiro */ 5764e4196cbSGregory Neil Shapiro 5774e4196cbSGregory Neil Shapiro int 5784e4196cbSGregory Neil Shapiro tls_retry(ssl, rfd, wfd, tlsstart, timeout, err, where) 5794e4196cbSGregory Neil Shapiro SSL *ssl; 5804e4196cbSGregory Neil Shapiro int rfd; 5814e4196cbSGregory Neil Shapiro int wfd; 5824e4196cbSGregory Neil Shapiro time_t tlsstart; 5834e4196cbSGregory Neil Shapiro int timeout; 5844e4196cbSGregory Neil Shapiro int err; 5854e4196cbSGregory Neil Shapiro const char *where; 5864e4196cbSGregory Neil Shapiro { 5874e4196cbSGregory Neil Shapiro int ret; 5884e4196cbSGregory Neil Shapiro time_t left; 5894e4196cbSGregory Neil Shapiro time_t now = curtime(); 5904e4196cbSGregory Neil Shapiro struct timeval tv; 5914e4196cbSGregory Neil Shapiro 5924e4196cbSGregory Neil Shapiro ret = -1; 5934e4196cbSGregory Neil Shapiro 5944e4196cbSGregory Neil Shapiro /* 5954e4196cbSGregory Neil Shapiro ** For SSL_ERROR_WANT_{READ,WRITE}: 5964e4196cbSGregory Neil Shapiro ** There is not a complete SSL record available yet 5974e4196cbSGregory Neil Shapiro ** or there is only a partial SSL record removed from 5984e4196cbSGregory Neil Shapiro ** the network (socket) buffer into the SSL buffer. 5994e4196cbSGregory Neil Shapiro ** The SSL_connect will only succeed when a full 6004e4196cbSGregory Neil Shapiro ** SSL record is available (assuming a "real" error 6014e4196cbSGregory Neil Shapiro ** doesn't happen). To handle when a "real" error 6024e4196cbSGregory Neil Shapiro ** does happen the select is set for exceptions too. 6034e4196cbSGregory Neil Shapiro ** The connection may be re-negotiated during this time 6044e4196cbSGregory Neil Shapiro ** so both read and write "want errors" need to be handled. 6054e4196cbSGregory Neil Shapiro ** A select() exception loops back so that a proper SSL 6064e4196cbSGregory Neil Shapiro ** error message can be gotten. 6074e4196cbSGregory Neil Shapiro */ 6084e4196cbSGregory Neil Shapiro 6094e4196cbSGregory Neil Shapiro left = timeout - (now - tlsstart); 6104e4196cbSGregory Neil Shapiro if (left <= 0) 6114e4196cbSGregory Neil Shapiro return 0; /* timeout */ 6124e4196cbSGregory Neil Shapiro tv.tv_sec = left; 6134e4196cbSGregory Neil Shapiro tv.tv_usec = 0; 6144e4196cbSGregory Neil Shapiro 6154e4196cbSGregory Neil Shapiro if (LogLevel > 14) 6164e4196cbSGregory Neil Shapiro { 6174e4196cbSGregory Neil Shapiro sm_syslog(LOG_INFO, NOQID, 6184e4196cbSGregory Neil Shapiro "STARTTLS=%s, info: fds=%d/%d, err=%d", 6194e4196cbSGregory Neil Shapiro where, rfd, wfd, err); 6204e4196cbSGregory Neil Shapiro } 6214e4196cbSGregory Neil Shapiro 622*da7d7b9cSGregory Neil Shapiro if ((err == SSL_ERROR_WANT_READ && !SM_FD_OK_SELECT(rfd)) || 623*da7d7b9cSGregory Neil Shapiro (err == SSL_ERROR_WANT_WRITE && !SM_FD_OK_SELECT(wfd))) 6244e4196cbSGregory Neil Shapiro { 6254e4196cbSGregory Neil Shapiro if (LogLevel > 5) 6264e4196cbSGregory Neil Shapiro { 6274e4196cbSGregory Neil Shapiro sm_syslog(LOG_ERR, NOQID, 6284e4196cbSGregory Neil Shapiro "STARTTLS=%s, error: fd %d/%d too large", 6294e4196cbSGregory Neil Shapiro where, rfd, wfd); 6304e4196cbSGregory Neil Shapiro if (LogLevel > 8) 631552d4955SGregory Neil Shapiro tlslogerr(LOG_WARNING, where); 6324e4196cbSGregory Neil Shapiro } 6334e4196cbSGregory Neil Shapiro errno = EINVAL; 6344e4196cbSGregory Neil Shapiro } 6354e4196cbSGregory Neil Shapiro else if (err == SSL_ERROR_WANT_READ) 6364e4196cbSGregory Neil Shapiro { 6374e4196cbSGregory Neil Shapiro fd_set ssl_maskr, ssl_maskx; 638552d4955SGregory Neil Shapiro int save_errno = errno; 6394e4196cbSGregory Neil Shapiro 6404e4196cbSGregory Neil Shapiro FD_ZERO(&ssl_maskr); 6414e4196cbSGregory Neil Shapiro FD_SET(rfd, &ssl_maskr); 6424e4196cbSGregory Neil Shapiro FD_ZERO(&ssl_maskx); 6434e4196cbSGregory Neil Shapiro FD_SET(rfd, &ssl_maskx); 6444e4196cbSGregory Neil Shapiro do 6454e4196cbSGregory Neil Shapiro { 6464e4196cbSGregory Neil Shapiro ret = select(rfd + 1, &ssl_maskr, NULL, &ssl_maskx, 6474e4196cbSGregory Neil Shapiro &tv); 6484e4196cbSGregory Neil Shapiro } while (ret < 0 && errno == EINTR); 6494e4196cbSGregory Neil Shapiro if (ret < 0 && errno > 0) 6504e4196cbSGregory Neil Shapiro ret = -errno; 651552d4955SGregory Neil Shapiro errno = save_errno; 6524e4196cbSGregory Neil Shapiro } 6534e4196cbSGregory Neil Shapiro else if (err == SSL_ERROR_WANT_WRITE) 6544e4196cbSGregory Neil Shapiro { 6554e4196cbSGregory Neil Shapiro fd_set ssl_maskw, ssl_maskx; 656552d4955SGregory Neil Shapiro int save_errno = errno; 6574e4196cbSGregory Neil Shapiro 6584e4196cbSGregory Neil Shapiro FD_ZERO(&ssl_maskw); 6594e4196cbSGregory Neil Shapiro FD_SET(wfd, &ssl_maskw); 6604e4196cbSGregory Neil Shapiro FD_ZERO(&ssl_maskx); 6614e4196cbSGregory Neil Shapiro FD_SET(rfd, &ssl_maskx); 6624e4196cbSGregory Neil Shapiro do 6634e4196cbSGregory Neil Shapiro { 6644e4196cbSGregory Neil Shapiro ret = select(wfd + 1, NULL, &ssl_maskw, &ssl_maskx, 6654e4196cbSGregory Neil Shapiro &tv); 6664e4196cbSGregory Neil Shapiro } while (ret < 0 && errno == EINTR); 6674e4196cbSGregory Neil Shapiro if (ret < 0 && errno > 0) 6684e4196cbSGregory Neil Shapiro ret = -errno; 669552d4955SGregory Neil Shapiro errno = save_errno; 6704e4196cbSGregory Neil Shapiro } 6714e4196cbSGregory Neil Shapiro return ret; 6724e4196cbSGregory Neil Shapiro } 6734e4196cbSGregory Neil Shapiro 6744e4196cbSGregory Neil Shapiro /* errno to force refill() etc to stop (see IS_IO_ERROR()) */ 6754e4196cbSGregory Neil Shapiro #ifdef ETIMEDOUT 6764e4196cbSGregory Neil Shapiro # define SM_ERR_TIMEOUT ETIMEDOUT 6774e4196cbSGregory Neil Shapiro #else /* ETIMEDOUT */ 6784e4196cbSGregory Neil Shapiro # define SM_ERR_TIMEOUT EIO 6794e4196cbSGregory Neil Shapiro #endif /* ETIMEDOUT */ 6804e4196cbSGregory Neil Shapiro 6814e4196cbSGregory Neil Shapiro /* 682e3793f76SGregory Neil Shapiro ** SET_TLS_RD_TMO -- read secured information for the caller 683e3793f76SGregory Neil Shapiro ** 684e3793f76SGregory Neil Shapiro ** Parameters: 685e3793f76SGregory Neil Shapiro ** rd_tmo -- read timeout 686e3793f76SGregory Neil Shapiro ** 687e3793f76SGregory Neil Shapiro ** Results: 688*da7d7b9cSGregory Neil Shapiro ** previous read timeout 689e3793f76SGregory Neil Shapiro ** This is a hack: there is no way to pass it in 690e3793f76SGregory Neil Shapiro */ 691e3793f76SGregory Neil Shapiro 692e3793f76SGregory Neil Shapiro static int tls_rd_tmo = -1; 693e3793f76SGregory Neil Shapiro 694*da7d7b9cSGregory Neil Shapiro int 695e3793f76SGregory Neil Shapiro set_tls_rd_tmo(rd_tmo) 696e3793f76SGregory Neil Shapiro int rd_tmo; 697e3793f76SGregory Neil Shapiro { 698*da7d7b9cSGregory Neil Shapiro int old_rd_tmo; 699*da7d7b9cSGregory Neil Shapiro 700*da7d7b9cSGregory Neil Shapiro old_rd_tmo = tls_rd_tmo; 701e3793f76SGregory Neil Shapiro tls_rd_tmo = rd_tmo; 702*da7d7b9cSGregory Neil Shapiro return old_rd_tmo; 703e3793f76SGregory Neil Shapiro } 704e3793f76SGregory Neil Shapiro 705e3793f76SGregory Neil Shapiro /* 70640266059SGregory Neil Shapiro ** TLS_READ -- read secured information for the caller 70740266059SGregory Neil Shapiro ** 70840266059SGregory Neil Shapiro ** Parameters: 70940266059SGregory Neil Shapiro ** fp -- the file pointer 71040266059SGregory Neil Shapiro ** buf -- the location to place the data 71140266059SGregory Neil Shapiro ** size -- the number of bytes to read from connection 71240266059SGregory Neil Shapiro ** 71340266059SGregory Neil Shapiro ** Results: 71440266059SGregory Neil Shapiro ** -1 on error 71540266059SGregory Neil Shapiro ** otherwise the number of bytes read 71640266059SGregory Neil Shapiro */ 71740266059SGregory Neil Shapiro 71840266059SGregory Neil Shapiro static ssize_t tls_read __P((SM_FILE_T *, char *, size_t)); 71940266059SGregory Neil Shapiro 72040266059SGregory Neil Shapiro static ssize_t 72140266059SGregory Neil Shapiro tls_read(fp, buf, size) 72240266059SGregory Neil Shapiro SM_FILE_T *fp; 72313058a91SGregory Neil Shapiro char *buf; 72440266059SGregory Neil Shapiro size_t size; 72506f25ae9SGregory Neil Shapiro { 7264e4196cbSGregory Neil Shapiro int r, rfd, wfd, try, ssl_err; 72740266059SGregory Neil Shapiro struct tls_obj *so = (struct tls_obj *) fp->f_cookie; 7284e4196cbSGregory Neil Shapiro time_t tlsstart; 72906f25ae9SGregory Neil Shapiro char *err; 73006f25ae9SGregory Neil Shapiro 7314e4196cbSGregory Neil Shapiro try = 99; 7324e4196cbSGregory Neil Shapiro err = NULL; 7334e4196cbSGregory Neil Shapiro tlsstart = curtime(); 7344e4196cbSGregory Neil Shapiro 7354e4196cbSGregory Neil Shapiro retry: 73640266059SGregory Neil Shapiro r = SSL_read(so->con, (char *) buf, size); 73740266059SGregory Neil Shapiro 73840266059SGregory Neil Shapiro if (r > 0) 73940266059SGregory Neil Shapiro return r; 74040266059SGregory Neil Shapiro 74106f25ae9SGregory Neil Shapiro err = NULL; 7424e4196cbSGregory Neil Shapiro switch (ssl_err = SSL_get_error(so->con, r)) 74306f25ae9SGregory Neil Shapiro { 74406f25ae9SGregory Neil Shapiro case SSL_ERROR_NONE: 74540266059SGregory Neil Shapiro case SSL_ERROR_ZERO_RETURN: 74606f25ae9SGregory Neil Shapiro break; 74706f25ae9SGregory Neil Shapiro case SSL_ERROR_WANT_WRITE: 74840266059SGregory Neil Shapiro err = "read W BLOCK"; 7494e4196cbSGregory Neil Shapiro /* FALLTHROUGH */ 75006f25ae9SGregory Neil Shapiro case SSL_ERROR_WANT_READ: 7514e4196cbSGregory Neil Shapiro if (err == NULL) 75240266059SGregory Neil Shapiro err = "read R BLOCK"; 7534e4196cbSGregory Neil Shapiro rfd = SSL_get_rfd(so->con); 7544e4196cbSGregory Neil Shapiro wfd = SSL_get_wfd(so->con); 7554e4196cbSGregory Neil Shapiro try = tls_retry(so->con, rfd, wfd, tlsstart, 756e3793f76SGregory Neil Shapiro (tls_rd_tmo < 0) ? TimeOuts.to_datablock 757e3793f76SGregory Neil Shapiro : tls_rd_tmo, 758e3793f76SGregory Neil Shapiro ssl_err, "read"); 7594e4196cbSGregory Neil Shapiro if (try > 0) 7604e4196cbSGregory Neil Shapiro goto retry; 7614e4196cbSGregory Neil Shapiro errno = SM_ERR_TIMEOUT; 76206f25ae9SGregory Neil Shapiro break; 7634e4196cbSGregory Neil Shapiro 76406f25ae9SGregory Neil Shapiro case SSL_ERROR_WANT_X509_LOOKUP: 76506f25ae9SGregory Neil Shapiro err = "write X BLOCK"; 76606f25ae9SGregory Neil Shapiro break; 76706f25ae9SGregory Neil Shapiro case SSL_ERROR_SYSCALL: 76840266059SGregory Neil Shapiro if (r == 0 && errno == 0) /* out of protocol EOF found */ 76940266059SGregory Neil Shapiro break; 77006f25ae9SGregory Neil Shapiro err = "syscall error"; 77106f25ae9SGregory Neil Shapiro /* 77206f25ae9SGregory Neil Shapiro get_last_socket_error()); 77306f25ae9SGregory Neil Shapiro */ 77406f25ae9SGregory Neil Shapiro break; 77506f25ae9SGregory Neil Shapiro case SSL_ERROR_SSL: 776b6bacd31SGregory Neil Shapiro #if DEAL_WITH_ERROR_SSL 777959366dcSGregory Neil Shapiro if (r == 0 && errno == 0) /* out of protocol EOF found */ 778959366dcSGregory Neil Shapiro break; 779b6bacd31SGregory Neil Shapiro #endif /* DEAL_WITH_ERROR_SSL */ 78006f25ae9SGregory Neil Shapiro err = "generic SSL error"; 781552d4955SGregory Neil Shapiro 78240266059SGregory Neil Shapiro if (LogLevel > 9) 783552d4955SGregory Neil Shapiro { 784552d4955SGregory Neil Shapiro int pri; 785552d4955SGregory Neil Shapiro 786552d4955SGregory Neil Shapiro if (errno == EAGAIN && try > 0) 787552d4955SGregory Neil Shapiro pri = LOG_DEBUG; 788552d4955SGregory Neil Shapiro else 789552d4955SGregory Neil Shapiro pri = LOG_WARNING; 790552d4955SGregory Neil Shapiro tlslogerr(pri, "read"); 791552d4955SGregory Neil Shapiro } 792959366dcSGregory Neil Shapiro 793b6bacd31SGregory Neil Shapiro #if DEAL_WITH_ERROR_SSL 794959366dcSGregory Neil Shapiro /* avoid repeated calls? */ 795959366dcSGregory Neil Shapiro if (r == 0) 796959366dcSGregory Neil Shapiro r = -1; 797b6bacd31SGregory Neil Shapiro #endif /* DEAL_WITH_ERROR_SSL */ 79806f25ae9SGregory Neil Shapiro break; 79906f25ae9SGregory Neil Shapiro } 80006f25ae9SGregory Neil Shapiro if (err != NULL) 80140266059SGregory Neil Shapiro { 802605302a5SGregory Neil Shapiro int save_errno; 803605302a5SGregory Neil Shapiro 804605302a5SGregory Neil Shapiro save_errno = (errno == 0) ? EIO : errno; 8054e4196cbSGregory Neil Shapiro if (try == 0 && save_errno == SM_ERR_TIMEOUT) 8064e4196cbSGregory Neil Shapiro { 8074e4196cbSGregory Neil Shapiro if (LogLevel > 7) 808a7ec597cSGregory Neil Shapiro sm_syslog(LOG_WARNING, NOQID, 8094e4196cbSGregory Neil Shapiro "STARTTLS: read error=timeout"); 8104e4196cbSGregory Neil Shapiro } 8114e4196cbSGregory Neil Shapiro else if (LogLevel > 8) 812552d4955SGregory Neil Shapiro { 813552d4955SGregory Neil Shapiro int pri; 814552d4955SGregory Neil Shapiro 815552d4955SGregory Neil Shapiro if (save_errno == EAGAIN && try > 0) 816552d4955SGregory Neil Shapiro pri = LOG_DEBUG; 817552d4955SGregory Neil Shapiro else 818552d4955SGregory Neil Shapiro pri = LOG_WARNING; 819552d4955SGregory Neil Shapiro sm_syslog(pri, NOQID, 8204e4196cbSGregory Neil Shapiro "STARTTLS: read error=%s (%d), errno=%d, get_error=%s, retry=%d, ssl_err=%d", 821a7ec597cSGregory Neil Shapiro err, r, errno, 8224e4196cbSGregory Neil Shapiro ERR_error_string(ERR_get_error(), NULL), try, 8234e4196cbSGregory Neil Shapiro ssl_err); 824552d4955SGregory Neil Shapiro } 825a7ec597cSGregory Neil Shapiro else if (LogLevel > 7) 82640266059SGregory Neil Shapiro sm_syslog(LOG_WARNING, NOQID, 827*da7d7b9cSGregory Neil Shapiro "STARTTLS: read error=%s (%d), errno=%d, retry=%d, ssl_err=%d", 8284e4196cbSGregory Neil Shapiro err, r, errno, try, ssl_err); 829605302a5SGregory Neil Shapiro errno = save_errno; 83006f25ae9SGregory Neil Shapiro } 83106f25ae9SGregory Neil Shapiro return r; 83206f25ae9SGregory Neil Shapiro } 83306f25ae9SGregory Neil Shapiro 83440266059SGregory Neil Shapiro /* 83540266059SGregory Neil Shapiro ** TLS_WRITE -- write information out through secure connection 83640266059SGregory Neil Shapiro ** 83740266059SGregory Neil Shapiro ** Parameters: 83840266059SGregory Neil Shapiro ** fp -- the file pointer 83940266059SGregory Neil Shapiro ** buf -- holds the data to be securely written 84040266059SGregory Neil Shapiro ** size -- the number of bytes to write 84140266059SGregory Neil Shapiro ** 84240266059SGregory Neil Shapiro ** Returns: 84340266059SGregory Neil Shapiro ** -1 on error 84440266059SGregory Neil Shapiro ** otherwise number of bytes written 84540266059SGregory Neil Shapiro */ 84640266059SGregory Neil Shapiro 84740266059SGregory Neil Shapiro static ssize_t tls_write __P((SM_FILE_T *, const char *, size_t)); 84840266059SGregory Neil Shapiro 84913058a91SGregory Neil Shapiro static ssize_t 85040266059SGregory Neil Shapiro tls_write(fp, buf, size) 85140266059SGregory Neil Shapiro SM_FILE_T *fp; 85213058a91SGregory Neil Shapiro const char *buf; 85340266059SGregory Neil Shapiro size_t size; 85406f25ae9SGregory Neil Shapiro { 8554e4196cbSGregory Neil Shapiro int r, rfd, wfd, try, ssl_err; 85640266059SGregory Neil Shapiro struct tls_obj *so = (struct tls_obj *) fp->f_cookie; 8574e4196cbSGregory Neil Shapiro time_t tlsstart; 85806f25ae9SGregory Neil Shapiro char *err; 85906f25ae9SGregory Neil Shapiro 8604e4196cbSGregory Neil Shapiro try = 99; 8614e4196cbSGregory Neil Shapiro err = NULL; 8624e4196cbSGregory Neil Shapiro tlsstart = curtime(); 8634e4196cbSGregory Neil Shapiro 8644e4196cbSGregory Neil Shapiro retry: 86540266059SGregory Neil Shapiro r = SSL_write(so->con, (char *) buf, size); 86640266059SGregory Neil Shapiro 86740266059SGregory Neil Shapiro if (r > 0) 86840266059SGregory Neil Shapiro return r; 86906f25ae9SGregory Neil Shapiro err = NULL; 8704e4196cbSGregory Neil Shapiro switch (ssl_err = SSL_get_error(so->con, r)) 87106f25ae9SGregory Neil Shapiro { 87206f25ae9SGregory Neil Shapiro case SSL_ERROR_NONE: 87340266059SGregory Neil Shapiro case SSL_ERROR_ZERO_RETURN: 87406f25ae9SGregory Neil Shapiro break; 87506f25ae9SGregory Neil Shapiro case SSL_ERROR_WANT_WRITE: 8764e4196cbSGregory Neil Shapiro err = "read W BLOCK"; 8774e4196cbSGregory Neil Shapiro /* FALLTHROUGH */ 87806f25ae9SGregory Neil Shapiro case SSL_ERROR_WANT_READ: 8794e4196cbSGregory Neil Shapiro if (err == NULL) 8804e4196cbSGregory Neil Shapiro err = "read R BLOCK"; 8814e4196cbSGregory Neil Shapiro rfd = SSL_get_rfd(so->con); 8824e4196cbSGregory Neil Shapiro wfd = SSL_get_wfd(so->con); 8834e4196cbSGregory Neil Shapiro try = tls_retry(so->con, rfd, wfd, tlsstart, 8844e4196cbSGregory Neil Shapiro DATA_PROGRESS_TIMEOUT, ssl_err, "write"); 8854e4196cbSGregory Neil Shapiro if (try > 0) 8864e4196cbSGregory Neil Shapiro goto retry; 8874e4196cbSGregory Neil Shapiro errno = SM_ERR_TIMEOUT; 88806f25ae9SGregory Neil Shapiro break; 88906f25ae9SGregory Neil Shapiro case SSL_ERROR_WANT_X509_LOOKUP: 89006f25ae9SGregory Neil Shapiro err = "write X BLOCK"; 89106f25ae9SGregory Neil Shapiro break; 89206f25ae9SGregory Neil Shapiro case SSL_ERROR_SYSCALL: 89340266059SGregory Neil Shapiro if (r == 0 && errno == 0) /* out of protocol EOF found */ 89440266059SGregory Neil Shapiro break; 89506f25ae9SGregory Neil Shapiro err = "syscall error"; 89606f25ae9SGregory Neil Shapiro /* 89706f25ae9SGregory Neil Shapiro get_last_socket_error()); 89806f25ae9SGregory Neil Shapiro */ 89906f25ae9SGregory Neil Shapiro break; 90006f25ae9SGregory Neil Shapiro case SSL_ERROR_SSL: 90106f25ae9SGregory Neil Shapiro err = "generic SSL error"; 90206f25ae9SGregory Neil Shapiro /* 90306f25ae9SGregory Neil Shapiro ERR_GET_REASON(ERR_peek_error())); 90406f25ae9SGregory Neil Shapiro */ 90540266059SGregory Neil Shapiro if (LogLevel > 9) 906552d4955SGregory Neil Shapiro tlslogerr(LOG_WARNING, "write"); 907959366dcSGregory Neil Shapiro 908b6bacd31SGregory Neil Shapiro #if DEAL_WITH_ERROR_SSL 909959366dcSGregory Neil Shapiro /* avoid repeated calls? */ 910959366dcSGregory Neil Shapiro if (r == 0) 911959366dcSGregory Neil Shapiro r = -1; 912b6bacd31SGregory Neil Shapiro #endif /* DEAL_WITH_ERROR_SSL */ 91306f25ae9SGregory Neil Shapiro break; 91406f25ae9SGregory Neil Shapiro } 91506f25ae9SGregory Neil Shapiro if (err != NULL) 91640266059SGregory Neil Shapiro { 917605302a5SGregory Neil Shapiro int save_errno; 918605302a5SGregory Neil Shapiro 919605302a5SGregory Neil Shapiro save_errno = (errno == 0) ? EIO : errno; 9204e4196cbSGregory Neil Shapiro if (try == 0 && save_errno == SM_ERR_TIMEOUT) 9214e4196cbSGregory Neil Shapiro { 9224e4196cbSGregory Neil Shapiro if (LogLevel > 7) 923a7ec597cSGregory Neil Shapiro sm_syslog(LOG_WARNING, NOQID, 9244e4196cbSGregory Neil Shapiro "STARTTLS: write error=timeout"); 9254e4196cbSGregory Neil Shapiro } 9264e4196cbSGregory Neil Shapiro else if (LogLevel > 8) 9274e4196cbSGregory Neil Shapiro sm_syslog(LOG_WARNING, NOQID, 9284e4196cbSGregory Neil Shapiro "STARTTLS: write error=%s (%d), errno=%d, get_error=%s, retry=%d, ssl_err=%d", 929a7ec597cSGregory Neil Shapiro err, r, errno, 9304e4196cbSGregory Neil Shapiro ERR_error_string(ERR_get_error(), NULL), try, 9314e4196cbSGregory Neil Shapiro ssl_err); 932a7ec597cSGregory Neil Shapiro else if (LogLevel > 7) 93340266059SGregory Neil Shapiro sm_syslog(LOG_WARNING, NOQID, 9344e4196cbSGregory Neil Shapiro "STARTTLS: write error=%s (%d), errno=%d, retry=%d, ssl_err=%d", 9354e4196cbSGregory Neil Shapiro err, r, errno, try, ssl_err); 936605302a5SGregory Neil Shapiro errno = save_errno; 93706f25ae9SGregory Neil Shapiro } 93806f25ae9SGregory Neil Shapiro return r; 93906f25ae9SGregory Neil Shapiro } 94006f25ae9SGregory Neil Shapiro 94140266059SGregory Neil Shapiro /* 94240266059SGregory Neil Shapiro ** SFDCTLS -- create tls file type and open in and out file pointers 94340266059SGregory Neil Shapiro ** for sendmail to read from and write to. 94440266059SGregory Neil Shapiro ** 94540266059SGregory Neil Shapiro ** Parameters: 94640266059SGregory Neil Shapiro ** fin -- data input source being replaced 94740266059SGregory Neil Shapiro ** fout -- data output source being replaced 948a7ec597cSGregory Neil Shapiro ** con -- the tls connection pointer 94940266059SGregory Neil Shapiro ** 95040266059SGregory Neil Shapiro ** Returns: 95140266059SGregory Neil Shapiro ** -1 on error 95240266059SGregory Neil Shapiro ** 0 on success 95340266059SGregory Neil Shapiro ** 95440266059SGregory Neil Shapiro ** Side effects: 95540266059SGregory Neil Shapiro ** The arguments "fin" and "fout" are replaced with the new 95640266059SGregory Neil Shapiro ** SM_FILE_T pointers. 95740266059SGregory Neil Shapiro ** The original "fin" and "fout" are preserved in the tls file 95840266059SGregory Neil Shapiro ** type but are not actually used because of the design of TLS. 95940266059SGregory Neil Shapiro */ 96006f25ae9SGregory Neil Shapiro 96106f25ae9SGregory Neil Shapiro int 96206f25ae9SGregory Neil Shapiro sfdctls(fin, fout, con) 96340266059SGregory Neil Shapiro SM_FILE_T **fin; 96440266059SGregory Neil Shapiro SM_FILE_T **fout; 96506f25ae9SGregory Neil Shapiro SSL *con; 96606f25ae9SGregory Neil Shapiro { 96740266059SGregory Neil Shapiro SM_FILE_T *tlsin, *tlsout; 96840266059SGregory Neil Shapiro SM_FILE_T SM_IO_SET_TYPE(tls_vector, "tls", tls_open, tls_close, 96940266059SGregory Neil Shapiro tls_read, tls_write, NULL, tls_getinfo, NULL, 97040266059SGregory Neil Shapiro SM_TIME_FOREVER); 97140266059SGregory Neil Shapiro struct tls_info info; 97206f25ae9SGregory Neil Shapiro 97340266059SGregory Neil Shapiro SM_ASSERT(con != NULL); 97406f25ae9SGregory Neil Shapiro 97540266059SGregory Neil Shapiro SM_IO_INIT_TYPE(tls_vector, "tls", tls_open, tls_close, 97640266059SGregory Neil Shapiro tls_read, tls_write, NULL, tls_getinfo, NULL, 97740266059SGregory Neil Shapiro SM_TIME_FOREVER); 97840266059SGregory Neil Shapiro info.fp = *fin; 97940266059SGregory Neil Shapiro info.con = con; 980e92d3f3fSGregory Neil Shapiro tlsin = sm_io_open(&tls_vector, SM_TIME_DEFAULT, &info, SM_IO_RDONLY_B, 98140266059SGregory Neil Shapiro NULL); 98240266059SGregory Neil Shapiro if (tlsin == NULL) 98340266059SGregory Neil Shapiro return -1; 98406f25ae9SGregory Neil Shapiro 98540266059SGregory Neil Shapiro info.fp = *fout; 986e92d3f3fSGregory Neil Shapiro tlsout = sm_io_open(&tls_vector, SM_TIME_DEFAULT, &info, SM_IO_WRONLY_B, 98740266059SGregory Neil Shapiro NULL); 98840266059SGregory Neil Shapiro if (tlsout == NULL) 98942e5d165SGregory Neil Shapiro { 99040266059SGregory Neil Shapiro (void) sm_io_close(tlsin, SM_TIME_DEFAULT); 99142e5d165SGregory Neil Shapiro return -1; 99242e5d165SGregory Neil Shapiro } 99340266059SGregory Neil Shapiro sm_io_automode(tlsin, tlsout); 99406f25ae9SGregory Neil Shapiro 99540266059SGregory Neil Shapiro *fin = tlsin; 99640266059SGregory Neil Shapiro *fout = tlsout; 99706f25ae9SGregory Neil Shapiro return 0; 99806f25ae9SGregory Neil Shapiro } 99940266059SGregory Neil Shapiro #endif /* STARTTLS */ 1000