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>
16da7d7b9cSGregory 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
225b0945b5SGregory Neil Shapiro #endif
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
sasl_getinfo(fp,what,valp)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;
695b0945b5SGregory Neil Shapiro return so->fp->f_file; /* for stdio fileno() compatibility */
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
sasl_open(fp,info,flags,rpool)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
sasl_close(fp)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;
1572fb4f839SGregory Neil Shapiro SM_CLOSE_FP(so->fp);
15840266059SGregory Neil Shapiro sm_free(so);
15940266059SGregory Neil Shapiro so = NULL;
16040266059SGregory Neil Shapiro return 0;
16140266059SGregory Neil Shapiro }
16240266059SGregory Neil Shapiro
163193538b7SGregory Neil Shapiro /* how to deallocate a buffer allocated by SASL */
16440266059SGregory Neil Shapiro extern void sm_sasl_free __P((void *));
16540266059SGregory Neil Shapiro # define SASL_DEALLOC(b) sm_sasl_free(b)
16640266059SGregory Neil Shapiro
16740266059SGregory Neil Shapiro /*
16840266059SGregory Neil Shapiro ** SASL_READ -- read encrypted information and decrypt it for the caller
16940266059SGregory Neil Shapiro **
17040266059SGregory Neil Shapiro ** Parameters:
17140266059SGregory Neil Shapiro ** fp -- the file pointer
17240266059SGregory Neil Shapiro ** buf -- the location to place the decrypted information
17340266059SGregory Neil Shapiro ** size -- the number of bytes to read after decryption
17440266059SGregory Neil Shapiro **
175*d39bd2c1SGregory Neil Shapiro ** Returns:
17640266059SGregory Neil Shapiro ** -1 on error
17740266059SGregory Neil Shapiro ** otherwise the number of bytes read
17840266059SGregory Neil Shapiro */
17940266059SGregory Neil Shapiro
18040266059SGregory Neil Shapiro static ssize_t sasl_read __P((SM_FILE_T *, char *, size_t));
181193538b7SGregory Neil Shapiro
18206f25ae9SGregory Neil Shapiro static ssize_t
sasl_read(fp,buf,size)18340266059SGregory Neil Shapiro sasl_read(fp, buf, size)
18440266059SGregory Neil Shapiro SM_FILE_T *fp;
18540266059SGregory Neil Shapiro char *buf;
18606f25ae9SGregory Neil Shapiro size_t size;
18706f25ae9SGregory Neil Shapiro {
18840266059SGregory Neil Shapiro int result;
18940266059SGregory Neil Shapiro ssize_t len;
19094c01205SGregory Neil Shapiro # if SASL >= 20000
19113bd1963SGregory Neil Shapiro static const char *outbuf = NULL;
1925b0945b5SGregory Neil Shapiro # else
193193538b7SGregory Neil Shapiro static char *outbuf = NULL;
1945b0945b5SGregory Neil Shapiro # endif
195193538b7SGregory Neil Shapiro static unsigned int outlen = 0;
196193538b7SGregory Neil Shapiro static unsigned int offset = 0;
19740266059SGregory Neil Shapiro struct sasl_obj *so = (struct sasl_obj *) fp->f_cookie;
19806f25ae9SGregory Neil Shapiro
199193538b7SGregory Neil Shapiro /*
200193538b7SGregory Neil Shapiro ** sasl_decode() may require more data than a single read() returns.
201193538b7SGregory Neil Shapiro ** Hence we have to put a loop around the decoding.
202193538b7SGregory Neil Shapiro ** This also requires that we may have to split up the returned
203193538b7SGregory Neil Shapiro ** data since it might be larger than the allowed size.
204193538b7SGregory Neil Shapiro ** Therefore we use a static pointer and return portions of it
205193538b7SGregory Neil Shapiro ** if necessary.
206a7ec597cSGregory Neil Shapiro ** XXX Note: This function is not thread-safe nor can it be used
207a7ec597cSGregory Neil Shapiro ** on more than one file. A correct implementation would store
208a7ec597cSGregory Neil Shapiro ** this data in fp->f_cookie.
209193538b7SGregory Neil Shapiro */
21006f25ae9SGregory Neil Shapiro
21113bd1963SGregory Neil Shapiro # if SASL >= 20000
21213bd1963SGregory Neil Shapiro while (outlen == 0)
2135b0945b5SGregory Neil Shapiro # else
214193538b7SGregory Neil Shapiro while (outbuf == NULL && outlen == 0)
2155b0945b5SGregory Neil Shapiro # endif
216193538b7SGregory Neil Shapiro {
21740266059SGregory Neil Shapiro len = sm_io_read(so->fp, SM_TIME_DEFAULT, buf, size);
21806f25ae9SGregory Neil Shapiro if (len <= 0)
21906f25ae9SGregory Neil Shapiro return len;
22040266059SGregory Neil Shapiro result = sasl_decode(so->conn, buf,
22140266059SGregory Neil Shapiro (unsigned int) len, &outbuf, &outlen);
22206f25ae9SGregory Neil Shapiro if (result != SASL_OK)
22306f25ae9SGregory Neil Shapiro {
2244e4196cbSGregory Neil Shapiro if (LogLevel > 7)
2254e4196cbSGregory Neil Shapiro sm_syslog(LOG_WARNING, NOQID,
2264e4196cbSGregory Neil Shapiro "AUTH: sasl_decode error=%d", result);
227193538b7SGregory Neil Shapiro outbuf = NULL;
228193538b7SGregory Neil Shapiro offset = 0;
229193538b7SGregory Neil Shapiro outlen = 0;
23006f25ae9SGregory Neil Shapiro return -1;
23106f25ae9SGregory Neil Shapiro }
232193538b7SGregory Neil Shapiro }
23306f25ae9SGregory Neil Shapiro
23440266059SGregory Neil Shapiro if (outbuf == NULL)
23506f25ae9SGregory Neil Shapiro {
23640266059SGregory Neil Shapiro /* be paranoid: outbuf == NULL but outlen != 0 */
23740266059SGregory Neil Shapiro syserr("@sasl_read failure: outbuf == NULL but outlen != 0");
23840266059SGregory Neil Shapiro /* NOTREACHED */
23940266059SGregory Neil Shapiro }
240193538b7SGregory Neil Shapiro if (outlen - offset > size)
241193538b7SGregory Neil Shapiro {
242193538b7SGregory Neil Shapiro /* return another part of the buffer */
24340266059SGregory Neil Shapiro (void) memcpy(buf, outbuf + offset, size);
244193538b7SGregory Neil Shapiro offset += size;
24540266059SGregory Neil Shapiro len = size;
24606f25ae9SGregory Neil Shapiro }
247193538b7SGregory Neil Shapiro else
248193538b7SGregory Neil Shapiro {
249193538b7SGregory Neil Shapiro /* return the rest of the buffer */
25040266059SGregory Neil Shapiro len = outlen - offset;
25140266059SGregory Neil Shapiro (void) memcpy(buf, outbuf + offset, (size_t) len);
25294c01205SGregory Neil Shapiro # if SASL < 20000
253193538b7SGregory Neil Shapiro SASL_DEALLOC(outbuf);
2545b0945b5SGregory Neil Shapiro # endif
255193538b7SGregory Neil Shapiro outbuf = NULL;
256193538b7SGregory Neil Shapiro offset = 0;
257193538b7SGregory Neil Shapiro outlen = 0;
258193538b7SGregory Neil Shapiro }
25940266059SGregory Neil Shapiro return len;
26006f25ae9SGregory Neil Shapiro }
26106f25ae9SGregory Neil Shapiro
26240266059SGregory Neil Shapiro /*
26340266059SGregory Neil Shapiro ** SASL_WRITE -- write information out after encrypting it
26440266059SGregory Neil Shapiro **
26540266059SGregory Neil Shapiro ** Parameters:
26640266059SGregory Neil Shapiro ** fp -- the file pointer
26740266059SGregory Neil Shapiro ** buf -- holds the data to be encrypted and written
26840266059SGregory Neil Shapiro ** size -- the number of bytes to have encrypted and written
26940266059SGregory Neil Shapiro **
27040266059SGregory Neil Shapiro ** Returns:
27140266059SGregory Neil Shapiro ** -1 on error
27240266059SGregory Neil Shapiro ** otherwise number of bytes written
27340266059SGregory Neil Shapiro */
27440266059SGregory Neil Shapiro
27540266059SGregory Neil Shapiro static ssize_t sasl_write __P((SM_FILE_T *, const char *, size_t));
27640266059SGregory Neil Shapiro
27706f25ae9SGregory Neil Shapiro static ssize_t
sasl_write(fp,buf,size)27840266059SGregory Neil Shapiro sasl_write(fp, buf, size)
27940266059SGregory Neil Shapiro SM_FILE_T *fp;
28040266059SGregory Neil Shapiro const char *buf;
28106f25ae9SGregory Neil Shapiro size_t size;
28206f25ae9SGregory Neil Shapiro {
28306f25ae9SGregory Neil Shapiro int result;
28494c01205SGregory Neil Shapiro # if SASL >= 20000
28594c01205SGregory Neil Shapiro const char *outbuf;
2865b0945b5SGregory Neil Shapiro # else
28706f25ae9SGregory Neil Shapiro char *outbuf;
2885b0945b5SGregory Neil Shapiro # endif
289b6bacd31SGregory Neil Shapiro unsigned int outlen, *maxencode;
29040266059SGregory Neil Shapiro size_t ret = 0, total = 0;
29140266059SGregory Neil Shapiro struct sasl_obj *so = (struct sasl_obj *) fp->f_cookie;
29206f25ae9SGregory Neil Shapiro
293b6bacd31SGregory Neil Shapiro /*
294b6bacd31SGregory Neil Shapiro ** Fetch the maximum input buffer size for sasl_encode().
295b6bacd31SGregory Neil Shapiro ** This can be less than the size set in attemptauth()
2969bd497b8SGregory Neil Shapiro ** due to a negotiation with the other side, e.g.,
297b6bacd31SGregory Neil Shapiro ** Cyrus IMAP lmtp program sets maxbuf=4096,
2985b0945b5SGregory Neil Shapiro ** digestmd5 subtracts 25 and hence we'll get 4071
299b6bacd31SGregory Neil Shapiro ** instead of 8192 (MAXOUTLEN).
300b6bacd31SGregory Neil Shapiro ** Hack (for now): simply reduce the size, callers are (must be)
301b6bacd31SGregory Neil Shapiro ** able to deal with that and invoke sasl_write() again with
302b6bacd31SGregory Neil Shapiro ** the rest of the data.
303b6bacd31SGregory Neil Shapiro ** Note: it would be better to store this value in the context
304b6bacd31SGregory Neil Shapiro ** after the negotiation.
305b6bacd31SGregory Neil Shapiro */
306b6bacd31SGregory Neil Shapiro
307b6bacd31SGregory Neil Shapiro result = sasl_getprop(so->conn, SASL_MAXOUTBUF,
308b6bacd31SGregory Neil Shapiro (const void **) &maxencode);
309b6bacd31SGregory Neil Shapiro if (result == SASL_OK && size > *maxencode && *maxencode > 0)
310b6bacd31SGregory Neil Shapiro size = *maxencode;
311b6bacd31SGregory Neil Shapiro
31240266059SGregory Neil Shapiro result = sasl_encode(so->conn, buf,
31340266059SGregory Neil Shapiro (unsigned int) size, &outbuf, &outlen);
31406f25ae9SGregory Neil Shapiro
31506f25ae9SGregory Neil Shapiro if (result != SASL_OK)
3164e4196cbSGregory Neil Shapiro {
3174e4196cbSGregory Neil Shapiro if (LogLevel > 7)
3184e4196cbSGregory Neil Shapiro sm_syslog(LOG_WARNING, NOQID,
3194e4196cbSGregory Neil Shapiro "AUTH: sasl_encode error=%d", result);
32006f25ae9SGregory Neil Shapiro return -1;
3214e4196cbSGregory Neil Shapiro }
32206f25ae9SGregory Neil Shapiro
32306f25ae9SGregory Neil Shapiro if (outbuf != NULL)
32406f25ae9SGregory Neil Shapiro {
32540266059SGregory Neil Shapiro while (outlen > 0)
32640266059SGregory Neil Shapiro {
327af9557fdSGregory Neil Shapiro errno = 0;
328605302a5SGregory Neil Shapiro /* XXX result == 0? */
32940266059SGregory Neil Shapiro ret = sm_io_write(so->fp, SM_TIME_DEFAULT,
33040266059SGregory Neil Shapiro &outbuf[total], outlen);
331a7ec597cSGregory Neil Shapiro if (ret <= 0)
332a7ec597cSGregory Neil Shapiro return ret;
33340266059SGregory Neil Shapiro outlen -= ret;
33440266059SGregory Neil Shapiro total += ret;
33540266059SGregory Neil Shapiro }
33694c01205SGregory Neil Shapiro # if SASL < 20000
337193538b7SGregory Neil Shapiro SASL_DEALLOC(outbuf);
3385b0945b5SGregory Neil Shapiro # endif
33906f25ae9SGregory Neil Shapiro }
34006f25ae9SGregory Neil Shapiro return size;
34106f25ae9SGregory Neil Shapiro }
34206f25ae9SGregory Neil Shapiro
34340266059SGregory Neil Shapiro /*
34440266059SGregory Neil Shapiro ** SFDCSASL -- create sasl file type and open in and out file pointers
34540266059SGregory Neil Shapiro ** for sendmail to read from and write to.
34640266059SGregory Neil Shapiro **
34740266059SGregory Neil Shapiro ** Parameters:
34840266059SGregory Neil Shapiro ** fin -- the sm_io file encrypted data to be read from
349af9557fdSGregory Neil Shapiro ** fout -- the sm_io file encrypted data to be written to
35040266059SGregory Neil Shapiro ** conn -- the sasl connection pointer
351af9557fdSGregory Neil Shapiro ** tmo -- timeout
35240266059SGregory Neil Shapiro **
35340266059SGregory Neil Shapiro ** Returns:
35440266059SGregory Neil Shapiro ** -1 on error
35540266059SGregory Neil Shapiro ** 0 on success
35640266059SGregory Neil Shapiro **
35740266059SGregory Neil Shapiro ** Side effects:
35840266059SGregory Neil Shapiro ** The arguments "fin" and "fout" are replaced with the new
35940266059SGregory Neil Shapiro ** SM_FILE_T pointers.
36040266059SGregory Neil Shapiro */
36140266059SGregory Neil Shapiro
36206f25ae9SGregory Neil Shapiro int
sfdcsasl(fin,fout,conn,tmo)363af9557fdSGregory Neil Shapiro sfdcsasl(fin, fout, conn, tmo)
36440266059SGregory Neil Shapiro SM_FILE_T **fin;
36540266059SGregory Neil Shapiro SM_FILE_T **fout;
36606f25ae9SGregory Neil Shapiro sasl_conn_t *conn;
367af9557fdSGregory Neil Shapiro int tmo;
36806f25ae9SGregory Neil Shapiro {
36940266059SGregory Neil Shapiro SM_FILE_T *newin, *newout;
37040266059SGregory Neil Shapiro SM_FILE_T SM_IO_SET_TYPE(sasl_vector, "sasl", sasl_open, sasl_close,
37140266059SGregory Neil Shapiro sasl_read, sasl_write, NULL, sasl_getinfo, NULL,
372af9557fdSGregory Neil Shapiro SM_TIME_DEFAULT);
37340266059SGregory Neil Shapiro struct sasl_info info;
37406f25ae9SGregory Neil Shapiro
37506f25ae9SGregory Neil Shapiro if (conn == NULL)
37606f25ae9SGregory Neil Shapiro {
37706f25ae9SGregory Neil Shapiro /* no need to do anything */
37806f25ae9SGregory Neil Shapiro return 0;
37906f25ae9SGregory Neil Shapiro }
38006f25ae9SGregory Neil Shapiro
38140266059SGregory Neil Shapiro SM_IO_INIT_TYPE(sasl_vector, "sasl", sasl_open, sasl_close,
38240266059SGregory Neil Shapiro sasl_read, sasl_write, NULL, sasl_getinfo, NULL,
383af9557fdSGregory Neil Shapiro SM_TIME_DEFAULT);
38440266059SGregory Neil Shapiro info.fp = *fin;
38540266059SGregory Neil Shapiro info.conn = conn;
386e92d3f3fSGregory Neil Shapiro newin = sm_io_open(&sasl_vector, SM_TIME_DEFAULT, &info,
387e92d3f3fSGregory Neil Shapiro SM_IO_RDONLY_B, NULL);
38806f25ae9SGregory Neil Shapiro
38940266059SGregory Neil Shapiro if (newin == NULL)
39040266059SGregory Neil Shapiro return -1;
39106f25ae9SGregory Neil Shapiro
39240266059SGregory Neil Shapiro info.fp = *fout;
39340266059SGregory Neil Shapiro info.conn = conn;
394e92d3f3fSGregory Neil Shapiro newout = sm_io_open(&sasl_vector, SM_TIME_DEFAULT, &info,
395e92d3f3fSGregory Neil Shapiro SM_IO_WRONLY_B, NULL);
39606f25ae9SGregory Neil Shapiro
39740266059SGregory Neil Shapiro if (newout == NULL)
39806f25ae9SGregory Neil Shapiro {
39940266059SGregory Neil Shapiro (void) sm_io_close(newin, SM_TIME_DEFAULT);
40006f25ae9SGregory Neil Shapiro return -1;
40106f25ae9SGregory Neil Shapiro }
40240266059SGregory Neil Shapiro sm_io_automode(newin, newout);
40340266059SGregory Neil Shapiro
404af9557fdSGregory Neil Shapiro sm_io_setinfo(*fin, SM_IO_WHAT_TIMEOUT, &tmo);
405af9557fdSGregory Neil Shapiro sm_io_setinfo(*fout, SM_IO_WHAT_TIMEOUT, &tmo);
406af9557fdSGregory Neil Shapiro
40740266059SGregory Neil Shapiro *fin = newin;
40840266059SGregory Neil Shapiro *fout = newout;
40906f25ae9SGregory Neil Shapiro return 0;
41006f25ae9SGregory Neil Shapiro }
41140266059SGregory Neil Shapiro #endif /* SASL */
41206f25ae9SGregory Neil Shapiro
41340266059SGregory Neil Shapiro #if STARTTLS
41406f25ae9SGregory Neil Shapiro # include "sfsasl.h"
4155b0945b5SGregory Neil Shapiro # include <tls.h>
41606f25ae9SGregory Neil Shapiro # include <openssl/err.h>
41706f25ae9SGregory Neil Shapiro
41840266059SGregory Neil Shapiro /* Structure used by the "tls" file type */
41940266059SGregory Neil Shapiro struct tls_obj
42040266059SGregory Neil Shapiro {
42140266059SGregory Neil Shapiro SM_FILE_T *fp;
42240266059SGregory Neil Shapiro SSL *con;
42340266059SGregory Neil Shapiro };
42440266059SGregory Neil Shapiro
42540266059SGregory Neil Shapiro struct tls_info
42640266059SGregory Neil Shapiro {
42740266059SGregory Neil Shapiro SM_FILE_T *fp;
42840266059SGregory Neil Shapiro SSL *con;
42940266059SGregory Neil Shapiro };
43040266059SGregory Neil Shapiro
43140266059SGregory Neil Shapiro /*
43240266059SGregory Neil Shapiro ** TLS_GETINFO - returns requested information about a "tls" file
43340266059SGregory Neil Shapiro ** descriptor.
43440266059SGregory Neil Shapiro **
43540266059SGregory Neil Shapiro ** Parameters:
43640266059SGregory Neil Shapiro ** fp -- the file descriptor
43740266059SGregory Neil Shapiro ** what -- the type of information requested
43840266059SGregory Neil Shapiro ** valp -- the thang to return the information in (unused)
43940266059SGregory Neil Shapiro **
44040266059SGregory Neil Shapiro ** Returns:
44140266059SGregory Neil Shapiro ** -1 for unknown requests
44240266059SGregory Neil Shapiro ** >=0 on success with valp filled in (if possible).
44340266059SGregory Neil Shapiro */
44440266059SGregory Neil Shapiro
44540266059SGregory Neil Shapiro static int tls_getinfo __P((SM_FILE_T *, int, void *));
44640266059SGregory Neil Shapiro
44740266059SGregory Neil Shapiro /* ARGSUSED2 */
44813058a91SGregory Neil Shapiro static int
tls_getinfo(fp,what,valp)44940266059SGregory Neil Shapiro tls_getinfo(fp, what, valp)
45040266059SGregory Neil Shapiro SM_FILE_T *fp;
45140266059SGregory Neil Shapiro int what;
45240266059SGregory Neil Shapiro void *valp;
45340266059SGregory Neil Shapiro {
45440266059SGregory Neil Shapiro struct tls_obj *so = (struct tls_obj *) fp->f_cookie;
45540266059SGregory Neil Shapiro
45640266059SGregory Neil Shapiro switch (what)
45740266059SGregory Neil Shapiro {
45840266059SGregory Neil Shapiro case SM_IO_WHAT_FD:
45940266059SGregory Neil Shapiro if (so->fp == NULL)
46040266059SGregory Neil Shapiro return -1;
4615b0945b5SGregory Neil Shapiro return so->fp->f_file; /* for stdio fileno() compatibility */
46240266059SGregory Neil Shapiro
46340266059SGregory Neil Shapiro case SM_IO_IS_READABLE:
46440266059SGregory Neil Shapiro return SSL_pending(so->con) > 0;
46540266059SGregory Neil Shapiro
46640266059SGregory Neil Shapiro default:
46740266059SGregory Neil Shapiro return -1;
46840266059SGregory Neil Shapiro }
46940266059SGregory Neil Shapiro }
47040266059SGregory Neil Shapiro
47140266059SGregory Neil Shapiro /*
47240266059SGregory Neil Shapiro ** TLS_OPEN -- creates the tls specific information for opening a
47340266059SGregory Neil Shapiro ** file of the tls type.
47440266059SGregory Neil Shapiro **
47540266059SGregory Neil Shapiro ** Parameters:
47640266059SGregory Neil Shapiro ** fp -- the file pointer associated with the new open
47740266059SGregory Neil Shapiro ** info -- the sm_io file pointer holding the open and the
47840266059SGregory Neil Shapiro ** TLS encryption connection to be read from or written to
47940266059SGregory Neil Shapiro ** flags -- ignored
48040266059SGregory Neil Shapiro ** rpool -- ignored
48140266059SGregory Neil Shapiro **
48240266059SGregory Neil Shapiro ** Returns:
48340266059SGregory Neil Shapiro ** 0 on success
48440266059SGregory Neil Shapiro */
48540266059SGregory Neil Shapiro
48640266059SGregory Neil Shapiro static int tls_open __P((SM_FILE_T *, const void *, int, const void *));
48740266059SGregory Neil Shapiro
48840266059SGregory Neil Shapiro /* ARGSUSED2 */
48940266059SGregory Neil Shapiro static int
tls_open(fp,info,flags,rpool)49040266059SGregory Neil Shapiro tls_open(fp, info, flags, rpool)
49140266059SGregory Neil Shapiro SM_FILE_T *fp;
49240266059SGregory Neil Shapiro const void *info;
49340266059SGregory Neil Shapiro int flags;
49440266059SGregory Neil Shapiro const void *rpool;
49540266059SGregory Neil Shapiro {
49640266059SGregory Neil Shapiro struct tls_obj *so;
49740266059SGregory Neil Shapiro struct tls_info *ti = (struct tls_info *) info;
49840266059SGregory Neil Shapiro
49940266059SGregory Neil Shapiro so = (struct tls_obj *) sm_malloc(sizeof(struct tls_obj));
500a7ec597cSGregory Neil Shapiro if (so == NULL)
501a7ec597cSGregory Neil Shapiro {
502a7ec597cSGregory Neil Shapiro errno = ENOMEM;
503a7ec597cSGregory Neil Shapiro return -1;
504a7ec597cSGregory Neil Shapiro }
50540266059SGregory Neil Shapiro so->fp = ti->fp;
50640266059SGregory Neil Shapiro so->con = ti->con;
50740266059SGregory Neil Shapiro
50840266059SGregory Neil Shapiro /*
50940266059SGregory Neil Shapiro ** We try to get the "raw" file descriptor that TLS uses to
51040266059SGregory Neil Shapiro ** do the actual read/write with. This is to allow us control
51140266059SGregory Neil Shapiro ** over the file descriptor being a blocking or non-blocking type.
51240266059SGregory Neil Shapiro ** Under the covers TLS handles the change and this allows us
51340266059SGregory Neil Shapiro ** to do timeouts with sm_io.
51440266059SGregory Neil Shapiro */
51540266059SGregory Neil Shapiro
51640266059SGregory Neil Shapiro fp->f_file = sm_io_getinfo(so->fp, SM_IO_WHAT_FD, NULL);
51740266059SGregory Neil Shapiro (void) sm_io_setvbuf(so->fp, SM_TIME_DEFAULT, NULL, SM_IO_NOW, 0);
51840266059SGregory Neil Shapiro fp->f_cookie = so;
51940266059SGregory Neil Shapiro return 0;
52040266059SGregory Neil Shapiro }
52140266059SGregory Neil Shapiro
52240266059SGregory Neil Shapiro /*
52340266059SGregory Neil Shapiro ** TLS_CLOSE -- close the tls specific parts of the tls file pointer
52440266059SGregory Neil Shapiro **
52540266059SGregory Neil Shapiro ** Parameters:
52640266059SGregory Neil Shapiro ** fp -- the file pointer to close
52740266059SGregory Neil Shapiro **
52840266059SGregory Neil Shapiro ** Returns:
52940266059SGregory Neil Shapiro ** 0 on success
53040266059SGregory Neil Shapiro */
53140266059SGregory Neil Shapiro
53240266059SGregory Neil Shapiro static int tls_close __P((SM_FILE_T *));
53340266059SGregory Neil Shapiro
53440266059SGregory Neil Shapiro static int
tls_close(fp)53540266059SGregory Neil Shapiro tls_close(fp)
53640266059SGregory Neil Shapiro SM_FILE_T *fp;
53740266059SGregory Neil Shapiro {
53840266059SGregory Neil Shapiro struct tls_obj *so;
53940266059SGregory Neil Shapiro
54040266059SGregory Neil Shapiro so = (struct tls_obj *) fp->f_cookie;
541a7ec597cSGregory Neil Shapiro if (so == NULL)
542a7ec597cSGregory Neil Shapiro return 0;
5432fb4f839SGregory Neil Shapiro SM_CLOSE_FP(so->fp);
54440266059SGregory Neil Shapiro sm_free(so);
54540266059SGregory Neil Shapiro so = NULL;
54640266059SGregory Neil Shapiro return 0;
54740266059SGregory Neil Shapiro }
54840266059SGregory Neil Shapiro
54940266059SGregory Neil Shapiro /* maximum number of retries for TLS related I/O due to handshakes */
55040266059SGregory Neil Shapiro # define MAX_TLS_IOS 4
55140266059SGregory Neil Shapiro
55240266059SGregory Neil Shapiro /*
5534e4196cbSGregory Neil Shapiro ** TLS_RETRY -- check whether a failed SSL operation can be retried
5544e4196cbSGregory Neil Shapiro **
5554e4196cbSGregory Neil Shapiro ** Parameters:
5564e4196cbSGregory Neil Shapiro ** ssl -- TLS structure
5574e4196cbSGregory Neil Shapiro ** rfd -- read fd
5584e4196cbSGregory Neil Shapiro ** wfd -- write fd
5594e4196cbSGregory Neil Shapiro ** tlsstart -- start time of TLS operation
5604e4196cbSGregory Neil Shapiro ** timeout -- timeout for TLS operation
5614e4196cbSGregory Neil Shapiro ** err -- SSL error
5624e4196cbSGregory Neil Shapiro ** where -- description of operation
5634e4196cbSGregory Neil Shapiro **
564*d39bd2c1SGregory Neil Shapiro ** Returns:
5654e4196cbSGregory Neil Shapiro ** >0 on success
5664e4196cbSGregory Neil Shapiro ** 0 on timeout
5674e4196cbSGregory Neil Shapiro ** <0 on error
5684e4196cbSGregory Neil Shapiro */
5694e4196cbSGregory Neil Shapiro
5704e4196cbSGregory Neil Shapiro int
tls_retry(ssl,rfd,wfd,tlsstart,timeout,err,where)5714e4196cbSGregory Neil Shapiro tls_retry(ssl, rfd, wfd, tlsstart, timeout, err, where)
5724e4196cbSGregory Neil Shapiro SSL *ssl;
5734e4196cbSGregory Neil Shapiro int rfd;
5744e4196cbSGregory Neil Shapiro int wfd;
5754e4196cbSGregory Neil Shapiro time_t tlsstart;
5764e4196cbSGregory Neil Shapiro int timeout;
5774e4196cbSGregory Neil Shapiro int err;
5784e4196cbSGregory Neil Shapiro const char *where;
5794e4196cbSGregory Neil Shapiro {
5804e4196cbSGregory Neil Shapiro int ret;
5814e4196cbSGregory Neil Shapiro time_t left;
5824e4196cbSGregory Neil Shapiro time_t now = curtime();
5834e4196cbSGregory Neil Shapiro struct timeval tv;
5844e4196cbSGregory Neil Shapiro
5854e4196cbSGregory Neil Shapiro ret = -1;
5864e4196cbSGregory Neil Shapiro
5874e4196cbSGregory Neil Shapiro /*
5884e4196cbSGregory Neil Shapiro ** For SSL_ERROR_WANT_{READ,WRITE}:
5894e4196cbSGregory Neil Shapiro ** There is not a complete SSL record available yet
5904e4196cbSGregory Neil Shapiro ** or there is only a partial SSL record removed from
5914e4196cbSGregory Neil Shapiro ** the network (socket) buffer into the SSL buffer.
5924e4196cbSGregory Neil Shapiro ** The SSL_connect will only succeed when a full
5934e4196cbSGregory Neil Shapiro ** SSL record is available (assuming a "real" error
5944e4196cbSGregory Neil Shapiro ** doesn't happen). To handle when a "real" error
5954e4196cbSGregory Neil Shapiro ** does happen the select is set for exceptions too.
5964e4196cbSGregory Neil Shapiro ** The connection may be re-negotiated during this time
5974e4196cbSGregory Neil Shapiro ** so both read and write "want errors" need to be handled.
5984e4196cbSGregory Neil Shapiro ** A select() exception loops back so that a proper SSL
5994e4196cbSGregory Neil Shapiro ** error message can be gotten.
6004e4196cbSGregory Neil Shapiro */
6014e4196cbSGregory Neil Shapiro
6024e4196cbSGregory Neil Shapiro left = timeout - (now - tlsstart);
6034e4196cbSGregory Neil Shapiro if (left <= 0)
6044e4196cbSGregory Neil Shapiro return 0; /* timeout */
6054e4196cbSGregory Neil Shapiro tv.tv_sec = left;
6064e4196cbSGregory Neil Shapiro tv.tv_usec = 0;
6074e4196cbSGregory Neil Shapiro
6084e4196cbSGregory Neil Shapiro if (LogLevel > 14)
6094e4196cbSGregory Neil Shapiro {
6104e4196cbSGregory Neil Shapiro sm_syslog(LOG_INFO, NOQID,
6114e4196cbSGregory Neil Shapiro "STARTTLS=%s, info: fds=%d/%d, err=%d",
6124e4196cbSGregory Neil Shapiro where, rfd, wfd, err);
6134e4196cbSGregory Neil Shapiro }
6144e4196cbSGregory Neil Shapiro
615da7d7b9cSGregory Neil Shapiro if ((err == SSL_ERROR_WANT_READ && !SM_FD_OK_SELECT(rfd)) ||
616da7d7b9cSGregory Neil Shapiro (err == SSL_ERROR_WANT_WRITE && !SM_FD_OK_SELECT(wfd)))
6174e4196cbSGregory Neil Shapiro {
6184e4196cbSGregory Neil Shapiro if (LogLevel > 5)
6194e4196cbSGregory Neil Shapiro {
6204e4196cbSGregory Neil Shapiro sm_syslog(LOG_ERR, NOQID,
6214e4196cbSGregory Neil Shapiro "STARTTLS=%s, error: fd %d/%d too large",
6224e4196cbSGregory Neil Shapiro where, rfd, wfd);
6235b0945b5SGregory Neil Shapiro tlslogerr(LOG_WARNING, 8, where);
6244e4196cbSGregory Neil Shapiro }
6254e4196cbSGregory Neil Shapiro errno = EINVAL;
6264e4196cbSGregory Neil Shapiro }
6274e4196cbSGregory Neil Shapiro else if (err == SSL_ERROR_WANT_READ)
6284e4196cbSGregory Neil Shapiro {
6294e4196cbSGregory Neil Shapiro fd_set ssl_maskr, ssl_maskx;
630552d4955SGregory Neil Shapiro int save_errno = errno;
6314e4196cbSGregory Neil Shapiro
6324e4196cbSGregory Neil Shapiro FD_ZERO(&ssl_maskr);
6334e4196cbSGregory Neil Shapiro FD_SET(rfd, &ssl_maskr);
6344e4196cbSGregory Neil Shapiro FD_ZERO(&ssl_maskx);
6354e4196cbSGregory Neil Shapiro FD_SET(rfd, &ssl_maskx);
6364e4196cbSGregory Neil Shapiro do
6374e4196cbSGregory Neil Shapiro {
6384e4196cbSGregory Neil Shapiro ret = select(rfd + 1, &ssl_maskr, NULL, &ssl_maskx,
6394e4196cbSGregory Neil Shapiro &tv);
6404e4196cbSGregory Neil Shapiro } while (ret < 0 && errno == EINTR);
6414e4196cbSGregory Neil Shapiro if (ret < 0 && errno > 0)
6424e4196cbSGregory Neil Shapiro ret = -errno;
643552d4955SGregory Neil Shapiro errno = save_errno;
6444e4196cbSGregory Neil Shapiro }
6454e4196cbSGregory Neil Shapiro else if (err == SSL_ERROR_WANT_WRITE)
6464e4196cbSGregory Neil Shapiro {
6474e4196cbSGregory Neil Shapiro fd_set ssl_maskw, ssl_maskx;
648552d4955SGregory Neil Shapiro int save_errno = errno;
6494e4196cbSGregory Neil Shapiro
6504e4196cbSGregory Neil Shapiro FD_ZERO(&ssl_maskw);
6514e4196cbSGregory Neil Shapiro FD_SET(wfd, &ssl_maskw);
6524e4196cbSGregory Neil Shapiro FD_ZERO(&ssl_maskx);
6534e4196cbSGregory Neil Shapiro FD_SET(rfd, &ssl_maskx);
6544e4196cbSGregory Neil Shapiro do
6554e4196cbSGregory Neil Shapiro {
6564e4196cbSGregory Neil Shapiro ret = select(wfd + 1, NULL, &ssl_maskw, &ssl_maskx,
6574e4196cbSGregory Neil Shapiro &tv);
6584e4196cbSGregory Neil Shapiro } while (ret < 0 && errno == EINTR);
6594e4196cbSGregory Neil Shapiro if (ret < 0 && errno > 0)
6604e4196cbSGregory Neil Shapiro ret = -errno;
661552d4955SGregory Neil Shapiro errno = save_errno;
6624e4196cbSGregory Neil Shapiro }
6634e4196cbSGregory Neil Shapiro return ret;
6644e4196cbSGregory Neil Shapiro }
6654e4196cbSGregory Neil Shapiro
6664e4196cbSGregory Neil Shapiro /* errno to force refill() etc to stop (see IS_IO_ERROR()) */
6674e4196cbSGregory Neil Shapiro # ifdef ETIMEDOUT
6684e4196cbSGregory Neil Shapiro # define SM_ERR_TIMEOUT ETIMEDOUT
6695b0945b5SGregory Neil Shapiro # else
6704e4196cbSGregory Neil Shapiro # define SM_ERR_TIMEOUT EIO
6715b0945b5SGregory Neil Shapiro # endif
6724e4196cbSGregory Neil Shapiro
6734e4196cbSGregory Neil Shapiro /*
674e3793f76SGregory Neil Shapiro ** SET_TLS_RD_TMO -- read secured information for the caller
675e3793f76SGregory Neil Shapiro **
676e3793f76SGregory Neil Shapiro ** Parameters:
677e3793f76SGregory Neil Shapiro ** rd_tmo -- read timeout
678e3793f76SGregory Neil Shapiro **
679*d39bd2c1SGregory Neil Shapiro ** Returns:
680da7d7b9cSGregory Neil Shapiro ** previous read timeout
681e3793f76SGregory Neil Shapiro ** This is a hack: there is no way to pass it in
682e3793f76SGregory Neil Shapiro */
683e3793f76SGregory Neil Shapiro
684e3793f76SGregory Neil Shapiro static int tls_rd_tmo = -1;
685e3793f76SGregory Neil Shapiro
686da7d7b9cSGregory Neil Shapiro int
set_tls_rd_tmo(rd_tmo)687e3793f76SGregory Neil Shapiro set_tls_rd_tmo(rd_tmo)
688e3793f76SGregory Neil Shapiro int rd_tmo;
689e3793f76SGregory Neil Shapiro {
690da7d7b9cSGregory Neil Shapiro int old_rd_tmo;
691da7d7b9cSGregory Neil Shapiro
692da7d7b9cSGregory Neil Shapiro old_rd_tmo = tls_rd_tmo;
693e3793f76SGregory Neil Shapiro tls_rd_tmo = rd_tmo;
694da7d7b9cSGregory Neil Shapiro return old_rd_tmo;
695e3793f76SGregory Neil Shapiro }
696e3793f76SGregory Neil Shapiro
697e3793f76SGregory Neil Shapiro /*
69840266059SGregory Neil Shapiro ** TLS_READ -- read secured information for the caller
69940266059SGregory Neil Shapiro **
70040266059SGregory Neil Shapiro ** Parameters:
70140266059SGregory Neil Shapiro ** fp -- the file pointer
70240266059SGregory Neil Shapiro ** buf -- the location to place the data
70340266059SGregory Neil Shapiro ** size -- the number of bytes to read from connection
70440266059SGregory Neil Shapiro **
705*d39bd2c1SGregory Neil Shapiro ** Returns:
70640266059SGregory Neil Shapiro ** -1 on error
70740266059SGregory Neil Shapiro ** otherwise the number of bytes read
70840266059SGregory Neil Shapiro */
70940266059SGregory Neil Shapiro
71040266059SGregory Neil Shapiro static ssize_t tls_read __P((SM_FILE_T *, char *, size_t));
71140266059SGregory Neil Shapiro
71240266059SGregory Neil Shapiro static ssize_t
tls_read(fp,buf,size)71340266059SGregory Neil Shapiro tls_read(fp, buf, size)
71440266059SGregory Neil Shapiro SM_FILE_T *fp;
71513058a91SGregory Neil Shapiro char *buf;
71640266059SGregory Neil Shapiro size_t size;
71706f25ae9SGregory Neil Shapiro {
7184e4196cbSGregory Neil Shapiro int r, rfd, wfd, try, ssl_err;
71940266059SGregory Neil Shapiro struct tls_obj *so = (struct tls_obj *) fp->f_cookie;
7204e4196cbSGregory Neil Shapiro time_t tlsstart;
72106f25ae9SGregory Neil Shapiro char *err;
72206f25ae9SGregory Neil Shapiro
7234e4196cbSGregory Neil Shapiro try = 99;
7244e4196cbSGregory Neil Shapiro err = NULL;
7254e4196cbSGregory Neil Shapiro tlsstart = curtime();
7264e4196cbSGregory Neil Shapiro
7274e4196cbSGregory Neil Shapiro retry:
72840266059SGregory Neil Shapiro r = SSL_read(so->con, (char *) buf, size);
72940266059SGregory Neil Shapiro
73040266059SGregory Neil Shapiro if (r > 0)
73140266059SGregory Neil Shapiro return r;
73240266059SGregory Neil Shapiro
73306f25ae9SGregory Neil Shapiro err = NULL;
7344e4196cbSGregory Neil Shapiro switch (ssl_err = SSL_get_error(so->con, r))
73506f25ae9SGregory Neil Shapiro {
73606f25ae9SGregory Neil Shapiro case SSL_ERROR_NONE:
73740266059SGregory Neil Shapiro case SSL_ERROR_ZERO_RETURN:
73806f25ae9SGregory Neil Shapiro break;
73906f25ae9SGregory Neil Shapiro case SSL_ERROR_WANT_WRITE:
74040266059SGregory Neil Shapiro err = "read W BLOCK";
7414e4196cbSGregory Neil Shapiro /* FALLTHROUGH */
74206f25ae9SGregory Neil Shapiro case SSL_ERROR_WANT_READ:
7434e4196cbSGregory Neil Shapiro if (err == NULL)
74440266059SGregory Neil Shapiro err = "read R BLOCK";
7454e4196cbSGregory Neil Shapiro rfd = SSL_get_rfd(so->con);
7464e4196cbSGregory Neil Shapiro wfd = SSL_get_wfd(so->con);
7474e4196cbSGregory Neil Shapiro try = tls_retry(so->con, rfd, wfd, tlsstart,
748e3793f76SGregory Neil Shapiro (tls_rd_tmo < 0) ? TimeOuts.to_datablock
749e3793f76SGregory Neil Shapiro : tls_rd_tmo,
750e3793f76SGregory Neil Shapiro ssl_err, "read");
7514e4196cbSGregory Neil Shapiro if (try > 0)
7524e4196cbSGregory Neil Shapiro goto retry;
7534e4196cbSGregory Neil Shapiro errno = SM_ERR_TIMEOUT;
75406f25ae9SGregory Neil Shapiro break;
7554e4196cbSGregory Neil Shapiro
75606f25ae9SGregory Neil Shapiro case SSL_ERROR_WANT_X509_LOOKUP:
75706f25ae9SGregory Neil Shapiro err = "write X BLOCK";
75806f25ae9SGregory Neil Shapiro break;
75906f25ae9SGregory Neil Shapiro case SSL_ERROR_SYSCALL:
76040266059SGregory Neil Shapiro if (r == 0 && errno == 0) /* out of protocol EOF found */
76140266059SGregory Neil Shapiro break;
76206f25ae9SGregory Neil Shapiro err = "syscall error";
76306f25ae9SGregory Neil Shapiro break;
76406f25ae9SGregory Neil Shapiro case SSL_ERROR_SSL:
765b6bacd31SGregory Neil Shapiro # if DEAL_WITH_ERROR_SSL
766959366dcSGregory Neil Shapiro if (r == 0 && errno == 0) /* out of protocol EOF found */
767959366dcSGregory Neil Shapiro break;
7685b0945b5SGregory Neil Shapiro # endif
76906f25ae9SGregory Neil Shapiro err = "generic SSL error";
770552d4955SGregory Neil Shapiro
77140266059SGregory Neil Shapiro if (LogLevel > 9)
772552d4955SGregory Neil Shapiro {
773552d4955SGregory Neil Shapiro int pri;
774552d4955SGregory Neil Shapiro
775552d4955SGregory Neil Shapiro if (errno == EAGAIN && try > 0)
776552d4955SGregory Neil Shapiro pri = LOG_DEBUG;
777552d4955SGregory Neil Shapiro else
778552d4955SGregory Neil Shapiro pri = LOG_WARNING;
7795b0945b5SGregory Neil Shapiro tlslogerr(pri, 9, "read");
780552d4955SGregory Neil Shapiro }
781959366dcSGregory Neil Shapiro
782b6bacd31SGregory Neil Shapiro # if DEAL_WITH_ERROR_SSL
783959366dcSGregory Neil Shapiro /* avoid repeated calls? */
784959366dcSGregory Neil Shapiro if (r == 0)
785959366dcSGregory Neil Shapiro r = -1;
7865b0945b5SGregory Neil Shapiro # endif
78706f25ae9SGregory Neil Shapiro break;
78806f25ae9SGregory Neil Shapiro }
78906f25ae9SGregory Neil Shapiro if (err != NULL)
79040266059SGregory Neil Shapiro {
791605302a5SGregory Neil Shapiro int save_errno;
792605302a5SGregory Neil Shapiro
793605302a5SGregory Neil Shapiro save_errno = (errno == 0) ? EIO : errno;
7944e4196cbSGregory Neil Shapiro if (try == 0 && save_errno == SM_ERR_TIMEOUT)
7954e4196cbSGregory Neil Shapiro {
7964e4196cbSGregory Neil Shapiro if (LogLevel > 7)
797a7ec597cSGregory Neil Shapiro sm_syslog(LOG_WARNING, NOQID,
7984e4196cbSGregory Neil Shapiro "STARTTLS: read error=timeout");
7994e4196cbSGregory Neil Shapiro }
8004e4196cbSGregory Neil Shapiro else if (LogLevel > 8)
801552d4955SGregory Neil Shapiro {
802552d4955SGregory Neil Shapiro int pri;
803552d4955SGregory Neil Shapiro
804552d4955SGregory Neil Shapiro if (save_errno == EAGAIN && try > 0)
805552d4955SGregory Neil Shapiro pri = LOG_DEBUG;
806552d4955SGregory Neil Shapiro else
807552d4955SGregory Neil Shapiro pri = LOG_WARNING;
808552d4955SGregory Neil Shapiro sm_syslog(pri, NOQID,
8094e4196cbSGregory Neil Shapiro "STARTTLS: read error=%s (%d), errno=%d, get_error=%s, retry=%d, ssl_err=%d",
810a7ec597cSGregory Neil Shapiro err, r, errno,
8114e4196cbSGregory Neil Shapiro ERR_error_string(ERR_get_error(), NULL), try,
8124e4196cbSGregory Neil Shapiro ssl_err);
813552d4955SGregory Neil Shapiro }
814a7ec597cSGregory Neil Shapiro else if (LogLevel > 7)
81540266059SGregory Neil Shapiro sm_syslog(LOG_WARNING, NOQID,
816da7d7b9cSGregory Neil Shapiro "STARTTLS: read error=%s (%d), errno=%d, retry=%d, ssl_err=%d",
8174e4196cbSGregory Neil Shapiro err, r, errno, try, ssl_err);
818605302a5SGregory Neil Shapiro errno = save_errno;
81906f25ae9SGregory Neil Shapiro }
82006f25ae9SGregory Neil Shapiro return r;
82106f25ae9SGregory Neil Shapiro }
82206f25ae9SGregory Neil Shapiro
82340266059SGregory Neil Shapiro /*
82440266059SGregory Neil Shapiro ** TLS_WRITE -- write information out through secure connection
82540266059SGregory Neil Shapiro **
82640266059SGregory Neil Shapiro ** Parameters:
82740266059SGregory Neil Shapiro ** fp -- the file pointer
82840266059SGregory Neil Shapiro ** buf -- holds the data to be securely written
82940266059SGregory Neil Shapiro ** size -- the number of bytes to write
83040266059SGregory Neil Shapiro **
83140266059SGregory Neil Shapiro ** Returns:
83240266059SGregory Neil Shapiro ** -1 on error
83340266059SGregory Neil Shapiro ** otherwise number of bytes written
83440266059SGregory Neil Shapiro */
83540266059SGregory Neil Shapiro
83640266059SGregory Neil Shapiro static ssize_t tls_write __P((SM_FILE_T *, const char *, size_t));
83740266059SGregory Neil Shapiro
83813058a91SGregory Neil Shapiro static ssize_t
tls_write(fp,buf,size)83940266059SGregory Neil Shapiro tls_write(fp, buf, size)
84040266059SGregory Neil Shapiro SM_FILE_T *fp;
84113058a91SGregory Neil Shapiro const char *buf;
84240266059SGregory Neil Shapiro size_t size;
84306f25ae9SGregory Neil Shapiro {
8444e4196cbSGregory Neil Shapiro int r, rfd, wfd, try, ssl_err;
84540266059SGregory Neil Shapiro struct tls_obj *so = (struct tls_obj *) fp->f_cookie;
8464e4196cbSGregory Neil Shapiro time_t tlsstart;
84706f25ae9SGregory Neil Shapiro char *err;
84806f25ae9SGregory Neil Shapiro
8494e4196cbSGregory Neil Shapiro try = 99;
8504e4196cbSGregory Neil Shapiro err = NULL;
8514e4196cbSGregory Neil Shapiro tlsstart = curtime();
8524e4196cbSGregory Neil Shapiro
8534e4196cbSGregory Neil Shapiro retry:
85440266059SGregory Neil Shapiro r = SSL_write(so->con, (char *) buf, size);
85540266059SGregory Neil Shapiro
85640266059SGregory Neil Shapiro if (r > 0)
85740266059SGregory Neil Shapiro return r;
85806f25ae9SGregory Neil Shapiro err = NULL;
8594e4196cbSGregory Neil Shapiro switch (ssl_err = SSL_get_error(so->con, r))
86006f25ae9SGregory Neil Shapiro {
86106f25ae9SGregory Neil Shapiro case SSL_ERROR_NONE:
86240266059SGregory Neil Shapiro case SSL_ERROR_ZERO_RETURN:
86306f25ae9SGregory Neil Shapiro break;
86406f25ae9SGregory Neil Shapiro case SSL_ERROR_WANT_WRITE:
8654e4196cbSGregory Neil Shapiro err = "read W BLOCK";
8664e4196cbSGregory Neil Shapiro /* FALLTHROUGH */
86706f25ae9SGregory Neil Shapiro case SSL_ERROR_WANT_READ:
8684e4196cbSGregory Neil Shapiro if (err == NULL)
8694e4196cbSGregory Neil Shapiro err = "read R BLOCK";
8704e4196cbSGregory Neil Shapiro rfd = SSL_get_rfd(so->con);
8714e4196cbSGregory Neil Shapiro wfd = SSL_get_wfd(so->con);
8724e4196cbSGregory Neil Shapiro try = tls_retry(so->con, rfd, wfd, tlsstart,
8734e4196cbSGregory Neil Shapiro DATA_PROGRESS_TIMEOUT, ssl_err, "write");
8744e4196cbSGregory Neil Shapiro if (try > 0)
8754e4196cbSGregory Neil Shapiro goto retry;
8764e4196cbSGregory Neil Shapiro errno = SM_ERR_TIMEOUT;
87706f25ae9SGregory Neil Shapiro break;
87806f25ae9SGregory Neil Shapiro case SSL_ERROR_WANT_X509_LOOKUP:
87906f25ae9SGregory Neil Shapiro err = "write X BLOCK";
88006f25ae9SGregory Neil Shapiro break;
88106f25ae9SGregory Neil Shapiro case SSL_ERROR_SYSCALL:
88240266059SGregory Neil Shapiro if (r == 0 && errno == 0) /* out of protocol EOF found */
88340266059SGregory Neil Shapiro break;
88406f25ae9SGregory Neil Shapiro err = "syscall error";
88506f25ae9SGregory Neil Shapiro break;
88606f25ae9SGregory Neil Shapiro case SSL_ERROR_SSL:
88706f25ae9SGregory Neil Shapiro err = "generic SSL error";
88806f25ae9SGregory Neil Shapiro /*
88906f25ae9SGregory Neil Shapiro ERR_GET_REASON(ERR_peek_error()));
89006f25ae9SGregory Neil Shapiro */
8915b0945b5SGregory Neil Shapiro tlslogerr(LOG_WARNING, 9, "write");
892959366dcSGregory Neil Shapiro
893b6bacd31SGregory Neil Shapiro # if DEAL_WITH_ERROR_SSL
894959366dcSGregory Neil Shapiro /* avoid repeated calls? */
895959366dcSGregory Neil Shapiro if (r == 0)
896959366dcSGregory Neil Shapiro r = -1;
8975b0945b5SGregory Neil Shapiro # endif
89806f25ae9SGregory Neil Shapiro break;
89906f25ae9SGregory Neil Shapiro }
90006f25ae9SGregory Neil Shapiro if (err != NULL)
90140266059SGregory Neil Shapiro {
902605302a5SGregory Neil Shapiro int save_errno;
903605302a5SGregory Neil Shapiro
904605302a5SGregory Neil Shapiro save_errno = (errno == 0) ? EIO : errno;
9054e4196cbSGregory Neil Shapiro if (try == 0 && save_errno == SM_ERR_TIMEOUT)
9064e4196cbSGregory Neil Shapiro {
9074e4196cbSGregory Neil Shapiro if (LogLevel > 7)
908a7ec597cSGregory Neil Shapiro sm_syslog(LOG_WARNING, NOQID,
9094e4196cbSGregory Neil Shapiro "STARTTLS: write error=timeout");
9104e4196cbSGregory Neil Shapiro }
9114e4196cbSGregory Neil Shapiro else if (LogLevel > 8)
9124e4196cbSGregory Neil Shapiro sm_syslog(LOG_WARNING, NOQID,
9134e4196cbSGregory Neil Shapiro "STARTTLS: write error=%s (%d), errno=%d, get_error=%s, retry=%d, ssl_err=%d",
914a7ec597cSGregory Neil Shapiro err, r, errno,
9154e4196cbSGregory Neil Shapiro ERR_error_string(ERR_get_error(), NULL), try,
9164e4196cbSGregory Neil Shapiro ssl_err);
917a7ec597cSGregory Neil Shapiro else if (LogLevel > 7)
91840266059SGregory Neil Shapiro sm_syslog(LOG_WARNING, NOQID,
9194e4196cbSGregory Neil Shapiro "STARTTLS: write error=%s (%d), errno=%d, retry=%d, ssl_err=%d",
9204e4196cbSGregory Neil Shapiro err, r, errno, try, ssl_err);
921605302a5SGregory Neil Shapiro errno = save_errno;
92206f25ae9SGregory Neil Shapiro }
92306f25ae9SGregory Neil Shapiro return r;
92406f25ae9SGregory Neil Shapiro }
92506f25ae9SGregory Neil Shapiro
92640266059SGregory Neil Shapiro /*
92740266059SGregory Neil Shapiro ** SFDCTLS -- create tls file type and open in and out file pointers
92840266059SGregory Neil Shapiro ** for sendmail to read from and write to.
92940266059SGregory Neil Shapiro **
93040266059SGregory Neil Shapiro ** Parameters:
93140266059SGregory Neil Shapiro ** fin -- data input source being replaced
93240266059SGregory Neil Shapiro ** fout -- data output source being replaced
933a7ec597cSGregory Neil Shapiro ** con -- the tls connection pointer
93440266059SGregory Neil Shapiro **
93540266059SGregory Neil Shapiro ** Returns:
93640266059SGregory Neil Shapiro ** -1 on error
93740266059SGregory Neil Shapiro ** 0 on success
93840266059SGregory Neil Shapiro **
93940266059SGregory Neil Shapiro ** Side effects:
94040266059SGregory Neil Shapiro ** The arguments "fin" and "fout" are replaced with the new
94140266059SGregory Neil Shapiro ** SM_FILE_T pointers.
94240266059SGregory Neil Shapiro ** The original "fin" and "fout" are preserved in the tls file
94340266059SGregory Neil Shapiro ** type but are not actually used because of the design of TLS.
94440266059SGregory Neil Shapiro */
94506f25ae9SGregory Neil Shapiro
94606f25ae9SGregory Neil Shapiro int
sfdctls(fin,fout,con)94706f25ae9SGregory Neil Shapiro sfdctls(fin, fout, con)
94840266059SGregory Neil Shapiro SM_FILE_T **fin;
94940266059SGregory Neil Shapiro SM_FILE_T **fout;
95006f25ae9SGregory Neil Shapiro SSL *con;
95106f25ae9SGregory Neil Shapiro {
95240266059SGregory Neil Shapiro SM_FILE_T *tlsin, *tlsout;
95340266059SGregory Neil Shapiro SM_FILE_T SM_IO_SET_TYPE(tls_vector, "tls", tls_open, tls_close,
95440266059SGregory Neil Shapiro tls_read, tls_write, NULL, tls_getinfo, NULL,
95540266059SGregory Neil Shapiro SM_TIME_FOREVER);
95640266059SGregory Neil Shapiro struct tls_info info;
95706f25ae9SGregory Neil Shapiro
95840266059SGregory Neil Shapiro SM_ASSERT(con != NULL);
95906f25ae9SGregory Neil Shapiro
96040266059SGregory Neil Shapiro SM_IO_INIT_TYPE(tls_vector, "tls", tls_open, tls_close,
96140266059SGregory Neil Shapiro tls_read, tls_write, NULL, tls_getinfo, NULL,
96240266059SGregory Neil Shapiro SM_TIME_FOREVER);
96340266059SGregory Neil Shapiro info.fp = *fin;
96440266059SGregory Neil Shapiro info.con = con;
965e92d3f3fSGregory Neil Shapiro tlsin = sm_io_open(&tls_vector, SM_TIME_DEFAULT, &info, SM_IO_RDONLY_B,
96640266059SGregory Neil Shapiro NULL);
96740266059SGregory Neil Shapiro if (tlsin == NULL)
96840266059SGregory Neil Shapiro return -1;
96906f25ae9SGregory Neil Shapiro
97040266059SGregory Neil Shapiro info.fp = *fout;
971e92d3f3fSGregory Neil Shapiro tlsout = sm_io_open(&tls_vector, SM_TIME_DEFAULT, &info, SM_IO_WRONLY_B,
97240266059SGregory Neil Shapiro NULL);
97340266059SGregory Neil Shapiro if (tlsout == NULL)
97442e5d165SGregory Neil Shapiro {
97540266059SGregory Neil Shapiro (void) sm_io_close(tlsin, SM_TIME_DEFAULT);
97642e5d165SGregory Neil Shapiro return -1;
97742e5d165SGregory Neil Shapiro }
97840266059SGregory Neil Shapiro sm_io_automode(tlsin, tlsout);
97906f25ae9SGregory Neil Shapiro
98040266059SGregory Neil Shapiro *fin = tlsin;
98140266059SGregory Neil Shapiro *fout = tlsout;
98206f25ae9SGregory Neil Shapiro return 0;
98306f25ae9SGregory Neil Shapiro }
98440266059SGregory Neil Shapiro #endif /* STARTTLS */
985