Changeset d84e2a9


Ignore:
Timestamp:
2008-08-02T11:21:36Z (11 years ago)
Author:
Wilmer van der Gaast <wilmer@…>
Branches:
master
Children:
280e655
Parents:
e0798cc
Message:

Microsoft, I hate you.

Location:
protocols/msn
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • protocols/msn/ns.c

    re0798cc rd84e2a9  
    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 )
     
    222222                {
    223223                        /* Time for some Passport black magic... */
    224                         if( !passport_get_id( msn_auth_got_passport_id, ic, ic->acc->user, ic->acc->pass, cmd[4] ) )
     224                        if( !passport_get_token( msn_auth_got_passport_token, ic, ic->acc->user, ic->acc->pass, cmd[4] ) )
    225225                        {
    226226                                imcb_error( ic, "Error while contacting Passport server" );
     
    709709}
    710710
    711 static void msn_auth_got_passport_id( struct passport_reply *rep )
     711static void msn_auth_got_passport_token( struct msn_auth_data *mad )
    712712{
    713         struct im_connection *ic = rep->data;
    714         struct msn_data *md = ic->proto_data;
    715         char *key = rep->result;
    716         char buf[1024];
    717        
    718         if( key == NULL )
    719         {
    720                 imcb_error( ic, "Error during Passport authentication (%s)",
    721                                rep->error_string ? rep->error_string : "Unknown error" );
     713        struct im_connection *ic = mad->data;
     714        struct msn_data *md;
     715       
     716        /* Dead connection? */
     717        if( g_slist_find( msn_connections, ic ) == NULL )
     718                return;
     719       
     720        md = ic->proto_data;
     721        if( mad->token )
     722        {
     723                char buf[1024];
     724               
     725                g_snprintf( buf, sizeof( buf ), "USR %d TWN S %s\r\n", ++md->trId, mad->token );
     726                msn_write( ic, buf, strlen( buf ) );
     727        }
     728        else
     729        {
     730                imcb_error( ic, "Error during Passport authentication: %s", mad->error );
    722731                imc_logout( ic, TRUE );
    723732        }
    724         else
    725         {
    726                 g_snprintf( buf, sizeof( buf ), "USR %d TWN S %s\r\n", ++md->trId, key );
    727                 msn_write( ic, buf, strlen( buf ) );
    728         }
    729733}
  • protocols/msn/passport.c

    re0798cc rd84e2a9  
    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        /* 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 );
    5061}
    5162
    52 static int passport_get_id_real( gpointer func, gpointer data, char *header )
     63static int passport_get_token_real( struct msn_auth_data *mad )
    5364{
    54         struct passport_reply *rep;
    55         char *server, *dummy, *reqs;
     65        char *post_payload, *post_request;
    5666        struct http_request *req;
     67        url_t url;
    5768       
    58         rep = g_new0( struct passport_reply, 1 );
    59         rep->data = data;
    60         rep->func = func;
    61         rep->header = header;
     69        url_set( &url, mad->url );
    6270       
    63         server = g_strdup( prd_cached );
    64         dummy = strchr( server, '/' );
     71        post_payload = g_markup_printf_escaped( SOAP_AUTHENTICATION_PAYLOAD,
     72                                                mad->username,
     73                                                mad->password,
     74                                                mad->cookie );
    6575       
    66         if( dummy == NULL )
    67         {
    68                 destroy_reply( rep );
    69                 return( 0 );
    70         }
     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 );
    7183       
    72         reqs = g_strdup_printf( "GET %s HTTP/1.0\r\n%s\r\n\r\n", dummy, header );
     84        g_free( post_request );
     85        g_free( post_payload );
    7386       
    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 );
     87        return req != NULL;
    8488}
    8589
    86 static void passport_get_id_ready( struct http_request *req )
     90static xt_status passport_xt_extract_token( struct xt_node *node, gpointer data );
     91static xt_status passport_xt_handle_fault( struct xt_node *node, gpointer data );
     92
     93static 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
     99static void passport_get_token_ready( struct http_request *req )
    87100{
    88         struct passport_reply *rep = req->data;
     101        struct msn_auth_data *mad = req->data;
     102        struct xt_parser *parser;
    89103       
    90         if( !g_slist_find( msn_connections, rep->data ) )
     104        g_free( mad->url );
     105        g_free( mad->error );
     106        mad->url = mad->error = NULL;
     107       
     108        if( req->status_code == 200 )
    91109        {
    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                 }
     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 );
    115114        }
    116115        else
    117116        {
    118                 rep->error_string = g_strdup_printf( "HTTP error: %s",
    119                                       req->status_string ? req->status_string : "Unknown error" );
     117                mad->error = g_strdup_printf( "HTTP error %d (%s)", req->status_code,
     118                                              req->status_string ? req->status_string : "unknown" );
    120119        }
    121120       
    122         rep->func( rep );
    123         destroy_reply( rep );
     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        }
    124140}
    125141
    126 static char *passport_create_header( char *cookie, char *email, char *pwd )
     142static xt_status passport_xt_extract_token( struct xt_node *node, gpointer data )
    127143{
    128         char *buffer;
    129         char *currenttoken;
    130         char *email_enc, *pwd_enc;
     144        struct msn_auth_data *mad = data;
     145        char *s;
    131146       
    132         currenttoken = strstr( cookie, "lc=" );
    133         if( currenttoken == NULL )
    134                 return NULL;
     147        if( ( s = xt_find_attr( node, "Id" ) ) && strcmp( s, "PPToken1" ) == 0 )
     148                mad->token = g_memdup( node->text, node->text_len + 1 );
    135149       
    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;
     150        return XT_HANDLED;
    154151}
    155152
    156 static int passport_retrieve_dalogin( gpointer func, gpointer data, char *header )
     153static xt_status passport_xt_handle_fault( struct xt_node *node, gpointer data )
    157154{
    158         struct passport_reply *rep = g_new0( struct passport_reply, 1 );
    159         struct http_request *req;
     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" );
    160159       
    161         rep->data = data;
    162         rep->func = func;
    163         rep->header = header;
     160        if( redirect && redirect->text_len && mad->ttl-- > 0 )
     161                mad->url = g_memdup( redirect->text, redirect->text_len + 1 );
    164162       
    165         req = http_dorequest_url( "https://nexus.passport.com/rdr/pprdr.asp", passport_retrieve_dalogin_ready, rep );
     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" );
    166168       
    167         if( !req )
    168                 destroy_reply( rep );
    169        
    170         return( req != NULL );
     169        return XT_HANDLED;
    171170}
    172 
    173 static 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        
    220 failure:       
    221         rep->func( rep );
    222         destroy_reply( rep );
    223 }
    224 
    225 static 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 }
  • protocols/msn/passport.h

    re0798cc rd84e2a9  
    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
     38#define MAX_PASSPORT_PWLEN 16
     39
     40struct msn_auth_data
    3641{
    37         void (*func)( struct passport_reply * );
    38         void *data;
    39         char *result;
    40         char *header;
    41         char *error_string;
     42        char *url;
     43        int ttl;
     44       
     45        char *username;
     46        char *password;
     47        char *cookie;
     48       
     49        /* The end result, the only thing we'll really be interested in
     50           once finished. */
     51        char *token;
     52        char *error; /* Yeah, or that... */
     53       
     54        void (*callback)( struct msn_auth_data *mad );
     55        gpointer data;
    4256};
    4357
    44 int passport_get_id( gpointer func, gpointer data, char *username, char *password, char *cookie );
     58#define SOAP_AUTHENTICATION_URL "https://loginnet.passport.com/RST.srf"
     59
     60#define SOAP_AUTHENTICATION_REQUEST \
     61"POST %s HTTP/1.0\r\n" \
     62"Accept: text/*\r\n" \
     63"User-Agent: BitlBee " BITLBEE_VERSION "\r\n" \
     64"Host: %s\r\n" \
     65"Content-Length: %d\r\n" \
     66"Cache-Control: no-cache\r\n" \
     67"\r\n" \
     68"%s"
     69
     70#define SOAP_AUTHENTICATION_PAYLOAD \
     71"<?xml version=\"1.0\" encoding=\"UTF-8\"?>" \
     72"<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\">" \
     73  "<Header>" \
     74    "<ps:AuthInfo xmlns:ps=\"http://schemas.microsoft.com/Passport/SoapServices/PPCRL\" Id=\"PPAuthInfo\">" \
     75      "<ps:HostingApp>{7108E71A-9926-4FCB-BCC9-9A9D3F32E423}</ps:HostingApp>" \
     76      "<ps:BinaryVersion>4</ps:BinaryVersion>" \
     77      "<ps:UIVersion>1</ps:UIVersion>" \
     78      "<ps:Cookies></ps:Cookies>" \
     79      "<ps:RequestParams>AQAAAAIAAABsYwQAAAAzMDg0</ps:RequestParams>" \
     80    "</ps:AuthInfo>" \
     81    "<wsse:Security>" \
     82       "<wsse:UsernameToken Id=\"user\">" \
     83         "<wsse:Username>%s</wsse:Username>" \
     84         "<wsse:Password>%s</wsse:Password>" \
     85       "</wsse:UsernameToken>" \
     86    "</wsse:Security>" \
     87  "</Header>" \
     88  "<Body>" \
     89    "<ps:RequestMultipleSecurityTokens xmlns:ps=\"http://schemas.microsoft.com/Passport/SoapServices/PPCRL\" Id=\"RSTS\">" \
     90      "<wst:RequestSecurityToken Id=\"RST0\">" \
     91        "<wst:RequestType>http://schemas.xmlsoap.org/ws/2004/04/security/trust/Issue</wst:RequestType>" \
     92        "<wsp:AppliesTo>" \
     93          "<wsa:EndpointReference>" \
     94            "<wsa:Address>http://Passport.NET/tb</wsa:Address>" \
     95          "</wsa:EndpointReference>" \
     96        "</wsp:AppliesTo>" \
     97      "</wst:RequestSecurityToken>" \
     98      "<wst:RequestSecurityToken Id=\"RST1\">" \
     99       "<wst:RequestType>http://schemas.xmlsoap.org/ws/2004/04/security/trust/Issue</wst:RequestType>" \
     100        "<wsp:AppliesTo>" \
     101          "<wsa:EndpointReference>" \
     102            "<wsa:Address>messenger.msn.com</wsa:Address>" \
     103          "</wsa:EndpointReference>" \
     104        "</wsp:AppliesTo>" \
     105        "<wsse:PolicyReference URI=\"?%s\"></wsse:PolicyReference>" \
     106      "</wst:RequestSecurityToken>" \
     107    "</ps:RequestMultipleSecurityTokens>" \
     108  "</Body>" \
     109"</Envelope>"
     110
     111int passport_get_token( gpointer func, gpointer data, char *username, char *password, char *cookie );
    45112
    46113#endif /* __PASSPORT_H__ */
Note: See TracChangeset for help on using the changeset viewer.