#include "squid.h" #include "HttpRequest.h" #include "HttpReply.h" #include "client_side.h" #include "auth/UserRequest.h" #include "auth/AclProxyAuth.h" #include "acl/FilledChecklist.h" CBDATA_CLASS_INIT(ACLFilledChecklist); #if MOVED int ACLFilledChecklist::authenticated() { http_hdr_type headertype; if (NULL == request) { fatal ("requiresRequest SHOULD have been true for this ACL!!"); return 0; } else if (request->flags.accelerated) { /* WWW authorization on accelerated requests */ headertype = HDR_AUTHORIZATION; } else if (request->flags.intercepted || request->flags.spoof_client_ip) { debugs(28, DBG_IMPORTANT, HERE << " authentication not applicable on intercepted requests."); return -1; } else { /* Proxy authorization on proxy requests */ headertype = HDR_PROXY_AUTHORIZATION; } /* get authed here */ /* Note: this fills in auth_user_request when applicable */ /* * DPW 2007-05-08 * tryToAuthenticateAndSetAuthUser used to try to lock and * unlock auth_user_request on our behalf, but it was too * ugly and hard to follow. Now we do our own locking here. * * I'm not sure what tryToAuthenticateAndSetAuthUser does when * auth_user_request is set before calling. I'm tempted to * unlock and set it to NULL, but it seems safer to save the * pointer before calling and unlock it afterwards. If the * pointer doesn't change then its a no-op. */ AuthUserRequest *old_auth_user_request = auth_user_request; auth_acl_t result = AuthUserRequest::tryToAuthenticateAndSetAuthUser (&auth_user_request, headertype, request, conn(), src_addr); if (auth_user_request) AUTHUSERREQUESTLOCK(auth_user_request, "ACLFilledChecklist"); AUTHUSERREQUESTUNLOCK(old_auth_user_request, "old ACLFilledChecklist"); switch (result) { case AUTH_ACL_CANNOT_AUTHENTICATE: debugs(28, 4, "aclMatchAcl: returning 0 user authenticated but not authorised."); return 0; case AUTH_AUTHENTICATED: return 1; break; case AUTH_ACL_HELPER: debugs(28, 4, "aclMatchAcl: returning 0 sending credentials to helper."); changeState (ProxyAuthLookup::Instance()); return 0; case AUTH_ACL_CHALLENGE: debugs(28, 4, "aclMatchAcl: returning 0 sending authentication challenge."); changeState (ProxyAuthNeeded::Instance()); return 0; default: fatal("unexpected authenticateAuthenticate reply\n"); return 0; } } #endif void ACLFilledChecklist::checkCallback(allow_t answer) { debugs(28, 5, "ACLFilledChecklist::checkCallback: " << this << " answer=" << answer); /* During reconfigure, we can end up not finishing call * sequences into the auth code */ if (auth_user_request) { /* the filled_checklist lock */ AUTHUSERREQUESTUNLOCK(auth_user_request, "ACLFilledChecklist"); /* it might have been connection based */ /* * DPW 2007-05-08 * yuck, this make me uncomfortable. why do this here? * ConnStateData will do its own unlocking. */ /* BUG 2827: the connection may also not exist. ie fast ACL tests vs client disconnection. */ if (conn()) { AUTHUSERREQUESTUNLOCK(conn()->auth_user_request, "conn via ACLFilledChecklist"); conn()->auth_type = AUTH_BROKEN; } } ACLChecklist::checkCallback(answer); // may delete us } void * ACLFilledChecklist::operator new (size_t size) { assert (size == sizeof(ACLFilledChecklist)); CBDATA_INIT_TYPE(ACLFilledChecklist); ACLFilledChecklist *result = cbdataAlloc(ACLFilledChecklist); return result; } void ACLFilledChecklist::operator delete (void *address) { ACLFilledChecklist *t = static_cast(address); cbdataFree(t); } ACLFilledChecklist::ACLFilledChecklist() : dst_peer(NULL), dst_rdns(NULL), request (NULL), reply (NULL), auth_user_request (NULL), #if SQUID_SNMP snmp_community(NULL), #endif #if USE_SSL ssl_error(0), #endif extacl_entry (NULL), conn_(NULL), fd_(-1), destinationDomainChecked_(false), sourceDomainChecked_(false) { my_addr.SetEmpty(); src_addr.SetEmpty(); dst_addr.SetEmpty(); rfc931[0] = '\0'; } ACLFilledChecklist::~ACLFilledChecklist() { assert (!asyncInProgress()); safe_free(dst_rdns); // created by xstrdup(). if (extacl_entry) cbdataReferenceDone(extacl_entry); HTTPMSGUNLOCK(request); HTTPMSGUNLOCK(reply); // no auth_user_request in builds without any Authentication configured if (auth_user_request) AUTHUSERREQUESTUNLOCK(auth_user_request, "ACLFilledChecklist destructor"); cbdataReferenceDone(conn_); debugs(28, 4, HERE << "ACLFilledChecklist destroyed " << this); } ConnStateData * ACLFilledChecklist::conn() const { return conn_; } void ACLFilledChecklist::conn(ConnStateData *aConn) { assert (conn() == NULL); conn_ = cbdataReference(aConn); } int ACLFilledChecklist::fd() const { return conn_ != NULL ? conn_->fd : fd_; } void ACLFilledChecklist::fd(int aDescriptor) { assert(!conn() || conn()->fd == aDescriptor); fd_ = aDescriptor; } bool ACLFilledChecklist::destinationDomainChecked() const { return destinationDomainChecked_; } void ACLFilledChecklist::markDestinationDomainChecked() { assert (!finished() && !destinationDomainChecked()); destinationDomainChecked_ = true; } bool ACLFilledChecklist::sourceDomainChecked() const { return sourceDomainChecked_; } void ACLFilledChecklist::markSourceDomainChecked() { assert (!finished() && !sourceDomainChecked()); sourceDomainChecked_ = true; } /* * There are two common ACLFilledChecklist lifecycles paths: * * A) Using aclCheckFast(): The caller creates an ACLFilledChecklist object * on stack and calls aclCheckFast(). * * B) Using aclNBCheck() and callbacks: The caller allocates an * ACLFilledChecklist object (via operator new) and passes it to * aclNBCheck(). Control eventually passes to ACLChecklist::checkCallback(), * which will invoke the callback function as requested by the * original caller of aclNBCheck(). This callback function must * *not* delete the list. After the callback function returns, * checkCallback() will delete the list (i.e., self). */ ACLFilledChecklist::ACLFilledChecklist(const acl_access *A, HttpRequest *http_request, const char *ident): dst_peer(NULL), dst_rdns(NULL), request(NULL), reply(NULL), auth_user_request(NULL), #if SQUID_SNMP snmp_community(NULL), #endif #if USE_SSL ssl_error(0), #endif extacl_entry (NULL), conn_(NULL), fd_(-1), destinationDomainChecked_(false), sourceDomainChecked_(false) { my_addr.SetEmpty(); src_addr.SetEmpty(); dst_addr.SetEmpty(); rfc931[0] = '\0'; // cbdataReferenceDone() is in either fastCheck() or the destructor if (A) accessList = cbdataReference(A); if (http_request != NULL) { request = HTTPMSGLOCK(http_request); #if FOLLOW_X_FORWARDED_FOR if (Config.onoff.acl_uses_indirect_client) src_addr = request->indirect_client_addr; else #endif /* FOLLOW_X_FORWARDED_FOR */ src_addr = request->client_addr; my_addr = request->my_addr; } #if USE_IDENT if (ident) xstrncpy(rfc931, ident, USER_IDENT_SZ); #endif } .