sasl.c revision 182352
1/*
2 * Copyright (c) 2001-2002 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#include <sm/gen.h>
12SM_RCSID("@(#)$Id: sasl.c,v 8.22 2006/08/15 23:24:57 ca Exp $")
13
14#if SASL
15# include <stdlib.h>
16# include <sendmail.h>
17# include <errno.h>
18
19/*
20**  In order to ensure that storage leaks are tracked, and to prevent
21**  conflicts between the sm_heap package and sasl, we tell sasl to
22**  use the following heap allocation functions.  Unfortunately,
23**  the sasl package incorrectly specifies the size of a block
24**  using unsigned long: for portability, it should be size_t.
25*/
26
27void *sm_sasl_malloc __P((unsigned long));
28static void *sm_sasl_calloc __P((unsigned long, unsigned long));
29static void *sm_sasl_realloc __P((void *, unsigned long));
30void sm_sasl_free __P((void *));
31
32/*
33**  SASLv1:
34**  We can't use an rpool for Cyrus-SASL memory management routines,
35**	since the encryption/decryption routines in Cyrus-SASL
36**	allocate/deallocate a buffer each time. Since rpool
37**	don't release memory until the very end, memory consumption is
38**	proportional to the size of an e-mail, which is unacceptable.
39*/
40
41/*
42**  SM_SASL_MALLOC -- malloc() for SASL
43**
44**	Parameters:
45**		size -- size of requested memory.
46**
47**	Returns:
48**		pointer to memory.
49*/
50
51void *
52sm_sasl_malloc(size)
53	unsigned long size;
54{
55	return sm_malloc((size_t) size);
56}
57
58/*
59**  SM_SASL_CALLOC -- calloc() for SASL
60**
61**	Parameters:
62**		nelem -- number of elements.
63**		elemsize -- size of each element.
64**
65**	Returns:
66**		pointer to memory.
67**
68**	Notice:
69**		this isn't currently used by SASL.
70*/
71
72static void *
73sm_sasl_calloc(nelem, elemsize)
74	unsigned long nelem;
75	unsigned long elemsize;
76{
77	size_t size;
78	void *p;
79
80	size = (size_t) nelem * (size_t) elemsize;
81	p = sm_malloc(size);
82	if (p == NULL)
83		return NULL;
84	memset(p, '\0', size);
85	return p;
86}
87
88/*
89**  SM_SASL_REALLOC -- realloc() for SASL
90**
91**	Parameters:
92**		p -- pointer to old memory.
93**		size -- size of requested memory.
94**
95**	Returns:
96**		pointer to new memory.
97*/
98
99static void *
100sm_sasl_realloc(o, size)
101	void *o;
102	unsigned long size;
103{
104	return sm_realloc(o, (size_t) size);
105}
106
107/*
108**  SM_SASL_FREE -- free() for SASL
109**
110**	Parameters:
111**		p -- pointer to free.
112**
113**	Returns:
114**		none
115*/
116
117void
118sm_sasl_free(p)
119	void *p;
120{
121	sm_free(p);
122}
123
124/*
125**  SM_SASL_INIT -- sendmail specific SASL initialization
126**
127**	Parameters:
128**		none.
129**
130**	Returns:
131**		none
132**
133**	Side Effects:
134**		installs memory management routines for SASL.
135*/
136
137void
138sm_sasl_init()
139{
140	sasl_set_alloc(sm_sasl_malloc, sm_sasl_calloc,
141		       sm_sasl_realloc, sm_sasl_free);
142}
143/*
144**  INTERSECT -- create the intersection between two lists
145**
146**	Parameters:
147**		s1, s2 -- lists of items (separated by single blanks).
148**		rpool -- resource pool from which result is allocated.
149**
150**	Returns:
151**		the intersection of both lists.
152*/
153
154char *
155intersect(s1, s2, rpool)
156	char *s1, *s2;
157	SM_RPOOL_T *rpool;
158{
159	char *hr, *h1, *h, *res;
160	int l1, l2, rl;
161
162	if (s1 == NULL || s2 == NULL)	/* NULL string(s) -> NULL result */
163		return NULL;
164	l1 = strlen(s1);
165	l2 = strlen(s2);
166	rl = SM_MIN(l1, l2);
167	res = (char *) sm_rpool_malloc(rpool, rl + 1);
168	if (res == NULL)
169		return NULL;
170	*res = '\0';
171	if (rl == 0)	/* at least one string empty? */
172		return res;
173	hr = res;
174	h1 = s1;
175	h = s1;
176
177	/* walk through s1 */
178	while (h != NULL && *h1 != '\0')
179	{
180		/* is there something after the current word? */
181		if ((h = strchr(h1, ' ')) != NULL)
182			*h = '\0';
183		l1 = strlen(h1);
184
185		/* does the current word appear in s2 ? */
186		if (iteminlist(h1, s2, " ") != NULL)
187		{
188			/* add a blank if not first item */
189			if (hr != res)
190				*hr++ = ' ';
191
192			/* copy the item */
193			memcpy(hr, h1, l1);
194
195			/* advance pointer in result list */
196			hr += l1;
197			*hr = '\0';
198		}
199		if (h != NULL)
200		{
201			/* there are more items */
202			*h = ' ';
203			h1 = h + 1;
204		}
205	}
206	return res;
207}
208# if SASL >= 20000
209/*
210**  IPTOSTRING -- create string for SASL_IP*PORT property
211**		(borrowed from lib/iptostring.c in Cyrus-IMAP)
212**
213**	Parameters:
214**		addr -- (pointer to) socket address
215**		addrlen -- length of socket address
216**		out -- output string (result)
217**		outlen -- maximum length of output string
218**
219**	Returns:
220**		true iff successful.
221**
222**	Side Effects:
223**		creates output string if successful.
224**		sets errno if unsuccessful.
225*/
226
227#  include <arpa/inet.h>
228
229#  ifndef NI_MAXHOST
230#   define NI_MAXHOST	1025
231#  endif
232#  ifndef NI_MAXSERV
233#   define NI_MAXSERV	32
234#  endif
235
236bool
237iptostring(addr, addrlen, out, outlen)
238	SOCKADDR *addr;
239	SOCKADDR_LEN_T addrlen;
240	char *out;
241	unsigned outlen;
242{
243	char hbuf[NI_MAXHOST], pbuf[NI_MAXSERV];
244#  if NETINET6
245	int niflags;
246#  endif /* NETINET6 */
247
248	if (addr == NULL || out == NULL)
249	{
250		errno = EINVAL;
251		return false;
252	}
253
254#  if NETINET6
255	niflags = (NI_NUMERICHOST | NI_NUMERICSERV);
256#   ifdef NI_WITHSCOPEID
257	if (addr->sa.sa_family == AF_INET6)
258		niflags |= NI_WITHSCOPEID;
259#   endif /* NI_WITHSCOPEID */
260	if (getnameinfo((struct sockaddr *) addr, addrlen,
261			hbuf, sizeof(hbuf), pbuf, sizeof(pbuf), niflags) != 0)
262		return false;
263#  else /* NETINET6 */
264	if (addr->sa.sa_family != AF_INET)
265	{
266		errno = EINVAL;
267		return false;
268	}
269	if (sm_strlcpy(hbuf, inet_ntoa(addr->sin.sin_addr), sizeof(hbuf))
270	    >= sizeof(hbuf))
271	{
272		errno = ENOMEM;
273		return false;
274	}
275	sm_snprintf(pbuf, sizeof(pbuf), "%d", ntohs(addr->sin.sin_port));
276#  endif /* NETINET6 */
277
278	if (outlen < strlen(hbuf) + strlen(pbuf) + 2)
279	{
280		errno = ENOMEM;
281		return false;
282	}
283	sm_snprintf(out, outlen, "%s;%s", hbuf, pbuf);
284	return true;
285}
286# endif /* SASL >= 20000 */
287#endif /* SASL */
288