]> diplodocus.org Git - nmh/blob - sbr/netsec.c
Replaced use of GNU sed extension.
[nmh] / sbr / netsec.c
1
2 /*
3 * netsec.c -- Network security routines for handling protocols that
4 * require SASL and/or TLS.
5 *
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.
9 */
10
11 #include <h/mh.h>
12 #include <h/utils.h>
13 #include <h/netsec.h>
14 #include <h/oauth.h>
15 #include <stdarg.h>
16 #include <sys/select.h>
17
18 #ifdef CYRUS_SASL
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 */
28
29 static int netsec_get_user(void *context, int id, const char **result,
30 unsigned int *len);
31 static int netsec_get_password(sasl_conn_t *conn, void *context, int id,
32 sasl_secret_t **psecret);
33
34 static int sasl_initialized = 0;
35
36 #define SASL_MAXRECVBUF 65536
37 #endif /* CYRUS_SASL */
38
39 #ifdef TLS_SUPPORT
40 #include <openssl/ssl.h>
41 #include <openssl/err.h>
42
43 static int tls_initialized = 0;
44 static SSL_CTX *sslctx = NULL; /* SSL Context */
45
46 #endif /* TLS_SUPPORT */
47
48 /* I'm going to hardcode this for now; maybe make it adjustable later? */
49 #define NETSEC_BUFSIZE 65536
50
51 /*
52 * Our context structure, which holds all of the relevant information
53 * about a connection.
54 */
55
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 unsigned char *ns_inbuffer; /* Our read input buffer */
66 unsigned char *ns_inptr; /* Our read buffer input pointer */
67 unsigned int ns_inbuflen; /* Length of data in input buffer */
68 unsigned int ns_inbufsize; /* Size of input buffer */
69 unsigned char *ns_outbuffer;/* Output buffer */
70 unsigned char *ns_outptr; /* Output buffer pointer */
71 unsigned int ns_outbuflen; /* Output buffer data length */
72 unsigned int ns_outbufsize; /* Output buffer size */
73 char *sasl_mech; /* User-requested mechanism */
74 char *sasl_chosen_mech; /* Mechanism chosen by SASL */
75 netsec_sasl_callback sasl_proto_cb; /* SASL callback we use */
76 #ifdef OAUTH_SUPPORT
77 char *oauth_service; /* OAuth2 service name */
78 #endif /* OAUTH_SUPPORT */
79 #ifdef CYRUS_SASL
80 char *sasl_hostname; /* Hostname we've connected to */
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 */
90 #ifdef TLS_SUPPORT
91 BIO *ssl_io; /* BIO used for connection I/O */
92 int tls_active; /* If true, TLS is running */
93 #endif /* TLS_SUPPORT */
94 };
95
96 /*
97 * Function to read data from the actual network socket
98 */
99
100 static int netsec_fillread(netsec_context *ns_context, char **errstr);
101
102 /*
103 * Code to check the ASCII content of a byte array.
104 */
105
106 static int checkascii(const unsigned char *byte, size_t len);
107
108 /*
109 * How this code works, in general.
110 *
111 * _If_ we are using no encryption or SASL encryption, then we buffer the
112 * network data through ns_inbuffer and ns_outbuffer. That should be
113 * relatively self-explanatory.
114 *
115 * If we are using SSL for encryption, then use a buffering BIO for output
116 * (that just easier). Still do buffering for reads; when we need more
117 * data we call the BIO_read() function to fill our local buffer.
118 *
119 * For SASL, we make use of (for now) the Cyrus-SASL library. For some
120 * mechanisms, we implement those mechanisms directly since the Cyrus SASL
121 * library doesn't support them (like OAuth).
122 */
123
124 /*
125 * Allocate and initialize our security context
126 */
127
128 netsec_context *
129 netsec_init(void)
130 {
131 netsec_context *nsc = mh_xmalloc(sizeof(*nsc));
132
133 nsc->ns_readfd = -1;
134 nsc->ns_writefd = -1;
135 nsc->ns_snoop = 0;
136 nsc->ns_snoop_noend = 0;
137 nsc->ns_snoop_cb = NULL;
138 nsc->ns_snoop_context = NULL;
139 nsc->ns_userid = NULL;
140 nsc->ns_timeout = 60; /* Our default */
141 nsc->ns_inbufsize = NETSEC_BUFSIZE;
142 nsc->ns_inbuffer = mh_xmalloc(nsc->ns_inbufsize);
143 nsc->ns_inptr = nsc->ns_inbuffer;
144 nsc->ns_inbuflen = 0;
145 nsc->ns_outbufsize = NETSEC_BUFSIZE;
146 nsc->ns_outbuffer = mh_xmalloc(nsc->ns_outbufsize);
147 nsc->ns_outptr = nsc->ns_outbuffer;
148 nsc->ns_outbuflen = 0;
149 nsc->sasl_mech = NULL;
150 nsc->sasl_chosen_mech = NULL;
151 nsc->sasl_proto_cb = NULL;
152 #ifdef OAUTH_SUPPORT
153 nsc->oauth_service = NULL;
154 #endif /* OAUTH_SUPPORT */
155 #ifdef CYRUS_SASL
156 nsc->sasl_conn = NULL;
157 nsc->sasl_hostname = NULL;
158 nsc->sasl_cbs = NULL;
159 nsc->sasl_creds = NULL;
160 nsc->sasl_secret = NULL;
161 nsc->sasl_ssf = 0;
162 nsc->sasl_seclayer = 0;
163 nsc->sasl_tmpbuf = NULL;
164 nsc->sasl_maxbufsize = 0;
165 #endif /* CYRUS_SASL */
166 #ifdef TLS_SUPPORT
167 nsc->ssl_io = NULL;
168 nsc->tls_active = 0;
169 #endif /* TLS_SUPPORT */
170 return nsc;
171 }
172
173 /*
174 * Shutdown the connection completely and free all resources.
175 * The connection is only closed if the flag is given.
176 */
177
178 void
179 netsec_shutdown(netsec_context *nsc, int closeflag)
180 {
181 if (nsc->ns_userid)
182 free(nsc->ns_userid);
183 if (nsc->ns_inbuffer)
184 free(nsc->ns_inbuffer);
185 if (nsc->ns_outbuffer)
186 free(nsc->ns_outbuffer);
187 if (nsc->sasl_mech)
188 free(nsc->sasl_mech);
189 if (nsc->sasl_chosen_mech)
190 free(nsc->sasl_chosen_mech);
191 #ifdef OAUTH_SERVICE
192 if (nsc->oauth_service)
193 free(nsc->oauth_service);
194 #endif /* OAUTH_SERVICE */
195 #ifdef CYRUS_SASL
196 if (nsc->sasl_conn)
197 sasl_dispose(&nsc->sasl_conn);
198 if (nsc->sasl_hostname)
199 free(nsc->sasl_hostname);
200 if (nsc->sasl_cbs)
201 free(nsc->sasl_cbs);
202 if (nsc->sasl_creds) {
203 if (nsc->sasl_creds->password)
204 memset(nsc->sasl_creds->password, 0,
205 strlen(nsc->sasl_creds->password));
206 free(nsc->sasl_creds);
207 }
208 if (nsc->sasl_secret) {
209 if (nsc->sasl_secret->len > 0) {
210 memset(nsc->sasl_secret->data, 0, nsc->sasl_secret->len);
211 }
212 free(nsc->sasl_secret);
213 }
214 if (nsc->sasl_tmpbuf)
215 free(nsc->sasl_tmpbuf);
216 #endif /* CYRUS_SASL */
217 #ifdef TLS_SUPPORT
218 if (nsc->ssl_io)
219 /*
220 * I checked; BIO_free_all() will cause SSL_shutdown to be called
221 * on the SSL object in the chain.
222 */
223 BIO_free_all(nsc->ssl_io);
224 #endif /* TLS_SUPPORT */
225
226 if (closeflag) {
227 if (nsc->ns_readfd != -1)
228 close(nsc->ns_readfd);
229 if (nsc->ns_writefd != -1 && nsc->ns_writefd != nsc->ns_readfd)
230 close(nsc->ns_writefd);
231 }
232
233 free(nsc);
234 }
235
236 /*
237 * Set the file descriptor for our context
238 */
239
240 void
241 netsec_set_fd(netsec_context *nsc, int readfd, int writefd)
242 {
243 nsc->ns_readfd = readfd;
244 nsc->ns_writefd = writefd;
245 }
246
247 /*
248 * Set the userid used for authentication for this context
249 */
250
251 void
252 netsec_set_userid(netsec_context *nsc, const char *userid)
253 {
254 nsc->ns_userid = getcpy(userid);
255 }
256
257 /*
258 * Get the snoop flag for this connection
259 */
260
261 int
262 netsec_get_snoop(netsec_context *nsc)
263 {
264 return nsc->ns_snoop;
265 }
266
267 /*
268 * Set the snoop flag for this connection
269 */
270
271 void
272 netsec_set_snoop(netsec_context *nsc, int snoop)
273 {
274 nsc->ns_snoop = snoop;
275 }
276
277 /*
278 * Set the snoop callback for this connection.
279 */
280
281 void netsec_set_snoop_callback(netsec_context *nsc,
282 netsec_snoop_callback callback, void *context)
283 {
284 nsc->ns_snoop_cb = callback;
285 nsc->ns_snoop_context = context;
286 }
287
288 /*
289 * A base64-decoding snoop callback
290 */
291
292 void
293 netsec_b64_snoop_decoder(netsec_context *nsc, const char *string, size_t len,
294 void *context)
295 {
296 unsigned char *decoded;
297 size_t decodedlen;
298 int offset;
299 NMH_UNUSED(nsc);
300
301 offset = context ? *((int *) context) : 0;
302
303 if (offset > 0) {
304 /*
305 * Output non-base64 data first.
306 */
307 fprintf(stderr, "%.*s", offset, string);
308 string += offset;
309 len -= offset;
310 }
311
312 if (decodeBase64(string, &decoded, &decodedlen, 1, NULL) == OK) {
313 /*
314 * Some mechanisms preoduce large binary tokens, which aren't really
315 * readable. So let's do a simple heuristic. If the token is greater
316 * than 100 characters _and_ the first 100 bytes are more than 50%
317 * non-ASCII, then don't print the decoded buffer, just the
318 * base64 text.
319 */
320 if (decodedlen > 100 && !checkascii(decoded, 100)) {
321 fprintf(stderr, "%.*s\n", (int) len, string);
322 } else {
323 char *hexified;
324 hexify(decoded, decodedlen, &hexified);
325 fprintf(stderr, "b64<%s>\n", hexified);
326 free(hexified);
327 }
328 free(decoded);
329 } else {
330 fprintf(stderr, "%.*s\n", (int) len, string);
331 }
332 }
333
334 /*
335 * If the ASCII content is > 50%, return 1
336 */
337
338 static int
339 checkascii(const unsigned char *bytes, size_t len)
340 {
341 size_t count = 0, half = len / 2;
342
343 while (len-- > 0) {
344 if (isascii(*bytes) && isprint(*bytes) && ++count > half)
345 return 1;
346 bytes++;
347 /* No chance by this point */
348 if (count + len < half)
349 return 0;
350 }
351
352 return 0;
353 }
354
355 /*
356 * Set the read timeout for this connection
357 */
358
359 void
360 netsec_set_timeout(netsec_context *nsc, int timeout)
361 {
362 nsc->ns_timeout = timeout;
363 }
364
365 /*
366 * Read data from the network. Basically, return anything in our buffer,
367 * otherwise fill from the network.
368 */
369
370 ssize_t
371 netsec_read(netsec_context *nsc, void *buffer, size_t size, char **errstr)
372 {
373 int retlen;
374
375 /*
376 * If our buffer is empty, then we should fill it now
377 */
378
379 if (nsc->ns_inbuflen == 0) {
380 if (netsec_fillread(nsc, errstr) != OK)
381 return NOTOK;
382 }
383
384 /*
385 * netsec_fillread only returns if the buffer is full, so we can
386 * assume here that this has something in it.
387 */
388
389 retlen = size > nsc->ns_inbuflen ? nsc->ns_inbuflen : size;
390
391 memcpy(buffer, nsc->ns_inptr, retlen);
392
393 if (retlen == (int) nsc->ns_inbuflen) {
394 /*
395 * We've emptied our buffer, so reset everything.
396 */
397 nsc->ns_inptr = nsc->ns_inbuffer;
398 nsc->ns_inbuflen = 0;
399 } else {
400 nsc->ns_inptr += size;
401 nsc->ns_inbuflen -= size;
402 }
403
404 return OK;
405 }
406
407 /*
408 * Get a "line" (CR/LF) terminated from the network.
409 *
410 * Okay, we play some games here, so pay attention:
411 *
412 * - Unlike every other function, we return a pointer to the
413 * existing buffer. This pointer is valid until you call another
414 * read function again.
415 * - We NUL-terminate the buffer right at the end, before the CR-LF terminator.
416 * - Technically we look for a LF; if we find a CR right before it, then
417 * we back up one.
418 * - If your data may contain embedded NULs, this won't work. You should
419 * be using netsec_read() in that case.
420 */
421
422 char *
423 netsec_readline(netsec_context *nsc, size_t *len, char **errstr)
424 {
425 unsigned char *ptr = nsc->ns_inptr;
426 size_t count = 0, offset;
427
428 retry:
429 /*
430 * Search through our existing buffer for a LF
431 */
432
433 while (count < nsc->ns_inbuflen) {
434 count++;
435 if (*ptr++ == '\n') {
436 char *sptr = (char *) nsc->ns_inptr;
437 if (count > 1 && *(ptr - 2) == '\r')
438 ptr--;
439 *--ptr = '\0';
440 if (len)
441 *len = ptr - nsc->ns_inptr;
442 nsc->ns_inptr += count;
443 nsc->ns_inbuflen -= count;
444 if (nsc->ns_snoop) {
445 #ifdef CYRUS_SASL
446 if (nsc->sasl_seclayer)
447 fprintf(stderr, "(sasl-decrypted) ");
448 #endif /* CYRUS_SASL */
449 #ifdef TLS_SUPPORT
450 if (nsc->tls_active)
451 fprintf(stderr, "(tls-decrypted) ");
452 #endif /* TLS_SUPPORT */
453 fprintf(stderr, "<= ");
454 if (nsc->ns_snoop_cb)
455 nsc->ns_snoop_cb(nsc, sptr, strlen(sptr),
456 nsc->ns_snoop_context);
457 else
458 fprintf(stderr, "%s\n", sptr);
459 }
460 return sptr;
461 }
462 }
463
464 /*
465 * Hm, we didn't find a \n. If we've already searched half of the input
466 * buffer, return an error.
467 */
468
469 if (count >= nsc->ns_inbufsize / 2) {
470 netsec_err(errstr, "Unable to find a line terminator after %d bytes",
471 count);
472 return NULL;
473 }
474
475 /*
476 * Okay, get some more network data. This may move inptr, so regenerate
477 * our ptr value;
478 */
479
480 offset = ptr - nsc->ns_inptr;
481
482 if (netsec_fillread(nsc, errstr) != OK)
483 return NULL;
484
485 ptr = nsc->ns_inptr + offset;
486
487 goto retry;
488
489 return NULL; /* Should never reach this */
490 }
491
492 /*
493 * Fill our read buffer with some data from the network.
494 */
495
496 static int
497 netsec_fillread(netsec_context *nsc, char **errstr)
498 {
499 unsigned char *end;
500 char *readbuf;
501 size_t readbufsize, remaining, startoffset;
502 int rc;
503
504 /*
505 * If inbuflen is zero, that means the buffer has been emptied
506 * completely. In that case move inptr back to the start.
507 */
508
509 if (nsc->ns_inbuflen == 0) {
510 nsc->ns_inptr = nsc->ns_inbuffer;
511 }
512
513 #ifdef CYRUS_SASL
514 retry:
515 #endif /* CYRUS_SASL */
516 /*
517 * If we are using TLS and there's anything pending, then skip the
518 * select call
519 */
520 #ifdef TLS_SUPPORT
521 if (!nsc->tls_active || BIO_pending(nsc->ssl_io) == 0)
522 #endif /* TLS_SUPPORT */
523 {
524 struct timeval tv;
525 fd_set rfds;
526
527 FD_ZERO(&rfds);
528 FD_SET(nsc->ns_readfd, &rfds);
529
530 tv.tv_sec = nsc->ns_timeout;
531 tv.tv_usec = 0;
532
533 rc = select(nsc->ns_readfd + 1, &rfds, NULL, NULL, &tv);
534
535 if (rc == -1) {
536 netsec_err(errstr, "select() while reading failed: %s",
537 strerror(errno));
538 return NOTOK;
539 }
540
541 if (rc == 0) {
542 netsec_err(errstr, "read() timed out after %d seconds",
543 nsc->ns_timeout);
544 return NOTOK;
545 }
546
547 /*
548 * At this point, we know that rc is 1, so there's not even any
549 * point to check to see if our descriptor is set in rfds.
550 */
551 }
552
553 startoffset = nsc->ns_inptr - nsc->ns_inbuffer;
554 remaining = nsc->ns_inbufsize - (startoffset + nsc->ns_inbuflen);
555 end = nsc->ns_inptr + nsc->ns_inbuflen;
556
557 /*
558 * If we are using TLS, then just read via the BIO. But we still
559 * use our local buffer.
560 */
561 #ifdef TLS_SUPPORT
562 if (nsc->tls_active) {
563 rc = BIO_read(nsc->ssl_io, end, remaining);
564 if (rc == 0) {
565 /*
566 * Either EOF, or possibly an error. Either way, it was probably
567 * unexpected, so treat as error.
568 */
569 netsec_err(errstr, "TLS peer aborted connection");
570 return NOTOK;
571 } else if (rc < 0) {
572 /* Definitely an error */
573 netsec_err(errstr, "Read on TLS connection failed: %s",
574 ERR_error_string(ERR_get_error(), NULL));
575 return NOTOK;
576 }
577
578 nsc->ns_inbuflen += rc;
579
580 return OK;
581 }
582 #endif /* TLS_SUPPORT */
583
584 /*
585 * Okay, time to read some data. Either we're just doing it straight
586 * or we're passing it through sasl_decode() first.
587 */
588
589 #ifdef CYRUS_SASL
590 if (nsc->sasl_seclayer) {
591 readbuf = nsc->sasl_tmpbuf;
592 readbufsize = nsc->sasl_maxbufsize;
593 } else
594 #endif /* CYRUS_SASL */
595 {
596 readbuf = (char *) end;
597 readbufsize = remaining;
598 }
599
600 /*
601 * At this point, we should have active data on the connection (see
602 * select() above) so this read SHOULDN'T block. Hopefully.
603 */
604
605 rc = read(nsc->ns_readfd, readbuf, readbufsize);
606
607 if (rc == 0) {
608 netsec_err(errstr, "Received EOF on network read");
609 return NOTOK;
610 }
611
612 if (rc < 0) {
613 netsec_err(errstr, "Network read failed: %s", strerror(errno));
614 return NOTOK;
615 }
616
617 /*
618 * Okay, so we've had a successful read. If we are doing SASL security
619 * layers, pass this through sasl_decode(). sasl_decode() can return
620 * 0 bytes decoded; if that happens, jump back to the beginning. Otherwise
621 * we can just update our length pointer.
622 */
623
624 #ifdef CYRUS_SASL
625 if (nsc->sasl_seclayer) {
626 const char *tmpout;
627 unsigned int tmpoutlen;
628
629 rc = sasl_decode(nsc->sasl_conn, nsc->sasl_tmpbuf, rc,
630 &tmpout, &tmpoutlen);
631
632 if (rc != SASL_OK) {
633 netsec_err(errstr, "Unable to decode SASL network data: %s",
634 sasl_errdetail(nsc->sasl_conn));
635 return NOTOK;
636 }
637
638 if (tmpoutlen == 0)
639 goto retry;
640
641 /*
642 * Just in case ...
643 */
644
645 if (tmpoutlen > remaining) {
646 netsec_err(errstr, "Internal error: SASL decode buffer overflow!");
647 return NOTOK;
648 }
649
650 memcpy(end, tmpout, tmpoutlen);
651
652 nsc->ns_inbuflen += tmpoutlen;
653 } else
654 #endif /* CYRUS_SASL */
655 nsc->ns_inbuflen += rc;
656
657 /*
658 * If we're past the halfway point in our read buffers, shuffle everything
659 * back to the beginning.
660 */
661
662 if (startoffset > nsc->ns_inbufsize / 2) {
663 memmove(nsc->ns_inbuffer, nsc->ns_inptr, nsc->ns_inbuflen);
664 nsc->ns_inptr = nsc->ns_inbuffer;
665 }
666
667 return OK;
668 }
669
670 /*
671 * Write data to our network connection. Really, fill up the buffer as
672 * much as we can, and flush it out if necessary. netsec_flush() does
673 * the real work.
674 */
675
676 int
677 netsec_write(netsec_context *nsc, const void *buffer, size_t size,
678 char **errstr)
679 {
680 const unsigned char *bufptr = buffer;
681 int rc, remaining;
682
683 /* Just in case */
684
685 if (size == 0)
686 return OK;
687
688 /*
689 * Run a loop copying in data to our local buffer; when we're done with
690 * any buffer overflows then just copy any remaining data in.
691 */
692
693 while ((int) size >= (remaining = nsc->ns_outbufsize - nsc->ns_outbuflen)) {
694 memcpy(nsc->ns_outptr, bufptr, remaining);
695
696 /*
697 * In theory I should increment outptr, but netsec_flush just resets
698 * it anyway.
699 */
700 nsc->ns_outbuflen = nsc->ns_outbufsize;
701
702 rc = netsec_flush(nsc, errstr);
703
704 if (rc != OK)
705 return NOTOK;
706
707 bufptr += remaining;
708 size -= remaining;
709 }
710
711 /*
712 * Copy any leftover data into the buffer.
713 */
714
715 if (size > 0) {
716 memcpy(nsc->ns_outptr, bufptr, size);
717 nsc->ns_outptr += size;
718 nsc->ns_outbuflen += size;
719 }
720
721 return OK;
722 }
723
724 /*
725 * Our network printf() routine, which really just calls netsec_vprintf().
726 */
727
728 int
729 netsec_printf(netsec_context *nsc, char **errstr, const char *format, ...)
730 {
731 va_list ap;
732 int rc;
733
734 va_start(ap, format);
735 rc = netsec_vprintf(nsc, errstr, format, ap);
736 va_end(ap);
737
738 return rc;
739 }
740
741 /*
742 * Write bytes to the network using printf()-style formatting.
743 *
744 * Again, for the most part copy stuff into our buffer to be flushed
745 * out later.
746 */
747
748 int
749 netsec_vprintf(netsec_context *nsc, char **errstr, const char *format,
750 va_list ap)
751 {
752 int rc;
753
754 /*
755 * Cheat a little. If we can fit the data into our outgoing buffer,
756 * great! If not, generate a flush and retry once.
757 */
758
759 retry:
760 rc = vsnprintf((char *) nsc->ns_outptr,
761 nsc->ns_outbufsize - nsc->ns_outbuflen, format, ap);
762
763 if (rc >= (int) (nsc->ns_outbufsize - nsc->ns_outbuflen)) {
764 /*
765 * This means we have an overflow. Note that we don't actually
766 * make use of the terminating NUL, but according to the spec
767 * vsnprintf() won't write to the last byte in the string; that's
768 * why we have to use >= in the comparison above.
769 */
770 if (nsc->ns_outbuffer == nsc->ns_outptr) {
771 /*
772 * Whoops, if the buffer pointer was the same as the start of the
773 * buffer, that means we overflowed the internal buffer.
774 * At that point, just give up.
775 */
776 netsec_err(errstr, "Internal error: wanted to printf() a total of "
777 "%d bytes, but our buffer size was only %d bytes",
778 rc, nsc->ns_outbufsize);
779 return NOTOK;
780 } else {
781 /*
782 * Generate a flush (which may be inefficient, but hopefully
783 * it isn't) and then try again.
784 */
785 if (netsec_flush(nsc, errstr) != OK)
786 return NOTOK;
787 /*
788 * After this, outbuffer should == outptr, so we shouldn't
789 * hit this next time around.
790 */
791 goto retry;
792 }
793 }
794
795 if (nsc->ns_snoop) {
796 int outlen = rc;
797 if (outlen > 0 && nsc->ns_outptr[outlen - 1] == '\n') {
798 outlen--;
799 if (outlen > 0 && nsc->ns_outptr[outlen - 1] == '\r')
800 outlen--;
801 } else {
802 nsc->ns_snoop_noend = 1;
803 }
804 if (outlen > 0 || nsc->ns_snoop_noend == 0) {
805 #ifdef CYRUS_SASL
806 if (nsc->sasl_seclayer)
807 fprintf(stderr, "(sasl-encrypted) ");
808 #endif /* CYRUS_SASL */
809 #ifdef TLS_SUPPORT
810 if (nsc->tls_active)
811 fprintf(stderr, "(tls-encrypted) ");
812 #endif /* TLS_SUPPORT */
813 fprintf(stderr, "=> ");
814 if (nsc->ns_snoop_cb)
815 nsc->ns_snoop_cb(nsc, (char *) nsc->ns_outptr, outlen,
816 nsc->ns_snoop_context);
817 else
818 fprintf(stderr, "%.*s\n", outlen, nsc->ns_outptr);
819 } else {
820 nsc->ns_snoop_noend = 0;
821 }
822 }
823
824 nsc->ns_outptr += rc;
825 nsc->ns_outbuflen += rc;
826
827 return OK;
828 }
829
830 /*
831 * Flush out any buffered data in our output buffers. This routine is
832 * actually where the real network writes take place.
833 */
834
835 int
836 netsec_flush(netsec_context *nsc, char **errstr)
837 {
838 const char *netoutbuf = (const char *) nsc->ns_outbuffer;
839 unsigned int netoutlen = nsc->ns_outbuflen;
840 int rc;
841
842 /*
843 * Small optimization
844 */
845
846 if (netoutlen == 0)
847 return OK;
848
849 /*
850 * If SASL security layers are in effect, run the data through
851 * sasl_encode() first.
852 */
853 #ifdef CYRUS_SASL
854 if (nsc->sasl_seclayer) {
855 rc = sasl_encode(nsc->sasl_conn, (const char *) nsc->ns_outbuffer,
856 nsc->ns_outbuflen, &netoutbuf, &netoutlen);
857
858 if (rc != SASL_OK) {
859 netsec_err(errstr, "SASL data encoding failed: %s",
860 sasl_errdetail(nsc->sasl_conn));
861 return NOTOK;
862 }
863
864 }
865 #endif /* CYRUS_SASL */
866
867 /*
868 * If TLS is active, then use those functions to write out the
869 * data.
870 */
871 #ifdef TLS_SUPPORT
872 if (nsc->tls_active) {
873 if (BIO_write(nsc->ssl_io, netoutbuf, netoutlen) <= 0) {
874 netsec_err(errstr, "Error writing to TLS connection: %s",
875 ERR_error_string(ERR_get_error(), NULL));
876 return NOTOK;
877 }
878 } else
879 #endif /* TLS_SUPPORT */
880 {
881 rc = write(nsc->ns_writefd, netoutbuf, netoutlen);
882
883 if (rc < 0) {
884 netsec_err(errstr, "write() failed: %s", strerror(errno));
885 return NOTOK;
886 }
887 }
888
889 nsc->ns_outptr = nsc->ns_outbuffer;
890 nsc->ns_outbuflen = 0;
891
892 return OK;
893 }
894
895 /*
896 * Set various SASL protocol parameters
897 */
898
899 int
900 netsec_set_sasl_params(netsec_context *nsc, const char *hostname,
901 const char *service, const char *mechanism,
902 netsec_sasl_callback callback, char **errstr)
903 {
904 #ifdef CYRUS_SASL
905 sasl_callback_t *sasl_cbs;
906 int retval;
907
908 if (! sasl_initialized) {
909 retval = sasl_client_init(NULL);
910 if (retval != SASL_OK) {
911 netsec_err(errstr, "SASL client initialization failed: %s",
912 sasl_errstring(retval, NULL, NULL));
913 return NOTOK;
914 }
915 sasl_initialized++;
916 }
917
918 /*
919 * Allocate an array of SASL callbacks for this connection.
920 * Right now we just allocate an array of four callbacks.
921 */
922
923 sasl_cbs = mh_xmalloc(sizeof(*sasl_cbs) * 4);
924
925 sasl_cbs[0].id = SASL_CB_USER;
926 sasl_cbs[0].proc = (sasl_callback_ft) netsec_get_user;
927 sasl_cbs[0].context = nsc;
928
929 sasl_cbs[1].id = SASL_CB_AUTHNAME;
930 sasl_cbs[1].proc = (sasl_callback_ft) netsec_get_user;
931 sasl_cbs[1].context = nsc;
932
933 sasl_cbs[2].id = SASL_CB_PASS;
934 sasl_cbs[2].proc = (sasl_callback_ft) netsec_get_password;
935 sasl_cbs[2].context = nsc;
936
937 sasl_cbs[3].id = SASL_CB_LIST_END;
938 sasl_cbs[3].proc = NULL;
939 sasl_cbs[3].context = NULL;
940
941 nsc->sasl_cbs = sasl_cbs;
942
943 retval = sasl_client_new(service, hostname, NULL, NULL, nsc->sasl_cbs, 0,
944 &nsc->sasl_conn);
945
946 if (retval) {
947 netsec_err(errstr, "SASL new client allocation failed: %s",
948 sasl_errstring(retval, NULL, NULL));
949 return NOTOK;
950 }
951
952 nsc->sasl_hostname = getcpy(hostname);
953 #else /* CYRUS_SASL */
954 NMH_UNUSED(hostname);
955 NMH_UNUSED(service);
956 NMH_UNUSED(errstr);
957 #endif /* CYRUS_SASL */
958
959 /*
960 * According to the RFC, mechanisms can only be uppercase letter, numbers,
961 * and a hypen or underscore. So make sure we uppercase any letters
962 * in case the user passed in lowercase.
963 */
964
965 if (mechanism) {
966 char *p;
967 nsc->sasl_mech = getcpy(mechanism);
968
969 for (p = nsc->sasl_mech; *p; p++)
970 if (isascii((unsigned char) *p)) /* Just in case */
971 *p = toupper((unsigned char) *p);
972 }
973
974 nsc->sasl_proto_cb = callback;
975
976 return OK;
977 }
978
979 #ifdef CYRUS_SASL
980 /*
981 * Our userid callback; return the specified username to the SASL
982 * library when asked.
983 */
984
985 int netsec_get_user(void *context, int id, const char **result,
986 unsigned int *len)
987 {
988 netsec_context *nsc = (netsec_context *) context;
989
990 if (! result || (id != SASL_CB_USER && id != SASL_CB_AUTHNAME))
991 return SASL_BADPARAM;
992
993 if (nsc->ns_userid == NULL) {
994 /*
995 * Pass the 1 third argument to nmh_get_credentials() so that
996 * a defauly user if the -user switch wasn't supplied, and so
997 * that a default password will be supplied. That's used when
998 * those values really don't matter, and only with legacy/.netrc,
999 * i.e., with a credentials profile entry.
1000 */
1001
1002 if (nsc->sasl_creds == NULL) {
1003 nsc->sasl_creds = mh_xmalloc(sizeof(*nsc->sasl_creds));
1004 nsc->sasl_creds->user = NULL;
1005 nsc->sasl_creds->password = NULL;
1006 }
1007
1008 if (nmh_get_credentials(nsc->sasl_hostname, nsc->ns_userid, 1,
1009 nsc->sasl_creds) != OK)
1010 return SASL_BADPARAM;
1011
1012 if (nsc->ns_userid != nsc->sasl_creds->user) {
1013 if (nsc->ns_userid)
1014 free(nsc->ns_userid);
1015 nsc->ns_userid = getcpy(nsc->sasl_creds->user);
1016 }
1017 }
1018
1019 *result = nsc->ns_userid;
1020 if (len)
1021 *len = strlen(nsc->ns_userid);
1022
1023 return SASL_OK;
1024 }
1025
1026 /*
1027 * Retrieve a password and return it to SASL
1028 */
1029
1030 static int
1031 netsec_get_password(sasl_conn_t *conn, void *context, int id,
1032 sasl_secret_t **psecret)
1033 {
1034 netsec_context *nsc = (netsec_context *) context;
1035 int len;
1036
1037 NMH_UNUSED(conn);
1038
1039 if (! psecret || id != SASL_CB_PASS)
1040 return SASL_BADPARAM;
1041
1042 if (nsc->sasl_creds == NULL) {
1043 nsc->sasl_creds = mh_xmalloc(sizeof(*nsc->sasl_creds));
1044 nsc->sasl_creds->user = NULL;
1045 nsc->sasl_creds->password = NULL;
1046 }
1047
1048 if (nsc->sasl_creds->password == NULL) {
1049 /*
1050 * Pass the 0 third argument to nmh_get_credentials() so
1051 * that the default password isn't used. With legacy/.netrc
1052 * credentials support, we'll only get here if the -user
1053 * switch to send(1)/post(8) wasn't used.
1054 */
1055
1056 if (nmh_get_credentials(nsc->sasl_hostname, nsc->ns_userid, 0,
1057 nsc->sasl_creds) != OK) {
1058 return SASL_BADPARAM;
1059 }
1060 }
1061
1062 len = strlen(nsc->sasl_creds->password);
1063
1064 /*
1065 * sasl_secret_t includes 1 bytes for "data" already, so that leaves
1066 * us room for a terminating NUL
1067 */
1068
1069 *psecret = (sasl_secret_t *) malloc(sizeof(sasl_secret_t) + len);
1070
1071 if (! *psecret)
1072 return SASL_NOMEM;
1073
1074 (*psecret)->len = len;
1075 strcpy((char *) (*psecret)->data, nsc->sasl_creds->password);
1076
1077 nsc->sasl_secret = *psecret;
1078
1079 return SASL_OK;
1080 }
1081 #endif /* CYRUS_SASL */
1082
1083 /*
1084 * Negotiate SASL on this connection
1085 */
1086
1087 int
1088 netsec_negotiate_sasl(netsec_context *nsc, const char *mechlist, char **errstr)
1089 {
1090 #ifdef CYRUS_SASL
1091 sasl_security_properties_t secprops;
1092 const char *chosen_mech;
1093 const unsigned char *saslbuf;
1094 unsigned char *outbuf;
1095 unsigned int saslbuflen, outbuflen;
1096 sasl_ssf_t *ssf;
1097 int *outbufmax;
1098 #endif
1099 #ifdef OAUTH_SUPPORT
1100 unsigned char *xoauth_client_res;
1101 size_t xoauth_client_res_len;
1102 #endif /* OAUTH_SUPPORT */
1103 #if defined CYRUS_SASL || defined OAUTH_SUPPORT
1104 int rc;
1105 #endif /* CYRUS_SASL || OAUTH_SUPPORT */
1106
1107 /*
1108 * If we've been passed a requested mechanism, check our mechanism
1109 * list from the protocol. If it's not supported, return an error.
1110 */
1111
1112 if (nsc->sasl_mech) {
1113 char **str, *mlist = getcpy(mechlist);
1114 int i;
1115
1116 str = brkstring(mlist, " ", NULL);
1117
1118 for (i = 0; str[i] != NULL; i++) {
1119 if (strcasecmp(nsc->sasl_mech, str[i]) == 0) {
1120 break;
1121 }
1122 }
1123
1124 i = (str[i] == NULL);
1125
1126 free(mlist);
1127
1128 if (i) {
1129 netsec_err(errstr, "Chosen mechanism %s not supported by server",
1130 nsc->sasl_mech);
1131 return NOTOK;
1132 }
1133 }
1134
1135 #ifdef OAUTH_SUPPORT
1136 if (nsc->sasl_mech && strcasecmp(nsc->sasl_mech, "XOAUTH2") == 0) {
1137 /*
1138 * This should be relatively straightforward, but requires some
1139 * help from the plugin. Basically, if XOAUTH2 is a success,
1140 * the callback has to return success, but no output data. If
1141 * there is output data, it will be assumed that it is the JSON
1142 * error message.
1143 */
1144
1145 if (! nsc->oauth_service) {
1146 netsec_err(errstr, "Internal error: OAuth2 service name not given");
1147 return NOTOK;
1148 }
1149
1150 nsc->sasl_chosen_mech = getcpy(nsc->sasl_mech);
1151
1152 if (mh_oauth_do_xoauth(nsc->ns_userid, nsc->oauth_service,
1153 &xoauth_client_res, &xoauth_client_res_len,
1154 nsc->ns_snoop ? stderr : NULL) != OK) {
1155 netsec_err(errstr, "Internal error: Unable to get OAuth2 "
1156 "bearer token");
1157 return NOTOK;
1158 }
1159
1160 rc = nsc->sasl_proto_cb(NETSEC_SASL_START, xoauth_client_res,
1161 xoauth_client_res_len, NULL, 0, errstr);
1162 free(xoauth_client_res);
1163
1164 if (rc != OK)
1165 return NOTOK;
1166
1167 /*
1168 * Okay, we need to do a NETSEC_SASL_FINISH now. If we return
1169 * success, we indicate that with no output data. But if we
1170 * fail, then send a blank message and get the resulting
1171 * error.
1172 */
1173
1174 rc = nsc->sasl_proto_cb(NETSEC_SASL_FINISH, NULL, 0, NULL, 0, errstr);
1175
1176 if (rc != OK) {
1177 /*
1178 * We're going to assume the error here is a JSON response;
1179 * we ignore it and send a blank message in response. We should
1180 * then get a failure messages with a useful error. We should
1181 * NOT get a success message at this point.
1182 */
1183 free(*errstr);
1184 nsc->sasl_proto_cb(NETSEC_SASL_WRITE, NULL, 0, NULL, 0, NULL);
1185 rc = nsc->sasl_proto_cb(NETSEC_SASL_FINISH, NULL, 0, NULL, 0,
1186 errstr);
1187 if (rc == 0) {
1188 netsec_err(errstr, "Unexpected success after OAuth failure!");
1189 }
1190 return NOTOK;
1191 }
1192 return OK;
1193 }
1194 #endif /* OAUTH_SUPPORT */
1195
1196 #ifdef CYRUS_SASL
1197 /*
1198 * In netsec_set_sasl_params, we've already done all of our setup with
1199 * sasl_client_init() and sasl_client_new(). So time to set security
1200 * properties, call sasl_client_start(), and generate the protocol
1201 * messages.
1202 */
1203
1204 memset(&secprops, 0, sizeof(secprops));
1205 secprops.maxbufsize = SASL_MAXRECVBUF;
1206
1207 /*
1208 * If we're using TLS, do not negotiate a security layer
1209 */
1210
1211 secprops.max_ssf =
1212 #ifdef TLS_SUPPORT
1213 nsc->tls_active ? 0 :
1214 #endif /* TLS_SUPPORT */
1215 UINT_MAX;
1216
1217 rc = sasl_setprop(nsc->sasl_conn, SASL_SEC_PROPS, &secprops);
1218
1219 if (rc != SASL_OK) {
1220 netsec_err(errstr, "SASL security property initialization failed: %s",
1221 sasl_errstring(rc, NULL, NULL));
1222 return NOTOK;
1223 }
1224
1225 /*
1226 * Start the actual protocol negotiation, and go through the
1227 * sasl_client_step() loop (after sasl_client_start, of course).
1228 */
1229
1230 rc = sasl_client_start(nsc->sasl_conn,
1231 nsc->sasl_mech ? nsc->sasl_mech : mechlist, NULL,
1232 (const char **) &saslbuf, &saslbuflen,
1233 &chosen_mech);
1234
1235 if (rc != SASL_OK && rc != SASL_CONTINUE) {
1236 netsec_err(errstr, "SASL client start failed: %s",
1237 sasl_errdetail(nsc->sasl_conn));
1238 return NOTOK;
1239 }
1240
1241 nsc->sasl_chosen_mech = getcpy(chosen_mech);
1242
1243 if (nsc->sasl_proto_cb(NETSEC_SASL_START, saslbuf, saslbuflen, NULL, 0,
1244 errstr) != OK)
1245 return NOTOK;
1246
1247 /*
1248 * We've written out our first message; enter in the step loop
1249 */
1250
1251 while (rc == SASL_CONTINUE) {
1252 /*
1253 * Call our SASL callback, which will handle the details of
1254 * reading data from the network.
1255 */
1256
1257 if (nsc->sasl_proto_cb(NETSEC_SASL_READ, NULL, 0, &outbuf, &outbuflen,
1258 errstr) != OK) {
1259 nsc->sasl_proto_cb(NETSEC_SASL_CANCEL, NULL, 0, NULL, 0, NULL);
1260 return NOTOK;
1261 }
1262
1263 rc = sasl_client_step(nsc->sasl_conn, (char *) outbuf, outbuflen, NULL,
1264 (const char **) &saslbuf, &saslbuflen);
1265
1266 if (outbuf)
1267 free(outbuf);
1268
1269 if (rc != SASL_OK && rc != SASL_CONTINUE) {
1270 netsec_err(errstr, "SASL client negotiation failed: %s",
1271 sasl_errdetail(nsc->sasl_conn));
1272 nsc->sasl_proto_cb(NETSEC_SASL_CANCEL, NULL, 0, NULL, 0, NULL);
1273 return NOTOK;
1274 }
1275
1276 if (nsc->sasl_proto_cb(NETSEC_SASL_WRITE, saslbuf, saslbuflen,
1277 NULL, 0, errstr) != OK) {
1278 nsc->sasl_proto_cb(NETSEC_SASL_CANCEL, NULL, 0, NULL, 0, NULL);
1279 return NOTOK;
1280 }
1281 }
1282
1283 /*
1284 * SASL exchanges should be complete, process the final response message
1285 * from the server.
1286 */
1287
1288 if (nsc->sasl_proto_cb(NETSEC_SASL_FINISH, NULL, 0, NULL, 0,
1289 errstr) != OK) {
1290 /*
1291 * At this point we can't really send an abort since the SASL dialog
1292 * has completed, so just bubble back up the error message.
1293 */
1294
1295 return NOTOK;
1296 }
1297
1298 /*
1299 * At this point, SASL should be complete. Get a few properties
1300 * from the authentication exchange.
1301 */
1302
1303 rc = sasl_getprop(nsc->sasl_conn, SASL_SSF, (const void **) &ssf);
1304
1305 if (rc != SASL_OK) {
1306 netsec_err(errstr, "Cannot retrieve SASL negotiated security "
1307 "strength factor: %s", sasl_errstring(rc, NULL, NULL));
1308 return NOTOK;
1309 }
1310
1311 nsc->sasl_ssf = *ssf;
1312
1313 if (nsc->sasl_ssf > 0) {
1314 rc = sasl_getprop(nsc->sasl_conn, SASL_MAXOUTBUF,
1315 (const void **) &outbufmax);
1316
1317 if (rc != SASL_OK) {
1318 netsec_err(errstr, "Cannot retrieve SASL negotiated output "
1319 "buffer size: %s", sasl_errstring(rc, NULL, NULL));
1320 return NOTOK;
1321 }
1322
1323 /*
1324 * If our output buffer isn't the same size as the input buffer,
1325 * reallocate it and set the new size (since we won't encode any
1326 * data larger than that).
1327 */
1328
1329 nsc->sasl_maxbufsize = *outbufmax;
1330
1331 if (nsc->ns_outbufsize != nsc->sasl_maxbufsize) {
1332 nsc->ns_outbufsize = nsc->sasl_maxbufsize;
1333 nsc->ns_outbuffer = mh_xrealloc(nsc->ns_outbuffer,
1334 nsc->ns_outbufsize);
1335 /*
1336 * There shouldn't be any data in the buffer, but for
1337 * consistency's sake discard it.
1338 */
1339 nsc->ns_outptr = nsc->ns_outbuffer;
1340 nsc->ns_outbuflen = 0;
1341 }
1342
1343 /*
1344 * Allocate a buffer to do temporary reads into, before we
1345 * call sasl_decode()
1346 */
1347
1348 nsc->sasl_tmpbuf = mh_xmalloc(nsc->sasl_maxbufsize);
1349
1350 /*
1351 * Okay, this is a bit weird. Make sure that the input buffer
1352 * is at least TWICE the size of the max buffer size. That's
1353 * because if we're consuming data but want to extend the current
1354 * buffer, we want to be sure there's room for another full buffer's
1355 * worth of data.
1356 */
1357
1358 if (nsc->ns_inbufsize < nsc->sasl_maxbufsize * 2) {
1359 size_t offset = nsc->ns_inptr - nsc->ns_inbuffer;
1360 nsc->ns_inbufsize = nsc->sasl_maxbufsize * 2;
1361 nsc->ns_inbuffer = mh_xrealloc(nsc->ns_inbuffer, nsc->ns_inbufsize);
1362 nsc->ns_inptr = nsc->ns_inbuffer + offset;
1363 }
1364
1365 nsc->sasl_seclayer = 1;
1366 }
1367
1368 return OK;
1369 #else
1370 /*
1371 * If we're at this point, then either we have NEITHER OAuth2 or
1372 * Cyrus-SASL compiled in, or have OAuth2 but didn't give the XOAUTH2
1373 * mechanism on the command line.
1374 */
1375
1376 if (! nsc->sasl_mech)
1377 netsec_err(errstr, "SASL library support not available; please "
1378 "specify a SASL mechanism to use");
1379 else
1380 netsec_err(errstr, "No support for the %s SASL mechanism",
1381 nsc->sasl_mech);
1382
1383 return NOTOK;
1384 #endif /* CYRUS_SASL */
1385 }
1386
1387 /*
1388 * Retrieve our chosen SASL mechanism
1389 */
1390
1391 char *
1392 netsec_get_sasl_mechanism(netsec_context *nsc)
1393 {
1394 return nsc->sasl_chosen_mech;
1395 }
1396
1397 /*
1398 * Set an OAuth2 service name, if we support it.
1399 */
1400
1401 int
1402 netsec_set_oauth_service(netsec_context *nsc, const char *service)
1403 {
1404 #ifdef OAUTH_SUPPORT
1405 nsc->oauth_service = getcpy(service);
1406 return OK;
1407 #else /* OAUTH_SUPPORT */
1408 NMH_UNUSED(nsc);
1409 NMH_UNUSED(service);
1410 return NOTOK;
1411 #endif /* OAUTH_SUPPORT */
1412 }
1413
1414 /*
1415 * Initialize (and enable) TLS for this connection
1416 */
1417
1418 int
1419 netsec_set_tls(netsec_context *nsc, int tls, char **errstr)
1420 {
1421 if (tls) {
1422 #ifdef TLS_SUPPORT
1423 SSL *ssl;
1424 BIO *rbio, *wbio, *ssl_bio;;
1425
1426 if (! tls_initialized) {
1427 SSL_library_init();
1428 SSL_load_error_strings();
1429
1430 /*
1431 * Create the SSL context; this has the properties for all
1432 * SSL connections (we are only doing one), though. Make sure
1433 * we only support secure (known as of now) TLS protocols.
1434 */
1435
1436 sslctx = SSL_CTX_new(SSLv23_client_method());
1437
1438 if (! sslctx) {
1439 netsec_err(errstr, "Unable to initialize OpenSSL context: %s",
1440 ERR_error_string(ERR_get_error(), NULL));
1441 return NOTOK;
1442 }
1443
1444 SSL_CTX_set_options(sslctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 |
1445 SSL_OP_NO_TLSv1);
1446
1447 tls_initialized++;
1448 }
1449
1450 if (nsc->ns_readfd == -1 || nsc->ns_writefd == -1) {
1451 netsec_err(errstr, "Invalid file descriptor in netsec context");
1452 return NOTOK;
1453 }
1454
1455 /*
1456 * Create the SSL structure which holds the data for a single
1457 * TLS connection.
1458 */
1459
1460 ssl = SSL_new(sslctx);
1461
1462 if (! ssl) {
1463 netsec_err(errstr, "Unable to create SSL connection: %s",
1464 ERR_error_string(ERR_get_error(), NULL));
1465 return NOTOK;
1466 }
1467
1468 /*
1469 * Never bother us, since we are using blocking sockets.
1470 */
1471
1472 SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY);
1473
1474 /*
1475 * This is a bit weird, so pay attention.
1476 *
1477 * We create a socket BIO, and bind it to our SSL connection.
1478 * That means reads and writes to the SSL connection will use our
1479 * supplied socket.
1480 *
1481 * Then we create an SSL BIO, and assign our current SSL connection
1482 * to it. This is done so our code stays simple if we want to use
1483 * any buffering BIOs (right now we do our own buffering).
1484 * So the chain looks like:
1485 *
1486 * SSL BIO -> socket BIO.
1487 */
1488
1489 rbio = BIO_new_socket(nsc->ns_readfd, BIO_NOCLOSE);
1490
1491 if (! rbio) {
1492 netsec_err(errstr, "Unable to create a read socket BIO: %s",
1493 ERR_error_string(ERR_get_error(), NULL));
1494 SSL_free(ssl);
1495 return NOTOK;
1496 }
1497
1498 wbio = BIO_new_socket(nsc->ns_writefd, BIO_NOCLOSE);
1499
1500 if (! wbio) {
1501 netsec_err(errstr, "Unable to create a write socket BIO: %s",
1502 ERR_error_string(ERR_get_error(), NULL));
1503 SSL_free(ssl);
1504 BIO_free(rbio);
1505 return NOTOK;
1506 }
1507
1508 SSL_set_bio(ssl, rbio, wbio);
1509 SSL_set_connect_state(ssl);
1510
1511 ssl_bio = BIO_new(BIO_f_ssl());
1512
1513 if (! ssl_bio) {
1514 netsec_err(errstr, "Unable to create a SSL BIO: %s",
1515 ERR_error_string(ERR_get_error(), NULL));
1516 SSL_free(ssl);
1517 return NOTOK;
1518 }
1519
1520 BIO_set_ssl(ssl_bio, ssl, BIO_CLOSE);
1521 nsc->ssl_io = ssl_bio;
1522
1523 return OK;
1524 } else {
1525 BIO_free_all(nsc->ssl_io);
1526 nsc->ssl_io = NULL;
1527
1528 return OK;
1529 }
1530 #else /* TLS_SUPPORT */
1531 netsec_err(errstr, "TLS is not supported");
1532
1533 return NOTOK;
1534 }
1535 #endif /* TLS_SUPPORT */
1536 }
1537
1538 /*
1539 * Start TLS negotiation on this connection
1540 */
1541
1542 int
1543 netsec_negotiate_tls(netsec_context *nsc, char **errstr)
1544 {
1545 #ifdef TLS_SUPPORT
1546 if (! nsc->ssl_io) {
1547 netsec_err(errstr, "TLS has not been configured for this connection");
1548 return NOTOK;
1549 }
1550
1551 if (BIO_do_handshake(nsc->ssl_io) < 1) {
1552 netsec_err(errstr, "TLS negotiation failed: %s",
1553 ERR_error_string(ERR_get_error(), NULL));
1554 return NOTOK;
1555 }
1556
1557 if (nsc->ns_snoop) {
1558 SSL *ssl;
1559
1560 if (BIO_get_ssl(nsc->ssl_io, &ssl) < 1) {
1561 fprintf(stderr, "WARNING: cannot determine SSL ciphers\n");
1562 } else {
1563 const SSL_CIPHER *cipher = SSL_get_current_cipher(ssl);
1564 fprintf(stderr, "TLS negotiation successful: %s(%d) %s\n",
1565 SSL_CIPHER_get_name(cipher),
1566 SSL_CIPHER_get_bits(cipher, NULL),
1567 SSL_CIPHER_get_version(cipher));
1568 }
1569 }
1570
1571 nsc->tls_active = 1;
1572
1573 return OK;
1574 #else /* TLS_SUPPORT */
1575 netsec_err(errstr, "TLS not supported");
1576
1577 return NOTOK;
1578 #endif /* TLS_SUPPORT */
1579 }
1580
1581 /*
1582 * Generate an (allocated) error string
1583 */
1584
1585 void
1586 netsec_err(char **errstr, const char *fmt, ...)
1587 {
1588 va_list ap;
1589 size_t errbufsize;
1590 char *errbuf = NULL;
1591 int rc = 127;
1592
1593 if (! errstr)
1594 return;
1595
1596 do {
1597 errbufsize = rc + 1;
1598 errbuf = mh_xrealloc(errbuf, errbufsize);
1599 va_start(ap, fmt);
1600 rc = vsnprintf(errbuf, errbufsize, fmt, ap);
1601 va_end(ap);
1602 } while (rc >= (int) errbufsize);
1603
1604 *errstr = errbuf;
1605 }