sfsasl.c revision 64562
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
12static char id[] = "@(#)$Id: sfsasl.c,v 8.17.4.7 2000/07/18 18:44:51 gshapiro 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
30static ssize_t
31sasl_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
63static ssize_t
64sasl_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
91int
92sfdcsasl(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
145static ssize_t
146# if SFIO
147tls_read(f, buf, size, disc)
148	Sfio_t *f;
149	Void_t *buf;
150	size_t size;
151	Sfdisc_t *disc;
152# else /* SFIO */
153tls_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
203static ssize_t
204# if SFIO
205tls_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 */
211tls_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
265static int
266tls_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
286int
287sfdctls(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# endif /* !SFIO */
301
302	if (con == NULL)
303		return 0;
304
305	if ((tlsin = (Tlsdisc_t *) malloc(sizeof(Tlsdisc_t))) == NULL)
306		return -1;
307	if ((tlsout = (Tlsdisc_t *) malloc(sizeof(Tlsdisc_t))) == NULL)
308	{
309		free(tlsin);
310		return -1;
311	}
312
313# if SFIO
314	tlsin->disc.readf = tls_read;
315	tlsin->disc.writef = tls_write;
316	tlsin->disc.seekf = NULL;
317	tlsin->disc.exceptf = NULL;
318	tlsin->con = con;
319
320	tlsout->disc.readf = tls_read;
321	tlsout->disc.writef = tls_write;
322	tlsout->disc.seekf = NULL;
323	tlsout->disc.exceptf = NULL;
324	tlsout->con = con;
325
326	SSL_set_rfd(con, fileno(fin));	/* fileno or sffileno? XXX */
327	SSL_set_wfd(con, fileno(fout));
328	if (sfdisc(fin, (Sfdisc_t *) tlsin) != (Sfdisc_t *) tlsin ||
329	    sfdisc(fout, (Sfdisc_t *) tlsout) != (Sfdisc_t *) tlsout)
330	{
331		free(tlsin);
332		free(tlsout);
333		return -1;
334	}
335# else /* SFIO */
336	tlsin->fp = *fin;
337	tlsin->con = con;
338	fp = funopen(tlsin, tls_read, tls_write, NULL, tls_close);
339	if (fp == NULL)
340	{
341		free(tlsin);
342		return -1;
343	}
344	*fin = fp;
345
346	tlsout->fp = *fout;
347	tlsout->con = con;
348	fp = funopen(tlsout, tls_read, tls_write, NULL, tls_close);
349	if (fp == NULL)
350	{
351		FILE *save;
352
353		/* Hack: Don't close underlying fp */
354		save = tlsin->fp;
355		tlsin->fp = NULL;
356		fclose(*fin);
357		*fin = save;
358		free(tlsout);
359		return -1;
360	}
361	*fout = fp;
362	SSL_set_rfd(con, fileno(tlsin->fp));
363	SSL_set_wfd(con, fileno(tlsout->fp));
364# endif /* SFIO */
365	return 0;
366}
367#endif /* STARTTLS && (SFIO || _FFR_TLS_TOREK) */
368