void authenticateProxyUserCacheCleanup(void *datanotused) { /* * We walk the hash by username as that is the unique key we use. * For big hashs we could consider stepping through the cache, 100/200 * entries at a time. Lets see how it flys first. */ auth_user_hash_pointer *usernamehash; auth_user_t *auth_user; char *username = NULL; debug(29, 3) ("authenticateProxyUserCacheCleanup: Cleaning the user cache now\n"); debug(29, 3) ("authenticateProxyUserCacheCleanup: Current time: %ld\n", (long int) current_time.tv_sec); hash_first(proxy_auth_username_cache); while ((usernamehash = ((auth_user_hash_pointer *) hash_next(proxy_auth_username_cache)))) { auth_user = usernamehash->auth_user; username = authenticateUserUsername(auth_user); /* if we need to have inpedendent expiry clauses, insert a module call * here */ debug(29, 4) ("authenticateProxyUserCacheCleanup: Cache entry:\n\tType: %d\n\tUsername: %s\n\texpires: %ld\n\treferences: %ld\n", auth_user->auth_type, username, (long int) (auth_user->expiretime + Config.authenticateTTL), (long int) auth_user->references); if (auth_user->expiretime + Config.authenticateTTL <= current_time.tv_sec) { debug(29, 5) ("authenticateProxyUserCacheCleanup: Removing user %s from cache due to timeout.\n", username); /* the minus 1 accounts for the cache lock */ if ((authenticateAuthUserInuse(auth_user) - 1)) debug(29, 4) ("authenticateProxyUserCacheCleanup: this cache entry has expired AND has a non-zero ref count.\n"); else authenticateAuthUserUnlock(auth_user); } } debug(29, 3) ("authenticateProxyUserCacheCleanup: Finished cleaning the user cache.\n"); eventAdd("User Cache Maintenance", authenticateProxyUserCacheCleanup, NULL, Config.authenticateGCInterval, 1); }
/* authenticateUserRequestUsername: return a pointer to the username in the */ char * authenticateUserRequestUsername(auth_user_request_t * auth_user_request) { assert(auth_user_request != NULL); if (auth_user_request->auth_user) return authenticateUserUsername(auth_user_request->auth_user); else return NULL; }
/* UserNameCacheAdd: add a auth_user structure to the username cache */ void authenticateUserNameCacheAdd(auth_user_t * auth_user) { auth_user_hash_pointer *usernamehash; usernamehash = memAllocate(MEM_AUTH_USER_HASH); usernamehash->key = authenticateUserUsername(auth_user); usernamehash->auth_user = auth_user; hash_join(proxy_auth_username_cache, (hash_link *) usernamehash); auth_user->usernamehash = usernamehash; /* lock for presence in the cache */ authenticateAuthUserLock(auth_user); }
void authenticateUserCacheRestart(void) { auth_user_hash_pointer *usernamehash; auth_user_t *auth_user; char *username = NULL; debug(29, 3) ("authenticateUserCacheRestart: Clearing config dependent cache data.\n"); hash_first(proxy_auth_username_cache); while ((usernamehash = ((auth_user_hash_pointer *) hash_next(proxy_auth_username_cache)))) { auth_user = usernamehash->auth_user; username = authenticateUserUsername(auth_user); debug(29, 5) ("authenticateUserCacheRestat: Clearing cache ACL results for user: %s\n", username); aclCacheMatchFlush(&auth_user->proxy_match_cache); } }
char * internalRedirectProcessURL(clientHttpRequest * req, rewritetoken * head) { char *dev = NULL; size_t len = 0; debug(85, 5) ("internalRedirectProcessURL: start\n"); for (; head != NULL; head = head->next) { const char *str = NULL; /* string to append */ size_t str_len = 0; int do_ulong = 0; unsigned long ulong = 0; const char *ulong_fmt = "%lu"; debug(85, 5) ("internalRedirectProcessURL: token=%s str=%s urlEncode=%s\n", tokenNames[head->type], head->str, head->urlEncode ? "true" : "false"); switch (head->type) { case RFT_STRING: str = head->str; str_len = head->str_len; break; case RFT_CLIENT_IPADDRESS: str = inet_ntoa(req->conn->peer.sin_addr); break; case RFT_LOCAL_IPADDRESS: str = inet_ntoa(req->conn->me.sin_addr); break; case RFT_LOCAL_PORT: ulong = ntohs(req->conn->me.sin_port); do_ulong = 1; break; case RFT_EPOCH_SECONDS: ulong = current_time.tv_sec; do_ulong = 1; break; case RFT_TIME_SUBSECONDS: ulong = current_time.tv_usec / 1000; do_ulong = 1; ulong_fmt = "%03lu"; break; case RFT_USERNAME: if (req->request->auth_user_request) str = authenticateUserUsername(req->request->auth_user_request->auth_user); if (!str || !*str) str = req->conn->rfc931; #ifdef USE_SSL if ((!str || !*str) && req->conn != NULL) str = sslGetUserEmail(fd_table[req->conn->fd].ssl); #endif if (!str || !*str) str = req->request->extacl_user; break; case RFT_USERLOGIN: str = req->request->login; break; case RFT_USERIDENT: str = req->conn->rfc931; break; case RFT_USERSSL: #ifdef USE_SSL if (req->conn != NULL) str = sslGetUserEmail(fd_table[req->conn->fd].ssl); #endif break; case RFT_EXTERNALACL_USER: str = req->request->extacl_user; break; case RFT_METHOD: str = req->request->method->string; break; case RFT_PROTOCOL: str = ProtocolStr[req->request->protocol]; break; case RFT_URL: str = req->uri; break; case RFT_URLPATH: str = req->request->urlpath.buf; break; case RFT_URLHOST: str = req->request->host; break; case RFT_HDRHOST: str = httpHeaderGetStr(&req->request->header, HDR_HOST); break; case RFT_EXTERNALACL_LOGSTR: str = req->request->extacl_log.buf; break; default: assert(0 && "Invalid rewrite token type"); break; } if (do_ulong) { char tmpstr[12]; int nbytes = snprintf(tmpstr, 12, ulong_fmt, ulong); assert(nbytes > 0); dev = xreacat(dev, &len, tmpstr, nbytes); } else { if ((str == NULL) || (*str == '\0')) str = "-"; if (str_len == 0) str_len = strlen(str); if (head->urlEncode) { str = rfc1738_escape_part(str); str_len = strlen(str); } dev = xreacat(dev, &len, str, str_len); } } debug(85, 5) ("internalRedirectProcessURL: done: %s\n", dev); return dev; }
static void authenticateAuthUserRequestSetIp(auth_user_request_t * auth_user_request, struct in_addr ipaddr) { auth_user_ip_t *ipdata, *tempnode; auth_user_t *auth_user; char *ip1; int found = 0; CBDATA_INIT_TYPE(auth_user_ip_t); if (!auth_user_request->auth_user) return; auth_user = auth_user_request->auth_user; ipdata = (auth_user_ip_t *) auth_user->ip_list.head; /* * we walk the entire list to prevent the first item in the list * preventing old entries being flushed and locking a user out after * a timeout+reconfigure */ while (ipdata) { tempnode = (auth_user_ip_t *) ipdata->node.next; /* walk the ip list */ if (ipdata->ipaddr.s_addr == ipaddr.s_addr) { /* This ip has already been seen. */ found = 1; /* update IP ttl */ ipdata->ip_expiretime = squid_curtime; } else if (ipdata->ip_expiretime + Config.authenticateIpTTL < squid_curtime) { /* This IP has expired - remove from the seen list */ dlinkDelete(&ipdata->node, &auth_user->ip_list); cbdataFree(ipdata); /* catch incipient underflow */ assert(auth_user->ipcount); auth_user->ipcount--; } ipdata = tempnode; } if (found) return; /* This ip is not in the seen list */ ipdata = cbdataAlloc(auth_user_ip_t); ipdata->ip_expiretime = squid_curtime; ipdata->ipaddr = ipaddr; dlinkAddTail(ipdata, &ipdata->node, &auth_user->ip_list); auth_user->ipcount++; ip1 = xstrdup(inet_ntoa(ipaddr)); debug(29, 2) ("authenticateAuthUserRequestSetIp: user '%s' has been seen at a new IP address (%s)\n ", authenticateUserUsername(auth_user), ip1); safe_free(ip1); }
static void authenticateDigestDecodeAuth(auth_user_request_t * auth_user_request, const char *proxy_auth) { String temp; const char *item; const char *p; const char *pos = NULL; char *username = NULL; digest_nonce_h *nonce; int ilen; digest_request_h *digest_request; digest_user_h *digest_user; auth_user_t *auth_user; dlink_node *node; debug(29, 9) ("authenticateDigestDecodeAuth: beginning\n"); assert(auth_user_request != NULL); digest_request = authDigestRequestNew(); /* trim DIGEST from string */ while (xisgraph(*proxy_auth)) proxy_auth++; /* Trim leading whitespace before decoding */ while (xisspace(*proxy_auth)) proxy_auth++; stringInit(&temp, proxy_auth); while (strListGetItem(&temp, ',', &item, &ilen, &pos)) { if ((p = strchr(item, '=')) && (p - item < ilen)) ilen = p++ - item; if (!strncmp(item, "username", ilen)) { /* white space */ while (xisspace(*p)) p++; /* quote mark */ p++; username = xstrndup(p, strchr(p, '"') + 1 - p); debug(29, 9) ("authDigestDecodeAuth: Found Username '%s'\n", username); } else if (!strncmp(item, "realm", ilen)) { /* white space */ while (xisspace(*p)) p++; /* quote mark */ p++; digest_request->realm = xstrndup(p, strchr(p, '"') + 1 - p); debug(29, 9) ("authDigestDecodeAuth: Found realm '%s'\n", digest_request->realm); } else if (!strncmp(item, "qop", ilen)) { /* white space */ while (xisspace(*p)) p++; if (*p == '\"') /* quote mark */ p++; digest_request->qop = xstrndup(p, strcspn(p, "\" \t\r\n()<>@,;:\\/[]?={}") + 1); debug(29, 9) ("authDigestDecodeAuth: Found qop '%s'\n", digest_request->qop); } else if (!strncmp(item, "algorithm", ilen)) { /* white space */ while (xisspace(*p)) p++; if (*p == '\"') /* quote mark */ p++; digest_request->algorithm = xstrndup(p, strcspn(p, "\" \t\r\n()<>@,;:\\/[]?={}") + 1); debug(29, 9) ("authDigestDecodeAuth: Found algorithm '%s'\n", digest_request->algorithm); } else if (!strncmp(item, "uri", ilen)) { /* white space */ while (xisspace(*p)) p++; /* quote mark */ p++; digest_request->uri = xstrndup(p, strchr(p, '"') + 1 - p); debug(29, 9) ("authDigestDecodeAuth: Found uri '%s'\n", digest_request->uri); } else if (!strncmp(item, "nonce", ilen)) { /* white space */ while (xisspace(*p)) p++; /* quote mark */ p++; digest_request->nonceb64 = xstrndup(p, strchr(p, '"') + 1 - p); debug(29, 9) ("authDigestDecodeAuth: Found nonce '%s'\n", digest_request->nonceb64); } else if (!strncmp(item, "nc", ilen)) { /* white space */ while (xisspace(*p)) p++; xstrncpy(digest_request->nc, p, 9); debug(29, 9) ("authDigestDecodeAuth: Found noncecount '%s'\n", digest_request->nc); } else if (!strncmp(item, "cnonce", ilen)) { /* white space */ while (xisspace(*p)) p++; /* quote mark */ p++; digest_request->cnonce = xstrndup(p, strchr(p, '"') + 1 - p); debug(29, 9) ("authDigestDecodeAuth: Found cnonce '%s'\n", digest_request->cnonce); } else if (!strncmp(item, "response", ilen)) { /* white space */ while (xisspace(*p)) p++; /* quote mark */ p++; digest_request->response = xstrndup(p, strchr(p, '"') + 1 - p); debug(29, 9) ("authDigestDecodeAuth: Found response '%s'\n", digest_request->response); } } stringClean(&temp); /* now we validate the data given to us */ /* * TODO: on invalid parameters we should return 400, not 407. * Find some clean way of doing this. perhaps return a valid * struct, and set the direction to clientwards combined with * a change to the clientwards handling code (ie let the * clientwards call set the error type (but limited to known * correct values - 400/401/407 */ /* first the NONCE count */ if (digest_request->cnonce && strlen(digest_request->nc) != 8) { debug(29, 4) ("authenticateDigestDecode: nonce count length invalid\n"); authDigestLogUsername(auth_user_request, username); /* we don't need the scheme specific data anymore */ authDigestRequestDelete(digest_request); auth_user_request->scheme_data = NULL; return; } /* now the nonce */ nonce = authenticateDigestNonceFindNonce(digest_request->nonceb64); if (!nonce) { /* we couldn't find a matching nonce! */ debug(29, 4) ("authenticateDigestDecode: Unexpected or invalid nonce recieved\n"); authDigestLogUsername(auth_user_request, username); /* we don't need the scheme specific data anymore */ authDigestRequestDelete(digest_request); auth_user_request->scheme_data = NULL; return; } digest_request->nonce = nonce; authDigestNonceLink(nonce); /* check the qop is what we expected. Note that for compatability with * RFC 2069 we should support a missing qop. Tough. */ if (!digest_request->qop || strcmp(digest_request->qop, QOP_AUTH)) { /* we recieved a qop option we didn't send */ debug(29, 4) ("authenticateDigestDecode: Invalid qop option recieved\n"); authDigestLogUsername(auth_user_request, username); /* we don't need the scheme specific data anymore */ authDigestRequestDelete(digest_request); auth_user_request->scheme_data = NULL; return; } /* we can't check the URI just yet. We'll check it in the * authenticate phase */ /* is the response the correct length? */ if (!digest_request->response || strlen(digest_request->response) != 32) { debug(29, 4) ("authenticateDigestDecode: Response length invalid\n"); authDigestLogUsername(auth_user_request, username); /* we don't need the scheme specific data anymore */ authDigestRequestDelete(digest_request); auth_user_request->scheme_data = NULL; return; } /* do we have a username ? */ if (!username || username[0] == '\0') { debug(29, 4) ("authenticateDigestDecode: Empty or not present username\n"); authDigestLogUsername(auth_user_request, username); /* we don't need the scheme specific data anymore */ authDigestRequestDelete(digest_request); auth_user_request->scheme_data = NULL; return; } /* check that we're not being hacked / the username hasn't changed */ if (nonce->auth_user && strcmp(username, authenticateUserUsername(nonce->auth_user))) { debug(29, 4) ("authenticateDigestDecode: Username for the nonce does not equal the username for the request\n"); authDigestLogUsername(auth_user_request, username); /* we don't need the scheme specific data anymore */ authDigestRequestDelete(digest_request); auth_user_request->scheme_data = NULL; return; } /* if we got a qop, did we get a cnonce or did we get a cnonce wihtout a qop? */ if ((digest_request->qop && !digest_request->cnonce) || (!digest_request->qop && digest_request->cnonce)) { debug(29, 4) ("authenticateDigestDecode: qop without cnonce, or vice versa!\n"); authDigestLogUsername(auth_user_request, username); /* we don't need the scheme specific data anymore */ authDigestRequestDelete(digest_request); auth_user_request->scheme_data = NULL; return; } /* check the algorithm is present and supported */ if (!digest_request->algorithm) digest_request->algorithm = xstrndup("MD5", 4); else if (strcmp(digest_request->algorithm, "MD5") && strcmp(digest_request->algorithm, "MD5-sess")) { debug(29, 4) ("authenticateDigestDecode: invalid algorithm specified!\n"); authDigestLogUsername(auth_user_request, username); /* we don't need the scheme specific data anymore */ authDigestRequestDelete(digest_request); auth_user_request->scheme_data = NULL; return; } /* the method we'll check at the authenticate step as well */ /* we don't send or parse opaques. Ok so we're flexable ... */ /* find the user */ if ((auth_user = authDigestUserFindUsername(username)) == NULL) { /* the user doesn't exist in the username cache yet */ debug(29, 9) ("authDigestDecodeAuth: Creating new digest user '%s'\n", username); /* new auth_user */ auth_user = authenticateAuthUserNew("digest"); /* new scheme user data */ digest_user = authDigestUserNew(); /* save the username */ digest_user->username = username; /* link the primary struct in */ auth_user->scheme_data = digest_user; /* set the user type */ auth_user->auth_type = AUTH_DIGEST; /* this auth_user struct is the one to get added to the * username cache */ /* store user in hash's */ authenticateUserNameCacheAdd(auth_user); /* * Add the digest to the user so we can tell if a hacking * or spoofing attack is taking place. We do this by assuming * the user agent won't change user name without warning. */ authDigestUserLinkNonce(auth_user, nonce); } else { debug(29, 9) ("authDigestDecodeAuth: Found user '%s' in the user cache as '%p'\n", username, auth_user); digest_user = auth_user->scheme_data; xfree(username); } /*link the request and the user */ auth_user_request->auth_user = auth_user; auth_user_request->scheme_data = digest_request; /* lock for the request link */ authenticateAuthUserLock(auth_user); node = dlinkNodeNew(); dlinkAdd(auth_user_request, node, &auth_user->requests); debug(29, 9) ("username = '******'\nrealm = '%s'\nqop = '%s'\nalgorithm = '%s'\nuri = '%s'\nnonce = '%s'\nnc = '%s'\ncnonce = '%s'\nresponse = '%s'\ndigestnonce = '%p'\n", digest_user->username, digest_request->realm, digest_request->qop, digest_request->algorithm, digest_request->uri, digest_request->nonceb64, digest_request->nc, digest_request->cnonce, digest_request->response, nonce); return; }