3 * netsec.c -- Network security routines for handling protocols that
4 * require SASL and/or TLS.
6 * This code is Copyright (c) 2016, by the authors of nmh. See the
7 * COPYRIGHT file in the root directory of the nmh distribution for
8 * complete copyright information.
16 #include <sys/select.h>
19 #include <sasl/sasl.h>
20 #include <sasl/saslutil.h>
21 # if SASL_VERSION_FULL < 0x020125
22 /* Cyrus SASL 2.1.25 introduced the sasl_callback_ft prototype,
23 which has an explicit void parameter list, according to best
24 practice. So we need to cast to avoid compile warnings.
25 Provide this prototype for earlier versions. */
26 typedef int (*sasl_callback_ft
)();
27 # endif /* SASL_VERSION_FULL < 0x020125 */
29 static int netsec_get_user(void *context
, int id
, const char **result
,
31 static int netsec_get_password(sasl_conn_t
*conn
, void *context
, int id
,
32 sasl_secret_t
**psecret
);
34 static int sasl_initialized
= 0;
36 #define SASL_MAXRECVBUF 65536
37 #endif /* CYRUS_SASL */
40 #include <openssl/ssl.h>
41 #include <openssl/err.h>
43 static int tls_initialized
= 0;
44 static SSL_CTX
*sslctx
= NULL
; /* SSL Context */
46 #endif /* TLS_SUPPORT */
48 /* I'm going to hardcode this for now; maybe make it adjustable later? */
49 #define NETSEC_BUFSIZE 65536
52 * Our context structure, which holds all of the relevant information
56 struct _netsec_context
{
57 int ns_readfd
; /* Read descriptor for network connection */
58 int ns_writefd
; /* Write descriptor for network connection */
59 int ns_snoop
; /* If true, display network data */
60 int ns_snoop_noend
; /* If true, didn't get a CR/LF on last line */
61 netsec_snoop_callback
*ns_snoop_cb
; /* Snoop output callback */
62 void *ns_snoop_context
; /* Context data for snoop function */
63 int ns_timeout
; /* Network read timeout, in seconds */
64 char *ns_userid
; /* Userid for authentication */
65 char *ns_hostname
; /* Hostname we've connected to */
66 unsigned char *ns_inbuffer
; /* Our read input buffer */
67 unsigned char *ns_inptr
; /* Our read buffer input pointer */
68 unsigned int ns_inbuflen
; /* Length of data in input buffer */
69 unsigned int ns_inbufsize
; /* Size of input buffer */
70 unsigned char *ns_outbuffer
;/* Output buffer */
71 unsigned char *ns_outptr
; /* Output buffer pointer */
72 unsigned int ns_outbuflen
; /* Output buffer data length */
73 unsigned int ns_outbufsize
; /* Output buffer size */
74 char *sasl_mech
; /* User-requested mechanism */
75 char *sasl_chosen_mech
; /* Mechanism chosen by SASL */
76 netsec_sasl_callback sasl_proto_cb
; /* SASL callback we use */
78 char *oauth_service
; /* OAuth2 service name */
79 #endif /* OAUTH_SUPPORT */
81 sasl_conn_t
*sasl_conn
; /* SASL connection context */
82 sasl_ssf_t sasl_ssf
; /* SASL Security Strength Factor */
83 sasl_callback_t
*sasl_cbs
; /* Callbacks used by SASL */
84 nmh_creds_t sasl_creds
; /* Credentials (username/password) */
85 sasl_secret_t
*sasl_secret
; /* SASL password structure */
86 int sasl_seclayer
; /* If true, SASL security layer is enabled */
87 char *sasl_tmpbuf
; /* Temporary read buffer for decodes */
88 size_t sasl_maxbufsize
; /* Maximum negotiated SASL buffer size */
89 #endif /* CYRUS_SASL */
91 BIO
*ssl_io
; /* BIO used for connection I/O */
92 int tls_active
; /* If true, TLS is running */
93 #endif /* TLS_SUPPORT */
97 * Function to read data from the actual network socket
100 static int netsec_fillread(netsec_context
*ns_context
, char **errstr
);
103 * Code to check the ASCII content of a byte array.
106 static int checkascii(const unsigned char *byte
, size_t len
);
109 * How this code works, in general.
111 * _If_ we are using no encryption then we buffer the network data
112 * through ns_inbuffer and ns_outbuffer. That should be relatively
115 * If we use encryption, then ns_inbuffer and ns_outbuffer contain the
116 * cleartext data. When it comes time to send the encrypted data on the
117 * (either from a flush or the buffer is full) we either use BIO_write()
118 * for TLS or sasl_encode() (followed by a write() for Cyrus-SASL. For
119 * reads we either use BIO_read() (TLS) or do a network read into a
120 * temporary buffer and use sasl_decode() (Cyrus-SASL). Note that if
121 * negotiate TLS then we disable SASL encryption.
123 * We used to use a buffering BIO for the reads/writes for TLS, but it
124 * ended up being complicated to special-case the buffering for everything
125 * except TLS, so the buffering is now unified, no matter which encryption
126 * method is being used (even none).
128 * For SASL authentication, we make use of (for now) the Cyrus-SASL
129 * library. For some mechanisms, we implement those mechanisms directly
130 * since the Cyrus SASL library doesn't support them (like OAuth).
134 * Allocate and initialize our security context
144 nsc
->ns_writefd
= -1;
146 nsc
->ns_snoop_noend
= 0;
147 nsc
->ns_snoop_cb
= NULL
;
148 nsc
->ns_snoop_context
= NULL
;
149 nsc
->ns_userid
= NULL
;
150 nsc
->ns_hostname
= NULL
;
151 nsc
->ns_timeout
= 60; /* Our default */
152 nsc
->ns_inbufsize
= NETSEC_BUFSIZE
;
153 nsc
->ns_inbuffer
= mh_xmalloc(nsc
->ns_inbufsize
);
154 nsc
->ns_inptr
= nsc
->ns_inbuffer
;
155 nsc
->ns_inbuflen
= 0;
156 nsc
->ns_outbufsize
= NETSEC_BUFSIZE
;
157 nsc
->ns_outbuffer
= mh_xmalloc(nsc
->ns_outbufsize
);
158 nsc
->ns_outptr
= nsc
->ns_outbuffer
;
159 nsc
->ns_outbuflen
= 0;
160 nsc
->sasl_mech
= NULL
;
161 nsc
->sasl_chosen_mech
= NULL
;
162 nsc
->sasl_proto_cb
= NULL
;
164 nsc
->oauth_service
= NULL
;
165 #endif /* OAUTH_SUPPORT */
167 nsc
->sasl_conn
= NULL
;
168 nsc
->sasl_cbs
= NULL
;
169 nsc
->sasl_creds
= NULL
;
170 nsc
->sasl_secret
= NULL
;
172 nsc
->sasl_seclayer
= 0;
173 nsc
->sasl_tmpbuf
= NULL
;
174 nsc
->sasl_maxbufsize
= 0;
175 #endif /* CYRUS_SASL */
179 #endif /* TLS_SUPPORT */
184 * Shutdown the connection completely and free all resources.
185 * The connection is only closed if the flag is given.
189 netsec_shutdown(netsec_context
*nsc
, int closeflag
)
191 mh_xfree(nsc
->ns_userid
);
192 mh_xfree(nsc
->ns_hostname
);
193 mh_xfree(nsc
->ns_inbuffer
);
194 mh_xfree(nsc
->ns_outbuffer
);
195 mh_xfree(nsc
->sasl_mech
);
196 mh_xfree(nsc
->sasl_chosen_mech
);
198 mh_xfree(nsc
->oauth_service
);
199 #endif /* OAUTH_SERVICE */
202 sasl_dispose(&nsc
->sasl_conn
);
203 mh_xfree(nsc
->sasl_cbs
);
205 nmh_credentials_free(nsc
->sasl_creds
);
206 if (nsc
->sasl_secret
) {
207 if (nsc
->sasl_secret
->len
> 0) {
208 memset(nsc
->sasl_secret
->data
, 0, nsc
->sasl_secret
->len
);
210 free(nsc
->sasl_secret
);
212 mh_xfree(nsc
->sasl_tmpbuf
);
213 #endif /* CYRUS_SASL */
217 * I checked; BIO_free_all() will cause SSL_shutdown to be called
218 * on the SSL object in the chain.
220 BIO_free_all(nsc
->ssl_io
);
221 #endif /* TLS_SUPPORT */
224 if (nsc
->ns_readfd
!= -1)
225 close(nsc
->ns_readfd
);
226 if (nsc
->ns_writefd
!= -1 && nsc
->ns_writefd
!= nsc
->ns_readfd
)
227 close(nsc
->ns_writefd
);
234 * Set the file descriptor for our context
238 netsec_set_fd(netsec_context
*nsc
, int readfd
, int writefd
)
240 nsc
->ns_readfd
= readfd
;
241 nsc
->ns_writefd
= writefd
;
245 * Set the userid used for authentication for this context
249 netsec_set_userid(netsec_context
*nsc
, const char *userid
)
251 nsc
->ns_userid
= getcpy(userid
);
255 * Set the hostname of the remote host we're connecting to.
259 netsec_set_hostname(netsec_context
*nsc
, const char *hostname
)
261 nsc
->ns_hostname
= mh_xstrdup(hostname
);
265 * Get the snoop flag for this connection
269 netsec_get_snoop(netsec_context
*nsc
)
271 return nsc
->ns_snoop
;
275 * Set the snoop flag for this connection
279 netsec_set_snoop(netsec_context
*nsc
, int snoop
)
281 nsc
->ns_snoop
= snoop
;
285 * Set the snoop callback for this connection.
288 void netsec_set_snoop_callback(netsec_context
*nsc
,
289 netsec_snoop_callback callback
, void *context
)
291 nsc
->ns_snoop_cb
= callback
;
292 nsc
->ns_snoop_context
= context
;
296 * A base64-decoding snoop callback
300 netsec_b64_snoop_decoder(netsec_context
*nsc
, const char *string
, size_t len
,
303 unsigned char *decoded
;
308 offset
= context
? *((int *) context
) : 0;
312 * Output non-base64 data first.
314 fprintf(stderr
, "%.*s", offset
, string
);
319 if (decodeBase64(string
, &decoded
, &decodedlen
, 1, NULL
) == OK
) {
321 * Some mechanisms produce large binary tokens, which aren't really
322 * readable. So let's do a simple heuristic. If the token is greater
323 * than 100 characters _and_ the first 100 bytes are more than 50%
324 * non-ASCII, then don't print the decoded buffer, just the
327 if (decodedlen
> 100 && !checkascii(decoded
, 100)) {
328 fprintf(stderr
, "%.*s\n", (int) len
, string
);
331 hexify(decoded
, decodedlen
, &hexified
);
332 fprintf(stderr
, "b64<%s>\n", hexified
);
337 fprintf(stderr
, "%.*s\n", (int) len
, string
);
342 * If the ASCII content is > 50%, return 1
346 checkascii(const unsigned char *bytes
, size_t len
)
348 size_t count
= 0, half
= len
/ 2;
351 if (isascii(*bytes
) && isprint(*bytes
) && ++count
> half
)
354 /* No chance by this point */
355 if (count
+ len
< half
)
363 * Set the read timeout for this connection
367 netsec_set_timeout(netsec_context
*nsc
, int timeout
)
369 nsc
->ns_timeout
= timeout
;
373 * Read data from the network. Basically, return anything in our buffer,
374 * otherwise fill from the network.
378 netsec_read(netsec_context
*nsc
, void *buffer
, size_t size
, char **errstr
)
383 * If our buffer is empty, then we should fill it now
386 if (nsc
->ns_inbuflen
== 0) {
387 if (netsec_fillread(nsc
, errstr
) != OK
)
392 * netsec_fillread only returns if the buffer is full, so we can
393 * assume here that this has something in it.
396 retlen
= size
> nsc
->ns_inbuflen
? nsc
->ns_inbuflen
: size
;
398 memcpy(buffer
, nsc
->ns_inptr
, retlen
);
400 if (retlen
== (int) nsc
->ns_inbuflen
) {
402 * We've emptied our buffer, so reset everything.
404 nsc
->ns_inptr
= nsc
->ns_inbuffer
;
405 nsc
->ns_inbuflen
= 0;
407 nsc
->ns_inptr
+= size
;
408 nsc
->ns_inbuflen
-= size
;
415 * Get a "line" (CR/LF) terminated from the network.
417 * Okay, we play some games here, so pay attention:
419 * - Unlike every other function, we return a pointer to the
420 * existing buffer. This pointer is valid until you call another
421 * read function again.
422 * - We NUL-terminate the buffer right at the end, before the CR-LF terminator.
423 * - Technically we look for a LF; if we find a CR right before it, then
425 * - If your data may contain embedded NULs, this won't work. You should
426 * be using netsec_read() in that case.
430 netsec_readline(netsec_context
*nsc
, size_t *len
, char **errstr
)
432 unsigned char *ptr
= nsc
->ns_inptr
;
433 size_t count
= 0, offset
;
437 * Search through our existing buffer for a LF
440 while (count
< nsc
->ns_inbuflen
) {
442 if (*ptr
++ == '\n') {
443 char *sptr
= (char *) nsc
->ns_inptr
;
444 if (count
> 1 && *(ptr
- 2) == '\r')
448 *len
= ptr
- nsc
->ns_inptr
;
449 nsc
->ns_inptr
+= count
;
450 nsc
->ns_inbuflen
-= count
;
453 if (nsc
->sasl_seclayer
)
454 fprintf(stderr
, "(sasl-decrypted) ");
455 #endif /* CYRUS_SASL */
458 fprintf(stderr
, "(tls-decrypted) ");
459 #endif /* TLS_SUPPORT */
460 fprintf(stderr
, "<= ");
461 if (nsc
->ns_snoop_cb
)
462 nsc
->ns_snoop_cb(nsc
, sptr
, strlen(sptr
),
463 nsc
->ns_snoop_context
);
465 fprintf(stderr
, "%s\n", sptr
);
472 * Hm, we didn't find a \n. If we've already searched half of the input
473 * buffer, return an error.
476 if (count
>= nsc
->ns_inbufsize
/ 2) {
477 netsec_err(errstr
, "Unable to find a line terminator after %d bytes",
483 * Okay, get some more network data. This may move inptr, so regenerate
487 offset
= ptr
- nsc
->ns_inptr
;
489 if (netsec_fillread(nsc
, errstr
) != OK
)
492 ptr
= nsc
->ns_inptr
+ offset
;
496 return NULL
; /* Should never reach this */
500 * Fill our read buffer with some data from the network.
504 netsec_fillread(netsec_context
*nsc
, char **errstr
)
508 size_t readbufsize
, remaining
, startoffset
;
512 * If inbuflen is zero, that means the buffer has been emptied
513 * completely. In that case move inptr back to the start.
516 if (nsc
->ns_inbuflen
== 0) {
517 nsc
->ns_inptr
= nsc
->ns_inbuffer
;
520 #if defined(CYRUS_SASL) || defined(TLS_SUPPORT)
522 #endif /* CYRUS_SASL || TLS_SUPPORT */
524 * If we are using TLS and there's anything pending, then skip the
528 if (!nsc
->tls_active
|| BIO_pending(nsc
->ssl_io
) == 0)
529 #endif /* TLS_SUPPORT */
535 FD_SET(nsc
->ns_readfd
, &rfds
);
537 tv
.tv_sec
= nsc
->ns_timeout
;
540 rc
= select(nsc
->ns_readfd
+ 1, &rfds
, NULL
, NULL
, &tv
);
543 netsec_err(errstr
, "select() while reading failed: %s",
549 netsec_err(errstr
, "read() timed out after %d seconds",
555 * At this point, we know that rc is 1, so there's not even any
556 * point to check to see if our descriptor is set in rfds.
563 * startoffset is the offset from the beginning of the input
564 * buffer to data that is in our input buffer, but has not yet
565 * been consumed. This can be non-zero if functions like
566 * netsec_readline() leave leftover data.
568 * remaining is the remaining amount of unconsumed data in the input
571 * end is a pointer to the end of the valid data + 1; it's where
572 * the next read should go.
575 startoffset
= nsc
->ns_inptr
- nsc
->ns_inbuffer
;
576 remaining
= nsc
->ns_inbufsize
- (startoffset
+ nsc
->ns_inbuflen
);
577 end
= nsc
->ns_inptr
+ nsc
->ns_inbuflen
;
580 * If we're past the halfway point in our read buffers, shuffle everything
581 * back to the beginning.
584 if (startoffset
> nsc
->ns_inbufsize
/ 2) {
585 memmove(nsc
->ns_inbuffer
, nsc
->ns_inptr
, nsc
->ns_inbuflen
);
586 nsc
->ns_inptr
= nsc
->ns_inbuffer
;
588 remaining
= nsc
->ns_inbufsize
- nsc
->ns_inbuflen
;
589 end
= nsc
->ns_inptr
+ nsc
->ns_inbuflen
;
593 * If we are using TLS, then just read via the BIO. But we still
594 * use our local buffer.
597 if (nsc
->tls_active
) {
598 rc
= BIO_read(nsc
->ssl_io
, end
, remaining
);
604 * Check to see if we're supposed to retry; if so,
605 * then go back and read again.
608 if (BIO_should_retry(nsc
->ssl_io
))
612 * Okay, fine. Get the real error out of the SSL context.
615 if (BIO_get_ssl(nsc
->ssl_io
, &ssl
) < 1) {
616 netsec_err(errstr
, "SSL_read() returned 0, but cannot "
617 "retrieve SSL context");
621 errcode
= SSL_get_error(ssl
, rc
);
622 if (errcode
== SSL_ERROR_ZERO_RETURN
) {
623 netsec_err(errstr
, "TLS peer closed remote connection");
625 netsec_err(errstr
, "TLS network read failed: %s",
626 ERR_error_string(ERR_peek_last_error(), NULL
));
629 ERR_print_errors_fp(stderr
);
633 /* Definitely an error */
634 netsec_err(errstr
, "Read on TLS connection failed: %s",
635 ERR_error_string(ERR_get_error(), NULL
));
639 nsc
->ns_inbuflen
+= rc
;
643 #endif /* TLS_SUPPORT */
646 * Okay, time to read some data. Either we're just doing it straight
647 * or we're passing it through sasl_decode() first.
651 if (nsc
->sasl_seclayer
) {
652 readbuf
= nsc
->sasl_tmpbuf
;
653 readbufsize
= nsc
->sasl_maxbufsize
;
655 #endif /* CYRUS_SASL */
657 readbuf
= (char *) end
;
658 readbufsize
= remaining
;
662 * At this point, we should have active data on the connection (see
663 * select() above) so this read SHOULDN'T block. Hopefully.
666 rc
= read(nsc
->ns_readfd
, readbuf
, readbufsize
);
669 netsec_err(errstr
, "Received EOF on network read");
674 netsec_err(errstr
, "Network read failed: %s", strerror(errno
));
679 * Okay, so we've had a successful read. If we are doing SASL security
680 * layers, pass this through sasl_decode(). sasl_decode() can return
681 * 0 bytes decoded; if that happens, jump back to the beginning. Otherwise
682 * we can just update our length pointer.
686 if (nsc
->sasl_seclayer
) {
688 unsigned int tmpoutlen
;
690 rc
= sasl_decode(nsc
->sasl_conn
, nsc
->sasl_tmpbuf
, rc
,
691 &tmpout
, &tmpoutlen
);
694 netsec_err(errstr
, "Unable to decode SASL network data: %s",
695 sasl_errdetail(nsc
->sasl_conn
));
706 if (tmpoutlen
> remaining
) {
707 netsec_err(errstr
, "Internal error: SASL decode buffer overflow!");
711 memcpy(end
, tmpout
, tmpoutlen
);
713 nsc
->ns_inbuflen
+= tmpoutlen
;
715 #endif /* CYRUS_SASL */
716 nsc
->ns_inbuflen
+= rc
;
722 * Write data to our network connection. Really, fill up the buffer as
723 * much as we can, and flush it out if necessary. netsec_flush() does
728 netsec_write(netsec_context
*nsc
, const void *buffer
, size_t size
,
731 const unsigned char *bufptr
= buffer
;
740 * Run a loop copying in data to our local buffer; when we're done with
741 * any buffer overflows then just copy any remaining data in.
744 while ((int) size
>= (remaining
= nsc
->ns_outbufsize
- nsc
->ns_outbuflen
)) {
745 memcpy(nsc
->ns_outptr
, bufptr
, remaining
);
748 * In theory I should increment outptr, but netsec_flush just resets
751 nsc
->ns_outbuflen
= nsc
->ns_outbufsize
;
753 rc
= netsec_flush(nsc
, errstr
);
763 * Copy any leftover data into the buffer.
767 memcpy(nsc
->ns_outptr
, bufptr
, size
);
768 nsc
->ns_outptr
+= size
;
769 nsc
->ns_outbuflen
+= size
;
776 * Our network printf() routine, which really just calls netsec_vprintf().
780 netsec_printf(netsec_context
*nsc
, char **errstr
, const char *format
, ...)
785 va_start(ap
, format
);
786 rc
= netsec_vprintf(nsc
, errstr
, format
, ap
);
793 * Write bytes to the network using printf()-style formatting.
795 * Again, for the most part copy stuff into our buffer to be flushed
800 netsec_vprintf(netsec_context
*nsc
, char **errstr
, const char *format
,
806 * Cheat a little. If we can fit the data into our outgoing buffer,
807 * great! If not, generate a flush and retry once.
811 rc
= vsnprintf((char *) nsc
->ns_outptr
,
812 nsc
->ns_outbufsize
- nsc
->ns_outbuflen
, format
, ap
);
814 if (rc
>= (int) (nsc
->ns_outbufsize
- nsc
->ns_outbuflen
)) {
816 * This means we have an overflow. Note that we don't actually
817 * make use of the terminating NUL, but according to the spec
818 * vsnprintf() won't write to the last byte in the string; that's
819 * why we have to use >= in the comparison above.
821 if (nsc
->ns_outbuffer
== nsc
->ns_outptr
) {
823 * Whoops, if the buffer pointer was the same as the start of the
824 * buffer, that means we overflowed the internal buffer.
825 * At that point, just give up.
827 netsec_err(errstr
, "Internal error: wanted to printf() a total of "
828 "%d bytes, but our buffer size was only %d bytes",
829 rc
, nsc
->ns_outbufsize
);
833 * Generate a flush (which may be inefficient, but hopefully
834 * it isn't) and then try again.
836 if (netsec_flush(nsc
, errstr
) != OK
)
839 * After this, outbuffer should == outptr, so we shouldn't
840 * hit this next time around.
847 if (outlen
> 0 && nsc
->ns_outptr
[outlen
- 1] == '\n') {
849 if (outlen
> 0 && nsc
->ns_outptr
[outlen
- 1] == '\r')
852 nsc
->ns_snoop_noend
= 1;
854 if (outlen
> 0 || nsc
->ns_snoop_noend
== 0) {
856 if (nsc
->sasl_seclayer
)
857 fprintf(stderr
, "(sasl-encrypted) ");
858 #endif /* CYRUS_SASL */
861 fprintf(stderr
, "(tls-encrypted) ");
862 #endif /* TLS_SUPPORT */
863 fprintf(stderr
, "=> ");
864 if (nsc
->ns_snoop_cb
)
865 nsc
->ns_snoop_cb(nsc
, (char *) nsc
->ns_outptr
, outlen
,
866 nsc
->ns_snoop_context
);
868 fprintf(stderr
, "%.*s\n", outlen
, nsc
->ns_outptr
);
870 nsc
->ns_snoop_noend
= 0;
874 nsc
->ns_outptr
+= rc
;
875 nsc
->ns_outbuflen
+= rc
;
881 * Flush out any buffered data in our output buffers. This routine is
882 * actually where the real network writes take place.
886 netsec_flush(netsec_context
*nsc
, char **errstr
)
888 const char *netoutbuf
= (const char *) nsc
->ns_outbuffer
;
889 unsigned int netoutlen
= nsc
->ns_outbuflen
;
900 * If SASL security layers are in effect, run the data through
901 * sasl_encode() first.
904 if (nsc
->sasl_seclayer
) {
905 rc
= sasl_encode(nsc
->sasl_conn
, (const char *) nsc
->ns_outbuffer
,
906 nsc
->ns_outbuflen
, &netoutbuf
, &netoutlen
);
909 netsec_err(errstr
, "SASL data encoding failed: %s",
910 sasl_errdetail(nsc
->sasl_conn
));
915 #endif /* CYRUS_SASL */
918 * If TLS is active, then use those functions to write out the
922 if (nsc
->tls_active
) {
923 if (BIO_write(nsc
->ssl_io
, netoutbuf
, netoutlen
) <= 0) {
924 netsec_err(errstr
, "Error writing to TLS connection: %s",
925 ERR_error_string(ERR_get_error(), NULL
));
929 #endif /* TLS_SUPPORT */
931 rc
= write(nsc
->ns_writefd
, netoutbuf
, netoutlen
);
934 netsec_err(errstr
, "write() failed: %s", strerror(errno
));
939 nsc
->ns_outptr
= nsc
->ns_outbuffer
;
940 nsc
->ns_outbuflen
= 0;
946 * Set various SASL protocol parameters
950 netsec_set_sasl_params(netsec_context
*nsc
, const char *service
,
951 const char *mechanism
, netsec_sasl_callback callback
,
955 sasl_callback_t
*sasl_cbs
;
958 if (!nsc
->ns_hostname
) {
959 netsec_err(errstr
, "Internal error: ns_hostname is NULL");
963 if (! sasl_initialized
) {
964 retval
= sasl_client_init(NULL
);
965 if (retval
!= SASL_OK
) {
966 netsec_err(errstr
, "SASL client initialization failed: %s",
967 sasl_errstring(retval
, NULL
, NULL
));
974 * Allocate an array of SASL callbacks for this connection.
975 * Right now we just allocate an array of four callbacks.
978 sasl_cbs
= mh_xmalloc(sizeof(*sasl_cbs
) * 4);
980 sasl_cbs
[0].id
= SASL_CB_USER
;
981 sasl_cbs
[0].proc
= (sasl_callback_ft
) netsec_get_user
;
982 sasl_cbs
[0].context
= nsc
;
984 sasl_cbs
[1].id
= SASL_CB_AUTHNAME
;
985 sasl_cbs
[1].proc
= (sasl_callback_ft
) netsec_get_user
;
986 sasl_cbs
[1].context
= nsc
;
988 sasl_cbs
[2].id
= SASL_CB_PASS
;
989 sasl_cbs
[2].proc
= (sasl_callback_ft
) netsec_get_password
;
990 sasl_cbs
[2].context
= nsc
;
992 sasl_cbs
[3].id
= SASL_CB_LIST_END
;
993 sasl_cbs
[3].proc
= NULL
;
994 sasl_cbs
[3].context
= NULL
;
996 nsc
->sasl_cbs
= sasl_cbs
;
998 retval
= sasl_client_new(service
, nsc
->ns_hostname
, NULL
, NULL
,
999 nsc
->sasl_cbs
, 0, &nsc
->sasl_conn
);
1002 netsec_err(errstr
, "SASL new client allocation failed: %s",
1003 sasl_errstring(retval
, NULL
, NULL
));
1008 * Set up our credentials
1011 nsc
->sasl_creds
= nmh_get_credentials(nsc
->ns_hostname
, nsc
->ns_userid
);
1013 #else /* CYRUS_SASL */
1014 NMH_UNUSED(service
);
1016 #endif /* CYRUS_SASL */
1019 * According to the RFC, mechanisms can only be uppercase letter, numbers,
1020 * and a hypen or underscore. So make sure we uppercase any letters
1021 * in case the user passed in lowercase.
1026 nsc
->sasl_mech
= mh_xstrdup(mechanism
);
1028 for (p
= nsc
->sasl_mech
; *p
; p
++)
1029 if (isascii((unsigned char) *p
)) /* Leave non-ASCII lower alone. */
1030 *p
= toupper((unsigned char) *p
);
1033 nsc
->sasl_proto_cb
= callback
;
1040 * Our userid callback; return the specified username to the SASL
1041 * library when asked.
1044 int netsec_get_user(void *context
, int id
, const char **result
,
1047 netsec_context
*nsc
= (netsec_context
*) context
;
1049 if (! result
|| (id
!= SASL_CB_USER
&& id
!= SASL_CB_AUTHNAME
))
1050 return SASL_BADPARAM
;
1052 *result
= nmh_cred_get_user(nsc
->sasl_creds
);
1055 *len
= strlen(*result
);
1061 * Retrieve a password and return it to SASL
1065 netsec_get_password(sasl_conn_t
*conn
, void *context
, int id
,
1066 sasl_secret_t
**psecret
)
1068 netsec_context
*nsc
= (netsec_context
*) context
;
1069 const char *password
;
1074 if (! psecret
|| id
!= SASL_CB_PASS
)
1075 return SASL_BADPARAM
;
1077 password
= nmh_cred_get_password(nsc
->sasl_creds
);
1079 len
= strlen(password
);
1082 * sasl_secret_t includes 1 bytes for "data" already, so that leaves
1083 * us room for a terminating NUL
1086 *psecret
= (sasl_secret_t
*) malloc(sizeof(sasl_secret_t
) + len
);
1091 (*psecret
)->len
= len
;
1092 strcpy((char *) (*psecret
)->data
, password
);
1094 nsc
->sasl_secret
= *psecret
;
1098 #endif /* CYRUS_SASL */
1101 * Negotiate SASL on this connection
1105 netsec_negotiate_sasl(netsec_context
*nsc
, const char *mechlist
, char **errstr
)
1108 sasl_security_properties_t secprops
;
1109 const char *chosen_mech
;
1110 const unsigned char *saslbuf
;
1111 unsigned char *outbuf
;
1112 unsigned int saslbuflen
, outbuflen
;
1116 #ifdef OAUTH_SUPPORT
1117 unsigned char *xoauth_client_res
;
1118 size_t xoauth_client_res_len
;
1119 #endif /* OAUTH_SUPPORT */
1120 #if defined CYRUS_SASL || defined OAUTH_SUPPORT
1122 #endif /* CYRUS_SASL || OAUTH_SUPPORT */
1125 * If we've been passed a requested mechanism, check our mechanism
1126 * list from the protocol. If it's not supported, return an error.
1129 if (nsc
->sasl_mech
) {
1130 char **str
, *mlist
= getcpy(mechlist
);
1133 str
= brkstring(mlist
, " ", NULL
);
1135 for (i
= 0; str
[i
] != NULL
; i
++) {
1136 if (strcasecmp(nsc
->sasl_mech
, str
[i
]) == 0) {
1141 i
= (str
[i
] == NULL
);
1146 netsec_err(errstr
, "Chosen mechanism %s not supported by server",
1152 #ifdef OAUTH_SUPPORT
1153 if (nsc
->sasl_mech
&& strcasecmp(nsc
->sasl_mech
, "XOAUTH2") == 0) {
1155 * This should be relatively straightforward, but requires some
1156 * help from the plugin. Basically, if XOAUTH2 is a success,
1157 * the callback has to return success, but no output data. If
1158 * there is output data, it will be assumed that it is the JSON
1162 if (! nsc
->oauth_service
) {
1163 netsec_err(errstr
, "Internal error: OAuth2 service name not given");
1167 nsc
->sasl_chosen_mech
= mh_xstrdup(nsc
->sasl_mech
);
1169 if (mh_oauth_do_xoauth(nsc
->ns_userid
, nsc
->oauth_service
,
1170 &xoauth_client_res
, &xoauth_client_res_len
,
1171 nsc
->ns_snoop
? stderr
: NULL
) != OK
) {
1172 netsec_err(errstr
, "Internal error: Unable to get OAuth2 "
1177 rc
= nsc
->sasl_proto_cb(NETSEC_SASL_START
, xoauth_client_res
,
1178 xoauth_client_res_len
, NULL
, 0, errstr
);
1179 free(xoauth_client_res
);
1185 * Okay, we need to do a NETSEC_SASL_FINISH now. If we return
1186 * success, we indicate that with no output data. But if we
1187 * fail, then send a blank message and get the resulting
1191 rc
= nsc
->sasl_proto_cb(NETSEC_SASL_FINISH
, NULL
, 0, NULL
, 0, errstr
);
1195 * We're going to assume the error here is a JSON response;
1196 * we ignore it and send a blank message in response. We should
1197 * then get a failure messages with a useful error. We should
1198 * NOT get a success message at this point.
1201 nsc
->sasl_proto_cb(NETSEC_SASL_WRITE
, NULL
, 0, NULL
, 0, NULL
);
1202 rc
= nsc
->sasl_proto_cb(NETSEC_SASL_FINISH
, NULL
, 0, NULL
, 0,
1205 netsec_err(errstr
, "Unexpected success after OAuth failure!");
1211 #endif /* OAUTH_SUPPORT */
1215 * In netsec_set_sasl_params, we've already done all of our setup with
1216 * sasl_client_init() and sasl_client_new(). So time to set security
1217 * properties, call sasl_client_start(), and generate the protocol
1221 memset(&secprops
, 0, sizeof(secprops
));
1222 secprops
.maxbufsize
= SASL_MAXRECVBUF
;
1225 * If we're using TLS, do not negotiate a security layer
1230 nsc
->tls_active
? 0 :
1231 #endif /* TLS_SUPPORT */
1234 rc
= sasl_setprop(nsc
->sasl_conn
, SASL_SEC_PROPS
, &secprops
);
1236 if (rc
!= SASL_OK
) {
1237 netsec_err(errstr
, "SASL security property initialization failed: %s",
1238 sasl_errstring(rc
, NULL
, NULL
));
1243 * Start the actual protocol negotiation, and go through the
1244 * sasl_client_step() loop (after sasl_client_start, of course).
1247 rc
= sasl_client_start(nsc
->sasl_conn
,
1248 nsc
->sasl_mech
? nsc
->sasl_mech
: mechlist
, NULL
,
1249 (const char **) &saslbuf
, &saslbuflen
,
1252 if (rc
!= SASL_OK
&& rc
!= SASL_CONTINUE
) {
1253 netsec_err(errstr
, "SASL client start failed: %s",
1254 sasl_errdetail(nsc
->sasl_conn
));
1258 nsc
->sasl_chosen_mech
= getcpy(chosen_mech
);
1260 if (nsc
->sasl_proto_cb(NETSEC_SASL_START
, saslbuf
, saslbuflen
, NULL
, 0,
1265 * We've written out our first message; enter in the step loop
1268 while (rc
== SASL_CONTINUE
) {
1270 * Call our SASL callback, which will handle the details of
1271 * reading data from the network.
1274 if (nsc
->sasl_proto_cb(NETSEC_SASL_READ
, NULL
, 0, &outbuf
, &outbuflen
,
1276 nsc
->sasl_proto_cb(NETSEC_SASL_CANCEL
, NULL
, 0, NULL
, 0, NULL
);
1280 rc
= sasl_client_step(nsc
->sasl_conn
, (char *) outbuf
, outbuflen
, NULL
,
1281 (const char **) &saslbuf
, &saslbuflen
);
1285 if (rc
!= SASL_OK
&& rc
!= SASL_CONTINUE
) {
1286 netsec_err(errstr
, "SASL client negotiation failed: %s",
1287 sasl_errdetail(nsc
->sasl_conn
));
1288 nsc
->sasl_proto_cb(NETSEC_SASL_CANCEL
, NULL
, 0, NULL
, 0, NULL
);
1292 if (nsc
->sasl_proto_cb(NETSEC_SASL_WRITE
, saslbuf
, saslbuflen
,
1293 NULL
, 0, errstr
) != OK
) {
1294 nsc
->sasl_proto_cb(NETSEC_SASL_CANCEL
, NULL
, 0, NULL
, 0, NULL
);
1300 * SASL exchanges should be complete, process the final response message
1304 if (nsc
->sasl_proto_cb(NETSEC_SASL_FINISH
, NULL
, 0, NULL
, 0,
1307 * At this point we can't really send an abort since the SASL dialog
1308 * has completed, so just bubble back up the error message.
1315 * At this point, SASL should be complete. Get a few properties
1316 * from the authentication exchange.
1319 rc
= sasl_getprop(nsc
->sasl_conn
, SASL_SSF
, (const void **) &ssf
);
1321 if (rc
!= SASL_OK
) {
1322 netsec_err(errstr
, "Cannot retrieve SASL negotiated security "
1323 "strength factor: %s", sasl_errstring(rc
, NULL
, NULL
));
1327 nsc
->sasl_ssf
= *ssf
;
1329 if (nsc
->sasl_ssf
> 0) {
1330 rc
= sasl_getprop(nsc
->sasl_conn
, SASL_MAXOUTBUF
,
1331 (const void **) &outbufmax
);
1333 if (rc
!= SASL_OK
) {
1334 netsec_err(errstr
, "Cannot retrieve SASL negotiated output "
1335 "buffer size: %s", sasl_errstring(rc
, NULL
, NULL
));
1340 * If our output buffer isn't the same size as the input buffer,
1341 * reallocate it and set the new size (since we won't encode any
1342 * data larger than that).
1345 nsc
->sasl_maxbufsize
= *outbufmax
;
1347 if (nsc
->ns_outbufsize
!= nsc
->sasl_maxbufsize
) {
1348 nsc
->ns_outbufsize
= nsc
->sasl_maxbufsize
;
1349 nsc
->ns_outbuffer
= mh_xrealloc(nsc
->ns_outbuffer
,
1350 nsc
->ns_outbufsize
);
1352 * There shouldn't be any data in the buffer, but for
1353 * consistency's sake discard it.
1355 nsc
->ns_outptr
= nsc
->ns_outbuffer
;
1356 nsc
->ns_outbuflen
= 0;
1360 * Allocate a buffer to do temporary reads into, before we
1361 * call sasl_decode()
1364 nsc
->sasl_tmpbuf
= mh_xmalloc(nsc
->sasl_maxbufsize
);
1367 * Okay, this is a bit weird. Make sure that the input buffer
1368 * is at least TWICE the size of the max buffer size. That's
1369 * because if we're consuming data but want to extend the current
1370 * buffer, we want to be sure there's room for another full buffer's
1374 if (nsc
->ns_inbufsize
< nsc
->sasl_maxbufsize
* 2) {
1375 size_t offset
= nsc
->ns_inptr
- nsc
->ns_inbuffer
;
1376 nsc
->ns_inbufsize
= nsc
->sasl_maxbufsize
* 2;
1377 nsc
->ns_inbuffer
= mh_xrealloc(nsc
->ns_inbuffer
, nsc
->ns_inbufsize
);
1378 nsc
->ns_inptr
= nsc
->ns_inbuffer
+ offset
;
1381 nsc
->sasl_seclayer
= 1;
1387 * If we're at this point, then either we have NEITHER OAuth2 or
1388 * Cyrus-SASL compiled in, or have OAuth2 but didn't give the XOAUTH2
1389 * mechanism on the command line.
1392 if (! nsc
->sasl_mech
)
1393 netsec_err(errstr
, "SASL library support not available; please "
1394 "specify a SASL mechanism to use");
1396 netsec_err(errstr
, "No support for the %s SASL mechanism",
1400 #endif /* CYRUS_SASL */
1404 * Retrieve our chosen SASL mechanism
1408 netsec_get_sasl_mechanism(netsec_context
*nsc
)
1410 return nsc
->sasl_chosen_mech
;
1414 * Set an OAuth2 service name, if we support it.
1418 netsec_set_oauth_service(netsec_context
*nsc
, const char *service
)
1420 #ifdef OAUTH_SUPPORT
1421 nsc
->oauth_service
= getcpy(service
);
1423 #else /* OAUTH_SUPPORT */
1425 NMH_UNUSED(service
);
1427 #endif /* OAUTH_SUPPORT */
1431 * Initialize (and enable) TLS for this connection
1435 netsec_set_tls(netsec_context
*nsc
, int tls
, int noverify
, char **errstr
)
1440 BIO
*rbio
, *wbio
, *ssl_bio
;;
1442 if (! tls_initialized
) {
1444 SSL_load_error_strings();
1447 * Create the SSL context; this has the properties for all
1448 * SSL connections (we are only doing one), though. Make sure
1449 * we only support secure (known as of now) TLS protocols.
1452 sslctx
= SSL_CTX_new(SSLv23_client_method());
1455 netsec_err(errstr
, "Unable to initialize OpenSSL context: %s",
1456 ERR_error_string(ERR_get_error(), NULL
));
1460 SSL_CTX_set_options(sslctx
, SSL_OP_NO_SSLv2
| SSL_OP_NO_SSLv3
|
1463 if (!SSL_CTX_set_default_verify_paths(sslctx
)) {
1464 netsec_err(errstr
, "Unable to set default certificate "
1465 "verification paths: %s",
1466 ERR_error_string(ERR_get_error(), NULL
));
1473 if (nsc
->ns_readfd
== -1 || nsc
->ns_writefd
== -1) {
1474 netsec_err(errstr
, "Invalid file descriptor in netsec context");
1479 * Create the SSL structure which holds the data for a single
1483 ssl
= SSL_new(sslctx
);
1486 netsec_err(errstr
, "Unable to create SSL connection: %s",
1487 ERR_error_string(ERR_get_error(), NULL
));
1492 * Never bother us, since we are using blocking sockets.
1495 SSL_set_mode(ssl
, SSL_MODE_AUTO_RETRY
);
1498 * This is a bit weird, so pay attention.
1500 * We create a socket BIO, and bind it to our SSL connection.
1501 * That means reads and writes to the SSL connection will use our
1504 * Then we create an SSL BIO, and assign our current SSL connection
1505 * to it. This is done so our code stays simple if we want to use
1506 * any buffering BIOs (right now we do our own buffering).
1507 * So the chain looks like:
1509 * SSL BIO -> socket BIO.
1512 rbio
= BIO_new_socket(nsc
->ns_readfd
, BIO_NOCLOSE
);
1515 netsec_err(errstr
, "Unable to create a read socket BIO: %s",
1516 ERR_error_string(ERR_get_error(), NULL
));
1521 wbio
= BIO_new_socket(nsc
->ns_writefd
, BIO_NOCLOSE
);
1524 netsec_err(errstr
, "Unable to create a write socket BIO: %s",
1525 ERR_error_string(ERR_get_error(), NULL
));
1531 SSL_set_bio(ssl
, rbio
, wbio
);
1532 SSL_set_connect_state(ssl
);
1535 * If noverify is NOT set, then do certificate validation.
1536 * Turning on SSL_VERIFY_PEER will verify the certificate chain
1537 * against locally stored root certificates (the locations are
1538 * set using SSL_CTX_set_default_verify_paths()), and we put
1539 * the hostname in the X509 verification parameters so the OpenSSL
1540 * code will verify that the hostname appears in the server
1545 #ifdef HAVE_X509_VERIFY_PARAM_SET1_HOST
1546 X509_VERIFY_PARAM
*param
;
1547 #endif /* HAVE_X509_VERIFY_PARAM_SET1_HOST */
1549 SSL_set_verify(ssl
, SSL_VERIFY_PEER
, NULL
);
1550 if (! nsc
->ns_hostname
) {
1551 netsec_err(errstr
, "Internal error: hostname not set and "
1552 "certification verification enabled");
1557 #ifdef HAVE_X509_VERIFY_PARAM_SET1_HOST
1558 param
= SSL_get0_param(ssl
);
1560 if (! X509_VERIFY_PARAM_set1_host(param
, nsc
->ns_hostname
, 0)) {
1561 netsec_err(errstr
, "Unable to add hostname %s to cert "
1562 "verification parameters: %s", nsc
->ns_hostname
,
1563 ERR_error_string(ERR_get_error(), NULL
));
1567 #endif /* HAVE_X509_VERIFY_PARAM_SET1_HOST */
1570 ssl_bio
= BIO_new(BIO_f_ssl());
1573 netsec_err(errstr
, "Unable to create a SSL BIO: %s",
1574 ERR_error_string(ERR_get_error(), NULL
));
1579 BIO_set_ssl(ssl_bio
, ssl
, BIO_CLOSE
);
1580 nsc
->ssl_io
= ssl_bio
;
1584 BIO_free_all(nsc
->ssl_io
);
1587 #else /* TLS_SUPPORT */
1589 NMH_UNUSED(noverify
);
1592 netsec_err(errstr
, "TLS is not supported");
1595 #endif /* TLS_SUPPORT */
1601 * Start TLS negotiation on this connection
1605 netsec_negotiate_tls(netsec_context
*nsc
, char **errstr
)
1608 if (! nsc
->ssl_io
) {
1609 netsec_err(errstr
, "TLS has not been configured for this connection");
1613 if (BIO_do_handshake(nsc
->ssl_io
) < 1) {
1614 unsigned long errcode
= ERR_get_error();
1617 * Print a more detailed message if it was certificate verification
1621 if (ERR_GET_LIB(errcode
) == ERR_LIB_SSL
&&
1622 ERR_GET_REASON(errcode
) == SSL_R_CERTIFICATE_VERIFY_FAILED
) {
1625 if (BIO_get_ssl(nsc
->ssl_io
, &ssl
) < 1) {
1626 netsec_err(errstr
, "Certificate verification failed, but "
1627 "cannot retrieve SSL handle: %s",
1628 ERR_error_string(ERR_get_error(), NULL
));
1630 netsec_err(errstr
, "Server certificate verification failed: %s",
1631 X509_verify_cert_error_string(
1632 SSL_get_verify_result(ssl
)));
1635 netsec_err(errstr
, "TLS negotiation failed: %s",
1636 ERR_error_string(ERR_get_error(), NULL
));
1640 * Because negotiation failed, shut down TLS so we don't get any
1641 * garbage on the connection. Because of weirdness with SSL_shutdown,
1642 * we end up calling it twice: once explicitly, once as part of
1646 BIO_ssl_shutdown(nsc
->ssl_io
);
1647 BIO_free_all(nsc
->ssl_io
);
1653 if (nsc
->ns_snoop
) {
1656 if (BIO_get_ssl(nsc
->ssl_io
, &ssl
) < 1) {
1657 fprintf(stderr
, "WARNING: cannot determine SSL ciphers\n");
1659 const SSL_CIPHER
*cipher
= SSL_get_current_cipher(ssl
);
1660 fprintf(stderr
, "TLS negotiation successful: %s(%d) %s\n",
1661 SSL_CIPHER_get_name(cipher
),
1662 SSL_CIPHER_get_bits(cipher
, NULL
),
1663 SSL_CIPHER_get_version(cipher
));
1664 SSL_SESSION_print_fp(stderr
, SSL_get_session(ssl
));
1668 nsc
->tls_active
= 1;
1671 #else /* TLS_SUPPORT */
1673 netsec_err(errstr
, "TLS not supported");
1676 #endif /* TLS_SUPPORT */
1680 * Generate an (allocated) error string
1684 netsec_err(char **errstr
, const char *fmt
, ...)
1688 char *errbuf
= NULL
;
1695 errbufsize
= rc
+ 1;
1696 errbuf
= mh_xrealloc(errbuf
, errbufsize
);
1698 rc
= vsnprintf(errbuf
, errbufsize
, fmt
, ap
);
1700 } while (rc
>= (int) errbufsize
);