sfsasl.c revision 64562
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 12static char id[] = "@(#)$Id: sfsasl.c,v 8.17.4.7 2000/07/18 18:44:51 gshapiro 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 30static ssize_t 31sasl_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 63static ssize_t 64sasl_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 91int 92sfdcsasl(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 145static ssize_t 146# if SFIO 147tls_read(f, buf, size, disc) 148 Sfio_t *f; 149 Void_t *buf; 150 size_t size; 151 Sfdisc_t *disc; 152# else /* SFIO */ 153tls_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 203static ssize_t 204# if SFIO 205tls_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 */ 211tls_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 265static int 266tls_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 286int 287sfdctls(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# endif /* !SFIO */ 301 302 if (con == NULL) 303 return 0; 304 305 if ((tlsin = (Tlsdisc_t *) malloc(sizeof(Tlsdisc_t))) == NULL) 306 return -1; 307 if ((tlsout = (Tlsdisc_t *) malloc(sizeof(Tlsdisc_t))) == NULL) 308 { 309 free(tlsin); 310 return -1; 311 } 312 313# if SFIO 314 tlsin->disc.readf = tls_read; 315 tlsin->disc.writef = tls_write; 316 tlsin->disc.seekf = NULL; 317 tlsin->disc.exceptf = NULL; 318 tlsin->con = con; 319 320 tlsout->disc.readf = tls_read; 321 tlsout->disc.writef = tls_write; 322 tlsout->disc.seekf = NULL; 323 tlsout->disc.exceptf = NULL; 324 tlsout->con = con; 325 326 SSL_set_rfd(con, fileno(fin)); /* fileno or sffileno? XXX */ 327 SSL_set_wfd(con, fileno(fout)); 328 if (sfdisc(fin, (Sfdisc_t *) tlsin) != (Sfdisc_t *) tlsin || 329 sfdisc(fout, (Sfdisc_t *) tlsout) != (Sfdisc_t *) tlsout) 330 { 331 free(tlsin); 332 free(tlsout); 333 return -1; 334 } 335# else /* SFIO */ 336 tlsin->fp = *fin; 337 tlsin->con = con; 338 fp = funopen(tlsin, tls_read, tls_write, NULL, tls_close); 339 if (fp == NULL) 340 { 341 free(tlsin); 342 return -1; 343 } 344 *fin = fp; 345 346 tlsout->fp = *fout; 347 tlsout->con = con; 348 fp = funopen(tlsout, tls_read, tls_write, NULL, tls_close); 349 if (fp == NULL) 350 { 351 FILE *save; 352 353 /* Hack: Don't close underlying fp */ 354 save = tlsin->fp; 355 tlsin->fp = NULL; 356 fclose(*fin); 357 *fin = save; 358 free(tlsout); 359 return -1; 360 } 361 *fout = fp; 362 SSL_set_rfd(con, fileno(tlsin->fp)); 363 SSL_set_wfd(con, fileno(tlsout->fp)); 364# endif /* SFIO */ 365 return 0; 366} 367#endif /* STARTTLS && (SFIO || _FFR_TLS_TOREK) */ 368