Ignore:
Timestamp:
2008-04-02T14:22:57Z (16 years ago)
Author:
Jelmer Vernooij <jelmer@…>
Branches:
master
Children:
f9dbc99
Parents:
875ad42 (diff), dd34575 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

Merge trunk.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • protocols/msn/passport.c

    r875ad42 r85d7b85  
    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;
     69        url_set( &url, mad->url );
    6170       
    62         server = g_strdup( prd_cached );
    63         dummy = strchr( server, '/' );
     71        post_payload = g_markup_printf_escaped( SOAP_AUTHENTICATION_PAYLOAD,
     72                                                mad->username,
     73                                                mad->password,
     74                                                mad->cookie );
    6475       
    65         if( dummy == NULL )
    66         {
    67                 destroy_reply( rep );
    68                 return( 0 );
    69         }
     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 );
    7083       
    71         reqs = g_malloc( strlen( header ) + strlen( dummy ) + 128 );
    72         sprintf( reqs, "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 ) || !req->finished || !req->reply_headers )
    91         {
    92                 destroy_reply( rep );
    93                 return;
    94         }
     104        g_free( mad->url );
     105        g_free( mad->error );
     106        mad->url = mad->error = NULL;
    95107       
    96108        if( req->status_code == 200 )
    97109        {
    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                 }
     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 );
     114        }
     115        else
     116        {
     117                mad->error = g_strdup_printf( "HTTP error %d (%s)", req->status_code,
     118                                              req->status_string ? req->status_string : "unknown" );
    111119        }
    112120       
    113         rep->func( rep );
    114         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        }
    115140}
    116141
    117 static char *passport_create_header( char *cookie, char *email, char *pwd )
     142static xt_status passport_xt_extract_token( struct xt_node *node, gpointer data )
    118143{
    119         char *buffer = g_new0( char, 2048 );
    120         char *currenttoken;
    121         char *email_enc, *pwd_enc;
     144        struct msn_auth_data *mad = data;
     145        char *s;
    122146       
    123         email_enc = g_new0( char, strlen( email ) * 3 + 1 );
    124         strcpy( email_enc, email );
    125         http_encode( email_enc );
     147        if( ( s = xt_find_attr( node, "Id" ) ) && strcmp( s, "PPToken1" ) == 0 )
     148                mad->token = g_memdup( node->text, node->text_len + 1 );
    126149       
    127         pwd_enc = g_new0( char, strlen( pwd ) * 3 + 1 );
    128         strcpy( pwd_enc, pwd );
    129         http_encode( pwd_enc );
    130        
    131         currenttoken = strstr( cookie, "lc=" );
    132         if( currenttoken == NULL )
    133                 return( NULL );
    134        
    135         g_snprintf( buffer, 2048,
    136                     "Authorization: Passport1.4 OrgVerb=GET,"
    137                     "OrgURL=http%%3A%%2F%%2Fmessenger%%2Emsn%%2Ecom,"
    138                     "sign-in=%s,pwd=%s,%s", email_enc, pwd_enc,
    139                     currenttoken );
    140        
    141         g_free( email_enc );
    142         g_free( pwd_enc );
    143        
    144         return( buffer );
     150        return XT_HANDLED;
    145151}
    146152
    147 #define PPR_REQUEST "GET /rdr/pprdr.asp HTTP/1.0\r\n\r\n"
    148 static int passport_retrieve_dalogin( gpointer func, gpointer data, char *header )
     153static xt_status passport_xt_handle_fault( struct xt_node *node, gpointer data )
    149154{
    150         struct passport_reply *rep = g_new0( struct passport_reply, 1 );
    151         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" );
    152159       
    153         rep->data = data;
    154         rep->func = func;
    155         rep->header = header;
     160        if( redirect && redirect->text_len && mad->ttl-- > 0 )
     161                mad->url = g_memdup( redirect->text, redirect->text_len + 1 );
    156162       
    157         req = http_dorequest( "nexus.passport.com", 443, 1, PPR_REQUEST, 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" );
    158168       
    159         if( !req )
    160                 destroy_reply( rep );
    161        
    162         return( req != NULL );
     169        return XT_HANDLED;
    163170}
    164 
    165 static void passport_retrieve_dalogin_ready( struct http_request *req )
    166 {
    167         struct passport_reply *rep = req->data;
    168         char *dalogin;
    169         char *urlend;
    170        
    171         if( !g_slist_find( msn_connections, rep->data ) || !req->finished || !req->reply_headers )
    172         {
    173                 destroy_reply( rep );
    174                 return;
    175         }
    176        
    177         dalogin = strstr( req->reply_headers, "DALogin=" );     
    178        
    179         if( !dalogin )
    180                 goto failure;
    181        
    182         dalogin += strlen( "DALogin=" );
    183         urlend = strchr( dalogin, ',' );
    184         if( urlend )
    185                 *urlend = 0;
    186        
    187         /* strip the http(s):// part from the url */
    188         urlend = strstr( urlend, "://" );
    189         if( urlend )
    190                 dalogin = urlend + strlen( "://" );
    191        
    192         if( prd_cached == NULL )
    193                 prd_cached = g_strdup( dalogin );
    194        
    195         if( passport_get_id_real( rep->func, rep->data, rep->header ) )
    196         {
    197                 destroy_reply( rep );
    198                 return;
    199         }
    200        
    201 failure:       
    202         rep->func( rep );
    203         destroy_reply( rep );
    204 }
    205 
    206 static void destroy_reply( struct passport_reply *rep )
    207 {
    208         g_free( rep->result );
    209         g_free( rep->header );
    210         g_free( rep );
    211 }
Note: See TracChangeset for help on using the changeset viewer.