From: Christos Tsantilas Date: Wed, 18 Jul 2012 16:21:47 +0000 (+0300) Subject: merge from trunk (r12216 v3.2.0.18+) X-Git-Tag: sourceformat-review-1~173^2 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=71cae3894fd0c52dd4b4bfedb3ac1323eb619a73;p=thirdparty%2Fsquid.git merge from trunk (r12216 v3.2.0.18+) --- 71cae3894fd0c52dd4b4bfedb3ac1323eb619a73 diff --cc src/AccessLogEntry.cc index 4f86995316,31ea406864..cfab6e533b --- a/src/AccessLogEntry.cc +++ b/src/AccessLogEntry.cc @@@ -1,14 -1,6 +1,14 @@@ #include "squid.h" #include "AccessLogEntry.h" #include "HttpRequest.h" +#include "ssl/support.h" + +#if USE_SSL - AccessLogEntry::Ssl::Ssl(): user(NULL), bumpMode(::Ssl::bumpEnd) ++AccessLogEntry::SslDetails::SslDetails(): user(NULL), bumpMode(::Ssl::bumpEnd) +{ +} +#endif /* USE_SSL */ + void AccessLogEntry::getLogClientIp(char *buf, size_t bufsz) const diff --cc src/AccessLogEntry.h index df2e8f8a68,2c12c4f168..6acbb646a6 --- a/src/AccessLogEntry.h +++ b/src/AccessLogEntry.h @@@ -111,17 -118,6 +118,17 @@@ public const char *opcode; } htcp; +#if USE_SSL + /// logging information specific to the SSL protocol - class Ssl { ++ class SslDetails { + public: - Ssl(); ++ SslDetails(); + + const char *user; ///< emailAddress from the SSL client certificate + int bumpMode; ///< whether and how the request was SslBumped + } ssl; +#endif + /** \brief This subclass holds log info for Squid internal stats * \todo Inner class declarations should be moved outside * \todo some details relevant to particular protocols need shuffling to other sub-classes diff --cc src/cache_cf.cc index 0e1c9242d2,83b4f6e09e..b1d936726d --- a/src/cache_cf.cc +++ b/src/cache_cf.cc @@@ -4400,261 -4319,70 +4338,326 @@@ static void free_icap_service_failure_l cfg->oldest_service_failure = 0; cfg->service_failure_limit = 0; } +#endif + +#if USE_SSL +static void parse_sslproxy_cert_adapt(sslproxy_cert_adapt **cert_adapt) +{ + char *al; + sslproxy_cert_adapt *ca = (sslproxy_cert_adapt *) xcalloc(1, sizeof(sslproxy_cert_adapt)); + if ((al = strtok(NULL, w_space)) == NULL) { + self_destruct(); + return; + } + + const char *param; + if ( char *s = strchr(al, '{')) { + *s = '\0'; // terminate the al string + s++; + param = s; + s = strchr(s, '}'); + if (!s) { + self_destruct(); + return; + } + *s = '\0'; + } + else + param = NULL; + + if (strcmp(al, Ssl::CertAdaptAlgorithmStr[Ssl::algSetValidAfter]) == 0) { + ca->alg = Ssl::algSetValidAfter; + ca->param = strdup("on"); + } + else if (strcmp(al, Ssl::CertAdaptAlgorithmStr[Ssl::algSetValidBefore]) == 0) { + ca->alg = Ssl::algSetValidBefore; + ca->param = strdup("on"); + } + else if (strcmp(al, Ssl::CertAdaptAlgorithmStr[Ssl::algSetCommonName]) == 0) { + ca->alg = Ssl::algSetCommonName; + if (param) { + if (strlen(param) > 64) { + debugs(3, DBG_CRITICAL, "FATAL: sslproxy_cert_adapt: setCommonName{" <param = strdup(param); + } + } else { + debugs(3, DBG_CRITICAL, "FATAL: sslproxy_cert_adapt: unknown cert adaptation algorithm: " << al); + self_destruct(); + return; + } + + aclParseAclList(LegacyParser, &ca->aclList); + + while(*cert_adapt) + cert_adapt = &(*cert_adapt)->next; + + *cert_adapt = ca; +} + +static void dump_sslproxy_cert_adapt(StoreEntry *entry, const char *name, sslproxy_cert_adapt *cert_adapt) +{ + for (sslproxy_cert_adapt *ca = cert_adapt; ca != NULL; ca = ca->next) { + storeAppendPrintf(entry, "%s ", name); + storeAppendPrintf(entry, "%s{%s} ", Ssl::sslCertAdaptAlgoritm(ca->alg), ca->param); + if (ca->aclList) + dump_acl_list(entry, ca->aclList); + storeAppendPrintf(entry, "\n"); + } +} + +static void free_sslproxy_cert_adapt(sslproxy_cert_adapt **cert_adapt) +{ + while(*cert_adapt) { + sslproxy_cert_adapt *ca = *cert_adapt; + *cert_adapt = ca->next; + safe_free(ca->param); + + if (ca->aclList) + aclDestroyAclList(&ca->aclList); + + safe_free(ca); + } +} + +static void parse_sslproxy_cert_sign(sslproxy_cert_sign **cert_sign) +{ + char *al; + sslproxy_cert_sign *cs = (sslproxy_cert_sign *) xcalloc(1, sizeof(sslproxy_cert_sign)); + if ((al = strtok(NULL, w_space)) == NULL) { + self_destruct(); + return; + } + + if (strcmp(al, Ssl::CertSignAlgorithmStr[Ssl::algSignTrusted]) == 0) + cs->alg = Ssl::algSignTrusted; + else if (strcmp(al, Ssl::CertSignAlgorithmStr[Ssl::algSignUntrusted]) == 0) + cs->alg = Ssl::algSignUntrusted; + else if (strcmp(al, Ssl::CertSignAlgorithmStr[Ssl::algSignSelf]) == 0) + cs->alg = Ssl::algSignSelf; + else { + debugs(3, DBG_CRITICAL, "FATAL: sslproxy_cert_sign: unknown cert signing algorithm: " << al); + self_destruct(); + return; + } + + aclParseAclList(LegacyParser, &cs->aclList); + + while(*cert_sign) + cert_sign = &(*cert_sign)->next; + + *cert_sign = cs; +} + +static void dump_sslproxy_cert_sign(StoreEntry *entry, const char *name, sslproxy_cert_sign *cert_sign) +{ + sslproxy_cert_sign *cs; + for (cs = cert_sign; cs != NULL; cs = cs->next) { + storeAppendPrintf(entry, "%s ", name); + storeAppendPrintf(entry, "%s ", Ssl::certSignAlgorithm(cs->alg)); + if (cs->aclList) + dump_acl_list(entry, cs->aclList); + storeAppendPrintf(entry, "\n"); + } +} + +static void free_sslproxy_cert_sign(sslproxy_cert_sign **cert_sign) +{ + while(*cert_sign) { + sslproxy_cert_sign *cs = *cert_sign; + *cert_sign = cs->next; + + if (cs->aclList) + aclDestroyAclList(&cs->aclList); + + safe_free(cs); + } +} + +class sslBumpCfgRr: public ::RegisteredRunner +{ +public: + static Ssl::BumpMode lastDeprecatedRule; + /* RegisteredRunner API */ + virtual void run(const RunnerRegistry &); +}; + +Ssl::BumpMode sslBumpCfgRr::lastDeprecatedRule = Ssl::bumpEnd; + +RunnerRegistrationEntry(rrFinalizeConfig, sslBumpCfgRr); + +void sslBumpCfgRr::run(const RunnerRegistry &r) +{ + if (lastDeprecatedRule != Ssl::bumpEnd) { + assert( lastDeprecatedRule == Ssl::bumpClientFirst || lastDeprecatedRule == Ssl::bumpNone); + static char buf[1024]; + if (lastDeprecatedRule == Ssl::bumpClientFirst) { + strcpy(buf, "ssl_bump deny all"); + debugs(3, DBG_CRITICAL, "WARNING: auto-converting deprecated implicit " + "\"ssl_bump deny all\" to \"ssl_bump none all\". New ssl_bump configurations " + "must not use implicit rules. Update your ssl_bump rules."); + } else { + strcpy(buf, "ssl_bump allow all"); + debugs(3, DBG_CRITICAL, "SECURITY NOTICE: auto-converting deprecated implicit " + "\"ssl_bump allow all\" to \"ssl_bump client-first all\" which is usually " + "inferior to the newer server-first bumping mode. New ssl_bump" + " configurations must not use implicit rules. Update your ssl_bump rules."); + } + parse_line(buf); + } +} + +static void parse_sslproxy_ssl_bump(acl_access **ssl_bump) +{ + typedef const char *BumpCfgStyle; + BumpCfgStyle bcsNone = NULL; + BumpCfgStyle bcsNew = "new client/server-first/none"; + BumpCfgStyle bcsOld = "deprecated allow/deny"; + static BumpCfgStyle bumpCfgStyleLast = bcsNone; + BumpCfgStyle bumpCfgStyleNow = bcsNone; + char *bm; + if ((bm = strtok(NULL, w_space)) == NULL) { + self_destruct(); + return; + } + + // if this is the first rule proccessed + if (*ssl_bump == NULL) { + bumpCfgStyleLast = bcsNone; + sslBumpCfgRr::lastDeprecatedRule = Ssl::bumpEnd; + } + + acl_access *A = new acl_access; + A->allow = allow_t(ACCESS_ALLOWED); + + if (strcmp(bm, Ssl::BumpModeStr[Ssl::bumpClientFirst]) == 0) { + A->allow.kind = Ssl::bumpClientFirst; + bumpCfgStyleNow = bcsNew; + } else if (strcmp(bm, Ssl::BumpModeStr[Ssl::bumpServerFirst]) == 0) { + A->allow.kind = Ssl::bumpServerFirst; + bumpCfgStyleNow = bcsNew; + } else if (strcmp(bm, Ssl::BumpModeStr[Ssl::bumpNone]) == 0) { + A->allow.kind = Ssl::bumpNone; + bumpCfgStyleNow = bcsNew; + } else if (strcmp(bm, "allow") == 0) { + debugs(3, DBG_CRITICAL, "SECURITY NOTICE: auto-converting deprecated " + "\"ssl_bump allow \" to \"ssl_bump client-first \" which " + "is usually inferior to the newer server-first " + "bumping mode. Update your ssl_bump rules."); + A->allow.kind = Ssl::bumpClientFirst; + bumpCfgStyleNow = bcsOld; + sslBumpCfgRr::lastDeprecatedRule = Ssl::bumpClientFirst; + } else if (strcmp(bm, "deny") == 0) { + debugs(3, DBG_CRITICAL, "WARNING: auto-converting deprecated " + "\"ssl_bump deny \" to \"ssl_bump none \". Update " + "your ssl_bump rules."); + A->allow.kind = Ssl::bumpNone; + bumpCfgStyleNow = bcsOld; + sslBumpCfgRr::lastDeprecatedRule = Ssl::bumpNone; + } else { + debugs(3, DBG_CRITICAL, "FATAL: unknown ssl_bump mode: " << bm); + self_destruct(); + return; + } + + if (bumpCfgStyleLast != bcsNone && bumpCfgStyleNow != bumpCfgStyleLast) { + debugs(3, DBG_CRITICAL, "FATAL: do not mix " << bumpCfgStyleNow << " actions with " << + bumpCfgStyleLast << " actions. Update your ssl_bump rules."); + self_destruct(); + return; + } + + bumpCfgStyleLast = bumpCfgStyleNow; + + aclParseAclList(LegacyParser, &A->aclList); + + acl_access *B, **T; + for (B = *ssl_bump, T = ssl_bump; B; T = &B->next, B = B->next); + *T = A; +} + +static void dump_sslproxy_ssl_bump(StoreEntry *entry, const char *name, acl_access *ssl_bump) +{ + acl_access *sb; + for (sb = ssl_bump; sb != NULL; sb = sb->next) { + storeAppendPrintf(entry, "%s ", name); + storeAppendPrintf(entry, "%s ", Ssl::bumpMode(sb->allow.kind)); + if (sb->aclList) + dump_acl_list(entry, sb->aclList); + storeAppendPrintf(entry, "\n"); + } +} + +static void free_sslproxy_ssl_bump(acl_access **ssl_bump) +{ + free_acl_access(ssl_bump); +} #endif + + static void dump_HeaderWithAclList(StoreEntry * entry, const char *name, HeaderWithAclList *headers) + { + if (!headers) + return; + + for (HeaderWithAclList::iterator hwa = headers->begin(); hwa != headers->end(); ++hwa) { + storeAppendPrintf(entry, "%s ", hwa->fieldName.c_str()); + storeAppendPrintf(entry, "%s ", hwa->fieldValue.c_str()); + if (hwa->aclList) + dump_acl_list(entry, hwa->aclList); + storeAppendPrintf(entry, "\n"); + } + } + + static void parse_HeaderWithAclList(HeaderWithAclList **headers) + { + char *fn; + if (!*headers) { + *headers = new HeaderWithAclList; + } + if ((fn = strtok(NULL, w_space)) == NULL) { + self_destruct(); + return; + } + HeaderWithAcl hwa; + hwa.fieldName = fn; + hwa.fieldId = httpHeaderIdByNameDef(fn, strlen(fn)); + if (hwa.fieldId == HDR_BAD_HDR) + hwa.fieldId = HDR_OTHER; + + String buf; + bool wasQuoted; + ConfigParser::ParseQuotedString(&buf, &wasQuoted); + hwa.fieldValue = buf.termedBuf(); + hwa.quoted = wasQuoted; + if (hwa.quoted) { + Format::Format *nlf = new ::Format::Format("hdrWithAcl"); + if (!nlf->parse(hwa.fieldValue.c_str())) { + self_destruct(); + return; + } + hwa.valueFormat = nlf; + } + aclParseAclList(LegacyParser, &hwa.aclList); + (*headers)->push_back(hwa); + } + + static void free_HeaderWithAclList(HeaderWithAclList **header) + { + if (!(*header)) + return; + + for (HeaderWithAclList::iterator hwa = (*header)->begin(); hwa != (*header)->end(); ++hwa) { + if (hwa->aclList) + aclDestroyAclList(&hwa->aclList); + + if (hwa->valueFormat) { + delete hwa->valueFormat; + hwa->valueFormat = NULL; + } + } + delete *header; + *header = NULL; + } diff --cc src/client_side.cc index 9914034c34,346156bdd8..10c04df54d --- a/src/client_side.cc +++ b/src/client_side.cc @@@ -2450,100 -2441,6 +2448,100 @@@ ConnStateData::clientAfterReadingReques readSomeData(); } +void +ConnStateData::quitAfterError(HttpRequest *request) +{ + // From HTTP p.o.v., we do not have to close after every error detected + // at the client-side, but many such errors do require closure and the + // client-side code is bad at handling errors so we play it safe. + if (request) + request->flags.proxy_keepalive = 0; + flags.readMore = false; + debugs(33,4, HERE << "Will close after error: " << clientConnection); +} + +#if USE_SSL +bool ConnStateData::serveDelayedError(ClientSocketContext *context) +{ + ClientHttpRequest *http = context->http; + + if (!sslServerBump) + return false; + + assert(sslServerBump->entry); + // Did we create an error entry while processing CONNECT? + if (!sslServerBump->entry->isEmpty()) { + quitAfterError(http->request); + + // Get the saved error entry and send it to the client by replacing the + // ClientHttpRequest store entry with it. + clientStreamNode *node = context->getClientReplyContext(); + clientReplyContext *repContext = dynamic_cast(node->data.getRaw()); + assert(repContext); + debugs(33, 5, "Responding with delated error for " << http->uri); + repContext->setReplyToStoreEntry(sslServerBump->entry); + + // save the original request for logging purposes - if (!context->http->al.request) - context->http->al.request = HTTPMSGLOCK(http->request); ++ if (!context->http->al->request) ++ context->http->al->request = HTTPMSGLOCK(http->request); + + // Get error details from the fake certificate-peeking request. + http->request->detailError(sslServerBump->request->errType, sslServerBump->request->errDetail); + context->pullData(); + return true; + } + + // In bump-server-first mode, we have not necessarily seen the intended + // server name at certificate-peeking time. Check for domain mismatch now, + // when we can extract the intended name from the bumped HTTP request. + if (sslServerBump->serverCert.get()) { + HttpRequest *request = http->request; + if (!Ssl::checkX509ServerValidity(sslServerBump->serverCert.get(), request->GetHost())) { + debugs(33, 2, "SQUID_X509_V_ERR_DOMAIN_MISMATCH: Certificate " << + "does not match domainname " << request->GetHost()); + + ACLFilledChecklist check(Config.ssl_client.cert_error, request, dash_str); + check.sslErrors = new Ssl::Errors(SQUID_X509_V_ERR_DOMAIN_MISMATCH); + if (Comm::IsConnOpen(pinning.serverConnection)) + check.fd(pinning.serverConnection->fd); + const bool allowDomainMismatch = + check.fastCheck() == ACCESS_ALLOWED; + delete check.sslErrors; + check.sslErrors = NULL; + + if (!allowDomainMismatch) { + quitAfterError(request); + + clientStreamNode *node = context->getClientReplyContext(); + clientReplyContext *repContext = dynamic_cast(node->data.getRaw()); + assert (repContext); + + // Fill the server IP and hostname for error page generation. + HttpRequest::Pointer const & peekerRequest = sslServerBump->request; + request->hier.note(peekerRequest->hier.tcpServer, request->GetHost()); + + // Create an error object and fill it + ErrorState *err = new ErrorState(ERR_SECURE_CONNECT_FAIL, HTTP_SERVICE_UNAVAILABLE, request); + err->src_addr = clientConnection->remote; + Ssl::ErrorDetail *errDetail = new Ssl::ErrorDetail( + SQUID_X509_V_ERR_DOMAIN_MISMATCH, + sslServerBump->serverCert.get(), NULL); + err->detail = errDetail; + // Save the original request for logging purposes. - if (!context->http->al.request) - context->http->al.request = HTTPMSGLOCK(request); ++ if (!context->http->al->request) ++ context->http->al->request = HTTPMSGLOCK(request); + repContext->setReplyToError(request->method, err); + assert(context->http->out.offset == 0); + context->pullData(); + return true; + } + } + } + + return false; +} +#endif // USE_SSL + static void clientProcessRequest(ConnStateData *conn, HttpParser *hp, ClientSocketContext *context, const HttpRequestMethod& method, HttpVersion http_ver) { diff --cc src/client_side_reply.cc index 16cf40a61e,69754bd439..6d9753dcc0 --- a/src/client_side_reply.cc +++ b/src/client_side_reply.cc @@@ -125,9 -117,12 +125,9 @@@ void clientReplyContext::setReplyToErro /* prevent confusion over whether we default to persistent or not */ http->request->flags.proxy_keepalive = 0; - http->al.http.code = errstate->httpStatus; + http->al->http.code = errstate->httpStatus; createStoreEntry(method, request_flags()); -#if USE_AUTH - errstate->auth_user_request = auth_user_request; -#endif assert(errstate->callback_data == NULL); errorAppendEntry(http->storeEntry(), errstate); /* Now the caller reads to get this */ diff --cc src/client_side_request.cc index 4522ac483c,27e72f2b94..956687d46c --- a/src/client_side_request.cc +++ b/src/client_side_request.cc @@@ -1277,40 -1286,17 +1284,40 @@@ ClientRequestContext::checkNoCacheDone( bool ClientRequestContext::sslBumpAccessCheck() { - if (http->request->method == METHOD_CONNECT && - Config.accessList.ssl_bump && http->getConn()->port->sslBump) { - debugs(85, 5, HERE << "SslBump possible, checking ACL"); + // If SSL connection tunneling or bumping decision has been made, obey it. + const Ssl::BumpMode bumpMode = http->getConn()->sslBumpMode; + if (bumpMode != Ssl::bumpEnd) { + debugs(85, 5, HERE << "SslBump already decided (" << bumpMode << + "), " << "ignoring ssl_bump for " << http->getConn()); - http->al.ssl.bumpMode = bumpMode; // inherited from bumped connection ++ http->al->ssl.bumpMode = bumpMode; // inherited from bumped connection + return false; + } - ACLFilledChecklist *acl_checklist = clientAclChecklistCreate(Config.accessList.ssl_bump, http); - acl_checklist->nonBlockingCheck(sslBumpAccessCheckDoneWrapper, this); - return true; - } else { - http->sslBumpNeeded(false); + // If we have not decided yet, decide whether to bump now. + + // Bumping here can only start with a CONNECT request on a bumping port + // (bumping of intercepted SSL conns is decided before we get 1st request). + // We also do not bump redirected CONNECT requests. + if (http->request->method != METHOD_CONNECT || http->redirect.status || + !Config.accessList.ssl_bump || !http->getConn()->port->sslBump) { - http->al.ssl.bumpMode = Ssl::bumpEnd; // SslBump does not apply; log - ++ http->al->ssl.bumpMode = Ssl::bumpEnd; // SslBump does not apply; log - + debugs(85, 5, HERE << "cannot SslBump this request"); return false; } + + // Do not bump during authentication: clients would not proxy-authenticate + // if we delay a 407 response and respond with 200 OK to CONNECT. + if (error && error->httpStatus == HTTP_PROXY_AUTHENTICATION_REQUIRED) { - http->al.ssl.bumpMode = Ssl::bumpEnd; // SslBump does not apply; log - ++ http->al->ssl.bumpMode = Ssl::bumpEnd; // SslBump does not apply; log - + debugs(85, 5, HERE << "no SslBump during proxy authentication"); + return false; + } + + debugs(85, 5, HERE << "SslBump possible, checking ACL"); + + ACLFilledChecklist *acl_checklist = clientAclChecklistCreate(Config.accessList.ssl_bump, http); + acl_checklist->nonBlockingCheck(sslBumpAccessCheckDoneWrapper, this); + return true; } /** @@@ -1328,16 -1314,9 +1335,16 @@@ sslBumpAccessCheckDoneWrapper(allow_t a } void -ClientRequestContext::sslBumpAccessCheckDone(bool doSslBump) +ClientRequestContext::sslBumpAccessCheckDone(const allow_t &answer) { - http->sslBumpNeeded(doSslBump); + if (!httpStateIsValid()) + return; + + const Ssl::BumpMode bumpMode = answer == ACCESS_ALLOWED ? + static_cast(answer.kind) : Ssl::bumpNone; + http->sslBumpNeed(bumpMode); // for processRequest() to bump if needed - http->al.ssl.bumpMode = bumpMode; // for logging ++ http->al->ssl.bumpMode = bumpMode; // for logging + http->doCallouts(); } #endif @@@ -1416,10 -1402,6 +1423,10 @@@ ClientHttpRequest::sslBumpEstablish(com return; } + // We lack HttpReply which logRequest() uses to log the status code. + // TODO: Use HttpReply instead of the "200 Connection established" string. - al.http.code = 200; ++ al->http.code = 200; + #if USE_AUTH // Preserve authentication info for the ssl-bumped request if (request->auth_user_request != NULL) @@@ -1520,70 -1499,68 +1527,70 @@@ ClientHttpRequest::doCallouts( assert(calloutContext); /*Save the original request for logging purposes*/ - if (!calloutContext->http->al.request) - calloutContext->http->al.request = HTTPMSGLOCK(request); + if (!calloutContext->http->al->request) + calloutContext->http->al->request = HTTPMSGLOCK(request); + if (!calloutContext->error) { // CVE-2009-0801: verify the Host: header is consistent with other known details. - if (!calloutContext->host_header_verify_done) { - debugs(83, 3, HERE << "Doing calloutContext->hostHeaderVerify()"); - calloutContext->host_header_verify_done = true; - calloutContext->hostHeaderVerify(); - return; - } + if (!calloutContext->host_header_verify_done) { + debugs(83, 3, HERE << "Doing calloutContext->hostHeaderVerify()"); + calloutContext->host_header_verify_done = true; + calloutContext->hostHeaderVerify(); + return; + } - if (!calloutContext->http_access_done) { - debugs(83, 3, HERE << "Doing calloutContext->clientAccessCheck()"); - calloutContext->http_access_done = true; - calloutContext->clientAccessCheck(); - return; - } + if (!calloutContext->http_access_done) { + debugs(83, 3, HERE << "Doing calloutContext->clientAccessCheck()"); + calloutContext->http_access_done = true; + calloutContext->clientAccessCheck(); + return; + } #if USE_ADAPTATION - if (!calloutContext->adaptation_acl_check_done) { - calloutContext->adaptation_acl_check_done = true; - if (Adaptation::AccessCheck::Start( + if (!calloutContext->adaptation_acl_check_done) { + calloutContext->adaptation_acl_check_done = true; + if (Adaptation::AccessCheck::Start( Adaptation::methodReqmod, Adaptation::pointPreCache, request, NULL, this)) - return; // will call callback - } + return; // will call callback + } #endif - if (!calloutContext->redirect_done) { - calloutContext->redirect_done = true; - assert(calloutContext->redirect_state == REDIRECT_NONE); + if (!calloutContext->redirect_done) { + calloutContext->redirect_done = true; + assert(calloutContext->redirect_state == REDIRECT_NONE); - if (Config.Program.redirect) { - debugs(83, 3, HERE << "Doing calloutContext->clientRedirectStart()"); - calloutContext->redirect_state = REDIRECT_PENDING; - calloutContext->clientRedirectStart(); - return; + if (Config.Program.redirect) { + debugs(83, 3, HERE << "Doing calloutContext->clientRedirectStart()"); + calloutContext->redirect_state = REDIRECT_PENDING; + calloutContext->clientRedirectStart(); + return; + } } - } - if (!calloutContext->adapted_http_access_done) { - debugs(83, 3, HERE << "Doing calloutContext->clientAccessCheck2()"); - calloutContext->adapted_http_access_done = true; - calloutContext->clientAccessCheck2(); - return; - } + if (!calloutContext->adapted_http_access_done) { + debugs(83, 3, HERE << "Doing calloutContext->clientAccessCheck2()"); + calloutContext->adapted_http_access_done = true; + calloutContext->clientAccessCheck2(); + return; + } - if (!calloutContext->interpreted_req_hdrs) { - debugs(83, 3, HERE << "Doing clientInterpretRequestHeaders()"); - calloutContext->interpreted_req_hdrs = 1; - clientInterpretRequestHeaders(this); - } + if (!calloutContext->interpreted_req_hdrs) { + debugs(83, 3, HERE << "Doing clientInterpretRequestHeaders()"); + calloutContext->interpreted_req_hdrs = 1; + clientInterpretRequestHeaders(this); + } - if (!calloutContext->no_cache_done) { - calloutContext->no_cache_done = true; + if (!calloutContext->no_cache_done) { + calloutContext->no_cache_done = true; - if (Config.accessList.noCache && request->flags.cachable) { - debugs(83, 3, HERE << "Doing calloutContext->checkNoCache()"); - calloutContext->checkNoCache(); - return; + if (Config.accessList.noCache && request->flags.cachable) { + debugs(83, 3, HERE << "Doing calloutContext->checkNoCache()"); + calloutContext->checkNoCache(); + return; + } } - } + } // if !calloutContext->error if (!calloutContext->tosToClientDone) { calloutContext->tosToClientDone = true; diff --cc src/format/ByteCode.h index b793693215,1470f08775..ef25149429 --- a/src/format/ByteCode.h +++ b/src/format/ByteCode.h @@@ -191,7 -191,8 +191,9 @@@ typedef enum #endif #if USE_SSL + LFT_SSL_BUMP_MODE, + LFT_SSL_USER_CERT_SUBJECT, + LFT_SSL_USER_CERT_ISSUER, #endif LFT_PERCENT /* special string cases for escaped chars */ diff --cc src/format/Format.cc index ba24d1a0c2,656e4a9e2b..de62d545b4 --- a/src/format/Format.cc +++ b/src/format/Format.cc @@@ -1005,12 -1006,23 +1006,30 @@@ Format::Format::assemble(MemBuf &mb, co break; #if USE_SSL + case LFT_SSL_BUMP_MODE: { + const Ssl::BumpMode mode = static_cast(al->ssl.bumpMode); + // for Ssl::bumpEnd, Ssl::bumpMode() returns NULL and we log '-' + out = Ssl::bumpMode(mode); + break; + } ++ + case LFT_SSL_USER_CERT_SUBJECT: + if (X509 *cert = al->cache.sslClientCert.get()) { + if (X509_NAME *subject = X509_get_subject_name(cert)) { + X509_NAME_oneline(subject, tmp, sizeof(tmp)); + out = tmp; + } + } + break; + + case LFT_SSL_USER_CERT_ISSUER: + if (X509 *cert = al->cache.sslClientCert.get()) { + if (X509_NAME *issuer = X509_get_issuer_name(cert)) { + X509_NAME_oneline(issuer, tmp, sizeof(tmp)); + out = tmp; + } + } + break; #endif case LFT_PERCENT: diff --cc src/format/Token.cc index 163405684f,1acd028171..c273a4f269 --- a/src/format/Token.cc +++ b/src/format/Token.cc @@@ -189,7 -189,8 +189,9 @@@ static TokenTableEntry TokenTableIcap[ #if USE_SSL // SSL (ssl::) tokens static TokenTableEntry TokenTableSsl[] = { + {"bump_mode", LFT_SSL_BUMP_MODE}, + {">cert_subject", LFT_SSL_USER_CERT_SUBJECT}, + {">cert_issuer", LFT_SSL_USER_CERT_ISSUER}, {NULL, LFT_NONE} }; #endif