source: protocols/msn/passport.c @ e907683

Last change on this file since e907683 was f8ec890, checked in by Wilmer van der Gaast <wilmer@…>, at 2010-05-15T00:20:33Z

Passport 3.0 authentication turns out to be slightly different from what
the msnpiki MSNP13 doc says and stuff is breaking now. This should fix
the main problem now.

  • Property mode set to 100644
File size: 5.7 KB
Line 
1/** passport.c
2 *
3 * Functions to login to Microsoft Passport service for Messenger
4 * Copyright (C) 2004-2008 Wilmer van der Gaast <wilmer@gaast.net>
5 *
6 * This program is free software; you can redistribute it and/or modify             
7 * it under the terms of the GNU General Public License version 2                   
8 * as published by the Free Software Foundation                                     
9 *                                                                                   
10 * This program is distributed in the hope that is will be useful,                 
11 * bit WITHOU ANY WARRANTY; without even the implied warranty of                   
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                   
13 * GNU General Public License for more details.                                     
14 *                                                                                   
15 * You should have received a copy of the GNU General Public License               
16 * along with this program; if not, write to the Free Software                     
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA         
18 *
19 */
20
21#include "http_client.h"
22#include "passport.h"
23#include "msn.h"
24#include "bitlbee.h"
25#include "url.h"
26#include "misc.h"
27#include "xmltree.h"
28#include <ctype.h>
29#include <errno.h>
30
31static int passport_get_token_real( struct msn_auth_data *mad );
32static void passport_get_token_ready( struct http_request *req );
33
34int 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
63static int passport_get_token_real( struct msn_auth_data *mad )
64{
65        char *post_payload, *post_request;
66        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
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 )
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 );
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" );
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
142static 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" ) ) &&
148            ( strncmp( s, "Compact", 7 ) == 0 ||
149              strncmp( s, "PPToken", 7 ) == 0 ) )
150                mad->token = g_memdup( node->text, node->text_len + 1 );
151       
152        return XT_HANDLED;
153}
154
155static xt_status passport_xt_handle_fault( struct xt_node *node, gpointer data )
156{
157        struct msn_auth_data *mad = data;
158        struct xt_node *code = xt_find_node( node->children, "faultcode" );
159        struct xt_node *string = xt_find_node( node->children, "faultstring" );
160        struct xt_node *redirect = xt_find_node( node->children, "psf:redirectUrl" );
161       
162        if( redirect && redirect->text_len && mad->ttl-- > 0 )
163                mad->url = g_memdup( redirect->text, redirect->text_len + 1 );
164       
165        if( code == NULL || code->text_len == 0 )
166                mad->error = g_strdup( "Unknown error" );
167        else
168                mad->error = g_strdup_printf( "%s (%s)", code->text, string && string->text_len ?
169                                              string->text : "no description available" );
170       
171        return XT_HANDLED;
172}
Note: See TracBrowser for help on using the repository browser.