Changeset 523fb23 for protocols/msn


Ignore:
Timestamp:
2010-08-11T08:08:39Z (14 years ago)
Author:
Wilmer van der Gaast <wilmer@…>
Branches:
master
Children:
7f34ce2
Parents:
7db65b7
Message:

Implement MSNP15 SSO (Sadistic Sign-On).

Location:
protocols/msn
Files:
8 edited

Legend:

Unmodified
Added
Removed
  • protocols/msn/Makefile

    r7db65b7 r523fb23  
    4343        @$(LD) $(LFLAGS) $(objects) -o msn_mod.o
    4444       
    45 
     45soap.o: soap.h soap.c
  • protocols/msn/msn.c

    r7db65b7 r523fb23  
    103103                        g_free( md->grouplist[--md->groupcount] );
    104104                g_free( md->grouplist );
    105                 g_free( md->passport_token );
     105                g_free( md->tokens[0] );
     106                g_free( md->tokens[1] );
    106107                g_free( md->lock_key );
    107108               
  • protocols/msn/msn.h

    r7db65b7 r523fb23  
    7676       
    7777        int trId;
    78         char *passport_token;
     78        char *tokens[2];
    7979        char *lock_key;
    8080       
     
    171171/* ns.c */
    172172gboolean msn_ns_connected( gpointer data, gint source, b_input_condition cond );
     173void msn_auth_got_passport_token( struct im_connection *ic, char *token );
    173174
    174175/* msn_util.c */
  • protocols/msn/msn_util.c

    r7db65b7 r523fb23  
    3333        struct msn_data *md = ic->proto_data;
    3434        int st;
     35       
     36        if( getenv( "BITLBEE_DEBUG" ) )
     37        {
     38                write( 2, "->NS:", 5 );
     39                write( 2, s, len );
     40        }
    3541       
    3642        st = write( md->fd, s, len );
     
    280286        if( st <= 0 )
    281287                return( -1 );
     288       
     289        if( getenv( "BITLBEE_DEBUG" ) )
     290        {
     291                write( 2, "->C:", 4 );
     292                write( 2, h->rxq + h->rxlen - st, st );
     293        }
    282294       
    283295        while( st )
     
    446458}
    447459
    448 unsigned int little_endian( unsigned int dw )
    449 {
    450 #if defined(__BYTE_ORDER) && __BYTE_ORDER == __LITTLE_ENDIAN
    451         return dw;
    452 #else
    453         /* We're still not sure if this machine is big endian since the
    454            constants above are not that portable. Don't swap bytes, just
    455            force-compose a 32-bit little endian integer. */
    456         unsigned int ret = 0, i;
    457         char *dst = (char*) (&ret + 1);
    458        
    459         for (i = 0; i < 4; i ++)
    460         {
    461                 *(--dst) = dw >> 24;
    462                 dw <<= 8;
    463         }
    464        
    465         return ret;
    466 #endif
    467 }
    468 
    469460/* Copied and heavily modified from http://tmsnc.sourceforge.net/chl.c */
    470461char *msn_p11_challenge( char *challenge )
     
    487478        for (i = 0; i < 4; i ++)
    488479        { 
    489                 md5Parts[i] = little_endian(md5Parts[i]);
     480                md5Parts[i] = GUINT32_TO_LE(md5Parts[i]);
    490481               
    491482                /* & each integer with 0x7FFFFFFF */
     
    508499                long long temp;
    509500
    510                 chlStringParts[i]   = little_endian(chlStringParts[i]);
    511                 chlStringParts[i+1] = little_endian(chlStringParts[i+1]);
     501                chlStringParts[i]   = GUINT32_TO_LE(chlStringParts[i]);
     502                chlStringParts[i+1] = GUINT32_TO_LE(chlStringParts[i+1]);
    512503
    513504                temp  = (md5Parts[0] * (((0x0E79A9C1 * (long long)chlStringParts[i]) % 0x7FFFFFFF)+nHigh) + md5Parts[1])%0x7FFFFFFF;
     
    525516        /* swap more bytes if big endian */
    526517        for (i = 0; i < 4; i ++)
    527                 newHashParts[i] = little_endian(newHashParts[i]);
     518                newHashParts[i] = GUINT32_TO_LE(newHashParts[i]);
    528519       
    529520        /* make a string of the parts */
  • protocols/msn/ns.c

    r7db65b7 r523fb23  
    3535static int msn_ns_message( gpointer data, char *msg, int msglen, char **cmd, int num_parts );
    3636
    37 static void msn_auth_got_passport_token( struct msn_auth_data *mad );
    3837static gboolean msn_ns_got_display_name( struct im_connection *ic, char *name );
    3938
     
    7473        md->handler->rxq = g_new0( char, 1 );
    7574       
    76         g_snprintf( s, sizeof( s ), "VER %d MSNP14 CVR0\r\n", ++md->trId );
     75        g_snprintf( s, sizeof( s ), "VER %d MSNP15 CVR0\r\n", ++md->trId );
    7776        if( msn_write( ic, s, strlen( s ) ) )
    7877        {
     
    114113        if( strcmp( cmd[0], "VER" ) == 0 )
    115114        {
    116                 if( cmd[2] && strncmp( cmd[2], "MSNP14", 5 ) != 0 )
     115                if( cmd[2] && strncmp( cmd[2], "MSNP15", 5 ) != 0 )
    117116                {
    118117                        imcb_error( ic, "Unsupported protocol" );
     
    128127        {
    129128                /* We don't give a damn about the information we just received */
    130                 g_snprintf( buf, sizeof( buf ), "USR %d TWN I %s\r\n", ++md->trId, ic->acc->user );
     129                g_snprintf( buf, sizeof( buf ), "USR %d SSO I %s\r\n", ++md->trId, ic->acc->user );
    131130                return( msn_write( ic, buf, strlen( buf ) ) );
    132131        }
     
    221220        else if( strcmp( cmd[0], "USR" ) == 0 )
    222221        {
    223                 if( num_parts == 5 && strcmp( cmd[2], "TWN" ) == 0 && strcmp( cmd[3], "S" ) == 0 )
    224                 {
    225                         /* Time for some Passport black magic... */
    226                         if( !passport_get_token( msn_auth_got_passport_token, ic, ic->acc->user, ic->acc->pass, cmd[4] ) )
    227                         {
    228                                 imcb_error( ic, "Error while contacting Passport server" );
    229                                 imc_logout( ic, TRUE );
    230                                 return( 0 );
    231                         }
     222                if( num_parts >= 6 && strcmp( cmd[2], "SSO" ) == 0 &&
     223                    strcmp( cmd[3], "S" ) == 0 )
     224                {
     225                        msn_soap_passport_sso_request( ic, cmd[4], cmd[5] );
    232226                }
    233227                else if( strcmp( cmd[2], "OK" ) == 0 )
     
    775769}
    776770
    777 static void msn_auth_got_passport_token( struct msn_auth_data *mad )
     771void msn_auth_got_passport_token( struct im_connection *ic, char *token )
    778772{
    779         struct im_connection *ic = mad->data;
    780773        struct msn_data *md;
    781774       
     
    785778       
    786779        md = ic->proto_data;
    787         if( mad->token )
     780       
    788781        {
    789782                char buf[1024];
    790783               
    791                 md->passport_token = g_strdup( mad->token );
    792                
    793                 g_snprintf( buf, sizeof( buf ), "USR %d TWN S %s\r\n", ++md->trId, mad->token );
     784                g_snprintf( buf, sizeof( buf ), "USR %d SSO S %s %s\r\n", ++md->trId, md->tokens[0], token );
    794785                msn_write( ic, buf, strlen( buf ) );
    795         }
    796         else
    797         {
    798                 imcb_error( ic, "Error during Passport authentication: %s", mad->error );
    799                 imc_logout( ic, TRUE );
    800786        }
    801787}
  • protocols/msn/sb.c

    r7db65b7 r523fb23  
    3939{
    4040        int st;
     41       
     42        if( getenv( "BITLBEE_DEBUG" ) )
     43        {
     44                write( 2, "->SB:", 5 );
     45                write( 2, s, len );
     46        }
    4147       
    4248        st = write( sb->fd, s, len );
  • protocols/msn/soap.c

    r7db65b7 r523fb23  
    2828#include "url.h"
    2929#include "misc.h"
     30#include "sha1.h"
    3031#include "base64.h"
    3132#include "xmltree.h"
     
    8384static int msn_soap_send_request( struct msn_soap_req_data *soap_req )
    8485{
    85         struct msn_data *md = soap_req->ic->proto_data;
    8686        char *http_req;
    87         char *pom, *s;
     87        char *soap_action = NULL;
    8888        url_t url;
    8989       
    9090        soap_req->build_request( soap_req );
    9191       
    92         pom = g_new0( char, strlen( md->passport_token ) * 3 );
    93         strcpy( pom, md->passport_token + 2 );
    94         if( ( s = strchr( pom, '&' ) ) )
    95                 *s = '\0';
     92        if( soap_req->action )
     93                soap_action = g_strdup_printf( "SOAPAction: \"%s\"\r\n", soap_req->action );
    9694       
    9795        url_set( &url, soap_req->url );
    9896        http_req = g_strdup_printf( SOAP_HTTP_REQUEST, url.file, url.host,
    99                 soap_req->action, pom,
     97                soap_action ? soap_action : "",
    10098                strlen( soap_req->payload ), soap_req->payload );
    10199       
     
    104102       
    105103        g_free( http_req );
     104        g_free( soap_action );
    106105       
    107106        return soap_req->http_req != NULL;
     
    140139
    141140
     141/* passport_sso: Authentication MSNP15+ */
     142
     143struct msn_soap_passport_sso_data
     144{
     145        char *policy;
     146        char *nonce;
     147        char *secret;
     148};
     149
     150static int msn_soap_passport_sso_build_request( struct msn_soap_req_data *soap_req )
     151{
     152        struct msn_soap_passport_sso_data *sd = soap_req->data;
     153        struct im_connection *ic = soap_req->ic;
     154       
     155        soap_req->url = g_strdup( SOAP_PASSPORT_SSO_URL );
     156        soap_req->payload = g_markup_printf_escaped( SOAP_PASSPORT_SSO_PAYLOAD,
     157                ic->acc->user, ic->acc->pass, sd->policy );
     158       
     159        return MSN_SOAP_OK;
     160}
     161
     162static xt_status msn_soap_passport_sso_token( struct xt_node *node, gpointer data )
     163{
     164        struct msn_soap_req_data *soap_req = data;
     165        struct msn_soap_passport_sso_data *sd = soap_req->data;
     166        struct msn_data *md = soap_req->ic->proto_data;
     167        struct xt_node *p;
     168        char *id;
     169       
     170        if( ( id = xt_find_attr( node, "Id" ) ) == NULL )
     171                return XT_HANDLED;
     172        id += strlen( id ) - 1;
     173        if( *id == '1' &&
     174            ( p = node->parent ) && ( p = p->parent ) &&
     175            ( p = xt_find_node( p->children, "wst:RequestedProofToken" ) ) &&
     176            ( p = xt_find_node( p->children, "wst:BinarySecret" ) ) &&
     177            p->text )
     178                sd->secret = g_strdup( p->text );
     179       
     180        if( *id == '1' )
     181                md->tokens[0] = g_strdup( node->text );
     182        else if( *id == '2' )
     183                md->tokens[1] = g_strdup( node->text );
     184       
     185        return XT_HANDLED;
     186}
     187
     188static const struct xt_handler_entry msn_soap_passport_sso_parser[] = {
     189        { "wsse:BinarySecurityToken", "wst:RequestedSecurityToken", msn_soap_passport_sso_token },
     190        { NULL, NULL, NULL }
     191};
     192
     193static char *msn_key_fuckery( char *key, int key_len, char *type )
     194{
     195        unsigned char hash1[20+strlen(type)+1];
     196        unsigned char hash2[20];
     197        char *ret;
     198       
     199        sha1_hmac( key, key_len, type, 0, hash1 );
     200        strcpy( (char*) hash1 + 20, type );
     201        sha1_hmac( key, key_len, (char*) hash1, sizeof( hash1 ) - 1, hash2 );
     202       
     203        /* This is okay as hash1 is read completely before it's overwritten. */
     204        sha1_hmac( key, key_len, (char*) hash1, 20, hash1 );
     205        sha1_hmac( key, key_len, (char*) hash1, sizeof( hash1 ) - 1, hash1 );
     206       
     207        ret = g_malloc( 24 );
     208        memcpy( ret, hash2, 20 );
     209        memcpy( ret + 20, hash1, 4 );
     210        return ret;
     211}
     212
     213static int msn_soap_passport_sso_handle_response( struct msn_soap_req_data *soap_req )
     214{
     215        struct msn_soap_passport_sso_data *sd = soap_req->data;
     216        struct im_connection *ic = soap_req->ic;
     217        char *key1, *key2, *key3, *blurb64;
     218        int key1_len;
     219        unsigned char *padnonce, *des3res;
     220        struct
     221        {
     222                unsigned int uStructHeaderSize; // 28. Does not count data
     223                unsigned int uCryptMode; // CRYPT_MODE_CBC (1)
     224                unsigned int uCipherType; // TripleDES (0x6603)
     225                unsigned int uHashType; // SHA1 (0x8004)
     226                unsigned int uIVLen;    // 8
     227                unsigned int uHashLen;  // 20
     228                unsigned int uCipherLen; // 72
     229                unsigned char iv[8];
     230                unsigned char hash[20];
     231                unsigned char cipherbytes[72];
     232        } blurb = {
     233                GUINT32_TO_LE( 28 ),
     234                GUINT32_TO_LE( 1 ),
     235                GUINT32_TO_LE( 0x6603 ),
     236                GUINT32_TO_LE( 0x8004 ),
     237                GUINT32_TO_LE( 8 ),
     238                GUINT32_TO_LE( 20 ),
     239                GUINT32_TO_LE( 72 ),
     240        };
     241
     242        key1_len = base64_decode( sd->secret, (unsigned char**) &key1 );
     243       
     244        key2 = msn_key_fuckery( key1, key1_len, "WS-SecureConversationSESSION KEY HASH" );
     245        key3 = msn_key_fuckery( key1, key1_len, "WS-SecureConversationSESSION KEY ENCRYPTION" );
     246       
     247        sha1_hmac( key2, 24, sd->nonce, 0, blurb.hash );
     248        padnonce = g_malloc( strlen( sd->nonce ) + 8 );
     249        strcpy( (char*) padnonce, sd->nonce );
     250        memset( padnonce + strlen( sd->nonce ), 8, 8 );
     251       
     252        random_bytes( blurb.iv, 8 );
     253       
     254        ssl_des3_encrypt( (unsigned char*) key3, 24, padnonce, strlen( sd->nonce ) + 8, blurb.iv, &des3res );
     255        memcpy( blurb.cipherbytes, des3res, 72 );
     256       
     257        blurb64 = base64_encode( (unsigned char*) &blurb, sizeof( blurb ) );
     258        msn_auth_got_passport_token( ic, blurb64 );
     259       
     260        g_free( padnonce );
     261        g_free( blurb64 );
     262        g_free( des3res );
     263        g_free( key1 );
     264        g_free( key2 );
     265        g_free( key3 );
     266       
     267        return MSN_SOAP_OK;
     268}
     269
     270static int msn_soap_passport_sso_free_data( struct msn_soap_req_data *soap_req )
     271{
     272        struct msn_soap_passport_sso_data *sd = soap_req->data;
     273       
     274        g_free( sd->policy );
     275        g_free( sd->nonce );
     276        g_free( sd->secret );
     277       
     278        return MSN_SOAP_OK;
     279}
     280
     281int msn_soap_passport_sso_request( struct im_connection *ic, const char *policy, const char *nonce )
     282{
     283        struct msn_soap_passport_sso_data *sd = g_new0( struct msn_soap_passport_sso_data, 1 );
     284       
     285        sd->policy = g_strdup( policy );
     286        sd->nonce = g_strdup( nonce );
     287       
     288        return msn_soap_start( ic, sd, msn_soap_passport_sso_build_request,
     289                                       msn_soap_passport_sso_parser,
     290                                       msn_soap_passport_sso_handle_response,
     291                                       msn_soap_passport_sso_free_data );
     292}
     293
     294
    142295/* oim_send: Sending offline messages */
    143296
     
    162315        soap_req->action = g_strdup( SOAP_OIM_SEND_ACTION );
    163316        soap_req->payload = g_markup_printf_escaped( SOAP_OIM_SEND_PAYLOAD,
    164                 ic->acc->user, display_name_b64, oim->to, md->passport_token,
     317                ic->acc->user, display_name_b64, oim->to, "bla", //md->passport_token,
    165318                MSNP11_PROD_ID, md->lock_key ? md->lock_key : "",
    166319                oim->number, oim->number, oim->msg );
     
    168321        g_free( display_name_b64 );
    169322       
    170         return 1;
     323        return MSN_SOAP_OK;
    171324}
    172325
     
    220373        g_free( oim );
    221374       
    222         return 0;
     375        return MSN_SOAP_OK;
    223376}
    224377
     
    263416                *msgq = g_slist_remove( *msgq, m );
    264417        }
     418       
     419        return 1;
    265420}
    266421
  • protocols/msn/soap.h

    r7db65b7 r523fb23  
    4343"Host: %s\r\n" \
    4444"Accept: */*\r\n" \
    45 "SOAPAction: \"%s\"\r\n" \
    4645"User-Agent: BitlBee " BITLBEE_VERSION "\r\n" \
    4746"Content-Type: text/xml; charset=utf-8\r\n" \
    48 "Cookie: MSPAuth=%s\r\n" \
    49 "Content-Length: %d\r\n" \
     47"%s" \
     48"Content-Length: %zd\r\n" \
    5049"Cache-Control: no-cache\r\n" \
    5150"\r\n" \
    5251"%s"
     52
     53
     54#define SOAP_PASSPORT_SSO_URL "https://login.live.com/RST.srf"
     55#define SOAP_PASSPORT_SSO_URL_MSN "https://msnia.login.live.com/pp550/RST.srf"
     56
     57#define SOAP_PASSPORT_SSO_PAYLOAD \
     58"<Envelope xmlns=\"http://schemas.xmlsoap.org/soap/envelope/\" " \
     59   "xmlns:wsse=\"http://schemas.xmlsoap.org/ws/2003/06/secext\" " \
     60   "xmlns:saml=\"urn:oasis:names:tc:SAML:1.0:assertion\" " \
     61   "xmlns:wsp=\"http://schemas.xmlsoap.org/ws/2002/12/policy\" " \
     62   "xmlns:wsu=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd\" " \
     63   "xmlns:wsa=\"http://schemas.xmlsoap.org/ws/2004/03/addressing\" " \
     64   "xmlns:wssc=\"http://schemas.xmlsoap.org/ws/2004/04/sc\" " \
     65   "xmlns:wst=\"http://schemas.xmlsoap.org/ws/2004/04/trust\">" \
     66   "<Header>" \
     67       "<ps:AuthInfo " \
     68           "xmlns:ps=\"http://schemas.microsoft.com/Passport/SoapServices/PPCRL\" " \
     69           "Id=\"PPAuthInfo\">" \
     70           "<ps:HostingApp>{7108E71A-9926-4FCB-BCC9-9A9D3F32E423}</ps:HostingApp>" \
     71           "<ps:BinaryVersion>4</ps:BinaryVersion>" \
     72           "<ps:UIVersion>1</ps:UIVersion>" \
     73           "<ps:Cookies></ps:Cookies>" \
     74           "<ps:RequestParams>AQAAAAIAAABsYwQAAAAxMDMz</ps:RequestParams>" \
     75       "</ps:AuthInfo>" \
     76       "<wsse:Security>" \
     77           "<wsse:UsernameToken Id=\"user\">" \
     78               "<wsse:Username>%s</wsse:Username>" \
     79               "<wsse:Password>%s</wsse:Password>" \
     80           "</wsse:UsernameToken>" \
     81       "</wsse:Security>" \
     82   "</Header>" \
     83   "<Body>" \
     84       "<ps:RequestMultipleSecurityTokens " \
     85           "xmlns:ps=\"http://schemas.microsoft.com/Passport/SoapServices/PPCRL\" " \
     86           "Id=\"RSTS\">" \
     87           "<wst:RequestSecurityToken Id=\"RST0\">" \
     88               "<wst:RequestType>http://schemas.xmlsoap.org/ws/2004/04/security/trust/Issue</wst:RequestType>" \
     89               "<wsp:AppliesTo>" \
     90                   "<wsa:EndpointReference>" \
     91                       "<wsa:Address>http://Passport.NET/tb</wsa:Address>" \
     92                   "</wsa:EndpointReference>" \
     93               "</wsp:AppliesTo>" \
     94           "</wst:RequestSecurityToken>" \
     95           "<wst:RequestSecurityToken Id=\"RST1\">" \
     96               "<wst:RequestType>http://schemas.xmlsoap.org/ws/2004/04/security/trust/Issue</wst:RequestType>" \
     97               "<wsp:AppliesTo>" \
     98                   "<wsa:EndpointReference>" \
     99                       "<wsa:Address>messengerclear.live.com</wsa:Address>" \
     100                   "</wsa:EndpointReference>" \
     101               "</wsp:AppliesTo>" \
     102               "<wsse:PolicyReference URI=\"%s\"></wsse:PolicyReference>" \
     103           "</wst:RequestSecurityToken>" \
     104           "<wst:RequestSecurityToken Id=\"RST2\">" \
     105               "<wst:RequestType>http://schemas.xmlsoap.org/ws/2004/04/security/trust/Issue</wst:RequestType>" \
     106               "<wsp:AppliesTo>" \
     107                   "<wsa:EndpointReference>" \
     108                       "<wsa:Address>contacts.msn.com</wsa:Address>" \
     109                   "</wsa:EndpointReference>" \
     110               "</wsp:AppliesTo>" \
     111               "<wsse:PolicyReference xmlns=\"http://schemas.xmlsoap.org/ws/2003/06/secext\" URI=\"MBI\"></wsse:PolicyReference>" \
     112           "</wst:RequestSecurityToken>" \
     113       "</ps:RequestMultipleSecurityTokens>" \
     114   "</Body>" \
     115"</Envelope>"
     116
     117int msn_soap_passport_sso_request( struct im_connection *ic, const char *policy, const char *nonce );
    53118
    54119
Note: See TracChangeset for help on using the changeset viewer.