From 8a3360d18ab148fad6b32b4a8e710f84cd9a45d2 Mon Sep 17 00:00:00 2001 From: Martin Storsjö Date: Mon, 12 Mar 2012 13:59:36 +0200 Subject: httpauth: Parse the stale field in digest auth MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Martin Storsjö --- libavformat/httpauth.c | 10 ++++++++++ libavformat/httpauth.h | 7 +++++++ 2 files changed, 17 insertions(+) (limited to 'libavformat') diff --git a/libavformat/httpauth.c b/libavformat/httpauth.c index 4383585db1..c1cf019eda 100644 --- a/libavformat/httpauth.c +++ b/libavformat/httpauth.c @@ -57,6 +57,9 @@ static void handle_digest_params(HTTPAuthState *state, const char *key, } else if (!strncmp(key, "qop=", key_len)) { *dest = digest->qop; *dest_len = sizeof(digest->qop); + } else if (!strncmp(key, "stale=", key_len)) { + *dest = digest->stale; + *dest_len = sizeof(digest->stale); } } @@ -93,6 +96,7 @@ void ff_http_auth_handle_header(HTTPAuthState *state, const char *key, state->auth_type <= HTTP_AUTH_BASIC) { state->auth_type = HTTP_AUTH_BASIC; state->realm[0] = 0; + state->stale = 0; ff_parse_key_value(p, (ff_parse_key_val_cb) handle_basic_params, state); } else if (av_stristart(value, "Digest ", &p) && @@ -100,10 +104,13 @@ void ff_http_auth_handle_header(HTTPAuthState *state, const char *key, state->auth_type = HTTP_AUTH_DIGEST; memset(&state->digest_params, 0, sizeof(DigestParams)); state->realm[0] = 0; + state->stale = 0; ff_parse_key_value(p, (ff_parse_key_val_cb) handle_digest_params, state); choose_qop(state->digest_params.qop, sizeof(state->digest_params.qop)); + if (!av_strcasecmp(state->digest_params.stale, "true")) + state->stale = 1; } } else if (!strcmp(key, "Authentication-Info")) { ff_parse_key_value(value, (ff_parse_key_val_cb) handle_digest_update, @@ -237,6 +244,9 @@ char *ff_http_auth_create_response(HTTPAuthState *state, const char *auth, { char *authstr = NULL; + /* Clear the stale flag, we assume the auth is ok now. It is reset + * by the server headers if there's a new issue. */ + state->stale = 0; if (!auth || !strchr(auth, ':')) return NULL; diff --git a/libavformat/httpauth.h b/libavformat/httpauth.h index d2a4a55305..bd0644906a 100644 --- a/libavformat/httpauth.h +++ b/libavformat/httpauth.h @@ -41,6 +41,9 @@ typedef struct { char opaque[300]; /**< A server-specified string that should be * included in authentication responses, not * included in the actual digest calculation. */ + char stale[10]; /**< The server indicated that the auth was ok, + * but needs to be redone with a new, non-stale + * nonce. */ int nc; /**< Nonce count, the number of earlier replies * where this particular nonce has been used. */ } DigestParams; @@ -62,6 +65,10 @@ typedef struct { * The parameters specifiec to digest authentication. */ DigestParams digest_params; + /** + * Auth ok, but needs to be resent with a new nonce. + */ + int stale; } HTTPAuthState; void ff_http_auth_handle_header(HTTPAuthState *state, const char *key, -- cgit v1.2.3 From 2f96cc1fc41f2d3a349d55f9d2078694a6a87dc1 Mon Sep 17 00:00:00 2001 From: Martin Storsjö Date: Mon, 12 Mar 2012 13:59:53 +0200 Subject: rtsp: Retry authentication if failed due to being stale MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Martin Storsjö --- libavformat/rtsp.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'libavformat') diff --git a/libavformat/rtsp.c b/libavformat/rtsp.c index 4290abbdc1..ecc1cbafef 100644 --- a/libavformat/rtsp.c +++ b/libavformat/rtsp.c @@ -1122,7 +1122,7 @@ int ff_rtsp_send_cmd_with_content(AVFormatContext *s, { RTSPState *rt = s->priv_data; HTTPAuthType cur_auth_type; - int ret; + int ret, attempts = 0; retry: cur_auth_type = rt->auth_state.auth_type; @@ -1133,9 +1133,11 @@ retry: if ((ret = ff_rtsp_read_reply(s, reply, content_ptr, 0, method) ) < 0) return ret; + attempts++; - if (reply->status_code == 401 && cur_auth_type == HTTP_AUTH_NONE && - rt->auth_state.auth_type != HTTP_AUTH_NONE) + if (reply->status_code == 401 && + (cur_auth_type == HTTP_AUTH_NONE || rt->auth_state.stale) && + rt->auth_state.auth_type != HTTP_AUTH_NONE && attempts < 2) goto retry; if (reply->status_code > 400){ -- cgit v1.2.3 From cdf9108b6ae35f597f3a7932b70be7c8cf9bd743 Mon Sep 17 00:00:00 2001 From: Martin Storsjö Date: Mon, 12 Mar 2012 16:11:22 +0200 Subject: rtsp: Resend new keepalive commands if they used stale auth MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit These commands are sent asynchronously, not waiting for the reply. This reply is parsed later by ff_rtsp_tcp_read_packet or udp_read_packet. If the reply indicates that we used stale authentication and need to use a new nonce, resend a new keepalive command immediately. This is the only request sent asynchronously, so currently there's no other command that needs to be resent in the same way. Signed-off-by: Martin Storsjö --- libavformat/rtspdec.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'libavformat') diff --git a/libavformat/rtspdec.c b/libavformat/rtspdec.c index 80420aa42d..acae436c13 100644 --- a/libavformat/rtspdec.c +++ b/libavformat/rtspdec.c @@ -335,7 +335,8 @@ retry: rt->packets++; /* send dummy request to keep TCP connection alive */ - if ((av_gettime() - rt->last_cmd_time) / 1000000 >= rt->timeout / 2) { + if ((av_gettime() - rt->last_cmd_time) / 1000000 >= rt->timeout / 2 || + rt->auth_state.stale) { if (rt->server_type == RTSP_SERVER_WMS || (rt->server_type != RTSP_SERVER_REAL && rt->get_parameter_supported)) { @@ -343,6 +344,10 @@ retry: } else { ff_rtsp_send_cmd_async(s, "OPTIONS", "*", NULL); } + /* The stale flag should be reset when creating the auth response in + * ff_rtsp_send_cmd_async, but reset it here just in case we never + * called the auth code (if we didn't have any credentials set). */ + rt->auth_state.stale = 0; } return 0; -- cgit v1.2.3 From e75bbcf493aeb549d04c56f49406aeee3950d93b Mon Sep 17 00:00:00 2001 From: Martin Storsjö Date: Mon, 12 Mar 2012 14:00:16 +0200 Subject: http: Retry auth if it failed due to being stale MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Allow up to 4 retries for normal requests, where both the proxy and the target server might need to authenticate. Signed-off-by: Martin Storsjö --- libavformat/http.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) (limited to 'libavformat') diff --git a/libavformat/http.c b/libavformat/http.c index eea8dedcbc..a768b19fd9 100644 --- a/libavformat/http.c +++ b/libavformat/http.c @@ -93,7 +93,7 @@ static int http_open_cnx(URLContext *h) char auth[1024], proxyauth[1024] = ""; char path1[1024]; char buf[1024], urlbuf[1024]; - int port, use_proxy, err, location_changed = 0, redirects = 0; + int port, use_proxy, err, location_changed = 0, redirects = 0, attempts = 0; HTTPAuthType cur_auth_type, cur_proxy_auth_type; HTTPContext *s = h->priv_data; URLContext *hd = NULL; @@ -145,16 +145,18 @@ static int http_open_cnx(URLContext *h) cur_proxy_auth_type = s->auth_state.auth_type; if (http_connect(h, path, local_path, hoststr, auth, proxyauth, &location_changed) < 0) goto fail; + attempts++; if (s->http_code == 401) { - if (cur_auth_type == HTTP_AUTH_NONE && s->auth_state.auth_type != HTTP_AUTH_NONE) { + if ((cur_auth_type == HTTP_AUTH_NONE || s->auth_state.stale) && + s->auth_state.auth_type != HTTP_AUTH_NONE && attempts < 4) { ffurl_close(hd); goto redo; } else goto fail; } if (s->http_code == 407) { - if (cur_proxy_auth_type == HTTP_AUTH_NONE && - s->proxy_auth_state.auth_type != HTTP_AUTH_NONE) { + if ((cur_proxy_auth_type == HTTP_AUTH_NONE || s->proxy_auth_state.stale) && + s->proxy_auth_state.auth_type != HTTP_AUTH_NONE && attempts < 4) { ffurl_close(hd); goto redo; } else @@ -166,6 +168,7 @@ static int http_open_cnx(URLContext *h) ffurl_close(hd); if (redirects++ >= MAX_REDIRECTS) return AVERROR(EIO); + attempts = 0; location_changed = 0; goto redo; } @@ -598,7 +601,7 @@ static int http_proxy_open(URLContext *h, const char *uri, int flags) char hostname[1024], hoststr[1024]; char auth[1024], pathbuf[1024], *path; char line[1024], lower_url[100]; - int port, ret = 0; + int port, ret = 0, attempts = 0; HTTPAuthType cur_auth_type; char *authstr; @@ -665,8 +668,10 @@ redo: break; s->line_count++; } - if (s->http_code == 407 && cur_auth_type == HTTP_AUTH_NONE && - s->proxy_auth_state.auth_type != HTTP_AUTH_NONE) { + attempts++; + if (s->http_code == 407 && + (cur_auth_type == HTTP_AUTH_NONE || s->proxy_auth_state.stale) && + s->proxy_auth_state.auth_type != HTTP_AUTH_NONE && attempts < 2) { ffurl_close(s->hd); s->hd = NULL; goto redo; -- cgit v1.2.3 From 499ad54d982307a31ef70f6256a9ffccff0057e5 Mon Sep 17 00:00:00 2001 From: Martin Storsjö Date: Mon, 12 Mar 2012 14:03:46 +0200 Subject: http: Clear the auth state on redirects MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently we only try continuing with the same auth mechanism as the initial request. Signed-off-by: Martin Storsjö --- libavformat/http.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'libavformat') diff --git a/libavformat/http.c b/libavformat/http.c index a768b19fd9..c69e3f5055 100644 --- a/libavformat/http.c +++ b/libavformat/http.c @@ -168,6 +168,9 @@ static int http_open_cnx(URLContext *h) ffurl_close(hd); if (redirects++ >= MAX_REDIRECTS) return AVERROR(EIO); + /* Restart the authentication process with the new target, which + * might use a different auth mechanism. */ + memset(&s->auth_state, 0, sizeof(s->auth_state)); attempts = 0; location_changed = 0; goto redo; -- cgit v1.2.3