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