⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mod_auth_digest.c

📁 apache 安装教程 apache 安装教程
💻 C
📖 第 1 页 / 共 4 页
字号:
    /* 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,						      &digest_auth_module);    resp->needed_auth = 1;    /* get our conf */    conf = (digest_config_rec *) ap_get_module_config(r->per_dir_config,						      &digest_auth_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_NOERRNO|APLOG_ERR, 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_NOERRNO|APLOG_ERR, 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 AUTH_REQUIRED;    }    r->connection->user         = (char *) resp->username;    r->connection->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	 */	uri_components r_uri, d_uri;	copy_uri_components(&r_uri, resp->psd_request_uri, r);	if (ap_parse_uri_components(r->pool, resp->uri, &d_uri) != HTTP_OK) {	    ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r,			  "Digest: invalid uri <%s> in Authorization header",			  resp->uri);	    return 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);	if (r->method_number == M_CONNECT) {	    if (strcmp(resp->uri, r_uri.hostinfo)) {		ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r,			      "Digest: uri mismatch - <%s> does not match "			      "request-uri <%s>", resp->uri, r_uri.hostinfo);		return BAD_REQUEST;	    }	}	else if (	    /* check hostname matches, if present */	    !compare_hostnames(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_NOERRNO|APLOG_ERR, r,			  "Digest: uri mismatch - <%s> does not match "			  "request-uri <%s>", resp->uri, resp->raw_request_uri);	    return BAD_REQUEST;	}    }    if (resp->opaque && resp->opaque_num == 0) {	ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r,		      "Digest: received invalid opaque - got `%s'",		      resp->opaque);	note_digest_auth_failure(r, conf, resp, 0);	return AUTH_REQUIRED;    }    if (strcmp(resp->realm, conf->realm)) {	ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r,		      "Digest: realm mismatch - got `%s' but expected `%s'",		      resp->realm, conf->realm);	note_digest_auth_failure(r, conf, resp, 0);	return AUTH_REQUIRED;    }    if (resp->algorithm != NULL	&& strcasecmp(resp->algorithm, "MD5")	&& strcasecmp(resp->algorithm, "MD5-sess")) {	ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r,		      "Digest: unknown algorithm `%s' received: %s",		      resp->algorithm, r->uri);	note_digest_auth_failure(r, conf, resp, 0);	return AUTH_REQUIRED;    }    if (!conf->pwfile)	return DECLINED;    if (!(conf->ha1 = get_hash(r, conn->user, conf->realm, conf->pwfile))) {	ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r,		      "Digest: user `%s' in realm `%s' not found: %s",		      conn->user, conf->realm, r->uri);	note_digest_auth_failure(r, conf, resp, 0);	return AUTH_REQUIRED;    }    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_NOERRNO|APLOG_ERR, r,			  "Digest: user %s: password mismatch: %s", conn->user,			  r->uri);	    note_digest_auth_failure(r, conf, resp, 0);	    return AUTH_REQUIRED;	}    }    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_NOERRNO|APLOG_ERR, r,			  "Digest: invalid qop `%s' received: %s",			  resp->message_qop, r->uri);	    note_digest_auth_failure(r, conf, resp, 0);	    return AUTH_REQUIRED;	}	if (check_nc(r, resp, conf) != OK) {	    note_digest_auth_failure(r, conf, resp, 0);	    return AUTH_REQUIRED;	}	exp_digest = new_digest(r, resp, conf);	if (!exp_digest) {	    /* we failed to allocate a client struct */	    return SERVER_ERROR;	}	if (strcmp(resp->digest, exp_digest)) {	    ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r,			  "Digest: user %s: password mismatch: %s", conn->user,			  r->uri);	    note_digest_auth_failure(r, conf, resp, 0);	    return AUTH_REQUIRED;	}    }    /* 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;}/* * Checking ID */static table *groups_for_user(request_rec *r, const char *user,			      const char *grpfile){    configfile_t *f;    table *grps = ap_make_table(r->pool, 15);    pool *sp;    char l[MAX_STRING_LEN];    const char *group_name, *ll, *w;    if (!(f = ap_pcfg_openfile(r->pool, grpfile))) {	ap_log_rerror(APLOG_MARK, APLOG_ERR, r,		      "Digest: Could not open group file: %s", grpfile);	return NULL;    }    sp = ap_make_sub_pool(r->pool);    while (!(ap_cfg_getline(l, MAX_STRING_LEN, f))) {	if ((l[0] == '#') || (!l[0]))	    continue;	ll = l;	ap_clear_pool(sp);	group_name = ap_getword(sp, &ll, ':');	while (ll[0]) {	    w = ap_getword_conf(sp, &ll);	    if (!strcmp(w, user)) {		ap_table_setn(grps, ap_pstrdup(r->pool, group_name), "in");		break;	    }	}    }    ap_cfg_closefile(f);    ap_destroy_pool(sp);    return grps;}static int digest_check_auth(request_rec *r){    const digest_config_rec *conf =		(digest_config_rec *) ap_get_module_config(r->per_dir_config,							   &digest_auth_module);    const char *user = r->connection->user;    int m = r->method_number;    int method_restricted = 0;    register int x;    const char *t, *w;    table *grpstatus;    const array_header *reqs_arr;    require_line *reqs;    if (!(t = ap_auth_type(r)) || strcasecmp(t, "Digest"))	return DECLINED;    reqs_arr = ap_requires(r);    /* If there is no "requires" directive, then any user will do.     */    if (!reqs_arr)	return OK;    reqs = (require_line *) reqs_arr->elts;    if (conf->grpfile)	grpstatus = groups_for_user(r, user, conf->grpfile);    else	grpstatus = NULL;    for (x = 0; x < reqs_arr->nelts; x++) {	if (!(reqs[x].method_mask & (1 << m)))	    continue;	method_restricted = 1;	t = reqs[x].requirement;	w = ap_getword_white(r->pool, &t);	if (!strcasecmp(w, "valid-user"))	    return OK;	else if (!strcasecmp(w, "user")) {	    while (t[0]) {		w = ap_getword_conf(r->pool, &t);		if (!strcmp(user, w))		    return OK;	    }	}	else if (!strcasecmp(w, "group")) {	    if (!grpstatus)		return DECLINED;	    while (t[0]) {		w = ap_getword_conf(r->pool, &t);		if (ap_table_get(grpstatus, w))		    return OK;	    }	}	else {	    ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r,		"Digest: access to %s failed, reason: unknown require "		"directive \"%s\"", r->uri, reqs[x].requirement);	    return DECLINED;	}    }    if (!method_restricted)	return OK;    ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r,	"Digest: access to %s failed, reason: user %s not allowed access",	r->uri, user);    note_digest_auth_failure(r, conf,	(digest_header_rec *) ap_get_module_config(r->request_config,						   &digest_auth_module),	0);    return AUTH_REQUIRED;}/* * Authorization-Info header code */#ifdef SEND_DIGESTstatic const char *hdr(const table *tbl, const char *name){    const char *val = ap_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,							   &digest_auth_module);    digest_header_rec *resp =		(digest_header_rec *) ap_get_module_config(r->request_config,							   &digest_auth_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 *entity_info =	    ap_md5(r->pool,		   (unsigned char *) ap_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 && !ap_table_get(r->headers_out, "Expires") ?			    ap_gm_timestr_822(r->pool, r->request_time) :			    hdr(r->headers_out, "Expires"),		       NULL));	digest =	    ap_md5(r->pool,		   (unsigned char *)ap_pstrcat(r->pool, conf->ha1, ":",					       resp->nonce, ":",					       r->method, ":",					       ap_gm_timestr_822(r->pool, r->request_time), ":",					       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 (difftime(r->request_time, resp->nonce_time) > (conf->nonce_lifetime-NEXTNONCE_DELTA)) {	    nextnonce = ap_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 = ap_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 = ap_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_NOERRNO|APLOG_ERR, r,			      "Digest: internal error: couldn't find session "			      "info for user %s", resp->username);		return !OK;	    }	}	else	    ha1 = conf->ha1;	if (resp->message_qop && !strcasecmp(resp->message_qop, "auth-int"))	    a2 = ap_pstrcat(r->pool, ":", resp->uri, ":",			    ap_md5(r->pool, (const unsigned char *) ""), NULL); /* TBD */	else	    a2 = ap_pstrcat(r->pool, ":", resp->uri, NULL);	ha2 = ap_md5(r->pool, (const unsigned char *)a2);	resp_dig = ap_md5(r->pool,		         (unsigned char *)ap_pstrcat(r->pool, ha1, ":",						     resp->nonce, ":",						     resp->nonce_count, ":",						     resp->cnonce, ":",						     resp->message_qop ?							 resp->message_qop : "",						     ":", ha2, NULL));	/* assemble Authentication-Info header	 */	ai = ap_pstrcat(r->pool,			"rspauth=\"", resp_dig, "\"",			nextnonce,		        resp->cnonce ? ", cnonce=\"" : "",		        resp->cnonce ? ap_escape_quotes(r->pool, resp->cnonce) :					"",		        resp->cnonce ? "\"" : "",		        resp->nonce_count ? ", nc=" : "",		        resp->nonce_count ? resp->nonce_count : "",		        resp->message_qop ? ", qop=" : "",		        resp->message_qop ? resp->message_qop : "",			digest ? "digest=\"" : "",			digest ? digest : "",			digest ? "\"" : "",			NULL);    }    if (ai && ai[0])	ap_table_mergen(r->headers_out,			r->proxyreq == STD_PROXY ? "Proxy-Authentication-Info"						 : "Authentication-Info",			ai);    return OK;}module MODULE_VAR_EXPORT digest_auth_module ={    STANDARD_MODULE_STUFF,    initialize_module,		/* initializer */    create_digest_dir_config,	/* dir config creater */    NULL,			/* dir merger --- default is to override */    NULL,			/* server config */    NULL,			/* merge server config */    digest_cmds,		/* command table */    NULL,			/* handlers */    NULL,			/* filename translation */    authenticate_digest_user,	/* check_user_id */    digest_check_auth,		/* check auth */    NULL,			/* check access */    NULL,			/* type_checker */    add_auth_info,		/* fixups */    NULL,			/* logger */    NULL,			/* header parser */    NULL,			/* child_init */    NULL,			/* child_exit */    update_nonce_count		/* post read-request */};

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -