diff --git a/include/types/action.h b/include/types/action.h index b01380c3a..00c37fa6a 100644 --- a/include/types/action.h +++ b/include/types/action.h @@ -89,7 +89,6 @@ enum act_name { /* http request actions. */ ACT_HTTP_REQ_TARPIT, - ACT_HTTP_REQ_AUTH, /* tcp actions */ ACT_TCP_EXPECT_PX, diff --git a/src/http_act.c b/src/http_act.c index ab4a8bb94..b18da6164 100644 --- a/src/http_act.c +++ b/src/http_act.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -884,6 +885,85 @@ static enum act_parse_ret parse_http_deny(const char **args, int *orig_arg, stru return ACT_RET_PRS_OK; } + +/* This function executes a auth action. It builds an 401/407 HTX message using + * the corresponding proxy's error message. On success, it returns + * ACT_RET_ABRT. If an error occurs ACT_RET_ERR is returned. + */ +static enum act_return http_action_auth(struct act_rule *rule, struct proxy *px, + struct session *sess, struct stream *s, int flags) +{ + struct channel *req = &s->req; + struct channel *res = &s->res; + struct htx *htx = htx_from_buf(&res->buf); + struct http_reply *reply; + const char *auth_realm; + struct http_hdr_ctx ctx; + struct ist hdr; + + /* Auth might be performed on regular http-req rules as well as on stats */ + auth_realm = rule->arg.http.str.ptr; + if (!auth_realm) { + if (px->uri_auth && s->current_rule_list == &px->uri_auth->http_req_rules) + auth_realm = STATS_DEFAULT_REALM; + else + auth_realm = px->id; + } + + if (!(s->txn->flags & TX_USE_PX_CONN)) { + s->txn->status = 401; + hdr = ist("WWW-Authenticate"); + } + else { + s->txn->status = 407; + hdr = ist("Proxy-Authenticate"); + } + reply = http_error_message(s); + channel_htx_truncate(res, htx); + + if (chunk_printf(&trash, "Basic realm=\"%s\"", auth_realm) == -1) + goto fail; + + /* Write the generic 40x message */ + if (http_reply_to_htx(s, htx, reply) == -1) + goto fail; + + /* Remove all existing occurrences of the XXX-Authenticate header */ + ctx.blk = NULL; + while (http_find_header(htx, hdr, &ctx, 1)) + http_remove_header(htx, &ctx); + + /* Now a the right XXX-Authenticate header */ + if (!http_add_header(htx, hdr, ist2(b_orig(&trash), b_data(&trash)))) + goto fail; + + /* Finally forward the reply */ + htx_to_buf(htx, &res->buf); + if (!http_forward_proxy_resp(s, 1)) + goto fail; + + /* Note: Only eval on the request */ + s->logs.tv_request = now; + req->analysers &= AN_REQ_FLT_END; + + if (s->sess->fe == s->be) /* report it if the request was intercepted by the frontend */ + _HA_ATOMIC_ADD(&s->sess->fe->fe_counters.intercepted_req, 1); + + if (!(s->flags & SF_ERR_MASK)) + s->flags |= SF_ERR_LOCAL; + if (!(s->flags & SF_FINST_MASK)) + s->flags |= SF_FINST_R; + + stream_inc_http_err_ctr(s); + return ACT_RET_ABRT; + + fail: + /* If an error occurred, remove the incomplete HTTP response from the + * buffer */ + channel_htx_truncate(res, htx); + return ACT_RET_ERR; +} + /* Parse a "auth" action. It may take 2 optional arguments to define a "realm" * parameter. It returns ACT_RET_PRS_OK on success, ACT_RET_PRS_ERR on error. */ @@ -892,8 +972,9 @@ static enum act_parse_ret parse_http_auth(const char **args, int *orig_arg, stru { int cur_arg; - rule->action = ACT_HTTP_REQ_AUTH; + rule->action = ACT_CUSTOM; rule->flags |= ACT_FLAG_FINAL; + rule->action_ptr = http_action_auth; rule->release_ptr = release_http_action; cur_arg = *orig_arg; diff --git a/src/http_ana.c b/src/http_ana.c index e239f7c31..cf9570c3b 100644 --- a/src/http_ana.c +++ b/src/http_ana.c @@ -63,7 +63,6 @@ static int http_handle_stats(struct stream *s, struct channel *req); static int http_handle_expect_hdr(struct stream *s, struct htx *htx, struct http_msg *msg); static int http_reply_100_continue(struct stream *s); -static int http_reply_40x_unauthorized(struct stream *s, const char *auth_realm); /* This stream analyser waits for a complete HTTP request. It returns 1 if the * processing can continue on next analysers, or zero if it either needs more @@ -2824,7 +2823,6 @@ static enum rule_result http_req_get_intercept_rule(struct proxy *px, struct lis struct htx *htx; struct act_rule *rule; struct http_hdr_ctx ctx; - const char *auth_realm; enum rule_result rule_ret = HTTP_RULE_RES_CONT; int act_opts = 0; @@ -2920,25 +2918,6 @@ static enum rule_result http_req_get_intercept_rule(struct proxy *px, struct lis rule_ret = HTTP_RULE_RES_DENY; goto end; - case ACT_HTTP_REQ_AUTH: - /* Auth might be performed on regular http-req rules as well as on stats */ - auth_realm = rule->arg.http.str.ptr; - if (!auth_realm) { - if (px->uri_auth && rules == &px->uri_auth->http_req_rules) - auth_realm = STATS_DEFAULT_REALM; - else - auth_realm = px->id; - } - /* send 401/407 depending on whether we use a proxy or not. We still - * count one error, because normal browsing won't significantly - * increase the counter but brute force attempts will. - */ - rule_ret = HTTP_RULE_RES_ABRT; - if (http_reply_40x_unauthorized(s, auth_realm) == -1) - rule_ret = HTTP_RULE_RES_ERROR; - stream_inc_http_err_ctr(s); - goto end; - case ACT_HTTP_REDIR: rule_ret = HTTP_RULE_RES_ABRT; if (!http_apply_redirect_rule(rule->arg.redir, s, txn)) @@ -4902,71 +4881,6 @@ static int http_reply_100_continue(struct stream *s) } -/* Send a 401-Unauthorized or 407-Unauthorized response to the client, depending - * ont whether we use a proxy or not. It returns 0 on success and -1 on - * error. The response channel is updated accordingly. - */ -static int http_reply_40x_unauthorized(struct stream *s, const char *auth_realm) -{ - struct channel *res = &s->res; - struct htx *htx = htx_from_buf(&res->buf); - struct http_reply *reply; - struct http_hdr_ctx ctx; - struct ist hdr; - - if (!(s->txn->flags & TX_USE_PX_CONN)) { - s->txn->status = 401; - hdr = ist("WWW-Authenticate"); - } - else { - s->txn->status = 407; - hdr = ist("Proxy-Authenticate"); - } - reply = http_error_message(s); - channel_htx_truncate(res, htx); - - if (chunk_printf(&trash, "Basic realm=\"%s\"", auth_realm) == -1) - goto fail; - - /* Write the generic 40x message */ - if (http_reply_to_htx(s, htx, reply) == -1) - goto fail; - - /* Remove all existing occurrences of the XXX-Authenticate header */ - ctx.blk = NULL; - while (http_find_header(htx, hdr, &ctx, 1)) - http_remove_header(htx, &ctx); - - /* Now a the right XXX-Authenticate header */ - if (!http_add_header(htx, hdr, ist2(b_orig(&trash), b_data(&trash)))) - goto fail; - - /* Finally forward the reply */ - htx_to_buf(htx, &res->buf); - if (!http_forward_proxy_resp(s, 1)) - goto fail; - - /* Note: Only eval on the request */ - s->logs.tv_request = now; - s->req.analysers &= AN_REQ_FLT_END; - - if (s->sess->fe == s->be) /* report it if the request was intercepted by the frontend */ - _HA_ATOMIC_ADD(&s->sess->fe->fe_counters.intercepted_req, 1); - - if (!(s->flags & SF_ERR_MASK)) - s->flags |= SF_ERR_LOCAL; - if (!(s->flags & SF_FINST_MASK)) - s->flags |= SF_FINST_R; - - return 0; - - fail: - /* If an error occurred, remove the incomplete HTTP response from the - * buffer */ - channel_htx_truncate(res, htx); - return -1; -} - /* * Capture headers from message according to header list , and * fill the pointers appropriately.