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.21 2004/11/22 23:09:00 gshapiro 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