📄 mod_auth_digest.c
字号:
} } return ha1;}static void clear_session(const digest_header_rec *resp){ if (resp->client) { resp->client->ha1[0] = '\0'; }}/* * Authorization challenge generation code (for WWW-Authenticate) */static const char *ltox(apr_pool_t *p, unsigned long num){ if (num != 0) { return apr_psprintf(p, "%lx", num); } else { return ""; }}static void note_digest_auth_failure(request_rec *r, const digest_config_rec *conf, digest_header_rec *resp, int stale){ const char *qop, *opaque, *opaque_param, *domain, *nonce; int cnt; /* Setup qop */ if (conf->qop_list[0] == NULL) { qop = ", qop=\"auth\""; } else if (!strcasecmp(conf->qop_list[0], "none")) { qop = ""; } else { qop = apr_pstrcat(r->pool, ", qop=\"", conf->qop_list[0], NULL); for (cnt = 1; conf->qop_list[cnt] != NULL; cnt++) { qop = apr_pstrcat(r->pool, qop, ",", conf->qop_list[cnt], NULL); } qop = apr_pstrcat(r->pool, qop, "\"", NULL); } /* Setup opaque */ if (resp->opaque == NULL) { /* new client */ if ((conf->check_nc || conf->nonce_lifetime == 0 || !strcasecmp(conf->algorithm, "MD5-sess")) && (resp->client = gen_client(r)) != NULL) { opaque = ltox(r->pool, resp->client->key); } else { opaque = ""; /* opaque not needed */ } } else if (resp->client == NULL) { /* client info was gc'd */ resp->client = gen_client(r); if (resp->client != NULL) { opaque = ltox(r->pool, resp->client->key); stale = 1; client_list->num_renewed++; } else { opaque = ""; /* ??? */ } } else { opaque = resp->opaque; /* we're generating a new nonce, so reset the nonce-count */ resp->client->nonce_count = 0; } if (opaque[0]) { opaque_param = apr_pstrcat(r->pool, ", opaque=\"", opaque, "\"", NULL); } else { opaque_param = NULL; } /* Setup nonce */ nonce = gen_nonce(r->pool, r->request_time, opaque, r->server, conf); if (resp->client && conf->nonce_lifetime == 0) { memcpy(resp->client->last_nonce, nonce, NONCE_LEN+1); } /* Setup MD5-sess stuff. Note that we just clear out the session * info here, since we can't generate a new session until the request * from the client comes in with the cnonce. */ if (!strcasecmp(conf->algorithm, "MD5-sess")) { clear_session(resp); } /* setup domain attribute. We want to send this attribute wherever * possible so that the client won't send the Authorization header * unneccessarily (it's usually > 200 bytes!). */ /* don't send domain * - for proxy requests * - if it's no specified */ if (r->proxyreq || !conf->uri_list) { domain = NULL; } else { domain = conf->uri_list; } apr_table_mergen(r->err_headers_out, (PROXYREQ_PROXY == r->proxyreq) ? "Proxy-Authenticate" : "WWW-Authenticate", apr_psprintf(r->pool, "Digest realm=\"%s\", " "nonce=\"%s\", algorithm=%s%s%s%s%s", ap_auth_name(r), nonce, conf->algorithm, opaque_param ? opaque_param : "", domain ? domain : "", stale ? ", stale=true" : "", qop));}/* * Authorization header verification code */static authn_status get_hash(request_rec *r, const char *user, digest_config_rec *conf){ authn_status auth_result; char *password; authn_provider_list *current_provider; current_provider = conf->providers; do { const authn_provider *provider; /* For now, if a provider isn't set, we'll be nice and use the file * provider. */ if (!current_provider) { provider = ap_lookup_provider(AUTHN_PROVIDER_GROUP, AUTHN_DEFAULT_PROVIDER, "0"); if (!provider || !provider->get_realm_hash) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "No Authn provider configured"); auth_result = AUTH_GENERAL_ERROR; break; } apr_table_setn(r->notes, AUTHN_PROVIDER_NAME_NOTE, AUTHN_DEFAULT_PROVIDER); } else { provider = current_provider->provider; apr_table_setn(r->notes, AUTHN_PROVIDER_NAME_NOTE, current_provider->provider_name); } /* We expect the password to be md5 hash of user:realm:password */ auth_result = provider->get_realm_hash(r, user, conf->realm, &password); apr_table_unset(r->notes, AUTHN_PROVIDER_NAME_NOTE); /* Something occured. Stop checking. */ if (auth_result != AUTH_USER_NOT_FOUND) { break; } /* If we're not really configured for providers, stop now. */ if (!conf->providers) { break; } current_provider = current_provider->next; } while (current_provider); if (auth_result == AUTH_USER_FOUND) { conf->ha1 = password; } return auth_result;}static int check_nc(const request_rec *r, const digest_header_rec *resp, const digest_config_rec *conf){ unsigned long nc; const char *snc = resp->nonce_count; char *endptr; if (!conf->check_nc || !client_shm) { return OK; } nc = strtol(snc, &endptr, 16); if (endptr < (snc+strlen(snc)) && !apr_isspace(*endptr)) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "Digest: invalid nc %s received - not a number", snc); return !OK; } if (!resp->client) { return !OK; } if (nc != resp->client->nonce_count) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "Digest: Warning, possible replay attack: nonce-count " "check failed: %lu != %lu", nc, resp->client->nonce_count); return !OK; } return OK;}static int check_nonce(request_rec *r, digest_header_rec *resp, const digest_config_rec *conf){ apr_time_t dt; int len; time_rec nonce_time; char tmp, hash[NONCE_HASH_LEN+1]; if (strlen(resp->nonce) != NONCE_LEN) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "Digest: invalid nonce %s received - length is not %d", resp->nonce, NONCE_LEN); note_digest_auth_failure(r, conf, resp, 1); return HTTP_UNAUTHORIZED; } tmp = resp->nonce[NONCE_TIME_LEN]; resp->nonce[NONCE_TIME_LEN] = '\0'; len = apr_base64_decode_binary(nonce_time.arr, resp->nonce); gen_nonce_hash(hash, resp->nonce, resp->opaque, r->server, conf); resp->nonce[NONCE_TIME_LEN] = tmp; resp->nonce_time = nonce_time.time; if (strcmp(hash, resp->nonce+NONCE_TIME_LEN)) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "Digest: invalid nonce %s received - hash is not %s", resp->nonce, hash); note_digest_auth_failure(r, conf, resp, 1); return HTTP_UNAUTHORIZED; } dt = r->request_time - nonce_time.time; if (conf->nonce_lifetime > 0 && dt < 0) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "Digest: invalid nonce %s received - user attempted " "time travel", resp->nonce); note_digest_auth_failure(r, conf, resp, 1); return HTTP_UNAUTHORIZED; } if (conf->nonce_lifetime > 0) { if (dt > conf->nonce_lifetime) { ap_log_rerror(APLOG_MARK, APLOG_INFO, 0,r, "Digest: user %s: nonce expired (%.2f seconds old " "- max lifetime %.2f) - sending new nonce", r->user, (double)apr_time_sec(dt), (double)apr_time_sec(conf->nonce_lifetime)); note_digest_auth_failure(r, conf, resp, 1); return HTTP_UNAUTHORIZED; } } else if (conf->nonce_lifetime == 0 && resp->client) { if (memcmp(resp->client->last_nonce, resp->nonce, NONCE_LEN)) { ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, "Digest: user %s: one-time-nonce mismatch - sending " "new nonce", r->user); note_digest_auth_failure(r, conf, resp, 1); return HTTP_UNAUTHORIZED; } } /* else (lifetime < 0) => never expires */ return OK;}/* The actual MD5 code... whee *//* RFC-2069 */static const char *old_digest(const request_rec *r, const digest_header_rec *resp, const char *ha1){ const char *ha2; ha2 = ap_md5(r->pool, (unsigned char *)apr_pstrcat(r->pool, resp->method, ":", resp->uri, NULL)); return ap_md5(r->pool, (unsigned char *)apr_pstrcat(r->pool, ha1, ":", resp->nonce, ":", ha2, NULL));}/* RFC-2617 */static const char *new_digest(const request_rec *r, digest_header_rec *resp, const digest_config_rec *conf){ const char *ha1, *ha2, *a2; if (resp->algorithm && !strcasecmp(resp->algorithm, "MD5-sess")) { ha1 = get_session_HA1(r, resp, conf, 1); if (!ha1) { return NULL; } } else { ha1 = conf->ha1; } if (resp->message_qop && !strcasecmp(resp->message_qop, "auth-int")) { a2 = apr_pstrcat(r->pool, resp->method, ":", resp->uri, ":", ap_md5(r->pool, (const unsigned char*) ""), NULL); /* TBD */ } else { a2 = apr_pstrcat(r->pool, resp->method, ":", resp->uri, NULL); } ha2 = ap_md5(r->pool, (const unsigned char *)a2); return ap_md5(r->pool, (unsigned char *)apr_pstrcat(r->pool, ha1, ":", resp->nonce, ":", resp->nonce_count, ":", resp->cnonce, ":", resp->message_qop, ":", ha2, NULL));}static void copy_uri_components(apr_uri_t *dst, apr_uri_t *src, request_rec *r) { if (src->scheme && src->scheme[0] != '\0') { dst->scheme = src->scheme; } else { dst->scheme = (char *) "http"; } if (src->hostname && src->hostname[0] != '\0') { dst->hostname = apr_pstrdup(r->pool, src->hostname); ap_unescape_url(dst->hostname); } else { dst->hostname = (char *) ap_get_server_name(r); } if (src->port_str && src->port_str[0] != '\0') { dst->port = src->port; } else { dst->port = ap_get_server_port(r); } if (src->path && src->path[0] != '\0') { dst->path = apr_pstrdup(r->pool, src->path); ap_unescape_url(dst->path); } else { dst->path = src->path; } if (src->query && src->query[0] != '\0') { dst->query = apr_pstrdup(r->pool, src->query); ap_unescape_url(dst->query); } else { dst->query = src->query; } dst->hostinfo = src->hostinfo;}/* These functions return 0 if client is OK, and proper error status * if not... either HTTP_UNAUTHORIZED, if we made a check, and it failed, or * HTTP_INTERNAL_SERVER_ERROR, if things are so totally confused that we * couldn't figure out how to tell if the client is authorized or not.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -