summaryrefslogtreecommitdiffstats
path: root/src/tls/tls_stream.c
blob: 4cc53a71b9fa5474f78bf4db7ae753cdd3a40989 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
/*++
/* NAME
/*	tls_stream
/* SUMMARY
/*	VSTREAM over TLS
/* SYNOPSIS
/*	#define TLS_INTERNAL
/*	#include <tls.h>
/*
/*	void	tls_stream_start(stream, context)
/*	VSTREAM	*stream;
/*	TLS_SESS_STATE *context;
/*
/*	void	tls_stream_stop(stream)
/*	VSTREAM	*stream;
/* DESCRIPTION
/*	This module implements the VSTREAM over TLS support user interface.
/*	The hard work is done elsewhere.
/*
/*	tls_stream_start() enables TLS on the named stream. All read
/*	and write operations are directed through the TLS library,
/*	using the state information specified with the context argument.
/*
/*	tls_stream_stop() replaces the VSTREAM read/write routines
/*	by dummies that have no side effects, and deletes the
/*	VSTREAM's reference to the TLS context.
/* DIAGNOSTICS
/*	The tls_stream(3) read/write routines return the non-zero
/*	number of plaintext bytes read/written if successful; -1
/*	after TLS protocol failure, system-call failure, or for any
/*	reason described under "in addition" below; and zero when
/*	the remote party closed the connection or sent a TLS shutdown
/*	request.
/*
/*	Upon return from the tls_stream(3) read/write routines the
/*	global errno value is non-zero when the requested operation
/*	did not complete due to system call failure.
/*
/*	In addition, the result value is set to -1, and the global
/*	errno value is set to ETIMEDOUT, when a network read/write
/*	request did not complete within the time limit.
/* SEE ALSO
/*	dummy_read(3), placebo read routine
/*	dummy_write(3), placebo write routine
/* LICENSE
/* .ad
/* .fi
/*	This software is free. You can do with it whatever you want.
/*	The original author kindly requests that you acknowledge
/*	the use of his software.
/* AUTHOR(S)
/*	Based on code that was originally written by:
/*	Lutz Jaenicke
/*	BTU Cottbus
/*	Allgemeine Elektrotechnik
/*	Universitaetsplatz 3-4
/*	D-03044 Cottbus, Germany
/*
/*	Updated by:
/*	Wietse Venema
/*	IBM T.J. Watson Research
/*	P.O. Box 704
/*	Yorktown Heights, NY 10598, USA
/*--*/

/* System library. */

#include <sys_defs.h>

#ifdef USE_TLS

/* Utility library. */

#include <iostuff.h>
#include <vstream.h>
#include <msg.h>

/* TLS library. */

#define TLS_INTERNAL
#include <tls.h>

 /*
  * Interface mis-match compensation. The OpenSSL read/write routines return
  * unspecified negative values when an operation fails, while the vstream(3)
  * plaintext timed_read/write() functions follow the convention of UNIX
  * system calls, and return -1 upon error. The macro below makes OpenSSL
  * read/write results consistent with the UNIX system-call convention.
  */
#define NORMALIZED_VSTREAM_RETURN(retval) ((retval) < 0 ? -1 : (retval))

/* tls_timed_read - read content from stream, then TLS decapsulate */

static ssize_t tls_timed_read(int fd, void *buf, size_t len, int timeout,
			              void *context)
{
    const char *myname = "tls_timed_read";
    ssize_t ret;
    TLS_SESS_STATE *TLScontext;

    TLScontext = (TLS_SESS_STATE *) context;
    if (!TLScontext)
	msg_panic("%s: no context", myname);

    ret = tls_bio_read(fd, buf, len, timeout, TLScontext);
    if (ret > 0 && (TLScontext->log_mask & TLS_LOG_ALLPKTS))
	msg_info("Read %ld chars: %.*s",
		 (long) ret, (int) (ret > 40 ? 40 : ret), (char *) buf);
    return (NORMALIZED_VSTREAM_RETURN(ret));
}

/* tls_timed_write - TLS encapsulate content, then write to stream */

static ssize_t tls_timed_write(int fd, void *buf, size_t len, int timeout,
			               void *context)
{
    const char *myname = "tls_timed_write";
    ssize_t ret;
    TLS_SESS_STATE *TLScontext;

    TLScontext = (TLS_SESS_STATE *) context;
    if (!TLScontext)
	msg_panic("%s: no context", myname);

    if (TLScontext->log_mask & TLS_LOG_ALLPKTS)
	msg_info("Write %ld chars: %.*s",
		 (long) len, (int) (len > 40 ? 40 : len), (char *) buf);
    ret = tls_bio_write(fd, buf, len, timeout, TLScontext);
    return (NORMALIZED_VSTREAM_RETURN(ret));
}

/* tls_stream_start - start VSTREAM over TLS */

void    tls_stream_start(VSTREAM *stream, TLS_SESS_STATE *context)
{
    vstream_control(stream,
		    CA_VSTREAM_CTL_READ_FN(tls_timed_read),
		    CA_VSTREAM_CTL_WRITE_FN(tls_timed_write),
		    CA_VSTREAM_CTL_CONTEXT(context),
		    CA_VSTREAM_CTL_END);
}

/* tls_stream_stop - stop VSTREAM over TLS */

void    tls_stream_stop(VSTREAM *stream)
{

    /*
     * Prevent data leakage after TLS is turned off. The Postfix/TLS patch
     * provided null function pointers; we use dummy routines that make less
     * noise when used.
     */
    vstream_control(stream,
		    CA_VSTREAM_CTL_READ_FN(dummy_read),
		    CA_VSTREAM_CTL_WRITE_FN(dummy_write),
		    CA_VSTREAM_CTL_CONTEXT((void *) 0),
		    CA_VSTREAM_CTL_END);
}

#endif