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 *
sm_sasl_malloc(size)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 *
sm_sasl_calloc(nelem,elemsize)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 *
sm_sasl_realloc(o,size)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
sm_sasl_free(p)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
sm_sasl_init()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 *
intersect(s1,s2,rpool)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
iptostring(addr,addrlen,out,outlen)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