00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "httpauth.h"
00023 #include "libavutil/base64.h"
00024 #include "libavutil/avstring.h"
00025 #include "internal.h"
00026 #include "libavutil/random_seed.h"
00027 #include "libavutil/md5.h"
00028 #include "urldecode.h"
00029 #include "avformat.h"
00030 #include <ctype.h>
00031
00032 static void handle_basic_params(HTTPAuthState *state, const char *key,
00033 int key_len, char **dest, int *dest_len)
00034 {
00035 if (!strncmp(key, "realm=", key_len)) {
00036 *dest = state->realm;
00037 *dest_len = sizeof(state->realm);
00038 }
00039 }
00040
00041 static void handle_digest_params(HTTPAuthState *state, const char *key,
00042 int key_len, char **dest, int *dest_len)
00043 {
00044 DigestParams *digest = &state->digest_params;
00045
00046 if (!strncmp(key, "realm=", key_len)) {
00047 *dest = state->realm;
00048 *dest_len = sizeof(state->realm);
00049 } else if (!strncmp(key, "nonce=", key_len)) {
00050 *dest = digest->nonce;
00051 *dest_len = sizeof(digest->nonce);
00052 } else if (!strncmp(key, "opaque=", key_len)) {
00053 *dest = digest->opaque;
00054 *dest_len = sizeof(digest->opaque);
00055 } else if (!strncmp(key, "algorithm=", key_len)) {
00056 *dest = digest->algorithm;
00057 *dest_len = sizeof(digest->algorithm);
00058 } else if (!strncmp(key, "qop=", key_len)) {
00059 *dest = digest->qop;
00060 *dest_len = sizeof(digest->qop);
00061 } else if (!strncmp(key, "stale=", key_len)) {
00062 *dest = digest->stale;
00063 *dest_len = sizeof(digest->stale);
00064 }
00065 }
00066
00067 static void handle_digest_update(HTTPAuthState *state, const char *key,
00068 int key_len, char **dest, int *dest_len)
00069 {
00070 DigestParams *digest = &state->digest_params;
00071
00072 if (!strncmp(key, "nextnonce=", key_len)) {
00073 *dest = digest->nonce;
00074 *dest_len = sizeof(digest->nonce);
00075 }
00076 }
00077
00078 static void choose_qop(char *qop, int size)
00079 {
00080 char *ptr = strstr(qop, "auth");
00081 char *end = ptr + strlen("auth");
00082
00083 if (ptr && (!*end || isspace(*end) || *end == ',') &&
00084 (ptr == qop || isspace(ptr[-1]) || ptr[-1] == ',')) {
00085 av_strlcpy(qop, "auth", size);
00086 } else {
00087 qop[0] = 0;
00088 }
00089 }
00090
00091 void ff_http_auth_handle_header(HTTPAuthState *state, const char *key,
00092 const char *value)
00093 {
00094 if (!strcmp(key, "WWW-Authenticate") || !strcmp(key, "Proxy-Authenticate")) {
00095 const char *p;
00096 if (av_stristart(value, "Basic ", &p) &&
00097 state->auth_type <= HTTP_AUTH_BASIC) {
00098 state->auth_type = HTTP_AUTH_BASIC;
00099 state->realm[0] = 0;
00100 state->stale = 0;
00101 ff_parse_key_value(p, (ff_parse_key_val_cb) handle_basic_params,
00102 state);
00103 } else if (av_stristart(value, "Digest ", &p) &&
00104 state->auth_type <= HTTP_AUTH_DIGEST) {
00105 state->auth_type = HTTP_AUTH_DIGEST;
00106 memset(&state->digest_params, 0, sizeof(DigestParams));
00107 state->realm[0] = 0;
00108 state->stale = 0;
00109 ff_parse_key_value(p, (ff_parse_key_val_cb) handle_digest_params,
00110 state);
00111 choose_qop(state->digest_params.qop,
00112 sizeof(state->digest_params.qop));
00113 if (!av_strcasecmp(state->digest_params.stale, "true"))
00114 state->stale = 1;
00115 }
00116 } else if (!strcmp(key, "Authentication-Info")) {
00117 ff_parse_key_value(value, (ff_parse_key_val_cb) handle_digest_update,
00118 state);
00119 }
00120 }
00121
00122
00123 static void update_md5_strings(struct AVMD5 *md5ctx, ...)
00124 {
00125 va_list vl;
00126
00127 va_start(vl, md5ctx);
00128 while (1) {
00129 const char* str = va_arg(vl, const char*);
00130 if (!str)
00131 break;
00132 av_md5_update(md5ctx, str, strlen(str));
00133 }
00134 va_end(vl);
00135 }
00136
00137
00138 static char *make_digest_auth(HTTPAuthState *state, const char *username,
00139 const char *password, const char *uri,
00140 const char *method)
00141 {
00142 DigestParams *digest = &state->digest_params;
00143 int len;
00144 uint32_t cnonce_buf[2];
00145 char cnonce[17];
00146 char nc[9];
00147 int i;
00148 char A1hash[33], A2hash[33], response[33];
00149 struct AVMD5 *md5ctx;
00150 uint8_t hash[16];
00151 char *authstr;
00152
00153 digest->nc++;
00154 snprintf(nc, sizeof(nc), "%08x", digest->nc);
00155
00156
00157 for (i = 0; i < 2; i++)
00158 cnonce_buf[i] = av_get_random_seed();
00159 ff_data_to_hex(cnonce, (const uint8_t*) cnonce_buf, sizeof(cnonce_buf), 1);
00160 cnonce[2*sizeof(cnonce_buf)] = 0;
00161
00162 md5ctx = av_malloc(av_md5_size);
00163 if (!md5ctx)
00164 return NULL;
00165
00166 av_md5_init(md5ctx);
00167 update_md5_strings(md5ctx, username, ":", state->realm, ":", password, NULL);
00168 av_md5_final(md5ctx, hash);
00169 ff_data_to_hex(A1hash, hash, 16, 1);
00170 A1hash[32] = 0;
00171
00172 if (!strcmp(digest->algorithm, "") || !strcmp(digest->algorithm, "MD5")) {
00173 } else if (!strcmp(digest->algorithm, "MD5-sess")) {
00174 av_md5_init(md5ctx);
00175 update_md5_strings(md5ctx, A1hash, ":", digest->nonce, ":", cnonce, NULL);
00176 av_md5_final(md5ctx, hash);
00177 ff_data_to_hex(A1hash, hash, 16, 1);
00178 A1hash[32] = 0;
00179 } else {
00180
00181 av_free(md5ctx);
00182 return NULL;
00183 }
00184
00185 av_md5_init(md5ctx);
00186 update_md5_strings(md5ctx, method, ":", uri, NULL);
00187 av_md5_final(md5ctx, hash);
00188 ff_data_to_hex(A2hash, hash, 16, 1);
00189 A2hash[32] = 0;
00190
00191 av_md5_init(md5ctx);
00192 update_md5_strings(md5ctx, A1hash, ":", digest->nonce, NULL);
00193 if (!strcmp(digest->qop, "auth") || !strcmp(digest->qop, "auth-int")) {
00194 update_md5_strings(md5ctx, ":", nc, ":", cnonce, ":", digest->qop, NULL);
00195 }
00196 update_md5_strings(md5ctx, ":", A2hash, NULL);
00197 av_md5_final(md5ctx, hash);
00198 ff_data_to_hex(response, hash, 16, 1);
00199 response[32] = 0;
00200
00201 av_free(md5ctx);
00202
00203 if (!strcmp(digest->qop, "") || !strcmp(digest->qop, "auth")) {
00204 } else if (!strcmp(digest->qop, "auth-int")) {
00205
00206 return NULL;
00207 } else {
00208
00209 return NULL;
00210 }
00211
00212 len = strlen(username) + strlen(state->realm) + strlen(digest->nonce) +
00213 strlen(uri) + strlen(response) + strlen(digest->algorithm) +
00214 strlen(digest->opaque) + strlen(digest->qop) + strlen(cnonce) +
00215 strlen(nc) + 150;
00216
00217 authstr = av_malloc(len);
00218 if (!authstr)
00219 return NULL;
00220 snprintf(authstr, len, "Authorization: Digest ");
00221
00222
00223 av_strlcatf(authstr, len, "username=\"%s\"", username);
00224 av_strlcatf(authstr, len, ",realm=\"%s\"", state->realm);
00225 av_strlcatf(authstr, len, ",nonce=\"%s\"", digest->nonce);
00226 av_strlcatf(authstr, len, ",uri=\"%s\"", uri);
00227 av_strlcatf(authstr, len, ",response=\"%s\"", response);
00228 if (digest->algorithm[0])
00229 av_strlcatf(authstr, len, ",algorithm=%s", digest->algorithm);
00230 if (digest->opaque[0])
00231 av_strlcatf(authstr, len, ",opaque=\"%s\"", digest->opaque);
00232 if (digest->qop[0]) {
00233 av_strlcatf(authstr, len, ",qop=\"%s\"", digest->qop);
00234 av_strlcatf(authstr, len, ",cnonce=\"%s\"", cnonce);
00235 av_strlcatf(authstr, len, ",nc=%s", nc);
00236 }
00237
00238 av_strlcatf(authstr, len, "\r\n");
00239
00240 return authstr;
00241 }
00242
00243 char *ff_http_auth_create_response(HTTPAuthState *state, const char *auth,
00244 const char *path, const char *method)
00245 {
00246 char *authstr = NULL;
00247
00248
00249
00250 state->stale = 0;
00251 if (!auth || !strchr(auth, ':'))
00252 return NULL;
00253
00254 if (state->auth_type == HTTP_AUTH_BASIC) {
00255 int auth_b64_len, len;
00256 char *ptr, *decoded_auth = ff_urldecode(auth);
00257
00258 if (!decoded_auth)
00259 return NULL;
00260
00261 auth_b64_len = AV_BASE64_SIZE(strlen(decoded_auth));
00262 len = auth_b64_len + 30;
00263
00264 authstr = av_malloc(len);
00265 if (!authstr) {
00266 av_free(decoded_auth);
00267 return NULL;
00268 }
00269
00270 snprintf(authstr, len, "Authorization: Basic ");
00271 ptr = authstr + strlen(authstr);
00272 av_base64_encode(ptr, auth_b64_len, decoded_auth, strlen(decoded_auth));
00273 av_strlcat(ptr, "\r\n", len - (ptr - authstr));
00274 av_free(decoded_auth);
00275 } else if (state->auth_type == HTTP_AUTH_DIGEST) {
00276 char *username = ff_urldecode(auth), *password;
00277
00278 if (!username)
00279 return NULL;
00280
00281 if ((password = strchr(username, ':'))) {
00282 *password++ = 0;
00283 authstr = make_digest_auth(state, username, password, path, method);
00284 }
00285 av_free(username);
00286 }
00287 return authstr;
00288 }