Add missing libraries to examples' Makefiles
[dockapps.git] / wmbiff / wmbiff / tlsComm.c
blobbbf3e718a148fea418512ae609d6441f7311bb3d
1 /* tlsComm.c - primitive routines to aid TLS communication
2 within wmbiff, without rewriting each mailbox access
3 scheme. These functions hide whether the underlying
4 transport is encrypted.
6 Neil Spring (nspring@cs.washington.edu) */
8 /* TODO: handle "* BYE" internally? */
9 #ifdef HAVE_CONFIG_H
10 #include <config.h>
11 #endif
13 #include <stdarg.h>
14 #include <sys/time.h>
15 #include <sys/types.h>
16 #include <unistd.h>
17 #include <stdio.h>
18 #include <errno.h>
19 #include <string.h>
20 #include <stdlib.h>
21 #include <assert.h>
22 #ifdef USE_GNUTLS
23 #include <gnutls/gnutls.h>
24 #include <gnutls/x509.h>
25 #include <sys/stat.h>
26 #endif
27 #ifdef USE_DMALLOC
28 #include <dmalloc.h>
29 #endif
31 #include "Client.h" /* debugging messages */
32 #include "tlsComm.h"
33 #include "wmbiff.h"
35 /* if non-null, set to a file for certificate verification */
36 extern const char *certificate_filename;
37 /* if set, don't fail when dealing with a bad certificate.
38 (continue to whine, though, as bad certs should be fixed) */
39 extern int SkipCertificateCheck;
40 /* gnutls: specify the priorities to use on the ciphers, key exchange methods,
41 macs and compression methods. */
42 extern const char *tls;
44 /* WARNING: implcitly uses scs to gain access to the mailbox
45 that holds the per-mailbox debug flag. */
46 #define TDM(lvl, args...) DM(scs->pc, lvl, "comm: " args)
48 /* how long to wait for the server to do its thing
49 when we issue it a command (in seconds) */
50 #define EXPECT_TIMEOUT 40
52 /* this is the per-connection state that is maintained for
53 each connection; BIG variables are for ssl (null if not
54 used). */
55 #define BUF_SIZE 1024
56 struct connection_state {
57 int sd;
58 char *name;
59 #ifdef USE_GNUTLS
60 gnutls_session_t tls_state;
61 gnutls_certificate_credentials_t xcred;
62 #else
63 /*@null@ */ void *tls_state;
64 /*@null@ */ void *xcred;
65 #endif
66 char unprocessed[BUF_SIZE];
67 Pop3 *pc; /* mailbox handle for debugging messages */
70 /* gotta do our own line buffering, sigh */
71 int getline_from_buffer(char *readbuffer, char *linebuffer,
72 int linebuflen);
73 void handle_gnutls_read_error(int readbytes, struct connection_state *scs);
75 void tlscomm_close(struct connection_state *scs)
77 TDM(DEBUG_INFO, "%s: closing.\n",
78 (scs->name != NULL) ? scs->name : "null");
80 /* not ok to call this more than once */
81 if (scs->tls_state) {
82 #ifdef USE_GNUTLS
83 /* this next line seems capable of hanging... */
84 /* gnutls_bye(scs->tls_state, GNUTLS_SHUT_RDWR); */
85 /* so we'll try just _bye'ing the WR direction, which
86 should send the alert but not wait for a response. */
87 gnutls_bye(scs->tls_state, GNUTLS_SHUT_WR);
88 gnutls_certificate_free_credentials(scs->xcred);
89 gnutls_deinit(scs->tls_state);
90 scs->xcred = NULL;
91 #endif
92 } else {
93 (void) close(scs->sd);
95 scs->sd = -1;
96 scs->tls_state = NULL;
97 scs->xcred = NULL;
98 free(scs->name);
99 scs->name = NULL;
100 free(scs);
103 /* this avoids blocking without using non-blocking i/o */
104 static int wait_for_it(int sd, int timeoutseconds)
106 fd_set readfds;
107 struct timeval tv;
108 int ready_descriptors;
109 int maxfd;
110 int xfd;
111 struct timeval time_now;
112 struct timeval time_out;
114 gettimeofday(&time_now, NULL);
115 memcpy(&time_out, &time_now, sizeof(struct timeval));
116 time_out.tv_sec += timeoutseconds;
118 xfd = x_socket();
119 maxfd = max(sd, xfd);
121 do {
122 do {
123 ProcessPendingEvents();
125 gettimeofday(&time_now, NULL);
126 tv.tv_sec = max(time_out.tv_sec - time_now.tv_sec + 1, (time_t) 0); /* sloppy, but bfd */
127 tv.tv_usec = 0;
128 /* select will return if we have X stuff or we have comm stuff on sd */
129 FD_ZERO(&readfds);
130 FD_SET(sd, &readfds);
131 // FD_SET(xfd, &readfds);
132 ready_descriptors = select(maxfd + 1, &readfds, NULL, NULL, &tv);
133 // DMA(DEBUG_INFO,
134 // "select %d/%d returned %d descriptor, %d\n",
135 // sd, timeoutseconds, ready_descriptors, FD_ISSET(sd, &readfds));
137 } while(tv.tv_sec > 0 && (!FD_ISSET(sd, &readfds) || (errno == EINTR && ready_descriptors == -1)));
139 FD_ZERO(&readfds);
140 FD_SET(sd, &readfds);
141 tv.tv_sec = 0; tv.tv_usec = 0;
142 ready_descriptors = select(sd + 1, &readfds, NULL, NULL, &tv);
144 while (ready_descriptors == -1 && errno == EINTR);
145 if (ready_descriptors == 0) {
146 DMA(DEBUG_INFO,
147 "select timed out after %d seconds on socket: %d\n",
148 timeoutseconds, sd);
149 return (0);
150 } else if (ready_descriptors == -1) {
151 DMA(DEBUG_ERROR,
152 "select failed on socket %d: %s\n", sd, strerror(errno));
153 return (0);
155 return (FD_ISSET(sd, &readfds));
158 /* exported for testing */
159 extern int
160 getline_from_buffer(char *readbuffer, char *linebuffer, int linebuflen)
162 char *p, *q;
163 int i;
164 /* find end of line (stopping if linebuflen is too small. */
165 for (p = readbuffer, i = 0;
166 *p != '\n' && *p != '\0' && i < linebuflen - 1; p++, i++);
168 /* gobble \n if it starts the line. */
169 if (*p == '\n') {
170 /* grab the end of line too! and then advance past
171 the newline */
172 i++;
173 p++;
174 } else {
175 /* TODO -- perhaps we should return no line at all
176 here, as it might be incomplete. don't want to
177 break anything though. */
178 DMA(DEBUG_INFO, "expected line doesn't end on its own.\n");
181 if (i != 0) {
182 /* copy a line into the linebuffer */
183 strncpy(linebuffer, readbuffer, (size_t) i);
184 /* sigh, null terminate */
185 linebuffer[i] = '\0';
186 /* shift the rest over; this could be done
187 instead with strcpy... I think. */
188 q = readbuffer;
189 if (*p != '\0') {
190 while (*p != '\0') {
191 *(q++) = *(p++);
194 /* null terminate */
195 *(q++) = *(p++);
196 /* return the length of the line */
198 if (i < 0 || i > linebuflen) {
199 DM((Pop3 *) NULL, DEBUG_ERROR, "bork bork bork!: %d %d\n", i,
200 linebuflen);
202 return i;
205 /* eat lines, until one starting with prefix is found;
206 this skips 'informational' IMAP responses */
207 /* the correct response to a return value of 0 is almost
208 certainly tlscomm_close(scs): don't _expect() anything
209 unless anything else would represent failure */
211 tlscomm_expect(struct connection_state *scs,
212 const char *prefix, char *linebuf, int buflen)
214 int prefixlen = (int) strlen(prefix);
215 int buffered_bytes = 0;
216 memset(linebuf, 0, buflen);
217 TDM(DEBUG_INFO, "%s: expecting: %s\n", scs->name, prefix);
218 /* if(scs->unprocessed[0]) {
219 TDM(DEBUG_INFO, "%s: buffered: %s\n", scs->name, scs->unprocessed);
220 } */
221 while (scs->unprocessed[0] != '\0'
222 || wait_for_it(scs->sd, EXPECT_TIMEOUT)) {
223 if (scs->unprocessed[buffered_bytes] == '\0') {
224 int thisreadbytes;
225 #ifdef USE_GNUTLS
226 if (scs->tls_state) {
227 /* BUF_SIZE - 1 leaves room for trailing \0 */
228 do {
229 thisreadbytes =
230 gnutls_read(scs->tls_state,
231 &scs->unprocessed[buffered_bytes],
232 BUF_SIZE - 1 - buffered_bytes);
233 } while (thisreadbytes == GNUTLS_E_AGAIN);
234 if (thisreadbytes < 0) {
235 handle_gnutls_read_error(thisreadbytes, scs);
236 return 0;
238 } else
239 #endif
241 thisreadbytes =
242 read(scs->sd, &scs->unprocessed[buffered_bytes],
243 BUF_SIZE - 1 - buffered_bytes);
244 if (thisreadbytes < 0) {
245 TDM(DEBUG_ERROR, "%s: error reading: %s\n",
246 scs->name, strerror(errno));
247 return 0;
250 buffered_bytes += thisreadbytes;
251 /* force null termination */
252 scs->unprocessed[buffered_bytes] = '\0';
253 if (buffered_bytes == 0) {
254 return 0; /* bummer */
256 } else {
257 buffered_bytes = strlen(scs->unprocessed);
259 while (buffered_bytes >= prefixlen) {
260 int linebytes;
261 linebytes =
262 getline_from_buffer(scs->unprocessed, linebuf, buflen);
263 if (linebytes == 0) {
264 buffered_bytes = 0;
265 } else {
266 buffered_bytes -= linebytes;
267 if (strncmp(linebuf, prefix, prefixlen) == 0) {
268 TDM(DEBUG_INFO, "%s: got: %*s", scs->name,
269 linebytes, linebuf);
270 return 1; /* got it! */
272 TDM(DEBUG_INFO, "%s: dumped(%d/%d): %.*s", scs->name,
273 linebytes, buffered_bytes, linebytes, linebuf);
277 if (buffered_bytes == -1) {
278 TDM(DEBUG_INFO, "%s: timed out while expecting '%s'\n",
279 scs->name, prefix);
280 } else {
281 TDM(DEBUG_ERROR, "%s: expecting: '%s', saw (%d): %s%s",
282 scs->name, prefix, buffered_bytes, linebuf,
283 /* only print the newline if the linebuf lacks it */
284 (linebuf[strlen(linebuf) - 1] == '\n') ? "\n" : "");
286 return 0; /* wait_for_it failed */
289 int tlscomm_gets(char *buf, int buflen, struct connection_state *scs)
291 return (tlscomm_expect(scs, "", buf, buflen));
294 void tlscomm_printf(struct connection_state *scs, const char *format, ...)
296 va_list args;
297 char buf[1024];
298 int bytes;
299 ssize_t unused __attribute__((unused));
301 if (scs == NULL) {
302 DMA(DEBUG_ERROR, "null connection to tlscomm_printf\n");
303 abort();
305 va_start(args, format);
306 bytes = vsnprintf(buf, 1024, format, args);
307 va_end(args);
309 if (scs->sd != -1) {
310 #ifdef USE_GNUTLS
311 if (scs->tls_state) {
312 int written = gnutls_write(scs->tls_state, buf, bytes);
313 if (written < bytes) {
314 TDM(DEBUG_ERROR,
315 "Error %s prevented writing: %*s\n",
316 gnutls_strerror(written), bytes, buf);
317 return;
319 } else
320 #endif
321 /* Why???? */
322 unused = write(scs->sd, buf, bytes);
323 } else {
324 printf
325 ("warning: tlscomm_printf called with an invalid socket descriptor\n");
326 return;
328 TDM(DEBUG_INFO, "wrote %*s", bytes, buf);
331 /* most of this file only makes sense if using TLS. */
332 #ifdef USE_GNUTLS
333 #include "gnutls-common.h"
335 static void
336 bad_certificate(const struct connection_state *scs, const char *msg)
338 TDM(DEBUG_ERROR, "%s", msg);
339 if (!SkipCertificateCheck) {
340 TDM(DEBUG_ERROR, "to ignore this error, run wmbiff "
341 "with the -skip-certificate-check option\n");
342 exit(1);
346 static void
347 warn_certificate(const struct connection_state *scs, const char *msg)
349 if (!SkipCertificateCheck) {
350 TDM(DEBUG_ERROR, "%s", msg);
351 TDM(DEBUG_ERROR, "to ignore this warning, run wmbiff "
352 "with the -skip-certificate-check option\n");
356 /* a start of a hack at verifying certificates. does not
357 provide any security at all. I'm waiting for either
358 gnutls to make this as easy as it should be, or someone
359 to port Andrew McDonald's gnutls-for-mutt patch.
362 #define CERT_SEP "-----BEGIN"
364 /* this bit is based on read_ca_file() in gnutls */
365 static int tls_compare_certificates(const gnutls_datum_t * peercert)
367 gnutls_datum_t cert;
368 unsigned char *ptr;
369 FILE *fd1;
370 int ret;
371 gnutls_datum_t b64_data;
372 unsigned char *b64_data_data;
373 struct stat filestat;
375 if (stat(certificate_filename, &filestat) == -1)
376 return 0;
378 b64_data.size = filestat.st_size + 1;
379 b64_data_data = (unsigned char *) malloc(b64_data.size);
380 b64_data_data[b64_data.size - 1] = '\0';
381 b64_data.data = b64_data_data;
383 fd1 = fopen(certificate_filename, "r");
384 if (fd1 == NULL) {
385 free(b64_data_data);
386 return 0;
388 b64_data.size = fread(b64_data.data, 1, b64_data.size, fd1);
389 fclose(fd1);
391 do {
392 ret = gnutls_pem_base64_decode_alloc(NULL, &b64_data, &cert);
393 if (ret != 0) {
394 free(b64_data_data);
395 return 0;
398 ptr = (unsigned char *) strstr((char *) b64_data.data, CERT_SEP) + 1;
399 ptr = (unsigned char *) strstr((char *) ptr, CERT_SEP);
401 b64_data.size = b64_data.size - (ptr - b64_data.data);
402 b64_data.data = ptr;
404 if (cert.size == peercert->size) {
405 if (memcmp(cert.data, peercert->data, cert.size) == 0) {
406 /* match found */
407 gnutls_free(cert.data);
408 free(b64_data_data);
409 return 1;
413 gnutls_free(cert.data);
414 } while (ptr != NULL);
416 /* no match found */
417 free(b64_data_data);
418 return 0;
422 static void
423 tls_check_certificate(struct connection_state *scs,
424 const char *remote_hostname)
426 int ret;
427 unsigned int certstat;
428 const gnutls_datum_t *cert_list;
429 unsigned int cert_list_size = 0;
430 gnutls_x509_crt_t cert;
432 if (gnutls_auth_get_type(scs->tls_state) != GNUTLS_CRD_CERTIFICATE) {
433 bad_certificate(scs, "Unable to get certificate from peer.\n");
434 return; /* bad_cert will exit if -skip-certificate-check was not given */
436 ret = gnutls_certificate_verify_peers2(scs->tls_state, &certstat);
438 if (ret < 0) {
439 char errbuf[1024];
441 snprintf(errbuf, 1024, "could not verify certificate: %s (%d).\n",
442 gnutls_strerror(ret), ret);
443 bad_certificate(scs, (ret == GNUTLS_E_NO_CERTIFICATE_FOUND ?
444 "server presented no certificate.\n" :
445 errbuf));
446 return;
447 #ifdef GNUTLS_CERT_CORRUPTED
448 } else if (certstat & GNUTLS_CERT_CORRUPTED) {
449 bad_certificate(scs, "server's certificate is corrupt.\n");
450 #endif
451 } else if (certstat & GNUTLS_CERT_REVOKED) {
452 bad_certificate(scs, "server's certificate has been revoked.\n");
453 } else if (certstat & GNUTLS_CERT_EXPIRED) {
454 bad_certificate(scs, "server's certificate is expired.\n");
455 } else if (certstat & GNUTLS_CERT_INSECURE_ALGORITHM) {
456 warn_certificate(scs, "server's certificate use an insecure algorithm.\n");
457 } else if (certstat & GNUTLS_CERT_INVALID) {
458 if (gnutls_certificate_type_get(scs->tls_state) == GNUTLS_CRT_X509) {
459 /* bad_certificate(scs, "server's certificate is not trusted.\n"
460 "there may be a problem with the certificate stored in your certfile\n"); */
461 } else {
462 bad_certificate(scs,
463 "server's certificate is invalid or not X.509.\n"
464 "there may be a problem with the certificate stored in your certfile\n");
466 #if defined(GNUTLS_CERT_SIGNER_NOT_FOUND)
467 } else if (certstat & GNUTLS_CERT_SIGNER_NOT_FOUND) {
468 TDM(DEBUG_INFO, "server's certificate is not signed.\n");
469 TDM(DEBUG_INFO,
470 "to verify that a certificate is trusted, use the certfile option.\n");
471 #endif
473 #if defined(GNUTLS_CERT_NOT_TRUSTED)
474 } else if (certstat & GNUTLS_CERT_NOT_TRUSTED) {
475 TDM(DEBUG_INFO, "server's certificate is not trusted.\n");
476 TDM(DEBUG_INFO,
477 "to verify that a certificate is trusted, use the certfile option.\n");
478 #endif
481 if (gnutls_x509_crt_init(&cert) < 0) {
482 bad_certificate(scs,
483 "Unable to initialize certificate data structure");
487 /* not checking for not-yet-valid certs... this would make sense
488 if we weren't just comparing to stored ones */
489 cert_list =
490 gnutls_certificate_get_peers(scs->tls_state, &cert_list_size);
492 if (gnutls_x509_crt_import(cert, &cert_list[0], GNUTLS_X509_FMT_DER) <
493 0) {
494 bad_certificate(scs, "Error processing certificate data");
497 if (gnutls_x509_crt_get_expiration_time(cert) < time(NULL)) {
498 bad_certificate(scs, "server's certificate has expired.\n");
499 } else if (gnutls_x509_crt_get_activation_time(cert)
500 > time(NULL)) {
501 bad_certificate(scs, "server's certificate is not yet valid.\n");
502 } else {
503 TDM(DEBUG_INFO, "certificate passed time check.\n");
506 if (gnutls_x509_crt_check_hostname(cert, remote_hostname) == 0) {
507 char certificate_hostname[256];
508 size_t buflen = 255;
509 gnutls_x509_crt_get_dn(cert, certificate_hostname, &buflen);
510 /* gnutls_x509_extract_certificate_dn(&cert_list[0], &dn); */
511 TDM(DEBUG_INFO,
512 "server's certificate (%s) does not match its hostname (%s).\n",
513 certificate_hostname, remote_hostname);
514 bad_certificate(scs,
515 "server's certificate does not match its hostname.\n");
516 } else {
517 if ((scs->pc)->debug >= DEBUG_INFO) {
518 char certificate_hostname[256];
519 size_t buflen = 255;
520 gnutls_x509_crt_get_dn(cert, certificate_hostname, &buflen);
521 /* gnutls_x509_extract_certificate_dn(&cert_list[0], &dn); */
522 TDM(DEBUG_INFO,
523 "server's certificate (%s) matched its hostname (%s).\n",
524 certificate_hostname, remote_hostname);
528 if (certificate_filename != NULL &&
529 tls_compare_certificates(&cert_list[0]) == 0) {
530 bad_certificate(scs,
531 "server's certificate was not found in the certificate file.\n");
534 gnutls_x509_crt_deinit(cert);
536 TDM(DEBUG_INFO, "certificate check ok.\n");
537 return;
540 struct connection_state *initialize_gnutls(intptr_t sd, char *name, Pop3 *pc,
541 const char *remote_hostname)
543 static int gnutls_initialized;
544 int zok;
545 struct connection_state *scs = malloc(sizeof(struct connection_state));
546 memset(scs, 0, sizeof(struct connection_state)); /* clears the unprocessed buffer */
548 scs->pc = pc;
550 assert(sd >= 0);
552 if (gnutls_initialized == 0) {
553 assert(gnutls_global_init() == 0);
554 gnutls_initialized = 1;
557 assert(gnutls_init(&scs->tls_state, GNUTLS_CLIENT) == 0);
559 const char *err_pos;
560 if (GNUTLS_E_SUCCESS != gnutls_priority_set_direct(scs->tls_state, tls, &err_pos)) {
561 DMA(DEBUG_ERROR,
562 "Unable to set the priorities to use on the ciphers, "
563 "key exchange methods, macs and/or compression methods.\n"
564 "See 'tls' parameter in config file: '%s'.\n",
565 err_pos);
566 exit(1);
569 /* no client private key */
570 if (gnutls_certificate_allocate_credentials(&scs->xcred) < 0) {
571 DMA(DEBUG_ERROR, "gnutls memory error\n");
572 exit(1);
575 /* certfile seems to work. */
576 if (certificate_filename != NULL) {
577 if (!exists(certificate_filename)) {
578 DMA(DEBUG_ERROR,
579 "Certificate file (certfile=) %s not found.\n",
580 certificate_filename);
581 exit(1);
583 zok = gnutls_certificate_set_x509_trust_file(scs->xcred,
584 (char *)
585 certificate_filename,
586 GNUTLS_X509_FMT_PEM);
587 if (zok < 0) {
588 DMA(DEBUG_ERROR,
589 "GNUTLS did not like your certificate file %s (%d).\n",
590 certificate_filename, zok);
591 gnutls_perror(zok);
592 exit(1);
596 gnutls_server_name_set(scs->tls_state, GNUTLS_NAME_DNS,
597 remote_hostname, strlen(remote_hostname));
598 gnutls_cred_set(scs->tls_state, GNUTLS_CRD_CERTIFICATE,
599 scs->xcred);
600 gnutls_transport_set_ptr(scs->tls_state,
601 (gnutls_transport_ptr_t) sd);
602 do {
603 zok = gnutls_handshake(scs->tls_state);
605 while (zok == GNUTLS_E_INTERRUPTED || zok == GNUTLS_E_AGAIN);
607 tls_check_certificate(scs, remote_hostname);
610 if (zok < 0) {
611 TDM(DEBUG_ERROR, "%s: Handshake failed\n", name);
612 TDM(DEBUG_ERROR, "%s: This may be a problem in gnutls, "
613 "which is under development\n", name);
614 TDM(DEBUG_ERROR,
615 "%s: This copy of wmbiff was compiled with \n"
616 " gnutls version %s.\n", name, LIBGNUTLS_VERSION);
617 gnutls_perror(zok);
618 if (scs->pc->u.pop_imap.serverPort != 143 /* starttls */ ) {
619 TDM(DEBUG_ERROR,
620 "%s: Please run 'gnutls-cli-debug -p %d %s' to test ssl directly.\n"
621 " That tool provides a lower-level test of gnutls with your server.\n",
622 name, scs->pc->u.pop_imap.serverPort, remote_hostname);
624 gnutls_deinit(scs->tls_state);
625 free(scs);
626 return (NULL);
627 } else {
628 TDM(DEBUG_INFO, "%s: Handshake was completed\n", name);
629 if (scs->pc->debug >= DEBUG_INFO)
630 print_info(scs->tls_state, remote_hostname);
631 scs->sd = sd;
632 scs->name = name;
634 return (scs);
637 /* moved down here, to keep from interrupting the flow with
638 verbose error crap */
639 void handle_gnutls_read_error(int readbytes, struct connection_state *scs)
641 if (gnutls_error_is_fatal(readbytes) == 1) {
642 TDM(DEBUG_ERROR,
643 "%s: Received corrupted data(%d) - server has terminated the connection abnormally\n",
644 scs->name, readbytes);
645 } else {
646 if (readbytes == GNUTLS_E_WARNING_ALERT_RECEIVED
647 || readbytes == GNUTLS_E_FATAL_ALERT_RECEIVED)
648 TDM(DEBUG_ERROR, "* Received alert [%d]\n",
649 gnutls_alert_get(scs->tls_state));
650 if (readbytes == GNUTLS_E_REHANDSHAKE)
651 TDM(DEBUG_ERROR, "* Received HelloRequest message\n");
653 TDM(DEBUG_ERROR,
654 "%s: gnutls error reading: %s\n",
655 scs->name, gnutls_strerror(readbytes));
658 #else
659 /* declare stubs when tls isn't compiled in */
660 struct connection_state *initialize_gnutls(UNUSED(intptr_t sd),
661 UNUSED(char *name),
662 UNUSED(Pop3 *pc),
663 UNUSED(const char
664 *remote_hostname))
666 DM(pc, DEBUG_ERROR,
667 "FATAL: tried to initialize ssl when ssl wasn't compiled in.\n");
668 exit(EXIT_FAILURE);
670 #endif
672 /* either way: */
673 struct connection_state *initialize_unencrypted(int sd,
674 /*@only@ */ char *name,
675 Pop3 *pc)
677 struct connection_state *ret = malloc(sizeof(struct connection_state));
678 assert(sd >= 0);
679 assert(ret != NULL);
680 memset(ret, 0, sizeof(struct connection_state)); /* clears the unprocessed buffer */
681 ret->sd = sd;
682 ret->name = name;
683 ret->tls_state = NULL;
684 ret->xcred = NULL;
685 ret->pc = pc;
686 return (ret);
689 /* bad seed connections that can't be setup */
690 /*@only@*/
691 struct connection_state *initialize_blacklist( /*@only@ */ char *name)
693 struct connection_state *ret = malloc(sizeof(struct connection_state));
694 assert(ret != NULL);
695 ret->sd = -1;
696 ret->name = name;
697 ret->tls_state = NULL;
698 ret->xcred = NULL;
699 ret->pc = NULL;
700 return (ret);
704 int tlscomm_is_blacklisted(const struct connection_state *scs)
706 return (scs != NULL && scs->sd == -1);
709 /* vim:set ts=4: */
711 * Local Variables:
712 * tab-width: 4
713 * c-indent-level: 4
714 * c-basic-offset: 4
715 * End: