📄 mod_auth_digest.c
字号:
/* 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 const char *get_hash(request_rec *r, const char *user, const char *realm, const char *auth_pwfile){ ap_configfile_t *f; char l[MAX_STRING_LEN]; const char *rpw; char *w, *x; apr_status_t sts; if ((sts = ap_pcfg_openfile(&f, r->pool, auth_pwfile)) != APR_SUCCESS) { ap_log_rerror(APLOG_MARK, APLOG_ERR, sts, r, "Digest: Could not open password file: %s", auth_pwfile); return NULL; } while (!(ap_cfg_getline(l, MAX_STRING_LEN, f))) { if ((l[0] == '#') || (!l[0])) { continue; } rpw = l; w = ap_getword(r->pool, &rpw, ':'); x = ap_getword(r->pool, &rpw, ':'); if (x && w && !strcmp(user, w) && !strcmp(realm, x)) { ap_cfg_closefile(f); return apr_pstrdup(r->pool, rpw); } } ap_cfg_closefile(f); return NULL;}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. * * 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; /* 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);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -