1 /* 2 * Copyright (c) 1999-2000 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 #ifndef lint 12 static char id[] = "@(#)$Id: sfsasl.c,v 8.17.4.8 2000/09/14 00:14:13 ca Exp $"; 13 #endif /* ! lint */ 14 15 #if SFIO 16 # include <sfio/stdio.h> 17 #endif /* SFIO */ 18 19 #include <stdlib.h> 20 #include <sendmail.h> 21 22 #if SASL && SFIO 23 /* 24 ** SASL 25 */ 26 27 # include <sasl.h> 28 # include "sfsasl.h" 29 30 static ssize_t 31 sasl_read(f, buf, size, disc) 32 Sfio_t *f; 33 Void_t *buf; 34 size_t size; 35 Sfdisc_t *disc; 36 { 37 int len, result; 38 char *outbuf; 39 unsigned int outlen; 40 Sasldisc_t *sd = (Sasldisc_t *) disc; 41 42 len = sfrd(f, buf, size, disc); 43 44 if (len <= 0) 45 return len; 46 47 result = sasl_decode(sd->conn, buf, len, &outbuf, &outlen); 48 49 if (result != SASL_OK) 50 { 51 /* eventually, we'll want an exception here */ 52 return -1; 53 } 54 55 if (outbuf != NULL) 56 { 57 (void)memcpy(buf, outbuf, outlen); 58 free(outbuf); 59 } 60 return outlen; 61 } 62 63 static ssize_t 64 sasl_write(f, buf, size, disc) 65 Sfio_t *f; 66 const Void_t *buf; 67 size_t size; 68 Sfdisc_t *disc; 69 { 70 int result; 71 char *outbuf; 72 unsigned int outlen; 73 Sasldisc_t *sd = (Sasldisc_t *) disc; 74 75 result = sasl_encode(sd->conn, buf, size, &outbuf, &outlen); 76 77 if (result != SASL_OK) 78 { 79 /* eventually, we'll want an exception here */ 80 return -1; 81 } 82 83 if (outbuf != NULL) 84 { 85 sfwr(f, outbuf, outlen, disc); 86 free(outbuf); 87 } 88 return size; 89 } 90 91 int 92 sfdcsasl(fin, fout, conn) 93 Sfio_t *fin; 94 Sfio_t *fout; 95 sasl_conn_t *conn; 96 { 97 Sasldisc_t *saslin, *saslout; 98 99 if (conn == NULL) 100 { 101 /* no need to do anything */ 102 return 0; 103 } 104 105 if ((saslin = (Sasldisc_t *) malloc(sizeof(Sasldisc_t))) == NULL) 106 return -1; 107 if ((saslout = (Sasldisc_t *) malloc(sizeof(Sasldisc_t))) == NULL) 108 { 109 free(saslin); 110 return -1; 111 } 112 113 saslin->disc.readf = sasl_read; 114 saslin->disc.writef = sasl_write; 115 saslin->disc.seekf = NULL; 116 saslin->disc.exceptf = NULL; 117 118 saslout->disc.readf = sasl_read; 119 saslout->disc.writef = sasl_write; 120 saslout->disc.seekf = NULL; 121 saslout->disc.exceptf = NULL; 122 123 saslin->conn = conn; 124 saslout->conn = conn; 125 126 if (sfdisc(fin, (Sfdisc_t *) saslin) != (Sfdisc_t *) saslin || 127 sfdisc(fout, (Sfdisc_t *) saslout) != (Sfdisc_t *) saslout) 128 { 129 free(saslin); 130 free(saslout); 131 return -1; 132 } 133 return 0; 134 } 135 #endif /* SASL && SFIO */ 136 137 #if STARTTLS && (SFIO || _FFR_TLS_TOREK) 138 /* 139 ** STARTTLS 140 */ 141 142 # include "sfsasl.h" 143 # include <openssl/err.h> 144 145 static ssize_t 146 # if SFIO 147 tls_read(f, buf, size, disc) 148 Sfio_t *f; 149 Void_t *buf; 150 size_t size; 151 Sfdisc_t *disc; 152 # else /* SFIO */ 153 tls_read(disc, buf, size) 154 void *disc; 155 void *buf; 156 size_t size; 157 # endif /* SFIO */ 158 { 159 int r; 160 Tlsdisc_t *sd; 161 162 /* Cast back to correct type */ 163 sd = (Tlsdisc_t *) disc; 164 165 r = SSL_read(sd->con, (char *) buf, size); 166 if (r < 0 && LogLevel > 7) 167 { 168 char *err; 169 170 err = NULL; 171 switch (SSL_get_error(sd->con, r)) 172 { 173 case SSL_ERROR_NONE: 174 break; 175 case SSL_ERROR_WANT_WRITE: 176 err = "write W BLOCK"; 177 break; 178 case SSL_ERROR_WANT_READ: 179 err = "write R BLOCK"; 180 break; 181 case SSL_ERROR_WANT_X509_LOOKUP: 182 err = "write X BLOCK"; 183 break; 184 case SSL_ERROR_ZERO_RETURN: 185 break; 186 case SSL_ERROR_SYSCALL: 187 err = "syscall error"; 188 /* 189 get_last_socket_error()); 190 */ 191 break; 192 case SSL_ERROR_SSL: 193 err = "generic SSL error"; 194 break; 195 } 196 if (err != NULL) 197 sm_syslog(LOG_WARNING, NOQID, "TLS: read error: %s", 198 err); 199 } 200 return r; 201 } 202 203 static ssize_t 204 # if SFIO 205 tls_write(f, buf, size, disc) 206 Sfio_t *f; 207 const Void_t *buf; 208 size_t size; 209 Sfdisc_t *disc; 210 # else /* SFIO */ 211 tls_write(disc, buf, size) 212 void *disc; 213 const void *buf; 214 size_t size; 215 # endif /* SFIO */ 216 { 217 int r; 218 Tlsdisc_t *sd; 219 220 /* Cast back to correct type */ 221 sd = (Tlsdisc_t *) disc; 222 223 r = SSL_write(sd->con, (char *)buf, size); 224 if (r < 0 && LogLevel > 7) 225 { 226 char *err; 227 228 err = NULL; 229 switch (SSL_get_error(sd->con, r)) 230 { 231 case SSL_ERROR_NONE: 232 break; 233 case SSL_ERROR_WANT_WRITE: 234 err = "write W BLOCK"; 235 break; 236 case SSL_ERROR_WANT_READ: 237 err = "write R BLOCK"; 238 break; 239 case SSL_ERROR_WANT_X509_LOOKUP: 240 err = "write X BLOCK"; 241 break; 242 case SSL_ERROR_ZERO_RETURN: 243 break; 244 case SSL_ERROR_SYSCALL: 245 err = "syscall error"; 246 /* 247 get_last_socket_error()); 248 */ 249 break; 250 case SSL_ERROR_SSL: 251 err = "generic SSL error"; 252 /* 253 ERR_GET_REASON(ERR_peek_error())); 254 */ 255 break; 256 } 257 if (err != NULL) 258 sm_syslog(LOG_WARNING, NOQID, "TLS: write error: %s", 259 err); 260 } 261 return r; 262 } 263 264 # if !SFIO 265 static int 266 tls_close(cookie) 267 void *cookie; 268 { 269 int retval = 0; 270 Tlsdisc_t *tc; 271 272 /* Cast back to correct type */ 273 tc = (Tlsdisc_t *)cookie; 274 275 if (tc->fp != NULL) 276 { 277 retval = fclose(tc->fp); 278 tc->fp = NULL; 279 } 280 281 free(tc); 282 return retval; 283 } 284 # endif /* !SFIO */ 285 286 int 287 sfdctls(fin, fout, con) 288 # if SFIO 289 Sfio_t *fin; 290 Sfio_t *fout; 291 # else /* SFIO */ 292 FILE **fin; 293 FILE **fout; 294 # endif /* SFIO */ 295 SSL *con; 296 { 297 Tlsdisc_t *tlsin, *tlsout; 298 # if !SFIO 299 FILE *fp; 300 # else /* !SFIO */ 301 int rfd, wfd; 302 # endif /* !SFIO */ 303 304 if (con == NULL) 305 return 0; 306 307 if ((tlsin = (Tlsdisc_t *) malloc(sizeof(Tlsdisc_t))) == NULL) 308 return -1; 309 if ((tlsout = (Tlsdisc_t *) malloc(sizeof(Tlsdisc_t))) == NULL) 310 { 311 free(tlsin); 312 return -1; 313 } 314 315 # if SFIO 316 tlsin->disc.readf = tls_read; 317 tlsin->disc.writef = tls_write; 318 tlsin->disc.seekf = NULL; 319 tlsin->disc.exceptf = NULL; 320 tlsin->con = con; 321 322 tlsout->disc.readf = tls_read; 323 tlsout->disc.writef = tls_write; 324 tlsout->disc.seekf = NULL; 325 tlsout->disc.exceptf = NULL; 326 tlsout->con = con; 327 328 rfd = fileno(fin); 329 wfd = fileno(fout); 330 if (rfd < 0 || wfd < 0 || 331 SSL_set_rfd(con, rfd) <= 0 || SSL_set_wfd(con, wfd) <= 0) 332 { 333 free(tlsin); 334 free(tlsout); 335 return -1; 336 } 337 if (sfdisc(fin, (Sfdisc_t *) tlsin) != (Sfdisc_t *) tlsin || 338 sfdisc(fout, (Sfdisc_t *) tlsout) != (Sfdisc_t *) tlsout) 339 { 340 free(tlsin); 341 free(tlsout); 342 return -1; 343 } 344 # else /* SFIO */ 345 tlsin->fp = *fin; 346 tlsin->con = con; 347 fp = funopen(tlsin, tls_read, tls_write, NULL, tls_close); 348 if (fp == NULL) 349 { 350 free(tlsin); 351 return -1; 352 } 353 *fin = fp; 354 355 tlsout->fp = *fout; 356 tlsout->con = con; 357 fp = funopen(tlsout, tls_read, tls_write, NULL, tls_close); 358 if (fp == NULL) 359 { 360 FILE *save; 361 362 /* Hack: Don't close underlying fp */ 363 save = tlsin->fp; 364 tlsin->fp = NULL; 365 fclose(*fin); 366 *fin = save; 367 free(tlsout); 368 return -1; 369 } 370 *fout = fp; 371 SSL_set_rfd(con, fileno(tlsin->fp)); 372 SSL_set_wfd(con, fileno(tlsout->fp)); 373 # endif /* SFIO */ 374 return 0; 375 } 376 #endif /* STARTTLS && (SFIO || _FFR_TLS_TOREK) */ 377