Show
Ignore:
Timestamp:
2008-07-31T20:44:43Z (2 years ago)
Author:
Wilmer van der Gaast <wilmer@…>
branch-nick:
devel
revision id:
wilmer@gaast.net-20080731204443-lvon6xxb8erdw240
Message:

Reverting to the old MSN/Passport authentication mechanism, the new one
is "broken". (Bug #439)

Files:
1 modified

Legend:

Unmodified
Added
Removed
  • devel/protocols/msn/passport.c

    r336 r411  
    1 /** passport.c 
     1/* passport.c 
    22 * 
    3  * Functions to login to Microsoft Passport service for Messenger 
    4  * Copyright (C) 2004-2008 Wilmer van der Gaast <wilmer@gaast.net> 
     3 * Functions to login to microsoft passport service for Messenger 
     4 * Copyright (C) 2004 Wouter Paesen <wouter@blue-gate.be> 
     5 * Copyright (C) 2004 Wilmer van der Gaast <wilmer@gaast.net> 
    56 * 
    67 * This program is free software; you can redistribute it and/or modify              
     
    2324#include "msn.h" 
    2425#include "bitlbee.h" 
    25 #include "url.h" 
    26 #include "misc.h" 
    27 #include "xmltree.h" 
    2826#include <ctype.h> 
    2927#include <errno.h> 
    3028 
    31 static int passport_get_token_real( struct msn_auth_data *mad ); 
    32 static void passport_get_token_ready( struct http_request *req ); 
    33  
    34 int passport_get_token( gpointer func, gpointer data, char *username, char *password, char *cookie ) 
    35 { 
    36         struct msn_auth_data *mad = g_new0( struct msn_auth_data, 1 ); 
    37         int i; 
    38          
    39         mad->username = g_strdup( username ); 
    40         mad->password = g_strdup( password ); 
    41         mad->cookie = g_strdup( cookie ); 
    42          
    43         mad->callback = func; 
    44         mad->data = data; 
    45          
    46         mad->url = g_strdup( SOAP_AUTHENTICATION_URL ); 
    47         mad->ttl = 3; /* Max. # of redirects. */ 
    48          
    49         /* HTTP-escape stuff and s/,/&/ */ 
    50         http_decode( mad->cookie ); 
    51         for( i = 0; mad->cookie[i]; i ++ ) 
    52                 if( mad->cookie[i] == ',' ) 
    53                         mad->cookie[i] = '&'; 
    54          
    55         /* Microsoft doesn't allow password longer than 16 chars and silently 
    56            fails authentication if you give the "full version" of your passwd. */ 
    57         if( strlen( mad->password ) > MAX_PASSPORT_PWLEN ) 
    58                 mad->password[MAX_PASSPORT_PWLEN] = 0; 
    59          
    60         return passport_get_token_real( mad ); 
    61 } 
    62  
    63 static int passport_get_token_real( struct msn_auth_data *mad ) 
    64 { 
    65         char *post_payload, *post_request; 
     29#define MSN_BUF_LEN 8192 
     30 
     31static char *prd_cached = NULL; 
     32 
     33static int passport_get_id_real( gpointer func, gpointer data, char *header ); 
     34static void passport_get_id_ready( struct http_request *req ); 
     35 
     36static int passport_retrieve_dalogin( gpointer data, gpointer func, char *header ); 
     37static void passport_retrieve_dalogin_ready( struct http_request *req ); 
     38 
     39static char *passport_create_header( char *cookie, char *email, char *pwd ); 
     40static void destroy_reply( struct passport_reply *rep ); 
     41 
     42int passport_get_id( gpointer func, gpointer data, char *username, char *password, char *cookie ) 
     43{ 
     44        char *header = passport_create_header( cookie, username, password ); 
     45         
     46        if( prd_cached == NULL ) 
     47                return passport_retrieve_dalogin( func, data, header ); 
     48        else 
     49                return passport_get_id_real( func, data, header ); 
     50} 
     51 
     52static int passport_get_id_real( gpointer func, gpointer data, char *header ) 
     53{ 
     54        struct passport_reply *rep; 
     55        char *server, *dummy, *reqs; 
    6656        struct http_request *req; 
    67         url_t url; 
    68          
    69         url_set( &url, mad->url ); 
    70          
    71         post_payload = g_markup_printf_escaped( SOAP_AUTHENTICATION_PAYLOAD, 
    72                                                 mad->username, 
    73                                                 mad->password, 
    74                                                 mad->cookie ); 
    75          
    76         post_request = g_strdup_printf( SOAP_AUTHENTICATION_REQUEST, 
    77                                         url.file, url.host, 
    78                                         (int) strlen( post_payload ), 
    79                                         post_payload ); 
    80                                          
    81         req = http_dorequest( url.host, url.port, 1, post_request, 
    82                               passport_get_token_ready, mad ); 
    83          
    84         g_free( post_request ); 
    85         g_free( post_payload ); 
    86          
    87         return req != NULL; 
    88 } 
    89  
    90 static xt_status passport_xt_extract_token( struct xt_node *node, gpointer data ); 
    91 static xt_status passport_xt_handle_fault( struct xt_node *node, gpointer data ); 
    92  
    93 static const struct xt_handler_entry passport_xt_handlers[] = { 
    94         { "wsse:BinarySecurityToken", "wst:RequestedSecurityToken", passport_xt_extract_token }, 
    95         { "S:Fault",                  "S:Envelope",                 passport_xt_handle_fault  }, 
    96         { NULL,                       NULL,                         NULL                      } 
    97 }; 
    98  
    99 static void passport_get_token_ready( struct http_request *req ) 
    100 { 
    101         struct msn_auth_data *mad = req->data; 
    102         struct xt_parser *parser; 
    103          
    104         g_free( mad->url ); 
    105         g_free( mad->error ); 
    106         mad->url = mad->error = NULL; 
    107          
    108         if( req->status_code == 200 ) 
    109         { 
    110                 parser = xt_new( passport_xt_handlers, mad ); 
    111                 xt_feed( parser, req->reply_body, req->body_size ); 
    112                 xt_handle( parser, NULL, -1 ); 
    113                 xt_free( parser ); 
     57         
     58        rep = g_new0( struct passport_reply, 1 ); 
     59        rep->data = data; 
     60        rep->func = func; 
     61        rep->header = header; 
     62         
     63        server = g_strdup( prd_cached ); 
     64        dummy = strchr( server, '/' ); 
     65         
     66        if( dummy == NULL ) 
     67        { 
     68                destroy_reply( rep ); 
     69                return( 0 ); 
     70        } 
     71         
     72        reqs = g_strdup_printf( "GET %s HTTP/1.0\r\n%s\r\n\r\n", dummy, header ); 
     73         
     74        *dummy = 0; 
     75        req = http_dorequest( server, 443, 1, reqs, passport_get_id_ready, rep ); 
     76         
     77        g_free( server ); 
     78        g_free( reqs ); 
     79         
     80        if( req == NULL ) 
     81                destroy_reply( rep ); 
     82         
     83        return( req != NULL ); 
     84} 
     85 
     86static void passport_get_id_ready( struct http_request *req ) 
     87{ 
     88        struct passport_reply *rep = req->data; 
     89         
     90        if( !g_slist_find( msn_connections, rep->data ) ) 
     91        { 
     92                destroy_reply( rep ); 
     93                return; 
     94        } 
     95         
     96        if( req->finished && req->reply_headers && req->status_code == 200 ) 
     97        { 
     98                char *dummy; 
     99                 
     100                if( ( dummy = strstr( req->reply_headers, "from-PP='" ) ) ) 
     101                { 
     102                        char *responseend; 
     103                         
     104                        dummy += strlen( "from-PP='" ); 
     105                        responseend = strchr( dummy, '\'' ); 
     106                        if( responseend ) 
     107                                *responseend = 0; 
     108                         
     109                        rep->result = g_strdup( dummy ); 
     110                } 
     111                else 
     112                { 
     113                        rep->error_string = g_strdup( "Could not parse Passport server response" ); 
     114                } 
    114115        } 
    115116        else 
    116117        { 
    117                 mad->error = g_strdup_printf( "HTTP error %d (%s)", req->status_code, 
    118                                               req->status_string ? req->status_string : "unknown" ); 
    119         } 
    120          
    121         if( mad->error == NULL && mad->token == NULL ) 
    122                 mad->error = g_strdup( "Could not parse Passport server response" ); 
    123          
    124         if( mad->url && mad->token == NULL ) 
    125         { 
    126                 passport_get_token_real( mad ); 
    127         } 
    128         else 
    129         { 
    130                 mad->callback( mad ); 
    131                  
    132                 g_free( mad->url ); 
    133                 g_free( mad->username ); 
    134                 g_free( mad->password ); 
    135                 g_free( mad->cookie ); 
    136                 g_free( mad->token ); 
    137                 g_free( mad->error ); 
    138                 g_free( mad ); 
    139         } 
    140 } 
    141  
    142 static xt_status passport_xt_extract_token( struct xt_node *node, gpointer data ) 
    143 { 
    144         struct msn_auth_data *mad = data; 
    145         char *s; 
    146          
    147         if( ( s = xt_find_attr( node, "Id" ) ) && strcmp( s, "PPToken1" ) == 0 ) 
    148                 mad->token = g_memdup( node->text, node->text_len + 1 ); 
    149          
    150         return XT_HANDLED; 
    151 } 
    152  
    153 static xt_status passport_xt_handle_fault( struct xt_node *node, gpointer data ) 
    154 { 
    155         struct msn_auth_data *mad = data; 
    156         struct xt_node *code = xt_find_node( node->children, "faultcode" ); 
    157         struct xt_node *string = xt_find_node( node->children, "faultstring" ); 
    158         struct xt_node *redirect = xt_find_node( node->children, "psf:redirectUrl" ); 
    159          
    160         if( redirect && redirect->text_len && mad->ttl-- > 0 ) 
    161                 mad->url = g_memdup( redirect->text, redirect->text_len + 1 ); 
    162          
    163         if( code == NULL || code->text_len == 0 ) 
    164                 mad->error = g_strdup( "Unknown error" ); 
    165         else 
    166                 mad->error = g_strdup_printf( "%s (%s)", code->text, string && string->text_len ? 
    167                                               string->text : "no description available" ); 
    168          
    169         return XT_HANDLED; 
    170 } 
     118                rep->error_string = g_strdup_printf( "HTTP error: %s", 
     119                                      req->status_string ? req->status_string : "Unknown error" ); 
     120        } 
     121         
     122        rep->func( rep ); 
     123        destroy_reply( rep ); 
     124} 
     125 
     126static char *passport_create_header( char *cookie, char *email, char *pwd ) 
     127{ 
     128        char *buffer; 
     129        char *currenttoken; 
     130        char *email_enc, *pwd_enc; 
     131         
     132        currenttoken = strstr( cookie, "lc=" ); 
     133        if( currenttoken == NULL ) 
     134                return NULL; 
     135         
     136        email_enc = g_new0( char, strlen( email ) * 3 + 1 ); 
     137        strcpy( email_enc, email ); 
     138        http_encode( email_enc ); 
     139         
     140        pwd_enc = g_new0( char, strlen( pwd ) * 3 + 1 ); 
     141        g_snprintf( pwd_enc, 17, "%s", pwd ); /* Passwords >16 chars never succeed. (Bug #360) */ 
     142        strcpy( pwd_enc, pwd ); 
     143        http_encode( pwd_enc ); 
     144         
     145        buffer = g_strdup_printf( "Authorization: Passport1.4 OrgVerb=GET," 
     146                                  "OrgURL=http%%3A%%2F%%2Fmessenger%%2Emsn%%2Ecom," 
     147                                  "sign-in=%s,pwd=%s,%s", email_enc, pwd_enc, 
     148                                  currenttoken ); 
     149         
     150        g_free( email_enc ); 
     151        g_free( pwd_enc ); 
     152         
     153        return buffer; 
     154} 
     155 
     156static int passport_retrieve_dalogin( gpointer func, gpointer data, char *header ) 
     157{ 
     158        struct passport_reply *rep = g_new0( struct passport_reply, 1 ); 
     159        struct http_request *req; 
     160         
     161        rep->data = data; 
     162        rep->func = func; 
     163        rep->header = header; 
     164         
     165        req = http_dorequest_url( "https://nexus.passport.com/rdr/pprdr.asp", passport_retrieve_dalogin_ready, rep ); 
     166         
     167        if( !req ) 
     168                destroy_reply( rep ); 
     169         
     170        return( req != NULL ); 
     171} 
     172 
     173static void passport_retrieve_dalogin_ready( struct http_request *req ) 
     174{ 
     175        struct passport_reply *rep = req->data; 
     176        char *dalogin; 
     177        char *urlend; 
     178         
     179        if( !g_slist_find( msn_connections, rep->data ) ) 
     180        { 
     181                destroy_reply( rep ); 
     182                return; 
     183        } 
     184         
     185        if( !req->finished || !req->reply_headers || req->status_code != 200 ) 
     186        { 
     187                rep->error_string = g_strdup_printf( "HTTP error while fetching DALogin: %s", 
     188                                        req->status_string ? req->status_string : "Unknown error" ); 
     189                goto failure; 
     190        } 
     191         
     192        dalogin = strstr( req->reply_headers, "DALogin=" );      
     193         
     194        if( !dalogin ) 
     195        { 
     196                rep->error_string = g_strdup( "Parse error while fetching DALogin" ); 
     197                goto failure; 
     198        } 
     199         
     200        dalogin += strlen( "DALogin=" ); 
     201        urlend = strchr( dalogin, ',' ); 
     202        if( urlend ) 
     203                *urlend = 0; 
     204         
     205        /* strip the http(s):// part from the url */ 
     206        urlend = strstr( urlend, "://" ); 
     207        if( urlend ) 
     208                dalogin = urlend + strlen( "://" ); 
     209         
     210        if( prd_cached == NULL ) 
     211                prd_cached = g_strdup( dalogin ); 
     212         
     213        if( passport_get_id_real( rep->func, rep->data, rep->header ) ) 
     214        { 
     215                rep->header = NULL; 
     216                destroy_reply( rep ); 
     217                return; 
     218        } 
     219         
     220failure:         
     221        rep->func( rep ); 
     222        destroy_reply( rep ); 
     223} 
     224 
     225static void destroy_reply( struct passport_reply *rep ) 
     226{ 
     227        g_free( rep->result ); 
     228        g_free( rep->header ); 
     229        g_free( rep->error_string ); 
     230        g_free( rep ); 
     231}