1 | /*************************************************************************** |
2 | * _ _ ____ _ |
3 | * Project ___| | | | _ \| | |
4 | * / __| | | | |_) | | |
5 | * | (__| |_| | _ <| |___ |
6 | * \___|\___/|_| \_\_____| |
7 | * |
8 | * Copyright (C) 1998 - 2022, Daniel Stenberg, <[email protected]>, et al. |
9 | * |
10 | * This software is licensed as described in the file COPYING, which |
11 | * you should have received as part of this distribution. The terms |
12 | * are also available at https://curl.se/docs/copyright.html. |
13 | * |
14 | * You may opt to use, copy, modify, merge, publish, distribute and/or sell |
15 | * copies of the Software, and permit persons to whom the Software is |
16 | * furnished to do so, under the terms of the COPYING file. |
17 | * |
18 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY |
19 | * KIND, either express or implied. |
20 | * |
21 | * SPDX-License-Identifier: curl |
22 | * |
23 | ***************************************************************************/ |
24 | |
25 | #include "curl_setup.h" |
26 | |
27 | #include <curl/curl.h> |
28 | #include "urldata.h" |
29 | #include "vtls/vtls.h" |
30 | #include "http2.h" |
31 | #include "vssh/ssh.h" |
32 | #include "quic.h" |
33 | #include "curl_printf.h" |
34 | #include "easy_lock.h" |
35 | |
36 | #ifdef USE_ARES |
37 | # if defined(CURL_STATICLIB) && !defined(CARES_STATICLIB) && \ |
38 | defined(WIN32) |
39 | # define CARES_STATICLIB |
40 | # endif |
41 | # include <ares.h> |
42 | #endif |
43 | |
44 | #ifdef USE_LIBIDN2 |
45 | #include <idn2.h> |
46 | #endif |
47 | |
48 | #ifdef USE_LIBPSL |
49 | #include <libpsl.h> |
50 | #endif |
51 | |
52 | #ifdef USE_LIBRTMP |
53 | #include <librtmp/rtmp.h> |
54 | #endif |
55 | |
56 | #ifdef HAVE_ZLIB_H |
57 | #include <zlib.h> |
58 | #endif |
59 | |
60 | #ifdef HAVE_BROTLI |
61 | #include <brotli/decode.h> |
62 | #endif |
63 | |
64 | #ifdef HAVE_ZSTD |
65 | #include <zstd.h> |
66 | #endif |
67 | |
68 | #ifdef USE_GSASL |
69 | #include <gsasl.h> |
70 | #endif |
71 | |
72 | #ifdef USE_OPENLDAP |
73 | #include <ldap.h> |
74 | #endif |
75 | |
76 | #ifdef HAVE_BROTLI |
77 | static void brotli_version(char *buf, size_t bufsz) |
78 | { |
79 | uint32_t brotli_version = BrotliDecoderVersion(); |
80 | unsigned int major = brotli_version >> 24; |
81 | unsigned int minor = (brotli_version & 0x00FFFFFF) >> 12; |
82 | unsigned int patch = brotli_version & 0x00000FFF; |
83 | (void)msnprintf(buf, bufsz, "%u.%u.%u" , major, minor, patch); |
84 | } |
85 | #endif |
86 | |
87 | #ifdef HAVE_ZSTD |
88 | static void zstd_version(char *buf, size_t bufsz) |
89 | { |
90 | unsigned long zstd_version = (unsigned long)ZSTD_versionNumber(); |
91 | unsigned int major = (unsigned int)(zstd_version / (100 * 100)); |
92 | unsigned int minor = (unsigned int)((zstd_version - |
93 | (major * 100 * 100)) / 100); |
94 | unsigned int patch = (unsigned int)(zstd_version - |
95 | (major * 100 * 100) - (minor * 100)); |
96 | (void)msnprintf(buf, bufsz, "%u.%u.%u" , major, minor, patch); |
97 | } |
98 | #endif |
99 | |
100 | /* |
101 | * curl_version() returns a pointer to a static buffer. |
102 | * |
103 | * It is implemented to work multi-threaded by making sure repeated invokes |
104 | * generate the exact same string and never write any temporary data like |
105 | * zeros in the data. |
106 | */ |
107 | |
108 | #define VERSION_PARTS 16 /* number of substrings we can concatenate */ |
109 | |
110 | char *curl_version(void) |
111 | { |
112 | static char out[300]; |
113 | char *outp; |
114 | size_t outlen; |
115 | const char *src[VERSION_PARTS]; |
116 | #ifdef USE_SSL |
117 | char ssl_version[200]; |
118 | #endif |
119 | #ifdef HAVE_LIBZ |
120 | char z_version[40]; |
121 | #endif |
122 | #ifdef HAVE_BROTLI |
123 | char br_version[40] = "brotli/" ; |
124 | #endif |
125 | #ifdef HAVE_ZSTD |
126 | char zst_version[40] = "zstd/" ; |
127 | #endif |
128 | #ifdef USE_ARES |
129 | char cares_version[40]; |
130 | #endif |
131 | #if defined(USE_LIBIDN2) |
132 | char idn_version[40]; |
133 | #endif |
134 | #ifdef USE_LIBPSL |
135 | char psl_version[40]; |
136 | #endif |
137 | #ifdef USE_SSH |
138 | char ssh_version[40]; |
139 | #endif |
140 | #ifdef USE_NGHTTP2 |
141 | char h2_version[40]; |
142 | #endif |
143 | #ifdef ENABLE_QUIC |
144 | char h3_version[40]; |
145 | #endif |
146 | #ifdef USE_LIBRTMP |
147 | char rtmp_version[40]; |
148 | #endif |
149 | #ifdef USE_HYPER |
150 | char hyper_buf[30]; |
151 | #endif |
152 | #ifdef USE_GSASL |
153 | char gsasl_buf[30]; |
154 | #endif |
155 | #ifdef USE_OPENLDAP |
156 | char ldap_buf[30]; |
157 | #endif |
158 | int i = 0; |
159 | int j; |
160 | |
161 | #ifdef DEBUGBUILD |
162 | /* Override version string when environment variable CURL_VERSION is set */ |
163 | const char *debugversion = getenv("CURL_VERSION" ); |
164 | if(debugversion) { |
165 | strncpy(out, debugversion, sizeof(out)-1); |
166 | out[sizeof(out)-1] = '\0'; |
167 | return out; |
168 | } |
169 | #endif |
170 | |
171 | src[i++] = LIBCURL_NAME "/" LIBCURL_VERSION; |
172 | #ifdef USE_SSL |
173 | Curl_ssl_version(ssl_version, sizeof(ssl_version)); |
174 | src[i++] = ssl_version; |
175 | #endif |
176 | #ifdef HAVE_LIBZ |
177 | msnprintf(z_version, sizeof(z_version), "zlib/%s" , zlibVersion()); |
178 | src[i++] = z_version; |
179 | #endif |
180 | #ifdef HAVE_BROTLI |
181 | brotli_version(&br_version[7], sizeof(br_version) - 7); |
182 | src[i++] = br_version; |
183 | #endif |
184 | #ifdef HAVE_ZSTD |
185 | zstd_version(&zst_version[5], sizeof(zst_version) - 5); |
186 | src[i++] = zst_version; |
187 | #endif |
188 | #ifdef USE_ARES |
189 | msnprintf(cares_version, sizeof(cares_version), |
190 | "c-ares/%s" , ares_version(NULL)); |
191 | src[i++] = cares_version; |
192 | #endif |
193 | #ifdef USE_LIBIDN2 |
194 | msnprintf(idn_version, sizeof(idn_version), |
195 | "libidn2/%s" , idn2_check_version(NULL)); |
196 | src[i++] = idn_version; |
197 | #elif defined(USE_WIN32_IDN) |
198 | src[i++] = (char *)"WinIDN" ; |
199 | #endif |
200 | |
201 | #ifdef USE_LIBPSL |
202 | msnprintf(psl_version, sizeof(psl_version), "libpsl/%s" , psl_get_version()); |
203 | src[i++] = psl_version; |
204 | #endif |
205 | |
206 | #ifdef USE_SSH |
207 | Curl_ssh_version(ssh_version, sizeof(ssh_version)); |
208 | src[i++] = ssh_version; |
209 | #endif |
210 | #ifdef USE_NGHTTP2 |
211 | Curl_http2_ver(h2_version, sizeof(h2_version)); |
212 | src[i++] = h2_version; |
213 | #endif |
214 | #ifdef ENABLE_QUIC |
215 | Curl_quic_ver(h3_version, sizeof(h3_version)); |
216 | src[i++] = h3_version; |
217 | #endif |
218 | #ifdef USE_LIBRTMP |
219 | { |
220 | char suff[2]; |
221 | if(RTMP_LIB_VERSION & 0xff) { |
222 | suff[0] = (RTMP_LIB_VERSION & 0xff) + 'a' - 1; |
223 | suff[1] = '\0'; |
224 | } |
225 | else |
226 | suff[0] = '\0'; |
227 | |
228 | msnprintf(rtmp_version, sizeof(rtmp_version), "librtmp/%d.%d%s" , |
229 | RTMP_LIB_VERSION >> 16, (RTMP_LIB_VERSION >> 8) & 0xff, |
230 | suff); |
231 | src[i++] = rtmp_version; |
232 | } |
233 | #endif |
234 | #ifdef USE_HYPER |
235 | msnprintf(hyper_buf, sizeof(hyper_buf), "Hyper/%s" , hyper_version()); |
236 | src[i++] = hyper_buf; |
237 | #endif |
238 | #ifdef USE_GSASL |
239 | msnprintf(gsasl_buf, sizeof(gsasl_buf), "libgsasl/%s" , |
240 | gsasl_check_version(NULL)); |
241 | src[i++] = gsasl_buf; |
242 | #endif |
243 | #ifdef USE_OPENLDAP |
244 | { |
245 | LDAPAPIInfo api; |
246 | api.ldapai_info_version = LDAP_API_INFO_VERSION; |
247 | |
248 | if(ldap_get_option(NULL, LDAP_OPT_API_INFO, &api) == LDAP_OPT_SUCCESS) { |
249 | unsigned int patch = api.ldapai_vendor_version % 100; |
250 | unsigned int major = api.ldapai_vendor_version / 10000; |
251 | unsigned int minor = |
252 | ((api.ldapai_vendor_version - major * 10000) - patch) / 100; |
253 | msnprintf(ldap_buf, sizeof(ldap_buf), "%s/%u.%u.%u" , |
254 | api.ldapai_vendor_name, major, minor, patch); |
255 | src[i++] = ldap_buf; |
256 | ldap_memfree(api.ldapai_vendor_name); |
257 | ber_memvfree((void **)api.ldapai_extensions); |
258 | } |
259 | } |
260 | #endif |
261 | |
262 | DEBUGASSERT(i <= VERSION_PARTS); |
263 | |
264 | outp = &out[0]; |
265 | outlen = sizeof(out); |
266 | for(j = 0; j < i; j++) { |
267 | size_t n = strlen(src[j]); |
268 | /* we need room for a space, the string and the final zero */ |
269 | if(outlen <= (n + 2)) |
270 | break; |
271 | if(j) { |
272 | /* prepend a space if not the first */ |
273 | *outp++ = ' '; |
274 | outlen--; |
275 | } |
276 | memcpy(outp, src[j], n); |
277 | outp += n; |
278 | outlen -= n; |
279 | } |
280 | *outp = 0; |
281 | |
282 | return out; |
283 | } |
284 | |
285 | /* data for curl_version_info |
286 | |
287 | Keep the list sorted alphabetically. It is also written so that each |
288 | protocol line has its own #if line to make things easier on the eye. |
289 | */ |
290 | |
291 | static const char * const protocols[] = { |
292 | #ifndef CURL_DISABLE_DICT |
293 | "dict" , |
294 | #endif |
295 | #ifndef CURL_DISABLE_FILE |
296 | "file" , |
297 | #endif |
298 | #ifndef CURL_DISABLE_FTP |
299 | "ftp" , |
300 | #endif |
301 | #if defined(USE_SSL) && !defined(CURL_DISABLE_FTP) |
302 | "ftps" , |
303 | #endif |
304 | #ifndef CURL_DISABLE_GOPHER |
305 | "gopher" , |
306 | #endif |
307 | #if defined(USE_SSL) && !defined(CURL_DISABLE_GOPHER) |
308 | "gophers" , |
309 | #endif |
310 | #ifndef CURL_DISABLE_HTTP |
311 | "http" , |
312 | #endif |
313 | #if defined(USE_SSL) && !defined(CURL_DISABLE_HTTP) |
314 | "https" , |
315 | #endif |
316 | #ifndef CURL_DISABLE_IMAP |
317 | "imap" , |
318 | #endif |
319 | #if defined(USE_SSL) && !defined(CURL_DISABLE_IMAP) |
320 | "imaps" , |
321 | #endif |
322 | #ifndef CURL_DISABLE_LDAP |
323 | "ldap" , |
324 | #if !defined(CURL_DISABLE_LDAPS) && \ |
325 | ((defined(USE_OPENLDAP) && defined(USE_SSL)) || \ |
326 | (!defined(USE_OPENLDAP) && defined(HAVE_LDAP_SSL))) |
327 | "ldaps" , |
328 | #endif |
329 | #endif |
330 | #ifndef CURL_DISABLE_MQTT |
331 | "mqtt" , |
332 | #endif |
333 | #ifndef CURL_DISABLE_POP3 |
334 | "pop3" , |
335 | #endif |
336 | #if defined(USE_SSL) && !defined(CURL_DISABLE_POP3) |
337 | "pop3s" , |
338 | #endif |
339 | #ifdef USE_LIBRTMP |
340 | "rtmp" , |
341 | #endif |
342 | #ifndef CURL_DISABLE_RTSP |
343 | "rtsp" , |
344 | #endif |
345 | #if defined(USE_SSH) && !defined(USE_WOLFSSH) |
346 | "scp" , |
347 | #endif |
348 | #ifdef USE_SSH |
349 | "sftp" , |
350 | #endif |
351 | #if !defined(CURL_DISABLE_SMB) && defined(USE_CURL_NTLM_CORE) && \ |
352 | (SIZEOF_CURL_OFF_T > 4) |
353 | "smb" , |
354 | # ifdef USE_SSL |
355 | "smbs" , |
356 | # endif |
357 | #endif |
358 | #ifndef CURL_DISABLE_SMTP |
359 | "smtp" , |
360 | #endif |
361 | #if defined(USE_SSL) && !defined(CURL_DISABLE_SMTP) |
362 | "smtps" , |
363 | #endif |
364 | #ifndef CURL_DISABLE_TELNET |
365 | "telnet" , |
366 | #endif |
367 | #ifndef CURL_DISABLE_TFTP |
368 | "tftp" , |
369 | #endif |
370 | |
371 | NULL |
372 | }; |
373 | |
374 | static curl_version_info_data version_info = { |
375 | CURLVERSION_NOW, |
376 | LIBCURL_VERSION, |
377 | LIBCURL_VERSION_NUM, |
378 | OS, /* as found by configure or set by hand at build-time */ |
379 | 0 /* features is 0 by default */ |
380 | #ifdef ENABLE_IPV6 |
381 | | CURL_VERSION_IPV6 |
382 | #endif |
383 | #ifdef USE_SSL |
384 | | CURL_VERSION_SSL |
385 | #endif |
386 | #ifdef USE_NTLM |
387 | | CURL_VERSION_NTLM |
388 | #endif |
389 | #if !defined(CURL_DISABLE_HTTP) && defined(USE_NTLM) && \ |
390 | defined(NTLM_WB_ENABLED) |
391 | | CURL_VERSION_NTLM_WB |
392 | #endif |
393 | #ifdef USE_SPNEGO |
394 | | CURL_VERSION_SPNEGO |
395 | #endif |
396 | #ifdef USE_KERBEROS5 |
397 | | CURL_VERSION_KERBEROS5 |
398 | #endif |
399 | #ifdef HAVE_GSSAPI |
400 | | CURL_VERSION_GSSAPI |
401 | #endif |
402 | #ifdef USE_WINDOWS_SSPI |
403 | | CURL_VERSION_SSPI |
404 | #endif |
405 | #ifdef HAVE_LIBZ |
406 | | CURL_VERSION_LIBZ |
407 | #endif |
408 | #ifdef DEBUGBUILD |
409 | | CURL_VERSION_DEBUG |
410 | #endif |
411 | #ifdef CURLDEBUG |
412 | | CURL_VERSION_CURLDEBUG |
413 | #endif |
414 | #ifdef CURLRES_ASYNCH |
415 | | CURL_VERSION_ASYNCHDNS |
416 | #endif |
417 | #if (SIZEOF_CURL_OFF_T > 4) && \ |
418 | ( (SIZEOF_OFF_T > 4) || defined(USE_WIN32_LARGE_FILES) ) |
419 | | CURL_VERSION_LARGEFILE |
420 | #endif |
421 | #if defined(WIN32) && defined(UNICODE) && defined(_UNICODE) |
422 | | CURL_VERSION_UNICODE |
423 | #endif |
424 | #if defined(USE_TLS_SRP) |
425 | | CURL_VERSION_TLSAUTH_SRP |
426 | #endif |
427 | #if defined(USE_NGHTTP2) || defined(USE_HYPER) |
428 | | CURL_VERSION_HTTP2 |
429 | #endif |
430 | #if defined(ENABLE_QUIC) |
431 | | CURL_VERSION_HTTP3 |
432 | #endif |
433 | #if defined(USE_UNIX_SOCKETS) |
434 | | CURL_VERSION_UNIX_SOCKETS |
435 | #endif |
436 | #if defined(USE_LIBPSL) |
437 | | CURL_VERSION_PSL |
438 | #endif |
439 | #if defined(CURL_WITH_MULTI_SSL) |
440 | | CURL_VERSION_MULTI_SSL |
441 | #endif |
442 | #if defined(HAVE_BROTLI) |
443 | | CURL_VERSION_BROTLI |
444 | #endif |
445 | #if defined(HAVE_ZSTD) |
446 | | CURL_VERSION_ZSTD |
447 | #endif |
448 | #ifndef CURL_DISABLE_ALTSVC |
449 | | CURL_VERSION_ALTSVC |
450 | #endif |
451 | #ifndef CURL_DISABLE_HSTS |
452 | | CURL_VERSION_HSTS |
453 | #endif |
454 | #if defined(USE_GSASL) |
455 | | CURL_VERSION_GSASL |
456 | #endif |
457 | #if defined(GLOBAL_INIT_IS_THREADSAFE) |
458 | | CURL_VERSION_THREADSAFE |
459 | #endif |
460 | , |
461 | NULL, /* ssl_version */ |
462 | 0, /* ssl_version_num, this is kept at zero */ |
463 | NULL, /* zlib_version */ |
464 | protocols, |
465 | NULL, /* c-ares version */ |
466 | 0, /* c-ares version numerical */ |
467 | NULL, /* libidn version */ |
468 | 0, /* iconv version */ |
469 | NULL, /* ssh lib version */ |
470 | 0, /* brotli_ver_num */ |
471 | NULL, /* brotli version */ |
472 | 0, /* nghttp2 version number */ |
473 | NULL, /* nghttp2 version string */ |
474 | NULL, /* quic library string */ |
475 | #ifdef CURL_CA_BUNDLE |
476 | CURL_CA_BUNDLE, /* cainfo */ |
477 | #else |
478 | NULL, |
479 | #endif |
480 | #ifdef CURL_CA_PATH |
481 | CURL_CA_PATH, /* capath */ |
482 | #else |
483 | NULL, |
484 | #endif |
485 | 0, /* zstd_ver_num */ |
486 | NULL, /* zstd version */ |
487 | NULL, /* Hyper version */ |
488 | NULL /* gsasl version */ |
489 | }; |
490 | |
491 | curl_version_info_data *curl_version_info(CURLversion stamp) |
492 | { |
493 | #if defined(USE_SSH) |
494 | static char ssh_buffer[80]; |
495 | #endif |
496 | #ifdef USE_SSL |
497 | #ifdef CURL_WITH_MULTI_SSL |
498 | static char ssl_buffer[200]; |
499 | #else |
500 | static char ssl_buffer[80]; |
501 | #endif |
502 | #endif |
503 | #ifdef HAVE_BROTLI |
504 | static char brotli_buffer[80]; |
505 | #endif |
506 | #ifdef HAVE_ZSTD |
507 | static char zstd_buffer[80]; |
508 | #endif |
509 | |
510 | #ifdef USE_SSL |
511 | Curl_ssl_version(ssl_buffer, sizeof(ssl_buffer)); |
512 | version_info.ssl_version = ssl_buffer; |
513 | #ifndef CURL_DISABLE_PROXY |
514 | if(Curl_ssl->supports & SSLSUPP_HTTPS_PROXY) |
515 | version_info.features |= CURL_VERSION_HTTPS_PROXY; |
516 | else |
517 | version_info.features &= ~CURL_VERSION_HTTPS_PROXY; |
518 | #endif |
519 | #endif |
520 | |
521 | #ifdef HAVE_LIBZ |
522 | version_info.libz_version = zlibVersion(); |
523 | /* libz left NULL if non-existing */ |
524 | #endif |
525 | #ifdef USE_ARES |
526 | { |
527 | int aresnum; |
528 | version_info.ares = ares_version(&aresnum); |
529 | version_info.ares_num = aresnum; |
530 | } |
531 | #endif |
532 | #ifdef USE_LIBIDN2 |
533 | /* This returns a version string if we use the given version or later, |
534 | otherwise it returns NULL */ |
535 | version_info.libidn = idn2_check_version(IDN2_VERSION); |
536 | if(version_info.libidn) |
537 | version_info.features |= CURL_VERSION_IDN; |
538 | #elif defined(USE_WIN32_IDN) |
539 | version_info.features |= CURL_VERSION_IDN; |
540 | #endif |
541 | |
542 | #if defined(USE_SSH) |
543 | Curl_ssh_version(ssh_buffer, sizeof(ssh_buffer)); |
544 | version_info.libssh_version = ssh_buffer; |
545 | #endif |
546 | |
547 | #ifdef HAVE_BROTLI |
548 | version_info.brotli_ver_num = BrotliDecoderVersion(); |
549 | brotli_version(brotli_buffer, sizeof(brotli_buffer)); |
550 | version_info.brotli_version = brotli_buffer; |
551 | #endif |
552 | |
553 | #ifdef HAVE_ZSTD |
554 | version_info.zstd_ver_num = (unsigned int)ZSTD_versionNumber(); |
555 | zstd_version(zstd_buffer, sizeof(zstd_buffer)); |
556 | version_info.zstd_version = zstd_buffer; |
557 | #endif |
558 | |
559 | #ifdef USE_NGHTTP2 |
560 | { |
561 | nghttp2_info *h2 = nghttp2_version(0); |
562 | version_info.nghttp2_ver_num = h2->version_num; |
563 | version_info.nghttp2_version = h2->version_str; |
564 | } |
565 | #endif |
566 | |
567 | #ifdef ENABLE_QUIC |
568 | { |
569 | static char quicbuffer[80]; |
570 | Curl_quic_ver(quicbuffer, sizeof(quicbuffer)); |
571 | version_info.quic_version = quicbuffer; |
572 | } |
573 | #endif |
574 | |
575 | #ifdef USE_HYPER |
576 | { |
577 | static char hyper_buffer[30]; |
578 | msnprintf(hyper_buffer, sizeof(hyper_buffer), "Hyper/%s" , hyper_version()); |
579 | version_info.hyper_version = hyper_buffer; |
580 | } |
581 | #endif |
582 | |
583 | #ifdef USE_GSASL |
584 | { |
585 | version_info.gsasl_version = gsasl_check_version(NULL); |
586 | } |
587 | #endif |
588 | |
589 | (void)stamp; /* avoid compiler warnings, we don't use this */ |
590 | return &version_info; |
591 | } |
592 | |