Squid Web Cache master
Loading...
Searching...
No Matches
helper.cc
Go to the documentation of this file.
1/*
2 * Copyright (C) 1996-2025 The Squid Software Foundation and contributors
3 *
4 * Squid software is distributed under GPLv2+ license and includes
5 * contributions from numerous individuals and organizations.
6 * Please see the COPYING and CONTRIBUTORS files for details.
7 */
8
9#include "squid.h"
10#include "../helper.h"
11#include "anyp/PortCfg.h"
12#include "base/AsyncCallbacks.h"
13#include "cache_cf.h"
14#include "fs_io.h"
15#include "helper/Reply.h"
16#include "Parsing.h"
17#include "sbuf/Stream.h"
18#include "SquidConfig.h"
20#include "ssl/Config.h"
21#include "ssl/helper.h"
22#include "wordlist.h"
23
24#include <limits>
25
27
28#if USE_SSL_CRTD
29
30namespace Ssl {
31
34public:
35 GeneratorRequestor(HLPCB *aCallback, void *aData): callback(aCallback), data(aData) {}
38};
39
43
44public:
46 void emplace(HLPCB *callback, void *data) { requestors.emplace_back(callback, data); }
47
49
51 typedef std::vector<GeneratorRequestor> GeneratorRequestors;
53};
54
56typedef std::unordered_map<SBuf, GeneratorRequest*> GeneratorRequests;
57
58static void HandleGeneratorReply(void *data, const ::Helper::Reply &reply);
59
61static GeneratorRequests &
63{
64 static auto generatorRequests = new GeneratorRequests();
65 return *generatorRequests;
66}
67
68} // namespace Ssl
69
70CBDATA_NAMESPACED_CLASS_INIT(Ssl, GeneratorRequest);
71
73static std::ostream &
74operator <<(std::ostream &os, const Ssl::GeneratorRequest &gr)
75{
76 return os << "crtGenRq" << gr.query.id.value << "/" << gr.requestors.size();
77}
78
80
82{
83 assert(ssl_crtd == nullptr);
84
85 // we need to start ssl_crtd only if some port(s) need to bump SSL *and* generate certificates
86 // TODO: generate host certificates for SNI enabled accel ports
87 bool found = false;
88 for (AnyP::PortCfgPointer s = HttpPortList; !found && s != nullptr; s = s->next)
89 found = s->flags.tunnelSslBumping && s->secure.generateHostCertificates;
90 if (!found)
91 return;
92
93 ssl_crtd = ::Helper::Client::Make("sslcrtd_program");
94 ssl_crtd->childs.updateLimits(Ssl::TheConfig.ssl_crtdChildren);
95 ssl_crtd->ipc_type = IPC_STREAM;
96 // The crtd messages may contain the eol ('\n') character. We are
97 // going to use the '\1' char as the end-of-message mark.
98 ssl_crtd->eom = '\1';
99 assert(ssl_crtd->cmdline == nullptr);
100 {
101 char *tmp = xstrdup(Ssl::TheConfig.ssl_crtd);
102 char *tmp_begin = tmp;
103 char *token = nullptr;
104 while ((token = strwordtok(nullptr, &tmp))) {
105 wordlistAdd(&ssl_crtd->cmdline, token);
106 }
107 safe_free(tmp_begin);
108 }
109 ssl_crtd->openSessions();
110}
111
113{
114 if (!ssl_crtd)
115 return;
116 helperShutdown(ssl_crtd);
117 wordlistDestroy(&ssl_crtd->cmdline);
118 ssl_crtd = nullptr;
119}
120
121void
123{
124 Shutdown();
125 Init();
126}
127
128void Ssl::Helper::Submit(CrtdMessage const & message, HLPCB * callback, void * data)
129{
130 SBuf rawMessage(message.compose().c_str()); // XXX: helpers cannot use SBuf
131 rawMessage.append("\n", 1);
132
133 const auto pending = TheGeneratorRequests().find(rawMessage);
134 if (pending != TheGeneratorRequests().end()) {
135 pending->second->emplace(callback, data);
136 debugs(83, 5, "collapsed request from " << data << " onto " << *pending->second);
137 return;
138 }
139
140 GeneratorRequest *request = new GeneratorRequest;
141 request->query = rawMessage;
142 request->emplace(callback, data);
143 TheGeneratorRequests().emplace(request->query, request);
144 debugs(83, 5, "request from " << data << " as " << *request);
145 // ssl_crtd becomes nil if Squid is reconfigured without SslBump or
146 // certificate generation disabled in the new configuration
147 if (ssl_crtd && ssl_crtd->trySubmit(request->query.c_str(), HandleGeneratorReply, request))
148 return;
149
151 failReply.notes.add("message", "error 45 Temporary network problem, please retry later");
152 HandleGeneratorReply(request, failReply);
153}
154
156static void
157Ssl::HandleGeneratorReply(void *data, const ::Helper::Reply &reply)
158{
159 const std::unique_ptr<Ssl::GeneratorRequest> request(static_cast<Ssl::GeneratorRequest*>(data));
160 assert(request);
161 const auto erased = TheGeneratorRequests().erase(request->query);
162 assert(erased);
163
164 for (auto &requestor: request->requestors) {
165 if (void *cbdata = requestor.data.validDone()) {
166 debugs(83, 5, "to " << cbdata << " in " << *request);
167 requestor.callback(cbdata, reply);
168 }
169 }
170}
171#endif //USE_SSL_CRTD
172
174
176{
177 if (!Ssl::TheConfig.ssl_crt_validator)
178 return;
179
180 assert(ssl_crt_validator == nullptr);
181
182 // we need to start ssl_crtd only if some port(s) need to bump SSL
183 bool found = false;
184 for (AnyP::PortCfgPointer s = HttpPortList; !found && s != nullptr; s = s->next)
185 found = s->flags.tunnelSslBumping;
186 if (!found)
187 return;
188
189 ssl_crt_validator = ::Helper::Client::Make("ssl_crt_validator");
190 ssl_crt_validator->childs.updateLimits(Ssl::TheConfig.ssl_crt_validator_Children);
191 ssl_crt_validator->ipc_type = IPC_STREAM;
192 // The crtd messages may contain the eol ('\n') character. We are
193 // going to use the '\1' char as the end-of-message mark.
194 ssl_crt_validator->eom = '\1';
195 assert(ssl_crt_validator->cmdline == nullptr);
196
197 /* defaults */
198 int ttl = 3600; // 1 hour
199 size_t cache = 64*1024*1024; // 64 MB
200 {
201 // TODO: Do this during parseConfigFile() for proper parsing, error handling
202 char *tmp = xstrdup(Ssl::TheConfig.ssl_crt_validator);
203 char *tmp_begin = tmp;
204 char * token = nullptr;
205 bool parseParams = true;
206 while ((token = strwordtok(nullptr, &tmp))) {
207 if (parseParams) {
208 if (strcmp(token, "ttl=infinity") == 0) {
209 ttl = std::numeric_limits<CacheType::Ttl>::max();
210 continue;
211 } else if (strncmp(token, "ttl=", 4) == 0) {
212 ttl = xatoi(token + 4);
213 if (ttl < 0) {
214 throw TextException(ToSBuf("Negative TTL in sslcrtvalidator_program ", Ssl::TheConfig.ssl_crt_validator,
215 Debug::Extra, "For unlimited TTL, use ttl=infinity"),
216 Here());
217 }
218 continue;
219 } else if (strncmp(token, "cache=", 6) == 0) {
220 cache = xatoi(token + 6);
221 continue;
222 } else
223 parseParams = false;
224 }
225 wordlistAdd(&ssl_crt_validator->cmdline, token);
226 }
227 xfree(tmp_begin);
228 }
229 ssl_crt_validator->openSessions();
230
231 //WARNING: initializing static member in an object initialization method
232 assert(HelperCache == nullptr);
233 HelperCache = new CacheType(cache, ttl);
234}
235
237{
238 if (!ssl_crt_validator)
239 return;
240 helperShutdown(ssl_crt_validator);
241 wordlistDestroy(&ssl_crt_validator->cmdline);
242 ssl_crt_validator = nullptr;
243
244 // CertValidationHelper::HelperCache is a static member, it is not good policy to
245 // reset it here. Will work because the current Ssl::CertValidationHelper is
246 // always the same static object.
247 delete HelperCache;
248 HelperCache = nullptr;
249}
250
251void
253{
254 Shutdown();
255 Init();
256}
257
268
269static void
270sslCrtvdHandleReplyWrapper(void *data, const ::Helper::Reply &reply)
271{
273
274 submitData *crtdvdData = static_cast<submitData *>(data);
275 assert(crtdvdData->ssl.get());
276 Ssl::CertValidationResponse::Pointer validationResponse = new Ssl::CertValidationResponse(crtdvdData->ssl);
277 if (reply.result == ::Helper::BrokenHelper) {
278 debugs(83, DBG_IMPORTANT, "ERROR: \"ssl_crtvd\" helper error response: " << reply.other().content());
279 validationResponse->resultCode = ::Helper::BrokenHelper;
280 } else if (!reply.other().hasContent()) {
281 debugs(83, DBG_IMPORTANT, "\"ssl_crtvd\" helper returned NULL response");
282 validationResponse->resultCode = ::Helper::BrokenHelper;
283 } else if (replyMsg.parse(reply.other().content(), reply.other().contentSize()) != Ssl::CrtdMessage::OK ||
284 !replyMsg.parseResponse(*validationResponse) ) {
285 debugs(83, DBG_IMPORTANT, "WARNING: Reply from ssl_crtvd for " << " is incorrect");
286 debugs(83, DBG_IMPORTANT, "ERROR: Certificate cannot be validated. ssl_crtvd response: " << replyMsg.getBody());
287 validationResponse->resultCode = ::Helper::BrokenHelper;
288 } else
289 validationResponse->resultCode = reply.result;
290
291 crtdvdData->callback.answer() = validationResponse;
292 ScheduleCallHere(crtdvdData->callback.release());
293
295 (validationResponse->resultCode == ::Helper::Okay || validationResponse->resultCode == ::Helper::Error)) {
296 (void)Ssl::CertValidationHelper::HelperCache->add(crtdvdData->query, validationResponse);
297 }
298
299 delete crtdvdData;
300}
301
302void
304{
307 message.composeRequest(request);
308 debugs(83, 5, "SSL crtvd request: " << message.compose().c_str());
309
310 submitData *crtdvdData = new submitData;
311 crtdvdData->query.assign(message.compose().c_str());
312 crtdvdData->query.append('\n');
313 crtdvdData->callback = callback;
314 crtdvdData->ssl = request.ssl;
315 Ssl::CertValidationResponse::Pointer const*validationResponse;
316
318 (validationResponse = CertValidationHelper::HelperCache->get(crtdvdData->query))) {
319
320 crtdvdData->callback.answer() = *validationResponse;
321 ScheduleCallHere(crtdvdData->callback.release());
322 delete crtdvdData;
323 return;
324 }
325
326 // ssl_crt_validator becomes nil if Squid is reconfigured with cert
327 // validator disabled in the new configuration
328 if (ssl_crt_validator && ssl_crt_validator->trySubmit(crtdvdData->query.c_str(), sslCrtvdHandleReplyWrapper, crtdvdData))
329 return;
330
332 resp->resultCode = ::Helper::BrokenHelper;
333 crtdvdData->callback.answer() = resp;
334 ScheduleCallHere(crtdvdData->callback.release());
335 delete crtdvdData;
336 return;
337}
338
#define ScheduleCallHere(call)
Definition AsyncCall.h:166
#define Here()
source code location of the caller
Definition Here.h:15
int xatoi(const char *token)
Definition Parsing.cc:44
AnyP::PortCfgPointer HttpPortList
list of Squid http(s)_port configured
Definition PortCfg.cc:22
char * strwordtok(char *buf, char **t)
Definition String.cc:321
#define assert(EX)
Definition assert.h:17
#define CBDATA_CLASS_INIT(type)
Definition cbdata.h:325
#define CBDATA_CLASS(type)
Definition cbdata.h:289
#define CBDATA_NAMESPACED_CLASS_INIT(namespace, type)
Definition cbdata.h:333
a smart AsyncCall pointer for delivery of future results
AsyncCall::Pointer release()
Answer & answer()
an old-style void* callback parameter
Definition cbdata.h:384
static std::ostream & Extra(std::ostream &)
Definition debug.cc:1316
static Pointer Make(const char *name)
Definition helper.cc:758
NotePairs notes
Definition Reply.h:62
Value value
instance identifier
Definition InstanceId.h:70
void add(const SBuf &key, const SBuf &value)
Definition Notes.cc:322
Definition SBuf.h:94
const char * c_str()
Definition SBuf.cc:516
const InstanceId< SBuf > id
Definition SBuf.h:608
size_type find(char c, size_type startPos=0) const
Definition SBuf.cc:584
SBuf & append(const SBuf &S)
Definition SBuf.cc:185
SBuf & assign(const SBuf &S)
Definition SBuf.cc:83
::Helper::ClientPointer ssl_crt_validator
helper for management of ssl_crtd.
Definition helper.h:56
static void Submit(const Ssl::CertValidationRequest &, const Callback &)
Submit crtd request message to external crtd server.
Definition helper.cc:303
static CacheType * HelperCache
cache for cert validation helper
Definition helper.h:59
static void Shutdown()
Shutdown helper structure.
Definition helper.cc:236
static void Init()
Init helper structure.
Definition helper.cc:175
static void Reconfigure()
Definition helper.cc:252
void composeRequest(CertValidationRequest const &vcert)
bool parseResponse(CertValidationResponse &resp)
Parse a response message and fill the resp object with parsed information.
static const std::string code_cert_validate
String code for "cert_validate" messages.
Security::SessionPointer ssl
void setCode(std::string const &aCode)
Set new request/reply code to compose.
std::string const & getBody() const
Current body. If parsing is not finished the method returns incompleted body.
ParseResult parse(const char *buffer, size_t len)
std::string compose() const
A pending Ssl::Helper request, combining the original and collapsed queries.
Definition helper.cc:41
void emplace(HLPCB *callback, void *data)
adds a GeneratorRequestor
Definition helper.cc:46
GeneratorRequestors requestors
Definition helper.cc:52
SBuf query
Ssl::Helper request message (GeneratorRequests key)
Definition helper.cc:48
std::vector< GeneratorRequestor > GeneratorRequestors
Ssl::Helper request initiators waiting for the same answer (FIFO).
Definition helper.cc:51
Initiator of an Ssl::Helper query.
Definition helper.cc:33
GeneratorRequestor(HLPCB *aCallback, void *aData)
Definition helper.cc:35
CallbackData data
Definition helper.cc:37
static void Submit(CrtdMessage const &message, HLPCB *callback, void *data)
Submit crtd message to external crtd server.
Definition helper.cc:128
static void Init()
Init helper structure.
Definition helper.cc:81
::Helper::ClientPointer ssl_crtd
helper for management of ssl_crtd.
Definition helper.h:37
static void Reconfigure()
Definition helper.cc:122
static void Shutdown()
Shutdown helper structure.
Definition helper.cc:112
an std::runtime_error with thrower location info
void * data
Definition cbdata.cc:78
Ssl::CertValidationHelper::Callback callback
Definition helper.cc:264
SBuf query
Definition helper.cc:263
Security::SessionPointer ssl
Definition helper.cc:265
#define DBG_IMPORTANT
Definition Stream.h:38
#define debugs(SECTION, LEVEL, CONTENT)
Definition Stream.h:192
#define IPC_STREAM
Definition defines.h:104
void HLPCB(void *, const Helper::Reply &)
Definition forward.h:33
void helperShutdown(const Helper::Client::Pointer &hlp)
Definition helper.cc:770
@ BrokenHelper
Definition ResultCode.h:20
std::shared_ptr< SSL > SessionPointer
Definition Session.h:53
Definition Xaction.cc:40
std::unordered_map< SBuf, GeneratorRequest * > GeneratorRequests
Ssl::Helper query:GeneratorRequest map.
Definition helper.cc:56
Config TheConfig
Definition Config.cc:12
static void HandleGeneratorReply(void *data, const ::Helper::Reply &reply)
receives helper response
Definition helper.cc:157
static GeneratorRequests & TheGeneratorRequests()
pending Ssl::Helper requests (to all certificate generator helpers combined)
Definition helper.cc:62
#define xfree
#define xstrdup
SBuf ToSBuf(Args &&... args)
slowly stream-prints all arguments into a freshly allocated SBuf
Definition Stream.h:63
static void sslCrtvdHandleReplyWrapper(void *data, const ::Helper::Reply &reply)
Definition helper.cc:270
static std::ostream & operator<<(std::ostream &os, const Ssl::GeneratorRequest &gr)
prints Ssl::GeneratorRequest for debugging
Definition helper.cc:74
const char * wordlistAdd(wordlist **list, const char *key)
Definition wordlist.cc:25
void wordlistDestroy(wordlist **list)
destroy a wordlist
Definition wordlist.cc:16
#define safe_free(x)
Definition xalloc.h:73