98 static int authDigestNonceLinks(digest_nonce_h * nonce);
114 SquidMD5Update(&Md5Ctx, reinterpret_cast<const uint8_t *>(&nonce->noncedata),
sizeof(nonce->noncedata));
118 CvtHex(H, static_cast<char *>(nonce->key));
124 digest_nonce_h *newnonce = static_cast < digest_nonce_h * >(digest_nonce_pool->
alloc());
165 static std::mt19937 mt(static_cast<uint32_t>(
getCurrentTime() & 0xFFFFFFFF));
166 static xuniform_int_distribution<uint32_t> newRandomData;
170 newnonce->flags.valid =
true;
171 newnonce->noncedata.self = newnonce;
173 newnonce->noncedata.randomdata = newRandomData(mt);
180 newnonce->noncedata.randomdata = newRandomData(mt);
187 newnonce->flags.incache =
true;
188 debugs(29, 5,
"created nonce " << newnonce <<
" at " << newnonce->noncedata.creationtime);
196 assert(nonce->references == 0);
199 if (nonce->flags.incache)
204 assert(!nonce->flags.incache);
208 digest_nonce_pool->
freeOne(nonce);
215 if (!digest_nonce_pool)
216 digest_nonce_pool =
memPoolCreate(
"Digest Scheme nonce's",
sizeof(digest_nonce_h));
218 if (!digest_nonce_cache) {
220 assert(digest_nonce_cache);
231 digest_nonce_h *nonce;
233 if (digest_nonce_cache) {
234 debugs(29, 2,
"Shutting down nonce cache");
237 while ((nonce = ((digest_nonce_h *)
hash_next(digest_nonce_cache)))) {
238 assert(nonce->flags.incache);
244 if (digest_nonce_pool) {
246 digest_nonce_pool =
NULL;
250 debugs(29, 2,
"Nonce cache shutdown");
262 digest_nonce_h *nonce;
263 debugs(29, 3,
"Cleaning the nonce cache now");
267 while ((nonce = ((digest_nonce_h *)
hash_next(digest_nonce_cache)))) {
268 debugs(29, 3,
"nonce entry : " << nonce <<
" '" << (
char *) nonce->key <<
"'");
269 debugs(29, 4,
"Creation time: " << nonce->noncedata.creationtime);
272 debugs(29, 4,
"Removing nonce " << (
char *) nonce->key <<
" from cache due to timeout.");
273 assert(nonce->flags.incache);
275 nonce->flags.valid =
false;
282 debugs(29, 3,
"Finished cleaning the nonce cache.");
293 debugs(29, 9,
"nonce '" << nonce <<
"' now at '" << nonce->references <<
"'.");
298 authDigestNonceLinks(digest_nonce_h * nonce)
303 return nonce->references;
313 if (nonce->references > 0) {
314 -- nonce->references;
319 debugs(29, 9,
"nonce '" << nonce <<
"' now at '" << nonce->references <<
"'.");
321 if (nonce->references == 0)
331 return (
char const *) nonce->key;
334 static digest_nonce_h *
337 digest_nonce_h *nonce =
NULL;
339 if (noncehex ==
NULL)
342 debugs(29, 9,
"looking for noncehex '" << noncehex <<
"' in the nonce cache.");
344 nonce = static_cast < digest_nonce_h * >(
hash_lookup(digest_nonce_cache, noncehex));
349 debugs(29, 9,
"Found nonce '" << nonce <<
"'");
363 intnc = strtol(nc,
NULL, 16);
366 if (!nonce->flags.valid) {
367 debugs(29, 4,
"Nonce already invalidated");
374 intnc = nonce->nc + 1;
377 if ((static_cast<Auth::Digest::Config*>(
Auth::SchemeConfig::Find(
"digest"))->NonceStrictness && intnc != nonce->nc + 1) ||
378 intnc < nonce->nc + 1) {
379 debugs(29, 4,
"Nonce count doesn't match");
380 nonce->flags.valid =
false;
401 if (!nonce->flags.valid)
406 debugs(29, 4,
"Nonce is too old. " <<
407 nonce->noncedata.creationtime <<
" " <<
411 nonce->flags.valid =
false;
415 if (nonce->nc > 99999998) {
416 debugs(29, 4,
"Nonce count overflow");
417 nonce->flags.valid =
false;
422 debugs(29, 4,
"Nonce count over user limit");
423 nonce->flags.valid =
false;
441 if (nonce->nc == 99999997) {
442 debugs(29, 4,
"Nonce count about to overflow");
447 debugs(29, 4,
"Nonce count about to hit user limit");
461 if (!nonce->flags.incache)
466 nonce->flags.incache =
false;
473 Auth::Digest::Config::rotateHelpers()
476 if (digestauthenticators) {
489 storeAppendPrintf(entry,
"%s %s nonce_max_count %d\n%s %s nonce_max_duration %d seconds\n%s %s nonce_garbage_interval %d seconds\n",
490 name,
"digest", noncemaxuses,
491 name,
"digest", (
int) noncemaxduration,
492 name,
"digest", (
int) nonceGCInterval);
497 Auth::Digest::Config::active()
const 503 Auth::Digest::Config::configured()
const 505 if ((authenticateProgram !=
NULL) &&
506 (authenticateChildren.n_max != 0) &&
507 !realm.isEmpty() && (noncemaxduration > -1))
517 if (!authenticateProgram)
521 digest_nonce_h *nonce =
NULL;
524 if (auth_user_request !=
NULL) {
525 Auth::Digest::User *digest_user =
dynamic_cast<Auth::Digest::User *
>(auth_user_request->user().getRaw());
530 nonce = digest_user->currentNonce();
538 debugs(29, 9,
"Sending type:" << hdrType <<
539 " header: 'Digest realm=\"" << realm <<
"\", nonce=\"" <<
541 "\", stale=" << (stale ?
"true" :
"false"));
553 if (authenticateProgram) {
557 if (digestauthenticators ==
NULL)
558 digestauthenticators =
new helper(
"digestauthenticator");
560 digestauthenticators->
cmdline = authenticateProgram;
571 Auth::Digest::Config::registerWithCacheManager(
void)
574 "Digest User Authenticator Stats",
580 Auth::Digest::Config::done()
586 if (digestauthenticators)
593 digestauthenticators =
NULL;
595 if (authenticateProgram)
600 nonceGCInterval(5*60),
601 noncemaxduration(30*60),
611 if (strcmp(param_str,
"nonce_garbage_interval") == 0) {
613 }
else if (strcmp(param_str,
"nonce_max_duration") == 0) {
615 }
else if (strcmp(param_str,
"nonce_max_count") == 0) {
617 }
else if (strcmp(param_str,
"nonce_strictness") == 0) {
619 }
else if (strcmp(param_str,
"check_nonce_count") == 0) {
621 }
else if (strcmp(param_str,
"post_workaround") == 0) {
630 return Auth::Digest::Scheme::GetInstance()->type();
636 if (digestauthenticators)
637 digestauthenticators->
packStatsInto(sentry,
"Digest Authenticator Statistics");
645 Auth::Digest::User *digest_user;
654 digest_user = nonce->user;
659 link = digest_user->nonces.head;
665 if (tmplink->
data == nonce) {
685 if (!user || !nonce || !nonce->user)
688 Auth::Digest::User *digest_user = user;
690 node = digest_user->nonces.head;
692 while (node && (node->
data != nonce))
705 assert((nonce->user ==
NULL) || (nonce->user == user));
720 debugs(29, 9,
"Creating new user for logging '" << (username?username:
"[no username]") <<
"'");
723 digest_user->username(username);
727 auth_user_request->user(digest_user);
728 return auth_user_request;
736 Auth::Digest::Config::decode(
char const *proxy_auth,
const char *aRequestRealm)
740 const char *pos =
NULL;
741 char *username =
NULL;
742 digest_nonce_h *nonce;
745 debugs(29, 9,
"beginning");
747 Auth::Digest::UserRequest *digest_request =
new Auth::Digest::UserRequest();
764 if ((p = (
const char *)memchr(item,
'=', ilen)) && (p - item < ilen)) {
767 vlen = ilen - (p - item);
773 SBuf keyName(item, nlen);
779 if (keyName ==
SBuf(
"domain",6) || keyName ==
SBuf(
"uri",3)) {
782 if (vlen > 1 && *p ==
'"' && *(p + vlen -1) ==
'"') {
783 value.
assign(p+1, vlen-2);
785 }
else if (keyName ==
SBuf(
"qop",3)) {
789 if (vlen > 1 && *p ==
'"' && *(p + vlen -1) ==
'"') {
790 value.
assign(p+1, vlen-2);
794 }
else if (*p ==
'"') {
796 debugs(29, 9,
"Failed to parse attribute '" << item <<
"' in '" << temp <<
"'");
803 debugs(29, 9,
"Failed to parse attribute '" << item <<
"' in '" << temp <<
"'");
813 if (value.
size() != 0)
815 debugs(29, 9,
"Found Username '" << username <<
"'");
820 if (value.
size() != 0)
822 debugs(29, 9,
"Found realm '" << digest_request->realm <<
"'");
827 if (value.
size() != 0)
829 debugs(29, 9,
"Found qop '" << digest_request->qop <<
"'");
834 if (value.
size() != 0)
836 debugs(29, 9,
"Found algorithm '" << digest_request->algorithm <<
"'");
841 if (value.
size() != 0)
843 debugs(29, 9,
"Found uri '" << digest_request->uri <<
"'");
848 if (value.
size() != 0)
850 debugs(29, 9,
"Found nonce '" << digest_request->noncehex <<
"'");
854 if (value.
size() != 8) {
855 debugs(29, 9,
"Invalid nc '" << value <<
"' in '" << temp <<
"'");
858 debugs(29, 9,
"Found noncecount '" << digest_request->nc <<
"'");
863 if (value.
size() != 0)
865 debugs(29, 9,
"Found cnonce '" << digest_request->cnonce <<
"'");
870 if (value.
size() != 0)
872 debugs(29, 9,
"Found response '" << digest_request->response <<
"'");
876 debugs(29, 3,
"Unknown attribute '" << item <<
"' in '" << temp <<
"'");
899 if (!username || username[0] ==
'\0') {
900 debugs(29, 2,
"Empty or not present username");
910 if (strchr(username,
'"')) {
911 debugs(29, 2,
"Unacceptable username '" << username <<
"'");
918 if (!digest_request->realm || digest_request->realm[0] ==
'\0') {
919 debugs(29, 2,
"Empty or not present realm");
926 if (!digest_request->noncehex || digest_request->noncehex[0] ==
'\0') {
927 debugs(29, 2,
"Empty or not present nonce");
935 if (!digest_request->uri || digest_request->uri[0] ==
'\0') {
936 debugs(29, 2,
"Missing URI field");
943 if (!digest_request->response || strlen(digest_request->response) != 32) {
944 debugs(29, 2,
"Response length invalid");
951 if (!digest_request->algorithm)
952 digest_request->algorithm =
xstrndup(
"MD5", 4);
953 else if (strcmp(digest_request->algorithm,
"MD5")
954 && strcmp(digest_request->algorithm,
"MD5-sess")) {
955 debugs(29, 2,
"invalid algorithm specified!");
962 if (digest_request->qop) {
965 if (strcmp(digest_request->qop, QOP_AUTH) != 0) {
967 debugs(29, 2,
"Invalid qop option received");
974 if (!digest_request->cnonce || digest_request->cnonce[0] ==
'\0') {
975 debugs(29, 2,
"Missing cnonce field");
982 if (strlen(digest_request->nc) != 8 || strspn(digest_request->nc,
"0123456789abcdefABCDEF") != 8) {
983 debugs(29, 2,
"invalid nonce count");
990 if (digest_request->cnonce || digest_request->nc[0] !=
'\0') {
991 debugs(29, 2,
"missing qop!");
1003 if (nonce && nonce->user && strcmp(username, nonce->user->username())) {
1004 debugs(29, 2,
"Username for the nonce does not equal the username for the request");
1010 debugs(29, 2,
"Unexpected or invalid nonce received from " << username);
1014 return auth_request;
1017 digest_request->nonce = nonce;
1021 if (nonce->user && strcmp(username, nonce->user->username())) {
1022 debugs(29, 2,
"Username for the nonce does not equal the username for the request");
1033 Auth::Digest::User *digest_user;
1040 debugs(29, 9,
"Creating new digest user '" << username <<
"'");
1041 digest_user =
new Auth::Digest::User(
this, aRequestRealm);
1043 auth_user = digest_user;
1045 digest_user->username(username);
1051 digest_user->addToNameCache();
1064 debugs(29, 9,
"Found user '" << username <<
"' in the user cache as '" << auth_user <<
"'");
1065 digest_user =
static_cast<Auth::Digest::User *
>(auth_user.
getRaw());
1073 digest_request->user(digest_user);
1074 debugs(29, 9,
"username = '" << digest_user->username() <<
"'\nrealm = '" <<
1075 digest_request->realm <<
"'\nqop = '" << digest_request->qop <<
1076 "'\nalgorithm = '" << digest_request->algorithm <<
"'\nuri = '" <<
1077 digest_request->uri <<
"'\nnonce = '" << digest_request->noncehex <<
1078 "'\nnc = '" << digest_request->nc <<
"'\ncnonce = '" <<
1079 digest_request->cnonce <<
"'\nresponse = '" <<
1080 digest_request->response <<
"'\ndigestnonce = '" << nonce <<
"'");
1082 return digest_request;
EnumType lookup(const SBuf &key) const
char const * rawBuf() const
char HASHHEX[HASHHEXLEN+1]
int strListGetItem(const String *str, char del, const char **item, int *ilen, const char **pos)
SQUIDCEXTERN void hash_first(hash_table *)
void authDigestNoncePurge(digest_nonce_h *nonce)
void parse_time_t(time_t *var)
void authDigestUserLinkNonce(Auth::Digest::User *user, digest_nonce_h *nonce)
void AUTHSSTATS(StoreEntry *)
int authDigestNonceIsStale(digest_nonce_h *nonce)
SQUIDCEXTERN HASHHASH hash_string
virtual void freeOne(void *)=0
Helper::ChildConfig childs
Configuration settings for number running.
char * xstrndup(const char *s, size_t n)
static struct node * parse(FILE *fp)
digest_nonce_h * authenticateDigestNonceNew(void)
void wordlistDestroy(wordlist **list)
destroy a wordlist
static hash_table * digest_nonce_cache
void helperShutdown(helper *hlp)
SQUIDCEXTERN void hash_join(hash_table *, hash_link *)
void dlinkDelete(dlink_node *m, dlink_list *list)
void parse_onoff(int *var)
int authDigestNonceLastRequest(digest_nonce_h *nonce)
static Auth::UserRequest::Pointer authDigestLogUsername(char *username, Auth::UserRequest::Pointer auth_user_request, const char *requestRealm)
struct timeval current_time
static void authenticateDigestNonceDelete(digest_nonce_h *nonce)
SQUIDCEXTERN void SquidMD5Update(struct SquidMD5Context *context, const void *buf, unsigned len)
static AUTHSSTATS authenticateDigestStats
static SBuf BuildUserKey(const char *username, const char *realm)
helper * digestauthenticators
static void authDigestNonceEncode(digest_nonce_h *nonce)
void const char HLPCB void * data
void packStatsInto(Packable *p, const char *label=NULL) const
Dump some stats about the helper state to a Packable object.
#define debugs(SECTION, LEVEL, CONTENT)
int authDigestNonceIsValid(digest_nonce_h *nonce, char nc[9])
void RegisterAction(char const *action, char const *desc, OBJH *handler, int pw_req_flag, int atomic)
ChildConfig & updateLimits(const ChildConfig &rhs)
static void authDigestNonceUserUnlink(digest_nonce_h *nonce)
SQUIDCEXTERN hash_link * hash_lookup(hash_table *, const void *)
virtual void parse(SchemeConfig *, int, char *)
char * xstrncpy(char *dst, const char *src, size_t n)
void dlinkAddTail(void *data, dlink_node *m, dlink_list *list)
void CvtHex(const HASH Bin, HASHHEX Hex)
static int authdigest_initialised
SQUIDCEXTERN hash_table * hash_create(HASHCMP *, int, HASHHASH *)
void helperOpenServers(helper *hlp)
const char * authenticateDigestNonceNonceHex(const digest_nonce_h *nonce)
static void authDigestNonceLink(digest_nonce_h *nonce)
static SchemeConfig * Find(const char *proxy_auth)
SQUIDCEXTERN hash_link * hash_next(hash_table *)
time_t getCurrentTime(void)
Get current time.
void eventAdd(const char *name, EVH *func, void *arg, double when, int weight, bool cbdata)
static MemAllocator * digest_nonce_pool
static void authenticateDigestNonceSetup(void)
SQUIDCEXTERN void hash_remove_link(hash_table *, hash_link *)
void authDigestNonceUnlink(digest_nonce_h *nonce)
SQUIDCEXTERN void SquidMD5Final(uint8_t digest[16], struct SquidMD5Context *context)
static uint32 H(uint32 X, uint32 Y, uint32 Z)
void assign(const char *str, int len)
static void authenticateDigestNonceCacheCleanup(void *data)
void authenticateDigestNonceShutdown(void)
#define SQUIDSBUFPRINT(s)
void storeAppendPrintf(StoreEntry *e, const char *fmt,...)
SQUIDCEXTERN void SquidMD5Init(struct SquidMD5Context *context)
static const LookupTable< http_digest_attr_type >::Record DigestAttrs[]
static digest_nonce_h * authenticateDigestNonceFindNonce(const char *noncehex)
virtual bool dump(StoreEntry *, const char *, SchemeConfig *) const
int HASHCMP(const void *, const void *)
LookupTable< http_digest_attr_type > DigestFieldsLookupTable(DIGEST_INVALID_ATTR, DigestAttrs)