auth_acl_t authenticateTryToAuthenticateAndSetAuthUser(auth_user_request_t ** auth_user_request, http_hdr_type headertype, request_t * request, ConnStateData * conn, struct in_addr src_addr) { /* If we have already been called, return the cached value */ auth_user_request_t *t = authTryGetUser(auth_user_request, conn, request); auth_acl_t result; if (t && t->lastReply != AUTH_ACL_CANNOT_AUTHENTICATE && t->lastReply != AUTH_ACL_HELPER) { if (!*auth_user_request) { *auth_user_request = t; authenticateAuthUserRequestLock(*auth_user_request); } if (!request->auth_user_request) { request->auth_user_request = t; authenticateAuthUserRequestLock(request->auth_user_request); } return t->lastReply; } /* ok, call the actual authenticator routine. */ result = authenticateAuthenticate(auth_user_request, headertype, request, conn, src_addr); t = authTryGetUser(auth_user_request, conn, request); if (t && result != AUTH_ACL_CANNOT_AUTHENTICATE && result != AUTH_ACL_HELPER) { t->lastReply = result; } return result; }
/* send the initial data to a digest authenticator module */ static void authenticateDigestStart(auth_user_request_t * auth_user_request, RH * handler, void *data) { authenticateStateData *r = NULL; char buf[8192]; digest_request_h *digest_request; digest_user_h *digest_user; assert(auth_user_request); assert(handler); assert(auth_user_request->auth_user->auth_type == AUTH_DIGEST); assert(auth_user_request->auth_user->scheme_data != NULL); assert(auth_user_request->scheme_data != NULL); digest_request = auth_user_request->scheme_data; digest_user = auth_user_request->auth_user->scheme_data; debug(29, 9) ("authenticateStart: '\"%s\":\"%s\"'\n", digest_user->username, digest_request->realm); if (digestConfig->authenticate == NULL) { handler(data, NULL); return; } r = cbdataAlloc(authenticateStateData); r->handler = handler; cbdataLock(data); r->data = data; r->auth_user_request = auth_user_request; authenticateAuthUserRequestLock(r->auth_user_request); snprintf(buf, 8192, "\"%s\":\"%s\"\n", digest_user->username, digest_request->realm); helperSubmit(digestauthenticators, buf, authenticateDigestHandleReply, r); }
static void authenticateAuthUserRequestLinkIp(auth_user_request_t * auth_user_request, const struct in_addr ipaddr, request_t * request) { auth_user_request_ip_hash_t *hash_entry; if (!Config.authenticateIpShortcircuitTTL) return; #ifdef CC_FRAMEWORK acl_access * acl = cc_get_acl_access_by_token_and_host("authenticate_ip_shortcircuit_access",request->host); if (acl && !aclCheckFastRequest(acl, request)) #else if (Config.accessList.auth_ip_shortcircuit && !aclCheckFastRequest(Config.accessList.auth_ip_shortcircuit, request)) #endif return; if (!auth_user_request_ip_hash) { auth_user_request_ip_hash = hash_create((HASHCMP *) cmp_in_addr, 7921, hash_in_addr); auth_user_request_ip_pool = memPoolCreate("auth_user_request_ip_hash_t", sizeof(auth_user_request_ip_hash_t)); } authenticateAuthUserRequestUnlinkIp(ipaddr); hash_entry = memPoolAlloc(auth_user_request_ip_pool); hash_entry->ipaddr = ipaddr; hash_entry->hash.key = &hash_entry->ipaddr; hash_entry->auth_user_request = auth_user_request; authenticateAuthUserRequestLock(hash_entry->auth_user_request); hash_entry->last_seen = squid_curtime; hash_join(auth_user_request_ip_hash, &hash_entry->hash); }
/* Get Auth User: Return a filled out auth_user structure for the given * Proxy Auth (or Auth) header. It may be a cached Auth User or a new * Unauthenticated structure. The structure is given an inital lock here. */ static auth_user_request_t * authenticateGetAuthUser(const char *proxy_auth) { auth_user_request_t *auth_user_request = authenticateAuthUserRequestNew(); /* and lock for the callers instance */ authenticateAuthUserRequestLock(auth_user_request); /* The scheme is allowed to provide a cached auth_user or a new one */ authenticateDecodeAuth(proxy_auth, auth_user_request); return auth_user_request; }
/* send the initial data to a basic authenticator module */ static void authenticateBasicStart(auth_user_request_t * auth_user_request, RH * handler, void *data) { authenticateStateData *r = NULL; char buf[8192]; char user[1024], pass[1024]; basic_data *basic_auth; assert(auth_user_request); assert(handler); assert(auth_user_request->auth_user->auth_type == AUTH_BASIC); assert(auth_user_request->auth_user->scheme_data != NULL); basic_auth = auth_user_request->auth_user->scheme_data; debug(29, 9) ("authenticateStart: '%s:%s'\n", basic_auth->username, basic_auth->passwd); if (basicConfig->authenticate == NULL) { handler(data, NULL); return; } /* check to see if the auth_user already has a request outstanding */ if (basic_auth->flags.credentials_ok == 2) { /* there is a request with the same credentials already being verified */ auth_basic_queue_node *node; node = xmalloc(sizeof(auth_basic_queue_node)); assert(node); /* save the details */ node->next = basic_auth->auth_queue; basic_auth->auth_queue = node; node->handler = handler; node->data = data; cbdataLock(data); return; } else { r = cbdataAlloc(authenticateStateData); r->handler = handler; cbdataLock(data); r->data = data; r->auth_user_request = auth_user_request; authenticateAuthUserRequestLock(r->auth_user_request); /* mark the user as haveing verification in progress */ basic_auth->flags.credentials_ok = 2; if (basicConfig->utf8) { latin1_to_utf8(user, sizeof(user), basic_auth->username); latin1_to_utf8(pass, sizeof(pass), basic_auth->passwd); xstrncpy(user, rfc1738_escape(user), sizeof(user)); xstrncpy(pass, rfc1738_escape(pass), sizeof(pass)); } else { xstrncpy(user, rfc1738_escape(basic_auth->username), sizeof(user)); xstrncpy(pass, rfc1738_escape(basic_auth->passwd), sizeof(pass)); } snprintf(buf, sizeof(buf), "%s %s\n", user, pass); helperSubmit(basicauthenticators, buf, authenticateBasicHandleReply, r); } }
static inline void modify_request(clientHttpRequest * http) { debug(97, 3)("modify_request: start, uri=[%s]\n", http->uri); request_t* old_request = http->request; request_t* new_request = urlParse(old_request->method, http->uri); safe_free(http->uri); if (new_request) { safe_free(http->uri); http->uri = xstrdup(urlCanonical(new_request)); if(!http->log_uri) http->log_uri = xstrdup(urlCanonicalClean(old_request)); new_request->http_ver = old_request->http_ver; httpHeaderAppend(&new_request->header, &old_request->header); new_request->client_addr = old_request->client_addr; new_request->client_port = old_request->client_port; #if FOLLOW_X_FORWARDED_FOR new_request->indirect_client_addr = old_request->indirect_client_addr; #endif /* FOLLOW_X_FORWARDED_FOR */ new_request->my_addr = old_request->my_addr; new_request->my_port = old_request->my_port; new_request->flags = old_request->flags; new_request->flags.redirected = 1; if (old_request->auth_user_request) { new_request->auth_user_request = old_request->auth_user_request; authenticateAuthUserRequestLock(new_request->auth_user_request); } if (old_request->body_reader) { new_request->body_reader = old_request->body_reader; new_request->body_reader_data = old_request->body_reader_data; old_request->body_reader = NULL; old_request->body_reader_data = NULL; } new_request->content_length = old_request->content_length; if (strBuf(old_request->extacl_log)) new_request->extacl_log = stringDup(&old_request->extacl_log); if (old_request->extacl_user) new_request->extacl_user = xstrdup(old_request->extacl_user); if (old_request->extacl_passwd) new_request->extacl_passwd = xstrdup(old_request->extacl_passwd); if(old_request->cc_request_private_data) { new_request->cc_request_private_data = old_request->cc_request_private_data; old_request->cc_request_private_data = NULL; } requestUnlink(old_request); http->request = requestLink(new_request); } }
static auth_user_request_t * authTryGetUser(auth_user_request_t ** auth_user_request, ConnStateData * conn, request_t * request) { if (*auth_user_request) return *auth_user_request; else if (request && request->auth_user_request) return request->auth_user_request; else if (conn && conn->auth_user_request) return conn->auth_user_request; else { request->auth_user_request = authenticateAuthUserRequestFindByIp(request->client_addr); if (request->auth_user_request) authenticateAuthUserRequestLock(request->auth_user_request); return request->auth_user_request; } }
/* send the initial data to a stateful negotiate authenticator module */ static void authenticateNegotiateStart(auth_user_request_t * auth_user_request, RH * handler, void *data) { authenticateStateData *r = NULL; char buf[MAX_AUTHTOKEN_LEN]; char *sent_string = NULL; negotiate_user_t *negotiate_user; negotiate_request_t *negotiate_request; auth_user_t *auth_user; assert(auth_user_request); auth_user = auth_user_request->auth_user; negotiate_user = auth_user->scheme_data; negotiate_request = auth_user_request->scheme_data; assert(negotiate_user); assert(negotiate_request); assert(handler); assert(data); assert(auth_user->auth_type == AUTH_NEGOTIATE); debug(29, 9) ("authenticateNegotiateStart: auth state '%d'\n", negotiate_request->auth_state); sent_string = negotiate_request->client_blob; debug(29, 9) ("authenticateNegotiateStart: state '%d'\n", negotiate_request->auth_state); debug(29, 9) ("authenticateNegotiateStart: '%s'\n", sent_string); if (negotiateConfig->authenticate == NULL) { debug(29, 0) ("authenticateNegotiateStart: no Negotiate program specified:'%s'\n", sent_string); handler(data, NULL); return; } /* Send blob to helper */ r = cbdataAlloc(authenticateStateData); r->handler = handler; cbdataLock(data); r->data = data; r->auth_user_request = auth_user_request; authenticateAuthUserRequestLock(r->auth_user_request); if (negotiate_request->auth_state == AUTHENTICATE_STATE_INITIAL) { snprintf(buf, MAX_AUTHTOKEN_LEN, "YR %s\n", sent_string); } else { snprintf(buf, MAX_AUTHTOKEN_LEN, "KK %s\n", sent_string); } negotiate_request->waiting = 1; safe_free(negotiate_request->client_blob); helperStatefulSubmit(negotiateauthenticators, buf, authenticateNegotiateHandleReply, r, negotiate_request->authserver); }
/* returns one of * AUTH_ACL_CHALLENGE, * AUTH_ACL_HELPER, * AUTH_ACL_CANNOT_AUTHENTICATE, * AUTH_AUTHENTICATED * * How to use: In your proxy-auth dependent acl code, use the following * construct: * int rv; * if ((rv = AuthenticateAuthenticate()) != AUTH_AUTHENTICATED) * return rv; * * when this code is reached, the request/connection is authenticated. * * if you have non-acl code, but want to force authentication, you need a * callback mechanism like the acl testing routines that will send a 40[1|7] to * the client when rv==AUTH_ACL_CHALLENGE, and will communicate with * the authenticateStart routine for rv==AUTH_ACL_HELPER */ auth_acl_t authenticateAuthenticate(auth_user_request_t ** auth_user_request, http_hdr_type headertype, request_t * request, ConnStateData * conn, struct in_addr src_addr) { const char *proxy_auth; assert(headertype != 0); proxy_auth = httpHeaderGetStr(&request->header, headertype); /* * a note on proxy_auth logix here: * proxy_auth==NULL -> unauthenticated request || already * authenticated connection so we test for an authenticated * connection when we recieve no authentication header. */ if (((proxy_auth == NULL) && (!authenticateUserAuthenticated(authTryGetUser(auth_user_request, conn, request)))) || (conn && conn->auth_type == AUTH_BROKEN)) { /* no header or authentication failed/got corrupted - restart */ if (conn) conn->auth_type = AUTH_UNKNOWN; debug(28, 4) ("authenticateAuthenticate: broken auth or no proxy_auth header. Requesting auth header.\n"); /* something wrong with the AUTH credentials. Force a new attempt */ if (conn && conn->auth_user_request) { authenticateAuthUserRequestUnlock(conn->auth_user_request); conn->auth_user_request = NULL; } if (*auth_user_request) { /* unlock the ACL lock */ authenticateAuthUserRequestUnlock(*auth_user_request); *auth_user_request = NULL; } return AUTH_ACL_CHALLENGE; } #if 0 /* * Is this an already authenticated connection with a new auth header? * No check for function required in the if: its compulsory for conn based * auth modules */ if (proxy_auth && conn && conn->auth_user_request && authenticateUserAuthenticated(conn->auth_user_request) && strcmp(proxy_auth, authscheme_list[conn->auth_user_request->auth_user->auth_module - 1].authConnLastHeader(conn->auth_user_request))) { debug(28, 2) ("authenticateAuthenticate: DUPLICATE AUTH - authentication header on already authenticated connection!. AU %p, Current user '%s' proxy_auth %s\n", conn->auth_user_request, authenticateUserRequestUsername(conn->auth_user_request), proxy_auth); /* remove this request struct - the link is already authed and it can't be to * reauth. */ /* This should _only_ ever occur on the first pass through * authenticateAuthenticate */ assert(*auth_user_request == NULL); /* unlock the conn lock on the auth_user_request */ authenticateAuthUserRequestUnlock(conn->auth_user_request); /* mark the conn as non-authed. */ conn->auth_user_request = NULL; /* Set the connection auth type */ conn->auth_type = AUTH_UNKNOWN; } #endif /* we have a proxy auth header and as far as we know this connection has * not had bungled connection oriented authentication happen on it. */ debug(28, 9) ("authenticateAuthenticate: header %s.\n", proxy_auth ? proxy_auth : NULL); if (*auth_user_request == NULL) { debug(28, 9) ("authenticateAuthenticate: This is a new checklist test on FD:%d\n", conn ? conn->fd : -1); if ((!request->auth_user_request) && (!conn || conn->auth_type == AUTH_UNKNOWN)) { /* beginning of a new request check */ debug(28, 4) ("authenticateAuthenticate: no connection authentication type\n"); if (!authenticateValidateUser(*auth_user_request = authenticateGetAuthUser(proxy_auth))) { /* the decode might have left a username for logging, or a message to * the user */ if (authenticateUserRequestUsername(*auth_user_request)) { /* lock the user for the request structure link */ authenticateAuthUserRequestLock(*auth_user_request); request->auth_user_request = *auth_user_request; } /* unlock the ACL reference granted by ...GetAuthUser. */ authenticateAuthUserRequestUnlock(*auth_user_request); *auth_user_request = NULL; return AUTH_ACL_CHALLENGE; } /* the user_request comes prelocked for the caller to GetAuthUser (us) */ } else if (request->auth_user_request) { *auth_user_request = request->auth_user_request; /* lock the user request for this ACL processing */ authenticateAuthUserRequestLock(*auth_user_request); } else { assert(conn); if (conn->auth_user_request != NULL) { *auth_user_request = conn->auth_user_request; /* lock the user request for this ACL processing */ authenticateAuthUserRequestLock(*auth_user_request); } else { /* failed connection based authentication */ debug(28, 4) ("authenticateAuthenticate: Auth user request %p conn-auth user request %p conn type %d authentication failed.\n", *auth_user_request, conn->auth_user_request, conn->auth_type); authenticateAuthUserRequestUnlock(*auth_user_request); *auth_user_request = NULL; return AUTH_ACL_CHALLENGE; } } } if (!authenticateUserAuthenticated(*auth_user_request)) { /* User not logged in. Log them in */ authenticateAuthenticateUser(*auth_user_request, request, conn, headertype); switch (authenticateDirection(*auth_user_request)) { case 1: if (!request->auth_user_request) { /* lock the user for the request structure link */ authenticateAuthUserRequestLock(*auth_user_request); request->auth_user_request = *auth_user_request; } /* fallthrough to -2 */ case -2: /* this ACL check is finished. Unlock. */ authenticateAuthUserRequestUnlock(*auth_user_request); *auth_user_request = NULL; return AUTH_ACL_CHALLENGE; case -1: /* we are partway through authentication within squid, * the *auth_user_request variables stores the auth_user_request * for the callback to here - Do not Unlock */ return AUTH_ACL_HELPER; } /* on 0 the authentication is finished - fallthrough */ /* See if user authentication failed for some reason */ if (!authenticateUserAuthenticated(*auth_user_request)) { if ((authenticateUserRequestUsername(*auth_user_request))) { if (!request->auth_user_request) { /* lock the user for the request structure link */ authenticateAuthUserRequestLock(*auth_user_request); request->auth_user_request = *auth_user_request; } } /* this ACL check is finished. Unlock. */ authenticateAuthUserRequestUnlock(*auth_user_request); *auth_user_request = NULL; return AUTH_ACL_CHALLENGE; } } /* copy username to request for logging on client-side */ /* the credentials are correct at this point */ if (!request->auth_user_request) { /* lock the user for the request structure link */ authenticateAuthUserRequestLock(*auth_user_request); request->auth_user_request = *auth_user_request; authenticateAuthUserRequestSetIp(*auth_user_request, src_addr); } /* Unlock the request - we've authenticated it */ authenticateAuthUserRequestUnlock(*auth_user_request); *auth_user_request = NULL; return AUTH_AUTHENTICATED; }
static void authenticateNegotiateAuthenticateUser(auth_user_request_t * auth_user_request, request_t * request, ConnStateData * conn, http_hdr_type type) { const char *proxy_auth, *blob; auth_user_t *auth_user; negotiate_request_t *negotiate_request; auth_user = auth_user_request->auth_user; assert(auth_user); assert(auth_user->auth_type == AUTH_NEGOTIATE); assert(auth_user->scheme_data != NULL); assert(auth_user_request->scheme_data != NULL); negotiate_request = auth_user_request->scheme_data; /* Check that we are in the client side, where we can generate * auth challenges */ if (!conn) { negotiate_request->auth_state = AUTHENTICATE_STATE_FAILED; debug(29, 1) ("authenticateNegotiateAuthenticateUser: attempt to perform authentication without a connection!\n"); return; } if (negotiate_request->waiting) { debug(29, 1) ("authenticateNegotiateAuthenticateUser: waiting for helper reply!\n"); return; } if (negotiate_request->server_blob) { debug(29, 2) ("authenticateNegotiateAuthenticateUser: need to challenge client '%s'!\n", negotiate_request->server_blob); return; } /* get header */ proxy_auth = httpHeaderGetStr(&request->header, type); blob = proxy_auth; while (xisspace(*blob) && *blob) blob++; while (!xisspace(*blob) && *blob) blob++; while (xisspace(*blob) && *blob) blob++; switch (negotiate_request->auth_state) { case AUTHENTICATE_STATE_NONE: /* we've received a negotiate request. pass to a helper */ debug(29, 9) ("authenticateNegotiateAuthenticateUser: auth state negotiate none. %s\n", proxy_auth); negotiate_request->auth_state = AUTHENTICATE_STATE_INITIAL; safe_free(negotiate_request->client_blob); negotiate_request->client_blob = xstrdup(blob); conn->auth_type = AUTH_NEGOTIATE; conn->auth_user_request = auth_user_request; negotiate_request->conn = conn; /* and lock for the connection duration */ debug(29, 9) ("authenticateNegotiateAuthenticateUser: Locking auth_user from the connection.\n"); authenticateAuthUserRequestLock(auth_user_request); negotiate_request->request = requestLink(request); return; break; case AUTHENTICATE_STATE_INITIAL: debug(29, 1) ("authenticateNegotiateAuthenticateUser: need to ask helper!\n"); return; break; case AUTHENTICATE_STATE_NEGOTIATE: /* we should have received a blob from the clien. pass it to the same * helper process */ debug(29, 9) ("authenticateNegotiateAuthenticateUser: auth state challenge with header %s.\n", proxy_auth); /* do a cache lookup here. If it matches it's a successful negotiate * challenge - release the helper and use the existing auth_user * details. */ safe_free(negotiate_request->client_blob); negotiate_request->client_blob = xstrdup(blob); if (negotiate_request->request) requestUnlink(negotiate_request->request); negotiate_request->request = requestLink(request); return; break; case AUTHENTICATE_STATE_DONE: fatal("authenticateNegotiateAuthenticateUser: unexpect auth state DONE! Report a bug to the squid developers.\n"); break; case AUTHENTICATE_STATE_FAILED: /* we've failed somewhere in authentication */ debug(29, 9) ("authenticateNegotiateAuthenticateUser: auth state negotiate failed. %s\n", proxy_auth); return; } return; }