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