xref: /illumos-gate/usr/src/cmd/sendmail/src/sasl.c (revision d583b39bfb4e2571d3e41097c5c357ffe353ad45)
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>
12 SM_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 
27 void *sm_sasl_malloc __P((unsigned long));
28 static void *sm_sasl_calloc __P((unsigned long, unsigned long));
29 static void *sm_sasl_realloc __P((void *, unsigned long));
30 void 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 
51 void *
52 sm_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 
72 static void *
73 sm_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 
99 static void *
100 sm_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 
117 void
118 sm_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 
137 void
138 sm_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 
154 char *
155 intersect(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 
236 bool
237 iptostring(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