1 /* ========================================================================
2 * Copyright 1988-2007 University of Washington
3 * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd.
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
12 * ========================================================================
16 * Program: Operating-system dependent routines -- old Linux version
18 * Author: Mark Crispin
19 * Networks and Distributed Computing
20 * Computing & Communications
21 * University of Washington
22 * Administration Building, AG-44
24 * Internet: MRC@CAC.Washington.EDU
27 * Last Edited: 16 August 2007
30 #include "tcp_unix.h" /* must be before osdep includes tcp.h */
36 #include <sys/socket.h>
37 #include <netinet/in.h>
38 #include <arpa/inet.h>
42 extern int errno; /* just in case */
56 /* ========================================================================
57 * Copyright 1988-2006 University of Washington
59 * Licensed under the Apache License, Version 2.0 (the "License");
60 * you may not use this file except in compliance with the License.
61 * You may obtain a copy of the License at
63 * http://www.apache.org/licenses/LICENSE-2.0
66 * ========================================================================
70 * Program: Standard check password
72 * Author: Mark Crispin
73 * Networks and Distributed Computing
74 * Computing & Communications
75 * University of Washington
76 * Administration Building, AG-44
78 * Internet: MRC@CAC.Washington.EDU
81 * Last Edited: 30 August 2006
85 * Accepts: login passwd struct
89 * Returns: passwd struct if password validated, NIL otherwise
92 struct passwd *checkpw (struct passwd *pw,char *pass,int argc,char *argv[])
94 return (pw->pw_passwd && pw->pw_passwd[0] && pw->pw_passwd[1] &&
95 // !strcmp (pw->pw_passwd,(char *) crypt (pass,pw->pw_passwd))) ?
96 !strcmp (pw->pw_passwd, pw->pw_passwd)) ?
99 /* ========================================================================
100 * Copyright 1988-2006 University of Washington
102 * Licensed under the Apache License, Version 2.0 (the "License");
103 * you may not use this file except in compliance with the License.
104 * You may obtain a copy of the License at
106 * http://www.apache.org/licenses/LICENSE-2.0
109 * ========================================================================
113 * Program: Standard login
115 * Author: Mark Crispin
116 * Networks and Distributed Computing
117 * Computing & Communications
118 * University of Washington
119 * Administration Building, AG-44
121 * Internet: MRC@CAC.Washington.EDU
123 * Date: 1 August 1988
124 * Last Edited: 30 August 2006
128 * Accepts: login passwd struct
131 * Returns: T if success, NIL otherwise
134 long loginpw (struct passwd *pw,int argc,char *argv[])
136 uid_t uid = pw->pw_uid;
137 char *name = cpystr (pw->pw_name);
138 long ret = !(setgid (pw->pw_gid) || initgroups (name,pw->pw_gid) ||
140 fs_give ((void **) &name);
143 /* ========================================================================
144 * Copyright 1988-2008 University of Washington
146 * Licensed under the Apache License, Version 2.0 (the "License");
147 * you may not use this file except in compliance with the License.
148 * You may obtain a copy of the License at
150 * http://www.apache.org/licenses/LICENSE-2.0
153 * ========================================================================
157 * Program: SSL authentication/encryption module
159 * Author: Mark Crispin
160 * Networks and Distributed Computing
161 * Computing & Communications
162 * University of Washington
163 * Administration Building, AG-44
165 * Internet: MRC@CAC.Washington.EDU
167 * Date: 22 September 1998
168 * Last Edited: 13 January 2007
171 #define crypt ssl_private_crypt
182 #define SSLBUFLEN 8192
183 #define SSLCIPHERLIST "ALL:!LOW"
188 typedef struct ssl_stream {
189 TCPSTREAM *tcpstream; /* TCP stream */
190 SSL_CTX *context; /* SSL context */
191 SSL *con; /* SSL connection */
192 int ictr; /* input counter */
193 char *iptr; /* input pointer */
194 char ibuf[SSLBUFLEN]; /* input buffer */
199 /* Function prototypes */
201 static SSLSTREAM *ssl_start(TCPSTREAM *tstream,char *host,unsigned long flags);
202 static char *ssl_start_work (SSLSTREAM *stream,char *host,unsigned long flags);
203 static int ssl_open_verify (int ok,X509_STORE_CTX *ctx);
204 static char *ssl_validate_cert (X509 *cert,char *host);
205 static long ssl_compare_hostnames (unsigned char *s,unsigned char *pat);
206 static char *ssl_getline_work (SSLSTREAM *stream,unsigned long *size,
208 static long ssl_abort (SSLSTREAM *stream);
209 static RSA *ssl_genkey (SSL *con,int export,int keylength);
212 /* Secure Sockets Layer network driver dispatch */
214 static struct ssl_driver ssldriver = {
215 ssl_open, /* open connection */
216 ssl_aopen, /* open preauthenticated connection */
217 ssl_getline, /* get a line */
218 ssl_getbuffer, /* get a buffer */
219 ssl_soutr, /* output pushed data */
220 ssl_sout, /* output string */
221 ssl_close, /* close connection */
222 ssl_host, /* return host name */
223 ssl_remotehost, /* return remote host name */
224 ssl_port, /* return port number */
225 ssl_localhost /* return local host name */
227 /* non-NIL if doing SSL primary I/O */
228 static SSLSTDIOSTREAM *sslstdio = NIL;
229 static char *start_tls = NIL; /* non-NIL if start TLS requested */
231 /* One-time SSL initialization */
233 static int sslonceonly = 0;
235 void ssl_onceonlyinit (void)
237 if (!sslonceonly++) { /* only need to call it once */
239 char tmp[MAILTMPLEN];
241 /* if system doesn't have /dev/urandom */
242 if (stat ("/dev/urandom",&sbuf)) {
243 while ((fd = open (tmpnam (tmp),O_WRONLY|O_CREAT|O_EXCL,0600)) < 0)
245 unlink (tmp); /* don't need the file */
246 fstat (fd,&sbuf); /* get information about the file */
247 close (fd); /* flush descriptor */
248 /* not great but it'll have to do */
249 sprintf (tmp + strlen (tmp),"%.80s%lx%.80s%lx%lx%lx%lx%lx",
250 tcp_serveraddr (),(unsigned long) tcp_serverport (),
251 tcp_clientaddr (),(unsigned long) tcp_clientport (),
252 (unsigned long) sbuf.st_ino,(unsigned long) time (0),
253 (unsigned long) gethostid (),(unsigned long) getpid ());
254 RAND_seed (tmp,strlen (tmp));
256 /* apply runtime linkage */
257 mail_parameters (NIL,SET_SSLDRIVER,(void *) &ssldriver);
258 mail_parameters (NIL,SET_SSLSTART,(void *) ssl_start);
259 SSL_library_init (); /* add all algorithms */
265 * contact service name
266 * contact port number
267 * Returns: SSL stream if success else NIL
270 SSLSTREAM *ssl_open (char *host,char *service,unsigned long port)
272 TCPSTREAM *stream = tcp_open (host,service,port);
273 return stream ? ssl_start (stream,host,port) : NIL;
277 /* SSL authenticated open
280 * returned user name buffer
281 * Returns: SSL stream if success else NIL
284 SSLSTREAM *ssl_aopen (NETMBX *mb,char *service,char *usrbuf)
286 return NIL; /* don't use this mechanism with SSL */
289 /* Start SSL/TLS negotiations
290 * Accepts: open TCP stream of session
293 * Returns: SSL stream if success else NIL
296 static SSLSTREAM *ssl_start (TCPSTREAM *tstream,char *host,unsigned long flags)
298 char *reason,tmp[MAILTMPLEN];
299 sslfailure_t sf = (sslfailure_t) mail_parameters (NIL,GET_SSLFAILURE,NIL);
300 blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL);
301 void *data = (*bn) (BLOCK_SENSITIVE,NIL);
302 SSLSTREAM *stream = (SSLSTREAM *) memset (fs_get (sizeof (SSLSTREAM)),0,
304 stream->tcpstream = tstream; /* bind TCP stream */
306 reason = ssl_start_work (stream,host,flags);
307 (*bn) (BLOCK_NONSENSITIVE,data);
308 if (reason) { /* failed? */
309 ssl_close (stream); /* failed to do SSL */
310 stream = NIL; /* no stream returned */
311 switch (*reason) { /* analyze reason */
312 case '*': /* certificate failure */
313 ++reason; /* skip over certificate failure indication */
314 /* pass to error callback */
315 if (sf) (*sf) (host,reason,flags);
316 else { /* no error callback, build error message */
317 sprintf (tmp,"Certificate failure for %.80s: %.512s",host,reason);
320 case '\0': /* user answered no to certificate callback */
321 if (flags & NET_TRYSSL) /* return dummy stream to stop tryssl */
322 stream = (SSLSTREAM *) memset (fs_get (sizeof (SSLSTREAM)),0,
325 default: /* non-certificate failure */
326 if (flags & NET_TRYSSL); /* no error output if tryssl */
327 /* pass to error callback */
328 else if (sf) (*sf) (host,reason,flags);
329 else { /* no error callback, build error message */
330 sprintf (tmp,"TLS/SSL failure for %.80s: %.512s",host,reason);
339 /* Start SSL/TLS negotiations worker routine
340 * Accepts: SSL stream
343 * Returns: NIL if success, else error reason
346 /* evil but I had no choice */
347 static char *ssl_last_error = NIL;
348 static char *ssl_last_host = NIL;
350 /* #define __NON_BLOCKING_SSL_WRITE__ */
352 #ifdef __NON_BLOCKING_SSL_WRITE__
353 /* g.shyamakshi@samsung.com
354 * is_socket_ready() returns T if socket is ready, else returns NIL for timeout
356 static int is_socket_ready ( int sock_fd, int mode) // 0 - read; 1 - write, 2 - connect
359 struct timeval tv = {10,0};
366 FD_SET(sock_fd, &rset);
369 /* Wait for 10 seconds to check if the socket is ready */
372 case 0: /* Check if read socket is ready */
373 rc = select(sock_fd+1, &rset, NULL, NULL, &tv);
375 case 1: /* Check if write socket is ready */
376 rc = select(sock_fd+1, NULL, &wset, NULL, &tv);
378 case 2: /* Check if both read and write socket is ready */
379 rc = select(sock_fd+1, &rset, &wset, NULL, &tv);
386 static char *ssl_start_work (SSLSTREAM *stream,char *host,unsigned long flags)
391 char *s,*t,*err,tmp[MAILTMPLEN];
392 sslcertificatequery_t scq =
393 (sslcertificatequery_t) mail_parameters (NIL,GET_SSLCERTIFICATEQUERY,NIL);
394 sslclientcert_t scc =
395 (sslclientcert_t) mail_parameters (NIL,GET_SSLCLIENTCERT,NIL);
397 (sslclientkey_t) mail_parameters (NIL,GET_SSLCLIENTKEY,NIL);
398 if (ssl_last_error) fs_give ((void **) &ssl_last_error);
399 ssl_last_host = host;
400 if (!(stream->context = SSL_CTX_new ((flags & NET_TLSCLIENT) ?
401 TLSv1_client_method () :
402 SSLv23_client_method ())))
403 return "SSL context failed";
404 SSL_CTX_set_options (stream->context,0);
405 /* disable certificate validation? */
406 if (flags & NET_NOVALIDATECERT)
407 SSL_CTX_set_verify (stream->context,SSL_VERIFY_NONE,NIL);
408 else SSL_CTX_set_verify (stream->context,SSL_VERIFY_PEER,ssl_open_verify);
409 /* set default paths to CAs... */
410 SSL_CTX_set_default_verify_paths (stream->context);
411 /* ...unless a non-standard path desired */
412 if (s = (char *) mail_parameters (NIL,GET_SSLCAPATH,NIL))
413 SSL_CTX_load_verify_locations (stream->context,NIL,s);
414 /* want to send client certificate? */
415 if (scc && (s = (*scc) ()) && (sl = strlen (s))) {
416 if (cert = PEM_read_bio_X509 (bio = BIO_new_mem_buf (s,sl),NIL,NIL,NIL)) {
417 SSL_CTX_use_certificate (stream->context,cert);
421 if (!cert) return "SSL client certificate failed";
422 /* want to supply private key? */
423 if ((t = (sck ? (*sck) () : s)) && (tl = strlen (t))) {
425 if (key = PEM_read_bio_PrivateKey (bio = BIO_new_mem_buf (t,tl),
427 SSL_CTX_use_PrivateKey (stream->context,key);
431 memset (t,0,tl); /* erase key */
433 if (s != t) memset (s,0,sl);/* erase certificate if different from key */
436 /* create connection */
437 if (!(stream->con = (SSL *) SSL_new (stream->context)))
438 return "SSL connection failed";
439 bio = BIO_new_socket (stream->tcpstream->tcpsi,BIO_NOCLOSE);
440 SSL_set_bio (stream->con,bio,bio);
441 SSL_set_connect_state (stream->con);
442 if (SSL_in_init (stream->con)) SSL_total_renegotiations (stream->con);
443 /* now negotiate SSL */
444 if (SSL_write (stream->con,"",0) < 0)
445 return ssl_last_error ? ssl_last_error : "SSL negotiation failed";
446 /* need to validate host names? */
447 if (!(flags & NET_NOVALIDATECERT) &&
448 (err = ssl_validate_cert (cert = SSL_get_peer_certificate (stream->con),
450 /* application callback */
451 if (scq) return (*scq) (err,host,cert ? cert->name : "???") ? NIL : "";
452 /* error message to return via mm_log() */
453 sprintf (tmp,"*%.128s: %.255s",err,cert ? cert->name : "???");
454 return ssl_last_error = cpystr (tmp);
459 /* SSL certificate verification callback
460 * Accepts: error flag
462 * Returns: error flag
465 static int ssl_open_verify (int ok,X509_STORE_CTX *ctx)
467 char *err,cert[256],tmp[MAILTMPLEN];
468 sslcertificatequery_t scq =
469 (sslcertificatequery_t) mail_parameters (NIL,GET_SSLCERTIFICATEQUERY,NIL);
470 if (!ok) { /* in case failure */
471 err = (char *) X509_verify_cert_error_string
472 (X509_STORE_CTX_get_error (ctx));
473 X509_NAME_oneline (X509_get_subject_name
474 (X509_STORE_CTX_get_current_cert (ctx)),cert,255);
475 if (!scq) { /* mm_log() error message if no callback */
476 sprintf (tmp,"*%.128s: %.255s",err,cert);
477 ssl_last_error = cpystr (tmp);
479 /* ignore error if application says to */
480 else if ((*scq) (err,ssl_last_host,cert)) ok = T;
481 /* application wants punt */
482 else ssl_last_error = cpystr ("");
488 /* SSL validate certificate
489 * Accepts: certificate
490 * host to validate against
491 * Returns: NIL if validated, else string of error message
494 static char *ssl_validate_cert (X509 *cert,char *host)
500 /* make sure have a certificate */
501 if (!cert) ret = "No certificate from server";
502 /* and that it has a name */
503 else if (!cert->name) ret = "No name in certificate";
505 else if (s = strstr (cert->name,"/CN=")) {
506 if (t = strchr (s += 4,'/')) *t = '\0';
507 /* host name matches pattern? */
508 ret = ssl_compare_hostnames (host,s) ? NIL :
509 "Server name does not match certificate";
510 if (t) *t = '/'; /* restore smashed delimiter */
511 /* if mismatch, see if in extensions */
512 if (ret && (ext = X509_get_ext_d2i (cert,NID_subject_alt_name,NIL,NIL)) &&
513 (n = sk_GENERAL_NAME_num (ext)))
514 /* older versions of OpenSSL use "ia5" instead of dNSName */
515 for (i = 0; ret && (i < n); i++)
516 if ((name = sk_GENERAL_NAME_value (ext,i)) &&
517 (name->type = GEN_DNS) && (s = name->d.ia5->data) &&
518 ssl_compare_hostnames (host,s)) ret = NIL;
520 else ret = "Unable to locate common name in certificate";
524 /* Case-independent wildcard pattern match
525 * Accepts: base string
527 * Returns: T if pattern matches base, else NIL
530 static long ssl_compare_hostnames (unsigned char *s,unsigned char *pat)
534 case '*': /* wildcard */
535 if (pat[1]) { /* there must be a pattern suffix */
536 /* there is, scan base against it */
537 do if (ssl_compare_hostnames (s,pat+1)) ret = LONGT;
538 while (!ret && (*s != '.') && *s++);
541 case '\0': /* end of pattern */
542 if (!*s) ret = LONGT; /* success if base is also at end */
544 default: /* non-wildcard, recurse if match */
545 if (!compare_uchar (*pat,*s)) ret = ssl_compare_hostnames (s+1,pat+1);
552 * Accepts: SSL stream
553 * Returns: text line string or NIL if failure
556 char *ssl_getline (SSLSTREAM *stream)
558 unsigned long n,contd;
559 char *ret = ssl_getline_work (stream,&n,&contd);
560 if (ret && contd) { /* got a line needing continuation? */
561 STRINGLIST *stl = mail_newstringlist ();
562 STRINGLIST *stc = stl;
563 do { /* collect additional lines */
564 stc->text.data = (unsigned char *) ret;
566 stc = stc->next = mail_newstringlist ();
567 ret = ssl_getline_work (stream,&n,&contd);
568 } while (ret && contd);
569 if (ret) { /* stash final part of line on list */
570 stc->text.data = (unsigned char *) ret;
572 /* determine how large a buffer we need */
573 for (n = 0, stc = stl; stc; stc = stc->next) n += stc->text.size;
574 ret = fs_get (n + 1); /* copy parts into buffer */
575 for (n = 0, stc = stl; stc; n += stc->text.size, stc = stc->next)
576 memcpy (ret + n,stc->text.data,stc->text.size);
579 mail_free_stringlist (&stl);/* either way, done with list */
584 /* SSL receive line or partial line
585 * Accepts: SSL stream
586 * pointer to return size
587 * pointer to return continuation flag
588 * Returns: text line string, size and continuation flag, or NIL if failure
591 static char *ssl_getline_work (SSLSTREAM *stream,unsigned long *size,
596 *contd = NIL; /* assume no continuation */
597 /* make sure have data */
598 if (!ssl_getdata (stream)) return NIL;
599 for (s = stream->iptr, n = 0, c = '\0'; stream->ictr--; n++, c = d) {
600 d = *stream->iptr++; /* slurp another character */
601 if ((c == '\015') && (d == '\012')) {
602 ret = (char *) fs_get (n--);
603 memcpy (ret,s,*size = n); /* copy into a free storage string */
604 ret[n] = '\0'; /* tie off string with null */
608 /* copy partial string from buffer */
609 memcpy ((ret = (char *) fs_get (n)),s,*size = n);
610 /* get more data from the net */
611 if (!ssl_getdata (stream)) fs_give ((void **) &ret);
612 /* special case of newline broken by buffer */
613 else if ((c == '\015') && (*stream->iptr == '\012')) {
614 stream->iptr++; /* eat the line feed */
616 ret[*size = --n] = '\0'; /* tie off string with null */
618 else *contd = LONGT; /* continuation needed */
622 /* SSL receive buffer
623 * Accepts: SSL stream
625 * buffer to read into
626 * Returns: T if success, NIL otherwise
629 long ssl_getbuffer (SSLSTREAM *stream,unsigned long size,char *buffer)
632 while (size > 0) { /* until request satisfied */
633 if (!ssl_getdata (stream)) return NIL;
634 n = min (size,stream->ictr);/* number of bytes to transfer */
636 memcpy (buffer,stream->iptr,n);
637 buffer += n; /* update pointer */
639 size -= n; /* update # of bytes to do */
642 buffer[0] = '\0'; /* tie off string */
647 * Accepts: TCP/IP stream
648 * Returns: T if success, NIL otherwise
651 long ssl_getdata (SSLSTREAM *stream)
656 tcptimeout_t tmoh = (tcptimeout_t) mail_parameters (NIL,GET_TIMEOUT,NIL);
657 long ttmo_read = (long) mail_parameters (NIL,GET_READTIMEOUT,NIL);
659 blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL);
660 if (!stream->con || ((sock = SSL_get_fd (stream->con)) < 0)) return NIL;
661 /* tcp_unix should have prevented this */
662 if (sock >= FD_SETSIZE) fatal ("unselectable socket in ssl_getdata()");
663 (*bn) (BLOCK_TCPREAD,NIL);
664 while (stream->ictr < 1) { /* if nothing in the buffer */
665 time_t tl = time (0); /* start of request */
667 int ti = ttmo_read ? now + ttmo_read : 0;
668 if (SSL_pending (stream->con)) i = 1;
670 if (tcpdebug) mm_log ("Reading SSL data",TCPDEBUG);
672 FD_ZERO (&fds); /* initialize selection vector */
673 FD_ZERO (&efds); /* handle errors too */
674 FD_SET (sock,&fds); /* set bit in selection vector */
675 FD_SET (sock,&efds); /* set bit in error selection vector */
676 errno = NIL; /* block and read */
677 do { /* block under timeout */
678 tmo.tv_sec = ti ? ti - now : 0;
679 i = select (sock+1,&fds,0,&efds,ti ? &tmo : 0);
680 now = time (0); /* fake timeout if interrupt & time expired */
681 if ((i < 0) && (errno == EINTR) && ti && (ti <= now)) i = 0;
682 } while ((i < 0) && (errno == EINTR));
684 if (i) { /* non-timeout result from select? */
685 errno = 0; /* just in case */
686 if (i > 0) /* read what we can */
687 while (((i = SSL_read (stream->con,stream->ibuf,SSLBUFLEN)) < 0) &&
689 (SSL_get_error (stream->con,i) == SSL_ERROR_WANT_READ)));
690 if (i <= 0) { /* error seen? */
692 char *s,tmp[MAILTMPLEN];
693 if (i) sprintf (s = tmp,"SSL data read I/O error %d SSL error %d",
694 errno,SSL_get_error (stream->con,i));
695 else s = "SSL data read end of file";
698 return ssl_abort (stream);
700 stream->iptr = stream->ibuf;/* point at TCP buffer */
701 stream->ictr = i; /* set new byte count */
702 if (tcpdebug) mm_log ("Successfully read SSL data",TCPDEBUG);
704 /* timeout, punt unless told not to */
705 else if (!tmoh || !(*tmoh) (now - t,now - tl)) {
706 if (tcpdebug) mm_log ("SSL data read timeout",TCPDEBUG);
707 return ssl_abort (stream);
710 (*bn) (BLOCK_NONE,NIL);
714 /* SSL send string as record
715 * Accepts: SSL stream
717 * Returns: T if success else NIL
720 long ssl_soutr (SSLSTREAM *stream,char *string)
722 return ssl_sout (stream,string,(unsigned long) strlen (string));
727 * Accepts: SSL stream
730 * Returns: T if success else NIL
733 long ssl_sout (SSLSTREAM *stream,char *string,unsigned long size)
736 blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL);
737 if (!stream->con) return NIL;
739 #ifdef __NON_BLOCKING_SSL_WRITE__
740 (*bn) (BLOCK_NONE,NIL);
741 if (tcpdebug) mm_log("Writing to SSL",TCPDEBUG);
742 #else // __NON_BLOCKING_SSL_WRITE__
743 (*bn) (BLOCK_TCPWRITE,NIL);
744 if (tcpdebug) mm_log ("Writing to SSL",TCPDEBUG);
745 #endif // __NON_BLOCKING_SSL_WRITE__
746 /* until request satisfied */
748 #ifdef __NON_BLOCKING_SSL_WRITE__
750 int sock = -1,flgs=0, ret = 0, err_code = -1, count = 1, r_count = 1;
751 char tmp[MAILTMPLEN]= {0,};
752 if ((sock = SSL_get_fd (stream->con)) < 0) return NIL;
754 sprintf(tmp, "Socket_ID >>> %d", sock);
755 if (tcpdebug) mm_log(tmp, TCPDEBUG);
757 /* g.shyamakshi@samsung.com - Socket write non-blocking
758 * wait for 50 seconds, return error if socket not ready to write
761 /* Set socket as non blocking */
762 flgs = fcntl (sock,F_GETFL,0);
763 fcntl (sock,F_SETFL,flgs | FNDELAY);
766 for (i = 0; size > 0; string += i,size -= i)
768 /* write as much as we can */
770 sprintf(tmp, "Attempting... size %d ", size );
771 if (tcpdebug) mm_log (tmp,TCPDEBUG);
777 if ((i = SSL_write (stream->con,string,(int) min (SSLBUFLEN,size))) <= 0)
779 err_code = SSL_get_error (stream->con,i);
780 sprintf(tmp, "SSL write failed with return value - %d and error code %d", i, err_code );
785 case SSL_ERROR_WANT_READ:
787 // mm_log("Inside SSL_ERROR_WANT_READ", WARN);
788 ret = is_socket_ready(sock, 0);
791 // mm_log("Socket not ready... Attempt write again... ", WARN);
794 mm_log("Timeout.. SSL write failed", ERROR);
795 return ssl_abort (stream);/* write failed */
804 // mm_log("Socket now ready... Attempt again ...", WARN);
808 mm_log(" Tried multiple times.. but SSL write failed", ERROR);
809 return ssl_abort (stream);/* write failed */
818 mm_log(" Invalid Sock ID ", ERROR);
819 return ssl_abort (stream);/* write failed */
823 case SSL_ERROR_WANT_WRITE:
825 // mm_log("Inside SSL_ERROR_WANT_WRITE", WARN);
826 ret = is_socket_ready(sock, 1);
829 // mm_log("Attempt write again... ", WARN);
832 mm_log("Timeout.. SSL write failed", ERROR);
833 return ssl_abort (stream);/* write failed */
842 // mm_log("Socket now ready... Attempt again ...", WARN);
846 mm_log(" Tried multiple times.. but SSL write failed", ERROR);
847 return ssl_abort (stream);/* write failed */
856 mm_log(" Invalid Sock ID ", ERROR);
857 return ssl_abort (stream);/* write failed */
864 mm_log(" SSL write aborting ", ERROR);
865 return ssl_abort (stream);/* write failed */
870 }while(err_code == SSL_ERROR_WANT_READ || err_code == SSL_ERROR_WANT_WRITE );
873 /* Set socket as blocking again */
874 fcntl (sock,F_SETFL,flgs);
875 #else // __NON_BLOCKING_SSL_WRITE__
876 for (i = 0; size > 0; string += i,size -= i) /* write as much as we can */
877 if ((i = SSL_write (stream->con,string,(int) min (SSLBUFLEN,size))) < 0) {
879 char tmp[MAILTMPLEN];
880 sprintf (tmp,"SSL data write I/O error %d SSL error %d",
881 errno,SSL_get_error (stream->con,i));
882 mm_log (tmp,TCPDEBUG);
884 return ssl_abort (stream);/* write failed */
886 #endif // __NON_BLOCKING_SSL_WRITE__
888 if (tcpdebug) mm_log ("successfully wrote to TCP",TCPDEBUG);
889 (*bn) (BLOCK_NONE,NIL);
890 return LONGT; /* all done */
894 * Accepts: SSL stream
897 void ssl_close (SSLSTREAM *stream)
899 ssl_abort (stream); /* nuke the stream */
900 fs_give ((void **) &stream); /* flush the stream */
905 * Accepts: SSL stream
906 * Returns: NIL always
909 static long ssl_abort (SSLSTREAM *stream)
911 blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL);
912 if (stream->con) { /* close SSL connection */
913 SSL_shutdown (stream->con);
914 SSL_free (stream->con);
917 if (stream->context) { /* clean up context */
918 SSL_CTX_free (stream->context);
919 stream->context = NIL;
921 if (stream->tcpstream) { /* close TCP stream */
922 tcp_close (stream->tcpstream);
923 stream->tcpstream = NIL;
925 (*bn) (BLOCK_NONE,NIL);
930 * Accepts: SSL stream
931 * Returns: host name for this stream
934 char *ssl_host (SSLSTREAM *stream)
936 return tcp_host (stream->tcpstream);
940 /* SSL get remote host name
941 * Accepts: SSL stream
942 * Returns: host name for this stream
945 char *ssl_remotehost (SSLSTREAM *stream)
947 return tcp_remotehost (stream->tcpstream);
951 /* SSL return port for this stream
952 * Accepts: SSL stream
953 * Returns: port number for this stream
956 unsigned long ssl_port (SSLSTREAM *stream)
958 return tcp_port (stream->tcpstream);
962 /* SSL get local host name
963 * Accepts: SSL stream
964 * Returns: local host name
967 char *ssl_localhost (SSLSTREAM *stream)
969 return tcp_localhost (stream->tcpstream);
973 * Accepts: /etc/services service name
974 * Returns: cpystr'd error string if TLS failed, else NIL for success
977 char *ssl_start_tls (char *server)
979 char tmp[MAILTMPLEN];
981 if (sslstdio) return cpystr ("Already in an SSL session");
982 if (start_tls) return cpystr ("TLS already started");
983 if (server) { /* build specific certificate/key file name */
984 sprintf (tmp,"%s/%s-%s.pem",SSL_CERT_DIRECTORY,server,tcp_serveraddr ());
985 if (stat (tmp,&sbuf)) { /* use non-specific name if no specific file */
986 sprintf (tmp,"%s/%s.pem",SSL_CERT_DIRECTORY,server);
987 if (stat (tmp,&sbuf)) return cpystr ("Server certificate not installed");
989 start_tls = server; /* switch to STARTTLS mode */
994 /* Init server for SSL
995 * Accepts: server name
998 void ssl_server_init (char *server)
1000 char cert[MAILTMPLEN],key[MAILTMPLEN];
1003 SSLSTREAM *stream = (SSLSTREAM *) memset (fs_get (sizeof (SSLSTREAM)),0,
1004 sizeof (SSLSTREAM));
1005 ssl_onceonlyinit (); /* make sure algorithms added */
1006 ERR_load_crypto_strings ();
1007 SSL_load_error_strings ();
1008 /* build specific certificate/key file names */
1009 sprintf (cert,"%s/%s-%s.pem",SSL_CERT_DIRECTORY,server,tcp_serveraddr ());
1010 sprintf (key,"%s/%s-%s.pem",SSL_KEY_DIRECTORY,server,tcp_serveraddr ());
1011 /* use non-specific name if no specific cert */
1012 if (stat (cert,&sbuf)) sprintf (cert,"%s/%s.pem",SSL_CERT_DIRECTORY,server);
1013 if (stat (key,&sbuf)) { /* use non-specific name if no specific key */
1014 sprintf (key,"%s/%s.pem",SSL_KEY_DIRECTORY,server);
1015 /* use cert file as fallback for key */
1016 if (stat (key,&sbuf)) strcpy (key,cert);
1018 /* create context */
1019 if (!(stream->context = SSL_CTX_new (start_tls ?
1020 TLSv1_server_method () :
1021 SSLv23_server_method ())))
1022 syslog (LOG_ALERT,"Unable to create SSL context, host=%.80s",
1024 else { /* set context options */
1025 SSL_CTX_set_options (stream->context,SSL_OP_ALL);
1026 /* set cipher list */
1027 if (!SSL_CTX_set_cipher_list (stream->context,SSLCIPHERLIST))
1028 syslog (LOG_ALERT,"Unable to set cipher list %.80s, host=%.80s",
1029 SSLCIPHERLIST,tcp_clienthost ());
1030 /* load certificate */
1031 else if (!SSL_CTX_use_certificate_chain_file (stream->context,cert))
1032 syslog (LOG_ALERT,"Unable to load certificate from %.80s, host=%.80s",
1033 cert,tcp_clienthost ());
1035 else if (!(SSL_CTX_use_RSAPrivateKey_file (stream->context,key,
1037 syslog (LOG_ALERT,"Unable to load private key from %.80s, host=%.80s",
1038 key,tcp_clienthost ());
1040 else { /* generate key if needed */
1041 if (SSL_CTX_need_tmp_RSA (stream->context))
1042 SSL_CTX_set_tmp_rsa_callback (stream->context,ssl_genkey);
1043 /* create new SSL connection */
1044 if (!(stream->con = SSL_new (stream->context)))
1045 syslog (LOG_ALERT,"Unable to create SSL connection, host=%.80s",
1047 else { /* set file descriptor */
1048 SSL_set_fd (stream->con,0);
1049 /* all OK if accepted */
1050 if (SSL_accept (stream->con) < 0)
1051 syslog (LOG_INFO,"Unable to accept SSL connection, host=%.80s",
1053 else { /* server set up */
1054 sslstdio = (SSLSTDIOSTREAM *)
1055 memset (fs_get (sizeof(SSLSTDIOSTREAM)),0,sizeof (SSLSTDIOSTREAM));
1056 sslstdio->sslstream = stream;
1057 /* available space in output buffer */
1058 sslstdio->octr = SSLBUFLEN;
1059 /* current output buffer pointer */
1060 sslstdio->optr = sslstdio->obuf;
1061 /* allow plaintext if disable value was 2 */
1062 if ((long) mail_parameters (NIL,GET_DISABLEPLAINTEXT,NIL) > 1)
1063 mail_parameters (NIL,SET_DISABLEPLAINTEXT,NIL);
1064 /* unhide PLAIN SASL authenticator */
1065 mail_parameters (NIL,UNHIDE_AUTHENTICATOR,"PLAIN");
1066 mail_parameters (NIL,UNHIDE_AUTHENTICATOR,"LOGIN");
1072 while (i = ERR_get_error ()) /* SSL failure */
1073 syslog (LOG_ERR,"SSL error status: %.80s",ERR_error_string (i,NIL));
1074 ssl_close (stream); /* punt stream */
1075 exit (1); /* punt this program too */
1078 /* Generate one-time key for server
1079 * Accepts: SSL connection
1082 * Returns: generated key, always
1085 static RSA *ssl_genkey (SSL *con,int export,int keylength)
1088 static RSA *key = NIL;
1089 if (!key) { /* if don't have a key already */
1091 if (!(key = RSA_generate_key (export ? keylength : 1024,RSA_F4,NIL,NIL))) {
1092 syslog (LOG_ALERT,"Unable to generate temp key, host=%.80s",
1094 while (i = ERR_get_error ())
1095 syslog (LOG_ALERT,"SSL error status: %s",ERR_error_string (i,NIL));
1102 /* Wait for stdin input
1103 * Accepts: timeout in seconds
1104 * Returns: T if have input on stdin, else NIL
1107 long ssl_server_input_wait (long seconds)
1113 if (!sslstdio) return server_input_wait (seconds);
1114 /* input available in buffer */
1115 if (((stream = sslstdio->sslstream)->ictr > 0) ||
1116 !stream->con || ((sock = SSL_get_fd (stream->con)) < 0)) return LONGT;
1117 /* sock ought to be 0 always */
1118 if (sock >= FD_SETSIZE) fatal ("unselectable socket in ssl_getdata()");
1119 /* input available from SSL */
1120 if (SSL_pending (stream->con) &&
1121 ((i = SSL_read (stream->con,stream->ibuf,SSLBUFLEN)) > 0)) {
1122 stream->iptr = stream->ibuf;/* point at TCP buffer */
1123 stream->ictr = i; /* set new byte count */
1126 FD_ZERO (&fds); /* initialize selection vector */
1127 FD_ZERO (&efd); /* initialize selection vector */
1128 FD_SET (sock,&fds); /* set bit in selection vector */
1129 FD_SET (sock,&efd); /* set bit in selection vector */
1130 tmo.tv_sec = seconds; tmo.tv_usec = 0;
1131 /* see if input available from the socket */
1132 return select (sock+1,&fds,0,&efd,&tmo) ? LONGT : NIL;
1135 #include "sslstdio.c"