2013-12-17 17:32:47 -05:00
|
|
|
#ifndef HEADER_CURL_VTLS_H
|
|
|
|
#define HEADER_CURL_VTLS_H
|
2005-04-07 11:27:13 -04:00
|
|
|
/***************************************************************************
|
|
|
|
* _ _ ____ _
|
|
|
|
* Project ___| | | | _ \| |
|
|
|
|
* / __| | | | |_) | |
|
|
|
|
* | (__| |_| | _ <| |___
|
|
|
|
* \___|\___/|_| \_\_____|
|
|
|
|
*
|
2020-01-16 02:17:04 -05:00
|
|
|
* Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
|
2005-04-07 11:27:13 -04:00
|
|
|
*
|
|
|
|
* This software is licensed as described in the file COPYING, which
|
|
|
|
* you should have received as part of this distribution. The terms
|
2016-02-02 18:19:02 -05:00
|
|
|
* are also available at https://curl.haxx.se/docs/copyright.html.
|
2005-04-07 11:27:13 -04:00
|
|
|
*
|
|
|
|
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
|
|
|
|
* copies of the Software, and permit persons to whom the Software is
|
|
|
|
* furnished to do so, under the terms of the COPYING file.
|
|
|
|
*
|
|
|
|
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
|
|
|
* KIND, either express or implied.
|
|
|
|
*
|
|
|
|
***************************************************************************/
|
2013-01-06 13:06:49 -05:00
|
|
|
#include "curl_setup.h"
|
2005-04-07 11:27:13 -04:00
|
|
|
|
2017-06-22 10:36:03 -04:00
|
|
|
struct connectdata;
|
2017-06-23 10:05:26 -04:00
|
|
|
struct ssl_connect_data;
|
2017-06-22 10:36:03 -04:00
|
|
|
|
2018-05-04 06:10:39 -04:00
|
|
|
#define SSLSUPP_CA_PATH (1<<0) /* supports CAPATH */
|
|
|
|
#define SSLSUPP_CERTINFO (1<<1) /* supports CURLOPT_CERTINFO */
|
|
|
|
#define SSLSUPP_PINNEDPUBKEY (1<<2) /* supports CURLOPT_PINNEDPUBLICKEY */
|
|
|
|
#define SSLSUPP_SSL_CTX (1<<3) /* supports CURLOPT_SSL_CTX */
|
|
|
|
#define SSLSUPP_HTTPS_PROXY (1<<4) /* supports access via HTTPS proxies */
|
2018-05-29 10:12:52 -04:00
|
|
|
#define SSLSUPP_TLS13_CIPHERSUITES (1<<5) /* supports TLS 1.3 ciphersuites */
|
2018-05-04 06:10:39 -04:00
|
|
|
|
2017-06-22 10:36:03 -04:00
|
|
|
struct Curl_ssl {
|
2017-07-15 07:49:30 -04:00
|
|
|
/*
|
|
|
|
* This *must* be the first entry to allow returning the list of available
|
|
|
|
* backends in curl_global_sslset().
|
|
|
|
*/
|
|
|
|
curl_ssl_backend info;
|
2018-05-04 06:10:39 -04:00
|
|
|
unsigned int supports; /* bitfield, see above */
|
vtls: encapsulate SSL backend-specific data
So far, all of the SSL backends' private data has been declared as
part of the ssl_connect_data struct, in one big #if .. #elif .. #endif
block.
This can only work as long as the SSL backend is a compile-time option,
something we want to change in the next commits.
Therefore, let's encapsulate the exact data needed by each SSL backend
into a private struct, and let's avoid bleeding any SSL backend-specific
information into urldata.h. This is also necessary to allow multiple SSL
backends to be compiled in at the same time, as e.g. OpenSSL's and
CyaSSL's headers cannot be included in the same .c file.
To avoid too many malloc() calls, we simply append the private structs
to the connectdata struct in allocate_conn().
This requires us to take extra care of alignment issues: struct fields
often need to be aligned on certain boundaries e.g. 32-bit values need to
be stored at addresses that divide evenly by 4 (= 32 bit / 8
bit-per-byte).
We do that by assuming that no SSL backend's private data contains any
fields that need to be aligned on boundaries larger than `long long`
(typically 64-bit) would need. Under this assumption, we simply add a
dummy field of type `long long` to the `struct connectdata` struct. This
field will never be accessed but acts as a placeholder for the four
instances of ssl_backend_data instead. the size of each ssl_backend_data
struct is stored in the SSL backend-specific metadata, to allow
allocate_conn() to know how much extra space to allocate, and how to
initialize the ssl[sockindex]->backend and proxy_ssl[sockindex]->backend
pointers.
This would appear to be a little complicated at first, but is really
necessary to encapsulate the private data of each SSL backend correctly.
And we need to encapsulate thusly if we ever want to allow selecting
CyaSSL and OpenSSL at runtime, as their headers cannot be included within
the same .c file (there are just too many conflicting definitions and
declarations for that).
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
2017-07-28 16:09:35 -04:00
|
|
|
size_t sizeof_ssl_backend_data;
|
|
|
|
|
2017-06-22 10:36:03 -04:00
|
|
|
int (*init)(void);
|
|
|
|
void (*cleanup)(void);
|
|
|
|
|
|
|
|
size_t (*version)(char *buffer, size_t size);
|
|
|
|
int (*check_cxn)(struct connectdata *cxn);
|
2019-03-12 18:50:28 -04:00
|
|
|
int (*shut_down)(struct connectdata *conn, int sockindex);
|
2017-06-22 10:36:03 -04:00
|
|
|
bool (*data_pending)(const struct connectdata *conn,
|
|
|
|
int connindex);
|
|
|
|
|
|
|
|
/* return 0 if a find random is filled in */
|
|
|
|
CURLcode (*random)(struct Curl_easy *data, unsigned char *entropy,
|
|
|
|
size_t length);
|
|
|
|
bool (*cert_status_request)(void);
|
|
|
|
|
2019-03-12 18:50:28 -04:00
|
|
|
CURLcode (*connect_blocking)(struct connectdata *conn, int sockindex);
|
2017-06-22 10:36:03 -04:00
|
|
|
CURLcode (*connect_nonblocking)(struct connectdata *conn, int sockindex,
|
|
|
|
bool *done);
|
2017-06-23 10:05:26 -04:00
|
|
|
void *(*get_internals)(struct ssl_connect_data *connssl, CURLINFO info);
|
2017-10-19 14:55:17 -04:00
|
|
|
void (*close_one)(struct connectdata *conn, int sockindex);
|
2017-06-22 10:36:03 -04:00
|
|
|
void (*close_all)(struct Curl_easy *data);
|
|
|
|
void (*session_free)(void *ptr);
|
|
|
|
|
|
|
|
CURLcode (*set_engine)(struct Curl_easy *data, const char *engine);
|
|
|
|
CURLcode (*set_engine_default)(struct Curl_easy *data);
|
|
|
|
struct curl_slist *(*engines_list)(struct Curl_easy *data);
|
|
|
|
|
|
|
|
bool (*false_start)(void);
|
2017-06-22 19:04:56 -04:00
|
|
|
|
|
|
|
CURLcode (*md5sum)(unsigned char *input, size_t inputlen,
|
|
|
|
unsigned char *md5sum, size_t md5sumlen);
|
2018-04-02 13:33:00 -04:00
|
|
|
CURLcode (*sha256sum)(const unsigned char *input, size_t inputlen,
|
2017-06-22 19:04:56 -04:00
|
|
|
unsigned char *sha256sum, size_t sha256sumlen);
|
2017-06-22 10:36:03 -04:00
|
|
|
};
|
|
|
|
|
2017-06-22 18:22:47 -04:00
|
|
|
#ifdef USE_SSL
|
|
|
|
extern const struct Curl_ssl *Curl_ssl;
|
|
|
|
#endif
|
|
|
|
|
2017-06-22 10:45:34 -04:00
|
|
|
int Curl_none_init(void);
|
|
|
|
void Curl_none_cleanup(void);
|
|
|
|
int Curl_none_shutdown(struct connectdata *conn, int sockindex);
|
|
|
|
int Curl_none_check_cxn(struct connectdata *conn);
|
|
|
|
CURLcode Curl_none_random(struct Curl_easy *data, unsigned char *entropy,
|
|
|
|
size_t length);
|
|
|
|
void Curl_none_close_all(struct Curl_easy *data);
|
|
|
|
void Curl_none_session_free(void *ptr);
|
|
|
|
bool Curl_none_data_pending(const struct connectdata *conn, int connindex);
|
|
|
|
bool Curl_none_cert_status_request(void);
|
|
|
|
CURLcode Curl_none_set_engine(struct Curl_easy *data, const char *engine);
|
|
|
|
CURLcode Curl_none_set_engine_default(struct Curl_easy *data);
|
|
|
|
struct curl_slist *Curl_none_engines_list(struct Curl_easy *data);
|
|
|
|
bool Curl_none_false_start(void);
|
2018-05-29 10:12:52 -04:00
|
|
|
bool Curl_ssl_tls13_ciphersuites(void);
|
2017-06-22 19:04:56 -04:00
|
|
|
CURLcode Curl_none_md5sum(unsigned char *input, size_t inputlen,
|
|
|
|
unsigned char *md5sum, size_t md5len);
|
2017-06-22 10:45:34 -04:00
|
|
|
|
2014-12-25 12:15:15 -05:00
|
|
|
#include "openssl.h" /* OpenSSL versions */
|
|
|
|
#include "gtls.h" /* GnuTLS versions */
|
|
|
|
#include "nssg.h" /* NSS versions */
|
|
|
|
#include "gskit.h" /* Global Secure ToolKit versions */
|
2019-06-02 10:55:05 -04:00
|
|
|
#include "wolfssl.h" /* wolfSSL versions */
|
2015-02-07 15:50:30 -05:00
|
|
|
#include "schannel.h" /* Schannel SSPI version */
|
2019-02-26 03:21:12 -05:00
|
|
|
#include "sectransp.h" /* SecureTransport (Darwin) version */
|
2015-10-19 08:25:34 -04:00
|
|
|
#include "mbedtls.h" /* mbedTLS versions */
|
2018-09-10 16:08:21 -04:00
|
|
|
#include "mesalink.h" /* MesaLink versions */
|
2019-11-07 23:17:18 -05:00
|
|
|
#include "bearssl.h" /* BearSSL versions */
|
2014-10-09 16:34:34 -04:00
|
|
|
|
2014-11-24 13:30:09 -05:00
|
|
|
#ifndef MAX_PINNED_PUBKEY_SIZE
|
|
|
|
#define MAX_PINNED_PUBKEY_SIZE 1048576 /* 1MB */
|
|
|
|
#endif
|
|
|
|
|
2017-09-06 03:32:02 -04:00
|
|
|
#ifndef CURL_SHA256_DIGEST_LENGTH
|
|
|
|
#define CURL_SHA256_DIGEST_LENGTH 32 /* fixed size */
|
2015-06-30 20:23:54 -04:00
|
|
|
#endif
|
|
|
|
|
2016-02-02 23:09:25 -05:00
|
|
|
/* see https://tools.ietf.org/html/draft-ietf-tls-applayerprotoneg-04 */
|
2014-02-04 03:10:37 -05:00
|
|
|
#define ALPN_HTTP_1_1_LENGTH 8
|
2014-05-20 01:36:31 -04:00
|
|
|
#define ALPN_HTTP_1_1 "http/1.1"
|
2014-02-04 03:10:37 -05:00
|
|
|
|
2016-11-16 12:49:15 -05:00
|
|
|
/* set of helper macros for the backends to access the correct fields. For the
|
|
|
|
proxy or for the remote host - to properly support HTTPS proxy */
|
2020-05-27 05:51:34 -04:00
|
|
|
#ifndef CURL_DISABLE_PROXY
|
|
|
|
#define SSL_IS_PROXY() \
|
|
|
|
(CURLPROXY_HTTPS == conn->http_proxy.proxytype && \
|
|
|
|
ssl_connection_complete != \
|
|
|
|
conn->proxy_ssl[conn->sock[SECONDARYSOCKET] == \
|
|
|
|
CURL_SOCKET_BAD ? FIRSTSOCKET : SECONDARYSOCKET].state)
|
|
|
|
#define SSL_SET_OPTION(var) \
|
|
|
|
(SSL_IS_PROXY() ? data->set.proxy_ssl.var : data->set.ssl.var)
|
|
|
|
#define SSL_CONN_CONFIG(var) \
|
|
|
|
(SSL_IS_PROXY() ? conn->proxy_ssl_config.var : conn->ssl_config.var)
|
|
|
|
#else
|
|
|
|
#define SSL_IS_PROXY() FALSE
|
|
|
|
#define SSL_SET_OPTION(var) data->set.ssl.var
|
|
|
|
#define SSL_CONN_CONFIG(var) conn->ssl_config.var
|
|
|
|
#endif
|
2016-11-16 12:49:15 -05:00
|
|
|
|
2020-05-13 06:56:53 -04:00
|
|
|
bool Curl_ssl_config_matches(struct ssl_primary_config *data,
|
|
|
|
struct ssl_primary_config *needle);
|
2016-11-16 12:49:15 -05:00
|
|
|
bool Curl_clone_primary_ssl_config(struct ssl_primary_config *source,
|
|
|
|
struct ssl_primary_config *dest);
|
2020-05-13 06:56:53 -04:00
|
|
|
void Curl_free_primary_ssl_config(struct ssl_primary_config *sslc);
|
2019-07-30 05:02:03 -04:00
|
|
|
int Curl_ssl_getsock(struct connectdata *conn, curl_socket_t *socks);
|
2005-04-07 11:27:13 -04:00
|
|
|
|
2014-08-03 04:40:36 -04:00
|
|
|
int Curl_ssl_backend(void);
|
|
|
|
|
2008-06-11 13:01:58 -04:00
|
|
|
#ifdef USE_SSL
|
2005-04-07 11:27:13 -04:00
|
|
|
int Curl_ssl_init(void);
|
|
|
|
void Curl_ssl_cleanup(void);
|
|
|
|
CURLcode Curl_ssl_connect(struct connectdata *conn, int sockindex);
|
2006-11-11 16:34:43 -05:00
|
|
|
CURLcode Curl_ssl_connect_nonblocking(struct connectdata *conn,
|
2006-03-21 16:54:44 -05:00
|
|
|
int sockindex,
|
|
|
|
bool *done);
|
2005-04-07 11:27:13 -04:00
|
|
|
/* tell the SSL stuff to close down all open information regarding
|
|
|
|
connections (and thus session ID caching etc) */
|
2016-06-21 09:47:12 -04:00
|
|
|
void Curl_ssl_close_all(struct Curl_easy *data);
|
2008-06-11 13:01:58 -04:00
|
|
|
void Curl_ssl_close(struct connectdata *conn, int sockindex);
|
|
|
|
CURLcode Curl_ssl_shutdown(struct connectdata *conn, int sockindex);
|
2016-06-21 09:47:12 -04:00
|
|
|
CURLcode Curl_ssl_set_engine(struct Curl_easy *data, const char *engine);
|
2005-04-07 11:27:13 -04:00
|
|
|
/* Sets engine as default for all SSL operations */
|
2016-06-21 09:47:12 -04:00
|
|
|
CURLcode Curl_ssl_set_engine_default(struct Curl_easy *data);
|
|
|
|
struct curl_slist *Curl_ssl_engines_list(struct Curl_easy *data);
|
2010-04-04 17:37:18 -04:00
|
|
|
|
2005-04-07 11:27:13 -04:00
|
|
|
/* init the SSL session ID cache */
|
2016-06-21 09:47:12 -04:00
|
|
|
CURLcode Curl_ssl_initsessions(struct Curl_easy *, size_t);
|
2008-06-11 13:01:58 -04:00
|
|
|
size_t Curl_ssl_version(char *buffer, size_t size);
|
|
|
|
bool Curl_ssl_data_pending(const struct connectdata *conn,
|
|
|
|
int connindex);
|
|
|
|
int Curl_ssl_check_cxn(struct connectdata *conn);
|
2013-07-15 11:26:59 -04:00
|
|
|
|
|
|
|
/* Certificate information list handling. */
|
|
|
|
|
2016-06-21 09:47:12 -04:00
|
|
|
void Curl_ssl_free_certinfo(struct Curl_easy *data);
|
2016-11-23 01:53:24 -05:00
|
|
|
CURLcode Curl_ssl_init_certinfo(struct Curl_easy *data, int num);
|
|
|
|
CURLcode Curl_ssl_push_certinfo_len(struct Curl_easy *data, int certnum,
|
|
|
|
const char *label, const char *value,
|
2013-07-15 11:26:59 -04:00
|
|
|
size_t valuelen);
|
2016-11-23 01:53:24 -05:00
|
|
|
CURLcode Curl_ssl_push_certinfo(struct Curl_easy *data, int certnum,
|
|
|
|
const char *label, const char *value);
|
2008-10-20 19:07:48 -04:00
|
|
|
|
|
|
|
/* Functions to be used by SSL library adaptation functions */
|
|
|
|
|
2016-06-01 03:30:03 -04:00
|
|
|
/* Lock session cache mutex.
|
|
|
|
* Call this before calling other Curl_ssl_*session* functions
|
|
|
|
* Caller should unlock this mutex as soon as possible, as it may block
|
|
|
|
* other SSL connection from making progress.
|
|
|
|
* The purpose of explicitly locking SSL session cache data is to allow
|
|
|
|
* individual SSL engines to manage session lifetime in their specific way.
|
|
|
|
*/
|
|
|
|
void Curl_ssl_sessionid_lock(struct connectdata *conn);
|
|
|
|
|
|
|
|
/* Unlock session cache mutex */
|
|
|
|
void Curl_ssl_sessionid_unlock(struct connectdata *conn);
|
|
|
|
|
|
|
|
/* extract a session ID
|
|
|
|
* Sessionid mutex must be locked (see Curl_ssl_sessionid_lock).
|
|
|
|
* Caller must make sure that the ownership of returned sessionid object
|
|
|
|
* is properly taken (e.g. its refcount is incremented
|
|
|
|
* under sessionid mutex).
|
|
|
|
*/
|
2014-12-25 12:15:15 -05:00
|
|
|
bool Curl_ssl_getsessionid(struct connectdata *conn,
|
|
|
|
void **ssl_sessionid,
|
2016-11-16 12:49:15 -05:00
|
|
|
size_t *idsize, /* set 0 if unknown */
|
|
|
|
int sockindex);
|
2016-06-01 03:30:03 -04:00
|
|
|
/* add a new session ID
|
|
|
|
* Sessionid mutex must be locked (see Curl_ssl_sessionid_lock).
|
|
|
|
* Caller must ensure that it has properly shared ownership of this sessionid
|
|
|
|
* object with cache (e.g. incrementing refcount on success)
|
|
|
|
*/
|
2008-10-20 19:07:48 -04:00
|
|
|
CURLcode Curl_ssl_addsessionid(struct connectdata *conn,
|
|
|
|
void *ssl_sessionid,
|
2016-11-16 12:49:15 -05:00
|
|
|
size_t idsize,
|
|
|
|
int sockindex);
|
2016-06-01 03:30:03 -04:00
|
|
|
/* Kill a single session ID entry in the cache
|
|
|
|
* Sessionid mutex must be locked (see Curl_ssl_sessionid_lock).
|
|
|
|
* This will call engine-specific curlssl_session_free function, which must
|
|
|
|
* take sessionid object ownership from sessionid cache
|
|
|
|
* (e.g. decrement refcount).
|
|
|
|
*/
|
2012-01-18 17:39:30 -05:00
|
|
|
void Curl_ssl_kill_session(struct curl_ssl_session *session);
|
2016-06-01 03:30:03 -04:00
|
|
|
/* delete a session from the cache
|
|
|
|
* Sessionid mutex must be locked (see Curl_ssl_sessionid_lock).
|
|
|
|
* This will call engine-specific curlssl_session_free function, which must
|
|
|
|
* take sessionid object ownership from sessionid cache
|
|
|
|
* (e.g. decrement refcount).
|
|
|
|
*/
|
2009-05-04 17:57:14 -04:00
|
|
|
void Curl_ssl_delsessionid(struct connectdata *conn, void *ssl_sessionid);
|
2008-10-20 19:07:48 -04:00
|
|
|
|
2016-11-11 08:53:36 -05:00
|
|
|
/* get N random bytes into the buffer */
|
|
|
|
CURLcode Curl_ssl_random(struct Curl_easy *data, unsigned char *buffer,
|
|
|
|
size_t length);
|
2015-03-25 03:32:12 -04:00
|
|
|
CURLcode Curl_ssl_md5sum(unsigned char *tmp, /* input */
|
|
|
|
size_t tmplen,
|
|
|
|
unsigned char *md5sum, /* output */
|
|
|
|
size_t md5len);
|
2014-10-13 12:34:51 -04:00
|
|
|
/* Check pinned public key. */
|
2016-06-21 09:47:12 -04:00
|
|
|
CURLcode Curl_pin_peer_pubkey(struct Curl_easy *data,
|
2015-09-12 17:35:12 -04:00
|
|
|
const char *pinnedpubkey,
|
2014-10-13 12:34:51 -04:00
|
|
|
const unsigned char *pubkey, size_t pubkeylen);
|
2012-06-26 08:52:46 -04:00
|
|
|
|
2014-06-16 07:20:47 -04:00
|
|
|
bool Curl_ssl_cert_status_request(void);
|
|
|
|
|
2015-02-14 10:57:07 -05:00
|
|
|
bool Curl_ssl_false_start(void);
|
|
|
|
|
2008-10-20 19:07:48 -04:00
|
|
|
#define SSL_SHUTDOWN_TIMEOUT 10000 /* ms */
|
|
|
|
|
2018-05-29 10:12:52 -04:00
|
|
|
#else /* if not USE_SSL */
|
2015-01-17 11:03:49 -05:00
|
|
|
|
2008-06-11 13:01:58 -04:00
|
|
|
/* When SSL support is not present, just define away these function calls */
|
|
|
|
#define Curl_ssl_init() 1
|
2011-09-03 10:06:10 -04:00
|
|
|
#define Curl_ssl_cleanup() Curl_nop_stmt
|
2011-04-05 09:14:02 -04:00
|
|
|
#define Curl_ssl_connect(x,y) CURLE_NOT_BUILT_IN
|
2011-09-03 10:06:10 -04:00
|
|
|
#define Curl_ssl_close_all(x) Curl_nop_stmt
|
|
|
|
#define Curl_ssl_close(x,y) Curl_nop_stmt
|
2011-04-05 09:14:02 -04:00
|
|
|
#define Curl_ssl_shutdown(x,y) CURLE_NOT_BUILT_IN
|
|
|
|
#define Curl_ssl_set_engine(x,y) CURLE_NOT_BUILT_IN
|
|
|
|
#define Curl_ssl_set_engine_default(x) CURLE_NOT_BUILT_IN
|
2008-06-11 13:01:58 -04:00
|
|
|
#define Curl_ssl_engines_list(x) NULL
|
2010-04-05 19:41:33 -04:00
|
|
|
#define Curl_ssl_send(a,b,c,d,e) -1
|
|
|
|
#define Curl_ssl_recv(a,b,c,d,e) -1
|
2008-06-11 13:01:58 -04:00
|
|
|
#define Curl_ssl_initsessions(x,y) CURLE_OK
|
|
|
|
#define Curl_ssl_data_pending(x,y) 0
|
|
|
|
#define Curl_ssl_check_cxn(x) 0
|
2011-09-03 10:06:10 -04:00
|
|
|
#define Curl_ssl_free_certinfo(x) Curl_nop_stmt
|
2011-04-05 09:14:02 -04:00
|
|
|
#define Curl_ssl_connect_nonblocking(x,y,z) CURLE_NOT_BUILT_IN
|
2012-01-18 17:39:30 -05:00
|
|
|
#define Curl_ssl_kill_session(x) Curl_nop_stmt
|
2014-11-09 13:09:58 -05:00
|
|
|
#define Curl_ssl_random(x,y,z) ((void)x, CURLE_NOT_BUILT_IN)
|
2015-01-17 10:13:29 -05:00
|
|
|
#define Curl_ssl_cert_status_request() FALSE
|
2015-02-14 10:57:07 -05:00
|
|
|
#define Curl_ssl_false_start() FALSE
|
2018-05-29 10:12:52 -04:00
|
|
|
#define Curl_ssl_tls13_ciphersuites() FALSE
|
2008-06-11 13:01:58 -04:00
|
|
|
#endif
|
|
|
|
|
2013-12-17 17:32:47 -05:00
|
|
|
#endif /* HEADER_CURL_VTLS_H */
|