📄 htaabrow.c
字号:
PRIVATE BOOL digest_credentials (HTRequest * request, HTDigest * digest){ if (request && digest && digest->realm) { char * realm = (char *) digest->realm; char * uri; char * method = (char *) HTMethod_name (HTRequest_method (request)); char * cleartext = NULL; char nc[9]; HASHHEX HA1; HASHHEX HA2; HASHHEX response; /* @@ maybe optimize all my reallocs by preallocating the memory */ if (digest->proxy) uri = HTRequest_proxy(request); else { char * tmp; /* we get the absolute URL */ tmp = HTAnchor_address( (HTAnchor*)HTRequest_anchor(request)); /* and then remove what makes it absolute, to be backwards compatible */ uri = HTParse (tmp, "", PARSE_PATH | PARSE_PUNCTUATION); HT_FREE(tmp); } /* increment the nonce counter */ digest->nc++; sprintf (nc, "%08lx", digest->nc); add_param (&cleartext, "username", digest->uid, YES); add_param (&cleartext, "realm", realm, YES); add_param (&cleartext, "nonce", digest->nonce, YES); add_param (&cleartext, "uri", uri, YES); /* @@@ no support for auth-int yet */ if (digest->qop) { add_param (&cleartext, "qop", "auth", NO); add_param (&cleartext, "nc", nc, NO); add_param (&cleartext, "cnonce", digest->cnonce, YES); } /* compute the response digest */ /* @@@ md5 hard coded, change it to something from the answer, md5-sess, etc */ DigestCalcHA1 (digest->algorithm, "md5", digest->uid, realm, digest->pw, digest->nonce, digest->cnonce, HA1); DigestCalcResponse (digest->algorithm, HA1, digest->nonce, nc, digest->cnonce, digest->qop, method, uri, HA2, response); add_param (&cleartext, "response", response, NO); add_param (&cleartext, "opaque", digest->opaque, NO); /* Create the credentials and assign them to the request object */ { int cr_len = strlen ("Digest") + strlen (cleartext) + 3; char * cookie = (char *) HT_MALLOC(cr_len+1); if (!cookie) HT_OUTOFMEM("digest_credentials"); strcpy(cookie, "Digest "); strcat (cookie, cleartext); HTTRACE(AUTH_TRACE, "Digest Cookie `%s\'\n" _ cookie); /* Check whether it is proxy or normal credentials */ if (digest->proxy) HTRequest_addCredentials(request, "Proxy-Authorization", cookie); else HTRequest_addCredentials(request, "Authorization", cookie); HT_FREE(cookie); } if (!digest->proxy) HT_FREE(uri); HT_FREE(cleartext); return HT_OK; } return HT_ERROR;}/* HTDigest_generate** ----------------** This function generates "digest" credentials for the challenge found in** the authentication information base for this request. The result is** stored as an association list in the request object.** This is a callback function for the AA handler.*/PUBLIC int HTDigest_generate (HTRequest * request, void * context, int mode){ HTDigest * digest = (HTDigest *) context; BOOL proxy = mode==HT_NO_PROXY_ACCESS ? YES : NO; if (request) { const char * realm = HTRequest_realm(request); /* ** If we were asked to explicitly ask the user again */ if (mode == HT_REAUTH || mode == HT_PROXY_REAUTH) digest->retry = YES; /* ** If we don't have a digest context then add a new one to the tree. ** We use different trees for normal and proxy authentication */ if (!digest) { digest = HTDigest_new(); if (proxy) { char * url = HTRequest_proxy(request); digest->proxy = YES; HTAA_updateNode(proxy, DIGEST_AUTH, realm, url, digest); } else { char * url = HTAnchor_address((HTAnchor*)HTRequest_anchor(request)); HTAA_updateNode(proxy, DIGEST_AUTH, realm, url, digest); HT_FREE(url); } } /* ** If we have a set of credentials (or the user provides a new set) ** then store it in the request object as the credentials */ if ((digest->retry && prompt_digest_user(request, realm, digest) == HT_OK) || (!digest->retry && digest->uid)) { /* @@@ here we should generate a new cnonce value */ HTSACopy (&(digest->cnonce), "012345678"); digest->retry = NO; return digest_credentials(request, digest); } else { char * url = HTAnchor_address((HTAnchor*)HTRequest_anchor(request)); if (proxy) HTAA_deleteNode(proxy, DIGEST_AUTH, realm, url); else HTAA_deleteNode(proxy, DIGEST_AUTH, realm, url); HT_FREE(url); return HT_ERROR; } } return HT_OK;}/*** Evaluates the existing authentication info (nonce, uid, pwd) and** returns TRUE if we evaluate that the nonce is stale, FALSE** otherwise.*/PRIVATE BOOL nonce_is_stale (HTRequest *request, HTDigest * digest, char * old_nonce){ if (!digest->uid || !digest->pw) return FALSE; if (!digest->nonce || !old_nonce) return FALSE; if (strcmp (digest->nonce, old_nonce)) return TRUE; /* because of a pipelining implementation bug, we don't send any good credentials on requests following the first one in the pipeline */ if (!HTRequest_credentials (request) && HTRequest_AAretrys (request) == 1) return TRUE; return FALSE;}/* HTDigest_parse** -------------** This function parses the contents of a "digest" challenge ** and stores the challenge in our authentication information datebase.** We also store the realm in the request object which will help finding** the right set of credentials to generate.** The function is a callback function for the AA handler.*/PUBLIC int HTDigest_parse (HTRequest * request, HTResponse * response, void * context, int status){ HTAssocList * challenge = HTResponse_challenge(response); HTDigest * digest = NULL; BOOL proxy = status==HT_NO_PROXY_ACCESS ? YES : NO; if (request && challenge) { char * p = HTAssocList_findObject(challenge, DIGEST_AUTH); char * realm = HTNextField(&p); char * rm = HTNextField(&p); char * value = NULL; char * token = NULL; char * uris = NULL; /* the value of the previous nonce in case the server has changed its challenge */ char * old_nonce = NULL; /* ** If valid challenge then make a template for the resource and ** store this information in our authentication URL Tree */ if (realm && !strcasecomp(realm, "realm") && rm) { HTTRACE(AUTH_TRACE, "Digest Parse. Realm `%s\' found\n" _ rm); HTRequest_setRealm(request, rm); /* ** If we are in proxy mode then add the proxy - not the final URL */ if (proxy) { char * url = HTRequest_proxy(request); HTTRACE(AUTH_TRACE, "Digest Parse. Proxy authentication\n"); digest = (HTDigest *) HTAA_updateNode(proxy, DIGEST_AUTH, rm, url, NULL); /* if the previous authentication failed, then try again */ if (HTRequest_AAretrys (request) > 1 && status == HT_NO_ACCESS && digest) digest->retry = YES; } else { char * url = HTAnchor_address((HTAnchor *) HTRequest_anchor(request)); char * tmplate = make_template(url); digest = (HTDigest *) HTAA_updateNode(proxy, DIGEST_AUTH, rm, tmplate, NULL); /* if the previous authentication failed, then try again */ if (HTRequest_AAretrys (request) > 1 && status == HT_NO_ACCESS && digest) digest->retry = YES; HT_FREE(tmplate); HT_FREE(url); } } else { HTTRACE(AUTH_TRACE, "Digest Parse. Missing or incomplete realm\n"); return HT_ERROR; } /* if we get here it's because there's no digest */ /* we parse the digest parameters from the challenge */ if (digest) { /* it's an old digest, so we clean all in it except for the uid and the password, hoping that the server send back that data */ old_nonce = digest->nonce; digest->nonce = NULL; HTDigest_reset (digest); } else { /* it's a brand new digest */ digest = HTDigest_new(); StrAllocCopy (digest->realm, rm); } /* ** Search through the set of parameters in the digest header. ** If valid challenge then make a template for the resource and ** store this information in our authentication URL Tree */ while ((token = HTNextField(&p))) { if (!strcasecomp(token, "domain")) { if ((value = HTNextField(&p))) uris = value; } else if (!strcasecomp(token, "nonce")) { if ((value = HTNextField(&p))) StrAllocCopy(digest->nonce, value); } else if (!strcasecomp(token, "opaque")) { if ((value = HTNextField(&p))) StrAllocCopy(digest->opaque, value); } else if (!strcasecomp(token, "qop")) { /* split the qop */ if ((value = HTNextField(&p))) StrAllocCopy(digest->qop, value); } else if (!strcasecomp(token, "stale")) { if ((value = HTNextField(&p)) && !strcasecomp(value, "true")) { /* only true if we already had a digest with uid and pw info */ if (digest->uid && digest->pw) { digest->stale = YES; } } } else if (!strcasecomp(token, "algorithm")) { if ((value = HTNextField(&p)) && strcasecomp(value, "md5")) { /* ** We only support MD5 for the moment */ HTTRACE(AUTH_TRACE, "Digest Parse Unknown algorithm `%s\'\n" _ value); HTDigest_delete(digest); if (old_nonce) HT_FREE (old_nonce); return HT_ERROR; } else digest->algorithm = HTDaMD5; } } /* Pipelining support. If a nonce becomes stale When sending ** several requests thru the pipeline, we may miss the stale ** reply in the server's answer. To avoid this, we keep a copy ** of the nonce in each request. If the nonce wasn't explicitly ** marked stale and if it's the same that we sent, then we ** consider that the uid/pwd pairs were false. Otherwise, we ** assume the stole went stale before */ if (!digest->stale && nonce_is_stale (request, digest, old_nonce)) digest->stale = YES; if (old_nonce) HT_FREE (old_nonce); if (digest->stale) { digest->stale = NO; digest->retry = NO; return HT_OK; } else if (digest->uid || digest->pw) { /* ** For some reason there was no stale nonce header and the ** authentication failed so we have to ask the user if we should ** try again. It may be because the user typed the wrong user name ** and password */ HTAlertCallback * prompt = HTAlert_find(HT_A_CONFIRM); /* ** Do we have a method registered for prompting the user whether ** we should retry */ if (prompt) { int code = proxy ? HT_MSG_RETRY_PROXY_AUTH : HT_MSG_RETRY_AUTHENTICATION; if ((*prompt)(request, HT_A_CONFIRM, code, NULL, NULL, NULL) != YES) return HT_ERROR; return HT_OK; } return HT_ERROR; } /* ** It's the first time we go this way, so we check the domain field to ** create the digest node entries for each URI. */ if (!uris) { if (proxy) { /* we ignore the domain */ char * location = HTRequest_proxy(request); HTTRACE(AUTH_TRACE, "Digest Parse Proxy authentication\n"); HTAA_updateNode(proxy, DIGEST_AUTH, rm, location, digest); } else { char * url = HTAnchor_address((HTAnchor *) HTRequest_anchor(request)); char * tmplate = make_template(url); HTAA_updateNode(proxy, DIGEST_AUTH, rm, tmplate, digest); HT_FREE(url); HT_FREE(tmplate); } } else { char * base_url = HTAnchor_address((HTAnchor *) HTRequest_anchor(request)); char * domain_url; char * full_url; while ((domain_url = HTNextField (&uris))) { /* complete the URL if it's an absolute one */ full_url = HTParse (domain_url, base_url, PARSE_ALL); digest->references++; if (proxy) { HTTRACE(AUTH_TRACE, "Digest Parse Proxy authentication\n"); HTAA_updateNode(proxy, DIGEST_AUTH, rm, full_url, digest); } else { char * tmplate = make_template(full_url); HTAA_updateNode (proxy, DIGEST_AUTH, rm, tmplate, digest); HT_FREE (tmplate); } HT_FREE (full_url); } HT_FREE (base_url); } return HT_OK; } HTTRACE(AUTH_TRACE, "Auth........ No challenges found\n"); return HT_ERROR;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -