annotate ffmpeg/libavformat/httpauth.c @ 13:844d341cf643 tip

Back up before ISMIR
author Yading Song <yading.song@eecs.qmul.ac.uk>
date Thu, 31 Oct 2013 13:17:06 +0000
parents f445c3017523
children
rev   line source
yading@11 1 /*
yading@11 2 * HTTP authentication
yading@11 3 * Copyright (c) 2010 Martin Storsjo
yading@11 4 *
yading@11 5 * This file is part of FFmpeg.
yading@11 6 *
yading@11 7 * FFmpeg is free software; you can redistribute it and/or
yading@11 8 * modify it under the terms of the GNU Lesser General Public
yading@11 9 * License as published by the Free Software Foundation; either
yading@11 10 * version 2.1 of the License, or (at your option) any later version.
yading@11 11 *
yading@11 12 * FFmpeg is distributed in the hope that it will be useful,
yading@11 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
yading@11 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
yading@11 15 * Lesser General Public License for more details.
yading@11 16 *
yading@11 17 * You should have received a copy of the GNU Lesser General Public
yading@11 18 * License along with FFmpeg; if not, write to the Free Software
yading@11 19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
yading@11 20 */
yading@11 21
yading@11 22 #include "httpauth.h"
yading@11 23 #include "libavutil/base64.h"
yading@11 24 #include "libavutil/avstring.h"
yading@11 25 #include "internal.h"
yading@11 26 #include "libavutil/random_seed.h"
yading@11 27 #include "libavutil/md5.h"
yading@11 28 #include "urldecode.h"
yading@11 29 #include "avformat.h"
yading@11 30
yading@11 31 static void handle_basic_params(HTTPAuthState *state, const char *key,
yading@11 32 int key_len, char **dest, int *dest_len)
yading@11 33 {
yading@11 34 if (!strncmp(key, "realm=", key_len)) {
yading@11 35 *dest = state->realm;
yading@11 36 *dest_len = sizeof(state->realm);
yading@11 37 }
yading@11 38 }
yading@11 39
yading@11 40 static void handle_digest_params(HTTPAuthState *state, const char *key,
yading@11 41 int key_len, char **dest, int *dest_len)
yading@11 42 {
yading@11 43 DigestParams *digest = &state->digest_params;
yading@11 44
yading@11 45 if (!strncmp(key, "realm=", key_len)) {
yading@11 46 *dest = state->realm;
yading@11 47 *dest_len = sizeof(state->realm);
yading@11 48 } else if (!strncmp(key, "nonce=", key_len)) {
yading@11 49 *dest = digest->nonce;
yading@11 50 *dest_len = sizeof(digest->nonce);
yading@11 51 } else if (!strncmp(key, "opaque=", key_len)) {
yading@11 52 *dest = digest->opaque;
yading@11 53 *dest_len = sizeof(digest->opaque);
yading@11 54 } else if (!strncmp(key, "algorithm=", key_len)) {
yading@11 55 *dest = digest->algorithm;
yading@11 56 *dest_len = sizeof(digest->algorithm);
yading@11 57 } else if (!strncmp(key, "qop=", key_len)) {
yading@11 58 *dest = digest->qop;
yading@11 59 *dest_len = sizeof(digest->qop);
yading@11 60 } else if (!strncmp(key, "stale=", key_len)) {
yading@11 61 *dest = digest->stale;
yading@11 62 *dest_len = sizeof(digest->stale);
yading@11 63 }
yading@11 64 }
yading@11 65
yading@11 66 static void handle_digest_update(HTTPAuthState *state, const char *key,
yading@11 67 int key_len, char **dest, int *dest_len)
yading@11 68 {
yading@11 69 DigestParams *digest = &state->digest_params;
yading@11 70
yading@11 71 if (!strncmp(key, "nextnonce=", key_len)) {
yading@11 72 *dest = digest->nonce;
yading@11 73 *dest_len = sizeof(digest->nonce);
yading@11 74 }
yading@11 75 }
yading@11 76
yading@11 77 static void choose_qop(char *qop, int size)
yading@11 78 {
yading@11 79 char *ptr = strstr(qop, "auth");
yading@11 80 char *end = ptr + strlen("auth");
yading@11 81
yading@11 82 if (ptr && (!*end || av_isspace(*end) || *end == ',') &&
yading@11 83 (ptr == qop || av_isspace(ptr[-1]) || ptr[-1] == ',')) {
yading@11 84 av_strlcpy(qop, "auth", size);
yading@11 85 } else {
yading@11 86 qop[0] = 0;
yading@11 87 }
yading@11 88 }
yading@11 89
yading@11 90 void ff_http_auth_handle_header(HTTPAuthState *state, const char *key,
yading@11 91 const char *value)
yading@11 92 {
yading@11 93 if (!strcmp(key, "WWW-Authenticate") || !strcmp(key, "Proxy-Authenticate")) {
yading@11 94 const char *p;
yading@11 95 if (av_stristart(value, "Basic ", &p) &&
yading@11 96 state->auth_type <= HTTP_AUTH_BASIC) {
yading@11 97 state->auth_type = HTTP_AUTH_BASIC;
yading@11 98 state->realm[0] = 0;
yading@11 99 state->stale = 0;
yading@11 100 ff_parse_key_value(p, (ff_parse_key_val_cb) handle_basic_params,
yading@11 101 state);
yading@11 102 } else if (av_stristart(value, "Digest ", &p) &&
yading@11 103 state->auth_type <= HTTP_AUTH_DIGEST) {
yading@11 104 state->auth_type = HTTP_AUTH_DIGEST;
yading@11 105 memset(&state->digest_params, 0, sizeof(DigestParams));
yading@11 106 state->realm[0] = 0;
yading@11 107 state->stale = 0;
yading@11 108 ff_parse_key_value(p, (ff_parse_key_val_cb) handle_digest_params,
yading@11 109 state);
yading@11 110 choose_qop(state->digest_params.qop,
yading@11 111 sizeof(state->digest_params.qop));
yading@11 112 if (!av_strcasecmp(state->digest_params.stale, "true"))
yading@11 113 state->stale = 1;
yading@11 114 }
yading@11 115 } else if (!strcmp(key, "Authentication-Info")) {
yading@11 116 ff_parse_key_value(value, (ff_parse_key_val_cb) handle_digest_update,
yading@11 117 state);
yading@11 118 }
yading@11 119 }
yading@11 120
yading@11 121
yading@11 122 static void update_md5_strings(struct AVMD5 *md5ctx, ...)
yading@11 123 {
yading@11 124 va_list vl;
yading@11 125
yading@11 126 va_start(vl, md5ctx);
yading@11 127 while (1) {
yading@11 128 const char* str = va_arg(vl, const char*);
yading@11 129 if (!str)
yading@11 130 break;
yading@11 131 av_md5_update(md5ctx, str, strlen(str));
yading@11 132 }
yading@11 133 va_end(vl);
yading@11 134 }
yading@11 135
yading@11 136 /* Generate a digest reply, according to RFC 2617. */
yading@11 137 static char *make_digest_auth(HTTPAuthState *state, const char *username,
yading@11 138 const char *password, const char *uri,
yading@11 139 const char *method)
yading@11 140 {
yading@11 141 DigestParams *digest = &state->digest_params;
yading@11 142 int len;
yading@11 143 uint32_t cnonce_buf[2];
yading@11 144 char cnonce[17];
yading@11 145 char nc[9];
yading@11 146 int i;
yading@11 147 char A1hash[33], A2hash[33], response[33];
yading@11 148 struct AVMD5 *md5ctx;
yading@11 149 uint8_t hash[16];
yading@11 150 char *authstr;
yading@11 151
yading@11 152 digest->nc++;
yading@11 153 snprintf(nc, sizeof(nc), "%08x", digest->nc);
yading@11 154
yading@11 155 /* Generate a client nonce. */
yading@11 156 for (i = 0; i < 2; i++)
yading@11 157 cnonce_buf[i] = av_get_random_seed();
yading@11 158 ff_data_to_hex(cnonce, (const uint8_t*) cnonce_buf, sizeof(cnonce_buf), 1);
yading@11 159 cnonce[2*sizeof(cnonce_buf)] = 0;
yading@11 160
yading@11 161 md5ctx = av_md5_alloc();
yading@11 162 if (!md5ctx)
yading@11 163 return NULL;
yading@11 164
yading@11 165 av_md5_init(md5ctx);
yading@11 166 update_md5_strings(md5ctx, username, ":", state->realm, ":", password, NULL);
yading@11 167 av_md5_final(md5ctx, hash);
yading@11 168 ff_data_to_hex(A1hash, hash, 16, 1);
yading@11 169 A1hash[32] = 0;
yading@11 170
yading@11 171 if (!strcmp(digest->algorithm, "") || !strcmp(digest->algorithm, "MD5")) {
yading@11 172 } else if (!strcmp(digest->algorithm, "MD5-sess")) {
yading@11 173 av_md5_init(md5ctx);
yading@11 174 update_md5_strings(md5ctx, A1hash, ":", digest->nonce, ":", cnonce, NULL);
yading@11 175 av_md5_final(md5ctx, hash);
yading@11 176 ff_data_to_hex(A1hash, hash, 16, 1);
yading@11 177 A1hash[32] = 0;
yading@11 178 } else {
yading@11 179 /* Unsupported algorithm */
yading@11 180 av_free(md5ctx);
yading@11 181 return NULL;
yading@11 182 }
yading@11 183
yading@11 184 av_md5_init(md5ctx);
yading@11 185 update_md5_strings(md5ctx, method, ":", uri, NULL);
yading@11 186 av_md5_final(md5ctx, hash);
yading@11 187 ff_data_to_hex(A2hash, hash, 16, 1);
yading@11 188 A2hash[32] = 0;
yading@11 189
yading@11 190 av_md5_init(md5ctx);
yading@11 191 update_md5_strings(md5ctx, A1hash, ":", digest->nonce, NULL);
yading@11 192 if (!strcmp(digest->qop, "auth") || !strcmp(digest->qop, "auth-int")) {
yading@11 193 update_md5_strings(md5ctx, ":", nc, ":", cnonce, ":", digest->qop, NULL);
yading@11 194 }
yading@11 195 update_md5_strings(md5ctx, ":", A2hash, NULL);
yading@11 196 av_md5_final(md5ctx, hash);
yading@11 197 ff_data_to_hex(response, hash, 16, 1);
yading@11 198 response[32] = 0;
yading@11 199
yading@11 200 av_free(md5ctx);
yading@11 201
yading@11 202 if (!strcmp(digest->qop, "") || !strcmp(digest->qop, "auth")) {
yading@11 203 } else if (!strcmp(digest->qop, "auth-int")) {
yading@11 204 /* qop=auth-int not supported */
yading@11 205 return NULL;
yading@11 206 } else {
yading@11 207 /* Unsupported qop value. */
yading@11 208 return NULL;
yading@11 209 }
yading@11 210
yading@11 211 len = strlen(username) + strlen(state->realm) + strlen(digest->nonce) +
yading@11 212 strlen(uri) + strlen(response) + strlen(digest->algorithm) +
yading@11 213 strlen(digest->opaque) + strlen(digest->qop) + strlen(cnonce) +
yading@11 214 strlen(nc) + 150;
yading@11 215
yading@11 216 authstr = av_malloc(len);
yading@11 217 if (!authstr)
yading@11 218 return NULL;
yading@11 219 snprintf(authstr, len, "Authorization: Digest ");
yading@11 220
yading@11 221 /* TODO: Escape the quoted strings properly. */
yading@11 222 av_strlcatf(authstr, len, "username=\"%s\"", username);
yading@11 223 av_strlcatf(authstr, len, ",realm=\"%s\"", state->realm);
yading@11 224 av_strlcatf(authstr, len, ",nonce=\"%s\"", digest->nonce);
yading@11 225 av_strlcatf(authstr, len, ",uri=\"%s\"", uri);
yading@11 226 av_strlcatf(authstr, len, ",response=\"%s\"", response);
yading@11 227 if (digest->algorithm[0])
yading@11 228 av_strlcatf(authstr, len, ",algorithm=%s", digest->algorithm);
yading@11 229 if (digest->opaque[0])
yading@11 230 av_strlcatf(authstr, len, ",opaque=\"%s\"", digest->opaque);
yading@11 231 if (digest->qop[0]) {
yading@11 232 av_strlcatf(authstr, len, ",qop=\"%s\"", digest->qop);
yading@11 233 av_strlcatf(authstr, len, ",cnonce=\"%s\"", cnonce);
yading@11 234 av_strlcatf(authstr, len, ",nc=%s", nc);
yading@11 235 }
yading@11 236
yading@11 237 av_strlcatf(authstr, len, "\r\n");
yading@11 238
yading@11 239 return authstr;
yading@11 240 }
yading@11 241
yading@11 242 char *ff_http_auth_create_response(HTTPAuthState *state, const char *auth,
yading@11 243 const char *path, const char *method)
yading@11 244 {
yading@11 245 char *authstr = NULL;
yading@11 246
yading@11 247 /* Clear the stale flag, we assume the auth is ok now. It is reset
yading@11 248 * by the server headers if there's a new issue. */
yading@11 249 state->stale = 0;
yading@11 250 if (!auth || !strchr(auth, ':'))
yading@11 251 return NULL;
yading@11 252
yading@11 253 if (state->auth_type == HTTP_AUTH_BASIC) {
yading@11 254 int auth_b64_len, len;
yading@11 255 char *ptr, *decoded_auth = ff_urldecode(auth);
yading@11 256
yading@11 257 if (!decoded_auth)
yading@11 258 return NULL;
yading@11 259
yading@11 260 auth_b64_len = AV_BASE64_SIZE(strlen(decoded_auth));
yading@11 261 len = auth_b64_len + 30;
yading@11 262
yading@11 263 authstr = av_malloc(len);
yading@11 264 if (!authstr) {
yading@11 265 av_free(decoded_auth);
yading@11 266 return NULL;
yading@11 267 }
yading@11 268
yading@11 269 snprintf(authstr, len, "Authorization: Basic ");
yading@11 270 ptr = authstr + strlen(authstr);
yading@11 271 av_base64_encode(ptr, auth_b64_len, decoded_auth, strlen(decoded_auth));
yading@11 272 av_strlcat(ptr, "\r\n", len - (ptr - authstr));
yading@11 273 av_free(decoded_auth);
yading@11 274 } else if (state->auth_type == HTTP_AUTH_DIGEST) {
yading@11 275 char *username = ff_urldecode(auth), *password;
yading@11 276
yading@11 277 if (!username)
yading@11 278 return NULL;
yading@11 279
yading@11 280 if ((password = strchr(username, ':'))) {
yading@11 281 *password++ = 0;
yading@11 282 authstr = make_digest_auth(state, username, password, path, method);
yading@11 283 }
yading@11 284 av_free(username);
yading@11 285 }
yading@11 286 return authstr;
yading@11 287 }