📄 auth_digest.c
字号:
/* * $Id: auth_digest.c,v 1.21 2006/07/30 23:27:04 hno Exp $ * * DEBUG: section 29 Authenticator * AUTHOR: Robert Collins * * SQUID Internet Object Cache http://squid.nlanr.net/Squid/ * ---------------------------------------------------------- * * Squid is the result of efforts by numerous individuals from the * Internet community. Development is led by Duane Wessels of the * National Laboratory for Applied Network Research and funded by the * National Science Foundation. Squid is Copyrighted (C) 1998 by * the Regents of the University of California. Please see the * COPYRIGHT file for full details. Squid incorporates software * developed and/or copyrighted by other sources. Please see the * CREDITS file for full details. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. * *//* The functions in this file handle authentication. * They DO NOT perform access control or auditing. * See acl.c for access control and client_side.c for auditing */#include "squid.h"#include "rfc2617.h"#include "auth_digest.h"extern AUTHSSETUP authSchemeSetup_digest;static voidauthenticateStateFree(authenticateStateData * r){ if (r->auth_user_request) { authenticateAuthUserRequestUnlock(r->auth_user_request); r->auth_user_request = NULL; } cbdataFree(r);}/* Digest Scheme */static HLPCB authenticateDigestHandleReply;static AUTHSACTIVE authenticateDigestActive;static AUTHSADDHEADER authDigestAddHeader;#if WAITING_FOR_TEstatic AUTHSADDTRAILER authDigestAddTrailer;#endifstatic AUTHSAUTHED authDigestAuthenticated;static AUTHSAUTHUSER authenticateDigestAuthenticateUser;static AUTHSCONFIGURED authDigestConfigured;static AUTHSDIRECTION authenticateDigestDirection;static AUTHSDECODE authenticateDigestDecodeAuth;static AUTHSDUMP authDigestCfgDump;static AUTHSFIXERR authenticateDigestFixHeader;static AUTHSFREE authenticateDigestUserFree;static AUTHSFREECONFIG authDigestFreeConfig;static AUTHSINIT authDigestInit;static AUTHSPARSE authDigestParse;static AUTHSCHECKCONFIG authDigestCheckConfig;static AUTHSREQFREE authDigestAURequestFree;static AUTHSSTART authenticateDigestStart;static AUTHSSTATS authenticateDigestStats;static AUTHSUSERNAME authenticateDigestUsername;static AUTHSSHUTDOWN authDigestDone;static helper *digestauthenticators = NULL;static hash_table *digest_nonce_cache;static auth_digest_config *digestConfig = NULL;static int authdigest_initialised = 0;static MemPool *digest_user_pool = NULL;static MemPool *digest_request_pool = NULL;static MemPool *digest_nonce_pool = NULL;CBDATA_TYPE(authenticateStateData);/* * * Nonce Functions * */static void authenticateDigestNonceCacheCleanup(void *data);static digest_nonce_h *authenticateDigestNonceFindNonce(const char *nonceb64);static digest_nonce_h *authenticateDigestNonceNew(void);static void authenticateDigestNonceDelete(digest_nonce_h * nonce);static void authenticateDigestNonceSetup(void);static void authenticateDigestNonceShutdown(void);static void authenticateDigestNonceReconfigure(void);static const char *authenticateDigestNonceNonceb64(digest_nonce_h * nonce);static int authDigestNonceIsValid(digest_nonce_h * nonce, char nc[9]);static int authDigestNonceIsStale(digest_nonce_h * nonce);static void authDigestNonceEncode(digest_nonce_h * nonce);static int authDigestNonceLastRequest(digest_nonce_h * nonce);static void authDigestNonceLink(digest_nonce_h * nonce);static void authDigestNonceUnlink(digest_nonce_h * nonce);#if NOT_USEDstatic int authDigestNonceLinks(digest_nonce_h * nonce);#endifstatic void authDigestNonceUserUnlink(digest_nonce_h * nonce);static void authDigestNoncePurge(digest_nonce_h * nonce);static voidauthDigestNonceEncode(digest_nonce_h * nonce){ if (!nonce) return; if (nonce->hash.key) xfree(nonce->hash.key); nonce->hash.key = xstrdup(base64_encode_bin((char *) &(nonce->noncedata), sizeof(digest_nonce_data)));}static digest_nonce_h *authenticateDigestNonceNew(void){ digest_nonce_h *newnonce = memPoolAlloc(digest_nonce_pool); digest_nonce_h *temp;/* NONCE CREATION - NOTES AND REASONING. RBC 20010108 * === EXCERPT FROM RFC 2617 === * The contents of the nonce are implementation dependent. The quality * of the implementation depends on a good choice. A nonce might, for * example, be constructed as the base 64 encoding of * * time-stamp H(time-stamp ":" ETag ":" private-key) * * where time-stamp is a server-generated time or other non-repeating * value, ETag is the value of the HTTP ETag header associated with * the requested entity, and private-key is data known only to the * server. With a nonce of this form a server would recalculate the * hash portion after receiving the client authentication header and * reject the request if it did not match the nonce from that header * or if the time-stamp value is not recent enough. In this way the * server can limit the time of the nonce's validity. The inclusion of * the ETag prevents a replay request for an updated version of the * resource. (Note: including the IP address of the client in the * nonce would appear to offer the server the ability to limit the * reuse of the nonce to the same client that originally got it. * However, that would break proxy farms, where requests from a single * user often go through different proxies in the farm. Also, IP * address spoofing is not that hard.) * ==== * * Now for my reasoning: * We will not accept a unrecognised nonce->we have all recognisable * nonces stored If we send out unique base64 encodings we guarantee * that a given nonce applies to only one user (barring attacks or * really bad timing with expiry and creation). Using a random * component in the nonce allows us to loop to find a unique nonce. * We use H(nonce_data) so the nonce is meaningless to the reciever. * So our nonce looks like base64(H(timestamp,pointertohash,randomdata)) * And even if our randomness is not very random (probably due to * bad coding on my part) we don't really care - the timestamp and * memory pointer should provide enough protection for the users * authentication. */ /* create a new nonce */ newnonce->nc = 0; newnonce->flags.valid = 1; newnonce->noncedata.self = newnonce; newnonce->noncedata.creationtime = current_time.tv_sec; newnonce->noncedata.randomdata = squid_random(); authDigestNonceEncode(newnonce); /* * loop until we get a unique nonce. The nonce creation must * have a random factor */ while ((temp = authenticateDigestNonceFindNonce(newnonce->hash.key))) { /* create a new nonce */ newnonce->noncedata.randomdata = squid_random(); authDigestNonceEncode(newnonce); } hash_join(digest_nonce_cache, &newnonce->hash); /* the cache's link */ authDigestNonceLink(newnonce); newnonce->flags.incache = 1; debug(29, 5) ("authenticateDigestNonceNew: created nonce %p at %ld\n", newnonce, (long int) newnonce->noncedata.creationtime); return newnonce;}static voidauthenticateDigestNonceDelete(digest_nonce_h * nonce){ if (nonce) { assert(nonce->references == 0);#if UNREACHABLECODE if (nonce->flags.incache) hash_remove_link(digest_nonce_cache, &nonce->hash);#endif assert(nonce->flags.incache == 0); safe_free(nonce->hash.key); memPoolFree(digest_nonce_pool, nonce); }}static voidauthenticateDigestNonceSetup(void){ if (!digest_nonce_pool) digest_nonce_pool = memPoolCreate("Digest Scheme nonce's", sizeof(digest_nonce_h)); if (!digest_nonce_cache) { digest_nonce_cache = hash_create((HASHCMP *) strcmp, 7921, hash_string); assert(digest_nonce_cache); eventAdd("Digest none cache maintenance", authenticateDigestNonceCacheCleanup, NULL, digestConfig->nonceGCInterval, 1); }}static voidauthenticateDigestNonceShutdown(void){ /* * We empty the cache of any nonces left in there. */ digest_nonce_h *nonce; if (digest_nonce_cache) { debug(29, 2) ("authenticateDigestNonceShutdown: Shutting down nonce cache \n"); hash_first(digest_nonce_cache); while ((nonce = ((digest_nonce_h *) hash_next(digest_nonce_cache)))) { assert(nonce->flags.incache); authDigestNoncePurge(nonce); } } if (digest_nonce_pool) { assert(memPoolInUseCount(digest_nonce_pool) == 0); memPoolDestroy(digest_nonce_pool); digest_nonce_pool = NULL; } debug(29, 2) ("authenticateDigestNonceShutdown: Nonce cache shutdown\n");}static voidauthenticateDigestNonceReconfigure(void){}static voidauthenticateDigestNonceCacheCleanup(void *data){ /* * We walk the hash by nonceb64 as that is the unique key we * use. For big hash tables we could consider stepping through * the cache, 100/200 entries at a time. Lets see how it flies * first. */ digest_nonce_h *nonce; debug(29, 3) ("authenticateDigestNonceCacheCleanup: Cleaning the nonce cache now\n"); debug(29, 3) ("authenticateDigestNonceCacheCleanup: Current time: %ld\n", (long int) current_time.tv_sec); hash_first(digest_nonce_cache); while ((nonce = ((digest_nonce_h *) hash_next(digest_nonce_cache)))) { debug(29, 3) ("authenticateDigestNonceCacheCleanup: nonce entry : %p '%s'\n", nonce, (char *) nonce->hash.key); debug(29, 4) ("authenticateDigestNonceCacheCleanup: Creation time: %ld\n", (long int) nonce->noncedata.creationtime); if (authDigestNonceIsStale(nonce)) { debug(29, 4) ("authenticateDigestNonceCacheCleanup: Removing nonce %s from cache due to timeout.\n", (char *) nonce->hash.key); assert(nonce->flags.incache); /* invalidate nonce so future requests fail */ nonce->flags.valid = 0; /* if it is tied to a auth_user, remove the tie */ authDigestNonceUserUnlink(nonce); authDigestNoncePurge(nonce); } } debug(29, 3) ("authenticateDigestNonceCacheCleanup: Finished cleaning the nonce cache.\n"); if (authenticateDigestActive()) eventAdd("Digest none cache maintenance", authenticateDigestNonceCacheCleanup, NULL, digestConfig->nonceGCInterval, 1);}static voidauthDigestNonceLink(digest_nonce_h * nonce){ assert(nonce != NULL); nonce->references++; debug(29, 9) ("authDigestNonceLink: nonce '%p' now at '%d'.\n", nonce, nonce->references);}#if NOT_USEDstatic intauthDigestNonceLinks(digest_nonce_h * nonce){ if (!nonce) return -1; return nonce->references;}#endifstatic voidauthDigestNonceUnlink(digest_nonce_h * nonce){ assert(nonce != NULL); if (nonce->references > 0) { nonce->references--; } else { debug(29, 1) ("authDigestNonceUnlink; Attempt to lower nonce %p refcount below 0!\n", nonce); } debug(29, 9) ("authDigestNonceUnlink: nonce '%p' now at '%d'.\n", nonce, nonce->references); if (nonce->references == 0) authenticateDigestNonceDelete(nonce);}static const char *authenticateDigestNonceNonceb64(digest_nonce_h * nonce){ if (!nonce) return NULL; return nonce->hash.key;}static digest_nonce_h *authenticateDigestNonceFindNonce(const char *nonceb64){ digest_nonce_h *nonce = NULL; if (nonceb64 == NULL) return NULL; debug(29, 9) ("authDigestNonceFindNonce:looking for nonceb64 '%s' in the nonce cache.\n", nonceb64); nonce = hash_lookup(digest_nonce_cache, nonceb64); if ((nonce == NULL) || (strcmp(nonce->hash.key, nonceb64))) return NULL; debug(29, 9) ("authDigestNonceFindNonce: Found nonce '%p'\n", nonce); return nonce;}static intauthDigestNonceIsValid(digest_nonce_h * nonce, char nc[9]){ unsigned long intnc; /* do we have a nonce ? */ if (!nonce) return 0; intnc = strtol(nc, NULL, 16); /* has it already been invalidated ? */ if (!nonce->flags.valid) { debug(29, 4) ("authDigestNonceIsValid: Nonce already invalidated\n"); return 0; } /* is the nonce-count ok ? */ if (!digestConfig->CheckNonceCount) { nonce->nc++; return -1; /* forced OK by configuration */ }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -