Changeset e6648bf


Ignore:
Timestamp:
2008-02-17T11:16:01Z (12 years ago)
Author:
Wilmer van der Gaast <wilmer@…>
Branches:
master
Children:
9186d15
Parents:
4bbcba3
Message:

Replaced old MSN Passport (v1.4) authentication code with what's described on
http://msnpiki.msnfanatic.com/index.php/MSNP13:SOAPTweener . This was an
attempt to fix bug #360, but it didn't. However, this change may make BitlBee
a little bit more future-proof. Plus, the code is tidier and sometimes faster
than the old mechanism.

Location:
protocols/msn
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • protocols/msn/ns.c

    r4bbcba3 re6648bf  
    3434static int msn_ns_message( gpointer data, char *msg, int msglen, char **cmd, int num_parts );
    3535
    36 static void msn_auth_got_passport_id( struct passport_reply *rep );
     36static void msn_auth_got_passport_token( struct msn_auth_data *mad );
    3737
    3838gboolean msn_ns_connected( gpointer data, gint source, b_input_condition cond )
     
    214214                {
    215215                        /* Time for some Passport black magic... */
    216                         if( !passport_get_id( msn_auth_got_passport_id, ic, ic->acc->user, ic->acc->pass, cmd[4] ) )
     216                        if( !passport_get_token( msn_auth_got_passport_token, ic, ic->acc->user, ic->acc->pass, cmd[4] ) )
    217217                        {
    218218                                imcb_error( ic, "Error while contacting Passport server" );
     
    674674}
    675675
    676 static void msn_auth_got_passport_id( struct passport_reply *rep )
     676static void msn_auth_got_passport_token( struct msn_auth_data *mad )
    677677{
    678         struct im_connection *ic = rep->data;
    679         struct msn_data *md = ic->proto_data;
    680         char *key = rep->result;
    681         char buf[1024];
    682        
    683         if( key == NULL )
    684         {
    685                 imcb_error( ic, "Error during Passport authentication (%s)",
    686                                rep->error_string ? rep->error_string : "Unknown error" );
     678        struct im_connection *ic = mad->data;
     679        struct msn_data *md;
     680       
     681        /* Dead connection? */
     682        if( g_slist_find( msn_connections, ic ) == NULL )
     683                return;
     684       
     685        md = ic->proto_data;
     686        if( mad->token )
     687        {
     688                char buf[1024];
     689               
     690                g_snprintf( buf, sizeof( buf ), "USR %d TWN S %s\r\n", ++md->trId, mad->token );
     691                msn_write( ic, buf, strlen( buf ) );
     692        }
     693        else
     694        {
     695                imcb_error( ic, "Error during Passport authentication: %s", mad->error );
    687696                imc_logout( ic, TRUE );
    688697        }
    689         else
    690         {
    691                 g_snprintf( buf, sizeof( buf ), "USR %d TWN S %s\r\n", ++md->trId, key );
    692                 msn_write( ic, buf, strlen( buf ) );
    693         }
    694698}
  • protocols/msn/passport.c

    r4bbcba3 re6648bf  
    1 /* passport.c
     1/** passport.c
    22 *
    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>
     3 * Functions to login to Microsoft Passport service for Messenger
     4 * Copyright (C) 2004-2008 Wilmer van der Gaast <wilmer@gaast.net>
    65 *
    76 * This program is free software; you can redistribute it and/or modify             
     
    2423#include "msn.h"
    2524#include "bitlbee.h"
     25#include "url.h"
     26#include "misc.h"
     27#include "xmltree.h"
    2628#include <ctype.h>
    2729#include <errno.h>
    2830
    29 #define MSN_BUF_LEN 8192
     31static int passport_get_token_real( struct msn_auth_data *mad );
     32static void passport_get_token_ready( struct http_request *req );
    3033
    31 static char *prd_cached = NULL;
    32 
    33 static int passport_get_id_real( gpointer func, gpointer data, char *header );
    34 static void passport_get_id_ready( struct http_request *req );
    35 
    36 static int passport_retrieve_dalogin( gpointer data, gpointer func, char *header );
    37 static void passport_retrieve_dalogin_ready( struct http_request *req );
    38 
    39 static char *passport_create_header( char *cookie, char *email, char *pwd );
    40 static void destroy_reply( struct passport_reply *rep );
    41 
    42 int passport_get_id( gpointer func, gpointer data, char *username, char *password, char *cookie )
     34int passport_get_token( gpointer func, gpointer data, char *username, char *password, char *cookie )
    4335{
    44         char *header = passport_create_header( cookie, username, password );
     36        struct msn_auth_data *mad = g_new0( struct msn_auth_data, 1 );
     37        int i;
    4538       
    46         if( prd_cached == NULL )
    47                 return passport_retrieve_dalogin( func, data, header );
    48         else
    49                 return passport_get_id_real( func, data, header );
     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        return passport_get_token_real( mad );
    5056}
    5157
    52 static int passport_get_id_real( gpointer func, gpointer data, char *header )
     58static int passport_get_token_real( struct msn_auth_data *mad )
    5359{
    54         struct passport_reply *rep;
    55         char *server, *dummy, *reqs;
     60        char *post_payload, *post_request;
    5661        struct http_request *req;
     62        url_t url;
    5763       
    58         rep = g_new0( struct passport_reply, 1 );
    59         rep->data = data;
    60         rep->func = func;
    61         rep->header = header;
     64        url_set( &url, mad->url );
    6265       
    63         server = g_strdup( prd_cached );
    64         dummy = strchr( server, '/' );
     66        post_payload = g_markup_printf_escaped( SOAP_AUTHENTICATION_PAYLOAD,
     67                                                mad->username,
     68                                                mad->password,
     69                                                mad->cookie );
    6570       
    66         if( dummy == NULL )
    67         {
    68                 destroy_reply( rep );
    69                 return( 0 );
    70         }
     71        post_request = g_strdup_printf( SOAP_AUTHENTICATION_REQUEST,
     72                                        url.file, url.host,
     73                                        (int) strlen( post_payload ),
     74                                        post_payload );
     75                                       
     76        req = http_dorequest( url.host, url.port, 1, post_request,
     77                              passport_get_token_ready, mad );
    7178       
    72         reqs = g_strdup_printf( "GET %s HTTP/1.0\r\n%s\r\n\r\n", dummy, header );
     79        g_free( post_request );
     80        g_free( post_payload );
    7381       
    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 );
     82        return req != NULL;
    8483}
    8584
    86 static void passport_get_id_ready( struct http_request *req )
     85static xt_status passport_xt_extract_token( struct xt_node *node, gpointer data );
     86static xt_status passport_xt_handle_fault( struct xt_node *node, gpointer data );
     87
     88static const struct xt_handler_entry passport_xt_handlers[] = {
     89        { "wsse:BinarySecurityToken", "wst:RequestedSecurityToken", passport_xt_extract_token },
     90        { "S:Fault",                  "S:Envelope",                 passport_xt_handle_fault  },
     91        { NULL,                       NULL,                         NULL                      }
     92};
     93
     94static void passport_get_token_ready( struct http_request *req )
    8795{
    88         struct passport_reply *rep = req->data;
     96        struct msn_auth_data *mad = req->data;
     97        struct xt_parser *parser;
    8998       
    90         if( !g_slist_find( msn_connections, rep->data ) )
     99        g_free( mad->url );
     100        g_free( mad->error );
     101        mad->url = mad->error = NULL;
     102       
     103        if( req->status_code == 200 )
    91104        {
    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                 }
     105                parser = xt_new( passport_xt_handlers, mad );
     106                xt_feed( parser, req->reply_body, req->body_size );
     107                xt_handle( parser, NULL, -1 );
     108                xt_free( parser );
    115109        }
    116110        else
    117111        {
    118                 rep->error_string = g_strdup_printf( "HTTP error: %s",
    119                                       req->status_string ? req->status_string : "Unknown error" );
     112                mad->error = g_strdup_printf( "HTTP error %d (%s)", req->status_code,
     113                                              req->status_string ? req->status_string : "unknown" );
    120114        }
    121115       
    122         rep->func( rep );
    123         destroy_reply( rep );
     116        if( mad->error == NULL && mad->token == NULL )
     117                mad->error = g_strdup( "Could not parse Passport server response" );
     118       
     119        if( mad->url && mad->token == NULL )
     120        {
     121                passport_get_token_real( mad );
     122        }
     123        else
     124        {
     125                mad->callback( mad );
     126               
     127                g_free( mad->url );
     128                g_free( mad->username );
     129                g_free( mad->password );
     130                g_free( mad->cookie );
     131                g_free( mad->token );
     132                g_free( mad->error );
     133                g_free( mad );
     134        }
    124135}
    125136
    126 static char *passport_create_header( char *cookie, char *email, char *pwd )
     137static xt_status passport_xt_extract_token( struct xt_node *node, gpointer data )
    127138{
    128         char *buffer;
    129         char *currenttoken;
    130         char *email_enc, *pwd_enc;
     139        struct msn_auth_data *mad = data;
     140        char *s;
    131141       
    132         currenttoken = strstr( cookie, "lc=" );
    133         if( currenttoken == NULL )
    134                 return NULL;
     142        if( ( s = xt_find_attr( node, "Id" ) ) && strcmp( s, "PPToken1" ) == 0 )
     143                mad->token = g_memdup( node->text, node->text_len + 1 );
    135144       
    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         strcpy( pwd_enc, pwd );
    142         http_encode( pwd_enc );
    143        
    144         buffer = g_strdup_printf( "Authorization: Passport1.4 OrgVerb=GET,"
    145                                   "OrgURL=http%%3A%%2F%%2Fmessenger%%2Emsn%%2Ecom,"
    146                                   "sign-in=%s,pwd=%s,%s", email_enc, pwd_enc,
    147                                   currenttoken );
    148        
    149         g_free( email_enc );
    150         g_free( pwd_enc );
    151        
    152         return buffer;
     145        return XT_HANDLED;
    153146}
    154147
    155 static int passport_retrieve_dalogin( gpointer func, gpointer data, char *header )
     148static xt_status passport_xt_handle_fault( struct xt_node *node, gpointer data )
    156149{
    157         struct passport_reply *rep = g_new0( struct passport_reply, 1 );
    158         struct http_request *req;
     150        struct msn_auth_data *mad = data;
     151        struct xt_node *code = xt_find_node( node->children, "faultcode" );
     152        struct xt_node *string = xt_find_node( node->children, "faultstring" );
     153        struct xt_node *redirect = xt_find_node( node->children, "psf:redirectUrl" );
    159154       
    160         rep->data = data;
    161         rep->func = func;
    162         rep->header = header;
     155        if( redirect && redirect->text_len && mad->ttl-- > 0 )
     156                mad->url = g_memdup( redirect->text, redirect->text_len + 1 );
    163157       
    164         req = http_dorequest_url( "https://nexus.passport.com/rdr/pprdr.asp", passport_retrieve_dalogin_ready, rep );
     158        if( code == NULL || code->text_len == 0 )
     159                mad->error = g_strdup( "Unknown error" );
     160        else
     161                mad->error = g_strdup_printf( "%s (%s)", code->text, string && string->text_len ?
     162                                              string->text : "no description available" );
    165163       
    166         if( !req )
    167                 destroy_reply( rep );
    168        
    169         return( req != NULL );
     164        return XT_HANDLED;
    170165}
    171 
    172 static void passport_retrieve_dalogin_ready( struct http_request *req )
    173 {
    174         struct passport_reply *rep = req->data;
    175         char *dalogin;
    176         char *urlend;
    177        
    178         if( !g_slist_find( msn_connections, rep->data ) )
    179         {
    180                 destroy_reply( rep );
    181                 return;
    182         }
    183        
    184         if( !req->finished || !req->reply_headers || req->status_code != 200 )
    185         {
    186                 rep->error_string = g_strdup_printf( "HTTP error while fetching DALogin: %s",
    187                                         req->status_string ? req->status_string : "Unknown error" );
    188                 goto failure;
    189         }
    190        
    191         dalogin = strstr( req->reply_headers, "DALogin=" );     
    192        
    193         if( !dalogin )
    194         {
    195                 rep->error_string = g_strdup( "Parse error while fetching DALogin" );
    196                 goto failure;
    197         }
    198        
    199         dalogin += strlen( "DALogin=" );
    200         urlend = strchr( dalogin, ',' );
    201         if( urlend )
    202                 *urlend = 0;
    203        
    204         /* strip the http(s):// part from the url */
    205         urlend = strstr( urlend, "://" );
    206         if( urlend )
    207                 dalogin = urlend + strlen( "://" );
    208        
    209         if( prd_cached == NULL )
    210                 prd_cached = g_strdup( dalogin );
    211        
    212         if( passport_get_id_real( rep->func, rep->data, rep->header ) )
    213         {
    214                 rep->header = NULL;
    215                 destroy_reply( rep );
    216                 return;
    217         }
    218        
    219 failure:       
    220         rep->func( rep );
    221         destroy_reply( rep );
    222 }
    223 
    224 static void destroy_reply( struct passport_reply *rep )
    225 {
    226         g_free( rep->result );
    227         g_free( rep->header );
    228         g_free( rep->error_string );
    229         g_free( rep );
    230 }
  • protocols/msn/passport.h

    r4bbcba3 re6648bf  
    1 #ifndef __PASSPORT_H__
    2 #define __PASSPORT_H__
    31/* passport.h
    42 *
    5  * Functions to login to Microsoft Passport Service for Messenger
    6  * Copyright (C) 2004 Wouter Paesen <wouter@blue-gate.be>,
    7  *                    Wilmer van der Gaast <wilmer@gaast.net>
     3 * Functions to login to Microsoft Passport service for Messenger
     4 * Copyright (C) 2004-2008 Wilmer van der Gaast <wilmer@gaast.net>
    85 *
    96 * This program is free software; you can redistribute it and/or modify             
     
    1815 * You should have received a copy of the GNU General Public License               
    1916 * along with this program; if not, write to the Free Software                     
    20  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA         
     17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA         
    2118 */
     19
     20/* Thanks to http://msnpiki.msnfanatic.com/index.php/MSNP13:SOAPTweener
     21   for the specs! */
     22
     23#ifndef __PASSPORT_H__
     24#define __PASSPORT_H__
    2225
    2326#include <stdio.h>
     
    3336#include "nogaim.h"
    3437
    35 struct passport_reply
     38struct msn_auth_data
    3639{
    37         void (*func)( struct passport_reply * );
    38         void *data;
    39         char *result;
    40         char *header;
    41         char *error_string;
     40        char *url;
     41        int ttl;
     42       
     43        char *username;
     44        char *password;
     45        char *cookie;
     46       
     47        /* The end result, the only thing we'll really be interested in
     48           once finished. */
     49        char *token;
     50        char *error; /* Yeah, or that... */
     51       
     52        void (*callback)( struct msn_auth_data *mad );
     53        gpointer data;
    4254};
    4355
    44 int passport_get_id( gpointer func, gpointer data, char *username, char *password, char *cookie );
     56#define SOAP_AUTHENTICATION_URL "https://loginnet.passport.com/RST.srf"
     57
     58#define SOAP_AUTHENTICATION_REQUEST \
     59"POST %s HTTP/1.0\r\n" \
     60"Accept: text/*\r\n" \
     61"User-Agent: BitlBee " BITLBEE_VERSION "\r\n" \
     62"Host: %s\r\n" \
     63"Content-Length: %d\r\n" \
     64"Cache-Control: no-cache\r\n" \
     65"\r\n" \
     66"%s"
     67
     68#define SOAP_AUTHENTICATION_PAYLOAD \
     69"<?xml version=\"1.0\" encoding=\"UTF-8\"?>" \
     70"<Envelope xmlns=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:wsse=\"http://schemas.xmlsoap.org/ws/2003/06/secext\" xmlns:saml=\"urn:oasis:names:tc:SAML:1.0:assertion\" xmlns:wsp=\"http://schemas.xmlsoap.org/ws/2002/12/policy\" xmlns:wsu=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd\" xmlns:wsa=\"http://schemas.xmlsoap.org/ws/2004/03/addressing\" xmlns:wssc=\"http://schemas.xmlsoap.org/ws/2004/04/sc\" xmlns:wst=\"http://schemas.xmlsoap.org/ws/2004/04/trust\">" \
     71  "<Header>" \
     72    "<ps:AuthInfo xmlns:ps=\"http://schemas.microsoft.com/Passport/SoapServices/PPCRL\" Id=\"PPAuthInfo\">" \
     73      "<ps:HostingApp>{7108E71A-9926-4FCB-BCC9-9A9D3F32E423}</ps:HostingApp>" \
     74      "<ps:BinaryVersion>4</ps:BinaryVersion>" \
     75      "<ps:UIVersion>1</ps:UIVersion>" \
     76      "<ps:Cookies></ps:Cookies>" \
     77      "<ps:RequestParams>AQAAAAIAAABsYwQAAAAzMDg0</ps:RequestParams>" \
     78    "</ps:AuthInfo>" \
     79    "<wsse:Security>" \
     80       "<wsse:UsernameToken Id=\"user\">" \
     81         "<wsse:Username>%s</wsse:Username>" \
     82         "<wsse:Password>%s</wsse:Password>" \
     83       "</wsse:UsernameToken>" \
     84    "</wsse:Security>" \
     85  "</Header>" \
     86  "<Body>" \
     87    "<ps:RequestMultipleSecurityTokens xmlns:ps=\"http://schemas.microsoft.com/Passport/SoapServices/PPCRL\" Id=\"RSTS\">" \
     88      "<wst:RequestSecurityToken Id=\"RST0\">" \
     89        "<wst:RequestType>http://schemas.xmlsoap.org/ws/2004/04/security/trust/Issue</wst:RequestType>" \
     90        "<wsp:AppliesTo>" \
     91          "<wsa:EndpointReference>" \
     92            "<wsa:Address>http://Passport.NET/tb</wsa:Address>" \
     93          "</wsa:EndpointReference>" \
     94        "</wsp:AppliesTo>" \
     95      "</wst:RequestSecurityToken>" \
     96      "<wst:RequestSecurityToken Id=\"RST1\">" \
     97       "<wst:RequestType>http://schemas.xmlsoap.org/ws/2004/04/security/trust/Issue</wst:RequestType>" \
     98        "<wsp:AppliesTo>" \
     99          "<wsa:EndpointReference>" \
     100            "<wsa:Address>messenger.msn.com</wsa:Address>" \
     101          "</wsa:EndpointReference>" \
     102        "</wsp:AppliesTo>" \
     103        "<wsse:PolicyReference URI=\"?%s\"></wsse:PolicyReference>" \
     104      "</wst:RequestSecurityToken>" \
     105    "</ps:RequestMultipleSecurityTokens>" \
     106  "</Body>" \
     107"</Envelope>"
     108
     109int passport_get_token( gpointer func, gpointer data, char *username, char *password, char *cookie );
    45110
    46111#endif /* __PASSPORT_H__ */
Note: See TracChangeset for help on using the changeset viewer.