📄 mod_auth_digest.c
字号:
* * If they return DECLINED, and all other modules also decline, that's * treated by the server core as a configuration error, logged and * reported as such. *//* Determine user ID, and check if the attributes are correct, if it * really is that user, if the nonce is correct, etc. */static int authenticate_digest_user(request_rec *r){ digest_config_rec *conf; digest_header_rec *resp; request_rec *mainreq; const char *t; int res; authn_status return_code; /* do we require Digest auth for this URI? */ if (!(t = ap_auth_type(r)) || strcasecmp(t, "Digest")) { return DECLINED; } if (!ap_auth_name(r)) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "Digest: need AuthName: %s", r->uri); return HTTP_INTERNAL_SERVER_ERROR; } /* get the client response and mark */ mainreq = r; while (mainreq->main != NULL) { mainreq = mainreq->main; } while (mainreq->prev != NULL) { mainreq = mainreq->prev; } resp = (digest_header_rec *) ap_get_module_config(mainreq->request_config, &auth_digest_module); resp->needed_auth = 1; /* get our conf */ conf = (digest_config_rec *) ap_get_module_config(r->per_dir_config, &auth_digest_module); /* check for existence and syntax of Auth header */ if (resp->auth_hdr_sts != VALID) { if (resp->auth_hdr_sts == NOT_DIGEST) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "Digest: client used wrong authentication scheme " "`%s': %s", resp->scheme, r->uri); } else if (resp->auth_hdr_sts == INVALID) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "Digest: missing user, realm, nonce, uri, digest, " "cnonce, or nonce_count in authorization header: %s", r->uri); } /* else (resp->auth_hdr_sts == NO_HEADER) */ note_digest_auth_failure(r, conf, resp, 0); return HTTP_UNAUTHORIZED; } r->user = (char *) resp->username; r->ap_auth_type = (char *) "Digest"; /* check the auth attributes */ if (strcmp(resp->uri, resp->raw_request_uri)) { /* Hmm, the simple match didn't work (probably a proxy modified the * request-uri), so lets do a more sophisticated match */ apr_uri_t r_uri, d_uri; copy_uri_components(&r_uri, resp->psd_request_uri, r); if (apr_uri_parse(r->pool, resp->uri, &d_uri) != APR_SUCCESS) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "Digest: invalid uri <%s> in Authorization header", resp->uri); return HTTP_BAD_REQUEST; } if (d_uri.hostname) { ap_unescape_url(d_uri.hostname); } if (d_uri.path) { ap_unescape_url(d_uri.path); } if (d_uri.query) { ap_unescape_url(d_uri.query); } else if (r_uri.query) { /* MSIE compatibility hack. MSIE has some RFC issues - doesn't * include the query string in the uri Authorization component * or when computing the response component. the second part * works out ok, since we can hash the header and get the same * result. however, the uri from the request line won't match * the uri Authorization component since the header lacks the * query string, leaving us incompatable with a (broken) MSIE. * * the workaround is to fake a query string match if in the proper * environment - BrowserMatch MSIE, for example. the cool thing * is that if MSIE ever fixes itself the simple match ought to * work and this code won't be reached anyway, even if the * environment is set. */ if (apr_table_get(r->subprocess_env, "AuthDigestEnableQueryStringHack")) { ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, "Digest: " "applying AuthDigestEnableQueryStringHack " "to uri <%s>", resp->raw_request_uri); d_uri.query = r_uri.query; } } if (r->method_number == M_CONNECT) { if (!r_uri.hostinfo || strcmp(resp->uri, r_uri.hostinfo)) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "Digest: uri mismatch - <%s> does not match " "request-uri <%s>", resp->uri, r_uri.hostinfo); return HTTP_BAD_REQUEST; } } else if ( /* check hostname matches, if present */ (d_uri.hostname && d_uri.hostname[0] != '\0' && strcasecmp(d_uri.hostname, r_uri.hostname)) /* check port matches, if present */ || (d_uri.port_str && d_uri.port != r_uri.port) /* check that server-port is default port if no port present */ || (d_uri.hostname && d_uri.hostname[0] != '\0' && !d_uri.port_str && r_uri.port != ap_default_port(r)) /* check that path matches */ || (d_uri.path != r_uri.path /* either exact match */ && (!d_uri.path || !r_uri.path || strcmp(d_uri.path, r_uri.path)) /* or '*' matches empty path in scheme://host */ && !(d_uri.path && !r_uri.path && resp->psd_request_uri->hostname && d_uri.path[0] == '*' && d_uri.path[1] == '\0')) /* check that query matches */ || (d_uri.query != r_uri.query && (!d_uri.query || !r_uri.query || strcmp(d_uri.query, r_uri.query))) ) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "Digest: uri mismatch - <%s> does not match " "request-uri <%s>", resp->uri, resp->raw_request_uri); return HTTP_BAD_REQUEST; } } if (resp->opaque && resp->opaque_num == 0) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "Digest: received invalid opaque - got `%s'", resp->opaque); note_digest_auth_failure(r, conf, resp, 0); return HTTP_UNAUTHORIZED; } if (strcmp(resp->realm, conf->realm)) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "Digest: realm mismatch - got `%s' but expected `%s'", resp->realm, conf->realm); note_digest_auth_failure(r, conf, resp, 0); return HTTP_UNAUTHORIZED; } if (resp->algorithm != NULL && strcasecmp(resp->algorithm, "MD5") && strcasecmp(resp->algorithm, "MD5-sess")) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "Digest: unknown algorithm `%s' received: %s", resp->algorithm, r->uri); note_digest_auth_failure(r, conf, resp, 0); return HTTP_UNAUTHORIZED; } return_code = get_hash(r, r->user, conf); if (return_code == AUTH_USER_NOT_FOUND) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "Digest: user `%s' in realm `%s' not found: %s", r->user, conf->realm, r->uri); note_digest_auth_failure(r, conf, resp, 0); return HTTP_UNAUTHORIZED; } else if (return_code == AUTH_USER_FOUND) { /* we have a password, so continue */ } else if (return_code == AUTH_DENIED) { /* authentication denied in the provider before attempting a match */ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "Digest: user `%s' in realm `%s' denied by provider: %s", r->user, conf->realm, r->uri); note_digest_auth_failure(r, conf, resp, 0); return HTTP_UNAUTHORIZED; } else { /* AUTH_GENERAL_ERROR (or worse) * We'll assume that the module has already said what its error * was in the logs. */ return HTTP_INTERNAL_SERVER_ERROR; } if (resp->message_qop == NULL) { /* old (rfc-2069) style digest */ if (strcmp(resp->digest, old_digest(r, resp, conf->ha1))) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "Digest: user %s: password mismatch: %s", r->user, r->uri); note_digest_auth_failure(r, conf, resp, 0); return HTTP_UNAUTHORIZED; } } else { const char *exp_digest; int match = 0, idx; for (idx = 0; conf->qop_list[idx] != NULL; idx++) { if (!strcasecmp(conf->qop_list[idx], resp->message_qop)) { match = 1; break; } } if (!match && !(conf->qop_list[0] == NULL && !strcasecmp(resp->message_qop, "auth"))) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "Digest: invalid qop `%s' received: %s", resp->message_qop, r->uri); note_digest_auth_failure(r, conf, resp, 0); return HTTP_UNAUTHORIZED; } exp_digest = new_digest(r, resp, conf); if (!exp_digest) { /* we failed to allocate a client struct */ return HTTP_INTERNAL_SERVER_ERROR; } if (strcmp(resp->digest, exp_digest)) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "Digest: user %s: password mismatch: %s", r->user, r->uri); note_digest_auth_failure(r, conf, resp, 0); return HTTP_UNAUTHORIZED; } } if (check_nc(r, resp, conf) != OK) { note_digest_auth_failure(r, conf, resp, 0); return HTTP_UNAUTHORIZED; } /* Note: this check is done last so that a "stale=true" can be generated if the nonce is old */ if ((res = check_nonce(r, resp, conf))) { return res; } return OK;}/* * Authorization-Info header code */#ifdef SEND_DIGESTstatic const char *hdr(const apr_table_t *tbl, const char *name){ const char *val = apr_table_get(tbl, name); if (val) { return val; } else { return ""; }}#endifstatic int add_auth_info(request_rec *r){ const digest_config_rec *conf = (digest_config_rec *) ap_get_module_config(r->per_dir_config, &auth_digest_module); digest_header_rec *resp = (digest_header_rec *) ap_get_module_config(r->request_config, &auth_digest_module); const char *ai = NULL, *digest = NULL, *nextnonce = ""; if (resp == NULL || !resp->needed_auth || conf == NULL) { return OK; } /* rfc-2069 digest */ if (resp->message_qop == NULL) { /* old client, so calc rfc-2069 digest */#ifdef SEND_DIGEST /* most of this totally bogus because the handlers don't set the * headers until the final handler phase (I wonder why this phase * is called fixup when there's almost nothing you can fix up...) * * Because it's basically impossible to get this right (e.g. the * Content-length is never set yet when we get here, and we can't * calc the entity hash) it's best to just leave this #def'd out. */ char date[APR_RFC822_DATE_LEN]; apr_rfc822_date(date, r->request_time); char *entity_info = ap_md5(r->pool, (unsigned char *) apr_pstrcat(r->pool, resp->raw_request_uri, ":", r->content_type ? r->content_type : ap_default_type(r), ":", hdr(r->headers_out, "Content-Length"), ":", r->content_encoding ? r->content_encoding : "", ":", hdr(r->headers_out, "Last-Modified"), ":", r->no_cache && !apr_table_get(r->headers_out, "Expires") ? date : hdr(r->headers_out, "Expires"), NULL)); digest = ap_md5(r->pool, (unsigned char *)apr_pstrcat(r->pool, conf->ha1, ":", resp->nonce, ":", r->method, ":", date, ":", entity_info, ":", ap_md5(r->pool, (unsigned char *) ""), /* H(entity) - TBD */ NULL));#endif } /* setup nextnonce */ if (conf->nonce_lifetime > 0) { /* send nextnonce if current nonce will expire in less than 30 secs */ if ((r->request_time - resp->nonce_time) > (conf->nonce_lifetime-NEXTNONCE_DELTA)) { nextnonce = apr_pstrcat(r->pool, ", nextnonce=\"", gen_nonce(r->pool, r->request_time, resp->opaque, r->server, conf), "\"", NULL); if (resp->client) resp->client->nonce_count = 0; } } else if (conf->nonce_lifetime == 0 && resp->client) { const char *nonce = gen_nonce(r->pool, 0, resp->opaque, r->server, conf); nextnonce = apr_pstrcat(r->pool, ", nextnonce=\"", nonce, "\"", NULL); memcpy(resp->client->last_nonce, nonce, NONCE_LEN+1); } /* else nonce never expires, hence no nextnonce */ /* do rfc-2069 digest */ if (conf->qop_list[0] && !strcasecmp(conf->qop_list[0], "none") && resp->message_qop == NULL) { /* use only RFC-2069 format */ if (digest) { ai = apr_pstrcat(r->pool, "digest=\"", digest, "\"", nextnonce,NULL); } else { ai = nextnonce; } } else { const char *resp_dig, *ha1, *a2, *ha2; /* calculate rspauth attribute */ if (resp->algorithm && !strcasecmp(resp->algorithm, "MD5-sess")) { ha1 = get_session_HA1(r, resp, conf, 0); if (!ha1) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "Digest: internal error:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -