📄 auth_digest.c
字号:
digest_request->nc, digest_request->cnonce, digest_request->qop, RequestMethodStr[METHOD_GET], digest_request->uri, HA2, Response); if (strcasecmp(digest_request->response, Response)) { digest_request->flags.credentials_ok = 3; safe_free(auth_user_request->message); auth_user_request->message = xstrdup("Incorrect password"); return; } else { const char *useragent = httpHeaderGetStr(&request->header, HDR_USER_AGENT); static struct in_addr last_broken_addr; static int seen_broken_client = 0; if (!seen_broken_client) { last_broken_addr = no_addr; seen_broken_client = 1; } if (memcmp(&last_broken_addr, &request->client_addr, sizeof(last_broken_addr)) != 0) { debug(29, 1) ("\nDigest POST bug detected from %s using '%s'. Please upgrade browser. See Bug #630 for details.\n", inet_ntoa(request->client_addr), useragent ? useragent : "-"); last_broken_addr = request->client_addr; } } } else { digest_request->flags.credentials_ok = 3; safe_free(auth_user_request->message); auth_user_request->message = xstrdup("Incorrect password"); return; } } /* check for stale nonce */ if (!authDigestNonceIsValid(digest_request->nonce, digest_request->nc)) { debug(29, 3) ("authenticateDigestAuthenticateuser: user '%s' validated OK but nonce stale\n", digest_user->username); digest_request->flags.nonce_stale = 1; digest_request->flags.credentials_ok = 3; safe_free(auth_user_request->message); auth_user_request->message = xstrdup("Stale nonce"); return; } /* password was checked and did match */ digest_request->flags.credentials_ok = 1; debug(29, 4) ("authenticateDigestAuthenticateuser: user '%s' validated OK\n", digest_user->username); /* auth_user is now linked, we reset these values * after external auth occurs anyway */ auth_user->expiretime = current_time.tv_sec; return;}static intauthenticateDigestDirection(auth_user_request_t * auth_user_request){ digest_request_h *digest_request = auth_user_request->scheme_data; if (!digest_request) return -2; switch (digest_request->flags.credentials_ok) { case 0: /* not checked */ return -1; case 1: /* checked & ok */ return 0; case 2: /* partway through checking. */ return -1; case 3: /* authentication process failed. */ if (digest_request->flags.nonce_stale) /* nonce is stale, send new challenge */ return 1; return -2; } return -2;}/* add the [proxy]authorisation header */static voidauthDigestAddHeader(auth_user_request_t * auth_user_request, HttpReply * rep, int accel){ int type; digest_request_h *digest_request; if (!auth_user_request) return; digest_request = auth_user_request->scheme_data; if (!digest_request) return; /* don't add to authentication error pages */ if ((!accel && rep->sline.status == HTTP_PROXY_AUTHENTICATION_REQUIRED) || (accel && rep->sline.status == HTTP_UNAUTHORIZED)) return; type = accel ? HDR_AUTHENTICATION_INFO : HDR_PROXY_AUTHENTICATION_INFO;#if WAITING_FOR_TE /* test for http/1.1 transfer chunked encoding */ if (chunkedtest) return;#endif if ((digestConfig->authenticate) && authDigestNonceLastRequest(digest_request->nonce)) { digest_request->flags.authinfo_sent = 1; debug(29, 9) ("authDigestAddHead: Sending type:%d header: 'nextnonce=\"%s\"", type, authenticateDigestNonceNonceb64(digest_request->nonce)); httpHeaderPutStrf(&rep->header, type, "nextnonce=\"%s\"", authenticateDigestNonceNonceb64(digest_request->nonce)); }}#if WAITING_FOR_TE/* add the [proxy]authorisation header */static voidauthDigestAddTrailer(auth_user_request_t * auth_user_request, HttpReply * rep, int accel){ int type; digest_request_h *digest_request; if (!auth_user_request) return; digest_request = auth_user_request->scheme_data; /* has the header already been send? */ if (digest_request->flags.authinfo_sent) return; /* don't add to authentication error pages */ if ((!accel && rep->sline.status == HTTP_PROXY_AUTHENTICATION_REQUIRED) || (accel && rep->sline.status == HTTP_UNAUTHORIZED)) return; type = accel ? HDR_AUTHENTICATION_INFO : HDR_PROXY_AUTHENTICATION_INFO; if ((digestConfig->authenticate) && authDigestNonceLastRequest(digest_request->nonce)) { debug(29, 9) ("authDigestAddTrailer: Sending type:%d header: 'nextnonce=\"%s\"", type, authenticateDigestNonceNonceb64(digest_request->nonce)); httpTrailerPutStrf(&rep->header, type, "nextnonce=\"%s\"", authenticateDigestNonceNonceb64(digest_request->nonce)); }}#endif/* add the [www-|Proxy-]authenticate header on a 407 or 401 reply */voidauthenticateDigestFixHeader(auth_user_request_t * auth_user_request, HttpReply * rep, http_hdr_type type, request_t * request){ digest_request_h *digest_request; int stale = 0; digest_nonce_h *nonce = authenticateDigestNonceNew(); if (auth_user_request && auth_user_request->scheme_data) { digest_request = auth_user_request->scheme_data; stale = digest_request->flags.nonce_stale; } if (digestConfig->authenticate) { debug(29, 9) ("authenticateFixHeader: Sending type:%d header: 'Digest realm=\"%s\", nonce=\"%s\", qop=\"%s\", stale=%s\n", type, digestConfig->digestAuthRealm, authenticateDigestNonceNonceb64(nonce), QOP_AUTH, stale ? "true" : "false"); /* in the future, for WWW auth we may want to support the domain entry */ httpHeaderPutStrf(&rep->header, type, "Digest realm=\"%s\", nonce=\"%s\", qop=\"%s\", stale=%s", digestConfig->digestAuthRealm, authenticateDigestNonceNonceb64(nonce), QOP_AUTH, stale ? "true" : "false"); }}static voidauthenticateDigestUserFree(auth_user_t * auth_user){ digest_user_h *digest_user = auth_user->scheme_data; dlink_node *link, *tmplink; debug(29, 9) ("authenticateDigestFreeUser: Clearing Digest scheme data\n"); if (!digest_user) return; safe_free(digest_user->username); link = digest_user->nonces.head; while (link) { tmplink = link; link = link->next; dlinkDelete(tmplink, &digest_user->nonces); authDigestNoncePurge(tmplink->data); authDigestNonceUnlink(tmplink->data); dlinkNodeDelete(tmplink); } memPoolFree(digest_user_pool, auth_user->scheme_data); auth_user->scheme_data = NULL;}static voidauthenticateDigestHandleReply(void *data, char *reply){ authenticateStateData *r = data; auth_user_request_t *auth_user_request; digest_request_h *digest_request; digest_user_h *digest_user; int valid; char *t = NULL; debug(29, 9) ("authenticateDigestHandleReply: {%s}\n", reply ? reply : "<NULL>"); if (reply) { if ((t = strchr(reply, ' '))) *t++ = '\0'; if (*reply == '\0' || *reply == '\n') reply = NULL; } assert(r->auth_user_request != NULL); auth_user_request = r->auth_user_request; assert(auth_user_request->scheme_data != NULL); digest_request = auth_user_request->scheme_data; digest_user = auth_user_request->auth_user->scheme_data; if (reply && (strncasecmp(reply, "ERR", 3) == 0)) { digest_request->flags.credentials_ok = 3; safe_free(auth_user_request->message); if (t && *t) auth_user_request->message = xstrdup(t); } else if (reply) { CvtBin(reply, digest_user->HA1); digest_user->HA1created = 1; } valid = cbdataValid(r->data); if (valid) r->handler(r->data, NULL); cbdataUnlock(r->data); authenticateStateFree(r);}/* Initialize helpers and the like for this auth scheme. Called AFTER parsing the * config file */static voidauthDigestInit(authScheme * scheme){ static int init = 0; if (digestConfig->authenticate) { authDigestUserSetup(); authDigestRequestSetup(); authenticateDigestNonceSetup(); authdigest_initialised = 1; if (digestauthenticators == NULL) digestauthenticators = helperCreate("digestauthenticator"); digestauthenticators->cmdline = digestConfig->authenticate; digestauthenticators->n_to_start = digestConfig->authenticateChildren; digestauthenticators->concurrency = digestConfig->authenticateConcurrency; digestauthenticators->ipc_type = IPC_STREAM; helperOpenServers(digestauthenticators); if (!init) { cachemgrRegister("digestauthenticator", "Digest User Authenticator Stats", authenticateDigestStats, 0, 1); init++; } CBDATA_INIT_TYPE(authenticateStateData); }}/* free any allocated configuration details */voidauthDigestFreeConfig(authScheme * scheme){ if (digestConfig == NULL) return; assert(digestConfig == scheme->scheme_data); if (digestConfig->authenticate) wordlistDestroy(&digestConfig->authenticate); if (digestConfig->digestAuthRealm) safe_free(digestConfig->digestAuthRealm); xfree(digestConfig); digestConfig = NULL;}static voidauthDigestParse(authScheme * scheme, int n_configured, char *param_str){ if (scheme->scheme_data == NULL) { assert(digestConfig == NULL); /* this is the first param to be found */ scheme->scheme_data = xmalloc(sizeof(auth_digest_config)); memset(scheme->scheme_data, 0, sizeof(auth_digest_config)); digestConfig = scheme->scheme_data; digestConfig->authenticateChildren = 5; digestConfig->digestAuthRealm = xstrdup("Squid proxy-caching web server"); /* 5 minutes */ digestConfig->nonceGCInterval = 5 * 60; /* 30 minutes */ digestConfig->noncemaxduration = 30 * 60; /* 50 requests */ digestConfig->noncemaxuses = 50; /* Not strict nonce count behaviour */ digestConfig->NonceStrictness = 0; /* Verify nonce count */ digestConfig->CheckNonceCount = 1; digestConfig->PostWorkaround = 0; } digestConfig = scheme->scheme_data; if (strcasecmp(param_str, "program") == 0) { if (digestConfig->authenticate) wordlistDestroy(&digestConfig->authenticate); parse_wordlist(&digestConfig->authenticate); } else if (strcasecmp(param_str, "children") == 0) { parse_int(&digestConfig->authenticateChildren); } else if (strcasecmp(param_str, "concurrency") == 0) { parse_int(&digestConfig->authenticateConcurrency); } else if (strcasecmp(param_str, "realm") == 0) { parse_eol(&digestConfig->digestAuthRealm); } else if (strcasecmp(param_str, "nonce_garbage_interval") == 0) { parse_time_t(&digestConfig->nonceGCInterval); } else if (strcasecmp(param_str, "nonce_max_duration") == 0) { parse_time_t(&digestConfig->noncemaxduration); } else if (strcasecmp(param_str, "nonce_max_count") == 0) { parse_int(&digestConfig->noncemaxuses); } else if (strcasecmp(param_str, "nonce_strictness") == 0) { parse_onoff(&digestConfig->NonceStrictness); } else if (strcasecmp(param_str, "check_nonce_count") == 0) { parse_onoff(&digestConfig->CheckNonceCount); } else if (strcasecmp(param_str, "post_workaround") == 0) { parse_onoff(&digestConfig->PostWorkaround); } else { debug(29, 0) ("unrecognised digest auth scheme parameter '%s'\n", param_str); }}static voidauthDigestCheckConfig(authScheme * scheme){ auth_digest_config *config = scheme->scheme_data; requirePathnameExists("authparam digest program", config->authenticate->key);}static voidauthenticateDigestStats(StoreEntry * sentry){ storeAppendPrintf(sentry, "Digest Authenticator Statistics:\n"); helperStats(sentry, digestauthenticators);}/* NonceUserUnlink: remove the reference to auth_user and unlink the node from the list */static voidauthDigestNonceUserUnlink(digest_nonce_h * nonce){ digest_user_h *digest_user; dlink_node *link, *tmplink; if (!nonce) return; if (!nonce->auth_user) return; digest_user = nonce->auth_user->scheme_data; /* unlink from the user list. Yes we're crossing structures but this is the only * time this code is needed */ link = digest_user->nonces.head; while (link) { tmplink = link; link = link->next; if (tmplink->data == nonce) { dlinkDelete(tmplink, &digest_user->nonces); authDigestNonceUnlink(tmplink->data); dlinkNodeDelete(tmplink); link = NULL; } } /* this reference to auth_user was not locked because freeeing the auth_user frees * the nonce too. */ nonce->auth_user = NULL;}/* authDigestUserLinkNonce: add a nonce to a given user's struct */static voidauthDigestUserLinkNonce(auth_user_t * auth_user, digest_nonce_h * nonce){ dlink_node *node; digest_user_h *digest_user; if (!auth_user || !nonce) return; if (!auth_user->scheme_data) return; digest_user = auth_user->scheme_data;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -