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