helper.cc
Go to the documentation of this file.
1/*
2 * Copyright (C) 1996-2023 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"
19#include "SquidString.h"
21#include "ssl/Config.h"
22#include "ssl/helper.h"
23#include "wordlist.h"
24
25#include <limits>
26
28
29#if USE_SSL_CRTD
30
31namespace Ssl {
32
35public:
36 GeneratorRequestor(HLPCB *aCallback, void *aData): callback(aCallback), data(aData) {}
39};
40
44
45public:
47 void emplace(HLPCB *callback, void *data) { requestors.emplace_back(callback, data); }
48
50
52 typedef std::vector<GeneratorRequestor> GeneratorRequestors;
54};
55
57typedef std::unordered_map<SBuf, GeneratorRequest*> GeneratorRequests;
58
59static void HandleGeneratorReply(void *data, const ::Helper::Reply &reply);
60
61} // namespace Ssl
62
63CBDATA_NAMESPACED_CLASS_INIT(Ssl, GeneratorRequest);
64
66static std::ostream &
67operator <<(std::ostream &os, const Ssl::GeneratorRequest &gr)
68{
69 return os << "crtGenRq" << gr.query.id.value << "/" << gr.requestors.size();
70}
71
74
76
78{
79 assert(ssl_crtd == nullptr);
80
81 // we need to start ssl_crtd only if some port(s) need to bump SSL *and* generate certificates
82 // TODO: generate host certificates for SNI enabled accel ports
83 bool found = false;
84 for (AnyP::PortCfgPointer s = HttpPortList; !found && s != nullptr; s = s->next)
85 found = s->flags.tunnelSslBumping && s->secure.generateHostCertificates;
86 if (!found)
87 return;
88
89 ssl_crtd = new helper("sslcrtd_program");
90 ssl_crtd->childs.updateLimits(Ssl::TheConfig.ssl_crtdChildren);
92 // The crtd messages may contain the eol ('\n') character. We are
93 // going to use the '\1' char as the end-of-message mark.
94 ssl_crtd->eom = '\1';
95 assert(ssl_crtd->cmdline == nullptr);
96 {
97 char *tmp = xstrdup(Ssl::TheConfig.ssl_crtd);
98 char *tmp_begin = tmp;
99 char *token = nullptr;
100 while ((token = strwordtok(nullptr, &tmp))) {
101 wordlistAdd(&ssl_crtd->cmdline, token);
102 }
103 safe_free(tmp_begin);
104 }
106}
107
109{
110 if (!ssl_crtd)
111 return;
112 helperShutdown(ssl_crtd);
113 wordlistDestroy(&ssl_crtd->cmdline);
114 delete ssl_crtd;
115 ssl_crtd = nullptr;
116}
117
118void
120{
121 Shutdown();
122 Init();
123}
124
125void Ssl::Helper::Submit(CrtdMessage const & message, HLPCB * callback, void * data)
126{
127 SBuf rawMessage(message.compose().c_str()); // XXX: helpers cannot use SBuf
128 rawMessage.append("\n", 1);
129
130 const auto pending = TheGeneratorRequests.find(rawMessage);
131 if (pending != TheGeneratorRequests.end()) {
132 pending->second->emplace(callback, data);
133 debugs(83, 5, "collapsed request from " << data << " onto " << *pending->second);
134 return;
135 }
136
137 GeneratorRequest *request = new GeneratorRequest;
138 request->query = rawMessage;
139 request->emplace(callback, data);
140 TheGeneratorRequests.emplace(request->query, request);
141 debugs(83, 5, "request from " << data << " as " << *request);
142 // ssl_crtd becomes nil if Squid is reconfigured without SslBump or
143 // certificate generation disabled in the new configuration
144 if (ssl_crtd && ssl_crtd->trySubmit(request->query.c_str(), HandleGeneratorReply, request))
145 return;
146
148 failReply.notes.add("message", "error 45 Temporary network problem, please retry later");
149 HandleGeneratorReply(request, failReply);
150}
151
153static void
154Ssl::HandleGeneratorReply(void *data, const ::Helper::Reply &reply)
155{
156 const std::unique_ptr<Ssl::GeneratorRequest> request(static_cast<Ssl::GeneratorRequest*>(data));
157 assert(request);
158 const auto erased = TheGeneratorRequests.erase(request->query);
159 assert(erased);
160
161 for (auto &requestor: request->requestors) {
162 if (void *cbdata = requestor.data.validDone()) {
163 debugs(83, 5, "to " << cbdata << " in " << *request);
164 requestor.callback(cbdata, reply);
165 }
166 }
167}
168#endif //USE_SSL_CRTD
169
171
173{
174 if (!Ssl::TheConfig.ssl_crt_validator)
175 return;
176
177 assert(ssl_crt_validator == nullptr);
178
179 // we need to start ssl_crtd only if some port(s) need to bump SSL
180 bool found = false;
181 for (AnyP::PortCfgPointer s = HttpPortList; !found && s != nullptr; s = s->next)
182 found = s->flags.tunnelSslBumping;
183 if (!found)
184 return;
185
186 ssl_crt_validator = new helper("ssl_crt_validator");
187 ssl_crt_validator->childs.updateLimits(Ssl::TheConfig.ssl_crt_validator_Children);
188 ssl_crt_validator->ipc_type = IPC_STREAM;
189 // The crtd messages may contain the eol ('\n') character. We are
190 // going to use the '\1' char as the end-of-message mark.
191 ssl_crt_validator->eom = '\1';
192 assert(ssl_crt_validator->cmdline == nullptr);
193
194 /* defaults */
195 int ttl = 3600; // 1 hour
196 size_t cache = 64*1024*1024; // 64 MB
197 {
198 // TODO: Do this during parseConfigFile() for proper parsing, error handling
199 char *tmp = xstrdup(Ssl::TheConfig.ssl_crt_validator);
200 char *tmp_begin = tmp;
201 char * token = nullptr;
202 bool parseParams = true;
203 while ((token = strwordtok(nullptr, &tmp))) {
204 if (parseParams) {
205 if (strcmp(token, "ttl=infinity") == 0) {
207 continue;
208 } else if (strncmp(token, "ttl=", 4) == 0) {
209 ttl = xatoi(token + 4);
210 if (ttl < 0) {
211 throw TextException(ToSBuf("Negative TTL in sslcrtvalidator_program ", Ssl::TheConfig.ssl_crt_validator,
212 Debug::Extra, "For unlimited TTL, use ttl=infinity"),
213 Here());
214 }
215 continue;
216 } else if (strncmp(token, "cache=", 6) == 0) {
217 cache = xatoi(token + 6);
218 continue;
219 } else
220 parseParams = false;
221 }
222 wordlistAdd(&ssl_crt_validator->cmdline, token);
223 }
224 xfree(tmp_begin);
225 }
226 helperOpenServers(ssl_crt_validator);
227
228 //WARNING: initializing static member in an object initialization method
229 assert(HelperCache == nullptr);
230 HelperCache = new CacheType(cache, ttl);
231}
232
234{
235 if (!ssl_crt_validator)
236 return;
237 helperShutdown(ssl_crt_validator);
238 wordlistDestroy(&ssl_crt_validator->cmdline);
239 delete ssl_crt_validator;
240 ssl_crt_validator = nullptr;
241
242 // CertValidationHelper::HelperCache is a static member, it is not good policy to
243 // reset it here. Will work because the current Ssl::CertValidationHelper is
244 // always the same static object.
245 delete HelperCache;
246 HelperCache = nullptr;
247}
248
249void
251{
252 Shutdown();
253 Init();
254}
255
257{
259
260public:
264};
266
267static void
268sslCrtvdHandleReplyWrapper(void *data, const ::Helper::Reply &reply)
269{
271
272 submitData *crtdvdData = static_cast<submitData *>(data);
273 assert(crtdvdData->ssl.get());
274 Ssl::CertValidationResponse::Pointer validationResponse = new Ssl::CertValidationResponse(crtdvdData->ssl);
275 if (reply.result == ::Helper::BrokenHelper) {
276 debugs(83, DBG_IMPORTANT, "ERROR: \"ssl_crtvd\" helper error response: " << reply.other().content());
277 validationResponse->resultCode = ::Helper::BrokenHelper;
278 } else if (!reply.other().hasContent()) {
279 debugs(83, DBG_IMPORTANT, "\"ssl_crtvd\" helper returned NULL response");
280 validationResponse->resultCode = ::Helper::BrokenHelper;
281 } else if (replyMsg.parse(reply.other().content(), reply.other().contentSize()) != Ssl::CrtdMessage::OK ||
282 !replyMsg.parseResponse(*validationResponse) ) {
283 debugs(83, DBG_IMPORTANT, "WARNING: Reply from ssl_crtvd for " << " is incorrect");
284 debugs(83, DBG_IMPORTANT, "ERROR: Certificate cannot be validated. ssl_crtvd response: " << replyMsg.getBody());
285 validationResponse->resultCode = ::Helper::BrokenHelper;
286 } else
287 validationResponse->resultCode = reply.result;
288
289 crtdvdData->callback.answer() = validationResponse;
290 ScheduleCallHere(crtdvdData->callback.release());
291
293 (validationResponse->resultCode == ::Helper::Okay || validationResponse->resultCode == ::Helper::Error)) {
294 (void)Ssl::CertValidationHelper::HelperCache->add(crtdvdData->query, validationResponse);
295 }
296
297 delete crtdvdData;
298}
299
300void
302{
305 message.composeRequest(request);
306 debugs(83, 5, "SSL crtvd request: " << message.compose().c_str());
307
308 submitData *crtdvdData = new submitData;
309 crtdvdData->query.assign(message.compose().c_str());
310 crtdvdData->query.append('\n');
311 crtdvdData->callback = callback;
312 crtdvdData->ssl = request.ssl;
313 Ssl::CertValidationResponse::Pointer const*validationResponse;
314
316 (validationResponse = CertValidationHelper::HelperCache->get(crtdvdData->query))) {
317
318 crtdvdData->callback.answer() = *validationResponse;
319 ScheduleCallHere(crtdvdData->callback.release());
320 delete crtdvdData;
321 return;
322 }
323
324 // ssl_crt_validator becomes nil if Squid is reconfigured with cert
325 // validator disabled in the new configuration
326 if (ssl_crt_validator && ssl_crt_validator->trySubmit(crtdvdData->query.c_str(), sslCrtvdHandleReplyWrapper, crtdvdData))
327 return;
328
330 resp->resultCode = ::Helper::BrokenHelper;
331 crtdvdData->callback.answer() = resp;
332 ScheduleCallHere(crtdvdData->callback.release());
333 delete crtdvdData;
334 return;
335}
336
#define ScheduleCallHere(call)
Definition: AsyncCall.h:165
#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:393
#define assert(EX)
Definition: assert.h:17
#define CBDATA_CLASS_INIT(type)
Definition: cbdata.h:320
#define CBDATA_CLASS(type)
Definition: cbdata.h:289
#define CBDATA_NAMESPACED_CLASS_INIT(namespace, type)
Definition: cbdata.h:328
an old-style void* callback parameter
Definition: cbdata.h:379
Definition: ClpMap.h:41
static std::ostream & Extra(std::ostream &os)
prefixes each grouped debugs() line after the first one in the group
Definition: Stream.h:114
ChildConfig & updateLimits(const ChildConfig &rhs)
Definition: ChildConfig.cc:44
NotePairs notes
Definition: Reply.h:62
Value value
instance identifier
Definition: InstanceId.h:69
void add(const SBuf &key, const SBuf &value)
Definition: Notes.cc:312
Definition: SBuf.h:94
const char * c_str()
Definition: SBuf.cc:516
const InstanceId< SBuf > id
Definition: SBuf.h:604
SBuf & append(const SBuf &S)
Definition: SBuf.cc:185
SBuf & assign(const SBuf &S)
Definition: SBuf.cc:83
static void Submit(const Ssl::CertValidationRequest &, const Callback &)
Submit crtd request message to external crtd server.
Definition: helper.cc:301
static CacheType * HelperCache
cache for cert validation helper
Definition: helper.h:59
static void Shutdown()
Shutdown helper structure.
Definition: helper.cc:233
static helper * ssl_crt_validator
helper for management of ssl_crtd.
Definition: helper.h:56
static void Init()
Init helper structure.
Definition: helper.cc:172
AsyncCallback< Answer > Callback
Definition: helper.h:47
static void Reconfigure()
Definition: helper.cc:250
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)
Definition: crtd_message.cc:23
std::string compose() const
A pending Ssl::Helper request, combining the original and collapsed queries.
Definition: helper.cc:42
void emplace(HLPCB *callback, void *data)
adds a GeneratorRequestor
Definition: helper.cc:47
GeneratorRequestors requestors
Definition: helper.cc:53
SBuf query
Ssl::Helper request message (GeneratorRequests key)
Definition: helper.cc:49
std::vector< GeneratorRequestor > GeneratorRequestors
Ssl::Helper request initiators waiting for the same answer (FIFO).
Definition: helper.cc:52
Initiator of an Ssl::Helper query.
Definition: helper.cc:34
GeneratorRequestor(HLPCB *aCallback, void *aData)
Definition: helper.cc:36
CallbackData data
Definition: helper.cc:38
static helper * ssl_crtd
helper for management of ssl_crtd.
Definition: helper.h:37
static void Submit(CrtdMessage const &message, HLPCB *callback, void *data)
Submit crtd message to external crtd server.
Definition: helper.cc:125
static void Init()
Init helper structure.
Definition: helper.cc:77
static void Reconfigure()
Definition: helper.cc:119
static void Shutdown()
Shutdown helper structure.
Definition: helper.cc:108
an std::runtime_error with thrower location info
Definition: TextException.h:21
Definition: cbdata.cc:38
void * data
Definition: cbdata.cc:78
Definition: helper.h:64
char eom
The char which marks the end of (response) message, normally ' '.
Definition: helper.h:122
wordlist * cmdline
Definition: helper.h:107
Helper::ChildConfig childs
Configuration settings for number running.
Definition: helper.h:111
int ipc_type
Definition: helper.h:112
Ssl::CertValidationHelper::Callback callback
Definition: helper.cc:262
SBuf query
Definition: helper.cc:261
Security::SessionPointer ssl
Definition: helper.cc:263
A const & max(A const &lhs, A const &rhs)
#define DBG_IMPORTANT
Definition: Stream.h:38
#define debugs(SECTION, LEVEL, CONTENT)
Definition: Stream.h:193
#define IPC_STREAM
Definition: defines.h:106
void HLPCB(void *, const Helper::Reply &)
Definition: forward.h:27
void helperShutdown(helper *hlp)
Definition: helper.cc:740
void helperOpenServers(helper *hlp)
Definition: helper.cc:201
void Init(void)
prepares to parse ACLs configuration
Definition: AclRegs.cc:114
@ BrokenHelper
Definition: ResultCode.h:20
@ Error
Definition: ResultCode.h:19
@ Okay
Definition: ResultCode.h:18
std::shared_ptr< SSL > SessionPointer
Definition: Session.h:49
Definition: Xaction.cc:40
std::unordered_map< SBuf, GeneratorRequest * > GeneratorRequests
Ssl::Helper query:GeneratorRequest map.
Definition: helper.cc:57
Config TheConfig
Definition: Config.cc:12
static void HandleGeneratorReply(void *data, const ::Helper::Reply &reply)
receives helper response
Definition: helper.cc:154
#define xfree
#define xstrdup
SBuf ToSBuf(Args &&... args)
slowly stream-prints all arguments into a freshly allocated SBuf
Definition: Stream.h:63
static Ssl::GeneratorRequests TheGeneratorRequests
pending Ssl::Helper requests (to all certificate generator helpers combined)
Definition: helper.cc:73
static void sslCrtvdHandleReplyWrapper(void *data, const ::Helper::Reply &reply)
Definition: helper.cc:268
static std::ostream & operator<<(std::ostream &os, const Ssl::GeneratorRequest &gr)
prints Ssl::GeneratorRequest for debugging
Definition: helper.cc:67
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

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors