Check the server's reply upon successful authentication and validate it (just to...
authorAntoine Cellerier <dionoea@videolan.org>
Wed, 9 Apr 2008 20:46:24 +0000 (22:46 +0200)
committerAntoine Cellerier <dionoea@videolan.org>
Wed, 9 Apr 2008 20:46:24 +0000 (22:46 +0200)
modules/access/http.c

index c2d41f6..c8c27dd 100644 (file)
@@ -209,6 +209,8 @@ static void AuthParseHeader( access_t *p_access, const char *psz_header,
                              http_auth_t *p_auth );
 static void AuthReply( access_t *p_acces, const char *psz_prefix,
                        vlc_url_t *p_url, http_auth_t *p_auth );
+static int AuthCheckReply( access_t *p_access, const char *psz_header,
+                           vlc_url_t *p_url, http_auth_t *p_auth );
 static void AuthReset( http_auth_t *p_auth );
 
 /*****************************************************************************
@@ -1360,8 +1362,15 @@ static int Request( access_t *p_access, int64_t i_tell )
         }
         else if( !strcasecmp( psz, "authentication-info" ) )
         {
-            msg_Dbg( p_access, "Authentication info: %s", p );
-            /* FIXME: use */
+            msg_Dbg( p_access, "Authentication Info header: %s", p );
+            if( AuthCheckReply( p_access, p, &p_sys->url, &p_sys->auth ) )
+                goto error;
+        }
+        else if( !strcasecmp( psz, "proxy-authentication-info" ) )
+        {
+            msg_Dbg( p_access, "Proxy Authentication Info header: %s", p );
+            if( AuthCheckReply( p_access, p, &p_sys->proxy, &p_sys->proxy_auth ) )
+                goto error;
         }
 
         free( psz );
@@ -1600,17 +1609,113 @@ static void AuthParseHeader( access_t *p_access, const char *psz_header,
                       psz_header );
     }
 }
-static char *AuthAlgoMD5( const char *psz_data )
+
+static char *AuthDigest( access_t *p_access, vlc_url_t *p_url,
+                         http_auth_t *p_auth, const char *psz_method )
 {
+    (void)p_access;
+    const char *psz_username = p_url->psz_username ?: "";
+    const char *psz_password = p_url->psz_password ?: "";
+
+    char *psz_HA1 = NULL;
+    char *psz_HA2 = NULL;
+    char *psz_response = NULL;
     struct md5_s md5;
-    char *psz_md5;
+
+    /* H(A1) */
+    if( p_auth->psz_HA1 )
+    {
+        psz_HA1 = strdup( p_auth->psz_HA1 );
+        if( !psz_HA1 ) goto error;
+    }
+    else
+    {
+        InitMD5( &md5 );
+        AddMD5( &md5, psz_username, strlen( psz_username ) );
+        AddMD5( &md5, ":", 1 );
+        AddMD5( &md5, p_auth->psz_realm, strlen( p_auth->psz_realm ) );
+        AddMD5( &md5, ":", 1 );
+        AddMD5( &md5, psz_password, strlen( psz_password ) );
+        EndMD5( &md5 );
+
+        psz_HA1 = psz_md5_hash( &md5 );
+        if( !psz_HA1 ) goto error;
+
+        if( p_auth->psz_algorithm
+            && !strcmp( p_auth->psz_algorithm, "MD5-sess" ) )
+        {
+            InitMD5( &md5 );
+            AddMD5( &md5, psz_HA1, 32 );
+            free( psz_HA1 );
+            AddMD5( &md5, ":", 1 );
+            AddMD5( &md5, p_auth->psz_nonce, strlen( p_auth->psz_nonce ) );
+            AddMD5( &md5, ":", 1 );
+            AddMD5( &md5, p_auth->psz_cnonce, strlen( p_auth->psz_cnonce ) );
+            EndMD5( &md5 );
+
+            psz_HA1 = psz_md5_hash( &md5 );
+            if( !psz_HA1 ) goto error;
+            p_auth->psz_HA1 = strdup( psz_HA1 );
+            if( !p_auth->psz_HA1 ) goto error;
+        }
+    }
+
+    /* H(A2) */
+    InitMD5( &md5 );
+    if( *psz_method )
+        AddMD5( &md5, psz_method, strlen( psz_method ) );
+    AddMD5( &md5, ":", 1 );
+    if( p_url->psz_path )
+        AddMD5( &md5, p_url->psz_path, strlen( p_url->psz_path ) );
+    else
+        AddMD5( &md5, "/", 1 );
+    if( p_auth->psz_qop && !strcmp( p_auth->psz_qop, "auth-int" ) )
+    {
+        char *psz_ent;
+        struct md5_s ent;
+        InitMD5( &ent );
+        AddMD5( &ent, "", 0 ); /* XXX: entity-body. should be ok for GET */
+        EndMD5( &ent );
+        psz_ent = psz_md5_hash( &ent );
+        if( !psz_ent ) goto error;
+        AddMD5( &md5, ":", 1 );
+        AddMD5( &md5, psz_ent, 32 );
+        free( psz_ent );
+    }
+    EndMD5( &md5 );
+    psz_HA2 = psz_md5_hash( &md5 );
+    if( !psz_HA2 ) goto error;
+
+    /* Request digest */
     InitMD5( &md5 );
-    AddMD5( &md5, psz_data, strlen( psz_data ) );
+    AddMD5( &md5, psz_HA1, 32 );
+    AddMD5( &md5, ":", 1 );
+    AddMD5( &md5, p_auth->psz_nonce, strlen( p_auth->psz_nonce ) );
+    AddMD5( &md5, ":", 1 );
+    if( p_auth->psz_qop
+        && ( !strcmp( p_auth->psz_qop, "auth" )
+             || !strcmp( p_auth->psz_qop, "auth-int" ) ) )
+    {
+        char psz_inonce[9];
+        snprintf( psz_inonce, 9, "%08x", p_auth->i_nonce );
+        AddMD5( &md5, psz_inonce, 8 );
+        AddMD5( &md5, ":", 1 );
+        AddMD5( &md5, p_auth->psz_cnonce, strlen( p_auth->psz_cnonce ) );
+        AddMD5( &md5, ":", 1 );
+        AddMD5( &md5, p_auth->psz_qop, strlen( p_auth->psz_qop ) );
+        AddMD5( &md5, ":", 1 );
+    }
+    AddMD5( &md5, psz_HA2, 32 );
     EndMD5( &md5 );
-    psz_md5 = psz_md5_hash( &md5 );
-    return psz_md5;
+    psz_response = psz_md5_hash( &md5 );
+
+    error:
+        free( psz_HA1 );
+        free( psz_HA2 );
+        return psz_response;
 }
 
+
 static void AuthReply( access_t *p_access, const char *psz_prefix,
                        vlc_url_t *p_url, http_auth_t *p_auth )
 {
@@ -1623,10 +1728,7 @@ static void AuthReply( access_t *p_access, const char *psz_prefix,
     if( p_auth->psz_nonce )
     {
         /* Digest Access Authentication */
-        char *psz_HA1 = NULL;
-        char *psz_HA2 = NULL;
-        char *psz_response = NULL;
-        struct md5_s md5;
+        char *psz_response;
 
         if(    p_auth->psz_algorithm
             && strcmp( p_auth->psz_algorithm, "MD5" )
@@ -1646,92 +1748,8 @@ static void AuthReply( access_t *p_access, const char *psz_prefix,
         }
         p_auth->i_nonce ++;
 
-        /* H(A1) */
-        if( p_auth->psz_HA1 )
-        {
-            psz_HA1 = strdup( p_auth->psz_HA1 );
-            if( !psz_HA1 ) goto error;
-        }
-        else
-        {
-            InitMD5( &md5 );
-            AddMD5( &md5, psz_username, strlen( psz_username ) );
-            AddMD5( &md5, ":", 1 );
-            AddMD5( &md5, p_auth->psz_realm, strlen( p_auth->psz_realm ) );
-            AddMD5( &md5, ":", 1 );
-            AddMD5( &md5, psz_password, strlen( psz_password ) );
-            EndMD5( &md5 );
-
-            psz_HA1 = psz_md5_hash( &md5 );
-            if( !psz_HA1 ) goto error;
-
-            if( p_auth->psz_algorithm
-                && !strcmp( p_auth->psz_algorithm, "MD5-sess" ) )
-            {
-                InitMD5( &md5 );
-                AddMD5( &md5, psz_HA1, 32 );
-                free( psz_HA1 );
-                AddMD5( &md5, ":", 1 );
-                AddMD5( &md5, p_auth->psz_nonce, strlen( p_auth->psz_nonce ) );
-                AddMD5( &md5, ":", 1 );
-                AddMD5( &md5, p_auth->psz_cnonce, strlen( p_auth->psz_cnonce ) );
-                EndMD5( &md5 );
-
-                psz_HA1 = psz_md5_hash( &md5 );
-                if( !psz_HA1 ) goto error;
-                p_auth->psz_HA1 = strdup( psz_HA1 );
-                if( !p_auth->psz_HA1 ) goto error;
-            }
-        }
-
-        /* H(A2) */
-        InitMD5( &md5 );
-        AddMD5( &md5, "GET", 3 ); /* FIXME ? */
-        AddMD5( &md5, ":", 1 );
-        if( p_url->psz_path )
-            AddMD5( &md5, p_url->psz_path, strlen( p_url->psz_path ) );
-        else
-            AddMD5( &md5, "/", 1 );
-        if( p_auth->psz_qop && !strcmp( p_auth->psz_qop, "auth-int" ) )
-        {
-            char *psz_ent;
-            struct md5_s ent;
-            InitMD5( &ent );
-            AddMD5( &ent, "", 0 ); /* XXX: entity-body. should be ok for GET */
-            EndMD5( &ent );
-            psz_ent = psz_md5_hash( &ent );
-            if( !psz_ent ) goto error;
-            AddMD5( &md5, ":", 1 );
-            AddMD5( &md5, psz_ent, 32 );
-            free( psz_ent );
-        }
-        EndMD5( &md5 );
-        psz_HA2 = psz_md5_hash( &md5 );
-        if( !psz_HA2 ) goto error;
-
-        /* Request digest */
-        InitMD5( &md5 );
-        AddMD5( &md5, psz_HA1, 32 );
-        AddMD5( &md5, ":", 1 );
-        AddMD5( &md5, p_auth->psz_nonce, strlen( p_auth->psz_nonce ) );
-        AddMD5( &md5, ":", 1 );
-        if( p_auth->psz_qop
-            && ( !strcmp( p_auth->psz_qop, "auth" )
-                 || !strcmp( p_auth->psz_qop, "auth-int" ) ) )
-        {
-            char psz_inonce[9];
-            snprintf( psz_inonce, 9, "%08x", p_auth->i_nonce );
-            AddMD5( &md5, psz_inonce, 8 );
-            AddMD5( &md5, ":", 1 );
-            AddMD5( &md5, p_auth->psz_cnonce, strlen( p_auth->psz_cnonce ) );
-            AddMD5( &md5, ":", 1 );
-            AddMD5( &md5, p_auth->psz_qop, strlen( p_auth->psz_qop ) );
-            AddMD5( &md5, ":", 1 );
-        }
-        AddMD5( &md5, psz_HA2, 32 );
-        EndMD5( &md5 );
-        psz_response = psz_md5_hash( &md5 );
-        if( !psz_response ) goto error;
+        psz_response = AuthDigest( p_access, p_url, p_auth, "GET" );
+        if( !psz_response ) return;
 
         net_Printf( VLC_OBJECT(p_access), p_sys->fd, pvs,
                     "%sAuthorization: Digest "
@@ -1773,10 +1791,6 @@ static void AuthReply( access_t *p_access, const char *psz_prefix,
                     p_auth->i_nonce ? "\"" : "\""
                   );
 
-
-    error:
-        free( psz_HA1 );
-        free( psz_HA2 );
         free( psz_response );
     }
     else
@@ -1797,6 +1811,69 @@ static void AuthReply( access_t *p_access, const char *psz_prefix,
     }
 }
 
+static int AuthCheckReply( access_t *p_access, const char *psz_header,
+                           vlc_url_t *p_url, http_auth_t *p_auth )
+{
+    int i_ret = VLC_EGENERIC;
+    char *psz_nextnonce = AuthGetParam( psz_header, "nextnonce" );
+    char *psz_qop = AuthGetParamNoQuotes( psz_header, "qop" );
+    char *psz_rspauth = AuthGetParam( psz_header, "rspauth" );
+    char *psz_cnonce = AuthGetParam( psz_header, "cnonce" );
+    char *psz_nc = AuthGetParamNoQuotes( psz_header, "nc" );
+
+    if( psz_cnonce )
+    {
+        char *psz_digest;
+
+        if( strcmp( psz_cnonce, p_auth->psz_cnonce ) )
+        {
+            msg_Err( p_access, "HTTP Digest Access Authentication: server replied with a different client nonce value." );
+            goto error;
+        }
+
+        if( psz_nc )
+        {
+            int i_nonce;
+            i_nonce = strtol( psz_nc, NULL, 16 );
+            if( i_nonce != p_auth->i_nonce )
+            {
+                msg_Err( p_access, "HTTP Digest Access Authentication: server replied with a different nonce count value." );
+                goto error;
+            }
+        }
+
+        if( psz_qop && p_auth->psz_qop && strcmp( psz_qop, p_auth->psz_qop ) )
+            msg_Warn( p_access, "HTTP Digest Access Authentication: server replied using a different 'quality of protection' option" );
+
+        /* All the clear text values match, let's now check the response
+         * digest */
+        psz_digest = AuthDigest( p_access, p_url, p_auth, "" );
+        if( strcmp( psz_digest, psz_rspauth ) )
+        {
+            msg_Err( p_access, "HTTP Digest Access Authentication: server replied with an invalid response digest (expected value: %s).", psz_digest );
+            free( psz_digest );
+            goto error;
+        }
+        free( psz_digest );
+    }
+
+    if( psz_nextnonce )
+    {
+        free( p_auth->psz_nonce );
+        p_auth->psz_nonce = psz_nextnonce;
+        psz_nextnonce = NULL;
+    }
+
+    i_ret = VLC_SUCCESS;
+    error:
+        free( psz_nextnonce );
+        free( psz_qop );
+        free( psz_rspauth );
+        free( psz_cnonce );
+
+    return i_ret;
+}
+
 static void AuthReset( http_auth_t *p_auth )
 {
     FREENULL( p_auth->psz_realm );