xref: /freebsd/contrib/sendmail/src/sfsasl.c (revision 77a0943ded95b9e6438f7db70c4a28e4d93946d4)
1 /*
2  * Copyright (c) 1999-2000 Sendmail, Inc. and its suppliers.
3  *	All rights reserved.
4  *
5  * By using this file, you agree to the terms and conditions set
6  * forth in the LICENSE file which can be found at the top level of
7  * the sendmail distribution.
8  *
9  */
10 
11 #ifndef lint
12 static char id[] = "@(#)$Id: sfsasl.c,v 8.17.4.8 2000/09/14 00:14:13 ca Exp $";
13 #endif /* ! lint */
14 
15 #if SFIO
16 # include <sfio/stdio.h>
17 #endif /* SFIO */
18 
19 #include <stdlib.h>
20 #include <sendmail.h>
21 
22 #if SASL && SFIO
23 /*
24 **  SASL
25 */
26 
27 # include <sasl.h>
28 # include "sfsasl.h"
29 
30 static ssize_t
31 sasl_read(f, buf, size, disc)
32 	Sfio_t *f;
33 	Void_t *buf;
34 	size_t size;
35 	Sfdisc_t *disc;
36 {
37 	int len, result;
38 	char *outbuf;
39 	unsigned int outlen;
40 	Sasldisc_t *sd = (Sasldisc_t *) disc;
41 
42 	len = sfrd(f, buf, size, disc);
43 
44 	if (len <= 0)
45 		return len;
46 
47 	result = sasl_decode(sd->conn, buf, len, &outbuf, &outlen);
48 
49 	if (result != SASL_OK)
50 	{
51 		/* eventually, we'll want an exception here */
52 		return -1;
53 	}
54 
55 	if (outbuf != NULL)
56 	{
57 		(void)memcpy(buf, outbuf, outlen);
58 		free(outbuf);
59 	}
60 	return outlen;
61 }
62 
63 static ssize_t
64 sasl_write(f, buf, size, disc)
65 	Sfio_t *f;
66 	const Void_t *buf;
67 	size_t size;
68 	Sfdisc_t *disc;
69 {
70 	int result;
71 	char *outbuf;
72 	unsigned int outlen;
73 	Sasldisc_t *sd = (Sasldisc_t *) disc;
74 
75 	result = sasl_encode(sd->conn, buf, size, &outbuf, &outlen);
76 
77 	if (result != SASL_OK)
78 	{
79 		/* eventually, we'll want an exception here */
80 		return -1;
81 	}
82 
83 	if (outbuf != NULL)
84 	{
85 		sfwr(f, outbuf, outlen, disc);
86 		free(outbuf);
87 	}
88 	return size;
89 }
90 
91 int
92 sfdcsasl(fin, fout, conn)
93 	Sfio_t *fin;
94 	Sfio_t *fout;
95 	sasl_conn_t *conn;
96 {
97 	Sasldisc_t *saslin, *saslout;
98 
99 	if (conn == NULL)
100 	{
101 		/* no need to do anything */
102 		return 0;
103 	}
104 
105 	if ((saslin = (Sasldisc_t *) malloc(sizeof(Sasldisc_t))) == NULL)
106 		return -1;
107 	if ((saslout = (Sasldisc_t *) malloc(sizeof(Sasldisc_t))) == NULL)
108 	{
109 		free(saslin);
110 		return -1;
111 	}
112 
113 	saslin->disc.readf = sasl_read;
114 	saslin->disc.writef = sasl_write;
115 	saslin->disc.seekf = NULL;
116 	saslin->disc.exceptf = NULL;
117 
118 	saslout->disc.readf = sasl_read;
119 	saslout->disc.writef = sasl_write;
120 	saslout->disc.seekf = NULL;
121 	saslout->disc.exceptf = NULL;
122 
123 	saslin->conn = conn;
124 	saslout->conn = conn;
125 
126 	if (sfdisc(fin, (Sfdisc_t *) saslin) != (Sfdisc_t *) saslin ||
127 	    sfdisc(fout, (Sfdisc_t *) saslout) != (Sfdisc_t *) saslout)
128 	{
129 		free(saslin);
130 		free(saslout);
131 		return -1;
132 	}
133 	return 0;
134 }
135 #endif /* SASL && SFIO */
136 
137 #if STARTTLS && (SFIO || _FFR_TLS_TOREK)
138 /*
139 **  STARTTLS
140 */
141 
142 # include "sfsasl.h"
143 #  include <openssl/err.h>
144 
145 static ssize_t
146 # if SFIO
147 tls_read(f, buf, size, disc)
148 	Sfio_t *f;
149 	Void_t *buf;
150 	size_t size;
151 	Sfdisc_t *disc;
152 # else /* SFIO */
153 tls_read(disc, buf, size)
154 	void *disc;
155 	void *buf;
156 	size_t size;
157 # endif /* SFIO */
158 {
159 	int r;
160 	Tlsdisc_t *sd;
161 
162 	/* Cast back to correct type */
163 	sd = (Tlsdisc_t *) disc;
164 
165 	r = SSL_read(sd->con, (char *) buf, size);
166 	if (r < 0 && LogLevel > 7)
167 	{
168 		char *err;
169 
170 		err = NULL;
171 		switch (SSL_get_error(sd->con, r))
172 		{
173 			case SSL_ERROR_NONE:
174 				break;
175 			case SSL_ERROR_WANT_WRITE:
176 				err = "write W BLOCK";
177 				break;
178 			case SSL_ERROR_WANT_READ:
179 				err = "write R BLOCK";
180 				break;
181 			case SSL_ERROR_WANT_X509_LOOKUP:
182 				err = "write X BLOCK";
183 				break;
184 			case SSL_ERROR_ZERO_RETURN:
185 				break;
186 			case SSL_ERROR_SYSCALL:
187 				err = "syscall error";
188 /*
189 				get_last_socket_error());
190 */
191 				break;
192 			case SSL_ERROR_SSL:
193 				err = "generic SSL error";
194 				break;
195 		}
196 		if (err != NULL)
197 			sm_syslog(LOG_WARNING, NOQID, "TLS: read error:  %s",
198 				  err);
199 	}
200 	return r;
201 }
202 
203 static ssize_t
204 # if SFIO
205 tls_write(f, buf, size, disc)
206 	Sfio_t *f;
207 	const Void_t *buf;
208 	size_t size;
209 	Sfdisc_t *disc;
210 # else /* SFIO */
211 tls_write(disc, buf, size)
212 	void *disc;
213 	const void *buf;
214 	size_t size;
215 # endif /* SFIO */
216 {
217 	int r;
218 	Tlsdisc_t *sd;
219 
220 	/* Cast back to correct type */
221 	sd = (Tlsdisc_t *) disc;
222 
223 	r = SSL_write(sd->con, (char *)buf, size);
224 	if (r < 0 && LogLevel > 7)
225 	{
226 		char *err;
227 
228 		err = NULL;
229 		switch (SSL_get_error(sd->con, r))
230 		{
231 			case SSL_ERROR_NONE:
232 				break;
233 			case SSL_ERROR_WANT_WRITE:
234 				err = "write W BLOCK";
235 				break;
236 			case SSL_ERROR_WANT_READ:
237 				err = "write R BLOCK";
238 				break;
239 			case SSL_ERROR_WANT_X509_LOOKUP:
240 				err = "write X BLOCK";
241 				break;
242 			case SSL_ERROR_ZERO_RETURN:
243 				break;
244 			case SSL_ERROR_SYSCALL:
245 				err = "syscall error";
246 /*
247 				get_last_socket_error());
248 */
249 				break;
250 			case SSL_ERROR_SSL:
251 				err = "generic SSL error";
252 /*
253 				ERR_GET_REASON(ERR_peek_error()));
254 */
255 				break;
256 		}
257 		if (err != NULL)
258 			sm_syslog(LOG_WARNING, NOQID, "TLS: write error:  %s",
259 				  err);
260 	}
261 	return r;
262 }
263 
264 # if !SFIO
265 static int
266 tls_close(cookie)
267 	void *cookie;
268 {
269 	int retval = 0;
270 	Tlsdisc_t *tc;
271 
272 	/* Cast back to correct type */
273 	tc = (Tlsdisc_t *)cookie;
274 
275 	if (tc->fp != NULL)
276 	{
277 		retval = fclose(tc->fp);
278 		tc->fp = NULL;
279 	}
280 
281 	free(tc);
282 	return retval;
283 }
284 # endif /* !SFIO */
285 
286 int
287 sfdctls(fin, fout, con)
288 # if SFIO
289 	Sfio_t *fin;
290 	Sfio_t *fout;
291 # else /* SFIO */
292 	FILE **fin;
293 	FILE **fout;
294 # endif /* SFIO */
295 	SSL *con;
296 {
297 	Tlsdisc_t *tlsin, *tlsout;
298 # if !SFIO
299 	FILE *fp;
300 # else /* !SFIO */
301 	int rfd, wfd;
302 # endif /* !SFIO */
303 
304 	if (con == NULL)
305 		return 0;
306 
307 	if ((tlsin = (Tlsdisc_t *) malloc(sizeof(Tlsdisc_t))) == NULL)
308 		return -1;
309 	if ((tlsout = (Tlsdisc_t *) malloc(sizeof(Tlsdisc_t))) == NULL)
310 	{
311 		free(tlsin);
312 		return -1;
313 	}
314 
315 # if SFIO
316 	tlsin->disc.readf = tls_read;
317 	tlsin->disc.writef = tls_write;
318 	tlsin->disc.seekf = NULL;
319 	tlsin->disc.exceptf = NULL;
320 	tlsin->con = con;
321 
322 	tlsout->disc.readf = tls_read;
323 	tlsout->disc.writef = tls_write;
324 	tlsout->disc.seekf = NULL;
325 	tlsout->disc.exceptf = NULL;
326 	tlsout->con = con;
327 
328 	rfd = fileno(fin);
329 	wfd = fileno(fout);
330 	if (rfd < 0 || wfd < 0 ||
331 	    SSL_set_rfd(con, rfd) <= 0 || SSL_set_wfd(con, wfd) <= 0)
332 	{
333 		free(tlsin);
334 		free(tlsout);
335 		return -1;
336 	}
337 	if (sfdisc(fin, (Sfdisc_t *) tlsin) != (Sfdisc_t *) tlsin ||
338 	    sfdisc(fout, (Sfdisc_t *) tlsout) != (Sfdisc_t *) tlsout)
339 	{
340 		free(tlsin);
341 		free(tlsout);
342 		return -1;
343 	}
344 # else /* SFIO */
345 	tlsin->fp = *fin;
346 	tlsin->con = con;
347 	fp = funopen(tlsin, tls_read, tls_write, NULL, tls_close);
348 	if (fp == NULL)
349 	{
350 		free(tlsin);
351 		return -1;
352 	}
353 	*fin = fp;
354 
355 	tlsout->fp = *fout;
356 	tlsout->con = con;
357 	fp = funopen(tlsout, tls_read, tls_write, NULL, tls_close);
358 	if (fp == NULL)
359 	{
360 		FILE *save;
361 
362 		/* Hack: Don't close underlying fp */
363 		save = tlsin->fp;
364 		tlsin->fp = NULL;
365 		fclose(*fin);
366 		*fin = save;
367 		free(tlsout);
368 		return -1;
369 	}
370 	*fout = fp;
371 	SSL_set_rfd(con, fileno(tlsin->fp));
372 	SSL_set_wfd(con, fileno(tlsout->fp));
373 # endif /* SFIO */
374 	return 0;
375 }
376 #endif /* STARTTLS && (SFIO || _FFR_TLS_TOREK) */
377