YAZ  4.2.57
tcpip.c
Go to the documentation of this file.
1 /* This file is part of the YAZ toolkit.
2  * Copyright (C) 1995-2013 Index Data
3  * See the file LICENSE for details.
4  */
9 #if HAVE_CONFIG_H
10 #include <config.h>
11 #endif
12 
13 #include <stdio.h>
14 #include <string.h>
15 #include <assert.h>
16 #include <stdlib.h>
17 #include <errno.h>
18 #include <fcntl.h>
19 #include <signal.h>
20 #if HAVE_SYS_TYPES_H
21 #include <sys/types.h>
22 #endif
23 #if HAVE_SYS_TIME_H
24 #include <sys/time.h>
25 #endif
26 #if HAVE_UNISTD_H
27 #include <unistd.h>
28 #endif
29 
30 #ifdef WIN32
31 /* VS 2003 or later has getaddrinfo; older versions do not */
32 #include <winsock2.h>
33 #if _MSC_VER >= 1300
34 #include <ws2tcpip.h>
35 #define HAVE_GETADDRINFO 1
36 #else
37 #define HAVE_GETADDRINFO 0
38 #endif
39 #endif
40 
41 #if HAVE_NETINET_IN_H
42 #include <netinet/in.h>
43 #endif
44 #if HAVE_NETDB_H
45 #include <netdb.h>
46 #endif
47 #if HAVE_ARPA_INET_H
48 #include <arpa/inet.h>
49 #endif
50 #if HAVE_NETINET_TCP_H
51 #include <netinet/tcp.h>
52 #endif
53 #if HAVE_SYS_SOCKET_H
54 #include <sys/socket.h>
55 #endif
56 #if HAVE_SYS_WAIT_H
57 #include <sys/wait.h>
58 #endif
59 
60 #if HAVE_GNUTLS_H
61 #include <gnutls/x509.h>
62 #include <gnutls/gnutls.h>
63 #define ENABLE_SSL 1
64 #endif
65 
66 #if HAVE_OPENSSL_SSL_H
67 #include <openssl/ssl.h>
68 #include <openssl/err.h>
69 #define ENABLE_SSL 1
70 #endif
71 
72 #include <yaz/comstack.h>
73 #include <yaz/tcpip.h>
74 #include <yaz/errno.h>
75 
76 static void tcpip_close(COMSTACK h);
77 static int tcpip_put(COMSTACK h, char *buf, int size);
78 static int tcpip_get(COMSTACK h, char **buf, int *bufsize);
79 static int tcpip_put_connect(COMSTACK h, char *buf, int size);
80 static int tcpip_get_connect(COMSTACK h, char **buf, int *bufsize);
81 static int tcpip_connect(COMSTACK h, void *address);
82 static int tcpip_more(COMSTACK h);
83 static int tcpip_rcvconnect(COMSTACK h);
84 static int tcpip_bind(COMSTACK h, void *address, int mode);
85 static int tcpip_listen(COMSTACK h, char *raddr, int *addrlen,
86  int (*check_ip)(void *cd, const char *a, int len, int type),
87  void *cd);
88 static int tcpip_set_blocking(COMSTACK p, int blocking);
89 
90 #if ENABLE_SSL
91 static int ssl_get(COMSTACK h, char **buf, int *bufsize);
92 static int ssl_put(COMSTACK h, char *buf, int size);
93 #endif
94 
96 static const char *tcpip_addrstr(COMSTACK h);
97 static void *tcpip_straddr(COMSTACK h, const char *str);
98 
99 #if 0
100 #define TRC(x) x
101 #else
102 #define TRC(X)
103 #endif
104 
105 #ifndef YAZ_SOCKLEN_T
106 #define YAZ_SOCKLEN_T int
107 #endif
108 
109 #if HAVE_GNUTLS_H
110 struct tcpip_cred_ptr {
111  gnutls_certificate_credentials_t xcred;
112  int ref;
113 };
114 
115 #endif
116 /* this state is used for both SSL and straight TCP/IP */
117 typedef struct tcpip_state
118 {
119  char *altbuf; /* alternate buffer for surplus data */
120  int altsize; /* size as xmalloced */
121  int altlen; /* length of data or 0 if none */
122 
123  int written; /* -1 if we aren't writing */
124  int towrite; /* to verify against user input */
125  int (*complete)(const char *buf, int len); /* length/complete. */
126 #if HAVE_GETADDRINFO
127  struct addrinfo *ai;
128 #else
129  struct sockaddr_in addr; /* returned by cs_straddr */
130 #endif
131  char buf[128]; /* returned by cs_addrstr */
132 #if HAVE_GNUTLS_H
133  struct tcpip_cred_ptr *cred_ptr;
134  gnutls_session_t session;
135  char cert_fname[256];
136 #elif HAVE_OPENSSL_SSL_H
137  SSL_CTX *ctx; /* current CTX. */
138  SSL_CTX *ctx_alloc; /* If =ctx it is owned by CS. If 0 it is not owned */
139  SSL *ssl;
140  char cert_fname[256];
141 #endif
146 } tcpip_state;
147 
148 #ifdef WIN32
149 static int tcpip_init(void)
150 {
151  static int initialized = 0;
152  if (!initialized)
153  {
154  WORD requested;
155  WSADATA wd;
156 
157  requested = MAKEWORD(1, 1);
158  if (WSAStartup(requested, &wd))
159  return 0;
160  initialized = 1;
161  }
162  return 1;
163 }
164 #else
165 static int tcpip_init(void)
166 {
167  return 1;
168 }
169 #endif
170 
171 /*
172  * This function is always called through the cs_create() macro.
173  * s >= 0: socket has already been established for us.
174  */
175 COMSTACK tcpip_type(int s, int flags, int protocol, void *vp)
176 {
177  COMSTACK p;
178  tcpip_state *sp;
179 
180  if (!tcpip_init())
181  return 0;
182  if (!(p = (struct comstack *)xmalloc(sizeof(struct comstack))))
183  return 0;
184  if (!(sp = (struct tcpip_state *)(p->cprivate =
185  xmalloc(sizeof(tcpip_state)))))
186  return 0;
187 
188  p->flags = flags;
189 
190  p->io_pending = 0;
191  p->iofile = s;
192  p->type = tcpip_type;
193  p->protocol = (enum oid_proto) protocol;
194 
197  p->f_get = tcpip_get;
198  p->f_put = tcpip_put;
199  p->f_close = tcpip_close;
200  p->f_more = tcpip_more;
201  p->f_bind = tcpip_bind;
202  p->f_listen = tcpip_listen;
203  p->f_accept = tcpip_accept;
207  p->max_recv_bytes = 128 * 1024 * 1024;
208 
209  p->state = s < 0 ? CS_ST_UNBND : CS_ST_IDLE; /* state of line */
210  p->event = CS_NONE;
211  p->cerrno = 0;
212  p->user = 0;
213 
214 #if HAVE_GNUTLS_H
215  sp->cred_ptr = 0;
216  sp->session = 0;
217  strcpy(sp->cert_fname, "yaz.pem");
218 #elif HAVE_OPENSSL_SSL_H
219  sp->ctx = sp->ctx_alloc = 0;
220  sp->ssl = 0;
221  strcpy(sp->cert_fname, "yaz.pem");
222 #endif
223 
224 #if HAVE_GETADDRINFO
225  sp->ai = 0;
226 #endif
227  sp->altbuf = 0;
228  sp->altsize = sp->altlen = 0;
229  sp->towrite = sp->written = -1;
230  if (protocol == PROTO_WAIS)
231  sp->complete = completeWAIS;
232  else
234 
235  sp->connect_request_buf = 0;
236  sp->connect_request_len = 0;
237  sp->connect_response_buf = 0;
238  sp->connect_response_len = 0;
239 
241  TRC(fprintf(stderr, "Created new TCPIP comstack h=%p\n", p));
242 
243  return p;
244 }
245 
246 COMSTACK yaz_tcpip_create(int s, int flags, int protocol,
247  const char *connect_host)
248 {
249  COMSTACK p = tcpip_type(s, flags, protocol, 0);
250  if (!p)
251  return 0;
252  if (connect_host)
253  {
254  tcpip_state *sp = (tcpip_state *) p->cprivate;
255  sp->connect_request_buf = (char *) xmalloc(strlen(connect_host) + 30);
256  sprintf(sp->connect_request_buf, "CONNECT %s HTTP/1.0\r\n\r\n",
257  connect_host);
258  sp->connect_request_len = strlen(sp->connect_request_buf);
261  sp->complete = cs_complete_auto_head; /* only want HTTP header */
262  }
263  return p;
264 }
265 
266 #if HAVE_GNUTLS_H
267 static void tcpip_create_cred(COMSTACK cs)
268 {
269  tcpip_state *sp = (tcpip_state *) cs->cprivate;
270  sp->cred_ptr = (struct tcpip_cred_ptr *) xmalloc(sizeof(*sp->cred_ptr));
271  sp->cred_ptr->ref = 1;
272  gnutls_certificate_allocate_credentials(&sp->cred_ptr->xcred);
273 }
274 
275 #endif
276 
277 COMSTACK ssl_type(int s, int flags, int protocol, void *vp)
278 {
279 #if !ENABLE_SSL
280  return 0;
281 #else
282  tcpip_state *sp;
283  COMSTACK p;
284 
285  p = tcpip_type(s, flags, protocol, 0);
286  if (!p)
287  return 0;
288  p->f_get = ssl_get;
289  p->f_put = ssl_put;
290  p->type = ssl_type;
291  sp = (tcpip_state *) p->cprivate;
292 
293 #if HAVE_GNUTLS_H
294  sp->session = (gnutls_session_t) vp;
295 #elif HAVE_OPENSSL_SSL_H
296  sp->ctx = (SSL_CTX *) vp; /* may be NULL */
297 #endif
298  /* note: we don't handle already opened socket in SSL mode - yet */
299  return p;
300 #endif
301 }
302 
303 #if ENABLE_SSL
304 static int ssl_check_error(COMSTACK h, tcpip_state *sp, int res)
305 {
306 #if HAVE_OPENSSL_SSL_H
307  int err = SSL_get_error(sp->ssl, res);
308  TRC(fprintf(stderr, "got err=%d\n", err));
309  if (err == SSL_ERROR_WANT_READ)
310  {
311  TRC(fprintf(stderr, " -> SSL_ERROR_WANT_READ\n"));
313  return 1;
314  }
315  if (err == SSL_ERROR_WANT_WRITE)
316  {
317  TRC(fprintf(stderr, " -> SSL_ERROR_WANT_WRITE\n"));
319  return 1;
320  }
321 #elif HAVE_GNUTLS_H
322  TRC(fprintf(stderr, "ssl_check_error error=%d fatal=%d msg=%s\n",
323  res,
324  gnutls_error_is_fatal(res),
325  gnutls_strerror(res)));
326  if (res == GNUTLS_E_AGAIN || res == GNUTLS_E_INTERRUPTED)
327  {
328  int dir = gnutls_record_get_direction(sp->session);
329  TRC(fprintf(stderr, " -> incomplete dir=%d\n", dir));
331  return 1;
332  }
333 #endif
334  h->cerrno = CSERRORSSL;
335  return 0;
336 }
337 #endif
338 
339 #if HAVE_GETADDRINFO
340 /* resolve using getaddrinfo */
341 struct addrinfo *tcpip_getaddrinfo(const char *str, const char *port,
342  int *ipv6_only)
343 {
344  struct addrinfo hints, *res;
345  int error;
346  char host[512], *p;
347 
348  hints.ai_flags = 0;
349  hints.ai_family = AF_UNSPEC;
350  hints.ai_socktype = SOCK_STREAM;
351  hints.ai_protocol = 0;
352  hints.ai_addrlen = 0;
353  hints.ai_addr = NULL;
354  hints.ai_canonname = NULL;
355  hints.ai_next = NULL;
356 
357  strncpy(host, str, sizeof(host)-1);
358  host[sizeof(host)-1] = 0;
359  if ((p = strchr(host, '/')))
360  *p = 0;
361  if ((p = strrchr(host, ':')))
362  {
363  *p = '\0';
364  port = p+1;
365  }
366 
367  if (!strcmp("@", host))
368  {
369  hints.ai_flags = AI_PASSIVE;
370  hints.ai_family = AF_UNSPEC;
371  error = getaddrinfo(0, port, &hints, &res);
372  *ipv6_only = 0;
373  }
374  else if (!strcmp("@4", host))
375  {
376  hints.ai_flags = AI_PASSIVE;
377  hints.ai_family = AF_INET;
378  error = getaddrinfo(0, port, &hints, &res);
379  *ipv6_only = -1;
380  }
381  else if (!strcmp("@6", host))
382  {
383  hints.ai_flags = AI_PASSIVE;
384  hints.ai_family = AF_INET6;
385  error = getaddrinfo(0, port, &hints, &res);
386  *ipv6_only = 1;
387  }
388  else
389  {
390  error = getaddrinfo(host, port, &hints, &res);
391  *ipv6_only = -1;
392  }
393  if (error)
394  return 0;
395  return res;
396 }
397 
398 #endif
399 /* gethostbyname .. old systems */
400 int tcpip_strtoaddr_ex(const char *str, struct sockaddr_in *add,
401  int default_port)
402 {
403  struct hostent *hp;
404  char *p, buf[512];
405  short int port = default_port;
406 #ifdef WIN32
407  unsigned long tmpadd;
408 #else
409  in_addr_t tmpadd;
410 #endif
411  TRC(fprintf(stderr, "tcpip_strtoaddress: %s\n", str ? str : "NULL"));
412  add->sin_family = AF_INET;
413  strncpy(buf, str, sizeof(buf)-1);
414  buf[sizeof(buf)-1] = 0;
415  if ((p = strchr(buf, '/')))
416  *p = 0;
417  if ((p = strrchr(buf, ':')))
418  {
419  *p = 0;
420  port = atoi(p + 1);
421  }
422  add->sin_port = htons(port);
423  if (!strcmp("@", buf))
424  {
425  add->sin_addr.s_addr = INADDR_ANY;
426  }
427  else if ((tmpadd = inet_addr(buf)) != -1)
428  {
429  memcpy(&add->sin_addr.s_addr, &tmpadd, sizeof(struct in_addr));
430  }
431  else if ((hp = gethostbyname(buf)))
432  {
433  memcpy(&add->sin_addr.s_addr, *hp->h_addr_list,
434  sizeof(struct in_addr));
435  }
436  else
437  return 0;
438  return 1;
439 }
440 
441 #if HAVE_GETADDRINFO
442 void *tcpip_straddr(COMSTACK h, const char *str)
443 {
444  tcpip_state *sp = (tcpip_state *)h->cprivate;
445  const char *port = "210";
446  struct addrinfo *ai = 0;
447  int ipv6_only = 0;
448  if (h->protocol == PROTO_HTTP)
449  {
450  if (h->type == ssl_type)
451  port = "443";
452  else
453  port = "80";
454  }
455  if (!tcpip_init())
456  return 0;
457 
458  if (sp->ai)
459  freeaddrinfo(sp->ai);
460  sp->ai = tcpip_getaddrinfo(str, port, &ipv6_only);
461  if (sp->ai && h->state == CS_ST_UNBND)
462  {
463  int s = -1;
464  for (ai = sp->ai; ai; ai = ai->ai_next)
465  {
466  if (ai->ai_family == AF_INET6)
467  {
468  s = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
469  if (s != -1)
470  break;
471  }
472  }
473  if (s == -1)
474  {
475  for (ai = sp->ai; ai; ai = ai->ai_next)
476  {
477  s = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
478  if (s != -1)
479  break;
480  }
481  }
482  if (s == -1)
483  return 0;
484  assert(ai);
485  h->iofile = s;
486  if (ai->ai_family == AF_INET6 && ipv6_only >= 0 &&
487  setsockopt(h->iofile,
488  IPPROTO_IPV6,
489  IPV6_V6ONLY, &ipv6_only, sizeof(ipv6_only)))
490  return 0;
491  if (!tcpip_set_blocking(h, h->flags))
492  return 0;
493  }
494  return ai;
495 }
496 #else
497 void *tcpip_straddr(COMSTACK h, const char *str)
498 {
499  tcpip_state *sp = (tcpip_state *)h->cprivate;
500  int port = 210;
501  if (h->protocol == PROTO_HTTP)
502  {
503  if (h->type == ssl_type)
504  port = 443;
505  else
506  port = 80;
507  }
508 
509  if (!tcpip_init())
510  return 0;
511  if (!tcpip_strtoaddr_ex(str, &sp->addr, port))
512  return 0;
513  if (h->state == CS_ST_UNBND)
514  {
515  int s;
516  s = socket(AF_INET, SOCK_STREAM, 0);
517  if (s < 0)
518  return 0;
519  h->iofile = s;
520 
521  if (!tcpip_set_blocking(h, h->flags))
522  return 0;
523  }
524  return &sp->addr;
525 }
526 #endif
527 
529 {
530  tcpip_state *sp = (tcpip_state *)h->cprivate;
531 
532  return sp->altlen && (*sp->complete)(sp->altbuf, sp->altlen);
533 }
534 
535 /*
536  * connect(2) will block (sometimes) - nothing we can do short of doing
537  * weird things like spawning subprocesses or threading or some weird junk
538  * like that.
539  */
540 int tcpip_connect(COMSTACK h, void *address)
541 {
542 #if HAVE_GETADDRINFO
543  struct addrinfo *ai = (struct addrinfo *) address;
544  tcpip_state *sp = (tcpip_state *)h->cprivate;
545 #else
546  struct sockaddr_in *add = (struct sockaddr_in *) address;
547 #endif
548  int r;
549  TRC(fprintf(stderr, "tcpip_connect h=%p\n", h));
550  h->io_pending = 0;
551  if (h->state != CS_ST_UNBND)
552  {
553  h->cerrno = CSOUTSTATE;
554  return -1;
555  }
556 #if HAVE_GETADDRINFO
557  r = connect(h->iofile, ai->ai_addr, ai->ai_addrlen);
558  freeaddrinfo(sp->ai);
559  sp->ai = 0;
560 #else
561  r = connect(h->iofile, (struct sockaddr *) add, sizeof(*add));
562 #endif
563  if (r < 0)
564  {
565 #ifdef WIN32
566  if (WSAGetLastError() == WSAEWOULDBLOCK)
567  {
568  h->event = CS_CONNECT;
569  h->state = CS_ST_CONNECTING;
571  return 1;
572  }
573 #else
574  if (yaz_errno() == EINPROGRESS)
575  {
576  h->event = CS_CONNECT;
577  h->state = CS_ST_CONNECTING;
579  return 1;
580  }
581 #endif
582  h->cerrno = CSYSERR;
583  return -1;
584  }
585  h->event = CS_CONNECT;
586  h->state = CS_ST_CONNECTING;
587 
588  return tcpip_rcvconnect(h);
589 }
590 
591 /*
592  * nop
593  */
595 {
596 #if ENABLE_SSL
597  tcpip_state *sp = (tcpip_state *)h->cprivate;
598 #endif
599  TRC(fprintf(stderr, "tcpip_rcvconnect\n"));
600 
601  if (h->state == CS_ST_DATAXFER)
602  return 0;
603  if (h->state != CS_ST_CONNECTING)
604  {
605  h->cerrno = CSOUTSTATE;
606  return -1;
607  }
608 #if HAVE_GNUTLS_H
609  if (h->type == ssl_type && !sp->session)
610  {
611  gnutls_global_init();
612  tcpip_create_cred(h);
613  gnutls_init(&sp->session, GNUTLS_CLIENT);
614  gnutls_set_default_priority(sp->session);
615  gnutls_credentials_set (sp->session, GNUTLS_CRD_CERTIFICATE,
616  sp->cred_ptr->xcred);
617  /* cast to intermediate size_t to avoid GCC warning. */
618  gnutls_transport_set_ptr(sp->session,
619  (gnutls_transport_ptr_t)
620  (size_t) h->iofile);
621  }
622  if (sp->session)
623  {
624  int res = gnutls_handshake(sp->session);
625  if (res < 0)
626  {
627  if (ssl_check_error(h, sp, res))
628  return 1;
629  return -1;
630  }
631  }
632 #elif HAVE_OPENSSL_SSL_H
633  if (h->type == ssl_type && !sp->ctx)
634  {
635  SSL_library_init();
636  SSL_load_error_strings();
637 
638  sp->ctx = sp->ctx_alloc = SSL_CTX_new(SSLv23_client_method());
639  if (!sp->ctx)
640  {
641  h->cerrno = CSERRORSSL;
642  return -1;
643  }
644  }
645  if (sp->ctx)
646  {
647  int res;
648 
649  if (!sp->ssl)
650  {
651  sp->ssl = SSL_new(sp->ctx);
652  SSL_set_fd(sp->ssl, h->iofile);
653  }
654  res = SSL_connect(sp->ssl);
655  if (res <= 0)
656  {
657  if (ssl_check_error(h, sp, res))
658  return 1;
659  return -1;
660  }
661  }
662 #endif
663  h->event = CS_DATA;
664  h->state = CS_ST_DATAXFER;
665  return 0;
666 }
667 
668 #define CERTF "ztest.pem"
669 #define KEYF "ztest.pem"
670 
671 static int tcpip_bind(COMSTACK h, void *address, int mode)
672 {
673  int r;
674  tcpip_state *sp = (tcpip_state *)h->cprivate;
676  struct addrinfo *ai = (struct addrinfo *) address;
677 #else
678  struct sockaddr *addr = (struct sockaddr *)address;
679 #endif
680 #ifdef WIN32
681  BOOL one = 1;
682 #else
683  int one = 1;
684 #endif
685 
686 #if HAVE_GNUTLS_H
687  if (h->type == ssl_type && !sp->session)
688  {
689  int res;
690  gnutls_global_init();
691 
692  tcpip_create_cred(h);
693 
694  res = gnutls_certificate_set_x509_key_file(sp->cred_ptr->xcred,
695  sp->cert_fname,
696  sp->cert_fname,
697  GNUTLS_X509_FMT_PEM);
698  if (res != GNUTLS_E_SUCCESS)
699  {
700  h->cerrno = CSERRORSSL;
701  return -1;
702  }
703  }
704 #elif HAVE_OPENSSL_SSL_H
705  if (h->type == ssl_type && !sp->ctx)
706  {
707  SSL_library_init();
708  SSL_load_error_strings();
709 
710  sp->ctx = sp->ctx_alloc = SSL_CTX_new(SSLv23_server_method());
711  if (!sp->ctx)
712  {
713  h->cerrno = CSERRORSSL;
714  return -1;
715  }
716  }
717  if (sp->ctx)
718  {
719  if (sp->ctx_alloc)
720  {
721  int res;
722  res = SSL_CTX_use_certificate_file(sp->ctx, sp->cert_fname,
723  SSL_FILETYPE_PEM);
724  if (res <= 0)
725  {
726  ERR_print_errors_fp(stderr);
727  exit(2);
728  }
729  res = SSL_CTX_use_PrivateKey_file(sp->ctx, sp->cert_fname,
730  SSL_FILETYPE_PEM);
731  if (res <= 0)
732  {
733  ERR_print_errors_fp(stderr);
734  exit(3);
735  }
736  res = SSL_CTX_check_private_key(sp->ctx);
737  if (res <= 0)
738  {
739  ERR_print_errors_fp(stderr);
740  exit(5);
741  }
742  }
743  TRC(fprintf(stderr, "ssl_bind\n"));
744  }
745  else
746  {
747  TRC(fprintf(stderr, "tcpip_bind\n"));
748  }
749 #else
750  TRC(fprintf(stderr, "tcpip_bind\n"));
751 #endif
752 #ifndef WIN32
753  if (setsockopt(h->iofile, SOL_SOCKET, SO_REUSEADDR, (char*)
754  &one, sizeof(one)) < 0)
755  {
756  h->cerrno = CSYSERR;
757  return -1;
758  }
759 #endif
760 #if HAVE_GETADDRINFO
761  r = bind(h->iofile, ai->ai_addr, ai->ai_addrlen);
762  freeaddrinfo(sp->ai);
763  sp->ai = 0;
764 #else
765  r = bind(h->iofile, addr, sizeof(struct sockaddr_in));
766 #endif
767  if (r)
768  {
769  h->cerrno = CSYSERR;
770  return -1;
771  }
772  /* Allow a maximum-sized backlog of waiting-to-connect clients */
773  if (mode == CS_SERVER && listen(h->iofile, SOMAXCONN) < 0)
774  {
775  h->cerrno = CSYSERR;
776  return -1;
777  }
778  h->state = CS_ST_IDLE;
779  h->event = CS_LISTEN;
780  return 0;
781 }
782 
783 int tcpip_listen(COMSTACK h, char *raddr, int *addrlen,
784  int (*check_ip)(void *cd, const char *a, int len, int t),
785  void *cd)
786 {
787 #ifdef WIN32
788  /* we don't get peer address on Windows (via accept) */
789 #else
790  struct sockaddr_in addr;
791  YAZ_SOCKLEN_T len = sizeof(addr);
792 #endif
793 
794  TRC(fprintf(stderr, "tcpip_listen pid=%d\n", getpid()));
795  if (h->state != CS_ST_IDLE)
796  {
797  h->cerrno = CSOUTSTATE;
798  return -1;
799  }
800 #ifdef WIN32
801  h->newfd = accept(h->iofile, 0, 0);
802 #else
803  h->newfd = accept(h->iofile, (struct sockaddr*)&addr, &len);
804 #endif
805  if (h->newfd < 0)
806  {
807  if (
808 #ifdef WIN32
809  WSAGetLastError() == WSAEWOULDBLOCK
810 #else
811  yaz_errno() == EWOULDBLOCK
812 #ifdef EAGAIN
813 #if EAGAIN != EWOULDBLOCK
814  || yaz_errno() == EAGAIN
815 #endif
816 #endif
817 #endif
818  )
819  h->cerrno = CSNODATA;
820  else
821  {
822 #ifdef WIN32
823  shutdown(h->iofile, SD_RECEIVE);
824 #else
825  shutdown(h->iofile, SHUT_RD);
826 #endif
827  listen(h->iofile, SOMAXCONN);
828  h->cerrno = CSYSERR;
829  }
830  return -1;
831  }
832 #ifdef WIN32
833  if (addrlen)
834  *addrlen = 0;
835 #else
836  if (addrlen && (size_t) (*addrlen) >= sizeof(struct sockaddr_in))
837  memcpy(raddr, &addr, *addrlen = sizeof(struct sockaddr_in));
838  else if (addrlen)
839  *addrlen = 0;
840  if (check_ip && (*check_ip)(cd, (const char *) &addr,
841  sizeof(addr), AF_INET))
842  {
843  h->cerrno = CSDENY;
844 #ifdef WIN32
845  closesocket(h->newfd);
846 #else
847  close(h->newfd);
848 #endif
849  h->newfd = -1;
850  return -1;
851  }
852 #endif
853  h->state = CS_ST_INCON;
854  return 0;
855 }
856 
858 {
859  COMSTACK cnew;
860 #ifdef WIN32
861  unsigned long tru = 1;
862 #endif
863 
864  TRC(fprintf(stderr, "tcpip_accept h=%p pid=%d\n", h, getpid()));
865  if (h->state == CS_ST_INCON)
866  {
867  tcpip_state *state, *st = (tcpip_state *)h->cprivate;
868  if (!(cnew = (COMSTACK)xmalloc(sizeof(*cnew))))
869  {
870  h->cerrno = CSYSERR;
871 #ifdef WIN32
872  closesocket(h->newfd);
873 #else
874  close(h->newfd);
875 #endif
876  h->newfd = -1;
877  return 0;
878  }
879  memcpy(cnew, h, sizeof(*h));
880  cnew->iofile = h->newfd;
881  cnew->io_pending = 0;
882 
883  if (!(state = (tcpip_state *)
884  (cnew->cprivate = xmalloc(sizeof(tcpip_state)))))
885  {
886  h->cerrno = CSYSERR;
887  if (h->newfd != -1)
888  {
889 #ifdef WIN32
890  closesocket(h->newfd);
891 #else
892  close(h->newfd);
893 #endif
894  h->newfd = -1;
895  }
896  return 0;
897  }
898  if (!tcpip_set_blocking(cnew, cnew->flags))
899  {
900  h->cerrno = CSYSERR;
901  if (h->newfd != -1)
902  {
903 #ifdef WIN32
904  closesocket(h->newfd);
905 #else
906  close(h->newfd);
907 #endif
908  h->newfd = -1;
909  }
910  xfree(cnew);
911  xfree(state);
912  return 0;
913  }
914  h->newfd = -1;
915  state->altbuf = 0;
916  state->altsize = state->altlen = 0;
917  state->towrite = state->written = -1;
918  state->complete = st->complete;
919 #if HAVE_GETADDRINFO
920  state->ai = 0;
921 #endif
922  cnew->state = CS_ST_ACCEPT;
923  h->state = CS_ST_IDLE;
924 
925 #if HAVE_GNUTLS_H
926  state->cred_ptr = st->cred_ptr;
927  state->session = 0;
928  if (st->cred_ptr)
929  {
930  int res;
931 
932  (state->cred_ptr->ref)++;
933  gnutls_init(&state->session, GNUTLS_SERVER);
934  if (!state->session)
935  {
936  xfree(cnew);
937  xfree(state);
938  return 0;
939  }
940  res = gnutls_set_default_priority(state->session);
941  if (res != GNUTLS_E_SUCCESS)
942  {
943  xfree(cnew);
944  xfree(state);
945  return 0;
946  }
947  res = gnutls_credentials_set(state->session,
948  GNUTLS_CRD_CERTIFICATE,
949  st->cred_ptr->xcred);
950  if (res != GNUTLS_E_SUCCESS)
951  {
952  xfree(cnew);
953  xfree(state);
954  return 0;
955  }
956  /* cast to intermediate size_t to avoid GCC warning. */
957  gnutls_transport_set_ptr(state->session,
958  (gnutls_transport_ptr_t)
959  (size_t) cnew->iofile);
960  }
961 #elif HAVE_OPENSSL_SSL_H
962  state->ctx = st->ctx;
963  state->ctx_alloc = 0;
964  state->ssl = st->ssl;
965  if (state->ctx)
966  {
967  state->ssl = SSL_new(state->ctx);
968  SSL_set_fd(state->ssl, cnew->iofile);
969  }
970 #endif
971  state->connect_request_buf = 0;
972  state->connect_response_buf = 0;
973  h = cnew;
974  }
975  if (h->state == CS_ST_ACCEPT)
976  {
977 #if HAVE_GNUTLS_H
978  tcpip_state *state = (tcpip_state *)h->cprivate;
979  if (state->session)
980  {
981  int res = gnutls_handshake(state->session);
982  if (res < 0)
983  {
984  if (ssl_check_error(h, state, res))
985  {
986  TRC(fprintf(stderr, "gnutls_handshake int in tcpip_accept\n"));
987  return h;
988  }
989  TRC(fprintf(stderr, "gnutls_handshake failed in tcpip_accept\n"));
990  cs_close(h);
991  return 0;
992  }
993  TRC(fprintf(stderr, "SSL_accept complete. gnutls\n"));
994  }
995 #elif HAVE_OPENSSL_SSL_H
996  tcpip_state *state = (tcpip_state *)h->cprivate;
997  if (state->ctx)
998  {
999  int res;
1000  errno = 0;
1001  res = SSL_accept(state->ssl);
1002  TRC(fprintf(stderr, "SSL_accept res=%d\n", res));
1003  if (res <= 0)
1004  {
1005  if (ssl_check_error(h, state, res))
1006  {
1007  return h;
1008  }
1009  cs_close(h);
1010  return 0;
1011  }
1012  TRC(fprintf(stderr, "SSL_accept complete\n"));
1013  }
1014 #endif
1015  }
1016  else
1017  {
1018  h->cerrno = CSOUTSTATE;
1019  return 0;
1020  }
1021  h->io_pending = 0;
1022  h->state = CS_ST_DATAXFER;
1023  h->event = CS_DATA;
1024  return h;
1025 }
1026 
1027 #define CS_TCPIP_BUFCHUNK 4096
1028 
1029 /*
1030  * Return: -1 error, >1 good, len of buffer, ==1 incomplete buffer,
1031  * 0=connection closed.
1032  */
1033 int tcpip_get(COMSTACK h, char **buf, int *bufsize)
1034 {
1035  tcpip_state *sp = (tcpip_state *)h->cprivate;
1036  char *tmpc;
1037  int tmpi, berlen, rest, req, tomove;
1038  int hasread = 0, res;
1039 
1040  TRC(fprintf(stderr, "tcpip_get: h=%p bufsize=%d\n", h, *bufsize));
1041  if (sp->altlen) /* switch buffers */
1042  {
1043  TRC(fprintf(stderr, " %d bytes in altbuf (%p)\n", sp->altlen,
1044  sp->altbuf));
1045  tmpc = *buf;
1046  tmpi = *bufsize;
1047  *buf = sp->altbuf;
1048  *bufsize = sp->altsize;
1049  hasread = sp->altlen;
1050  sp->altlen = 0;
1051  sp->altbuf = tmpc;
1052  sp->altsize = tmpi;
1053  }
1054  h->io_pending = 0;
1055  while (!(berlen = (*sp->complete)(*buf, hasread)))
1056  {
1057  if (!*bufsize)
1058  {
1059  if (!(*buf = (char *)xmalloc(*bufsize = CS_TCPIP_BUFCHUNK)))
1060  {
1061  h->cerrno = CSYSERR;
1062  return -1;
1063  }
1064  }
1065  else if (*bufsize - hasread < CS_TCPIP_BUFCHUNK)
1066  if (!(*buf =(char *)xrealloc(*buf, *bufsize *= 2)))
1067  {
1068  h->cerrno = CSYSERR;
1069  return -1;
1070  }
1071 #ifdef __sun__
1072  yaz_set_errno( 0 );
1073  /* unfortunatly, sun sometimes forgets to set errno in recv
1074  when EWOULDBLOCK etc. would be required (res = -1) */
1075 #endif
1076  res = recv(h->iofile, *buf + hasread, CS_TCPIP_BUFCHUNK, 0);
1077  TRC(fprintf(stderr, " recv res=%d, hasread=%d\n", res, hasread));
1078  if (res < 0)
1079  {
1080  TRC(fprintf(stderr, " recv errno=%d, (%s)\n", yaz_errno(),
1081  strerror(yaz_errno())));
1082 #ifdef WIN32
1083  if (WSAGetLastError() == WSAEWOULDBLOCK)
1084  {
1085  h->io_pending = CS_WANT_READ;
1086  break;
1087  }
1088  else
1089  {
1090  h->cerrno = CSYSERR;
1091  return -1;
1092  }
1093 #else
1094  if (yaz_errno() == EWOULDBLOCK
1095 #ifdef EAGAIN
1096 #if EAGAIN != EWOULDBLOCK
1097  || yaz_errno() == EAGAIN
1098 #endif
1099 #endif
1100  || yaz_errno() == EINPROGRESS
1101 #ifdef __sun__
1102  || yaz_errno() == ENOENT /* Sun's sometimes set errno to this */
1103 #endif
1104  )
1105  {
1106  h->io_pending = CS_WANT_READ;
1107  break;
1108  }
1109  else if (yaz_errno() == 0)
1110  continue;
1111  else
1112  {
1113  h->cerrno = CSYSERR;
1114  return -1;
1115  }
1116 #endif
1117  }
1118  else if (!res)
1119  return hasread;
1120  hasread += res;
1121  if (hasread > h->max_recv_bytes)
1122  {
1123  h->cerrno = CSBUFSIZE;
1124  return -1;
1125  }
1126  }
1127  TRC(fprintf(stderr, " Out of read loop with hasread=%d, berlen=%d\n",
1128  hasread, berlen));
1129  /* move surplus buffer (or everything if we didn't get a BER rec.) */
1130  if (hasread > berlen)
1131  {
1132  tomove = req = hasread - berlen;
1133  rest = tomove % CS_TCPIP_BUFCHUNK;
1134  if (rest)
1135  req += CS_TCPIP_BUFCHUNK - rest;
1136  if (!sp->altbuf)
1137  {
1138  if (!(sp->altbuf = (char *)xmalloc(sp->altsize = req)))
1139  {
1140  h->cerrno = CSYSERR;
1141  return -1;
1142  }
1143  } else if (sp->altsize < req)
1144  if (!(sp->altbuf =(char *)xrealloc(sp->altbuf, sp->altsize = req)))
1145  {
1146  h->cerrno = CSYSERR;
1147  return -1;
1148  }
1149  TRC(fprintf(stderr, " Moving %d bytes to altbuf(%p)\n", tomove,
1150  sp->altbuf));
1151  memcpy(sp->altbuf, *buf + berlen, sp->altlen = tomove);
1152  }
1153  if (berlen < CS_TCPIP_BUFCHUNK - 1)
1154  *(*buf + berlen) = '\0';
1155  return berlen ? berlen : 1;
1156 }
1157 
1158 
1159 #if ENABLE_SSL
1160 /*
1161  * Return: -1 error, >1 good, len of buffer, ==1 incomplete buffer,
1162  * 0=connection closed.
1163  */
1164 int ssl_get(COMSTACK h, char **buf, int *bufsize)
1165 {
1166  tcpip_state *sp = (tcpip_state *)h->cprivate;
1167  char *tmpc;
1168  int tmpi, berlen, rest, req, tomove;
1169  int hasread = 0, res;
1170 
1171  TRC(fprintf(stderr, "ssl_get: bufsize=%d\n", *bufsize));
1172  if (sp->altlen) /* switch buffers */
1173  {
1174  TRC(fprintf(stderr, " %d bytes in altbuf (%p)\n", sp->altlen,
1175  sp->altbuf));
1176  tmpc = *buf;
1177  tmpi = *bufsize;
1178  *buf = sp->altbuf;
1179  *bufsize = sp->altsize;
1180  hasread = sp->altlen;
1181  sp->altlen = 0;
1182  sp->altbuf = tmpc;
1183  sp->altsize = tmpi;
1184  }
1185  h->io_pending = 0;
1186  while (!(berlen = (*sp->complete)(*buf, hasread)))
1187  {
1188  if (!*bufsize)
1189  {
1190  if (!(*buf = (char *)xmalloc(*bufsize = CS_TCPIP_BUFCHUNK)))
1191  return -1;
1192  }
1193  else if (*bufsize - hasread < CS_TCPIP_BUFCHUNK)
1194  if (!(*buf =(char *)xrealloc(*buf, *bufsize *= 2)))
1195  return -1;
1196 #if HAVE_GNUTLS_H
1197  res = gnutls_record_recv(sp->session, *buf + hasread,
1199  if (res == 0)
1200  {
1201  TRC(fprintf(stderr, "gnutls_record_recv returned 0\n"));
1202  return 0;
1203  }
1204  else if (res < 0)
1205  {
1206  if (ssl_check_error(h, sp, res))
1207  break;
1208  return -1;
1209  }
1210 #else
1211  res = SSL_read(sp->ssl, *buf + hasread, CS_TCPIP_BUFCHUNK);
1212  TRC(fprintf(stderr, " SSL_read res=%d, hasread=%d\n", res, hasread));
1213  if (res <= 0)
1214  {
1215  if (ssl_check_error(h, sp, res))
1216  break;
1217  return -1;
1218  }
1219 #endif
1220  hasread += res;
1221  }
1222  TRC (fprintf (stderr, " Out of read loop with hasread=%d, berlen=%d\n",
1223  hasread, berlen));
1224  /* move surplus buffer (or everything if we didn't get a BER rec.) */
1225  if (hasread > berlen)
1226  {
1227  tomove = req = hasread - berlen;
1228  rest = tomove % CS_TCPIP_BUFCHUNK;
1229  if (rest)
1230  req += CS_TCPIP_BUFCHUNK - rest;
1231  if (!sp->altbuf)
1232  {
1233  if (!(sp->altbuf = (char *)xmalloc(sp->altsize = req)))
1234  return -1;
1235  } else if (sp->altsize < req)
1236  if (!(sp->altbuf =(char *)xrealloc(sp->altbuf, sp->altsize = req)))
1237  return -1;
1238  TRC(fprintf(stderr, " Moving %d bytes to altbuf(%p)\n", tomove,
1239  sp->altbuf));
1240  memcpy(sp->altbuf, *buf + berlen, sp->altlen = tomove);
1241  }
1242  if (berlen < CS_TCPIP_BUFCHUNK - 1)
1243  *(*buf + berlen) = '\0';
1244  return berlen ? berlen : 1;
1245 }
1246 #endif
1247 
1248 /*
1249  * Returns 1, 0 or -1
1250  * In nonblocking mode, you must call again with same buffer while
1251  * return value is 1.
1252  */
1253 int tcpip_put(COMSTACK h, char *buf, int size)
1254 {
1255  int res;
1256  struct tcpip_state *state = (struct tcpip_state *)h->cprivate;
1257 
1258  TRC(fprintf(stderr, "tcpip_put: h=%p size=%d\n", h, size));
1259  h->io_pending = 0;
1260  h->event = CS_DATA;
1261  if (state->towrite < 0)
1262  {
1263  state->towrite = size;
1264  state->written = 0;
1265  }
1266  else if (state->towrite != size)
1267  {
1268  h->cerrno = CSWRONGBUF;
1269  return -1;
1270  }
1271  while (state->towrite > state->written)
1272  {
1273  if ((res =
1274  send(h->iofile, buf + state->written, size -
1275  state->written,
1276 #ifdef MSG_NOSIGNAL
1277  MSG_NOSIGNAL
1278 #else
1279  0
1280 #endif
1281  )) < 0)
1282  {
1283  if (
1284 #ifdef WIN32
1285  WSAGetLastError() == WSAEWOULDBLOCK
1286 #else
1287  yaz_errno() == EWOULDBLOCK
1288 #ifdef EAGAIN
1289 #if EAGAIN != EWOULDBLOCK
1290  || yaz_errno() == EAGAIN
1291 #endif
1292 #endif
1293 #ifdef __sun__
1294  || yaz_errno() == ENOENT /* Sun's sometimes set errno to this value! */
1295 #endif
1296  || yaz_errno() == EINPROGRESS
1297 #endif
1298  )
1299  {
1300  TRC(fprintf(stderr, " Flow control stop\n"));
1302  return 1;
1303  }
1304  h->cerrno = CSYSERR;
1305  return -1;
1306  }
1307  state->written += res;
1308  TRC(fprintf(stderr, " Wrote %d, written=%d, nbytes=%d\n",
1309  res, state->written, size));
1310  }
1311  state->towrite = state->written = -1;
1312  TRC(fprintf(stderr, " Ok\n"));
1313  return 0;
1314 }
1315 
1316 
1317 #if ENABLE_SSL
1318 /*
1319  * Returns 1, 0 or -1
1320  * In nonblocking mode, you must call again with same buffer while
1321  * return value is 1.
1322  */
1323 int ssl_put(COMSTACK h, char *buf, int size)
1324 {
1325  int res;
1326  struct tcpip_state *state = (struct tcpip_state *)h->cprivate;
1327 
1328  TRC(fprintf(stderr, "ssl_put: size=%d\n", size));
1329  h->io_pending = 0;
1330  h->event = CS_DATA;
1331  if (state->towrite < 0)
1332  {
1333  state->towrite = size;
1334  state->written = 0;
1335  }
1336  else if (state->towrite != size)
1337  {
1338  h->cerrno = CSWRONGBUF;
1339  return -1;
1340  }
1341  while (state->towrite > state->written)
1342  {
1343 #if HAVE_GNUTLS_H
1344  res = gnutls_record_send(state->session, buf + state->written,
1345  size - state->written);
1346  if (res <= 0)
1347  {
1348  if (ssl_check_error(h, state, res))
1349  return 1;
1350  return -1;
1351  }
1352 #else
1353  res = SSL_write(state->ssl, buf + state->written,
1354  size - state->written);
1355  if (res <= 0)
1356  {
1357  if (ssl_check_error(h, state, res))
1358  return 1;
1359  return -1;
1360  }
1361 #endif
1362  state->written += res;
1363  TRC(fprintf(stderr, " Wrote %d, written=%d, nbytes=%d\n",
1364  res, state->written, size));
1365  }
1366  state->towrite = state->written = -1;
1367  TRC(fprintf(stderr, " Ok\n"));
1368  return 0;
1369 }
1370 #endif
1371 
1373 {
1374  tcpip_state *sp = (struct tcpip_state *)h->cprivate;
1375 
1376  TRC(fprintf(stderr, "tcpip_close: h=%p pid=%d\n", h, getpid()));
1377  if (h->iofile != -1)
1378  {
1379 #if HAVE_GNUTLS_H
1380  if (sp->session)
1381  gnutls_bye(sp->session, GNUTLS_SHUT_WR);
1382 #elif HAVE_OPENSSL_SSL_H
1383  if (sp->ssl)
1384  {
1385  SSL_shutdown(sp->ssl);
1386  }
1387 #endif
1388 #ifdef WIN32
1389  closesocket(h->iofile);
1390 #else
1391  close(h->iofile);
1392 #endif
1393  }
1394  if (sp->altbuf)
1395  xfree(sp->altbuf);
1396 #if HAVE_GNUTLS_H
1397  if (sp->session)
1398  {
1399  gnutls_deinit(sp->session);
1400  }
1401  if (sp->cred_ptr)
1402  {
1403  assert(sp->cred_ptr->ref > 0);
1404 
1405  if (--(sp->cred_ptr->ref) == 0)
1406  {
1407  TRC(fprintf(stderr, "Removed credentials %p pid=%d\n",
1408  sp->cred_ptr->xcred, getpid()));
1409  gnutls_certificate_free_credentials(sp->cred_ptr->xcred);
1410  xfree(sp->cred_ptr);
1411  }
1412  sp->cred_ptr = 0;
1413  }
1414 #elif HAVE_OPENSSL_SSL_H
1415  if (sp->ssl)
1416  {
1417  TRC(fprintf(stderr, "SSL_free\n"));
1418  SSL_free(sp->ssl);
1419  }
1420  sp->ssl = 0;
1421  if (sp->ctx_alloc)
1422  SSL_CTX_free(sp->ctx_alloc);
1423 #endif
1424 #if HAVE_GETADDRINFO
1425  if (sp->ai)
1426  freeaddrinfo(sp->ai);
1427 #endif
1430  xfree(sp);
1431  xfree(h);
1432 }
1433 
1434 const char *tcpip_addrstr(COMSTACK h)
1435 {
1436  tcpip_state *sp = (struct tcpip_state *)h->cprivate;
1437  char *r = 0, *buf = sp->buf;
1438 
1439 #if HAVE_GETADDRINFO
1440  char host[120];
1441  struct sockaddr_storage addr;
1442  YAZ_SOCKLEN_T len = sizeof(addr);
1443 
1444  if (getpeername(h->iofile, (struct sockaddr *)&addr, &len) < 0)
1445  {
1446  h->cerrno = CSYSERR;
1447  return 0;
1448  }
1449  if (getnameinfo((struct sockaddr *) &addr, len, host, sizeof(host)-1,
1450  0, 0,
1451  (h->flags & CS_FLAGS_NUMERICHOST) ? NI_NUMERICHOST : 0))
1452  {
1453  r = "unknown";
1454  }
1455  else
1456  r = host;
1457 
1458 #else
1459 
1460  struct sockaddr_in addr;
1461  YAZ_SOCKLEN_T len = sizeof(addr);
1462  struct hostent *host;
1463 
1464  if (getpeername(h->iofile, (struct sockaddr*) &addr, &len) < 0)
1465  {
1466  h->cerrno = CSYSERR;
1467  return 0;
1468  }
1469  if (!(h->flags & CS_FLAGS_NUMERICHOST))
1470  {
1471  if ((host = gethostbyaddr((char*)&addr.sin_addr,
1472  sizeof(addr.sin_addr),
1473  AF_INET)))
1474  r = (char*) host->h_name;
1475  }
1476  if (!r)
1477  r = inet_ntoa(addr.sin_addr);
1478 #endif
1479 
1480  if (h->protocol == PROTO_HTTP)
1481  sprintf(buf, "http:%s", r);
1482  else
1483  sprintf(buf, "tcp:%s", r);
1484 #if HAVE_GNUTLS_H
1485  if (sp->session)
1486  {
1487  if (h->protocol == PROTO_HTTP)
1488  sprintf(buf, "https:%s", r);
1489  else
1490  sprintf(buf, "ssl:%s", r);
1491  }
1492 #elif HAVE_OPENSSL_SSL_H
1493  if (sp->ctx)
1494  {
1495  if (h->protocol == PROTO_HTTP)
1496  sprintf(buf, "https:%s", r);
1497  else
1498  sprintf(buf, "ssl:%s", r);
1499  }
1500 #endif
1501  return buf;
1502 }
1503 
1504 static int tcpip_set_blocking(COMSTACK p, int flags)
1505 {
1506  unsigned long flag;
1507 
1508 #ifdef WIN32
1509  flag = (flags & CS_FLAGS_BLOCKING) ? 0 : 1;
1510  if (ioctlsocket(p->iofile, FIONBIO, &flag) < 0)
1511  return 0;
1512 #else
1513  flag = fcntl(p->iofile, F_GETFL, 0);
1514  if (flags & CS_FLAGS_BLOCKING)
1515  flag = flag & ~O_NONBLOCK; /* blocking */
1516  else
1517  {
1518  flag = flag | O_NONBLOCK; /* non-blocking */
1519  signal(SIGPIPE, SIG_IGN);
1520  }
1521  if (fcntl(p->iofile, F_SETFL, flag) < 0)
1522  return 0;
1523 #endif
1524  p->flags = flags;
1525  return 1;
1526 }
1527 
1528 
1529 #if HAVE_GNUTLS_H
1530 /* gnutls_x509_crt_print appeared in 1.7.6. Memory leaks were fixed in 1.7.9.
1531  GNUTLS_CRT_PRINT_FULL appeared in 2.4.0. */
1532 #if GNUTLS_VERSION_NUMBER >= 0x020400
1533 #define USE_GNUTLS_X509_CRT_PRINT 1
1534 #else
1535 #define USE_GNUTLS_X509_CRT_PRINT 0
1536 #endif
1537 
1538 
1539 #if USE_GNUTLS_X509_CRT_PRINT
1540 #else
1541 static const char *bin2hex(const void *bin, size_t bin_size)
1542 {
1543  static char printable[110];
1544  const unsigned char *_bin = bin;
1545  char *print;
1546  size_t i;
1547  if (bin_size > 50)
1548  bin_size = 50;
1549  print = printable;
1550  for (i = 0; i < bin_size; i++)
1551  {
1552  sprintf(print, "%.2x ", _bin[i]);
1553  print += 2;
1554  }
1555  return printable;
1556 }
1557 
1558 static void x509_crt_print(gnutls_x509_crt_t cert)
1559 {
1560  time_t expiration_time, activation_time;
1561  size_t size;
1562  char serial[40];
1563  char dn[256];
1564  unsigned int algo, bits;
1565 
1566  expiration_time = gnutls_x509_crt_get_expiration_time(cert);
1567  activation_time = gnutls_x509_crt_get_activation_time(cert);
1568 
1569  printf("\tCertificate is valid since: %s", ctime(&activation_time));
1570  printf("\tCertificate expires: %s", ctime(&expiration_time));
1571 
1572  /* Print the serial number of the certificate. */
1573  size = sizeof(serial);
1574  gnutls_x509_crt_get_serial(cert, serial, &size);
1575 
1576  printf("\tCertificate serial number: %s\n", bin2hex(serial, size));
1577 
1578  /* Extract some of the public key algorithm's parameters
1579  */
1580  algo = gnutls_x509_crt_get_pk_algorithm(cert, &bits);
1581 
1582  printf("Certificate public key: %s", gnutls_pk_algorithm_get_name(algo));
1583 
1584  /* Print the version of the X.509 certificate. */
1585  printf("\tCertificate version: #%d\n", gnutls_x509_crt_get_version(cert));
1586 
1587  size = sizeof(dn);
1588  gnutls_x509_crt_get_dn(cert, dn, &size);
1589  printf("\tDN: %s\n", dn);
1590 
1591  size = sizeof(dn);
1592  gnutls_x509_crt_get_issuer_dn(cert, dn, &size);
1593  printf("\tIssuer's DN: %s\n", dn);
1594 }
1595 #endif
1596 #endif
1597 
1599 {
1600 #if HAVE_GNUTLS_H
1601  struct tcpip_state *sp = (struct tcpip_state *) cs->cprivate;
1602  if (cs->type == ssl_type && sp->session)
1603  {
1604  const gnutls_datum_t *cert_list;
1605  unsigned i, cert_list_size;
1606  if (gnutls_certificate_type_get(sp->session) != GNUTLS_CRT_X509)
1607  return;
1608  printf("X509 certificate\n");
1609  cert_list = gnutls_certificate_get_peers(sp->session,
1610  &cert_list_size);
1611  printf("Peer provided %u certificates\n", cert_list_size);
1612  for (i = 0; i < cert_list_size; i++)
1613  {
1614  gnutls_x509_crt_t cert;
1615 #if USE_GNUTLS_X509_CRT_PRINT
1616  int ret;
1617  gnutls_datum_t cinfo;
1618 #endif
1619  gnutls_x509_crt_init(&cert);
1620  gnutls_x509_crt_import(cert, &cert_list[i], GNUTLS_X509_FMT_DER);
1621  printf("Certificate info %d:\n", i + 1);
1622 #if USE_GNUTLS_X509_CRT_PRINT
1623  ret = gnutls_x509_crt_print(cert, GNUTLS_CRT_PRINT_FULL,
1624  &cinfo);
1625  if (ret == 0)
1626  {
1627  printf("\t%s\n", cinfo.data);
1628  gnutls_free(cinfo.data);
1629  }
1630 #else
1631  x509_crt_print(cert);
1632 #endif
1633  gnutls_x509_crt_deinit(cert);
1634 
1635  }
1636  }
1637 #elif HAVE_OPENSSL_SSL_H
1638  if (cs->type == ssl_type)
1639  {
1640  struct tcpip_state *sp = (struct tcpip_state *) cs->cprivate;
1641  SSL *ssl = (SSL *) sp->ssl;
1642  if (ssl)
1643  {
1644  X509 *server_cert = SSL_get_peer_certificate(ssl);
1645  if (server_cert)
1646  {
1647  char *pem_buf;
1648  int pem_len;
1649  BIO *bio = BIO_new(BIO_s_mem());
1650 
1651  /* get PEM buffer in memory */
1652  PEM_write_bio_X509(bio, server_cert);
1653  pem_len = BIO_get_mem_data(bio, &pem_buf);
1654  fwrite(pem_buf, pem_len, 1, stdout);
1655 
1656  /* print all info on screen .. */
1657  X509_print_fp(stdout, server_cert);
1658  BIO_free(bio);
1659 
1660  X509_free(server_cert);
1661  }
1662  }
1663  }
1664 #endif
1665 }
1666 
1668 {
1669 #if HAVE_OPENSSL_SSL_H
1670  if (cs && cs->type == ssl_type)
1671  {
1672  struct tcpip_state *sp = (struct tcpip_state *) cs->cprivate;
1673  return sp->ssl;
1674  }
1675 #endif
1676  return 0;
1677 }
1678 
1679 int cs_set_ssl_ctx(COMSTACK cs, void *ctx)
1680 {
1681 #if ENABLE_SSL
1682  if (cs && cs->type == ssl_type)
1683  {
1684 #if HAVE_OPENSSL_SSL_H
1685  struct tcpip_state *sp = (struct tcpip_state *) cs->cprivate;
1686  if (sp->ctx_alloc)
1687  return 0;
1688  sp->ctx = (SSL_CTX *) ctx;
1689 #endif
1690  return 1;
1691  }
1692 #endif
1693  return 0;
1694 }
1695 
1696 int cs_set_ssl_certificate_file(COMSTACK cs, const char *fname)
1697 {
1698 #if ENABLE_SSL
1699  if (cs && cs->type == ssl_type)
1700  {
1701  struct tcpip_state *sp = (struct tcpip_state *) cs->cprivate;
1702  strncpy(sp->cert_fname, fname, sizeof(sp->cert_fname)-1);
1703  sp->cert_fname[sizeof(sp->cert_fname)-1] = '\0';
1704  return 1;
1705  }
1706 #endif
1707  return 0;
1708 }
1709 
1710 int cs_get_peer_certificate_x509(COMSTACK cs, char **buf, int *len)
1711 {
1712 #if HAVE_OPENSSL_SSL_H
1713  SSL *ssl = (SSL *) cs_get_ssl(cs);
1714  if (ssl)
1715  {
1716  X509 *server_cert = SSL_get_peer_certificate(ssl);
1717  if (server_cert)
1718  {
1719  BIO *bio = BIO_new(BIO_s_mem());
1720  char *pem_buf;
1721  /* get PEM buffer in memory */
1722  PEM_write_bio_X509(bio, server_cert);
1723  *len = BIO_get_mem_data(bio, &pem_buf);
1724  *buf = (char *) xmalloc(*len);
1725  memcpy(*buf, pem_buf, *len);
1726  BIO_free(bio);
1727  return 1;
1728  }
1729  }
1730 #endif
1731  return 0;
1732 }
1733 
1734 static int tcpip_put_connect(COMSTACK h, char *buf, int size)
1735 {
1736  struct tcpip_state *state = (struct tcpip_state *)h->cprivate;
1737 
1738  int r = tcpip_put(h, state->connect_request_buf,
1739  state->connect_request_len);
1740  if (r == 0)
1741  {
1742  /* it's sent */
1743  h->f_put = tcpip_put; /* switch to normal tcpip put */
1744  r = tcpip_put(h, buf, size);
1745  }
1746  return r;
1747 }
1748 
1749 static int tcpip_get_connect(COMSTACK h, char **buf, int *bufsize)
1750 {
1751  struct tcpip_state *state = (struct tcpip_state *)h->cprivate;
1752  int r;
1753 
1754  r = tcpip_get(h, &state->connect_response_buf,
1755  &state->connect_response_len);
1756  if (r < 1)
1757  return r;
1758  /* got the connect response completely */
1759  state->complete = cs_complete_auto; /* switch to normal tcpip get */
1760  h->f_get = tcpip_get;
1761  return tcpip_get(h, buf, bufsize);
1762 }
1763 
1764 
1765 /*
1766  * Local variables:
1767  * c-basic-offset: 4
1768  * c-file-style: "Stroustrup"
1769  * indent-tabs-mode: nil
1770  * End:
1771  * vim: shiftwidth=4 tabstop=8 expandtab
1772  */
1773