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