LCOV - code coverage report
Current view: top level - libavformat - httpauth.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 165 0.0 %
Date: 2017-12-15 02:19:58 Functions: 0 8 0.0 %

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

Generated by: LCOV version 1.13