1/*
2     This file is part of libmicrohttpd
3     Copyright (C) 2007 Christian Grothoff
4
5     libmicrohttpd is free software; you can redistribute it and/or modify
6     it under the terms of the GNU General Public License as published
7     by the Free Software Foundation; either version 2, or (at your
8     option) any later version.
9
10     libmicrohttpd is distributed in the hope that it will be useful, but
11     WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13     General Public License for more details.
14
15     You should have received a copy of the GNU General Public License
16     along with libmicrohttpd; see the file COPYING.  If not, write to the
17     Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18     Boston, MA 02111-1307, USA.
19*/
20
21/**
22 * @file curl_version_check.c
23 * @brief  verify required cURL version is available to run tests
24 * @author Sagie Amir
25 */
26
27#include "MHD_config.h"
28#include "platform.h"
29#include <curl/curl.h>
30
31#ifndef WINDOWS
32#include <unistd.h>
33#endif
34
35static int
36parse_version_number (const char **s)
37{
38  int i = 0;
39  char num[17];
40
41  while (i < 16 && ((**s >= '0') & (**s <= '9')))
42    {
43      num[i] = **s;
44      (*s)++;
45      i++;
46    }
47
48  num[i] = '\0';
49
50  return atoi (num);
51}
52
53const char *
54parse_version_string (const char *s, int *major, int *minor, int *micro)
55{
56  if (!s)
57    return NULL;
58  *major = parse_version_number (&s);
59  if (*s != '.')
60    return NULL;
61  s++;
62  *minor = parse_version_number (&s);
63  if (*s != '.')
64    return NULL;
65  s++;
66  *micro = parse_version_number (&s);
67  return s;
68}
69
70#if HTTPS_SUPPORT
71int
72curl_uses_nss_ssl()
73{
74  return (strstr(curl_version(), " NSS/") != NULL) ? 0 : -1;
75}
76#endif
77
78/*
79 * check local libcurl version matches required version
80 */
81int
82curl_check_version (const char *req_version)
83{
84  const char *ver;
85  const char *curl_ver;
86#if HTTPS_SUPPORT
87  const char *ssl_ver;
88  const char *req_ssl_ver;
89#endif
90
91  int loc_major, loc_minor, loc_micro;
92  int rq_major, rq_minor, rq_micro;
93
94  ver = curl_version ();
95#if HAVE_MESSAGES
96  fprintf (stderr, "curl version: %s\n", ver);
97#endif
98  /*
99   * this call relies on the cURL string to be of the exact following format :
100   * 'libcurl/7.16.4 OpenSSL/0.9.8g zlib/1.2.3.3 libidn/0.6.5' OR
101   * 'libcurl/7.18.2 GnuTLS/2.4.0 zlib/1.2.3.3 libidn/0.6.5'
102   */
103  curl_ver = strchr (ver, '/');
104  if (curl_ver == NULL)
105    return -1;
106  curl_ver++;
107  /* Parse version numbers */
108  if ( (NULL == parse_version_string (req_version, &rq_major, &rq_minor, &rq_micro)) ||
109       (NULL == parse_version_string (curl_ver, &loc_major, &loc_minor, &loc_micro)) )
110    return -1;
111
112  /* Compare version numbers.  */
113  if ((loc_major > rq_major
114       || (loc_major == rq_major && loc_minor > rq_minor)
115       || (loc_major == rq_major && loc_minor == rq_minor
116           && loc_micro > rq_micro) || (loc_major == rq_major
117                                        && loc_minor == rq_minor
118                                        && loc_micro == rq_micro)) == 0)
119    {
120      fprintf (stderr,
121               "Error: running curl test depends on local libcurl version > %s\n",
122               req_version);
123      return -1;
124    }
125
126  /*
127   * enforce required gnutls/openssl version.
128   * TODO use curl version string to assert use of gnutls
129   */
130#if HTTPS_SUPPORT
131  ssl_ver = strchr (curl_ver, ' ');
132  if (ssl_ver == NULL)
133    return -1;
134  ssl_ver++;
135  if (strncmp ("GnuTLS", ssl_ver, strlen ("GNUtls")) == 0)
136    {
137      ssl_ver = strchr (ssl_ver, '/');
138      req_ssl_ver = MHD_REQ_CURL_GNUTLS_VERSION;
139    }
140  else if (strncmp ("OpenSSL", ssl_ver, strlen ("OpenSSL")) == 0)
141    {
142      ssl_ver = strchr (ssl_ver, '/');
143      req_ssl_ver = MHD_REQ_CURL_OPENSSL_VERSION;
144    }
145  else if (strncmp ("NSS", ssl_ver, strlen ("NSS")) == 0)
146    {
147      ssl_ver = strchr (ssl_ver, '/');
148      req_ssl_ver = MHD_REQ_CURL_NSS_VERSION;
149    }
150  else
151    {
152      fprintf (stderr, "Error: unrecognized curl ssl library\n");
153      return -1;
154    }
155  if (ssl_ver == NULL)
156    return -1;
157  ssl_ver++;
158  if ( (NULL == parse_version_string (req_ssl_ver, &rq_major, &rq_minor, &rq_micro)) ||
159       (NULL == parse_version_string (ssl_ver, &loc_major, &loc_minor, &loc_micro)) )
160    return -1;
161
162  if ((loc_major > rq_major
163       || (loc_major == rq_major && loc_minor > rq_minor)
164       || (loc_major == rq_major && loc_minor == rq_minor
165           && loc_micro > rq_micro) || (loc_major == rq_major
166                                        && loc_minor == rq_minor
167                                        && loc_micro == rq_micro)) == 0)
168    {
169      fprintf (stderr,
170               "Error: running curl test depends on local libcurl SSL version > %s\n",
171               req_ssl_ver);
172      return -1;
173    }
174#endif
175  return 0;
176}
177