• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /***************************************************************************
2  *                                  _   _ ____  _
3  *  Project                     ___| | | |  _ \| |
4  *                             / __| | | | |_) | |
5  *                            | (__| |_| |  _ <| |___
6  *                             \___|\___/|_| \_\_____|
7  *
8  * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, 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 #include "tool_setup.h"
25 
26 #include "strcase.h"
27 
28 #include "curlx.h"
29 
30 #include "tool_libinfo.h"
31 
32 #include "memdebug.h" /* keep this as LAST include */
33 
34 /* global variable definitions, for libcurl runtime info */
35 
36 static const char *no_protos = NULL;
37 
38 curl_version_info_data *curlinfo = NULL;
39 const char * const *built_in_protos = &no_protos;
40 
41 size_t proto_count = 0;
42 
43 const char *proto_file = NULL;
44 const char *proto_ftp = NULL;
45 const char *proto_ftps = NULL;
46 const char *proto_http = NULL;
47 const char *proto_https = NULL;
48 const char *proto_rtsp = NULL;
49 const char *proto_scp = NULL;
50 const char *proto_sftp = NULL;
51 const char *proto_tftp = NULL;
52 #ifndef CURL_DISABLE_IPFS
53 const char *proto_ipfs = "ipfs";
54 const char *proto_ipns = "ipns";
55 #endif /* !CURL_DISABLE_IPFS */
56 
57 static struct proto_name_tokenp {
58   const char   *proto_name;
59   const char  **proto_tokenp;
60 } const possibly_built_in[] = {
61   { "file",     &proto_file  },
62   { "ftp",      &proto_ftp   },
63   { "ftps",     &proto_ftps  },
64   { "http",     &proto_http  },
65   { "https",    &proto_https },
66   { "rtsp",     &proto_rtsp  },
67   { "scp",      &proto_scp   },
68   { "sftp",     &proto_sftp  },
69   { "tftp",     &proto_tftp  },
70   {  NULL,      NULL         }
71 };
72 
73 bool feature_altsvc = FALSE;
74 bool feature_brotli = FALSE;
75 bool feature_hsts = FALSE;
76 bool feature_http2 = FALSE;
77 bool feature_http3 = FALSE;
78 bool feature_httpsproxy = FALSE;
79 bool feature_libz = FALSE;
80 bool feature_libssh2 = FALSE;
81 bool feature_ntlm = FALSE;
82 bool feature_ntlm_wb = FALSE;
83 bool feature_spnego = FALSE;
84 bool feature_ssl = FALSE;
85 bool feature_tls_srp = FALSE;
86 bool feature_zstd = FALSE;
87 bool feature_ech = FALSE;
88 bool feature_ssls_export = FALSE;
89 
90 static struct feature_name_presentp {
91   const char   *feature_name;
92   bool         *feature_presentp;
93   int           feature_bitmask;
94 } const maybe_feature[] = {
95   /* Keep alphabetically sorted. */
96   {"alt-svc",        &feature_altsvc,     CURL_VERSION_ALTSVC},
97   {"AsynchDNS",      NULL,                CURL_VERSION_ASYNCHDNS},
98   {"brotli",         &feature_brotli,     CURL_VERSION_BROTLI},
99   {"CharConv",       NULL,                CURL_VERSION_CONV},
100   {"Debug",          NULL,                CURL_VERSION_DEBUG},
101   {"ECH",            &feature_ech,        0},
102   {"gsasl",          NULL,                CURL_VERSION_GSASL},
103   {"GSS-API",        NULL,                CURL_VERSION_GSSAPI},
104   {"HSTS",           &feature_hsts,       CURL_VERSION_HSTS},
105   {"HTTP2",          &feature_http2,      CURL_VERSION_HTTP2},
106   {"HTTP3",          &feature_http3,      CURL_VERSION_HTTP3},
107   {"HTTPS-proxy",    &feature_httpsproxy, CURL_VERSION_HTTPS_PROXY},
108   {"IDN",            NULL,                CURL_VERSION_IDN},
109   {"IPv6",           NULL,                CURL_VERSION_IPV6},
110   {"Kerberos",       NULL,                CURL_VERSION_KERBEROS5},
111   {"Largefile",      NULL,                CURL_VERSION_LARGEFILE},
112   {"libz",           &feature_libz,       CURL_VERSION_LIBZ},
113   {"MultiSSL",       NULL,                CURL_VERSION_MULTI_SSL},
114   {"NTLM",           &feature_ntlm,       CURL_VERSION_NTLM},
115   {"NTLM_WB",        &feature_ntlm_wb,    CURL_VERSION_NTLM_WB},
116   {"PSL",            NULL,                CURL_VERSION_PSL},
117   {"SPNEGO",         &feature_spnego,     CURL_VERSION_SPNEGO},
118   {"SSL",            &feature_ssl,        CURL_VERSION_SSL},
119   {"SSPI",           NULL,                CURL_VERSION_SSPI},
120   {"SSLS-EXPORT",    &feature_ssls_export, 0},
121   {"threadsafe",     NULL,                CURL_VERSION_THREADSAFE},
122   {"TLS-SRP",        &feature_tls_srp,    CURL_VERSION_TLSAUTH_SRP},
123   {"TrackMemory",    NULL,                CURL_VERSION_CURLDEBUG},
124   {"Unicode",        NULL,                CURL_VERSION_UNICODE},
125   {"UnixSockets",    NULL,                CURL_VERSION_UNIX_SOCKETS},
126   {"zstd",           &feature_zstd,       CURL_VERSION_ZSTD},
127   {NULL,             NULL,                0}
128 };
129 
130 static const char *fnames[sizeof(maybe_feature) / sizeof(maybe_feature[0])];
131 const char * const *feature_names = fnames;
132 size_t feature_count;
133 
134 /*
135  * libcurl_info_init: retrieves runtime information about libcurl,
136  * setting a global pointer 'curlinfo' to libcurl's runtime info
137  * struct, count protocols and flag those we are interested in.
138  * Global pointer feature_names is set to the feature names array. If
139  * the latter is not returned by curl_version_info(), it is built from
140  * the returned features bit mask.
141  */
142 
get_libcurl_info(void)143 CURLcode get_libcurl_info(void)
144 {
145   CURLcode result = CURLE_OK;
146   const char *const *builtin;
147 
148   /* Pointer to libcurl's runtime version information */
149   curlinfo = curl_version_info(CURLVERSION_NOW);
150   if(!curlinfo)
151     return CURLE_FAILED_INIT;
152 
153   if(curlinfo->protocols) {
154     const struct proto_name_tokenp *p;
155 
156     built_in_protos = curlinfo->protocols;
157 
158     for(builtin = built_in_protos; !result && *builtin; builtin++) {
159       /* Identify protocols we are interested in. */
160       for(p = possibly_built_in; p->proto_name; p++)
161         if(curl_strequal(p->proto_name, *builtin)) {
162           *p->proto_tokenp = *builtin;
163           break;
164         }
165     }
166     proto_count = builtin - built_in_protos;
167   }
168 
169   if(curlinfo->age >= CURLVERSION_ELEVENTH && curlinfo->feature_names)
170     feature_names = curlinfo->feature_names;
171   else {
172     const struct feature_name_presentp *p;
173     const char **cpp = fnames;
174 
175     for(p = maybe_feature; p->feature_name; p++)
176       if(curlinfo->features & p->feature_bitmask)
177         *cpp++ = p->feature_name;
178     *cpp = NULL;
179   }
180 
181   /* Identify features we are interested in. */
182   for(builtin = feature_names; *builtin; builtin++) {
183     const struct feature_name_presentp *p;
184 
185     for(p = maybe_feature; p->feature_name; p++)
186       if(curl_strequal(p->feature_name, *builtin)) {
187         if(p->feature_presentp)
188           *p->feature_presentp = TRUE;
189         break;
190       }
191     ++feature_count;
192   }
193 
194   feature_libssh2 = curlinfo->libssh_version &&
195     !strncmp("libssh2", curlinfo->libssh_version, 7);
196   return CURLE_OK;
197 }
198 
199 /* Tokenize a protocol name.
200  * Return the address of the protocol name listed by the library, or NULL if
201  * not found.
202  * Although this may seem useless, this always returns the same address for
203  * a given protocol and thus allows comparing pointers rather than strings.
204  * In addition, the returned pointer is not deallocated until the program ends.
205  */
206 
proto_token(const char * proto)207 const char *proto_token(const char *proto)
208 {
209   const char * const *builtin;
210 
211   if(!proto)
212     return NULL;
213   for(builtin = built_in_protos; *builtin; builtin++)
214     if(curl_strequal(*builtin, proto))
215       break;
216   return *builtin;
217 }
218