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