helper.cc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 1996-2020 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 "cache_cf.h"
13 #include "fs_io.h"
14 #include "helper/Reply.h"
15 #include "Parsing.h"
16 #include "sbuf/Stream.h"
17 #include "SquidConfig.h"
18 #include "SquidString.h"
19 #include "SquidTime.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 
31 namespace Ssl {
32 
35 public:
36  GeneratorRequestor(HLPCB *aCallback, void *aData): callback(aCallback), data(aData) {}
39 };
40 
44 
45 public:
47  void emplace(HLPCB *callback, void *data) { requestors.emplace_back(callback, data); }
48 
50 
52  typedef std::vector<GeneratorRequestor> GeneratorRequestors;
54 };
55 
57 typedef std::unordered_map<SBuf, GeneratorRequest*> GeneratorRequests;
58 
59 static void HandleGeneratorReply(void *data, const ::Helper::Reply &reply);
60 
61 } // namespace Ssl
62 
63 CBDATA_NAMESPACED_CLASS_INIT(Ssl, GeneratorRequest);
64 
66 static std::ostream &
67 operator <<(std::ostream &os, const Ssl::GeneratorRequest &gr)
68 {
69  return os << "crtGenRq" << gr.query.id.value << "/" << gr.requestors.size();
70 }
71 
74 
75 helper *Ssl::Helper::ssl_crtd = nullptr;
76 
78 {
79  assert(ssl_crtd == NULL);
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 != NULL; s = s->next)
85  found = s->flags.tunnelSslBumping && s->secure.generateHostCertificates;
86  if (!found)
87  return;
88 
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';
96  {
97  char *tmp = xstrdup(Ssl::TheConfig.ssl_crtd);
98  char *tmp_begin = tmp;
99  char *token = NULL;
100  while ((token = strwordtok(NULL, &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 = NULL;
116 }
117 
118 void
120 {
121  Shutdown();
122  Init();
123 }
124 
125 void 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 
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 
153 static void
154 Ssl::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 == NULL);
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 != NULL; 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 == NULL);
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 = NULL;
202  bool parseParams = true;
203  while ((token = strwordtok(NULL, &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 == NULL);
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 = NULL;
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 = NULL;
247 }
248 
249 void
251 {
252  Shutdown();
253  Init();
254 }
255 
257 {
259 
260 public:
264 };
266 
267 static void
268 sslCrtvdHandleReplyWrapper(void *data, const ::Helper::Reply &reply)
269 {
271  std::string error;
272 
273  submitData *crtdvdData = static_cast<submitData *>(data);
274  assert(crtdvdData->ssl.get());
275  Ssl::CertValidationResponse::Pointer validationResponse = new Ssl::CertValidationResponse(crtdvdData->ssl);
276  if (reply.result == ::Helper::BrokenHelper) {
277  debugs(83, DBG_IMPORTANT, "\"ssl_crtvd\" helper error response: " << reply.other().content());
278  validationResponse->resultCode = ::Helper::BrokenHelper;
279  } else if (!reply.other().hasContent()) {
280  debugs(83, DBG_IMPORTANT, "\"ssl_crtvd\" helper returned NULL response");
281  validationResponse->resultCode = ::Helper::BrokenHelper;
282  } else if (replyMsg.parse(reply.other().content(), reply.other().contentSize()) != Ssl::CrtdMessage::OK ||
283  !replyMsg.parseResponse(*validationResponse, error) ) {
284  debugs(83, DBG_IMPORTANT, "WARNING: Reply from ssl_crtvd for " << " is incorrect");
285  debugs(83, DBG_IMPORTANT, "Certificate cannot be validated. ssl_crtvd response: " << replyMsg.getBody());
286  validationResponse->resultCode = ::Helper::BrokenHelper;
287  } else
288  validationResponse->resultCode = reply.result;
289 
291  Must(dialer);
292  dialer->arg1 = validationResponse;
293  ScheduleCallHere(crtdvdData->callback);
294 
296  (validationResponse->resultCode == ::Helper::Okay || validationResponse->resultCode == ::Helper::Error)) {
297  (void)Ssl::CertValidationHelper::HelperCache->add(crtdvdData->query, validationResponse);
298  }
299 
300  delete crtdvdData;
301 }
302 
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  CertValidationHelper::CbDialer *dialer = dynamic_cast<CertValidationHelper::CbDialer*>(callback->getDialer());
321  Must(dialer);
322  dialer->arg1 = *validationResponse;
324  delete crtdvdData;
325  return;
326  }
327 
328  // ssl_crt_validator becomes nil if Squid is reconfigured with cert
329  // validator disabled in the new configuration
330  if (ssl_crt_validator && ssl_crt_validator->trySubmit(crtdvdData->query.c_str(), sslCrtvdHandleReplyWrapper, crtdvdData))
331  return;
332 
334  resp->resultCode = ::Helper::BrokenHelper;
336  Must(dialer);
337  dialer->arg1 = resp;
339  delete crtdvdData;
340  return;
341 }
342 
an old-style void* callback parameter
Definition: cbdata.h:377
Value value
instance identifier
Definition: InstanceId.h:69
void helperOpenServers(helper *hlp)
Definition: helper.cc:196
Helper::ChildConfig childs
Configuration settings for number running.
Definition: helper.h:110
std::vector< GeneratorRequestor > GeneratorRequestors
Ssl::Helper request initiators waiting for the same answer (FIFO).
Definition: helper.cc:52
#define Here()
source code location of the caller
Definition: Here.h:15
void wordlistDestroy(wordlist **list)
destroy a wordlist
Definition: wordlist.cc:16
static void HandleGeneratorReply(void *data, const ::Helper::Reply &reply)
receives helper response
Definition: helper.cc:154
static Ssl::GeneratorRequests TheGeneratorRequests
pending Ssl::Helper requests (to all certificate generator helpers combined)
Definition: helper.cc:73
wordlist * cmdline
Definition: helper.h:106
SBuf & assign(const SBuf &S)
Definition: SBuf.cc:83
static std::ostream & Extra(std::ostream &os)
prefixes each grouped debugs() line after the first one in the group
Definition: Debug.h:104
@ Error
Definition: ResultCode.h:19
AnyP::PortCfgPointer HttpPortList
list of Squid http(s)_port configured
Definition: PortCfg.cc:21
Security::SessionPointer ssl
Definition: helper.cc:263
#define CBDATA_NAMESPACED_CLASS_INIT(namespace, type)
Definition: cbdata.h:326
static const std::string code_cert_validate
String code for "cert_validate" messages.
Initiator of an Ssl::Helper query.
Definition: helper.cc:34
void composeRequest(CertValidationRequest const &vcert)
GeneratorRequestors requestors
Definition: helper.cc:53
#define ScheduleCallHere(call)
Definition: AsyncCall.h:166
void error(char *format,...)
static void Submit(CrtdMessage const &message, HLPCB *callback, void *data)
Submit crtd message to external crtd server.
Definition: helper.cc:125
#define CBDATA_CLASS(type)
Definition: cbdata.h:302
int ipc_type
Definition: helper.h:111
Definition: SBuf.h:87
static void sslCrtvdHandleReplyWrapper(void *data, const ::Helper::Reply &reply)
Definition: helper.cc:268
static void Shutdown()
Shutdown helper structure.
Definition: helper.cc:233
#define xstrdup
virtual CallDialer * getDialer()=0
Definition: cbdata.cc:61
std::string const & getBody() const
Current body. If parsing is not finished the method returns incompleted body.
ChildConfig & updateLimits(const ChildConfig &rhs)
Definition: ChildConfig.cc:44
#define DBG_IMPORTANT
Definition: Debug.h:46
A const & max(A const &lhs, A const &rhs)
SBuf query
Ssl::Helper request message (GeneratorRequests key)
Definition: helper.cc:49
static void Reconfigure()
Definition: helper.cc:250
static void Init()
Init helper structure.
Definition: helper.cc:77
#define NULL
Definition: types.h:166
static void Init()
Init helper structure.
Definition: helper.cc:172
#define debugs(SECTION, LEVEL, CONTENT)
Definition: Debug.h:128
void * data
Definition: cbdata.cc:123
static void Shutdown()
Shutdown helper structure.
Definition: helper.cc:108
std::string compose() const
char * strwordtok(char *buf, char **t)
Definition: String.cc:407
Definition: helper.h:64
Definition: ClpMap.h:41
Definition: Xaction.cc:48
NotePairs notes
Definition: Reply.h:62
void const char HLPCB void * data
Definition: stub_helper.cc:16
int xatoi(const char *token)
Definition: Parsing.cc:43
static helper * ssl_crtd
helper for management of ssl_crtd.
Definition: helper.h:37
#define safe_free(x)
Definition: xalloc.h:73
static std::ostream & operator<<(std::ostream &os, const Ssl::GeneratorRequest &gr)
prints Ssl::GeneratorRequest for debugging
Definition: helper.cc:67
Config TheConfig
Definition: Config.cc:12
#define assert(EX)
Definition: assert.h:19
@ Okay
Definition: ResultCode.h:18
void helperShutdown(helper *hlp)
Definition: helper.cc:735
static void Reconfigure()
Definition: helper.cc:119
const char * c_str()
Definition: SBuf.cc:523
#define CBDATA_CLASS_INIT(type)
Definition: cbdata.h:318
SBuf & append(const SBuf &S)
Definition: SBuf.cc:192
#define xfree
void setCode(std::string const &aCode)
Set new request/reply code to compose.
std::shared_ptr< SSL > SessionPointer
Definition: Session.h:46
ParseResult parse(const char *buffer, size_t len)
Definition: crtd_message.cc:21
CallbackData data
Definition: helper.cc:38
SBuf query
Definition: helper.cc:258
an std::runtime_error with thrower location info
Definition: TextException.h:20
SBuf ToSBuf(Args &&... args)
slowly stream-prints all arguments into a freshly allocated SBuf
Definition: Stream.h:124
#define Must(condition)
Like assert() but throws an exception instead of aborting the process.
Definition: TextException.h:72
A pending Ssl::Helper request, combining the original and collapsed queries.
Definition: helper.cc:42
void const char HLPCB * callback
Definition: stub_helper.cc:16
static void Submit(Ssl::CertValidationRequest const &request, AsyncCall::Pointer &)
Submit crtd request message to external crtd server.
Definition: helper.cc:303
void add(const SBuf &key, const SBuf &value)
Definition: Notes.cc:312
@ BrokenHelper
Definition: ResultCode.h:20
GeneratorRequestor(HLPCB *aCallback, void *aData)
Definition: helper.cc:36
AsyncCall::Pointer callback
Definition: helper.cc:262
std::unordered_map< SBuf, GeneratorRequest * > GeneratorRequests
Ssl::Helper query:GeneratorRequest map.
Definition: helper.cc:57
void HLPCB(void *, const Helper::Reply &)
Definition: forward.h:27
static CacheType * HelperCache
cache for cert validation helper
Definition: helper.h:58
const char * wordlistAdd(wordlist **list, const char *key)
Definition: wordlist.cc:25
const InstanceId< SBuf > id
Definition: SBuf.h:593
#define IPC_STREAM
Definition: defines.h:161
struct _request * request(char *urlin)
Definition: tcp-banger2.c:291
void Init(void)
prepares to parse ACLs configuration
Definition: AclRegs.cc:114
static helper * ssl_crt_validator
helper for management of ssl_crtd.
Definition: helper.h:55
char eom
The char which marks the end of (response) message, normally ' '.
Definition: helper.h:121
void emplace(HLPCB *callback, void *data)
adds a GeneratorRequestor
Definition: helper.cc:47
bool parseResponse(CertValidationResponse &resp, std::string &error)
Parse a response message and fill the resp object with parsed information.

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors